darcs-2.8.4/0000755001765600176560000000000012104371431012141 5ustar ganeshganeshdarcs-2.8.4/src/0000755001765600176560000000000012104371431012730 5ustar ganeshganeshdarcs-2.8.4/src/Crypt/0000755001765600176560000000000012104371431014031 5ustar ganeshganeshdarcs-2.8.4/src/Crypt/SHA256.hs0000644001765600176560000000274612104371431015246 0ustar ganeshganesh{-# LANGUAGE CPP, ForeignFunctionInterface #-} -- | -- Module: Data.Digest.SHA256 -- Copyright: Zooko O'Whielacronx -- License: GPL -- -- Stability: experimental -- ByteString-based, zero-copying binding to Crypto++'s sha interface -- thanks to Don Stewart , Matthew Sackman -- , Brian O'Sullivan, lispy, Adam Langley module Crypt.SHA256 ( sha256sum ) where import Foreign import Foreign.C.Types import Numeric (showHex) import Foreign.C.String ( withCString ) import Data.ByteString.Unsafe (unsafeUseAsCStringLen) import qualified Data.ByteString as B sha256sum :: B.ByteString -> String sha256sum p = unsafePerformIO $ withCString (take 64 $ repeat 'x') $ \digestCString -> unsafeUseAsCStringLen p $ \(ptr,n) -> do let digest = castPtr digestCString :: Ptr Word8 c_sha256 ptr (fromIntegral n) digest go digest 0 [] where -- print it in 0-padded hex format go :: Ptr Word8 -> Int -> [String] -> IO String go q n acc | seq q n >= 32 = return $ concat (reverse acc) | otherwise = do w <- peekElemOff q n go q (n+1) (draw w : acc) draw w = case showHex w [] of [x] -> ['0', x] x -> x -- void sha256sum(const unsigned char *d, size_t n, unsigned char *md); -- foreign import ccall unsafe "sha2.h darcs_sha256" c_sha256 :: Ptr CChar -> CSize -> Ptr Word8 -> IO () darcs-2.8.4/src/Crypt/sha2.c0000644001765600176560000010061612104371431015036 0ustar ganeshganesh/* * FIPS 180-2 SHA-224/256/384/512 implementation * Last update: 02/02/2007 * Issue date: 04/30/2005 * * Copyright (C) 2005, 2007 Olivier Gay * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #if 0 #define UNROLL_LOOPS /* Enable loops unrolling */ #endif #include #include "sha2.h" #define SHFR(x, n) (x >> n) #define ROTR(x, n) ((x >> n) | (x << ((sizeof(x) << 3) - n))) #define ROTL(x, n) ((x << n) | (x >> ((sizeof(x) << 3) - n))) #define CH(x, y, z) ((x & y) ^ (~x & z)) #define MAJ(x, y, z) ((x & y) ^ (x & z) ^ (y & z)) #define SHA256_F1(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22)) #define SHA256_F2(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25)) #define SHA256_F3(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHFR(x, 3)) #define SHA256_F4(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHFR(x, 10)) #define SHA512_F1(x) (ROTR(x, 28) ^ ROTR(x, 34) ^ ROTR(x, 39)) #define SHA512_F2(x) (ROTR(x, 14) ^ ROTR(x, 18) ^ ROTR(x, 41)) #define SHA512_F3(x) (ROTR(x, 1) ^ ROTR(x, 8) ^ SHFR(x, 7)) #define SHA512_F4(x) (ROTR(x, 19) ^ ROTR(x, 61) ^ SHFR(x, 6)) #define UNPACK32(x, str) \ { \ *((str) + 3) = (uint8) ((x) ); \ *((str) + 2) = (uint8) ((x) >> 8); \ *((str) + 1) = (uint8) ((x) >> 16); \ *((str) + 0) = (uint8) ((x) >> 24); \ } #define PACK32(str, x) \ { \ *(x) = ((uint32) *((str) + 3) ) \ | ((uint32) *((str) + 2) << 8) \ | ((uint32) *((str) + 1) << 16) \ | ((uint32) *((str) + 0) << 24); \ } #define UNPACK64(x, str) \ { \ *((str) + 7) = (uint8) ((x) ); \ *((str) + 6) = (uint8) ((x) >> 8); \ *((str) + 5) = (uint8) ((x) >> 16); \ *((str) + 4) = (uint8) ((x) >> 24); \ *((str) + 3) = (uint8) ((x) >> 32); \ *((str) + 2) = (uint8) ((x) >> 40); \ *((str) + 1) = (uint8) ((x) >> 48); \ *((str) + 0) = (uint8) ((x) >> 56); \ } #define PACK64(str, x) \ { \ *(x) = ((uint64) *((str) + 7) ) \ | ((uint64) *((str) + 6) << 8) \ | ((uint64) *((str) + 5) << 16) \ | ((uint64) *((str) + 4) << 24) \ | ((uint64) *((str) + 3) << 32) \ | ((uint64) *((str) + 2) << 40) \ | ((uint64) *((str) + 1) << 48) \ | ((uint64) *((str) + 0) << 56); \ } /* Macros used for loops unrolling */ #define SHA256_SCR(i) \ { \ w[i] = SHA256_F4(w[i - 2]) + w[i - 7] \ + SHA256_F3(w[i - 15]) + w[i - 16]; \ } #define SHA512_SCR(i) \ { \ w[i] = SHA512_F4(w[i - 2]) + w[i - 7] \ + SHA512_F3(w[i - 15]) + w[i - 16]; \ } #define SHA256_EXP(a, b, c, d, e, f, g, h, j) \ { \ t1 = wv[h] + SHA256_F2(wv[e]) + CH(wv[e], wv[f], wv[g]) \ + sha256_k[j] + w[j]; \ t2 = SHA256_F1(wv[a]) + MAJ(wv[a], wv[b], wv[c]); \ wv[d] += t1; \ wv[h] = t1 + t2; \ } #define SHA512_EXP(a, b, c, d, e, f, g ,h, j) \ { \ t1 = wv[h] + SHA512_F2(wv[e]) + CH(wv[e], wv[f], wv[g]) \ + sha512_k[j] + w[j]; \ t2 = SHA512_F1(wv[a]) + MAJ(wv[a], wv[b], wv[c]); \ wv[d] += t1; \ wv[h] = t1 + t2; \ } static uint32 sha224_h0[8] = {0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4}; static uint32 sha256_h0[8] = {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19}; static uint64 sha384_h0[8] = {0xcbbb9d5dc1059ed8ULL, 0x629a292a367cd507ULL, 0x9159015a3070dd17ULL, 0x152fecd8f70e5939ULL, 0x67332667ffc00b31ULL, 0x8eb44a8768581511ULL, 0xdb0c2e0d64f98fa7ULL, 0x47b5481dbefa4fa4ULL}; static uint64 sha512_h0[8] = {0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL, 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL}; static uint32 sha256_k[64] = {0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2}; static uint64 sha512_k[80] = {0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL}; /* SHA-256 functions */ static void sha256_transf(sha256_ctx *ctx, const unsigned char *message, unsigned int block_nb) { uint32 w[64]; uint32 wv[8]; uint32 t1, t2; const unsigned char *sub_block; int i; #ifndef UNROLL_LOOPS int j; #endif for (i = 0; i < (int) block_nb; i++) { sub_block = message + (i << 6); #ifndef UNROLL_LOOPS for (j = 0; j < 16; j++) { PACK32(&sub_block[j << 2], &w[j]); } for (j = 16; j < 64; j++) { SHA256_SCR(j); } for (j = 0; j < 8; j++) { wv[j] = ctx->h[j]; } for (j = 0; j < 64; j++) { t1 = wv[7] + SHA256_F2(wv[4]) + CH(wv[4], wv[5], wv[6]) + sha256_k[j] + w[j]; t2 = SHA256_F1(wv[0]) + MAJ(wv[0], wv[1], wv[2]); wv[7] = wv[6]; wv[6] = wv[5]; wv[5] = wv[4]; wv[4] = wv[3] + t1; wv[3] = wv[2]; wv[2] = wv[1]; wv[1] = wv[0]; wv[0] = t1 + t2; } for (j = 0; j < 8; j++) { ctx->h[j] += wv[j]; } #else PACK32(&sub_block[ 0], &w[ 0]); PACK32(&sub_block[ 4], &w[ 1]); PACK32(&sub_block[ 8], &w[ 2]); PACK32(&sub_block[12], &w[ 3]); PACK32(&sub_block[16], &w[ 4]); PACK32(&sub_block[20], &w[ 5]); PACK32(&sub_block[24], &w[ 6]); PACK32(&sub_block[28], &w[ 7]); PACK32(&sub_block[32], &w[ 8]); PACK32(&sub_block[36], &w[ 9]); PACK32(&sub_block[40], &w[10]); PACK32(&sub_block[44], &w[11]); PACK32(&sub_block[48], &w[12]); PACK32(&sub_block[52], &w[13]); PACK32(&sub_block[56], &w[14]); PACK32(&sub_block[60], &w[15]); SHA256_SCR(16); SHA256_SCR(17); SHA256_SCR(18); SHA256_SCR(19); SHA256_SCR(20); SHA256_SCR(21); SHA256_SCR(22); SHA256_SCR(23); SHA256_SCR(24); SHA256_SCR(25); SHA256_SCR(26); SHA256_SCR(27); SHA256_SCR(28); SHA256_SCR(29); SHA256_SCR(30); SHA256_SCR(31); SHA256_SCR(32); SHA256_SCR(33); SHA256_SCR(34); SHA256_SCR(35); SHA256_SCR(36); SHA256_SCR(37); SHA256_SCR(38); SHA256_SCR(39); SHA256_SCR(40); SHA256_SCR(41); SHA256_SCR(42); SHA256_SCR(43); SHA256_SCR(44); SHA256_SCR(45); SHA256_SCR(46); SHA256_SCR(47); SHA256_SCR(48); SHA256_SCR(49); SHA256_SCR(50); SHA256_SCR(51); SHA256_SCR(52); SHA256_SCR(53); SHA256_SCR(54); SHA256_SCR(55); SHA256_SCR(56); SHA256_SCR(57); SHA256_SCR(58); SHA256_SCR(59); SHA256_SCR(60); SHA256_SCR(61); SHA256_SCR(62); SHA256_SCR(63); wv[0] = ctx->h[0]; wv[1] = ctx->h[1]; wv[2] = ctx->h[2]; wv[3] = ctx->h[3]; wv[4] = ctx->h[4]; wv[5] = ctx->h[5]; wv[6] = ctx->h[6]; wv[7] = ctx->h[7]; SHA256_EXP(0,1,2,3,4,5,6,7, 0); SHA256_EXP(7,0,1,2,3,4,5,6, 1); SHA256_EXP(6,7,0,1,2,3,4,5, 2); SHA256_EXP(5,6,7,0,1,2,3,4, 3); SHA256_EXP(4,5,6,7,0,1,2,3, 4); SHA256_EXP(3,4,5,6,7,0,1,2, 5); SHA256_EXP(2,3,4,5,6,7,0,1, 6); SHA256_EXP(1,2,3,4,5,6,7,0, 7); SHA256_EXP(0,1,2,3,4,5,6,7, 8); SHA256_EXP(7,0,1,2,3,4,5,6, 9); SHA256_EXP(6,7,0,1,2,3,4,5,10); SHA256_EXP(5,6,7,0,1,2,3,4,11); SHA256_EXP(4,5,6,7,0,1,2,3,12); SHA256_EXP(3,4,5,6,7,0,1,2,13); SHA256_EXP(2,3,4,5,6,7,0,1,14); SHA256_EXP(1,2,3,4,5,6,7,0,15); SHA256_EXP(0,1,2,3,4,5,6,7,16); SHA256_EXP(7,0,1,2,3,4,5,6,17); SHA256_EXP(6,7,0,1,2,3,4,5,18); SHA256_EXP(5,6,7,0,1,2,3,4,19); SHA256_EXP(4,5,6,7,0,1,2,3,20); SHA256_EXP(3,4,5,6,7,0,1,2,21); SHA256_EXP(2,3,4,5,6,7,0,1,22); SHA256_EXP(1,2,3,4,5,6,7,0,23); SHA256_EXP(0,1,2,3,4,5,6,7,24); SHA256_EXP(7,0,1,2,3,4,5,6,25); SHA256_EXP(6,7,0,1,2,3,4,5,26); SHA256_EXP(5,6,7,0,1,2,3,4,27); SHA256_EXP(4,5,6,7,0,1,2,3,28); SHA256_EXP(3,4,5,6,7,0,1,2,29); SHA256_EXP(2,3,4,5,6,7,0,1,30); SHA256_EXP(1,2,3,4,5,6,7,0,31); SHA256_EXP(0,1,2,3,4,5,6,7,32); SHA256_EXP(7,0,1,2,3,4,5,6,33); SHA256_EXP(6,7,0,1,2,3,4,5,34); SHA256_EXP(5,6,7,0,1,2,3,4,35); SHA256_EXP(4,5,6,7,0,1,2,3,36); SHA256_EXP(3,4,5,6,7,0,1,2,37); SHA256_EXP(2,3,4,5,6,7,0,1,38); SHA256_EXP(1,2,3,4,5,6,7,0,39); SHA256_EXP(0,1,2,3,4,5,6,7,40); SHA256_EXP(7,0,1,2,3,4,5,6,41); SHA256_EXP(6,7,0,1,2,3,4,5,42); SHA256_EXP(5,6,7,0,1,2,3,4,43); SHA256_EXP(4,5,6,7,0,1,2,3,44); SHA256_EXP(3,4,5,6,7,0,1,2,45); SHA256_EXP(2,3,4,5,6,7,0,1,46); SHA256_EXP(1,2,3,4,5,6,7,0,47); SHA256_EXP(0,1,2,3,4,5,6,7,48); SHA256_EXP(7,0,1,2,3,4,5,6,49); SHA256_EXP(6,7,0,1,2,3,4,5,50); SHA256_EXP(5,6,7,0,1,2,3,4,51); SHA256_EXP(4,5,6,7,0,1,2,3,52); SHA256_EXP(3,4,5,6,7,0,1,2,53); SHA256_EXP(2,3,4,5,6,7,0,1,54); SHA256_EXP(1,2,3,4,5,6,7,0,55); SHA256_EXP(0,1,2,3,4,5,6,7,56); SHA256_EXP(7,0,1,2,3,4,5,6,57); SHA256_EXP(6,7,0,1,2,3,4,5,58); SHA256_EXP(5,6,7,0,1,2,3,4,59); SHA256_EXP(4,5,6,7,0,1,2,3,60); SHA256_EXP(3,4,5,6,7,0,1,2,61); SHA256_EXP(2,3,4,5,6,7,0,1,62); SHA256_EXP(1,2,3,4,5,6,7,0,63); ctx->h[0] += wv[0]; ctx->h[1] += wv[1]; ctx->h[2] += wv[2]; ctx->h[3] += wv[3]; ctx->h[4] += wv[4]; ctx->h[5] += wv[5]; ctx->h[6] += wv[6]; ctx->h[7] += wv[7]; #endif /* !UNROLL_LOOPS */ } } static void sha256_init(sha256_ctx *ctx) { #ifndef UNROLL_LOOPS int i; for (i = 0; i < 8; i++) { ctx->h[i] = sha256_h0[i]; } #else ctx->h[0] = sha256_h0[0]; ctx->h[1] = sha256_h0[1]; ctx->h[2] = sha256_h0[2]; ctx->h[3] = sha256_h0[3]; ctx->h[4] = sha256_h0[4]; ctx->h[5] = sha256_h0[5]; ctx->h[6] = sha256_h0[6]; ctx->h[7] = sha256_h0[7]; #endif /* !UNROLL_LOOPS */ ctx->len = 0; ctx->tot_len = 0; } static void sha256_update(sha256_ctx *ctx, const unsigned char *message, unsigned int len) { unsigned int block_nb; unsigned int new_len, rem_len, tmp_len; const unsigned char *shifted_message; tmp_len = SHA256_BLOCK_SIZE - ctx->len; rem_len = len < tmp_len ? len : tmp_len; memcpy(&ctx->block[ctx->len], message, rem_len); if (ctx->len + len < SHA256_BLOCK_SIZE) { ctx->len += len; return; } new_len = len - rem_len; block_nb = new_len / SHA256_BLOCK_SIZE; shifted_message = message + rem_len; sha256_transf(ctx, ctx->block, 1); sha256_transf(ctx, shifted_message, block_nb); rem_len = new_len % SHA256_BLOCK_SIZE; memcpy(ctx->block, &shifted_message[block_nb << 6], rem_len); ctx->len = rem_len; ctx->tot_len += (block_nb + 1) << 6; } static void sha256_final(sha256_ctx *ctx, unsigned char *digest) { unsigned int block_nb; unsigned int pm_len; unsigned int len_b; #ifndef UNROLL_LOOPS int i; #endif block_nb = (1 + ((SHA256_BLOCK_SIZE - 9) < (ctx->len % SHA256_BLOCK_SIZE))); len_b = (ctx->tot_len + ctx->len) << 3; pm_len = block_nb << 6; memset(ctx->block + ctx->len, 0, pm_len - ctx->len); ctx->block[ctx->len] = 0x80; UNPACK32(len_b, ctx->block + pm_len - 4); sha256_transf(ctx, ctx->block, block_nb); #ifndef UNROLL_LOOPS for (i = 0 ; i < 8; i++) { UNPACK32(ctx->h[i], &digest[i << 2]); } #else UNPACK32(ctx->h[0], &digest[ 0]); UNPACK32(ctx->h[1], &digest[ 4]); UNPACK32(ctx->h[2], &digest[ 8]); UNPACK32(ctx->h[3], &digest[12]); UNPACK32(ctx->h[4], &digest[16]); UNPACK32(ctx->h[5], &digest[20]); UNPACK32(ctx->h[6], &digest[24]); UNPACK32(ctx->h[7], &digest[28]); #endif /* !UNROLL_LOOPS */ } void darcs_sha256(const unsigned char *message, unsigned int len, unsigned char *digest) { sha256_ctx ctx; sha256_init(&ctx); sha256_update(&ctx, message, len); sha256_final(&ctx, digest); } /* SHA-512 functions */ static void sha512_transf(sha512_ctx *ctx, const unsigned char *message, unsigned int block_nb) { uint64 w[80]; uint64 wv[8]; uint64 t1, t2; const unsigned char *sub_block; int i, j; for (i = 0; i < (int) block_nb; i++) { sub_block = message + (i << 7); #ifndef UNROLL_LOOPS for (j = 0; j < 16; j++) { PACK64(&sub_block[j << 3], &w[j]); } for (j = 16; j < 80; j++) { SHA512_SCR(j); } for (j = 0; j < 8; j++) { wv[j] = ctx->h[j]; } for (j = 0; j < 80; j++) { t1 = wv[7] + SHA512_F2(wv[4]) + CH(wv[4], wv[5], wv[6]) + sha512_k[j] + w[j]; t2 = SHA512_F1(wv[0]) + MAJ(wv[0], wv[1], wv[2]); wv[7] = wv[6]; wv[6] = wv[5]; wv[5] = wv[4]; wv[4] = wv[3] + t1; wv[3] = wv[2]; wv[2] = wv[1]; wv[1] = wv[0]; wv[0] = t1 + t2; } for (j = 0; j < 8; j++) { ctx->h[j] += wv[j]; } #else PACK64(&sub_block[ 0], &w[ 0]); PACK64(&sub_block[ 8], &w[ 1]); PACK64(&sub_block[ 16], &w[ 2]); PACK64(&sub_block[ 24], &w[ 3]); PACK64(&sub_block[ 32], &w[ 4]); PACK64(&sub_block[ 40], &w[ 5]); PACK64(&sub_block[ 48], &w[ 6]); PACK64(&sub_block[ 56], &w[ 7]); PACK64(&sub_block[ 64], &w[ 8]); PACK64(&sub_block[ 72], &w[ 9]); PACK64(&sub_block[ 80], &w[10]); PACK64(&sub_block[ 88], &w[11]); PACK64(&sub_block[ 96], &w[12]); PACK64(&sub_block[104], &w[13]); PACK64(&sub_block[112], &w[14]); PACK64(&sub_block[120], &w[15]); SHA512_SCR(16); SHA512_SCR(17); SHA512_SCR(18); SHA512_SCR(19); SHA512_SCR(20); SHA512_SCR(21); SHA512_SCR(22); SHA512_SCR(23); SHA512_SCR(24); SHA512_SCR(25); SHA512_SCR(26); SHA512_SCR(27); SHA512_SCR(28); SHA512_SCR(29); SHA512_SCR(30); SHA512_SCR(31); SHA512_SCR(32); SHA512_SCR(33); SHA512_SCR(34); SHA512_SCR(35); SHA512_SCR(36); SHA512_SCR(37); SHA512_SCR(38); SHA512_SCR(39); SHA512_SCR(40); SHA512_SCR(41); SHA512_SCR(42); SHA512_SCR(43); SHA512_SCR(44); SHA512_SCR(45); SHA512_SCR(46); SHA512_SCR(47); SHA512_SCR(48); SHA512_SCR(49); SHA512_SCR(50); SHA512_SCR(51); SHA512_SCR(52); SHA512_SCR(53); SHA512_SCR(54); SHA512_SCR(55); SHA512_SCR(56); SHA512_SCR(57); SHA512_SCR(58); SHA512_SCR(59); SHA512_SCR(60); SHA512_SCR(61); SHA512_SCR(62); SHA512_SCR(63); SHA512_SCR(64); SHA512_SCR(65); SHA512_SCR(66); SHA512_SCR(67); SHA512_SCR(68); SHA512_SCR(69); SHA512_SCR(70); SHA512_SCR(71); SHA512_SCR(72); SHA512_SCR(73); SHA512_SCR(74); SHA512_SCR(75); SHA512_SCR(76); SHA512_SCR(77); SHA512_SCR(78); SHA512_SCR(79); wv[0] = ctx->h[0]; wv[1] = ctx->h[1]; wv[2] = ctx->h[2]; wv[3] = ctx->h[3]; wv[4] = ctx->h[4]; wv[5] = ctx->h[5]; wv[6] = ctx->h[6]; wv[7] = ctx->h[7]; j = 0; do { SHA512_EXP(0,1,2,3,4,5,6,7,j); j++; SHA512_EXP(7,0,1,2,3,4,5,6,j); j++; SHA512_EXP(6,7,0,1,2,3,4,5,j); j++; SHA512_EXP(5,6,7,0,1,2,3,4,j); j++; SHA512_EXP(4,5,6,7,0,1,2,3,j); j++; SHA512_EXP(3,4,5,6,7,0,1,2,j); j++; SHA512_EXP(2,3,4,5,6,7,0,1,j); j++; SHA512_EXP(1,2,3,4,5,6,7,0,j); j++; } while (j < 80); ctx->h[0] += wv[0]; ctx->h[1] += wv[1]; ctx->h[2] += wv[2]; ctx->h[3] += wv[3]; ctx->h[4] += wv[4]; ctx->h[5] += wv[5]; ctx->h[6] += wv[6]; ctx->h[7] += wv[7]; #endif /* !UNROLL_LOOPS */ } } static void sha512_init(sha512_ctx *ctx) { #ifndef UNROLL_LOOPS int i; for (i = 0; i < 8; i++) { ctx->h[i] = sha512_h0[i]; } #else ctx->h[0] = sha512_h0[0]; ctx->h[1] = sha512_h0[1]; ctx->h[2] = sha512_h0[2]; ctx->h[3] = sha512_h0[3]; ctx->h[4] = sha512_h0[4]; ctx->h[5] = sha512_h0[5]; ctx->h[6] = sha512_h0[6]; ctx->h[7] = sha512_h0[7]; #endif /* !UNROLL_LOOPS */ ctx->len = 0; ctx->tot_len = 0; } static void sha512_update(sha512_ctx *ctx, const unsigned char *message, unsigned int len) { unsigned int block_nb; unsigned int new_len, rem_len, tmp_len; const unsigned char *shifted_message; tmp_len = SHA512_BLOCK_SIZE - ctx->len; rem_len = len < tmp_len ? len : tmp_len; memcpy(&ctx->block[ctx->len], message, rem_len); if (ctx->len + len < SHA512_BLOCK_SIZE) { ctx->len += len; return; } new_len = len - rem_len; block_nb = new_len / SHA512_BLOCK_SIZE; shifted_message = message + rem_len; sha512_transf(ctx, ctx->block, 1); sha512_transf(ctx, shifted_message, block_nb); rem_len = new_len % SHA512_BLOCK_SIZE; memcpy(ctx->block, &shifted_message[block_nb << 7], rem_len); ctx->len = rem_len; ctx->tot_len += (block_nb + 1) << 7; } static void sha512_final(sha512_ctx *ctx, unsigned char *digest) { unsigned int block_nb; unsigned int pm_len; unsigned int len_b; #ifndef UNROLL_LOOPS int i; #endif block_nb = 1 + ((SHA512_BLOCK_SIZE - 17) < (ctx->len % SHA512_BLOCK_SIZE)); len_b = (ctx->tot_len + ctx->len) << 3; pm_len = block_nb << 7; memset(ctx->block + ctx->len, 0, pm_len - ctx->len); ctx->block[ctx->len] = 0x80; UNPACK32(len_b, ctx->block + pm_len - 4); sha512_transf(ctx, ctx->block, block_nb); #ifndef UNROLL_LOOPS for (i = 0 ; i < 8; i++) { UNPACK64(ctx->h[i], &digest[i << 3]); } #else UNPACK64(ctx->h[0], &digest[ 0]); UNPACK64(ctx->h[1], &digest[ 8]); UNPACK64(ctx->h[2], &digest[16]); UNPACK64(ctx->h[3], &digest[24]); UNPACK64(ctx->h[4], &digest[32]); UNPACK64(ctx->h[5], &digest[40]); UNPACK64(ctx->h[6], &digest[48]); UNPACK64(ctx->h[7], &digest[56]); #endif /* !UNROLL_LOOPS */ } void darcs_sha512(const unsigned char *message, unsigned int len, unsigned char *digest) { sha512_ctx ctx; sha512_init(&ctx); sha512_update(&ctx, message, len); sha512_final(&ctx, digest); } /* SHA-384 functions */ static void sha384_init(sha384_ctx *ctx) { #ifndef UNROLL_LOOPS int i; for (i = 0; i < 8; i++) { ctx->h[i] = sha384_h0[i]; } #else ctx->h[0] = sha384_h0[0]; ctx->h[1] = sha384_h0[1]; ctx->h[2] = sha384_h0[2]; ctx->h[3] = sha384_h0[3]; ctx->h[4] = sha384_h0[4]; ctx->h[5] = sha384_h0[5]; ctx->h[6] = sha384_h0[6]; ctx->h[7] = sha384_h0[7]; #endif /* !UNROLL_LOOPS */ ctx->len = 0; ctx->tot_len = 0; } static void sha384_update(sha384_ctx *ctx, const unsigned char *message, unsigned int len) { unsigned int block_nb; unsigned int new_len, rem_len, tmp_len; const unsigned char *shifted_message; tmp_len = SHA384_BLOCK_SIZE - ctx->len; rem_len = len < tmp_len ? len : tmp_len; memcpy(&ctx->block[ctx->len], message, rem_len); if (ctx->len + len < SHA384_BLOCK_SIZE) { ctx->len += len; return; } new_len = len - rem_len; block_nb = new_len / SHA384_BLOCK_SIZE; shifted_message = message + rem_len; sha512_transf(ctx, ctx->block, 1); sha512_transf(ctx, shifted_message, block_nb); rem_len = new_len % SHA384_BLOCK_SIZE; memcpy(ctx->block, &shifted_message[block_nb << 7], rem_len); ctx->len = rem_len; ctx->tot_len += (block_nb + 1) << 7; } static void sha384_final(sha384_ctx *ctx, unsigned char *digest) { unsigned int block_nb; unsigned int pm_len; unsigned int len_b; #ifndef UNROLL_LOOPS int i; #endif block_nb = (1 + ((SHA384_BLOCK_SIZE - 17) < (ctx->len % SHA384_BLOCK_SIZE))); len_b = (ctx->tot_len + ctx->len) << 3; pm_len = block_nb << 7; memset(ctx->block + ctx->len, 0, pm_len - ctx->len); ctx->block[ctx->len] = 0x80; UNPACK32(len_b, ctx->block + pm_len - 4); sha512_transf(ctx, ctx->block, block_nb); #ifndef UNROLL_LOOPS for (i = 0 ; i < 6; i++) { UNPACK64(ctx->h[i], &digest[i << 3]); } #else UNPACK64(ctx->h[0], &digest[ 0]); UNPACK64(ctx->h[1], &digest[ 8]); UNPACK64(ctx->h[2], &digest[16]); UNPACK64(ctx->h[3], &digest[24]); UNPACK64(ctx->h[4], &digest[32]); UNPACK64(ctx->h[5], &digest[40]); #endif /* !UNROLL_LOOPS */ } void darcs_sha384(const unsigned char *message, unsigned int len, unsigned char *digest) { sha384_ctx ctx; sha384_init(&ctx); sha384_update(&ctx, message, len); sha384_final(&ctx, digest); } /* SHA-224 functions */ static void sha224_init(sha224_ctx *ctx) { #ifndef UNROLL_LOOPS int i; for (i = 0; i < 8; i++) { ctx->h[i] = sha224_h0[i]; } #else ctx->h[0] = sha224_h0[0]; ctx->h[1] = sha224_h0[1]; ctx->h[2] = sha224_h0[2]; ctx->h[3] = sha224_h0[3]; ctx->h[4] = sha224_h0[4]; ctx->h[5] = sha224_h0[5]; ctx->h[6] = sha224_h0[6]; ctx->h[7] = sha224_h0[7]; #endif /* !UNROLL_LOOPS */ ctx->len = 0; ctx->tot_len = 0; } static void sha224_update(sha224_ctx *ctx, const unsigned char *message, unsigned int len) { unsigned int block_nb; unsigned int new_len, rem_len, tmp_len; const unsigned char *shifted_message; tmp_len = SHA224_BLOCK_SIZE - ctx->len; rem_len = len < tmp_len ? len : tmp_len; memcpy(&ctx->block[ctx->len], message, rem_len); if (ctx->len + len < SHA224_BLOCK_SIZE) { ctx->len += len; return; } new_len = len - rem_len; block_nb = new_len / SHA224_BLOCK_SIZE; shifted_message = message + rem_len; sha256_transf(ctx, ctx->block, 1); sha256_transf(ctx, shifted_message, block_nb); rem_len = new_len % SHA224_BLOCK_SIZE; memcpy(ctx->block, &shifted_message[block_nb << 6], rem_len); ctx->len = rem_len; ctx->tot_len += (block_nb + 1) << 6; } static void sha224_final(sha224_ctx *ctx, unsigned char *digest) { unsigned int block_nb; unsigned int pm_len; unsigned int len_b; #ifndef UNROLL_LOOPS int i; #endif block_nb = (1 + ((SHA224_BLOCK_SIZE - 9) < (ctx->len % SHA224_BLOCK_SIZE))); len_b = (ctx->tot_len + ctx->len) << 3; pm_len = block_nb << 6; memset(ctx->block + ctx->len, 0, pm_len - ctx->len); ctx->block[ctx->len] = 0x80; UNPACK32(len_b, ctx->block + pm_len - 4); sha256_transf(ctx, ctx->block, block_nb); #ifndef UNROLL_LOOPS for (i = 0 ; i < 7; i++) { UNPACK32(ctx->h[i], &digest[i << 2]); } #else UNPACK32(ctx->h[0], &digest[ 0]); UNPACK32(ctx->h[1], &digest[ 4]); UNPACK32(ctx->h[2], &digest[ 8]); UNPACK32(ctx->h[3], &digest[12]); UNPACK32(ctx->h[4], &digest[16]); UNPACK32(ctx->h[5], &digest[20]); UNPACK32(ctx->h[6], &digest[24]); #endif /* !UNROLL_LOOPS */ } void darcs_sha224(const unsigned char *message, unsigned int len, unsigned char *digest) { sha224_ctx ctx; sha224_init(&ctx); sha224_update(&ctx, message, len); sha224_final(&ctx, digest); } #ifdef TEST_VECTORS /* FIPS 180-2 Validation tests */ #include #include void test(const unsigned char *vector, unsigned char *digest, unsigned int digest_size) { unsigned char output[2 * SHA512_DIGEST_SIZE + 1]; int i; output[2 * digest_size] = '\0'; for (i = 0; i < (int) digest_size ; i++) { sprintf((char *) output + 2 * i, "%02x", digest[i]); } printf("H: %s\n", output); if (strcmp((char *) vector, (char *) output)) { fprintf(stderr, "Test failed.\n"); exit(EXIT_FAILURE); } } int main() { static const unsigned char *vectors[4][3] = { /* SHA-224 */ { "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", "75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525", "20794655980c91d8bbb4c1ea97618a4bf03f42581948b2ee4ee7ad67", }, /* SHA-256 */ { "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1", "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0", }, /* SHA-384 */ { "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed" "8086072ba1e7cc2358baeca134c825a7", "09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712" "fcc7c71a557e2db966c3e9fa91746039", "9d0e1809716474cb086e834e310a4a1ced149e9c00f248527972cec5704c2a5b" "07b8b3dc38ecc4ebae97ddd87f3d8985", }, /* SHA-512 */ { "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a" "2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", "8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018" "501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909", "e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973eb" "de0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b" } }; static const unsigned char message1[] = "abc"; static const unsigned char message2a[] = "abcdbcdecdefdefgefghfghighijhi" "jkijkljklmklmnlmnomnopnopq"; static const unsigned char message2b[] = "abcdefghbcdefghicdefghijdefghijkefghij" "klfghijklmghijklmnhijklmnoijklmnopjklm" "nopqklmnopqrlmnopqrsmnopqrstnopqrstu"; unsigned char *message3; unsigned int message3_len = 1000000; unsigned char digest[SHA512_DIGEST_SIZE]; message3 = malloc(message3_len); if (message3 == NULL) { fprintf(stderr, "Can't allocate memory\n"); return -1; } memset(message3, 'a', message3_len); printf("SHA-2 FIPS 180-2 Validation tests\n\n"); printf("SHA-224 Test vectors\n"); sha224(message1, strlen((char *) message1), digest); test(vectors[0][0], digest, SHA224_DIGEST_SIZE); sha224(message2a, strlen((char *) message2a), digest); test(vectors[0][1], digest, SHA224_DIGEST_SIZE); sha224(message3, message3_len, digest); test(vectors[0][2], digest, SHA224_DIGEST_SIZE); printf("\n"); printf("SHA-256 Test vectors\n"); sha256(message1, strlen((char *) message1), digest); test(vectors[1][0], digest, SHA256_DIGEST_SIZE); sha256(message2a, strlen((char *) message2a), digest); test(vectors[1][1], digest, SHA256_DIGEST_SIZE); sha256(message3, message3_len, digest); test(vectors[1][2], digest, SHA256_DIGEST_SIZE); printf("\n"); printf("SHA-384 Test vectors\n"); sha384(message1, strlen((char *) message1), digest); test(vectors[2][0], digest, SHA384_DIGEST_SIZE); sha384(message2b, strlen((char *) message2b), digest); test(vectors[2][1], digest, SHA384_DIGEST_SIZE); sha384(message3, message3_len, digest); test(vectors[2][2], digest, SHA384_DIGEST_SIZE); printf("\n"); printf("SHA-512 Test vectors\n"); sha512(message1, strlen((char *) message1), digest); test(vectors[3][0], digest, SHA512_DIGEST_SIZE); sha512(message2b, strlen((char *) message2b), digest); test(vectors[3][1], digest, SHA512_DIGEST_SIZE); sha512(message3, message3_len, digest); test(vectors[3][2], digest, SHA512_DIGEST_SIZE); printf("\n"); printf("All tests passed.\n"); return 0; } #endif /* TEST_VECTORS */ darcs-2.8.4/src/Crypt/sha2.h0000644001765600176560000000576012104371431015047 0ustar ganeshganesh/* * FIPS 180-2 SHA-224/256/384/512 implementation * Last update: 02/02/2007 * Issue date: 04/30/2005 * * Copyright (C) 2005, 2007 Olivier Gay * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef SHA2_H #define SHA2_H #define SHA224_DIGEST_SIZE ( 224 / 8) #define SHA256_DIGEST_SIZE ( 256 / 8) #define SHA384_DIGEST_SIZE ( 384 / 8) #define SHA512_DIGEST_SIZE ( 512 / 8) #define SHA256_BLOCK_SIZE ( 512 / 8) #define SHA512_BLOCK_SIZE (1024 / 8) #define SHA384_BLOCK_SIZE SHA512_BLOCK_SIZE #define SHA224_BLOCK_SIZE SHA256_BLOCK_SIZE #ifndef SHA2_TYPES #define SHA2_TYPES typedef unsigned char uint8; typedef unsigned int uint32; typedef unsigned long long uint64; #endif #ifdef __cplusplus extern "C" { #endif typedef struct { unsigned int tot_len; unsigned int len; unsigned char block[2 * SHA256_BLOCK_SIZE]; uint32 h[8]; } sha256_ctx; typedef struct { unsigned int tot_len; unsigned int len; unsigned char block[2 * SHA512_BLOCK_SIZE]; uint64 h[8]; } sha512_ctx; typedef sha512_ctx sha384_ctx; typedef sha256_ctx sha224_ctx; void darcs_sha224(const unsigned char *message, unsigned int len, unsigned char *digest); void darcs_sha256(const unsigned char *message, unsigned int len, unsigned char *digest); void darcs_sha384(const unsigned char *message, unsigned int len, unsigned char *digest); void darcs_sha512(const unsigned char *message, unsigned int len, unsigned char *digest); #ifdef __cplusplus } #endif #endif /* !SHA2_H */ darcs-2.8.4/src/Darcs/0000755001765600176560000000000012104371431013764 5ustar ganeshganeshdarcs-2.8.4/src/Darcs/Commands/0000755001765600176560000000000012104371431015525 5ustar ganeshganeshdarcs-2.8.4/src/Darcs/Commands/Add.hs0000644001765600176560000003075312104371431016561 0ustar ganeshganesh-- Copyright (C) 2002-2004 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. -- | -- Module : Darcs.Commands.Add -- Copyright : 2002-2004 David Roundy -- License : GPL -- Maintainer : darcs-devel@darcs.net -- Stability : experimental -- Portability : portable module Darcs.Commands.Add ( add , expandDirs ) where #include "gadts.h" #include "impossible.h" import Prelude hiding ( catch ) import Control.Exception ( catch, IOException ) import Control.Monad ( when, unless, liftM ) import Data.List ( (\\), nub ) import Data.Maybe ( isNothing, maybeToList ) import Printer ( text ) import Storage.Hashed.Tree ( Tree, findTree, expand ) import Storage.Hashed.AnchoredPath ( floatPath, anchorPath, parents ) import System.FilePath.Posix ( takeDirectory, () ) import System.Posix.Files ( isRegularFile, isDirectory, isSymbolicLink ) import System.Directory ( getPermissions, readable ) import qualified System.FilePath.Windows as WindowsFilePath import Darcs.Arguments ( noskipBoring, allowProblematicFilenames, recursive, workingRepoDir, dryRunNoxml, umaskOption, listFiles, listUnregisteredFiles, DarcsFlag ( Recursive, DryRun, Verbose, Quiet ), fixSubPaths, ) import Darcs.Commands ( DarcsCommand(..), putVerbose, putWarning, nodefaults) import Darcs.Flags ( includeBoring, doAllowCaseOnly, doAllowWindowsReserved ) import Darcs.Patch ( Patchy, PrimPatch, applyToTree, addfile, adddir ) import Darcs.Patch.Apply ( ApplyState ) import Darcs.RepoPath ( SubPath, toFilePath, simpleSubPath, toPath ) import Darcs.Repository.State ( readRecordedAndPending ) import Darcs.Repository ( amInHashedRepository, withRepoLock, RepoJob(..), addToPending ) import Darcs.Repository.Prefs ( darcsdirFilter, boringFileFilter ) import Darcs.Utils ( treeHas, treeHasDir, treeHasAnycase, getFileStatus, withCurrentDirectory, nubsort ) import Darcs.Witnesses.Ordered ( FL(..), (+>+), nullFL ) import Darcs.Witnesses.Sealed ( Sealed(..), Gap(..), FreeLeft, unFreeLeft ) addDescription :: String addDescription = "Add one or more new files or directories." addHelp :: String addHelp = "Generally a repository contains both files that should be version\n" ++ "controlled (such as source code) and files that Darcs should ignore\n" ++ "(such as executables compiled from the source code). The `darcs add'\n" ++ "command is used to tell Darcs which files to version control.\n" ++ "\n" ++ "When an existing project is first imported into a Darcs repository, it\n" ++ "is common to run `darcs add -r *' or `darcs record -l' to add all\n" ++ "initial source files into darcs.\n"++ "\n" ++ "Adding symbolic links (symlinks) is not supported.\n\n" addHelp' :: String addHelp' = "Darcs will ignore all files and folders that look `boring'. The\n" ++ "--boring option overrides this behaviour.\n" ++ "\n" ++ "Darcs will not add file if another file in the same folder has the\n" ++ "same name, except for case. The --case-ok option overrides this\n" ++ "behaviour. Windows and OS X usually use filesystems that do not allow\n" ++ "files a folder to have the same name except for case (for example,\n" ++ "`ReadMe' and `README'). If --case-ok is used, the repository might be\n" ++ "unusable on those systems!\n\n" add :: DarcsCommand add = DarcsCommand { commandProgramName = "darcs" , commandName = "add" , commandHelp = addHelp ++ addHelp' , commandDescription = addDescription , commandExtraArgs = -1 , commandExtraArgHelp = [ " ..." ] , commandCommand = addCmd , commandPrereq = amInHashedRepository , commandGetArgPossibilities = listUnregisteredFiles , commandArgdefaults = nodefaults , commandAdvancedOptions = [umaskOption] , commandBasicOptions = [ noskipBoring , allowProblematicFilenames , recursive "add contents of subdirectories" , workingRepoDir , dryRunNoxml ] } addCmd :: [DarcsFlag] -> [String] -> IO () addCmd opts args | null args = putStrLn $ "Nothing specified, nothing added." ++ "Maybe you wanted to say `darcs add --recursive .'?" | otherwise = do fs <- fixSubPaths opts args case fs of [] -> fail "No valid arguments were given" _ -> addFiles opts fs addFiles :: [DarcsFlag] -- ^ Command options -> [SubPath] -> IO () addFiles opts origfiles = withRepoLock opts $ RepoJob $ \repository -> do -- TODO do not expand here, and use findM/findIO or such later -- (needs adding to hashed-storage first though) cur <- expand =<< readRecordedAndPending repository let parlist = getParents cur (map toFilePath origfiles) flist' <- if Recursive `elem` opts then expandDirs origfiles else return origfiles let flist = nubsort (parlist ++ toFilePath `map` flist') -- refuse to add boring files recursively: nboring <- if includeBoring opts then return darcsdirFilter else boringFileFilter let fixedOpts = if DryRun `elem` opts then Verbose:opts else opts mapM_ (putWarning fixedOpts . text . ((msgSkipping msgs ++ " boring file ")++)) $ flist \\ nboring flist Sealed ps <- fmap unFreeLeft $ addp msgs fixedOpts cur $ nboring flist when (nullFL ps && not (null origfiles) && not (Quiet `elem` opts)) $ fail "No files were added" unless gotDryRun $ addToPending repository ps where gotDryRun = DryRun `elem` opts msgs | gotDryRun = dryRunMessages | otherwise = normalMessages addp :: forall prim . (Patchy prim, PrimPatch prim, ApplyState prim ~ Tree) => AddMessages -> [DarcsFlag] -> Tree IO -> [FilePath] -> IO (FreeLeft (FL prim)) addp msgs opts cur0 files = do (ps, dups) <- foldr (\f rest cur accPS accDups -> do addResult <- addp' cur f case addResult of -- If a single file fails to add, stop further processing. (_, Nothing, Nothing) -> return ([], []) (cur', mp, mdup) -> rest cur' (maybeToList mp ++ accPS) (maybeToList mdup ++ accDups)) (\_ ps dups -> return (reverse ps, dups)) files cur0 [] [] let uniq_dups = nub dups caseMsg = if gotAllowCaseOnly then ":" else ";\nnote that to ensure portability we don't allow\n" ++ "files that differ only in case. Use --case-ok to override this:" unless (null dups) $ do dupMsg <- case uniq_dups of [f] -> do isDir <- doesDirectoryReallyExist f if isDir then return $ "The following directory " ++ msgIs msgs ++ " already in the repository" else return $ "The following file " ++ msgIs msgs ++ " already in the repository" fs -> do areDirs <- mapM doesDirectoryReallyExist fs if and areDirs then return $ "The following directories " ++ msgAre msgs ++ " already in the repository" else (if or areDirs then return $ "The following files and directories " ++ msgAre msgs ++ " already in the repository" else return $ "The following files " ++ msgAre msgs ++ " already in the repository") putWarning opts . text $ dupMsg ++ caseMsg mapM_ (putWarning opts . text) uniq_dups return $ foldr (joinGap (+>+)) (emptyGap NilFL) ps where addp' :: Tree IO -> FilePath -> IO (Tree IO, Maybe (FreeLeft (FL prim)), Maybe FilePath) addp' cur f = do already_has <- (if gotAllowCaseOnly then treeHas else treeHasAnycase) cur f mstatus <- getFileStatus f case (already_has, is_badfilename, mstatus) of (True, _, _) -> return (cur, Nothing, Just f) (_, True, _) -> do putWarning opts . text $ "The filename " ++ f ++ " is invalid under Windows.\n" ++ "Use --reserved-ok to allow it." return add_failure (_, _, Just s) | isDirectory s -> trypatch $ freeGap (adddir f :>: NilFL) | isRegularFile s -> trypatch $ freeGap (addfile f :>: NilFL) | isSymbolicLink s -> do putWarning opts . text $ "Sorry, file " ++ f ++ " is a symbolic link, which is unsupported by darcs." return add_failure _ -> do putWarning opts . text $ "File "++ f ++" does not exist!" return add_failure where is_badfilename = not (gotAllowWindowsReserved || WindowsFilePath.isValid f) add_failure = (cur, Nothing, Nothing) trypatch :: FreeLeft (FL prim) -> IO (Tree IO, Maybe (FreeLeft (FL prim)), Maybe FilePath) trypatch p = do perms <- getPermissions f if not $ readable perms then do putWarning opts . text $ msgSkipping msgs ++ " '" ++ f ++ "': permission denied " return (cur, Nothing, Nothing) else trypatch' p trypatch' p = do Sealed p' <- return $ unFreeLeft p ok <- treeHasDir cur parentdir if ok then do tree <- applyToTree p' cur putVerbose opts . text $ msgAdding msgs ++ " '" ++ f ++ "'" return (tree, Just p, Nothing) else do putWarning opts . text $ msgSkipping msgs ++ " '" ++ f ++ "' ... couldn't add parent directory '" ++ parentdir ++ "' to repository" return (cur, Nothing, Nothing) `catch` \(e :: IOException) -> do putWarning opts . text $ msgSkipping msgs ++ " '" ++ f ++ "' ... " ++ show e return (cur, Nothing, Nothing) parentdir = takeDirectory f gotAllowCaseOnly = doAllowCaseOnly opts gotAllowWindowsReserved = doAllowWindowsReserved opts data AddMessages = AddMessages { msgSkipping :: String , msgAdding :: String , msgIs :: String , msgAre :: String } normalMessages :: AddMessages normalMessages = AddMessages { msgSkipping = "Skipping" , msgAdding = "Adding" , msgIs = "is" , msgAre = "are" } dryRunMessages :: AddMessages dryRunMessages = AddMessages { msgSkipping = "Would skip" , msgAdding = "Would add" , msgIs = "would be" , msgAre = "would be" } doesDirectoryReallyExist :: FilePath -> IO Bool doesDirectoryReallyExist f = maybe False isDirectory `fmap` getFileStatus f expandDirs :: [SubPath] -> IO [SubPath] expandDirs fs = liftM (map (fromJust . simpleSubPath)) $ concat `fmap` mapM (expandOne . toPath) fs expandOne :: FilePath -> IO [FilePath] expandOne "" = listFiles expandOne f = do isdir <- doesDirectoryReallyExist f if not isdir then return [f] else do fs <- withCurrentDirectory f listFiles return $ f: map (f ) fs getParents :: Tree IO -> [FilePath] -> [FilePath] getParents cur = map (anchorPath "") . go . map floatPath where go fs = filter (isNothing . findTree cur) $ concatMap parents fs darcs-2.8.4/src/Darcs/Commands/AmendRecord.hs0000644001765600176560000003435312104371431020254 0ustar ganeshganesh-- Copyright (C) 2004,2007 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. -- | -- Module : Darcs.Commands.AmendRecord -- Copyright : 2004, 2007 David Roundy -- License : GPL -- Maintainer : darcs-devel@darcs.net -- Stability : experimental -- Portability : portable module Darcs.Commands.AmendRecord ( amendrecord , amendunrecord ) where #include "gadts.h" import Data.Maybe ( isJust, isNothing ) import Data.List ( intersect ) import Control.Applicative ( (<$>) ) import Control.Monad ( when, unless ) import System.Directory ( removeFile ) import System.Exit ( ExitCode(..), exitWith ) import Darcs.Arguments ( DarcsFlag ( All, AmendUnrecord, Unified ), fixSubPaths, setEnvDarcsFiles, allInteractive, ignoretimes, askLongComment, askdeps, keepDate, author, patchnameOption, leaveTestDir, nocompress, lookforadds, workingRepoDir, matchOneNontag, umaskOption, test, listRegisteredFiles, getEasyAuthor, setScriptsExecutableOption, amendUnrecord , unified ) import Darcs.Commands ( DarcsCommand(..), commandAlias, nodefaults ) import Darcs.Commands.Record ( getDate, getLog, askAboutDepends ) import Darcs.Commands.Util ( announceFiles ) import Darcs.Flags ( DarcsFlag(Author, LogFile, PatchName, AskDeps, EditLongComment, PromptLongComment, KeepDate) , isInteractive , diffingOpts, compression, removeFromAmended ) import Darcs.Lock ( worldReadableTemp ) import Darcs.Patch ( RepoPatch, description, PrimOf, fromPrims, infopatch, getdeps, adddeps, effect, invertFL ) import Darcs.Patch.Apply ( ApplyState ) import Darcs.Patch.Info ( piAuthor, piName, piLog, piDateString, PatchInfo, patchinfo, isInverted, isTag, invertName, ) import Darcs.Patch.Prim ( canonizeFL ) import Darcs.Patch.Split ( primSplitter ) import Darcs.Patch.PatchInfoAnd ( PatchInfoAnd, n2pia, hopefully, info, patchDesc ) import Darcs.RepoPath ( toFilePath, SubPath() ) import Darcs.Repository ( Repository, withRepoLock, RepoJob(..), withGutsOf, tentativelyRemovePatches, tentativelyAddPatch, finalizeRepositoryChanges, amInHashedRepository , invalidateIndex, unrecordedChanges , testTentative , readRecorded ) import Darcs.Repository.Prefs ( globalPrefsDirDoc ) import Darcs.SelectChanges ( selectChanges, WhichChanges(..), selectionContextPrim, runSelection, withSelectedPatchFromRepo ) import Darcs.Utils ( askUser, clarifyErrors, PromptConfig(..), promptChar ) import Darcs.Witnesses.Ordered ( FL(..), (:>)(..), (+>+), nullFL, reverseRL ) import Printer ( putDocLn ) import Storage.Hashed.Tree( Tree ) amendrecordDescription :: String amendrecordDescription = "Improve a patch before it leaves your repository." amendrecordHelp :: String amendrecordHelp = "Amend-record updates a `draft' patch with additions or improvements,\n" ++ "resulting in a single `finished' patch. This is better than recording\n" ++ "the additions and improvements as separate patches, because then\n" ++ "whenever the `draft' patch is copied between repositories, you would\n" ++ "need to make sure all the extra patches are copied, too.\n" ++ "\n" ++ "Do not copy draft patches between repositories, because a finished\n" ++ "patch cannot be copied into a repository that contains a draft of the\n" ++ "same patch. If this has already happened, `darcs obliterate' can be\n" ++ "used to remove the draft patch.\n" ++ "\n" ++ -- FIXME: is the following still true in Darcs 2.1? --twb "Do not run amend-record in repository that other developers can pull\n" ++ "from, because if they pull while an amend-record is in progress, their\n" ++ "repository may be corrupted.\n" ++ "\n" ++ "When recording a draft patch, it is a good idea to start the name with\n" ++ "`DRAFT:' so that other developers know it is not finished. When\n" ++ "finished, remove it with `darcs amend-record --edit-long-comment'.\n" ++ "To change the patch name without starting an editor, use --patch-name.\n" ++ "\n" ++ "Like `darcs record', if you call amend-record with files as arguments,\n" ++ "you will only be asked about changes to those files. So to amend a\n" ++ "patch to foo.c with improvements in bar.c, you would run:\n" ++ "\n" ++ " darcs amend-record --match 'touch foo.c' bar.c\n" ++ "\n" ++ "It is usually a bad idea to amend another developer's patch. To make\n" ++ "amend-record only ask about your own patches by default, you can add\n" ++ "something like `amend-record match David Roundy' to " ++ globalPrefsDirDoc ++ "defaults, \n" ++ "where `David Roundy' is your name.\n" amendrecord :: DarcsCommand amendrecord = DarcsCommand { commandProgramName = "darcs" , commandName = "amend-record" , commandHelp = amendrecordHelp , commandDescription = amendrecordDescription , commandExtraArgs = -1 , commandExtraArgHelp = ["[FILE or DIRECTORY]..."] , commandCommand = amendrecordCmd , commandPrereq = amInHashedRepository , commandGetArgPossibilities = listRegisteredFiles , commandArgdefaults = nodefaults , commandAdvancedOptions = [ nocompress , ignoretimes , umaskOption , setScriptsExecutableOption ] , commandBasicOptions = [ matchOneNontag , test , leaveTestDir , allInteractive , author , patchnameOption , askdeps , askLongComment , keepDate , lookforadds , workingRepoDir , amendUnrecord , unified ] } amendunrecord :: DarcsCommand amendunrecord = (commandAlias "amend-unrecord" Nothing amendrecord) { commandCommand = \fs -> commandCommand amendrecord (AmendUnrecord : fs) , commandDescription = "Alias for `darcs " ++ commandName amendrecord ++ " --unrecord '.\n" ++ "This allows changes already recorded in the patch to be removed." } amendrecordCmd :: [DarcsFlag] -> [String] -> IO () amendrecordCmd opts [] = doAmendRecord opts Nothing amendrecordCmd opts args = do files <- fixSubPaths opts args if null files then fail "No valid arguments were given, nothing to do." else doAmendRecord opts $ Just files doAmendRecord :: [DarcsFlag] -> Maybe [SubPath] -> IO () doAmendRecord opts files = withRepoLock opts $ RepoJob $ \(repository :: Repository p C(r u r)) -> do withSelectedPatchFromRepo "amend" repository opts $ \ (_ :> oldp) -> do announceFiles files "Amending changes in" -- auxiliary function needed because the witness types differ for the isTag case pristine <- readRecorded repository let go :: FORALL(u1) FL (PrimOf p) C(r u1) -> IO () go NilFL | not (hasEditMetadata opts) = putStrLn "No changes!" go ch = do let context = selectionContextPrim "add" (intersect [All,Unified] opts) (Just primSplitter) (map toFilePath <$> files) (Just pristine) (chosenPatches :> _) <- runSelection (selectChanges First ch) context addChangesToPatch opts repository oldp chosenPatches if not (isTag (info oldp)) -- amending a normal patch then if removeFromAmended opts then do let sel = selectChanges Last (effect oldp) context = selectionContextPrim "unrecord" (intersect [All,Unified] opts) (Just primSplitter) (map toFilePath <$> files) (Just pristine) (_ :> chosenPrims) <- runSelection sel context let invPrims = reverseRL (invertFL chosenPrims) addChangesToPatch opts repository oldp invPrims else go =<< unrecordedChanges (diffingOpts opts) repository files -- amending a tag else if hasEditMetadata opts && isNothing files -- the user is not trying to add new changes to the tag so there is -- no reason to warn. then go NilFL -- the user is trying to add new changes to a tag. else do if hasEditMetadata opts -- the user already knows that it is possible to edit tag metadata, -- note that s/he is providing editing options! then putStrLn "You cannot add new changes to a tag." -- the user may not be aware that s/he can edit tag metadata. else putStrLn "You cannot add new changes to a tag, but you are allowed to edit tag's metadata (see darcs help amend-record)." go NilFL addChangesToPatch :: forall p C(r u t x y) . (RepoPatch p, ApplyState p ~ Tree) => [DarcsFlag] -> Repository p C(r u t) -> PatchInfoAnd p C(x t) -> FL (PrimOf p) C(t y) -> IO () addChangesToPatch opts repository oldp chs = if (nullFL chs && not (hasEditMetadata opts)) then putStrLn "You don't want to record anything!" else do invalidateIndex repository withGutsOf repository $ do repository' <- tentativelyRemovePatches repository (compression opts) (oldp :>: NilFL) (mlogf, newp) <- updatePatchHeader opts repository' oldp chs setEnvDarcsFiles newp repository'' <- tentativelyAddPatch repository' (compression opts) newp let failmsg = maybe "" (\lf -> "\nLogfile left in "++lf++".") mlogf rc <- testTentative repository when (rc /= ExitSuccess) $ do when (not $ isInteractive opts) $ exitWith rc `clarifyErrors` failmsg putStrLn $ "Looks like you have a bad patch: '" ++ patchDesc newp ++ "'" let prompt = "Shall I amend it anyway?" yn <- promptChar (PromptConfig prompt "yn" [] (Just 'n') []) case yn of 'y' -> return () _ -> exitWith rc `clarifyErrors` failmsg finalizeRepositoryChanges repository'' `clarifyErrors` failmsg maybe (return ()) removeFile mlogf putStrLn "Finished amending patch:" putDocLn $ description newp updatePatchHeader :: forall p C(x y r u t) . (RepoPatch p, ApplyState p ~ Tree) => [DarcsFlag] -> Repository p C(r u t) -> PatchInfoAnd p C(t x) -> FL (PrimOf p) C(x y) -> IO (Maybe String, PatchInfoAnd p C(t y)) updatePatchHeader opts repository oldp chs = do let newchs = canonizeFL (effect oldp +>+ chs) let old_pdeps = getdeps $ hopefully oldp newdeps <- if AskDeps `elem` opts then askAboutDepends repository newchs opts old_pdeps else return old_pdeps let old_pinf = info oldp prior = (piName old_pinf, piLog old_pinf) make_log = worldReadableTemp "darcs-amend-record" old_author = piAuthor old_pinf date <- if KeepDate `elem` opts then return (piDateString old_pinf) else getDate opts warnIfHijacking opts old_author (new_name, new_log, mlogf) <- getLog opts (Just prior) make_log chs let new_author = case getAuthor opts of Just a -> a Nothing -> piAuthor old_pinf maybe_invert = if isInverted old_pinf then invertName else id new_pinf <- maybe_invert `fmap` patchinfo date new_name new_author new_log let newp = n2pia (adddeps (infopatch new_pinf (fromPrims newchs)) newdeps) return (mlogf, newp) warnIfHijacking :: [DarcsFlag] -> String -> IO () warnIfHijacking opts old_author = do authors_here <- getEasyAuthor let edit_author = isJust (getAuthor opts) unless (edit_author || any (== old_author) authors_here) $ do yorn <- askUser $ "You're not " ++ old_author ++"! Amend anyway? " case yorn of ('y':_) -> return () _ -> exitWith ExitSuccess hasEditMetadata :: [DarcsFlag] -> Bool hasEditMetadata [] = False hasEditMetadata (Author _:_) = True hasEditMetadata (LogFile _:_) = True hasEditMetadata (PatchName _:_) = True hasEditMetadata (EditLongComment:_) = True hasEditMetadata (PromptLongComment:_) = True hasEditMetadata (AskDeps:_) = True hasEditMetadata (_:fs) = hasEditMetadata fs getAuthor :: [DarcsFlag] -> Maybe String getAuthor (Author a:_) = Just a getAuthor (_:as) = getAuthor as getAuthor [] = Nothing darcs-2.8.4/src/Darcs/Commands/Annotate.hs0000644001765600176560000001571312104371431017641 0ustar ganeshganesh-- Copyright (C) 2003 David Roundy, 2010-2011 Petr Rockai -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP, OverloadedStrings #-} {-# OPTIONS_GHC -cpp #-} module Darcs.Commands.Annotate ( annotate ) where import Control.Monad ( when ) import Darcs.Commands ( DarcsCommand(..), nodefaults ) import Darcs.Arguments ( DarcsFlag(..), workingRepoDir, summary, unified, machineReadable, creatorhash, fixSubPaths, listRegisteredFiles, matchOne, ) import Darcs.Flags ( isUnified ) import Storage.Hashed.Plain( readPlainTree ) import Darcs.Repository.State ( readRecorded ) import Darcs.Repository ( Repository, amInHashedRepository, withRepository, RepoJob(..), readRepo ) import Darcs.Patch.Set ( newset2RL ) import Darcs.Patch ( RepoPatch, Named, patch2patchinfo, invertRL ) import Darcs.Patch.Apply( ApplyState ) import qualified Darcs.Patch ( summary ) import qualified Data.ByteString.Char8 as BC ( pack, concat, intercalate ) import Data.ByteString.Lazy ( toChunks ) import Darcs.PrintPatch ( printPatch, contextualPrintPatch ) import Darcs.Patch.ApplyMonad( withFileNames ) import Darcs.Patch.FileName( fp2fn ) import System.FilePath( () ) import Darcs.RepoPath( toFilePath ) import Darcs.Patch.Info ( humanFriendly, showPatchInfo ) import Darcs.Match ( matchPatch, haveNonrangeMatch, getFirstMatch, getOnePatchset, getNonrangeMatchS ) import Darcs.Lock ( withTempDir ) import Darcs.Witnesses.Sealed ( Sealed2(..), Sealed(..), seal ) import qualified Darcs.Annotate as A import Printer ( putDocLn, Doc ) import Storage.Hashed.Tree( Tree, TreeItem(..), readBlob, list, expand ) import Storage.Hashed.Monad( findM, virtualTreeIO ) import Storage.Hashed.AnchoredPath( floatPath, anchorPath ) #include "gadts.h" #include "impossible.h" annotateDescription :: String annotateDescription = "Display which patch last modified something." annotateHelp :: String annotateHelp = "The `darcs annotate' command provides two unrelated operations. When\n" ++ "called on a file, it will find the patch that last modified each line\n" ++ "in that file. When called on a patch (e.g. using --patch), it will\n" ++ "print the internal representation of that patch.\n" ++ "\n" ++ "The --summary option will result in a summarized patch annotation,\n" ++ "similar to `darcs whatsnew'. It has no effect on file annotations.\n" ++ "\n" ++ "By default, output is in a human-readable format. The --machine-readable\n" ++ "option can be used to generate output for machine postprocessing.\n" annotate :: DarcsCommand annotate = DarcsCommand {commandProgramName = "darcs", commandName = "annotate", commandHelp = annotateHelp, commandDescription = annotateDescription, commandExtraArgs = -1, commandExtraArgHelp = ["[FILE or DIRECTORY]..."], commandCommand = annotateCmd, commandPrereq = amInHashedRepository, commandGetArgPossibilities = listRegisteredFiles, commandArgdefaults = nodefaults, commandAdvancedOptions = [], commandBasicOptions = [summary,unified, machineReadable, matchOne, creatorhash, workingRepoDir]} annotateCmd :: [DarcsFlag] -> [String] -> IO () annotateCmd opts files = withRepository opts (RepoJob (annotate' opts files)) annotate' :: (RepoPatch p, ApplyState p ~ Tree) => [DarcsFlag] -> [String] -> Repository p C(r u r) -> IO () annotate' opts [] repository = do when (not $ haveNonrangeMatch opts) $ fail $ "Annotate requires either a patch pattern or a " ++ "file or directory argument." Sealed2 p <- matchPatch opts `fmap` readRepo repository if Summary `elem` opts then do putDocLn $ showpi $ patch2patchinfo p putDocLn $ show_summary p else if isUnified opts then withTempDir "context" $ \_ -> do getFirstMatch repository opts c <- readPlainTree "." contextualPrintPatch c p else printPatch p where showpi | MachineReadable `elem` opts = showPatchInfo | otherwise = humanFriendly show_summary :: RepoPatch p => Named p C(x y) -> Doc show_summary = Darcs.Patch.summary annotate' opts [""] repository = annotate' opts [] repository annotate' opts args@[_] repository = do r <- readRepo repository (origpath:_) <- fixSubPaths opts args recorded <- readRecorded repository (Sealed patches, initial, path) <- if haveNonrangeMatch opts then do Sealed x <- getOnePatchset repository opts let fn = [fp2fn $ toFilePath origpath] nonRangeMatch = getNonrangeMatchS opts r (_, [path], _) = withFileNames Nothing fn nonRangeMatch initial <- snd `fmap` virtualTreeIO (getNonrangeMatchS opts r) recorded return $ (seal $ newset2RL x, initial, toFilePath path) else return $ (seal $ newset2RL r, recorded, toFilePath origpath) found <- findM initial (floatPath $ toFilePath path) -- TODO need to decide about the --machine flag let fmt = if MachineReadable `elem` opts then A.machineFormat else A.format case found of Nothing -> fail $ "No such file or directory: " ++ toFilePath path Just (SubTree s) -> do s' <- expand s let subs = map (fp2fn . (path ) . anchorPath "" . fst) $ list s' showPath (n, File _) = BC.pack (path n) showPath (n, _) = BC.concat [BC.pack (path n), "/"] putStrLn $ fmt (BC.intercalate "\n" $ map showPath $ map (\(x,y) -> (anchorPath "" x, y)) $ list s') $ A.annotateDirectory (invertRL patches) (fp2fn $ "./" ++ path) subs Just (File b) -> do con <- BC.concat `fmap` toChunks `fmap` readBlob b putStrLn $ fmt con $ A.annotate (invertRL patches) (fp2fn $ "./" ++ path) con Just (Stub _ _) -> impossible annotate' _ _ _ = fail "annotate accepts at most one argument" darcs-2.8.4/src/Darcs/Commands/Apply.hs0000644001765600176560000004270312104371431017154 0ustar ganeshganesh-- Copyright (C) 2003-2005 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP, PatternGuards #-} module Darcs.Commands.Apply ( apply, getPatchBundle ) where import System.Exit ( ExitCode(..), exitWith ) import Prelude hiding ( catch ) import System.IO ( hClose, stdout, stderr ) import Control.Exception.Extensible ( catch, fromException, SomeException, throwIO ) import Control.Monad ( when ) import Darcs.Patch.PatchInfoAnd ( PatchInfoAnd, hopefullyM, info ) import Darcs.SignalHandler ( withSignalsBlocked ) import Darcs.Commands ( DarcsCommand(..), putVerbose ) import Darcs.CommandsAux ( checkPaths ) import Darcs.Arguments ( DarcsFlag( All, Interactive, Reply ) , allInteractive , applyConflictOptions , changesReverse , dryRun , fixFilePathOrStd , getCc , getSendmailCmd , happyForwarding , ignoretimes , leaveTestDir , listFiles , makeScriptsExecutable , matchSeveral , nocompress , notest , pauseForGui , printDryRunMessageAndExit , reply , restrictPaths , sendmailCmd , setEnvDarcsPatches , setScriptsExecutableOption , umaskOption , useExternalMerge , verify , workingRepoDir ) import Darcs.Flags(doHappyForwarding, doReverse, isInteractive) import qualified Darcs.Arguments as DarcsArguments ( ccApply ) import Darcs.RepoPath ( toFilePath, useAbsoluteOrStd ) import Darcs.Repository ( Repository, SealedPatchSet, withRepoLock, RepoJob(..), amInHashedRepository, tentativelyMergePatches, readRepo, finalizeRepositoryChanges, testTentative, applyToWorking, invalidateIndex ) #ifdef GADT_WITNESSES import Darcs.Patch.Set ( Origin ) #endif import Darcs.Patch.Set ( newset2RL ) import Darcs.Patch ( RepoPatch, description, PrimOf ) import Darcs.Patch.Apply( ApplyState ) import Darcs.Patch.Info ( PatchInfo, humanFriendly ) import Darcs.Utils ( PromptConfig(..), promptChar ) import Darcs.Witnesses.Ordered ( FL, RL(..), (:\/:)(..), (:>)(..), mapFL, mapRL, nullFL, reverseFL ) import ByteStringUtils ( linesPS, unlinesPS, gzReadFilePS, gzReadStdin ) import Data.List( (\\) ) import qualified Data.ByteString as B (ByteString, null, init, take, drop) import qualified Data.ByteString.Char8 as BC (unpack, last, pack) import Darcs.External ( sendEmail, sendEmailDoc, resendEmail, verifyPS ) import Darcs.Email ( readEmail ) import Darcs.Lock ( withStdoutTemp, readBinFile ) import Darcs.Patch.Depends ( findUncommon, findCommonWithThem ) import Darcs.SelectChanges ( selectChanges, WhichChanges(..), runSelection, selectionContext, filterOutConflicts ) import Darcs.Patch.Bundle ( scanBundle ) import Darcs.Witnesses.Sealed ( Sealed(Sealed) ) import Printer ( packedString, vcat, text, empty, renderString ) import Storage.Hashed.Tree( Tree ) #include "impossible.h" #include "gadts.h" applyDescription :: String applyDescription = "Apply a patch bundle created by `darcs send'." applyHelp :: String applyHelp = "The `darcs apply' command takes a patch bundle and attempts to insert\n" ++ "it into the current repository. In addition to invoking it directly\n" ++ "on bundles created by `darcs send', it is used internally by `darcs\n" ++ "push' and `darcs put' on the remote end of an SSH connection.\n" ++ "\n" ++ "If no file is supplied, the bundle is read from standard input.\n" ++ "\n" ++ "If given an email instead of a patch bundle, Darcs will look for the\n" ++ "bundle as a MIME attachment to that email. Currently this will fail\n" ++ "if the MIME boundary is rewritten, such as in Courier and Mail.app.\n" ++ "\n" ++ "If the `--reply noreply@example.net' option is used, and the bundle is\n" ++ "attached to an email, Darcs will send a report (indicating success or\n" ++ "failure) to the sender of the bundle (the To field). The argument to\n" ++ "noreply is the address the report will appear to originate FROM.\n" ++ "\n" ++ "The --cc option will cause the report to be CC'd to another address,\n" ++ "for example `--cc reports@lists.example.net,admin@lists.example.net'.\n" ++ "Using --cc without --reply is undefined.\n" ++ "\n" ++ "If gpg(1) is installed, you can use `--verify pubring.gpg' to reject\n" ++ "bundles that aren't signed by a key in pubring.gpg.\n" ++ "\n" ++ "If --test is supplied and a test is defined (see `darcs setpref'), the\n" ++ "bundle will be rejected if the test fails after applying it. In that\n" ++ "case, the rejection email from --reply will include the test output.\n" stdindefault :: a -> [String] -> IO [String] stdindefault _ [] = return ["-"] stdindefault _ x = return x apply :: DarcsCommand apply = DarcsCommand {commandProgramName = "darcs", commandName = "apply", commandHelp = applyHelp ++ "\n" ++ applyHelp', commandDescription = applyDescription, commandExtraArgs = 1, commandExtraArgHelp = [""], commandCommand = applyCmd, commandPrereq = amInHashedRepository, commandGetArgPossibilities = listFiles, commandArgdefaults = const stdindefault, commandAdvancedOptions = [ reply , DarcsArguments.ccApply , happyForwarding , sendmailCmd , ignoretimes , nocompress , setScriptsExecutableOption , umaskOption , restrictPaths , changesReverse , pauseForGui ], commandBasicOptions = [verify, allInteractive]++dryRun++ [matchSeveral, applyConflictOptions, useExternalMerge, notest, leaveTestDir, workingRepoDir]} applyCmd :: [DarcsFlag] -> [String] -> IO () applyCmd _ [""] = fail "Empty filename argument given to apply!" applyCmd opts [unfixed_patchesfile] = withRepoLock opts $ RepoJob $ \repository -> do when (unfixed_patchesfile == "-") $ do -- for darcs users who try out 'darcs apply' without any arguments putVerbose opts $ text "reading patch bundle from stdin..." patchesfile <- fixFilePathOrStd opts unfixed_patchesfile ps <- useAbsoluteOrStd (gzReadFilePS . toFilePath) gzReadStdin patchesfile let from_whom = getFrom ps us <- readRepo repository either_them <- getPatchBundle opts ps Sealed them <- case either_them of Right t -> return t Left er -> do forwarded <- considerForwarding opts ps if forwarded then exitWith ExitSuccess else fail er common :> _ <- return $ findCommonWithThem us them -- all patches that are in "them" and not in "common" need to be available; check that let common_i = mapRL info $ newset2RL common them_i = mapRL info $ newset2RL them required = them_i \\ common_i -- FIXME quadratic? check :: RL (PatchInfoAnd p) C(x y) -> [PatchInfo] -> IO () check (p :<: ps') bad = case hopefullyM p of Nothing | info p `elem` required -> check ps' (info p : bad) _ -> check ps' bad check NilRL [] = return () check NilRL bad = fail . renderString $ vcat $ map humanFriendly bad ++ [ text "\nFATAL: Cannot apply this bundle. We are missing the above patches." ] check (newset2RL them) [] (us':\/:them') <- return $ findUncommon us them (hadConflicts, Sealed their_ps) <- filterOutConflicts opts (reverseFL us') repository them' when hadConflicts $ putStrLn "Skipping some patches which would cause conflicts." when (nullFL their_ps) $ do putStr $ "All these patches have already been applied. " ++ "Nothing to do.\n" exitWith ExitSuccess let context = selectionContext "apply" fixed_opts Nothing Nothing selector = selectChanges $ if doReverse opts then FirstReversed else First (to_be_applied :> _) <- runSelection (selector their_ps) context applyItNow opts from_whom repository us' to_be_applied where fixed_opts = if Interactive `elem` opts then opts else All : opts applyCmd _ _ = impossible applyItNow :: FORALL(p r u t x z) (RepoPatch p, ApplyState (PrimOf p) ~ Tree, ApplyState p ~ Tree) => [DarcsFlag] -> String -> Repository p C(r u t) -> FL (PatchInfoAnd p) C(x t) -> FL (PatchInfoAnd p) C(x z) -> IO () applyItNow opts from_whom repository us' to_be_applied = do printDryRunMessageAndExit "apply" opts to_be_applied when (nullFL to_be_applied) $ do putStrLn "You don't want to apply any patches, so I'm exiting!" exitWith ExitSuccess checkPaths opts to_be_applied redirectOutput opts from_whom $ do putVerbose opts $ text "Will apply the following patches:" putVerbose opts . vcat $ mapFL description to_be_applied setEnvDarcsPatches to_be_applied Sealed pw <- tentativelyMergePatches repository "apply" opts us' to_be_applied invalidateIndex repository rc <- testTentative repository when (rc /= ExitSuccess) $ do when (not $ isInteractive opts) $ exitWith rc putStrLn $ "Looks like those patches do not pass the tests." let prompt = "Shall I apply them anyway?" yn <- promptChar (PromptConfig prompt "yn" [] (Just 'n') []) case yn of 'y' -> return () _ -> exitWith rc withSignalsBlocked $ do finalizeRepositoryChanges repository _ <- applyToWorking repository opts pw `catch` \(e :: SomeException) -> fail ("Error applying patch to working dir:\n" ++ show e) makeScriptsExecutable opts pw return () putStrLn "Finished applying..." getPatchBundle :: RepoPatch p => [DarcsFlag] -> B.ByteString -> IO (Either String (SealedPatchSet p C(Origin))) getPatchBundle opts fps = do mps <- verifyPS opts $ readEmail fps mops <- verifyPS opts fps case (mps, mops) of (Nothing, Nothing) -> return $ Left "Patch bundle not properly signed, or gpg failed." (Just ps, Nothing) -> return $ scanBundle ps (Nothing, Just ps) -> return $ scanBundle ps -- We use careful_scan_bundle only below because in either of the two -- above case we know the patch was signed, so it really shouldn't -- need stripping of CRs. (Just ps1, Just ps2) -> case careful_scan_bundle ps1 of Left _ -> return $ careful_scan_bundle ps2 Right x -> return $ Right x where careful_scan_bundle ps = case scanBundle ps of Left e -> case scanBundle $ stripCrPS ps of Right x -> Right x _ -> Left e x -> x stripCrPS :: B.ByteString -> B.ByteString stripCrPS ps = unlinesPS $ map stripline $ linesPS ps stripline p | B.null p = p | BC.last p == '\r' = B.init p | otherwise = p applyHelp' :: String applyHelp' = "A patch bundle may introduce unresolved conflicts with existing\n" ++ "patches or with the working tree. By default, Darcs will add conflict\n" ++ "markers (see `darcs mark-conflicts').\n" ++ "\n" ++ "The --external-merge option lets you resolve these conflicts\n" ++ "using an external merge tool. In the option, '%a' is replaced with\n" ++ "the common ancestor (merge base), '%1' with the first version, '%2'\n" ++ "with the second version, and '%o' with the path where your resolved\n" ++ "content should go. For example, to use the xxdiff visual merge tool\n" ++ "you'd specify: --external-merge='xxdiff -m -O -M %o %1 %a %2'\n" ++ "\n" ++ "The --allow-conflicts option will skip conflict marking; this is\n" ++ "useful when you want to treat a repository as just a bunch of patches,\n" ++ "such as using `darcs pull --union' to download of your co-workers\n" ++ "patches before going offline.\n" ++ "\n" ++ "This can mess up unrecorded changes in the working tree, forcing you\n" ++ "to resolve the conflict immediately. To simply reject bundles that\n" ++ "introduce unresolved conflicts, using the --dont-allow-conflicts\n" ++ "option. Making this the default in push-based workflows is strongly\n" ++ "recommended.\n" ++ "\n" ++ "Unlike most Darcs commands, `darcs apply' defaults to --all. Use the\n" ++ "--interactive option to pick which patches to apply from a bundle.\n" getFrom :: B.ByteString -> String getFrom ps = readFrom $ linesPS ps where readFrom [] = "" readFrom (x:xs) | B.take 5 x == fromStart = BC.unpack $ B.drop 5 x | otherwise = readFrom xs redirectOutput :: forall a . [DarcsFlag] -> String -> IO a -> IO a redirectOutput opts to doit = ro opts where cc = getCc opts ro [] = doit ro (Reply f:_) = withStdoutTemp $ \tempf-> do {a <- doit; hClose stdout; hClose stderr; return a; } `catch` (sendit tempf) where sendit :: FilePath -> SomeException -> IO a sendit tempf e | Just ExitSuccess <- fromException e = do sendSanitizedEmail opts f to "Patch applied" cc tempf throwIO e sendit tempf e | Just (_ :: ExitCode) <- fromException e = do sendSanitizedEmail opts f to "Patch failed!" cc tempf throwIO ExitSuccess sendit tempf e = do sendSanitizedEmail opts f to "Darcs error applying patch!" cc $ tempf ++ "\n\nCaught exception:\n"++ show e++"\n" throwIO ExitSuccess ro (_:fs) = ro fs -- |sendSanitizedEmail sends a sanitized email using the given sendmailcmd -- It takes @DacrsFlag@ options a file with the mail contents, -- To:, Subject:, CC:, and mail body sendSanitizedEmail :: [DarcsFlag] -> String -> String -> String -> String -> String -> IO () sendSanitizedEmail opts file to subject cc mailtext = do scmd <- getSendmailCmd opts body <- sanitizeFile mailtext sendEmail file to subject cc scmd body -- sanitizeFile is used to clean up the stdout/stderr before sticking it in -- an email. sanitizeFile :: FilePath -> IO String sanitizeFile f = sanitize `fmap` readBinFile f where sanitize s = wash $ remove_backspaces "" s wash ('\000':s) = "\\NUL" ++ wash s wash ('\026':s) = "\\EOF" ++ wash s wash (c:cs) = c : wash cs wash [] = [] remove_backspaces rev_sofar "" = reverse rev_sofar remove_backspaces (_:rs) ('\008':s) = remove_backspaces rs s remove_backspaces "" ('\008':s) = remove_backspaces "" s remove_backspaces rs (s:ss) = remove_backspaces (s:rs) ss forwardingMessage :: B.ByteString forwardingMessage = BC.pack $ "The following patch was either unsigned, or signed by a non-allowed\n"++ "key, or there was a GPG failure.\n" considerForwarding :: [DarcsFlag] -> B.ByteString -> IO Bool considerForwarding opts m = cf opts (getCc opts) where cf [] _ = return False cf (Reply t:_) cc = case break is_from (linesPS m) of (m1, f:m2) -> let m_lines = forwardingMessage:m1 ++ m2 m' = unlinesPS m_lines f' = BC.unpack (B.drop 5 f) in if t == f' || t == init f' then return False -- Refuse possible email loop. else do scmd <- getSendmailCmd opts if doHappyForwarding opts then resendEmail t scmd m else sendEmailDoc f' t "A forwarded darcs patch" cc scmd (Just (empty,empty)) (packedString m') return True _ -> return False -- Don't forward emails lacking headers! cf (_:fs) cc = cf fs cc is_from l = B.take 5 l == fromStart fromStart :: B.ByteString fromStart = BC.pack "From:" darcs-2.8.4/src/Darcs/Commands/Changes.hs0000644001765600176560000004357412104371431017446 0ustar ganeshganesh-- Copyright (C) 2003-2004 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP, PatternGuards #-} #include "gadts.h" module Darcs.Commands.Changes ( changes, log ) where import Prelude hiding ( log, catch ) import Unsafe.Coerce (unsafeCoerce) import Data.List ( intersect, sort, nub, find ) import Data.Maybe ( fromMaybe, fromJust, isJust ) import Control.Arrow ( second ) import Control.Exception ( catch, IOException ) import Control.Monad.State.Strict import Control.Applicative ((<$>)) import Darcs.Patch.PatchInfoAnd ( hopefullyM, info ) import Darcs.Commands ( DarcsCommand(..), nodefaults, commandAlias ) import Darcs.Arguments ( DarcsFlag(GenContext, HumanReadable, MachineReadable, Interactive, Count, NumberPatches, XMLOutput, Summary, Verbose, Debug), fixSubPaths, changesFormat, possiblyRemoteRepoDir, getRepourl, workingRepoDir, onlyToFiles, summary, changesReverse, matchSeveralOrRange, matchMaxcount, maxCount, allInteractive, showFriendly, networkOptions ) import Darcs.Flags ( doReverse, showChangesOnlyToFiles, UseIndex(..), ScanKnown(..) ) import Darcs.RepoPath ( SubPath(), toFilePath ) import Darcs.Patch.FileName ( fp2fn, fn2fp, normPath ) import Darcs.Repository ( PatchSet, PatchInfoAnd, withRepositoryDirectory, RepoJob(..), findRepository, readRepo, unrecordedChanges ) import Darcs.Patch.Set ( PatchSet(..), newset2RL ) import Darcs.Patch.Info ( toXml, showPatchInfo, escapeXML, PatchInfo ) import Darcs.Patch.Depends ( findCommonWithThem ) import Darcs.Patch.Bundle( contextPatches ) import Darcs.Patch.TouchesFiles ( lookTouch ) import Darcs.Patch.Apply( ApplyState ) import Darcs.Patch ( RepoPatch, invert, xmlSummary, description, effectOnFilePaths, listTouchedFiles, effect ) import Darcs.Witnesses.Eq ( EqCheck(..) ) import Darcs.Witnesses.Ordered ( FL(NilFL), RL(..), filterFLFL, filterRL, reverseFL, (:>)(..), mapRL ) import Darcs.Match ( firstMatch, secondMatch, matchAPatchread, haveNonrangeMatch, matchFirstPatchset, matchSecondPatchset, ) import Printer ( Doc, putDocLnWith, simplePrinters, (<+>), prefix, text, vcat, vsep, (<>), ($$), errorDoc, insertBeforeLastline ) import Darcs.ColorPrinter ( fancyPrinters ) import Progress ( setProgressMode, debugMessage ) import Darcs.SelectChanges ( viewChanges ) import Darcs.Witnesses.Sealed ( Sealed2(..), unseal2, Sealed(..), seal2 ) import Storage.Hashed.Tree( Tree ) changesDescription :: String changesDescription = "List patches in the repository." changesHelp :: String changesHelp = "The `darcs changes' command lists the patches that constitute the\n" ++ "current repository or, with --repo, a remote repository. Without\n" ++ "options or arguments, ALL patches will be listed.\n" ++ "\n" ++ changesHelp' ++ "\n" ++ changesHelp'' changes :: DarcsCommand changes = DarcsCommand {commandProgramName = "darcs", commandName = "changes", commandHelp = changesHelp, commandDescription = changesDescription, commandExtraArgs = -1, commandExtraArgHelp = ["[FILE or DIRECTORY]..."], commandGetArgPossibilities = return [], commandCommand = changesCmd, commandPrereq = findRepository, commandArgdefaults = nodefaults, commandAdvancedOptions = networkOptions, commandBasicOptions = [matchSeveralOrRange, matchMaxcount, onlyToFiles, changesFormat, summary, changesReverse, possiblyRemoteRepoDir, workingRepoDir, allInteractive]} changesCmd :: [DarcsFlag] -> [String] -> IO () changesCmd opts args | GenContext `elem` opts = if not . null $ args then fail "changes --context cannot accept other arguments" else changesContext opts | null args = showChanges opts Nothing | otherwise = do fs <- fixSubPaths opts args case fs of [] -> putStrLn "No valid arguments were given, nothing to do." _ -> showChanges opts . Just . nub $ sort fs showChanges :: [DarcsFlag] -> Maybe [SubPath] -> IO () showChanges opts files = let repodir = fromMaybe "." (getRepourl opts) in withRepositoryDirectory opts repodir $ RepoJob $ \repository -> do unless (Debug `elem` opts) $ setProgressMode False Sealed unrec <- case files of Nothing -> return $ Sealed NilFL Just _ -> Sealed `fmap` unrecordedChanges (UseIndex, ScanKnown) repository files `catch` \(_ :: IOException) -> return (Sealed NilFL) -- this is triggered when repository is remote let normfp = fn2fp . normPath . fp2fn undoUnrecordedOnFPs = effectOnFilePaths (invert unrec) recFiles = map normfp . undoUnrecordedOnFPs . map toFilePath <$> files filtered_changes p = maybe_reverse $ getChangesInfo opts recFiles p debugMessage "About to read the repository..." patches <- readRepo repository debugMessage "Done reading the repository." if Interactive `elem` opts then do let (fp_and_fs, _, _) = filtered_changes patches fp = map fst fp_and_fs viewChanges opts fp else do when (isJust files && not (XMLOutput `elem` opts)) $ putStrLn $ "Changes to "++unwords (fromJust recFiles)++":\n" debugMessage "About to print the changes..." let printers = if XMLOutput `elem` opts then simplePrinters else fancyPrinters ps <- readRepo repository -- read repo again to prevent holding onto -- values forced by filtered_changes putDocLnWith printers $ changelog opts ps $ filtered_changes patches where maybe_reverse (xs,b,c) = if doReverse opts then (reverse xs, b, c) else (xs, b, c) -- FIXME: this prose is unreadable. --twb, 2009-08 changesHelp' :: String changesHelp' = "When given one or more files or directories as arguments, only\n" ++ "patches which affect those files or directories are listed. This\n" ++ "includes changes that happened to files before they were moved or\n" ++ "renamed.\n" ++ "\n" ++ "When given a --from-tag, --from-patch or --from-match, only changes\n" ++ "since that tag or patch are listed. Similarly, the --to-tag,\n" ++ "--to-patch and --to-match options restrict the list to older patches.\n" ++ "\n" ++ "The --last and --max-count options both limit the number of patches\n" ++ "listed. The former applies BEFORE other filters, whereas the latter\n" ++ "applies AFTER other filters. For example `darcs changes foo.c\n" ++ "--max-count 3' will print the last three patches that affect foo.c,\n" ++ "whereas `darcs changes --last 3 foo.c' will, of the last three\n" ++ "patches, print only those that affect foo.c.\n" getChangesInfo :: (RepoPatch p, ApplyState p ~ Tree) => [DarcsFlag] -> Maybe [FilePath] -> PatchSet p C(x y) -> ( [(Sealed2 (PatchInfoAnd p), [FilePath])] , [(FilePath, FilePath)] , Maybe Doc ) getChangesInfo opts plain_fs ps = case (sp1s, sp2s) of (Sealed p1s, Sealed p2s) -> case findCommonWithThem p2s p1s of _ :> us -> let ps' = filterRL pf (reverseFL us) in case plain_fs of Nothing -> foldr (\x xs -> (x, []) -:- xs) ([], [], Nothing) $ maybe id take (maxCount opts) ps' Just fs -> let fs' = map (\x -> "./" ++ x) fs in filterPatchesByNames (maxCount opts) fs' ps' where sp1s = if firstMatch opts then matchFirstPatchset opts ps else Sealed $ PatchSet NilRL NilRL sp2s = if secondMatch opts then matchSecondPatchset opts ps else Sealed $ ps pf = if haveNonrangeMatch opts then matchAPatchread opts else \_ -> True -- | Take a list of filenames and patches and produce a list of patches that -- actually touch the given files with a list of touched file names, a list of -- original-to-current filepath mappings, indicating the original names of the -- affected files and possibly an error. Additionaly, the function takes a -- "depth limit" -- maxcount, that could be Nothing (return everything) or -- "Just n" -- returns at most n patches touching the file (starting from the -- beginning of the patch list). filterPatchesByNames :: (RepoPatch p, ApplyState p ~ Tree) => Maybe Int -- ^ maxcount -> [FilePath] -- ^ filenames -> [Sealed2 (PatchInfoAnd p)] -- ^ patchlist -> ([(Sealed2 (PatchInfoAnd p),[FilePath])], [(FilePath, FilePath)], Maybe Doc) filterPatchesByNames maxcount fns patches = removeNonRenames $ evalState (filterPatchesByNames' fns patches) (maxcount, initRenames) where removeNonRenames (ps, renames, doc) = (ps, removeIds renames, doc) removeIds = filter (\(a, b) -> a /= b) initRenames = map (\x -> (x, x)) fns returnFinal = (\renames -> ([], renames, Nothing)) <$> gets snd filterPatchesByNames' [] _ = returnFinal filterPatchesByNames' _ [] = returnFinal filterPatchesByNames' fs (s2hp@(Sealed2 hp) : ps) = do (count, renames) <- get let stopNow = case count of Nothing -> False Just c -> c <= 0 if stopNow then returnFinal else case hopefullyM hp of Nothing -> do let err = text "Can't find changes prior to:" $$ description hp return ([], renames, Just err) Just p -> case lookTouch (Just renames) fs (invert p) of (True, affected, [], renames') -> do return ([(s2hp, affected)], renames', Nothing) (True, affected, fs', renames') -> do let sub1Mb c = (subtract 1) <$> c modify $ \(c, _) -> (sub1Mb c, renames') rest <- filterPatchesByNames' fs' ps return $ (s2hp, affected) -:- rest (False, _, fs', renames') -> do modify $ second (const renames') filterPatchesByNames' fs' ps -- | Note, lazy pattern matching is required to make functions like -- filterPatchesByNames lazy in case you are only not interested in -- the first element. E.g.: -- -- let (fs, _, _) = filterPatchesByNames ... (-:-) :: a -> ([a],b,c) -> ([a],b,c) x -:- ~(xs,y,z) = (x:xs,y,z) changelog :: forall p C(start x) . (RepoPatch p, ApplyState p ~ Tree) => [DarcsFlag] -> PatchSet p C(start x) -> ([(Sealed2 (PatchInfoAnd p), [FilePath])], [(FilePath, FilePath)], Maybe Doc) -> Doc changelog opts patchset (pis_and_fs, createdAsFs, mbErr) | Count `elem` opts = text $ show $ length pis_and_fs | MachineReadable `elem` opts = maybe (vsep $ map (unseal2 (showPatchInfo.info)) pis) errorDoc mbErr | XMLOutput `elem` opts = text "" $$ vcat created_as_xml $$ vcat actual_xml_changes $$ text "" | Summary `elem` opts || Verbose `elem` opts = mbAppendErr $ vsep (map (number_patch change_with_summary) pis_and_fs) | otherwise = mbAppendErr $ vsep (map (number_patch description') pis_and_fs) where mbAppendErr = maybe id (\err -> ($$ err)) mbErr change_with_summary :: (Sealed2 (PatchInfoAnd p), [FilePath]) -> Doc change_with_summary (Sealed2 hp, fs) | Just p <- hopefullyM hp = if showChangesOnlyToFiles opts then description hp $$ text "" $$ indent (showFriendly opts (filterFLFL xx $ effect p)) else showFriendly opts p | otherwise = description hp $$ indent (text "[this patch is unavailable]") where xx x = case listTouchedFiles x of ys | null $ ys `intersect` fs -> unsafeCoerce IsEq -- in that case, the change does not affect the patches we are -- looking at, so we ignore the difference between the two states. -- It's all read-only anyway. _ -> NotEq xml_with_summary (Sealed2 hp) | Just p <- hopefullyM hp = insertBeforeLastline (toXml $ info hp) (indent $ xmlSummary p) xml_with_summary (Sealed2 hp) = toXml (info hp) indent = prefix " " actual_xml_changes = if Summary `elem` opts then map xml_with_summary pis else map (toXml . (unseal2 info)) pis created_as_xml = map create createdAsFs where create rename@(_, as) = createdAsXml (first_change_of as) rename -- We need to reorder the patches when they haven't been reversed -- already, so that we find the *first* patch that modifies a given -- file, not the last (by default, the list is oldest->newest). reorderer = if not (doReverse opts) then reverse else id oldest_first_pis_and_fs = reorderer pis_and_fs couldnt_find fn = error $ "Couldn't find first patch affecting " ++ fn ++ " in pis_and_fs" mb_first_change_of fn = find ((fn `elem`) . snd) oldest_first_pis_and_fs find_first_change_of fn = fromMaybe (couldnt_find fn) (mb_first_change_of fn) first_change_of = unseal2 info . fst . find_first_change_of number_patch f x = if NumberPatches `elem` opts then case get_number (fst x) of Just n -> text (show n++":") <+> f x Nothing -> f x else f x get_number :: Sealed2 (PatchInfoAnd p) -> Maybe Int get_number (Sealed2 y) = gn 1 (newset2RL patchset) where iy = info y gn :: Int -> RL (PatchInfoAnd p) C(start y) -> Maybe Int gn n (b:<:bs) | seq n (info b) == iy = Just n | otherwise = gn (n+1) bs gn _ NilRL = Nothing pis = map fst pis_and_fs description' = unseal2 description . fst -- FIXME: this prose is unreadable. --twb, 2009-08 changesHelp'' :: String changesHelp'' = "Three output formats exist. The default is --human-readable. You can\n" ++ "also select --context, which is the internal format (as seen in patch\n" ++ "bundles) that can be re-read by Darcs (e.g. `darcs get --context').\n" ++ "\n" ++ "Finally, there is --xml-output, which emits valid XML... unless a the\n" ++ "patch metadata (author, name or description) contains a non-ASCII\n" ++ "character and was recorded in a non-UTF8 locale.\n" ++ "\n" ++ -- FIXME: can't we just disallow the following usage? "Note that while the --context flag may be used in conjunction with\n" ++ "--xml-output or --human-readable, in neither case will darcs get be\n" ++ "able to read the output. On the other hand, sufficient information\n" ++ "WILL be output for a knowledgeable human to recreate the current state\n" ++ "of the repository.\n" changesContext :: [DarcsFlag] -> IO () changesContext opts = do let repodir = fromMaybe "." $ getRepourl opts withRepositoryDirectory opts repodir $ RepoJob $ \repository -> do (_ :> ps') <- contextPatches `fmap` readRepo repository let ps = mapRL (\p -> (seal2 p, [])) ps' unless fancy $ putStrLn "\nContext:\n" putDocLnWith simplePrinters $ changelog opts' emptyset (ps, [], Nothing) where opts' = if fancy then opts else MachineReadable : opts fancy = HumanReadable `elem` opts || XMLOutput `elem` opts emptyset = PatchSet NilRL NilRL log :: DarcsCommand log = commandAlias "log" Nothing changes createdAsXml :: PatchInfo -> (String, String) -> Doc createdAsXml pinfo (current, createdAs) = text "" $$ toXml pinfo $$ text "" darcs-2.8.4/src/Darcs/Commands/Check.hs0000644001765600176560000001625112104371431017103 0ustar ganeshganesh-- Copyright (C) 2002-2005 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. module Darcs.Commands.Check ( check, repair ) where import Prelude hiding ( catch ) import Control.Monad ( when, unless ) import Control.Applicative( (<$>) ) import Control.Exception ( catch, IOException ) import System.Exit ( ExitCode(..), exitWith ) import System.Directory( renameFile ) import Darcs.Commands ( DarcsCommand(..), nodefaults, putInfo ) import Darcs.Arguments ( DarcsFlag(Quiet), test, umaskOption, leaveTestDir, workingRepoDir, ignoretimes ) import Darcs.Flags(willIgnoreTimes) import Darcs.Repository.Repair( replayRepository, checkIndex, replayRepositoryInTemp, RepositoryConsistency(..) ) import Darcs.Repository ( Repository, amInHashedRepository, withRepository, testRecorded, readRecorded, RepoJob(..), withRepoLock, replacePristine, writePatchSet ) import Darcs.Patch ( RepoPatch, showPatch, PrimOf ) import Darcs.Patch.Apply( ApplyState ) import Darcs.Witnesses.Ordered ( FL(..) ) import Darcs.Witnesses.Sealed ( Sealed(..), unFreeLeft ) import Darcs.Repository.Prefs ( filetypeFunction ) import Darcs.Diff( treeDiff ) import Printer ( text, ($$), (<+>) ) import Storage.Hashed.Tree( Tree ) #include "gadts.h" checkDescription :: String checkDescription = "Check the repository for consistency." checkHelp :: String checkHelp = "This command verifies that the patches in the repository, when applied\n" ++ "successively to an empty tree, result in the pristine tree. If not,\n" ++ "the differences are printed and Darcs exits unsucessfully (with a\n" ++ "non-zero exit status).\n" ++ "\n" ++ "If a regression test is defined (see `darcs setpref') it will be run\n" ++ "by `darcs check'. Use the --no-test option to disable this.\n" check :: DarcsCommand check = DarcsCommand {commandProgramName = "darcs", commandName = "check", commandHelp = checkHelp, commandDescription = checkDescription, commandExtraArgs = 0, commandExtraArgHelp = [], commandCommand = checkCmd, commandPrereq = amInHashedRepository, commandGetArgPossibilities = return [], commandArgdefaults = nodefaults, commandAdvancedOptions = [], commandBasicOptions = [ test, leaveTestDir, workingRepoDir, ignoretimes ]} checkCmd :: [DarcsFlag] -> [String] -> IO () checkCmd opts _ = withRepository opts (RepoJob (check' opts)) check' :: forall p C(r u t) . (RepoPatch p, ApplyState p ~ Tree) => [DarcsFlag] -> Repository p C(r u t) -> IO () check' opts repository = do state <- replayRepositoryInTemp repository opts failed <- case state of RepositoryConsistent -> do putInfo opts $ text "The repository is consistent!" rc <- testRecorded repository when (rc /= ExitSuccess) $ exitWith rc return False BrokenPristine newpris -> do brokenPristine newpris return True BrokenPatches newpris _ -> do brokenPristine newpris putInfo opts $ text "Found broken patches." return True bad_index <- case willIgnoreTimes opts of False -> not <$> checkIndex repository (Quiet `elem` opts) True -> return False when bad_index $ putInfo opts $ text "Bad index." exitWith $ if failed || bad_index then ExitFailure 1 else ExitSuccess where brokenPristine newpris = do putInfo opts $ text "Looks like we have a difference..." mc' <- (fmap Just $ readRecorded repository) `catch` (\(_ :: IOException) -> return Nothing) case mc' of Nothing -> do putInfo opts $ text "cannot compute that difference, try repair" putInfo opts $ text "" $$ text "Inconsistent repository" return () Just mc -> do ftf <- filetypeFunction Sealed (diff :: FL (PrimOf p) C(r r2)) <- unFreeLeft `fmap` treeDiff ftf newpris mc :: IO (Sealed (FL (PrimOf p) C(r))) putInfo opts $ case diff of NilFL -> text "Nothing" patch -> text "Difference: " <+> showPatch patch putInfo opts $ text "" $$ text "Inconsistent repository!" repairDescription :: String repairDescription = "Repair a corrupted repository." repairHelp :: String repairHelp = "The `darcs repair' command attempts to fix corruption in the current\n" ++ "repository. Currently it can only repair damage to the pristine tree,\n" ++ "which is where most corruption occurs.\n" repair :: DarcsCommand repair = DarcsCommand {commandProgramName = "darcs", commandName = "repair", commandHelp = repairHelp, commandDescription = repairDescription, commandExtraArgs = 0, commandExtraArgHelp = [], commandCommand = repairCmd, commandPrereq = amInHashedRepository, commandGetArgPossibilities = return [], commandArgdefaults = nodefaults, commandAdvancedOptions = [umaskOption], commandBasicOptions = [workingRepoDir]} repairCmd :: [DarcsFlag] -> [String] -> IO () repairCmd opts _ = withRepoLock opts $ RepoJob $ \repository -> do replayRepository repository opts $ \state -> case state of RepositoryConsistent -> putStrLn "The repository is already consistent, no changes made." BrokenPristine tree -> do putStrLn "Fixing pristine tree..." replacePristine repository tree BrokenPatches tree newps -> do putStrLn "Writing out repaired patches..." _ <- writePatchSet newps opts putStrLn "Fixing pristine tree..." replacePristine repository tree index_ok <- checkIndex repository (Quiet `elem` opts) unless index_ok $ do renameFile "_darcs/index" "_darcs/index.bad" putStrLn "Bad index discarded." darcs-2.8.4/src/Darcs/Commands/Convert.hs0000644001765600176560000003052112104371431017502 0ustar ganeshganesh-- Copyright (C) 2002-2005,2007 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP, MagicHash #-} #include "gadts.h" module Darcs.Commands.Convert ( convert ) where import System.Directory ( setCurrentDirectory, doesDirectoryExist, doesFileExist, createDirectory ) import Workaround ( getCurrentDirectory ) import Control.Monad ( when ) import GHC.Base ( unsafeCoerce# ) import Data.Maybe ( catMaybes ) import qualified Data.ByteString as B import Darcs.Patch.PatchInfoAnd ( PatchInfoAnd, n2pia, info, hopefully ) import Darcs.Commands ( DarcsCommand(..), nodefaults, putInfo ) import Darcs.Arguments ( DarcsFlag ( AllowConflicts, NewRepo, SetScriptsExecutable, UseFormat2 , NoUpdateWorking ) , reponame , setScriptsExecutableOption , networkOptions ) import Darcs.Repository ( Repository, withRepoLock, RepoJob(..), withRepositoryDirectory, readRepo, createRepository, invalidateIndex, optimizeInventory, tentativelyMergePatches, patchSetToPatches, createPristineDirectoryTree, revertRepositoryChanges, finalizeRepositoryChanges, applyToWorking, setScriptsExecutable ) import Darcs.Global ( darcsdir ) import Darcs.Patch ( Named, showPatch, patch2patchinfo, fromPrim, fromPrims, infopatch, adddeps, getdeps, effect, patchcontents ) import Darcs.Witnesses.Eq ( EqCheck(..), (=/\=) ) import Darcs.Witnesses.Ordered ( FL(..), RL(..), bunchFL, mapFL, mapFL_FL, concatFL, mapRL ) import Darcs.Patch.Info ( piRename, piTag, isTag, PatchInfo ) import Darcs.Patch.V1 ( Patch ) import Darcs.Patch.V2 ( RealPatch ) import Darcs.Patch.V1.Commute ( publicUnravel ) import Darcs.Patch.V1.Core ( Patch(PP), isMerger ) import Darcs.Patch.V2.Real ( mergeUnravelled ) import Darcs.Patch.Prim.V1 ( Prim ) import Darcs.Patch.Set ( PatchSet(..), Tagged(..), newset2RL ) import Darcs.RepoPath ( ioAbsoluteOrRemote, toPath ) import Darcs.Repository.Format(identifyRepoFormat, formatHas, RepoProperty(Darcs2)) import Darcs.Repository.Motd ( showMotd ) import Darcs.Utils ( clarifyErrors, askUser, catchall ) import Darcs.ProgressPatches ( progressFL ) import Darcs.Witnesses.Sealed ( FlippedSeal(..), Sealed(..) ) import Printer ( text, ($$) ) import Darcs.ColorPrinter ( traceDoc ) import Darcs.Lock ( writeBinFile ) import Darcs.External ( fetchFilePS, Cachable(Uncachable) ) import System.FilePath.Posix #include "gadts.h" #include "impossible.h" convertDescription :: String convertDescription = "Convert a repository from a legacy format." convertHelp :: String convertHelp = "The current repository format is called `darcs-2'. It was introduced\n" ++ "in Darcs 2.0 and became the default for new projects in Darcs 2.2.\n" ++ "The `darcs convert' command allows existing projects to migrate to\n" ++ "this format from the older `darcs-1' format.\n" ++ "\n" ++ "This command DOES NOT modify the source repository; a new destination\n" ++ "repository is created. It is safe to run this command more than once\n" ++ "on a repository (e.g. for testing), before the final conversion.\n" ++ "\n" ++ convertHelp' ++ "\n" ++ "Due to this limitation, migrating a multi-branch project is a little\n" ++ "awkward. Sorry! Here is the recommended process:\n" ++ "\n" ++ " 1. for each branch `foo', tag that branch with `foo-final';\n" ++ " 2. merge all branches together (--allow-conflicts may help);\n" ++ " 3. run `darcs optimize --reorder' on the result;\n" ++ " 4. run `darcs convert' to create a merged darcs-2 repository;\n" ++ " 5. re-create each branch by calling `darcs get --tag foo-final' on\n" ++ " the darcs-2 repository; and finally\n" ++ " 6. use `darcs obliterate' to delete the foo-final tags.\n" -- | This part of the help is split out because it is used twice: in -- the help string, and in the prompt for confirmation. convertHelp' :: String convertHelp' = "WARNING: the repository produced by this command is not understood by\n" ++ "Darcs 1.x, and patches cannot be exchanged between repositories in\n" ++ "darcs-1 and darcs-2 formats.\n" ++ "\n" ++ "Furthermore, darcs 2 repositories created by different invocations of\n" ++ "this command SHOULD NOT exchange patches, unless those repositories\n" ++ "had no patches in common when they were converted. (That is, within a\n" ++ "set of repos that exchange patches, no patch should be converted more\n" ++ "than once.)\n" convert :: DarcsCommand convert = DarcsCommand {commandProgramName = "darcs", commandName = "convert", commandHelp = convertHelp, commandDescription = convertDescription, commandExtraArgs = -1, commandExtraArgHelp = ["", "[]"], commandCommand = convertCmd, commandPrereq = \_ -> return $ Right (), commandGetArgPossibilities = return [], commandArgdefaults = nodefaults, commandAdvancedOptions = networkOptions, commandBasicOptions = [reponame,setScriptsExecutableOption]} convertCmd :: [DarcsFlag] -> [String] -> IO () convertCmd opts [inrepodir, outname] = convertCmd (NewRepo outname:opts) [inrepodir] convertCmd orig_opts [inrepodir] = do typed_repodir <- ioAbsoluteOrRemote inrepodir let repodir = toPath typed_repodir --test for converting darcs-2 repository format <- identifyRepoFormat repodir when (formatHas Darcs2 format) $ fail "Repository is already in darcs 2 format." putStrLn convertHelp' let vow = "I understand the consequences of my action" putStrLn "Please confirm that you have read and understood the above" vow' <- askUser ("by typing `" ++ vow ++ "': ") when (vow' /= vow) $ fail "User didn't understand the consequences." let opts = UseFormat2:orig_opts showMotd opts repodir mysimplename <- makeRepoName opts repodir createDirectory mysimplename setCurrentDirectory mysimplename createRepository opts writeBinFile (darcsdir++"/hashed_inventory") "" withRepoLock (NoUpdateWorking:opts) $ V2Job $ \repository -> withRepositoryDirectory opts repodir $ V1Job $ \themrepo -> do theirstuff <- readRepo themrepo let patches = mapFL_FL convertNamed $ patchSetToPatches theirstuff inOrderTags = iot theirstuff where iot :: PatchSet p C(s x) -> [PatchInfo] iot (PatchSet _ ts) = iot_ ts iot_ :: RL(Tagged t1) C(t y) -> [PatchInfo] iot_ (Tagged t _ _ :<: ts) = info t : iot_ ts iot_ NilRL = [] outOfOrderTags = catMaybes $ mapRL oot $ newset2RL theirstuff where oot t = if isTag (info t) && not (info t `elem` inOrderTags) then Just (info t, getdeps $ hopefully t) else Nothing fixDep p = case lookup p outOfOrderTags of Just d -> p : concatMap fixDep d Nothing -> [p] convertOne :: Patch Prim C(x y) -> FL (RealPatch Prim) C(x y) convertOne x | isMerger x = case mergeUnravelled $ publicUnravel x of Just (FlippedSeal y) -> case effect y =/\= effect x of IsEq -> y :>: NilFL NotEq -> traceDoc (text "lossy conversion:" $$ showPatch x) fromPrims (effect x) Nothing -> traceDoc (text "lossy conversion of complicated conflict:" $$ showPatch x) fromPrims (effect x) convertOne (PP x) = fromPrim x :>: NilFL convertOne _ = impossible convertFL :: FL (Patch Prim) C(x y) -> FL (RealPatch Prim) C(x y) convertFL = concatFL . mapFL_FL convertOne convertNamed :: Named (Patch Prim) C(x y) -> PatchInfoAnd (RealPatch Prim) C(x y) convertNamed n = n2pia $ adddeps (infopatch (convertInfo $ patch2patchinfo n) $ convertFL $ patchcontents n) (map convertInfo $ concatMap fixDep $ getdeps n) convertInfo n | n `elem` inOrderTags = n | otherwise = maybe n (\t -> piRename n ("old tag: "++t)) $ piTag n applySome xs = do -- TODO this unsafeCoerce hack is because we don't keep track of the repository state properly -- Really sequence_ $ mapFL applySome below should instead be a repeated add operation - -- there doesn't seem to be any reason we need to do a merge here. let repository2 = unsafeCoerce# repository :: Repository (RealPatch Prim) C(a b a) Sealed pw <- tentativelyMergePatches repository2 "convert" (AllowConflicts:opts) NilFL xs finalizeRepositoryChanges repository2 -- this is to clean out pristine.hashed revertRepositoryChanges repository2 _ <- revertable $ applyToWorking repository2 opts pw invalidateIndex repository2 sequence_ $ mapFL applySome $ bunchFL 100 $ progressFL "Converting patch" patches invalidateIndex repository revertable $ createPristineDirectoryTree repository "." when (SetScriptsExecutable `elem` opts) $ setScriptsExecutable -- Copy over the prefs file let prefsRelPath = darcsdir "prefs" "prefs" (fetchFilePS (repodir prefsRelPath) Uncachable >>= B.writeFile prefsRelPath) `catchall` return () optimizeInventory repository putInfo opts $ text "Finished converting." where revertable x = x `clarifyErrors` unlines ["An error may have left your new working directory an inconsistent", "but recoverable state. You should be able to make the new", "repository consistent again by running darcs revert -a."] convertCmd _ _ = fail "You must provide 'convert' with either one or two arguments." makeRepoName :: [DarcsFlag] -> FilePath -> IO String makeRepoName (NewRepo n:_) _ = do exists <- doesDirectoryExist n file_exists <- doesFileExist n if exists || file_exists then fail $ "Directory or file named '" ++ n ++ "' already exists." else return n makeRepoName (_:as) d = makeRepoName as d makeRepoName [] d = case dropWhile (=='.') $ reverse $ takeWhile (\c -> c /= '/' && c /= ':') $ dropWhile (=='/') $ reverse d of "" -> modifyRepoName "anonymous_repo" base -> modifyRepoName base modifyRepoName :: String -> IO String modifyRepoName name = if head name == '/' then mrn name (-1) else do cwd <- getCurrentDirectory mrn (cwd ++ "/" ++ name) (-1) where mrn :: String -> Int -> IO String mrn n i = do exists <- doesDirectoryExist thename file_exists <- doesFileExist thename if not exists && not file_exists then do when (i /= -1) $ putStrLn $ "Directory '"++ n ++ "' already exists, creating repository as '"++ thename ++"'" return thename else mrn n $ i+1 where thename = if i == -1 then n else n++"_"++show i darcs-2.8.4/src/Darcs/Commands/Diff.hs0000644001765600176560000002337412104371431016742 0ustar ganeshganesh-- Copyright (C) 2003-2004 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP #-} module Darcs.Commands.Diff ( diffCommand ) where import System.FilePath.Posix ( takeFileName ) import Workaround ( getCurrentDirectory ) import Darcs.Utils ( askEnter, withCurrentDirectory ) import Control.Monad ( when ) import Data.List ( (\\) ) import Storage.Hashed.Plain( writePlainTree ) import Darcs.External( diffProgram ) import CommandLine ( parseCmd ) import Darcs.Commands ( DarcsCommand(..), nodefaults ) import Darcs.Arguments ( DarcsFlag(AfterPatch, DiffCmd, DiffFlags, LastN) , diffCmdFlag , diffflags , fixSubPaths , matchRange , pauseForGui , storeInMemory , unidiff , workingRepoDir ) import Darcs.Flags ( isNotUnified, wantGuiPause ) import Darcs.Patch.PatchInfoAnd ( info ) import Darcs.RepoPath ( AbsolutePath, SubPath, toFilePath, sp2fn ) import Darcs.Match ( getPartialFirstMatch, getPartialSecondMatch, firstMatch, secondMatch, matchFirstPatchset, matchSecondPatchset ) import Darcs.Repository ( withRepository, RepoJob(..), readRepo, amInHashedRepository, createPristineDirectoryTree, createPartialsPristineDirectoryTree ) import Darcs.Patch.Set ( PatchSet, newset2RL ) import Darcs.Repository.State ( readUnrecorded ) import Darcs.Patch ( RepoPatch ) import Darcs.Witnesses.Ordered ( mapRL ) import Darcs.Patch.Info ( PatchInfo, humanFriendly ) import Darcs.External ( execPipeIgnoreError ) import Darcs.Lock ( withTempDir ) import Darcs.Witnesses.Sealed ( unseal ) import Printer ( Doc, putDoc, vcat, empty, ($$) ) #include "impossible.h" #include "gadts.h" diffDescription :: String diffDescription = "Create a diff between two versions of the repository." diffHelp :: String diffHelp = "The `darcs diff' command compares two versions of the working tree of\n" ++ "the current repository. Without options, the pristine (recorded) and\n" ++ "unrecorded working trees are compared. This is lower-level than\n" ++ "the `darcs whatsnew' command, since it outputs a line-by-line diff,\n" ++ "and it is also slower. As with `darcs whatsnew', if you specify\n" ++ "files or directories, changes to other files are not listed.\n" ++ "The command always uses an external diff utility.\n" ++ "\n" ++ "With the --patch option, the comparison will be made between working\n" ++ "trees with and without that patch. Patches `after' the selected patch\n" ++ "are not present in either of the compared working trees. The\n" ++ "--from-patch and --to-patch options allow the set of patches in the\n" ++ "`old' and `new' working trees to be specified separately.\n" ++ "\n" ++ "The associated tag and match options are also understood, e.g. `darcs\n" ++ "diff --from-tag 1.0 --to-tag 1.1'. All these options assume an\n" ++ "ordering of the patch set, so results may be affected by operations\n" ++ "such as `darcs optimize --reorder'.\n" ++ "\n" ++ "diff(1) is called with the arguments -rN. The --unified option causes\n" ++ "-u to be passed to diff(1). An additional argument can be passed\n" ++ "using --diff-opts, such as --diff-opts=-ud or --diff-opts=-wU9.\n" ++ "\n" ++ "The --diff-command option can be used to specify an alternative\n" ++ "utility, such as meld (GNOME) or opendiff (OS X). Arguments may be\n" ++ "included, separated by whitespace. The value is not interpreted by a\n" ++ "shell, so shell constructs cannot be used. The arguments %1 and %2\n" ++ "MUST be included, these are substituted for the two working trees\n" ++ "being compared. If this option is used, --diff-opts is ignored.\n" diffCommand :: DarcsCommand diffCommand = DarcsCommand {commandProgramName = "darcs", commandName = "diff", commandHelp = diffHelp, commandDescription = diffDescription, commandExtraArgs = -1, commandExtraArgHelp = ["[FILE or DIRECTORY]..."], commandCommand = diffCmd, commandPrereq = amInHashedRepository, commandGetArgPossibilities = return [], commandArgdefaults = nodefaults, commandAdvancedOptions = [ pauseForGui ], commandBasicOptions = [ matchRange , diffCmdFlag , diffflags , unidiff , workingRepoDir , storeInMemory ] } getDiffOpts :: [DarcsFlag] -> [String] getDiffOpts opts | isNotUnified opts = get_nonU_diff_opts opts | otherwise = "-u" : get_nonU_diff_opts opts where get_nonU_diff_opts (DiffFlags f:fs) = f : get_nonU_diff_opts fs get_nonU_diff_opts (_:fs) = get_nonU_diff_opts fs get_nonU_diff_opts [] = [] -- | Returns the command we should use for diff as a tuple (command, arguments). -- This will either be whatever the user specified via --diff-command or the -- default 'diffProgram'. Note that this potentially involves parsing the -- user's diff-command, hence the possibility for failure with an exception. getDiffCmdAndArgs :: String -> [DarcsFlag] -> String -> String -> Either String (String, [String]) getDiffCmdAndArgs cmd opts f1 f2 = helper opts where helper (DiffCmd c:_) = case parseCmd [ ('1', f1) , ('2', f2) ] c of Left err -> Left $ show err Right ([],_) -> bug $ "parseCmd should never return empty list" Right ((h:t),_) -> Right (h,t) helper [] = -- if no command specified, use 'diff' Right (cmd, ("-rN":getDiffOpts opts++[f1,f2])) helper (_:t) = helper t diffCmd :: [DarcsFlag] -> [String] -> IO () diffCmd opts args | not (null [i | LastN i <- opts]) && not (null [p | AfterPatch p <- opts]) = fail $ "using --patch and --last at the same time with the 'diff'" ++ " command doesn't make sense. Use --from-patch to create a diff" ++ " from this patch to the present, or use just '--patch' to view" ++ " this specific patch." | null args = doDiff opts Nothing | otherwise = doDiff opts . Just =<< fixSubPaths opts args doDiff :: [DarcsFlag] -> Maybe [SubPath] -> IO () doDiff opts sps = withRepository opts $ RepoJob $ \repository -> do let pathList = map sp2fn `fmap` sps formerdir <- getCurrentDirectory withTempDirs (takeFileName formerdir) $ \odir ndir -> do if firstMatch opts then withCurrentDirectory odir $ getPartialFirstMatch repository opts pathList else case pathList of Nothing -> createPristineDirectoryTree repository $ toFilePath odir Just pl -> createPartialsPristineDirectoryTree repository pl $ toFilePath odir if secondMatch opts then withCurrentDirectory ndir $ getPartialSecondMatch repository opts pathList else withCurrentDirectory formerdir $ readUnrecorded repository sps >>= (flip writePlainTree (toFilePath ndir)) thediff <- withCurrentDirectory (toFilePath odir ++ "/..") $ case pathList of Nothing -> rundiff (takeFileName $ toFilePath odir) (takeFileName $ toFilePath ndir) Just fs -> vcat `fmap` mapM (\f -> rundiff (takeFileName (toFilePath odir) ++ "/" ++ toFilePath f) (takeFileName (toFilePath ndir) ++ "/" ++ toFilePath f)) fs morepatches <- readRepo repository putDoc $ changelog (getDiffInfo opts morepatches) $$ thediff where rundiff :: String -> String -> IO Doc rundiff f1 f2 = do cmd <- diffProgram case getDiffCmdAndArgs cmd opts f1 f2 of Left err -> fail err Right (d_cmd, d_args) -> let pausingForGui = wantGuiPause opts in do when pausingForGui $ putStrLn $ "Running command '" ++ unwords (d_cmd:d_args) ++ "'" output <- execPipeIgnoreError d_cmd d_args empty when pausingForGui $ askEnter "Hit return to move on..." return output withTempDirs :: String -> (AbsolutePath -> AbsolutePath -> IO a) -> IO a withTempDirs x f = withTempDir ("old-" ++ x) $ \odir -> withTempDir ("new-" ++ x) $ \ndir -> f odir ndir getDiffInfo :: RepoPatch p => [DarcsFlag] -> PatchSet p C(start x) -> [PatchInfo] getDiffInfo opts ps = let infos = mapRL info . newset2RL handle (match_cond, do_match) | match_cond opts = unseal infos (do_match opts ps) | otherwise = infos ps in handle (secondMatch, matchSecondPatchset) \\ handle (firstMatch, matchFirstPatchset) changelog :: [PatchInfo] -> Doc changelog pis = vcat $ map humanFriendly pis darcs-2.8.4/src/Darcs/Commands/Dist.hs0000644001765600176560000001473612104371431016777 0ustar ganeshganesh-- Copyright (C) 2003 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. -- | -- Module : Darcs.Commands.Dist -- Copyright : 2003 David Roundy -- License : GPL -- Maintainer : darcs-devel@darcs.net -- Stability : experimental -- Portability : portable module Darcs.Commands.Dist ( dist ) where import Prelude hiding ( writeFile ) import Data.ByteString.Lazy ( writeFile ) import Data.Char ( isAlphaNum ) import Control.Monad ( when ) import System.Directory ( setCurrentDirectory ) import System.Cmd ( system ) import System.Exit ( ExitCode(..), exitWith ) import System.FilePath.Posix ( takeFileName, () ) import Workaround ( getCurrentDirectory ) import Codec.Archive.Tar ( pack, write ) import Codec.Archive.Tar.Entry ( entryPath ) import Codec.Compression.GZip ( compress ) import Darcs.Arguments ( DarcsFlag(Verbose, Quiet, DistName, SetScriptsExecutable), distnameOption, workingRepoDir, matchOne, storeInMemory, setScriptsExecutableOption ) import Darcs.Commands ( DarcsCommand(..), nodefaults ) import Darcs.Lock ( withTempDir ) import Darcs.Match ( getNonrangeMatch, haveNonrangeMatch, firstMatch, getFirstMatch ) import Darcs.Repository ( amInHashedRepository, withRepoReadLock, RepoJob(..), setScriptsExecutable, createPartialsPristineDirectoryTree ) import Darcs.Repository.Prefs ( getPrefval ) import Darcs.RepoPath ( AbsolutePath, toFilePath ) import Darcs.Utils ( withCurrentDirectory ) distDescription :: String distDescription = "Create a distribution tarball." distHelp :: String distHelp = "The `darcs dist' command creates a compressed archive (a `tarball') in\n" ++ "the repository's root directory, containing the recorded state of the\n" ++ "working tree (unrecorded changes and the _darcs directory are\n" ++ "excluded).\n" ++ "\n" ++ "If a predist command is set (see `darcs setpref'), that command will\n" ++ "be run on the tarball contents prior to archiving. For example,\n" ++ "autotools projects would set it to `autoconf && automake'.\n" ++ "\n" ++ "By default, the tarball (and the top-level directory within the\n" ++ "tarball) has the same name as the repository, but this can be\n" ++ "overridden with the --dist-name option.\n" -- FIXME: this is tedious and ugly. {- ++ "\n" ++ "Suppose you use a version numbering scheme `major.minor.patch', and\n" ++ "you tag each release `major.minor'. You can then calculate the\n" ++ "version number by taking the newest tag and appending a dot and the\n" ++ "number of patches since that tag. If you use the directory name as\n" ++ "the project name, you can make tarballs of the form name-version.tgz\n" ++ "using the following shell script:\n" ++ "\n" ++ " major_minor=$(darcs show tags | head -1) &&\n" ++ " patch_level=$(($(darcs changes --count --from-tag .) - 1)) &&\n" ++ " version=$major_minor.$patch_level &&\n" ++ " project=${PWD##*/} &&\n" ++ " darcs dist --dist-name \"$project\"-\"$version\".tar.gz\n" -} dist :: DarcsCommand dist = DarcsCommand { commandProgramName = "darcs" , commandName = "dist" , commandHelp = distHelp , commandDescription = distDescription , commandExtraArgs = 0 , commandExtraArgHelp = [] , commandCommand = distCmd , commandPrereq = amInHashedRepository , commandGetArgPossibilities = return [] , commandArgdefaults = nodefaults , commandAdvancedOptions = [] , commandBasicOptions = [ distnameOption , workingRepoDir , matchOne , setScriptsExecutableOption , storeInMemory ] } distCmd :: [DarcsFlag] -> [String] -> IO () distCmd opts _ = withRepoReadLock opts $ RepoJob $ \repository -> do formerdir <- getCurrentDirectory let distname = getDistName formerdir [x | DistName x <- opts] predist <- getPrefval "predist" let resultfile = formerdir distname ++ ".tar.gz" withTempDir "darcsdist" $ \tempdir -> do setCurrentDirectory formerdir withTempDir (toFilePath tempdir takeFileName distname) $ \ddir -> do if haveNonrangeMatch opts then if firstMatch opts then withCurrentDirectory ddir $ getFirstMatch repository opts else withCurrentDirectory ddir $ getNonrangeMatch repository opts else createPartialsPristineDirectoryTree repository [""] (toFilePath ddir) ec <- case predist of Nothing -> return ExitSuccess Just pd -> system pd if ec == ExitSuccess then do withCurrentDirectory ddir $ when (SetScriptsExecutable `elem` opts) setScriptsExecutable doDist opts tempdir ddir resultfile else do putStrLn "Dist aborted due to predist failure" exitWith ec -- | This function performs the actual distribution action itself. -- NB - it does /not/ perform the pre-dist, that should already -- have completed successfully before this is invoked. doDist :: [DarcsFlag] -> AbsolutePath -> AbsolutePath -> FilePath -> IO () doDist opts tempdir ddir resultfile = do setCurrentDirectory (toFilePath tempdir) let safeddir = safename $ takeFileName $ toFilePath ddir entries <- pack "." [safeddir] when (Verbose `elem` opts) $ putStr $ unlines $ map entryPath entries writeFile resultfile $ compress $ write entries when (Quiet `notElem` opts) $ putStrLn $ "Created dist as " ++ resultfile where safename n@(c:_) | isAlphaNum c = n safename n = "./" ++ n getDistName :: FilePath -> [String] -> FilePath getDistName _ (dn:_) = dn getDistName currentDirectory _ = takeFileName currentDirectory darcs-2.8.4/src/Darcs/Commands/Get.hs0000644001765600176560000003205012104371431016600 0ustar ganeshganesh-- Copyright (C) 2002-2005 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP #-} module Darcs.Commands.Get ( get, clone ) where import Prelude hiding ( catch ) import System.Directory ( setCurrentDirectory, doesDirectoryExist, doesFileExist, createDirectory ) import Workaround ( getCurrentDirectory ) import Control.Exception ( catch, IOException ) import Control.Monad ( when ) import Darcs.Commands ( DarcsCommand(..), nodefaults, commandAlias, putInfo ) import Darcs.Flags( compression ) import Darcs.Arguments ( DarcsFlag( NewRepo, Lazy, UseFormat2, UseHashedInventory, UseNoWorkingDir, SetScriptsExecutable, OnePattern ), getContext, useWorkingDir, partial, reponame, matchOneContext, setDefault, setScriptsExecutableOption, networkOptions, makeScriptsExecutable, usePacks ) import Darcs.Repository ( Repository, withRepository, RepoJob(..), withRepoLock, identifyRepositoryFor, readRepo, tentativelyRemovePatches, patchSetToRepository, copyRepository, tentativelyAddToPending, finalizeRepositoryChanges, setScriptsExecutable , invalidateIndex, createRepository ) import Darcs.Repository.Format ( identifyRepoFormat, RepoFormat, RepoProperty ( Darcs2, HashedInventory ), formatHas ) import Darcs.Patch ( RepoPatch, apply, invert, effect, PrimOf ) import Darcs.Patch.Apply( ApplyState ) import Darcs.Witnesses.Ordered ( lengthFL, mapFL_FL, (:>)(..) ) import Darcs.Patch.PatchInfoAnd ( hopefully ) import Darcs.Patch.Depends ( findCommonWithThem, countUsThem ) import Darcs.Repository.Prefs ( setDefaultrepo ) import Darcs.Repository.Motd ( showMotd ) import Darcs.Match ( havePatchsetMatch, getOnePatchset ) import Progress ( debugMessage ) import Printer ( text, errorDoc, ($$) ) import Darcs.Lock ( writeBinFile ) import Darcs.RepoPath ( toFilePath, toPath, ioAbsoluteOrRemote) import Darcs.Witnesses.Sealed ( Sealed(..) ) import Darcs.Global ( darcsdir ) import English ( englishNum, Noun(..) ) import Storage.Hashed.Tree( Tree ) #include "gadts.h" getDescription :: String getDescription = "Create a local copy of a repository." getHelp :: String getHelp = "Get creates a local copy of a repository. The optional second\n" ++ "argument specifies a destination directory for the new copy; if\n" ++ "omitted, it is inferred from the source location.\n" ++ "\n" ++ "By default Darcs will copy every patch from the original repository.\n" ++ "This means the copy is completely independent of the original; you can\n" ++ "operate on the new repository even when the original is inaccessible.\n" ++ "If you expect the original repository to remain accessible, you can\n" ++ "use --lazy to avoid copying patches until they are needed (`copy on\n" ++ "demand'). This is particularly useful when copying a remote\n" ++ "repository with a long history that you don't care about.\n" ++ "\n" ++ "The --lazy option isn't as useful for local copies, because Darcs will\n" ++ "automatically use `hard linking' where possible. As well as saving\n" ++ "time and space, you can move or delete the original repository without\n" ++ "affecting a complete, hard-linked copy. Hard linking requires that\n" ++ "the copy be on the same filesystem and the original repository, and\n" ++ "that the filesystem support hard linking. This includes NTFS, HFS+\n" ++ "and all general-purpose Unix filesystems (such as ext3, UFS and ZFS).\n" ++ "FAT does not support hard links.\n" ++ "\n" ++ "Darcs get will not copy unrecorded changes to the source repository's\n" ++ "working tree.\n" ++ "\n" ++ getHelpTag get :: DarcsCommand get = DarcsCommand {commandProgramName = "darcs", commandName = "get", commandHelp = getHelp, commandDescription = getDescription, commandExtraArgs = -1, commandExtraArgHelp = ["", "[]"], commandCommand = getCmd, commandPrereq = contextExists, commandGetArgPossibilities = return [], commandArgdefaults = nodefaults, commandAdvancedOptions = usePacks:networkOptions, commandBasicOptions = [reponame, partial, matchOneContext, setDefault True, setScriptsExecutableOption, useWorkingDir] } clone :: DarcsCommand clone = commandAlias "clone" Nothing get getCmd :: [DarcsFlag] -> [String] -> IO () getCmd opts [inrepodir, outname] = getCmd (NewRepo outname:opts) [inrepodir] getCmd opts [inrepodir] = do debugMessage "Starting work on get..." typed_repodir <- ioAbsoluteOrRemote inrepodir let repodir = toPath typed_repodir showMotd opts repodir rfsource <- identifyRepoFormat repodir debugMessage $ "Found the format of "++repodir++"..." mysimplename <- makeRepoName opts repodir createDirectory mysimplename setCurrentDirectory mysimplename let opts' = if formatHas Darcs2 rfsource then UseFormat2:opts else UseHashedInventory:filter (/= UseFormat2) opts createRepository opts' debugMessage "Finished initializing new directory." setDefaultrepo repodir opts writeBinFile (darcsdir++"/hashed_inventory") "" if not (null [p | OnePattern p <- opts]) -- --to-match given && Lazy `notElem` opts then withRepository opts $ RepoJob $ \repository -> do debugMessage "Using economical get --to-match handling" fromrepo <- identifyRepositoryFor repository repodir Sealed patches_to_get <- getOnePatchset fromrepo opts -- Warning: A do-notation statement discarded a result of type Repository p ghc-prim _ <- patchSetToRepository fromrepo patches_to_get opts debugMessage "Finished converting selected patch set to new repository" else copyRepoAndGoToChosenVersion opts repodir rfsource getCmd _ _ = fail "You must provide 'get' with either one or two arguments." -- | called by getCmd -- assumes that the target repo of the get is the current directory, and that an inventory in the -- right format has already been created. copyRepoAndGoToChosenVersion :: [DarcsFlag] -> String -> RepoFormat -> IO () copyRepoAndGoToChosenVersion opts repodir rfsource = do copyRepo withRepository opts ((RepoJob $ \repository -> goToChosenVersion repository opts) :: RepoJob ()) putInfo opts $ text "Finished getting." where copyRepo = withRepository opts $ RepoJob $ \repository -> if formatHas HashedInventory rfsource then do debugMessage "Identifying and copying repository..." copyRepoHashed repository else do putInfo opts $ text "***********************************************************************" $$ text " _______ Sorry for the wait! The repository you are fetching is" $$ text " | | using the DEPRECATED 'old-fashioned' format. I'm getting a" $$ text " | O O | hashed copy instead, but this may take a while." $$ text " | ___ |" $$ text " | / \\ | We recommend that the maintainer upgrade the remote copy" $$ text " |_______| as well. See http://wiki.darcs.net/OF for more information." $$ text "" $$ text "***********************************************************************" copyRepoHashed repository copyRepoHashed repository = do identifyRepositoryFor repository repodir >>= flip copyRepository (UseNoWorkingDir `notElem` opts) when (SetScriptsExecutable `elem` opts) setScriptsExecutable makeRepoName :: [DarcsFlag] -> FilePath -> IO String makeRepoName (NewRepo n:_) _ = do exists <- doesDirectoryExist n file_exists <- doesFileExist n if exists || file_exists then fail $ "Directory or file named '" ++ n ++ "' already exists." else return n makeRepoName (_:as) d = makeRepoName as d makeRepoName [] d = case dropWhile (=='.') $ reverse $ takeWhile (\c -> c /= '/' && c /= ':') $ dropWhile (=='/') $ reverse d of "" -> modifyRepoName "anonymous_repo" base -> modifyRepoName base modifyRepoName :: String -> IO String modifyRepoName name = if head name == '/' then mrn name (-1) else do cwd <- getCurrentDirectory mrn (cwd ++ "/" ++ name) (-1) where mrn :: String -> Int -> IO String mrn n i = do exists <- doesDirectoryExist thename file_exists <- doesFileExist thename if not exists && not file_exists then do when (i /= -1) $ putStrLn $ "Directory '"++ n ++ "' already exists, creating repository as '"++ thename ++"'" return thename else mrn n $ i+1 where thename = if i == -1 then n else n++"_"++show i getHelpTag :: String getHelpTag = "It is often desirable to make a copy of a repository that excludes\n" ++ "some patches. For example, if releases are tagged then `darcs get\n" ++ "--tag .' would make a copy of the repository as at the latest release.\n" ++ "\n" ++ "An untagged repository state can still be identified unambiguously by\n" ++ "a context file, as generated by `darcs changes --context'. Given the\n" ++ "name of such a file, the --context option will create a repository\n" ++ "that includes only the patches from that context. When a user reports\n" ++ "a bug in an unreleased version of your project, the recommended way to\n" ++ "find out exactly what version they were running is to have them\n" ++ "include a context file in the bug report.\n" ++ "\n" ++ "You can also make a copy of an untagged state using the --to-patch or\n" ++ "--to-match options, which exclude patches `after' the first matching\n" ++ "patch. Because these options treat the set of patches as an ordered\n" ++ "sequence, you may get different results after reordering with `darcs\n" ++ "optimize', so tagging is preferred.\n" contextExists :: [DarcsFlag] -> IO (Either String ()) contextExists opts = case getContext opts of Nothing -> return $ Right () Just f -> do exists <- doesFileExist $ toFilePath f return $ if exists then Right () else Left $ "Context file "++toFilePath f++" does not exist" goToChosenVersion :: (RepoPatch p, ApplyState p ~ Tree, ApplyState (PrimOf p) ~ Tree) => Repository p C(r u r) -> [DarcsFlag] -> IO () goToChosenVersion repository opts = when (havePatchsetMatch opts) $ do debugMessage "Going to specified version..." patches <- readRepo repository Sealed context <- getOnePatchset repository opts when (snd (countUsThem patches context) > 0) $ errorDoc $ text "Missing patches from context!" -- FIXME : - ( _ :> us' <- return $ findCommonWithThem patches context let ps = mapFL_FL hopefully us' putInfo opts $ text $ "Unapplying " ++ show (lengthFL ps) ++ " " ++ englishNum (lengthFL ps) (Noun "patch") "" invalidateIndex repository withRepoLock opts $ RepoJob $ \_ -> -- Warning: A do-notation statement discarded a result of type Repository p r u z. do _ <- tentativelyRemovePatches repository (compression opts) us' tentativelyAddToPending repository opts $ invert $ effect us' finalizeRepositoryChanges repository apply (invert $ effect ps) `catch` \(e :: IOException) -> fail ("Couldn't undo patch in working dir.\n" ++ show e) makeScriptsExecutable opts (invert $ effect ps) darcs-2.8.4/src/Darcs/Commands/GZCRCs.hs0000644001765600176560000002154212104371431017120 0ustar ganeshganesh-- Copyright (C) 2009 Ganesh Sittampalam -- -- 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. {-# LANGUAGE CPP #-} module Darcs.Commands.GZCRCs ( gzcrcs, doCRCWarnings ) where import Control.Arrow ( first ) import Control.Monad ( when, unless ) import Control.Monad.Trans ( liftIO ) import Control.Monad.Writer ( runWriterT, tell ) import Data.List ( intercalate ) import Data.Monoid ( Any(..), Sum(..) ) import qualified Data.ByteString as B import qualified Data.ByteString.Lazy as BL import System.Directory ( getDirectoryContents, doesFileExist, doesDirectoryExist ) import System.Exit ( ExitCode(..), exitWith ) import System.IO ( hPutStr, hPutStrLn, stderr ) import Data.IORef ( newIORef, readIORef, writeIORef ) import Darcs.Commands ( DarcsCommand(..), nodefaults ) import Darcs.Arguments ( DarcsFlag( Quiet, Verbose, Check, Repair, JustThisRepo ), checkOrRepair, workingRepoDir, justThisRepo ) import Darcs.Repository ( Repository, amInRepository, withRepository, RepoJob(..) ) import Darcs.Patch ( RepoPatch ) import Printer ( putDocLn, text ) import ByteStringUtils ( isGZFile ) import Darcs.Lock ( gzWriteAtomicFilePSs ) -- This command needs access beyond the normal repository APIs (to -- get at the caches and inspect them directly) -- Could move the relevant code into Darcs.Repository modules -- but it doesn't really seem worth it. import Darcs.Repository.InternalTypes ( extractCache ) import Darcs.Repository.Cache ( Cache(..), writable, isthisrepo, hashedFilePath, allHashedDirs ) import Darcs.Global ( getCRCWarnings, resetCRCWarnings ) import ByteStringUtils ( gzDecompress ) #include "gadts.h" gzcrcsDescription :: String gzcrcsDescription = "Check or repair the CRCs of compressed files in the repository." gzcrcsHelp :: String gzcrcsHelp = formatText [ "Versions of darcs >=1.0.4 and <2.2.0 had a bug that caused compressed files " ++ "with bad CRCs (but valid data) to be written out. CRCs were not checked on " ++ "reading, so this bug wasn't noticed.", "This command inspects your repository for this corruption and optionally repairs it.", "By default it also does this for any caches you have configured and any other " ++ "local repositories listed as sources of patches for this one, perhaps because of a " ++ "lazy get. You can limit the scope to just the current repo with the --just-this-repo " ++ "flag.", "Note that readonly caches, or other repositories listed as sources, " ++ "will be checked but not repaired. Also, this command will abort if it encounters " ++ "any non-CRC corruption in compressed files.", "You may wish to also run 'darcs check --complete' before repairing the corruption. " ++ "This is not done automatically because it might result in needing to fetch extra " ++ "patches if the repository is lazy.", "If there are any other problems with your repository, you can still repair the CRCs, " ++ "but you are advised to first make a backup copy in case the CRC errors are actually " ++ "caused by bad data and the old CRCs might be useful in recovering that data.", "If you were warned about CRC errors during an operation involving another repository, " ++ "then it is possible that the other repository contains the corrupt CRCs, so you " ++ "should arrange for that repository to also be checked/repaired." ] formatText :: [String] -> String formatText = unlines . intercalate [""] . map (map unwords . para 80 . words) -- |Take a list of words and split it up so that each chunk fits into the specified width -- when spaces are included. Any words longer than the specified width end up in a chunk -- of their own. para :: Int -> [[a]] -> [[[a]]] para w = para' where para' [] = [] para' xs = uncurry (:) $ para'' w xs para'' r (x:xs) | w == r || length x < r = first (x:) $ para'' (r - length x - 1) xs para'' _ xs = ([], para' xs) -- |This is designed for use in an atexit handler, e.g. in Darcs.RunCommand doCRCWarnings :: Bool -> IO () doCRCWarnings verbose = do files <- getCRCWarnings resetCRCWarnings when (not . null $ files) $ do hPutStr stderr . formatText $ ["", "Warning: CRC errors found. These are probably harmless but should " ++ "be repaired. See 'darcs gzcrcs --help' for more information.", ""] when verbose $ hPutStrLn stderr $ unlines ("The following corrupt files were found:":files) gzcrcs :: DarcsCommand gzcrcs = DarcsCommand {commandProgramName = "darcs", commandName = "gzcrcs", commandHelp = gzcrcsHelp, commandDescription = gzcrcsDescription, commandExtraArgs = 0, commandExtraArgHelp = [], commandCommand = gzcrcsCmd, commandPrereq = amInRepository, commandGetArgPossibilities = return [], commandArgdefaults = nodefaults, commandAdvancedOptions = [], commandBasicOptions = [checkOrRepair, justThisRepo, workingRepoDir ]} gzcrcsCmd :: [DarcsFlag] -> [String] -> IO () gzcrcsCmd opts _ | Check `elem` opts || Repair `elem` opts = withRepository opts (RepoJob (gzcrcs' opts)) gzcrcsCmd _ _ = error "You must specify --check or --repair for gzcrcs" gzcrcs' :: (RepoPatch p) => [DarcsFlag] -> Repository p C(r u t) -> IO () gzcrcs' opts repo = do let Ca locs = extractCache repo -- Somewhat ugly IORef use here because it's convenient, would be nicer -- to pre-filter the list of locs to check and then decide whether to -- print the message up front. warnRelatedRepos <- newIORef (JustThisRepo `notElem` opts) ((), Any checkFailed) <- runWriterT $ flip mapM_ locs $ \loc -> do unless (JustThisRepo `elem` opts && not (isthisrepo loc)) $ do let w = writable loc flip mapM_ allHashedDirs $ \hdir -> do let dir = hashedFilePath loc hdir "" exists <- liftIO $ doesDirectoryExist dir when exists $ do liftIO $ do warn <- readIORef warnRelatedRepos when (warn && not (isthisrepo loc)) $ do writeIORef warnRelatedRepos False putInfo $ text "Also checking related repos and caches; use --just-this-repo to disable." liftIO $ putInfo $ text $ "Checking " ++ dir ++ (if w then "" else " (readonly)") files <- liftIO $ getDirectoryContents dir ((), Sum count) <- runWriterT $ flip mapM_ files $ \file -> do let fn = dir ++ file isfile <- liftIO $ doesFileExist fn when isfile $ do gz <- liftIO $ isGZFile fn case gz of Nothing -> return () Just len -> do contents <- liftIO $ B.readFile fn let (uncompressed, isCorrupt) = gzDecompress (Just len) . BL.fromChunks $ [contents] when isCorrupt $ do tell (Sum 1) -- count of files in current directory liftIO $ putVerbose $ text $ "Corrupt: " ++ fn when (w && Repair `elem` opts) $ liftIO $ gzWriteAtomicFilePSs fn uncompressed when (count > (0 :: Int)) $ do liftIO $ putInfo $ text $ "Found " ++ show count ++ " corrupt file" ++ (if count > 1 then "s" else "") ++ (if Repair `elem` opts then (if w then " (repaired)" else " (not repaired") else "") tell (Any True) -- something corrupt somewhere when (Check `elem` opts && checkFailed) $ exitWith $ ExitFailure 1 where putInfo s = when (not $ Quiet `elem` opts) $ putDocLn s putVerbose s = when (Verbose `elem` opts) $ putDocLn s darcs-2.8.4/src/Darcs/Commands/Help.hs0000644001765600176560000003056112104371431016756 0ustar ganeshganesh-- Copyright (C) 2002-2004 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. module Darcs.Commands.Help ( helpCmd, commandControlList, environmentHelp, -- these are for preproc.hs printVersion, listAvailableCommands ) where import Darcs.Arguments ( DarcsFlag(..), environmentHelpEmail, environmentHelpSendmail ) import Darcs.Commands ( CommandArgs(..), CommandControl(..), DarcsCommand(..), disambiguateCommands, extractCommands, getCommandHelp, nodefaults, usage ) import Darcs.External ( viewDoc ) import Darcs.Lock ( environmentHelpTmpdir, environmentHelpKeepTmpdir ) import Darcs.Patch.Match ( helpOnMatchers ) import Darcs.Repository.Prefs ( boringFileHelp, binariesFileHelp, environmentHelpHome ) import Darcs.Ssh ( environmentHelpSsh, environmentHelpScp, environmentHelpSshPort ) import Darcs.Utils ( withCurrentDirectory, environmentHelpEditor, environmentHelpPager ) import Data.Char ( isAlphaNum, toLower, toUpper ) import Data.List ( groupBy, isPrefixOf, intercalate, nub ) import English ( andClauses ) import Printer (text, vcat, vsep, ($$)) import System.Exit ( ExitCode(..), exitWith ) import Version ( version ) import URL (environmentHelpProxy, environmentHelpProxyPassword) import Workaround ( getCurrentDirectory ) import qualified Darcs.TheCommands as TheCommands helpDescription :: String helpDescription = "Display help about darcs and darcs commands." helpHelp :: String helpHelp = "Without arguments, `darcs help' prints a categorized list of darcs\n" ++ "commands and a short description of each one. With an extra argument,\n" ++ "`darcs help foo' prints detailed help about the darcs command foo.\n" help :: DarcsCommand help = DarcsCommand {commandProgramName = "darcs", commandName = "help", commandHelp = helpHelp, commandDescription = helpDescription, commandExtraArgs = -1, commandExtraArgHelp = ["[ [DARCS_SUBCOMMAND]] "], commandCommand = \ x y -> helpCmd x y >> exitWith ExitSuccess, commandPrereq = \_ -> return $ Right (), commandGetArgPossibilities = return [], commandArgdefaults = nodefaults, commandAdvancedOptions = [], commandBasicOptions = []} helpCmd :: [DarcsFlag] -> [String] -> IO () helpCmd _ ["manpage"] = putStr $ unlines manpageLines helpCmd _ ["patterns"] = viewDoc $ text $ helpOnMatchers helpCmd _ ("environment":vs_) = viewDoc . vsep $ if null vs then header : map render environmentHelp else map render known ++ [footer] where header = vcat [ text "Environment Variables" , text "=====================" ] footer = text ("Unknown environment variables: " ++ intercalate ", " unknown) render (ks, ds) = text (andClauses ks ++ ":") $$ vcat [text (" " ++ d) | d <- ds] lookupEnv v = [ e | e@(ks,_) <- environmentHelp, v `elem` ks ] unknown = [ v | v <- vs, null (lookupEnv v) ] known = nub (concatMap lookupEnv vs) vs = map (map toUpper) vs_ helpCmd _ [] = viewDoc $ text $ usage commandControlList helpCmd _ (cmd:args) = let disambiguated = disambiguateCommands commandControlList cmd args in case disambiguated of Left err -> fail err Right (cmds,_) -> let msg = case cmds of CommandOnly c -> getCommandHelp Nothing c SuperCommandOnly c -> getCommandHelp Nothing c SuperCommandSub c s -> getCommandHelp (Just c) s in viewDoc $ text msg listAvailableCommands :: IO () listAvailableCommands = do here <- getCurrentDirectory is_valid <- mapM (\c-> withCurrentDirectory here $ (commandPrereq c) []) (extractCommands commandControlList) putStr $ unlines $ map (commandName . fst) $ filter (isRight.snd) $ zip (extractCommands commandControlList) is_valid putStrLn "--help" putStrLn "--version" putStrLn "--exact-version" putStrLn "--overview" where isRight (Right _) = True isRight _ = False printVersion :: IO () printVersion = putStrLn $ "darcs version " ++ version -- avoiding a module import cycle between Help and TheCommands commandControlList :: [CommandControl] commandControlList = CommandData help : TheCommands.commandControlList -- FIXME: the "grouping" comments below should made subsections in the -- manpage, as we already do for DarcsCommand groups. --twb, 2009 -- | Help on each environment variable in which Darcs is interested. environmentHelp :: [([String], [String])] environmentHelp = [ -- General-purpose environmentHelpHome, environmentHelpEditor, environmentHelpPager, environmentHelpTmpdir, environmentHelpKeepTmpdir, environmentHelpEmail, environmentHelpSendmail, -- Remote Repositories environmentHelpSsh, environmentHelpScp, environmentHelpSshPort, environmentHelpProxy, environmentHelpProxyPassword] -- | This module is responsible for emitting a darcs "man-page", a -- reference document used widely on Unix-like systems. Manpages are -- primarily used as a quick reference, or "memory jogger", so the -- output should be terser than the user manual. -- -- Before modifying the output, please be sure to read the man(7) and -- man-pages(7) manpages, as these respectively describe the relevant -- syntax and conventions. -- | The lines of the manpage to be printed. manpageLines :: [String] manpageLines = [ ".TH DARCS 1 \"" ++ version ++ "\"", ".SH NAME", "darcs \\- an advanced revision control system", ".SH SYNOPSIS", ".B darcs", ".I command", ".RI < arguments |[ options ]>...", "", "Where the", ".I commands", "and their respective", ".I arguments", "are", "", unlines synopsis, ".SH DESCRIPTION", -- FIXME: this is copy-and-pasted from darcs.cabal, so -- it'll get out of date as people forget to maintain -- both in sync. "Darcs is a free, open source revision control", "system. It is:", ".TP 3", "\\(bu", "Distributed: Every user has access to the full", "command set, removing boundaries between server and", "client or committer and non\\(hycommitters.", ".TP", "\\(bu", "Interactive: Darcs is easy to learn and efficient to", "use because it asks you questions in response to", "simple commands, giving you choices in your work", "flow. You can choose to record one change in a file,", "while ignoring another. As you update from upstream,", "you can review each patch name, even the full `diff'", "for interesting patches.", ".TP", "\\(bu", "Smart: Originally developed by physicist David", "Roundy, darcs is based on a unique algebra of", "patches.", "This smartness lets you respond to changing demands", "in ways that would otherwise not be possible. Learn", "more about spontaneous branches with darcs.", ".SH OPTIONS", "Different options are accepted by different Darcs commands.", "Each command's most important options are listed in the", ".B COMMANDS", "section. For a full list of all options accepted by", "a particular command, run `darcs", ".I command", "\\-\\-help'.", ".SS " ++ escape helpOnMatchers, -- FIXME: this is a kludge. ".SH COMMANDS", unlines commands, unlines environment, ".SH FILES", ".SS \"_darcs/prefs/binaries\"", escape $ unlines binariesFileHelp, ".SS \"_darcs/prefs/boring\"", escape $ unlines boringFileHelp, ".SH BUGS", "At http://bugs.darcs.net/ you can find a list of known", "bugs in Darcs. Unknown bugs can be reported at that", "site (after creating an account) or by emailing the", "report to bugs@darcs.net.", -- ".SH EXAMPLE", -- FIXME: -- new project: init, rec -la; -- track upstream project: get, pull -a; -- contribute to project: add, rec, push/send. ".SH SEE ALSO", "A user manual is included with Darcs, in PDF and HTML", "form. It can also be found at http://darcs.net/manual/.", ".SH LICENSE", "Darcs 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, or (at your option)", "any later version." ] where -- | A synopsis line for each command. Uses 'foldl' because it is -- necessary to avoid blank lines from Hidden_commands, as groff -- translates them into annoying vertical padding (unlike TeX). synopsis :: [String] synopsis = foldl iter [] commandControlList where iter :: [String] -> CommandControl -> [String] iter acc (GroupName _) = acc iter acc (HiddenCommand _) = acc iter acc (CommandData c@SuperCommand {}) = acc ++ concatMap (render (commandName c ++ " ")) (extractCommands (commandSubCommands c)) iter acc (CommandData c) = acc ++ render "" c render :: String -> DarcsCommand -> [String] render prefix c = [".B darcs " ++ prefix ++ commandName c] ++ (map mangle_args $ commandExtraArgHelp c) ++ -- In the output, we want each command to be on its own -- line, but we don't want blank lines between them. -- AFAICT this can only be achieved with the .br -- directive, which is probably a GNUism. [".br"] -- | As 'synopsis', but make each group a subsection (.SS), and -- include the help text for each command. commands :: [String] commands = foldl iter [] commandControlList where iter :: [String] -> CommandControl -> [String] iter acc (GroupName x) = acc ++ [".SS \"" ++ x ++ "\""] iter acc (HiddenCommand _) = acc iter acc (CommandData c@SuperCommand {}) = acc ++ concatMap (render (commandName c ++ " ")) (extractCommands (commandSubCommands c)) iter acc (CommandData c) = acc ++ render "" c render :: String -> DarcsCommand -> [String] render prefix c = [".B darcs " ++ prefix ++ commandName c] ++ (map mangle_args $ commandExtraArgHelp c) ++ [".RS 4", escape $ commandHelp c, ".RE"] -- | Now I'm showing off: mangle the extra arguments of Darcs commands -- so as to use the ideal format for manpages, italic words and roman -- punctuation. mangle_args :: String -> String mangle_args s = ".RI " ++ (unwords $ map show (groupBy cmp $ map toLower $ gank s)) where cmp x y = not $ xor (isAlphaNum x) (isAlphaNum y) xor x y = (x && not y) || (y && not x) gank (' ':'o':'r':' ':xs) = '|' : gank xs gank (x:xs) = x : gank xs gank [] = [] environment :: [String] environment = ".SH ENVIRONMENT" : concat [(".SS \"" ++ andClauses ks ++ "\"") : map escape ds | (ks, ds) <- environmentHelp] -- | Copied from Preproc.escape_latex_specials. escape :: String -> String escape = minus . bs -- Order is important where minus = replace "-" "\\-" bs = replace "\\" "\\\\" replace :: Eq a => [a] -> [a] -> [a] -> [a] replace _ _ [] = [] replace find repl s = if find `isPrefixOf` s then repl ++ (replace find repl (drop (length find) s)) else [head s] ++ replace find repl (tail s) darcs-2.8.4/src/Darcs/Commands/Init.hs0000644001765600176560000000566712104371431017002 0ustar ganeshganesh-- Copyright (C) 2002-2003 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. module Darcs.Commands.Init ( initialize, initializeCmd ) where import Darcs.Commands ( DarcsCommand(..), nodefaults ) import Darcs.Arguments ( DarcsFlag, workingRepoDir, patchFormatChoices, useWorkingDir ) import Darcs.Repository ( amNotInRepository, createRepository ) initializeDescription :: String initializeDescription = "Make the current directory a repository." initializeHelp :: String initializeHelp = "The `darcs initialize' command turns the current directory into a\n" ++ "Darcs repository. Any existing files and subdirectories become\n" ++ "UNSAVED changes: record them with `darcs record --look-for-adds'.\n" ++ "\n" ++ "This command creates the `_darcs' directory, which stores version\n" ++ "control metadata. It also contains per-repository settings in\n" ++ "_darcs/prefs/, which you can read about in the user manual.\n" ++ "\n" ++ "By default, patches of the new repository are in the darcs-2 semantics.\n" ++ "However it is possible to create a repository in darcs-1 semantics with\n" ++ "the flag `--hashed', althought this is not recommended except for sharing\n" ++ "patches with a project that uses patches in the darcs-1 semantics.\n" ++ "\n" ++ "Initialize is commonly abbreviated to `init'.\n" initialize :: DarcsCommand initialize = DarcsCommand {commandProgramName = "darcs", commandName = "initialize", commandHelp = initializeHelp, commandDescription = initializeDescription, commandExtraArgs = 0, commandExtraArgHelp = [], commandPrereq = amNotInRepository, commandCommand = initializeCmd, commandGetArgPossibilities = return [], commandArgdefaults = nodefaults, commandAdvancedOptions = [], commandBasicOptions = [patchFormatChoices, useWorkingDir, workingRepoDir]} initializeCmd :: [DarcsFlag] -> [String] -> IO () initializeCmd opts _ = createRepository opts darcs-2.8.4/src/Darcs/Commands/MarkConflicts.hs0000644001765600176560000001174612104371431020631 0ustar ganeshganesh-- Copyright (C) 2002-2003,2005 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP #-} module Darcs.Commands.MarkConflicts ( markconflicts ) where import Prelude hiding ( catch ) import System.Exit ( ExitCode(..), exitWith ) import Darcs.SignalHandler ( withSignalsBlocked ) import Control.Monad ( unless ) import Control.Exception ( catch, IOException ) import Darcs.Commands ( DarcsCommand(..), nodefaults ) import Darcs.Arguments ( DarcsFlag, ignoretimes, workingRepoDir, umaskOption ) import Darcs.Flags ( diffingOpts ) import Darcs.Repository ( withRepoLock, RepoJob(..), amInHashedRepository, addToPending, applyToWorking, readRepo, unrecordedChanges, Repository ) import Darcs.Patch ( invert, PrimOf ) import Darcs.Witnesses.Ordered ( FL(..) ) import Darcs.Witnesses.Sealed ( Sealed(Sealed) ) import Darcs.Resolution ( patchsetConflictResolutions ) import Darcs.Utils ( promptYorn ) #include "impossible.h" #include "gadts.h" markconflictsDescription :: String markconflictsDescription = "Mark unresolved conflicts in working tree, for manual resolution." markconflictsHelp :: String markconflictsHelp = "Darcs requires human guidance to unify changes to the same part of a\n" ++ "source file. When a conflict first occurs, darcs will add the\n" ++ "initial state and both choices to the working tree, delimited by the\n" ++ "markers `v v v', `=====', `* * *' and `^ ^ ^', as follows:\n" ++ "\n" ++ "v v v v v v v\n" ++ "Initial state.\n" ++ "=============\n" ++ "First choice.\n" ++ "*************\n" ++ "Second choice.\n" ++ "^ ^ ^ ^ ^ ^ ^\n" ++ "\n" ++ "However, you might revert or manually delete these markers without\n" ++ "actually resolving the conflict. In this case, `darcs mark-conflicts'\n" ++ "is useful to show where any unresolved conflicts. It is also useful\n" ++ "if `darcs apply' is called with --apply-conflicts, where conflicts\n" ++ "aren't marked initially.\n" ++ "\n" ++ "Any unrecorded changes to the working tree WILL be lost forever when\n" ++ "you run this command! You will be prompted for confirmation before\n" ++ "this takes place.\n" markconflicts :: DarcsCommand markconflicts = DarcsCommand {commandProgramName = "darcs", commandName = "mark-conflicts", commandHelp = markconflictsHelp, commandDescription = markconflictsDescription, commandExtraArgs = 0, commandExtraArgHelp = [], commandCommand = markconflictsCmd, commandPrereq = amInHashedRepository, commandGetArgPossibilities = return [], commandArgdefaults = nodefaults, commandAdvancedOptions = [umaskOption], commandBasicOptions = [ignoretimes, workingRepoDir]} markconflictsCmd :: [DarcsFlag] -> [String] -> IO () markconflictsCmd opts [] = withRepoLock opts $ RepoJob $ \(repository :: Repository p C(r u r)) -> do pend <- unrecordedChanges (diffingOpts opts) repository Nothing r <- readRepo repository Sealed res <- return $ patchsetConflictResolutions r (case res of NilFL -> do putStrLn "No conflicts to mark." exitWith ExitSuccess _ -> return ()) :: IO () let undoUnrec :: FL (PrimOf p) C(r u) -> IO (Repository p C(r r r)) undoUnrec NilFL = return repository undoUnrec pend' = do putStrLn ("This will trash any unrecorded changes"++ " in the working directory.") confirmed <- promptYorn "Are you sure? " unless confirmed $ exitWith ExitSuccess applyToWorking repository opts (invert pend') `catch` \(e :: IOException) -> bug ("Can't undo pending changes!" ++ show e) repository' <- undoUnrec pend withSignalsBlocked $ do addToPending repository' res _ <- applyToWorking repository' opts res `catch` \(e :: IOException) -> bug ("Problem marking conflicts in mark-conflicts!" ++ show e) return () putStrLn "Finished marking conflicts." markconflictsCmd _ _ = impossible darcs-2.8.4/src/Darcs/Commands/Move.hs0000644001765600176560000002730612104371431016777 0ustar ganeshganesh-- Copyright (C) 2002-2003 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP #-} module Darcs.Commands.Move ( move, mv ) where import Control.Applicative ( (<$>) ) import Control.Monad ( when, unless, zipWithM_ ) import Data.Maybe ( catMaybes ) import Darcs.SignalHandler ( withSignalsBlocked ) import Darcs.Commands ( DarcsCommand(..), nodefaults, commandAlias ) import Darcs.Arguments ( DarcsFlag(), maybeFixSubPaths, fixSubPaths, workingRepoDir, listFiles, allowProblematicFilenames, umaskOption, ) import Darcs.Flags ( doAllowCaseOnly, doAllowWindowsReserved ) import Darcs.RepoPath ( SubPath(), toFilePath ) import System.FilePath.Posix ( (), takeFileName ) import System.Directory ( renameDirectory ) import Workaround ( renameFile ) import Darcs.Repository.State ( readRecordedAndPending, readRecorded ) import Darcs.Repository ( Repository, withRepoLock, RepoJob(..), amInHashedRepository, addToPending ) import Darcs.Witnesses.Ordered ( FL(..), toFL ) import Darcs.Witnesses.Sealed ( Sealed(..), unseal, freeGap, FreeLeft, unFreeLeft ) import Darcs.Global ( debugMessage ) import qualified Darcs.Patch import Darcs.Patch ( RepoPatch, PrimPatch ) import Darcs.Patch.FileName ( fp2fn, fn2fp, superName ) import Darcs.Patch.Apply( ApplyState ) import Data.List ( nub, sort ) import qualified System.FilePath.Windows as WindowsFilePath import Darcs.Utils( treeHas, treeHasDir, treeHasAnycase, treeHasFile ) import Storage.Hashed.Tree( Tree, modifyTree ) import Storage.Hashed.Plain( readPlainTree ) import Storage.Hashed.AnchoredPath( floatPath ) #include "gadts.h" moveDescription :: String moveDescription = "Move or rename files." moveHelp :: String moveHelp = "Darcs cannot reliably distinguish between a file being deleted and a\n" ++ "new one added, and a file being moved. Therefore Darcs always assumes\n" ++ "the former, and provides the `darcs mv' command to let Darcs know when\n" ++ "you want the latter. This command will also move the file in the\n" ++ "working tree (unlike `darcs remove'), unless it has already been moved.\n" ++ "\n" ++ -- Note that this paragraph is very similar to one in ./Add.lhs. "Darcs will not rename a file if another file in the same folder has\n" ++ "the same name, except for case. The --case-ok option overrides this\n" ++ "behaviour. Windows and OS X usually use filesystems that do not allow\n" ++ "files a folder to have the same name except for case (for example,\n" ++ "`ReadMe' and `README'). If --case-ok is used, the repository might be\n" ++ "unusable on those systems!\n" move :: DarcsCommand move = DarcsCommand {commandProgramName = "darcs", commandName = "move", commandHelp = moveHelp, commandDescription = moveDescription, commandExtraArgs = -1, commandExtraArgHelp = [" ... "], commandCommand = moveCmd, commandPrereq = amInHashedRepository, commandGetArgPossibilities = listFiles, commandArgdefaults = nodefaults, commandAdvancedOptions = [umaskOption], commandBasicOptions = [allowProblematicFilenames, workingRepoDir]} moveCmd :: [DarcsFlag] -> [String] -> IO () moveCmd opts args | length args < 2 = fail $ "The `darcs move' command requires at least two arguments." | length args == 2 = do xs <- maybeFixSubPaths opts args case xs of [Just from, Just to] | from == to -> fail "Cannot rename a file or directory onto itself!" | toFilePath from == "" -> fail "Cannot move the root of the repository" | otherwise -> moveFile opts from to _ -> fail "Both source and destination must be valid." | otherwise = let (froms, to) = (init args, last args) in do x <- head <$> maybeFixSubPaths opts [to] case x of Nothing -> fail "Invalid destination directory." Just to' -> do xs <- nub . sort <$> fixSubPaths opts froms if to' `elem` xs then fail "Cannot rename a file or directory onto itself!" else case xs of [] -> fail "Nothing to move." froms' -> moveFilesToDir opts froms' to' data FileKind = Dir | File deriving (Show, Eq) data FileStatus = Nonexistant | Unadded FileKind | Shadow FileKind -- ^ known to darcs, but absent in working copy | Known FileKind deriving Show fileStatus :: Tree IO -> Tree IO -> Tree IO -> FilePath -> IO FileStatus fileStatus work cur rec fp = do exists_in_cur <- treeHas cur fp exists_in_rec <- treeHas rec fp exists_in_work <- treeHas work fp case (exists_in_rec, exists_in_cur, exists_in_work) of (_, True, True) -> do isDirCur <- treeHasDir cur fp isDirWork <- treeHasDir work fp unless (isDirCur == isDirWork) . fail $ "don't know what to do with " ++ fp return . Known $ if isDirCur then Dir else File (_, False, True) -> do isDir <- treeHasDir work fp if isDir then return $ Unadded Dir else return $ Unadded File (False, False, False) -> return Nonexistant (_, _, False) -> do isDir <- treeHasDir cur fp if isDir then return $ Shadow Dir else return $ Shadow File -- | Takes two filenames (as 'Subpath'), and tries to move the first -- into/onto the second. Needs to guess what that means: renaming or moving -- into a directory, and whether it is a post-hoc move. moveFile :: [DarcsFlag] -> SubPath -> SubPath -> IO () moveFile opts old new = withRepoLock opts $ RepoJob $ \repository -> do work <- readPlainTree "." cur <- readRecordedAndPending repository rec <- readRecorded repository let old_fp = toFilePath old new_fp = toFilePath new new_fs <- fileStatus work cur rec new_fp old_fs <- fileStatus work cur rec old_fp case (old_fs, new_fs) of (Nonexistant, _) -> fail $ old_fp ++ " is inexistant." (Unadded k, _) -> fail $ show k ++ " " ++ old_fp ++ " is unadded." (Known _, Nonexistant) -> simpleMove repository opts cur work old_fp new_fp (Known _, Shadow _) -> simpleMove repository opts cur work old_fp new_fp (_, Nonexistant) -> fail $ old_fp ++ " is not in the repository." (Known _, Known Dir) -> moveToDir repository opts [old_fp] new_fp (Known _, Unadded Dir) -> fail $ new_fp ++ " is not known to darcs; please add it to the repository." (Known _, _) -> fail $ new_fp ++ " already exists." (Shadow k, Unadded k') | k == k' -> simpleMove repository opts cur work old_fp new_fp (Shadow _, Known Dir) -> moveToDir repository opts [old_fp] new_fp (Shadow k, _) -> fail $ "cannot move " ++ show k ++ " " ++ old_fp ++ " into " ++ new_fp ++ " : " ++ "did you already move it elsewhere?" simpleMove :: (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u t) -> [DarcsFlag] -> Tree IO -> Tree IO -> FilePath -> FilePath -> IO () simpleMove repository opts cur work old_fp new_fp = do addpatch <- checkNewAndOldFilenames opts cur work (old_fp,new_fp) withSignalsBlocked $ do case unFreeLeft <$> addpatch of Nothing -> addToPending repository (Darcs.Patch.move old_fp new_fp :>: NilFL) Just (Sealed p) -> addToPending repository (p :>: Darcs.Patch.move old_fp new_fp :>: NilFL) moveFileOrDir work old_fp new_fp moveFilesToDir :: [DarcsFlag] -> [SubPath] -> SubPath -> IO () moveFilesToDir opts froms to = withRepoLock opts $ RepoJob $ \repo -> moveToDir repo opts (map toFilePath froms) $ toFilePath to moveToDir :: (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u t) -> [DarcsFlag] -> [FilePath] -> FilePath -> IO () moveToDir repository opts moved finaldir = let movefns = map takeFileName moved movetargets = map (finaldir ) movefns movepatches = zipWith (\a b -> freeGap (Darcs.Patch.move a b)) moved movetargets in do cur <- readRecordedAndPending repository work <- readPlainTree "." addpatches <- mapM (checkNewAndOldFilenames opts cur work) $ zip moved movetargets withSignalsBlocked $ do unseal (addToPending repository) $ toFL $ catMaybes addpatches ++ movepatches zipWithM_ (moveFileOrDir work) moved movetargets checkNewAndOldFilenames :: PrimPatch prim => [DarcsFlag] -> Tree IO -> Tree IO -> (FilePath, FilePath) -> IO (Maybe (FreeLeft prim)) checkNewAndOldFilenames opts cur work (old,new) = do unless (doAllowWindowsReserved opts || WindowsFilePath.isValid new) $ fail $ "The filename " ++ new ++ " is not valid under Windows.\n" ++ "Use --reserved-ok to allow such filenames." has_work <- treeHas work old maybe_add_file_thats_been_moved <- if has_work -- We need to move the object then do has_target <- treeHasDir work (fn2fp $ superName $ fp2fn new) unless has_target $ fail $ "The target directory " ++ (fn2fp $ superName $ fp2fn new)++ " isn't known in working directory, did you forget to add it?" has_new <- it_has work when has_new $ fail $ already_exists "working directory" return Nothing else do has_new <- treeHas work new has_cur_dir <- treeHasDir cur old unless has_new $ fail $ doesnt_exist "working directory" let add_patch = if has_cur_dir then Darcs.Patch.adddir old else Darcs.Patch.addfile old return (Just (freeGap (add_patch))) has_target <- treeHasDir cur (fn2fp $ superName $ fp2fn new) unless has_target $ fail $ "The target directory " ++ (fn2fp $ superName $ fp2fn new)++ " isn't known in working directory, did you forget to add it?" has_new <- it_has cur when has_new $ fail $ already_exists "repository" return maybe_add_file_thats_been_moved where it_has s = treeHas_case (modifyTree s (floatPath old) Nothing) new treeHas_case = if doAllowCaseOnly opts then treeHas else treeHasAnycase already_exists what_slurpy = if doAllowCaseOnly opts then "A file or dir named "++new++" already exists in " ++ what_slurpy ++ "." else "A file or dir named "++new++" (or perhaps differing"++ " only in case)\nalready exists in "++ what_slurpy ++ ".\n"++ "Use --case-ok to allow files differing only in case." doesnt_exist what_slurpy = "There is no file or dir named " ++ old ++ " in the "++ what_slurpy ++ "." moveFileOrDir :: Tree IO -> FilePath -> FilePath -> IO () moveFileOrDir work old new = do has_file <- treeHasFile work old has_dir <- treeHasDir work old when has_file $ do debugMessage $ unwords ["renameFile",old,new] renameFile old new when has_dir $ do debugMessage $ unwords ["renameDirectory",old,new] renameDirectory old new mv :: DarcsCommand mv = commandAlias "mv" Nothing move darcs-2.8.4/src/Darcs/Commands/Optimize.hs0000644001765600176560000004214012104371431017662 0ustar ganeshganesh-- Copyright (C) 2003-2005 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP #-} module Darcs.Commands.Optimize ( optimize ) where import Control.Applicative ( (<$>) ) import Control.Exception ( finally ) import Control.Monad ( when, unless ) import Data.Maybe ( isJust ) import Data.List ( sort ) import System.Directory ( getDirectoryContents, doesDirectoryExist, doesFileExist, renameFile, getModificationTime ) import System.IO.Unsafe ( unsafeInterleaveIO ) import qualified Data.ByteString.Char8 as BS import qualified Data.ByteString.Lazy as BL import Storage.Hashed.Darcs( decodeDarcsSize ) import Darcs.Patch.PatchInfoAnd ( info, extractHash ) import Darcs.Commands ( DarcsCommand(..), nodefaults ) import Darcs.Arguments ( DarcsFlag( UpgradeFormat, UseHashedInventory, Compress, UnCompress, NoCompress, Reorder, Relink, OptimizePristine, OptimizeHTTP ), reorderPatches, uncompressNocompress, relink, sibling, flagsToSiblings, upgradeFormat, workingRepoDir, umaskOption, optimizePristine, optimizeHTTP ) import Darcs.Repository.Prefs ( getPreflist ) import Darcs.Repository ( Repository, withRepoLock, RepoJob(..), withGutsOf, readRepo, optimizeInventory, tentativelyReplacePatches, cleanRepository, amInRepository, finalizeRepositoryChanges, replacePristine ) import Darcs.Repository.Old ( oldRepoFailMsg ) import Darcs.Witnesses.Ordered ( (+<+), reverseRL, mapRL, (:>)(..) , mapFL, bunchFL, lengthRL ) import Darcs.Patch.Info ( isTag ) import Darcs.Patch ( RepoPatch ) import Darcs.Patch.Set ( PatchSet(..), newset2RL, newset2FL, progressPatchSet ) import Darcs.Patch.Apply( ApplyState ) import ByteStringUtils ( gzReadFilePS ) import Darcs.Patch.Depends ( splitOnTag ) import Darcs.Lock ( maybeRelink, gzWriteAtomicFilePS, writeAtomicFilePS ) import Darcs.RepoPath ( toFilePath ) import Darcs.Utils ( withCurrentDirectory ) import Progress ( debugMessage ) import Darcs.Global ( darcsdir ) -- imports for optimize --upgrade; to be tidied import System.Directory ( createDirectoryIfMissing, removeFile ) import System.FilePath.Posix ( takeExtension, (), (<.>), takeFileName ) import Progress ( beginTedious, endTedious, tediousSize ) import Darcs.Flags ( compression ) import Darcs.Lock ( rmRecursive ) import Darcs.ProgressPatches ( progressFL ) import Darcs.Repository.Cache ( hashedDir, HashedDir(HashedPristineDir) ) import Darcs.Repository.Format ( identifyRepoFormat, createRepoFormat, writeRepoFormat, formatHas, RepoProperty ( HashedInventory ) ) import qualified Darcs.Repository.HashedRepo as HashedRepo import Darcs.Repository.Prefs ( getCaches ) import Darcs.Repository.State ( readRecorded ) import Darcs.Utils ( catchall ) import Storage.Hashed.Tree( Tree, TreeItem(..), list, expand, emptyTree ) import Storage.Hashed.AnchoredPath( anchorPath ) import Storage.Hashed.Plain( readPlainTree ) import Storage.Hashed.Darcs( writeDarcsHashed ) import Codec.Archive.Tar ( write ) import Codec.Archive.Tar.Entry ( fileEntry, toTarPath ) import Codec.Compression.GZip ( compress ) #include "gadts.h" optimizeDescription :: String optimizeDescription = "Optimize the repository." optimizeHelp :: String optimizeHelp = "The `darcs optimize' command modifies the current repository in an\n" ++ "attempt to reduce its resource requirements. By default a single\n" ++ "fast, safe optimization is performed; additional optimization\n" ++ "techniques can be enabled by passing options to `darcs optimize'.\n" ++ "\n" ++ optimizeHelpInventory ++ -- "\n" ++ optimize_help_reorder ++ "\n" ++ optimizeHelpRelink ++ -- uncompression is least useful, so it is last. "\n" ++ optimizeHelpCompression ++ "\n" ++ "There is one more optimization which CAN NOT be performed by this\n" ++ "command. Every time your record a patch, a new inventory file is\n" ++ "written to _darcs/inventories/, and old inventories are never reaped.\n" ++ "\n" ++ "If _darcs/inventories/ is consuming a relatively large amount of\n" ++ "space, you can safely reclaim it by using `darcs get' to make a\n" ++ "complete copy of the repo. When doing so, don't forget to copy over\n" ++ "any unsaved changes you have made to the working tree or to\n" ++ "unversioned files in _darcs/prefs/ (such as _darcs/prefs/author).\n" optimize :: DarcsCommand optimize = DarcsCommand {commandProgramName = "darcs", commandName = "optimize", commandHelp = optimizeHelp, commandDescription = optimizeDescription, commandExtraArgs = 0, commandExtraArgHelp = [], commandCommand = optimizeCmd, commandPrereq = amInRepository, commandGetArgPossibilities = return [], commandArgdefaults = nodefaults, commandAdvancedOptions = [uncompressNocompress, umaskOption], commandBasicOptions = [workingRepoDir, reorderPatches, sibling, relink, upgradeFormat, optimizePristine, optimizeHTTP]} optimizeCmd :: [DarcsFlag] -> [String] -> IO () optimizeCmd origopts _ = do when (UpgradeFormat `elem` origopts) optimizeUpgradeFormat withRepoLock opts $ RepoJob $ \repository -> do cleanRepository repository -- garbage collect pristine.hashed directory when (OptimizeHTTP `elem` origopts) $ doOptimizeHTTP repository if (OptimizePristine `elem` opts) then doOptimizePristine repository else do when (Reorder `elem` opts) $ doReorder opts repository doOptimizeInventory repository when (Compress `elem` opts || UnCompress `elem` opts) $ optimizeCompression opts when (Relink `elem` opts) $ doRelink opts putStrLn "Done optimizing!" where opts = if UnCompress `elem` origopts then NoCompress:origopts else origopts optimizeHelpInventory :: String optimizeHelpInventory = "The default optimization moves recent patches (those not included in\n" ++ "the latest tag) to the `front', reducing the amount that a typical\n" ++ "remote command needs to download. It should also reduce the CPU time\n" ++ "needed for some operations.\n" doOptimizeInventory :: (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u t) -> IO () doOptimizeInventory repository = do debugMessage "Writing out a nice copy of the inventory." optimizeInventory repository debugMessage "Done writing out a nice copy of the inventory." optimizeHelpCompression :: String optimizeHelpCompression = "By default patches are compressed with zlib (RFC 1951) to reduce\n" ++ "storage (and download) size. In exceptional circumstances, it may be\n" ++ "preferable to avoid compression. In this case the `--dont-compress'\n" ++ "option can be used (e.g. with `darcs record') to avoid compression.\n" ++ "\n" ++ "The `darcs optimize --uncompress' and `darcs optimize --compress'\n" ++ "commands can be used to ensure existing patches in the current\n" ++ "repository are respectively uncompressed or compressed. Note that\n" ++ "repositories in the legacy `old-fashioned-inventory' format have a .gz\n" ++ "extension on patch files even when uncompressed.\n" optimizeCompression :: [DarcsFlag] -> IO () optimizeCompression opts = do putStrLn "Optimizing (un)compression of patches..." do_compress (darcsdir++"/patches") putStrLn "Optimizing (un)compression of inventories..." do_compress (darcsdir++"/inventories") where do_compress f = do isd <- doesDirectoryExist f if isd then withCurrentDirectory f $ do fs <- filter notdot `fmap` getDirectoryContents "." mapM_ do_compress fs else if Compress `elem` opts then gzReadFilePS f >>= gzWriteAtomicFilePS f else gzReadFilePS f >>= writeAtomicFilePS f notdot ('.':_) = False notdot _ = True optimizeHelpRelink :: String optimizeHelpRelink = "The `darcs optimize --relink' command hard-links patches that the\n" ++ "current repository has in common with its peers. Peers are those\n" ++ "repositories listed in _darcs/prefs/sources, or defined with the\n" ++ "`--sibling' option (which can be used multiple times).\n" ++ "\n" ++ "Darcs uses hard-links automatically, so this command is rarely needed.\n" ++ "It is most useful if you used `cp -r' instead of `darcs get' to copy a\n" ++ "repository, or if you pulled the same patch from a remote repository\n" ++ "into multiple local repositories.\n" doOptimizePristine :: (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u t) -> IO () doOptimizePristine repo = do hashed <- doesFileExist $ darcsdir "hashed_inventory" when hashed $ do inv <- BS.readFile (darcsdir "hashed_inventory") let linesInv = BS.split '\n' inv case linesInv of [] -> return () (pris_line:_) -> let size = decodeDarcsSize $ BS.drop 9 pris_line in when (isJust size) $ do putStrLn "Optimizing hashed pristine..." readRecorded repo >>= replacePristine repo cleanRepository repo doRelink :: [DarcsFlag] -> IO () doRelink opts = do some_siblings <- return (flagsToSiblings opts) defrepolist <- getPreflist "defaultrepo" siblings <- return (map toFilePath some_siblings ++ defrepolist) if null siblings then putStrLn "No siblings -- no relinking done." else do debugMessage "Relinking patches..." patch_tree <- expand =<< readPlainTree "_darcs/patches" let patches = [ anchorPath "" p | (p, File _) <- list patch_tree ] maybeRelinkFiles siblings patches "_darcs/patches" debugMessage "Done relinking." maybeRelinkFiles :: [String] -> [String] -> String -> IO () maybeRelinkFiles src dst dir = mapM_ (maybeRelinkFile src) (map ((dir ++ "/") ++) dst) maybeRelinkFile :: [String] -> String -> IO () maybeRelinkFile [] _ = return () maybeRelinkFile (h:t) f = do done <- maybeRelink (h ++ "/" ++ f) f unless done $ maybeRelinkFile t f -- FIXME: someone needs to grovel through the source and determine -- just how optimizeInventory differs from doReorder. The following -- is purely speculation. --twb, 2009-04 -- optimize_help_reorder :: String -- optimize_help_reorder = -- "The `darcs optimize --reorder' command is a more comprehensive version\n" ++ -- "of the default optimization. It reorders patches with respect to ALL\n" ++ -- "tags, rather than just the latest tag.\n" doReorder :: (RepoPatch p, ApplyState p ~ Tree) => [DarcsFlag] -> Repository p C(r u r) -> IO () doReorder opts repository = do debugMessage "Reordering the inventory." PatchSet ps _ <- chooseOrder `fmap` readRepo repository -- Warning: A do-notation statement discarded a result of type Repository p r u r. withGutsOf repository $ do _ <- tentativelyReplacePatches repository (compression opts) $ reverseRL ps finalizeRepositoryChanges repository debugMessage "Done reordering the inventory." chooseOrder :: forall p C(s x) . RepoPatch p => PatchSet p C(s x) -> PatchSet p C(s x) chooseOrder ps = case filter isTag $ mapRL info $ newset2RL ps of [] -> ps (lt:_) -> case splitOnTag lt ps of PatchSet xs ts :> r -> PatchSet (r+<+xs) ts optimizeUpgradeFormat :: IO () optimizeUpgradeFormat = do debugMessage $ "Upgrading to hashed..." rf <- identifyRepoFormat "." debugMessage $ "Found our format" if formatHas HashedInventory rf then putStrLn "No action taken because this repository already is hashed." else do putStrLn "Checking repository in case of corruption..." withRepoLock [] $ RepoJob $ \repository -> do actuallyUpgradeFormat repository actuallyUpgradeFormat :: (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u t) -> IO () actuallyUpgradeFormat repository = do -- convert patches/inventory patches <- readRepo repository let k = "Hashing patch" beginTedious k tediousSize k (lengthRL $ newset2RL patches) let patches' = progressPatchSet k patches cache <- getCaches [] "." let compr = compression [] -- default compression HashedRepo.writeTentativeInventory cache compr patches' endTedious k -- convert pristine by applying patches -- the faster alternative would be to copy pristine, but the apply method is more reliable let patchesToApply = progressFL "Applying patch" $ newset2FL $ patches' createDirectoryIfMissing False $ darcsdir hashedDir HashedPristineDir -- Warning: A do-notation statement discarded a result of type Storage.Hashed.Hash.Hash. _ <- writeDarcsHashed emptyTree "_darcs/pristine.hashed" sequence_ $ mapFL HashedRepo.applyToTentativePristine $ bunchFL 100 patchesToApply -- now make it official HashedRepo.finalizeTentativeChanges repository compr writeRepoFormat (createRepoFormat [UseHashedInventory]) (darcsdir "format") -- clean out old-fashioned junk debugMessage "Cleaning out old-fashioned repository files..." removeFile $ darcsdir "inventory" removeFile $ darcsdir "tentative_inventory" rmRecursive (darcsdir "pristine") `catchall` rmRecursive (darcsdir "current") rmGzsIn (darcsdir "patches") rmGzsIn (darcsdir "inventories") let checkpointDir = darcsdir "checkpoints" hasCheckPoints <- doesDirectoryExist checkpointDir when hasCheckPoints $ rmRecursive checkpointDir putStrLn "Done upgrading!" where rmGzsIn dir = withCurrentDirectory dir $ do gzs <- filter ((== ".gz") . takeExtension) `fmap` getDirectoryContents "." mapM_ removeFile gzs doOptimizeHTTP :: (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u t) -> IO () doOptimizeHTTP repo = flip finally (mapM_ (removeFileIfExists) [ darcsdir "meta-filelist-inventories" , darcsdir "meta-filelist-pristine" , basicTar <.> "part" , patchesTar <.> "part" ]) $ do rf <- identifyRepoFormat "." unless (formatHas HashedInventory rf) $ fail oldRepoFailMsg createDirectoryIfMissing False packsDir -- pack patchesTar ps <- mapRL hashedPatchFileName . newset2RL <$> readRepo repo is <- map ((darcsdir "inventories") ) <$> HashedRepo.listInventories writeFile (darcsdir "meta-filelist-inventories") . unlines $ map takeFileName is BL.writeFile (patchesTar <.> "part") . compress . write =<< mapM fileEntry' ((darcsdir "meta-filelist-inventories") : ps ++ reverse is) renameFile (patchesTar <.> "part") patchesTar -- pack basicTar pr <- sortByMTime =<< dirContents "pristine.hashed" writeFile (darcsdir "meta-filelist-pristine") . unlines $ map takeFileName pr BL.writeFile (basicTar <.> "part") . compress . write =<< mapM fileEntry' ( [ darcsdir "meta-filelist-pristine" , darcsdir "hashed_inventory" ] ++ reverse pr) renameFile (basicTar <.> "part") basicTar where packsDir = darcsdir "packs" basicTar = packsDir "basic.tar.gz" patchesTar = packsDir "patches.tar.gz" fileEntry' x = unsafeInterleaveIO $ do content <- BL.fromChunks . return <$> gzReadFilePS x tp <- either fail return $ toTarPath False x return $ fileEntry tp content dirContents d = dirContents' d $ const True dirContents' d f = map ((darcsdir d) ) . filter (\x -> head x /= '.' && f x) <$> getDirectoryContents (darcsdir d) hashedPatchFileName x = case extractHash x of Left _ -> fail "unexpected unhashed patch" Right h -> darcsdir "patches" h sortByMTime xs = map snd . sort <$> mapM (\x -> (\t -> (t, x)) <$> getModificationTime x) xs removeFileIfExists x = do ex <- doesFileExist x when ex $ removeFile x darcs-2.8.4/src/Darcs/Commands/Pull.hs0000644001765600176560000003677212104371431017014 0ustar ganeshganesh-- Copyright (C) 2002-2005 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP #-} module Darcs.Commands.Pull ( pull, fetch ) where import System.Exit ( ExitCode(..), exitWith ) import Workaround ( getCurrentDirectory ) import Control.Monad ( when ) import Data.List ( nub ) import Data.Maybe ( fromMaybe ) import Darcs.Commands ( DarcsCommand(..), putVerbose, putInfo ) import Darcs.CommandsAux ( checkPaths ) import Darcs.Arguments ( DarcsFlag ( AllowConflicts , Complement , DryRun , Intersection , MarkConflicts , NoAllowConflicts , Verbose , XMLOutput ) , allInteractive , allowUnrelatedRepos , changesReverse , depsSel , dryRun , fixUrl , getOutput , ignoretimes , makeScriptsExecutable , matchSeveral , networkOptions , nocompress , output , pauseForGui , printDryRunMessageAndExit , pullConflictOptions , remoteRepo , repoCombinator , restrictPaths , setDefault , setEnvDarcsPatches , setScriptsExecutableOption , summary , test , umaskOption , useExternalMerge , workingRepoDir ) import Darcs.Flags( doReverse, isInteractive ) import Darcs.Repository ( Repository, identifyRepositoryFor, withGutsOf, amInHashedRepository, withRepoLock, RepoJob(..), finalizeRepositoryChanges, applyToWorking, testTentative, readRepo, checkUnrelatedRepos, invalidateIndex, modifyCache, modifyCache, Cache(..), CacheLoc(..), WritableOrNot(..)) import qualified Darcs.Repository.Cache as DarcsCache import Darcs.Repository.Merge ( tentativelyMergePatches ) import Darcs.Patch.PatchInfoAnd ( info, hopefully, patchDesc ) import Darcs.Patch ( RepoPatch, description, PrimOf ) import Darcs.Patch.Bundle( makeBundleN, patchFilename ) import Darcs.Patch.Apply( ApplyState ) import Darcs.Patch.PatchInfoAnd ( PatchInfoAnd ) #ifdef GADT_WITNESSES import Darcs.Patch.Set ( Origin ) #endif import Darcs.Patch.Set ( PatchSet(..), SealedPatchSet ) import Darcs.Witnesses.Unsafe ( unsafeCoercePEnd ) import Darcs.Witnesses.Ordered ( (:>)(..), (:\/:)(..), FL(..), RL(..) , mapFL, nullFL, reverseFL, mapFL_FL ) import Darcs.Patch.Permutations ( partitionFL ) import Darcs.Repository.Prefs ( addToPreflist, defaultrepo, setDefaultrepo, getPreflist ) import Darcs.Repository.Motd (showMotd ) import Darcs.Patch.Depends ( findUncommon, findCommonWithThem, newsetIntersection, newsetUnion ) import Darcs.SelectChanges ( selectChanges, WhichChanges(..), filterOutConflicts, runSelection, selectionContext) import Darcs.Utils ( clarifyErrors, formatPath, PromptConfig(..), promptChar ) import Darcs.Witnesses.Sealed ( Sealed(..), seal ) import Printer ( putDocLn, vcat, ($$), text, putDoc ) import Darcs.Lock ( writeDocBinFile ) import Darcs.RepoPath ( useAbsoluteOrStd, stdOut ) import Storage.Hashed.Tree( Tree ) #include "impossible.h" #include "gadts.h" pullDescription :: String pullDescription = "Copy and apply patches from another repository to this one." fetchDescription :: String fetchDescription = "Fetch patches from another repository, but don't apply them." pullHelp :: String pullHelp = "Pull is used to bring changes made in another repository into the current\n"++ "repository (that is, either the one in the current directory, or the one\n"++ "specified with the --repodir option). Pull allows you to bring over all or\n"++ "some of the patches that are in that repository but not in this one. Pull\n"++ "accepts arguments, which are URLs from which to pull, and when called\n"++ "without an argument, pull will use the repository from which you have most\n"++ "recently either pushed or pulled.\n" ++ "\n" ++ "See 'darcs help apply' for detailed description of many options.\n" fetchHelp :: String fetchHelp = "fetch is used to bring changes made in another repository\n" ++ "into the current repository without actually applying\n"++ "them. Fetch allows you to bring over all or\n"++ "some of the patches that are in that repository but not in this one. Fetch\n"++ "accepts arguments, which are URLs from which to fetch, and when called\n"++ "without an argument, fetch will use the repository from which you have most\n"++ "recently either pushed or pulled.\n"++ "The fetched patches are stored into a patch bundle, to be later\n" ++ "applied using \"darcs apply\"." fetch :: DarcsCommand fetch = DarcsCommand { commandProgramName = "darcs", commandName = "fetch", commandHelp = fetchHelp, commandDescription = fetchDescription, commandExtraArgs = -1, commandExtraArgHelp = ["[REPOSITORY]..."], commandCommand = fetchCmd, commandPrereq = amInHashedRepository, commandGetArgPossibilities = getPreflist "repos", commandArgdefaults = defaultrepo, commandAdvancedOptions = [ repoCombinator , remoteRepo ] ++ networkOptions, commandBasicOptions = [matchSeveral, allInteractive] ++dryRun++ [summary, depsSel, setDefault False, workingRepoDir, output, allowUnrelatedRepos]} pull :: DarcsCommand pull = DarcsCommand {commandProgramName = "darcs", commandName = "pull", commandHelp = pullHelp, commandDescription = pullDescription, commandExtraArgs = -1, commandExtraArgHelp = ["[REPOSITORY]..."], commandCommand = pullCmd, commandPrereq = amInHashedRepository, commandGetArgPossibilities = getPreflist "repos", commandArgdefaults = defaultrepo, commandAdvancedOptions = [ repoCombinator , nocompress , ignoretimes , remoteRepo , setScriptsExecutableOption , umaskOption , restrictPaths , changesReverse , pauseForGui ] ++ networkOptions, commandBasicOptions = [matchSeveral, allInteractive, pullConflictOptions, useExternalMerge, test]++dryRun++[summary, depsSel, setDefault False, workingRepoDir, allowUnrelatedRepos]} mergeOpts :: [DarcsFlag] -> [DarcsFlag] mergeOpts opts | NoAllowConflicts `elem` opts = opts | AllowConflicts `elem` opts = opts | otherwise = MarkConflicts : opts pullCmd :: [DarcsFlag] -> [String] -> IO () pullCmd opts repos = do pullingFrom <- mapM (fixUrl opts) repos withRepoLock opts $ RepoJob $ \ initRepo -> do let repository = modifyCache initRepo $ addReposToCache pullingFrom r <- fetchPatches opts' repos "pull" repository applyPatches opts' repository r where opts' = mergeOpts opts addReposToCache repos' (Ca cache) = Ca $ [ toReadOnlyCache r | r <- repos' ] ++ cache toReadOnlyCache = Cache DarcsCache.Repo NotWritable fetchCmd :: [DarcsFlag] -> [String] -> IO () fetchCmd opts repos = withRepoLock opts $ RepoJob $ \ repository -> fetchPatches opts repos "fetch" repository >>= makeBundle opts fetchPatches :: FORALL(p r u) (RepoPatch p, ApplyState p ~ Tree) => [DarcsFlag] -> [String] -> String -> Repository p C(r u r) -> IO (SealedPatchSet p C(Origin), Sealed ((FL (PatchInfoAnd p) :\/: FL (PatchInfoAnd p)) C(r))) fetchPatches opts unfixedrepodirs@(_:_) jobname repository = do here <- getCurrentDirectory repodirs <- (nub . filter (/= here)) `fmap` mapM (fixUrl opts) unfixedrepodirs -- Test to make sure we aren't trying to pull from the current repo when (null repodirs) $ fail "Can't pull from current repository!" old_default <- getPreflist "defaultrepo" when (old_default == repodirs && not (XMLOutput `elem` opts)) $ let pulling = if DryRun `elem` opts then "Would pull" else "Pulling" in putInfo opts $ text $ pulling++" from "++concatMap formatPath repodirs++"..." (Sealed them, Sealed compl) <- readRepos repository opts repodirs setDefaultrepo (head repodirs) opts mapM_ (addToPreflist "repos") repodirs mapM_ (showMotd opts) repodirs us <- readRepo repository checkUnrelatedRepos opts us them common :> _ <- return $ findCommonWithThem us them us' :\/: them' <- return $ findUncommon us them _ :\/: compl' <- return $ findUncommon us compl let avoided = mapFL info compl' ps :> _ <- return $ partitionFL (not . (`elem` avoided) . info) them' when (Verbose `elem` opts) $ do case us' of (x@(_:>:_)) -> putDocLn $ text "We have the following new (to them) patches:" $$ (vcat $ mapFL description x) _ -> return () when (not $ nullFL ps) $ putDocLn $ text "They have the following patches to pull:" $$ (vcat $ mapFL description ps) (hadConflicts, Sealed psFiltered) <- filterOutConflicts opts (reverseFL us') repository ps when hadConflicts $ putStrLn "Skipping some patches which would cause conflicts." when (nullFL psFiltered) $ do putInfo opts $ text "No remote changes to pull in!" setEnvDarcsPatches psFiltered exitWith ExitSuccess let context = selectionContext jobname opts Nothing Nothing selector = if doReverse opts then selectChanges FirstReversed else selectChanges First (to_be_pulled :> _) <- runSelection (selector psFiltered) $ context return (seal common, seal $ us' :\/: to_be_pulled) fetchPatches _ [] jobname _ = fail $ "No default repository to " ++ jobname ++ " from, please specify one" applyPatches :: forall p C(r u). (RepoPatch p, ApplyState p ~ Tree, ApplyState (PrimOf p) ~ Tree) => [DarcsFlag] -> Repository p C(r u r) -> (SealedPatchSet p C(Origin), Sealed ((FL (PatchInfoAnd p) :\/: FL (PatchInfoAnd p)) C(r))) -> IO () applyPatches opts repository (_, Sealed (us' :\/: to_be_pulled)) = do printDryRunMessageAndExit "pull" opts to_be_pulled setEnvDarcsPatches to_be_pulled when (nullFL to_be_pulled) $ do putStrLn "You don't want to pull any patches, and that's fine with me!" exitWith ExitSuccess checkPaths opts to_be_pulled putVerbose opts $ text "Getting and merging the following patches:" putVerbose opts $ vcat $ mapFL description to_be_pulled Sealed pw <- tentativelyMergePatches repository "pull" opts us' to_be_pulled invalidateIndex repository rc <- testTentative repository when (rc /= ExitSuccess) $ do when (not $ isInteractive opts) $ exitWith rc putStrLn $ "Looks like those patches do not pass the tests." let prompt = "Shall I apply them anyway?" yn <- promptChar (PromptConfig prompt "yn" [] (Just 'n') []) case yn of 'y' -> return () _ -> exitWith rc withGutsOf repository $ do finalizeRepositoryChanges repository _ <- revertable $ applyToWorking repository opts pw makeScriptsExecutable opts pw return () putInfo opts $ text "Finished pulling and applying." makeBundle :: forall p C(r) . (RepoPatch p, ApplyState p ~ Tree) => [DarcsFlag] -> (SealedPatchSet p C(Origin), Sealed ((FL (PatchInfoAnd p) :\/: FL (PatchInfoAnd p)) C(r))) -> IO () makeBundle opts (Sealed common, Sealed (_ :\/: to_be_fetched)) = do bundle <- makeBundleN Nothing (unsafeCoercePEnd common) $ mapFL_FL hopefully to_be_fetched let fname = case to_be_fetched of (x:>:_)-> patchFilename $ patchDesc x _ -> impossible o = fromMaybe stdOut (getOutput opts fname) useAbsoluteOrStd writeDocBinFile putDoc o $ bundle revertable :: IO a -> IO a revertable x = x `clarifyErrors` unlines ["Error applying patch to the working directory.","", "This may have left your working directory an inconsistent", "but recoverable state. If you had no un-recorded changes", "by using 'darcs revert' you should be able to make your", "working directory consistent again."] {- Read in the specified pull-from repositories. Perform Intersection, Union, or Complement read. In patch-theory terms (stated in set algebra, where + is union and & is intersection and \ is complement): Union = ((R1 + R2 + ... + Rn) \ Rc) Intersection = ((R1 & R2 & ... & Rn) \ Rc) Complement = (R1 \ Rc) \ ((R2 + R3 + ... + Rn) \ Rc) where Rc = local repo R1 = 1st specified pull repo R2, R3, Rn = other specified pull repo Since Rc is not provided here yet, the result of readRepos is a tuple: the first patchset(s) to be complemented against Rc and then the second patchset(s) to be complemented against Rc. -} readRepos :: (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u t) -> [DarcsFlag] -> [String] -> IO (SealedPatchSet p C(Origin),SealedPatchSet p C(Origin)) readRepos _ _ [] = impossible readRepos to_repo opts us = do rs <- mapM (\u -> do r <- identifyRepositoryFor to_repo u ps <- readRepo r return $ seal ps) us return $ if Intersection `elem` opts then (newsetIntersection rs, seal (PatchSet NilRL NilRL)) else if Complement `elem` opts then (head rs, newsetUnion $ tail rs) else (newsetUnion rs, seal (PatchSet NilRL NilRL)) darcs-2.8.4/src/Darcs/Commands/Push.hs0000644001765600176560000002103212104371431016776 0ustar ganeshganesh-- Copyright (C) 2002-2004 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP, TypeOperators #-} module Darcs.Commands.Push ( push ) where import System.Exit ( exitWith, ExitCode( ExitSuccess, ExitFailure ) ) import Control.Monad ( when ) import Data.Char ( toUpper ) import Workaround ( getCurrentDirectory ) import Darcs.Commands ( DarcsCommand(..), putVerbose, putInfo, abortRun ) import Darcs.Arguments ( DarcsFlag( DryRun, Sign, SignAs, NoSign, SignSSL ), setEnvDarcsPatches, workingRepoDir, summary, printDryRunMessageAndExit, applyas, matchSeveral, fixUrl, depsSel, allInteractive, dryRun, remoteRepo, networkOptions, setDefault, sign, allowUnrelatedRepos, changesReverse ) import Darcs.Flags(doReverse) import Darcs.Patch.PatchInfoAnd ( PatchInfoAnd, hopefully ) import Darcs.Repository ( Repository, withRepoReadLock, RepoJob(..), identifyRepositoryFor, readRepo, amInHashedRepository, checkUnrelatedRepos ) import Darcs.Patch ( RepoPatch, description ) import Darcs.Patch.Apply( ApplyState ) import Darcs.Witnesses.Ordered ( (:>)(..), RL, FL, nullRL, nullFL, reverseFL, mapFL_FL, mapRL ) import Darcs.Repository.Prefs ( defaultrepo, setDefaultrepo, getPreflist ) import Darcs.External ( maybeURLCmd, signString ) import Darcs.URL ( isHttpUrl, isFile ) import Darcs.SelectChanges ( selectChanges, WhichChanges(..), selectionContext, runSelection ) import Darcs.Utils ( formatPath ) import Darcs.Patch.Depends ( findCommonWithThem, countUsThem ) import Darcs.Patch.Bundle ( makeBundleN ) import Darcs.Patch.Patchy( ShowPatch ) import Darcs.Patch.Set ( PatchSet ) #ifdef GADT_WITNESSES import Darcs.Patch.Set ( Origin ) #endif import Printer ( Doc, vcat, empty, text, ($$) ) import Darcs.RemoteApply ( remoteApply, applyAs ) import Darcs.Email ( makeEmail ) import English (englishNum, Noun(..)) import Storage.Hashed.Tree( Tree ) #include "impossible.h" #include "gadts.h" pushDescription :: String pushDescription = "Copy and apply patches from this repository to another one." pushHelp :: String pushHelp = "Push is the opposite of pull. Push allows you to copy changes from the\n"++ "current repository into another repository.\n" push :: DarcsCommand push = DarcsCommand {commandProgramName = "darcs", commandName = "push", commandHelp = pushHelp, commandDescription = pushDescription, commandExtraArgs = 1, commandExtraArgHelp = ["[REPOSITORY]"], commandCommand = pushCmd, commandPrereq = amInHashedRepository, commandGetArgPossibilities = getPreflist "repos", commandArgdefaults = defaultrepo, commandAdvancedOptions = [applyas, remoteRepo, changesReverse] ++ networkOptions, commandBasicOptions = [matchSeveral, depsSel, allInteractive, sign]++dryRun++[summary, workingRepoDir, setDefault False, allowUnrelatedRepos]} pushCmd :: [DarcsFlag] -> [String] -> IO () pushCmd _ [""] = impossible pushCmd opts [unfixedrepodir] = do repodir <- fixUrl opts unfixedrepodir -- Test to make sure we aren't trying to push to the current repo here <- getCurrentDirectory checkOptionsSanity opts repodir when (repodir == here) $ fail "Cannot push from repository to itself." -- absolute '.' also taken into account by fix_filepath (bundle) <- withRepoReadLock opts $ RepoJob $ prepareBundle opts repodir sbundle <- signString opts bundle let body = if isFile repodir then sbundle else makeEmail repodir [] Nothing Nothing sbundle Nothing rval <- remoteApply opts repodir body case rval of ExitFailure ec -> do putStrLn $ "Apply failed!" exitWith (ExitFailure ec) ExitSuccess -> putInfo opts $ text "Push successful." pushCmd _ _ = impossible prepareBundle :: forall p C(r u t). (RepoPatch p, ApplyState p ~ Tree) => [DarcsFlag] -> String -> Repository p C(r u t) -> IO (Doc) prepareBundle opts repodir repository = do old_default <- getPreflist "defaultrepo" when (old_default == [repodir]) $ let pushing = if DryRun `elem` opts then "Would push" else "Pushing" in putInfo opts $ text $ pushing++" to "++formatPath repodir++"..." them <- identifyRepositoryFor repository repodir >>= readRepo setDefaultrepo repodir opts us <- readRepo repository common :> us' <- return $ findCommonWithThem us them prePushChatter opts us (reverseFL us') them let context = selectionContext "push" opts Nothing Nothing selector = if doReverse opts then selectChanges FirstReversed else selectChanges First runSelection (selector us') context >>= bundlePatches opts common prePushChatter :: forall p a C(x y t) . (RepoPatch p, ShowPatch a) => [DarcsFlag] -> PatchSet p C(Origin x) -> RL a C(t x) -> PatchSet p C(Origin y) -> IO () prePushChatter opts us us' them = do checkUnrelatedRepos opts us them let num_to_pull = snd $ countUsThem us them pull_reminder = if num_to_pull > 0 then text $ "The remote repository has " ++ show num_to_pull ++ " " ++ englishNum num_to_pull (Noun "patch") " to pull." else empty putVerbose opts $ text "We have the following patches to push:" $$ (vcat $ mapRL description us') when (not $ nullRL us') $ do putInfo opts $ pull_reminder when (nullRL us') $ do putInfo opts $ text "No recorded local changes to push!" exitWith ExitSuccess bundlePatches :: forall t p C(z w a). (RepoPatch p, ApplyState p ~ Tree) => [DarcsFlag] -> PatchSet p C(a z) -> (FL (PatchInfoAnd p) :> t) C(z w) -> IO (Doc) bundlePatches opts common (to_be_pushed :> _) = do setEnvDarcsPatches to_be_pushed printDryRunMessageAndExit "push" opts to_be_pushed when (nullFL to_be_pushed) $ do putInfo opts $ text "You don't want to push any patches, and that's fine with me!" exitWith ExitSuccess bundle <- makeBundleN Nothing common (mapFL_FL hopefully to_be_pushed) return (bundle) wantSign :: [DarcsFlag] -> Bool wantSign opts = case opts of [] -> False Sign:_ -> True (SignAs _):_ -> True (SignSSL _):_ -> True NoSign:_ -> False _:opts' -> wantSign opts' checkOptionsSanity :: [DarcsFlag] -> String -> IO () checkOptionsSanity opts repodir = if isHttpUrl repodir then do when (applyAs opts /= Nothing) $ abortRun opts $ text "Cannot --apply-as when pushing to URLs" maybeapply <- maybeURLCmd "APPLY" repodir when (maybeapply == Nothing) $ let lprot = takeWhile (/= ':') repodir prot = map toUpper lprot msg = text ("Pushing to "++lprot++" URLs is not supported.\n"++ "You may be able to hack this to work"++ " using DARCS_APPLY_"++prot) in abortRun opts msg else do when (wantSign opts) $ abortRun opts $ text "Signing doesn't make sense for local repositories or when pushing over ssh." darcs-2.8.4/src/Darcs/Commands/Put.hs0000644001765600176560000001362512104371431016640 0ustar ganeshganesh{-# LANGUAGE CPP #-} module Darcs.Commands.Put ( put ) where import System.Exit ( ExitCode( ExitSuccess, ExitFailure ), exitWith ) import Control.Monad ( when ) import Data.Maybe ( mapMaybe ) import System.Directory ( createDirectory ) import Darcs.Commands ( DarcsCommand(..), nodefaults, putVerbose, putInfo ) import Darcs.Arguments ( DarcsFlag( UseFormat2, UseHashedInventory ), applyas, matchOneContext, fixUrl, networkOptions, flagToString, setScriptsExecutableOption, workingRepoDir, setDefault ) import Darcs.Repository ( withRepoReadLock, RepoJob(..), patchSetToPatches, readRepo, amInHashedRepository ) import Darcs.Repository.Format ( identifyRepoFormat, RepoProperty ( Darcs2 ), formatHas ) import Darcs.Patch.Bundle ( makeBundle2 ) import Darcs.Patch.Set ( PatchSet ) #ifdef GADT_WITNESSES import Darcs.Patch.Set ( Origin ) #endif import Darcs.Witnesses.Eq ( EqCheck(..) ) import Darcs.Witnesses.Unsafe ( unsafeCoerceP ) import Darcs.Witnesses.Ordered ( RL(..), nullFL ) import Darcs.Match ( havePatchsetMatch, getOnePatchset ) import Darcs.Repository.Prefs ( getPreflist, setDefaultrepo ) import Darcs.URL ( isHttpUrl, isFile, splitSshUrl, SshFilePath(..) ) import Darcs.Utils ( withCurrentDirectory ) import Progress ( debugMessage ) import Darcs.RepoPath ( ioAbsoluteOrRemote, toPath ) import Darcs.External ( execSSH ) import Darcs.RemoteApply ( remoteApply ) import Darcs.Commands.Init ( initialize ) import Darcs.Email ( makeEmail ) import Darcs.Witnesses.Sealed ( Sealed(..), seal ) import Printer ( text ) #include "impossible.h" #include "gadts.h" putDescription :: String putDescription = "Makes a copy of the repository" putHelp :: String putHelp = "The `darcs put' command creates a copy of the current repository. It\n" ++ "is currently very inefficient, so when creating local copies you\n" ++ "should use `darcs get . x' instead of `darcs put x'.\n" ++ "\n" ++ "Currently this command just uses `darcs init' to create the target\n" ++ "repository, then `darcs push --all' to copy patches to it. Options\n" ++ "passed to `darcs put' are passed to the init and/or push commands as\n" ++ "appropriate. See those commands for an explanation of each option.\n" put ::DarcsCommand put = DarcsCommand {commandProgramName = "darcs", commandName = "put", commandHelp = putHelp, commandDescription = putDescription, commandExtraArgs = 1, commandExtraArgHelp = [""], commandCommand = putCmd, commandPrereq = amInHashedRepository, commandGetArgPossibilities = getPreflist "repos", commandArgdefaults = nodefaults, commandAdvancedOptions = [applyas] ++ networkOptions, commandBasicOptions = [matchOneContext, setScriptsExecutableOption, setDefault False, workingRepoDir]} putCmd :: [DarcsFlag] -> [String] -> IO () putCmd _ [""] = fail "Empty repository argument given to put." putCmd opts [unfixedrepodir] = do repodir <- fixUrl opts unfixedrepodir -- Test to make sure we aren't trying to push to the current repo t_cur_absolute_repo_dir <- ioAbsoluteOrRemote "." t_req_absolute_repo_dir <- ioAbsoluteOrRemote repodir let cur_absolute_repo_dir = toPath t_cur_absolute_repo_dir req_absolute_repo_dir = toPath t_req_absolute_repo_dir when (cur_absolute_repo_dir == req_absolute_repo_dir) $ fail "Can't put to current repository!" when (isHttpUrl req_absolute_repo_dir) $ error "Can't put to a URL!" debugMessage "Creating repository" putVerbose opts $ text "Creating repository" rf <- identifyRepoFormat "." let initopts = if formatHas Darcs2 rf then UseFormat2:opts else UseHashedInventory:filter (/= UseFormat2) opts if isFile req_absolute_repo_dir then do createDirectory req_absolute_repo_dir withCurrentDirectory req_absolute_repo_dir $ (commandCommand initialize) initopts [] else do -- isSshUrl req_absolute_repo_dir remoteInit (splitSshUrl req_absolute_repo_dir) initopts withCurrentDirectory cur_absolute_repo_dir $ withRepoReadLock opts $ RepoJob $ \repository -> (do setDefaultrepo req_absolute_repo_dir opts let doRead = if havePatchsetMatch opts then getOnePatchset repository opts -- todo: make sure getOnePatchset has the right type else readRepo repository >>= (return . seal) Sealed (patchset :: PatchSet p C(Origin x1)) <- doRead Sealed (patchset2 :: PatchSet p C(Origin x2)) <- doRead IsEq <- return (unsafeCoerceP IsEq) :: IO (EqCheck C(x1 x2)) let patches = patchSetToPatches patchset patches2 = patchSetToPatches patchset2 when (nullFL patches) $ do putInfo opts $ text "No patches were selected to put. Nothing to be done." exitWith ExitSuccess bundle <- makeBundle2 Nothing NilRL patches patches2 let message = if isFile req_absolute_repo_dir then bundle else makeEmail req_absolute_repo_dir [] Nothing Nothing bundle Nothing putVerbose opts $ text "Applying patches in new repository..." rval <- remoteApply opts req_absolute_repo_dir message case rval of ExitFailure ec -> do putStrLn $ "Apply failed!" exitWith (ExitFailure ec) ExitSuccess -> putInfo opts $ text "Put successful.") :: IO () putCmd _ _ = impossible remoteInit :: SshFilePath -> [DarcsFlag] -> IO () remoteInit repo opts = do let args = mapMaybe (flagToString $ commandBasicOptions initialize) opts command = "darcs initialize --repodir='" ++ (sshRepo repo) ++ "' " ++ unwords args exitCode <- execSSH repo command when (exitCode /= ExitSuccess) $ fail "Couldn't initialize remote repository." darcs-2.8.4/src/Darcs/Commands/Record.hs0000644001765600176560000005400312104371431017301 0ustar ganeshganesh-- Copyright (C) 2002-2003 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP, PatternGuards #-} module Darcs.Commands.Record ( record, commit, getDate, getLog, askAboutDepends ) where import Prelude hiding ( catch ) import qualified Ratified( hGetContents ) import Control.Applicative ( (<$>) ) import Control.Exception.Extensible ( handleJust, catch, IOException ) import Control.Monad ( when, unless ) import System.IO ( stdin ) import Data.List ( sort, isPrefixOf, union ) import Data.Char ( ord ) import System.Exit ( exitWith, exitFailure, ExitCode(..) ) import System.Directory ( removeFile ) import Data.Maybe ( isJust, catMaybes ) import qualified Data.ByteString as B ( hPut ) import Darcs.Lock ( readLocaleFile, writeLocaleFile, worldReadableTemp, appendToFile ) import Darcs.Patch.PatchInfoAnd ( info, n2pia, PatchInfoAnd ) import Darcs.Repository ( Repository, amInHashedRepository, withRepoLock, RepoJob(..), withGutsOf, readTentativeRepo, tentativelyAddPatch, finalizeRepositoryChanges , testTentative , invalidateIndex, unrecordedChanges, readRecorded ) import Darcs.Patch ( RepoPatch, Patchy, PrimOf, PrimPatch, namepatch, summaryFL, anonymous, adddeps, fromPrims ) import Darcs.Patch.Set ( PatchSet(..) ) import Darcs.Witnesses.Eq ( unsafeCompare ) import Darcs.Witnesses.Ordered ( FL(..), (:>)(..), (+>+), reverseRL, mapFL, mapFL_FL, nullFL ) import Darcs.Witnesses.Sealed import Darcs.Patch.Info ( PatchInfo ) import Darcs.Patch.Apply( ApplyState ) import Darcs.Patch.Split ( primSplitter ) import Darcs.Patch.Choices ( patchChoicesTps, tpPatch, forceFirsts, getChoices, tag ) import Darcs.SelectChanges ( selectChanges, WhichChanges(..), selectionContext, selectionContextPrim, runSelection ) import Darcs.RepoPath ( FilePathLike, SubPath, toFilePath ) import Darcs.Commands ( DarcsCommand(..), nodefaults, commandStub ) import Darcs.Commands.Util ( announceFiles, filterExistingFiles ) import Darcs.Arguments ( DarcsFlag( PromptLongComment, NoEditLongComment, EditLongComment, LogFile, Pipe, Quiet, PatchName, AskDeps, All ), fileHelpAuthor, getAuthor, workingRepoDir, lookforadds, fixSubPaths, setEnvDarcsFiles, askLongComment, askdeps, patchSelectFlag, allPipeInteractive, leaveTestDir, test, author, patchnameOption, umaskOption, ignoretimes, nocompress, rmlogfile, logfile, listRegisteredFiles, setScriptsExecutableOption , unified ) import Darcs.Flags (willRemoveLogFile, diffingOpts, compression, isInteractive) import Darcs.Utils ( askUser, promptYorn, PromptConfig(..), promptChar, editFile, clarifyErrors ) import Progress ( debugMessage) import Darcs.ProgressPatches( progressFL) import IsoDate ( getIsoDateTime, cleanLocalDate ) import Printer ( hPutDocLn, text, wrapText, ($$) ) import ByteStringUtils ( encodeLocale ) import Storage.Hashed.Tree( Tree ) #include "impossible.h" #include "gadts.h" recordDescription :: String recordDescription = "Create a patch from unrecorded changes." recordHelp :: String recordHelp = "The `darcs record' command is used to create a patch from changes in\n" ++ "the working tree. If you specify a set of files and directories,\n" ++ "changes to other files will be skipped.\n" ++ "\n" ++ recordHelp' ++ "\n" ++ recordHelp'' record :: DarcsCommand record = DarcsCommand {commandProgramName = "darcs", commandName = "record", commandHelp = recordHelp, commandDescription = recordDescription, commandExtraArgs = -1, commandExtraArgHelp = ["[FILE or DIRECTORY]..."], commandCommand = recordCmd, commandPrereq = amInHashedRepository, commandGetArgPossibilities = listRegisteredFiles, commandArgdefaults = nodefaults, commandAdvancedOptions = [logfile, rmlogfile, nocompress, ignoretimes, umaskOption, setScriptsExecutableOption], commandBasicOptions = [patchnameOption, author, test, leaveTestDir, allPipeInteractive, askdeps, askLongComment, lookforadds, workingRepoDir, unified]} commitDescription :: String commitDescription = "Redirect the user to record, push or send." commitHelp :: String commitHelp = "This command does not do anything.\n"++ "If you want to save changes locally, use the `darcs record' command.\n"++ "If you want to save a recorded patch to another repository, use the\n"++ "`darcs push' or `darcs send' commands instead.\n" commit :: DarcsCommand commit = commandStub "commit" commitHelp commitDescription record recordCmd :: [DarcsFlag] -> [String] -> IO () recordCmd opts args = do checkNameIsNotOption opts withRepoLock opts $ RepoJob $ \repository -> do files <- if null args then return Nothing else Just . sort <$> fixSubPaths opts args when (files == Just []) $ fail "No valid arguments were given." announceFiles files "Recording changes in" existing_files <- maybe (return Nothing) (fmap Just . filterExistingFiles repository) files when (existing_files == Just []) $ fail "None of the files you specified exist!" debugMessage "About to get the unrecorded changes." changes <- unrecordedChanges (diffingOpts opts) repository files debugMessage "I've gotten unrecorded." case allow_empty_with_askdeps changes of -- Warning: A do-notation statement discarded a result of type String. Nothing -> do when (Pipe `elem` opts) $ do _ <- getDate opts return () putStrLn "No changes!" exitFailure Just ch -> doRecord repository opts existing_files ch where allow_empty_with_askdeps :: FL p C(x y) -> Maybe (FL p C(x y)) allow_empty_with_askdeps NilFL | AskDeps `elem` opts = Just NilFL | otherwise = Nothing allow_empty_with_askdeps p = Just p -- check that what we treat as the patch name is not accidentally a command -- line flag checkNameIsNotOption :: [DarcsFlag] -> IO () checkNameIsNotOption opts = do let patchNames = [n | PatchName n <- opts] when (length patchNames == 1) $ do let n = head patchNames oneLetterName = length n == 1 || (length n == 2 && head n == '-') if (oneLetterName && (All `notElem` opts)) then do confirmed <- promptYorn $ "You specified " ++ show n ++ " as the patch name. Is that really what you want?" unless confirmed $ do putStrLn "Okay, aborting the record." exitFailure else return () doRecord :: (RepoPatch p, ApplyState p ~ Tree, ApplyState (PrimOf p) ~ Tree) => Repository p C(r u r) -> [DarcsFlag] -> Maybe [SubPath] -> FL (PrimOf p) C(r x) -> IO () doRecord repository opts files ps = do let make_log = worldReadableTemp "darcs-record" date <- getDate opts my_author <- getAuthor opts debugMessage "I'm slurping the repository." debugMessage "About to select changes..." pristine <- readRecorded repository (chs :> _ ) <- runSelection (selectChanges First ps) $ selectionContextPrim "record" opts (Just primSplitter) (map toFilePath <$> files) (Just pristine) when (is_empty_but_not_askdeps chs) $ do putStrLn "Ok, if you don't want to record anything, that's fine!" exitWith ExitSuccess handleJust onlySuccessfulExits (\_ -> return ()) $ do deps <- if AskDeps `elem` opts then askAboutDepends repository chs opts [] else return [] when (AskDeps `elem` opts) $ debugMessage "I've asked about dependencies." if nullFL chs && null deps then putStrLn "Ok, if you don't want to record anything, that's fine!" else do setEnvDarcsFiles chs (name, my_log, logf) <- getLog opts Nothing make_log chs debugMessage ("Patch name as received from getLog: " ++ show (map ord name)) doActualRecord repository opts name date my_author my_log logf deps chs where is_empty_but_not_askdeps l | AskDeps `elem` opts = False -- a "partial tag" patch; see below. | otherwise = nullFL l doActualRecord :: (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u r) -> [DarcsFlag] -> String -> String -> String -> [String] -> Maybe String -> [PatchInfo] -> FL (PrimOf p) C(r x) -> IO () doActualRecord repository opts name date my_author my_log logf deps chs = do debugMessage "Writing the patch file..." mypatch <- namepatch date name my_author my_log $ fromPrims $ progressFL "Writing changes:" chs -- Warning: A do-notation statement discarded a result of type Repository p r u x. _ <- tentativelyAddPatch repository (compression opts) $ n2pia $ adddeps mypatch deps invalidateIndex repository debugMessage "Applying to pristine..." rc <- testTentative repository when (rc /= ExitSuccess) $ do when (not $ isInteractive opts) $ exitWith rc `clarifyErrors` failuremessage putStrLn $ "Looks like you have a bad patch: '"++name++"'" let prompt = "Shall I record it anyway?" yn <- promptChar (PromptConfig prompt "yn" [] (Just 'n') []) case yn of 'y' -> return () _ -> exitWith rc `clarifyErrors` failuremessage withGutsOf repository (finalizeRepositoryChanges repository) `clarifyErrors` failuremessage debugMessage "Syncing timestamps..." when (isJust logf) $ removeFile (fromJust logf) when (Quiet `notElem` opts) $ putStrLn $ "Finished recording patch '"++name++"'" where failuremessage = "Failed to record patch '"++name++"'" ++ case logf of Just lf -> "\nLogfile left in "++lf++"." Nothing -> "" recordHelp' :: String recordHelp' = "Every patch has a name, an optional description, an author and a date.\n" ++ "\n" ++ "The patch name should be a short sentence that concisely describes the\n" ++ "patch, such as `Add error handling to main event loop.' You can\n" ++ "supply it in advance with the -m option, or provide it when prompted.\n" ++ "\n" ++ "The patch description is an optional block of free-form text. It is\n" ++ "used to supply additional information that doesn't fit in the patch\n" ++ "name. For example, it might include a rationale of WHY the change was\n" ++ "necessary. By default Darcs asks if you want to add a description;\n" ++ "the --edit-long-comment and --skip-long-comment can be used to answer\n" ++ "`yes' or `no' (respectively) to this prompt. Finally, the --logfile\n" ++ "option allows you to supply a file that already contains the patch\n" ++ "name (first line) and patch description (subsequent lines). This is\n" ++ "useful if a previous record failed and left a darcs-record-0 file.\n" ++ "\n" ++ unlines fileHelpAuthor ++ "\n" ++ "The patch date is generated automatically. It can only be spoofed by\n" ++ "using the --pipe option.\n" getDate :: [DarcsFlag] -> IO String getDate opts | Pipe `elem` opts = do cleanLocalDate `fmap` askUser "What is the date? " getDate _ = getIsoDateTime data PName = FlagPatchName String | PriorPatchName String | NoPatchName getLog :: forall prim C(x y) . (Patchy prim, PrimPatch prim) => [DarcsFlag] -> Maybe (String, [String]) -> IO String -> FL prim C(x y) -> IO (String, [String], Maybe String) getLog opts m_old make_log chs = gl opts where patchname_specified = patchname_helper opts patchname_helper (PatchName n:_) | "TAG " `isPrefixOf` n = FlagPatchName $ '.':n | otherwise = FlagPatchName n patchname_helper (_:fs) = patchname_helper fs patchname_helper [] = case m_old of Just (p,_) -> PriorPatchName p Nothing -> NoPatchName default_log = case m_old of Nothing -> [] Just (_,l) -> l gl (Pipe:_) = do p <- case patchname_specified of FlagPatchName p -> return p PriorPatchName p -> return p NoPatchName -> prompt_patchname False putStrLn "What is the log?" thelog <- lines `fmap` Ratified.hGetContents stdin return (p, thelog, Nothing) gl (LogFile f:fs) = do -- round 1 (patchname) mlp <- lines `fmap` readLocaleFile f `catch` (\(_ :: IOException) -> return []) firstname <- case (patchname_specified, mlp) of (FlagPatchName p, []) -> return p (_, p:_) -> return p -- logfile trumps prior! (PriorPatchName p, []) -> return p (NoPatchName, []) -> prompt_patchname True -- round 2 append_info f firstname -- Warning: A do-notation statement discarded a result of type ExitCode. when (EditLongComment `elem` fs) $ do _ <- editFile f return () (name, thelog, _) <- read_long_comment f firstname let toRemove = if willRemoveLogFile opts then Just $ toFilePath f else Nothing return (name, thelog, toRemove) gl (EditLongComment:_) = case patchname_specified of FlagPatchName p -> actually_get_log p PriorPatchName p -> actually_get_log p NoPatchName -> prompt_patchname True >>= actually_get_log gl (NoEditLongComment:_) = case patchname_specified of FlagPatchName p | Just ("",_) <- m_old -> return (p, default_log, Nothing) -- rollback -m FlagPatchName p -> return (p, default_log, Nothing) -- record (or amend) -m PriorPatchName p -> return (p, default_log, Nothing) -- amend NoPatchName -> do p <- prompt_patchname True -- record return (p, [], Nothing) gl (PromptLongComment:fs) = case patchname_specified of FlagPatchName p -> prompt_long_comment p -- record (or amend) -m _ -> gl fs gl (_:fs) = gl fs gl [] = case patchname_specified of FlagPatchName p -> return (p, default_log, Nothing) -- record (or amend) -m PriorPatchName "" -> prompt_patchname True >>= prompt_long_comment PriorPatchName p -> return (p, default_log, Nothing) NoPatchName -> prompt_patchname True >>= prompt_long_comment prompt_patchname retry = do n <- askUser "What is the patch name? " if n == "" || "TAG " `isPrefixOf` n then if retry then prompt_patchname retry else fail "Bad patch name!" else return n prompt_long_comment oldname = do y <- promptYorn "Do you want to add a long comment?" if y then actually_get_log oldname else return (oldname, [], Nothing) actually_get_log p = do logf <- make_log -- TODO: make sure encoding used for logf is the same everywhere -- probably should be locale because the editor will assume it writeLocaleFile logf $ unlines $ p : default_log append_info logf p -- Warning: A do-notation statement discarded a result of type ExitCode. _ <- editFile logf read_long_comment logf p read_long_comment :: FilePathLike p => p -> String -> IO (String, [String], Maybe p) read_long_comment f oldname = do t <- (lines.filter (/='\r')) `fmap` readLocaleFile f case t of [] -> return (oldname, [], Just f) (n:ls) -> return (n, takeWhile (not.(eod `isPrefixOf`)) ls, Just f) append_info f oldname = do fc <- readLocaleFile f appendToFile f $ \h -> do case fc of _ | null (lines fc) -> B.hPut h (encodeLocale (oldname ++ "\n")) | last fc /= '\n' -> B.hPut h (encodeLocale "\n") | otherwise -> return () hPutDocLn h $ text eod $$ text "" $$ wrapText 75 ("Place the long patch description above the "++ eod++ " marker. The first line of this file "++ "will be the patch name.") $$ text "" $$ text "This patch contains the following changes:" $$ text "" $$ summaryFL chs eod :: String eod = "***END OF DESCRIPTION***" askAboutDepends :: forall p C(r u t y) . (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u t) -> FL (PrimOf p) C(t y) -> [DarcsFlag] -> [PatchInfo] -> IO [PatchInfo] askAboutDepends repository pa' opts olddeps = do -- ideally we'd just default the olddeps to yes but still ask about them. -- SelectChanges doesn't currently (17/12/09) offer a way to do this so would -- have to have this support added first. pps <- readTentativeRepo repository pa <- n2pia `fmap` anonymous (fromPrims pa') FlippedSeal ps <- return ((case pps of PatchSet x _ -> FlippedSeal ((reverseRL x)+>+(pa:>:NilFL))) :: FlippedSeal (FL (PatchInfoAnd p)) C(y)) let (pc, tps) = patchChoicesTps ps tas = case catMaybes (mapFL (\tp -> if pa `unsafeCompare` (tpPatch tp) || info (tpPatch tp) `elem` olddeps then Just (tag tp) else Nothing) tps) of [] -> error "askAboutDepends: []" tgs -> tgs Sealed2 ps' <- return $ case getChoices (forceFirsts tas pc) of _ :> mc :> _ -> Sealed2 $ mapFL_FL tpPatch mc (deps:>_) <- runSelection (selectChanges FirstReversed ps') $ selectionContext "depend on" (filter askdep_allowed opts) Nothing Nothing return $ olddeps `union` mapFL info deps where askdep_allowed = not . patchSelectFlag onlySuccessfulExits :: ExitCode -> Maybe () onlySuccessfulExits ExitSuccess = Just () onlySuccessfulExits _ = Nothing recordHelp'' :: String recordHelp'' = "If a test command has been defined with `darcs setpref', attempting to\n" ++ "record a patch will cause the test command to be run in a clean copy\n" ++ "of the working tree (that is, including only recorded changes). If\n" ++ "the test fails, you will be offered to abort the record operation.\n" ++ "\n" ++ "The --set-scripts-executable option causes scripts to be made\n" ++ "executable in the clean copy of the working tree, prior to running the\n" ++ "test. See `darcs get' for an explanation of the script heuristic.\n" ++ "\n" ++ "If your test command is tediously slow (e.g. `make all') and you are\n" ++ "recording several patches in a row, you may wish to use --no-test to\n" ++ "skip all but the final test.\n" ++ "\n" ++ "To see some context (unchanged lines) around each change, use the\n" ++ "--unified option.\n" darcs-2.8.4/src/Darcs/Commands/Remove.hs0000644001765600176560000001731512104371431017325 0ustar ganeshganesh-- Copyright (C) 2002-2004 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP #-} module Darcs.Commands.Remove ( remove, rm, unadd ) where import Control.Monad ( when, foldM ) import Darcs.Commands ( DarcsCommand(..), nodefaults, commandAlias, commandStub, putWarning ) import Darcs.Arguments ( DarcsFlag (Recursive), fixSubPaths, listRegisteredFiles, workingRepoDir, umaskOption, recursive ) import Darcs.RepoPath ( SubPath, sp2fn ) import Darcs.Repository ( Repository, withRepoLock, RepoJob(..), amInHashedRepository, addToPending, readRecordedAndPending, readUnrecorded ) import Darcs.Diff( treeDiff ) import Darcs.Patch ( RepoPatch, PrimOf, PrimPatch, adddir, rmdir, addfile, rmfile ) import Darcs.Patch.FileName( fn2fp ) import Darcs.Patch.Apply( ApplyState ) import Darcs.Witnesses.Ordered ( FL(..), (+>+) ) import Darcs.Witnesses.Sealed ( Sealed(..), Gap(..), FreeLeft, unFreeLeft ) import Darcs.Repository.Prefs ( filetypeFunction, FileType ) import Storage.Hashed.Tree( Tree, TreeItem(..), find, modifyTree, expand, list ) import Storage.Hashed.AnchoredPath( anchorPath, AnchoredPath ) import Storage.Hashed( floatPath ) import Darcs.Commands.Add( expandDirs ) import Printer ( text ) #include "gadts.h" removeDescription :: String removeDescription = "Remove files from version control." removeHelp :: String removeHelp = "The `darcs remove' command exists primarily for symmetry with `darcs\n" ++ "add', as the normal way to remove a file from version control is\n" ++ "simply to delete it from the working tree. This command is only\n" ++ "useful in the unusual case where one wants to record a removal patch\n" ++ "WITHOUT deleting the copy in the working tree (which can be re-added).\n" ++ "\n" ++ "Note that applying a removal patch to a repository (e.g. by pulling\n" ++ "the patch) will ALWAYS affect the working tree of that repository.\n" remove :: DarcsCommand remove = DarcsCommand {commandProgramName = "darcs", commandName = "remove", commandHelp = removeHelp, commandDescription = removeDescription, commandExtraArgs = -1, commandExtraArgHelp = [" ..."], commandCommand = removeCmd, commandPrereq = amInHashedRepository, commandGetArgPossibilities = listRegisteredFiles, commandArgdefaults = nodefaults, commandAdvancedOptions = [umaskOption], commandBasicOptions = [workingRepoDir, recursive "recurse into subdirectories"]} removeCmd :: [DarcsFlag] -> [String] -> IO () removeCmd opts relargs = do when (null relargs) $ fail "Nothing specified, nothing removed." origfiles <- fixSubPaths opts relargs when (null origfiles) $ fail "No valid arguments were given." withRepoLock opts $ RepoJob $ \repository -> do args <- if Recursive `elem` opts then reverse `fmap` expandDirs origfiles else return origfiles Sealed p <- makeRemovePatch opts repository args addToPending repository p -- | makeRemovePatch builds a list of patches to remove the given filepaths. -- This function does not recursively process directories. The 'Recursive' -- flag should be handled by the caller by adding all offspring of a directory -- to the files list. makeRemovePatch :: (RepoPatch p, ApplyState p ~ Tree) => [DarcsFlag] -> Repository p C(r u t) -> [SubPath] -> IO (Sealed (FL (PrimOf p) C(u))) makeRemovePatch opts repository files = do recorded <- expand =<< readRecordedAndPending repository unrecorded <- readUnrecorded repository $ Just files ftf <- filetypeFunction result <- foldM removeOnePath (ftf,recorded,unrecorded, []) $ map (floatPath . fn2fp . sp2fn) files case result of (_, _, _, patches) -> return $ unFreeLeft $ foldr (joinGap (+>+)) (emptyGap NilFL) $ reverse patches where removeOnePath (ftf, recorded, unrecorded, patches) f = do let recorded' = modifyTree recorded f Nothing unrecorded' = modifyTree unrecorded f Nothing local <- makeRemoveGap opts ftf recorded unrecorded unrecorded' f -- we can tell if the remove succeeded by looking if local is -- empty. If the remove succeeded, we should pass on updated -- recorded and unrecorded that reflect the removal return $ case local of Just gap -> (ftf, recorded', unrecorded', gap : patches) _ -> (ftf, recorded, unrecorded, patches) -- | Takes a file path and returns the FL of patches to remove that, wrapped in -- a 'Gap'. -- Returns 'Nothing' in case the path cannot be removed (if it is not tracked, -- or if it's a directory and it's not tracked). -- The three 'Tree' arguments are the recorded state, the unrecorded state -- excluding the removal of this file, and the unrecorded state including the -- removal of this file. makeRemoveGap :: PrimPatch prim => [DarcsFlag] -> (FilePath -> FileType) -> Tree IO -> Tree IO -> Tree IO -> AnchoredPath -> IO (Maybe (FreeLeft (FL prim))) makeRemoveGap opts ftf recorded unrecorded unrecorded' f = case (find recorded f, find unrecorded f) of (Just (SubTree _), Just (SubTree unrecordedChildren)) -> do if not $ null (list unrecordedChildren) then skipAndWarn "it is not empty" else return $ Just $ freeGap (rmdir f_fp :>: NilFL) (Just (File _), Just (File _)) -> Just `fmap` treeDiff ftf unrecorded unrecorded' (Just (File _), _) -> return $ Just $ freeGap (addfile f_fp :>: rmfile f_fp :>: NilFL) (Just (SubTree _), _) -> return $ Just $ freeGap (adddir f_fp :>: rmdir f_fp :>: NilFL) (_, _) -> skipAndWarn "it is not tracked by darcs" where f_fp = anchorPath "" f skipAndWarn reason = do putWarning opts . text $ "Can't remove " ++ f_fp ++ " (" ++ reason ++ ")" return $ Nothing rmDescription :: String rmDescription = "Help newbies find `darcs remove'." rmHelp :: String rmHelp = "The `darcs rm' command does nothing.\n" ++ "\n" ++ "The normal way to remove a file from version control is simply to\n" ++ "delete it from the working tree. To remove a file from version\n" ++ "control WITHOUT affecting the working tree, see `darcs remove'.\n" rm :: DarcsCommand rm = commandStub "rm" rmHelp rmDescription remove unadd :: DarcsCommand unadd = commandAlias "unadd" Nothing remove darcs-2.8.4/src/Darcs/Commands/Replace.hs0000644001765600176560000002773212104371431017447 0ustar ganeshganesh-- Copyright (C) 2002-2005 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP #-} module Darcs.Commands.Replace ( replace, defaultToks ) where import Prelude hiding ( catch ) import Data.Maybe ( isJust ) import Control.Monad ( unless, filterM ) import Control.Applicative( (<$>) ) import Control.Exception ( catch, IOException ) import Darcs.Commands ( DarcsCommand(..), nodefaults ) import Darcs.Arguments ( DarcsFlag(ForceReplace, Toks), listRegisteredFiles, ignoretimes, umaskOption, tokens, forceReplace, workingRepoDir, fixSubPaths ) import Darcs.Repository ( withRepoLock, RepoJob(..), addToPending, amInHashedRepository, applyToWorking, readUnrecorded, readRecordedAndPending ) import Darcs.Patch ( Patchy, PrimPatch, tokreplace, forceTokReplace, applyToTree ) import Darcs.Patch.Apply( ApplyState ) import Darcs.Patch.FileName( fn2fp ) import Darcs.Patch.Patchy ( Apply ) import Darcs.Witnesses.Ordered ( FL(..), (+>+), concatFL, toFL ) import Darcs.Witnesses.Sealed ( Sealed(..), mapSeal, FreeLeft, Gap(..) ) import Darcs.Patch.RegChars ( regChars ) import Data.Char ( isSpace ) import Darcs.RepoPath ( SubPath, toFilePath, sp2fn ) import Darcs.Repository.Prefs ( FileType(TextFile) ) import Darcs.Diff( treeDiff ) import Storage.Hashed.Tree( readBlob, modifyTree , findFile, TreeItem(..), Tree, makeBlobBS ) import Storage.Hashed.AnchoredPath( AnchoredPath, floatPath ) import qualified Data.ByteString.Lazy as BL import qualified Data.ByteString as BS #include "impossible.h" #include "gadts.h" replaceDescription :: String replaceDescription = "Substitute one word for another." replaceHelp :: String replaceHelp = "In addition to line-based patches, Darcs supports a limited form of\n" ++ "lexical substitution. Files are treated as sequences of words, and\n" ++ "each occurrence of the old word is replaced by the new word.\n" ++ "This is intended to provide a clean way to rename a function or\n" ++ "variable. Such renamings typically affect lines all through the\n" ++ "source code, so a traditional line-based patch would be very likely to\n" ++ "conflict with other branches, requiring manual merging.\n" ++ "\n" ++ "Files are tokenized according to one simple rule: words are strings of\n" ++ "valid token characters, and everything between them (punctuation and\n" ++ -- FIXME: this heuristic is ham-fisted and silly. Can we drop it? "whitespace) is discarded. By default, valid token characters are\n" ++ "letters, numbers and the underscore (i.e. [A-Za-z0-9_]). However if\n" ++ "the old and/or new token contains either a hyphen or period, BOTH\n" ++ "hyphen and period are treated as valid (i.e. [A-Za-z0-9_.-]).\n" ++ "\n" ++ "The set of valid characters can be customized using the --token-chars\n" ++ "option. The argument must be surrounded by square brackets. If a\n" ++ "hyphen occurs between two characters in the set, it is treated as a\n" ++ "set range. For example, in most locales [A-Z] denotes all uppercase\n" ++ "letters. If the first character is a caret, valid tokens are taken to\n" ++ "be the complement of the remaining characters. For example, [^:\\n]\n" ++ "could be used to match fields in the passwd(5), where records and\n" ++ "fields are separated by newlines and colons respectively.\n" ++ "\n" ++ "If you choose to use --token-chars, you are STRONGLY encouraged to do\n" ++ "so consistently. The consequences of using multiple replace patches\n" ++ "with different --token-chars arguments on the same file are not well\n" ++ "tested nor well understood.\n" ++ "\n" ++ "By default Darcs will refuse to perform a replacement if the new token\n" ++ "is already in use, because the replacements would be not be\n" ++ "distinguishable from the existing tokens. This behaviour can be\n" ++ "overridden by supplying the --force option, but an attempt to `darcs\n" ++ "rollback' the resulting patch will affect these existing tokens.\n" ++ "\n" ++ "Limitations:\n" ++ "\n" ++ "The tokenizer treats files as byte strings, so it is not possible for\n" ++ "--token-chars to include multi-byte characters, such as the non-ASCII\n" ++ "parts of UTF-8. Similarly, trying to replace a `high-bit' character\n" ++ "from a unibyte encoding will also result in replacement of the same\n" ++ "byte in files with different encodings. For example, an acute a from\n" ++ "ISO 8859-1 will also match an alpha from ISO 8859-7.\n" ++ "\n" ++ "Due to limitations in the patch file format, --token-chars arguments\n" ++ "cannot contain literal whitespace. For example, [^ \\n\\t] cannot be\n" ++ "used to declare all characters except the space, tab and newline as\n" ++ "valid within a word, because it contains a literal space.\n" ++ "\n" ++ "Unlike POSIX regex(7) bracket expressions, character classes (such as\n" ++ "[[:alnum:]]) are NOT supported by --token-chars, and will be silently\n" ++ "treated as a simple set of characters.\n" replace :: DarcsCommand replace = DarcsCommand {commandProgramName = "darcs", commandName = "replace", commandHelp = replaceHelp, commandDescription = replaceDescription, commandExtraArgs = -1, commandExtraArgHelp = ["","", " ..."], commandCommand = replaceCmd, commandPrereq = amInHashedRepository, commandGetArgPossibilities = listRegisteredFiles, commandArgdefaults = nodefaults, commandAdvancedOptions = [ignoretimes, umaskOption], commandBasicOptions = [tokens, forceReplace, workingRepoDir]} replaceCmd :: [DarcsFlag] -> [String] -> IO () replaceCmd opts (old:new:relfs) = withRepoLock opts $ RepoJob $ \repository -> do fs <- fixSubPaths opts relfs toks <- chooseToks opts old new let checkToken tok = unless (isTok toks tok) $ fail $ "'"++tok++"' is not a valid token!" checkToken old checkToken new work <- readUnrecorded repository Nothing cur <- readRecordedAndPending repository files <- filterM (exists work) fs Sealed pswork <- mapSeal concatFL . toFL <$> mapM (repl toks cur work) files addToPending repository pswork _ <- applyToWorking repository opts pswork `catch` \(e :: IOException) -> fail $ "Can't do replace on working!\n" ++ "Perhaps one of the files already contains '"++ new++"'?\n" ++ show e return () where ftf _ = TextFile skipmsg f = "Skipping file '" ++ toFilePath f ++ "' which isn't in the repository." exists tree file = if isJust $ findFile tree (floatSubPath file) then return True else do putStrLn $ skipmsg file return False repl :: forall prim . (Patchy prim, PrimPatch prim, ApplyState prim ~ Tree) => String -> Tree IO -> Tree IO -> SubPath -> IO (FreeLeft (FL prim)) repl toks cur work f = do work_replaced <- maybeApplyToTree replace_patch work cur_replaced <- maybeApplyToTree replace_patch cur if ForceReplace `elem` opts || isJust work_replaced || isJust cur_replaced then get_force_replace f toks work else do putStrLn $ "Skipping file '"++f_fp++"'" putStrLn $ "Perhaps the recorded version of this " ++ "file already contains '" ++new++"'?" putStrLn $ "Use the --force option to override." return (emptyGap NilFL) where f_fp = toFilePath f replace_patch :: prim C(x y) replace_patch = tokreplace f_fp toks old new get_force_replace :: PrimPatch prim => SubPath -> String -> Tree IO -> IO (FreeLeft (FL prim)) get_force_replace f toks tree = do let path = floatSubPath f content <- readBlob $ fromJust $ findFile tree path let newcontent = forceTokReplace toks new old (BS.concat $ BL.toChunks content) tree' = modifyTree tree path (File . makeBlobBS <$> newcontent) case newcontent of Nothing -> bug "weird forcing bug in replace." Just _ -> do pfix <- treeDiff ftf tree tree' putStrLn $ "Don't be surprised!" putStrLn $ "I've changed all instances of '" ++ new ++ "' to '" ++ old ++ "' first" putStrLn $ "so that darcs replace can token-replace them back into '" ++ new ++ "' again." return $ joinGap (+>+) pfix (freeGap (tokreplace f_fp toks old new :>: NilFL)) where f_fp = toFilePath f replaceCmd _ _ = fail "Usage: darcs replace OLD NEW [FILES]" floatSubPath :: SubPath -> AnchoredPath floatSubPath = floatPath . fn2fp . sp2fn maybeApplyToTree :: (Apply p, ApplyState p ~ Tree) => p C(x y) -> Tree IO -> IO (Maybe (Tree IO)) maybeApplyToTree patch tree = catch (Just `fmap` applyToTree patch tree) (\(_ :: IOException) -> return Nothing) defaultToks :: String defaultToks = "A-Za-z_0-9" filenameToks :: String filenameToks = "A-Za-z_0-9\\-\\." -- | Given a set of characters and a string, returns true iff the -- string contains only characters from the set. A set beginning with -- a caret (@^@) is treated as a complementary set. isTok :: String -> String -> Bool isTok _ "" = False isTok toks s = all (regChars toks) s -- | This function checks for @--token-chars@ on the command-line. If -- found, it validates the argument and returns it, without the -- surrounding square brackets. Otherwise, it returns either -- 'defaultToks' or 'filenameToks' as explained in 'replaceHelp'. -- -- Note: Limitations in the current replace patch file format prevents -- tokens and token-char specifiers from containing any whitespace. chooseToks :: [DarcsFlag] -> String -> String -> IO String chooseToks (Toks t:_) a b | length t <= 2 = bad_token_spec $ "It must contain more than 2 characters, because " ++ "it should be enclosed in square brackets" | head t /= '[' || last t /= ']' = bad_token_spec "It should be enclosed in square brackets" | '^' == head tok && length tok == 1 = bad_token_spec "Must be at least one character in the complementary set" | any isSpace t = bad_token_spec "Space is not allowed in the spec" | any isSpace a = bad_token_spec $ spacey_token a | any isSpace b = bad_token_spec $ spacey_token b | not (isTok tok a) = bad_token_spec $ not_a_token a | not (isTok tok b) = bad_token_spec $ not_a_token b | otherwise = return tok where tok = init $ tail t :: String bad_token_spec msg = fail $ "Bad token spec: '"++ t ++"' ("++ msg ++")" spacey_token x = x ++ " must not contain any space" not_a_token x = x ++ " is not a token, according to your spec" chooseToks (_:fs) a b = chooseToks fs a b chooseToks [] a b = if isTok defaultToks a && isTok defaultToks b then return defaultToks else return filenameToks darcs-2.8.4/src/Darcs/Commands/Revert.hs0000644001765600176560000001337212104371431017336 0ustar ganeshganesh-- Copyright (C) 2002-2005 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. module Darcs.Commands.Revert ( revert ) where import Prelude hiding ( catch ) import System.Exit ( ExitCode(..), exitWith ) import Control.Applicative ( (<$>) ) import Control.Exception ( catch, IOException ) import Control.Monad ( when ) import Data.List ( sort ) import English (englishNum, This(..), Noun(..)) import Darcs.Flags( diffingOpts ) import Darcs.Commands ( DarcsCommand(..), nodefaults ) import Darcs.Commands.Util ( announceFiles ) import Darcs.Arguments ( DarcsFlag( All, Debug ), ignoretimes, workingRepoDir, allInteractive, fixSubPaths, listRegisteredFiles, umaskOption, unified ) import Darcs.Utils ( askUser ) import Darcs.RepoPath ( toFilePath ) import Darcs.Repository ( withRepoLock, RepoJob(..), withGutsOf, addToPending, applyToWorking, amInHashedRepository, readRecorded, unrecordedChanges ) import Darcs.Patch ( invert, effectOnFilePaths, commute ) import Darcs.Patch.Split ( reversePrimSplitter ) import Darcs.Witnesses.Ordered ( FL(..), (:>)(..), lengthFL, nullFL, (+>+) ) import Darcs.SelectChanges ( selectChanges, WhichChanges(Last), selectionContextPrim, runSelection ) import Darcs.Patch.TouchesFiles ( chooseTouching ) import Darcs.Commands.Unrevert ( writeUnrevert ) import Darcs.Witnesses.Sealed ( Sealed(..) ) #include "gadts.h" revertDescription :: String revertDescription = "Discard unrecorded changes." revertHelp :: String revertHelp = "The `darcs revert' command discards unrecorded changes the working\n" ++ "tree. As with `darcs record', you will be asked which hunks (changes)\n" ++ "to revert. The --all switch can be used to avoid such prompting. If\n" ++ "files or directories are specified, other parts of the working tree\n" ++ "are not reverted.\n" ++ "\n" ++ "In you accidentally reverted something you wanted to keep (for\n" ++ "example, typing `darcs rev -a' instead of `darcs rec -a'), you can\n" ++ "immediately run `darcs unrevert' to restore it. This is only\n" ++ "guaranteed to work if the repository has not changed since `darcs\n" ++ "revert' ran.\n" revert :: DarcsCommand revert = DarcsCommand {commandProgramName = "darcs", commandName = "revert", commandHelp = revertHelp, commandDescription = revertDescription, commandExtraArgs = -1, commandExtraArgHelp = ["[FILE or DIRECTORY]..."], commandCommand = revertCmd, commandPrereq = amInHashedRepository, commandGetArgPossibilities = listRegisteredFiles, commandArgdefaults = nodefaults, commandAdvancedOptions = [ignoretimes, umaskOption], commandBasicOptions = [allInteractive, unified, workingRepoDir]} revertCmd :: [DarcsFlag] -> [String] -> IO () revertCmd opts args = withRepoLock opts $ RepoJob $ \repository -> do files <- if null args then return Nothing else Just . sort <$> fixSubPaths opts args announceFiles files "Reverting changes in" changes <- unrecordedChanges (diffingOpts opts {- always ScanKnown here -}) repository files let pre_changed_files = effectOnFilePaths (invert changes) . map toFilePath <$> files rec <- readRecorded repository Sealed touching_changes <- return (chooseTouching pre_changed_files changes) (case touching_changes of NilFL -> putStrLn "There are no changes to revert!" _ -> do let context = selectionContextPrim "revert" opts (Just reversePrimSplitter) pre_changed_files (Just rec) (norevert:>p) <- runSelection (selectChanges Last changes) context if nullFL p then putStrLn $ "If you don't want to revert after all," ++ " that's fine with me!" else do let theseChanges = englishNum (lengthFL p) . This . Noun $ "change" yorn <- if All `elem` opts then return "y" else askUser $ "Do you really want to revert " ++ theseChanges "? " case yorn of ('y':_) -> return () _ -> exitWith $ ExitSuccess withGutsOf repository $ do addToPending repository $ invert p when (Debug `elem` opts) $ putStrLn "About to write the unrevert file." case commute (norevert:>p) of Just (p':>_) -> writeUnrevert repository p' rec NilFL Nothing -> writeUnrevert repository (norevert+>+p) rec NilFL when (Debug `elem` opts) $ putStrLn "About to apply to the working directory." _ <- applyToWorking repository opts (invert p) `catch` \(e :: IOException) -> fail ("Unable to apply inverse patch!" ++ show e) return ()) :: IO () putStrLn "Finished reverting." darcs-2.8.4/src/Darcs/Commands/Rollback.hs0000644001765600176560000002275012104371431017620 0ustar ganeshganesh-- Copyright (C) 2002-2004,2007 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP #-} module Darcs.Commands.Rollback ( rollback ) where import Prelude hiding ( catch ) import Control.Applicative ( (<$>) ) import Control.Exception ( catch, IOException ) import Control.Monad ( when ) import System.Exit ( exitWith, ExitCode(..) ) import Data.List ( sort ) import Data.Maybe ( isJust ) import System.Directory ( removeFile ) import Darcs.Commands ( DarcsCommand(..), nodefaults ) import Darcs.Arguments ( DarcsFlag(MarkConflicts), fixSubPaths, getAuthor, setEnvDarcsPatches, workingRepoDir, nocompress, author, patchnameOption, askLongComment, leaveTestDir, notest, listRegisteredFiles, matchSeveralOrLast, allInteractive, umaskOption, recordRollback ) import Darcs.RepoPath ( toFilePath ) import Darcs.Repository ( Repository, amInHashedRepository, withRepoLock, RepoJob(..), applyToWorking, readRepo, tentativelyMergePatches, withGutsOf, testTentative, finalizeRepositoryChanges, invalidateIndex, tentativelyAddToPending, considerMergeToWorking ) import Darcs.Patch ( RepoPatch, summary, invert, namepatch, effect, fromPrims, sortCoalesceFL, canonize, anonymous, PrimOf ) import Darcs.Patch.Apply( ApplyState ) import Darcs.Flags ( isInteractive, rollbackInWorkingDir ) import Darcs.Patch.Set ( PatchSet(..), newset2FL ) import Darcs.Patch.Split ( reversePrimSplitter ) import Darcs.Witnesses.Ordered import Darcs.Patch.PatchInfoAnd ( PatchInfoAnd, n2pia ) import Darcs.Lock ( worldReadableTemp ) import Darcs.Match ( firstMatch ) import Darcs.SelectChanges ( selectChanges, WhichChanges(..), selectionContext, selectionContextPrim, runSelection ) import Darcs.Commands.Record ( getLog ) import Darcs.Commands.Unrecord ( getLastPatches ) import Darcs.Commands.Util ( announceFiles, filterExistingFiles ) import Darcs.Utils ( clarifyErrors, PromptConfig(..), promptChar ) import Printer ( renderString ) import Progress ( debugMessage ) import Darcs.Witnesses.Sealed ( Sealed(..) ) import IsoDate ( getIsoDateTime ) import Storage.Hashed.Tree( Tree ) #include "impossible.h" #include "gadts.h" rollbackDescription :: String rollbackDescription = "Record a new patch reversing some recorded changes." rollbackHelp :: String rollbackHelp = "Rollback is used to undo the effects of one or more patches without actually\n"++ "deleting them. Instead, it creates a new patch reversing selected portions.\n"++ "of those changes. Unlike obliterate and unrecord (which accomplish a similar\n"++ "goal) rollback is perfectly safe, since it leaves in the repository a record\n"++ "of its changes.\n" rollback :: DarcsCommand rollback = DarcsCommand {commandProgramName = "darcs", commandName = "rollback", commandHelp = rollbackHelp, commandDescription = rollbackDescription, commandExtraArgs = -1, commandExtraArgHelp = ["[FILE or DIRECTORY]..."], commandCommand = rollbackCmd, commandPrereq = amInHashedRepository, commandGetArgPossibilities = listRegisteredFiles, commandArgdefaults = nodefaults, commandAdvancedOptions = [nocompress,umaskOption], commandBasicOptions = [matchSeveralOrLast, allInteractive, author, patchnameOption, askLongComment, notest, leaveTestDir, workingRepoDir, recordRollback]} rollbackCmd :: [DarcsFlag] -> [String] -> IO () rollbackCmd opts args = withRepoLock opts $ RepoJob $ \repository -> do files <- if null args then return Nothing else Just . sort <$> fixSubPaths opts args when (files == Just []) $ fail "No valid arguments were given." let files_fp = map toFilePath <$> files announceFiles files "Recording changes in" existing_files <- maybe (return Nothing) (fmap Just . filterExistingFiles repository) files when (existing_files == Just []) $ fail "None of the files you specified exist!" allpatches <- readRepo repository (_ :> patches) <- return $ if firstMatch opts then getLastPatches opts allpatches else (PatchSet NilRL NilRL):> (newset2FL allpatches) let patches_context = selectionContext "rollback" opts Nothing files_fp (_ :> ps) <- runSelection (selectChanges LastReversed patches) patches_context when (nullFL ps) $ do putStrLn "No patches selected!" exitWith ExitSuccess setEnvDarcsPatches ps let hunks_context = selectionContextPrim "rollback" opts (Just reversePrimSplitter) files_fp Nothing hunks = (concatFL $ mapFL_FL canonize $ sortCoalesceFL $ effect ps) runSelection (selectChanges Last hunks) hunks_context >>= if (rollbackInWorkingDir opts) then (undoItNow opts repository) else (rollItBackNow opts repository ps) rollItBackNow :: (RepoPatch p, ApplyState p ~ Tree, ApplyState (PrimOf p) ~ Tree) => [DarcsFlag] -> Repository p C(r u t) -> FL (PatchInfoAnd p) C(x y) -> (q :> FL (PrimOf p)) C(a t) -> IO () rollItBackNow opts repository ps (_ :> ps'') = do when (nullFL ps'') $ do putStrLn "No changes selected!" exitWith ExitSuccess let make_log = worldReadableTemp "darcs-rollback" newlog = Just ("", "":"rolling back:":"":lines (renderString $ summary ps )) --tentativelyRemovePatches repository opts (mapFL_FL hopefully ps) (name, my_log, logf) <- getLog opts newlog make_log $ invert ps'' date <- getIsoDateTime my_author <- getAuthor opts rbp <- n2pia `fmap` namepatch date name my_author my_log (fromPrims $ invert ps'') debugMessage "Adding rollback patch to repository." Sealed pw <- tentativelyMergePatches repository "rollback" (MarkConflicts : opts) NilFL (rbp :>: NilFL) debugMessage "Finalizing rollback changes..." invalidateIndex repository rc <- testTentative repository when (rc /= ExitSuccess) $ do when (not $ isInteractive opts) $ exitWith rc putStrLn $ "Looks like you have a bad patch: '"++name++"'" let prompt = "Shall I rollback anyway?" yn <- promptChar (PromptConfig prompt "yn" [] (Just 'n') []) case yn of 'y' -> return () _ -> exitWith rc withGutsOf repository $ do finalizeRepositoryChanges repository debugMessage "About to apply rolled-back changes to working directory." _ <- revertable $ applyToWorking repository opts pw return () when (isJust logf) $ removeFile (fromJust logf) putStrLn "Finished rolling back." where revertable x = x `clarifyErrors` unlines ["Error applying patch to the working directory.","", "This may have left your working directory an inconsistent", "but recoverable state. If you had no un-recorded changes", "by using 'darcs revert' you should be able to make your", "working directory consistent again."] undoItNow :: (RepoPatch p, ApplyState p ~ Tree, ApplyState (PrimOf p) ~ Tree) => [DarcsFlag] -> Repository p C(r u t) -> (q :> FL (PrimOf p)) C(a t) -> IO () undoItNow opts repo (_ :> prims) = do rbp <- n2pia `fmap` anonymous (fromPrims $ invert prims) Sealed pw <- considerMergeToWorking repo "rollback" (MarkConflicts: opts) NilFL (rbp :>: NilFL) tentativelyAddToPending repo opts pw withGutsOf repo $ do finalizeRepositoryChanges repo _ <- applyToWorking repo opts pw `catch` \(e :: IOException) -> fail ("error applying rolled back patch to working directory\n" ++ show e) debugMessage "Finished applying unrecorded rollback patch" darcs-2.8.4/src/Darcs/Commands/Send.hs0000644001765600176560000004756612104371431016774 0ustar ganeshganesh-- Copyright (C) 2002-2004 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP, TypeOperators #-} module Darcs.Commands.Send ( send ) where import Prelude hiding ( catch ) import System.Exit ( exitWith, ExitCode( ExitSuccess ) ) #ifndef HAVE_MAPI import System.Exit ( ExitCode( ExitFailure ) ) #endif import System.IO.Error ( ioeGetErrorString ) import System.IO ( hClose ) import Control.Exception ( catch, IOException ) import Control.Monad ( when, unless, forM_ ) import Storage.Hashed.Tree ( Tree ) import Data.List ( intercalate, isPrefixOf, stripPrefix ) import Data.Maybe ( isNothing, fromMaybe ) import Darcs.Commands ( DarcsCommand(..), putInfo, putVerbose ) import Darcs.Arguments ( DarcsFlag( EditDescription, LogFile, Target, Context, DryRun, Quiet ), fixUrl, setEnvDarcsPatches, getCc, getAuthor, workingRepoDir, editDescription, logfile, rmlogfile, sign, getSubject, depsSel, getInReplyTo, matchSeveral, setDefault, outputAutoName, output, ccSend, subject, target, author, sendmailCmd, inReplyTo, remoteRepo, networkOptions, allInteractive, getSendmailCmd, printDryRunMessageAndExit, summary, allowUnrelatedRepos, fromOpt, dryRun, sendToContext, getOutput, changesReverse, charset, getCharset, ) import Darcs.Flags ( willRemoveLogFile, doReverse ) import Darcs.Patch.PatchInfoAnd ( PatchInfoAnd, hopefully, patchDesc ) import Darcs.Repository ( PatchSet, Repository, amInHashedRepository, identifyRepositoryFor, withRepoReadLock, RepoJob(..), readRepo, readRecorded, prefsUrl, checkUnrelatedRepos ) #ifdef GADT_WITNESSES import Darcs.Patch.Set ( Origin ) #endif import Darcs.Patch.Apply( ApplyState ) import Darcs.Patch ( RepoPatch, description, applyToTree, invert ) import Darcs.Witnesses.Unsafe ( unsafeCoerceP ) import Darcs.Witnesses.Ordered ( FL(..), (:>)(..), (:\/:)(..), (:>)(..), mapFL, mapFL_FL, lengthFL, nullFL ) import Darcs.Patch.Bundle ( makeBundleN, scanContext, patchFilename ) import Darcs.Repository.Prefs ( defaultrepo, setDefaultrepo, getPreflist ) import Darcs.External ( signString, sendEmailDoc, fetchFilePS, Cachable(..), generateEmail #ifndef HAVE_MAPI , haveSendmail #endif ) import ByteStringUtils ( mmapFilePS, isAscii ) import qualified Data.ByteString.Char8 as BC (unpack) import Darcs.Lock ( withOpenTemp, writeDocBinFile, readDocBinFile, worldReadableTemp, removeFileMayNotExist ) import Darcs.SelectChanges ( selectChanges, WhichChanges(..), selectionContext, runSelection ) import Darcs.Patch.Depends ( findCommonWithThem ) import Darcs.Utils ( askUser, promptYorn, catchall, editFile, formatPath, getSystemEncoding, isUTF8Locale ) import Data.Text.Encoding ( decodeUtf8' ) import Progress ( debugMessage ) import Darcs.Email ( makeEmail ) import Printer ( Doc, vsep, vcat, text, ($$), (<+>), (<>), putDoc, renderPS ) import Darcs.RepoPath ( FilePathLike, toFilePath, AbsolutePath, AbsolutePathOrStd, getCurrentDirectory, useAbsoluteOrStd ) import URL.HTTP ( postUrl ) #include "impossible.h" #include "gadts.h" sendDescription :: String sendDescription = "Send by email a bundle of one or more patches." sendHelp :: String sendHelp = "Send is used to prepare a bundle of patches that can be applied to a target\n"++ "repository. Send accepts the URL of the repository as an argument. When\n"++ "called without an argument, send will use the most recent repository that\n"++ "was either pushed to, pulled from or sent to. By default, the patch bundle\n"++ "is sent by email, although you may save it to a file.\n" send :: DarcsCommand send = DarcsCommand {commandProgramName = "darcs", commandName = "send", commandHelp = sendHelp, commandDescription = sendDescription, commandExtraArgs = 1, commandExtraArgHelp = ["[REPOSITORY]"], commandCommand = sendCmd, commandPrereq = amInHashedRepository, commandGetArgPossibilities = getPreflist "repos", commandArgdefaults = defaultrepo, commandAdvancedOptions = [logfile, rmlogfile, remoteRepo, sendToContext, changesReverse] ++ networkOptions, commandBasicOptions = [matchSeveral, depsSel, allInteractive, fromOpt, author, target,ccSend,subject, inReplyTo, charset, output,outputAutoName,sign] ++dryRun++[summary, editDescription, setDefault False, workingRepoDir, sendmailCmd, allowUnrelatedRepos]} sendCmd :: [DarcsFlag] -> [String] -> IO () sendCmd input_opts [""] = sendCmd input_opts [] sendCmd input_opts [unfixedrepodir] = withRepoReadLock input_opts $ RepoJob $ \(repository :: Repository p C(r u r)) -> do context_ps <- the_context input_opts case context_ps of Just them -> do wtds <- decideOnBehavior input_opts (Nothing :: Maybe (Repository p C(r u r))) sendToThem repository input_opts wtds "CONTEXT" them Nothing -> do repodir <- fixUrl input_opts unfixedrepodir -- Test to make sure we aren't trying to push to the current repo here <- getCurrentDirectory when (repodir == toFilePath here) $ fail "Can't send to current repository! Did you mean send --context?" old_default <- getPreflist "defaultrepo" when (old_default == [repodir] && Quiet `notElem` input_opts) $ putStrLn $ "Creating patch to "++formatPath repodir++"..." repo <- identifyRepositoryFor repository repodir them <- readRepo repo setDefaultrepo repodir input_opts wtds <- decideOnBehavior input_opts (Just repo) sendToThem repository input_opts wtds repodir them where the_context [] = return Nothing the_context (Context foo:_) = (Just . scanContext )`fmap` mmapFilePS (toFilePath foo) the_context (_:fs) = the_context fs sendCmd _ _ = impossible sendToThem :: (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u t) -> [DarcsFlag] -> [WhatToDo] -> String -> PatchSet p C(Origin x) -> IO () sendToThem repo opts wtds their_name them = do #ifndef HAVE_MAPI -- Check if the user has sendmail or provided a --sendmail-cmd -- (unless -o/-O or --dry-run is used) sendmail <- haveSendmail sm_cmd <- getSendmailCmd opts when (isNothing (getOutput opts "") && DryRun `notElem` opts && not sendmail && sm_cmd == "") $ do putInfo opts $ text "No working sendmail instance on your machine!" exitWith $ ExitFailure 1 #endif us <- readRepo repo common :> us' <- return $ findCommonWithThem us them checkUnrelatedRepos opts us them (case us' of NilFL -> do putInfo opts $ text "No recorded local changes to send!" exitWith ExitSuccess _ -> putVerbose opts $ text "We have the following patches to send:" $$ vcat (mapFL description us')) :: IO () pristine <- readRecorded repo let context = selectionContext "send" opts Nothing Nothing selector = if doReverse opts then selectChanges FirstReversed else selectChanges First (to_be_sent :> _) <- runSelection (selector us') context printDryRunMessageAndExit "send" opts to_be_sent when (nullFL to_be_sent) $ do putInfo opts $ text "You don't want to send any patches, and that's fine with me!" exitWith ExitSuccess setEnvDarcsPatches to_be_sent bundle <- prepareBundle opts common pristine (us':\/:to_be_sent) let make_fname (tb:>:_) = patchFilename $ patchDesc tb make_fname _ = impossible fname = make_fname to_be_sent outname = getOutput opts fname case outname of Just fname' -> writeBundleToFile opts to_be_sent bundle fname' wtds their_name Nothing -> sendBundle opts to_be_sent bundle fname wtds their_name prepareBundle :: forall p C(x y z). (RepoPatch p, ApplyState p ~ Tree) => [DarcsFlag] -> PatchSet p C(Origin z) -> Tree IO -> (FL (PatchInfoAnd p) :\/: FL (PatchInfoAnd p)) C(x y) -> IO Doc prepareBundle opts common pristine (us' :\/: to_be_sent) = do pristine' <- applyToTree (invert $ mapFL_FL hopefully us') pristine unsig_bundle <- makeBundleN (Just pristine') (unsafeCoerceP common) (mapFL_FL hopefully to_be_sent) signString opts unsig_bundle sendBundle :: forall p C(x y) . (RepoPatch p, ApplyState p ~ Tree) => [DarcsFlag] -> FL (PatchInfoAnd p) C(x y) -> Doc -> String -> [WhatToDo] -> String -> IO () sendBundle opts to_be_sent bundle fname wtds their_name= let auto_subject :: forall pp C(a b) . FL (PatchInfoAnd pp) C(a b) -> String auto_subject (p:>:NilFL) = "darcs patch: " ++ trim (patchDesc p) 57 auto_subject (p:>:ps) = "darcs patch: " ++ trim (patchDesc p) 43 ++ " (and " ++ show (lengthFL ps) ++ " more)" auto_subject _ = error "Tried to get a name from empty patch list." trim st n = if length st <= n then st else take (n-3) st ++ "..." in do thetargets <- getTargets wtds from <- getAuthor opts let thesubject = fromMaybe (auto_subject to_be_sent) $ getSubject opts (mailcontents, mailfile, mailcharset) <- getDescription opts their_name to_be_sent let warnMailBody = let msg = "Email body left in " in case mailfile of Just mf -> putStrLn $ msg++mf++"." Nothing -> return () warnCharset msg = do confirmed <- promptYorn $ "Warning: " ++ msg ++ " Send anyway?" unless confirmed $ do putStrLn "Aborted. You can specify charset with the --charset option." warnMailBody exitWith ExitSuccess thecharset <- case getCharset opts of -- Always trust provided charset providedCset@(Just _) -> return providedCset Nothing -> case mailcharset of Nothing -> do warnCharset "darcs could not guess the charset of your mail." return mailcharset Just "utf-8" -> do -- Check the locale encoding for consistency encoding <- getSystemEncoding debugMessage $ "Current locale encoding: " ++ encoding unless (isUTF8Locale encoding) $ warnCharset "your mail is valid UTF-8 but your locale differs." return mailcharset -- Trust other cases (us-ascii) Just _ -> return mailcharset let body = makeEmail their_name (maybe [] (\x -> [("In-Reply-To", x), ("References", x)]) . getInReplyTo $ opts) (Just mailcontents) thecharset bundle (Just fname) contentAndBundle = Just (mailcontents, bundle) sendmail = do sm_cmd <- getSendmailCmd opts let to = generateEmailToString thetargets sendEmailDoc from to thesubject (getCc opts) sm_cmd contentAndBundle body >> (putInfo opts . text $ ("Successfully sent patch bundle to: " ++ to ++ ccs (getCc opts) ++".")) `catch` \e -> do warnMailBody fail $ ioeGetErrorString e ccs [] = [] ccs cs = " and cc'ed " ++ cs when (null [ p | Post p <- thetargets]) sendmail nbody <- withOpenTemp $ \ (fh,fn) -> do let to = generateEmailToString thetargets generateEmail fh from to thesubject (getCc opts) body hClose fh mmapFilePS fn forM_ [ p | Post p <- thetargets] (\url -> do putInfo opts . text $ "Posting patch to " ++ url postUrl url (BC.unpack nbody) "message/rfc822") `catch` (\(_ :: IOException) -> sendmail) cleanup opts mailfile generateEmailToString :: [WhatToDo] -> String generateEmailToString = intercalate " , " . filter (/= "") . map extractEmail where extractEmail (SendMail t) = t extractEmail _ = "" cleanup :: (FilePathLike t) => [DarcsFlag] -> Maybe t -> IO () cleanup opts (Just mailfile) = when (isNothing (getFileopt opts) || willRemoveLogFile opts) $ removeFileMayNotExist mailfile cleanup _ Nothing = return () writeBundleToFile :: forall p C(x y) . (RepoPatch p, ApplyState p ~ Tree) => [DarcsFlag] -> FL (PatchInfoAnd p) C(x y) -> Doc -> AbsolutePathOrStd -> [WhatToDo] -> String -> IO () writeBundleToFile opts to_be_sent bundle fname wtds their_name = do (d,f,_) <- getDescription opts their_name to_be_sent let putabs a = do writeDocBinFile a (d $$ bundle) putStrLn $ "Wrote patch to " ++ toFilePath a ++ "." putstd = putDoc (d $$ bundle) useAbsoluteOrStd putabs putstd fname let to = generateEmailToString wtds unless (null to) $ putInfo opts . text $ "The usual recipent for this bundle is: " ++ to cleanup opts f data WhatToDo = Post String -- ^ POST the patch via HTTP | SendMail String -- ^ send patch via email decideOnBehavior :: RepoPatch p => [DarcsFlag] -> Maybe (Repository p C(r u t)) -> IO [WhatToDo] decideOnBehavior opts remote_repo = case the_targets of [] -> do wtds <- case remote_repo of Nothing -> return [] Just r -> check_post r unless (null wtds) $ announce_recipients wtds return wtds ts -> do announce_recipients ts return ts where the_targets = collectTargets opts #ifdef HAVE_HTTP -- the ifdef above is to so that darcs only checks the remote -- _darcs/post if we have an implementation of postUrl. See -- our HTTP module for more details check_post the_remote_repo = do p <- ((readPost . BC.unpack) `fmap` fetchFilePS (prefsUrl the_remote_repo++"/post") (MaxAge 600)) `catchall` return [] emails <- who_to_email the_remote_repo return (p++emails) readPost = map parseLine . lines where parseLine t = maybe (Post t) SendMail $ stripPrefix "mailto:" t #else check_post = who_to_email #endif who_to_email the_remote_repo = do email <- (BC.unpack `fmap` fetchFilePS (prefsUrl the_remote_repo++"/email") (MaxAge 600)) `catchall` return "" if '@' `elem` email then return . map SendMail $ lines email else return [] announce_recipients emails = let pn (SendMail s) = s pn (Post p) = p in if DryRun `elem` opts then putInfo opts . text $ "Patch bundle would be sent to: "++unwords (map pn emails) else when (null the_targets && isNothing (getOutput opts "")) $ putInfo opts . text $ "Patch bundle will be sent to: "++unwords (map pn emails) getTargets :: [WhatToDo] -> IO [WhatToDo] getTargets [] = fmap ((:[]) . SendMail) $ askUser "What is the target email address? " getTargets wtds = return wtds collectTargets :: [DarcsFlag] -> [WhatToDo] collectTargets flags = [ f t | Target t <- flags ] where f url | "http:" `isPrefixOf` url = Post url f em = SendMail em getDescription :: (RepoPatch p, ApplyState p ~ Tree) => [DarcsFlag] -> String -> FL (PatchInfoAnd p) C(x y) -> IO (Doc, Maybe String, Maybe String) getDescription opts their_name patches = case get_filename of Just f -> do file <- f when (EditDescription `elem` opts) $ do when (isNothing $ getFileopt opts) $ writeDocBinFile file patchdesc debugMessage $ "About to edit file " ++ file (_, changed) <- editFile file unless changed $ do confirmed <- promptYorn "File content did not change. Continue anyway?" unless confirmed $ do putStrLn "Aborted." exitWith ExitSuccess return () doc <- readDocBinFile file return (doc, Just file, tryGetCharset doc) Nothing -> return (patchdesc, Nothing, tryGetCharset patchdesc) where patchdesc = text (if lengthFL patches == 1 then "1 patch" else show (lengthFL patches) ++ " patches") <+> text "for repository" <+> text their_name <> text ":" $$ text "" $$ vsep (mapFL description patches) get_filename = case getFileopt opts of Just f -> Just $ return $ toFilePath f Nothing -> if EditDescription `elem` opts then Just tempfile else Nothing tempfile = worldReadableTemp "darcs-temp-mail" tryGetCharset content = let body = renderPS content in if isAscii body then Just "us-ascii" else either (const Nothing) (const $ Just "utf-8") (decodeUtf8' body) getFileopt :: [DarcsFlag] -> Maybe AbsolutePath getFileopt (LogFile f:_) = Just f getFileopt (_:flags) = getFileopt flags getFileopt [] = Nothing darcs-2.8.4/src/Darcs/Commands/SetPref.hs0000644001765600176560000001112212104371431017426 0ustar ganeshganesh-- Copyright (C) 2003 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP #-} module Darcs.Commands.SetPref ( setpref ) where import System.Exit ( exitWith, ExitCode(..) ) import Control.Monad (when) import Data.Maybe (fromMaybe) import Darcs.Commands ( DarcsCommand(..), nodefaults ) import Darcs.Arguments ( DarcsFlag, workingRepoDir, umaskOption ) import Darcs.Repository ( amInHashedRepository, addToPending, withRepoLock, RepoJob(..) ) import Darcs.Patch ( changepref ) import Darcs.Witnesses.Ordered ( FL(..) ) import Darcs.Repository.Prefs ( getPrefval, changePrefval, ) import English ( orClauses ) #include "impossible.h" -- | A list of all valid preferences for @_darcs/prefs/prefs@. validPrefData :: [(String, String)] -- ^ (name, one line description) validPrefData = [("test", "a shell command that runs regression tests"), ("predist", "a shell command to run before `darcs dist'"), ("boringfile", "the path to a version-controlled boring file"), ("binariesfile", "the path to a version-controlled binaries file")] validPrefs :: [String] validPrefs = map fst validPrefData setprefDescription :: String setprefDescription = "Set a preference (" ++ orClauses validPrefs ++ ")." setprefHelp :: String setprefHelp = "When working on project with multiple repositories and contributors,\n" ++ "it is sometimes desirable for a preference to be set consistently\n" ++ "project-wide. This is achieved by treating a preference set with\n" ++ "`darcs setpref' as an unrecorded change, which can then be recorded\n" ++ "and then treated like any other patch.\n" ++ "\n" ++ "Valid preferences are:\n" ++ "\n" ++ unlines [" "++x++" -- "++y | (x,y) <- validPrefData] ++ "\n" ++ "For example, a project using GNU autotools, with a `make test' target\n" ++ "to perform regression tests, might enable Darcs' integrated regression\n" ++ "testing with the following command:\n" ++ "\n" ++ " darcs setpref test 'autoconf && ./configure && make && make test'\n" ++ "\n" ++ "Note that merging is not currently implemented for preferences: if two\n" ++ "patches attempt to set the same preference, the last patch applied to\n" ++ "the repository will always take precedence. This is considered a\n" ++ "low-priority bug, because preferences are seldom set.\n" setpref :: DarcsCommand setpref = DarcsCommand {commandProgramName = "darcs", commandName = "setpref", commandHelp = setprefHelp, commandDescription = setprefDescription, commandExtraArgs = 2, commandExtraArgHelp = ["", ""], commandCommand = setprefCmd, commandPrereq = amInHashedRepository, commandGetArgPossibilities = return validPrefs, commandArgdefaults = nodefaults, commandAdvancedOptions = [umaskOption], commandBasicOptions = [workingRepoDir]} setprefCmd :: [DarcsFlag] -> [String] -> IO () setprefCmd opts [pref,val] = withRepoLock opts $ RepoJob $ \repository -> do when (' ' `elem` pref) $ do putStrLn $ "'"++pref++ "' is not a valid preference name: no spaces allowed!" exitWith $ ExitFailure 1 when (pref `notElem` validPrefs) $ do putStrLn $ "'"++pref++"' is not a valid preference name!" putStrLn $ "Try one of: " ++ unwords validPrefs exitWith $ ExitFailure 1 oval <- getPrefval pref let old = fromMaybe "" oval when ('\n' `elem` val) $ do putStrLn $ val ++ "is not a valid preference value: newlines forbidden!" exitWith $ ExitFailure 1 changePrefval pref old val putStrLn $ "Changing value of "++pref++" from '"++old++"' to '"++val++"'" addToPending repository (changepref pref old val :>: NilFL) setprefCmd _ _ = impossible darcs-2.8.4/src/Darcs/Commands/Show.hs0000644001765600176560000000702012104371431017000 0ustar ganeshganesh-- Copyright (C) 2002-2004 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. module Darcs.Commands.Show ( showCommand, list, query ) where import Darcs.Commands ( DarcsCommand(..), CommandControl(CommandData, HiddenCommand), commandAlias, ) import Darcs.Commands.ShowAuthors ( showAuthors ) import Darcs.Commands.ShowBug ( showBug ) import Darcs.Commands.ShowContents ( showContents ) import Darcs.Commands.ShowFiles ( showFiles, manifestCmd, toListManifest ) import Darcs.Commands.ShowTags ( showTags ) import Darcs.Commands.ShowRepo ( showRepo ) import Darcs.Commands.ShowIndex ( showIndex, showPristineCmd ) import Darcs.Repository ( amInRepository ) showDescription :: String showDescription = "Show information which is stored by darcs." showHelp :: String showHelp = "Use the --help option with the subcommands to obtain help for\n"++ "subcommands (for example, \"darcs show files --help\").\n" ++ "\n" ++ "In previous releases, this command was called `darcs query'.\n" ++ "Currently this is a deprecated alias.\n" showCommand :: DarcsCommand showCommand = SuperCommand {commandProgramName = "darcs", commandName = "show", commandHelp = showHelp, commandDescription = showDescription, commandPrereq = amInRepository, commandSubCommands = [HiddenCommand showBug, CommandData showContents, CommandData showFiles, HiddenCommand showManifest, CommandData showIndex, CommandData showPristine, CommandData showRepo, CommandData showAuthors, CommandData showTags] } query :: DarcsCommand query = commandAlias "query" Nothing showCommand list :: DarcsCommand list = commandAlias "list" Nothing showCommand -- unfortunately, aliases for sub-commands have to live in their parent command -- to avoid an import cycle showPristine :: DarcsCommand showPristine = (commandAlias "pristine" (Just showCommand) showIndex) { commandCommand = showPristineCmd, commandDescription = "Dump contents of pristine cache.", commandHelp = "The `darcs show pristine' command lists all version-controlled files " ++ "and directories along with the hashes of their pristine copies. " ++ "For files, the fields correspond to file size, sha256 of the pristine " ++ "file content and the filename." } showManifest :: DarcsCommand showManifest = (commandAlias "manifest" (Just showCommand) showFiles) { commandCommand = manifestCmd toListManifest } darcs-2.8.4/src/Darcs/Commands/ShowAuthors.hs0000644001765600176560000001733712104371431020362 0ustar ganeshganesh-- Copyright (C) 2004-2009 David Roundy, Eric Kow, Simon Michael, Tomas Caithaml -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. module Darcs.Commands.ShowAuthors ( showAuthors ) where import Prelude hiding ( catch ) import qualified Ratified( readFile ) import Control.Arrow ((&&&), (***)) import Control.Exception ( catch, IOException ) import Data.List ( isInfixOf, sortBy, groupBy, group, sort) import Data.Ord (comparing) import Data.Char ( toLower, isSpace ) import Data.Maybe( isJust ) import Text.ParserCombinators.Parsec hiding (lower, count, Line) import Text.ParserCombinators.Parsec.Error import Text.Regex ( Regex, mkRegexWithOpts, matchRegex ) import Darcs.Arguments ( DarcsFlag(..), workingRepoDir ) import Darcs.Commands ( DarcsCommand(..), nodefaults, putWarning ) import Darcs.External ( viewDoc ) import Darcs.Patch.PatchInfoAnd ( info ) import Darcs.Repository ( amInRepository, readRepo, withRepository, RepoJob(..) ) import Darcs.Patch.Info ( piAuthor ) import Darcs.Patch.Set ( newset2RL ) import Darcs.Witnesses.Ordered ( mapRL ) import Printer ( text ) import Data.Function (on) data Spelling = Spelling String String [Regex] -- name, email, regexps type ParsedLine = Maybe Spelling -- Nothing for blank lines showAuthorsDescription :: String showAuthorsDescription = "List authors by patch count." showAuthorsHelp :: String showAuthorsHelp = "The `darcs show authors' command lists the authors of the current\n" ++ "repository, sorted by the number of patches contributed. With the\n" ++ "--verbose option, this command simply lists the author of each patch\n" ++ "(without aggregation or sorting).\n" ++ "\n" ++ "An author's name or email address may change over time. To tell Darcs\n" ++ "when multiple author strings refer to the same individual, create an\n" ++ "`.authorspellings' file in the root of the working tree. Each line in\n" ++ "this file begins with an author's canonical name and address, and may\n" ++ "be followed by a comma separated list of extended regular expressions.\n" ++ "Blank lines and lines beginning with two hyphens are ignored.\n" ++ "The format of .authorspelling can be described by this pattern:\n" ++ "\n" ++ " name
[, regexp ]*\n" ++ "\n" ++ "There are some pitfalls concerning special characters:\n" ++ "Whitespaces are stripped, if you need space in regexp use [ ]. \n" ++ "Because comma serves as a separator you have to escape it if you want\n" ++ "it in regexp. Note that .authorspelingfile use extended regular\n" ++ "expressions so +, ? and so on are metacharacters and you need to \n" ++ "escape them to be interpreted literally.\n" ++ "\n" ++ "Any patch with an author string that matches the canonical address or\n" ++ "any of the associated regexps is considered to be the work of that\n" ++ "author. All matching is case-insensitive and partial (it can match a\n" ++ "substring). Use ^,$ to match the whole string in regexps\n" ++ "\n" ++ "Currently this canonicalization step is done only in `darcs show\n" ++ "authors'. Other commands, such as `darcs changes' use author strings\n" ++ "verbatim.\n" ++ "\n" ++ "An example .authorspelling file is:\n" ++ "\n" ++ " -- This is a comment.\n" ++ " Fred Nurk \n" ++ " John Snagge , John, snagge@, js@(si|mit).edu\n" ++ " Chuck Jones\\, Jr. , cj\\+user@example.com\n" showAuthors :: DarcsCommand showAuthors = DarcsCommand { commandProgramName = "darcs", commandName = "authors", commandHelp = showAuthorsHelp, commandDescription = showAuthorsDescription, commandExtraArgs = 0, commandExtraArgHelp = [], commandCommand = authorsCmd, commandPrereq = amInRepository, commandGetArgPossibilities = return [], commandArgdefaults = nodefaults, commandAdvancedOptions = [], commandBasicOptions = [workingRepoDir] } authorsCmd :: [DarcsFlag] -> [String] -> IO () authorsCmd opts _ = withRepository opts $ RepoJob $ \repository -> do patches <- readRepo repository spellings <- compiledAuthorSpellings opts let authors = mapRL (piAuthor . info) $ newset2RL patches viewDoc $ text $ unlines $ if Verbose `elem` opts then authors else -- A list of the form [" "]... -- Turn the final result into a list of strings. map (\ (count, name) -> show count ++ "\t" ++ name) $ -- Sort by descending patch count. reverse $ sortBy (comparing fst) $ -- Combine duplicates from a list [(count, canonized name)] -- with duplicates canonized names (see next comment). map ((sum *** head) . unzip) $ groupBy ((==) `on` snd) $ sortBy (comparing snd) $ -- Because it would take a long time to canonize "foo" into -- "foo " once per patch, the code below -- generates a list [(count, canonized name)]. map (length &&& (canonizeAuthor spellings . head)) $ group $ sort authors canonizeAuthor :: [Spelling] -> String -> String canonizeAuthor spells author = getName canonicals where getName [] = author getName ((Spelling name email _):_) = name ++ " <" ++ email ++ ">" canonicals = filter (ismatch author) spells ismatch s (Spelling _ mail regexps) = s `correspondsTo` mail || any (s `contains_regex`) regexps contains_regex a r = isJust $ matchRegex r a correspondsTo a b = lower b `isInfixOf` lower a lower = map toLower compiledAuthorSpellings :: [DarcsFlag] -> IO [Spelling] compiledAuthorSpellings opts = do let as_file = ".authorspellings" contents <- (Ratified.readFile -- never unlinked from within darcs as_file `catch` (\(_ :: IOException) -> return "")) let parse_results = map (parse sentence as_file) $ lines contents clean 1 parse_results where clean :: Int -> [Either ParseError ParsedLine] -> IO [Spelling] clean _ [] = return [] -- print parse error clean n ((Left err):xs) = do let npos = setSourceLine (errorPos err) n putWarning opts . text . show $ setErrorPos npos err clean (n+1) xs -- skip blank line clean n ((Right Nothing):xs) = clean (n+1) xs -- unwrap Spelling clean n ((Right (Just a):xs)) = do as <- clean (n+1) xs return (a:as) ---------- -- PARSERS sentence :: Parser ParsedLine sentence = spaces >> (comment <|> blank <|> addressline) where comment = string "--" >> return Nothing blank = eof >> return Nothing addressline :: Parser ParsedLine addressline = do name <- canonicalName "Canonical name" addr <- between (char '<') (char '>') (many1 (noneOf ">")) "Address" spaces rest <- option [] (char ',' >> regexp `sepBy` char ',') "List of regexps" return $ Just $ Spelling (strip name) addr (compile rest) where strip = dropWhile isSpace . reverse . dropWhile isSpace . reverse makeRegex s = mkRegexWithOpts s True False compile = map makeRegex . filter (not . null) . map strip regexp :: Parser String regexp = many1 p "Regular expression" where p = try (string "\\," >> return ',') <|> noneOf "," canonicalName :: Parser String canonicalName = many1 p where p = try (string "\\," >> return ',') <|> noneOf ",<" darcs-2.8.4/src/Darcs/Commands/ShowBug.hs0000644001765600176560000000400212104371431017433 0ustar ganeshganesh-- Copyright (C) 2007 Eric Kow -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP #-} module Darcs.Commands.ShowBug ( showBug ) where import Darcs.Commands ( DarcsCommand(..), nodefaults ) import Darcs.Arguments ( DarcsFlag, workingRepoDir ) import Darcs.Repository ( findRepository ) #include "impossible.h" showBugDescription :: String showBugDescription = "Simulate a run-time failure." showBugHelp :: String showBugHelp = "Show bug can be used to see what darcs would show you if you encountered.\n" ++"a bug in darcs.\n" showBug :: DarcsCommand showBug = DarcsCommand {commandProgramName = "darcs", commandName = "bug", commandHelp = showBugHelp, commandDescription = showBugDescription, commandExtraArgs = 0, commandExtraArgHelp = [], commandCommand = showBugCmd, commandPrereq = findRepository, commandGetArgPossibilities = return [], commandArgdefaults = nodefaults, commandAdvancedOptions = [], commandBasicOptions = [workingRepoDir]} showBugCmd :: [DarcsFlag] -> [String] -> IO () showBugCmd _ _ = bug "This is actually a fake bug in darcs." darcs-2.8.4/src/Darcs/Commands/ShowContents.hs0000644001765600176560000001036012104371431020517 0ustar ganeshganesh-- Copyright (C) 2007 Eric Kow -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. module Darcs.Commands.ShowContents ( showContents ) where import Control.Monad ( filterM, forM_, forM, unless ) import System.IO ( stdout ) import qualified Data.ByteString as B import qualified Data.ByteString.Lazy as BL import Darcs.Commands ( DarcsCommand(..), nodefaults ) import Darcs.Arguments ( DarcsFlag, matchOne, workingRepoDir, fixSubPaths ) import Darcs.RepoPath ( sp2fn, toFilePath ) import Darcs.Patch.FileName( FileName, fp2fn ) import Darcs.Patch.ApplyMonad ( withFiles ) import Darcs.Match ( haveNonrangeMatch, applyInvToMatcher, nonrangeMatcher , InclusiveOrExclusive(..), matchExists, applyNInv , hasIndexRange ) import Darcs.Repository ( withRepository, RepoJob(..), findRepository, readRepo, readRecorded ) import qualified Storage.Hashed.Monad as HSM import Storage.Hashed.AnchoredPath( floatPath, anchorPath ) showContentsDescription :: String showContentsDescription = "Outputs a specific version of a file." showContentsHelp :: String showContentsHelp = "Show contents can be used to display an earlier version of some file(s).\n"++ "If you give show contents no version arguments, it displays the recorded\n"++ "version of the file(s).\n" showContents :: DarcsCommand showContents = DarcsCommand {commandProgramName = "darcs", commandName = "contents", commandHelp = showContentsHelp, commandDescription = showContentsDescription, commandExtraArgs = -1, commandExtraArgHelp = ["[FILE]..."], commandCommand = showContentsCmd, commandPrereq = findRepository, commandGetArgPossibilities = return [], commandArgdefaults = nodefaults, commandAdvancedOptions = [], commandBasicOptions = [matchOne, workingRepoDir]} showContentsCmd :: [DarcsFlag] -> [String] -> IO () showContentsCmd _ [] = fail "show contents needs at least one argument." showContentsCmd opts args = withRepository opts $ RepoJob $ \repository -> do path_list <- map sp2fn `fmap` fixSubPaths opts args pristine <- readRecorded repository unapply <- if haveNonrangeMatch opts then do patchset <- readRepo repository case nonrangeMatcher opts of -- Index cannot be a Matcher, so handle it manually. Nothing -> case hasIndexRange opts of Just (n, m) | n == m -> return $ applyNInv (n-1) patchset _ -> fail "Couldn't obtain a valid matcher." Just m -> do unless (matchExists m patchset) $ fail $ "Couldn't match pattern " ++ show m return $ applyInvToMatcher Exclusive m patchset else return (return ()) let dump :: HSM.TreeIO [(FileName, B.ByteString)] dump = do let floatedPaths = map (floatPath . toFilePath) path_list okpaths <- filterM HSM.fileExists floatedPaths forM okpaths $ \f -> do content <- (B.concat . BL.toChunks) `fmap` HSM.readFile f return (fp2fn $ ("./" ++) $ anchorPath "" f, content) files <- flip withFiles unapply `fmap` fst `fmap` HSM.virtualTreeIO dump pristine forM_ files $ \(_, f) -> B.hPut stdout f darcs-2.8.4/src/Darcs/Commands/ShowFiles.hs0000644001765600176560000001425512104371431017773 0ustar ganeshganesh-- Copyright (C) 2005 Florian Weimer -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP #-} #include "gadts.h" module Darcs.Commands.ShowFiles ( showFiles , manifestCmd, toListManifest -- for alias , manifest ) where import Darcs.Arguments ( DarcsFlag(..), workingRepoDir, files, directories, pending, nullFlag, matchOne ) import Darcs.Commands ( DarcsCommand(..), nodefaults ) import Darcs.Repository ( Repository, amInRepository, withRepository, RepoJob(..) ) import Darcs.Patch ( RepoPatch ) import Darcs.Patch.Apply( ApplyState ) import Darcs.Repository.State ( readRecorded, readRecordedAndPending ) import Storage.Hashed.Tree( Tree, TreeItem(..), list, expand ) import Storage.Hashed.AnchoredPath( anchorPath ) import Storage.Hashed.Plain( readPlainTree ) import System.FilePath ( splitDirectories ) import Data.List( isPrefixOf ) import Darcs.Match ( haveNonrangeMatch, getNonrangeMatch ) import Darcs.Lock ( withDelayedDir ) showFilesDescription :: String showFilesDescription = "Show version-controlled files in the working copy." showFilesHelp :: String showFilesHelp = "The `darcs show files' command lists those files and directories in\n" ++ "the working tree that are under version control. This command is\n" ++ "primarily for scripting purposes; end users will probably want `darcs\n" ++ "whatsnew --summary'.\n" ++ "\n" ++ "A file is `pending' if it has been added but not recorded. By\n" ++ "default, pending files (and directories) are listed; the --no-pending\n" ++ "option prevents this.\n" ++ "\n" ++ "By default `darcs show files' lists both files and directories, but\n" ++ "the alias `darcs show manifest' only lists files. The --files,\n" ++ "--directories, --no-files and --no-directories modify this behaviour.\n" ++ "\n" ++ "By default entries are one-per-line (i.e. newline separated). This\n" ++ "can cause problems if the files themselves contain newlines or other\n" ++ "control characters. To get aroudn this, the --null option uses the\n" ++ "null character instead. The script interpreting output from this\n" ++ "command needs to understand this idiom; `xargs -0' is such a command.\n" ++ "\n" ++ "For example, to list version-controlled files by size:\n" ++ "\n" ++ " darcs show files -0 | xargs -0 ls -ldS\n" showFiles :: DarcsCommand showFiles = DarcsCommand { commandProgramName = "darcs", commandName = "files", commandHelp = showFilesHelp, commandDescription = showFilesDescription, commandExtraArgs = -1, commandExtraArgHelp = ["[FILE or DIRECTORY]..."], commandCommand = manifestCmd toListFiles, commandPrereq = amInRepository, commandGetArgPossibilities = return [], commandArgdefaults = nodefaults, commandAdvancedOptions = [], commandBasicOptions = [files, directories, pending, nullFlag, matchOne, workingRepoDir] } toListFiles, toListManifest :: [DarcsFlag] -> Tree m -> [FilePath] toListFiles opts = filesDirs (NoFiles `notElem` opts) (NoDirectories `notElem` opts) toListManifest opts = filesDirs (NoFiles `notElem` opts) (Directories `elem` opts) filesDirs :: Bool -> Bool -> Tree m -> [FilePath] filesDirs False False _ = [] filesDirs False True t = "." : [ anchorPath "." p | (p, SubTree _) <- list t ] filesDirs True False t = [ anchorPath "." p | (p, File _) <- list t ] filesDirs True True t = "." : (map (anchorPath "." . fst) $ list t) manifest :: [DarcsFlag] -> [String] -> IO [FilePath] manifest = manifestHelper toListFiles manifestCmd :: ([DarcsFlag] -> Tree IO -> [FilePath]) -> [DarcsFlag] -> [String] -> IO () manifestCmd to_list opts argList = do mapM_ output =<< manifestHelper to_list opts argList where output_null name = do { putStr name ; putChar '\0' } output = if NullFlag `elem` opts then output_null else putStrLn manifestHelper :: ([DarcsFlag] -> Tree IO -> [FilePath]) -> [DarcsFlag] -> [String] -> IO [FilePath] manifestHelper to_list opts argList = do list' <- (to_list opts) `fmap` withRepository opts (RepoJob myslurp) case argList of [] -> return list' prefixes -> return (onlysubdirs prefixes list') where myslurp :: (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u r) -> IO (Tree IO) myslurp r = do let fRevisioned = haveNonrangeMatch opts fPending = Pending `elem` opts fNoPending = NoPending `elem` opts -- this covers all 8 options expand =<< case (fRevisioned,fPending,fNoPending) of (True,False,_) -> slurpRevision opts r (True,True,_) -> error $ "can't mix revisioned and pending flags" (False,False,True) -> readRecorded r (False,_,False) -> readRecordedAndPending r -- pending is default (False,True,True) -> error $ "can't mix pending and no-pending flags" isParentDir a' b' = let a = splitDirectories a' b = splitDirectories b' in (a `isPrefixOf` b) || (("." : a) `isPrefixOf` b) onlysubdirs dirs = filter (\p -> any (`isParentDir` p) dirs) slurpRevision :: (RepoPatch p, ApplyState p ~ Tree) => [DarcsFlag] -> Repository p C(r u r) -> IO (Tree IO) slurpRevision opts r = withDelayedDir "revisioned.showfiles" $ \_ -> do getNonrangeMatch r opts expand =<< readPlainTree "." darcs-2.8.4/src/Darcs/Commands/ShowIndex.hs0000644001765600176560000000677512104371431020010 0ustar ganeshganesh-- Copyright (C) 2009 Petr Rockai -- -- 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. {-# LANGUAGE CPP #-} #include "gadts.h" module Darcs.Commands.ShowIndex ( showIndex , showPristineCmd -- for alias ) where import Darcs.Arguments ( DarcsFlag(..), workingRepoDir, files, directories, nullFlag ) import Darcs.Commands ( DarcsCommand(..), nodefaults ) import Darcs.Repository ( amInRepository, withRepository, RepoJob(..), readIndex ) import Darcs.Repository.State ( readRecorded ) import Storage.Hashed( floatPath ) import Storage.Hashed.Hash( encodeBase16, Hash( NoHash ) ) import Storage.Hashed.Tree( list, expand, itemHash, Tree, TreeItem( SubTree ) ) import Storage.Hashed.Index( updateIndex ) import Storage.Hashed.AnchoredPath( anchorPath ) import qualified Data.ByteString.Char8 as BS showIndex :: DarcsCommand showIndex = DarcsCommand { commandProgramName = "darcs", commandName = "index", commandDescription = "Dump contents of working tree index.", commandHelp = "The `darcs show index' command lists all version-controlled files and " ++ "directories along with their hashes as stored in _darcs/index. " ++ "For files, the fields correspond to file size, sha256 of the current " ++ "file content and the filename.", commandExtraArgs = 0, commandExtraArgHelp = [], commandCommand = showIndexCmd, commandPrereq = amInRepository, commandGetArgPossibilities = return [], commandArgdefaults = nodefaults, commandAdvancedOptions = [], commandBasicOptions = [files, directories, nullFlag, workingRepoDir] } dump :: [DarcsFlag] -> Tree IO -> IO () dump opts tree = do let line | NullFlag `elem` opts = \t -> putStr t >> putChar '\0' | otherwise = putStrLn output (p, i) = do let hash = case itemHash i of NoHash -> "(no hash available)" h -> BS.unpack $ encodeBase16 h path = anchorPath "" p isdir = case i of SubTree _ -> "/" _ -> "" line $ hash ++ " " ++ path ++ isdir x <- expand tree mapM_ output $ (floatPath ".", SubTree x) : list x showIndexCmd :: [DarcsFlag] -> [String] -> IO () showIndexCmd opts _ = withRepository opts $ RepoJob $ \repo -> do readIndex repo >>= updateIndex >>= dump opts showPristineCmd :: [DarcsFlag] -> [String] -> IO () showPristineCmd opts _ = withRepository opts $ RepoJob $ \repo -> do readRecorded repo >>= dump opts darcs-2.8.4/src/Darcs/Commands/ShowRepo.hs0000644001765600176560000001452112104371431017632 0ustar ganeshganesh-- Copyright (C) 2007 Kevin Quick -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP #-} #include "gadts.h" module Darcs.Commands.ShowRepo ( showRepo ) where import Data.Char ( toLower, isSpace ) import Data.List ( intercalate ) import Control.Monad ( when, unless ) import Text.Html ( tag, stringToHtml ) import Darcs.Arguments ( DarcsFlag(..), workingRepoDir, files, xmloutput ) import Darcs.Commands ( DarcsCommand(..), nodefaults ) import Darcs.Repository ( withRepository, RepoJob(..), amInRepository, readRepo ) import Darcs.Repository.Internal ( Repository(..), RepoType(..) ) import Darcs.Repository.Format ( RepoFormat(..) ) import Darcs.Repository.Prefs ( getPreflist ) import Darcs.Repository.Motd ( getMotd ) import Darcs.Patch ( RepoPatch ) import Darcs.Patch.Set ( newset2RL ) import Darcs.Witnesses.Ordered ( lengthRL ) import qualified Data.ByteString.Char8 as BC (unpack) import Darcs.Patch.Apply( ApplyState ) import Storage.Hashed.Tree ( Tree ) showRepoHelp :: String showRepoHelp = "The `darcs show repo' command displays statistics about the current\n" ++ "repository, allowing third-party scripts to access this information\n" ++ "without inspecting _darcs directly (and without breaking when the\n" ++ "_darcs format changes).\n" ++ "\n" ++ "By default, the number of patches is shown. If this data isn't\n" ++ "needed, use --no-files to accelerate this command from O(n) to O(1).\n" ++ "\n" ++ "By default, output is in a human-readable format. The --xml-output\n" ++ "option can be used to generate output for machine postprocessing.\n" showRepoDescription :: String showRepoDescription = "Show repository summary information" showRepo :: DarcsCommand showRepo = DarcsCommand { commandProgramName = "darcs", commandName = "repo", commandHelp = showRepoHelp, commandDescription = showRepoDescription, commandExtraArgs = 0, commandExtraArgHelp = [], commandCommand = repoCmd, commandPrereq = amInRepository, commandGetArgPossibilities = return [], commandArgdefaults = nodefaults, commandAdvancedOptions = [], commandBasicOptions = [workingRepoDir, files, xmloutput] } repoCmd :: [DarcsFlag] -> [String] -> IO () repoCmd opts _ = let put_mode = if XMLOutput `elem` opts then showInfoXML else showInfoUsr in withRepository opts $ RepoJob $ \repository -> actuallyShowRepo (putInfo put_mode) repository -- Some convenience functions to output a labelled text string or an -- XML tag + value (same API). If no value, output is suppressed -- entirely. Borrow some help from Text.Html to perform XML output. type ShowInfo = String -> String -> String showInfoXML :: ShowInfo showInfoXML t i = show $ tag (safeTag t) $ stringToHtml i safeTag :: String -> String safeTag [] = [] safeTag (' ':cs) = safeTag cs safeTag ('#':cs) = "num_" ++ (safeTag cs) safeTag (c:cs) = toLower c : safeTag cs -- labelled strings: labels are right-aligned at 14 characters; -- subsequent lines in multi-line output are indented accordingly. showInfoUsr :: ShowInfo showInfoUsr t i = (replicate (14 - length(t)) ' ') ++ t ++ ": " ++ intercalate ('\n' : (replicate 16 ' ')) (lines i) ++ "\n" type PutInfo = String -> String -> IO () putInfo :: ShowInfo -> PutInfo putInfo m t i = unless (null i) (putStr $ m t i) -- Primary show-repo operation. Determines ordering of output for -- sub-displays. The `out' argument is one of the above operations to -- output a labelled text string or an XML tag and contained value. actuallyShowRepo :: (RepoPatch p, ApplyState p ~ Tree) => PutInfo -> Repository p C(r u r) -> IO () actuallyShowRepo out r@(Repo loc opts rf rt) = do when (XMLOutput `elem` opts) (putStr "\n") showRepoType out rt when (Verbose `elem` opts) (out "Show" $ show r) showRepoFormat out rf out "Root" loc showRepoAux out rt showRepoPrefs out unless (NoFiles `elem` opts) (numPatches r >>= (out "Num Patches" . show )) showRepoMOTD out r when (XMLOutput `elem` opts) (putStr "\n") -- Most of the actual elements being displayed are part of the Show -- class; that's fine for a Haskeller, but not for the common user, so -- the routines below work to provide more human-readable information -- regarding the repository elements. showRepoType :: PutInfo -> RepoType p -> IO () showRepoType out (DarcsRepository _ _) = out "Type" "darcs" showRepoFormat :: PutInfo -> RepoFormat -> IO () showRepoFormat out (RF rf) = out "Format" $ intercalate ", " (map (intercalate "|" . map BC.unpack) rf) showRepoAux :: PutInfo -> RepoType p -> IO () showRepoAux out (DarcsRepository pris cs) = do out "Pristine" $ show pris out "Cache" $ intercalate ", " $ lines $ show cs showRepoPrefs :: PutInfo -> IO () showRepoPrefs out = do getPreflist "prefs" >>= mapM_ prefOut getPreflist "author" >>= out "Author" . unlines getPreflist "defaultrepo" >>= out "Default Remote" . unlines where prefOut = uncurry out . (\(p,v) -> (p++" Pref", (dropWhile isSpace v))) . break isSpace showRepoMOTD :: RepoPatch p => PutInfo -> Repository p C(r u r) -> IO () showRepoMOTD out (Repo loc _ _ _) = getMotd loc >>= out "MOTD" . BC.unpack -- Support routines to provide information used by the PutInfo operations above. numPatches :: (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u r) -> IO Int numPatches r = readRepo r >>= (return . lengthRL . newset2RL) darcs-2.8.4/src/Darcs/Commands/ShowTags.hs0000644001765600176560000000612312104371431017622 0ustar ganeshganesh-- Copyright (C) 2007 Florian Weimer -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. module Darcs.Commands.ShowTags ( showTags ) where import Darcs.Arguments ( DarcsFlag(..), possiblyRemoteRepoDir, getRepourl ) import Darcs.Commands ( DarcsCommand(..), nodefaults ) import Darcs.Patch.PatchInfoAnd ( info ) import Darcs.Repository ( findRepository, readRepo, withRepositoryDirectory, RepoJob(..) ) import Darcs.Patch.Info ( piTag ) import Darcs.Patch.Set ( newset2RL ) import Darcs.Witnesses.Ordered ( mapRL ) import Data.Maybe ( fromMaybe ) import System.IO ( stderr, hPutStrLn ) -- import Printer ( renderPS ) showTagsDescription :: String showTagsDescription = "Show all tags in the repository." showTagsHelp :: String showTagsHelp = "The tags command writes a list of all tags in the repository to standard\n"++ "output.\n" ++ "\n" ++ "Tab characters (ASCII character 9) in tag names are changed to spaces\n" ++ "for better interoperability with shell tools. A warning is printed if\n" ++ "this happens." showTags :: DarcsCommand showTags = DarcsCommand { commandProgramName = "darcs", commandName = "tags", commandHelp = showTagsHelp, commandDescription = showTagsDescription, commandExtraArgs = 0, commandExtraArgHelp = [], commandCommand = tagsCmd, commandPrereq = findRepository, commandGetArgPossibilities = return [], commandArgdefaults = nodefaults, commandAdvancedOptions = [], commandBasicOptions = [possiblyRemoteRepoDir] } tagsCmd :: [DarcsFlag] -> [String] -> IO () tagsCmd opts _ = let repodir = fromMaybe "." (getRepourl opts) in withRepositoryDirectory opts repodir $ RepoJob $ \repository -> do patches <- readRepo repository sequence_ $ mapRL process $ newset2RL patches where process hp = case piTag $ info hp of Just t -> do t' <- normalize t t False putStrLn t' Nothing -> return () normalize :: String -> String -> Bool -> IO String normalize _ [] _ = return [] normalize t (x : xs) flag = if x == '\t' then do if flag then return () else hPutStrLn stderr ("warning: tag with TAB character: " ++ t) rest <- (normalize t xs True) return $ ' ' : rest else do rest <- (normalize t xs flag) return $ x : rest darcs-2.8.4/src/Darcs/Commands/Tag.hs0000644001765600176560000001402612104371431016577 0ustar ganeshganesh-- Copyright (C) 2003-2004 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. module Darcs.Commands.Tag ( tag ) where import System.Directory ( removeFile ) import Control.Monad ( when ) import Darcs.Commands ( DarcsCommand(..), nodefaults ) import Darcs.Arguments ( nocompress, umaskOption, patchnameOption, author, pipeInteractive, askLongComment, workingRepoDir, getAuthor ) import Darcs.Patch.PatchInfoAnd ( n2pia ) import Darcs.Repository ( amInHashedRepository, withRepoLock, Repository, RepoJob(..), readRepo, tentativelyAddPatch, finalizeRepositoryChanges, ) import Darcs.Patch ( infopatch, adddeps, Patchy, PrimPatch, PrimOf ) import Darcs.Patch.Info ( patchinfo ) import Darcs.Patch.Depends ( getTagsRight ) import Darcs.Commands.Record ( getDate, getLog ) import Darcs.Witnesses.Ordered ( FL(..) ) import Darcs.Lock ( worldReadableTemp ) import Darcs.Flags ( DarcsFlag(..), compression ) import System.IO ( hPutStr, stderr ) #include "gadts.h" tagDescription :: String tagDescription = "Name the current repository state for future reference." tagHelp :: String tagHelp = "The `darcs tag' command names the current repository state, so that it\n" ++ "can easily be referred to later. Every `important' state should be\n" ++ "tagged; in particular it is good practice to tag each stable release\n" ++ "with a number or codename. Advice on release numbering can be found\n" ++ "at http://producingoss.com/en/development-cycle.html.\n" ++ "\n" ++ "To reproduce the state of a repository `R' as at tag `t', use the\n" ++ "command `darcs get --tag t R'. The command `darcs show tags' lists\n" ++ "all tags in the current repository.\n" ++ "\n" ++ "Tagging also provides significant performance benefits: when Darcs\n" ++ "reaches a shared tag that depends on all antecedent patches, it can\n" ++ "simply stop processing.\n" ++ "\n" ++ "Like normal patches, a tag has a name, an author, a timestamp and an\n" ++ "optional long description, but it does not change the working tree.\n" ++ "A tag can have any name, but it is generally best to pick a naming\n" ++ "scheme and stick to it.\n" ++ "\n" ++ "The `darcs tag' command accepts the --pipe option, which behaves as\n" ++ "described in `darcs record'.\n" tag :: DarcsCommand tag = DarcsCommand {commandProgramName = "darcs", commandName = "tag", commandHelp = tagHelp, commandDescription = tagDescription, commandExtraArgs = -1, commandExtraArgHelp = ["[TAGNAME]"], commandCommand = tagCmd, commandPrereq = amInHashedRepository, commandGetArgPossibilities = return [], commandArgdefaults = nodefaults, commandAdvancedOptions = [nocompress,umaskOption], commandBasicOptions = [patchnameOption, author, pipeInteractive, askLongComment, workingRepoDir]} tagCmd :: [DarcsFlag] -> [String] -> IO () tagCmd opts args = withRepoLock opts $ RepoJob $ \(repository :: Repository p C(r u r)) -> do date <- getDate opts the_author <- getAuthor opts deps <- getTagsRight `fmap` readRepo repository (name, long_comment, mlogf) <- get_name_log (NilFL :: FL (PrimOf p) C(a a)) opts args myinfo <- patchinfo date name the_author long_comment let mypatch = infopatch myinfo NilFL -- Warning: A do-notation statement discarded a result of type Darcs.Repository.InternalTypes.Repository p r u r. _ <- tentativelyAddPatch repository (compression opts) $ n2pia $ adddeps mypatch deps finalizeRepositoryChanges repository maybe (return ()) removeFile mlogf putStrLn $ "Finished tagging patch '"++name++"'" where get_name_log ::(Patchy prim, PrimPatch prim) => FL prim C(a a) -> [DarcsFlag] -> [String] -> IO (String, [String], Maybe String) get_name_log nilFL o a = do let o2 = if null a then o else (add_patch_name o (unwords a)) (name, comment, mlogf) <- getLog o2 Nothing (worldReadableTemp "darcs-tag") nilFL when (length name < 2) $ hPutStr stderr $ "Do you really want to tag '" ++name++"'? If not type: darcs obliterate --last=1\n" return ("TAG " ++ name, comment, mlogf) add_patch_name :: [DarcsFlag] -> String -> [DarcsFlag] add_patch_name o a| has_patch_name o = o | otherwise = [PatchName a] ++ o has_patch_name (PatchName _:_) = True has_patch_name (_:fs) = has_patch_name fs has_patch_name [] = False -- This may be useful for developers, but users don't care about -- internals: -- -- A tagged version automatically depends on all patches in the -- repository. This allows you to later reproduce precisely that -- version. The tag does this by depending on all patches in the -- repository, except for those which are depended upon by other tags -- already in the repository. In the common case of a sequential -- series of tags, this means that the tag depends on all patches -- since the last tag, plus that tag itself. darcs-2.8.4/src/Darcs/Commands/Test.hs0000644001765600176560000000520612104371431017003 0ustar ganeshganesh-- Copyright (C) 2002-2005 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. module Darcs.Commands.Test ( test ) where import Prelude hiding ( catch ) import System.Exit ( exitWith ) import Darcs.Commands ( DarcsCommand(..), nodefaults, putInfo ) import Darcs.Arguments ( DarcsFlag(Test) , leaveTestDir , workingRepoDir ) import Darcs.Repository ( Repository, amInHashedRepository, withRepository, testRecorded, RepoJob(..) ) import Darcs.Patch ( RepoPatch ) import Darcs.Patch.Apply( ApplyState ) import Printer ( text ) import Storage.Hashed.Tree( Tree ) #include "gadts.h" testDescription :: String testDescription = "Run regression test." testHelp :: String testHelp = "If a regression test is defined (see `darcs setpref') it will be run.\n" test :: DarcsCommand test = DarcsCommand {commandProgramName = "darcs", commandName = "test", commandHelp = testHelp, commandDescription = testDescription, commandExtraArgs = 0, commandExtraArgHelp = [], commandCommand = testCmd, commandPrereq = amInHashedRepository, commandGetArgPossibilities = return [], commandArgdefaults = nodefaults, commandAdvancedOptions = [], commandBasicOptions = [ leaveTestDir, workingRepoDir ]} testCmd :: [DarcsFlag] -> [String] -> IO () testCmd opts _ = withRepository (Test:opts) (RepoJob (test' opts)) test' :: forall p C(r u t) . (RepoPatch p, ApplyState p ~ Tree) => [DarcsFlag] -> Repository p C(r u t) -> IO () test' opts repository = do putInfo opts $ text "Running test on current repository state." rc <- testRecorded repository exitWith rc darcs-2.8.4/src/Darcs/Commands/TrackDown.hs0000644001765600176560000002220312104371431017754 0ustar ganeshganesh-- Copyright (C) 2002-2005 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. module Darcs.Commands.TrackDown ( trackdown ) where import Prelude hiding ( init, catch ) import System.Exit ( ExitCode(..) ) import System.Cmd ( system ) import System.IO ( hFlush, stdout ) import Control.Exception ( catch, IOException ) import Control.Monad( when ) import Darcs.Commands ( DarcsCommand(..), nodefaults ) import Darcs.Arguments ( DarcsFlag(SetScriptsExecutable, Bisect), workingRepoDir, bisect, setScriptsExecutableOption, makeScriptsExecutable ) import Darcs.Patch.PatchInfoAnd ( hopefully ) import Darcs.Repository ( amInHashedRepository, readRepo, withRepoReadLock, RepoJob(..), withRecorded, setScriptsExecutable ) import Darcs.Witnesses.Ordered ( RL(..), (:<)(..), (+<+), reverseRL, splitAtRL, lengthRL, mapRL, mapFL, mapRL_RL ) import Darcs.Patch.Conflict ( Conflict ) import Darcs.Patch.FileHunk ( IsHunk ) import Darcs.Patch.ApplyMonad ( ApplyMonad ) import Darcs.Patch.Apply ( ApplyState ) import Darcs.Patch.Format ( PatchListFormat ) import Darcs.Patch.Patchy ( Patchy, Invert, Apply, ShowPatch ) import Darcs.Patch ( RepoPatch, Named, description, apply, invert ) import Darcs.Patch.Set ( newset2RL ) import Printer ( putDocLn ) import Darcs.Test ( getTest ) import Darcs.Lock ( withTempDir ) import Storage.Hashed.Tree( Tree ) #include "gadts.h" trackdownDescription :: String trackdownDescription = "Locate the most recent version lacking an error." trackdownHelp :: String trackdownHelp = "Trackdown tries to find the most recent version in the repository which\n"++ "passes a test. Given no arguments, it uses the default repository test.\n"++ "Given one argument, it treats it as a test command. Given two arguments,\n"++ "the first is an initialization command with is run only once, and the\n"++ "second is the test command.\n\n"++ "Without the --bisect option, trackdown does linear search starting from head,\n"++ "and moving away from head. With the --bisect option, it does binary search.\n\n"++ "Under the assumption that failure is monotonous, trackdown produces\n"++ "the same result with and without --bisect. (Monotonous means that when\n"++ "moving away from head, the test result changes only once from \"fail\" to \"ok\".)\n"++ "If failure is not monotonous, any one of the patches that break the test is\n"++ "found at random." trackdown :: DarcsCommand trackdown = DarcsCommand {commandProgramName = "darcs", commandName = "trackdown", commandHelp = trackdownHelp, commandDescription = trackdownDescription, commandExtraArgs = -1, commandExtraArgHelp = ["[[INITIALIZATION]", "COMMAND]"], commandCommand = trackdownCmd, commandPrereq = amInHashedRepository, commandGetArgPossibilities = return [], commandArgdefaults = nodefaults, commandAdvancedOptions = [setScriptsExecutableOption], commandBasicOptions = [workingRepoDir, bisect]} trackdownCmd :: [DarcsFlag] -> [String] -> IO () trackdownCmd opts args = withRepoReadLock opts $ RepoJob $ \repository -> do patches <- readRepo repository (init,test) <- case args of [] -> do t <- getTest opts return (return ExitSuccess, t) [cmd] -> do putStrLn $ "Tracking down command:\n"++cmd return $ (return ExitSuccess, system cmd) [init,cmd] -> do putStrLn $ "Initializing with command:\n"++init putStrLn $ "Tracking down command:\n"++cmd return $ (system init, system cmd) _ -> fail "Trackdown expects zero to two arguments." withRecorded repository (withTempDir "trackingdown") $ \_ -> do when (SetScriptsExecutable `elem` opts) setScriptsExecutable _ <- init (if Bisect `elem` opts then trackBisect else trackNextLinear) opts test (mapRL_RL hopefully . newset2RL $ patches) -- | linear search (without --bisect) trackNextLinear :: (RepoPatch p, ApplyMonad IO (ApplyState p), ApplyState p ~ Tree) => [DarcsFlag] -> IO ExitCode -> RL (Named p) C(x y) -> IO () trackNextLinear opts test (p:<:ps) = do test_result <- test if test_result == ExitSuccess then putStrLn "Success!" else do apply (invert p) `catch` \(e :: IOException) -> fail ("Bad patch:\n" ++ show e) makeScriptsExecutable opts (invert p) putStrLn "Trying without the patch:" putDocLn $ description $ invert p hFlush stdout trackNextLinear opts test ps trackNextLinear _opts test NilRL = do test_result <- test if test_result == ExitSuccess then putStrLn "Success!" else putStrLn "Noone passed the test!" -- | binary search (with --bisect) trackBisect :: (IsHunk p, Conflict p, PatchListFormat p, Patchy p, ApplyMonad IO (ApplyState p)) => [DarcsFlag] -> IO ExitCode -> RL p C(x y) -> IO () trackBisect _ test NilRL = do test_result <- test if test_result == ExitSuccess then putStrLn "Success!" else putStrLn "Noone passed the test!" trackBisect opts test ps = do test_result <- test if test_result == ExitSuccess then putStrLn ("Test does not fail on head.") else trackNextBisect opts curr_prog test BisectRight (patchTreeFromRL ps) where curr_prog = (1, 1 + round ((logBase 2 $ fromIntegral $ lengthRL ps) :: Double)) :: (Int,Int) -- | Bisect Patch Tree data PatchTree p C(x y) where Leaf :: p C(x y) -> PatchTree p C(x y) Fork :: PatchTree p C(y z) -> PatchTree p C(x y) -> PatchTree p C(x z) -- | Direction of Bisect trackdown data BisectDir = BisectLeft | BisectRight deriving Show -- | Progress of Bisect type BisectState = (Int, Int) -- | Create Bisect PatchTree from the RL patchTreeFromRL :: (Patchy p) => RL p C(x y) -> PatchTree p C(x y) patchTreeFromRL (l :<: NilRL) = Leaf l patchTreeFromRL xs = case splitAtRL (lengthRL xs `div` 2) xs of (l :< r) -> Fork (patchTreeFromRL l) (patchTreeFromRL r) -- | Convert PatchTree back to RL patchTree2RL :: (Patchy p) => PatchTree p C(x y) -> RL p C(x y) patchTree2RL (Leaf p) = p :<: NilRL patchTree2RL (Fork l r) = (patchTree2RL l) +<+ (patchTree2RL r) -- | Iterate the Patch Tree trackNextBisect :: (IsHunk p, Conflict p, PatchListFormat p, Patchy p, ApplyMonad IO (ApplyState p)) => [DarcsFlag] -> BisectState -> IO ExitCode -> BisectDir -> PatchTree p C(x y) -> IO () trackNextBisect opts (dnow, dtotal) test dir (Fork l r) = do putStr ("Trying " ++ show dnow ++ "/" ++ show dtotal ++ " sequences...\n") hFlush stdout case dir of BisectRight -> jumpHalfOnRight opts l -- move in temporary repo BisectLeft -> jumpHalfOnLeft opts r -- within given direction test_result <- test -- execute test on repo case test_result of ExitSuccess -> trackNextBisect opts (dnow+1, dtotal) test BisectLeft l -- continue left (to the present) _ -> trackNextBisect opts (dnow+1, dtotal) test BisectRight r -- continue right (to the past) trackNextBisect _ _ _ _ (Leaf p) = do putStrLn ("Last recent patch that fails the test (assuming monotony in the given range):") putDocLn (description p) jumpHalfOnRight :: (IsHunk p, Conflict p, PatchListFormat p, Patchy p, ApplyMonad IO (ApplyState p)) => [DarcsFlag] -> PatchTree p C(x y) -> IO () jumpHalfOnRight opts l = unapplyRL ps >> makeScriptsExecutable opts ps where ps = patchTree2RL l jumpHalfOnLeft :: (IsHunk p, Conflict p, PatchListFormat p, Patchy p, ApplyMonad IO (ApplyState p)) => [DarcsFlag] -> PatchTree p C(x y) -> IO () jumpHalfOnLeft opts r = applyRL p >> makeScriptsExecutable opts p where p = patchTree2RL r applyRL :: (Invert p, ShowPatch p, Apply p, ApplyMonad IO (ApplyState p)) => RL p C(x y) -> IO () applyRL patches = sequence_ (mapFL safeApply (reverseRL $ patches)) unapplyRL :: (Invert p, ShowPatch p, Apply p, ApplyMonad IO (ApplyState p)) => RL p C(x y) -> IO () unapplyRL patches = sequence_ (mapRL (safeApply . invert) patches) safeApply :: (Invert p, ShowPatch p, Apply p, ApplyMonad IO (ApplyState p)) => p C(x y) -> IO () safeApply p = apply p `catch` (\(msg :: IOException) -> fail ("Bad patch (during trackdown --bisect):\n" ++ show msg)) darcs-2.8.4/src/Darcs/Commands/TransferMode.hs0000644001765600176560000000733112104371431020456 0ustar ganeshganesh-- Copyright (C) 2008 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP, PatternGuards #-} -- The pragma above is only for pattern guards. module Darcs.Commands.TransferMode ( transferMode ) where import Prelude hiding ( catch ) import Control.Exception.Extensible ( catch ) import System.IO ( stdout, hFlush ) import Darcs.Utils ( withCurrentDirectory, prettyException ) import Darcs.Commands ( DarcsCommand(..), nodefaults ) import Darcs.Arguments ( DarcsFlag, workingRepoDir ) import Darcs.Repository ( amInRepository ) import Progress ( setProgressMode ) import Darcs.Global ( darcsdir ) import qualified Data.ByteString as B (hPut, readFile, length, ByteString) transferModeDescription :: String transferModeDescription = "Internal command for efficient ssh transfers." transferModeHelp :: String transferModeHelp = "When pulling from or pushing to a remote repository over ssh, if both\n" ++ "the local and remote ends have Darcs 2, the `transfer-mode' command\n" ++ "will be invoked on the remote end. This allows Darcs to intelligently\n" ++ "transfer information over a single ssh connection.\n" ++ "\n" ++ "If either end runs Darcs 1, a separate ssh connection will be created\n" ++ "for each transfer. As well as being less efficient, this means users\n" ++ "who do not run ssh-agent will be prompted for the ssh password tens or\n" ++ "hundreds of times!\n" transferMode :: DarcsCommand transferMode = DarcsCommand {commandProgramName = "darcs", commandName = "transfer-mode", commandHelp = transferModeHelp, commandDescription = transferModeDescription, commandExtraArgs = 0, commandExtraArgHelp = [], commandGetArgPossibilities = return [], commandCommand = transferModeCmd, commandPrereq = amInRepository, commandArgdefaults = nodefaults, commandAdvancedOptions = [], commandBasicOptions = [workingRepoDir]} transferModeCmd :: [DarcsFlag] -> [String] -> IO () transferModeCmd _ _ = do setProgressMode False putStrLn "Hello user, I am darcs transfer mode" hFlush stdout withCurrentDirectory darcsdir $ transfer transfer :: IO () transfer = do 'g':'e':'t':' ':fn <- getLine x <- readfile fn case x of Right c -> do putStrLn $ "got " ++ fn print $ B.length c B.hPut stdout c hFlush stdout Left e -> do putStrLn $ "error " ++ fn print e hFlush stdout transfer readfile :: String -> IO (Either String B.ByteString) readfile fn = (Right `fmap` B.readFile fn) `catch` (\e -> return $ Left (prettyException e)) darcs-2.8.4/src/Darcs/Commands/Util.hs0000644001765600176560000000523512104371431017003 0ustar ganeshganesh-- Copyright (C) 2002-2004 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP #-} #include "gadts.h" module Darcs.Commands.Util ( announceFiles, filterExistingFiles ) where import Darcs.Arguments ( DarcsFlag(LookForAdds) ) import Darcs.Patch ( RepoPatch ) import Darcs.RepoPath ( SubPath, toFilePath ) import Darcs.Repository ( Repository, extractOptions, readRecorded, readUnrecorded ) import Darcs.Repository.State ( applyTreeFilter, restrictBoring ) import Darcs.Patch.Apply ( ApplyState ) import Storage.Hashed( floatPath, readPlainTree ) import Storage.Hashed.Tree( Tree ) import Storage.Hashed.Monad ( virtualTreeIO, exists ) announceFiles :: Maybe [SubPath] -> String -> IO () announceFiles Nothing _ = return () announceFiles (Just files) message = putStrLn $ message ++ " " ++ unwords (map show files) ++ ":\n" filterExistingFiles :: (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u t) -> [SubPath] -> IO [SubPath] filterExistingFiles repo files = do pristine <- readRecorded repo -- TODO this is slightly inefficient, since we should really somehow -- extract the unrecorded state as a side-effect of unrecordedChanges index <- readUnrecorded repo $ Just files nonboring <- restrictBoring index working <- applyTreeFilter nonboring `fmap` readPlainTree "." let paths = map toFilePath files check = virtualTreeIO (mapM exists $ map floatPath paths) (in_working, _) <- check working (in_pristine, _) <- check pristine mapM_ maybe_warn $ zip3 paths in_working in_pristine return [ path | (path, True) <- zip files (zipWith (||) in_working in_pristine) ] where maybe_warn (file, False, False) = putStrLn $ "WARNING: File '"++file++"' does not exist!" maybe_warn (file, True, False) | LookForAdds `notElem` extractOptions repo = putStrLn $ "WARNING: File '" ++ file ++ "' not in repository!" maybe_warn _ = return () darcs-2.8.4/src/Darcs/Commands/Unrecord.hs0000644001765600176560000003037012104371431017645 0ustar ganeshganesh-- Copyright (C) 2002-2005 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP #-} module Darcs.Commands.Unrecord ( unrecord, unpull, obliterate, getLastPatches ) where import Prelude hiding ( catch ) import Control.Exception ( catch, IOException ) import Control.Monad ( when ) import System.Exit ( exitWith, ExitCode( ExitSuccess ) ) import Data.Maybe( isJust ) import Printer ( text, putDoc ) import English ( presentParticiple ) import Darcs.Patch.PatchInfoAnd ( hopefully, patchDesc ) import Darcs.Commands ( DarcsCommand(..), nodefaults, commandAlias, putVerbose ) import Darcs.Arguments ( DarcsFlag, output, outputAutoName, getOutput, workingRepoDir, nocompress, setEnvDarcsPatches, matchSeveralOrLast, depsSel, ignoretimes, allInteractive, umaskOption, summary, dryRun, printDryRunMessageAndExit, changesReverse ) import Darcs.Flags ( doReverse, UseIndex(..), ScanKnown(..), compression ) import Darcs.Match ( firstMatch, matchFirstPatchset, matchAPatchread ) import Darcs.Repository ( PatchInfoAnd, withGutsOf, withRepoLock, RepoJob(..), tentativelyRemovePatches, finalizeRepositoryChanges, tentativelyAddToPending, applyToWorking, readRepo, amInHashedRepository, invalidateIndex, unrecordedChanges ) import Darcs.Patch ( RepoPatch, invert, commute, effect ) import Darcs.Patch.Apply( ApplyState ) import Darcs.Patch.Set ( PatchSet(..), Tagged(..), appendPSFL ) #ifdef GADT_WITNESSES import Darcs.Patch.Set ( Origin ) #endif import Darcs.Witnesses.Ordered ( RL(..), (:>)(..), (+<+), mapFL_FL, nullFL, reverseRL, mapRL, FL(..) ) import Darcs.Patch.Depends ( findCommonWithThem ) import Darcs.SelectChanges ( selectChanges , WhichChanges(..) , selectionContext, runSelection ) import Darcs.Patch.Bundle ( makeBundleN, patchFilename, contextPatches ) import Progress ( debugMessage ) import Darcs.Witnesses.Sealed ( Sealed(..) ) import Darcs.RepoPath( useAbsoluteOrStd ) import Darcs.Lock( writeDocBinFile ) import Storage.Hashed.Tree( Tree ) #include "gadts.h" unrecordDescription :: String unrecordDescription = "Remove recorded patches without changing the working copy." unrecordHelp :: String unrecordHelp = "Unrecord does the opposite of record in that it makes the changes from\n"++ "patches active changes again which you may record or revert later. The\n"++ "working copy itself will not change.\n"++ "Beware that you should not use this command if you are going to\n"++ "re-record the changes in any way and there is a possibility that\n"++ "another user may have already pulled the patch.\n" unrecord :: DarcsCommand unrecord = DarcsCommand {commandProgramName = "darcs", commandName = "unrecord", commandHelp = unrecordHelp, commandDescription = unrecordDescription, commandExtraArgs = 0, commandExtraArgHelp = [], commandCommand = unrecordCmd, commandPrereq = amInHashedRepository, commandGetArgPossibilities = return [], commandArgdefaults = nodefaults, commandAdvancedOptions = [nocompress,umaskOption,changesReverse], commandBasicOptions = [matchSeveralOrLast, depsSel, allInteractive, workingRepoDir]} unrecordCmd :: [DarcsFlag] -> [String] -> IO () unrecordCmd opts _ = withRepoLock opts $ RepoJob $ \repository -> do allpatches <- readRepo repository (_ :> patches) <- return $ if firstMatch opts then getLastPatches opts allpatches else matchingHead opts allpatches let context = selectionContext "unrecord" opts Nothing Nothing selector = if doReverse opts then selectChanges Last else selectChanges LastReversed (_ :> to_unrecord) <- runSelection (selector patches) context when (nullFL to_unrecord) $ do putStrLn "No patches selected!" exitWith ExitSuccess putVerbose opts $ text "About to write out (potentially) modified patches..." setEnvDarcsPatches to_unrecord invalidateIndex repository -- Warning: A do-notation statement discarded a result of type Darcs.Repository.InternalTypes.Repository p r u z. withGutsOf repository $ do _ <- tentativelyRemovePatches repository (compression opts) to_unrecord finalizeRepositoryChanges repository putStrLn "Finished unrecording." getLastPatches :: RepoPatch p => [DarcsFlag] -> PatchSet p C(Origin r) -> ((PatchSet p) :> (FL (PatchInfoAnd p))) C(Origin r) getLastPatches opts ps = case matchFirstPatchset opts ps of Sealed p1s -> findCommonWithThem ps p1s unpullDescription :: String unpullDescription = "Opposite of pull; unsafe if patch is not in remote repository." unpullHelp :: String unpullHelp = "Unpull completely removes recorded patches from your local repository.\n"++ "The changes will be undone in your working copy and the patches will not be\n"++ "shown in your changes list anymore.\n"++ "Beware that if the patches are not still present in another repository you\n"++ "will lose precious code by unpulling!\n" unpull :: DarcsCommand unpull = (commandAlias "unpull" Nothing obliterate) {commandHelp = unpullHelp, commandDescription = unpullDescription, commandCommand = unpullCmd} unpullCmd :: [DarcsFlag] -> [String] -> IO () unpullCmd = genericObliterateCmd "unpull" obliterateDescription :: String obliterateDescription = "Delete selected patches from the repository. (UNSAFE!)" obliterateHelp :: String obliterateHelp = "Obliterate completely removes recorded patches from your local repository.\n"++ "The changes will be undone in your working copy and the patches will not be\n"++ "shown in your changes list anymore.\n"++ "Beware that you can lose precious code by obliterating!\n" obliterate :: DarcsCommand obliterate = DarcsCommand {commandProgramName = "darcs", commandName = "obliterate", commandHelp = obliterateHelp, commandDescription = obliterateDescription, commandExtraArgs = 0, commandExtraArgHelp = [], commandCommand = obliterateCmd, commandPrereq = amInHashedRepository, commandGetArgPossibilities = return [], commandArgdefaults = nodefaults, commandAdvancedOptions = [nocompress,ignoretimes,umaskOption, changesReverse], commandBasicOptions = [matchSeveralOrLast, depsSel, allInteractive, workingRepoDir, summary, output, outputAutoName]++ dryRun} obliterateCmd :: [DarcsFlag] -> [String] -> IO () obliterateCmd = genericObliterateCmd "obliterate" -- | genericObliterateCmd is the function that executes the "obliterate" and -- "unpull" commands. genericObliterateCmd :: String -- ^ The name under which the command is invoked (@unpull@ or @obliterate@) -> [DarcsFlag] -- ^ The flags given on the command line -> [String] -- ^ Files given on the command line (unused) -> IO () genericObliterateCmd cmdname opts _ = withRepoLock opts $ RepoJob $ \repository -> do -- FIXME we may need to honour --ignore-times here, although this command -- does not take that option (yet) pend <- unrecordedChanges (UseIndex, ScanKnown) repository Nothing allpatches <- readRepo repository (auto_kept :> removal_candidates) <- return $ if firstMatch opts then getLastPatches opts allpatches else matchingHead opts allpatches let context = selectionContext cmdname opts Nothing Nothing selector = if doReverse opts then selectChanges Last else selectChanges LastReversed (kept :> removed) <- runSelection (selector removal_candidates) context when (nullFL removed) $ do putStrLn "No patches selected!" exitWith ExitSuccess case commute (effect removed :> pend) of Nothing -> fail $ "Can't "++ cmdname ++ " patch without reverting some unrecorded change." Just (_ :> p_after_pending) -> do printDryRunMessageAndExit "obliterate" opts removed setEnvDarcsPatches removed when (isJust $ getOutput opts "") $ savetoBundle opts (auto_kept `appendPSFL` kept) removed invalidateIndex repository withGutsOf repository $ -- Warning: A do-notation statement discarded a result of type Darcs.Repository.InternalTypes.Repository p r u z. do _ <- tentativelyRemovePatches repository (compression opts) removed tentativelyAddToPending repository opts $ invert $ effect removed finalizeRepositoryChanges repository debugMessage "Applying patches to working directory..." _ <- applyToWorking repository opts (invert p_after_pending) `catch` \(e :: IOException) -> fail ("Couldn't undo patch in working dir.\n" ++ show e) return () putStrLn $ "Finished " ++ presentParticiple cmdname ++ "." -- | matchingHead returns the repository up to some tag. The tag t is -- the last tag such that there is a patch after t that is matched by -- the user's query. matchingHead :: forall p C(r). RepoPatch p => [DarcsFlag] -> PatchSet p C(Origin r) -> (PatchSet p :> FL (PatchInfoAnd p)) C(Origin r) matchingHead opts set = case mh set of (start :> patches) -> (start :> reverseRL patches) where mh :: FORALL(x) PatchSet p C(Origin x) -> (PatchSet p :> RL (PatchInfoAnd p)) C(Origin x) mh s@(PatchSet x _) | or (mapRL (matchAPatchread opts) x) = contextPatches s mh (PatchSet x (Tagged t _ ps :<: ts)) = case mh (PatchSet (t:<:ps) ts) of (start :> patches) -> (start :> x +<+ patches) mh ps = (ps :> NilRL) savetoBundle :: (RepoPatch p, ApplyState p ~ Tree) => [DarcsFlag] -> PatchSet p C(Origin z) -> FL (PatchInfoAnd p) C(z t) -> IO () savetoBundle opts kept removed@(x :>: _) = do bundle <- makeBundleN Nothing kept (mapFL_FL hopefully removed) let filename = patchFilename $ patchDesc x Just outname = getOutput opts filename useAbsoluteOrStd writeDocBinFile putDoc outname $ bundle savetoBundle _ _ NilFL = return () darcs-2.8.4/src/Darcs/Commands/Unrevert.hs0000644001765600176560000001447012104371431017701 0ustar ganeshganesh-- Copyright (C) 2003-2005 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP, GADTs #-} #include "gadts.h" module Darcs.Commands.Unrevert ( unrevert, writeUnrevert ) where import Prelude hiding ( catch ) import Control.Exception ( catch, IOException ) import System.Exit ( ExitCode(..), exitWith ) import Storage.Hashed.Tree( Tree ) import Darcs.Commands ( DarcsCommand(..), nodefaults ) import Darcs.Flags( diffingOpts ) import Darcs.Arguments ( DarcsFlag( MarkConflicts ), ignoretimes, workingRepoDir, allInteractive, umaskOption, unified ) import Darcs.Repository ( SealedPatchSet, Repository, withRepoLock, RepoJob(..), unrevertUrl, considerMergeToWorking, tentativelyAddToPending, finalizeRepositoryChanges, readRepo, amInHashedRepository, readRecorded, applyToWorking, unrecordedChanges ) import Darcs.Patch ( RepoPatch, PrimOf, commute, namepatch, fromPrims ) import Darcs.Patch.Apply( ApplyState ) #ifdef GADT_WITNESSES import Darcs.Patch.Set ( Origin ) #endif import Darcs.Witnesses.Ordered ( FL(..), (:>)(..), (+>+) ) import Darcs.SelectChanges ( selectChanges, WhichChanges(First), runSelection, selectionContextPrim ) import qualified Data.ByteString as B import Darcs.Lock ( writeDocBinFile, removeFileMayNotExist ) import Darcs.Patch.Depends ( mergeThem ) import Darcs.Utils ( askUser, catchall ) import Darcs.Patch.Bundle ( scanBundle, makeBundleN ) import IsoDate ( getIsoDateTime ) import Darcs.SignalHandler ( withSignalsBlocked ) import Progress ( debugMessage ) import Darcs.Witnesses.Sealed ( Sealed(Sealed) ) #include "impossible.h" unrevertDescription :: String unrevertDescription = "Undo the last revert (may fail if changes after the revert)." unrevertHelp :: String unrevertHelp = "Unrevert is a rescue command in case you accidentally reverted\n" ++ "something you wanted to keep (for example, typing `darcs rev -a'\n" ++ "instead of `darcs rec -a').\n" ++ "\n" ++ "This command may fail if the repository has changed since the revert\n" ++ "took place. Darcs will ask for confirmation before executing an\n" ++ "interactive command that will DEFINITELY prevent unreversion.\n" unrevert :: DarcsCommand unrevert = DarcsCommand {commandProgramName = "darcs", commandName = "unrevert", commandHelp = unrevertHelp, commandDescription = unrevertDescription, commandExtraArgs = 0, commandExtraArgHelp = [], commandCommand = unrevertCmd, commandPrereq = amInHashedRepository, commandGetArgPossibilities = return [], commandArgdefaults = nodefaults, commandAdvancedOptions = [umaskOption], commandBasicOptions = [ignoretimes, allInteractive, workingRepoDir, unified]} unrevertCmd :: [DarcsFlag] -> [String] -> IO () unrevertCmd opts [] = withRepoLock opts $ RepoJob $ \repository -> do us <- readRepo repository Sealed them <- unrevertPatchBundle repository rec <- readRecorded repository unrec <- unrecordedChanges (diffingOpts opts {- always ScanKnown here -}) repository Nothing Sealed h_them <- return $ mergeThem us them Sealed pw <- considerMergeToWorking repository "pull" (MarkConflicts:opts) NilFL h_them let context = selectionContextPrim "unrevert" opts Nothing Nothing (Just rec) (p :> skipped) <- runSelection (selectChanges First pw) context tentativelyAddToPending repository opts p withSignalsBlocked $ do finalizeRepositoryChanges repository _ <- applyToWorking repository opts p `catch` \(e :: IOException) -> fail ("Error applying unrevert to working directory...\n" ++ show e) debugMessage "I'm about to writeUnrevert." writeUnrevert repository skipped rec (unrec+>+p) debugMessage "Finished unreverting." unrevertCmd _ _ = impossible writeUnrevert :: (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u t) -> FL (PrimOf p) C(x y) -> Tree IO -> FL (PrimOf p) C(r x) -> IO () writeUnrevert repository NilFL _ _ = removeFileMayNotExist $ unrevertUrl repository writeUnrevert repository ps rec pend = do case commute (pend :> ps) of Nothing -> do really <- askUser "You will not be able to unrevert this operation! Proceed? " case really of ('y':_) -> return () _ -> exitWith $ ExitSuccess writeUnrevert repository NilFL rec pend Just (p' :> _) -> do rep <- readRepo repository date <- getIsoDateTime np <- namepatch date "unrevert" "anon" [] (fromRepoPrims repository p') bundle <- makeBundleN (Just rec) rep (np :>: NilFL) writeDocBinFile (unrevertUrl repository) bundle where fromRepoPrims :: RepoPatch p => Repository p C(r u t) -> FL (PrimOf p) C(r y) -> FL p C(r y) fromRepoPrims _ xs = fromPrims xs unrevertPatchBundle :: RepoPatch p => Repository p C(r u t) -> IO (SealedPatchSet p C(Origin)) unrevertPatchBundle repository = do pf <- B.readFile (unrevertUrl repository) `catchall` fail "There's nothing to unrevert!" case scanBundle pf of Right ps -> return ps Left err -> fail $ "Couldn't parse unrevert patch:\n" ++ err darcs-2.8.4/src/Darcs/Commands/WhatsNew.hs0000644001765600176560000002212212104371431017620 0ustar ganeshganesh-- Copyright (C) 2002-2004 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP #-} #include "gadts.h" module Darcs.Commands.WhatsNew ( whatsnew , status ) where import Control.Applicative ( (<$>) ) import Data.List ( delete ) import System.Exit ( ExitCode(..), exitWith ) import Storage.Hashed.Tree( Tree ) import Darcs.Arguments ( DarcsFlag(..), workingRepoDir, lookforadds, ignoretimes, noskipBoring, unified, summary, fixSubPaths, listRegisteredFiles ) import Darcs.Commands ( DarcsCommand(..), nodefaults, commandAlias ) import Darcs.Commands.Util ( announceFiles ) import Darcs.Diff( treeDiff ) import Darcs.Flags( isUnified, diffingOpts ) import Darcs.Patch ( RepoPatch, PrimPatch, PrimOf, plainSummaryPrims, primIsHunk, applyToTree ) import Darcs.Patch.Apply( ApplyState ) import Darcs.Patch.Format ( PatchListFormat(..) ) import Darcs.Patch.FileHunk ( IsHunk(..) ) import Darcs.Patch.Patchy ( Patchy ) import Darcs.Patch.Permutations ( partitionRL ) import Darcs.Patch.Prim.Class ( PrimDetails(..) ) import Darcs.Patch.TouchesFiles( choosePreTouching ) import Darcs.RepoPath( SubPath, toFilePath ) import Darcs.Repository ( Repository, withRepository, RepoJob(..) , amInRepository , unrecordedChanges, readRecorded ) import Darcs.Repository.Prefs ( filetypeFunction ) import Darcs.PrintPatch ( printPatch, contextualPrintPatch ) import Darcs.Witnesses.Ordered ( FL(..), reverseRL, reverseFL, (:>)(..) ) import Darcs.Witnesses.Sealed ( Sealed(..), unFreeLeft ) import Printer ( putDocLn, renderString, vcat, text ) whatsnew :: DarcsCommand whatsnew = DarcsCommand { commandProgramName = "darcs" , commandName = "whatsnew" , commandHelp = whatsnewHelp , commandDescription = whatsnewDescription , commandExtraArgs = -1 , commandExtraArgHelp = ["[FILE or DIRECTORY]..."] , commandCommand = whatsnewCmd , commandPrereq = amInRepository , commandGetArgPossibilities = listRegisteredFiles , commandArgdefaults = nodefaults , commandAdvancedOptions = [ignoretimes, noskipBoring] , commandBasicOptions = [ summary , unified , lookforadds , workingRepoDir ] } whatsnewDescription :: String whatsnewDescription = "List unrecorded changes in the working tree." whatsnewHelp :: String whatsnewHelp = "The `darcs whatsnew' command lists unrecorded changes to the working\n" ++ "tree. If you specify a set of files and directories, only unrecorded\n" ++ "changes to those files and directories are listed.\n" ++ "\n" ++ "With the --summary option, the changes are condensed to one line per\n" ++ "file, with mnemonics to indicate the nature and extent of the change.\n" ++ "The --look-for-adds option causes candidates for `darcs add' to be\n" ++ "included in the summary output. Summary mnemonics are as follows:\n" ++ "\n" ++ " `A f' and `A d/' respectively mean an added file or directory.\n" ++ " `R f' and `R d/' respectively mean a removed file or directory.\n" ++ " `M f -N +M rP' means a modified file, with N lines deleted, M\n" ++ " lines added, and P lexical replacements.\n" ++ " `f -> g' means a moved file or directory.\n" ++ " `a f' and `a d/' respectively mean a new, but unadded, file or\n" ++ " directory, when using --look-for-adds.\n" ++ "\n" ++ " An exclamation mark (!) as in `R! foo.c', means the hunk is known to\n" ++ " conflict with a hunk in another patch. The phrase `duplicated'\n" ++ " means the hunk is known to be identical to a hunk in another patch.\n" ++ "\n" ++ "By default, `darcs whatsnew' uses Darcs' internal format for changes.\n" ++ "To see some context (unchanged lines) around each change, use the\n" ++ "--unified option. To view changes in conventional `diff' format, use\n" ++ "the `darcs diff' command; but note that `darcs whatsnew' is faster.\n" ++ "\n" ++ "This command exits unsuccessfully (returns a non-zero exit status) if\n" ++ "there are no unrecorded changes.\n" whatsnewCmd :: [DarcsFlag] -> [String] -> IO () whatsnewCmd opts args = withRepository opts $ RepoJob $ \(repo :: Repository p C(r u r)) -> do files <- if null args then return Nothing else Just <$> fixSubPaths opts args let isLookForAdds = LookForAdds `elem` opts && NoSummary `notElem` opts -- LookForAdds implies Summary, unless it's explcitly disabled. optsModifier = if isLookForAdds then (Summary :) . (LookForAdds `delete`) else id opts' = optsModifier opts Sealed noLookChanges <- filteredUnrecordedChanges opts' repo files pristine <- readRecorded repo -- If we are looking for adds, return the corresponding FL of changes. Sealed unaddedNewPathsPs <- if isLookForAdds then do -- Use opts not opts', here, since we *do* want to look for adds. Sealed lookChanges <- filteredUnrecordedChanges opts repo files noLookAddsTree <- applyAddPatchesToPristine noLookChanges pristine lookAddsTree <- applyAddPatchesToPristine lookChanges pristine ftf <- filetypeFunction -- Return the patches that create files/dirs that aren't yet added. unFreeLeft <$> treeDiff ftf noLookAddsTree lookAddsTree else return (Sealed NilFL) announceFiles files "What's new in" exitOnNoChanges (unaddedNewPathsPs, noLookChanges) printChanges opts' pristine noLookChanges printUnaddedPaths unaddedNewPathsPs where -- |Filter out hunk patches (leaving add patches) and return the tree -- resulting from applying the filtered patches to the pristine tree. applyAddPatchesToPristine ps pristine = do adds :> _ <- return $ partitionRL primIsHunk $ reverseFL ps applyToTree (reverseRL adds) pristine exitOnNoChanges :: (FL p C(x y), FL p C(u v)) -> IO () exitOnNoChanges (NilFL, NilFL) = do putStrLn "No changes!" exitWith $ ExitFailure 1 exitOnNoChanges _ = return () printUnaddedPaths :: PrimPatch p => FL p C(x y) -> IO () printUnaddedPaths NilFL = return () printUnaddedPaths ps = putDocLn . lowercaseAs . renderString . plainSummaryPrims $ ps -- Make any add markers lowercase, to distinguish new-but-unadded files -- from those that are unrecorded, but added. lowercaseAs x = vcat $ map (text . lowercaseA) $ lines x lowercaseA ('A' : x) = 'a' : x lowercaseA x = x -- |Appropriately print changes, according to the passed flags. printChanges :: (PatchListFormat p, IsHunk p, Patchy p, PrimDetails p, ApplyState p ~ Tree) => [DarcsFlag] -> Tree IO -> FL p C(x y) -> IO () printChanges opts' pristine changes | Summary `elem` opts' = putDocLn $ plainSummaryPrims changes | isUnified opts' = contextualPrintPatch pristine changes | otherwise = printPatch changes -- |return the unrecorded changes that affect an optional list of paths. filteredUnrecordedChanges :: (RepoPatch p, ApplyState p ~ Tree, ApplyState (PrimOf p) ~ Tree) => [DarcsFlag] -> Repository p C(r u t) -> Maybe [SubPath] -> IO (Sealed (FL (PrimOf p) C(t))) filteredUnrecordedChanges opts' repo files = let filePaths = map toFilePath <$> files in let diffOpts = diffingOpts opts' in choosePreTouching filePaths <$> unrecordedChanges diffOpts repo files -- |status is an alias for whatsnew, with implicit Summary and LookForAdds -- flags. We override the default description, to include the implicit flags. status :: DarcsCommand status = statusAlias { commandCommand = statusCmd , commandDescription = statusDesc } where statusAlias = commandAlias "status" Nothing whatsnew statusCmd fs = commandCommand whatsnew (Summary : LookForAdds : fs) statusDesc = "Alias for `darcs " ++ commandName whatsnew ++ " -ls '." darcs-2.8.4/src/Darcs/Patch/0000755001765600176560000000000012104371431015023 5ustar ganeshganeshdarcs-2.8.4/src/Darcs/Patch/Bracketed/0000755001765600176560000000000012104371431016707 5ustar ganeshganeshdarcs-2.8.4/src/Darcs/Patch/Bracketed/Instances.hs0000644001765600176560000000146712104371431021202 0ustar ganeshganesh{-# OPTIONS_GHC -fno-warn-orphans #-} module Darcs.Patch.Bracketed.Instances () where import Darcs.Patch.Bracketed ( Bracketed(..) ) import Darcs.Patch.Show ( ShowPatchBasic(..) ) import Darcs.Witnesses.Ordered ( FL(NilFL), mapFL ) import Printer ( vcat, blueText, ($$) ) #include "gadts.h" instance ShowPatchBasic p => ShowPatchBasic (Bracketed p) where showPatch (Singleton p) = showPatch p showPatch (Braced NilFL) = blueText "{" $$ blueText "}" showPatch (Braced ps) = blueText "{" $$ vcat (mapFL showPatch ps) $$ blueText "}" showPatch (Parens ps) = blueText "(" $$ vcat (mapFL showPatch ps) $$ blueText ")" -- the ReadPatch instance is defined in Darcs.Patch.Read as it is -- used as an intermediate form during reading of lists of patches -- that are specified as ListFormatV1 or ListFormatV2. darcs-2.8.4/src/Darcs/Patch/Patchy/0000755001765600176560000000000012104371431016253 5ustar ganeshganeshdarcs-2.8.4/src/Darcs/Patch/Patchy/Instances.hs0000644001765600176560000000067712104371431020550 0ustar ganeshganesh{-# OPTIONS_GHC -fno-warn-orphans #-} module Darcs.Patch.Patchy.Instances () where import Darcs.Patch.Format ( PatchListFormat ) import Darcs.Patch.Patchy ( Patchy ) import Darcs.Patch.Permutations () import Darcs.Patch.FileHunk ( IsHunk ) import Darcs.Patch.Viewing () import Darcs.Witnesses.Ordered ( FL, RL ) instance (IsHunk p, PatchListFormat p, Patchy p) => Patchy (FL p) instance (IsHunk p, PatchListFormat p, Patchy p) => Patchy (RL p) darcs-2.8.4/src/Darcs/Patch/Prim/0000755001765600176560000000000012104371431015732 5ustar ganeshganeshdarcs-2.8.4/src/Darcs/Patch/Prim/V1/0000755001765600176560000000000012104371431016220 5ustar ganeshganeshdarcs-2.8.4/src/Darcs/Patch/Prim/V1/Apply.hs0000644001765600176560000001470212104371431017645 0ustar ganeshganesh{-# OPTIONS_GHC -fno-warn-orphans #-} module Darcs.Patch.Prim.V1.Apply () where import Darcs.Patch.Apply ( Apply(..) ) import Darcs.Patch.Repair ( RepairToFL(..) ) import Darcs.Patch.Prim.Class ( PrimApply(..) ) import Darcs.Patch.Prim.V1.Core ( Prim(..), DirPatchType(..), FilePatchType(..) ) import Darcs.Patch.Prim.V1.Show ( showHunk ) import Darcs.Patch.FileName ( fn2fp ) import Darcs.Patch.Format ( FileNameFormat(..) ) import Darcs.Patch.TokenReplace ( tryTokInternal ) import Darcs.Patch.ApplyMonad ( ApplyMonad(..) ) import Storage.Hashed.Tree( Tree ) import Darcs.Witnesses.Ordered ( FL(..), mapFL_FL, spanFL, (:>)(..) ) import Darcs.Witnesses.Unsafe ( unsafeCoercePStart ) import ByteStringUtils ( unlinesPS, breakAfterNthNewline, breakBeforeNthNewline, ) import Printer( renderString ) import qualified Data.ByteString as B ( ByteString, empty, null, concat ) import qualified Data.ByteString.Char8 as BC (pack, singleton, unpack) import Data.List ( intersperse ) #include "gadts.h" #include "impossible.h" type FileContents = B.ByteString instance Apply Prim where type ApplyState Prim = Tree apply (FP f RmFile) = mRemoveFile f apply (FP f AddFile) = mCreateFile f apply p@(FP _ (Hunk _ _ _)) = applyPrimFL (p :>: NilFL) apply (FP f (TokReplace t o n)) = mModifyFilePSs f doreplace where doreplace ls = case mapM (tryTokInternal t (BC.pack o) (BC.pack n)) ls of Nothing -> fail $ "replace patch to " ++ fn2fp f ++ " couldn't apply." Just ls' -> return $ map B.concat ls' apply (FP f (Binary o n)) = mModifyFilePS f doapply where doapply oldf = if o == oldf then return n else fail $ "binary patch to " ++ fn2fp f ++ " couldn't apply." apply (DP d AddDir) = mCreateDirectory d apply (DP d RmDir) = mRemoveDirectory d apply (Move f f') = mRename f f' apply (ChangePref p f t) = mChangePref p f t instance RepairToFL Prim where applyAndTryToFixFL (FP f RmFile) = do x <- mReadFilePS f mRemoveFile f return $ case B.null x of True -> Nothing False -> Just ("WARNING: Fixing removal of non-empty file "++fn2fp f, -- No need to coerce because the content -- removal patch has freely decided contexts FP f (Binary x B.empty) :>: FP f RmFile :>: NilFL ) applyAndTryToFixFL (FP f AddFile) = do exists <- mDoesFileExist f if exists then return $ Just ("WARNING: Dropping add of existing file "++fn2fp f, -- the old context was wrong, so we have to coerce unsafeCoercePStart NilFL ) else do mCreateFile f return Nothing applyAndTryToFixFL (DP f AddDir) = do exists <- mDoesDirectoryExist f if exists then return $ Just ("WARNING: Dropping add of existing directory "++fn2fp f, -- the old context was wrong, so we have to coerce unsafeCoercePStart NilFL ) else do mCreateDirectory f return Nothing applyAndTryToFixFL p = do apply p; return Nothing instance PrimApply Prim where applyPrimFL NilFL = return () applyPrimFL ((FP f h@(Hunk _ _ _)):>:the_ps) = case spanFL f_hunk the_ps of (xs :> ps') -> do let foo = h :>: mapFL_FL (\(FP _ h') -> h') xs mModifyFilePS f $ hunkmod foo applyPrimFL ps' where f_hunk (FP f' (Hunk _ _ _)) | f == f' = True f_hunk _ = False hunkmod :: ApplyMonad m Tree => FL FilePatchType C(x y) -> B.ByteString -> m B.ByteString hunkmod NilFL ps = return ps hunkmod (Hunk line old new:>:hs) ps = case applyHunkLines [(line,old,new)] ps of Just ps' -> hunkmod hs ps' Nothing -> fail $ "### Error applying:\n" ++ (renderString $ showHunk NewFormat f line old new) ++ "\n### to file " ++ fn2fp f ++ ":\n" ++ BC.unpack ps hunkmod _ _ = impossible applyPrimFL (p:>:ps) = do apply p applyPrimFL ps applyHunks :: [(Int, [B.ByteString], [B.ByteString])] -> B.ByteString -> Maybe [B.ByteString] applyHunks [] ps = Just [ps] applyHunks ((l, [], n):hs) ps = case breakBeforeNthNewline (l - 2) ps of (prfix, after_prefix) -> do rest <- applyHunks hs after_prefix return $ intersperse nl (prfix:n) ++ rest where nl = BC.singleton '\n' applyHunks ((l, o, n):hs) ps = case breakBeforeNthNewline (l - 2) ps of (prfix, after_prefix) -> case breakBeforeNthNewline (length o) after_prefix of (oo, _) | oo /= unlinesPS (B.empty:o) -> fail "applyHunks error" (_, suffix) -> do rest <- applyHunks hs suffix return $ intersperse nl (prfix:n) ++ rest where nl = BC.singleton '\n' applyHunkLines :: [(Int, [B.ByteString], [B.ByteString])] -> FileContents -> Maybe FileContents applyHunkLines [] c = Just c applyHunkLines [(1, [], n)] ps | B.null ps = Just $ unlinesPS (n++[B.empty]) applyHunkLines hs@((l, o, n):hs') ps = do pss <- case l of 1 -> case breakAfterNthNewline (length o) ps of Nothing -> if ps == unlinesPS o then return $ intersperse nl n else fail "applyHunkLines: Unexpected hunks" Just (shouldbeo, suffix) | shouldbeo /= unlinesPS (o++[B.empty]) -> fail $ "applyHunkLines: Bad patch!" | null n -> do x <- applyHunkLines hs' suffix return [x] | otherwise -> do rest <- applyHunks hs' suffix return $ intersperse nl n ++ nl:rest _ | l < 0 -> bug "Prim.applyHunkLines: After -ve lines?" | otherwise -> applyHunks hs ps let result = B.concat pss return result where nl = BC.singleton '\n' darcs-2.8.4/src/Darcs/Patch/Prim/V1/Coalesce.hs0000644001765600176560000002441012104371431020273 0ustar ganeshganesh{-# OPTIONS_GHC -fno-warn-orphans #-} module Darcs.Patch.Prim.V1.Coalesce () where import Prelude hiding ( pi ) import Data.Map ( elems, fromListWith, mapWithKey ) import qualified Data.ByteString as B (ByteString) import Darcs.Patch.FileName ( FileName, fp2fn ) import Darcs.Patch.Prim.Class ( PrimCanonize(..) ) import Darcs.Patch.Prim.V1.Commute () import Darcs.Patch.Prim.V1.Core ( Prim(..), FilePatchType(..), DirPatchType(..) , comparePrim, isIdentity ) import Darcs.Patch.Prim.V1.Show () import Darcs.Witnesses.Eq ( MyEq(..), EqCheck(..) ) import Darcs.Witnesses.Ordered ( FL(..), RL(..), (:>)(..), (:<)(..) , reverseRL, mapFL, mapFL_FL , concatFL, lengthFL, (+>+) ) import Darcs.Witnesses.Sealed ( unseal, Sealed2(..), unsafeUnseal2 , Gap(..), unFreeLeft ) import Darcs.Witnesses.Unsafe ( unsafeCoerceP, unsafeCoercePEnd ) import Darcs.Patch.Invert ( Invert(..) ) import Darcs.Patch.Commute ( Commute(..) ) -- import Darcs.Patch.Permutations () -- for Invert instance of FL import Lcs ( getChanges ) #include "gadts.h" #include "impossible.h" -- | 'coalesce' @p2 :< p1@ tries to combine @p1@ and @p2@ into a single -- patch without intermediary changes. For example, two hunk patches -- modifying adjacent lines can be coalesced into a bigger hunk patch. -- Or a patch which moves file A to file B can be coalesced with a -- patch that moves file B into file C, yielding a patch that moves -- file A to file C. coalesce :: (Prim :< Prim) C(x y) -> Maybe (FL Prim C(x y)) coalesce (FP f1 _ :< FP f2 _) | f1 /= f2 = Nothing coalesce (p2 :< p1) | IsEq <- p2 =\/= invert p1 = Just NilFL coalesce (FP f1 p1 :< FP _ p2) = fmap (:>: NilFL) $ coalesceFilePrim f1 (p1 :< p2) -- f1 = f2 coalesce (Move a b :< Move b' a') | a == a' = Just $ Move b' b :>: NilFL coalesce (Move a b :< FP f AddFile) | f == a = Just $ FP b AddFile :>: NilFL coalesce (Move a b :< DP f AddDir) | f == a = Just $ DP b AddDir :>: NilFL coalesce (FP f RmFile :< Move a b) | b == f = Just $ FP a RmFile :>: NilFL coalesce (DP f RmDir :< Move a b) | b == f = Just $ DP a RmDir :>: NilFL coalesce (ChangePref p f1 t1 :< ChangePref p2 f2 t2) | p == p2 && t2 == f1 = Just $ ChangePref p f2 t1 :>: NilFL coalesce _ = Nothing mapPrimFL :: (FORALL(x y) FL Prim C(x y) -> FL Prim C(x y)) -> FL Prim C(w z) -> FL Prim C(w z) mapPrimFL f x = -- an optimisation; break the list up into independent sublists -- and apply f to each of them case mapM toSimpleSealed $ mapFL Sealed2 x of Just sx -> concatFL $ unsealList $ elems $ mapWithKey (\ k p -> Sealed2 (f (fromSimples k (unsealList (p []))))) $ fromListWith (flip (.)) $ map (\ (a,b) -> (a,(b:))) sx Nothing -> f x where unsealList :: [Sealed2 p] -> FL p C(a b) unsealList [] = unsafeCoerceP NilFL unsealList (y:ys) = unsafeUnseal2 y :>: unsealList ys toSimpleSealed :: Sealed2 Prim -> Maybe (FileName, Sealed2 Simple) toSimpleSealed (Sealed2 p) = fmap (\(fn, s) -> (fn, Sealed2 s)) (toSimple p) data Simple C(x y) = SFP !(FilePatchType C(x y)) | SDP !(DirPatchType C(x y)) | SCP String String String deriving ( Show ) toSimple :: Prim C(x y) -> Maybe (FileName, Simple C(x y)) toSimple (FP a b) = Just (a, SFP b) toSimple (DP a AddDir) = Just (a, SDP AddDir) toSimple (DP _ RmDir) = Nothing -- ordering is trickier with rmdir present toSimple (Move _ _) = Nothing toSimple (ChangePref a b c) = Just (fp2fn "_darcs/prefs/prefs", SCP a b c) fromSimple :: FileName -> Simple C(x y) -> Prim C(x y) fromSimple a (SFP b) = FP a b fromSimple a (SDP b) = DP a b fromSimple _ (SCP a b c) = ChangePref a b c fromSimples :: FileName -> FL Simple C(x y) -> FL Prim C(x y) fromSimples a bs = mapFL_FL (fromSimple a) bs tryHarderToShrink :: FL Prim C(x y) -> FL Prim C(x y) tryHarderToShrink x = tryToShrink2 $ maybe x id (tryShrinkingInverse x) tryToShrink2 :: FL Prim C(x y) -> FL Prim C(x y) tryToShrink2 psold = let ps = sortCoalesceFL psold ps_shrunk = shrinkABit ps in if lengthFL ps_shrunk < lengthFL ps then tryToShrink2 ps_shrunk else ps_shrunk shrinkABit :: FL Prim C(x y) -> FL Prim C(x y) shrinkABit NilFL = NilFL shrinkABit (p:>:ps) = case tryOne NilRL p ps of Nothing -> p :>: shrinkABit ps Just ps' -> ps' tryOne :: RL Prim C(w x) -> Prim C(x y) -> FL Prim C(y z) -> Maybe (FL Prim C(w z)) tryOne _ _ NilFL = Nothing tryOne sofar p (p1:>:ps) = case coalesce (p1 :< p) of Just p' -> Just (reverseRL sofar +>+ p' +>+ ps) Nothing -> case commute (p :> p1) of Nothing -> Nothing Just (p1' :> p') -> tryOne (p1':<:sofar) p' ps -- | The heart of "sortCoalesceFL" sortCoalesceFL2 :: FL Prim C(x y) -> FL Prim C(x y) sortCoalesceFL2 NilFL = NilFL sortCoalesceFL2 (x:>:xs) | IsEq <- isIdentity x = sortCoalesceFL2 xs sortCoalesceFL2 (x:>:xs) = either id id $ pushCoalescePatch x $ sortCoalesceFL2 xs -- | 'pushCoalescePatch' @new ps@ is almost like @new :>: ps@ except -- as an alternative to consing, we first try to coalesce @new@ with -- the head of @ps@. If this fails, we try again, using commutation -- to push @new@ down the list until we find a place where either -- (a) @new@ is @LT@ the next member of the list [see 'comparePrim'] -- (b) commutation fails or -- (c) coalescing succeeds. -- The basic principle is to coalesce if we can and cons otherwise. -- -- As an additional optimization, pushCoalescePatch outputs a Left -- value if it wasn't able to shrink the patch sequence at all, and -- a Right value if it was indeed able to shrink the patch sequence. -- This avoids the O(N) calls to lengthFL that were in the older -- code. -- -- Also note that pushCoalescePatch is only ever used (and should -- only ever be used) as an internal function in in -- sortCoalesceFL2. pushCoalescePatch :: Prim C(x y) -> FL Prim C(y z) -> Either (FL Prim C(x z)) (FL Prim C(x z)) pushCoalescePatch new NilFL = Left (new:>:NilFL) pushCoalescePatch new ps@(p:>:ps') = case coalesce (p :< new) of Just (new' :>: NilFL) -> Right $ either id id $ pushCoalescePatch new' ps' Just NilFL -> Right ps' Just _ -> impossible -- coalesce either returns a singleton or empty Nothing -> if comparePrim new p == LT then Left (new:>:ps) else case commute (new :> p) of Just (p' :> new') -> case pushCoalescePatch new' ps' of Right r -> Right $ either id id $ pushCoalescePatch p' r Left r -> Left (p' :>: r) Nothing -> Left (new:>:ps) coalesceFilePrim :: FileName -> (FilePatchType :< FilePatchType) C(x y) -> Maybe (Prim C(x y)) coalesceFilePrim f (Hunk line1 old1 new1 :< Hunk line2 old2 new2) = coalesceHunk f line1 old1 new1 line2 old2 new2 -- Token replace patches operating right after (or before) AddFile (RmFile) -- is an identity patch, as far as coalescing is concerned. coalesceFilePrim f (TokReplace _ _ _ :< AddFile) = Just $ FP f AddFile coalesceFilePrim f (RmFile :< TokReplace _ _ _) = Just $ FP f RmFile coalesceFilePrim f (TokReplace t1 o1 n1 :< TokReplace t2 o2 n2) | t1 == t2 && n2 == o1 = Just $ FP f $ TokReplace t1 o2 n1 coalesceFilePrim f (Binary m n :< Binary o m') | m == m' = Just $ FP f $ Binary o n coalesceFilePrim _ _ = Nothing coalesceHunk :: FileName -> Int -> [B.ByteString] -> [B.ByteString] -> Int -> [B.ByteString] -> [B.ByteString] -> Maybe (Prim C(x y)) coalesceHunk f line1 old1 new1 line2 old2 new2 | line1 == line2 && lengthold1 < lengthnew2 = if take lengthold1 new2 /= old1 then Nothing else case drop lengthold1 new2 of extranew -> Just (FP f (Hunk line1 old2 (new1 ++ extranew))) | line1 == line2 && lengthold1 > lengthnew2 = if take lengthnew2 old1 /= new2 then Nothing else case drop lengthnew2 old1 of extraold -> Just (FP f (Hunk line1 (old2 ++ extraold) new1)) | line1 == line2 = if new2 == old1 then Just (FP f (Hunk line1 old2 new1)) else Nothing | line1 < line2 && lengthold1 >= line2 - line1 = case take (line2 - line1) old1 of extra-> coalesceHunk f line1 old1 new1 line1 (extra ++ old2) (extra ++ new2) | line1 > line2 && lengthnew2 >= line1 - line2 = case take (line1 - line2) new2 of extra-> coalesceHunk f line2 (extra ++ old1) (extra ++ new1) line2 old2 new2 | otherwise = Nothing where lengthold1 = length old1 lengthnew2 = length new2 canonizeHunk :: Gap w => FileName -> Int -> [B.ByteString] -> [B.ByteString] -> w (FL Prim) canonizeHunk f line old new | null old || null new = freeGap (FP f (Hunk line old new) :>: NilFL) canonizeHunk f line old new = makeHoley f line $ getChanges old new makeHoley :: Gap w => FileName -> Int -> [(Int,[B.ByteString], [B.ByteString])] -> w (FL Prim) makeHoley f line changes = foldr (joinGap (:>:)) (emptyGap NilFL) $ map (\ (l,o,n) -> freeGap (FP f (Hunk (l+line) o n))) changes instance PrimCanonize Prim where tryToShrink = mapPrimFL tryHarderToShrink tryShrinkingInverse (x:>:y:>:z) | IsEq <- invert x =\/= y = Just z | otherwise = case tryShrinkingInverse (y:>:z) of Nothing -> Nothing Just yz' -> Just $ case tryShrinkingInverse (x:>:yz') of Nothing -> x:>:yz' Just xyz' -> xyz' tryShrinkingInverse _ = Nothing sortCoalesceFL = mapPrimFL sortCoalesceFL2 canonize p | IsEq <- isIdentity p = NilFL canonize (FP f (Hunk line old new)) = unseal unsafeCoercePEnd $ unFreeLeft $ canonizeHunk f line old new canonize p = p :>: NilFL -- Running canonize twice is apparently necessary to fix issue525; -- would be nice to understand why. canonizeFL = concatFL . mapFL_FL canonize . sortCoalesceFL . concatFL . mapFL_FL canonize join (x :> y) = coalesce (y :< x) darcs-2.8.4/src/Darcs/Patch/Prim/V1/Commute.hs0000644001765600176560000002022612104371431020167 0ustar ganeshganesh{-# OPTIONS_GHC -fno-warn-orphans #-} module Darcs.Patch.Prim.V1.Commute ( Perhaps(..) , subcommutes, WrappedCommuteFunction(..) ) where import Prelude hiding ( pi ) import Control.Monad ( MonadPlus, msum, mzero, mplus ) import qualified Data.ByteString as B (ByteString, concat) import qualified Data.ByteString.Char8 as BC (pack) import Darcs.Patch.FileName ( FileName, fn2fp, movedirfilename ) import Darcs.Witnesses.Ordered ( (:<)(..) ) import Darcs.Witnesses.Unsafe ( unsafeCoerceP ) import Darcs.Patch.Prim.V1.Core ( Prim(..), FilePatchType(..) ) import Darcs.Patch.Invert ( Invert(..) ) import Darcs.Patch.Commute ( Commute(..), toFwdCommute, toRevCommute ) import Darcs.Patch.Permutations () -- for Invert instance of FL import Darcs.Patch.TokenReplace ( tryTokInternal ) #include "impossible.h" #include "gadts.h" isInDirectory :: FileName -> FileName -> Bool isInDirectory d f = iid (fn2fp d) (fn2fp f) where iid (cd:cds) (cf:cfs) | cd /= cf = False | otherwise = iid cds cfs iid [] ('/':_) = True iid [] [] = True -- Count directory itself as being in directory... iid _ _ = False data Perhaps a = Unknown | Failed | Succeeded a instance Monad Perhaps where (Succeeded x) >>= k = k x Failed >>= _ = Failed Unknown >>= _ = Unknown Failed >> _ = Failed (Succeeded _) >> k = k Unknown >> k = k return = Succeeded fail _ = Unknown instance MonadPlus Perhaps where mzero = Unknown Unknown `mplus` ys = ys Failed `mplus` _ = Failed (Succeeded x) `mplus` _ = Succeeded x toMaybe :: Perhaps a -> Maybe a toMaybe (Succeeded x) = Just x toMaybe _ = Nothing toPerhaps :: Maybe a -> Perhaps a toPerhaps (Just x) = Succeeded x toPerhaps Nothing = Failed cleverCommute :: CommuteFunction -> CommuteFunction cleverCommute c (p1: Succeeded x Failed -> Failed Unknown -> case c (invert p2 :< invert p1) of Succeeded (p1' :< p2') -> Succeeded (invert p2' :< invert p1') Failed -> Failed Unknown -> Unknown --cleverCommute c (p1,p2) = c (p1,p2) `mplus` -- (case c (invert p2,invert p1) of -- Succeeded (p1', p2') -> Succeeded (invert p2', invert p1') -- Failed -> Failed -- Unknown -> Unknown) speedyCommute :: CommuteFunction -- Deal with common cases quickly! -- Two file-patches modifying different files trivially commute. speedyCommute (p2@(FP f' _) :< p1@(FP f _)) | f /= f' = Succeeded (unsafeCoerceP p1 :< unsafeCoerceP p2) speedyCommute _other = Unknown everythingElseCommute :: CommuteFunction everythingElseCommute x = eec x where eec :: CommuteFunction eec (ChangePref p f t : FileName -> Bool isSuperdir d1 d2 = isd (fn2fp d1) (fn2fp d2) where isd s1 s2 = length s2 >= length s1 + 1 && take (length s1 + 1) s2 == s1 ++ "/" commuteFiledir :: CommuteFunction commuteFiledir (FP f1 p1 :< FP f2 p2) = if f1 /= f2 then Succeeded ( FP f2 (unsafeCoerceP p2) :< FP f1 (unsafeCoerceP p1) ) else commuteFP f1 (p1 :< p2) commuteFiledir (DP d1 p1 :< DP d2 p2) = if (not $ isInDirectory d1 d2) && (not $ isInDirectory d2 d1) && d1 /= d2 then Succeeded ( DP d2 (unsafeCoerceP p2) :< DP d1 (unsafeCoerceP p1) ) else Failed commuteFiledir (DP d dp :< FP f fp) = if not $ isInDirectory d f then Succeeded (FP f (unsafeCoerceP fp) :< DP d (unsafeCoerceP dp)) else Failed commuteFiledir (Move d d' :< FP f2 p2) | f2 == d' = Failed | (p2 == AddFile || p2 == RmFile) && d == f2 = Failed | otherwise = Succeeded (FP (movedirfilename d d' f2) (unsafeCoerceP p2) :< Move d d') commuteFiledir (Move d d' :< DP d2 p2) | isSuperdir d2 d' || isSuperdir d2 d = Failed | d == d2 = Failed -- The exact guard is p2 == AddDir && d == d2 -- but note d == d2 suffices because we know p2 != RmDir -- (and hence p2 == AddDir) since patches must be sequential. | d2 == d' = Failed | otherwise = Succeeded (DP (movedirfilename d d' d2) (unsafeCoerceP p2) :< Move d d') commuteFiledir (Move d d' :< Move f f') | f == d' || f' == d = Failed | f == d || f' == d' = Failed | d `isSuperdir` f && f' `isSuperdir` d' = Failed | otherwise = Succeeded (Move (movedirfilename d d' f) (movedirfilename d d' f') :< Move (movedirfilename f' f d) (movedirfilename f' f d')) commuteFiledir _ = Unknown type CommuteFunction = FORALL(x y) (Prim :< Prim) C(x y) -> Perhaps ((Prim :< Prim) C(x y)) newtype WrappedCommuteFunction = WrappedCommuteFunction { runWrappedCommuteFunction :: CommuteFunction } subcommutes :: [(String, WrappedCommuteFunction)] subcommutes = [("speedyCommute", WrappedCommuteFunction speedyCommute), ("commuteFiledir", WrappedCommuteFunction (cleverCommute commuteFiledir)), ("commuteFilepatches", WrappedCommuteFunction (cleverCommute commuteFilepatches)), ("commutex", WrappedCommuteFunction (toPerhaps . toRevCommute commute)) ] commuteFilepatches :: CommuteFunction commuteFilepatches (FP f1 p1 :< FP f2 p2) | f1 == f2 = commuteFP f1 (p1 :< p2) commuteFilepatches _ = Unknown commuteFP :: FileName -> (FilePatchType :< FilePatchType) C(x y) -> Perhaps ((Prim :< Prim) C(x y)) commuteFP f (Hunk line1 [] [] :< p2) = seq f $ Succeeded (FP f (unsafeCoerceP p2) :< FP f (Hunk line1 [] [])) commuteFP f (p2 :< Hunk line1 [] []) = seq f $ Succeeded (FP f (Hunk line1 [] []) :< FP f (unsafeCoerceP p2)) commuteFP f (Hunk line1 old1 new1 :< Hunk line2 old2 new2) = seq f $ toPerhaps $ commuteHunk f (Hunk line1 old1 new1 :< Hunk line2 old2 new2) commuteFP f (TokReplace t o n :< Hunk line2 old2 new2) = seq f $ case tryTokReplace t o n old2 of Nothing -> Failed Just old2' -> case tryTokReplace t o n new2 of Nothing -> Failed Just new2' -> Succeeded (FP f (Hunk line2 old2' new2') :< FP f (TokReplace t o n)) commuteFP f (TokReplace t o n :< TokReplace t2 o2 n2) | seq f $ t /= t2 = Failed | o == o2 = Failed | n == o2 = Failed | o == n2 = Failed | n == n2 = Failed | otherwise = Succeeded (FP f (TokReplace t2 o2 n2) :< FP f (TokReplace t o n)) commuteFP _ _ = Unknown commuteHunk :: FileName -> (FilePatchType :< FilePatchType) C(x y) -> Maybe ((Prim :< Prim) C(x y)) commuteHunk f (Hunk line2 old2 new2 :< Hunk line1 old1 new1) | seq f $ line1 + lengthnew1 < line2 = Just (FP f (Hunk line1 old1 new1) :< FP f (Hunk (line2 - lengthnew1 + lengthold1) old2 new2)) | line2 + lengthold2 < line1 = Just (FP f (Hunk (line1+ lengthnew2 - lengthold2) old1 new1) :< FP f (Hunk line2 old2 new2)) | line1 + lengthnew1 == line2 && lengthold2 /= 0 && lengthold1 /= 0 && lengthnew2 /= 0 && lengthnew1 /= 0 = Just (FP f (Hunk line1 old1 new1) :< FP f (Hunk (line2 - lengthnew1 + lengthold1) old2 new2)) | line2 + lengthold2 == line1 && lengthold2 /= 0 && lengthold1 /= 0 && lengthnew2 /= 0 && lengthnew1 /= 0 = Just (FP f (Hunk (line1 + lengthnew2 - lengthold2) old1 new1) :< FP f (Hunk line2 old2 new2)) | otherwise = seq f Nothing where lengthnew1 = length new1 lengthnew2 = length new2 lengthold1 = length old1 lengthold2 = length old2 commuteHunk _ _ = impossible tryTokReplace :: String -> String -> String -> [B.ByteString] -> Maybe [B.ByteString] tryTokReplace t o n mss = mapM (fmap B.concat . tryTokInternal t (BC.pack o) (BC.pack n)) mss darcs-2.8.4/src/Darcs/Patch/Prim/V1/Core.hs0000644001765600176560000001461012104371431017446 0ustar ganeshganesh-- Copyright (C) 2002-2003,2007 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP #-} #include "gadts.h" module Darcs.Patch.Prim.V1.Core ( Prim(..), DirPatchType(..), FilePatchType(..), isIdentity, comparePrim, ) where import Prelude hiding ( pi ) import qualified Data.ByteString as B (ByteString) import Darcs.Patch.FileName ( FileName, fn2fp, fp2fn, normPath ) import Darcs.Witnesses.Eq ( MyEq(..), EqCheck(..) ) import Darcs.Witnesses.Unsafe ( unsafeCoerceP ) import Darcs.Patch.FileHunk ( FileHunk(..), IsHunk(..) ) import Darcs.Patch.Invert ( Invert(..) ) import Darcs.Patch.Inspect ( PatchInspect(..) ) import Darcs.Patch.Permutations () -- for Invert instance of FL import Darcs.Patch.Prim.Class ( PrimConstruct(..), PrimClassify(..) ) data Prim C(x y) where Move :: !FileName -> !FileName -> Prim C(x y) DP :: !FileName -> !(DirPatchType C(x y)) -> Prim C(x y) FP :: !FileName -> !(FilePatchType C(x y)) -> Prim C(x y) ChangePref :: !String -> !String -> !String -> Prim C(x y) data FilePatchType C(x y) = RmFile | AddFile | Hunk !Int [B.ByteString] [B.ByteString] | TokReplace !String !String !String | Binary B.ByteString B.ByteString deriving (Eq,Ord) data DirPatchType C(x y) = RmDir | AddDir deriving (Eq,Ord) instance MyEq FilePatchType where unsafeCompare a b = a == unsafeCoerceP b instance MyEq DirPatchType where unsafeCompare a b = a == unsafeCoerceP b isIdentity :: Prim C(x y) -> EqCheck C(x y) isIdentity (FP _ (Binary old new)) | old == new = unsafeCoerceP IsEq isIdentity (FP _ (Hunk _ old new)) | old == new = unsafeCoerceP IsEq isIdentity (FP _ (TokReplace _ old new)) | old == new = unsafeCoerceP IsEq isIdentity (Move old new) | old == new = unsafeCoerceP IsEq isIdentity _ = NotEq instance PrimClassify Prim where primIsAddfile (FP _ AddFile) = True primIsAddfile _ = False primIsRmfile (FP _ RmFile) = True primIsRmfile _ = False primIsAdddir (DP _ AddDir) = True primIsAdddir _ = False primIsRmdir (DP _ RmDir) = True primIsRmdir _ = False primIsMove (Move _ _) = True primIsMove _ = False primIsHunk (FP _ (Hunk _ _ _)) = True primIsHunk _ = False primIsTokReplace (FP _ (TokReplace _ _ _)) = True primIsTokReplace _ = False primIsBinary (FP _ (Binary _ _)) = True primIsBinary _ = False primIsSetpref (ChangePref _ _ _) = True primIsSetpref _ = False is_filepatch (FP f _) = Just f is_filepatch _ = Nothing evalargs :: (a -> b -> c) -> a -> b -> c evalargs f x y = (f $! x) $! y instance PrimConstruct Prim where addfile f = FP (fp2fn $ nFn f) AddFile rmfile f = FP (fp2fn $ nFn f) RmFile adddir d = DP (fp2fn $ nFn d) AddDir rmdir d = DP (fp2fn $ nFn d) RmDir move f f' = Move (fp2fn $ nFn f) (fp2fn $ nFn f') changepref p f t = ChangePref p f t hunk f line old new = evalargs FP (fp2fn $ nFn f) (Hunk line old new) tokreplace f tokchars old new = evalargs FP (fp2fn $ nFn f) (TokReplace tokchars old new) binary f old new = FP (fp2fn $! nFn f) $ Binary old new primFromHunk (FileHunk fn line before after) = FP fn (Hunk line before after) anIdentity = let fp = "./dummy" in move fp fp nFn :: FilePath -> FilePath nFn f = "./"++(fn2fp $ normPath $ fp2fn f) instance IsHunk Prim where isHunk (FP fn (Hunk line before after)) = Just (FileHunk fn line before after) isHunk _ = Nothing instance Invert Prim where invert (FP f RmFile) = FP f AddFile invert (FP f AddFile) = FP f RmFile invert (FP f (Hunk line old new)) = FP f $ Hunk line new old invert (FP f (TokReplace t o n)) = FP f $ TokReplace t n o invert (FP f (Binary o n)) = FP f $ Binary n o invert (DP d RmDir) = DP d AddDir invert (DP d AddDir) = DP d RmDir invert (Move f f') = Move f' f invert (ChangePref p f t) = ChangePref p t f instance PatchInspect Prim where -- Recurse on everything, these are potentially spoofed patches listTouchedFiles (Move f1 f2) = map fn2fp [f1, f2] listTouchedFiles (FP f _) = [fn2fp f] listTouchedFiles (DP d _) = [fn2fp d] listTouchedFiles (ChangePref _ _ _) = [] hunkMatches f (FP _ (Hunk _ remove add)) = anyMatches remove || anyMatches add where anyMatches = foldr ((||) . f) False hunkMatches _ (FP _ _) = False hunkMatches _ (DP _ _) = False hunkMatches _ (ChangePref _ _ _) = False hunkMatches _ (Move _ _) = False instance MyEq Prim where unsafeCompare (Move a b) (Move c d) = a == c && b == d unsafeCompare (DP d1 p1) (DP d2 p2) = d1 == d2 && p1 `unsafeCompare` p2 unsafeCompare (FP f1 fp1) (FP f2 fp2) = f1 == f2 && fp1 `unsafeCompare` fp2 unsafeCompare (ChangePref a1 b1 c1) (ChangePref a2 b2 c2) = c1 == c2 && b1 == b2 && a1 == a2 unsafeCompare _ _ = False instance Eq (Prim C(x y)) where (==) = unsafeCompare -- | 'comparePrim' @p1 p2@ is used to provide an arbitrary ordering between -- @p1@ and @p2@. Basically, identical patches are equal and -- @Move < DP < FP < ChangePref@. -- Everything else is compared in dictionary order of its arguments. comparePrim :: Prim C(x y) -> Prim C(w z) -> Ordering comparePrim (Move a b) (Move c d) = compare (a, b) (c, d) comparePrim (Move _ _) _ = LT comparePrim _ (Move _ _) = GT comparePrim (DP d1 p1) (DP d2 p2) = compare (d1, p1) $ unsafeCoerceP (d2, p2) comparePrim (DP _ _) _ = LT comparePrim _ (DP _ _) = GT comparePrim (FP f1 fp1) (FP f2 fp2) = compare (f1, fp1) $ unsafeCoerceP (f2, fp2) comparePrim (FP _ _) _ = LT comparePrim _ (FP _ _) = GT comparePrim (ChangePref a1 b1 c1) (ChangePref a2 b2 c2) = compare (c1, b1, a1) (c2, b2, a2) darcs-2.8.4/src/Darcs/Patch/Prim/V1/Details.hs0000644001765600176560000000157612104371431020152 0ustar ganeshganesh{-# OPTIONS_GHC -fno-warn-orphans #-} module Darcs.Patch.Prim.V1.Details () where import Prelude hiding ( pi ) import Darcs.Patch.Prim.Class ( PrimDetails(..) ) import Darcs.Patch.Prim.V1.Core ( Prim(..), FilePatchType(..), DirPatchType(..) ) import Darcs.Patch.SummaryData ( SummDetail(..), SummOp(..) ) #include "gadts.h" instance PrimDetails Prim where summarizePrim (FP f (Hunk _ o n)) = [SummFile SummMod f (length o) (length n) 0] summarizePrim (FP f (Binary _ _)) = [SummFile SummMod f 0 0 0] summarizePrim (FP f AddFile) = [SummFile SummAdd f 0 0 0] summarizePrim (FP f RmFile) = [SummFile SummRm f 0 0 0] summarizePrim (FP f (TokReplace _ _ _)) = [SummFile SummMod f 0 0 1] summarizePrim (DP d AddDir) = [SummAddDir d] summarizePrim (DP d RmDir) = [SummRmDir d] summarizePrim (Move f1 f2) = [SummMv f1 f2] summarizePrim (ChangePref _ _ _) = [SummNone] darcs-2.8.4/src/Darcs/Patch/Prim/V1/Read.hs0000644001765600176560000001065612104371431017437 0ustar ganeshganesh{-# OPTIONS_GHC -fno-warn-orphans #-} module Darcs.Patch.Prim.V1.Read () where import Darcs.Patch.Prim.Class ( PrimRead(..), hunk, binary ) import Darcs.Patch.Prim.V1.Core ( Prim(..), DirPatchType(..), FilePatchType(..) ) import Darcs.Patch.FileName ( fn2fp ) import Darcs.Patch.Format ( FileNameFormat(..) ) import Darcs.Patch.Read ( ReadPatch(..), readFileName ) import Darcs.Patch.ReadMonads (ParserM, takeTillChar, string, int, option, choice, anyChar, char, myLex', skipSpace, skipWhile, linesStartingWith) import Darcs.Witnesses.Sealed ( seal ) import ByteStringUtils ( fromHex2PS ) import Control.Monad ( liftM ) import qualified Data.ByteString as B ( ByteString, init, tail, concat ) import qualified Data.ByteString.Char8 as BC ( unpack, pack ) #include "gadts.h" instance ReadPatch Prim where readPatch' = readPrim OldFormat instance PrimRead Prim where readPrim x = skipSpace >> choice [ return' $ readHunk x , return' $ readAddFile x , return' $ readAddDir x , return' $ readMove x , return' $ readRmFile x , return' $ readRmDir x , return' $ readTok x , return' $ readBinary x , return' $ readChangePref ] where return' = liftM seal hunk' :: B.ByteString hunk' = BC.pack "hunk" replace :: B.ByteString replace = BC.pack "replace" binary' :: B.ByteString binary' = BC.pack "binary" addfile :: B.ByteString addfile = BC.pack "addfile" adddir :: B.ByteString adddir = BC.pack "adddir" rmfile :: B.ByteString rmfile = BC.pack "rmfile" rmdir :: B.ByteString rmdir = BC.pack "rmdir" move :: B.ByteString move = BC.pack "move" changepref :: B.ByteString changepref = BC.pack "changepref" readHunk :: ParserM m => FileNameFormat -> m (Prim C(x y)) readHunk x = do string hunk' fi <- myLex' l <- int have_nl <- skipNewline if have_nl then do _ <- linesStartingWith ' ' -- skipping context old <- linesStartingWith '-' new <- linesStartingWith '+' _ <- linesStartingWith ' ' -- skipping context return $ hunk (fn2fp $ readFileName x fi) l old new else return $ hunk (fn2fp $ readFileName x fi) l [] [] skipNewline :: ParserM m => m Bool skipNewline = option False (char '\n' >> return True) readTok :: ParserM m => FileNameFormat -> m (Prim C(x y)) readTok x = do string replace f <- myLex' regstr <- myLex' o <- myLex' n <- myLex' return $ FP (readFileName x f) $ TokReplace (BC.unpack (drop_brackets regstr)) (BC.unpack o) (BC.unpack n) where drop_brackets = B.init . B.tail -- * Binary file modification -- -- | Modify a binary file -- -- > binary FILENAME -- > oldhex -- > *HEXHEXHEX -- > ... -- > newhex -- > *HEXHEXHEX -- > ... readBinary :: ParserM m => FileNameFormat -> m (Prim C(x y)) readBinary x = do string binary' fi <- myLex' _ <- myLex' skipSpace old <- linesStartingWith '*' _ <- myLex' skipSpace new <- linesStartingWith '*' return $ binary (fn2fp $ readFileName x fi) (fromHex2PS $ B.concat old) (fromHex2PS $ B.concat new) readAddFile :: ParserM m => FileNameFormat -> m (Prim C(x y)) readAddFile x = do string addfile f <- myLex' return $ FP (readFileName x f) AddFile readRmFile :: ParserM m => FileNameFormat -> m (Prim C(x y)) readRmFile x = do string rmfile f <- myLex' return $ FP (readFileName x f) RmFile readMove :: ParserM m => FileNameFormat -> m (Prim C(x y)) readMove x = do string move d <- myLex' d' <- myLex' return $ Move (readFileName x d) (readFileName x d') readChangePref :: ParserM m => m (Prim C(x y)) readChangePref = do string changepref p <- myLex' skipWhile (== ' ') _ <- anyChar -- skip newline f <- takeTillChar '\n' _ <- anyChar -- skip newline t <- takeTillChar '\n' return $ ChangePref (BC.unpack p) (BC.unpack f) (BC.unpack t) readAddDir :: ParserM m => FileNameFormat -> m (Prim C(x y)) readAddDir x = do string adddir f <- myLex' return $ DP (readFileName x f) AddDir readRmDir :: ParserM m => FileNameFormat -> m (Prim C(x y)) readRmDir x = do string rmdir f <- myLex' return $ DP (readFileName x f) RmDir darcs-2.8.4/src/Darcs/Patch/Prim/V1/Show.hs0000644001765600176560000001545212104371431017503 0ustar ganeshganesh{-# OPTIONS_GHC -fno-warn-orphans #-} {-# LANGUAGE ViewPatterns, UndecidableInstances #-} -- XXX Undecidable only in GHC < 7 module Darcs.Patch.Prim.V1.Show ( showHunk ) where import Prelude hiding ( pi ) import ByteStringUtils ( fromPS2Hex ) import qualified Data.ByteString as B (ByteString, length, take, drop) import qualified Data.ByteString.Char8 as BC (head) import Storage.Hashed.Tree( Tree ) import Darcs.Patch.FileHunk ( FileHunk(..), IsHunk(..), showFileHunk ) import Darcs.Patch.FileName ( FileName ) import Darcs.Patch.Format ( PatchListFormat, FileNameFormat(..) ) import Darcs.Patch.Show ( ShowPatchBasic(..), ShowPatch(..), formatFileName ) import Darcs.Patch.Apply( ApplyState ) import Darcs.Patch.Summary ( plainSummaryPrim, plainSummaryPrims ) import Darcs.Patch.Viewing ( showContextHunk ) import Darcs.Patch.Permutations () -- for Invert instance of FL import Darcs.Patch.Prim.Class ( PrimShow(..) ) import Darcs.Patch.Prim.V1.Core ( Prim(..), FilePatchType(..), DirPatchType(..) ) import Darcs.Patch.Prim.V1.Details () import Darcs.Witnesses.Show ( appPrec, Show1(..), Show2(..), ShowDict(..) ) import Printer ( Doc, vcat, text, userchunk, invisibleText, invisiblePS, blueText, ($$), (<+>), (<>), ) #include "gadts.h" -- TODO this instance shouldn't really be necessary, as Prims aren't used generically instance PatchListFormat Prim instance ShowPatchBasic Prim where showPatch = showPrim OldFormat instance (ApplyState Prim ~ Tree) => ShowPatch Prim where showContextPatch (isHunk -> Just fh) = showContextHunk fh showContextPatch p = return $ showPatch p summary = plainSummaryPrim summaryFL = plainSummaryPrims thing _ = "change" instance Show (Prim C(x y)) where showsPrec d (Move fn1 fn2) = showParen (d > appPrec) $ showString "Move " . showsPrec (appPrec + 1) fn1 . showString " " . showsPrec (appPrec + 1) fn2 showsPrec d (DP fn dp) = showParen (d > appPrec) $ showString "DP " . showsPrec (appPrec + 1) fn . showString " " . showsPrec (appPrec + 1) dp showsPrec d (FP fn fp) = showParen (d > appPrec) $ showString "FP " . showsPrec (appPrec + 1) fn . showString " " . showsPrec (appPrec + 1) fp showsPrec d (ChangePref p f t) = showParen (d > appPrec) $ showString "ChangePref " . showsPrec (appPrec + 1) p . showString " " . showsPrec (appPrec + 1) f . showString " " . showsPrec (appPrec + 1) t instance Show2 Prim where showDict2 = ShowDictClass instance Show1 (Prim C(x)) where showDict1 = ShowDictClass instance Show (FilePatchType C(x y)) where showsPrec _ RmFile = showString "RmFile" showsPrec _ AddFile = showString "AddFile" showsPrec d (Hunk line old new) | all ((==1) . B.length) old && all ((==1) . B.length) new = showParen (d > appPrec) $ showString "Hunk " . showsPrec (appPrec + 1) line . showString " " . showsPrecC old . showString " " . showsPrecC new where showsPrecC [] = showString "[]" showsPrecC ss = showParen True $ showString "packStringLetters " . showsPrec (appPrec + 1) (map BC.head ss) showsPrec d (Hunk line old new) = showParen (d > appPrec) $ showString "Hunk " . showsPrec (appPrec + 1) line . showString " " . showsPrec (appPrec + 1) old . showString " " . showsPrec (appPrec + 1) new showsPrec d (TokReplace t old new) = showParen (d > appPrec) $ showString "TokReplace " . showsPrec (appPrec + 1) t . showString " " . showsPrec (appPrec + 1) old . showString " " . showsPrec (appPrec + 1) new -- this case may not work usefully showsPrec d (Binary old new) = showParen (d > appPrec) $ showString "Binary " . showsPrec (appPrec + 1) old . showString " " . showsPrec (appPrec + 1) new instance Show (DirPatchType C(x y)) where showsPrec _ RmDir = showString "RmDir" showsPrec _ AddDir = showString "AddDir" {- instance Show (Prim C(x y)) where show p = renderString (showPrim p) ++ "\n" -} instance PrimShow Prim where showPrim x (FP f AddFile) = showAddFile x f showPrim x (FP f RmFile) = showRmFile x f showPrim x (FP f (Hunk line old new)) = showHunk x f line old new showPrim x (FP f (TokReplace t old new)) = showTok x f t old new showPrim x (FP f (Binary old new)) = showBinary x f old new showPrim x (DP d AddDir) = showAddDir x d showPrim x (DP d RmDir) = showRmDir x d showPrim x (Move f f') = showMove x f f' showPrim _ (ChangePref p f t) = showChangePref p f t showAddFile :: FileNameFormat -> FileName -> Doc showAddFile x f = blueText "addfile" <+> formatFileName x f showRmFile :: FileNameFormat -> FileName -> Doc showRmFile x f = blueText "rmfile" <+> formatFileName x f showMove :: FileNameFormat -> FileName -> FileName -> Doc showMove x d d' = blueText "move" <+> formatFileName x d <+> formatFileName x d' showChangePref :: String -> String -> String -> Doc showChangePref p f t = blueText "changepref" <+> text p $$ userchunk f $$ userchunk t showAddDir :: FileNameFormat -> FileName -> Doc showAddDir x d = blueText "adddir" <+> formatFileName x d showRmDir :: FileNameFormat -> FileName -> Doc showRmDir x d = blueText "rmdir" <+> formatFileName x d showHunk :: FileNameFormat -> FileName -> Int -> [B.ByteString] -> [B.ByteString] -> Doc showHunk x f line old new = showFileHunk x (FileHunk f line old new) showTok :: FileNameFormat -> FileName -> String -> String -> String -> Doc showTok x f t o n = blueText "replace" <+> formatFileName x f <+> text "[" <> userchunk t <> text "]" <+> userchunk o <+> userchunk n showBinary :: FileNameFormat -> FileName -> B.ByteString -> B.ByteString -> Doc showBinary x f o n = blueText "binary" <+> formatFileName x f $$ invisibleText "oldhex" $$ (vcat $ map makeprintable $ breakEvery 78 $ fromPS2Hex o) $$ invisibleText "newhex" $$ (vcat $ map makeprintable $ breakEvery 78 $ fromPS2Hex n) where makeprintable ps = invisibleText "*" <> invisiblePS ps breakEvery :: Int -> B.ByteString -> [B.ByteString] breakEvery n ps | B.length ps < n = [ps] | otherwise = B.take n ps : breakEvery n (B.drop n ps) darcs-2.8.4/src/Darcs/Patch/Prim/V3/0000755001765600176560000000000012104371431016222 5ustar ganeshganeshdarcs-2.8.4/src/Darcs/Patch/Prim/V3/ObjectMap.hs0000644001765600176560000000357112104371431020430 0ustar ganeshganesh-- Copyright (C) 2011 Petr Rockai -- -- 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. module Darcs.Patch.Prim.V3.ObjectMap( UUID(..), Location, Object(..), ObjectMap(..), DirContent ) where import Storage.Hashed.Hash( Hash ) import qualified Data.ByteString as BS (ByteString) import qualified Data.Map as M newtype UUID = UUID BS.ByteString deriving (Eq, Ord, Show) type Location = (UUID, BS.ByteString) type DirContent = M.Map BS.ByteString UUID data Object (m :: * -> *) = Directory DirContent | Blob (m BS.ByteString) !Hash data ObjectMap (m :: * -> *) = ObjectMap { getObject :: UUID -> m (Maybe (Object m)) , putObject :: UUID -> Object m -> m (ObjectMap m) , listObjects :: m [UUID] } darcs-2.8.4/src/Darcs/Patch/Prim/V3/Apply.hs0000644001765600176560000000457312104371431017654 0ustar ganeshganesh{-# LANGUAGE CPP, MultiParamTypeClasses, OverloadedStrings #-} {-# OPTIONS_GHC -fno-warn-orphans #-} module Darcs.Patch.Prim.V3.Apply ( ObjectMap(..) ) where import Darcs.Patch.Apply ( Apply(..) ) import Darcs.Patch.ApplyMonad ( ApplyMonad(..), ApplyMonadTrans(..), ToTree(..) ) import Darcs.Patch.Repair ( RepairToFL(..) ) import Darcs.Patch.Prim.Class ( PrimApply(..) ) import Darcs.Patch.Prim.V3.Core ( Prim(..), hunkEdit ) import Darcs.Patch.Prim.V3.ObjectMap import Control.Monad.State( StateT, runStateT, gets, lift, put ) import qualified Data.Map as M -- import Darcs.Patch.ApplyMonad ( ApplyMonad(..) ) import Darcs.Witnesses.Ordered ( FL(..) ) import Storage.Hashed.Hash( Hash(..) ) #include "gadts.h" #include "impossible.h" instance Apply Prim where type ApplyState Prim = ObjectMap apply (Manifest id (dirid, name)) = editDirectory dirid (M.insert name id) apply (Demanifest _ (dirid, name)) = editDirectory dirid (M.delete name) apply (TextHunk id hunk) = editFile id (hunkEdit hunk) apply (BinaryHunk id hunk) = editFile id (hunkEdit hunk) instance RepairToFL Prim where applyAndTryToFixFL p = apply p >> return Nothing instance PrimApply Prim where applyPrimFL NilFL = return () applyPrimFL (p:>:ps) = apply p >> applyPrimFL ps instance ToTree ObjectMap -- TODO editObject :: (Monad m) => UUID -> (Maybe (Object m) -> Object m) -> (StateT (ObjectMap m) m) () editObject id edit = do load <- gets getObject store <- gets putObject obj <- lift $ load id new <- lift $ store id $ edit obj put new return () instance (Functor m, Monad m) => ApplyMonad (StateT (ObjectMap m) m) ObjectMap where type ApplyMonadBase (StateT (ObjectMap m) m) = m editFile id edit = editObject id edit' where edit' (Just (Blob x _)) = Blob (edit `fmap` x) NoHash edit' (Just (Directory x)) = Directory x -- error? edit' Nothing = Blob (return $ edit "") NoHash editDirectory id edit = editObject id edit' where edit' (Just (Directory x)) = Directory $ edit x edit' (Just (Blob x y)) = Blob x y -- error? edit' Nothing = Directory $ edit M.empty instance (Functor m, Monad m) => ApplyMonadTrans m ObjectMap where type ApplyMonadOver m ObjectMap = StateT (ObjectMap m) m runApplyMonad = runStateT darcs-2.8.4/src/Darcs/Patch/Prim/V3/Coalesce.hs0000644001765600176560000000074612104371431020303 0ustar ganeshganesh{-# OPTIONS_GHC -fno-warn-orphans #-} module Darcs.Patch.Prim.V3.Coalesce () where import Darcs.Patch.Prim.Class ( PrimCanonize(..) ) import Darcs.Witnesses.Ordered( FL(..) ) import Darcs.Patch.Prim.V3.Core( Prim ) #include "gadts.h" #include "impossible.h" -- TODO instance PrimCanonize Prim where tryToShrink = error "tryToShrink" tryShrinkingInverse _ = error "tryShrinkingInverse" sortCoalesceFL = id canonize = (:>: NilFL) canonizeFL = id join = const Nothing darcs-2.8.4/src/Darcs/Patch/Prim/V3/Commute.hs0000644001765600176560000000550412104371431020173 0ustar ganeshganesh{-# OPTIONS_GHC -fno-warn-orphans #-} module Darcs.Patch.Prim.V3.Commute ( CommuteMonad(..) ) where import Data.List ( intersect ) import qualified Data.ByteString as BS (length) import Darcs.Witnesses.Ordered ( (:>)(..) ) import Darcs.Witnesses.Unsafe ( unsafeCoerceP ) import Darcs.Patch.Prim.V3.Core ( Prim(..), Hunk(..), touches ) import Darcs.Patch.Commute ( Commute(..) ) import Darcs.Patch.Permutations () -- for Invert instance of FL #include "impossible.h" #include "gadts.h" class Monad m => CommuteMonad m where commuteFail :: m a -- TODO we eventually have to get rid of runCommute with this signature, -- since m might involve IO at some point, which we can't "run"; -- alternatively, for IO it could always yield Nothing, having a separate -- IO-specific function to "run" commutes in IO instance CommuteMonad Maybe where commuteFail = Nothing instance Commute Prim where commute = commute' class Commute' p where commute' :: (CommuteMonad m) => (p :> p) wX wY -> m ((p :> p) wX wY) typematch :: Prim wX wY -> Prim wY wZ -> Bool typematch _ _ = True -- TODO instance Commute' Prim where commute' (a :> b) | null (touches a `intersect` touches b) = return (unsafeCoerceP b :> unsafeCoerceP a) | not (a `typematch` b) = commuteFail | otherwise = commuteOverlapping (a :> b) -- Commute patches that have actual overlap in terms of touched objects, and their types allow commuteOverlapping :: (CommuteMonad m) => (Prim :> Prim) wX wY -> m ((Prim :> Prim) wX wY) commuteOverlapping ((BinaryHunk a x) :> (BinaryHunk _ y)) = do (y' :> x') <- commuteHunk (x :> y) return $ unsafeCoerceP (BinaryHunk a y' :> BinaryHunk a x') commuteOverlapping ((TextHunk a x) :> (TextHunk _ y)) = do (y' :> x') <- commuteHunk (x :> y) return $ unsafeCoerceP (TextHunk a y' :> TextHunk a x') commuteOverlapping _ = commuteFail commuteHunk :: (CommuteMonad m) => (Hunk :> Hunk) C(x y) -> m ((Hunk :> Hunk) C(y x)) commuteHunk ((Hunk off1 old1 new1) :> (Hunk off2 old2 new2)) | off1 + lengthnew1 < off2 = return $ Hunk (off2 - lengthnew1 + lengthold1) old2 new2 :> Hunk off1 old1 new1 | off2 + lengthold2 < off1 = return $ (Hunk off2 old2 new2) :> Hunk (off1 + lengthnew2 - lengthold2) old1 new1 | off1 + lengthnew1 == off2 && lengthold2 /= 0 && lengthold1 /= 0 && lengthnew2 /= 0 && lengthnew1 /= 0 = return $ Hunk (off2 - lengthnew1 + lengthold1) old2 new2 :> Hunk off1 old1 new1 | off2 + lengthold2 == off1 && lengthold2 /= 0 && lengthold1 /= 0 && lengthnew2 /= 0 && lengthnew1 /= 0 = return $ Hunk off2 old2 new2 :> Hunk (off1 + lengthnew2 - lengthold2) old1 new1 | otherwise = commuteFail where lengthnew1 = BS.length new1 lengthnew2 = BS.length new2 lengthold1 = BS.length old1 lengthold2 = BS.length old2 commuteHunk _ = impossible darcs-2.8.4/src/Darcs/Patch/Prim/V3/Core.hs0000644001765600176560000001173412104371431017454 0ustar ganeshganesh{-# LANGUAGE CPP, OverloadedStrings #-} -- Copyright (C) 2011 Petr Rockai -- -- 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. #include "gadts.h" module Darcs.Patch.Prim.V3.Core ( Prim(..), Hunk(..), UUID(..), Location, Object(..), touches, hunkEdit ) where import qualified Data.ByteString as BS import Darcs.Witnesses.Eq ( MyEq(..) ) import Darcs.Patch.FileHunk( IsHunk(..) ) import Darcs.Patch.Invert ( Invert(..) ) import Darcs.Patch.Inspect ( PatchInspect(..) ) import Darcs.Patch.Prim.Class ( PrimConstruct(..), PrimClassify(..) ) import Darcs.Patch.Prim.V3.ObjectMap -- TODO: elaborate data Hunk C(x y) where Hunk :: !Int -> BS.ByteString -> BS.ByteString -> Hunk C(x y) invertHunk :: Hunk C(x y) -> Hunk C(y x) invertHunk (Hunk off old new) = Hunk off new old hunkEdit :: Hunk C(x y) -> BS.ByteString -> BS.ByteString hunkEdit (Hunk off old new) bs = case splice bs (off) (off + BS.length old) of x | x == old -> BS.concat [ BS.take off bs, new, BS.drop (off + BS.length old) bs ] | otherwise -> error $ "error applying hunk: " ++ show off ++ " " ++ show old ++ " " ++ show new ++ " to " ++ show bs where splice bs' x y = BS.drop x $ BS.take y bs' instance MyEq Hunk where unsafeCompare (Hunk i x y) (Hunk i' x' y') = i == i' && x == x' && y == y' data Prim C(x y) where BinaryHunk :: !UUID -> Hunk C(x y) -> Prim C(x y) TextHunk :: !UUID -> Hunk C(x y) -> Prim C(x y) -- TODO: String is not the right type here. However, what it represents is -- a single file *name* (not a path). No slashes allowed, no "." and ".." -- allowed either. Manifest :: !UUID -> Location -> Prim C(x y) Demanifest :: !UUID -> Location -> Prim C(x y) Move :: !UUID -> Location -> Location -> Prim C(x y) Identity :: Prim C(x x) touches :: Prim C(x y) -> [UUID] touches (BinaryHunk x _) = [x] touches (TextHunk x _) = [x] touches (Manifest _ (x, _)) = [x] touches (Demanifest _ (x, _)) = [x] touches (Move _ (x, _) (y, _)) = [x, y] touches Identity = [] -- TODO: PrimClassify doesn't make sense for V3 prims instance PrimClassify Prim where primIsAddfile _ = False primIsRmfile _ = False primIsAdddir _ = False primIsRmdir _ = False primIsHunk _ = False primIsMove _ = False primIsBinary _ = False primIsTokReplace _ = False primIsSetpref _ = False is_filepatch _ = Nothing -- TODO: PrimConstruct makes no sense for V3 prims instance PrimConstruct Prim where addfile _ = error "PrimConstruct addfile" rmfile _ = error "PrimConstruct rmfile" adddir _ = error "PrimConstruct adddir" rmdir _ = error "PrimConstruct rmdir" move _ _ = error "PrimConstruct move" changepref _ _ _ = error "PrimConstruct changepref" hunk _ _ _ _ = error "PrimConstruct hunk" tokreplace _ _ _ _ = error "PrimConstruct tokreplace" binary _ _ _ = error "PrimConstruct binary" primFromHunk _ = error "PrimConstruct primFromHunk" anIdentity = Identity instance IsHunk Prim where isHunk _ = Nothing instance Invert Prim where invert (BinaryHunk x h) = BinaryHunk x $ invertHunk h invert (TextHunk x h) = TextHunk x $ invertHunk h invert (Manifest x y) = Demanifest x y invert (Demanifest x y) = Manifest x y invert (Move x y z) = Move x z y invert Identity = Identity instance PatchInspect Prim where -- We don't need this for V3. Slashes are not allowed in Manifest and -- Demanifest patches and nothing else uses working-copy paths. listTouchedFiles _ = [] -- TODO (used for --match 'hunk ...', presumably) hunkMatches _ _ = False instance MyEq Prim where unsafeCompare (BinaryHunk a b) (BinaryHunk c d) = a == c && b `unsafeCompare` d unsafeCompare (TextHunk a b) (TextHunk c d) = a == c && b `unsafeCompare` d unsafeCompare (Manifest a b) (Manifest c d) = a == c && b == d unsafeCompare (Demanifest a b) (Demanifest c d) = a == c && b == d unsafeCompare Identity Identity = True unsafeCompare _ _ = False instance Eq (Prim C(x y)) where (==) = unsafeCompare darcs-2.8.4/src/Darcs/Patch/Prim/V3/Details.hs0000644001765600176560000000041612104371431020144 0ustar ganeshganesh{-# OPTIONS_GHC -fno-warn-orphans #-} module Darcs.Patch.Prim.V3.Details () where import Darcs.Patch.Prim.Class ( PrimDetails(..) ) import Darcs.Patch.Prim.V3.Core ( Prim(..) ) #include "gadts.h" -- TODO instance PrimDetails Prim where summarizePrim _ = [] darcs-2.8.4/src/Darcs/Patch/Prim/V3/Read.hs0000644001765600176560000000402512104371431017432 0ustar ganeshganesh{-# LANGUAGE ViewPatterns, OverloadedStrings #-} {-# OPTIONS_GHC -fno-warn-orphans #-} module Darcs.Patch.Prim.V3.Read () where import Darcs.Patch.Read ( ReadPatch(..) ) import Darcs.Patch.ReadMonads import Darcs.Patch.Prim.Class( PrimRead(..) ) import Darcs.Patch.Prim.V3.Core( Prim(..), Hunk(..) ) import Darcs.Patch.Prim.V3.ObjectMap import Darcs.Witnesses.Sealed( seal ) import Control.Applicative ( (<$>) ) import Control.Monad ( liftM, liftM2 ) import qualified Data.ByteString as B import qualified Data.ByteString.Char8 as BC import Data.Char ( chr ) instance PrimRead Prim where readPrim _ = do skipSpace choice $ map (liftM seal) [ identity, hunk "hunk" TextHunk, hunk "binhunk" BinaryHunk, manifest "manifest" Manifest, manifest "demanifest" Demanifest ] where manifest kind ctor = liftM2 ctor (patch kind) location identity = lexString "identity" >> return Identity patch x = string x >> uuid uuid = UUID <$> myLex' filename = encoded encoded = decodeWhite <$> myLex' hunktext = skipSpace >> choice [ string "." >> encoded, string "!" >> return B.empty ] location = liftM2 (,) uuid filename hunk kind ctor = do uid <- patch kind offset <- int old <- hunktext new <- hunktext return $ ctor uid (Hunk offset old new) instance ReadPatch Prim where readPatch' = readPrim undefined -- XXX a bytestring version of decodeWhite from Darcs.FileName decodeWhite :: B.ByteString -> B.ByteString decodeWhite (BC.uncons -> Just ('\\', cs)) = case BC.break (=='\\') cs of (theord, BC.uncons -> Just ('\\', rest)) -> chr (read $ BC.unpack theord) `BC.cons` decodeWhite rest _ -> error "malformed filename" decodeWhite (BC.uncons -> Just (c, cs)) = c `BC.cons` decodeWhite cs decodeWhite (BC.uncons -> Nothing) = BC.empty darcs-2.8.4/src/Darcs/Patch/Prim/V3/Show.hs0000644001765600176560000000530312104371431017477 0ustar ganeshganesh{-# OPTIONS_GHC -fno-warn-orphans #-} {-# LANGUAGE ViewPatterns, OverloadedStrings #-} module Darcs.Patch.Prim.V3.Show ( showHunk ) where import Prelude hiding ( pi ) import Data.Char ( isSpace, ord ) import qualified Data.ByteString as B import qualified Data.ByteString.Char8 as BC import Darcs.Patch.Format ( PatchListFormat, FileNameFormat(..) ) import Darcs.Patch.Show ( ShowPatchBasic(..), ShowPatch(..) ) import Darcs.Patch.Summary ( plainSummaryPrim, plainSummaryPrims ) import Darcs.Patch.Prim.Class ( PrimShow(..) ) import Darcs.Patch.Prim.V3.Core ( Prim(..), Hunk(..), UUID(..) ) import Darcs.Patch.Prim.V3.Details () import Darcs.Witnesses.Show ( Show1(..), Show2(..), ShowDict(..) ) import Printer ( renderString, text, packedString, blueText, (<+>), (<>), Doc ) #include "gadts.h" -- TODO this instance shouldn't really be necessary, as Prims aren't used generically instance PatchListFormat Prim instance ShowPatchBasic Prim where showPatch = showPrim OldFormat instance ShowPatch Prim where showContextPatch p = return $ showPatch p summary = plainSummaryPrim summaryFL = plainSummaryPrims thing _ = "change" instance Show (Prim C(x y)) where show = renderString . showPrim undefined instance Show2 Prim where showDict2 = ShowDictClass instance Show1 (Prim C(x)) where showDict1 = ShowDictClass instance PrimShow Prim where showPrim _ (TextHunk u h) = showHunk "hunk" u h showPrim _ (BinaryHunk u h) = showHunk "binhunk" u h showPrim _ (Manifest f (d,p)) = showManifest "manifest" d f p showPrim _ (Demanifest f (d,p)) = showManifest "demanifest" d f p showPrim _ Identity = blueText "identity" showManifest :: String -> UUID -> UUID -> BC.ByteString -> Doc showManifest txt dir file path = blueText txt <+> formatUUID file <+> formatUUID dir <+> packedString (encodeWhite path) showHunk :: String -> UUID -> Hunk C(x y) -> Doc showHunk txt uid (Hunk off old new) = blueText txt <+> formatUUID uid <+> text (show off) <+> hunktext old <+> hunktext new where hunktext bit | B.null bit = text "!" | otherwise = text "." <> packedString (encodeWhite bit) formatUUID :: UUID -> Doc formatUUID (UUID x) = packedString x -- XXX a bytestring version of encodeWhite from Darcs.FileName encodeWhite :: B.ByteString -> B.ByteString encodeWhite = BC.concatMap encode where encode c | isSpace c || c == '\\' = B.concat [ "\\", BC.pack $ show $ ord c, "\\" ] | otherwise = BC.singleton c darcs-2.8.4/src/Darcs/Patch/Prim/Class.hs0000644001765600176560000001157312104371431017342 0ustar ganeshganeshmodule Darcs.Patch.Prim.Class ( PrimConstruct(..), PrimCanonize(..) , PrimClassify(..), PrimDetails(..) , PrimShow(..), showPrimFL, PrimRead(..) , PrimApply(..) , PrimPatch, PrimPatchBase(..) , FromPrim(..), FromPrims(..), ToFromPrim(..) ) where import Darcs.Patch.ApplyMonad ( ApplyMonad ) import Darcs.Patch.Apply( ApplyState ) import Darcs.Patch.FileHunk ( FileHunk, IsHunk ) import Darcs.Patch.FileName ( FileName ) import Darcs.Patch.Format ( PatchListFormat, FileNameFormat(..) ) import Darcs.Patch.Patchy ( Patchy ) import Darcs.Patch.ReadMonads ( ParserM ) import Darcs.Patch.Repair ( RepairToFL ) import Darcs.Patch.SummaryData ( SummDetail ) import Darcs.Witnesses.Ordered ( FL(..), RL, (:>), mapFL, mapFL_FL, concatFL, reverseFL, concatRL ) import Darcs.Witnesses.Sealed ( Sealed ) import Printer ( Doc, vcat ) import qualified Data.ByteString as B ( ByteString ) #include "gadts.h" class (Patchy prim, PatchListFormat prim, IsHunk prim, RepairToFL prim ,PrimConstruct prim, PrimCanonize prim ,PrimClassify prim, PrimDetails prim ,PrimShow prim, PrimRead prim, PrimApply prim ) => PrimPatch prim class PrimPatch (PrimOf p) => PrimPatchBase p where type PrimOf (p :: PATCHKIND) :: PATCHKIND instance PrimPatchBase p => PrimPatchBase (FL p) where type PrimOf (FL p) = PrimOf p instance PrimPatchBase p => PrimPatchBase (RL p) where type PrimOf (RL p) = PrimOf p class FromPrim p where fromPrim :: PrimOf p C(x y) -> p C(x y) class FromPrim p => ToFromPrim p where toPrim :: p C(x y) -> Maybe (PrimOf p C(x y)) class FromPrims p where fromPrims :: FL (PrimOf p) C(x y) -> p C(x y) joinPatches :: FL p C(x y) -> p C(x y) instance FromPrim p => FromPrim (FL p) where fromPrim p = fromPrim p :>: NilFL instance FromPrim p => FromPrims (FL p) where fromPrims = mapFL_FL fromPrim joinPatches = concatFL instance FromPrim p => FromPrims (RL p) where fromPrims = reverseFL . mapFL_FL fromPrim joinPatches = concatRL . reverseFL class PrimClassify prim where primIsAddfile :: prim C(x y) -> Bool primIsRmfile :: prim C(x y) -> Bool primIsAdddir :: prim C(x y) -> Bool primIsRmdir :: prim C(x y) -> Bool primIsMove :: prim C(x y) -> Bool primIsHunk :: prim C(x y) -> Bool primIsTokReplace :: prim C(x y) -> Bool primIsBinary :: prim C(x y) -> Bool primIsSetpref :: prim C(x y) -> Bool is_filepatch :: prim C(x y) -> Maybe FileName class PrimConstruct prim where addfile :: FilePath -> prim C(x y) rmfile :: FilePath -> prim C(x y) adddir :: FilePath -> prim C(x y) rmdir :: FilePath -> prim C(x y) move :: FilePath -> FilePath -> prim C(x y) changepref :: String -> String -> String -> prim C(x y) hunk :: FilePath -> Int -> [B.ByteString] -> [B.ByteString] -> prim C(x y) tokreplace :: FilePath -> String -> String -> String -> prim C(x y) binary :: FilePath -> B.ByteString -> B.ByteString -> prim C(x y) primFromHunk :: FileHunk C(x y) -> prim C(x y) anIdentity :: prim C(x x) class PrimCanonize prim where tryToShrink :: FL prim C(x y) -> FL prim C(x y) tryShrinkingInverse :: FL prim C(x y) -> Maybe (FL prim C(x y)) -- | 'sortCoalesceFL' @ps@ coalesces as many patches in @ps@ as -- possible, sorting the results in some standard order. sortCoalesceFL :: FL prim C(x y) -> FL prim C(x y) -- | It can sometimes be handy to have a canonical representation of a given -- patch. We achieve this by defining a canonical form for each patch type, -- and a function 'canonize' which takes a patch and puts it into -- canonical form. This routine is used by the diff function to create an -- optimal patch (based on an LCS algorithm) from a simple hunk describing the -- old and new version of a file. canonize :: prim C(x y) -> FL prim C(x y) -- | 'canonizeFL' @ps@ puts a sequence of primitive patches into -- canonical form. Even if the patches are just hunk patches, -- this is not necessarily the same set of results as you would get -- if you applied the sequence to a specific tree and recalculated -- a diff. -- -- Note that this process does not preserve the commutation behaviour -- of the patches and is therefore not appropriate for use when -- working with already recorded patches (unless doing amend-record -- or the like). canonizeFL :: FL prim C(x y) -> FL prim C(x y) join :: (prim :> prim) C(x y) -> Maybe (FL prim C(x y)) class PrimDetails prim where summarizePrim :: prim C(x y) -> [SummDetail] class PrimShow prim where showPrim :: FileNameFormat -> prim C(a b) -> Doc showPrimFL :: PrimShow prim => FileNameFormat -> FL prim C(a b) -> Doc showPrimFL f xs = vcat (mapFL (showPrim f) xs) class PrimRead prim where readPrim :: ParserM m => FileNameFormat -> m (Sealed (prim C(x ))) class PrimApply prim where applyPrimFL :: ApplyMonad m (ApplyState prim) => FL prim C(x y) -> m () darcs-2.8.4/src/Darcs/Patch/Prim/V1.hs0000644001765600176560000000114212104371431016552 0ustar ganeshganesh{-# OPTIONS_GHC -fno-warn-orphans #-} module Darcs.Patch.Prim.V1 ( Prim ) where import Darcs.Patch.Prim.V1.Apply () import Darcs.Patch.Prim.V1.Coalesce () import Darcs.Patch.Prim.V1.Commute () import Darcs.Patch.Prim.V1.Core ( Prim ) import Darcs.Patch.Prim.V1.Details () import Darcs.Patch.Prim.V1.Read () import Darcs.Patch.Prim.V1.Show () import Darcs.Patch.Prim.Class ( PrimPatch, PrimPatchBase(..), FromPrim(..) ) import Darcs.Patch.Patchy ( Patchy ) instance PrimPatch Prim instance Patchy Prim instance PrimPatchBase Prim where type PrimOf Prim = Prim instance FromPrim Prim where fromPrim = id darcs-2.8.4/src/Darcs/Patch/Prim/V3.hs0000644001765600176560000000114312104371431016555 0ustar ganeshganesh{-# OPTIONS_GHC -fno-warn-orphans #-} module Darcs.Patch.Prim.V3 ( Prim ) where import Darcs.Patch.Prim.V3.Apply () import Darcs.Patch.Prim.V3.Coalesce () import Darcs.Patch.Prim.V3.Commute () import Darcs.Patch.Prim.V3.Core ( Prim ) import Darcs.Patch.Prim.V3.Details () import Darcs.Patch.Prim.V3.Read () import Darcs.Patch.Prim.V3.Show () import Darcs.Patch.Prim.Class ( PrimPatch, PrimPatchBase(..), FromPrim(..) ) import Darcs.Patch.Patchy ( Patchy ) instance PrimPatch Prim instance Patchy Prim instance PrimPatchBase Prim where type PrimOf Prim = Prim instance FromPrim Prim where fromPrim = id darcs-2.8.4/src/Darcs/Patch/V1/0000755001765600176560000000000012104371431015311 5ustar ganeshganeshdarcs-2.8.4/src/Darcs/Patch/V1/Apply.hs0000644001765600176560000000147212104371431016736 0ustar ganeshganesh{-# OPTIONS_GHC -fno-warn-orphans #-} module Darcs.Patch.V1.Apply () where import Darcs.Patch.Apply ( Apply, apply ) import Darcs.Patch.Prim ( PrimPatch, applyPrimFL ) import Darcs.Patch.Repair ( RepairToFL, applyAndTryToFixFL, mapMaybeSnd ) import Darcs.Patch.Effect ( effect ) import Darcs.Patch.V1.Commute () import Darcs.Patch.V1.Core ( Patch(..) ) import Darcs.Patch.Apply( ApplyState ) import Darcs.Witnesses.Ordered ( mapFL_FL ) #include "gadts.h" instance PrimPatch prim => Apply (Patch prim) where type ApplyState (Patch prim) = ApplyState prim apply p = applyPrimFL $ effect p instance PrimPatch prim => RepairToFL (Patch prim) where applyAndTryToFixFL (PP x) = mapMaybeSnd (mapFL_FL PP) `fmap` applyAndTryToFixFL x applyAndTryToFixFL x = do apply x; return Nothing darcs-2.8.4/src/Darcs/Patch/V1/Commute.hs0000644001765600176560000004654312104371431017272 0ustar ganeshganesh-- Copyright (C) 2002-2003 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# OPTIONS_GHC -fno-warn-orphans #-} {-# LANGUAGE CPP #-} #include "gadts.h" module Darcs.Patch.V1.Commute ( merge, merger, unravel, publicUnravel, ) where import Control.Monad ( MonadPlus, mplus, msum, mzero, guard ) import Darcs.Patch.Commute ( toFwdCommute ) import Darcs.Patch.ConflictMarking ( mangleUnravelled ) import Darcs.Patch.FileName ( FileName ) import Darcs.Patch.Invert ( invertRL ) import Darcs.Patch.Merge ( Merge(..) ) import Darcs.Patch.Patchy ( Commute(..), PatchInspect(..), Invert(..) ) import Darcs.Patch.V1.Core ( Patch(..), isMerger, mergerUndo ) import Darcs.Patch.Conflict ( Conflict(..), CommuteNoConflicts(..) ) import Darcs.Patch.Effect ( Effect(..) ) import Darcs.Patch.FileHunk ( IsHunk(..) ) import Darcs.Patch.Prim ( FromPrim(..), PrimPatch, is_filepatch, sortCoalesceFL, ) import Darcs.Patch.Permutations ( headPermutationsRL, simpleHeadPermutationsFL, commuterIdFL, commuterFLId, selfCommuter ) import Printer ( text, vcat, ($$) ) import Darcs.Patch.V1.Show ( showPatch_ ) import Data.List ( nub, nubBy ) import Darcs.Witnesses.Sealed ( unsafeUnseal, unsafeUnsealFlipped ) import Darcs.Utils ( nubsort ) #include "impossible.h" import Darcs.Witnesses.Sealed ( Sealed(..), mapSeal, unseal, FlippedSeal(..), mapFlipped ) import Darcs.Witnesses.Eq ( EqCheck(..), MyEq(..) ) import Darcs.Witnesses.Unsafe ( unsafeCoerceP, unsafeCoercePStart , unsafeCoercePEnd ) import Darcs.Witnesses.Ordered ( mapFL_FL, FL(..), RL(..), (:/\:)(..), (:<)(..), (:\/:)(..), (:>)(..), lengthFL, mapRL, reverseFL, reverseRL, concatFL ) --import Darcs.ColorPrinter ( traceDoc ) --import Printer ( greenText ) data Perhaps a = Unknown | Failed | Succeeded a instance Monad Perhaps where (Succeeded x) >>= k = k x Failed >>= _ = Failed Unknown >>= _ = Unknown Failed >> _ = Failed (Succeeded _) >> k = k Unknown >> k = k return = Succeeded fail _ = Unknown instance MonadPlus Perhaps where mzero = Unknown Unknown `mplus` ys = ys Failed `mplus` _ = Failed (Succeeded x) `mplus` _ = Succeeded x toMaybe :: Perhaps a -> Maybe a toMaybe (Succeeded x) = Just x toMaybe _ = Nothing toPerhaps :: Maybe a -> Perhaps a toPerhaps (Just x) = Succeeded x toPerhaps Nothing = Failed cleverCommute :: Invert prim => CommuteFunction prim -> CommuteFunction prim cleverCommute c (p1: Succeeded x Failed -> Failed Unknown -> case c (invert p2 :< invert p1) of Succeeded (p1' :< p2') -> Succeeded (invert p2' :< invert p1') Failed -> Failed Unknown -> Unknown speedyCommute :: PrimPatch prim => CommuteFunction prim speedyCommute (p1 :< p2) -- Deal with common case quickly! | p1_modifies /= Nothing && p2_modifies /= Nothing && p1_modifies /= p2_modifies = Succeeded (unsafeCoerceP p2 :< unsafeCoerceP p1) | otherwise = Unknown where p1_modifies = isFilepatchMerger p1 p2_modifies = isFilepatchMerger p2 everythingElseCommute :: forall prim . PrimPatch prim => CommuteFunction prim everythingElseCommute x = eec x where eec :: CommuteFunction prim eec (PP px :< PP py) = toPerhaps $ do x' :> y' <- commute (py :> px) return (PP y' :< PP x') eec _xx = msum [ cleverCommute commuteRecursiveMerger _xx ,cleverCommute otherCommuteRecursiveMerger _xx ] {- Note that it must be true that commutex (A^-1 A, P) = Just (P, A'^-1 A') and if commutex (A, B) == Just (B', A') then commutex (B^-1, A^-1) == Just (A'^-1, B'^-1) -} unsafeMerger :: PrimPatch prim => String -> Patch prim C(x y) -> Patch prim C(x z) -> Patch prim C(a b) unsafeMerger x p1 p2 = unsafeCoercePStart $ unsafeUnseal $ merger x p1 p2 mergerCommute :: PrimPatch prim => (Patch prim :< Patch prim) C(x y) -> Perhaps ((Patch prim :< Patch prim) C(x y)) mergerCommute (Merger _ _ p1 p2 :< pA) | unsafeCompare pA p1 = Succeeded (unsafeMerger "0.0" p2 p1 :< unsafeCoercePStart p2) | unsafeCompare pA (invert (unsafeMerger "0.0" p2 p1)) = Failed mergerCommute (Merger _ _ (Merger _ _ c b) (Merger _ _ c' a) :< Merger _ _ b' c'') | unsafeCompare b' b && unsafeCompare c c' && unsafeCompare c c'' = Succeeded (unsafeMerger "0.0" (unsafeMerger "0.0" b (unsafeCoercePStart a)) (unsafeMerger "0.0" b c) :< unsafeMerger "0.0" b (unsafeCoercePStart a)) mergerCommute _ = Unknown instance PrimPatch prim => Merge (Patch prim) where merge (y :\/: z) = case actualMerge (y:\/:z) of Sealed y' -> case commute (z :> y') of Nothing -> bugDoc $ text "merge_patches bug" $$ showPatch_ y $$ showPatch_ z $$ showPatch_ y' Just (_ :> z') -> -- actualMerge returns one arm of a -- merge result, so commuting then gives -- us the other arm but we have to assert -- that the starting context is correct unsafeCoercePStart z' :/\: y' instance PrimPatch prim => Commute (Patch prim) where commute x = toMaybe $ msum [toFwdCommute speedyCommute x, toFwdCommute (cleverCommute mergerCommute) x, toFwdCommute everythingElseCommute x ] instance PrimPatch prim => PatchInspect (Patch prim) where -- Recurse on everything, these are potentially spoofed patches listTouchedFiles (Merger _ _ p1 p2) = nubsort $ listTouchedFiles p1 ++ listTouchedFiles p2 listTouchedFiles c@(Regrem _ _ _ _) = listTouchedFiles $ invert c listTouchedFiles (PP p) = listTouchedFiles p hunkMatches f (Merger _ _ p1 p2) = hunkMatches f p1 || hunkMatches f p2 hunkMatches f c@(Regrem _ _ _ _) = hunkMatches f $ invert c hunkMatches f (PP p) = hunkMatches f p commuteNoMerger :: PrimPatch prim => MaybeCommute prim commuteNoMerger x = toMaybe $ msum [speedyCommute x, everythingElseCommute x] isFilepatchMerger :: PrimPatch prim => Patch prim C(x y) -> Maybe FileName isFilepatchMerger (PP p) = is_filepatch p isFilepatchMerger (Merger _ _ p1 p2) = do f1 <- isFilepatchMerger p1 f2 <- isFilepatchMerger p2 if f1 == f2 then return f1 else Nothing isFilepatchMerger (Regrem und unw p1 p2) = isFilepatchMerger (Merger und unw p1 p2) commuteRecursiveMerger :: PrimPatch prim => (Patch prim :< Patch prim) C(x y) -> Perhaps ((Patch prim :< Patch prim) C(x y)) commuteRecursiveMerger (p@(Merger _ _ p1 p2) :< pA) = toPerhaps $ do (_ :> pA') <- commuterIdFL selfCommuter (pA :> undo) _ <- commuterIdFL selfCommuter (pA' :> invert undo) (_ :> pAmid) <- commute (pA :> unsafeCoercePStart (invert p1)) (p1' :> pAx) <- commute (pAmid :> p1) guard (pAx `unsafeCompare` pA) (p2' :> _) <- commute (pAmid :> p2) (p2o :> _) <- commute (invert pAmid :> p2') guard (p2o `unsafeCompare` p2) let p' = if unsafeCompare p1' p1 && unsafeCompare p2' p2 then unsafeCoerceP p else unsafeMerger "0.0" p1' p2' undo' = mergerUndo p' (pAo :> _) <- commuterFLId selfCommuter (undo' :> pA') guard (pAo `unsafeCompare` pA) return (pA' :< p') where undo = mergerUndo p commuteRecursiveMerger _ = Unknown otherCommuteRecursiveMerger :: PrimPatch prim => (Patch prim :< Patch prim) C(x y) -> Perhaps ((Patch prim :< Patch prim) C(x y)) otherCommuteRecursiveMerger (pA':< p_old@(Merger _ _ p1' p2')) = toPerhaps $ do (pA :> _) <- commuterFLId selfCommuter (mergerUndo p_old :> pA') (pAmid :> p1) <- commute (unsafeCoercePEnd p1' :> pA) (_ :> pAmido) <- commute (pA :> invert p1) guard (pAmido `unsafeCompare` pAmid) (p2 :> _) <- commute (invert pAmid :> p2') (p2o' :> _) <- commute (pAmid :> p2) guard (p2o' `unsafeCompare` p2') let p = if p1 `unsafeCompare` p1' && p2 `unsafeCompare` p2' then unsafeCoerceP p_old else unsafeMerger "0.0" p1 p2 undo = mergerUndo p guard (not $ pA `unsafeCompare` p1) -- special case here... (_ :> pAo') <- commuterIdFL selfCommuter (pA :> undo) guard (pAo' `unsafeCompare` pA') return (p :< pA) otherCommuteRecursiveMerger _ = Unknown type CommuteFunction prim = FORALL(x y) (Patch prim :< Patch prim) C(x y) -> Perhaps ((Patch prim :< Patch prim) C(x y)) type MaybeCommute prim = FORALL(x y) (Patch prim :< Patch prim) C(x y) -> Maybe ((Patch prim :< Patch prim) C(x y)) revCommuteFLId :: MaybeCommute prim -> (FL (Patch prim) :< Patch prim) C(x y) -> Maybe ((Patch prim :< FL (Patch prim)) C(x y)) revCommuteFLId _ (NilFL :< p) = return (p :< NilFL) revCommuteFLId commuter ((q :>: qs) :< p) = do p' :< q' <- commuter (q :< p) p'' :< qs' <- revCommuteFLId commuter (qs :< p') return (p'' :< (q' :>: qs')) elegantMerge :: PrimPatch prim => (Patch prim :\/: Patch prim) C(x y) -> Maybe ((Patch prim :/\: Patch prim) C(x y)) elegantMerge (p1 :\/: p2) = do p1' :> ip2' <- commute (invert p2 :> p1) p1o :> _ <- commute (p2 :> p1') guard $ unsafeCompare p1o p1 -- should be a redundant check return $ invert ip2' :/\: p1' {- A note about mergers and type witnesses --------------------------------------- The merger code predates the introduction of type witnesses, and because of its complexity has proved the hardest part of the codebase to retrofit. Attempting to do this has exposed various places where the code behaves oddly (e.g. 'putBefore' below); these are likely to be bugs but fixing them would be potentially disruptive and dangerous as it might change the existing merge behaviour and thus break existing repositories. As a result the addition of witnesses to this code has required the liberal use of unsafe operators. In effect, witnesses bring no safety in this area; the sole purpose of adding them here was to allow this code to run as part of a codebase that uses witnesses everywhere else. A key problem point is the type of the 'Merger' and 'Regrem' constructors of Patch, where the witnesses seem odd. It is likely that some or many of the unsafe operations could be removed by finding a better type for these constructors. -} actualMerge :: PrimPatch prim => (Patch prim :\/: Patch prim) C(x y) -> Sealed (Patch prim C(y)) actualMerge (p1 :\/: p2) = case elegantMerge (p1:\/:p2) of Just (_ :/\: p1') -> Sealed p1' Nothing -> merger "0.0" p2 p1 unwind :: Patch prim C(x y) -> Sealed (RL (Patch prim) C(x)) -- Recreates a patch history in reverse. unwind (Merger _ unwindings _ _) = Sealed unwindings unwind p = Sealed (p :<: NilRL) trueUnwind :: PrimPatch prim => Patch prim C(x y) -> Sealed (RL (Patch prim) C(x)) -- Recreates a patch history in reverse. trueUnwind p@(Merger _ _ p1 p2) = case (unwind p1, unwind p2) of (Sealed (_:<:p1s),Sealed (_:<:p2s)) -> Sealed (p :<: unsafeCoerceP p1 :<: unsafeUnsealFlipped (reconcileUnwindings p p1s (unsafeCoercePEnd p2s))) _ -> impossible trueUnwind _ = impossible reconcileUnwindings :: PrimPatch prim => Patch prim C(a b) -> RL (Patch prim) C(x z) -> RL (Patch prim) C(y z) -> FlippedSeal (RL (Patch prim)) C(z) reconcileUnwindings _ NilRL p2s = FlippedSeal p2s reconcileUnwindings _ p1s NilRL = FlippedSeal p1s reconcileUnwindings p (p1:<:p1s) p2s@(p2:<:tp2s) = case [(p1s', p2s')| p1s'@(hp1s':<:_) <- headPermutationsRL (p1:<:p1s), p2s'@(hp2s':<:_) <- headPermutationsRL p2s, hp1s' `unsafeCompare` hp2s'] of ((p1':<:p1s', _:<:p2s'):_) -> mapFlipped (p1' :<:) $ reconcileUnwindings p p1s' (unsafeCoercePEnd p2s') [] -> case reverseFL `fmap` putBefore p1 (reverseRL p2s) of Just p2s' -> mapFlipped (p1 :<:) $ reconcileUnwindings p p1s p2s' Nothing -> case fmap reverseFL $ putBefore p2 $ reverseRL (p1:<:p1s) of Just p1s' -> mapFlipped (p2 :<:) $ reconcileUnwindings p p1s' tp2s Nothing -> bugDoc $ text "in function reconcileUnwindings" $$ text "Original patch:" $$ showPatch_ p _ -> bug "in reconcileUnwindings" -- This code seems wrong, shouldn't the commute be invert p1 :> p2 ? And why isn't p1' re-inverted? -- it seems to have been this way forever: -- Fri May 23 10:27:04 BST 2003 droundy@abridgegame.org -- * fix bug in unwind and add docs on unwind algorithm. putBefore :: PrimPatch prim => Patch prim C(y z) -> FL (Patch prim) C(x z) -> Maybe (FL (Patch prim) C(y w)) putBefore p1 (p2:>:p2s) = do p1' :> p2' <- commute (unsafeCoerceP p2 :> invert p1) _ <- commute (p2' :> p1) (unsafeCoerceP p2' :>:) `fmap` putBefore p1' (unsafeCoerceP p2s) putBefore _ NilFL = Just (unsafeCoerceP NilFL) instance PrimPatch prim => CommuteNoConflicts (Patch prim) where commuteNoConflicts (x:>y) = do x' :< y' <- commuteNoMerger (y :< x) return (y':>x') instance PrimPatch prim => Conflict (Patch prim) where resolveConflicts patch = rcs NilFL (patch :<: NilRL) where rcs :: FL (Patch prim) C(y w) -> RL (Patch prim) C(x y) -> [[Sealed (FL prim C(w))]] rcs _ NilRL = [] rcs passedby (p@(Merger _ _ _ _):<:ps) = case revCommuteFLId commuteNoMerger (passedby: (map Sealed $ nubBy unsafeCompare $ effect (unsafeCoercePStart $ unsafeUnseal (glump09 p1 p2)) : map (unsafeCoercePStart . unsafeUnseal) (unravel p')) : rcs (p :>: passedby) ps Nothing -> rcs (p :>: passedby) ps _ -> impossible rcs passedby (p:<:ps) = seq passedby $ rcs (p :>: passedby) ps -- This type seems wrong - the most natural type for the result would seem to be -- [Sealed (FL Prim C(x))], given the type of unwind. -- However downstream code in darcs convert assumes the C(y) type, and I was unable -- to figure out whether this could/should reasonably be changed -- Ganesh 13/4/10 publicUnravel :: PrimPatch prim => Patch prim C(x y) -> [Sealed (FL prim C(y))] publicUnravel = map (mapSeal unsafeCoercePStart) . unravel unravel :: PrimPatch prim => Patch prim C(x y) -> [Sealed (FL prim C(x))] unravel p = nub $ map (mapSeal (sortCoalesceFL . concatFL . mapFL_FL effect)) $ getSupers $ map (mapSeal reverseRL) $ unseal (newUr p) $ unwind p getSupers :: PrimPatch prim => [Sealed (FL (Patch prim) C(x))] -> [Sealed (FL (Patch prim) C(x))] getSupers (x:xs) = case filter (not.(x `isSuperpatchOf`)) xs of xs' -> if or $ map (`isSuperpatchOf` x) xs' then getSupers xs' else x : getSupers xs' getSupers [] = [] isSuperpatchOf :: PrimPatch prim => Sealed (FL (Patch prim) C(x)) -> Sealed (FL (Patch prim) C(x)) -> Bool Sealed x `isSuperpatchOf` Sealed y | lengthFL y > lengthFL x = False -- should be just an optimisation Sealed x `isSuperpatchOf` Sealed y = x `iso` y where iso :: PrimPatch prim => FL (Patch prim) C(x y) -> FL (Patch prim) C(x z) -> Bool _ `iso` NilFL = True NilFL `iso` _ = False a `iso` (b:>:bs) = head $ ([as `iso` bs | (ah :>: as) <- simpleHeadPermutationsFL a, IsEq <- [ah =\/= b]] :: [Bool]) ++ [False] merger :: PrimPatch prim => String -> Patch prim C(x y) -> Patch prim C(x z) -> Sealed (Patch prim C(y)) merger "0.0" p1 p2 = Sealed $ Merger undoit unwindings p1 p2 where fake_p = Merger NilFL NilRL p1 p2 unwindings = unsafeUnseal (trueUnwind fake_p) p = Merger NilFL unwindings p1 p2 undoit = case (isMerger p1, isMerger p2) of (True ,True ) -> case unwind p of Sealed (_:<:t) -> unsafeCoerceP $ invertRL t _ -> impossible (False,False) -> unsafeCoerceP $ invert p1 :>: NilFL (True ,False) -> unsafeCoerceP $ NilFL (False,True ) -> unsafeCoerceP $ invert p1 :>: mergerUndo p2 merger g _ _ = error $ "Cannot handle mergers other than version 0.0\n"++g ++ "\nPlease use darcs optimize --modernize with an older darcs." glump09 :: PrimPatch prim => Patch prim C(x y) -> Patch prim C(x z) -> Sealed (FL (Patch prim) C(y)) glump09 p1 p2 = mapSeal (mapFL_FL fromPrim) $ mangleUnravelled $ unseal unravel $ merger "0.0" p1 p2 instance PrimPatch prim => Effect (Patch prim) where effect p@(Merger _ _ _ _) = sortCoalesceFL $ effect $ mergerUndo p effect p@(Regrem _ _ _ _) = invert $ effect $ invert p effect (PP p) = p :>: NilFL instance IsHunk prim => IsHunk (Patch prim) where isHunk p = do PP p' <- return p isHunk p' newUr :: PrimPatch prim => Patch prim C(a b) -> RL (Patch prim) C(x y) -> [Sealed (RL (Patch prim) C(x))] newUr p (Merger _ _ p1 p2 :<: ps) = case filter (\(pp:<:_) -> pp `unsafeCompare` p1) $ headPermutationsRL ps of ((_:<:ps'):_) -> newUr p (unsafeCoercePStart p1:<:ps') ++ newUr p (unsafeCoercePStart p2:<:ps') _ -> bugDoc $ text "in function newUr" $$ text "Original patch:" $$ showPatch_ p $$ text "Unwound:" $$ vcat (unseal (mapRL showPatch_) $ unwind p) newUr op ps = case filter (\(p:<:_) -> isMerger p) $ headPermutationsRL ps of [] -> [Sealed ps] (ps':_) -> newUr op ps' instance Invert prim => Invert (Patch prim) where invert (Merger undo unwindings p1 p2) = Regrem undo unwindings p1 p2 invert (Regrem undo unwindings p1 p2) = Merger undo unwindings p1 p2 invert (PP p) = PP (invert p) instance MyEq prim => MyEq (Patch prim) where unsafeCompare = eqPatches instance MyEq prim => Eq (Patch prim C(x y)) where (==) = unsafeCompare eqPatches :: MyEq prim => Patch prim C(x y) -> Patch prim C(w z) -> Bool eqPatches (PP p1) (PP p2) = unsafeCompare p1 p2 eqPatches (Merger _ _ p1a p1b) (Merger _ _ p2a p2b) = eqPatches p1a p2a && eqPatches p1b p2b eqPatches (Regrem _ _ p1a p1b) (Regrem _ _ p2a p2b) = eqPatches p1a p2a && eqPatches p1b p2b eqPatches _ _ = False darcs-2.8.4/src/Darcs/Patch/V1/Core.hs0000644001765600176560000000304512104371431016537 0ustar ganeshganeshmodule Darcs.Patch.V1.Core ( Patch(..), isMerger, mergerUndo ) where import Darcs.Patch.Format ( PatchListFormat(..), ListFormat(ListFormatV1) ) import Darcs.Patch.Prim ( FromPrim(..), PrimOf, PrimPatchBase, PrimPatch ) import Darcs.Patch.Repair ( Check ) import Darcs.Witnesses.Ordered ( FL(..), RL ) #include "gadts.h" #include "impossible.h" data Patch prim C(x y) where PP :: prim C(x y) -> Patch prim C(x y) Merger :: FL (Patch prim) C(x y) -> RL (Patch prim) C(x b) -> Patch prim C(c b) -> Patch prim C(c d) -> Patch prim C(x y) Regrem :: FL (Patch prim) C(x y) -> RL (Patch prim) C(x b) -> Patch prim C(c b) -> Patch prim C(c a) -> Patch prim C(y x) instance PrimPatch prim => PrimPatchBase (Patch prim) where type PrimOf (Patch prim) = prim instance FromPrim (Patch prim) where fromPrim = PP isMerger :: Patch prim C(a b) -> Bool isMerger (Merger _ _ _ _) = True isMerger (Regrem _ _ _ _) = True isMerger _ = False mergerUndo :: Patch prim C(x y) -> FL (Patch prim) C(x y) mergerUndo (Merger undo _ _ _) = undo mergerUndo _ = impossible instance PatchListFormat (Patch prim) where -- In principle we could use ListFormatDefault when prim /= V1 Prim patches, -- as those are the only case where we need to support a legacy on-disk -- format. In practice we don't expect Patch to be used with any other argument -- anyway, so it doesn't matter. patchListFormat = ListFormatV1 instance Check (Patch prim) -- no checks darcs-2.8.4/src/Darcs/Patch/V1/Read.hs0000644001765600176560000000274012104371431016523 0ustar ganeshganesh{-# OPTIONS_GHC -fno-warn-orphans #-} module Darcs.Patch.V1.Read () where import Darcs.Patch.Invert ( invert ) import Darcs.Patch.Prim ( PrimPatch ) import Darcs.Patch.Read ( ReadPatch(..) ) import Darcs.Patch.ReadMonads ( ParserM, choice, string, lexChar, myLex', skipSpace ) import Darcs.Patch.V1.Core ( Patch(..) ) import Darcs.Patch.V1.Commute ( merger ) import Darcs.Witnesses.Sealed ( Sealed(..), seal, mapSeal ) import Darcs.Witnesses.Unsafe ( unsafeCoerceP ) import Control.Monad ( liftM ) import qualified Data.ByteString.Char8 as BC ( unpack, pack ) import qualified Data.ByteString as B (ByteString ) #include "gadts.h" instance PrimPatch prim => ReadPatch (Patch prim) where readPatch' = choice [ liftM seal $ skipSpace >> readMerger True , liftM seal $ skipSpace >> readMerger False , liftM (mapSeal PP) $ readPatch' ] readMerger :: (ParserM m, PrimPatch prim) => Bool -> m (Patch prim C(x y)) readMerger b = do string s g <- myLex' lexChar '(' Sealed p1 <- readPatch' Sealed p2 <- readPatch' lexChar ')' Sealed m <- return $ merger (BC.unpack g) p1 p2 return $ if b then unsafeCoerceP m else unsafeCoerceP (invert m) where s | b = merger' | otherwise = regrem merger' :: B.ByteString merger' = BC.pack "merger" regrem :: B.ByteString regrem = BC.pack "regrem" darcs-2.8.4/src/Darcs/Patch/V1/Show.hs0000644001765600176560000000230012104371431016560 0ustar ganeshganesh{-# OPTIONS_GHC -fno-warn-orphans #-} module Darcs.Patch.V1.Show ( showPatch_ ) where import Darcs.Patch.Format ( FileNameFormat(..) ) import Darcs.Patch.Prim ( showPrim, PrimPatch ) import Darcs.Patch.V1.Core ( Patch(..) ) import Darcs.Witnesses.Show ( Show1(..), Show2(..), ShowDict(..) ) import Printer ( Doc, renderString, text, blueText, ($$), (<+>) ) #include "gadts.h" instance PrimPatch prim => Show (Patch prim C(x y)) where show p = renderString (showPatch_ p) ++ "\n" instance PrimPatch prim => Show1 (Patch prim C(x)) where showDict1 = ShowDictClass instance PrimPatch prim => Show2 (Patch prim) where showDict2 = ShowDictClass showPatch_ :: PrimPatch prim => Patch prim C(a b) -> Doc showPatch_ (PP p) = showPrim OldFormat p showPatch_ (Merger _ _ p1 p2) = showMerger "merger" p1 p2 showPatch_ (Regrem _ _ p1 p2) = showMerger "regrem" p1 p2 showMerger :: PrimPatch prim => String -> Patch prim C(a b) -> Patch prim C(d e) -> Doc showMerger merger_name p1 p2 = blueText merger_name <+> text "0.0" <+> blueText "(" $$ showPatch_ p1 $$ showPatch_ p2 $$ blueText ")" darcs-2.8.4/src/Darcs/Patch/V1/Viewing.hs0000644001765600176560000000130412104371431017253 0ustar ganeshganesh{-# OPTIONS_GHC -fno-warn-orphans #-} {-# LANGUAGE ViewPatterns #-} module Darcs.Patch.V1.Viewing () where import Darcs.Patch.Prim ( PrimPatch ) import Darcs.Patch.Show ( ShowPatchBasic(..), ShowPatch(..) ) import Darcs.Patch.Summary ( plainSummary ) import Darcs.Patch.V1.Apply () import Darcs.Patch.V1.Core ( Patch(..) ) import Darcs.Patch.V1.Show ( showPatch_ ) #include "gadts.h" instance PrimPatch prim => ShowPatchBasic (Patch prim) where showPatch = showPatch_ instance PrimPatch prim => ShowPatch (Patch prim) where showContextPatch (PP p) = showContextPatch p showContextPatch p = return $ showPatch p summary = plainSummary summaryFL = plainSummary thing _ = "change" darcs-2.8.4/src/Darcs/Patch/V2/0000755001765600176560000000000012104371431015312 5ustar ganeshganeshdarcs-2.8.4/src/Darcs/Patch/V2/Non.hs0000644001765600176560000002536312104371431016411 0ustar ganeshganesh-- Copyright (C) 2007 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# OPTIONS_GHC -fno-warn-orphans -fno-warn-name-shadowing #-} {-# LANGUAGE CPP, FlexibleContexts, UndecidableInstances #-} #include "gadts.h" module Darcs.Patch.V2.Non ( Non(..) , Nonable(..) , unNon , showNon , showNons , readNon , readNons , commutePrimsOrAddToCtx , commuteOrAddToCtx , commuteOrRemFromCtx , commuteOrAddToCtxRL , commuteOrRemFromCtxFL , remNons , (*>) , (>*) , (*>>) , (>>*) ) where import Prelude hiding ( rem ) import Data.List ( delete ) import Control.Monad ( liftM, mzero ) import Darcs.Patch.Commute ( commuteFL ) import Darcs.Patch.Effect ( Effect(..) ) import Darcs.Patch.Format ( PatchListFormat, FileNameFormat(..) ) import Darcs.Patch.Invert ( Invert, invertFL, invertRL ) import Darcs.Patch.Prim ( FromPrim(..), ToFromPrim(..), PrimOf, PrimPatchBase, showPrim, sortCoalesceFL, readPrim ) import Darcs.Patch.Patchy ( Patchy, showPatch, ReadPatch(..), Commute(..), invert ) import Darcs.Patch.ReadMonads ( ParserM, lexChar ) import Darcs.Witnesses.Eq ( MyEq(..), EqCheck(..) ) import Darcs.Witnesses.Ordered ( FL(..), RL(..), (+>+), mapRL_RL , (:>)(..), reverseFL, reverseRL ) import Darcs.Patch.Read ( peekfor ) import Darcs.Patch.Show ( ShowPatchBasic ) import Darcs.Patch.Viewing () import Darcs.Patch.Permutations ( removeFL, commuteWhatWeCanFL ) import Darcs.Witnesses.Show ( ShowDict(..), Show1(..), Show2(..), appPrec , showsPrec2 ) import Darcs.Witnesses.Sealed ( Sealed(Sealed) ) import Printer ( Doc, empty, vcat, hiddenPrefix, blueText, ($$) ) import qualified Data.ByteString.Char8 as BC ( pack, singleton ) -- |A 'Non' stores a context with a 'Prim' patch. It is a patch whose effect -- isn't visible - a Non-affecting patch. data Non p C(x) where Non :: FL p C(x y) -> PrimOf p C(y z) -> Non p C(x) -- |unNon converts a Non into a FL of its context followed by the primitive -- patch. unNon :: FromPrim p => Non p C(x) -> Sealed (FL p C(x)) unNon (Non c x) = Sealed (c +>+ fromPrim x :>: NilFL) instance (Show2 p, Show2 (PrimOf p)) => Show (Non p C(x)) where showsPrec d (Non cs p) = showParen (d > appPrec) $ showString "Non " . showsPrec2 (appPrec + 1) cs . showString " " . showsPrec2 (appPrec + 1) p instance (Show2 p, Show2 (PrimOf p)) => Show1 (Non p) where showDict1 = ShowDictClass -- |showNons creates a Doc representing a list of Nons. showNons :: (ShowPatchBasic p, PatchListFormat p, PrimPatchBase p) => [Non p C(x)] -> Doc showNons [] = empty showNons xs = blueText "{{" $$ vcat (map showNon xs) $$ blueText "}}" -- |showNon creates a Doc representing a Non. showNon :: (ShowPatchBasic p, PatchListFormat p, PrimPatchBase p) => Non p C(x) -> Doc showNon (Non c p) = hiddenPrefix "|" (showPatch c) $$ hiddenPrefix "|" (blueText ":") $$ showPrim NewFormat p -- |readNons is a parser that attempts to read a list of Nons. readNons :: (ReadPatch p, PatchListFormat p, PrimPatchBase p, ParserM m) => m [Non p C(x)] readNons = peekfor (BC.pack "{{") rns (return []) where rns = peekfor (BC.pack "}}") (return []) $ do Sealed ps <- readPatch' lexChar ':' Sealed p <- readPrim NewFormat (Non ps p :) `liftM` rns -- |readNon is a parser that attempts to read a single Non. readNon :: (ReadPatch p, PatchListFormat p, PrimPatchBase p, ParserM m) => m (Non p C(x)) readNon = do Sealed ps <- readPatch' let doReadPrim = do Sealed p <- readPrim NewFormat return $ Non ps p peekfor (BC.singleton ':') doReadPrim mzero -- |Nons are equal if their context patches are equal, and they have an equal -- prim patch. instance (Commute p, MyEq p, MyEq (PrimOf p)) => Eq (Non p C(x)) where Non (cx :: FL p C(x y1)) (x :: PrimOf p C(y1 z1)) == Non (cy :: FL p C(x y2)) (y :: PrimOf p C(y2 z2)) = case cx =\/= cy of IsEq -> case x =\/= y :: EqCheck C(z1 z2) of IsEq -> True NotEq -> False NotEq -> False -- |Nonable represents the class of patches that can be turned into a Non. class Nonable p where non :: p C(x y) -> Non p C(x) -- |'commuteOrAddToCtx' @x cy@ tries to commute @x@ past @cy@ and always -- returns some variant @cy'@. If commutation suceeds, the variant is just -- straightforwardly the commuted version. If commutation fails, the variant -- consists of @x@ prepended to the context of @cy@. commuteOrAddToCtx :: (Patchy p, ToFromPrim p) => p C(x y) -> Non p C(y) -> Non p C(x) commuteOrAddToCtx p n | Just n' <- p >* n = n' commuteOrAddToCtx p (Non c x) = Non (p:>:c) x -- | 'commuteOrAddToCtxRL' @xs cy@ commutes as many patches of @xs@ past @cy@ -- as possible, adding any that don't commute to the context of cy. Suppose we -- have -- -- > x1 x2 x3 [c1 c2 y] -- -- and that in our example @x1@ fails to commute past @c1@, this function -- would commute down to -- -- > x1 [c1'' c2'' y''] x2' x3' -- -- and return @[x1 c1'' c2'' y'']@ commuteOrAddToCtxRL :: (Patchy p, ToFromPrim p) => RL p C(x y) -> Non p C(y) -> Non p C(x) commuteOrAddToCtxRL NilRL n = n commuteOrAddToCtxRL (p:<:ps) n = commuteOrAddToCtxRL ps $ commuteOrAddToCtx p n -- |abstract over 'FL'/'RL' class WL l where toFL :: l p C(x y) -> FL p C(x y) toRL :: l p C(x y) -> RL p C(x y) invertWL :: Invert p => l p C(x y) -> l p C(y x) instance WL FL where toFL = id toRL = reverseFL invertWL = reverseRL . invertFL instance WL RL where toFL = reverseRL toRL = id invertWL = reverseFL . invertRL -- |commutePrimsOrAddToCtx takes a WL of prims and attempts to commute them -- past a Non. commutePrimsOrAddToCtx :: (WL l, Patchy p, ToFromPrim p) => l (PrimOf p) C(x y) -> Non p C(y) -> Non p C(x) commutePrimsOrAddToCtx q = commuteOrAddToCtxRL (mapRL_RL fromPrim $ toRL q) -- TODO: Figure out what remNons is for; it's is only used in one place - when -- commuting two Conflictors: -- -- > commute (Conflictor a1 n1 p1 :> Conflictor a2 n2 p2) -- > ... -- > a1' = map (commutePrimsOrAddToCtx n2) a1 -- > p2ooo = remNons a1' p2 -- > n2n1 = n2 +>+ n1 -- > n1' :> n2' <- return $ filterConflictsFL p2ooo n2n1 -- -- which appears to be munging the not-yet-undone FLs in the Conflictors. a1' -- will be the list of Nons with n2 commuted in/past them. So we then want to -- modify p2, so that it doesn't have any of a1' in its context. -- remNons really only works right if the relevant nons are conflicting... remNons :: (Nonable p, Effect p, Patchy p, ToFromPrim p, PrimPatchBase p, MyEq (PrimOf p)) => [Non p C(x)] -> Non p C(x) -> Non p C(x) remNons ns n@(Non c x) = case remNonHelper ns c of NilFL :> c' -> Non c' x _ -> n where remNonHelper :: (Nonable p, Effect p, Patchy p, ToFromPrim p, PrimPatchBase p, MyEq (PrimOf p)) => [Non p C(x)] -> FL p C(x y) -> (FL (PrimOf p) :> FL p) C(x y) remNonHelper [] x = NilFL :> x remNonHelper _ NilFL = NilFL :> NilFL remNonHelper ns (c:>:cs) | non c `elem` ns = let nsWithoutC = delete (non c) ns in let commuteOrAddInvC = commuteOrAddToCtx $ invert c in case remNonHelper (map commuteOrAddInvC $ nsWithoutC) cs of a :> z -> sortCoalesceFL (effect c +>+ a) :> z | otherwise = case commuteWhatWeCanFL (c :> cs) of b :> c' :> d -> case remNonHelper ns b of a :> b' -> a :> (b' +>+ c' :>: d) -- |commuteOrRemFromCtx attempts to remove a given patch from a Non. If the -- patch was not in the Non, then the commute will succeed and the modified Non -- will be returned. If the commute fails then the patch is either in the Non -- context, or the Non patch itself; we attempt to remove the patch from the -- context and then return the non with the updated context. -- -- TODO: understand if there is any case where p is equal to the prim patch of -- the Non, in which case, we return the original Non, is that right? commuteOrRemFromCtx :: (Patchy p, ToFromPrim p) => p C(x y) -> Non p C(x) -> Maybe (Non p C(y)) commuteOrRemFromCtx p n | n'@(Just _) <- n *> p = n' commuteOrRemFromCtx p (Non pc x) = removeFL p pc >>= \c -> return (Non c x) -- |commuteOrRemFromCtxFL attempts to remove a FL of patches from a Non, -- returning Nothing if any of the individual removes fail. commuteOrRemFromCtxFL :: (Patchy p, ToFromPrim p) => FL p C(x y) -> Non p C(x) -> Maybe (Non p C(y)) commuteOrRemFromCtxFL NilFL n = Just n commuteOrRemFromCtxFL (p:>:ps) n = do n' <- commuteOrRemFromCtx p n commuteOrRemFromCtxFL ps n' -- |(*>) attemts to modify a Non by commuting it past a given patch. (*>) :: (Patchy p, ToFromPrim p) => Non p C(x) -> p C(x y) -> Maybe (Non p C(y)) n *> p = invert p >* n -- |(>*) attempts to modify a Non, by commuting a given patch past it. (>*) :: (Patchy p, ToFromPrim p) => p C(x y) -> Non p C(y) -> Maybe (Non p C(x)) y >* (Non c x) = do c' :> y' <- commuteFL (y :> c) px' :> _ <- commute (y' :> fromPrim x) x' <- toPrim px' return (Non c' x') -- |(*>>) attempts to modify a Non by commuting it past a given WL of patches. (*>>) :: (WL l, Patchy p, ToFromPrim p, PrimPatchBase p) => Non p C(x) -> l (PrimOf p) C(x y) -> Maybe (Non p C(y)) n *>> p = invertWL p >>* n -- |(>>*) attempts to modify a Non by commuting a given WL of patches past it. (>>*) :: (WL l, Patchy p, ToFromPrim p) => l (PrimOf p) C(x y) -> Non p C(y) -> Maybe (Non p C(x)) ps >>* n = commuteRLPastNon (toRL ps) n where commuteRLPastNon :: (Patchy p, ToFromPrim p) => RL (PrimOf p) C(x y) -> Non p C(y) -> Maybe (Non p C(x)) commuteRLPastNon NilRL n = Just n commuteRLPastNon (x:<:xs) n = fromPrim x >* n >>= commuteRLPastNon xs darcs-2.8.4/src/Darcs/Patch/V2/Real.hs0000644001765600176560000012106012104371431016531 0ustar ganeshganesh-- Copyright (C) 2007 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# OPTIONS_GHC -fno-warn-orphans -fno-warn-name-shadowing #-} {-# LANGUAGE CPP #-} #include "gadts.h" module Darcs.Patch.V2.Real ( RealPatch(..) , prim2real , isConsistent , isForward , isDuplicate , mergeUnravelled ) where import Control.Monad ( mplus, liftM ) import qualified Data.ByteString.Char8 as BC ( ByteString, pack ) import Data.Maybe ( fromMaybe ) import Data.List ( partition, nub ) import Darcs.ColorPrinter ( errorDoc, assertDoc ) import Darcs.Patch.Commute ( commuteFL, commuteFLorComplain, commuteRL , commuteRLFL ) import Darcs.Patch.Conflict ( Conflict(..), CommuteNoConflicts(..) , IsConflictedPrim(..), ConflictState(..) ) import Darcs.Patch.ConflictMarking ( mangleUnravelled ) import Darcs.Patch.Effect ( Effect(..) ) import Darcs.Patch.FileHunk ( IsHunk(..) ) import Darcs.Patch.Format ( PatchListFormat(..), ListFormat(..) , FileNameFormat(NewFormat) ) import Darcs.Patch.Invert ( invertFL, invertRL ) import Darcs.Patch.Merge ( Merge(..) ) import Darcs.Patch.Prim ( FromPrim(..), ToFromPrim(..), showPrim, showPrimFL , readPrim, PrimOf, PrimPatchBase, PrimPatch ) import Darcs.Patch.Read ( bracketedFL ) import Darcs.Patch.ReadMonads ( skipSpace, string, choice ) import Darcs.Patch.Repair ( mapMaybeSnd, RepairToFL(..), Check(..) ) import Darcs.Patch.Patchy ( Patchy, Apply(..), Commute(..), PatchInspect(..) , ReadPatch(..), ShowPatch(..), Invert(..) ) import Darcs.Patch.Permutations ( commuteWhatWeCanFL, commuteWhatWeCanRL , genCommuteWhatWeCanRL, removeRL, removeFL , removeSubsequenceFL ) import Darcs.Patch.Show ( ShowPatchBasic(..) ) import Darcs.Patch.Summary ( plainSummary ) import Darcs.Patch.V2.Non ( Non(..), Nonable(..), unNon, showNons, showNon , readNons, readNon, commutePrimsOrAddToCtx , commuteOrAddToCtx, commuteOrAddToCtxRL , commuteOrRemFromCtx, commuteOrRemFromCtxFL , remNons, (*>), (>*), (*>>), (>>*) ) import Darcs.Utils ( nubsort ) import Darcs.Witnesses.Unsafe ( unsafeCoerceP ) import Darcs.Witnesses.Eq ( MyEq(..), EqCheck(..) ) import Darcs.Witnesses.Ordered ( FL(..), RL(..), (:>)(..), (+>+), (+<+) , mapFL_FL, reverseFL, (:\/:)(..), (:/\:)(..) , reverseRL, lengthFL, lengthRL, nullFL ) import Darcs.Witnesses.Sealed ( FlippedSeal(..), Sealed(Sealed), mapSeal , unseal ) import Darcs.Witnesses.Show ( Show2(..), ShowDict(..) ) import Printer ( Doc, renderString, blueText, redText, (<+>), ($$) ) #include "impossible.h" -- |'RealPatch' is used to represents prim patches that are duplicates of, or -- conflict with, another prim patch in the repository. -- -- @Normal prim@: A primitive patch -- -- @Duplicate x@: This patch has no effect since @x@ is already present in the -- repository. -- -- @Etacilpud x: invert (Duplicate x)@ -- -- @Conflictor ix xx x@: -- @ix@ is the set of patches: -- * that conflict with @x@ and also conflict with another patch in the -- repository. -- * that conflict with a patch that conflict with @x@ -- -- @xx@ is the sequence of patches that conflict *only* with @x@ -- -- @x@ is the original, conflicting patch. -- -- @ix@ and @x@ are stored as @Non@ objects, which include any necessary -- context to uniquely define the patch that is referred to. -- -- The intuition is that a Conflictor should have the effect of inverting any -- patches that 'x' conflicts with, that haven't already been undone by another -- Conflictor in the repository. -- Therefore, the effect of a Conflictor is @invert xx@. -- -- @InvConflictor ix xx x@: like @invert (Conflictor ix xx x)@ data RealPatch prim C(x y) where Duplicate :: Non (RealPatch prim) C(x) -> RealPatch prim C(x x) Etacilpud :: Non (RealPatch prim) C(x) -> RealPatch prim C(x x) Normal :: prim C(x y) -> RealPatch prim C(x y) Conflictor :: [Non (RealPatch prim) C(x)] -> FL prim C(x y) -> Non (RealPatch prim) C(x) -> RealPatch prim C(y x) InvConflictor :: [Non (RealPatch prim) C(x)] -> FL prim C(x y) -> Non (RealPatch prim) C(x) -> RealPatch prim C(x y) instance PrimPatch prim => PrimPatchBase (RealPatch prim) where type PrimOf (RealPatch prim) = prim -- | 'isDuplicate' @p@ is @True@ if @p@ is either a 'Duplicate' or 'Etacilpud' -- patch. isDuplicate :: RealPatch prim C(s y) -> Bool isDuplicate (Duplicate _) = True isDuplicate (Etacilpud _) = True isDuplicate _ = False -- | 'isForward' @p@ is @True@ if @p@ is either an 'InvConflictor' or -- 'Etacilpud'. isForward :: PrimPatch prim => RealPatch prim C(s y) -> Maybe Doc isForward p = case p of p@(InvConflictor _ _ _) -> justRedP "An inverse conflictor" p p@(Etacilpud _) -> justRedP "An inverse duplicate" p _ -> Nothing where justRedP msg p = Just $ redText msg $$ showPatch p -- |'mergeUnravelled' is used when converting from Darcs V1 patches (Mergers) -- to Darcs V2 patches (Conflictors). mergeUnravelled :: PrimPatch prim => [Sealed ((FL prim) C(x))] -> Maybe (FlippedSeal (RealPatch prim) C(x)) mergeUnravelled [] = Nothing mergeUnravelled [_] = Nothing mergeUnravelled ws = case mergeUnravelled_private ws of Nothing -> Nothing Just NilRL -> bug "found no patches in mergeUnravelled" Just (z :<: _) -> Just $ FlippedSeal z where notNullS :: PrimPatch prim => Sealed ((FL prim) C(x)) -> Bool notNullS (Sealed NilFL) = False notNullS _ = True mergeUnravelled_private :: PrimPatch prim => [Sealed (FL prim C(x))] -> Maybe (RL (RealPatch prim) C(x x)) mergeUnravelled_private xs = let nonNullXs = filter notNullS xs in reverseFL `fmap` mergeConflictingNons (map sealed2non nonNullXs) -- | 'sealed2non' @(Sealed xs)@ converts @xs@ to a 'Non'. -- @xs@ must be non-empty since we split this list at the last patch, -- taking @init xs@ as the context of @last xs@. sealed2non :: Sealed ((FL prim) C(x)) -> Non (RealPatch prim) C(x) sealed2non (Sealed xs) = case reverseFL xs of y :<: ys -> Non (mapFL_FL fromPrim $ reverseRL ys) y NilRL -> bug "NilFL encountered in sealed2non" mergeConflictingNons :: PrimPatch prim => [Non (RealPatch prim) C(x)] -> Maybe (FL (RealPatch prim) C(x x)) mergeConflictingNons ns = mcn $ map unNon ns where mcn :: PrimPatch prim => [Sealed (FL (RealPatch prim) C(x))] -> Maybe (FL (RealPatch prim) C(x x)) mcn [] = Just NilFL -- Apparently, the joinEffects call is a safety check "and could be -- removed when we're sure of the code"! mcn [Sealed p] = case joinEffects p of NilFL -> Just p _ -> Nothing mcn (Sealed p1:Sealed p2:zs) = case pullCommon p1 p2 of Common c ps qs -> case merge (ps :\/: qs) of qs' :/\: _ -> mcn (Sealed (c +>+ ps +>+ qs'):zs) joinEffects :: forall p C(x y) . (Effect p, Invert (PrimOf p), Commute (PrimOf p), MyEq (PrimOf p)) => p C(x y) -> FL (PrimOf p) C(x y) joinEffects = joinInverses . effect where joinInverses :: FL (PrimOf p) C(a b) -> FL (PrimOf p) C(a b) joinInverses NilFL = NilFL joinInverses (p :>: ps) = let ps' = joinInverses ps in fromMaybe (p :>: ps') $ removeFL (invert p) ps' assertConsistent :: PrimPatch prim => RealPatch prim C(x y) -> RealPatch prim C(x y) assertConsistent x = flip assertDoc x $ do e <- isConsistent x Just (redText "Inconsistent patch:" $$ showPatch x $$ e) -- | @mergeAfterConflicting@ takes as input a sequence of conflicting patches -- @xxx@ (which therefore have no effect) and a sequence of primitive patches -- @yyy@ that follow said sequence of conflicting patches, and may depend upon -- some of the conflicting patches (as a resolution). -- The output is two sequences of patches the first consisting of a set of -- mutually-conflicting patches, and the second having the same effect as the -- original primitive patch sequence in the input. -- So far as I can tell, the second output is always identical to @mapFL Normal -- yyy@ -- The first output is the set of patches from @xxx@ that are depended upon by -- @yyy@. mergeAfterConflicting :: PrimPatch prim => FL (RealPatch prim) C(x x) -> FL prim C(x y) -> Maybe ( FL (RealPatch prim) C(x x) , FL (RealPatch prim) C(x y)) mergeAfterConflicting xxx yyy = mac (reverseFL xxx) yyy NilFL where mac :: PrimPatch prim => RL (RealPatch prim) C(x y) -> FL prim C(y z) -> FL (RealPatch prim) C(z a) -> Maybe (FL (RealPatch prim) C(x x), FL (RealPatch prim) C(x a)) mac NilRL xs goneby = case joinEffects goneby of NilFL -> Just (NilFL, mapFL_FL Normal xs) _ -> Nothing mac (p :<: ps) xs goneby = case commuteFLorComplain (p :> mapFL_FL Normal xs) of Left _ -> case genCommuteWhatWeCanRL commuteNoConflicts (ps :> p) of a :> p' :> b -> do (b', xs') <- mac b xs goneby let pa = joinEffects $ p' :<: a NilFL <- return pa return (reverseRL (p' :<: a) +>+ b', xs') `mplus` do NilFL <- return goneby NilFL <- return $ joinEffects (p :<: ps) return (reverseRL (p :<: ps), mapFL_FL Normal xs) Right (l :> p'') -> case allNormal l of Just xs'' -> mac ps xs'' (p'' :>: goneby) Nothing -> case genCommuteWhatWeCanRL commuteNoConflicts (ps :> p) of a :> p' :> b -> do (b', xs') <- mac b xs goneby let pa = joinEffects $ p' :<: a NilFL <- return pa return (reverseRL (p' :<: a) +>+ b', xs') geteff :: PrimPatch prim => [Non (RealPatch prim) C(x)] -> FL prim C(x y) -> ([Non (RealPatch prim) C(x)], FL (RealPatch prim) C(x y)) geteff _ NilFL = ([], NilFL) geteff ix (x :>: xs) | Just ix' <- mapM (commuteOrRemFromCtx (Normal x)) ix = case geteff ix' xs of (ns, xs') -> ( non (Normal x) : map (commuteOrAddToCtx (Normal x)) ns , Normal x :>: xs') geteff ix xx = case mergeConflictingNons ix of Nothing -> errorDoc $ redText "mergeConflictingNons failed in geteff: ix" $$ showNons ix $$ redText "xx" $$ showPatch xx Just rix -> case mergeAfterConflicting rix xx of Just (a, x) -> ( map (commuteOrAddToCtxRL (reverseFL a)) $ toNons x , a +>+ x) Nothing -> errorDoc $ redText "mergeAfterConflicting failed in geteff" $$ redText "where ix" $$ showNons ix $$ redText "and xx" $$ showPatch xx $$ redText "and rix" $$ showPatch rix xx2nons :: PrimPatch prim => [Non (RealPatch prim) C(x)] -> FL prim C(x y) -> [Non (RealPatch prim) C(x)] xx2nons ix xx = fst $ geteff ix xx xx2patches :: PrimPatch prim => [Non (RealPatch prim) C(x)] -> FL prim C(x y) -> FL (RealPatch prim) C(x y) xx2patches ix xx = snd $ geteff ix xx -- | If @xs@ consists only of 'Normal' patches, 'allNormal' @xs@ returns -- @Just pxs@ those patches (so @lengthFL pxs == lengthFL xs@). -- Otherwise, it returns 'Nothing'. allNormal :: FL (RealPatch prim) C(x y) -> Maybe (FL prim C(x y)) allNormal (Normal x :>: xs) = (x :>: ) `fmap` allNormal xs allNormal NilFL = Just NilFL allNormal _ = Nothing -- | This is used for unit-testing and for internal sanity checks isConsistent :: PrimPatch prim => RealPatch prim C(x y) -> Maybe Doc isConsistent (Normal _) = Nothing isConsistent (Duplicate _) = Nothing isConsistent (Etacilpud _) = Nothing isConsistent c@(InvConflictor _ _ _) = isConsistent (invert c) isConsistent (Conflictor im mm m@(Non deps _)) | not $ everyoneConflicts im = Just $ redText "Someone doesn't conflict in im in isConsistent" | Just _ <- commuteOrRemFromCtxFL rmm m, _ :>: _ <- mm = Just $ redText "m doesn't conflict with mm in isConsistent" | any (\x -> any (x `conflictsWith`) nmm) im = Just $ redText "mm conflicts with im in isConsistent where nmm is" $$ showNons nmm | Nothing <- (nmm ++ im) `minus` toNons deps = Just $ redText "dependencies not in conflict:" $$ showNons (toNons deps) $$ redText "compared with deps itself:" $$ showPatch deps | otherwise = case allConflictsWith m im of (im1, []) | im1 `eqSet` im -> Nothing (_, imnc) -> Just $ redText ("m doesn't conflict with im in " ++ "isConsistent. unconflicting:") $$ showNons imnc where (nmm, rmm) = geteff im mm everyoneConflicts :: PrimPatch prim => [Non (RealPatch prim) C(x)] -> Bool everyoneConflicts [] = True everyoneConflicts (x : xs) = case allConflictsWith x xs of ([], _) -> False (_, xs') -> everyoneConflicts xs' prim2real :: prim C(x y) -> RealPatch prim C(x y) prim2real = Normal instance PrimPatch prim => Patchy (RealPatch prim) mergeWith :: PrimPatch prim => Non (RealPatch prim) C(x) -> [Non (RealPatch prim) C(x)] -> Sealed (FL prim C(x)) mergeWith p [] = effect `mapSeal` unNon p mergeWith p xs = mergeall . map unNon . (p :) . unconflicting_of $ nonDependsOrConflictsP xs where nonDependsOrConflictsP = filter (\x -> not ((p `dependsUpon` x) || (p `conflictsWith` x))) mergeall :: PrimPatch prim => [Sealed (FL (RealPatch prim) C(x))] -> Sealed (FL prim C(x)) mergeall [Sealed x] = Sealed $ effect x mergeall [] = Sealed NilFL mergeall (Sealed x : Sealed y : rest) = case merge (x :\/: y) of y' :/\: _ -> mergeall (Sealed (x +>+ y') : rest) unconflicting_of [] = [] unconflicting_of (q : qs) = case allConflictsWith q qs of ([], _) -> q : qs (_, nc) -> unconflicting_of nc instance PrimPatch prim => Conflict (RealPatch prim) where conflictedEffect (Duplicate (Non _ x)) = [IsC Duplicated x] conflictedEffect (Etacilpud _) = impossible conflictedEffect (Conflictor _ _ (Non _ x)) = [IsC Conflicted x] conflictedEffect (InvConflictor _ _ _) = impossible conflictedEffect (Normal x) = [IsC Okay x] resolveConflicts (Conflictor ix xx x) = [mangledUnravelled : unravelled] where mangledUnravelled = mangleUnravelled unravelled unravelled = nub $ filter isCons $ map (`mergeWith` xIxNonXX) xIxNonXX xIxNonXX = x : ix ++ nonxx nonxx = nonxx_ (reverseFL $ xx2patches ix xx) -- |nonxx_ takes an RL of patches, and returns a singleton list -- containing a Non, in the case where we have a Normal patch at the -- end of the list (using the rest of the RL as context), and an empty -- list otherwise. nonxx_ :: RL (RealPatch prim) C(x y) -> [Non (RealPatch prim) C(x)] nonxx_ (Normal q :<: qs) = [Non (reverseRL qs) q] nonxx_ _ = [] isCons = unseal (not . nullFL) resolveConflicts _ = [] instance PrimPatch prim => CommuteNoConflicts (RealPatch prim) where commuteNoConflicts (d1@(Duplicate _) :> d2@(Duplicate _)) = Just (d2 :> d1) commuteNoConflicts (e@(Etacilpud _) :> d@(Duplicate _)) = Just (d :> e) commuteNoConflicts (d@(Duplicate _) :> e@(Etacilpud _)) = Just (e :> d) commuteNoConflicts (e1@(Etacilpud _) :> e2@(Etacilpud _)) = Just (e2 :> e1) -- If the duplicate is @x@, as a 'Non', with @invert x@ as the context, -- then it is the patch the duplicate @d@ represents, so commuting results -- in the same two patches (since we'd make one a duplicate, and the other -- would become @x@ as it would no longer be duplicated). -- Otherwise, we commute past, or remove @invert x@ from the context of @d@ -- to obtain a new Duplicate. commuteNoConflicts orig@(x :> Duplicate d) = if d == commuteOrAddToCtx (invert x) (non x) then Just orig else do d' <- commuteOrRemFromCtx (invert x) d return (Duplicate d' :> x) -- Commuting a Duplicate and any other patch simply places @invert x@ into -- the context of the non @d@, by commuting past, or adding to the context. commuteNoConflicts (Duplicate d :> x) = Just (x :> Duplicate (commuteOrAddToCtx (invert x) d)) -- handle Etacilpud cases by first inverting, then using the previous -- definitions. commuteNoConflicts c@(Etacilpud _ :> _) = invertCommuteNC c commuteNoConflicts c@(_ :> Etacilpud _) = invertCommuteNC c -- Two normal patches should be simply commuted (assuming the can). commuteNoConflicts (Normal x :> Normal y) = do y' :> x' <- commute (x :> y) return (Normal y' :> Normal x') -- Commuting a Normal patch past a Conflictor first commutes @x@ past the -- effect of the Conflictor, then commutes the resulting @x'@ past the -- conflicting patch and the already-undone patches. The commuting must be -- done in this order to make the contexts match up (@iy@ and @y@ are made -- in the context before @yy@ have their effect, so we need to commute past -- the effect of @yy@ first). commuteNoConflicts (Normal x :> Conflictor iy yy y) = do iyy' :> x' <- commuteFL (x :> invert yy) y' : iy' <- mapM (Normal x' >*) (y : iy) return (Conflictor iy' (invert iyy') y' :> Normal x') -- Handle via the previous case, using the inverting commuter. commuteNoConflicts c@(InvConflictor _ _ _ :> Normal _) = invertCommuteNC c -- Commuting a Conflictor past a Normal patch is the dual operation to -- commuting a Normal patch past a Conflictor. commuteNoConflicts (Conflictor iy yy y :> Normal x) = do y' : iy' <- mapM (*> Normal x) (y : iy) x' :> iyy' <- commuteRL (invertFL yy :> x) return (Normal x' :> Conflictor iy' (invertRL iyy') y') -- Handle via the previous case, using the inverting commuter. commuteNoConflicts c@(Normal _ :> InvConflictor _ _ _) = invertCommuteNC c -- Commuting two Conflictors, c1 and c2, first commutes the Conflictors' -- effects, then commutes the effect of c1 and c2 and the other's -- already-undone, and conflicting patch, to bring the already-undone and -- conflicting patch into the context of the commuted effects. commuteNoConflicts (Conflictor ix xx x :> Conflictor iy yy y) = do xx' :> yy' <- commute (yy :> xx) x':ix' <- mapM (yy >>*) (x:ix) y':iy' <- mapM (*>> xx') (y:iy) False <- return $ any (conflictsWith y) (x':ix') False <- return $ any (conflictsWith x') iy return (Conflictor iy' yy' y' :> Conflictor ix' xx' x') -- Handle via the previous case, using the inverting commuter. commuteNoConflicts c@(InvConflictor _ _ _ :> InvConflictor _ _ _) = invertCommuteNC c commuteNoConflicts (InvConflictor ix xx x :> Conflictor iy yy y) = do iyy' :> xx' <- commute (xx :> invert yy) y':iy' <- mapM (xx' >>*) (y:iy) x':ix' <- mapM (invertFL iyy' >>*) (x:ix) False <- return $ any (conflictsWith y') (x':ix') False <- return $ any (conflictsWith x') iy' return (Conflictor iy' (invert iyy') y' :> InvConflictor ix' xx' x') commuteNoConflicts (Conflictor iy' yy' y' :> InvConflictor ix' xx' x') = do xx :> iyy <- commute (invert yy' :> xx') y:iy <- mapM (*>> xx') (y':iy') x:ix <- mapM (*>> yy') (x':ix') False <- return $ any (conflictsWith y') (x':ix') False <- return $ any (conflictsWith x') iy' return (InvConflictor ix xx x :> Conflictor iy (invert iyy) y) instance PrimPatch prim => Check (RealPatch prim) where isInconsistent = isConsistent instance FromPrim (RealPatch prim) where fromPrim = prim2real instance ToFromPrim (RealPatch prim) where toPrim (Normal p) = Just p toPrim _ = Nothing instance PrimPatch prim => MyEq (RealPatch prim) where (Duplicate x) =\/= (Duplicate y) | x == y = IsEq (Etacilpud x) =\/= (Etacilpud y) | x == y = IsEq (Normal x) =\/= (Normal y) = x =\/= y (Conflictor cx xx x) =\/= (Conflictor cy yy y) | map commuteOrAddIXX cx `eqSet` map commuteOrAddIYY cy && commuteOrAddIXX x == commuteOrAddIYY y = xx =/\= yy where commuteOrAddIXX = commutePrimsOrAddToCtx (invertFL xx) commuteOrAddIYY = commutePrimsOrAddToCtx (invertFL yy) (InvConflictor cx xx x) =\/= (InvConflictor cy yy y) | cx `eqSet` cy && x == y = xx =\/= yy _ =\/= _ = NotEq eqSet :: Eq a => [a] -> [a] -> Bool eqSet [] [] = True eqSet (x:xs) xys | Just ys <- remove1 x xys = eqSet xs ys eqSet _ _ = False remove1 :: Eq a => a -> [a] -> Maybe [a] remove1 x (y : ys) = if x == y then Just ys else (y :) `fmap` remove1 x ys remove1 _ [] = Nothing minus :: Eq a => [a] -> [a] -> Maybe [a] minus xs [] = Just xs minus xs (y:ys) = do xs' <- remove1 y xs xs' `minus` ys invertNon :: PrimPatch prim => Non (RealPatch prim) C(x) -> Non (RealPatch prim) C(x) invertNon (Non c x) | Just rc' <- removeRL nix (reverseFL c) = Non (reverseRL rc') (invert x) | otherwise = commuteOrAddToCtxRL (Normal x :<: reverseFL c) $ non nix where nix = Normal $ invert x nonTouches :: PatchInspect prim => Non (RealPatch prim) C(x) -> [FilePath] nonTouches (Non c x) = listTouchedFiles (c +>+ fromPrim x :>: NilFL) nonHunkMatches :: PatchInspect prim => (BC.ByteString -> Bool) -> Non (RealPatch prim) C(x) -> Bool nonHunkMatches f (Non c x) = hunkMatches f c || hunkMatches f x toNons :: forall p C(x y) . (Conflict p, Patchy p, PatchListFormat p, ToFromPrim p, Nonable p, ShowPatchBasic (PrimOf p)) => FL p C(x y) -> [Non p C(x)] toNons xs = map lastNon $ initsFL xs where lastNon :: Sealed ((p :> FL p) C(x)) -> Non p C(x) lastNon (Sealed xxx) = case lastNon_aux xxx of deps :> p :> _ -> case non p of Non NilFL pp -> Non (reverseRL deps) pp Non ds pp -> errorDoc $ redText "Weird case in toNons" $$ redText "please report this bug!" $$ (case xxx of z :> zs -> showPatch (z :>: zs)) $$ redText "ds are" $$ showPatch ds $$ redText "pp is" $$ showPatch pp reverseFoo :: (p :> FL p) C(x z) -> (RL p :> p) C(x z) reverseFoo (p :> ps) = rf NilRL p ps where rf :: RL p C(a b) -> p C(b c) -> FL p C(c d) -> (RL p :> p) C(a d) rf rs l NilFL = rs :> l rf rs x (y :>: ys) = rf (x :<: rs) y ys lastNon_aux :: (p :> FL p) C(x z) -> (RL p :> p :> RL p) C(x z) lastNon_aux = commuteWhatWeCanRL . reverseFoo initsFL :: Patchy p => FL p C(x y) -> [Sealed ((p :> FL p) C(x))] initsFL NilFL = [] initsFL (x :>: xs) = Sealed (x :> NilFL) : map (\(Sealed (y :> xs')) -> Sealed (x :> y :>: xs')) (initsFL xs) filterConflictsFL :: PrimPatch prim => Non (RealPatch prim) C(x) -> FL prim C(x y) -> (FL prim :> FL prim) C(x y) filterConflictsFL _ NilFL = NilFL :> NilFL filterConflictsFL n (p :>: ps) | Just n' <- commuteOrRemFromCtx (fromPrim p) n = case filterConflictsFL n' ps of p1 :> p2 -> p :>: p1 :> p2 | otherwise = case commuteWhatWeCanFL (p :> ps) of p1 :> p' :> p2 -> case filterConflictsFL n p1 of p1a :> p1b -> p1a :> p1b +>+ p' :>: p2 instance Invert prim => Invert (RealPatch prim) where invert (Duplicate d) = Etacilpud d invert (Etacilpud d) = Duplicate d invert (Normal p) = Normal (invert p) invert (Conflictor x c p) = InvConflictor x c p invert (InvConflictor x c p) = Conflictor x c p instance PrimPatch prim => Commute (RealPatch prim) where commute (x :> y) | Just (y' :> x') <- commuteNoConflicts (assertConsistent x :> assertConsistent y) = Just (y' :> x') -- These patches conflicted, since we failed to commuteNoConflicts in the -- case above. commute (Normal x :> Conflictor a1'nop2 n1'x p1') | Just rn1' <- removeRL x (reverseFL n1'x) = do let p2 : n1nons = reverse $ xx2nons a1'nop2 $ reverseRL (x :<: rn1') a2 = p1' : a1'nop2 ++ n1nons case (a1'nop2, reverseRL rn1', p1') of ([], NilFL, Non c y) | NilFL <- joinEffects c -> Just (Normal y :> Conflictor a1'nop2 (y :>: NilFL) p2) (a1, n1, _) -> Just (Conflictor a1 n1 p1' :> Conflictor a2 NilFL p2) -- Handle using the inverting commuter, and the previous case. N.b. this -- is innefficient, since we'll have to also try commuteNoConflicts again -- (which we know will fail, since we got here). commute c@(InvConflictor _ _ _ :> Normal _) = invertCommute c commute (Conflictor a1 n1 p1 :> Conflictor a2 n2 p2) | Just a2_minus_p1 <- remove1 p1' a2 , not (p2 `dependsUpon` p1') = do let n1nons = map (commutePrimsOrAddToCtx n2) $ xx2nons a1 n1 n2nons = xx2nons a2 n2 Just a2_minus_p1n1 = a2_minus_p1 `minus` n1nons n2n1 = n2 +>+ n1 a1' = map (commutePrimsOrAddToCtx n2) a1 p2ooo = remNons a1' p2 n1' :> n2' <- return $ filterConflictsFL p2ooo n2n1 let n1'n2'nons = xx2nons a2_minus_p1n1 (n1' +>+ n2') n1'nons = take (lengthFL n1') n1'n2'nons n2'nons = drop (lengthFL n1') n1'n2'nons Just a1'nop2 = (a2 ++ n2nons) `minus` (p1' : n1'nons) Just a2'o = fst (allConflictsWith p2 $ a2_minus_p1 ++ n2nons) `minus` n2'nons Just a2' = mapM (commuteOrRemFromCtxFL (xx2patches a1'nop2 n1')) a2'o Just p2' = commuteOrRemFromCtxFL (xx2patches a1'nop2 n1') p2 case (a2', n2', p2') of ([], NilFL, Non c x) -> case joinEffects c of NilFL -> let n1'x = n1' +>+ x :>: NilFL in Just (Normal x :> Conflictor a1'nop2 n1'x p1') _ -> impossible _ -> Just (c1 :> c2) where c1 = Conflictor a2' n2' p2' c2 = Conflictor (p2 : a1'nop2) n1' p1' where (_, rpn2) = geteff a2 n2 p1' = commuteOrAddToCtxRL (reverseFL rpn2) p1 -- Handle using the inverting commuter, and the previous case. This is also -- innefficient, since we'll have to also try commuteNoConflicts again -- (which we know will fail, since we got here). commute c@(InvConflictor _ _ _ :> InvConflictor _ _ _) = invertCommute c commute _ = Nothing instance PrimPatch prim => Merge (RealPatch prim) where merge (InvConflictor _ _ _ :\/: _) = impossible merge (_ :\/: InvConflictor _ _ _) = impossible merge (Etacilpud _ :\/: _) = impossible merge (_ :\/: Etacilpud _) = impossible merge (Duplicate a :\/: Duplicate b) = Duplicate b :/\: Duplicate a -- We had a FIXME comment on this case, why? merge (Duplicate a :\/: b) = b :/\: Duplicate (commuteOrAddToCtx (invert b) a) -- Handle using the swap merge and the previous case. merge m@(_ :\/: Duplicate _) = swapMerge m -- When merging x and y, we do a bunch of what look like "consistency" -- check merges. If the resulting y'' and y are equal, then we succeed. -- If the first case fails, we check for equal patches (which wouldn't -- commute) and return a Duplicate on both sides of the merge, in that -- case. merge (x :\/: y) | Just (y' :> ix') <- commute (invert (assertConsistent x) :> assertConsistent y) , Just (y'' :> _) <- commute (x :> y') , IsEq <- y'' =\/= y = assertConsistent y' :/\: invert (assertConsistent ix') -- If we detect equal patches, we have a duplicate. | IsEq <- x =\/= y , n <- commuteOrAddToCtx (invert x) $ non x = Duplicate n :/\: Duplicate n -- We know that these two patches conflict, and aren't Duplicates, since we -- failed the previous case. We therefore create basic Conflictors, which -- undo the other patch. merge (nx@(Normal x) :\/: ny@(Normal y)) = cy :/\: cx where cy = Conflictor [] (x :>: NilFL) (non ny) cx = Conflictor [] (y :>: NilFL) (non nx) -- If a Normal patch @x@ and a Conflictor @cy@ conflict, we add @x@ to the -- effect of @cy@ on one side, and create a Conflictor that has no effect, -- but has the already-undone and conflicted patch of @cy@ and some foos as -- the already-undone on the other side. -- -- TODO: what is foo? -- Why do we need nyy? I think @x'@ is @x@ in the context of @yy@. merge (Normal x :\/: Conflictor iy yy y) = Conflictor iy yyx y :/\: Conflictor (y : iy ++ nyy) NilFL x' where yyx = yy +>+ x :>: NilFL (x' : nyy) = reverse $ xx2nons iy yyx -- Handle using the swap merge and the previous case. merge m@(Conflictor _ _ _ :\/: Normal _) = swapMerge m -- mH see also cH merge (Conflictor ix xx x :\/: Conflictor iy yy y) = case pullCommonRL (reverseFL xx) (reverseFL yy) of CommonRL rxx1 ryy1 c -> case commuteRLFL (ryy1 :> invertRL rxx1) of Just (ixx' :> ryy') -> let xx' = invert ixx' yy' = reverseRL ryy' y' : iy' = map (commutePrimsOrAddToCtx xx') (y : iy) x' : ix' = map (commutePrimsOrAddToCtx ryy') (x : ix) nyy' = xx2nons iy' yy' nxx' = xx2nons ix' xx' icx = drop (lengthRL rxx1) $ xx2nons ix (reverseRL $ c +<+ rxx1) ic' = map (commutePrimsOrAddToCtx ryy') icx -- +++ is a more efficient version of nub (iy' ++ -- ix') given that we know each element shows up -- only once in either list. ixy' = ic' ++ (iy' +++ ix') c1 = Conflictor (x' : ixy' ++ nxx') yy' y' c2 = Conflictor (y' : ixy' ++ nyy') xx' x' in c1 :/\: c2 Nothing -> impossible instance PatchInspect prim => PatchInspect (RealPatch prim) where listTouchedFiles (Duplicate p) = nonTouches p listTouchedFiles (Etacilpud p) = nonTouches p listTouchedFiles (Normal p) = listTouchedFiles p listTouchedFiles (Conflictor x c p) = nubsort $ concatMap nonTouches x ++ listTouchedFiles c ++ nonTouches p listTouchedFiles (InvConflictor x c p) = nubsort $ concatMap nonTouches x ++ listTouchedFiles c ++ nonTouches p hunkMatches f (Duplicate p) = nonHunkMatches f p hunkMatches f (Etacilpud p) = nonHunkMatches f p hunkMatches f (Normal p) = hunkMatches f p hunkMatches f (Conflictor x c p) = any (nonHunkMatches f) x || hunkMatches f c || nonHunkMatches f p hunkMatches f (InvConflictor x c p) = any (nonHunkMatches f) x || hunkMatches f c || nonHunkMatches f p allConflictsWith :: PrimPatch prim => Non (RealPatch prim) C(x) -> [Non (RealPatch prim) C(x)] -> ([Non (RealPatch prim) C(x)], [Non (RealPatch prim) C(x)]) allConflictsWith x ys = acw $ partition (conflictsWith x) ys where acw ([], nc) = ([], nc) acw (c:cs, nc) = case allConflictsWith c nc of (c1, nc1) -> case acw (cs, nc1) of (xs', nc') -> (c : c1 ++ xs', nc') conflictsWith :: PrimPatch prim => Non (RealPatch prim) C(x) -> Non (RealPatch prim) C(x) -> Bool conflictsWith x y | x `dependsUpon` y || y `dependsUpon` x = False conflictsWith x (Non cy y) = case commuteOrRemFromCtxFL cy x of Just (Non cx' x') -> let iy = fromPrim $ invert y in case commuteFLorComplain (iy :> cx' +>+ fromPrim x' :>: NilFL) of Right _ -> False Left _ -> True Nothing -> True dependsUpon :: PrimPatch prim => Non (RealPatch prim) C(x) -> Non (RealPatch prim) C(x) -> Bool dependsUpon (Non xs _) (Non ys y) = case removeSubsequenceFL (ys +>+ fromPrim y :>: NilFL) xs of Just _ -> True Nothing -> False (+++) :: Eq a => [a] -> [a] -> [a] [] +++ x = x x +++ [] = x (x:xs) +++ xys | Just ys <- remove1 x xys = x : (xs +++ ys) | otherwise = x : (xs +++ xys) swapMerge :: PrimPatch prim => (RealPatch prim :\/: RealPatch prim) C(x y) -> (RealPatch prim :/\: RealPatch prim) C(x y) swapMerge (x :\/: y) = case merge (y :\/: x) of x' :/\: y' -> y' :/\: x' invertCommute :: PrimPatch prim => (RealPatch prim :> RealPatch prim) C(x y) -> Maybe ((RealPatch prim :> RealPatch prim) C(x y)) invertCommute (x :> y) = do ix' :> iy' <- commute (invert y :> invert x) return (invert iy' :> invert ix') invertCommuteNC :: PrimPatch prim => (RealPatch prim :> RealPatch prim) C(x y) -> Maybe ((RealPatch prim :> RealPatch prim) C(x y)) invertCommuteNC (x :> y) = do ix' :> iy' <- commuteNoConflicts (invert y :> invert x) return (invert iy' :> invert ix') -- | 'pullCommon' @xs ys@ returns the set of patches that can be commuted out -- of both @xs@ and @ys@ along with the remnants of both lists pullCommon :: Patchy p => FL p C(o x) -> FL p C(o y) -> Common p C(o x y) pullCommon NilFL ys = Common NilFL NilFL ys pullCommon xs NilFL = Common NilFL xs NilFL pullCommon (x :>: xs) xys | Just ys <- removeFL x xys = case pullCommon xs ys of Common c xs' ys' -> Common (x :>: c) xs' ys' pullCommon (x :>: xs) ys = case commuteWhatWeCanFL (x :> xs) of xs1 :> x' :> xs2 -> case pullCommon xs1 ys of Common c xs1' ys' -> Common c (xs1' +>+ x' :>: xs2) ys' -- | 'Common' @cs xs ys@ represents two sequences of patches that have @cs@ in -- common, in other words @cs +>+ xs@ and @cs +>+ ys@ data Common p C(o x y) where Common :: FL p C(o i) -> FL p C(i x) -> FL p C(i y) -> Common p C(o x y) -- | 'pullCommonRL' @xs ys@ returns the set of patches that can be commuted -- out of both @xs@ and @ys@ along with the remnants of both lists pullCommonRL :: Patchy p => RL p C(x o) -> RL p C(y o) -> CommonRL p C(x y o) pullCommonRL NilRL ys = CommonRL NilRL ys NilRL pullCommonRL xs NilRL = CommonRL xs NilRL NilRL pullCommonRL (x :<: xs) xys | Just ys <- removeRL x xys = case pullCommonRL xs ys of CommonRL xs' ys' c -> CommonRL xs' ys' (x :<: c) pullCommonRL (x :<: xs) ys = case commuteWhatWeCanRL (xs :> x) of xs1 :> x' :> xs2 -> case pullCommonRL xs2 ys of CommonRL xs2' ys' c -> CommonRL (xs2' +<+ x' :<: xs1) ys' c -- | 'CommonRL' @xs ys cs@' represents two sequences of patches that have @cs@ -- in common, in other words @xs +<+ cs@ and @ys +<+ cs@ data CommonRL p C(x y f) where CommonRL :: RL p C(x i) -> RL p C(y i) -> RL p C(i f) -> CommonRL p C(x y f) instance PrimPatch prim => Apply (RealPatch prim) where type ApplyState (RealPatch prim) = ApplyState prim apply p = apply (effect p) instance PrimPatch prim => RepairToFL (RealPatch prim) where applyAndTryToFixFL (Normal p) = mapMaybeSnd (mapFL_FL Normal) `liftM` applyAndTryToFixFL p applyAndTryToFixFL x = do apply x; return Nothing instance PatchListFormat (RealPatch prim) where -- In principle we could use ListFormatDefault when prim /= V1 Prim patches, -- as those are the only case where we need to support a legacy on-disk -- format. In practice we don't expect RealPatch to be used with any other -- argument anyway, so it doesn't matter. patchListFormat = ListFormatV2 duplicate, etacilpud, conflictor, rotcilfnoc :: String duplicate = "duplicate" etacilpud = "etacilpud" conflictor = "conflictor" rotcilfnoc = "rotcilfnoc" instance PrimPatch prim => ShowPatchBasic (RealPatch prim) where showPatch (Duplicate d) = blueText duplicate $$ showNon d showPatch (Etacilpud d) = blueText etacilpud $$ showNon d showPatch (Normal p) = showPrim NewFormat p showPatch (Conflictor i NilFL p) = blueText conflictor <+> showNons i <+> blueText "[]" $$ showNon p showPatch (Conflictor i cs p) = blueText conflictor <+> showNons i <+> blueText "[" $$ showPrimFL NewFormat cs $$ blueText "]" $$ showNon p showPatch (InvConflictor i NilFL p) = blueText rotcilfnoc <+> showNons i <+> blueText "[]" $$ showNon p showPatch (InvConflictor i cs p) = blueText rotcilfnoc <+> showNons i <+> blueText "[" $$ showPrimFL NewFormat cs $$ blueText "]" $$ showNon p instance PrimPatch prim => ShowPatch (RealPatch prim) where showContextPatch (Normal p) = showContextPatch p showContextPatch c = return $ showPatch c summary = plainSummary summaryFL = plainSummary thing _ = "change" instance PrimPatch prim => ReadPatch (RealPatch prim) where readPatch' = do skipSpace let str = string . BC.pack readConflictorPs = do i <- readNons ps <- bracketedFL (readPrim NewFormat) '[' ']' p <- readNon return (i, ps, p) choice [ do str duplicate p <- readNon return $ Sealed $ Duplicate p , do str etacilpud p <- readNon return $ Sealed $ Etacilpud p , do str conflictor (i, Sealed ps, p) <- readConflictorPs return $ Sealed $ Conflictor i (unsafeCoerceP ps) p , do str rotcilfnoc (i, Sealed ps, p) <- readConflictorPs return $ Sealed $ InvConflictor i ps p , do Sealed p <- readPrim NewFormat return $ Sealed $ Normal p ] instance PrimPatch prim => Show (RealPatch prim C(x y)) where show p = renderString $ showPatch p instance PrimPatch prim => Show2 (RealPatch prim) where showDict2 = ShowDictClass instance PrimPatch prim => Nonable (RealPatch prim) where non (Duplicate d) = d non (Etacilpud d) = invertNon d -- FIXME !!! ??? non (Normal p) = Non NilFL p non (Conflictor _ xx x) = commutePrimsOrAddToCtx (invertFL xx) x non (InvConflictor _ _ n) = invertNon n instance PrimPatch prim => Effect (RealPatch prim) where effect (Duplicate _) = NilFL effect (Etacilpud _) = NilFL effect (Normal p) = p :>: NilFL effect (Conflictor _ e _) = invert e effect (InvConflictor _ e _) = e effectRL (Duplicate _) = NilRL effectRL (Etacilpud _) = NilRL effectRL (Normal p) = p :<: NilRL effectRL (Conflictor _ e _) = invertFL e effectRL (InvConflictor _ e _) = reverseFL e instance IsHunk prim => IsHunk (RealPatch prim) where isHunk rp = do Normal p <- return rp isHunk p darcs-2.8.4/src/Darcs/Patch/Apply.hs0000644001765600176560000000622612104371431016452 0ustar ganeshganesh-- Copyright (C) 2002-2005 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP, MultiParamTypeClasses #-} #include "gadts.h" -- | -- Module : Darcs.Patch.Apply -- Copyright : 2002-2005 David Roundy -- License : GPL -- Maintainer : darcs-devel@darcs.net -- Stability : experimental -- Portability : portable module Darcs.Patch.Apply ( Apply(..) , applyToFilePaths , applyToTree , applyToState , effectOnFilePaths ) where import Prelude hiding ( catch, pi ) import Control.Applicative ( (<$>) ) import Control.Arrow ( (***) ) import Storage.Hashed.Tree( Tree ) import Storage.Hashed.Monad( virtualTreeMonad ) import Darcs.Patch.ApplyMonad ( ApplyMonad(..), withFileNames, ApplyMonadTrans(..) ) import Darcs.Patch.FileName( fn2fp, fp2fn ) import Darcs.Witnesses.Ordered ( FL(..), RL(..) ) class Apply p where type ApplyState p :: (* -> *) -> * apply :: ApplyMonad m (ApplyState p) => p C(x y) -> m () instance Apply p => Apply (FL p) where type ApplyState (FL p) = ApplyState p apply NilFL = return () apply (p:>:ps) = apply p >> apply ps instance Apply p => Apply (RL p) where type ApplyState (RL p) = ApplyState p apply NilRL = return () apply (p:<:ps) = apply ps >> apply p effectOnFilePaths :: (Apply p, ApplyState p ~ Tree) => p C(x y) -> [FilePath] -> [FilePath] effectOnFilePaths p fps = fps' where (_, fps', _) = applyToFilePaths p Nothing fps applyToFilePaths :: (Apply p, ApplyState p ~ Tree) => p C(x y) -> Maybe [(FilePath, FilePath)] -> [FilePath] -> ([FilePath], [FilePath], [(FilePath, FilePath)]) applyToFilePaths pa ofpos fs = toFPs $ withFileNames ofnos fns (apply pa) where fns = map fp2fn fs ofnos = map (fp2fn *** fp2fn) <$> ofpos toFPs (affected, new, renames) = (map fn2fp affected, map fn2fp new, map (fn2fp *** fn2fp) renames) -- | Apply a patch to a 'Tree', yielding a new 'Tree'. applyToTree :: (Apply p, Functor m, Monad m, ApplyState p ~ Tree) => p C(x y) -> Tree m -> m (Tree m) applyToTree patch t = snd <$> virtualTreeMonad (apply patch) t applyToState :: forall p m C(x y). (Apply p, ApplyMonadTrans m (ApplyState p)) => p C(x y) -> (ApplyState p) m -> m ((ApplyState p) m) applyToState patch t = snd <$> runApplyMonad (apply patch) t darcs-2.8.4/src/Darcs/Patch/ApplyMonad.hs0000644001765600176560000002045612104371431017432 0ustar ganeshganesh{-# LANGUAGE TypeSynonymInstances, MultiParamTypeClasses #-} -- Copyright (C) 2010, 2011 Petr Rockai -- -- 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. module Darcs.Patch.ApplyMonad( ApplyMonad(..), ApplyMonadTrans(..), withFileNames, withFiles, ToTree(..) ) where import qualified Data.ByteString as B import qualified Data.ByteString.Lazy as BL import qualified Data.Map as M import qualified Storage.Hashed.Monad as HSM import Storage.Hashed.Tree ( Tree ) import ByteStringUtils( linesPS, unlinesPS ) import Darcs.Patch.FileName( FileName, movedirfilename, fn2fp, isParentOrEqOf ) import Storage.Hashed.AnchoredPath( floatPath, AnchoredPath ) import Control.Monad.State.Strict import Control.Monad.Identity( Identity ) import Darcs.MonadProgress -- TODO should UUID/Object live somewhere more central? import Darcs.Patch.Prim.V3.ObjectMap ( UUID, ObjectMap, DirContent ) fn2ap :: FileName -> AnchoredPath fn2ap = floatPath . fn2fp class ToTree s where toTree :: s m -> Tree m instance ToTree Tree where toTree = id class (Functor m, Monad m, ApplyMonad (ApplyMonadOver m state) state) => ApplyMonadTrans m (state :: (* -> *) -> *) where type ApplyMonadOver m state :: * -> * runApplyMonad :: (ApplyMonadOver m state) x -> state m -> m (x, state m) instance (Functor m, Monad m) => ApplyMonadTrans m Tree where type ApplyMonadOver m Tree = HSM.TreeMonad m runApplyMonad = HSM.virtualTreeMonad class (Functor m, Monad m, Functor (ApplyMonadBase m), Monad (ApplyMonadBase m), ToTree state) -- ApplyMonadOver (ApplyMonadBase m) ~ m is *not* required in general, -- since ApplyMonadBase is not injective => ApplyMonad m (state :: (* -> *) -> *) where type ApplyMonadBase m :: * -> * nestedApply :: m x -> state (ApplyMonadBase m) -> m (x, state (ApplyMonadBase m)) liftApply :: (state (ApplyMonadBase m) -> (ApplyMonadBase m) x) -> state (ApplyMonadBase m) -> m (x, state (ApplyMonadBase m)) getApplyState :: m (state (ApplyMonadBase m)) putApplyState :: state m -> m () -- a semantic, ObjectMap-based interface for patch application editFile :: (state ~ ObjectMap) => UUID -> (B.ByteString -> B.ByteString) -> m () editDirectory :: (state ~ ObjectMap) => UUID -> (DirContent -> DirContent) -> m () -- a semantic, Tree-based interface for patch application mDoesDirectoryExist :: (state ~ Tree) => FileName -> m Bool mDoesFileExist :: (state ~ Tree) => FileName -> m Bool mReadFilePS :: (state ~ Tree) => FileName -> m B.ByteString mReadFilePSs :: (state ~ Tree) => FileName -> m [B.ByteString] mReadFilePSs f = linesPS `fmap` mReadFilePS f mCreateDirectory :: (state ~ Tree) => FileName -> m () mRemoveDirectory :: (state ~ Tree) => FileName -> m () mCreateFile :: (state ~ Tree) => FileName -> m () mCreateFile f = mModifyFilePS f $ \_ -> return B.empty mRemoveFile :: (state ~ Tree) => FileName -> m () mRename :: (state ~ Tree) => FileName -> FileName -> m () mModifyFilePS :: (state ~ Tree) => FileName -> (B.ByteString -> m B.ByteString) -> m () mModifyFilePSs :: (state ~ Tree) => FileName -> ([B.ByteString] -> m [B.ByteString]) -> m () mModifyFilePSs f j = mModifyFilePS f (fmap unlinesPS . j . linesPS) mChangePref :: (state ~ Tree) => String -> String -> String -> m () mChangePref _ _ _ = return () instance (Functor m, Monad m) => ApplyMonad (HSM.TreeMonad m) Tree where type ApplyMonadBase (HSM.TreeMonad m) = m getApplyState = gets HSM.tree nestedApply a start = lift $ runApplyMonad a start liftApply a start = do x <- gets HSM.tree lift $ runApplyMonad (lift $ a x) start -- putApplyState needs some support from HSM mDoesDirectoryExist d = HSM.directoryExists (fn2ap d) mDoesFileExist d = HSM.fileExists (fn2ap d) mReadFilePS p = B.concat `fmap` BL.toChunks `fmap` HSM.readFile (fn2ap p) mModifyFilePS p j = do have <- HSM.fileExists (fn2ap p) x <- if have then B.concat `fmap` BL.toChunks `fmap` HSM.readFile (fn2ap p) else return B.empty HSM.writeFile (fn2ap p) . BL.fromChunks . (:[]) =<< j x mCreateDirectory p = HSM.createDirectory (fn2ap p) mRename from to = HSM.rename (fn2ap from) (fn2ap to) mRemoveDirectory = HSM.unlink . fn2ap mRemoveFile = HSM.unlink . fn2ap -- Latest name, current original name. type OrigFileNameOf = (FileName, FileName) -- Touched files, new file list (after removes etc.) and rename details type FilePathMonadState = ([FileName], [FileName], [OrigFileNameOf]) type FilePathMonad = State FilePathMonadState -- |trackOrigRename takes an old and new name and attempts to apply the mapping -- to the OrigFileNameOf pair. If the old name is the most up-to-date name of -- the file in question, the first element of the OFNO will match, otherwise if -- the up-to-date name was originally old, the second element will match. trackOrigRename :: FileName -> FileName -> OrigFileNameOf -> OrigFileNameOf trackOrigRename old new pair@(latest, from) | old `isParentOrEqOf` latest = (latest, movedirfilename old new latest) | old `isParentOrEqOf` from = (latest, movedirfilename old new from) | otherwise = pair -- |withFileNames takes a maybe list of existing rename-pairs, a list of -- filenames and an action, and returns the resulting triple of affected files, -- updated filename list and new rename details. If the rename-pairs are not -- present, a new list is generated from the filesnames. withFileNames :: (Maybe [OrigFileNameOf]) -> [FileName] -> FilePathMonad a -> FilePathMonadState withFileNames mbofnos fps x = execState x ([], fps, ofnos) where ofnos = maybe (map (\y -> (y, y)) fps) id mbofnos instance ApplyMonad FilePathMonad Tree where type ApplyMonadBase FilePathMonad = Identity -- We can't check it actually is a directory here mDoesDirectoryExist d = gets $ \(_, fs, _) -> d `elem` fs mCreateDirectory = mCreateFile mCreateFile f = modify $ \(ms, fs, rns) -> (f : ms, fs, rns) mRemoveFile f = modify $ \(ms, fs, rns) -> (f : ms, filter (/= f) fs, rns) mRemoveDirectory = mRemoveFile mRename a b = modify $ \(ms, fs, rns) -> ( a : b : ms , map (movedirfilename a b) fs , map (trackOrigRename a b) rns) mModifyFilePS f _ = mCreateFile f instance MonadProgress FilePathMonad where runProgressActions = silentlyRunProgressActions type RestrictedApply = State (M.Map FileName B.ByteString) instance ApplyMonad RestrictedApply Tree where type ApplyMonadBase RestrictedApply = Identity mDoesDirectoryExist _ = return True mCreateDirectory _ = return () mRemoveFile f = modify $ M.delete f mRemoveDirectory _ = return () mRename a b = modify $ M.mapKeys (movedirfilename a b) mModifyFilePS f j = do look <- gets $ M.lookup f case look of Nothing -> return () Just bits -> do new <- j bits modify $ M.insert f new instance MonadProgress RestrictedApply where runProgressActions = silentlyRunProgressActions withFiles :: [(FileName, B.ByteString)] -> RestrictedApply a -> [(FileName, B.ByteString)] withFiles p x = M.toList $ execState x $ M.fromList p darcs-2.8.4/src/Darcs/Patch/Bracketed.hs0000644001765600176560000000336412104371431017251 0ustar ganeshganeshmodule Darcs.Patch.Bracketed ( Bracketed(..), mapBracketed, unBracketed , BracketedFL, mapBracketedFL_FL, unBracketedFL ) where #include "gadts.h" import Darcs.Patch.Format ( PatchListFormat ) import Darcs.Witnesses.Ordered ( FL(..), mapFL_FL, concatFL ) -- |This type exists for legacy support of on-disk format patch formats. -- It is a wrapper type that explicitly tracks the nesting of braces and parens -- in the on-disk representation of such patches. It is used as an intermediate -- form when reading such patches normally, and also for round-tripping such -- patches when checking the hash in bundles. -- It shouldn't be used for anything else. data Bracketed p C(x y) where Singleton :: p C(x y) -> Bracketed p C(x y) -- A single patch, not wrapped in anything Braced :: BracketedFL p C(x y) -> Bracketed p C(x y) -- A list of patches, wrapped in {} Parens :: BracketedFL p C(x y) -> Bracketed p C(x y) -- A list of patches, wrapped in () type BracketedFL p C(x y) = FL (Bracketed p) C(x y) unBracketed :: Bracketed p C(x y) -> FL p C(x y) unBracketed (Singleton p) = p :>: NilFL unBracketed (Braced ps) = unBracketedFL ps unBracketed (Parens ps) = unBracketedFL ps unBracketedFL :: BracketedFL p C(x y) -> FL p C(x y) unBracketedFL = concatFL . mapFL_FL unBracketed mapBracketed :: (FORALL(a b) p C(a b) -> q C(a b)) -> Bracketed p C(x y) -> Bracketed q C(x y) mapBracketed f (Singleton p) = Singleton (f p) mapBracketed f (Braced ps) = Braced (mapBracketedFL_FL f ps) mapBracketed f (Parens ps) = Parens (mapBracketedFL_FL f ps) mapBracketedFL_FL :: (FORALL(a b) p C(a b) -> q C(a b)) -> BracketedFL p C(x y) -> BracketedFL q C(x y) mapBracketedFL_FL f ps = mapFL_FL (mapBracketed f) ps instance PatchListFormat (Bracketed p) darcs-2.8.4/src/Darcs/Patch/Bundle.hs0000644001765600176560000002751212104371431016577 0ustar ganeshganesh-- Copyright (C) 2002-2004,2007 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP #-} #include "gadts.h" module Darcs.Patch.Bundle ( hashBundle, makeBundle2, makeBundleN, scanBundle, contextPatches, scanContext, patchFilename, getContext, parseBundle ) where import Data.Char ( isAlpha, toLower, isDigit, isSpace ) import Darcs.Patch.PatchInfoAnd ( PatchInfoAnd, piap, fmapFL_PIAP, patchInfoAndPatch, unavailable, hopefully ) import Darcs.Patch ( RepoPatch, Named, showPatch, showContextPatch, readPatchPartial ) import Darcs.Patch.Apply( ApplyState ) import Darcs.Patch.Bracketed ( Bracketed, unBracketedFL ) import Darcs.Patch.Bracketed.Instances () import Darcs.Patch.Format ( PatchListFormat ) import Darcs.Patch.Info ( PatchInfo, readPatchInfo, showPatchInfo, humanFriendly, isTag ) import Darcs.Patch.Set ( PatchSet(..), Tagged(..), SealedPatchSet ) import Darcs.Patch.Show ( ShowPatchBasic ) import Darcs.Patch.Depends ( slightlyOptimizePatchset ) import Darcs.Patch.ReadMonads ( parseStrictly ) import Darcs.Patch.PatchInfoAnd( info ) #ifdef GADT_WITNESSES import Darcs.Patch.Set ( Origin ) #endif import Darcs.Witnesses.Unsafe ( unsafeCoerceP ) import Darcs.Witnesses.Ordered ( RL(..), FL(..), (:>)(..), reverseFL, (+<+), mapFL, mapFL_FL, mapRL ) import Printer ( Doc, renderPS, newline, text, ($$), (<>), vcat, vsep, renderString ) import ByteStringUtils ( linesPS, unlinesPS, dropSpace, substrPS) import qualified Data.ByteString as B (ByteString, length, null, drop, isPrefixOf) import qualified Data.ByteString.Char8 as BC (unpack, break, pack) import SHA1( sha1PS ) import Darcs.Witnesses.Sealed ( Sealed(Sealed)) import Storage.Hashed.Tree( Tree ) import Storage.Hashed.Monad( virtualTreeIO ) -- |hashBundle creates a SHA1 string of a given a FL of named patches. This -- allows us to ensure that the patches in a received patchBundle have not been -- modified in transit. hashBundle :: (PatchListFormat p, ShowPatchBasic p) => FL (Named p) C(x y) -> String hashBundle to_be_sent = sha1PS $ renderPS $ vcat (mapFL showPatch to_be_sent) <> newline makeBundleN :: (ApplyState p ~ Tree, RepoPatch p) => Maybe (Tree IO) -> PatchSet p C(start x) -> FL (Named p) C(x y) -> IO Doc makeBundleN the_s (PatchSet ps (Tagged t _ _ :<: _)) to_be_sent = makeBundle2 the_s (ps +<+ (t :<: NilRL)) to_be_sent to_be_sent makeBundleN the_s (PatchSet ps NilRL) to_be_sent = makeBundle2 the_s ps to_be_sent to_be_sent -- | In makeBundle2, it is presumed that the two patch sequences are -- identical, but that they may be lazily generated. If two different -- patch sequences are passed, a bundle with a mismatched hash will be -- generated, which is not the end of the world, but isn't very useful -- either. makeBundle2 :: (ApplyState p ~ Tree, RepoPatch p) => Maybe (Tree IO) -> RL (PatchInfoAnd p) C(start x) -> FL (Named p) C(x y) -> FL (Named p) C(x y) -> IO Doc makeBundle2 the_s common' to_be_sent to_be_sent2 = do patches <- case the_s of Just tree -> fst `fmap` virtualTreeIO (showContextPatch to_be_sent) tree Nothing -> return (vsep $ mapFL showPatch to_be_sent) return $ format patches where format the_new = text "" $$ text "New patches:" $$ text "" $$ the_new $$ text "" $$ text "Context:" $$ text "" $$ (vcat $ map showPatchInfo common) $$ text "Patch bundle hash:" $$ text (hashBundle to_be_sent2) $$ text "" common = mapRL info common' parseBundle ::forall p. RepoPatch p => B.ByteString -> Either String (Sealed ((PatchSet p :> FL (PatchInfoAnd p)) C(Origin))) parseBundle ps | B.null ps = Left "Bad patch bundle!" | otherwise = case sillyLex ps of ("New patches:",rest) -> case getPatches rest of (Sealed bracketedPatches, rest') -> case sillyLex rest' of ("Context:", rest'') -> case getContext rest'' of (cont,maybe_hash) -> case substrPS (BC.pack "Patch bundle hash:") maybe_hash of Just n -> if hashBundle (mapFL_FL hopefully bracketedPatches) == fst (sillyLex $ snd $ sillyLex $ B.drop n maybe_hash) then Right $ sealContextWithPatches cont bracketedPatches else Left $ "Patch bundle failed hash!\n" ++ "This probably means that the patch has been "++ "corrupted by a mailer.\n"++ "The most likely culprit is CRLF newlines." Nothing -> Right $ sealContextWithPatches cont bracketedPatches (a,r) -> Left $ "Malformed patch bundle: '"++a++"' is not 'Context:'" ++ "\n" ++ BC.unpack r ("Context:",rest) -> case getContext rest of (cont, rest') -> case sillyLex rest' of ("New patches:", rest'') -> case getPatches rest'' of (Sealed bracketedPatches, _) -> Right $ sealContextWithPatches cont bracketedPatches (a,_) -> Left $ "Malformed patch bundle: '" ++ a ++ "' is not 'New patches:'" ("-----BEGIN PGP SIGNED MESSAGE-----",rest) -> parseBundle $ filterGpgDashes rest (_,rest) -> parseBundle rest where sealContextWithPatches :: RepoPatch p => [PatchInfo] -> FL (PatchInfoAnd (Bracketed p)) C(x y) -> Sealed ((PatchSet p :> FL (PatchInfoAnd p)) C(Origin)) sealContextWithPatches context bracketedPatches = let patches = mapFL_FL (fmapFL_PIAP unBracketedFL) bracketedPatches in case reverse context of (x:ry) | isTag x -> Sealed $ (PatchSet (unavailablePatches (reverse ry)) (Tagged (piUnavailable x) Nothing NilRL :<: NilRL) :> patches) _ -> Sealed ((PatchSet (unavailablePatches context) NilRL) :> patches) -- The above NilRLs aren't quite right, because ther *are* -- earlier patches, but we can't set this to undefined -- because there are situations where we look at the rest. -- :{ scanBundle ::forall p . RepoPatch p => B.ByteString -> Either String (SealedPatchSet p C(Origin)) scanBundle bundle = do Sealed ((PatchSet recent tagged):>ps) <- parseBundle bundle return . Sealed $ PatchSet (reverseFL ps +<+ recent) tagged -- |filterGpgDashes unescapes a clearsigned patch, which will have had any -- lines starting with dashes escaped with a leading "- ". filterGpgDashes :: B.ByteString -> B.ByteString filterGpgDashes ps = unlinesPS $ map drop_dashes $ takeWhile (/= BC.pack "-----END PGP SIGNED MESSAGE-----") $ dropWhile not_context_or_newpatches $ linesPS ps where drop_dashes x = if B.length x < 2 then x else if BC.pack "- " `B.isPrefixOf` x then B.drop 2 x else x not_context_or_newpatches s = (s /= BC.pack "Context:") && (s /= BC.pack "New patches:") -- |unavailablePatches converts a list of PatchInfos into a RL of PatchInfoAnd -- Unavailable patches. This is used to represent the Context of a patchBundle. unavailablePatches :: RepoPatch p => [PatchInfo] -> RL (PatchInfoAnd p) C(x y) unavailablePatches [] = unsafeCoerceP NilRL unavailablePatches (x:xs) = piUnavailable x :<: unavailablePatches xs -- |piUnavailable returns an Unavailable within a PatchInfoAnd given a -- PatchInfo. piUnavailable :: RepoPatch p => PatchInfo -> PatchInfoAnd p C(x y) piUnavailable i = (i `patchInfoAndPatch` unavailable ("Patch not stored in patch bundle:\n" ++ renderString (humanFriendly i))) -- |getContext parses a context list, returning a tuple containing the list, -- and remaining ByteString input. getContext :: B.ByteString -> ([PatchInfo],B.ByteString) getContext ps = case parseStrictly readPatchInfo ps of Just (pinfo,r') -> case getContext r' of (pis,r'') -> (pinfo:pis, r'') Nothing -> ([],ps) -- |(-:-) is used to build up a Sealed FL of patches and tuple it, along with -- any unconsumed input. (-:-) :: a C(x y) -> (Sealed (FL a C(y)),b) -> (Sealed (FL a C(x)),b) p -:- (Sealed ps, r) = (Sealed (p:>:ps), r) -- |getPatches attempts to parse a sequence of patches from a ByteString, -- returning the FL of as many patches-with-info as were successfully parsed, -- along with any unconsumed input. getPatches :: RepoPatch p => B.ByteString -> (Sealed (FL (PatchInfoAnd (Bracketed p)) C(x)), B.ByteString) getPatches ps = case parseStrictly readPatchInfo ps of Nothing -> (Sealed NilFL, ps) Just (pinfo,_) -> case readPatchPartial ps of Nothing -> (Sealed NilFL, ps) Just (Sealed p, r) -> (pinfo `piap` p) -:- getPatches r -- |sillyLex takes a ByteString and breaks it upon the first newline, having -- removed any leading spaces. The before-newline part is unpacked to a String, -- and tupled up with the remaining ByteString. sillyLex :: B.ByteString -> (String, B.ByteString) sillyLex ps = (BC.unpack a, b) where (a, b) = BC.break (== '\n') (dropSpace ps) contextPatches :: RepoPatch p => PatchSet p C(Origin x) -> (PatchSet p :> (RL (PatchInfoAnd p))) C(Origin x) contextPatches set = case slightlyOptimizePatchset set of PatchSet ps (Tagged t _ ps' :<: ts) -> (PatchSet ps' ts) :> (ps +<+ (t :<: NilRL)) PatchSet ps NilRL -> (PatchSet NilRL NilRL :> ps) -- are the type witnesses sensible? scanContext :: RepoPatch p => B.ByteString -> PatchSet p C(Origin x) scanContext ps | B.null ps = error "Bad context!" | otherwise = case sillyLex ps of ("Context:",rest) -> case getContext rest of (cont@(_:_), _) | isTag (last cont) -> PatchSet (unavailablePatches $ init cont) (Tagged (piUnavailable $ last cont) Nothing NilRL :<: NilRL) (cont, _) -> PatchSet (unavailablePatches cont) NilRL ("-----BEGIN PGP SIGNED MESSAGE-----",rest) -> scanContext $ filterGpgDashes rest (_,rest) -> scanContext rest -- |patchFilename maps a patch description string to a safe (lowercased, spaces -- removed and ascii-only characters) patch filename. patchFilename :: String -> String patchFilename the_summary = name ++ ".dpatch" where name = map safeFileChar the_summary safeFileChar c | isAlpha c = toLower c | isDigit c = c | isSpace c = '-' safeFileChar _ = '_' darcs-2.8.4/src/Darcs/Patch/Choices.hs0000644001765600176560000004243412104371431016743 0ustar ganeshganesh-- Copyright (C) 2002-2004 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP #-} #include "gadts.h" -- | PatchChoices divides a sequence of patches into three sets: "first", -- "middle" and "last", such that all patches can be applied, if you first -- apply the first ones then the middle ones and then the last ones. -- Obviously if there are dependencies between the patches that will put a -- constraint on how you can choose to divide them up. The PatchChoices data -- type and associated functions are here to deal with many of the common -- cases that come up when choosing a subset of a group of patches. -- -- 'forceLast' tells PatchChoices that a particular patch is required to be in -- the "last" group, which also means that any patches that depend on it -- must be in the "last" group. -- -- Internally, a PatchChoices doesn't always reorder the patches until -- it is asked for the final output (e.g. by 'get_first_choice'). -- Instead, each patch is placed in a state of definitely first, -- definitely last and undecided; undecided leans towards -- "middle". The patches that are first are commuted to the head -- immediately, but patches that are middle and last are mixed -- together. In case you're wondering about the first-middle-last -- language, it's because in some cases the "yes" answers will be last -- (as is the case for the revert command), and in others first (as in -- record, pull and push). -- -- Some patch marked "middle" may in fact be unselectable because of -- dependencies: when a patch is marked "last", its dependencies are -- not updated until patchSlot is called on them. module Darcs.Patch.Choices ( PatchChoices, patchChoices, patchChoicesTps, patchChoicesTpsSub, patchSlot, patchSlot', getChoices, refineChoices, separateFirstMiddleFromLast, separateFirstFromMiddleLast, forceFirst, forceFirsts, forceLast, forceLasts, forceMatchingFirst, forceMatchingLast, selectAllMiddles, makeUncertain, makeEverythingLater, makeEverythingSooner, TaggedPatch, Tag, tag, tpPatch, Slot(..), substitute ) where import Control.Monad.Identity ( Identity ) import Control.Monad.State ( StateT(..) ) import Prelude hiding ( pred ) import Darcs.Patch ( Patchy, commuteRL, commute, merge, listTouchedFiles, hunkMatches , invert ) import Darcs.Patch.Merge ( Merge ) import Darcs.Patch.Permutations ( commuteWhatWeCanRL, commuteWhatWeCanFL ) import Darcs.Patch.Patchy ( Invert, Commute, PatchInspect ) import Darcs.Witnesses.Eq ( MyEq(..), EqCheck(..) ) import Darcs.Witnesses.Unsafe ( unsafeCoerceP ) import Darcs.Witnesses.Ordered ( FL(..), RL(..), (:>)(..), (:\/:)(..), (:/\:)(..), (:||:)(..), zipWithFL, mapFL_FL, concatFL, (+>+), reverseRL, anyFL ) import Darcs.Witnesses.Sealed ( Sealed2(..) ) #include "impossible.h" -- | 'TG' @mp i@ acts as a temporary identifier to help us keep track of patches -- during the selection process. These are useful for finding patches that -- may have moved around during patch selection (being pushed forwards or -- backwards as dependencies arise). -- -- The identifier is implemented as a tuple @TG mp i@. The @i@ is just some -- arbitrary label, expected to be unique within the patches being -- scrutinised. The @mp@ is motivated by patch splitting; it -- provides a convenient way to generate a new identifier from the patch -- being split. For example, if we split a patch identified as @TG Nothing -- 5@, the resulting sub-patches could be identified as @TG (TG Nothing 5) -- 1@, @TG (TG Nothing 5) 2@, etc. data Tag = TG (Maybe Tag) Integer deriving ( Eq, Ord ) data TaggedPatch p C(x y) = TP Tag (p C(x y)) -- | The @Bool@ parameter indicates whether the patch has been explicitely -- selected (or rejected) by the user. data PatchChoice p C(x y) = PC { pcPatch :: (TaggedPatch p C(x y)) , _pcChoice :: Bool} data PatchChoices p C(x y) where PCs { pcsFirsts :: FL (TaggedPatch p) C(x m) , pcsLasts :: FL (PatchChoice p) C(m y)} :: PatchChoices p C(x y) -- | See module documentation for 'Darcs.Patch.Choices' data Slot = InFirst | InMiddle | InLast tag :: TaggedPatch p C(x y) -> Tag tag (TP tg _) = tg tpPatch :: TaggedPatch p C(x y) -> p C(x y) tpPatch (TP _ p) = p liftTP :: (p C(x y) -> p C(a b)) -> (TaggedPatch p C(x y) -> TaggedPatch p C(a b)) liftTP f (TP t p) = TP t (f p) -- This is dangerous if two patches from different tagged series are compared -- ideally Tag (and hence TaggedPatch/PatchChoices) would have a witness type -- to represent the originally tagged sequence. compareTags :: TaggedPatch p C(a b) -> TaggedPatch p C(c d) -> EqCheck C((a, b) (c, d)) compareTags (TP t1 _) (TP t2 _) = if t1 == t2 then unsafeCoerceP IsEq else NotEq instance MyEq p => MyEq (TaggedPatch p) where unsafeCompare (TP t1 p1) (TP t2 p2) = t1 == t2 && unsafeCompare p1 p2 instance Invert p => Invert (TaggedPatch p) where invert = liftTP invert instance Commute p => Commute (TaggedPatch p) where commute (TP t1 p1 :> TP t2 p2) = do p2' :> p1' <- commute (p1 :> p2) return (TP t2 p2' :> TP t1 p1') instance PatchInspect p => PatchInspect (TaggedPatch p) where listTouchedFiles (TP _ p) = listTouchedFiles p hunkMatches f (TP _ p) = hunkMatches f p instance Merge p => Merge (TaggedPatch p) where merge (TP t1 p1 :\/: TP t2 p2) = case merge (p1 :\/: p2) of p2' :/\: p1' -> TP t2 p2' :/\: TP t1 p1' instance Commute p => Commute (PatchChoice p) where commute (PC p1 c1 :> PC p2 c2) = do p2' :> p1' <- commute (p1 :> p2) return (PC p2' c2 :> PC p1' c1) instance PatchInspect p => PatchInspect (PatchChoice p) where listTouchedFiles (PC p _) = listTouchedFiles p hunkMatches f (PC p _) = hunkMatches f p instance Merge p => Merge (PatchChoice p) where merge (PC tp1 c1 :\/: PC tp2 c2) = case merge (tp1 :\/: tp2) of tp2' :/\: tp1' -> PC tp2' c2 :/\: PC tp1' c1 patchChoices :: Patchy p => FL p C(x y) -> PatchChoices p C(x y) patchChoices = fst . patchChoicesTps -- |Tag a sequence of patches as subpatches of an existing tag. This is intended for -- use when substituting a patch for an equivalent patch or patches. patchChoicesTpsSub :: Patchy p => Maybe Tag -> FL p C(x y) -> (PatchChoices p C(x y), FL (TaggedPatch p) C(x y)) patchChoicesTpsSub tg ps = let tps = zipWithFL TP (map (TG tg) [1..]) ps in (PCs NilFL (mapFL_FL (\tp -> PC tp False) tps), tps) -- |Tag a sequence of patches. patchChoicesTps :: Patchy p => FL p C(x y) -> (PatchChoices p C(x y), FL (TaggedPatch p) C(x y)) patchChoicesTps = patchChoicesTpsSub Nothing instance MyEq p => MyEq (PatchChoice p) where unsafeCompare (PC tp1 _) (PC tp2 _) = unsafeCompare tp1 tp2 separateFirstFromMiddleLast :: Patchy p => PatchChoices p C(x z) -> (FL (TaggedPatch p) :> FL (TaggedPatch p)) C(x z) separateFirstFromMiddleLast (PCs f l) = f :> mapFL_FL (\ (PC tp _) -> tp) l separateFirstMiddleFromLast :: Patchy p => PatchChoices p C(x z) -> (FL (TaggedPatch p) :> FL (TaggedPatch p)) C(x z) separateFirstMiddleFromLast (PCs f l) = case pushLasts l of (m :> l') -> f +>+ m :> l' -- | @getChoices@ evaluates a @PatchChoices@ into the first, middle and last sequences -- by doing the commutes that were needed. getChoices :: Patchy p => PatchChoices p C(x y) -> (FL (TaggedPatch p) :> FL (TaggedPatch p) :> FL (TaggedPatch p)) C(x y) getChoices (PCs f l) = case pushLasts l of (m :> l') -> f :> m :> l' pushLasts :: Patchy p => FL (PatchChoice p) C(x y) -> (FL (TaggedPatch p) :> FL (TaggedPatch p)) C(x y) pushLasts NilFL = NilFL :> NilFL pushLasts (PC tp False :>: pcs) = case pushLasts pcs of (m :> l) -> (tp :>: m) :> l pushLasts (PC tp True :>: pcs) = case pushLasts pcs of (m :> l) -> case commuteWhatWeCanFL (tp :> m) of (m' :> tp' :> deps) -> m' :> (tp' :>: deps +>+ l) -- | @refineChoices act@ performs @act@ on the middle part of a sequence -- of choices, in order to hopefully get more patches into the @first@ and -- @last@ parts of a @PatchChoices@. refineChoices :: (Patchy p, Monad m, Functor m) => (FORALL(u v) FL (TaggedPatch p) C(u v) -> PatchChoices p C(u v) -> m (PatchChoices p C(u v))) -> PatchChoices p C(x y) -> m (PatchChoices p C(x y)) refineChoices act ps = case getChoices ps of (f :> m :> l) -> do let mchoices = PCs NilFL . mapFL_FL (flip PC False) $ m (PCs f' l') <- act m mchoices return . PCs (f +>+ f') $ l' +>+ mapFL_FL (flip PC True) l patchSlot :: forall p C(a b x y). Patchy p => TaggedPatch p C(a b) -> PatchChoices p C(x y) -> (Slot, PatchChoices p C(x y)) patchSlot (TP t _) pc@(PCs f l) = if foundIn f then (InFirst, pc) else psLast f NilRL NilRL l where foundIn = anyFL ((== t) . tag) psLast :: FORALL(m c l) FL (TaggedPatch p) C(x m) -> RL (TaggedPatch p) C(m c) -> RL (TaggedPatch p) C(c l) -> FL (PatchChoice p) C(l y) -> (Slot, PatchChoices p C(x y)) psLast firsts middles bubble (PC tp True :>: ls) | tag tp == t = (InLast , PCs { pcsFirsts = firsts , pcsLasts = settleM middles +>+ settleB bubble +>+ PC tp True :>: ls}) psLast firsts middles bubble (PC tp False :>: ls) | tag tp == t = case commuteRL (bubble :> tp) of Just (tp' :> bubble') -> (InMiddle, PCs { pcsFirsts = firsts , pcsLasts = settleM middles +>+ PC tp' False :>: settleB bubble' +>+ ls}) Nothing -> (InLast, PCs { pcsFirsts = firsts , pcsLasts = settleM middles +>+ settleB bubble +>+ PC tp True :>: ls}) psLast firsts middles bubble (PC tp True :>: ls) = psLast firsts middles (tp :<: bubble) ls psLast firsts middles bubble (PC tp False :>: ls) = case commuteRL (bubble :> tp) of Just (tp' :> bubble') -> psLast firsts (tp' :<: middles) bubble' ls Nothing -> psLast firsts middles (tp :<: bubble) ls psLast _ _ _ NilFL = impossible settleM middles = mapFL_FL (\tp -> PC tp False) $ reverseRL middles settleB bubble = mapFL_FL (\tp -> PC tp True) $ reverseRL bubble patchSlot' :: Patchy p => TaggedPatch p C(a b) -> StateT (PatchChoices p C(x y)) Identity Slot patchSlot' tp = StateT (return . patchSlot tp) forceMatchingFirst :: forall p C(a b). Patchy p => ( FORALL(x y) TaggedPatch p C(x y) -> Bool) -> PatchChoices p C(a b) -> PatchChoices p C(a b) forceMatchingFirst pred (PCs fn l) = fmfLasts fn NilRL l where fmfLasts :: FL (TaggedPatch p) C(a m) -> RL (PatchChoice p) C(m n) -> FL (PatchChoice p) C(n b) -> PatchChoices p C(a b) fmfLasts f l1 (a :>: l2) | pred_pc a = case commuteWhatWeCanRL (l1 :> a) of (deps :> a' :> l1') -> let f' = f +>+ mapFL_FL pcPatch (reverseRL deps) +>+ (pcPatch a' :>: NilFL) in fmfLasts f' l1' l2 fmfLasts f l1 (a :>: l2) = fmfLasts f (a :<: l1) l2 fmfLasts f l1 NilFL = PCs { pcsFirsts = f , pcsLasts = reverseRL l1 } pred_pc :: FORALL(x y) PatchChoice p C(x y) -> Bool pred_pc (PC tp _) = pred tp forceFirsts :: Patchy p => [Tag] -> PatchChoices p C(a b) -> PatchChoices p C(a b) forceFirsts ps = forceMatchingFirst ((`elem` ps) . tag) forceFirst :: Patchy p => Tag -> PatchChoices p C(a b) -> PatchChoices p C(a b) forceFirst p = forceMatchingFirst ((== p) . tag) --TODO: stop after having seen the patch we want to force first selectAllMiddles :: forall p C(x y). Patchy p => Bool -> PatchChoices p C(x y) -> PatchChoices p C(x y) selectAllMiddles True (PCs f l) = PCs f (mapFL_FL g l) where g (PC tp _) = PC tp True selectAllMiddles False (PCs f l) = samf f NilRL NilRL l where samf :: FORALL(m1 m2 m3) FL (TaggedPatch p) C(x m1) -> RL (TaggedPatch p) C(m1 m2) -> RL (PatchChoice p) C(m2 m3) -> FL (PatchChoice p) C(m3 y) -> PatchChoices p C(x y) samf f1 f2 l1 (pc@(PC tp False) :>: l2) = case commuteRL (l1 :> pc) of Nothing -> samf f1 f2 (PC tp True :<: l1) l2 Just ((PC tp' _) :> l1') -> samf f1 (tp' :<: f2) l1' l2 samf f1 f2 l1 (PC tp True :>: l2) = samf f1 f2 (PC tp True :<: l1) l2 samf f1 f2 l1 NilFL = PCs (f1 +>+ reverseRL f2) (reverseRL l1) forceMatchingLast :: Patchy p => (FORALL(x y) TaggedPatch p C(x y) -> Bool) -> PatchChoices p C(a b) -> PatchChoices p C(a b) forceMatchingLast pred (PCs f l) = do fmlFirst pred True NilRL f l fmlFirst :: forall p C(a b m1 m2) . Patchy p => (FORALL(x y) TaggedPatch p C(x y) -> Bool) -> Bool -> RL (TaggedPatch p) C(a m1) -> FL (TaggedPatch p) C(m1 m2) -> FL (PatchChoice p) C(m2 b) -> PatchChoices p C(a b) fmlFirst pred b f1 (a :>: f2) l | pred a = case commuteWhatWeCanFL (a :> f2) of (f2' :> a' :> deps) -> let l' = mapFL_FL (\tp -> PC tp b) (a' :>: deps) +>+ l in fmlFirst pred b f1 f2' l' fmlFirst pred b f1 (a :>: f2) l = fmlFirst pred b (a :<: f1) f2 l fmlFirst pred b f1 NilFL l = PCs { pcsFirsts = reverseRL f1 , pcsLasts = mapFL_FL ch l} where ch (PC tp c) = (PC tp (if pred tp then b else c) ) forceLasts :: Patchy p => [Tag] -> PatchChoices p C(a b) -> PatchChoices p C(a b) forceLasts ps = forceMatchingLast ((`elem` ps) . tag) forceLast :: Patchy p => Tag -> PatchChoices p C(a b) -> PatchChoices p C(a b) forceLast p = forceMatchingLast ((== p) . tag) makeUncertain :: Patchy p => Tag -> PatchChoices p C(a b) -> PatchChoices p C(a b) makeUncertain t (PCs f l) = fmlFirst ((== t) . tag) False NilRL f l makeEverythingLater :: Patchy p => PatchChoices p C(x y) -> PatchChoices p C(x y) makeEverythingLater (PCs f l) = let m = mapFL_FL (\tp -> PC tp False) f l' = mapFL_FL (\(PC tp _) -> PC tp True) l in PCs NilFL $ m +>+ l' makeEverythingSooner :: forall p C(x y). Patchy p => PatchChoices p C(x y) -> PatchChoices p C(x y) makeEverythingSooner (PCs f l) = case mes NilRL NilRL l of (m :> l') -> PCs (f +>+ m) l' where mes :: FORALL(m1 m2 m3) RL (TaggedPatch p) C(m1 m2) -> RL (TaggedPatch p) C(m2 m3) -> FL (PatchChoice p) C(m3 y) -> (FL (TaggedPatch p) :> FL (PatchChoice p)) C(m1 y) mes middle bubble (PC tp True :>: ls) = mes middle (tp :<: bubble) ls mes middle bubble (PC tp False :>: ls) = case commuteRL (bubble :> tp) of Nothing -> mes middle (tp :<: bubble) ls Just (tp' :> bubble') -> mes (tp' :<: middle) bubble' ls mes middle bubble NilFL = (reverseRL middle) :> mapFL_FL (\tp -> PC tp False) (reverseRL bubble) -- | 'substitute' @(a :||: bs)@ @pcs@ replaces @a@ with @bs@ in @pcs@ preserving the choice -- associated with @a@ substitute :: forall p C(x y) . Patchy p => Sealed2 (TaggedPatch p :||: FL (TaggedPatch p)) -> PatchChoices p C(x y) -> PatchChoices p C(x y) substitute (Sealed2 (tp :||: new_tps)) (PCs f l) = PCs (concatFL $ mapFL_FL substTp f) (concatFL $ mapFL_FL substPc l) where substTp :: TaggedPatch p C(a b) -> FL (TaggedPatch p) C(a b) substTp tp' | IsEq <- compareTags tp tp' = new_tps | otherwise = tp' :>: NilFL substPc :: PatchChoice p C(a b) -> FL (PatchChoice p) C(a b) substPc (PC tp' c) | IsEq <- compareTags tp tp' = mapFL_FL (flip PC c) new_tps | otherwise = PC tp' c :>: NilFL darcs-2.8.4/src/Darcs/Patch/Commute.hs0000644001765600176560000000567712104371431017007 0ustar ganeshganeshmodule Darcs.Patch.Commute ( Commute(..), commuteFL, commuteFLorComplain, commuteRL, commuteRLFL, toFwdCommute, toRevCommute ) where import Darcs.Witnesses.Ordered (FL(..), RL(..), reverseFL, reverseRL, (:>)(..), (:<)(..) ) import Darcs.Witnesses.Sealed ( Sealed2, seal2 ) #include "gadts.h" -- | Things that can commute. class Commute p where commute :: (p :> p) C(x y) -> Maybe ((p :> p) C(x y)) -- | Swaps the ordered pair type so that commute can be -- called directly. toFwdCommute :: (Commute p, Commute q, Monad m) => ((p :< q) C(x y) -> m ((q :< p) C(x y))) -> (q :> p) C(x y) -> m ((p :> q) C(x y)) toFwdCommute c (x :> y) = do x' :< y' <- c (y :< x) return (y' :> x') -- | Swaps the ordered pair type from the order expected -- by commute to the reverse order. toRevCommute :: (Commute p, Commute q, Monad m) => ((p :> q) C(x y) -> m ((q :> p) C(x y))) -> (q :< p) C(x y) -> m ((p :< q) C(x y)) toRevCommute c (x :< y) = do x' :> y' <- c (y :> x) return (y' :< x') instance Commute p => Commute (FL p) where commute (NilFL :> x) = Just (x :> NilFL) commute (x :> NilFL) = Just (NilFL :> x) commute (xs :> ys) = do ys' :> rxs' <- commuteRLFL (reverseFL xs :> ys) return $ ys' :> reverseRL rxs' commuteRLFL :: Commute p => (RL p :> FL p) C(x y) -> Maybe ((FL p :> RL p) C(x y)) commuteRLFL (NilRL :> ys) = Just (ys :> NilRL) commuteRLFL (xs :> NilFL) = Just (NilFL :> xs) commuteRLFL (xs :> y :>: ys) = do y' :> xs' <- commuteRL (xs :> y) ys' :> xs'' <- commuteRLFL (xs' :> ys) return (y' :>: ys' :> xs'') commuteRL :: Commute p => (RL p :> p) C(x y) -> Maybe ((p :> RL p) C(x y)) commuteRL (z :<: zs :> w) = do w' :> z' <- commute (z :> w) w'' :> zs' <- commuteRL (zs :> w') return (w'' :> z' :<: zs') commuteRL (NilRL :> w) = Just (w :> NilRL) commuteFLorComplain :: Commute p => (p :> FL p) C(x y) -> Either (Sealed2 p) ((FL p :> p) C(x y)) commuteFLorComplain (p :> NilFL) = Right (NilFL :> p) commuteFLorComplain (q :> p :>: ps) = case commute (q :> p) of Just (p' :> q') -> case commuteFLorComplain (q' :> ps) of Right (ps' :> q'') -> Right (p' :>: ps' :> q'') Left l -> Left l Nothing -> Left $ seal2 p commuteFL :: Commute p => (p :> FL p) C(x y) -> Maybe ((FL p :> p) C(x y)) commuteFL = either (const Nothing) Just . commuteFLorComplain instance Commute p => Commute (RL p) where commute (xs :> ys) = do fys' :> xs' <- commuteRLFL (xs :> reverseRL ys) return (reverseFL fys' :> xs') darcs-2.8.4/src/Darcs/Patch/Conflict.hs0000644001765600176560000001102312104371431017115 0ustar ganeshganeshmodule Darcs.Patch.Conflict ( Conflict(..), CommuteNoConflicts(..) , IsConflictedPrim(..), ConflictState(..) ) where import Darcs.Patch.Effect ( Effect(..) ) import Darcs.Patch.Inspect ( PatchInspect(..) ) import Darcs.Patch.Permutations () import Darcs.Patch.Prim.Class ( PrimOf ) import Darcs.Witnesses.Ordered ( FL(..), RL(..), (:>)(..) , mapFL, reverseFL, mapRL, reverseRL ) import Darcs.Witnesses.Sealed ( Sealed, unseal ) import Darcs.Utils ( nubsort ) #include "gadts.h" class (Effect p, PatchInspect (PrimOf p)) => Conflict p where listConflictedFiles :: p C(x y) -> [FilePath] listConflictedFiles p = nubsort $ concatMap (unseal listTouchedFiles) $ concat $ resolveConflicts p resolveConflicts :: p C(x y) -> [[Sealed (FL (PrimOf p) C(y))]] conflictedEffect :: p C(x y) -> [IsConflictedPrim (PrimOf p)] conflictedEffect x = case listConflictedFiles x of [] -> mapFL (IsC Okay) $ effect x _ -> mapFL (IsC Conflicted) $ effect x class CommuteNoConflicts p where -- | If 'commuteNoConflicts' @x :> y@ succeeds, we know that that @x@ commutes -- past @y@ without any conflicts. This function is useful for patch types -- for which 'commute' is defined to always succeed; so we need some way to -- pick out the specific cases where commutation succeeds without any conflicts. commuteNoConflicts :: (p :> p) C(x y) -> Maybe ((p :> p) C(x y)) instance (CommuteNoConflicts p, Conflict p) => Conflict (FL p) where listConflictedFiles = nubsort . concat . mapFL listConflictedFiles resolveConflicts NilFL = [] resolveConflicts x = resolveConflicts $ reverseFL x conflictedEffect = concat . mapFL conflictedEffect instance CommuteNoConflicts p => CommuteNoConflicts (FL p) where commuteNoConflicts (NilFL :> x) = Just (x :> NilFL) commuteNoConflicts (x :> NilFL) = Just (NilFL :> x) commuteNoConflicts (xs :> ys) = do ys' :> rxs' <- commuteNoConflictsRLFL (reverseFL xs :> ys) return $ ys' :> reverseRL rxs' instance (CommuteNoConflicts p, Conflict p) => Conflict (RL p) where listConflictedFiles = nubsort . concat . mapRL listConflictedFiles resolveConflicts x = rcs x NilFL where rcs :: RL p C(x y) -> FL p C(y w) -> [[Sealed (FL (PrimOf p) C(w))]] rcs NilRL _ = [] rcs (p:<:ps) passedby | (_:_) <- resolveConflicts p = case commuteNoConflictsFL (p:>passedby) of Just (_:> p') -> resolveConflicts p' ++ rcs ps (p:>:passedby) Nothing -> rcs ps (p:>:passedby) rcs (p:<:ps) passedby = seq passedby $ rcs ps (p:>:passedby) conflictedEffect = concat . reverse . mapRL conflictedEffect instance CommuteNoConflicts p => CommuteNoConflicts (RL p) where commuteNoConflicts (NilRL :> x) = Just (x :> NilRL) commuteNoConflicts (x :> NilRL) = Just (NilRL :> x) commuteNoConflicts (xs :> ys) = do ys' :> rxs' <- commuteNoConflictsRLFL (xs :> reverseRL ys) return $ reverseFL ys' :> rxs' data IsConflictedPrim prim where IsC :: !ConflictState -> !(prim C(x y)) -> IsConflictedPrim prim data ConflictState = Okay | Conflicted | Duplicated deriving ( Eq, Ord, Show, Read) commuteNoConflictsFL :: CommuteNoConflicts p => (p :> FL p) C(x y) -> Maybe ((FL p :> p) C(x y)) commuteNoConflictsFL (p :> NilFL) = Just (NilFL :> p) commuteNoConflictsFL (q :> p :>: ps) = do p' :> q' <- commuteNoConflicts (q :> p) ps' :> q'' <- commuteNoConflictsFL (q' :> ps) return (p' :>: ps' :> q'') commuteNoConflictsRL :: CommuteNoConflicts p => (RL p :> p) C(x y) -> Maybe ((p :> RL p) C(x y)) commuteNoConflictsRL (NilRL :> p) = Just (p :> NilRL) commuteNoConflictsRL (p :<: ps :> q) = do q' :> p' <- commuteNoConflicts (p :> q) q'' :> ps' <- commuteNoConflictsRL (ps :> q') return (q'' :> p' :<: ps') commuteNoConflictsRLFL :: CommuteNoConflicts p => (RL p :> FL p) C(x y) -> Maybe ((FL p :> RL p) C(x y)) commuteNoConflictsRLFL (NilRL :> ys) = Just (ys :> NilRL) commuteNoConflictsRLFL (xs :> NilFL) = Just (NilFL :> xs) commuteNoConflictsRLFL (xs :> y :>: ys) = do y' :> xs' <- commuteNoConflictsRL (xs :> y) ys' :> xs'' <- commuteNoConflictsRLFL (xs' :> ys) return (y' :>: ys' :> xs'') darcs-2.8.4/src/Darcs/Patch/ConflictMarking.hs0000644001765600176560000001010412104371431020425 0ustar ganeshganesh-- Copyright (C) 2002-2003 David Roundy, 2010 Ganesh Sittampalam {-# LANGUAGE ViewPatterns #-} module Darcs.Patch.ConflictMarking ( mangleUnravelled ) where import qualified Data.ByteString.Char8 as BC (pack, last) import qualified Data.ByteString as B (null, ByteString) import Data.List ( sort, intersperse ) import Data.Maybe ( isJust ) import Darcs.Patch.FileHunk ( FileHunk(..), IsHunk, isHunk ) import Darcs.Patch.FileName ( FileName, fn2fp, fp2fn ) import Darcs.Patch.Inspect ( PatchInspect(..) ) import Darcs.Patch.Invert ( Invert(..) ) import Darcs.Patch.Permutations () import Darcs.Patch.Prim ( PrimPatch, is_filepatch, primIsHunk, primFromHunk ) import Darcs.Witnesses.Ordered ( FL(..) ) import Darcs.Witnesses.Sealed ( Sealed(..), mapSeal ) #include "gadts.h" #include "impossible.h" applyHunks :: IsHunk prim => [Maybe B.ByteString] -> FL prim C(x y) -> [Maybe B.ByteString] applyHunks ms ((isHunk -> Just (FileHunk _ l o n)):>:ps) = applyHunks (rls l ms) ps where rls k _ | k <=0 = bug $ "bad hunk: start position <=0 (" ++ show k ++ ")" rls 1 mls = map Just n ++ drop (length o) mls rls i (ml:mls) = ml : rls (i-1) mls rls _ [] = bug "rls in applyHunks" applyHunks ms NilFL = ms applyHunks _ (_:>:_) = impossible getAFilename :: PrimPatch prim => [Sealed (FL prim C(x))] -> FileName getAFilename ((Sealed ((is_filepatch -> Just f):>:_)):_) = f getAFilename _ = fp2fn "" getOld :: PrimPatch prim => [Maybe B.ByteString] -> [Sealed (FL prim C(x))] -> [Maybe B.ByteString] getOld mls (ps:pss) = getOld (getHunksOld mls ps) pss getOld mls [] = mls getHunksOld :: PrimPatch prim => [Maybe B.ByteString] -> Sealed (FL prim C(x)) -> [Maybe B.ByteString] getHunksOld mls (Sealed ps) = applyHunks (applyHunks mls ps) (invert ps) getHunksNew :: IsHunk prim => [Maybe B.ByteString] -> Sealed (FL prim C(x)) -> [Maybe B.ByteString] getHunksNew mls (Sealed ps) = applyHunks mls ps getHunkline :: [[Maybe B.ByteString]] -> Int getHunkline = ghl 1 where ghl :: Int -> [[Maybe B.ByteString]] -> Int ghl n pps = if any (isJust . head) pps then n else ghl (n+1) $ map tail pps makeChunk :: Int -> [Maybe B.ByteString] -> [B.ByteString] makeChunk n mls = pull_chunk $ drop (n-1) mls where pull_chunk (Just l:mls') = l : pull_chunk mls' pull_chunk (Nothing:_) = [] pull_chunk [] = bug "should this be [] in pull_chunk?" mangleUnravelled :: PrimPatch prim => [Sealed (FL prim C(x))] -> Sealed (FL prim C(x)) mangleUnravelled pss = if onlyHunks pss then (:>: NilFL) `mapSeal` mangleUnravelledHunks pss else head pss onlyHunks :: forall prim C(x) . PrimPatch prim => [Sealed (FL prim C(x))] -> Bool onlyHunks [] = False onlyHunks pss = fn2fp f /= "" && all oh pss where f = getAFilename pss oh :: Sealed (FL prim C(y)) -> Bool oh (Sealed (p:>:ps)) = primIsHunk p && [fn2fp f] == listTouchedFiles p && oh (Sealed ps) oh (Sealed NilFL) = True mangleUnravelledHunks :: PrimPatch prim => [Sealed (FL prim C(x))] -> Sealed (prim C(x)) --mangleUnravelledHunks [[h1],[h2]] = Deal with simple cases handily? mangleUnravelledHunks pss = if null nchs then bug "mangleUnravelledHunks" else Sealed (primFromHunk (FileHunk filename l old new)) where oldf = getOld (repeat Nothing) pss newfs = map (getHunksNew oldf) pss l = getHunkline $ oldf : newfs nchs = sort $ map (makeChunk l) newfs filename = getAFilename pss old = makeChunk l oldf new = [top] ++ old ++ [initial] ++ concat (intersperse [middle] nchs) ++ [bottom] top = BC.pack $ "v v v v v v v" ++ eol_c initial= BC.pack $ "=============" ++ eol_c middle = BC.pack $ "*************" ++ eol_c bottom = BC.pack $ "^ ^ ^ ^ ^ ^ ^" ++ eol_c eol_c = if any (\ps -> not (B.null ps) && BC.last ps == '\r') old then "\r" else "" darcs-2.8.4/src/Darcs/Patch/Depends.hs0000644001765600176560000004661612104371431016756 0ustar ganeshganesh-- Copyright (C) 2003-2004 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP , ScopedTypeVariables #-} #include "gadts.h" module Darcs.Patch.Depends ( getTagsRight, areUnrelatedRepos, mergeThem, findCommonWithThem, countUsThem, removeFromPatchSet, optimizePatchset, deepOptimizePatchset, slightlyOptimizePatchset, getPatchesBeyondTag, getPatchesInTag, splitOnTag, newsetUnion, newsetIntersection, commuteToEnd, findUncommon, merge2FL ) where import Data.List ( delete, intersect, (\\) ) import Darcs.Patch ( RepoPatch, getdeps, commute, commuteFLorComplain, commuteRL ) import Darcs.Patch.Info ( PatchInfo, isTag, humanFriendly ) import Darcs.Patch.Merge ( mergeFL ) import Darcs.Patch.Permutations ( partitionFL, partitionRL, removeSubsequenceRL ) import Darcs.Patch.PatchInfoAnd( PatchInfoAnd, hopefully, hopefullyM, info ) import Darcs.Witnesses.Eq ( EqCheck(..), (=\/=), (=/\=) ) import Darcs.Witnesses.Unsafe ( unsafeCoerceP, unsafeCoercePStart ) import Darcs.Witnesses.Ordered ( (:\/:)(..), (:/\:)(..), (:>)(..), (:>)(..), (+>+), mapFL, RL(..), FL(..), isShorterThanRL, (+<+), reverseFL, reverseRL, mapRL, ) import Darcs.Patch.Set ( PatchSet(..), Tagged(..), SealedPatchSet, newset2RL ) import Darcs.ProgressPatches ( progressRL ) import Darcs.Witnesses.Sealed (Sealed(..), FlippedSeal(..), flipSeal, seal ) import Printer ( renderString, vcat ) #include "impossible.h" {-| with_partial_intersection takes two 'PatchSet's and splits them into a /common/ intersection portion and two sets of patches. The intersection, however, is only lazily determined, so there is no guarantee that all intersecting patches will be included in the intersection 'PatchSet'. This is a pretty efficient function, because it makes use of the already-broken-up nature of 'PatchSet's. Note that the first argument to with_partial_intersection should be the repository that is more cheaply accessed (i.e. local), as with_partial_intersection does its best to reduce the number of inventories that are accessed from its rightmost argument. -} with_partial_intersection :: RepoPatch p => PatchSet p C(start x) -> PatchSet p C(start y) -> (FORALL(a c) RL (Tagged p) C(start a) -> RL (PatchInfoAnd p) C(a x) -> RL (PatchInfoAnd p) C(a c) -> ddd) -> ddd with_partial_intersection (PatchSet ps1 NilRL) s j = j NilRL ps1 (newset2RL s) with_partial_intersection s (PatchSet ps2 NilRL) j = j NilRL (newset2RL s) ps2 with_partial_intersection bbb (PatchSet a (Tagged ta _ _ :<: _)) j | Just (PatchSet b t) <- simpleTag (info ta) bbb = j t b (unsafeCoerceP a) with_partial_intersection aaa (PatchSet b (Tagged tb _ pb :<: tbs)) j = case hopefullyM tb of Just _ -> with_partial_intersection aaa (PatchSet (b+<+tb:<:pb) tbs) j Nothing -> case splitOnTag (info tb) aaa of PatchSet NilRL com :> us -> j com us (unsafeCoerceP b) _ -> impossible getPatchesBeyondTag :: RepoPatch p => PatchInfo -> PatchSet p C(start x) -> FlippedSeal (RL (PatchInfoAnd p)) C(x) getPatchesBeyondTag t (PatchSet ps (Tagged hp _ _ :<:_)) | info hp == t = flipSeal ps getPatchesBeyondTag t patchset@(PatchSet (hp:<:ps) ts) = if info hp == t then if getTagsRight patchset == [info hp] then flipSeal $ NilRL -- special case to avoid looking at redundant patches else case splitOnTag t patchset of _ :> e -> flipSeal e else case getPatchesBeyondTag t (PatchSet ps ts) of FlippedSeal xxs -> FlippedSeal (hp :<: xxs) getPatchesBeyondTag t (PatchSet NilRL NilRL) = bug $ "tag\n" ++ renderString (humanFriendly t) ++ "\nis not in the patchset in getPatchesBeyondTag." getPatchesBeyondTag t0 (PatchSet NilRL (Tagged t _ ps :<: ts)) = getPatchesBeyondTag t0 (PatchSet (t:<:ps) ts) splitOnTag :: RepoPatch p => PatchInfo -> PatchSet p C(start x) -> (PatchSet p :> RL (PatchInfoAnd p)) C(start x) splitOnTag t (PatchSet ps (Tagged hp x ps2 :<: ts)) | info hp == t = (PatchSet NilRL (Tagged hp x ps2 :<: ts)) :> ps splitOnTag t patchset@(PatchSet (hp:<:ps) ts) | info hp == t = if getTagsRight patchset == [info hp] then PatchSet NilRL (Tagged hp Nothing ps :<: ts) :> NilRL else case partitionRL ((`notElem` (t:ds)) . info) (hp:<:ps) of (x:<:a) :> b -> if getTagsRight (PatchSet (x:<:a) ts) == [t] then PatchSet NilRL (Tagged x Nothing a :<: ts) :> b else case splitOnTag t $ eatOne $ PatchSet (x:<:a) ts of xx :> yy -> xx :> (b +<+ yy) _ -> impossible where ds = getdeps (hopefully hp) eatOne :: PatchSet p C(start x) -> PatchSet p C(start x) eatOne (PatchSet ps1 (Tagged x _ ps2 :<: ts')) = PatchSet (ps1+<+x:<:ps2) ts' eatOne _ = bug "a stubborn case in splitOnTag (theoretically possible)" splitOnTag t (PatchSet (p:<:ps) ts) = case splitOnTag t (PatchSet ps ts) of ns :> x -> ns :> (p:<:x) splitOnTag t0 (PatchSet NilRL (Tagged t _ ps :<: ts)) = splitOnTag t0 (PatchSet (t:<:ps) ts) splitOnTag t0 (PatchSet NilRL NilRL) = bug $ "tag\n" ++ renderString (humanFriendly t0) ++ "\nis not in the patchset in splitOnTag." -- | @getPatchesInTag t ps@ returns a 'SealedPatchSet' of all -- patches in @ps@ which are contained in @t@. getPatchesInTag :: RepoPatch p => PatchInfo -> PatchSet p C(start x) -> SealedPatchSet p C(start) getPatchesInTag t ns = case splitOnTag t ns of ns' :> _ -> seal ns' -- | @getTagsRight ps@ returns the 'PatchInfo' for all the patches in -- @ps@ that are not depended on by anything else *through explicit -- dependencies*. Tags are a likely candidate, although we may also -- find some non-tag patches in this list. -- -- Keep in mind that in a typical repository with a lot of tags, only a small -- fraction of tags would be returned as they would be at least indirectly -- depended on by the topmost ones. getTagsRight :: PatchSet p C(start x) -> [PatchInfo] getTagsRight (PatchSet ps NilRL) = getTagsR (mapRL infoAndDeps ps) getTagsRight (PatchSet ps (Tagged t _ _ :<: _)) = getTagsR (mapRL infoAndDeps (ps+<+t:<:NilRL)) getTagsR :: [(PatchInfo, Maybe [PatchInfo])] -> [PatchInfo] getTagsR [] = [] getTagsR ((i0,Nothing):pps0) = i0 : getTagsR pps0 getTagsR ((i0,Just ds0):pps0) = i0 : getTagsR (drop_tags_r ds0 pps0) where -- example traversal given dependencies: -- -- X1 -> X2 -- X1 -> X4 -- X2 -> X3 -- -- [X2,X4]: | o1 o2 X2 o3 o4 X3 o5 X5 -- o1 |o2 X2 o3 o4 X3 o5 X5 -- [X4,X3]: o1 o2 | o3 o4 X3 o5 X5 -- ... -- [X4]: o1 o2 o3 o4 | o5 X5 -- ... -- []: o1 o2 o3 o4 o5 drop_tags_r :: [PatchInfo] -> [(PatchInfo, Maybe [PatchInfo])] -> [(PatchInfo, Maybe [PatchInfo])] drop_tags_r [] pps = pps drop_tags_r _ [] = [] drop_tags_r ds (hp:pps) | fst hp `elem` ds = case snd hp of Just ds' -> drop_tags_r (ds'++delete (fst hp) ds) pps Nothing -> drop_tags_r (delete (fst hp) ds) pps | otherwise = hp : drop_tags_r ds pps infoAndDeps :: PatchInfoAnd p C(x y) -> (PatchInfo, Maybe [PatchInfo]) infoAndDeps p | isTag (info p) = (info p, getdeps `fmap` hopefullyM p) | otherwise = (info p, Nothing) -- | @deepOptimizePatchset@ runs through all patches whether they are in the -- surface inventory or the deep one. deepOptimizePatchset :: PatchSet p C(start x) -> PatchSet p C(start x) deepOptimizePatchset ns = optimizePatchset (PatchSet (newset2RL ns) NilRL) -- | @optimizePatchset@ is similar to @slightlyOptimizePatchset@ in -- that it only works on the surface inventory (see below), but it -- works a bit harder and can optimize several tags. -- -- * surface inventory: the sequence of patches that corresponds -- to the @\_darcs/hashed\_inventory@ or @\_darcs/inventory@ files -- -- * deep inventory: the sequence of sequences of patches that -- corresponds to the @\_darcs/inventories@ directory optimizePatchset :: PatchSet p C(start x) -> PatchSet p C(start x) optimizePatchset (PatchSet NilRL ts) = PatchSet NilRL ts optimizePatchset (PatchSet (p:<:ps) ts) | isTag (info p) && getTagsRight (PatchSet (p:<:ps) ts) == [info p] -- all subsequent patches depend on p = case optimizePatchset (PatchSet ps ts) of PatchSet ps' ts' -> PatchSet NilRL (Tagged p Nothing ps' :<: ts') | otherwise = case optimizePatchset (PatchSet ps ts) of PatchSet ps' ts' -> PatchSet (p:<:ps') ts' -- | @slightlyOptimizePatchset@ only works on the surface inventory -- (see 'optimizePatchset') and only optimises at most one tag in -- there, going for the most recent tag which has no non-depended -- patch after it. Older tags won't be 'clean', which means the -- PatchSet will not be in 'unclean :< clean' state. slightlyOptimizePatchset :: PatchSet p C(start x) -> PatchSet p C(start x) slightlyOptimizePatchset (PatchSet ps0 ts0) = sops $ PatchSet (progressRL "Optimizing inventory" ps0) ts0 where sops :: PatchSet p C(start y) -> PatchSet p C(start y) sops (PatchSet NilRL ts) = PatchSet NilRL ts sops (PatchSet (hp:<:ps) ts) | isTag (info hp) = if getTagsRight (PatchSet (hp:<:ps) ts) == [info hp] then -- exactly one tag and it depends on everything not already archived PatchSet NilRL (Tagged hp Nothing ps :<: ts) else -- other tags or other top-level patches too (so move past hp) case sops $ PatchSet (progressRL "Optimizing inventory" ps) ts of PatchSet ps' ts' -> PatchSet (hp:<:ps') ts' | otherwise = -- move past hp case sops $ PatchSet ps ts of PatchSet ps' ts' -> PatchSet (hp:<:ps') ts' commuteToEnd :: forall p C(start x y). RepoPatch p => RL (PatchInfoAnd p) C(x y) -> PatchSet p C(start y) -> (PatchSet p :> RL (PatchInfoAnd p)) C(start x) commuteToEnd NilRL (PatchSet ps ts) = PatchSet NilRL ts :> ps commuteToEnd (p:<:ps) (PatchSet xs ts) | info p `elem` mapRL info xs = case fastRemoveRL p xs of Just xs' -> commuteToEnd ps (PatchSet xs' ts) Nothing -> impossible -- "Nothing is impossible" commuteToEnd ps (PatchSet xs (Tagged t _ ys :<: ts)) = commuteToEnd ps (PatchSet (xs+<+t:<:ys) ts) commuteToEnd _ _ = impossible removeFromPatchSet :: RepoPatch p => FL (PatchInfoAnd p) C(x y) -> PatchSet p C(start y) -> Maybe (PatchSet p C(start x)) removeFromPatchSet bad0 = rfns (reverseFL bad0) where rfns :: RepoPatch p => RL (PatchInfoAnd p) C(x y) -> PatchSet p C(start y) -> Maybe (PatchSet p C(start x)) rfns bad (PatchSet ps ts) | all (`elem` (mapRL info ps)) (mapRL info bad) = do ps' <- removeSubsequenceRL bad ps Just $ PatchSet ps' ts rfns _ (PatchSet _ NilRL) = Nothing rfns bad (PatchSet ps (Tagged t _ tps :<: ts)) = rfns bad (PatchSet (ps+<+t:<:tps) ts) findCommonWithThem :: RepoPatch p => PatchSet p C(start x) -> PatchSet p C(start y) -> (PatchSet p :> FL (PatchInfoAnd p)) C(start x) findCommonWithThem us them = with_partial_intersection us them $ \common us' them' -> case partitionFL ((`elem` mapRL info them') . info) $ reverseRL us' of _ :> bad@(_:>:_) :> _ -> bug $ "Failed to commute common patches:\n" ++ (renderString $ vcat $ mapRL (humanFriendly . info) $ reverseFL bad) common2 :> _nilfl :> only_ours -> PatchSet (reverseFL common2) common :> unsafeCoerceP only_ours findUncommon :: RepoPatch p => PatchSet p C(start x) -> PatchSet p C(start y) -> (FL (PatchInfoAnd p) :\/: FL (PatchInfoAnd p)) C(x y) findUncommon us them = case findCommonWithThem us them of _common :> us' -> case findCommonWithThem them us of _ :> them' -> unsafeCoercePStart us' :\/: them' countUsThem :: RepoPatch p => PatchSet p C(start x) -> PatchSet p C(start y) -> (Int, Int) countUsThem us them = with_partial_intersection us them $ \_ us' them' -> let uu = mapRL info us' tt = mapRL info them' in (length $ uu \\ tt, length $ tt \\ uu) mergeThem :: RepoPatch p => PatchSet p C(start x) -> PatchSet p C(start y) -> Sealed (FL (PatchInfoAnd p) C(x)) mergeThem us them = with_partial_intersection us them $ \_ us' them' -> merge2FL (reverseRL us') (reverseRL them') newsetIntersection :: RepoPatch p => [SealedPatchSet p C(start)] -> SealedPatchSet p C(start) newsetIntersection [] = seal $ PatchSet NilRL NilRL newsetIntersection [x] = x newsetIntersection (Sealed y:ys) = case newsetIntersection ys of Sealed z -> with_partial_intersection y z $ \common a b -> case mapRL info a `intersect` mapRL info b of morecommon -> case partitionRL (\e -> info e `notElem` morecommon) a of commonps :> _ -> seal $ PatchSet commonps common newsetUnion :: RepoPatch p => [SealedPatchSet p C(start)] -> SealedPatchSet p C(start) newsetUnion [] = seal $ PatchSet NilRL NilRL newsetUnion [x] = x newsetUnion (Sealed y@(PatchSet psy tsy):Sealed y2:ys) = case mergeThem y y2 of Sealed p2 -> newsetUnion $ seal (PatchSet (reverseFL p2+<+psy) tsy) : ys -- | Merge two FLs (say L and R), starting in a common context. The result is a -- FL starting in the original end context of L, going to a new context that is -- the result of applying all patches from R on top of patches from L. -- -- While this function is similar to 'mergeFL', there are three important -- differences to keep in mind: -- -- * 'mergeFL' does not correctly deal with duplicate patches whereas this one -- does -- (Question from Eric Kow: in what sense? Why not fix the mergeFL instance?) -- -- * 'mergeFL' returns both paths of the merge diamond, but this version only -- returns one, so you'd better choose the order carefully, eg. -- (@merge2FL l r@) -- -- * The conventional order we use in this function is reversed from -- 'mergeFL' (so @mergeFL r l@ vs. @merge2FL l r@. This does not -- matter so much for the former since you get both paths. -- (Question from Eric Kow: should we flip merge2FL for more uniformity in -- the code?) merge2FL :: RepoPatch p => FL (PatchInfoAnd p) C(x y) -> FL (PatchInfoAnd p) C(x z) -> Sealed (FL (PatchInfoAnd p) C(y)) merge2FL _ NilFL = seal NilFL merge2FL NilFL ys = seal ys merge2FL xs (y:>:ys) | Just xs' <- fastRemoveFL y xs = merge2FL xs' ys merge2FL (x:>:xs) ys | Just ys' <- fastRemoveFL x ys = merge2FL xs ys' | otherwise = case mergeFL (x :\/: ys) of ys' :/\: _ -> merge2FL xs ys' simpleTag :: PatchInfo -> PatchSet p C(start x) -> Maybe (PatchSet p C(start x)) simpleTag t0 (PatchSet ps (Tagged t h pst :<: ts)) | t0 == info t = Just $ PatchSet ps (Tagged t h pst :<: ts) | otherwise = do PatchSet ps' ts' <- simpleTag t0 (PatchSet (t:<:pst) ts) Just $ PatchSet (ps +<+ ps') ts' simpleTag _ _ = Nothing areUnrelatedRepos :: RepoPatch p => PatchSet p C(start x) -> PatchSet p C(start y) -> Bool areUnrelatedRepos us them = with_partial_intersection us them checkit where checkit (Tagged _ _ _ :<: _) _ _ = False checkit _ u t | t `isShorterThanRL` 5 = False | u `isShorterThanRL` 5 = False | otherwise = null $ intersect (mapRL info u) (mapRL info t) -- | Remove a patch from FL, using PatchInfo equality. The result is Just -- whenever the patch has been found and removed. If the patch is not present -- in the sequence at all or any commutation fails, we get Nothing. First two -- cases are optimisations for the common cases where the head of the list is -- the patch to remove, or the patch is not there at all. fastRemoveFL :: RepoPatch p => PatchInfoAnd p C(x y) -> FL (PatchInfoAnd p) C(x z) -> Maybe (FL (PatchInfoAnd p) C(y z)) fastRemoveFL _ NilFL = Nothing fastRemoveFL a (b:>:bs) | IsEq <- a =\/= b = Just bs | info a `notElem` mapFL info bs = Nothing fastRemoveFL a (b:>:bs) = do a' :> bs' <- pullout NilRL bs a'' :> b' <- commute (b :> a') IsEq <- return (a'' =\/= a) Just (b':>:bs') where i = info a pullout :: RepoPatch p => RL (PatchInfoAnd p) C(a0 a) -> FL (PatchInfoAnd p) C(a b) -> Maybe ((PatchInfoAnd p :> FL (PatchInfoAnd p)) C(a0 b)) pullout _ NilFL = Nothing pullout acc (x:>:xs) | info x == i = do x' :> acc' <- commuteRL (acc :> x) Just (x' :> reverseRL acc' +>+ xs) | otherwise = pullout (x:<:acc) xs fastRemoveRL :: RepoPatch p => PatchInfoAnd p C(y z) -> RL (PatchInfoAnd p) C(x z) -> Maybe (RL (PatchInfoAnd p) C(x y)) fastRemoveRL _ NilRL = Nothing fastRemoveRL a (b:<:bs) | IsEq <- a =/\= b = Just bs | info a `notElem` mapRL info bs = Nothing fastRemoveRL a (b:<:bs) = do bs' :> a' <- pullout NilFL bs b' :> a'' <- commute (a' :> b) IsEq <- return (a'' =/\= a) Just (b':<:bs') where i = info a pullout :: RepoPatch p => FL (PatchInfoAnd p) C(b c) -> RL (PatchInfoAnd p) C(a b) -> Maybe ((RL (PatchInfoAnd p) :> PatchInfoAnd p) C(a c)) pullout _ NilRL = Nothing pullout acc (x:<:xs) | info x == i = do acc' :> x' <- either (const Nothing) Just (commuteFLorComplain (x :> acc)) Just (reverseFL acc' +<+ xs :> x') | otherwise = pullout (x:>:acc) xs darcs-2.8.4/src/Darcs/Patch/Dummy.hs0000644001765600176560000000151412104371431016453 0ustar ganeshganesh{-# OPTIONS_GHC -fno-warn-missing-methods #-} {-# LANGUAGE EmptyDataDecls #-} module Darcs.Patch.Dummy ( DummyPatch ) where import Darcs.Patch.FileHunk ( IsHunk ) import Darcs.Patch.Format ( PatchListFormat ) import Darcs.Patch.Patchy ( Patchy, ShowPatch, Invert, Commute, Apply(..), PatchInspect , ReadPatch ) import Darcs.Patch.Show ( ShowPatchBasic ) import Darcs.Witnesses.Eq ( MyEq ) import Storage.Hashed.Tree( Tree ) #include "gadts.h" data DummyPatch C(x y) instance IsHunk DummyPatch instance PatchListFormat DummyPatch instance MyEq DummyPatch instance Invert DummyPatch instance PatchInspect DummyPatch instance ReadPatch DummyPatch instance ShowPatchBasic DummyPatch instance ShowPatch DummyPatch instance Commute DummyPatch instance Apply DummyPatch where type ApplyState DummyPatch = Tree instance Patchy DummyPatch darcs-2.8.4/src/Darcs/Patch/Effect.hs0000644001765600176560000000156112104371431016556 0ustar ganeshganeshmodule Darcs.Patch.Effect ( Effect(..) ) where import Darcs.Patch.Prim.Class ( PrimOf ) import Darcs.Witnesses.Ordered ( FL(..), RL(..), reverseFL, reverseRL , concatFL, concatRL, mapFL_FL, mapRL_RL ) #include "gadts.h" -- | Patches whose concrete effect which can be expressed as a list of -- primitive patches. -- -- A minimal definition would be either of @effect@ or @effectRL@. class Effect p where effect :: p C(x y) -> FL (PrimOf p) C(x y) effect = reverseRL . effectRL effectRL :: p C(x y) -> RL (PrimOf p) C(x y) effectRL = reverseFL . effect instance Effect p => Effect (FL p) where effect p = concatFL $ mapFL_FL effect p effectRL p = concatRL $ mapRL_RL effectRL $ reverseFL p instance Effect p => Effect (RL p) where effect p = concatFL $ mapFL_FL effect $ reverseRL p effectRL p = concatRL $ mapRL_RL effectRL p darcs-2.8.4/src/Darcs/Patch/FileName.hs0000644001765600176560000001336312104371431017045 0ustar ganeshganesh-- Copyright (C) 2002-2003 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. -- | FileName is an abstract type intended to facilitate the input and output of -- unicode filenames. module Darcs.Patch.FileName ( FileName( ), fp2fn, fn2fp, fn2ps, ps2fn, niceps2fn, fn2niceps, breakOnDir, normPath, ownName, superName, movedirfilename, encodeWhite, decodeWhite, (///), breakup, isParentOrEqOf ) where import Data.Char ( isSpace, chr, ord ) import Data.List ( stripPrefix ) import ByteStringUtils ( packStringToUTF8, unpackPSFromUTF8 ) import qualified Data.ByteString.Char8 as BC (unpack, pack) import qualified Data.ByteString as B (ByteString) newtype FileName = FN FilePath deriving ( Eq, Ord ) instance Show FileName where showsPrec d (FN fp) = showParen (d > appPrec) $ showString "fp2fn " . showsPrec (appPrec + 1) fp where appPrec = 10 {-# INLINE fp2fn #-} fp2fn :: FilePath -> FileName fp2fn fp = FN fp {-# INLINE fn2fp #-} fn2fp :: FileName -> FilePath fn2fp (FN fp) = fp {-# INLINE niceps2fn #-} niceps2fn :: B.ByteString -> FileName niceps2fn = FN . decodeWhite . BC.unpack {-# INLINE fn2niceps #-} fn2niceps :: FileName -> B.ByteString fn2niceps (FN fp) = BC.pack $ encodeWhite fp {-# INLINE fn2ps #-} fn2ps :: FileName -> B.ByteString fn2ps (FN fp) = packStringToUTF8 $ encodeWhite fp {-# INLINE ps2fn #-} ps2fn :: B.ByteString -> FileName ps2fn ps = FN $ decodeWhite $ unpackPSFromUTF8 ps -- | 'encodeWhite' translates whitespace in filenames to a darcs-specific -- format (numerical representation according to 'ord' surrounded by -- backslashes). Note that backslashes are also escaped since they are used -- in the encoding. -- -- > encodeWhite "hello there" == "hello\32\there" -- > encodeWhite "hello\there" == "hello\92\there" encodeWhite :: FilePath -> String encodeWhite (c:cs) | isSpace c || c == '\\' = '\\' : (show $ ord c) ++ "\\" ++ encodeWhite cs encodeWhite (c:cs) = c : encodeWhite cs encodeWhite [] = [] -- | 'decodeWhite' interprets the Darcs-specific \"encoded\" filenames -- produced by 'encodeWhite' -- -- > decodeWhite "hello\32\there" == "hello there" -- > decodeWhite "hello\92\there" == "hello\there" -- > decodeWhite "hello\there" == error "malformed filename" decodeWhite :: String -> FilePath decodeWhite ('\\':cs) = case break (=='\\') cs of (theord, '\\':rest) -> chr (read theord) : decodeWhite rest _ -> error "malformed filename" decodeWhite (c:cs) = c: decodeWhite cs decodeWhite "" = "" ownName :: FileName -> FileName ownName (FN f) = case breakLast '/' f of Nothing -> FN f Just (_,f') -> FN f' superName :: FileName -> FileName superName fn = case normPath fn of FN f -> case breakLast '/' f of Nothing -> FN "." Just (d,_) -> FN d breakOnDir :: FileName -> Maybe (FileName,FileName) breakOnDir (FN p) = case breakFirst '/' p of Nothing -> Nothing Just (d,f) | d == "." -> breakOnDir $ FN f | otherwise -> Just (FN d, FN f) normPath :: FileName -> FileName -- remove "./" normPath (FN p) = FN $ repath $ dropDotdot $ breakup p repath :: [String] -> String repath [] = "" repath [f] = f repath (d:p) = d ++ "/" ++ repath p dropDotdot :: [String] -> [String] dropDotdot ("":p) = dropDotdot p dropDotdot (".":p) = dropDotdot p dropDotdot ("..":p) = ".." : (dropDotdot p) dropDotdot (_:"..":p) = dropDotdot p dropDotdot (d:p) = case dropDotdot p of ("..":p') -> p' p' -> d : p' dropDotdot [] = [] -- | Split a file path at the slashes breakup :: String -> [String] breakup p = case break (=='/') p of (d,"") -> [d] (d,p') -> d : breakup (tail p') breakFirst :: Char -> String -> Maybe (String,String) breakFirst c l = bf [] l where bf a (r:rs) | r == c = Just (reverse a,rs) | otherwise = bf (r:a) rs bf _ [] = Nothing breakLast :: Char -> String -> Maybe (String,String) breakLast c l = case breakFirst c (reverse l) of Nothing -> Nothing Just (a,b) -> Just (reverse b, reverse a) (///) :: FileName -> FileName -> FileName (FN "")///b = normPath b a///b = normPath $ fp2fn $ fn2fp a ++ "/" ++ fn2fp b isParentOrEqOf :: FileName -> FileName -> Bool isParentOrEqOf fn1 fn2 = case stripPrefix (fn2fp fn1) (fn2fp fn2) of Just ('/' : _) -> True Just [] -> True _ -> False movedirfilename :: FileName -> FileName -> FileName -> FileName movedirfilename old new name = if name' == old' then new else case stripPrefix old' name' of Just rest@('/':_) -> fp2fn $ "./" ++ new' ++ rest _ -> name where old' = fn2fp $ normPath old new' = fn2fp $ normPath new name' = fn2fp $ normPath name darcs-2.8.4/src/Darcs/Patch/FileHunk.hs0000644001765600176560000000155712104371431017074 0ustar ganeshganeshmodule Darcs.Patch.FileHunk ( FileHunk(..), IsHunk(..), showFileHunk ) where import Darcs.Patch.FileName ( FileName ) import Darcs.Patch.Format ( FileNameFormat ) import Darcs.Patch.Show ( formatFileName ) import Printer ( Doc, blueText, text, lineColor, vcat, userchunkPS , prefix, ($$), (<+>), Color(Cyan, Magenta) ) import qualified Data.ByteString as B ( ByteString ) #include "gadts.h" data FileHunk C(x y) = FileHunk !FileName !Int [B.ByteString] [B.ByteString] class IsHunk p where isHunk :: p C(x y) -> Maybe (FileHunk C(x y)) showFileHunk :: FileNameFormat -> FileHunk C(x y) -> Doc showFileHunk x (FileHunk f line old new) = blueText "hunk" <+> formatFileName x f <+> text (show line) $$ lineColor Magenta (prefix "-" (vcat $ map userchunkPS old)) $$ lineColor Cyan (prefix "+" (vcat $ map userchunkPS new)) darcs-2.8.4/src/Darcs/Patch/Format.hs0000644001765600176560000000257112104371431016614 0ustar ganeshganeshmodule Darcs.Patch.Format ( PatchListFormat(..), ListFormat(..) , FileNameFormat(..) ) where #include "gadts.h" -- | Showing and reading lists of patches This class allows us to control how -- lists of patches are formatted on disk. For legacy reasons V1 patches have -- their own special treatment (see 'ListFormat'). Other patch types use the -- default format which just puts them in a sequence without separators or any -- prelude/epilogue. -- -- This means that 'FL (FL p)' etc would be ambiguous, so there are no instances -- for 'FL p' or other list types. class PatchListFormat p where patchListFormat :: ListFormat p patchListFormat = ListFormatDefault -- | This type is used to tweak the way that lists of 'p' are shown for a given -- 'Patch' type 'p'. It is needed to maintain backwards compatibility for V1 and -- V2 patches. data ListFormat (p :: PATCHKIND) = ListFormatDefault -- ^ Show and read lists without braces. | ListFormatV1 -- ^ Show lists with a single layer of braces around the outside, -- except for singletons which have no braces. -- Read with arbitrary nested braces and parens and flatten them out. | ListFormatV2 -- ^ Show lists without braces -- Read with arbitrary nested parens and flatten them out. data FileNameFormat = OldFormat | NewFormat darcs-2.8.4/src/Darcs/Patch/Info.hs0000644001765600176560000003612212104371431016256 0ustar ganeshganesh-- Copyright (C) 2002-2003 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. module Darcs.Patch.Info ( PatchInfo(..), patchinfo, invertName, idpatchinfo, addJunk, makePatchname, makeFilename, makeAltFilename, readPatchInfo, justName, justAuthor, justLog, repopatchinfo, RepoPatchInfo, humanFriendly, toXml, piDate, setPiDate, piDateString, piDateBytestring, piName, piRename, piAuthor, piTag, piLog, showPatchInfo, isTag, readPatchInfos, escapeXML ) where import Text.Html hiding (name, text, option) import System.Random ( randomRIO ) import Numeric ( showHex ) import Control.Monad ( when, unless ) import ByteStringUtils ( unlinesPS, packStringToUTF8, unpackPSFromUTF8, decodeLocale) import qualified Darcs.Patch.ReadMonads as RM ( take ) import Darcs.Patch.ReadMonads as RM ( skipSpace, char, takeTill, anyChar, ParserM, option, parseStrictly, takeTillChar, linesStartingWithEndingWith) import qualified Data.ByteString as B (length, splitAt, null ,isPrefixOf, tail, concat ,empty, head, cons, append ,ByteString ) import qualified Data.ByteString.Char8 as BC (index, head, unpack, pack) import Data.List( isPrefixOf ) import Printer ( renderString, Doc, packedString, empty, ($$), (<>), (<+>), vcat, text, blueText, prefix ) import Darcs.Patch.OldDate ( readUTCDate, showIsoDateTime ) import System.Time ( CalendarTime(ctTZ), calendarTimeToString, toClockTime, toCalendarTime ) import System.IO.Unsafe ( unsafePerformIO ) import SHA1 ( sha1PS ) import Darcs.Utils ( promptYorn ) import Prelude hiding (pi, log) data RepoPatchInfo = RPI String PatchInfo repopatchinfo :: String -> PatchInfo -> RepoPatchInfo repopatchinfo r pi = RPI r pi -- | A PatchInfo value contains the metadata of a patch. The date, name, author -- and log fields are UTF-8 encoded text in darcs 2.4 and later, and just -- sequences of bytes (decoded with whatever is the locale when displayed) in -- earlier darcs. -- -- The members with names that start with '_' are not supposed to be used -- directly in code that does not care how the patch info is stored. data PatchInfo = PatchInfo { _piDate :: !B.ByteString , _piName :: !B.ByteString , _piAuthor :: !B.ByteString , _piLog :: ![B.ByteString] , isInverted :: !Bool } deriving (Eq,Ord) idpatchinfo :: PatchInfo idpatchinfo = PatchInfo myid myid myid [] False where myid = BC.pack "identity" patchinfo :: String -> String -> String -> [String] -> IO PatchInfo patchinfo date name author log = addJunk $ PatchInfo { _piDate = BC.pack date , _piName = packStringToUTF8 name , _piAuthor = packStringToUTF8 author , _piLog = map packStringToUTF8 log , isInverted = False } -- | addJunk adds a line that contains a random number to make the patch -- unique. addJunk :: PatchInfo -> IO PatchInfo addJunk pinf = do x <- randomRIO (0,2^(128 ::Integer) :: Integer) when (_piLog pinf /= ignoreJunk (_piLog pinf)) $ do putStrLn "Lines beginning with 'Ignore-this: ' will be ignored." confirmed <- promptYorn "Proceed? " unless confirmed $ fail "User cancelled because of Ignore-this." return $ pinf { _piLog = BC.pack (head ignored++showHex x ""): _piLog pinf } ignored :: [String] -- this is a [String] so we can change the junk header. ignored = ["Ignore-this: "] ignoreJunk :: [B.ByteString] -> [B.ByteString] ignoreJunk = filter isnt_ignored where isnt_ignored x = doesnt_start_with x (map BC.pack ignored) -- TODO doesnt_start_with x ys = not $ any (`B.isPrefixOf` x) ys -- * Patch info formatting invertName :: PatchInfo -> PatchInfo invertName pi = pi { isInverted = not (isInverted pi) } -- | Get the name, including an "UNDO: " prefix if the patch is inverted. justName :: PatchInfo -> String justName pinf = if isInverted pinf then "UNDO: " ++ nameString else nameString where nameString = metadataToString (_piName pinf) -- | Returns the author of a patch. justAuthor :: PatchInfo -> String justAuthor = metadataToString . _piAuthor justLog :: PatchInfo -> String justLog = unlines . map BC.unpack . _piLog humanFriendly :: PatchInfo -> Doc humanFriendly pi = text (friendlyD $ _piDate pi) <> text " " <> text (piAuthor pi) $$ hfn (piName pi) $$ vcat (map ((text " " <>) . text) (piLog pi)) where hfn x = case piTag pi of Nothing -> inverted <+> text x Just t -> text " tagged" <+> text t inverted = if isInverted pi then text " UNDO:" else text " *" -- | Returns the name of the patch. Unlike 'justName', it does not preprend -- "UNDO: " to the name if the patch is inverted. piName :: PatchInfo -> String piName = metadataToString . _piName piRename :: PatchInfo -> String -> PatchInfo piRename x n = x { _piName = packStringToUTF8 n } -- | Returns the author of a patch. piAuthor :: PatchInfo -> String piAuthor = metadataToString . _piAuthor isTag :: PatchInfo -> Bool isTag pinfo = "TAG " `isPrefixOf` justName pinfo -- | Note: we ignore timezone information in the date string, -- systematically treating a time as UTC. So if the patch -- tells me it's 17:00 EST, we're actually treating it as -- 17:00 UTC, in other words 11:00 EST. This is for -- backwards compatibility to darcs prior to 2003-11, sometime -- before 1.0. Fortunately, newer patch dates are written in -- UTC, so this timezone truncation is harmless for them. readPatchDate :: B.ByteString -> CalendarTime readPatchDate = ignoreTz . readUTCDate . BC.unpack where ignoreTz ct = ct { ctTZ = 0 } piDate :: PatchInfo -> CalendarTime piDate = readPatchDate . _piDate piDateString :: PatchInfo -> String piDateString = BC.unpack . _piDate piDateBytestring :: PatchInfo -> B.ByteString piDateBytestring = _piDate setPiDate :: String -> PatchInfo -> PatchInfo setPiDate date pi = pi { _piDate = BC.pack date } -- | Get the log message of a patch. piLog :: PatchInfo -> [String] piLog = map metadataToString . ignoreJunk . _piLog -- | Get the tag name, if the patch is a tag patch. piTag :: PatchInfo -> Maybe String piTag pinf = if l == t then Just $ metadataToString r else Nothing where (l, r) = B.splitAt (B.length t) (_piName pinf) t = BC.pack "TAG " -- | Convert a metadata ByteString to a string. It first tries to convert -- using UTF-8, and if that fails, tries the locale encoding. -- We try UTF-8 first because UTF-8 is clearly recognizable, widely used, -- and people may have UTF-8 patches even when UTF-8 is not their locale. metadataToString :: B.ByteString -> String metadataToString bs | not ('\xfffd' `elem` bsUtf8) = bsUtf8 | otherwise = decodeLocale bs where bsUtf8 = unpackPSFromUTF8 bs friendlyD :: B.ByteString -> String --friendlyD d = calendarTimeToString . readPatchDate . d friendlyD d = unsafePerformIO $ do ct <- toCalendarTime $ toClockTime $ readPatchDate d return $ calendarTimeToString ct toXml :: PatchInfo -> Doc toXml pi = text " text "author='" <> escapeXMLByteString (_piAuthor pi) <> text "'" <+> text "date='" <> escapeXMLByteString (_piDate pi) <> text "'" <+> text "local_date='" <> escapeXML (friendlyD $ _piDate pi) <> text "'" <+> text "inverted='" <> text (show $ isInverted pi) <> text "'" <+> text "hash='" <> text (makePatchname pi) <> text "'>" $$ prefix "\t" ( text "" <> escapeXMLByteString (_piName pi) <> text "" $$ commentsAsXml (_piLog pi)) $$ text "" commentsAsXml :: [B.ByteString] -> Doc commentsAsXml comments | B.length comments' > 0 = text "" <> escapeXMLByteString comments' <> text "" | otherwise = empty where comments' = unlinesPS comments -- escapeXML is duplicated in Patch.lhs and Annotate.lhs -- It should probably be refactored to exist in one place. escapeXML :: String -> Doc escapeXML = text . strReplace '\'' "'" . strReplace '"' """ . strReplace '>' ">" . strReplace '<' "<" . strReplace '&' "&" -- Escape XML characters in a UTF-8 encoded ByteString, and turn it into a Doc. -- The data will be in the Doc as a bytestring. escapeXMLByteString :: B.ByteString -> Doc escapeXMLByteString = packedString . bstrReplace '\'' "'" . bstrReplace '"' """ . bstrReplace '>' ">" . bstrReplace '<' "<" . bstrReplace '&' "&" strReplace :: Char -> String -> String -> String strReplace _ _ [] = [] strReplace x y (z:zs) | x == z = y ++ (strReplace x y zs) | otherwise = z : (strReplace x y zs) bstrReplace :: Char -> String -> B.ByteString -> B.ByteString bstrReplace c s bs | B.null bs = B.empty | otherwise = if BC.head bs == c then B.append (BC.pack s) (bstrReplace c s (B.tail bs)) else B.cons (B.head bs) (bstrReplace c s (B.tail bs)) makeAltFilename :: PatchInfo -> String makeAltFilename pi@(PatchInfo { isInverted = False }) = fixUpFname (midtrunc (piName pi)++"-"++justAuthor pi++"-"++BC.unpack (_piDate pi)) makeAltFilename pi@(PatchInfo { isInverted = True}) = makeAltFilename (pi { isInverted = False }) ++ "-inverted" -- | This makes darcs-1 (non-hashed repos) filenames, and is also generally -- used in both in hashed and non-hashed repo code for making patch "hashes". -- -- The name consists of three segments: -- -- * timestamp (ISO8601-compatible yyyymmmddHHMMSS, UTC) -- -- * SHA1 hash of the author -- -- * SHA1 hash of the patch name, author, date, log, and \"inverted\" -- flag. makeFilename :: PatchInfo -> String makeFilename pi = makePatchname pi ++ ".gz" makePatchname :: PatchInfo -> String makePatchname pi = showIsoDateTime d++"-"++sha1_a++"-"++sha1PS sha1_me where b2ps True = BC.pack "t" b2ps False = BC.pack "f" sha1_me = B.concat [_piName pi, _piAuthor pi, _piDate pi, B.concat $ _piLog pi, b2ps $ isInverted pi] d = readPatchDate $ _piDate pi sha1_a = take 5 $ sha1PS $ _piAuthor pi midtrunc :: String -> String midtrunc s | length s < 73 = s | otherwise = (take 40 s)++"..."++(reverse $ take 30 $ reverse s) fixUpFname :: String -> String fixUpFname = map mungeChar mungeChar :: Char -> Char mungeChar '*' = '+' mungeChar '?' = '2' mungeChar '>' = '7' mungeChar '<' = '2' mungeChar ' ' = '_' mungeChar '"' = '~' mungeChar '`' = '.' mungeChar '\'' = '.' mungeChar '/' = '1' mungeChar '\\' = '1' mungeChar '!' = '1' mungeChar ':' = '.' mungeChar ';' = ',' mungeChar '{' = '~' mungeChar '}' = '~' mungeChar '(' = '~' mungeChar ')' = '~' mungeChar '[' = '~' mungeChar ']' = '~' mungeChar '=' = '+' mungeChar '#' = '+' mungeChar '%' = '8' mungeChar '&' = '6' mungeChar '@' = '9' mungeChar '|' = '1' mungeChar c = c instance HTML RepoPatchInfo where toHtml = htmlPatchInfo instance Show PatchInfo where show pi = renderString (showPatchInfo pi) -- |Patch is stored between square brackets. -- -- > [ -- > * -- > (indented one) -- > -- > -- > -- > ] -- -- note that below I assume the name has no newline in it. -- See 'readPatchInfo' for the inverse operation. showPatchInfo :: PatchInfo -> Doc showPatchInfo pi = blueText "[" <> packedString (_piName pi) $$ packedString (_piAuthor pi) <> text inverted <> packedString (_piDate pi) <> myunlines (_piLog pi) <> blueText "] " where inverted = if isInverted pi then "*-" else "**" myunlines [] = empty myunlines xs = mul xs where mul [] = text "\n" mul (s:ss) = text "\n " <> packedString s <> mul ss -- |Parser for 'PatchInfo' as stored in patch bundles and inventory files, -- for example: -- -- > [Document the foo interface -- > John Doe **20110615084241 -- > Ignore-this: 85b94f67d377c4ab671101266ef9c229 -- > Nobody knows what a 'foo' is, so describe it. -- > ] -- -- See 'showPatchInfo' for the inverse operation. readPatchInfo :: ParserM m => m (PatchInfo) readPatchInfo = do skipSpace char '[' name <- takeTillChar '\n' _ <- anyChar author <- takeTillChar '*' s2 <- RM.take 2 ct <- takeTill (\c->c==']'||c=='\n') option () (char '\n' >> return ()) -- consume newline char, if present log <- linesStartingWithEndingWith ' ' ']' return $ PatchInfo { _piDate = ct , _piName = name , _piAuthor = author , _piLog = log , isInverted = BC.index s2 1 /= '*' } readPatchInfos :: B.ByteString -> [PatchInfo] readPatchInfos inv | B.null inv = [] readPatchInfos inv = case parseStrictly readPatchInfo inv of Just (pinfo,r) -> pinfo : readPatchInfos r _ -> [] htmlPatchInfo :: RepoPatchInfo -> Html htmlPatchInfo (RPI r pi) = toHtml $ (td << patchLink r pi) `above` ((td ! [align "right"] << mailLink (justAuthor pi)) `beside` (td << (friendlyD $ _piDate pi))) patchLink :: String -> PatchInfo -> Html patchLink r pi = toHtml $ hotlink ("darcs?"++r++"**"++makeFilename pi) [toHtml $ piName pi] mailLink :: String -> Html mailLink email = toHtml $ hotlink ("mailto:"++email) [toHtml email] darcs-2.8.4/src/Darcs/Patch/Inspect.hs0000644001765600176560000000125612104371431016770 0ustar ganeshganeshmodule Darcs.Patch.Inspect ( PatchInspect(..) ) where import Darcs.Witnesses.Ordered ( FL, RL, reverseRL, mapFL ) import qualified Data.ByteString.Char8 as BC import Data.List ( nub ) #include "gadts.h" class PatchInspect p where listTouchedFiles :: p C(x y) -> [FilePath] hunkMatches :: (BC.ByteString -> Bool) -> p C(x y) -> Bool instance PatchInspect p => PatchInspect (FL p) where listTouchedFiles xs = nub $ concat $ mapFL listTouchedFiles xs hunkMatches f = or . mapFL (hunkMatches f) instance PatchInspect p => PatchInspect (RL p) where listTouchedFiles = listTouchedFiles . reverseRL hunkMatches f = hunkMatches f . reverseRL darcs-2.8.4/src/Darcs/Patch/Invert.hs0000644001765600176560000000071012104371431016624 0ustar ganeshganeshmodule Darcs.Patch.Invert ( Invert(..), invertFL, invertRL ) where import Darcs.Witnesses.Ordered ( FL(..), RL(..) ) #include "gadts.h" class Invert p where invert :: p C(x y) -> p C(y x) invertFL :: Invert p => FL p C(x y) -> RL p C(y x) invertFL NilFL = NilRL invertFL (x:>:xs) = invert x :<: invertFL xs invertRL :: Invert p => RL p C(x y) -> FL p C(y x) invertRL NilRL = NilFL invertRL (x:<:xs) = invert x :>: invertRL xs darcs-2.8.4/src/Darcs/Patch/Match.hs0000644001765600176560000002230512104371431016415 0ustar ganeshganesh-- Copyright (C) 2004 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. #include "gadts.h" module Darcs.Patch.Match ( PatchMatch, Matcher, MatchFun, patchMatch, matchPattern, applyMatcher, makeMatcher, parseMatch, matchParser, helpOnMatchers, ) where import Text.ParserCombinators.Parsec import Text.ParserCombinators.Parsec.Expr import Text.Regex ( mkRegex, matchRegex ) import Data.Maybe ( isJust ) import System.IO.Unsafe ( unsafePerformIO ) import Darcs.Patch.PatchInfoAnd ( PatchInfoAnd, hopefully, info ) import Darcs.Patch ( Patchy, hunkMatches, listTouchedFiles, patchcontents ) import Darcs.Patch.Info ( justName, justAuthor, justLog, makeFilename, piDate ) import Darcs.Witnesses.Sealed ( Sealed2(..), seal2 ) import DateMatcher ( parseDateMatcher ) import Darcs.Patch.MatchData ( PatchMatch(..), patchMatch ) import qualified Data.ByteString.Char8 as BC import Darcs.Patch.Dummy ( DummyPatch ) -- | A type for predicates over patches which do not care about -- contexts type MatchFun p = Sealed2 (PatchInfoAnd p) -> Bool -- | A @Matcher@ is made of a 'MatchFun' which we will use to match -- patches and a @String@ representing it. data Matcher p = MATCH String (MatchFun p) instance Show (Matcher p) where show (MATCH s _) = '"':s ++ "\"" makeMatcher :: String -> (Sealed2 (PatchInfoAnd p) -> Bool) -> Matcher p makeMatcher s m = MATCH s m -- | @applyMatcher@ applies a matcher to a patch. applyMatcher :: Matcher p -> PatchInfoAnd p C(x y) -> Bool applyMatcher (MATCH _ m) = m . seal2 parseMatch :: Patchy p => PatchMatch -> Either String (MatchFun p) parseMatch (PatternMatch s) = case parse matchParser "match" s of Left err -> Left $ "Invalid -"++"-match pattern '"++s++ "'.\n"++ unlines (map (" "++) $ lines $ show err) -- indent Right m -> Right m matchPattern :: Patchy p => PatchMatch -> Matcher p matchPattern p@(PatternMatch s) = case parseMatch p of Left err -> error err Right m -> makeMatcher s m trivial :: Patchy p => MatchFun p trivial = const True matchParser :: Patchy p => CharParser st (MatchFun p) matchParser = do m <- option trivial submatch eof return m submatch :: Patchy p => CharParser st (MatchFun p) submatch = buildExpressionParser table match "match rule" table :: OperatorTable Char st (MatchFun p) table = [ [prefix "not" negate_match, prefix "!" negate_match ] , [binary "||" or_match, binary "or" or_match, binary "&&" and_match, binary "and" and_match ] ] where binary name fun = Infix (do _ <- trystring name spaces return fun) AssocLeft prefix name fun = Prefix $ do _ <- trystring name spaces return fun negate_match a p = not (a p) or_match m1 m2 p = (m1 p) || (m2 p) and_match m1 m2 p = (m1 p) && (m2 p) trystring :: String -> CharParser st String trystring s = try $ string s match :: Patchy p => CharParser st (MatchFun p) match = between spaces spaces (parens submatch <|> choice matchers_ "simple match") where matchers_ = map createMatchHelper primitiveMatchers createMatchHelper :: (String, String, [String], String -> MatchFun p) -> CharParser st (MatchFun p) createMatchHelper (key,_,_,matcher) = do _ <- trystring key spaces q <- quoted return $ matcher q -- FIXME: would this be better defined in Darcs.Commands.Help? -- | The string that is emitted when the user runs @darcs help --match@. helpOnMatchers :: String helpOnMatchers = unlines $ ["Selecting Patches:", "", "The --patches option yields patches with names matching an `extended'", "regular expression. See regex(7) for details. The --matches option", "yields patches that match a logical (Boolean) expression: one or more", "primitive expressions combined by grouping (parentheses) and the", "complement (not), conjunction (and) and disjunction (or) operators.", "The C notation for logic operators (!, && and ||) can also be used.", "", " --patches=regex is a synonym for --matches='name regex'", " --from-patch and --to-patch are synonyms for --from-match='name... and --to-match='name...", " --from-patch and --to-match can be unproblematically combined:", " darcs changes --from-patch='html.*documentation' --to-match='date 20040212'", "", "The following primitive Boolean expressions are supported:"] ++ keywords ++ ["", "Here are some examples:"] ++ examples where -- This type signature exists to appease GHC. ps :: [(String, String, [String], String -> MatchFun DummyPatch)] ps = primitiveMatchers keywords = [showKeyword k d | (k,d,_,_) <- ps] examples = [showExample k e | (k,_,es,_) <- ps, e <- es] showKeyword keyword description = -- FIXME: it would be nice to have a variable name here: -- "author REGEX - match against author (email address)" -- or "exact STRING - match against exact patch name". " " ++ keyword ++ " - " ++ description ++ "." showExample keyword example = -- FIXME: this string is long, and its not a use case I've -- ever seen in practice. Can we use something else, -- like "darcs changes --matches"? --twb, 2008-12-28 " darcs annotate --summary --match " ++ "'" ++ keyword ++ " " ++ example ++ "'" primitiveMatchers :: Patchy p => [(String, String, [String], String -> MatchFun p)] -- ^ keyword (operator), help description, list -- of examples, matcher function primitiveMatchers = [ ("exact", "check a literal string against the patch name" , ["\"Resolve issue17: use dynamic memory allocation.\""] , exactmatch ) , ("name", "check a regular expression against the patch name" , ["issue17", "\"^[Rr]esolve issue17\\>\""] , mymatch ) , ("author", "check a regular expression against the author name" , ["\"David Roundy\"", "droundy", "droundy@darcs.net"] , authormatch ) , ("hunk", "check a regular expression against the contents of a hunk patch" , ["\"foo = 2\"", "\"^instance .* Foo where$\""] , hunkmatch ) , ("comment", "check a regular expression against the log message" , ["\"prevent deadlocks\""] , logmatch ) , ("hash", "match the darcs hash for a patch" , ["20040403105958-53a90-c719567e92c3b0ab9eddd5290b705712b8b918ef"] , hashmatch ) , ("date", "match the patch date" , ["\"2006-04-02 22:41\"", "\"tea time yesterday\""] , datematch ) , ("touch", "match file paths for a patch" , ["src/foo.c", "src/", "\"src/*.(c|h)\""] , touchmatch ) ] parens :: CharParser st (MatchFun p) -> CharParser st (MatchFun p) parens p = between (string "(") (string ")") p quoted :: CharParser st String quoted = between (char '"') (char '"') (many $ do { _ <- char '\\' -- allow escapes ; try (oneOf ['\\', '"']) <|> return '\\' } <|> noneOf ['"']) <|> between spaces spaces (many $ noneOf " ()") "string" mymatch, exactmatch, authormatch, hunkmatch, hashmatch, datematch, touchmatch :: Patchy p => String -> MatchFun p mymatch r (Sealed2 hp) = isJust $ matchRegex (mkRegex r) $ justName (info hp) exactmatch r (Sealed2 hp) = r == (justName (info hp)) authormatch a (Sealed2 hp) = isJust $ matchRegex (mkRegex a) $ justAuthor (info hp) logmatch :: Patchy p => String -> MatchFun p logmatch l (Sealed2 hp) = isJust $ matchRegex (mkRegex l) $ justLog (info hp) hunkmatch r (Sealed2 hp) = let patch = patchcontents $ hopefully hp regexMatcher = isJust . (matchRegex (mkRegex r) . BC.unpack) in hunkMatches regexMatcher patch hashmatch h (Sealed2 hp) = let rh = makeFilename (info hp) in (rh == h) || (rh == h++".gz") datematch d (Sealed2 hp) = let dm = unsafePerformIO $ parseDateMatcher d in dm $ piDate (info hp) touchmatch r (Sealed2 hp) = let files = listTouchedFiles $ patchcontents $ hopefully hp in or $ map (isJust . matchRegex (mkRegex r)) files darcs-2.8.4/src/Darcs/Patch/MatchData.hs0000644001765600176560000000206512104371431017210 0ustar ganeshganesh-- Copyright (C) 2004 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. module Darcs.Patch.MatchData ( PatchMatch(..), patchMatch, ) where data PatchMatch = PatternMatch String deriving ( Eq ) instance Show PatchMatch where show (PatternMatch m) = "pattern " ++ show m patchMatch :: String -> PatchMatch patchMatch s = PatternMatch s darcs-2.8.4/src/Darcs/Patch/Merge.hs0000644001765600176560000000261212104371431016417 0ustar ganeshganesh#include "gadts.h" -- | -- Module : Darcs.Patch.Merge -- Maintainer : darcs-devel@darcs.net -- Stability : experimental -- Portability : portable module Darcs.Patch.Merge ( Merge(..) , mergeFL ) where import Data.Maybe ( fromJust ) import Darcs.Patch.Commute ( Commute ) import Darcs.Witnesses.Ordered ( (:\/:)(..), (:/\:)(..), FL(..), RL, reverseFL, reverseRL ) -- | Things that can always be merged class Commute p => Merge p where merge :: (p :\/: p) C(x y) -> (p :/\: p) C(x y) instance Merge p => Merge (FL p) where merge (NilFL :\/: x) = x :/\: NilFL merge (x :\/: NilFL) = NilFL :/\: x merge ((x:>:xs) :\/: ys) = fromJust $ do ys' :/\: x' <- return $ mergeFL (x :\/: ys) xs' :/\: ys'' <- return $ merge (ys' :\/: xs) return (ys'' :/\: (x' :>: xs')) instance Merge p => Merge (RL p) where merge (x :\/: y) = case merge (reverseRL x :\/: reverseRL y) of (ry' :/\: rx') -> reverseFL ry' :/\: reverseFL rx' mergeFL :: Merge p => (p :\/: FL p) C(x y) -> (FL p :/\: p) C(x y) mergeFL (p :\/: NilFL) = NilFL :/\: p mergeFL (p :\/: (x :>: xs)) = fromJust $ do x' :/\: p' <- return $ merge (p :\/: x) xs' :/\: p'' <- return $ mergeFL (p' :\/: xs) return ((x' :>: xs') :/\: p'') darcs-2.8.4/src/Darcs/Patch/Named.hs0000644001765600176560000001751212104371431016411 0ustar ganeshganesh-- Copyright (C) 2002-2003 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP #-} #include "gadts.h" module Darcs.Patch.Named ( Named(..), infopatch, adddeps, namepatch, anonymous, getdeps, patch2patchinfo, patchname, patchcontents, fmapNamed, fmapFL_Named ) where import Prelude hiding ( pi ) import Darcs.Patch.Conflict ( Conflict(..), CommuteNoConflicts ) import Darcs.Patch.Effect ( Effect(effect, effectRL) ) import Darcs.Patch.FileHunk ( IsHunk(..) ) import Darcs.Patch.Format ( PatchListFormat ) import Darcs.Patch.Info ( PatchInfo, readPatchInfo, showPatchInfo, patchinfo, humanFriendly, makePatchname, invertName ) import Darcs.Patch.Merge ( Merge(..) ) import Darcs.Patch.Patchy ( Patchy, Commute(..), Invert(..), Apply(..), PatchInspect(..), ReadPatch(..) ) import Darcs.Patch.Prim ( PrimOf, PrimPatchBase ) import Darcs.Patch.ReadMonads ( ParserM, option, lexChar, choice, skipWhile, anyChar ) import Darcs.Patch.Repair ( mapMaybeSnd, Repair(..), RepairToFL, Check(..) ) import Darcs.Patch.Show ( ShowPatchBasic(..), ShowPatch(..), showNamedPrefix ) import Darcs.Patch.Summary ( plainSummary ) import Darcs.Patch.Viewing () -- for ShowPatch FL instances import Darcs.Witnesses.Eq ( MyEq(..) ) import Darcs.Witnesses.Ordered ( (:>)(..), (:\/:)(..), (:/\:)(..), FL, mapFL, mapFL_FL ) import Darcs.Witnesses.Sealed ( Sealed, mapSeal ) import Darcs.Witnesses.Show ( ShowDict(..), Show1(..), Show2(..) ) import Printer ( renderString, ($$), (<+>), (<>), prefix, text, vcat ) -- | The @Named@ type adds a patch info about a patch, that is a name. data Named p C(x y) where NamedP :: !PatchInfo -> ![PatchInfo] -> !(FL p C(x y)) -> Named p C(x y) -- ^ @NamedP info deps p@ represents patch @p@ with name -- @info@. @deps@ is a list of dependencies added at the named patch -- level, compared with the unnamed level (ie, dependencies added with -- @darcs record --ask-deps@). instance PrimPatchBase p => PrimPatchBase (Named p) where type PrimOf (Named p) = PrimOf p instance Effect p => Effect (Named p) where effect (NamedP _ _ p) = effect p effectRL (NamedP _ _ p) = effectRL p instance IsHunk (Named p) where isHunk _ = Nothing instance PatchListFormat (Named p) instance (ReadPatch p, PatchListFormat p) => ReadPatch (Named p) where readPatch' = readNamed readNamed :: (ReadPatch p, PatchListFormat p, ParserM m) => m (Sealed (Named p C(x ))) readNamed = do n <- readPatchInfo d <- readDepends p <- readPatch' return $ (NamedP n d) `mapSeal` p readDepends :: ParserM m => m [PatchInfo] readDepends = option [] $ do lexChar '<' readPis readPis :: ParserM m => m [PatchInfo] readPis = choice [ do pi <- readPatchInfo pis <- readPis return (pi:pis) , do skipWhile (/= '>') _ <- anyChar return [] ] instance Apply p => Apply (Named p) where type ApplyState (Named p) = ApplyState p apply (NamedP _ _ p) = apply p instance RepairToFL p => Repair (Named p) where applyAndTryToFix (NamedP n d p) = mapMaybeSnd (NamedP n d) `fmap` applyAndTryToFix p namepatch :: Patchy p => String -> String -> String -> [String] -> FL p C(x y) -> IO (Named p C(x y)) namepatch date name author desc p | '\n' `elem` name = error "Patch names cannot contain newlines." | otherwise = do pinf <- patchinfo date name author desc return $ NamedP pinf [] p anonymous :: Patchy p => FL p C(x y) -> IO (Named p C(x y)) anonymous p = namepatch "today" "anonymous" "unknown" ["anonymous"] p infopatch :: Patchy p => PatchInfo -> FL p C(x y) -> Named p C(x y) infopatch pi p = NamedP pi [] p adddeps :: Named p C(x y) -> [PatchInfo] -> Named p C(x y) adddeps (NamedP pi _ p) ds = NamedP pi ds p getdeps :: Named p C(x y) -> [PatchInfo] getdeps (NamedP _ ds _) = ds patch2patchinfo :: Named p C(x y) -> PatchInfo patch2patchinfo (NamedP i _ _) = i patchname :: Named p C(x y) -> String patchname (NamedP i _ _) = makePatchname i patchcontents :: Named p C(x y) -> FL p C(x y) patchcontents (NamedP _ _ p) = p fmapNamed :: (FORALL(a b) p C(a b) -> q C(a b)) -> Named p C(x y) -> Named q C(x y) fmapNamed f (NamedP i deps p) = NamedP i deps (mapFL_FL f p) fmapFL_Named :: (FL p C(x y) -> FL q C(x y)) -> Named p C(x y) -> Named q C(x y) fmapFL_Named f (NamedP i deps p) = NamedP i deps (f p) instance (Commute p, MyEq p) => MyEq (Named p) where unsafeCompare (NamedP n1 d1 p1) (NamedP n2 d2 p2) = n1 == n2 && d1 == d2 && unsafeCompare p1 p2 instance (Commute p, Invert p) => Invert (Named p) where invert (NamedP n d p) = NamedP (invertName n) (map invertName d) (invert p) instance Commute p => Commute (Named p) where commute (NamedP n1 d1 p1 :> NamedP n2 d2 p2) = if n2 `elem` d1 || n1 `elem` d2 then Nothing else do (p2' :> p1') <- commute (p1 :> p2) return (NamedP n2 d2 p2' :> NamedP n1 d1 p1') instance Merge p => Merge (Named p) where merge (NamedP n1 d1 p1 :\/: NamedP n2 d2 p2) = case merge (p1 :\/: p2) of (p2' :/\: p1') -> NamedP n2 d2 p2' :/\: NamedP n1 d1 p1' instance PatchInspect p => PatchInspect (Named p) where listTouchedFiles (NamedP _ _ p) = listTouchedFiles p hunkMatches f (NamedP _ _ p) = hunkMatches f p instance (CommuteNoConflicts p, Conflict p) => Conflict (Named p) where listConflictedFiles (NamedP _ _ p) = listConflictedFiles p resolveConflicts (NamedP _ _ p) = resolveConflicts p instance Check p => Check (Named p) where isInconsistent (NamedP _ _ p) = isInconsistent p instance (PatchListFormat p, ShowPatchBasic p) => ShowPatchBasic (Named p) where showPatch (NamedP n [] p) = showPatchInfo n <> showPatch p showPatch (NamedP n d p) = showNamedPrefix n d <+> showPatch p instance (Apply p, CommuteNoConflicts p, Conflict p, IsHunk p, PatchListFormat p, PrimPatchBase p, ShowPatch p) => ShowPatch (Named p) where showContextPatch (NamedP n [] p) = showContextPatch p >>= return . (showPatchInfo n <>) showContextPatch (NamedP n d p) = showContextPatch p >>= return . (showNamedPrefix n d <+>) description (NamedP n _ _) = humanFriendly n summary p = description p $$ text "" $$ prefix " " (plainSummary p) -- this isn't summary because summary does the -- wrong thing with (Named (FL p)) so that it can -- get the summary of a sequence of named patches -- right. summaryFL = vcat . mapFL summary showNicely p@(NamedP _ _ pt) = description p $$ prefix " " (showNicely pt) instance (PatchListFormat p, ShowPatch p) => Show (Named p C(x y)) where show = renderString . showPatch instance (PatchListFormat p, ShowPatch p) => Show1 (Named p C(x)) where showDict1 = ShowDictClass instance (PatchListFormat p, ShowPatch p) => Show2 (Named p) where showDict2 = ShowDictClass darcs-2.8.4/src/Darcs/Patch/OldDate.hs0000644001765600176560000003374412104371431016706 0ustar ganeshganesh-- Copyright (C) 2003 Peter Simons -- Copyright (C) 2003,2008 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. -- This module is intended to provide backwards-compatibility in the parsing -- of darcs patches. In other words: don't change it, new features don't get -- added here. The only user should be Darcs.Patch.Info. module Darcs.Patch.OldDate ( readUTCDate, showIsoDateTime ) where import Text.ParserCombinators.Parsec import System.Time import Data.Char ( toUpper, isDigit ) import Control.Monad ( liftM, liftM2 ) import qualified Data.ByteString.Char8 as B import Data.Maybe ( fromMaybe ) -- | Read/interpret a date string, assuming UTC if timezone -- is not specified in the string readUTCDate :: String -> CalendarTime readUTCDate = readDate 0 readDate :: Int -> String -> CalendarTime readDate tz d = case parseDate tz d of Left e -> error e Right ct -> ct parseDate :: Int -> String -> Either String CalendarTime parseDate tz d = if length d >= 14 && B.all isDigit bd then Right $ CalendarTime (readI $ B.take 4 bd) (toEnum $ (+ (-1)) $ readI $ B.take 2 $ B.drop 4 bd) (readI $ B.take 2 $ B.drop 6 bd) -- Day (readI $ B.take 2 $ B.drop 8 bd) -- Hour (readI $ B.take 2 $ B.drop 10 bd) -- Minute (readI $ B.take 2 $ B.drop 12 bd) -- Second 0 Sunday 0 -- Picosecond, weekday and day of year unknown "GMT" 0 False else let dt = do { x <- dateTime tz; eof; return x } in case parse dt "" d of Left e -> Left $ "bad date: "++d++" - "++show e Right ct -> Right ct where bd = B.pack (take 14 d) readI s = fst $ fromMaybe (error "parseDate: invalid date") (B.readInt s) showIsoDateTime :: CalendarTime -> String showIsoDateTime ct = concat [ show $ ctYear ct , twoDigit . show . (+1) . fromEnum $ ctMonth ct , twoDigit . show $ ctDay ct , twoDigit . show $ ctHour ct , twoDigit . show $ ctMin ct , twoDigit . show $ ctSec ct ] where twoDigit [] = undefined twoDigit x@(_:[]) = '0' : x twoDigit x@(_:_:[]) = x twoDigit _ = undefined ----- Parser Combinators --------------------------------------------- -- |Case-insensitive variant of Parsec's 'char' function. caseChar :: Char -> GenParser Char a Char caseChar c = satisfy (\x -> toUpper x == toUpper c) -- |Case-insensitive variant of Parsec's 'string' function. caseString :: String -> GenParser Char a () caseString cs = mapM_ caseChar cs cs -- |Match a parser at least @n@ times. manyN :: Int -> GenParser a b c -> GenParser a b [c] manyN n p | n <= 0 = return [] | otherwise = liftM2 (++) (count n p) (many p) -- |Match a parser at least @n@ times, but no more than @m@ times. manyNtoM :: Int -> Int -> GenParser a b c -> GenParser a b [c] manyNtoM n m p | n < 0 = return [] | n > m = return [] | n == m = count n p | n == 0 = foldr (<|>) (return []) (map (\x -> try $ count x p) (reverse [1..m])) | otherwise = liftM2 (++) (count n p) (manyNtoM 0 (m-n) p) ----- Date/Time Parser ----------------------------------------------- dateTime :: Int -> CharParser a CalendarTime dateTime tz = choice [try $ cvsDateTime tz, try $ iso8601DateTime tz, oldDateTime] cvsDateTime :: Int -> CharParser a CalendarTime cvsDateTime tz = do y <- year _ <- char '/' mon <- monthNum _ <- char '/' d <- day _ <- mySpaces h <- hour _ <- char ':' m <- minute _ <- char ':' s <- second z <- option tz $ mySpaces >> zone return (CalendarTime y mon d h m s 0 Monday 0 "" z False) oldDateTime :: CharParser a CalendarTime oldDateTime = do wd <- dayName _ <- mySpaces mon <- monthName _ <- mySpaces d <- day _ <- mySpaces h <- hour _ <- char ':' m <- minute _ <- char ':' s <- second _ <- mySpaces z <- zone _ <- mySpaces y <- year return (CalendarTime y mon d h m s 0 wd 0 "" z False) {- FIXME: In case you ever want to use this outside of darcs, you should note that this implementation of ISO 8601 is not complete. reluctant to implement (ambiguous!): * years > 9999 * truncated representations with implied century (89 for 1989) unimplemented: * repeated durations (not relevant) * lowest order component fractions in intervals * negative dates (BC) unverified or too relaxed: * the difference between 24h and 0h * allows stuff like 2005-1212; either you use the hyphen all the way (2005-12-12) or you don't use it at all (20051212), but you don't use it halfway, likewise with time * No bounds checking whatsoever on intervals! (next action: read iso doc to see if bounds-checking required?) -} iso8601DateTime :: Int -> CharParser a CalendarTime iso8601DateTime localTz = try $ do d <- iso8601Date t <- option id $ try $ do optional $ oneOf " T" iso8601Time return $ t $ d { ctTZ = localTz } iso8601Date :: CharParser a CalendarTime iso8601Date = do d <- calendar_date <|> week_date <|> ordinal_date return $ foldr ($) nullCalendar d where calendar_date = -- yyyy-mm-dd try $ do d <- optchain year_ [ (dash, month_), (dash, day_) ] -- allow other variants to be parsed correctly notFollowedBy (digit <|> char 'W') return d week_date = --yyyy-Www-dd try $ do yfn <- year_ optional dash _ <- char 'W' -- offset human 'week 1' -> computer 'week 0' w' <- (\x -> x-1) `liftM` twoDigits wd <- option 1 $ do { optional dash; nDigits 1 } let y = yfn nullCalendar firstDay = ctWDay y -- things that make this complicated -- 1. iso8601 weeks start from Monday; Haskell weeks start from Sunday -- 2. the first week is the one that contains at least Thursday -- if the year starts after Thursday, then some days of the year -- will have already passed before the first week let afterThursday = firstDay == Sunday || firstDay > Thursday w = if afterThursday then w'+1 else w' diff c = c { ctDay = (7 * w) + wd - (fromEnum firstDay) } return [(toUTCTime.toClockTime.diff.yfn)] ordinal_date = -- yyyy-ddd try $ optchain year_ [ (dash, yearDay_) ] -- year_ = try $ do y <- fourDigits "year (0000-9999)" return $ \c -> c { ctYear = y } month_ = try $ do m <- twoDigits "month (1 to 12)" -- we (artificially) use ctPicosec to indicate -- whether the month has been specified. return $ \c -> c { ctMonth = intToMonth m, ctPicosec = 0 } day_ = try $ do d <- twoDigits "day in month (1 to 31)" return $ \c -> c { ctDay = d } yearDay_ = try $ do d <- nDigits 3 "day in year (1 to 366)" return $ \c -> c { ctYDay = d } dash = char '-' -- we return a function which sets the time on another calendar iso8601Time :: CharParser a (CalendarTime -> CalendarTime) iso8601Time = try $ do ts <- optchain hour_ [ (colon , min_) , (colon , sec_) , (oneOf ",.", pico_) ] z <- option id $ choice [ zulu , offset ] return $ foldr (.) id (z:ts) where hour_ = do h <- twoDigits return $ \c -> c { ctHour = h } min_ = do m <- twoDigits return $ \c -> c { ctMin = m } sec_ = do s <- twoDigits return $ \c -> c { ctSec = s } pico_ = do digs <- many digit let picoExp = 12 digsExp = length digs let frac | null digs = 0 | digsExp > picoExp = read $ take picoExp digs | otherwise = 10 ^ (picoExp - digsExp) * (read digs) return $ \c -> c { ctPicosec = frac } zulu = do { _ <- char 'Z'; return (\c -> c { ctTZ = 0 }) } offset = do sign <- choice [ do { char '+' >> return 1 } , do { char '-' >> return (-1) } ] h <- twoDigits m <- option 0 $ do { optional colon; twoDigits } return $ \c -> c { ctTZ = sign * 60 * ((h*60)+m) } colon = char ':' optchain :: CharParser a b -> [(CharParser a c, CharParser a b)] -> CharParser a [b] optchain p next = try $ do r1 <- p r2 <- case next of [] -> return [] ((sep,p2):next2) -> option [] $ do { optional sep; optchain p2 next2 } return (r1:r2) nDigits :: Int -> CharParser a Int nDigits n = read `liftM` count n digit twoDigits, fourDigits :: CharParser a Int twoDigits = nDigits 2 fourDigits = nDigits 4 mySpaces :: CharParser a String mySpaces = manyN 1 $ char ' ' dayName :: CharParser a Day dayName = choice [ caseString "Mon" >> return Monday , try (caseString "Tue") >> return Tuesday , caseString "Wed" >> return Wednesday , caseString "Thu" >> return Thursday , caseString "Fri" >> return Friday , try (caseString "Sat") >> return Saturday , caseString "Sun" >> return Sunday ] year :: CharParser a Int year = fourDigits monthNum :: CharParser a Month monthNum = do mn <- manyNtoM 1 2 digit return $ intToMonth $ (read mn :: Int) intToMonth :: Int -> Month intToMonth 1 = January intToMonth 2 = February intToMonth 3 = March intToMonth 4 = April intToMonth 5 = May intToMonth 6 = June intToMonth 7 = July intToMonth 8 = August intToMonth 9 = September intToMonth 10 = October intToMonth 11 = November intToMonth 12 = December intToMonth _ = error "invalid month!" monthName :: CharParser a Month monthName = choice [ try (caseString "Jan") >> return January , caseString "Feb" >> return February , try (caseString "Mar") >> return March , try (caseString "Apr") >> return April , caseString "May" >> return May , try (caseString "Jun") >> return June , caseString "Jul" >> return July , caseString "Aug" >> return August , caseString "Sep" >> return September , caseString "Oct" >> return October , caseString "Nov" >> return November , caseString "Dec" >> return December ] day :: CharParser a Int day = do d <- manyNtoM 1 2 digit return (read d :: Int) hour :: CharParser a Int hour = twoDigits minute :: CharParser a Int minute = twoDigits second :: CharParser a Int second = twoDigits zone :: CharParser a Int zone = choice [ do { _ <- char '+'; h <- hour; m <- minute; return (((h*60)+m)*60) } , do { _ <- char '-'; h <- hour; m <- minute; return (-((h*60)+m)*60) } , mkZone "UTC" 0 , mkZone "UT" 0 , mkZone "GMT" 0 , mkZone "EST" (-5) , mkZone "EDT" (-4) , mkZone "CST" (-6) , mkZone "CDT" (-5) , mkZone "MST" (-7) , mkZone "MDT" (-6) , mkZone "PST" (-8) , mkZone "PDT" (-7) , mkZone "CEST" 2 , mkZone "EEST" 3 -- if we don't understand it, just give a GMT answer... , do { _ <- manyTill (oneOf $ ['a'..'z']++['A'..'Z']++[' ']) (lookAhead space_digit); return 0 } ] where mkZone n o = try $ do { caseString n; return (o*60*60) } space_digit = try $ do { _ <- char ' '; oneOf ['0'..'9'] } nullCalendar :: CalendarTime nullCalendar = CalendarTime 0 January 0 0 0 0 1 Sunday 0 "" 0 False darcs-2.8.4/src/Darcs/Patch/PatchInfoAnd.hs0000644001765600176560000002451712104371431017666 0ustar ganeshganesh-- Copyright (C) 2006 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP, UndecidableInstances #-} -- XXX Undecidable only in GHC < 7 #include "gadts.h" module Darcs.Patch.PatchInfoAnd ( Hopefully, PatchInfoAnd, WPatchInfo, unWPatchInfo, compareWPatchInfo, piap, n2pia, patchInfoAndPatch, fmapPIAP, fmapFL_PIAP, conscientiously, hopefully, info, winfo, hopefullyM, createHashed, extractHash, actually, unavailable, patchDesc ) where import System.IO.Unsafe ( unsafeInterleaveIO ) import Darcs.SignalHandler ( catchNonSignal ) import Printer ( Doc, renderString, errorDoc, text, ($$), vcat ) import Darcs.Patch.Info ( PatchInfo, humanFriendly, justName ) import Darcs.Patch ( RepoPatch, Named, patch2patchinfo ) import Darcs.Patch.Conflict ( Conflict, CommuteNoConflicts ) import Darcs.Patch.Effect ( Effect(..) ) import Darcs.Patch.FileHunk ( IsHunk(..) ) import Darcs.Patch.Format ( PatchListFormat ) import Darcs.Patch.Merge ( Merge(..) ) import Darcs.Patch.Named ( fmapNamed, fmapFL_Named ) import Darcs.Patch.Prim ( PrimPatchBase(..) ) import Darcs.Patch.Patchy ( Patchy, ReadPatch(..), Apply(..), Invert(..), ShowPatch(..), Commute(..), PatchInspect(..) ) import Darcs.Patch.Repair ( Repair(..), RepairToFL ) import Darcs.Patch.Show ( ShowPatchBasic(..) ) import Darcs.Witnesses.Eq ( MyEq(..), EqCheck(..) ) import Darcs.Witnesses.Unsafe ( unsafeCoerceP ) import Darcs.Witnesses.Ordered ( (:>)(..), (:\/:)(..), (:/\:)(..), FL, mapFL ) import Darcs.Witnesses.Sealed ( Sealed(Sealed), seal, mapSeal ) import Darcs.Utils ( prettyException ) import Storage.Hashed.Tree( Tree ) import Control.Applicative ( (<$>) ) -- | @'Hopefully' p C@ @(x y)@ is @'Either' String (p C@ @(x y))@ in a -- form adapted to darcs patches. The @C@ @(x y)@ represents the type -- witness for the patch that should be there. The @Hopefully@ type -- just tells whether we expect the patch to be hashed or not, and -- 'SimpleHopefully' does the real work of emulating -- 'Either'. @Hopefully sh@ represents an expected unhashed patch, and -- @Hashed hash sh@ represents an expected hashed patch with its hash. data Hopefully a C(x y) = Hopefully (SimpleHopefully a C(x y)) | Hashed String (SimpleHopefully a C(x y)) -- | @SimpleHopefully@ is a variant of @Either String@ adapted for -- type witnesses. @Actually@ is the equivalent of @Right@, while -- @Unavailable@ is @Left@. data SimpleHopefully a C(x y) = Actually (a C(x y)) | Unavailable String -- | @'PatchInfoAnd' p C(a b)@ represents a hope we have to get a -- patch through its info. We're not sure we have the patch, but we -- know its info. data PatchInfoAnd p C(a b) = PIAP !PatchInfo (Hopefully (Named p) C(a b)) instance PrimPatchBase p => PrimPatchBase (PatchInfoAnd p) where type PrimOf (PatchInfoAnd p) = PrimOf p -- | @'WPatchInfo' C(a b)@ represents the info of a patch, marked with -- the patch's witnesses. newtype WPatchInfo C(a b) = WPatchInfo { unWPatchInfo :: PatchInfo } -- This is actually unsafe if we ever commute patches and then compare them -- using this function. TODO: consider adding an extra existential to WPatchInfo -- (as with TaggedPatch in Darcs.Patch.Choices) compareWPatchInfo :: WPatchInfo C(a b) -> WPatchInfo C(c d) -> EqCheck C((a, b) (c, d)) compareWPatchInfo (WPatchInfo x) (WPatchInfo y) = if x == y then unsafeCoerceP IsEq else NotEq instance MyEq WPatchInfo where WPatchInfo x `unsafeCompare` WPatchInfo y = x == y fmapH :: (a C(x y) -> b C(w z)) -> Hopefully a C(x y) -> Hopefully b C(w z) fmapH f (Hopefully sh) = Hopefully (ff sh) where ff (Actually a) = Actually (f a) ff (Unavailable e) = Unavailable e fmapH f (Hashed h sh) = Hashed h (ff sh) where ff (Actually a) = Actually (f a) ff (Unavailable e) = Unavailable e info :: PatchInfoAnd p C(a b) -> PatchInfo info (PIAP i _) = i patchDesc :: forall p C(x y) . PatchInfoAnd p C(x y) -> String patchDesc p = justName $ info p winfo :: PatchInfoAnd p C(a b) -> WPatchInfo C(a b) winfo (PIAP i _) = WPatchInfo i -- | @'piap' i p@ creates a PatchInfoAnd containing p with info i. piap :: PatchInfo -> Named p C(a b) -> PatchInfoAnd p C(a b) piap i p = PIAP i (Hopefully $ Actually p) -- | @n2pia@ creates a PatchInfoAnd representing a @Named@ patch. n2pia :: Named p C(x y) -> PatchInfoAnd p C(x y) n2pia x = patch2patchinfo x `piap` x patchInfoAndPatch :: PatchInfo -> Hopefully (Named p) C(a b) -> PatchInfoAnd p C(a b) patchInfoAndPatch = PIAP fmapPIAP :: (FORALL(a b) p C(a b) -> q C(a b)) -> PatchInfoAnd p C(x y) -> PatchInfoAnd q C(x y) fmapPIAP f (PIAP i hp) = PIAP i (fmapH (fmapNamed f) hp) fmapFL_PIAP :: (FL p C(x y) -> FL q C(x y)) -> PatchInfoAnd p C(x y) -> PatchInfoAnd q C(x y) fmapFL_PIAP f (PIAP i hp) = PIAP i (fmapH (fmapFL_Named f) hp) -- | @'hopefully' hp@ tries to get a patch from a 'PatchInfoAnd' -- value. If it fails, it outputs an error \"failed to read patch: -- \\". We get the description of the patch -- from the info part of 'hp' hopefully :: PatchInfoAnd p C(a b) -> Named p C(a b) hopefully = conscientiously $ \e -> text "failed to read patch:" $$ e -- | @'conscientiously' er hp@ tries to extract a patch from a 'PatchInfoAnd'. -- If it fails, it applies the error handling function @er@ to a description -- of the patch info component of @hp@. conscientiously :: (Doc -> Doc) -> PatchInfoAnd p C(a b) -> Named p C(a b) conscientiously er (PIAP pinf hp) = case hopefully2either hp of Right p -> p Left e -> errorDoc $ er (humanFriendly pinf $$ text e) -- | @hopefullyM@ is a version of @hopefully@ which calls @fail@ in a -- monad instead of erroring. hopefullyM :: Monad m => PatchInfoAnd p C(a b) -> m (Named p C(a b)) hopefullyM (PIAP pinf hp) = case hopefully2either hp of Right p -> return p Left e -> fail $ renderString (humanFriendly pinf $$ text e) -- Any recommendations for a nice adverb to name the below? hopefully2either :: Hopefully a C(x y) -> Either String (a C(x y)) hopefully2either (Hopefully (Actually p)) = Right p hopefully2either (Hashed _ (Actually p)) = Right p hopefully2either (Hopefully (Unavailable e)) = Left e hopefully2either (Hashed _ (Unavailable e)) = Left e actually :: a C(x y) -> Hopefully a C(x y) actually = Hopefully . Actually createHashed :: String -> (String -> IO (Sealed (a C(x)))) -> IO (Sealed (Hopefully a C(x))) createHashed h f = do mapSeal (Hashed h) `fmap` unsafeInterleaveIO (f' `catchNonSignal` handler) where f' = do Sealed x <- f h return (Sealed (Actually x)) handler e = return $ seal $ Unavailable $ prettyException e extractHash :: PatchInfoAnd p C(a b) -> Either (Named p C(a b)) String extractHash (PIAP _ (Hashed s _)) = Right s extractHash hp = Left $ conscientiously (\e -> text "unable to read patch:" $$ e) hp unavailable :: String -> Hopefully a C(x y) unavailable = Hopefully . Unavailable instance (Commute p, MyEq p) => MyEq (PatchInfoAnd p) where unsafeCompare (PIAP i _) (PIAP i2 _) = i == i2 --instance Invert (p C(x y)) => Invert (PatchInfoAnd (p C(x y))) where instance (Commute p, Invert p) => Invert (PatchInfoAnd p) where invert (PIAP i p) = PIAP i (invert `fmapH` p) instance PatchListFormat (PatchInfoAnd p) instance (PatchListFormat p, ShowPatchBasic p) => ShowPatchBasic (PatchInfoAnd p) where showPatch (PIAP n p) = case hopefully2either p of Right x -> showPatch x Left _ -> humanFriendly n instance (Apply p, Conflict p, CommuteNoConflicts p, IsHunk p, PatchListFormat p, PrimPatchBase p, ShowPatch p, ApplyState p ~ Tree) => ShowPatch (PatchInfoAnd p) where showContextPatch (PIAP n p) = case hopefully2either p of Right x -> showContextPatch x Left _ -> return $ humanFriendly n description (PIAP n _) = humanFriendly n summary (PIAP n p) = case hopefully2either p of Right x -> summary x Left _ -> humanFriendly n summaryFL = vcat . mapFL summary showNicely (PIAP n p) = case hopefully2either p of Right x -> showNicely x Left _ -> humanFriendly n instance Commute p => Commute (PatchInfoAnd p) where commute (x :> y) = do y' :> x' <- commute (hopefully x :> hopefully y) return $ (info y `piap` y') :> (info x `piap` x') instance Merge p => Merge (PatchInfoAnd p) where merge (x :\/: y) = case merge (hopefully x :\/: hopefully y) of y' :/\: x' -> (info y `piap` y') :/\: (info x `piap` x') instance PatchInspect p => PatchInspect (PatchInfoAnd p) where listTouchedFiles = listTouchedFiles . hopefully hunkMatches _ _ = error "hunkmatches not implemented for PatchInfoAnd" instance Apply p => Apply (PatchInfoAnd p) where type ApplyState (PatchInfoAnd p) = ApplyState p apply p = apply $ hopefully p instance RepairToFL p => Repair (PatchInfoAnd p) where applyAndTryToFix p = do mp' <- applyAndTryToFix $ hopefully p case mp' of Nothing -> return Nothing Just (e,p') -> return $ Just (e, n2pia p') instance (ReadPatch p, PatchListFormat p) => ReadPatch (PatchInfoAnd p) where readPatch' = mapSeal n2pia <$> readPatch' instance Effect p => Effect (PatchInfoAnd p) where effect = effect . hopefully effectRL = effectRL . hopefully instance IsHunk (PatchInfoAnd p) where isHunk _ = Nothing instance (RepoPatch p, ApplyState p ~ Tree) => Patchy (PatchInfoAnd p) darcs-2.8.4/src/Darcs/Patch/Patchy.hs0000644001765600176560000000256612104371431016620 0ustar ganeshganesh-- Copyright (C) 2007 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP #-} #include "gadts.h" module Darcs.Patch.Patchy ( Patchy, Apply(..), Commute(..), Invert(..), PatchInspect(..), ReadPatch(..), showPatch, ShowPatch(..) ) where import Darcs.Patch.Apply ( Apply(..) ) import Darcs.Patch.Commute ( Commute(..) ) import Darcs.Patch.Invert ( Invert(..) ) import Darcs.Patch.Inspect ( PatchInspect(..) ) import Darcs.Patch.Read ( ReadPatch(..) ) import Darcs.Patch.Show ( showPatch, ShowPatch(..), ShowPatchBasic ) import Darcs.Witnesses.Eq ( MyEq ) class (MyEq p, Apply p, Commute p, PatchInspect p, ShowPatch p, ReadPatch p, Invert p) => Patchy p darcs-2.8.4/src/Darcs/Patch/Permutations.hs0000644001765600176560000003372312104371431020061 0ustar ganeshganesh-- Copyright (C) 2002-2003 David Roundy -- Copyright (C) 2009 Ganesh Sittampalam -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# OPTIONS_GHC -fno-warn-orphans #-} {-# LANGUAGE CPP #-} #include "gadts.h" module Darcs.Patch.Permutations ( removeFL, removeRL, removeCommon, commuteWhatWeCanFL, commuteWhatWeCanRL, genCommuteWhatWeCanRL, partitionFL, partitionRL, simpleHeadPermutationsFL, headPermutationsRL, headPermutationsFL, removeSubsequenceFL, removeSubsequenceRL, partitionConflictingFL, CommuteFn, selfCommuter, commuterIdFL, commuterFLId, commuterIdRL ) where import Data.Maybe ( mapMaybe ) import Darcs.Patch.Commute ( Commute, commute, commuteFLorComplain, commuteRL ) import Darcs.Patch.Invert ( Invert(..), invertFL, invertRL ) import Darcs.Witnesses.Eq ( MyEq(..), EqCheck(..) ) import Darcs.Witnesses.Ordered ( FL(..), RL(..), (:>)(..), (+<+) , reverseFL, (+>+), (:\/:)(..), lengthFL , lengthRL, reverseRL ) #include "impossible.h" -- |split an 'FL' into "left" and "right" lists according to a predicate @p@, using commutation as necessary. -- If a patch does satisfy the predicate but cannot be commuted past one that does not satisfy -- the predicate, it goes in the "middle" list; to sum up, we have: @all p left@ and @all (not.p) right@, while -- midddle is mixed. partitionFL :: Commute p => (FORALL(u v) p C(u v) -> Bool) -- ^predicate; if true we would like the patch in the "left" list -> FL p C(x y) -- ^input 'FL' -> ((FL p :> FL p :> FL p) C(x y)) -- ^"left", "middle" and "right" -- optimise by using an accumulating parameter to track all the "right" patches that we've found so far partitionFL' :: Commute p => (FORALL(u v) p C(u v) -> Bool) -> RL p C(a b) -- the "middle" patches found so far -> RL p C(b c) -- the "right" patches found so far -> FL p C(c d) -> ((FL p :> FL p :> FL p) C(a d)) partitionFL keepleft ps = partitionFL' keepleft NilRL NilRL ps partitionFL' _ middle right NilFL = (NilFL :> reverseRL middle :> reverseRL right) partitionFL' keepleft middle right (p :>: ps) | keepleft p = case commuteRL (right :> p) of Just (p' :> right') -> case commuteRL (middle :> p') of Just (p'' :> middle') -> case partitionFL' keepleft middle' right' ps of (a :> b :> c) -> (p'' :>: a :> b :> c) Nothing -> partitionFL' keepleft (p' :<: middle) right' ps Nothing -> case commuteWhatWeCanRL (right :> p) of (tomiddle :> p' :> right') -> partitionFL' keepleft (p' :<: tomiddle +<+ middle) right' ps | otherwise = partitionFL' keepleft middle (p :<: right) ps -- |split an 'RL' into "left" and "right" lists according to a predicate, using commutation as necessary. -- If a patch does satisfy the predicate but cannot be commuted past one that does not satisfy -- the predicate, it goes in the "left" list. partitionRL :: Commute p => (FORALL(u v) p C(u v) -> Bool) -- ^predicate; if true we would like the patch in the "right" list -> RL p C(x y) -- ^input 'RL' -> (RL p :> RL p) C(x y) -- ^"left" and "right" results -- optimise by using an accumulating parameter to track all the "left" patches that we've found so far partitionRL' :: Commute p => (FORALL(u v) p C(u v) -> Bool) -> RL p C(x z) -> FL p C(z y) -- the "left" patches found so far -> (RL p :> RL p) C(x y) partitionRL keepright ps = partitionRL' keepright ps NilFL partitionRL' _ NilRL qs = reverseFL qs :> NilRL partitionRL' keepright (p :<: ps) qs | keepright p, Right (qs' :> p') <- commuteFLorComplain (p :> qs) = case partitionRL' keepright ps qs' of a :> b -> a :> p' :<: b | otherwise = partitionRL' keepright ps (p :>: qs) commuteWhatWeCanFL :: Commute p => (p :> FL p) C(x y) -> (FL p :> p :> FL p) C(x y) commuteWhatWeCanFL (p :> x :>: xs) = case commute (p :> x) of Nothing -> case commuteWhatWeCanFL (x :> xs) of xs1 :> x' :> xs2 -> case commuteWhatWeCanFL (p :> xs1) of xs1' :> p' :> xs2' -> xs1' :> p' :> xs2' +>+ x' :>: xs2 Just (x' :> p') -> case commuteWhatWeCanFL (p' :> xs) of a :> p'' :> c -> x' :>: a :> p'' :> c commuteWhatWeCanFL (y :> NilFL) = NilFL :> y :> NilFL commuteWhatWeCanRL :: Commute p => (RL p :> p) C(x y) -> (RL p :> p :> RL p) C(x y) commuteWhatWeCanRL = genCommuteWhatWeCanRL commute genCommuteWhatWeCanRL :: (FORALL(a b) ((p :> p) C(a b) -> Maybe ((p :> p) C(a b)))) -> (RL p :> p) C(x y) -> (RL p :> p :> RL p) C(x y) genCommuteWhatWeCanRL com (x :<: xs :> p) = case com (x :> p) of Nothing -> case genCommuteWhatWeCanRL com (xs :> x) of xs1 :> x' :> xs2 -> case genCommuteWhatWeCanRL com (xs2 :> p) of xs1' :> p' :> xs2' -> xs1' +<+ x' :<: xs1 :> p' :> xs2' Just (p' :> x') -> case genCommuteWhatWeCanRL com (xs :> p') of a :> p'' :> c -> a :> p'' :> x' :<: c genCommuteWhatWeCanRL _ (NilRL :> y) = NilRL :> y :> NilRL removeCommon :: (MyEq p, Commute p) => (FL p :\/: FL p) C(x y) -> (FL p :\/: FL p) C(x y) removeCommon (xs :\/: NilFL) = xs :\/: NilFL removeCommon (NilFL :\/: xs) = NilFL :\/: xs removeCommon (xs :\/: ys) = rc xs (headPermutationsFL ys) where rc :: (MyEq p, Commute p) => FL p C(x y) -> [(p:>FL p) C(x z)] -> (FL p :\/: FL p) C(y z) rc nms ((n:>ns):_) | Just ms <- removeFL n nms = removeCommon (ms :\/: ns) rc ms [n:>ns] = ms :\/: n:>:ns rc ms (_:nss) = rc ms nss rc _ [] = impossible -- because we already checked for NilFL case -- | 'removeFL' @x xs@ removes @x@ from @xs@ if @x@ can be commuted to its head. -- Otherwise it returns 'Nothing' removeFL :: (MyEq p, Commute p) => p C(x y) -> FL p C(x z) -> Maybe (FL p C(y z)) removeFL x xs = r x $ headPermutationsFL xs where r :: (MyEq p, Commute p) => p C(x y) -> [(p:>FL p) C(x z)] -> Maybe (FL p C(y z)) r _ [] = Nothing r z ((z':>zs):zss) | IsEq <- z =\/= z' = Just zs | otherwise = r z zss -- | 'removeRL' is like 'removeFL' except with 'RL' removeRL :: (MyEq p, Commute p) => p C(y z) -> RL p C(x z) -> Maybe (RL p C(x y)) removeRL x xs = r x $ headPermutationsRL xs where r :: (MyEq p, Commute p) => p C(y z) -> [RL p C(x z)] -> Maybe (RL p C(x y)) r z ((z':<:zs):zss) | IsEq <- z =/\= z' = Just zs | otherwise = r z zss r _ _ = Nothing -- | 'removeSubsequenceFL' @ab abc@ returns @Just c'@ where all the patches in -- @ab@ have been commuted out of it, if possible. If this is not possible -- for any reason (the set of patches @ab@ is not actually a subset of @abc@, -- or they can't be commuted out) we return 'Nothing'. removeSubsequenceFL :: (MyEq p, Commute p) => FL p C(a b) -> FL p C(a c) -> Maybe (FL p C(b c)) removeSubsequenceFL a b | lengthFL a > lengthFL b = Nothing | otherwise = rsFL a b where rsFL :: (MyEq p, Commute p) => FL p C(a b) -> FL p C(a c) -> Maybe (FL p C(b c)) rsFL NilFL ys = Just ys rsFL (x:>:xs) yys = removeFL x yys >>= removeSubsequenceFL xs -- | 'removeSubsequenceRL' is like @removeSubsequenceFL@ except that it works -- on 'RL' removeSubsequenceRL :: (MyEq p, Commute p) => RL p C(ab abc) -> RL p C(a abc) -> Maybe (RL p C(a ab)) removeSubsequenceRL a b | lengthRL a > lengthRL b = Nothing | otherwise = rsRL a b where rsRL :: (MyEq p, Commute p) => RL p C(ab abc) -> RL p C(a abc) -> Maybe (RL p C(a ab)) rsRL NilRL ys = Just ys rsRL (x:<:xs) yys = removeRL x yys >>= removeSubsequenceRL xs -- | This is a minor variant of 'headPermutationsFL' with each permutation -- is simply returned as a 'FL' simpleHeadPermutationsFL :: Commute p => FL p C(x y) -> [FL p C(x y)] simpleHeadPermutationsFL ps = map (\ (x:>xs) -> x:>:xs) $ headPermutationsFL ps -- | 'headPermutationsFL' @p:>:ps@ returns all the permutations of the list -- in which one element of @ps@ is commuted past @p@ -- -- Suppose we have a sequence of patches -- -- > X h a y s-t-c k -- -- Suppose furthermore that the patch @c@ depends on @t@, which in turn -- depends on @s@. This function will return -- -- > X :> h a y s t c k -- > h :> X a y s t c k -- > a :> X h y s t c k -- > y :> X h a s t c k -- > s :> X h a y t c k -- > k :> X h a y s t c headPermutationsFL :: Commute p => FL p C(x y) -> [(p :> FL p) C(x y)] headPermutationsFL NilFL = [] headPermutationsFL (p:>:ps) = (p:>ps) : mapMaybe (swapfirstFL.(p:>)) (headPermutationsFL ps) where swapfirstFL (p1:>p2:>xs) = do p2':>p1' <- commute (p1:>p2) Just $ p2':>p1':>:xs -- | 'headPermutationsRL' is like 'headPermutationsFL', except that we -- operate on an 'RL' (in other words, we are pushing things to the end of a -- patch sequence instead of to the beginning). headPermutationsRL :: Commute p => RL p C(x y) -> [RL p C(x y)] headPermutationsRL NilRL = [] headPermutationsRL (p:<:ps) = (p:<:ps) : mapMaybe (swapfirstRL.(p:<:)) (headPermutationsRL ps) where swapfirstRL (p1:<:p2:<:xs) = do p1':>p2' <- commute (p2:>p1) Just $ p2':<:p1':<:xs swapfirstRL _ = Nothing instance (MyEq p, Commute p) => MyEq (FL p) where a =\/= b | lengthFL a /= lengthFL b = NotEq | otherwise = cmpSameLength a b where cmpSameLength :: FL p C(x y) -> FL p C(x z) -> EqCheck C(y z) cmpSameLength (x:>:xs) xys | Just ys <- removeFL x xys = cmpSameLength xs ys cmpSameLength NilFL NilFL = IsEq cmpSameLength _ _ = NotEq xs =/\= ys = reverseFL xs =/\= reverseFL ys instance (Invert p, Commute p) => Invert (FL p) where invert = reverseRL . invertFL instance (MyEq p, Commute p) => MyEq (RL p) where unsafeCompare = bug "Buggy use of unsafeCompare on RL" a =/\= b | lengthRL a /= lengthRL b = NotEq | otherwise = cmpSameLength a b where cmpSameLength :: RL p C(x y) -> RL p C(w y) -> EqCheck C(x w) cmpSameLength (x:<:xs) xys | Just ys <- removeRL x xys = cmpSameLength xs ys cmpSameLength NilRL NilRL = IsEq cmpSameLength _ _ = NotEq xs =\/= ys = reverseRL xs =\/= reverseRL ys instance (Commute p, Invert p) => Invert (RL p) where invert = reverseFL . invertRL -- |CommuteFn is the basis of a general framework for building up commutation -- operations between different patch types in a generic manner. Unfortunately -- type classes are not well suited to the problem because of the multiple possible -- routes by which the commuter for (FL p1, FL p2) can be built out of the -- commuter for (p1, p2) - and more complicated problems when we start building -- multiple constructors on top of each other. The type class resolution machinery -- really can't cope with selecting some route, because it doesn't know that all -- possible routes should be equivalent. type CommuteFn p1 p2 = FORALL(x y) (p1 :> p2) C(x y) -> Maybe ((p2 :> p1) C(x y)) -- |Build a commuter between a patch and itself using the operation from the type class. selfCommuter :: Commute p => CommuteFn p p selfCommuter = commute commuterIdRL :: CommuteFn p1 p2 -> CommuteFn p1 (RL p2) commuterIdRL _ (x :> NilRL) = return (NilRL :> x) commuterIdRL commuter (x :> (y :<: ys)) = do ys' :> x' <- commuterIdRL commuter (x :> ys) y' :> x'' <- commuter (x' :> y) return ((y' :<: ys') :> x'') commuterIdFL :: CommuteFn p1 p2 -> CommuteFn p1 (FL p2) commuterIdFL _ (x :> NilFL) = return (NilFL :> x) commuterIdFL commuter (x :> (y :>: ys)) = do y' :> x' <- commuter (x :> y) ys' :> x'' <- commuterIdFL commuter (x' :> ys) return ((y' :>: ys') :> x'') commuterFLId :: CommuteFn p1 p2 -> CommuteFn (FL p1) p2 commuterFLId _ (NilFL :> y) = return (y :> NilFL) commuterFLId commuter ((x :>: xs) :> y) = do y' :> xs' <- commuterFLId commuter (xs :> y) y'' :> x' <- commuter (x :> y') return (y'' :> (x' :>: xs')) -- |Partition a list into the patches that commute with the given patch and those that don't (including dependencies) partitionConflictingFL :: (Commute p1, Invert p1) => CommuteFn p1 p2 -> FL p1 C(x y) -> p2 C(x z) -> (FL p1 :> FL p1) C(x y) partitionConflictingFL _ NilFL _ = (NilFL :> NilFL) partitionConflictingFL commuter (x :>: xs) y = case commuter (invert x :> y) of Nothing -> case commuteWhatWeCanFL (x :> xs) of xs_ok :> x' :> xs_deps -> case partitionConflictingFL commuter xs_ok y of xs_clean :> xs_conflicts -> xs_clean :> (xs_conflicts +>+ (x' :>: xs_deps)) Just (y' :> _) -> case partitionConflictingFL commuter xs y' of xs_clean :> xs_conflicts -> (x :>: xs_clean) :> xs_conflicts darcs-2.8.4/src/Darcs/Patch/Prim.hs0000644001765600176560000000140012104371431016261 0ustar ganeshganesh{-# OPTIONS_GHC -fno-warn-orphans #-} module Darcs.Patch.Prim ( showPrim, showPrimFL, primIsAddfile, primIsHunk, primIsBinary, primIsSetpref, primIsAdddir, is_filepatch, canonize, tryToShrink, sortCoalesceFL, join, canonizeFL, tryShrinkingInverse, summarizePrim, applyPrimFL, readPrim, FromPrim(..), FromPrims(..), ToFromPrim(..), PrimPatch, PrimPatchBase(..), PrimConstruct(..) ) where import Darcs.Patch.Prim.Class ( PrimConstruct(..), PrimCanonize(..) , PrimClassify(..), PrimDetails(..) , PrimShow(..), showPrimFL, PrimRead(..) , PrimApply(..) , FromPrim(..), FromPrims(..), ToFromPrim(..) , PrimPatchBase(..), PrimPatch ) darcs-2.8.4/src/Darcs/Patch/Read.hs0000644001765600176560000001201612104371431016232 0ustar ganeshganesh-- Copyright (C) 2002-2003 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP #-} module Darcs.Patch.Read ( ReadPatch(..), readPatch, readPatchPartial, bracketedFL, peekfor, readFileName ) where import Prelude hiding ( pi ) import ByteStringUtils ( dropSpace ) import qualified Data.ByteString as B (ByteString, null) import Darcs.Patch.Bracketed ( Bracketed(..), unBracketedFL ) import Darcs.Patch.FileName ( FileName, fp2fn, ps2fn, decodeWhite ) import Darcs.Patch.Format ( PatchListFormat(..), ListFormat(..), FileNameFormat(..) ) import Darcs.Patch.ReadMonads (ParserM, parseStrictly, choice, lexChar, lexString, checkConsumes ) import Darcs.Witnesses.Ordered ( FL(..), RL, reverseFL ) import Darcs.Witnesses.Sealed ( Sealed(..), mapSeal ) import Control.Applicative ( (<$>), (<|>) ) import Control.Monad ( mzero ) import qualified Data.ByteString.Char8 as BC ( ByteString, unpack ) #include "gadts.h" class ReadPatch p where readPatch' :: ParserM m => m (Sealed (p C(x ))) readPatchPartial :: ReadPatch p => B.ByteString -> Maybe (Sealed (p C(x )), B.ByteString) readPatchPartial ps = case parseStrictly readPatch' ps of Just (p, ps') -> Just (p, ps') _ -> Nothing readPatch :: ReadPatch p => B.ByteString -> Maybe (Sealed (p C(x ))) readPatch ps = case readPatchPartial ps of Just (p, ps') | B.null (dropSpace ps') -> Just p _ -> Nothing instance ReadPatch p => ReadPatch (Bracketed p) where readPatch' = mapSeal Braced <$> bracketedFL readPatch' '{' '}' <|> mapSeal Parens <$> bracketedFL readPatch' '(' ')' <|> mapSeal Singleton <$> readPatch' instance (ReadPatch p, PatchListFormat p) => ReadPatch (FL p) where readPatch' | ListFormatV1 <- patchListFormat :: ListFormat p = mapSeal unBracketedFL <$> readPatch' -- in the V2 format case, we only need to support () on reading, not {} -- for simplicity we just go through the same code path. | ListFormatV2 <- patchListFormat :: ListFormat p = mapSeal unBracketedFL <$> readPatch' | otherwise = read_patches where read_patches :: ParserM m => m (Sealed (FL p C(x ))) read_patches = do --tracePeek "starting FL read" -- checkConsumes is needed to make sure that something is read, -- to avoid stack overflow when parsing FL (FL p) mp <- (Just <$> checkConsumes readPatch') <|> return Nothing case mp of Just (Sealed p) -> do --tracePeek "found one patch" Sealed ps <- read_patches return $ Sealed (p:>:ps) Nothing -> return $ Sealed NilFL -- tracePeek x = do y <- peekInput -- traceDoc (greenText x $$ greenText (show $ sal_to_string y)) return () instance (ReadPatch p, PatchListFormat p) => ReadPatch (RL p) where readPatch' = mapSeal reverseFL <$> readPatch' {-# INLINE bracketedFL #-} bracketedFL :: forall p m C(x) . (ParserM m) => (FORALL(y) m (Sealed (p C(y)))) -> Char -> Char -> m (Sealed (FL p C(x))) bracketedFL parser pre post = peekforc pre bfl mzero where bfl :: FORALL(z) m (Sealed (FL p C(z))) bfl = peekforc post (return $ Sealed NilFL) (do Sealed p <- parser Sealed ps <- bfl return $ Sealed (p:>:ps)) {-# INLINE peekforc #-} peekforc :: ParserM m => Char -> m a -> m a -> m a peekforc c ifstr ifnot = choice [ lexChar c >> ifstr , ifnot ] peekfor :: ParserM m => BC.ByteString -> m a -> m a -> m a peekfor ps ifstr ifnot = choice [ do lexString ps ifstr , ifnot ] {-# INLINE peekfor #-} readFileName :: FileNameFormat -> B.ByteString -> FileName readFileName OldFormat = ps2fn readFileName NewFormat = fp2fn . decodeWhite . BC.unpack darcs-2.8.4/src/Darcs/Patch/ReadMonads.hs0000644001765600176560000002524212104371431017401 0ustar ganeshganesh{-# LANGUAGE BangPatterns #-} -- | This module defines our parsing monad. In the past there have been lazy -- and strict parsers in this module. Currently we have only the strict -- variant and it is used for parsing patch files. module Darcs.Patch.ReadMonads (ParserM, Darcs.Patch.ReadMonads.take, parse, parseStrictly, char, int, option, choice, skipSpace, skipWhile, string, lexChar, lexString, lexEof, takeTillChar, myLex', anyChar, endOfInput, takeTill, checkConsumes, linesStartingWith, linesStartingWithEndingWith) where import ByteStringUtils ( dropSpace, breakSpace, breakFirstPS, readIntPS, breakLastPS ) import qualified Data.ByteString as B (null, drop, length, tail, empty, ByteString) import qualified Data.ByteString.Char8 as BC ( uncons, dropWhile, break , splitAt, length, head ) import Control.Applicative ( Alternative(..), Applicative(..), (<$>) ) import Control.Monad ( MonadPlus(..) ) -- | 'lexChar' checks if the next space delimited token from -- the input stream matches a specific 'Char'. -- Uses 'Maybe' inside 'ParserM' to handle failed matches, so -- that it always returns () on success. lexChar :: ParserM m => Char -> m () lexChar c = do skipSpace char c return () -- | 'lexString' fetches the next whitespace delimited token from -- from the input and checks if it matches the 'ByteString' input. -- Uses 'Maybe' inside 'ParserM' to handle failed matches, so -- that it always returns () on success. lexString :: ParserM m => B.ByteString -> m () lexString str = work $ \s -> case myLex s of Just (xs :*: ys) | xs == str -> Just (() :*: ys) _ -> Nothing -- | Only succeeds if the characters in the input exactly match @str@. string :: ParserM m => B.ByteString -> m () string str = work $ \s -> case BC.splitAt (BC.length str) s of (h, t) | h == str -> Just (() :*: t) _ -> Nothing -- | 'lexEof' looks for optional spaces followed by the end of input. -- Uses 'Maybe' inside 'ParserM' to handle failed matches, so -- that it always returns () on success. lexEof :: ParserM m => m () lexEof = work $ \s -> if B.null (dropSpace s) then Just (() :*: B.empty) else Nothing -- | 'myLex' drops leading spaces and then breaks the string at the -- next space. Returns 'Nothing' when the string is empty after -- dropping leading spaces, otherwise it returns the first sequence -- of non-spaces and the remainder of the input. myLex :: B.ByteString -> Maybe (ParserState B.ByteString) myLex s = let s' = dropSpace s in if B.null s' then Nothing else Just $ stuple $ breakSpace s' -- | Like 'myLex' except that it is in ParserM myLex' :: ParserM m => m B.ByteString myLex' = work myLex -- | Accepts the next character and returns it. Only fails at end of -- input. anyChar :: ParserM m => m Char anyChar = work $ \s -> stuple <$> BC.uncons s -- | Only succeeds at end of input, consumes no characters. endOfInput :: ParserM m => m () endOfInput = work $ \s -> if B.null s then Just (() :*: s) else Nothing -- | Accepts only the specified character. Consumes a character, if -- available. char :: ParserM m => Char -> m () char c = work $ \s -> case BC.uncons s of Just (c', s') | c == c' -> Just (() :*: s') _ -> Nothing -- | Parse an integer and return it. Skips leading whitespaces and -- | uses the efficient ByteString readInt. int :: ParserM m => m Int int = work $ \s -> stuple <$> readIntPS s -- | Discards spaces until a non-space character is encountered. -- Always succeeds. skipSpace :: ParserM m => m () skipSpace = alterInput dropSpace -- | Discards any characters as long as @p@ returns True. Always -- | succeeds. skipWhile :: ParserM m => (Char -> Bool) -> m () skipWhile p = alterInput (BC.dropWhile p) -- | Takes characters while @p@ returns True. Always succeeds. takeTill :: ParserM m => (Char -> Bool) -> m B.ByteString takeTill p = work $ \s -> Just $ stuple (BC.break p s) -- | Equivalent to @takeTill (==c)@, except that it is optimized for -- | the equality case. takeTillChar :: ParserM m => Char -> m B.ByteString takeTillChar c = work $ \s -> Just $ stuple (BC.break (==c) s) -- | Takes exactly @n@ bytes, or fails. take :: ParserM m => Int -> m B.ByteString take n = work $ \s -> if B.length s >= n then Just $ stuple $ BC.splitAt n s else Nothing -- | This is a highly optimized way to read lines that start with a -- particular character. To implement this efficiently we need access -- to the parser's internal state. If this is implemented in terms of -- the other primitives for the parser it requires us to consume one -- character at a time. That leads to @(>>=)@ wasting significant -- time. linesStartingWith :: ParserM m => Char -> m [B.ByteString] linesStartingWith c = work $ linesStartingWith' c -- | Helper function for 'linesStartingWith'. linesStartingWith' :: Char -> B.ByteString -> Maybe (ParserState [B.ByteString]) linesStartingWith' c thes = Just (lsw [] thes) where lsw acc s | B.null s || BC.head s /= c = (reverse acc :*: s) lsw acc s = let s' = B.tail s in case breakFirstPS '\n' s' of Just (l, r) -> lsw (l:acc) r Nothing -> (reverse (s':acc) :*: B.empty) -- | This is a highly optimized way to read lines that start with a -- particular character, and stops when it reaches a particular | -- character. See 'linesStartingWith' for details on why this | -- defined here as a primitive. linesStartingWithEndingWith :: ParserM m => Char -> Char -> m [B.ByteString] linesStartingWithEndingWith st en = work $ linesStartingWithEndingWith' st en -- | Helper function for 'linesStartingWithEndingWith'. linesStartingWithEndingWith' :: Char -> Char -> B.ByteString -> Maybe (ParserState [B.ByteString]) linesStartingWithEndingWith' st en s = lswew s where lswew x | B.null x = Nothing lswew x = if BC.head x == en then Just ([] :*: B.tail x) else if BC.head x /= st then Nothing else case BC.break ((==) '\n') $ B.tail x of (l,r) -> case lswew $ B.tail r of Just (ls :*: r') -> Just ((l:ls) :*: r') Nothing -> case breakLastPS en l of Just (l2,_) -> Just ([l2] :*: B.drop (B.length l2+2) x) Nothing -> Nothing -- | Applies a function to the input stream and discards the -- result of the function. alterInput :: ParserM m => (B.ByteString -> B.ByteString) -> m () alterInput f = work (\s -> Just (() :*: f s)) -- | If @p@ fails it returns @x@, otherwise it returns the result of @p@. option :: Alternative f => a -> f a -> f a option x p = p <|> pure x -- | Attempts each option until one succeeds. choice :: Alternative f => [f a] -> f a choice = foldr (<|>) empty -- |Ensure that a parser consumes input when producing a result -- Causes the initial state of the input stream to be held on to while the -- parser runs, so use with caution. checkConsumes :: ParserM m => m a -> m a checkConsumes parser = do x <- B.length <$> peekInput res <- parser x' <- B.length <$> peekInput if x' < x then return res else mzero class (Functor m, Applicative m, Alternative m, Monad m, MonadPlus m) => ParserM m where -- | Applies a parsing function inside the 'ParserM' monad. work :: (B.ByteString -> Maybe (ParserState a)) -> m a -- | Applies a parsing function, that can return 'Nothing', -- inside the 'ParserM' monad. maybeWork :: (B.ByteString -> Maybe (ParserState a)) -> m (Maybe a) -- | Allows for the inspection of the input that is yet to be parsed. peekInput :: m B.ByteString -- | Run the parser parse :: m a -> B.ByteString -> Maybe (a, B.ByteString) ----- Strict Monad ----- -- | 'parseStrictly' applies the parser functions to a string -- and checks that each parser produced a result as it goes. -- The strictness is in the 'ParserM' instance for 'SM'. parseStrictly :: SM a -> B.ByteString -> Maybe (a, B.ByteString) parseStrictly (SM f) s = case f s of Just (a :*: r) -> Just (a, r) _ -> Nothing -- | ParserState represents the internal state of the parser. We make it -- strict and specialize it on ByteString. This is purely to help GHC -- optimize. If performance were not a concern, it could be replaced -- with @(a, ByteString)@. data ParserState a = !a :*: !B.ByteString -- | Convert from a lazy tuple to a strict tuple. stuple :: (a, B.ByteString) -> ParserState a stuple (a, b) = a :*: b -- | 'SM' is the Strict Monad for parsing. newtype SM a = SM (B.ByteString -> Maybe (ParserState a)) bindSM :: SM a -> (a -> SM b) -> SM b bindSM (SM m) k = SM $ \s -> case m s of Nothing -> Nothing Just (x :*: s') -> case k x of SM y -> y s' {-# INLINE bindSM #-} returnSM :: a -> SM a returnSM x = SM (\s -> Just (x :*: s)) {-# INLINE returnSM #-} failSM :: String -> SM a failSM _ = SM (\_ -> Nothing) {-# INLINE failSM #-} instance Monad SM where (>>=) = bindSM return = returnSM fail = failSM instance ParserM SM where work f = SM f maybeWork f = SM $ \s -> case f s of Just (x :*: s') -> Just (Just x :*: s') Nothing -> Just (Nothing :*: s) peekInput = SM $ \s -> Just (s :*: s) parse = parseStrictly -- The following instances allow us to use more conventional -- interfaces provided by other parser libraries. The instances are -- defined using bindSM, returnSM, and failSM to avoid any infinite, -- or even unneccessary, recursion of instances between between -- ParserM and Monad. Other recursive uses will be fine, such as -- (<|>) = mplus. instance MonadPlus SM where mzero = failSM "" -- | Over using mplus can lead to space leaks. It's best to push -- the use of mplus as far down as possible, because until the the -- first parameter completes, we must hold on to the input. mplus (SM a) (SM b) = SM $ \s -> case a s of Nothing -> b s r -> r instance Functor SM where fmap f m = m `bindSM` (returnSM . f) instance Applicative SM where pure = returnSM a <*> b = a `bindSM` \c -> b `bindSM` \d -> returnSM (c d) instance Alternative SM where empty = failSM "" (<|>) = mplus darcs-2.8.4/src/Darcs/Patch/RegChars.hs0000644001765600176560000000605012104371431017056 0ustar ganeshganesh-- Copyright (C) 2003 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. module Darcs.Patch.RegChars ( regChars, ) where (&&&) :: (a -> Bool) -> (a -> Bool) -> (a -> Bool) (&&&) a b c = a c && b c (|||) :: (a -> Bool) -> (a -> Bool) -> (a -> Bool) (|||) a b c = a c || b c {-# INLINE regChars #-} -- | 'regChars' returns a filter function that tells if a char is a member -- of the regChar expression or not. The regChar expression is basically a -- set of chars, but it can contain ranges with use of the '-' (dash), and -- it can also be specified as a complement set by prefixing with '^' -- (caret). The dash and caret, as well as the backslash, can all be -- escaped with a backslash to suppress their special meaning. -- -- NOTE: The '.' (dot) is allowed to be escaped. It has no special meaning -- if it is not escaped, but the default 'filename_toks' in -- Darcs.Commands.Replace uses an escaped dot (WHY?). regChars :: String -> (Char -> Bool) regChars ('^':cs) = not . normalRegChars (unescapeChars cs) regChars ('\\':'^':cs) = normalRegChars $ unescapeChars $ '^':cs regChars cs = normalRegChars $ unescapeChars cs {-# INLINE unescapeChars #-} -- | 'unescapeChars' unescapes whitespace, which is escaped in the replace -- patch file format. It will also unescape escaped carets, which is useful -- for escaping a leading caret that should not invert the regChars. All -- other escapes are left for the unescaping in 'normalRegChars'. unescapeChars :: String -> String unescapeChars ('\\':'n':cs) = '\n' : unescapeChars cs unescapeChars ('\\':'t':cs) = '\t' : unescapeChars cs unescapeChars ('\\':'^':cs) = '^' : unescapeChars cs unescapeChars (c:cs) = c : unescapeChars cs unescapeChars [] = [] {-# INLINE normalRegChars #-} -- | 'normalRegChars' assembles the filter function. It handles special -- chars, and also unescaping of escaped special chars. If a non-special -- char is still escaped by now we get a failure. normalRegChars :: String -> (Char -> Bool) normalRegChars ('\\':'.':cs) = (=='.') ||| normalRegChars cs normalRegChars ('\\':'-':cs) = (=='-') ||| normalRegChars cs normalRegChars ('\\':'\\':cs) = (=='\\') ||| normalRegChars cs normalRegChars ('\\':c:_) = error $ "'\\"++[c]++"' not supported." normalRegChars (c1:'-':c2:cs) = ((>= c1) &&& (<= c2)) ||| normalRegChars cs normalRegChars (c:cs) = (== c) ||| normalRegChars cs normalRegChars [] = \_ -> False darcs-2.8.4/src/Darcs/Patch/Repair.hs0000644001765600176560000000427312104371431016607 0ustar ganeshganeshmodule Darcs.Patch.Repair ( Repair(..), RepairToFL(..), mapMaybeSnd, Check(..) ) where import Darcs.Patch.Apply ( Apply(..) ) import Darcs.Patch.ApplyMonad ( ApplyMonad ) import Darcs.Witnesses.Ordered ( FL(..), RL(..), mapFL, mapRL, (+>+) ) import Printer ( Doc ) import Data.Maybe ( catMaybes, listToMaybe ) #include "gadts.h" class Check p where isInconsistent :: p C(x y) -> Maybe Doc isInconsistent _ = Nothing -- |'Repair' and 'RepairToFL' deal with repairing old patches that were -- were written out due to bugs or that we no longer wish to support. -- 'Repair' is implemented by collections of patches (FL, Named, PatchInfoAnd) that -- might need repairing. class Repair p where applyAndTryToFix :: ApplyMonad m (ApplyState p) => p C(x y) -> m (Maybe (String, p C(x y))) -- |'RepairToFL' is implemented by single patches that can be repaired (Prim, Patch, RealPatch) -- There is a default so that patch types with no current legacy problems don't need to -- have an implementation. class Apply p => RepairToFL p where applyAndTryToFixFL :: ApplyMonad m (ApplyState p) => p C(x y) -> m (Maybe (String, FL p C(x y))) applyAndTryToFixFL p = do apply p; return Nothing mapMaybeSnd :: (a -> b) -> Maybe (c, a) -> Maybe (c, b) mapMaybeSnd f (Just (a,b)) = Just (a,f b) mapMaybeSnd _ Nothing = Nothing instance Check p => Check (FL p) where isInconsistent = listToMaybe . catMaybes . mapFL isInconsistent instance Check p => Check (RL p) where isInconsistent = listToMaybe . catMaybes . mapRL isInconsistent instance RepairToFL p => Repair (FL p) where applyAndTryToFix NilFL = return Nothing applyAndTryToFix (p:>:ps) = do mp <- applyAndTryToFixFL p mps <- applyAndTryToFix ps return $ case (mp,mps) of (Nothing, Nothing) -> Nothing (Just (e,p'),Nothing) -> Just (e,p'+>+ps) (Nothing, Just (e,ps')) -> Just (e,p:>:ps') (Just (e,p'), Just (es,ps')) -> Just (unlines [e,es], p'+>+ps') darcs-2.8.4/src/Darcs/Patch/RepoPatch.hs0000644001765600176560000000125312104371431017245 0ustar ganeshganeshmodule Darcs.Patch.RepoPatch ( RepoPatch ) where import Darcs.Patch.Conflict ( Conflict, CommuteNoConflicts ) import Darcs.Patch.Effect ( Effect ) import Darcs.Patch.FileHunk ( IsHunk ) import Darcs.Patch.Format ( PatchListFormat ) import Darcs.Patch.Merge ( Merge ) import Darcs.Patch.Patchy ( Patchy ) import Darcs.Patch.Patchy.Instances () import Darcs.Patch.Prim ( PrimPatchBase, PrimOf, FromPrim ) import Darcs.Patch.Repair ( RepairToFL, Check ) class (Patchy p, Merge p, Effect p, IsHunk p, FromPrim p, Conflict p, CommuteNoConflicts p, Check p, RepairToFL p, PatchListFormat p, PrimPatchBase p, Patchy (PrimOf p), IsHunk (PrimOf p) ) => RepoPatch p darcs-2.8.4/src/Darcs/Patch/Set.hs0000644001765600176560000000653612104371431016124 0ustar ganeshganesh-- Copyright (C) 2003 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP, EmptyDataDecls #-} #include "gadts.h" module Darcs.Patch.Set ( PatchSet(..), Tagged(..), SealedPatchSet, Origin, progressPatchSet, tags, appendPSFL, newset2RL, newset2FL ) where import Progress ( progress ) import Darcs.Patch.Info ( PatchInfo ) import Darcs.Patch.PatchInfoAnd ( PatchInfoAnd, info ) import Darcs.Witnesses.Ordered ( FL, RL(..), (+<+), reverseFL, reverseRL, mapRL_RL, concatRL, mapRL ) import Darcs.Witnesses.Sealed ( Sealed ) data Origin type SealedPatchSet p C(start) = Sealed ((PatchSet p) C(start)) -- A PatchSet is a list of patches since the last tag, and a list of tagged -- patch lists that form a repo's history. data PatchSet p C(start y) where PatchSet :: RL (PatchInfoAnd p) C(x y) -> RL (Tagged p) C(start x) -> PatchSet p C(start y) -- A Tagged is a Tag, the hash of the 'previous' inventory (if it exists) and -- the list of patches since that previous inventory. data Tagged p C(x z) where Tagged :: PatchInfoAnd p C(y z) -> Maybe String -> RL (PatchInfoAnd p) C(x y) -> Tagged p C(x z) -- |newset2RL takes a PatchSet and returns an equivalent, linear RL of patches. newset2RL :: PatchSet p C(start x) -> RL (PatchInfoAnd p) C(start x) newset2RL (PatchSet ps ts) = ps +<+ concatRL (mapRL_RL ts2rl ts) where ts2rl :: Tagged p C(y z) -> RL (PatchInfoAnd p) C(y z) ts2rl (Tagged t _ ps2) = t :<: ps2 -- |newset2FL takes a PatchSet and returns an equivalent, linear FL of patches. newset2FL :: PatchSet p C(start x) -> FL (PatchInfoAnd p) C(start x) newset2FL = reverseRL . newset2RL -- |appendPSFL takes a PatchSet and a FL of patches that 'follow' the PatchSet, -- and concatenates the patches into the PatchSet. appendPSFL :: PatchSet p C(start x) -> FL (PatchInfoAnd p) C(x y) -> PatchSet p C(start y) appendPSFL (PatchSet ps ts) newps = PatchSet (reverseFL newps +<+ ps) ts -- |Runs a progress action for each tag and patch in a given PatchSet, using -- the passed progress message. Does not alter the PatchSet. progressPatchSet :: String -> PatchSet p C(start x) -> PatchSet p C(start x) progressPatchSet k (PatchSet ps0 ts0) = PatchSet (mapRL_RL prog ps0) $ mapRL_RL pts ts0 where prog = progress k pts :: Tagged p C(y z) -> Tagged p C(y z) pts (Tagged t h ps) = Tagged (prog t) h (mapRL_RL prog ps) -- |tags returns the PatchInfos corresponding to the tags of a given PatchSet. tags :: PatchSet p C(start x) -> [PatchInfo] tags (PatchSet _ ts) = mapRL f ts where f :: Tagged p C(y z) -> PatchInfo f (Tagged t _ _) = info t darcs-2.8.4/src/Darcs/Patch/Show.hs0000644001765600176560000000576512104371431016314 0ustar ganeshganesh-- Copyright (C) 2002-2005 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP #-} module Darcs.Patch.Show ( ShowPatchBasic(..), ShowPatch(..) , showNamedPrefix , writePatch, gzWritePatch , formatFileName ) where import Prelude hiding ( pi ) import Darcs.Lock ( writeDocBinFile, gzWriteDocFile ) import Darcs.Patch.FileName ( FileName, fn2ps, encodeWhite, fn2fp ) import Darcs.Patch.Format ( FileNameFormat(..) ) import Darcs.Patch.Info ( PatchInfo, showPatchInfo ) import Darcs.Witnesses.Ordered ( FL ) import English ( plural, Noun(Noun) ) import Printer ( Doc, vcat, blueText, ($$), (<>), text, packedString ) import Darcs.Patch.ApplyMonad ( ApplyMonadTrans, ApplyMonad ) import Darcs.Patch.Apply ( ApplyState ) #include "gadts.h" showNamedPrefix :: PatchInfo -> [PatchInfo] -> Doc showNamedPrefix n d = showPatchInfo n $$ blueText "<" $$ vcat (map showPatchInfo d) $$ blueText ">" class ShowPatchBasic p where showPatch :: p C(x y) -> Doc class ShowPatchBasic p => ShowPatch p where showNicely :: p C(x y) -> Doc showNicely = showPatch -- | showContextPatch is used to add context to a patch, as diff -- -u does. Thus, it differs from showPatch only for hunks. It is -- used for instance before putting it into a bundle. As this -- unified context is not included in patch representation, this -- requires access to the tree. showContextPatch :: (Monad m, ApplyMonadTrans m (ApplyState p), ApplyMonad m (ApplyState p)) => p C(x y) -> m Doc showContextPatch p = return $ showPatch p description :: p C(x y) -> Doc description = showPatch summary :: p C(x y) -> Doc summaryFL :: FL p C(x y) -> Doc thing :: p C(x y) -> String thing _ = "patch" things :: p C(x y) -> String things x = plural (Noun $ thing x) "" writePatch :: ShowPatchBasic p => FilePath -> p C(x y) -> IO () writePatch f p = writeDocBinFile f $ showPatch p <> text "\n" gzWritePatch :: ShowPatchBasic p => FilePath -> p C(x y) -> IO () gzWritePatch f p = gzWriteDocFile f $ showPatch p <> text "\n" formatFileName :: FileNameFormat -> FileName -> Doc formatFileName OldFormat = packedString . fn2ps formatFileName NewFormat = text . encodeWhite . fn2fp darcs-2.8.4/src/Darcs/Patch/Split.hs0000644001765600176560000002106212104371431016453 0ustar ganeshganesh{-# LANGUAGE CPP, RankNTypes, GADTs, ViewPatterns #-} {-# OPTIONS_GHC -fno-warn-unused-imports #-} -- Copyright (C) 2009 Ganesh Sittampalam -- -- 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. module Darcs.Patch.Split ( Splitter(..), rawSplitter, noSplitter, primSplitter, reversePrimSplitter ) where import Data.List ( intersperse ) import Darcs.Witnesses.Ordered import Darcs.Witnesses.Sealed import Darcs.Patch.FileHunk ( FileHunk(..), IsHunk(..) ) import Darcs.Patch.Patchy ( ReadPatch(..), showPatch, ShowPatch(..), Invert(..) ) import Darcs.Patch.Invert (invertFL) import Darcs.Patch.Prim ( PrimPatch, canonize, canonizeFL, primFromHunk ) import Darcs.Patch.ReadMonads ( parseStrictly ) import Darcs.Patch.Read () import Darcs.Patch.Viewing () import Printer ( renderPS ) import qualified Data.ByteString as B import qualified Data.ByteString.Char8 as BC #include "gadts.h" -- |A splitter is something that can take a patch and (possibly) render it -- as text in some format of its own choosing. -- This text can then be presented to the user for editing, and the result -- given to the splitter for parsing. -- If the parse succeeds, the result is a list of patches that could replace -- the original patch in any context. -- Typically this list will contain the changed version of the patch, along -- with fixup pieces to ensure that the overall effect of the list is the same -- as the original patch. -- The individual elements of the list can then be offered separately to the -- user, allowing them to accept some and reject others. -- -- There's no immediate application for a splitter for anything other than -- Prim (you shouldn't go editing named patches, you'll break them!) -- However you might want to compose splitters for FilePatchType to make -- splitters for Prim etc, and the generality doesn't cost anything. data Splitter p = Splitter { applySplitter :: FORALL(x y) p C(x y) -> Maybe (B.ByteString, B.ByteString -> Maybe (FL p C(x y))) -- canonization is needed to undo the effects of splitting -- Typically, the list returned by applySplitter will not -- be in the simplest possible form (since the user will have -- deliberately added extra stuff). Once the user has selected -- the pieces they want, we need to make sure that we eliminate -- any remaining redundancy in the selected pieces, otherwise -- we might record (or whatever) a rather strange looking patch. -- This hook allows the splitter to provide an appropriate -- function for doing this. ,canonizeSplit :: FORALL(x y) FL p C(x y) -> FL p C(x y) } {- Some facts that probably ought to be true about splitters: should make some QC properties applySplitter p = Just (bs, f) ==> f bs == Just (p :>: NilFL) applySplitter p = Just (bs, f) ; f bs' = Just ps ==> canonizeSplit ps = p :>: NilFL -} -- Does not canonize as there is no generic operation to do this. withEditedHead :: Invert p => p C(x y) -> p C(x z) -> FL p C(x y) withEditedHead p res = res :>: invert res :>: p :>: NilFL -- |This generic splitter just lets the user edit the printed representation of the patch -- Should not be used expect for testing and experimentation. rawSplitter :: (ShowPatch p, ReadPatch p, Invert p) => Splitter p rawSplitter = Splitter { applySplitter = \p -> Just (renderPS . showPatch $ p, \str -> case parseStrictly readPatch' str of Just (Sealed res, _) -> Just (withEditedHead p res) _ -> Nothing ) ,canonizeSplit = id } -- |Never splits. In other code we normally pass around Maybe Splitter instead of using this -- as the default, because it saves clients that don't care about splitting from having to -- import this module just to get noSplitter. noSplitter :: Splitter p noSplitter = Splitter { applySplitter = const Nothing, canonizeSplit = id } doPrimSplit :: PrimPatch prim => prim C(x y) -> Maybe (B.ByteString, B.ByteString -> Maybe (FL prim C(x y))) doPrimSplit = doPrimSplit_ True explanation where explanation = map BC.pack [ "Interactive hunk edit:" , " - Edit the section marked 'AFTER'" , " - Arbitrary editing is supported" , " - This will only affect the patch, not your working copy" , " - Hints:" , " - To split added text, delete the part you want to postpone" , " - To split removed text, copy back the part you want to retain" , "" ] doPrimSplit_ edit_before_part helptext (isHunk -> Just (FileHunk fn n before after)) = Just (B.concat $ intersperse (BC.pack "\n") $ concat [ helptext , [mkSep " BEFORE (reference) =========================="] , before , [mkSep "=== AFTER (edit) ============================="] , after , [mkSep "=== (edit above) ============================="] ], \bs -> do let ls = BC.split '\n' bs (_, ls2) <- breakSep ls -- before (before', ls3) <- breakSep ls2 -- after 1 (after', _) <- breakSep ls3 -- after return $ if edit_before_part then hunk before before' +>+ hunk before' after' +>+ hunk after' after else hunk before after' +>+ hunk after' after) where sep = BC.pack "==========================" hunk :: PrimPatch prim => [B.ByteString] -> [B.ByteString] -> FL prim C(a b) hunk b a = canonize (primFromHunk (FileHunk fn n b a)) mkSep s = BC.append sep (BC.pack s) breakSep xs = case break (sep `BC.isPrefixOf`) xs of (_, []) -> Nothing (ys, _:zs) -> Just (ys, zs) doPrimSplit_ _ _ _ = Nothing -- |Split a primitive hunk patch up -- by allowing the user to edit both the before and after lines, then insert fixup patches -- to clean up the mess. primSplitter :: PrimPatch p => Splitter p primSplitter = Splitter { applySplitter = doPrimSplit , canonizeSplit = canonizeFL } doReversePrimSplit :: PrimPatch prim => prim C(x y) -> Maybe (B.ByteString, B.ByteString -> Maybe (FL prim C(x y))) doReversePrimSplit prim = do (text, parser) <- doPrimSplit_ False reverseExplanation (invert prim) let parser' p = do patch <- parser p return . reverseRL $ invertFL patch return (text, parser') where reverseExplanation = map BC.pack [ "Interactive hunk edit:" , " - Edit the section marked 'AFTER' (representing the state to which you'll revert)" , " - Arbitrary editing is supported" , " - Your working copy will be returned to the 'AFTER' state" , " - Do not touch the 'BEFORE' section" , " - Hints:" , " - To revert only a part of a text addition, delete the part you want to get rid of" , " - To revert only a part of a removal, copy back the part you want to retain" , "" ] reversePrimSplitter :: PrimPatch prim => Splitter prim reversePrimSplitter = Splitter { applySplitter = doReversePrimSplit , canonizeSplit = canonizeFL} darcs-2.8.4/src/Darcs/Patch/Summary.hs0000644001765600176560000001261412104371431017020 0ustar ganeshganeshmodule Darcs.Patch.Summary ( plainSummary, plainSummaryPrim, plainSummaryPrims, xmlSummary ) where import Darcs.Patch.FileName ( fn2fp ) import Darcs.Patch.Conflict ( Conflict(..), IsConflictedPrim(IsC), ConflictState(..) ) import Darcs.Patch.Effect ( Effect ) import Darcs.Patch.Prim.Class ( PrimDetails(..), PrimPatchBase ) import Darcs.Patch.SummaryData ( SummDetail(..), SummOp(..) ) import Darcs.Witnesses.Ordered ( FL, mapFL ) import Printer ( Doc, empty, vcat, text, minus, plus, ($$), (<+>), (<>), ) #include "gadts.h" plainSummaryPrim :: PrimDetails prim => prim C(x y) -> Doc plainSummaryPrim = vcat . map summChunkToLine . genSummary . (:[]) . IsC Okay plainSummaryPrims :: PrimDetails prim => FL prim C(x y) -> Doc plainSummaryPrims = vcat . map summChunkToLine . genSummary . mapFL (IsC Okay) plainSummary :: (Conflict e, Effect e, PrimPatchBase e) => e C(x y) -> Doc plainSummary = vcat . map summChunkToLine . genSummary . conflictedEffect xmlSummary :: (Effect p, Conflict p, PrimPatchBase p) => p C(x y) -> Doc xmlSummary p = text "" $$ (vcat . map summChunkToXML . genSummary . conflictedEffect $ p) $$ text "" -- Yuck duplicated code below... escapeXML :: String -> Doc escapeXML = text . strReplace '\'' "'" . strReplace '"' """ . strReplace '>' ">" . strReplace '<' "<" . strReplace '&' "&" strReplace :: Char -> String -> String -> String strReplace _ _ [] = [] strReplace x y (z:zs) | x == z = y ++ (strReplace x y zs) | otherwise = z : (strReplace x y zs) -- end yuck duplicated code. -- | High-level representation of a piece of patch summary data SummChunk = SummChunk SummDetail ConflictState deriving (Ord, Eq) genSummary :: forall p . PrimDetails p => [IsConflictedPrim p] -> [SummChunk] genSummary p = combine $ concatMap s2 p where s2 :: IsConflictedPrim p -> [SummChunk] s2 (IsC c x) = map (\d -> SummChunk d c) $ summarizePrim x combine (x1@(SummChunk d1 c1) : x2@(SummChunk d2 c2) : ss) = case combineDetail d1 d2 of Nothing -> x1 : combine (x2:ss) Just d3 -> combine $ SummChunk d3 (combineConflitStates c1 c2) : ss combine (x:ss) = x : combine ss combine [] = [] -- combineDetail (SummFile o1 f1 r1 a1 x1) (SummFile o2 f2 r2 a2 x2) | f1 == f2 = do o3 <- combineOp o1 o2 return $ SummFile o3 f1 (r1 + r2) (a1 + a2) (x1 + x2) combineDetail _ _ = Nothing -- combineConflitStates Conflicted _ = Conflicted combineConflitStates _ Conflicted = Conflicted combineConflitStates Duplicated _ = Duplicated combineConflitStates _ Duplicated = Duplicated combineConflitStates Okay Okay = Okay -- Don't combine AddFile and RmFile: (maybe an old revision of) darcs -- allows a single patch to add and remove the same file, see issue 185 combineOp SummAdd SummRm = Nothing combineOp SummRm SummAdd = Nothing combineOp SummAdd _ = Just SummAdd combineOp _ SummAdd = Just SummAdd combineOp SummRm _ = Just SummRm combineOp _ SummRm = Just SummRm combineOp SummMod SummMod = Just SummMod summChunkToXML :: SummChunk -> Doc summChunkToXML (SummChunk detail c) = case detail of SummRmDir f -> xconf c "remove_directory" (xfn f) SummAddDir f -> xconf c "add_directory" (xfn f) SummFile SummRm f _ _ _ -> xconf c "remove_file" (xfn f) SummFile SummAdd f _ _ _ -> xconf c "add_file" (xfn f) SummFile SummMod f r a x -> xconf c "modify_file" $ xfn f <> xrm r <> xad a <> xrp x SummMv f1 f2 -> text " xfn f1 <> text "\" to=\"" <> xfn f2 <> text"\"/>" SummNone -> empty where xconf Okay t x = text ('<':t++">") $$ x $$ text ("") xconf Conflicted t x = text ('<':t++" conflict='true'>") $$ x $$ text ("") xconf Duplicated t x = text ('<':t++" duplicate='true'>") $$ x $$ text ("") xfn = escapeXML . dropDotSlash .fn2fp -- xad 0 = empty xad a = text "" xrm 0 = empty xrm a = text "" xrp 0 = empty xrp a = text "" summChunkToLine :: SummChunk -> Doc summChunkToLine (SummChunk detail c) = case detail of SummRmDir f -> lconf c "R" $ text (fn2fp f) <> text "/" SummAddDir f -> lconf c "A" $ text (fn2fp f) <> text "/" SummFile SummRm f _ _ _ -> lconf c "R" $ text (fn2fp f) SummFile SummAdd f _ _ _ -> lconf c "A" $ text (fn2fp f) SummFile SummMod f r a x -> lconf c "M" $ text (fn2fp f) <+> rm r <+> ad a <+> rp x SummMv f1 f2 -> text " " <> text (fn2fp f1) <> text " -> " <> text (fn2fp f2) SummNone -> case c of Okay -> empty _ -> lconf c "" empty where lconf Okay t x = text t <+> x lconf Conflicted t x = text (t ++ "!") <+> x lconf Duplicated t x = text t <+> x <+> text "duplicate" -- ad 0 = empty ad a = plus <> text (show a) rm 0 = empty rm a = minus <> text (show a) rp 0 = empty rp a = text "r" <> text (show a) dropDotSlash :: FilePath -> FilePath dropDotSlash ('.':'/':str) = dropDotSlash str dropDotSlash str = str darcs-2.8.4/src/Darcs/Patch/SummaryData.hs0000644001765600176560000000061512104371431017610 0ustar ganeshganeshmodule Darcs.Patch.SummaryData ( SummDetail(..), SummOp(..) ) where import Darcs.Patch.FileName ( FileName ) data SummDetail = SummAddDir FileName | SummRmDir FileName | SummFile SummOp FileName Int Int Int | SummMv FileName FileName | SummNone deriving (Ord, Eq) data SummOp = SummAdd | SummRm | SummMod deriving (Ord, Eq) darcs-2.8.4/src/Darcs/Patch/TokenReplace.hs0000644001765600176560000000315412104371431017736 0ustar ganeshganeshmodule Darcs.Patch.TokenReplace ( tryTokInternal , forceTokReplace ) where import Darcs.Patch.RegChars ( regChars ) import ByteStringUtils ( substrPS, linesPS, unlinesPS ) import qualified Data.ByteString as B import qualified Data.ByteString.Char8 as BC import Data.Maybe ( isNothing ) tryTokInternal :: String -> B.ByteString -> B.ByteString -> B.ByteString -> Maybe [B.ByteString] tryTokInternal _ o n s | isNothing (substrPS o s) && isNothing (substrPS n s) = Just [s] tryTokInternal t o n s = case BC.break (regChars t) s of (before,s') -> case BC.break (not . regChars t) s' of (tok,after) -> case tryTokInternal t o n after of Nothing -> Nothing Just rest -> if tok == o then Just $ before : n : rest else if tok == n then Nothing else Just $ before : tok : rest forceTokReplace :: String -> String -> String -> B.ByteString -> Maybe B.ByteString forceTokReplace t os ns c = Just $ unlinesPS $ map forceReplace $ linesPS c where o = BC.pack os n = BC.pack ns tokchar = regChars t toks_and_intratoks ps | B.null ps = [] toks_and_intratoks ps = let (before,s') = BC.break tokchar ps (tok, after) = BC.break (not . tokchar) s' in before : tok : toks_and_intratoks after forceReplace ps = B.concat $ map o_t_n $ toks_and_intratoks ps o_t_n s | s == o = n | otherwise = s darcs-2.8.4/src/Darcs/Patch/TouchesFiles.hs0000644001765600176560000001233712104371431017762 0ustar ganeshganesh-- Copyright (C) 2002-2004 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP #-} #include "gadts.h" module Darcs.Patch.TouchesFiles ( lookTouch, chooseTouching, choosePreTouching, selectTouching, deselectNotTouching, selectNotTouching, ) where import Control.Applicative ( (<$>) ) import Data.List ( isSuffixOf, nub ) import Darcs.Patch.Choices ( PatchChoices, Tag, TaggedPatch, patchChoices, tag, getChoices, forceFirsts, forceLasts, tpPatch, ) import Darcs.Patch ( Patchy, invert ) import Darcs.Patch.Apply ( ApplyState, applyToFilePaths, effectOnFilePaths ) import Darcs.Witnesses.Ordered ( FL(..), (:>)(..), mapFL_FL, (+>+) ) import Darcs.Witnesses.Sealed ( Sealed, seal ) import Storage.Hashed.Tree( Tree ) selectTouching :: (Patchy p, ApplyState p ~ Tree) => Maybe [FilePath] -> PatchChoices p C(x y) -> PatchChoices p C(x y) selectTouching Nothing pc = pc selectTouching (Just files) pc = forceFirsts xs pc where ct :: (Patchy p, ApplyState p ~ Tree) => [FilePath] -> FL (TaggedPatch p) C(x y) -> [Tag] ct _ NilFL = [] ct fs (tp:>:tps) = case lookTouchOnlyEffect fs (tpPatch tp) of (True, fs') -> tag tp:ct fs' tps (False, fs') -> ct fs' tps xs = case getChoices pc of _ :> mc :> lc -> ct (map fix files) (mc +>+ lc) deselectNotTouching :: (Patchy p, ApplyState p ~ Tree) => Maybe [FilePath] -> PatchChoices p C(x y) -> PatchChoices p C(x y) deselectNotTouching Nothing pc = pc deselectNotTouching (Just files) pc = forceLasts xs pc where ct :: (Patchy p, ApplyState p ~ Tree) => [FilePath] -> FL (TaggedPatch p) C(x y) -> [Tag] ct _ NilFL = [] ct fs (tp:>:tps) = case lookTouchOnlyEffect fs (tpPatch tp) of (True, fs') -> ct fs' tps (False, fs') -> tag tp:ct fs' tps xs = case getChoices pc of fc :> mc :> _ -> ct (map fix files) (fc +>+ mc) selectNotTouching :: (Patchy p, ApplyState p ~ Tree) => Maybe [FilePath] -> PatchChoices p C(x y) -> PatchChoices p C(x y) selectNotTouching Nothing pc = pc selectNotTouching (Just files) pc = forceFirsts xs pc where ct :: (Patchy p, ApplyState p ~ Tree) => [FilePath] -> FL (TaggedPatch p) C(x y) -> [Tag] ct _ NilFL = [] ct fs (tp:>:tps) = case lookTouchOnlyEffect fs (tpPatch tp) of (True, fs') -> ct fs' tps (False, fs') -> tag tp:ct fs' tps xs = case getChoices pc of fc :> mc :> _ -> ct (map fix files) (fc +>+ mc) fix :: FilePath -> FilePath fix f | "/" `isSuffixOf` f = fix $ init f fix "" = "." fix "." = "." fix f = "./" ++ f chooseTouching :: (Patchy p, ApplyState p ~ Tree) => Maybe [FilePath] -> FL p C(x y) -> Sealed (FL p C(x)) chooseTouching Nothing p = seal p chooseTouching files p = case getChoices $ selectTouching files $ patchChoices p of fc :> _ :> _ -> seal $ mapFL_FL tpPatch fc choosePreTouching :: (Patchy p, ApplyState p ~ Tree) => Maybe [FilePath] -> FL p C(x y) -> Sealed (FL p C(x)) choosePreTouching files patch = chooseTouching filesBeforePatch patch where filesBeforePatch = effectOnFilePaths (invert patch) <$> files lookTouchOnlyEffect :: (Patchy p, ApplyState p ~ Tree) => [FilePath] -> p C(x y) -> (Bool, [FilePath]) lookTouchOnlyEffect fs p = (wasTouched, fs') where (wasTouched, _, fs', _) = lookTouch Nothing fs p lookTouch :: (Patchy p, ApplyState p ~ Tree) => Maybe [(FilePath, FilePath)] -> [FilePath] -> p C(x y) -> (Bool, [FilePath], [FilePath], [(FilePath, FilePath)]) lookTouch renames fs p = (anyTouched, touchedFs, fs', renames') where touchedFs = nub . concatMap fsAffectedBy $ affected fsAffectedBy af = filter (affectedBy af) fs anyTouched = length touchedFs > 0 affectedBy :: FilePath -> FilePath -> Bool touched `affectedBy` f = touched == f || touched `isSubPathOf` f || f `isSubPathOf` touched isSubPathOf :: FilePath -> FilePath -> Bool path `isSubPathOf` parent = case splitAt (length parent) path of (path', '/':_) -> path' == parent _ -> False (affected, fs', renames') = applyToFilePaths p renames fs darcs-2.8.4/src/Darcs/Patch/Viewing.hs0000644001765600176560000001676012104371431017001 0ustar ganeshganesh-- Copyright (C) 2002-2004 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# OPTIONS_GHC -fno-warn-orphans #-} {-# LANGUAGE CPP #-} module Darcs.Patch.Viewing ( showContextHunk, showContextSeries ) where import Prelude hiding ( pi, readFile ) import Control.Applicative( (<$>) ) import Storage.Hashed.Monad( TreeIO, fileExists, readFile, tree, virtualTreeMonad ) import Storage.Hashed.Tree( Tree ) import Storage.Hashed.AnchoredPath( floatPath ) import ByteStringUtils (linesPS ) import qualified Data.ByteString as BS (null, concat) import qualified Data.ByteString.Lazy as BL (toChunks) import Darcs.Patch.FileName ( fn2fp ) import Printer ( Doc, empty, vcat, text, blueText, Color(Cyan,Magenta), lineColor, ($$), (<+>), prefix, userchunkPS, ) import Darcs.Patch.Format ( PatchListFormat(..), ListFormat(..), FileNameFormat(..) ) import Darcs.Patch.FileHunk ( IsHunk(..), FileHunk(..), showFileHunk ) import Darcs.Patch.Show ( ShowPatchBasic(..), ShowPatch(..), formatFileName ) import Darcs.Patch.Apply ( Apply(..), applyToState ) import Darcs.Patch.ApplyMonad ( ApplyMonadTrans, runApplyMonad, getApplyState , ApplyMonadOver, ApplyMonad(..), toTree ) #include "gadts.h" import Darcs.Witnesses.Ordered ( RL(..), FL(..), mapFL, mapFL_FL, reverseRL, concatFL ) showContextSeries :: forall p m x y. (Apply p, ShowPatch p, IsHunk p, ApplyMonadTrans m (ApplyState p), ApplyMonad m (ApplyState p)) => FL p C(x y) -> m Doc showContextSeries patches = scs Nothing patches where scs :: forall m' ww xx yy. (ApplyMonadTrans m' (ApplyState p), ApplyMonad m' (ApplyState p), ApplyMonadBase m ~ ApplyMonadBase m') => Maybe (FileHunk C(ww xx)) -> FL p C(xx yy) -> m' Doc scs pold (p:>:ps) = do (_, s') <- nestedApply (apply p) =<< getApplyState case isHunk p of Nothing -> do a <- showContextPatch p b <- nestedApply (scs Nothing ps) s' return $ a $$ fst b Just fh -> case ps of NilFL -> fst <$> liftApply (cool pold fh Nothing) s' (p2:>:_) -> do a <- fst <$> liftApply (cool pold fh (isHunk p2)) s' b <- nestedApply (scs (Just fh) ps) s' return $ a $$ fst b scs _ NilFL = return empty cool :: Maybe (FileHunk C(a b)) -> FileHunk C(b c) -> Maybe (FileHunk C(c d)) -> (ApplyState p) (ApplyMonadBase m) -> (ApplyMonadBase m) Doc cool pold fh ps s = fst <$> virtualTreeMonad (coolContextHunk pold fh ps) (toTree s) showContextHunk :: (ApplyMonad m Tree) => FileHunk C(x y) -> m Doc showContextHunk h = coolContextHunk Nothing h Nothing coolContextHunk :: (ApplyMonad m Tree, ApplyMonadTrans m Tree) => Maybe (FileHunk C(a b)) -> FileHunk C(b c) -> Maybe (FileHunk C(c d)) -> m Doc coolContextHunk prev fh@(FileHunk f l o n) next = do have <- mDoesFileExist f content <- if have then Just `fmap` mReadFilePS f else return Nothing case linesPS `fmap` content of Nothing -> return $ showFileHunk OldFormat fh -- This is a weird error... Just ls -> let numpre = case prev of Just (FileHunk f' lprev _ nprev) | f' == f && l - (lprev + length nprev + 3) < 3 && lprev < l -> max 0 $ l - (lprev + length nprev + 3) _ -> if l >= 4 then 3 else l - 1 pre = take numpre $ drop (l - numpre - 1) ls numpost = case next of Just (FileHunk f' lnext _ _) | f' == f && lnext < l+length n+4 && lnext > l -> lnext - (l+length n) _ -> 3 cleanedls = case reverse ls of (x:xs) | BS.null x -> reverse xs _ -> ls post = take numpost $ drop (max 0 $ l+length o-1) cleanedls in return $ blueText "hunk" <+> formatFileName OldFormat f <+> text (show l) $$ prefix " " (vcat $ map userchunkPS pre) $$ lineColor Magenta (prefix "-" (vcat $ map userchunkPS o)) $$ lineColor Cyan (prefix "+" (vcat $ map userchunkPS n)) $$ prefix " " (vcat $ map userchunkPS post) instance (PatchListFormat p, ShowPatchBasic p) => ShowPatchBasic (FL p) where showPatch = showPatchInternal patchListFormat where showPatchInternal :: ListFormat p -> FL p C(x y) -> Doc showPatchInternal ListFormatV1 (p :>: NilFL) = showPatch p showPatchInternal ListFormatV1 NilFL = blueText "{" $$ blueText "}" showPatchInternal ListFormatV1 ps = blueText "{" $$ vcat (mapFL showPatch ps) $$ blueText "}" showPatchInternal ListFormatV2 ps = vcat (mapFL showPatch ps) showPatchInternal ListFormatDefault ps = vcat (mapFL showPatch ps) instance (Apply p, IsHunk p, PatchListFormat p, ShowPatch p) => ShowPatch (FL p) where showContextPatch = showContextPatchInternal patchListFormat where showContextPatchInternal :: (ApplyMonadTrans m (ApplyState p), ApplyMonad m (ApplyState (FL p))) => ListFormat p -> FL p C(x y) -> m Doc showContextPatchInternal ListFormatV1 (p :>: NilFL) = showContextPatch p showContextPatchInternal ListFormatV1 NilFL = return $ blueText "{" $$ blueText "}" showContextPatchInternal ListFormatV1 ps = do x <- showContextSeries ps return $ blueText "{" $$ x $$ blueText "}" showContextPatchInternal ListFormatV2 ps = showContextSeries ps showContextPatchInternal ListFormatDefault ps = showContextSeries ps description = vcat . mapFL description summary = summaryFL summaryFL = summaryFL . concatFL thing x = thing (helperx x) ++ "s" where helperx :: FL a C(x y) -> a C(x y) helperx _ = undefined things = thing instance (PatchListFormat p, ShowPatchBasic p) => ShowPatchBasic (RL p) where showPatch = showPatch . reverseRL instance (Apply p, IsHunk p, PatchListFormat p, ShowPatch p) => ShowPatch (RL p) where showContextPatch = showContextPatch . reverseRL description = description . reverseRL summary = summary . reverseRL summaryFL = summaryFL . mapFL_FL reverseRL thing = thing . reverseRL things = things . reverseRL darcs-2.8.4/src/Darcs/Patch/V1.hs0000644001765600176560000000075012104371431015647 0ustar ganeshganesh{-# OPTIONS_GHC -fno-warn-orphans #-} module Darcs.Patch.V1 ( Patch ) where import Darcs.Patch.Patchy ( Patchy ) import Darcs.Patch.Prim ( PrimPatch ) import Darcs.Patch.RepoPatch ( RepoPatch ) import Darcs.Patch.V1.Apply () import Darcs.Patch.V1.Commute () import Darcs.Patch.V1.Core ( Patch ) import Darcs.Patch.V1.Read () import Darcs.Patch.V1.Show () import Darcs.Patch.V1.Viewing () instance PrimPatch prim => Patchy (Patch prim) instance PrimPatch prim => RepoPatch (Patch prim) darcs-2.8.4/src/Darcs/Patch/V2.hs0000644001765600176560000000043112104371431015644 0ustar ganeshganesh{-# OPTIONS_GHC -fno-warn-orphans #-} module Darcs.Patch.V2 ( RealPatch, prim2real ) where import Darcs.Patch.Prim ( PrimPatch ) import Darcs.Patch.RepoPatch ( RepoPatch ) import Darcs.Patch.V2.Real ( RealPatch, prim2real ) instance PrimPatch prim => RepoPatch (RealPatch prim) darcs-2.8.4/src/Darcs/Repository/0000755001765600176560000000000012104371431016143 5ustar ganeshganeshdarcs-2.8.4/src/Darcs/Repository/ApplyPatches.hs0000644001765600176560000000331612104371431021077 0ustar ganeshganesh-- Copyright (C) 2002-2005,2007 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP #-} #include "gadts.h" module Darcs.Repository.ApplyPatches ( applyPatches ) where import Darcs.Patch.ApplyMonad( ApplyMonad ) import Darcs.MonadProgress ( MonadProgress, ProgressAction(..), runProgressActions) import Darcs.Patch ( Patchy, apply ) import Darcs.IO () -- for ApplyMonad IO import Darcs.Patch.PatchInfoAnd ( PatchInfoAnd, hopefully, info ) import Darcs.Patch.Info ( humanFriendly ) import Darcs.Patch.Apply( ApplyState ) import Darcs.Witnesses.Ordered ( FL(..), mapFL ) import Printer ( text, ($$) ) applyPatches :: (MonadProgress m, ApplyMonad m (ApplyState p), Patchy p) => FL (PatchInfoAnd p) C(x y) -> m () applyPatches ps = runProgressActions "Applying patch" (mapFL doApply ps) where doApply hp = ProgressAction { paAction = apply (hopefully hp) , paMessage = humanFriendly (info hp) , paOnError = text "Unapplicable patch:" $$ humanFriendly (info hp) } darcs-2.8.4/src/Darcs/Repository/Cache.hs0000644001765600176560000004661712104371431017520 0ustar ganeshganesh{-# LANGUAGE CPP #-} #include "gadts.h" module Darcs.Repository.Cache ( cacheHash, okayHash, takeHash, Cache(..), CacheType(..), CacheLoc(..), WritableOrNot(..), HashedDir(..), hashedDir, unionCaches, unionRemoteCaches, cleanCaches, cleanCachesWithHint, fetchFileUsingCache, speculateFileUsingCache, speculateFilesUsingCache, writeFileUsingCache, peekInCache, repo2cache, writable, isthisrepo, hashedFilePath, allHashedDirs, compareByLocality, reportBadSources ) where import Control.Monad ( liftM, when, guard, unless, filterM, forM_, mplus ) import Data.List ( nub, intercalate ) import Data.Maybe ( catMaybes, listToMaybe, isJust, fromMaybe ) import System.Directory ( removeFile, doesFileExist, doesDirectoryExist, getDirectoryContents, getPermissions ) import qualified System.Directory as SD ( writable ) import System.Posix.Files ( linkCount, getSymbolicLinkStatus ) import System.IO ( hPutStrLn, stderr ) import Crypt.SHA256 ( sha256sum ) import ByteStringUtils ( gzWriteFilePS, linesPS ) import qualified Data.ByteString as B (length, drop, ByteString ) import qualified Data.ByteString.Char8 as BC (unpack) import SHA1 ( sha1PS ) import System.Posix.Files ( createLink ) import System.FilePath.Posix ( () ) import System.Directory ( createDirectoryIfMissing ) import Darcs.External ( gzFetchFilePS, fetchFilePS, speculateFileOrUrl, copyFileOrUrl, Cachable( Cachable ) ) import Darcs.Flags ( Compression( .. ), RemoteDarcs(..) ) import Darcs.Global ( darcsdir, addBadSource, isBadSource, addReachableSource, isReachableSource, getBadSourcesList ) import Darcs.Lock ( writeAtomicFilePS, gzWriteAtomicFilePS, withTemp ) import Progress ( progressList, debugMessage, debugFail ) import English ( englishNum, Noun(..), Pronoun(..) ) import Darcs.URL ( isFile, isHttpUrl, isSshUrl ) import Darcs.Utils ( withCurrentDirectory, catchall ) import Darcs.SignalHandler ( catchNonSignal ) import qualified URL ( ConnectionError(..) ) data HashedDir = HashedPristineDir | HashedPatchesDir | HashedInventoriesDir hashedDir :: HashedDir -> String hashedDir HashedPristineDir = "pristine.hashed" hashedDir HashedPatchesDir = "patches" hashedDir HashedInventoriesDir = "inventories" allHashedDirs :: [HashedDir] allHashedDirs = [HashedPristineDir, HashedPatchesDir, HashedInventoriesDir] data WritableOrNot = Writable | NotWritable deriving ( Show ) data CacheType = Repo | Directory deriving ( Eq, Show ) data CacheLoc = Cache { cacheType:: !CacheType, cacheWritable:: !WritableOrNot, cacheSource:: !String } newtype Cache = Ca [CacheLoc] -- abstract type for hiding cache instance Eq CacheLoc where (Cache Repo _ a) == (Cache Repo _ b) = a == b (Cache Directory _ a) == (Cache Directory _ b) = a == b _ == _ = False instance Show CacheLoc where show (Cache Repo Writable a) = "thisrepo:" ++ a show (Cache Repo NotWritable a) = "repo:" ++ a show (Cache Directory Writable a) = "cache:" ++ a show (Cache Directory NotWritable a) = "readonly:" ++ a instance Show Cache where show (Ca cs) = unlines $ map show cs unionCaches :: Cache -> Cache -> Cache unionCaches (Ca a) (Ca b) = Ca (nub (a++b)) -- | unionRemoteCaches merges caches. It tries to do better than just blindly -- copying remote cache entries: -- -- * If remote repository is accessed through network, do not copy any cache -- entries from it. Taking local entries does not make sense and using -- network entries can lead to darcs hang when it tries to get to -- unaccessible host. -- -- * If remote repositoty is local, copy all network cache entries. For local -- cache entries if the cache directory exists and is writable it is added -- as writable cache, if it exists but is not writable it is added as -- read-only cache. -- -- This approach should save us from bogus cache entries. One case it does not -- work very well is when you fetch from partial repository over network. -- Hopefully this is not a common case. unionRemoteCaches :: Cache -> Cache -> String -> IO (Cache) unionRemoteCaches local (Ca remote) repourl | isFile repourl = do f <- filtered return $ local `unionCaches` Ca f | otherwise = return local where filtered = mapM (\x -> fn x `catchall` return Nothing) remote >>= return . catMaybes fn :: CacheLoc -> IO (Maybe CacheLoc) fn (Cache Repo Writable _) = return Nothing fn c@(Cache t _ url) | isFile url = do ex <- doesDirectoryExist url if ex then do p <- getPermissions url return $ Just $ if writable c && SD.writable p then c else Cache t NotWritable url else return Nothing | otherwise = return $ Just c -- | Compares two caches, a remote cache is greater than a local one. -- The order of the comparison is given by: local < http < ssh compareByLocality :: CacheLoc -> CacheLoc -> Ordering compareByLocality (Cache _ _ x) (Cache _ _ y) | isLocal x && isRemote y = LT | isRemote x && isLocal y = GT | isHttpUrl x && isSshUrl y = LT | isSshUrl x && isHttpUrl y = GT | otherwise = EQ where isRemote r= isHttpUrl r || isSshUrl r isLocal = isFile repo2cache :: String -> Cache repo2cache r = Ca [Cache Repo NotWritable r] -- | 'cacheHash' computes the cache hash (i.e. filename) of a packed string. cacheHash :: B.ByteString -> String cacheHash ps = case show (B.length ps) of x | l > 10 -> sha256sum ps | otherwise -> replicate (10-l) '0' ++ x ++'-':sha256sum ps where l = length x okayHash :: String -> Bool okayHash s = length s == 40 || length s == 64 || length s == 75 takeHash :: B.ByteString -> Maybe (String, B.ByteString) takeHash ps = do h <- listToMaybe $ linesPS ps let v = BC.unpack h guard $ okayHash v Just (v, B.drop (B.length h) ps) checkHash :: String -> B.ByteString -> Bool checkHash h s | length h == 40 = sha1PS s == h | length h == 64 = sha256sum s == h | length h == 75 = B.length s == read (take 10 h) && sha256sum s == drop 11 h | otherwise = False -- |@fetchFileUsingCache cache dir hash@ receives a list of caches -- @cache@, the directory for which that file belongs @dir@ and the -- @hash@ of the file to fetch. It tries to fetch the file from one -- of the sources, trying them in order one by one. If the file -- cannot be fetched from any of the sources, this operation fails. fetchFileUsingCache :: Cache -> HashedDir -> String -> IO (String, B.ByteString) fetchFileUsingCache = fetchFileUsingCachePrivate Anywhere writable :: CacheLoc -> Bool writable (Cache _ NotWritable _) = False writable (Cache _ Writable _) = True isthisrepo :: CacheLoc -> Bool isthisrepo (Cache Repo Writable _) = True isthisrepo _ = False -- | @hashedFilePath cachelocation subdir hash@ returns the physical filename of -- hash @hash@ in the @subdir@ section of @cachelocation@. hashedFilePath :: CacheLoc -> HashedDir -> String -> String hashedFilePath (Cache Directory _ d) s f = d ++ "/" ++ (hashedDir s) ++ "/" ++ f hashedFilePath (Cache Repo _ r) s f = r ++ "/"++darcsdir++"/" ++ (hashedDir s) ++ "/" ++ f -- | @peekInCache cache subdir hash@ tells whether @cache@ and -- contains an object with hash @hash@ in a writable position. -- Florent: why do we want it to be in a writable position? peekInCache :: Cache -> HashedDir -> String -> IO Bool peekInCache (Ca cache) subdir f = cacheHasIt cache `catchall` return False where cacheHasIt [] = return False cacheHasIt (c:cs) | not $ writable c = cacheHasIt cs | otherwise = do ex <- doesFileExist $ fn c if ex then return True else cacheHasIt cs fn c = hashedFilePath c subdir f -- | @speculateFileUsingCache cache subdirectory name@ takes note that -- the file @name@ is likely to be useful soon: pipelined downloads -- will add it to the (low-priority) queue, for the rest it is a noop. speculateFileUsingCache :: Cache -> HashedDir -> String -> IO () speculateFileUsingCache c sd h = do debugMessage $ "Speculating on "++h copyFileUsingCache OnlySpeculate c sd h -- | Note that the files are likely to be useful soon: pipelined downloads will -- add them to the (low-priority) queue, for the rest it is a noop. speculateFilesUsingCache :: Cache -> HashedDir -> [String] -> IO () speculateFilesUsingCache _ _ [] = return () speculateFilesUsingCache cache sd hs = do --debugMessage $ "Thinking about speculating on "++unwords hs hs' <- filterM (fmap not . peekInCache cache sd) hs unless (null hs') $ do debugMessage $ "Speculating on "++unwords hs' copyFilesUsingCache OnlySpeculate cache sd hs' data OrOnlySpeculate = ActuallyCopy | OnlySpeculate deriving ( Eq ) -- | @copyFileUsingCache oos cache subdir f@ copy or hardlinks the -- file @f@ to one of the caches in @cache@,usually the global cache. -- If a writable cache doesn't exist the function will fail. copyFileUsingCache :: OrOnlySpeculate -> Cache -> HashedDir -> String -> IO () copyFileUsingCache oos (Ca cache) subdir f = do debugMessage $ "I'm doing copyFileUsingCache on "++(hashedDir subdir)++"/"++f Just stickItHere <- cacheLoc cache createDirectoryIfMissing False (reverse $ dropWhile (/='/') $ reverse stickItHere) filterBadSources cache >>= (flip sfuc) stickItHere `catchall` return () where cacheLoc [] = return Nothing cacheLoc (c:cs) | not $ writable c = cacheLoc cs | otherwise = do ex <- doesFileExist $ fn c if ex then fail "Bug in darcs: This exception should be caught in speculateFileUsingCache" else do othercache <- cacheLoc cs return $ othercache `mplus` Just (fn c) sfuc [] _ = return () sfuc (c:cs) out | not (writable c) = if oos == OnlySpeculate then speculateFileOrUrl (fn c) out `catchNonSignal` (\e -> checkCacheReachability (show e) c) else copyFileOrUrl DefaultRemoteDarcs (fn c) out Cachable `catchNonSignal` (\e -> checkCacheReachability (show e) c) | otherwise = sfuc cs out fn c = hashedFilePath c subdir f copyFilesUsingCache :: OrOnlySpeculate -> Cache -> HashedDir -> [String] -> IO () copyFilesUsingCache oos cache subdir hs = forM_ hs $ copyFileUsingCache oos cache subdir data FromWhere = LocalOnly | Anywhere deriving ( Eq ) -- | Checks if a given cache entry is reachable or not. -- It receives an error caught during execution and the cache entry. -- If the caches is not reachable it is blacklisted and not longer tried for -- the rest of the session. If it is reachable it is whitelisted and future errors with such -- cache get ignore. -- To determine reachability: -- * For a local cache, if the given source doesn't exist anymore, it is blacklisted. -- * For remote sources if the error is timeout, it is blacklisted, if not, -- it checks if _darcs/hashed_inventory exist, if it does, the entry is whitelisted, if -- it doesn't, it is blacklisted. checkCacheReachability :: String -> CacheLoc -> IO () checkCacheReachability e cache | isFile source = do reachable <- isReachableSource unless (reachable source) $ do exist <- doesDirectoryExist source if exist then addReachableSource source else addBadSource source | isHttpUrl source = do reachable <- isReachableSource unless (reachable source) $ do let string = case dropWhile (/='(') e of (_:xs) -> fst (break (==')') xs) _ -> e let cerror = case reads string ::[(URL.ConnectionError,String)] of [(ce,_)] -> Just ce _ -> Nothing if isJust cerror then addBadSource source else checkFileReachability | isSshUrl source = do reachable <- isReachableSource unless (reachable source) checkFileReachability | otherwise = fail $ "unknown transport protocol for: " ++ source where source = cacheSource cache checkFileReachability = do reachable <- checkHashedInventoryReachability cache if reachable then addReachableSource source else addBadSource source -- | Returns a list of reachables cache entries, -- taking out the blacklisted entries filterBadSources :: [CacheLoc] -> IO [CacheLoc] filterBadSources cache = do badSource <- isBadSource return $ filter (not . badSource . cacheSource) cache -- | Checks if the _darcs/hashed_inventory exist and is reachable checkHashedInventoryReachability :: CacheLoc -> IO Bool checkHashedInventoryReachability cache = withTemp $ \tempout -> do let f = cacheSource cache darcsdir "hashed_inventory" copyFileOrUrl DefaultRemoteDarcs f tempout Cachable return True `catchNonSignal` (\_ -> return False) fetchFileUsingCachePrivate :: FromWhere -> Cache -> HashedDir -> String -> IO (String, B.ByteString) fetchFileUsingCachePrivate fromWhere (Ca cache) subdir f = do when (fromWhere == Anywhere) $ copyFileUsingCache ActuallyCopy (Ca cache) subdir f filterBadSources cache >>= ffuc `catchall` debugFail ("Couldn't fetch `"++f++"'\nin subdir "++ hashedDir subdir ++ " from sources:\n\n"++show (Ca cache)) where ffuc (c:cs) | not (writable c) && (Anywhere == fromWhere || isFile (fn c)) = do debugMessage $ "In fetchFileUsingCachePrivate I'm going manually" debugMessage $ " getting "++f debugMessage $ " from " ++ fn c x <- gzFetchFilePS (fn c) Cachable if not $ checkHash f x then do x' <- fetchFilePS (fn c) Cachable when (not $ checkHash f x') $ do hPutStrLn stderr $ "Hash failure in " ++ fn c fail $ "Hash failure in " ++ fn c return (fn c, x') else return (fn c, x) -- FIXME: create links in caches `catchNonSignal` (\e -> do checkCacheReachability (show e) c filterBadSources cs >>= ffuc) | writable c = do x1 <- gzFetchFilePS (fn c) Cachable x <- if not $ checkHash f x1 then do x2 <- fetchFilePS (fn c) Cachable when (not $ checkHash f x2) $ do hPutStrLn stderr $ "Hash failure in " ++ fn c removeFile $ fn c fail $ "Hash failure in " ++ fn c return x2 else return x1 mapM_ (tryLinking (fn c)) cs return (fn c, x) `catchNonSignal` (\ e -> do createCache c subdir `catchall` return () -- don't worry checkCacheReachability (show e) c (fname,x) <- filterBadSources cs >>= ffuc do createLink fname (fn c) return (fn c, x) `catchall` do gzWriteFilePS (fn c) x `catchall` return () return (fname,x)) | otherwise = ffuc cs ffuc [] = debugFail $ "No sources from which to fetch file `"++f++"'\n"++ show (Ca cache) tryLinking ff c@(Cache Directory Writable d) = do createDirectoryIfMissing False (d++"/"++(hashedDir subdir)) createLink ff (fn c) `catchall` return () tryLinking _ _ = return () fn c = hashedFilePath c subdir f createCache :: CacheLoc -> HashedDir -> IO () createCache (Cache Directory _ d) subdir = createDirectoryIfMissing True (d ++ "/" ++ (hashedDir subdir)) createCache _ _ = return () -- | @write compression filename content@ writes @content@ to the file @filename@ according -- to the policy given by @compression@. write :: Compression -> String -> B.ByteString -> IO () write NoCompression = writeAtomicFilePS write GzipCompression = gzWriteAtomicFilePS -- | @writeFileUsingCache cache compression subdir contents@ write the string @contents@ to -- the directory subdir, except if it is already in the cache, in which case it is a noop. -- Warning (?) this means that in case of a hash collision, writing using writeFileUsingCache is -- a noop. The returned value is the filename that was given to the string. writeFileUsingCache :: Cache -> Compression -> HashedDir -> B.ByteString -> IO String writeFileUsingCache (Ca cache) compr subdir ps = (fetchFileUsingCachePrivate LocalOnly (Ca cache) subdir hash >> return hash) `catchall` wfuc cache `catchall` debugFail ("Couldn't write `"++hash++"'\nin subdir "++(hashedDir subdir)++" to sources:\n\n"++ show (Ca cache)) where hash = cacheHash ps wfuc (c:cs) | not $ writable c = wfuc cs | otherwise = do createCache c subdir write compr (fn c) ps -- FIXME: create links in caches return hash wfuc [] = debugFail $ "No location to write file `" ++ (hashedDir subdir) ++"/"++hash ++ "'" fn c = hashedFilePath c subdir hash cleanCaches :: Cache -> HashedDir -> IO () cleanCaches c d = cleanCachesWithHint' c d Nothing cleanCachesWithHint :: Cache -> HashedDir -> [String] -> IO () cleanCachesWithHint c d h = cleanCachesWithHint' c d (Just h) cleanCachesWithHint' :: Cache -> HashedDir -> Maybe [String] -> IO () cleanCachesWithHint' (Ca cs) subdir hint = mapM_ cleanCache cs where cleanCache (Cache Directory Writable d) = (withCurrentDirectory (d++"/"++(hashedDir subdir)) $ do fs' <- getDirectoryContents "." let fs = fromMaybe fs' hint mapM_ clean $ progressList ("Cleaning cache "++d++"/"++(hashedDir subdir)) $ filter okayHash fs) `catchall` return () cleanCache _ = return () clean f = do lc <- linkCount `liftM` getSymbolicLinkStatus f when (lc < 2) $ removeFile f `catchall` return () -- | Prints an error message with a list of bad caches. reportBadSources :: IO () reportBadSources = do sources <- getBadSourcesList let size = length sources unless (null sources) $ hPutStrLn stderr $ concat [ "\nHINT: I could not reach the following ", englishNum size (Noun "repository") ":" , "\n", (intercalate "\n" (map (" " ++) sources)) , "\n If you're not using ", englishNum size It ", you should probably delete" , "\n the corresponding ", englishNum size (Noun "entry") " from _darcs/prefs/sources." ] darcs-2.8.4/src/Darcs/Repository/Format.hs0000644001765600176560000001604212104371431017732 0ustar ganeshganesh-- Copyright (C) 2005 David Roundy -- -- This file is licensed under the GPL, version two or later. {-# LANGUAGE CPP #-} module Darcs.Repository.Format ( RepoFormat(..), RepoProperty(..), identifyRepoFormat, tryIdentifyRepoFormat, createRepoFormat, writeRepoFormat, writeProblem, readProblem, readfromAndWritetoProblem, formatHas, ) where import Data.Maybe ( isJust, mapMaybe ) import Control.Monad ( mplus, (<=<) ) import Darcs.SignalHandler ( catchNonSignal ) import Darcs.External ( fetchFilePS, Cachable( Cachable ) ) import Darcs.Flags ( DarcsFlag ( UseFormat2, UseHashedInventory, UseNoWorkingDir ) ) import Darcs.Lock ( writeBinFile ) import Darcs.Utils ( catchall, prettyException ) import Progress ( beginTedious, endTedious, finishedOneIO ) import Darcs.Global ( darcsdir ) import ByteStringUtils ( linesPS ) import qualified Data.ByteString.Char8 as BC (split, unpack, singleton, elemIndex, pack) import qualified Data.ByteString as B (ByteString, null, empty) import qualified ByteStringUtils as BU ( intercalate ) #include "impossible.h" data RepoProperty = Darcs1_0 | Darcs2 | HashedInventory | NoWorkingDir -- | @RepoFormat@ is the representation of the format of a -- repository. Each sublist corresponds to a line in the format -- file. Each line is decomposed into words. newtype RepoFormat = RF [[B.ByteString]] deriving ( Show ) -- | The file where the format information should be. df :: FilePath df = darcsdir++"/format" -- | @identifyRepoFormat URL@ identifies the format of the repository -- at the given address. Fails if we weren't able to identify the format. identifyRepoFormat :: String -> IO RepoFormat identifyRepoFormat = either fail return <=< tryIdentifyRepoFormat -- | @tryIdentifyRepoFormat URL@ identifies the format of the repository -- at the given address. Return @Left reason@ if it fails, where -- @reason@ explains why we weren't able to identify the format. tryIdentifyRepoFormat :: String -> IO (Either String RepoFormat) tryIdentifyRepoFormat repo = do let k = "Identifying repository "++repo beginTedious k finishedOneIO k "format" dff <- fetchFilePS (repo ++ "/" ++ df) Cachable `catchall` return B.empty -- below is a workaround for servers that don't return a 404 on nonexistent files rf <- if B.null dff || isJust (BC.elemIndex '<' dff) then do finishedOneIO k "inventory" have_inventory <- doesRemoteFileExist (repo++"/"++darcsdir++"/inventory") return $ case have_inventory of Right _ -> Right defaultRepoFormat Left e -> Left . unlines $ [ "Not a repository: "++repo++" ("++e++")" , "" , "HINT: Do you have the right URI for the repository?" , "" , " If so, check with the repository owner to see if the following files" , " are readable:" , "" , " 1. _darcs/format - might not exist; that's OK" , " 2. _darcs/inventory - should exist if #1 is missing" , " 3. _darcs/hashed_inventory - should exist if #2 is missing" ] else return $ Right $ parseRepoFormat dff endTedious k return rf where drfe x = fetchFilePS x Cachable >> return True doesRemoteFileExist x = fmap Right (drfe x) `catchNonSignal` (\e -> return (Left (prettyException e))) -- | @writeRepoFormat@ writes the repo format to the given file. writeRepoFormat :: RepoFormat -> FilePath -> IO () writeRepoFormat (RF rf) loc = writeBinFile loc $ unlines $ map (BC.unpack . BU.intercalate (BC.singleton '|')) rf parseRepoFormat :: B.ByteString -> RepoFormat parseRepoFormat ps = RF $ map (BC.split '|') $ filter (not . B.null) $ linesPS ps -- | The repo format we assume if we do not find a format file. defaultRepoFormat :: RepoFormat defaultRepoFormat = RF [[rp2ps Darcs1_0]] createRepoFormat :: [DarcsFlag] -> RepoFormat createRepoFormat fs = RF (map rp2ps (HashedInventory:flags2wd): maybe2) where maybe2 = if UseFormat2 `notElem` fs && (UseHashedInventory `elem` fs) then [] else [[rp2ps Darcs2]] flags2wd = if UseNoWorkingDir `elem` fs then [NoWorkingDir] else [] -- | @writeProblem form@ tells if we can write to a repo in format @form@. -- It returns @Nothing@ if there's no problem writing to such a repository. writeProblem :: RepoFormat -> Maybe String writeProblem rf = readProblem rf `mplus` allProblems rf wp where wp x | all isKnown x = Nothing wp [] = impossible wp x = Just $ unwords $ "Can't write repository format: " : map BC.unpack (filter (not . isKnown) x) -- | @readfromAndWritetoProblem form@ tells if we can read from and write to a repo in -- format @form@. It returns @Nothing@ if there's no problem reading -- and writing to such a repository. readfromAndWritetoProblem :: RepoFormat -> RepoFormat -> Maybe String readfromAndWritetoProblem inrf outrf | formatHas Darcs2 inrf /= formatHas Darcs2 outrf = Just "Cannot mix darcs-2 repositories with older formats" | otherwise = readProblem inrf `mplus` writeProblem outrf -- | @readProblem form@ tells if we can read from a repo in format @form@. -- It returns @Nothing@ if there's no problem reading from such a repository. readProblem :: RepoFormat -> Maybe String readProblem rf | formatHas Darcs1_0 rf && formatHas Darcs2 rf = Just "Invalid repositoryformat: format 2 is incompatible with format 1" readProblem rf = allProblems rf rp where rp x | any isKnown x = Nothing rp [] = impossible rp x = Just $ unwords $ "Can't understand repository format:" : map BC.unpack x allProblems :: RepoFormat -> ([B.ByteString] -> Maybe String) -> Maybe String allProblems (RF ks) repoFormatLineProblem = maybeSingleError $ mapMaybe repoFormatLineProblem ks where maybeSingleError [] = Nothing maybeSingleError xs = Just $ unlines xs -- | Does this version of darcs know how to handle this property? isKnown :: B.ByteString -> Bool isKnown p = p `elem` map rp2ps knownProperties -- | This is the list of properties which this version of darcs knows -- how to handle. knownProperties :: [RepoProperty] knownProperties = [Darcs1_0, Darcs2, HashedInventory, NoWorkingDir] formatHas :: RepoProperty -> RepoFormat -> Bool formatHas f (RF ks) = rp2ps f `elem` concat ks instance Show RepoProperty where show Darcs1_0 = "darcs-1.0" show Darcs2 = "darcs-2" show HashedInventory = "hashed" show NoWorkingDir = "no-working-dir" rp2ps :: RepoProperty -> B.ByteString rp2ps = BC.pack . showdarcs-2.8.4/src/Darcs/Repository/HashedIO.hs0000644001765600176560000003331412104371431020127 0ustar ganeshganesh-- Copyright (C) 2007 David Roundy -- -- 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, 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. {-# LANGUAGE CPP, TypeSynonymInstances, FlexibleInstances, MultiParamTypeClasses #-} #include "gadts.h" module Darcs.Repository.HashedIO ( HashedIO, copyHashed, copyPartialsHashed, cleanHashdir, RW(RW) -- only exported to make warning go away ) where import Darcs.Global ( darcsdir ) import qualified Data.Set as Set import System.Directory ( getDirectoryContents, createDirectoryIfMissing ) import Control.Monad.State ( StateT, runStateT, modify, get, put, gets, lift ) import Control.Monad ( when ) import Control.Applicative ( (<$>) ) import Data.Maybe ( isJust ) import System.IO.Unsafe ( unsafeInterleaveIO ) import Darcs.Repository.Cache ( Cache(..), fetchFileUsingCache, writeFileUsingCache, peekInCache, speculateFileUsingCache, okayHash, cleanCachesWithHint, HashedDir(..), hashedDir ) import Darcs.RepoPath ( FilePathLike, toFilePath ) import Darcs.Patch.ApplyMonad ( ApplyMonad(..) ) import Darcs.Flags ( Compression( .. ) ) import Darcs.Lock ( writeAtomicFilePS, removeFileMayNotExist ) import Darcs.Utils ( withCurrentDirectory ) import Progress ( debugMessage, tediousSize, finishedOneIO ) import Darcs.Patch.FileName ( FileName, normPath, fp2fn, fn2fp, fn2niceps, niceps2fn, breakOnDir, ownName, superName ) import ByteStringUtils ( linesPS, unlinesPS ) import qualified Data.ByteString as B (ByteString, length, empty) import qualified Data.ByteString.Char8 as BC (unpack, pack) import Storage.Hashed.Darcs( readDarcsHashedDir, darcsLocation, decodeDarcsHash, decodeDarcsSize ) import Storage.Hashed.Tree( ItemType(..), Tree ) import Darcs.CommandsAux -- | @readHashFile c subdir hash@ reads the file with hash @hash@ in dir subdir, -- fetching it from 'Cache' @c@ if needed. readHashFile :: Cache -> HashedDir -> String -> IO (String,B.ByteString) readHashFile c subdir hash = do debugMessage $ "Reading hash file "++hash++" from "++(hashedDir subdir)++"/" fetchFileUsingCache c subdir hash data HashDir r p = HashDir { permissions :: !r, cache :: !Cache, compress :: !Compression, rootHash :: !String } type HashedIO p = StateT (HashDir RW p) IO data RW = RW {- class Readable r where isRO :: r -> Bool isRO = const False instance Readable RW instance Readable RO where isRO RO = True -} mWithCurrentDirectory :: FileName -> HashedIO p a -> HashedIO p a mWithCurrentDirectory fn j | fn' == fp2fn "" = j | otherwise = case breakOnDir fn' of Nothing -> do c <- readroot case geta D fn' c of Nothing -> fail "dir doesn't exist in mWithCurrentDirectory..." Just h -> do (h',x) <- withh h j writeroot $ seta D fn' h' c return x Just (d,fn'') -> do c <- readroot case geta D d c of Nothing -> fail "dir doesn't exist..." Just h -> do (h',x) <- withh h $ mWithCurrentDirectory fn'' j writeroot $ seta D d h' c return x where fn' = normPath fn mInCurrentDirectory :: FileName -> HashedIO p a -> HashedIO p a mInCurrentDirectory fn j | fn' == fp2fn "" = j | otherwise = case breakOnDir fn' of Nothing -> do c <- readroot case geta D fn' c of Nothing -> fail "dir doesn't exist mInCurrentDirectory..." Just h -> inh h j Just (d,fn'') -> do c <- readroot case geta D d c of Nothing -> fail "dir doesn't exist..." Just h -> inh h $ mInCurrentDirectory fn'' j where fn' = normPath fn instance ApplyMonad (HashedIO p) Tree where type ApplyMonadBase (HashedIO p) = IO mDoesDirectoryExist fn = do thing <- identifyThing fn case thing of Just (D,_) -> return True _ -> return False mReadFilePS fn = mInCurrentDirectory (superName fn) $ do c <- readroot case geta F (ownName fn) c of Nothing -> fail $ " file don't exist... "++ fn2fp fn Just h -> readhash h mCreateDirectory fn = do h <- writeHashFile B.empty exists <- isJust `fmap` identifyThing fn when exists $ fail "can't mCreateDirectory over an existing object." makeThing fn (D,h) mRename o n = do nexists <- isJust `fmap` identifyThing n when nexists $ fail "mRename failed..." mx <- identifyThing o -- for backwards compatibility accept rename of nonexistent files. case mx of Nothing -> return () Just x -> do rmThing o makeThing n x mRemoveDirectory = rmThing mRemoveFile f = do x <- mReadFilePS f when (B.length x /= 0) $ fail $ "Cannot remove non-empty file "++fn2fp f rmThing f identifyThing :: FileName -> HashedIO p (Maybe (ObjType,String)) identifyThing fn | fn' == fp2fn "" = do h <- gets rootHash return $ Just (D, h) | otherwise = case breakOnDir fn' of Nothing -> getany fn' `fmap` readroot Just (d,fn'') -> do c <- readroot case geta D d c of Nothing -> return Nothing Just h -> inh h $ identifyThing fn'' where fn' = normPath fn makeThing :: FileName -> (ObjType,String) -> HashedIO p () makeThing fn (o,h) = mWithCurrentDirectory (superName $ normPath fn) $ seta o (ownName $ normPath fn) h `fmap` readroot >>= writeroot rmThing :: FileName -> HashedIO p () rmThing fn = mWithCurrentDirectory (superName $ normPath fn) $ do c <- readroot let c' = filter (\(_,x,_)->x/= ownName (normPath fn)) c if length c' == length c - 1 then writeroot c' else fail "obj doesn't exist in rmThing" readhash :: String -> HashedIO p B.ByteString readhash h = do c <- gets cache z <- lift $ unsafeInterleaveIO $ readHashFile c HashedPristineDir h let (_,out) = z return out withh :: String -> HashedIO p a -> HashedIO p (String,a) withh h j = do hd <- get put $ hd { rootHash = h } x <- j h' <- gets rootHash put hd return (h',x) inh :: String -> HashedIO p a -> HashedIO p a inh h j = do hd <- get put $ hd { rootHash = h } x <- j put hd return x readroot :: HashedIO p [(ObjType, FileName, String)] readroot = do haveitalready <- peekroot cc <- gets rootHash >>= readdir when (not haveitalready) $ speculate cc return cc where speculate :: [(a,b,String)] -> HashedIO q () speculate c = do cac <- gets cache mapM_ (\(_,_,z) -> lift $ speculateFileUsingCache cac HashedPristineDir z) c peekroot :: HashedIO p Bool peekroot = do HashDir _ c _ h <- get lift $ peekInCache c HashedPristineDir h writeroot :: [(ObjType, FileName, String)] -> HashedIO p () writeroot c = do h <- writedir c modify $ \hd -> hd { rootHash = h } data ObjType = F | D deriving Eq -- | @geta objtype name stuff@ tries to get an object of type @objtype@ named @name@ -- in @stuff@. geta :: ObjType -> FileName -> [(ObjType, FileName, String)] -> Maybe String geta o f c = do (o',h) <- getany f c if o == o' then Just h else Nothing getany :: FileName -> [(ObjType, FileName, String)] -> Maybe (ObjType,String) getany _ [] = Nothing getany f ((o,f',h):_) | f == f' = Just (o,h) getany f (_:r) = getany f r seta :: ObjType -> FileName -> String -> [(ObjType, FileName, String)] -> [(ObjType, FileName, String)] seta o f h [] = [(o,f,h)] seta o f h ((_,f',_):r) | f == f' = (o,f,h):r seta o f h (x:xs) = x : seta o f h xs readdir :: String -> HashedIO p [(ObjType, FileName, String)] readdir hash = (parsed . linesPS) `fmap` readhash hash where parsed (t:n:h:rest) | t == dir = (D, niceps2fn n, BC.unpack h) : parsed rest | t == file = (F, niceps2fn n, BC.unpack h) : parsed rest parsed _ = [] dir :: B.ByteString dir = BC.pack "directory:" file :: B.ByteString file = BC.pack "file:" writedir :: [(ObjType, FileName, String)] -> HashedIO p String writedir c = writeHashFile cps where cps = unlinesPS $ concatMap (\ (o,d,h) -> [showO o,fn2niceps d,BC.pack h]) c++[B.empty] showO D = dir showO F = file writeHashFile :: B.ByteString -> HashedIO p String writeHashFile ps = do c <- gets cache compr <- gets compress lift $ writeFileUsingCache c compr HashedPristineDir ps copyHashed :: String -> Cache -> Compression -> String -> IO () -- Warning: A do-notation statement discarded a result of type ((), HashDir RO ghc-prim copyHashed k c compr z = do _ <- runStateT cph $ HashDir { permissions = RW, cache = c, compress = compr, rootHash = z } return () where cph = do cc <- readroot lift $ tediousSize k (length cc) mapM_ cp cc cp (F,n,h) = do ps <- readhash h lift $ finishedOneIO k (fn2fp n) lift $ writeAtomicFilePS (fn2fp n) ps cp (D,n,h) = if isMaliciousSubPath (fn2fp n) then fail ("Caught malicious path: " ++ fn2fp n) else do lift $ createDirectoryIfMissing False (fn2fp n) lift $ finishedOneIO k (fn2fp n) lift $ withCurrentDirectory (fn2fp n) $ copyHashed k c compr h copyPartialsHashed :: FilePathLike fp => Cache -> Compression -> String -> [fp] -> IO () copyPartialsHashed c compr root = mapM_ (copyPartialHashed c compr root) copyPartialHashed :: FilePathLike fp => Cache -> Compression -> String -> fp -> IO () copyPartialHashed c compr root ff = do createDirectoryIfMissing True (basename $ toFilePath ff) -- Warning: A do-notation statement discarded a result of type ((), HashDir RO ghc-prim _ <- runStateT (cp $ fp2fn $ toFilePath ff) $ HashDir { permissions = RW, cache = c, compress=compr, rootHash = root } return () where basename = reverse . dropWhile ('/' /=) . dropWhile ('/' ==) . reverse cp f = do mt <- identifyThing f case mt of Just (D,h) -> do lift $ createDirectoryIfMissing True (fn2fp f) lift $ withCurrentDirectory (fn2fp f) $ copyHashed "" c compr h Just (F,h) -> do ps <- readhash h lift $ writeAtomicFilePS (fn2fp f) ps Nothing -> return () cleanHashdir :: Cache -> HashedDir -> [String] -> IO () cleanHashdir c dir_ hashroots = do -- we'll remove obsolete bits of "dir" debugMessage $ "Cleaning out " ++ (hashedDir dir_) ++ "..." let hashdir = darcsdir ++ "/" ++ (hashedDir dir_) ++ "/" listone h = do let size = decodeDarcsSize $ BC.pack h hash = decodeDarcsHash $ BC.pack h x <- readDarcsHashedDir hashdir (size, hash) let subs = [ fst $ darcsLocation "" (s, h') | (TreeType, _, s, h') <- x ] hashes = h : [ fst $ darcsLocation "" (s, h') | (_, _, s, h') <- x ] (hashes++) . concat <$> mapM listone subs hs <- set . concat <$> mapM listone hashroots fs <- set . filter okayHash <$> getDirectoryContents hashdir mapM_ (removeFileMayNotExist . (hashdir++)) (unset $ fs `Set.difference` hs) -- and also clean out any global caches. debugMessage "Cleaning out any global caches..." cleanCachesWithHint c dir_ (unset $ fs `Set.difference` hs) where set = Set.fromList . map BC.pack unset = map BC.unpack . Set.toList darcs-2.8.4/src/Darcs/Repository/HashedRepo.hs0000644001765600176560000006314012104371431020525 0ustar ganeshganesh-- Copyright (C) 2006-2007 David Roundy -- -- 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, 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. {-# LANGUAGE CPP, ScopedTypeVariables #-} #include "gadts.h" module Darcs.Repository.HashedRepo ( revertTentativeChanges, finalizeTentativeChanges, cleanPristine, copyPristine, copyPartialsPristine, applyToTentativePristine, addToSpecificInventory, addToTentativeInventory, removeFromTentativeInventory, readRepo, readTentativeRepo, readRepoUsingSpecificInventory, writeAndReadPatch, writeTentativeInventory, copyRepo, readHashedPristineRoot, pris2inv, copySources, listInventories, writePatchIfNecessary, readRepoFromInventoryList, readPatchIds ) where import Prelude hiding ( catch ) import System.Directory ( createDirectoryIfMissing ) import System.FilePath.Posix( () ) import System.IO.Unsafe ( unsafeInterleaveIO ) import System.IO ( stderr, hPutStrLn ) import Data.List ( delete ) import Control.Monad ( unless ) import Control.Applicative ( (<$>) ) import Control.Exception ( catch, IOException ) import Workaround ( renameFile ) import Darcs.Flags ( Compression, RemoteDarcs ) import Darcs.Patch.Set ( PatchSet(..), Tagged(..), SealedPatchSet ) #ifdef GADT_WITNESSES import Darcs.Patch.Set ( Origin ) #endif import Darcs.RepoPath ( FilePathLike, ioAbsoluteOrRemote, toPath ) import Darcs.Repository.Cache ( Cache(..), CacheLoc(..), fetchFileUsingCache, speculateFilesUsingCache, writeFileUsingCache, unionCaches, repo2cache, okayHash, takeHash, HashedDir(..), hashedDir, peekInCache ) import qualified Darcs.Repository.Cache as DarcsCache import Darcs.Repository.HashedIO ( copyHashed, copyPartialsHashed, cleanHashdir ) import Darcs.Repository.InternalTypes ( Repository(..), extractCache, modifyCache ) import Darcs.Patch.PatchInfoAnd ( PatchInfoAnd, patchInfoAndPatch, info, extractHash, createHashed ) import Darcs.Patch ( RepoPatch, Patchy, showPatch, readPatch, apply ) import Darcs.Patch.Apply ( Apply, ApplyState ) import Darcs.Patch.ReadMonads ( parseStrictly ) import Darcs.Patch.Depends ( commuteToEnd, slightlyOptimizePatchset ) import Darcs.Patch.Info ( PatchInfo, showPatchInfo, humanFriendly, readPatchInfo ) import Darcs.Witnesses.Unsafe ( unsafeCoerceP ) import Darcs.Witnesses.Ordered ( reverseRL, reverseFL, (+<+) ) import ByteStringUtils ( gzReadFilePS, dropSpace ) import qualified Data.ByteString as B (null, length, empty ,tail, take, drop, ByteString) import qualified Data.ByteString.Char8 as BC (unpack, dropWhile, break, pack) import Printer ( Doc, hcat, (<>), ($$), renderString, renderPS, text, invisiblePS ) import Darcs.ColorPrinter () -- for instance Show Doc import Crypt.SHA256 ( sha256sum ) import Darcs.External ( copyFileOrUrl, cloneFile, fetchFilePS, gzFetchFilePS, Cachable( Uncachable ) ) import Darcs.Lock ( writeBinFile, writeDocBinFile, writeAtomicFilePS, appendBinFile, appendDocBinFile ) import Darcs.Utils ( withCurrentDirectory ) import Progress ( beginTedious, endTedious, debugMessage, finishedOneIO ) #include "impossible.h" import Darcs.Witnesses.Ordered ( FL(..), RL(..), (:>)(..), mapRL, mapFL ) import Darcs.Witnesses.Sealed ( Sealed(..), seal, unseal, mapSeal ) import Darcs.Global ( darcsdir ) import Storage.Hashed.Darcs( hashedTreeIO, readDarcsHashedNosize, readDarcsHashed, writeDarcsHashed, decodeDarcsHash, decodeDarcsSize ) import Storage.Hashed.Tree( treeHash, Tree ) import Storage.Hashed.Hash( encodeBase16, Hash(..) ) applyHashed' :: (Apply p, ApplyState p ~ Tree) => Hash -> p C(x y) -> IO String applyHashed' root p = do case root of (SHA256 _) -> return () _ -> fail $ "Cannot handle hash: " ++ show root s <- readDarcsHashedNosize "_darcs/pristine.hashed" root (_, t) <- (hashedTreeIO (apply p) s "_darcs/pristine.hashed") return $ BC.unpack . encodeBase16 $ treeHash t applyHashed :: (ApplyState q ~ Tree, Patchy q) => String -> q C(x y) -> IO String applyHashed h p = applyHashed' hash p `catch` \(_ :: IOException) -> do hPutStrLn stderr warn inv <- gzReadFilePS invpath let oldroot = BC.pack $ inv2pris inv oldroot_hash = decodeDarcsHash oldroot oldroot_size = decodeDarcsSize oldroot old <- readDarcsHashed "_darcs/pristine.hashed" (oldroot_size, oldroot_hash) root <- writeDarcsHashed old "_darcs/pristine.hashed" let newroot = BC.unpack $ encodeBase16 root writeDocBinFile invpath $ pris2inv newroot inv cleanHashdir (Ca []) HashedPristineDir [newroot] hPutStrLn stderr "Pristine conversion done..." applyHashed' root p where invpath = darcsdir ++ "/hashed_inventory" hash = decodeDarcsHash $ BC.pack h warn = "WARNING: Doing a one-time conversion of pristine format.\n" ++ "This may take a while. The new format is backwards-compatible." revertTentativeChanges :: IO () revertTentativeChanges = do cloneFile (darcsdir++"/hashed_inventory") (darcsdir++"/tentative_hashed_inventory") i <- gzReadFilePS (darcsdir++"/hashed_inventory") writeBinFile (darcsdir++"/tentative_pristine") $ "pristine:" ++ inv2pris i finalizeTentativeChanges :: (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u t) -> Compression -> IO () finalizeTentativeChanges r compr = do let t = darcsdir++"/tentative_hashed_inventory" -- first let's optimize it... debugMessage "Optimizing the inventory..." ps <- readTentativeRepo r "." writeTentativeInventory (extractCache r) compr ps -- then we'll add in the pristine cache, i <- gzReadFilePS t p <- gzReadFilePS $ darcsdir++"/tentative_pristine" writeDocBinFile t $ pris2inv (inv2pris p) i -- and rename it to its final value renameFile t $ darcsdir++"/hashed_inventory" -- note: in general we can't clean the pristine cache, because a -- simultaneous get might be in progress readHashedPristineRoot :: Repository p C(r u t) -> IO (Maybe String) readHashedPristineRoot (Repo d _ _ _) = withCurrentDirectory d $ do i <- (Just `fmap` gzReadFilePS (darcsdir++"/hashed_inventory")) `catch` (\(_ :: IOException) -> return Nothing) return $ inv2pris `fmap` i cleanPristine :: Repository p C(r u t) -> IO () cleanPristine r@(Repo d _ _ _) = withCurrentDirectory d $ do -- we'll remove obsolete bits of our pristine cache debugMessage "Cleaning out the pristine cache..." i <- gzReadFilePS (darcsdir++"/hashed_inventory") cleanHashdir (extractCache r) HashedPristineDir [inv2pris i] addToSpecificInventory :: RepoPatch p => String -> Cache -> Compression -> PatchInfoAnd p C(x y) -> IO FilePath addToSpecificInventory invPath c compr p = do let invFile = darcsdir invPath hash <- snd `fmap` writePatchIfNecessary c compr p appendDocBinFile invFile $ showPatchInfo $ info p appendBinFile invFile $ "\nhash: " ++ hash ++ "\n" return $ darcsdir "patches" hash addToTentativeInventory :: RepoPatch p => Cache -> Compression -> PatchInfoAnd p C(x y) -> IO FilePath addToTentativeInventory = addToSpecificInventory "tentative_hashed_inventory" removeFromTentativeInventory :: (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u t) -> Compression -> FL (PatchInfoAnd p) C(x t) -> IO () removeFromTentativeInventory repo compr to_remove = -- FIXME: This algorithm should be *far* simpler. All we need do is -- to to remove the patches from a patchset and then write that -- patchset. The commutation behavior of PatchInfoAnd should track -- which patches need to be rewritten for us. do allpatches <- readTentativeRepo repo "." _ :> skipped <- return $ commuteToEnd (reverseFL to_remove) allpatches okay <- simpleRemoveFromTentativeInventory repo compr (mapFL info to_remove ++ mapRL info skipped) unless okay $ bug "bug in HashedRepo.removeFromTentativeInventory" sequence_ $ mapFL (addToTentativeInventory (extractCache repo) compr) (reverseRL skipped) simpleRemoveFromTentativeInventory :: forall p C(r u t). (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u t) -> Compression -> [PatchInfo] -> IO Bool simpleRemoveFromTentativeInventory repo compr pis = do inv <- readTentativeRepo repo "." case cut_inv pis inv of Nothing -> return False Just (Sealed inv') -> do writeTentativeInventory (extractCache repo) compr inv' return True where cut_inv :: [PatchInfo] -> PatchSet p C(start x) -> Maybe (SealedPatchSet p C(start)) cut_inv [] x = Just $ seal x cut_inv x (PatchSet NilRL (Tagged t _ ps :<: ts)) = cut_inv x (PatchSet (t :<: ps) ts) cut_inv xs (PatchSet (hp:<:r) ts) | info hp `elem` xs = cut_inv (info hp `delete` xs) (PatchSet r ts) cut_inv _ _ = Nothing writeHashFile :: Cache -> Compression -> HashedDir -> Doc -> IO String writeHashFile c compr subdir d = do debugMessage $ "Writing hash file to "++(hashedDir subdir) writeFileUsingCache c compr subdir $ renderPS d readRepo :: (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u t) -> String -> IO (PatchSet p C(Origin r)) readRepo repo d = readRepoUsingSpecificInventory "hashed_inventory" repo d readTentativeRepo :: (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u t) -> String -> IO (PatchSet p C(Origin t)) readTentativeRepo repo d = readRepoUsingSpecificInventory "tentative_hashed_inventory" repo d readRepoUsingSpecificInventory :: (RepoPatch p, ApplyState p ~ Tree) => String -> Repository p C(r u t) -> String -> IO (PatchSet p C(Origin s)) readRepoUsingSpecificInventory invPath repo dir = do realdir <- toPath `fmap` ioAbsoluteOrRemote dir Sealed ps <- readRepoPrivate (extractCache repo) realdir invPath `catch` (\e -> do hPutStrLn stderr ("Invalid repository: " ++ realdir) ioError e) return $ unsafeCoerceP ps readRepoPrivate :: (RepoPatch p, ApplyState p ~ Tree) => Cache -> FilePath -> FilePath -> IO (SealedPatchSet p C(Origin)) readRepoPrivate cache d iname = do inventory <- readInventoryPrivate cache (d "_darcs") iname readRepoFromInventoryList cache inventory readRepoFromInventoryList :: (RepoPatch p, ApplyState p ~ Tree) => Cache -> (Maybe String, [(PatchInfo, String)]) -> IO (SealedPatchSet p C(Origin)) readRepoFromInventoryList cache inventory = parseinvs inventory where read_patches :: (RepoPatch p, ApplyState p ~ Tree) => [(PatchInfo, String)] -> IO (Sealed (RL (PatchInfoAnd p) C(x))) read_patches [] = return $ seal NilRL read_patches allis@((i1,h1):is1) = lift2Sealed (\p rest -> i1 `patchInfoAndPatch` p :<: rest) (rp is1) (createHashed h1 (const $ speculate h1 allis >> parse i1 h1)) where rp :: (RepoPatch p, ApplyState p ~ Tree) => [(PatchInfo, String)] -> IO (Sealed (RL (PatchInfoAnd p) C(x))) rp [] = return $ seal NilRL rp [(i,h),(il,hl)] = lift2Sealed (\p rest -> i `patchInfoAndPatch` p :<: rest) (rp [(il,hl)]) (createHashed h (const $ speculate h (reverse allis) >> parse i h)) rp ((i,h):is) = lift2Sealed (\p rest -> i `patchInfoAndPatch` p :<: rest) (rp is) (createHashed h (parse i)) read_tag :: (RepoPatch p, ApplyState p ~ Tree) => (PatchInfo, String) -> IO (Sealed (PatchInfoAnd p C(x))) read_tag (i,h) = mapSeal (patchInfoAndPatch i) `fmap` createHashed h (parse i) speculate :: String -> [(PatchInfo, String)] -> IO () speculate h is = do already_got_one <- peekInCache cache HashedPatchesDir h unless already_got_one $ speculateFilesUsingCache cache HashedPatchesDir (map snd is) parse :: Patchy p => PatchInfo -> String -> IO (Sealed (p C(x))) parse i h = do debugMessage ("Reading patch file: "++ show (humanFriendly i)) (fn,ps) <- fetchFileUsingCache cache HashedPatchesDir h case readPatch ps of Just p -> return p Nothing -> fail $ unlines ["Couldn't parse file "++fn, "which is patch", renderString $ humanFriendly i] parseinvs :: (RepoPatch p, ApplyState p ~ Tree) => (Maybe String, [(PatchInfo, String)]) -> IO (SealedPatchSet p C(Origin)) parseinvs (Nothing, ris) = mapSeal (\ps -> PatchSet ps NilRL) `fmap` (read_patches $ reverse ris) parseinvs (Just h, []) = bug $ "bad inventory "++h++" (no tag) in parseinvs!" parseinvs (Just h, t:ris) = do Sealed ts <- unseal seal `fmap` unsafeInterleaveIO (read_ts t h) Sealed ps <- unseal seal `fmap` unsafeInterleaveIO (read_patches $ reverse ris) return $ seal $ PatchSet ps ts read_ts :: (RepoPatch p, ApplyState p ~ Tree) => (PatchInfo, String) -> String -> IO (Sealed (RL (Tagged p) C(Origin))) read_ts tag0 h0 = do contents <- unsafeInterleaveIO $ readTaggedInventory cache h0 let is = reverse $ case contents of (Just _, _:ris0) -> ris0 (Nothing, ris0) -> ris0 (Just _, []) -> bug "inventory without tag!!!!" Sealed ts <- fmap (unseal seal) $ unsafeInterleaveIO $ case contents of (Just h', t':_) -> read_ts t' h' (Just _, []) -> bug "inventory without tag!!!!" (Nothing, _) -> return $ seal NilRL Sealed ps <- unseal seal `fmap` unsafeInterleaveIO (read_patches is) Sealed tag00 <- read_tag tag0 return $ seal $ Tagged tag00 (Just h0) ps :<: ts lift2Sealed :: (FORALL(y z) q C(y z) -> p C(x y) -> r C(x z)) -> IO (Sealed (p C(x))) -> (FORALL(b) IO (Sealed (q C(b)))) -> IO (Sealed (r C(x))) lift2Sealed f iox ioy = do Sealed x <- unseal seal `fmap` unsafeInterleaveIO iox Sealed y <- unseal seal `fmap` unsafeInterleaveIO ioy return $ seal $ f y x readTaggedInventory :: Cache -> String -> IO (Maybe String, [(PatchInfo, String)]) readTaggedInventory cache ihash = do (fn,i_and_p) <- fetchFileUsingCache cache HashedInventoriesDir ihash let i = skipPristine i_and_p (rest,str) <- case BC.break ((==)'\n') i of (swt,pistr) | swt == BC.pack "Starting with inventory:" -> case BC.break ((==)'\n') $ B.tail pistr of (h,thisinv) | okayHash hash -> return (Just hash, thisinv) where hash = BC.unpack h _ -> fail $ "Bad hash in file " ++ fn _ -> return (Nothing,i) return (rest, readPatchIds str) copyRepo :: RepoPatch p => Repository p C(r u t) -> RemoteDarcs -> String -> IO () copyRepo repo@(Repo outr _ _ _) remote inr = do createDirectoryIfMissing False (outr++"/"++darcsdir++"/inventories") copyFileOrUrl remote (inr darcsdir "hashed_inventory") (outr darcsdir "hashed_inventory") Uncachable -- no need to copy anything but hashed_inventory! copySources repo inr debugMessage "Done copying hashed inventory." -- |'copySources' copies the prefs/sources file to the local repo, from the -- remote, having first filtered the local filesystem sources. copySources :: RepoPatch p => Repository p C(r u t) -> String -> IO () copySources repo@(Repo outr _ _ _) inr = do let repoCache = extractCache $ modifyCache repo dropNonRepos appendBinFile (outr++"/"++darcsdir++"/prefs/sources") (show $ repo2cache inr `unionCaches` repoCache ) where dropNonRepos (Ca cache) = Ca $ filter notRepo cache notRepo xs = case xs of Cache DarcsCache.Directory _ _ -> False Cache _ DarcsCache.Writable _ -> False _ -> True writeAndReadPatch :: RepoPatch p => Cache -> Compression -> PatchInfoAnd p C(x y) -> IO (PatchInfoAnd p C(x y)) writeAndReadPatch c compr p = do (i,h) <- writePatchIfNecessary c compr p unsafeInterleaveIO $ readp h i where parse i h = do debugMessage ("Rereading patch file: "++ show (humanFriendly i)) (fn,ps) <- fetchFileUsingCache c HashedPatchesDir h case readPatch ps of Just x -> return x Nothing -> fail $ unlines ["Couldn't parse patch file "++fn, "which is", renderString $ humanFriendly i] readp h i = do Sealed x <- createHashed h (parse i) return $ patchInfoAndPatch i $ unsafeCoerceP x writeTentativeInventory :: RepoPatch p => Cache -> Compression -> PatchSet p C(Origin x) -> IO () writeTentativeInventory cache compr = writeEitherInventory cache compr "tentative_hashed_inventory" writeEitherInventory :: RepoPatch p => Cache -> Compression -> String -> PatchSet p C(Origin x) -> IO () writeEitherInventory cache compr iname x = do debugMessage "in writeEitherInventory..." createDirectoryIfMissing False $ "_darcs/inventories" let k = "Writing inventory" beginTedious k hsh <- writeInventoryPrivate cache k compr $ slightlyOptimizePatchset x endTedious k debugMessage "still in writeEitherInventory..." case hsh of Nothing -> writeBinFile ("_darcs" iname) "" Just h -> fmap snd (fetchFileUsingCache cache HashedInventoriesDir h) >>= writeAtomicFilePS ("_darcs" iname) writeInventoryPrivate :: RepoPatch p => Cache -> String -> Compression -> PatchSet p C(Origin x) -> IO (Maybe String) writeInventoryPrivate _ _ _ (PatchSet NilRL NilRL) = return Nothing writeInventoryPrivate cache _ compr (PatchSet x NilRL) = do inventory <- sequence $ mapRL (writePatchIfNecessary cache compr) x let inventorylist = hcat (map pihash $ reverse inventory) hash <- writeHashFile cache compr HashedInventoriesDir inventorylist return $ Just hash writeInventoryPrivate cache k compr (PatchSet x xs@(Tagged t _ _ :<: _)) = do resthash <- write_ts xs finishedOneIO k $ maybe "" id resthash inventory <- sequence $ mapRL (writePatchIfNecessary cache compr) (x+<+t:<:NilRL) let inventorylist = hcat (map pihash $ reverse inventory) inventorycontents = case resthash of Just h -> text ("Starting with inventory:\n"++h) $$ inventorylist Nothing -> inventorylist hash <- writeHashFile cache compr HashedInventoriesDir inventorycontents return $ Just hash where write_ts :: RepoPatch p => RL (Tagged p) C(Origin x) -> IO (Maybe String) write_ts (Tagged _ (Just h) _ :<: _) = return (Just h) -- already written! write_ts (Tagged _ Nothing pps :<: tts) = writeInventoryPrivate cache k compr $ PatchSet pps tts write_ts NilRL = return Nothing writePatchIfNecessary :: RepoPatch p => Cache -> Compression -> PatchInfoAnd p C(x y) -> IO (PatchInfo, String) writePatchIfNecessary c compr hp = seq infohp $ case extractHash hp of Right h -> return (infohp, h) Left p -> (\h -> (infohp, h)) `fmap` writeHashFile c compr HashedPatchesDir (showPatch p) where infohp = info hp pihash :: (PatchInfo,String) -> Doc pihash (pinf,hash) = showPatchInfo pinf $$ text ("hash: " ++ hash ++ "\n") readInventoryPrivate :: Cache -> String -> String -> IO (Maybe String, [(PatchInfo, String)]) readInventoryPrivate _ d iname = do i <- skipPristine `fmap` gzFetchFilePS (d iname) Uncachable (rest,str) <- case BC.break ((==)'\n') i of (swt,pistr) | swt == BC.pack "Starting with inventory:" -> case BC.break ((==)'\n') $ B.tail pistr of (h,thisinv) | okayHash hash -> return (Just hash, thisinv) where hash = BC.unpack h _ -> fail $ "Bad hash in " ++ toPath d ++ "/_darcs/" ++ iname _ -> return (Nothing, i) return (rest, readPatchIds str) listInventories :: IO [String] listInventories = do x <- fst <$> readInventoryPrivate (Ca []) darcsdir "hashed_inventory" maybe (return []) f x where f i = do x <- fst <$> readInventoryPrivate (Ca []) (darcsdir "inventories") i (i :) <$> maybe (return []) f x -- | 'readPatchIds inventory' parses the content of a hashed_inventory file -- after the "pristine:" and "Starting with inventory:" header lines have -- been removed. The second value in the resulting tuples is the file hash -- of the associated patch (the "hash:" line). readPatchIds :: B.ByteString -> [(PatchInfo, String)] readPatchIds inv | B.null inv = [] readPatchIds inv = case parseStrictly readPatchInfo inv of Nothing -> [] Just (pinfo,r) -> case readHash r of Nothing -> [] Just (h,r') -> (pinfo,h) : readPatchIds r' readHash :: B.ByteString -> Maybe (String, B.ByteString) readHash s = let s' = dropSpace s (l,r) = BC.break ((==)'\n') s' (kw,h) = BC.break ((==)' ') l in if kw /= BC.pack "hash:" || B.length h <= 1 then Nothing else Just (BC.unpack $ B.tail h,r) applyPristine :: (ApplyState q ~ Tree, Patchy q) => String -> String -> q C(x y) -> IO () applyPristine d iname p = do i <- gzReadFilePS (d++"/"++iname) h <- applyHashed (inv2pris i) p writeDocBinFile (d++"/"++iname) $ pris2inv h i applyToTentativePristine :: (ApplyState q ~ Tree, Patchy q) => q C(x y) -> IO () applyToTentativePristine p = applyPristine "." (darcsdir++"/tentative_pristine") p copyPristine :: Cache -> Compression -> String -> String -> IO () copyPristine c compr d iname = do i <- fetchFilePS (d++"/"++iname) Uncachable debugMessage $ "Copying hashed pristine tree: "++inv2pris i let k = "Copying pristine" beginTedious k copyHashed k c compr $ inv2pris i endTedious k copyPartialsPristine :: FilePathLike fp => Cache -> Compression -> String -> String -> [fp] -> IO () copyPartialsPristine c compr d iname fps = do i <- fetchFilePS (d++"/"++iname) Uncachable copyPartialsHashed c compr (inv2pris i) fps inv2pris :: B.ByteString -> String inv2pris inv | B.take pristineNameLength inv == pristineName = case takeHash $ B.drop pristineNameLength inv of Just (h,_) -> h Nothing -> error "Bad hash in inventory!" | otherwise = sha256sum B.empty pris2inv :: String -> B.ByteString -> Doc pris2inv h inv = invisiblePS pristineName <> text h $$ invisiblePS (skipPristine inv) pristineName :: B.ByteString pristineName = BC.pack "pristine:" skipPristine :: B.ByteString -> B.ByteString skipPristine ps | B.take pristineNameLength ps == pristineName = B.drop 1 $ BC.dropWhile (/= '\n') $ B.drop pristineNameLength ps | otherwise = ps pristineNameLength :: Int pristineNameLength = B.length pristineName darcs-2.8.4/src/Darcs/Repository/Internal.hs0000644001765600176560000013132212104371431020255 0ustar ganeshganesh-- Copyright (C) 2002-2004,2007-2008 David Roundy -- Copyright (C) 2005 Juliusz Chroboczek -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP, ScopedTypeVariables, Rank2Types, RankNTypes, PatternGuards #-} #include "gadts.h" module Darcs.Repository.Internal ( Repository(..), RepoType(..), RIO(unsafeUnRIO), RepoJob(..), maybeIdentifyRepository, identifyDarcsRepository, identifyRepositoryFor, IdentifyRepo(..), findRepository, amInRepository, amNotInRepository, amInHashedRepository, revertRepositoryChanges, announceMergeConflicts, setTentativePending, checkUnrecordedConflicts, withRecorded, readRepo, readTentativeRepo, readRepoUsingSpecificInventory, prefsUrl, makePatchLazy, withRepoLock, withRepoReadLock, withRepository, withRepositoryDirectory, withGutsOf, tentativelyAddPatch, tentativelyRemovePatches, tentativelyAddToPending, tentativelyAddPatch_, tentativelyReplacePatches, finalizeRepositoryChanges, unrevertUrl, applyToWorking, patchSetToPatches, createPristineDirectoryTree, createPartialsPristineDirectoryTree, optimizeInventory, cleanRepository, setScriptsExecutable, setScriptsExecutablePatches, getRepository, rIO, testTentative, testRecorded, UpdatePristine(..), MakeChanges(..), applyToTentativePristine, makeNewPending, seekRepo ) where import Prelude hiding ( catch ) import Printer ( putDocLn, (<+>), text, ($$), redText, putDocLnWith, (<>), ($$)) import Darcs.ColorPrinter (fancyPrinters) import Darcs.Repository.Prefs ( getPrefval ) import Darcs.Repository.State ( readRecorded, readWorking ) import Darcs.Repository.LowLevel ( readPending, readTentativePending , writeTentativePending , readNewPending, writeNewPending , pendingName ) import System.Exit ( ExitCode(..), exitWith ) import System.Cmd ( system ) import Darcs.IO ( runTolerantly, runSilently ) import Darcs.SignalHandler ( withSignalsBlocked ) import Darcs.Repository.Format ( RepoFormat, RepoProperty( Darcs2 , HashedInventory, NoWorkingDir ), tryIdentifyRepoFormat, formatHas, writeProblem, readProblem, readfromAndWritetoProblem ) import System.Directory ( doesDirectoryExist, setCurrentDirectory, createDirectoryIfMissing, doesFileExist ) import Control.Monad ( when, unless, filterM ) import Control.Applicative ( (<$>) ) import Control.Exception ( catch, IOException ) import Workaround ( getCurrentDirectory, renameFile, setExecutable ) import qualified Data.ByteString as B ( readFile, isPrefixOf ) import qualified Data.ByteString.Char8 as BC (pack) import Darcs.Patch ( Effect, primIsHunk, primIsBinary, description, tryToShrink, commuteFLorComplain, commute, fromPrim ) import Darcs.Patch.Dummy ( DummyPatch ) import Darcs.Patch.Apply ( ApplyState ) import Darcs.Patch.V1 ( Patch ) import Darcs.Patch.V2 ( RealPatch ) import Darcs.Patch.Prim.V1 ( Prim ) import Darcs.Patch.Inspect ( PatchInspect ) import Darcs.Patch.Prim ( PrimPatchBase, PrimOf, tryShrinkingInverse, PrimPatch ) import Darcs.Patch.Bundle ( scanBundle, makeBundleN ) import Darcs.Patch.PatchInfoAnd ( PatchInfoAnd, hopefully ) import qualified Darcs.Repository.HashedRepo as HashedRepo ( revertTentativeChanges, finalizeTentativeChanges, removeFromTentativeInventory, copyPristine, copyPartialsPristine, applyToTentativePristine, writeTentativeInventory, writeAndReadPatch, addToTentativeInventory, readRepo, readTentativeRepo, readRepoUsingSpecificInventory, cleanPristine ) import qualified Darcs.Repository.Old as Old ( readOldRepo, revertTentativeChanges, oldRepoFailMsg ) import Darcs.Flags ( DarcsFlag(Verbose, Quiet, MarkConflicts, AllowConflicts, NoUpdateWorking, WorkRepoUrl, WorkRepoDir, UMask, Test, LeaveTestDir, SetScriptsExecutable, DryRun ), wantExternalMerge, compression, Compression ) import Darcs.Witnesses.Eq ( EqCheck(..) ) import Darcs.Witnesses.Unsafe ( unsafeCoerceP, unsafeCoercePStart ) import Darcs.Witnesses.Ordered ( FL(..), RL(..), (:\/:)(..), (:/\:)(..), (:>)(..), (+>+), lengthFL, allFL, filterFLFL, reverseFL, mapFL_FL, concatFL ) import Darcs.Patch ( RepoPatch, Patchy, merge, listConflictedFiles, listTouchedFiles, Named, commuteRL, fromPrims, readPatch, effect, invert, primIsAddfile, primIsAdddir, primIsSetpref, apply, applyToTree, ) import Darcs.Patch.Permutations ( commuteWhatWeCanFL, removeFL ) import Darcs.Patch.Set ( PatchSet(..), SealedPatchSet, newset2FL ) #ifdef GADT_WITNESSES import Darcs.Patch.Set ( Origin ) #endif import Darcs.Patch.Depends ( deepOptimizePatchset, removeFromPatchSet, mergeThem ) import Darcs.RepoPath ( FilePathLike, AbsolutePath, toFilePath, ioAbsoluteOrRemote, toPath ) import Darcs.Utils ( promptYorn, catchall, withCurrentDirectory, withUMask, nubsort ) import Progress ( debugMessage ) import Darcs.ProgressPatches (progressFL) import Darcs.URL ( isFile ) import Darcs.Repository.Prefs ( getCaches ) import Darcs.Lock ( withLock, writeDocBinFile, removeFileMayNotExist, withTempDir, withPermDir ) import Darcs.Witnesses.Sealed ( Sealed(Sealed), seal, FlippedSeal(FlippedSeal), flipSeal, mapSeal ) import Darcs.Repository.InternalTypes( Repository(..), RepoType(..), Pristine(..) ) import Darcs.Global ( darcsdir ) import System.Mem( performGC ) import qualified Storage.Hashed.Tree as Tree import Storage.Hashed.Tree ( Tree ) import Storage.Hashed.AnchoredPath( anchorPath ) #include "impossible.h" -- | Repository IO monad. This monad-like datatype is responsible for -- sequencing IO actions that modify the tentative recorded state of -- the repository. newtype RIO p C(r u t t1) a = RIO { unsafeUnRIO :: Repository p C(r u t) -> IO a -- ^ converts @RIO a@ to @IO a@. } -- | This is just like @>>=@ from the Monad class except that it -- respects type witness safe repository transformations. Even so, it -- only tracks modifications to the tentative recorded state. (>>>=) :: RIO p C(r u t t1) a -> (a -> RIO p C(r u t1 t2) b) -> RIO p C(r u t t2) b m >>>= k = RIO $ \ (Repo x y z w) -> do a <- unsafeUnRIO m (Repo x y z w) unsafeUnRIO (k a) (Repo x y z w) -- | This corresponds to @>>@ from the Monad class. (>>>) :: RIO p C(r u t t1) a -> RIO p C(r u t1 t2) b -> RIO p C(r u t t2) b a >>> b = a >>>= (const b) -- | This corresponds to @return@ from the Monad class. returnR :: a -> RIO p C(r u t t) a returnR = rIO . return -- | This the @RIO@ equivalent of @liftIO@. rIO :: IO a -> RIO p C(r u t t) a rIO = RIO . const instance Functor (RIO p C(r u t t)) where fmap f m = RIO $ \r -> fmap f (unsafeUnRIO m r) -- | We have an instance of Monad so that IO actions that do not -- change the tentative recorded state are convenient in the IO monad. instance Monad (RIO p C(r u t t)) where (>>=) = (>>>=) (>>) = (>>>) return = returnR fail = rIO . fail -- | Similar to the @ask@ function of the MonadReader class. -- This allows actions in the RIO monad to get the current -- repository. -- FIXME: Don't export this. If we don't export this -- it makes it harder for arbitrary IO actions to access -- the repository and hence our code is easier to audit. getRepository :: RIO p C(r u t t) (Repository p C(r u t)) getRepository = RIO return -- | The status of a given directory: is it a darcs repository? data IdentifyRepo p C(r u t) = BadRepository String -- ^ looks like a repository with some error | NonRepository String -- ^ safest guess | GoodRepository (Repository p C(r u t)) -- | Tries to identify the repository in a given directory maybeIdentifyRepository :: [DarcsFlag] -> String -> IO (IdentifyRepo p C(r u t)) maybeIdentifyRepository opts "." = do darcs <- doesDirectoryExist darcsdir rf_or_e <- tryIdentifyRepoFormat "." here <- toPath `fmap` ioAbsoluteOrRemote "." case rf_or_e of Left err -> return $ NonRepository err Right rf -> case readProblem rf of Just err -> return $ BadRepository err Nothing -> if darcs then do pris <- identifyPristine cs <- getCaches opts here return $ GoodRepository $ Repo here opts rf (DarcsRepository pris cs) else return (NonRepository "Not a repository") maybeIdentifyRepository opts url' = do url <- toPath `fmap` ioAbsoluteOrRemote url' rf_or_e <- tryIdentifyRepoFormat url case rf_or_e of Left e -> return $ NonRepository e Right rf -> case readProblem rf of Just err -> return $ BadRepository err Nothing -> do cs <- getCaches opts url return $ GoodRepository $ Repo url opts rf (DarcsRepository NoPristine cs) identifyPristine :: IO Pristine identifyPristine = do pristine <- doesDirectoryExist $ darcsdir++"/pristine" current <- doesDirectoryExist $ darcsdir++"/current" hashinv <- doesFileExist $ darcsdir++"/hashed_inventory" case (pristine || current, hashinv) of (False, False) -> return NoPristine (True, False) -> return PlainPristine (False, True ) -> return HashedPristine _ -> fail "Multiple pristine trees." -- | identifyDarcsRepository identifies the repo at 'url'. Warning: -- you have to know what kind of patches are found in that repo. identifyDarcsRepository :: forall p C(r u t). [DarcsFlag] -> String -> IO (Repository p C(r u t)) identifyDarcsRepository opts url = do er <- maybeIdentifyRepository opts url case er of BadRepository s -> fail s NonRepository s -> fail s GoodRepository r -> return r -- | @identifyRepositoryFor repo url@ identifies (and returns) the repo at 'url', -- but fails if it is not compatible for reading from and writing to. identifyRepositoryFor :: forall p C(r u t). RepoPatch p => Repository p C(r u t) -> String -> IO (Repository p C(r u t)) identifyRepositoryFor (Repo _ opts rf _) url = do Repo absurl _ rf_ t <- identifyDarcsRepository opts url let t' = case t of DarcsRepository x c -> DarcsRepository x c case readfromAndWritetoProblem rf_ rf of Just e -> fail $ "Incompatibility with repository " ++ url ++ ":\n" ++ e Nothing -> return $ Repo absurl opts rf_ t' amInRepository :: [DarcsFlag] -> IO (Either String ()) amInRepository (WorkRepoDir d:_) = do setCurrentDirectory d `catchall` (fail $ "can't set directory to "++d) status <- maybeIdentifyRepository [] "." case status of GoodRepository _ -> return (Right ()) BadRepository e -> return (Left $ "While " ++ d ++ " looks like a repository directory, we have a problem with it:\n" ++ e) NonRepository _ -> return (Left "You need to be in a repository directory to run this command.") amInRepository (_:fs) = amInRepository fs amInRepository [] = do maybe (Left $ "You need to be in a repository directory " ++ "to run this command.") id <$> seekRepo amInHashedRepository :: [DarcsFlag] -> IO (Either String ()) amInHashedRepository flags = do inrepo <- amInRepository flags case inrepo of Right _ -> do pristine <- identifyPristine case pristine of HashedPristine -> return (Right ()) _ -> return (Left Old.oldRepoFailMsg) left -> return left -- | hunt upwards for the darcs repository -- This keeps changing up one parent directory, testing at each -- step if the current directory is a repository or not. $ -- The result is: -- Nothing, if no repository found -- Just (Left errorMessage), if bad repository found -- Just (Right ()), if good repository found. -- WARNING this changes the current directory for good if matchFn succeeds seekRepo :: IO (Maybe (Either String ())) seekRepo = getCurrentDirectory >>= helper where helper startpwd = do status <- maybeIdentifyRepository [] "." case status of GoodRepository _ -> return . Just $ Right () BadRepository e -> return . Just $ Left e NonRepository _ -> do cd <- toFilePath `fmap` getCurrentDirectory setCurrentDirectory ".." cd' <- toFilePath `fmap` getCurrentDirectory if cd' /= cd then helper startpwd else do setCurrentDirectory startpwd return Nothing -- The performGC in this function is a workaround for a library/GHC bug, -- http://hackage.haskell.org/trac/ghc/ticket/2924 -- (doesn't seem to be a -- problem on fast machines, but virtual ones trip this from time to time) amNotInRepository :: [DarcsFlag] -> IO (Either String ()) amNotInRepository (WorkRepoDir d:_) = do createDirectoryIfMissing False d `catchall` (performGC >> createDirectoryIfMissing False d) -- note that the above could always fail setCurrentDirectory d amNotInRepository [] amNotInRepository (_:f) = amNotInRepository f amNotInRepository [] = do status <- maybeIdentifyRepository [] "." case status of GoodRepository _ -> return (Left $ "You may not run this command in a repository.") BadRepository e -> return (Left $ "You may not run this command in a repository.\nBy the way, we have a problem with it:\n" ++ e) NonRepository _ -> return (Right ()) findRepository :: [DarcsFlag] -> IO (Either String ()) findRepository (WorkRepoUrl d:_) | isFile d = do setCurrentDirectory d `catchall` (fail $ "can't set directory to "++d) findRepository [] findRepository (WorkRepoDir d:_) = do setCurrentDirectory d `catchall` (fail $ "can't set directory to "++d) findRepository [] findRepository (_:fs) = findRepository fs findRepository [] = maybe (Right ()) id <$> seekRepo -- TODO: see also Repository.State.readPendingLL ... to be removed after GHC 7.2 readNewPendingLL :: (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u t) -> IO (Sealed ((FL p) C(t))) readNewPendingLL repo = mapSeal (mapFL_FL fromPrim) `fmap` readNewPending repo makeNewPending :: forall p C(r u t y). (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u t) -> FL (PrimOf p) C(t y) -> IO () makeNewPending (Repo _ opts _ _) _ | NoUpdateWorking `elem` opts = return () makeNewPending repo@(Repo r _ _ tp) origp = withCurrentDirectory r $ do let newname = pendingName tp ++ ".new" debugMessage $ "Writing new pending: " ++ newname Sealed sfp <- return $ siftForPending origp writeNewPending repo sfp cur <- readRecorded repo Sealed p <- readNewPendingLL repo -- :: IO (Sealed (FL (PrimOf p) C(t))) -- Warning: A do-notation statement discarded a result of type Tree.Tree IO. _ <- catch (applyToTree p cur) $ \(err :: IOException) -> do let buggyname = pendingName tp ++ "_buggy" renameFile newname buggyname bugDoc $ text ("There was an attempt to write an invalid pending! " ++ show err) $$ text "If possible, please send the contents of" <+> text buggyname $$ text "along with a bug report." renameFile newname (pendingName tp) debugMessage $ "Finished writing new pending: " ++ newname siftForPending :: forall prim C(x y) . PrimPatch prim => FL prim C(x y) -> Sealed (FL prim C(x)) siftForPending simple_ps = let oldps = maybe simple_ps id $ tryShrinkingInverse $ crudeSift simple_ps in if allFL (\p -> primIsAddfile p || primIsAdddir p) $ oldps then seal oldps else fromJust $ do Sealed x <- return $ sfp NilFL $ reverseFL oldps return (case tryToShrink x of ps | lengthFL ps < lengthFL oldps -> siftForPending ps | otherwise -> seal ps) where sfp :: FL prim C(a b) -> RL prim C(c a) -> Sealed (FL prim C(c)) sfp sofar NilRL = seal sofar sfp sofar (p:<:ps) | primIsHunk p || primIsBinary p = case commuteFLorComplain (p :> sofar) of Right (sofar' :> _) -> sfp sofar' ps Left _ -> sfp (p:>:sofar) ps sfp sofar (p:<:ps) = sfp (p:>:sofar) ps -- @todo: we should not have to open the result of HashedRepo and -- seal it. Instead, update this function to work with type witnesses -- by fixing DarcsRepo to match HashedRepo in the handling of -- Repository state. readRepo :: (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u t) -> IO (PatchSet p C(Origin r)) readRepo repo@(Repo r _ rf _) | formatHas HashedInventory rf = HashedRepo.readRepo repo r | otherwise = do Sealed ps <- Old.readOldRepo r return $ unsafeCoerceP ps readTentativeRepo :: (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u t) -> IO (PatchSet p C(Origin t)) readTentativeRepo repo@(Repo r _ rf _) | formatHas HashedInventory rf = HashedRepo.readTentativeRepo repo r | otherwise = fail Old.oldRepoFailMsg readRepoUsingSpecificInventory :: (RepoPatch p, ApplyState p ~ Tree) => String -> Repository p C(r u t) -> IO (PatchSet p C(Origin t)) readRepoUsingSpecificInventory invPath repo@(Repo r _ rf _) | formatHas HashedInventory rf = HashedRepo.readRepoUsingSpecificInventory invPath repo r | otherwise = fail Old.oldRepoFailMsg makePatchLazy :: RepoPatch p => Repository p C(r u t) -> PatchInfoAnd p C(x y) -> IO (PatchInfoAnd p C(x y)) makePatchLazy (Repo r opts rf (DarcsRepository _ c)) p | formatHas HashedInventory rf = withCurrentDirectory r $ HashedRepo.writeAndReadPatch c (compression opts) p | otherwise = fail Old.oldRepoFailMsg prefsUrl :: Repository p C(r u t) -> String prefsUrl (Repo r _ _ (DarcsRepository _ _)) = r ++ "/"++darcsdir++"/prefs" unrevertUrl :: Repository p C(r u t) -> String unrevertUrl (Repo r _ _ (DarcsRepository _ _)) = r ++ "/"++darcsdir++"/patches/unrevert" applyToWorking :: (ApplyState (PrimOf p) ~ Tree, RepoPatch p) => Repository p C(r u t) -> [DarcsFlag] -> FL (PrimOf p) C(u y) -> IO (Repository p C(r y t)) applyToWorking (Repo r ropts rf (DarcsRepository t c)) opts patch = do unless (formatHas NoWorkingDir rf) $ withCurrentDirectory r $ if Quiet `elem` opts then runSilently $ apply patch else runTolerantly $ apply patch return (Repo r ropts rf (DarcsRepository t c)) handlePendForAdd :: forall p C(r u t x y). (RepoPatch p) => Repository p C(r u t) -> PatchInfoAnd p C(x y) -> IO () handlePendForAdd (Repo _ opts _ _) _ | NoUpdateWorking `elem` opts = return () handlePendForAdd repo p = do Sealed pend <- readTentativePending repo let effectp = if allFL isSimple pend then crudeSift $ effect p else effect p Sealed newpend <- return $ rmpend (progressFL "Removing from pending:" effectp) (unsafeCoercePStart pend) writeTentativePending repo (unsafeCoercePStart newpend) where rmpend :: FL (PrimOf p) C(a b) -> FL (PrimOf p) C(a c) -> Sealed (FL (PrimOf p) C(b)) rmpend NilFL x = Sealed x rmpend _ NilFL = Sealed NilFL rmpend (x:>:xs) xys | Just ys <- removeFL x xys = rmpend xs ys rmpend (x:>:xs) ys = case commuteWhatWeCanFL (x:>xs) of a:>x':>b -> case rmpend a ys of Sealed ys' -> case commute (invert (x':>:b) :> ys') of Just (ys'' :> _) -> seal ys'' Nothing -> seal $ invert (x':>:b)+>+ys' -- DJR: I don't think this -- last case should be -- reached, but it also -- shouldn't lead to -- corruption. isSimple :: PrimPatch prim => prim C(x y) -> Bool isSimple x = primIsHunk x || primIsBinary x || primIsSetpref x crudeSift :: forall prim C(x y) . PrimPatch prim => FL prim C(x y) -> FL prim C(x y) crudeSift xs = if allFL isSimple xs then filterFLFL ishunkbinary xs else xs where ishunkbinary :: prim C(a b) -> EqCheck C(a b) ishunkbinary x | primIsHunk x || primIsBinary x = unsafeCoerceP IsEq | otherwise = NotEq data HashedVsOld a = HvsO { old, hashed :: a } decideHashedOrNormal :: Monad m => RepoFormat -> HashedVsOld (m a) -> m a decideHashedOrNormal rf (HvsO { hashed = h, old = o }) | formatHas HashedInventory rf = h | otherwise = o data MakeChanges = MakeChanges | DontMakeChanges deriving ( Eq ) announceMergeConflicts :: (PrimPatch p, PatchInspect p) => String -> [DarcsFlag] -> FL p C(x y) -> IO Bool announceMergeConflicts cmd opts resolved_pw = case nubsort $ listTouchedFiles resolved_pw of [] -> return False cfs -> if MarkConflicts `elem` opts || AllowConflicts `elem` opts || wantExternalMerge opts /= Nothing then do putDocLnWith fancyPrinters $ redText "We have conflicts in the following files:" $$ text (unwords cfs) return True else do putDocLnWith fancyPrinters $ redText "There are conflicts in the following files:" $$ text (unwords cfs) fail $ "Refusing to "++cmd++" patches leading to conflicts.\n"++ "If you would rather apply the patch and mark the conflicts,\n"++ "use the --mark-conflicts or --allow-conflicts options to "++cmd++"\n"++ "These can set as defaults by adding\n"++ " "++cmd++" mark-conflicts\n"++ "to "++darcsdir++"/prefs/defaults in the target repo. " checkUnrecordedConflicts :: forall p C(t y). RepoPatch p => [DarcsFlag] -> FL (Named p) C(t y) -> IO Bool checkUnrecordedConflicts opts _ | NoUpdateWorking `elem` opts = return False checkUnrecordedConflicts opts pc = do repository <- identifyDarcsRepository opts "." cuc repository where cuc :: Repository p C(r u t) -> IO Bool cuc r = do Sealed (mpend :: FL (PrimOf p) C(t x)) <- readPending r :: IO (Sealed (FL (PrimOf p) C(t))) case mpend of NilFL -> return False pend -> case merge (fromPrims_ pend :\/: fromPrims_ (concatFL $ mapFL_FL effect pc)) of _ :/\: pend' -> case listConflictedFiles pend' of [] -> return False fs -> do putStrLn ("You have conflicting local changes to:\n" ++ unwords fs) confirmed <- promptYorn "Proceed?" unless confirmed $ do putStrLn "Cancelled." exitWith ExitSuccess return True fromPrims_ :: FL (PrimOf p) C(a b) -> FL p C(a b) fromPrims_ = fromPrims tentativelyAddPatch :: (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u t) -> Compression -> PatchInfoAnd p C(t y) -> IO (Repository p C(r u y)) tentativelyAddPatch = tentativelyAddPatch_ UpdatePristine data UpdatePristine = UpdatePristine | DontUpdatePristine deriving Eq -- TODO re-add a safety catch for --dry-run? Maybe using a global, like dryRun -- :: Bool, with dryRun = unsafePerformIO $ readIORef ... tentativelyAddPatch_ :: (RepoPatch p, ApplyState p ~ Tree) => UpdatePristine -> Repository p C(r u t) -> Compression -> PatchInfoAnd p C(t y) -> IO (Repository p C(r u y)) tentativelyAddPatch_ up r@(Repo dir ropts rf (DarcsRepository t c)) compr p = withCurrentDirectory dir $ -- Warning: A do-notation statement discarded a result of type FilePath. do _ <- decideHashedOrNormal rf $ HvsO { hashed = HashedRepo.addToTentativeInventory c compr p, old = fail Old.oldRepoFailMsg} when (up == UpdatePristine) $ do debugMessage "Applying to pristine cache..." applyToTentativePristine r p debugMessage "Updating pending..." handlePendForAdd r p return (Repo dir ropts rf (DarcsRepository t c)) applyToTentativePristine :: (ApplyState q ~ Tree, Effect q, Patchy q, PrimPatchBase q) => Repository p C(r u t) -> q C(t y) -> IO () applyToTentativePristine (Repo dir opts rf (DarcsRepository _ _)) p = withCurrentDirectory dir $ do when (Verbose `elem` opts) $ putDocLn $ text "Applying to pristine..." <+> description p decideHashedOrNormal rf $ HvsO {hashed = HashedRepo.applyToTentativePristine p, old = fail Old.oldRepoFailMsg} -- | This fuction is unsafe because it accepts a patch that works on the tentative -- pending and we don't currently track the state of the tentative pending. tentativelyAddToPending :: forall p C(r u t x y). RepoPatch p => Repository p C(r u t) -> [DarcsFlag] -> FL (PrimOf p) C(x y) -> IO () tentativelyAddToPending (Repo _ opts _ _) _ _ | NoUpdateWorking `elem` opts = return () | DryRun `elem` opts = bug "tentativelyAddToPending called when --dry-run is specified" tentativelyAddToPending repo@(Repo dir _ _ _) _ patch = withCurrentDirectory dir $ do Sealed pend <- readTentativePending repo FlippedSeal newpend_ <- return $ newpend (unsafeCoerceP pend :: FL (PrimOf p) C(a x)) patch writeTentativePending repo (unsafeCoercePStart newpend_) where newpend :: FL prim C(a b) -> FL prim C(b c) -> FlippedSeal (FL prim) C(c) newpend NilFL patch_ = flipSeal patch_ newpend p patch_ = flipSeal $ p +>+ patch_ -- | setTentativePending is basically unsafe. It overwrites the pending state with a new one, not related to -- the repository state. setTentativePending :: forall p C(r u t x y). RepoPatch p => Repository p C(r u t) -> FL (PrimOf p) C(x y) -> IO () setTentativePending (Repo _ opts _ _) _ | NoUpdateWorking `elem` opts = return () setTentativePending repo@(Repo dir _ _ _) patch = do Sealed prims <- return $ siftForPending patch withCurrentDirectory dir $ writeTentativePending repo (unsafeCoercePStart prims) -- | prepend is basically unsafe. It overwrites the pending state -- with a new one, not related to the repository state. prepend :: forall p C(r u t x y). RepoPatch p => Repository p C(r u t) -> FL (PrimOf p) C(x y) -> IO () prepend (Repo _ opts _ _) _ | NoUpdateWorking `elem` opts = return () prepend repo@(Repo _ _ _ _) patch = do Sealed pend <- readTentativePending repo Sealed newpend_ <- return $ newpend (unsafeCoerceP pend) patch writeTentativePending repo (unsafeCoercePStart $ crudeSift newpend_) where newpend :: FL prim C(b c) -> FL prim C(a b) -> Sealed (FL prim C(a)) newpend NilFL patch_ = seal patch_ newpend p patch_ = seal $ patch_ +>+ p tentativelyRemovePatches :: (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u t) -> Compression -> FL (PatchInfoAnd p) C(x t) -> IO (Repository p C(r u x)) tentativelyRemovePatches = tentativelyRemovePatches_ UpdatePristine tentativelyRemovePatches_ :: forall p C(r u t x). (RepoPatch p, ApplyState p ~ Tree) => UpdatePristine -> Repository p C(r u t) -> Compression -> FL (PatchInfoAnd p) C(x t) -> IO (Repository p C(r u x)) tentativelyRemovePatches_ up repository@(Repo dir ropts rf (DarcsRepository t c)) compr ps = withCurrentDirectory dir $ do when (up == UpdatePristine) $ do debugMessage "Adding changes to pending..." prepend repository $ effect ps removeFromUnrevertContext repository ps debugMessage "Removing changes from tentative inventory..." if formatHas HashedInventory rf then do HashedRepo.removeFromTentativeInventory repository compr ps when (up == UpdatePristine) $ HashedRepo.applyToTentativePristine $ progressFL "Applying inverse to pristine" $ invert ps else fail Old.oldRepoFailMsg return (Repo dir ropts rf (DarcsRepository t c)) tentativelyReplacePatches :: forall p C(r u t x). (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u t) -> Compression -> FL (PatchInfoAnd p) C(x t) -> IO (Repository p C(r u t)) tentativelyReplacePatches repository compr ps = do repository' <- tentativelyRemovePatches_ DontUpdatePristine repository compr ps mapAdd repository' ps where mapAdd :: Repository p C(m l i) -> FL (PatchInfoAnd p) C(i j) -> IO (Repository p C(m l j)) mapAdd r NilFL = return r mapAdd r (a:>:as) = do r' <- tentativelyAddPatch_ DontUpdatePristine r compr a mapAdd r' as finalizePending :: (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u t) -> IO () finalizePending (Repo dir opts _ rt) | NoUpdateWorking `elem` opts = withCurrentDirectory dir $ removeFileMayNotExist $ (pendingName rt) finalizePending repository@(Repo dir _ _ _) = do withCurrentDirectory dir $ do Sealed tpend <- readTentativePending repository Sealed new_pending <- return $ siftForPending tpend makeNewPending repository new_pending finalizeRepositoryChanges :: (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u t) -> IO () finalizeRepositoryChanges (Repo _ opts _ _) | DryRun `elem` opts = bug "finalizeRepositoryChanges called when --dry-run specified" finalizeRepositoryChanges repository@(Repo dir opts rf _) | formatHas HashedInventory rf = withCurrentDirectory dir $ do debugMessage "Considering whether to test..." _ <- testTentative repository debugMessage "Finalizing changes..." withSignalsBlocked $ do HashedRepo.finalizeTentativeChanges repository (compression opts) finalizePending repository debugMessage "Done finalizing changes..." | otherwise = fail Old.oldRepoFailMsg testTentative :: (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u t) -> IO (ExitCode) testTentative = testAny withTentative testRecorded :: (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u t) -> IO (ExitCode) testRecorded = testAny withRecorded testAny :: RepoPatch p => (Repository p C(r u t) -> ((AbsolutePath -> IO (ExitCode)) -> IO (ExitCode)) -> ((AbsolutePath -> IO (ExitCode)) -> IO (ExitCode))) -> Repository p C(r u t) -> IO (ExitCode) testAny withD repository@(Repo dir opts _ _) = debugMessage "Considering whether to test..." >> if not $ Test `elem` opts then return ExitSuccess else withCurrentDirectory dir $ do let putInfo = if Quiet `elem` opts then const (return ()) else putStrLn debugMessage "About to run test if it exists." testline <- getPrefval "test" case testline of Nothing -> return ExitSuccess Just testcode -> withD repository (wd "testing") $ \_ -> do putInfo "Running test...\n" when (SetScriptsExecutable `elem` opts) setScriptsExecutable ec <- system testcode if ec == ExitSuccess then putInfo "Test ran successfully.\n" else putInfo "Test failed!\n" return ec where wd = if LeaveTestDir `elem` opts then withPermDir else withTempDir revertRepositoryChanges :: RepoPatch p => Repository p C(r u t) -> IO () revertRepositoryChanges (Repo _ opts _ _) | DryRun `elem` opts = bug "revertRepositoryChanges called when --dry-run is specified" revertRepositoryChanges r@(Repo dir opts rf dr@(DarcsRepository _ _)) = withCurrentDirectory dir $ do removeFileMayNotExist (pendingName dr ++ ".tentative") Sealed x <- readPending r setTentativePending r x when (NoUpdateWorking `elem` opts) $ removeFileMayNotExist $ pendingName dr decideHashedOrNormal rf $ HvsO { hashed = HashedRepo.revertTentativeChanges, old = Old.revertTentativeChanges } patchSetToPatches :: RepoPatch p => PatchSet p C(x y) -> FL (Named p) C(x y) patchSetToPatches patchSet = mapFL_FL hopefully $ newset2FL patchSet getUMask :: [DarcsFlag] -> Maybe String getUMask [] = Nothing getUMask ((UMask u):_) = Just u getUMask (_:l) = getUMask l withUMaskFromOpts :: [DarcsFlag] -> IO a -> IO a withUMaskFromOpts = maybe id withUMask . getUMask withGutsOf :: Repository p C(r u t) -> IO a -> IO a withGutsOf (Repo _ _ rf _) | formatHas HashedInventory rf = id | otherwise = withSignalsBlocked data RepoJob a -- = RepoJob (forall p C(r u) . RepoPatch p => Repository p C(r u r) -> IO a) -- TODO: Unbind Tree from RepoJob, possibly renaming existing RepoJob = RepoJob (forall p C(r u) . (RepoPatch p, ApplyState p ~ Tree, ApplyState (PrimOf p) ~ Tree) => Repository p C(r u r) -> IO a) | V1Job (forall C(r u) . Repository (Patch Prim) C(r u r) -> IO a) | V2Job (forall C(r u) . Repository (RealPatch Prim) C(r u r) -> IO a) | PrimV1Job (forall p C(r u) . (RepoPatch p, ApplyState p ~ Tree, PrimOf p ~ Prim) => Repository p C(r u r) -> IO a) onRepoJob :: RepoJob a -> (forall p C(r u) . RepoPatch p => (Repository p C(r u r) -> IO a) -> (Repository p C(r u r) -> IO a)) -> RepoJob a onRepoJob (RepoJob job) f = RepoJob (f job) -- onRepoJob (TreeJob job) f = TreeJob (f job) onRepoJob (V1Job job) f = V1Job (f job) onRepoJob (V2Job job) f = V2Job (f job) onRepoJob (PrimV1Job job) f = PrimV1Job (f job) withRepository :: [DarcsFlag] -> RepoJob a -> IO a withRepository opts1 = withRepositoryDirectory opts1 "." withRepositoryDirectory :: forall a. [DarcsFlag] -> String -> RepoJob a -> IO a withRepositoryDirectory opts1 url repojob = do Repo dir opts rf (DarcsRepository t c) <- identifyDarcsRepository opts1 url if formatHas Darcs2 rf then do debugMessage $ "Identified darcs-2 repo: " ++ dir let therepo = Repo dir opts rf (DarcsRepository t c) :: Repository (RealPatch Prim) C(r u r) case repojob of RepoJob job -> job therepo -- TreeJob job -> job therepo V2Job job -> job therepo PrimV1Job job -> job therepo V1Job _ -> fail "This repository contains darcs v1 patches, but the command requires darcs v2 patches." else do debugMessage $ "Identified darcs-1 repo: " ++ dir let therepo = Repo dir opts rf (DarcsRepository t c) :: Repository (Patch Prim) C(r u r) case repojob of RepoJob job -> job therepo -- TreeJob job -> job therepo V1Job job -> job therepo PrimV1Job job -> job therepo V2Job _ -> fail "This repository contains darcs v2 patches, but the command requires darcs v1 patches." withRepoLock :: [DarcsFlag] -> RepoJob a -> IO a withRepoLock opts repojob = withRepository opts $ onRepoJob repojob $ \job repository@(Repo _ _ rf _) -> do maybe (return ()) fail $ writeProblem rf let name = "./"++darcsdir++"/lock" withUMaskFromOpts opts $ if DryRun `elem` opts then job repository else withLock name (revertRepositoryChanges repository >> job repository) withRepoReadLock :: [DarcsFlag] -> RepoJob a -> IO a withRepoReadLock opts repojob = withRepository opts $ onRepoJob repojob $ \job repository@(Repo _ _ rf _) -> do maybe (return ()) fail $ writeProblem rf let name = "./"++darcsdir++"/lock" withUMaskFromOpts opts $ if formatHas HashedInventory rf || DryRun `elem` opts then job repository else withLock name (revertRepositoryChanges repository >> job repository) removeFromUnrevertContext :: forall p C(r u t x). (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u t) -> FL (PatchInfoAnd p) C(x t) -> IO () removeFromUnrevertContext repository ps = do Sealed bundle <- unrevert_patch_bundle `catchall` (return $ seal (PatchSet NilRL NilRL)) remove_from_unrevert_context_ bundle where unrevert_impossible = do confirmed <- promptYorn "This operation will make unrevert impossible!\nProceed?" if confirmed then removeFileMayNotExist (unrevertUrl repository) else fail "Cancelled." unrevert_patch_bundle :: IO (SealedPatchSet p C(Origin)) unrevert_patch_bundle = do pf <- B.readFile (unrevertUrl repository) case scanBundle pf of Right foo -> return foo Left err -> fail $ "Couldn't parse unrevert patch:\n" ++ err remove_from_unrevert_context_ :: PatchSet p C(Origin z) -> IO () remove_from_unrevert_context_ (PatchSet NilRL NilRL) = return () remove_from_unrevert_context_ bundle = do debugMessage "Adjusting the context of the unrevert changes..." debugMessage $ "Removing "++ show (lengthFL ps) ++ " patches in removeFromUnrevertContext!" ref <- readTentativeRepo repository let withSinglet :: Sealed (FL ppp C(xxx)) -> (FORALL(yyy) ppp C(xxx yyy) -> IO ()) -> IO () withSinglet (Sealed (x :>: NilFL)) j = j x withSinglet _ _ = return () withSinglet (mergeThem ref bundle) $ \h_us -> case commuteRL (reverseFL ps :> h_us) of Nothing -> unrevert_impossible Just (us' :> _) -> case removeFromPatchSet ps ref of Nothing -> unrevert_impossible Just common -> do debugMessage "Have now found the new context..." bundle' <- makeBundleN Nothing common (hopefully us':>:NilFL) writeDocBinFile (unrevertUrl repository) bundle' debugMessage "Done adjusting the context of the unrevert changes!" -- | Writes out a fresh copy of the inventory that minimizes the -- amount of inventory that need be downloaded when people pull from -- the repository. -- -- Specifically, it breaks up the inventory on the most recent tag. -- This speeds up most commands when run remotely, both because a -- smaller file needs to be transfered (only the most recent -- inventory). It also gives a guarantee that all the patches prior -- to a given tag are included in that tag, so less commutation and -- history traversal is needed. This latter issue can become very -- important in large repositories. optimizeInventory :: (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u t) -> IO () optimizeInventory repository@(Repo _ opts rf (DarcsRepository _ c)) = do ps <- readRepo repository decideHashedOrNormal rf $ HvsO { hashed = do revertRepositoryChanges repository HashedRepo.writeTentativeInventory c (compression opts) $ deepOptimizePatchset ps finalizeRepositoryChanges repository, old = fail Old.oldRepoFailMsg} cleanRepository :: RepoPatch p => Repository p C(r u t) -> IO () cleanRepository repository@(Repo _ _ rf _) = decideHashedOrNormal rf $ HvsO { hashed = HashedRepo.cleanPristine repository, old = fail Old.oldRepoFailMsg} createPristineDirectoryTree :: RepoPatch p => Repository p C(r u t) -> FilePath -> IO () createPristineDirectoryTree (Repo r opts rf (DarcsRepository _ c)) reldir | formatHas HashedInventory rf = do createDirectoryIfMissing True reldir withCurrentDirectory reldir $ HashedRepo.copyPristine c (compression opts) r (darcsdir++"/hashed_inventory") | otherwise = fail Old.oldRepoFailMsg -- fp below really should be FileName -- | Used by the commands dist and diff createPartialsPristineDirectoryTree :: (FilePathLike fp, RepoPatch p) => Repository p C(r u t) -> [fp] -> FilePath -> IO () createPartialsPristineDirectoryTree (Repo r opts rf (DarcsRepository _ c)) prefs dir | formatHas HashedInventory rf = do createDirectoryIfMissing True dir withCurrentDirectory dir $ HashedRepo.copyPartialsPristine c (compression opts) r (darcsdir++"/hashed_inventory") prefs | otherwise = fail Old.oldRepoFailMsg withRecorded :: RepoPatch p => Repository p C(r u t) -> ((AbsolutePath -> IO a) -> IO a) -> (AbsolutePath -> IO a) -> IO a withRecorded repository mk_dir f = mk_dir $ \d -> do createPristineDirectoryTree repository (toFilePath d) f d withTentative :: forall p a C(r u t). (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u t) -> ((AbsolutePath -> IO a) -> IO a) -> (AbsolutePath -> IO a) -> IO a withTentative (Repo dir opts rf (DarcsRepository _ c)) mk_dir f | formatHas HashedInventory rf = mk_dir $ \d -> do HashedRepo.copyPristine c (compression opts) dir (darcsdir++"/tentative_pristine") f d withTentative repository@(Repo dir _ _ _) mk_dir f = withRecorded repository mk_dir $ \d -> do Sealed ps <- read_patches (dir ++ "/"++darcsdir++"/tentative_pristine") apply ps f d where read_patches :: FilePath -> IO (Sealed (FL p C(x))) read_patches fil = do ps <- B.readFile fil return $ maybe (seal NilFL) id $ readPatch ps -- | Sets scripts in or below the current directory executable. A script is any file that starts -- with the bytes '#!'. This is used for --set-scripts-executable. setScriptsExecutable_ :: Patchy p => Maybe (p C(x y)) -> IO () setScriptsExecutable_ pw = do debugMessage "Making scripts executable" tree <- readWorking paths <- case pw of Just ps -> filterM doesFileExist $ listTouchedFiles ps Nothing -> return [ anchorPath "." p | (p, Tree.File _) <- Tree.list tree ] let setExecutableIfScript f = do contents <- B.readFile f when (BC.pack "#!" `B.isPrefixOf` contents) $ do debugMessage ("Making executable: " ++ f) setExecutable f True mapM_ setExecutableIfScript paths setScriptsExecutable :: IO () setScriptsExecutable = setScriptsExecutable_ (Nothing :: Maybe (FL DummyPatch C(x y))) setScriptsExecutablePatches :: Patchy p => p C(x y) -> IO () setScriptsExecutablePatches = setScriptsExecutable_ . Just darcs-2.8.4/src/Darcs/Repository/LowLevel.hs0000644001765600176560000001143112104371431020230 0ustar ganeshganesh-- Copyright (C) 2002-2004,2007-2008 David Roundy -- Copyright (C) 2005 Juliusz Chroboczek -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP #-} #include "gadts.h" module Darcs.Repository.LowLevel ( readPending, readTentativePending , writeTentativePending -- deprecated interface: , readNewPending, writeNewPending , pendingName ) where import Darcs.Repository.InternalTypes ( RepoType(..), Repository(..) ) import Darcs.Patch ( readPatch, writePatch, RepoPatch, PrimOf ) import Darcs.Patch.Read ( ReadPatch(..), bracketedFL ) import Darcs.Patch.ReadMonads ( ParserM ) import Darcs.Patch.Show ( ShowPatchBasic(..) ) import Darcs.Global ( darcsdir ) import Darcs.Witnesses.Sealed ( Sealed(Sealed), mapSeal ) import Darcs.Witnesses.Ordered ( FL(..), mapFL ) import Darcs.Utils ( catchall ) import ByteStringUtils ( gzReadFilePS ) import Printer ( Doc, ($$), text, vcat ) import Control.Applicative import qualified Data.ByteString as BS ( ByteString, empty ) pendingName :: RepoType p -> String pendingName (DarcsRepository _ _) = darcsdir++"/patches/pending" -- | Read the contents of pending. CWD should be the repository directory. -- The return type is currently incorrect as it refers to the tentative -- state rather than the recorded state. readPending :: RepoPatch p => Repository p C(r u t) -> IO (Sealed (FL (PrimOf p) C(t))) readPending (Repo _ _ _ tp) = readPendingFile (pendingName tp) -- |Read the contents of tentative pending. CWD should be the repository directory. readTentativePending :: RepoPatch p => Repository p C(r u t) -> IO (Sealed (FL (PrimOf p) C(t))) readTentativePending (Repo _ _ _ tp) = readPendingFile (pendingName tp ++ ".tentative") -- |Read the contents of tentative pending. CWD should be the repository directory. readNewPending :: RepoPatch p => Repository p C(r u t) -> IO (Sealed (FL (PrimOf p) C(t))) readNewPending (Repo _ _ _ tp) = readPendingFile (pendingName tp ++ ".new") readPendingFile :: ReadPatch prim => String -> IO (Sealed (FL prim C(x))) readPendingFile name = do pend <- gzReadFilePS name `catchall` return BS.empty return $ readPendingContents pend -- Wrapper around FL where printed format uses { } except around singletons -- Now that the Show behaviour of FL p can be customised (using showFLBehavior), -- we could instead change the general behaviour of FL Prim; but since the pending -- code can be kept nicely compartmentalised, it's nicer to do it this way. newtype FLM p C(x y) = FLM { unFLM :: FL p C(x y) } instance ReadPatch p => ReadPatch (FLM p) where readPatch' = mapSeal FLM <$> readMaybeBracketedFL readPatch' '{' '}' instance ShowPatchBasic p => ShowPatchBasic (FLM p) where showPatch = showMaybeBracketedFL showPatch '{' '}' . unFLM readPendingContents :: ReadPatch prim => BS.ByteString -> Sealed (FL prim C(x)) readPendingContents = maybe (Sealed NilFL) (mapSeal unFLM) . readPatch writePendingFile :: ShowPatchBasic prim => String -> FL prim C(x y) -> IO () writePendingFile name = writePatch name . FLM readMaybeBracketedFL :: forall m p C(x) . ParserM m => (FORALL(y) m (Sealed (p C(y)))) -> Char -> Char -> m (Sealed (FL p C(x))) readMaybeBracketedFL parser pre post = bracketedFL parser pre post <|> (mapSeal (:>:NilFL) <$> parser) showMaybeBracketedFL :: (FORALL(x y) p C(x y) -> Doc) -> Char -> Char -> FL p C(a b) -> Doc showMaybeBracketedFL _ pre post NilFL = text [pre] $$ text [post] showMaybeBracketedFL printer _ _ (p :>: NilFL) = printer p showMaybeBracketedFL printer pre post ps = text [pre] $$ vcat (mapFL printer ps) $$ text [post] -- |Read the contents of tentative pending. CWD should be the repository directory. writeTentativePending :: RepoPatch p => Repository p C(r u t) -> FL (PrimOf p) C(t y) -> IO () writeTentativePending (Repo _ _ _ tp) pend = writePendingFile (pendingName tp ++ ".tentative") pend -- |Read the contents of new pending. CWD should be the repository directory. writeNewPending :: RepoPatch p => Repository p C(r u t) -> FL (PrimOf p) C(t y) -> IO () writeNewPending (Repo _ _ _ tp) pend = writePendingFile (pendingName tp ++ ".new") pend darcs-2.8.4/src/Darcs/Repository/Merge.hs0000644001765600176560000001370012104371431017537 0ustar ganeshganesh-- Copyright (C) 2002-2004,2007-2008 David Roundy -- Copyright (C) 2005 Juliusz Chroboczek -- Copyright (C) 2009 Petr Rockai -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. #include "gadts.h" module Darcs.Repository.Merge ( tentativelyMergePatches, considerMergeToWorking ) where import Darcs.Resolution ( standardResolution, externalResolution ) import Darcs.External ( backupByCopying ) import Control.Monad ( when, unless ) import Darcs.Patch.PatchInfoAnd ( PatchInfoAnd, n2pia, hopefully ) import Darcs.Flags ( DarcsFlag( AllowConflicts, NoAllowConflicts ), wantExternalMerge, diffingOpts, compression ) import Darcs.Witnesses.Ordered ( FL(..), (:\/:)(..), (:/\:)(..), (+>+), mapFL_FL ) import Darcs.Patch ( RepoPatch, PrimOf, merge, joinPatches, listTouchedFiles , patchcontents, anonymous, fromPrims, effect ) import Darcs.Patch.Apply ( ApplyState ) import Darcs.Patch.Depends( merge2FL ) import Progress( debugMessage ) import Darcs.ProgressPatches( progressFL ) import Darcs.Witnesses.Sealed( Sealed(Sealed), seal ) import Darcs.Repository.InternalTypes( Repository(..) ) import Darcs.Repository.State( unrecordedChanges, readUnrecorded ) import Darcs.Repository.Internal ( announceMergeConflicts, checkUnrecordedConflicts , MakeChanges(..), setTentativePending , tentativelyAddPatch_, applyToTentativePristine, UpdatePristine(..) ) import Storage.Hashed.Tree( Tree ) tentativelyMergePatches_ :: forall p C(r u t y x). (RepoPatch p, ApplyState p ~ Tree) => MakeChanges -> Repository p C(r u t) -> String -> [DarcsFlag] -> FL (PatchInfoAnd p) C(x t) -> FL (PatchInfoAnd p) C(x y) -> IO (Sealed (FL (PrimOf p) C(u))) tentativelyMergePatches_ mc r cmd opts usi themi = do let us = mapFL_FL hopefully usi them = mapFL_FL hopefully themi Sealed pc <- return $ merge2FL (progressFL "Merging us" usi) (progressFL "Merging them" themi) pend <- unrecordedChanges (diffingOpts opts) r Nothing anonpend <- n2pia `fmap` anonymous (fromPrims pend) pend' :/\: pw <- return $ merge (pc :\/: anonpend :>: NilFL) let pwprim = joinPatches $ progressFL "Examining patches for conflicts" $ mapFL_FL (patchcontents . hopefully) pw Sealed standard_resolved_pw <- return $ standardResolution pwprim debugMessage "Checking for conflicts..." unless (AllowConflicts `elem` opts || NoAllowConflicts `elem` opts) $ mapM_ backupByCopying $ listTouchedFiles standard_resolved_pw debugMessage "Announcing conflicts..." have_conflicts <- announceMergeConflicts cmd opts standard_resolved_pw debugMessage "Checking for unrecorded conflicts..." have_unrecorded_conflicts <- checkUnrecordedConflicts opts $ mapFL_FL hopefully pc debugMessage "Reading working directory..." working <- readUnrecorded r Nothing debugMessage "Working out conflicts in actual working directory..." Sealed pw_resolution <- case (wantExternalMerge opts, have_conflicts || have_unrecorded_conflicts) of (Nothing,_) -> return $ if AllowConflicts `elem` opts then seal NilFL else seal standard_resolved_pw (_,False) -> return $ seal standard_resolved_pw (Just c, True) -> externalResolution working c opts (effect us +>+ pend) (effect them) pwprim debugMessage "Applying patches to the local directories..." when (mc == MakeChanges) $ do let doChanges :: FL (PatchInfoAnd p) C(x t) -> IO () doChanges NilFL = applyps r themi doChanges _ = applyps r pc doChanges usi setTentativePending r (effect pend' +>+ pw_resolution) return $ seal (effect pwprim +>+ pw_resolution) where mapAdd :: Repository p C(m l i) -> FL (PatchInfoAnd p) C(i j) -> IO (Repository p C(m l j)) mapAdd repo NilFL = return repo mapAdd repo (a:>:as) = do repo' <- tentativelyAddPatch_ DontUpdatePristine repo (compression opts) a mapAdd repo' as applyps :: Repository p C(m l i) -> FL (PatchInfoAnd p) C(i j) -> IO () applyps repo ps = do debugMessage "Adding patches to inventory..." -- Warning: A do-notation statement discarded a result of type Repository p m l j. _ <- mapAdd repo ps debugMessage "Applying patches to pristine..." applyToTentativePristine repo ps tentativelyMergePatches :: (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u t) -> String -> [DarcsFlag] -> FL (PatchInfoAnd p) C(x t) -> FL (PatchInfoAnd p) C(x y) -> IO (Sealed (FL (PrimOf p) C(u))) tentativelyMergePatches = tentativelyMergePatches_ MakeChanges considerMergeToWorking :: (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u t) -> String -> [DarcsFlag] -> FL (PatchInfoAnd p) C(x t) -> FL (PatchInfoAnd p) C(x y) -> IO (Sealed (FL (PrimOf p) C(u))) considerMergeToWorking = tentativelyMergePatches_ DontMakeChanges darcs-2.8.4/src/Darcs/Repository/InternalTypes.hs0000644001765600176560000000431012104371431021276 0ustar ganeshganesh-- Copyright (C) 2006-2007 David Roundy -- -- 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, 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. {-# LANGUAGE CPP #-} #include "gadts.h" module Darcs.Repository.InternalTypes ( Repository(..), RepoType(..), Pristine(..) , extractCache, extractOptions, modifyCache ) where import Data.List ( nub, sortBy ) import Darcs.Repository.Cache ( Cache (..) , compareByLocality ) import Darcs.Flags ( DarcsFlag ) import Darcs.Repository.Format ( RepoFormat ) import Darcs.Patch ( RepoPatch ) data Pristine = NoPristine | PlainPristine | HashedPristine deriving ( Show, Eq ) data Repository (p :: * C(-> * -> *)) C(recordedstate unrecordedstate tentativestate) = Repo !String ![DarcsFlag] !RepoFormat !(RepoType p) deriving ( Show ) data RepoType (p :: * C(-> * -> *)) = DarcsRepository !Pristine Cache deriving ( Show ) extractCache :: Repository p C(r u t) -> Cache extractCache (Repo _ _ _ (DarcsRepository _ c)) = c extractOptions :: Repository p C(r u t) -> [DarcsFlag] extractOptions (Repo _ opts _ _) = opts -- | 'modifyCache' @repository function@ modifies the cache of -- @repository@ with @function@, remove duplicates and sort the results with 'compareByLocality'. modifyCache :: FORALL(p r u t) (RepoPatch p) => Repository p C(r u t) -> (Cache -> Cache) -> Repository p C(r u t) modifyCache (Repo dir opts rf (DarcsRepository pristine cache)) f = Repo dir opts rf dr where dr = DarcsRepository pristine . cmap ( sortBy compareByLocality . nub ) $ f cache cmap g (Ca c) = Ca (g c) darcs-2.8.4/src/Darcs/Repository/Motd.hs0000644001765600176560000000332212104371431017402 0ustar ganeshganesh-- Copyright (C) 2002-2004 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. module Darcs.Repository.Motd (getMotd, showMotd) where import Control.Monad ( unless ) import Darcs.Flags ( DarcsFlag( Quiet, XMLOutput ) ) import Darcs.External ( fetchFilePS, Cachable(..) ) import Darcs.Global ( darcsdir ) import qualified Data.ByteString as B (null, hPut, empty, ByteString) import Darcs.Utils ( catchall ) import System.IO ( stdout ) -- | Fetch and return the message of the day for a given repository. getMotd :: String -> IO B.ByteString getMotd repo = fetchFilePS (repo++"/"++darcsdir++"/prefs/motd") (MaxAge 600) `catchall` return B.empty -- | Display the message of the day for a given repository, -- unless either the 'XMLOutput' or the 'Quiet' flags are passed in showMotd :: [DarcsFlag] -> String -> IO () showMotd opts repo = unless (Quiet `elem` opts || XMLOutput `elem` opts) $ do motd <- getMotd repo unless (B.null motd) $ do B.hPut stdout motd putStrLn "**********************" darcs-2.8.4/src/Darcs/Repository/Old.hs0000644001765600176560000001543612104371431017226 0ustar ganeshganesh-- Copyright (C) 2002-2005,2007-2008 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP, ScopedTypeVariables #-} #include "gadts.h" module Darcs.Repository.Old ( readOldRepo, revertTentativeChanges, oldRepoFailMsg ) where import Prelude hiding ( catch ) import Progress ( debugMessage, beginTedious, endTedious, finishedOneIO ) import Darcs.RepoPath ( ioAbsoluteOrRemote, toPath ) import System.IO ( hPutStrLn, stderr ) import System.IO.Unsafe ( unsafeInterleaveIO ) import System.FilePath.Posix ( () ) import Darcs.Patch.PatchInfoAnd ( Hopefully, PatchInfoAnd, patchInfoAndPatch, actually, unavailable ) import qualified Data.ByteString.Char8 as BC (break, pack) import Darcs.Patch ( RepoPatch, Named, readPatch ) import Darcs.Witnesses.Ordered ( RL(..) ) import Darcs.Patch.Info ( PatchInfo, makeFilename, readPatchInfos ) import Darcs.Patch.Set ( PatchSet(..), Tagged(..), SealedPatchSet ) #ifdef GADT_WITNESSES import Darcs.Patch.Set ( Origin ) #endif import Darcs.External ( gzFetchFilePS, Cachable(..), cloneFile ) import Darcs.Lock ( writeBinFile ) import Darcs.Global ( darcsdir ) import Darcs.Witnesses.Sealed ( Sealed(Sealed), seal, unseal, mapSeal ) import Control.Exception ( catch, IOException ) #include "impossible.h" readOldRepo :: RepoPatch p => String -> IO (SealedPatchSet p C(Origin)) readOldRepo d = do realdir <- toPath `fmap` ioAbsoluteOrRemote d let k = "Reading inventory of repository "++d beginTedious k readRepoPrivate k realdir "inventory" `catch` (\e -> do hPutStrLn stderr ("Invalid repository: " ++ realdir) ioError e) readRepoPrivate :: RepoPatch p => String -> FilePath -> FilePath -> IO (SealedPatchSet p C(Origin)) readRepoPrivate k d iname = do i <- gzFetchFilePS (d "_darcs" iname) Uncachable finishedOneIO k iname let parse inf = parse2 inf $ d "_darcs/patches" makeFilename inf (mt, is) = case BC.break ((==) '\n') i of (swt,pistr) | swt == BC.pack "Starting with tag:" -> case readPatchInfos pistr of (t:ids) -> (Just t,reverse ids) [] -> bug "bad inventory in readRepoPrivate" _ -> (Nothing, reverse $ readPatchInfos i) Sealed ts <- unseal seal `fmap` unsafeInterleaveIO (read_ts parse mt) Sealed ps <- unseal seal `fmap` unsafeInterleaveIO (read_patches parse is) return $ seal (PatchSet ps ts) where read_ts :: RepoPatch p => (FORALL(b) PatchInfo -> IO (Sealed (PatchInfoAnd p C(b)))) -> Maybe PatchInfo -> IO (Sealed (RL (Tagged p) C(Origin))) read_ts _ Nothing = do endTedious k return $ seal NilRL read_ts parse (Just tag0) = do debugMessage $ "Looking for inventory for:\n"++ show tag0 i <- unsafeInterleaveIO $ do x <- gzFetchFilePS (d"_darcs/inventories"makeFilename tag0) Uncachable finishedOneIO k (show tag0) return x let (mt, is) = case BC.break ((==) '\n') i of (swt,pistr) | swt == BC.pack "Starting with tag:" -> case readPatchInfos pistr of (t:ids) -> (Just t,reverse ids) [] -> bug "bad inventory in readRepoPrivate" _ -> (Nothing, reverse $ readPatchInfos i) Sealed ts <- fmap (unseal seal) $ unsafeInterleaveIO $ read_ts parse mt Sealed ps <- unseal seal `fmap` unsafeInterleaveIO (read_patches parse is) Sealed tag00 <- parse tag0 `catch` \(e :: IOException) -> return $ seal $ patchInfoAndPatch tag0 $ unavailable $ show e return $ seal $ Tagged tag00 Nothing ps :<: ts parse2 :: RepoPatch p => PatchInfo -> FilePath -> IO (Sealed (PatchInfoAnd p C(x))) parse2 i fn = do ps <- unsafeInterleaveIO $ gzFetchFilePS fn Cachable return $ patchInfoAndPatch i `mapSeal` hopefullyNoParseError (toPath fn) (readPatch ps) hopefullyNoParseError :: String -> Maybe (Sealed (Named a1dr C(x))) -> Sealed (Hopefully (Named a1dr) C(x)) hopefullyNoParseError _ (Just (Sealed x)) = seal $ actually x hopefullyNoParseError s Nothing = seal $ unavailable $ "Couldn't parse file "++s read_patches :: RepoPatch p => (FORALL(b) PatchInfo -> IO (Sealed (PatchInfoAnd p C(b)))) -> [PatchInfo] -> IO (Sealed (RL (PatchInfoAnd p) C(x))) read_patches _ [] = return $ seal NilRL read_patches parse (i:is) = lift2Sealed (:<:) (read_patches parse is) (parse i `catch` \(e :: IOException) -> return $ seal $ patchInfoAndPatch i $ unavailable $ show e) lift2Sealed :: (FORALL(y z) q C(y z) -> pp C(y) -> r C(z)) -> IO (Sealed pp) -> (FORALL(b) IO (Sealed (q C(b)))) -> IO (Sealed r) lift2Sealed f iox ioy = do Sealed x <- unseal seal `fmap` unsafeInterleaveIO iox Sealed y <- unseal seal `fmap` unsafeInterleaveIO ioy return $ seal $ f y x revertTentativeChanges :: IO () revertTentativeChanges = do cloneFile (darcsdir++"/inventory") (darcsdir++"/tentative_inventory") writeBinFile (darcsdir++"/tentative_pristine") "" oldRepoFailMsg :: String oldRepoFailMsg = "ERROR: repository upgrade required, try `darcs optimize --upgrade`\n" ++ "See http://wiki.darcs.net/OF for more details." darcs-2.8.4/src/Darcs/Repository/Prefs.hs0000644001765600176560000004327212104371431017566 0ustar ganeshganesh-- Copyright (C) 2002-2003 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP #-} #include "gadts.h" module Darcs.Repository.Prefs ( addToPreflist, getPreflist, setPreflist, getGlobal, environmentHelpHome, defaultrepo, setDefaultrepo, getPrefval, setPrefval, changePrefval, defPrefval, writeDefaultPrefs, boringRegexps, boringFileFilter, darcsdirFilter, FileType(..), filetypeFunction, getCaches, binariesFileHelp, boringFileHelp, globalCacheDir, globalPrefsDirDoc, ) where import Prelude hiding ( catch ) import System.IO.Error ( isDoesNotExistError ) import Control.Exception ( catch ) import Control.Monad ( unless, when ) import Text.Regex ( Regex, mkRegex, matchRegex, ) import Data.Char ( toUpper ) import Data.Maybe ( isJust, fromMaybe, mapMaybe ) import Data.List ( nub, isPrefixOf, union, sortBy ) import System.Directory ( getAppUserDataDirectory, doesDirectoryExist, createDirectory, doesFileExist ) import Darcs.Lock( readBinFile, writeBinFile ) import System.FilePath.Posix ( () ) import System.Environment ( getEnvironment ) import Darcs.Flags ( DarcsFlag( NoCache, NoSetDefault, DryRun, RemoteRepo ) ) import Darcs.RepoPath ( AbsolutePath, ioAbsolute, toFilePath, getCurrentDirectory ) import Darcs.Utils ( catchall, stripCr ) import Darcs.External ( gzFetchFilePS, Cachable( Cachable ) ) import qualified Data.ByteString.Char8 as BC ( unpack ) import qualified Data.ByteString as B ( empty ) import Darcs.Global ( darcsdir ) import Darcs.Repository.Cache ( Cache(..), CacheType(..), CacheLoc(..), WritableOrNot(..), compareByLocality ) import Darcs.URL ( isFile ) writeDefaultPrefs :: IO () writeDefaultPrefs = do setPreflist "boring" defaultBoring setPreflist "binaries" defaultBinaries setPreflist "motd" [] {-# NOINLINE defaultBoring #-} defaultBoring :: [String] defaultBoring = help ++ [ "", "### compiler and interpreter intermediate files", "# haskell (ghc) interfaces", "\\.hi$", "\\.hi-boot$", "\\.o-boot$", "# object files", "\\.o$","\\.o\\.cmd$", "# profiling haskell", "\\.p_hi$", "\\.p_o$", "# haskell program coverage resp. profiling info", "\\.tix$", "\\.prof$", "# fortran module files", "\\.mod$", "# linux kernel", "\\.ko\\.cmd$","\\.mod\\.c$", "(^|/)\\.tmp_versions($|/)", "# *.ko files aren't boring by default because they might", "# be Korean translations rather than kernel modules", "# \\.ko$", "# python, emacs, java byte code", "\\.py[co]$", "\\.elc$","\\.class$", "# objects and libraries; lo and la are libtool things", "\\.(obj|a|exe|so|lo|la)$", "# compiled zsh configuration files", "\\.zwc$", "# Common LISP output files for CLISP and CMUCL", "\\.(fas|fasl|sparcf|x86f)$", "", "### build and packaging systems", "# cabal intermediates", "\\.installed-pkg-config", "\\.setup-config", "# standard cabal build dir, might not be boring for everybody", "# ^dist(/|$)", "# autotools", "(^|/)autom4te\\.cache($|/)", "(^|/)config\\.(log|status)$", "# microsoft web expression, visual studio metadata directories", "\\_vti_cnf$", "\\_vti_pvt$", "# gentoo tools", "\\.revdep-rebuild.*", "# generated dependencies", "^\\.depend$", "", "### version control systems", "# cvs", "(^|/)CVS($|/)","\\.cvsignore$", "# cvs, emacs locks", "^\\.#", "# rcs", "(^|/)RCS($|/)", ",v$", "# subversion", "(^|/)\\.svn($|/)", "# mercurial", "(^|/)\\.hg($|/)", "# git", "(^|/)\\.git($|/)", "# bzr", "\\.bzr$", "# sccs", "(^|/)SCCS($|/)", "# darcs", "(^|/)"++darcsdir++"($|/)", "(^|/)\\.darcsrepo($|/)", "^\\.darcs-temp-mail$", "-darcs-backup[[:digit:]]+$", "# gnu arch", "(^|/)(\\+|,)", "(^|/)vssver\\.scc$", "\\.swp$","(^|/)MT($|/)", "(^|/)\\{arch\\}($|/)","(^|/).arch-ids($|/)", "# bitkeeper", "(^|/)BitKeeper($|/)","(^|/)ChangeSet($|/)", "", "### miscellaneous", "# backup files", "~$","\\.bak$","\\.BAK$", "# patch originals and rejects", "\\.orig$", "\\.rej$", "# X server", "\\..serverauth.*", "# image spam", "\\#", "(^|/)Thumbs\\.db$", "# vi, emacs tags", "(^|/)(tags|TAGS)$", "#(^|/)\\.[^/]", "# core dumps", "(^|/|\\.)core$", "# partial broken files (KIO copy operations)", "\\.part$", "# waf files, see http://code.google.com/p/waf/", "(^|/)\\.waf-[[:digit:].]+-[[:digit:]]+($|/)", "(^|/)\\.lock-wscript$", "# mac os finder", "(^|/)\\.DS_Store$" ] where help = map ("# "++) boringFileHelp boringFileHelp :: [String] boringFileHelp = [ "This file contains a list of extended regular expressions, one per" , "line. A file path matching any of these expressions will be filtered" , "out during `darcs add', or when the `--look-for-adds' flag is passed" , "to `darcs whatsnew' and `record'. The entries in " ++ globalPrefsDirDoc ++ "boring (if" , "it exists) supplement those in this file." , "" , "Blank lines, and lines beginning with an octothorpe (#) are ignored." , "See regex(7) for a description of extended regular expressions." ] darcsdirFilter :: [FilePath] -> [FilePath] darcsdirFilter = filter (not.isDarcsdir) isDarcsdir :: FilePath -> Bool isDarcsdir ('.':'/':f) = isDarcsdir f isDarcsdir "." = True isDarcsdir "" = True isDarcsdir ".." = True isDarcsdir "../" = True isDarcsdir "_darcs" = True isDarcsdir fp = "_darcs/" `isPrefixOf` fp -- | The path of the global preference directory; @~/.darcs@ on Unix, -- and @%APPDATA%/darcs@ on Windows. globalPrefsDir :: IO (Maybe FilePath) globalPrefsDir = do env <- getEnvironment case lookup "DARCS_TESTING_PREFS_DIR" env of Just d -> return (Just d) Nothing -> fmap Just (getAppUserDataDirectory "darcs") `catchall` (return Nothing) -- | The relative path of the global preference directory; @~/.darcs@ on Unix, -- and @%APPDATA%/darcs@ on Windows. This is used for online documentation. globalPrefsDirDoc :: String globalPrefsDirDoc = #ifndef WIN32 "~/.darcs/" #else "%APPDATA%\\darcs\\" #endif environmentHelpHome :: ([String], [String]) environmentHelpHome = (["HOME", "APPDATA"], [ "Per-user preferences are set in $HOME/.darcs (on Unix) or", "%APPDATA%/darcs (on Windows). This is also the default location of", "the cache."]) getGlobal :: String -> IO [String] getGlobal f = do dir <- globalPrefsDir case dir of (Just d) -> getPreffile $ d f Nothing -> return [] globalCacheDir :: IO (Maybe FilePath) globalCacheDir = slash_cache `fmap` globalPrefsDir where slash_cache = fmap ( "cache") boringRegexps :: IO [Regex] boringRegexps = do borefile <- defPrefval "boringfile" (darcsdir ++ "/prefs/boring") bores <- getPrefLines borefile `catchall` return [] gbs <- getGlobal "boring" return $ map mkRegex $ bores ++ gbs boringFileFilter :: IO ([FilePath] -> [FilePath]) boringFileFilter = fmap actualBoringFileFilter boringRegexps noncomments :: [String] -> [String] noncomments ss = filter is_ok ss where is_ok "" = False is_ok ('#':_) = False is_ok _ = True getPrefLines :: FilePath -> IO [String] getPrefLines f = (notconflicts . noncomments . map stripCr . lines) `fmap` readBinFile f where notconflicts = filter nc startswith [] _ = True startswith (x:xs) (y:ys) | x == y = startswith xs ys startswith _ _ = False nc l | startswith "v v v v v v v" l = False nc l | startswith "*************" l = False nc l | startswith "^ ^ ^ ^ ^ ^ ^" l = False nc _ = True -- | From a list of paths, filter out any that are within @_darcs@ or -- match a boring regexp. actualBoringFileFilter :: [Regex] -> [FilePath] -> [FilePath] actualBoringFileFilter regexps files = filter (not . boring . normalize) files where boring file = isDarcsdir file || any (\regexp -> isJust $ matchRegex regexp file) regexps normalize :: FilePath -> FilePath normalize ('.':'/':f) = normalize f normalize f = normalize_helper $ reverse f where normalize_helper ('/':rf) = normalize_helper rf normalize_helper rf = reverse rf data FileType = BinaryFile | TextFile deriving (Eq) {-# NOINLINE defaultBinaries #-} -- | The lines that will be inserted into @_darcs/prefs/binaries@ when -- @darcs init@ is run. Hence, a list of comments, blank lines and -- regular expressions (ERE dialect). -- -- Note that while this matches .gz and .GZ, it will not match .gZ, -- i.e. it is not truly case insensitive. defaultBinaries :: [String] defaultBinaries = help ++ ["\\.(" ++ e ++ "|" ++ map toUpper e ++ ")$" | e <- extensions ] where extensions = ["a","bmp","bz2","doc","elc","exe","gif","gz","iso", "jar","jpe?g","mng","mpe?g","p[nbgp]m","pdf","png", "pyc","so","tar","tgz","tiff?","z","zip"] help = map ("# "++) binariesFileHelp binariesFileHelp :: [String] binariesFileHelp = ["This file contains a list of extended regular expressions, one per", "line. A file path matching any of these expressions is assumed to", "contain binary data (not text). The entries in " ++ globalPrefsDirDoc ++ "binaries (if", "it exists) supplement those in this file.", "", "Blank lines, and lines beginning with an octothorpe (#) are ignored.", "See regex(7) for a description of extended regular expressions."] filetypeFunction :: IO (FilePath -> FileType) filetypeFunction = do binsfile <- defPrefval "binariesfile" (darcsdir ++ "/prefs/binaries") bins <- getPrefLines binsfile `catch` (\e-> if isDoesNotExistError e then return [] else ioError e) gbs <- getGlobal "binaries" let regexes = map mkRegex (bins ++ gbs) let isbin f = any (\r -> isJust $ matchRegex r f) regexes ftf f = if isbin $ normalize f then BinaryFile else TextFile in return ftf -- this avoids a circular dependency with Repository prefsDirectory :: IO (Maybe String) prefsDirectory = do darcs <- doesDirectoryExist darcsdir return $ if darcs then Just $ darcsdir ++ "/prefs/" else Nothing withPrefsDirectory :: (String -> IO ()) -> IO () withPrefsDirectory j = prefsDirectory >>= maybe (return ()) j addToPreflist :: String -> String -> IO () addToPreflist p s = withPrefsDirectory $ \prefs -> do hasprefs <- doesDirectoryExist prefs unless hasprefs $ createDirectory prefs pl <- getPreflist p writeBinFile (prefs ++ p) $ unlines $ union [s] pl getPreflist :: String -> IO [String] getPreflist p = prefsDirectory >>= maybe (return []) (\prefs -> getPreffile $ prefs ++ p) getPreffile :: FilePath -> IO [String] getPreffile f = do hasprefs <- doesFileExist f if hasprefs then getPrefLines f else return [] setPreflist :: String -> [String] -> IO () setPreflist p ls = withPrefsDirectory $ \prefs -> do haspref <- doesDirectoryExist prefs when haspref $ writeBinFile (prefs ++ p) (unlines ls) defPrefval :: String -> String -> IO String defPrefval p d = fromMaybe d `fmap` getPrefval p getPrefval :: String -> IO (Maybe String) getPrefval p = do pl <- getPreflist "prefs" return $ case map snd $ filter ((==p).fst) $ map (break (==' ')) pl of [val] -> case words val of [] -> Nothing _ -> Just $ tail val _ -> Nothing setPrefval :: String -> String -> IO () setPrefval p v = do pl <- getPreflist "prefs" setPreflist "prefs" $ filter ((/=p) . fst . break (==' ')) pl ++ [p++" "++v] changePrefval :: String -> String -> String -> IO () changePrefval p f t = do pl <- getPreflist "prefs" ov <- getPrefval p let newval = case ov of Nothing -> t Just old -> if old == f then t else old setPreflist "prefs" $ filter ((/=p) . fst . break(==' ')) pl ++ [p++" "++newval] defaultrepo :: [DarcsFlag] -> AbsolutePath -> [String] -> IO [String] defaultrepo opts _ [] = do let fixR r | isFile r = toFilePath `fmap` ioAbsolute r | otherwise = return r case [r | RemoteRepo r <- opts] of [] -> do defrepo <- getPreflist "defaultrepo" case defrepo of [r] -> (:[]) `fmap` fixR r _ -> return [] rs -> mapM fixR rs defaultrepo _ _ r = return r setDefaultrepo :: String -> [DarcsFlag] -> IO () setDefaultrepo r opts = do olddef <- getPreflist "defaultrepo" let doit = null noSetDefault && greenLight greenLight = wetRun && not rIsTmp && (olddef /= [r] || olddef == []) if doit then setPreflist "defaultrepo" [r] else when (True `notElem` noSetDefault && greenLight) $ putStr . unlines $ -- the nuance here is that we should only notify when the -- reason we're not setting default is the --no-set-default -- flag, not the various automatic show stoppers [ "HINT: if you want to change the default remote repository to" , " " ++ r ++ "," , " quit now and issue the same command with the --set-default flag." ] addToPreflist "repos" r `catchall` return () -- we don't care if this fails! where wetRun = DryRun `notElem` opts rIsTmp = r `elem` [x | RemoteRepo x <- opts] noSetDefault = [x | NoSetDefault x <- opts] getCaches :: [DarcsFlag] -> String -> IO Cache getCaches opts repodir = do here <- parsehs `fmap` getPreffile (darcsdir ++ "/prefs/sources") there <- (parsehs . lines . BC.unpack) `fmap` (gzFetchFilePS (repodir darcsdir "prefs/sources") Cachable `catchall` return B.empty) globalcachedir <- globalCacheDir let globalcache = case (nocache,globalcachedir) of (True,_) -> [] (_,Just d) -> [Cache Directory Writable d] _ -> [] globalsources <- parsehs `fmap` getGlobal "sources" thisdir <- getCurrentDirectory let thisrepo = [Cache Repo Writable $ toFilePath thisdir] let tempCache = nub $ thisrepo ++ globalcache ++ globalsources ++ here ++ [Cache Repo NotWritable repodir] ++ filterExternalSources there return $ Ca $ sortBy compareByLocality tempCache where parsehs = mapMaybe readln . noncomments readln l | "repo:" `isPrefixOf` l = Just (Cache Repo NotWritable (drop 5 l)) | nocache = Nothing | "cache:" `isPrefixOf` l = Just (Cache Directory Writable (drop 6 l)) | "readonly:" `isPrefixOf` l = Just (Cache Directory NotWritable (drop 9 l)) | otherwise = Nothing nocache = NoCache `elem` opts filterExternalSources there = if isFile repodir then there else filter (not . isFile . cacheSource) there darcs-2.8.4/src/Darcs/Repository/Repair.hs0000644001765600176560000002330412104371431017723 0ustar ganeshganesh{-# LANGUAGE CPP, PatternGuards #-} module Darcs.Repository.Repair ( replayRepository, checkIndex, replayRepositoryInTemp, RepositoryConsistency(..) ) where import Prelude hiding ( catch ) import Control.Monad ( when, unless ) import Control.Monad.Trans ( liftIO ) import Control.Applicative( (<$>) ) import Control.Exception ( catch, finally, IOException ) import Data.Maybe ( catMaybes ) import Data.List ( sort, (\\) ) import System.Directory ( createDirectoryIfMissing, getCurrentDirectory, setCurrentDirectory ) import Darcs.Lock( rmRecursive ) import Darcs.RepoPath( AbsolutePath, ioAbsolute, toFilePath ) import Darcs.Patch.PatchInfoAnd ( PatchInfoAnd, info, winfo, WPatchInfo, unWPatchInfo, compareWPatchInfo ) import Darcs.Witnesses.Eq ( EqCheck(..) ) import Darcs.Witnesses.Ordered ( FL(..), RL(..), lengthFL, reverseFL, mapRL, nullFL, (:||:)(..) ) import Darcs.Witnesses.Sealed ( Sealed2(..), Sealed(..), unFreeLeft ) import Darcs.Patch.Apply( ApplyState ) import Darcs.Patch.Repair ( Repair(applyAndTryToFix) ) import Darcs.Patch.PatchInfoAnd( hopefully ) import Darcs.Patch.Info ( humanFriendly ) import Darcs.Patch.Set ( PatchSet(..), newset2FL, newset2RL ) #ifdef GADT_WITNESSES import Darcs.Patch.Set ( Origin ) #endif import Darcs.Patch ( RepoPatch, PrimOf, isInconsistent ) import Darcs.Patch.Named ( patchcontents ) import Darcs.Repository.Format ( identifyRepoFormat, RepoProperty ( HashedInventory ), formatHas ) import Darcs.Repository.Cache ( HashedDir( HashedPristineDir ) ) import Darcs.Repository.HashedIO ( cleanHashdir ) import Darcs.Repository.HashedRepo ( readHashedPristineRoot ) import Darcs.Repository.InternalTypes ( extractCache ) import Darcs.Repository.Prefs ( filetypeFunction ) import Darcs.Repository ( Repository, readRepo, makePatchLazy , readRecorded, readIndex, readRecordedAndPending ) import Progress ( debugMessage, beginTedious, endTedious, tediousSize, finishedOneIO ) import Darcs.Utils ( catchall ) import Darcs.Global ( darcsdir ) import Darcs.Lock( withTempDir ) import Printer ( Doc, putDocLn, text ) import Darcs.Arguments ( DarcsFlag( Verbose, Quiet ) ) import Darcs.Diff( treeDiff ) import Storage.Hashed.Monad( TreeIO ) import Storage.Hashed.Darcs( hashedTreeIO ) import Storage.Hashed.Tree( Tree, emptyTree ) import Storage.Hashed.AnchoredPath( anchorPath ) import Storage.Hashed.Hash( Hash(NoHash), encodeBase16 ) import Storage.Hashed.Tree( list, restrict, expand, itemHash, zipTrees ) import Storage.Hashed.Darcs( darcsUpdateHashes ) import Storage.Hashed.Index( updateIndex ) import Storage.Hashed( readPlainTree ) import qualified Data.ByteString.Char8 as BS #include "impossible.h" #include "gadts.h" replaceInFL :: FL (PatchInfoAnd a) C(x y) -> [Sealed2 (WPatchInfo :||: PatchInfoAnd a)] -> FL (PatchInfoAnd a) C(x y) replaceInFL orig [] = orig replaceInFL NilFL _ = impossible replaceInFL (o:>:orig) ch@(Sealed2 (o':||:c):ch_rest) | IsEq <- winfo o `compareWPatchInfo` o' = c:>:replaceInFL orig ch_rest | otherwise = o:>:replaceInFL orig ch applyAndFix :: forall p C(r u t). (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u t) -> FL (PatchInfoAnd p) C(Origin r) -> TreeIO (FL (PatchInfoAnd p) C(Origin r), Bool) applyAndFix _ NilFL = return (NilFL, True) applyAndFix r psin = do liftIO $ beginTedious k liftIO $ tediousSize k $ lengthFL psin (repaired, ok) <- aaf psin liftIO $ endTedious k orig <- liftIO $ newset2FL `fmap` readRepo r return (replaceInFL orig repaired, ok) where k = "Replaying patch" aaf :: FL (PatchInfoAnd p) C(w z) -> TreeIO ([Sealed2 (WPatchInfo :||: PatchInfoAnd p)], Bool) aaf NilFL = return ([], True) aaf (p:>:ps) = do mp' <- applyAndTryToFix p case isInconsistent . patchcontents . hopefully $ p of Just err -> liftIO $ putDocLn err Nothing -> return () let !winfp = winfo p -- assure that 'p' can be garbage collected. liftIO $ finishedOneIO k $ show $ humanFriendly $ unWPatchInfo winfp (ps', restok) <- aaf ps case mp' of Nothing -> return (ps', restok) Just (e,pp) -> liftIO $ do putStrLn e p' <- makePatchLazy r pp return (Sealed2 (winfp :||: p'):ps', False) data RepositoryConsistency p C(x) = RepositoryConsistent | BrokenPristine (Tree IO) | BrokenPatches (Tree IO) (PatchSet p C(Origin x)) checkUniqueness :: (RepoPatch p, ApplyState p ~ Tree) => (Doc -> IO ()) -> (Doc -> IO ()) -> Repository p C(r u t) -> IO () checkUniqueness putVerbose putInfo repository = do putVerbose $ text "Checking that patch names are unique..." r <- readRepo repository case hasDuplicate $ mapRL info $ newset2RL r of Nothing -> return () Just pinf -> do putInfo $ text "Error! Duplicate patch name:" putInfo $ humanFriendly pinf fail "Duplicate patches found." hasDuplicate :: Ord a => [a] -> Maybe a hasDuplicate li = hd $ sort li where hd [_] = Nothing hd [] = Nothing hd (x1:x2:xs) | x1 == x2 = Just x1 | otherwise = hd (x2:xs) replayRepository' :: forall p C(r u t) . (RepoPatch p, ApplyState p ~ Tree) => AbsolutePath -> Repository p C(r u t) -> [DarcsFlag] -> IO (RepositoryConsistency p C(r)) replayRepository' whereToReplay' repo opts = do let whereToReplay = toFilePath whereToReplay' putVerbose s = when (Verbose `elem` opts) $ putDocLn s putInfo s = when (not $ Quiet `elem` opts) $ putDocLn s checkUniqueness putVerbose putInfo repo createDirectoryIfMissing False whereToReplay putVerbose $ text "Reading recorded state..." pris <- readRecorded repo `catch` \(_ :: IOException) -> return emptyTree putVerbose $ text "Applying patches..." patches <- readRepo repo debugMessage "Fixing any broken patches..." let psin = newset2FL patches repair = applyAndFix repo psin ((ps, patches_ok), newpris) <- hashedTreeIO repair emptyTree whereToReplay debugMessage "Done fixing broken patches..." let newpatches = PatchSet (reverseFL ps) NilRL debugMessage "Checking pristine against slurpy" ftf <- filetypeFunction is_same <- do Sealed diff <- unFreeLeft `fmap` treeDiff ftf pris newpris :: IO (Sealed (FL (PrimOf p) C(r))) return $ nullFL diff `catchall` return False -- TODO is the latter condition needed? Does a broken patch imply pristine -- difference? Why, or why not? return (if is_same && patches_ok then RepositoryConsistent else if patches_ok then BrokenPristine newpris else BrokenPatches newpris newpatches) cleanupRepositoryReplay :: Repository p C(r u t) -> IO () cleanupRepositoryReplay r = do let c = extractCache r rf <- identifyRepoFormat "." unless (formatHas HashedInventory rf) $ rmRecursive $ darcsdir ++ "/pristine.hashed" when (formatHas HashedInventory rf) $ do current <- readHashedPristineRoot r cleanHashdir c HashedPristineDir $ catMaybes [current] replayRepositoryInTemp :: (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u t) -> [DarcsFlag] -> IO (RepositoryConsistency p C(r)) replayRepositoryInTemp r opt = do repodir <- getCurrentDirectory withTempDir "darcs-check" $ \tmpDir -> do setCurrentDirectory repodir replayRepository' tmpDir r opt replayRepository :: (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u t) -> [DarcsFlag] -> (RepositoryConsistency p C(r) -> IO a) -> IO a replayRepository r opt f = do run `finally` cleanupRepositoryReplay r where run = do createDirectoryIfMissing False "_darcs/pristine.hashed" hashedPristine <- ioAbsolute "_darcs/pristine.hashed" st <- replayRepository' hashedPristine r opt f st checkIndex :: (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u t) -> Bool -> IO Bool checkIndex repo quiet = do index <- updateIndex =<< readIndex repo pristine <- expand =<< readRecordedAndPending repo working <- expand =<< restrict pristine <$> readPlainTree "." working_hashed <- darcsUpdateHashes working let index_paths = [ p | (p, _) <- list index ] working_paths = [ p | (p, _) <- list working ] index_extra = index_paths \\ working_paths working_extra = working_paths \\ index_paths gethashes p (Just i1) (Just i2) = (p, itemHash i1, itemHash i2) gethashes p (Just i1) Nothing = (p, itemHash i1, NoHash) gethashes p Nothing (Just i2) = (p, NoHash, itemHash i2) gethashes p Nothing Nothing = error $ "Bad case at " ++ show p mismatches = [ miss | miss@(_, h1, h2) <- zipTrees gethashes index working_hashed, h1 /= h2 ] format paths = unlines $ (map $ ((" " ++) . anchorPath "")) paths mismatches_disp = unlines [ anchorPath "" p ++ "\n index: " ++ BS.unpack (encodeBase16 h1) ++ "\n working: " ++ BS.unpack (encodeBase16 h2) | (p, h1, h2) <- mismatches ] unless (quiet || null index_extra) $ putStrLn $ "Extra items in index!\n" ++ format index_extra unless (quiet || null working_extra) $ putStrLn $ "Missing items in index!\n" ++ format working_extra unless (quiet || null mismatches) $ putStrLn $ "Hash mismatch(es)!\n" ++ mismatches_disp return $ null index_extra && null working_extra && null mismatches darcs-2.8.4/src/Darcs/Repository/State.hs0000644001765600176560000003403012104371431017557 0ustar ganeshganesh{-# OPTIONS_GHC -fno-warn-orphans #-} {-# LANGUAGE CPP #-} -- Copyright (C) 2009 Petr Rockai -- -- 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. module Darcs.Repository.State ( restrictSubpaths, restrictBoring, TreeFilter(..) -- * Diffs. , unrecordedChanges, readPending -- * Trees. , readRecorded, readUnrecorded, readRecordedAndPending, readWorking -- * Index. , readIndex, invalidateIndex, UseIndex(..), ScanKnown(..) ) where import Prelude hiding ( filter, catch ) import Control.Monad( when ) import Control.Applicative( (<$>) ) import Control.Exception ( catch, IOException ) import Data.Maybe( isJust ) import Data.List( union ) import Text.Regex( matchRegex ) import System.Directory( removeFile, doesFileExist, doesDirectoryExist, renameFile ) import System.FilePath ( () ) import qualified Data.ByteString as BS import qualified Data.ByteString.Char8 as BSC import Darcs.Patch ( RepoPatch, PrimOf, sortCoalesceFL, fromPrim, effect ) import Darcs.Patch.Apply ( ApplyState, applyToTree, effectOnFilePaths ) import Darcs.Witnesses.Ordered ( FL(..), (+>+), mapFL_FL ) import Darcs.Witnesses.Eq ( EqCheck(IsEq, NotEq) ) import Darcs.Witnesses.Unsafe ( unsafeCoerceP ) import Darcs.Witnesses.Sealed ( Sealed(Sealed), seal, unFreeLeft, mapSeal ) import Darcs.Diff ( treeDiff ) import Darcs.Flags ( UseIndex(..), ScanKnown(..) ) import Darcs.Global ( darcsdir ) import Darcs.Utils ( filterPaths ) import Darcs.Repository.InternalTypes ( Repository(..) ) import Darcs.Repository.Format(formatHas, RepoProperty(NoWorkingDir)) import qualified Darcs.Repository.LowLevel as LowLevel import Darcs.Repository.Prefs ( filetypeFunction, boringRegexps ) import Darcs.Patch.FileName ( fn2fp ) import Darcs.RepoPath ( SubPath, sp2fn ) import Storage.Hashed.AnchoredPath( AnchoredPath(..), anchorPath, floatPath, Name(..) ) import Storage.Hashed.Tree( Tree, restrict, FilterTree, expand, filter, emptyTree, overlay, find ) import Storage.Hashed.Plain( readPlainTree ) import Storage.Hashed.Darcs( darcsTreeHash, readDarcsHashed, decodeDarcsHash, decodeDarcsSize ) import Storage.Hashed.Hash( Hash( NoHash ) ) import qualified Storage.Hashed.Index as I import qualified Storage.Hashed.Tree as Tree #include "gadts.h" newtype TreeFilter m = TreeFilter { applyTreeFilter :: forall tr . FilterTree tr m => tr m -> tr m } -- TODO: We wrap the pending patch inside RepoPatch here, to avoid the -- requirement to propagate an (ApplyState (PrimOf p) ~ ApplyState p) -- constraint everywhere. When we have GHC 7.2 as a minimum requirement, we can -- lift this constraint into RepoPatch superclass context and remove this hack. readPendingLL :: (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u t) -> IO (Sealed ((FL p) C(t))) readPendingLL repo = mapSeal (mapFL_FL fromPrim) `fmap` LowLevel.readPending repo -- | From a repository and a list of SubPath's, construct a filter that can be -- used on a Tree (recorded or unrecorded state) of this repository. This -- constructed filter will take pending into account, so the subpaths will be -- translated correctly relative to pending move patches. restrictSubpaths :: forall p m C(r u t). (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u t) -> [SubPath] -> IO (TreeFilter m) restrictSubpaths repo subpaths = do Sealed pending <- readPendingLL repo let paths = map (fn2fp . sp2fn) subpaths paths' = paths `union` (effectOnFilePaths pending paths) anchored = map floatPath paths' restrictPaths :: FilterTree tree m => tree m -> tree m restrictPaths = filter (filterPaths anchored) return (TreeFilter restrictPaths) -- |Is the given path in (or equal to) the _darcs metadata directory? inDarcsDir :: AnchoredPath -> Bool inDarcsDir (AnchoredPath (Name x:_)) | x == BSC.pack darcsdir = True inDarcsDir _ = False -- | Construct a Tree filter that removes any boring files the Tree might have -- contained. Additionally, you should (in most cases) pass an (expanded) Tree -- that corresponds to the recorded content of the repository. This is -- important in the cases when the repository contains files that would be -- boring otherwise. (If you pass emptyTree instead, such files will simply be -- discarded by the filter, which is usually not what you want.) -- -- This function is most useful when you have a plain Tree corresponding to the -- full working copy of the repository, including untracked -- files. Cf. whatsnew, record --look-for-adds. NB. Assumes that our CWD is -- the repository root. restrictBoring :: forall m . Tree m -> IO (TreeFilter m) restrictBoring guide = do boring <- boringRegexps let boring' p | inDarcsDir p = False boring' p = not $ any (\rx -> isJust $ matchRegex rx p') boring where p' = anchorPath "" p restrictTree :: FilterTree t m => t m -> t m restrictTree = filter $ \p _ -> case find guide p of Nothing -> boring' p _ -> True return (TreeFilter restrictTree) -- | Construct a Tree filter that removes any darcs metadata files the -- Tree might have contained. restrictDarcsdir :: forall m . TreeFilter m restrictDarcsdir = TreeFilter $ filter $ \p _ -> not (inDarcsDir p) -- | For a repository and an optional list of paths (when Nothing, take -- everything) compute a (forward) list of prims (i.e. a patch) going from the -- recorded state of the repository (pristine) to the unrecorded state of the -- repository (the working copy + pending). When a list of paths is given, at -- least the files that live under any of these paths in either recorded or -- unrecorded will be included in the resulting patch. NB. More patches may be -- included in this list, eg. the full contents of the pending patch. This is -- usually not a problem, since selectChanges will properly filter the results -- anyway. -- -- This also depends on the options given: with LookForAdds, we will include -- any non-boring files (i.e. also those that do not exist in the "recorded" -- state) in the working in the "unrecorded" state, and therefore they will -- show up in the patches as addfiles. -- -- The IgnoreTimes option disables index usage completely -- for each file, we -- read both the unrecorded and the recorded copy and run a diff on them. This -- is very inefficient, although in extremely rare cases, the index could go -- out of sync (file is modified, index is updated and file is modified again -- within a single second). unrecordedChanges :: forall p C(r u t) . (RepoPatch p, ApplyState p ~ Tree) => (UseIndex, ScanKnown) -> Repository p C(r u t) -> Maybe [SubPath] -> IO (FL (PrimOf p) C(t u)) unrecordedChanges _ r@(Repo _ _ rf _) _ | (formatHas NoWorkingDir rf) = do IsEq <- return $ workDirLessRepoWitness r return NilFL unrecordedChanges (useidx, scan) repo mbpaths = do (all_current, Sealed (pending :: FL p C(t x))) <- readPending repo relevant <- maybe (return $ TreeFilter id) (restrictSubpaths repo) mbpaths let getIndex = I.updateIndex =<< (applyTreeFilter relevant <$> readIndex repo) current = applyTreeFilter relevant all_current index <- getIndex working <- applyTreeFilter restrictDarcsdir <$> case scan of ScanKnown -> case useidx of UseIndex -> getIndex IgnoreIndex -> do guide <- expand current applyTreeFilter relevant <$> restrict guide <$> readPlainTree "." ScanAll -> do nonboring <- restrictBoring index plain <- applyTreeFilter relevant <$> applyTreeFilter nonboring <$> readPlainTree "." return $ case useidx of UseIndex -> plain `overlay` index IgnoreIndex -> plain ScanBoring -> do plain <- applyTreeFilter relevant <$> readPlainTree "." return $ case useidx of UseIndex -> plain `overlay` index IgnoreIndex -> plain ft <- filetypeFunction Sealed (diff :: FL (PrimOf p) C(x y)) <- (unFreeLeft `fmap` treeDiff ft current working) :: IO (Sealed (FL (PrimOf p) C(x))) IsEq <- return (unsafeCoerceP IsEq) :: IO (EqCheck C(y u)) return $ sortCoalesceFL (effect pending +>+ diff) -- | Witnesses the fact that in the absence of a working directory, we -- pretend that the working dir updates magically to the tentative state. workDirLessRepoWitness :: Repository p C(r u t) -> (EqCheck C(u t)) workDirLessRepoWitness (Repo _ _ rf _) | formatHas NoWorkingDir rf = unsafeCoerceP IsEq | otherwise = NotEq -- | Obtains a Tree corresponding to the "recorded" state of the repository: -- this is the same as the pristine cache, which is the same as the result of -- applying all the repository's patches to an empty directory. -- -- Handles the plain and hashed pristine cases. Currently does not handle the -- no-pristine case, as that requires replaying patches. Cf. 'readDarcsHashed' -- and 'readPlainTree' in hashed-storage that are used to do the actual 'Tree' -- construction. readRecorded :: (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u t) -> IO (Tree IO) readRecorded _repo = do let h_inventory = darcsdir "hashed_inventory" hashed <- doesFileExist h_inventory if hashed then do inv <- BS.readFile h_inventory let linesInv = BSC.split '\n' inv case linesInv of [] -> return emptyTree (pris_line:_) -> do let hash = decodeDarcsHash $ BS.drop 9 pris_line size = decodeDarcsSize $ BS.drop 9 pris_line when (hash == NoHash) $ fail $ "Bad pristine root: " ++ show pris_line readDarcsHashed (darcsdir "pristine.hashed") (size, hash) else do have_pristine <- doesDirectoryExist $ darcsdir "pristine" have_current <- doesDirectoryExist $ darcsdir "current" case (have_pristine, have_current) of (True, _) -> readPlainTree $ darcsdir "pristine" (False, True) -> readPlainTree $ darcsdir "current" (_, _) -> fail "No pristine tree is available!" -- | Obtains a Tree corresponding to the "unrecorded" state of the repository: -- the working tree plus the "pending" patch. The optional list of paths allows -- to restrict the query to a subtree. -- -- Limiting the query may be more efficient, since hashes on the uninteresting -- parts of the index do not need to go through an up-to-date check (which -- involves a relatively expensive lstat(2) per file. readUnrecorded :: (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u t) -> Maybe [SubPath] -> IO (Tree IO) readUnrecorded repo mbpaths = do relevant <- maybe (return $ TreeFilter id) (restrictSubpaths repo) mbpaths readIndex repo >>= I.updateIndex . applyTreeFilter relevant -- | Obtains a Tree corresponding to the working copy of the -- repository. NB. Almost always, using readUnrecorded is the right -- choice. This function is only useful in not-completely-constructed -- repositories. readWorking :: IO (Tree IO) readWorking = expand =<< (nodarcs `fmap` readPlainTree ".") where nodarcs = Tree.filter (\(AnchoredPath (Name x:_)) _ -> x /= BSC.pack "_darcs") readRecordedAndPending :: (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u t) -> IO (Tree IO) readRecordedAndPending repo = fst `fmap` readPending repo readPending :: (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u t) -> IO (Tree IO, Sealed (FL p C(t))) readPending repo = do Sealed pending <- readPendingLL repo pristine <- readRecorded repo catch ((\t -> (t, seal pending)) `fmap` applyToTree pending pristine) $ \ (err :: IOException) -> do putStrLn $ "Yikes, pending has conflicts! " ++ show err putStrLn $ "Stashing the buggy pending as _darcs/patches/pending_buggy" renameFile "_darcs/patches/pending" "_darcs/patches/pending_buggy" return (pristine, seal NilFL) -- | Mark the existing index as invalid. This has to be called whenever the -- listing of pristine changes and will cause darcs to update the index next -- time it tries to read it. (NB. This is about files added and removed from -- pristine: changes to file content in either pristine or working are handled -- transparently by the index reading code.) invalidateIndex :: t -> IO () invalidateIndex _ = do BS.writeFile "_darcs/index_invalid" BS.empty readIndex :: (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u t) -> IO I.Index readIndex repo = do invalid <- doesFileExist "_darcs/index_invalid" exist <- doesFileExist "_darcs/index" format_valid <- if exist then I.indexFormatValid "_darcs/index" else return True when (exist && not format_valid) $ #if mingw32_HOST_OS renameFile "_darcs/index" "_darcs/index.old" #else removeFile "_darcs/index" #endif if (not exist || invalid || not format_valid) then do pris <- readRecordedAndPending repo idx <- I.updateIndexFrom "_darcs/index" darcsTreeHash pris when invalid $ removeFile "_darcs/index_invalid" return idx else I.readIndex "_darcs/index" darcsTreeHash darcs-2.8.4/src/Darcs/Witnesses/0000755001765600176560000000000012104371431015750 5ustar ganeshganeshdarcs-2.8.4/src/Darcs/Witnesses/Eq.hs0000644001765600176560000000354612104371431016661 0ustar ganeshganesh#include "gadts.h" module Darcs.Witnesses.Eq ( EqCheck(..), MyEq(..), isIsEq ) where import Darcs.Witnesses.Unsafe ( unsafeCoerceP ) -- |'EqCheck' is used to pass around evidence (or lack thereof) of -- two witness types being equal. data EqCheck C(a b) where IsEq :: EqCheck C(a a) NotEq :: EqCheck C(a b) instance Eq (EqCheck C(a b)) where IsEq == IsEq = True NotEq == NotEq = True _ == _ = False instance Show (EqCheck C(a b)) where show IsEq = "IsEq" show NotEq = "NotEq" -- |An witness aware equality class. -- A minimal definition defines any one of 'unsafeCompare', '=\/=' and '=/\='. class MyEq p where -- |It is unsafe to define a class instance via this method, because -- if it returns True then the default implementations of '=\/=' and '=/\=' -- will coerce the equality of two witnesses. -- -- Calling this method is safe, although '=\/=' or '=/\=' would be better -- choices as it is not usually meaningul to compare two patches that -- don't share either a starting or an ending context unsafeCompare :: p C(a b) -> p C(c d) -> Bool unsafeCompare a b = IsEq == (a =/\= unsafeCoerceP b) -- |Compare two things with the same starting witness. If the things -- compare equal, evidence of the ending witnesses being equal will -- be returned. (=\/=) :: p C(a b) -> p C(a c) -> EqCheck C(b c) a =\/= b | unsafeCompare a b = unsafeCoerceP IsEq | otherwise = NotEq -- |Compare two things with the same ending witness. If the things -- compare equal, evidence of the starting witnesses being equal will -- be returned. (=/\=) :: p C(a c) -> p C(b c) -> EqCheck C(a b) a =/\= b | IsEq == (a =\/= unsafeCoerceP b) = unsafeCoerceP IsEq | otherwise = NotEq infix 4 =\/=, =/\= isIsEq :: EqCheck C(a b) -> Bool isIsEq IsEq = True isIsEq NotEq = False darcs-2.8.4/src/Darcs/Witnesses/Ordered.hs0000644001765600176560000002451612104371431017700 0ustar ganeshganesh-- Copyright (C) 2007 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP #-} #include "gadts.h" module Darcs.Witnesses.Ordered ( (:>)(..), (:<)(..), (:\/:)(..), (:/\:)(..), (:||:)(..), FL(..), RL(..), lengthFL, mapFL, mapFL_FL, spanFL, foldlFL, allFL, anyFL, filterFL, splitAtFL, splitAtRL, bunchFL, foldlRL, lengthRL, isShorterThanRL, mapRL, mapRL_RL, zipWithFL, filterFLFL, filterRL, reverseFL, reverseRL, (+>+), (+<+), nullFL, concatFL, concatRL, consRLSealed, nullRL, toFL, dropWhileFL, dropWhileRL, spanFL_M, eqFL, eqFLRev, eqFLUnsafe ) where #include "impossible.h" import Darcs.Witnesses.Show import Darcs.Witnesses.Sealed ( FlippedSeal(..), flipSeal, Sealed(..), FreeLeft, unFreeLeft, Sealed2(..), seal ) import Darcs.Witnesses.Eq ( MyEq(..), EqCheck(..) ) data (a1 :> a2) C(x y) = FORALL(z) (a1 C(x z)) :> (a2 C(z y)) infixr 1 :> data (a1 :< a2) C(x y) = FORALL(z) (a1 C(z y)) :< (a2 C(x z)) infix 1 :< infix 1 :/\:, :\/:, :||: data (a1 :\/: a2) C(x y) = FORALL(z) (a1 C(z x)) :\/: (a2 C(z y)) data (a1 :/\: a2) C(x y) = FORALL(z) (a1 C(x z)) :/\: (a2 C(y z)) data (a1 :||: a2) C(x y) = (a1 C(x y)) :||: (a2 C(x y)) instance (Show2 a, Show2 b) => Show ( (a :> b) C(x y) ) where showsPrec d (x :> y) = showOp2 1 ":>" d x y instance (MyEq a, MyEq b) => MyEq (a :> b) where (a1 :> b1) =\/= (a2 :> b2) | IsEq <- a1 =\/= a2 = b1 =\/= b2 | otherwise = NotEq instance (MyEq a, MyEq b) => Eq ((a :> b) C(x y)) where (==) = unsafeCompare instance (MyEq a, MyEq b) => MyEq (a :< b) where (a1 :< b1) =\/= (a2 :< b2) | IsEq <- b1 =\/= b2 = a1 =\/= a2 | otherwise = NotEq instance (MyEq a, MyEq b) => Eq ((a :< b) C(x y)) where (==) = unsafeCompare instance (Show2 a, Show2 b) => Show2 (a :> b) where showDict2 = ShowDictClass instance (Show2 a, Show2 b) => Show ( (a :\/: b) C(x y) ) where showsPrec d (x :\/: y) = showOp2 9 ":\\/:" d x y instance (Show2 a, Show2 b) => Show2 (a :\/: b) where showDict2 = ShowDictClass infixr 5 :>:, :<:, +>+, +<+ -- forward list data FL a C(x z) where (:>:) :: a C(x y) -> FL a C(y z) -> FL a C(x z) NilFL :: FL a C(x x) instance Show2 a => Show (FL a C(x z)) where showsPrec _ NilFL = showString "NilFL" showsPrec d (x :>: xs) = showParen (d > prec) $ showsPrec2 (prec + 1) x . showString " :>: " . showsPrec (prec + 1) xs where prec = 5 instance Show2 a => Show1 (FL a C(x)) where showDict1 = ShowDictClass instance Show2 a => Show2 (FL a) where showDict2 = ShowDictClass instance Show2 a => Show (RL a C(x z)) where showsPrec _ NilRL = showString "NilRL" showsPrec d (x :<: xs) = showParen (d > prec) $ showsPrec2 (prec + 1) x . showString " :<: " . showsPrec (prec + 1) xs where prec = 5 instance Show2 a => Show1 (RL a C(x)) where showDict1 = ShowDictClass instance Show2 a => Show2 (RL a) where showDict2 = ShowDictClass instance (Show2 a, Show2 b) => Show1 ((a :> b) C(x)) where showDict1 = ShowDictClass -- reverse list data RL a C(x z) where (:<:) :: a C(y z) -> RL a C(x y) -> RL a C(x z) NilRL :: RL a C(x x) nullFL :: FL a C(x z) -> Bool nullFL NilFL = True nullFL _ = False nullRL :: RL a C(x z) -> Bool nullRL NilRL = True nullRL _ = False filterFLFL :: (FORALL(x y) p C(x y) -> EqCheck C(x y)) -> FL p C(w z) -> FL p C(w z) filterFLFL _ NilFL = NilFL filterFLFL f (x:>:xs) | IsEq <- f x = filterFLFL f xs | otherwise = x :>: filterFLFL f xs filterRL :: (FORALL(x y) p C(x y) -> Bool) -> RL p C(a b) -> [Sealed2 p] filterRL _ NilRL = [] filterRL f (x :<: xs) | f x = Sealed2 x : (filterRL f xs) | otherwise = filterRL f xs (+>+) :: FL a C(x y) -> FL a C(y z) -> FL a C(x z) NilFL +>+ ys = ys (x:>:xs) +>+ ys = x :>: xs +>+ ys (+<+) :: RL a C(y z) -> RL a C(x y) -> RL a C(x z) NilRL +<+ ys = ys (x:<:xs) +<+ ys = x :<: xs +<+ ys reverseFL :: FL a C(x z) -> RL a C(x z) reverseFL xs = r NilRL xs where r :: RL a C(l m) -> FL a C(m o) -> RL a C(l o) r ls NilFL = ls r ls (a:>:as) = r (a:<:ls) as reverseRL :: RL a C(x z) -> FL a C(x z) reverseRL xs = r NilFL xs -- r (xs :> NilFL) where r :: FL a C(m o) -> RL a C(l m) -> FL a C(l o) r ls NilRL = ls r ls (a:<:as) = r (a:>:ls) as concatFL :: FL (FL a) C(x z) -> FL a C(x z) concatFL NilFL = NilFL concatFL (a:>:as) = a +>+ concatFL as concatRL :: RL (RL a) C(x z) -> RL a C(x z) concatRL NilRL = NilRL concatRL (a:<:as) = a +<+ concatRL as spanFL :: (FORALL(w y) a C(w y) -> Bool) -> FL a C(x z) -> (FL a :> FL a) C(x z) spanFL f (x:>:xs) | f x = case spanFL f xs of ys :> zs -> (x:>:ys) :> zs spanFL _ xs = NilFL :> xs spanFL_M :: forall a m C(x z). Monad m => (FORALL(w y) a C(w y) -> m Bool) -> FL a C(x z) -> m ((FL a :> FL a) C(x z)) spanFL_M f (x:>:xs) = do continue <- f x if continue then do (ys :> zs) <- spanFL_M f xs return $ (x :>: ys) :> zs else return $ NilFL :> (x :>: xs) spanFL_M _ (NilFL) = return $ NilFL :> NilFL splitAtFL :: Int -> FL a C(x z) -> (FL a :> FL a) C(x z) splitAtFL 0 xs = NilFL :> xs splitAtFL _ NilFL = NilFL :> NilFL splitAtFL n (x:>:xs) = case splitAtFL (n-1) xs of (xs':>xs'') -> (x:>:xs' :> xs'') splitAtRL :: Int -> RL a C(x z) -> (RL a :< RL a) C(x z) splitAtRL 0 xs = NilRL :< xs splitAtRL _ NilRL = NilRL :< NilRL splitAtRL n (x:<:xs) = case splitAtRL (n-1) xs of (xs': (x:<:xs' :< xs'') -- 'bunchFL n' groups patches into batches of n, except that it always puts -- the first patch in its own group, this being a recognition that the -- first patch is often *very* large. bunchFL :: Int -> FL a C(x y) -> FL (FL a) C(x y) bunchFL _ NilFL = NilFL bunchFL n (x:>:xs) = (x :>: NilFL) :>: bFL xs where bFL :: FL a C(x y) -> FL (FL a) C(x y) bFL NilFL = NilFL bFL bs = case splitAtFL n bs of a :> b -> a :>: bFL b allFL :: (FORALL(x y) a C(x y) -> Bool) -> FL a C(w z) -> Bool allFL f xs = and $ mapFL f xs anyFL :: (FORALL(x y) a C(x y) -> Bool) -> FL a C(w z) -> Bool anyFL f xs = or $ mapFL f xs foldlFL :: (FORALL(w y) a -> b C(w y) -> a) -> a -> FL b C(x z) -> a foldlFL _ x NilFL = x foldlFL f x (y:>:ys) = foldlFL f (f x y) ys foldlRL :: (FORALL(w y) a -> b C(w y) -> a) -> a -> RL b C(x z) -> a foldlRL _ x NilRL = x foldlRL f x (y:<:ys) = foldlRL f (f x y) ys mapFL_FL :: (FORALL(w y) a C(w y) -> b C(w y)) -> FL a C(x z) -> FL b C(x z) mapFL_FL _ NilFL = NilFL mapFL_FL f (a:>:as) = f a :>: mapFL_FL f as zipWithFL :: (FORALL(x y) a -> p C(x y) -> q C(x y)) -> [a] -> FL p C(w z) -> FL q C(w z) zipWithFL f (x:xs) (y :>: ys) = f x y :>: zipWithFL f xs ys zipWithFL _ _ NilFL = NilFL zipWithFL _ [] (_:>:_) = bug "zipWithFL called with too short a list" mapRL_RL :: (FORALL(w y) a C(w y) -> b C(w y)) -> RL a C(x z) -> RL b C(x z) mapRL_RL _ NilRL = NilRL mapRL_RL f (a:<:as) = f a :<: mapRL_RL f as mapFL :: (FORALL(w z) a C(w z) -> b) -> FL a C(x y) -> [b] mapFL _ NilFL = [] mapFL f (a :>: b) = f a : mapFL f b filterFL :: (FORALL(x y) a C(x y) -> Bool) -> FL a C(w z) -> [Sealed2 a] filterFL _ NilFL = [] filterFL f (a :>: b) = if f a then (Sealed2 a):(filterFL f b) else filterFL f b mapRL :: (FORALL(w z) a C(w z) -> b) -> RL a C(x y) -> [b] mapRL _ NilRL = [] mapRL f (a :<: b) = f a : mapRL f b lengthFL :: FL a C(x z) -> Int lengthFL xs = l xs 0 where l :: FL a C(x z) -> Int -> Int l NilFL n = n l (_:>:as) n = l as $! n+1 lengthRL :: RL a C(x z) -> Int lengthRL xs = l xs 0 where l :: RL a C(x z) -> Int -> Int l NilRL n = n l (_:<:as) n = l as $! n+1 isShorterThanRL :: RL a C(x y) -> Int -> Bool isShorterThanRL _ n | n <= 0 = False isShorterThanRL NilRL _ = True isShorterThanRL (_:<:xs) n = isShorterThanRL xs (n-1) consRLSealed :: a C(y z) -> FlippedSeal (RL a) C(y) -> FlippedSeal (RL a) C(z) consRLSealed a (FlippedSeal as) = flipSeal $ a :<: as toFL :: [FreeLeft a] -> Sealed (FL a C(x)) toFL [] = Sealed NilFL toFL (x:xs) = case unFreeLeft x of Sealed y -> case toFL xs of Sealed ys -> Sealed (y :>: ys) dropWhileFL :: (FORALL(x y) a C(x y) -> Bool) -> FL a C(r v) -> FlippedSeal (FL a) C(v) dropWhileFL _ NilFL = flipSeal NilFL dropWhileFL p xs@(x:>:xs') | p x = dropWhileFL p xs' | otherwise = flipSeal xs dropWhileRL :: (FORALL(x y) a C(x y) -> Bool) -> RL a C(r v) -> Sealed (RL a C(r)) dropWhileRL _ NilRL = seal NilRL dropWhileRL p xs@(x:<:xs') | p x = dropWhileRL p xs' | otherwise = seal xs -- |Check that two 'FL's are equal element by element. -- This differs from the 'MyEq' instance for 'FL' which -- uses commutation. eqFL :: MyEq a => FL a C(x y) -> FL a C(x z) -> EqCheck C(y z) eqFL NilFL NilFL = IsEq eqFL (x:>:xs) (y:>:ys) | IsEq <- x =\/= y, IsEq <- eqFL xs ys = IsEq eqFL _ _ = NotEq eqFLRev :: MyEq a => FL a C(x z) -> FL a C(y z) -> EqCheck C(x y) eqFLRev NilFL NilFL = IsEq eqFLRev (x:>:xs) (y:>:ys) | IsEq <- eqFLRev xs ys, IsEq <- x =/\= y = IsEq eqFLRev _ _ = NotEq eqFLUnsafe :: MyEq a => FL a C(x y) -> FL a C(z w) -> Bool eqFLUnsafe NilFL NilFL = True eqFLUnsafe (x:>:xs) (y:>:ys) = unsafeCompare x y && eqFLUnsafe xs ys eqFLUnsafe _ _ = False darcs-2.8.4/src/Darcs/Witnesses/Sealed.hs0000644001765600176560000001400612104371431017502 0ustar ganeshganesh-- Copyright (C) 2007 David Roundy, 2009 Ganesh Sittampalam -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP, FlexibleInstances #-} #include "gadts.h" module Darcs.Witnesses.Sealed ( Sealed(..), seal, unseal, mapSeal, unsafeUnseal, unsafeUnsealFlipped, unsafeUnseal2, Sealed2(..), seal2, unseal2, mapSeal2, FlippedSeal(..), flipSeal, unsealFlipped, mapFlipped, unsealM, liftSM, Gap(..), FreeLeft, unFreeLeft, FreeRight, unFreeRight ) where import Darcs.Witnesses.Eq ( MyEq, EqCheck(..) ) import Darcs.Witnesses.Show import Darcs.Witnesses.Eq ( (=\/=) ) import Darcs.Witnesses.Unsafe ( unsafeCoerceP1, unsafeCoerceP ) data Sealed a where Sealed :: a C(x ) -> Sealed a seal :: a C(x ) -> Sealed a seal = Sealed instance MyEq a => Eq (Sealed (a C(x ))) where Sealed x == Sealed y | IsEq <- x =\/= y = True | otherwise = False data Sealed2 a where Sealed2 :: !(a C(x y )) -> Sealed2 a seal2 :: a C(x y ) -> Sealed2 a seal2 = Sealed2 data FlippedSeal a C(y) where FlippedSeal :: !(a C(x y)) -> FlippedSeal a C(y) flipSeal :: a C(x y) -> FlippedSeal a C(y) flipSeal = FlippedSeal unsafeUnseal :: Sealed a -> a C(x) unsafeUnseal (Sealed a) = unsafeCoerceP1 a unsafeUnsealFlipped :: FlippedSeal a C(y) -> a C(x y) unsafeUnsealFlipped (FlippedSeal a) = unsafeCoerceP a unsafeUnseal2 :: Sealed2 a -> a C(x y) unsafeUnseal2 (Sealed2 a) = unsafeCoerceP a unseal :: (FORALL(x) a C(x ) -> b) -> Sealed a -> b unseal f x = f (unsafeUnseal x) -- laziness property: -- unseal (const True) undefined == True unsealM :: Monad m => m (Sealed a) -> (FORALL(x) a C(x) -> m b) -> m b unsealM m1 m2 = do sx <- m1 unseal m2 sx liftSM :: Monad m => (FORALL(x) a C(x) -> b) -> m (Sealed a) -> m b liftSM f m = do sx <- m return (unseal f sx) mapSeal :: (FORALL(x) a C(x ) -> b C(x )) -> Sealed a -> Sealed b mapSeal f = unseal (seal . f) mapFlipped :: (FORALL(x) a C(x y) -> b C(x z)) -> FlippedSeal a C(y) -> FlippedSeal b C(z) mapFlipped f (FlippedSeal x) = FlippedSeal (f x) unseal2 :: (FORALL(x y) a C(x y ) -> b) -> Sealed2 a -> b unseal2 f a = f (unsafeUnseal2 a) mapSeal2 :: (FORALL(x y) a C(x y ) -> b C(x y )) -> Sealed2 a -> Sealed2 b mapSeal2 f = unseal2 (seal2 . f) unsealFlipped :: (FORALL(x y) a C(x y) -> b) -> FlippedSeal a C(z) -> b unsealFlipped f (FlippedSeal a) = f a instance Show1 a => Show (Sealed a) where showsPrec d (Sealed x) = showParen (d > appPrec) $ showString "Sealed " . showsPrec1 (appPrec + 1) x instance Show2 a => Show (Sealed2 a) where showsPrec d (Sealed2 x) = showParen (d > appPrec) $ showString "Sealed2 " . showsPrec2 (appPrec + 1) x -- |'Poly' is similar to 'Sealed', but the type argument is -- universally quantified instead of being existentially quantified. newtype Poly a = Poly { unPoly :: FORALL(x) a C(x) } -- |'Stepped' is a type level composition operator. -- For example, 'Stepped Sealed p' is equivalent to 'lambda x . Sealed (p x)' newtype Stepped (f :: SEALEDPATCHKIND -> *) a C(x) = Stepped { unStepped :: f (a C(x)) } -- |'FreeLeft p' is '\forall x . \exists y . p x y' -- In other words the caller is free to specify the left witness, -- and then the right witness is an existential. -- Note that the order of the type constructors is important for ensuring -- that 'y' is dependent on the 'x' that is supplied. -- This is why 'Stepped' is needed, rather than writing the more obvious -- 'Sealed (Poly p)' which would notionally have the same quantification -- of the type witnesses. newtype FreeLeft p = FLInternal (Poly (Stepped Sealed p)) -- |'FreeLeft p' is '\forall y . \exists x . p x y' -- In other words the caller is free to specify the right witness, -- and then the left witness is an existential. -- Note that the order of the type constructors is important for ensuring -- that 'x' is dependent on the 'y' that is supplied. newtype FreeRight p = FRInternal (Poly (FlippedSeal p)) -- |Unwrap a 'FreeLeft' value unFreeLeft :: FreeLeft p -> Sealed (p C(x)) unFreeLeft (FLInternal x) = unStepped (unPoly x) -- |Unwrap a 'FreeRight' value unFreeRight :: FreeRight p -> FlippedSeal p C(x) unFreeRight (FRInternal x) = unPoly x -- |'Gap' abstracts over 'FreeLeft' and 'FreeRight' for code constructing these values class Gap w where -- |An empty 'Gap', e.g. 'NilFL' or 'NilRL' emptyGap :: (FORALL(x) p C(x x)) -> w p -- |A 'Gap' constructed from a completely polymorphic value, for example the constructors -- for primitive patches freeGap :: (FORALL(x y) p C(x y)) -> w p -- |Compose two 'Gap' values together in series, e.g. 'joinGap (+>+)' or 'joinGap (:>:)' joinGap :: (FORALL(x y z) p C(x y) -> q C(y z) -> r C(x z)) -> w p -> w q -> w r instance Gap FreeLeft where emptyGap e = FLInternal (Poly (Stepped (Sealed e))) freeGap e = FLInternal (Poly (Stepped (Sealed e))) joinGap op (FLInternal p) (FLInternal q) = FLInternal (Poly (case unPoly p of Stepped (Sealed p') -> case unPoly q of Stepped (Sealed q') -> Stepped (Sealed (p' `op` q')))) instance Gap FreeRight where emptyGap e = FRInternal (Poly (FlippedSeal e)) freeGap e = FRInternal (Poly (FlippedSeal e)) joinGap op (FRInternal p) (FRInternal q) = FRInternal (Poly (case unPoly q of FlippedSeal q' -> case unPoly p of FlippedSeal p' -> FlippedSeal (p' `op` q'))) darcs-2.8.4/src/Darcs/Witnesses/Show.hs0000644001765600176560000000265612104371431017235 0ustar ganeshganesh{-# LANGUAGE CPP #-} module Darcs.Witnesses.Show(ShowDict(..), showD, showListD, showsPrecD, Show1(..), Show2(..), show1, showsPrec1, show2, showsPrec2, showOp2, appPrec) where #include "gadts.h" data ShowDict a where ShowDictClass :: Show a => ShowDict a ShowDictRecord :: (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> ShowDict a showsPrecD :: ShowDict a -> Int -> a -> ShowS showsPrecD ShowDictClass = showsPrec showsPrecD (ShowDictRecord showsPrecR _ _) = showsPrecR showD :: ShowDict a -> a -> String showD ShowDictClass = show showD (ShowDictRecord _ showR _) = showR showListD :: ShowDict a -> [a] -> ShowS showListD ShowDictClass = showList showListD (ShowDictRecord _ _ showListR) = showListR class Show1 a where showDict1 :: ShowDict (a C(x)) showsPrec1 :: Show1 a => Int -> a C(x) -> ShowS showsPrec1 = showsPrecD showDict1 show1 :: Show1 a => a C(x) -> String show1 = showD showDict1 class Show2 a where showDict2 :: ShowDict (a C(x y)) showsPrec2 :: Show2 a => Int -> a C(x y) -> ShowS showsPrec2 = showsPrecD showDict2 show2 :: Show2 a => a C(x y) -> String show2 = showD showDict2 showOp2 :: (Show2 a, Show2 b) => Int -> String -> Int -> a C(w x) -> b C(y z) -> String -> String showOp2 prec opstr d x y = showParen (d > prec) $ showsPrec2 (prec + 1) x . showString opstr . showsPrec2 (prec + 1) y appPrec :: Int appPrec = 10 darcs-2.8.4/src/Darcs/Witnesses/Unsafe.hs0000644001765600176560000000110612104371431017523 0ustar ganeshganesh{-# LANGUAGE MagicHash #-} #include "gadts.h" module Darcs.Witnesses.Unsafe ( unsafeCoerceP, unsafeCoercePStart, unsafeCoercePEnd, unsafeCoerceP2, unsafeCoerceP1 ) where import GHC.Base (unsafeCoerce#) unsafeCoerceP :: a C(x y) -> a C(b c) unsafeCoerceP = unsafeCoerce# unsafeCoercePStart :: a C(x1 y) -> a C(x2 y) unsafeCoercePStart = unsafeCoerce# unsafeCoercePEnd :: a C(x y1) -> a C(x y2) unsafeCoercePEnd = unsafeCoerce# unsafeCoerceP2 :: t C(w x y z) -> t C(a b c d) unsafeCoerceP2 = unsafeCoerce# unsafeCoerceP1 :: a C(x) -> a C(y) unsafeCoerceP1 = unsafeCoerce# darcs-2.8.4/src/Darcs/Witnesses/WZipper.hs0000644001765600176560000000547212104371431017714 0ustar ganeshganesh-- Copyright (C) 2009 Florent Becker -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP #-} #include "gadts.h" module Darcs.Witnesses.WZipper ( FZipper(..), focus, leftmost, left , rightmost, right, jokers, clowns , flToZipper, lengthFZ, nullFZ , toEnd, toStart ) where import Darcs.Witnesses.Ordered ( FL(..), RL(..), nullFL, nullRL , lengthFL, lengthRL, (+<+) , reverseFL, reverseRL, (+>+) ) import Darcs.Witnesses.Sealed(Sealed2(..), Sealed(..), FlippedSeal(..)) -- forward zipper data FZipper a C(x z) where FZipper :: RL a C(x y) -> FL a C(y z) -> FZipper a C(x z) -- Constructors flToZipper :: FL a C(x y) -> FZipper a C(x y) flToZipper l = FZipper NilRL l --destructors nullFZ :: FZipper a C(x y) -> Bool nullFZ (FZipper l r) = nullRL l && nullFL r lengthFZ :: FZipper a C(x y) -> Int lengthFZ (FZipper l r) = lengthRL l + lengthFL r focus :: FZipper a C(x y) -> Maybe (Sealed2 a) focus (FZipper _ (x :>: _)) = Just $ Sealed2 x focus _ = Nothing -- | \"Clowns to the left of me, jokers to the right. Here I am, stuck -- in the middle of you\" -- clowns :: FZipper a C(x y) -> Sealed ((RL a) C(x)) clowns (FZipper l _) = Sealed l -- | See 'clowns' jokers :: FZipper a C(x y) -> FlippedSeal (FL a) C(y) jokers (FZipper _ r) = FlippedSeal r rightmost :: FZipper p C(x y) -> Bool rightmost (FZipper _ NilFL) = True rightmost _ = False right :: FZipper p C(x y) -> FZipper p C(x y) right (FZipper l (b:>:r)) = FZipper (b :<: l) r right x@(FZipper _ NilFL) = x leftmost :: FZipper p C(x y) -> Bool leftmost (FZipper NilRL _) = True leftmost _ = False left :: FZipper p C(x y) -> FZipper p C(x y) left (FZipper (b :<: l) r) = FZipper l (b :>: r) left x@(FZipper NilRL _) = x toEnd :: FZipper p C(x y) -> FZipper p C(x y) toEnd (FZipper l r) = FZipper (reverseFL r +<+ l) NilFL toStart :: FZipper p C(x y) -> FZipper p C(x y) toStart (FZipper l r) = FZipper NilRL ((reverseRL l) +>+ r)darcs-2.8.4/src/Darcs/Test/0000755001765600176560000000000012104371431014703 5ustar ganeshganeshdarcs-2.8.4/src/Darcs/Test/Patch/0000755001765600176560000000000012104371431015742 5ustar ganeshganeshdarcs-2.8.4/src/Darcs/Test/Patch/Examples/0000755001765600176560000000000012104371431017520 5ustar ganeshganeshdarcs-2.8.4/src/Darcs/Test/Patch/Examples/Set1.hs0000644001765600176560000004356312104371431020703 0ustar ganeshganesh-- Copyright (C) 2002-2005,2007 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# OPTIONS_GHC -fno-warn-orphans -fno-warn-deprecations #-} {-# LANGUAGE CPP #-} module Darcs.Test.Patch.Examples.Set1 ( knownCommutes, knownCantCommutes, knownMerges , knownMergeEquivs, knownCanons, mergePairs2 , validPatches, commutePairs, mergePairs , primitiveTestPatches, testPatches, testPatchesNamed , primitiveCommutePairs ) where import System.IO.Unsafe ( unsafePerformIO ) import qualified Data.ByteString.Char8 as BC ( pack ) import qualified Data.ByteString as B ( empty ) import Darcs.Patch ( commute, invert, merge , Named, namepatch , readPatch, fromPrim , adddir, addfile, hunk, binary, rmdir, rmfile, tokreplace ) import Darcs.Patch.Prim ( PrimOf, FromPrim ) import Darcs.Patch.Prim.V1 ( Prim ) import qualified Darcs.Patch.V1 as V1 ( Patch ) import Darcs.Test.Patch.Properties.Check( checkAPatch ) import Darcs.Witnesses.Ordered import Darcs.Witnesses.Sealed ( unsafeUnseal ) import Darcs.Witnesses.Unsafe ( unsafeCoerceP, unsafeCoercePEnd ) #include "gadts.h" #include "impossible.h" type Patch = V1.Patch Prim -- The unit tester function is really just a glorified map for functions that -- return lists, in which the lists get concatenated (where map would end up -- with a list of lists). quickmerge :: (FL Patch :\/: FL Patch) C(x y) -> FL Patch C(y z) quickmerge (p1:\/:p2) = case merge (p1:\/:p2) of _ :/\: p1' -> unsafeCoercePEnd p1' -- ---------------------------------------------------------------------- -- * Show/Read tests -- ---------------------------------------------------------------------- -- | This test involves calling 'show' to print a string describing a patch, -- and then using readPatch to read it back in, and making sure the patch we -- read in is the same as the original. Useful for making sure that I don't -- have any stupid IO bugs. -- ---------------------------------------------------------------------- -- * Canonization tests -- ---------------------------------------------------------------------- knownCanons :: [(FL Patch C(x y),FL Patch C(x y))] knownCanons = [(quickhunk 1 "abcde" "ab" :>: NilFL, quickhunk 3 "cde" "" :>: NilFL), (quickhunk 1 "abcde" "bd" :>: NilFL, quickhunk 1 "a" "" :>: quickhunk 2 "c" "" :>: quickhunk 3 "e" "" :>: NilFL), (quickhunk 4 "a" "b" :>: quickhunk 1 "c" "d" :>: NilFL, quickhunk 1 "c" "d" :>: quickhunk 4 "a" "b" :>: NilFL), (quickhunk 1 "a" "" :>: quickhunk 1 "" "b" :>: NilFL, quickhunk 1 "a" "b" :>: NilFL), (quickhunk 1 "ab" "c" :>: quickhunk 1 "cd" "e" :>: NilFL, quickhunk 1 "abd" "e" :>: NilFL), (quickhunk 1 "abcde" "cde" :>: NilFL, quickhunk 1 "ab" "" :>: NilFL), (quickhunk 1 "abcde" "acde" :>: NilFL, quickhunk 2 "b" "" :>: NilFL)] quickhunk :: (FromPrim p, PrimOf p ~ Prim) => Int -> String -> String -> p C(x y) quickhunk l o n = fromPrim $ hunk "test" l (map (\c -> BC.pack [c]) o) (map (\c -> BC.pack [c]) n) -- ---------------------------------------------------------------------- -- * Merge/unmgerge tests -- ---------------------------------------------------------------------- -- | It should always be true that if two patches can be unmerged, then merging -- the resulting patches should give them back again. mergePairs :: [(FL Patch :\/: FL Patch) C(x y)] mergePairs = take 400 [(p1:\/:p2)| i <- [0..(length testPatches)-1], p1<-[testPatches!!i], p2<-drop i testPatches, checkAPatch (invert p2 :>: p1 :>: NilFL)] -- ---------------------------------------------------------------------- -- * Commute/recommute tests -- ---------------------------------------------------------------------- -- | Here we test to see if commuting patch A and patch B and then commuting -- the result gives us patch A and patch B again. The set of patches (A,B) -- is chosen from the set of all pairs of test patches by selecting those which -- commute with one another. commutePairs :: [(FL Patch :> FL Patch) C(x y)] commutePairs = take 200 [(p1:>p2)| p1<-testPatches, p2<-filter (\p->checkAPatch (p1:>:p:>:NilFL)) testPatches, commute (p1:>p2) /= Nothing] primitiveCommutePairs :: [(FL Patch :> FL Patch) C(x y)] primitiveCommutePairs = [(p2:>p1)| p1<-primitiveTestPatches, p2<-primitiveTestPatches, commute (p2:>p1) /= Nothing, checkAPatch (p2:>:p1:>:NilFL)] -- ---------------------------------------------------------------------- -- * Commute tests -- ---------------------------------------------------------------------- -- | Here we provide a set of known interesting commutes. knownCommutes :: [((FL Patch:: quickhunk 6 "d" "ef" :>: NilFL):\/: (quickhunk 3 "a" "bc" :>: quickhunk 8 "d" "ef" :>: NilFL), (quickhunk 1 "a" "bc" :>: quickhunk 7 "d" "ef" :>: NilFL)), (testhunk 1 [BC.pack "A"] [BC.pack "B"]:\/: testhunk 2 [BC.pack "B"] [BC.pack "C"], testhunk 1 [BC.pack "A"] [BC.pack "B"]), (testhunk 2 [BC.pack "A"] [BC.pack "B",BC.pack "C"]:\/: testhunk 1 [BC.pack "B"] [BC.pack "C",BC.pack "D"], testhunk 3 [BC.pack "A"] [BC.pack "B",BC.pack "C"])] where testhunk l o n = fromPrim $ hunk "test" l o n knownMergeEquivs :: [((FL Patch :\/: FL Patch) C(x y), FL Patch C(y z))] knownMergeEquivs = [ -- The following tests are going to be failed by the -- Conflictor code as a cleanup. --(addfile "test":\/: -- adddir "test", -- joinPatches (adddir "test" :>: -- addfile "test-conflict" :>: NilFL)), --(move "silly" "test":\/: -- adddir "test", -- joinPatches (adddir "test" :>: -- move "silly" "test-conflict" :>: NilFL)), --(addfile "test":\/: -- move "old" "test", -- joinPatches (addfile "test" :>: -- move "old" "test-conflict" :>: NilFL)), --(move "a" "test":\/: -- move "old" "test", -- joinPatches (move "a" "test" :>: -- move "old" "test-conflict" :>: NilFL)), (fromPrim (hunk "test" 1 [] [BC.pack "A"]) :\/: fromPrim (hunk "test" 1 [] [BC.pack "B"]), fromPrim (hunk "test" 1 [] [BC.pack "A", BC.pack "B"])), (fromPrim (hunk "test" 1 [] [BC.pack "a"]):\/: fromPrim (hunk "test" 1 [BC.pack "b"] []), unsafeCoerceP NilFL), --hunk "test" 1 [] [BC.pack "v v v v v v v", -- BC.pack "*************", -- BC.pack "a", -- BC.pack "b", -- BC.pack "^ ^ ^ ^ ^ ^ ^"]), (quickhunk 4 "a" "" :\/: quickhunk 3 "a" "", quickhunk 3 "aa" ""), ((quickhunk 1 "a" "bc" :>: quickhunk 6 "d" "ef" :>: NilFL) :\/: (quickhunk 3 "a" "bc" :>: quickhunk 8 "d" "ef" :>: NilFL), quickhunk 3 "a" "bc" :>: quickhunk 8 "d" "ef" :>: quickhunk 1 "a" "bc" :>: quickhunk 7 "d" "ef" :>: NilFL), (quickmerge (quickhunk 2 "" "bd":\/:quickhunk 2 "" "a") :\/: quickmerge (quickhunk 2 "" "c":\/:quickhunk 2 "" "a"), quickhunk 2 "" "abdc") ] -- | It also is useful to verify that it doesn't matter which order we specify -- the patches when we merge. mergePairs2 :: [(FL Patch C(x y), FL Patch C(x z))] mergePairs2 = [(p1, p2) | p1<-primitiveTestPatches, p2<-primitiveTestPatches, checkAPatch (invert p1:>:p2:>:NilFL) ] -- ---------------------------------------------------------------------- -- Patch test data -- This is where we define the set of patches which we run our tests on. This -- should be kept up to date with as many interesting permutations of patch -- types as possible. -- ---------------------------------------------------------------------- testPatches :: [FL Patch C(x y)] testPatchesNamed :: [Named Patch C(x y)] testPatchesAddfile :: [FL Patch C(x y)] testPatchesRmfile :: [FL Patch C(x y)] testPatchesHunk :: [FL Patch C(x y)] primitiveTestPatches :: [FL Patch C(x y)] testPatchesBinary :: [FL Patch C(x y)] testPatchesCompositeNocom :: [FL Patch C(x y)] testPatchesComposite :: [FL Patch C(x y)] testPatchesTwoCompositeHunks :: [FL Patch C(x y)] testPatchesCompositeHunks :: [FL Patch C(x y)] testPatchesCompositeFourHunks :: [FL Patch C(x y)] testPatchesMerged :: [FL Patch C(x y)] validPatches :: [FL Patch C(x y)] testPatchesNamed = [unsafePerformIO $ namepatch "date is" "patch name" "David Roundy" [] (fromPrim $ addfile "test"), unsafePerformIO $ namepatch "Sat Oct 19 08:31:13 EDT 2002" "This is another patch" "David Roundy" ["This log file has","two lines in it"] (fromPrim $ rmfile "test")] testPatchesAddfile = map fromPrim [addfile "test",adddir "test",addfile "test/test"] testPatchesRmfile = map invert testPatchesAddfile testPatchesHunk = [fromPrim (hunk file line old new) | file <- ["test"], line <- [1,2], old <- map (map BC.pack) partials, new <- map (map BC.pack) partials, old /= new ] where partials = [["A"],["B"],[],["B","B2"]] primitiveTestPatches = testPatchesAddfile ++ testPatchesRmfile ++ testPatchesHunk ++ [unsafeUnseal.fromJust.readPatch $ BC.pack "move ./test/test ./hello", unsafeUnseal.fromJust.readPatch $ BC.pack "move ./test ./hello"] ++ testPatchesBinary testPatchesBinary = [fromPrim $ binary "./hello" (BC.pack $ "agadshhdhdsa75745457574asdgg" ++ "a326424677373735753246463gadshhdhdsaasdgg" ++ "a326424677373735753246463gadshhdhdsaasdgg" ++ "a326424677373735753246463gadshhdhdsaasdgg") (BC.pack $ "adafjttkykrehhtrththrthrthre" ++ "a326424677373735753246463gadshhdhdsaasdgg" ++ "a326424677373735753246463gadshhdhdsaasdgg" ++ "a326424677373735753246463gadshhdhdsaagg"), fromPrim $ binary "./hello" B.empty (BC.pack "adafjttkykrere")] testPatchesCompositeNocom = take 50 [p1+>+p2| p1<-primitiveTestPatches, p2<-filter (\p->checkAPatch (p1:>:p:>:NilFL)) primitiveTestPatches, commute (p1:>p2) == Nothing] testPatchesComposite = take 100 [p1+>+p2| p1<-primitiveTestPatches, p2<-filter (\p->checkAPatch (p1:>:p:>:NilFL)) primitiveTestPatches, commute (p1:>p2) /= Nothing, commute (p1:>p2) /= Just (unsafeCoerceP p2:>unsafeCoerceP p1)] testPatchesTwoCompositeHunks = take 100 [p1+>+p2| p1<-testPatchesHunk, p2<-filter (\p->checkAPatch (p1:>:p:>:NilFL)) testPatchesHunk] testPatchesCompositeHunks = take 100 [p1+>+p2+>+p3| p1<-testPatchesHunk, p2<-filter (\p->checkAPatch (p1:>:p:>:NilFL)) testPatchesHunk, p3<-filter (\p->checkAPatch (p1:>:p2:>:p:>:NilFL)) testPatchesHunk] testPatchesCompositeFourHunks = take 100 [p1+>+p2+>+p3+>+p4| p1<-testPatchesHunk, p2<-filter (\p->checkAPatch (p1:>:p:>:NilFL)) testPatchesHunk, p3<-filter (\p->checkAPatch (p1:>:p2:>:p:>:NilFL)) testPatchesHunk, p4<-filter (\p->checkAPatch (p1:>:p2:>:p3:>:p:>:NilFL)) testPatchesHunk] testPatchesMerged = take 200 [p2+>+quickmerge (p1:\/:p2) | p1<-take 10 (drop 15 testPatchesCompositeHunks)++primitiveTestPatches ++take 10 (drop 15 testPatchesTwoCompositeHunks) ++ take 2 (drop 4 testPatchesCompositeFourHunks), p2<-take 10 testPatchesCompositeHunks++primitiveTestPatches ++take 10 testPatchesTwoCompositeHunks ++take 2 testPatchesCompositeFourHunks, checkAPatch (invert p1 :>: p2 :>: NilFL), commute (p2:>p1) /= Just (p1:>p2) ] testPatches = primitiveTestPatches ++ testPatchesComposite ++ testPatchesCompositeNocom ++ testPatchesMerged -- ---------------------------------------------------------------------- -- * Check patch test -- ---------------------------------------------------------------------- validPatches = [(quickhunk 4 "a" "b" :>: quickhunk 1 "c" "d" :>: NilFL), (quickhunk 1 "a" "bc" :>: quickhunk 1 "b" "d" :>: NilFL), (quickhunk 1 "a" "b" :>: quickhunk 1 "b" "d" :>: NilFL)]++testPatches darcs-2.8.4/src/Darcs/Test/Patch/Examples/Set2Unwitnessed.hs0000644001765600176560000006224612104371431023134 0ustar ganeshganesh-- Copyright (C) 2007 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# OPTIONS_GHC -fno-warn-deprecations -fno-warn-orphans #-} {-# LANGUAGE CPP #-} #include "gadts.h" module Darcs.Test.Patch.Examples.Set2Unwitnessed ( primPermutables, primPatches , commutables, commutablesFL , realCommutables , realMergeables, realTriples , realNonduplicateTriples, realPatches, realPatchLoopExamples ) where import Data.Maybe ( catMaybes ) import qualified Data.ByteString.Char8 as BC ( pack ) import Darcs.Witnesses.Sealed import Darcs.Patch ( invert, hunk ) import Darcs.Patch.Patchy ( Invert(..) ) import Darcs.Patch.Prim ( PrimPatch ) import Darcs.Patch.Prim.V1 ( Prim ) import Darcs.Patch.V2 ( RealPatch ) import Darcs.Patch.V2.Real ( prim2real ) -- import Darcs.Test.Patch.Test () -- for instance Eq Patch -- import Darcs.Test.Patch.Examples.Set2Unwitnessed import Darcs.Witnesses.Unsafe ( unsafeCoerceP ) import qualified Darcs.Test.Patch.Arbitrary.Real as W ( notDuplicatestriple ) --import Printer ( greenText ) --import Darcs.ColorPrinter ( traceDoc ) --import Darcs.ColorPrinter ( errorDoc ) import Darcs.ColorPrinter () -- for instance Show Doc import Darcs.Test.Patch.WSub import qualified Darcs.Witnesses.Ordered as W ( (:>), (:\/:) ) import qualified Data.ByteString as B ( ByteString ) import Darcs.Test.Patch.V1Model ( V1Model, Content , makeRepo, makeName, makeFile) import Darcs.Test.Patch.WithState ( WithStartState(..) ) import Darcs.Patch.Prim.V1.Core ( Prim(FP), FilePatchType(Hunk) ) import Darcs.Patch.FileName ( FileName, fp2fn ) import Darcs.Patch.Prim ( PrimPatchBase(..), FromPrim ) import Darcs.Patch.Merge ( Merge ) import Darcs.Test.Patch.Arbitrary.Generic ( Tree(..) , TreeWithFlattenPos(..) , commutePairFromTree, commuteTripleFromTree , mergePairFromCommutePair, commutePairFromTWFP , canonizeTree ) -- import Debug.Trace -- #include "impossible.h" makeSimpleRepo :: String -> Content -> V1Model C(x) makeSimpleRepo filename content = makeRepo [(makeName filename, makeFile content)] w_tripleExamples :: (FromPrim p, Merge p, Invert p, PrimPatchBase p, PrimOf p ~ Prim) => [Sealed2 (p W.:> p W.:> p)] w_tripleExamples = [commuteTripleFromTree seal2 $ WithStartState (makeSimpleRepo "file" []) (ParTree (SeqTree (FP (fp2fn "./file") (Hunk 1 [] [BC.pack "g"])) (SeqTree (FP (fp2fn "./file") (Hunk 2 [] [BC.pack "j"])) (SeqTree (FP (fp2fn "./file") (Hunk 1 [] [BC.pack "s"])) NilTree))) (SeqTree (FP (fp2fn "./file") (Hunk 1 [] [BC.pack "e"])) NilTree)) ,commuteTripleFromTree seal2 $ WithStartState (makeSimpleRepo "file" [BC.pack "j"]) (ParTree (SeqTree (FP (fp2fn "./file") (Hunk 1 [] [BC.pack "s"])) (ParTree (SeqTree (FP (fp2fn "./file") (Hunk 2 [BC.pack "j"] [])) NilTree) (SeqTree (FP (fp2fn "./file") (Hunk 2 [BC.pack "j"] [])) NilTree))) (SeqTree (FP (fp2fn "./file") (Hunk 1 [BC.pack "j"] [])) NilTree)) ] w_mergeExamples :: (FromPrim p, Merge p, Invert p, PrimPatchBase p, PrimOf p ~ Prim) => [Sealed2 (p W.:\/: p)] w_mergeExamples = map (unseal2 (mergePairFromCommutePair seal2)) w_commuteExamples w_commuteExamples :: (FromPrim p, Merge p, PrimPatchBase p, PrimOf p ~ Prim) => [Sealed2 (p W.:> p)] w_commuteExamples = [ commutePairFromTWFP seal2 $ WithStartState (makeSimpleRepo "file" []) (TWFP 3 (ParTree (SeqTree (FP (fp2fn "./file") (Hunk 1 [] [BC.pack "h"])) NilTree) (SeqTree (FP (fp2fn "./file") (Hunk 1 [] [BC.pack "b"])) (SeqTree (FP (fp2fn "./file") (Hunk 1 [] [BC.pack "f"])) (SeqTree (FP (fp2fn "./file") (Hunk 1 [] [BC.pack "v"])) (SeqTree (FP (fp2fn "./file") (Hunk 2 [BC.pack "f"] [])) NilTree)))))), commutePairFromTWFP seal2 $ WithStartState (makeSimpleRepo "file" [BC.pack "f",BC.pack "s",BC.pack "d"]) (TWFP 3 (ParTree (SeqTree (FP (fp2fn "./file") (Hunk 3 [BC.pack "d"] [])) NilTree) (ParTree (SeqTree (FP (fp2fn "./file") (Hunk 1 [BC.pack "f"] [])) NilTree) (SeqTree (FP (fp2fn "./file") (Hunk 1 [BC.pack "f"] [])) (SeqTree (FP (fp2fn "./file") (Hunk 1 [BC.pack "s",BC.pack "d"] [])) (SeqTree (FP (fp2fn "./file") (Hunk 1 [] [BC.pack "v"])) NilTree)))))), {- commutePairFromTWFP seal2 $ WithStartState (makeSimpleRepo "file" [BC.pack "f",BC.pack "u", BC.pack "s",BC.pack "d"]) (TWFP 5 (ParTree (SeqTree (FP (fp2fn "./file") (Hunk 5 [] [BC.pack "x"])) (SeqTree (FP (fp2fn "./file") (Hunk 4 [BC.pack "d"] [])) NilTree)) (ParTree (SeqTree (FP (fp2fn "./file") (Hunk 1 [BC.pack "f",BC.pack "u"] [])) NilTree) (SeqTree (FP (fp2fn "./file") (Hunk 1 [BC.pack "f"] [])) (SeqTree (FP(fp2fn "./file") (Hunk 1 [BC.pack "u",BC.pack "s",BC.pack "d"] [])) (SeqTree (FP (fp2fn "./file") (Hunk 1 [] [BC.pack "a"])) (SeqTree (FP (fp2fn "./file") (Hunk 1 [BC.pack "a"] [])) NilTree))))))),-} commutePairFromTree seal2 $ WithStartState (makeSimpleRepo "file" [BC.pack "n",BC.pack "t",BC.pack "h"]) (ParTree (SeqTree (FP (fp2fn "./file") (Hunk 1 [BC.pack "n",BC.pack "t",BC.pack "h"] [])) NilTree) (SeqTree (FP (fp2fn "./file") (Hunk 3 [BC.pack "h"] [])) (SeqTree (FP (fp2fn "./file") (Hunk 1 [BC.pack "n"] [])) (SeqTree (FP (fp2fn "./file") (Hunk 1 [BC.pack "t"] [])) NilTree)))), commutePairFromTree seal2 $ WithStartState (makeSimpleRepo "file" []) (ParTree (SeqTree (FP (fp2fn "./file") (Hunk 1 [] [BC.pack "n"])) NilTree) (SeqTree (FP (fp2fn "./file") (Hunk 1 [] [BC.pack "i"])) (SeqTree (FP (fp2fn "./file") (Hunk 1 [] [BC.pack "i"])) NilTree))), commutePairFromTree seal2 $ WithStartState (makeSimpleRepo "file" []) (ParTree (SeqTree (FP (fp2fn "./file") (Hunk 1 [] [BC.pack "c"])) (ParTree (SeqTree (FP (fp2fn "./file") (Hunk 1 [BC.pack "c"] [BC.pack "r"])) NilTree) (SeqTree (FP (fp2fn "./file") (Hunk 1 [] [BC.pack "h"])) (SeqTree (FP (fp2fn "./file") (Hunk 1 [] [BC.pack "d"])) NilTree)))) (SeqTree (FP (fp2fn "./file") (Hunk 1 [] [BC.pack "f"])) NilTree)), commutePairFromTWFP seal2 $ WithStartState (makeSimpleRepo "file" []) (TWFP 1 (ParTree (ParTree (SeqTree (FP (fp2fn "./file") (Hunk 1 [] [BC.pack "t"])) NilTree) (SeqTree (FP (fp2fn "./file") (Hunk 1 [] [BC.pack "t"])) NilTree)) (SeqTree (FP (fp2fn "./file") (Hunk 1 [] [BC.pack "f"])) NilTree))), commutePairFromTWFP seal2 $ WithStartState (makeSimpleRepo "file" [BC.pack "f",BC.pack " r", BC.pack "c",BC.pack "v"]) (TWFP 4 (ParTree (SeqTree (FP (fp2fn "./file") (Hunk 3 [BC.pack "c",BC.pack "v"] [])) (ParTree (SeqTree (FP (fp2fn "./file") (Hunk 2 [BC.pack "r"] [])) (SeqTree (FP (fp2fn "fi le") (Hunk 1 [BC.pack "f"] [])) NilTree)) (SeqTree (FP (fp2fn "./file") (Hunk 1 [BC.pack "f",BC.pack "r"] [])) (SeqTree (FP (fp2fn "./file") (Hunk 1 [] [BC.pack "y"])) NilTree)))) (SeqTree (FP (fp2fn "./file") (Hunk 4 [BC.pack "v"] [])) NilTree))), commutePairFromTree seal2 $ WithStartState (makeSimpleRepo "file" []) (ParTree (SeqTree (FP (fp2fn "./file") (Hunk 1 [] [BC.pack "z"])) NilTree) (ParTree (SeqTree (FP (fp2fn "./file") (Hunk 1 [] [BC.pack "f"])) NilTree) (ParTree (SeqTree (FP (fp2fn "./file") (Hunk 1 [] [BC.pack "r"])) NilTree) (SeqTree (FP (fp2fn "./file") (Hunk 1 [] [BC.pack "d"])) NilTree)))) , commutePairFromTree seal2 $ WithStartState (makeSimpleRepo "file" [BC.pack "t",BC.pack "r",BC.pack "h"]) (ParTree (ParTree (SeqTree (FP (fp2fn "./file") (Hunk 1 [BC.pack "t",BC.pack "r",BC.pack "h"] [])) NilTree) (SeqTree (FP (fp2fn "./file") (Hunk 1 [] [BC.pack "o"])) NilTree)) (SeqTree (FP (fp2fn "./file") (Hunk 1 [BC.pack "t"] [])) (SeqTree (FP (fp2fn "./file") (Hunk 2 [BC.pack "h"] [])) NilTree))) , commutePairFromTWFP seal2 $ WithStartState (makeSimpleRepo "file" []) $ TWFP 2 (ParTree (SeqTree (FP (fp2fn "./file") (Hunk 1 [] [BC.pack "h"])) NilTree) (SeqTree (FP (fp2fn "./file") (Hunk 1 [] [BC.pack "y"])) (SeqTree (FP (fp2fn "./file") (Hunk 2 [] [BC.pack "m"])) (SeqTree (FP (fp2fn "./file") (Hunk 1 [] [BC.pack "v"])) NilTree)))) , commutePairFromTree seal2 $ WithStartState (makeSimpleRepo "file" []) (ParTree (SeqTree (FP (fp2fn "./file") (Hunk 1 [] [BC.pack "p"])) (SeqTree (FP (fp2fn "./file") (Hunk 1 [BC.pack "p"] [])) (SeqTree (FP (fp2fn "./file") (Hunk 1 [] [BC.pack "c"])) NilTree))) (SeqTree (FP (fp2fn "./file") (Hunk 1 [] [BC.pack "z"])) NilTree)) , commutePairFromTree seal2 $ WithStartState (makeSimpleRepo "file" []) (ParTree (SeqTree (FP (fp2fn "./file") (Hunk 1 [] [BC.pack "j" ])) (SeqTree (FP (fp2fn "./file") (Hunk 1 [BC.pack "j"] [])) NilTree)) (SeqTree (FP (fp2fn "./file") (Hunk 1 [] [BC.pack "v"])) NilTree)) , commutePairFromTree seal2 $ WithStartState (makeSimpleRepo "file" []) (ParTree (SeqTree (FP (fp2fn "./file") (Hunk 1 [] [BC.pack "v"])) NilTree) (SeqTree (FP (fp2fn "./file") (Hunk 1 [] [BC.pack "j" ])) (SeqTree (FP (fp2fn "./file") (Hunk 1 [BC.pack "j"] [])) NilTree))) , commutePairFromTree seal2 $ WithStartState (makeSimpleRepo "file" [BC.pack "x",BC.pack "c"]) (ParTree (SeqTree (FP (fp2fn "./file") (Hunk 1 [] [BC.pack "h"])) (ParTree (SeqTree (FP (fp2fn "./file") (Hunk 3 [BC.pack "c"] [])) NilTree) (SeqTree (FP (fp2fn "./file") (Hunk 2 [BC.pack "x"] [])) (SeqTree (FP (fp2fn "./file") (Hunk 1 [] [BC.pack "j"])) NilTree)))) (SeqTree (FP (fp2fn "./file") (Hunk 1 [] [BC.pack "l"])) NilTree)) , commutePairFromTree seal2 $ WithStartState (makeSimpleRepo "file" []) (ParTree (SeqTree (FP (fp2fn "./file") (Hunk 1 [] (packStringLetters "s"))) NilTree) (SeqTree (FP (fp2fn "./file") (Hunk 1 [] (packStringLetters "k"))) (SeqTree (FP (fp2fn "./file") (Hunk 1 (packStringLetters "k") [])) (SeqTree (FP (fp2fn "./file") (Hunk 1 [] (packStringLetters "m"))) (SeqTree (FP (fp2fn "./file") (Hunk 1 (packStringLetters "m") [])) NilTree))))) ] packStringLetters :: String -> [B.ByteString] packStringLetters = map (BC.pack . (:[])) w_realPatchLoopExamples :: [Sealed (WithStartState V1Model (Tree Prim))] w_realPatchLoopExamples = [Sealed (WithStartState (makeSimpleRepo fx_name []) $ canonizeTree (ParTree (SeqTree (FP fx (Hunk 1 [] (packStringLetters "pkotufogbvdabnmbzajvolwviqebieonxvcvuvigkfgybmqhzuaaurjspd"))) (ParTree (SeqTree (FP fx (Hunk 47 (packStringLetters "qhzu") (packStringLetters "zafybdcokyjskcgnvhkbzpysaafnjjhcstgrczplxsfwagmh"))) (ParTree (ParTree NilTree (ParTree (ParTree (ParTree (SeqTree (FP fx (Hunk 15 (packStringLetters "mbzajvolwviqebieonxvcvuvigkfgyb") (packStringLetters "vujnxnhvybvpouyciaabszfmgssezlwwjgnethvrpnfrkubphzvdgymjjoacppqps"))) (ParTree NilTree (ParTree (SeqTree (FP fx (Hunk 40 (packStringLetters "ssezlwwjgnethvrpnfrkubphzvdgymjjoacppqpsmzafybdcokyjskcgnvhkbz") (packStringLetters "wnesidpccwoiqiichxaaejdsyrhrusqljlcoro"))) (ParTree (ParTree (SeqTree (FP fx (Hunk 12 (packStringLetters "abnvujnxnhvybvpouyciaabszfmgwnesidpccwoiqii") (packStringLetters "czfdhqkipdstfjycqaxwnbxrihrufdeyneqiiiafwzlmg"))) NilTree) NilTree) NilTree)) (SeqTree (FP fx (Hunk 25 [] (packStringLetters "dihgmsotezucqdgxczvcivijootyvhlwymbiueufnvpwpeukmskqllalfe"))) NilTree)))) (SeqTree (FP fx (Hunk 56 (packStringLetters "yjskcgnvhkbzpysaafnjjhcstgrczplxsfwagmhaaurjsp") (packStringLetters "xldhrutyhcyaqeezwujiguawfyawjjqlirxshjddvq"))) NilTree)) (SeqTree (FP fx (Hunk 20 [] (packStringLetters "ooygwiyogqrqnytixqtmvdxx"))) (SeqTree (FP fx (Hunk 26 (packStringLetters "yogqrqnytixqtmvdxxvolwviqebieonxvcvuvigkfgybmzafybdcokyjskcgnvhkbz") (packStringLetters "akhsmlbkdxnvfoikmiatfbpzdrsyykkpoxvvddeaspzxe"))) (SeqTree (FP fx (Hunk 39 [] (packStringLetters "ji"))) (ParTree NilTree (ParTree NilTree (ParTree (ParTree NilTree (SeqTree (FP fx (Hunk 26 (packStringLetters "akhsmlbkdxnvfjioikmiatfbpzdrsyykkpoxvvddeaspzxepysaafnjjhcstgrczplxs") (packStringLetters "onjbhddskcj"))) (SeqTree (FP fx (Hunk 39 [] (packStringLetters "fyscunxxxjjtyqpfxeznhtwvlphmp"))) NilTree))) (ParTree NilTree (SeqTree (FP fx (Hunk 44 [] (packStringLetters "xcchzwmzoezxkmkhcmesplnjpqriypshgiqklgdnbmmkldnydiy"))) (ParTree NilTree (SeqTree (FP fx (Hunk 64 (packStringLetters "plnjpqriypshgiqklgdnbmmkldnydiymiatfbpzdrsyykkpoxvvddeaspzxepysaafn") (packStringLetters "anjlzfdqbjqbcplvqvkhwjtkigp"))) NilTree))))))))))) (ParTree NilTree NilTree))) NilTree)) NilTree)) (ParTree NilTree (SeqTree (FP fx (Hunk 1 [] (packStringLetters "ti"))) (SeqTree (FP fx (Hunk 1 (packStringLetters "t") (packStringLetters "ybcop"))) (SeqTree (FP fx (Hunk 2 [] (packStringLetters "dvlhgwqlpaeweerqrhnjtfolczbqbzoccnvdsyqiefqitrqneralf"))) (SeqTree (FP fx (Hunk 15 [] (packStringLetters "yairbjphwtnaerccdlfewujvjvmjakbc"))) (SeqTree (FP fx (Hunk 51 [] (packStringLetters "xayvfuwaiiogginufnhsrmktpmlbvxiakjwllddkiyofyfw"))) (ParTree NilTree NilTree)))))))))] where fx_name :: String fx_name = "F" fx :: FileName fx = fp2fn "./F" mergeExamples :: [Sealed2 (RealPatch Prim :\/: RealPatch Prim)] mergeExamples = map (mapSeal2 fromW) w_mergeExamples realPatchLoopExamples :: [Sealed (WithStartState V1Model (Tree Prim))] realPatchLoopExamples = w_realPatchLoopExamples commuteExamples :: [Sealed2 (RealPatch Prim :> RealPatch Prim)] commuteExamples = map (mapSeal2 fromW) w_commuteExamples tripleExamples :: [Sealed2 (RealPatch Prim :> RealPatch Prim :> RealPatch Prim)] tripleExamples = map (mapSeal2 fromW) w_tripleExamples notDuplicatestriple :: (RealPatch Prim :> RealPatch Prim :> RealPatch Prim) C(x y) -> Bool notDuplicatestriple = W.notDuplicatestriple . toW quickhunk :: PrimPatch prim => Int -> String -> String -> prim C(x y) quickhunk l o n = hunk "test" l (map (\c -> BC.pack [c]) o) (map (\c -> BC.pack [c]) n) primPermutables :: [(Prim :> Prim :> Prim) C(x y)] primPermutables = [quickhunk 0 "e" "bo" :> quickhunk 3 "" "x" :> quickhunk 2 "f" "qljo"] mergeables :: [(Prim :\/: Prim) C(x y)] mergeables = [quickhunk 1 "a" "b" :\/: quickhunk 1 "a" "c", quickhunk 1 "a" "b" :\/: quickhunk 3 "z" "c", quickhunk 0 "" "a" :\/: quickhunk 1 "" "b", quickhunk 0 "a" "" :\/: quickhunk 1 "" "b", quickhunk 0 "a" "" :\/: quickhunk 1 "b" "", quickhunk 0 "" "a" :\/: quickhunk 1 "b" "" ] mergeablesFL :: [(FL Prim :\/: FL Prim) C(x y)] mergeablesFL = map (\ (x:\/:y) -> (x :>: NilFL) :\/: (y :>: NilFL)) mergeables ++ [] -- [(quickhunk 1 "a" "b" :>: quickhunk 3 "z" "c" :>: NilFL) -- :\/: (quickhunk 1 "a" "z" :>: NilFL), -- (quickhunk 1 "a" "b" :>: quickhunk 1 "b" "c" :>: NilFL) -- :\/: (quickhunk 1 "a" "z" :>: NilFL)] mergeable2commutable :: Invert p => (p :\/: p) C(x y) -> (p :> p) C(x y) mergeable2commutable (x :\/: y) = unsafeCoerceP (invert x) :> y commutablesFL :: [(FL Prim :> FL Prim) C(x y)] commutablesFL = map mergeable2commutable mergeablesFL commutables :: [(Prim :> Prim) C(x y)] commutables = map mergeable2commutable mergeables primPatches :: [Prim C(x y)] primPatches = concatMap mergeable2patches mergeables where mergeable2patches (x:\/:y) = [x,y] realPatches :: [RealPatch Prim C(x y)] realPatches = concatMap commutable2patches realCommutables where commutable2patches (x:>y) = [x,y] realTriples :: [(RealPatch Prim :> RealPatch Prim :> RealPatch Prim) C(x y)] realTriples = [ob' :> oa2 :> a2'', oa' :> oa2 :> a2''] ++ map unsafeUnseal2 tripleExamples ++ map unsafeUnseal2 (concatMap getTriples realFLs) where oa = prim2real $ quickhunk 1 "o" "aa" oa2 = oa a2 = prim2real $ quickhunk 2 "a34" "2xx" ob = prim2real $ quickhunk 1 "o" "bb" ob' :/\: oa' = merge (oa :\/: ob) a2' :/\: _ = merge (ob' :\/: a2) a2'' :/\: _ = merge (oa2 :\/: a2') realNonduplicateTriples :: [(RealPatch Prim :> RealPatch Prim :> RealPatch Prim) C(x y)] realNonduplicateTriples = filter (notDuplicatestriple) realTriples realFLs :: [FL (RealPatch Prim) C(x y)] realFLs = [oa :>: invert oa :>: oa :>: invert oa :>: ps +>+ oa :>: invert oa :>: NilFL] where oa = prim2real $ quickhunk 1 "o" "a" ps :/\: _ = merge (oa :>: invert oa :>: NilFL :\/: oa :>: invert oa :>: NilFL) realCommutables :: [(RealPatch Prim :> RealPatch Prim) C(x y)] realCommutables = map unsafeUnseal2 commuteExamples++ map mergeable2commutable realMergeables++ [invert oa :> ob'] ++ map unsafeUnseal2 (concatMap getPairs realFLs) where oa = prim2real $ quickhunk 1 "o" "a" ob = prim2real $ quickhunk 1 "o" "b" _ :/\: ob' = mergeFL (ob :\/: oa :>: invert oa :>: NilFL) realMergeables :: [(RealPatch Prim :\/: RealPatch Prim) C(x y)] realMergeables = map (\ (x :\/: y) -> prim2real x :\/: prim2real y) mergeables ++ realIglooMergeables ++ realQuickcheckMergeables ++ map unsafeUnseal2 mergeExamples ++ catMaybes (map pair2m (concatMap getPairs realFLs)) ++ [(oa :\/: od), (oa :\/: a2'), (ob' :\/: od''), (oe :\/: od), (of' :\/: oe'), (ob' :\/: oe'), (oa :\/: oe'), (ob' :\/: oc'), (b2' :\/: oc'''), (ob' :\/: a2), (b2' :\/: og'''), (oc''' :\/: og'''), (oc'' :\/: og''), (ob'' :\/: og''), (ob'' :\/: oc''), (oc' :\/: od'')] where oa = prim2real $ quickhunk 1 "o" "aa" a2 = prim2real $ quickhunk 2 "a34" "2xx" og = prim2real $ quickhunk 3 "4" "g" ob = prim2real $ quickhunk 1 "o" "bb" b2 = prim2real $ quickhunk 2 "b" "2" oc = prim2real $ quickhunk 1 "o" "cc" od = prim2real $ quickhunk 7 "x" "d" oe = prim2real $ quickhunk 7 "x" "e" pf = prim2real $ quickhunk 7 "x" "f" od'' = prim2real $ quickhunk 8 "x" "d" ob' :>: b2' :>: NilFL :/\: _ = mergeFL (oa :\/: ob :>: b2 :>: NilFL) a2' :/\: _ = merge (ob' :\/: a2) ob'' :/\: _ = merge (a2 :\/: ob') og' :/\: _ = merge (oa :\/: og) og'' :/\: _ = merge (a2 :\/: og') og''' :/\: _ = merge (ob' :\/: og') oc' :/\: _ = merge (oa :\/: oc) oc'' :/\: _ = merge (a2 :\/: oc) oc''' :/\: _ = merge (ob' :\/: oc') oe' :/\: _ = merge (od :\/: oe) of' :/\: _ = merge (od :\/: pf) pair2m :: Sealed2 (RealPatch Prim :> RealPatch Prim) -> Maybe ((RealPatch Prim :\/: RealPatch Prim) C(x y)) pair2m (Sealed2 (xx :> y)) = do y' :> _ <- commute (xx :> y) return $ unsafeCoerceP (xx :\/: y') realIglooMergeables :: [(RealPatch Prim :\/: RealPatch Prim) C(x y)] realIglooMergeables = [(a :\/: b), (b :\/: c), (a :\/: c), (x :\/: a), (y :\/: b), (z :\/: c), (x' :\/: y'), (z' :\/: y'), (x' :\/: z'), (a :\/: a)] where a = prim2real $ quickhunk 1 "1" "A" b = prim2real $ quickhunk 2 "2" "B" c = prim2real $ quickhunk 3 "3" "C" x = prim2real $ quickhunk 1 "1BC" "xbc" y = prim2real $ quickhunk 1 "A2C" "ayc" z = prim2real $ quickhunk 1 "AB3" "abz" x' :/\: _ = merge (a :\/: x) y' :/\: _ = merge (b :\/: y) z' :/\: _ = merge (c :\/: z) realQuickcheckMergeables :: [(RealPatch Prim :\/: RealPatch Prim) C(x y)] realQuickcheckMergeables = [-- invert k1 :\/: n1 --, invert k2 :\/: n2 hb :\/: k , b' :\/: b' , n' :\/: n' , b :\/: d , k' :\/: k' , k3 :\/: k3 ] ++ catMaybes (map pair2m pairs) where hb = prim2real $ quickhunk 0 "" "hb" k = prim2real $ quickhunk 0 "" "k" n = prim2real $ quickhunk 0 "" "n" b = prim2real $ quickhunk 1 "b" "" d = prim2real $ quickhunk 2 "" "d" d':/\:_ = merge (b :\/: d) --k1 :>: n1 :>: NilFL :/\: _ = mergeFL (hb :\/: k :>: n :>: NilFL) --k2 :>: n2 :>: NilFL :/\: _ = -- merge (hb :>: b :>: NilFL :\/: k :>: n :>: NilFL) k' :>: n' :>: NilFL :/\: _ :>: b' :>: _ = merge (hb :>: b :>: d' :>: NilFL :\/: k :>: n :>: NilFL) pairs = getPairs (hb :>: b :>: d' :>: k' :>: n' :>: NilFL) pair2m :: Sealed2 (RealPatch Prim :> RealPatch Prim) -> Maybe ((RealPatch Prim :\/: RealPatch Prim) C(x y)) pair2m (Sealed2 (xx :> y)) = do y' :> _ <- commute (xx :> y) return $ unsafeCoerceP (xx :\/: y') i = prim2real $ quickhunk 0 "" "i" x = prim2real $ quickhunk 0 "" "x" xi = prim2real $ quickhunk 0 "xi" "" d3 :/\: _ = merge (xi :\/: d) _ :/\: k3 = mergeFL (k :\/: i :>: x :>: xi :>: d3 :>: NilFL) darcs-2.8.4/src/Darcs/Test/Patch/Properties/0000755001765600176560000000000012104371431020076 5ustar ganeshganeshdarcs-2.8.4/src/Darcs/Test/Patch/Properties/V1Set1.hs0000644001765600176560000001455412104371431021466 0ustar ganeshganesh{-# LANGUAGE CPP #-} {-# OPTIONS_GHC -fno-warn-orphans #-} module Darcs.Test.Patch.Properties.V1Set1 ( checkMerge, checkMergeEquiv, checkMergeSwap, checkCanon , checkCommute, checkCantCommute , tShowRead , tMergeEitherWayValid, tTestCheck ) where import Darcs.Patch ( Patchy, commute, invert, merge, effect , readPatch, showPatch , fromPrim, canonize, sortCoalesceFL ) import Darcs.Patch.Prim.V1 ( Prim ) import Darcs.Patch.Merge ( Merge ) import qualified Darcs.Patch.V1 as V1 ( Patch ) import Darcs.Test.Patch.Properties.Check ( checkAPatch, Check ) import Printer ( renderPS ) import Darcs.Witnesses.Eq import Darcs.Witnesses.Ordered import Darcs.Witnesses.Show import Darcs.Witnesses.Sealed ( Sealed(Sealed) ) import Darcs.Witnesses.Unsafe( unsafeCoercePEnd ) import Darcs.Test.Util.TestResult import Printer ( text ) #include "gadts.h" type Patch = V1.Patch Prim quickmerge :: (Patchy p, Merge p) => (p :\/: p ) C(x y) -> p C(y z) quickmerge (p1:\/:p2) = case merge (p1:\/:p2) of _ :/\: p1' -> unsafeCoercePEnd p1' instance Show2 p => Show ((p :/\: p) C(x y)) where show (x :/\: y) = show2 x ++ " :/\\: " ++ show2 y instance Show2 p => Show ((p :< p) C(x y)) where show (x :< y) = show2 x ++ " :< " ++ show2 y instance MyEq p => Eq ((p :/\: p) C(x y)) where (x :/\: y) == (x' :/\: y') = isIsEq (x =\/= x') && isIsEq (y =\/= y') -- ---------------------------------------------------------------------------- -- A number of "comparison" properties: these carry out some operation on -- inputs (first value in the pair) and compare the results with a known -- expected value (the second value in the pair). -- checkMerge :: ((FL Patch:\/: FL Patch) C(x y), FL Patch C(y z)) -> TestResult checkMerge (p1:\/:p2,p1') = case merge (p1:\/:p2) of _ :/\: p1a -> if isIsEq (p1a `eqFL` p1') then succeeded else failed $ text $ "Merge gave wrong value!\n"++show p1++show p2 ++"I expected\n"++show p1' ++"but found instead\n"++show p1a checkMergeEquiv :: ((FL Patch:\/:FL Patch) C(x y),FL Patch C(y z)) -> TestResult checkMergeEquiv (p1:\/: p2, pe) = case quickmerge (p1:\/:p2) of p1' -> if checkAPatch (invert p1 :>: p2 :>: p1' :>: invert pe :>: NilFL) then succeeded else failed $ text $ "Oh no, merger isn't equivalent...\n"++show p1++"\n"++show p2 ++"in other words\n" ++ show (p1 :\/: p2) ++"merges as\n" ++ show (merge $ p1 :\/: p2) ++"merges to\n" ++ show (quickmerge $ p1 :\/: p2) ++"which is equivalent to\n" ++ show (effect p1') ++ "should all work out to\n" ++ show pe checkMergeSwap :: (FL Patch C(x y), FL Patch C(x z)) -> TestResult checkMergeSwap (p1, p2) = case merge (p2:\/:p1) of _ :/\: p2' -> case merge (p1:\/:p2) of _ :/\: p1' -> case commute (p1:>p2') of Just (_:>p1'b) -> if not $ p1'b `eqFLUnsafe` p1' then failed $ text $ "Merge swapping problem with...\np1 "++ show p1++"merged with\np2 "++ show p2++"p1' is\np1' "++ show p1'++"p1'b is\np1'b "++ show p1'b else succeeded Nothing -> failed $ text $ "Merge commuting problem with...\np1 "++ show p1++"merged with\np2 "++ show p2++"gives\np2' "++ show p2'++"which doesn't commute with p1.\n" checkCanon :: FORALL(x y) (FL Patch C(x y), FL Patch C(x y)) -> TestResult checkCanon (p1,p2) = if isIsEq $ eqFL p1_ p2 then succeeded else failed $ text $ "Canonization failed:\n"++show p1++"canonized is\n" ++show (p1_ :: FL Patch C(x y)) ++"which is not\n"++show p2 where p1_ = mapFL_FL fromPrim $ concatFL $ mapFL_FL canonize $ sortCoalesceFL $ effect p1 checkCommute :: ((FL Patch:< FL Patch) C(x y), (FL Patch:< FL Patch) C(x y)) -> TestResult checkCommute (p1:p1) of Just (p1a:>p2a) -> if (p2a:< p1a) == (p2':< p1') then succeeded else failed $ text $ "Commute gave wrong value!\n"++show p1++"\n"++show p2 ++"should be\n"++show p2'++"\n"++show p1' ++"but is\n"++show p2a++"\n"++show p1a Nothing -> failed $ text $ "Commute failed!\n"++show p1++"\n"++show p2 <&&> case commute (p1':>p2') of Just (p2a:>p1a) -> if (p1a:< p2a) == (p1:< p2) then succeeded else failed $ text $ "Commute gave wrong value!\n"++show p2a++"\n"++show p1a ++"should have been\n"++show p2'++"\n"++show p1' Nothing -> failed $ text $ "Commute failed!\n"++show p2'++"\n"++show p1' checkCantCommute :: (FL Patch:< FL Patch) C(x y) -> TestResult checkCantCommute (p1:p1) of Nothing -> succeeded _ -> failed $ text $ show p1 ++ "\n\n" ++ show p2 ++ "\nArgh, these guys shouldn't commute!\n" -- ---------------------------------------------------------------------------- -- A few "test" properties, doing things with input patches and giving a OK/not -- OK type of answer. tShowRead :: (Show2 p, Patchy p) => (FORALL(x y w z) p C(x y) -> p C(w z) -> Bool) -> FORALL(x y) p C(x y) -> TestResult tShowRead eq p = case readPatch $ renderPS $ showPatch p of Just (Sealed p') -> if p' `eq` p then succeeded else failed $ text $ "Failed to read shown: "++(show2 p)++"\n" Nothing -> failed $ text $ "Failed to read at all: "++(show2 p)++"\n" tMergeEitherWayValid :: FORALL(x y p) (Check p, Show2 p, Merge p, Patchy p) => (p :\/: p) C(x y) -> TestResult tMergeEitherWayValid (p1 :\/: p2) = case p2 :>: quickmerge (p1:\/: p2) :>: NilFL of combo2 -> case p1 :>: quickmerge (p2:\/: p1) :>: NilFL of combo1 -> if not $ checkAPatch combo1 then failed $ text $ "oh my combo1 invalid:\n"++show2 p1++"and...\n"++show2 p2++show combo1 else if checkAPatch (invert combo1 :>: combo2 :>: NilFL) then succeeded else failed $ text $ "merge both ways invalid:\n"++show2 p1++"and...\n"++show2 p2++ show combo1++ show combo2 tTestCheck :: FORALL(x y) FL Patch C(x y) -> TestResult tTestCheck p = if checkAPatch p then succeeded else failed $ text $ "Failed the check: "++show p++"\n" darcs-2.8.4/src/Darcs/Test/Patch/Properties/V1Set2.hs0000644001765600176560000003401212104371431021456 0ustar ganeshganesh-- Copyright (C) 2002-2003,2007 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP #-} #include "gadts.h" module Darcs.Test.Patch.Properties.V1Set2 ( propCommuteInverse, propPatchAndInverseIsIdentity , propSimpleSmartMergeGoodEnough, propCommuteEquivalency , propMergeValid, propInverseValid, propOtherInverseValid , propCommuteEitherOrder , propCommuteEitherWay, propCommuteTwice , propMergeIsCommutableAndCorrect, propMergeIsSwapable , checkSubcommutes , subcommutesInverse, subcommutesNontrivialInverse, subcommutesFailure , propReadShow -- TODO: these are exported temporarily to mark them as used -- Figure out whether to enable or remove the tests. , propUnravelThreeMerge, propUnravelSeqMerge , propUnravelOrderIndependent, propResolveConflictsValid ) where import Prelude hiding ( pi ) import Test.QuickCheck import Test.Framework.Providers.QuickCheck2 ( testProperty ) import Test.Framework ( Test ) import Data.Maybe ( isJust ) import Darcs.Test.Patch.Properties.Check ( Check, checkAPatch ) import Darcs.Patch ( invert, commute, merge, readPatch, resolveConflicts, fromPrim, showPatch ) import Darcs.Patch.Commute ( Commute ) import Darcs.Patch.Invert ( Invert ) import qualified Darcs.Patch.V1 as V1 ( Patch ) import Darcs.Patch.V1.Commute ( unravel, merger ) import Darcs.Patch.Prim.V1 () import Darcs.Patch.Prim.V1.Core ( Prim(..) ) import Darcs.Patch.Prim.V1.Commute ( WrappedCommuteFunction(..), Perhaps(..), subcommutes ) import Printer ( renderPS ) import Darcs.Witnesses.Eq import Darcs.Witnesses.Ordered import Darcs.Witnesses.Sealed ( Sealed(Sealed), unsafeUnseal, unseal, mapSeal, Sealed2(..) ) import Darcs.Witnesses.Unsafe #include "impossible.h" type Patch = V1.Patch Prim -- | Groups a set of tests by giving them the same prefix in their description. -- When this is called as @checkSubcommutes subcoms expl@, the prefix for a -- test becomes @"Checking " ++ expl ++ " for subcommute "@. checkSubcommutes :: Testable a => [(String, a)] -> String -> [Test] checkSubcommutes subcoms expl = map check_subcommute subcoms where check_subcommute (name, test) = let testName = expl ++ " for subcommute " ++ name in testProperty testName test propInverseValid :: Sealed2 (FL Patch) -> Bool propInverseValid (Sealed2 p1) = checkAPatch (invert p1:>:p1:>:NilFL) propOtherInverseValid :: Sealed2 (FL Patch) -> Bool propOtherInverseValid (Sealed2 p1) = checkAPatch (p1:>:invert p1:>:NilFL) propCommuteTwice :: Sealed2 (FL Patch :> FL Patch) -> Property propCommuteTwice (Sealed2 (p1:>p2)) = (doesCommute p1 p2) ==> (Just (p1:>p2) == (commute (p1:>p2) >>= commute)) doesCommute :: (MyEq p, Invert p, Commute p, Check p) => p C(x y) -> p C(y z) -> Bool doesCommute p1 p2 = commute (p1:>p2) /= Nothing && checkAPatch (p1:>:p2:>:NilFL) propCommuteEquivalency :: Sealed2 (FL Patch :> FL Patch) -> Property propCommuteEquivalency (Sealed2 (p1:>p2)) = (doesCommute p1 p2) ==> case commute (p1:>p2) of Just (p2':>p1') -> checkAPatch (p1:>:p2:>:invert p1':>:invert p2':>:NilFL) _ -> impossible propCommuteEitherWay :: Sealed2 (FL Patch :> FL Patch) -> Property propCommuteEitherWay (Sealed2 (p1:>p2)) = doesCommute p1 p2 ==> doesCommute (invert p2) (invert p1) propCommuteEitherOrder :: Sealed2 (FL Patch :> FL Patch :> FL Patch) -> Property propCommuteEitherOrder (Sealed2 (p1:>p2:>p3)) = checkAPatch (p1:>:p2:>:p3:>:NilFL) && doesCommute p1 (p2+>+p3) && doesCommute p2 p3 ==> case commute (p1:>p2) of Nothing -> False Just (p2':>p1') -> case commute (p1':>p3) of Nothing -> False Just (p3':>_) -> case commute (p2':>p3') of Nothing -> False Just (p3'' :> _) -> case commute (p2:>p3) of Nothing -> False Just (p3'a:>_) -> case commute (p1:>p3'a) of Just (p3''a:>_) -> isIsEq (p3''a =\/= p3'') Nothing -> False propPatchAndInverseIsIdentity :: Sealed2 (FL Patch :> FL Patch) -> Property propPatchAndInverseIsIdentity (Sealed2 (p1:>p2)) = checkAPatch (p1:>:p2:>:NilFL) && (commute (p1:>p2) /= Nothing) ==> case commute (p1:>p2) of Just (p2':>_) -> case commute (invert p1:>p2') of Nothing -> True -- This is a subtle distinction. Just (p2'':>_) -> isIsEq (p2'' =\/= p2) Nothing -> impossible propMergeIsCommutableAndCorrect :: Sealed2 (FL Patch :\/: FL Patch) -> Property propMergeIsCommutableAndCorrect (Sealed2 (p1:\/:p2)) = checkAPatch (invert p1:>:p2:>:NilFL) ==> case merge (p2:\/:p1) of p1' :/\: p2' -> case commute (p1:>p2') of Nothing -> False Just (p2'':>p1'') -> isIsEq (p2'' =\/= p2) && isIsEq (p1' =/\= p1'') propMergeIsSwapable :: Sealed2 (FL Patch :\/: FL Patch) -> Property propMergeIsSwapable (Sealed2 (p1:\/:p2)) = checkAPatch (invert p1:>:p2:>:NilFL) ==> case merge (p2:\/:p1) of p1' :/\: p2' -> case merge (p1:\/:p2) of p2''' :/\: p1''' -> isIsEq (p1' =\/= p1''') && isIsEq (p2' =\/= p2''') propMergeValid :: Sealed2 (FL Patch :\/: FL Patch) -> Property propMergeValid (Sealed2 (p1:\/:p2)) = checkAPatch (invert p1:>:p2:>:NilFL) ==> case merge (p2:\/:p1) of _ :/\: p2' -> checkAPatch (invert p1:>:p2:>:invert p2:>:p1:>:p2':>:NilFL) propSimpleSmartMergeGoodEnough :: Sealed2 (FL Patch :\/: FL Patch) -> Property propSimpleSmartMergeGoodEnough (Sealed2 (p1:\/:p2)) = checkAPatch (invert p1:>:p2:>:NilFL) ==> case simpleSmartMerge (p1 :\/: p2) of Nothing -> True Just (Sealed p1'a) -> isJust ((do p1o :> _ <- commute (p2 :> p1'a) IsEq <- return $ p1o =\/= p1 Sealed p2'a <- simpleSmartMerge (p2 :\/: p1) p2b :> p1'b <- commute (p1 :> p2'a) IsEq <- return $ p2 =\/= p2b IsEq <- return $ p1'a =\/= p1'b return ()) :: Maybe ()) simpleSmartMerge :: (Commute p, Invert p) => (p :\/: p) C(x y) -> Maybe (Sealed (p C(y))) simpleSmartMerge (p1 :\/: p2) = case commute (invert p2 :> p1) of Just (p1':>_) -> Just (Sealed p1') Nothing -> Nothing -- | The conflict resolution code (glump) begins by "unravelling" the merger -- into a set of sequences of patches. Each sequence of patches corresponds -- to one non-conflicted patch that got merged together with the others. The -- result of the unravelling of a series of merges must obviously be -- independent of the order in which those merges are performed. This -- unravelling code (which uses the unwind code mentioned above) uses probably -- the second most complicated algorithm. Fortunately, if we can successfully -- unravel the merger, almost any function of the unravelled merger satisfies -- the two constraints mentioned above that the conflict resolution code must -- satisfy. propUnravelThreeMerge :: Patch C(x y) -> Patch C(x z) -> Patch C(x w) -> Property propUnravelThreeMerge p1 p2 p3 = checkAPatch (invert p1:>:p2:>:invert p2:>:p3:>:NilFL) ==> (unravel $ unsafeUnseal $ merger "0.0" (unsafeUnseal (merger "0.0" p2 p3)) (unsafeUnseal (merger "0.0" p2 p1))) == (unravel $ unsafeUnseal $ merger "0.0" (unsafeUnseal (merger "0.0" p1 p3)) (unsafeUnseal (merger "0.0" p1 p2))) propUnravelSeqMerge :: Patch C(x y) -> Patch C(x z) -> Patch C(z w) -> Property propUnravelSeqMerge p1 p2 p3 = checkAPatch (invert p1:>:p2:>:p3:>:NilFL) ==> (unravel $ unsafeUnseal $ merger "0.0" p3 $ unsafeUnseal $ merger "0.0" p2 p1) == (unravel $ unsafeUnseal $ merger "0.0" (unsafeUnseal $ merger "0.0" p2 p1) p3) propUnravelOrderIndependent :: Patch C(x y) -> Patch C(x z) -> Property propUnravelOrderIndependent p1 p2 = checkAPatch (invert p1:>:p2:>:NilFL) ==> (unravel $ unsafeCoercePStart $ unsafeUnseal $ merger "0.0" p2 p1) == (unravel $ unsafeUnseal $ merger "0.0" p1 p2) propResolveConflictsValid :: Patch C(x y) -> Patch C(x z) -> Property propResolveConflictsValid p1 p2 = case merge (p1:\/:p2) of _ :/\: p1' -> let p = p2:>:p1':>:NilFL in checkAPatch (invert p1:>:p2:>:NilFL) ==> and $ map (\l -> (\ml -> checkAPatch (p+>+ml)) `unseal` mergeList l) $ resolveConflicts p mergeList :: [Sealed (FL Prim C(x))] -> Sealed (FL Patch C(x)) mergeList patches = mapFL_FL fromPrim `mapSeal` doml NilFL patches where doml :: FL Prim C(x y) -> [Sealed (FL Prim C(x))] -> Sealed (FL Prim C(x)) doml mp (Sealed p:ps) = case commute (invert p :> mp) of Just (mp' :> _) -> doml (p +>+ mp') ps Nothing -> doml mp ps -- This shouldn't happen for "good" resolutions. doml mp [] = Sealed mp propReadShow :: FL Patch C(x y) -> Bool propReadShow p = case readPatch $ renderPS $ showPatch p of Just (Sealed p') -> isIsEq (p' =\/= p) Nothing -> False -- |In order for merges to work right with commuted patches, inverting a patch -- past a patch and its inverse had golly well better give you the same patch -- back again. propCommuteInverse :: Sealed2 (FL Patch :> FL Patch) -> Property propCommuteInverse (Sealed2 (p1 :> p2)) = doesCommute p1 p2 ==> case commute (p1 :> p2) of Nothing -> impossible Just (_ :> p1') -> case commute (p1' :> invert p2) of Nothing -> False Just (_ :> p1'') -> isIsEq (p1'' =/\= p1) type CommuteProperty = Sealed2 (Prim :> Prim) -> Property subcommutesInverse :: [(String, CommuteProperty)] subcommutesInverse = zip names (map prop_subcommute cs) where (names, cs) = unzip subcommutes prop_subcommute c (Sealed2 (p1:>p2)) = does c p1 p2 ==> case runWrappedCommuteFunction c (p2:< p1) of Succeeded (p1': case runWrappedCommuteFunction c (invert p2:< p1') of Succeeded (p1'': isIsEq (p1'' =/\= p1) && case runWrappedCommuteFunction c (invert p1:< invert p2) of Succeeded (ip2':< ip1') -> case runWrappedCommuteFunction c (p2':< invert p1) of Succeeded (ip1o':< p2o) -> isJust ((do IsEq <- return $ invert ip1' =/\= p1' IsEq <- return $ invert ip2' =/\= p2' IsEq <- return $ ip1o' =/\= ip1' IsEq <- return $ p2o =\/= p2 IsEq <- return $ p1'' =/\= p1 IsEq <- return $ ip2x' =\/= ip2' return ()) :: Maybe ()) _ -> False _ -> False _ -> False _ -> False subcommutesNontrivialInverse :: [(String, CommuteProperty)] subcommutesNontrivialInverse = zip names (map prop_subcommute cs) where (names, cs) = unzip subcommutes prop_subcommute c (Sealed2 (p1 :> p2)) = nontrivial c p1 p2 ==> case runWrappedCommuteFunction c (p2:< p1) of Succeeded (p1': case runWrappedCommuteFunction c (invert p2:< p1') of Succeeded (p1'': isIsEq (p1'' =/\= p1) && case runWrappedCommuteFunction c (invert p1:< invert p2) of Succeeded (ip2':< ip1') -> case runWrappedCommuteFunction c (p2':< invert p1) of Succeeded (ip1o':< p2o) -> isJust ((do IsEq <- return $ invert ip1' =/\= p1' IsEq <- return $ invert ip2' =/\= p2' IsEq <- return $ ip1o' =/\= ip1' IsEq <- return $ p2o =\/= p2 IsEq <- return $ p1'' =/\= p1 IsEq <- return $ ip2x' =\/= ip2' return ()) :: Maybe ()) _ -> False _ -> False _ -> False _ -> False subcommutesFailure :: [(String, CommuteProperty)] subcommutesFailure = zip names (map prop cs) where (names, cs) = unzip subcommutes prop c (Sealed2 (p1 :> p2)) = doesFail c p1 p2 ==> case runWrappedCommuteFunction c (invert p1 :< invert p2) of Failed -> True _ -> False doesFail :: WrappedCommuteFunction -> Prim C(x y) -> Prim C(y z) -> Bool doesFail c p1 p2 = fails (runWrappedCommuteFunction c (p2:: p2 :>: NilFL) where fails Failed = True fails _ = False does :: WrappedCommuteFunction -> Prim C(x y) -> Prim C(y z) -> Bool does c p1 p2 = succeeds (runWrappedCommuteFunction c (p2:: p2 :>: NilFL) where succeeds (Succeeded _) = True succeeds _ = False nontrivial :: WrappedCommuteFunction -> Prim C(x y) -> Prim C(y z) -> Bool nontrivial c p1 p2 = succeeds (runWrappedCommuteFunction c (p2:: p2 :>: NilFL) where succeeds (Succeeded (p1' :< p2')) = not (p1' `unsafeCompare` p1 && p2' `unsafeCompare` p2) succeeds _ = False darcs-2.8.4/src/Darcs/Test/Patch/Properties/Generic.hs0000644001765600176560000004512312104371431022013 0ustar ganeshganesh-- Copyright (C) 2007 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP #-} {-# OPTIONS_GHC -fno-warn-deprecations -fno-warn-orphans #-} #include "gadts.h" module Darcs.Test.Patch.Properties.Generic ( invertSymmetry, inverseComposition, invertRollback, recommute, commuteInverses, effectPreserving, permutivity, partialPermutivity, patchAndInverseCommute, mergeEitherWay, show_read, mergeCommute, mergeConsistent, mergeArgumentsConsistent, joinEffectPreserving, joinCommute, propIsMergeable ) where import Darcs.Test.Util.TestResult ( TestResult, succeeded, failed, rejected, (<&&>), fromMaybe ) import Darcs.Test.Patch.RepoModel ( RepoModel, RepoState, repoApply, eqModel, showModel , maybeFail ) import Darcs.Test.Patch.WithState ( WithState(..), WithStartState(..) ) import Darcs.Test.Patch.Arbitrary.Generic ( Tree, flattenOne ) import Control.Monad ( msum ) import Darcs.Witnesses.Show ( Show2(..), show2 ) import Darcs.Patch.Patchy ( Patchy, showPatch, commute, invert ) import Darcs.Patch.Prim.Class ( PrimPatch, PrimOf, FromPrim ) import Darcs.Patch () import Darcs.Patch.Apply ( ApplyState ) import Darcs.Patch.Commute ( commuteFLorComplain ) import Darcs.Patch.Merge ( Merge(merge) ) import Darcs.Patch.Read ( readPatch ) import Darcs.Patch.Invert ( invertFL ) import Darcs.Witnesses.Eq ( MyEq(..), EqCheck(..), isIsEq ) import Darcs.Witnesses.Ordered ( FL(..), (:>)(..), (:\/:)(..), (:/\:)(..), lengthFL, eqFL, reverseRL ) import Darcs.Witnesses.Sealed ( Sealed(Sealed), seal2, Sealed2 ) import Printer ( Doc, renderPS, redText, greenText, ($$), text ) --import Darcs.ColorPrinter ( traceDoc ) propIsMergeable :: forall model p C(x) . (FromPrim p, Merge p, RepoModel model) => Sealed (WithStartState model (Tree (PrimOf p))) -> Maybe (Tree p C(x)) propIsMergeable (Sealed (WithStartState _ t)) = case flattenOne t of Sealed ps -> let _ = seal2 ps :: Sealed2 (FL p) in case lengthFL ps of _ -> Nothing -- | invert symmetry inv(inv(p)) = p invertSymmetry :: Patchy p => p C(a b) -> TestResult invertSymmetry p = case invert (invert p) =\/= p of IsEq -> succeeded NotEq -> failed $ redText "p /= inv(inv(p))" inverseComposition :: Patchy p => (p :> p) C(x y) -> TestResult inverseComposition (a :> b) = case eqFL (reverseRL (invertFL (a:>:b:>:NilFL))) (invert b:>:invert a:>:NilFL) of IsEq -> succeeded NotEq -> failed $ redText "inv(a :>: b :>: NilFL) /= inv(b) :>: inv(a) :>: NilFL" -- | invert rollback if b = A(a) then a = A'(b) invertRollback :: (ApplyState p ~ RepoState model, Patchy p, RepoModel model) => WithState model p C(a b) -> TestResult invertRollback (WithState a x b) = case maybeFail $ repoApply b (invert x) of Nothing -> failed $ redText "x' not applicable to b." Just a1 -> if a1 `eqModel` a then succeeded else failed $ redText "a1: " $$ text (showModel a1) $$ redText " ---- is not equals to a:" $$ text (showModel a) $$ redText "where a was" $$ text (showModel b) $$ redText "with (invert x) on top:" $$ showPatch (invert x) -- | recommute AB ↔ B′A′ if and only if B′A′ ↔ AB recommute :: Patchy p => (FORALL(x y) ((p :> p) C(x y) -> Maybe ((p :> p) C(x y)))) -> (p :> p) C(a b) -> TestResult recommute c (x :> y) = case c (x :> y) of Nothing -> rejected Just (y' :> x') -> case c (y' :> x') of Nothing -> failed (redText "failed" $$ showPatch y' $$ redText ":>" $$ showPatch x') Just (x'' :> y'') -> case y'' =/\= y of NotEq -> failed (redText "y'' =/\\= y failed, where x" $$ showPatch x $$ redText ":> y" $$ showPatch y $$ redText "y'" $$ showPatch y' $$ redText ":> x'" $$ showPatch x' $$ redText "x''" $$ showPatch x'' $$ redText ":> y''" $$ showPatch y'') IsEq -> case x'' =/\= x of NotEq -> failed (redText "x'' /= x" $$ showPatch x'' $$ redText ":>" $$ showPatch y'') IsEq -> succeeded -- | commuteInverses AB ↔ B′A′ if and only if Bâ»Â¹Aâ»Â¹ ↔ A′â»Â¹B′â»Â¹ commuteInverses :: Patchy p => (FORALL(x y) (p :> p) C(x y) -> Maybe ((p :> p) C(x y))) -> (p :> p) C(a b) -> TestResult commuteInverses c (x :> y) = case c (x :> y) of Nothing -> rejected Just (y' :> x') -> case c (invert y :> invert x) of Nothing -> failed $ redText "second commute failed" $$ redText "x" $$ showPatch x $$ redText "y" $$ showPatch y $$ redText "y'" $$ showPatch y' $$ redText "x'" $$ showPatch x' Just (ix' :> iy') -> case invert ix' =/\= x' of NotEq -> failed $ redText "invert ix' /= x'" $$ redText "x" $$ showPatch x $$ redText "y" $$ showPatch y $$ redText "y'" $$ showPatch y' $$ redText "x'" $$ showPatch x' $$ redText "ix'" $$ showPatch ix' $$ redText "iy'" $$ showPatch iy' $$ redText "invert ix'" $$ showPatch (invert ix') $$ redText "invert iy'" $$ showPatch (invert iy') IsEq -> case y' =\/= invert iy' of NotEq -> failed $ redText "y' /= invert iy'" $$ showPatch iy' $$ showPatch y' IsEq -> succeeded -- | effect preserving AB <--> B'A' then effect(AB) = effect(B'A') effectPreserving :: (Patchy p, RepoModel model, ApplyState p ~ RepoState model) => (FORALL(x y) (p :> p) C(x y) -> Maybe ((p :> p) C(x y))) -> WithState model (p :> p) C(a b) -> TestResult effectPreserving c (WithState r (x :> y) r') = case c (x :> y) of Nothing -> rejected Just (y' :> x') -> case maybeFail $ repoApply r y' of Nothing -> failed $ redText "y' is not applicable to r." Just r_y' -> case maybeFail $ repoApply r_y' x' of Nothing -> failed $ redText "x' is not applicable to r_y'." Just r_y'x' -> if r_y'x' `eqModel` r' then succeeded else failed $ redText "r_y'x' is not equal to r'." -- | patchAndInverseCommute If AB ↔ B′A′ then Aâ»Â¹B′ ↔ BA′â»Â¹ patchAndInverseCommute :: Patchy p => (FORALL(x y) (p :> p) C(x y) -> Maybe ((p :> p) C(x y))) -> (p :> p) C(a b) -> TestResult patchAndInverseCommute c (x :> y) = case c (x :> y) of Nothing -> rejected Just (y' :> x') -> case c (invert x :> y') of Nothing -> failed (redText "" $$ redText "-------- original commute (x :> y):" $$ showPatch x $$ redText ":>" $$ showPatch y $$ redText "-------- result (y' :> x'):" $$ showPatch y' $$ redText ":>" $$ showPatch x' $$ redText "-------- bad commute (invert x :> y'):" $$ showPatch (invert x) $$ redText ":>" $$ showPatch y') Just (y'' :> ix') -> case y'' =\/= y of NotEq -> failed (redText "y'' /= y" $$ redText "x" $$ showPatch x $$ redText "y" $$ showPatch y $$ redText "x'" $$ showPatch x' $$ redText "y'" $$ showPatch y' $$ redText "y''" $$ showPatch y'' $$ redText ":> x'" $$ showPatch x') IsEq -> case x' =\/= invert ix' of NotEq -> failed (redText "x' /= invert ix'" $$ redText "y''" $$ showPatch y'' $$ redText ":> x'" $$ showPatch x' $$ redText "invert x" $$ showPatch (invert x) $$ redText ":> y" $$ showPatch y $$ redText "y'" $$ showPatch y' $$ redText "ix'" $$ showPatch ix') IsEq -> succeeded permutivity :: Patchy p => (FORALL(x y) (p :> p) C(x y) -> Maybe ((p :> p) C(x y))) -> (p :> p :> p) C(a b) -> TestResult permutivity c (x:>y:>z) = case c (x :> y) of Nothing -> rejected Just (y1 :> x1) -> case c (y :> z) of Nothing -> rejected Just (z2 :> y2) -> case c (x :> z2) of Nothing -> rejected Just (z3 :> x3) -> case c (x1 :> z) of Nothing -> failed $ redText "permutivity1" Just (z4 :> x4) -> --traceDoc (greenText "third commuted" $$ -- greenText "about to commute" $$ -- greenText "y1" $$ showPatch y1 $$ -- greenText "z4" $$ showPatch z4) $ case c (y1 :> z4) of Nothing -> failed $ redText "permutivity2" Just (z3_ :> y4) | IsEq <- z3_ =\/= z3 -> --traceDoc (greenText "passed z3") $ error "foobar test" $ case c (y4 :> x4) of Nothing -> failed $ redText "permutivity5: input was" $$ redText "x" $$ showPatch x $$ redText "y" $$ showPatch y $$ redText "z" $$ showPatch z $$ redText "z3" $$ showPatch z3 $$ redText "failed commute of" $$ redText "y4" $$ showPatch y4 $$ redText "x4" $$ showPatch x4 $$ redText "whereas commute of x and y give" $$ redText "y1" $$ showPatch y1 $$ redText "x1" $$ showPatch x1 Just (x3_ :> y2_) | NotEq <- x3_ =\/= x3 -> failed $ redText "permutivity6" | NotEq <- y2_ =/\= y2 -> failed $ redText "permutivity7" | otherwise -> succeeded | otherwise -> failed $ redText "permutivity failed" $$ redText "z3" $$ showPatch z3 $$ redText "z3_" $$ showPatch z3_ partialPermutivity :: Patchy p => (FORALL(x y) (p :> p) C(x y) -> Maybe ((p :> p) C(x y))) -> (p :> p :> p) C(a b) -> TestResult partialPermutivity c (xx:>yy:>zz) = pp (xx:>yy:>zz) <&&> pp (invert zz:>invert yy:>invert xx) where pp (x:>y:>z) = case c (y :> z) of Nothing -> rejected Just (z1 :> y1) -> case c (x :> z1) of Nothing -> rejected Just (_ :> x1) -> case c (x :> y) of Just _ -> rejected -- this is covered by full permutivity test above Nothing -> case c (x1 :> y1) of Nothing -> succeeded Just _ -> failed $ greenText "partialPermutivity error" $$ greenText "x" $$ showPatch x $$ greenText "y" $$ showPatch y $$ greenText "z" $$ showPatch z mergeArgumentsConsistent :: Patchy p => (FORALL(x y) p C(x y) -> Maybe Doc) -> (p :\/: p) C(a b) -> TestResult mergeArgumentsConsistent isConsistent (x :\/: y) = fromMaybe $ msum [(\z -> redText "mergeArgumentsConsistent x" $$ showPatch x $$ z) `fmap` isConsistent x, (\z -> redText "mergeArgumentsConsistent y" $$ showPatch y $$ z) `fmap` isConsistent y] mergeConsistent :: (Patchy p, Merge p) => (FORALL(x y) p C(x y) -> Maybe Doc) -> (p :\/: p) C(a b) -> TestResult mergeConsistent isConsistent (x :\/: y) = case merge (x :\/: y) of y' :/\: x' -> fromMaybe $ msum [(\z -> redText "mergeConsistent x" $$ showPatch x $$ z) `fmap` isConsistent x, (\z -> redText "mergeConsistent y" $$ showPatch y $$ z) `fmap` isConsistent y, (\z -> redText "mergeConsistent x'" $$ showPatch x' $$ z $$ redText "where x' comes from x" $$ showPatch x $$ redText "and y" $$ showPatch y) `fmap` isConsistent x', (\z -> redText "mergeConsistent y'" $$ showPatch y' $$ z) `fmap` isConsistent y'] mergeEitherWay :: (Patchy p, Merge p) => (p :\/: p) C(x y) -> TestResult mergeEitherWay (x :\/: y) = case merge (x :\/: y) of y' :/\: x' -> case merge (y :\/: x) of x'' :/\: y'' | IsEq <- x'' =\/= x', IsEq <- y'' =\/= y' -> succeeded | otherwise -> failed $ redText "mergeEitherWay bug" mergeCommute :: (Patchy p, Merge p) => (p :\/: p) C(x y) -> TestResult mergeCommute (x :\/: y) = case merge (x :\/: y) of y' :/\: x' -> case commute (x :> y') of Nothing -> failed $ redText "mergeCommute 1" $$ redText "x" $$ showPatch x $$ redText "y" $$ showPatch y $$ redText "x'" $$ showPatch x' $$ redText "y'" $$ showPatch y' Just (y_ :> x'_) | IsEq <- y_ =\/= y, IsEq <- x'_ =\/= x' -> case commute (y :> x') of Nothing -> failed $ redText "mergeCommute 2 failed" $$ redText "x" $$ showPatch x $$ redText "y" $$ showPatch y $$ redText "x'" $$ showPatch x' $$ redText "y'" $$ showPatch y' Just (x_ :> y'_) | IsEq <- x_ =\/= x, IsEq <- y'_ =\/= y' -> succeeded | otherwise -> failed $ redText "mergeCommute 3" $$ redText "x" $$ showPatch x $$ redText "y" $$ showPatch y $$ redText "x'" $$ showPatch x' $$ redText "y'" $$ showPatch y' $$ redText "x_" $$ showPatch x_ $$ redText "y'_" $$ showPatch y'_ | otherwise -> failed $ redText "mergeCommute 4" $$ redText "x" $$ showPatch x $$ redText "y" $$ showPatch y $$ redText "x'" $$ showPatch x' $$ redText "y'" $$ showPatch y' $$ redText "x'_" $$ showPatch x'_ $$ redText "y_" $$ showPatch y_ -- | join effect preserving joinEffectPreserving :: (PrimPatch prim, RepoModel model, ApplyState prim ~ RepoState model ) => (FORALL(x y) (prim :> prim) C(x y) -> Maybe (FL prim C(x y))) -> WithState model (prim :> prim) C(a b) -> TestResult joinEffectPreserving j (WithState r (a :> b) r') = case j (a :> b) of Nothing -> rejected Just x -> case maybeFail $ repoApply r x of Nothing -> failed $ redText "x is not applicable to r." Just r_x -> if r_x `eqModel` r' then succeeded else failed $ redText "r_x /= r'" joinCommute :: (PrimPatch prim) => (FORALL(x y) (prim :> prim) C(x y) -> Maybe (FL prim C(x y))) -> (prim :> prim :> prim) C(a b) -> TestResult joinCommute j (a :> b :> c) = case j (b :> c) of Nothing -> rejected Just x -> case commuteFLorComplain (a :> b :>: c :>: NilFL) of Right (b' :>: c' :>: NilFL :> a') -> case commute (a:>:NilFL :> x) of Just (x' :> a'':>:NilFL) -> case a'' =/\= a' of NotEq -> failed $ greenText "joinCommute 3" IsEq -> case j (b' :> c') of Nothing -> failed $ greenText "joinCommute 4" Just x'' -> case x' =\/= x'' of NotEq -> failed $ greenText "joinCommute 5" IsEq -> succeeded _ -> failed $ greenText "joinCommute 1" _ -> rejected show_read :: (Show2 p, Patchy p) => p C(a b) -> TestResult show_read p = let ps = renderPS (showPatch p) in case readPatch ps of Nothing -> failed (redText "unable to read " $$ showPatch p) Just (Sealed p' ) | IsEq <- p' =\/= p -> succeeded | otherwise -> failed $ redText "trouble reading patch p" $$ showPatch p $$ redText "reads as p'" $$ showPatch p' $$ redText "aka" $$ greenText (show2 p) $$ redText "and" $$ greenText (show2 p') -- vim: fileencoding=utf-8 : darcs-2.8.4/src/Darcs/Test/Patch/Properties/GenericUnwitnessed.hs0000644001765600176560000000777212104371431024254 0ustar ganeshganeshmodule Darcs.Test.Patch.Properties.GenericUnwitnessed where import qualified Darcs.Test.Patch.Properties.Generic as W ( permutivity, partialPermutivity , mergeConsistent, mergeArgumentsConsistent, mergeEitherWay , mergeCommute, patchAndInverseCommute, joinCommute, commuteInverses , recommute , show_read ) import Darcs.Test.Patch.Arbitrary.Generic ( Tree ) import Darcs.Test.Patch.RepoModel( RepoModel, RepoState ) import Darcs.Test.Patch.WithState( WithStartState ) import qualified Darcs.Test.Patch.Properties.Real as W ( propConsistentTreeFlattenings ) import Darcs.Test.Patch.WSub import Darcs.Test.Util.TestResult import Darcs.Patch.Prim.V1 ( Prim ) import Darcs.Patch.Patchy ( showPatch ) import Darcs.Witnesses.Show import Darcs.Witnesses.Eq import Darcs.Witnesses.Sealed( Sealed ) import Darcs.Patch.Merge ( Merge ) import Darcs.Patch ( Patchy ) import Printer ( Doc, redText, ($$) ) import qualified Storage.Hashed.Tree as HST ( Tree ) #include "gadts.h" permutivity :: (Patchy wp, WSub wp p) => (FORALL(x y) (p :> p) C(x y) -> Maybe ((p :> p) C(x y))) -> (p :> p :> p) C(a b) -> TestResult permutivity f = W.permutivity (fmap toW . f . fromW) . toW partialPermutivity :: (Patchy wp, WSub wp p) => (FORALL(x y) (p :> p) C(x y) -> Maybe ((p :> p) C(x y))) -> (p :> p :> p) C(a b) -> TestResult partialPermutivity f = W.partialPermutivity (fmap toW . f . fromW) . toW mergeEitherWay :: (Patchy wp, Merge wp, WSub wp p) => (p :\/: p) C(x y) -> TestResult mergeEitherWay = W.mergeEitherWay . toW commuteInverses :: (Patchy wp, WSub wp p) => (FORALL(x y) (p :> p) C(x y) -> Maybe ((p :> p) C(x y))) -> (p :> p) C(a b) -> TestResult commuteInverses f = W.commuteInverses (fmap toW . f . fromW) . toW recommute :: (Patchy wp, WSub wp p) => (FORALL(x y) ((p :> p) C(x y) -> Maybe ((p :> p) C(x y)))) -> (p :> p) C(a b) -> TestResult recommute f = W.recommute (fmap toW . f . fromW) . toW mergeCommute :: (Patchy wp, Merge wp, WSub wp p) => (p :\/: p) C(x y) -> TestResult mergeCommute = W.mergeCommute . toW mergeConsistent :: (Patchy wp, Merge wp, WSub wp p) => (FORALL(x y) p C(x y) -> Maybe Doc) -> (p :\/: p) C(a b) -> TestResult mergeConsistent f = W.mergeConsistent (f . fromW) . toW mergeArgumentsConsistent :: (Patchy wp, WSub wp p) => (FORALL(x y) p C(x y) -> Maybe Doc) -> (p :\/: p) C(a b) -> TestResult mergeArgumentsConsistent f = W.mergeArgumentsConsistent (f . fromW) . toW show_read :: (Patchy p, Show2 p) => p C(x y) -> TestResult show_read = W.show_read patchAndInverseCommute :: (Patchy wp, WSub wp p) => (FORALL(x y) (p :> p) C(x y) -> Maybe ((p :> p) C(x y))) -> (p :> p) C(a b) -> TestResult patchAndInverseCommute f = W.patchAndInverseCommute (fmap toW . f . fromW) . toW joinCommute :: (FORALL(x y) (Prim :> Prim) C(x y) -> Maybe (FL Prim C(x y))) -> (Prim :> Prim :> Prim) C(a b) -> TestResult joinCommute f = W.joinCommute (fmap toW . f . fromW) . toW consistentTreeFlattenings :: (RepoState model ~ HST.Tree, RepoModel model) => Sealed (WithStartState model (Tree Prim)) -> TestResult consistentTreeFlattenings = (\x -> if W.propConsistentTreeFlattenings x then succeeded else failed $ redText "oops") commuteFails :: (MyEq p, Patchy p) => ((p :> p) C(x y) -> Maybe ((p :> p) C(x y))) -> (p :> p) C(x y) -> TestResult commuteFails c (x :> y) = case c (x :> y) of Nothing -> succeeded Just (y' :> x') -> failed $ redText "x" $$ showPatch x $$ redText ":> y" $$ showPatch y $$ redText "y'" $$ showPatch y' $$ redText ":> x'" $$ showPatch x' darcs-2.8.4/src/Darcs/Test/Patch/Properties/Check.hs0000644001765600176560000001017612104371431021454 0ustar ganeshganeshmodule Darcs.Test.Patch.Properties.Check ( Check(..), checkAPatch ) where import Test.QuickCheck import Control.Applicative import Control.Monad ( liftM, liftM2, liftM3, liftM4, replicateM ) import Darcs.Patch.Info ( PatchInfo, patchinfo ) import Darcs.Test.Patch.Check ( PatchCheck, checkMove, removeDir, createDir, isValid, insertLine, fileEmpty, fileExists, deleteLine, modifyFile, createFile, removeFile, doCheck, doVerboseCheck, FileContents(..) ) import Darcs.Patch.RegChars ( regChars ) import ByteStringUtils ( linesPS ) import qualified Data.ByteString as B ( ByteString, null, concat ) import qualified Data.ByteString.Char8 as BC ( break, pack ) import Darcs.Patch.FileName ( fn2fp ) import qualified Data.Map as M ( mapMaybe ) import Darcs.Patch ( addfile, adddir, move, hunk, tokreplace, binary, changepref, invert, merge, effect ) import Darcs.Patch.Invert ( Invert ) import Darcs.Patch.V1 () import qualified Darcs.Patch.V1.Core as V1 ( Patch(..) ) import Darcs.Patch.V1.Core ( isMerger ) import Darcs.Patch.Prim.V1 () import Darcs.Patch.Prim.V1.Core ( Prim(..), DirPatchType(..), FilePatchType(..) ) import Darcs.Witnesses.Ordered import Darcs.Witnesses.Sealed ( Sealed(Sealed), unseal, mapSeal, Sealed2(..) ) import Darcs.Witnesses.Unsafe #include "gadts.h" #include "impossible.h" type Patch = V1.Patch Prim class Check p where checkPatch :: p C(x y) -> PatchCheck Bool instance Check p => Check (FL p) where checkPatch NilFL = isValid checkPatch (p :>: ps) = checkPatch p >> checkPatch ps checkAPatch :: (Invert p, Check p) => p C(x y) -> Bool checkAPatch p = doCheck $ do _ <- checkPatch p checkPatch $ invert p instance Check (V1.Patch Prim) where checkPatch p | isMerger p = do checkPatch $ effect p checkPatch (V1.Merger _ _ _ _) = impossible checkPatch (V1.Regrem _ _ _ _) = impossible checkPatch (V1.PP p) = checkPatch p instance Check Prim where checkPatch (FP f RmFile) = removeFile $ fn2fp f checkPatch (FP f AddFile) = createFile $ fn2fp f checkPatch (FP f (Hunk line old new)) = do _ <- fileExists $ fn2fp f mapM_ (deleteLine (fn2fp f) line) old mapM_ (insertLine (fn2fp f) line) (reverse new) isValid checkPatch (FP f (TokReplace t old new)) = modifyFile (fn2fp f) (tryTokPossibly t old new) -- note that the above isn't really a sure check, as it leaves PSomethings -- and PNothings which may have contained new... checkPatch (FP f (Binary o n)) = do _ <- fileExists $ fn2fp f mapM_ (deleteLine (fn2fp f) 1) (linesPS o) _ <- fileEmpty $ fn2fp f mapM_ (insertLine (fn2fp f) 1) (reverse $ linesPS n) isValid checkPatch (DP d AddDir) = createDir $ fn2fp d checkPatch (DP d RmDir) = removeDir $ fn2fp d checkPatch (Move f f') = checkMove (fn2fp f) (fn2fp f') checkPatch (ChangePref _ _ _) = return True tryTokPossibly :: String -> String -> String -> (Maybe FileContents) -> (Maybe FileContents) tryTokPossibly t o n = liftM $ \contents -> let lines' = M.mapMaybe (liftM B.concat . tryTokInternal t (BC.pack o) (BC.pack n)) (fcLines contents) in contents { fcLines = lines' } tryTokInternal :: String -> B.ByteString -> B.ByteString -> B.ByteString -> Maybe [B.ByteString] tryTokInternal _ _ _ s | B.null s = Just [] tryTokInternal t o n s = case BC.break (regChars t) s of (before,s') -> case BC.break (not . regChars t) s' of (tok,after) -> case tryTokInternal t o n after of Nothing -> Nothing Just rest -> if tok == o then Just $ before : n : rest else if tok == n then Nothing else Just $ before : tok : rest verboseCheckAPatch :: (Invert p, Check p) => p C(x y) -> Bool verboseCheckAPatch p = doVerboseCheck $ do checkPatch p darcs-2.8.4/src/Darcs/Test/Patch/Properties/Real.hs0000644001765600176560000000313712104371431021321 0ustar ganeshganeshmodule Darcs.Test.Patch.Properties.Real ( propConsistentTreeFlattenings ) where import Darcs.Test.Patch.Arbitrary.Generic ( Tree, flattenTree, G2(..), mapTree ) import Darcs.Test.Patch.WithState import Darcs.Test.Patch.RepoModel ( RepoModel, repoApply, showModel, eqModel, RepoState , Fail, maybeFail ) import qualified Storage.Hashed.Tree as HST ( Tree ) import Darcs.Witnesses.Sealed( Sealed(..) ) import Darcs.Patch.V2.Real( prim2real ) import Darcs.Patch.Prim.V1 ( Prim ) #include "gadts.h" #include "impossible.h" assertEqualFst :: (RepoModel a, Show b, Show c) => (Fail (a x), b) -> (Fail (a x), c) -> Bool assertEqualFst (x,bx) (y,by) | Just x' <- maybeFail x, Just y' <- maybeFail y, x' `eqModel` y' = True | Nothing <- maybeFail x, Nothing <- maybeFail y = True | otherwise = error ("Not really equal:\n" ++ showx ++ "\nand\n" ++ showy ++ "\ncoming from\n" ++ show bx ++ "\nand\n" ++ show by) where showx | Just x' <- maybeFail x = showModel x' | otherwise = "Nothing" showy | Just y' <- maybeFail y = showModel y' | otherwise = "Nothing" propConsistentTreeFlattenings :: (RepoState model ~ HST.Tree, RepoModel model) => Sealed (WithStartState model (Tree Prim)) -> Bool propConsistentTreeFlattenings (Sealed (WithStartState start t)) = fromJust $ do Sealed (G2 flat) <- return $ flattenTree $ mapTree prim2real t rms <- return $ map (start `repoApply`) flat return $ and $ zipWith assertEqualFst (zip rms flat) (tail $ zip rms flat) darcs-2.8.4/src/Darcs/Test/Patch/Arbitrary/0000755001765600176560000000000012104371431017701 5ustar ganeshganeshdarcs-2.8.4/src/Darcs/Test/Patch/Arbitrary/Generic.hs0000644001765600176560000002537012104371431021620 0ustar ganeshganesh{-# OPTIONS_GHC -fno-warn-deprecations -fno-warn-orphans #-} {-# LANGUAGE CPP, UndecidableInstances, ScopedTypeVariables, MultiParamTypeClasses, FlexibleInstances, ViewPatterns #-} #include "gadts.h" module Darcs.Test.Patch.Arbitrary.Generic ( Tree(..), TreeWithFlattenPos(..), G2(..), ArbitraryPrim, NullPatch(..), RepoModel(..) , flattenOne, flattenTree, mapTree, sizeTree , commutePairFromTree, mergePairFromTree , commuteTripleFromTree, mergePairFromCommutePair , commutePairFromTWFP, mergePairFromTWFP, getPairs, getTriples , patchFromTree , canonizeTree , quickCheck ) where import Control.Monad ( liftM ) import Test.QuickCheck import Darcs.Test.Patch.WithState import Darcs.Test.Patch.RepoModel import Darcs.Test.Util.QuickCheck ( bSized ) import Darcs.Witnesses.Sealed import Darcs.Witnesses.Eq import Darcs.Witnesses.Unsafe import Darcs.Witnesses.Ordered import Darcs.Patch.Merge ( Merge(..) ) import Darcs.Patch.Patchy ( Invert(..), Commute(..) ) import Darcs.Patch.Prim ( PrimOf, PrimPatch, PrimPatchBase, FromPrim(..), PrimConstruct( anIdentity ) ) import Darcs.Patch.Prim.V1 () import Darcs.Patch.V2 ( RealPatch ) -- XXX this is more or less a hack --import Darcs.ColorPrinter ( errorDoc ) --import Darcs.ColorPrinter ( traceDoc ) import Darcs.Witnesses.Show --import Printer ( greenText, ($$) ) -- | Generate a patch to a certain state. class ArbitraryStateIn s p where arbitraryStateIn :: s C(x) -> Gen (p C(x)) data Tree p C(x) where NilTree :: Tree p C(x) SeqTree :: p C(x y) -> Tree p C(y) -> Tree p C(x) ParTree :: Tree p C(x) -> Tree p C(x) -> Tree p C(x) mapTree :: (FORALL(y z) p C(y z) -> q C(y z)) -> Tree p C(x) -> Tree q C(x) mapTree _ NilTree = NilTree mapTree f (SeqTree p t) = SeqTree (f p) (mapTree f t) mapTree f (ParTree t1 t2) = ParTree (mapTree f t1) (mapTree f t2) instance Show2 p => Show (Tree p C(x)) where showsPrec _ NilTree = showString "NilTree" showsPrec d (SeqTree a t) = showParen (d > appPrec) $ showString "SeqTree " . showsPrec2 (appPrec + 1) a . showString " " . showsPrec (appPrec + 1) t showsPrec d (ParTree t1 t2) = showParen (d > appPrec) $ showString "ParTree " . showsPrec (appPrec + 1) t1 . showString " " . showsPrec (appPrec + 1) t2 instance Show2 p => Show1 (Tree p) where showDict1 = ShowDictClass instance Show2 p => Show1 (TreeWithFlattenPos p) where showDict1 = ShowDictClass sizeTree :: Tree p C(x) -> Int sizeTree NilTree = 0 sizeTree (SeqTree _ t) = 1 + sizeTree t sizeTree (ParTree t1 t2) = 1 + sizeTree t1 + sizeTree t2 -- newtype G1 l p C(x) = G1 { _unG1 :: l (p C(x)) } newtype G2 l p C(x y) = G2 { unG2 :: l (p C(x y)) } flattenTree :: (Merge p) => Tree p C(z) -> Sealed (G2 [] (FL p) C(z)) flattenTree NilTree = seal $ G2 $ return NilFL flattenTree (SeqTree p t) = mapSeal (G2 . map (p :>:) . unG2) $ flattenTree t flattenTree (ParTree (flattenTree -> Sealed gpss1) (flattenTree -> Sealed gpss2)) = seal $ G2 $ do ps1 <- unG2 gpss1 ps2 <- unG2 gpss2 ps2' :/\: ps1' <- return $ merge (ps1 :\/: ps2) -- We can't prove that the existential type in the result -- of merge will be the same for each pair of -- ps1 and ps2. map unsafeCoerceP [ps1 +>+ ps2', ps2 +>+ ps1'] instance ArbitraryState s p => ArbitraryStateIn s (Tree p) where -- Don't generate trees deeper than 6 with default QuickCheck size (0..99). -- Note if we don't put a non-zero lower bound the first generated trees will always have depth 0. arbitraryStateIn rm = bSized 3 0.035 9 $ \depth -> arbitraryTree rm depth -- | Generate a tree of patches, bounded by the depth @maxDepth@. arbitraryTree :: ArbitraryState s p => s C(x) -> Int -> Gen (Tree p C(x)) arbitraryTree rm depth | depth == 0 = return NilTree -- Note a probability of N for NilTree would imply ~(100*N)% of empty trees. -- For the purpose of this module empty trees are useless, but even when -- NilTree case is omitted there is still a small percentage of empty trees -- due to the generation of null-patches (empty-hunks) and the use of canonizeTree. | otherwise = frequency [(1, do Sealed (WithEndState p rm') <- arbitraryState rm t <- arbitraryTree rm' (depth - 1) return (SeqTree p t)) ,(3, do t1 <- arbitraryTree rm (depth - 1) t2 <- arbitraryTree rm (depth - 1) return (ParTree t1 t2))] class NullPatch p where nullPatch :: p C(x y) -> EqCheck C(x y) class (ArbitraryState (ModelOf prim) prim, NullPatch prim, PrimPatch prim, RepoModel (ModelOf prim)) => ArbitraryPrim prim -- canonize a tree, removing any dead branches canonizeTree :: NullPatch p => Tree p C(x) -> Tree p C(x) canonizeTree NilTree = NilTree canonizeTree (ParTree t1 t2) | NilTree <- canonizeTree t1 = canonizeTree t2 | NilTree <- canonizeTree t2 = canonizeTree t1 | otherwise = ParTree (canonizeTree t1) (canonizeTree t2) canonizeTree (SeqTree p t) | IsEq <- nullPatch p = canonizeTree t | otherwise = SeqTree p (canonizeTree t) instance (RepoModel model, ArbitraryPrim prim, model ~ ModelOf prim, ArbitraryState model prim) => Arbitrary (Sealed (WithStartState model (Tree prim))) where arbitrary = do repo <- aSmallRepo Sealed (WithStartState rm tree) <- liftM (seal . WithStartState repo) (arbitraryStateIn repo) return $ Sealed $ WithStartState rm (canonizeTree tree) flattenOne :: (FromPrim p, Merge p) => Tree (PrimOf p) C(x) -> Sealed (FL p C(x)) flattenOne NilTree = seal NilFL flattenOne (SeqTree p (flattenOne -> Sealed ps)) = seal (fromPrim p :>: ps) flattenOne (ParTree (flattenOne -> Sealed ps1) (flattenOne -> Sealed ps2)) = --traceDoc (greenText "flattening two parallel series: ps1" $$ showPatch ps1 $$ -- greenText "ps2" $$ showPatch ps2) $ case merge (ps1 :\/: ps2) of ps2' :/\: _ -> seal (ps1 +>+ ps2') data TreeWithFlattenPos p C(x) = TWFP Int (Tree p C(x)) commutePairFromTWFP :: (FromPrim p, Merge p, PrimPatchBase p) => (FORALL (y z) (p :> p) C(y z) -> t) -> (WithStartState model (TreeWithFlattenPos (PrimOf p)) C(x) -> t) commutePairFromTWFP handlePair (WithStartState _ (TWFP n t)) = unseal2 handlePair $ let xs = unseal getPairs (flattenOne t) in if length xs > n && n >= 0 then xs!!n else seal2 (fromPrim anIdentity :> fromPrim anIdentity) commutePairFromTree :: (FromPrim p, Merge p, PrimPatchBase p) => (FORALL (y z) (p :> p) C(y z) -> t) -> (WithStartState model (Tree (PrimOf p)) C(x) -> t) commutePairFromTree handlePair (WithStartState _ t) = unseal2 handlePair $ case flattenOne t of Sealed ps -> let xs = --traceDoc (greenText "I'm flattening one to get:" $$ showPatch ps) $ getPairs ps in if null xs then seal2 (fromPrim anIdentity :> fromPrim anIdentity) else last xs commuteTripleFromTree :: (FromPrim p, Merge p, PrimPatchBase p) => (FORALL (y z) (p :> p :> p) C(y z) -> t) -> (WithStartState model (Tree (PrimOf p)) C(x) -> t) commuteTripleFromTree handle (WithStartState _ t) = unseal2 handle $ case flattenOne t of Sealed ps -> let xs = --traceDoc (greenText "I'm flattening one to get:" $$ showPatch ps) $ getTriples ps in if null xs then seal2 (fromPrim anIdentity :> fromPrim anIdentity :> fromPrim anIdentity) else last xs mergePairFromCommutePair :: (Commute p, Invert p) => (FORALL (y z) (p :\/: p) C(y z) -> t) -> (FORALL (y z) (p :> p) C(y z) -> t) mergePairFromCommutePair handlePair (a :> b) = case commute (a :> b) of Just (b' :> _) -> handlePair (a :\/: b') Nothing -> handlePair (b :\/: b) -- impredicativity problems mean we can't use (.) in the definitions below mergePairFromTWFP :: (FromPrim p, Merge p, Invert p, PrimPatchBase p) => (FORALL (y z) (p :\/: p) C(y z) -> t) -> (WithStartState model (TreeWithFlattenPos (PrimOf p)) C(x) -> t) mergePairFromTWFP x = commutePairFromTWFP (mergePairFromCommutePair x) mergePairFromTree :: (FromPrim p, Merge p, Invert p, PrimPatchBase p) => (FORALL (y z) (p :\/: p) C(y z) -> t) -> (WithStartState model (Tree (PrimOf p)) C(x) -> t) mergePairFromTree x = commutePairFromTree (mergePairFromCommutePair x) patchFromCommutePair :: (Commute p, Invert p) => (FORALL (y z) p C(y z) -> t) -> (FORALL (y z) (p :> p) C(y z) -> t) patchFromCommutePair handle (_ :> b) = handle b patchFromTree :: (FromPrim p, Merge p, Invert p, PrimPatchBase p) => (FORALL (y z) p C(y z) -> t) -> (WithStartState model (Tree (PrimOf p)) C(x) -> t) patchFromTree x = commutePairFromTree (patchFromCommutePair x) instance Show2 p => Show (TreeWithFlattenPos p C(x)) where showsPrec d (TWFP n t) = showParen (d > appPrec) $ showString "TWFP " . showsPrec (appPrec + 1) n . showString " " . showsPrec1 (appPrec + 1) t getPairs :: FL p C(x y) -> [Sealed2 (p :> p)] getPairs NilFL = [] getPairs (_:>:NilFL) = [] getPairs (a:>:b:>:c) = seal2 (a:>b) : getPairs (b:>:c) getTriples :: FL p C(x y) -> [Sealed2 (p :> p :> p)] getTriples NilFL = [] getTriples (_:>:NilFL) = [] getTriples (_:>:_:>:NilFL) = [] getTriples (a:>:b:>:c:>:d) = seal2 (a:>b:>c) : getTriples (b:>:c:>:d) instance (ArbitraryPrim prim, RepoModel (ModelOf prim), model ~ ModelOf prim, ArbitraryState model prim) => Arbitrary (Sealed (WithStartState model (TreeWithFlattenPos prim))) where arbitrary = do Sealed (WithStartState rm t) <- arbitrary let num = unseal (length . getPairs) (flattenOneRP t) if num == 0 then return $ Sealed $ WithStartState rm $ TWFP 0 NilTree else do n <- choose (0, num - 1) return $ Sealed $ WithStartState rm $ TWFP n t where -- just used to get the length. In principle this should be independent of the patch type. flattenOneRP :: Tree prim C(x) -> Sealed (FL (RealPatch prim) C(x)) flattenOneRP = flattenOne darcs-2.8.4/src/Darcs/Test/Patch/Arbitrary/Real.hs0000644001765600176560000000570512104371431021127 0ustar ganeshganesh{-# OPTIONS_GHC -fno-warn-orphans #-} {-# LANGUAGE UndecidableInstances #-} module Darcs.Test.Patch.Arbitrary.Real where import Darcs.Test.Patch.Arbitrary.Generic import Darcs.Test.Patch.Arbitrary.PrimV1 () import Darcs.Test.Patch.RepoModel import Darcs.Witnesses.Ordered import Darcs.Patch.Merge ( Merge(..) ) import Darcs.Patch.Patchy ( Patchy, Commute(..) ) import Darcs.Patch.Prim ( PrimPatch, anIdentity ) import Darcs.Patch.V2 ( RealPatch ) import Darcs.Patch.V2.Real ( isDuplicate ) import Test.QuickCheck import Darcs.Test.Patch.WithState import Darcs.Witnesses.Sealed import Darcs.Witnesses.Eq import Darcs.Patch.Prim ( FromPrim(..) ) #include "gadts.h" nontrivialReals :: PrimPatch prim => (RealPatch prim :> RealPatch prim) C(x y) -> Bool nontrivialReals = nontrivialCommute nontrivialCommute :: Patchy p => (p :> p) C(x y) -> Bool nontrivialCommute (x :> y) = case commute (x :> y) of Just (y' :> x') -> not (y' `unsafeCompare` y) || not (x' `unsafeCompare` x) Nothing -> False nontrivialMergeReals :: PrimPatch prim => (RealPatch prim :\/: RealPatch prim) C(x y) -> Bool nontrivialMergeReals = nontrivialMerge nontrivialMerge :: (Patchy p, Merge p) => (p :\/: p) C(x y) -> Bool nontrivialMerge (x :\/: y) = case merge (x :\/: y) of y' :/\: x' -> not (y' `unsafeCompare` y) || not (x' `unsafeCompare` x) instance (RepoModel (ModelOf prim), ArbitraryPrim prim) => Arbitrary (Sealed2 (FL (RealPatch prim))) where arbitrary = do Sealed (WithStartState _ tree) <- arbitrary :: Gen (Sealed (WithStartState (ModelOf prim) (Tree prim))) return $ unseal seal2 (flattenOne tree) instance (RepoModel (ModelOf prim), ArbitraryPrim prim) => Arbitrary (Sealed2 (RealPatch prim)) where arbitrary = do Sealed (WithStartState _ tree) <- arbitrary :: Gen (Sealed (WithStartState (ModelOf prim) (Tree prim))) case mapFL seal2 `unseal` flattenOne tree of [] -> return $ seal2 $ fromPrim anIdentity ps -> elements ps notDuplicatestriple :: (RealPatch prim :> RealPatch prim :> RealPatch prim) C(x y) -> Bool notDuplicatestriple (a :> b :> c) = not (isDuplicate a || isDuplicate b || isDuplicate c) nontrivialTriple :: PrimPatch prim => (RealPatch prim :> RealPatch prim :> RealPatch prim) C(x y) -> Bool nontrivialTriple (a :> b :> c) = case commute (a :> b) of Nothing -> False Just (b' :> a') -> case commute (a' :> c) of Nothing -> False Just (c'' :> a'') -> case commute (b :> c) of Nothing -> False Just (c' :> b'') -> (not (a `unsafeCompare` a') || not (b `unsafeCompare` b')) && (not (c' `unsafeCompare` c) || not (b'' `unsafeCompare` b)) && (not (c'' `unsafeCompare` c) || not (a'' `unsafeCompare` a')) darcs-2.8.4/src/Darcs/Test/Patch/Arbitrary/PrimV1.hs0000644001765600176560000003277012104371431021364 0ustar ganeshganesh{-# LANGUAGE MultiParamTypeClasses #-} {-# OPTIONS_GHC -fno-warn-orphans #-} module Darcs.Test.Patch.Arbitrary.PrimV1 where import qualified Darcs.Test.Patch.Arbitrary.Generic as T ( commuteTripleFromTree, commutePairFromTree, commutePairFromTWFP , mergePairFromTree, mergePairFromTWFP , patchFromTree ) import Darcs.Test.Patch.Arbitrary.Generic import Darcs.Test.Patch.RepoModel import Control.Monad ( liftM ) import Test.QuickCheck import Darcs.Test.Patch.WithState import Darcs.Witnesses.Sealed import Darcs.Witnesses.Eq import Darcs.Witnesses.Unsafe import Darcs.Witnesses.Ordered -- import Darcs.Witnesses.Show import Darcs.Patch.Prim.V1 () import Darcs.Patch.Prim.V1.Core ( FilePatchType( Hunk, TokReplace ), Prim( FP ), isIdentity ) import Darcs.Patch.RepoPatch ( RepoPatch ) import Darcs.Patch.FileHunk( IsHunk( isHunk ), FileHunk(..) ) import Darcs.Test.Patch.V1Model import Darcs.Test.Util.QuickCheck ( alpha, notIn, maybeOf ) import Darcs.Commands.Replace ( defaultToks ) import Darcs.Patch.Prim import Control.Applicative ( (<$>) ) import qualified Data.ByteString.Char8 as BC import Data.Maybe ( isJust ) #include "gadts.h" #include "impossible.h" patchFromTree :: (RepoPatch p, PrimOf p ~ Prim) => (FORALL(y z) p C(y z) -> t) -> WithStartState V1Model (Tree Prim) C(x) -> t patchFromTree = T.patchFromTree mergePairFromTree :: (RepoPatch p, PrimOf p ~ Prim) => (FORALL(y z) (p :\/: p) C(y z) -> t) -> WithStartState V1Model (Tree Prim) C(x) -> t mergePairFromTree = T.mergePairFromTree mergePairFromTWFP :: (RepoPatch p, PrimOf p ~ Prim) => (FORALL(y z) (p :\/: p) C(y z) -> t) -> WithStartState V1Model (TreeWithFlattenPos Prim) C(x) -> t mergePairFromTWFP = T.mergePairFromTWFP commutePairFromTWFP :: (RepoPatch p, PrimOf p ~ Prim) => (FORALL(y z) (p :> p) C(y z) -> t) -> WithStartState V1Model (TreeWithFlattenPos Prim) C(x) -> t commutePairFromTWFP = T.commutePairFromTWFP commutePairFromTree :: (RepoPatch p, PrimOf p ~ Prim) => (FORALL(y z) (p :> p) C(y z) -> t) -> WithStartState V1Model (Tree Prim) C(x) -> t commutePairFromTree = T.commutePairFromTree commuteTripleFromTree :: (RepoPatch p, PrimOf p ~ Prim) => (FORALL(y z) (p :> p :> p) C(y z) -> t) -> WithStartState V1Model (Tree Prim) C(x) -> t commuteTripleFromTree = T.commuteTripleFromTree nonEmptyHunk :: (IsHunk p) => p C(x y) -> Bool nonEmptyHunk p | Just (FileHunk _ _ [] []) <- isHunk p = False | otherwise = True nonEmptyHunksPair :: (IsHunk p) => (p :> p) C(x y) -> Bool nonEmptyHunksPair (p1 :> p2) = nonEmptyHunk p1 && nonEmptyHunk p2 nonEmptyHunksTriple :: (IsHunk p) => (p :> p :> p) C(x y) -> Bool nonEmptyHunksTriple (p1 :> p2 :> p3) = nonEmptyHunk p1 && nonEmptyHunk p2 && nonEmptyHunk p3 nonEmptyHunksFLPair :: (IsHunk p) => (FL p :> FL p) C(x y) -> Bool nonEmptyHunksFLPair (ps :> qs) = allFL nonEmptyHunk ps && allFL nonEmptyHunk qs type instance ModelOf Prim = V1Model instance ArbitraryPrim Prim instance NullPatch Prim where nullPatch (FP _ fp) = nullPatch fp nullPatch p | IsEq <- isIdentity p = IsEq nullPatch _ = NotEq instance NullPatch FilePatchType where nullPatch (Hunk _ [] []) = unsafeCoerceP IsEq -- is this safe? nullPatch _ = NotEq instance Arbitrary (Sealed2 (FL (WithState V1Model Prim))) where arbitrary = do repo <- ourSmallRepo liftM (unseal (seal2 . wesPatch)) $ arbitraryState repo -- instance Show1 (TreeWithFlattenPos Prim) where -- showDict1 = ShowDictClass -- WithState and propFail are handy for debugging arbitrary code propFail :: Int -> Tree Prim C(x) -> Bool propFail n xs = sizeTree xs < n ---------------------------------------------------------------------- -- * QuickCheck generators ---------------------------------------------------------------------- -- ** FilePatchType generators aHunk :: FORALL(x y) Content -> Gen (FilePatchType C(x y)) aHunk content = sized $ \n -> do pos <- choose (1, contentLen+1) let prefixLen = pos-1 restLen = contentLen-prefixLen oldLen <- frequency [ (75, choose (0, min restLen n)) -- produces small hunks common in real editing , (25, choose (0, min 10 restLen)) ] -- newLen choice aims to cover all possibilities, that is, -- remove less/the same/more than added and empty the file. newLen <- frequency [ ( 54 , choose (1,min 1 n) ) , ( if oldLen /= 0 then 42 else 0 , choose (1,min 1 oldLen) ) , ( if oldLen /= 0 then 2 else 0 , return oldLen ) , ( if oldLen /= 0 then 2 else 0 , return 0 ) ] new <- vectorOf newLen aLine let old = take oldLen $ drop prefixLen $ content return $ Hunk pos old new where contentLen = length content aTokReplace :: FORALL(x y) Content -> Gen (FilePatchType C(x y)) aTokReplace [] = do w <- vectorOf 1 alpha w' <- vectorOf 1 alpha return $ TokReplace defaultToks w w' aTokReplace content = do let fileWords = concatMap BC.words content wB <- elements fileWords w' <- alphaBS `notIn` fileWords return $ TokReplace defaultToks (BC.unpack wB) (BC.unpack w') where alphaBS = do x <- alpha; return $ BC.pack [x] ---------------------------------------------------------------------- -- ** Prim generators aHunkP :: FORALL(x y) (AnchoredPath,File) -> Gen (Prim C(x y)) aHunkP (path,file) = do Hunk pos old new <- aHunk content return $ hunk (ap2fp path) pos old new where content = fileContent file aTokReplaceP :: FORALL (x y) (AnchoredPath,File) -> Gen (Prim C(x y)) aTokReplaceP (path,file) = do TokReplace tokchars old new <- aTokReplace content return $ tokreplace (ap2fp path) tokchars old new where content = fileContent file anAddFileP :: FORALL (x y) (AnchoredPath,Dir) -> Gen (Prim C(x y)) anAddFileP (path,dir) = do newFilename <- aFilename `notIn` existing let newPath = path `appendPath` newFilename return $ addfile (ap2fp newPath) where existing = map fst $ filterFiles $ dirContent dir aRmFileP :: FORALL (x y) AnchoredPath -- ^ Path of an empty file -> Prim C(x y) aRmFileP path = rmfile (ap2fp path) anAddDirP :: FORALL (x y) (AnchoredPath,Dir) -> Gen (Prim C(x y)) anAddDirP (path,dir) = do newDirname <- aDirname `notIn` existing let newPath = path `appendPath` newDirname return $ adddir (ap2fp newPath) where existing = map fst $ filterDirs $ dirContent dir aRmDirP :: FORALL (x y) AnchoredPath -- ^ Path of an empty directory -> Prim C(x y) aRmDirP path = rmdir (ap2fp path) aMoveP :: FORALL (x y) Gen Name -> AnchoredPath -> (AnchoredPath,Dir) -> Gen (Prim C(x y)) aMoveP nameGen oldPath (dirPath,dir) = do newName <- nameGen `notIn` existing let newPath = dirPath `appendPath` newName return $ move (ap2fp oldPath) (ap2fp newPath) where existing = map fst $ dirContent dir -- | Generates any type of 'Prim' patch, except binary and setpref patches. aPrim :: FORALL(x y) V1Model C(x) -> Gen (WithEndState V1Model (Prim C(x)) C(y)) aPrim repo = do mbFile <- maybeOf repoFiles mbEmptyFile <- maybeOf $ filter (isEmpty . snd) repoFiles dir <- elements (rootDir:repoDirs) mbOldDir <- maybeOf repoDirs mbEmptyDir <- maybeOf $ filter (isEmpty . snd) repoDirs patch <- frequency [ ( if isJust mbFile then 12 else 0 , aHunkP $ fromJust mbFile ) , ( if isJust mbFile then 6 else 0 , aTokReplaceP $ fromJust mbFile ) , ( 2 , anAddFileP dir ) , ( if isJust mbEmptyFile then 12 else 0 , return $ aRmFileP $ fst $ fromJust mbEmptyFile ) , ( 2 , anAddDirP dir ) , ( if isJust mbEmptyDir then 10 else 0 , return $ aRmDirP $ fst $ fromJust mbEmptyDir ) , ( if isJust mbFile then 3 else 0 , aMoveP aFilename (fst $ fromJust mbFile) dir ) , let oldPath = fst $ fromJust mbOldDir in ( if isJust mbOldDir && not (oldPath `isPrefix` fst dir) then 4 else 0 , aMoveP aDirname oldPath dir ) ] let repo' = unFail $ repoApply repo patch return $ WithEndState patch repo' where repoItems = list repo repoFiles = filterFiles repoItems repoDirs = filterDirs repoItems rootDir = (anchoredRoot,root repo) {- [COVERAGE OF aPrim] PLEASE, if you change something that may affect the coverage of aPrim then a) recalculate it, or if that is not possible; b) indicate the need to do it. Patch type ---------- 42% hunk 22% tokreplace 14% move 6% rmdir 6% addfile 6% adddir 4% rmfile -} ---------------------------------------------------------------------- -- *** Pairs of primitive patches -- Try to generate commutable pairs of hunks hunkPairP :: FORALL(x y) (AnchoredPath,File) -> Gen ((Prim :> Prim) C(x y)) hunkPairP (path,file) = do h1@(Hunk l1 old1 new1) <- aHunk content (delta, content') <- selectChunk h1 content Hunk l2' old2 new2 <- aHunk content' let l2 = l2'+delta return (hunk fpPath l1 old1 new1 :> hunk fpPath l2 old2 new2) where content = fileContent file fpPath = ap2fp path selectChunk (Hunk l old new) content_ = elements [prefix, suffix] where start = l - 1 prefix = (0, take start content_) suffix = (start + length new, drop (start + length old) content_) selectChunk _ _ = impossible aPrimPair :: FORALL(x y) V1Model C(x) -> Gen (WithEndState V1Model ((Prim :> Prim) C(x)) C(y)) aPrimPair repo = do mbFile <- maybeOf repoFiles frequency [ ( if isJust mbFile then 1 else 0 , do p1 :> p2 <- hunkPairP $ fromJust mbFile let repo' = unFail $ repoApply repo p1 repo'' = unFail $ repoApply repo' p2 return $ WithEndState (p1 :> p2) repo'' ) , ( 1 , do Sealed wesP <- arbitraryState repo return $ unsafeCoerceP1 wesP ) ] where repoItems = list repo repoFiles = filterFiles repoItems {- [COVERAGE OF aPrimPair] PLEASE, if you change something that may affect the coverage of aPrimPair then a) recalculate it, or if that is not possible; b) indicate the need to do it. Rate of ommutable pairs ----------------------- 67% commutable Commutable coverage (for 1000 tests) ------------------- 21% hunks-B 20% hunks-A 14% file:>dir 12% file:>move 8% trivial-FP 8% hunk:>tok 4% hunks-D 3% tok:>tok 2% hunks-C 1% move:>move 1% dir:>move 1% dir:>dir 0% emptyhunk:>file -} ---------------------------------------------------------------------- -- Arbitrary instances ourSmallRepo :: Gen (V1Model C(x)) ourSmallRepo = aSmallRepo instance ArbitraryState V1Model Prim where arbitraryState s = seal <$> aPrim s instance Arbitrary (Sealed2 Prim) where arbitrary = makeS2Gen ourSmallRepo instance Arbitrary (Sealed2 (Prim :> Prim)) where arbitrary = do repo <- ourSmallRepo WithEndState pp _ <- aPrimPair repo return $ seal2 pp instance Arbitrary (Sealed ((Prim :> Prim) C(a))) where arbitrary = do repo <- ourSmallRepo WithEndState pp _ <- aPrimPair repo return $ seal pp instance Arbitrary (Sealed2 (Prim :> Prim :> Prim)) where arbitrary = makeS2Gen ourSmallRepo instance Arbitrary (Sealed ((Prim :> Prim :> Prim) a)) where arbitrary = makeSGen ourSmallRepo instance Arbitrary (Sealed2 (FL Prim)) where arbitrary = makeS2Gen ourSmallRepo instance Arbitrary (Sealed ((FL Prim) C(a))) where arbitrary = makeSGen ourSmallRepo instance Arbitrary (Sealed2 (FL Prim :> FL Prim)) where arbitrary = makeS2Gen ourSmallRepo instance Arbitrary (Sealed ((FL Prim :> FL Prim) C(a))) where arbitrary = makeSGen ourSmallRepo instance Arbitrary (Sealed2 (WithState V1Model Prim)) where arbitrary = makeWS2Gen ourSmallRepo instance Arbitrary (Sealed (WithState V1Model Prim C(a))) where arbitrary = makeWSGen ourSmallRepo instance Arbitrary (Sealed (WithState V1Model (FL Prim) C(a))) where arbitrary = makeWSGen ourSmallRepo instance Arbitrary (Sealed2 (WithState V1Model (Prim :> Prim))) where arbitrary = do repo <- ourSmallRepo WithEndState pp repo' <- aPrimPair repo return $ seal2 $ WithState repo pp repo' instance Arbitrary (Sealed (WithState V1Model (Prim :> Prim) a)) where arbitrary = do repo <- ourSmallRepo WithEndState pp repo' <- aPrimPair repo return $ seal $ WithState repo pp repo' instance Arbitrary (Sealed2 (WithState V1Model (FL Prim))) where arbitrary = makeWS2Gen ourSmallRepo instance Arbitrary (Sealed2 (WithState V1Model (FL Prim :> FL Prim))) where arbitrary = makeWS2Gen ourSmallRepo instance Arbitrary (Sealed (WithState V1Model (FL Prim :> FL Prim) a)) where arbitrary = makeWSGen ourSmallRepo darcs-2.8.4/src/Darcs/Test/Patch/Arbitrary/PrimV3.hs0000644001765600176560000002361012104371431021357 0ustar ganeshganesh-- TODO: Remove these warning disabling flags... {-# OPTIONS_GHC -w #-} {-# LANGUAGE MultiParamTypeClasses, OverloadedStrings #-} module Darcs.Test.Patch.Arbitrary.PrimV3 where import qualified Darcs.Test.Patch.Arbitrary.Generic as T ( commuteTripleFromTree, commutePairFromTree, commutePairFromTWFP , mergePairFromTree, mergePairFromTWFP , patchFromTree ) import Darcs.Test.Patch.Arbitrary.Generic import Darcs.Test.Patch.RepoModel import Control.Monad ( liftM ) import Test.QuickCheck import Darcs.Test.Patch.WithState import Darcs.Witnesses.Sealed import Darcs.Witnesses.Eq import Darcs.Witnesses.Unsafe import Darcs.Witnesses.Ordered -- import Darcs.Witnesses.Show import Darcs.Patch.Prim.V3 () import Darcs.Patch.Prim.V3.Core ( Prim(..), Location, Hunk(..), UUID(..) ) import Darcs.Patch.RepoPatch ( RepoPatch ) import Darcs.Test.Patch.V3Model import Darcs.Test.Util.QuickCheck ( alpha, notIn, maybeOf ) import Darcs.Commands.Replace ( defaultToks ) import Darcs.Patch.Prim import Control.Applicative ( (<$>) ) import qualified Data.ByteString.Char8 as BC import qualified Data.ByteString as BS import Data.Maybe ( isJust ) import qualified Data.Map as M import Storage.Hashed.Hash( Hash(..) ) #include "gadts.h" #include "impossible.h" patchFromTree :: (RepoPatch p, PrimOf p ~ Prim) => (FORALL(y z) p C(y z) -> t) -> WithStartState V3Model (Tree Prim) C(x) -> t patchFromTree = T.patchFromTree mergePairFromTree :: (RepoPatch p, PrimOf p ~ Prim) => (FORALL(y z) (p :\/: p) C(y z) -> t) -> WithStartState V3Model (Tree Prim) C(x) -> t mergePairFromTree = T.mergePairFromTree mergePairFromTWFP :: (RepoPatch p, PrimOf p ~ Prim) => (FORALL(y z) (p :\/: p) C(y z) -> t) -> WithStartState V3Model (TreeWithFlattenPos Prim) C(x) -> t mergePairFromTWFP = T.mergePairFromTWFP commutePairFromTWFP :: (RepoPatch p, PrimOf p ~ Prim) => (FORALL(y z) (p :> p) C(y z) -> t) -> WithStartState V3Model (TreeWithFlattenPos Prim) C(x) -> t commutePairFromTWFP = T.commutePairFromTWFP commutePairFromTree :: (RepoPatch p, PrimOf p ~ Prim) => (FORALL(y z) (p :> p) C(y z) -> t) -> WithStartState V3Model (Tree Prim) C(x) -> t commutePairFromTree = T.commutePairFromTree commuteTripleFromTree :: (RepoPatch p, PrimOf p ~ Prim) => (FORALL(y z) (p :> p :> p) C(y z) -> t) -> WithStartState V3Model (Tree Prim) C(x) -> t commuteTripleFromTree = T.commuteTripleFromTree type instance ModelOf Prim = V3Model instance ArbitraryPrim Prim hunkIdentity (Hunk _ old new) | old == new = unsafeCoerceP IsEq hunkIdentity _ = NotEq instance NullPatch Prim where nullPatch (BinaryHunk _ x) = hunkIdentity x nullPatch (TextHunk _ x) = hunkIdentity x nullPatch _ = NotEq instance Arbitrary (Sealed2 (FL (WithState V3Model Prim))) where arbitrary = do repo <- ourSmallRepo liftM (unseal (seal2 . wesPatch)) $ arbitraryState repo -- instance Show1 (TreeWithFlattenPos Prim) where -- showDict1 = ShowDictClass -- WithState and propFail are handy for debugging arbitrary code propFail :: Int -> Tree Prim C(x) -> Bool propFail n xs = sizeTree xs < n ---------------------------------------------------------------------- -- * QuickCheck generators aHunk :: FORALL(x y) BS.ByteString -> Gen (Hunk C(x y)) aHunk content = sized $ \n -> do pos <- choose (0, BS.length content) let prefixLen = pos restLen = BS.length content - prefixLen oldLen <- frequency [ (75, choose (0, min restLen n)) , (25, choose (0, min 10 restLen)) ] let nonempty x = if oldLen /= 0 then x else 0 newLen <- frequency [ ( 54, choose (1,min 1 n) ) , ( nonempty 42, choose (1,min 1 oldLen) ) , ( nonempty 2, return oldLen ) , ( nonempty 2, return 0 ) ] new <- BS.concat <$> vectorOf newLen aLine let old = BS.take oldLen $ BS.drop prefixLen $ content return $ Hunk pos old new aTextHunk :: FORALL (x y) (UUID, Object Fail) -> Gen (Prim C(x y)) aTextHunk (uuid, (Blob text _)) = do hunk <- aHunk (unFail text) return $ TextHunk uuid hunk aManifest :: FORALL (x y) UUID -> Location -> Object Fail -> Gen (Prim C(x y)) aManifest uuid loc (Directory dir) = do newFilename <- aFilename `notIn` (M.keys dir) return $ Manifest uuid loc aDemanifest :: FORALL (x y) UUID -> Location -> Gen (Prim C(x y)) aDemanifest uuid loc = return $ Demanifest uuid loc -- | Generates any type of 'Prim' patch, except binary and setpref patches. aPrim :: FORALL(x y) V3Model C(x) -> Gen (WithEndState V3Model (Prim C(x)) C(y)) aPrim repo = do mbFile <- maybeOf repoFiles mbDir <- maybeOf repoDirs mbExisting <- maybeOf $ repoObjects repo mbManifested <- maybeOf manifested fresh <- anUUID filename <- aFilename dir <- elements (rootDir:repoDirs) mbOtherDir <- maybeOf repoDirs let whenfile x = if isJust mbFile then x else 0 whendir x = if isJust mbDir then x else 0 whenexisting x = if isJust mbExisting then x else 0 whenmanifested x = if isJust mbManifested then x else 0 patch <- frequency [ ( whenfile 12, aTextHunk $ fromJust mbFile ) , ( 2, aTextHunk (fresh, Blob (return "") NoHash) ) -- create an empty thing , ( whenexisting (whendir 2), -- manifest an existing object aManifest (fst $ fromJust mbExisting) (fst $ fromJust mbDir, filename) (snd $ fromJust mbDir)) , ( whenmanifested 2, uncurry aDemanifest $ fromJust mbManifested ) -- TODO: demanifest ] let repo' = unFail $ repoApply repo patch return $ WithEndState patch repo' where manifested = [ (id, (dirid, name)) | (dirid, Directory dir) <- repoDirs , (name, id) <- M.toList dir ] repoFiles = [ (id, Blob x y) | (id, Blob x y) <- repoObjects repo ] repoDirs = [ (id, Directory x) | (id, Directory x) <- repoObjects repo ] rootDir = (UUID "ROOT", root repo) ---------------------------------------------------------------------- -- *** Pairs of primitive patches -- Try to generate commutable pairs of hunks hunkPair :: FORALL(x y) (UUID, Object Fail) -> Gen ((Prim :> Prim) C(x y)) hunkPair (uuid, (Blob file _)) = do h1@(Hunk l1 old1 new1) <- aHunk (unFail file) (delta, content') <- selectChunk h1 (unFail file) Hunk l2' old2 new2 <- aHunk content' let l2 = l2'+delta return (TextHunk uuid (Hunk l1 old1 new1) :> TextHunk uuid (Hunk l2 old2 new2)) where selectChunk (Hunk l old new) content = elements [prefix, suffix] where start = l - 1 prefix = (0, BS.take start content) suffix = (start + BS.length new, BS.drop (start + BS.length old) content) selectChunk _ _ = impossible aPrimPair :: FORALL(x y) V3Model C(x) -> Gen (WithEndState V3Model ((Prim :> Prim) C(x)) C(y)) aPrimPair repo = do mbFile <- maybeOf repoFiles frequency [ ( if isJust mbFile then 1 else 0 , do p1 :> p2 <- hunkPair $ fromJust mbFile let repo' = unFail $ repoApply repo p1 repo'' = unFail $ repoApply repo' p2 return $ WithEndState (p1 :> p2) repo'' ) , ( 1 , do Sealed wesP <- arbitraryState repo return $ unsafeCoerceP1 wesP ) ] where repoFiles = [ (id, Blob x y) | (id, Blob x y) <- repoObjects repo ] ---------------------------------------------------------------------- -- Arbitrary instances ourSmallRepo :: Gen (V3Model C(x)) ourSmallRepo = aSmallRepo instance ArbitraryState V3Model Prim where arbitraryState s = seal <$> aPrim s instance Arbitrary (Sealed2 Prim) where arbitrary = makeS2Gen ourSmallRepo instance Arbitrary (Sealed (Prim x)) where arbitrary = makeSGen ourSmallRepo instance Arbitrary (Sealed2 (Prim :> Prim)) where arbitrary = do repo <- ourSmallRepo WithEndState pp _ <- aPrimPair repo return $ seal2 pp instance Arbitrary (Sealed ((Prim :> Prim) C(a))) where arbitrary = do repo <- ourSmallRepo WithEndState pp _ <- aPrimPair repo return $ seal pp instance Arbitrary (Sealed2 (Prim :> Prim :> Prim)) where arbitrary = makeS2Gen ourSmallRepo instance Arbitrary (Sealed ((Prim :> Prim :> Prim) a)) where arbitrary = makeSGen ourSmallRepo instance Arbitrary (Sealed2 (FL Prim)) where arbitrary = makeS2Gen ourSmallRepo instance Arbitrary (Sealed ((FL Prim) C(a))) where arbitrary = makeSGen ourSmallRepo instance Arbitrary (Sealed2 (FL Prim :> FL Prim)) where arbitrary = makeS2Gen ourSmallRepo instance Arbitrary (Sealed ((FL Prim :> FL Prim) C(a))) where arbitrary = makeSGen ourSmallRepo instance Arbitrary (Sealed2 (WithState V3Model Prim)) where arbitrary = makeWS2Gen ourSmallRepo instance Arbitrary (Sealed (WithState V3Model Prim C(a))) where arbitrary = makeWSGen ourSmallRepo instance Arbitrary (Sealed (WithState V3Model (FL Prim) C(a))) where arbitrary = makeWSGen ourSmallRepo instance Arbitrary (Sealed2 (WithState V3Model (Prim :> Prim))) where arbitrary = do repo <- ourSmallRepo WithEndState pp repo' <- aPrimPair repo return $ seal2 $ WithState repo pp repo' instance Arbitrary (Sealed (WithState V3Model (Prim :> Prim) a)) where arbitrary = do repo <- ourSmallRepo WithEndState pp repo' <- aPrimPair repo return $ seal $ WithState repo pp repo' instance Arbitrary (Sealed2 (WithState V3Model (FL Prim))) where arbitrary = makeWS2Gen ourSmallRepo instance Arbitrary (Sealed2 (WithState V3Model (FL Prim :> FL Prim))) where arbitrary = makeWS2Gen ourSmallRepo instance Arbitrary (Sealed (WithState V3Model (FL Prim :> FL Prim) a)) where arbitrary = makeWSGen ourSmallRepo darcs-2.8.4/src/Darcs/Test/Patch/Arbitrary/PatchV1.hs0000644001765600176560000002402112104371431021502 0ustar ganeshganesh-- Copyright (C) 2002-2003,2007 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# OPTIONS_GHC -fno-warn-orphans #-} {-# LANGUAGE CPP, FlexibleInstances, TypeSynonymInstances #-} #include "gadts.h" module Darcs.Test.Patch.Arbitrary.PatchV1 () where import Prelude hiding ( pi ) import System.IO.Unsafe ( unsafePerformIO ) import Test.QuickCheck import Control.Applicative import Control.Monad ( liftM, liftM2, liftM3, liftM4, replicateM ) import Darcs.Patch.Info ( PatchInfo, patchinfo ) import qualified Data.ByteString as B ( ByteString ) import qualified Data.ByteString.Char8 as BC ( pack ) import Darcs.Patch ( addfile, adddir, move, hunk, tokreplace, binary, changepref, invert, merge ) import Darcs.Patch.V1 () import qualified Darcs.Patch.V1.Core as V1 ( Patch(..) ) import Darcs.Patch.Prim.V1 () import Darcs.Patch.Prim.V1.Core ( Prim(..) ) import Darcs.Witnesses.Ordered import Darcs.Witnesses.Sealed ( Sealed(Sealed), unseal, mapSeal, Sealed2(..) ) import Darcs.Witnesses.Unsafe -- This definitely feels a bit weird to be importing Properties here, and -- probably means we want to move this elsewhere, but Darcs.Test.Patch.Check is -- already taken with something apparently only semi-related import Darcs.Test.Patch.Properties.Check( checkAPatch ) #include "impossible.h" type Patch = V1.Patch Prim class ArbitraryP p where arbitraryP :: Gen (Sealed (p C(x))) {- TODO: there is a lot of overlap in testing between between this module and Darcs.Test.Patch.QuickCheck This module tests Prim and V1 patches, and Darcs.Test.Patch.QuickCheck tests Prim and V2 patches This module's generator covers a wider set of patch types, but is less likely to generate conflicts than Darcs.Test.Patch.QuickCheck. Until this is cleaned up, we take some care that the Arbitrary instances do not overlap and are only used for tests from the respective modules. (There are also tests in other modules that probably depend on the Arbitrary instances in this module.) -} instance Arbitrary (Sealed (Prim C(x))) where arbitrary = arbitraryP instance Arbitrary (Sealed (FL Patch C(x))) where arbitrary = arbitraryP -- instance Arbitrary (Sealed2 (Prim :> Prim)) where -- arbitrary = unseal Sealed2 <$> arbitraryP instance Arbitrary (Sealed2 (FL Patch)) where arbitrary = unseal Sealed2 <$> arbitraryP instance Arbitrary (Sealed2 (FL Patch :\/: FL Patch)) where arbitrary = unseal Sealed2 <$> arbitraryP instance Arbitrary (Sealed2 (FL Patch :> FL Patch)) where arbitrary = unseal Sealed2 <$> arbitraryP instance Arbitrary (Sealed2 (FL Patch :> FL Patch :> FL Patch)) where arbitrary = unseal Sealed2 <$> arbitraryP instance (ArbitraryP p1, ArbitraryP p2) => ArbitraryP (p1 :> p2) where arbitraryP = do Sealed p1 <- arbitraryP Sealed p2 <- arbitraryP return (Sealed (p1 :> p2)) instance (ArbitraryP p1, ArbitraryP p2) => ArbitraryP (p1 :\/: p2) where arbitraryP = do Sealed p1 <- arbitraryP Sealed p2 <- arbitraryP return (Sealed (unsafeCoercePEnd p1 :\/: p2)) instance ArbitraryP (FL Patch) where arbitraryP = sized arbpatch instance ArbitraryP Prim where arbitraryP = onepatchgen hunkgen :: Gen (Sealed (Prim C(x))) hunkgen = do i <- frequency [(1,choose (0,5)),(1,choose (0,35)), (2,return 0),(3,return 1),(2,return 2),(1,return 3)] j <- frequency [(1,choose (0,5)),(1,choose (0,35)), (2,return 0),(3,return 1),(2,return 2),(1,return 3)] if i == 0 && j == 0 then hunkgen else Sealed <$> liftM4 hunk filepathgen linenumgen (replicateM i filelinegen) (replicateM j filelinegen) tokreplacegen :: Gen (Sealed (Prim C(x))) tokreplacegen = do f <- filepathgen o <- tokengen n <- tokengen if o == n then return $ Sealed $ tokreplace f "A-Za-z" "old" "new" else return $ Sealed $ tokreplace f "A-Za-z_" o n twofilegen :: (FORALL(y) FilePath -> FilePath -> Prim C(x y)) -> Gen (Sealed (Prim C(x))) twofilegen p = do n1 <- filepathgen n2 <- filepathgen if n1 /= n2 && checkAPatch (p n1 n2) then return $ Sealed $ p n1 n2 else twofilegen p chprefgen :: Gen (Sealed (Prim C(x))) chprefgen = do f <- oneof [return "color", return "movie"] o <- tokengen n <- tokengen if o == n then return $ Sealed $ changepref f "old" "new" else return $ Sealed $ changepref f o n simplepatchgen :: Gen (Sealed (Prim C(x))) simplepatchgen = frequency [(1,liftM (Sealed . addfile) filepathgen), (1,liftM (Sealed . adddir) filepathgen), (1,liftM3 (\x y z -> Sealed (binary x y z)) filepathgen arbitrary arbitrary), (1,twofilegen move), (1,tokreplacegen), (1,chprefgen), (7,hunkgen) ] onepatchgen :: Gen (Sealed (Prim C(x))) onepatchgen = oneof [simplepatchgen, mapSeal (invert . unsafeCoerceP) `fmap` simplepatchgen] norecursgen :: Int -> Gen (Sealed (FL Patch C(x))) norecursgen 0 = mapSeal (\p -> V1.PP p :>: NilFL) `fmap` onepatchgen norecursgen n = oneof [mapSeal (\p -> V1.PP p :>: NilFL) `fmap` onepatchgen,flatcompgen n] arbpatch :: Int -> Gen (Sealed (FL Patch C(x))) arbpatch 0 = mapSeal (\p -> V1.PP p :>: NilFL) `fmap` onepatchgen arbpatch n = frequency [(3,mapSeal (\p -> V1.PP p :>: NilFL) `fmap` onepatchgen), (2,flatcompgen n), (0,rawMergeGen n), (0,mergegen n), (1,mapSeal (\p -> V1.PP p :>: NilFL) `fmap` onepatchgen) ] -- | Generate an arbitrary list of at least one element unempty :: Arbitrary a => Gen [a] unempty = do a <- arbitrary as <- arbitrary return (a:as) rawMergeGen :: Int -> Gen (Sealed (FL Patch C(x))) rawMergeGen n = do Sealed p1 <- arbpatch len Sealed p2 <- arbpatch len if checkAPatch (invert p1:>:p2:>:NilFL) && checkAPatch (invert p2:>:p1:>:NilFL) then case merge (p2 :\/: p1) of _ :/\: p2' -> return (Sealed (unsafeCoercePStart p2')) else rawMergeGen n where len = if n < 15 then n`div`3 else 3 mergegen :: Int -> Gen (Sealed (FL Patch C(x))) mergegen n = do Sealed p1 <- norecursgen len Sealed p2 <- norecursgen len if checkAPatch (invert p1:>:p2:>:NilFL) && checkAPatch (invert p2:>:p1:>:NilFL) then case merge (p2:\/:p1) of _ :/\: p2' -> if checkAPatch (p1+>+p2') then return $ Sealed $ p1+>+p2' else impossible else mergegen n where len = if n < 15 then n`div`3 else 3 arbpi :: Gen PatchInfo arbpi = do n <- unempty a <- unempty l <- unempty d <- unempty return $ unsafePerformIO $ patchinfo n d a l instance Arbitrary PatchInfo where arbitrary = arbpi instance Arbitrary B.ByteString where arbitrary = liftM BC.pack arbitrary flatlistgen :: Int -> Gen (Sealed (FL Patch C(x))) flatlistgen 0 = return $ Sealed NilFL flatlistgen n = do Sealed x <- onepatchgen Sealed xs <- flatlistgen (n-1) return (Sealed (V1.PP x :>: xs)) flatcompgen :: Int -> Gen (Sealed (FL Patch C(x))) flatcompgen n = do Sealed ps <- flatlistgen n let myp = regularizePatches $ ps if checkAPatch myp then return $ Sealed myp else flatcompgen n -- resize to size 25, that means we'll get line numbers no greater -- than 1025 using QuickCheck 2.1 linenumgen :: Gen Int linenumgen = frequency [(1,return 1), (1,return 2), (1,return 3), (3,liftM (\n->1+abs n) (resize 25 arbitrary)) ] tokengen :: Gen String tokengen = oneof [return "hello", return "world", return "this", return "is", return "a", return "silly", return "token", return "test"] toklinegen :: Gen String toklinegen = liftM unwords $ replicateM 3 tokengen filelinegen :: Gen B.ByteString filelinegen = liftM BC.pack $ frequency [(1,map fromSafeChar `fmap` arbitrary),(5,toklinegen), (1,return ""), (1,return "{"), (1,return "}") ] filepathgen :: Gen String filepathgen = liftM fixpath badfpgen fixpath :: String -> String fixpath "" = "test" fixpath p = fpth p fpth :: String -> String fpth ('/':'/':cs) = fpth ('/':cs) fpth (c:cs) = c : fpth cs fpth [] = [] newtype SafeChar = SS Char instance Arbitrary SafeChar where arbitrary = oneof $ map (return . SS) (['a'..'z']++['A'..'Z']++['1'..'9']++"0") fromSafeChar :: SafeChar -> Char fromSafeChar (SS s) = s badfpgen :: Gen String badfpgen = frequency [(1,return "test"), (1,return "hello"), (1,return "world"), (1,map fromSafeChar `fmap` arbitrary), (1,liftM2 (\a b-> a++"/"++b) filepathgen filepathgen) ] regularizePatches :: FL Patch C(x y) -> FL Patch C(x y) regularizePatches patches = rpint (unsafeCoerceP NilFL) patches where -- this reverses the list, which seems odd and causes -- the witness unsafety rpint :: FL Patch C(x y) -> FL Patch C(a b) -> FL Patch C(x y) rpint ok_ps NilFL = ok_ps rpint ok_ps (p:>:ps) = if checkAPatch (unsafeCoerceP p:>:ok_ps) then rpint (unsafeCoerceP p:>:ok_ps) ps else rpint ok_ps ps darcs-2.8.4/src/Darcs/Test/Patch/Check.hs0000644001765600176560000003164012104371431017317 0ustar ganeshganesh-- Copyright (C) 2002-2003 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. module Darcs.Test.Patch.Check ( PatchCheck(), doCheck, fileExists, dirExists, removeFile, removeDir, createFile, createDir, insertLine, deleteLine, isValid, doVerboseCheck, fileEmpty, checkMove, modifyFile, FileContents(..) ) where import System.IO.Unsafe ( unsafePerformIO ) import qualified Data.ByteString as B (ByteString) import Data.List ( isPrefixOf, inits ) import Control.Monad.State ( State, evalState, runState ) import Control.Monad.State.Class ( get, put, modify ) -- use Map, not IntMap, because Map has mapKeys and IntMap hasn't import Data.Map ( Map ) import qualified Data.Map as M ( mapKeys, delete, insert, empty, lookup, null ) import System.FilePath ( joinPath, splitDirectories ) #include "impossible.h" -- | File contents are represented by a map from line numbers to line contents. -- If for a certain line number, the line contents are Nothing, that means -- that we are sure that that line exists, but we don't know its contents. -- We must also store the greatest line number that is known to exist in a -- file, to be able to exclude the possibility of it being empty without -- knowing its contents. data FileContents = FC { fcLines :: Map Int B.ByteString , fcMaxline :: Int } deriving (Eq, Show) data Prop = FileEx String | DirEx String | NotEx String | FileLines String FileContents deriving (Eq) -- | A @KnownState@ is a simulated repository state. The repository is either -- inconsistent, or it has two lists of properties: one list with properties -- that hold for this repo, and one with properties that do not hold for this -- repo. These two lists may not have any common elements: if they had, the -- repository would be inconsistent. data KnownState = P [Prop] [Prop] | Inconsistent deriving (Show) instance Show Prop where show (FileEx f) = "FileEx "++f show (DirEx d) = "DirEx "++d show (NotEx f) = "NotEx"++f show (FileLines f l) = "FileLines "++f++": "++show l -- TODO the way that the standard way to use PatchCheck is -- by returning PatchCheck Bool but then often ignoring the -- result and instead checking again for state consistency -- is weird. It should be possible to replace it by a more normal -- error handling mechanism. -- | PatchCheck is a state monad with a simulated repository state type PatchCheck = State KnownState -- | The @FileContents@ structure for an empty file emptyFilecontents :: FileContents emptyFilecontents = FC M.empty 0 -- | Returns a given value if the repository state is inconsistent, and performs -- a given action otherwise. handleInconsistent :: a -- ^ The value to return if the state is inconsistent -> PatchCheck a -- ^ The action to perform otherwise -> PatchCheck a handleInconsistent v a = do state <- get case state of Inconsistent -> return v _ -> a doCheck :: PatchCheck a -> a doCheck p = evalState p (P [] []) -- | Run a check, and print the final repository state doVerboseCheck :: PatchCheck a -> a doVerboseCheck p = case runState p (P [] []) of (b, pc) -> unsafePerformIO $ do print pc return b -- | Returns true if the current repository state is not inconsistent isValid :: PatchCheck Bool isValid = handleInconsistent False (return True) has :: Prop -> [Prop] -> Bool has _ [] = False has k (k':ks) = k == k' || has k ks modifyFile :: String -> (Maybe FileContents -> Maybe FileContents) -> PatchCheck Bool modifyFile f change = do _ <- fileExists f c <- fileContents f case change c of Nothing -> assertNot $ FileEx f -- shorthand for "FAIL" Just c' -> do setContents f c' isValid insertLine :: String -> Int -> B.ByteString -> PatchCheck Bool insertLine f n l = do c <- fileContents f case c of Nothing -> assertNot $ FileEx f -- in this case, the repo is inconsistent Just c' -> do let lines' = M.mapKeys (\k -> if k >= n then k+1 else k) (fcLines c') lines'' = M.insert n l lines' maxline' = max n (fcMaxline c') setContents f (FC lines'' maxline') return True -- deletes a line from a hunk patch (third argument) in the given file (first -- argument) at the given line number (second argument) deleteLine :: String -> Int -> B.ByteString -> PatchCheck Bool deleteLine f n l = do c <- fileContents f case c of Nothing -> assertNot $ FileEx f Just c' -> let flines = fcLines c' flines' = M.mapKeys (\k -> if k > n then k-1 else k) (M.delete n flines) maxlinenum' | n <= fcMaxline c' = fcMaxline c' - 1 | otherwise = n - 1 c'' = FC flines' maxlinenum' do_delete = do setContents f c'' isValid in case M.lookup n flines of Nothing -> do_delete Just l' -> if l == l' then do_delete else assertNot $ FileEx f setContents :: String -> FileContents -> PatchCheck () setContents f c = handleInconsistent () $ do P ks nots <- get let ks' = FileLines f c : filter (not . is_file_lines_for f) ks put (P ks' nots) where is_file_lines_for file prop = case prop of FileLines f' _ -> file == f' _ -> False -- | Get (as much as we know about) the contents of a file in the current state. -- Returns Nothing if the state is inconsistent. fileContents :: String -> PatchCheck (Maybe FileContents) fileContents f = handleInconsistent Nothing $ do P ks _ <- get return (fic ks) where fic (FileLines f' c:_) | f == f' = Just c fic (_:ks) = fic ks fic [] = Just emptyFilecontents -- | Checks if a file is empty fileEmpty :: String -- ^ Name of the file to check -> PatchCheck Bool fileEmpty f = do c <- fileContents f let empty = case c of Just c' -> fcMaxline c' == 0 && M.null (fcLines c') Nothing -> True _ <- if empty then do setContents f emptyFilecontents isValid -- Crude way to make it inconsistent and return false: else assertNot $ FileEx f return empty movedirfilename :: String -> String -> String -> String movedirfilename d d' f | (d ++ "/") `isPrefixOf` f = d' ++ drop (length d) f | f == d = d' | otherwise = f -- | Replaces a filename by another in all paths. Returns True if the repository -- is consistent, False if it is not. doSwap :: String -> String -> PatchCheck Bool doSwap f f' = handleInconsistent False $ do modify map_sw return True where sw (FileEx a) | f `is_soe` a = FileEx $ movedirfilename f f' a | f' `is_soe` a = FileEx $ movedirfilename f' f a sw (DirEx a) | f `is_soe` a = DirEx $ movedirfilename f f' a | f' `is_soe` a = DirEx $ movedirfilename f' f a sw (FileLines a c) | f `is_soe` a = FileLines (movedirfilename f f' a) c | f' `is_soe` a = FileLines (movedirfilename f' f a) c sw (NotEx a) | f `is_soe` a = NotEx $ movedirfilename f f' a | f' `is_soe` a = NotEx $ movedirfilename f' f a sw p = p is_soe d1 d2 = -- is_superdir_or_equal d1 == d2 || (d1 ++ "/") `isPrefixOf` d2 map_sw (P ks nots) = P (map sw ks) (map sw nots) map_sw _ = impossible -- | Assert a property about the repository. If the property is already present -- in the repo state, nothing changes, and the function returns True. If it is -- not present yet, it is added to the repo state, and the function is True. If -- the property is already in the list of properties that do not hold for the -- repo, the state becomes inconsistent, and the function returns false. assert :: Prop -> PatchCheck Bool assert p = handleInconsistent False $ do P ks nots <- get if has p nots then do put Inconsistent return False else if has p ks then return True else do put (P (p:ks) nots) return True -- | Like @assert@, but negatively: state that some property must not hold for -- the current repo. assertNot :: Prop -> PatchCheck Bool assertNot p = handleInconsistent False $ do P ks nots <- get if has p ks then do put Inconsistent return False else if has p nots then return True else do put (P ks (p:nots)) return True -- | Remove a property from the list of properties that do not hold for this -- repo (if it's there), and add it to the list of properties that hold. -- Returns False if the repo is inconsistent, True otherwise. changeToTrue :: Prop -> PatchCheck Bool changeToTrue p = handleInconsistent False $ do modify filter_nots return True where filter_nots (P ks nots) = P (p:ks) (filter (p /=) nots) filter_nots _ = impossible -- | Remove a property from the list of properties that hold for this repo (if -- it's in there), and add it to the list of properties that do not hold. -- Returns False if the repo is inconsistent, True otherwise. changeToFalse :: Prop -> PatchCheck Bool changeToFalse p = handleInconsistent False $ do modify filter_ks return True where filter_ks (P ks nots) = P (filter (p /=) ks) (p:nots) filter_ks _ = impossible assertFileExists :: String -> PatchCheck Bool assertFileExists f = do _ <- assertNot $ NotEx f _ <- assertNot $ DirEx f assert $ FileEx f assertDirExists :: String -> PatchCheck Bool assertDirExists d = do _ <- assertNot $ NotEx d _ <- assertNot $ FileEx d assert $ DirEx d assertExists :: String -> PatchCheck Bool assertExists f = assertNot $ NotEx f assertNoSuch :: String -> PatchCheck Bool assertNoSuch f = do _ <- assertNot $ FileEx f _ <- assertNot $ DirEx f assert $ NotEx f createFile :: String -> PatchCheck Bool createFile fn = do _ <- superdirsExist fn _ <- assertNoSuch fn _ <- changeToTrue (FileEx fn) changeToFalse (NotEx fn) createDir :: String -> PatchCheck Bool createDir fn = do _ <- substuffDontExist fn _ <- superdirsExist fn _ <- assertNoSuch fn _ <- changeToTrue (DirEx fn) changeToFalse (NotEx fn) removeFile :: String -> PatchCheck Bool removeFile fn = do _ <- superdirsExist fn _ <- assertFileExists fn _ <- fileEmpty fn _ <- changeToFalse (FileEx fn) changeToTrue (NotEx fn) removeDir :: String -> PatchCheck Bool removeDir fn = do _ <- substuffDontExist fn _ <- superdirsExist fn _ <- assertDirExists fn _ <- changeToFalse (DirEx fn) changeToTrue (NotEx fn) checkMove :: String -> String -> PatchCheck Bool checkMove f f' = do _ <- superdirsExist f _ <- superdirsExist f' _ <- assertExists f _ <- assertNoSuch f' doSwap f f' substuffDontExist :: String -> PatchCheck Bool substuffDontExist d = handleInconsistent False $ do P ks _ <- get if all noss ks then return True else do put Inconsistent return False where noss (FileEx f) = not (is_within_dir f) noss (DirEx f) = not (is_within_dir f) noss _ = True is_within_dir f = (d ++ "/") `isPrefixOf` f -- the init and tail calls dump the final init (which is just the path itself -- again), the first init (which is empty), and the initial "." from -- splitDirectories superdirsExist :: String -> PatchCheck Bool superdirsExist fn = and `fmap` mapM assertDirExists superdirs where superdirs = map (("./"++) . joinPath) (init (tail (inits (tail (splitDirectories fn))))) fileExists :: String -> PatchCheck Bool fileExists fn = do _ <- superdirsExist fn assertFileExists fn dirExists :: String -> PatchCheck Bool dirExists fn = do _ <- superdirsExist fn assertDirExists fn darcs-2.8.4/src/Darcs/Test/Patch/WSub.hs0000644001765600176560000001145512104371431017164 0ustar ganeshganesh{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, UndecidableInstances #-} module Darcs.Test.Patch.WSub where {- The Examples.Set2Unwitnessed module builds a lot of test cases by pattern matching on the results of merge/commute in where clauses. This would be very painful to switch to using witnesses properly, because we'd have to make them use case in series. So instead we give up on witnesses for this module, but instead of preprocessor hacks which make incompatible code with the rest of darcs, we build a fresh set of witnesses constructors (FL etc) which aren't actually GADTs or existentials. So the pattern matching works as before, but we need to translate back and forth a lot. We call the normal darcs constructors the 'W' variants. -} import qualified Darcs.Test.Patch.Arbitrary.Generic as W ( getPairs, getTriples ) import qualified Darcs.Patch as W ( commute ) import qualified Darcs.Patch.Merge as W ( merge, mergeFL ) import qualified Darcs.Patch.Prim as W ( join ) import qualified Darcs.Witnesses.Ordered as W import Darcs.Witnesses.Sealed import Darcs.Witnesses.Eq import Darcs.Witnesses.Show import Darcs.Witnesses.Unsafe ( unsafeCoerceP, unsafeCoercePStart, unsafeCoercePEnd ) import Darcs.Patch.Merge ( Merge ) import Darcs.Patch.Prim.V1 ( Prim ) import Darcs.Patch.V2 ( RealPatch ) import Darcs.Patch.Patchy ( Commute, Invert(..) ) #include "gadts.h" infixr 5 :>: infixr 5 +>+ infixr 1 :> infix 1 :/\: infix 1 :\/: data FL p C(x y) where NilFL :: FL p C(x y) (:>:) :: p C(x y) -> FL p C(x y) -> FL p C(x y) (+>+) :: FL p C(x y) -> FL p C(x y) -> FL p C(x y) NilFL +>+ ps = ps (p :>: ps) +>+ qs = p :>: (ps +>+ qs) data (p :> q) C(x y) where (:>) :: p C(x y) -> q C(x y) -> (p :> q) C(x y) data (p :\/: q) C(x y) where (:\/:) :: p C(x y) -> q C(x y) -> (p :\/: q) C(x y) data (p :/\: q) C(x y) where (:/\:) :: p C(x y) -> q C(x y) -> (p :/\: q) C(x y) class WSub wp p | p -> wp, wp -> p where fromW :: wp C(x y) -> p C(x y) toW :: p C(x y) -> wp C(x y) instance (WSub wp1 p1, WSub wp2 p2) => WSub (wp1 W.:\/: wp2) (p1 :\/: p2) where fromW (x W.:\/: y) = unsafeCoerceP (fromW x) :\/: unsafeCoerceP (fromW y) toW (x :\/: y) = unsafeCoerceP (toW x) W.:\/: unsafeCoerceP (toW y) instance (WSub wp1 p1, WSub wp2 p2) => WSub (wp1 W.:/\: wp2) (p1 :/\: p2) where fromW (x W.:/\: y) = unsafeCoerceP (fromW x) :/\: unsafeCoerceP (fromW y) toW (x :/\: y) = unsafeCoerceP (toW x) W.:/\: unsafeCoerceP (toW y) instance (WSub wp1 p1, WSub wp2 p2) => WSub (wp1 W.:> wp2) (p1 :> p2) where fromW (x W.:> y) = unsafeCoercePEnd (fromW x) :> unsafeCoercePStart (fromW y) toW (x :> y) = unsafeCoercePEnd (toW x) W.:> unsafeCoercePStart (toW y) instance WSub wp p => WSub (W.FL wp) (FL p) where fromW W.NilFL = unsafeCoerceP NilFL fromW (x W.:>: xs) = unsafeCoercePEnd (fromW x) :>: unsafeCoercePStart (fromW xs) toW NilFL = unsafeCoerceP W.NilFL toW (x :>: xs) = unsafeCoercePEnd (toW x) W.:>: unsafeCoercePStart (toW xs) instance WSub prim prim => WSub (RealPatch prim) (RealPatch prim) where fromW = id toW = id instance WSub Prim Prim where fromW = id toW = id instance (WSub wp p, WSub wq q, Show2 wp, Show2 wq) => Show ((p :> q) C(x y)) where show = show . toW instance (WSub wp p, WSub wq q, Show2 wp, Show2 wq) => Show2 (p :> q) where showDict2 = ShowDictClass instance (WSub wp p, WSub wq q, Show2 wp, Show2 wq) => Show ((p :\/: q) C(x y)) where show = show . toW instance (WSub wp p, WSub wq q, Show2 wp, Show2 wq) => Show2 (p :\/: q) where showDict2 = ShowDictClass instance (WSub wp p, Show2 wp) => Show (FL p C(x y)) where show = show . toW instance (WSub wp p, Show2 wp) => Show2 (FL p) where showDict2 = ShowDictClass instance (WSub wp p, Commute wp, MyEq wp) => MyEq (FL p) where unsafeCompare x y = unsafeCompare (toW x) (toW y) instance (WSub wp p, Commute wp, Invert wp) => Invert (FL p) where invert = fromW . invert . toW instance (WSub wp p, Commute wp) => Commute (FL p) where commute (xs W.:> ys) = do ys' W.:> xs' <- W.commute (toW xs W.:> toW ys) return (fromW ys' W.:> fromW xs') mergeFL :: (WSub wp p, Merge wp) => (p :\/: FL p) C(x y) -> (FL p :/\: p) C(x y) mergeFL = fromW . W.mergeFL . toW merge :: (WSub wp p, Merge wp) => (p :\/: p) C(x y) -> (p :/\: p) C(x y) merge = fromW . W.merge . toW commute :: (WSub wp p, Commute wp) => (p :> p) C(x y) -> Maybe ((p :> p) C(x y)) commute = fmap fromW . W.commute . toW getPairs :: FL (RealPatch Prim) C(x y) -> [Sealed2 (RealPatch Prim :> RealPatch Prim)] getPairs = map (mapSeal2 fromW) . W.getPairs . toW getTriples :: FL (RealPatch Prim) C(x y) -> [Sealed2 (RealPatch Prim :> RealPatch Prim :> RealPatch Prim)] getTriples = map (mapSeal2 fromW) . W.getTriples . toW join :: (Prim :> Prim) C(x y) -> Maybe (FL Prim C(x y)) join = fmap fromW . W.join . toW darcs-2.8.4/src/Darcs/Test/Patch/Info.hs0000644001765600176560000001616612104371431017203 0ustar ganeshganesh-- Copyright (C) 2009 Reinier Lamers -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. -- | This module contains tests for the code in Darcs.Patch.Info. Most of them -- are about the UTF-8-encoding of patch metadata. module Darcs.Test.Patch.Info ( testSuite ) where import Prelude hiding ( pi ) import Data.ByteString ( ByteString ) import qualified Data.ByteString as B ( split, pack ) import qualified Data.ByteString.Char8 as BC ( unpack ) import Data.List ( sort ) import Data.Maybe ( isNothing ) import Data.Text as T ( find, any ) import Data.Text.Encoding ( decodeUtf8With ) import Data.Text.Encoding.Error ( lenientDecode ) import Foreign ( unsafePerformIO ) import Test.QuickCheck ( Arbitrary(arbitrary), oneof, listOf, choose, shrink , Gen ) import Test.Framework.Providers.QuickCheck2 ( testProperty ) import Test.Framework (Test, testGroup) import Data.List ( isPrefixOf ) import Darcs.Patch.Info ( PatchInfo(..), patchinfo, piLog, piAuthor, piName ) import ByteStringUtils ( decodeLocale, packStringToUTF8, unpackPSFromUTF8 ) testSuite :: Test testSuite = testGroup "Darcs.Patch.Info" [ metadataDecodingTest , metadataEncodingTest , packUnpackTest ] -- | A newtype wrapping String so we can make our own random generator for it. newtype UnicodeString = UnicodeString { asString :: String } deriving (Show, Eq, Ord) -- | A newtype wrapping PatchInfo that has a random generator that generates -- both UTF-8-encoded and non-encoded PatchInfo's. newtype UTF8OrNotPatchInfo = UTF8OrNotPatchInfo PatchInfo deriving (Eq, Ord) -- | A newtype wrapping PatchInfo, which has a random generator that generates -- only UTF-8-encoded PatchInfo's. newtype UTF8PatchInfo = UTF8PatchInfo PatchInfo deriving (Eq, Ord) instance Arbitrary UnicodeString where -- 0x10ffff is the highest Unicode code point ; 0xd800 - 0xdfff are -- surrogates. '\xfffd' is excluded because it is used as a marker -- for UTF-8 test failure. arbitrary = UnicodeString `fmap` listOf (oneof [choose ('\0', '\xd799') ,choose ('\xe000', '\xfffc') ,choose ('\xfffe', '\x10ffff')]) instance Show UTF8PatchInfo where showsPrec _ = withUTF8PatchInfo rawPatchInfoShow instance Show UTF8OrNotPatchInfo where showsPrec _ = withUTF8OrNotPatchInfo rawPatchInfoShow -- | Shows a PatchInfo, outputting every byte and clearly marking what is what rawPatchInfoShow :: PatchInfo -> String -> String rawPatchInfoShow pi = ("PatchInfo: \n"++) . ("date: "++) . shows (_piDate pi) . ('\n':) . ("author: "++) . shows (_piAuthor pi) . ('\n':) . ("name: "++) . shows (_piName pi) . ('\n':) . ("log: "++) . shows (_piLog pi) . ('\n':) instance Arbitrary UTF8PatchInfo where arbitrary = UTF8PatchInfo `fmap` arbitraryUTF8Patch shrink upi = flip withUTF8PatchInfo upi $ \pi -> do sn <- shrink (piName pi) sa <- shrink (piAuthor pi) sl <- shrink (filter (not . isPrefixOf "Ignore-this:") (piLog pi)) return (UTF8PatchInfo (unsafePerformIO $ patchinfo sn (BC.unpack (_piDate pi)) sa sl)) instance Arbitrary UTF8OrNotPatchInfo where arbitrary = UTF8OrNotPatchInfo `fmap` oneof ([arbitraryUTF8Patch, arbitraryUnencodedPatch]) -- | Generate arbitrary patch metadata that uses the metadata creation function -- 'patchinfo' from Darcs.Patch.Info. arbitraryUTF8Patch :: Gen PatchInfo arbitraryUTF8Patch = do n <- asString `fmap` arbitrary d <- arbitrary a <- asString `fmap` arbitrary l <- (lines . asString) `fmap` arbitrary return $ unsafePerformIO $ patchinfo n d a l -- | Generate arbitrary patch metadata that has totally arbitrary byte strings -- as its name, date, author and log. arbitraryUnencodedPatch :: Gen PatchInfo arbitraryUnencodedPatch = do n <- arbitraryByteString d <- arbitraryByteString a <- arbitraryByteString -- split 10 is the ByteString equivalent of 'lines' l <- B.split 10 `fmap` arbitraryByteString i <- arbitrary return (PatchInfo d n a l i) arbitraryByteString :: Gen ByteString arbitraryByteString = (B.pack . map fromIntegral) `fmap` listOf (choose (0, 255) :: Gen Int) -- | Test that anything produced by the 'patchinfo' function is valid UTF-8 metadataEncodingTest :: Test metadataEncodingTest = testProperty "Testing patch metadata encoding" $ withUTF8PatchInfo $ \patchInfo -> encodingOK (_piAuthor patchInfo) && encodingOK (_piName patchInfo) && all encodingOK (_piLog patchInfo) where encodingOK = isNothing . T.find (=='\xfffd') . decodeUtf8With lenientDecode -- | Test that metadata in patches are decoded as UTF-8 or locale depending on -- whether they're valid UTF-8. metadataDecodingTest :: Test metadataDecodingTest = testProperty "Testing patch metadata decoding" $ withUTF8OrNotPatchInfo $ \patchInfo -> utf8OrLocale (_piAuthor patchInfo) == piAuthor patchInfo && utf8OrLocale (_piName patchInfo) == piName patchInfo && map utf8OrLocale (_piLog patchInfo) `superset` piLog patchInfo where utf8OrLocale bs = if isValidUTF8 bs then unpackPSFromUTF8 bs else decodeLocale bs isValidUTF8 :: ByteString -> Bool isValidUTF8 = not . T.any (=='\xfffd') . decodeUtf8With lenientDecode packUnpackTest :: Test packUnpackTest = testProperty "Testing UTF-8 packing and unpacking" $ \uString -> asString uString == (unpackPSFromUTF8 . packStringToUTF8) (asString uString) superset :: (Eq a, Ord a) => [a] -> [a] -> Bool superset a b = sorted_superset (sort a) (sort b) where sorted_superset (x:xs) (y:ys) | x == y = sorted_superset xs ys | x < y = sorted_superset xs (y:ys) | otherwise = False sorted_superset [] (_:_) = False sorted_superset _ [] = True withUTF8PatchInfo :: (PatchInfo -> a) -> UTF8PatchInfo -> a withUTF8PatchInfo f mpi = case mpi of UTF8PatchInfo pinf -> f pinf withUTF8OrNotPatchInfo :: (PatchInfo -> a) -> UTF8OrNotPatchInfo -> a withUTF8OrNotPatchInfo f mpi = case mpi of UTF8OrNotPatchInfo pinf -> f pinf darcs-2.8.4/src/Darcs/Test/Patch/RepoModel.hs0000644001765600176560000000122412104371431020163 0ustar ganeshganeshmodule Darcs.Test.Patch.RepoModel where import Darcs.Patch.Apply ( Apply, ApplyState ) import Test.QuickCheck ( Gen ) type Fail = Either String unFail :: Either [Char] t -> t unFail (Right x) = x unFail (Left err) = error $ "unFail failed: " ++ err maybeFail :: Either t a -> Maybe a maybeFail (Right x) = Just x maybeFail _ = Nothing class RepoModel model where type RepoState model :: (* -> *) -> * showModel :: model x -> String eqModel :: model x -> model x -> Bool aSmallRepo :: Gen (model x) repoApply :: (Apply p, ApplyState p ~ RepoState model) => model x -> p x y -> Fail (model y) type family ModelOf (patch :: * -> * -> *) :: * -> * darcs-2.8.4/src/Darcs/Test/Patch/Utils.hs0000644001765600176560000000203412104371431017375 0ustar ganeshganeshmodule Darcs.Test.Patch.Utils ( testConditional, testStringList ) where import Test.Framework ( Test, TestName ) import Test.Framework.Providers.HUnit ( testCase ) import Test.Framework.Providers.QuickCheck2 ( testProperty ) import Test.HUnit ( assertFailure ) import Test.QuickCheck ( Arbitrary, Testable, (==>) ) -- | Turns a condition and a test function into a conditional quickcheck -- property that can be run by test-framework. testConditional :: (Arbitrary a, Show a, Testable prop) => TestName -- ^ Test name -> (a -> Bool) -- ^ Condition -> (a -> prop) -- ^ Test function -> Test testConditional name cond t = testProperty name t' where t' x = cond x ==> t x -- | Utility function to run old tests that return a list of error messages, -- with the empty list meaning success. testStringList :: String -> [String] -> Test testStringList name test = testCase name $ mapM_ assertFailure test darcs-2.8.4/src/Darcs/Test/Patch/V1Model.hs0000644001765600176560000002124112104371431017545 0ustar ganeshganesh{-# LANGUAGE CPP #-} #include "gadts.h" -- | Repository model module Darcs.Test.Patch.V1Model ( module Storage.Hashed.AnchoredPath , V1Model, repoTree , RepoItem, File, Dir, Content , makeRepo, emptyRepo , makeFile, emptyFile , emptyDir , nullRepo , isFile, isDir , fileContent, dirContent , isEmpty , root , filterFiles, filterDirs , find , list , ap2fp , aFilename, aDirname , aLine, aContent , aFile, aDir , aRepo ) where import Darcs.Test.Util.QuickCheck ( alpha, uniques, bSized ) import Darcs.Test.Patch.RepoModel import Darcs.Patch.Apply( applyToTree ) import Darcs.Witnesses.Sealed ( Sealed, seal ) import Darcs.Witnesses.Show import Storage.Hashed.AnchoredPath import Storage.Hashed.Tree( Tree, TreeItem ) import Storage.Hashed.Darcs ( darcsUpdateHashes ) import qualified Storage.Hashed.Tree as T import Control.Applicative ( (<$>) ) import Control.Arrow ( second ) import qualified Data.ByteString as B import qualified Data.ByteString.Char8 as BC import qualified Data.ByteString.Lazy as BL import qualified Data.ByteString.Lazy.Char8 as BLC import Data.List ( intercalate ) import qualified Data.Map as M import Test.QuickCheck ( Arbitrary(..) , Gen, choose, vectorOf, frequency ) #include "impossible.h" ---------------------------------------------------------------------- -- * Model definition -- | A repository is an abstraction build in top of a 'Tree'. -- NB: Repository preferences are not supported yet. newtype V1Model C(x) = V1Model { repoTree :: Tree Fail } -- | Repository items may be text files or directories. -- NB: Binary files are not supported yet. newtype RepoItem = RepoItem { treeItem :: TreeItem Fail } type File = RepoItem type Dir = RepoItem type Content = [B.ByteString] ---------------------------------------- -- Instances instance Show (V1Model C(x)) where show repo = "V1Model{ " ++ intercalate " " (map showEntry $ list repo) ++ " }" where showPath = show . flatten showContent content = "[" ++ intercalate " " (map show content) ++ "]" showEntry (path,item) | isDir item = showPath path | isFile item = showPath path ++ showContent (fileContent item) showEntry _ = impossible instance Show1 V1Model where showDict1 = ShowDictClass ---------------------------------------- -- Utils bs2lbs :: B.ByteString -> BL.ByteString bs2lbs bs = BL.fromChunks [bs] lbs2bs :: BL.ByteString -> B.ByteString lbs2bs = B.concat . BL.toChunks content2lbs :: Content -> BL.ByteString content2lbs = BLC.unlines . map bs2lbs lbs2content :: BL.ByteString -> Content lbs2content = map lbs2bs . BLC.lines ---------------------------------------------------------------------- -- ** Path conversion ap2fp :: AnchoredPath -> FilePath ap2fp = anchorPath "" ---------------------------------------------------------------------- -- * Constructors makeRepo :: [(Name, RepoItem)] -> V1Model C(x) makeRepo = V1Model . T.makeTree . map (second treeItem) emptyRepo :: V1Model C(x) emptyRepo = V1Model T.emptyTree makeFile :: Content -> File makeFile = RepoItem . T.File . T.makeBlob . content2lbs emptyFile :: File emptyFile = RepoItem $ T.File T.emptyBlob emptyDir :: Dir emptyDir = RepoItem $ T.SubTree T.emptyTree ---------------------------------------------------------------------- -- * Queries nullRepo :: V1Model C(x) -> Bool nullRepo = M.null . T.items . repoTree isFile :: RepoItem -> Bool isFile (RepoItem (T.File _)) = True isFile _other = False isDir :: RepoItem -> Bool isDir (RepoItem (T.SubTree _)) = True isDir _other = False fileContent :: File -> Content fileContent (RepoItem (T.File blob)) = lbs2content $ unFail $ T.readBlob blob fileContent _other = error "fileContent: Not a file." dirContent :: Dir -> [(Name, RepoItem)] dirContent (RepoItem (T.SubTree subtree)) = map (second RepoItem) $ M.toList $ T.items subtree dirContent _other = error "dirContent: Not a directory." -- | @isEmpty file@ <=> file content is empty -- @isEmpty dir@ <=> dir has no child isEmpty :: RepoItem -> Bool isEmpty item | isFile item = null $ fileContent item | isDir item = null $ dirContent item | otherwise = undefined -- | The root directory of a repository. root :: V1Model C(x) -> Dir root = RepoItem . T.SubTree . repoTree find :: V1Model C(x) -> AnchoredPath -> Maybe RepoItem find (V1Model tree) path = RepoItem <$> T.find tree path -- | List repository items. -- NB: It does not include the root directory. list :: V1Model C(x) -> [(AnchoredPath, RepoItem)] list (V1Model tree) = map (second RepoItem) $ T.list tree ---------------------------------------------------------------------- -- ** Filtering filterFiles :: [(n, RepoItem)] -> [(n, File)] filterFiles = filter (isFile . snd) filterDirs :: [(n, RepoItem)] -> [(n, Dir)] filterDirs = filter (isDir . snd) ---------------------------------------------------------------------- -- * Comparing repositories diffRepos :: V1Model C(x) -> V1Model C(y) -> (V1Model C(u), V1Model C(v)) diffRepos repo1 repo2 = let (diff1,diff2) = unFail $ T.diffTrees hashedTree1 hashedTree2 in (V1Model diff1, V1Model diff2) where hashedTree1, hashedTree2 :: Tree Fail hashedTree1 = unFail $ darcsUpdateHashes $ repoTree repo1 hashedTree2 = unFail $ darcsUpdateHashes $ repoTree repo2 ---------------------------------------------------------------------- -- * Patch application ---------------------------------------------------------------------- -- * QuickCheck generators -- Testing code assumes that aFilename and aDirname generators -- will always be able to generate a unique name given a list of -- existing names. This should be OK as long as the number of possible -- file/dirnames is much bigger than the number of files/dirs per repository. -- 'Arbitrary' 'V1Model' instance is based on the 'aSmallRepo' generator. -- | Files are distinguish by ending their names with ".txt". aFilename :: Gen Name aFilename = do len <- choose (1,maxLength) name <- vectorOf len alpha return $ makeName (name ++ ".txt") where maxLength = 3 aDirname :: Gen Name aDirname = do len <- choose (1,maxLength) name <- vectorOf len alpha return $ makeName name where maxLength = 3 aWord :: Gen B.ByteString aWord = do c <- alpha return $ BC.pack[c] aLine :: Gen B.ByteString aLine = do wordsNo <- choose (1,2) ws <- vectorOf wordsNo aWord return $ BC.unwords ws aContent :: Gen Content aContent = bSized 0 0.5 80 $ \k -> do n <- choose (0,k) vectorOf n aLine aFile :: Gen File aFile = makeFile <$> aContent -- | See 'aRepo', the same applies for 'aDir'. aDir :: Int -- ^ Maximum number of files -> Int -- ^ Maximum number of directories -> Gen Dir aDir filesL dirL = root <$> aRepo filesL dirL -- | @aRepo filesNo dirsNo@ produces repositories with *at most* -- @filesNo@ files and @dirsNo@ directories. -- The structure of the repository is aleatory. aRepo :: Int -- ^ Maximum number of files -> Int -- ^ Maximum number of directories -> Gen (V1Model C(x)) aRepo maxFiles maxDirs = do let minFiles = if maxDirs == 0 && maxFiles > 0 then 1 else 0 filesNo <- choose (minFiles,maxFiles) let minDirs = if filesNo == 0 && maxDirs > 0 then 1 else 0 dirsNo <- choose (minDirs,maxDirs) -- NB: Thanks to laziness we don't need to care about division by zero -- since if dirsNo == 0 then neither filesPerDirL nor subdirsPerDirL will -- be evaluated. let filesPerDirL = (maxFiles-filesNo) `div` dirsNo subdirsPerDirL = (maxDirs-dirsNo) `div` dirsNo files <- vectorOf filesNo aFile filenames <- uniques filesNo aFilename dirs <- vectorOf dirsNo (aDir filesPerDirL subdirsPerDirL) dirnames <- uniques dirsNo aDirname return $ makeRepo (filenames `zip` files ++ dirnames `zip` dirs) -- | Generate small repositories. -- Small repositories help generating (potentially) conflicting patches. instance RepoModel V1Model where type RepoState V1Model = Tree showModel m = show m aSmallRepo = do filesNo <- frequency [(3, return 1), (1, return 2)] dirsNo <- frequency [(3, return 1), (1, return 0)] aRepo filesNo dirsNo repoApply (V1Model tree) patch = V1Model <$> applyToTree patch tree eqModel repo1 repo2 = let (diff1,diff2) = diffRepos repo1 repo2 in nullRepo diff1 && nullRepo diff2 instance Arbitrary (Sealed V1Model) where arbitrary = seal <$> aSmallRepo darcs-2.8.4/src/Darcs/Test/Patch/V3Model.hs0000644001765600176560000001622112104371431017551 0ustar ganeshganesh{-# OPTIONS_GHC -fno-warn-name-shadowing -fno-warn-unused-binds -fno-warn-unused-imports -fno-warn-orphans #-} {-# LANGUAGE CPP, OverloadedStrings, MultiParamTypeClasses, StandaloneDeriving #-} #include "gadts.h" -- | Repository model module Darcs.Test.Patch.V3Model ( module Storage.Hashed.AnchoredPath , V3Model , Object(..) , repoApply , emptyFile , emptyDir , nullRepo , isEmpty , root, repoObjects , aFilename, aDirname , aLine, aContent , aFile, aDir , aRepo , anUUID ) where import Darcs.Test.Util.QuickCheck ( alpha, uniques, bSized ) import Darcs.Test.Patch.RepoModel import Darcs.Patch.Apply( Apply(..), applyToState ) import Darcs.Patch.ApplyMonad( ApplyMonad(..) ) import Darcs.Patch.Prim.V3.Core( UUID(..), Hunk(..), Prim(..), Object(..) ) import Darcs.Patch.Prim.V3.Apply( ObjectMap(..) ) import Darcs.Witnesses.Sealed ( Sealed, seal ) import Darcs.Witnesses.Show import Storage.Hashed.AnchoredPath import Storage.Hashed.Tree( Tree, TreeItem ) import Storage.Hashed.Darcs ( darcsUpdateHashes ) import Storage.Hashed.Hash( Hash(..) ) import qualified Storage.Hashed.Tree as T import Control.Applicative ( (<$>) ) import Control.Arrow ( second ) import qualified Data.ByteString as BS import qualified Data.ByteString.Char8 as BC import qualified Data.ByteString.Lazy as BL import qualified Data.ByteString.Lazy.Char8 as BLC import Data.List ( intercalate, sort ) import qualified Data.Map as M import Test.QuickCheck ( Arbitrary(..) , Gen, choose, vectorOf, frequency, oneof ) #include "impossible.h" ---------------------------------------------------------------------- -- * Model definition newtype V3Model C(x) = V3Model { repoMap :: ObjectMap Fail } ---------------------------------------- -- Instances instance Show (Object Fail) where show (Directory l) = show l show (Blob c _) = show c deriving instance Eq (Object Fail) instance Show (V3Model x) where show = showModel instance Show1 V3Model where showDict1 = ShowDictClass ---------------------------------------------------------------------- -- * Constructors objectMap :: (Monad m) => M.Map UUID (Object m) -> ObjectMap m objectMap map = ObjectMap { getObject = get, putObject = put, listObjects = list } where list = return $ M.keys map put k o = return $ objectMap (M.insert k o map) get k = return $ M.lookup k map emptyRepo :: V3Model C(x) emptyRepo = V3Model (objectMap M.empty) emptyFile :: (Monad m) => Object m emptyFile = Blob (return BS.empty) NoHash emptyDir :: Object m emptyDir = Directory M.empty ---------------------------------------------------------------------- -- * Queries nullRepo :: V3Model C(x) -> Bool nullRepo = null . repoObjects -- | @isEmpty file@ <=> file content is empty -- @isEmpty dir@ <=> dir has no child isEmpty :: Object Fail -> Bool isEmpty (Directory d) = M.null d isEmpty (Blob f _) = BS.null $ unFail f -- | The root directory of a repository. root :: V3Model C(x) -> Object Fail root (V3Model repo) = fromJust $ unFail $ getObject repo (UUID "ROOT") repoObjects :: V3Model C(x) -> [(UUID, Object Fail)] repoObjects (V3Model repo) = [ (id, obj id) | id <- unFail $ listObjects repo, not $ isEmpty $ obj id ] where obj id = fromJust $ unFail $ getObject repo id ---------------------------------------------------------------------- -- * Comparing repositories ---------------------------------------------------------------------- -- * QuickCheck generators -- Testing code assumes that aFilename and aDirname generators -- will always be able to generate a unique name given a list of -- existing names. This should be OK as long as the number of possible -- file/dirnames is much bigger than the number of files/dirs per repository. -- 'Arbitrary' 'V3Model' instance is based on the 'aSmallRepo' generator. -- | Files are distinguish by ending their names with ".txt". aFilename :: Gen BS.ByteString aFilename = do len <- choose (1,maxLength) name <- vectorOf len alpha return $ BC.pack $ name ++ ".txt" where maxLength = 3 aDirname :: Gen BS.ByteString aDirname = do len <- choose (1,maxLength) BC.pack <$> vectorOf len alpha where maxLength = 3 aWord :: Gen BS.ByteString aWord = do c <- alpha return $ BC.pack[c] aLine :: Gen BS.ByteString aLine = do wordsNo <- choose (1,2) ws <- vectorOf wordsNo aWord return $ BC.unwords ws aContent :: Gen BS.ByteString aContent = bSized 0 0.5 80 $ \k -> do n <- choose (0,k) BC.intercalate "\n" <$> vectorOf n aLine aFile :: (Monad m) => Gen (Object m) aFile = aContent >>= \c -> return $ Blob (return c) NoHash aDir :: (Monad m) => [UUID] -> [UUID] -> Gen [(UUID, Object m)] aDir [] _ = return [] aDir (dirid:dirids) fileids = do dirsplit <- choose (1, length dirids) filesplit <- choose (1, length fileids) let ids = take filesplit fileids rem = drop filesplit fileids files <- vectorOf filesplit aFile names <- vectorOf filesplit aFilename dirnames <- vectorOf dirsplit aDirname dirs <- subdirs (take dirsplit dirids) (drop dirsplit dirids) (drop filesplit fileids) return $ (dirid, Directory $ M.fromList $ names `zip` ids ++ dirnames `zip` dirids) : (fileids `zip` files) ++ dirs where subdirs [] _ _ = return [] subdirs tomake dirs files = do dirsplit <- choose (1, length dirs) filesplit <- choose (1, length files) dir <- aDir (head tomake : take dirsplit dirs) (take filesplit files) rem <- subdirs (tail tomake) (drop dirsplit dirs) (drop filesplit files) return $ dir ++ rem anUUID :: Gen UUID anUUID = UUID . BC.pack <$> vectorOf 32 (oneof $ map return "0123456789") -- | @aRepo filesNo dirsNo@ produces repositories with *at most* -- @filesNo@ files and @dirsNo@ directories. -- The structure of the repository is aleatory. aRepo :: Int -- ^ Maximum number of files -> Int -- ^ Maximum number of directories -> Gen (V3Model C(x)) aRepo maxFiles maxDirs = do let minFiles = if maxDirs == 0 && maxFiles > 0 then 1 else 0 filesNo <- choose (minFiles,maxFiles) let minDirs = if filesNo == 0 && maxDirs > 0 then 1 else 0 dirsNo <- choose (minDirs,maxDirs) dirids <- (UUID "ROOT":) <$> uniques dirsNo anUUID fileids <- uniques filesNo anUUID objectmap <- aDir dirids fileids return $ V3Model $ objectMap $ M.fromList objectmap -- | Generate small repositories. -- Small repositories help generating (potentially) conflicting patches. instance RepoModel V3Model where type RepoState V3Model = ObjectMap aSmallRepo = do filesNo <- frequency [(3, return 1), (1, return 2)] dirsNo <- frequency [(3, return 1), (1, return 0)] aRepo filesNo dirsNo repoApply (V3Model state) patch = V3Model <$> applyToState patch state showModel model = "V3Model{\n" ++ unlines (map entry $ repoObjects model) ++ "}" where entry (id, obj) = show id ++ " -> " ++ show obj eqModel r1 r2 = repoObjects r1 == repoObjects r2 instance Arbitrary (Sealed V3Model) where arbitrary = seal <$> aSmallRepo darcs-2.8.4/src/Darcs/Test/Patch/WithState.hs0000644001765600176560000001247712104371431020225 0ustar ganeshganesh{-# LANGUAGE CPP, MultiParamTypeClasses, ScopedTypeVariables, UndecidableInstances #-} #include "gadts.h" module Darcs.Test.Patch.WithState where import Darcs.Witnesses.Ordered import Darcs.Witnesses.Sealed import Darcs.Witnesses.Show import Test.QuickCheck ( Gen, sized, choose ) ---------------------------------------------------------------------- -- * WithState data WithState s p C(x y) = WithState { wsStartState :: s C(x) , wsPatch :: p C(x y) , wsEndState :: s C(y) } deriving Eq instance (Show1 s, Show2 p) => Show (WithState s p C(x y)) where showsPrec d (WithState s p s') = showParen (d > appPrec) $ showString "WithState " . showsPrec1 (appPrec+1) s . showString " " . showsPrec2 (appPrec+1) p . showString " " . showsPrec1 (appPrec+1) s' instance (Show1 s, Show2 p) => Show2 (WithState s p) where showDict2 = ShowDictClass data WithStartState s p C(x) = WithStartState { wssStartState :: s C(x) , wssPatch :: p C(x) } deriving Eq instance (Show1 s, Show1 p) => Show (WithStartState s p C(x)) where showsPrec d (WithStartState s p) = showParen (d > appPrec) $ showString "WithStartState " . showsPrec1 (appPrec + 1) s . showString " " . showsPrec1 (appPrec + 1) p instance (Show1 s, Show1 p) => Show1 (WithStartState s p) where showDict1 = ShowDictClass -- | A combination of a patch and its final state. The state, in this module, is -- typically represented by a 'RepoModel' value. The @px@ type is typically a -- patch type applied to its pre-state, e.g. @Prim x@. data WithEndState s px C(y) = WithEndState { wesPatch :: px C(y) , wesEndState :: s C(y) } deriving Eq instance (Show1 s, Show1 p) => Show (WithEndState s p C(x)) where showsPrec d (WithEndState p s) = showParen (d > appPrec) $ showString "WithEndState " . showsPrec1 (appPrec + 1) p . showString " " . showsPrec1 (appPrec + 1) s instance (Show1 s, Show1 p) => Show1 (WithEndState s p) where showDict1 = ShowDictClass ---------------------------------------------------------------------- -- * ArbitraryState generators -- | A type class to generate arbitrary values, threading a state through the -- arbitrary calls. So this can be used to generate a patch that comes after -- another patch. The post-state of the generated patch is hidden by the -- 'Sealed'. class ArbitraryState s p where arbitraryState :: s C(x) -> Gen (Sealed (WithEndState s (p C(x)))) -- does a coarbitrary make sense? instance ArbitraryState s p => ArbitraryState s (WithState s p) where arbitraryState s = do Sealed (WithEndState x s') <- arbitraryState s return $ seal $ WithEndState (WithState s x s') s' instance ArbitraryState s p => ArbitraryState s (p :> p) where arbitraryState s = do Sealed (WithEndState p1 s') <- arbitraryState s Sealed (WithEndState p2 s'') <- arbitraryState s' return $ seal $ WithEndState (p1 :> p2) s'' instance ArbitraryState s p => ArbitraryState s (p :> p :> p) where arbitraryState s0 = do Sealed (WithEndState p1 s1) <- arbitraryState s0 Sealed (WithEndState p2 s2) <- arbitraryState s1 Sealed (WithEndState p3 s3) <- arbitraryState s2 return $ seal $ WithEndState (p1 :> p2 :> p3) s3 arbitraryFL :: ArbitraryState s p => FORALL(x) Int -> s C(x) -> Gen (Sealed (WithEndState s (FL p C(x)))) arbitraryFL 0 s = return $ seal $ WithEndState NilFL s arbitraryFL n s = do Sealed (WithEndState x s') <- arbitraryState s Sealed (WithEndState xs s'') <- arbitraryFL (n-1) s' return $ seal $ WithEndState (x :>: xs) s'' instance ArbitraryState s p => ArbitraryState s (FL p) where arbitraryState s = sized $ \n -> do k <- choose (0, min 2 (n `div` 5)) arbitraryFL k s makeS2Gen :: ArbitraryState s p => Gen (s C(x)) -> Gen (Sealed2 p) makeS2Gen stGen = do s <- stGen Sealed (WithEndState p _) <- arbitraryState s return $ seal2 p makeSGen :: ArbitraryState s p => Gen (s C(x)) -> Gen (Sealed (p C(x))) makeSGen stGen = do s <- stGen Sealed (WithEndState p _) <- arbitraryState s return $ seal p makeWS2Gen :: ArbitraryState s p => Gen (s C(x)) -> Gen (Sealed2 (WithState s p)) makeWS2Gen stGen = do s <- stGen Sealed (WithEndState wsP _) <- arbitraryState s return $ seal2 wsP makeWSGen :: ArbitraryState s p => Gen (s C(x)) -> Gen (Sealed (WithState s p C(x))) makeWSGen stGen = do s <- stGen Sealed (WithEndState wsP _) <- arbitraryState s return $ seal wsP instance (Show2 p, Show1 s) => Show1 ((WithState s p) C(a)) where showDict1 = ShowDictClass darcs-2.8.4/src/Darcs/Test/Util/0000755001765600176560000000000012104371431015620 5ustar ganeshganeshdarcs-2.8.4/src/Darcs/Test/Util/TestResult.hs0000644001765600176560000000324112104371431020272 0ustar ganeshganesh module Darcs.Test.Util.TestResult ( TestResult , succeeded , failed , rejected , (<&&>) , fromMaybe , isOk , isFailed ) where import Printer ( Doc, renderString ) import qualified Test.QuickCheck.Property as Q data TestResult = TestSucceeded | TestFailed Doc | TestRejected -- ^ Rejects test case succeeded :: TestResult succeeded = TestSucceeded failed :: Doc -- ^ Error message -> TestResult failed = TestFailed rejected :: TestResult rejected = TestRejected -- | @t <&&> s@ fails <=> t or s fails -- @t <&&> s@ succeeds <=> none fails and some succeeds -- @t <&&> s@ is rejected <=> both are rejected (<&&>) :: TestResult -> TestResult -> TestResult t@(TestFailed _) <&&> _s = t _t <&&> s@(TestFailed _) = s TestRejected <&&> s = s t <&&> TestRejected = t TestSucceeded <&&> TestSucceeded = TestSucceeded -- | 'Nothing' is considered success whilst 'Just' is considered failure. fromMaybe :: Maybe Doc -> TestResult fromMaybe Nothing = succeeded fromMaybe (Just errMsg) = failed errMsg isFailed :: TestResult -> Bool isFailed (TestFailed _) = True isFailed _other = False -- | A test is considered OK if it does not fail. isOk :: TestResult -> Bool isOk = not . isFailed -- 'Testable' instance is defined by converting 'TestResult' to 'QuickCheck.Property.Result' instance Q.Testable TestResult where property TestSucceeded = Q.property Q.succeeded property (TestFailed errorMsg) = Q.property (Q.failed{Q.reason = renderString errorMsg}) property TestRejected = Q.property Q.rejected darcs-2.8.4/src/Darcs/Test/Util/QuickCheck.hs0000644001765600176560000000242612104371431020172 0ustar ganeshganesh module Darcs.Test.Util.QuickCheck ( upper , lower , alpha , notIn , uniques , maybeOf , bSized ) where import Control.Applicative import Test.QuickCheck.Gen -- | An uppercase alphabetic character. upper :: Gen Char upper = choose ('A','Z') -- | A lowercase alphabetic character. lower :: Gen Char lower = choose ('a','z') -- | An alphabetic character. alpha :: Gen Char alpha = oneof [upper, lower] -- | @gen `notIn` xs@ generate a @x@ that is not in @xs@. notIn :: Eq a => Gen a -> [a] -> Gen a gen `notIn` xs = gen `suchThat` (`notElem` xs) -- | @uniques k gen@ generates a list of @k@ unique values. uniques :: Eq a => Int -> Gen a -> Gen [a] uniques k gen = go k [] where go 0 xs = return xs go n xs = do x <- gen `notIn` xs go (n-1) (x:xs) -- | Try to arbitrarily pick some element of the list. maybeOf :: [a] -> Gen (Maybe a) maybeOf [] = return Nothing maybeOf xs = Just <$> elements xs -- | A bounded sized combinator. bSized :: Int -- ^ Lower bound -> Double -- ^ Increment -> Int -- ^ Upper bound -> (Int -> Gen a) -> Gen a bSized low inc upp mkGen = sized $ mkGen . resize' where resize' :: Int -> Int resize' n = let x = fromIntegral n in min upp (floor(inc*x) + low) darcs-2.8.4/src/Darcs/Test/Email.hs0000644001765600176560000001026012104371431016265 0ustar ganeshganesh-- Copyright (C) 2002-2005,2007 David Roundy -- Copyright (C) 2009 Reinier Lamers -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. -- | This module contains unit tests of the code in 'Darcs.Email' -- -- These tests check whether the emails generated by darcs meet a few criteria. -- We check for line length and non-ASCII characters. We apparently do not have -- to check for CR-LF newlines because that's handled by sendmail. module Darcs.Test.Email ( testSuite ) where import Data.Char ( isPrint ) import qualified Data.ByteString as B ( length, unpack, null, head, cons, empty, foldr, ByteString ) import qualified Data.ByteString.Char8 as BC ( unpack ) import Test.Framework ( Test, testGroup ) import Test.Framework.Providers.QuickCheck2 ( testProperty ) import Printer ( text, renderPS ) import Darcs.Email ( makeEmail, readEmail, formatHeader ) testSuite :: Test testSuite = testGroup "Darcs.Email" [ emailParsing , emailHeaderNoLongLines , emailHeaderAsciiChars , emailHeaderLinesStart , emailHeaderNoEmptyLines ] -- | Checks that darcs can read the emails it generates emailParsing :: Test emailParsing = testProperty "Checking that email can be parsed" $ \s -> unlines ("":s++["", ""]) == BC.unpack (readEmail (renderPS $ makeEmail "reponame" [] (Just (text "contents\n")) Nothing (text $ unlines s) (Just "filename"))) -- | Check that formatHeader never creates lines longer than 78 characters -- (excluding the carriage return and line feed) emailHeaderNoLongLines :: Test emailHeaderNoLongLines = testProperty "Checking email header line length" $ \field value -> let cleanField = cleanFieldString field in not $ any (>78) $ map B.length $ bsLines $ formatHeader cleanField value -- Check that an email header does not contain non-ASCII characters -- formatHeader doesn't escape field names, there is no such thing as non-ascii -- field names afaik emailHeaderAsciiChars :: Test emailHeaderAsciiChars = testProperty "Checking email for illegal characters" $ \field value -> let cleanField = cleanFieldString field in not (any (>127) (B.unpack (formatHeader cleanField value))) -- Check that header the second and later lines of a header start with a space emailHeaderLinesStart :: Test emailHeaderLinesStart = testProperty "Checking for spaces at start of folded email header lines" $ \field value -> let headerLines = bsLines (formatHeader cleanField value) cleanField = cleanFieldString field in all (\l -> B.null l || B.head l == 32) (tail headerLines) -- Checks that there are no lines in email headers with only whitespace emailHeaderNoEmptyLines :: Test emailHeaderNoEmptyLines = testProperty "Checking that there are no empty lines in email headers" $ \field value -> let headerLines = bsLines (formatHeader cleanField value) cleanField = cleanFieldString field in all (not . B.null) headerLines --(not . B.null . B.filter (not . (`elem` [10, 32, 9]))) headerLines bsLines :: B.ByteString -> [B.ByteString] bsLines = finalizeFold . B.foldr splitAtLines (B.empty, []) where splitAtLines 10 (thisLine, prevLines) = (B.empty, thisLine:prevLines) splitAtLines c (thisLine, prevLines) = (B.cons c thisLine, prevLines) finalizeFold (lastLine, otherLines) = lastLine : otherLines cleanFieldString :: String -> String cleanFieldString = filter (\c -> isPrint c && c < '\x80' && c /= ':') darcs-2.8.4/src/Darcs/Test/Patch.hs0000644001765600176560000004616412104371431016311 0ustar ganeshganesh{-# OPTIONS_GHC -fno-warn-orphans #-} #if __GLASGOW_HASKELL__ >= 700 {-# LANGUAGE ImpredicativeTypes #-} #endif -- Copyright (C) 2002-2005,2007 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. module Darcs.Test.Patch ( testSuite ) where import Data.Maybe( isNothing ) import Test.Framework ( Test, testGroup ) import Test.Framework.Providers.HUnit ( testCase ) import Test.Framework.Providers.QuickCheck2 ( testProperty ) import Test.QuickCheck.Arbitrary( Arbitrary ) import Test.QuickCheck( Testable ) import Test.HUnit ( assertBool ) import Darcs.Test.Util.TestResult ( TestResult, isOk, fromMaybe ) import Darcs.Test.Patch.Utils ( testConditional ) import Darcs.Witnesses.Ordered import Darcs.Witnesses.Sealed import Darcs.Witnesses.Eq ( unsafeCompare ) import Darcs.Witnesses.Show import Darcs.Patch.Prim( PrimPatch, join, FromPrim, PrimOf, PrimPatchBase ) import Darcs.Patch.Prim.Class( PrimCanonize ) import qualified Darcs.Patch.Prim.V1 as V1 ( Prim ) import qualified Darcs.Patch.Prim.V3 as V3 ( Prim ) import qualified Darcs.Patch.V1 as V1 import Darcs.Patch.V2.Real ( isConsistent, isForward, RealPatch ) import Darcs.Patch.RepoPatch( RepoPatch ) import Darcs.Patch.Patchy ( Commute(..), Patchy ) import Darcs.Patch.Merge( Merge ) import Darcs.Patch.Apply( ApplyState ) import Darcs.Test.Patch.Arbitrary.Generic import qualified Darcs.Test.Patch.Arbitrary.PrimV1 as P1 import qualified Darcs.Test.Patch.Arbitrary.PrimV3 as P3 import Darcs.Test.Patch.Arbitrary.Real import Darcs.Test.Patch.Arbitrary.PatchV1 () import Darcs.Test.Patch.Arbitrary.PrimV1 () import Darcs.Test.Patch.RepoModel import Darcs.Test.Patch.V3Model( V3Model ) import Darcs.Test.Patch.V1Model( V1Model ) import Darcs.Test.Patch.WithState( WithState, wsPatch, WithStartState ) import qualified Darcs.Test.Patch.Info import qualified Darcs.Test.Patch.Examples.Set1 as Ex import qualified Darcs.Test.Patch.Examples.Set2Unwitnessed as ExU import Darcs.Test.Patch.Properties.Check( Check(..), checkAPatch ) import qualified Darcs.Test.Patch.Properties.V1Set1 as Prop import qualified Darcs.Test.Patch.Properties.V1Set2 as Prop import qualified Darcs.Test.Patch.Properties.Generic as Prop import qualified Darcs.Test.Patch.Properties.Real as Prop import qualified Darcs.Test.Patch.Properties.GenericUnwitnessed as PropU import qualified Darcs.Test.Patch.WSub as WSub #include "gadts.h" type instance ModelOf (FL prim) = ModelOf prim #if __GLASGOW_HASKELL__ >= 700 type TestGenerator thing gen = (FORALL(t ctx) ((FORALL(xx yy) thing xx yy -> t) -> (gen ctx -> t))) type TestCondition thing = (FORALL (yy zz) thing C(yy zz) -> Bool) type TestCheck thing t = (FORALL (yy zz) thing C(yy zz) -> t) -- arbitraryThing :: (FORALL(xx yy) thing C(xx yy) -> t) -> (thing C(a b) -> t) arbitraryThing :: x -> TestGenerator thing (thing x) arbitraryThing _ f p = f p #endif -- | Run a test function on a set of data, using HUnit. The test function should -- return @Nothing@ upon success and a @Just x@ upon failure. testCases :: Show a => String -- ^ The test name -> (a -> TestResult) -- ^ The test function -> [a] -- ^ The test data -> Test testCases name test datas = testCase name (assertBool assertName res) where assertName = "Boolean assertion for \"" ++ name ++ "\"" res = and $ map (isOk . test) datas unit_V1P1:: [Test] unit_V1P1 = [ testCases "known commutes" Prop.checkCommute Ex.knownCommutes , testCases "known non-commutes" Prop.checkCantCommute Ex.knownCantCommutes , testCases "known merges" Prop.checkMerge Ex.knownMerges , testCases "known merges (equiv)" Prop.checkMergeEquiv Ex.knownMergeEquivs , testCases "known canons" Prop.checkCanon Ex.knownCanons , testCases "merge swaps" Prop.checkMergeSwap Ex.mergePairs2 , testCases "the patch validation works" Prop.tTestCheck Ex.validPatches , testCases "commute/recommute" (Prop.recommute commute) Ex.commutePairs , testCases "merge properties: merge either way valid" Prop.tMergeEitherWayValid Ex.mergePairs , testCases "merge properties: merge swap" Prop.mergeEitherWay Ex.mergePairs , testCases "primitive patch IO functions" (Prop.tShowRead eqFLUnsafe) Ex.primitiveTestPatches , testCases "IO functions (test patches)" (Prop.tShowRead eqFLUnsafe) Ex.testPatches , testCases "IO functions (named test patches)" (Prop.tShowRead unsafeCompare) Ex.testPatchesNamed , testCases "primitive commute/recommute" (Prop.recommute commute) Ex.primitiveCommutePairs ] unit_V2P1 :: [Test] unit_V2P1 = [ testCases "join commute" (PropU.joinCommute WSub.join) ExU.primPermutables , testCases "prim recommute" (PropU.recommute WSub.commute) ExU.commutables , testCases "prim patch and inverse commute" (PropU.patchAndInverseCommute WSub.commute) ExU.commutables , testCases "prim inverses commute" (PropU.commuteInverses WSub.commute) ExU.commutables , testCases "FL prim recommute" (PropU.recommute WSub.commute) ExU.commutablesFL , testCases "FL prim patch and inverse commute" (PropU.patchAndInverseCommute WSub.commute) ExU.commutablesFL , testCases "FL prim inverses commute" (PropU.commuteInverses WSub.commute) $ ExU.commutablesFL , testCases "fails" (PropU.commuteFails WSub.commute) ([] :: [(V1.Prim WSub.:> V1.Prim) C(x y)]) , testCases "read and show work on Prim" PropU.show_read ExU.primPatches , testCases "read and show work on RealPatch" PropU.show_read ExU.realPatches , testCases "example flattenings work" PropU.consistentTreeFlattenings ExU.realPatchLoopExamples , testCases "real merge input consistent" (PropU.mergeArgumentsConsistent isConsistent) ExU.realMergeables , testCases "real merge input is forward" (PropU.mergeArgumentsConsistent isForward) ExU.realMergeables , testCases "real merge output is forward" (PropU.mergeConsistent isForward) ExU.realMergeables , testCases "real merge output consistent" (PropU.mergeConsistent isConsistent) ExU.realMergeables , testCases "real merge either way" PropU.mergeEitherWay ExU.realMergeables , testCases "real merge and commute" PropU.mergeCommute ExU.realMergeables , testCases "real recommute" (PropU.recommute WSub.commute) ExU.realCommutables , testCases "real inverses commute" (PropU.commuteInverses WSub.commute) ExU.realCommutables , testCases "real permutivity" (PropU.permutivity WSub.commute) ExU.realNonduplicateTriples , testCases "real partial permutivity" (PropU.partialPermutivity WSub.commute) ExU.realNonduplicateTriples ] instance PrimPatch prim => Check (RealPatch prim) where checkPatch p = return $ isNothing $ isConsistent p instance Check V3.Prim where checkPatch _ = return True -- XXX commuteReals :: PrimPatch prim => (RealPatch prim :> RealPatch prim) C(x y) -> Maybe ((RealPatch prim :> RealPatch prim) C(x y)) commuteReals = commute qc_prim :: forall prim C(x y a) model. (PrimPatch prim, ArbitraryPrim prim, Show2 prim , model ~ ModelOf prim, RepoModel model , RepoState model ~ ApplyState (PrimOf prim) , Show1 (ModelOf prim) , Check prim, PrimPatchBase prim, PrimOf prim ~ prim , FromPrim prim , Show1 (prim C(a)) , Show1 ((prim :> prim) C(a)) , Show1 (WithState model prim C(a)) , Arbitrary (Sealed ((prim :> prim) C(a))) , Arbitrary (Sealed ((prim :> prim :> prim) C(a))) , Arbitrary (Sealed (prim C(a))) , Arbitrary (Sealed (FL prim C(a))) , Arbitrary (Sealed ((FL prim :> FL prim) C(a))) , Arbitrary (Sealed (WithState model prim C(a))) , Arbitrary (Sealed (WithState model (FL prim) C(a))) , Arbitrary (Sealed2 (WithState model (prim :> prim))) , Arbitrary (Sealed ((WithState model (prim :> prim)) C(a))) , Arbitrary (Sealed ((WithState model (FL prim :> FL prim)) C(a))) ) => prim C(x y) -> [Test] qc_prim _ = -- The following fails because of setpref patches... -- testProperty "prim inverse doesn't commute" (inverseDoesntCommute :: Prim -> Maybe Doc) [ testProperty "prim join effect preserving... " (unseal2 $ Prop.joinEffectPreserving join :: Sealed2 (WithState model (prim :> prim)) -> TestResult) ] #if __GLASGOW_HASKELL__ >= 700 ++ concat [ pair_properties (undefined :: prim C(x y)) "arbitrary" arbitraryThing' , pair_properties (undefined :: FL prim C(x y)) "arbitrary FL" arbitraryThing' , coalesce_properties (undefined :: prim C(x y)) "arbitrary" arbitraryThing' , nonreal_commute_properties (undefined :: prim C(x y)) "arbitrary" arbitraryThing' , nonreal_commute_properties (undefined :: FL prim C(x y)) "arbitrary FL" arbitraryThing' , patch_properties (undefined :: prim C(x a)) "arbitrary" arbitraryThing' , patch_properties (undefined :: FL prim C(x a)) "arbitrary FL" arbitraryThing' , patch_repo_properties (undefined :: prim C(x a)) "arbitrary" arbitraryThing' , patch_repo_properties (undefined :: FL prim C(x a)) "arbitrary FL" arbitraryThing' , pair_repo_properties (undefined :: prim C(x a)) "arbitrary" arbitraryThing' , pair_repo_properties (undefined :: FL prim C(x a)) "arbitrary FL" arbitraryThing' ] where arbitraryThing' = arbitraryThing (undefined :: a) -- bind the witness for generator #endif qc_V2P1 :: [Test] qc_V2P1 = [ testProperty "tree flattenings are consistent... " Prop.propConsistentTreeFlattenings , testProperty "with quickcheck that real patches are consistent... " (unseal $ P1.patchFromTree $ fromMaybe . isConsistent) -- permutivity ---------------------------------------------------------------------------- , testConditional "permutivity" (unseal $ P1.commuteTripleFromTree notDuplicatestriple) (unseal $ P1.commuteTripleFromTree $ Prop.permutivity commuteReals) , testConditional "partial permutivity" (unseal $ P1.commuteTripleFromTree notDuplicatestriple) (unseal $ P1.commuteTripleFromTree $ Prop.partialPermutivity commuteReals) , testConditional "nontrivial permutivity" (unseal $ P1.commuteTripleFromTree (\t -> nontrivialTriple t && notDuplicatestriple t)) (unseal $ P1.commuteTripleFromTree $ (Prop.permutivity commuteReals)) ] qc_V2 :: forall prim C(xx yy a). (PrimPatch prim, Show1 (ModelOf prim), RepoModel (ModelOf prim), Check (RealPatch prim), ArbitraryPrim prim, Show2 prim, RepoState (ModelOf prim) ~ ApplyState prim) => prim C(xx yy) -> [Test] qc_V2 _ = [ testProperty "readPatch and showPatch work on RealPatch... " (unseal $ patchFromTree $ (Prop.show_read :: RealPatch prim C(x y) -> TestResult)) , testProperty "readPatch and showPatch work on FL RealPatch... " (unseal2 $ (Prop.show_read :: FL (RealPatch prim) C(x y) -> TestResult)) , testProperty "we can do merges using QuickCheck" (isNothing . (Prop.propIsMergeable :: Sealed (WithStartState (ModelOf prim) (Tree prim)) -> Maybe (Tree (RealPatch prim) C(x)))) ] #if __GLASGOW_HASKELL__ >= 700 ++ concat [ merge_properties (undefined :: RealPatch prim C(x y)) "tree" mergePairFromTree , merge_properties (undefined :: RealPatch prim C(x y)) "twfp" mergePairFromTWFP , pair_properties (undefined :: RealPatch prim C(x y)) "tree" commutePairFromTree , pair_properties (undefined :: RealPatch prim C(x y)) "twfp" commutePairFromTWFP , patch_properties (undefined :: RealPatch prim C(x y)) "tree" patchFromTree -- , patch_repo_properties (undefined :: RealPatch prim C(x y)) "tree" arbitraryThing' ] where arbitraryThing' = arbitraryThing (undefined :: a) #endif #if __GLASGOW_HASKELL__ >= 700 properties :: forall thing gen. (Show1 gen, Arbitrary (Sealed gen)) => TestGenerator thing gen -- -> forall xx yy. thing xx yy -> String -> String -> forall t. Testable t => [(String, TestCondition thing, TestCheck thing t)] -> [Test] properties gen prefix genname tests = [ cond name condition check | (name, condition, check) <- tests ] where cond :: forall testable. Testable testable => String -> TestCondition thing -> TestCheck thing testable -> Test cond t c p = testConditional (prefix ++ " (" ++ genname ++ "): " ++ t) (unseal $ gen c) (unseal $ gen p) type PropList what gen = String -> TestGenerator what gen -> [Test] pair_properties :: forall p gen x y. (Show1 gen, Arbitrary (Sealed gen), Patchy p) => p x y -> PropList (p :> p) gen pair_properties _ genname gen = properties gen "commute" genname [ ("recommute" , const True , Prop.recommute commute ) , ("nontrivial recommute" , nontrivialCommute, Prop.recommute commute ) , ("inverses commute" , const True , Prop.commuteInverses commute ) , ("nontrivial inverses" , nontrivialCommute, Prop.commuteInverses commute ) , ("inverse composition" , const True , Prop.inverseComposition ) ] coalesce_properties :: forall p gen x y. (Show1 gen, Arbitrary (Sealed gen), Patchy p, PrimPatch p) => p x y -> PropList (p :> p :> p) gen coalesce_properties _ genname gen = properties gen "commute" genname [ ("join commutes with commute", const True, Prop.joinCommute join) ] -- The following properties do not hold for "Real" patches (conflictors and -- duplicates, specifically) . nonreal_commute_properties :: forall p gen x y. (Show1 gen, Arbitrary (Sealed gen), Patchy p) => p x y -> PropList (p :> p) gen nonreal_commute_properties _ genname gen = properties gen "commute" genname [ ("patch & inverse commute", const True , Prop.patchAndInverseCommute commute) , ("patch & inverse commute", nontrivialCommute, Prop.patchAndInverseCommute commute) ] patch_properties :: forall p gen x y. (Show1 gen, Arbitrary (Sealed gen), Patchy p) => p x y -> PropList p gen patch_properties _ genname gen = properties gen "patch" genname [ ("inverse . inverse is id" , const True , Prop.invertSymmetry) ] patch_repo_properties :: forall p gen x y. (Show1 gen, Arbitrary (Sealed gen), Patchy p, RepoModel (ModelOf (PrimOf p)), RepoState (ModelOf (PrimOf p)) ~ ApplyState p) => p x y -> PropList (WithState (ModelOf (PrimOf p)) p) gen patch_repo_properties _ genname gen = properties gen "patch/repo" genname [ ("invert rollback" , const True , Prop.invertRollback) ] pair_repo_properties :: forall p gen x y. (Show1 gen, Arbitrary (Sealed gen), Patchy p, RepoModel (ModelOf p), RepoState (ModelOf p) ~ ApplyState p) => p x y -> PropList (WithState (ModelOf p) (p :> p)) gen pair_repo_properties _ genname gen = properties gen "patch/repo" genname [ ("commute is effect preserving" , const True , Prop.effectPreserving commute ) ] merge_properties :: forall p gen x y. (Show1 gen, Arbitrary (Sealed gen) , Patchy p, Merge p, Show2 p, Check p) => p x y -> PropList (p :\/: p) gen merge_properties _ genname gen = properties gen "merge" genname [ ("merge either way" , const True , Prop.mergeEitherWay ) , ("merge either way valid" , const True , Prop.tMergeEitherWayValid) , ("nontrivial merge either way", nontrivialMerge, Prop.mergeEitherWay ) , ("merge commute" , const True , Prop.mergeCommute ) ] #endif qc_V1P1 :: [Test] qc_V1P1 = [ testProperty "show and read work right" (unseal Prop.propReadShow) ] ++ Prop.checkSubcommutes Prop.subcommutesInverse "patch and inverse both commute" ++ Prop.checkSubcommutes Prop.subcommutesNontrivialInverse "nontrivial commutes are correct" ++ Prop.checkSubcommutes Prop.subcommutesFailure "inverses fail" ++ [ testProperty "commuting by patch and its inverse is ok" Prop.propCommuteInverse -- , testProperty "conflict resolution is valid... " Prop.propResolveConflictsValid , testProperty "a patch followed by its inverse is identity" Prop.propPatchAndInverseIsIdentity , testProperty "'simple smart merge'" Prop.propSimpleSmartMergeGoodEnough , testProperty "commutes are equivalent" Prop.propCommuteEquivalency , testProperty "merges are valid" Prop.propMergeValid , testProperty "inverses being valid" Prop.propInverseValid , testProperty "other inverse being valid" Prop.propOtherInverseValid -- The patch generator isn't smart enough to generate correct test cases for -- the following: (which will be obsoleted soon, anyhow) -- , testProperty "the order dependence of unravel... " Prop.propUnravelOrderIndependent -- , testProperty "the unravelling of three merges... " Prop.propUnravelThreeMerge -- , testProperty "the unravelling of a merge of a sequence... " Prop.propUnravelSeqMerge , testProperty "the order of commutes" Prop.propCommuteEitherOrder , testProperty "commute either way" Prop.propCommuteEitherWay , testProperty "the double commute" Prop.propCommuteTwice , testProperty "merges commute and are well behaved" Prop.propMergeIsCommutableAndCorrect , testProperty "merges can be swapped" Prop.propMergeIsSwapable , testProperty "again that merges can be swapped (I'm paranoid) " Prop.propMergeIsSwapable ] -- the following properties are disabled, because they routinely lead to -- exponential cases, making the tests run for ever and ever; nevertheless, -- we would expect them to hold {- ++ merge_properties (undefined :: V1.Patch Prim C(x y)) "tree" mergePairFromTree ++ merge_properties (undefined :: V1.Patch Prim C(x y)) "twfp" mergePairFromTWFP ++ commute_properties (undefined :: V1.Patch Prim C(x y)) "tree" commutePairFromTree ++ commute_properties (undefined :: V1.Patch Prim C(x y)) "twfp" commutePairFromTWFP -} -- | This is the big list of tests that will be run using testrunner. testSuite :: [Test] testSuite = [ testGroup "Darcs.Patch.Prim.V1" $ qc_prim (undefined :: V1.Prim C(x y)) , testGroup "Darcs.Patch.V1 (using Prim.V1)" $ unit_V1P1 ++ qc_V1P1 , testGroup "Darcs.Patch.V2 (using Prim.V1)" $ unit_V2P1 ++ qc_V2 (undefined :: V1.Prim C(x y)) ++ qc_V2P1 , testGroup "Darcs.Patch.Prim.V3" $ qc_prim (undefined :: V3.Prim C(x y)) , testGroup "Darcs.Patch.V2 (using Prim.V3)" $ qc_V2 (undefined :: V3.Prim C(x y)) , Darcs.Test.Patch.Info.testSuite ] darcs-2.8.4/src/Darcs/Test/Misc.hs0000644001765600176560000001064112104371431016134 0ustar ganeshganesh-- Copyright (C) 2002-2005,2007 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP #-} module Darcs.Test.Misc ( testSuite ) where import ByteStringUtils ( unpackPSFromUTF8, fromHex2PS, fromPS2Hex ) import qualified Data.ByteString.Char8 as BC ( unpack, pack ) import qualified Data.ByteString as B ( concat, empty ) import Lcs ( shiftBoundaries ) import Data.Array.Base import Control.Monad.ST import Test.HUnit ( assertBool, assertEqual, assertFailure ) import Test.Framework.Providers.QuickCheck2 ( testProperty ) import Test.Framework.Providers.HUnit ( testCase ) import Test.Framework ( Test, testGroup ) #include "gadts.h" testSuite :: Test testSuite = testGroup "" [ byteStringUtilsTestSuite , lcsTestSuite ] -- ---------------------------------------------------------------------- -- * ByteStringUtils -- Here are a few quick tests of the shiftBoundaries function. -- ---------------------------------------------------------------------- byteStringUtilsTestSuite :: Test byteStringUtilsTestSuite = testGroup "ByteStringUtils" [ testCase "UTF-8 packing and unpacking preserves 'hello world'" (assertBool "" (unpackPSFromUTF8 (BC.pack "hello world") == "hello world")) , testCase "Checking that hex packing and unpacking preserves 'hello world'" (assertEqual "" (BC.unpack (fromHex2PS $ fromPS2Hex $ BC.pack "hello world")) "hello world") , testProperty "Checking that B.concat works" propConcatPS , testProperty "Checking that hex conversion works" propHexConversion ] propHexConversion :: String -> Bool propHexConversion s = fromHex2PS (fromPS2Hex $ BC.pack s) == BC.pack s propConcatPS :: [String] -> Bool propConcatPS ss = concat ss == BC.unpack (B.concat $ map BC.pack ss) -- ---------------------------------------------------------------------- -- * LCS -- Here are a few quick tests of the shiftBoundaries function. -- ---------------------------------------------------------------------- lcsTestSuite :: Test lcsTestSuite = testGroup "LCS" [ testCase "lcs code" (mapM_ assertFailure showLcsTests) ] showLcsTests :: [String] showLcsTests = concatMap checkKnownShifts knownShifts checkKnownShifts :: ([Int],[Int],String,String,[Int],[Int]) -> [String] checkKnownShifts (ca, cb, sa, sb, ca', cb') = runST ( do ca_arr <- newListArray (0, length ca) $ toBool (0:ca) cb_arr <- newListArray (0, length cb) $ toBool (0:cb) let p_a = listArray (0, length sa) $ B.empty:(toPS sa) p_b = listArray (0, length sb) $ B.empty:(toPS sb) shiftBoundaries ca_arr cb_arr p_a 1 1 shiftBoundaries cb_arr ca_arr p_b 1 1 ca_res <- fmap (fromBool . tail) $ getElems ca_arr cb_res <- fmap (fromBool . tail) $ getElems cb_arr return $ if ca_res == ca' && cb_res == cb' then [] else ["shiftBoundaries failed on "++sa++" and "++sb++" with " ++(show (ca,cb))++" expected "++(show (ca', cb')) ++" got "++(show (ca_res, cb_res))++"\n"]) where toPS = map (\c -> if c == ' ' then B.empty else BC.pack [c]) toBool = map (>0) fromBool = map (\b -> if b then 1 else 0) knownShifts :: [([Int],[Int],String,String,[Int],[Int])] knownShifts = [([0,0,0],[0,1,0,1,0],"aaa","aaaaa", [0,0,0],[0,0,0,1,1]), ([0,1,0],[0,1,1,0],"cd ","c a ", [0,1,0],[0,1,1,0]), ([1,0,0,0,0,0,0,0,0],[1,0,0,0,0,0,1,1,1,1,1,0,0,0], "fg{} if{}","dg{} ih{} if{}", [1,0,0,0,0,0,0,0,0],[1,0,0,0,0,1,1,1,1,1,0,0,0,0]), -- prefer empty line at end ([0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,1,1,1,1,1,0,0,0], "fg{} if{}","fg{} ih{} if{}", [0,0,0,0,0,0,0,0,0],[0,0,0,0,0,1,1,1,1,1,0,0,0,0]), -- prefer empty line at end ([],[1,1],"","aa",[],[1,1]), ([1,1],[],"aa","",[1,1],[])] darcs-2.8.4/src/Darcs/Annotate.hs0000644001765600176560000002165612104371431016103 0ustar ganeshganesh{-# LANGUAGE OverloadedStrings, TypeSynonymInstances, MultiParamTypeClasses #-} -- Copyright (C) 2010 Petr Rockai -- -- 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. -- | -- Module : Darcs.Annotate -- Copyright : 2010 Petr Rockai -- License : MIT -- Maintainer : darcs-devel@darcs.net -- Stability : experimental -- Portability : portable module Darcs.Annotate ( annotate , annotateDirectory , format , machineFormat ) where import Prelude hiding ( pi ) import qualified Data.ByteString as B import qualified Data.ByteString.Char8 as BC import qualified Data.Map as M import qualified Data.Vector as V import Data.List( nub, groupBy ) import Data.Maybe( isJust, catMaybes, isNothing ) import Control.Monad.State ( modify, when, gets, State, execState ) import Control.Applicative( (<$>) ) import Darcs.Patch.ApplyMonad( ApplyMonad(..) ) import Darcs.Patch.FileName( FileName, movedirfilename, fn2ps, ps2fn ) import Darcs.Patch.Apply ( Apply, apply, ApplyState ) import Darcs.Patch.Info ( PatchInfo(..), humanFriendly, piAuthor, makeFilename ) import Darcs.Patch.PatchInfoAnd( info, PatchInfoAnd ) import Darcs.Witnesses.Ordered import Storage.Hashed.Tree( Tree ) import Lcs( getChanges ) import Printer( renderString ) import ByteStringUtils ( linesPS, unlinesPS ) #include "gadts.h" #include "impossible.h" data FileOrDirectory = File | Directory deriving (Show, Eq) data Annotated = Annotated { annotated :: V.Vector (Maybe PatchInfo, B.ByteString) , current :: [(Int, B.ByteString)] , path :: Maybe FileName , what :: FileOrDirectory , currentInfo :: PatchInfo } deriving Show type AnnotatedM = State Annotated -- XXX: No explicit method nor default method for 'editFile', 'editDirectory' instance ApplyMonad AnnotatedM Tree where type ApplyMonadBase AnnotatedM = AnnotatedM nestedApply _ _ = undefinedFun "nestedApply" liftApply _ _ = undefinedFun "liftApply" getApplyState = undefinedFun "getApplyState" putApplyState _ = undefinedFun "putApplyState" mReadFilePS = undefinedFun "mReadFilePS" mDoesFileExist _ = return True mDoesDirectoryExist _ = return True mCreateDirectory _ = return () mCreateFile _ = return () mRemoveFile f = do p <- gets path when (p == Just f) $ modify (\x -> x { path = Nothing }) updateDirectory f mRemoveDirectory = mRemoveFile mRename a b = do p <- gets path w <- gets what when (isJust p) $ modify $ \st -> st { path = Just $ movedirfilename a b (fromJust p) } when (w == Directory) $ do let fix (i, x) = (i, fn2ps $ movedirfilename a b (ps2fn x)) modify $ \st -> st { current = map fix $ current st } mModifyFilePS f job = do p <- gets path when (p == Just f) $ updateFile (fmap linesPS . job . unlinesPS) mModifyFilePSs f job = do p <- gets path when (p == Just f) $ updateFile job undefinedFun :: Monad m => String -> m a undefinedFun name = fail $ name ++ " undefined for Annotated" updateFile :: ([B.ByteString] -> AnnotatedM [B.ByteString]) -> AnnotatedM () updateFile job = (==File) <$> gets what >>= flip when go where go = do before <- map snd `fmap` gets current after <- job before reannotate $ getChanges before after reannotate [] = return () reannotate ((off, remove, add):rest) = do i <- gets currentInfo c <- gets current a <- gets annotated modify $ \s -> s { current = take off c ++ [ (-1, x) | x <- add ] ++ drop (off + length remove) c , annotated = merge i a $ take (length remove) $ drop off c } reannotate rest merge i a l = a V.// [ (line, (Just i, B.empty)) | (line, _) <- l, line >= 0 && line < V.length a] updateDirectory :: FileName -> AnnotatedM () updateDirectory p = (==Directory) <$> gets what >>= flip when go where go = do let line = fn2ps p files <- gets current case filter ((==line) . snd) files of [match@(ident, _)] -> reannotate ident match line _ -> return () reannotate ident match line = modify $ \x -> x { annotated = annotated x V.// [ (ident, update line $ currentInfo x) ] , current = filter (/= match) $ current x } update line inf = (Just inf, BC.concat [ " -- created as: ", line ]) complete :: Annotated -> Bool complete x = (V.all (isJust . fst) $ annotated x) || (isNothing $ path x) annotate' :: (Apply p, ApplyState p ~ Tree) => FL (PatchInfoAnd p) C(x y) -> Annotated -> Annotated annotate' NilFL ann = ann annotate' (p :>: ps) ann | complete ann = ann | otherwise = annotate' ps $ execState (apply p) (ann { currentInfo = info p }) annotate :: (Apply p, ApplyState p ~ Tree) => FL (PatchInfoAnd p) C(x y) -> FileName -> B.ByteString -> Annotated annotate patches inipath inicontent = annotate' patches initial where initial = Annotated { path = Just inipath , currentInfo = error "There is no currentInfo." , current = zip [0..] (linesPS inicontent) , what = File , annotated = V.replicate (length $ breakLines inicontent) (Nothing, B.empty) } annotateDirectory :: (Apply p, ApplyState p ~ Tree) => FL (PatchInfoAnd p) C(x y) -> FileName -> [FileName] -> Annotated annotateDirectory patches inipath inicontent = annotate' patches initial where initial = Annotated { path = Just inipath , currentInfo = error "There is no currentInfo." , current = zip [0..] (map fn2ps inicontent) , what = Directory , annotated = V.replicate (length inicontent) (Nothing, B.empty) } machineFormat :: B.ByteString -> Annotated -> String machineFormat d a = unlines [ case i of Just inf -> makeFilename inf Nothing -> -- make unknowns uniform, for easier parsing "19700101000000-0000-0000000000000000000000000000000000000000.gz" ++ " | " ++ BC.unpack line ++ " " ++ BC.unpack add | ((i, add), line) <- zip (V.toList $ annotated a) (breakLines d) ] format :: B.ByteString -> Annotated -> String format d a = pi_list ++ "\n" ++ file where pi_list = unlines $ [ show n ++ ": " ++ renderString (humanFriendly i) | (n :: Int, i) <- zip [1..] pis ] file = concat [ annotation (fst $ head chunk) ++ " | " ++ line (head chunk) ++ "\n" ++ unlines [ indent 25 (" | " ++ line l) | l <- tail chunk ] | chunk <- file_ann ] pis = nub $ catMaybes . map fst $ V.toList (annotated a) pi_map = M.fromList (zip pis [1 :: Int ..]) file_ann = groupBy (\x y -> fst x == fst y) $ zip (V.toList $ annotated a) (breakLines d) line ((_, add), l) = BC.unpack $ BC.concat [l, " ", add] annotation (Just i, _) | Just n <- M.lookup i pi_map = pad 20 (piMail i) ++ " " ++ pad 4 ("#" ++ show n) annotation _ = pad 25 "unknown" pad n str = replicate (n - length str) ' ' ++ (take n str) indent n str = replicate n ' ' ++ str piMail pi | '<' `elem` piAuthor pi = takeWhile (/= '>') . drop 1 . dropWhile (/= '<') $ piAuthor pi | otherwise = piAuthor pi breakLines :: BC.ByteString -> [BC.ByteString] breakLines s = case BC.split '\n' s of [] -> [] split | BC.null (last split) -> init split | otherwise -> split darcs-2.8.4/src/Darcs/ArgumentDefaults.hs0000644001765600176560000000764312104371431017604 0ustar ganeshganesh-- Copyright (C) 2003 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. module Darcs.ArgumentDefaults ( getDefaultFlags ) where import Data.Maybe ( listToMaybe, mapMaybe ) import Darcs.Arguments ( DarcsFlag, atomicOptions, DarcsAtomicOption( .. ), DarcsOption ( .. ), applyDefaults, arein ) import Darcs.Commands ( CommandControl( CommandData ), commandAlloptions ) import Darcs.Commands.Help ( commandControlList ) import Darcs.Repository.Prefs ( getGlobal, getPreflist ) getDefaultFlags :: String -> [DarcsOption] -> [DarcsFlag] -> IO [DarcsFlag] getDefaultFlags com com_opts already = do repo_defs <- defaultContent $ getPreflist "defaults" global_defs <- defaultContent $ getGlobal "defaults" let repo_flags = getFlagsFrom com com_opts already repo_defs global_flags = getFlagsFrom com com_opts (already++repo_flags) global_defs return $ applyDefaults com_opts -- hard-coded defaults (respects user preferences) $ repo_flags ++ global_flags -- user preferences getFlagsFrom :: String -> [DarcsOption] -> [DarcsFlag] -> [(String,String,String)] -> [DarcsFlag] getFlagsFrom com com_opts already defs = options_for com_defs com_opts com_opts ++ options_for all_defs com_opts all_opts where com_defs = filter (\ (c,_,_) -> c == com) defs all_defs = filter (\ (c,_,_) -> c == "ALL") defs options_for d o ao = concatMap (findOption o ao already) d all_opts = concatMap get_opts commandControlList get_opts (CommandData c) = let (o1, o2) = commandAlloptions c in o1 ++ o2 get_opts _ = [] findOption :: [DarcsOption] -> [DarcsOption] -> [DarcsFlag] -> (String,String,String) -> [DarcsFlag] findOption opts all_opts already (c, f, d) = if null $ mapMaybe choose_option all_opts then error $ "Bad default option: command '"++c++"' has no option '"++f++"'." else concat $ mapMaybe choose_option opts where choose_atomic_option (DarcsNoArgOption _ fls o _) | f `elem` fls = if null d then Just [o] else error $ "Bad default option: '"++f ++"' takes no argument, but '"++d ++"' argument given." choose_atomic_option (DarcsArgOption _ fls o _ _) | f `elem` fls = if null d then error $ "Bad default option: '"++f ++"' requires an argument, but no " ++"argument given." else Just [o d] choose_atomic_option _ = Nothing choose_option o | o `arein` already = Just [] | otherwise = listToMaybe $ mapMaybe choose_atomic_option $ atomicOptions o defaultContent :: IO [String] -> IO [(String,String,String)] defaultContent = fmap (mapMaybe (doline . words)) where doline (c:a:r) = Just (c, drop_dashdash a, unwords r) doline _ = Nothing drop_dashdash ('-':'-':a) = a drop_dashdash a = a darcs-2.8.4/src/Darcs/Arguments.hs0000644001765600176560000021304212104371431016267 0ustar ganeshganesh-- Copyright (C) 2002-2004 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP, PatternGuards #-} #include "gadts.h" module Darcs.Arguments ( DarcsFlag( .. ), flagToString, applyDefaults, nubOptions, maxCount, isin, arein, setEnvDarcsPatches, setEnvDarcsFiles, fixFilePathOrStd, fixUrl, fixUrlFlag, fixSubPaths, maybeFixSubPaths, DarcsAtomicOption( .. ), atomicOptions, DarcsOption( .. ), optionFromDarcsOption, help, listOptions, listFiles, anyVerbosity, disable, restrictPaths, notest, test, workingRepoDir, remoteRepo, leaveTestDir, possiblyRemoteRepoDir, getRepourl, listRegisteredFiles, listUnregisteredFiles, author, getAuthor, getEasyAuthor, getSendmailCmd, fileHelpAuthor, environmentHelpEmail, patchnameOption, distnameOption, logfile, rmlogfile, fromOpt, subject, getSubject, charset, getCharset, inReplyTo, getInReplyTo, target, ccSend, ccApply, getCc, output, outputAutoName, recursive, patchFormatChoices, upgradeFormat, useWorkingDir, askdeps, ignoretimes, lookforadds, askLongComment, keepDate, sendmailCmd, environmentHelpSendmail, sign, verify, editDescription, reponame, creatorhash, applyConflictOptions, reply, pullConflictOptions, useExternalMerge, depsSel, nocompress, uncompressNocompress, repoCombinator, optionsLatex, reorderPatches, noskipBoring, allowProblematicFilenames, applyas, humanReadable, machineReadable, changesReverse, onlyToFiles, changesFormat, matchOneContext, matchOneNontag, matchMaxcount, sendToContext, getContext, pipeInteractive, allInteractive, allPipeInteractive, summary, unified, tokens, partial, diffCmdFlag, diffflags, unidiff, xmloutput, pauseForGui, forceReplace, dryRun, dryRunNoxml, printDryRunMessageAndExit, showFriendly, matchOne, matchSeveral, matchRange, matchSeveralOrRange, happyForwarding, matchSeveralOrLast, setDefault, setScriptsExecutableOption, bisect, sibling, flagsToSiblings, relink, files, directories, pending, posthookCmd, posthookPrompt, getPosthookCmd, prehookCmd, prehookPrompt, getPrehookCmd, nullFlag, umaskOption, storeInMemory, patchSelectFlag, networkOptions, noCache, allowUnrelatedRepos, checkOrRepair, justThisRepo, optimizePristine, optimizeHTTP, getOutput, makeScriptsExecutable, usePacks, recordRollback, amendUnrecord ) where import System.Console.GetOpt import System.Directory ( doesDirectoryExist ) import Storage.Hashed.AnchoredPath( anchorPath ) import Storage.Hashed.Plain( readPlainTree ) import Storage.Hashed.Tree( list, expand, emptyTree ) import Data.List ( (\\), nub, intercalate ) import Data.Maybe ( fromMaybe, listToMaybe, maybeToList, isNothing, catMaybes, mapMaybe ) import System.Exit ( ExitCode(ExitSuccess), exitWith ) import Control.Monad ( when, unless ) import Control.Applicative( (<$>) ) import Data.Char ( isDigit ) #ifndef WIN32 import Printer ( renderString ) import System.Posix.Env ( setEnv ) import Darcs.Patch ( listTouchedFiles ) import Progress ( beginTedious, endTedious, tediousSize, finishedOneIO ) #endif import Darcs.Patch.PatchInfoAnd ( PatchInfoAnd, info, hopefullyM ) import Darcs.Patch.Apply( ApplyState ) import Darcs.Patch ( RepoPatch, Patchy, showNicely, description, xmlSummary ) import Darcs.Patch.Info ( toXml ) import Darcs.Witnesses.Ordered ( FL, mapFL ) import qualified Darcs.Patch ( summary ) import Darcs.Utils ( askUser, askUserListItem, maybeGetEnv, firstJustIO, catchall, withCurrentDirectory ) import Darcs.Repository.Prefs ( getPreflist, getGlobal, globalPrefsDirDoc ) import Darcs.Repository.State ( restrictBoring, applyTreeFilter, readRecordedAndPending ) import Darcs.Repository( setScriptsExecutablePatches ) import Darcs.URL ( isFile ) import Darcs.RepoPath ( AbsolutePath, AbsolutePathOrStd, SubPath, toFilePath, makeSubPathOf, ioAbsolute, ioAbsoluteOrStd, makeAbsolute, makeAbsoluteOrStd ) import Darcs.Patch.MatchData ( patchMatch ) import Darcs.Flags ( DarcsFlag(..), maxCount, defaultFlag ) import Darcs.Repository ( withRepository, RepoJob(..) ) import Darcs.Global ( darcsdir ) import Darcs.Lock ( writeLocaleFile ) import Printer ( Doc, putDocLn, text, vsep, ($$), vcat, insertBeforeLastline, prefix ) import ByteStringUtils ( decodeString ) import Storage.Hashed.Tree( Tree ) #include "impossible.h" data FlagContent = NoContent | AbsoluteContent AbsolutePath | AbsoluteOrStdContent AbsolutePathOrStd | StringContent String deriving (Eq, Show, Ord) -- getContent is very tedious to write, but this is the only way (that -- I know of) to guarantee that it works for all flags (which then -- guarantees that isAnAbsolute, isa, flagToString, etc also work -- properly) -- | 'getContentString' returns the content of a flag, if any. -- For instance, the content of @Author \"Louis Aragon\"@ is @StringContent -- \"Louis Aragon\"@, while the content of @Pipe@ is @NoContent@ getContent :: DarcsFlag -> FlagContent getContent (PatchName s) = StringContent s getContent (Output s) = AbsoluteOrStdContent s getContent Verbose = NoContent getContent Help = NoContent getContent ListOptions = NoContent getContent Test = NoContent getContent NoTest = NoContent getContent OnlyChangesToFiles = NoContent getContent ChangesToAllFiles = NoContent getContent LeaveTestDir = NoContent getContent NoLeaveTestDir = NoContent getContent Timings = NoContent getContent Debug = NoContent getContent DebugVerbose = NoContent getContent DebugHTTP = NoContent getContent NormalVerbosity = NoContent getContent Quiet = NoContent getContent (Target s) = StringContent s getContent (Cc s) = StringContent s getContent (Subject s) = StringContent s getContent (Charset s) = StringContent s getContent (InReplyTo s) = StringContent s getContent (SendmailCmd s) = StringContent s getContent (Author s) = StringContent s getContent (OnePatch s) = StringContent s getContent (SeveralPatch s) = StringContent s getContent (AfterPatch s) = StringContent s getContent (UpToPatch s) = StringContent s getContent (TagName s) = StringContent s getContent (LastN s) = StringContent (show s) getContent (MaxCount s) = StringContent (show s) getContent (OneTag s) = StringContent s getContent (AfterTag s) = StringContent s getContent (UpToTag s) = StringContent s getContent (Context s) = AbsoluteContent s getContent GenContext = NoContent getContent (LogFile s) = AbsoluteContent s getContent (OutputAutoName s) = AbsoluteContent s getContent NumberPatches = NoContent getContent (PatchIndexRange _ _) = NoContent -- FIXME this doesn't fit into a neat category getContent Count = NoContent getContent All = NoContent getContent Recursive = NoContent getContent NoRecursive = NoContent getContent Reorder = NoContent getContent RestrictPaths = NoContent getContent DontRestrictPaths = NoContent getContent AskDeps = NoContent getContent NoAskDeps = NoContent getContent RmLogFile = NoContent getContent DontRmLogFile = NoContent getContent (DistName s) = StringContent s getContent (CreatorHash s) = StringContent s getContent (SignAs s) = StringContent s getContent (SignSSL s) = StringContent s getContent (Verify s) = AbsoluteContent s getContent (VerifySSL s) = AbsoluteContent s getContent IgnoreTimes = NoContent getContent DontIgnoreTimes = NoContent getContent LookForAdds = NoContent getContent NoLookForAdds = NoContent getContent AnyOrder = NoContent getContent Intersection = NoContent getContent Unified = NoContent getContent NonUnified = NoContent getContent Union = NoContent getContent Complement = NoContent getContent Sign = NoContent getContent NoSign = NoContent getContent HappyForwarding = NoContent getContent NoHappyForwarding = NoContent getContent (RemoteDarcsOpt s) = StringContent s getContent (Toks s) = StringContent s getContent (WorkRepoDir s) = StringContent s getContent (WorkRepoUrl s) = StringContent s getContent (RemoteRepo s) = StringContent s getContent (NewRepo s) = StringContent s getContent (Reply s) = StringContent s getContent EditDescription = NoContent getContent NoEditDescription = NoContent getContent EditLongComment = NoContent getContent NoEditLongComment = NoContent getContent PromptLongComment = NoContent getContent KeepDate = NoContent getContent NoKeepDate = NoContent getContent AllowConflicts = NoContent getContent MarkConflicts = NoContent getContent NoAllowConflicts = NoContent getContent SkipConflicts = NoContent getContent Boring = NoContent getContent SkipBoring = NoContent getContent AllowCaseOnly = NoContent getContent DontAllowCaseOnly = NoContent getContent AllowWindowsReserved = NoContent getContent DontAllowWindowsReserved = NoContent getContent DontGrabDeps = NoContent getContent DontPromptForDependencies = NoContent getContent PromptForDependencies = NoContent getContent Compress = NoContent getContent NoCompress = NoContent getContent UnCompress = NoContent getContent MachineReadable = NoContent getContent HumanReadable = NoContent getContent Pipe = NoContent getContent Interactive = NoContent getContent Summary = NoContent getContent NoSummary = NoContent getContent (ApplyAs s) = StringContent s getContent (DiffCmd s) = StringContent s getContent (ExternalMerge s) = StringContent s getContent PauseForGui = NoContent getContent NoPauseForGui = NoContent getContent (DiffFlags s) = StringContent s getContent (OnePattern _) = NoContent -- FIXME!!! getContent (SeveralPattern _) = NoContent -- FIXME!!! getContent (UpToPattern _) = NoContent -- FIXME!!! getContent (AfterPattern _) = NoContent -- FIXME!!! getContent Reverse = NoContent getContent Forward = NoContent getContent Complete = NoContent getContent Lazy = NoContent getContent (FixFilePath _ _) = NoContent -- FIXME!!! getContent XMLOutput = NoContent getContent ForceReplace = NoContent getContent NonApply = NoContent getContent NonVerify = NoContent getContent NonForce = NoContent getContent DryRun = NoContent getContent (SetDefault _) = NoContent getContent (NoSetDefault _) = NoContent getContent Disable = NoContent getContent SetScriptsExecutable = NoContent getContent DontSetScriptsExecutable = NoContent getContent Bisect = NoContent getContent UseHashedInventory = NoContent getContent UseFormat2 = NoContent getContent NoUpdateWorking = NoContent getContent UpgradeFormat = NoContent getContent Relink = NoContent getContent Files = NoContent getContent NoFiles = NoContent getContent Directories = NoContent getContent NoDirectories = NoContent getContent Pending = NoContent getContent NoPending = NoContent getContent NoPosthook = NoContent getContent AskPosthook = NoContent getContent (Sibling s) = AbsoluteContent s getContent (PosthookCmd s) = StringContent s getContent RunPosthook = NoContent getContent NoPrehook = NoContent getContent RunPrehook = NoContent getContent AskPrehook = NoContent getContent StoreInMemory = NoContent getContent ApplyOnDisk = NoContent getContent NoHTTPPipelining = NoContent getContent Packs = NoContent getContent NoPacks = NoContent getContent NoCache = NoContent getContent NullFlag = NoContent getContent (PrehookCmd s) = StringContent s getContent (UMask s) = StringContent s getContent AllowUnrelatedRepos = NoContent getContent Check = NoContent getContent Repair = NoContent getContent JustThisRepo = NoContent getContent OptimizePristine = NoContent getContent OptimizeHTTP = NoContent getContent RecordRollback = NoContent getContent NoRecordRollback = NoContent getContent AmendUnrecord = NoContent getContent NoAmendUnrecord = NoContent getContent UseWorkingDir = NoContent getContent UseNoWorkingDir = NoContent getContentString :: DarcsFlag -> Maybe String getContentString f = do StringContent s <- Just $ getContent f return s -- | @a `'isa'` b@ tests whether @a@ is flag @b@ with a string argument. -- @b@ typically is a Flag constructor expecting a string -- For example, @(Author \"Ted Hughes\") `isa` Author@ returns true. isa :: DarcsFlag -> (String -> DarcsFlag) -> Bool a `isa` b = case getContentString a of Nothing -> False Just s -> a == b s -- | @a `'isAnAbsolute'` b@ tests whether @a@ is flag @b@ with an absolute path argument. -- @b@ typically is a Flag constructor expecting an absolute path argument -- For example, @(Context contextfile) `isAnAbsolute` Context@ returns true. isAnAbsolute :: DarcsFlag -> (AbsolutePath -> DarcsFlag) -> Bool isAnAbsolute f x = case getContent f of AbsoluteContent s -> f == x s _ -> False -- | @a `'isAnAbsoluteOrStd'` b@ tests whether @a@ is flag @b@ with a path argument. -- @b@ typically is a Flag constructor expecting a path argument -- For example, @(Output o) `isAnAbsoluteOrStd` @ returns true. isAnAbsoluteOrStd :: DarcsFlag -> (AbsolutePathOrStd -> DarcsFlag) -> Bool isAnAbsoluteOrStd f x = case getContent f of AbsoluteOrStdContent s -> f == x s _ -> False isin :: DarcsAtomicOption -> [DarcsFlag] -> Bool (DarcsInternalOption f) `isin` fs = f `elem` fs (DarcsNoArgOption _ _ f _) `isin` fs = f `elem` fs (DarcsArgOption _ _ f _ _) `isin` fs = any (`isa` f) fs (DarcsAbsPathOption _ _ f _ _) `isin` fs = any (`isAnAbsolute` f) fs (DarcsAbsPathOrStdOption _ _ f _ _) `isin` fs = any (`isAnAbsoluteOrStd` f) fs (DarcsOptAbsPathOption _ _ _ f _ _) `isin` fs = any (`isAnAbsolute` f) fs arein :: DarcsOption -> [DarcsFlag] -> Bool o `arein` fs = any (`isin` fs) (atomicOptions o) -- | A type for darcs' options. The value contains the command line -- switch(es) for the option, a help string, and a function to build a -- @DarcsFlag@ from the command line arguments. for each constructor, -- 'shortSwitches' represents the list of short command line switches -- which invoke the option, longSwitches the list of long command line -- switches, optDescr the description of the option, and argDescr the description -- of its argument, if any. mkFlag is a function which makes a @DarcsFlag@ from -- the arguments of the option. data DarcsAtomicOption = DarcsArgOption [Char] [String] (String->DarcsFlag) String String -- ^ @DarcsArgOption shortSwitches longSwitches mkFlag ArgDescr OptDescr@ -- The constructor for options with a string argument, such as -- @--tag@ | DarcsAbsPathOption [Char] [String] (AbsolutePath -> DarcsFlag) String String -- ^ @DarcsAbsPathOption shortSwitches longSwitches mkFlag ArgDescr OptDescr@ -- The constructor for options with an absolute path argument, such as -- @--sibling@ | DarcsAbsPathOrStdOption [Char] [String] (AbsolutePathOrStd -> DarcsFlag) String String -- ^ @DarcsAbsPathOrStdOption shortSwitches longSwitches mkFlag ArgDescr OptDescr@ -- The constructor for options with a path argument, such as @-o@ | DarcsOptAbsPathOption [Char] [String] String (AbsolutePath -> DarcsFlag) String String -- ^ @DarcsOptAbsPathOrStdOption shortSwitches longSwitches defaultPath -- mkFlag ArgDescr OptDescr@ where defaultPath is a default value -- for the Path, as a string to be parsed as if it had been given -- on the command line. -- The constructor for options with an optional path argument, such as @-O@ | DarcsNoArgOption [Char] [String] DarcsFlag String -- ^ @DarcsNoArgOption shortSwitches longSwitches mkFlag optDescr@ -- The constructon fon options with no arguments. | DarcsInternalOption DarcsFlag -- ^ @DarcsInternalOption@ -- An option just for internal use (e.g. defaulting), not directly available to the user. data DarcsOption = DarcsSingleOption DarcsAtomicOption | DarcsMultipleChoiceOption [DarcsAtomicOption] -- ^ A constructor for grouping related options together, such as -- @--hashed@ and @--darcs-2@. | DarcsMutuallyExclusive [DarcsAtomicOption] -- choices ([DarcsFlag] -> [DarcsFlag]) -- setter type NoArgPieces = (DarcsFlag -> String -> DarcsAtomicOption, DarcsFlag , String) mkMutuallyExclusive :: [NoArgPieces] -- ^ before -> NoArgPieces -- ^ default -> [NoArgPieces] -- ^ after -> DarcsOption mkMutuallyExclusive os1 od_ os2 = DarcsMutuallyExclusive (map option (os1 ++ (od : os2))) (defaultFlag (map flag (os1 ++ os2)) (flag od)) where od = third (++ " [DEFAULT]") od_ flag (_,f,_) = f option (x,y,z) = x y z third f (x,y,z) = (x,y,f z) nubOptions :: [DarcsOption] -> [DarcsFlag] -> [DarcsFlag] nubOptions [] opts = opts nubOptions (DarcsMutuallyExclusive ch _:options) opts = nubOptions options $ collapse opts where collapse (x:xs) | x `elem` flags ch = x : clear xs | otherwise = x : collapse xs collapse [] = [] clear (x:xs) | x `elem` flags ch = clear xs | otherwise = x : clear xs clear [] = [] flags (DarcsNoArgOption _ _ fl _:xs) = fl : flags xs flags (DarcsInternalOption fl:xs) = fl : flags xs flags (_:xs) = flags xs flags [] = [] nubOptions (_:options) opts = nubOptions options opts applyDefaults :: [DarcsOption] -> [DarcsFlag] -> [DarcsFlag] applyDefaults opts = foldr (.) id (mapMaybe getSetter opts) where getSetter (DarcsMutuallyExclusive _ f) = Just f getSetter _ = Nothing optionFromDarcsAtomicOption :: AbsolutePath -> DarcsAtomicOption -> Maybe (OptDescr DarcsFlag) optionFromDarcsAtomicOption _ (DarcsInternalOption _) = Nothing optionFromDarcsAtomicOption _ (DarcsNoArgOption a b c h) = Just $ Option a b (NoArg c) h optionFromDarcsAtomicOption _ (DarcsArgOption a b c n h) = Just $ Option a b (ReqArg c n) h optionFromDarcsAtomicOption wd (DarcsAbsPathOrStdOption a b c n h) = Just $ Option a b (ReqArg (c . makeAbsoluteOrStd wd) n) h optionFromDarcsAtomicOption wd (DarcsAbsPathOption a b c n h) = Just $ Option a b (ReqArg (c . makeAbsolute wd) n) h optionFromDarcsAtomicOption wd (DarcsOptAbsPathOption a b d c n h) = Just $ Option a b (OptArg (c . makeAbsolute wd . fromMaybe d) n) h atomicOptions :: DarcsOption -> [DarcsAtomicOption] atomicOptions (DarcsSingleOption x) = [x] atomicOptions (DarcsMultipleChoiceOption xs) = xs atomicOptions (DarcsMutuallyExclusive xs _) = xs optionFromDarcsOption :: AbsolutePath -> DarcsOption -> [OptDescr DarcsFlag] optionFromDarcsOption wd = mapMaybe (optionFromDarcsAtomicOption wd) . atomicOptions -- | 'concat_option' creates a DarcsMultipleChoiceOption from a list of -- option, flattening any DarcsMultipleChoiceOption in the list. concatOptions :: [DarcsOption] -> DarcsOption concatOptions = DarcsMultipleChoiceOption . concatMap atomicOptions extractFixPath :: [DarcsFlag] -> Maybe (AbsolutePath, AbsolutePath) extractFixPath [] = Nothing extractFixPath ((FixFilePath repo orig):_) = Just (repo, orig) extractFixPath (_:fs) = extractFixPath fs fixFilePath :: [DarcsFlag] -> FilePath -> IO AbsolutePath fixFilePath opts f = case extractFixPath opts of Nothing -> bug "Can't fix path in fixFilePath" Just (_,o) -> withCurrentDirectory o $ ioAbsolute f fixFilePathOrStd :: [DarcsFlag] -> FilePath -> IO AbsolutePathOrStd fixFilePathOrStd opts f = case extractFixPath opts of Nothing -> bug "Can't fix path in fixFilePathOrStd" Just (_,o) -> withCurrentDirectory o $ ioAbsoluteOrStd f fixUrlFlag :: [DarcsFlag] -> DarcsFlag -> IO DarcsFlag fixUrlFlag opts (RemoteRepo f) = RemoteRepo `fmap` fixUrl opts f fixUrlFlag _ f = return f fixUrl :: [DarcsFlag] -> String -> IO String fixUrl opts f = if isFile f then toFilePath `fmap` fixFilePath opts f else return f -- | @maybeFixSubPaths files@ tries to turn the file paths in its argument into -- @SubPath@s. -- -- When converting a relative path to an absolute one, this function first tries -- to interpret the relative path with respect to the current working directory. -- If that fails, it tries to interpret it with respect to the repository -- directory. Only when that fails does it put a @Nothing@ in the result at the -- position of the path that cannot be converted. -- -- It is intended for validating file arguments to darcs commands. maybeFixSubPaths :: [DarcsFlag] -> [FilePath] -> IO [Maybe SubPath] maybeFixSubPaths flags fs = withCurrentDirectory o $ do fixedFs <- mapM fixit fs let bads = snd . unzip . filter (isNothing . fst) $ zip fixedFs fs unless (null bads) . putStrLn $ "Ignoring non-repository paths: " ++ intercalate ", " bads return fixedFs where (r,o) = case extractFixPath flags of Just xxx -> xxx Nothing -> bug "Can't fix path in fixSubPaths" fixit p = do ap <- ioAbsolute p case makeSubPathOf r ap of Just sp -> return $ Just sp Nothing -> withCurrentDirectory r $ do absolutePathByRepodir <- ioAbsolute p return $ makeSubPathOf r absolutePathByRepodir -- | @fixSubPaths files@ returns the @SubPath@s for the paths in @files@ that -- are inside the repository, preserving their order. Paths in @files@ that are -- outside the repository directory are not in the result. -- -- When converting a relative path to an absolute one, this function first tries -- to interpret the relative path with respect to the current working directory. -- If that fails, it tries to interpret it with respect to the repository -- directory. Only when that fails does it omit the path from the result. -- -- It is intended for validating file arguments to darcs commands. fixSubPaths :: [DarcsFlag] -> [FilePath] -> IO [SubPath] fixSubPaths flags fs = nub . catMaybes <$> (maybeFixSubPaths flags $ filter (not . null) fs) -- | 'list_option' is an option which lists the command's arguments listOptions :: DarcsOption listOptions = DarcsSingleOption $ DarcsNoArgOption [] ["list-options"] ListOptions "simply list the command's arguments" flagToString :: [DarcsOption] -> DarcsFlag -> Maybe String flagToString x f = listToMaybe $ mapMaybe f2o $ concatMap atomicOptions x where f2o (DarcsArgOption _ (s:_) c _ _) = do arg <- getContentString f if c arg == f then return $ unwords [('-':'-':s), arg] else Nothing f2o (DarcsNoArgOption _ (s:_) f' _) | f == f' = Just ('-':'-':s) f2o _ = Nothing pipeInteractive, allPipeInteractive, allInteractive, humanReadable, machineReadable, diffflags, allowProblematicFilenames, noskipBoring, askLongComment, matchOneNontag, changesReverse, creatorhash, changesFormat, matchOneContext, happyForwarding, sendToContext, diffCmdFlag, storeInMemory, useExternalMerge, pauseForGui, pullConflictOptions, target, ccSend, ccApply, applyConflictOptions, reply, xmloutput, distnameOption, patchnameOption, editDescription, output, outputAutoName, unidiff, repoCombinator, unified, summary, uncompressNocompress, subject, charset, inReplyTo, nocompress, matchSeveralOrRange, matchSeveralOrLast, author, askdeps, lookforadds, ignoretimes, test, notest, help, forceReplace, allowUnrelatedRepos, matchOne, matchRange, matchSeveral, sendmailCmd, logfile, rmlogfile, leaveTestDir, fromOpt, recordRollback, amendUnrecord :: DarcsOption sign, applyas, verify :: DarcsOption help = DarcsSingleOption $ DarcsNoArgOption ['h'] ["help"] Help "shows brief description of command and its arguments" disable :: DarcsOption disable = DarcsSingleOption $ DarcsNoArgOption [] ["disable"] Disable "disable this command" anyVerbosity :: [DarcsOption] anyVerbosity =[DarcsMultipleChoiceOption [DarcsNoArgOption [] ["debug"] Debug "give only debug output", DarcsNoArgOption [] ["debug-verbose"] DebugVerbose "give debug and verbose output", DarcsNoArgOption [] ["debug-http"] DebugHTTP "give debug output for libcurl", DarcsNoArgOption ['v'] ["verbose"] Verbose "give verbose output", DarcsNoArgOption ['q'] ["quiet"] Quiet "suppress informational output", DarcsNoArgOption [] ["standard-verbosity"] NormalVerbosity "neither verbose nor quiet output"], DarcsSingleOption (DarcsNoArgOption [] ["timings"] Timings "provide debugging timings information")] workingRepoDir :: DarcsOption workingRepoDir = DarcsSingleOption $ DarcsArgOption [] ["repodir"] WorkRepoDir "DIRECTORY" "specify the repository directory in which to run" possiblyRemoteRepoDir :: DarcsOption possiblyRemoteRepoDir = DarcsSingleOption $ DarcsArgOption [] ["repo"] WorkRepoUrl "URL" "specify the repository URL" -- | 'getRepourl' takes a list of flags and returns the url of the -- repository specified by @Repodir \"directory\"@ in that list of flags, if any. -- This flag is present if darcs was invoked with @--repodir=DIRECTORY@ getRepourl :: [DarcsFlag] -> Maybe String getRepourl [] = Nothing getRepourl (WorkRepoUrl d:_) | not (isFile d) = Just d getRepourl (_:fs) = getRepourl fs -- | 'remoteRepo' is the option used to specify the URL of the remote -- repository to work with remoteRepo :: DarcsOption remoteRepo = DarcsSingleOption $ DarcsArgOption [] ["remote-repo"] RemoteRepo "URL" "specify the remote repository URL to work with" patchnameOption = DarcsSingleOption $ DarcsArgOption ['m'] ["name"] (PatchName . decodeString) "PATCHNAME" "name of patch" sendToContext = DarcsSingleOption $ DarcsAbsPathOption [] ["context"] Context "FILENAME" "send to context stored in FILENAME" matchOneContext = DarcsMultipleChoiceOption [DarcsArgOption [] ["to-match"] mp "PATTERN" "select changes up to a patch matching PATTERN", DarcsArgOption [] ["to-patch"] OnePatch "REGEXP" "select changes up to a patch matching REGEXP", __tag, DarcsAbsPathOption [] ["context"] Context "FILENAME" "version specified by the context in FILENAME" ] where mp s = OnePattern (patchMatch s) matchOne = DarcsMultipleChoiceOption [__match, __patch, __tag, __index] -- [NOTE --index removed from matchOneNontag because issue1926] -- The --index option was removed for 2.5 release because it isn't handled -- by amend-record (see issue1926). -- -- At this moment, amend-record is the only command that uses 'matchOneNontag', -- so there is no other command affected. matchOneNontag = DarcsMultipleChoiceOption [__match, __patch {- , __index -} ] matchSeveral = DarcsMultipleChoiceOption [__matches, __patches, __tags] matchRange = concatOptions $ [ matchTo, matchFrom , DarcsMultipleChoiceOption [__match, __patch, __last, __indexes] ] matchSeveralOrRange = concatOptions [ matchTo, matchFrom , DarcsMultipleChoiceOption [ __last, __indexes, __matches, __patches, __tags] ] matchSeveralOrLast = concatOptions [ matchFrom , DarcsMultipleChoiceOption [ __last, __matches, __patches, __tags] ] matchTo, matchFrom :: DarcsOption matchTo = DarcsMultipleChoiceOption [DarcsArgOption [] ["to-match"] uptop "PATTERN" "select changes up to a patch matching PATTERN", DarcsArgOption [] ["to-patch"] UpToPatch "REGEXP" "select changes up to a patch matching REGEXP", DarcsArgOption [] ["to-tag"] UpToTag "REGEXP" "select changes up to a tag matching REGEXP"] where uptop s = UpToPattern (patchMatch s) matchFrom = DarcsMultipleChoiceOption [DarcsArgOption [] ["from-match"] fromp "PATTERN" "select changes starting with a patch matching PATTERN", DarcsArgOption [] ["from-patch"] AfterPatch "REGEXP" "select changes starting with a patch matching REGEXP", DarcsArgOption [] ["from-tag"] AfterTag "REGEXP" "select changes starting with a tag matching REGEXP"] where fromp s = AfterPattern (patchMatch s) __tag, __tags, __patch, __patches, __match, __matches, __last, __index, __indexes :: DarcsAtomicOption __tag = DarcsArgOption ['t'] ["tag"] OneTag "REGEXP" "select tag matching REGEXP" __tags = DarcsArgOption ['t'] ["tags"] OneTag "REGEXP" "select tags matching REGEXP" __patch = DarcsArgOption ['p'] ["patch"] OnePatch "REGEXP" "select a single patch matching REGEXP" __patches = DarcsArgOption ['p'] ["patches"] SeveralPatch "REGEXP" "select patches matching REGEXP" __match = DarcsArgOption [] ["match"] mp "PATTERN" "select a single patch matching PATTERN" where mp s = OnePattern (patchMatch s) __matches = DarcsArgOption [] ["matches"] mp "PATTERN" "select patches matching PATTERN" where mp s = SeveralPattern (patchMatch s) __last = DarcsArgOption [] ["last"] lastn "NUMBER" "select the last NUMBER patches" where lastn = LastN . numberString __index = DarcsArgOption ['n'] ["index"] indexrange "N" "select one patch" where indexrange s = if all isDigit s then PatchIndexRange (read s) (read s) else PatchIndexRange 0 0 __indexes = DarcsArgOption ['n'] ["index"] indexrange "N-M" "select a range of patches" where indexrange s = if all isokay s then if '-' `elem` s then let x1 = takeWhile (/= '-') s x2 = reverse $ takeWhile (/= '-') $ reverse s in PatchIndexRange (read x1) (read x2) else PatchIndexRange (read s) (read s) else PatchIndexRange 0 0 isokay c = isDigit c || c == '-' matchMaxcount :: DarcsOption matchMaxcount = DarcsSingleOption $ DarcsArgOption [] ["max-count"] mc "NUMBER" "return only NUMBER results" where mc = MaxCount . numberString -- | 'getContext' takes a list of flags and returns the context -- specified by @Context c@ in that list of flags, if any. -- This flag is present if darcs was invoked with @--context=FILE@ getContext :: [DarcsFlag] -> Maybe AbsolutePath getContext xs = listToMaybe [ c | Context c <- xs ] notest = DarcsMultipleChoiceOption [DarcsNoArgOption [] ["no-test"] NoTest "don't run the test script", DarcsNoArgOption [] ["test"] Test "run the test script"] test = DarcsMultipleChoiceOption [DarcsNoArgOption [] ["test"] Test "run the test script", DarcsNoArgOption [] ["no-test"] NoTest "don't run the test script"] leaveTestDir = DarcsMultipleChoiceOption [DarcsNoArgOption [] ["leave-test-directory"] LeaveTestDir "don't remove the test directory", DarcsNoArgOption [] ["remove-test-directory"] NoLeaveTestDir "remove the test directory"] recordRollback = DarcsMultipleChoiceOption [DarcsNoArgOption [] ["record"] RecordRollback "record the rollback patch (default)", DarcsNoArgOption [] ["no-record"] NoRecordRollback "don't record the rollback patch (only roll back in working dir)"] amendUnrecord = DarcsMultipleChoiceOption [DarcsNoArgOption [] ["add"] NoAmendUnrecord "add the changes to patch (default)", DarcsNoArgOption [] ["unrecord"] AmendUnrecord "subtract the changes from patch"] ignoretimes = DarcsMultipleChoiceOption [DarcsNoArgOption [] ["ignore-times"] IgnoreTimes "don't trust the file modification times" ,DarcsNoArgOption [] ["no-ignore-times"] DontIgnoreTimes "trust modification times to find modified files [DEFAULT]" ] lookforadds = DarcsMultipleChoiceOption [DarcsNoArgOption ['l'] ["look-for-adds"] LookForAdds "look for (non-boring) files that could be added", DarcsNoArgOption [] ["dont-look-for-adds","no-look-for-adds"] NoLookForAdds "don't look for any files that could be added [DEFAULT]"] askdeps = DarcsMultipleChoiceOption [DarcsNoArgOption [] ["ask-deps"] AskDeps "ask for extra dependencies", DarcsNoArgOption [] ["no-ask-deps"] NoAskDeps "don't ask for extra dependencies"] askLongComment = DarcsMultipleChoiceOption [DarcsNoArgOption [] ["edit-long-comment"] EditLongComment "edit the long comment by default", DarcsNoArgOption [] ["skip-long-comment"] NoEditLongComment "don't give a long comment", DarcsNoArgOption [] ["prompt-long-comment"] PromptLongComment "prompt for whether to edit the long comment"] keepDate :: DarcsOption keepDate = DarcsMultipleChoiceOption [DarcsNoArgOption [] ["keep-date"] KeepDate "keep the date of the original patch", DarcsNoArgOption [] ["no-keep-date"] NoKeepDate "use the current date for the amended patch" ] logfile = DarcsSingleOption $ DarcsAbsPathOption [] ["logfile"] LogFile "FILE" "give patch name and comment in file" rmlogfile = DarcsMultipleChoiceOption [DarcsNoArgOption [] ["delete-logfile"] RmLogFile "delete the logfile when done", DarcsNoArgOption [] ["no-delete-logfile"] DontRmLogFile "keep the logfile when done [DEFAULT]"] author = DarcsSingleOption $ DarcsArgOption ['A'] ["author"] (Author . decodeString) "EMAIL" "specify author id" fromOpt = DarcsSingleOption $ DarcsArgOption [] ["from"] (Author . decodeString) "EMAIL" "specify email address" fileHelpAuthor :: [String] fileHelpAuthor = [ "Each patch is attributed to its author, usually by email address (for", "example, `Fred Bloggs '). Darcs looks in several", "places for this author string: the --author option, the files", "_darcs/prefs/author (in the repository) and " ++ globalPrefsDirDoc ++ "author (in your", "home directory), and the environment variables $DARCS_EMAIL and", "$EMAIL. If none of those exist, Darcs will prompt you for an author", "string and write it to _darcs/prefs/author. Note that if if you have more", "than one email address, note that you can put them all in " ++ globalPrefsDirDoc ++ "author,", "one author per line. Darcs will still prompt you for an author, but it", "allows you to select from the list, or to type in an alternative." ] environmentHelpEmail :: ([String], [String]) environmentHelpEmail = (["DARCS_EMAIL","EMAIL"], fileHelpAuthor) -- | 'getAuthor' takes a list of flags and returns the author of the -- change specified by @Author \"Leo Tolstoy\"@ in that list of flags, if any. -- Otherwise, if @Pipe@ is present, asks the user who is the author and -- returns the answer. If neither are present, try to guess the author, -- from @_darcs/prefs@, and if it's not possible, ask the user. getAuthor :: [DarcsFlag] -> IO String getAuthor (Author a:_) = return a getAuthor (Pipe:_) = askUser "Who is the author? " getAuthor (_:flags) = getAuthor flags getAuthor [] = do easy_author <- getEasyAuthor case easy_author of [a] -> return a [] -> askForAuthor shortPrompt longPrompt as -> askForAuthor (fancyPrompt as) (fancyPrompt as) where shortPrompt = askUser "What is your email address? " longPrompt = askUser "What is your email address (e.g. Fred Bloggs )? " fancyPrompt xs = do putDocLn $ text "" $$ text "You have saved the following email addresses to your global settings:" str <- askUserListItem "Please select an email address for this repository: " (xs ++ ["Other"]) if str == "Other" then longPrompt else return str askForAuthor askfn1 askfn2 = do aminrepo <- doesDirectoryExist (darcsdir++"/prefs") if aminrepo then do putDocLn $ text "Each patch is attributed to its author, usually by email address (for" $$ text "example, `Fred Bloggs '). Darcs could not determine" $$ text "your email address, so you will be prompted for it." $$ text "" $$ text ("Your address will be stored in " ++ darcsdir ++ "/prefs/author.") $$ text "It will be used for all patches recorded in this repository." $$ text ("If you move that file to " ++ globalPrefsDirDoc ++ "author, it will be used for patches") $$ text "you record in ALL repositories." add <- askfn1 writeLocaleFile (darcsdir ++ "/prefs/author") $ unlines ["# " ++ line | line <- fileHelpAuthor] ++ "\n" ++ add return add else askfn2 -- | 'getEasyAuthor' tries to get the author name first from the repository preferences, -- then from global preferences, then from environment variables. Returns @[]@ -- if it could not get it. Note that it may only return multiple possibilities when -- reading from global preferences getEasyAuthor :: IO [String] getEasyAuthor = fmap (map decodeString) $ firstNotNullIO [ (take 1 . nonblank) `fmap` getPreflist "author" , nonblank `fmap` getGlobal "author" , maybeToList `fmap` maybeGetEnv "DARCS_EMAIL" , maybeToList `fmap` maybeGetEnv "EMAIL" ] where nonblank = filter (not . null) -- this could perhaps be simplified with Control.Monad -- but note that we do NOT want to concatenate the results firstNotNullIO [] = return [] firstNotNullIO (e:es) = do v <- e `catchall` return [] if null v then firstNotNullIO es else return v nocompress = DarcsMultipleChoiceOption [__compress, __dontCompress] uncompressNocompress = DarcsMultipleChoiceOption [__compress, __dontCompress, __uncompress] __compress, __dontCompress, __uncompress :: DarcsAtomicOption __compress = DarcsNoArgOption [] ["compress"] Compress "create compressed patches" __dontCompress = DarcsNoArgOption [] ["dont-compress","no-compress"] NoCompress "don't create compressed patches" __uncompress = DarcsNoArgOption [] ["uncompress"] UnCompress "uncompress patches" summary = DarcsMultipleChoiceOption [DarcsNoArgOption ['s'] ["summary"] Summary "summarize changes", DarcsNoArgOption [] ["no-summary"] NoSummary "don't summarize changes"] unified = DarcsMultipleChoiceOption [DarcsNoArgOption ['u'] ["unified"] Unified "output changes in a darcs-specific format similar to diff -u", DarcsNoArgOption [] ["no-unified"] NonUnified "output changes in darcs' usual format"] unidiff = DarcsMultipleChoiceOption [DarcsNoArgOption ['u'] ["unified"] Unified "pass -u option to diff [DEFAULT]", DarcsNoArgOption [] ["no-unified"] NonUnified "output patch in diff's dumb format"] diffCmdFlag = DarcsSingleOption $ DarcsArgOption [] ["diff-command"] DiffCmd "COMMAND" "specify diff command (ignores --diff-opts)" pauseForGui = DarcsMultipleChoiceOption [ DarcsNoArgOption [] ["pause-for-gui"] PauseForGui "pause for an external diff or merge command to finish [DEFAULT]" , DarcsNoArgOption [] ["no-pause-for-gui"] NoPauseForGui "return immediately after external diff or merge command finishes" ] storeInMemory = DarcsMultipleChoiceOption [DarcsNoArgOption [] ["store-in-memory"] StoreInMemory "do patch application in memory rather than on disk", DarcsNoArgOption [] ["no-store-in-memory"] ApplyOnDisk "do patch application on disk [DEFAULT]"] target = DarcsSingleOption $ DarcsArgOption [] ["to"] Target "EMAIL" "specify destination email" ccSend = DarcsSingleOption $ DarcsArgOption [] ["cc"] Cc "EMAIL" "mail results to additional EMAIL(s)" ccApply = DarcsSingleOption $ DarcsArgOption [] ["cc"] Cc "EMAIL" "mail results to additional EMAIL(s). Requires --reply" -- |'getCc' takes a list of flags and returns the addresses to send a copy of -- the patch bundle to when using @darcs send@. -- looks for a cc address specified by @Cc \"address\"@ in that list of flags. -- Returns the addresses as a comma separated string. getCc :: [DarcsFlag] -> String getCc fs = lt $ mapMaybe whatcc fs where whatcc (Cc t) = Just t whatcc _ = Nothing lt [t] = t lt [t,""] = t lt (t:ts) = t++" , "++lt ts lt [] = "" subject = DarcsSingleOption $ DarcsArgOption [] ["subject"] Subject "SUBJECT" "specify mail subject" -- |'getSubject' takes a list of flags and returns the subject of the mail -- to be sent by @darcs send@. Looks for a subject specified by -- @Subject \"subject\"@ in that list of flags, if any. -- This flag is present if darcs was invoked with @--subject=SUBJECT@ getSubject :: [DarcsFlag] -> Maybe String getSubject (Subject s:_) = Just s getSubject (_:fs) = getSubject fs getSubject [] = Nothing charset = DarcsSingleOption $ DarcsArgOption [] ["charset"] Charset "CHARSET" "specify mail charset" getCharset :: [DarcsFlag] -> Maybe String getCharset (Charset s:_) = Just s getCharset (_:fs) = getCharset fs getCharset [] = Nothing inReplyTo = DarcsSingleOption $ DarcsArgOption [] ["in-reply-to"] InReplyTo "EMAIL" "specify in-reply-to header" getInReplyTo :: [DarcsFlag] -> Maybe String getInReplyTo (InReplyTo s:_) = Just s getInReplyTo (_:fs) = getInReplyTo fs getInReplyTo [] = Nothing output = DarcsSingleOption $ DarcsAbsPathOrStdOption ['o'] ["output"] Output "FILE" "specify output filename" outputAutoName = DarcsSingleOption $ DarcsOptAbsPathOption ['O'] ["output-auto-name"] "." OutputAutoName "DIRECTORY" "output to automatically named file in DIRECTORY, default: current directory" getOutput :: [DarcsFlag] -> FilePath -> Maybe AbsolutePathOrStd getOutput (Output a:_) _ = return a getOutput (OutputAutoName a:_) f = return $ makeAbsoluteOrStd a f getOutput (_:flags) f = getOutput flags f getOutput [] _ = Nothing editDescription = mkMutuallyExclusive [] yes [no] where yes = ( DarcsNoArgOption [] ["edit-description"] , EditDescription , "edit the patch bundle description" ) no = ( DarcsNoArgOption [] ["dont-edit-description","no-edit-description"] , NoEditDescription , "don't edit the patch bundle description" ) distnameOption = DarcsSingleOption $ DarcsArgOption ['d'] ["dist-name"] DistName "DISTNAME" "name of version" recursive :: String -> DarcsOption recursive h = DarcsMultipleChoiceOption [DarcsNoArgOption ['r'] ["recursive"] Recursive h, DarcsNoArgOption [] ["not-recursive","no-recursive"] NoRecursive ("don't "++h)] patchFormatChoices :: DarcsOption patchFormatChoices = DarcsMultipleChoiceOption [DarcsNoArgOption [] ["hashed"] UseHashedInventory "Some new features. Compatible with older repos", DarcsNoArgOption [] ["darcs-2"] UseFormat2 "All features. Related repos must use same format [DEFAULT]."] useWorkingDir :: DarcsOption useWorkingDir = DarcsMultipleChoiceOption [ DarcsNoArgOption [] ["with-working-dir"] UseWorkingDir "Create a working directory (normal repository)", DarcsNoArgOption [] ["no-working-dir"] UseNoWorkingDir "Do not create a working directory (bare repository)"] upgradeFormat :: DarcsOption upgradeFormat = DarcsSingleOption $ DarcsNoArgOption [] ["upgrade"] UpgradeFormat "upgrade repository to latest compatible format" xmloutput = DarcsSingleOption $ DarcsNoArgOption [] ["xml-output"] XMLOutput "generate XML formatted output" creatorhash = DarcsSingleOption $ DarcsArgOption [] ["creator-hash"] CreatorHash "HASH" "specify hash of creator patch (see docs)" sign = DarcsMultipleChoiceOption [DarcsNoArgOption [] ["sign"] Sign "sign the patch with your gpg key", DarcsArgOption [] ["sign-as"] SignAs "KEYID" "sign the patch with a given keyid", DarcsArgOption [] ["sign-ssl"] SignSSL "IDFILE" "sign the patch using openssl with a given private key", DarcsNoArgOption [] ["dont-sign","no-sign"] NoSign "don't sign the patch"] applyas = DarcsMultipleChoiceOption [DarcsArgOption [] ["apply-as"] ApplyAs "USERNAME" "apply patch as another user using sudo", DarcsNoArgOption [] ["no-apply-as"] NonApply "don't use sudo to apply as another user [DEFAULT]"] happyForwarding = DarcsMultipleChoiceOption [DarcsNoArgOption [] ["happy-forwarding"] HappyForwarding "forward unsigned messages without extra header", DarcsNoArgOption [] ["no-happy-forwarding"] NoHappyForwarding "don't forward unsigned messages without extra header [DEFAULT]"] setDefault :: Bool -> DarcsOption setDefault wantYes | wantYes = mkMutuallyExclusive [yes,no] defaultyes [] | otherwise = mkMutuallyExclusive [yes,no] defaultno [] where yes = ( DarcsNoArgOption [] ["set-default"], SetDefault True , "set default repository" ++ defaultText wantYes ) no = ( DarcsNoArgOption [] ["no-set-default"], NoSetDefault True , "don't set default repository" ++ defaultText (not wantYes) ) defaultyes = ( \f _ -> DarcsInternalOption f, SetDefault False, "" ) defaultno = ( \f _ -> DarcsInternalOption f, NoSetDefault False, "" ) defaultText True = " [DEFAULT]" defaultText False = "" verify = DarcsMultipleChoiceOption [DarcsAbsPathOption [] ["verify"] Verify "PUBRING" "verify that the patch was signed by a key in PUBRING", DarcsAbsPathOption [] ["verify-ssl"] VerifySSL "KEYS" "verify using openSSL with authorized keys from file KEYS", DarcsNoArgOption [] ["no-verify"] NonVerify "don't verify patch signature"] reponame :: DarcsOption reponame = DarcsSingleOption $ DarcsArgOption [] ["repo-name","repodir"] NewRepo "DIRECTORY" "path of output directory" --repodir is there for compatibility --should be removed eventually depsSel :: DarcsOption depsSel = DarcsMultipleChoiceOption [DarcsNoArgOption [] ["no-deps"] DontGrabDeps "don't automatically fulfill dependencies", DarcsNoArgOption [] ["dont-prompt-for-dependencies"] DontPromptForDependencies "don't ask about patches that are depended on by matched patches (with --match or --patch)", DarcsNoArgOption [] ["prompt-for-dependencies"] PromptForDependencies "prompt about patches that are depended on by matched patches [DEFAULT]"] tokens :: DarcsOption tokens = DarcsSingleOption $ DarcsArgOption [] ["token-chars"] Toks "\"[CHARS]\"" "define token to contain these characters" partial :: DarcsOption partial = DarcsMultipleChoiceOption [__lazy, __complete] __lazy, __complete :: DarcsAtomicOption __lazy = DarcsNoArgOption [] ["lazy"] Lazy "get patch files only as needed" __complete = DarcsNoArgOption [] ["complete"] Complete "get a complete copy of the repository" forceReplace = DarcsMultipleChoiceOption [DarcsNoArgOption ['f'] ["force"] ForceReplace "proceed with replace even if 'new' token already exists", DarcsNoArgOption [] ["no-force"] NonForce "don't force the replace if it looks scary"] reply = DarcsSingleOption $ DarcsArgOption [] ["reply"] Reply "FROM" "reply to email-based patch using FROM address" applyConflictOptions = DarcsMultipleChoiceOption [DarcsNoArgOption [] ["mark-conflicts"] MarkConflicts "mark conflicts", DarcsNoArgOption [] ["allow-conflicts"] AllowConflicts "allow conflicts, but don't mark them", DarcsNoArgOption [] ["no-resolve-conflicts"] NoAllowConflicts "equivalent to --dont-allow-conflicts, for backwards compatibility", DarcsNoArgOption [] ["dont-allow-conflicts","no-allow-conflicts"] NoAllowConflicts "fail if there are patches that would create conflicts [DEFAULT]", DarcsNoArgOption [] ["skip-conflicts"] SkipConflicts "filter out any patches that would create conflicts" ] pullConflictOptions = DarcsMultipleChoiceOption [DarcsNoArgOption [] ["mark-conflicts"] MarkConflicts "mark conflicts [DEFAULT]", DarcsNoArgOption [] ["allow-conflicts"] AllowConflicts "allow conflicts, but don't mark them", DarcsNoArgOption [] ["dont-allow-conflicts","no-allow-conflicts"] NoAllowConflicts "fail if there are patches that would create conflicts", DarcsNoArgOption [] ["skip-conflicts"] SkipConflicts "filter out any patches that would create conflicts" ] useExternalMerge = DarcsSingleOption $ DarcsArgOption [] ["external-merge"] ExternalMerge "COMMAND" "use external tool to merge conflicts" -- NOTE: I'd rather work to have no uses of dryRunNoxml, so that any time -- --dry-run is a possibility, automated users can examine the results more -- easily with --xml. dryRunNoxml :: DarcsOption dryRunNoxml = DarcsSingleOption $ DarcsNoArgOption [] ["dry-run"] DryRun "don't actually take the action" dryRun :: [DarcsOption] dryRun = [dryRunNoxml, xmloutput] -- | @'showFriendly' flags patch@ returns a 'Doc' representing the right -- way to show @patch@ given the list @flags@ of flags darcs was invoked with. showFriendly :: Patchy p => [DarcsFlag] -> p C(x y) -> Doc showFriendly opts p | Verbose `elem` opts = showNicely p | Summary `elem` opts = Darcs.Patch.summary p | otherwise = description p -- | @'printDryRunMessageAndExit' action opts patches@ prints a string -- representing the action that would be taken if the @--dry-run@ option -- had not been passed to darcs. Then darcs exits successfully. -- @action@ is the name of the action being taken, like @\"push\"@ -- @opts@ is the list of flags which were sent to darcs -- @patches@ is the sequence of patches which would be touched by @action@. printDryRunMessageAndExit :: (RepoPatch p, ApplyState p ~ Tree) => String -> [DarcsFlag] -> FL (PatchInfoAnd p) C(x y) -> IO () printDryRunMessageAndExit action opts patches = do when (DryRun `elem` opts) $ do putInfo $ text $ "Would " ++ action ++ " the following changes:" putDocLn $ put_mode putInfo $ text $ "" putInfo $ text $ "Making no changes: this is a dry run." exitWith ExitSuccess when (All `elem` opts && Summary `elem` opts) $ do putInfo $ text $ "Will " ++ action ++ " the following changes:" putDocLn $ put_mode where put_mode = if XMLOutput `elem` opts then (text "" $$ vcat (mapFL (indent . xml_info) patches) $$ text "") else (vsep $ mapFL (showFriendly opts) patches) putInfo = if XMLOutput `elem` opts then \_ -> return () else putDocLn xml_info pl | Summary `elem` opts = xml_with_summary pl | otherwise = (toXml . info) pl xml_with_summary hp | Just p <- hopefullyM hp = insertBeforeLastline (toXml $ info hp) (indent $ xmlSummary p) xml_with_summary hp = toXml (info hp) indent = prefix " " noskipBoring = DarcsMultipleChoiceOption [DarcsNoArgOption [] ["boring"] Boring "don't skip boring files", DarcsNoArgOption [] ["no-boring"] SkipBoring "skip boring files [DEFAULT]"] allowProblematicFilenames = DarcsMultipleChoiceOption [DarcsNoArgOption [] ["case-ok"] AllowCaseOnly "don't refuse to add files differing only in case" ,DarcsNoArgOption [] ["no-case-ok"] DontAllowCaseOnly "refuse to add files whose name differ only in case [DEFAULT]" ,DarcsNoArgOption [] ["reserved-ok"] AllowWindowsReserved "don't refuse to add files with Windows-reserved names" ,DarcsNoArgOption [] ["no-reserved-ok"] DontAllowWindowsReserved "refuse to add files with Windows-reserved names [DEFAULT]"] diffflags = DarcsSingleOption $ DarcsArgOption [] ["diff-opts"] DiffFlags "OPTIONS" "options to pass to diff" changesFormat = concatOptions $ [DarcsMultipleChoiceOption [ DarcsNoArgOption [] ["context"] GenContext "give output suitable for get --context" ], xmloutput, humanReadable, DarcsMultipleChoiceOption [ DarcsNoArgOption [] ["number"] NumberPatches "number the changes", DarcsNoArgOption [] ["count"] Count "output count of changes" ] ] changesReverse = DarcsMultipleChoiceOption [DarcsNoArgOption [] ["reverse"] Reverse "show changes in reverse order" ,DarcsNoArgOption [] ["no-reverse"] Forward "show changes in the usual order [DEFAULT]"] onlyToFiles :: DarcsOption onlyToFiles = DarcsMultipleChoiceOption [DarcsNoArgOption [] ["only-to-files"] OnlyChangesToFiles "show only changes to specified files", DarcsNoArgOption [] ["no-only-to-files"] ChangesToAllFiles "show changes to all files [DEFAULT]"] humanReadable = DarcsSingleOption $ DarcsNoArgOption [] ["human-readable"] HumanReadable "give human-readable output" machineReadable = DarcsSingleOption $ DarcsNoArgOption [] ["machine-readable"] MachineReadable "give machine-readable output" pipe :: DarcsAtomicOption pipe = DarcsNoArgOption [] ["pipe"] Pipe "ask user interactively for the patch metadata" interactive :: DarcsAtomicOption interactive = DarcsNoArgOption ['i'] ["interactive"] Interactive "prompt user interactively" allPatches :: DarcsAtomicOption allPatches = DarcsNoArgOption ['a'] ["all"] All "answer yes to all patches" allInteractive = DarcsMultipleChoiceOption [allPatches, interactive] allPipeInteractive = DarcsMultipleChoiceOption [allPatches,pipe,interactive] pipeInteractive = DarcsMultipleChoiceOption [pipe, interactive] repoCombinator = DarcsMultipleChoiceOption [DarcsNoArgOption [] ["intersection"] Intersection "take intersection of all repositories", DarcsNoArgOption [] ["union"] Union "take union of all repositories [DEFAULT]", DarcsNoArgOption [] ["complement"] Complement "take complement of repositories (in order listed)"] -- | Get a list of all non-boring files and directories in the working copy. listFiles :: IO [String] listFiles = do nonboring <- restrictBoring emptyTree working <- expand =<< applyTreeFilter nonboring <$> readPlainTree "." return $ map (anchorPath "" . fst) $ list working -- | 'listUnregisteredFiles' returns the list of all non-boring unregistered -- files in the repository. listUnregisteredFiles :: IO [String] listUnregisteredFiles = do unregd <- listFiles regd <- listRegisteredFiles return $ unregd \\ regd -- (inefficient) -- | 'listRegisteredFiles' returns the list of all registered files in the repository. listRegisteredFiles :: IO [String] listRegisteredFiles = do recorded <- expand =<< withRepository [] (RepoJob readRecordedAndPending) return $ map (anchorPath "" . fst) $ list recorded optionsLatex :: [DarcsOption] -> String optionsLatex opts = "\\begin{tabular}{lll}\n"++ unlines (map optionListLatex opts)++ "\\end{tabular}\n" latexHelp :: String -> String latexHelp h = "\\begin{minipage}{7cm}\n\\raggedright\n" ++ h ++ "\\end{minipage}\n" optionListLatex :: DarcsOption -> String optionListLatex (DarcsSingleOption o) = optionLatex o optionListLatex (DarcsMultipleChoiceOption os) = unlines (map optionLatex os) optionListLatex (DarcsMutuallyExclusive os _) = unlines (map optionLatex os) optionLatex :: DarcsAtomicOption -> String optionLatex (DarcsInternalOption _) = "" optionLatex (DarcsNoArgOption a b _ h) = showShortOptions a ++ showLongOptions b ++ latexHelp h ++ "\\\\" optionLatex (DarcsArgOption a b _ arg h) = showShortOptions a ++ showLongOptions (map (++(" "++arg)) b) ++ latexHelp h ++ "\\\\" optionLatex (DarcsAbsPathOrStdOption a b _ arg h) = showShortOptions a ++ showLongOptions (map (++(" "++arg)) b) ++ latexHelp h ++ "\\\\" optionLatex (DarcsAbsPathOption a b _ arg h) = showShortOptions a ++ showLongOptions (map (++(" "++arg)) b) ++ latexHelp h ++ "\\\\" optionLatex (DarcsOptAbsPathOption a b _ _ arg h) = showShortOptions a ++ showLongOptions (map (++("[="++arg++"]")) b) ++ latexHelp h ++ "\\\\" showShortOptions :: [Char] -> String showShortOptions [] = "&" showShortOptions [c] = "\\verb!-"++[c]++"! &" showShortOptions (c:cs) = "\\verb!-"++[c]++"!,"++showShortOptions cs showLongOptions :: [String] -> String showLongOptions [] = " &" showLongOptions [s] = "\\verb!--" ++ s ++ "! &" showLongOptions (s:ss) = "\\verb!--" ++ s ++ "!,"++ showLongOptions ss setScriptsExecutableOption :: DarcsOption setScriptsExecutableOption = DarcsMultipleChoiceOption [DarcsNoArgOption [] ["set-scripts-executable"] SetScriptsExecutable "make scripts executable", DarcsNoArgOption [] ["dont-set-scripts-executable","no-set-scripts-executable"] DontSetScriptsExecutable "don't make scripts executable"] bisect :: DarcsOption bisect = DarcsSingleOption $ DarcsNoArgOption [] ["bisect"] Bisect "binary instead of linear search" relink, sibling :: DarcsOption relink = DarcsSingleOption $ DarcsNoArgOption [] ["relink"] Relink "relink random internal data to a sibling" sibling = DarcsSingleOption $ DarcsAbsPathOption [] ["sibling"] Sibling "URL" "specify a sibling directory" -- | 'flagsToSiblings' collects the contents of all @Sibling@ flags in a list of flags. flagsToSiblings :: [DarcsFlag] -> [AbsolutePath] flagsToSiblings ((Sibling s) : l) = s : (flagsToSiblings l) flagsToSiblings (_ : l) = flagsToSiblings l flagsToSiblings [] = [] reorderPatches :: DarcsOption reorderPatches = DarcsSingleOption $ DarcsNoArgOption [] ["reorder-patches"] Reorder "reorder the patches in the repository" sendmailCmd = DarcsSingleOption $ DarcsArgOption [] ["sendmail-command"] SendmailCmd "COMMAND" "specify sendmail command" environmentHelpSendmail :: ([String], [String]) environmentHelpSendmail = (["SENDMAIL"], [ "On Unix, the `darcs send' command relies on sendmail(8). The", "`--sendmail-command' or $SENDMAIL environment variable can be used to", "provide an explicit path to this program; otherwise the standard", "locations /usr/sbin/sendmail and /usr/lib/sendmail will be tried."]) -- FIXME: mention the following also: -- * sendmail(8) is not sendmail-specific; -- * nowadays, desktops often have no MTA or an unconfigured MTA -- -- which is awful, because it accepts mail but doesn't relay it; -- * in this case, can be a sendmail(8)-emulating wrapper on top of an -- MUA that sends mail directly to a smarthost; and -- * on a multi-user system without an MTA and on which you haven't -- got root, can be msmtp. -- |'getSendmailCmd' takes a list of flags and returns the sendmail command -- to be used by @darcs send@. Looks for a command specified by -- @SendmailCmd \"command\"@ in that list of flags, if any. -- This flag is present if darcs was invoked with @--sendmail-command=COMMAND@ -- Alternatively the user can set @$S@@ENDMAIL@ which will be used as a fallback if present. getSendmailCmd :: [DarcsFlag] -> IO String getSendmailCmd (SendmailCmd a:_) = return a getSendmailCmd (_:flags) = getSendmailCmd flags getSendmailCmd [] = do easy_sendmail <- firstJustIO [ maybeGetEnv "SENDMAIL" ] case easy_sendmail of Just a -> return a Nothing -> return "" files :: DarcsOption files = DarcsMultipleChoiceOption [DarcsNoArgOption [] ["files"] Files "include files in output [DEFAULT]", DarcsNoArgOption [] ["no-files"] NoFiles "don't include files in output"] directories :: DarcsOption directories = DarcsMultipleChoiceOption [DarcsNoArgOption [] ["directories"] Directories "include directories in output [DEFAULT]", DarcsNoArgOption [] ["no-directories"] NoDirectories "don't include directories in output"] pending :: DarcsOption pending = DarcsMultipleChoiceOption [DarcsNoArgOption [] ["pending"] Pending "reflect pending patches in output [DEFAULT]", DarcsNoArgOption [] ["no-pending"] NoPending "only included recorded patches in output"] nullFlag :: DarcsOption -- "null" is already taken nullFlag = DarcsSingleOption $ DarcsNoArgOption ['0'] ["null"] NullFlag "separate file names by NUL characters" -- | Set the DARCS_PATCHES and DARCS_PATCHES_XML environment variables -- with info about the given patches, for use in post-hooks. setEnvDarcsPatches :: (RepoPatch p, ApplyState p ~ Tree) => FL (PatchInfoAnd p) C(x y) -> IO () #ifndef WIN32 setEnvDarcsPatches ps = do let k = "Defining set of chosen patches" beginTedious k tediousSize k 3 finishedOneIO k "DARCS_PATCHES" setEnvCautiously "DARCS_PATCHES" (renderString $ Darcs.Patch.summary ps) finishedOneIO k "DARCS_PATCHES_XML" setEnvCautiously "DARCS_PATCHES_XML" (renderString $ text "" $$ vcat (mapFL (toXml . info) ps) $$ text "") finishedOneIO k "DARCS_FILES" setEnvCautiously "DARCS_FILES" (unlines$ listTouchedFiles ps) endTedious k -- | Set some environment variable to the given value, unless said value -- is longer than 10K characters, in which case do nothing. setEnvCautiously :: String -> String -> IO () setEnvCautiously e v | toobig (10*1024) v = return () | otherwise = setEnv e v True where toobig :: Int -> [a] -> Bool toobig 0 _ = True toobig _ [] = False toobig n (_:xs) = toobig (n-1) xs #else setEnvDarcsPatches _ = return () #endif -- | Set the DARCS_FILES environment variable to the files touched by the -- given patch, one per line, for use in post-hooks. setEnvDarcsFiles :: Patchy p => p C(x y) -> IO () #ifndef WIN32 setEnvDarcsFiles ps = setEnvCautiously "DARCS_FILES" (unlines $ listTouchedFiles ps) #else setEnvDarcsFiles _ = return () #endif posthookCmd :: DarcsOption posthookCmd = DarcsMultipleChoiceOption [DarcsArgOption [] ["posthook"] PosthookCmd "COMMAND" "specify command to run after this darcs command", DarcsNoArgOption [] ["no-posthook"] NoPosthook "don't run posthook command"] posthookPrompt :: DarcsOption posthookPrompt = DarcsMultipleChoiceOption [DarcsNoArgOption [] ["prompt-posthook"] AskPosthook "prompt before running posthook [DEFAULT]", DarcsNoArgOption [] ["run-posthook"] RunPosthook "run posthook command without prompting"] -- | 'getPosthookCmd' takes a list of flags and returns the posthook command -- specified by @PosthookCmd a@ in that list of flags, if any. getPosthookCmd :: [DarcsFlag] -> Maybe String getPosthookCmd (PosthookCmd a:_) = Just a getPosthookCmd (NoPosthook:_) = Nothing getPosthookCmd (_:flags) = getPosthookCmd flags getPosthookCmd [] = Nothing prehookCmd :: DarcsOption prehookCmd = DarcsMultipleChoiceOption [DarcsArgOption [] ["prehook"] PrehookCmd "COMMAND" "specify command to run before this darcs command", DarcsNoArgOption [] ["no-prehook"] NoPrehook "don't run prehook command"] prehookPrompt :: DarcsOption prehookPrompt = DarcsMultipleChoiceOption [DarcsNoArgOption [] ["prompt-prehook"] AskPrehook "prompt before running prehook [DEFAULT]", DarcsNoArgOption [] ["run-prehook"] RunPrehook "run prehook command without prompting"] -- | 'getPrehookCmd' takes a list of flags and returns the prehook command -- specified by @PrehookCmd a@ in that list of flags, if any. getPrehookCmd :: [DarcsFlag] -> Maybe String getPrehookCmd (PrehookCmd a:_) = Just a getPrehookCmd (NoPrehook:_) = Nothing getPrehookCmd (_:flags) = getPrehookCmd flags getPrehookCmd [] = Nothing networkOptions :: [DarcsOption] networkOptions = [ DarcsMultipleChoiceOption [ DarcsNoArgOption [] ["no-http-pipelining"] NoHTTPPipelining "disable HTTP pipelining" ] , remoteDarcs ] remoteDarcs :: DarcsOption remoteDarcs = DarcsSingleOption $ DarcsArgOption [] ["remote-darcs"] RemoteDarcsOpt "COMMAND" "name of the darcs executable on the remote server" noCache :: DarcsOption noCache = DarcsSingleOption $ DarcsNoArgOption [] ["no-cache"] NoCache "don't use patch caches" optimizePristine :: DarcsOption optimizePristine = DarcsSingleOption $ DarcsNoArgOption [] ["pristine"] OptimizePristine "optimize hashed pristine layout" optimizeHTTP :: DarcsOption optimizeHTTP = DarcsSingleOption $ DarcsNoArgOption [] ["http"] OptimizeHTTP "optimize repository for getting over network" usePacks :: DarcsOption usePacks = DarcsMultipleChoiceOption [ DarcsNoArgOption [] ["packs"] Packs "use repository packs [DEFAULT]" , DarcsNoArgOption [] ["no-packs"] NoPacks "don't use repository packs" ] umaskOption :: DarcsOption umaskOption = DarcsSingleOption $ DarcsArgOption [] ["umask"] UMask "UMASK" "specify umask to use when writing" restrictPaths :: DarcsOption restrictPaths = DarcsMultipleChoiceOption [DarcsNoArgOption [] ["restrict-paths"] RestrictPaths "don't allow darcs to touch external files or repo metadata", DarcsNoArgOption [] ["dont-restrict-paths","no-restrict-paths"] DontRestrictPaths "allow darcs to modify any file or directory (unsafe)"] allowUnrelatedRepos = DarcsSingleOption $ DarcsNoArgOption [] ["ignore-unrelated-repos"] AllowUnrelatedRepos "do not check if repositories are unrelated" justThisRepo :: DarcsOption justThisRepo = DarcsSingleOption $ DarcsNoArgOption [] ["just-this-repo"] JustThisRepo "Limit the check or repair to the current repo" check, repair, checkOrRepair :: DarcsOption check = DarcsSingleOption $ DarcsNoArgOption [] ["check"] Check "Specify checking mode" repair = DarcsSingleOption $ DarcsNoArgOption [] ["repair"] Repair "Specify repair mode" checkOrRepair = concatOptions [check, repair] -- | @'patchSelectFlag' f@ holds whenever @f@ is a way of selecting -- patches such as @PatchName n@. patchSelectFlag :: DarcsFlag -> Bool patchSelectFlag All = True patchSelectFlag (PatchName _) = True patchSelectFlag (OnePatch _) = True patchSelectFlag (SeveralPatch _) = True patchSelectFlag (AfterPatch _) = True patchSelectFlag (UpToPatch _) = True patchSelectFlag (TagName _) = True patchSelectFlag (LastN _) = True patchSelectFlag (OneTag _) = True patchSelectFlag (AfterTag _) = True patchSelectFlag (UpToTag _) = True patchSelectFlag (OnePattern _) = True patchSelectFlag (SeveralPattern _) = True patchSelectFlag (AfterPattern _) = True patchSelectFlag (UpToPattern _) = True patchSelectFlag _ = False -- | The integer corresponding to a string, if it's only composed of digits. -- Otherwise, -1. numberString :: String -> Int numberString "" = -1 numberString s = if all isDigit s then read s else (-1) makeScriptsExecutable :: Patchy p => [DarcsFlag] -> p C(x y) -> IO () makeScriptsExecutable opts p = when (SetScriptsExecutable `elem` opts) $ setScriptsExecutablePatches p darcs-2.8.4/src/Darcs/Bug.hs0000644001765600176560000000152512104371431015040 0ustar ganeshganesh-- Reporting bugs in darcs. See also impossible.h. module Darcs.Bug ( _bug, _bugDoc, _impossible, _fromJust ) where import Printer ( Doc, errorDoc, text, ($$) ) type BugStuff = (String, Int, String, String) _bug :: BugStuff -> String -> a _bug bs s = _bugDoc bs (text s) _bugDoc :: BugStuff -> Doc -> a _bugDoc bs s = errorDoc $ text ("bug at " ++ _bugLoc bs) $$ s $$ text ("See http://wiki.darcs.net/BugTracker/Reporting " ++ "for help on bug reporting.") _bugLoc :: BugStuff -> String _bugLoc (file, line, date, time) = file++":"++show line++" compiled "++time++" "++date _impossible :: BugStuff -> a _impossible bs = _bug bs $ "Impossible case at "++_bugLoc bs _fromJust :: BugStuff -> Maybe a -> a _fromJust bs mx = case mx of Nothing -> _bug bs $ "fromJust error at "++_bugLoc bs Just x -> x darcs-2.8.4/src/Darcs/ColorPrinter.hs0000644001765600176560000002571212104371431016751 0ustar ganeshganesh{-# OPTIONS -fno-warn-orphans #-} module Darcs.ColorPrinter ( errorDoc, traceDoc, assertDoc, fancyPrinters ) where import Prelude hiding ( catch ) import Control.Exception ( catch, IOException ) import Debug.Trace ( trace ) import System.IO ( stderr ) import Darcs.External (getTermNColors) import Printer (Printer, Printers, Printers'(..), Printable(..), Color(..), invisiblePrinter, (<>), (), Doc(Doc,unDoc), unsafeBothText, simplePrinter, hcat, unsafeText, unsafePackedString, renderStringWith, prefix ) import Data.Char ( isAscii, isPrint, isSpace, isControl, ord, chr ) import Data.Bits ( bit, xor ) import System.Environment ( getEnv ) import qualified Data.ByteString.Char8 as BC (unpack, any, last, spanEnd) import qualified Data.ByteString as B (null, init) import System.IO.Unsafe ( unsafePerformIO ) import System.IO ( hIsTerminalDevice, Handle ) import Text.Printf ( printf ) dollar, cr :: Doc dollar = unsafeBothText "$" cr = unsafeBothText "\r" errorDoc :: Doc -> a errorDoc = error . show traceDoc :: Doc -> a -> a traceDoc d = trace (show d) assertDoc :: Maybe Doc -> a -> a assertDoc Nothing x = x assertDoc (Just e) _ = errorDoc e instance Show Doc where show = renderStringWith (fancyPrinters stderr) -- policy -- | the 'Policy' type is a record containing the variables which control -- how 'Doc's will be rendered on some output. data Policy = Policy { poColor :: Bool -- ^ overall use of color , poEscape :: Bool -- ^ overall use of escaping , poLineColor :: Bool -- ^ overall use of colored lines (only hunks for now) , poAltColor :: Bool -- ^ alternative to color (bold, inverse) , poIsprint :: Bool -- ^ don't escape isprints , po8bit :: Bool -- ^ don't escape 8-bit chars , poNoEscX :: String -- ^ extra chars to never escape , poEscX :: String -- ^ extra chars to always escape , poTrailing :: Bool -- ^ escape trailing spaces , poCR :: Bool -- ^ ignore \r at end of lines , poSpace :: Bool -- ^ escape spaces (used with poTrailing) } {-# NOINLINE getPolicy #-} -- | 'getPolicy' returns a suitable policy for a given handle. -- The policy is chosen according to environment variables, and to the -- type of terminal which the handle represents getPolicy :: Handle -> Policy getPolicy handle = unsafePerformIO $ do isTerminal <- hIsTerminalDevice handle nColors <- if isTerminal then getTermNColors else return 0 envDontEscapeAnything <- getEnvBool "DARCS_DONT_ESCAPE_ANYTHING" envDontEscapeIsprint <- getEnvBool "DARCS_DONT_ESCAPE_ISPRINT" envUseIsprint <- getEnvBool "DARCS_USE_ISPRINT" -- for backwards-compatibility envDontEscape8bit <- getEnvBool "DARCS_DONT_ESCAPE_8BIT" envDontEscapeExtra <- getEnvString "DARCS_DONT_ESCAPE_EXTRA" envEscapeExtra <- getEnvString "DARCS_ESCAPE_EXTRA" envDontEscapeTrailingSpace <- getEnvBool "DARCS_DONT_ESCAPE_TRAILING_SPACES" envDontEscapeTrailingCR <- getEnvBool "DARCS_DONT_ESCAPE_TRAILING_CR" envDontColor <- getEnvBool "DARCS_DONT_COLOR" envAlwaysColor <- getEnvBool "DARCS_ALWAYS_COLOR" envAlternativeColor <- getEnvBool "DARCS_ALTERNATIVE_COLOR" envDoColorLines <- getEnvBool "DARCS_DO_COLOR_LINES" let haveColor = envAlwaysColor || (isTerminal && (nColors > 4)) doColor = not envDontColor && haveColor return Policy { poColor = doColor, poEscape = not envDontEscapeAnything, poLineColor= doColor && envDoColorLines, poIsprint = envDontEscapeIsprint || envUseIsprint, po8bit = envDontEscape8bit, poNoEscX = envDontEscapeExtra, poEscX = envEscapeExtra, poTrailing = not envDontEscapeTrailingSpace, poCR = envDontEscapeTrailingCR, poAltColor = haveColor && envAlternativeColor, poSpace = False } where getEnvBool s = safeGetEnv s >>= return.(/= "0") safeGetEnv s = getEnv s `catch` \(_ :: IOException) -> return "0" getEnvString s = getEnv s `catch` \(_ :: IOException) -> return "" -- printers -- | @'fancyPrinters' h@ returns a set of printers suitable for outputting -- to @h@ fancyPrinters :: Printers fancyPrinters h = let policy = getPolicy h in Printers { colorP = colorPrinter policy, invisibleP = invisiblePrinter, hiddenP = colorPrinter policy Green, userchunkP = userchunkPrinter policy, defP = escapePrinter policy, lineColorT = lineColorTrans policy, lineColorS = lineColorSuffix policy } -- | @'lineColorTrans' policy@ tries to color a Doc, according to policy po. -- That is, if @policy@ has @poLineColor@ set, then colors the line, otherwise -- does nothing. lineColorTrans :: Policy -> Color -> Doc -> Doc lineColorTrans po | poLineColor po = \c d -> prefix (setColor c) d unsafeBothText resetColor | otherwise = const id lineColorSuffix :: Policy -> [Printable] -> [Printable] lineColorSuffix po | poLineColor po = \d -> S resetColor : d | otherwise = id colorPrinter :: Policy -> Color -> Printer colorPrinter po | poColor po = \c -> unDoc . color po c . Doc . escapePrinter po{poColor=False} | otherwise = const $ escapePrinter po userchunkPrinter :: Policy -> Printer userchunkPrinter po p | not (poEscape po) = simplePrinter p | not (poTrailing po) = escapePrinter po p | otherwise = unDoc $ pr p where pr (S s) = prString s pr (Both _ ps) = prPS ps pr (PS ps) = prPS ps prPS ps = let (leadPS, trailPS) = BC.spanEnd isSpace ps in if B.null trailPS then Doc $ escapePrinter po p else Doc (escapePrinter po (PS leadPS)) <> Doc (escapePrinter po{poSpace=True} (PS trailPS)) <> markEscape po dollar prString s = let (trail',lead') = span isSpace (reverse s) lead = reverse lead' trail = reverse trail' in if (not.null) trail then Doc (escapePrinter po (S lead)) <> Doc (escapePrinter po{poSpace=True} (S trail)) <> markEscape po dollar else Doc (escapePrinter po p) escapePrinter :: Policy -> Printer escapePrinter po | (not.poEscape) po = simplePrinter | otherwise = unDoc . crepr where crepr p | poCR po && isEndCR p = epr (initPR p) <> cr | otherwise = epr p epr (S s) = escape po s epr (PS ps) = if BC.any (not.noEscape po) ps then escape po (BC.unpack ps) else unsafePackedString ps epr (Both s _) = escape po s isEndCR (S s) = not (null s) && last s == '\r' isEndCR (PS ps) = not (B.null ps) && BC.last ps == '\r' isEndCR (Both _ ps) = not (B.null ps) && BC.last ps == '\r' initPR (S s) = S $ init s initPR (PS ps) = PS $ B.init ps initPR (Both s ps) = Both (init s) (B.init ps) -- | @'escape' policy string@ escapes @string@ according to the rules -- defined in 'policy', turning it into a 'Doc'. escape :: Policy -> String -> Doc escape _ "" = unsafeText "" escape po s = hcat $ escape' s where escape' "" = [] escape' s'@(c:_) | mundane c = let (printables, rest) = span mundane s' in (unsafeText printables):(escape' rest) escape' (c:rest) = (emph . unsafeText $ quoteChar c):(escape' rest) mundane c = (noEscape po c) || (c == ' ') emph = (markEscape po) -- | @'noEscape' policy c@ tells wether @c@ will be left as-is -- when escaping according to @policy@ noEscape :: Policy -> Char -> Bool noEscape po c | poSpace po && isSpace c = False noEscape po c | c `elem` poEscX po = False noEscape po c | c `elem` poNoEscX po = True noEscape _ '\t' = True -- tabs will likely be converted to spaces noEscape _ '\n' = True noEscape po c = if (poIsprint po) then isPrint c else isPrintableAscii c || c >= '\x80' && po8bit po -- | 'isPrintableAscii' tells wether a character is a printable character -- of the ascii range. isPrintableAscii :: Char -> Bool isPrintableAscii c = isAscii c && isPrint c -- | 'quoteChar' represents a special character as a string. -- * @quoteChar '^c'@ (where @^c@ is a control character) is @"^c"@ -- * Otherwise, @quoteChar@ returns "\hex", where 'hex' is the -- hexadecimal number of the character. quoteChar :: Char -> String quoteChar c | isControl c && isPrintableAscii cHat = ['^', cHat] | otherwise = sHex where cHat = chr $ (bit 6 `xor`) $ ord c sHex = "" -- make colors and highlightings -- | @'markEscape' policy doc@ marks @doc@ with the appropriate -- marking for escaped characters according to @policy@ markEscape :: Policy -> Doc -> Doc markEscape po | poAltColor po = makeInvert | poColor po = makeColor Red | otherwise = makeAsciiart -- | @'color' policy color doc@ colors @doc@ with color @color@ if -- @policy@ is not set to use an alternative to color. In that case, -- it makes the text bold instead. color :: Policy -> Color -> Doc -> Doc color po | poAltColor po = \_ -> makeBold | otherwise = makeColor makeColor, makeColor' :: Color -> Doc -> Doc makeColor' = withColor . setColor -- memoized version of makeColor' makeColor Blue = makeColor' Blue makeColor Red = makeColor' Red makeColor Green = makeColor' Green makeColor Cyan = makeColor' Cyan makeColor Magenta = makeColor' Magenta setColor :: Color -> String setColor Blue = "\x1B[01;34m" -- bold blue setColor Red = "\x1B[01;31m" -- bold red setColor Green = "\x1B[01;32m" -- bold green setColor Cyan = "\x1B[36m" -- light cyan setColor Magenta = "\x1B[35m" -- light magenta -- | @'makeAsciiart' doc@ tries to make @doc@ (usually a -- single escaped char) stand out with the help of only plain -- ascii, i.e., no color or font style. makeAsciiart :: Doc -> Doc makeAsciiart x = unsafeBothText "[_" <> x <> unsafeBothText "_]" -- | the string to reset the terminal's color. resetColor :: String resetColor = "\x1B[00m" -- | @'withColor' color doc@ returns a colorized version of @doc@. -- @color@ is a string that represents a color, given by 'setColor' withColor :: String -> Doc -> Doc withColor c = let c' = unsafeBothText c r' = unsafeBothText resetColor in \x -> c' <> x <> r' -- | 'makeBold' boldens a doc. makeBold :: Doc -> Doc -- | 'makeInvert' returns an invert video version of a doc. makeInvert :: Doc -> Doc makeBold = withColor "\x1B[01m" makeInvert = withColor "\x1B[07m" darcs-2.8.4/src/Darcs/Commands.hs0000644001765600176560000002512312104371431016064 0ustar ganeshganesh-- Copyright (C) 2002,2003,2005 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. module Darcs.Commands ( CommandControl( CommandData, HiddenCommand, GroupName ), DarcsCommand( DarcsCommand, commandProgramName, commandName, commandHelp, commandDescription, commandBasicOptions, commandAdvancedOptions, commandCommand, commandPrereq, commandExtraArgHelp, commandExtraArgs, commandArgdefaults, commandGetArgPossibilities, SuperCommand, commandSubCommands ), commandAlias, commandStub, commandOptions, commandAlloptions, disambiguateCommands, CommandArgs(..), getCommandHelp, getCommandMiniHelp, getSubcommands, usage, usageHelper, subusage, chompNewline, extractCommands, superName, nodefaults, putInfo, putVerbose, putWarning, abortRun ) where import System.Console.GetOpt( OptDescr, usageInfo ) import Control.Monad (when, unless) import Data.List ( sort, isPrefixOf ) import Darcs.Arguments ( DarcsFlag(Quiet,Verbose, DryRun), DarcsOption, disable, help, anyVerbosity, noCache, posthookCmd, posthookPrompt, prehookCmd, prehookPrompt, optionFromDarcsOption ) import Darcs.RepoPath ( AbsolutePath, rootDirectory ) import Printer ( Doc, putDocLn, hPutDocLn, text, (<+>), errorDoc ) import System.IO ( stderr ) extractCommands, extractHiddenCommands :: [CommandControl] -> [DarcsCommand] extractCommands cs = concatMap (\x -> case x of { CommandData cmd_d -> [cmd_d]; _ -> []}) cs extractHiddenCommands cs = concatMap (\x -> case x of { HiddenCommand cmd_d -> [cmd_d]; _ -> []}) cs data CommandControl = CommandData DarcsCommand | HiddenCommand DarcsCommand | GroupName String data DarcsCommand = DarcsCommand {commandProgramName, commandName, commandHelp, commandDescription :: String, commandExtraArgs :: Int, commandExtraArgHelp :: [String], commandCommand :: [DarcsFlag] -> [String] -> IO (), commandPrereq :: [DarcsFlag] -> IO (Either String ()), commandGetArgPossibilities :: IO [String], commandArgdefaults :: [DarcsFlag] -> AbsolutePath -> [String] -> IO [String], commandBasicOptions :: [DarcsOption], commandAdvancedOptions :: [DarcsOption]} | SuperCommand {commandProgramName, commandName, commandHelp, commandDescription :: String, commandPrereq :: [DarcsFlag] -> IO (Either String ()), commandSubCommands :: [CommandControl]} commandAlloptions :: DarcsCommand -> ([DarcsOption], [DarcsOption]) commandAlloptions DarcsCommand { commandBasicOptions = opts1 , commandAdvancedOptions = opts2 } = (opts1 ++ [disable, help], anyVerbosity ++ opts2 ++ [noCache ,posthookCmd, posthookPrompt ,prehookCmd, prehookPrompt]) -- Supercommands cannot be disabled. commandAlloptions SuperCommand { } = ([help],[]) -- Obtain options suitable as input to -- System.Console.Getopt, including the --disable option (which is -- not listed explicitly in the DarcsCommand definitions). commandOptions :: AbsolutePath -> DarcsCommand -> ([OptDescr DarcsFlag], [OptDescr DarcsFlag]) commandOptions cwd c = (convert basic, convert advanced) where (basic, advanced) = commandAlloptions c convert = concatMap (optionFromDarcsOption cwd) nodefaults :: [DarcsFlag] -> AbsolutePath -> [String] -> IO [String] nodefaults _ _ xs = return xs getSubcommands :: DarcsCommand -> [CommandControl] getSubcommands c@(SuperCommand {}) = commandSubCommands c getSubcommands _ = [] commandAlias :: String -> Maybe DarcsCommand -> DarcsCommand -> DarcsCommand commandAlias n msuper c = c { commandName = n , commandDescription = "Alias for `" ++ commandProgramName c ++ " " ++ cmdName ++ "'." , commandHelp = "The `" ++ commandProgramName c ++ " " ++ n ++ "' command is an alias for " ++ "`" ++ commandProgramName c ++ " " ++ cmdName ++ "'.\n" ++ commandHelp c } where cmdName = unwords . map commandName . maybe id (:) msuper $ [ c ] commandStub :: String -> String -> String -> DarcsCommand -> DarcsCommand commandStub n h d c = c { commandName = n , commandHelp = h , commandDescription = d , commandCommand = \_ _ -> putStr h } usage :: [CommandControl] -> String usage cs = "Usage: darcs COMMAND ...\n\nCommands:\n" ++ usageHelper cs ++ "\n" ++ "Use 'darcs COMMAND --help' for help on a single command.\n" ++ "Use 'darcs --version' to see the darcs version number.\n" ++ "Use 'darcs --exact-version' to get the exact version of this darcs instance.\n" ++ "Use 'darcs help patterns' for help on patch matching.\n" ++ "Use 'darcs help environment' for help on environment variables.\n" ++ "\n" ++ "Check bug reports at http://bugs.darcs.net/\n" subusage :: DarcsCommand -> String subusage super = (usageInfo ("Usage: " ++ commandProgramName super ++ " "++commandName super++" SUBCOMMAND ... " ++ "\n\n"++ commandDescription super++ "\n\nSubcommands:\n" ++ usageHelper (getSubcommands super) ++ "\nOptions:") (optionFromDarcsOption rootDirectory help)) ++ "\n" ++ commandHelp super usageHelper :: [CommandControl] -> String usageHelper [] = "" usageHelper (HiddenCommand _:cs) = usageHelper cs usageHelper ((CommandData c):cs) = " "++padSpaces (commandName c) 15 ++ chompNewline (commandDescription c)++"\n"++usageHelper cs usageHelper ((GroupName n):cs) = "\n" ++ n ++ "\n" ++ usageHelper cs chompNewline :: String -> String chompNewline "" = "" chompNewline s = if last s == '\n' then init s else s padSpaces :: String -> Int -> String padSpaces s n = s ++ replicate (n - length s) ' ' superName :: Maybe DarcsCommand -> String superName Nothing = "" superName (Just x) = commandName x ++ " " getCommandMiniHelp :: Maybe DarcsCommand -> DarcsCommand -> String getCommandMiniHelp msuper cmd = getCommandHelpCore msuper cmd ++ "\n\nSee " ++ commandProgramName cmd ++ " help " ++ (maybe "" (\c -> commandName c ++ " ") msuper) ++ commandName cmd ++ " for details." getCommandHelp :: Maybe DarcsCommand -> DarcsCommand -> String getCommandHelp msuper cmd = unlines (reverse basicR) ++ (if null advanced then "" else "\nAdvanced options:\n" ++ unlines (reverse advancedR)) ++ "\n" ++ commandHelp cmd where -- we could just call usageInfo twice, but then the advanced -- options might not line up with the basic ones (no short flags) (advancedR, basicR) = splitAt (length advanced) $ reverse $ lines combinedUsage combinedUsage = usageInfo (getCommandHelpCore msuper cmd ++ subcommands ++ "\n\nOptions:") (basic ++ advanced) (basic, advanced) = commandOptions rootDirectory cmd subcommands = case msuper of Nothing -> case getSubcommands cmd of [] -> [] s -> "\n\nSubcommands:\n" ++ (usageHelper s) -- we don't want to list subcommands if we're already specifying them Just _ -> "" getCommandHelpCore :: Maybe DarcsCommand -> DarcsCommand -> String getCommandHelpCore msuper cmd = "Usage: " ++ commandProgramName cmd ++ " "++superName msuper++commandName cmd++ " [OPTION]... " ++ unwords args_help ++ "\n"++ commandDescription cmd where args_help = case cmd of (DarcsCommand {}) -> commandExtraArgHelp cmd _ -> [] data CommandArgs = CommandOnly DarcsCommand | SuperCommandOnly DarcsCommand | SuperCommandSub DarcsCommand DarcsCommand -- Parses a darcs command line with potentially abbreviated commands disambiguateCommands :: [CommandControl] -> String -> [String] -> Either String (CommandArgs, [String]) disambiguateCommands allcs cmd args = do c <- extract cmd allcs case (getSubcommands c, args) of ([], _) -> return (CommandOnly c, args) (_ ,[]) -> return (SuperCommandOnly c, args) (subcs, (a:as)) -> case extract a subcs of Left _ -> return (SuperCommandOnly c, args) Right sc -> return (SuperCommandSub c sc, as) extract :: String -> [CommandControl] -> Either String DarcsCommand extract cmd cs = case [ c | c <- extractCommands cs, cmd `isPrefixOf` commandName c ] ++ [ h | h <- extractHiddenCommands cs, cmd == commandName h ] of [] -> Left $ "No such command '" ++ cmd ++ "'\n" [c] -> Right c cs' -> Left $ "Ambiguous command...\n\n" ++ "The command '"++cmd++"' could mean one of:\n" ++ unwords (sort $ map commandName cs') amVerbose :: [DarcsFlag] -> Bool amVerbose = elem Verbose amQuiet :: [DarcsFlag] -> Bool amQuiet = elem Quiet putVerbose :: [DarcsFlag] -> Doc -> IO () putVerbose opts = when (amVerbose opts) . putDocLn putInfo :: [DarcsFlag] -> Doc -> IO () putInfo opts = unless (amQuiet opts) . putDocLn putWarning :: [DarcsFlag] -> Doc -> IO () putWarning opts = unless (amQuiet opts) . hPutDocLn stderr abortRun :: [DarcsFlag] -> Doc -> IO () abortRun opts msg = if DryRun `elem` opts then putInfo opts $ text "NOTE:" <+> msg else errorDoc msg darcs-2.8.4/src/Darcs/CommandsAux.hs0000644001765600176560000001125012104371431016536 0ustar ganeshganesh-- Copyright (C) 2006 Tommy Pettersson -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP #-} #include "gadts.h" module Darcs.CommandsAux ( checkPaths, maliciousPatches, hasMaliciousPath, isMaliciousPath, isMaliciousSubPath, ) where import Darcs.Flags ( DarcsFlag( RestrictPaths, DontRestrictPaths ) ) import Darcs.Patch ( Patchy, listTouchedFiles ) import Darcs.Witnesses.Ordered ( FL, mapFL ) import Darcs.Witnesses.Sealed ( Sealed2(..), unseal2 ) import Darcs.Global ( darcsdir ) import Data.List ( intersect ) import System.FilePath ( splitDirectories, isRelative ) -- * File paths {- Darcs will operate on files and directories with the invoking user's privileges. The paths for these files and directories are stored in patches, which darcs receives in various ways. Even though darcs will not create patches with "unexpected" file paths, there are no such guarantees for received patches. A spoofed patch could inflict changes on any file or directory which the invoking user is privileged to modify. There is no one single "apply" function that can check paths, so each command is responsible for not applying patches without first checking them with one of these function when appropriate. -} {- | A convenience function to call from all darcs command functions before applying any patches. It checks for malicious paths in patches, and prints an error message and fails if it finds one. -} checkPaths :: Patchy p => [DarcsFlag] -> FL p C(x y) -> IO () checkPaths opts patches = if check_is_on && or (mapFL hasMaliciousPath patches) then fail $ unlines $ ["Malicious path in patch:"] ++ (map (\s -> " " ++ s) $ concat $ mapFL maliciousPaths patches) ++ ["", "If you are sure this is ok then you can run again with the --dont-restrict-paths option."] -- TODO: print patch(es) -- NOTE: should use safe Doc printer, this can be evil chars else return () where check_is_on = DontRestrictPaths `notElem` opts || RestrictPaths `elem` opts -- | Filter out patches that contains some malicious file path maliciousPatches :: Patchy p => [Sealed2 p] -> [Sealed2 p] maliciousPatches to_check = filter (unseal2 hasMaliciousPath) to_check hasMaliciousPath :: Patchy p => p C(x y) -> Bool hasMaliciousPath patch = case maliciousPaths patch of [] -> False _ -> True maliciousPaths :: Patchy p => p C(x y) -> [String] maliciousPaths patch = let paths = listTouchedFiles patch in filter isMaliciousPath paths {-| What is a malicious path? A spoofed path is a malicious path. 1. Darcs only creates explicitly relative paths (beginning with @\".\/\"@), so any not explicitly relative path is surely spoofed. 2. Darcs normalizes paths so they never contain @\"\/..\/\"@, so paths with @\"\/..\/\"@ are surely spoofed. A path to a darcs repository's meta data can modify \"trusted\" patches or change safety defaults in that repository, so we check for paths containing @\"\/_darcs\/\"@ which is the entry to darcs meta data. To do? * How about get repositories? * Would it be worth adding a --semi-safe-paths option for allowing changes to certain preference files (_darcs\/prefs\/) in sub repositories'? -} isMaliciousPath :: String -> Bool isMaliciousPath fp = not (isExplicitlyRelative fp) || isGenerallyMalicious fp -- | Warning : this is less rigorous than isMaliciousPath -- but it's to allow for subpath representations that -- don't start with ./ isMaliciousSubPath :: String -> Bool isMaliciousSubPath fp = not (isRelative fp) || isGenerallyMalicious fp isGenerallyMalicious :: String -> Bool isGenerallyMalicious fp = splitDirectories fp `contains_any` [ "..", darcsdir ] where contains_any a b = not . null $ intersect a b isExplicitlyRelative :: String -> Bool isExplicitlyRelative ('.':'/':_) = True -- begins with "./" isExplicitlyRelative _ = False darcs-2.8.4/src/Darcs/Compat.hs0000644001765600176560000001141012104371431015540 0ustar ganeshganesh{-# OPTIONS_GHC -fno-warn-dodgy-imports #-} -- needed for GHC 7.0/7.2 {-# LANGUAGE CPP, ForeignFunctionInterface #-} module Darcs.Compat (stdoutIsAPipe, mkStdoutTemp, canonFilename, maybeRelink, atomicCreate, sloppyAtomicCreate) where import Prelude hiding ( catch ) import Darcs.Utils ( withCurrentDirectory ) #ifdef WIN32 import Darcs.Utils ( showHexLen ) import Data.Bits ( (.&.) ) import System.Random ( randomIO ) #else import Foreign.C.String ( peekCString ) #endif import Control.Monad ( unless ) import Foreign.C.Types ( CInt(..) ) import Foreign.C.String ( CString, withCString ) import Foreign.C.Error ( throwErrno, eEXIST, getErrno ) import System.Directory ( getCurrentDirectory ) import System.IO ( hFlush, stdout, stderr, hSetBuffering, BufferMode(NoBuffering) ) import System.IO.Error ( mkIOError, alreadyExistsErrorType ) import System.Posix.Files ( stdFileMode ) import System.Posix.IO ( openFd, closeFd, stdOutput, stdError, dupTo, defaultFileFlags, exclusive, OpenMode(WriteOnly) ) import System.Posix.Types ( Fd(..) ) import Darcs.SignalHandler ( stdoutIsAPipe ) canonFilename :: FilePath -> IO FilePath canonFilename f@(_:':':_) = return f -- absolute windows paths canonFilename f@('/':_) = return f canonFilename ('.':'/':f) = do cd <- getCurrentDirectory return $ cd ++ "/" ++ f canonFilename f = case reverse $ dropWhile (/='/') $ reverse f of "" -> fmap (++('/':f)) getCurrentDirectory rd -> withCurrentDirectory rd $ do fd <- getCurrentDirectory return $ fd ++ "/" ++ simplefilename where simplefilename = reverse $ takeWhile (/='/') $ reverse f #ifdef WIN32 mkstempCore :: FilePath -> IO (Fd, String) mkstempCore fp = do r <- randomIO let fp' = fp ++ (showHexLen 6 (r .&. 0xFFFFFF :: Int)) fd <- openFd fp' WriteOnly (Just stdFileMode) flags return (fd, fp') where flags = defaultFileFlags { exclusive = True } #else mkstempCore :: String -> IO (Fd, String) mkstempCore str = withCString (str++"XXXXXX") $ \cstr -> do fd <- c_mkstemp cstr if fd < 0 then throwErrno $ "Failed to create temporary file "++str else do str' <- peekCString cstr fname <- canonFilename str' return (Fd fd, fname) foreign import ccall unsafe "static stdlib.h mkstemp" c_mkstemp :: CString -> IO CInt #endif mkStdoutTemp :: String -> IO String mkStdoutTemp str = do (fd, fn) <- mkstempCore str hFlush stdout hFlush stderr -- Warning: A do-notation statement discarded a result of type Fd. _ <- dupTo fd stdOutput -- Warning: A do-notation statement discarded a result of type Fd. _ <- dupTo fd stdError hFlush stdout hFlush stderr hSetBuffering stdout NoBuffering hSetBuffering stderr NoBuffering return fn foreign import ccall unsafe "maybe_relink.h maybe_relink" maybe_relink :: CString -> CString -> CInt -> IO CInt -- Checks whether src and dst are identical. If so, makes dst into a -- link to src. Returns True if dst is a link to src (either because -- we linked it or it already was). Safe against changes to src if -- they are not in place, but not to dst. maybeRelink :: String -> String -> IO Bool maybeRelink src dst = withCString src $ \csrc -> withCString dst $ \cdst -> do rc <- maybe_relink csrc cdst 1 (case rc of 0 -> return True 1 -> return True -1 -> throwErrno ("Relinking " ++ dst) -2 -> return False -3 -> do putStrLn ("Relinking: race condition avoided on file " ++ dst) return False _ -> fail ("Unexpected situation when relinking " ++ dst)) sloppyAtomicCreate :: FilePath -> IO () sloppyAtomicCreate fp = do fd <- openFd fp WriteOnly (Just stdFileMode) flags closeFd fd where flags = defaultFileFlags { exclusive = True } atomicCreate :: FilePath -> IO () atomicCreate fp = withCString fp $ \cstr -> do rc <- c_atomic_create cstr unless (rc >= 0) $ do errno <- getErrno pwd <- getCurrentDirectory if errno == eEXIST then ioError $ mkIOError alreadyExistsErrorType ("atomicCreate in "++pwd) Nothing (Just fp) else throwErrno $ "atomicCreate "++fp++" in "++pwd foreign import ccall unsafe "atomic_create.h atomic_create" c_atomic_create :: CString -> IO CInt darcs-2.8.4/src/Darcs/Diff.hs0000644001765600176560000001270512104371431015175 0ustar ganeshganesh-- Copyright (C) 2009 Petr Rockai -- -- 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. -- | -- Module : Darcs.Diff -- Copyright : 2009 Petr Rockai -- License : MIT -- Maintainer : darcs-devel@darcs.net -- Stability : experimental -- Portability : portable module Darcs.Diff ( treeDiff ) where import qualified Data.ByteString.Lazy.Char8 as BLC import qualified Data.ByteString as BS import qualified Data.ByteString.Lazy as BL import Data.List ( sortBy ) import Storage.Hashed.Tree ( diffTrees , zipTrees , TreeItem(..) , Tree , readBlob , emptyBlob ) import Storage.Hashed.AnchoredPath( AnchoredPath, anchorPath ) import ByteStringUtils ( isFunky ) import Darcs.Patch ( PrimPatch , hunk , canonize , binary , addfile , rmfile , adddir , rmdir , invert ) import Darcs.Repository.Prefs ( FileType(..) ) import Darcs.Witnesses.Ordered ( FL(..) , (+>+) ) import Darcs.Witnesses.Sealed ( Gap(..) ) #include "gadts.h" #include "impossible.h" data Diff m = Added (TreeItem m) | Removed (TreeItem m) | Changed (TreeItem m) (TreeItem m) getDiff :: AnchoredPath -> Maybe (TreeItem m) -> Maybe (TreeItem m) -> (AnchoredPath, Diff m) getDiff p Nothing (Just t) = (p, Added t) getDiff p (Just from) (Just to) = (p, Changed from to) getDiff p (Just t) Nothing = (p, Removed t) getDiff _ Nothing Nothing = impossible -- zipTrees should never return this treeDiff :: forall m w prim . (Functor m, Monad m, Gap w, PrimPatch prim) => (FilePath -> FileType) -> Tree m -> Tree m -> m (w (FL prim)) treeDiff ft t1 t2 = do (from, to) <- diffTrees t1 t2 diffs <- mapM (uncurry diff) $ sortBy organise $ zipTrees getDiff from to return $ foldr (joinGap (+>+)) (emptyGap NilFL) diffs where -- sort into removes, changes, adds, with removes in reverse-path order -- and everything else in forward order organise :: (AnchoredPath, Diff m) -> (AnchoredPath, Diff m) -> Ordering organise (p1, Changed _ _ ) (p2, Changed _ _) = compare p1 p2 organise (p1, Added _) (p2, Added _) = compare p1 p2 organise (p1, Removed _) (p2, Removed _) = compare p2 p1 organise (_, Removed _) _ = LT organise _ (_, Removed _) = GT organise (_, Changed _ _) _ = LT organise _ (_, Changed _ _) = GT diff :: AnchoredPath -> Diff m -> m (w (FL prim)) diff _ (Changed (SubTree _) (SubTree _)) = return (emptyGap NilFL) diff p (Removed (SubTree _)) = return $ freeGap (rmdir (anchorPath "" p) :>: NilFL) diff p (Added (SubTree _)) = return $ freeGap (adddir (anchorPath "" p) :>: NilFL) diff p (Added b'@(File _)) = do diff' <- diff p (Changed (File emptyBlob) b') return $ joinGap (:>:) (freeGap (addfile (anchorPath "" p))) diff' diff p (Removed a'@(File _)) = do diff' <- diff p (Changed a' (File emptyBlob)) return $ joinGap (+>+) diff' (freeGap (rmfile (anchorPath "" p) :>: NilFL)) diff p (Changed (File a') (File b')) = do a <- readBlob a' b <- readBlob b' let path = anchorPath "" p case ft path of TextFile | no_bin a && no_bin b -> return $ text_diff path a b _ -> return $ if a /= b then freeGap (binary path (strict a) (strict b) :>: NilFL) else emptyGap NilFL diff p _ = fail $ "Missing case at path " ++ show p text_diff p a b | BL.null a && BL.null b = emptyGap NilFL | BL.null a = freeGap (diff_from_empty p b) | BL.null b = freeGap (diff_to_empty p a) | otherwise = freeGap (line_diff p (linesB a) (linesB b)) line_diff p a b = canonize (hunk p 1 a b) diff_to_empty p x | BLC.last x == '\n' = line_diff p (init $ linesB x) [] | otherwise = line_diff p (linesB x) [BS.empty] diff_from_empty p x = invert (diff_to_empty p x) no_bin = not . isFunky . strict . BL.take 4096 linesB = map strict . BLC.split '\n' strict = BS.concat . BL.toChunks darcs-2.8.4/src/Darcs/Email.hs0000644001765600176560000002534112104371431015354 0ustar ganeshganesh{-# LANGUAGE CPP #-} module Darcs.Email ( makeEmail, readEmail, formatHeader ) where import Data.Char ( digitToInt, isHexDigit, ord, intToDigit, isPrint, toUpper ) import Data.List ( isInfixOf ) import Printer ( Doc, ($$), (<+>), (<>), text, empty, packedString, renderPS) import ByteStringUtils ( packStringToUTF8, dropSpace, linesPS, betweenLinesPS ) import qualified Data.ByteString as B (ByteString, length, null, tail ,drop, head, concat, singleton ,pack, append, empty, unpack ) import qualified Data.ByteString.Char8 as BC (index, head, pack) import Data.ByteString.Internal as B (c2w, createAndTrim) import System.IO.Unsafe ( unsafePerformIO ) import Foreign.Ptr ( Ptr, plusPtr ) import Foreign.Storable ( poke ) import Data.Word ( Word8 ) import Data.Maybe ( fromMaybe ) -- lineMax is maximum number of characters in an e-mail line excluding the CRLF -- at the end. qlineMax is the number of characters in a q-encoded or -- quoted-printable-encoded line. lineMax, qlineMax :: Int lineMax = 78 qlineMax = 75 -- | Formats an e-mail header by encoding any non-ascii characters using UTF-8 -- and Q-encoding, and folding lines at appropriate points. It doesn't do -- more than that, so the header name and header value should be -- well-formatted give or take line length and encoding. So no non-ASCII -- characters within quoted-string, quoted-pair, or atom; no semantically -- meaningful signs in names; no non-ASCII characters in the header name; -- etcetera. formatHeader :: String -> String -> B.ByteString formatHeader headerName headerValue = B.append nameColon encodedValue where nameColon = B.pack (map B.c2w (headerName ++ ":")) -- space for folding encodedValue = foldAndEncode (' ':headerValue) (B.length nameColon) False False -- run through a string and encode non-ascii words and fold where appropriate. -- the integer argument is the current position in the current line. -- the string in the first argument must begin with whitespace, or be empty. foldAndEncode :: String -> Int -> Bool -> Bool -> B.ByteString foldAndEncode [] _ _ _ = B.empty foldAndEncode s p lastWordEncoded inMidWord = let newline = B.singleton 10 space = B.singleton 32 s2bs = B.pack . map B.c2w -- the twelve there is the max number of ASCII chars to encode a single -- character: 4 * 3, 4 UTF-8 bytes times 3 ASCII chars per byte safeEncChunkLength = (qlineMax - B.length encodedWordStart - B.length encodedWordEnd) `div` 12 (curSpace, afterCurSpace) = span (== ' ') s (curWord, afterCurWord) = break (== ' ') afterCurSpace qEncWord | lastWordEncoded = qEncode (curSpace ++ curWord) | otherwise = qEncode curWord mustEncode = inMidWord || any (\c -> not (isPrint c) || (ord c) > 127) curWord || length curWord > lineMax - 1 || isInfixOf "=?" curWord mustFold | mustEncode && lastWordEncoded = p + 1 + B.length qEncWord > lineMax | mustEncode = p + length curSpace + B.length qEncWord > lineMax | otherwise = p + length curSpace + length curWord > lineMax mustSplit = (B.length qEncWord > qlineMax && mustEncode) || length curWord > lineMax - 1 spaceToInsert | mustEncode && lastWordEncoded = space | otherwise = s2bs curSpace wordToInsert | mustEncode && mustSplit = qEncode (take safeEncChunkLength curWord) | mustEncode = qEncWord | otherwise = s2bs curWord doneChunk | mustFold = B.concat [newline, spaceToInsert, wordToInsert] | otherwise = B.concat [spaceToInsert, wordToInsert] (rest, nextP) | mustSplit = (drop safeEncChunkLength curWord ++ afterCurWord, qlineMax + 1) | mustEncode && mustFold = (afterCurWord, B.length spaceToInsert + B.length wordToInsert) | otherwise = (afterCurWord, p + B.length doneChunk) in B.append doneChunk (foldAndEncode rest nextP mustEncode mustSplit) -- | Turns a piece of string into a q-encoded block -- Applies q-encoding, for use in e-mail header values, as defined in RFC 2047. -- It just takes a string and builds an encoded-word from it, it does not check -- length or necessity. qEncode :: String -> B.ByteString qEncode s = B.concat [encodedWordStart, encodedString, encodedWordEnd] where encodedString = B.concat (map qEncodeChar s) encodedWordStart, encodedWordEnd :: B.ByteString encodedWordStart = B.pack (map B.c2w "=?UTF-8?Q?") encodedWordEnd = B.pack (map B.c2w "?=") -- turns a character into its q-encoded bytestring value. For most printable -- ASCII characters, that's just the singleton bytestring with that char. qEncodeChar :: Char -> B.ByteString qEncodeChar c | c == ' ' = c2bs '_' | isPrint c && not (c `elem` ['?', '=', '_']) && ord c < 128 = c2bs c | otherwise = B.concat (map qbyte (B.unpack (packStringToUTF8 [c]))) where c2bs = B.singleton . B.c2w -- qbyte turns a byte into its q-encoded "=hh" representation qbyte b = B.pack (map B.c2w ['=' ,word8ToUDigit (b `div` 16) ,word8ToUDigit (b `mod` 16) ]) word8ToUDigit :: Word8 -> Char word8ToUDigit = toUpper . intToDigit . fromIntegral -- TODO is this doing mime encoding?? qpencode :: B.ByteString -> B.ByteString qpencode s = unsafePerformIO -- Really only (3 + 2/75) * length or something in the worst case $ B.createAndTrim (4 * B.length s) (\buf -> encode s qlineMax buf 0) encode :: B.ByteString -> Int -> Ptr Word8 -> Int -> IO Int encode ps _ _ bufi | B.null ps = return bufi encode ps n buf bufi = case B.head ps of c | c == newline -> do poke (buf `plusPtr` bufi) newline encode ps' qlineMax buf (bufi+1) | n == 0 && B.length ps > 1 -> do poke (buf `plusPtr` bufi) equals poke (buf `plusPtr` (bufi+1)) newline encode ps qlineMax buf (bufi + 2) | (c == tab || c == space) -> if B.null ps' || B.head ps' == newline then do poke (buf `plusPtr` bufi) c poke (buf `plusPtr` (bufi+1)) equals poke (buf `plusPtr` (bufi+2)) newline encode ps' qlineMax buf (bufi + 3) else do poke (buf `plusPtr` bufi) c encode ps' (n - 1) buf (bufi + 1) | (c >= bang && c /= equals && c <= tilde) -> do poke (buf `plusPtr` bufi) c encode ps' (n - 1) buf (bufi + 1) | n < 3 -> encode ps 0 buf bufi | otherwise -> do let (x, y) = c `divMod` 16 h1 = intToUDigit x h2 = intToUDigit y poke (buf `plusPtr` bufi) equals poke (buf `plusPtr` (bufi+1)) h1 poke (buf `plusPtr` (bufi+2)) h2 encode ps' (n - 3) buf (bufi + 3) where ps' = B.tail ps newline = B.c2w '\n' tab = B.c2w '\t' space = B.c2w ' ' bang = B.c2w '!' tilde = B.c2w '~' equals = B.c2w '=' intToUDigit i | i >= 0 && i <= 9 = B.c2w '0' + i | i >= 10 && i <= 15 = B.c2w 'A' + i - 10 | otherwise = error $ "intToUDigit: '"++show i++"'not a digit" qpdecode :: B.ByteString -> B.ByteString qpdecode s = unsafePerformIO -- Add 1 as linesPS "\n" -> ["", ""] -> "\n\n" $ B.createAndTrim (B.length s + 1) (\buf -> decode (linesPS s) buf 0) decode :: [B.ByteString] -> Ptr Word8 -> Int -> IO Int decode [] _ bufi = return bufi decode (ps:pss) buf bufi | B.null (dropSpace ps) = do poke (buf `plusPtr` bufi) newline decode pss buf (bufi+1) | is_equals && B.length ps >= 3 && isHexDigit c1 && isHexDigit c2 = do poke (buf `plusPtr` bufi) (toWord8 $ digitToInt c1 * 16 + digitToInt c2) decode (B.drop 3 ps:pss) buf (bufi+1) | is_equals && B.null (dropSpace (B.tail ps)) = decode pss buf bufi | otherwise = do poke (buf `plusPtr` bufi) (B.head ps) decode (B.tail ps:pss) buf (bufi+1) where is_equals = BC.head ps == '=' c1 = BC.index ps 1 c2 = BC.index ps 2 newline = B.c2w '\n' toWord8 :: Int -> Word8 toWord8 = fromIntegral makeEmail :: String -> [(String, String)] -> (Maybe Doc) -> Maybe String -> Doc -> (Maybe String) -> Doc makeEmail repodir headers mcontents mcharset bundle mfilename = text "DarcsURL:" <+> text repodir $$ foldl (\m (h,v) -> m $$ (text (h ++ ":") <+> text v)) empty headers $$ text "MIME-Version: 1.0" $$ text "Content-Type: multipart/mixed; boundary=\"=_\"" $$ text "" $$ text "--=_" $$ (case mcontents of Just contents -> text ("Content-Type: text/plain; charset=\"" ++ fromMaybe "x-unknown" mcharset ++ "\"") $$ text "Content-Transfer-Encoding: quoted-printable" $$ text "" $$ packedString (qpencode (renderPS contents)) $$ text "" $$ text "--=_" Nothing -> empty) $$ text "Content-Type: text/x-darcs-patch; name=\"patch-preview.txt\"" $$ text "Content-Disposition: inline" $$ text "Content-Transfer-Encoding: quoted-printable" $$ text "Content-Description: Patch preview" $$ text "" $$ (case betweenLinesPS (BC.pack "New patches:") (BC.pack "Context:") (renderPS bundle) of Just s -> packedString $ qpencode s -- this should not happen, but in case it does, keep everything Nothing -> packedString $ qpencode $ renderPS bundle) $$ text "--=_" $$ text "Content-Type: application/x-darcs-patch" <> (case mfilename of Just filename -> text "; name=\"" <> text filename <> text "\"" Nothing -> empty) $$ text "Content-Transfer-Encoding: quoted-printable" $$ text "Content-Disposition: attachment" $$ text "Content-Description: A darcs patch for your repository!" $$ text "" $$ packedString (qpencode (renderPS bundle)) $$ text "--=_--" $$ text "" $$ text "." $$ text "" $$ text "" readEmail :: B.ByteString -> B.ByteString readEmail s = case betweenLinesPS (BC.pack "Content-Description: A darcs patch for your repository!") (BC.pack "--=_--") s of Nothing -> s -- if it wasn't an email in the first place, just pass along. Just s' -> qpdecode s' darcs-2.8.4/src/Darcs/External.hs0000644001765600176560000006157212104371431016115 0ustar ganeshganesh{-# LANGUAGE CPP, ForeignFunctionInterface #-} module Darcs.External ( backupByRenaming, backupByCopying, copyFileOrUrl, speculateFileOrUrl, copyLocal, cloneFile, cloneTree, cloneTreeExcept, fetchFilePS, fetchFileLazyPS, gzFetchFilePS, sendEmail, generateEmail, sendEmailDoc, resendEmail, signString, verifyPS, execDocPipe, execPipeIgnoreError, getTermNColors, pipeDoc, pipeDocSSH, execSSH, maybeURLCmd, Cachable(Cachable, Uncachable, MaxAge), viewDoc, viewDocWith, haveSendmail, sendmailPath, diffProgram, darcsProgram ) where import Prelude hiding ( catch ) import qualified Ratified import Data.Maybe ( isJust, isNothing, maybeToList ) import Control.Monad ( when, zipWithM_, filterM, liftM2 ) import System.Exit ( ExitCode(..) ) import System.Environment ( getEnv, getProgName ) import System.IO ( hSetBinaryMode, hPutStr, hPutStrLn, hClose, openBinaryFile, IOMode( ReadMode ), openBinaryTempFile, hIsTerminalDevice, stdout, stderr, Handle ) import System.IO.Error ( isDoesNotExistError ) import System.Posix.Files ( getSymbolicLinkStatus, isRegularFile, isDirectory ) import System.Directory ( createDirectory, getDirectoryContents, doesFileExist, doesDirectoryExist, renameFile, renameDirectory, copyFile, findExecutable ) import System.Process ( runProcess, runInteractiveProcess, waitForProcess ) import Control.Concurrent ( forkIO, newEmptyMVar, putMVar, takeMVar ) import Control.Exception.Extensible ( bracket, try, finally, catch, IOException, SomeException ) import Data.Char ( toUpper ) #if defined (HAVE_MAPI) import Foreign.C ( CString, withCString ) #endif #ifdef HAVE_MAPI import Foreign.Ptr ( nullPtr ) import Darcs.Lock ( canonFilename, writeDocBinFile ) #endif #ifdef HAVE_TERMINFO import System.Console.Terminfo( tiGetNum, setupTermFromEnv, getCapability ) #endif import System.Posix.Files ( createLink ) import System.FilePath.Posix ( (), normalise ) import Darcs.Flags ( DarcsFlag( SignAs, Sign, SignSSL, Verify, VerifySSL ) , RemoteDarcs(..) ) import Darcs.RepoPath ( AbsolutePath, toFilePath ) import Darcs.Utils ( breakCommand, getViewer, ortryrunning, ) import Progress ( withoutProgress, debugMessage ) import ByteStringUtils (gzReadFilePS, linesPS, unlinesPS) import qualified Data.ByteString as B (ByteString, empty, null, readFile ,hGetContents, writeFile, hPut, length ,take, concat, drop, isPrefixOf, singleton, append) import qualified Data.ByteString.Char8 as BC (unpack, pack) import qualified Data.ByteString.Lazy as BL import Darcs.Lock ( withTemp, withOpenTemp, tempdirLoc, removeFileMayNotExist ) import CommandLine ( parseCmd, addUrlencoded ) import URL ( copyUrl, copyUrlFirst, waitUrl ) import URL ( Cachable(..) ) import Exec ( exec, Redirect(..), withoutNonBlock ) import Darcs.Ssh ( getSSH, copySSH, SSHCmd(..) ) import Darcs.URL ( isFile, isHttpUrl, isSshUrl, splitSshUrl, SshFilePath, sshUhost ) import Darcs.Utils ( catchall ) import Printer ( Doc, Printers, putDocLnWith, hPutDoc, hPutDocLn, hPutDocWith, ($$), renderPS, simplePrinters, text, empty, packedString, vcat, renderString ) import Darcs.Email ( formatHeader ) #ifdef HAVE_HTTP import Network.Browser ( browse, request, setErrHandler, setOutHandler , setAllowRedirects ) import Network.HTTP ( RequestMethod(GET), rspCode, rspBody, rspReason , mkRequest ) import Network.URI ( parseURI, uriScheme ) #endif sendmailPath :: IO String sendmailPath = do l <- filterM doesFileExist $ liftM2 () [ "/usr/sbin", "/sbin", "/usr/lib" ] [ "sendmail" ] ex <- findExecutable "sendmail" when (isNothing ex && null l) $ fail "Cannot find the \"sendmail\" program." return $ head $ maybeToList ex ++ l diffProgram :: IO String diffProgram = do l <- filterM (fmap isJust . findExecutable) [ "gdiff", "gnudiff", "diff" ] when (null l) $ fail "Cannot find the \"diff\" program." return $ head l -- |Get the name of the darcs executable (as supplied by @getProgName@) darcsProgram :: IO String darcsProgram = getProgName -- Another option: getEnv "DARCS" `catch` \(_ :: IOException) -> getProgName backupByRenaming :: FilePath -> IO () backupByRenaming = backupBy rename where rename x y = do isD <- doesDirectoryExist x if isD then renameDirectory x y else renameFile x y backupByCopying :: FilePath -> IO () backupByCopying = backupBy copy where copy x y = do isD <- doesDirectoryExist x if isD then do createDirectory y cloneTree (normalise x) (normalise y) else copyFile x y backupBy :: (FilePath -> FilePath -> IO ()) -> FilePath -> IO () backupBy backup f = do hasBF <- doesFileExist f hasBD <- doesDirectoryExist f when (hasBF || hasBD) $ helper 0 where helper :: Int -> IO () helper i = do existsF <- doesFileExist next existsD <- doesDirectoryExist next if (existsF || existsD) then helper (i + 1) else do putStrLn $ "Backing up " ++ f ++ "(" ++ suffix ++ ")" backup f next where next = f ++ suffix suffix = ".~" ++ show i ++ "~" copyAndReadFile :: (FilePath -> IO a) -> String -> Cachable -> IO a copyAndReadFile readfn fou _ | isFile fou = readfn fou copyAndReadFile readfn fou cache = withTemp $ \t -> do copyFileOrUrl DefaultRemoteDarcs fou t cache readfn t -- | @fetchFile fileOrUrl cache@ returns the content of its argument (either a -- file or an URL). If it has to download an url, then it will use a cache as -- required by its second argument. -- -- We always use default remote darcs, since it is not fatal if the remote -- darcs does not exist or is too old -- anything that supports transfer-mode -- should do, and if not, we will fall back to SFTP or SCP. fetchFilePS :: String -> Cachable -> IO B.ByteString fetchFilePS = copyAndReadFile B.readFile -- | @fetchFileLazyPS fileOrUrl cache@ lazily reads the content of its argument -- (either a file or an URL). Warning: this function may constitute a fd leak; -- make sure to force consumption of file contents to avoid that. See -- "fetchFilePS" for details. fetchFileLazyPS :: String -> Cachable -> IO BL.ByteString #ifdef HAVE_HTTP fetchFileLazyPS x c = case parseURI x of Just x' | uriScheme x' == "http:" -> do rsp <- fmap snd . browse $ do setErrHandler . const $ return () setOutHandler . const $ return () setAllowRedirects True request $ mkRequest GET x' if rspCode rsp /= (2, 0, 0) then fail $ "fetchFileLazyPS: " ++ rspReason rsp else return $ rspBody rsp _ -> copyAndReadFile BL.readFile x c #else fetchFileLazyPS x c = copyAndReadFile BL.readFile x c #endif gzFetchFilePS :: String -> Cachable -> IO B.ByteString gzFetchFilePS = copyAndReadFile gzReadFilePS copyFileOrUrl :: RemoteDarcs -> FilePath -> FilePath -> Cachable -> IO () copyFileOrUrl _ fou out _ | isFile fou = copyLocal fou out copyFileOrUrl _ fou out cache | isHttpUrl fou = copyRemote fou out cache copyFileOrUrl rd fou out _ | isSshUrl fou = copySSH rd (splitSshUrl fou) out copyFileOrUrl _ fou _ _ = fail $ "unknown transport protocol: " ++ fou speculateFileOrUrl :: String -> FilePath -> IO () speculateFileOrUrl fou out | isHttpUrl fou = speculateRemote fou out | otherwise = return () copyLocal :: String -> FilePath -> IO () copyLocal fou out = createLink fou out `catchall` cloneFile fou out cloneTree :: FilePath -> FilePath -> IO () cloneTree = cloneTreeExcept [] cloneTreeExcept :: [FilePath] -> FilePath -> FilePath -> IO () cloneTreeExcept except source dest = do fs <- getSymbolicLinkStatus source if isDirectory fs then do fps <- getDirectoryContents source let fps' = filter (`notElem` (".":"..":except)) fps mk_source fp = source fp mk_dest fp = dest fp zipWithM_ cloneSubTree (map mk_source fps') (map mk_dest fps') else fail ("cloneTreeExcept: Bad source " ++ source) `catch` (\(_ :: IOException) -> fail ("cloneTreeExcept: Bad source " ++ source)) cloneSubTree :: FilePath -> FilePath -> IO () cloneSubTree source dest = do fs <- getSymbolicLinkStatus source if isDirectory fs then do createDirectory dest fps <- getDirectoryContents source let fps' = filter (`notElem` [".", ".."]) fps mk_source fp = source fp mk_dest fp = dest fp zipWithM_ cloneSubTree (map mk_source fps') (map mk_dest fps') else if isRegularFile fs then cloneFile source dest else fail ("cloneSubTree: Bad source "++ source) `catch` (\e -> if isDoesNotExistError e then return () else ioError e) cloneFile :: FilePath -> FilePath -> IO () cloneFile = copyFile maybeURLCmd :: String -> String -> IO(Maybe(String)) maybeURLCmd what url = do let prot = map toUpper $ takeWhile (/= ':') url fmap Just (getEnv ("DARCS_" ++ what ++ "_" ++ prot)) `catch` \(_ :: IOException) -> return Nothing speculateRemote :: String -> FilePath -> IO () -- speculations are always Cachable #if defined(HAVE_CURL) || defined(HAVE_HTTP) speculateRemote u v = do maybeget <- maybeURLCmd "GET" u case maybeget of Just _ -> return () -- can't pipeline these Nothing -> copyUrl u v Cachable #else speculateRemote u _ = maybeURLCmd "GET" u >> return () #endif copyRemote :: String -> FilePath -> Cachable -> IO () copyRemote u v cache = do maybeget <- maybeURLCmd "GET" u case maybeget of Nothing -> copyRemoteNormal u v cache Just get -> do let (cmd,args) = breakCommand get r <- exec cmd (args++[u]) (Null, File v, AsIs) when (r /= ExitSuccess) $ fail $ "(" ++ get ++ ") failed to fetch: " ++ u copyRemoteNormal :: String -> FilePath -> Cachable -> IO () copyRemoteNormal u v cache = copyUrlFirst u v cache >> waitUrl u -- | Run a command on a remote location without passing it any input or -- reading its output. Return its ExitCode execSSH :: SshFilePath -> String -> IO ExitCode execSSH remoteAddr command = do (ssh, ssh_args) <- getSSH SSH debugMessage $ unwords (ssh:ssh_args++[sshUhost remoteAddr,command]) withoutProgress $ do hid <- runProcess ssh (ssh_args++[sshUhost remoteAddr,command]) Nothing Nothing Nothing Nothing Nothing waitForProcess hid pipeDoc :: String -> [String] -> Doc -> IO ExitCode pipeDoc c args inp = withoutNonBlock $ withoutProgress $ do debugMessage $ unwords (c:args) (i,o,e,pid) <- runInteractiveProcess c args Nothing Nothing hSetBinaryMode i True hSetBinaryMode o True mvare <- newEmptyMVar -- Warning: A do-notation statement discarded a result of type GHC.Conc.ThreadId. _ <- forkIO ((Ratified.hGetContents e >>= -- ratify: immediately consumed hPutStr stderr) `finally` putMVar mvare ()) mvaro <- newEmptyMVar -- Warning: A do-notation statement discarded a result of type GHC.Conc.ThreadId. _ <- forkIO ((Ratified.hGetContents o >>= -- ratify: immediately consumed hPutStr stdout) `finally` putMVar mvaro ()) hPutDoc i inp hClose i rval <- waitForProcess pid takeMVar mvare takeMVar mvaro when (rval == ExitFailure 127) $ putStrLn $ "Command not found:\n "++ show (c:args) return rval pipeDocSSH :: SshFilePath -> [String] -> Doc -> IO ExitCode pipeDocSSH remoteAddr args input = do (ssh, ssh_args) <- getSSH SSH pipeDoc ssh (ssh_args++ (sshUhost remoteAddr:args)) input sendEmail :: String -> String -> String -> String -> String -> String -> IO () sendEmail f t s cc scmd body = sendEmailDoc f t s cc scmd Nothing (text body) generateEmail :: Handle -- ^ handle to write email to -> String -- ^ From -> String -- ^ To -> String -- ^ Subject -> String -- ^ CC -> Doc -- ^ body -> IO () generateEmail h f t s cc body = do putHeader "To" t putHeader "From" f putHeader "Subject" s when (not (null cc)) (putHeader "Cc" cc) putHeader "X-Mail-Originator" "Darcs Version Control System" hPutDocLn h body where putHeader field value = B.hPut h (B.append (formatHeader field value) newline) newline = B.singleton 10 haveSendmail :: IO Bool haveSendmail = (sendmailPath >> return True) `catch` (\(_ :: IOException) -> return False) -- | Send an email, optionally containing a patch bundle -- (more precisely, its description and the bundle itself) sendEmailDoc :: String -- ^ from -> String -- ^ to -> String -- ^ subject -> String -- ^ cc -> String -- ^ send command -> Maybe (Doc, Doc) -- ^ (content,bundle) -> Doc -- ^ body -> IO () sendEmailDoc _ "" _ "" _ _ _ = return () sendEmailDoc f "" s cc scmd mbundle body = sendEmailDoc f cc s "" scmd mbundle body sendEmailDoc f t s cc scmd mbundle body = do use_sendmail <- haveSendmail if use_sendmail || scmd /= "" then withOpenTemp $ \(h,fn) -> do generateEmail h f t s cc body hClose h withOpenTemp $ \(hat,at) -> do ftable' <- case mbundle of Just (content,bundle) -> do hPutDocLn hat $ bundle return [ ('b', renderString content) , ('a', at) ] Nothing -> return [ ('b', renderString body) ] hClose hat let ftable = [ ('t',addressOnly t),('c',cc),('f',f),('s',s) ] ++ ftable' r <- execSendmail ftable scmd fn when (r /= ExitSuccess) $ fail ("failed to send mail to: " ++ t ++ cc_list cc ++ "\nPerhaps sendmail is not configured.") #ifdef HAVE_MAPI else do r <- withCString t $ \tp -> withCString f $ \fp -> withCString cc $ \ccp -> withCString s $ \sp -> withOpenTemp $ \(h,fn) -> do hPutDoc h body hClose h writeDocBinFile "mailed_patch" body cfn <- canonFilename fn withCString cfn $ \pcfn -> c_send_email fp tp ccp sp nullPtr pcfn when (r /= 0) $ fail ("failed to send mail to: " ++ t) #else else fail $ "no mail facility (sendmail or mapi) located at configure time!" #endif where addressOnly a = case dropWhile (/= '<') a of ('<':a2) -> takeWhile (/= '>') a2 _ -> a cc_list [] = [] cc_list c = " and cc'ed " ++ c resendEmail :: String -> String -> B.ByteString -> IO () resendEmail "" _ _ = return () resendEmail t scmd body = do use_sendmail <- haveSendmail if use_sendmail || scmd /= "" then withOpenTemp $ \(h,fn) -> do hPutStrLn h $ "To: "++ t hPutStrLn h $ find_from (linesPS body) hPutStrLn h $ find_subject (linesPS body) hPutDocLn h $ fixit $ linesPS body hClose h let ftable = [('t',t)] r <- execSendmail ftable scmd fn when (r /= ExitSuccess) $ fail ("failed to send mail to: " ++ t) else #ifdef HAVE_MAPI fail "Don't know how to resend email with MAPI" #else fail "no mail facility (sendmail or mapi) located at configure time (use the sendmail-command option)!" #endif where br = BC.pack "\r" darcsurl = BC.pack "DarcsURL:" content = BC.pack "Content-" from_start = BC.pack "From:" subject_start = BC.pack "Subject:" fixit (l:ls) | B.null l = packedString B.empty $$ vcat (map packedString ls) | l == br = packedString B.empty $$ vcat (map packedString ls) | B.take 9 l == darcsurl || B.take 8 l == content = packedString l $$ fixit ls | otherwise = fixit ls fixit [] = empty find_from (l:ls) | B.take 5 l == from_start = BC.unpack l | otherwise = find_from ls find_from [] = "From: unknown" find_subject (l:ls) | B.take 8 l == subject_start = BC.unpack l | otherwise = find_subject ls find_subject [] = "Subject: (no subject)" execSendmail :: [(Char,String)] -> String -> String -> IO ExitCode execSendmail ftable scmd fn = if scmd == "" then do cmd <- sendmailPath exec cmd ["-i", "-t"] (File fn, Null, AsIs) else case parseCmd (addUrlencoded ftable) scmd of Right (arg0:opts, wantstdin) -> do let stdin = if wantstdin then File fn else Null exec arg0 opts (stdin, Null, AsIs) Left e -> fail $ ("failed to send mail, invalid sendmail-command: "++(show e)) _ -> fail $ ("failed to send mail, invalid sendmail-command") #ifdef HAVE_MAPI foreign import ccall "win32/send_email.h send_email" c_send_email :: CString -> {- sender -} CString -> {- recipient -} CString -> {- cc -} CString -> {- subject -} CString -> {- body -} CString -> {- path -} IO Int #endif execPSPipe :: String -> [String] -> B.ByteString -> IO B.ByteString execPSPipe c args ps = fmap renderPS $ execDocPipe c args $ packedString ps execDocPipe :: String -> [String] -> Doc -> IO Doc execDocPipe c args instr = withoutProgress $ do (i,o,e,pid) <- runInteractiveProcess c args Nothing Nothing -- Warning: A do-notation statement discarded a result of type GHC.Conc.ThreadId. _ <- forkIO $ hPutDoc i instr >> hClose i mvare <- newEmptyMVar -- Warning: A do-notation statement discarded a result of type GHC.Conc.ThreadId. _ <- forkIO ((Ratified.hGetContents e >>= -- ratify: immediately consumed hPutStr stderr) `finally` putMVar mvare ()) out <- B.hGetContents o rval <- waitForProcess pid takeMVar mvare case rval of ExitFailure ec ->fail $ "External program '"++c++ "' failed with exit code "++ show ec ExitSuccess -> return $ packedString out -- The following is needed for diff, which returns non-zero whenever -- the files differ. execPipeIgnoreError :: String -> [String] -> Doc -> IO Doc execPipeIgnoreError c args instr = withoutProgress $ do (i,o,e,pid) <- runInteractiveProcess c args Nothing Nothing -- Warning: A do-notation statement discarded a result of type GHC.Conc.ThreadId. _ <- forkIO $ hPutDoc i instr >> hClose i mvare <- newEmptyMVar -- Warning: A do-notation statement discarded a result of type GHC.Conc.ThreadId. _ <- forkIO ((Ratified.hGetContents e >>= -- ratify: immediately consumed hPutStr stderr) `finally` putMVar mvare ()) out <- B.hGetContents o -- Warning: A do-notation statement discarded a result of type ExitCode. _ <- waitForProcess pid takeMVar mvare return $ if B.null out then empty else packedString out signString :: [DarcsFlag] -> Doc -> IO Doc signString [] d = return d signString (Sign:_) d = signPGP [] d signString (SignAs keyid:_) d = signPGP ["--local-user", keyid] d signString (SignSSL idf:_) d = signSSL idf d signString (_:os) d = signString os d signPGP :: [String] -> Doc -> IO Doc signPGP args t = execDocPipe "gpg" ("--clearsign":args) t signSSL :: String -> Doc -> IO Doc signSSL idfile t = withTemp $ \cert -> do opensslPS ["req", "-new", "-key", idfile, "-outform", "PEM", "-days", "365"] (BC.pack "\n\n\n\n\n\n\n\n\n\n\n") >>= opensslPS ["x509", "-req", "-extensions", "v3_ca", "-signkey", idfile, "-outform", "PEM", "-days", "365"] >>= opensslPS ["x509", "-outform", "PEM"] >>= B.writeFile cert opensslDoc ["smime", "-sign", "-signer", cert, "-inkey", idfile, "-noattr", "-text"] t where opensslDoc = execDocPipe "openssl" opensslPS = execPSPipe "openssl" verifyPS :: [DarcsFlag] -> B.ByteString -> IO (Maybe B.ByteString) verifyPS [] ps = return $ Just ps verifyPS (Verify pks:_) ps = verifyGPG pks ps verifyPS (VerifySSL auks:_) ps = verifySSL auks ps verifyPS (_:os) ps = verifyPS os ps verifyGPG :: AbsolutePath -> B.ByteString -> IO (Maybe B.ByteString) verifyGPG goodkeys s = withOpenTemp $ \(th,tn) -> do B.hPut th s hClose th rval <- exec "gpg" ["--batch","--no-default-keyring", "--keyring",fix_path $ toFilePath goodkeys, "--verify"] (File tn, Null, Null) case rval of ExitSuccess -> return $ Just gpg_fixed_s _ -> return Nothing where gpg_fixed_s = let not_begin_signature x = x /= BC.pack "-----BEGIN PGP SIGNED MESSAGE-----" && x /= BC.pack "-----BEGIN PGP SIGNED MESSAGE-----\r" in unlinesPS $ map fix_line $ tail $ dropWhile not_begin_signature $ linesPS s fix_line x | B.length x < 3 = x | BC.pack "- -" `B.isPrefixOf` x = B.drop 2 x | otherwise = x #if defined(WIN32) fix_sep c | c=='/' = '\\' | otherwise = c fix_path p = map fix_sep p #else fix_path p = p #endif verifySSL :: AbsolutePath -> B.ByteString -> IO (Maybe B.ByteString) verifySSL goodkeys s = do certdata <- opensslPS ["smime", "-pk7out"] s >>= opensslPS ["pkcs7", "-print_certs"] cruddy_pk <- opensslPS ["x509", "-pubkey"] certdata let key_used = B.concat $ tail $ takeWhile (/= BC.pack"-----END PUBLIC KEY-----") $ linesPS cruddy_pk in do allowed_keys <- linesPS `fmap` B.readFile (toFilePath goodkeys) if not $ key_used `elem` allowed_keys then return Nothing -- Not an allowed key! else withTemp $ \cert -> withTemp $ \on -> withOpenTemp $ \(th,tn) -> do B.hPut th s hClose th B.writeFile cert certdata rval <- exec "openssl" ["smime", "-verify", "-CAfile", cert, "-certfile", cert] (File tn, File on, Null) case rval of ExitSuccess -> Just `fmap` B.readFile on _ -> return Nothing where opensslPS = execPSPipe "openssl" {- - This function returns number of colors supported by current terminal - or -1 if color output not supported or error occured. - Terminal type determined by TERM env. variable. -} getTermNColors :: IO Int #ifdef HAVE_TERMINFO getTermNColors = do t <- setupTermFromEnv return $ case getCapability t $ tiGetNum "colors" of Nothing -> (-1) Just x -> x #else getTermNColors = return (-1) #endif viewDoc :: Doc -> IO () viewDoc = viewDocWith simplePrinters viewDocWith :: Printers -> Doc -> IO () viewDocWith pr msg = do isTerminal <- hIsTerminalDevice stdout -- Warning: A do-notation statement discarded a result of type ExitCode. _ <- if isTerminal && lengthGreaterThan (20 :: Int) (lines $ renderString msg) then do viewerPlusArgs <- getViewer let (viewer:args) = words viewerPlusArgs pipeDocToPager viewer args pr msg `ortryrunning` pipeDocToPager "less" [] pr msg `ortryrunning` pipeDocToPager "more" [] pr msg #ifdef WIN32 `ortryrunning` pipeDocToPager "more.com" [] pr msg #endif `ortryrunning` pipeDocToPager "" [] pr msg else pipeDocToPager "" [] pr msg return () where lengthGreaterThan n _ | n <= 0 = True lengthGreaterThan _ [] = False lengthGreaterThan n (_:xs) = lengthGreaterThan (n-1) xs pipeDocToPager :: String -> [String] -> Printers -> Doc -> IO ExitCode pipeDocToPager "" _ pr inp = do putDocLnWith pr inp return ExitSuccess pipeDocToPager c args pr inp = withoutNonBlock $ withoutProgress $ do tmp <- tempdirLoc bracket (openBinaryTempFile tmp "darcs-pager") cleanup $ \(fn,fh) -> do hPutDocWith pr fh inp hClose fh bracket (openBinaryFile fn ReadMode) hClose $ \h -> do x <- do waitForProcess =<< runProcess c args Nothing Nothing (Just h) Nothing Nothing when (x == ExitFailure 127) $ putStrLn $ "Command not found:\n "++ show (c:args) return x where -- Warning: A do-notation statement discarded a result of type Either SomeException (). cleanup (f,h) = do _ <- try (hClose h) :: IO (Either SomeException ()) removeFileMayNotExist f darcs-2.8.4/src/Darcs/Flags.hs0000644001765600176560000002416412104371431015363 0ustar ganeshganesh-- Copyright (C) 2002-2004 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. module Darcs.Flags ( DarcsFlag( .. ) , Compression( .. ) , UseIndex(..) , ScanKnown(..) , RemoteDarcs(..) , compression , remoteDarcs , diffingOpts , wantExternalMerge , wantGuiPause , isInteractive , maxCount , willIgnoreTimes , willRemoveLogFile , isUnified , isNotUnified , doHappyForwarding , includeBoring , doAllowCaseOnly , doAllowWindowsReserved , doReverse , usePacks , showChangesOnlyToFiles , rollbackInWorkingDir , removeFromAmended , defaultFlag ) where import Data.List ( find ) import Data.Maybe( fromMaybe, isJust ) import Darcs.Patch.MatchData ( PatchMatch ) import Darcs.RepoPath ( AbsolutePath, AbsolutePathOrStd ) -- | The 'DarcsFlag' type is a list of all flags that can ever be -- passed to darcs, or to one of its commands. data DarcsFlag = Help | ListOptions | NoTest | Test | OnlyChangesToFiles | ChangesToAllFiles | LeaveTestDir | NoLeaveTestDir | Timings | Debug | DebugVerbose | DebugHTTP | Verbose | NormalVerbosity | Quiet | Target String | Cc String | Output AbsolutePathOrStd | OutputAutoName AbsolutePath | Subject String | InReplyTo String | Charset String | SendmailCmd String | Author String | PatchName String | OnePatch String | SeveralPatch String | AfterPatch String | UpToPatch String | TagName String | LastN Int | MaxCount Int | PatchIndexRange Int Int | NumberPatches | OneTag String | AfterTag String | UpToTag String | GenContext | Context AbsolutePath | Count | LogFile AbsolutePath | RmLogFile | DontRmLogFile | DistName String | All | Recursive | NoRecursive | Reorder | RestrictPaths | DontRestrictPaths | AskDeps | NoAskDeps | IgnoreTimes | DontIgnoreTimes | LookForAdds | NoLookForAdds | AnyOrder | CreatorHash String | Intersection | Union | Complement | Sign | SignAs String | NoSign | SignSSL String | HappyForwarding | NoHappyForwarding | Verify AbsolutePath | VerifySSL AbsolutePath | RemoteDarcsOpt String | EditDescription | NoEditDescription | Toks String | EditLongComment | NoEditLongComment | PromptLongComment | KeepDate | NoKeepDate | AllowConflicts | MarkConflicts | NoAllowConflicts | SkipConflicts | Boring | SkipBoring | AllowCaseOnly | DontAllowCaseOnly | AllowWindowsReserved | DontAllowWindowsReserved | DontGrabDeps | DontPromptForDependencies | PromptForDependencies | Compress | NoCompress | UnCompress | WorkRepoDir String | WorkRepoUrl String | RemoteRepo String | NewRepo String | Reply String | ApplyAs String | MachineReadable | HumanReadable | Pipe | Interactive | DiffCmd String | ExternalMerge String | Summary | NoSummary | PauseForGui | NoPauseForGui | Unified | NonUnified | Reverse | Forward | Complete | Lazy | FixFilePath AbsolutePath AbsolutePath | DiffFlags String | XMLOutput | ForceReplace | OnePattern PatchMatch | SeveralPattern PatchMatch | AfterPattern PatchMatch | UpToPattern PatchMatch | NonApply | NonVerify | NonForce | DryRun -- The Bool parameters are a bit of a hack so that we can tell -- whether the user explicitly set the option or not. -- A more general mechanism would be better. -- True = explicitly set by user (on command-line or in prefs/defaults), -- False = defaulted by darcs | SetDefault Bool | NoSetDefault Bool | Disable | SetScriptsExecutable | DontSetScriptsExecutable | Bisect | UseHashedInventory | UseFormat2 | UseNoWorkingDir | UseWorkingDir | NoUpdateWorking | Sibling AbsolutePath | Relink | OptimizePristine | OptimizeHTTP | UpgradeFormat | Files | NoFiles | Directories | NoDirectories | Pending | NoPending | PosthookCmd String | NoPosthook | AskPosthook | RunPosthook | PrehookCmd String | NoPrehook | AskPrehook | RunPrehook | UMask String | StoreInMemory | ApplyOnDisk | NoHTTPPipelining | Packs | NoPacks | NoCache | AllowUnrelatedRepos | Check | Repair | JustThisRepo | NullFlag | RecordRollback | NoRecordRollback | NoAmendUnrecord | AmendUnrecord deriving ( Eq, Show ) -- ADTs for selecting specific behaviour... FIXME These should be eventually -- moved out from this module, closer to where they are actually used data Compression = NoCompression | GzipCompression data UseIndex = UseIndex | IgnoreIndex data ScanKnown = ScanKnown -- ^Just files already known to darcs | ScanAll -- ^All files, i.e. look for new ones | ScanBoring -- ^All files, even boring ones data RemoteDarcs = RemoteDarcs String | DefaultRemoteDarcs compression :: [DarcsFlag] -> Compression compression f | NoCompress `elem` f = NoCompression | otherwise = GzipCompression remoteDarcs :: [DarcsFlag] -> RemoteDarcs remoteDarcs f | (x:_) <- [ c | RemoteDarcsOpt c <- f ] = RemoteDarcs x | otherwise = DefaultRemoteDarcs diffingOpts :: [DarcsFlag] -> (UseIndex, ScanKnown) diffingOpts opts = (index, scan) where index = if willIgnoreTimes opts then IgnoreIndex else UseIndex scan = if LookForAdds `elem` opts then if Boring `elem` opts then ScanBoring else ScanAll else ScanKnown wantExternalMerge :: [DarcsFlag] -> Maybe String wantExternalMerge [] = Nothing wantExternalMerge (ExternalMerge c:_) = Just c wantExternalMerge (_:fs) = wantExternalMerge fs wantGuiPause :: [DarcsFlag] -> Bool wantGuiPause fs = (hasDiffCmd || hasExternalMerge) && hasPause where hasDiffCmd = any isDiffCmd fs hasExternalMerge = isJust $ wantExternalMerge fs isDiffCmd (DiffCmd _) = True isDiffCmd _ = False hasPause = maybe True (==PauseForGui) $ find isPauseFlag $ reverse fs isPauseFlag f = (f==PauseForGui) || (f==NoPauseForGui) isInteractive :: [DarcsFlag] -> Bool isInteractive = isInteractive_ True where isInteractive_ def [] = def isInteractive_ _ (Interactive:_) = True isInteractive_ _ (All:_) = False isInteractive_ _ (DryRun:fs) = isInteractive_ False fs isInteractive_ def (_:fs) = isInteractive_ def fs maxCount :: [DarcsFlag] -> Maybe Int maxCount (MaxCount n : _) = Just n maxCount (_:xs) = maxCount xs maxCount [] = Nothing -- | @lastWord [(flag, value)] default opts@ scans @opts@ for a flag -- in the list and returns the value of the first match, or @default@ -- if none is found. -- -- We call this the \"last\" word because we assume that flags are -- *prepended* in the order they arrive, so what is first internally -- is last from the user's point of view. lastWord :: [(DarcsFlag,a)] -> a -> [DarcsFlag] -> a lastWord known_flags = foldr . flip $ \ def -> fromMaybe def . flip lookup known_flags getBoolFlag :: DarcsFlag -> DarcsFlag -> [DarcsFlag] -> Bool getBoolFlag t f = lastWord [(t, True), (f, False)] False willIgnoreTimes :: [DarcsFlag] -> Bool willIgnoreTimes = getBoolFlag IgnoreTimes DontIgnoreTimes willRemoveLogFile :: [DarcsFlag] -> Bool willRemoveLogFile = getBoolFlag RmLogFile DontRmLogFile isUnified :: [DarcsFlag] -> Bool isUnified = getBoolFlag Unified NonUnified isNotUnified :: [DarcsFlag] -> Bool isNotUnified = getBoolFlag NonUnified Unified doHappyForwarding :: [DarcsFlag] -> Bool doHappyForwarding = getBoolFlag HappyForwarding NoHappyForwarding includeBoring :: [DarcsFlag] -> Bool includeBoring = getBoolFlag Boring SkipBoring doAllowCaseOnly :: [DarcsFlag] -> Bool doAllowCaseOnly = getBoolFlag AllowCaseOnly DontAllowCaseOnly doAllowWindowsReserved :: [DarcsFlag] -> Bool doAllowWindowsReserved = getBoolFlag AllowWindowsReserved DontAllowWindowsReserved doReverse :: [DarcsFlag] -> Bool doReverse = getBoolFlag Reverse Forward usePacks :: [DarcsFlag] -> Bool usePacks = getBoolFlag Packs NoPacks showChangesOnlyToFiles :: [DarcsFlag] -> Bool showChangesOnlyToFiles = getBoolFlag OnlyChangesToFiles ChangesToAllFiles -- | Set flags to a default value, but only one has not already been provided defaultFlag :: [DarcsFlag] -- ^ distractors -> DarcsFlag -- ^ default -> [DarcsFlag] -- ^ flags -> [DarcsFlag] -- ^ updated flags defaultFlag alts def flags = if any (`elem` flags) alts then flags else def : flags rollbackInWorkingDir :: [DarcsFlag] -> Bool rollbackInWorkingDir = getBoolFlag NoRecordRollback RecordRollback removeFromAmended :: [DarcsFlag] -> Bool removeFromAmended = getBoolFlag AmendUnrecord NoAmendUnrecord darcs-2.8.4/src/Darcs/Global.hs0000644001765600176560000001747712104371431015540 0ustar ganeshganesh-- Copyright (C) 2005 Tomasz Zielonka -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP #-} -- | -- Module : Darcs.Global -- Copyright : 2005 Tomasz Zielonka -- License : GPL -- Maintainer : darcs-devel@darcs.net -- Stability : experimental -- Portability : portable -- -- This was originally Tomasz Zielonka's AtExit module, slightly generalised -- to include global variables. Here, we attempt to cover broad, global -- features, such as exit handlers. These features slightly break the Haskellian -- purity of darcs, in favour of programming convenience. module Darcs.Global ( atexit , withAtexit , SshSettings(..) , defaultSsh , timingsMode , setTimingsMode , whenDebugMode , withDebugMode , setDebugMode , debugMessage , debugFail , putTiming , addCRCWarning , getCRCWarnings , resetCRCWarnings , addBadSource , getBadSourcesList , isBadSource , darcsdir , isReachableSource , addReachableSource , windows ) where import Control.Applicative ( (<$>), (<*>) ) import Control.Monad ( when ) import Control.Concurrent.MVar import Control.Exception.Extensible ( bracket_, catch, catchJust, SomeException , block, unblock ) import Data.IORef ( IORef, newIORef, readIORef, writeIORef ) import Data.IORef ( modifyIORef ) import Data.List ( isPrefixOf ) import System.Info ( os ) import System.IO.Unsafe (unsafePerformIO) import System.IO (hPutStrLn, hPutStr, stderr) import System.IO.Error ( ioeGetErrorType, isDoesNotExistErrorType ) import System.Process ( readProcessWithExitCode ) import System.Time ( calendarTimeToString, toCalendarTime, getClockTime ) import System.Environment ( getEnv ) import Prelude hiding (catch) windows :: Bool windows = "mingw" `isPrefixOf` os atexitActions :: MVar (Maybe [IO ()]) atexitActions = unsafePerformIO (newMVar (Just [])) {-# NOINLINE atexitActions #-} -- | Registers an IO action to run just before darcs exits. Useful for removing -- temporary files and directories, for example. Referenced in Issue1914. atexit :: IO () -> IO () atexit action = modifyMVar_ atexitActions $ \ml -> case ml of Just l -> return (Just (action : l)) Nothing -> do hPutStrLn stderr "It's too late to use atexit" return Nothing withAtexit :: IO a -> IO a withAtexit prog = bracket_ (return ()) exit prog where exit = block $ do Just actions <- swapMVar atexitActions Nothing -- from now on atexit will not register new actions mapM_ runAction actions runAction action = catch (unblock action) $ \(exn :: SomeException) -> do hPutStrLn stderr $ "Exception thrown by an atexit registered action:" hPutStrLn stderr $ show exn -- Write-once-read-many global variables make it easier to implement flags, such -- as --no-ssh-cm. Using global variables reduces the number of parameters that -- we have to pass around, but it is rather unsafe and should be used sparingly. _debugMode :: IORef Bool _debugMode = unsafePerformIO $ newIORef False {-# NOINLINE _debugMode #-} setDebugMode :: IO () setDebugMode = writeIORef _debugMode True whenDebugMode :: IO () -> IO () whenDebugMode j = do b <- readIORef _debugMode when b j withDebugMode :: (Bool -> IO a) -> IO a withDebugMode j = readIORef _debugMode >>= j debugMessage :: String -> IO () debugMessage m = whenDebugMode $ do putTiming; hPutStrLn stderr m debugFail :: String -> IO a debugFail m = debugMessage m >> fail m putTiming :: IO () putTiming = when timingsMode $ do t <- getClockTime >>= toCalendarTime hPutStr stderr (calendarTimeToString t++": ") _timingsMode :: IORef Bool _timingsMode = unsafePerformIO $ newIORef False {-# NOINLINE _timingsMode #-} setTimingsMode :: IO () setTimingsMode = writeIORef _timingsMode True timingsMode :: Bool timingsMode = unsafePerformIO $ readIORef _timingsMode {-# NOINLINE timingsMode #-} data SshSettings = SshSettings { ssh :: String , scp :: String , sftp :: String } deriving (Show, Eq) _defaultSsh :: IORef SshSettings _defaultSsh = unsafePerformIO $ newIORef =<< detectSsh -- | Expected properties: -- -- * only ever runs once in the lifetime of the program -- * environment variables override all -- * tries Putty first on Windows -- * falls back to plain old ssh detectSsh :: IO SshSettings detectSsh = do whenDebugMode (putStrLn "Detecting SSH settings") vanilla <- if windows then do plinkStr <- (snd3 <$> readProcessWithExitCode "plink" [] "") `catch` \(e :: SomeException) -> return (show e) whenDebugMode $ putStrLn $ "SSH settings (plink): " ++ (concat . take 1 . lines $ plinkStr) if "PuTTY" `isPrefixOf` plinkStr then return (SshSettings "plink" "pscp -q" "psftp") else return rawVanilla else return rawVanilla settings <- SshSettings <$> fromEnv (ssh vanilla) "DARCS_SSH" <*> fromEnv (scp vanilla) "DARCS_SCP" <*> fromEnv (sftp vanilla) "DARCS_SFTP" whenDebugMode (putStrLn $ "SSH settings: " ++ show settings) return settings where snd3 (_, x, _) = x rawVanilla = SshSettings "ssh" "scp -q" "sftp" fromEnv :: String -> String -> IO String fromEnv d v = catchJust notFound (getEnv v) (const (return d)) notFound e = if isDoesNotExistErrorType (ioeGetErrorType e) then Just () else Nothing defaultSsh :: SshSettings defaultSsh = unsafePerformIO $ readIORef _defaultSsh type CRCWarningList = [FilePath] _crcWarningList :: IORef CRCWarningList _crcWarningList = unsafePerformIO $ newIORef [] {-# NOINLINE _crcWarningList #-} addCRCWarning :: FilePath -> IO () addCRCWarning fp = modifyIORef _crcWarningList (fp:) getCRCWarnings :: IO [FilePath] getCRCWarnings = readIORef _crcWarningList resetCRCWarnings :: IO () resetCRCWarnings = writeIORef _crcWarningList [] _badSourcesList :: IORef [String] _badSourcesList = unsafePerformIO $ newIORef [] {- NOINLINE _badSourcesList -} addBadSource :: String -> IO () addBadSource cache = modifyIORef _badSourcesList (cache:) getBadSourcesList :: IO [String] getBadSourcesList = readIORef _badSourcesList isBadSource :: IO (String -> Bool) isBadSource = do badSources <- getBadSourcesList return (`elem` badSources) _reachableSourcesList :: IORef [String] _reachableSourcesList = unsafePerformIO $ newIORef [] {- NOINLINE _reachableSourcesList -} addReachableSource :: String -> IO () addReachableSource src = modifyIORef _reachableSourcesList (src:) getReachableSources :: IO [String] getReachableSources = readIORef _reachableSourcesList isReachableSource :: IO (String -> Bool) isReachableSource = do reachableSources <- getReachableSources return (`elem` reachableSources) darcsdir :: String darcsdir = "_darcs" darcs-2.8.4/src/Darcs/IO.hs0000644001765600176560000002037712104371431014640 0ustar ganeshganesh-- Copyright (C) 2005 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# OPTIONS_GHC -fno-warn-orphans #-} {-# LANGUAGE MultiParamTypeClasses #-} module Darcs.IO ( runTolerantly, runSilently ) where import Prelude hiding ( catch ) import Data.Char ( toLower ) import Data.List ( isSuffixOf ) import System.IO.Error ( isDoesNotExistError, isPermissionError ) import Control.Exception.Extensible ( catch, SomeException, IOException ) import Control.Monad.Error import System.Directory ( createDirectory, removeDirectory, removeFile, renameFile, renameDirectory, doesDirectoryExist, doesFileExist ) import Darcs.Repository.Prefs( changePrefval ) import qualified Data.ByteString as B (empty, null, readFile) import Darcs.Utils ( prettyException ) import Darcs.External ( backupByCopying, backupByRenaming ) import Darcs.Patch.FileName ( FileName, fn2fp ) import Darcs.Lock ( writeAtomicFilePS ) import Darcs.Patch.ApplyMonad( ApplyMonad(..) ) import Storage.Hashed.Tree( Tree ) instance ApplyMonad IO Tree where type ApplyMonadBase IO = IO mDoesDirectoryExist = doesDirectoryExist . fn2fp mChangePref = changePrefval mModifyFilePS f j = B.readFile (fn2fp f) >>= j >>= writeAtomicFilePS (fn2fp f) mCreateDirectory = createDirectory . fn2fp mCreateFile f = do exf <- doesFileExist (fn2fp f) if exf then fail $ "File '"++fn2fp f++"' already exists!" else do exd <- doesDirectoryExist $ fn2fp f if exd then fail $ "File '"++fn2fp f++"' already exists!" else writeAtomicFilePS (fn2fp f) B.empty mRemoveFile f = do let fp = fn2fp f x <- B.readFile fp when (not $ B.null x) $ fail $ "Cannot remove non-empty file "++fp removeFile fp mRemoveDirectory = removeDirectory . fn2fp mRename a b = catch (renameDirectory x y `mplus` renameFile x y) -- We need to catch does not exist errors, since older -- versions of darcs allowed users to rename nonexistent -- files. :( (\e -> if isDoesNotExistError e then return () else ioError e) where x = fn2fp a y = fn2fp b class Monad m => TolerantMonad m where warning :: IO () -> m () runIO :: m a -> IO a runTM :: IO a -> m a newtype TolerantIO a = TIO { runTolerantly :: IO a } instance TolerantMonad TolerantIO where warning io = TIO $ io `catch` \e -> putStrLn $ "Warning: " ++ prettyException e runIO (TIO io) = io runTM io = TIO io newtype SilentIO a = SIO { runSilently :: IO a } instance TolerantMonad SilentIO where warning io = SIO $ io `catch` \(_ :: SomeException) -> return () runIO (SIO io) = io runTM io = SIO io -- NOTE: The following instance declarations are duplicated merely to avoid -- enabling -fallow-undecidable-instances. If we used -- -fallow-undecidable-instances, we would write instead: -- instance TolerantMonad m => Monad m where -- ... -- etc. instance Functor TolerantIO where fmap f m = m >>= return . f instance Monad TolerantIO where f >>= g = runTM $ runIO f >>= runIO . g f >> g = runTM $ runIO f >> runIO g fail s = runTM $ fail s return x = runTM $ return x instance Functor SilentIO where fmap f m = m >>= return . f instance Monad SilentIO where f >>= g = runTM $ runIO f >>= runIO . g f >> g = runTM $ runIO f >> runIO g fail s = runTM $ fail s return x = runTM $ return x instance ApplyMonad TolerantIO Tree where type ApplyMonadBase TolerantIO = IO mDoesDirectoryExist d = runTM $ mDoesDirectoryExist d mReadFilePS f = runTM $ mReadFilePS f mChangePref a b c = warning $ mChangePref a b c mModifyFilePS f j = warning $ mModifyFilePS f (runIO . j) mCreateFile f = warning $ backup f >> mCreateFile f mCreateDirectory d = warning $ backup d >> mCreateDirectory d mRemoveFile f = warning $ mRemoveFile f mRemoveDirectory d = warning $ catch (mRemoveDirectory d) (\(e :: IOException) -> if "(Directory not empty)" `isSuffixOf` show e then ioError $ userError $ "Not deleting " ++ fn2fp d ++ " because it is not empty." else ioError $ userError $ "Not deleting " ++ fn2fp d ++ " because:\n" ++ show e) mRename a b = warning $ catch (let do_backup = if (map toLower x == map toLower y) then backupByCopying (fn2fp b) -- avoid making the original vanish else backupByRenaming (fn2fp b) in do_backup >> mRename a b) (\e -> case () of _ | isPermissionError e -> ioError $ userError $ couldNotRename ++ "." | isDoesNotExistError e -> ioError $ userError $ couldNotRename ++ " because " ++ x ++ " does not exist." | otherwise -> ioError e ) where x = fn2fp a y = fn2fp b couldNotRename = "Could not rename " ++ x ++ " to " ++ y instance ApplyMonad SilentIO Tree where type ApplyMonadBase SilentIO = IO mDoesDirectoryExist d = runTM $ mDoesDirectoryExist d mReadFilePS f = runTM $ mReadFilePS f mChangePref a b c = warning $ mChangePref a b c mModifyFilePS f j = warning $ mModifyFilePS f (runIO . j) mCreateFile f = warning $ backup f >> mCreateFile f mCreateDirectory d = warning $ backup d >> mCreateDirectory d mRemoveFile f = warning $ mRemoveFile f mRemoveDirectory d = warning $ catch (mRemoveDirectory d) (\(e :: SomeException) -> if "(Directory not empty)" `isSuffixOf` show e then ioError $ userError $ "Not deleting " ++ fn2fp d ++ " because it is not empty." else ioError $ userError $ "Not deleting " ++ fn2fp d ++ " because:\n" ++ show e) mRename a b = warning $ catch (let do_backup = if (map toLower x == map toLower y) then backupByCopying (fn2fp b) -- avoid making the original vanish else backupByRenaming (fn2fp b) in do_backup >> mRename a b) (\e -> case () of _ | isPermissionError e -> ioError $ userError $ couldNotRename ++ "." | isDoesNotExistError e -> ioError $ userError $ couldNotRename ++ " because " ++ x ++ " does not exist." | otherwise -> ioError e ) where x = fn2fp a y = fn2fp b couldNotRename = "Could not rename " ++ x ++ " to " ++ y backup :: FileName -> IO () backup f = backupByRenaming (fn2fp f) darcs-2.8.4/src/Darcs/Lock.hs0000644001765600176560000003631412104371431015217 0ustar ganeshganesh-- Copyright (C) 2003 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP, ForeignFunctionInterface #-} module Darcs.Lock ( withLock, withLockCanFail, withTemp, withOpenTemp, withStdoutTemp, withTempDir, withPermDir, withDelayedDir, withNamedTemp, writeToFile, appendToFile, writeBinFile, writeLocaleFile, writeDocBinFile, appendBinFile, appendDocBinFile, readBinFile, readLocaleFile, readDocBinFile, writeAtomicFilePS, gzWriteAtomicFilePS, gzWriteAtomicFilePSs, gzWriteDocFile, rmRecursive, removeFileMayNotExist, canonFilename, maybeRelink, worldReadableTemp, tempdirLoc, editText, environmentHelpTmpdir, environmentHelpKeepTmpdir ) where import Prelude hiding ( catch ) import Data.List ( inits ) import Data.Maybe ( isJust, listToMaybe ) import System.Exit ( exitWith, ExitCode(..) ) import System.IO ( openBinaryFile, openBinaryTempFile, hClose, hPutStr, Handle, IOMode(WriteMode, AppendMode), hFlush, stdout ) import System.IO.Error ( isDoesNotExistError, isAlreadyExistsError ) import Control.Exception.Extensible ( bracket, throwIO, catch, try, SomeException ) import System.Directory ( removeFile, removeDirectory, doesFileExist, doesDirectoryExist, getDirectoryContents, createDirectory, getTemporaryDirectory, ) import System.FilePath.Posix ( splitDirectories ) import Workaround ( renameFile ) import Darcs.Utils ( withCurrentDirectory, maybeGetEnv, firstJustIO, runEditor ) import Control.Monad ( unless, when ) import Darcs.URL ( isRelative ) import Darcs.Utils ( catchall, addToErrorLoc ) import Darcs.RepoPath ( AbsolutePath, FilePathLike, toFilePath, getCurrentDirectory, setCurrentDirectory ) import ByteStringUtils ( gzWriteFilePSs, decodeLocale, encodeLocale ) import qualified Data.ByteString as B (null, readFile, writeFile, hPut, ByteString) import qualified Data.ByteString.Char8 as BC (unpack) import Darcs.SignalHandler ( withSignalsBlocked ) import Printer ( Doc, hPutDoc, packedString, empty, renderPSs ) import Darcs.Global ( atexit, darcsdir ) import Darcs.Compat ( mkStdoutTemp, canonFilename, maybeRelink, atomicCreate, sloppyAtomicCreate ) import System.Posix.Files ( getSymbolicLinkStatus, isDirectory, fileMode, getFileStatus, setFileMode ) import System.Posix ( sleep ) #include "impossible.h" withLock :: String -> IO a -> IO a releaseLock :: String -> IO () withLock s job = bracket (getlock s 30) releaseLock (\_ -> job) -- | Tries to perform some task if it can obtain the lock, -- Otherwise, just gives up without doing the task withLockCanFail :: String -> IO a -> IO (Either () a) withLockCanFail s job = bracket (takeLock s) (\l -> when l $ releaseLock s) (\l -> if l then job >>= (return.Right) else return $ Left ()) getlock :: String -> Int -> IO String getlock l 0 = do putStrLn $ "Couldn't get lock "++l exitWith $ ExitFailure 1 getlock lbad tl = do l <- canonFilename lbad gotit <- takeLock l if gotit then return l else do putStrLn $ "Waiting for lock "++l hFlush stdout -- for Windows done <- sleep 2 if done == 0 then getlock l (tl - 1) else getlock l 0 removeFileMayNotExist :: FilePathLike p => p -> IO () removeFileMayNotExist f = catchNonExistence (removeFile $ toFilePath f) () catchNonExistence :: IO a -> a -> IO a catchNonExistence job nonexistval = catch job $ \e -> if isDoesNotExistError e then return nonexistval else ioError e releaseLock s = removeFileMayNotExist s takeLock :: FilePathLike p => p -> IO Bool takeLock fp = do atomicCreate $ toFilePath fp return True `catch` \e -> if isAlreadyExistsError e then return False else do pwd <- getCurrentDirectory throwIO $ addToErrorLoc e ("takeLock "++toFilePath fp++" in "++toFilePath pwd) takeFile :: FilePath -> IO Bool takeFile fp = do sloppyAtomicCreate fp return True `catch` \e -> if isAlreadyExistsError e then return False else do pwd <- getCurrentDirectory throwIO $ addToErrorLoc e ("takeFile "++fp++" in "++toFilePath pwd) -- |'withTemp' safely creates an empty file (not open for writing) and -- returns its name. -- -- The temp file operations are rather similar to the locking operations, in -- that they both should always try to clean up, so exitWith causes trouble. withTemp :: (String -> IO a) -> IO a withTemp = bracket get_empty_file removeFileMayNotExist where get_empty_file = do (f,h) <- openBinaryTempFile "." "darcs" hClose h return f -- |'withOpenTemp' creates a temporary file, and opens it. -- Both of them run their argument and then delete the file. Also, -- both of them (to my knowledge) are not susceptible to race conditions on -- the temporary file (as long as you never delete the temporary file; that -- would reintroduce a race condition). withOpenTemp :: ((Handle, String) -> IO a) -> IO a withOpenTemp = bracket get_empty_file cleanup -- Warning: A do-notation statement discarded a result of type Either SomeException (). where cleanup (h,f) = do _ <- try (hClose h) :: IO (Either SomeException ()) removeFileMayNotExist f get_empty_file = invert `fmap` openBinaryTempFile "." "darcs" invert (a,b) = (b,a) withStdoutTemp :: (String -> IO a) -> IO a withStdoutTemp = bracket (mkStdoutTemp "stdout_") removeFileMayNotExist tempdirLoc :: IO FilePath tempdirLoc = firstJustIO [ readBinFile (darcsdir++"/prefs/tmpdir") >>= return . Just . head.words >>= chkdir, maybeGetEnv "DARCS_TMPDIR" >>= chkdir, getTemporaryDirectory >>= chkdir . Just, getCurrentDirectorySansDarcs, return $ Just "." -- always returns a Just ] >>= return . fromJust where chkdir Nothing = return Nothing chkdir (Just d) = doesDirectoryExist d >>= return . \e -> if e then Just (d++"/") else Nothing environmentHelpTmpdir :: ([String], [String]) environmentHelpTmpdir = (["DARCS_TMPDIR", "TMPDIR"], [ "Darcs often creates temporary directories. For example, the `darcs", "diff' command creates two for the working trees to be diffed. By", "default temporary directories are created in /tmp, or if that doesn't", "exist, in _darcs (within the current repo). This can be overridden by", "specifying some other directory in the file _darcs/prefs/tmpdir or the", "environment variable $DARCS_TMPDIR or $TMPDIR."]) getCurrentDirectorySansDarcs :: IO (Maybe FilePath) getCurrentDirectorySansDarcs = do c <- getCurrentDirectory return $ listToMaybe $ drop 5 $ reverse $ takeWhile no_darcs $ inits $ toFilePath c where no_darcs x = not $ darcsdir `elem` splitDirectories x data WithDirKind = Perm | Temp | Delayed withDir :: WithDirKind -> String -> (AbsolutePath -> IO a) -> IO a withDir _ "" _ = bug "withDir called with empty directory name" withDir kind abs_or_relative_name job = do absolute_name <- if isRelative abs_or_relative_name then fmap (++ abs_or_relative_name) tempdirLoc else return abs_or_relative_name formerdir <- getCurrentDirectory bracket (create_directory absolute_name 0) (\dir -> do setCurrentDirectory formerdir k <- keep_tmpdir unless k $ do case kind of Perm -> return () Temp -> rmRecursive (toFilePath dir) Delayed -> atexit $ rmRecursive (toFilePath dir)) job where newname name 0 = name newname name n = name ++ "-" ++ show n create_directory :: FilePath -> Int -> IO AbsolutePath create_directory name n = do createDirectory $ newname name n setCurrentDirectory $ newname name n getCurrentDirectory `catch` (\e -> if isAlreadyExistsError e then create_directory name (n+1) else throwIO e) keep_tmpdir = isJust `fmap` maybeGetEnv "DARCS_KEEP_TMPDIR" environmentHelpKeepTmpdir :: ([String], [String]) environmentHelpKeepTmpdir = (["DARCS_KEEP_TMPDIR"],[ "If the environment variable DARCS_KEEP_TMPDIR is defined, darcs will", "not remove the temporary directories it creates. This is intended", "primarily for debugging Darcs itself, but it can also be useful, for", "example, to determine why your test preference (see `darcs setpref')", "is failing when you run `darcs record', but working when run manually."]) -- |'withPermDir' is like 'withTempDir', except that it doesn't -- delete the directory afterwards. withPermDir :: String -> (AbsolutePath -> IO a) -> IO a withPermDir = withDir Perm -- |'withTempDir' creates an empty directory and then removes it when it -- is no longer needed. withTempDir creates a temporary directory. The -- location of that directory is determined by the contents of -- _darcs/prefs/tmpdir, if it exists, otherwise by @$DARCS_TMPDIR@, and if -- that doesn't exist then whatever your operating system considers to be a -- a temporary directory (e.g. @$TMPDIR@ under Unix, @$TEMP@ under -- Windows). -- -- If none of those exist it creates the temporary directory -- in the current directory, unless the current directory is under a _darcs -- directory, in which case the temporary directory in the parent of the highest -- _darcs directory to avoid accidentally corrupting darcs's internals. -- This should not fail, but if it does indeed fail, we go ahead and use the -- current directory anyway. If @$DARCS_KEEP_TMPDIR@ variable is set -- temporary directory is not removed, this can be useful for debugging. withTempDir :: String -> (AbsolutePath -> IO a) -> IO a withTempDir = withDir Temp withDelayedDir :: String -> (AbsolutePath -> IO a) -> IO a withDelayedDir = withDir Delayed doesDirectoryReallyExist :: FilePath -> IO Bool doesDirectoryReallyExist f = catchNonExistence (isDirectory `fmap` getSymbolicLinkStatus f) False rmRecursive :: FilePath -> IO () rmRecursive d = do isd <- doesDirectoryReallyExist d if not isd then removeFile d else do conts <- actual_dir_contents withCurrentDirectory d $ mapM_ rmRecursive conts removeDirectory d where actual_dir_contents = -- doesn't include . or .. do c <- getDirectoryContents d return $ filter (/=".") $ filter (/="..") c worldReadableTemp :: String -> IO String worldReadableTemp f = wrt 0 where wrt :: Int -> IO String wrt 100 = fail $ "Failure creating temp named "++f wrt n = let f_new = f++"-"++show n in do ok <- takeFile f_new if ok then return f_new else wrt (n+1) withNamedTemp :: String -> (String -> IO a) -> IO a withNamedTemp n = bracket get_empty_file removeFileMayNotExist where get_empty_file = worldReadableTemp n editText :: String -> B.ByteString -> IO B.ByteString editText desc txt = withNamedTemp desc $ \f -> do B.writeFile f txt -- Warning: A do-notation statement discarded a result of type ExitCode. _ <- runEditor f B.readFile f readBinFile :: FilePathLike p => p -> IO String readBinFile = fmap BC.unpack . B.readFile . toFilePath -- | Reads a file. Differs from readBinFile in that it interprets the file in -- the current locale instead of as ISO-8859-1. readLocaleFile :: FilePathLike p => p -> IO String readLocaleFile f = decodeLocale `fmap` B.readFile (toFilePath f) readDocBinFile :: FilePathLike p => p -> IO Doc readDocBinFile fp = do ps <- B.readFile $ toFilePath fp return $ if B.null ps then empty else packedString ps appendBinFile :: FilePathLike p => p -> String -> IO () appendBinFile f s = appendToFile f $ \h -> hPutStr h s appendDocBinFile :: FilePathLike p => p -> Doc -> IO () appendDocBinFile f d = appendToFile f $ \h -> hPutDoc h d writeBinFile :: FilePathLike p => p -> String -> IO () writeBinFile f s = writeToFile f $ \h -> hPutStr h s -- | Writes a file. Differs from writeBinFile in that it writes the string -- encoded with the current locale instead of what GHC thinks is right. writeLocaleFile :: FilePathLike p => p -> String -> IO () writeLocaleFile f s = writeToFile f $ \h -> B.hPut h (encodeLocale s) writeDocBinFile :: FilePathLike p => p -> Doc -> IO () writeDocBinFile f d = writeToFile f $ \h -> hPutDoc h d writeAtomicFilePS :: FilePathLike p => p -> B.ByteString -> IO () writeAtomicFilePS f ps = writeToFile f $ \h -> B.hPut h ps gzWriteAtomicFilePS :: FilePathLike p => p -> B.ByteString -> IO () gzWriteAtomicFilePS f ps = gzWriteAtomicFilePSs f [ps] gzWriteAtomicFilePSs :: FilePathLike p => p -> [B.ByteString] -> IO () gzWriteAtomicFilePSs f pss = withSignalsBlocked $ withNamedTemp (toFilePath f) $ \newf -> do gzWriteFilePSs newf pss already_exists <- doesFileExist $ toFilePath f when already_exists $ do mode <- fileMode `fmap` getFileStatus (toFilePath f) setFileMode newf mode `catchall` return () renameFile newf (toFilePath f) gzWriteDocFile :: FilePathLike p => p -> Doc -> IO () gzWriteDocFile f d = gzWriteAtomicFilePSs f $ renderPSs d writeToFile :: FilePathLike p => p -> (Handle -> IO ()) -> IO () writeToFile f job = withSignalsBlocked $ withNamedTemp (toFilePath f) $ \newf -> do bracket (openBinaryFile newf WriteMode) hClose job already_exists <- doesFileExist (toFilePath f) when already_exists $ do mode <- fileMode `fmap` getFileStatus (toFilePath f) setFileMode newf mode `catchall` return () renameFile newf (toFilePath f) appendToFile :: FilePathLike p => p -> (Handle -> IO ()) -> IO () appendToFile f job = withSignalsBlocked $ bracket (openBinaryFile (toFilePath f) AppendMode) hClose job darcs-2.8.4/src/Darcs/Match.hs0000644001765600176560000005262012104371431015361 0ustar ganeshganesh-- Copyright (C) 2004-2005 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP, ScopedTypeVariables, MultiParamTypeClasses, FlexibleInstances, Rank2Types #-} #include "gadts.h" -- | /First matcher, Second matcher and Nonrange matcher/ -- -- When we match for patches, we have a PatchSet, of which we want a -- subset. This subset is formed by the patches in a given interval -- which match a given criterion. If we represent time going left to -- right, then we have (up to) three 'Matcher's: -- -- * the 'firstMatcher' is the left bound of the interval, -- -- * the 'secondMatcher' is the right bound, and -- -- * the 'nonrangeMatcher' is the criterion we use to select among -- patches in the interval. --- -- Each of these matchers can be present or not according to the -- options. The patches we want would then be the ones that all -- present matchers have in common. -- -- (Implementation note: keep in mind that the PatchSet is written -- backwards with respect to the timeline, ie., from right to left) module Darcs.Match ( matchFirstPatchset, matchSecondPatchset, matchPatch, matchAPatch, matchAPatchread, getFirstMatch, getNonrangeMatch, getNonrangeMatchS, getPartialFirstMatch, getPartialSecondMatch, getPartialNonrangeMatch, firstMatch, secondMatch, haveNonrangeMatch, havePatchsetMatch, getOnePatchset, checkMatchSyntax, applyInvToMatcher, nonrangeMatcher, InclusiveOrExclusive(..), matchExists, applyNInv, hasIndexRange ) where import Text.Regex ( mkRegex, matchRegex ) import Control.Monad ( when ) import Data.Maybe ( isJust ) import Data.List ( isPrefixOf ) import Darcs.MonadProgress ( MonadProgress ) import Darcs.Patch.PatchInfoAnd ( PatchInfoAnd, info, piap, conscientiously, hopefully ) import Darcs.Patch.Info ( justName ) import Darcs.Patch ( RepoPatch, Patchy, Named, invert, invertRL, patch2patchinfo, apply ) import Darcs.Patch.Dummy ( DummyPatch ) import Darcs.Repository ( Repository, readRepo, createPristineDirectoryTree ) import Darcs.Patch.Set ( PatchSet(..), Tagged(..), SealedPatchSet, newset2RL ) import Darcs.Patch.Apply( ApplyState ) #ifdef GADT_WITNESSES import Darcs.Patch.Set ( Origin ) #endif import Darcs.Repository.ApplyPatches ( applyPatches ) import Darcs.Patch.Depends ( getPatchesBeyondTag, splitOnTag ) import Darcs.Witnesses.Ordered ( RL(..), consRLSealed, (:>)(..) ) import ByteStringUtils ( mmapFilePS ) import Darcs.Flags ( DarcsFlag( OnePatch, SeveralPatch, Context, AfterPatch, UpToPatch, LastN, PatchIndexRange, OneTag, AfterTag, UpToTag, OnePattern, SeveralPattern, AfterPattern, UpToPattern ) ) import Darcs.Patch.Bundle ( scanContext ) import Darcs.Patch.Match ( Matcher, MatchFun, matchPattern, applyMatcher, makeMatcher, parseMatch ) import Darcs.Patch.MatchData ( PatchMatch ) import Printer ( text, ($$) ) import Darcs.RepoPath ( toFilePath ) import Darcs.Patch.ApplyMonad ( ApplyMonad(..) ) import Darcs.Patch.FileName ( FileName ) import Darcs.Witnesses.Sealed ( FlippedSeal(..), Sealed2(..), seal, flipSeal, seal2, unsealFlipped, unseal2, unseal ) import Storage.Hashed.Tree ( Tree ) #include "impossible.h" data InclusiveOrExclusive = Inclusive | Exclusive deriving Eq -- | @haveNonrangeMatch flags@ tells whether there is a flag in -- @flags@ which corresponds to a match that is "non-range". Thus, -- @--match@, @--patch@ and @--index@ make @haveNonrangeMatch@ -- true, but not @--from-patch@ or @--to-patch@. haveNonrangeMatch :: [DarcsFlag] -> Bool haveNonrangeMatch fs = isJust (hasIndexRange fs) || isJust (nonrangeMatcher fs::Maybe (Matcher DummyPatch)) -- | @havePatchsetMatch flags@ tells whether there is a "patchset -- match" in the flag list. A patchset match is @--match@ or -- @--patch@, or @--context@, but not @--from-patch@ nor (!) -- @--index@. -- Question: Is it supposed not to be a subset of @haveNonrangeMatch@? havePatchsetMatch :: [DarcsFlag] -> Bool havePatchsetMatch fs = isJust (nonrangeMatcher fs::Maybe (Matcher DummyPatch)) || hasC fs where hasC [] = False hasC (Context _:_) = True hasC (_:xs) = hasC xs getNonrangeMatch :: (ApplyMonad IO (ApplyState p), RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u t) -> [DarcsFlag] -> IO () getNonrangeMatch r fs = withRecordedMatch r (getNonrangeMatchS fs) getPartialNonrangeMatch :: (RepoPatch p, ApplyMonad IO (ApplyState p), ApplyState p ~ Tree) => Repository p C(r u t) -> [DarcsFlag] -> [FileName] -> IO () getPartialNonrangeMatch r fs _ = withRecordedMatch r (getNonrangeMatchS fs) getNonrangeMatchS :: (ApplyMonad m (ApplyState p), MonadProgress m, RepoPatch p, ApplyState p ~ Tree) => [DarcsFlag] -> PatchSet p C(Origin x) -> m () getNonrangeMatchS fs repo = case nonrangeMatcher fs of Just m -> if nonrangeMatcherIsTag fs then getTagS m repo else getMatcherS Exclusive m repo Nothing -> fail "Pattern not specified in getNonrangeMatch." -- | @firstMatch fs@ tells whether @fs@ implies a "first match", that -- is if we match against patches from a point in the past on, rather -- than against all patches since the creation of the repository. firstMatch :: [DarcsFlag] -> Bool firstMatch fs = isJust (hasLastn fs) || isJust (firstMatcher fs::Maybe (Matcher DummyPatch)) || isJust (hasIndexRange fs) getFirstMatch :: (ApplyMonad IO (ApplyState p), RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u t) -> [DarcsFlag] -> IO () getFirstMatch r fs = withRecordedMatch r (getFirstMatchS fs) getPartialFirstMatch :: (RepoPatch p, ApplyMonad IO (ApplyState p), ApplyState p ~ Tree) => Repository p C(r u t) -> [DarcsFlag] -> Maybe [FileName] -> IO () getPartialFirstMatch r fs _ = withRecordedMatch r (getFirstMatchS fs) getFirstMatchS :: (ApplyMonad m (ApplyState p), MonadProgress m, RepoPatch p) => [DarcsFlag] -> PatchSet p C(Origin x) -> m () getFirstMatchS fs repo = case hasLastn fs of Just n -> unpullLastN repo n Nothing -> case hasIndexRange fs of Just (_,b) -> unpullLastN repo b -- b is chronologically earlier than a Nothing -> case firstMatcher fs of Nothing -> fail "Pattern not specified in getFirstMatch." Just m -> if firstMatcherIsTag fs then getTagS m repo else getMatcherS Inclusive m repo -- | @secondMatch fs@ tells whether @fs@ implies a "second match", that -- is if we match against patches up to a point in the past on, rather -- than against all patches until now. secondMatch :: [DarcsFlag] -> Bool secondMatch fs = isJust (secondMatcher fs::Maybe (Matcher DummyPatch)) || isJust (hasIndexRange fs) getPartialSecondMatch :: (RepoPatch p, ApplyMonad IO (ApplyState p), ApplyState p ~ Tree) => Repository p C(r u t) -> [DarcsFlag] -> Maybe [FileName] -> IO () getPartialSecondMatch r fs _ = withRecordedMatch r $ \repo -> case secondMatcher fs of Nothing -> case hasIndexRange fs of Just (a,_) -> unpullLastN repo (a-1) Nothing -> fail "Two patterns not specified in get_second_match." Just m -> if secondMatcherIsTag fs then getTagS m repo else getMatcherS Exclusive m repo unpullLastN :: (ApplyMonad m (ApplyState p), MonadProgress m, Patchy p) => PatchSet p C(x y) -> Int -> m () unpullLastN repo n = applyInvRL `unsealFlipped` (safetake n $ newset2RL repo) checkMatchSyntax :: [DarcsFlag] -> IO () checkMatchSyntax opts = case getMatchPattern opts of Nothing -> return () Just p -> either fail (const $ return ()) $ (parseMatch p::Either String (MatchFun DummyPatch)) getMatchPattern :: [DarcsFlag] -> Maybe PatchMatch getMatchPattern [] = Nothing getMatchPattern (OnePattern m:_) = Just m getMatchPattern (SeveralPattern m:_) = Just m getMatchPattern (_:fs) = getMatchPattern fs tagmatch :: String -> Matcher p tagmatch r = makeMatcher ("tag-name "++r) tm where tm (Sealed2 p) = let n = justName (info p) in "TAG " `isPrefixOf` n && isJust (matchRegex (mkRegex r) $ drop 4 n) mymatch :: String -> Matcher p mymatch r = makeMatcher ("patch-name "++r) mm where mm (Sealed2 p) = isJust . matchRegex (mkRegex r) . justName . info $ p -- | strictJust is a strict version of the Just constructor, used to ensure -- that if we claim we've got a pattern match, that the pattern will -- actually match (rathern than fail to compile properly). strictJust :: a -> Maybe a strictJust x = Just $! x -- | @nonrangeMatcher@ is the criterion that is used to match against -- patches in the interval. It is 'Just m' when the @--patch@, @--match@, -- @--tag@ options are passed (or their plural variants). nonrangeMatcher :: Patchy p => [DarcsFlag] -> Maybe (Matcher p) nonrangeMatcher [] = Nothing nonrangeMatcher (OnePattern m:_) = strictJust $ matchPattern m nonrangeMatcher (OneTag t:_) = strictJust $ tagmatch t nonrangeMatcher (OnePatch p:_) = strictJust $ mymatch p nonrangeMatcher (SeveralPattern m:_) = strictJust $ matchPattern m nonrangeMatcher (SeveralPatch p:_) = strictJust $ mymatch p nonrangeMatcher (_:fs) = nonrangeMatcher fs -- | @nonrangeMatcherIsTag@ returns true if the matching option was -- '--tag' nonrangeMatcherIsTag :: [DarcsFlag] -> Bool nonrangeMatcherIsTag [] = False nonrangeMatcherIsTag (OneTag _:_) = True nonrangeMatcherIsTag (_:fs) = nonrangeMatcherIsTag fs -- | @firstMatcher@ returns the left bound of the matched interval. -- This left bound is also specified when we use the singular versions -- of @--patch@, @--match@ and @--tag@. Otherwise, @firstMatcher@ -- returns @Nothing@. firstMatcher :: Patchy p => [DarcsFlag] -> Maybe (Matcher p) firstMatcher [] = Nothing firstMatcher (OnePattern m:_) = strictJust $ matchPattern m firstMatcher (AfterPattern m:_) = strictJust $ matchPattern m firstMatcher (AfterTag t:_) = strictJust $ tagmatch t firstMatcher (OnePatch p:_) = strictJust $ mymatch p firstMatcher (AfterPatch p:_) = strictJust $ mymatch p firstMatcher (_:fs) = firstMatcher fs firstMatcherIsTag :: [DarcsFlag] -> Bool firstMatcherIsTag [] = False firstMatcherIsTag (AfterTag _:_) = True firstMatcherIsTag (_:fs) = firstMatcherIsTag fs secondMatcher :: Patchy p => [DarcsFlag] -> Maybe (Matcher p) secondMatcher [] = Nothing secondMatcher (OnePattern m:_) = strictJust $ matchPattern m secondMatcher (UpToPattern m:_) = strictJust $ matchPattern m secondMatcher (OnePatch p:_) = strictJust $ mymatch p secondMatcher (UpToPatch p:_) = strictJust $ mymatch p secondMatcher (UpToTag t:_) = strictJust $ tagmatch t secondMatcher (_:fs) = secondMatcher fs secondMatcherIsTag :: [DarcsFlag] -> Bool secondMatcherIsTag [] = False secondMatcherIsTag (UpToTag _:_) = True secondMatcherIsTag (_:fs) = secondMatcherIsTag fs -- | @matchAPatchread fs p@ tells whether @p@ matches the matchers in -- the flags listed in @fs@. matchAPatchread :: Patchy p => [DarcsFlag] -> PatchInfoAnd p C(x y) -> Bool matchAPatchread fs = case nonrangeMatcher fs of Nothing -> const True Just m -> applyMatcher m -- | @matchAPatch fs p@ tells whether @p@ matches the matchers in -- the flags @fs@ matchAPatch :: Patchy p => [DarcsFlag] -> Named p C(x y) -> Bool matchAPatch fs p = case nonrangeMatcher fs of Nothing -> True Just m -> applyMatcher m (patch2patchinfo p `piap` p) matchPatch :: RepoPatch p => [DarcsFlag] -> PatchSet p C(start x) -> Sealed2 (Named p) matchPatch fs ps = case hasIndexRange fs of Just (a,a') | a == a' -> case (unseal myhead) $ dropn (a-1) ps of Just (Sealed2 p) -> seal2 $ hopefully p Nothing -> error "Patch out of range!" | otherwise -> bug ("Invalid index range match given to matchPatch: "++ show (PatchIndexRange a a')) where myhead :: PatchSet p C(start x) -> Maybe (Sealed2 (PatchInfoAnd p)) myhead (PatchSet NilRL (Tagged t _ _ :<: _)) = Just $ seal2 t myhead (PatchSet (x:<:_) _) = Just $ seal2 x myhead _ = Nothing Nothing -> case nonrangeMatcher fs of Nothing -> bug "Couldn't matchPatch" Just m -> findAPatch m ps getOnePatchset :: (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u t) -> [DarcsFlag] -> IO (SealedPatchSet p C(Origin)) getOnePatchset repository fs = case nonrangeMatcher fs of Just m -> do ps <- readRepo repository if nonrangeMatcherIsTag fs then return $ getMatchingTag m ps else return $ matchAPatchset m ps Nothing -> (seal . scanContext) `fmap` mmapFilePS (toFilePath $ context_f fs) where context_f [] = bug "Couldn't match_nonrange_patchset" context_f (Context f:_) = f context_f (_:xs) = context_f xs -- | @hasLastn fs@ return the @--last@ argument in @fs@, if any. hasLastn :: [DarcsFlag] -> Maybe Int hasLastn [] = Nothing hasLastn (LastN (-1):_) = error "--last requires a positive integer argument." hasLastn (LastN n:_) = Just n hasLastn (_:fs) = hasLastn fs hasIndexRange :: [DarcsFlag] -> Maybe (Int,Int) hasIndexRange [] = Nothing hasIndexRange (PatchIndexRange x y:_) = Just (x,y) hasIndexRange (_:fs) = hasIndexRange fs -- | @matchFirstPatchset fs ps@ returns the part of @ps@ before its -- first matcher, ie the one that comes first dependencywise. Hence, -- patches in @matchFirstPatchset fs ps@ are the context for the ones -- we don't want. matchFirstPatchset :: RepoPatch p => [DarcsFlag] -> PatchSet p C(start x) -> SealedPatchSet p C(start) matchFirstPatchset fs patchset = case hasLastn fs of Just n -> dropn n patchset Nothing -> case hasIndexRange fs of Just (_,b) -> dropn b patchset Nothing -> case firstMatcher fs of Nothing -> bug "Couldn't matchFirstPatchset" Just m -> unseal (dropn 1) $ if firstMatcherIsTag fs then getMatchingTag m patchset else matchAPatchset m patchset -- | @dropn n ps@ drops the @n@ last patches from @ps@. dropn :: Int -> PatchSet p C(start x) -> SealedPatchSet p C(start) dropn n ps | n <= 0 = seal ps dropn n (PatchSet NilRL (Tagged t _ ps :<: ts)) = dropn n $ PatchSet (t:<:ps) ts dropn _ (PatchSet NilRL NilRL) = seal $ PatchSet NilRL NilRL dropn n (PatchSet (_:<:ps) ts) = dropn (n-1) $ PatchSet ps ts -- | @matchSecondPatchset fs ps@ returns the part of @ps@ before its -- second matcher, ie the one that comes last dependencywise. matchSecondPatchset :: RepoPatch p => [DarcsFlag] -> PatchSet p C(start x) -> SealedPatchSet p C(start) matchSecondPatchset fs ps = case hasIndexRange fs of Just (a,_) -> dropn (a-1) ps Nothing -> case secondMatcher fs of Nothing -> bug "Couldn't matchSecondPatchset" Just m -> if secondMatcherIsTag fs then getMatchingTag m ps else matchAPatchset m ps -- | @findAPatch m ps@ returns the last patch in @ps@ matching @m@, and -- calls 'error' if there is none. findAPatch :: RepoPatch p => Matcher p -> PatchSet p C(start x) -> Sealed2 (Named p) findAPatch m (PatchSet NilRL NilRL) = error $ "Couldn't find patch matching " ++ show m findAPatch m (PatchSet NilRL (Tagged t _ ps :<: ts)) = findAPatch m (PatchSet (t:<:ps) ts) findAPatch m (PatchSet (p:<:ps) ts) | applyMatcher m p = seal2 $ hopefully p | otherwise = findAPatch m (PatchSet ps ts) -- | @matchAPatchset m ps@ returns a (the largest?) subset of @ps@ -- ending in patch which matches @m@. Calls 'error' if there is none. matchAPatchset :: RepoPatch p => Matcher p -> PatchSet p C(start x) -> SealedPatchSet p C(start) matchAPatchset m (PatchSet NilRL NilRL) = error $ "Couldn't find patch matching " ++ show m matchAPatchset m (PatchSet NilRL (Tagged t _ ps :<: ts)) = matchAPatchset m (PatchSet (t:<:ps) ts) matchAPatchset m (PatchSet (p:<:ps) ts) | applyMatcher m p = seal (PatchSet (p:<:ps) ts) | otherwise = matchAPatchset m (PatchSet ps ts) -- | @getMatchingTag m ps@, where @m@ is a 'Matcher' which matches tags -- returns a 'SealedPatchSet' containing all patches in the last tag which -- matches @m@. Last tag means the most recent tag in repository order, -- i.e. the last one you'd see if you ran darcs changes -t @m@. Calls -- 'error' if there is no matching tag. getMatchingTag :: RepoPatch p => Matcher p -> PatchSet p C(start x) -> SealedPatchSet p C(start) getMatchingTag m (PatchSet NilRL NilRL) = error $ "Couldn't find a tag matching " ++ show m getMatchingTag m (PatchSet NilRL (Tagged t _ ps :<: ts)) = getMatchingTag m (PatchSet (t:<:ps) ts) getMatchingTag m (PatchSet (p:<:ps) ts) | applyMatcher m p = -- found a non-clean tag, need to commute out the things that it doesn't depend on case splitOnTag (info p) (PatchSet (p:<:ps) ts) of patchSet :> _ -> seal patchSet | otherwise = getMatchingTag m (PatchSet ps ts) -- | @matchExists m ps@ tells whether there is a patch matching -- @m@ in @ps@ matchExists :: Matcher p -> PatchSet p C(start x) -> Bool matchExists _ (PatchSet NilRL NilRL) = False matchExists m (PatchSet NilRL (Tagged t _ ps :<: ts)) = matchExists m (PatchSet (t:<:ps) ts) matchExists m (PatchSet (p:<:ps) ts) | applyMatcher m $ p = True | otherwise = matchExists m (PatchSet ps ts) applyInvToMatcher :: (RepoPatch p, ApplyMonad m (ApplyState p)) => InclusiveOrExclusive -> Matcher p -> PatchSet p C(Origin x) -> m () applyInvToMatcher _ _ (PatchSet NilRL NilRL) = impossible applyInvToMatcher ioe m (PatchSet NilRL (Tagged t _ ps :<: ts)) = applyInvToMatcher ioe m (PatchSet (t:<:ps) ts) applyInvToMatcher ioe m (PatchSet (p:<:ps) xs) | applyMatcher m p = when (ioe == Inclusive) (applyInvp p) | otherwise = applyInvp p >> applyInvToMatcher ioe m (PatchSet ps xs) -- | @applyNInv@ n ps applies the inverse of the last @n@ patches of @ps@. applyNInv :: (RepoPatch p, ApplyMonad m (ApplyState p)) => Int -> PatchSet p C(Origin x) -> m () applyNInv n _ | n <= 0 = return () applyNInv _ (PatchSet NilRL NilRL) = error "Index out of range." applyNInv n (PatchSet NilRL (Tagged t _ ps :<: ts)) = applyNInv n (PatchSet (t :<: ps) ts) applyNInv n (PatchSet (p :<: ps) xs) = applyInvp p >> applyNInv (n - 1) (PatchSet ps xs) getMatcherS :: (ApplyMonad m (ApplyState p), RepoPatch p) => InclusiveOrExclusive -> Matcher p -> PatchSet p C(Origin x) -> m () getMatcherS ioe m repo = if matchExists m repo then applyInvToMatcher ioe m repo else fail $ "Couldn't match pattern "++ show m getTagS :: (ApplyMonad m (ApplyState p), MonadProgress m, RepoPatch p) => Matcher p -> PatchSet p C(Origin x) -> m () getTagS match repo = do let pinfo = patch2patchinfo `unseal2` (findAPatch match repo) case getPatchesBeyondTag pinfo repo of FlippedSeal extras -> applyInvRL extras -- | @applyInvp@ tries to get the patch that's in a 'PatchInfoAnd -- patch', and to apply its inverse. If we fail to fetch the patch -- (presumably in a partial repositiory), then we share our sorrow -- with the user. applyInvp :: (Patchy p, ApplyMonad m (ApplyState p)) => PatchInfoAnd p C(x y) -> m () applyInvp hp = apply (invert $ fromHopefully hp) where fromHopefully = conscientiously $ \e -> text "Sorry, partial repository problem. Patch not available:" $$ e $$ text "" $$ text "If you think what you're trying to do is ok then" $$ text "report this as a bug on the darcs-user list." -- | a version of 'take' for 'RL' lists that cater for contexts. safetake :: Int -> RL a C(x y) -> FlippedSeal (RL a) C(y) safetake 0 _ = flipSeal NilRL safetake _ NilRL = error "There aren't that many patches..." safetake i (a:<:as) = a `consRLSealed` safetake (i-1) as withRecordedMatch :: (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u t) -> (PatchSet p C(Origin r) -> IO ()) -> IO () withRecordedMatch r job = do createPristineDirectoryTree r "." readRepo r >>= job applyInvRL :: (ApplyMonad m (ApplyState p), MonadProgress m, Patchy p) => RL (PatchInfoAnd p) C(x r) -> m () applyInvRL = applyPatches . invertRL -- this gives nicer feedback darcs-2.8.4/src/Darcs/MonadProgress.hs0000644001765600176560000000570412104371431017111 0ustar ganeshganesh{-# LANGUAGE TypeSynonymInstances #-} -- Copyright (C) 2011 Ganesh Sittampalam -- -- 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. module Darcs.MonadProgress ( MonadProgress(..), ProgressAction(..) , silentlyRunProgressActions ) where import Prelude hiding ( catch ) import Progress ( beginTedious, endTedious, tediousSize, finishedOneIO ) import Printer ( hPutDocLn, Doc ) import Darcs.ColorPrinter () -- for instance Show Doc import Control.Exception ( catch ) import System.IO ( stderr ) import qualified Storage.Hashed.Monad as HSM -- |a monadic action, annotated with a progress message that could be printed out -- while running the action, and a message that could be printed out on error. -- Actually printing out these messages is optional to allow non-IO monads to -- just run the action. data ProgressAction m a = ProgressAction {paAction :: m a ,paMessage :: Doc ,paOnError :: Doc } class Monad m => MonadProgress m where -- |run a list of 'ProgressAction's. In some monads (typically IO-based ones), -- the progress and error messages will be used. In others they will be -- ignored and just the actions will be run. runProgressActions :: String -> [ProgressAction m ()] -> m () instance MonadProgress IO where runProgressActions _ [] = return () runProgressActions what items = do beginTedious what tediousSize what (length items) mapM_ go items endTedious what where go item = do finishedOneIO what (show $ paMessage item) paAction item `catch` \e -> do hPutDocLn stderr $ paOnError item ioError e -- |run a list of 'ProgressAction's without any feedback messages silentlyRunProgressActions :: Monad m => String -> [ProgressAction m ()] -> m () silentlyRunProgressActions _ = mapM_ paAction instance (Functor m, Monad m) => MonadProgress (HSM.TreeMonad m) where runProgressActions = silentlyRunProgressActions darcs-2.8.4/src/Darcs/Patch.hs0000644001765600176560000001025712104371431015364 0ustar ganeshganesh-- Copyright (C) 2002-2003 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# OPTIONS_GHC -fno-warn-orphans #-} {-# LANGUAGE CPP, UndecidableInstances #-} -- XXX Undecidable only in GHC < 7 #include "gadts.h" module Darcs.Patch ( RepoPatch , PrimOf , Named , Patchy , joinPatches , fromPrim , fromPrims , rmfile , addfile , rmdir , adddir , move , hunk , tokreplace , namepatch , anonymous , binary , description , showContextPatch , showPatch , showNicely , infopatch , changepref , thing , things , primIsAddfile , primIsHunk , primIsSetpref , merge , commute , listTouchedFiles , hunkMatches , forceTokReplace , PrimPatch -- * for PatchTest , resolveConflicts , Effect , effect , primIsBinary , gzWritePatch , writePatch , primIsAdddir , invert , invertFL , invertRL , commuteFLorComplain , commuteRL , readPatch , readPatchPartial , canonize , sortCoalesceFL , tryToShrink , patchname , patchcontents , applyToFilePaths , apply , applyToTree , effectOnFilePaths , patch2patchinfo , summary , summaryFL , plainSummary , xmlSummary , plainSummaryPrims , adddeps , getdeps , listConflictedFiles , isInconsistent ) where import Darcs.Patch.Apply ( applyToFilePaths, effectOnFilePaths, applyToTree ) import Darcs.Patch.Apply ( ApplyState ) import Darcs.Patch.Commute ( commuteFLorComplain, commuteRL ) import Darcs.Patch.Conflict ( Conflict, CommuteNoConflicts, listConflictedFiles, resolveConflicts ) import Darcs.Patch.Effect ( Effect(effect) ) import Darcs.Patch.FileHunk ( IsHunk ) import Darcs.Patch.Format ( PatchListFormat ) import Darcs.Patch.Invert ( invertRL, invertFL ) import Darcs.Patch.Named ( Named, adddeps, namepatch, anonymous, getdeps, infopatch, patch2patchinfo, patchname, patchcontents ) import Darcs.Patch.Patchy ( Patchy, showPatch, showNicely, showContextPatch, invert, thing, things, apply, description, summary, summaryFL, commute, listTouchedFiles, hunkMatches ) import Darcs.Patch.Prim ( FromPrims, fromPrims, joinPatches, FromPrim, fromPrim, canonize, sortCoalesceFL, rmdir, rmfile, tokreplace, adddir, addfile, binary, changepref, hunk, move, primIsAdddir, primIsAddfile, primIsHunk, primIsBinary, primIsSetpref, tryToShrink, PrimPatch, PrimPatchBase(..) ) import Darcs.Patch.Read ( readPatch, readPatchPartial ) import Darcs.Patch.Repair ( isInconsistent ) import Darcs.Patch.RepoPatch ( RepoPatch ) import Darcs.Patch.Show ( writePatch, gzWritePatch ) import Darcs.Patch.Summary ( xmlSummary, plainSummary, plainSummaryPrims ) import Darcs.Patch.TokenReplace ( forceTokReplace ) import Darcs.Patch.V1.Commute ( merge ) import Storage.Hashed.Tree( Tree ) instance (CommuteNoConflicts p, Conflict p, IsHunk p, PatchListFormat p, PrimPatchBase p, Patchy p, ApplyState p ~ Tree) => Patchy (Named p) darcs-2.8.4/src/Darcs/PrintPatch.hs0000644001765600176560000000455012104371431016400 0ustar ganeshganesh-- Copyright (C) 2003 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP #-} #include "gadts.h" module Darcs.PrintPatch ( printPatch, contextualPrintPatch, printPatchPager, printFriendly ) where import Darcs.Patch ( Patchy, showContextPatch, showPatch ) import Darcs.Patch.Apply ( ApplyState ) import Storage.Hashed.Tree( Tree ) import Storage.Hashed.Monad( virtualTreeIO ) import Darcs.Arguments ( DarcsFlag, showFriendly ) import Darcs.Flags ( isUnified ) import Printer ( putDocLnWith ) import Darcs.ColorPrinter ( fancyPrinters ) import Darcs.External ( viewDocWith ) -- | @'printFriendly' opts patch@ prints @patch@ in accordance with the -- flags in opts, ie, whether @--verbose@ or @--summary@ were passed at -- the command-line. printFriendly :: (Patchy p, ApplyState p ~ Tree) => (Maybe (Tree IO)) -> [DarcsFlag] -> p C(x y) -> IO () printFriendly (Just pristine) opts p | isUnified opts = virtualTreeIO (showContextPatch p) pristine >>= putDocLnWith fancyPrinters . fst printFriendly _ opts p = putDocLnWith fancyPrinters $ showFriendly opts p -- | 'printPatch' prints a patch on standard output. printPatch :: Patchy p => p C(x y) -> IO () printPatch p = putDocLnWith fancyPrinters $ showPatch p -- | 'printPatchPager' runs '$PAGER' and shows a patch in it. printPatchPager :: Patchy p => p C(x y) -> IO () printPatchPager p = viewDocWith fancyPrinters $ showPatch p -- | 'contextualPrintPatch' prints a patch, together with its context, -- on standard output. contextualPrintPatch :: (Patchy p, ApplyState p ~ Tree) => Tree IO -> p C(x y) -> IO () contextualPrintPatch s p = virtualTreeIO (showContextPatch p) s >>= putDocLnWith fancyPrinters . fst darcs-2.8.4/src/Darcs/ProgressPatches.hs0000644001765600176560000000555412104371431017445 0ustar ganeshganesh{-# LANGUAGE CPP, GADTs #-} #include "gadts.h" module Darcs.ProgressPatches (progressRL, progressFL, progressRLShowTags) where import Darcs.Witnesses.Ordered ( FL(..), RL(..), lengthRL, lengthFL ) import Darcs.Patch.PatchInfoAnd (PatchInfoAnd,info) import System.IO.Unsafe ( unsafePerformIO ) import Progress (minlist, beginTedious, endTedious, progress, progressKeepLatest, tediousSize, finishedOne) import Darcs.Patch.Info (justName, isTag) -- | Evaluate an 'FL' list and report progress. progressFL :: String -> FL a C(x y) -> FL a C(x y) progressFL _ NilFL = NilFL progressFL k (x:>:xs) = if l < minlist then x:>:xs else startit x :>: pl xs where l = lengthFL (x:>:xs) startit y = unsafePerformIO $ do beginTedious k tediousSize k l return y pl :: FL a C(x y) -> FL a C(x y) pl NilFL = NilFL pl (y:>:NilFL) = unsafePerformIO $ do endTedious k return (y:>:NilFL) pl (y:>:ys) = progress k y :>: pl ys -- | Evaluate an 'RL' list and report progress. progressRL :: String -> RL a C(x y) -> RL a C(x y) progressRL _ NilRL = NilRL progressRL k (x:<:xs) = if l < minlist then x:<:xs else startit x :<: pl xs where l = lengthRL (x:<:xs) startit y = unsafePerformIO $ do beginTedious k tediousSize k l return y pl :: RL a C(x y) -> RL a C(x y) pl NilRL = NilRL pl (y:<:NilRL) = unsafePerformIO $ do endTedious k return (y:<:NilRL) pl (y:<:ys) = progress k y :<: pl ys -- | Evaluate an 'RL' list and report progress. In addition to printing -- the number of patches we got, show the name of the last tag we got. progressRLShowTags :: String -> RL (PatchInfoAnd p) C(x y) -> RL (PatchInfoAnd p) C(x y) progressRLShowTags _ NilRL = NilRL progressRLShowTags k (x:<:xs) = if l < minlist then x:<:xs else startit x :<: pl xs where l = lengthRL (x:<:xs) startit y = unsafePerformIO $ do beginTedious k tediousSize k l return y pl :: RL (PatchInfoAnd p) C(x y) -> RL (PatchInfoAnd p) C(x y) pl NilRL = NilRL pl (y:<:NilRL) = unsafePerformIO $ do endTedious k return (y:<:NilRL) pl (y:<:ys) = if isTag iy then finishedOne k ("back to "++ justName iy) y :<: pl ys else progressKeepLatest k y :<: pl ys where iy = info y darcs-2.8.4/src/Darcs/RemoteApply.hs0000644001765600176560000000523312104371431016564 0ustar ganeshganesh-- | This module is used by the push and put commands to apply the a bundle to a -- remote repository. By remote I do not necessarily mean a repository on another -- machine, it is just not the repository we're located in. module Darcs.RemoteApply ( remoteApply, applyAs ) where import System.Exit ( ExitCode ) import Darcs.Flags ( DarcsFlag( ApplyAs, Debug ), remoteDarcs ) import Darcs.Utils ( breakCommand ) import Darcs.URL ( isHttpUrl, isSshUrl, splitSshUrl, SshFilePath(..) ) import Darcs.External ( darcsProgram, pipeDoc, pipeDocSSH, maybeURLCmd ) import qualified Darcs.Ssh as Ssh ( remoteDarcs ) import Printer ( Doc ) remoteApply :: [DarcsFlag] -> String -> Doc -> IO ExitCode remoteApply opts repodir bundle = case applyAs opts of Nothing -> if isSshUrl repodir then applyViaSsh opts (splitSshUrl repodir) bundle else if isHttpUrl repodir then applyViaUrl opts repodir bundle else applyViaLocal opts repodir bundle Just un -> if isSshUrl repodir then applyViaSshAndSudo opts (splitSshUrl repodir) un bundle else applyViaSudo un repodir bundle applyAs :: [DarcsFlag] -> Maybe String applyAs (ApplyAs user:_) = Just user applyAs (_:fs) = applyAs fs applyAs [] = Nothing applyViaSudo :: String -> String -> Doc -> IO ExitCode applyViaSudo user repo bundle = darcsProgram >>= \darcs -> pipeDoc "sudo" ["-u",user,darcs,"apply","--all","--repodir",repo] bundle applyViaLocal :: [DarcsFlag] -> String -> Doc -> IO ExitCode applyViaLocal opts repo bundle = darcsProgram >>= \darcs -> pipeDoc darcs ("apply":"--all":"--repodir":repo:applyopts opts) bundle applyViaUrl :: [DarcsFlag] -> String -> Doc -> IO ExitCode applyViaUrl opts repo bundle = do maybeapply <- maybeURLCmd "APPLY" repo case maybeapply of Nothing -> applyViaLocal opts repo bundle Just apply -> do let (cmd, args) = breakCommand apply pipeDoc cmd (args ++ [repo]) bundle applyViaSsh :: [DarcsFlag] -> SshFilePath -> Doc -> IO ExitCode applyViaSsh opts repo bundle = pipeDocSSH repo [Ssh.remoteDarcs (remoteDarcs opts) ++" apply --all "++unwords (applyopts opts)++ " --repodir '"++(sshRepo repo)++"'"] bundle applyViaSshAndSudo :: [DarcsFlag] -> SshFilePath -> String -> Doc -> IO ExitCode applyViaSshAndSudo opts repo username bundle = pipeDocSSH repo ["sudo -u "++username++" "++Ssh.remoteDarcs (remoteDarcs opts)++ " apply --all --repodir '"++(sshRepo repo)++"'"] bundle applyopts :: [DarcsFlag] -> [String] applyopts opts = if Debug `elem` opts then ["--debug"] else [] darcs-2.8.4/src/Darcs/RepoPath.hs0000644001765600176560000002232612104371431016047 0ustar ganeshganesh{-# LANGUAGE CPP #-} -- Copyright (C) 2007 Eric Kow -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. -- | Various abstractions for dealing with paths. module Darcs.RepoPath ( -- * AbsolutePath AbsolutePath, makeAbsolute, ioAbsolute, rootDirectory, -- * AbsolutePathOrStd AbsolutePathOrStd, makeAbsoluteOrStd, ioAbsoluteOrStd, useAbsoluteOrStd, stdOut, -- * AbsoluteOrRemotePath AbsoluteOrRemotePath, ioAbsoluteOrRemote, isRemote, -- * SubPath SubPath, makeSubPathOf, simpleSubPath, -- * Miscellaneous sp2fn, FilePathOrURL(..), FilePathLike(toFilePath), getCurrentDirectory, setCurrentDirectory ) where import Control.Applicative ( (<$>) ) import Data.List ( isPrefixOf, isSuffixOf ) import Control.Exception ( tryJust, bracket ) import System.IO.Error ( isDoesNotExistError ) import Darcs.URL ( isAbsolute, isRelative, isSshNopath ) import qualified Workaround ( getCurrentDirectory ) import qualified System.Directory ( setCurrentDirectory ) import System.Directory ( doesDirectoryExist ) import qualified System.FilePath.Posix as FilePath ( normalise ) import qualified System.FilePath as NativeFilePath ( takeFileName, takeDirectory ) import qualified Darcs.Patch.FileName as PatchFileName ( FileName, fp2fn, fn2fp ) import System.Posix.Files ( isDirectory, getSymbolicLinkStatus ) #include "impossible.h" class FilePathOrURL a where toPath :: a -> String class FilePathOrURL a => FilePathLike a where toFilePath :: a -> FilePath -- | Paths which are relative to the local darcs repository and normalized. -- Note: These are understood not to have the dot in front. newtype SubPath = SubPath FilePath deriving (Eq, Ord) newtype AbsolutePath = AbsolutePath FilePath deriving (Eq, Ord) -- | This is for situations where a string (e.g. a command line argument) -- may take the value \"-\" to mean stdin or stdout (which one depends on -- context) instead of a normal file path. data AbsolutePathOrStd = AP AbsolutePath | APStd deriving (Eq, Ord) data AbsoluteOrRemotePath = AbsP AbsolutePath | RmtP String deriving (Eq, Ord) instance FilePathOrURL AbsolutePath where toPath (AbsolutePath x) = x instance FilePathOrURL SubPath where toPath (SubPath x) = x instance CharLike c => FilePathOrURL [c] where toPath = toFilePath instance FilePathOrURL AbsoluteOrRemotePath where toPath (AbsP a) = toPath a toPath (RmtP r) = r instance FilePathOrURL PatchFileName.FileName where toPath = PatchFileName.fn2fp instance FilePathLike PatchFileName.FileName where toFilePath = PatchFileName.fn2fp instance FilePathLike AbsolutePath where toFilePath (AbsolutePath x) = x instance FilePathLike SubPath where toFilePath (SubPath x) = x class CharLike c where toChar :: c -> Char fromChar :: Char -> c instance CharLike Char where toChar = id fromChar = id instance CharLike c => FilePathLike [c] where toFilePath = map toChar -- | Make the second path relative to the first, if possible makeSubPathOf :: AbsolutePath -> AbsolutePath -> Maybe SubPath makeSubPathOf (AbsolutePath p1) (AbsolutePath p2) = -- The slash prevents "foobar" from being treated as relative to "foo" if p1 == p2 || (p1 ++ "/") `isPrefixOf` p2 then Just $ SubPath $ drop (length p1 + 1) p2 else Nothing simpleSubPath :: FilePath -> Maybe SubPath simpleSubPath x | null x = bug "simpleSubPath called with empty path" | isRelative x = Just $ SubPath $ FilePath.normalise $ pathToPosix x | otherwise = Nothing -- | Ensure directory exists and is not a symbolic link. doesDirectoryReallyExist :: FilePath -> IO Bool doesDirectoryReallyExist f = do x <- tryJust (\x -> if isDoesNotExistError x then Just () else Nothing) $ isDirectory <$> getSymbolicLinkStatus f return $ case x of Left () -> False Right y -> y -- | Interpret a possibly relative path wrt the current working directory. ioAbsolute :: FilePath -> IO AbsolutePath ioAbsolute dir = do isdir <- doesDirectoryReallyExist dir here <- getCurrentDirectory if isdir then bracket (setCurrentDirectory dir) (const $ setCurrentDirectory $ toFilePath here) (const getCurrentDirectory) else let super_dir = case NativeFilePath.takeDirectory dir of "" -> "." d -> d file = NativeFilePath.takeFileName dir in do abs_dir <- if dir == super_dir then return $ AbsolutePath dir else ioAbsolute super_dir return $ makeAbsolute abs_dir file -- | Take an absolute path and a string representing a (possibly relative) -- path and combine them into an absolute path. If the second argument is -- already absolute, then the first argument gets ignored. This function also -- takes care that the result is converted to Posix convention and -- normalized. Also, parent directories (\"..\") at the front of the string -- argument get canceled out against trailing directory parts of the -- absolute path argument. -- -- Regarding the last point, someone more familiar with how these functions -- are used should verify that this is indeed necessary or at least useful. makeAbsolute :: AbsolutePath -> FilePath -> AbsolutePath makeAbsolute a dir = if not (null dir) && isAbsolute dir then AbsolutePath (normSlashes dir') else ma a dir' where dir' = FilePath.normalise $ pathToPosix dir -- Why do we care to reduce ".." here? -- Why not do this throughout the whole path, i.e. "x/y/../z" -> "x/z" ? ma here ('.':'.':'/':r) = ma (takeDirectory here) r ma here ".." = takeDirectory here ma here "." = here ma here "" = here ma here r = here /- ('/':r) (/-) :: AbsolutePath -> String -> AbsolutePath x /- ('/':r) = x /- r (AbsolutePath "/") /- r = AbsolutePath ('/':simpleClean r) (AbsolutePath x) /- r = AbsolutePath (x++'/':simpleClean r) -- | Convert to posix, remove trailing slashes, and (under Posix) -- reduce multiple leading slashes to one. simpleClean :: String -> String simpleClean = normSlashes . reverse . dropWhile (=='/') . reverse . pathToPosix -- | The root directory as an absolute path. rootDirectory :: AbsolutePath rootDirectory = AbsolutePath "/" makeAbsoluteOrStd :: AbsolutePath -> String -> AbsolutePathOrStd makeAbsoluteOrStd _ "-" = APStd makeAbsoluteOrStd a p = AP $ makeAbsolute a p stdOut :: AbsolutePathOrStd stdOut = APStd ioAbsoluteOrStd :: String -> IO AbsolutePathOrStd ioAbsoluteOrStd "-" = return APStd ioAbsoluteOrStd p = AP `fmap` ioAbsolute p -- | Execute either the first or the second argument action, depending on -- whether the given path is an 'AbsolutePath' or stdin/stdout. useAbsoluteOrStd :: (AbsolutePath -> a) -> a -> AbsolutePathOrStd -> a useAbsoluteOrStd _ f APStd = f useAbsoluteOrStd f _ (AP x) = f x ioAbsoluteOrRemote :: String -> IO AbsoluteOrRemotePath ioAbsoluteOrRemote p = do isdir <- doesDirectoryExist p if not isdir then return $ RmtP $ case () of _ | isSshNopath p -> p++"." | "/" `isSuffixOf` p -> init p | otherwise -> p else AbsP `fmap` ioAbsolute p isRemote :: AbsoluteOrRemotePath -> Bool isRemote (RmtP _) = True isRemote _ = False takeDirectory :: AbsolutePath -> AbsolutePath takeDirectory (AbsolutePath x) = case reverse $ drop 1 $ dropWhile (/='/') $ reverse x of "" -> AbsolutePath "/" x' -> AbsolutePath x' instance Show AbsolutePath where show = show . toFilePath instance Show SubPath where show = show . toFilePath instance Show AbsolutePathOrStd where show (AP a) = show a show APStd = "standard input/output" instance Show AbsoluteOrRemotePath where show (AbsP a) = show a show (RmtP r) = show r -- | Normalize the path separator to Posix style (slash, not backslash). -- This only affects Windows systems. pathToPosix :: FilePath -> FilePath pathToPosix = map convert where #ifdef WIN32 convert '\\' = '/' #endif convert c = c -- | Reduce multiple leading slashes to one. This only affects Posix systems. normSlashes :: FilePath -> FilePath #ifndef WIN32 -- multiple slashes in front are ignored under Posix normSlashes ('/':p) = '/' : dropWhile (== '/') p #endif normSlashes p = p getCurrentDirectory :: IO AbsolutePath getCurrentDirectory = AbsolutePath `fmap` Workaround.getCurrentDirectory setCurrentDirectory :: FilePathLike p => p -> IO () setCurrentDirectory = System.Directory.setCurrentDirectory . toFilePath {-# INLINE sp2fn #-} sp2fn :: SubPath -> PatchFileName.FileName sp2fn = PatchFileName.fp2fn . toFilePath darcs-2.8.4/src/Darcs/Repository.hs0000644001765600176560000005477212104371431016516 0ustar ganeshganesh-- Copyright (C) 2002-2004 David Roundy -- Copyright (C) 2005 Juliusz Chroboczek -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP, ScopedTypeVariables #-} #include "gadts.h" module Darcs.Repository ( Repository, HashedDir(..), Cache(..), CacheLoc(..), WritableOrNot(..) , RepoJob(..), maybeIdentifyRepository, identifyRepositoryFor , withRepoLock, withRepoReadLock, withRepository, withRepositoryDirectory , withGutsOf, makePatchLazy, writePatchSet, findRepository, amInRepository , amNotInRepository, amInHashedRepository, replacePristine , withRecorded, readRepo, prefsUrl, readRepoUsingSpecificInventory , addToPending, tentativelyAddPatch, tentativelyRemovePatches , tentativelyAddToPending, tentativelyReplacePatches, readTentativeRepo , tentativelyMergePatches, considerMergeToWorking, revertRepositoryChanges , finalizeRepositoryChanges, createRepository, copyRepository , patchSetToRepository, unrevertUrl, applyToWorking , patchSetToPatches, createPristineDirectoryTree , createPartialsPristineDirectoryTree, optimizeInventory, cleanRepository , PatchSet, SealedPatchSet, PatchInfoAnd , setScriptsExecutable, setScriptsExecutablePatches , checkUnrelatedRepos, testTentative, testRecorded , extractOptions, modifyCache, reportBadSources -- * Recorded and unrecorded and pending. , readRecorded, readUnrecorded, unrecordedChanges, readPending , readRecordedAndPending -- * Index. , readIndex, invalidateIndex ) where import Prelude hiding ( catch ) import System.Exit ( ExitCode(..), exitWith ) #if MIN_VERSION_tar(0,4,0) import Control.Exception ( Exception, throwIO, catch ) #else import Control.Exception ( catch ) #endif import Data.List ( isPrefixOf) import Data.Maybe( catMaybes, isJust, listToMaybe ) import Darcs.Repository.State( readRecorded, readUnrecorded, readWorking, unrecordedChanges , readPending, readIndex, invalidateIndex , readRecordedAndPending ) import Darcs.Repository.Internal (Repository(..), RepoType(..), RepoJob(..), maybeIdentifyRepository, identifyRepositoryFor, identifyDarcsRepository, IdentifyRepo(..), findRepository, amInRepository, amNotInRepository, amInHashedRepository, makePatchLazy, withRecorded, readRepo, readTentativeRepo, readRepoUsingSpecificInventory, prefsUrl, withRepoLock, withRepoReadLock, withRepository, withRepositoryDirectory, withGutsOf, tentativelyAddPatch, tentativelyRemovePatches, tentativelyAddToPending, tentativelyReplacePatches, revertRepositoryChanges, finalizeRepositoryChanges, unrevertUrl, applyToWorking, patchSetToPatches, createPristineDirectoryTree, createPartialsPristineDirectoryTree, optimizeInventory, cleanRepository, setScriptsExecutable, setScriptsExecutablePatches, testTentative, testRecorded, makeNewPending, seekRepo ) import Darcs.Repository.Merge( tentativelyMergePatches, considerMergeToWorking ) import Darcs.Repository.Cache ( unionRemoteCaches, fetchFileUsingCache, speculateFileUsingCache, HashedDir(..), Cache(..), CacheLoc(..), WritableOrNot(..), hashedDir , CacheType(Directory), reportBadSources ) import Darcs.Patch.Set ( PatchSet(..), SealedPatchSet, newset2RL, newset2FL, progressPatchSet ) #ifdef GADT_WITNESSES import Darcs.Patch.Set ( Origin ) #endif import URL ( maxPipelineLength ) import Control.Exception ( finally ) import Control.Concurrent ( forkIO ) import Control.Concurrent.MVar ( MVar, newMVar, putMVar, takeMVar ) import Control.Monad ( unless, when ) import System.Directory ( createDirectory, createDirectoryIfMissing, renameFile, doesFileExist, removeFile, getDirectoryContents, getCurrentDirectory, setCurrentDirectory ) import System.IO ( stderr ) import System.IO.Error ( isAlreadyExistsError ) import System.Posix.Files ( createLink ) import qualified Darcs.Repository.HashedRepo as HashedRepo import Darcs.Patch.PatchInfoAnd ( PatchInfoAnd, extractHash ) import Darcs.Repository.ApplyPatches ( applyPatches ) import Darcs.Repository.HashedRepo ( applyToTentativePristine, pris2inv, revertTentativeChanges, copySources ) import Darcs.Repository.InternalTypes ( extractOptions, modifyCache ) import Darcs.Patch ( RepoPatch, PrimOf ) import Darcs.Patch.Apply( ApplyState ) import Darcs.Witnesses.Ordered ( FL(..), RL(..), bunchFL, mapFL, mapRL , lengthRL, (+>+), (:\/:)(..) ) import Darcs.Repository.Format ( RepoProperty ( HashedInventory ), RepoFormat, createRepoFormat, formatHas, writeRepoFormat, readfromAndWritetoProblem) import Darcs.Repository.Prefs ( writeDefaultPrefs ) import Darcs.Patch.Depends ( areUnrelatedRepos, findUncommon ) import Darcs.Utils ( withCurrentDirectory, catchall, promptYorn ) import Darcs.External ( copyFileOrUrl, Cachable(..), fetchFileLazyPS ) import Progress ( debugMessage, tediousSize, beginTedious, endTedious ) import Darcs.ProgressPatches (progressRLShowTags, progressFL) import Darcs.Lock ( writeBinFile, writeDocBinFile, withTemp ) import Darcs.Witnesses.Sealed ( Sealed(..) ) import Darcs.Flags ( DarcsFlag( Verbose, Quiet, Lazy, Complete, AllowUnrelatedRepos, NoUpdateWorking) , compression, UseIndex(..), ScanKnown(..), remoteDarcs , usePacks ) import Darcs.Global ( darcsdir ) import Darcs.URL ( isFile ) import Darcs.SignalHandler ( catchInterrupt ) import Printer ( Doc, text, hPutDocLn, putDocLn ) import Storage.Hashed.Tree( Tree, emptyTree ) import Storage.Hashed.Hash( encodeBase16 ) import Storage.Hashed.Darcs( writeDarcsHashed, darcsAddMissingHashes ) import ByteStringUtils( gzReadFilePS ) import System.FilePath( (), takeFileName, splitPath, joinPath , takeDirectory ) import qualified Codec.Archive.Tar as Tar import Codec.Compression.GZip ( compress, decompress ) import qualified Data.ByteString.Char8 as BS import qualified Data.ByteString.Lazy.Char8 as BL #include "impossible.h" createRepository :: [DarcsFlag] -> IO () createRepository opts = do createDirectory darcsdir `catch` (\e-> if isAlreadyExistsError e then fail "Tree has already been initialized!" else fail $ "Error creating directory `"++darcsdir++"'.") cwd <- getCurrentDirectory x <- seekRepo when (isJust x) $ do setCurrentDirectory cwd putStrLn $ "WARNING: creating a nested repository." let rf = createRepoFormat opts createDirectory $ darcsdir ++ "/pristine.hashed" createDirectory $ darcsdir ++ "/patches" createDirectory $ darcsdir ++ "/prefs" writeDefaultPrefs writeRepoFormat rf (darcsdir++"/format") writeBinFile (darcsdir++"/hashed_inventory") "" writePristine "." emptyTree data RepoSort = Hashed | Old repoSort :: RepoFormat -> RepoSort repoSort f | formatHas HashedInventory f = Hashed | otherwise = Old copyInventory :: forall p C(r u t). (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u t) -> IO () copyInventory fromRepo@(Repo fromDir opts fromFormat (DarcsRepository _ fromCache)) = do toRepo@(Repo toDir opts' toFormat (DarcsRepository toPristine toCache)) <- identifyDarcsRepository opts "." let (_ :: Repository p C(r u t)) = toRepo --The witnesses are wrong, but cannot escape case readfromAndWritetoProblem fromFormat toFormat of Just e -> fail $ "Incompatibility with repository " ++ fromDir ++ ":\n" ++ e Nothing -> return () toCache2 <- unionRemoteCaches toCache fromCache fromDir let toRepo2 :: Repository p C(r u t) toRepo2 = Repo toDir opts' toFormat $ DarcsRepository toPristine toCache2 copyHashedHashed = HashedRepo.copyRepo toRepo2 (remoteDarcs opts) fromDir case repoSort fromFormat of Hashed -> copyHashedHashed Old -> withCurrentDirectory toDir $ do HashedRepo.revertTentativeChanges patches <- readRepo fromRepo let k = "Copying patch" beginTedious k tediousSize k (lengthRL $ newset2RL patches) let patches' = progressPatchSet k patches HashedRepo.writeTentativeInventory toCache (compression opts) patches' endTedious k HashedRepo.finalizeTentativeChanges toRepo $ compression opts copyRepository :: forall p C(r u t). (RepoPatch p, ApplyState (PrimOf p) ~ Tree, ApplyState p ~ Tree) => Repository p C(r u t) -> Bool -> IO () copyRepository fromRepo@(Repo fromDir opts _ _) withWorkingDir = do debugMessage "Copying prefs" copyFileOrUrl (remoteDarcs opts) (fromDir ++ "/" ++ darcsdir ++ "/prefs/prefs") (darcsdir ++ "/prefs/prefs") (MaxAge 600) `catchall` return () -- try packs for remote repositories if (not . isFile) fromDir && usePacks opts then copyPackedRepository fromRepo withWorkingDir else copyNotPackedRepository fromRepo withWorkingDir putInfo :: [DarcsFlag] -> Doc -> IO () putInfo opts = unless (Quiet `elem` opts) . hPutDocLn stderr copyNotPackedRepository :: forall p C(r u t). (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u t) -> Bool -> IO () copyNotPackedRepository fromrepository@(Repo _ opts rffrom _) withWorkingDir = do copyInventory fromrepository debugMessage "Grabbing lock in new repository..." withRepoLock opts $ RepoJob $ \torepository -> if formatHas HashedInventory rffrom then do when withWorkingDir $ do debugMessage "Writing working directory contents..." createPristineDirectoryTree torepository "." fetchPatchesIfNecessary opts torepository `catchInterrupt` (putInfo opts $ text "Using lazy repository.") else do local_patches <- readRepo torepository replacePristine torepository emptyTree let patchesToApply = progressFL "Applying patch" $ newset2FL local_patches sequence_ $ mapFL applyToTentativePristine $ bunchFL 100 patchesToApply finalizeRepositoryChanges torepository when withWorkingDir $ do debugMessage "Writing working directory contents..." createPristineDirectoryTree torepository "." copyPackedRepository :: forall p C(r u t). (RepoPatch p, ApplyState (PrimOf p) ~ Tree, ApplyState p ~ Tree) => Repository p C(r u t) -> Bool -> IO () copyPackedRepository r withWorkingDir = -- fallback to no-packs get in case of error copyPackedRepository2 r withWorkingDir `catchall` copyNotPackedRepository r withWorkingDir copyPackedRepository2 :: forall p C(r u t). (RepoPatch p, ApplyState (PrimOf p) ~ Tree, ApplyState p ~ Tree) => Repository p C(r u t) -> Bool -> IO () copyPackedRepository2 fromRepo@(Repo fromDir opts _ (DarcsRepository _ fromCache)) withWorkingDir = do b <- fetchFileLazyPS (fromDir ++ "/" ++ darcsdir ++ "/packs/basic.tar.gz") Uncachable when (Verbose `elem` opts) $ putDocLn $ text "Getting packed repository." Repo toDir _ toFormat (DarcsRepository toPristine toCache) <- identifyRepositoryFor fromRepo "." toCache2 <- unionRemoteCaches toCache fromCache fromDir let toRepo :: Repository p C(r u r) -- In empty repo, t(entative) = r(ecorded) toRepo = Repo toDir opts toFormat $ DarcsRepository toPristine toCache2 fromPacksDir = fromDir ++ "/" ++ darcsdir ++ "/packs/" createDirectoryIfMissing False $ darcsdir "inventories" copySources toRepo fromDir Repo _ _ _ (DarcsRepository _ toCache3) <- identifyRepositoryFor toRepo "." -- unpack inventory & pristine cache let isLazy = Lazy `elem` opts cleanDir "pristine.hashed" removeFile $ darcsdir "hashed_inventory" unpackBasic toCache3 . Tar.read $ decompress b when withWorkingDir $ createPristineDirectoryTree toRepo "." -- pull new patches us <- readRepo toRepo them <- readRepo fromRepo us' :\/: them' <- return $ findUncommon us them revertTentativeChanges Sealed pw <- tentativelyMergePatches toRepo "get" opts us' them' invalidateIndex toRepo withGutsOf toRepo $ do finalizeRepositoryChanges toRepo when withWorkingDir $ applyToWorking toRepo opts pw >> return () return () -- get old patches unless isLazy $ (do cleanDir "patches" putInfo opts $ text "Copying patches, to get lazy repository hit ctrl-C..." unpackPatches toCache3 (mapFL hashedPatchFileName $ newset2FL us) . Tar.read . decompress =<< fetchFileLazyPS (fromPacksDir ++ "patches.tar.gz") Uncachable ) `catchInterrupt` (putInfo opts $ text "Using lazy repository.") where cleanDir d = mapM_ (\x -> removeFile $ darcsdir d x) . filter (\x -> head x /= '.') =<< getDirectoryContents (darcsdir d) withControlMVar :: (MVar () -> IO ()) -> IO () withControlMVar f = do mv <- newMVar () f mv takeMVar mv forkWithControlMVar :: MVar () -> IO () -> IO () forkWithControlMVar mv f = do takeMVar mv _ <- forkIO $ flip finally (putMVar mv ()) f return () removeMetaFiles :: IO () removeMetaFiles = mapM_ (removeFile . (darcsdir )) . filter ("meta-" `isPrefixOf`) =<< getDirectoryContents darcsdir #if MIN_VERSION_tar(0,4,0) unpackBasic :: Exception e => Cache -> Tar.Entries e -> IO () #else unpackBasic :: Cache -> Tar.Entries -> IO () #endif unpackBasic c x = do withControlMVar $ \mv -> unpackTar c (basicMetaHandler c mv) x removeMetaFiles #if MIN_VERSION_tar(0,4,0) unpackPatches :: Exception e => Cache -> [String] -> Tar.Entries e -> IO () #else unpackPatches :: Cache -> [String] -> Tar.Entries -> IO () #endif unpackPatches c ps x = do withControlMVar $ \mv -> unpackTar c (patchesMetaHandler c ps mv) x removeMetaFiles #if MIN_VERSION_tar(0,4,0) unpackTar :: Exception e => Cache -> IO () -> Tar.Entries e -> IO () #else unpackTar :: Cache -> IO () -> Tar.Entries -> IO () #endif unpackTar _ _ Tar.Done = return () #if MIN_VERSION_tar(0,4,0) unpackTar _ _ (Tar.Fail e)= throwIO e #else unpackTar _ _ (Tar.Fail e)= fail e #endif unpackTar c mh (Tar.Next x xs) = case Tar.entryContent x of Tar.NormalFile x' _ -> do let p = Tar.entryPath x if "meta-" `isPrefixOf` takeFileName p then do BL.writeFile p x' mh unpackTar c mh xs else do ex <- doesFileExist p if ex then debugMessage $ "Tar thread: STOP " ++ p else do if p == darcsdir "hashed_inventory" then writeFile' Nothing p x' else writeFile' (cacheDir c) p $ compress x' debugMessage $ "Tar thread: GET " ++ p unpackTar c mh xs _ -> fail "Unexpected non-file tar entry" where writeFile' Nothing z y = withTemp $ \x' -> do BL.writeFile x' y renameFile x' z writeFile' (Just ca) z y = do let x' = joinPath . tail $ splitPath z -- drop darcsdir ex <- doesFileExist $ ca x' if ex then createLink' (ca x') z else withTemp $ \x'' -> do BL.writeFile x'' y createLink' x'' $ ca x' renameFile x'' z createLink' z y = do createDirectoryIfMissing True $ takeDirectory y createLink z y `catchall` return () basicMetaHandler :: Cache -> MVar () -> IO () basicMetaHandler ca mv = do ex <- doesFileExist $ darcsdir "meta-filelist-pristine" when ex . forkWithControlMVar mv $ fetchFilesUsingCache ca HashedPristineDir . lines =<< readFile (darcsdir "meta-filelist-pristine") return () patchesMetaHandler :: Cache -> [String] -> MVar () -> IO () patchesMetaHandler ca ps mv = do ex <- doesFileExist $ darcsdir "meta-filelist-inventories" when ex $ do forkWithControlMVar mv $ fetchFilesUsingCache ca HashedPristineDir . lines =<< readFile (darcsdir "meta-filelist-inventories") forkWithControlMVar mv $ fetchFilesUsingCache ca HashedPatchesDir ps return () cacheDir :: Cache -> Maybe String cacheDir (Ca cs) = listToMaybe . catMaybes .flip map cs $ \x -> case x of Cache Directory Writable x' -> Just x' _ -> Nothing hashedPatchFileName :: PatchInfoAnd p C(a b) -> String hashedPatchFileName x = case extractHash x of Left _ -> fail "unexpected unhashed patch" Right h -> h -- | fetchFilesUsingCache is similar to mapM fetchFileUsingCache, exepts -- it stops execution if file it's going to fetch already exists. fetchFilesUsingCache :: Cache -> HashedDir -> [FilePath] -> IO () fetchFilesUsingCache _ _ [] = return () fetchFilesUsingCache c d (f:fs) = do ex <- doesFileExist $ darcsdir hashedDir d f if ex then debugMessage $ "Cache thread: STOP " ++ (darcsdir hashedDir d f) else do debugMessage $ "Cache thread: GET " ++ (darcsdir hashedDir d f) -- Warning: A do-notation statement discarded a result of type (String, BS.ByteString). _ <- fetchFileUsingCache c d f fetchFilesUsingCache c d fs -- | writePatchSet is like patchSetToRepository, except that it doesn't -- touch the working directory or pristine cache. writePatchSet :: (RepoPatch p, ApplyState p ~ Tree) => PatchSet p C(Origin x) -> [DarcsFlag] -> IO (Repository p C(r u t)) writePatchSet patchset opts = do maybeRepo <- maybeIdentifyRepository opts "." let repo@(Repo _ _ _ (DarcsRepository _ c)) = case maybeRepo of GoodRepository r -> r BadRepository e -> bug ("Current directory is a bad repository in writePatchSet: " ++ e) NonRepository e -> bug ("Current directory not a repository in writePatchSet: " ++ e) debugMessage "Writing inventory" HashedRepo.writeTentativeInventory c (compression opts) patchset HashedRepo.finalizeTentativeChanges repo (compression opts) return repo -- | patchSetToRepository takes a patch set, and writes a new repository in the current directory -- that contains all the patches in the patch set. This function is used when 'darcs get'ing a -- repository with the --to-match flag and the new repository is not in hashed format. -- This function does not (yet) work for hashed repositories. If the passed @DarcsFlag@s tell -- darcs to create a hashed repository, this function will call @error@. patchSetToRepository :: (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r1 u1 r1) -> PatchSet p C(Origin x) -> [DarcsFlag] -> IO (Repository p C(r u t)) patchSetToRepository (Repo fromrepo _ rf _) patchset opts = do when (formatHas HashedInventory rf) $ -- set up sources and all that do writeFile "_darcs/tentative_pristine" "" -- this is hokey repox <- writePatchSet patchset opts HashedRepo.copyRepo repox (remoteDarcs opts) fromrepo repo <- writePatchSet patchset opts readRepo repo >>= (applyPatches . newset2FL) debugMessage "Writing the pristine" pristineFromWorking repo return repo checkUnrelatedRepos :: RepoPatch p => [DarcsFlag] -> PatchSet p C(start x) -> PatchSet p C(start y) -> IO () checkUnrelatedRepos opts _ _ | AllowUnrelatedRepos `elem` opts = return () checkUnrelatedRepos _ us them = if areUnrelatedRepos us them then do confirmed <- promptYorn "Repositories seem to be unrelated. Proceed?" unless confirmed $ do putStrLn "Cancelled." exitWith ExitSuccess else return () -- | Unless a flag has been given in the first argument that tells darcs not to do so (--lazy, -- or --partial), this function fetches all patches that the given repository has -- with fetchFileUsingCache. This is used as a helper in copyRepository. fetchPatchesIfNecessary :: forall p C(r u t). (RepoPatch p, ApplyState p ~ Tree) => [DarcsFlag] -> Repository p C(r u t) -> IO () fetchPatchesIfNecessary opts torepository@(Repo _ _ _ (DarcsRepository _ c)) = unless (Lazy `elem` opts) $ do unless (Complete `elem` opts) $ putInfo opts $ text "Copying patches, to get lazy repository hit ctrl-C..." r <- readRepo torepository pipelineLength <- maxPipelineLength let patches = newset2RL r ppatches = progressRLShowTags "Copying patches" patches (first, other) = splitAt (pipelineLength - 1) $ tail $ hashes patches speculate | pipelineLength > 1 = [] : first : map (:[]) other | otherwise = [] mapM_ fetchAndSpeculate $ zip (hashes ppatches) (speculate ++ repeat []) where hashes :: FORALL(x y) RL (PatchInfoAnd p) C(x y) -> [String] hashes = catMaybes . mapRL ((either (const Nothing) Just) . extractHash) fetchAndSpeculate :: (String, [String]) -> IO () fetchAndSpeculate (f, ss) = do -- Warning: A do-notation statement discarded a result of type (String, BS.ByteString). _ <- fetchFileUsingCache c HashedPatchesDir f mapM_ (speculateFileUsingCache c HashedPatchesDir) ss addToPending :: (RepoPatch p, ApplyState p ~ Tree) => Repository p C(r u t) -> FL (PrimOf p) C(u y) -> IO () addToPending (Repo _ opts _ _) _ | NoUpdateWorking `elem` opts = return () addToPending repo@(Repo{}) p = do pend <- unrecordedChanges (UseIndex, ScanKnown) repo Nothing invalidateIndex repo makeNewPending repo (pend +>+ p) -- | Replace the existing pristine with a new one (loaded up in a Tree object). replacePristine :: Repository p C(r u t) -> Tree IO -> IO () replacePristine (Repo r _ _ _) = writePristine r writePristine :: FilePath -> Tree IO -> IO () writePristine r tree = withCurrentDirectory r $ do let t = darcsdir "hashed_inventory" i <- gzReadFilePS t tree' <- darcsAddMissingHashes tree root <- writeDarcsHashed tree' $ darcsdir "pristine.hashed" writeDocBinFile t $ pris2inv (BS.unpack $ encodeBase16 root) i pristineFromWorking :: RepoPatch p => Repository p C(r u t) -> IO () pristineFromWorking repo@(Repo dir _ _ _) = withCurrentDirectory dir $ readWorking >>= replacePristine repo darcs-2.8.4/src/Darcs/Resolution.hs0000644001765600176560000001611512104371431016467 0ustar ganeshganesh-- Copyright (C) 2003,2005 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP #-} #include "gadts.h" module Darcs.Resolution ( standardResolution, externalResolution, patchsetConflictResolutions, ) where import System.FilePath.Posix ( () ) import System.Exit ( ExitCode( ExitSuccess ) ) import System.Directory ( setCurrentDirectory, getCurrentDirectory ) import Data.List ( zip4 ) import Control.Monad ( when ) import Darcs.Diff( treeDiff ) import Darcs.Patch ( PrimOf, PrimPatch, RepoPatch, joinPatches, resolveConflicts, effectOnFilePaths, patchcontents, invert, listConflictedFiles, commute, applyToTree, fromPrim ) import Darcs.Patch.Apply( ApplyState ) import Darcs.RepoPath ( toFilePath ) import Darcs.Witnesses.Ordered ( FL(..), RL(..), (:>)(..), (+>+), mapFL_FL, reverseRL ) import CommandLine ( parseCmd ) import Darcs.Patch.PatchInfoAnd ( hopefully ) import Darcs.Utils ( askEnter, filterFilePaths ) import Darcs.Patch.Set ( PatchSet(..) ) #ifdef GADT_WITNESSES import Darcs.Patch.Set ( Origin ) #endif import Darcs.Witnesses.Sealed ( Sealed(..), unFreeLeft ) import Darcs.Repository.Prefs ( filetypeFunction ) import Exec ( exec, Redirect(..) ) import Darcs.Lock ( withTempDir ) import Darcs.External ( cloneTree ) import Darcs.Flags ( DarcsFlag, wantGuiPause ) import qualified Storage.Hashed.Tree as Tree import Storage.Hashed ( writePlainTree, readPlainTree ) --import Darcs.ColorPrinter ( traceDoc ) --import Printer ( greenText, ($$), Doc ) --import Darcs.Patch ( showPatch ) standardResolution :: RepoPatch p => FL p C(x y) -> Sealed (FL (PrimOf p) C(y)) standardResolution p = mergeList $ map head $ resolveConflicts p mergeList :: forall prim C(x) . PrimPatch prim => [Sealed (FL prim C(x))] -> Sealed (FL prim C(x)) mergeList patches = doml NilFL patches where doml :: FL prim C(x y) -> [Sealed (FL prim C(x))] -> Sealed (FL prim C(x)) doml mp (Sealed p:ps) = case commute (invert p :> mp) of Just (mp' :> _) -> doml (p +>+ mp') ps Nothing -> doml mp ps -- This shouldn't happen for "good" resolutions. doml mp [] = Sealed mp externalResolution :: forall p C(x y z a). (RepoPatch p, ApplyState p ~ Tree.Tree) => Tree.Tree IO -> String -- ^ external merge tool command -> [DarcsFlag] -- ^ command line arguments -> FL (PrimOf p) C(x y) -> FL (PrimOf p) C(x z) -> FL p C(y a) -> IO (Sealed (FL (PrimOf p) C(a))) externalResolution s1 c opts p1_prim p2_prim pmerged = do -- TODO: remove the following two once we can rely on GHC 7.2 / superclass equality let p1 :: FL p C(x y) = mapFL_FL fromPrim p1_prim p2 :: FL p C(x z) = mapFL_FL fromPrim p2_prim sa <- applyToTree (invert p1) s1 sm <- applyToTree pmerged s1 s2 <- applyToTree p2 sa let effectOnFPs ps fps = effectOnFilePaths ps fps nms = listConflictedFiles pmerged nas = effectOnFPs (invert pmerged) nms n1s = effectOnFPs p1 nas n2s = effectOnFPs p2 nas ns = zip4 nas n1s n2s nms write_files tree fs = writePlainTree (Tree.filter (filterFilePaths fs) tree) "." in do former_dir <- getCurrentDirectory withTempDir "version1" $ \absd1 -> do let d1 = toFilePath absd1 write_files s1 n1s setCurrentDirectory former_dir withTempDir "ancestor" $ \absda -> do let da = toFilePath absda write_files sa nas setCurrentDirectory former_dir withTempDir "merged" $ \absdm -> do let dm = toFilePath absdm write_files sm nms setCurrentDirectory former_dir withTempDir "cleanmerged" $ \absdc -> do let dc = toFilePath absdc cloneTree dm "." setCurrentDirectory former_dir withTempDir "version2" $ \absd2 -> do let d2 = toFilePath absd2 write_files s2 n2s mapM_ (externallyResolveFile c opts da d1 d2 dm) ns sc <- readPlainTree dc sfixed <- readPlainTree dm ftf <- filetypeFunction unFreeLeft `fmap` treeDiff ftf sc sfixed externallyResolveFile :: String -- ^ external merge tool command -> [DarcsFlag] -- ^ command line arguments -> String -- ^ path to merge base -> String -- ^ path to side 1 of the merge -> String -- ^ path to side 2 of the merge -> String -- ^ path where resolved content should go -> (FilePath, FilePath, FilePath, FilePath) -> IO () externallyResolveFile c opts da d1 d2 dm (fa, f1, f2, fm) = do putStrLn $ "Merging file "++fm++" by hand." ec <- run c [('1', d1f1), ('2', d2f2), ('a', dafa), ('o', dmfm), ('%', "%")] when (ec /= ExitSuccess) $ putStrLn $ "External merge command exited with " ++ show ec when (wantGuiPause opts) $ askEnter "Hit return to move on, ^C to abort the whole operation..." run :: String -> [(Char,String)] -> IO ExitCode run c replacements = case parseCmd replacements c of Left err -> fail $ show err Right (c2,_) -> rr c2 where rr (command:args) = do putStrLn $ "Running command '" ++ unwords (command:args) ++ "'" exec command args (Null,Null,Null) rr [] = return ExitSuccess patchsetConflictResolutions :: RepoPatch p => PatchSet p C(Origin x) -> Sealed (FL (PrimOf p) C(x)) patchsetConflictResolutions (PatchSet NilRL _) = Sealed NilFL patchsetConflictResolutions (PatchSet xs _) = --traceDoc (greenText "looking at resolutions" $$ -- (sh $ resolveConflicts $ joinPatches $ -- mapFL_FL (patchcontents . hopefully) $ reverseRL xs )) $ mergeList $ map head $ resolveConflicts $ joinPatches $ mapFL_FL (patchcontents . hopefully) $ reverseRL xs --where sh :: [[Sealed (FL Prim)]] -> Doc -- sh [] = greenText "no more conflicts" -- sh (x:ps) = greenText "one conflict" $$ sh1 x $$ sh ps -- sh1 :: [Sealed (FL Prim)] -> Doc -- sh1 [] = greenText "end of unravellings" -- sh1 (Sealed x:ps) = greenText "one unravelling:" $$ showPatch x $$ -- sh1 ps darcs-2.8.4/src/Darcs/RunCommand.hs0000644001765600176560000002115712104371431016371 0ustar ganeshganesh-- Copyright (C) 2002,2003,2005 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP #-} module Darcs.RunCommand ( runTheCommand ) where import Control.Monad ( unless, when ) import System.Console.GetOpt( ArgOrder( Permute, RequireOrder ), OptDescr( Option ), getOpt ) import System.Exit ( ExitCode ( ExitSuccess ), exitWith ) import Darcs.Arguments ( DarcsFlag(..), help, fixUrlFlag, optionFromDarcsOption, listOptions, nubOptions ) import Darcs.ArgumentDefaults ( getDefaultFlags ) import Darcs.Commands ( CommandArgs( CommandOnly, SuperCommandOnly, SuperCommandSub ), CommandControl, DarcsCommand, commandName, commandCommand, commandPrereq, commandExtraArgHelp, commandExtraArgs, commandArgdefaults, commandGetArgPossibilities, commandOptions, commandAlloptions, disambiguateCommands, getCommandHelp, getCommandMiniHelp, getSubcommands, extractCommands, superName, subusage, chompNewline ) import Darcs.Commands.GZCRCs ( doCRCWarnings ) import Darcs.Global ( atexit ) import Darcs.External ( viewDoc ) import Darcs.Global ( setDebugMode, setTimingsMode ) import Darcs.Match ( checkMatchSyntax ) import Progress ( setProgressMode ) import Darcs.RepoPath ( getCurrentDirectory ) import Darcs.Test ( runPosthook, runPrehook ) import Darcs.Utils ( formatPath ) import Data.List ( intercalate ) import Printer ( text ) import URL ( setDebugHTTP, disableHTTPPipelining ) runTheCommand :: [CommandControl] -> String -> [String] -> IO () runTheCommand commandControlList cmd args = either fail rtc $ disambiguateCommands commandControlList cmd args where rtc (CommandOnly c, as) = runCommand Nothing c as rtc (SuperCommandOnly c, as) = runRawSupercommand c as rtc (SuperCommandSub c s, as) = runCommand (Just c) s as -- This is the actual heavy lifter code, which is responsible for parsing the -- arguments and then running the command itself. runCommand :: Maybe DarcsCommand -> DarcsCommand -> [String] -> IO () runCommand _ _ args -- Check for "dangerous" typoes... | "-all" `elem` args = -- -all indicates --all --look-for-adds! fail "Are you sure you didn't mean --all rather than -all?" runCommand msuper cmd args = do cwd <- getCurrentDirectory let options = opts1 ++ opts2 (opts1, opts2) = commandOptions cwd cmd case getOpt Permute (optionFromDarcsOption cwd listOptions++options) args of (opts,extra,[]) | Help `elem` opts -> viewDoc $ text $ getCommandHelp msuper cmd | ListOptions `elem` opts -> do setProgressMode False -- Warning: A do-notation statement discarded a result of type Either String (). _ <- commandPrereq cmd opts file_args <- commandGetArgPossibilities cmd putStrLn $ unlines $ getOptionsOptions (opts1++opts2) : file_args | otherwise -> considerRunning msuper cmd (addVerboseIfDebug opts) extra (_,_,ermsgs) -> fail $ chompNewline(unlines ermsgs) where addVerboseIfDebug opts | DebugVerbose `elem` opts = Debug:Verbose:opts | otherwise = opts considerRunning :: Maybe DarcsCommand -> DarcsCommand -> [DarcsFlag] -> [String] -> IO () considerRunning msuper cmd opts old_extra = do cwd <- getCurrentDirectory location <- commandPrereq cmd opts case location of Left complaint -> fail $ "Unable to " ++ formatPath ("darcs " ++ superName msuper ++ commandName cmd) ++ " here.\n\n" ++ complaint Right () -> do specops <- nubopts `fmap` addCommandDefaults cmd opts extra <- (commandArgdefaults cmd) specops cwd old_extra when (Disable `elem` specops) $ fail $ "Command "++commandName cmd++" disabled with --disable option!" case extraArgumentsError extra cmd msuper of Nothing -> runWithHooks specops extra Just msg -> fail msg where nubopts = nubOptions (uncurry (++) $ commandAlloptions cmd) runWithHooks os ex = do here <- getCurrentDirectory checkMatchSyntax os -- set any global variables when (Timings `elem` os) setTimingsMode when (Debug `elem` os) setDebugMode when (DebugHTTP `elem` os) setDebugHTTP when (Quiet `elem` os) $ setProgressMode False when (NoHTTPPipelining `elem` os) $ disableHTTPPipelining unless (Quiet `elem` os) $ atexit $ doCRCWarnings (Verbose `elem` os) -- actually run the command and its hooks preHookExitCode <- runPrehook os here if preHookExitCode /= ExitSuccess then exitWith preHookExitCode else do let fixFlag = FixFilePath here cwd fixedOs <- mapM (fixUrlFlag [fixFlag]) os (commandCommand cmd) (fixFlag : fixedOs) ex postHookExitCode <- runPosthook os here exitWith postHookExitCode -- Checks if the number of extra arguments matches the number of extra -- arguments supported by the command as specified in `commandExtraArgs`. -- Extra arguments are arguments that follow the command but aren't -- considered a flag. In `darcs push xyz`, xyz would be an extra argument. extraArgumentsError :: [String] -- extra commands provided by user -> DarcsCommand -> Maybe DarcsCommand -> Maybe String extraArgumentsError extra cmd msuper | extraArgsCmd < 0 = Nothing | extraArgsInput > extraArgsCmd = Just badArg | extraArgsInput < extraArgsCmd = Just missingArg | otherwise = Nothing where extraArgsInput = length extra extraArgsCmd = commandExtraArgs cmd badArg = "Bad argument: `" ++ unwords extra ++ "'\n" ++ getCommandMiniHelp msuper cmd missingArg = "Missing argument: " ++ nthArg (length extra + 1) ++ "\n" ++ getCommandMiniHelp msuper cmd nthArg n = nthOf n (commandExtraArgHelp cmd) nthOf 1 (h:_) = h nthOf n (_:hs) = nthOf (n-1) hs nthOf _ [] = "UNDOCUMENTED" addCommandDefaults :: DarcsCommand -> [DarcsFlag] -> IO [DarcsFlag] addCommandDefaults cmd already = do let (opts1, opts2) = commandAlloptions cmd defaults <- getDefaultFlags (commandName cmd) (opts1 ++ opts2) already return $ already ++ defaults getOptionsOptions :: [OptDescr DarcsFlag] -> String getOptionsOptions = intercalate "\n" . concatMap goo where goo (Option _ os _ _) = map ("--"++) os runRawSupercommand :: DarcsCommand -> [String] -> IO () runRawSupercommand super [] = fail $ "Command '"++ commandName super ++"' requires subcommand!\n\n" ++ subusage super runRawSupercommand super args = do cwd <- getCurrentDirectory case getOpt RequireOrder (optionFromDarcsOption cwd help++ optionFromDarcsOption cwd listOptions) args of (opts,_,[]) | Help `elem` opts -> viewDoc $ text $ getCommandHelp Nothing super | ListOptions `elem` opts -> do putStrLn "--help" mapM_ (putStrLn . commandName) (extractCommands $ getSubcommands super) | otherwise -> if Disable `elem` opts then fail $ "Command " ++ (commandName super) ++ " disabled with --disable option!" else fail $ "Invalid subcommand!\n\n" ++ subusage super (_,_,ermsgs) -> fail $ chompNewline(unlines ermsgs) darcs-2.8.4/src/Darcs/SelectChanges.hs0000644001765600176560000011330512104371431017033 0ustar ganeshganesh-- Copyright (C) 2002-2003 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP, ForeignFunctionInterface #-} #include "gadts.h" module Darcs.SelectChanges (selectChanges, WhichChanges(..), viewChanges, withSelectedPatchFromRepo, filterOutConflicts, runSelection, selectionContextPrim, selectionContext ) where import Data.List ( intersperse ) import Data.Maybe ( isJust, isNothing ) import Data.Char ( toUpper ) import Control.Monad ( when, (>=>) ) import Control.Monad.Identity ( Identity(..) ) import Control.Monad.Trans ( liftIO ) import Control.Monad.Reader ( ReaderT, Reader, asks, runReader, runReaderT ) import Control.Monad.State ( StateT, modify, gets, runStateT, execStateT ) import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import English ( Noun(..), englishNum ) import Darcs.Arguments ( showFriendly ) import Darcs.Patch.PatchInfoAnd ( PatchInfoAnd, hopefully, n2pia ) import Darcs.Repository ( Repository, readRepo, unrecordedChanges ) import Darcs.Patch ( RepoPatch, Patchy, PrimPatch, summary, invert, listTouchedFiles, commuteFLorComplain, fromPrims, anonymous ) import Darcs.Patch.Set ( newset2RL ) import Darcs.Patch.Apply( ApplyState ) import qualified Darcs.Patch ( thing, things ) import Darcs.Patch.Split ( Splitter(..) ) import Darcs.Witnesses.Ordered ( FL(..), RL(..), (:>)(..), (:||:)(..), (+>+), lengthFL, mapFL_FL, spanFL, spanFL_M, reverseFL, (+<+), mapFL, filterFL ) import Darcs.Witnesses.WZipper( FZipper(..), left, right , rightmost, nullFZ , toEnd, toStart) import Darcs.Patch.Choices ( PatchChoices, patchChoices, patchChoicesTpsSub, forceFirst, forceLast, makeUncertain, tag, getChoices, refineChoices, separateFirstFromMiddleLast, patchSlot', selectAllMiddles, forceMatchingLast, forceMatchingFirst, makeEverythingLater, makeEverythingSooner, TaggedPatch, tpPatch, Slot(..), substitute ) import Darcs.Patch.Permutations ( partitionConflictingFL, selfCommuter, commuterIdRL ) import qualified Darcs.Patch.TouchesFiles as TouchesFiles import Darcs.PrintPatch ( printFriendly, printPatch, printPatchPager ) import Darcs.Match ( haveNonrangeMatch, matchAPatch, matchAPatchread ) import Darcs.Flags ( DarcsFlag( Summary, DontGrabDeps, Verbose, DontPromptForDependencies , SkipConflicts ) , isInteractive, UseIndex(..), ScanKnown(..) ) import Darcs.Witnesses.Sealed ( FlippedSeal(..), flipSeal, seal2, unseal2, Sealed(..), Sealed2(..) ) import Darcs.Utils ( askUser, promptChar, PromptConfig(..) ) import Darcs.Lock ( editText ) import Printer ( prefix, putDocLn ) import Storage.Hashed.Tree( Tree ) -- | When asking about patches, we either ask about them in -- oldest-first or newest first (with respect to the current ordering -- of the repository), and we either want an initial segment or a -- final segment of the poset of patches. -- -- @First@: ask for an initial -- segment, first patches first (default for all pull-like commands) -- -- @FirstReversed@: ask for an initial segment, last patches first -- (used to ask about dependencies in record, and for pull-like -- commands with the @--reverse@ flag). -- -- @LastReversed@: ask for a final segment, last patches first. (default -- for unpull-like commands, except for selecting *primitive* patches in -- rollback) -- -- @Last@: ask for a final segment, first patches first. (used for selecting -- primitive patches in rollback, and for unpull-like commands with the -- @--reverse@ flag data WhichChanges = Last | LastReversed | First | FirstReversed deriving (Eq, Show) -- | A @WhichChanges@ is backwards if the order in which patches are presented -- is the opposite of the order of dependencies for that operation. backward :: WhichChanges -> Bool backward w = w == Last || w == FirstReversed -- | The type of the function we use to filter patches when @--match@ is -- given. type MatchCriterion p = WhichChanges -> [DarcsFlag] -> Sealed2 p -> Bool -- | A @PatchSelectionContext@ contains all the static settings for selecting -- patches. See "PatchSelectionM" data PatchSelectionContext p = PSC { opts :: [DarcsFlag] , splitter :: Maybe (Splitter p) , files :: Maybe [FilePath] , matchCriterion :: MatchCriterion p , jobname :: String , pristine :: Maybe (Tree IO)} -- | A 'PatchSelectionContext' for selecting 'Prim' patches. selectionContextPrim :: PrimPatch prim => String -> [DarcsFlag] -> Maybe (Splitter prim) -> Maybe [FilePath] -> Maybe (Tree IO) -> PatchSelectionContext prim selectionContextPrim jn o spl fs p = PSC { opts = o , splitter = spl , files = fs , matchCriterion = triv , jobname = jn , pristine = p } -- | A 'PatchSelectionContext' for selecting full patches ('PatchInfoAnd' patches) selectionContext :: (RepoPatch p) => String -> [DarcsFlag] -> Maybe (Splitter (PatchInfoAnd p)) -> Maybe [FilePath] -> PatchSelectionContext (PatchInfoAnd p) selectionContext jn o spl fs = PSC { opts = o , splitter = spl , files = fs , matchCriterion = iswanted , jobname = jn , pristine = Nothing } -- | The dynamic parameters for interactive selection of patches. data InteractiveSelectionContext p C(x y) = ISC { total :: Int -- ^ total number of patches , current :: Int -- ^ number of already-seen patches , tps :: FZipper (TaggedPatch p) C(x y) -- ^ the patches we offer , choices :: PatchChoices p C(x y) -- ^ the user's choices } type PatchSelectionM p a = ReaderT (PatchSelectionContext p) a type InteractiveSelectionM p C(x y) a = StateT (InteractiveSelectionContext p C(x y)) (PatchSelectionM p IO) a type PatchSelection p C(x y) = PatchSelectionM p IO ((FL p :> FL p) C(x y)) -- Common match criteria -- | For commands without @--match@, 'triv' matches all patches triv :: MatchCriterion p triv = \ _ _ _ -> True -- | 'iswanted' selects patches according to the @--match@ flag in -- opts' iswanted :: Patchy p => MatchCriterion (PatchInfoAnd p) iswanted whch opts' = unseal2 (iw whch) where iw First = matchAPatch opts' . hopefully iw Last = matchAPatch opts' . hopefully iw LastReversed = matchAPatch opts' . hopefully . invert iw FirstReversed = matchAPatch opts' . hopefully . invert liftR :: Monad m => Reader r a -> ReaderT r m a liftR = asks . runReader -- | runs a 'PatchSelection' action in the given 'PatchSelectionContext'. runSelection :: (Patchy p) => PatchSelection p C(x y) -> PatchSelectionContext p -> IO ((FL p :> FL p) C(x y)) runSelection = runReaderT -- | Select patches from a @FL@. selectChanges :: forall p C(x y) . (Patchy p, ApplyState p ~ Tree) => WhichChanges -> FL p C(x y) -> PatchSelection p C(x y) selectChanges First = sc1 First selectChanges Last = sc1 Last selectChanges FirstReversed = return . invert >=> sc1 FirstReversed >=> return . invertC selectChanges LastReversed = return . invert >=> sc1 LastReversed >=> return . invertC sc1 :: forall p C(x y) . (Patchy p, ApplyState p ~ Tree) => WhichChanges -> FL p C(x y) -> PatchSelection p C(x y) sc1 whch = ((liftR . patchesToConsider whch) >=> realSelectChanges whch >=> return . selectedPatches whch >=> (liftR . canonizeAfterSplitter)) -- | inverses the choices that have been made invertC :: (Patchy p) => (FL p :> FL p) C(x y) -> (FL p :> FL p) C(y x) invertC (a :> b) = (invert b) :> (invert a) -- | Shows the patch that is actually being selected the way the user -- should see it. repr :: (Patchy p) => WhichChanges -> Sealed2 p -> Sealed2 p repr First (Sealed2 p) = Sealed2 p repr LastReversed (Sealed2 p) = Sealed2 (invert p) repr Last (Sealed2 p) = Sealed2 p repr FirstReversed (Sealed2 p) = Sealed2 (invert p) -- | The equivalent of 'selectChanges' for the @darcs changes@ command viewChanges :: (Patchy p, ApplyState p ~ Tree) => [DarcsFlag] -> [Sealed2 p] -> IO () viewChanges opts' ps = textView opts' Nothing 0 [] ps -- | The type of the answers to a "shall I [wiggle] that [foo]?" question -- They are found in a [[KeyPress]] bunch, each list representing a set of -- answers which belong together data KeyPress = KeyPress { kp :: Char , kpHelp :: String } -- | Generates the help for a set of basic and advanced 'KeyPress' groups. helpFor :: String -> [[KeyPress]] -> [[KeyPress]] -> String helpFor jn basicKeypresses advancedKeyPresses = unlines $ [ "How to use "++jn++":" ] ++ (concat $ intersperse [""] $ map (map help) keypresses) ++ [ "" , "?: show this help" , "" , ": accept the current default (which is capitalized)" ] where help i = kp i:(": "++kpHelp i) keypresses = basicKeypresses ++ advancedKeyPresses -- | The keys used by a list of 'keyPress' groups. keysFor :: [[KeyPress]] -> [Char] keysFor = concatMap (map kp) -- | The function for selecting a patch to amend record. Read at your own risks. withSelectedPatchFromRepo :: forall p C(r u t). (RepoPatch p, ApplyState p ~ Tree) => String -- name of calling command (always "amend" as of now) -> Repository p C(r u t) -> [DarcsFlag] -> (FORALL(a) (FL (PatchInfoAnd p) :> PatchInfoAnd p) C(a r) -> IO ()) -> IO () withSelectedPatchFromRepo jn repository o job = do patchSet <- readRepo repository sp <- wspfr jn (matchAPatchread o) (newset2RL patchSet) NilFL case sp of Just (FlippedSeal (skipped :> selected')) -> job (skipped :> selected') Nothing -> putStrLn $ "Cancelling " ++ jn ++ " since no patch was selected." -- | This ensures that the selected patch commutes freely with the skipped -- patches, including pending and also that the skipped sequences has an -- ending context that matches the recorded state, z, of the repository. wspfr :: (RepoPatch p, ApplyState p ~ Tree) => String -> (FORALL(a b) (PatchInfoAnd p) C(a b) -> Bool) -> RL (PatchInfoAnd p) C(x y) -> FL (PatchInfoAnd p) C(y u) -> IO (Maybe (FlippedSeal (FL (PatchInfoAnd p) :> (PatchInfoAnd p)) C(u))) wspfr _ _ NilRL _ = return Nothing wspfr jn matches remaining@(p:<:pps) skipped | not $ matches p = wspfr jn matches pps (p:>:skipped) | otherwise = case commuteFLorComplain (p :> skipped) of Left _ -> do putStrLn "\nSkipping depended-upon patch:" printFriendly Nothing [] p wspfr jn matches pps (p:>:skipped) Right (skipped' :> p') -> do printFriendly Nothing [] p yorn <- promptChar $ PromptConfig { pPrompt = prompt' , pBasicCharacters = keysFor basicOptions , pAdvancedCharacters = keysFor advancedOptions , pDefault = Just 'n' , pHelp = "?h" } case yorn of 'y' -> return $ Just $ flipSeal $ skipped' :> p' 'n' -> nextPatch 'j' -> nextPatch 'k' -> case skipped of NilFL -> repeatThis (prev :>: skipped') -> wspfr jn matches (prev :<: remaining) skipped' 'v' -> printPatch p >> repeatThis 'p' -> printPatchPager p >> repeatThis 'x' -> do putDocLn $ prefix " " $ summary p repeatThis 'q' -> do putStrLn $ jnCapital ++ " cancelled." exitWith $ ExitSuccess _ -> do putStrLn $ helpFor jn basicOptions advancedOptions repeatThis where jnCapital = (toUpper $ head jn) : tail jn repeatThis = wspfr jn matches (p:<:pps) skipped prompt' = "Shall I " ++ jn ++ " this patch?" nextPatch = wspfr jn matches pps (p:>:skipped) basicOptions = [[ KeyPress 'y' (jn ++ " this patch") , KeyPress 'n' ("don't " ++ jn ++ " it") , KeyPress 'j' "skip to next patch" , KeyPress 'k' "back up to previous patch" ]] advancedOptions = [[ KeyPress 'v' "view this patch in full" , KeyPress 'p' "view this patch in full with pager" , KeyPress 'x' "view a summary of this patch" , KeyPress 'q' ("cancel " ++ jn) ]] -- After selecting with a splitter, the results may not be canonical canonizeAfterSplitter :: (FL p :> FL p) C(x y) -> Reader (PatchSelectionContext p) ((FL p :> FL p) C(x y)) canonizeAfterSplitter (x :> y) = do mspl <- asks splitter let canonizeIfNeeded = maybe id canonizeSplit mspl return $ canonizeIfNeeded x :> canonizeIfNeeded y realSelectChanges :: forall p C(x y). (Patchy p, ApplyState p ~ Tree) => WhichChanges -> PatchChoices p C(x y) -> PatchSelectionM p IO (PatchChoices p C(x y)) realSelectChanges whch autoChoices = do o <- asks opts if not $ isInteractive o then return $ promote autoChoices else refineChoices (textSelect whch) autoChoices where forward = not $ backward whch promote = if forward then makeEverythingSooner else makeEverythingLater -- | When using @--match@, remove unmatched patches not depended upon by matched -- patches. deselectUnwanted :: forall p C(x y) . Patchy p => WhichChanges -> PatchChoices p C(x y) -> Reader (PatchSelectionContext p) (PatchChoices p C(x y)) deselectUnwanted whichch pc = do o <- asks opts c <- asks matchCriterion let iswanted_ = c whichch o . seal2 . tpPatch select = if forward then forceMatchingFirst iswanted_ else forceMatchingLast iswanted_ deselect = if forward then forceMatchingLast (not . iswanted_) else forceMatchingFirst (not . iswanted_) return $ if haveNonrangeMatch o then if DontGrabDeps `elem` o then deselect pc else demote $ select pc else pc where forward = not $ backward whichch demote = if forward then makeEverythingLater else makeEverythingSooner -- | Selects the patches matching the match criterion, and puts them first or last -- according to whch, while respecting any dependencies. patchesToConsider :: (Patchy p, ApplyState p ~ Tree) => WhichChanges -> FL p C(x y) -> Reader (PatchSelectionContext p) (PatchChoices p C(x y)) patchesToConsider whch ps = do fs <- asks files o <- asks opts let deselectNotTouching = case whch of First -> TouchesFiles.deselectNotTouching Last -> TouchesFiles.selectNotTouching FirstReversed -> TouchesFiles.selectNotTouching LastReversed -> TouchesFiles.deselectNotTouching everything = patchChoices ps if isNothing fs && not (haveNonrangeMatch o) then return everything else do notUnwanted <- deselectUnwanted whch everything return $ deselectNotTouching fs notUnwanted -- | Returns the results of a patch selection user interaction selectedPatches :: Patchy p => WhichChanges -> PatchChoices p C(y z) -> (FL p :> FL p) C(y z) selectedPatches Last pc = case getChoices pc of fc :> mc :> lc -> mapFL_FL tpPatch (fc +>+ mc) :> mapFL_FL tpPatch lc selectedPatches First pc = case separateFirstFromMiddleLast pc of xs :> ys -> mapFL_FL tpPatch xs :> mapFL_FL tpPatch ys selectedPatches LastReversed pc = case separateFirstFromMiddleLast pc of xs :> ys -> mapFL_FL tpPatch (xs) :> (mapFL_FL tpPatch (ys)) selectedPatches FirstReversed pc = case getChoices pc of fc :> mc :> lc -> (mapFL_FL tpPatch (fc +>+ mc)) :> (mapFL_FL tpPatch lc) -- | Runs a function on the underlying @PatchChoices@ object liftChoices :: forall p a C(x y) . Patchy p => StateT (PatchChoices p C(x y)) Identity a -> InteractiveSelectionM p C(x y) a liftChoices act = do ch <- gets choices let (result, _) = runIdentity $ runStateT act ch modify $ \isc -> isc {choices = ch} -- Should this be ch or the result of runState? return result -- | @justDone n@ notes that @n@ patches have just been processed justDone :: Patchy p => Int -> InteractiveSelectionM p C(x y) () justDone n = modify $ \isc -> isc{ current = current isc + n} -- | The actual interactive selection process. textSelect :: forall p C(x y) . (Patchy p, ApplyState p ~ Tree) => WhichChanges -> FL (TaggedPatch p) C(x y) -> PatchChoices p C(x y) -> PatchSelectionM p IO (PatchChoices p C(x y)) textSelect whch tps' pcs = do userSelection <- execStateT (skipMundane whch >> showCur whch >> textSelectIfAny) $ ISC { total = lengthFL tps' , current = 0 , tps = FZipper NilRL tps' , choices = pcs } return $ choices userSelection where textSelectIfAny = do z <- gets tps if rightmost z then return () else textSelect' whch textSelect' :: (Patchy p, ApplyState p ~ Tree) => WhichChanges -> InteractiveSelectionM p C(x y) () textSelect' whch = do z <- gets tps when (not $ rightmost z) $ do textSelectOne whch textSelect' whch optionsBasic :: [Char] -> [Char] -> [KeyPress] optionsBasic jn aThing = [ KeyPress 'y' (jn++" this "++aThing) , KeyPress 'n' ("don't "++jn++" it") , KeyPress 'w' ("wait and decide later, defaulting to no") ] optionsFile :: [Char] -> [KeyPress] optionsFile jn = [ KeyPress 's' ("don't "++jn++" the rest of the changes to this file") , KeyPress 'f' (jn++" the rest of the changes to this file") ] optionsView :: String -> String -> [KeyPress] optionsView aThing someThings = [ KeyPress 'v' ("view this "++aThing++" in full") , KeyPress 'p' ("view this "++aThing++" in full with pager") , KeyPress 'l' ("list all selected "++someThings) ] optionsSummary :: String -> [KeyPress] optionsSummary aThing = [ KeyPress 'x' ("view a summary of this "++aThing) ] optionsQuit :: String -> String -> [KeyPress] optionsQuit jn someThings = [ KeyPress 'd' (jn++" selected "++someThings++", skipping all the remaining "++someThings) , KeyPress 'a' (jn++" all the remaining "++someThings) , KeyPress 'q' ("cancel "++jn) ] optionsNav :: String -> [KeyPress] optionsNav aThing = [ KeyPress 'j' ("skip to next "++ aThing) , KeyPress 'k' ("back up to previous "++ aThing) , KeyPress 'g' ("start over from the first "++aThing)] optionsSplit :: Maybe (Splitter a) -> String -> [KeyPress] optionsSplit split aThing | Just _ <- split = [ KeyPress 'e' ("interactively edit this "++ aThing) ] | otherwise = [] options :: forall p C(x y) . (Patchy p) => Bool -> InteractiveSelectionM p C(x y) ([[KeyPress]],[[KeyPress]]) options single = do split <- asks splitter jn <- asks jobname aThing <- thing someThings <- things o <- asks opts return $ ([optionsBasic jn aThing] ,[optionsSplit split aThing] ++ (if single then [optionsFile jn ] else []) ++ [optionsView aThing someThings ++ if Summary `elem` o then [] else optionsSummary aThing] ++ [optionsQuit jn someThings] ++ [optionsNav aThing] ) -- | Returns a @Sealed2@ version of the patch we are asking the user -- about. currentPatch :: forall p C(x y) . Patchy p => InteractiveSelectionM p C(x y) (Maybe (Sealed2 (TaggedPatch p))) currentPatch = do (FZipper _ tps_todo) :: FZipper (TaggedPatch p) C(x y) <- gets tps case tps_todo of NilFL -> return Nothing (tp:>:_) -> return $ Just (Sealed2 tp) -- | Returns the patches we have yet to ask the user about. todo :: forall p C(x y) . Patchy p => InteractiveSelectionM p C(x y) (FlippedSeal (FL (TaggedPatch p)) C(y)) todo = do (FZipper _ tps_todo) <- gets tps return (FlippedSeal tps_todo) -- | Modify the underlying @PatchChoices@ by some function modChoices :: forall p C(x y) . Patchy p => (PatchChoices p C(x y) -> PatchChoices p C(x y)) -> InteractiveSelectionM p C(x y) () modChoices f = modify $ \isc -> isc{choices = f $ choices isc} -- | returns @Just f@ if the 'currentPatch' only modifies @f@, -- @Nothing@ otherwise. currentFile :: forall p C(x y) . Patchy p => InteractiveSelectionM p C(x y) (Maybe FilePath) currentFile = do c <- currentPatch return $ case c of Nothing -> Nothing Just (Sealed2 tp) -> case listTouchedFiles tp of [f] -> Just f _ -> Nothing -- | @decide True@ selects the current patch, and @decide False@ deselects -- it. decide :: forall p C(x y t u) . Patchy p => WhichChanges -> Bool -> TaggedPatch p C(t u) -> InteractiveSelectionM p C(x y) () decide whch takeOrDrop tp = if backward whch == takeOrDrop -- we go backward xor we are dropping then modChoices $ forceLast (tag tp) else modChoices $ forceFirst (tag tp) -- | like 'decide', but for all patches touching @file@ decideWholeFile :: forall p C(x y). Patchy p => WhichChanges -> FilePath -> Bool -> InteractiveSelectionM p C(x y) () decideWholeFile whch file takeOrDrop = do FlippedSeal tps_todo <- todo let patches_to_skip = filterFL (\tp' -> listTouchedFiles tp' == [file]) tps_todo mapM_ (unseal2 $ decide whch takeOrDrop) patches_to_skip -- | Undecide the current patch. postponeNext :: forall p C(x y) . Patchy p => InteractiveSelectionM p C(x y) () postponeNext = do Just (Sealed2 tp) <- currentPatch modChoices $ makeUncertain (tag tp) -- | Focus the next patch. skipOne :: forall p C(x y) . Patchy p => InteractiveSelectionM p C(x y) () skipOne = modify so where so x = x{tps = right (tps x), current = current x +1} -- | Focus the previous patch. backOne :: forall p C(x y) . Patchy p => InteractiveSelectionM p C(x y) () backOne = modify so where so isc = isc{tps = left (tps isc), current = max (current isc-1) 0} -- | Split the current patch (presumably a hunk), and add the replace it -- with its parts. splitCurrent :: forall p C(x y) . Patchy p => Splitter p -> InteractiveSelectionM p C(x y) () splitCurrent s = do FZipper tps_done (tp:>:tps_todo) <- gets tps case (applySplitter s (tpPatch tp)) of Nothing -> return () Just (text, parse) -> do newText <- liftIO $ editText "darcs-patch-edit" text case parse newText of Nothing -> return () Just ps -> do tps_new <- liftIO . return . snd $ patchChoicesTpsSub (Just (tag tp)) ps modify $ \isc -> isc { total = ( total isc + lengthFL tps_new - 1 ) , tps = (FZipper tps_done (tps_new +>+ tps_todo)) , choices = (substitute (seal2 (tp :||: tps_new)) (choices isc)) } -- | Returns a list of the currently selected patches, in -- their original context, i.e., not commuted past unselected -- patches. selected :: forall p C(x y). Patchy p => WhichChanges -> InteractiveSelectionM p C(x y) [Sealed2 p] selected whichch = do c <- gets choices (first_chs :> _ :> last_chs) <- return $ getChoices c return $ if backward whichch then mapFL (repr whichch . Sealed2 . tpPatch) $ last_chs else mapFL (repr whichch . Sealed2 . tpPatch) $ first_chs -- | Prints the list of the selected patches. See 'selected'. printSelected :: Patchy p => WhichChanges -> InteractiveSelectionM p C(x y) () printSelected whichch = do someThings <- things o <- asks opts s <- selected whichch liftIO $ do putStrLn $ "---- Already selected "++someThings++" ----" mapM_ (putDocLn . unseal2 (showFriendly o)) s putStrLn $ "---- end of already selected "++someThings++" ----" printSummary :: forall p C(x y) . Patchy p => p C(x y) -> IO () printSummary = putDocLn . prefix " " . summary -- | Skips all remaining patches. skipAll :: forall p C(x y) . Patchy p => InteractiveSelectionM p C(x y) () skipAll = do modify $ \isc -> isc {tps = toEnd $ tps isc} backAll :: forall p C(x y) . Patchy p => InteractiveSelectionM p C(x y) () backAll = do modify $ \isc -> isc {tps = toStart $ tps isc ,current = 0} isSingleFile :: Patchy p => p C(x y) -> Bool isSingleFile p = length (listTouchedFiles p) == 1 askConfirmation :: forall p C(x y) . Patchy p => InteractiveSelectionM p C(x y) () askConfirmation = do jn <- asks jobname liftIO $ if jn `elem` ["unpull", "unrecord", "obliterate"] then do yorn <- askUser $ "Really " ++ jn ++ " all undecided patches? " case yorn of ('y':_) -> return () _ -> exitWith $ ExitSuccess else return () -- | The singular form of the noun for items of type @p@. thing :: Patchy p => InteractiveSelectionM p C(x y) String thing = gets choices >>= return . Darcs.Patch.thing . helper where helper :: PatchChoices p C(a b) -> p C(a b) helper = undefined -- | The plural form of the noun for items of type @p@. things :: Patchy p => InteractiveSelectionM p C(x y) String things = gets choices >>= return . Darcs.Patch.things . helper where helper :: PatchChoices p C(a b) -> p C(a b) helper = undefined -- | The question to ask about one patch. prompt :: Patchy p => InteractiveSelectionM p C(x y) String prompt = do jn <- asks jobname aThing <- thing n <- gets current n_max <- gets total return $ "Shall I "++jn++" this "++aThing++"? " ++ "(" ++ show (n+1) ++ "/" ++ show n_max ++ ") " -- | Asks the user about one patch, returns their answer. promptUser :: forall p C(x y) . Patchy p => Bool -> Char -> InteractiveSelectionM p C(x y) Char promptUser single def = do thePrompt <- prompt (basicOptions,advancedOptions) <- options single liftIO $ promptChar $ PromptConfig { pPrompt = thePrompt , pBasicCharacters = keysFor basicOptions , pAdvancedCharacters = keysFor advancedOptions , pDefault = Just def , pHelp = "?h" } -- | Ask the user what to do with the next patch. textSelectOne :: forall p C(x y). (Patchy p, ApplyState p ~ Tree) => WhichChanges -> InteractiveSelectionM p C(x y) () textSelectOne whichch = do c <- currentPatch case c of Nothing -> return () Just (Sealed2 tp) -> do jn <- asks jobname spl <- asks splitter let singleFile = isSingleFile (tpPatch tp) reprCur = repr whichch (Sealed2 (tpPatch tp)) (basicOptions,advancedOptions) <- options singleFile theSlot <- liftChoices $ patchSlot' tp let the_default = getDefault (whichch == Last || whichch == FirstReversed) theSlot jnCapital = (toUpper $ head jn) : tail jn yorn <- promptUser singleFile the_default let nextPatch = skipMundane whichch >> showCur whichch case yorn of 'y' -> decide whichch True tp >> skipOne >> nextPatch 'n' -> decide whichch False tp >> skipOne >> nextPatch 'w' -> postponeNext >> skipOne >> nextPatch 'e' | (Just s) <- spl -> splitCurrent s >> showCur whichch 's' -> currentFile >>= maybe (return ()) (\f -> decideWholeFile whichch f False) >> nextPatch 'f' -> currentFile >>= maybe (return ()) (\f -> decideWholeFile whichch f True) >> nextPatch 'v' -> liftIO $ unseal2 printPatch reprCur 'p' -> liftIO $ unseal2 printPatchPager reprCur 'l' -> printSelected whichch >> showCur whichch 'x' -> liftIO $ unseal2 printSummary reprCur 'd' -> skipAll 'g' -> backAll >> showCur whichch 'a' -> do askConfirmation modChoices $ selectAllMiddles (whichch == Last || whichch == FirstReversed) skipAll 'q' -> liftIO $ do putStrLn $ jnCapital++" cancelled." exitWith $ ExitSuccess 'j' -> skipOne >> showCur whichch 'k' -> backOne >> showCur whichch _ -> do liftIO . putStrLn $ helpFor jn basicOptions advancedOptions -- | Shows the current patch as it should be seen by the user. showCur :: forall p C(x y) . (Patchy p, ApplyState p ~ Tree) => WhichChanges -> InteractiveSelectionM p C(x y) () showCur whichch = do o <- asks opts p <- asks pristine c <- currentPatch case c of Nothing -> return () Just (Sealed2 tp) -> do let reprCur = repr whichch (Sealed2 (tpPatch tp)) liftIO . (unseal2 (printFriendly p o)) $ reprCur -- | The interactive part of @darcs changes@ textView :: forall p . (Patchy p, ApplyState p ~ Tree) => [DarcsFlag] -> Maybe Int -> Int -> [Sealed2 p] -> [Sealed2 p] -> IO () textView _ _ _ _ [] = return () textView o n_max n ps_done ps_todo@(p:ps_todo') = do unseal2 (printFriendly Nothing o) p repeatThis -- prompt the user where prev_patch :: IO () prev_patch = case ps_done of [] -> repeatThis (p':ps_done') -> textView o n_max (n-1) ps_done' (p':ps_todo) next_patch :: IO () next_patch = case ps_todo' of [] -> -- May as well work out the length now we have all -- the patches in memory textView o n_max n ps_done [] _ -> textView o n_max (n+1) (p:ps_done) ps_todo' first_patch = textView o n_max 0 [] (ps_done++ps_todo) options_yn = [ KeyPress 'y' "view this patch and go to the next" , KeyPress 'n' "skip to the next patch" ] optionsView' = [ KeyPress 'v' "view this patch in full" , KeyPress 'p' "view this patch in full with pager" ] optionsSummary' = [ KeyPress 'x' "view a summary of this patch" ] optionsNav' = [ KeyPress 'q' "quit view changes" , KeyPress 'k' "back up to previous patch" , KeyPress 'j' "skip to next patch" , KeyPress 'g' "start over from the first patch" , KeyPress 'c' "count total patch number" ] basicOptions = [ options_yn ] advancedOptions = [ optionsView' ++ if Summary `elem` o then [] else optionsSummary' ] ++ [ optionsNav' ] prompt' = "Shall I view this patch? " ++ "(" ++ show (n+1) ++ "/" ++ maybe "?" show n_max ++ ")" repeatThis :: IO () repeatThis = do yorn <- promptChar (PromptConfig prompt' (keysFor basicOptions) (keysFor advancedOptions) (Just 'n') "?h") case yorn of 'y' -> unseal2 printPatch p >> next_patch 'n' -> next_patch 'v' -> unseal2 printPatch p >> repeatThis 'p' -> unseal2 printPatchPager p >> repeatThis 'x' -> do putDocLn $ prefix " " $ unseal2 summary p repeatThis 'q' -> exitWith ExitSuccess 'k' -> prev_patch 'j' -> next_patch 'g' -> first_patch 'c' -> textView o count_n_max n ps_done ps_todo _ -> do putStrLn $ helpFor "view changes" basicOptions advancedOptions repeatThis count_n_max | isJust n_max = n_max | otherwise = Just $ length ps_done + length ps_todo -- | Skips patches we should not ask the user about skipMundane :: Patchy p => WhichChanges -> InteractiveSelectionM p C(x y) () skipMundane whichch = do (FZipper tps_done tps_todo) <- gets tps o <- asks opts crit <- asks matchCriterion jn <- asks jobname (skipped :> unskipped) <- liftChoices $ spanFL_M (patchSlot' >=> return . decided) tps_todo let numSkipped = lengthFL skipped when (numSkipped > 0) . liftIO $ show_skipped o jn numSkipped skipped let boringThenInteresting = if DontPromptForDependencies `elem` o then spanFL (not.(crit whichch o) . seal2 . tpPatch) $ unskipped else NilFL :> unskipped case boringThenInteresting of boring :> interesting -> do justDone $ lengthFL boring + numSkipped modify $ \isc -> isc {tps = (FZipper (reverseFL boring +<+ reverseFL skipped +<+ tps_done) interesting)} where show_skipped o jn n ps = do putStrLn $ _nevermind_ jn ++ _these_ n ++ "." when (Verbose `elem` o) $ showskippedpatch ps _nevermind_ jn = "Will not ask whether to " ++ jn ++ " " _these_ n = show n ++ " already decided " ++ _elem_ n "" _elem_ n = englishNum n (Noun "patch") showskippedpatch :: Patchy p => FL (TaggedPatch p) C(y t) -> IO () showskippedpatch = sequence_ . mapFL (printSummary . tpPatch) decided :: Slot -> Bool decided InMiddle = False decided _ = True -- | The action bound to space, depending on the current status of the -- patch. getDefault :: Bool -> Slot -> Char getDefault _ InMiddle = 'w' getDefault True InFirst = 'n' getDefault True InLast = 'y' getDefault False InFirst = 'y' getDefault False InLast = 'n' -- |Optionally remove any patches (+dependencies) from a sequence that -- conflict with the recorded or unrecorded changes in a repo filterOutConflicts :: (RepoPatch p, ApplyState p ~ Tree) => [DarcsFlag] -- ^Command-line options. Only 'SkipConflicts' is -- significant; filtering will happen iff it is present -> RL (PatchInfoAnd p) C(x t) -- ^Recorded patches from repository, starting from -- same context as the patches to filter -> Repository p C(r u t) -- ^Repository itself, used for grabbing unrecorded changes -> FL (PatchInfoAnd p) C(x z) -- ^Patches to filter -> IO (Bool, Sealed (FL (PatchInfoAnd p) C(x))) -- ^(True iff any patches were removed, possibly filtered patches) filterOutConflicts o us repository them | SkipConflicts `elem` o = do let commuter = commuterIdRL selfCommuter unrec <- fmap n2pia . (anonymous . fromPrims) =<< unrecordedChanges (UseIndex, ScanKnown) repository Nothing them' :> rest <- return $ partitionConflictingFL commuter them (unrec :<: us) return (check rest, Sealed them') | otherwise = return (False, Sealed them) where check :: FL p C(a b) -> Bool check NilFL = False check _ = True darcs-2.8.4/src/Darcs/SignalHandler.hs0000644001765600176560000001346312104371431017042 0ustar ganeshganesh-- Copyright (C) 2003 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP, DeriveDataTypeable #-} module Darcs.SignalHandler ( withSignalsHandled, withSignalsBlocked, catchInterrupt, catchNonSignal, tryNonSignal, stdoutIsAPipe ) where import Prelude hiding ( catch ) import System.IO.Error ( isUserError, ioeGetErrorString, ioeGetFileName ) import System.Exit ( exitWith, ExitCode ( ExitFailure ) ) import Control.Concurrent ( ThreadId, myThreadId ) import Control.Exception.Extensible ( catch, throw, throwTo, block, unblock, Exception(..), SomeException(..), IOException ) import System.Posix.Files ( getFdStatus, isNamedPipe ) import System.Posix.IO ( stdOutput ) import Data.Typeable ( Typeable, cast ) import Data.List ( isPrefixOf ) import System.IO ( hPutStrLn, stderr ) import Control.Monad ( when ) import Workaround ( installHandler, raiseSignal, Handler(..), Signal, sigINT, sigHUP, sigABRT, sigALRM, sigTERM, sigPIPE ) #ifdef WIN32 import CtrlC ( withCtrlCHandler ) #endif stdoutIsAPipe :: IO Bool stdoutIsAPipe = catch (do stat <- getFdStatus stdOutput return (isNamedPipe stat)) (\(_ :: IOException) -> return False) withSignalsHandled :: IO a -> IO a newtype SignalException = SignalException Signal deriving (Show, Typeable) instance Exception SignalException where toException e = SomeException e fromException (SomeException e) = cast e withSignalsHandled job = do thid <- myThreadId mapM_ (ih thid) [sigINT, sigHUP, sigABRT, sigTERM, sigPIPE] catchUserErrors (job' thid `catchSignal` defaults) die_with_string where defaults s | s == sigINT = ew s "Interrupted!" | s == sigHUP = ew s "HUP" | s == sigABRT = ew s "ABRT" | s == sigTERM = ew s "TERM" | s == sigPIPE = exitWith $ ExitFailure $ 1 | otherwise = ew s "Unhandled signal!" ew sig s = do hPutStrLn stderr $ ("withSignalsHandled: " ++ s) resethandler sig raiseSignal sig -- ensure that our caller knows how we died exitWith $ ExitFailure $ 1 die_with_string e | "STDOUT" `isPrefixOf` e = do is_pipe <- stdoutIsAPipe when (not is_pipe) $ hPutStrLn stderr $ "\ndarcs failed: "++drop 6 e exitWith $ ExitFailure $ 2 die_with_string e = do hPutStrLn stderr $ "\ndarcs failed: "++e exitWith $ ExitFailure $ 2 #ifdef WIN32 job' thid = withCtrlCHandler (throwTo thid $ SignalException sigINT) job #else job' _ = job #endif resethandler :: Signal -> IO () -- Warning: A do-notation statement discarded a result of type Handler. resethandler s = do _ <- installHandler s Default Nothing return () ih :: ThreadId -> Signal -> IO () ih thid s = -- Warning: A do-notation statement discarded a result of type Handler. do _ <- installHandler s (Catch $ throwTo thid $ SignalException s) Nothing return () catchSignal :: IO a -> (Signal -> IO a) -> IO a catchSignal job handler = job `catch` (\(SignalException sig) -> handler sig) -- catchNonSignal is a drop-in replacement for Control.Exception.catch, which allows -- us to catch anything but a signal. Useful for situations where we want -- don't want to inhibit ctrl-C. catchNonSignal :: IO a -> (SomeException -> IO a) -> IO a catchNonSignal comp handler = catch comp handler' where handler' se = case fromException se :: Maybe SignalException of Nothing -> handler se Just _ -> throw se catchInterrupt :: IO a -> IO a -> IO a catchInterrupt job handler = job `catchSignal` h where h s | s == sigINT = handler | otherwise = throw (SignalException s) tryNonSignal :: IO a -> IO (Either SomeException a) tryNonSignal j = (Right `fmap` j) `catchNonSignal` \e -> return (Left e) catchUserErrors :: IO a -> (String -> IO a) -> IO a catchUserErrors comp handler = catch comp handler' where handler' ioe | isUserError ioe = handler (ioeGetErrorString ioe) | ioeGetFileName ioe == Just "" = handler ("STDOUT" ++ ioeGetErrorString ioe) | otherwise = throw ioe withSignalsBlocked :: IO a -> IO a withSignalsBlocked job = block (job >>= \r -> unblock(return r) `catchSignal` couldnt_do r) where couldnt_do r s | s == sigINT = oops "interrupt" r | s == sigHUP = oops "HUP" r | s == sigABRT = oops "ABRT" r | s == sigALRM = oops "ALRM" r | s == sigTERM = oops "TERM" r | s == sigPIPE = return r | otherwise = oops "unknown signal" r oops s r = do hPutStrLn stderr $ "Couldn't handle " ++ s ++ " since darcs was in a sensitive job." return r darcs-2.8.4/src/Darcs/Ssh.hs0000644001765600176560000002147412104371431015065 0ustar ganeshganesh{-# LANGUAGE CPP, ForeignFunctionInterface #-} -- | -- Module : Darcs.Ssh -- Maintainer : darcs-devel@darcs.net -- Stability : experimental -- Portability : portable module Darcs.Ssh ( copySSH , SSHCmd(..) , getSSH , environmentHelpSsh , environmentHelpScp , environmentHelpSshPort , remoteDarcs ) where import Prelude hiding ( lookup, catch ) import qualified Ratified ( hGetContents ) import System.Environment ( getEnv ) import System.Exit ( ExitCode(..) ) import Control.Monad ( when ) import qualified Data.ByteString as B (ByteString, hGet, writeFile ) import Data.Map ( Map, empty, insert, lookup ) import Data.IORef ( IORef, newIORef, readIORef, modifyIORef ) import System.IO ( Handle, hSetBinaryMode, hPutStrLn, hGetLine, hFlush ) import System.IO.Unsafe ( unsafePerformIO ) import System.Process ( runInteractiveProcess ) import Darcs.SignalHandler ( catchNonSignal ) import Darcs.Flags( RemoteDarcs(..) ) import Darcs.Global ( defaultSsh, SshSettings) import Darcs.URL (SshFilePath(..), urlOf) import Darcs.Utils ( breakCommand, prettyException, catchall ) import Exec ( exec, Redirect(..), ) import Progress ( withoutProgress, debugMessage, debugFail ) import qualified Darcs.Global as Settings sshConnections :: IORef (Map String (Maybe Connection)) sshConnections = unsafePerformIO $ newIORef empty {-# NOINLINE sshConnections #-} data Connection = C { inp :: !Handle , out :: !Handle , err :: !Handle , deb :: String -> IO () } -- | @withSSHConnection rdarcs repoid withconnection withoutconnection@ -- performs an action on a remote host. If we are already connected to @repoid @, -- then it does @withconnection@, else @withoutconnection@. withSSHConnection :: String -- ^ rdarcs -> SshFilePath -- ^ Destination repo id -> (Connection -> IO a) -- ^ withconnection -> IO a -- ^ withoutconnection -> IO a withSSHConnection rdarcs repoid withconnection withoutconnection = withoutProgress $ do cs <- readIORef sshConnections case lookup (sshUhost repoid) (cs :: Map String (Maybe Connection)) of Just Nothing -> withoutconnection Just (Just c) -> withconnection c Nothing -> do mc <- do (ssh,sshargs_) <- getSSH SSH let sshargs = sshargs_ ++ [sshUhost repoid, rdarcs, "transfer-mode","--repodir",sshRepo repoid] debugMessage $ unwords (ssh : sshargs) (i,o,e,_) <- runInteractiveProcess ssh sshargs Nothing Nothing hSetBinaryMode i True hSetBinaryMode o True l <- hGetLine o if l == "Hello user, I am darcs transfer mode" then return () else debugFail "Couldn't start darcs transfer-mode on server" let c = C { inp = i, out = o, err = e, deb = \s -> debugMessage ("with ssh (transfer-mode) " ++ sshUhost repoid ++ " " ++ s) } modifyIORef sshConnections (insert (sshUhost repoid) (Just c)) return $ Just c `catchNonSignal` \e -> do debugMessage $ "Failed to start ssh connection:\n "++ prettyException e severSSHConnection repoid debugMessage $ unlines $ [ "NOTE: the server may be running a version of darcs prior to 2.0.0." , "" , "Installing darcs 2 on the server will speed up ssh-based commands." ] return Nothing maybe withoutconnection withconnection mc severSSHConnection :: SshFilePath -> IO () severSSHConnection x = do debugMessage $ "Severing ssh failed connection to " ++ (sshUhost x) modifyIORef sshConnections (insert (urlOf x) Nothing) grabSSH :: SshFilePath -> Connection -> IO B.ByteString grabSSH dest c = do debugMessage $ "grabSSH dest=" ++ urlOf dest let failwith e = do severSSHConnection dest -- hGetContents is ok here because we're -- only grabbing stderr, and we're also -- about to throw the contents. eee <- Ratified.hGetContents (err c) debugFail $ e ++ " grabbing ssh file "++ urlOf dest++"/"++ file ++"\n"++eee file = sshFile dest deb c $ "get "++ file hPutStrLn (inp c) $ "get " ++ file hFlush (inp c) l2 <- hGetLine (out c) if l2 == "got "++file then do showlen <- hGetLine (out c) case reads showlen of [(len,"")] -> B.hGet (out c) len _ -> failwith "Couldn't get length" else if l2 == "error "++file then do e <- hGetLine (out c) case reads e of (msg,_):_ -> debugFail $ "Error reading file remotely:\n"++msg [] -> failwith "An error occurred" else failwith "Error" remoteDarcs :: RemoteDarcs -> String remoteDarcs DefaultRemoteDarcs = "darcs" remoteDarcs (RemoteDarcs x) = x copySSH :: RemoteDarcs -> SshFilePath -> FilePath -> IO () copySSH remote dest to | rdarcs <- remoteDarcs remote = do debugMessage $ "copySSH file: " ++ urlOf dest withSSHConnection rdarcs dest (\c -> grabSSH dest c >>= B.writeFile to) $ do let u = escape_dollar $ urlOf dest (scp, args) <- getSSH SCP r <- exec scp (args ++ [u, to]) (AsIs,AsIs,AsIs) when (r /= ExitSuccess) $ debugFail $ "(scp) failed to fetch: " ++ u where -- '$' in filenames is troublesome for scp, for some reason. escape_dollar :: String -> String escape_dollar = concatMap tr where tr '$' = "\\$" tr c = [c] -- --------------------------------------------------------------------- -- older ssh helper functions -- --------------------------------------------------------------------- data SSHCmd = SSH | SCP | SFTP fromSshCmd :: SshSettings -> SSHCmd -> String fromSshCmd s SSH = Settings.ssh s fromSshCmd s SCP = Settings.scp s fromSshCmd s SFTP = Settings.sftp s -- | Return the command and arguments needed to run an ssh command -- First try the appropriate darcs environment variable and SSH_PORT -- defaulting to "ssh" and no specified port. getSSH :: SSHCmd -> IO (String, [String]) getSSH cmd = do port <- (portFlag cmd `fmap` getEnv "SSH_PORT") `catchall` return [] let (ssh, ssh_args) = breakCommand command return (ssh, ssh_args ++ port) where command = fromSshCmd defaultSsh cmd portFlag SSH x = ["-p", x] portFlag SCP x = ["-P", x] portFlag SFTP x = ["-oPort=" ++ x] environmentHelpSsh :: ([String], [String]) environmentHelpSsh = (["DARCS_SSH"], [ "Repositories of the form [user@]host:[dir] are taken to be remote", "repositories, which Darcs accesses with the external program ssh(1).", "", "The environment variable $DARCS_SSH can be used to specify an", "alternative SSH client. Arguments may be included, separated by", "whitespace. The value is not interpreted by a shell, so shell", "constructs cannot be used; in particular, it is not possible for the", "program name to contain whitespace by using quoting or escaping."]) environmentHelpScp :: ([String], [String]) environmentHelpScp = (["DARCS_SCP", "DARCS_SFTP"], [ "When reading from a remote repository, Darcs will attempt to run", "`darcs transfer-mode' on the remote host. This will fail if the", "remote host only has Darcs 1 installed, doesn't have Darcs installed", "at all, or only allows SFTP.", "", "If transfer-mode fails, Darcs will fall back on scp(1) and sftp(1).", "The commands invoked can be customized with the environment variables", "$DARCS_SCP and $DARCS_SFTP respectively, which behave like $DARCS_SSH.", "If the remote end allows only sftp, try setting DARCS_SCP=sftp."]) environmentHelpSshPort :: ([String], [String]) environmentHelpSshPort = (["SSH_PORT"], [ "If this environment variable is set, it will be used as the port", "number for all SSH calls made by Darcs (when accessing remote", "repositories over SSH). This is useful if your SSH server does not", "run on the default port, and your SSH client does not support", "ssh_config(5). OpenSSH users will probably prefer to put something", "like `Host *.example.net Port 443' into their ~/.ssh/config file."]) darcs-2.8.4/src/Darcs/Test.hs0000644001765600176560000001002712104371431015237 0ustar ganeshganesh-- Copyright (C) 2002-2005 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. module Darcs.Test ( getTest, runPosthook, runPrehook ) where import Darcs.RepoPath ( AbsolutePath ) import Darcs.Utils ( withCurrentDirectory ) import System.Exit ( ExitCode(..) ) import System.Cmd ( system ) import Control.Monad ( when ) import Darcs.Arguments ( DarcsFlag( Quiet, AskPosthook, AskPrehook ), getPosthookCmd, getPrehookCmd ) import Darcs.Repository.Prefs ( getPrefval ) import Darcs.Utils ( askUser ) import System.IO ( hPutStrLn, stderr ) getTest :: [DarcsFlag] -> IO (IO ExitCode) getTest opts = let putInfo s = when (not $ Quiet `elem` opts) $ putStr s in do testline <- getPrefval "test" return $ case testline of Nothing -> return ExitSuccess Just testcode -> do putInfo "Running test...\n" ec <- system testcode if ec == ExitSuccess then putInfo "Test ran successfully.\n" else putInfo "Test failed!\n" return ec runPosthook :: [DarcsFlag] -> AbsolutePath -> IO ExitCode runPosthook opts repodir = do ph <- getPosthook opts withCurrentDirectory repodir $ runHook opts "Posthook" ph getPosthook :: [DarcsFlag] -> IO (Maybe String) getPosthook opts = case getPosthookCmd opts of Nothing -> return Nothing Just command -> if AskPosthook `elem` opts then do putStr ("\nThe following command is set to execute.\n"++ "Execute the following command now (yes or no)?\n"++ command++"\n") yorn <- askUser "" case yorn of ('y':_) -> return $ Just command _ -> do putStrLn "Posthook cancelled..." return Nothing else return $ Just command runPrehook :: [DarcsFlag] -> AbsolutePath -> IO ExitCode runPrehook opts repodir = do ph <- getPrehook opts withCurrentDirectory repodir $ runHook opts "Prehook" ph getPrehook :: [DarcsFlag] -> IO (Maybe String) getPrehook opts = case getPrehookCmd opts of Nothing -> return Nothing Just command -> if AskPrehook `elem` opts then do putStr ("\nThe following command is set to execute.\n"++ "Execute the following command now (yes or no)?\n"++ command++"\n") yorn <- askUser "" case yorn of ('y':_) -> return $ Just command _ -> do putStrLn "Prehook cancelled..." return Nothing else return $ Just command runHook :: [DarcsFlag] -> String -> Maybe String -> IO ExitCode runHook _ _ Nothing = return ExitSuccess runHook opts cname (Just command) = do ec <- system command when (Quiet `notElem` opts) $ if ec == ExitSuccess then putStrLn $ cname++" ran successfully." else hPutStrLn stderr $ cname++" failed!" return ec darcs-2.8.4/src/Darcs/TheCommands.hs0000644001765600176560000001101712104371431016522 0ustar ganeshganesh-- Copyright (C) 2003 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP #-} module Darcs.TheCommands ( commandControlList ) where import Prelude () import Darcs.Commands.Add ( add ) import Darcs.Commands.AmendRecord ( amendrecord, amendunrecord ) import Darcs.Commands.Annotate ( annotate ) import Darcs.Commands.Apply ( apply ) import Darcs.Commands.Changes ( changes, log ) import Darcs.Commands.Check ( check, repair ) import Darcs.Commands.Convert ( convert ) import Darcs.Commands.Diff ( diffCommand ) import Darcs.Commands.Dist ( dist ) import Darcs.Commands.Get ( get, clone ) import Darcs.Commands.GZCRCs ( gzcrcs ) import Darcs.Commands.Init ( initialize ) import Darcs.Commands.Show ( showCommand, list, query ) import Darcs.Commands.MarkConflicts ( markconflicts ) import Darcs.Commands.Move ( move, mv ) import Darcs.Commands.Optimize ( optimize ) import Darcs.Commands.Pull ( pull, fetch ) import Darcs.Commands.Push ( push ) import Darcs.Commands.Put ( put ) import Darcs.Commands.Record ( record, commit ) import Darcs.Commands.Remove ( remove, rm, unadd ) import Darcs.Commands.Replace ( replace ) import Darcs.Commands.Revert ( revert ) import Darcs.Commands.Rollback ( rollback ) import Darcs.Commands.Send ( send ) import Darcs.Commands.SetPref ( setpref ) import Darcs.Commands.Tag ( tag ) import Darcs.Commands.Test ( test ) import Darcs.Commands.TrackDown ( trackdown ) import Darcs.Commands.TransferMode ( transferMode ) import Darcs.Commands.Unrecord ( unrecord, unpull, obliterate ) import Darcs.Commands.Unrevert ( unrevert ) import Darcs.Commands.WhatsNew ( whatsnew, status ) import Darcs.Commands ( CommandControl(CommandData,HiddenCommand,GroupName) ) -- | The commands that darcs knows about (e.g. whatsnew, record), -- organized into thematic groups. Note that hidden commands -- are also listed here. commandControlList :: [CommandControl] commandControlList = [GroupName "Changing and querying the working copy:", CommandData add, CommandData remove, HiddenCommand unadd, HiddenCommand rm, CommandData move, HiddenCommand mv, CommandData replace, CommandData revert, CommandData unrevert, CommandData whatsnew, HiddenCommand status, GroupName "Copying changes between the working copy and the repository:", CommandData record, HiddenCommand commit, CommandData unrecord, CommandData amendrecord, HiddenCommand amendunrecord, CommandData markconflicts, GroupName "Direct modification of the repository:", CommandData tag, CommandData setpref, GroupName "Querying the repository:", CommandData diffCommand, CommandData changes, HiddenCommand log, CommandData annotate, CommandData dist, CommandData test, CommandData trackdown, CommandData showCommand, HiddenCommand list, HiddenCommand query, HiddenCommand transferMode, GroupName "Copying patches between repositories with working copy update:", CommandData pull, CommandData fetch, CommandData obliterate, HiddenCommand unpull, CommandData rollback, CommandData push, CommandData send, CommandData apply, CommandData get, HiddenCommand clone, CommandData put, GroupName "Administrating repositories:", CommandData initialize, CommandData optimize, CommandData check, CommandData repair, CommandData convert ,HiddenCommand gzcrcs ] darcs-2.8.4/src/Darcs/URL.hs0000644001765600176560000000750712104371431014773 0ustar ganeshganesh{-# LANGUAGE CPP #-} {- Copyright (C) 2004 David Roundy 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, 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; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -} {-| Path resolving: * An http URL contains the sequence @\"http(s):\/\/\"@. * A local filepath does not contain colons, except as second character (windows drives) when this filepath is meant to be used as repository name * A path that is neither an http URL nor a local file is an ssh-path. Examples: > /usr/repo/foo -- local file > c:/src/darcs -- local file > http://darcs.net/ -- URL > peter@host:/path -- ssh > droundy@host: -- ssh > host:/path -- ssh This means that single-letter hosts in ssh-paths do not work, unless a username is provided. Perhaps ssh-paths should use @\"ssh:\/\/user\@host\/path\"@-syntax instead? -} module Darcs.URL ( isFile, isHttpUrl, isSshUrl, isRelative, isAbsolute, isSshNopath, SshFilePath, sshRepo, sshUhost, sshFile, urlOf, splitSshUrl ) where import Darcs.Global(darcsdir) import Data.List ( isPrefixOf, isInfixOf ) import Data.Char ( isSpace ) import qualified System.FilePath as FP (isRelative, isAbsolute, isValid) #include "impossible.h" isRelative :: String -> Bool isRelative "" = bug "Empty filename in isRelative" isRelative f = FP.isRelative f isAbsolute :: String -> Bool isAbsolute "" = bug "isAbsolute called with empty filename" isAbsolute f = FP.isAbsolute f isFile :: String -> Bool isFile f@(_:_:fou) = ':' `notElem` fou && FP.isValid f isFile f = FP.isValid f isHttpUrl :: String -> Bool isHttpUrl u = let u' = dropWhile isSpace u in ("http://" `isPrefixOf` u') || ("https://" `isPrefixOf` u') isSshUrl :: String -> Bool isSshUrl s = isu' (dropWhile isSpace s) where isu' s' | "ssh://" `isPrefixOf` s' = True | "://" `isInfixOf` s' = False | isFile s' = False | otherwise = ":" `isInfixOf` s' isSshNopath :: String -> Bool isSshNopath s = case reverse s of ':':x@(_:_:_) -> ':' `notElem` x _ -> False -- | Gives the (user, host, dir) out of an ssh url splitSshUrl :: String -> SshFilePath splitSshUrl s | "ssh://" `isPrefixOf` s = let s' = drop (length "ssh://") $ dropWhile isSpace s (dir, file) = cleanrepodir '/' s' in SshFP { sshUhost = takeWhile (/= '/') s' , sshRepo = dir , sshFile = file } splitSshUrl s = let (dir, file) = cleanrepodir ':' s in SshFP { sshUhost = dropWhile isSpace $ takeWhile (/= ':') s , sshRepo = dir , sshFile = file } cleanrepourl :: String -> (String, String) cleanrepourl zzz | dd `isPrefixOf` zzz = ([], drop (length dd) zzz) where dd = darcsdir++"/" cleanrepourl (z:zs) = let (repo',file) = cleanrepourl zs in (z : repo', file) cleanrepourl "" = ([],[]) cleanrepodir :: Char -> String -> (String, String) cleanrepodir sep = cleanrepourl . drop 1 . dropWhile (/= sep) data SshFilePath = SshFP { sshUhost :: String , sshRepo :: String , sshFile :: String} urlOf :: SshFilePath -> String urlOf (SshFP uhost dir file) = uhost ++ ":" ++ dir ++ "/" ++ darcsdir ++ "/" ++ file darcs-2.8.4/src/Darcs/Utils.hs0000644001765600176560000004165512104371431015433 0ustar ganeshganesh{-# OPTIONS_GHC -fno-warn-dodgy-imports #-} -- needed for GHC 7.0/7.2 {-# LANGUAGE CPP, ForeignFunctionInterface #-} -- | -- Module : Exec -- Maintainer : darcs-devel@darcs.net -- Stability : experimental -- Portability : portable -- -- Various utility functions that do not belong anywhere else. module Darcs.Utils ( ortryrunning , nubsort , breakCommand , showHexLen , maybeGetEnv , formatPath -- * Monads , firstJustIO -- * User prompts , askEnter , askUser , askUserListItem , PromptConfig(..) , promptYorn , promptChar -- * Text , getViewer , editFile , runEditor , stripCr -- * Help , environmentHelpEditor , environmentHelpPager -- * Errors and exceptions , catchall , clarifyErrors , prettyException , prettyError , addToErrorLoc -- * Files and directories , getFileStatus , withCurrentDirectory , withUMask -- * Locales , setDarcsEncodings , getSystemEncoding , isUTF8Locale -- * Tree filtering. , filterFilePaths , filterPaths -- * Tree lookup. , treeHas , treeHasDir , treeHasFile , treeHasAnycase ) where import Prelude hiding ( catch ) import Control.Exception.Extensible ( bracket, bracket_, catch, try, IOException, SomeException, Exception(fromException) ) import Control.Monad ( when, forM ) import Control.Monad.Error( MonadError ) import Control.Monad.State.Strict( gets ) import qualified Data.ByteString as B ( readFile ) import qualified Data.ByteString.Char8 as BSC import Data.Char ( toUpper, toLower, isSpace ) import Data.List ( group, sort ) import Data.Maybe ( isJust ) import Foreign.C.String ( CString, withCString, peekCString ) import Foreign.C.Error ( throwErrno ) import Foreign.C.Types ( CInt(..) ) #ifdef FORCE_CHAR8_ENCODING import GHC.IO.Encoding ( setFileSystemEncoding, setForeignEncoding, char8 ) #endif import Storage.Hashed.AnchoredPath( AnchoredPath(..), Name(..), isPrefix, floatPath ) import Storage.Hashed.Monad( withDirectory, fileExists, directoryExists , virtualTreeMonad, currentDirectory , TreeMonad ) import qualified Storage.Hashed.Monad as HS ( exists, tree ) import Storage.Hashed.Tree( Tree, listImmediate, findTree ) import System.Console.Haskeline ( runInputT, defaultSettings, getInputLine, getInputChar, outputStr, outputStrLn ) import System.Directory ( doesFileExist ) import System.Environment ( getEnv ) import System.Exit ( ExitCode(..) ) import System.IO.Error ( annotateIOError, isUserError, ioeGetErrorString , isDoesNotExistError, ioeGetFileName ) import System.Posix.Files( getSymbolicLinkStatus, FileStatus ) import Text.Regex import Darcs.RepoPath ( FilePathLike, getCurrentDirectory, setCurrentDirectory, toFilePath ) import Darcs.SignalHandler ( catchNonSignal ) import Exec ( execInteractive ) import Numeric ( showHex ) import Progress ( withoutProgress ) showHexLen :: (Integral a, Show a) => Int -> a -> String showHexLen n x = let s = showHex x "" in replicate (n - length s) ' ' ++ s addToErrorLoc :: IOException -> String -> IOException addToErrorLoc ioe s = annotateIOError ioe s Nothing Nothing catchall :: IO a -> IO a -> IO a a `catchall` b = a `catchNonSignal` (\_ -> b) maybeGetEnv :: String -> IO (Maybe String) maybeGetEnv s = fmap Just (getEnv s) `catchall` return Nothing -- err can only be isDoesNotExist -- | The firstJustM returns the first Just entry in a list of monadic -- operations. This is close to `listToMaybe `fmap` sequence`, but the sequence -- operator evaluates all monadic members of the list before passing it along -- (i.e. sequence is strict). The firstJustM is lazy in that list member monads -- are only evaluated up to the point where the first Just entry is obtained. firstJustM :: Monad m => [m (Maybe a)] -> m (Maybe a) firstJustM [] = return Nothing firstJustM (e:es) = e >>= (\v -> if isJust v then return v else firstJustM es) -- | The firstJustIO is a slight modification to firstJustM: the entries in the -- list must be IO monad operations and the firstJustIO will silently turn any -- monad call that throws an exception into Nothing, basically causing it to be -- ignored. firstJustIO :: [IO (Maybe a)] -> IO (Maybe a) firstJustIO = firstJustM . map (`catchall` return Nothing) clarifyErrors :: IO a -> String -> IO a clarifyErrors a e = a `catch` (\x -> fail $ unlines [prettyException x,e]) prettyException :: SomeException -> String prettyException e | Just ioe <- fromException e, isUserError ioe = ioeGetErrorString ioe prettyException e | Just ioe <- fromException e, isDoesNotExistError ioe = case ioeGetFileName ioe of Just f -> f ++ " does not exist" Nothing -> show e prettyException e = show e prettyError :: IOError -> String prettyError e | isUserError e = ioeGetErrorString e | otherwise = show e -- | Given two shell commands as arguments, execute the former. The -- latter is then executed if the former failed because the executable -- wasn't found (code 127), wasn't executable (code 126) or some other -- exception occurred. Other failures (such as the user holding ^C) -- do not cause the second command to be tried. ortryrunning :: IO ExitCode -> IO ExitCode -> IO ExitCode a `ortryrunning` b = do ret <- try a case ret of (Right (ExitFailure 126)) -> b -- command not executable (Right (ExitFailure 127)) -> b -- command not found #ifdef WIN32 (Right (ExitFailure 9009)) -> b -- command not found by cmd.exe on Windows #endif (Right x) -> return x -- legitimate success/failure (Left (_ :: SomeException)) -> b -- an exception withCurrentDirectory :: FilePathLike p => p -> IO a -> IO a withCurrentDirectory name m = bracket (do cwd <- getCurrentDirectory when (toFilePath name /= "") (setCurrentDirectory name) return cwd) (\oldwd -> setCurrentDirectory oldwd `catchall` return ()) (const m) foreign import ccall unsafe "umask.h set_umask" set_umask :: CString -> IO CInt foreign import ccall unsafe "umask.h reset_umask" reset_umask :: CInt -> IO CInt withUMask :: String -> IO a -> IO a withUMask umask job = do rc <- withCString umask set_umask when (rc < 0) (throwErrno "Couldn't set umask") bracket_ (return ()) (reset_umask rc) job -- | Ask the user for a line of input. askUser :: String -- ^ The prompt to display -> IO String -- ^ The string the user entered. askUser prompt = withoutProgress $ runInputT defaultSettings $ getInputLine prompt >>= maybe (error "askUser: unexpected end of input") return -- | Ask the user to press Enter askEnter :: String -- ^ The prompt to display -> IO () askEnter prompt = askUser prompt >> return () -- | @askUserListItem prompt xs@ enumerates @xs@ on the screen, allowing -- the user to choose one of the items askUserListItem :: String -> [String] -> IO String askUserListItem prompt xs = withoutProgress $ runInputT defaultSettings $ do outputStr . unlines $ zipWith (\n x -> show n ++ ". " ++ x) [1::Int ..] xs loop where loop = do answer <- getInputLine prompt >>= maybe (error "askUser: unexpected end of input") return case maybeRead answer of Just n | n > 0 && n <= length xs -> return (xs !! (n-1)) _ -> outputStrLn "Invalid response, try again!" >> loop maybeRead :: Read a => String -> Maybe a maybeRead s = case reads s of [(x, rest)] | all isSpace rest -> Just x _ -> Nothing stripCr :: String -> String stripCr "" = "" stripCr "\r" = "" stripCr (c:cs) = c : stripCr cs -- | Format a path for screen output, so that the user sees where the path -- begins and ends. Could (should?) also warn about unprintable characters here. formatPath :: String -> String formatPath path = "\"" ++ quote path ++ "\"" where quote "" = "" quote (c:cs) = if c `elem` ['\\', '"'] then '\\':c:quote cs else c:quote cs breakCommand :: String -> (String, [String]) breakCommand s = case words s of (arg0:args) -> (arg0,args) [] -> (s,[]) nubsort :: Ord a => [a] -> [a] nubsort = map head . group . sort -- | @editFile f@ lets the user edit a file which could but does not need to -- already exist. This function returns the exit code from the text editor and a -- flag indicating if the user made any changes. editFile :: FilePathLike p => p -> IO (ExitCode, Bool) editFile ff = do old_content <- file_content ec <- runEditor f new_content <- file_content return (ec, new_content /= old_content) where f = toFilePath ff file_content = do exists <- doesFileExist f if exists then do content <- B.readFile f return $ Just content else return Nothing runEditor :: FilePath -> IO ExitCode runEditor f = do ed <- getEditor execInteractive ed f `ortryrunning` execInteractive "emacs" f `ortryrunning` execInteractive "emacs -nw" f `ortryrunning` execInteractive "nano" f #ifdef WIN32 `ortryrunning` execInteractive "edit" f #endif getEditor :: IO String getEditor = getEnv "DARCS_EDITOR" `catchall` getEnv "DARCSEDITOR" `catchall` getEnv "VISUAL" `catchall` getEnv "EDITOR" `catchall` return "vi" environmentHelpEditor :: ([String], [String]) environmentHelpEditor = (["DARCS_EDITOR", "DARCSEDITOR", "VISUAL", "EDITOR"],[ "To edit a patch description of email comment, Darcs will invoke an", "external editor. Your preferred editor can be set as any of the", "environment variables $DARCS_EDITOR, $DARCSEDITOR, $VISUAL or $EDITOR.", "If none of these are set, vi(1) is used. If vi crashes or is not", "found in your PATH, emacs, emacs -nw, nano and (on Windows) edit are", "each tried in turn."]) getViewer :: IO String getViewer = getEnv "DARCS_PAGER" `catchall` getEnv "PAGER" `catchall` return "less" environmentHelpPager :: ([String], [String]) environmentHelpPager = (["DARCS_PAGER", "PAGER"],[ "Darcs will sometimes invoke a pager if it deems output to be too long", "to fit onscreen. Darcs will use the pager specified by $DARCS_PAGER", "or $PAGER. If neither are set, `less' will be used."]) data PromptConfig = PromptConfig { pPrompt :: String , pBasicCharacters :: [Char] , pAdvancedCharacters :: [Char] -- ^ only shown on help , pDefault :: Maybe Char , pHelp :: [Char] } -- | Prompt the user for a yes or no promptYorn :: [Char] -> IO Bool promptYorn p = (== 'y') `fmap` promptChar (PromptConfig p "yn" [] Nothing []) promptChar :: PromptConfig -> IO Char promptChar (PromptConfig p basic_chs adv_chs md help_chs) = withoutProgress $ runInputT defaultSettings loopChar where chs = basic_chs ++ adv_chs loopChar = do let chars = setDefault (basic_chs ++ (if null adv_chs then "" else "...")) prompt = p ++ " [" ++ chars ++ "]" ++ helpStr a <- getInputChar prompt >>= maybe (error "promptChar: unexpected end of input") return case () of _ | a `elem` chs -> return a | a == ' ' -> maybe tryAgain return md | a `elem` help_chs -> return a | otherwise -> tryAgain helpStr = case help_chs of [] -> "" (h:_) | null adv_chs -> ", or " ++ (h:" for help: ") | otherwise -> ", or " ++ (h:" for more options: ") tryAgain = do outputStrLn "Invalid response, try again!" loopChar setDefault s = case md of Nothing -> s Just d -> map (setUpper d) s setUpper d c = if d == c then toUpper c else c -- | Construct a filter from a list of AnchoredPaths, that will accept any path -- that is either a parent or a child of any of the listed paths, and discard -- everything else. filterPaths :: [AnchoredPath] -> AnchoredPath -> t -> Bool filterPaths files p _ = any (\x -> x `isPrefix` p || p `isPrefix` x) files -- | Same as 'filterPath', but for ordinary 'FilePath's (as opposed to -- AnchoredPath). filterFilePaths :: [FilePath] -> AnchoredPath -> t -> Bool filterFilePaths = filterPaths . map floatPath getFileStatus :: FilePath -> IO (Maybe FileStatus) getFileStatus f = Just `fmap` getSymbolicLinkStatus f `catchall` return Nothing treeHasAnycase :: (MonadError e m, Functor m, Monad m) => Tree m -> FilePath -> m Bool treeHasAnycase tree path = fst `fmap` virtualTreeMonad (existsAnycase $ floatPath path) tree existsAnycase :: (MonadError e m, Functor m, Monad m) => AnchoredPath -> TreeMonad m Bool existsAnycase (AnchoredPath []) = return True existsAnycase (AnchoredPath (Name x:xs)) = do do wd <- currentDirectory Just tree <- gets (flip findTree wd . HS.tree) let subs = [ AnchoredPath [Name n] | (Name n, _) <- listImmediate tree, BSC.map toLower n == BSC.map toLower x ] or `fmap` forM subs (\path -> do file <- fileExists path if file then return True else withDirectory path (existsAnycase $ AnchoredPath xs)) treeHas :: (MonadError e m, Functor m, Monad m) => Tree m -> FilePath -> m Bool treeHas tree path = fst `fmap` virtualTreeMonad (HS.exists $ floatPath path) tree treeHasDir :: (MonadError e m, Functor m, Monad m) => Tree m -> FilePath -> m Bool treeHasDir tree path = fst `fmap` virtualTreeMonad (directoryExists $ floatPath path) tree treeHasFile :: (MonadError e m, Functor m, Monad m) => Tree m -> FilePath -> m Bool treeHasFile tree path = fst `fmap` virtualTreeMonad (fileExists $ floatPath path) tree -- | In some environments, darcs requires that certain global GHC library variables that -- control the encoding used in internal translations are set to specific values. -- -- @setDarcsEncoding@ enforces those settings, and should be called before the -- first time any darcs operation is run, and again if anything else might have -- set those encodings to different values. -- -- Note that it isn't thread-safe and has a global effect on your program. -- -- The current behaviour of this function is as follows, though this may -- change in future: -- -- Encodings are only set on GHC 7.4 and up, on any non-Windows platform. -- -- Two encodings are set, both to @GHC.IO.Encoding.char8@: -- @GHC.IO.Encoding.setFileSystemEncoding@ and @GHC.IO.Encoding.setForeignEncoding@. -- setDarcsEncodings :: IO () setDarcsEncodings = do #ifdef FORCE_CHAR8_ENCODING -- This is needed for appropriate behaviour from getArgs and from general -- filesystem calls (e.g. getDirectoryContents, readFile, ...) setFileSystemEncoding char8 -- This ensures that foreign calls made by hashed-storage to stat -- filenames returned from getDirectoryContents are translated appropriately setForeignEncoding char8 #endif return () -- The following functions are copied from the encoding package (BSD3 -- licence, by Henning Günther). -- | @getSystemEncoding@ fetches the current encoding from locale foreign import ccall "system_encoding.h get_system_encoding" get_system_encoding :: IO CString getSystemEncoding :: IO String getSystemEncoding = do enc <- get_system_encoding peekCString enc -- | @isUTF8@ checks if an encoding is UTF-8 (or ascii, since it is a -- subset of UTF-8). isUTF8Locale :: String -> Bool isUTF8Locale codeName = case (normalizeEncoding codeName) of -- ASCII "ascii" -> True "646" -> True "ansi_x3_4_1968" -> True "ansi_x3.4_1986" -> True "cp367" -> True "csascii" -> True "ibm367" -> True "iso646_us" -> True "iso_646.irv_1991" -> True "iso_ir_6" -> True "us" -> True "us_ascii" -> True -- UTF-8 "utf_8" -> True "u8" -> True "utf" -> True "utf8" -> True "utf8_ucs2" -> True "utf8_ucs4" -> True -- Everything else _ -> False where normalizeEncoding s = map toLower $ subRegex sep s "_" sep = mkRegex "[^0-9A-Za-z]+" darcs-2.8.4/src/URL/0000755001765600176560000000000012104371431013372 5ustar ganeshganeshdarcs-2.8.4/src/URL/Request.hs0000644001765600176560000000352712104371431015365 0ustar ganeshganeshmodule URL.Request where import Data.Map ( Map ) import Data.List ( delete ) import Foreign.C.Types ( CInt ) data UrlRequest = UrlRequest { url :: String , file :: FilePath , cachable :: Cachable , priority :: Priority } data Cachable = Cachable | Uncachable | MaxAge !CInt deriving (Show, Eq) data UrlState = UrlState { inProgress :: Map String ( FilePath , [FilePath] , Cachable ) , waitToStart :: Q String , pipeLength :: Int , randomJunk :: String } data Q a = Q [a] [a] readQ :: Q a -> Maybe (a, Q a) readQ (Q (x:xs) ys) = Just (x, Q xs ys) readQ (Q [] ys) = do x:xs <- Just $ reverse ys Just (x, Q xs []) insertQ :: a -> Q a -> Q a insertQ y (Q xs ys) = Q xs (y:ys) pushQ :: a -> Q a -> Q a pushQ x (Q xs ys) = Q (x:xs) ys deleteQ :: Eq a => a -> Q a -> Q a deleteQ x (Q xs ys) = Q (delete x xs) (delete x ys) elemQ :: Eq a => a -> Q a -> Bool elemQ x (Q xs ys) = x `elem` xs || x `elem` ys emptyQ :: Q a emptyQ = Q [] [] nullQ :: Q a -> Bool nullQ (Q [] []) = True nullQ _ = False data Priority = High | Low deriving Eq -- | Data type to represent a connection error. -- The following are the codes from libcurl -- which map to each of the constructors: -- * 6 -> CouldNotResolveHost : The remote host was not resolved. -- * 7 -> CouldNotConnectToServer : Failed to connect() to host or proxy. -- * 28 -> OperationTimeout: the specified time-out period was reached. data ConnectionError = CouldNotResolveHost | CouldNotConnectToServer | OperationTimeout deriving (Eq, Read, Show) darcs-2.8.4/src/URL/HTTP.hs0000644001765600176560000001045012104371431014505 0ustar ganeshganesh{-# LANGUAGE CPP #-} module URL.HTTP( fetchUrl, postUrl, requestUrl, waitNextUrl ) where import Prelude hiding ( catch ) import Darcs.Global ( debugFail ) import Version ( version ) import URL.Request ( ConnectionError(..) ) #ifdef HAVE_HTTP import Control.Exception ( catch, IOException ) import Data.IORef ( newIORef, readIORef, writeIORef, IORef ) import Network.HTTP import Network.Browser ( browse, request, setCheckForProxy, setErrHandler, setOutHandler ) import Network.URI import System.IO.Error ( ioeGetErrorString ) import System.IO.Unsafe ( unsafePerformIO ) import Darcs.Global ( debugMessage ) import qualified Data.ByteString as B import qualified Data.ByteString.Char8 as BC #endif fetchUrl :: String -> IO String postUrl :: String -- ^ url -> String -- ^ body -> String -- ^ mime type -> IO () -- ^ result requestUrl :: String -> FilePath -> a -> IO String waitNextUrl :: IO (String, String, Maybe ConnectionError) #ifdef HAVE_HTTP headers :: [Header] headers = [Header HdrUserAgent $ "darcs-HTTP/" ++ version] fetchUrl url = case parseURI url of Nothing -> fail $ "Invalid URI: " ++ url Just uri -> do debugMessage $ "Fetching over HTTP: "++url resp <- catch (browse $ do setCheckForProxy True setOutHandler debugMessage setErrHandler debugMessage request Request { rqURI = uri, rqMethod = GET, rqHeaders = headers, rqBody = "" }) (\(err :: IOException) -> debugFail $ show err) case resp of (_, res@Response { rspCode = (2,0,0) }) -> return (rspBody res) (_, Response { rspCode = (x,y,z) }) -> debugFail $ "HTTP " ++ show x ++ show y ++ show z ++ " error getting " ++ show uri postUrl url body mime = case parseURI url of Nothing -> fail $ "Invalid URI: " ++ url Just uri -> do debugMessage $ "Posting to HTTP: "++url resp <- catch (browse $ do setCheckForProxy True setOutHandler debugMessage setErrHandler debugMessage request Request { rqURI = uri, rqMethod = POST, rqHeaders = headers ++ [Header HdrContentType mime, Header HdrAccept "text/plain", Header HdrContentLength (show $ length body) ], rqBody = body }) (\(err :: IOException) -> debugFail $ show err) case resp of (_, res@Response { rspCode = (2,y,z) }) -> do putStrLn $ "Success 2" ++ show y ++ show z putStrLn (rspBody res) return () (_, res@Response { rspCode = (x,y,z) }) -> do putStrLn $ rspBody res debugFail $ "HTTP " ++ show x ++ show y ++ show z ++ " error posting to " ++ show uri requestedUrl :: IORef (String, FilePath) requestedUrl = unsafePerformIO $ newIORef ("", "") requestUrl u f _ = do (u', _) <- readIORef requestedUrl if null u' then do writeIORef requestedUrl (u, f) return "" else return "URL already requested" waitNextUrl = do (u, f) <- readIORef requestedUrl if null u then return ("", "No URL requested", Nothing) else do writeIORef requestedUrl ("", "") e <- (fetchUrl u >>= \s -> B.writeFile f (BC.pack s) >> return "") `catch` h let ce = case e of "timeout" -> Just OperationTimeout _ -> Nothing return (u, e, ce) where h = return . ioeGetErrorString #else fetchUrl _ = debugFail "Network.HTTP does not exist" postUrl _ _ _ = debugFail "Cannot use http POST because darcs was not compiled with Network.HTTP." requestUrl _ _ _ = debugFail "Network.HTTP does not exist" waitNextUrl = debugFail "Network.HTTP does not exist" #endif darcs-2.8.4/src/URL/Curl.hs0000644001765600176560000000464712104371431014646 0ustar ganeshganesh{-# OPTIONS_GHC -fno-warn-dodgy-imports #-} -- needed for GHC 7.0/7.2 {-# LANGUAGE CPP, ForeignFunctionInterface #-} module URL.Curl where #ifdef HAVE_CURL import Control.Exception.Extensible ( bracket ) import Control.Monad ( when ) import Foreign.C.Types ( CLong(..), CInt(..) ) import Progress ( debugMessage ) import URL.Request import Foreign.C.String ( withCString, peekCString, CString ) import Foreign.Ptr import Foreign.Marshal.Alloc import Foreign.Storable setDebugHTTP :: IO () setDebugHTTP = curl_enable_debug requestUrl :: String -> FilePath -> Cachable -> IO String requestUrl u f cache = withCString u $ \ustr -> withCString f $ \fstr -> do err <- curl_request_url ustr fstr (cachableToInt cache) >>= peekCString return err waitNextUrl :: IO (String, String, Maybe ConnectionError) waitNextUrl = bracket malloc free $ \ errorPointer -> bracket malloc free $ \ httpErrorPointer -> do e <- curl_wait_next_url errorPointer httpErrorPointer >>= peekCString ce <- do errorNum <- peek errorPointer if not (null e) then return $ case errorNum of 6 -> Just CouldNotResolveHost 7 -> Just CouldNotConnectToServer 28 -> Just OperationTimeout _ -> Nothing else do when (errorNum == 90 ) $ debugMessage "The environment variable DARCS_CONNECTION_TIMEOUT is not a number" return Nothing u <- curl_last_url >>= peekCString httpErrorCode <- peek httpErrorPointer let detailedErrorMessage = if httpErrorCode > 0 then e ++ " " ++ show httpErrorCode else e return (u, detailedErrorMessage, ce) pipeliningEnabled :: IO Bool pipeliningEnabled = do r <- curl_pipelining_enabled return $ r /= 0 cachableToInt :: Cachable -> CInt cachableToInt Cachable = -1 cachableToInt Uncachable = 0 cachableToInt (MaxAge n) = n foreign import ccall "hscurl.h curl_request_url" curl_request_url :: CString -> CString -> CInt -> IO CString foreign import ccall "hscurl.h curl_wait_next_url" curl_wait_next_url :: Ptr CInt -> Ptr CLong-> IO CString foreign import ccall "hscurl.h curl_last_url" curl_last_url :: IO CString foreign import ccall "hscurl.h curl_enable_debug" curl_enable_debug :: IO () foreign import ccall "hscurl.h curl_pipelining_enabled" curl_pipelining_enabled :: IO CInt #endifdarcs-2.8.4/src/win32/0000755001765600176560000000000012104371431013672 5ustar ganeshganeshdarcs-2.8.4/src/win32/System/0000755001765600176560000000000012104371431015156 5ustar ganeshganeshdarcs-2.8.4/src/win32/System/Posix/0000755001765600176560000000000012104371431016260 5ustar ganeshganeshdarcs-2.8.4/src/win32/System/Posix/Files.hsc0000644001765600176560000000257212104371431020027 0ustar ganeshganesh{-# OPTIONS_GHC -fno-warn-dodgy-imports #-} -- needed for GHC 7.0/7.2 {-# LANGUAGE CPP, ForeignFunctionInterface #-} module System.Posix.Files( isNamedPipe, isDirectory, isRegularFile, isSymbolicLink , getFdStatus, getFileStatus, getSymbolicLinkStatus , modificationTime, setFileMode, fileSize, fileMode , stdFileMode, linkCount, createLink , FileStatus ) where import System.PosixCompat.Files( isNamedPipe, isDirectory, isRegularFile, isSymbolicLink , getFdStatus, getFileStatus, getSymbolicLinkStatus , modificationTime, setFileMode, fileSize, fileMode , stdFileMode, FileStatus ) import Foreign.C.String( CWString, withCWString ) import Foreign.C.Error( throwErrnoPathIf_ ) import Foreign.Ptr( Ptr, nullPtr ) import Foreign.C( CInt(..) ) linkCount :: FileStatus -> Int linkCount _ = 1 #define _WIN32_WINNT 0x0500 foreign import stdcall "winbase.h CreateHardLinkW" c_CreateHardLink :: CWString -> CWString -> Ptr a -> IO CInt createLink :: FilePath -> FilePath -> IO () createLink old new = withCWString old $ \c_old -> withCWString new $ \c_new -> throwErrnoPathIf_ (==0) "createLink" new $ c_CreateHardLink c_new c_old nullPtr darcs-2.8.4/src/win32/System/Posix/IO.hsc0000644001765600176560000000376212104371431017276 0ustar ganeshganesh{-# LANGUAGE ForeignFunctionInterface #-} module System.Posix.IO where #if mingw32_HOST_OS && __GLASGOW_HASKELL__ >= 612 import Foreign.C.String( withCWString ) #else import Foreign.C.String ( withCString ) #endif import Foreign.C.Error ( throwErrnoIfMinus1, throwErrnoIfMinus1_ ) import GHC.IO.Handle.FD ( fdToHandle ) import System.Posix.Internals ( c_open, c_close, c_dup2 ) import System.Posix.Types ( Fd(..), FileMode ) import System.IO ( Handle ) import Data.Bits ( (.|.) ) stdOutput :: Fd stdOutput = Fd 1 stdError :: Fd stdError = Fd 2 data OpenFileFlags = OpenFileFlags { append :: Bool, exclusive :: Bool, noctty :: Bool, nonBlock :: Bool, trunc :: Bool } -- Adapted from System.Posix.IO in ghc #include openFd :: FilePath -> OpenMode -> Maybe FileMode -> OpenFileFlags -> IO Fd openFd name how maybe_mode off = do #if mingw32_HOST_OS && __GLASGOW_HASKELL__ >= 612 withCWString name $ \s -> do #else withCString name $ \s -> do #endif fd <- throwErrnoIfMinus1 "openFd" (c_open s all_flags mode_w) return (Fd fd) where all_flags = binary .|. creat .|. flags .|. open_mode flags = (if append off then (#const O_APPEND) else 0) .|. (if exclusive off then (#const O_EXCL) else 0) .|. (if trunc off then (#const O_TRUNC) else 0) binary = (#const O_BINARY) (creat, mode_w) = maybe (0,0) (\x->((#const O_CREAT),x)) maybe_mode open_mode = case how of ReadOnly -> (#const O_RDONLY) WriteOnly -> (#const O_WRONLY) ReadWrite -> (#const O_RDWR) closeFd :: Fd -> IO () closeFd (Fd fd) = throwErrnoIfMinus1_ "closeFd" (c_close fd) fdToHandle :: Fd -> IO Handle fdToHandle fd = GHC.IO.Handle.FD.fdToHandle (fromIntegral fd) dupTo :: Fd -> Fd -> IO Fd dupTo (Fd fd1) (Fd fd2) = do r <- throwErrnoIfMinus1 "dupTo" (c_dup2 fd1 fd2) return (Fd r) data OpenMode = ReadOnly | WriteOnly | ReadWrite defaultFileFlags :: OpenFileFlags defaultFileFlags = OpenFileFlags False False False False False darcs-2.8.4/src/win32/System/Posix.hs0000644001765600176560000000056012104371431016615 0ustar ganeshganesh{-# OPTIONS_GHC -fno-warn-dodgy-imports #-} -- needed for GHC 7.0/7.2 {-# LANGUAGE ForeignFunctionInterface #-} module System.Posix ( sleep ) where import Foreign.C.Types ( CInt(..), CUInt(..), CULong(..) ) foreign import stdcall "winbase.h SleepEx" c_SleepEx :: CULong -> CUInt -> IO CInt sleep :: Integer -> IO CInt sleep n = c_SleepEx (1000 * fromIntegral n) 1 darcs-2.8.4/src/win32/sys/0000755001765600176560000000000012104371431014510 5ustar ganeshganeshdarcs-2.8.4/src/win32/sys/mman.h0000644001765600176560000000022612104371431015611 0ustar ganeshganesh #include void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset); int munmap(void *start, size_t length); darcs-2.8.4/src/win32/CtrlC.hs0000644001765600176560000000113212104371431015232 0ustar ganeshganesh{-# LANGUAGE ForeignFunctionInterface #-} module CtrlC (withCtrlCHandler) where import Data.Word ( Word32 ) import Foreign.Ptr ( FunPtr ) import Control.Exception ( bracket ) type Handler = Word32 -> IO Int foreign import ccall "wrapper" wrap :: Handler -> IO (FunPtr Handler) foreign import stdcall "SetConsoleCtrlHandler" setConsoleCtrlHandler :: FunPtr Handler -> Int -> IO () withCtrlCHandler :: IO () -> IO a -> IO a withCtrlCHandler handler m = do fp <- wrap (\_ctrlType -> handler >> return 1) bracket (setConsoleCtrlHandler fp 1) (const $ setConsoleCtrlHandler fp 0) (const m) darcs-2.8.4/src/win32/send_email.c0000644001765600176560000002137412104371431016145 0ustar ganeshganesh #include #include #include #include "send_email.h" typedef struct sMapiFuns { LPMAPILOGON logon; LPMAPISENDMAIL sendmail; LPMAPIRESOLVENAME resolve; LPMAPIFREEBUFFER free_buf; LPMAPILOGOFF logoff; HMODULE dll; } MapiFuns; int load_dll(const char* name, MapiFuns* funs); void free_dll(MapiFuns* funs); void get_recipient(MapiFuns* funs, const char *name, ULONG recipClass, MapiRecipDesc *desc, lpMapiRecipDesc *desc_lookup); int send_email(const char *sendname, const char *recvname, const char *ccname, const char *subj, const char *body, const char *path) { FLAGS flags; MapiMessage msg; ULONG send_res; MapiRecipDesc orig; MapiRecipDesc recips[2]; MapiRecipDesc *orig_lookup, *recip_lookup, *cc_lookup; int num_recip = 1, return_code = -1; MapiFileDesc attachment; MapiFileTagExt file_type; const char *filename; char *attachment_path = 0; MapiFuns funs; if(load_dll("mapistub.dll", &funs) || load_dll("mapi32.dll", &funs)) { return_code=0; } else { fprintf(stderr, "Unable to load mapistub.dll or mapi32.dll: Bailing out. \n"); return_code=-1; } if(return_code==0) { LHANDLE session; /* logon seems to be necessary for outlook express, sometimes, and doesn't seem to hurt, otherwise. */ funs.logon(0, 0, 0, MAPI_LOGON_UI, 0, &session); orig_lookup = recip_lookup = cc_lookup = NULL; get_recipient(&funs, sendname, MAPI_ORIG, &orig, &orig_lookup); get_recipient(&funs, recvname, MAPI_TO, &recips[0], &recip_lookup); if (ccname && strlen(ccname) > 0) { get_recipient(&funs, ccname, MAPI_CC, &recips[1], &cc_lookup); num_recip++; } memset(&msg, 0, sizeof(msg)); msg.lpOriginator = &orig; msg.lpRecips = recips; msg.lpszMessageType = "text/plain"; msg.lpszNoteText = (LPSTR) body; msg.lpszSubject = (LPSTR)subj; msg.nRecipCount = num_recip; msg.flFlags = 0; if (path) { attachment_path = strdup(path); /* convert / to \ (thunderbird doesn't like /) */ char *p = attachment_path; while ((p = strchr(p, '/'))) *p = '\\'; /* find filename */ filename = strrchr(attachment_path, '\\'); if (filename == 0) filename = attachment_path; else filename++; memset(&attachment, 0, sizeof(attachment)); attachment.nPosition = -1; attachment.lpszPathName = (LPTSTR)attachment_path; attachment.lpszFileName = (LPTSTR)filename; attachment.lpFileType = &file_type; memset(&file_type, 0, sizeof(file_type)); file_type.lpTag = "text/plain"; file_type.cbTag = sizeof(file_type.lpTag); msg.nFileCount = 1; msg.lpFiles = &attachment; } flags = 0; send_res = funs.sendmail(0, 0, &msg, flags, 0); if (send_res == SUCCESS_SUCCESS) return_code = 0; else { return_code=-1; if(send_res==MAPI_E_USER_ABORT) fprintf(stderr, "MAPI error: User aborted.\n"); else if(send_res== MAPI_E_FAILURE) fprintf(stderr, "MAPI error: Generic error.\n"); else if(send_res== MAPI_E_LOGIN_FAILURE) fprintf(stderr, "MAPI error: Login failure.\n"); else if(send_res== MAPI_E_DISK_FULL) fprintf(stderr, "MAPI error: Disk full.\n"); else if(send_res== MAPI_E_INSUFFICIENT_MEMORY) fprintf(stderr, "MAPI error: Insufficient memory.\n"); else if(send_res== MAPI_E_ACCESS_DENIED) fprintf(stderr, "MAPI error: Access denied.\n"); else if(send_res== MAPI_E_TOO_MANY_SESSIONS) fprintf(stderr, "MAPI error: Too many sessions\n"); else if(send_res== MAPI_E_TOO_MANY_FILES) fprintf(stderr, "MAPI error: Too many files.\n"); else if(send_res== MAPI_E_TOO_MANY_RECIPIENTS) fprintf(stderr, "MAPI error: Too many recipients.\n"); else if(send_res== MAPI_E_ATTACHMENT_NOT_FOUND) fprintf(stderr, "MAPI error: Attachment not found.\n"); else if(send_res== MAPI_E_ATTACHMENT_OPEN_FAILURE) fprintf(stderr, "MAPI error: Failed to open attachment.\n"); else if(send_res== MAPI_E_ATTACHMENT_WRITE_FAILURE) fprintf(stderr, "MAPI error: Failed to write attachment.\n"); else if(send_res== MAPI_E_UNKNOWN_RECIPIENT) fprintf(stderr, "MAPI error: Unknown recipient\n"); else if(send_res== MAPI_E_BAD_RECIPTYPE) fprintf(stderr, "MAPI error: Bad type of recipent.\n"); else if(send_res== MAPI_E_NO_MESSAGES) fprintf(stderr, "MAPI error: No messages.\n"); else if(send_res== MAPI_E_INVALID_MESSAGE) fprintf(stderr, "MAPI error: Invalid message.\n"); else if(send_res== MAPI_E_TEXT_TOO_LARGE) fprintf(stderr, "MAPI error: Text too large.\n"); else if(send_res== MAPI_E_INVALID_SESSION) fprintf(stderr, "MAPI error: Invalid session.\n"); else if(send_res== MAPI_E_TYPE_NOT_SUPPORTED) fprintf(stderr, "MAPI error: Type not supported.\n"); else if(send_res== MAPI_E_AMBIGUOUS_RECIP) fprintf(stderr, "MAPI error: Ambigious recipient.\n"); else if(send_res== MAPI_E_MESSAGE_IN_USE) fprintf(stderr, "MAPI error: Messag in use.\n"); else if(send_res== MAPI_E_NETWORK_FAILURE) fprintf(stderr, "MAPI error: Network failure.\n"); else if(send_res== MAPI_E_INVALID_EDITFIELDS) fprintf(stderr, "MAPI error: Invalid editfields\n"); else if(send_res== MAPI_E_INVALID_RECIPS) fprintf(stderr, "MAPI error: Invalid recipient(s)\n"); else if(send_res== MAPI_E_NOT_SUPPORTED) fprintf(stderr, "MAPI error: Operation not supported.\n"); else fprintf(stderr, "MAPISendMail returned %ld\n", send_res); } if (orig_lookup) funs.free_buf(orig_lookup); if (recip_lookup) funs.free_buf(recip_lookup); if (cc_lookup) funs.free_buf(cc_lookup); if (attachment_path) free(attachment_path); funs.logoff(session, 0, 0, 0); } free_dll(&funs); return return_code; } void get_recipient(MapiFuns* funs, const char *name, ULONG recipClass, MapiRecipDesc *desc, lpMapiRecipDesc *desc_lookup) { ULONG ret = funs->resolve(0, 0, (LPSTR) name, 0, 0, desc_lookup); if (ret == SUCCESS_SUCCESS) { memcpy(desc, *desc_lookup, sizeof(MapiRecipDesc)); } else { /* Default to something sensible if MAPIResolveName is not supported * by the mail client (thunderbird) */ memset(desc, 0, sizeof(MapiRecipDesc)); desc->lpszName = (LPSTR)name; desc->lpszAddress = (LPSTR)name; desc->lpEntryID = 0; desc->ulEIDSize = 0; } desc->ulRecipClass = recipClass; } int load_dll(const char* name, MapiFuns* funs) { funs->dll = 0; funs->dll = LoadLibrary(name); if(funs->dll!=NULL) { /* We try first loading by easy name, then by ordinal, and then by other names seen */ funs->logon = (LPMAPILOGON) GetProcAddress(funs->dll, "MAPILogon"); if(funs->logon==NULL) funs->logon = (LPMAPILOGON) GetProcAddress(funs->dll, (LPCSTR)209); funs->logoff = (LPMAPILOGOFF) GetProcAddress(funs->dll, "MAPILogOff"); if(funs->logoff==NULL) funs->logoff = (LPMAPILOGOFF) GetProcAddress(funs->dll, (LPCSTR)210); funs->resolve = (LPMAPIRESOLVENAME) GetProcAddress(funs->dll, "MAPIResolveName"); if(funs->resolve==NULL) funs->resolve = (LPMAPIRESOLVENAME) GetProcAddress(funs->dll, (LPCSTR)219); funs->free_buf = (LPMAPIFREEBUFFER) GetProcAddress(funs->dll, "MAPIFreeBuffer"); if(funs->free_buf==NULL) funs->free_buf = (LPMAPIFREEBUFFER) GetProcAddress(funs->dll, (LPCSTR)16); if(funs->free_buf==NULL) funs->free_buf = (LPMAPIFREEBUFFER) GetProcAddress(funs->dll, "MAPIFreeBuffer@4"); funs->sendmail = (LPMAPISENDMAIL) GetProcAddress(funs->dll, "MAPISendMail"); if(funs->sendmail==NULL) funs->sendmail = (LPMAPISENDMAIL) GetProcAddress(funs->dll, (LPCSTR)211); } return funs->dll!=NULL && funs->logon!=NULL && funs->logoff!=NULL && funs->resolve!=NULL && funs->free_buf!=NULL && funs->sendmail!=NULL; } void free_dll(MapiFuns* funs) { if(funs->dll!=NULL) FreeLibrary(funs->dll); funs->dll=NULL; } darcs-2.8.4/src/win32/send_email.h0000644001765600176560000000032712104371431016145 0ustar ganeshganesh int send_email(const char *sendname, const char *recvname, const char *ccname, const char *subj, const char *body, const char *path); darcs-2.8.4/src/Encoding/0000755001765600176560000000000012104371431014456 5ustar ganeshganeshdarcs-2.8.4/src/Encoding/Win32.hs0000644001765600176560000000666012104371431015724 0ustar ganeshganesh-- Copyright 2007-2009, Judah Jacobson. -- All Rights Reserved. -- Redistribution and use in source and binary forms, with or without -- modification, are permitted provided that the following conditions are met: -- - Redistribution of source code must retain the above copyright notice, -- this list of conditions and the following disclaimer. -- - Redistribution in binary form must reproduce the above copyright notice, -- this list of conditions and the following disclaimer in the documentation -- and/or other materials provided with the distribution. -- THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY -- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -- DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR THE CONTRIBUTORS BE LIABLE -- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -- SERVICES; LOSS OF USE, DATA OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -- OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -- USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. {-# LANGUAGE ForeignFunctionInterface #-} module Encoding.Win32 ( encode, decode ) where import Data.ByteString.Internal ( createAndTrim ) import qualified Data.ByteString as B ( ByteString, useAsCStringLen ) import Foreign ( castPtr, allocaArray0 ) import Foreign.C ( CInt(..), peekCWStringLen, withCWStringLen ) import System.Win32 ( CodePage, nullPtr, getConsoleCP, getACP , LPCSTR, LPWSTR, LPCWSTR, LPBOOL, DWORD ) encode :: String -> IO B.ByteString encode str = getCodePage >>= flip unicodeToCodePage str decode :: B.ByteString -> IO String decode str = getCodePage >>= flip codePageToUnicode str ------------------------ -- Multi-byte conversion foreign import stdcall "WideCharToMultiByte" wideCharToMultiByte :: CodePage -> DWORD -> LPCWSTR -> CInt -> LPCSTR -> CInt -> LPCSTR -> LPBOOL -> IO CInt unicodeToCodePage :: CodePage -> String -> IO B.ByteString unicodeToCodePage cp wideStr = withCWStringLen wideStr $ \(wideBuff, wideLen) -> do -- first, ask for the length without filling the buffer. outSize <- wideCharToMultiByte cp 0 wideBuff (toEnum wideLen) nullPtr 0 nullPtr nullPtr -- then, actually perform the encoding. createAndTrim (fromEnum outSize) $ \outBuff -> fmap fromEnum $ wideCharToMultiByte cp 0 wideBuff (toEnum wideLen) (castPtr outBuff) outSize nullPtr nullPtr foreign import stdcall "MultiByteToWideChar" multiByteToWideChar :: CodePage -> DWORD -> LPCSTR -> CInt -> LPWSTR -> CInt -> IO CInt codePageToUnicode :: CodePage -> B.ByteString -> IO String codePageToUnicode cp bs = B.useAsCStringLen bs $ \(inBuff, inLen) -> do -- first ask for the size without filling the buffer. outSize <- multiByteToWideChar cp 0 inBuff (toEnum inLen) nullPtr 0 -- then, actually perform the decoding. allocaArray0 (fromEnum outSize) $ \outBuff -> do outSize' <- multiByteToWideChar cp 0 inBuff (toEnum inLen) outBuff outSize peekCWStringLen (outBuff, fromEnum outSize') getCodePage :: IO CodePage getCodePage = do conCP <- getConsoleCP if conCP > 0 then return conCP else getACP darcs-2.8.4/src/Encoding/IConv.hsc0000644001765600176560000001627212104371431016203 0ustar ganeshganesh-- Copyright 2007-2009, Judah Jacobson. -- All Rights Reserved. -- Redistribution and use in source and binary forms, with or without -- modification, are permitted provided that the following conditions are met: -- - Redistribution of source code must retain the above copyright notice, -- this list of conditions and the following disclaimer. -- - Redistribution in binary form must reproduce the above copyright notice, -- this list of conditions and the following disclaimer in the documentation -- and/or other materials provided with the distribution. -- THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY -- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -- DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR THE CONTRIBUTORS BE LIABLE -- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -- SERVICES; LOSS OF USE, DATA OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -- OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -- USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. {-# LANGUAGE ForeignFunctionInterface #-} module Encoding.IConv ( encode, decode ) where import Foreign.C ( CString, CSize(..), CInt(..) , peekCAString, withCAString , Errno(..), getErrno, throwErrno, eINVAL, e2BIG ) import Foreign ( Ptr, castPtr, nullPtr, plusPtr , peek, maybePeek , with, maybeWith , ForeignPtr, withForeignPtr, newForeignPtr , FunPtr , Int32, Word8 ) import Control.Exception ( bracket ) import Data.ByteString ( ByteString, useAsCStringLen, append ) import Data.ByteString.Internal ( createAndTrim' ) import qualified Data.ByteString as B import qualified Data.ByteString.UTF8 as UTF8 import Data.Maybe ( fromMaybe ) #include #include #include "h_iconv.h" getLocaleCodeset :: IO String getLocaleCodeset = bracket (setLocale (Just "")) setLocale (const getCodeset) encode :: String -> IO ByteString encode str = getLocaleCodeset >>= \codeset -> openEncoder codeset >>= ($ str) decode :: ByteString -> IO String decode str = getLocaleCodeset >>= \codeset -> openDecoder codeset >>= ($ str) openEncoder :: String -> IO (String -> IO ByteString) openEncoder codeset = do encodeT <- iconvOpen codeset "UTF-8" return $ simpleIConv dropUTF8Char encodeT . UTF8.fromString openDecoder :: String -> IO (ByteString -> IO String) openDecoder codeset = do decodeT <- iconvOpen "UTF-8" codeset return $ fmap UTF8.toString . simpleIConv (B.drop 1) decodeT dropUTF8Char :: ByteString -> ByteString dropUTF8Char = fromMaybe B.empty . fmap snd . UTF8.uncons replacement :: Word8 replacement = toEnum (fromEnum '?') -- handle errors by dropping unuseable chars. simpleIConv :: (ByteString -> ByteString) -> IConvT -> ByteString -> IO ByteString simpleIConv dropper t bs = do (cs,result) <- iconv t bs case result of Invalid rest -> continueOnError cs rest Incomplete rest -> continueOnError cs rest _ -> return cs where continueOnError cs rest = fmap ((cs `append`) . (replacement `B.cons`)) $ simpleIConv dropper t (dropper rest) --------------------- -- Setting the locale foreign import ccall "setlocale" c_setlocale :: CInt -> CString -> IO CString setLocale :: Maybe String -> IO (Maybe String) setLocale oldLocale = (maybeWith withCAString) oldLocale $ \loc_p -> do c_setlocale (#const LC_CTYPE) loc_p >>= maybePeek peekCAString ----------------- -- Getting the encoding type NLItem = #type nl_item foreign import ccall nl_langinfo :: NLItem -> IO CString getCodeset :: IO String getCodeset = do str <- nl_langinfo (#const CODESET) >>= peekCAString -- check for codesets which may be returned by Solaris, but not understood -- by GNU iconv. if str `elem` ["","646"] then return "ISO-8859-1" else return str ---------------- -- Iconv -- TODO: This may not work on platforms where iconv_t is not a pointer. type IConvT = ForeignPtr () type IConvTPtr = Ptr () foreign import ccall "haskeline_iconv_open" iconv_open :: CString -> CString -> IO IConvTPtr iconvOpen :: String -> String -> IO IConvT iconvOpen destName srcName = withCAString destName $ \dest -> withCAString srcName $ \src -> do res <- iconv_open dest src if res == nullPtr `plusPtr` (-1) then throwErrno $ "iconvOpen " ++ show (srcName,destName) -- list the two it couldn't convert between? else newForeignPtr iconv_close res -- really this returns a CInt, but it's easiest to just ignore that, I think. foreign import ccall "& haskeline_iconv_close" iconv_close :: FunPtr (IConvTPtr -> IO ()) foreign import ccall "haskeline_iconv" c_iconv :: IConvTPtr -> Ptr CString -> Ptr CSize -> Ptr CString -> Ptr CSize -> IO CSize data Result = Successful | Invalid ByteString | Incomplete ByteString deriving Show iconv :: IConvT -> ByteString -> IO (ByteString,Result) iconv cd inStr = useAsCStringLen inStr $ \(inPtr, inBuffLen) -> with inPtr $ \inBuff -> with (toEnum inBuffLen) $ \inBytesLeft -> do out <- loop inBuffLen (castPtr inBuff) inBytesLeft return out where -- TODO: maybe a better algorithm for increasing the buffer size? -- and also maybe a different starting buffer size? biggerBuffer = (+1) loop outSize inBuff inBytesLeft = do (bs, errno) <- partialIconv cd outSize inBuff inBytesLeft inLeft <- fmap fromEnum $ peek inBytesLeft let rest = B.drop (B.length inStr - inLeft) inStr case errno of Nothing -> return (bs,Successful) Just err | err == e2BIG -> do -- output buffer too small (bs',result) <- loop (biggerBuffer outSize) inBuff inBytesLeft -- TODO: is this efficient enough? return (bs `append` bs', result) | err == eINVAL -> return (bs,Incomplete rest) | otherwise -> return (bs, Invalid rest) partialIconv :: IConvT -> Int -> Ptr CString -> Ptr CSize -> IO (ByteString, Maybe Errno) partialIconv cd outSize inBuff inBytesLeft = withForeignPtr cd $ \cd_p -> createAndTrim' outSize $ \outPtr -> with outPtr $ \outBuff -> with (toEnum outSize) $ \outBytesLeft -> do -- ignore the return value; checking the errno is more reliable. _ <- c_iconv cd_p inBuff inBytesLeft (castPtr outBuff) outBytesLeft outLeft <- fmap fromEnum $ peek outBytesLeft inLeft <- peek inBytesLeft errno <- if inLeft > 0 then fmap Just getErrno else return Nothing return (0,outSize - outLeft,errno) darcs-2.8.4/src/CommandLine.hs0000644001765600176560000001201712104371431015453 0ustar ganeshganesh-- Copyright (C) 2005 Benedikt Schmidt -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. -- | -- Module : CommandLine -- Copyright : 2005 Benedikt Schmidt -- License : GPL -- Maintainer : darcs-devel@darcs.net -- Stability : experimental -- Portability : portable -- -- |A parser for commandlines, returns an arg list and expands -- format strings given in a translation table. Additionally -- the commandline can end with "%<" specifying that the command -- expects input on stdin. -- -- Some tests for the parser. -- -- > formatTable = [('s',""), -- > ('a',"")] -- > -- > testParser :: (Show a, Eq a) => Parser a -> String -> a -> a -- > testParser p s ok = case parse p "" s of -- > Left e -> error $ "Parser failed with: " ++ (show e) -- > Right res -> if res == ok -- > then res -- > else error $ "Parser failed: got " -- > ++ (show res) ++ ", expected " -- > ++ (show ok) -- > -- > testCases = [("a b",(["a","b"], False)), -- > ("a b %<",(["a","b"], True)), -- > ("a b %< ",(["a","b"], True)), -- > ("\"arg0 contains spaces \\\"quotes\\\"\" b", -- > (["arg0 contains spaces \"quotes\"","b"],False)), -- > ("a %s %<",(["a",""], True))] -- > -- > runTests = map (uncurry $ testParser (commandline formatTable)) testCases module CommandLine ( parseCmd , addUrlencoded ) where import Control.Arrow ( (***) ) import Data.Char ( ord, intToDigit, toUpper ) import Data.List ( find ) import Text.ParserCombinators.Parsec -- | assoc list mapping characters to strings -- eg (c,s) means that %c is replaced by s type FTable = [(Char,String)] commandline :: FTable -> Parser ([String], Bool) commandline ftable = consumeAll $ do l <- sepEndBy1 (arg ftable) (try separator) redir <- formatRedir spaces return (l,redir) arg :: FTable -> Parser String arg ftable = quotedArg ftable <|> unquotedArg ftable unquotedArg :: FTable -> Parser String unquotedArg ftable = try (format ftable) <|> many1 (noneOf " \t\"%") quotedArg :: FTable -> Parser String quotedArg ftable = between quoteChar quoteChar $ quoteContent ftable where quoteChar = char '"' quoteContent :: FTable -> Parser String quoteContent ftable = do s1 <- escape <|> try (format ftable) <|> many1 (noneOf "\"\\%") s2 <- quoteContent ftable return $ s1 ++ s2 <|> return "" formatRedir :: Parser Bool formatRedir = (string "%<" >> return True) <|> return False format :: FTable -> Parser String format ftable = do _ <- char '%' c <- oneOf (map fst ftable) return $ expandFormat ftable c escape :: Parser String escape = do _ <- char '\\' c <- anyChar return [c] consumeAll :: Parser a -> Parser a consumeAll p = do r <- p eof return r separator :: Parser () separator = skipMany1 space expandFormat :: FTable -> Char -> String expandFormat ftable c = case find ((==c) . fst) ftable of Just (_,s) -> s Nothing -> error "impossible" -- | parse a commandline returning a list of strings -- (intended to be used as argv) and a bool value which -- specifies if the command expects input on stdin -- format specifiers with a mapping in ftable are accepted -- and replaced by the given strings. E.g. if the ftable is -- [('s',"Some subject")], then "%s" is replaced by "Some subject" parseCmd :: FTable -> String -> Either ParseError ([String],Bool) parseCmd ftable = parse (commandline ftable) "" urlEncode :: String -> String urlEncode s = concatMap escapeC s where escapeC x = if allowed x then [x] else '%' : intToHex (ord x) intToHex i = map intToDigit [i `div` 16, i `mod` 16] allowed x = x `elem` allowedChars allowedChars = ['a'..'z'] ++ ['A'..'Z'] ++ ['0'..'9'] ++ "!'()*-.~" -- | for every mapping (c,s), add a mapping with uppercase c -- and the urlencoded string s addUrlencoded :: FTable -> FTable addUrlencoded ftable = ftable ++ map (toUpper *** urlEncode) ftable darcs-2.8.4/src/DateMatcher.hs0000644001765600176560000001667412104371431015463 0ustar ganeshganesh-- Copyright (C) 2004 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE ExistentialQuantification #-} -- | -- Module : DateMatcher -- Copyright : 2004 David Roundy -- License : GPL -- Maintainer : darcs-devel@darcs.net -- Stability : experimental -- Portability : portable module DateMatcher ( parseDateMatcher -- for debugging only , DateMatcher(..) , getMatchers ) where import Control.Exception.Extensible ( catch, throw ) import Data.Maybe ( isJust ) import Prelude hiding ( catch ) import System.IO.Error ( isUserError, ioeGetErrorString ) import System.Time import Text.ParserCombinators.Parsec ( eof, parse, ParseError ) import IsoDate ( parseDate, englishDateTime, englishInterval, englishLast, iso8601Interval, resetCalendar, subtractFromMCal, getLocalTz, MCalendarTime(..), toMCalendarTime, unsafeToCalendarTime, unsetTime ) -- | 'withinDay' @x y@ is true if @x <= y < (x + one_day)@ -- Note that this converts the two dates to @ClockTime@ to avoid -- any timezone-related errors withinDay :: CalendarTime -> CalendarTime -> Bool withinDay a b = within (Just $ toClockTime a) (Just (addToClockTime day $ toClockTime a)) (toClockTime b) where day = TimeDiff 0 0 1 0 0 0 0 -- | 'dateRange' @x1 x2 y@ is true if @x1 <= y < x2@ -- Since @x1@ and @x2@ can be underspecified, we simply assume the -- first date that they could stand for. dateRange :: Maybe MCalendarTime -> Maybe MCalendarTime -> CalendarTime -> Bool dateRange a b = cDateRange (fmap unsafeToCalendarTime a) (fmap unsafeToCalendarTime b) -- | 'cDateRange' @x1 x2 y@ is true if @x1 <= y < x2@ cDateRange :: Maybe CalendarTime -> Maybe CalendarTime -> CalendarTime -> Bool cDateRange a b c = within (fmap toClockTime a) (fmap toClockTime b) (toClockTime c) -- | 'within' @x1 x2 y@ is true if @x1 <= y < x2@ within :: Maybe ClockTime -> Maybe ClockTime -> ClockTime -> Bool within (Just start) (Just end) time = start <= time && time < end within Nothing (Just end) time = time < end within (Just start) Nothing time = start <= time within _ _ _ = undefined -- | 'samePartialDate' @range exact@ is true if @exact@ falls -- within the a range of dates represented by @range@. -- The purpose of this function is to support matching on partially -- specified dates. That is, if you only specify the date 2007, -- this function should match any dates within that year. On the -- other hand, if you specify 2007-01, this function will match any -- dates within that month. This function only matches up to the -- second. samePartialDate :: MCalendarTime -> CalendarTime -> Bool samePartialDate a b_ = within (Just clockA) (Just $ addToClockTime interval clockA) (toClockTime calB) where interval | isJust (mctSec a) = second | isJust (mctMin a) = minute | isJust (mctHour a) = hour | isJust (mctYDay a) = day | mctWeek a = maybe week (const day) (mctWDay a) | isJust (mctDay a) = day | isJust (mctMonth a) = month | otherwise = year year = TimeDiff 1 0 0 0 0 0 0 month = TimeDiff 0 1 0 0 0 0 0 week = TimeDiff 0 0 7 0 0 0 0 day = TimeDiff 0 0 1 0 0 0 0 hour = TimeDiff 0 0 0 1 0 0 0 minute = TimeDiff 0 0 0 0 1 0 0 second = TimeDiff 0 0 0 0 0 1 0 clockA = toClockTime $ unsafeToCalendarTime a calB = resetCalendar b_ -- | A 'DateMatcher' combines a potential parse for a date string -- with a "matcher" function that operates on a given date. -- We use an existential type on the matcher to allow -- the date string to either be interpreted as a point in time -- or as an interval. data DateMatcher = forall d . (Show d) => DM String -- name (Either ParseError d) -- parser (d -> CalendarTime -> Bool) -- matcher -- | 'parseDateMatcher' @s@ return the first matcher in -- 'getMatchers' that can parse 's' parseDateMatcher :: String -> IO (CalendarTime -> Bool) parseDateMatcher d = testDateMatcher `catchUserError` handleError where catchUserError comp handler = catch comp $ \e -> if isUserError e then handler (ioeGetErrorString e) else throw e -- If the user enters a date > maxint seconds ago, the toClockTime -- function cannot work. handleError e = if e == "Time.toClockTime: invalid input" then error "Can't handle dates that far back!" else error e -- Hack: test the matcher against the current date and discard the results. -- We just want to make sure it won't throw any exceptions when we use it -- for real. testDateMatcher = do matcher <- tryMatchers `fmap` getMatchers d matcher `fmap` now >>= (`seq` return matcher) -- | 'getMatchers' @d@ returns the list of matchers that will be -- applied on @d@. If you wish to extend the date parsing code, -- this will likely be the function that you modify to do so. getMatchers :: String -> IO [DateMatcher] getMatchers d = do rightNow <- now let midnightToday = unsetTime rightNow mRightNow = toMCalendarTime rightNow matchIsoInterval (Left dur) = let durAgo = dur `subtractFromMCal` mRightNow in dateRange (Just durAgo) (Just mRightNow) matchIsoInterval (Right (a,b)) = dateRange (Just a) (Just b) tzNow <- getLocalTz return -- note that the order of these is quite important as some matchers can -- match the same date. [ DM "from English date" (parseDateWith $ englishLast midnightToday) (\(a,_) -> cDateRange (Just a) Nothing) , DM "specific English date" (parseDateWith $ englishDateTime midnightToday) withinDay , DM "English interval" (parseDateWith $ englishInterval rightNow) (uncurry cDateRange) , DM "ISO 8601 interval" (parseDateWith $ iso8601Interval tzNow) matchIsoInterval , DM "CVS, ISO 8601, or old style date" (parseDate tzNow d) samePartialDate ] where tillEof p = do { x <- p; eof; return x } parseDateWith p = parse (tillEof p) "" d -- | 'tryMatchers' @ms@ returns the first successful match in @ms@ -- It is an error if there are no matches tryMatchers :: [DateMatcher] -> CalendarTime -> Bool tryMatchers (DM _ parsed matcher : ms) = case parsed of Left _ -> tryMatchers ms Right d -> matcher d tryMatchers [] = error "Can't support fancy dates." now :: IO CalendarTime now = getClockTime >>= toCalendarTime darcs-2.8.4/src/Encoding.hs0000644001765600176560000000364012104371431015015 0ustar ganeshganesh-- Copyright 2007-2009, Judah Jacobson. -- All Rights Reserved. -- Redistribution and use in source and binary forms, with or without -- modification, are permitted provided that the following conditions are met: -- - Redistribution of source code must retain the above copyright notice, -- this list of conditions and the following disclaimer. -- - Redistribution in binary form must reproduce the above copyright notice, -- this list of conditions and the following disclaimer in the documentation -- and/or other materials provided with the distribution. -- THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY -- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -- DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR THE CONTRIBUTORS BE LIABLE -- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -- SERVICES; LOSS OF USE, DATA OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -- OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -- USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. {-# LANGUAGE CPP #-} module Encoding ( encode,decode ) where import Data.ByteString ( ByteString ) #ifdef WIN32 import qualified Encoding.Win32 as Backend ( encode, decode ) #else import qualified Encoding.IConv as Backend ( encode, decode ) #endif -- functions redefined to add haddock (there might well be a better way!) -- | Encode a Unicode 'String' into a 'ByteString' suitable for the current -- console. encode :: String -> IO ByteString encode = Backend.encode -- | Convert a 'ByteString' from the console's encoding into a Unicode 'String'. decode :: ByteString -> IO String decode = Backend.decode darcs-2.8.4/src/English.hs0000644001765600176560000000701612104371431014661 0ustar ganeshganesh-- Copyright (C) 2008 Eric Kow -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. -- | -- Module : English -- Copyright : 2008 Eric Kow -- License : GPL -- Maintainer : darcs-devel@darcs.net -- Stability : experimental -- Portability : portable -- -- This modules provides rudimentary natural language generation -- (NLG) utilities. That is, generating natural language from a -- machine representation. Initially, only English is supported at -- all. Representations are implemented for: -- -- * countable nouns (plurality); and -- * lists of clauses (foo, bar and/or baz). module English where import Data.List (isSuffixOf, intercalate) -- | > englishNum 0 (Noun "watch") "" == "watches" -- > englishNum 1 (Noun "watch") "" == "watch" -- > englishNum 2 (Noun "watch") "" == "watches" englishNum :: Countable n => Int -> n -> ShowS englishNum x = if x == 1 then singular else plural -- | Things that have a plural and singular spelling class Countable a where plural :: a -> ShowS singular :: a -> ShowS -- | This only distinguishes between nouns with a final -ch, -- and nouns which do not. -- More irregular nouns will just need to have their own type -- -- > plural (Noun "batch") "" == "batches" -- > plural (Noun "bat") "" == "bats" -- > plural (Noun "mouse") "" == "mouses" -- :-( newtype Noun = Noun String data Pronoun = It instance Countable Noun where -- more irregular nouns will just need to have their own type plural (Noun s) | "ch" `isSuffixOf` s = showString s . showString "es" plural (Noun s) | "y" `isSuffixOf` s && length s > 1 && last (init s) `notElem` "aeiou" = showString (init s) . showString "ies" plural (Noun s) = showString s . showChar 's' singular (Noun s) = showString s instance Countable Pronoun where plural It = showString "them" singular It = showString "it" -- | > singular This (Noun "batch") "" == "this batch" -- > plural This (Noun "batch") "" == "these batches" data This = This Noun instance Countable This where plural (This s) = showString "these " . plural s singular (This s) = showString "this " . singular s -- | Given a list of things, combine them thusly: -- -- > orClauses ["foo", "bar", "baz"] == "foo, bar or baz" andClauses, orClauses :: [String] -> String andClauses = intersperseLast ", " " and " orClauses = intersperseLast ", " " or " -- | As 'intersperse', with a different separator for the last -- | interspersal. intersperseLast :: String -> String -> [String] -> String intersperseLast _ _ [] = "" intersperseLast _ _ [clause] = clause intersperseLast sep sepLast clauses = intercalate sep (init clauses) ++ sepLast ++ last clauses presentParticiple :: String -> String presentParticiple v | last v == 'e' = init v ++ "ing" | otherwise = v ++ "ing" darcs-2.8.4/src/Exec.hs0000644001765600176560000001640212104371431014153 0ustar ganeshganesh-- Copyright (C) 2003 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP, ForeignFunctionInterface, DeriveDataTypeable #-} -- | -- Module : Exec -- Copyright : 2003 David Roundy -- License : GPL -- Maintainer : darcs-devel@darcs.net -- Stability : experimental -- Portability : portable module Exec ( exec , execInteractive , withoutNonBlock , Redirects , Redirect(..) , ExecException(..) ) where #ifndef WIN32 import Control.Exception.Extensible ( bracket ) import System.Posix.Env ( setEnv, getEnv, unsetEnv ) import System.Posix.IO ( queryFdOption, setFdOption, FdOption(..), stdInput ) import System.IO ( stdin ) #else import Control.Exception.Extensible ( catchJust, IOException ) import Data.List ( isInfixOf ) #endif #if __GLASGOW_HASKELL__ >= 612 import GHC.IO.Handle ( hDuplicate ) #else import GHC.Handle ( hDuplicate ) #endif import Control.Exception.Extensible ( bracketOnError, Exception(..), SomeException(..) ) import Data.Typeable ( Typeable, cast ) import System.Cmd ( system ) import System.Exit ( ExitCode (..) ) import System.IO ( IOMode(..), openBinaryFile, stdout ) import System.Process ( runProcess, terminateProcess, waitForProcess ) import Darcs.Global ( whenDebugMode ) import Progress ( withoutProgress ) {- A redirection is a three-tuple of values (in, out, err). The most common values are: AsIs don't change it Null /dev/null on Unix, NUL on Windows File open a file for reading or writing There is also the value Stdout, which is only meaningful for redirection of errors, and is performed AFTER stdout is redirected so that output and errors mix together. StdIn and StdErr could be added as well if they are useful. NOTE: Lots of care must be taken when redirecting stdin, stdout and stderr to one of EACH OTHER, since the ORDER in which they are changed have a significant effect on the result. -} type Redirects = (Redirect, Redirect, Redirect) data Redirect = AsIs | Null | File FilePath | Stdout deriving Show {- ExecException is thrown by exec if any system call fails, for example because the executable we're trying to run doesn't exist. -} -- ExecException cmd args redirecs errorDesc data ExecException = ExecException String -- cmd [String] -- args Redirects -- redirects String -- errorDesc deriving (Typeable,Show) instance Exception ExecException where toException e = SomeException e fromException (SomeException e) = cast e _devNull :: FilePath #ifdef WIN32 _devNull = "NUL" #else _devNull = "/dev/null" #endif {- We use System.Process, which does the necessary quoting and redirection for us behind the scenes. -} exec :: String -> [String] -> Redirects -> IO ExitCode exec cmd args (inp,out,err) = withoutProgress $ do h_stdin <- redirect inp ReadMode h_stdout <- redirect out WriteMode h_stderr <- redirect err WriteMode withExit127 $ bracketOnError (do doOptionalDebug runProcess cmd args Nothing Nothing h_stdin h_stdout h_stderr) (terminateProcess) (waitForProcess) where doOptionalDebug = whenDebugMode . putStrLn . unwords $ cmd : args ++ ["; #"] ++ map show [inp, out, err] redirect AsIs _ = return Nothing redirect Null mode = Just `fmap` openBinaryFile _devNull mode redirect (File "/dev/null") mode = redirect Null mode redirect (File f) mode = Just `fmap` openBinaryFile f mode -- hDuplicate stdout rather than passing stdout itself, -- because runProcess closes the Handles we pass it. redirect Stdout _ = Just `fmap` hDuplicate stdout execInteractive :: String -> String -> IO ExitCode #ifndef WIN32 {- This should handle arbitrary commands interpreted by the shell on Unix since that's what people expect. But we don't want to allow the shell to interpret the argument in any way, so we set an environment variable and call cmd "$DARCS_ARGUMENT" -} execInteractive cmd arg = withoutProgress $ do let var = "DARCS_ARGUMENT" stdin `seq` return () withoutNonBlock $ bracket (do oldval <- getEnv var setEnv var arg True return oldval) (\oldval -> case oldval of Nothing -> unsetEnv var Just val -> setEnv var val True) (\_ -> withExit127 $ system $ cmd++" \"$"++var++"\"") #else -- The `system' function passes commands to execute via cmd.exe (or -- command.com) it's return value is equivalent to the one returned by the -- shell. For regular applications - this works correctly resulting in the -- exit code of the program. However in case of a command/file which can't be -- found - cmd.exe will return 1 instead of propagating the ExitFailure 9009 -- which on windows is equivalent to ExitFailure 127 from *nix machines. -- -- Here we force return the exit code of the last cmd.exe action by appending -- & exit !errorlevel! to the command being executed that way chaining with -- ortryrunning works correctly. -- -- SETLOCAL EnableDelayedExpansion makes sure that !variable! expansion is done -- correctly on systems where that function is not enabled by default. -- execInteractive cmd arg = withoutProgress $ do withExit127 $ system $ "SETLOCAL EnableDelayedExpansion & " ++ cmd ++ " " ++ arg ++ " & exit !errorlevel!" #endif withoutNonBlock :: IO a -> IO a #ifndef WIN32 {- Do IO without NonBlockingRead on stdInput. This is needed when running unsuspecting external commands with interactive mode - if read from terminal is non-blocking also write to terminal is non-blocking. -} withoutNonBlock x = do nb <- queryFdOption stdInput NonBlockingRead if nb then bracket (setFdOption stdInput NonBlockingRead False) (\_ -> setFdOption stdInput NonBlockingRead True) (\_ -> x) else x #else withoutNonBlock x = do x #endif {- Ensure that we exit 127 if the thing we are trying to run does not exist (Only needed under Windows) -} withExit127 :: IO ExitCode -> IO ExitCode #ifdef WIN32 withExit127 a = catchJust notFoundError a (const $ return $ ExitFailure 127) notFoundError :: IOException -> Maybe () notFoundError e | "runProcess: does not exist" `isInfixOf` show e = Just () notFoundError _ = Nothing #else withExit127 = id #endif darcs-2.8.4/src/ByteStringUtils.hs0000644001765600176560000005025012104371431016401 0ustar ganeshganesh{-# OPTIONS_GHC -fno-warn-dodgy-imports #-} -- needed for GHC 7.0/7.2 {-# LANGUAGE BangPatterns, ForeignFunctionInterface, CPP, ScopedTypeVariables #-} ----------------------------------------------------------------------------- -- | -- Module : ByteStringUtils -- Copyright : (c) The University of Glasgow 2001, -- David Roundy 2003-2005 -- License : GPL (I'm happy to also license this file BSD style but don't -- want to bother distributing two license files with darcs. -- -- Maintainer : droundy@abridgegame.org -- Stability : experimental -- Portability : portable -- -- GZIp and MMap IO for ByteStrings, encoding utilities, and miscellaneous -- functions for Data.ByteString -- module ByteStringUtils ( unsafeWithInternals, unpackPSFromUTF8, packStringToUTF8, -- IO with mmap or gzip gzReadFilePS, mmapFilePS, gzWriteFilePS, gzWriteFilePSs, gzReadStdin, -- gzip handling isGZFile, gzDecompress, -- list utilities dropSpace, breakSpace, linesPS, unlinesPS, hashPS, breakFirstPS, breakLastPS, substrPS, readIntPS, isFunky, fromHex2PS, fromPS2Hex, betweenLinesPS, breakAfterNthNewline, breakBeforeNthNewline, intercalate, -- encoding and unicode utilities isAscii, decodeLocale, encodeLocale, decodeString ) where import Prelude hiding ( catch ) import qualified Data.ByteString as B import qualified Data.ByteString.Char8 as BC import qualified Data.ByteString.Internal as BI import Data.ByteString (intercalate) import Data.ByteString.Internal (fromForeignPtr) #if defined (HAVE_MMAP) import Control.Exception.Extensible ( catch, SomeException ) #endif import System.IO import System.IO.Unsafe ( unsafePerformIO ) import Encoding ( decode, encode ) import Foreign.Storable ( peekElemOff, peek ) import Foreign.Marshal.Array ( advancePtr ) import Foreign.C.Types ( CInt(..) ) import Data.Bits ( rotateL ) import Data.Char ( ord, isSpace ) import Data.Word ( Word8 ) import Data.Int ( Int32 ) import qualified Data.Text as T ( pack, unpack ) import Data.Text.Encoding ( encodeUtf8, decodeUtf8With ) import Data.Text.Encoding.Error ( lenientDecode ) import Control.Monad ( when ) import Foreign.Ptr ( plusPtr, Ptr ) import Foreign.ForeignPtr ( withForeignPtr ) #ifdef DEBUG_PS import Foreign.ForeignPtr ( addForeignPtrFinalizer ) import Foreign.Ptr ( FunPtr ) #endif import qualified Data.ByteString.Lazy as BL import qualified Codec.Compression.GZip as GZ import qualified Codec.Compression.Zlib.Internal as ZI import Darcs.Global ( addCRCWarning ) #ifdef HAVE_MMAP import System.IO.MMap( mmapFileByteString ) import System.Mem( performGC ) import System.Posix.Files( fileSize, getSymbolicLinkStatus ) #endif -- ----------------------------------------------------------------------------- -- obsolete debugging code -- ----------------------------------------------------------------------------- -- unsafeWithInternals -- | Do something with the internals of a PackedString. Beware of -- altering the contents! unsafeWithInternals :: B.ByteString -> (Ptr Word8 -> Int -> IO a) -> IO a unsafeWithInternals ps f = case BI.toForeignPtr ps of (fp,s,l) -> withForeignPtr fp $ \p -> f (p `plusPtr` s) l -- | readIntPS skips any whitespace at the beginning of its argument, and -- reads an Int from the beginning of the PackedString. If there is no -- integer at the beginning of the string, it returns Nothing, otherwise it -- just returns the int read, along with a B.ByteString containing the -- remainder of its input. readIntPS :: B.ByteString -> Maybe (Int, B.ByteString) readIntPS = BC.readInt . BC.dropWhile isSpace -- ----------------------------------------------------------------------------- -- Destructor functions (taking PackedStrings apart) -- | Decodes a 'ByteString' containing UTF-8 to a 'String'. Decoding errors are -- flagged with the U+FFFD character. unpackPSFromUTF8 :: B.ByteString -> String unpackPSFromUTF8 = T.unpack . decodeUtf8With lenientDecode packStringToUTF8 :: String -> B.ByteString packStringToUTF8 = encodeUtf8 . T.pack ------------------------------------------------------------------------ -- A reimplementation of Data.ByteString.Char8.dropSpace, but -- specialised to darcs' need for a 4 way isspace. -- -- TODO: if it is safe to use the expanded definition of isSpaceWord8 -- provided by Data.ByteString.Char8, then all this can go. -- A locale-independent isspace(3) so patches are interpreted the same everywhere. -- ((c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\r') isSpaceWord8 :: Word8 -> Bool isSpaceWord8 w = w == 0x20 || -- ' ' w == 0x09 || -- '\t' w == 0x0A || -- '\n' w == 0x0D -- '\r' {-# INLINE isSpaceWord8 #-} firstnonspace :: Ptr Word8 -> Int -> Int -> IO Int firstnonspace !ptr !n !m | n >= m = return n | otherwise = do w <- peekElemOff ptr n if isSpaceWord8 w then firstnonspace ptr (n+1) m else return n firstspace :: Ptr Word8 -> Int -> Int -> IO Int firstspace !ptr !n !m | n >= m = return n | otherwise = do w <- peekElemOff ptr n if (not . isSpaceWord8) w then firstspace ptr (n+1) m else return n -- | 'dropSpace' efficiently returns the 'ByteString' argument with -- white space Chars removed from the front. It is more efficient than -- calling dropWhile for removing whitespace. I.e. -- -- > dropWhile isSpace == dropSpace -- dropSpace :: B.ByteString -> B.ByteString dropSpace (BI.PS x s l) = BI.inlinePerformIO $ withForeignPtr x $ \p -> do i <- firstnonspace (p `plusPtr` s) 0 l return $! if i == l then B.empty else BI.PS x (s+i) (l-i) {-# INLINE dropSpace #-} -- | 'breakSpace' returns the pair of ByteStrings when the argument is -- broken at the first whitespace byte. I.e. -- -- > break isSpace == breakSpace -- breakSpace :: B.ByteString -> (B.ByteString,B.ByteString) breakSpace (BI.PS x s l) = BI.inlinePerformIO $ withForeignPtr x $ \p -> do i <- firstspace (p `plusPtr` s) 0 l return $! case () of {_ | i == 0 -> (B.empty, BI.PS x s l) | i == l -> (BI.PS x s l, B.empty) | otherwise -> (BI.PS x s i, BI.PS x (s+i) (l-i)) } {-# INLINE breakSpace #-} ------------------------------------------------------------------------ {-# INLINE isFunky #-} isFunky :: B.ByteString -> Bool isFunky ps = case BI.toForeignPtr ps of (x,s,l) -> unsafePerformIO $ withForeignPtr x $ \p-> (/=0) `fmap` has_funky_char (p `plusPtr` s) (fromIntegral l) foreign import ccall unsafe "fpstring.h has_funky_char" has_funky_char :: Ptr Word8 -> CInt -> IO CInt ------------------------------------------------------------------------ -- ByteString rewrites break (=='x') to breakByte 'x' -- break ((==) x) = breakChar x -- break (==x) = breakChar x -- {- {-# INLINE breakOnPS #-} breakOnPS :: Char -> B.ByteString -> (B.ByteString, B.ByteString) breakOnPS c p = case BC.elemIndex c p of Nothing -> (p, BC.empty) Just n -> (B.take n p, B.drop n p) -} {-# INLINE hashPS #-} hashPS :: B.ByteString -> Int32 hashPS ps = case BI.toForeignPtr ps of (x,s,l) -> unsafePerformIO $ withForeignPtr x $ \p-> hash (p `plusPtr` s) l hash :: Ptr Word8 -> Int -> IO Int32 hash ptr len = f (0 :: Int32) ptr len where f h _ 0 = return h f h p n = do x <- peek p let !h' = (fromIntegral x) + (rotateL h 8) f h' (p `advancePtr` 1) (n-1) {-# INLINE substrPS #-} substrPS :: B.ByteString -> B.ByteString -> Maybe Int substrPS tok str | B.null tok = Just 0 | B.length tok > B.length str = Nothing | otherwise = do n <- BC.elemIndex (BC.head tok) str let ttok = B.tail tok reststr = B.drop (n+1) str if ttok == B.take (B.length ttok) reststr then Just n else ((n+1)+) `fmap` substrPS tok reststr ------------------------------------------------------------------------ -- TODO: replace breakFirstPS and breakLastPS with definitions based on -- ByteString's break/breakEnd {-# INLINE breakFirstPS #-} breakFirstPS :: Char -> B.ByteString -> Maybe (B.ByteString,B.ByteString) breakFirstPS c p = case BC.elemIndex c p of Nothing -> Nothing Just n -> Just (B.take n p, B.drop (n+1) p) {-# INLINE breakLastPS #-} breakLastPS :: Char -> B.ByteString -> Maybe (B.ByteString,B.ByteString) breakLastPS c p = case BC.elemIndexEnd c p of Nothing -> Nothing Just n -> Just (B.take n p, B.drop (n+1) p) -- TODO: rename {-# INLINE linesPS #-} linesPS :: B.ByteString -> [B.ByteString] linesPS ps | B.null ps = [B.empty] | otherwise = BC.split '\n' ps {- QuickCheck property: import Test.QuickCheck import qualified Data.ByteString.Char8 as BC import Data.Char instance Arbitrary BC.ByteString where arbitrary = fmap BC.pack arbitrary instance Arbitrary Char where arbitrary = chr `fmap` choose (32,127) deepCheck = check (defaultConfig { configMaxTest = 10000}) testLines = deepCheck (\x -> (linesPS x == linesPSOld x)) linesPSOld ps = case BC.elemIndex '\n' ps of Nothing -> [ps] Just n -> B.take n ps : linesPS (B.drop (n+1) ps) -} {-| This function acts exactly like the "Prelude" unlines function, or like "Data.ByteString.Char8" 'unlines', but with one important difference: it will produce a string which may not end with a newline! That is: > unlinesPS ["foo", "bar"] evaluates to \"foo\\nbar\", not \"foo\\nbar\\n\"! This point should hold true for 'linesPS' as well. TODO: rename this function. -} unlinesPS :: [B.ByteString] -> B.ByteString unlinesPS [] = BC.empty unlinesPS x = BC.init $ BC.unlines x {-# INLINE unlinesPS #-} {- QuickCheck property: testUnlines = deepCheck (\x -> (unlinesPS x == unlinesPSOld x)) unlinesPSOld ss = BC.concat $ intersperse_newlines ss where intersperse_newlines (a:b:s) = a : newline : intersperse_newlines (b:s) intersperse_newlines s = s newline = BC.pack "\n" -} -- ----------------------------------------------------------------------------- -- gzReadFilePS -- |Decompress the given bytestring into a lazy list of chunks, along with a boolean -- flag indicating (if True) that the CRC was corrupted. -- Inspecting the flag will cause the entire list of chunks to be evaluated (but if -- you throw away the list immediately this should run in constant space). gzDecompress :: Maybe Int -> BL.ByteString -> ([B.ByteString], Bool) gzDecompress mbufsize = -- This is what the code would be without the bad CRC recovery logic: -- return . BL.toChunks . GZ.decompressWith decompressParams toListWarn . ZI.decompressWithErrors ZI.gzipFormat decompressParams where decompressParams = case mbufsize of Just bufsize -> GZ.defaultDecompressParams { GZ.decompressBufferSize = bufsize } Nothing -> GZ.defaultDecompressParams toListWarn :: ZI.DecompressStream -> ([B.ByteString], Bool) toListWarn = foldDecompressStream (\x ~(xs, b) -> (x:xs, b)) ([], False) handleBad -- cut and paste from Zlib since it's not currently exported (interface not yet certain) foldDecompressStream :: (B.ByteString -> a -> a) -> a -> (ZI.DecompressError -> String -> a) -> ZI.DecompressStream -> a foldDecompressStream chunk end err = fold where fold ZI.StreamEnd = end fold (ZI.StreamChunk bs stream) = chunk bs (fold stream) fold (ZI.StreamError code msg) = err code msg -- For a while a bug in darcs caused gzip files with good data but bad CRCs to be -- produced. Trap bad CRC messages, run the specified action to report that it happened, -- but continue on the assumption that the data is valid. handleBad ZI.DataError "incorrect data check" = ([], True) handleBad _ msg = error msg isGZFile :: FilePath -> IO (Maybe Int) isGZFile f = do h <- openBinaryFile f ReadMode header <- B.hGet h 2 if header /= BC.pack "\31\139" then do hClose h return Nothing else do hSeek h SeekFromEnd (-4) len <- hGetLittleEndInt h hClose h return (Just len) -- | Read an entire file, which may or may not be gzip compressed, directly -- into a 'B.ByteString'. gzReadFilePS :: FilePath -> IO B.ByteString gzReadFilePS f = do mlen <- isGZFile f case mlen of Nothing -> mmapFilePS f Just len -> do -- Passing the length to gzDecompress means that it produces produces one chunk, -- which in turn means that B.concat won't need to copy data. -- If the length is wrong this will just affect efficiency, not correctness let doDecompress buf = let (res, bad) = gzDecompress (Just len) buf in do when bad $ addCRCWarning f return res compressed <- (BL.fromChunks . return) `fmap` mmapFilePS f B.concat `fmap` doDecompress compressed hGetLittleEndInt :: Handle -> IO Int hGetLittleEndInt h = do b1 <- ord `fmap` hGetChar h b2 <- ord `fmap` hGetChar h b3 <- ord `fmap` hGetChar h b4 <- ord `fmap` hGetChar h return $ b1 + 256*b2 + 65536*b3 + 16777216*b4 gzWriteFilePS :: FilePath -> B.ByteString -> IO () gzWriteFilePS f ps = gzWriteFilePSs f [ps] gzWriteFilePSs :: FilePath -> [B.ByteString] -> IO () gzWriteFilePSs f pss = BL.writeFile f $ GZ.compress $ BL.fromChunks pss -- | Read standard input, which may or may not be gzip compressed, directly -- into a 'B.ByteString'. gzReadStdin :: IO B.ByteString gzReadStdin = do header <- B.hGet stdin 2 rest <- B.hGetContents stdin let allStdin = B.concat [header,rest] return $ if header /= BC.pack "\31\139" then allStdin else let decompress = fst . gzDecompress Nothing compressed = BL.fromChunks [allStdin] in B.concat $ decompress compressed -- ----------------------------------------------------------------------------- -- mmapFilePS -- | Like readFilePS, this reads an entire file directly into a -- 'B.ByteString', but it is even more efficient. It involves directly -- mapping the file to memory. This has the advantage that the contents of -- the file never need to be copied. Also, under memory pressure the page -- may simply be discarded, wile in the case of readFilePS it would need to -- be written to swap. If you read many small files, mmapFilePS will be -- less memory-efficient than readFilePS, since each mmapFilePS takes up a -- separate page of memory. Also, you can run into bus errors if the file -- is modified. NOTE: as with 'readFilePS', the string representation in -- the file is assumed to be ISO-8859-1. mmapFilePS :: FilePath -> IO B.ByteString #ifdef HAVE_MMAP mmapFilePS f = do x <- mmapFileByteString f Nothing `catch` (\(_ :: SomeException) -> do size <- fileSize `fmap` getSymbolicLinkStatus f if size == 0 then return B.empty else performGC >> mmapFileByteString f Nothing) return x #else mmapFilePS = B.readFile #endif -- ------------------------------------------------------------------------- -- fromPS2Hex foreign import ccall unsafe "static fpstring.h conv_to_hex" conv_to_hex :: Ptr Word8 -> Ptr Word8 -> CInt -> IO () fromPS2Hex :: B.ByteString -> B.ByteString fromPS2Hex ps = case BI.toForeignPtr ps of (x,s,l) -> BI.unsafeCreate (2*l) $ \p -> withForeignPtr x $ \f -> conv_to_hex p (f `plusPtr` s) $ fromIntegral l -- ------------------------------------------------------------------------- -- fromHex2PS foreign import ccall unsafe "static fpstring.h conv_from_hex" conv_from_hex :: Ptr Word8 -> Ptr Word8 -> CInt -> IO () fromHex2PS :: B.ByteString -> B.ByteString fromHex2PS ps = case BI.toForeignPtr ps of (x,s,l) -> BI.unsafeCreate (l `div` 2) $ \p -> withForeignPtr x $ \f -> conv_from_hex p (f `plusPtr` s) (fromIntegral $ l `div` 2) -- ------------------------------------------------------------------------- -- betweenLinesPS -- | betweenLinesPS returns the B.ByteString between the two lines given, -- or Nothing if they do not appear. betweenLinesPS :: B.ByteString -> B.ByteString -> B.ByteString -> Maybe (B.ByteString) betweenLinesPS start end ps = case break (start ==) (linesPS ps) of (_, _:rest@(bs1:_)) -> case BI.toForeignPtr bs1 of (ps1,s1,_) -> case break (end ==) rest of (_, bs2:_) -> case BI.toForeignPtr bs2 of (_,s2,_) -> Just $ fromForeignPtr ps1 s1 (s2 - s1) _ -> Nothing _ -> Nothing -- ------------------------------------------------------------------------- -- breakAfterNthNewline breakAfterNthNewline :: Int -> B.ByteString -> Maybe (B.ByteString, B.ByteString) breakAfterNthNewline 0 the_ps | B.null the_ps = Just (B.empty, B.empty) breakAfterNthNewline n the_ps = case BI.toForeignPtr the_ps of (fp,the_s,l) -> unsafePerformIO $ withForeignPtr fp $ \p -> do let findit 0 s | s == end = return $ Just (the_ps, B.empty) findit _ s | s == end = return Nothing findit 0 s = let left_l = s - the_s in return $ Just (fromForeignPtr fp the_s left_l, fromForeignPtr fp s (l - left_l)) findit i s = do w <- peekElemOff p s if w == nl then findit (i-1) (s+1) else findit i (s+1) nl = BI.c2w '\n' end = the_s + l findit n the_s -- ------------------------------------------------------------------------- -- breakBeforeNthNewline breakBeforeNthNewline :: Int -> B.ByteString -> (B.ByteString, B.ByteString) breakBeforeNthNewline 0 the_ps | B.null the_ps = (B.empty, B.empty) breakBeforeNthNewline n the_ps = case BI.toForeignPtr the_ps of (fp,the_s,l) -> unsafePerformIO $ withForeignPtr fp $ \p -> do let findit _ s | s == end = return (the_ps, B.empty) findit i s = do w <- peekElemOff p s if w == nl then if i == 0 then let left_l = s - the_s in return (fromForeignPtr fp the_s left_l, fromForeignPtr fp s (l - left_l)) else findit (i-1) (s+1) else findit i (s+1) nl = BI.c2w '\n' end = the_s + l findit n the_s -- | Test if a ByteString is made of ascii characters isAscii :: B.ByteString -> Bool isAscii = B.all (\w -> w < 128) -- | Decode a ByteString to a String according to the current locale -- unsafePerformIO in the locale function is ratified by the fact that GHC 6.12 -- and above also supply locale conversion with functions with a pure type. -- Unrecognized byte sequences in the input are skipped. decodeLocale :: B.ByteString -> String decodeLocale = unsafePerformIO . decode -- | Encode a String to a ByteString with latin1 (i.e., the values of the -- characters become the values of the bytes; if a character value is greater -- than 255, its byte becomes the character value modulo 256) encodeLatin1 :: String -> B.ByteString encodeLatin1 = B.pack . (map (fromIntegral . ord)) -- | Encode a String to a ByteString according to the current locale encodeLocale :: String -> B.ByteString encodeLocale = unsafePerformIO . encode -- | Take a @String@ that represents byte values and re-decode it acording to -- the current locale. decodeString :: String -> String decodeString = decodeLocale . encodeLatin1 darcs-2.8.4/src/IsoDate.hs0000644001765600176560000010001712104371431014613 0ustar ganeshganesh-- Copyright (C) 2003 Peter Simons -- Copyright (C) 2003 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. -- | -- Module : IsoDate -- Copyright : 2003 Peter Simons -- 2003 David Roundy -- License : GPL -- Maintainer : darcs-devel@darcs.net -- Stability : experimental -- Portability : portable module IsoDate ( getIsoDateTime, readLocalDate, readUTCDate, parseDate, getLocalTz, englishDateTime, englishInterval, englishLast, iso8601Interval, iso8601Duration, cleanLocalDate, resetCalendar, MCalendarTime(..), subtractFromMCal, addToMCal, toMCalendarTime, unsafeToCalendarTime, unsetTime, TimeInterval ) where import Text.ParserCombinators.Parsec import System.Time import System.IO.Unsafe ( unsafePerformIO ) import Data.Char ( toUpper, isDigit ) import Data.Maybe ( fromMaybe ) import Control.Monad ( liftM, liftM2 ) import qualified Data.ByteString.Char8 as B type TimeInterval = (Maybe CalendarTime, Maybe CalendarTime) -- | Read/interpret a date string, assuming UTC if timezone -- is not specified in the string (see 'readDate') -- Warning! This errors out if we fail to interpret the -- date readUTCDate :: String -> CalendarTime readUTCDate = readDate 0 -- | Convert a date string into ISO 8601 format (yyyymmdd variant) -- assuming local timezone if not specified in the string -- Warning! This errors out if we fail to interpret the date cleanLocalDate :: String -> String cleanLocalDate = showIsoDateTime . resetCalendar . readDate (unsafePerformIO getLocalTz) -- | Read/interpret a date string, assuming local timezone if not -- specified in the string readLocalDate :: String -> CalendarTime readLocalDate = readDate (unsafePerformIO getLocalTz) -- | Return the local timezone offset from UTC in seconds getLocalTz :: IO Int getLocalTz = ctTZ `liftM` (getClockTime >>= toCalendarTime) -- | Parse a date string with 'parseDate' -- Warning! This errors out if we fail to interpret the date -- Uses its first argument as the default time zone. readDate :: Int -> String -> CalendarTime readDate tz d = case parseDate tz d of Left e -> error $ "bad date: "++d++" - "++show e Right ct -> resetCalendar $ unsafeToCalendarTime ct -- | Parse a date string, assuming a default timezone if -- the date string does not specify one. The date formats -- understood are those of 'showIsoDateTime' and 'dateTime' parseDate :: Int -> String -> Either ParseError MCalendarTime parseDate tz d = if length d >= 14 && B.all isDigit bd then Right $ toMCalendarTime $ CalendarTime (readI $ B.take 4 bd) (toEnum $ (+ (-1)) $ readI $ B.take 2 $ B.drop 4 bd) (readI $ B.take 2 $ B.drop 6 bd) -- Day (readI $ B.take 2 $ B.drop 8 bd) -- Hour (readI $ B.take 2 $ B.drop 10 bd) -- Minute (readI $ B.take 2 $ B.drop 12 bd) -- Second 0 Sunday 0 -- Picosecond, weekday and day of year unknown "GMT" 0 False else let dt = do { x <- dateTime tz; eof; return x } in parse dt "" d where bd = B.pack (take 14 d) readI s = fst $ fromMaybe (error "parseDate: invalid date") (B.readInt s) -- | Display a 'CalendarTime' in the ISO 8601 format without any -- separators, e.g. 20080825142503 showIsoDateTime :: CalendarTime -> String showIsoDateTime ct = concat [ show $ ctYear ct , twoDigit . show . (+1) . fromEnum $ ctMonth ct , twoDigit . show $ ctDay ct , twoDigit . show $ ctHour ct , twoDigit . show $ ctMin ct , twoDigit . show $ ctSec ct ] where twoDigit [] = undefined twoDigit x@(_:[]) = '0' : x twoDigit x@(_:_:[]) = x twoDigit _ = undefined -- | The current time in the format returned by 'showIsoDateTime' getIsoDateTime :: IO String getIsoDateTime = (showIsoDateTime . toUTCTime) `liftM` getClockTime ----- Parser Combinators --------------------------------------------- -- | Case-insensitive variant of Parsec's 'char' function. caseChar :: Char -> GenParser Char a Char caseChar c = satisfy (\x -> toUpper x == toUpper c) -- | Case-insensitive variant of Parsec's 'string' function. caseString :: String -> GenParser Char a () caseString cs = mapM_ caseChar cs cs -- [x,y] => x <|> y caseStrings :: [String] -> GenParser Char a () caseStrings xs = foldl1 (<|>) $ map caseString xs -- | Match a parser at least @n@ times. manyN :: Int -> GenParser a b c -> GenParser a b [c] manyN n p | n <= 0 = return [] | otherwise = liftM2 (++) (count n p) (many p) -- | Match a parser at least @n@ times, but no more than @m@ times. manyNtoM :: Int -> Int -> GenParser a b c -> GenParser a b [c] manyNtoM n m p | n < 0 = return [] | n > m = return [] | n == m = count n p | n == 0 = foldr (<|>) (return []) (map (\x -> try $ count x p) (reverse [1..m])) | otherwise = liftM2 (++) (count n p) (manyNtoM 0 (m-n) p) ----- Date/Time Parser ----------------------------------------------- -- | Try each of these date parsers in the following order -- -- (1) 'cvsDateTime' -- -- (2) 'iso8601DateTime' -- -- (3) 'oldDateTime dateTime :: Int -> CharParser a MCalendarTime dateTime tz = choice [try $ toMCalendarTime `fmap` cvsDateTime tz, try $ iso8601DateTime tz, toMCalendarTime `fmap` oldDateTime] -- | CVS-style date/times, e.g. -- 2007/08/25 14:25:39 GMT -- Note that time-zones are optional here. cvsDateTime :: Int -> CharParser a CalendarTime cvsDateTime tz = do y <- year _ <- char '/' mon <- monthNum _ <- char '/' d <- day _ <- mySpaces h <- hour _ <- char ':' m <- minute _ <- char ':' s <- second z <- option tz $ mySpaces >> zone return (CalendarTime y mon d h m s 0 Monday 0 "" z False) -- | \"Old\"-style dates, e.g. -- Tue Jan 3 14:08:07 EST 1999 -- darcs-doc: Question (what does the "old" stand for really?) oldDateTime :: CharParser a CalendarTime oldDateTime = do wd <- dayName _ <- mySpaces mon <- monthName _ <- mySpaces d <- day _ <- mySpaces h <- hour _ <- char ':' m <- minute _ <- char ':' s <- second _ <- mySpaces z <- zone _ <- mySpaces y <- year return (CalendarTime y mon d h m s 0 wd 0 "" z False) -- | ISO 8601 dates and times. Please note the following flaws: -- -- I am reluctant to implement: -- -- * years > 9999 -- -- * truncated representations with implied century (89 for 1989) -- -- I have not implemented: -- -- * repeated durations (not relevant) -- -- * lowest order component fractions in intervals -- -- * negative dates (BC) -- -- I have not verified or have left too relaxed: -- -- * the difference between 24h and 0h -- -- * allows stuff like 2005-1212; either you use the hyphen all the way -- (2005-12-12) or you don't use it at all (20051212), but you don't use -- it halfway, likewise with time -- -- * No bounds checking whatsoever on intervals! -- (next action: read iso doc to see if bounds-checking required?) -} iso8601DateTime :: Int -> CharParser a MCalendarTime iso8601DateTime localTz = try $ do d <- iso8601Date t <- option id $ try $ do optional $ oneOf " T" iso8601Time return $ t $ d { mctTZ = Just localTz } -- | Three types of ISO 8601 date: -- -- * calendar date, e.g., 1997-07-17, 1997-07, 199707, 1997 -- -- * week+day in year, e.g., 1997-W32-4 -- -- * day in year, e.g, 1997-273 iso8601Date :: CharParser a MCalendarTime iso8601Date = do d <- calendar_date <|> week_date <|> ordinal_date return $ foldr ($) nullMCalendar d where calendar_date = -- yyyy-mm-dd try $ do d <- optchain year_ [ (dash, month_), (dash, day_) ] -- allow other variants to be parsed correctly notFollowedBy (digit <|> char 'W') return d week_date = --yyyy-Www-d try $ do yfn <- year_ optional dash _ <- char 'W' -- offset human 'week 1' -> computer 'week 0' w' <- (\x -> x-1) `liftM` twoDigits mwd <- option Nothing $ do { optional dash; Just `fmap` nDigits 1 } let y = resetCalendar . unsafeToCalendarTime . yfn $ nullMCalendar { mctDay = Just 1 } firstDay = ctWDay y -- things that make this complicated -- 1. iso8601 weeks start from Monday; Haskell weeks start from Sunday -- 2. the first week is the one that contains at least Thursday -- if the year starts after Thursday, then some days of the year -- will have already passed before the first week let afterThursday = firstDay == Sunday || firstDay > Thursday w = if afterThursday then w'+1 else w' yday = (7 * w) + fromMaybe 1 mwd diff c = c { mctWeek = True , mctWDay = toEnum `fmap` mwd , mctDay = Just yday } return [(diff.yfn)] ordinal_date = -- yyyy-ddd try $ optchain year_ [ (dash, yearDay_) ] -- year_ = try $ do y <- fourDigits "year (0000-9999)" return $ \c -> c { mctYear = Just y } month_ = try $ do m <- twoDigits "month (1 to 12)" return $ \c -> c { mctMonth = Just $ intToMonth m } day_ = try $ do d <- twoDigits "day in month (1 to 31)" return $ \c -> c { mctDay = Just d } yearDay_ = try $ do d <- nDigits 3 "day in year (001 to 366)" return $ \c -> c { mctDay = Just d , mctYDay = Just (d - 1) } dash = char '-' -- | Note that this returns a function which sets the time on -- another calendar (see 'iso8601DateTime' for a list of -- flaws iso8601Time :: CharParser a (MCalendarTime -> MCalendarTime) iso8601Time = try $ do ts <- optchain hour_ [ (colon , min_) , (colon , sec_) , (oneOf ",.", pico_) ] z <- option id $ choice [ zulu , offset ] return $ foldr (.) id (z:ts) where hour_ = do h <- twoDigits return $ \c -> c { mctHour = Just h } min_ = do m <- twoDigits return $ \c -> c { mctMin = Just m } sec_ = do s <- twoDigits return $ \c -> c { mctSec = Just s } pico_ = do digs <- many digit let picoExp = 12 digsExp = length digs let frac | null digs = 0 | digsExp > picoExp = read $ take picoExp digs | otherwise = 10 ^ (picoExp - digsExp) * (read digs) return $ \c -> c { mctPicosec = Just $ frac } zulu = do { _ <- char 'Z'; return (\c -> c { mctTZ = Just 0 }) } offset = do sign <- choice [ char '+' >> return 1 , char '-' >> return (-1) ] h <- twoDigits m <- option 0 $ do { optional colon; twoDigits } return $ \c -> c { mctTZ = Just $ sign * 60 * ((h*60)+m) } colon = char ':' -- | Intervals in ISO 8601, e.g., -- -- * 2008-09/2012-08-17T16:30 -- -- * 2008-09/P2Y11MT16H30M -- -- * P2Y11MT16H30M/2012-08-17T16:30 -- -- See 'iso8601Duration' iso8601Interval :: Int -> CharParser a (Either TimeDiff (MCalendarTime, MCalendarTime)) iso8601Interval localTz = leftDur <|> rightDur where leftDur = do dur <- iso8601Duration end <- option Nothing $ do { _ <- char '/'; Just `liftM` isoDt } return $ case end of Nothing -> Left dur Just e -> Right (dur `subtractFromMCal` e, e) rightDur = do start <- isoDt _ <- char '/' durOrEnd <- Left `liftM` iso8601Duration <|> Right `liftM` isoDt return $ case durOrEnd of Left dur -> Right (start, dur `addToMCal` start) Right end -> Right (start, end) isoDt = iso8601DateTime localTz -- | Durations in ISO 8601, e.g., -- -- * P4Y (four years) -- -- * P5M (five months) -- -- * P4Y5M (four years and five months) -- -- * P4YT3H6S (four years, three hours and six seconds) iso8601Duration :: CharParser a TimeDiff iso8601Duration = do _ <- char 'P' y <- block 0 'Y' mon <- block 0 'M' d <- block 0 'D' (h,m,s) <- option (0,0,0) $ do _ <- char 'T' h' <- block (-1) 'H' m' <- block (-1) 'M' s' <- block (-1) 'S' let unset = (== (-1)) if all unset [h',m',s'] then fail "T should be omitted if time is unspecified" else let clear x = if (unset x) then 0 else x in return (clear h', clear m', clear s') -- return $ TimeDiff y mon d h m s 0 where block d c = option d $ try $ do n <- many1 digit _ <- char c return $ read n -- | 'optchain' @p xs@ parses a string with the obligatory -- parser @p@. If this suceeds, it continues on to the -- rest of the input using the next parsers down the -- chain. Each part of the chain consists of a parser -- for a separator and for the content itself. The -- separator is optional. -- -- A good use of this function is to help in parsing ISO -- ISO 8601 dates and times. For example, the parser -- @optchain year [(dash, month), (dash, day)]@ accepts -- dates like 2007 (only the year is used), 2007-07 (only -- the year and month), 200707 (only the year and month -- with no separator), 2007-07-19 (year, month and day). optchain :: CharParser a b -> [(CharParser a c, CharParser a b)] -> CharParser a [b] optchain p next = try $ do r1 <- p r2 <- case next of [] -> return [] ((sep,p2):next2) -> option [] $ do { optional sep; optchain p2 next2 } return (r1:r2) nDigits :: Int -> CharParser a Int nDigits n = read `liftM` count n digit twoDigits, fourDigits :: CharParser a Int twoDigits = nDigits 2 fourDigits = nDigits 4 -- | One or more space. -- WARNING! This only matches on the space character, not on -- whitespace in general mySpaces :: CharParser a String mySpaces = manyN 1 $ char ' ' -- | English three-letter day abbreviations (e.g. Mon, Tue, Wed) dayName :: CharParser a Day dayName = choice [ caseString "Mon" >> return Monday , try (caseString "Tue") >> return Tuesday , caseString "Wed" >> return Wednesday , caseString "Thu" >> return Thursday , caseString "Fri" >> return Friday , try (caseString "Sat") >> return Saturday , caseString "Sun" >> return Sunday ] -- | Four-digit year year :: CharParser a Int year = fourDigits -- | One or two digit month (e.g. 3 for March, 11 for November) monthNum :: CharParser a Month monthNum = do mn <- manyNtoM 1 2 digit return $ intToMonth $ (read mn :: Int) -- | January is 1, February is 2, etc intToMonth :: Int -> Month intToMonth 1 = January intToMonth 2 = February intToMonth 3 = March intToMonth 4 = April intToMonth 5 = May intToMonth 6 = June intToMonth 7 = July intToMonth 8 = August intToMonth 9 = September intToMonth 10 = October intToMonth 11 = November intToMonth 12 = December intToMonth _ = error "invalid month!" -- | English three-letter month abbreviations (e.g. Jan, Feb, Mar) monthName :: CharParser a Month monthName = choice [ try (caseString "Jan") >> return January , caseString "Feb" >> return February , try (caseString "Mar") >> return March , try (caseString "Apr") >> return April , caseString "May" >> return May , try (caseString "Jun") >> return June , caseString "Jul" >> return July , caseString "Aug" >> return August , caseString "Sep" >> return September , caseString "Oct" >> return October , caseString "Nov" >> return November , caseString "Dec" >> return December ] -- | day in one or two digit notation day :: CharParser a Int day = do d <- manyNtoM 1 2 digit return (read d :: Int) -- | hour in two-digit notation hour :: CharParser a Int hour = twoDigits -- | minute in two-digit notation minute :: CharParser a Int minute = twoDigits -- | second in two-digit notation second :: CharParser a Int second = twoDigits -- | limited timezone support -- -- * +HHMM or -HHMM -- -- * Universal timezones: UTC, UT -- -- * Zones from GNU coreutils/lib/getdate.y, less half-hour ones -- -- sorry Newfies. -- -- * any sequence of alphabetic characters (WARNING! treated as 0!) zone :: CharParser a Int zone = choice [ do { _ <- char '+'; h <- hour; m <- minute; return (((h*60)+m)*60) } , do { _ <- char '-'; h <- hour; m <- minute; return (-((h*60)+m)*60) } , mkZone "UTC" 0 , mkZone "UT" 0 , mkZone "GMT" 0 , mkZone "WET" 0 , mkZone "WEST" 1 , mkZone "BST" 1 , mkZone "ART" (-3) , mkZone "BRT" (-3) , mkZone "BRST" (-2) , mkZone "AST" (-4) , mkZone "ADT" (-3) , mkZone "CLT" (-4) , mkZone "CLST" (-3) , mkZone "EST" (-5) , mkZone "EDT" (-4) , mkZone "CST" (-6) , mkZone "CDT" (-5) , mkZone "MST" (-7) , mkZone "MDT" (-6) , mkZone "PST" (-8) , mkZone "PDT" (-7) , mkZone "AKST" (-9) , mkZone "AKDT" (-8) , mkZone "HST" (-10) , mkZone "HAST" (-10) , mkZone "HADT" (-9) , mkZone "SST" (-12) , mkZone "WAT" 1 , mkZone "CET" 1 , mkZone "CEST" 2 , mkZone "MET" 1 , mkZone "MEZ" 1 , mkZone "MEST" 2 , mkZone "MESZ" 2 , mkZone "EET" 2 , mkZone "EEST" 3 , mkZone "CAT" 2 , mkZone "SAST" 2 , mkZone "EAT" 3 , mkZone "MSK" 3 , mkZone "MSD" 4 , mkZone "SGT" 8 , mkZone "KST" 9 , mkZone "JST" 9 , mkZone "GST" 10 , mkZone "NZST" 12 , mkZone "NZDT" 13 -- if we don't understand it, just give a GMT answer... , do { _ <- manyTill (oneOf $ ['a'..'z']++['A'..'Z']++[' ']) (lookAhead space_digit); return 0 } ] where mkZone n o = try $ do { caseString n; return (o*60*60) } space_digit = try $ do { _ <- char ' '; oneOf ['0'..'9'] } ----- English dates and intervals ----------------------------------------------- -- | In English, either a date followed by a time, or vice-versa, e.g, -- -- * yesterday at noon -- -- * yesterday tea time -- -- * 12:00 yesterday -- -- See 'englishDate' and 'englishTime' -- Uses its first argument as "now", i.e. the time relative to which -- "yesterday", "today" etc are to be interpreted englishDateTime :: CalendarTime -> CharParser a CalendarTime englishDateTime now = try $ dateMaybeAtTime <|> timeThenDate where -- yesterday (at) noon dateMaybeAtTime = try $ do ed <- englishDate now t <- option Nothing $ try $ do { _ <- space; optional $ caseString "at "; Just `liftM` englishTime } return $ fromMaybe id t $ ed -- tea time 2005-12-04 timeThenDate = try $ do t <- englishTime optional $ char ',' _ <- space ed <- englishDate now return $ t $ unsetTime $ ed -- | Specific dates in English as specific points of time, e.g, -- -- * today -- -- * yesterday -- -- * last week (i.e. the beginning of that interval) -- -- * 4 months ago (via 'englishAgo') -- -- The first argument is "now". englishDate :: CalendarTime -> CharParser a CalendarTime englishDate now = try $ (caseString "today" >> (return $ resetCalendar now)) <|> (caseString "yesterday" >> (return $ oneDay `subtractFromCal` now) ) <|> fst `fmap` englishLast now <|> englishAgo now where oneDay = TimeDiff 0 0 1 0 0 0 0 -- | English expressions for points in the past, e.g. -- -- * 4 months ago -- -- * 1 day ago -- -- * day before yesterday -- -- See 'englishDuration' englishAgo :: CalendarTime -> CharParser a CalendarTime englishAgo now = try $ do p <- englishDuration _ <- try space (m,ref) <- (try $ caseString "ago" >> return ((-1), now)) <|> do m <- beforeMod <|> afterMod _ <- space d <- englishDate now <|> fst `fmap` englishLast now <|> unsafeToCalendarTime `fmap` iso8601DateTime (ctTZ now) return (m,d) return $ multiplyDiff m p `addToCal` ref where beforeMod = try $ caseString "before" >> return (-1) afterMod = try $ (caseStrings ["after","since"]) >> return 1 -- | English expressions for intervals of time, -- -- * before tea time (i.e. from the beginning of time) -- -- * after 14:00 last month (i.e. till now) -- -- * between last year and last month -- -- * in the last three months (i.e. from then till now) -- -- * 4 months ago (i.e. till now; see 'englishAgo') englishInterval :: CalendarTime -> CharParser a TimeInterval englishInterval now = twixt <|> before <|> after <|> inTheLast <|> lastetc where englishDT = (unsafeToCalendarTime `fmap` iso8601DateTime (ctTZ now) <|> englishDateTime now) before = try $ do caseString "before" _ <- space end <- englishDT return (Just theBeginning, Just end) after = try $ do caseStrings ["after","since"] _ <- space start <- englishDT return (Just start, Nothing) twixt = try $ do caseString "between" _ <- space start <- englishDT _ <- space caseString "and" _ <- space end <- englishDT return (Just start, Just end) inTheLast = try $ do caseString "in the last" _ <- space dur <- englishDuration return (Just $ dur `subtractFromCal` now, Just now) lastetc = do l <- englishAgo now return (Just l, Just now) -- | Durations in English that begin with the word \"last\", -- E.g. \"last 4 months\" is treated as the duration between -- 4 months ago and now englishLast :: CalendarTime -> CharParser a (CalendarTime, CalendarTime) englishLast now = -- last year, last week, last 3 years, etc try $ do caseString "last" _ <- space d <- englishDuration return (d `subtractFromCal` now, now) -- | Either an 'iso8601Time' or one of several common -- English time expressions like 'noon' or 'tea time' englishTime :: CharParser a (CalendarTime->CalendarTime) englishTime = try $ choice [ wrapM `fmap` iso8601Time , namedTime "noon" 12 0 , namedTime "midnight" 0 0 , namedTime "tea time" 16 30 , namedTime "bed time" 2 30 , namedTime "proper bed time" 21 30 ] where namedTime name h m = try $ do caseString name return $ \c -> c { ctHour = h, ctMin = m } wrapM f = unsafeToCalendarTime . f . toMCalendarTime -- | Some English durations, e.g. -- -- * day -- -- * 4 score -- -- * 7 years -- -- * 12 months -- -- This is not particularly strict about what it accepts. -- For example, "7 yeares", "4 scores" or "1 days" are -- just fine. englishDuration :: CharParser a TimeDiff englishDuration = try $ do n <- option 1 $ do { x <- many1 digit; _ <- space; (return $ read x) } b <- base optional (caseStrings ["es","s"]) let current = multiplyDiff n b next <- option noTimeDiff $ try $ do { optional space; _ <- char ',' ; optional space ; englishDuration } return $ addDiff current next where base = choice [ try $ caseString "score" >> (return $ TimeDiff 20 0 0 0 0 0 0) -- why not? , caseString "year" >> (return $ TimeDiff 1 0 0 0 0 0 0) , try $ caseString "month" >> (return $ TimeDiff 0 1 0 0 0 0 0) , caseString "fortnight" >> (return $ TimeDiff 0 0 14 0 0 0 0) , caseString "week" >> (return $ TimeDiff 0 0 7 0 0 0 0) , caseString "day" >> (return $ TimeDiff 0 0 1 0 0 0 0) , caseString "hour" >> (return $ TimeDiff 0 0 0 1 0 0 0) , caseString "minute" >> (return $ TimeDiff 0 0 0 0 1 0 0) , caseString "second" >> (return $ TimeDiff 0 0 0 0 0 1 0) ] ----- Calendar and TimeDiff manipulation --------------------------------------------- -- | The very beginning of time, i.e. 1970-01-01 theBeginning :: CalendarTime theBeginning = unsafePerformIO $ toCalendarTime $ TOD 0 0 -- | An 'MCalenderTime' is an underspecified 'CalendarTime' -- It is used for parsing dates. For example, if you want to parse -- the date '4 January', it may be useful to underspecify the year -- by setting it to 'Nothing'. This uses almost the same fields as -- 'System.Time.CalendarTime', a notable exception being that we -- introduce 'mctWeek' to indicate if a weekday was specified or not data MCalendarTime = MCalendarTime { mctYear :: Maybe Int , mctMonth :: Maybe Month , mctDay :: Maybe Int , mctHour :: Maybe Int , mctMin :: Maybe Int , mctSec :: Maybe Int , mctPicosec :: Maybe Integer , mctWDay :: Maybe Day , mctYDay :: Maybe Int , mctTZName :: Maybe String , mctTZ :: Maybe Int , mctIsDST :: Maybe Bool , mctWeek :: Bool -- is set or not } deriving Show -- | Trivially convert a 'CalendarTime' to a fully specified -- 'MCalendarTime' (note that this sets the 'mctWeek' flag to -- @False@ toMCalendarTime :: CalendarTime -> MCalendarTime toMCalendarTime (CalendarTime a b c d e f g h i j k l) = MCalendarTime (Just a) (Just b) (Just c) (Just d) (Just e) (Just f) (Just g) (Just h) (Just i) (Just j) (Just k) (Just l) False -- | Returns the first 'CalendarTime' that falls within a 'MCalendarTime' -- This is only unsafe in the sense that it plugs in default values -- for fields that have not been set, e.g. @January@ for the month -- or @0@ for the seconds field. -- Maybe we should rename it something happier. -- See also 'resetCalendar' unsafeToCalendarTime :: MCalendarTime -> CalendarTime unsafeToCalendarTime m = CalendarTime { ctYear = fromMaybe 0 $ mctYear m , ctMonth = fromMaybe January $ mctMonth m , ctDay = fromMaybe 1 $ mctDay m , ctHour = fromMaybe 0 $ mctHour m , ctMin = fromMaybe 0 $ mctMin m , ctSec = fromMaybe 0 $ mctSec m , ctPicosec = fromMaybe 0 $ mctPicosec m , ctWDay = fromMaybe Sunday $ mctWDay m , ctYDay = fromMaybe 0 $ mctYDay m , ctTZName = fromMaybe "" $ mctTZName m , ctTZ = fromMaybe 0 $ mctTZ m , ctIsDST = fromMaybe False $ mctIsDST m } addToCal :: TimeDiff -> CalendarTime -> CalendarTime addToCal td = toUTCTime . addToClockTime td . toClockTime subtractFromCal :: TimeDiff -> CalendarTime -> CalendarTime subtractFromCal = addToCal . multiplyDiff (-1) addToMCal :: TimeDiff -> MCalendarTime -> MCalendarTime addToMCal td mc = copyCalendar (addToCal td $ unsafeToCalendarTime mc) mc subtractFromMCal :: TimeDiff -> MCalendarTime -> MCalendarTime subtractFromMCal = addToMCal . multiplyDiff (-1) -- surely there is a more concise way to express these addDiff :: TimeDiff -> TimeDiff -> TimeDiff addDiff (TimeDiff a1 a2 a3 a4 a5 a6 a7) (TimeDiff b1 b2 b3 b4 b5 b6 b7) = TimeDiff (a1+b1) (a2+b2) (a3+b3) (a4+b4) (a5+b5) (a6+b6) (a7 + b7) -- | 'multiplyDiff' @i d@ multiplies every field in @d@ with @i@ -- -- FIXME; this seems like a terrible idea! it seems like -- we should get rid of it if at all possible, maybe adding an -- invertDiff function multiplyDiff :: Int -> TimeDiff -> TimeDiff multiplyDiff m (TimeDiff a1 a2 a3 a4 a5 a6 a7) = TimeDiff (a1*m) (a2*m) (a3*m) (a4*m) (a5*m) (a6*m) (a7 * (toInteger m)) nullMCalendar :: MCalendarTime nullMCalendar = MCalendarTime Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing False -- | Set a calendar to UTC time any eliminate any inconsistencies within -- (for example, where the weekday is given as @Thursday@, but this does not -- match what the numerical date would lead one to expect) resetCalendar :: CalendarTime -> CalendarTime resetCalendar = toUTCTime . toClockTime -- | 'copyCalendar' @c mc@ replaces any field which is -- specified in @mc@ with the equivalent field in @c@ -- @copyCalendar c nullMCalendar == nullMCalendar@ copyCalendar :: CalendarTime -> MCalendarTime -> MCalendarTime copyCalendar c mc = mc { mctYear = mctYear mc >> Just (ctYear c) , mctMonth = mctMonth mc >> Just (ctMonth c) , mctDay = mctDay mc >> Just (ctDay c) , mctHour = mctHour mc >> Just (ctHour c) , mctMin = mctMin mc >> Just (ctMin c) , mctSec = mctSec mc >> Just (ctSec c) , mctPicosec = mctPicosec mc >> Just (ctPicosec c) , mctWDay = mctWDay mc >> Just (ctWDay c) , mctYDay = mctYDay mc >> Just (ctYDay c) , mctTZName = mctTZName mc >> Just (ctTZName c) , mctTZ = mctTZ mc >> Just (ctTZ c) , mctIsDST = mctIsDST mc >> Just (ctIsDST c) } -- | Zero the time fields of a 'CalendarTime' unsetTime :: CalendarTime -> CalendarTime unsetTime mc = mc { ctHour = 0 , ctMin = 0 , ctSec = 0 , ctPicosec = 0 } darcs-2.8.4/src/Lcs.hs0000644001765600176560000005071412104371431014014 0ustar ganeshganesh-- Copyright (C) 2002 David Roundy -- Copyright (C) 2005 Benedikt Schmidt -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP #-} -- | -- Module : Lcs -- Copyright : 2003 David Roundy -- 2005 Benedikt Schmidt -- License : GPL -- Maintainer : darcs-devel@darcs.net -- Stability : experimental -- Portability : portable -- -- LCS stands for Longest Common Subsequence, and it is a relatively -- challenging problem to find an LCS efficiently. This module implements -- the algorithm described in: -- -- "An O(ND) Difference Algorithm and its Variations", Eugene Myers, -- Algorithmica Vol. 1 No. 2, 1986, pp. 251-266; -- especially the variation described in section 4.2 and most refinements -- implemented in GNU diff (D is the edit-distance). -- -- There is currently no heuristic to reduce the running time and produce -- suboptimal output for large inputs with many differences. It behaves like -- GNU diff with the -d option in this regard. -- -- In the first step, a hash value for every line is calculated and collisions -- are marked with a special value. This reduces a string comparison to an -- int comparison for line tuples where at least one of the hash values is -- not equal to the special value. After that, lines which only exists in one -- of the files are removed and marked as changed which reduces the running -- time of the following difference algorithm. GNU diff additionally removes -- lines that appear very often in the other file in some cases. -- The last step tries to create longer changed regions and line up deletions -- in the first file to insertions in the second by shifting changed lines -- forward and backward. module Lcs ( getChanges, shiftBoundaries ) where import Control.Monad import Data.Int import Control.Monad.ST import Data.Maybe import ByteStringUtils (hashPS) import qualified Data.ByteString as B (empty, ByteString) import Data.Array.Base import Data.Array.Unboxed import qualified Data.Map as Map ( lookup, empty, insertWith ) #include "impossible.h" -- | create a list of changes between a and b, each change has the form -- (starta, lima, startb, limb) which means that a[starta, lima) -- has to be replaced by b[startb, limb) getChanges :: [B.ByteString] -> [B.ByteString] -> [(Int,[B.ByteString],[B.ByteString])] getChanges a b = dropStart (initP a) (initP b) 1 dropStart :: PArray -> PArray -> Int -> [(Int,[B.ByteString],[B.ByteString])] dropStart a b off | off > aLen a = [(off - 1, [], getSlice b off (aLen b))] | off > aLen b = [(off - 1, getSlice a off (aLen a), [])] | a!off == b!off = dropStart a b (off + 1) | otherwise = dropEnd a b off 0 dropEnd :: PArray -> PArray -> Int -> Int -> [(Int,[B.ByteString],[B.ByteString])] dropEnd a b off end | off > alast = [(off - 1, [], getSlice b off blast)] | off > blast = [(off - 1, getSlice a off alast, [])] | a!alast == b!blast = dropEnd a b off (end + 1) | otherwise = getChanges' (a, (off, alast)) (b, (off, blast)) where alast = aLen a - end blast = aLen b - end getSlice :: PArray -> Int -> Int -> [B.ByteString] getSlice a from to | from > to = [] | otherwise = (a ! from) : (getSlice a (from + 1) to) getChanges' :: (PArray, (Int, Int)) -> (PArray, (Int, Int)) -> [(Int,[B.ByteString],[B.ByteString])] getChanges' (a, abounds) (b, bbounds) = map (convertPatch 0 a b) $ createPatch c_a c_b where -- If the last few characters of two lines are the same, the lines are -- probably the same. The choice of 20 is plucked out of the air. toHash x bnds = listArray bnds [ hashPS $ x!i | i <- range bnds] ah = toHash a abounds :: HArray mkAMap m (i:is) = let ins (_,_,_,new) (collision,_,_,old) = (collision || (new /= old), True, False, old) m' = Map.insertWith ins (ah!i) (False, True, False, a!i) m in mkAMap m' is mkAMap m _ = m hm_a = mkAMap Map.empty (range abounds) -- bh = toHash b bbounds :: HArray mkBMap m (i:is) = let ins (_,_,_,new) (collision,in_a,_,old) = (collision || (new /= old), in_a, True, old) m' = Map.insertWith ins (bh!i) (False, False, True, b!i) m in mkBMap m' is mkBMap m _ = m hm = mkBMap hm_a (range bbounds) -- take care of collisions, if there are different lines with the -- same hash in both files, then set the hash to markColl, -- PackedStrings are compared for two lines with the hash markColl get (i, h) = case Map.lookup h hm of Just (_,False,_,_) -> Nothing Just (_,_,False,_) -> Nothing Just (False,True,True,_) -> Just (i, h) Just (True,True,True,_) -> Just (i, markColl) Nothing -> impossible a' = mapMaybe get [(i, ah!i) | i <- range (bounds ah)] b' = mapMaybe get [(i, bh!i) | i <- range (bounds bh)] (c_a, c_b) = diffArr a' b' (a, abounds) (b, bbounds) -- | mark hash value where collision occured markColl :: Int32 markColl = 2345677 -- | return arrays with changes in a and b (1 indexed), offsets start with 0 diffArr :: [(Int,Int32)] -> [(Int,Int32)] -> (PArray, (Int, Int)) -> (PArray, (Int, Int)) -> (BArray, BArray) diffArr a b (p_a, (off_a, l_a)) (p_b, (off_b, l_b)) = runST ( do let h_a = initH (map snd a) h_b = initH (map snd b) m_a = initM (map fst a) m_b = initM (map fst b) end_a = (aLen p_a) end_b = (aLen p_b) c_a <- initVChanged end_a c_b <- initVChanged end_b mapM_ (\ (l,_) -> writeArray c_a l False) a mapM_ (\ (l,_) -> writeArray c_b l False) b _ <- cmpseq h_a h_b p_a p_b m_a m_b c_a c_b 0 0 (aLen h_a) (aLen h_b) let unchanged ar = do {xs <- getElems ar; return $ length (filter not xs) -1} err <- liftM2 (/=) (unchanged c_a) (unchanged c_b) when err impossible -- Mark common lines at beginning and end mapM_ (\ i -> writeArray c_a i False ) [1..(off_a - 1)] mapM_ (\ i -> writeArray c_b i False ) [1..(off_b - 1)] mapM_ (\ i -> writeArray c_a i False ) [(l_a + 1) .. end_a] mapM_ (\ i -> writeArray c_b i False ) [(l_b + 1) .. end_b] shiftBoundaries c_a c_b p_a 1 1 shiftBoundaries c_b c_a p_b 1 1 err1 <- liftM2 (/=) (unchanged c_a) (unchanged c_b) when err1 impossible c_a' <- unsafeFreeze c_a c_b' <- unsafeFreeze c_b return (c_a', c_b')) -- | set changes array for a and b and return number of changed lines cmpseq :: HArray -> HArray -> PArray -> PArray -> MapArray -> MapArray -> BSTArray s -> BSTArray s -> Int -> Int -> Int -> Int -> ST s Int cmpseq _ _ _ _ _ _ _ _ _ _ 0 0 = return 0 cmpseq h_a h_b p_a p_b m_a m_b c_a c_b off_a off_b l_a l_b = do let lim_a = off_a+l_a lim_b = off_b+l_b off_a' = findSnake h_a h_b p_a p_b m_a m_b off_a off_b l_a l_b off_a off_b off_b' = off_b+off_a'-off_a lim_a' = findSnakeRev h_a h_b p_a p_b m_a m_b lim_a lim_b off_a' off_b' lim_b' = lim_b+lim_a'-lim_a l_a' = lim_a'-off_a' l_b' = lim_b'-off_b' if l_a' == 0 || l_b' == 0 then if l_a' == 0 then do when (l_b' > 0) $ mapM_ (\i -> writeArray c_b (m_b!i) True) [(off_b' + 1) .. lim_b'] return l_b' else do when (l_a' > 0) $ mapM_ (\i -> writeArray c_a (m_a!i) True) [(off_a' + 1) .. lim_a'] return l_a' else do let m = l_a' + l_b' del = l_a' - l_b' dodd = odd del v <- initV m vrev <- initVRev m l_a' writeArray vrev 0 l_a' writeArray v 0 0 (xmid, ymid, _) <- findDiag 1 h_a h_b p_a p_b m_a m_b v vrev off_a' off_b' l_a' l_b' del dodd when ((xmid == 0 && ymid == 0) || (xmid == l_a' && ymid == l_b') || (xmid < 0 || ymid < 0 || xmid > l_a' || ymid > l_b')) impossible c1 <- cmpseq h_a h_b p_a p_b m_a m_b c_a c_b off_a' off_b' xmid ymid c2 <- cmpseq h_a h_b p_a p_b m_a m_b c_a c_b (off_a' + xmid) (off_b' + ymid) (l_a' - xmid) (l_b' - ymid) return $ c1 + c2 -- | return (xmid, ymid, cost) for the two substrings -- a[off_a+1..off_a+1+l_a] and b findDiag :: Int -> HArray -> HArray -> PArray -> PArray -> MapArray -> MapArray -> VSTArray s -> VSTArray s -> Int -> Int -> Int -> Int -> Int -> Bool -> ST s (Int, Int, Int) findDiag c h_a h_b p_a p_b m_a m_b v vrev off_a off_b l_a l_b del dodd = do when (c > l_a + l_b) $ error "findDiag failed" r <- findF case r of Just (xmid, ymid) -> return (xmid, ymid, (c*2 - 1)) Nothing -> do r' <- findR case r' of Just (xmid, ymid) -> return (xmid, ymid, c*2) Nothing -> findDiag (c + 1) h_a h_b p_a p_b m_a m_b v vrev off_a off_b l_a l_b del dodd where fdmax = if c <= l_a then c else l_a - ((l_a + c) `mod` 2) rdmax = if c <= l_b then c else l_b - ((l_b + c) `mod` 2) lastrdmax = if (c-1) <= l_b then c-1 else l_b-(l_b + (c-1) `mod` 2) lastrdmin = -(if (c-1) <= l_a then c-1 else l_a-((l_a + (c-1)) `mod` 2)) fdmin = -rdmax rdmin = -fdmax findF = findF' fdmax findR = findR' rdmax findF' d = do x <- findOne h_a h_b p_a p_b m_a m_b v d off_a off_b l_a l_b if dodd && d - del >= lastrdmin && d - del <= lastrdmax then do xr <- readArray vrev (d - del) if xr <= x then return $ Just (x, x - d) else if d <= fdmin then return Nothing else findF' (d-2) else if d <= fdmin then return Nothing else findF' (d-2) findR' d = do x <- findOneRev h_a h_b p_a p_b m_a m_b vrev d del off_a off_b if not dodd && (d + del >= fdmin) && (d + del <= fdmax) then do xf <- readArray v (d + del) if x <= xf then return $ Just (x,x-del-d) else if d <= rdmin then return Nothing else findR' (d-2) else if d <= rdmin then return Nothing else findR' (d-2) -- | find position on diag d with one more insert/delete going forward findOne :: HArray -> HArray -> PArray -> PArray -> MapArray -> MapArray -> VSTArray s -> Int -> Int -> Int -> Int -> Int -> ST s Int findOne h_a h_b p_a p_b m_a m_b v d off_a off_b l_a l_b = do x0 <- do xbelow <- readArray v (d - 1) xover <- readArray v (d + 1) return $ if xover > xbelow then xover else xbelow + 1 let y0 = x0 - d x = findSnake h_a h_b p_a p_b m_a m_b (x0+off_a) (y0+off_b) l_a l_b off_a off_b writeArray v d (x - off_a) return (x-off_a) -- | follow snake from northwest to southeast, x and y are absolute positions findSnake :: HArray -> HArray -> PArray -> PArray -> MapArray -> MapArray -> Int -> Int -> Int -> Int -> Int -> Int -> Int findSnake h_a h_b p_a p_b m_a m_b x y l_a l_b off_a off_b = if x < l_a + off_a && y < l_b + off_b && h_a!(x+1) == h_b!(y+1) && (h_a!(x+1) /= markColl || p_a!(m_a!(x+1)) == p_b!(m_b!(y+1))) then findSnake h_a h_b p_a p_b m_a m_b (x + 1) (y + 1) l_a l_b off_a off_b else x -- | find position on diag d with one more insert/delete going backward findOneRev :: HArray -> HArray -> PArray -> PArray -> MapArray -> MapArray -> VSTArray s -> Int -> Int -> Int -> Int -> ST s Int findOneRev h_a h_b p_a p_b m_a m_b v d del off_a off_b = do x0 <- do xbelow <- readArray v (d - 1) xover <- readArray v (d + 1) return $ if xbelow < xover then xbelow else xover-1 let y0 = x0 - del - d x = findSnakeRev h_a h_b p_a p_b m_a m_b (x0+off_a) (y0+off_b) off_a off_b writeArray v d (x-off_a) return (x-off_a) -- | follow snake from southeast to northwest, x and y are absolute positions findSnakeRev :: HArray -> HArray -> PArray -> PArray -> MapArray -> MapArray -> Int -> Int -> Int -> Int -> Int findSnakeRev h_a h_b p_a p_b m_a m_b x y off_a off_b = if x > off_a && y > off_b && h_a!x == h_b!y && (h_a!x /= markColl || p_a!(m_a!x) == p_b!(m_b!y)) then findSnakeRev h_a h_b p_a p_b m_a m_b (x - 1) (y - 1) off_a off_b else x -- | try to create nicer diffs by shifting around regions of changed lines shiftBoundaries :: BSTArray s -> BSTArray s -> PArray -> Int -> Int -> ST s () shiftBoundaries c_a c_b p_a i_ j_ = do x <- nextChanged c_a i_ case x of Just start -> do let skipped = start - i_ j1 <- nextUnchangedN c_b skipped j_ end <- nextUnchanged c_a start j2 <- nextUnchanged c_b j1 (i3,j3) <- expand start end j2 shiftBoundaries c_a c_b p_a i3 j3 Nothing -> return () -- no change up to end of file where noline = (aLen p_a) + 1 expand start i j = do let len = i - start (start0,i0,j0) <- shiftBackward start i j b <- if j0 > 1 then readArray c_b (j0-1) else return False let corr = if b then i0 else noline let blank = if p_a!(i0-1) == B.empty then i0 else noline (start1,i1,j1,corr1,blank1) <- shiftForward start0 i0 j0 corr blank -- prefer corresponding to ending with blank line let newi = if corr1 == noline then blank1 else corr1 (start2,i2,j2) <- moveCorr start1 i1 j1 newi if len /= i2 - start2 then expand start2 i2 j2 else return (i2, j2) shiftBackward start i j = if start > 1 && p_a!(i-1) == p_a!(start-1) then do when (i == start) impossible b1 <- readArray c_a (i-1) b2 <- readArray c_a (start-1) when (not b1 || b2) impossible writeArray c_a (i-1) False writeArray c_a (start-1) True b <- if start > 2 then readArray c_a (start-2) else return False start' <- if b then liftM (1+) (prevUnchanged c_a (start-2)) else return (start-1) j' <- prevUnchanged c_b (j-1) shiftBackward start' (i-1) j' else return (start,i,j) shiftForward start i j corr blank = if i <= aLen p_a && p_a!i == p_a!start && -- B.empty at the end of file marks empty line after final newline not ((i == aLen p_a) && (p_a!i == B.empty)) then do when (i == start) impossible b1 <- readArray c_a i b2 <- readArray c_a start when (not b2 || b1) impossible writeArray c_a i True writeArray c_a start False i0 <- nextUnchanged c_a (i+1) j0 <- nextUnchanged c_b (j+1) let corr0 = if i0 > (i+1) then noline else if j0-j > 2 then i0 else corr let blank0 = if i0 > i+1 then noline else if p_a!(i0-1) == B.empty then i0 else blank shiftForward (start+1) i0 j0 corr0 blank0 else return (start,i,j,corr,blank) moveCorr start i j corr = if corr >= i then return (start,i,j) else do b1 <- readArray c_a (i-1) b2 <- readArray c_a (start-1) when (not b1 || b2) impossible when (p_a!(i-1) /= p_a!(start-1)) impossible writeArray c_a (i-1) False writeArray c_a (start-1) True j' <- prevUnchanged c_b (j-1) moveCorr (start-1) (i-1) j' corr -- | goto next unchanged line, return the given line if unchanged nextUnchanged :: BSTArray s -> Int -> ST s Int nextUnchanged c i = do len <- aLenM c if i == len + 1 then return i else do b <- readArray c i if b then nextUnchanged c (i+1) else return i -- | skip at least one unchanged line, if there is none advance -- behind the last line skipOneUnChanged :: BSTArray s -> Int -> ST s Int skipOneUnChanged c i = do len <- aLenM c if i == len + 1 then return i else do b <- readArray c i if not b then return (i+1) else skipOneUnChanged c (i+1) -- | goto n-th next unchanged line nextUnchangedN :: BSTArray s -> Int -> Int -> ST s Int nextUnchangedN c n i = if n == 0 then return i else do i' <- skipOneUnChanged c i nextUnchangedN c (n-1) i' -- | goto next changed line, return the given line if changed nextChanged :: BSTArray s -> Int -> ST s (Maybe Int) nextChanged c i = do len <- aLenM c if i <= len then do b <- readArray c i if not b then nextChanged c (i+1) else return $ Just i else return Nothing -- | goto previous unchanged line, return the given line if unchanged prevUnchanged :: BSTArray s -> Int -> ST s Int prevUnchanged c i = do b <- readArray c i if b then prevUnchanged c (i-1) else return i type HArray = UArray Int Int32 type BArray = UArray Int Bool type PArray = Array Int B.ByteString type MapArray = UArray Int Int type VSTArray s = STUArray s Int Int type BSTArray s = STUArray s Int Bool initV :: Int -> ST s (VSTArray s) initV dmax = newArray (-(dmax + 1), dmax + 1) (-1) initVRev :: Int -> Int -> ST s (VSTArray s) initVRev dmax xmax = newArray (-(dmax + 1), dmax + 1) (xmax + 1) -- 1 indexed, v[0] is used as a guard element initVChanged :: Int -> ST s (BSTArray s) initVChanged l = do a <- newArray (0, l) True writeArray a 0 False return a -- set to false for all lines which have a mapping later -- other lines are only present in one of the files initH :: [Int32] -> HArray initH a = listArray (0, length a) (0:a) initM :: [Int] -> MapArray initM a = listArray (0, length a) (0:a) initP :: [B.ByteString] -> PArray initP a = listArray (0, length a) (B.empty:a) aLen :: (IArray a e) => a Int e -> Int aLen a = snd $ bounds a aLenM :: (MArray a e m) => a Int e -> m Int aLenM a = getBounds a >>= return . snd convertPatch :: Int -> PArray -> PArray -> (Int, Int, Int, Int) -> (Int,[B.ByteString],[B.ByteString]) convertPatch off a b (a0,a1,b0,b1) | b0 == b1 = (b0+off,getDelete a a0 a1,[]) | a0 == a1 = (b0+off,[],getInsert b b0 b1) | otherwise = (b0+off,getDelete a a0 a1,getInsert b b0 b1) getInsert :: PArray -> Int -> Int -> [B.ByteString] getInsert b from to | from >= to = [] | otherwise = (b!(from+1)):(getInsert b (from+1) to) getDelete :: PArray -> Int -> Int -> [B.ByteString] getDelete a from to | from >= to = [] | otherwise = (a!(from+1)):(getDelete a (from+1) to) createPatch :: BArray -> BArray -> [(Int, Int, Int, Int)] createPatch c_a c_b = reverse $ createP c_a c_b (aLen c_a) (aLen c_b) createP :: BArray -> BArray -> Int -> Int -> [(Int, Int, Int, Int)] createP _ _ 0 0 = [] createP c_a c_b ia ib = if c_a!ia || c_b!ib then let ia' = skipChangedRev c_a ia ib' = skipChangedRev c_b ib in (ia',ia,ib',ib):(createP c_a c_b ia' ib') else createP c_a c_b (ia-1) (ib-1) skipChangedRev :: BArray -> Int -> Int skipChangedRev c i = if i >= 0 && c!i then skipChangedRev c (i-1) else i darcs-2.8.4/src/Printer.lhs0000644001765600176560000004075212104371431015073 0ustar ganeshganesh A Document is at heart ShowS from the prelude \htmladdnormallink{http://www.haskell.org/onlinereport/standard-prelude.html#\$tShowS} Essentially, if you give a Doc a string it'll print out whatever it wants followed by that string. So \verb!(text "foo")! makes the Doc that prints \verb!"foo"! followed by its argument. The combinator names are taken from Text.PrettyPrint.HughesPJ, although the behaviour of the two libraries is slightly different. The advantage of Printer over simple string appending/concatenating is that the appends end up associating to the right, e.g.: \begin{verbatim} (text "foo" <> text "bar") <> (text "baz" <> text "quux") "" = \s -> (text "foo" <> text "bar") ((text "baz" <> text "quux") s) "" = (text "foo" <> text "bar") ((text "baz" <> text "quux") "") = (\s -> (text "foo") (text "bar" s)) ((text "baz" <> text "quux") "") = text "foo" (text "bar" ((text "baz" <> text "quux") "")) = (\s -> "foo" ++ s) (text "bar" ((text "baz" <> text "quux") "")) = "foo" ++ (text "bar" ((text "baz" <> text "quux") "")) = "foo" ++ ("bar" ++ ((text "baz" <> text "quux") "")) = "foo" ++ ("bar" ++ ((\s -> text "baz" (text "quux" s)) "")) = "foo" ++ ("bar" ++ (text "baz" (text "quux" ""))) = "foo" ++ ("bar" ++ ("baz" ++ (text "quux" ""))) = "foo" ++ ("bar" ++ ("baz" ++ ("quux" ++ ""))) \end{verbatim} The Empty alternative comes in because you want \begin{verbatim} text "a" $$ vcat xs $$ text "b" \end{verbatim} (\verb!$$! means ``above'', vcat is the list version of \verb!$$!) to be \verb!"a\nb"! when \verb!xs! is \verb![]!, but without the concept of an Empty Document each \verb!$$! would add a \verb!'\n'! and you'd end up with \verb!"a\n\nb"!. Note that \verb!Empty /= text ""! (the latter would cause two \verb!'\n'!s). This code was made generic in the element type by Juliusz Chroboczek. \begin{code} module Printer (Printable(..), Doc(Doc,unDoc), Printers, Printers'(..), Printer, Color(..), hPutDoc, hPutDocLn, putDoc, putDocLn, hPutDocWith, hPutDocLnWith, putDocWith, putDocLnWith, renderString, renderStringWith, renderPS, renderPSWith, renderPSs, renderPSsWith, lineColor, prefix, insertBeforeLastline, colorText, invisibleText, hiddenText, hiddenPrefix, userchunk, text, printable, wrapText, blueText, redText, greenText, magentaText, cyanText, unsafeText, unsafeBoth, unsafeBothText, unsafeChar, invisiblePS, packedString, unsafePackedString, userchunkPS, simplePrinters, invisiblePrinter, simplePrinter, doc, empty, (<>), (), (<+>), ($$), vcat, vsep, hcat, minus, newline, plus, space, backslash, lparen, rparen, parens, errorDoc, ) where import Data.List (intersperse) import System.IO (Handle, stdout, hPutStr) import ByteStringUtils ( linesPS ) import qualified Data.ByteString as B (ByteString, hPut, concat) import qualified Data.ByteString.Char8 as BC (unpack, pack, singleton) -- | A 'Printable' is either a String, a packed string, or a chunk of -- text with both representations. data Printable = S !String | PS !B.ByteString | Both !String !B.ByteString -- | 'spaceP' is the 'Printable' representation of a space. spaceP :: Printable spaceP = Both " " (BC.singleton ' ') -- | 'newlineP' is the 'Printable' representation of a newline. newlineP :: Printable newlineP = S "\n" -- | Minimal 'Doc's representing the common characters 'space', 'newline' -- 'minus', 'plus', and 'backslash'. space, newline, plus, minus, backslash :: Doc space = unsafeBoth " " (BC.singleton ' ') newline = unsafeChar '\n' minus = unsafeBoth "-" (BC.singleton '-') plus = unsafeBoth "+" (BC.singleton '+') backslash = unsafeBoth "\\" (BC.singleton '\\') -- | 'lparen' is the 'Doc' that represents @\"(\"@ lparen :: Doc lparen = unsafeBoth "(" (BC.singleton '(') -- | 'rparen' is the 'Doc' that represents @\")\"@ rparen :: Doc rparen = unsafeBoth ")" (BC.singleton ')') -- | @'parens' doc@ returns a 'Doc' with the content of @doc@ put within -- a pair of parenthesis. parens :: Doc -> Doc parens d = lparen <> d <> rparen errorDoc :: Doc -> a errorDoc = error . renderStringWith simplePrinters' -- | 'putDocWith' puts a doc on stdout using the given printer. putDocWith :: Printers -> Doc -> IO () putDocWith prs = hPutDocWith prs stdout -- | 'putDocLnWith' puts a doc, followed by a newline on stdout using -- the given printer. putDocLnWith :: Printers -> Doc -> IO () putDocLnWith prs = hPutDocLnWith prs stdout -- | 'putDoc' puts a doc on stdout using the simple printer 'simplePrinters'. putDoc :: Doc -> IO () -- | 'putDocLn' puts a doc, followed by a newline on stdout using -- 'simplePrinters' putDocLn :: Doc -> IO () putDoc = hPutDoc stdout putDocLn = hPutDocLn stdout -- | 'hputDocWith' puts a doc on the given handle using the given printer. hPutDocWith :: Printers -> Handle -> Doc -> IO () -- | 'hputDocLnWith' puts a doc, followed by a newline on the given -- handle using the given printer. hPutDocLnWith :: Printers -> Handle -> Doc -> IO () hPutDocWith prs h d = hPrintPrintables h (renderWith (prs h) d) hPutDocLnWith prs h d = hPutDocWith prs h (d newline) -- |'hputDoc' puts a doc on the given handle using 'simplePrinters' hPutDoc :: Handle -> Doc -> IO () -- 'hputDocLn' puts a doc, followed by a newline on the given handle using -- 'simplePrinters'. hPutDocLn :: Handle -> Doc -> IO () hPutDoc = hPutDocWith simplePrinters hPutDocLn = hPutDocLnWith simplePrinters -- | @'hPrintPrintables' h@ prints a list of 'Printable's to the handle h hPrintPrintables :: Handle -> [Printable] -> IO () hPrintPrintables h = mapM_ (hPrintPrintable h) -- | @hPrintPrintable h@ prints a 'Printable' to the handle h. hPrintPrintable :: Handle -> Printable -> IO () hPrintPrintable h (S ps) = hPutStr h ps hPrintPrintable h (PS ps) = B.hPut h ps hPrintPrintable h (Both _ ps) = B.hPut h ps -- | a 'Doc' is a bit of enriched text. 'Doc's get concatanated using -- '<>', which is right-associative. newtype Doc = Doc { unDoc :: St -> Document } -- | The State associated with a doc. Contains a set of printers for each -- hanlde, and the current prefix of the document. data St = St { printers :: !Printers', currentPrefix :: !([Printable] -> [Printable]) } type Printers = Handle -> Printers' -- | A set of printers to print different types of text to a handle. data Printers' = Printers {colorP :: !(Color -> Printer), invisibleP :: !Printer, hiddenP :: !Printer, userchunkP :: !Printer, defP :: !Printer, lineColorT :: !(Color -> Doc -> Doc), lineColorS :: !([Printable] -> [Printable]) } type Printer = Printable -> St -> Document data Color = Blue | Red | Green | Cyan | Magenta -- | 'Document' is a wrapper around '[Printable] -> [Printable]' which allows -- for empty Documents. The simplest 'Documents' are built from 'String's -- using 'text'. data Document = Document ([Printable] -> [Printable]) | Empty -- | renders a 'Doc' into a 'String' with control codes for the -- special features of the doc. renderString :: Doc -> String renderString = renderStringWith simplePrinters' -- | renders a 'Doc' into a 'String' using a given set of printers. renderStringWith :: Printers' -> Doc -> String renderStringWith prs d = concatMap toString $ renderWith prs d where toString (S s) = s toString (PS ps) = BC.unpack ps toString (Both s _) = s -- | renders a 'Doc' into 'B.ByteString' with control codes for the -- special features of the Doc. See also 'readerString'. renderPS :: Doc -> B.ByteString renderPS = renderPSWith simplePrinters' -- | renders a 'Doc' into a list of 'PackedStrings', one for each line. renderPSs :: Doc -> [B.ByteString] renderPSs = renderPSsWith simplePrinters' -- | renders a doc into a 'B.ByteString' using a given set of printers. renderPSWith :: Printers' -> Doc -> B.ByteString renderPSWith prs d = B.concat $ renderPSsWith prs d -- | renders a 'Doc' into a list of 'PackedStrings', one for each -- chunk of text that was added to the doc, using the given set of -- printers. renderPSsWith :: Printers' -> Doc -> [B.ByteString] renderPSsWith prs d = map toPS $ renderWith prs d where toPS (S s) = BC.pack s toPS (PS ps) = ps toPS (Both _ ps) = ps -- | renders a 'Doc' into a list of 'Printables' using a set of -- printers. Each item of the list corresponds to a string that was -- added to the doc. renderWith :: Printers' -> Doc -> [Printable] renderWith ps (Doc d) = case d (initState ps) of Empty -> [] Document f -> f [] initState :: Printers' -> St initState prs = St { printers = prs, currentPrefix = id } prefix :: String -> Doc -> Doc prefix s (Doc d) = Doc $ \st -> let p = S s st' = st { currentPrefix = currentPrefix st . (p:) } in case d st' of Document d'' -> Document $ (p:) . d'' Empty -> Empty insertBeforeLastline :: Doc -> Doc -> Doc insertBeforeLastline a b = case reverse $ map packedString $ linesPS $ renderPS a of (ll:ls) -> vcat (reverse ls) $$ b $$ ll [] -> error "empty Doc given as first argument of Printer.insert_before_last_line" lineColor :: Color -> Doc -> Doc lineColor c d = Doc $ \st -> case lineColorT (printers st) c d of Doc d' -> d' st hiddenPrefix :: String -> Doc -> Doc hiddenPrefix s (Doc d) = Doc $ \st -> let pr = printers st p = S (renderStringWith pr $ hiddenText s) st' = st { currentPrefix = currentPrefix st . (p:) } in case d st' of Document d'' -> Document $ (p:) . d'' Empty -> Empty -- | 'unsafeBoth' builds a Doc from a 'String' and a 'B.ByteString' representing -- the same text, but does not check that they do. unsafeBoth :: String -> B.ByteString -> Doc unsafeBoth s ps = Doc $ simplePrinter (Both s ps) -- | 'unsafeBothText' builds a 'Doc' from a 'String'. The string is stored in the -- Doc as both a String and a 'B.ByteString'. unsafeBothText :: String -> Doc unsafeBothText s = Doc $ simplePrinter (Both s (BC.pack s)) -- | 'packedString' builds a 'Doc' from a 'B.ByteString' using 'printable' packedString :: B.ByteString -> Doc -- | 'unsafePackedString' builds a 'Doc' from a 'B.ByteString' using 'simplePrinter' unsafePackedString :: B.ByteString -> Doc -- | 'invisiblePS' creates a 'Doc' with invisible text from a 'B.ByteString' invisiblePS :: B.ByteString -> Doc -- | 'userchunkPS' creates a 'Doc' representing a user chunk from a 'B.ByteString'. userchunkPS :: B.ByteString -> Doc packedString = printable . PS unsafePackedString = Doc . simplePrinter . PS invisiblePS = invisiblePrintable . PS userchunkPS = userchunkPrintable . PS -- | 'unsafeChar' creates a Doc containing just one character. unsafeChar :: Char -> Doc unsafeChar = unsafeText . (:"") -- | 'text' creates a 'Doc' from a @String@, using 'printable'. text :: String -> Doc -- | 'unsafeText' creates a 'Doc' from a 'String', using 'simplePrinter' directly unsafeText :: String -> Doc -- | 'invisibleText' creates a 'Doc' containing invisible text from a @String@ invisibleText :: String -> Doc -- | 'hiddenText' creates a 'Doc' containing hidden text from a @String@ hiddenText :: String -> Doc -- | 'userchunk' creates a 'Doc' containing a user chunk from a @String@ userchunk :: String -> Doc -- | 'blueText' creates a 'Doc' containing blue text from a @String@ blueText, redText, greenText, magentaText, cyanText :: String -> Doc text = printable . S unsafeText = Doc . simplePrinter . S invisibleText = invisiblePrintable . S hiddenText = hiddenPrintable . S userchunk = userchunkPrintable . S blueText = colorText Blue redText = colorText Red greenText = colorText Green magentaText = colorText Magenta cyanText = colorText Cyan -- | 'colorText' creates a 'Doc' containing colored text from a @String@ colorText :: Color -> String -> Doc colorText c = mkColorPrintable c . S -- | @'wrapText' n s@ is a 'Doc' representing @s@ line-wrapped at 'n' characters wrapText :: Int -> String -> Doc wrapText n s = vcat $ map text $ reverse $ "": (foldl add_to_line [] $ words s) where add_to_line [] a = [a] add_to_line ("":d) a = (a:d) add_to_line (l:ls) new | length l + length new > n = new:l:ls add_to_line (l:ls) new = (l ++ " " ++ new):ls -- | 'printable x' creates a 'Doc' from any 'Printable'. printable, invisiblePrintable, hiddenPrintable, userchunkPrintable :: Printable -> Doc printable x = Doc $ \st -> defP (printers st) x st mkColorPrintable :: Color -> Printable -> Doc mkColorPrintable c x = Doc $ \st -> colorP (printers st) c x st invisiblePrintable x = Doc $ \st -> invisibleP (printers st) x st hiddenPrintable x = Doc $ \st -> hiddenP (printers st) x st userchunkPrintable x = Doc $ \st -> userchunkP (printers st) x st -- | 'simplePrinters' is a 'Printers' which uses the set 'simplePriners\'' on any -- handle. simplePrinters :: Printers simplePrinters _ = simplePrinters' -- | A set of default printers suitable for any handle. Does not use color. simplePrinters' :: Printers' simplePrinters' = Printers { colorP = const simplePrinter, invisibleP = simplePrinter, hiddenP = invisiblePrinter, userchunkP = simplePrinter, defP = simplePrinter, lineColorT = const id, lineColorS = id } -- | 'simplePrinter' is the simplest 'Printer': it just concatenates together -- the pieces of the 'Doc' simplePrinter :: Printer -- | 'invisiblePrinter' is the 'Printer' for hidden text. It just replaces -- the document with 'empty'. It's useful to have a printer that doesn't -- actually do anything because this allows you to have tunable policies, -- for example, only printing some text if it's to the terminal, but not -- if it's to a file or vice-versa. invisiblePrinter :: Printer simplePrinter x = unDoc $ doc (\s -> x:s) invisiblePrinter _ = unDoc empty infixr 6 <> infixr 6 <+> infixr 5 $$ -- | The empty 'Doc'. empty :: Doc empty = Doc $ const Empty doc :: ([Printable] -> [Printable]) -> Doc doc f = Doc $ const $ Document f -- | '(<>)' is the concatenation operator for 'Doc's (<>) :: Doc -> Doc -> Doc -- | @a '' b@ is @a <> b@ if @a@ is not empty, else empty. () :: Doc -> Doc -> Doc -- | @a '<+>' b@ is @a@ followed by a space, then @b@. (<+>) :: Doc -> Doc -> Doc -- | @a '$$' b@ is @a@ above @b@. ($$) :: Doc -> Doc -> Doc -- a then b Doc a <> Doc b = Doc $ \st -> case a st of Empty -> b st Document af -> Document (\s -> af $ case b st of Empty -> s Document bf -> bf s) -- empty if a empty, else a then b Doc a Doc b = Doc $ \st -> case a st of Empty -> Empty Document af -> Document (\s -> af $ case b st of Empty -> s Document bf -> bf s) -- a then space then b Doc a <+> Doc b = Doc $ \st -> case a st of Empty -> b st Document af -> Document (\s -> af $ case b st of Empty -> s Document bf -> spaceP:bf s) -- a above b Doc a $$ Doc b = Doc $ \st -> case a st of Empty -> b st Document af -> Document (\s -> af $ case b st of Empty -> s Document bf -> sf (newlineP:pf (bf s))) where pf = currentPrefix st sf = lineColorS $ printers st -- | 'vcat' piles vertically a list of 'Doc's. vcat :: [Doc] -> Doc vcat [] = empty vcat ds = foldr1 ($$) ds -- | 'vsep' piles vertically a list of 'Doc's leaving a blank line between each. vsep :: [Doc] -> Doc vsep [] = empty vsep ds = foldr1 ($$) $ intersperse (text "") ds -- | 'hcat' concatenates (horizontally) a list of 'Doc's hcat :: [Doc] -> Doc hcat [] = empty hcat ds = foldr1 (<>) ds \end{code} darcs-2.8.4/src/Progress.hs0000644001765600176560000002041312104371431015070 0ustar ganeshganesh{-# LANGUAGE CPP #-} #include "gadts.h" -- | -- Module : Progress -- Copyright : 2008 David Roundy -- License : GPL -- Maintainer : darcs-devel@darcs.net -- Stability : experimental -- Portability : portable -- -- Utility functions for tracking progress of long-running actions. module Progress ( beginTedious , endTedious , tediousSize , debugMessage , debugFail , withoutProgress , progress , progressKeepLatest , finishedOne , finishedOneIO , progressList , minlist , setProgressMode ) where import Prelude hiding (lookup) import Control.Exception.Extensible ( onException ) import Control.Monad ( when ) import Control.Concurrent ( forkIO, threadDelay ) import Data.Char ( toLower ) import Data.Map ( Map, empty, adjust, insert, delete, lookup ) import Data.Maybe ( isJust ) import Data.IORef ( IORef, newIORef, readIORef, writeIORef, modifyIORef ) import System.IO ( stdout, stderr, hFlush, hPutStr, hPutStrLn, hSetBuffering, hIsTerminalDevice, Handle, BufferMode(LineBuffering) ) import System.IO.Unsafe ( unsafePerformIO ) import Darcs.Global ( withDebugMode, debugMessage, putTiming, debugFail ) data ProgressData = ProgressData { sofar :: !Int , latest :: !(Maybe String) , total :: !(Maybe Int) } handleProgress :: IO () handleProgress = do threadDelay 1000000 handleMoreProgress "" 0 handleMoreProgress :: String -> Int -> IO () handleMoreProgress k n = withProgressMode $ \m -> if m then do s <- getProgressLast mp <- getProgressData s case mp of Nothing -> do threadDelay 1000000 handleMoreProgress k n Just p -> do when (k /= s || n < sofar p) $ whenProgressMode $ printProgress s p threadDelay 1000000 handleMoreProgress s (sofar p) else do threadDelay 1000000 handleMoreProgress k n printProgress :: String -> ProgressData -> IO () printProgress k (ProgressData {sofar=s, total=Just t, latest=Just l}) = myput output output where output = k ++ " " ++ show s ++ " done, " ++ show (t - s) ++ " queued. " ++ l printProgress k (ProgressData {latest=Just l}) = myput (k ++ " " ++ l) k printProgress k (ProgressData {sofar=s, total=Just t}) | t >= s = myput (k ++ " " ++ show s ++ " done, " ++ show (t - s) ++ " queued") (k ++ " " ++ show s) printProgress k (ProgressData {sofar=s}) = myput (k ++ " " ++ show s) k myput :: String -> String -> IO () myput l s = withDebugMode $ \debugMode -> if debugMode then putTiming >> hPutStrLn stderr l else if '\n' `elem` l then myput (takeWhile (/= '\n') l) s else putTiming >> if length l < 80 then simpleput l else simpleput (take 80 s) simpleput :: String -> IO () simpleput = unsafePerformIO $ mkhPutCr stderr {-# NOINLINE simpleput #-} -- | @beginTedious k@ starts a tedious process and registers it in -- '_progressData' with the key @k@. A tedious process is one for which we want -- a progress indicator. -- -- Wouldn't it be safer if it had type String -> IO ProgressDataKey, so that we -- can ensure there is no collision? What happens if you call beginTedious twice -- with the same string, without calling endTedious in the meantime? beginTedious :: String -> IO () beginTedious k = do debugMessage $ "Beginning " ++ map toLower k setProgressData k $ ProgressData { sofar = 0 , latest = Nothing , total = Nothing } -- | @endTedious k@ unregisters the tedious process with key @k@, printing -- "Done" if such a tedious process exists. endTedious :: String -> IO () endTedious k = whenProgressMode $ do p <- getProgressData k modifyIORef _progressData (\(a,m) -> (a,delete k m)) when (isJust p) $ debugMessage $ "Done " ++ (map toLower k) tediousSize :: String -> Int -> IO () tediousSize k s = updateProgressData k uptot where uptot p = case total p of Just t -> seq ts $ p { total = Just ts } where ts = t + s Nothing -> p { total = Just s } -- | XXX: document this constant minlist :: Int minlist = 4 progressList :: String -> [a] -> [a] progressList _ [] = [] progressList k (x:xs) = if l < minlist then x:xs else startit x : pl xs where l = length (x:xs) startit y = unsafePerformIO $ do beginTedious k tediousSize k l return y pl [] = [] pl [y] = unsafePerformIO $ do endTedious k return [y] pl (y:ys) = progress k y : pl ys progress :: String -> a -> a progress k a = unsafePerformIO $ progressIO k >> return a progressIO :: String -> IO () progressIO "" = return () progressIO k = do updateProgressData k $ \p -> p { sofar = sofar p + 1, latest = Nothing } putDebug k "" progressKeepLatest :: String -> a -> a progressKeepLatest k a = unsafePerformIO $ progressKeepLatestIO k >> return a progressKeepLatestIO :: String -> IO () progressKeepLatestIO "" = return () progressKeepLatestIO k = do updateProgressData k (\p -> p {sofar = sofar p + 1}) putDebug k "" finishedOne :: String -> String -> a -> a finishedOne k l a = unsafePerformIO $ finishedOneIO k l >> return a finishedOneIO :: String -> String -> IO () finishedOneIO "" _ = return () finishedOneIO k l = do updateProgressData k (\p -> p { sofar = sofar p + 1, latest = Just l }) putDebug k l putDebug :: String -> String -> IO () putDebug _ _ = return () --putDebug k "" = when (False && debugMode) $ hPutStrLn stderr $ "P: "++k --putDebug k l = when (False && debugMode) $ hPutStrLn stderr $ "P: "++k++" : "++l _progressMode :: IORef Bool _progressMode = unsafePerformIO $ do hSetBuffering stderr LineBuffering newIORef True {-# NOINLINE _progressMode #-} _progressData :: IORef (String, Map String ProgressData) _progressData = unsafePerformIO $ do _ <- forkIO handleProgress newIORef ("", empty) {-# NOINLINE _progressData #-} mkhPutCr :: Handle -> IO (String -> IO ()) mkhPutCr fe = do isTerm <- hIsTerminalDevice fe stdoutIsTerm <- hIsTerminalDevice stdout return $ if isTerm then \s -> do hPutStr fe $ '\r':s ++ "\r" hFlush fe let spaces = '\r':replicate (length s) ' ' ++ "\r" hPutStr fe spaces when stdoutIsTerm $ hPutStr stdout spaces else \s -> when (not $ null s) $ do hPutStrLn fe s hFlush fe setProgressMode :: Bool -> IO () setProgressMode m = writeIORef _progressMode m withoutProgress :: IO a -> IO a withoutProgress j = withProgressMode $ \m -> do debugMessage "Disabling progress reports..." setProgressMode False a <- j `onException` setProgressMode m if m then debugMessage "Reenabling progress reports." else debugMessage "Leaving progress reports off." setProgressMode m return a updateProgressData :: String -> (ProgressData -> ProgressData) -> IO () updateProgressData k f = whenProgressMode $ modifyIORef _progressData (\(_,m) -> (k,adjust f k m)) setProgressData :: String -> ProgressData -> IO () setProgressData k p = whenProgressMode $ modifyIORef _progressData (\(a,m) -> (a,insert k p m)) getProgressData :: String -> IO (Maybe ProgressData) getProgressData k = withProgressMode $ \p -> if p then (lookup k . snd) `fmap` readIORef _progressData else return Nothing getProgressLast :: IO String getProgressLast = withProgressMode $ \p -> if p then fst `fmap` readIORef _progressData else return "" whenProgressMode :: IO a -> IO () whenProgressMode j = withProgressMode $ const $ j >> return () withProgressMode :: (Bool -> IO a) -> IO a withProgressMode j = readIORef _progressMode >>= j darcs-2.8.4/src/Ratified.hs0000644001765600176560000000023012104371431015006 0ustar ganeshganesh-- | XXX: Perhaps a word of explanation here [WL] module Ratified ( readFile , hGetContents ) where import System.IO( hGetContents ) darcs-2.8.4/src/SHA1.hs0000644001765600176560000002202312104371431013757 0ustar ganeshganesh-- Copyright (C) 2001, 2004 Ian Lynagh -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. -- name shadowing disabled because a,b,c,d,e are shadowed loads in step 4 {-# OPTIONS_GHC -fno-warn-name-shadowing #-} {-# LANGUAGE CPP #-} -- | -- Module : SHA1 -- Copyright : 2001, 2004 Ian Lynagh -- License : GPL -- Maintainer : darcs-devel@darcs.net -- Stability : experimental -- Portability : portable module SHA1 (sha1PS) where import ByteStringUtils (unsafeWithInternals) import qualified Data.ByteString as B (ByteString, pack, length, concat) import Data.Char (intToDigit) import Data.Bits (xor, (.&.), (.|.), complement, rotateL, shiftL, shiftR) import Data.Word (Word8, Word32) import Foreign.Ptr (Ptr, castPtr) import Foreign.Marshal.Array (advancePtr) import Foreign.Storable (peek, poke) import System.IO.Unsafe (unsafePerformIO) data ABCDE = ABCDE !Word32 !Word32 !Word32 !Word32 !Word32 data XYZ = XYZ !Word32 !Word32 !Word32 sha1PS :: B.ByteString -> String sha1PS s = s5 where s1_2 = sha1Step12PadLength s abcde = sha1Step3Init abcde' = unsafePerformIO $ unsafeWithInternals s1_2 (\ptr len -> do let ptr' = castPtr ptr #ifndef BIGENDIAN fiddleEndianness ptr' len #endif sha1Step4Main abcde ptr' len) s5 = sha1Step5Display abcde' fiddleEndianness :: Ptr Word32 -> Int -> IO () fiddleEndianness p 0 = p `seq` return () fiddleEndianness p n = do x <- peek p poke p $ shiftL x 24 .|. shiftL (x .&. 0xff00) 8 .|. (shiftR x 8 .&. 0xff00) .|. shiftR x 24 fiddleEndianness (p `advancePtr` 1) (n - 4) -- sha1Step12PadLength assumes the length is at most 2^61. -- This seems reasonable as the Int used to represent it is normally 32bit, -- but obviously could go wrong with large inputs on 64bit machines. -- The B.ByteString library should probably move to Word64s if this is an -- issue, though. sha1Step12PadLength :: B.ByteString -> B.ByteString sha1Step12PadLength s = let len = B.length s num_nuls = (55 - len) `mod` 64 padding = 128:replicate num_nuls 0 len_w8s = reverse $ sizeSplit 8 (fromIntegral len*8) in B.concat [s, B.pack padding, B.pack len_w8s] sizeSplit :: Int -> Integer -> [Word8] sizeSplit 0 _ = [] sizeSplit p n = fromIntegral d:sizeSplit (p-1) n' where (n', d) = divMod n 256 sha1Step3Init :: ABCDE sha1Step3Init = ABCDE 0x67452301 0xefcdab89 0x98badcfe 0x10325476 0xc3d2e1f0 sha1Step4Main :: ABCDE -> Ptr Word32 -> Int -> IO ABCDE sha1Step4Main abcde _ 0 = return $! abcde sha1Step4Main (ABCDE a0@a b0@b c0@c d0@d e0@e) s len = do (e, b) <- doit f1 0x5a827999 (x 0) a b c d e (d, a) <- doit f1 0x5a827999 (x 1) e a b c d (c, e) <- doit f1 0x5a827999 (x 2) d e a b c (b, d) <- doit f1 0x5a827999 (x 3) c d e a b (a, c) <- doit f1 0x5a827999 (x 4) b c d e a (e, b) <- doit f1 0x5a827999 (x 5) a b c d e (d, a) <- doit f1 0x5a827999 (x 6) e a b c d (c, e) <- doit f1 0x5a827999 (x 7) d e a b c (b, d) <- doit f1 0x5a827999 (x 8) c d e a b (a, c) <- doit f1 0x5a827999 (x 9) b c d e a (e, b) <- doit f1 0x5a827999 (x 10) a b c d e (d, a) <- doit f1 0x5a827999 (x 11) e a b c d (c, e) <- doit f1 0x5a827999 (x 12) d e a b c (b, d) <- doit f1 0x5a827999 (x 13) c d e a b (a, c) <- doit f1 0x5a827999 (x 14) b c d e a (e, b) <- doit f1 0x5a827999 (x 15) a b c d e (d, a) <- doit f1 0x5a827999 (m 16) e a b c d (c, e) <- doit f1 0x5a827999 (m 17) d e a b c (b, d) <- doit f1 0x5a827999 (m 18) c d e a b (a, c) <- doit f1 0x5a827999 (m 19) b c d e a (e, b) <- doit f2 0x6ed9eba1 (m 20) a b c d e (d, a) <- doit f2 0x6ed9eba1 (m 21) e a b c d (c, e) <- doit f2 0x6ed9eba1 (m 22) d e a b c (b, d) <- doit f2 0x6ed9eba1 (m 23) c d e a b (a, c) <- doit f2 0x6ed9eba1 (m 24) b c d e a (e, b) <- doit f2 0x6ed9eba1 (m 25) a b c d e (d, a) <- doit f2 0x6ed9eba1 (m 26) e a b c d (c, e) <- doit f2 0x6ed9eba1 (m 27) d e a b c (b, d) <- doit f2 0x6ed9eba1 (m 28) c d e a b (a, c) <- doit f2 0x6ed9eba1 (m 29) b c d e a (e, b) <- doit f2 0x6ed9eba1 (m 30) a b c d e (d, a) <- doit f2 0x6ed9eba1 (m 31) e a b c d (c, e) <- doit f2 0x6ed9eba1 (m 32) d e a b c (b, d) <- doit f2 0x6ed9eba1 (m 33) c d e a b (a, c) <- doit f2 0x6ed9eba1 (m 34) b c d e a (e, b) <- doit f2 0x6ed9eba1 (m 35) a b c d e (d, a) <- doit f2 0x6ed9eba1 (m 36) e a b c d (c, e) <- doit f2 0x6ed9eba1 (m 37) d e a b c (b, d) <- doit f2 0x6ed9eba1 (m 38) c d e a b (a, c) <- doit f2 0x6ed9eba1 (m 39) b c d e a (e, b) <- doit f3 0x8f1bbcdc (m 40) a b c d e (d, a) <- doit f3 0x8f1bbcdc (m 41) e a b c d (c, e) <- doit f3 0x8f1bbcdc (m 42) d e a b c (b, d) <- doit f3 0x8f1bbcdc (m 43) c d e a b (a, c) <- doit f3 0x8f1bbcdc (m 44) b c d e a (e, b) <- doit f3 0x8f1bbcdc (m 45) a b c d e (d, a) <- doit f3 0x8f1bbcdc (m 46) e a b c d (c, e) <- doit f3 0x8f1bbcdc (m 47) d e a b c (b, d) <- doit f3 0x8f1bbcdc (m 48) c d e a b (a, c) <- doit f3 0x8f1bbcdc (m 49) b c d e a (e, b) <- doit f3 0x8f1bbcdc (m 50) a b c d e (d, a) <- doit f3 0x8f1bbcdc (m 51) e a b c d (c, e) <- doit f3 0x8f1bbcdc (m 52) d e a b c (b, d) <- doit f3 0x8f1bbcdc (m 53) c d e a b (a, c) <- doit f3 0x8f1bbcdc (m 54) b c d e a (e, b) <- doit f3 0x8f1bbcdc (m 55) a b c d e (d, a) <- doit f3 0x8f1bbcdc (m 56) e a b c d (c, e) <- doit f3 0x8f1bbcdc (m 57) d e a b c (b, d) <- doit f3 0x8f1bbcdc (m 58) c d e a b (a, c) <- doit f3 0x8f1bbcdc (m 59) b c d e a (e, b) <- doit f2 0xca62c1d6 (m 60) a b c d e (d, a) <- doit f2 0xca62c1d6 (m 61) e a b c d (c, e) <- doit f2 0xca62c1d6 (m 62) d e a b c (b, d) <- doit f2 0xca62c1d6 (m 63) c d e a b (a, c) <- doit f2 0xca62c1d6 (m 64) b c d e a (e, b) <- doit f2 0xca62c1d6 (m 65) a b c d e (d, a) <- doit f2 0xca62c1d6 (m 66) e a b c d (c, e) <- doit f2 0xca62c1d6 (m 67) d e a b c (b, d) <- doit f2 0xca62c1d6 (m 68) c d e a b (a, c) <- doit f2 0xca62c1d6 (m 69) b c d e a (e, b) <- doit f2 0xca62c1d6 (m 70) a b c d e (d, a) <- doit f2 0xca62c1d6 (m 71) e a b c d (c, e) <- doit f2 0xca62c1d6 (m 72) d e a b c (b, d) <- doit f2 0xca62c1d6 (m 73) c d e a b (a, c) <- doit f2 0xca62c1d6 (m 74) b c d e a (e, b) <- doit f2 0xca62c1d6 (m 75) a b c d e (d, a) <- doit f2 0xca62c1d6 (m 76) e a b c d (c, e) <- doit f2 0xca62c1d6 (m 77) d e a b c (b, d) <- doit f2 0xca62c1d6 (m 78) c d e a b (a, c) <- doit f2 0xca62c1d6 (m 79) b c d e a let abcde' = ABCDE (a0 + a) (b0 + b) (c0 + c) (d0 + d) (e0 + e) sha1Step4Main abcde' (s `advancePtr` 16) (len - 64) where {-# INLINE f1 #-} f1 (XYZ x y z) = (x .&. y) .|. ((complement x) .&. z) {-# INLINE f2 #-} f2 (XYZ x y z) = x `xor` y `xor` z {-# INLINE f3 #-} f3 (XYZ x y z) = (x .&. y) .|. (x .&. z) .|. (y .&. z) {-# INLINE x #-} x n = peek (s `advancePtr` n) {-# INLINE m #-} m n = do let base = s `advancePtr` (n .&. 15) x0 <- peek base x1 <- peek (s `advancePtr` ((n - 14) .&. 15)) x2 <- peek (s `advancePtr` ((n - 8) .&. 15)) x3 <- peek (s `advancePtr` ((n - 3) .&. 15)) let res = rotateL (x0 `xor` x1 `xor` x2 `xor` x3) 1 poke base res return res {-# INLINE doit #-} doit f k i a b c d e = a `seq` c `seq` do i' <- i return (rotateL a 5 + f (XYZ b c d) + e + i' + k, rotateL b 30) sha1Step5Display :: ABCDE -> String sha1Step5Display (ABCDE a b c d e) = concatMap showAsHex [a, b, c, d, e] showAsHex :: Word32 -> String showAsHex n = showIt 8 n "" where showIt :: Int -> Word32 -> String -> String showIt 0 _ r = r showIt i x r = case quotRem x 16 of (y, z) -> let c = intToDigit (fromIntegral z) in c `seq` showIt (i-1) y (c:r) darcs-2.8.4/src/URL.hs0000644001765600176560000003146512104371431013737 0ustar ganeshganesh{-# LANGUAGE CPP, ForeignFunctionInterface #-} -- | -- Module : URL -- Copyright : 2008 Dmitry Kurochkin -- License : GPL -- Maintainer : darcs-devel@darcs.net -- Stability : experimental -- Portability : portable module URL ( copyUrl, copyUrlFirst, setDebugHTTP, disableHTTPPipelining, maxPipelineLength, waitUrl, Cachable(Cachable, Uncachable, MaxAge), environmentHelpProxy, environmentHelpProxyPassword, ConnectionError(..), ) where import Data.IORef ( newIORef, readIORef, writeIORef, IORef ) import Data.Map ( Map ) import qualified Data.Map as Map import System.Directory ( copyFile ) import System.IO.Unsafe ( unsafePerformIO ) import Control.Concurrent ( forkIO ) import Control.Concurrent.Chan ( isEmptyChan, newChan, readChan, writeChan, Chan ) import Control.Concurrent.MVar ( isEmptyMVar, modifyMVar_, newEmptyMVar, newMVar, putMVar, readMVar, withMVar, MVar ) import Control.Monad ( unless, when ) import Control.Monad.Trans ( liftIO ) import Control.Monad.State ( evalStateT, get, modify, put, StateT ) import Workaround ( renameFile ) import Darcs.Global ( atexit ) import Progress ( debugMessage ) import Darcs.Lock ( removeFileMayNotExist ) import Numeric ( showHex ) import System.Random ( randomRIO ) import URL.Request #ifdef HAVE_CURL import qualified URL.Curl as Curl #elif defined(HAVE_HTTP) import qualified URL.HTTP as HTTP #else import Progress ( debugFail ) import qualified HTTP ( requestUrl, waitNextUrl ) #endif #include "impossible.h" {-# NOINLINE maxPipelineLengthRef #-} maxPipelineLengthRef :: IORef Int maxPipelineLengthRef = unsafePerformIO $ do enabled <- pipeliningEnabled #ifdef HAVE_CURL when (not enabled) (debugMessage $ "Warning: pipelining is disabled, because libcurl "++ "version darcs was compiled with is too old (< 7.19.1)") #endif newIORef $ if enabled then 100 else 1 maxPipelineLength :: IO Int maxPipelineLength = readIORef maxPipelineLengthRef {-# NOINLINE urlNotifications #-} urlNotifications :: MVar (Map String (MVar String)) urlNotifications = unsafePerformIO $ newMVar Map.empty {-# NOINLINE urlChan #-} urlChan :: Chan UrlRequest urlChan = unsafePerformIO $ do ch <- newChan -- Warning: A do-notation statement discarded a result of type GHC.Conc.ThreadId. _ <- forkIO (urlThread ch) return ch -- ---------------------------------------------------------------------- -- urlThread -- ---------------------------------------------------------------------- type UrlM a = StateT UrlState IO a urlThread :: Chan UrlRequest -> IO () urlThread ch = do junk <- flip showHex "" `fmap` randomRIO rrange evalStateT (urlThread' ch) (UrlState Map.empty emptyQ 0 junk) where rrange = (0, 2^(128 :: Integer) :: Integer) -- | Internal to urlThread urlThread' :: Chan UrlRequest -> UrlM () urlThread' ch = do empty <- liftIO $ isEmptyChan ch st <- get let l = pipeLength st w = waitToStart st reqs <- if not empty || (nullQ w && l == 0) then liftIO (readAllRequests ch) else return [] mapM_ addReq reqs checkWaitToStart waitNextUrl urlThread' ch -- | Internal to urlThread readAllRequests :: Chan UrlRequest -> IO [UrlRequest] readAllRequests ch = do r <- readChan ch debugMessage $ "URL.urlThread ("++url r++"\n"++ " -> "++file r++")" empty <- isEmptyChan ch reqs <- if not empty then readAllRequests ch else return [] return (r:reqs) -- | Internal to urlThread addReq :: UrlRequest -> UrlM () addReq r = do d <- liftIO (alreadyDownloaded u) if d then dbg "Ignoring UrlRequest of URL that is already downloaded." else reallyAdd where f = file r c = cachable r u = url r reallyAdd = do st <- get let p = inProgress st w = waitToStart st e = (f, [], c) new_w = case priority r of High -> pushQ u w Low -> insertQ u w new_st = st { inProgress = Map.insert u e p , waitToStart = new_w } case Map.lookup u p of Just (f', fs', c') -> do let new_c = minCachable c c' when (c /= c') $ let new_p = Map.insert u (f', fs', new_c) p in do modify (\s -> s { inProgress = new_p }) dbg $ "Changing "++u++" request cachability from "++show c++" to "++show new_c when (u `elemQ` w && priority r == High) $ do modify (\s -> s { waitToStart = pushQ u (deleteQ u w) }) dbg $ "Moving "++u++" to head of download queue." if f `notElem` (f':fs') then let new_p = Map.insert u (f', f:fs', new_c) p in do modify (\s -> s { inProgress = new_p }) dbg "Adding new file to existing UrlRequest." else dbg "Ignoring UrlRequest of file that's already queued." _ -> put new_st -- | Internal to urlThread alreadyDownloaded :: String -> IO Bool alreadyDownloaded u = do n <- withMVar urlNotifications (return . (Map.lookup u)) case n of Just v -> not `fmap` isEmptyMVar v Nothing -> return True -- ---------------------------------------------------------------------- checkWaitToStart :: StateT UrlState IO () checkWaitToStart = do st <- get let l = pipeLength st mpl <- liftIO maxPipelineLength when (l < mpl) $ do let w = waitToStart st case readQ w of Just (u,rest) -> do case Map.lookup u (inProgress st) of Just (f, _, c) -> do dbg ("URL.requestUrl ("++u++"\n"++ " -> "++f++")") let f_new = f++"-new_"++randomJunk st err <- liftIO $ requestUrl u f_new c if null err then do liftIO $ atexit (removeFileMayNotExist f_new) put $ st { waitToStart = rest , pipeLength = l + 1 } else do dbg $ "Failed to start download URL "++u++": "++err liftIO $ do removeFileMayNotExist f_new downloadComplete u err put $ st { waitToStart = rest } _ -> bug $ "Possible bug in URL.checkWaitToStart "++u checkWaitToStart _ -> return () copyUrlFirst :: String -> FilePath -> Cachable -> IO () copyUrlFirst = copyUrlWithPriority High copyUrl :: String -> FilePath -> Cachable -> IO () copyUrl = copyUrlWithPriority Low copyUrlWithPriority :: Priority -> String -> String -> Cachable -> IO () copyUrlWithPriority p u f c = do debugMessage ("URL.copyUrlWithPriority ("++u++"\n"++ " -> "++f++")") v <- newEmptyMVar let fn _ old_val = old_val modifyMVar_ urlNotifications (return . (Map.insertWith fn u v)) let r = UrlRequest u f c p writeChan urlChan r waitNextUrl :: StateT UrlState IO () waitNextUrl = do st <- get let l = pipeLength st when (l > 0) $ do dbg "URL.waitNextUrl start" (u, e, ce) <- liftIO $ waitNextUrl' let p = inProgress st new_st = st { inProgress = Map.delete u p , pipeLength = l - 1 } liftIO $ if null e then case Map.lookup u p of Just (f, fs, _) -> do renameFile (f++"-new_"++randomJunk st) f mapM_ (safeCopyFile st f) fs downloadComplete u e debugMessage $ "URL.waitNextUrl succeeded: "++u++" "++f Nothing -> bug $ "Possible bug in URL.waitNextUrl: "++u else case Map.lookup u p of Just (f, _, _) -> do removeFileMayNotExist (f++"-new_"++randomJunk st) case ce of Just httpError -> downloadComplete u (show httpError) Nothing -> downloadComplete u e debugMessage $ "URL.waitNextUrl failed: "++ u++" "++f++" "++e Nothing -> bug $ "Another possible bug in URL.waitNextUrl: "++u++" "++e unless (null u) $ put new_st where safeCopyFile st f t = let new_t = t++"-new_"++randomJunk st in do copyFile f new_t renameFile new_t t downloadComplete :: String -> String -> IO () downloadComplete u e = do r <- withMVar urlNotifications (return . (Map.lookup u)) case r of Just notifyVar -> putMVar notifyVar e Nothing -> debugMessage $ "downloadComplete URL '"++u++"' downloaded several times" waitUrl :: String -> IO () waitUrl u = do debugMessage $ "URL.waitUrl "++u r <- withMVar urlNotifications (return . (Map.lookup u)) case r of Just var -> do e <- readMVar var modifyMVar_ urlNotifications (return . (Map.delete u)) unless (null e) $ do debugMessage $ "Failed to download URL "++u++": "++e fail e Nothing -> return () -- file was already downloaded dbg :: String -> StateT a IO () dbg = liftIO . debugMessage minCachable :: Cachable -> Cachable -> Cachable minCachable Uncachable _ = Uncachable minCachable _ Uncachable = Uncachable minCachable (MaxAge a) (MaxAge b) = MaxAge $ min a b minCachable (MaxAge a) _ = MaxAge a minCachable _ (MaxAge b) = MaxAge b minCachable _ _ = Cachable disableHTTPPipelining :: IO () disableHTTPPipelining = writeIORef maxPipelineLengthRef 1 setDebugHTTP :: IO () requestUrl :: String -> FilePath -> Cachable -> IO String waitNextUrl' :: IO (String, String, Maybe ConnectionError) pipeliningEnabled :: IO Bool #ifdef HAVE_CURL setDebugHTTP = Curl.setDebugHTTP requestUrl = Curl.requestUrl waitNextUrl' = Curl.waitNextUrl pipeliningEnabled = Curl.pipeliningEnabled #elif defined(HAVE_HTTP) setDebugHTTP = return () requestUrl = HTTP.requestUrl waitNextUrl' = HTTP.waitNextUrl pipeliningEnabled = return False #else setDebugHTTP = debugMessage "URL.setDebugHttp works only with libcurl" requestUrl _ _ _ = debugFail "URL.requestUrl: there is no libcurl!" waitNextUrl' = debugFail "URL.waitNextUrl': there is no libcurl!" pipeliningEnabled = return False #endif -- Usage of these environment variables happens in C code, so the -- closest to "literate" user documentation is here, where the -- offending function 'curl_request_url' is imported. environmentHelpProxy :: ([String], [String]) environmentHelpProxy = (["HTTP_PROXY", "HTTPS_PROXY", "FTP_PROXY", "ALL_PROXY", "NO_PROXY"], [ "If Darcs was built with libcurl, the environment variables HTTP_PROXY,", "HTTPS_PROXY and FTP_PROXY can be set to the URL of a proxy in the form", "", " [protocol://][:port]", "", "In which case libcurl will use the proxy for the associated protocol", "(HTTP, HTTPS and FTP). The environment variable ALL_PROXY can be used", "to set a single proxy for all libcurl requests.", "", "If the environment variable NO_PROXY is a comma-separated list of host", "names, access to those hosts will bypass proxies defined by the above", "variables. For example, it is quite common to avoid proxying requests", "to machines on the local network with", "", " NO_PROXY=localhost,*.localdomain", "", "For compatibility with lynx et al, lowercase equivalents of these", "environment variables (e.g. $http_proxy) are also understood and are", "used in preference to the uppercase versions.", "", "If Darcs was not built with libcurl, all these environment variables", "are silently ignored, and there is no way to use a web proxy."]) environmentHelpProxyPassword :: ([String], [String]) environmentHelpProxyPassword = (["DARCS_PROXYUSERPWD"], [ "If Darcs was built with libcurl, and you are using a web proxy that", "requires authentication, you can set the $DARCS_PROXYUSERPWD", "environment variable to the username and password expected by the", "proxy, separated by a colon. This environment variable is silently", "ignored if Darcs was not built with libcurl."]) darcs-2.8.4/src/Workaround.hs0000644001765600176560000000723012104371431015421 0ustar ganeshganesh{-# LANGUAGE CPP #-} -- | -- Module : Workaround -- Copyright : 2008 David Roundy -- License : GPL -- Maintainer : darcs-devel@darcs.net -- Stability : experimental -- Portability : portable module Workaround ( renameFile , setExecutable , getCurrentDirectory , installHandler , raiseSignal , Handler(..) , Signal , sigINT , sigHUP , sigABRT , sigALRM , sigTERM , sigPIPE ) where import Prelude hiding ( catch ) #ifdef WIN32 import qualified System.Directory ( renameFile, getCurrentDirectory, removeFile ) import Control.Exception ( catch, IOException ) import qualified Control.Exception ( block ) import qualified System.IO.Error ( isDoesNotExistError, ioError ) #else import System.Posix.Signals(installHandler, raiseSignal, Handler(..), Signal, sigINT, sigHUP, sigABRT, sigALRM, sigTERM, sigPIPE) import System.Directory ( renameFile, getCurrentDirectory ) import System.Posix.Files (fileMode,getFileStatus, setFileMode, setFileCreationMask, ownerReadMode, ownerWriteMode, ownerExecuteMode, groupReadMode, groupWriteMode, groupExecuteMode, otherReadMode, otherWriteMode, otherExecuteMode) import Data.Bits ( (.&.), (.|.), complement ) #endif #ifdef WIN32 -- Dummy implementation of POSIX signals data Handler = Default | Ignore | Catch (IO ()) type Signal = Int installHandler :: Signal -> Handler -> Maybe () -> IO () installHandler _ _ _ = return () raiseSignal :: Signal -> IO () raiseSignal _ = return () sigINT :: Signal sigINT = 0 -- not used: sigKILL = 0 sigHUP :: Signal sigHUP = 0 -- not used: sigQUIT = 0 sigABRT :: Signal sigABRT = 0 sigTERM :: Signal sigTERM = 0 sigPIPE :: Signal sigPIPE = 0 sigALRM :: Signal sigALRM = 0 -- | System.Directory.renameFile incorrectly fails when the new file already -- exists. This code works around that bug at the cost of losing atomic -- writes. renameFile :: FilePath -> FilePath -> IO () renameFile old new = Control.Exception.block $ System.Directory.renameFile old new `catch` \(_ :: IOException) -> do System.Directory.removeFile new `catch` (\e -> if System.IO.Error.isDoesNotExistError e then return () else System.IO.Error.ioError e) System.Directory.renameFile old new setExecutable :: FilePath -> Bool -> IO () setExecutable _ _ = return () -- | System.Directory.getCurrentDirectory returns a path with backslashes in it -- under windows, and some of the code gets confused by that, so we override -- getCurrentDirectory and translates '\\' to '/' getCurrentDirectory :: IO FilePath getCurrentDirectory = do d <- System.Directory.getCurrentDirectory return $ map rb d where rb '\\' = '/' rb c = c #else setExecutable :: FilePath -> Bool -> IO () setExecutable f ex = do st <- getFileStatus f umask <- setFileCreationMask 0 -- Warning: A do-notation statement discarded a result of type System.Posix.Types.FileMode. _ <- setFileCreationMask umask let rw = fileMode st .&. (ownerReadMode .|. ownerWriteMode .|. groupReadMode .|. groupWriteMode .|. otherReadMode .|. otherWriteMode) total = if ex then rw .|. ((ownerExecuteMode .|. groupExecuteMode .|. otherExecuteMode) .&. complement umask) else rw setFileMode f total #endif darcs-2.8.4/src/atomic_create.c0000644001765600176560000001113412104371431015673 0ustar ganeshganesh/* Copyright (C) 2005 Juliusz Chroboczek 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, 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; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #ifdef _WIN32 #include #include #endif int sloppy_atomic_create(const char *p) { int fd; fd = open(p, O_WRONLY | O_EXCL | O_CREAT, 0666); if(fd < 0) return -1; close(fd); return 1; } #ifdef _WIN32 int atomic_create(const char *p) { return sloppy_atomic_create(p); } #else static int careful_atomic_create(const char *p) { /* O_EXCL is not available over NFSv2, and even under NFSv3, it is broken on many systems. The following protocol is provably safe assuming that: - creation of hard links is atomic; - stat hits the server rather than working from the cache. */ static char hostname[65] = {'\0'}; int fd, rc, saved_errno; #define FILENAME_SIZE (11 + 15 + 8 + 1) char *filename; char *lastslash; int dirlen; struct timeval now; struct stat sb; if(hostname[0] == '\0') { char *c; int i; /* POSIX guarantees 65 is enough. */ rc = gethostname(hostname, 65); if(rc < 0 || rc >= 65) { fprintf(stderr, "Error reading hostname when locking.\n"); strcpy(hostname, "kremvax"); } c = strchr(hostname, '.'); if(c != NULL) *c = '\0'; hostname[15] = '\0'; /* clean up a few possible nasty characters folks might put in their hostname */ for (i=0;i<15;i++) if (hostname[i] == ':' || hostname[i] == '/' || hostname[i] == '\\') hostname[i] = '-'; } lastslash = strrchr(p, '/'); dirlen = lastslash ? lastslash - p + 1 : 0; filename = malloc(dirlen + FILENAME_SIZE); if(filename == NULL) return -1; if(dirlen > 0) memcpy(filename, p, dirlen); filename[dirlen] = '\0'; gettimeofday(&now, NULL); rc = snprintf(filename + dirlen, FILENAME_SIZE, "darcs_lock_%s%04x%04x", hostname, ((unsigned)getpid()) & 0xFFFF, ((unsigned)(now.tv_usec ^ (now.tv_usec >> 16))) & 0xFFFF); if(rc < 0 || rc >= FILENAME_SIZE) { fprintf(stderr, "Error writing to lock filename (%d)\n", rc < 0 ? errno : 0); goto fail2; } fd = open(filename, O_WRONLY | O_EXCL | O_CREAT, 0666); if(fd < 0) goto fail2; /* Paranoia: should cause the client to flush its metadata cache. */ rc = close(fd); if(rc < 0) { fprintf(stderr, "Error closing file %s. (%d)\n", filename, errno); goto fail; } rc = link(filename, p); if(rc >= 0) goto success; else if(errno == EPERM || errno == EOPNOTSUPP) { /* Linux returns EPERM when making hard links on filesystems that don't support them. */ /* It seems that MacOS returns EOPNOTSUPP on filesystems that don't support hard links. */ unlink(filename); free(filename); return sloppy_atomic_create(p); } else if(errno != EEXIST && errno != EIO) goto fail; /* The link may still have been successful if we're running over UDP and got EEXIST or EIO. Check the file's link count. */ rc = stat(filename, &sb); if(rc < 0) { goto fail; } if(sb.st_nlink != 2) { errno = EEXIST; goto fail; } success: unlink(filename); free(filename); return 1; fail: saved_errno = errno; unlink(filename); errno = saved_errno; fail2: free(filename); return -1; } int atomic_create(const char *p) { static int sloppy = -1; if(sloppy < 0) { char *s = getenv("DARCS_SLOPPY_LOCKS"); sloppy = (s != NULL); } if(sloppy) return sloppy_atomic_create(p); else return careful_atomic_create(p); } #endif darcs-2.8.4/src/fpstring.c0000644001765600176560000000330112104371431014725 0ustar ganeshganesh/* * Copyright (C) 2003 David Roundy * Most of the UTF code is Copyright (C) 1999-2001 Free Software Foundation, Inc. * This file is part of darcs. * * Darcs is free software; you can redistribute it and/or modify it under * the terms of the GNU Library General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * You should have received a copy of the GNU Library General Public * License along with the GNU LIBICONV Library; see the file COPYING.LIB. * If not, write to the Free Software Foundation, Inc., 51 Franklin Street, * Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "fpstring.h" #include #include #include #ifdef _WIN32 #include #else #include #endif int has_funky_char(const char *s, int len) { // We check first for the more likely \0 so we can break out of // memchr that much sooner. return !!(memchr(s, 0, len) || memchr(s, 26, len)); } /* Conversion to and from hex */ void conv_to_hex(unsigned char *dest, unsigned char *from, int num_chars) { static char hex[] = "0123456789abcdef"; unsigned char *end; for (end = from + num_chars; from < end; from++) { *dest++ = hex[*from >> 4]; *dest++ = hex[*from & 0xf]; } return; } #define NYBBLE_TO_INT(c) \ ((c) - ((c) >= 'a' ? 'a' - 10 : '0')) void conv_from_hex(unsigned char *dest, unsigned char *from, int num_chars) { unsigned char *end; unsigned char c; end = dest + num_chars; while (dest < end) { c = NYBBLE_TO_INT(*from) << 4, from++; *dest++ = c | NYBBLE_TO_INT(*from), from++; } return; } darcs-2.8.4/src/maybe_relink.c0000644001765600176560000001165612104371431015546 0ustar ganeshganesh/* Copyright (C) 2005 Juliusz Chroboczek 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, 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; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #ifdef _WIN32 int maybe_relink(const char *src, const char *dst, int careful) { return 0; } #else /* Tries to link src to dst if both files exist and have the same contents. If careful is false only the file sizes are compared; if it is true, the full contents are compared. This code assumes that dst cannot change behind our back -- the caller is supposed to protect it by a lock. On the other hand, it does handle simultaneous access to src, but only if src is never modified in place. It should also be safe over NFS. Assumes that rename cannot fail mid-way on a single filesystem. Returns 1 on success, 0 if the files are already linked, -1 for an error in errno, -2 if the files cannot be linked because they are not the same, on different devices, or on a filesystem with no support for hard links, -3 if there was a race condition, -4 if something unexpected happened. */ int maybe_relink(char *src, char *dst, int careful) { #define RELINK_BUFFER_SIZE 8192 int len, rc, saved_errno; char *tempname; struct stat srcstat, dststat, tempstat; struct timeval now; rc = stat(src, &srcstat); if(rc < 0) { if(errno == ENOENT) return -2; else return -1; } rc = stat(dst, &dststat); if(rc < 0) return -1; if(!S_ISREG(srcstat.st_mode) || !S_ISREG(dststat.st_mode)) { return -4; } if(srcstat.st_dev != dststat.st_dev) { return -2; } if(srcstat.st_ino == dststat.st_ino) /* Files are already linked */ return 0; if(srcstat.st_size != dststat.st_size) return -2; /* link is atomic even on NFS, we will fail gracefully if the name is not unique. */ gettimeofday(&now, NULL); rc = strlen(dst) + 6; tempname = malloc(rc); if(tempname == NULL) return -1; len = snprintf(tempname, rc, "%s-%04x", dst, ((unsigned)(now.tv_usec ^ (now.tv_usec >> 16))) & 0xFFFF); if(len < 0 || len >= rc) { free(tempname); return -4; } rc = link(src, tempname); if(rc < 0) { /* We need to try to remove the link in case this was a problem with NFS over an unreliable transport. */ goto fail; } rc = stat(tempname, &tempstat); if(rc < 0) goto fail; /* Check for a race condition. The size and mtime checks are gratuitious, but they don't cost much, and might save your data if you're on a filesystem without i-nodes. */ if(tempstat.st_ino != srcstat.st_ino || tempstat.st_size != srcstat.st_size || tempstat.st_mtime != srcstat.st_mtime) { unlink(tempname); free(tempname); return -3; } if(careful) { int fd1, fd2, i, rc1, rc2; char buf1[RELINK_BUFFER_SIZE], buf2[RELINK_BUFFER_SIZE]; fd1 = open(tempname, O_RDONLY); if(fd1 < 0) goto fail; fd2 = open(dst, O_RDONLY); if(fd2 < 0) { close(fd1); goto fail; } i = 0; /* This comparison is approximate: it doesn't deal with short reads and EINTR. It's okay, as these cases are rare and if they happen, we're still safe. */ while(i < tempstat.st_size) { rc1 = read(fd1, buf1, RELINK_BUFFER_SIZE); if(rc1 < 0) { close(fd1); close(fd2); goto fail; } rc2 = read(fd2, buf2, RELINK_BUFFER_SIZE); if(rc2 < 0) { close(fd1); close(fd2); goto fail; } if(rc1 == 0 || rc1 != rc2 || memcmp(buf1, buf2, rc1) != 0) { close(fd1); close(fd2); unlink(tempname); free(tempname); return -2; } i += rc1; } close(fd1); close(fd2); } rc = rename(tempname, dst); if(rc < 0) goto fail; free(tempname); return 1; fail: saved_errno = errno; unlink(tempname); free(tempname); errno = saved_errno; if(errno == EPERM || errno == EOPNOTSUPP) return -2; return -1; #undef RELINK_BUFFER_SIZE } #endif darcs-2.8.4/src/umask.c0000644001765600176560000000115012104371431014211 0ustar ganeshganesh#include #include #include #include #include "umask.h" int set_umask(char *mask_string) { #ifndef WIN32 int rc; unsigned mask; char *end; mask = strtoul(mask_string, &end, 8); if(!end || *end != '\0') { errno = EINVAL; return -1; } rc = umask(mask); return rc; #else /* umask() has no useful meaning on win32. */ return 0; #endif /* #ifndef WIN32 ... else ... */ } int reset_umask(int old_mask) { #ifndef WIN32 umask(old_mask); return 1; #else return 0; #endif /* #ifndef WIN32 ... else ... */ } darcs-2.8.4/src/system_encoding.c0000644001765600176560000000024012104371431016262 0ustar ganeshganesh#include "system_encoding.h" char* get_system_encoding() { #ifdef WIN32 return "utf8"; #else setlocale(LC_ALL,""); return nl_langinfo(CODESET); #endif } darcs-2.8.4/src/h_iconv.c0000644001765600176560000000120312104371431014515 0ustar ganeshganesh#include "h_iconv.h" // Wrapper functions, since iconv_open et al are macros in libiconv. iconv_t haskeline_iconv_open(const char *tocode, const char *fromcode) { return iconv_open(tocode, fromcode); } void haskeline_iconv_close(iconv_t cd) { iconv_close(cd); } size_t haskeline_iconv(iconv_t cd, char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft) { // Cast inbuf to (void*) so that it works both on Solaris, which expects // a (const char**), and on other platforms (e.g. Linux), which expect // a (char **). return iconv(cd, (void*)inbuf, inbytesleft, outbuf, outbytesleft); } darcs-2.8.4/src/hscurl.c0000644001765600176560000002160512104371431014400 0ustar ganeshganesh#include "hscurl.h" #include #include #include #include #include #if LIBCURL_VERSION_NUM >= 0x071301 /* enable pipelining for libcurl >= 7.19.1 */ #define ENABLE_PIPELINING #endif enum RESULT_CODES { RESULT_OK = 0, RESULT_MALLOC_FAIL, RESULT_SELECT_FAIL, RESULT_MULTI_INIT_FAIL, RESULT_EASY_INIT_FAIL, RESULT_SLIST_APPEND_FAIL, RESULT_MULTI_INFO_READ_FAIL, RESULT_UNKNOWN_MESSAGE, RESULT_FILE_OPEN_FAIL }; static const char *error_strings[] = { "", "malloc() failed", "select() failed", "curl_multi_init() failed", "curl_easy_init() failed", "curl_slist_append() failed", "curl_multi_info_read() failed", "curl_multi_info_read() returned unknown message", "fopen() failed" }; struct UrlData { char *url; FILE *file; struct curl_slist *headers; }; static int debug = 0; #ifndef _WIN32 static const char user_agent[] = "darcs/" PACKAGE_VERSION " libcurl/" LIBCURL_VERSION; #else static const char user_agent[] = "darcs/unknown libcurl/" LIBCURL_VERSION; #endif static const char *proxypass; static int init_done = 0; static CURLM *multi = NULL; static int msgs_in_queue = 0; static char *last_url = NULL; static const char *perform() { int error; int running_handles, running_handles_last; fd_set fd_read, fd_write, fd_except; int max_fd; long timeout; struct timeval tval; error = curl_multi_perform(multi, &running_handles); if (error != CURLM_OK && error != CURLM_CALL_MULTI_PERFORM) return curl_multi_strerror(error); running_handles_last = running_handles; while (running_handles_last > 0) { while (error == CURLM_CALL_MULTI_PERFORM) error = curl_multi_perform(multi, &running_handles); if (error != CURLM_OK) return curl_multi_strerror(error); if (running_handles < running_handles_last) break; FD_ZERO(&fd_read); FD_ZERO(&fd_write); FD_ZERO(&fd_except); error = curl_multi_fdset(multi, &fd_read, &fd_write, &fd_except, &max_fd); if (error != CURLM_OK && error != CURLM_CALL_MULTI_PERFORM) return curl_multi_strerror(error); #ifdef CURL_MULTI_TIMEOUT error = curl_multi_timeout(multi, &timeout); if (error != CURLM_OK && error != CURLM_CALL_MULTI_PERFORM) return curl_multi_strerror(error); if (timeout == -1) #endif timeout = 100; tval.tv_sec = timeout / 1000; tval.tv_usec = timeout % 1000 * 1000; while (select(max_fd + 1, &fd_read, &fd_write, &fd_except, &tval) < 0) if (errno != EINTR) { if (debug) perror(error_strings[RESULT_SELECT_FAIL]); return error_strings[RESULT_SELECT_FAIL]; } error = CURLM_CALL_MULTI_PERFORM; } return NULL; } const char *curl_request_url(const char *url, const char *filename, int cache_time) { int error; if (init_done == 0) { error = curl_global_init(CURL_GLOBAL_ALL); if (error != CURLE_OK) return curl_easy_strerror(error); proxypass = getenv("DARCS_PROXYUSERPWD"); init_done = 1; } if (multi == NULL) { multi = curl_multi_init(); if (multi == NULL) return error_strings[RESULT_MULTI_INIT_FAIL]; #ifdef ENABLE_PIPELINING error = curl_multi_setopt(multi, CURLMOPT_PIPELINING, 1); if (error != CURLM_OK && error != CURLM_CALL_MULTI_PERFORM) return curl_multi_strerror(error); #endif } CURL *easy = curl_easy_init(); if (easy == NULL) return error_strings[RESULT_EASY_INIT_FAIL]; if (debug) { error = curl_easy_setopt(easy, CURLOPT_VERBOSE, 1); if (error != CURLE_OK) return curl_easy_strerror(error); } struct UrlData *url_data = malloc(sizeof(struct UrlData)); if (url_data == NULL) return error_strings[RESULT_MALLOC_FAIL]; url_data->url = strdup(url); if (url_data->url == NULL) return error_strings[RESULT_MALLOC_FAIL]; url_data->file = fopen(filename,"wb"); if (url_data->file == NULL) { if (debug) perror(error_strings[RESULT_FILE_OPEN_FAIL]); return error_strings[RESULT_FILE_OPEN_FAIL]; } error = curl_easy_setopt(easy, CURLOPT_PRIVATE, url_data); if (error != CURLE_OK) return curl_easy_strerror(error); error = curl_easy_setopt(easy, CURLOPT_URL, url_data->url); if (error != CURLE_OK) return curl_easy_strerror(error); #ifdef CURLOPT_WRITEDATA error = curl_easy_setopt(easy, CURLOPT_WRITEDATA, url_data->file); #else error = curl_easy_setopt(easy, CURLOPT_FILE, url_data->file); #endif if (error != CURLE_OK) return curl_easy_strerror(error); error = curl_easy_setopt(easy, CURLOPT_USERAGENT, user_agent); if (error != CURLE_OK) return curl_easy_strerror(error); error = curl_easy_setopt(easy, CURLOPT_FOLLOWLOCATION, 1); if (error != CURLE_OK) return curl_easy_strerror(error); error = curl_easy_setopt(easy, CURLOPT_FAILONERROR, 1); if (error != CURLE_OK) return curl_easy_strerror(error); error = curl_easy_setopt(easy, CURLOPT_HTTPAUTH, CURLAUTH_ANY); if (error != CURLE_OK) return curl_easy_strerror(error); /* libcurl currently always sends Pragma: no-cache, but never Cache-Control, which is contradictory. We override both, just to be sure. */ url_data->headers = curl_slist_append(NULL, "Accept: */*"); if(cache_time == 0) { url_data->headers = curl_slist_append(url_data->headers, "Pragma: no-cache"); url_data->headers = curl_slist_append(url_data->headers, "Cache-Control: no-cache"); } else if(cache_time > 0) { /* This won't work well with HTTP/1.0 proxies. */ char buf[40]; snprintf(buf, sizeof(buf), "Cache-Control: max-age=%d", cache_time); buf[sizeof(buf) - 1] = '\n'; url_data->headers = curl_slist_append(url_data->headers, "Pragma:"); url_data->headers = curl_slist_append(url_data->headers, buf); } else { url_data->headers = curl_slist_append(url_data->headers, "Pragma:"); url_data->headers = curl_slist_append(url_data->headers, "Cache-Control:"); } if (url_data->headers == NULL) return error_strings[RESULT_SLIST_APPEND_FAIL]; error = curl_easy_setopt(easy, CURLOPT_HTTPHEADER, url_data->headers); if (error != CURLE_OK) return curl_easy_strerror(error); if (proxypass && *proxypass) { error = curl_easy_setopt(easy, CURLOPT_PROXYUSERPWD, proxypass); if (error != CURLE_OK) return curl_easy_strerror(error); } error = curl_multi_add_handle(multi, easy); if (error != CURLM_OK && error != CURLM_CALL_MULTI_PERFORM) return curl_multi_strerror(error); return error_strings[RESULT_OK]; } const char *curl_wait_next_url(int* errorCode, long* httpErrorCode) { *errorCode = -1; *httpErrorCode = -1; if (last_url != NULL) { free(last_url); last_url = NULL; } if (msgs_in_queue == 0) { const char *error = perform(); if (error != NULL) return error; } CURLMsg *msg = curl_multi_info_read(multi, &msgs_in_queue); if (msg == NULL) return error_strings[RESULT_MULTI_INFO_READ_FAIL]; if (msg->msg == CURLMSG_DONE) { CURL *easy = msg->easy_handle; CURLcode result = msg->data.result; struct UrlData *url_data; int error = set_time_out(easy, errorCode); if (error != CURLE_OK ){ *errorCode = error; return curl_easy_strerror(error); } error = curl_easy_getinfo(easy, CURLINFO_PRIVATE, (char **)&url_data); if (error != CURLE_OK){ *errorCode = error; return curl_easy_strerror(error); } last_url = url_data->url; fclose(url_data->file); curl_slist_free_all(url_data->headers); free(url_data); error = curl_multi_remove_handle(multi, easy); if (error != CURLM_OK && error != CURLM_CALL_MULTI_PERFORM) return curl_multi_strerror(error); curl_easy_cleanup(easy); if (result != CURLE_OK){ *errorCode = result; if (result == CURLE_HTTP_RETURNED_ERROR) curl_easy_getinfo(easy, CURLINFO_RESPONSE_CODE, httpErrorCode); return curl_easy_strerror(result); } } else return error_strings[RESULT_UNKNOWN_MESSAGE]; return error_strings[RESULT_OK]; } const char *curl_last_url() { return last_url != NULL ? last_url : ""; } void curl_enable_debug() { debug = 1; } int curl_pipelining_enabled() { #ifdef ENABLE_PIPELINING return 1; #else return 0; #endif } int set_time_out(CURL *handle, int* errorCode) { int error; long time_out = DEFAULT_CONNECTION_TIMEOUT; const char *stime_out; stime_out = getenv("DARCS_CONNECTION_TIMEOUT"); if (stime_out != NULL){ long result = atol (stime_out); if ( result > 0 ) time_out = result; else *errorCode = 90 ; } error = curl_easy_setopt(handle, CURLOPT_TIMEOUT, time_out); return error; } darcs-2.8.4/src/test.hs0000644001765600176560000002053512104371431014250 0ustar ganeshganesh{-# LANGUAGE CPP, MultiParamTypeClasses, DeriveDataTypeable #-} module Main ( main ) where import qualified Darcs.Test.Misc import qualified Darcs.Test.Patch import qualified Darcs.Test.Email import Control.Monad (when, filterM) import Data.List ( isPrefixOf, isSuffixOf, sort ) import qualified Data.ByteString.Char8 as B import System.Console.CmdLib import System.Directory ( doesFileExist ) import System.Environment.FindBin ( getProgPath ) import System.FilePath( takeDirectory, takeBaseName, isAbsolute ) import System.IO( hSetBinaryMode, hSetBuffering, BufferMode( NoBuffering ), stdin, stdout, stderr ) import Test.Framework.Providers.API import Test.Framework import Shellish hiding ( liftIO, run ) import qualified Shellish doUnit :: IO [Test] doUnit = return unitTests -- | This is the big list of tests that will be run using testrunner. unitTests :: [Test] unitTests = [ Darcs.Test.Email.testSuite , Darcs.Test.Misc.testSuite ] ++ Darcs.Test.Patch.testSuite -- ---------------------------------------------------------------------- -- shell tests -- ---------------------------------------------------------------------- data Format = Hashed | Darcs2 deriving Show data Running = Running deriving Show data Result = Success | Skipped | Failed String instance Show Result where show Success = "Success" show Skipped = "Skipped" show (Failed f) = unlines (map ("| " ++) $ lines f) instance TestResultlike Running Result where testSucceeded Success = True testSucceeded Skipped = True testSucceeded _ = False data ShellTest = ShellTest { format :: Format , testfile :: FilePath , testdir :: Maybe FilePath -- ^ only if you want to set it explicitly , _darcspath :: FilePath } deriving Typeable runtest' :: ShellTest -> FilePath -> ShIO Result runtest' (ShellTest fmt _ _ dp) srcdir = do wd <- pwd setenv "HOME" wd setenv "TESTDATA" (srcdir "tests" "data") setenv "TESTBIN" (srcdir "tests" "bin") setenv "DARCS_TESTING_PREFS_DIR" $ wd ".darcs" setenv "EMAIL" "tester" setenv "DARCS_DONT_COLOR" "1" setenv "DARCS_DONT_ESCAPE_ANYTHING" "1" getenv "PATH" >>= setenv "PATH" . ((takeDirectory dp ++ pathVarSeparator) ++) setenv "DARCS" dp mkdir ".darcs" writefile ".darcs/defaults" defaults -- Warning: A do-notation statement discarded a result of type String. _ <- Shellish.run "bash" [ "test" ] return Success `catch_sh` \e -> case e of RunFailed _ 200 _ -> return Skipped RunFailed _ _ _ -> Failed <$> B.unpack <$> lastOutput where defaults = unlines ["ALL " ++ fmtstr, "send no-edit-description", "ALL ignore-times"] fmtstr = case fmt of Darcs2 -> "darcs-2" Hashed -> "hashed" #ifdef WIN32 pathVarSeparator = ";" #else pathVarSeparator = ":" #endif runtest :: ShellTest -> ShIO Result runtest t = withTmp $ \dir -> do cp "tests/lib" dir cp ("tests" testfile t) (dir "test") srcdir <- pwd silently $ sub $ cd dir >> runtest' t srcdir where withTmp = case testdir t of Just dir -> \job -> do let d = (dir show (format t) takeBaseName (testfile t)) mkdir_p d job d Nothing -> withTmpDir instance Testlike Running Result ShellTest where testTypeName _ = "Shell" runTest _ test = runImprovingIO $ do yieldImprovement Running liftIO (shellish $ runtest test) shellTest :: FilePath -> Format -> Maybe FilePath -> String -> Test shellTest dp fmt tdir file = Test (file ++ " (" ++ show fmt ++ ")") $ ShellTest fmt file tdir dp findShell :: FilePath -> Maybe FilePath -> Bool -> ShIO [Test] findShell dp tdir isFailing = do files <- sort <$> grep relevant <$> grep (".sh" `isSuffixOf`) <$> ls "tests" return [ shellTest dp fmt tdir file | fmt <- [ Darcs2, Hashed ] , file <- files ] where relevant = (if isFailing then id else not) . ("failing-" `isPrefixOf`) findNetwork :: FilePath -> Maybe FilePath -> ShIO [Test] findNetwork dp tdir = do files <- sort <$> grep (".sh" `isSuffixOf`) <$> ls "tests/network" return [ shellTest dp Darcs2 tdir ("network" file) | file <- files ] -- ---------------------------------------------------------------------- -- harness -- ---------------------------------------------------------------------- data Config = Config { failing :: Bool , shell :: Bool , network :: Bool , unit :: Bool , darcs :: String , tests :: [String] , testDir :: Maybe FilePath , plain :: Bool , hideSuccesses :: Bool , threads :: Int } deriving (Data, Typeable, Eq) instance Attributes Config where attributes _ = group "Options" [ failing %> Help "Run the failing (shell) tests." , shell %> Help "Run the passing, non-network shell tests." %+ Default True , network %> Help "Run the network shell tests." , unit %> Help "Run the unit tests." %+ Default True , tests %> Help "Pattern to limit the tests to run." %+ short 't' , testDir %> Help "Directory to run tests in" %+ Default (Nothing :: Maybe FilePath) , plain %> Help "Use plain-text output." , hideSuccesses %> Help "Hide successes." , threads %> Default (1 :: Int) %+ short 'j' ] data DarcsTest = DarcsTest deriving Typeable instance Command DarcsTest (Record Config) where run _ conf _ = do let args = [ "-j", show $ threads conf ] ++ concat [ ["-t", x ] | x <- tests conf ] ++ [ "--plain" | True <- [plain conf] ] ++ [ "--hide-successes" | True <- [hideSuccesses conf] ] ++ [ "--maximum-unsuitable-generated-tests", "700" ] case testDir conf of Nothing -> return () Just d -> do e <- shellish (test_e d) when e $ fail ("Directory " ++ d ++ " already exists. Cowardly exiting") darcsBin <- case darcs conf of "" -> do path <- getProgPath let candidates = -- if darcs-test lives in foo/something, look for foo/darcs[.exe] -- for example if we've done cabal install -ftest, there'll be a darcs-test and darcs in the cabal -- installation folder [path "darcs" ++ exeSuffix] ++ -- if darcs-test lives in foo/darcs-test/something, look for foo/darcs/darcs[.exe] -- for example after cabal build we can run dist/build/darcs-test/darcs-test and it'll find -- the darcs in dist/build/darcs/darcs [takeDirectory path "darcs" "darcs" ++ exeSuffix | takeBaseName path == "darcs-test" ] availableCandidates <- filterM doesFileExist candidates case availableCandidates of (darcsBin:_) -> do putStrLn $ "Using darcs executable in " ++ darcsBin return darcsBin [] -> fail ("No darcs specified or found nearby. Perhaps --darcs `pwd`/dist/build/darcs/darcs" ++ exeSuffix ++ "?") v -> return v when (shell conf || network conf || failing conf) $ do when (not (isAbsolute $ darcsBin)) $ fail ("Argument to --darcs should be an absolute path") when (not (exeSuffix `isSuffixOf` darcsBin)) $ putStrLn $ "Warning: --darcs flag does not end with " ++ exeSuffix ++ " - some tests may fail (case does matter)" ftests <- shellish $ if failing conf then findShell darcsBin (testDir conf) True else return [] stests <- shellish $ if shell conf then findShell darcsBin (testDir conf) False else return [] utests <- if unit conf then doUnit else return [] ntests <- shellish $ if network conf then findNetwork (darcs conf) (testDir conf) else return [] defaultMainWithArgs (ftests ++ stests ++ utests ++ ntests) args where exeSuffix :: String #ifdef WIN32 exeSuffix = ".exe" #else exeSuffix = "" #endif main :: IO () main = do hSetBinaryMode stdout True hSetBuffering stdout NoBuffering hSetBinaryMode stderr True hSetBinaryMode stdin True getArgs >>= execute DarcsTest darcs-2.8.4/src/Preproc.hs0000644001765600176560000001704112104371431014701 0ustar ganeshganesh-- | This program mangles a pseudo-LaTeX document into actual LaTeX. -- There are three key changes to the input: -- -- * \\input{foo} is replaced by the contents of the file foo (after -- it, too, is mangled). Note that this is relative to the -- working directory, *not* relative to the file being parsed. -- -- * Anything between \\begin{code} and \\end{code} is deleted. -- Note that this is quite unlike normal literate documentation -- (for which we use Haddock, not LaTeX). -- -- * Some nonstandard pseudo-LaTeX commands are expanded into actual -- LaTeX text. In particular, \\darcsCommand{foo} is replaced by -- LaTeX markup describing the command @foo@. module Preproc ( preprocMain ) where import qualified Ratified( readFile ) import System.FilePath ( () ) import System.Environment ( getArgs ) import System.Exit ( exitWith, ExitCode(..) ) import Control.Monad ( when ) import Data.List ( stripPrefix ) import Text.Regex ( matchRegex, mkRegex ) import Darcs.Commands ( DarcsCommand(SuperCommand, commandSubCommands, commandName, commandExtraArgHelp, commandBasicOptions, commandAdvancedOptions, commandHelp, commandDescription), extractCommands ) import Darcs.Arguments ( optionsLatex ) import Darcs.Commands.Help ( commandControlList, environmentHelp ) import English ( andClauses ) import Version ( version ) theCommands :: [DarcsCommand] theCommands = extractCommands commandControlList -- | The entry point for this program. The path to the TeX master -- file is supplied as the first argument. Bootstrapping into -- 'preproc' then happens by passing it a pseudo-document that -- contains a single input (include) line. preprocMain :: [String] -> IO () preprocMain args = do when (length args < 1) $ exitWith $ ExitFailure 1 putStrLn "%% This file was automatically generated by preproc." c <- preproc ["\\input{"++head args++"}"] mapM_ putStrLn c -- | Depending on whether pdflatex or htlatex is to be used, the LaTeX -- output of this program must vary subtly. This procedure returns -- true iff the command-line arguments contain @--html@. amHtml :: IO Bool amHtml = do args <- getArgs return $ elem "--html" args -- | Given a list of input lines in pseudo-LaTeX, return the same -- document in LaTeX. The pseudo-LaTeX lines are replaced, other -- lines are used unmodified. preproc :: [String] -> IO [String] preproc [] = return [] -- Empty input, empty output. preproc ("\\usepackage{html}":ss) = -- only use html package with latex2html do rest <- preproc ss ah <- amHtml return $ if ah then "\\usepackage{html}" : rest else "\\usepackage{hyperref}" : rest preproc ("\\begin{code}":ss) = ignore ss where ignore :: [String] -> IO [String] ignore ("\\end{code}":ss') = preproc ss' ignore (_:ss') = ignore ss' ignore [] = return [] preproc ("\\begin{options}":ss) = do rest <- preproc ss ah <- amHtml return $ if ah then "\\begin{rawhtml}" : "
" : rest else ("\\begin{Verbatim}[frame=lines,xleftmargin=1cm," ++ "xrightmargin=1cm]") : rest preproc ("\\end{options}":ss) = do rest <- preproc ss ah <- amHtml return $ if ah then "
" : "\\end{rawhtml}" : rest else "\\end{Verbatim}" : rest preproc ("\\darcsVersion":ss) = do rest <- preproc ss return $ version:rest preproc (s:ss) = do rest <- preproc ss let rx = mkRegex "^\\\\(input|darcsCommand|darcsEnv)\\{(.+)\\}$" case matchRegex rx s of Just ["input", path] -> do cs <- Ratified.readFile $ "doc" "src" path -- not part of normal darcs operation this <- preproc $ lines cs return $ this ++ rest Just ["darcsCommand", command] -> return $ latexCommandHelp command : rest Just ["darcsEnv", variable] -> return $ envHelp variable : rest -- The base case for the whole preproc function. Nothing to -- mangle, so this is an ordinary line of TeX, and we append it to -- the result unmodified. _ -> return $ s : rest latexCommandHelp :: String -> String latexCommandHelp command = section ++ "{darcs " ++ command ++ "}\n" ++ "\\label{" ++ command ++ "}\n" ++ gh ++ getOptions command ++ "\n" ++ gd where section = if ' ' `elem` command then "\\subsubsection" else "\\subsection" -- | Given a Darcs command name as a string, return that command's (multi-line) help string. gh :: String gh = escapeLatexSpecials $ commandProperty commandHelp theCommands command -- | Given a Darcs command name as a string, return that command's (one-line) description string. gd :: String gd = commandProperty commandDescription theCommands command getOptions :: String -> String getOptions comm = getComOptions $ getC names theCommands where names = words comm getC :: [String] -> [DarcsCommand] -> [DarcsCommand] getC (name:ns) commands = case ns of [] -> [get name commands] _ -> case get name commands of c@SuperCommand { } -> c : getC ns (extractCommands $ commandSubCommands c) _ -> error $ "Not a supercommand: " ++ name where get n (c:cs) | commandName c == n = c | otherwise = get n cs get n [] = error $ "No such command: "++n getC [] _ = error "no command specified" getComOptions :: [DarcsCommand] -> String getComOptions c = "\\par\\verb!Usage: darcs " ++ cmd ++ " [OPTION]... " ++ args ++ "!\n\n" ++ "Options:\n\n" ++ optionsLatex opts1 ++ (if null opts2 then "" else "\n\n" ++ "Advanced options:\n\n" ++ optionsLatex opts2) where cmd = unwords $ map commandName c args = unwords $ commandExtraArgHelp $ last c opts1 = commandBasicOptions $ last c opts2 = commandAdvancedOptions $ last c commandProperty :: (DarcsCommand -> String) -> [DarcsCommand] -> String -> String commandProperty property commands name = property $ last c where names = words name c = getC names commands envHelp :: String -> String envHelp var = unlines $ render $ entry environmentHelp where render (ks, ds) = ("\\paragraph{" ++ escapeLatexSpecials (andClauses ks) ++ "}") : ("\\label{env:" ++ var ++ "}") : map escapeLatexSpecials ds entry [] = undefined entry (x:xs) | elem var $ fst x = x | otherwise = entry xs -- | LaTeX treats a number of characters or sequences specially. -- Therefore when including ordinary help text in a LaTeX document, it -- is necessary to escape these characters in the way LaTeX expects. escapeLatexSpecials :: String -> String -- Order is important escapeLatexSpecials = bs2 . amp . percent . carrot . dollar . underscore . rbrace . lbrace . bs1 where amp = replace "&" "\\&" bs1 = replace "\\" "\001" bs2 = replace "\001" "$\\backslash$" carrot = replace "^" "\\^{}" dollar = replace "$" "\\$" lbrace = replace "{" "\\{" percent = replace "%" "\\%" rbrace = replace "}" "\\}" underscore = replace "_" "\\_" replace :: Eq a => [a] -> [a] -> [a] -> [a] replace _ _ [] = [] replace find repl s = case stripPrefix find s of Just rest -> repl ++ replace find repl rest Nothing -> head s : replace find repl (tail s) darcs-2.8.4/src/darcs.hs0000644001765600176560000000623612104371431014367 0ustar ganeshganesh-- Copyright (C) 2002-2003 David Roundy -- -- 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, 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; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP #-} -- | -- Module : Main -- Copyright : 2002-2003 David Roundy -- License : GPL -- Maintainer : darcs-devel@darcs.net -- Stability : experimental -- Portability : portable module Main ( main ) where import Control.Exception.Extensible ( AssertionFailed(..), handle ) import Control.Monad ( forM_ ) import System.IO ( stdin, stdout, stderr, hSetBinaryMode ) import System.Exit ( exitWith, ExitCode(..) ) import System.Environment ( getArgs ) import Darcs.Commands.Help ( helpCmd, listAvailableCommands, printVersion, commandControlList ) import Darcs.Flags ( DarcsFlag(Verbose) ) import Darcs.Global ( withAtexit, atexit ) import Darcs.Repository( reportBadSources ) import Darcs.RunCommand ( runTheCommand ) import Darcs.SignalHandler ( withSignalsHandled ) import Darcs.Utils ( setDarcsEncodings ) import Exec ( ExecException(..) ) import Preproc( preprocMain ) import Version ( version, context, builddeps ) #include "impossible.h" execExceptionHandler :: ExecException -> IO a execExceptionHandler (ExecException cmd args redirects reason) = do putStrLn . unlines $ [ "Failed to execute external command: " ++ unwords (cmd:args) , "Lowlevel error: " ++ reason , "Redirects: " ++ show redirects ] exitWith $ ExitFailure 3 main :: IO () main = withAtexit . withSignalsHandled . handleExecFail . handleAssertFail $ do atexit reportBadSources setDarcsEncodings argv <- getArgs -- Explicitly handle no-args and special "help" arguments. case argv of [] -> printVersion >> runHelpCmd ["-h"] -> runHelpCmd ["--help"] -> runHelpCmd ["--overview"] -> helpCmd [Verbose] [] ["--commands"] -> listAvailableCommands ["-v"] -> putStrLn version ["--version"] -> putStrLn version ["--exact-version"] -> printExactVersion ("--preprocess-manual" : rest) -> preprocMain rest _ -> do forM_ [stdout, stdin, stderr] $ \h -> hSetBinaryMode h True runTheCommand commandControlList (head argv) (tail argv) where handleExecFail = handle execExceptionHandler handleAssertFail = handle $ \(AssertionFailed e) -> bug e runHelpCmd = helpCmd [] [] printExactVersion = do putStrLn $ "darcs compiled on " ++ __DATE__ ++ ", at " ++ __TIME__ putStrLn context putStrLn "Compiled with:\n" putStr builddeps darcs-2.8.4/src/atomic_create.h0000644001765600176560000000053712104371431015705 0ustar ganeshganesh #include #include #include int sloppy_atomic_create(const char *p); int atomic_create(const char *p); #ifdef _WIN32 int mkstemp(char *p); int pipe( int fildes[2] ); int renamefile(const char *from, const char *to); #endif int stdout_is_a_pipe(); int maybe_relink(const char *src, const char *dst, int careful); darcs-2.8.4/src/fpstring.h0000644001765600176560000000036012104371431014734 0ustar ganeshganesh#include #include int has_funky_char(const char *s, int len); void conv_to_hex(unsigned char *dest, unsigned char *from, int num_chars); void conv_from_hex(unsigned char *dest, unsigned char *from, int num_chars); darcs-2.8.4/src/gadts.h0000644001765600176560000000040112104371431014176 0ustar ganeshganesh#ifdef GADT_WITNESSES #define C(contexts) contexts #define FORALL(types) forall types. #define PATCHKIND (* -> * -> *) #define SEALEDPATCHKIND (* -> *) #else #define C(contexts) #define FORALL(types) #define PATCHKIND * #define SEALEDPATCHKIND * #endif darcs-2.8.4/src/hscurl.h0000644001765600176560000000055212104371431014403 0ustar ganeshganesh#define DEFAULT_CONNECTION_TIMEOUT 30 const char *curl_request_url(const char *url, const char *filename, int cache_time); const char *curl_wait_next_url(int *errorCode, long* httpErrorCode); const char *curl_last_url(); void curl_enable_debug(); int curl_pipelining_enabled(); int set_time_out(); darcs-2.8.4/src/impossible.h0000644001765600176560000000045712104371431015255 0ustar ganeshganeshimport qualified Darcs.Bug as Bug_ #define darcsBug (\imp_funny_name -> imp_funny_name (__FILE__,__LINE__,__TIME__,__DATE__)) #define bug (darcsBug Bug_._bug) #define impossible (darcsBug Bug_._impossible) #define fromJust (darcsBug Bug_._fromJust) #define bugDoc (darcsBug Bug_._bugDoc) darcs-2.8.4/src/maybe_relink.h0000644001765600176560000000010112104371431015532 0ustar ganeshganeshint maybe_relink(const char *src, const char *dst, int careful); darcs-2.8.4/src/system_encoding.h0000644001765600176560000000023612104371431016274 0ustar ganeshganesh#ifndef __SYSTEM_ENCODING__ #define __SYSTEM_ENCODING__ #ifndef WIN32 #include #include #endif char* get_system_encoding(); #endif darcs-2.8.4/src/umask.h0000644001765600176560000000010112104371431014211 0ustar ganeshganeshint set_umask(char *mask_string); int reset_umask(int old_mask); darcs-2.8.4/src/h_iconv.h0000644001765600176560000000040312104371431014523 0ustar ganeshganesh#include iconv_t haskeline_iconv_open(const char *tocode, const char *fromcode); void haskeline_iconv_close(iconv_t cd); size_t haskeline_iconv(iconv_t cd, char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft); darcs-2.8.4/contrib/0000755001765600176560000000000012104371431013601 5ustar ganeshganeshdarcs-2.8.4/contrib/_darcs.zsh0000644001765600176560000000225712104371431015570 0ustar ganeshganesh#compdef darcs ## Darcs completion snippet for zsh. ## ## Copyright (C) 2009 Nicolas Pouillard ## ## 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. if (($CURRENT == 2)); then # We're completing the first word after "darcs" -- the command. _wanted command expl 'darcs command' \ compadd -- $( darcs --commands ) else case "${words[$CURRENT]}"; in # If it looks like an URL... ht*|ft*) _arguments '*:URL:_urls' ;; # If it looks like an explicit path... /*|./*|\~*|../*) _arguments '*:file:_files' ;; # Otherwise, let's ask darcs for all possible options *) _wanted args expl 'arg for darcs command' \ compadd -- $( darcs ${words[2]} --list-option ) ;; esac fi darcs-2.8.4/contrib/darcs_completion0000644001765600176560000000356412104371431017061 0ustar ganeshganesh#-*- mode: shell-script;-*- # darcs command line completion. # Copyright 2002 "David Roundy" # This archive should be copied in the directory /etc/bash_completion.d/ _darcs() { local cur cur=${COMP_WORDS[COMP_CWORD]} COMPREPLY=() if (($COMP_CWORD == 1)); then COMPREPLY=( $( darcs --commands | command grep "^$cur" ) ) return 0 fi local IFS=$'\n' # So that the following "command-output to array" operation splits only at newlines, not at each space, tab or newline. COMPREPLY=( $( darcs ${COMP_WORDS[1]} --list-option | command grep "^${cur//./\\.}") ) # Then, we adapt the resulting strings to be reusable by bash. If we don't # do this, in the case where we have two repositories named # ~/space in there-0.1 and ~/space in there-0.2, the first completion will # give us: # bash> darcs push ~/space in there-0. # ~/space in there-0.1 ~/space in there-0.2 # and we have introduced two spaces in the command line (if we try to # recomplete that, it won't find anything, as it doesn't know anything # starting with "there-0."). # printf %q will gracefully add the necessary backslashes. # # Bash also interprets colon as a separator. If we didn't handle it # specially, completing http://example.org/repo from http://e would # give us: # bash> darcs pull http:http://example.org/repo # An option would be to require the user to escape : as \: and we # would do the same here. Instead, we return only the part after # the last colon that is already there, and thus fool bash. The # downside is that bash only shows this part to the user. local i=${#COMPREPLY[*]} local colonprefixes=${cur%"${cur##*:}"} while [ $((--i)) -ge 0 ]; do COMPREPLY[$i]=`printf %q "${COMPREPLY[$i]}"` COMPREPLY[$i]=${COMPREPLY[$i]#"$colonprefixes"} done return 0 } complete -F _darcs -o default darcs darcs-2.8.4/contrib/cygwin-wrapper.bash0000644001765600176560000002010212104371431017411 0ustar ganeshganesh#! /bin/bash DIRNAME=`dirname "${0}"` if [ "${DIRNAME:0:1}" = "/" ] ; then DARCSPACKAGEDIR="${DIRNAME}" else DARCSPACKAGEDIR="${PWD}/${DIRNAME}" fi # If the DARCSPACKAGEDIR assignment above doesn't work for some funny reason, # you could set these variables by hand. Or fix the script to work # automatically and submit a patch. # Should be set to the full Cygwin path to the directory containing the # putty executables. putty_binary_dir="${DARCSPACKAGEDIR}" # Should be set to the full Cygwin path to the directory containing the # Windows binary "darcs.exe". darcs_binary_dir="$putty_binary_dir" # Should be set to the full Cygwin path to the Windows binary # "darcs.exe". darcs_binary="${darcs_binary_dir}/realdarcs.exe" #--------------------------------------------------------------------- # Darcs Wrapper for Cygwin # # A Bash script that allows Cywin paths on the command line when using # a version of Darcs compiled for Windows. Darcs will still use still # Windows paths internally. # #--------------------------------------------------------------------- # Usage # # Edit this file and set the variables above. Then, rename this # script to "darcs" and put it in your PATH somewhere before the # original binary. # # Darcs needs to launch itself for some operations and so the original # binary needs to be in your Windows PATH. Do not rename it. # #--------------------------------------------------------------------- # Known Issues # # This script is just a stopgap measure. Things don't work perfectly. # We really need a Cygwin build of Darcs. # # No path conversion is performed on: # - Any preferences set with "setpref" # - The "COMMAND" argument to "darcs trackdown" # # When Darcs launches external programs, it uses a Windows system call # to do so. This means you may not be able to run "hash bang" scripts # directly. For example, to run the Bash script "myscript", you'll # have to tell Darcs to run "bash myscript". # # -------------------------------------------------------------------- PATH="$putty_binary_dir:$darcs_binary_dir:${PATH}" debug=false cmd="$1" # Print each argument to stderr on a separate line. Then exit. function die() { local line for line in "$@"; do echo "$line" > /dev/stderr done exit 2 } # Make sure 'darcs_binary_dir' is set. if [ ! -d "$darcs_binary_dir" ]; then die "Please edit this script and set the 'darcs_binary_dir' variable" \ "to refer to a valid directory." \ " script path = '$0'" \ " darcs_binary_dir = '$darcs_binary_dir'" fi # Special case for when the first argument is an option. if expr match "$cmd" '-' > /dev/null; then if $debug; then # echo "SIMPLE CASE:" for arg in "$@"; do echo " arg = '$arg'" done else # echo about to exec -a darcs "$darcs_binary" "$@" exec -a darcs "$darcs_binary" "$@" fi fi # Shift off the darcs command name shift function is_opaque_opt() { local opt for opt in "${opaque_binary_opts[@]}"; do if [ "$opt" == "$1" ]; then return 0 fi done return 1 } function is_file_opt() { local opt for opt in "${file_binary_opts[@]}"; do if [ "$opt" == "$1" ]; then return 0 fi done return 1 } # Options are not dealt with in a command-specific way. AFAIK, Darcs # doesn't use the same option in two different ways, so we should be # fine. # List of "opaque" binary options. These are options where we don't # treat the option argument like a file. declare -a opaque_binary_opts=( \ '--repo-name' \ '--to-match' '--to-patch' '--to-tag' \ '--from-match' '--from-patch' '--from-tag' \ '-t' '--tag' '--tags' '--tag-name' \ '-p' '--patch' '--patches' \ '-m' '--patch-name' \ '--matches' '--match' \ '--token-chars' \ '-A' '--author' '--from' '--to' '--cc' \ '--sign-as' '--creator-hash' \ '--last' '--diff-opts' \ '-d' '--dist-name' \ '--log-file' \ '--apply-as' \ ) # List of binary options that take file arguments that need to be converted. declare -a file_binary_opts=( \ '--repodir' '--repo' '--sibling' \ '--context' \ '--logfile' '-o' '--output' \ '--external-merge' \ '--sign-ssl' '--verify' '--verify-ssl' \ ) # -------------------------------------------------------------------- # The three command categories. We only use the first one, but the # others are listed to make sure we've covered everything. Luckily, # there aren't any commands that have some args that need to be # converted and some that don't. # Commands whose arguments are file paths that need to be translated. cmds_convert_nonoption_args='|get|put|pull|push|send|apply' # Commands who's arguments should be left alone. File paths that # refer to files in the repo should NOT be converted because they # are relative paths, which Darcs will handle just fine. Cygwin # sometimes makes them absolute paths, which confuses Darcs. #cmds_no_convert_nonoption_paths='|add|remove|mv|replace|record|whatsnew|changes|setpref|trackdown|amend-record|revert|diff|annotate' # Commands that don't accept non-option arguments #cmds_no_nonoption_args='|initialize|tag|check|optimize|rollback|unrecord|unpull|resolve|dist|repair' # See if we need to convert the non-option args for the current # command. This matches some prefix of one of the commands in the # list. The match may not be unambiguous, we can rely on Darcs to # deal with that correctly. if expr match "$cmds_convert_nonoption_args" ".*|$cmd" > /dev/null; then convert_nonoption_args=true else convert_nonoption_args=false fi function convert_path() { # echo "converting path ${*} ..." >> /tmp/log if expr match "$1" '[-@._A-Za-z0-9]*:' > /dev/null; then # Some sort of URL or remote ssh pathname ("xxx:/") echo "$1" # echo "converting path ${*} ... to ${1}" >> /tmp/log elif [ "$1" == '.' ]; then # Compensate for stupid 'cygpath' behavior. echo '.' # echo "converting path ${*} ... to ." >> /tmp/log else cygpath -wl -- "$1" # echo "converting path ${*} ... to `cygpath -wl -- ${1}`" >> /tmp/log fi } declare -a params=("$cmd") num_nonoption_args=0 while [ $# -gt 0 ]; do arg=$1 shift if expr match "$arg" '-' > /dev/null; then # It's an option. Check to see if it's an opaque binary option. if expr match "$arg" '.*=' > /dev/null; then # The option has an '=' in it. opt=`expr match "$arg" '\([^=]*\)'` opt_arg=`expr match "$arg" '[^=]*=\(.*\)'` if is_opaque_opt "$opt"; then true; elif is_file_opt "$opt"; then opt_arg=`convert_path "$opt_arg"` else die "darcs-wrapper: I don't think '$opt' accepts an argument." \ "[ If it does, then there is a bug in the wrapper script. ]" fi params[${#params[*]}]="$opt=$opt_arg" else # The option doesn't have an '=' opt="$arg" if is_opaque_opt "$opt"; then if [ $# -eq 0 ]; then die "darcs-wrapper: I think '$arg' requires an argument." \ "[ If it doesn't, then there is a bug in the wrapper script. ]" fi opt_arg="$1" shift params[${#params[*]}]="$opt" params[${#params[*]}]="$opt_arg" elif is_file_opt "$opt"; then if [ $# -eq 0 ]; then die "darcs-wrapper: I think '$arg' requires an argument." \ "[ If it doesn't, then there is a bug in the wrapper script. ]" fi opt_arg=`convert_path "$1"` shift params[${#params[*]}]="$opt" params[${#params[*]}]="$opt_arg" else params[${#params[*]}]="$opt" fi fi else if $convert_nonoption_args; then arg=`convert_path "$arg"` fi params[${#params[*]}]="$arg" (( num_nonoption_args += 1 )) fi done # DEBUG if $debug; then echo "ARGS:" for arg in "${params[@]}"; do echo " arg = '$arg'" done else # echo about to exec -a darcs "$darcs_binary" "${params[@]}" exec -a darcs "$darcs_binary" "${params[@]}" fi darcs-2.8.4/contrib/update_roundup.pl0000644001765600176560000000520412104371431017175 0ustar ganeshganesh#!/usr/bin/perl use strict; use warnings; # A script to update the status of an issue in a Roundup bug tracker # based on the format of a darcs patch name. # It is intended to be run from a darcs posthook. # The format we look for is: # resolved issue123 # in the first line of the patch. use Getopt::Long; use MIME::Lite; use XML::Simple; my $UPDATE_STRING="status=resolved"; if (scalar(@ARGV) == 1) { $UPDATE_STRING=$ARGV[0]; } unless ($ENV{DARCS_PATCHES_XML}) { die "DARCS_PATCHES_XML was expected to be set in the environment, but was not found. Are you running this from a Darcs 2.0 or newer posthook?" } my $xml = eval { XMLin($ENV{DARCS_PATCHES_XML}, forcearray=>['patch']); }; die "hmmm.. we couldn't parse your XML. The error was: $@" if $@; # $xml structure returned looks like this: # 'patch' => { # 'resolved issue123: adding t.t' => { # 'hash' => '20080215033723-20bb4-54f935f89817985a3e98f3de8e8ac9dad5e8e0e5.gz', # 'inverted' => 'False', # 'date' => '20080215033723', # 'author' => 'Mark Stosberg ', # 'local_date' => 'Thu Feb 14 22:37:23 EST 2008' # }, # 'some other patch' => { ... }, for my $patch_name (keys %{ $xml->{patch} }) { my $issue_re = qr/resolved? \s+ (issue ?\d+)/msxi; next unless ($patch_name =~ $issue_re); my $issue = $1; my $patch = $xml->{patch}{$patch_name}; # Using the Command Line would be a simpler alternative. # my $out = `roundup-admin -i /var/lib/roundup/trackers/darcs set $issue status=resolved`; # warn "unexpected output: $out" if $out; my $author = $patch->{author}; # If the Author name contains an @ sign, we take it to be an e-mail address. # Otherwise, we default to darcs-devel as the sender. my $email = ($author =~ m/\@/) ? $author : 'darcs-devel@darcs.net'; my $comment = $patch->{comment} ? "\n$patch->{comment}" : ''; my $patch_name_minus_status = $patch_name; $patch_name_minus_status =~ s/$issue_re(:?\s?)//; # Each patches can potentially update the status of a different issue, so generates a different e-mail my $msg = MIME::Lite->new( From => 'noreply@darcs.net', To =>'bugs@lists.osuosl.org', #To =>'mark@stosberg.com', Subject =>"[$issue] [$UPDATE_STRING]", Type =>'text/plain', Data => qq!The following patch sent by $email updated issue $issue with $UPDATE_STRING * $patch_name $comment ! ); $msg->send; # An alternative to actually sending, for debugging. # use File::Slurp; # write_file("msg-$patch->{hash}.out",$msg->as_string); } darcs-2.8.4/contrib/upload.cgi0000644001765600176560000000752712104371431015564 0ustar ganeshganesh#!/usr/bin/perl use strict; use File::Temp qw/ tempdir tempfile /; # this is a sample cgi script to accept darcs patches via POST # it simply takes patches and sends them using sendmail or # places them in a Maildir style mailbox. my $tmp_dir; # temporary directory, when placing patches to maildir # files are linked from $tmp_dir to $maildir $tmp_dir = "/tmp"; # target email addresses--leave blank to use To: header in patch contents. my $target_email; # target repository for patch testing. Leave blank to use DarcsURL header # in patch contents. my $target_repo; my $sendmail_cmd; # command to send patches with $sendmail_cmd = "/usr/sbin/sendmail -i -t $target_email"; my $maildir; # maildir to put patches to, replace sendmail #$maildir = "/tmp/maildir"; my $patch_test_cmd; # command to test patches with $patch_test_cmd = "darcs apply --dry-run --repodir 'TARGETREPO' 'TARGETPATCH'"; my $repo_get_cmd; # command to get testing repo # used only when $target_repo is blank $repo_get_cmd = "darcs get --lazy --repodir 'TARGETDIR' 'TARGETREPO'"; sub error_page { my ($m) = @_; print "Status: 500 Error accepting patch\n"; print "Content-Type: text/plain\n\n"; print($m || "There was an error processing your request"); print "\n"; exit 0; } sub success_page { print "Content-Type: text/plain\n\n"; print "Thank you for your contribution!\n"; exit 0; } if ($ENV{CONTENT_TYPE} eq 'message/rfc822') { my $m = start_message() or error_page("could not create temporary file"); my $fh = $m->{fh}; my ($totalbytes, $bytesread, $buffer); do { $bytesread = read(STDIN, $buffer, 1024); print $fh $buffer; $totalbytes += $bytesread; } while ($bytesread); my $r = end_message($m); $r ? error_page($r) : success_page(); } elsif ($ENV{CONTENT_TYPE}) { error_page("invalid content type, I expect something of message/rfc822"); } else { error_page("This url is for accepting darcs patches."); } sub maildir_file { my ($tmp_file) = @_; my $base_name = sprintf("patch-%d-%d-0000", $$, time()); my $count = 0; until (link("$tmp_file", "$maildir/$base_name")) { $base_name =~ s/-(\d+)$/"-" . (1 + $1)/e; return undef if $count++ > 100; } return "$maildir/$base_name"; } sub start_message { my ($fh, $fname) = tempfile("$tmp_dir/dpatch".'X'x8, UNLINK => 1) or return undef; return { fh => $fh, filename => $fname }; } sub end_message { my ($m) = @_; close $m->{fh} or return "$!: $m->{filename} - Could not close filehandle"; unless ($target_repo) { # Look for DarcsURL header my $darcsurl; open(MF,$m->{filename}) or return "$!: $m->{filename} - Could not open file"; while () { if (/^DarcsURL: (.+)$/) { $darcsurl = $1; last; } } close(MF); return "Could not find DarcsURL header" unless $darcsurl; my $test_dir = tempdir(CLEANUP => 1).'/repo' or return "$!: Could not create test directory"; $repo_get_cmd =~ s/TARGETDIR/$test_dir/; $repo_get_cmd =~ s/TARGETREPO/$darcsurl/; system("$repo_get_cmd >/dev/null 2>/dev/null") == 0 or return "Could not get target repo: '$repo_get_cmd' failed"; $target_repo = $test_dir; } $patch_test_cmd =~ s/TARGETREPO/$target_repo/; $patch_test_cmd =~ s/TARGETPATCH/$m->{filename}/; system("$patch_test_cmd >/dev/null 2>/dev/null") == 0 or return "Patch is not valid: '$patch_test_cmd' failed"; if ($maildir) { maildir_file("$m->{filename}") or return "$!: Could not create a new file in maildir"; } else { system("$sendmail_cmd < '$m->{filename}'") == 0 or return "$!: Could not send mail"; } return 0; } darcs-2.8.4/contrib/darcs-errors.hlint0000644001765600176560000000402112104371431017244 0ustar ganeshganesh-- Only report errors, since we use this as part of the testsuite. It needs to -- be easy to see what tripped up the testcase. ignore "Eta reduce" = "" ignore "Use camelCase" = "" ignore "Use const" = "" ignore "Use on" = "" ignore "Use foldr" = "" ignore "Use String" = "" ignore "Use string literal" = "" ignore "Use guards" = "" ignore "Use :" = "" ignore "Redundant brackets" = "" ignore "Redundant do" = "" ignore "Redundant return" = "" ignore "Redundant $" = "" ignore "Redundant lambda" = "" ignore "Use fewer imports" = "" ignore "Use better pragmas" = "" ignore "Use let" = "" ignore "Operator rotate" = "" ignore "Use foldl" = "" ignore "Unused LANGUAGE pragma" = "" -- The problem with Prelude readFile is that it's based on hGetContents, which -- is lazy by definition. This also means that unless you force consumption of -- the produced list, it will keep an fd open for the file, possibly -- indefinitely. This is called a fd leak. Other than being annoying and if done -- often, leading to fd exhaustion and failure to open any new files (which is -- usually fatal), it also prevents the file to be unlinked (deleted) on win32. -- On the other hand, *strict* bytestring version of readFile will read the whole -- file into a contiguous buffer, *close the fd* and return. This is perfectly -- safe with regards to fd leaks. Btw., this is *not* the case with lazy -- bytestring variant of readFile, so that one is unsafe as well. error "Avoid Prelude.readFile" = Prelude.readFile ==> Data.ByteString.readFile error "Avoid hGetContents" = System.IO.hGetContents ==> Data.ByteString.hGetContents error "Avoid BL.hGetContents" = Data.ByteString.Lazy.hGetContents ==> Data.ByteString.hGetContents error "Avoid BL.hGetContents" = Data.ByteString.Lazy.Char8.hGetContents ==> Data.ByteString.hGetContents -- error "Avoid BL.readFile" = Data.ByteString.Lazy.Char8.readFile ==> Data.ByteString.readFile -- error "Avoid BL.readFile" = Data.ByteString.Lazy.readFile ==> Data.ByteString.readFile darcs-2.8.4/doc/0000755001765600176560000000000012104371431012706 5ustar ganeshganeshdarcs-2.8.4/doc/src/0000755001765600176560000000000012104371431013475 5ustar ganeshganeshdarcs-2.8.4/doc/src/best_practices.tex0000644001765600176560000006651012104371431017221 0ustar ganeshganesh% This file (unlike the rest of darcs) is in the public domain. \chapter{Best practices} This chapter is intended to review various scenarios and describe in each case effective ways of using darcs. There is no one ``best practice'', and darcs is a sufficiently low-level tool that there are many high-level ways one can use it, which can be confusing to new users. \section{Creating patches} This section will lay down the concepts around patch creation. The aim is to develop a way of thinking that corresponds well to how darcs is behaving --- even in complicated situations. In a single darcs repository you can think of two ``versions'' of the source tree. They are called the \emph{working} and \emph{pristine} trees. \emph{Working} is your normal source tree, with or without darcs alongside. The only thing that makes it part of a darcs repository is the \verb!_darcs! directory in its root. \emph{Pristine} is the recorded state of the source tree. The pristine tree is constructed from groups of changes, called {\em patches\/} (some other version control systems use the term {\em changeset\/} instead of {\em patch\/}).\footnote{If you look inside \_darcs you will find files or directories named {\tt patches} and {\tt inventories}, which store all the patches ever recorded. If the repository holds a cached pristine tree, it is stored in a directory called {\tt pristine.hashed}.} Darcs will create and store these patches based on the changes you make in \emph{working}. \subsection{Changes} If \emph{working} and \emph{pristine} are the same, there are ``no changes'' in the working copy. Changes can be introduced (or removed) by editing the files in \emph{working}. They can also be caused by darcs commands, which can modify \emph{both} \emph{working} and \emph{pristine}. It is important to understand for each darcs command how it modifies \emph{working}, \emph{pristine} or both of them. \verb!whatsnew! (as well as \verb!diff!) can show the difference between \emph{working} and \emph{pristine} to you. It will be shown as a difference in \emph{working}. In advanced cases it need \emph{not} be \emph{working} that has changed; it can just as well have been \emph{pristine}, or both. The important thing is the difference and what darcs can do with it. \subsection{Keeping or discarding changes} If you have a difference in \emph{working}, you do two things with it: \verb!record! it to keep it, or \verb!revert! it to lose the changes.% \footnote{% Revert can undo precious work in a blink. To protect you from great grief, the discarded changes are saved temporarily so the latest revert can be undone with unrevert.} If you have a difference between \emph{working} and \emph{pristine}% ---for example after editing some files in \emph{working}---% \verb!whatsnew! will show some ``unrecorded changes''. To save these changes, use \verb!record!. It will create a new patch in \emph{pristine} with the same changes, so \emph{working} and \emph{pristine} are no longer different. To instead undo the changes in \emph{working}, use \verb!revert!. It will modify the files in \emph{working} to be the same as in \emph{pristine} (where the changes do not exist). \subsection{Unrecording changes} \verb!unrecord! is a command meant to be run only in private repositories. Its intended purpose is to allow developers the flexibility to undo patches that haven't been distributed yet. If you \verb!unrecord! a patch, that patch will be deleted from \emph{pristine}. This will cause \emph{working} to be different from \emph{pristine}, and \verb!whatsnew! to report unrecorded changes. The difference will be the same as just before that patch was \verb!record!ed. Think about it. \verb!record! examines what's different with \emph{working} and constructs a patch with the same changes in \emph{pristine} so they are no longer different. \verb!unrecord! deletes this patch; the changes in \emph{pristine} disappear and the difference is back. If the recorded changes included an error, the resulting flawed patch can be unrecorded. When the changes have been fixed, they can be recorded again as a new---hopefully flawless---patch. If the whole change was wrong it can be discarded from \emph{working} too, with \verb!revert!. \verb!revert! will update \emph{working} to the state of \emph{pristine}, in which the changes do no longer exist after the patch was deleted. Keep in mind that the patches are your history, so deleting them with \verb!unrecord! makes it impossible to track what changes you \emph{really} made. Redoing the patches is how you ``cover the tracks''. On the other hand, it can be a very convenient way to manage and organize changes while you try them out in your private repository. When all is ready for shipping, the changes can be reorganized in what seems as useful and impressive patches. Use it with care. All patches are global, so don't \emph{ever} replace an already ``shipped'' patch in this way! If an erroneous patch is deleted and replaced with a better one, you have to replace it in \emph{all} repositories that have a copy of it. This may not be feasible, unless it's all private repositories. If other developers have already made patches or tags in their repositories that depend on the old patch, things will get complicated. \subsection{Special patches and pending} The patches described in the previous sections have mostly been hunks. A \emph{hunk} is one of darcs' primitive patch types, and it is used to remove old lines and/or insert new lines. There are other types of primitive patches, such as \emph{adddir} and \emph{addfile} which add new directories and files, and \emph{replace} which does a search-and-replace on tokens in files. Hunks are always calculated in place with a diff algorithm just before \verb!whatsnew! or \verb!record!. But other types of primitive patches need to be explicitly created with a darcs command. They are kept in \emph{pending}, ie, in the file {\tt\_darcs/patches/pending}, until they are either recorded or reverted. \emph{Pending} can be thought of as a special extension of \emph{working}. When you issue, e.g., a darcs \verb!replace! command, the replace is performed on the files in \emph{working} and at the same time a replace patch is put in \emph{pending}. Patches in \emph{pending} describe special changes made in \emph{working}. The diff algorithm will fictively apply these changes to \emph{pristine} before it compares it to \emph{working}, so all lines in \emph{working} that are changed by a \verb!replace! command will also be changed in \emph{pending} and \emph{pristine} when the hunks are calculated. That's why no hunks with the replaced lines will be shown by \verb!whatsnew!; it only shows the replace patch in \emph{pending} responsible for the change. If a special patch is recorded, it will simply be moved to \emph{pristine}. If it is instead reverted, it will be deleted from \emph{pending} and the accompanying change will be removed from \emph{working}. Note that reverting a patch in pending is \emph{not} the same as simply removing it from pending. It actually applies the inverse of the change to \emph{working}. Most notable is that reverting an addfile patch will delete the file in \emph{working} (the inverse of adding it). So if you add the wrong file to darcs by mistake, \emph{don't} \verb!revert! the addfile. Instead use \verb!remove!, which cancels out the addfile in pending. \section{Using patches} % still basics This section will lay down the concepts around patch distribution and branches. The aim is to develop a way of thinking that corresponds well to how darcs is behaving --- even in complicated situations. A repository is a collection of patches. Patches have no defined order, but patches can have dependencies on other patches. Patches can be added to a repository in any order as long as all patches depended upon are there. Patches can be removed from a repository in any order, as long as no remaining patches depend on them. Repositories can be cloned to create branches. Patches created in different branches may conflict. A conflict is a valid state of a repository. A conflict makes the working tree ambiguous until the conflict is resolved. \subsection{Dependencies} There are two kinds of dependencies. Implicit dependencies is the far most common kind. These are calculated automatically by darcs. If a patch removes a file or a line of code, it will have to depend on the patch that added that file or line of code. If a patch adds a line of code, it will usually have to depend on the patch or patches that added the adjacent lines. Explicit dependencies can be created if you give the \verb|--ask-deps| option to \verb|darcs record|. This is good for assuring that logical dependencies hold between patches. It can also be used to group patches---% a patch with explicit dependencies doesn't need to change anything---% and pulling the patch also pulls all patches it was made to depend on. \subsection{Branches: just normal repositories} Darcs does not have branches---it doesn't need to. Any two repositories are ``branches'' in darcs, but it is not of much use unless they have a large portion of patches in common. If they are different projects they will have nothing in common, but darcs may still very well be able to merge them, although the result probably is nonsense. Therefore the word ``branch'' isn't a technical term in darcs; it's just the way we think of one repository in relation to another. Branches are \emph{very} useful in darcs. They are in fact \emph{necessary} if you want to do more than only simple work. When you \verb|get| someone's repository from the Internet, you are actually creating a branch of it. But darcs is designed this way, and it has means to make it efficient. The answer to many questions about how to do a thing with darcs is: ``use a branch''. It is a simple and elegant solution with great power and flexibility, which contributes to darcs' uncomplicated user interface. You create new branches (i.e., clone repositories) with the \verb|get| and \verb|put| commands. \subsection{Moving patches around---no versions} Patches are global, and a copy of a patch either is or is not present in a branch. This way you can rig a branch almost any way you like, as long as dependencies are fulfilled---% darcs \emph{won't} let you break dependencies. If you suspect a certain feature from some time ago introduced a bug, you can remove the patch/patches that adds the feature, and try without it.\footnote{% darcs even has a special command, {\tt trackdown} that automatically removes patches until a specified test no longer fails.} Patches are added to a repository with \verb|pull| and removed from the repositories with \verb|obliterate|. Don't confuse these two commands with \verb|record| and \verb|unrecord|, which constructs and deconstructs patches. It is important not to lose patches when (re)moving them around. \verb|pull| needs a source repository to copy the patch from, whereas \verb|obliterate| just erases the patch. Beware that if you obliterate \emph{all} copies of a patch it is completely lost---forever. Therefore you should work with branches when you obliterate patches. The \verb|obliterate| command can wisely be disabled in a dedicated main repository by adding \verb|obliterate disable| to the repository's defaults file. For convenience, there is a \verb|push| command. It works like \verb|pull| but in the other direction. It also differs from \verb|pull| in an important way: it starts a second instance of darcs to apply the patch in the target repository, even if it's on the same computer. It can cause surprises if you have a ``wrong'' darcs in your PATH. \subsection{Tags---versions} While \verb|pull| and \verb|obliterate| can be used to construct different ``versions'' in a repository, it is often desirable to name specific configurations of patches so they can be identified and retrieved easily later. This is how darcs implements what is usually known as versions. The command for this is \verb|tag|, and it records a tag in the current repository. A tag is just a patch, but it only contains explicit dependencies. It will depend on all the patches in the current repository.\footnote{% It will omit patches already depended upon by other patches, since they will be indirectly depended upon anyway.} Darcs can recognize if a patch is as a tag; tags are sometimes treated specially by darcs commands. While traditional revision control systems tag versions in the time line history, darcs lets you tag any configuration of patches at any time, and pass the tags around between branches. With the option \verb|--tag| to \verb|get| you can easily get a named version in the repository as a new branch. \subsection{Conflicts} A conflict \emph{happens} when two conflicting patches meet in the same repository. This is no problem for darcs; it can happily pull together just any patches. But it is a problem for the files in \emph{working} (and \emph{pristine}). The conflict can be thought of as two patches telling darcs different things about what a file should look like. Darcs escapes this problem by ignoring those parts of the patches that conflict. They are ignored in \emph{both} patches. If patch~A changes the line ``FIXME'' to ``FIXED'', and patch~B changes the same line to ``DONE'', the two patches together will produce the line ``FIXME''. Darcs doesn't care which one you pulled into the repository first, you still get the same result when the conflicting patches meet. All other changes made by A and B are performed as normal. Darcs can mark a conflict for you in \emph{working}. This is done with \verb|mark-conflicts|. Conflicts are marked such that both conflicting changes are inserted with special delimiter lines around them. Then you can merge the two changes by hand, and remove the delimiters. When you pull patches, darcs automatically performs a \verb|mark-conflicts| for you if a conflict happens. You can remove the markup with \verb|revert|, Remember that the result will be the lines from the previous version common to both conflicting patches. The conflict marking can be redone again with \verb|mark-conflicts|. A special case is when a pulled patch conflicts with unrecorded changes in the repository. The conflict will be automatically marked as usual, but since the markup is \emph{also} an unrecorded change, it will get mixed in with your unrecorded changes. There is no guarantee you can revert \emph{only} the markup after this, and \verb|mark-conflicts| will not be able to redo this markup later if you remove it. It is good practice to record important changes before pulling. \verb|mark-conflicts| can't mark complicated conflicts. In that case you'll have to use \verb|darcs diff| and other commands to understand what the conflict is all about. If for example two conflicting patches create the same file, \verb|mark-conflicts| will pick just one of them, and no delimiters are inserted. So watch out if darcs tells you about a conflict. \verb|mark-conflicts| can also be used to check for unresolved conflicts. If there are none, darcs replies ``No conflicts to mark.''. While \verb|pull| reports when a conflict happens, \verb|obliterate| and \verb|get| don't. \subsection{Resolving conflicts} A conflict is resolved (not marked, as with the command \verb|mark-conflicts|) as soon as some new patch depends on the conflicting patches. This will usually be the resolve patch you record after manually putting together the pieces from the conflict markup produced by \verb|mark-conflicts| (or \verb|pull|). But it can just as well be a tag. So don't forget to fix conflicts before you accidentally ``resolve'' them by recording other patches. If the conflict is with one of your not-yet-published patches, you may choose to amend that patch rather than creating a resolve patch. If you want to back out and wait with the conflict, you can \verb|obliterate| the conflicting patch you just pulled. Before you can do that you have to \verb|revert| the conflict markups that \verb|pull| inserted when the conflict happened. \section{Global and per-repository caches} Darcs uses a global cache, as this is one of its biggest performance enhancing tools. The global cache acts as a giant patch pool where darcs first looks for a patch when grabbing new patches. This saves time by not downloading the same patch twice from a remote server. It also saves space by storing the patch only once, if you ensure your cache and your repositories are on the same hardlink-supporting filesystem. Darcs now enables a global patch cache under your home directory by default. Older darcs 2.x versions required this manual step: \begin{verbatim} $ mkdir -p $HOME/.darcs/cache $ echo cache:$HOME/.darcs/cache > $HOME/.darcs/sources \end{verbatim} On MS Windows~\ref{ms_win}, using \verb|cmd.exe| (Command Prompt under Accessories): \begin{verbatim} > md "%APPDATA%\darcs\cache" (notice double quotes!) > echo cache:%APPDATA%\darcs\cache > "%APPDATA%\darcs\sources" \end{verbatim} Individual repositories also contain cache location information. Each time a repository is got, its location is added as an entry in \verb!_darcs/prefs/sources!. If one of these repositories were to become totally or temporarily unreachable, it can cause darcs to hang for a long time trying to reach it. Fortunately darcs has a mechanism which helps us to deal with that problem: if an unreachable entry is discovered, darcs stops using it for the rest of the session and then notifies the user to take further action. It will display a message like the following: \begin{verbatim}> I could not reach the following repository: > http://darcs.net/ > If you're not using it, you should probably delete > the corresponding entry from _darcs/prefs/sources. \end{verbatim} There are some other advanced things you can do in \verb!_darcs/prefs/sources!, such as create read-only caches and even set a primary source repository above any used in a \verb|darcs get| or \verb|darcs pull| command. \section{Distributed development with one primary developer} \label{darcs-development-practices} This is how a project with many contributors, but every contribution is reviewed and manually applied by the project leader, can be run. For this sort of a situation, \verb|darcs send| is ideal, since the barrier for contributions is very low, which helps encourage contributors. One could simply set the \verb!_darcs/prefs/email! value to the project mailing list, but you may also want to use darcs send to send your changes to the main server, so instead the email address could be set to something like ``\verb!Darcs Repo !''. Then the \verb-.procmailrc- file on the server should have the following rule: \begin{verbatim} :0 * ^TODarcs Repo |(umask 022; darcs apply --reply project-mailing-list@host.com \ --repodir /path/to/repo --verify /path/to/allowed_keys) \end{verbatim} This causes darcs apply to be run on any email sent to ``Darcs Repo''. \verb'apply' actually applies them only if they are signed by an authorized key. The central darcs repository contains the following values in its \verb!_darcs/prefs/defaults!: \begin{verbatim} apply test apply verbose apply happy-forwarding \end{verbatim} The first line tells apply to always run the test suite. The test suite can be a reason to use send rather than push, since it allows to easily continue working (or put one's computer to sleep) while the tests are being run on the main server. The second line is just there to improve the email response that the maintainer gets when a patch has either been applied or failed the tests. The third line makes darcs not complain about unsigned patches, but just to forward them to \verb!darcs-devel!. On one's development computer, one can have in their \verb!.muttrc! the following alias, which allows to easily apply patches received via email directly to one's darcs working directory: \begin{verbatim} macro pager A "(umask 022; darcs apply --no-test -v \ --repodir ~/darcs)" \end{verbatim} \section{Sending signed patches by email} Darcs send can be configured to send a cryptographically signed patch by email. You can then set up your mail system to have darcs verify that patches were signed by an authorized user and apply them when a patch is received by email. The results of the apply can be returned to the user by email. Unsigned patches (or patches signed by unauthorized users) will be forwarded to the repository owner (or whoever you configure them to be forwarded to\ldots). This method is especially nice when combined with the \verb!--test! option of darcs apply, since it allows you to run the test suite (assuming you have one) and reject patches that fail---and it's all done on the server, so you can happily go on working on your development machine without slowdown while the server runs the tests. Setting up darcs to run automatically in response to email is by far the most complicated way to get patches from one repository to another\ldots\ so it'll take a few sections to explain how to go about it. \paragraph{Security considerations} When you set up darcs to run apply on signed patches, you should assume that a user with write access can write to any file or directory that is writable by the user under which the apply process runs. Unless you specify the \verb!--no-test! flag to darcs apply (and this is \emph{not} the default), you are also allowing anyone with write access to that repository to run arbitrary code on your machine (since they can run a test suite---which they can modify however they like). This is quite a potential security hole. For these reasons, if you don't implicitly trust your users, it is recommended that you create a user for each repository to limit the damage an attacker can do with access to your repository. When considering who to trust, keep in mind that a security breach on any developer's machine could give an attacker access to their private key and passphrase, and thus to your repository. \paragraph{Installing necessary programs} You also must install the following programs: gnupg, a mailer configured to receive mail (e.g.\ exim, sendmail or postfix), and a web server (usually apache). \paragraph{Granting access to a repository} You create your gpg key by running (as your normal user): \begin{verbatim} $ gpg --gen-key \end{verbatim} You will be prompted for your name and email address, among other options. %%To add your public key to the allowed keys keyring. Of course, you can skip this step if you already have a gpg key you wish to use. You now need to export the public key so we can tell the patcher about it. You can do this with the following command (again as your normal user): \begin{verbatim} $ gpg --export "email@address" > /tmp/exported_key \end{verbatim} And now we can add your key to the \verb!allowed_keys!: \begin{verbatim} (as root)> gpg --keyring /var/lib/darcs/repos/myproject/allowed_keys \ --no-default-keyring --import /tmp/exported_key \end{verbatim} You can repeat this process any number of times to authorize multiple users to send patches to the repository. You should now be able to send a patch to the repository by running as your normal user, in a working copy of the repository: \begin{verbatim} $ darcs send --sign http://your.computer/repos/myproject \end{verbatim} You may want to add ``send sign'' to the file \verb!_darcs/prefs/defaults! so that you won't need to type \verb!--sign! every time you want to send\ldots If your gpg key is protected by a passphrase, then executing \verb!send! with the \verb!--sign! option might give you the following error: \begin{verbatim} darcs failed: Error running external program 'gpg' \end{verbatim} The most likely cause of this error is that you have a misconfigured gpg that tries to automatically use a non-existent gpg-agent program. GnuPG will still work without gpg-agent when you try to sign or encrypt your data with a passphrase protected key. However, it will exit with an error code 2 (\verb!ENOENT!) causing \verb!darcs! to fail. To fix this, you will need to edit your \verb!~/.gnupg/gpg.conf! file and comment out or remove the line that says: \begin{verbatim} use-agent \end{verbatim} If after commenting out or removing the \verb!use-agent! line in your gpg configuration file you still get the same error, then you probably have a modified GnuPG with use-agent as a hard-coded option. In that case, you should change \verb!use-agent! to \verb!no-use-agent! to disable it explicitly. \paragraph{Setting up a sendable repository using procmail} If you don't have root access on your machine, or perhaps simply don't want to bother creating a separate user, you can set up a darcs repository using procmail to filter your mail. Let us assume that you already use procmail to filter your email. If not, you will need to read up on it, or perhaps should use a different method for routing the email to darcs. To begin with, you must configure your repository so that a darcs send to your repository will know where to send the email. Do this by creating a file in \verb!/path/to/your/repo/_darcs/prefs! called \verb!email! containing your email address. As a trick (to be explained below), we will create the email address with ``darcs repo'' as your name, in an email address of the form ``User Name $<$user@host.com$>$.'' \begin{verbatim} $ echo 'my darcs repo ' \ > /path/to/your/repo/_darcs/prefs/email \end{verbatim} The next step is to set up a gnupg keyring containing the public keys of people authorized to send to your repository. Here is a second way of going about this (see above for the first). This time let us assume you want to give someone write access to your repository. You can do this by: \begin{verbatim} gpg --no-default-keyring \ --keyring /path/to/the/allowed_keys --recv-keys FFFFFFFF \end{verbatim} With ``FFFFFFFF'' being the ID of the gpg key of the person to be authorised, if this person has uploaded their key to the gpg keyservers. Actually, this also requires that you have configured gpg to access a valid keyserver. You can, of course, repeat this command for all keys you want to allow access to. Finally, we add a few lines to your \verb!.procmailrc!: \begin{verbatim} :0 * ^TOmy darcs repo |(umask 022; darcs apply --reply user@host.com \ --repodir /path/to/your/repo --verify /path/to/the/allowed_keys) \end{verbatim} The purpose for the ``my darcs repo'' trick is partially to make it easier to recognize patches sent to the repository, but is even more crucial to avoid nasty bounce loops by making the \verb!--reply! option have an email address that won't go back to the repository. This means that unsigned patches that are sent to your repository will be forwarded to your ordinary email. Like most mail-processing programs, Procmail by default sets a tight umask. However, this will prevent the repository from remaining world-readable; thus, the ``umask 022'' is required to relax the umask. (Alternatively, you could set Procmail's global \verb!UMASK! variable to a more suitable value.) \paragraph{Checking if your e-mail patch was applied} After sending a patch with \verb!darcs send!, you may not receive any feedback, even if the patch is applied. You can confirm whether or not your patch was applied to the remote repository by pointing \verb!darcs changes! at a remote repository: \begin{verbatim} darcs changes --last=10 --repo=http://darcs.net/ \end{verbatim} That shows you the last 10 changes in the remote repository. You can adjust the options given to \verb!changes! if a more advanced query is needed. darcs-2.8.4/doc/src/building_darcs.tex0000644001765600176560000000207612104371431017175 0ustar ganeshganesh\chapter{Building darcs} If your distribution provides a pre-built binary package of a recent Darcs release, you are strongly encouraged to use that rather than building Darcs yourself. If you have (or can install) the \htmladdnormallinkfoot{Haskell Platform}{http://haskell.org/platform/} this is the next best option, as this will resolve build dependencies automatically. To download, compile and install Darcs and its dependencies via \texttt{cabal-install}, the build tool provided by the Haskell Platform, simply run \begin{verbatim} cabal update cabal install darcs \end{verbatim} If you cannot install the Haskell Platform or \texttt{cabal-install}, you need to run \begin{verbatim} ghc --make Setup ./Setup configure ./Setup build ./Setup install \end{verbatim} This will require the following build dependencies: \begin{itemize} \item GHC 6.10 or higher; and \item Cabal 1.6 or higher. \end{itemize} Additional build dependencies are declared in the \texttt{darcs.cabal} file, and \texttt{./Setup configure} will tell you if any required build dependencies aren't found. darcs-2.8.4/doc/src/configuring_darcs.tex0000644001765600176560000005031512104371431017711 0ustar ganeshganesh% Copyright (C) 2004 David Roundy % % 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, 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. \chapter{Configuring darcs}\label{configuring} There are several ways you can adjust darcs' behavior to suit your needs. The first is to edit files in the \verb!_darcs/prefs/! directory of a repository. Such configuration only applies when working with that repository. To configure darcs on a per-user rather than per-repository basis (but with essentially the same methods), you can edit (or create) files in the \verb!~/.darcs/! directory. Finally, the behavior of some darcs commands can be modified by setting appropriate environment variables. \paragraph{Microsoft Windows}\label{ms_win} The global darcs directory is \verb!%APPDATA%\darcs\!. This typically expands to \texttt{C:\textbackslash{}Documents And Settings\textbackslash{}\emph{user}\textbackslash{}Application Data\textbackslash{}darcs\textbackslash{}}. This folder contains the cache, as well as all the per-user settings files: preferences, boring etc... These will became the new defaults that can be overridden on per-repository basis. \section{prefs} The \verb!_darcs! directory contains a \verb!prefs! directory. This directory exists simply to hold user configuration settings specific to this repository. The contents of this directory are intended to be modifiable by the user, although in some cases a mistake in such a modification may cause darcs to behave strangely. \paragraph{defaults}\label{defaults} Default values for darcs commands can be configured on a per-repository basis by editing (and possibly creating) the \verb!_darcs/prefs/defaults! file. Each line of this file has the following form: \begin{verbatim} COMMAND FLAG VALUE \end{verbatim} where \verb!COMMAND! is either the name of the command to which the default applies, or \verb!ALL! to indicate that the default applies to all commands accepting that flag. The \verb!FLAG! term is the name of the long argument option without the ``\verb!--!'', i.e.\ \verb!verbose! rather than \verb!--verbose!. Finally, the \verb!VALUE! option can be omitted if the flag is one such as \verb!verbose! that doesn't involve a value. If the value has spaces in it, use single quotes, not double quotes, to surround it. Each line only takes one flag. To set multiple defaults for the same command (or for \verb!ALL! commands), use multiple lines. Note that the use of \verb|ALL| easily can have unpredicted consequences, especially if commands in newer versions of darcs accepts flags that they didn't in previous versions. A command like \verb|obliterate| could be devastating with the ``wrong'' flags (for example --all). Only use safe flags with \verb|ALL|. \begin{tabular}{ll} {\tt \verb!~/.darcs/defaults!} & provides defaults for this user account (for MS Windows, see ~\ref{ms_win}) \\ {\tt \verb!repo/_darcs/prefs/defaults!} & provides defaults for one project,\\ & overrules changes per user \\ \end{tabular} For example, if your system clock is bizarre, you could instruct darcs to always ignore the file modification times by adding the following line to your \verb!_darcs/prefs/defaults! file. (Note that this would have to be done for each repository!) \begin{verbatim} ALL ignore-times \end{verbatim} If you never want to run a test when recording to a particular repository (but still want to do so when running \verb'check' on that repository), and like to name all your patches ``Stupid patch'', you could use the following: \begin{verbatim} record no-test record patch-name Stupid patch \end{verbatim} If you would like a command to be run every time patches are recorded in a particular repository (for example if you have one central repository, that all developers contribute to), then you can set apply to always run a command when apply is successful. For example, if you need to make sure that the files in the repository have the correct access rights you might use the following. There are two things to note about using darcs this way: \begin{itemize} \item Without the second line you will get errors, because the sub process that runs apply cannot prompt interactively. \item Whatever script is run by the post apply command should not be added to the repository with \verb!darcs add!; doing so would allow people to modify that file and then run arbitrary scripts on your main repository, possibly damaging or violating security. \end{itemize} \begin{verbatim} apply posthook chmod -R a+r * apply run-posthook \end{verbatim} Similarly, if you need a command to run automatically before darcs performs an action you can use a prehook. Using prehooks it could be possible to canonicalize line endings before recording patches. There are some options which are meant specifically for use in \verb!_darcs/prefs/defaults!. One of them is \verb!--disable!. As the name suggests, this option will disable every command that got it as argument. So, if you are afraid that you could damage your repositories by inadvertent use of a command like amend-record, add the following line to \verb!_darcs/prefs/defaults!: \begin{verbatim} amend-record disable \end{verbatim} Also, a global preferences file can be created with the name \verb!.darcs/defaults! in your home directory, on MS Windows~\ref{ms_win}. Options present there will be added to the repository-specific preferences. If they conflict with repository-specific options, the repository-specific ones will take precedence. \paragraph{repos} The \verb!_darcs/prefs/repos! file contains a list of repositories you have pulled from or pushed to, and is used for autocompletion of pull and push commands in bash. Feel free to delete any lines from this list that might get in there, or to delete the file as a whole. \paragraph{author}\label{author_prefs} The \verb!_darcs/prefs/author! file contains the email address (or name) to be used as the author when patches are recorded in this repository, e.g.\ \verb!David Roundy !. This file overrides the contents of the environment variables \verb!$DARCS_EMAIL! and \verb!$EMAIL!. \paragraph{boring}\label{boring} The \verb!_darcs/prefs/boring! file may contain a list of regular expressions describing files, such as object files, that you do not expect to add to your project. As an example, you could have: \begin{verbatim} \.hi$ \.o$ ^\.[^/] ^_ ~$ (^|/)CVS($|/) \end{verbatim} A newly created repository has a longer boring file that includes many common source control, backup, temporary, and compiled files. You may want to have the boring file under version control. To do this you can use darcs setpref to set the value ``boringfile'' to the name of your desired boring file (e.g.\ \verb-darcs setpref boringfile .boring-, where \verb-.boring- is the repository path of a file that has been darcs added to your repository). The boringfile preference overrides \verb!_darcs/prefs/boring!, so be sure to copy that file to the boringfile. You can also set up a ``boring'' regexps file in your home directory, named \verb!~/.darcs/boring!, (see \ref{ms_win} on MS Windows), which will be used with all of your darcs repositories. Any file not already managed by darcs and whose repository path (such as \verb!manual/index.html!) matches any of the boring regular expressions is considered boring. The boring file is used to filter the files provided to darcs add, to allow you to use a simple \verb-darcs add newdir newdir/-\verb-*- % cabal haddock barfs on adjacent / * without accidentally adding a bunch of object files. It is also used when the \verb!--look-for-adds! flag is given to whatsnew or record. Note that once a file has been added to darcs, it is not considered boring, even if it matches the boring file filter. \paragraph{binaries} The \verb!_darcs/prefs/binaries! file may contain a list of regular expressions describing files that should be treated as binary files rather than text files. Darcs automatically treats files containing \verb!^Z\! or \verb!'\0'! within the first 4096 bytes as being binary files. You probably will want to have the binaries file under version control. To do this you can use darcs setpref to set the value ``binariesfile'' to the name of your desired binaries file (e.g.\ \verb'darcs setpref binariesfile ./.binaries', where \verb'.binaries' is a file that has been darcs added to your repository). As with the boring file, you can also set up a \verb!~/.darcs/binaries! file if you like (see \ref{ms_win} on MS Windows). \paragraph{email} The \verb!_darcs/prefs/email! file is used to provide the e-mail address for your repository that others will use when they \verb!darcs send! a patch back to you. The contents of the file should simply be an e-mail address. \paragraph{sources} The \verb!_darcs/prefs/sources! file is used to indicate alternative locations from which to download patches when using a ``hashed'' repository. This file contains lines such as: \begin{verbatim} cache:/home/droundy/.darcs/cache readonly:/home/otheruser/.darcs/cache repo:http://darcs.net \end{verbatim} This would indicate that darcs should first look in \verb!/home/droundy/.darcs/cache! for patches that might be missing, and if the patch isn't there, it should save a copy there for future use. In that case, darcs will look in \verb!/home/otheruser/.darcs/cache! to see if that user might have downloaded a copy, but won't try to save a copy there, of course. Finally, it will look in \verb!http://darcs.net!. Note that the \verb!sources! file can also exist in \verb!~/.darcs/!. Also note that the sources mentioned in your \verb!sources! file will be tried \emph{before} the repository you are pulling from. This can be useful in avoiding downloading patches multiple times when you pull from a remote repository to more than one local repository. A global cache is enabled by default in your home directory. The cache allows darcs to avoid re-downloading patches (for example, when doing a second darcs get of the same repository), and also allows darcs to use hard links to reduce disk usage. Note that the cache directory should reside on the same filesystem as your repositories, so you may need to vary this. You can also use multiple cache directories on different filesystems, if you have several filesystems on which you use darcs. \paragraph{motd}\label{motd} The \verb!_darcs/prefs/motd! file may contain a ``message of the day'' which will be displayed to users who get or pull from the repository without the \verb!--quiet! option. \section{Environment variables} There are a few environment variables whose contents affect darcs' behavior. Here is a quick list of all the variables and their documentation in the rest of the manual: \begin{tabular}{|l|r|} \hline \textbf{Variable} & \textbf{Section} \\ \hline DARCS\_EDITOR, EDITOR, VISUAL & \ref{env:DARCS_EDITOR} \\ DARCS\_PAGER, PAGER & \ref{env:DARCS_PAGER} \\ HOME & \ref{env:HOME} \\ TERM & \ref{env:TERM} \\ \hline DARCS\_EMAIL, EMAIL & \ref{env:DARCS_EMAIL} \\ \hline DARCS\_APPLY\_FOO & \ref{env:DARCS_X_FOO} \\ DARCS\_GET\_FOO & \ref{env:DARCS_X_FOO} \\ DARCS\_MGET\_FOO & \ref{env:DARCS_X_FOO} \\ DARCS\_MGETMAX & \ref{env:DARCS_MGETMAX} \\ DARCS\_PROXYUSERPWD & \ref{env:DARCS_PROXYUSERPWD} \\ DARCS\_CONNECTION\_TIMEOUT & \ref{env:DARCS_CONNECTION_TIMEOUT}\\ DARCS\_SSH & \ref{env:DARCS_SSH} \\ DARCS\_SCP & \ref{env:DARCS_SCP} \\ DARCS\_SFTP & \ref{env:DARCS_SFTP} \\ SSH\_PORT & \ref{env:SSH_PORT} \\ \hline DARCS\_ALTERNATIVE\_COLOR & \ref{env:DARCS_ALWAYS_COLOR}\\ DARCS\_ALWAYS\_COLOR & \ref{env:DARCS_ALWAYS_COLOR}\\ DARCS\_DO\_COLOR\_LINES & \ref{env:DARCS_DO_COLOR_LINES}\\ DARCS\_DONT\_COLOR & \ref{env:DARCS_ALWAYS_COLOR} \\ DARCS\_DONT\_ESCAPE\_TRAILING\_CR & \ref{env:DARCS_DONT_ESCAPE_white}\\ DARCS\_DONT\_ESCAPE\_TRAILING\_SPACES & \ref{env:DARCS_DONT_ESCAPE_white} \\ DARCS\_DONT\_ESCAPE\_8BIT & \ref{env:DARCS_DONT_ESCAPE_nonascii}\\ DARCS\_DONT\_ESCAPE\_ANYTHING & \ref{env:DARCS_DONT_ESCAPE_nonascii}\\ DARCS\_DONT\_ESCAPE\_ISPRINT & \ref{env:DARCS_DONT_ESCAPE_nonascii}\\ DARCS\_ESCAPE\_EXTRA & \ref{env:DARCS_DONT_ESCAPE_nonascii}\\ DARCS\_DONT\_ESCAPE\_EXTRA & \ref{env:DARCS_DONT_ESCAPE_nonascii}\\ \hline \end{tabular} \section{General-purpose variables} \darcsEnv{DARCS_EDITOR} \darcsEnv{DARCS_PAGER} \darcsEnv{DARCS_TMPDIR} \darcsEnv{DARCS_KEEP_TMPDIR} \darcsEnv{HOME} \section{Remote repositories} \paragraph{DARCS\_CONNECTION\_TIMEOUT} \label{env:DARCS_CONNECTION_TIMEOUT} Set the maximum time in seconds that darcs allows and connection to take. If the variable is not specified the default are 30 seconds. This option only works with curl. \darcsEnv{DARCS_SSH} \darcsEnv{DARCS_SCP} \darcsEnv{SSH_PORT} \darcsEnv{HTTP_PROXY} \darcsEnv{DARCS_PROXYUSERPWD} \paragraph{DARCS\_GET\_FOO, DARCS\_MGET\_FOO and DARCS\_APPLY\_FOO} \label{env:DARCS_X_FOO} When trying to access a repository with a URL beginning foo://, darcs will invoke the program specified by the DARCS\_GET\_FOO environment variable (if defined) to download each file, and the command specified by the DARCS\_APPLY\_FOO environment variable (if defined) when pushing to a foo:// URL. This method overrides all other ways of getting \verb!foo://xxx! URLs. Note that each command should be constructed so that it sends the downloaded content to STDOUT, and the next argument to it should be the URL\@. Here are some examples that should work for DARCS\_GET\_HTTP: \begin{verbatim} fetch -q -o - curl -s -f lynx -source wget -q -O - \end{verbatim} Apart from such toy examples, it is likely that you will need to manipulate the argument before passing it to the actual fetcher program. For example, consider the problem of getting read access to a repository on a CIFS (SMB) share without mount privileges: \begin{verbatim} export DARCS_GET_SMB="smbclient -c get" darcs get smb://fs/twb/Desktop/hello-world \end{verbatim} The above command will not work for several reasons. Firstly, Darcs will pass it an argument beginning with `smb:', which smbclient does not understand. Secondly, the host and share `//fs/twb' must be presented as a separate argument to the path `Desktop/hello-world'. Thirdly, smbclient requires that `get' and the path be a single argument (including a space), rather than two separate arguments. Finally, smbclient's `get' command writes the file to disk, while Darcs expects it to be printed to standard output. In principle, we could get around such problems by making the variable contain a shell script, e.g. \begin{verbatim} export DARCS_GET_SMB='sh -c "...; smbclient $x -c \"get $y\""' \end{verbatim} Unfortunately, Darcs splits the command on whitespace and does not understand that quotation or escaping, so there is no way to make Darcs pass the text after `-c' to sh as a single argument. Therefore, we instead need to put such one-liners in separate, executable scripts. Continuing our smbclient example, we create an executable script \verb|~/.darcs/libexec/get_smb| with the following contents: \begin{verbatim} #!/bin/bash -e IFS=/ read host share file <<<"${1#smb://}" smbclient //$host/$share -c "get $file -" \end{verbatim} And at last we can say \begin{verbatim} export DARCS_GET_SMB=~/.darcs/libexec/get_smb darcs get smb://fs/twb/Desktop/hello-world \end{verbatim} If set, DARCS\_MGET\_FOO will be used to fetch many files from a single repository simultaneously. Replace FOO and foo as appropriate to handle other URL schemes. These commands are \emph{not} interpreted by a shell, so you cannot use shell metacharacters, and the first word in the command must be the name of an executable located in your path. The GET command will be called with a URL for each file. The MGET command will be invoked with a number of URLs and is expected to download the files to the current directory, preserving the file name but not the path. The APPLY command will be called with a darcs patchfile piped into its standard input. Example: \begin{verbatim} wget -q \end{verbatim} \paragraph{DARCS\_MGETMAX} \label{env:DARCS_MGETMAX} When invoking a DARCS\_MGET\_FOO command, darcs will limit the number of URLs presented to the command to the value of this variable, if set, or 200. These commands are \emph{not} interpreted by a shell, so you cannot use shell meta-characters. \section{Highlighted output} \label{env:DARCS_ALWAYS_COLOR} \label{env:DARCS_DO_COLOR_LINES} \label{env:DARCS_DONT_ESCAPE_white} If the terminal understands ANSI color escape sequences, darcs will highlight certain keywords and delimiters when printing patches. This can be turned off by setting the environment variable DARCS\_DONT\_COLOR to 1. If you use a pager that happens to understand ANSI colors, like \verb!less -R!, darcs can be forced always to highlight the output by setting DARCS\_ALWAYS\_COLOR to 1. If you can't see colors you can set DARCS\_ALTERNATIVE\_COLOR to 1, and darcs will use ANSI codes for bold and reverse video instead of colors. In addition, there is an extra-colorful mode, which is not enabled by default, which can be activated with DARCS\_DO\_COLOR\_LINES. By default darcs will escape (by highlighting if possible) any kind of spaces at the end of lines when showing patch contents. If you don't want this you can turn it off by setting DARCS\_DONT\_ESCAPE\_TRAILING\_SPACES to 1. A special case exists for only carriage returns: DARCS\_DONT\_ESCAPE\_TRAILING\_CR. \section{Character escaping and non-ASCII character encodings} \label{env:DARCS_DONT_ESCAPE_nonascii} Darcs needs to escape certain characters when printing patch contents to a terminal. Characters like \emph{backspace} can otherwise hide patch content from the user, and other character sequences can even in some cases redirect commands to the shell if the terminal allows it. By default darcs will only allow printable 7-bit ASCII characters (including space), and the two control characters \emph{tab} and \emph{newline}. (See the last paragraph in this section for a way to tailor this behavior.) All other octets are printed in quoted form (as \verb!^! or \verb!\!\verb!!). Darcs has some limited support for locales. If the system's locale is a single-byte character encoding, like the Latin encodings, you can set the environment variable DARCS\_DONT\_ESCAPE\_ISPRINT to 1 and darcs will display all the printables in the current system locale instead of just the ASCII ones. NOTE: This curently does not work on some architectures if darcs is compiled with GHC~6.4 or later. Some non-ASCII control characters might be printed and can possibly spoof the terminal. For multi-byte character encodings things are less smooth. UTF-8 will work if you set DARCS\_DONT\_ESCAPE\_8BIT to 1, but non-printables outside the 7-bit ASCII range are no longer escaped. E.g., the extra control characters from Latin-1 might leave your terminal at the mercy of the patch contents. Space characters outside the 7-bit ASCII range are no longer recognized and will not be properly escaped at line endings. As a last resort you can set DARCS\_DONT\_ESCAPE\_ANYTHING to 1. Then everything that doesn't flip code sets should work, and so will all the bells and whistles in your terminal. This environment variable can also be handy if you pipe the output to a pager or external filter that knows better than darcs how to handle your encoding. Note that \emph{all} escaping, including the special escaping of any line ending spaces, will be turned off by this setting. There are two environment variables you can set to explicitly tell darcs to not escape or escape octets. They are DARCS\_DONT\_ESCAPE\_EXTRA and DARCS\_ESCAPE\_EXTRA. Their values should be strings consisting of the verbatim octets in question. The do-escapes take precedence over the dont-escapes. Space characters are still escaped at line endings though. The special environment variable DARCS\_DONT\_ESCAPE\_TRAILING\_CR turns off escaping of carriage return last on the line (DOS style). darcs-2.8.4/doc/src/features.tex0000644001765600176560000000700312104371431016035 0ustar ganeshganesh\section{Features} \paragraph{Record changes locally} In darcs, the equivalent of a svn ``commit'' is called record, because it doesn't put the change into any remote or centralized repository. Changes are always recorded locally, meaning no net access is required in order to work on your project and record changes as you make them. \paragraph{Interactive records} You can choose to perform an interactive record, in which case darcs will prompt you for each change you have made and ask if you wish to record it. Of course, you can tell darcs to record all the changes in a given file, or to skip all the changes in a given file, or go back to a previous change, or whatever. \paragraph{Unrecord local changes} As a corollary to the ``local'' nature of the record operation, if a change hasn't yet been published to the world---that is, if the local repository isn't accessible by others---you can safely unrecord a change (even if it wasn't the most recently recorded change) and then re-record it differently, for example if you forgot to add a file, introduced a bug or realized that what you recorded as a single change was really two separate changes. \paragraph{Interactive everything else} Most darcs commands support an interactive interface. The ``revert'' command, for example, which undoes unrecorded changes has the same interface as record, so you can easily revert just a single change. Pull, push, send and apply all allow you to view and interactively select which changes you wish to pull, push, send or apply. \paragraph{Test suites} Darcs has support for integrating a test suite with a repository. If you choose to use this, you can define a test command (e.g.\ ``make check'') and have darcs run that command on a clean copy of the project either prior to recording a change or prior to applying changes---and to reject changes that cause the test to fail. \paragraph{Any old server} Darcs does not require a specialized server in order to make a repository available for read access. You can use http, ftp, or even just a plain old ssh server to access your darcs repository. \paragraph{You decide write permissions} Darcs doesn't try to manage write access. That's your business. Supported push methods include direct ssh access (if you're willing to \emph{give} direct ssh access away), using sudo to allow users who already have shell access to only apply changes to the repository, or verification of gpg-signed changes sent by email against a list of allowed keys. In addition, there is support for submission of patches by email that are not automatically applied, but can easily be applied with a shell escape from a mail reader. \paragraph{File and directory moves} Renames or moves of files and directories, of course are handled properly, so when you rename a file or move it to a different directory, its history is unbroken, and merges with repositories that don't have the file renamed will work as expected. \paragraph{Token replace} You can use the ``darcs replace'' command to modify all occurrences of a particular token (defined by a configurable set of characters that are allowed in ``tokens'') in a file. This has the advantage that merges with changes that introduce new copies of the old token will have the effect of changing it to the new token---which comes in handy when changing a variable or function name that is used throughout a project. \paragraph{Configurable defaults} You can easily configure the default flags passed to any command on either a per-repository or a per-user basis or a combination thereof. darcs-2.8.4/doc/src/gpl.tex0000644001765600176560000004446212104371431015013 0ustar ganeshganesh% This is the FSF GPL, reformatted as an appendix by David Roundy % This file is intended to be included in another file. \chapter{License} 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, or (at your option) any later version. \label{gpl} \section*{The GNU General Public License} \begin{center} Version 2, June 1991 Copyright \copyright\ 1989, 1991 Free Software Foundation, Inc. \bigskip 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA \bigskip Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. \end{center} \subsection*{Preamble} \begin{quote} The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software---to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. \end{quote} \begin{center} {\Large \sc GNU General Public License \\\vspace{3mm}Terms and Conditions For Copying, Distribution and Modification} \end{center} \begin{enumerate} \addtocounter{enumi}{-1} \item This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The ``Program'', below, refers to any such program or work, and a ``work based on the Program'' means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term ``modification''.) Each licensee is addressed as ``you''. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. \item You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. \item You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: \begin{enumerate} \item You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. \item You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. \item If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) \end{enumerate} These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. \item You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: \begin{enumerate} \item Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, \item Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, \item Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) \end{enumerate} The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. \item You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. \item You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. \item Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. \item If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. \item If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. \item The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and ``any later version'', you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. \item If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. \begin{center} {\Large\sc No Warranty } \end{center} \item {\sc Because the program is licensed free of charge, there is no warranty for the program, to the extent permitted by applicable law. Except when otherwise stated in writing the copyright holders and/or other parties provide the program ``as is'' without warranty of any kind, either expressed or implied, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose. The entire risk as to the quality and performance of the program is with you. Should the program prove defective, you assume the cost of all necessary servicing, repair or correction.} \item {\sc In no event unless required by applicable law or agreed to in writing will any copyright holder, or any other party who may modify and/or redistribute the program as permitted above, be liable to you for damages, including any general, special, incidental or consequential damages arising out of the use or inability to use the program (including but not limited to loss of data or data being rendered inaccurate or losses sustained by you or third parties or a failure of the program to operate with any other programs), even if such holder or other party has been advised of the possibility of such damages.} \end{enumerate} \begin{center} {\Large\sc End of Terms and Conditions} \end{center} \subsection*{Appendix: How to Apply These Terms to Your New Programs} If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the ``copyright'' line and a pointer to where the full notice is found. \begin{quote} $<$one line to give the program's name and a brief idea of what it does.$>$ \\ Copyright (C) $<$year$>$ $<$name of author$>$ \\ 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. \end{quote} Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: \begin{quote} Gnomovision version 69, Copyright (C) $<$year$>$ $<$name of author$>$ \\ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. \\ This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. \end{quote} The hypothetical commands {\tt show w} and {\tt show c} should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than {\tt show w} and {\tt show c}; they could even be mouse-clicks or menu items---whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a ``copyright disclaimer'' for the program, if necessary. Here is a sample; alter the names: \begin{quote} Yoyodyne, Inc., hereby disclaims all copyright interest in the program \\ `Gnomovision' (which makes passes at compilers) written by James Hacker. \\ $<$signature of Ty Coon$>$, 1 April 1989 \\ Ty Coon, President of Vice \end{quote} This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. darcs-2.8.4/doc/src/darcs.tex0000644001765600176560000016634612104371431015333 0ustar ganeshganesh% Copyright (C) 2002-2003 David Roundy % % 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, 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; see the file COPYING. If not, write to % the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, % Boston, MA 02110-1301, USA. \documentclass[oneside]{book} %\usepackage{color} \usepackage{fullpage} \usepackage{verbatim} \usepackage{html} \usepackage{fancyvrb} \newenvironment{code}{\comment}{\endcomment} % \newenvironment{code}{\color{blue}\verbatim}{\endverbatim} \begin{document} % Definition of title page: \title{Darcs User Manual} \date{ \darcsVersion } % icky newline before closing brace is to appease preproc.hs. \author{David Roundy} \maketitle \tableofcontents \chapter{Introduction} This manual provides a stable documentation for using darcs. To find more up-to-date and complementary information, please consult the \htmladdnormallinkfoot{darcs wiki}{http://wiki.darcs.net}. Darcs is a revision control system, along the lines of Subversion, Git or Mercurial. That means that it keeps track of various revisions and branches of your project, allows for changes to propagate from one branch to another. Darcs has two particularly distinctive features which differ from other revision control systems: \paragraph{Every source tree a branch} The primary simplifying notion of darcs is that \emph{every} copy of your source code is a full repository. This is dramatically different from Subversion, in which the normal usage is for there to be one central repository from which source code will be checked out. This has several advantages, since you can harness the full power of darcs in any scratch copy of your code, without committing your possibly destabilizing changes to a central repository. \paragraph{Darcs keeps track of changes rather than versions} In the world of darcs, the source tree is \emph{not} the fundamental object, but rather the patch is the fundamental object. Rather than a patch being defined in terms of the difference between two trees, a tree is defined as the result of applying a given set of patches to an empty tree. Moreover, these patches may be reordered without changing the tree. This makes many operations, like cherry-picking or merging, much more natural. \input{features.tex} \chapter{Getting started} This chapter will lead you through an example use of darcs, which hopefully will allow you to get started using darcs with your project. \section{Creating your repository} Creating your repository in the first place just involves telling darcs to create the special directory (called {\tt \_darcs}) in your project tree, which will hold the revision information. This is done by simply calling from the root directory of your project: \begin{verbatim} $ cd my_project/ $ darcs initialize \end{verbatim} This creates the \verb|_darcs| directory and populates it with whatever files and directories are needed to describe an empty project. You now need to tell darcs what files and directories in your project should be under revision control. You do this using the command \verb|darcs add|: \begin{verbatim} $ darcs add *.c Makefile.am configure.ac \end{verbatim} When you have added all your files (or at least, think you have), you will want to record your changes. ``Recording'' always includes adding a note as to why the change was made, or what it does. In this case, we'll just note that this is the initial version. \begin{verbatim} $ darcs record --all What is the patch name? Initial revision. \end{verbatim} Note that since we didn't specify a patch name on the command line we were prompted for one. If the environment variable `EMAIL' isn't set, you will also be prompted for your email address. Each patch that is recorded is given a unique identifier consisting of the patch name, its creator's email address, the date when it was created, and a random hash. \section{Making changes} Now that we have created our repository, make a change to one or more of your files. After making the modification run: \begin{verbatim} $ darcs whatsnew \end{verbatim} This should show you the modifications that you just made, in the darcs patch format. If you prefer to see your changes in a different format, read Section~\ref{whatsnew}, which describes the whatsnew command in detail. Let's say you have now made a change to your project. The next thing to do is to record a patch. Recording a patch consists of grouping together a set of related changes, and giving them a name. It also tags the patch with the date it was recorded and your email address. To record a patch simply type: \begin{verbatim} $ darcs record \end{verbatim} darcs will then prompt you with all the changes that you have made that have not yet been recorded, asking you which ones you want to include in the new patch. Finally, darcs will ask you for a name for the patch. You can now rerun whatsnew, and see that indeed the changes you have recorded are no longer marked as new. \section{Making your repository visible to others} How do you let the world know about these wonderful changes? Obviously, they must be able to see your repository. Currently the easiest way to do this is is to look for \htmladdnormallinkfoot{hosting services}{http://wiki.darcs.net/Hosting} for darcs repositories. You can also self-host your repositories by using any web server. The recommended way to do this (using apache in a UNIX environment) is to create a directory called {\tt /var/www/repos}, and then put a symlink to your repository there: \begin{verbatim} $ cd /var/www/repos $ ln -s /home/username/myproject . \end{verbatim} \section{Getting changes made to another repository} Ok, so your repository is browsable using any web browser\ldots\ so what? How does one get your changes into \emph{their} repository, where they can do some good? It couldn't be easier. One just \verb|cd| into their repository, and there type: \begin{verbatim} $ darcs pull http://your.server.org/repos/yourproject \end{verbatim} Darcs will check to see if you have recorded any changes that aren't in their current repository. If so, it'll prompt them for each one, to see which ones one want to add to their repository. Note that you may see a different series of prompts depending on your answers, since sometimes one patch depends on another, so if you answer yes to the first one, you won't be prompted for the second if the first depends on it. Of course, maybe people don't even have a copy of your repository. In that case they'd want to do a \begin{verbatim} $ darcs get http://your.server.org/repos/yourproject \end{verbatim} which gets the whole repository. Get, pull and push also work over ssh. Ssh-paths are of the same form accepted by scp, namely \verb|[username@]host:/path/to/repository|. \section{Moving patches from one repository to another} Darcs is flexible as to how you move patches from one repository to another. This section will introduce all the ways you can get patches from one place to another, starting with the simplest and moving to the most complicated. \subsection{Push} If you use ssh, you can use the push method to transfer changes. Push can also be used when the target repository is local, in which case ssh isn't needed. Note that you can use push to administer a multiple-user repository. You just need to create a user for the repository (or repositories), and give everyone with write access ssh access, perhaps using \verb!.ssh/authorized_keys!. Then they run \begin{verbatim} $ darcs push repouser@repo.server:repo/directory \end{verbatim} If you like this idea about creating a repository user to own a repository which is writable by a number of users, you have one other option. Push \verb!--apply-as! can run on either a local repository or one accessed with ssh, but uses \verb!sudo! to run a darcs apply command (having created a patch bundle as in send) as another user. You can add the following line in your \verb|sudoers| file to allow the users to apply their patches to a centralized repository: {\small \begin{verbatim} ALL ALL = (repo-user) NOPASSWD: /usr/bin/darcs apply --all --repodir /repo/path* \end{verbatim} } This method is ideal for a centralized repository when all the users have accounts on the same computer, if you don't want your users to be able to run arbitrary commands as repo-user. \subsection{All pulls} This method involves making each repository readable (by http, ftp, nfs-mounted disk, or a public web hosting), and you run \verb|darcs pull| in the repository you want to move the patch to. This is nice, as it doesn't require you to give write access to anyone else, and is reasonably simple. \subsection{Send and apply manually} Sometimes the push method is impossible because the owner of the main repository does not want or cannot create a user to write into it, and you cannot use the all-pull method because you cannot set up a web server on your machine, perhaps because it's behind a firewall or perhaps for security reasons, or because it is often turned off. In this case you can use \verb|darcs send| from that computer to generate a patch bundle for the remote repository. You can either let darcs email the patch for you, or save it as a file and transfer it by hand. Then in the destination repository the owner of that repository runs \verb|darcs apply| to apply the patches contained in the bundle. This is also quite a simple method since, like the all-pull method, it doesn't require that you give anyone write access to your repository. But it's less convenient, since the owner of the remote repository has to keep track of the patch bundle (in the email, or whatever). To use the send and apply method with email, the best is probably to create a \verb!_darcs/prefs/email! file in the target repository containing the email address of the maintainer. This way anyone who sends to this repository will automatically send the patch bundle to that email address. If you receive many patches by email, you probably will benefit by running darcs apply directly from your mail program. You can place in your \verb!.muttrc! the following: \begin{verbatim} auto_view text/x-patch text/x-darcs-patch macro pager A "darcs apply --verbose --mark-conflicts \ --reply droundy@abridgegame.org --repodir ~/darcs" \end{verbatim} which will allow you to view a sent patch, and then apply the patch directly from \verb!mutt!, sending a confirmation email to the person who sent you the patch. The autoview line relies on on the following lines, or something like them, being present in one's \verb!.mailcap!: \begin{verbatim} text/x-patch; cat; copiousoutput text/x-darcs-patch; cat; copiousoutput \end{verbatim} \input{configuring_darcs.tex} \input{best_practices.tex} \chapter{Darcs commands} The general format of a darcs command is \begin{verbatim} % darcs COMMAND OPTIONS ARGUMENTS ... \end{verbatim} Here \verb|COMMAND| is a command such as \verb|add| or \verb|record|, which of course may have one or more arguments. Options have the form \verb!--option! or \verb!-o!, while arguments vary from command to command. There are many options which are common to a number of different commands, which will be summarized here. If you wish, you may use any unambiguous beginning of a command name as a shortcut: for \verb!darcs record!, you could type \verb!darcs recor! or \verb!darcs rec!, but not \verb!darcs re! since that could be confused with \verb!darcs replace!, \verb!darcs revert! and \verb!darcs remove!. In some cases, \verb|COMMAND| actually consists of two words, a super-command and a subcommand. For example, the ``display the manifest'' command has the form \verb|darcs query manifest|. \paragraph{Command overview} Not all commands modify the ``patches'' of your repository (that is, the named patches which other users can pull); some commands only affect the copy of the source tree you're working on (your ``working directory''), and some affect both. This table summarizes what you should expect from each one and will hopefully serve as guide when you're having doubts about which command to use. \begin{center} \footnotetext[1]{But it affects the repository and working directory targeted by the push} \footnotetext[2]{As for the other end, see apply} \begin{tabular}{|c|c|c|} \hline affects & patches & working directory\\ \hline record & yes & no\\ \hline unrecord & yes & no\\ \hline rollback & yes & yes\\ \hline revert & no & yes\\ \hline unrevert & no & yes\\ \hline pull & yes & yes\\ \hline obliterate & yes & yes\\ \hline apply & yes & yes\\ \hline push\footnote{But it affects the repository and working directory targeted by the push} & no & no\\ \hline send\footnote{As for the other end, see apply} & no & no\\ \hline put\footnote{Creates a new repository} & no & no\\ \hline \end{tabular} \end{center} \section{Common options to darcs commands} \begin{options} --help \end{options} Every \verb|COMMAND| accepts \verb!--help! as an argument, which tells it to provide a bit of help. Among other things, this help always provides an accurate listing of the options available with that command, and is guaranteed never to be out of sync with the version of darcs you actually have installed (unlike this manual, which could be for an entirely different version of darcs). \begin{verbatim} % darcs COMMAND --help \end{verbatim} \begin{options} --disable \end{options} Every {\tt COMMAND} accepts the \verb!--disable! option, which can be used in \verb!_darcs/prefs/defaults! to disable some commands in the repository. This can be helpful if you want to protect the repository from accidental use of advanced commands like obliterate, unpull, unrecord or amend-record. \begin{options} --verbose, --quiet, --normal-verbosity \end{options} Most commands also accept the \verb!--verbose! option, which tells darcs to provide additional output. The amount of verbosity varies from command to command. Commands that accept \verb!--verbose! also accept \verb!--quiet!, which surpresses non-error output, and \verb!--normal-verbosity! which can be used to restore the default verbosity if \verb!--verbose! or \verb!--quiet! is in the defaults file. \begin{options} --debug, --debug-http \end{options} Many commands also accept the \verb!--debug! option, which causes darcs to generate additional output that may be useful for debugging its behavior, but which otherwise would not be interesting. Option \verb!--debug-http! makes darcs output debugging info for libcurl. \begin{options} --repodir \end{options} Another common option is the \verb!--repodir! option, which allows you to specify the directory of the repository in which to perform the command. This option is used with commands, such as whatsnew, that ordinarily would be performed within a repository directory, and allows you to use those commands without actually being in the repository directory when calling the command. This is useful when running darcs in a pipe, as might be the case when running \verb'apply' from a mailer. \begin{options} --remote-repo \end{options} Some commands, such as \verb'pull' require a remote repository to be specified, either from the command line or as a default. The \verb!--remote-repo! provides an alternative way to supply this remote repository path. This flag can be seen as temporarily ``replacing'' the default repository. Setting it causes the command to ignore the default repository (it also does not affect, i.e. overwrite the default repository). On the other hand, if any other repositories are supplied as command line arguments, this flag will be ignored (and the default repository may be overwritten). \paragraph{Selecting patches}\label{selecting} Many commands operate on a patch or patches that have already been recorded. There are a number of options that specify which patches are selected for these operations: \verb!--patch!, \verb!--match!, \verb!--tag!, and variants on these, which for \verb!--patch! are \verb!--patches!, \verb!--from-patch!, and \verb!--to-patch!. The \verb!--patch! and \verb!--tag! forms simply take (POSIX extended, aka \verb!egrep!) regular expressions and match them against tag and patch names. \verb!--match!, described below, allows more powerful patterns. The plural forms of these options select all matching patches. The singular forms select the last matching patch. The range (from and to) forms select patches after or up to (both inclusive) the last matching patch. These options use the current order of patches in the repository. darcs may reorder patches, so this is not necessarily the order of creation or the order in which patches were applied. However, as long as you are just recording patches in your own repository, they will remain in order. % NOTE --no-deps is implemented in SelectChanges.lhs, but documented here % for concistency. When a patch or a group of patches is selected, all patches they depend on get silently selected too. For example: \verb!darcs pull --patches bugfix! means ``pull all the patches with `bugfix' in their name, along with any patches they require.'' If you really only want patches with `bugfix' in their name, you should use the \verb!--no-deps! option, which makes darcs exclude any matched patches from the selection which have dependencies that are themselves not explicitly matched by the selection. For \verb!unrecord!, \verb!unpull! and \verb!obliterate!, patches that depend on the selected patches are silently included, or if \verb!--no-deps! is used selected patches with dependencies on not selected patches are excluded from the selection. \subsection{Match} Currently \verb!--match! accepts eight primitive match types, although there are plans to expand it to match more patterns. Also, note that the syntax is still preliminary and subject to change. The first match type accepts a literal string which is checked against the patch name. The syntax is \begin{verbatim} darcs annotate --summary --match 'exact foo+bar' \end{verbatim} This is useful for situations where a patch name contains characters that could be considered special for regular expressions. In this and the other match types, the argument must be enclosed in double quotes if it contains spaces. You can escape a quote in the argument with a backslash; backslash escapes itself, but it is treated literally if followed by a character other than a double quote or backslash, so it is typically not necessary to escape a backslash. No such escaping is necessary unless the argument is enclosed in double quotes. The second match type accepts a regular expression which is checked against the patch name. The syntax is \begin{verbatim} darcs annotate --summary --match 'name foo' \end{verbatim} Note that to match regexp metacharacters, such as \verb|(|, literally, they must be escaped with backslash along with any embedded double quotes. To match a literal backslash it must be written quadrupled in general, but often it need not be escaped, since backslash is only special in regexps when followed by a metacharacter. In the following example pairs, the first literal is matched by the second sequence in the match name: ``\verb|"|'':``\verb|\"|'', ``\verb|\|'':``\verb|\\\\|'', ``\verb|\x|'':``\verb|\x|'', ``\verb|(|'':``\verb|\(|''. The third match type matches the darcs hash for each patch: \begin{verbatim} darcs annotate --summary --match \ 'hash 20040403105958-53a90-c719567e92c3b0ab9eddd5290b705712b8b918ef' \end{verbatim} Note you need to provide the full hash string as above. This is intended to be used, for example, by programs allowing you to view darcs repositories (e.g.\ CGI scripts like viewCVS). The fourth match type accepts a regular expression which is checked against the patch author. The syntax is \begin{verbatim} darcs annotate --summary --match 'author foo' \end{verbatim} There is also support for matching by date. This is done using commands such as \begin{verbatim} darcs annotate --summary --match 'date "last week"' darcs annotate --summary --match 'date yesterday' darcs annotate --summary --match 'date "today 14:00"' darcs annotate --summary --match 'date "tea time yesterday"' darcs annotate --summary --match 'date "3 days before last year at 17:00"' darcs changes --from-match 'date "Sat Jun 30 11:31:30 EDT 2004"' \end{verbatim} Only English date specifications are supported---specifically you must use English day and month names. Also, only a limited set of time zones is supported (compatible with GNU coreutils' date parsing). Unrecognized zones are treated as UTC, which may result in the timestamps printed in change entries not being recognized by the date matching. You can avoid this problem on a POSIX-like system by running darcs in the UTC zone to get the times initially, e.g.: \begin{verbatim} TZ=UTC darcs changes \end{verbatim} When matching on the ISO format, a partial date is treated as a range. English dates can either refer to a specific day (``6 months ago',``day before yesterday''), or to an interval from some past date (``last month'') to the present. Putting this all together, if today is ``2004-07-24'' then the following matches should work: \begin{tabular}{|ll|} \hline \textbf{date} & \textbf{patches selected} \\ \hline 2004 & from 2004-01-01 up to and including 2004-12-31 \\ 2004-01 & from 2004-01-01 up to and including 2004-01-31 \\ 2004-01-01 & during 2004-01-01 \\ \hline today & during 2004-07-24 (starting midnight in your timezone) \\ yesterday & during 2004-07-23 \\ 6 months ago & during 2004-01-23 \\ \hline last 6 months & since 2004-01-23 \\ last month & since 2004-06-23 (not 2004-06-01!) \\ last week & since 2004-07-16 \\ \hline \end{tabular} For more precise control, you may specify an interval, either in a small subset of English or of \htmladdnormallinkfoot{the ISO 8601 format}{http://www.w3.org/TR/NOTE-datetime}. If you use the ISO format, note that durations, when specified alone, are interpreted as being relative to the current date and time. \begin{verbatim} darcs annotate --summary --match 'date "between 2004-03-12 and last week"' darcs annotate --summary --match 'date "after 2005"' darcs annotate --summary --match 'date "in the last 3 weeks"' darcs annotate --summary --match 'date "P3M/2006-03-17"' darcs annotate --summary --match 'date "2004-01-02/2006-03-17"' darcs annotate --summary --match 'date "P2M6D"' \end{verbatim} You may also prefer to combine date matching with a more specific pattern. \begin{verbatim} darcs annotate --summary --match 'date "last week" && name foo' \end{verbatim} The sixth match type accepts a regular expression which is checked against file paths that the patch touches. The syntax is \begin{verbatim} darcs annotate --summary --match 'touch foo/bar.c' \end{verbatim} The seventh match type accepts a regular expression which is checked against every hunk. The syntax is \begin{verbatim} darcs annotate --summary --match 'hunk "^instance .* Foo where$"' \end{verbatim} The eight match type accepts a regular expression which is checked against the long comment. The syntax is \begin{verbatim} darcs annotate --summary --match 'comment "remote repository"' \end{verbatim} The \verb!--match! pattern can include the logical operators \verb!&&!, \verb!||! and \verb!not!, as well as grouping of patterns with parentheses. For example \begin{verbatim} darcs annotate --summary --match 'name record && not name overrode' \end{verbatim} \begin{options} --ignore-times, --no-ignore-times \end{options} Darcs optimizes its operations by keeping track of the modification times of your files. This dramatically speeds up commands such as \verb!whatsnew! and \verb!record! which would otherwise require reading every file in the repository and comparing it with a reference version. However, there are times when this can cause problems, such as when running a series of darcs commands from a script, in which case often a file will be modified twice in the same second, which can lead to the second modification going unnoticed. The solution to such predicaments is the \verb!--ignore-times! option, which instructs darcs not to trust the file modification times, but instead to check each file's contents explicitly. \begin{options} --author \end{options} \darcsEnv{DARCS_EMAIL} \begin{options} --dont-compress, --compress \end{options} By default, darcs commands that write patches to disk will compress the patch files. If you don't want this, you can choose the \verb!--dont-compress! option, which causes darcs not to compress the patch file. \begin{options} --dry-run \end{options} The \verb!--dry-run! option will cause darcs not to actually take the specified action, but only print what would have happened. Not all commands accept \verb!--dry-run!, but those that do should accept the \verb!--summary! option. \begin{options} --summary, --no-summary \end{options} The \verb!--summary! option shows a summary of the patches that would have been pulled/pushed/whatever. The format is similar to the output format of \verb!cvs update! and looks like this: \begin{verbatim} A ./added_but_not_recorded.c A! ./added_but_not_recorded_conflicts.c a ./would_be_added_if_look_for_adds_option_was_used.h M ./modified.t -1 +1 M! ./modified_conflicts.t -1 +1 R ./removed_but_not_recorded.c R! ./removed_but_not_recorded_conflicts.c \end{verbatim} You can probably guess what the flags mean from the clever file names. \begin{description} \item{\texttt{A}} is for files that have been added but not recorded yet. \item{\texttt{a}} is for files found using the \verb!--look-for-adds! option available for \verb!whatsnew! and \verb!record!. They have not been added yet, but would be added automatically if \verb!--look-for-adds! were used with the next \verb!record! command. \item{\texttt{M}} is for files that have been modified in the working directory but not recorded yet. The number of added and subtracted lines is also shown. \item{\texttt{R}} is for files that have been removed, but the removal is not recorded yet. \end{description} An exclamation mark appears next to any option that has a conflict. \paragraph{Resolution of conflicts}\label{resolution} To resolve conflicts using an external tool, you need to specify a command to use, e.g. \begin{verbatim} --external-merge 'opendiff %1 %2 -ancestor %a -merge %o' \end{verbatim} The \verb!%1! and \verb!%2! are replaced with the two versions to be merged, \verb!%a! is replaced with the common ancestor of the two versions. Most importantly, \verb!%o! is replaced with the name of the output file that darcs will require to be created holding the merged version. The above example works with the FileMerge.app tool that comes with Apple's developer tools. To use xxdiff, you would use \begin{verbatim} --external-merge 'xxdiff -m -O -M %o %1 %a %2' \end{verbatim} To use \verb!kdiff3!, you can use \begin{verbatim} --external-merge 'kdiff3 --output %o %a %1 %2' \end{verbatim} To use \verb!tortoiseMerge!, you can use \begin{verbatim} --external-merge 'tortoiseMerge /base:"%a" /mine:"%1" /theirs:"%2" /merged:"%o"' \end{verbatim} (\verb!tortoiseMerge! is a nice merge tool that comes with TortoiseSVN and works well on Windows.) % Fixme: Is it actually a shell command on MS Windows? Note that the command is split into space-separated words and the first one is \verb!exec!ed with the rest as arguments---it is not a shell command. In particular, on Windows this means that the first command path should not contain spaces and you should make sure the command is in your \verb!PATH!. The substitution of the \verb!%! escapes is done everywhere. If you need to prevent substitution you can use a double percentage sign, i.e. \verb!%%a! is substituted with \verb!%a!. Here is an example script to use the Emacs' Ediff package for merging. % This is indented so that the leading #s don't confuse the preprocessor. \begin{verbatim} #! /bin/sh # External merge command for darcs, using Emacs Ediff, via server if possible. # It needs args %1 %2 %a %o, i.e. the external merge command is, say, # `emerge3 %1 %2 %a %o'. test $# -eq 4 || exit 1 form="(ediff-merge-files-with-ancestor" while test $# -gt 0; do count=$count. if [ $count = .... ]; then form=$form\ nil # Lisp STARTUP-HOOKS arg fi case $1 in # Worry about quoting -- escape " and \ *[\"\\]* ) form=$form\ \"$(echo $1 | sed -e's/["\\]/\\\0/g')\" ;; *) form=$form\ \"$1\" ;; esac shift done form=$form')' ( emacsclient --eval "$form" || # Emacs 22 server gnudoit "$form" || # XEmacs/Emacs 21 server emacs --eval "$form" || # Relatively slow to start up xemacs -eval "$form" # Horribly slow to start up ) 2>/dev/null \end{verbatim} It would be invoked like: \begin{verbatim} --external-merge 'emerge3 %1 %2 %a %o' \end{verbatim} Note that if you do use an external merge tool, most likely you will want to add to your defaults file (\verb!_darcs/prefs/defaults! or \verb!~/.darcs/prefs!, see \ref{defaults}, on MS Windows~\ref{ms_win}) a line such as \begin{verbatim} ALL external-merge kdiff3 --output %o %a %1 %2 \end{verbatim} or \begin{verbatim} ALL external-merge tortoiseMerge /base:"%a" /mine:"%1" /theirs:"%2" /merged:"%o" \end{verbatim} Note that the defaults file does not want quotes around the command. \begin{options} --sendmail-command \end{options} \darcsEnv{SENDMAIL} \subsection{Posthooks} \begin{options} --posthook=COMMAND, --no-posthook \end{options} To provide a command that should be run whenever a darcs command completes successfully, use \verb!--posthook! to specify the command. This is useful for people who want to have a command run whenever a patch is applied. Using \verb!--no-posthook! will disable running the command. \begin{options} --run-posthook, --prompt-posthook \end{options} These options control prompting before running the posthook. Use \verb!--prompt-posthook! to have darcs prompt before running the posthook command. You may use --run-posthook to reenable the default behavior of running user-specified posthooks. Some darcs commands export to the posthook command information about the changes being made. In particular, three environment variables are defined. \verb!DARCS_PATCHES! contains a human-readable summary of the patches being acted upon. The format is the same as "darcs changes". \verb!DARCS_PATCHES_XML! Contains the same details, in the same XML format as "darcs changes". Finally, \verb!DARCS_FILES! contains a list of the files affected, one file per line. If your repository has filenames including newlines, you'll just have to cope. Note, however, that \emph{none} of these environment variables are defined when running under windows. Note also that we refuse to pass environment variables greater in size than 10k, in order to avoid triggering \verb!E2BIG! errors. \subsection{Prehooks} \begin{options} --prehook=COMMAND, --no-prehook \end{options} To provide a command that should be run before a darcs command is executed, use \verb!--prehook! to specify the command. An example use is for people who want to have a command run whenever a patch is to be recorded, such as translating line endings before recording patches. Using \verb!--no-prehook! will disable running the command. \begin{options} --run-prehook, --prompt-prehook \end{options} These options control prompting before running the prehook. See the posthook documentation above for details. \begin{options} --http-pipelining, --no-http-pipelining \end{options} When compiled with libcurl (version 7.18.0 and above), darcs can use HTTP pipelining. It is enabled by default for libcurl (version 7.19.1 and above). This option will make darcs enable or disable HTTP pipelining, overwriting default. Note that if HTTP pipelining is really used depends on the server. \begin{options} --no-cache \end{options} Do not use patch caches. \begin{options} --umask \end{options} By default, Darcs will use your current umask. The option \verb|--umask| will cause Darcs to switch to a different umask before writing to the repository. \begin{options} --dont-restrict-paths, --restrict-paths \end{options} By default darcs is only allowed to manage and modify files and directories contained inside the current repository and not being part of any darcs repository's meta data (including the current one). This is mainly for security, to protect you from spoofed patches modifying arbitrary files with sensitive data---say, in your home directory---or tampering with any repository's meta data to switch off this safety guard. But sometimes you may want to manage a group of ``sub'' repositories' preference files with a global repository, or use darcs in some other advanced way. The best way is probably to put \verb!ALL dont-restrict-paths! in \verb!_darcs/prefs/defaults!. This turns off all sanity checking for file paths in patches. Path checking can be temporarily turned on with \verb!--restrict-paths! on the command line, when pulling or applying unknown patches. \begin{options} --allow-unrelated-repos \end{options} By default darcs checks and warns user if repositories are unrelated when doing pull, push and send. This option makes darcs skip this check. \section{Options apart from darcs commands} \begin{options} --help \end{options} Calling darcs with just \verb|--help| as an argument gives a brief summary of what commands are available. \begin{options} --version, --exact-version \end{options} Calling darcs with the flag \verb|--version| tells you the version of darcs you are using. Calling darcs with the flag \verb|--exact-version| gives the precise version of darcs, even if that version doesn't correspond to a released version number. This is helpful with bug reports, especially when running with a ``latest'' version of darcs. \begin{options} --commands \end{options} Similarly calling darcs with only \verb|--commands| gives a simple list of available commands. This latter arrangement is primarily intended for the use of command-line autocompletion facilities, as are available in bash. \section{Getting help} \darcsCommand{help} \section{Creating repositories} \darcsCommand{initialize} \darcsCommand{get} \section{Modifying the contents of a repository} \darcsCommand{add} \darcsCommand{remove} \darcsCommand{move} \darcsCommand{replace} \section{Working with changes} \darcsCommand{record} \begin{options} --ask-deps \end{options} Each patch may depend on any number of previous patches. If you choose to make your patch depend on a previous patch, that patch is required to be applied before your patch can be applied to a repository. This can be used, for example, if a piece of code requires a function to be defined, which was defined in an earlier patch. If you want to manually define any dependencies for your patch, you can use the \verb!--ask-deps! flag, and darcs will ask you for the patch's dependencies. It is possible to record a patch which has no actual changes but which has specific dependencies. This type of patch can be thought of as a ``partial tag''. The \verb!darcs tag! command will record a patch with no actual changes but which depends on the entire current inventory of the repository. The \verb!darcs record --ask-deps! with no selected changes will record a patch that depends on only those patches selected via the \verb!--ask-deps! operation, resulting in a patch which describes a set of patches; the presence of this primary patch in a repository implies the presence of (at least) the depended-upon patches. \begin{options} --pipe \end{options} If you run record with the \verb!--pipe! option, you will be prompted for the patch date, author, and the long comment. The long comment will extend until the end of file or stdin is reached (ctrl-D on Unixy systems, ctrl-Z on systems running a Microsoft OS). This interface is intended for scripting darcs, in particular for writing repository conversion scripts. The prompts are intended mostly as a useful guide (since scripts won't need them), to help you understand the format in which to provide the input. Here's an example of what the \verb!--pipe! prompts look like: \begin{verbatim} What is the date? Mon Nov 15 13:38:01 EST 2004 Who is the author? David Roundy What is the log? One or more comment lines \end{verbatim} \begin{options} --interactive \end{options} By default, \verb!record! works interactively. Probably the only thing you need to know about using this is that you can press \verb!?! at the prompt to be shown a list of the rest of the options and what they do. The rest should be clear from there. Here's a ``screenshot'' to demonstrate: \begin{verbatim} hunk ./hello.pl +2 +#!/usr/bin/perl +print "Hello World!\n"; Shall I record this patch? (2/2) [ynWsfqadjk], or ? for help: ? How to use record... y: record this patch n: don't record it w: wait and decide later, defaulting to no s: don't record the rest of the changes to this file f: record the rest of the changes to this file d: record selected patches a: record all the remaining patches q: cancel record j: skip to next patch k: back up to previous patch h or ?: show this help : accept the current default (which is capitalized) \end{verbatim} What you can't see in that ``screenshot'' is that \verb!darcs! will also try to use color in your terminal to make the output even easier to read. \darcsCommand{pull} \begin{options} --intersection, --union [DEFAULT], --complement \end{options} If you provide more than one repository as an argument to pull, darcs' behavior is determined by the presence of the \verb!--complement!, \verb!--intersection!, and \verb!--union! flags. \begin{itemize} \item The default (\verb!--union!) behavior is to pull any patches that are in any of the specified repositories. \item If you instead specify the \verb!--intersection! flag, darcs will only pull those patches which are present in all source repositories. \item If you specify the \verb!--complement! flag, darcs will only pull elements in the first repository that do not exist in any of the remaining repositories. \end{itemize} \begin{options} --external-merge \end{options} You can use an external interactive merge tool to resolve conflicts with the flag \verb!--external-merge!. For more details see subsection~\ref{resolution}. \begin{options} --matches, --patches, --tags, --no-deps \end{options} The \verb!--patches!, \verb!--matches!, \verb!--tags!, and \verb!--no-deps! options can be used to select which patches to pull, as described in subsection~\ref{selecting}. \begin{options} --no-test, --test \end{options} If you specify the \verb!--test! option, pull will run the test (if a test exists) on a scratch copy of the repository contents prior to actually performing the pull. If the test fails, the pull will be aborted. \begin{options} --verbose \end{options} Adding the \verb!--verbose! option causes another section to appear in the output which also displays a summary of patches that you have and the remote repository lacks. Thus, the following syntax can be used to show you all the patch differences between two repositories: \begin{verbatim} darcs pull --dry-run --verbose \end{verbatim} \darcsCommand{push} For obvious reasons, you can only push to repositories to which you have write access. In addition, you can only push to repos that you access either on the local file system or with ssh. In order to apply with ssh, darcs must also be installed on the remote computer. The command invoked to run ssh may be configured by the \verb!DARCS_SSH! environment variable (see subsection~\ref{env:DARCS_SSH}). The command invoked via ssh is always \verb!darcs!, i.e.\ the darcs executable must be in the default path on the remote machine. Push works by creating a patch bundle, and then running darcs apply in the target repository using that patch bundle. This means that the default options for \emph{apply} in the \emph{target} repository (such as, for example, \verb!--test!) will affect the behavior of push. This also means that push is somewhat less efficient than pull. When you receive an error message such as \begin{verbatim} bash: darcs: command not found \end{verbatim} then this means that the darcs on the remote machine could not be started. Make sure that the darcs executable is called \verb!darcs! and is found in the default path. The default path can be different in interactive and in non-interactive shells. Say \begin{verbatim} ssh login@remote.machine darcs \end{verbatim} to try whether the remote darcs can be found, or \begin{verbatim} ssh login@remote.machine 'echo $PATH' \end{verbatim} (note the single quotes) to check the default path. \begin{options} --apply-as \end{options} If you give the \verb!--apply-as! flag, darcs will use sudo to apply the changes as a different user. This can be useful if you want to set up a system where several users can modify the same repository, but you don't want to allow them full write access. This isn't secure against skilled malicious attackers, but at least can protect your repository from clumsy, inept or lazy users. \begin{options} --matches, --patches, --tags, --no-deps \end{options} The \verb!--patches!, \verb!--matches!, \verb!--tags!, and \verb!--no-deps! options can be used to select which patches to push, as described in subsection~\ref{selecting}. When there are conflicts, the behavior of push is determined by the default flags to \verb!apply! in the \emph{target} repository. Most commonly, for pushed-to repositories, you'd like to have \verb!--dont-allow-conflicts! as a default option to apply (by default, it is already the default\ldots). If this is the case, when there are conflicts on push, darcs will fail with an error message. You can then resolve by pulling the conflicting patch, recording a resolution and then pushing the resolution together with the conflicting patch. Darcs does not have an explicit way to tell you which patch conflicted, only the file name. You may want to pull all the patches from the remote repository just to be sure. If you don't want to do this in your working directory, you can create another darcs working directory for this purpose. If you want, you could set the target repository to use \verb!--allow-conflicts!. In this case conflicting patches will be applied, but the conflicts will not be marked in the working directory. If, on the other hand, you have \verb!--mark-conflicts! specified as a default flag for apply in the target repository, when there is a conflict, it will be marked in the working directory of the target repository. In this case, you should resolve the conflict in the target repository itself. \darcsCommand{send} Do not confuse the \verb!--author! options with the return address that \verb!darcs send! will set for your patch bundle. For example, if you have two email addresses A and B: \begin{description} \item If you use \verb!--author A! but your machine is configured to send mail from address B by default, then the return address on your message will be B. \item If you use \verb!--from A! and your mail client supports setting the From: address arbitrarily (some non-Unix-like mail clients, especially, may not support this), then the return address will be A; if it does not support this, then the return address will be B. \item If you supply neither \verb!--from! nor \verb!--author!, then the return address will be B. \end{description} In addition, unless you specify the sendmail command with \verb!--sendmail-command!, darcs sends email using the default email command on your computer. This default command is determined by the \verb!configure! script. Thus, on some non-Unix-like OSes, \verb!--from! is likely to not work at all. \begin{options} --output, --to, --cc \end{options} The \verb!--output!, \verb!--output-auto-name!, and \verb!--to! flags determine what darcs does with the patch bundle after creating it. If you provide an \verb!--output! argument, the patch bundle is saved to that file. If you specify \verb!--output-auto-name!, the patch bundle is saved to a file with an automatically generated name. If you give one or more \verb!--to! arguments, the bundle of patches is sent to those locations. The locations may either be email addresses or urls that the patch should be submitted to via HTTP. If you don't provide any of these options, darcs will look at the contents of the \verb!_darcs/prefs/email! file in the target repository (if it exists), and send the patch by email to that address. In this case, you may use the \verb!--cc! option to specify additional recipients without overriding the default repository email address. If \texttt{\_darcs/prefs/post} exists in the target repository, darcs will upload to the URL contained in that file, which may either be a \texttt{mailto:} URL, or an \texttt{http://} URL. In the latter case, the patch is posted to that URL. If there is no email address associated with the repository, darcs will prompt you for an email address. \begin{options} --subject \end{options} Use the \verb!--subject! flag to set the subject of the e-mail to be sent. If you don't provide a subject on the command line, darcs will make one up based on names of the patches in the patch bundle. \begin{options} --in-reply-to \end{options} Use the \verb!--in-reply-to! flag to set the In-Reply-To and References headers of the e-mail to be sent. By default no additional headers are included so e-mail will not be treated as reply by mail readers. \begin{options} --matches, --patches, --tags, --no-deps \end{options} The \verb!--patches!, \verb!--matches!, \verb!--tags!, and \verb!--no-deps! options can be used to select which patches to send, as described in subsection~\ref{selecting}. \begin{options} --edit-description \end{options} If you want to include a description or explanation along with the bundle of patches, you need to specify the \verb!--edit-description! flag, which will cause darcs to open up an editor with which you can compose a message to go along with your patches. \begin{options} --sendmail-command \end{options} If you want to use a command different from the default one for sending email, you need to specify a command line with the \verb!--sendmail-command! option. The command line can contain some format specifiers which are replaced by the actual values. Accepted format specifiers are \verb!%s! for subject, \verb!%t! for to, \verb!%c! for cc, \verb!%b! for the body of the mail, \verb!%f! for from, \verb!%a! for the patch bundle and the same specifiers in uppercase for the URL-encoded values. Additionally you can add \verb!%/dev/null' \end{verbatim} Then it runs the test command, for example \begin{verbatim} 'make && cd tests && sh /tmp/test.sh' \end{verbatim} While the test command exits with an error return code, darcs ``unapplies'' one patch from the version controlled files to retrieve an earlier version, and repeats the test command. If the test command finally succeeds, the name of the hunted down patch is found in the output before the last test run. The \verb!--bisect! variant of trackdown can be useful when the sought after patch is likely buried deep in the repository history; however, it currently requires an potentially expensive process of applying or unapplying half the repository's patches at a time. You may often find the straightforward linear trackdown to be more efficient in practice. \subsubsection{Example usage} If you want to find the last version of darcs that had a FIXME note in the file Record.lhs, you could run \begin{verbatim} % darcs trackdown 'grep FIXME Record.lhs' \end{verbatim} To find the latest version that compiles, you can run \begin{verbatim} % darcs trackdown 'autoconf' './configure && make' \end{verbatim} Trackdown can also be used to see how other features of the code changed with time. For example \begin{verbatim} % darcs trackdown 'autoconf; ./configure' \ "make darcs > /dev/null && cd ~/darcs && time darcs check && false" \end{verbatim} would let you see how long `darcs check' takes to run on each previous version of darcs that will actually compile. The ``\verb!&& false!'' ensures that trackdown keeps going. \darcsCommand{dist} \darcsCommand{put} \darcsCommand{fetch} \darcsCommand{convert} A project cannot mix both patch formats. By default, repositories created with `darcs initialize' are set to use the `darcs-2' format (\ref{initialize}). Cloning an existing repository with `darcs get' or `darcs put' preserves the patch format used. The `darcs-2' format improves on the `darcs-1' format in the following ways: \begin{itemize} \item The `exponential merge' problem is \emph{far} less likely to occur (it can still be produced in deliberately pathological cases). \item Identical primitive changes no longer conflict. For example, if two patches both attempt to add a directory `tests', these patches will not conflict. \end{itemize} \appendix \input{building_darcs.tex} \input{gpl.tex} \end{document} darcs-2.8.4/doc/darcs.css0000644001765600176560000000261512104371431014520 0ustar ganeshganeshBODY { background: white; color: black; font-family: arial,sans-serif; font-size: 90%; margin: 0; padding: 1em; } #col1, #col2 { float: left; width: 50%; } #col2 { margin-left: -1px; } .inner { margin: 0 1em; } A:link { background: transparent; color: #494a82; } A:visited { background: transparent; color: #8081b3 } IMG.thanks-left { float: left; margin-right: 5px; height: 50px; } IMG.thanks-right { float: right; margin-left: 5px; height: 50px; } BLOCKQUOTE.testimonial { font-style: italic; } PRE { background: #eeeeee; border: 1px solid #888888; color: black; padding: 1em; white-space: pre; } H1 { color: #494a82; font-size: 24px ; } H2 { color: #494a82; font-size: 18px; } H3 { color: #494a82; font-size: 16px; } H4 { color: #494a82; font-size: 14px; } /* headers for darcs command options */ .cmd-opt-hdr { color: #494a82; font-size: 14px; font-weight: bold; } /* begin styles for RSS Feed This is the most basic style to use for a list with no bullets */ .rss_title, rss_title a { margin: 0px 0; padding: 0; } .rss_items { list-style:none; margin:0; padding:0; } .rss_item { /* font-size: x-small; */ margin-bottom: 1em;; } .rss_item a:link, .rss_item a:visited, .rss_item a:active { } .rss_item a:hover { } .rss_date { font-size: xx-small; } darcs-2.8.4/COPYING0000644001765600176560000004310312104371431013175 0ustar ganeshganesh GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. darcs-2.8.4/release/0000755001765600176560000000000012104371431013561 5ustar ganeshganeshdarcs-2.8.4/release/distributed-version0000644001765600176560000000000612104371431017505 0ustar ganeshganeshJust 1darcs-2.8.4/release/distributed-context0000644001765600176560000001436212104371431017516 0ustar ganeshganeshJust "\nContext:\n\n[TAG 2.8.4\nGanesh Sittampalam **20130127231845\n Ignore-this: d032f69540341ecfd5858fce7aee1457\n] \n\n[Resolve issue2155: Expurgate the non-functional annotate --xml-output option\nDave Love **20130127231835\n Ignore-this: eb03207031e75687968091d56fb008f8\n backported from HEAD by Ganesh Sittampalam \n] \n\n[Resolve issue2155: Expurgate the non-functional annotate --xml-output option\nDave Love **20130120121739\n Ignore-this: 8a9ce6409a50b71cd0d2fdabbc181b1a\n backported from HEAD by Ganesh Sittampalam \n] \n\n[note dependency bumps in NEWS\nGanesh Sittampalam **20130120170310\n Ignore-this: 48cf181c89ec1b69fc6e9e701734ff19\n] \n\n[bump version to 2.8.4\nGanesh Sittampalam **20130120154856\n Ignore-this: 2f2542e9825b66cda3a0a17275b5e311\n] \n\n[resolve issue2199: getMatchingTag needs to commute for dirty tags\nGanesh Sittampalam **20121218191024\n Ignore-this: 947252cd8e084b793044aff564f0462d\n backported from HEAD\n] \n\n[accept issue2199: darcs get --tag gets too much\nGanesh Sittampalam **20120528164525\n Ignore-this: 8c138a80c294e6181a3ef9250593fa31\n] \n\n[constrain haskeline version on old GHC\nGanesh Sittampalam **20130119234432\n Ignore-this: 8af00cc3d3c1ad223a8b35712c06bae\n] \n\n[Add option -a to darcs changes in Setup.lhs\nBen Franksen **20120811195807\n Ignore-this: f23d2e558f7248fec8d07b0391d9a7e8\n \n Some (potential) contributors (like me) have 'changes interactive'\n in their ~/.darcs/defaults and then wonder why their build hangs.\n] \n\n[add copyright notices for the imported haskeline code\nGanesh Sittampalam **20130119163610\n Ignore-this: afcdc8048f8b3233fa17d3ab0c9c311f\n licence/copyright taken from haskeline 0.6.4.7:\n BSD3, copyright Judah Jacobson\n] \n\n[import encoding code from haskeline: switch over\nGanesh Sittampalam **20130118231907\n Ignore-this: b423a92ba93e74520d0578ac21aceab3\n] \n\n[import encoding code from haskeline: source files\nGanesh Sittampalam **20130118225947\n Ignore-this: c2d1e228fa4cce3e66e90a14fa2f3200\n] \n\n[import encoding code from haskeline: cabal file changes\nGanesh Sittampalam **20130118070642\n Ignore-this: d2ed13887d0c547cb7498bd5a2aef46f\n] \n\n[import encoding code from haskeline: Setup.lhs changes\nGanesh Sittampalam **20130115181040\n Ignore-this: 31ccdca76001bff769464fb7a8e574e9\n] \n\n[ROLLBACK: conditionally use bytestring-handle\nGanesh Sittampalam **20130111213829\n Ignore-this: d3c18b61f765bdfcb574b4977185197b\n It doesn't skip invalid byte sequences when decoding so breaks on \n repositories with non-UTF8 encoded metadata.\n] \n\n[bump network dependency\nGanesh Sittampalam **20130111184607\n Ignore-this: 54e55fa09793008d55572b6acad1a7b8\n] \n\n[add some comments about \"nearby\" darcs, and print out the one that was found\nGanesh Sittampalam **20130111211817\n Ignore-this: 57385f3248fc539435ed9de069a40bd5\n backported from HEAD\n] \n\n[make darcs-test look \"nearby\" for a darcs exe to use\nGanesh Sittampalam **20130111211445\n Ignore-this: d952cf330c0d9510c5c973dd41b191e0\n backported from HEAD\n] \n\n[need different path separator on Windows\nGanesh Sittampalam **20121219191221\n Ignore-this: 42c7ba1e46f5b6b600d23838e5a162cb\n] \n\n[test for issue2286: make sure we can read repos with non-UTF8 metadata\nGanesh Sittampalam **20130102222735\n Ignore-this: adc6165d5d5d991383ebf0e6547f7bf4\n] \n\n[We can use chcp to switch encodings on Windows\nGanesh Sittampalam **20130101122254\n Ignore-this: bc115467e31e144694a33e43dca3fb6c\n This means that the tests that require different encodings can run.\n] \n\n[Find latin9 locale on OS X too\nMichael Hendricks **20120420202408\n Ignore-this: c87db3b97312234ed2380d2ca11a8ca0\n \n Most Linux systems describe latin9 as \"iso885915\". OS X\n describes it with \"ISO8859-15\". The new regex catches both.\n] \n\n[windows test fix: replace shell script with a Haskell program\nGanesh Sittampalam **20121231224332\n Ignore-this: de01ab8647e7d62c18d8c266d514b054\n] \n\n[unsetting DARCS_TEST_PREFS_DIR in utf8 test doesn't seem to be necessary\nGanesh Sittampalam **20130101120246\n Ignore-this: ed74710d8b358b920d742e86a7f008d8\n \n It was causing problems on Windows because getAppUserDataDirectory\n still returns the normal user directory.\n \n It also means that the repository type choice isn't picked up.\n] \n\n[improve diagnostics when utf8 test fails\nGanesh Sittampalam **20121231224600\n Ignore-this: 63db587bc36f8826c66dc6913a4fdb2d\n] \n\n[need to do case-insensitive comparison on Windows\nGanesh Sittampalam **20121228214823\n Ignore-this: ef309d4aef22e87d5c3da3222926af0e\n] \n\n[update NEWS\nGanesh Sittampalam **20121216202654\n Ignore-this: aef3e47204a4157504f90554ffc3a327\n] \n\n[conditionally use bytestring-handle instead of haskeline for encoding\nGanesh Sittampalam **20121216201745\n Ignore-this: fd758796b689d090d01e003e660e405\n This is transitional because we need to support GHC 6.10: we can switch\n over to bytestring-handle unconditionally on HEAD.\n] \n\n[bump deps for GHC 7.6/latest hackage\nGanesh Sittampalam **20121216201543\n Ignore-this: 77829b074a4bff635a421879bdd04be0\n] \n\n[conditionally support tar 0.4\nGanesh Sittampalam **20121216201014\n Ignore-this: 8eff0330e6af196727bdd736ef31db25\n] \n\n[recent test-framework seems to require Typeable\nGanesh Sittampalam **20121216175601\n Ignore-this: a8cce6b69984bfc2335b5c19688950b3\n] \n\n[stop using Prelude.catch\nGanesh Sittampalam **20121216163240\n Ignore-this: b4bfc48775b3337f8f7ebe275be1a058\n \n backported from HEAD\n] \n\n[import constructors of C types to deal with a GHC change\nGanesh Sittampalam **20120401132500\n Ignore-this: ab7cf2fb5e9a2494c14fe7394200da9b\n] \n\n[TAG 2.8.3\nGanesh Sittampalam **20121104174910\n Ignore-this: 3198f6deecf3d1b44df6e05a2657d9ca\n] \n"darcs-2.8.4/README0000644001765600176560000000574612104371431013035 0ustar ganeshganeshDarcs ===== This is the source tree for darcs, a distributed version control system written in Haskell. For more information, visit the darcs web site: http://www.darcs.net Compilation and Installation ============================ Building Darcs is best done with the Haskell Platform: http://www.haskell.org/platform/. Any release of darcs should build with the most recent version of the Platform at the time of the release. This will also generally apply to unstable versions. If you are not using the Platform, then you need GHC and Cabal. The versions required can be found in the darcs.cabal file under 'build-tools' and 'Cabal-Version' respectively. The cabal-install package is also recommended. If you have the Platform or otherwise have the "cabal-install" package on your system (that is, there is a "cabal" executable in your path), you can use the following command to create an executable in ~/.cabal/bin/darcs (this will also automatically fetch and build dependencies from the Hackage server). $ cabal update $ cabal install Otherwise, if you have the "cabal" package but not the "cabal-install" package, run the following: $ runghc Setup configure $ runghc Setup build $ sudo runghc Setup install You may also omit the last step and copy the darcs executable (found in dist/build/darcs/darcs) to a location of your choosing. More detailed instructions can be found at including instructions on obtaining a copy of cabal-install. Please also note that the cabal-based build by default requires the cURL library (and development headers). If, for some reason, you cannot provide cURL, please pass "-f-curl" to the configure step above. Hacking ======= For more information about darcs hacking and best practices please check the darcs wiki at http://wiki.darcs.net Of particular interest are the following documents: * http://wiki.darcs.net/Development/GettingStarted * http://wiki.darcs.net/Development/FAQ Comments about do-notation warnings =================================== You may find a number of comments (163 of them at the time of writing) looking like: -- Warning: A do-notation statement discarded a result of type Whatever. They signal warnings issued by GHC that have been automatically silenced. See http://bugs.darcs.net/issue1988 for more detail. These warnings were most certainly harmless, but who knows... If you stumble upon one such comment, take a minute or two to check if it is really okay to ignore the return value (look for "_ <- " on the line next to the comment). If everything is correct, please remove the comment and send a patch (mentioning issue1988). If it isn't, you have found a bug, congratulations! Fix it, or fill a bug report on http//bugs.darcs.net/. Finally, if in doubt, leave it as is. Many thanks. Testing ======= For more information about the test suite, including how to run specific tests please read tests/README.test_maintainers.txt. Happy hacking! darcs-2.8.4/NEWS0000644001765600176560000033275312104371431012655 0ustar ganeshganesh * GHC 7.6 support * Bump some dependencies: base, network, unix, containers, bytestring, tar * Resolved issue2199: get --tag can include extra patches * Remove the --xml-output option to annotate: it stopped having any effect some time ago Darcs 2.8.3, 4 November 2012 * Darcs API: #ifdef some FFI imports so ghci works with -f-curl * Darcs API: Use darcs-specific names in sha2.c to avoid clashes with other packages Darcs 2.8.2, 3 September 2012 * Added PrimV1Job type to API to support darcsden Darcs 2.8.1, 14 May 2012 * Bumped mtl dependency * Updated contact details to use development mailing list Darcs 2.8, 22 April 2012 * Important changes in Darcs 2.8 * Local support for the legacy "old-fashioned" repository format has been removed. * You can still work with remote repositories in this format * Local repositories can still be upgraded via "darcs optimize --upgrade". * "darcs annotate" is now significantly faster and uses less memory, although it still slows down linearly with repository size. * An experimental option is available to speed up HTTP downloads. * You can now use "darcs optimize --http" to create a repo optimized for HTTP downloads, and use "darcs get --packs" to download such a repo. * There are still some known issues with it, so the feature is not enabled by default. * Darcs now supports multiple email addresses for the author in the global prefs file. So, if you use different identities for home and work, you can now easily select between them. (issue1530) * The -o/-O options for obliterate which were removed in 2.5 are back. * "darcs status" has been added as a hidden alias for "darcs whatnew -ls" to ease the transition from some other source control systems. (issue182) * "darcs amend-record" now has the option --unrecord to allow individual changes to be unrecorded. (issue1470). This can also be used as "darcs amend-unrecord". * "darcs amend-record"'s interactive selection now supports 'k' for going back to a previous patch. * "darcs dist" now has the option --set-scripts-executable. (issue734) * pushing to ssh:// URLS is now supported. eg: darcs push ssh://code.haskell.org/foo * If a test fails during darcs record, you now have the option to record it anyway. (issue332) * Hunk-splitting now works in "darcs revert" (issue114) * Sending patches by email is now more robust and human friendly. We display a cleaner version in plain text for humans, and have added a complete version of the patch for "darcs apply". (issue1350) * "darcs send" now tries to report the right character set in the email headers, and has the option --charset to override this. * A new environment variable has been added to help control network connections: DARCS\_CONNECTION\_TIMEOUT. See the manual for details. * The --ephemeral and --partials options to "darcs get" has been removed. "darcs check --partial" has also been removed. * "darcs rollback" now has a --no-record option, to be used when you only want to update the working directory. * The --nolinks option for "darcs get" was removed. * The "--old" flag has been removed for "darcs init", "darcs get" and "darcs put". * "darcs resolve" has been removed an alias for "darcs mark-conflicts". * "darcs init" and "darcs get" now have a --no-working-dir option. * Conflicts are now marked with red in the terminal. (issue1681) * ssh ControlMaster support has been removed. * ssh stderr output is now passed through, making it easier to diagnose problems. (issue845) * Interactive selection now has a 'g' command to go to the first patch. * The --unified flag is now available for record, end-record, revert and unrevert (issue1166) * darcs now has a "darcs test" command for running whatever test-suite is associated with the repository. * Other issues resolved in Darcs 2.8 * 1266: "darcs init" now warns when run inside another darcs repo. * 1344: When using darcs send, let users know sooner if they won't eventually be able to send * 1397: darcs changes /bad /paths no longer lists all changes * 1473: problem with annotate --repodir * 1551: Now we only use 'file content did not change' prompt for darcs send * 1558: xml output for patch hash no longer includes "gz" extension * 1599: automatically expire unused caches * 1637: When darcs get fails due to a HTTP failure, port the actual HTTP failure. * 1640: darcs apply --verbose docs have been improved * 1661: darcs add --quiet is quieter * 1705: fix error with unhandled --index in "darcs show contents" * 1714: provide more sensible behavior when combining an "ALL" default with a default for a specific sub-command * 1727: a better diagnostic message is provided when the user tries to move the root of the repository * 1740: "darcs mv" now gracefully the handles the case where the user first does an "mv" on a directory and then follows up with a "darcs mv" * 1804: The diagnostic message "getSymbolicLinkStatus: does not exist" has been improved * 1883: rename --patch-name option to --name. This is usually used in darcs record in shorthand (-m) form. This rename is aimed at eliminating the confusion with the patch matcher, which bites amend-record and rollback users. * 1884: darcs get was wrongly reporting "getting lazy repository" when you hit C-c * 1908: try to create a global cache before checking its availability * 1922: Fixed bug where obliterate -o was producing incorrect bundles in some cases * 1923: bad source warning mechanism no longer warns about sources outside your control * 1932: Handling of files with colons is improved * 1965: attempting "darcs move" on non-repo files now gives a sensible error * 1977: "darcs repair" now no longer complains if the pristine.hashed directory is missing * 1978: Improve handling of the _darcs/format file with "darcs get" * 1984: "darcs convert" now gives a better error message for invalid repo names * 2013: "darcs send" no longer ignores --to (or default recipient) with --context * 2021: character encoding handling has been improved * 2041: "darcs add" no longer follows directory symlinks * 2054: The behavior when combining --boring with a boring file has been improved * 2066: "darcs record" better handles adding deleted and added files passed on the command line * 2067: darcs diff no longer outputs blank lines when non-existent files are given * 2076: "darcs move myfile" into directory confuses darcs * 2077: "darcs mv myfile" into directory no longer confuses darcs * 2079: "darcs put" now does --set-default by default Darcs 2.5.2, 14 March 2011 * Important changes in Darcs 2.5.2 * compatible with Haskell Platform 2011.2.0.0 * bump parsec dependency for HP compatibility * fix regression allowing to add files inside boring directories * Issues resolved in Darcs 2.5.2 * 2049: Darcs regression: 2.5 creates a broken patch Darcs 2.5.1, 10 February 2011 * Important changes in Darcs 2.5.1 * original text is included in conflict marks * GHC 7.0 is supported * the version of GHC is restricted in the cabal file * warning message about old-fashioned repositories points to wiki * non-repository paths are guarded * library API: program name is configurable * darcs send prints the remote repository address right away * informational message about --set-default is disabled with --no-set * _darcs/format is correctly handled on get * linking libdarcs on Windows is fixed * Issues resolved in Darcs 2.5.1 * 1978: get does not correctly treat _darcs/format * 2003: Message about --set-default should be optional * 2008: build with GHC 7.0 * 2015: linking with libdarcs broken under Windows (2.5.0) * 2019: allow building with mtl 2 * 2035: darcs accepts fake subpaths (relative paths outside of the repo) Darcs 2.5, 30 October 2010: * Important changes in Darcs 2.5 * trackdown can now do binary search with the --bisect option * darcs always stores patch metadata encoded with UTF-8 * diff now supports the --index option * amend-record now supports the --ask-deps option * apply now supports the --match option * amend-record has a new --keep-date option * inventory-changing commands (like record and pull) now operate in constant time with respect to the number of patches in the repository * the push, pull, send and fetch commands no longer set the default repository by default * the --edit-description option is now on by default for the send command * Issues resolved in Darcs 2.5 * 64: store metadata as UTF-8 * 121: add --ask-deps support to amend-record * 643: darcs send -o outputs remote repo email address * 1159: avoid bogus repository cache entries * 1176: caches interfere with --remote-repo flag * 1208: add trackdown --bisect * 1210: global cache gets recorded in _darcs/prefs/sources * 1232: darcs convert copies _darcs/prefs/prefs * 1250: check for newlines in setpref values * 1277: percolate repository format errors correctly * 1288: the main darcs code now compiles and runs with witnesses * 1290: support diff --index * 1337: don't show unrelated patches in darcs changes on untracked path * 1389: change predist pref to point people to use 'cabal sdist' * 1427: accept gzipped patch bundles in darcs apply * 1456: make dist write more portable archives * 1473: make annotate accept '.' as argument * 1503: prefer local caches to remote ones * 1713: shorter interactive prompts * 1716: allow mail header lines of all whitespace in test * 1719: do not back up files when no conflict markers are inserted * 1726: don't consider all files with _darcs prefix boring * 1739: make ColorPrinter handle characters > 255 * 1763: use correct filename encoding in conflictors * 1765: refuse to remove non-tracked directories recursively * 1769: add support for --match 'comment ...' * 1784: push and pull print remote address right away * 1815: work around Cabal sdist permissions issue * 1817: fix support for external merge tools * 1824: avoid PACKAGE_VERSION under Windows * 1825: do not omit important prims in unrecordedChanges w/ files * 1860: (un)applying move patches doesn't corrupt pristine * 1861: fix typo in --no-boring help * 1874: recognise network tests on cabal test command line * 1875: avoid accidentally setting default * 1879: notice unexpected commute failure on merge * 1887: add a missing newline to --list-options output * 1893: move fields of conditional builds within scope of condition * 1898: notify user when they can use set-default * 1913: sort changes in treeDiff Darcs 2.4.4, 9 May 2010 * Important changes in Darcs 2.4.4 * darcs builds on Windows with GHC 6.10 (and GHC 6.12). * darcs (built with GHC 6.12 on Windows) works with SSH again * Issues resolved in Darcs 2.4.4 * 1814: Apply binary mode to ssh process and patch file handles. Darcs 2.4.3, 9 May 2010 * Important changes in Darcs 2.4.3 * darcs builds on Windows with GHC 6.12. Darcs 2.4.2, 8 May 2010 * Important changes in Darcs 2.4.2 * darcs will no longer give "mmap of _darcs_index" errors on Windows * darcs convert performance regression (against 2.3.x) solved * darcs get --partial no longer produces inconsistent repositories * Issues resolved in Darcs 2.4.2 * 1761: mmap of '_darcs/index' failed on Windows mapped drives * 1814: include contrib/darcs-errors.hlint in release tarball * 1823: read (mmap) _darcs/index file correctly on Windows * 1826: error building on Windows with GHC 6.12 * 1837: inconsistent repository upon darcs get --partial Darcs 2.4.1, 31 March 2010 * Important changes in Darcs 2.4.1 * darcs works again on Windows shared directories * missing documentation and test files have been added to the tarball * darcs will no longer give errors about a nonexistent file when compiled with the wrong mmap * moving files between directories can no longer break the directory index * darcs handles the case that someone uses 'remove -r' on an untracked directory * Bugs Fixed in Darcs 2.4.1 * 1750: uncover help text for 'darcs show pristine' * 1753: restrict mmap to version used by hashed-storage * 1754: fix issue458.sh on systems with xattrs * 1756: moving files between directories breaks index * 1757: add test files to distribution tarball * 1765: refuse to remove non-tracked directories recursively * 1767: send CRC erros to standard error Darcs 2.4, 27 February 2010 * Important changes in Darcs 2.4 * Use fast index-based diffing everywhere (Petr) * Interactive patch splitting (Ganesh) * An 'optimize --upgrade' option to convert to hashed format in-place (Eric) * Hunk matching (Kamil Dworakowski, tat.wright) * Progress reporting is no longer deceptive (Roman) * A 'remove --recursive' option to remove a directory tree from revision control (Roman) * 'show files' accepts arguments to show a subset of tracked files (Luca) * A '--remote-darcs' flag for pushing to a host where darcs isn't called darcs * Many miscellaneous Windows improvements (Salvatore, Petr and others) * 'darcs send' now mentions the repository name in the email body (Joachim) * Handle files with boring names in the repository correctly (Petr) * Fix parsing of .authorspellings file (Tomáš) * Various sane new command-line option names (Florent) * Remove the '--checkpoint' option (Petr) * Use external libraries for all UTF-8 handling (Eric, Reinier) * Use the Haskell zlib package exclusively for compression (Petr) * Bugs Fixed in Darcs 2.4 * 183: do not sort changes --summary output * 223: add --remote-darcs flag to specify name of remote darcs executable * 291: provide (basic) interactive patch splitting * 540: darcs remove --recursive * 835: 'show files' with arguments * 1122: get --complete should not offer to create a lazy repository * 1216: list Match section in ToC * 1224: refuse to convert a repo that's already in darcs-2 format * 1300: logfile deleted on unsucessful record * 1308: push should warn about unpulled patches before patch-selection * 1336: sane error message on --last "" (empty string to numbers parser) * 1362: mention repo name in mail send body * 1377: getProgname for local darcs instances * 1392: use parsec to parse .authorspelling * 1424: darcs get wrongly reports "using lazy repository" if you ctrl-c old-fashioned get * 1447: different online help for send/apply --cc * 1488: fix crash in whatsnew when invoked in non-tracked directory * 1548: show contents requires at least one argument * 1554: allow opt-out of -threaded (fix ARM builds) * 1563: official thank-you page * 1578: don't put newlines in the Haskeline prompts * 1583: on darcs get, suggest upgrading source repo to hashed * 1584: provide optimize --upgrade command * 1588: add --skip-conflicts option * 1594: define PREPROCHTML in makefile * 1620: make amend leave a log file when it should * 1636: hunk matching * 1643: optimize --upgrade should do optimize * 1652: suggest cabal update before cabal install * 1659: make restrictBoring take recorded state into account * 1677: create correct hashes for empty directories in index * 1681: preserve log on amend failure * 1709: fix short version of progress reporting * 1712: correctly report number of patches to pull * 1720: fix cabal haddock problem * 1731: fix performance regression in check and repair * 1741: fix --list-options when option has multiple names * 1749: refuse to remove non-empty directories Darcs 2.3.1, 20 Sep 2009 * Important changes in Darcs 2.3.1 * Fix bugs introduced by optimizations in 2.3.0 (Petr, Salvatore) * Documentation improvements (Taylor, Trent) * Remove autoconf build system (Petr) * Bugs Fixed in Darcs 2.3.1 See http://bugs.darcs.net/issueN for details on bug number N. * issue1373 darcs manual wrongly promises [^ ] is a valid token spec (Trent) * issue1478: document summary mnemonics (Trent) * issue1582 DeleteFile: permission denied (Access is denied.) (Salvatore) * issue1507 whatsnew does not use 'current' when 'pristine' is missing (Petr) Darcs 2.3.0, 23 Jul 2009 * Important changes in Darcs 2.3.0 * Lots and lots of documentation changes (Trent). * Haskeline improvements (Judah). * Cabal as default buildsystem (many contributors). * Fixes in darcs check/repair memory usage (Bertram, David). * Performance improvement in subtree record (Reinier). * New option: --summary --xml (Florian Gilcher). * New option: changes --max-count (Eric and Petr). * Fix changes --only-to-files for renames (Dmitry). * Performance fix in "darcs changes" (Benedikt). * Hardlinks on NTFS (Salvatore). * Coalesce more changes when creating rollbacks (David). * New unit test runner (Reinier). * Inclusion of darcs-shell in contrib (László, Trent). * Author name/address canonisation: .authorspellings (Simon). * Working directory index and substantial "darcs wh" optimisation (Petr). * New command: "darcs show index" (Petr). * Gzip CRC check and repair feature (Ganesh). * Bugs Fixed in Darcs 2.3.0 See http://bugs.darcs.net/issueN for details on bug number N. * 948 darcsman (Trent) * 1206 countable nouns (Trent) * 1285 cabal test v. cabal clean (Trent) * 1302 use resolved, not resolved-in-unstable (Trent) * 1235 obliterate --summary (Rob) * 1270 no MOTD for --xml-output (Lele) * 1311 cover more timezones (Dave) * 1292 re-encoding haskeline input (Judah) * 1313 clickable ToC and refs in PDF manual Trent) * 1310 create merged \darcsCommand{add} (Trent) * 1333 better "cannot push to current repository" warning (Petr) * 1347 (autoconf) check for unsafeMMapFile if mmap use enabled (Dave) * 1361 specify required includes for curl in cabal file (Reinier) * 1379 remove libwww support (Trent) * 1366 remove unreachable code for direct ncurses use (Trent) * 1271 do not install two copies of darcs.pdf (Trent) * 1358 encode non-ASCII characters in mail headers (Reinier) * 1393 swap "darcs mv" and "darcs move" (Trent) * 1405 improve discoverability of global author file (Trent) * 1402 don't "phone home" about bugs (Trent) * 1301 remove obsolete zsh completion scripts (Trent) * 1162 makeAbsolute is now a total function (Ben F) * 1269 setpref predist - exitcode ignored bug (Ben M) * 1415 --edit-long-comment, not --edit-description, in help (Trent) * 1413 remove duplicate documentation (Trent) * 1423 complain about empty add/remove (Trent) * 1437 Implement darcs changes --max-count (Eric) * 1430 lazy pattern matching in (-:-) from Changes command module (Dmitry) * 1434 refactor example test (Trent) * 1432 refer to %APPDATA%, not %USERPROFILE% (Trent) * 1186 give a chance to abort if user did not edit description file (Dmitry) * 1446 make amend-record -m foo replace only the patch name (Dmitry) * 1435 default to get --hashed from a darcs-1.0 source (Trent) * 1312 update and reduce build notes (Trent) * 1351 fix repository path handling on Windows (Salvatore) * 1173 support hard links on NTFS (Salvatore) * 1248 support compressed inventories for darcs-1 repos (Ganesh) * 1455 implement "darcs help environment" (Trent) Darcs 2.2.0, 16 Jan 2009 * Important changes in Darcs 2.2.0 * Support for GHC 6.10. * Improved Windows support. * Cabal is now supported as a build method for darcs. * Low-level optimisations in filesystem code. * Overhaul of the make-based build system. * Extensive manual and online help improvements. * Improved API documentation (haddock) for existing darcs modules. * Improvements in the testing infrastructure. * Improved performance for "darcs repair". * Improved robustness for "darcs check". * Numerous major and minor bug fixes, refactorings and cleanups. * When recording interactively it is now possible to list all currently selected hunks (command 'l'). * It is now possible to specify --in-reply-to when using darcs send, to generate correct references in the mail header. * Repositories can no longer be created with --no-pristine-tree. This only affects the legacy darcs-1 repository format. * Experimental Darcs library, providing increase flexibility and efficiency to third-party utilities (compared to the command-line interface). Only built via Cabal. NOT a stable API yet. * Bugs Fixed in Darcs 2.2.0 See http://bugs.darcs.net/issueN for details on bug number N. * 525 amend-record => darcs patches show duplicate additions * 971 darcs check fails (case sensitivity on filenames) * 1006 darcs check and repair do not look for adds * 1043 pull => mergeAfterConflicting failed in geteff (2.0.2+) * 1101 darcs send --cc recipient not included in success message * 1117 Whatsnew should warn on non-recorded files * 1144 Add darcs send --in-reply-to or --header "In-Reply-To:... * 1165 get should print last gotten tag * 1196 Asking for changes in /. of directory that doesn't exist... * 1198 Reproducible "mergeConflictingNons failed in geteff with ix" * 1199 Backup files darcs added after external merge * 1223 sporadic init.sh test failure (2.1.1rc2+472) * 1238 wish: darcs help setpref should list all prefs * 1247 make TAGS is broken * 1249 2.1.2 (+ 342 patches) local drive detection on Windows error * 1272 amend-record not the same as unrecord + record * 1273 renameFile: does not exist (No such file or directory) * 1223 sporadic init.sh test failure (2.1.1rc2+472) darcs (2.1.2) * Quality Assurance: Disable a new test that was not yet working under Windows -- Eric Kow Mon, 10 Nov 2008 10:40:00 GMT darcs (2.1.1) -- Eric Kow Mon, 10 Nov 2008 08:18:00 GMT darcs (2.1.1rc2) * Portability: Removed accidental QuickCheck 2.1 configure check. Note that it may be required in a future version of darcs. -- Eric Kow Mon, 10 Nov 2008 11:17:00 GMT darcs (2.1.1rc1) * Portability: GHC 6.10.1 support (Petr RoÄkai, Eric Kow) * Bug Fix: Fix file handle leak and check for exceptions on process running on Windows (issue784, Salvatore Insalaco) * Quality Assurance: Consolidated regression test suites using shell scripts only (Eric Kow, Tommy Petterson, Matthias Kilian) -- Eric Kow Mon, 10 Nov 2008 09:49:00 GMT darcs (2.1.0) * Bug Fix: Eliminate a 'same URLs with different parameters' error when fetching files over HTTP (issue1131, Dmitry Kurochkin) * User Experience: Corrections to the default boring file (Ben Franksen) * Bug Fix: Fix the %a option in darcs send --sendmail-command (Ben Franksen) * Bug Fix: Do not obscure the SSH prompts or text editor output with progress reporting (issue1104, issue1109, Dmitry Kurochkin, David Roundy) * Bug Fix: pull --intersection work now works as advertised (Tommy Pettersson) -- Eric Kow Sun, 09 Oct 2008 12:05:32 GMT darcs (2.1.0pre3) * Bug Fix: Eliminate an error merging repeated conflicts in darcs-2 repositories (issue1043, David Roundy) * New Feature: Hide 'Ignore-this:' lines which will be generated by future versions of darcs to prevent patch-id collisions. (issue1102, Eric Kow, David Roundy) * Bug Fix: Support darcs repositories which have symbolic links in their paths (issue1078, Dmitry Kurochkin) * Bug Fix: Make ssh connection sharing (darcs transfer-mode) work with old-fashioned repositories (issue1003, David Roundy) -- Eric Kow Sun, 02 Oct 2008 09:12:41 GMT darcs (2.1.0pre2) * IMPORTANT: Create darcs-2 repositories by default in darcs init (issue806, David Roundy) * User Experience: Do not allow users to add files to a darcs repository if their filenames would be considered invalid under Windows. This can be overridden with the --reserved-ok flag (issue53, Eric Kow) * Bug Fix: Do not leave behind a half-gotten directory if darcs get fails (issue1041, Vlad Dogaru, David Roundy) * User Experience: notice when you are trying to pull from a seemingly unrelated repository, that is one with a sufficiently different history. This can be overridden with the --allow-unrelated-repos flag (Dmitry Kurochkin, David Roundy) * Bug Fix: Fix hang after a user input error (for example, EOF) (Judah Jacobson) * Quality Assurance: Improvements to documentation and online help (Simon Michael) -- Eric Kow Sun, 25 Sep 2008 08:10:49 GMT darcs (2.0.3pre1) * New Feature: Optional readline-like functionality when compiled with the haskeline package (Judah Jacobson, Gaëtan Lehmann) * Bug Fix: No more spurious pending patches (issue709, issue1012, David Roundy) * Bug Fix: darcs get --to-match now works with hashed repositories (issue885, David Roundy) * User Experience: Catch mistakes in _darcs/prefs/defaults (issue691, Dmitry Kurochkin) * User Experience: Improved support for darcs send over http (see also tools/upload.cgi) (Dmitry Kurochkin, David Roundy) * Bug Fix: Recognize user@example.com: as an ssh path, that is, not requiring a path after the server component. (David Roundy) * New Feature: Accept an optional directory argument in darcs send --output-auto-name (Dmitry Kurochkin) * User Experience: New --no-cache option to help debug network issues (issue1054, Dmitry Kurochkin) * Performance: New --http-pipelining and --no-http-pipelining flags. Passing --http-pipelining to darcs can make darcs get and pull faster over HTTP. Due to a libcurl bug, this is not the default option unless darcs is compiled with libcurl 7.19.1, due 2008-11. (Dmitry Kurochkin) * Bug Fix: Eliminate hanging and crashes while fetching files over HTTP (issue920, issue977, issue996, issue1037, Dmitry Kurochkin) * Security: Fix some insecure uses of printfs in darcs.cgi (Steve Cotton) * Bug Fix: Handle filepaths in a simpler and more robust fashion. This fixes relative filepaths and recognition of symbolic links and avoids possible future bugs (issue950, issue1057, David Roundy, Dmitry Kurochkin) * Bug Fix: Make darcs diff --patch work even if the patch is within a tag (issue966, darcs 2 regression, Dmitry Kurochkin) * Quality Assurance: Extend use of Haskell's GADTs to most of the darcs code, fixing many potential bugs along the way (Jason Dagit, David Roundy) * Quality Assurance: Several improvements to darcs code quality (Petr RoÄkai) * Bug Fix: Correct assumptions made by darcs about Windows file size types (issue1015, Simon Marlow, Ganesh Sittampalam) * Bug Fix: Support case insensitive file systems using hashed repositories in darcs repair (partial issue971, Petr RoÄkai). IMPORTANT: This introduces a memory use regression, which affects large repositories. We found that doing a darcs repair on the GHC repository requires a machine with 2 GB of RAM. The regression is well-understood and should be solved in the next darcs release. In the meantime we felt that the improved robustness was worth the performance trade-off. * Quality Assurance: Simplify building darcs on Windows by optionally using the zlib and terminfo Haskell packages (Ganesh Sittampalam, Petr RoÄkai) * User Experience: Better error reporting when patches that should commute fail to do so. (Jason Dagit) * New Feature: --match "touch filenames", for example --match 'touch foo|bar|splotz.*(c|h)' (issue115, Dmitry Kurochkin) * User Experience: Improve debugging and error messages in HTTP code (Dmitry Kurochkin, David Roundy) * Bug Fix: Ensure that darcs responds to Ctrl-C on Window, even if compiled with GHC < 6.10 (issue1016, Simon Marlow) * New Feature: darcs changes --context now also works with --human-readable and --xml-output (issue995, Dmitry Kurochkin) * Bug Fix: Always darcs send with context, as if --unified flag were used (was implemented in 2.0.2, but not consistently) (David Roundy) * Bug Fix: Make sure that darcs get --tag works even when the user hits Ctrl-C to get a lazy repository (Dmitry Kurochkin) * Quality Assurance: Improvements to documentation and online help, most crucially, user-focused help on upgrading to darcs 2. (Trent Buck, Lele Gaifax, Simon Michael, Max Battcher) * New Feature: darcs changes --number associates each patch with number, counting backwards (see the --index feature) (David Roundy) * New Feature: ability to match patches on index, for example, darcs changes --index=3-6 shows the last three to six patches (David Roundy) * User Experience: slightly reduce the verbosity of darcs pull --verbose (David Roundy) -- Eric Kow Sun, 18 Sep 2008 02:36:45 GMT darcs (2.0.2) -- David Roundy Sun, 24 Jun 2008 01:20:41 GMT darcs (2.0.1) * Bug Fix: Make Ctrl-C work even though darcs is now compiled to use the threaded runtime (issue916, David Roundy) * New Feature: Include patch count in darcs --version, for example, 2.0.1 (+ 32 patches) (David Roundy) * Bug Fix: Avoid an error caused by renaming a file on case-insensitive file-systems (Eric Kow) * Bug Fix and New Feature: Improved XML output (Benjamin Franksen, Lele Gaifax, David Roundy) * User Experience: Always darcs send with context, as if --unified flag were used (David Roundy) -- David Roundy Sun, 23 Jun 2008 21:47:07 GMT darcs (2.0.1rc2) * Performance: Faster strings, using Data.Bytestring by default (Gwern Branwen, Eric Kow, Ian Lynagh, David Roundy) * User Experience: On Windows, use MS-DOS 'edit' as a default editor if Emacs and friends are not available (Eric Kow) * Bug Fix: On Windows, notice when external programs fail to launch because they do not exist (Eric Kow) * New Feature: darcs put --no-set-default and --set-default (Nicolas Pouillard) -- David Roundy Sun, 13 Jun 2008 01:17:45 GMT darcs (2.0.1rc1) * Bug Fix: Fix tag --checkpoint so that darcs get --partial can avoid fetching all patches (issue873, David Roundy) * User Experience: Better progress reporting [NB: darcs is now compiled with threaded runtime by default] (issue739, David Roundy, Bertram Felgenhauer) * Performance: Reduce memory usage of darcs put (David Roundy) * Bug Fix: Improved date matching (issue793, issue187, Eric Kow) * Performance: Fix an optimization in diff-detection (affects darcs whatsnew and record) (Pekka Pessi) * Quality Assurance: --enable-hpc for checking program coverage (Christopher Lane Hinson) * Bug Fix: Do not rollback if no primitive patches were selected (issue870, Eric Kow) * Bug Fix: Make it possible to --dry-run on repositories we cannot write to (issue855, Eric Kow, David Roundy) * Bug Fix: Avoid a race condition caused by cleaning out the pristine cache (issue687, David Roundy) * User Experience: When pushing, prints a small reminder when the remote repository has patches to pull (Eric Kow, David Roundy) * UI changes: --extended-help is now called --overview, no more --verify-hash, no more send --unified (David Roundy, Eric Kow) * User Experience: Show ssh's stderr output in case it wants to ask the user something (issue845, Eric Kow) * Bug Fix: Improved interaction with pager (David Roundy, Pekka Pessi, Eric Kow) * Bug Fix: darcs send -o - (Pekka Pessi) * Bug Fix: (regression) Re-enable darcs mv as a means of informing darcs about manual renames (issue803, David Roundy) * Bug Fix: Fix bugs related to use of threaded runtime (issue776, David Roundy) * Portability: Respect OS conventions in creation of temporary files (Eric Kow) * New Feature: Check for and repair patches which remove non-empty files (issue815, David Roundy) * Bug Fix: Make get --to-match work with hashed repositories (David Roundy) * Bug Fix: Conflict-handling with darcs-2 semantics (issue817, David Roundy) * Bug Fix: Make --ask-deps ask the right questions (Tommy Pettersson) * User Experience: Improved error messages and warnings (issue245, issue371, Nicolas Pouillard, David Roundy, Eric Kow) * New Feature: darcs trackdown --set-scripts-executable (Reinier Lamers) * Quality Assurance: Various improvements to documentation (issue76, issue809, Gwern Branwen, Lele Gaifax, Eric Kow, Nicolas Pouillard, David Roundy) * Bug Fix: Correct detection of incompatibility with future darcs (issue794, Eric Kow) * User Experience: Make darcs changes --interactive behave more like other interactive commands (Eric Kow) * Performance: Optimized handling of very large files (Gwern Branwen) * New Feature: Colorize added and removed lines, if the environment variable DARCS_DO_COLOR_LINES=True (Nicolas Pouillard) * New Feature: --remote-repodir flag to allow separate default repositories for push, pull and send (issue792, Eric Kow) * Performance: Optimized get --to-match handling for darcs 1 repositories (Reinier Lamers) * Bug Fix: Make changes --repo work when not in a repository (David Roundy) * New Feature: darcs changes --count (David Roundy) -- David Roundy Sun, 03 Jun 2008 12:43:31 GMT darcs (2.0.0) * Fix silly bug which leads to darcs --version not showing release when it's a released version. (David Roundy) -- David Roundy Sun, 07 Apr 2008 15:06:38 GMT darcs (2.0.0rc1) -- David Roundy Sun, 01 Apr 2008 15:44:11 GMT darcs (2.0.0pre4) * When darcs encounters a bug, check version versus central server in order to decide whether to recommend that the user report the bug. * Display duplicate identical changes when using darcs-2 repository format. (Issue579) * Fix a bug in convert that lead to invalid tags in the converted repository. (Issue585) * Add an annoying warning when users run convert. * Numerous fixes to the time/date matching code, which should now work even in central Europe. (Eric Kow) * Add support for reading hashed repositories that use SHA256 hashes. The plan is to enable writing of SHA256 hashes in the next release. (David Roundy) * New Feature: Add a 'show authors' command (Eric Kow) * darcs.cgi improvements: Patch pages show "Who" and "When" some file annotation pages show "who" and "when" with a mouse-over. Also, darcs.cgi can now be hosted in a path containing The tilde character. (Zooko, Mark Stosberg) * User Experience: Improved and added many debugging, error and progress messages (David Roundy, Mark Stosberg, Eric Kow) * New Feature: New DARCS_PATCHES, DARCS_FILES and DARCS_PATCHES_XML environment variables are made available for the posthook system, allowing for more easier options to to integrate darcs with other systems. (David Roundy, Mark Stosberg) * Quality Assurance: Added and updated automated regression tests (Mark Stosberg, David Roundy, Eric Kow, Trent Buck, Nicolas Pouillard, Dave Love, Tommy Pettersson) * Bug Fix: Gzipped files stored in the repo are now handled properly (Zooko, David Roundy) * Quality Assurance: Various Documentation Improvements (issue347, issue55 Mark Stosberg, Nicolas Pouillard, Marnix Klooster) * Bug Fix: With --repodir, commands could not be disabled (Trent Buck, David Roundy) * New Feature: tools/update_roundup.pl scripts allows the darcs bug tracker to be notified with a darcs patch resolving a particular issue is applied. A link to the patch in the web-based repo browser is provided in the e-mail notifying bug subscribers. (Mark Stosberg) * Internal: Begin work on memory efficiency improvements (David Roundy) * Performance: darcs is faster when identifying remote repos handling pending changes and running unrecord. (David Roundy) * Internal: Source code clean-up and improvements (David Roundy, Jason Dagit, Eric Kow, Mark Stosberg) * User Experience: A pager is used automatically more often, especially when viewing help. (Eric Kow) * Bug Fix: push => incorrect return code when couldn't get lock. (issue257, VMiklos, David Roundy, Eric Kow, Mark Stosberg) * Bug Fix: 'whatsnew' and 'replace' now work together correctly. (Nicolas Pouillard, David Roundy) -- David Roundy Sun, 21 Mar 2008 15:31:37 GMT darcs (2.0.0pre3) * Fix issue 244, allowing users of darcs changes to specify the new name of a file that has an unrecorded mv. (David Roundy, Mark Stosberg, Tuomo Valkonen) * Fix issue 600, bug in darcs optimize --relink. (David Roundy, Trent Buck, Mark Stosberg, Tommy Pettersson) * Add a new framework for outputting progress messages. If darcs takes more than about one second to run a command, some sort of feedback should now be provided. (David Roundy) * Rewrite rollback, changing its behavior to be more useful. Rollback now prompts for a name for the new "rollback" patches. It also allows you to roll back multiple patches simultaneously, and to roll back only portions of the patches selected. Altogether, rollback is now more interactive, and should also be more useful. (David Roundy) * Bug Fix: date parsing is now improved (Mark Stosberg, David Roundy) * Performance: Improved speed of darcs pull on very large repos. (David Roundy) * Fix issue 586, but in darcs repair on hashed and darcs-2 repositories. (Nicolas Pouillard) * Improve docs for 'darcs init' (Mark Stosberg) * Fix typo in test partial.sh which made part of the tests for --partial invalid. (Mark Stosberg) * Document that darcs handles some types of binary files automatically. (issue55, Mark Stosberg) * Fix typo in a test that made it compare a file to itself. (Mark Stosberg) * Document that single quotes should be used in .darcs/defaults. (issue347, Mark Stosberg) * New Feature: Automatically create the the global cache if we define we want to use it. (David Roundy, Trent Buck) * Performance: Improved HTTP pipelining support (Dmitry Kurochkin) * Fix issue 571, build failure when termio.h is not found. (Dave Love) -- David Roundy Sun, 22 Jan 2008 20:06:12 GMT darcs (2.0.0pre2) * Add instructions in documentation for how to view patches in Mutt (a mail reader). (Gwern Branwen) * Fix build on Solaris. (Dave Love) * Added "auto-optimize" support for hashed inventories, in that darcs automatically optimizes inventories when it seems wise (which is currently defined as "every time we modify the inventory"). * Fix expensive performance bugs involved in conflict handling. Thanks to Peter for pointing these out!. * Fix reading of hashed repositories to avoid reading patches that we don't actually need (i.e. foolish inefficiency bug). Thanks to Simon for reporting these performance bugs. * Added a new --debug flag for debug output. * Added compatibility with ghc 6.4. At this point darcs 2 should work with any ghc from 6.4 to 6.8.2. * Fix bug where parsing of setpref patch called tailPS unnecessarily. (David Roundy) * Refactor parsing of commands and command line arguments. Implement hidden commands. (Eric Kow) * Use a single command to initialize a remote repository. This replaces the method of stringing together multiple commands with the shell-dependent && operator. (Tristan Seligmann) * Allow for files in _darcs/inventories to be gzipped. This is not specifically related to issue553, but it fixes a regression introduced by the issue553 fix. (Issue553, Eric Kow) * Check for potential hash collision in writeHashFile. (Eric Kow) * Don't try to write hash file if it already exists, as you can not overwrite an open file on Windows. (Issue553, Eric Kow) * Close file handles when done reading it lazily. (Eric Kow) * Modernize and enhance buggy renameFile workaround by using the hierarchical library structure and only catching 'does not exist' errors. (Eric Kow) * Add "hidden" printer for decorating patches with color for easier reading when printed to screen during verbose or debug output, but hides (removes) the decoration when printing to the repository files. This is the counterpart of the invisible printer, which makes non-human-friendly patch contents invisible when printed to the screen. (David Roundy) * Add "hidden" printer, for printing things to screen but not file. (David Roundy) * Make darcs distinguish between repository sub paths and "normal" relative paths. Better handling of absolute paths. (Eric Kow) * Fix some bugs introduced by Better handling of file paths. (Eric Kow) * Handle corner case when polling from self. (issue354, issue358, Eric Kow) * Handle corner cases when pulling from current repository. (Issue354, Issue358, Eric Kow) * Fix bug in make_dotdots when pushing from a sub directory. (issue268, Eric Kow) * Fix bug in make_dotdots when pushing from a subdirectory. (Issue268, Eric Kow) * Better handling of file paths. Distinguish between paths to files belonging to the repository as well as not belonging to the repository, both in absolute and relative form. (Eric Kow) * Add path fixing to darcs send, and don't try sending to self. (issue427, Eric Kow) * Fix path issue for darcs send. (Issue427, Eric Kow) * Disable mmap under Windows. (issue320, Eric Kow) * Backup unmanaged working dir files as needed. (issue319, issue440, Eric Kow) * Backup unmanaged files in the working directory when they are overwritten by managed files with the same names in pulled or applied patches. (Issue319, Issue440, Eric Kow) * Offer some advice if sendmail failed. (issue407, Eric Kow) * Document behavior of "boring" managed files. (Issue259, Eric Kow) * Make Doc a newtype, so we can define a Show instance. (David Roundy) * Make make_changelog GHC 6.8 compliant. (Ganesh Sittampalam) * GHC 6.8 needs containers package. (Ganesh Sittampalam) * Configure hack to deal with openFd -> fdToHandle' renaming in GHC 6.8. (Ganesh Sittampalam) * Make makefile summarize calls to GHC when compiling. VERBOSE=1 turns the long format back on. (Eric Kow) * When building, print summarized call to GHC in makefile, instead of very long command lines with many boring options. VERBOSE=1 reverts to showing options again. (Eric Kow) * Add svg logo. (David Roundy) * Add mercurial files to the default boring file. (David Roundy) * Add patterns for mercurial files to default boring patterns. (David Roundy) * Define color versions of traceDoc and errorDoc for debugging. (David Roundy) * Clarify error message for --last. (issue537, Eric Kow) * Clarify in error message that darcs option --last requires a *positive* integer argument. (Issue537, Eric Kow) * Optimize getCurrentDirectorySansDarcs a little. (Eric Kow) * Never create temporary directories in the _darcs directory. (issue348, Eric Kow) * Never create temporary directories in the _darcs directory. (Issue348, Eric Kow) * Make revert short help less cryptic. (Eric Kow) * Make revert short help less cryptic. (Eric Kow) * Make --checkpoint short help more explicit. (issue520, Eric Kow) * Make --checkpoint short help more explicit. (Issue520, Eric Kow) * Add format infrastructure for darcs-2 repo format. (David Roundy) * Always optimize the inventory in 'darcs tag'. (Eric Kow) * Fix bug in Tag --checkpoint where the inventory was not updated. (Eric Kow) * Fix accidental regression of --no-ssh-cm flag. (Eric Kow) * Move conditional #include from Darcs.External to makefile. The GHC manual says that this is *not* the preferred option, but for some reason, the include pragmas seem to get ignored. Perhaps it is because the requirement that the pragmas be on the top of the file conflict with the #ifdef statements. In any case, this patch gets rid of the warning on MacOS X: warning: implicit declaration of function 'tgetnum'. (Eric Kow) * Pass CFLAGS to the assembler. E.g. -mcpu is essential on sparc. (Lennart Kolmodin) * Optimize 'darcs optimize --reorder'. (David Roundy) * Add a table of environmental variables to the manual. (issue69, Eric Kow) * Use System.Directory.copyFile for file copying. (Kevin Quick) * Implement darcs show contents command. It shows the contents of a file at a given version. (issue141, Eric Kow) * Make Changes --context --repodir work. (Issue467, Erik Kow) * Rename 'query' to 'show', but keep 'query' as an alias. (There is also an extra alias 'list' that means the same as show.) The subcommand 'query manifest' is renamed to 'show files', and does not list directories by default, unless the alias 'manifest' is used. (Eric Kow) * Support record -m --prompt-long-comment. (issue389, Eric Kow) * Hide the command 'unpull' in favor of 'obliterate'. (Eric Kow) * Make option --no-deps work again. It now also works for obliterate, unrecord, push and send. (issue353, Tommy Pettersson) * Make Record --ask-deps abort if user types 'q' instead of recording without explicit dependencies. User is now required to type 'd' (done). If the resulting patch is completely empty (no changes and no dependencies) the record is automatically canceled. (issue308, issue329, Kevin Quick) * Use pure record-access for PatchInfo in Patch.Info. (David Roundy) * Improve error message when unable to access a repository. (David Roundy) * Switch to using new Haskell standard library function cloneFile for copying files. (Kevin Quick) * Remove more GUI code. (Eric Kow) * Fix some --dry-run messages: "Would push" instead of "Pushing". (issue386, Eric Kow) * Ensure that logfile for record has trailing newline. (issue313, Eric Kow) * Add a stub command 'commit' that explains how to commit changes with darcs. (Eric Kow) * Makes non-repository paths in DarcsFlags absolute. (issue427, Zachary P. Landau) * Fix problem with missing newline in inventory, to simplify for third party scripts. (Issue412, Eric Kow) * Add all pulled repositories to _darcs/prefs/repos. (Issue368, Eric Kow) * Implement Apply --dry-run. (Issue37, Eric Kow) * Never change defaultrepo if --dry-run is used (issue186, Eric Kow) * Filter out any empty filenames from the command line arguments. (Issue396, Eric Kow) * Use prettyException in clarify_errors so we don't blame user for darcs' own errors. (Issue73, Eric Kow) * Rename command 'resolve' to 'mark-conflicts'. 'Resolve' remains as a hidden alias. (issue113, Eric Kow) * Make 'query manifest' list directories by default. (issue456, Eric Kow) * Allow --list-options even if command can not be run. (issue297, Eric Kow) * Make 'unadd' an alias for 'remove'. Make 'move' an alias for 'mv'. Add a stub for 'rm' that explains how to remove a file from a darcs repository. (issue127, Eric Kow) * Fix --help. (Issue282, Eric Kow) * New --nolinks option to request actual copies instead of hard-links for files. (Kevin Quick) * Harmonize capitalization in flags help. (Eric Kow) * Define datarootdir early enough in autoconf.mk.in. (Issue493, Eric Kow) * Fix a bug where Get --partial would use a checkpoint without detecting it was invalid. Checkpoints can for example become invalid after an Optimize --reorder. (issue490, David Roundy) * User Agent size limit for curl gets is removed. (Issue420, Kevin Quick) * Don't garb string parameters passed to libcurl, as required by the api specification. (Daniel Gorin) * Fix handling of --repo with relative paths. (Eric Kow) * Check for gzopen in zlib. curl depends on zlib and is detected prior to zlib by the configure file, but without the -lz flag on some versions. (Andres Loeh) * Switch to haskell's System.Process under Unix for execution of external commands; requires GHC 6.4. (Eric Kow) * Remove (some more) conflictor code. (Eric Kow) * Remove (unused) conflictor code. (David Roundy) * Support makefile docdir/datarootdir variables. (Dave Love) * Added prehooks that works the same as posthooks, but they run before the command is executed. This can for example be used to convert line endings or check character encodings before every Record. The darcs command aborts if the prehook exits with an error status. (Jason Dagit) * Use system instead of rawSystem for calling interactive cmds in Windows, which lets us support switches, for example, in DARCS_EDITOR. (Eric Kow) * add support for partial and lazy downloading of hashed repositories. (David Roundy) * Fix refactoring bug in Checkpoints where we sometimes looked for things in the wrong place. (David Roundy) * Fail on error in get_patches_beyond_tag. This will expose any bugs where we use this function wrongly. (As was the case in darcs check --partial with hashed inventories.) (David Roundy) * Restructure the source tree hierarchy from a mostly flat layout to one with directories and subdirectories that reflects the modularity of the source. (Eric Kow) * In tests, don't assume grep has -q and -x flags. (Dave Love) * Add --output-auto-name option to Send (Zachary P. Landau) * Added regression testing for the "pull --complement" operation. Updated documentation to explain why "darcs pull --complement R1 R1" is the same as "darcs pull R1" instead of the empty set. (Kevin Quick) * Change all "current" to "pristine" in manual and help texts. (Tommy Pettersson) * Added the ability to specify the --complement argument on the pull command as an alternative to --intersect and --union. When --complement is specified, candidate patches for a pull are all of the pullable patches that exist in the first repository specified but which don't exist in any of the remaining repositories (the set-theory complement of the first repository to the union of the remaining repositories). (Kevin Quick) * Fix bug where darcs would try to write temporary files in the root directory (/) if it couldn't find a repository root to write them in. Now it uses the current directory in that case. (issue385, Zachary P. Landau) * Make write_repo_format use the same syntax as read_repo_format when dealing with different repository formats. (Benedikt Schmidt) * Remove some unused functions from Population. (Eric Kow) * Use IO.bracket instead of Control.Exception.bracket in Exec, to restore the old way darcs works on *nix. (Eric Kow) * Import bracketOnError from Workaround instead of Control.Exception to support GHC 6.4. (Eric Kow) * Switch to haskell's System.Process under Windows for execution of external commands; requires GHC 6.4. (Simon Marlow) * Fix bug where darcs ignored command arguments in the VISUAL environment variable. (issue370, Benedikt Schmidt) * Make annotate work on files with spaces in the name. (Edwin Thomson) * Prettify exceptions in identifyRepository. (Juliusz Chroboczek) * QP-encode patch bundles transfered with the Put command. (Juliusz Chroboczek) * Fix bug in darcs get --tag that left cruft in pending. (David Roundy) * Fix bug when trying to 'darcs mv foo foo'. (issue360, David Roundy) * Separate comment from OPTIONS pragma for GHC 6.4 compatibility. (Eric Kow) * Make hashed inventories support optimize and reordering. (David Roundy) * Change all Maybe Patch to the new type Hopefully Patch, which is similar to Either String, for storing patches that may or may not exist. This should make it much easier to improve error reporting. (David Roundy) * Fix pending bug that broke several_commands.sh. (David Roundy) * Fix hashed inventory bug in Add. (David Roundy) * Make Get and Put reuse code for Initialize. This makes Put accept any flags that Init accepts. (David Roundy) * Fix new get to not mess up pending. (David Roundy) * External resolution can resolve conflicting adds. (Edwin Thomson) * Only copy the files that are needed for the resolution, when invoking an external resolution tool. This saves much time and resources on repositories with many files in them. (Edwin Thomson) * Change message in 'darcs check' from "applying" to "checking". (issue147, Tommy Pettersson) * Add code fore hashed inventories. (David Roundy) * New option for Diff: --store-in-memory. darcs diff usually builds the version to diff in a temporary file tree, but with --store-in-memory it will represent the files in memory, which is much faster (unless the tmp directory already is a ram disk). (Edwin Thomson) * Fix bug where duplicated file names on the command line would fool darcs. (issue273, Tommy Pettersson) * When recording with option --pipe, assume users local timezone if none is given, instead of UTC. Except if the date is given in raw patch format 'yyyymmddhhmmss' it is still parsed as UTC. (issue220, Eric Kow) * Account for timezone information, e.g. in dates when recording with option --pipe. (issue173, Eric Kow) * Fix bug in refactoring of get. (David Roundy) * Refactor repository handling to allow truly atomic updates. (David Roundy) -- David Roundy Sun, 16 Dec 2007 20:16:47 GMT darcs (1.0.9) * Make shell harness failures fatal in Makefile. (Eric Kow) * Bugfix, fix bug where we add a file but not its boring parent directory. (David Roundy) * Allow escaped quotes in 'quoted' for match text. (Dave Love) * Don't exit with failure when tests_to_run is used and there are no perl tests. (David Roundy) * Apply patches "tolerantly" to the working directory; don't quit, but print a warning for every problem and continue. This is a workaround for a bug in darcs where it sometimes fails to update the working directory. When darcs updates the working directory it has already successfully updated the inventory and the pristine cache, so the repository itself is not corrupted. However, an incomplete update to the working directory results in unintended differences between the working and pristine tree, looking like spurious unrecorded changes. These can be easily removed with 'darcs revert', but spurious changes have to be manually sorted out from real unrecorded changes. By darcs no longer quiting at the first problem, more of the working tree gets updated, giving less spurious changes and less manual work to fix the mess should the bug bite you. (issue434, Eric Kow, David Roundy) * Add a README file, created from HACKING. (issue287, Eric Kow) * New command, query tags (similar to 'darcs changes -t .) (Florian Weimer) * Include the query commands in the manual. (Florian Weimer) * The ssh control master is now off by default (it seems to hang on some large repositories). The option --disable-ssh-cm is replaced by the two options --ssh-cm and --no-ssh-cm (default). (Eric Kow) * Do not append a colon to host name when calling sftp. This does not solve all of issue362, just a minor annoyance along its way. (issue362, Eric Kow) * Get 'open' and 'psignal' declared on Solaris. (Dave Love) * Zsh completion supports new _darcs/pristine repository format. (Georg Neis) * Add documentation for DARCS_PAGER. (Benedikt Schmidt) * Turning off and on the ssh control master works for the Changes command. (issue383, Georg Neis) * Optimize unrecorded file moves with unrecorded file adds and removals. That is, if you add, rename and remove files multiple times without recording, whatsnew (and record) will only see the final result, not the whole sequence of moves. (Marco Tulio Gontijo e Silva) * Fix link error with errno for gcc 4.12 / glibc 2.4. (Benedikt Schmidt) * Remove the confusing text "user error" from some of GHC's error descriptions. (Juliusz Chroboczek) * Check for and fail build configuration if module quickcheck isn't available. (issue369, David Roundy) * Make darcs push QP-encode the bundle before transferring. This should hopefully fix issues with scp/sftp corrupting bundles in transit. (Juliusz Chroboczek) * Make it very clear in the documentation that the options --from and --author does NOT have anything to do with the sender or email author when sending patches as email with the darcs Send command. (Kirsten Chevalier) * Allow commented tests in tests_to_run. (David Roundy) * Make it an error to Put into a preexisting directory. Often one could be tempted to try to put into a directory, expecting to have the repository created as a subdirectory there, and it is confusing to have instead the repository contents mingled with whatever was already in that directory. (David Roundy) * Explicitly flush output on Windows after waiting for a lock, because Windows' stdout isn't always in line-buffered mode. (Simon Marlow) * Improve unhelpful "fromJust" error message in Push command. (Kirsten Chevalier) * Support option --all for Obliterate, Unpull and Unrecord. (issue111, David Roundy) * Ignore failure to set buffering mode for terminal in some places (supposedly fixes issue41, issue94, issue146 and issue318). (Tommy Pettersson) * Buildfix, don't import Control.Exception functions when compiling on Windows. (Edwin Thomson) * Add make rules for tag files. (Dave Love) * Add a semi-automated test for SSH-related things. (Eric Kow) * Allow Dist --dist-name to put the tar file in any directory by giving a full path as the dist name. (issue323, Wim Lewis) * Add rigorous error checking when darcs executes external commands. All low-level C return values are checked and turned into exceptions if they are error codes. In darcs main ExecExceptions are caught and turned into error messages to help the user. (Magnus Jonsson) * Redirect error messages from some external commands to stderr. (Tommy Pettersson) * Make configure fail if a required module is missing. (David Roundy) * The options for turning off and on the ssh control master works from the defaults file. (issue351, Tommy Pettersson) * Amend-record now keeps explicit dependencies (made with --ask-deps) from the amended patch. (issue328, Edwin Thomson) * Make libcurl use any http authentication. This let darcs use repositories protected with digest authentication. (Tobias Gruetzmacher) * Turning off and on the ssh control master works for the Send command. (Eric Kow) * Redirect stderr to Null when exiting SSH control master. This suppresses the output "Exit request sent" not suppressed by the quiet flag. (Eric Kow) * Fix curses stuff, especially on Solaris 10. (Dave Love) * Annotate various boring patterns. (Dave Love) -- Tommy Pettersson Sun, 03 Jun 2007 21:37:06 GMT darcs (1.0.9rc2) * Pass e-mail address only for %t in --sendmail-command. Msmtp seems to require this. Note that the full address is encoded in the message body. (Eric Kow) * Show error messages on stderr when starting and stopping the ssh control master. (Tommy Pettersson) * Rewrite check for spoofed patches with malicious paths. The check can now be turned off with the option --dont-restrict-paths (issue177). The new check only works for Apply and Pull, and it only looks at the remote patches. A more complete check is desirable. (Tommy Pettersson) * Add LGPL file referenced in fpstring.c (Dave Love). * Update FSF address in copyright headers(Dave Love). * New default boring file patterns: ,v .# .elc tags SCCS config.log .rej .bzr core .obj .a .exe .so .lo .la .darcs-temp-mail .depend and some more (Dave Love). * Move darcs.ps to the manual directory (Tommy Pettersson). * Pass -q flag to scp only, not ssh and scp. Putty's SSH (plink) does not recognize the -q flag. (issue334, Eric Kow) * Bugfix. Make darcs.cgi look for both pristine and current (Dan). * Don't lock the repo during `query manifest' (issue315, Dave Love). * Buildfix. Include curses.h with term.h (issue326, Dave Love). * Bugfix. Unrecord, Unpull and Obliterate could mess up a repository slightly if they removed a tag with a corresponding checkpoint. Only the commands Check and Repair were affected by the damage, and Get would also copy the damage to the new repository. (issue281, Tommy Pettersson) * Add a HACKING file with helpful references to pages on the darcs wiki (Jason Dagit). * New boring file patterns: hi-boot o-boot (Bulat Ziganshin, Eric Kow). * Require 'permission denied' test for MacOS X again. Perhaps something in MacOS X was fixed? (Eric Kow). * Look for Text.Regex in package regex-compat. Needed for GHC 6.6. (Josef Svenningsson) -- Tommy Pettersson Sun, 16 Nov 2006 14:03:51 GMT darcs (1.0.9rc1) * Improved handling of input, output and error output of external commands. Null-redirection on windows now works. Only stderr of ssh is null-redirected since putty needs stdin and stdout. (issue219, Eric Kow, Tommy Pettersson, Esa Ilari Vuokko) * Optimize away reading of non-managed files in summary mode of Whatsnew --look-for-adds (issue79, Jason Dagit). * Remove direct dependency to mapi32.dll; Improve MAPI compatibility. (Esa Ilari Vuokko) * Ignore .git if _darcs is found (Juliusz Chroboczek). * Add a haskell code policy test to catch uses of unwanted functions, bad formating and such. (Tommy Pettersson) * If the logfile supplied with option --logfile does not exist, fail instead of inserting no long comment. (issue142, Zachary P. Landau) * Make the pull 'permission test' work when run as root (Jon Olsson). * Handle unsimplified patches when further simplifying the summarized output. For unknown reason (a possibly previous version of) darcs allows a single patch to Add and Remove the same file in a single patch. The Changes command used to combine them, showing just a Remove. (issue185, Lele Gaifax) * Add workaround for HasBounds that was removed in GHC 6.6 (Esa Ilari Vuokko). * Really make --disable-ssh-cm work (issue239, Eric Kow). * Fix false errors in pull.pl test (David Roundy). * Clean up docs on DarcsRepo format (David Roundy). * Use stdin for passing the batch file to sftp, to allow password-based authentication (issue237, Eric Kow, Ori Avtalion). * Make darcs fail if the replace token pattern contains spaces. It would otherwise create a non-parsable patch in pending. (issue231, Tommy Pettersson) * Set a default author in the test suite harness so not every test has to do so. (Tommy Pettersson). * Run external ssh and scp commands quietly (with the quiet flag), but not sftp which doesn't recognize it (issue240). This reduces the amount of bogus error messages from putty. (Eric Kow) * Implement help --match, which lists all available forms for matching patches and tags with the various match options (Eric Kow). * Added .elc and .pyc suffixes to default binary file patterns (Juliusz Chroboczek ). * Added a link to the 'projects' part of the cgi repository interface, so that you go back to the project list (Peter Stuifzand). * Add a test suite for calling external programs (Eric Kow). * Don't warn about non-empty dirs when in quiet mode (Eric Kow). * New option --umask. This is best used in a repository's defaults file to ensure newly created files in the repository are (not) readable by other users. It can also be used when invoking darcs from a mail reader that otherwise sets a too restrictive umask. (Issue50, Juliusz Chroboczek) * Only check for ssh control master when it might be used. This suppresses the annoying "invalid command" error message. (Issue171, Eric Kow) * Fail with a sensible message when there is no default repository to pull from. (Lele Gaifax) -- Tommy Pettersson Sun, 08 Oct 2006 17:52:07 GMT darcs (1.0.7) * Fixed bug leading to a spurious "darcs failed: resource vanished" error message when darcs output is piped to a program such as head that then exits. (Issue160, David Roundy) * New option --diff-command overrides the default value of "diff" when darcs calls an external program to show differences between versions (Eric Kow). * Use the ControlMaster feature in OpenSSH version 3.9 and above to multiplex ssh sessions over a single connection, instead of opening a new connection for every patch (Issue32, Eric Kow). * Add a standalone graphical interface (experimental). The gui code prior to this patch allows graphical darcs forms to be run from the command line. This builds off that functionality by adding a graphical front-end, allowing users to access these forms with a click of a button. In other words, this allows users to run darcs without the command line. (Eric Kow) * Make unpull, unrecord, obliterate accept --gui (Eric Kow). * Freshen GUI code so that it compiles (Eric Kow). * Provide more information when a remote repository can't be correctly identified. (Juliusz Chroboczek) * The Send command can save, reuse and delete the accompanying description in a logfile. (Zachary P. Landau) * Display list of subcommands when getting help on a supercommand. (Eric Kow) * A proper fix for the problem with rmdir when there are non-managed files left in the working copy of the directory so it can't really be removed. This solves the two related problems with a missguiding error message in one case, and an unreported repository corruption in the other. Now there is no false warning and no repository coruption. (issue154, Eric Kow) * Escaping of trailing spaces and coloring now works with in the pager called with 'p' from interactive dialogues. (issue108, Tommy Pettersson) * Added default recognized binary file extensions: bmp, mng, pbm, pgm, pnm, ppm, tif, tiff. (Daniel Freedman) * Added a RSS link to common.xslt. (Peter Stuifzand) * Make short option -i a synonym for --interactive (Zachary P. Landau). * Improved argument substitution for --external-merger. All apperences of %N are replaced, not only those occurring as single words. (Daan Leijen) * Transition from _darcs/current to _darcs/pristine completed. New repositories are created with a "pristine" directory. Previous versions of darcs have been looking for this directory since version 1.0.2, but older versions than that can't read the new repository format. (Juliusz Chroboczek) * If you specify a repository directory, any absolute paths prefixed by this directory are converted to be ones relative to the repodir. (issue39, Eric Kow) * The --repodir flag works with many more commands: changes, dist, get, optimize, repair, replace, setpref, tag, trackdown. (RT#196, RT#567, Eric Kow) * The --repodir flag works with initialize command, and tries to create it if it does not exists. (RT#104, Eric Kow) * Add autom4te.cache to default boring patterns. (Kirill Smelkov) * Don't create temporary copies of the repository for the external merger program, unless there is for sure some conflict to resolve. (Edwin Thomson) * Modify Changes --interactive dialogue to behave like other interactive commands: accept 'y' and 'n' as answers and exit automatically after last question. (Zachary P. Landau) * Unnamed patches are now called "changes" in the interactive patch selection dialogues. (Tommy Pettersson) * Treat Enter as an invalid response in single character prompt mode, and give feedback instead of being mysteriously silent and unresponsive. (RT#261, Eric Kow) * Make short option -f a synonym for --force (Zooko). * Posthooks no longer cause an output message about success or failure, unless the --verbose option is used. (Jason Dagit) * Fix crash when using changes --interactive with --patch or --match (Zachary P. Landau). -- Tommy Pettersson Sun, 13 May 2006 17:14:38 GMT darcs (1.0.6) -- Tommy Pettersson Sun, 28 Feb 2006 11:18:41 GMT darcs (1.0.6rc1) * Check paths when applying patches to files and directories to stop maliciously handcrafted patches from modifying files outside of the repository or inside darcs private directories (issue48, Tommy Pettersson). * Revert optimization that sometimes applied patches incorrectly and corrupted the repository. This make darcs somewhat slower when applying patches. A full pull of the darcs repository itself takes 50% longer. (issue128, Tommy Pettersson). * Fix bug in Get --tag that produced a corrupt repository (issue67, Edwin Thomson). * Add newline between long comment and changed files list in dry-run summary to remove ambiguity (Edwin Thomson). * Extended date matching functionality: ISO 8601 dates and intervals, a larger subset of English like "yesterday at noon" (issue31/RT#34, Eric Kow). * Allow rename to different case (RT #466, Eric Kow). * Save long comment in a file if record fails the test run (Zachary P. Landau). * Fix win32 build breaks (Will Glozer). * Make --exact-version work when darcs is built from distributed tar ball (Marnix Klooster). * Coalesce pending changes created with setpref (issue70/RT#349, Eric Kow). * Support --interactive option in changes command (issue59, Zachary P. Landau). * New help command (RT#307, Eric Kow). * Add --without-docs option to configure (Richard Smith). * Obey normal autoconf conventions. Allows you to 'make install prefix=...' and doesn't change default for sysconfdir. (Dave Love) * Fix bug with non-existing directories. (David Roundy) * Remote apply does not use cd to change current directory to target directory any more. It uses --repodir when invoking remote darcs. This may break some darcs wrappers. (Victor Hugo Borja Rodriguez) * Support signed push (Esa Ilari Vuokko). * Added support for pulling from multiple repositories with one pull. The choice of --union/--intersection determines whether all new patches are pulled, or just those which are in all source repositories. This feature implements a suggestion by Junio Hamano of git. (David Roundy) * Patch bundle attachments get a file name, based on the first patch. (Zachary P. Landau) * The send command now takes a --subject flag. (Joeri van Ruth) * Fix --set-scripts-executable to work also when getting a local repository. (issue38, Eric Kow) * Removed the helper program darcs-createrepo. It was used for guided settup of a darcs repository and a corresponding user account to accept patches from signed emails. (issue14, Jason Dagit) * Print out the patch name when a test fails. (Zachary P. Landau). * Bugfix for --sendmail-command in Windows (Esa Ilari Vuokko). * Make apply --verify work with GnuPG in Windows (Esa Ilari Vuokko) * Bugfix for handling of absolute paths in Windows (issue47, Will Glozer) -- Tommy Pettersson Sun, 19 Feb 2006 23:19:19 GMT darcs (1.0.5) * Fixes for Windows (Will Glozer). * Adapt makefile to work with current ghc 6.4 (Will Glozer). * --help and --list-commands ignore other options (issue34, Eric Kow). * Fix apply with --verify for patch bundles signed by GnuPG in Windows (Esa Ilari Vuokko). * Make patch selection options together with --context work again (Daniel Bünzli). * Make option --commands outside of a repository work again (issue9, David Roundy). * Bugfix for pushing with ssh under Windows (issue15, Will Glozer). * Fix superfluous input bug in test suite (Florian Weimer). * Many English and markup fixes (Dave Love). -- Tommy Pettersson Sun, 07 Dec 2005 11:27:30 GMT darcs (1.0.4) * Fixed a bug in the external conflict resolution code. (bug #577, David Roundy) * Fixed a bug which made apply sometimes (but rarely) fail to check the the hash on patch bundles corrupted in just the wrong way. (David Roundy) * Added a simple check to darcs replace that avoids tokenizing lines that don't contain the token we're replacing. I feel a bit bad about introducing an optimization this late in the release cycle, but it makes a huge difference, and really should be safe. (David Roundy---famous last words) * Fixed bug where darcs didn't honor the SSH_PORT environment variable when calling sftp. (bug #576, fix suggested by Nicolas Frisby) * Avoid putting a wrongly-named directory in the tarball generated by darcs dist, if the name we wanted already exists in $TMPDIR. (Simon McVittie) * Fixed bug which caused "pull_firsts_middles called badly" errors when running record with --ask-deps flag. (bug #476, David Roundy) * Fixed bug where 'darcs changes --context' created a context that contained escapes that prevented its use with send. (bug #544, David Roundy) * Make interactive push/pull/send/apply respect the --summary option by printing each patch as if you had hit 'x'. (David Roundy, bug #512) * Fix bug when calling whatsnew --summary when a file without a trailing newline has been deleted. (David Roundy) * Fix --set-scripts-executable to work again. This feature had been broken since version 1.0.3. (David Roundy) * Simple (safe) fix for a bug which caused darcs to run out of file descriptors when pulling over 1000 patches. (David Roundy) * Fix bug in perl parts of test suite which led to spurious warning messages. (David Roundy) * Fix bug in configure when compiling darcs from tarball on a system that has no darcs present. (David Roundy) * Fix bug that shows up when recording in a repository lacking a pristine tree. (David Roundy) -- David Roundy Sun, 13 Nov 2005 13:44:31 GMT darcs (1.0.4pre4) * Fix error in install target of makefile, which was introduced in 1.0.4pre3. (Andres Loeh) * Fix problem where make install modified the permissions on system directories. (David Roundy, bug #494) * Fix bug in display when whatsnew is given "-l" twice. (David Roundy, bug #501) * Added support for --posthook to all commands. (Jason Dagit) * Made repair able to work on partial repositories. (fixes bug #189) * Changed the delimiter in the long-comment file from ***DARCS*** to ***END OF DESCRIPTION*** and clarified its meaning a bit. (Jason Dagit and David Roundy) * Added code to allow darcs to apply some patch bundles that have had carriage returns added to their line endings. (David Roundy, bug #291) * Make darcs accept command line flags in any order, rather than requiring that they precede file, directory or repository arguments. Fixes bug #477 (David Roundy) * Modified darcs get to display patch numbers rather than a bunch of dots while applying patches during a darcs get. Also added similar feedback to the check and repair commands. (Mat Lavin, bug #212) * Made revert --all not ask for confirmation, so it can be used in scripting, as one would use pull --all or record --all. (Jani Monoses) * Added file ChangeLog.README explaining how to add entries to the changelog. (Mark Stosberg and David Roundy) * Fixed incompatibility with somewhat older versions of libcurl. (Kannan Goundan) * Fixed bug that showed up when after editing a long comment, the long comment file is empty. (David Roundy, bug #224) -- David Roundy Sun, 01 Sep 2005 11:04:18 GMT darcs (1.0.4pre2) * (EXPERIMENTAL) Added support for reading and writing to git repositories. There remain efficiency issues with the handling of git merges and darcs is not yet able to either create a new git repository, or to pull from a remote git repository. See building darcs chapter in manual for instructions on building darcs with git support. (Juliusz Chroboczek, configuration contributed by Wim Lewis) * Add new "query manifest" command to list files and/or directories in repository. Add some related infrastucture to support "subcommands". (Florian Weimer) * Make configure properly detect that we're on windows when building under mingw. (David Roundy) * Fixed bug #208: error when specifying pulling from a relative default repository if we are ourselves within a subdirectory of our repository. (David Roundy) * Change internal mechanism for writing the "pending" file to be (hopefully) more robust. (David Roundy, original idea by Ian Lynagh) * Fixed a bug that caused get --partial to fail sometimes. (David Roundy) * Made push/pull --verbose --dry-run now display contents of patches, analogous to the behavior of changes --verbose. (Jim Radford) * Various build system cleanups. (Peter Simons) -- David Roundy Sun, 31 Jul 2005 12:10:29 GMT darcs (1.0.4pre1) * Performance improvement: Several commands now read patches lazily, which reduces memory usage. A test of 'darcs check' on the Linux kernel repository showed the memory usage was nearly cut in half, from about 700 Megs to 400. Coded by David Roundy. * New feature: darcs put, the easiest way to create a remote repo, symmetric with 'darcs get'. Coded by Josef Svenningsson. * Performance improvement: RT#222: darcs performs better on files with massive changes. Coded by Benedikt Schmidt. * New Feature: darcs optimize now has "--modernize-patches" and "--reorder-patches" flags. See the manual for details. * Performance improvement: Using 'darcs diff' is now exponentially faster when comparing specific files in the working directory to the most recent copy in the repo. Coded by kannan@cakoose.com. -- David Roundy Sun, 18 Jul 2005 11:22:34 GMT darcs (1.0.3) * Fixed bug #396: error when specifying a removed file on the command line of darcs record. -- Tomasz Zielonka Sun, 24 May 2005 21:51:27 GMT darcs (1.0.3rc2) * Internals: darcs' ChangeLog is automatically generated from repo history and a database of ChangeLog entries (Tomasz Zielonka) * Fixed: RT#370: --tags work in unpull and unrecord (Tommy Pettersson) * New feature: added support for displaying patches with pager when selecting patches (Benedikt Schmidt) * New feature: new match type "exact" (John Goerzen) * Feature: unrevert accepts --all and --interactive options (Jani Monoses) * Fixed: darcs works with nvi (Benedikt Schmidt) -- Tomasz Zielonka Sun, 15 May 2005 08:56:17 GMT darcs (1.0.3rc1) * New Feature: darcs.cgi now uses appropriate caching headers. This will make repeated calls to the same pages by cache-aware browsers much faste in some cases. It also means that darcs.cgi can be usefully combined with a cache-aware proxy for even better performance. (Will Glozer) * New feature: more control over color and escaping in printed patches, alternative color scheme, escaping of trailing spaces (Tommy Pettersson) * Fixed: fixed bug manifesting with failed createDirectory (David Roundy) * Internals: RT#255, several welcome refactors were made to the test suite, including comprehensible shell test script output, improved portability, and easier maintenance. (Michael Schwern). * New Feature: RT#245: Using --look-for-adds with 'whatsnew' implies --summary. This should save some typing for the common case. (Karel Gardas, Mark Stosberg) * New Feature: RT#231: darcs gives better feedback now if you try to record nonexistent files or directories. (Karel Gardas, Mark Stosberg) * New feature: send accepts --sendmail-command that allows to customize the command used for sending patch bundles (Benedikt Schmidt) * Fixed: RT#266: Adding a non-existent dir and file gives the expected message now. (Tomasz Zielonka). * Fixed: RT#10, a missed conflict resolution case. More accurately, we noticed at had been fixed some point. A regression test for it was added. (Tomasz Zielonka, Mark Stosberg) * New feature: darcs tag can now accept the tag name on the command line (RT#143). (Josef Svenningsson, Mark Stosberg, David Roundy) * New feature: unrecord and unpull have a more powerful interface similar to 'darcs pull'. This allows for multiple patch selection. Coded by Tommy Pettersson. * Bug fix: RT#305: Removed '--patch' from the 'changes', which conflicted with the new '--patches' option. * New feature: Automatically add parent directories for darcs add. (RT#20) Coded by Benedikt Schmidt. * Add helpful diagnostic message when there is a failure while pulling (RT#201) -- Tomasz Zielonka Sun, 26 Apr 2005 00:25:54 GMT darcs (1.0.2) * No changes from 1.0.2rc4. -- David Roundy Fri, 4 Feb 2005 07:33:09 -0500 darcs (1.0.2rc4) * More documentation improvements, plus one clearer error message. * Fixed (new since 1.0.1) bug which broke darcs repair. * Fixed problem with makefile which caused spurious relinkings. * Fixed bug in new optimize --relink command, which could cause repository corruption. -- David Roundy Wed, 2 Feb 2005 06:24:19 -0500 darcs (1.0.2rc3) * Documentation improvements related to Juliusz new code. * Fixed longstanding leaks in zlib/threads code. * Fixed some bugs in the new optimize --relink code. * Fixed bug in darcs diff when the repository name is empty. -- David Roundy Sat, 29 Jan 2005 07:28:39 -0500 darcs (1.0.2rc2) * Fixed bug on win32 when there are spaces in a repositories path and an external program (i.e. ssh) is called. (Will Glozer) -- David Roundy Thu, 27 Jan 2005 06:46:37 -0500 darcs (1.0.2rc1) * Added experimental support for repositories without a "pristine tree" This is the new name for the cache stored in _darcs/current/. (Juliusz Chroboczek) * Added an optimize --relink command to save disk space when using multiple repositories. (Juliusz Chroboczek) * Ignore conflict markers in the boring and binaries files. * Fixed bug in get --partial when patches are in an unusual order. (Andrew Johnson) * Fixed bug which caused a crash on a local get of a repository owned by another user. * Fixed bug in changes/annotate that shows up when a directory has been moved. * Allow ncurses in addition to curses in configure. * Added --set-scripts-executable option. (Karel Gardas) * Added configure option to fix path to sendmail even if it's not present. * Made bash completion more robust regarding shell special chars. * Added konquerer workaround to cgi annotate. (Will Glozer) * Addressed bug #114 - provide a better error when you accidently try to pull from yourself. (Mark Stosberg) * Made a few documentation improvements. * Made http user agent reflect the darcs and libcurl version. * Fixed commute bug in merger code. * Fixed bug in decoding mime messages. -- David Roundy Wed, 26 Jan 2005 08:51:24 -0500 darcs (1.0.1) * Made darcs changes --context work on an empty repo. * Fixed bug in relative directories as arguments to pull/push. * Fixed bug leading to extraneous changes in pending. * Fixed bug #137 - XML escaping for >. * Fixed gui code to compile with wxhaskell 0.8 (but it's still buggy). -- David Roundy Tue, 14 Dec 2004 08:16:10 -0500 darcs (1.0.1rc3) * Made it so adding and removing a file doesn't leave changes in pending. * Fixed bug in creating the file to be edited for the long comment. * Made "bug in get_extra" message explain possible cause of the problem, which is related to a bug in commutation that made it into version 1.0.0. * Fixed stubborn bug in annotate. * Fixed problem when unrecording binary file patches. -- David Roundy Sat, 11 Dec 2004 14:23:53 -0500 darcs (1.0.1rc2) * Various optimizations. * darcs now supports an arbitrary number of transport protocols through the use new environment variables. See DARCS_GET_FOO in the 'Configuring Darcs' chapter in the manual for more details. * darcs now supports an arbitrary number of concurrent connections when communicating with remote repos. See the documentation for DARCS_MGET_FOO in the 'Configuring Darcs' chapter in the manual for more details. -- David Roundy Wed, 8 Dec 2004 08:02:48 -0500 darcs (1.0.1rc1) * Fixed bug in commutation of adjacent hunks which have either no new or no old lines. * Numerous newline fixes for windows. * On windows, use MAPI to resolve to and from addresses. * Fixed problem where the --cc was ignored in apply if the patch succeeded. -- David Roundy Wed, 1 Dec 2004 06:24:08 -0500 darcs (1.0.1pre1) * Changed apply to by default refuse to apply patches that would lead to conflicts. * Removed the old darcs_cgi script, in favor of the darcs.cgi script. * Fixed changes to work better in partial repositories. * Set stdin and stdout to binary mode to fix end of line problems with push under windows. * Made send create proper MIME email. * Removed reportbug command, really wasn't necesary, and didn't work well. Report bugs by an email to bugs@darcs.net, which creates a ticket in our BTS. * Allow darcs to work with a password protected proxy. * Get multiple files with a single wget call when darcs is compiled without libcurl support. * Use sftp instead of scp to copy patches via ssh -- this reuses a single connection for better speed. * Made _darcs/current polymorphic (but not really documented). * Made optimize --uncompress work with --partial repos. * Various minor interface improvements. * Made changes work better when specifying a file, and working in a partial repository. * Fixed bug in causing "Fail: _darcs/patches/unrevert: removeFile: does not exist (No such file or directory)". Resolves bugs #57, #61. -- David Roundy Sun, 21 Nov 2004 08:29:24 -0500 darcs (1.0.0) * Fixed compile error when antimemoize is enabled. * Fixed bug that showed up when dealing with international characters in filenames. * Various documentation improvements. -- David Roundy Mon, 8 Nov 2004 06:12:08 -0500 darcs (1.0.0rc4) * Use autoconf to check for working install program. * Renamed rerecord to amend-record in a futile attempt to avoid confusion. * Made pull accept the --repodir option. * Fixed off-by-one error in annotate that kept users from seeing "deleted" version. * Check filesystem semantics at runtime to avoid using mmap on windows filesystems. * Fixed darcs.cgi to work properly when browsing history of renamed files. * Use anonymous file handle for temporary files in darcs.cgi -- fixes a temporary file leak and potentially improves security. * Added --summary option to commands that accept --dry-run. * Made pull prompt for confirmation when there is a conflict with unrecorded changes. * Made unrevert interactive. * Don't try to generate a new name on get if name was given explicitely. * Always mark conflicts, even if there's an obvious solution. * Quote conflict attribute values in xml output. * Fail if the user gives a newline in the patch name. * Fixed bug where new files didn't show up in darcs diff. * Really fix newlines in whatsnew -u. * Fixed bug in handling of tags in changes and annotate. * Fixed bug in default options containing "--". * Fixed various other build problems in 1.0.0rc3. * Fixed embarrassing failure-to-compile-on-windows bug. -- David Roundy Mon, 1 Nov 2004 05:19:01 -0500 darcs (1.0.0rc3) * Fixed bug leading to creation of empty "hunk" patches. * Fixed bug in rollback when there are pending changes. * Fixed push bug when default apply is --interactive. * Fixed a bug where "darcs pull --list-options" would try to complete to "home/.../darcs_repo" instead of "/home/.../darcs_repo". * Fixed flushing bug in darcs.cgi. * Fixed commutation bug with renames and file adds/removals. * Made --summary indicate conflicted changes. * Fixed generation of extra hunk in diff algorithm. * Added X-Mail-Originator header to emails sent by darcs. * Fixed a couple of bugs in the resolve command. * Added new cgi diff command to produce unified diff. * Notify when there are conflicts on push. * Added 'a' key to say yes to all remaining changes for interactive commands. * Automatically generate AUTHORS file from repo history. * Made pull --quiet actually quiet. * Fixed bugs in whatsnew -ls, and distinguished between manually added files and automatically added files. * Fixed bug in darcs --commands when called outside a repo. -- David Roundy Sun, 3 Oct 2004 07:45:05 -0400 darcs (1.0.0rc2) * Added support for comments in prefs files. * Added new --enable-antimemoize compile option which reduces memory usage at the expense of increased computational time. * Added a new command: "reportbug" * Fixed a bug that prevented applying of a patch bundle to an "unoptimized" repo. * Fixed bug where asking for changes to a nonexistent file in a subdirectory would show the patch that created or renamed that subdirectory. * Improved the robustness of unrevert. Now actions that will make unrevert impossible should warn the user. * Fixed bug when moving files or directories to the root directory of repo. * Various changes to make the --logfile way of specifying the patch name and comments in record more friendly: - Allows editing of the long comment even when --logfile is specified, if the --edit-long-comment option is also used. - When editing the long comment, the change summary is included below the actual text for reference, and the patch name is included in the first line (and thus may be modified). - The --logfile option is ignored if such a file doesn't exist. - A --delete-logfile option was added, which tells darcs to delete the file after doing the record. This is intended to allow you to stick a --logfile=foo option in your defaults without accidentally recording multiple patches with the same comments because you forgot to modify it. * Fixed bug leading to .hi files in tarball. * Made ctrl-C work under windows, but only "pure" windows consoles, not in cygwin shells or mingw's rxvt (room for improvement here). * Fixed bug that led to curl not being tried when darcs is not compiled with libcurl. * Added an environment variable DARCS_USE_ISPRINT for people who use non-ascii characters in their files to indicate if the haskell standard library "isPrint" function works properly on their system (which depends on locale). * Reduced the number of hunks produced by the internal diff algorithm, when there are multiple equivalent ways of interpreting a change. * Made the --from-{patch,tag,match} options inclusive, and added a --{patch,match} option to diff (which was made easier to define by the inclusiveness change, since --patch x is now equivalent to --from-patch x --to-patch x). * Added support for a second argument to get, which specifies the name of the new directory. -- David Roundy Sun, 12 Sep 2004 06:54:45 -0400 darcs (1.0.0rc1) * Remove some lazy file IO which may have been causing trouble pushing in windows and using windows shares. * Various interface improvements and improved error messages. * Fixed bug that could cause conflicts in pending when unrecording a patch that contained two non-commuting non-hunk patches. * Fixed bug in --ask-deps option of record. * Added --exact-version option which gives the precise darcs context from which darcs was compiled. * MIME fixes in patch forwarding. * Various improvements to the darcs.cgi script. * Added --reverse option to changes. * Fixed patch numbering when file or directory arguments are given to an interactive command. -- David Roundy Sun, 15 Aug 2004 07:43:30 -0400 darcs (0.9.23) * Added a rerecord command, which will add changes to an existing recorded patch * Added support for a MOTD. * Vastly improved the speed and memory use of darcs optimize --checkpoint as well as darcs record, in the case where a record consists primarily of adds. -- David Roundy Mon, 26 Jul 2004 08:11:20 -0400 darcs (0.9.22) * add preliminary --context option to changes and get. * display change number, e.g. "(1/3)" in interactive commands. * show moves in summary format. * add hash of patch bundles in darcs send. * properly support --verbose and --quiet in add. * don't display binary data to screen. * fix bug in selecting patches by pattern. * fix various locking-related bugs introduced in 0.9.21. * fix bug when specifying logfile in a subdirectory. * support backslashes for directory separators in windows. * fix file modification time bug. -- David Roundy Sat, 26 Jun 2004 07:42:05 -0400 darcs (0.9.21) * made mv work even if you've already mv'ed the file or directory. * remember configure settings when reconfiguring. * added --leave-test-directory to save the directory in which the test is run on record or check. * added HTTP redirect support (thanks Benedikt). * fixed problems when unrecording a patch with conflits. * fixed locking on nfs (thanks Juliusz). * added preliminary version of a new cgi script for browsing darcs repositories (thanks to Will Glozer for contributing this). * add and modify a number of short flag options. * fix bug in applying new order patch bundles that are GPG signed. * fix bug in diff when a tagged version was requested. -- David Roundy Sat, 12 Jun 2004 05:39:48 -0400 darcs (0.9.20) * fix bug in darcs-createrepo. * add support for DARCS_SCP and DARCS_SSH environment variables. * add XML support for --summary options of changes and annotate. * better command-line completion on commands accepting a list of files or directories. * fix bug causing empty hunk patches to lead to failures. * fix bug where --all overrode file choice in record. * fix bug when testing patches that create subdirectories within subdirectories. * preserve pending changes when pulling or applying. * give better error message in pull when patch isn't readable. * allow sendEmail with no "to", just "cc" recipients. This should fix the trouble with trying to --reply to a patch coming from a push rather than a send. -- David Roundy Wed, 5 May 2004 06:01:48 -0400 darcs (0.9.19) * fix bugs leading to failures in the wxhaskell interface. * fix bug that caused darcs diff to fail. * fixed bug in get that lead to _darcs/current/_darcs directories. * improved error reporting in several situations. * fixed bug when pulling or pushing into an empty repo. * added --summary option to changes to summarize the changes made in each patch. -- David Roundy Fri, 9 Apr 2004 07:19:34 -0400 darcs (0.9.18) * added support for sending email from windows using the MAPI interface. This code attaches the patch bundle in base64-encoded form, which darcs can't currently decode (expect that in the next release), but the patch bundle can be manually applied if a mail program does the decoding. * renamed "darcs push" to "darcs send" and added a new "darcs push" command roughly equivalent to the old "darcs push --and-apply". * removed support for setting up a test suite by simple creating a file named "darcs_test". You now should use setpref to define the test suite command. * fixed some problems when working in a --partial repository. * lots of code was cleaned up. We have enabled the -Wall compiler flag and are in the process of eliminating all the warnings. This should make the code more friendly to new developers, and also helps with the next bullet point: * improved handling of errors--informative failure messages are more likely than they were before. * by default only check changes made since last checkpoint--this greatly speeds up check. * add --quiet option. Some commands don't yet support this. If there's a command you want to quiet down, let us know. * several performance enhancements: improved SHA1 performance, faster check and get on repositories with a long history and improved performance with very large files. -- David Roundy Thu, 1 Apr 2004 05:43:18 -0500 darcs (0.9.17) * fixed bug in darcs apply that made the --no-test option fail. * fixed bug that caused darcs to set file permissions to be non-world-readable. * darcs record and whatsnew can now accept file or directory arguments and limit their actions to changes in those files or directories. * darcs changes now can accept file or directory arguments and limit itself to changes affecting those files or directories. -- David Roundy Sat, 21 Feb 2004 08:12:34 -0500 darcs (0.9.16) * Add --sign-as=KEYID option to push command. * make optimize split up inventory for faster pulls * Allow use of a different make command for tests, such as gmake * Can now put prefs that would normally go in _darcs/prefs (defaults, binaries and boring) in ~/.darcs/ to set the prefs for all your repositories at once. * add primitive xml output to annotate of directory. * When pushing a patch, add the list of changes in the description. * refuse to rollback a patch twice, since that would cause problems. * make darcs diff accept optional arguments indicating files and directories to diff. * preserve permissions on files in working directory. * put docs in ...share/doc/darcs not share/darcs/doc. * add support for multiple-choice options. This means that you can now set your default option in _darcs/prefs/defaults, and then override that default on the command line. * shortened --use-external-merge-tool option to --external-merge * more "boring" patterns. -- David Roundy Tue, 10 Feb 2004 07:08:14 -0500 darcs (0.9.15) * next step repository format transition--we use the new patch filenames. * fix handling of text files with no trailing newline--this will cause some trouble. Darcs will require that you convert your repository using convert-repo. This will leave you with a bunch of changes regarding trailing newlines which you will either want to record or revert. * the windows support is somewhat improved. * added simple "repair" command that can repair some kinds of inconsistencies in the repository. * added primitive "annotate" command to extract information about modifications to files and directories. * fixed handling of darcs mv to allow moving to directories in a more intuitive manner. * handling of binary files was dramatically improved in both memory and cpu usage. * added autoconf testing framework to clean up code dealing with different versions of ghc, features that don't exist on windows, bugs that only exist on windows, etc. * don't accept invalid flags. * add more patterns to boring and binary. * use autoconf test to handle posix signals and windows '\\' handling. * switch to using new patch filenames. * XML formatted output for 'changes' command * add support for unidiff-like whatsnew output. * fix bug in RTS memory calculation for large RAM size * add rollback command. * improve checkpointing support. * add diff-opts option to darcs diff. * add support for building docs using htlatex or hevea rather than latex2html. * use locking whereever it is needed. * add safe (atomic) writing of inventory files. -- David Roundy Fri, 12 Dec 2003 07:59:54 -0500 darcs (0.9.14) * darcs changes now shows times formatted according to current locale. * add support for automatically treating files containing ^Z or '\0' as binary. * add experimental checkpointing, allowing get to only download the recent change history. * allow darcs to be called within subdirectories of a repository. * make default be to compress patches. * add --summary option to whatsnew. * add trackdown command. * fix bug in darcs dist --verbose. * make darcs diff have closer behavior to cvs diff. In particular, darcs diff with no arguments now gives you the difference between the working directory and the latest recorded version. * support external graphical merge tools. * fix bug where binary patch is created even with no change. * support darcs -v for version. Also mention the darcs version in the usage mesage. * ignore empty lines in boring file and binary file. * preserve pending changes (e.g. file adds or darcs replaces) across revert and record. * create repositories with new patch filename format. The new repo format is now created alongside the old format, but the old format is read. There is a tool called convert-repo that will convert an old format repo to have both formats. * use iso format for dates in record. * New patch-selecting interface. This patch only uses the new routine for revert, since it's not particularly well tested. The text method now allows one to go back and edit previous patches. The idea is that eventually all commands that need the user to select a subset of patches will use this routine. * use hash for cgi cache file names. * add preliminary experimental GUI support using wxhaskell. * remember author name after first record in a repo. * add unrevert command. * always match full pathnames when checking boringness or binaryness. * rewrite replace tokenizer for more speed. * make darcs compile with ghc 6.2 and later. * fix some bugs in darcs diff. * make --and-apply work locally as well as via ssh. Also added a --and-apply-as that uses sudo to run the apply command as a different user. -- David Roundy Mon, 10 Nov 2003 07:08:20 -0500 darcs (0.9.13) * Various performance enhancements. * add --pipe option to tag and record, which causes them to prompt for all their input, including date. This can be useful when creating repository converters. * remove '-t' short command line option for '--to' and the '-o' short option for '--reponame'. * remove the darcs-patcher program. The functionality of the darcs-patcher program is taken over by the darcs apply command. Several fancy features have been added, as described in the Apply section of the manual. * support spaces and (maybe) unicode in filenames. * updates to win32 support * push via ssh * add --without-libcurl option to configure * include DarcsURL in push email. * add support for reading and writing gzipped patch files. * allow multiple --to addresses on push, and also support --cc for additional addresses. * when pulling or pushing from lastrepo, say where lastrepo is. * only save lastrepo in get if the source repo wasn't a relative directory path. -- David Roundy darcs (0.9.12) * add manual section on building darcs. * improve scaling of checking for and resolving conflicts, which was an O(n^2) function. * escape ESC char when printing patches. * don't reorder patches unless necesary--this avoids an O(n^2) operation which was making a darcs record very slow when a lot of files were added. * fix default regexps for boring file (Thanks Trevor!) * replace now ignores files that aren't in the repo. * make darcs add refuse to add files whose subdirectories don't exist. * implement support for binary files. * added support for running external programs to fetch files. * fix conflict resolution bug from 0.9.11. * make the patcher run the test prior to applying. * add repo locking. * Fix bug when pulling from a repo containing just one patch (thanks Peter). * install cgi script in cgi-bin directory. -- David Roundy darcs (0.9.11) * A rewrite of the configure code and makefile (thanks to Peter Simons). * Added several new repository configuration options including a setpref command which allows you to set preferences options that are pulled from repo to repo. * Yet another rewrite of the merging code. * User can now revert changes on a change-by-change basis. * Yet another major improvement in speed and memory consumption. * Add a darcs diff command to compare two versions. -- David Roundy Mon, 30 Jun 2003 06:42:10 -0400 darcs (0.9.10) * Added a way to configure the default values for options to darcs commands. See Appendix B of manual. * darcs push and pull now default to pulling and pushing from the most recently accessed repository (if you don't specify a repo). * Numerous bugfixes. -- David Roundy Wed, 21 May 2003 07:08:40 -0400 darcs (0.9.9) * Created a way to have a "centralized server". (See darcs-patcher chapter in manual). * Added new darcs-server package. * Switch to new repository format. Note that your repo will only be converted to the new format if you use certain commands such as unpull. You can recognize the new format by the presence of a _darcs/inventories/ directory. * Add the ability to sign patches sent with push using gnupg and to verify those signatures when applying. (This is the authentication basis for the above-mentioned server). * Fix bug in application of a file rename patch. -- David Roundy Thu, 8 May 2003 06:58:42 -0400 darcs (0.9.8) * Fix rare bug in check when files happen to be a multiple of 1024 bytes in length. * Fix bug in reading patch ids with long comments from local files. * Prepare for a change in the repository format. The format doesn't change for this version, but version 0.9.8 is able to read the new repository format. -- David Roundy Wed, 30 Apr 2003 08:54:18 -0400 darcs (0.9.7) * Fix a couple of rename conflict bugs. * Add new test suite framework, along with several tests. * Several major optimizations for speed and memory. * Added --ignore-times option to not assume that when a file modification time hasn't changed the file itself hasn't changed. -- David Roundy Sat, 26 Apr 2003 07:57:01 -0400 darcs (0.9.6) * Fixed a couple of bugs in the merging of conflicting renames. * Added an interface to include long comments when recording. * Improve the interface of pull, allowing for viewing the patches before pulling them. * Include zsh command completion examples with docs. * Massively improved responsiveness in command completion. * Use packed strings to save memory. * Fixed a bug that shows up in empty repos. * Fixed multiple bugs in the mv command. -- David Roundy Thu, 17 Apr 2003 09:34:34 -0400 darcs (0.9.5) * Improve merge of creation of files and directories with the same name. * Add darcs push and apply commands, which are the beginning of work towards supporting a "centralized server" concept a la CVS. However, they are also useful for a "Linus" style workflow, based on emailing patches. In theory they could also be used to provide a smart server that could server pulls using less bandwidth. * Add an unpull command analagous to unrecord, but which removes the patches from the working directory also. * Enable the mv command, since the mv patches have now been supported by a couple of versions. * Include zsh_completion code, thanks to Aaron Denney . -- David Roundy Wed, 9 Apr 2003 07:52:01 -0400 darcs (0.9.4) * Speed up whatsnew and record in the case where there are huge numbers of extra files in the working directory. * Small (~10%) speedup in get. -- David Roundy Fri, 4 Apr 2003 09:08:38 -0500 darcs (0.9.3) * Optimized whatsnew and record by seting modification time of "current" files equal to that of working files if they are identical, so I won't have to check again if the working one hasn't been changed. * Rewrite file renaming code (no creation). * Add support for replacing tokens in files. * Make cgi output work more accurately, and point out which files were modified by each patch. * Add a caching feature to the cgi script to speed things up a bit. * Turn on creation of dependencies when recording. * Add a 'tag' command. * Rewrote the 'pull' code to hopefully speed it up (and in any case to greatly simplify it). -- David Roundy Thu, 3 Apr 2003 07:08:05 -0500 darcs (0.9.2) * Add build dependency on tetex and latex2html * Have internal diff code properly respond to deleted files and directories. * Create file and directory rename patch types. (no creation--which means that I am waiting to create commands to create such patches until later, to avoid backward compatibility issues of repos.) * Add support for patch dependencies. (no creation) * Add support for token replacement patches. (no creation) -- David Roundy Thu, 27 Mar 2003 07:59:09 -0500 darcs (0.9.1) * Make darcs get --verbose actually be verbose (which is important because it takes so long that the user might be afraid it's hanging. * Speed up the merge in complicated cases, possibly dramatically. * Add a darcs remove command. -- David Roundy Mon, 10 Mar 2003 09:48:55 -0500 darcs 0.9.0 * Initial Release. -- David Roundy Wed, 3 Mar 2003 13:51:58 -0500 Local variables: mode: outline outline-regexp: "[dD]\\| +\\*+" paragraph-separate: "[ ]*$" end: darcs-2.8.4/tests/0000755001765600176560000000000012104371431013303 5ustar ganeshganeshdarcs-2.8.4/tests/data/0000755001765600176560000000000012104371431014214 5ustar ganeshganeshdarcs-2.8.4/tests/data/convert/0000755001765600176560000000000012104371431015674 5ustar ganeshganeshdarcs-2.8.4/tests/data/convert/darcs1/0000755001765600176560000000000012104371431017051 5ustar ganeshganeshdarcs-2.8.4/tests/data/convert/darcs1/resolution.dpatch0000644001765600176560000000204212104371431022437 0ustar ganeshganesh5 patches for repository /tmp/tmp6648/temp/empty-hashed: Sat Oct 16 23:32:07 BST 2010 tester * wibble Sat Oct 16 23:32:07 BST 2010 tester * A Sat Oct 16 23:32:07 BST 2010 tester * B Sat Oct 16 23:32:07 BST 2010 tester * AB Sat Oct 16 23:32:07 BST 2010 tester * C New patches: [wibble tester**20101016223207 Ignore-this: 64b5a1e603ddf61e59421bdde45b3bc ] { addfile ./wibble hunk ./wibble 1 +wibble } [A tester**20101016223207 Ignore-this: bc0d30ac5170e1a25ccb20e6cb06ac86 ] hunk ./wibble 2 wibble +A [B tester**20101016223207 Ignore-this: 3bbebcf8fa444bdcb31ab799c6754067 ] merger 0.0 ( hunk ./wibble 2 +A hunk ./wibble 2 +B ) [AB tester**20101016223207 Ignore-this: 8fa03d26b9dbbcdb50a323e5c58b16dd ] hunk ./wibble 2 wibble +AB [C tester**20101016223207 Ignore-this: e7c0716361e411645066f8a3c2eff769 ] merger 0.0 ( hunk ./wibble 2 +AB merger 0.0 ( merger 0.0 ( hunk ./wibble 2 +A hunk ./wibble 2 +B ) merger 0.0 ( hunk ./wibble 2 +A hunk ./wibble 2 +C ) ) ) Context: Patch bundle hash: b23d175b10d6fdaee3bb25ac92b55723de2822cd darcs-2.8.4/tests/data/convert/darcs1/simple.dpatch0000644001765600176560000000047312104371431021533 0ustar ganeshganesh1 patch for repository /tmp/tmp5746/temp/empty-hashed: Sat Oct 16 23:28:30 BST 2010 tester * wibble New patches: [wibble tester**20101016222830 Ignore-this: f155bc27211e0233c23b8c0a757b8071 ] { addfile ./wibble hunk ./wibble 1 +wibble } Context: Patch bundle hash: 1bfa82f0941e1dcc13f9f94179dd6a7426ca0b6f darcs-2.8.4/tests/data/convert/darcs1/threewayconflict.dpatch0000644001765600176560000000155312104371431023614 0ustar ganeshganesh4 patches for repository /tmp/tmp5605/temp/empty-hashed: Sat Oct 16 23:28:14 BST 2010 tester * wibble Sat Oct 16 23:28:14 BST 2010 tester * A Sat Oct 16 23:28:14 BST 2010 tester * B Sat Oct 16 23:28:14 BST 2010 tester * C New patches: [wibble tester**20101016222814 Ignore-this: c125275c671c210086eccb12de9f6c1c ] { addfile ./wibble hunk ./wibble 1 +wibble } [A tester**20101016222814 Ignore-this: 653be63c1f8a6f4bc1de1e45c0ae9084 ] hunk ./wibble 2 wibble +A [B tester**20101016222814 Ignore-this: 1a8e3f57d2baeca09f2dda003e4df58d ] merger 0.0 ( hunk ./wibble 2 +A hunk ./wibble 2 +B ) [C tester**20101016222814 Ignore-this: 9d40b33ef1b73b9a950f39c4e8a75dfe ] merger 0.0 ( merger 0.0 ( hunk ./wibble 2 +A hunk ./wibble 2 +B ) merger 0.0 ( hunk ./wibble 2 +A hunk ./wibble 2 +C ) ) Context: Patch bundle hash: c189b5635aed28be92cfbcf0de65c0f40c79da7a darcs-2.8.4/tests/data/convert/darcs1/threewayanddep.dpatch0000644001765600176560000000216312104371431023244 0ustar ganeshganesh5 patches for repository /tmp/tmp5530/temp/empty-hashed: Sat Oct 16 23:27:54 BST 2010 tester * wibble Sat Oct 16 23:27:54 BST 2010 tester * A1 Sat Oct 16 23:27:54 BST 2010 tester * A2 Sat Oct 16 23:27:54 BST 2010 tester * B Sat Oct 16 23:27:54 BST 2010 tester * C New patches: [wibble tester**20101016222754 Ignore-this: 355914edd0f88f0ea7c2ef60aec9c2a1 ] { addfile ./wibble hunk ./wibble 1 +wibble } [A1 tester**20101016222754 Ignore-this: 54df34ebd488b772c37c3d43a38b0bfa ] hunk ./wibble 2 wibble +A1 [A2 tester**20101016222754 Ignore-this: 4d1b08c7274743e7d0d2f210518d5a19 ] hunk ./wibble 3 wibble A1 +A2 [B tester**20101016222754 Ignore-this: 9ba51da6bb1506afa2104326cd5df54b ] merger 0.0 ( hunk ./wibble 3 +A2 merger 0.0 ( hunk ./wibble 2 +A1 hunk ./wibble 2 +B ) ) [C tester**20101016222754 Ignore-this: 295e8a851b7a936b3d08b0ce7eaaf2ac ] merger 0.0 ( merger 0.0 ( hunk ./wibble 3 +A2 merger 0.0 ( hunk ./wibble 2 +A1 hunk ./wibble 2 +B ) ) merger 0.0 ( hunk ./wibble 3 +A2 merger 0.0 ( hunk ./wibble 2 +A1 hunk ./wibble 2 +C ) ) ) Context: Patch bundle hash: 3c77da1c02a49215134a9607493af93d55608f56 darcs-2.8.4/tests/data/convert/darcs1/threewayandmultideps.dpatch0000644001765600176560000000507112104371431024503 0ustar ganeshganesh7 patches for repository /tmp/tmp5411/temp/empty-hashed: Sat Oct 16 23:27:21 BST 2010 tester * wibble Sat Oct 16 23:27:21 BST 2010 tester * A1 Sat Oct 16 23:27:21 BST 2010 tester * A2 Sat Oct 16 23:27:21 BST 2010 tester * B1 Sat Oct 16 23:27:21 BST 2010 tester * B2 Sat Oct 16 23:27:21 BST 2010 tester * C1 Sat Oct 16 23:27:21 BST 2010 tester * C2 New patches: [wibble tester**20101016222721 Ignore-this: 64432ba123d81c8f0e688b44feb8f587 ] { addfile ./wibble hunk ./wibble 1 +wibble } [A1 tester**20101016222721 Ignore-this: d749f48333e6ff2e994b1df71e76933b ] hunk ./wibble 2 wibble +A1 [A2 tester**20101016222721 Ignore-this: 6f006a52975a708a8038d52e5e39ef0f ] hunk ./wibble 3 wibble A1 +A2 [B1 tester**20101016222721 Ignore-this: f4d4b5b1c73bd6fa8abe6e5e680d66a7 ] merger 0.0 ( hunk ./wibble 3 +A2 merger 0.0 ( hunk ./wibble 2 +A1 hunk ./wibble 2 +B1 ) ) [B2 tester**20101016222721 Ignore-this: 1d60b6c0ba913fff4d1e32ad26ae07bb ] merger 0.0 ( merger 0.0 ( merger 0.0 ( hunk ./wibble 2 +A1 hunk ./wibble 2 +B1 ) hunk ./wibble 3 +A2 ) merger 0.0 ( merger 0.0 ( hunk ./wibble 2 +B1 hunk ./wibble 2 +A1 ) hunk ./wibble 3 +B2 ) ) [C1 tester**20101016222721 Ignore-this: 25b6a6959d19980ad16983a542c6825 ] merger 0.0 ( merger 0.0 ( merger 0.0 ( merger 0.0 ( hunk ./wibble 2 +A1 hunk ./wibble 2 +B1 ) hunk ./wibble 3 +A2 ) merger 0.0 ( merger 0.0 ( hunk ./wibble 2 +B1 hunk ./wibble 2 +A1 ) hunk ./wibble 3 +B2 ) ) merger 0.0 ( merger 0.0 ( hunk ./wibble 3 +A2 merger 0.0 ( hunk ./wibble 2 +A1 hunk ./wibble 2 +B1 ) ) merger 0.0 ( hunk ./wibble 3 +A2 merger 0.0 ( hunk ./wibble 2 +A1 hunk ./wibble 2 +C1 ) ) ) ) [C2 tester**20101016222721 Ignore-this: c16d607216c36d5f7727c64d2ec103d4 ] merger 0.0 ( merger 0.0 ( merger 0.0 ( merger 0.0 ( hunk ./wibble 3 +A2 merger 0.0 ( hunk ./wibble 2 +A1 hunk ./wibble 2 +B1 ) ) merger 0.0 ( hunk ./wibble 3 +A2 merger 0.0 ( hunk ./wibble 2 +A1 hunk ./wibble 2 +C1 ) ) ) merger 0.0 ( merger 0.0 ( merger 0.0 ( hunk ./wibble 2 +A1 hunk ./wibble 2 +B1 ) hunk ./wibble 3 +A2 ) merger 0.0 ( merger 0.0 ( hunk ./wibble 2 +B1 hunk ./wibble 2 +A1 ) hunk ./wibble 3 +B2 ) ) ) merger 0.0 ( merger 0.0 ( merger 0.0 ( hunk ./wibble 3 +A2 merger 0.0 ( hunk ./wibble 2 +A1 hunk ./wibble 2 +C1 ) ) merger 0.0 ( hunk ./wibble 3 +A2 merger 0.0 ( hunk ./wibble 2 +A1 hunk ./wibble 2 +B1 ) ) ) merger 0.0 ( merger 0.0 ( merger 0.0 ( hunk ./wibble 2 +A1 hunk ./wibble 2 +C1 ) hunk ./wibble 3 +A2 ) merger 0.0 ( merger 0.0 ( hunk ./wibble 2 +C1 hunk ./wibble 2 +A1 ) hunk ./wibble 3 +C2 ) ) ) ) Context: Patch bundle hash: 1069761dac242f9583871b27db2fabbd00d6f805 darcs-2.8.4/tests/data/convert/darcs1/tworesolutions.dpatch0000644001765600176560000000323412104371431023360 0ustar ganeshganesh7 patches for repository /tmp/tmp6805/temp/empty-hashed: Sat Oct 16 23:34:33 BST 2010 tester * wibble Sat Oct 16 23:34:33 BST 2010 tester * A Sat Oct 16 23:34:33 BST 2010 tester * B Sat Oct 16 23:34:33 BST 2010 tester * AB Sat Oct 16 23:34:33 BST 2010 tester * C Sat Oct 16 23:34:33 BST 2010 tester * ABC Sat Oct 16 23:34:33 BST 2010 tester * D New patches: [wibble tester**20101016223433 Ignore-this: 577185c51e4839dd1041372fbfa8515b ] { addfile ./wibble hunk ./wibble 1 +wibble } [A tester**20101016223433 Ignore-this: 580c4417986d5c56590bf36f5a125f38 ] hunk ./wibble 2 wibble +A [B tester**20101016223433 Ignore-this: a9f2335fe2dc972fd0bc09edc6252256 ] merger 0.0 ( hunk ./wibble 2 +A hunk ./wibble 2 +B ) [AB tester**20101016223433 Ignore-this: cba095e78e2bdfe15dbdf2cb5c69cc6d ] hunk ./wibble 2 wibble +AB [C tester**20101016223433 Ignore-this: da2a7e05abed8dba0077e69e55bd926 ] merger 0.0 ( hunk ./wibble 2 +AB merger 0.0 ( merger 0.0 ( hunk ./wibble 2 +A hunk ./wibble 2 +B ) merger 0.0 ( hunk ./wibble 2 +A hunk ./wibble 2 +C ) ) ) [ABC tester**20101016223433 Ignore-this: db94de3935df87d0a991c0ab6a58e5b1 ] hunk ./wibble 2 wibble +ABC [D tester**20101016223433 Ignore-this: 829adb4326b290aa6f741b3a15fbabfc ] merger 0.0 ( hunk ./wibble 2 +ABC merger 0.0 ( merger 0.0 ( hunk ./wibble 2 +AB merger 0.0 ( merger 0.0 ( hunk ./wibble 2 +A hunk ./wibble 2 +B ) merger 0.0 ( hunk ./wibble 2 +A hunk ./wibble 2 +C ) ) ) merger 0.0 ( hunk ./wibble 2 +AB merger 0.0 ( merger 0.0 ( hunk ./wibble 2 +A hunk ./wibble 2 +B ) merger 0.0 ( hunk ./wibble 2 +A hunk ./wibble 2 +D ) ) ) ) ) Context: Patch bundle hash: 5fc1d0ff89472d10a0b19ae4f7849b1b99d500b4 darcs-2.8.4/tests/data/convert/darcs1/twowayconflict.dpatch0000644001765600176560000000117312104371431023314 0ustar ganeshganesh3 patches for repository /tmp/tmp5677/temp/empty-hashed: Sat Oct 16 23:28:22 BST 2010 tester * wibble Sat Oct 16 23:28:22 BST 2010 tester * A Sat Oct 16 23:28:22 BST 2010 tester * B New patches: [wibble tester**20101016222822 Ignore-this: 88662d08dd524d92ad4cca6df0d643e4 ] { addfile ./wibble hunk ./wibble 1 +wibble } [A tester**20101016222822 Ignore-this: 2d69de402438481946682efcad5e20cd ] hunk ./wibble 2 wibble +A [B tester**20101016222822 Ignore-this: 9c8daaedcb674c022ddbcef19752d694 ] merger 0.0 ( hunk ./wibble 2 +A hunk ./wibble 2 +B ) Context: Patch bundle hash: 1e2ce71b56e4666c1b086b09ae351a6c3c768b8c darcs-2.8.4/tests/data/convert/darcs2/0000755001765600176560000000000012104371431017052 5ustar ganeshganeshdarcs-2.8.4/tests/data/convert/darcs2/resolution.dpatch0000644001765600176560000000167412104371431022452 0ustar ganeshganesh5 patches for repository /tmp/tmp6648/temp/empty-darcs2: Sat Oct 16 23:32:07 BST 2010 tester * wibble Sat Oct 16 23:32:07 BST 2010 tester * A Sat Oct 16 23:32:07 BST 2010 tester * B Sat Oct 16 23:32:07 BST 2010 tester * AB Sat Oct 16 23:32:07 BST 2010 tester * C New patches: [wibble tester**20101016223207 Ignore-this: 64b5a1e603ddf61e59421bdde45b3bc ] addfile ./wibble hunk ./wibble 1 +wibble [A tester**20101016223207 Ignore-this: bc0d30ac5170e1a25ccb20e6cb06ac86 ] hunk ./wibble 2 wibble +A [B tester**20101016223207 Ignore-this: 3bbebcf8fa444bdcb31ab799c6754067 ] conflictor [ hunk ./wibble 2 +A ] : hunk ./wibble 2 +B [AB tester**20101016223207 Ignore-this: 8fa03d26b9dbbcdb50a323e5c58b16dd ] hunk ./wibble 2 wibble +AB [C tester**20101016223207 Ignore-this: e7c0716361e411645066f8a3c2eff769 ] conflictor [ hunk ./wibble 2 +AB ] : hunk ./wibble 2 +C Context: Patch bundle hash: cc43b921f6010f451b2dbe275b7fcd04c3862335 darcs-2.8.4/tests/data/convert/darcs2/simple.dpatch0000644001765600176560000000046712104371431021537 0ustar ganeshganesh1 patch for repository /tmp/tmp5746/temp/empty-darcs2: Sat Oct 16 23:28:30 BST 2010 tester * wibble New patches: [wibble tester**20101016222830 Ignore-this: f155bc27211e0233c23b8c0a757b8071 ] addfile ./wibble hunk ./wibble 1 +wibble Context: Patch bundle hash: 75ced55c52362a8b2ff171b48751d19000fe1790 darcs-2.8.4/tests/data/convert/darcs2/threewayconflict.dpatch0000644001765600176560000000150312104371431023610 0ustar ganeshganesh4 patches for repository /tmp/tmp5605/temp/empty-darcs2: Sat Oct 16 23:28:14 BST 2010 tester * wibble Sat Oct 16 23:28:14 BST 2010 tester * A Sat Oct 16 23:28:14 BST 2010 tester * B Sat Oct 16 23:28:14 BST 2010 tester * C New patches: [wibble tester**20101016222814 Ignore-this: c125275c671c210086eccb12de9f6c1c ] addfile ./wibble hunk ./wibble 1 +wibble [A tester**20101016222814 Ignore-this: 653be63c1f8a6f4bc1de1e45c0ae9084 ] hunk ./wibble 2 wibble +A [B tester**20101016222814 Ignore-this: 1a8e3f57d2baeca09f2dda003e4df58d ] conflictor [ hunk ./wibble 2 +A ] : hunk ./wibble 2 +B [C tester**20101016222814 Ignore-this: 9d40b33ef1b73b9a950f39c4e8a75dfe ] conflictor {{ : hunk ./wibble 2 +A : hunk ./wibble 2 +B }} [] : hunk ./wibble 2 +C Context: Patch bundle hash: ba3e1ce15840fd37358fcd43c4c03273d1779153 darcs-2.8.4/tests/data/convert/darcs2/threewayanddep.dpatch0000644001765600176560000000175112104371431023247 0ustar ganeshganesh5 patches for repository /tmp/tmp5530/temp/empty-darcs2: Sat Oct 16 23:27:54 BST 2010 tester * wibble Sat Oct 16 23:27:54 BST 2010 tester * A1 Sat Oct 16 23:27:54 BST 2010 tester * A2 Sat Oct 16 23:27:54 BST 2010 tester * B Sat Oct 16 23:27:54 BST 2010 tester * C New patches: [wibble tester**20101016222754 Ignore-this: 355914edd0f88f0ea7c2ef60aec9c2a1 ] addfile ./wibble hunk ./wibble 1 +wibble [A1 tester**20101016222754 Ignore-this: 54df34ebd488b772c37c3d43a38b0bfa ] hunk ./wibble 2 wibble +A1 [A2 tester**20101016222754 Ignore-this: 4d1b08c7274743e7d0d2f210518d5a19 ] hunk ./wibble 3 wibble A1 +A2 [B tester**20101016222754 Ignore-this: 9ba51da6bb1506afa2104326cd5df54b ] conflictor [ hunk ./wibble 2 +A1 +A2 ] : hunk ./wibble 2 +B [C tester**20101016222754 Ignore-this: 295e8a851b7a936b3d08b0ce7eaaf2ac ] conflictor {{ : hunk ./wibble 2 +A1 +A2 : hunk ./wibble 2 +B }} [] : hunk ./wibble 2 +C Context: Patch bundle hash: f9974a2fdbdea580b1be0eaba951e6285f9bfb5d darcs-2.8.4/tests/data/convert/darcs2/threewayandmultideps.dpatch0000644001765600176560000000251012104371431024477 0ustar ganeshganesh7 patches for repository /tmp/tmp5411/temp/empty-darcs2: Sat Oct 16 23:27:21 BST 2010 tester * wibble Sat Oct 16 23:27:21 BST 2010 tester * A1 Sat Oct 16 23:27:21 BST 2010 tester * A2 Sat Oct 16 23:27:21 BST 2010 tester * B1 Sat Oct 16 23:27:21 BST 2010 tester * B2 Sat Oct 16 23:27:21 BST 2010 tester * C1 Sat Oct 16 23:27:21 BST 2010 tester * C2 New patches: [wibble tester**20101016222721 Ignore-this: 64432ba123d81c8f0e688b44feb8f587 ] addfile ./wibble hunk ./wibble 1 +wibble [A1 tester**20101016222721 Ignore-this: d749f48333e6ff2e994b1df71e76933b ] hunk ./wibble 2 wibble +A1 [A2 tester**20101016222721 Ignore-this: 6f006a52975a708a8038d52e5e39ef0f ] hunk ./wibble 3 wibble A1 +A2 [B1 tester**20101016222721 Ignore-this: f4d4b5b1c73bd6fa8abe6e5e680d66a7 ] conflictor [ hunk ./wibble 2 +A1 +A2 ] : hunk ./wibble 2 +B1 [B2 tester**20101016222721 Ignore-this: 1d60b6c0ba913fff4d1e32ad26ae07bb ] [C1 tester**20101016222721 Ignore-this: 25b6a6959d19980ad16983a542c6825 ] conflictor {{ : hunk ./wibble 2 +A1 +A2 : hunk ./wibble 2 +B1 +B2 }} [] : hunk ./wibble 2 +C1 [C2 tester**20101016222721 Ignore-this: c16d607216c36d5f7727c64d2ec103d4 ] conflictor {{ : hunk ./wibble 2 +A1 +A2 : hunk ./wibble 2 +B1 +B2 }} [] : hunk ./wibble 2 +C1 +C2 Context: Patch bundle hash: 7f2bd6324e6e1f2d4efe67f98696ca0ead048fe5 darcs-2.8.4/tests/data/convert/darcs2/tworesolutions.dpatch0000644001765600176560000000240412104371431023357 0ustar ganeshganesh7 patches for repository /tmp/tmp6805/temp/empty-darcs2: Sat Oct 16 23:34:33 BST 2010 tester * wibble Sat Oct 16 23:34:33 BST 2010 tester * A Sat Oct 16 23:34:33 BST 2010 tester * B Sat Oct 16 23:34:33 BST 2010 tester * AB Sat Oct 16 23:34:33 BST 2010 tester * C Sat Oct 16 23:34:33 BST 2010 tester * ABC Sat Oct 16 23:34:33 BST 2010 tester * D New patches: [wibble tester**20101016223433 Ignore-this: 577185c51e4839dd1041372fbfa8515b ] addfile ./wibble hunk ./wibble 1 +wibble [A tester**20101016223433 Ignore-this: 580c4417986d5c56590bf36f5a125f38 ] hunk ./wibble 2 wibble +A [B tester**20101016223433 Ignore-this: a9f2335fe2dc972fd0bc09edc6252256 ] conflictor [ hunk ./wibble 2 +A ] : hunk ./wibble 2 +B [AB tester**20101016223433 Ignore-this: cba095e78e2bdfe15dbdf2cb5c69cc6d ] hunk ./wibble 2 wibble +AB [C tester**20101016223433 Ignore-this: da2a7e05abed8dba0077e69e55bd926 ] conflictor [ hunk ./wibble 2 +AB ] : hunk ./wibble 2 +C [ABC tester**20101016223433 Ignore-this: db94de3935df87d0a991c0ab6a58e5b1 ] hunk ./wibble 2 wibble +ABC [D tester**20101016223433 Ignore-this: 829adb4326b290aa6f741b3a15fbabfc ] conflictor [ hunk ./wibble 2 +ABC ] : hunk ./wibble 2 +D Context: Patch bundle hash: b0ac3265aeb09b15b7dbc1dcf9447dae35d00a86 darcs-2.8.4/tests/data/convert/darcs2/twowayconflict.dpatch0000644001765600176560000000117112104371431023313 0ustar ganeshganesh3 patches for repository /tmp/tmp5677/temp/empty-darcs2: Sat Oct 16 23:28:22 BST 2010 tester * wibble Sat Oct 16 23:28:22 BST 2010 tester * A Sat Oct 16 23:28:22 BST 2010 tester * B New patches: [wibble tester**20101016222822 Ignore-this: 88662d08dd524d92ad4cca6df0d643e4 ] addfile ./wibble hunk ./wibble 1 +wibble [A tester**20101016222822 Ignore-this: 2d69de402438481946682efcad5e20cd ] hunk ./wibble 2 wibble +A [B tester**20101016222822 Ignore-this: 9c8daaedcb674c022ddbcef19752d694 ] conflictor [ hunk ./wibble 2 +A ] : hunk ./wibble 2 +B Context: Patch bundle hash: 33bebb546403626fc8539d4709fbcdb99e47e94c darcs-2.8.4/tests/data/maybench-crc.tgz0000644001765600176560000033702512104371431017307 0ustar ganeshganesh‹CT!Jì<ýwÚH’ùYE“[‹‰ €íxŸ/ø sÏ/àÉæysÐEH¬$l¸dþ÷«ªn}¶q&ž·wt^ŒÔÕÕUÝõ¥îžšËá &…7xýâǤ¦£ÃCú-–’¿azQ.WÊ¥ÊaéèÍÑ‹R¹rTzó>©4÷Óx16áO6×{¨ü_4M“üÿ<4½ÿ‡Oƒ­øPFþ”÷Ë;þ?GZÇÿ™gùåˆ?j"l¿þŽvëÿYÒ½üï ?ø&ÁöüsT>Üñÿ9ÒÃü¿P5ž>¶æ¥tp°¿ãÿs¤-øX¶_œø[÷A ~sp°‰ÿe\ï þ¿AþWÐx¥0Þ•ôÿÿîpn NCN™Óp7žÐ4k:s½f`/\ǵ† Ë_cjÎfÂæ±’3²ÂÛoòÙÆço'š6°M߇ºëøçbÀHAÐß~ËÃñ1˜P8Áìð'Ù¢k'©&ßN¸‰ª7±d¢3q?ןÒUA?Îg*Jð‰š Q†VƧW¯àzñIŒöêÕ‰¦Ó_ÆAQ„êI3¬QEM³q1Q‹ª sµkóýÜä“/²¢cÙð0!^”ª”#‹({€xƒ¾8^øÔ¿-[Myîô\õ”ìÃŒK¨=‰†gň ªô¤ýÙ³q—ž;m!ÿëîtj:Ãí5Àò¿‚>_ZÿWöÑ\ØÉÿgH_ ?Aç²ßê´{ŸßŸÕ¡0£ü»w±|ø©ð»¶VE¨ÉQëÔˆNb;T¤Þþ‚zaˆêB U¨O‡ðÓaÛœ ’a½À³œ±AY5oìSÖµÌûÄ™-g6âŠð»¦ÍgTÔcº*C1(ŸXÞêa¯ø¬ó™¶#tM`Tż—ÑÛ Õ]„ÊSú“Sʬ¨Gùšî2$‰Ò„%¾z~D¯Ü>Õ)çD}òwié%AèM°UEÿW!ÝNÊχÐRÜ| ¿"jg QZ ¨Í!LI«öîÐY«sùpGz~JeKšrˆ`·ÓõH¤æi+‡ Ú4ÂY©ƒ¥Ø¾3£†Æ=øå× %„œ›Ä*Ñš¿H{äu áWÕHÔÃ×W å×p@”±ã‰`î9` S•tEÈŒ ™¡«QíѼ-$j8wœÉs®‚«ci"c¿’Öàº`‡›Fw…ŸÖŒFmr,ÙAàã1þgË-ΦnŠéw_C©» ©ÕÒ\Å'"härÚ l´DØß rZ{lLÖm°3Ilz¼ý÷Ï_¦ì¿7‡o3ö_¹TÞßÙÏ‘Öw£®·ô1-ö­©Èd±XóùŽJ3æVt4ÈP4“Kõ[·]_“÷" ˆÂ ül«pèúiï\O½àÍ6ñÌA`Ý •ß`P‡b3«Z#¥OŠ2oÄâ4Ÿ‚sJ@.=ÆâÔô¾`ua:Ú:§a>Šâøù+Wo!¢l¼!ʆ„@³BÚsôÔ°F£O¨»pT*HB¤\« ”áÍFh2sÛk‚X+ÐûÉIôp+¬RGCuʆär¤ws9r2¸dCÏ›û«K@b!Ȫ¤ Š&5-§vÅ&‡d;äºsÇÁ¦Åbr˜m‹€üìcªÎë }BÏœÑ"¸ëM@GÐÇ:9wÂF£rçf f0°QŽà¯25+R)É,SúB¶É¯ÎB™t6þHª¶‚ýøú$û¢Á¿”"KQ 0Vš¦Ñ2eVÂ{7 ÌÌÇTHWÖº 9k"F–s¤ ‚뉰‘k ? ´,rKüëçŒM˜¯M”c¸ÐrSúy2†¹„ÜÐ\>À™;Çà\ûŽàòËM-gˆ'Ãè‰ä|¬ú¹Oa ùp-à ,éh*P4?ë~Ai«'˜àt0AÂ*æîCgá3(}-°½äÑW±H* L›,ˆœÅEÿ¡5‚Soá‡bÀáÌ­e4}|¹ÖÐgÅ™ê<(=†TËîH¢©'€(|sô#ûÉo\FÉ$lœÚII*Sr¤Ÿ‰ÐUü³¡|úòxÉïòÕ«Å«WéÂ%.Cô5œàáeH%Ÿ©\5i’ TÓäD3€¦¬8õÉ&Â%d­FeÁ¨ZçMI£šdrȬŸ) ›aü •!lÃüŸa¿¤1¬èýÍ¡¦ ƒ¾Û“Ó”ºŠ–¢tM¥€¬9¿ññèr½ï~Qâ\^ˆ2›ñâLZÞ20‘­UÕžŸ9›’Ì%ÜQJún’JÜGÔ\­„9ôaÊõ¦¦mýˆò_Æc-Eÿ¨rIÓîtfz"²ß±G3Í–Ñ"¾›2~™~•V¾Æ)P$ŒËFPÎóSÅ*8Ýp>ªe®ÚJrÕòRàu”á7\‰ÔÕ¨Ð~lÏejñï$NÈ3!®aKˆÚR¿1P%DäòŽ!Ò,§åR ‰¾€×°Díûg;}‰t¯ÿçÑGLï{·m¿ÿçèàp·ÿëYÒ£øÿ! â?T–‰ÿbñ.þó éQ’D°çùc< l}›,>hñ»¶(¢·Õ™e ›Î­å¹Î¥ðºhÏz’A#.ÙxÑ4w„»+®±·†ðÞŠû)ªV®F£B é:ÇÎNîè]ñOúJ¦ÿcÁJN‹|rõ‹FŽ~T´"pÑo"p=éÜØ"cßgž EÈTñˆ‹{“òFTÊÆEò.öì¾ÊFt*FG)ßò3×!=„‘›$‹bTèoÉZVEeÁe £žŽÎZVEeAg£¶ÄgÏÙ#”»"°(Ë_‡U²X"Ö¾º8mv ·ö|zƒþ™vžeÚ>!A¾*¸±±ó wNõÚv¹SùnÈê«aù3Íñ¹OV åŒÈX&Eô\INø 1Zù~­_×'¦÷))FbÛCô?j_…1K?¸Þ”¼%€4acž'~£¨ Ì(ƒPNi/CbŒ‘7õRbÝB¤AŸI—­]²£‘|a' _Å3…õ€ätoÎÎg¢8ŽtiSÓrb¼øñâøD¿&Æ)¼JãÅzá°Ít ®…6ø|F¤ÀJ¹åw~)ÂÈöqTÔ<ÓLF®, ïµ‘€\àÍEôh(©#ëßZq¢ÃIl=*”$÷³8ÒN» H)ˆjùeb”©éiÚHÈ»;R‘:Ðåpò•Â`]^ö•Á1-¦¸;JBÖ?×ìlÑ4ød|fÇLEl£$Ü*–BX. }ÁÚžæM†%*€÷R±&—¹aeš(+Œê1?b¹? ד@»XÅY‹8‡ØpÎsMÄiꢅ#‰…³pˆÈâ$d]Ë„Qð|wÜÑŒP ü™Ð SÎÂGsË‘³Ì÷y@Zÿ¬Õƒ^ç]ÿC­Û|¾ìv~m5š 8ýý³&Ô;—»­÷g}8ëœ7šÝÔÚ Ìm÷»­Ó«~§ÛÓrµ¶ÌqA­ýš¿ì6{=èt¡uqyÞB`½[k÷[Íž­výüªÑj¿7@»Ó×Î[­>Vëw îtµtÞÁE³[?Ã×Úië¼ÕÿÈý½kõÛÔ×»NW«Áe­ÛoÕ¯Îk]¸¼ê^vzM a5Z½úy­uÑl±wìš¿6Û}èÕÎÏ3£ì|h7»ˆº–"œ6á¼U;=oRG<ÈF«Û¬÷i4ñS ‡è£{Ù¬·ðAkþ½‰c©u?D„Ùkþí +a!4jµ÷84}•" ˆ†,©_u›„2’¡wuÚë·úWý&¼ïtLç^³û+êªÞÀy§Çĺê5 ì¡_£Ž R ‹±îéU¯Å4kµûÍn÷Š7A瑽*ˆc ›6˜¸6 Ôé~D Ñ€ioÀ‡³&æw‰žL©‘ ‡«÷!Q ûCöcÔÚÍ÷ç­÷Ív½I¥‚ò¡Õkæ‘U-Äì=¤n?Ô°Ï+2±±’­žNXƒ ­wPküÚ"´Ued}¯¥¦ “¬~¦È]TVŽú?,,ÌÓ~²Žy(þ·ºÿ¿txXÞéÿçHäC&…|×~•¡¹t…R±R<(–µsTLŽŸi}Úkì‡%…‘eÇÅʈÔjsË^¦Ïu&ÇêgÒÑ"Yùm4a¹æ/c×Ûbì¹ó™_DküDÓê¨ÇÆ®·LuÑp9 Ø[:îÌ·üTDË% 8Ìo\[ãpŸÅ€¸M„2ªd“ëq„SzÜt¦ {þÎ@dœ4•nDp'PwnõCEê“RE}7öÌ©d^­‡Ö˜%µj„º/-¦¥;GŠúÖX)í•´!;Z¾ŠàÓ_Ò#êf4Óì)sLŸ³×ÁBOî”B/˜PÄÆ+¨ñ_.ño%‡ÚH•7ì °‚0ÐŒh˜à[Ó™-È\¡]DsÔò>Ú+£Jú}± f z„>7$ŒB s>ÿ·lPE†É&htqÈn¶Ç$°˜áÜõçˆÑv è#û$ŒÉr÷í$fǯ_“Q[œ˜þaÛE×Grû¤¨¹S13ÇéUšl'-׳¨ákM;[ö°Ð_Î’M{Lz\a¨ ápR…r±¢Qà\  о?«W«oŠÅrím"If¶œš¾$mj}Õ'.m|bkQÜ?Å™A[¹IýóŠOÌÌÁŠÒ¡¬¹ñРf87ŒóPÐÁK\Ý<”ïwDäHlUŠeøË_à-¿ìsk#ÄH0Š]õ,8êí4MäöM+ÐÜ–û¿l_ÜÛø-PcªoÀ4°5h.¹H­ Þ…‹ÕÒŸÖÌ‹uûA¬Ç±4O—©Œ=> ]5­¹ƒyÀ3*’úpæzì/–‡u‹èµÉP€¶=ŸBàMûSݵ'š´I¡…ʼn™’„í¡B$U×Rf¥Î–Z,//µždÅrñpµi×íÃäšå°få‡Çiy(Q¥ÈúŒ`ùm1ÞÄŽ?Û@ú?žîµÿ{‚-ÚO>ø¡Òö©œ½ÿ¡|ô¦´;ÿñ,駃×sß{}c9¯…sK›²$4íÂOçÉè²N üx#FæÜhYïë¿\ºwýgÜ?L[ÇÿËG¥ò.þÿ,iÿßÅÿwñÿ]üÿßÅÿWôÿ…ùE—ù:æaûÿ «ÿöwñÿgI?\¸µ¦Ç´Ý¥´XÌP'æÍ±V°œ=²0ö XL±L¿ˆ¹ZXŸ… Sœ%œýge—¶O÷®ÿLhë©ç@¶¿ÿ+»óÏ‘¶âÿJÄîq}Ü/ÿ÷Ëåìý•üžôˆûßTèÒ,ô'Ö }¡gË1´åWV¯å•6jžGÇíäæïMwsl¸—£+L´õï¹³c¥³ÙÌf‡òV¤ðÑ Ýò[t]g”_w2„œ«¾«ƒ$Ëi‹g±n»ƒ/ EPŸ{ž‡Q ô_GWý:=Çm’“úR&窗ìñšèV]ûú$oX~WØ<†lÍFˆG—Ý8þF™÷#Ì™ž˜¢SetÅ`Ž(ÜŠ{Ža]áFÍ…Edè5j/ó6·EêôaŒ~n‹ñ*jm×ÃÍä½ÕÑa×»ÊóëîcQw<œ;† ù‚ƒ§˜y5¾‰c‹ãD|ÑM¸S8>$ôϹiÓe&C ÎùŸ£/hëîÍüã.vÑ‹ÅüÊMnk3ùF­Ä/ð•m°Oß?h„—xm@O]ä^_‹7wx_¾|À.¿‚iÛH‹Á½üð˜5âg:Ë0?‘í»S±’ý{ò&dË(¼‰†ž¹Æêʳ»bæÒh¢,è¬Ë¸©ÒACžO—÷‡„¥§´ÇƒÊXß%>ÿ%ᦰ’WU/1^8»¯LcGÜË™M.èÌsø¨Ú]P )ëú‰±ë ¾Ÿì·ÕÉcûß.Ç@X¿›;´¤ yóÑ-Fü ÁÆPU¶CFÆ2ެçåmlÙ[{$Î|7LƒŽªNÂñ¬»ú¥¡®ôáãCËSG=üÉèÂŽ¹#o ¤[B2±ŒhZ¡€­i¬&Ø.À<1³M 0²>“èÛ¨d†î£x%‘‹.M½~ií¨k Cœefo~ƒùé{*׸0P ?ÕËêwzªœoO‘%n6¤›~@¦ÿÅÏÎI.§#1„ 2 ©‹T©9>8Ž 'Ž4ÈvŸÓâ J׸ä’ÈÃÜAE5 8Õ õ`Iœ¨4—¼]†&‰Þ‘vj¶DßHM,o*ø8é©c¡f ¹{º£}KþÜ{ö›«@ÎMÔåR^dJÂI-¾Lykì¸êÄÆjaÛ%É·šÿ·¹%Öd˽l»º@…EÇ¿6•wû½e5ïÆ H…F3p›ùÇô_|1é«ñÝ8™»hénÕÜ2—×R-)üÍÏ›hv&¤ir>¼Tã±FX—n'‰Æ—ílÏÜ;w'¤ö„׿^ç \Ütj.µŒx8ù‚”N’…,Hì-÷Ô%/úÞpŽó¢‹Ür†<ÚådñŽdZ>Ƀdóÿeï;£ª²@‘ÎP¤/*˜ç$ÈL¦· ¡JBQ’¼™y“ ™ÆÌ¤€ÁB¯‹²° **‚JS*Ò- ˆŠ ²ê*"*("‚ÿž{ïk“„âßûwóv%óÞmç–Sï¹ç‚Ç¢x¨wž¬¬dåVWÖ‹³`—$"Gi–6¶šÒ |Öb âµÏ\³àhÈSLE‘ƒUW[ŒÅ9PGÙ˜¢<âø«$?*ä‡Bˆ„7ÀT;½Db†¡X¹ºzØ»  ¨®ò$F©Ÿ±}°°¼JPÊèAÓ² ZÒ3<ƒ¤ù$ÕÑoÑUÇp"ÌQg”š(r•´éü’§ƒa7•_òƒNéc!ù"OG°ó? I‘¼„J|>>Ön>,Dþƒ7àJù=ß8þžJÇ_ oÀŒb 3ð_$™DpÅlâ7ÌÚ ïR²-í•XH¬9¶~§¤=¦bqø¤$ÇŠƒJ84Vbô"˜„^$I0’b¼áD‰™ÅEJ|P>=‹_7”ˆD>è‡47¥ç$r *X̔¢,Æ'tø8i©BA” Ùz¬F0“$ÑÆIÙ¨7êƒ èb·0Ž'†(90Œ àOrÍXA"Ša =¸º`HR[¥ ½\CúÙÇMÂ?IônR+†”’d[Zèçü z”û9LH ìsçÏÆaéø¸zX"B£ è˜Ó¡D(1•t¨$œÄUIm•£i‘|%CþV“‰@§¤P2@~$Ã,„œ$CêÅ÷ÅQ±ø^(v{ë 4W0…ˆâpgdAø¼ÅJ€44Ð÷¹ŒÉ¨·êL&Æ91€$ÆÎôîþØ,:½%ÿ ½HF@’К×`èô¤¢ nA¤¡êÀ–3v×iu:&s`æF…r>6á D)z50†’»Ÿ$ˆdneä˜9Kþˆ+[’ßÃiFXhŸ¢yzðy\¤ªˆÇ’‡šhAƃað¨cÖ|‡1ó\³yH_ °œ\ÆDƒ™œªöìîâ ¹}R‹þlDíÑl>‡*±<ÑáS;H’¡ŠìV1»*qŒ$³¥ŠÌIÝ Í§ hÐŒWÎ+FZ%2º Zñxfla.«Î"ðJ í sp=¥†=…%/¤ÃºÇ潌œƤ"+#®=¯EjŠc´„`#@K©ª ¤{¢Žˆõ­|Ü 1|iìhT™=;(*‰êIÆEB˜ä+TÖ;I1a¸72\*¬Êš‘׌“iEU †`ªJçõ>Uì¨åãSÂÏëy.²e«^’m°‰0züo‚lÏÆ%&'Èöxh{ÊëSbQ¬r½bMFiõ‰EÓ!ƒz‚¿eEHdpeð›V…~ñµÃo$–Üñ¼4Hìõ ÖÔP.èó9YW±P±‡0D¤6Âñpâw Ö'l¾…dùr/Ê-=ü ˆL €”ra,F#®B „ Z I)yÇð±ÒP˜óà —ta›HÜâg–låˆóÌҨɬ¤ ôëD¹çJYÝ\‚­I~ëIEw£ „jRø¢)•lÖU<Á/ËDì+`Àá«´¡xMIË—PªèîƒåJ$"F¨ ‘ç –? ¶®‚n mÉ¡d „mýPÆÕÇ‘¿0/¾?¡+U¢HºÑøÝM|N•náß‚^Ê}@“ãÞڕ ù Ýê‡Ò²ïЮ²Š2’û p– ¦ç Ñ*Äý¾^£y]¯FMBâãë¼{8 Ä¢q‡“N[¨¥‡õZÖΟ\4 JŽºˆõŠs)Î/n\L“Ž ’d¸Pú&1)GµÃÞè² ™-OHÂä6GK/)±›4ž}hX=¡ëj)ÝÅ–:â ƒ‰ù ¡ñú„ºKIu9Jz®žVÏ×-™uLÝü>>"?¶j¯Pµd«AŒ;‡¤ze =Õ,ÝöÃy4Yxtc› Í›¤0:4Ô¡°Œ”HWÒN(a•±¹‡÷{Ç´ Ô˜£ ñë7÷ ®n%ø4ì­†Jéã;Rvä乃@!P$g:ªëž¤q’œÓ=qÅAHI}úǤÕj!€#ìaâs ĨÎdžöŠHÜŘøŠ˜’Dq"DœGbW—…?,"çtùV’P+•uWša¼Á^˜À%`_Zþ7¢®h„0$ ñbÜ’ä‡Fð©}lÕE <˜C<µÐ ”m‚ÜÔ&|Ê ìx(3q\D HL^V>bIâRÇwÉöƒ9ÙK{Sn`¨,œ+GáÓ+hµ‘*…³"¨m|Ð$¯@έ­¶’øA±x,pД¢–°·r3³j½z hbX ­R¡àã Q(ù©¢Åµ?¹4Dzu‚èºãí£¥ååÍWS!½nEïUÆ8Y"ƒ%aA˜“¾x-Ïù øBvÿа›V¤ž3XÀŠúù¸Ÿ•=³¨MWàš‘J²'weü¼ÁŽzòÛ%Jxáï=r“0§WJ¾JW&‘GŒ—H ÙÂYrºÀ…ÆÕU• †½…Þ€„ŒÑR¨Á*óラ•r }€2NCRæå&é>]îö&ËDb]¢ª**Pr¥OÕžv²b±æ4iZU–iº õ9‰H×ü…HTú’Ï{IÀÍy ä'¦•ÀFl¼RäÑ=…Ë“pPOÙÄ*=a.Rt­[RDƒc¬µôúey]F\€°ôh9ùÞ *fª1|ýH™ïÚÉí<…t«V÷®âªÁ¥ñÀãQ”ʹò<|$3E‘Å%÷—‹ñ–K%éÕtDîB‡/*è£NÛ[ZÀÕŒYWÝm1rO»*JëuPû” Ä€ùŠq¾K…º®a2Æ'/UÔ¯ý8â RIT­^­¬6Ê0ª®rœa„ºEÂp>¾Ÿ ¥‘™4©\™7-”ÄÆU“I9y ÁÕtüu[I~íªò“ò“€Ëc=\? ÂK¹ü%mšCÈí:$£DdÍ+ò já¯Ú°‰yqš3ôABäÊ!Ñט ‘Ë„p% Cä ö´àËñÀ”^p•frF)Ñk<!ÌkKnêñ@UÛ^EB%½)O„êúvnAv"ÍŠêHåvý¢[ÄbªP”/‰µe7q[¬vý3 ¾òÛkB^Ù1õÆKÆ:­¦VR%Ëá:uÅ:¹¦âN^³à!íäÓiL`rñÀˆñŸ1º1ƒñQ6¹Œ¢ÆVÀ—ÃÍ^’M†òàé(“/$aoâ´«1+K¸Üh_éÁL'„{QygˉJ¡9*j„®¿„%u+¿¹Bך29–w^Êç}6åÌŽqñ¾2¢›š…ªjŒ18R FÛ™rØ<úGšÊR›µük>„LKEÿÀíS`:v­»VáAEó”“x²ÊÄý÷ÔTØ +N©ÄåöFáWã`„‰‰Ð)¢b©Ê’à˜ÝÅÝm¨&ññãMÿú“ñ@n>þ·Ag´ÔœÿºOMüšø5ñ?jâÔÄÿ¨‰ÿq]þŸÕ+­ç€›v=þo®ÿœQkøÿ­xR™A¥ˆ™{¹2$`CÔá ë¶lŇàð—ÈE!<²4Êq˜+„à¦<Ãå, æÆ0E51½1’¸ØD÷` Yðt‡KÚJ½Á’ˆ,ú5âœÏ£`%Ä; N ˆR÷ù[Õ`÷¯Ãds„uÂ6=aŽNÄvÊPÞT¤ß“xÎ=Ûû@‰Îމ0e»$@aâb "34ȉC¡W3ý8{ÜbhÐø þL#nÓ `êð… #õÞ­0¨™ÞöŠ¥¸]Á0¤Pì—EˆæF:;ÒhûƱSQæ`„Sà‰ð‘øÖhÃAØQ+"cŠ`g‹ôë(¶ëáÓ> bã8 qCw má»kƒAÔwž©’–0àZ†$µÁƒ‹„Ôã#n+è––<°þEÅ Ñw6žTEgfH˜u3~°ë`#–C!v–F´¤ñMF¸„³ÛQz:\ ‰¡…ÂD†Õo ˜?‚À=én’G±ç»œØ¡)õMÇýt ]»’ÁÆ;sØ‚ÛLøÜ!nC¥Ü,Ø2 qÄ£1BvOǃôŒ)ÙF@³ Óuš¤¤SeÞb¯¤SÄáè[r6Ý ’GΈ@£Ã¹DìŒæ°5‹ xKŠQ–âìx!Ù'€Ü^¦L¦  }HÏ D°ø»µ^Ÿ7:F mðAíI,zz5g$H–N' $»ˆµPŽ °%!b`aך.. )ÐՆח3ˆÖ&êMʤ¹ÝHDg!¼§Ä‡}J€É%k $¿07ºÍ9šA!rV!Eˆ§†90ÒùÃa¤q'1d?€w¥!2¹LÄÁnÕˆ‘0ëØÖÞ-•ö÷ D“”Údrm"Xν…%aN©~ %r o‚Š+G¤P#Ï£F9%¨Äˆó‹X·;è*¦%Ô h]…‡VÍd&–‚ "\Ä 6æ9%a¸á(d¥ QOÀ©"¦q‡¢QwÎU”åÇP)òÆ¡+ *bØ¡pC?vá‹Ä3ƒŒ/(D$>Àÿcqœ/ˆ®xÑ$"nNêå½bð¾?v#e2™2´Rµ I+ü˜ÇÖd¸fLÛ„…ÒÆµ þd¾ÎÊÂúŠ *z¡…:™¿Ð5Ñ›°Ü‹yï¦0ß ÷zD²óÓ«ÑðcE6-S5!„åOGJ}Ý~|;…´HrLJ ê9´¯dmrò8Éh A }£7bœ#7Èx@6Öâ½,å!> wÃ$+Ñ7âF5IË!Yߪ‚wpù»Y$€­Q †4‘° UªR«¼Âh ŸÉ MÁbäXY!S‚“ΤEÄÂAØ/D««Ä‰4‚ä$mR‚JR±Z]©Ê¢1!$a^§Vô*«VSUµý%Žsx@#® FÁ!$@ÁÑÀXaô]ë£x&$$~hñÑ`j¡ˆúCüˆ¸Éè òšW6ßÓ£7"\ÔŽ‰6!aŒ²Œs¢å¡DºA‘i#% ˆF\!|}3¢µ¨6@sŠ£¼·RÅx¾K:ž Y´šžè‡"¨(d¦ß¡IⓇÌx^Ä­b¡0¢ª£1B ™Qª†Vƒï+æósŒƒŠ†:ÆÿPg“ .æ@c]‚¤~ ˆ¢QØÏhÂ<˜äÅÓCFKÛçÜšPq!Ïùž ¡ü5˜$vÖyMP|&ˆŽ—7·´H,ê–Ã(›ÎÊˉdçåx3ór‚ƒò¥)“©æ‹‹XRÊGß“®…ë 8¯8§’¬²‰VàÑp0äÞ”ÎEE£Â"â­˜’ _adÈÀ+ä£ì —^Ó‘WŠˆYU/"̈”Z%ïeã¹ñWfDAÂH›”œ$RJZd™%]•}W“UKôàotsÛèvFRü™¡Hë!6JèÃ;j‹"I±Mñp‘ ¤ ‹ÁB!ò­R‚éKIÀ[;Iš GƒÏG¢,E4–""Œd a’;ˆ „̨IcQØqM |ȨÊjÀÕ‹¸*èQØÆ/hq⠞Ȼ," ÊhÏ "×Úaz­‚sE¬Ó7Ÿ4* †Ñ;ñ†>ºÏà yÀHK˜:¢¤ä¢¨ß'ÁNôFZÊöú½>6ìÃ7ûòNõÁH5ã¥EÔ'"hÍ%nh(np²°-Ü®Fñ"C‰d+l£§°è‹Xì_ËË/Tä†ÝB7ç㢰C-J‡ŒÊ%cÞDigõä\ ®x±Ãíƒp'ötUQk¢Ó.êæILb SíhO*Aº{%QÈ‘\„z’L­.D|ˆ$K„F$0V[œQú‹A¦Ó„˜ëT” }Vb‘-$d‚7÷ñŽƒvÄ5ÐÑoÁ†‰„h.}ô’Ä^;ØÔÖÒj 9¡xa4n‰„¤‘TÛ„È*“´¨máØ??|¸×ÉŠFÂ(QÀYö—^»M!'êušìðÔe˜?Ü }WòS)‚p_¾” èŒ!¾eY‹‘ð/ÄѨ¸0y\j5]˜"Dø«à£Ìk• ªNã¢.wleUñ!œP‰ÅȾ‰›``~‘&Mu OH%Àè©@?€ñ Æu§…$^¡  ˆbSk.ªTõ58¡[jemâº($N î<ÑaøU‹oY%+—¹ÑÁšé “:"Žëap®ÜÙN)¬É¢ V°âÁ”ÏB"‰œà,샮ÀQ†(Gæ-mÚ›ÕÔÕ7‰(öþƒ¥æþ‡[òÄ3éxŽ A+!ö3¸»*¡"Y­‰IA‚b$&¹ZU‘·"¨N [+Q„”œà)J¬ñL®¶È›@ÿjœÁ`”¼¥¿éŸ\­ËïÆ•uÖIà 0ý£ Y}`à§ ]p±T­Ãøa{trL?D- ³ˆzqHUûbð®ðñ²›7]Œ@€)¹Z”Š~'(T#Q·sµHBÏç}’ÈHà„òÉÊ[!Þ1hprµñ$=«MO*ªŠ”$5 Q)ä«pŽ Ó\Ù=ø‚Ð/…œl1™žÖþÀ‘XøæFÑÜ¥‘‚µårAB¤,D ‘¶ý0ª³(wœä“¾h¼ni'“P àñ ô gv~v÷H÷FÁ%Š KÇC‹„‡84&ÇÌ`8†ÉaªÑ:RCŠJüÎH®Öí¤µbkŠr('8IÝD9AkÏ,¬O’ˆ:ñ¡åU`ó¬’Ö;%ÆSÈsF&çáäŠ\-ªº€ê :GU°\9W VøÐÿYZÑ‚9¤ùY¯/A¡¡n.ˆ=–„rrno¡7 öz\‡T ÿ|$ ¸<å6‹G )ö°ê o7ÂÇóH]}·cTÚ’ð»:»{Éü^ç}ƒ>|qê*í±½/¨ò'öOi“eÚT¼(gøöè¹Ó÷[TÓ'mž89cFß M ?6/ÉødûSÖùÓ´ËÞŽ‹vÙ7ç«Ö{GmÜýí•Cgv,Ù|¥Å¹óg[¬î6wç£Í–þQÏÚp|AëßBõÞÚòqÖøG¯{{×jÍóïnŒþ›lf;¥ÿV“Þ€¸3gãœ:£m« e²˜ôz»…³lFNo³²®› ÿ:£ÞCÿÍkÿç-yDú?kö~ÅN]ó‰çÆLOÖMÿÒRfH‹Ýq?´ØÝcaÆ= M‡­›z.Ðâìet`Ëg¿Ÿ?šÓwîÊ÷˜6KUYƒ¸{ò±Ïµ[Îüð³¾ÍŽLxÐô×~µáþâNmNe$ïuÍ?ôD†)ôÊ_~;Øâ^Õ›míO<å)9ôÌ{ eŸ|¸HÑmÄÖÄvÛîI;j}±÷×¢Cwå½zöÇŒg“¿½Ú¯ui«qCFìÚóåøûæ ûá½OïîÑqýöç»L:Öûó†ã~9Øjk­ é+?+»ãöŽäÿŸÏá?úÏBñ_ÏÚMv«sº<ƒËnäŒVÉb2êY#’äLf·ÛcµÚ]®›ÂÿXùÏlÕkðÿV<"þ¯šýV³ñºæS.vÝ3 YÃõµ4÷iý©Ą̊›NšSû¾Ý¿~oÙ¤³õù"OûÆ©G.m{s‘[Ó厗jwê²è“a–¦ÍÛ¿ÑìT I÷ÞŒE#Ö²rröÌvö±ÃFoZpoÖ7–ÜWU-;ôé³Ü¢¿´x½cÊœ‰»„'$¾÷æòZ[:£›£{y権ÛÛœ™Ûöñvþ…W†tJ©¨(XóX4×µîwÍ#LÜÖxe|¢nþÕ¸ Íøåëµã.¤Û.Ü÷U æÿéçzøá¾Ù`Ô!ÍÏbe5œÝé2r‹ÙÉšÌ6·E§·Y,œÛj1p¬ÎÈr¬ÅäA ¼î&ðß\IÿCFMü‡[òHô¿¬ƒvvo½åâðþwßÙ}ië'~k‘°¸å„¸‚Çfxm¾cÿóo–¼y¤ùÏo[¬9ÒGynÝÚ§¬çKOŒ÷ɤ êvóï(§½ãç‘‹Ò—nž0öéÝ-[¾íüÃ?C3ëlj?Xy¸×‰µ­—M:u×¢»wÈJùörÙ٣럽ÜãRÝ%G¦ýò@Û;×U=7Âÿu6£Þh¢øo28Þb2è9Ë9m+ëv!2€ô—‘µÙÍz›ž³X­7ÿˆ¸T£¹ÿoÅ#âɬ5Hþo]ëbÅž§»tÍ?œ5ªE‹¥ªM•Í2_é´.³oÿ¹W·ŽŸ1ÃÚáxh¾ÿõøûßüAwbÇþŸÆ•>ÀÖ{ïØàžñû ¾ØýYAëöWÓ,ú1þž»ÞÏë}îUÿ+Ž}¶Áú-EûÓâ-ã¾Ú ÷Aý»Ô³úöÑ×*<øâÇÛ“'¶ïg¹ü]a0a¨qíªÛ;$ÿSÏ â?’Ñ)þ;õv'k3­F¤ó³V›Ýit"üw#yÀàÔ¹mv$˜œœå&ðßTÙþ«3ÖØoÉ#âÿÒÙÀÿ›O>w¹K§SÎ3êÎÒ+ :ö½/ëνíÖæM.ÝUºñh^Ò¼þá¿2µý–§úw:àkãw>Øgo‹¹¯|~…QÄ58ÕN±ëÐ3©&í+°ÌN\[ôãÝ'š:ž¢tÅÛŽÓR»÷´w uö\h_¥:]»Í·qЄçãž©·õù4ÝÜ¡öèNIm8T¡9õ³:¯žo²¡:·×»¿ë³apñóÌüøRö°Ž¯”ugÉ"ãú%OMjöcéÈ31¶Ÿé|¸öè¡'gz©çCo·~Ûñpüè.-§5XöM†C_8ùËýï<`(>˜¾ïØßN{ÎzñDçUû–iSo~mQpsGãñ±ÏùìÆâG?ú×™¸K‰:›úO/ËÍxpóoÎ*oÕùJò¡Eµéåîø/Ô3®‹ÿ6ƒÕ 7‘þOðßÎr&›Ëhw"¾Í!ÀæbõœÎà´²FÎc×9 vËå¾)ùß ³Æâ¿^¯«Áÿ[ñˆø?£´ó~ͪ~šÎÞÿ û.ûôÕ|ּר’‡¯}dÆGu íçL76öýéü…–û¹ïÚ³ëÖÍlÒ$©IÒÌ÷g5™5«é~gCßó¯·¹p!ÒªËß²ÎÏ1^˜Óêo-#­gnŠîb2rÔL:©ñ©®ÔZÿ3¯wÊ­u1ãÅž oïüo?7ˆÿ3Ïÿ­F³Í`ñ˜Y½ÁbÖsz·Çj4ÙX³Ó®ó¸9ÓærºL.£ñ¦ô©ý߈ù¿ÎPƒÿ·â‘êÿŃüe[þèµ Vë“|*fðé:ýgfôïcšÜü苇&ûŸõ7h‰ôÿõ?—ûôºÔçì/_<ñnIóÇÎ|â=sŸúãW·©«½¸gÍ×s=µùÛ[FÒZÙÔþó©´T[Übë’fÃï}9¢|hfnÜÒûÆ~î]?vÕ¢Ã%ßmˆŒt*'Þ»¥ÖG÷Ÿô53TdwïY÷Ó žƒ*6wçcŠw—Íï»túÈ ß¸O„ †=ö»¢·‹ï=qrþ»Ô¼6dNÆäÀCÍúN7p\\cvØÉ²_6t˶.‰kÝà‡ïú*OÄ—m¶²ûÇ£MKO7øé“¾ßR»ßE÷>Cß×›ì\²aåëÄV©¯-ݶgo«7¿Š¨ö-H)w¸ÉžÄéÚïi3óÂS—Ù‰û¾wÁ‚ËO7nØ.aYû~WÛíjѳ]Rã¨ùȰ忤9œ½´ÿ²ÁCZ÷ôÑÊ?žöoL¹ëôô‚#ÅK'no2ŶðŽ~Któö¥_~¹NÜò'Rÿ£¬7ŠÿFžÿ;YVoq[YÖf2¸m6ÎftZ\Öj1#¹ßfD¢¿ÙÅÚô7¥ÿ[M1øo†°5ø  þÏNk<¾{ë‰Hþ?¡~ï§¥]þ>1³Å¢Í ZtÈ-Û×ëØ¼Ï{þ~QÓw~`¿·`ÛÅÉot°7ÐŽxaÓ_Ö±cYA¯:³ÜºG‹êl8t¥W».ëGùÛÐ&<ø×s§§þºÝq4ôè¨)íÎܰø¾c=k­~ßóÄ_-Ê}ü:/å׃ëÞ_sj~}§¸a¥¿<_ç¿P¿Ïá¿Þd°Qüg­¬Îf2›í“ÞÃYF£Åh2¬.³So²Ù<.¤ Xu6ÛÍà¿Y‹ÿ&CÍþß-y$úÿû)wŽ×µ®wrë[_PÔ[>­ÉÞv=òžé0s´Ê¿ÞÚ½ø·©¿ž׳wâÑmÆgNŸxéù6'C%][~?xçÏ Þýæñ®û6ÿ\®?øP焟2°ÜCóÍ9«—/\û[ÝNG›½0qþ}Áõó<Í·uY8ßšŸÕêù…O¶¤—½Ã†O‹»:§}ºéXÍ‹ç/~Pš±â×W¸é‹Ï–d¼ôè3O6Øßô€â×Û;DÿÕÏ â¿Ádì6·ÞdÕÜ'k´éM&“Áns›,»Ýhsê¬.—Çâ±»oÿ-úJøo®‰ÿzk ÿ²ß {ô­']¼Ú¦wÃFµwgÖOè®hñï‰å˹ Í¿1ºöÏL}=õÙÅÿãÄ™Á‡J÷ìêòÜ™3‘®ùÝ4û©Vn®=.³í*ÅŽOkïÝ™½jñ¥´Ü\÷è;ó>I›ž4}Ÿ7ûÒ³s·¼‘;&{îÁ‡–­ûnùži–g øàõÃ>˾êÝÛwçô•Ú{¾ì²2eÅ‹£Û>üêùO–mi×9§ùÛ¡Âsó˜ðéÌÞ_çÿµîøƒV÷£¼ïÇ ã+¿¨?hÍ'¿Õ¾ôÊzWÞ¦îüë¢%å{“—nÿL“síþøò©ãÆm7çsQop¦b÷ÅùÍ—=Ù/ûðð;¯^­x½]‡§Bë3ï™¶ë∷üößl;F—vnvÇç_/˜=ø-ßlI¼'¸Ñ˜ù²¹—éHÛºmÁÇ¿Î{Þ‚GJBO%=˜ÕaÓofºÕ<ï¦1'ëò¯2Ó›KëOèð]zÊŠKÉ‹Vï 6±ìÑfe»ëõ'í?n+>üÊ/o5ð¿¶eM×¹¿w¾Z«pñ¸½_×¾}ó#ø¯³ëÍz»†s8»Æjò°œ›5y\6“¸¿•59§™õX-.³Noq¹uf»þfìÿK,þ[ Æùÿ–<"þûgom6^WkbÙ¢/2º«5î˜ÙÎõÌ‘ÏmsÛNª¥ñžº2ô‰´Óc»½qîÕÞ‰©sûé`Ý¿Y×1x`Ô„Ç?ÑŒâ¦Ìé÷¯”%SÛ¸þCÍÆMÿZÈ $lõ÷>oõ¹Üûâ¨V/¼ùì¹Þs_2Íj¹pÍÎ:äÅQÝÓ/h:³ýþ3¯ÞŒV‰¿þЙ¢™4¬å÷3¿x¼ |ê+ûįW^u¿ü—no$~òþ‡ëÎßÞ¡ú¯|nÿ-ƒÁ.øÿèô:‰åðoæŒF«]ï4"¦o0Z &NçbívƒÉhvÝ”üoª¤ÿkôÿ[óHìÿÍFG‡ë>42~lüçÛýgΜ™4«©³Í&ߦÅÏö4ný^ÖŒéÆÇ™æÝ Ý}Öõ{dÑØiéYdfŒz2=s0ç¹9=s[úÏÈéŽF…½™Î¬ßõÜóØþÉ—Ÿ0\¿~§îgKGr×çÖšâÜþcbžÿÿô¹Qü7þ3kBøl3ÚY½ÙcrY »¡°•µ ä5!MAgA ÀMà¿ÞjÅ}Íþÿ­yªÙÿ;|º ðXxÚ»c—-1"£~ý¶õÛfx222þžQ⮥cŽ*ÆþöÎ&ªuÛ㊂H+½ˆв÷ìÙ{öPQº€4):UPštT•A¤QPšˆC¥éE REª(‹'Ç{¼žwïƒä“ûøg’™É$“ìÉü¾õÿÖZßÚ_òh!ª÷ÏV󜫦©Òð,*¦ù®©›<=oß¼ †!6xù{WA¹GÁà_{å+ú¦Åò|çŸ@„@0DƒÉ$*DÆ’qD”„(¥Â ƒ¢KáB~ŒÿØ?êÿ˜•þßeÑýþjåÀ·üÿ¦2Ñ£9X>ºÄ;Ã!S«îŠNŠgj «6{¸½f=—ÖP7ÝU÷xèqíFom•uqvé6þo›?hï¹Z~0QÕ`Ýîï÷§§VCÌU ⎔&*mV~uQÕä2bé‘miÏ}ÕH ¡GoÁµ#Ö1 \m³Ü¯~7½3èöÉ¡d|ëMýÄ®ušȽæÁŽt~ÝJ0X¬ÛÇvu3s¦\¯{gxÂÁËS»ÒûoÅÙU žã<¿öÔøÞn²ña•5ÁL» óx>Ÿ»×i1æÜħ¢3›ÍòLf."‰”1¾ŒìõR*nWÍ¢š–²©n çBC¾º*”¿;v˜Ó¾a—ü౞1Éd?«ÖW,´'TP­zíNæj-ç+cNN?NгKÐgr½d­à.l0xÌ™pwm]_¢ô†:³˜ôߌ;{FÎó”ËUþ›ºñŽºÊ’ALìvfk†ªèý­öǹŽwyìúú4ß.¡]ˆwg›õ—9’ê¾@î 髪x®žq‘žžÎ=T>£œNu«O‹ñËÄîÙN2²¾ba2Aÿh™s2oþ¦;ù²‹G[ó‰¸Z-!Ìð{îZËz|]¤©™[=É 1ò"iÝdªÀ˾XÍ–¼š6-‹ºŸ“<˜ç,ÙÏg ç}[îªû&ww~TdÕâPÍȬٛôÒþbõ¹ƒ~ÌH S=œädÚåSÏa#iž'>°±Ð‹ôÜÕ§Ê1“LªÓ‹?ü–)l'©uÞ[¶ætg¼"ÂùéÎóãÂÙSFŒ¿öϸ¢e×âÖ,}¯ÿ0D<‚Ca€0 %Q2(<‚I(‚Ãà±Td ó@ÿÝÿ­Ìÿ\ý°þXÛ¾<Ìõuä8H*œiö: ;ÄB’CUÔÜd¢Qå­n~{fK‡Ó¤•-¿ÎÔ§Y[ù¨vÙì/.¬“û´¯wà©ÓÀ±‹Q•à#Ôl£ÊÚ a–¼‹­ëü0=QÆÐâxЍ$÷©Ó8)Çn‡sœa¸É;ˆÍ>)£\6åÈåYmcõ|‰í²£Ñ NÙªÓvWQÖÈ\E¾ê‡Õ^ ‡‘OC®­^RÆžsF&-9íãîú‚ÃËò¨—?ÊPÒh“[ïgnצ ÙØx<ãÜø0C#ÂÉÊr¥±ÅÈZ“2ðûQ™c¿3æ>ig°¼:gQÑøE>•U·©«…¡´yƒï õ@‡FÀAeíÕƒ§·$UH4Š–Vé忝1óÛJºV«VÖ¯öIøÞÈ~õìºd‚)-Ú['îŠ[÷†Î›q¨jÛ+²ôC¶¬9ñôýž7*Z¤­ÓÍï³È®Jû†L[lB*v¶ÌÞ:ª4NÍòQ²Ôêšë"Fj¼{Œ¯³Ùò»Ùßòoø¨]Ñ ^¬çóaˆOîbÚf˜_ê@õ–qC2? öñº]žÈürŽqè¬uÛÅÈYLqû¤±µÐ¦äxÎsàäëÚ&†¡¼&†¶E¬¼™*í·îi›o”²öJé»ÿ<•ÂÃA…oÌù¤ç]’1ˆ?ïÜïô©ûºBïE`½®æÄð¡CŠ™«ÉæìOf8Îâ"Jù•¬B$øúê‹Ã¶µÃò¦Å¡E“ë‚EzŸHÚ¾•0Ô Lâ²'ãæXã|ˆa]ÿ‹Xÿ± ŠEàïý$„`±ð·-? A(€±xˆ áÉ(‰Šàˆ /‰D /)ÿÿ·õ^Éÿ-~Èÿ5=:U¦ÀÆÔ5w[ɉPàÜ«Äl™TÝà,‘P6-%[:'›ƒÄvÖr=ý )<ðÌ¿æ÷w•ÃOˆ²Ô²˜×s±Ì–áßU;\Áç§ÛÝ:Œ‹ó—ÐnAµ…2¥¹du Þ¶ô~Lòì›MOÇŸM¯ÉÀmoŦçpåª~b»w4ÚÊRž×¬™óù­ÄÕÇ_ŽWîmÒ86оz°)ïG&¨ü/ì´+ê>ŽŒ7Y½S½%èr³‘ôî‘ߤ{"û&§8â¶¶:¼¾‡)“¯¨.CRFº giòÍjØSWr?j±üÿ3ÿG&’IX" G…)8,‘@%‚0ºà↠…å€ÉÐRø_øâø‡ÿà»Rÿ[ýçó¿-‹Ïj°íÑ¨Óø_ò€ß;þk¯bºªÉ¨<â×þÿϵhþ¿×ÿ1âB€‡°x<Œà “È¢€GÅ“ˆ…B¥¢À’æb0?ñÈJþoYôÿ—ÀÓeÀ&o—9ß(c'Sœ·R¨†¨xÜŠ`ÂM× ©Í»©Œ±Íïîè¨z"Ä™$ð õt—€øIiæÇd‘ŽfÞÇS.Vœ=úîמÜȶ rQâ ¤v_SÚBOyNy´b½PJ´éº@’q” ¨=Ôæ ígmæã=ôU¯AçÕañiÔAL–«*àÜŒaɤVzÛ“`Ù¯|®ö%Ï‚†gej§ØRUJ·¸Î2Ϊ›Ù˜„¾ÓždüjôÖn%¸/Q‹äÆâþä"âA¡d \ F¨ ÀB…)˜ûOÀS ì·€K™ÿƒÿÿ‘•úß²èÿ¤D­Lëɨa]É“z„vSEB´å}É5 AeåÀúr6KgŠË3Äh¾C,ðÄÚØË7un¶ýõŸî)º&ùU><|/]­=@_×H·eUuÂæÄúm§D¶aW•Ó×ÉR×°ësõMŒTfi¸;µÊÏLlBÞ>êÒ?FM§ñåÇ ¹ì¶Hm{mq}Ï)WוëS«Ÿ1î32¯f˜’óË´¼tßRR®M'WÊ¿Í[=,Pv\Zß"mfBK›I›#5yáf»Ýè)#?Ý/ÿºn¿KÄš€âOEÎèxGÇd6¾æŠÝZ^õ¬¨ۦ$³Dès?­ýœüè”<ÁÝ |%cY79£Ê[ÍîœaX]ÙY ÷ æ,“Å? b ÜŸóa<G¥ xK!-<“°~Áöcp ’ $ ŠÅR¸´ù¿ÈÏü/Äÿ•ùË¢øÿ!þ¯Ù:xDé0kìvG‰„KREåßný'¸`ú2›RÌ«.ø|˜ýìuK}ï‹j>?CI[õcC}Õ`ŒFcG”_Ý'³Â xW.ú‹ó‡'䨷ï«^×+5„m}kuÉ"ÍZìZdŠÍ!m‘˜X0E‘9‚«-BI™%WŽÈâ-¥Þ¾-7¨0¿Î®3!‡kZÅê§~¥ý6mèLŒ-ôóóõ¾öéwöз¾é¦¡9,EkÞðhÏFï<“2‡ Ê0µÜç4߯äko²¥Ú½xë uÿ.ã51q+öàg-–ó'ÿ…` L&‡GX&¨T ˆ[x‹"$ PÁ%ùìÏüCðJþoYôÿYÌÿàº<:³»¿UñŒ‰á%® f§Qn3ÇæŽÍ†A>_ÝL¸]%$’ðòágGÝ^|¦{n´õkb9*­×É ‡w¼+!›&Ü·kwT(ß¼-ÛËlÑKÑ‚ÂýÝjœƒJ^Úò3"êô¸Ø¢±ûÚþvŠ”‡»Šªü%n= nS¸™#»Aãê ß×.|CEª¬Ìã#8Ké¯3äój4±Ã·S*W…× gcF1}Á9}–sXúxàO³µ*Í›Ù_{6 ü÷‡ìÿS-’ðŸ÷ÂSpX ‚D„@ÀâQŽJE°$ ‘Ð…°M…ððÏTâRúìþßâ?°âÿ—Eñï¡ý„å°íµ‡oÿÚ FÉxÇÖGjW·í‡·m¬æ<;—Ðeð²É•™~÷ȘןùÆ‘Ðõ{nyÞÉ«RˆºÔÚào¡|þJ—¼aß^QÞ²ánFñešþ5Z˜eŸ®~iÊ»»ò$PÖU›ô Ï»ýb¹Óñ}®ëPº?¢µÏŠKÅßž%4àÝ”ýŒpÛ˜tæ©h5î\z¥“¿öwúoÕ"ù0Ø?ù'!D<R@@!*^ø&áQ” ‚d,‹â¨d€ŒR‘¥ÄÌ¿Ääþÿ•û¿-þâßìú·ùßÛ˜~—«À9&‡'Ä^æݫՓ„–nŽŒ{«-YøDT˦JàuŸÜ„øÆ°[¥$_rܪ{̓WŠãLÉ•}bU¹C‚lÚ–÷Þ„Æ$ëEÛ|È6ÈÏ+­'x§h•çÉD¶»ì¸§Od«q`‘èª^k÷ö®3(ªlÝ‚HP‚$A%KÛÝtDr’ÔDÉtD@‚”¤€ ’s’$9Jh$ç,IÉbƒ "âe^ÍÜkÍT½§U÷9uëº~œ:Ï©Z{}ëûö^–ÔþÖ’}fðë.õDTÊßû;þëðü—ƒ ‡šÿ{ÿÀÀð ,šÁš~8 ŒC"pXMÀáðX „†`‘èéÿ–â?Lø+ÿ÷§àÿýT«U–IÉóN»8{[*eŽ0ŸŽ íITغ«tHýÓ ^ù})­3”.5\ýªKááïl‘wäÏ_E›¿F×29fq98÷®NØ ä3¡%¸è‡ !eÃèd\̵Ýð«œ%ïäíŽ(7ÔÉìÈêm|ýð5¢®óâÂhOlž·eß-—–¾^Gv‰ÊCqZ[NC»X]ÏgNJ1®Íº8àüjƒœ—7½Çì ˆÏà0Baþ“C7¯laÛ@4èŽy—K cƒC0jy'ˆKhæTQ¥´Hk£¹ZìÂXœš /o4Ø,¿1ú)D4¿åæÄÙŠÐ@SÃyñ^Vew[Ûûâ'{¨KE)…²åß[dÇ*V˜–»xô¿9»a–1ÿ•%FmBD#‚*yöì^XYü|8§ÿ®éø^þÿóüs(ï8ˆ†B‹úFcàP$„â Á±` <ÿCóÿ¿è?ü×üÿçàß6ÿ»O¯ÙÇ ñ=ó€=7XÙŒlËT÷÷~þ=¾“ÿ0èü?Ôv8° ÃHH4 % ÑX„I`18ô‡êøÏúýâÿOÁ·üï-ÖqÒÒPïC —ö‰©þ ù541¬…ĿпY™“ËiE”LN׆ â n+gk¡^GqEMe{½Ü/­Äï·hL¿äd?†H›âÖ‡šYŒÜn)äë‚C˜{(4·¤¤ÒŒ,?OùBůþ¿ßÉ0ðý¿ÐaqŽƒàñP$wÈw  ÇÁap( F‚…þÐþ?Tâ/þúkÿÏOÁ7ç?túµZd9ê>Š2¨ùöTUñúð1S]è vD®»½r¨uI™*‘ Ûˆ£Á×Ó}ðOéì6´#£•ÃlIÃVúê¨ÕÂQS4ÎU@k7´’꺡 P:_œ ¶©ÈØ­™¥dqÅ€¹GUo ¨U˜¾s’Ý[$œZ7Ó/’\HI#9…j3¼–¸‹7¾Ÿ¼—ý’D^¥ ââ_Ú)J6rX®xKÅMbô,Ù8,r—”k1£y“à³¾úÙéH5ƒÔØ$ø¶Õä »Þ k‰ÄmûʹârHÔ¾ÓÙÛ-Õ4A¯Ì?„›~Œ^LÜ^ìRŒ“Ot3·¶7}¾Ó»Õø,}ïÔ—Ç(Çgw-5¥N§ ÖÅuÿs+üÿßÁÿC->¤ë÷ÿÊ;Œ€  Câ!x ìpÀá8‚@cqPÜÔÿ¿]/ðgýýªÿ¾ñÿ†öŽÙ¦ƒ2O–XY…ªuƒ"û'ŽÃSeb•m*«¯ÇdøÝ‡˜LÝi$qcÖ5²%{aîN¶tŒ9¯³À®ª_:c¡<)–[ÕÔF Y@en¡@^ñ\·zI"^‘)ÓF§.ãÇŸ“H×$ë-úr‡Ü?¬Ž Ž}=É} hT'ÌǰxüM…>¼e ¥âd¹VŽ“[K'¤›¥‡©ÕxržÎéÎÖ  {7Gô¯˜€ï®_&‘Ívó\øÐíŠ÷¨ÌLÒ ž-€Ô%È‹%ŽéÎßúÛ¯»À”÷íž‘Ž—m1¶¨”¥x^Ö‚ ‘A¥®ÂØ·hŠSÖŒ­©éH_ׯý\4N_kÈ嘚uœÌµÈ ~bMžùÔ%Vñ§¢yTÍ|ÛD&˜9kÁ‹]gX§F^?O%D+=/€‚ùR¨ÌZäý:ÞŸ|óáivƒÅ‡Œ >£P&/s 2=ÖRÅÁÁÕN3›bœW”VºäëéJU2Æ5…º(§cd֨߷:«{rÙí¦S_4ŠïÙÄDèù>÷-*‚¼³¨º!óÙwÈìúÖÐò[Ã"Åb Å ô0Žk.umÊ,L­_¯ÊÇXP›2-„k÷ÙкeßLu ¼E€»Ægœ°£ÉÊ— X÷è`8:“I&ù$eAž¾ªÇÆXQ·¶ûjU:ïn#»„å*M߯‡\ïâ·cN |™—ØÊMðg…ÉÇ4“ý]A;EhîÉK½0øMAŠÀ̃èdÂ=e¬Bi¨UL< ¬ê¶”ª.Ù:ÿ¥i —WÉt鯫 ¾• ËTʨÉîÜÑ XÕnë ɯú˜j7ôÓ3ƒµ*ò"[>§6±Œ"ìbõÓÝ/¨…gúÜW‹m޾g³‰{TŸ×3»\XJÑKi<ÃÓàÐJ#+ÛHqP~²öÔîÇm·Ôsp¼Ò‰ú{Ò©³s} ˜@sß"ÆK] ªA匊Īƒmå#M@2÷ásTó7zih»µ°ˆ™ÏN”&=Ôû¤/¤À(OʹÚË'O«xçkÈóà{½ø2¦ÝìjØgf„•“}æÇŽÂbÎŽKéܱI¶3ss7ŸlIIÛ - (ßò?Úè˜_ĺs;w¼uIѬÔɤyýIØCŒ8äu„a€ô9äKÎÚvX$=ÀÔo¾RáÝ¿§<¥öBø…ôå„VäÛ@ªêj@%?Ë,ðþä ƒêIæ@•ÑóÊ·iôw¼_¯ì8ãƒ.uµoõì Ž9ù»†¬ú'7g[ƒ7ÐF j]T8¥‡<ØZË-#cˆz5^PتšëÝÂk¾^I—]˜†3VÕ­n8D;ŽI®‰Lhk{6>Þv/@ùßIâ|ý"-‘õõqCD6¨8\\¿dvØùÀù€:…:·Éð÷®j¿ð½ø^ý‡×8!‚àà@,> F ƒ PÄA@ÿ#ù`èŸûÿPø¯ü¿Ÿƒoý¿†JU½ÿò€°°º8ÀP¸ÛHUM\µÿ29->—͙Ȇ»µ” ö2‡ÂØcüÓã 18 éÑý‰ø¯0У„ÀEÁ£å´ÏÍþj¥·ý{¡æ «_DBH‰£PÎZÑîVE{ÔCÙ#ÖÖ–&›[ÎȘ­棌jæÖÃêö,PùË…)~Ùþÿ/üßüÁËÿúgþ‚p¸`°` ÆÀÀðCï/D#àP ”€…á`ƒþÀü›ÿ ÿŸýÿð_óÿŸ‚oü¿‰½ã«.æƒËò‹‘ÎQ¸h¼ÃpÝKbMB‚š‚eF©4§D Ð+P²²Sý1É8$/Ä\Ö<»&<¿V'³ÕW,cÙ¸«¶ÛÚôTØõüm˜éf÷#ÿmw™ Û7 ’¼„çÐÞ[k§¦ìÌœ§ÿbŒØÓ¼¥]ÿŒÝ’VÏðÉ¸í®–Ã¢h„Q«‘`/.ý^Ì•üÞÕ—5—Þ?kd .Ž­9p:È %»Ãòi(ŒÒK?‰h5`WÄœ¢è:Üö ,ûº¬ŸÅ¹à|Cõ.¢–k%s󵫂½\üÎü½ÄRucÅ3½/ßW5®ÚÌßû ½žût¿@‰¾[}nR7Öõâq·¥¸¼‘áC:¹R µ+Ɇ#†»ŠñÁÕ#ôz!ò&¡7ý¡§®‰$¸ænöì ´{<œcÕzÂ{e2õøýƒÊéaþ±O ë íN‰åžÑ9_ÚÙ“X *Ò9 wê 3§¼Kf¤£ºÞÊÇ r'¥ImŽ3ìøï–æ¤Q¢ÙæÛtÛÄîFl.(œiÏ8YT(šžš.š·Ã”)Õ;ôL*líÌ…xî«Úó¹ºÚ/?Õ7gAöSQ论©rÅ£74NÄ|œ±ÜKä%d¾¸ xÌ©§T š³îåœïz¼£Ô¹\?N¤º„“/½¢‚h:"oX4Ò“ 0"­¤{_{j)poÓ½LïµòÐ5/e?‹î¬ÂË•Kٺ㒱JiCI@×ç%¬å¾¥Û*É’­Q´Û˜YîªQ”yKãm]è{5Ž£# ºÆâ£$ =}3*ÙÇS”Ÿ|O3‹ÞŽ÷ `¿00méd³·‰’Zº,ï™<±D©ù0-{Oøë»®­ùåÒC¡ž²›xîÎRóŒ{*9iùײ£øðÄ%-+JðFm¿SdÀIŠ™ÎU±¨(¶äI¬¿¸YNˆbÿêB´Ö(2¶ ÷P³šcPŽqëQ†å>ç ¾4Ë÷ü!äù£¤HÒ-ù :C»ÄGƒ²"- Šâç†?œ ™SÿZºGÍ\”>v„1¶Õ#À™PÝ&Büê«!RÚ?‚ò9˜è¹øe×l¼f”ŠXüL-/š¼½è‚¡ìŠ<€õSòçåjª£gÙ»þûJnüšq5Ó7¹5UO=µgÿúÚÔº)Ž^cIÜ\Ïb¾ôE-Þ¬0@Í•þô’$¬àIkËèUIÙϲˆ5 )O!ÓøœÎ§k‚/ï2®ÊÀ€Ê&,¥¼›ÝÃ8AsGÁ©MáP;&;÷4º„ŒYG·.Éd¹å×Ûo~p$Ó|’ð¸Æ»¿±2 ô˜hª²˜¹˜drךco¶bÊ@uªÛ¿Ji»CñÈ,ä„)J[9Enç¬zŠ QS ‡—yÕ¶ iÞäemo[a–S-¢ãöÒut¤pQ‚»“ç1Q*¥,唎»£˜Ì7¶¨¼§Ô!Üü­M¾b2®4>Zê¿—Ç4ÓœÙÙ}ßt‹-< D¤üHì5œ¶5}¸§õtã ·Ì©vÕ‚r¥þäñݲz%›Šêý1¥´Îù+ræ®:Ý•Îc.¼y®Ym¶ =¡m>ypƬÀ×ĺçM–i×Áê ÈÏW‹Þ‹¹qktøÒq‰hä´-è‡æè’Ñ|0á’R;^MBÑ¥‰‘Þì'+4tŠgÒOuêì&+ä¼B‹ &–Ïg«ðDÐ-ºjž:ó=;zWƒ;Pºí¨»ÏA)kïC¨QñMd‡Kw UKÑËÎVÏ2ÔÊŠ­Ž§?B1Iâ§»¹\ÓåS0kð'PïÏ{Êß%ù“ÍÅP´RKIð Íøƒs_Dœ/@KžÈl¨éÖôj=Ÿï6}…*hú¾‡(„ÔЛÙi nÎÀ;ÐU/Ǧ__©´ETTÉséNva^Õe €£é•G¬¼X[Ø“YŽ¿ç,ÚMç_?h¢™c¶^P¹d>GaÚ4ÛÑ€e¡ˆÞ¿ç*P%ûz–ææ/ÞlçO½QB÷ÁÌòä+/ã{¦áw{Ÿ9Ég³Çh“/~N’_ÿžïv\­ÔØò¤].4Y3 lÃNeÛpâ~yx\‘"ð9‹nAÖ—!ž *:“m´¯9É7€¼ÁÒßÜ{ŠFx§žâ¼¶ç|B0ª–'SD@´œÁ££9•éBÔlñÄÿ[7Zªœz"·Ø›˜8Ãì¶J«#µ‘/qE{$¢DzÕÒ©\2Aq……Ë ©6¤IÞ,gÂhšIÅ:–†{!Z¬¥„­t0ý¹k#MI÷AíùYé“‚qôÜ.Æ(þaÿåè§4§i͇ 3ÆÀGЏ•_´¡«×x±IÙuÔ¬¢ÛOšÿÁÞyE¹.ûÉArFDrÉPA@rN"N”œ£ É dA”$$çŒHP@‚dÉ rñœ³÷Zgí[÷ê¹·ÜU{ûûç›ùfjªæ«zºûí÷ín8ÑSztŒJWÆgÜA)“û‚f+}ò¸¹ç{{[•H ÿ-ÂßKïü!FkååÞ  €ý¬Á¹æky[)~·¹Á@R!û"\ÔzÀË–¹!)©m>Ÿ’ZØæe?k×]~JOëE¹n“ÿ‘»\ÑOPøèå•䊨+vÎK[ǘKiÔ½=Wýé3ÍÖ½îY·»9’nò&T_èÌVK;/L{¯*éƒ9CÝ nÖ\CÄo³îª 9×'½ÙÉô1ý²¨m¸ }ÿ:ý ›ööÉêG²9Ï?·Ù%¿©V]Ù?é¢"rÔÜÛ^]ÃçÕ+®Ý#˜#Mw¦;_Úçb†µ7È|ÒS*‡Ìëi¸LÙQ@Ý{¦å,­¼’è[±4À7áô5–ö‚º &¼®fœw]áMÑ(x4Ȥ'‚ŸË1*¬O¸ä=×䟑Ä–‡ª^÷¾sY]óY€ëˆ^.Æ÷b‡¦–' Ïj˜j^ W™ÿ"#x÷Nż—ÓÖ¢ŸÿÓØOêøÆ5ä×â• mmîgdjHÝ»x• ‹Æ¿„ùà–îVÐ×:‹u/„£ý¨yÚD•¥_šrӽ̄ù…•ù®®©«w¤êœ¥‰$æ¹?:§\Y$Ûy$ß!é€[Ö2œ¸7ÀüÄàIख़öÊófÎÔ$ÂuÆ\SŒmö,© &Eé‚ Q —CÒ–®#¯í¨žp»/¬ ÛËKYg•­Õ:ó;ݼŠâÔ_TaI,Õ1T rÍ<yïdÅs—ŠU;çYsʘÛå‡4$±Ú¹“oz˜'Hμɼ]ÒnP·¨Œp1^Dè1jç:Ò==‚ ‘o_Œª^àX8ëWó6»Rxðsfsª±Âž rlë.çZãdLˆ÷‹2­‹>¾gV:­˜Ÿº±3LÆçZ@'¸9š Ïô5^±u¨ÅF Ò¥ÃÜÆaNt„òU ²ò?ºÔ]ìÆ×\kd;ÕÎÜ=옿`ŒsêXë%Ü$°,Ÿ.¿¶²µÈf³X†”%†ÁKˆ’¯Uê^ÉòÔÐf:˜hî[Ë~DJg\„²kÔ†rÖ$û<þxG’üâ׵ܯ‰GÖ>UZÖ s3*^ã:Id•†Léå™AÙÙ¨nH Òhp–¥õ<[dvâ̲-Ó@B^f.¬CR¼îÊõø¢\²†Zúñö3Ž4a‹8ÿüÙ[n›½i»Ìíæ89wy3߃ê—)º-éo2‹7D$âèÞãã¶ÂJúÞfpkí2e„ÛÖp ºú^2ÊÃÛ_¤JVpµUÏ󘙓ö}¶±lO´°ÙáÞò[*žÖ´jïœ%¿çe“/(5òààR€œÊìæ&Ûa.Íùþg¢|SÒ½-dÐ>yö†¤#À}“oÖ:l.»•ž1|1ø¾ï†þ—~ÝåJÞãUi’³óŒ¾é‡þFÊ/åªuÉù?¯Ã}Í\ÞŠäðo8|¶­=½óáU"ÓŒr_ôµQ7Ô'*ýŽÇ¨4š•ÚBœH¨D6ëj[ †^Ð#Õiº©FÛˆRÚ×¹–ž®˜9fíÙÆ79œ´nÔƒëO '‘!üñ¥£!6"¾„Kµ}ÏÇŽÙÏNbÝfг”(à@{SÉû `ªƒY蟻$ý­_¨ÍÿŸÿÁC(„†àáÇBÐP …€à0†â‘øŸëÿùKþü®ÿþ%úsþ·P襄ˆ6¹²ø¥Á-õµï©à×Ný}꽪گ•¾Ÿ |óÃgÂÎöE„Ÿ£þSC(Þ?B[2h&¸a³LH y5‰0õŸû÷ÿíõ#ü`PÀßû?‚¡0 ‡@` ŒÃ‚8Å!¡Àé}8 AÀP Ÿªÿ†ƒþšÿ…À÷ÿý%úƒ} uͺ†-QÓà²j*ÈsÞ ò˜P2L²ž4Û*ª®®,o4~¸n2t×þÒÖÒ½ÞÞ®‰ªƒŒñ¸©‡ßòlH=v½×ï¨ÁÂÒ&8Í¡%»’ËÞe‘*PµÙ'b:uïšæ=*eÛv¥½<ÖÚùìˆÊŶÃ,ùØ»Ÿ€n•»ßm‡|¹i joÜà?>¨‚;››"MÉwæM·d]G»ä­ ƶZôUº¸â%Kx ì’–ö>ë¢D7­Ë›MFÉ·%¾ €ý;lÛx$္ºtšW½¬½´É\†î¨Š‹S•IF uVó“zÀï ¥ÿÒñBþ6ÿ{z "Q  ÆâP(‚ÇÐ,‰ÇCá qü ÿÿ­þþŸç?óÿKô§þo-­2Lõ{¢ÔÊ:³è˜Ð›­Ýöô±%Öܶ÷TkÃ(¸×+Çí·zê“<âÞÕk[4’CGã…ââÈYô36,9¤ÅÛoºo”? ];Kõ\þž 2HsiÞè  !=²ê5”ûÂõu씹pÓ^» • 0‰ÄMæÙs^¦TF)yvE%züÙ[­ß_5ª@t\·)Êp¾m»ÞÕŸROµ¬rd&ÏÉ4~¥›n?l4Ï6‹éDQVMDî,@Ç-‡ ýÕ<_êžiЏ}S“"Yæù¼z²úõLåjÑ5µßÈÿïôƒüC@À¿÷DB`<€ÇBÑh<GÀÀXþÔF ÑÿÑ €~êü' þñ?üwýç/ÑüN8NÀèî-~²Ÿ,ezðpmiÎÝZs¨=©V}.|MÚY/‚0.úe2ŸAxÀÁÞgÂzåÜsa._õØeO)*jÓëô‰ê”‡äd©ªg=Øî¨½'ìñëN‘WX¦²‹+Ä—JS¦‚“7ê[66}i%l± ÐŠ—D,¤k+ÏÉ<=ƒ=ƒvÓ®x{•¬û­k{_¢$×k¾."6Z0¨˜kH’{ʬÙÂãŸxo‰Ž‚H×bräxH(¬K9àËÀ~È+¨ÐéTx7z¸ö ®YLy8>؇YE*ð‚æ啹³~ÀŒ›É„×|\»Ê,^="ò®IåÐò¨Œ  c«6S“ýò\+”ÅÑ{¡Y³‡FŠ€ÖÒâ˦KÇXÚ\èU¦Â¿Ï€.ÌQ<¾RUB¤fr5%Ž c‡|ѧ‘À Ò,\ÛºÈøÕdz:ˆx>U=H¾œc ° ¡­q1fíe‘¡“ú¤PL-dÉQ¤f‰>˃bç’¤Tªµ"ñã#ÓƒDÍlýþ;¯ÓAç÷*>hΕLSF¿lºàå0ÇÛô¤)3ó$ù½ÏsÓ€-N]U-VÙF‘}ô–wÄð\u‘UŸh‡äW¬´_ÙZï¼ó›o™;¤”X-?[TÞþ‰¦Ê~þõæ=ÿüA¾˜ÿâó¤KÄcÉKNW_…AU¤6Àþ2“½§ý(ÑhN—õeÁDÚ‚¨2ÿNá¡ñã ÄaË)öOâ™9>ý6žÏ+&ʸÈh'ÑÌ È–>[Ï̞˞Oýø(Hò ·o´xCT3gûƒ»ñŠeΡè-t Å‘Çæ¬òk=‰ûÂ14KT§M/?A·t®Im'ZÆ•_Íf°ñ0P€ ­×ßP³ºžG¿¨HÿÂ%x”{kmJ'OjiS,æ0š•÷¢¯¬ü“«Â›¨Wª™8ÆLV»yUuš‡a£ðÜHJ‡(çq:’üÌPÜÅU— "QS¶Šîãù—×òÿ£þ‰…Aß§<Ÿ.pX „Åc``‰Ã#q Àñ°Ÿèÿ „ž¾þküþÿÿ%úSü¯gcwÿ+2Û”a£{^†V>×UQn¡EœbÈópVõ5ƒ ÅÈ9%‰±Ýi7>œ”ë W6-o‡Ôå½É)§¯ŽÝo)#‘űX4I ÎXˆÂ Ë\ÞT87,""vk‚Áb¬æè6l*ò9Ì•]é"utïkÎ{@tèA¹¸øæQ Iç<.>Üþîµ6§»âæÊ‚¼j3qû—LS÷ßóÈ÷ê¢w‰%>G󉦸«6»ß¯¿&êA«Í¦PýíàÕßC5¢”vØéþ®xľÑ*Dò¥f‚gJÞ:gXüÄ¥Q3Ó°Õ¦|黨§=7`Q—Î ŽYìGŽì)4.«Þ| ÕH\ØÐц7áój™&°3ò„_½n¼¦Uàh*ÇÇwÏ“bÜš~õk8ó{¬ÿ‚oÝ&Br˜ˆ¢Ð:ß¼ªØ/Œ‰$޲TÊh³³©ÔcvâSåÀf¦¶çšØS@Ô³ÖyXƬ¬D¯ÙM^ 0ÆôV¿ÑÉXY œ<¹˜ë ïöN´‹nž4K¹‡îÈKaߤ±0ôª¶$+Óí¾«ñtÁ_¸Q½ì®¾“t•Ew5¡SŒÁ7¸ h—Ær½qB¸ç§¿¡ƒ{Rke¸Ô Að²’`+ù?—ñÿ“~ÀþÃ@ ò7ûÁ"Ah(‹@C0ðï­¿x >}!Ñ !¨Ÿ™ÿýßúÿ¿‚B÷ÿý5úSýoTF€éþžt;›Rè䡈’>I/_àmí7’³í¥±c$œeê¥\©ÄÎ߬t:ðúêÓñâPfÆüm§i‘E³Hn4•pжÄhÈMKí¶¸ñV/åé\ [qw«G™ÙEÆá×’—,®$áÞñ¥›&l°Wh¸Êt­«Þ×Zu½]{n:øÛ窬B?ë»Ì&€>ê^å—N«=ɽ5BŽˆˆc‘pK¼k†™×Ã7/ÈÓU’©ß~jÙ¸£¬ÝÙÈGåÓ))îÖ¶uƒ?Ÿ¸æÀ“Šâ¼PŽj²Ž³ãºÛ‰Š¸L³ºñ(xÀ{ìéY¾ '%M®/¼ŽçÕµéÖ6vlOµ>b¾G”ÈÉ/ûW­úÿC?Ä?€þ}þ+ÄB¿}GáQH4ü}ú+î4’¡‹„C~fÿøWþa§?õ›ÿ_¡?ñYJã »¿w¥£0‹xÖ2<¦[]ÃIÉdá‹ÚéVe Ñx?>Y왪R¼åo{Ãĉä¾Õ3 Ê׷ߥÝN¡®DÅ‹”J¨‹{ì ÕÉ|£Û™èTžÚ“áE›½ûõ²öX'æ}íh0cNàøÍ+±L²jùb.ØU¼ŸS`#’õ¥TG¸y֔ε0é}Xt”…ÆçíöÁë´û¢Žß1Ú™dGäGæIçĽœ‚ïíüOõcüŸ’‰€x¼8ÂÃP8ƒCÀNÉǃ ï=Á0,†ÁQ,ƒÀ~fþ3üWÿ‡ýÎÿüýÁ¿‹¾‰Ý*ìì½½bžgê"Îåô•Ì”^TôtìúÑØø^ùôY6žÝ8Lünlê¤õ˜·pÕMë{æ7CyiiPÞúú$´Ü¶£W}|e´„sŽËåóS4jLv¾`Q…–Œ·º»Ü’Eœõ¸¨Ô§,AIf¦M^>;Ô>ýMߨ¿½B,”“w|Ro4Ê{ ˜:^¿…; ž\\£æšèS_SÏ#oT ïTœdÓ"û0hÓíòÊ’8¸BnÚˆ¶3ÛͨQßr’·>x̓Øö©aÿ˜doÞ£Ò4'ää9i@ôàü”™Ò)Çd‚FE›ÊërZÞËab_ÒC\cCÎ@O—´„Ò¼*—Ç&‹×3 ©•íñ4ÀCRo‡íºfSŒVöÎÐÇ8É»sœ"vŸÔпY|Å5×>fÑpyã"Z"è¢À’²®ÝëUÖ‡Ža^O9©+_}9@zµ7¿¶š ¨\H,L³æÿpO 'ÊTùÒiéŽ×-šìÅžûÒ”w“”ó¯É©e]Ì:'-ëÙÛڮȡ X!˜iv:Úì߀äÉJ­§ïmž*uðîÞn Q­Â{^Ùf½kg>S"¯àT{Á¹離ƒQ§»Òyýúø< q•Â:uHjÿò¨>ÔÔ7ñ‚Ϙt+d¿äX<)ãôUîðk#²>ï0åV3gq¸z§7õ¡£›.±_üö£u½‡÷óÝÝôŒ¶Kú^ljÍušéy_½â¯ÔÕ«N~Œ†‰³†j…¡ðõ܇7 ?¿¹ª'sýØ ³TÌXx·žÑrU(+ÀÂx—túåÄ¢Nžø˜â™®ñýÛ*"*œPërSšT LÌóúX”Ú ªDæ“1sl—˜Ð~œRùj‰ a¨cÖ·±¤Sùý4ø;’a€ô}ë]¶DÅ~à£hhø2¥^'…YéPæúÒ˜Uñí€i’wË› §0Åzâyþ•G_F6Ô6J4Rú2‡ÙI§Â>㊧UM7[ôV»{» ÍÅÞB†4 W„)îËqæŒNp:BŽvößú?éù‡@`ÿÅ?Aa1( Àž~C€ „‚" X(ú}rˆ€ÿLÿ'ì¯üCÁÀßë¿_¢?ùÿYÕ¶ïóߘ6ãåÂYåúaZžtÂ\Û¼¼±øª¾!¼ìýI]Š@BƒX|Ëõ >­ˆú10Óൕ}Q+¿Jü«›l]Å‘(f)Õ×^ býöV»Õ7Ú£JY EóáÈs†Å\'Œê.Øë:v©´ÍÚo‡ïñ¸•+LzjñïůL¨hÇwy„b™œ /ªåÜàPYì;Oy«Wˆ‰½Åñ|ô¦‘ëo5wò-åOB]²‡±Æ]ÚdJ£|è¾,·5ÝN½¦tßÒ±îü×CcSU]}?—º¤¼S¼É´uA.("éãcÚ0…ÅQOôΗ/µxD3ÉÂ+2èW#]À¼‡ ÖñÎfÿ¨Fr¶ƒ-ä¿^>øÇø?…óoû?X‚C§Ž‚@Ap ‡@§ „€‚b~fþ û+ÿßó_~þà?â?ò¿L ns}äQ,~òÀ¹¹ì8 M–´µ®XfPôþŽJxþ¦Æ2ßêQ¢ˆ…'#Ô¯YDò:^o ~á­Cl"×ÊH4̹FžO(±ßfeÛd§Pá‚  ÆÞs£3AzYxÀî ©Aœ be>¶@vV­,ÝkO_kߟø5ù˜óÑp…–OMîW*$ ¤öSæþ¹è_\ÿWþ¡@(zêÓâx8üÔ 1H … 1 ø^ì‹EC!pDB±,ôýú3þ …ÿCüÿÝÿñ—èþ´ÔOã¦úeÃÞ–€Ê)›r“M¡m1ò]kÃ}ªŒ0îØ„,›MuzÒÏy¸R‡1lKó—u üÊDøh_i¿çòwl\ÓMì+ʬ™Â JÕÜ쬧4ž÷u­á¿Ô#ý,¼[Y^a~Ë]£fµp-cŠ8"Ûo8³ž[»S¢þÖJ/[óí=ËÀ¶eY@Å5ªOV~Êí¥äÝ2-Õ½$ßeíϺ;¿—Ë1èmÊNßZiÜà¸Ú°|—ŸÃ+@MW§]ÈòS9?¯{ÕÚ„ç½_X²À1)ú›¢Û¦Àû3Ž Um„ÿzÞûÿ]?È?ü7þñ <Œ‡ N£,sz…¢ñ,Œ9eá1h …üDýðû°×?ø‡üGþø{þÃ/ÑŸâ½Û ÀÙ†#Ñ®Õv¬è—±×«4R…2ÿ‹½¯ŽªzÝÚPi©µXÅ¢”.IIq%Jwƒ€ˆt)ˆ Ò]ÒR’Ò(HwÃÕïìoœ}öwǸ:Æî{ïñùwý÷þÖ3çóÎwÎg’5‘wwpö‘/\l}ãÅšU&¤ËõC(¹>žw{á9Ï8//İ ~O‘t8ÙìL _‰U¾XšÛ½Ãâ'|Ãüe¸ …ógyÅÕBÃNBÏî.¨¤”ÖLÉÙYä|¶ŽŽ²{Ú½®-§†(÷))m`6øÊtß]G–*=™mý"Ce†Òûê äžêm4²¦wKàÜöíIw_O–˜O-³¯âλ„ŽÆK-6„¡?©Ÿ•Ø‚e—ÃCkºý`–ÙÔûA>\x’\`~jÇ;6óÒjQ¿ËÎ]©Òòt9A£f&·î¿Ü{¼Ë7÷Ð*€—†lζWÃl±ÅÜÍWþ¶ìúiN›:cÊ yÛb_Kû‰¢"*ÃÕcBwYÀë¡'Œeá“hŸgE]UÇ]#Ú¼õ=Ú¥ ^Mó‹ïßï7þfüPüCDAð?â? _Ù‰Aà+‚°X°ˆÁ` ÿvü)ÿð_âÿw+™ßñÿWàOýßÑ5êMò—su<믃$ñ¹¥*NÒÈ›WhÇ95N)F#Å®¹ôëÖ{û„$­½Þ÷ÜŸw›éE_Ñ¥FWß~×ÈmËaùNLÔ~\ïë-¡š”n"¶ëBªöúº´Ã…MW§¡ïi-L?ï>sÛ$”DÞ°\¤á:½?ô|9|ž°.CõåZ©m¶€8Éöª¸Ø×âë¤úOÛîm‡ª=s¤kPSqë_5¬ H𽤤˜«~XÌß op-­•–ä|¡«±I—šž>s²–@y°ŠÓä‘.eª!µ• ×|ÅÑyFØ,5Â3îÄ•ø-ÿ ?Èøÿ¿¿÷1(Ð7ù&ó¾)>$ GC‘ ‹DÑ(Q Tþsý€¿ê? ä7ÿ þTÿé‘$nLKÖͶzf+›é„úù…ù–ø‰63Œ#ŸÄ³‚¦²t¬¤ù&÷':™O$…‰F6Ç•s8›ô#úuÍäu_Í?òy¢)FÊ–fgˆ$í\r‰…|%5ƒ^ÏðëƒwE¥uæ|œ°›(¬1Þ¾VX¦f-Q¾¨Iªek5æ²ÿ‘JØÿÊ!@艪4bÉ¢—(Db€ÕßãÒò%Ù5¹Pù¹‡ÏÃO‰Žãdã[Ú?àIâξ*uüÏ{¶ù·áù…ü7ÿáPA£D`X ƒaHQ( ‡Á`PŠ ¾Å‡Ÿá¿è¯÷?ì÷üç¯Á?ùïQDÚxÇ¥Ö·¢YE'ܾ䆘”Ú„—¯zghcª€2ª>tp¡P0}CM\BÌK5ûb)›‘««¹öÂ"v"'ߢ :ÍnzWd±7±Z9Z8š€Îd,á˜Ø&kãÓŠŸƒûEúÉv‚¢Mgwj=w®®M›_ñNy ÍðDõFkÝgªõ*jï©üçàÿÈзd ý¾T†‰@E`ÀïO¢P8€À DH Áßh„@¡ D‚Q?ÁØŸ÷üƒÿPØïúÏ/ÁŸê¿Újêã7ÉkŽï†ß!s®\}Ë*§ I•‹}=òšg/ôôÍGF%ÿƒuæ/x·´dIuöß$Ò÷Vïc%övâôI³¢}Qóæ híĬ¨˜ÑË‚ø( Xî€òÜCòý~ÏþÇ„æ¶ê÷Š÷Éxô*ÖÈÞ¥>ÿ,¯­½ÑBp=ÂÉ®¤€)wÑ‚k"­¨¨ïi4‡â~‰ÄC×,VˆA†s>¸ÝT¸+µ‘É‹]ŸÉDܸôÎw†¼ T‡Ú¦zÉÿµj‘^WjÍÀþW˜Ü°íMhFûT”|ª[†±ÅôuGŒH‘Þãö‚ӾŠ'&Ô~vcÁêNNí—o™:ú¸áÞ,9I/Wy´°±Y´§KU¬îoº‚+Øi?å"¿¹j´œäF\ß^–“ÿ\íH±tÃá$ðxú˜Ø’ºæv—à“*R‹­ iG…j}†z㸳èjqÑlî˾s ç‡ ]Íㄬ[ÉÄ\y÷À]à{uq=ÑÇ·µßZ&Ã9à«,ݤ¸üž %îËQtBNÏæ±ˆïækÌa1…gúà‚ªåçêé ¾”ô´NòFCnŒªs!×ñè1ÉY qáUüŸøþ?Ä þÁæ›^ƒ¡ 4 @¡XE@¡@àX õ3ó`úWþC~÷üü“ÿ¥ôæ¶ã¢{U^-~äõý#³L’¾•âæý $8?™Öºÿ"\~\†«ïiN¶tÒéê1 ß×tá ?’19‰I˜êcòÛ\ïq#:ðÞ—Ç"D:oÅ£z¶bÛïpúݦ¼-×\Ü 3 .x\-0Ü’;· "$,$$5¹¢ir%ˆy±~5¹éV0Î<…L0¯} ¤¿oõQ9ýÝ\Uúþ0TÜÅ·qŸÛÍÕÉ$ºPqž¸SÃŒçUç¼ýÂÁN&!côE¼Tå<·8ÕGå§.ÁŸxãÑd[á/§±”YÞrJJð0vtˆi ád:(5åQª»OÙ`ϪIOKÓYÖÐ{ÿ r®äš¨ª©+Ñ]vn3À•8 ­2{dk¿x|]ª†2|朢?îQb=Ë|˜·²'Ë€ÁZoÙÛ†åëì4ŸŸ>t#©¶ü`Mµ¼ña㙾Ã'ó­¹ÕŒ¡Üò.C&ŸŒÓJÒ‹NÝ0Ó;6TëésxgÔ¯+„®Üÿ(¿³;Jß}»JðC ·cÑ¥Æ%ª-_ws¡ËÆïnJ:Ç7R™ Z“¬¥“­ÛNŠçé6¿Ä9=Óñ”GË\‰¹Ž2 6 `CË/žáGL%°iÈù"ªÉ_ùsNËÆ+Û5­Pjuî'ñYx6Yx1\.ã}õÁáUðÐËáÔ§3!_¨Z]%Ê«q]΀Ï=Xc<¹ñR³«®¹#8$h•¹Ù¥žt&X=^zc×µ{#«Í„;Ìh/oöˆ56䨕Œ(è ßꢱì€7W=Ù·³ÛÏëd´•Ã>¹®͇tyÜá)²hÀ¼é¦š~_z?#u+lÁEFÎUx~&ž6#)WXYêÈ£˜¢ <`|Âq€ÇO¾~ >-¹t° iD÷Ø„Žx×-»-J µ qϱ\xæ¨B»qr‹×‚XoU>þ‡C•1æùeSt íî|a~ª—?“^«p=ÿªù Ýñã=rÆÏõNW}‡Õfmï8·Me£ ÎĆl>Xº5Dš<%¼YZ¸¸#}ÜËb<³^©õ4ËjÜs!ZüƒÃý™K2W}¢G/ .YÈ š0Ü62ëo.ˆèŒCrðÍ}ª“3#Äg²×r:Ô!)ïA÷PξÖÒᜓq½o«9!Oa¹¸š9œ4”!øE“åƒVïÙÓkÁYKX¾²kšúŠÏÍ{«×º€YÄsŒfº iSc‹På /'¤&W5rgnüH¶‚cþ0O¦´ñf¥&\›Ñ0^˰U‹^h5Í//%êÐMuxoÙskèa™‡ aRµX1SàŽj{X™Ÿ¸<7>V(õá;½ì1ê÷ŠV÷i¡®UEüéˆÌÓÝé™;—%H8”mi{œXš‹ñzo3MÆ{f+@‰¨"yVan¶ ù-+ úŒìïÉ$ö~aÍ(t"ãC “ô’³ÂÚÜÜ'#y]›Ç}Dÿxú™Ža¡®WcÝ£·éêC™›àÃOû&4®Eéw¯{Ð8–DÑJ$½(7`äã3§²Nq9þäåÔF—ð@n5:XKÃÅ7§›sO |B+ŒÜ•%yWÏÔ¬mÙ‘­%âqw‚$ñ²Õqe†ÊpÏa÷ÐÐènÀ\ùHV¾û#Y‚ ©»l¶5ÝF“8 U 5SvÐóX–æ˜ï=¿°ä&j¨^NÆÃÂ5·½ÁªäÃÔà‹df¡>9Çü~{¦üϨ™$*3paЫ­°m¡®Xýy‘,²y—Q‡!Auðú´ó{ã ¶\Xºa¡Wø×ùø;ïÍY[º©–úò/)hÛû<ãÁMC¾Æ/-¬™%j‘wÂî`‰T,?<Â~]À•Ú÷}è‡Mu)1¸Îò7–¦"Ú—>ä~ž!æéTh®YŸÚW>eY͸§‡ç’´èÝ+1»iÊþôQëNîÒp(ÈCßíFV·ÍÂã}ÇÈ*µí-Ý슒GÂf6Ã$š+k“KŠ>èа¡ý-ÃÆÍé=¨åa>BÑîXù6¶ÝâÈÂÏî&ÝýDd—›'6~i¦KÓTÜ¡·£êãZk5ÎäË)킹âáë…d‹H£¤Ïcð×cD«â‹åZWô>è~&~ʺœÚʦ’bÏ­Û­åÝ…a™ÆYƒ1×%ƒîç  *h.àÆðPBÃ+ãÌwß‘ë¶- ¡]>tñ?yË2æßl½v˜ÏKonÚÅ“9oÍT§tË3’<ÉÒó¼aF¨åõ¶u]WÒŽ&(7f ô*]HkàÆÝŽRK^Œ%­¸Îkm÷üÏu±¥Û‡¬bpç© Ž¿Wéýïñ#ú‚?ô?ˆ…E`(0‡À0¨ˆ! …¢H‹ Ñ(ˆì'ô¿È·ÿ§þýÖÿ¿ºÿë[Ž+‘Ÿ{µD±èå ´<φîÂkÈsRd˜Œ„˜Í­ÃTø3µÊ†ÏkJ\õ $Ÿ4Ò#_]O²uvvŽ XõO˜.Ï.}—Êó -X¢w· çÊðff”\§cˆ~ å“›ûï‹­g“Öa¤EVÌ“µ’,­ÏŸÌm÷-ô--®PÔªŽ{œn¤ÌÌĬ¤ò‚ÞA½Ÿ«*os<¹,`¬Ð•dhw_Ìoð)—ˆ©œØ#ÌšRµ ˆ :°Ä­ó¡=tLpeì}O|"&ê¤x¢ËYJ3Η‘ç¶C´bÅ?d '6‰vØ~)’Â~8X"½+ÕUZ²·:í|XîÂv³KÀûˆn}˜ÔøÉ6¢ƒ"Ȱ¿ÖÒvzÎÝéôËÉžQoášÛĺ„kJh¸tÄy†(üøDm›íáóÓ¨AºF‘bÙeªÍ¦g?_ê²§.jdâ¯&xTËèWjP[¢b£¼aKm…t·ãÅ9¬£gm›ij9ŒF·±Œ¾jÓU‘"áHCˆ£ÛŤz’IÊ9È.Ÿ¢ž§ßKÌ{ïûŽÝµª2]öžÂ ßú­þ+µÈì¶¶/T=®›ß¹mº—4×!ä‚HóçâЦ),¦¸¶Æú\;¦J¶Ô«`™&ä+†K…RÈîÍšqYüí÷T,:Fórc|šÚö2Þ±‰*zXÅú³äû[듽±Ã_;iÏ…'‘Bæ|¹´÷KbEÍ«ŸôR ” Ù^f˜4)PFAp«­Ô ´ô'—µ ì%‹3ÌxšUN\¸/éí’8m+RòªÇ*&!V®µT,Ñ)-iÀ^ue &©c™6¾?Qh¯äùÕ½jÞÚ`½¡¥s—5È‹IjFa£Ñá"‘øx¼Gž‹|/çhc°†Ëv¢³  ä^ÝO”¤f²´^ä­Æ4ƒ¥Ú>5åI¿»qsU0^ÙãòbÐAYáÁöú(ÊZX~7ÄÚãùçP© c©£Æ’ä}Å¢ÍÕ—ÇIãCÌf^ã–m À1ƒÂš-›ÂeýxÍ­S8Ë¥ :=²²T—Jý¯è§ê0ñTœêITÝ€þºô³>KÓØj/Ö•}|Rôb«æ½Î4°K–Öpø•ÌeRW¹MfòÊÇÖbÄ6HÝ—ûA© X¶h*,/S%CBùˆŠždI“Û÷¸K÷†kÛ×Ùj~Ý2–Ú±Šæ3Å¥ ⃭_gTí&pXW±…ÁÔJÍzÔʹä#®Ë,¬ö’÷÷39ËDÁTܺ§KB‰‹è{FxmÞ ÷a8::[Ñ„Ÿq¸UÊ8Œ—½*œw«îÒ'Ù&в¿3ÝÖ¼²%·R>[µ4+h;7¦ºÃ({ÄvzÑãrRä¿Éwô7þïÀ刈èù$*F$ ðM``Ž áXÌ7ƒ"PX þDÿôÏû_ ÿªÿC×ÿ þ™ÿSô m“TÈ=¿Ü 7ã”Åm«¨Ò`j3ÏSbS´xùžÌPo<ÇÈ'/¤ÿlä†ûv‘´J45áŒ]yi;è`>›/k—yíZ±ô¼+ÿãÖËãñ6Ê·ØF­Ë4’¯‡úè*ß÷RÕ•é q /ëëÙö ¬Jûˆ»yìp??sI¸Ýs[˜ç¥éË—\ÕדŒˆ[Ûƒ•[om= ìÁV+OÏËU{Ë•Ø{¾‹ª4ß’g|ìd tíãF…Õõåß²~U5YÐIØêÂfdâÇÐ\sL{!þº¸¾²aw¼×Xz Ýï#5@õ0ś֯å)h£F'´KqZ!´­O(d>–T%·V0ª&zcÆ;—H]õDÎÖ.U^8Ñ4ñ@@ÞÆ÷1o—tí ™‰WWg °”ÇžçÑŽÐ-MJ1ê’ÅMŒj]¿Æå|ÕFÏQWOáöxÛU‹¡8bÑTÅN•$oછÑÁ*_V˜«e‡kF]Ó(ßJõ(÷~œfCzŒõ='èlP™ÇíõUžÞlÕ.Âsè_"ÖàX‘- A•9)«È8ÓÃ5©€¹Y5ÓBio÷¡¼.~;Àiu±ã¬8hB¼ã.)“óf;}‰ÆÅ,ìÈ“;fe½Oò¥8ŽÞ•Z¶ËòNsÜÛú·» ˆ×bZü0}„nŸÇyÍ7ÞñÜ›$Œ'æQqãzý6á9å3Aú‰Éfìf eŠL‡^|ž•Éñ<õîzL˜ndö€‹B@ÓòÈ“™ ²4c¿” ¯‘ŽÒ6µÊ¾ÅwßsiÀVå ­]¥ÉÑ |Ý]ŸKkE^u?U™KNÒLù´R’+Mi®„×›¯aÖßOóš½d…?·Õš¸´eá´¨®Ë(¯³ê£8V) |ïᥬvƒZ`ÍÚ÷kR,Æ&®•ÄÈ–§±ZœhgW¥çòÁñ¢?¦4侂Ò+§—uرÏK˜µT ßœUå€}<(C.ëscdŒ)ÅCZä 8ÏœÜ;?ž£Uïå\ÑÃÉi½å©©Ê+˜å-ßô/h#¹`²“£ÝŠN]sí`®÷×$¾.”à°Òበ윱ܠBÍ[s%'· E¢ä‰ªn÷3nœáD&R@ŒÓ# ¦ßâ¾3ž.ïyÕÁÌÏ¿ºuëJÑJÏÖîÓ¯+š¾%L3Ñ—s1§eÛf¹ÅÀ8'?¨³3/g¨›Ý ¡ƒWI¶æîzÒ¢Ë3ó“ê& ˆô…!]!î »4Ùƒª(´_MþFW®xJK~Ç'£ù¯t >ÛJÔ ¹g§²œ4«Ö¼Þ\(î³Le1ž´&U¨=ñ½4ÍïìTÁŠ¡¥ =°¿ ”³z"ùt³`pᶆúóg}1n4S4u,®²ÖÒ:ÕwW':ƒû*ÖŸë¸3"ÄÚ»3Ì8|ŸÊ{>í2º!4/ ¤IæË,D°j¥Ô˜­´Œò<ªfòvšœ)wó­`„ܦâ9ºFx*È6œzðÁ$ØÿU£&vžeÏ/-ßúh—m2Õù£â¹6fýõ4 ,`NГ-*µb‰ñ“BÙ½+Jžµm2> ™MH­µb>m£w|\dÁ£Aʧ6Ì @ ‰Ú’žÈ¬%ã~ñËùë<µ -ªV˜jöq\ wŇ•ïétCÕÄ:bvˆz™žrìè‡_‡â+±^Ùb—…Â_QµŒ 2ÓjŸõÓ=é¾Xt7ž{£Êö†ŒŽDRæÅó[ŽdwZ òñ%‰]Âdõ0°¥šiÆhZQæœ{‹Y,›l~p䙢´¯‹9¼úX\m¼Ž)}»\™-ÆmrݱC¯h‰+…%ó9 È÷ãm‚å’Ë ØÀ†Ni™¥Zl5þRñ[n9ãü2}ó£6ÚWüÿü‚ÁpðùÃÑ0üýÕŒ‹‚(Ì÷ p8ŠÀ, Žþ ÿ/ì_ü_þ‘ÿE~û?üüiþCë“ú8€É}ßľ8JÉŒjì8G%@aßû"£A¿.Ìž1¬¹ç„mdø\Jü-FÞ,SØÞ*mmÍElêê­/Ü žAöeš9¬ÚûIÏÞ?}¢û£òâ½NË­1^žÜÐ¥Yw}FVE.iñ½õ.±Ìû„~VvA&/·X–fˆš”GêLlú§ý93mbßÅ:ûùìðþm)Adÿ£Õ#Í›©×^W#Ô G_Mõ,Í ΜšånWXÓù “'¦·8{ù »;çòb 3;˵Þ.øÕ”.'Ê(§[|°/UHœ<Óè5^BöXÂ%®›?ÒÐBÂÛïq"çTÊtܤfÿ([øYôðñçëÇ 0‹ëž[Ó§ux¯L- ¨ˆšº÷ì÷žõ×Þ4/ôõã²wëûP×}&S¡m-\Ρ°ÏJâ6èiy‰Í/ÁÚ1ÚªÏÀAbT[ótâtÑâõÛ@ê5Ö>Š2&‰îyMÑ]J·‡=©÷BûËÕPìŽyÔë”¶q»J³Ÿ$$YÃ)åhž©Vè’f (PçW9}2Ýô:ñùÌõDÕæÝê¡)o]¾„Mˆ ~­tôyán»à=¼ûþ?Êüþà GbáX( `X0 € @ „F~ã±(\Tôgæ¿!è_ù‚üžÿü%øSÿ¯fçí&yõ1ÿ^œ5O,{ŸŠ|uä‚ït?o.4R5ÿH£…èÚó¸…ŠÜP(SrW¤)ÖåéJ‚¥6Ó½òü%*Oj£H ±¡jÑŒ÷Ù¶±9®Óe½8re À@G¡ÏhœÐwÕ/3[ŽËiP gãÒ]XM’aãYè²–œ\á••ty–8ƒ„3»Ä ¦_Ü‹[c±ÏàSŒ µå*Fmúit@–JG«ë$´ -Lí®-§L&ƒƒú⯜VRdp7Iv>¤Ñ>ÓÙ©ºï¥E|YÕN=î˜ [[üÅ=åk7ÑuIœãÓÃFÿnyÇüÓÊIvKk±¡˜Â  m“ž¯ƒš¤~)†í…åÍ¡£¢J4ºIó}sÇWϦKë(›.,è÷ÁqçËSž¥ý?=Iðü¡` "A ¾ûcÁß‚D¾]þ¡P ðûÎúM ˆ (.ú3óßÿÚÿ ùGÿïoÿ·_‚ñ jPËï»·|òËV~=›ÎÞ/lG/G9V‹¸têV:}=u‰E´©f$õ*Ç…¨~"ÑsÙ•>óD;²ü°ä¡#zvq„iÐ#¦|–[óó­²q|lïY×+^½Ð3™¡‚L/$SÃ[]\Í:Žæ^:°²e!ñ=¥·/¯°µ$% ž>Ø»,…­Lþ½§òŸƒã¿È÷úß?øþnñ F|“üŠ€" PÀß]ßX”(†cfÿó·tÿþCA€ßõ¿_‚òß:òûüÿþYh¿š¥@¿t³ôÄE ˜½ÒvmüeNV‹óš¡†vÆÈ F–µ×ÁÓîHÎçýÚLtP™ŒÞ»zA5 nÎcÁÈ<–8»Ñ¾`ša+%|怹·Bª£`ã’¨Uw¾¬!À( ùn*׋…ªÏY>€O3Ð$»‘ˆjþD]RÊ%ê;pç0krÅ©³òÝk>8¡‘¡¶Ý‘ïÿÞSúÿ?È ä¿ó?‚€Š  QŠB Ñ¢(úíN"1 H€!€˜Ÿñüv­øùú[ÿÿü©ÿWKM}@^óån¸«Ê{n5¼c¹<|%¦òúI×â¢Ä‘§«_ÙÏÄû+Y3£XÞ7åö'“6Ãù°áFÏnrs*]jy¥zgå†ïy£ãÿbïÌÿ©\û=^2dÉ"¡¡2dè^ë^ýÌS²d.!C̤֘™‡P†ŒB™‡ˆZÈ!D)Ã’P"S*”NöÞÏó´÷çÔyÓ>çyùü ×ë~_÷wº>_8ÅØ¦R‚SB*FJ¬ FtÒXCÀ82_º±šëMŽmM ÃM¶á“ö)_íy_àžöaå +í¼çƒINw;ƒ÷Þñ îíõª5Û3f¡z°z.óJ‡‹íþúñýÏ]Ø;Ï~¼¹Ìw¦èr-‹r?<+n½•)­”Áx,ô*a$0Ö†ƒùƒKòÌ[±¢Ñ/£ÎŸÌÇ·ÆÄÇ';Ù"á!’s;µ™söá<Ïçfoö =çjëEÍÐkõ3rÊ0®•µ_ÊU³ÅÐ!­}A•6Ý¢ÇëЉø©”(žå¹ÖtZZ ·Lð6l¦nÖþþbY¥gÈt»ûðÀÇ!ËfeíG“·žÞHa¯B]r&ÓÙ<2E]¼[cà—n¶½‚1œMïJJ»Ó6€8ì3;³$—ê3Y28+tönp +­²ÌHAÝ-š“/¿r¼=Ô[© Xujwˆ•„¥¯ó5Þä<Á« w½ myv‡-ïö –ùú-süÑ“b온'Š7ßMj÷(¬ÈZ]“ÖÐcrÕ»¥”p´‚i4½Ïv‹R¹Ñ°kÒi=©v‰½\ç|Ã‡Ž›’Šš*–3î å8u«–æ'²’€'Å:Âk…qìêÅ–Z˜%ÿ(xØ”¡äþ‹gr-¹/} 9qÈ!ÆÜÂÅ µß85ø„G«Ì?§ö’’Ô4vÂ牑U*v@”>ŸÎ#ZжjlcíçᵂÍd >·£yTÜk–½~R$eH#‹UNn½ã£\¸[p?k\•ëkT ÜoÑ&Ð\ ê+%1ÍÈ5â¡‹Õi·mLäQvÖ£ ÞD‚¨ /9î2Þð´ùÎüYœê•ìÛâ#ª»ä…ºù Ü ÅmWEh}ŸÐÜ3Ú¼b]0ˆZi%·[`dµ§ßwÏ¸å •a›cÌi £Ÿã_CY°nûºä½\LÎô DZ=Qu³œ~ËÇÔ$¹R4ýÅ"S ¯Úô±^Í”U‰é}³+‹B„JrÑ­¡¦§¯`åv#â_à³ÙÐ#°ëÓ«W‰ôéÆcÅbdÕ·&® oêYm$–6…HêyžM=z—;4é ‰6A~sÛ†ÔWýÕšœRN(¬ØëL'ôzë=8vŠSõaUWËñ —I¯]‹¥k Ì›Oàr¬2 yõÁ€³4h/Q;.Ü3˜àlŠ~ÛÎl™“•±Xæ‚ÉOŽÌ¿ÝWQw 6ƨk&\Õ>¬@AcúâgSïv°½X^‰¬ÿˆ9h¯[+ë }x½^¸ý^Ôö¿¤ºÿA½ÞùÁ!(2ˆ#ã¾åg‹E"‰TI¤€°* ƒC‘ ü)ÿ‡ïó?ÌoýôFÿç—è»úO¤ª‚Ssv™çL¿KVˆö-c}˜¶¢6Bþü^›tâtžÖW/™ì´š Q/ä½3'áªý{ogðtøy7"BçkÁ{½ƒLh-ç—kæâmgúë–V³¤“)$$I:µ#91ÇÒƒ«#õ˜o+z9Þ8~Ð÷s–,SŽíœ‰S0wuïbέ¶ A¥ÚlÝãNZ\´èiÑ´×eŠKiÅ» fНt¿5~-á:·ëÝ#†Þ'G‡§X.ŸZ\fÙ°€øïéùG 0ðÅA$ H¦~Þ ¡ˆX$Ä12š€ÆQÖ;ÑH"‰Jý©ýhä_øÇ€óß¿FßņëþŸëùŸBXp%}¦H¦Œ‰GYÿÉ…­¤Ô/Â7È;ÂC¾ÙßHÈäž<Õ^ÐiÒÕû¸Ÿ‡9–‰ÉLÅ›³èºY[i/#õúk…:x'¹ D;?äÙzf]™{窠¤Û£JñÄ´—-ómi3&˜ Ã`ÕÑÎÍéK™š“Þfi*¶{ÉYR»fGlaŠl°‹òAa(³w7ÃwÆcrìRJ÷°z=ϯ‰×ÊñJËu¿p¡\êê]õø®Ñ#ßÙO(dùÊi*ÝϘî^$d9·±tþMx·ó ÙíQvٚʯ{_»¸Ã¤ß[¯HjÖ¤n±=,ÑÙ«¡ÙÖ7Kʹ05Ùé&áS^Ñò¥ñÕÎUf‘jÃiÞÿ×=žÿLÿ5ÿˆD€õÿ(K¢H2HÀQd,BRÑÃP"–LÂ(˜uàŸ©ÿþéýÇoü#ÿÿ/Ñ¿ø¼Ü óWÙ0«ô@XPûô©9ÎÇÙêdñ¨Çõögw~Œ:{È{¦qL€/²Ÿ9È䔸cÇJîXÏ6õ“ï3ùÙ‹„óßà;úÃ]¶¡î•´fã(¨[_4UH¿° J¸"¾EXk Š*‡Ž\•Ö?ÇQ¢zVøqÄá;žQ%Bo^ cø,ÞØg”¬xZ§GJyÌÒæôÏ8pͶ›,T<–žÞý(åµë›¿õ´þýôƒü£@èþÉH™HÁ¡2I%‚H4‡IˆŒÂ¬/4‰?Ç?æ¯ü#À ÿ‡_¢ïüŸ¢þÙÿMÎ×%ev«6=À[<Õxòž –,¶¯0;ä«c0¯@“üÐhîã9Í·i[-{I"›xejøÃ­ Ü3˜zTò·¯×´¨´‰ìb:Ü×ÈÛ¢)Õ7»çxRÒSîø¾öDkÿ⦯Ü=¶¡yº;fÜצîÜtS-Bk…}§ÒEl´vkkÊš*A+‹“ù¥„«òÎ’m€l—²dÈrY!ľyJi§{—çEmÄ­jKãWó}! ×)Õǘ›Ò»¥? óêàc ÉC׌ÎçÜõT”âBh/8 3áKE‚ÖFïuyÄEì'N¾Ý®Þ ¯36¯ã{Ü­Á..„‹š›êu ;³q˜{™½Ëø»ã #ÓÑFŸ/‡™Ç=6–p§êŽ£³ëÄ ’e·ºWªmqqRk4öÜ®¸þáÊ«×_z•øF ÖÖtpÙnº /z´s/<Æâ´Å_ÑQ|ÞºÀWþ¦qŸÍ/à{JuXþÞ/wCÿúøú–ŒaPà?æÿPhÌo}(4 ‘Ѐˆ! ‘h €…C“Q(ˆ üDü‡ùSÿóûþ§ùŸ_¢ÝÿFºúëû_g‹¯Ùë¼²sÙ|I Bu¿Xš ^!ØÏ:Ä»*’>_7hé®Y= ‚ž‹Kº¹gè›.áŠFëJG3Ôo»Ó¶å@Úx‡ô½ÇŠ1½fâúª K° |—ùl*÷„à,úî4¸hU` ë6šÒ.ô¹kðÕ¸kÙe™Ò-:¬ÖOl9÷=-Ýâ]Ù8¢mîJ·¿¿µ—o~[%}KŸ °ªxd ’:ÇE±’Éð2:ê”\ÈŸÚœh%ÂÕ/ˆ?³ó†@MWJ´ªÕ££Ò-b¹ÏDªŽÛ¶~pòŽdèul ÅÜI^e6ìK†{¼4Cg4©ê„ øÆé!Žô´<Ýa×˨…åO 9. /áMm—IÓfO—>-*‹ÄÔÒù¯á™>CYLwù(…Oç(|©¢Éƌ̩XðôMå[×§L Øq4‘P€#Ñä 7sü„Á'¤„-ßဌò´´’šz扪m˜Ný…‰=ý'³°òŸm{~ý6†áC­ïúEÄ‘ë9òÛÅ@DbÑ”oÁˆF‘ÑT™JE‚8 ó3ó? ö¯ý °ÿý}WÿÕ×]ßÿøÿ`£A7’”ÆöÇWÂYÖ'‡ àÝÛ¨¹ÓÁ™u/Ä|„=®a©/’ƒUäîØ ³>Mô¶cæ9ï&0²\ÁYq¾”ŸýTñ°ó­Æcvƒ_|æÊp_¼é™±cSó93­P—‰7b¸\©‡æqjígGöeS׬\,Uxl­UüÚ¡£EcÅ«zf™À܉ý[}s¸ó4õl¥ oŒ²X„·ßW+„¬^ÍËÏ=@u;HžV›¤±q8ª<'9_JmkAE[§Ô^Å~<Àu‡¯5h ìa,ÝYÌß¹•*ç×9ÊÓ¨y‰©Öhím¶#¼1Ï™·ª¾1r4¹(ݤía!?·%eiË÷î ™O‰kšÿx©BÁyMÖf?eX¹Ð Îó UÕ^ŠÝq×ßË÷¹®ýáÿ`ï:ƒ¢J·-Y‚„&(Yr`ÇÓ ¶ $‰‚d$vDrÉŠ´‘¨%*’3"A$¡Á€"™7÷V½çÔ«ëúuþœsªNÕZßÞû¬½·±óR@Ü{–rËQ½<ïš´Å›‹ã<ãéÅË…¹éÆŠfa “Ö ]sE¨×¤›ûbÇvöÊËõÆ…üJ{v5à>ªm°«™ø9ÊEêtŠÃøb~ƒ~5ãÊÍhû,®ñÇ•ÄM"æ‚{õX{˜œO¸«kä7p|ç~ÿ [¿××—ÂÔÀÊ3,ÚÂŽÛÍ ù-'Îñ%BP/øóÎ=¯ímƒX¡ððœÏ­”‚Gí3®éw~Í·yf¢ê. X!ïçį&Ú¯D;Ä]åÚáÃL|ÑͬäY®³³I'¦ç£q°vj8µ1V/Ëvᔩeï—EFºO`Ä ·™êìžô&åzïDìŸÊU“sªá%i•=(,{’µh¼½³ú•z½“ŸÂøÏ2öß©ÿ1ÚïúA!0D, ¡€ÃÃ!H, #<ÆáÁ( Ç`ÀÔ̓ÂÁ×à—ÿóçà/õ?Ó5ýq4Û~Fã §p¼¬ž&&`:_jLÍPYH¬]ÉÛÄž=邨¹y”œÀF£²ýI½DÙGPÇÛ¼Ûë¾'”¦P⬜X‘̉Æ,tJžºé¸Ñ1‰E á%íã(­àMuaêÕPY‹ÃH‹æYDZ»Š¾’ˆ2ïÝÛÖ¨V0šáfKâž»2Zñ‰X'Œ ÞK‚Ó)äm˜°k¹×õ)™ ý}U;.è­53ØòÊ•å¼} eþüÅs´gÕBJh“¥Ÿ.ÑS1—‚fºÞðì+ƒé•»ê–jÁü*Vž¼Îßå¾=Ú3¿Òü¨‚û0øÎÃŒ"‚mždwaí| /ùTjó½å(7pxCŒO¦ù“ðìhÙ,TÞ¨IH6¿;ßwäo\)(z„¯«ðÜÚ‰Œû¶µ3¢)í³)ü¡0±êÂ:ÛRIë¤Ie*Ié턲ý*e͉aŸÍc®Ûé»Þ±;wå]lYijZ;|ñÐ{Îv½äƒØA×¢QûÐT¹Î€–pzïð æ@­WKÃ}â‹ êµ5ÇûÁ/Ǭ%%oª(* VØs” |μaÕÐ~–s©—†úþ^Ò¦5=Ûœú—7„‹]Zn^Šw¨‡[Ùo¡)ÚIÛ_œ®WM9{‡v·“'ô*’¾Ã" L•†`¹z£zÜâ–’1ñôz,mnt¥îɧuð1P7t-šËœ9ÆX^E¹ViK+€‰†ÆPx ð+Ïp®~qd¡mÁ@­ÖûÝ@ >¤„terÎRÏ}²O+ñ w)þäï¦û”$PB5Ž›îÇ–J6Ëúž„[z'¸º®×rE™xEF,š?öaž-Ió•þdøìEµ¹Ã:÷Ø„WÅHš…W™^Ø.É!¿Ï«&“E*§¨_رÒEæPLæï].›&¾ê¤îžõ{nýhæð±®Ü.+mõ#³zÞË”Íד5Ò"“h' 1#þ |Èå›j÷xåDžŽ–µT°"•„ƒ{•ú¡-·‚œŽáax‰ ¦‡ŠCÇÍŘó  †‡6Î`ÝÆ¢ ífzõæVLšWê­2>è*xÊ5x#fÞm}\qRZ6\ÚÙ{çâRH~'¶9»§¹GÙèf·€þµSüÿ¾Kÿ!pôþ_ ŒÅ…x>P"†A)1p0†ˆDáPÜìÿþ÷úppÃ/ýÿøSÿ 7jY¨„9i¶c,†Ðúàdwé,qÍT –YvA‰O.„ûksø>ô:ðf\Å÷ˆ”w@)â ¿Cëù! 4(wðÂ{J¨CgÑkÞQŸ¸ë°„úö¼2¨Àë)ã2ÒÇ’Ûáz ïel?o«ÑܦAzPNùš‰Œ$"[RÄGjêZV þ~bǶ¯š’曵ì¶öÓüGàûøC‚?úÿ¿ù}À@?H‰ (AÀðxÈ·„€`ðXŠÄþÈü?ä¿åÐ_ý_?ò¿ØHç›ÿ§üðÎ[†QÉPMzö¬¶²MwCUmßàHŸÚå0Íëû¯×gäémà[`-û†í…Ô¾ ¢1+7¬2GD©kÍ~q|QÙƒÒ$P‚M3#d˜ž©½TˆÈ •À!ptÚÝUB  I+¦—Árë˧ֶä›eêdR Ÿ»Ñ%1ô.ÈÚvöv¤ËŠº.§!ßèÅ0‘ hÄ ÍŠˆ#&KjÀ 6x _ašç´±ÔñfÍÙ— D¾K; –/{ÓWé.»Cï¶í{ÐëÀoš'pT8Ϭ٢u®L«Sð÷¾4€æN³m»*’ÿl. ™eFb{¶ÈäE3†W6¯OIÖàMb4îkÄÈ{L~º¬KƒÃ¼ê5žV¢ø-'Ä“}›wÚ¯¤ëLf£},i¿k}c .4#Ÿ‹?‡úðÅ{9ÑHjyäB”çÖ•'ÇR1-±šÜ6«Ÿu\FYÈ­;4fÝ{vß9žóÿß×ÿEÂÿèÿ€< bð($ þm0’ÆÃ€ƒ¬ ŽDÂq` ‚ÂÿÈÿüïùþkþßOÁŸüÏ1±Ôsõ?D©¡GË™ch°å)å›MívÍ ãˆÎE€;ñd9×Lc¿¼÷ “®gNû–Â^ßÚÉ­Yj‡B:g4hŽ 5Z„ñ¸…¤´ÈD¹éÐÉHܵ‡C¨{ž'ð›KdŸþš]—)òvž¤}ÿÆ‚š”š\uZ¡Áô„ƒè öÏ ðs­¸@–|ƒ×a\7…Ÿç(¡NkåEmnmh¬ G½ÑÉnî:¥’Юö’t"„;DÝåéF/bXœì²+(f>ZjÖÂÅ#ȹÑ(T‡bh#{»X «jYˆX=rN©ò&,ÝìW›Rk{zíÞóêí7¹ÓîÆ/–Õ›}Çuãs´ ¯ðÞ–,µÖ0#WUÔ]½'6"œ²dýòÈJÛ'/Ïä˜)"ìÛ–ÂÝ_‡Ï __æÌ—A0Wå_“*âSuQ;µå3¬Ö¤UÜ^Ö. †}L7õ2[]š1ª{£Ê#¸ËV8‚>9À8ÅØ³A<Ú<ší?(X©«O^Y·æ ½}â˜~é³ëodêC±xßn1kýM¼Ù½û)Ò½®ÃÞõO¾¼×ɸiÑ*°+AÕ5•yùÙ<øy#ÓN-¢º!u~RÌ×zrº²¡õ²¥±l†ו$®kdïØý¼Àáþá’.–JÅVÿòžc7)eÓ}OÔ)«¼øÏýñ/|þCèAì÷»þÀ8 @~SkÜÌqp8®@„ã ‰<¸Ãpx<üôÿàÉÿðû?Õÿ~ þÿô2¶€¹kÉÒ* ëÚ/­ÆÜ¸˜ ôeNÖ ŸKÎ9«£««@ µ§Ö;ûçu$[yèR¨`½é­Åî®s¯ÍÛmÃ;^˜•Ž}|Ú}µ3˜XjîÙ°È×`‘³Úêó)xý3éVK7Iéöí1z[ÉÅæ»A¤å#2œíüåÚà0ò[¥ ¿3¦s( ·ÃW…9ZËÀ¹É’&¿SôÂ^Ž$Ý}¯ÿbïÊ£©lÛ}Š­Ì2TR!„mØÏÞÏžÉ<–a#ö˜… Qf™ÙÆ(2¤—6ÉeµM‘TŠ”mÈ,•yú|œ÷}¿Óyß?N³¾Þs¾Ïï¯g=k¯µ×º×óûÝ×uß×õ»–ênE.¡®niÇ]Ý¿y˜ÿ¿Æwñ‰Ä"°¿ñP6ê¼D"‚DÁ’‘x ba I‰x"†‚Èx<š@þ!ÿWøùÂÁMþÿ |ëÿúþßwlÄíÚˆ!Ï“&#áŽ{Uj55[pՋņù¹{ȶyë9µþÇêÇ¿¾°»ö|ŽŠòâh\šµ±šo—Ïë Ìv` ]¦½EŸèòg&'‘Mq\¯R ‚²ÉÍbaBÛN›·«ö{¾2íÒfÕC­2ÓúB–B;o£uÐjö]ƒ÷æ]¯ÚnÝÿò¯]¤a|/ÿßý¿ÖÙ‡,À®§}(<D$$’±xpæ?¦ÀþÿÔø7Ïþ“ÿá\º­zÏ L húëOmím º¦RM!ì#ç+É’Pá$èÛì­–^]‹¹F+B¯c½š+.ZYiB ‚:„œ““œsŸíµuÅ"9—ÍkIJsLâ¤ÄH¨*s9\wºPà¨p_õ-(2VÙ&¥ézfÀ´Þ´…eKý*îý_»ÿ¦ø>þ¨œÿ`ÈŽ$QÈD€@@a2Àbш‚ax‚Ãã1äñÿZÿƒ?Çÿ›ç??ßÜÿG°û«ðO-C‡,ÂîR‚´µ™ñ¾¸}’Ÿ6N-z¸÷¡Øêrœw+^¹×“"˜šCuÅ[õô”ÔoçØ]fz¼Oä¤Å}ùzë²ñË:_·šXÒ‘Ó•íì•mZ<=‚h¼Â…wu>©4;X,4,ê¼ÉLús‡DLÎF¨ê .éÕ˪>ô½UVÔ°mEkvÂåÇZqÓ*¨ÝãµU{X2d’úµàÕ¹%vêÀûDý 0w¿íÞ¿©+4¨U˜n&ÿ|'ÿ‘Øoü'¢HD–L@baSZˆXŽBQ0p  ð<(hü¡øüÿ‘›õÿ?Þÿ /mìþ²Í-&æRMZ‚²:r2fîrÍúfŸÛÌ uXŠfЦ[öu¸ñ!Üf¨Ón“%%²œœœ‘œí^`fFÍ8\oƇ§B%óCw§¸æˆ'ŠË<–3,Ô ˜K[XJ{ %ŒHÅ“†r<^ˆª$êQ¬¬œä’PÊUvIýo¸·\éž„}ùk—é_ßÉüîÿ·Qˆðp"Eh, ˆd v= €mœ ¢×³2åGüßúÿþÿ¯ À&ÿ¾¹ÿ¡8Öý¶ÿ‹à#tLÎÆ–ÅwìÏžÁ¹ôã{ô©OWcÞ\[« ÆY‰¶W=ƒMTN!Нŋ)Ádt“ü³vi41‚@þn‹~zŽèåbÿúG¹ ¿9Ërøk·ÃƘ½³î>>|óF;%¾HU &ꧬüÃDKÍÛ\m3ã÷¶«K/ø«ðŽ]7œ»¤“Ã$JÛFÞ¢p`ޝŒÙòLˆ¥ú{×Ö2šÔ,[]_ÄWˬ €…(Nãø³ê×°ëqËŒíÆ»ÆdŠdíeÇ:V ONXÔÜìO¯JRÑÚ±W%•Ø”d¦6<áÙÉõpACÐMÑ£‚^ó†¹s-É#ë|¨Ïç§Wø§\ >oº«Ì¼‡·Ö M®8UòV.ìç/Þ· ÁÕ§-ü5ýþÃÖÓz$(€x€(‡'PÐÃ_ë)~cö‰Œ!")dIax8K‚ êê¿€ÿ2ÿéWþ£7ý~¾½ÿ=»1ÿaÃÿKU[Oû¤TQ5«{œUòBªf¨xÏ`‡…øEG´ û¯*JE±(ÕnÙ»z¸bØ»íuø”Ÿ"E­Ö;%Ï6ÁÄ'="Ü—$Ò²Tbla²ŠÞ”“•’´EKxÌbOÓe»Ý‡ÔªÊ<=]ÉðRŠ»;?MýBˆiüÊ`,ŒŒL¾p\JçÐÊŠs,çþz»<¨¶?AùFaix twä|3èhˆuy6ÅrãfmP»’Tl¨4/‚¸2dÙY̟ؼ.ù°ãÒŽ¥-åªoB"ÂgZØânSŠ·FÎ D4 ¦lã¡ÄsMÔŸª Œ‚Wˆ¿ž‰Ê?Í,0F–ð_°øÒyîQrtð1§]’]¡á_öY0¯í$ =_éüÅŒÕ9³Å±J–Bu7iim+³rCœ/Î / … Á rFÇ ¤d^±ÖŸ|¼½kŸ™SÔ…¦xµð†ÿZó}Uö¡^ŸFX˜ˆptÆý’Å>“ÓîA¸ÖjnLS>“ó¥ ^%S¢4“˜]^ïN¸àhéÑb?´r’üQ‡€ò³e±#u廢};ßÛĹ[?kê?}u¤u«×A…Ͼ¡UÛ–Å;䃉Õv«\×ßÞ8;u4¡æåV-’bEÜØçÇ–wsºEy'^3&Éèi©k‡µi>‚à¾7·;˜_ð§}4KÉ ç¬-4¹{ô8aÚØ±}-}v9‹õõS¯ý—òI#Jy!snv²B]1!©íþ¢¿EMBd‘lk`vÕ#¿­O­‡K>x^?qBñµK\¥Á*KN"¯$ƒy´f*]%¤+vɶª.±q^MM/ôU½Ö££¯Ô>1D8£%³ÌþM¯gÿéøýßèð^—çßú¿àëñ±ž’ÑX2 ÀÃ(8KÄHx"„aÐ £`¤ÿc}ùFÿ_çnÞÿþ|ÓÿgãÒ ãžZ…F½JÍÝ6JMyJ9L¡=%’óN%?ñÕèy' cÔña:m áyÀLBÝÙñ@-SÔþ]?é£þjTMK}¥W|².£[»•¦BîìB¬•4Ip<…b—W¸—Òú¼•Û ×¥Ì{mŒ¥Ó>åËÈC2¦D³ƒÍõ¹èÆž¨kbº¸z$yi¢ú™¢:RÖ¶õY;#NXó……‚ÃbsTÖ©Å#&.¡…\zC¹†vÍž*òMåeŸŸUÏ´FXú`¥ß!ÉÒ‹e=€uôfâ~_»ü 7à`Sd¤?U Á=ü\’ò²AàÄ¢LnÖ9¿ÒךM>g8(|fÄOG xK‹Ãáãv:%Û÷άÁŒ'ý¢»àÁ‚%.[Ø¢<@û Š‚Û’+»ÍB±%”À-äš+jDg4v¥Å+¼Ë{Úê;B¬)ª\,²Â*¹Ù¼“zÄi—¥€/oÆ“Å|qõgB—(k·»#GŽ;7Øv§ƒBAOzŒjOM‡+¶=O;zdÑûÁ^åÀžïÎ#õ(ß(o¢Ç\ßæp²‡f=²b>^]cøàÖd2½zÏò ¶Dytîâý†;÷NÛEGz¾¨yü·ø•ýs  ìï0¹L )*@þÚsÿt|ŸþÃ0Øïú¡$@$Ñx‰)2_ÿ œ °0žˆ$?Rÿ ÐÈ?è?j=)ØÔÿŸoêp6õŸ>ÏŤ´w3¿=­q÷l;kÉ}÷IȹŸzmÃþ)Üw­zc «a¹'›ûB›Ò<¢z˜$u+ ²-ß>‘«—ÇÆdUw"ÍQ‘„&oµ©Hˆz'˜¼ÝÛÞËÏN—©¸VÊTR>áâü‰¹6Äýö×Å‹ ç›åÄHPÑÚ§ª|ä«ã܈ä›#Y¬¡ý‰cJ±ÌÚˆ Ê@üò]“ê ݼ/9ø({øxg쎆3ëd—Úà\ïå#JtŸh4¨¤¿Öp¾Å~3‘Q.ã®xùÎdIk9Ožn0‡×ª"ëèÀ#‰“™§]¿îqaBìØÉ×Þ`ì”^ÈëÞm·»P‹wé¼×;uŒ²T×iIÍ ß Í•…ÝfŸ¼Ø4sì¼¾/HÛÚ3 ºdÌVPkR``{Õœ»Åc’›)¬F™`ûjq\ ðØ}×1l6U¥÷IO‹]š,Ø¿¡»˜ãä4B}>m5Ù®¯eÐB?+äv#DÚ{›zlN§2“¯NNmi†Má;D\ï£P:ÀÊ#óŠyÌÔCµ.»¢ l¹j£Îˆ²xA£‚4­íío† ¶Ñ•¶\*0 ¤5 §¸q¯+¦“Øø‡tƒ<ÄÆÌXÚºÂ~}¿ïÝí§tÝOÉÝwÖ㯕tŸ5¢œc•[¹9zx¡*sLžuc5&ª½ÖV£{kˆÏ‘Žô.çKìy|sq$ÆaŠëœm·¯ùå««Rå¤KÁaô7*¬®óì· ×X ¿påA¢ÎKàÒ¬§¹dï­9dxXæ Ï,ç|š÷ öŸo$€ ç¡;¾HÍ’9zÇwžËÓ'÷äáÕO‡ChÐ0’‘ø=Ù0Ru8LÌS¿i-TÌÓ˜¿IÆÈ‰ƒ=Sû”XÉ’¿ée¦¶Y8ᬗMmÍ„ßqH×H¼­jz×gÃ*(玿–xÿGð}ú`ßõŸŒ‰ †².àDKB®¿$ÀðXp£*”LA“Öß6Œ¢~hþ/âOúØÔÿŸ‚oæ¿Åõº¤ÂxzWÍ{ˆÆVT¾C³ÁÉåWšqyÕúFûåéÒ‚vZÉ`hâêTñ˜¶ÚÉSÞ¬óU¶Š“ÇÍ™Ž–Â£ 6ºã:ÕO:…õ•„U3ú,“ý[¿î k˜0JKµTNÞ?Õ3?.¦Ï›~*±RÍÍm½×èkc¬~z Ê~¶º*!¼Ì$_ís{v˜‹»EòßÛbƒ˜ªL ¥1ÂåJ2gÙË™09M ½áŒL &¨õçë~`÷õõ¸U†jý˜k·+Üš'Úþn¤Ò÷°lLkiÜ¿vT˜\Þµ]€³Vš¸,\];cͽ•±L7sºäiãƒvI—…ëH[·ƒ%SãYP™cBœ©™®ŒÉ­þ5Ë:‚§™3$ é³ÁD®öa§åÂ_:¿±˜Hj½å|ü²Ü5ó÷\ïôK÷Z¾u`OÙƒÏëSOvSk)=|hàððÚ/6¬£ÁíÏÖ^.ú;ªžm”î–$×ÌÆd®f+fÊKwŸÈsÊJ⟌QŒV:¨¡—Çš¯ó"Zç:{¬¥w:š£Ç#+.¯6Æ?n ‹‚ê‹–_Ø5¶Rq#aEbmË#?þ…¨í½þoù¿žÜ¯“¢~óCA$"‘ðõ0@FXšL bÀõüŸ„Âã €€áâÌ€¡‘â?|³þãçàÿãçw0žÊi(DÝs_îh;x&æá™=¿²¹Ý̳Îâµ;¥?óÖo_šº-ÕrÑŠ5ÒSTº­­mbD¹5}ûmsR)C`([ÐRúY‡¤“Lškhz7´‚ ~9 ²|«›z#=:¤þnŸÇ Þݸ2ŸÖ—$&ÁHdÅKè—aMZ2³³}Fäà9’ ·ÙÁK…ê·ƒ^f@áÖ·•p$¸‘epB£Í‚ñÝfÓï­´gÐYçôïÁuÜÒ!K=s°ù‚3Pc®ì’Å#PXÊ×Öî×[™Ùö¿p 2(õLôYK¯ëÁP‚œ~G`7.PÚ¡ý`óÓåê.ë´Î>чò(–ÈL, $†ë¼²G¥ô€¤L=4O9aÂzSëN}›”!ù•á3¤ŽŠŸP¥I‹ùmÚhãk®¥X&ÛoâìÚ}½utgo7S"ÞĹ0Ïázþ§0R~=eÏÄî#Æ@:¶yM–;}wN5T«1)ÿîûqý ÿ Ðù?Ž@A`4…p0 ŠÂ¡NðÆÁÐ4Cá!¨“7þÌügô/ù?ü÷þÿ/ÑwüGO[úÛֽÜr`Ã¥QRÚÛõŒJ€¢ÈàKªØ ñ¶q s?º€R¼‚ú;D°Çí¤w T¸ÒÔfpûæeü%»÷öÍ-ÝÌðqÚÃ噕 ½>®„/¸½1kÛW]-A2%½«Ôs§]$m „éÞ;ÀÑßL­Ó8kjÉÿ¢Áû(±—¶É)ÿ±mÌ"®’ÙyëÚ9-_–ή©±¥ËmŠ71׈zÖËÏŸÞÓ/qèYu(dâ–€:JÎ^®;8ãÿF!Yó‰ü¸¶ç®z Ås;k‰ž<ÃUáÄkGà‹FýÏù›Ÿ  zþk—Œãÿ/ó_ÿÊ?€|3|ÄBÐüIžÂâPH ƒÀ1(0Š€À0ØOõÃaÎÿ¡pøïû¿DßíÿÆ©X1ÿÚÿ5à7îbê#SOæn£}D«H‚ì´B‘¬+âuSL=o ÛÆŒ[ÆîqX´gê­G°9‹W>£.‚+ –íÆóB àçS­iIÅoÜe~t3Mx&¶ÞˆìèáÐÜ$˶&Òªš×­\T ÁH|£åÓž›óÞ¾ùÖ"ÑΧ@ÿâ2 .Š’¡7ãþNV,ã1j…È>¤ßL¬¡RUzÂ.ò\k[Z“¯²Šmã1I»aâð Uî"!b#ÞÖᾟ¿[Uy‹Ã;}2« ÖïÌ]A,;»Uh=T!¾ÔááêHXž¥-WgÏWLíÝÖßƘQЗíP™aèûGáÁ¼XR¢ÀþaÄÈ*¶i!*Ÿ©8×6)ñÁ«JÕf•¥uvÚ"È|«ÊJ‚-Ú›’&Ãw´ºL»—rט·g³Aª^C´ô=é}AQ‚>ðÒ"ÄzÝzìÖcJêÆIŽÛÜOÄš nJ F ¾ÈÀIÜÍo"fo\¿¹bîürEÒ¯ýˆ²â½˜WJ ƒ,è)½LL=gŒ`ç[éñ@NO¶˜•bù²œ(l­|Ù-N…œµÁ]ÉužÐ%‹‰ÆpÈ—¤¯È Ì玳úûÿ ÿ@0òý?ÀÁp‡…á' €£ x æÛ&AaÁÀŸáÿŸü¿` ¿Æÿßùÿ/Ñwýß;}"Š:òý}j¯„x»_ªiñ* kðò*ª Íÿ£÷Ûáͽ×g@,1a !°âçÍ-êØmÅò¿÷‡ Rôݧ¸/„¹Ë͵˜•ãWáO178D©*Ä'4ÐÓÅ«+ßÿR©GYäìxNv¶¯`´vrRl³Žvrb´~êÃäØÌS ×t"/‘½"<5GJDüâßú›ùïÐñ‚ÿàG£1 ‚ÂA80‡`1<„F‚0XìÛø þaàÚÿÿ ÿ èïøÿKôþW lœÞ¶_8< 2ÊxzƲ0ï©â+ÍIH-MÅÊ%ù¾ˆ–"™“Š‹YlÜ«m!ããs=Ú‘ÉKjm­_Y[]•¨õ»#ÂðQS3^O®’7(˜ yüq ®&¬[Q)™_E‰•>ðu âuôš¤]—_o¦¹f …e'l­pîyú²‹p‹>äÊêö>ý²Y_ïßyüyof¦‡Ç„Åëh¡‡íaЂœ–Åx}HsÔjÖONÔTÒRL¸[Ñ]y¬‘ô$ˆEh˰¥$’÷yv9†\­åyjvÒñOR¼5Ê W@eOnvå_{dð4 2?÷ÿœ(¿É›6!/TÒ@¨DcZ1¢,;ËÙÛJ@¾Rm¬/ázÏ>1ä}YA‡Rxü'5HA8›ê ï¦Ò Î£¼pyx›‡êR†zÍ“yZ†hÕ§ @¹—ÀsŸÜ P¸ÔæÈ¤kàV\Ûf9:Å5òñK=ç!”¿˜l{†æð.u¹ùX í"-“ÿP»…ÊZåá¡–\Ö§Ú†Øq)†-ÄÞDdª’‚‚}æì€@ÝC÷Ø8{³ÂéÚÔ‹cÖ¼¹q&þ¦«i]P¹Ï€LšÑTþžœ­_÷À݃ò‹rDwFxÄ$‡Ä\\oàrÍÊ.T)Ãdñ˜´ëì'uV¥*æùË ¨Ej ¾RöÒYXC‹+#€Ïj›à+ùávK¾]Úm~ºmÿt”Lºü»!g¢ŽõÝ뛵c[2jQÇo§âõ²ÎÐS¸u ïØŠ1åÔ\TiF辚X¿¸•zëU‘ΑïÔÊMú¤YRìù%.ºxá¸è'ÙÎþ¹âq ¯Uˆ>Ø,†SW–µ)vˆéÎhÙ¬3é,åJœ^7Ä'» ÕŠËó↾Å´0}À¥YER‰]ÅÍ­ú²„ÅC*”›c¦¨ƒ(+íIœ^û$DkpÎÑkÍÐÏ×®épa{—q?YåJ–†CÄúϾuθ”3ÿ¹²7ë¼IyÿûÁ‹[–ªÚ¦ÁÏ Ÿ›Wd“¶gȼN c«ežhĤÏñ½öz–jçí¦‘ûÏnŒÐJ]< Yˆ3ãuO.)Õv'·Ch! €•—2%W0+}qE¥wnà Ü ~â³ìmz¤YêÚQ´˜ØÊüyÑ隯,¢—¬®fãüÚ…€:ž÷±Ü¨BØŽÂðÔÓP>‹jö»usJ¢gê*E÷Δ(¯buúgZwò3¢ŠýCõß$Ëã ":O|}ö.5ÉX;‰½xvå3ÝÆóëiôR³‹ç¼–«×3/5L R†Þ+Œ &S˜ (§hçÌöå#;>O×Gè̎”Ž‘#±c3üŠE ŒÁHO'}íÒ±jÓa¹Š´yÚj`m³WÊK§ÊÞÆ6³ûnÃÈ©jQ­?‰r¥!B­èÂPmôs­³~Ç*£Ôé×ÇÉ&>úĦZDÉ[‡F¸Z—â¢*0Aó_WÐ, uŒ"ª"íŸÖj[ž¡îö”¸¬»Z§:n(úÔ®0&ìxYjØã(;Wµú!{Ç|t YS½·¹—µ×ѶWºG}4÷þÔI"Ì~zÝèÛ©©¼Èá¥<×¶-Š rF¾±C<›9ã©+Ö¨bá²Óí³} ÁL˜FãµƒÍØÝ‚w|uöO‹ÌX9-¬P·l¯Ç x.N>q²øÌ'¸'š7µ"xj$$ë6|1¡gs¤Å™di!“(“ò@Ýœ-L;ZòÁ_–•z¹‹‘¤Çþ¶4eDòf„r¸™Î æ,3Jp€E!.i^i¬ÇÒôØFŸ¶TµìØ2o MŠ–ç‚gðõíën…ß³½lbE¨OuŒó~VβyE·:*Ø¿nw¸·g m~ßuz»÷¶ãXý•›×踚Ä=¤¯©ÆŽ8¯¾ u“Æ †})8¿´~çš.­–T³ßË~ã¨'bsi_tÅ$»J”Ï[^&Ü6iüÚ¿¿§ßØÈ˜²yÏa]0u @ôúκM÷€Ÿd…-{ìÐè»Õ[®zÅR/ó\¯ ÊÜâ¨Â+øÚ4U_ÄË~IùªS9q½ðAÄÅÊ·ü”L,åÑ…ì[$¤ïÒèÎGTS|BTÎ%QX4Ù7>dJÒÕu¬sW™,˜OMÞ?÷EW´nýŠ ‘ÙVÊsíB‚jX°jõàð¶í}ûˆæ0}ÖÌ`)~Õœ9@'V|Žç¦~n^'âY0LätŠuö Ý'rúD®÷èîuçKçö ÔP³ÖßqßÙîBz»¹~=ï¯ïmÊ×(éîîå1¨ Ïb+¶Z©‡ž}/ŸÏcWN •]<Íu¼Ù¿íð§^¬}Ì­L"â‰ÌTó }ç™Õ4ºd†Èšf¤-½®Ü-;ì€òz3¡N•cÛt:yžÖJ rå6-Yy #ˆëÞgj~¶A)À¿)M•ÞwÚ"+Ÿ¸ºycžLÁ­«’™ŸM(I[¹àZ’B€º@yÇð+~îóÞq›!ÌMir #¯S=é^¿JQ# xù.†Uó•°oÃ5ÑÊ Ž+Ô µ§ÕÞ¾‰3ãu,‚º9\!c¦ aª‡“{·£ƒ&ÉÍz8¬ê$·œTùd¥wÕ™Ê$ö%æÉÍÎßÊP´R…\-&–¢µ|×ÑÁ´«‘Ò c~i½ß¼Äó–q¡u<»í¦‘áWÙËkX³ %{ZcFï JHñ’Dzãó™c–[ïͬMnÁF\øØÞUVlM†ªÓð±î’îo¦^‰+æ´&½¹dDxüÈI¼L“¾Äñò²H‘(ãÕJÊÓS!F¥%ó/î¬ôL0‡U¯nØÚÑNs¸©;áo>ÚoŠvF*yÍò~õ~ƒe—y׺ï¬6“¸­j²;á©ÄÖ;ÞÝ©öièô?G;6Ž·ºìÍý¾ûìöÅý†ÐêOaxü;Šäµ&=Ÿ«X÷¶ðµí~ϘÃexö«WBkåÀ•7¡ ®éz-²zËžøÎ‡Ô$!Ú§ «á”OÒã4÷{‚ºFÌÆ§¶e{fl«Bh>wËåç´–N_øÀ›-³°ûà ù5}›3ºÌr§åøô,ÁÒì+ñmÂÏUšñ–§e:>]ÐB¿÷xÛimøöžÐ8/æ‰ÌYºªõrßh뵩(»ÉäÕd«BüS¾ƒerÁ:¿ܹîþ†Q¿›èŠìâ;ïß}¸ðsǸŒy+Ž5©kl”bóÖ˾G×€Ão¿œÝÔ kYµ™ªS½Bp»ÑZÔ5;Aõ ¹oA¸.ÉŽ|~ƒ¾¤äB¿_‡÷•ÛÔô’J¤h{—¾óIÌ»´úc®ö7ƒ—ƒ•uÎP.] b3œgz%#ßBq¾Í\oü8E6WéèY«ÛƒÒ è^»Æ´U3Á#9Xe©öÇ‚ïje^ópòí¤Xcé!ññÍ3ä‘ ¹±¤¤—F;Øvå5`ûÂ^l¸c¼H®ûûÛÕ”N2¬C’oKºñçŽéêÅEŽe"¨äõm,Þ™}S ˜{£€šª³ÆÜTÑ^¦ÑŽ—Õ)ÊR¡¥’«®â;Õ’¸¼;Îgø¶µVëÖ6ÂŒTkÒÑiZõR±ÃÅÝKgáR¦ò¥†‹Âc¾ˆS‚-MìØß´=ÛfQ^³·kM¯²;µGÌ8rZJúJñ©wrω˜ËæB}°VPÎõÍK=Ö9zXŸU9<ÊJ‘½]”®”õx«õbc«ñéñ6"ÓóÉØ‰G}UÐõ7“¶9Úép*-õë¹½o¸•y¦j¦úùuÖö!Z°û¶‹Ó HQ¤˜äÉ€Zœ1Íà}ZÓ NVõ˜qÏôæ$ÇnX7© P)µVO®´)çp›ê’øJ½ôœ‹/‘äÐX_É7ò¹¡;kÅä~G^Íï ,§´PžÝ9ø9þþøÕÚŒ'™×ùLPŽE”i ¼ÝI¶¦ç”z'ŸÅÄ£zªHëðU{™ÓU;ú«J“õ3ÌüÊsO‡Ü]9/FáZûËZ5\MÔ…¸o]•»ÔA°zÓdÂáÍaFï„GÒ›œº{ëåÌÖ=+ôS^—Û²1Uz÷óš}Ö!GF}5;wk0G’”ŠË–_74ÙÞŠP™vrÚz÷~ÿÿüøå¸jÝ˳Ǽ>]Ûu{Íðì~¯ÚˆÁÑëÃ…ØÇï®ÆóÒwòòÄ?²Ùïz¶ëcGyÑ"h¶Ñáig¿»§få¿\j÷¬}ª¸þøTçs1+ño9õÿ~°þG@ÁÌÿÁñ(ÈI@@PpGàh Å`x BƒQPüÏøCÿ²ÿý®ÿ‰¾ëÿ‰’þvÿ;pý@ (+Ør”3»‚©$#ƉR\—S¹ìLtAmÙXÅë9Ÿâ1}¡smS.nv»x]£åtX„ ¨ŸŸ³ÁÝ,Öô–k ¯iy7haÂc@ü°ä"µÍX@ò„5ByΚGA”‰'¶#êUúô 4 N9‘Q˜Y’(‰Ñ‡<˜Ê§¢L1¸¢‡´Ù/Úa&,ë§ÖÝfí‰KfäúíŠtžvlp˜óožö˜?*•é&ôµ¹íòÕÝöð¥i:-Y¿ñéu‚/l†(ø»ú9Š6‰HÙš I×zêZu‘Ò3DC•›Ù›ÿµ§~ÿÐò€þ8ÃñX0Œƒ 4òZ{² €ðƒ¾ÙÃþÿ0ðOüCá¿ç¿þ}ßÿ7­Ö  º³nâ`áuªª)èB4‡ôlàuïx*ÍánúšgV<ðhÝe’R¶)§V©ñ`í è9ò A™8öZ©:?)3w3ï%ËY'Ǿºnå–ví1¬b(éP‘©ÇàÒ–·Ï‡Ý×&ŸÓúæn<|+tb­ %wÛ—[.WÙ›ò+ð½¼EÕ«­~b'L%­;ÁŸýéî'¨_ØÔuþ“ÿ¬1V9ÁÕ :¯4^±;¼Å¯¦R¶1.ÅKÕljtþ•o£j9àW‡•/ôM(R…ËbЋo(ì)]NÍ”µw>›uô>Ãï{»¯^8§0?,V›á5YzSŠïê ݃JPŸv†iXU¯XXoZMÀMœÂeæ—)>½ì=3ÑžDkWªÈ(þ1/Á…m˜Š™ÑñNu®ë—Õ-ÂìaQ˜á„ð!ÂgDõÜmÕs•¡õ„µú`Óõ ÅGŸÞ´¼(º»êÎ’\[i¿CC&Û¸ãñ²"6XׯŸ ðÃüþÆ?‹…`€$üm†ƒH8þ]ùÍýƒ#€?3ÿ…ü™à÷ü_£ïûŒ”Ω§7‚d?x×Ò§æ†ì”¦iOÈ»€mÐ)]1JFŽkÇ4—I½£¨:“œÔÑZ-¦ òK0¥Wg,D’ØKÐ'ò¥lܧ€ï¶ß$©•œ µ%K¤ÞOqñŒÂeZSg b6ãï=(¡Â`3wIm>ÏTjpW›ô¹n°¥Bããä_¬‚Ì9×å…OÝŽ¸fÚ«ý™€rÿlO}AZ÷:ÉÍ÷–/WÇ—éíaA¤ƒGx‘üO]Þ<ÖÞ_»‘=Øô`;Nøþ6`öQŽ],©( g®í7¼™;Ù’Ñ&ÊS4<~ c5.a“ºø5öYT/ô#ä¡–&tøCúÀœÐÓ7;4›ÄS¥…è8 Á‰ÚE:™¬S¬ü»1Fæ½yM¢9_9ò>ú¬ØÜ§Þ·0ö‹ÅÁEÑÙÎûèiOVò*Åÿ|W˜âÿۈǿóÄÂð dù@ Žƒ  „Åà(<ŒÐèŸò@ÿÌ?ðwþÿkôÝù¿jŸ’r·‚Ž|ÿK¡NÂA®¼6.›Â¡¸$>Ré/Yî|ñ¤0>YÓ E´†c©±±eèÄ„è»wïFGg¥'åååI\s”C{XJkX2ž?œy3HPŸŽN›u·HZÊ’Í#µ´$í¤VÈJBòÝ<5½¬%ðïýþÿíúAþÁ ?ø?á€ÂÐP$…ð0èäÃ~ëã…B ˆ“âõsþ0Ø÷þÏà¿äÿ ßý¿¿Dÿà¿^»ëÛýŸúe6² ®°KfpjXUp¼…×ÜúB´üÝ'–d²Çõq ¼UVKé™gúz=7ƒŒÅê_ÒK57Ê7Œ#äúts±³}HË2­}ÅýÉÈrß~g[´‚‹‡C4w—ML¶«Þü² ÊâÞ;ºû^Ò^_†×m?ÛUBæ/&B­SXÑv¥\ðH0¼M^^IÔŒ«|áqx/Hį'¬®nKÔã’³`Ìôj?ÓªåcÌ–7%‹aô¶åÕÊå’+¾êExZ¢ú¥P g%?Ål~Y ˜G“dºm3ÑÊdïTÜöƒÃvã®pö}¬ëc_ãZH3w  N–þ¦t„’FåV¯÷Y¯/Ãt”Yͧ 釿/«ìŠA2.ä$sÂwõ7\÷}¯_iã¿^¹ê' ‚bw5­Ô}¨{©z Î(ë-•®öõh™ˆÕ9æ²HwÅÅF”‹ùúÐÜN=Mêë9kØÌ k÷8TóºKÇ2þÁ•ĵé°éÒž¤îLq±ÞW¡(bêußÄä7¶¢+…)M»oΔ&בùü¹…ï¥æø‡ÿÃ`O’~…Äžà„a± G ¿­4ŠÁ€~¦ÿ ü ÿ€ßó~‰¾«ÿÕzlOêÿº¹Tå¹ÜÅs—xë7Îê´5qrW¡­±<´¡[Ó]™ÏµÅÄûÌÍ\ð’Ó•¢-5ʈÑ+Éïٞל󼌢@ž!ÐL+xõƒÞµC§‹ÂòÂCš;úˆ ui ë9Âl[lyj>ͯWÇ”5•8m(Zkx«©‰“.}Vâ4žãÒ—e´¢V»&ÆßžºäF¦í`hß=kãí#xøZŠÑåÙö¦Fè÷ /¦ÞÙ€’aúp.çó$Ǩ‹gz.š¦Bõ¡bgÓÐÞ®„ù|ÌžyËͽb›ÜNdzõx¶Sл÷Öï¯Z³?ç“Ö© ‘÷|¢ñÈN£_RìéÇÓüv[T±>$¾’M(fަ$ý7ºNYtØËMüçWúÿgý(ÿ@Ø÷@p„F <…Àà¡0ÈÉO1H Žb°‚üÜü‡ªÿÁ­ÿóÿKôþuÔú€Œµ»|Ž47 çÓ2Òî…ν¹¬ú~(ÁÀho|mæ­éÑdLTÔBÉV]4AS|sÅq@¬Y\Øm)iÕ”{sÝ5å´ULF&˜šÏ1_÷¦ë WM‹¤§Ó.b/ËÞÇ™?ؽAÀÖ -¿)Æ«iýZÊYzkfÁ>#yïú[s b‡…"¿qüm“©©Ïý jü*/°5Íð£—?m¾1áp8ãB¬™zêw°ÿßèÇø!!à¿ñ… $ƒÄ¡@4 „ÂpX †a@ ‚C"¡HÄOÿAA?Ç(àwýÿKô}ü¿¥ÔòÍÿsS ?ËÖfB”5¥÷Ò‡’4¿©7‡d¶‘ØE…nÝÖcÛ:,»urŠWÃ{ïþ”]OHs _t¼¹£¼…4e]uxš¦ãY2ZdÒ3dÝ´3Ø—{3äFj_8íFn" é|áYhôf¯E›ÆÿcQbøGÙWÕ’áí‰gˆÈ½WmTeO—rÎóøJ|y’öT(‚$ºÜø ò4}æ;=8œ74npù ë1 ¾Ú'>È5£H"ñ "ñ#üö®G?Òr B›<²ÚµÆ•áòœ,F„о+~eßúŸéßí_µ?Çÿ Àü?f!‹BDÌ……€"QDÔÜh°@ª}€ dna)úçãÿàü/$üwüÿ/i?ýþ‡é*b¼-ú»ý 9½ñ­06Œ±ÉZ•¨[pµ°-¸ò+JQ9ä—©bîKácÝõ¶çûþíØÛr“Qþ}Ô{e ì§cä?gøï=ÖkX;”(‚òXW^’ÉÔæ|¥ÿùeÒ…,ëèÅî‰òÌ_iܻ°ú³Ã—Ù[O ³ŸÖy)Þë*T®Ž¦®ffJÞù:Ó¿Uçýue>‚R²Á×Kþγ¢¹Œµõ.VÌ_* i^ˆ?þþ°GÍkÙƒórží_ýÀ{ãíBÖe6C7bNy퉢m †Ÿƒ? ¬-½ÙL%—»U½…ã@B|Ó0ó|s)ÀØÎR÷e‹¢þ,Á5ÒИu-y"£Þηx9þ‡éþç´ȬÛËÚ´©Ç0*äÈ«‰\T/–§êK¸C|+%ÉôŠ\60›r÷NjtØå µ·‚·V®WFRŽn;8ÑÇÝh£ÝMZÓ`ÃÖ¶÷A°¶U ›S BÕ&è§Þ;ùì|Æ}HªéÔú~ ûÂg65N·Ù%¯`œ.„46_’Õ­Lþ®]±îþm㦠¨“XÄÏd€°{×QækøFsƤ÷#ôeIÕ*ÕjÏ2-•®—ÅåBˆq'°!䱯>«QîmÜ!šÊ˜‹ë>:÷ðU6:IÅ+ÁÑɯúYç8º¬ OìI^µÇÔ¤l$rrúwÆÄñÖº9é~´^ xUgÆÿ)¸áÕÆÍGEÇ.ô#ŒèðåJ…¶ mk›$뜷¯X¶Í0 ‹n;Κby]ØH ¿úrºŠ‡4©Hl6êƒÍ¬::ŸÛãì6ÓK.Vt¢£ìl5ÎÅzÆ!x >®¼ Š o'Q©GŒUY:©¸V@^ö]hz¾ñî–yb$&‰Ž’t§¼+}ûøfIr«Î»¬‹ ÞÜÂçx8¯rÓeð€šš(ú]SÊ~#Ò&9oÇ™“ïцoÍÕõ¥îáW îgÉíC/‰©%öm®ô¯ß2-î.æ Aàl_‡Úp´Â4ã®ë[Ö¥ŒEŠ9ÃòË s•ÏÉjƒïÝyU·vu„MÌÀ ë}ñ×{ÏÞSŸ®²;6·˜ÓØb=Ô{û;9%Ñó²HñÇÚ„º\鋾شP%JÿøBN»`@„îݾ“…aõh±¡”ÖÙ¾Ö0%_$áÕzN#–´(‘ª;ƒ€‹ð¾Å»ôEù^ è•MÛ§‡÷¸«íÞ*«xês'DÊåŸ ¨C¿è‡¨Ìêgß5âÚò’­Ä`3„2Rw¢‹+ª(ã²-ÙJÚúY°›„£“?eÀÒð°ùnÜÛöœ0¹õ˽‹PˆÉö§é'÷¸XFçÅxƒ²œ3T¦¼äL "ª"s¯¹Æyy[}ïQ;zeIZ¹/I¥šGµŽ"ÁFC®…õô!AkFZÁ׷Ÿ{'ÙO.\»À6~™Ù×ί¾MÆÛý‰$ ÷—v6UÑÌ7‹»@‘«Ð±ƒZñ#ÅkÀçÝ+®å°Ãp Úב­‰ís+À%3ÓŽ>òow;?? „žSaƒ…º³s¡yY÷ÈÍëkÔùÛ¼ÛùAÏ©_¯-ªrŒÆ¶ôË6êw‹\±T VL·ßX ‹°‚¹ðù“5’ùÌ7?“RuHw-âÓ9ÓÎ9[—W%ãÚ¸?ûÈ5qc!¹R?ña=¸¯m‡Æ†–îƒñÝ7\jf«Ù.GÞ"C‚—섇tÅÇ/=ëYƒõµ$0ÙGëi{_¾z|Û?³€}ìgkEXà5’hx{ ¹‹#‘ãd£CYJs3¸˜”ÊŸ¬{‹@ Ü·4WqÍwCÍZlåÀý¡²¹ÒõtÑ×[K[¯L¦ðôzC+ü¾4‡¿ïÓ¡ié¸ÎñúNðœíBw³Y…Ó0ô­UŒò½×drÛ37’E¨èw¾L\æâI˜ÚÇÞ&vÄÇŸ¦+¸Ü)z÷ÖÞ]¿0“j–{r[çÀV!2äÕÕGY—/:(ÍÐu˾Â+‘sÄSÝ µÖ/½­)À“ç¸,CÞõ®Ê½ÒÏ|\NtÖùÊ¥óÉ”Š7ü_S¿‡âí, 4¿QœI Ðî'¦;>ßGå8µýÈ¢à\AODA|Å>Á¼nEšxR¢­Yl5jTÖ!¶ôêºKèöUéáÃÑc]3S„ŠMÑ2Þ£±Î‡¯ÚE>†ìòM²E‰ö 8‚¯ËÖ”–¼åNïÆƒæ=ò|ÒOyCÒ¨UŠ}xŒšãqãŒpÙ‘¶»e¼´ä']÷4ÝÝ™D¸U®˜n »èkü­µqᇼ _>Õn“çk§(½ó7-}œqI܈YV1_±)M¤ü•FbšdSCI Ã(^’hF¥)½à­gçrÞâyZܾ&ûŒ¥°v­nrõ€¨qÏÖ{AºbŒ¡»dlß6 'ªyJW}mB3Ÿ#µ¼õv’û™OëlgxG›ÚÖÆ5ì ñs•O$xÀXKS·o±p -­péX*ÀÈR¦K\ Ž¿ò½Èß–ÇãÿÈ^˜é]LÃ:)“Qc×|`d´å^Í8öŠ’¸¢+þ1¾µ]»Q^ED0Á½íBxSœ.Dv¾DO—œ·åUqŸtæ†ü³oKͰ8ùØsW´öèŸÆ—Jæ°Å ÇÇÄfÕôê‚-n=‘{Ô¯Îe éJw¿}§¸Š”¸ä§%O²¶¬)]Ó²Î3¡äY´ñÈ>ç#`üÁø@÷Ö®UêHé&.%#R°˜Ë<è#|½’—šsE“~ûk̘fÁû6ü-ŽO6wi"µ†»…“|˜*‰=·…nÏfI=÷×^žÐœ´zµ$SÓT«lY;dZQ&¢ðà›É«U8I~zó‘Ür¥ýWF¦8Žƒ¼"o›B\/wÁ>3®ž£óÎ{&Û#Ep‡÷ÑÚºö×ïÐùwœßo>‡vB®n_€/O³³É”Üãz©¥Yö\ñõ’Z[w<þ×Ýà’—ôWj‹ˆžÄÏÙi%^?Œ1_º”êç¡Ü¡Ÿ7µmûšÈ õC /:l/~«ttb”l¨šQ—[Y $¥ Iðã7«c»‰WFÜ‚]æÂ€% sÖŠ ëÒâÑ;+Ðü’µƒ£a$ޮК—dCÛMÏŽÙÊ%¨º1 ,{ƒ)Ò§åøÎÉ]æƒ/BýíçÛXpƒŒdZÖ׉Œ¶Šx.ÄÞ;‚Éù8lc4š4.ñŸã°~KoâÅ\3H (›I®Á\Hr ¤œ9˜—Jà·Ôóß:VZ¼¾ÂBéºöêúR¦È›°X?¥ÃNÁ;Z\ Ut^' _R¬å¢h‰UróÃMMÓÔya7 /ÎsDáøŒ‹$9èòX.6gž§}ØØö€\Ö@Y•=®|‹¶Øôc,ζ”âvÂ+¢óÃz#ño-³mn=ú¼ûõ²6Žä´ú!‰«öW·P‹aÄeE ³Æ¡a]@m¤|e7¾ÞT ·¨¬&N†5,KÓ¯¢ÝÄž>·qçù­¥óÜñ1ŸÙq8TéÚ•š”ôoj<í”®â³Ý •ÓeRZÎ4Ĩ@m=–B™ZJøË#ê®? Ž%[ÓÄ<¹ÿ¤°QYÐ),„{/C’Í~ŸùBè½âœÀ¯çu ɤ@ø¸ËA&K9îΩø·™—yŸ…jU†›-ôÞLÞ Æ•ë¬$\=T{¹°S!™Õ¾ôqÇÂcírFOkÑqÆ@ά†àuùëbbß?¿–Lï_¶îE¼#]!ô¡¢¿Ñz<±l-^^ýx©rxHÍc?,m*óaz{°‚ÅJf:ÑáÝ󛳟Æ<ØxWˆ4ÎSÖŸlúEœ ͱ)]ÊüZ`(Lÿ’lìÞ7ë¨î4€b¸Í^µä’†$gðÆá‹0Í×åºk»|ç?ÒÍ"{_øK•HŠR»~³ºÑsÞúêb(­©?¨Öè\wœ—"Úâ*·~œ xódPÔ縜Ç"×`¿Íp‘®ÂÚåsÚΖ¦Øk§´Ïû:F˜Iïð¿À-\Íp«™”ôn#çä ß¾Á÷®›Z‡@_/Š}àdÇ|¥÷[ß“‚¤º3Xâ“s`Ò–a˜á6UyÝXT·)J÷÷Íû "W‰ º=}%Ö†(°ˆ`qÕŽŒëÐ1 Ù4åöí“>.«ˆÄ6ÞÙlz›”ü´z&¤Öø2–3>ƒ)I„—¾|˜NlãÂñ^÷æÛOËÄA#™"ŸM‚ÔŽJñžS® òpôæ]ù¦Y¯ævS%cðŽâÇÉ{:Žú²Xl~9|áì¡‹»,ΰ*ƒÄö÷ŽÉ0S×ûDÄ3’²Ð)­n[xL5|‚¢€é Y‚tÄT£4æ +ÖºDÙóôa<|ÿšäFÚ§uâæ]a/ñ†§¶‡OR$žæ?|ºœó¿üu¿ÇápÄKøë´•hÝ´Ó,5Ô×NášäµgvêÎWõ›!ޝG{rŒ ÍvV—uÞ^òa ^¡ ùô!ë8ÄŠ–ëηö]±ô+>õF³Ï{kiåjZ±Ä6&Í©¼<ú=Ÿû_Æ2¿¼&2PÇ…Sjóɔޟ·LÙ”“üÒúÔ1“¿þ^+ãɆÑ5ºƒ‚ú ³Rãz¼èl«JõvFyÙÒyòãÙœ¨ 3 “΄oõÂû\žÜG°×©‡›G•؃çi¸bEÑÏ·ÑÈË}&j0Ì¡ ªÒb”ž}È;v¸º?|ƒPóˆQm31!áièÍyÕCAÃKw•eë ‚G9%ïí±{ߥ¤5Ò¿ ¾®:kŠ ªñ9‰ºBc·>d8_§)´µþag|éJӦخäVƒä•9иm;/éŠêIÕÊ6ËàÑ+Ëuƒ™—Á­)8ŽŽÕ&ëMŸO0ŽÙÙ¬¯Ã€WCt£íyÚî=g3½_¥¹G2ãYdâÜ!)Þötû¸‹ÿ{T룆®¹]§taßôùÛ!ˆÖ)ˆßj§ÉË>²øŒô¯Æñ2oÖŠ?0O®_˜ .><÷L¢ñ)Ñ‹¬çè¯Ç~wGÖ¿Ó7Ø=†U_Ùùv=iŸ}ï¶¿»··žYtxø´¡áiIÉÊê³ÿå¯'ˆÃÃ2~…ñïQíŸ÷rÓïÌÏ!Ò}äïìÙ~›|àÝÍ?#vùIˆ¾§Uª§xÅï¡B=܆Ï;——ßîÓtñÓ×N®˜,3N÷XýÏ[þl&þ' ýØÿ ZX ‹ˆ€€‚f Y Þ.Á„`Pˆ(ü õÿ@ øñ?!¿ßÿó×´ßã]úðq¡Ë'ŸÍœÉqåž:ðî¾È~Ÿrû& ÙÇ” k1ü ;ª ßÊKªÙ*ÚÊuÌßýWZʘ…o¤[ÆK&Í¥gøx*Òg6É“¸|Ÿ ´¨.`¼LŠÍ`‡A|3 @¸pùK)ÔåOFc9Ý_º×m^Õñè¿koöÐî¼ÑøÒYÜ©œN\Pû‡,•3ÑQ‹çŠðw>‰Ë›~—mTIFßnÞš·\Ÿ ¶U«…ûÈ})" =˜ìZ>Ʊn¡§É4ÆWXm`ŽÕ|ç* ù¯`~â¬[·¬÷>éNßPâ¶Md'Åúgú[Á°äY8wÿ³Ôü©‹Fspú¡_hݱˆ“S»åçûKZØb9‰XwÄÄÛ P7½Í‘S" LH„7®Úµºb¿2ÛikvRîJåÖÙLÓ4hjŽè~lC5xÎÁ'3¿k­Q$ïYûÄdEþ¦úK#£>Qüã·Ü ¡ƒºGÞ®‘Ž€ì«2;f£þž«†º´Sn$Y&3`X¨Æ29ŽæúPHMíµÚ­?W“ë¬užJcàŽ[’wñD\ÆIQ8{W¼»-ÏÕXç±¥ŸjÀè‰?¶eíEVÀLâ{Pã„ÒÒ΂©.ÃÍÛ“-‹}8–,YФI]}W¤n[>€±Œ6èÜÖ~õ— PYÅ,¯7º­_V­|»˜õ0Û’`ûŽ%{€Që˜ôíáÇ j·‡Þ/ÞÄíTé„s pC>ó póOQ$‘[˜ÞVÓ Å6"N2Ë­}ÐXgs|ÁœœŒEö?+$ÿ/nVÿäÿ ¨9XŒÔç‚ A¤Z‡ –ˆÌBA€Èû!‚`è—öÿþ)ÿÿ½ÿÿ/iÿøþU½Í÷jÝ=Ê<úüúJÝÊzmÜíJÊ<*|Ãê*]ªÝmê<ÿ²C€G72ÒœÜE:tu9ˆ ï=Çy`ŸÚÆVút” qŽÏ½t#æv þ_nŽÿÁ ïÿ P ÒÎ " KasA°€(dX€D P!Ô ƒeÿï?ïÿ þ]ÿÿ—´ßùßô¡†Æü–2 [7Æ€àÞ«¤3ïp˜»¯X²N?•ñõ;beùoEdš]Ñ.{bíDã“b~³Òä­Ý–#÷-9¡ðŠ©æ—så?6x¦ÐA;*ø ®þÕ-U©F«k¹4=zzIÆl° ÇRð0öÆh›ªr3ü~ºÛþ23IA¢^¥ OÍ>…Õ±[òañMSáy>ô5¡¬'¸4¹‰ç{TÁaûÑøãzù@zoî~냽‹w#Qx’i›CªÁ¤·:ãw-GÛÃÓzD|NZîÁ÷1ö5¼þÞ/øÏíOñ¿ˆ Ä+*( ó‚¡‚` ØF:ü` …9,$,",l. …‚!" !Ø/üþÒŽø¹þŒ®ÿÿ]ÿó—´ŸöÿSÙiLTï^{=Ã!g™Lm]Ë­w_:¯W_©î­ì·æe:óh£V¬7¼G{>QWÂ@Xy×HÞJÀ¯dÞ[†ÅYq‡#C—‹¾D)ZÇî˜T¾I÷p¹šMÅ®w°˜¹!,,éØpç»ÿö¬ÙIßêÐLnu–\­Fí‹óäó9e秇=}Wœª}ŽÖ]öÆ)÷7k’(ޤ„RÚƒ…e÷ß±<¿ü}vp§÷!xjQeÏëZ0^Zºd‡ŠDï…#€w¥¶Æ ~ÂQ="n\< ˜)'AA8eyœ,Ÿv–³>y! ¦î7­‰çÇžåêë$ž^UeòÇHÌò̯ÏÕX¦ðr_}uùÒÀLÛuP×ýB’'ïýï±>³ãÎ\Ò¤1g¨?¸ãËAca[`Å\&öIs¹¯zèúd»UaÛÅ× ÓùúÀ¢1Á¶ÎÞGn®¸Ä;³)öóÚªöOeª„/K d½Öïèº÷ØòËÝHóK¼”ø¯.³^ɉ™#œ¹© ÔÁ¿ìšÎS[7’³Óí(äþzÑ9[äU~–M ¶TËû•†±Ùv5°5ùç²Gˉ¢Ýà77ûwä'ñôÚIZ¨ñ<†ÖñøžÐZš­¿[?JÆ»™4ÜÜ–”Y¼@bŠwóæ&yØänH–Á’~£Í8Óë+köKƒóXa¸øë|R¥gñnf&x¢Øj:¾×4÷ocØ?¼5s£Û9lö+ Ä» ,b¾ ”%­yMÅæº”ÓB¹ÄàÂÇT ;&¼M^¥Ð'x µþ\v;TÆI,yú5åH½ÑPvzúý[IÙV<#ïKC Ú ËȘ3sîÓVfNä6¶~"yJsF´¨“ DÚ#ª2ÏWŒG ÚIú僜S÷j2Üñ-.Ö?ƒ§W>[Åq#½_u^µB_YIÞë›Är=jøÃ'[ÿ|qÃ5 QË‘ÎàûMPvˆ—WI`aÁ¹IƒO*y’ÕˆËïEYMŠO >¨V¸ # ð%¡ºÊÆGŸ• £í•ñǤpïÌ»ÚZ¦¡F5Ž}%[þK‹Œ§N¼/õ$çÚƒKõ YîözÉn…á [éúkƒ14X—>$W3ŽÅÝáÿ¨/¢_û¤p·âAO}Ÿþ~–Åuf¶qO¾@ù· -òO¾MCïõ\só#›))Ü/æ+×ô4…ÑÖ¤^¨ü"Ö×°T“Ä„¡©Ý»ïÔø„s<ž¢ö©iÑ—÷‰9™FH› °ä•w(™.ñaÈØ—õ5Í䌄OÊØFÙÁÊFýO¹—µ|Içç…Û˯f—'ÇY¿÷?ác‘!›L=_JªÄÆK->GÁÐÁ7bT¢WáKX–±›šOQî~‘[ÍU§ûÞ&:ò~W‚˜ñ{®6êŒÛ&MÛòÜ`9}×¹§ð»R3*ò½ú×72ø±«ÊâM%ù?kØ×ÍÓß}c}{b†Ë¢ Y—DP0/_é™\~еQßדEJ£1ÍUóYú87ðÑ>¦ä–£‰›£¤ùËÄË´Ú@+¼½ö¤¥‡Ìçm…z°ºê…ÆL¢°™ªàÞéð¸B¢óµÞï¥Ê­#{ôdëm.\ Wšy‘W¶ž•û¡Gî7Í7IºlÜÑöw¢ƒKÖc''ˆë¼àp‰¢uø FCn9—M Qx3nº£”Ö{J²n­T+ƒœUK¸Z²÷rîX®.Ñd?q¸8¸Ö‹e:>äO¿ÄƒË³&iÿæ¢ûݯkKnù i»WÃ/™Ä§{oôºvõ–6é°—= ÐxlÆà;$ÐS ÏÀÑ4·ý&!º“+Pw“Ì4·vŠ”(žSë^~÷Ké|Õe¨‡÷d}ÑÝ0=6àEY‹nïÎ-š›A¼!ž[ï3;D:Bh?yµmâ4xÑ”{dd«eÙ+N¾lwì¾Üñpxë4ô®­u'†?¥6nRw—~ öcÉ›œ€ ¬xµe£¦YF"vWE<ØÖø¢qø‚¬‡:!°¤ÙवLLìÍÇŽNï%üØÄL2¾è j0¬N¿ú!`wðräõ, <©á9|qáÞõêuDhVÈÎ!Ô÷óV>ŠÞUñ¦CK0ó•×®«,v¯Þg΃B©™á†VËw¤ceüŠW²=·qªÅ¯¹²„_ê]VWÍ7¢>g;ÈdøÉÒ(OEüÜÜóv¯WZäËv×}g«Vß9.?H¥&Ø…RW§ò±ÃË!#Bƒ8oBYÇhÛ¢rÜ Ôo:¼´½<·jÞ« ûrÿ3ß<Áç™Ï‰û¸Š/^EÍ<Á Ûìè÷¯ ¬ô÷ÝU&æ§¹nhØŒ©:ʦ`®±GÕð¼Æ®™T¢êÝžÝc»ý¬^5¬U¤@«&?èm ¿:ùßòÍ]K‘úŽí/'ÕÏkDF%A÷Ò–ÏoÐ[š/wöÚ ’Š'µ»’SÉÿ¬à)þ^“—÷¡ç³ì¤²9>Í8:öø†{´Ÿ‰2 (¬x¶É‹¶!ú.ÑçRgÚc?o°]Yë¹øÅHõ|ßX‘´Í ~þ"ƒ]}P’N"µ°É‡ðT(_²%…7‚ººpO$že(Æ1cc'›øÒ¯¶ŽÓËÇ‚1ƒv…LN†4(yŒ;ÂçòÊ\û·Â°©D³¼Ã9<~¿9¼S?L à×GŽØ)…˜HYÍþÜy½²Ã—¶¾¹Æ+Öe4Xçá+À÷e£ÀϤ}°7Žž™Bá“ÎUœ>îô¸/Ù48UÞ²‹ˆŒÄ・Z¸ÐŸ/¬ÿ¹lKÒôð³Ñö¶ÏT7æFz« <6Ÿ_¶Uuaƒ{‘~M©ý˜*íÓ·úšGœMǹzÁÿ˜ò|]ùÈ[wrImçïXøÓ]]Fßpma~«UŸ©ú°#„O9ÅJq…•mn⃮wK}b¨òÚɹm ºØÇeõ'>îZÓS¬æ{ºŸTÇßîØîøŽá¶¾ìHõ?kaýŸÝþœý@:ä¿ÕÿD-  sas¨(P¶ `æ`! Ô& X–¿Pÿ ú‡÷‚Ñ¿ÿ#ðwýß_Ò~ªÿ×mŠBýþçyQ؇ÀòÑ ©Gò6av¤Ñ¬÷r‡á а¨°‘™RŽÃ ¿ÜõâÔŠÖÃÛÛ’…7ê©„‡uûäò6¬­ìvC…Ü­ÞoØ«_ùHzÜÙú hö!ý¸ŒÞäZñÊÖ§Uþª„…7àŽp8|òõñÖG¢×W´†RÞÁÑ›&[Ö>Ö¯ÄûÇ­ãªï-Þ•+YåþBèz¶øÒf•¼Ð·6´|hMö`ÄQ‘éeA÷N¾`×H¦êÀˆÿÒÚ¡€áí!!×sÎãÚ„¦Ííc•z{j´Ö¿%e¬½`ýbæA•Ý7 v·Xí`y«ëÚë¿×$¸Ó[£8ÎHU9t—ßsÆýÚtœ_·¶²´á ‘¼Èw3îb¦Ý!{iÆÄBçw‚¢ãs¬²8ù /kï¸ åºaY^¾Òw‘³²UW+í}ƒÃ6§k‘GüÇTÇ#3ÝÞ/ÍÑ rÂÇ{’¥Y±½ï†îÕÛܛޥ¾ ¾µ;t[ìæú!åö›6™¯!^*“Ù«ï3kt°o¦IåÖ—f͵ÞL#©vâ &g³ëcû°@6Å|'ۣɻC“¡Q¡&ÚÞ‰þó”M© ÛBobÍ <Õú~Ûöµí“—þX×^C×?ž<á¤YNÖÌ ¿V! áù,ß¡“ò\©G„µÅœµÅ5ßFÊ™n˜1#øA[MÅT‰üÁ-@H¿Á§Ðyî™LÊnù«3(¦õÝDžÏ’ä2 0®/6jRëzû8HYÑ"Ç Qá×RÉ›ml̤Þä4“—Ò¿Yz„¼}¦ŠÇöR©#RÙ8ÎEkz}¯C;+&2LT£uéaÆÛ ¯bå.Ã?– Ó˜{µqʤ7’oÇF~Ó—¶âºªQA¹CÂ*@„]ž4ÈŽ)-8“):'P^ÏzNïH'ŒgB»cÁ×­äµGŸZ˜•š¶ŠÄÞsH» ž©íl¥ Ñð÷>G³…™ܺÏuÅðºf_ z·§”§‚=+W\7/Áüº9.Ñé<µíÀ´Sô…—…¸Ú¤³]pyçÌT_ØÄ»à éÄÛç* eÖ© šiiÞ±ümµù OÈŒUÒ¹ªÂÖ‰ø¦ïáÖEe5®¤n_uVä©§Ì8थ}üÖÆ4С}mî@ätˆG=Cƒvþ/æÿ?%ÿ…ÁB`áù 9ÐB"DBBP¨0j €…¡PÔRDXDf) ûó¿ÿƒÿ!þ{*ÿ…ÿ–ÿIû]þ§›Ø!ÆÛâéNÂùüJã˜E+c•³……yW;,™up•Gµô¤Ê8™11øh…¾|ùݯÇÏ5§éž•P±š}´ÔÞú7ñ½¾ÃgHó²¼Ï;ãøï]!'úu)™¡Ç­'[W¶~Æò“LJ‹SßOŽÇ«îx};9þVuçäDcêûÁëÎï®Ãn'ö‡S¦?JF½»ÒU{cÃã5hÛùè¶aë›öéá I“ɨbüÚ¨ÙïØ'¾¥yªu)¯‡kÀþûx®Þ OG>{Âþn¿‘M|-(œ÷ÒÒøùÓ¹ ùO¶aÚ°bêùÊ "ÖD‚¥ñ§­§vŽýz/…„´âLFÕá·öÅàS¯}ö*÷>Á§’ï-Ÿã'2³¯á–R^éNH­xºÖ¯bt—1vNµ\ÍT/ûUÙùžî҃е¢7«-ºvu)yx©×ìZ²'GèȦqÊ ÙtR$“+²¿ng•ÈKÜG‘³¸1âb6õðl7u—,t>åè:?H»H-õ·H5Ó…©\%cë“]¨6›ïZ=y÷k¡ø›Ûx"˜,ú~|%J:޴ᦖNØ;¾¿ ÚûJçãá]åMw9}!¾+±lT'ýn9¶Lj2|]~ÊÍ;cíQý}]ƒYÑ1¡´‹>½o|õ.èŠé\[RÎLŠ|ï°ÉÎ7êR ¨´b(屿 «W°˜¬¾ÿ@ô G»G~£jÞhB‹N²}çê«Çy«¶¦q„icR,›ÐƒkÄWŸˆeRÐ>ÛH×î> À¼À“¶!v½çËÍUºÑO[åy5ÏìËǪ̈¶ -£ç|'Òµl“¾«”ÑEdó¯l»9 ¶qw¾¨ñ@&½Í_íëÅóªŠW?vY‹ t÷¾)‚¡39TðqÁ˜*B¨PéšX½Û昨Á«e¬€,,Ü®.­ƒ·\ÒøXšžRÚ;ö“ó:ÞÒ©jX írJ Q7³ŽeÒ;¦ÚV­¼n4Â5?|2³¸dê­_™—èyÅÖZj^fiNÏ%vÜ€i´ü{u¬Ù†è=Ù¯xüxƃ}ý·+u˜ºp½kÊ"TðÃè3->Í ÍXÛ„™âõ³³ÓÞeÙv]–vn·!Vuè®,ùÖ¦-'^Xå“P‚KrCÙÝä Ó<§&(6Ñø[ã[ÓÝºÃæ½@ÙÙ0ÞµE›ýBo6c㑱eúxûξ¾\™²÷®ò¯žU7ì&BË»6“$®ÒüÃl[iÞ '<1ðæ¡^G«¥°¹>÷–>XüÎÓ§¯+—êF?³1lš€•s«ü×ü½4ª¶º£Ši+øú}Uoñ[3QÐH‰b²:Ì7ÊÒ–P\Kð4Ò¢?ân ¼?òt@ÍØ¦WòÈVõYqò9p6»_h/+'}òàÞ âüRùân¸“$tw’GÙ©$îɵ2Ý´0¯bµ{~HßÊAa]—£-ÑF'"/Sz©=Šž[¼”áÛjS–Ü÷Q‰ú“g»ÑD狈†ÀË¥Ï63ð€ÄŠ©”†s©^Î^?^×ċԿ@|ŸèQYÄ»EZÕñ‘NåÇ#lNCì¸×®»1ñ ³i>oÆ-¹¥a˜è;WÀ‹§ÄÖû„b³&oƒ;¼¥WÚ¥vÍàV¸k» ©B¬/‰œH Ù5HqØ l1åþDW#R£ü¤rŸhSÌϤmB2øFŽDÔŠrÜ6…³ãŠb\>Àqç[êŒ$m¥B•·òS9LJÆR͉?.ʳ.䥕g%ÃÜ”JŠ' D® {:¨¦\~žŒe .™§×îäî8;¤»uíz_]ÈÝP=éMͦO%¶¾×ioHhtÝöu(þüîCÎè’£8X؃4g©Î®Xq`êz e¶”¹Q¬(œó ÑÝsÜ*Í ß Ð8àŒ ^"ðüs࣫s".GpÈÀËå†wr¶V™s–fcÒ1g¸«§DHr‰U —?}u¦ë§üœù/ÄêÜGе {枤7µXÄÎÓߥg&Û‰Ôi¼mô²{Mµ Æ} ~0ÒgPq‘ß|€R‰ðÕ»÷º’Ëç¾*‚·ã ›–KKÅŸ×éÌ;ò:TÊ·6>ÁZÔ"‘9‘¾Ç8u…ûáv·ö&멹4“40¨t¸tkýˆTœÍä ®ïçPakÕУˆçlm>d` ÍþéxÁ¬IåžßA˜Ïd]¾Ør¬ÄÌ—U¬IZu_6ì6¬½àtÌxwž¯é…Že¿GŽFèS‚b °Vý>cw¢´‰iM\ý¹lž„=±ØG´¦ÒZ+GR˜+%×9ÊÞcŠß"$¤ÈÈy[rŽRˆñuÛ¥üOÕ@ë÷›¦º'&‹{÷<*nbÚŠ² nZÈMN`•_{£õ°×#ߟœø*àjÜÙ'!Á‚àÃ[Íy[Û0Ý»ùåѺk–p1Ž—R/€ýEú‚=?­Ü}š•÷/Þ¦íUËîü(d:(¿½âxÿ£8u¦}ûb?§ËçIT,Èxgx5Ò£3,¢Y—Ï?ÇøÈÀà+Ð3ìØ.¥DN†ïîý%cãÁ#ÖQÞ=ŽBcòµT Z\7‘[†©›ÚšV±ë¬.IkìÌw×®}¼¡Y¤ }k[$‚GI•„õ|]¸çtà‡kn¶ë¾o©ók`Oåd˜X†Ít˜?s¼GÈðH7xˆƒïûŒŽïà ½°Ia•\ÏGâÊã[ÝZ}´Ý<Ó3<ÅŵsÛÙÓ] rŠ–ìñRÊ>À¯)}=^PJJ^Á˜ XG~!f I8÷þœÜ/:H„¶åðJñ»«”ê'/”lÙGÏ%?ŒÝu."ùµ»QÝÓLž™¶ù²ôojñ|J ›þ6ÊË)¶YâC{¹DJ=V¡à–ây[ÛæØ7n·ˆìBí`äæ’w®Rôîúæ¨R|¢¤.¢äVÉ6ÞÄógés 11pÄ…ØgÚÔØ'0™ŠáPŠKlŠšxv^‘›þ$EHoq÷j]\ Ñ"¹î.i¸ö¦D–S³Sƒ–9'>kÈqjîŤÇÄ7íq¡&ð(cÍ%<öÛµcÛZ&’Ê“ ºãÅÏ6e¸)œ^eÚ3wO»¹+¤å…DDZ¹yݯ t™z·¯Ë’Â3«â÷þ+¯Åy>¥äšÂb¥©¦7VP†×šë¦àsF箚¬(0ÄÓ)æV‰øÅÇÆïrr&Þ'y~Þ³½N›nO¯ŠúֺƒKÙ vÇzN9<„ºÁ³g˜±nØ0}èÅí"P]É>Ç)P¯­Õˆ¸‚ürÁ7g4b›™nò¦ ‹6<Û[É=n^ë³¼Þ ЪöbaÒµpŠý霴˜]o%Z—;í¤€÷%ÏbÒB ö…7àWKÇçˆ^ð--¾­#3Rç &gí.æRÂVÖReqéêvn²5Ò9¹Eæ…Ùͧ¯4lî=,½ƒyC†uÌûñÎI ¦!à;%¹o½¹É ù7FL¸"¦kðW¶ý¨BO8<=ðæ&‘n„mìáÅ‘Ë,EM˜Z>ªOÎÑåÊdÂd!œCvQ±´†¸/ô6û5« ‡«öëINˆ>ÕðŶe´½&_¤mr»Æ<6޳3k·%?S™Xùîø…ÍRÚ€ª7¬MT]ª1yeŒ"‰Mp“Ñòu{m—ˆ'ÊJT*¥‰#nä︇; Ùò>›\ Ç\ñz„U¹³oRCÉ Oœ­P’J±ò%{·Œ9$GÐ÷Z¬ ïñ½ƒ*¹R‘ô¯½ þà^j$™vEë±ÜgÍÐ-©¦-ŸÅ¸UNíÄó™ iÕ®ÞW‹#Þñµ¿¦b·ü1Ò²gþ‘ÜHwÌB'ºwýj/ÅQxn½ã"×´x±I´¬ãö]ž•ÝÔÓCþǦÃ0ƒòqèÕbRä}çƒ[™}³ESL®J3TnîŠñ5ßëëy†cð†ü·øß}û|Wx–üUzwI(¿m7¡ ¶3Ëu/ ÛˆËùÅ™ÃÑ4^†”ÈvQ\2üJRTfN•Ý8óàcHÌXLÜG.5·.Ã#ï5^±á-,;†©™ßh #ôT¼"M³R¨Ý…»RÚ‚AEPôä¹Aâä}ÇýÙ`/‰ßƒž¶NðÁA­`e匢…Uâf±úÛ‰]Áµ5Ôä¾ÅƒMIL =Úù#Ľ&ºpüuIIÍè„®»šŒÂBäÈ¿Yk`ö+¯”~ºóLŒÔ,6ïRŒù§=f™L†w\6‹•cï§MTÀS\”¬ýZ—Ý›.çMFÊÅcâW¥vs_ò—‘Ò½ýt¿J~!ˆIŽ7 T:¥w¨Œa}¡9+8 .Ã\­£™“êÌ–]Ó±Gƒ³h\'nÚóú‘1ñKqJé;Árx­¼Føž…ÝCj’„_¿/sãv}:C3Q•jƧ°ûçΊêv¾Š°¾sgI°Ù5wr›k£±)˜¬c“bõ™A`;ƒ›¯c¤)JWÜ“)¢›qM£’z&UìbeþÕ²¦úáO²ôúôLU žƒ/çP›è¼¾c!óê©„)æªÈH邱YÇÎÓå‹9¡­ûßqÚŸ•*­Cå£\õ×À¸ÃNL2ºBo`ã\œûþýi¢†ÉU2RÖêþïù|ò–ÕLãÂÛ~¯q¥LŒ§Ru™_z~+*ª]†nqµï'¶sI»³ˆ¹³ð¢ð\_#æÞðûò˪çHXô@_õ¯’Î.hÊäé‰wð¿ç¹ßm»õÍùûcMì 늋) ýêéMŽE;Or!û_r+.]ì:ÇšhšÊ$‹—å’%é­Ñ×ÀA]äÃz.æ$"Ítï #»{§=ég}L½Fä»w Ò—^ÔÈ´ãhà’gÕ¨§³b¾ ´T¬–¼ì/CÑц¥­.<ã+§¨¯Ì)•¸¸EÉ\ÁÛR$‚ûÅñþ<†©¶[ÂWáÓŸn ÚŠ=qù”i—J¼›à›²ðÝ ýþ®f¨Dz¸æI96Ÿ/å×w¥’”UÂeïjÆ=­(VÚ<œŽt´H¡ð}ýEIDÎÇ#O‹åÙ(ã–:Ó2‹kÚ]A÷m >ÅVxмÏ2 êÞü\ÁÓ/%yû LªP*wè†f#–.8QQ²¢ÊŒ=¯˜…Æ/¶¯ç°·/SÅ´¼ÐϦ¿tS;ÄñÉôŒCö>L¬J ðŒäýÐóT@¦QFeãv× fÁž)»€ë–Ü+-¥%3›üÇs|ê¬ —åÝ,JŽÖz“?)«¸}•ç qk=‰»çH¡Õ¬8{ÿËð…¢þáñ^¯’y>sCfA^/‘„ÖæÈ›å»—]È.ör‰a»\y¤ „ ²E:{.>‰Ö¦Ûy¥D.ݽûœCߘa–Å܆Ŗu“cø[2b³¹áÉõÎuOlõêS¬V^­M~¿©ã%^¾µ>Q°$ka$>M¾ªªTû®½Ýìý‹7¨ š¦!±ç#*YòÙgÄ"¦¤ypÎV@¢ê†,ÏlæùøÕºáãM%ü‡¸ø c¾÷úcõâü£²^&Rº‚Œ<ßà|fñvv:Ébö¡Ÿmör¤à+Öõo^Ù‹ýDÆsNtˆŸ}oß]°á•_õBØ‚* !5À@„Ž#ý#Àç¨ÜßëQX}Ï›KI"|ŠU,ö* ^áœQªÔÍÜ©û¯½«é§éˆb¿Õ.?•y«ð³XCaàu2aÁÄñ·7ŒÏ±),¢{‚¶È#ì4Ò\Í·=÷¤ˆq_×ç_HR>ÂØYß~ólt /7R±´oçÓ¶f²D: ÖÞåé‰~!VD£!²ø>yú$ÔS’Jú¢àæõä^ ‡Å|rOù~oâ'JíÐ{[¼ô^À£oX„nr¬ÖñMŠKô¥‚1w öܰ1•´¿÷Î{lÊçà<Ô|rmÛk“#hááSv9[*yø³ 9ZƒMóô€²IdL˜”M‰$ˆ$ DÜ{ÏOš,ÎÖZzKÖÑôIn^» |M>ܘ{r"Õÿö«pj©ç¾bÚÊäôFWm>Žpã¹OUõo[n_W‡âÔÔ§ÆLBRGúö¿¹(=Ե،t°srû*ÞGºs~)Y¢ñ‹‚E‚Z¢•å,ƒzq½ ¼«ë¶ë7Ñ^!{¿ Bý)Ïݤ¹¤?æSšêã€^5Ydê†æÃÞ>\ s}k´ÊÏâ"_Fœ€‘Î2ÿ>/«3’§Ñz.žE˜tŸÓ{!¶A ’Oó9RSÂ÷ªøy®~Æ%¹t°+±o¹yÄÅâÆBjÌŽ{ËÐ,…ö†9™7\Jf¹'úµ—3®‚;Óµ ¸Ôœ–}Ôk³$O.^”¯:7-­N—ÛÖ)³qår-ò³)«¹¼´Ú o]þLZ Â5Ê¢Îi{—;M¡ÚÒÊòôÍ*íwA"VxDC_¡Û›£›œØ¨»ÄüîëÀÛþIÅÔi ¢,Æ”ÎvŸ;³0{0­EdiÙ:íñº3<ï<)(ºÅÞâïÄ ?‘³Ÿ'?º,û6Dø®û mlËb›±þùFÆè¬‚à¡öwZÆ(»îd/ßÏ,Å)‘¹û©¯Çß®Û!‡V‡·ýÎÅâ7¿P¼0‰XîYÙ¯^)Åéz^c‡ÑeùnSð‰mqx›¼Ïë÷÷caÝã²S”÷×Þ ÇsÖ0Ü®w1èuÀ‰ún[^¶7°2zDèuQj²ýÍ]¢O)aBÜ5¡i[Or2•X}oØ­]@lî ¿ýRø2&ï­;Pš‚ÚÌ!_¼+d[‡ZrxÛòm¸å ¯´ešá6U© m”ÿã ªWßiÛD›‹Sß?^p!¸§ðüÉÜe¢RÍèt‚=âmé:Í£ lkÌ­5sÆWI.ˆ´nÏ ‹(ÛuW®¦¼–‰½,û^ #-¯G_uQ¼1ìÂ(\´F¬Ÿf4DoTàûWÀñ;Ñ«G™þKŸ“E‘ØHÝÿ´Š7Çì]àî$Z_‹£Y㉱waø²¡Îúã­ïsxõ%ðÃ謵Ú06qçŠÔrk·iÊ‚'™ð`œ™ƒ~÷…Mê”—¿}Jùê¨:ʼ7š¢å®ÁK¶”-„_JT>:žÞ¼I#SRiª+s}¶ìqƒ¨h–W˜Ì–¢c^ßܵ)ƒ¼6FâßËàÑñ÷ä´ÜTxéKiiõ„´õý·Ã8ÏpÉõþ~ Ìã¬7S¤˜Tþ;”!t šï Þ”oFx‹}?,,«¾ÿ]ñ6Õ÷/ÛÎÿ‚@˜da)bÉ ² YZBÌ…` As!(@@HÔ\ÐBÄÒ †‚-ÌÂó_ªÿøcþ(ð÷þÿ¿¤ýTÿoxZÿ_læL.¦ûÔaH{ü+Lµ”ᄎ± }hX[!Ÿ…™¢0F×6géÎTt Lù¥ö8uÿè]Ö/Q=õ›¾sžÏ‹÷¥"šâÚ ›à›ö3PN÷î5þž–™“ck_±Èf§}kªë¾kZ)ÊÎòŒ.éó¯ˆj˜)ɨ2/1úâ^J·bva`4~J#‰šð:_š¤­Éœ÷WË Ó,íêbâeq¶È a÷n<ÌK~Ds#Qe@ÐóåíW];å Žd¹Øé$žÄ XçUL…%&?ø¡„ÀW«âˇjáƒuê–åtâïÀñ€dRõc¡à¥hfØþQFžë[KÐæŒëØ+„ÛⲘi·ˆLzeLWgï5RKµäMHã=Ne5 91~Gš3Òo~åsóöE«+*W«Uô_ßl®ÊTi.Ã?ôƒE¶‘Lp}®=!ŠÎ!¿tòÙgÖk¶&ÿ[¸H :ü] Fü5goÓbRùT¦åHE¸Õ9¨$çפ5ö,êøë6ï`’Lëm®¼—AT·71Ÿv­~pßHãÂc¢»HÖŒ¹g,…ƒyÑæÙ6åóNŒxhݨÝg 2Ì¥Ž„&.ö4]ŠÙŠxîÒ]5&ÜMËKÍ&/ÛÙ×[UBÜ Àff°”#æ½}kdÞëü ±±3S;ݧígãjºçRE$¹<¸Cv’ ÎÚ $üÖŽ­À>èBþÔ ©̆¯€øàãIî‹a\<Ôþ }^íbNÎ'Œ²‰{N÷¯\¹°?³ã8³4Ã_àêçöÿ2m£úæ`\l¹þé¾ÝT9½{—%Æp i©ÝÛ„ìîÎl`@-кjÝo¹’öqºË€ÊI‰vÿ2»FÖÙº•ªöðIø¼Ø…ˆI£mú»óoB;ãªú²éVŸ±ë="l"ø(¤¨»x¿ñM»:5$µâÝËRqÚað§+,†D‡Uê3èÀm«¶ƒ"Ï)—pwíŽ /m¾þÖm°hQK?ìJù?+ûQíOè¤òFêàýoZˆ‰ŠX BÁ戈 €¨ZX -""B¿°ÿ úçú?àßû¿þ’ö“þ×S‡+\®ß6À¿ÏÐvßüê˜óƒÇ„Ú#‰çH KÙ™™\GMŘöº7eÍ9Ûµh±ŸðOÒ7xm—n+D„xÅè<Ëë- ¨rªwU©í&Í']Úm‰°ªÍß]³¥0•#œXà¸Ê¦ù¶t¶\Ì£–aÖÀöa핌gRs¢Ï¹¨ÇÕ”IÅT÷Wrã'¤ö¿Ô·A“hª«]Ùòºsë{pëÞës{ÓÔi$¨­žóÎ!ÞüŒåyð½¤;· ÜÕÕ»+7ˆA¦2&x—&IJ٣?ŠžŸóÅúÒÆ{d¼¾…G˜S‹¿A÷Ûä$Š;%¡6¤)éÞ#ÛCy ½<°–]ż+Z”q¢µ~ô^þ^$P“•{›"Fs›?v«²>ƒÀMO?Á_óäÑZ6îäÒ„íëÀyº™×¹Jªß[¯’Uêo¯ÇL…݇}ÛˆäKíÎz|ã…ÿ³Ø·Xn!EÖQìë¡8»t;³>Cqr£¶Ååþ6ö ÆèÇ: ,Qü׫?-Ænñ~­g°?\ªšè†kM3{‹¶té^¹{Ž×ýY²Ã¯C˜°%·”÷"¡DTΑÖINÉL{›>>°²öl9"É9 xÍ'à˜åþvÕû5Iò°ÒgA⦃ãÙGTŽ/¯©{ åNm†|(5sÀtøxØ­{“¢Øöæk¶KÎð@s[§;Œã„ܲLÆ^R/¸GÕÆ•ȸªé{#—ª4ÒÂ} IüFòC¾¦–ˆsW{K¬p"ã;¿§Ønß]éÂS/‡R}î{ë%Ð.™Æ¹¹¸_tüYˆv5sì|YpòÝÌžý஽ªM•μ¤G'á/s1 b ?}£=h´Ø?ÌSª¸óÉ.‘:A¤!p“*߯6¯tdï_ßy Zr»$†ïj¶”ÓÓ"v„Û^Ã%ÄœQÿ"’¡bäÅ÷ü )„©%‰ÄsÇ´‰ ¡2N”Ü`­â8n”¼¿Kq r>îš]1 `Ù·eß[…Æw„à<“û é¬ÿ[ñƒ /'²ìž„½½6KSðÔhg ×x—wŒ:åY<ÜE¾yo¶M1k¬:ýë_µýBU@¥óµÕRÓÇc%»râLžI¹WûS/ Ý£o¾“ùý¤Õ§ùÀ2ÅlçîŶãoùâé—|¼¢7JÌ¢6ÕS-Æ?Î'¿ê›G±‚W5¶ëºGé°ˆãø®…å|/¿‡OMh¡Ù We0 g!°qËŸ÷uÏëi^*zÃ=u¯˜U‹½¾ZöÞ£éUF¦FRÎþ—Þ[Õ»½låzÆås$v­gS+f`uí·yî{“–|®˜,&âŽØ§­õš©@2êŒ}“v ‹Ò¬Éz×D9±â$ ËÄñ½«û/½¡¼×;:Bâ6„¦ø¥ùáݽQt>k¦|d=KýïzK°õ²™ãÀWRO‚ÊsT[å¾ "¾ÉÜ›Ò.µ—»â }¥(ëáØ1\êʺ„ÑÎ×σï†Ý†·}ªýDŒiŠ.¼pýêRû9ûà‡Aާkçz™Ê“r„ßs<¼,¡òå«b6&uFÃý¢bÀî LwI¦Î±w‚âÙ{ËU™;m0¾ÉoΊÎÒºå´nÙ!Q›Jõøëmî“”wÚ*ƒùÈÿ.¨ý¿§ýgûO@T@ ðZ!‚‚¼`€% ZD…ö Øéñ#/ D-…E@0s¨ˆ@ÈüÏûÿ0Xèçø¿Úþûûý¿Mûwõ_dýtïGÅÅUÔyYµ(H´•:¢¸âŸâ´çß¿ˆ]m-E3<|²w}¯ïÁyNoËÙŽ·—\§zWŠî½©ŸÛx6sÌ̹Ø}TpðFòZ¥ÚâñâÌת×ÇûŸÞdJøm.¿¹¢!y|Raq>"¤½¿¦+ü^°ü¸[²ë»kLK ¿Àñ¾ÏŸ¯(Ve^{&vÇÑ_° ý3Üßbsq{=è@¼Ž>ê‚ðÂɧ#KWÈæÔ¦;pGcºÇàæ«Š¶®ÖŒÕô›ˆÃeRŠ%×.ùÒÑ„å§ÀVJöý}L®"p¬¹Q=[Ø@>?Wu§“#sÏÇóëÞŽfŒ¤•#9C‰÷—©>7"ž\~´òl)„kûÓìòò½½‚×ßœlذêÄ}Kç+ϱ‚ho<-ÃÓ!·$ T‹áïdvÓKî^é ¿öfÁîø’°„RU§hó©ÕDvÒ»Ô ÌºÛ Ï®ÞQÙfÕ¯ð¿¥ËÖ^63Äwèº4uñægÕÔçVÉ0‰¤åŽÃ¡4#Š<£ ïYq¬¥×!nË:|Pýv„¯z¥åÍAXAíÛÊ–”n ÅÛbNoŸÂ;(õ’E.A@ ©]ÉÐ…† ÈÆ=…‡XÙue2B>OI^JYƒ¶ëë—jo|ˆ=f0¶–{úl‹ÎöFðõ%ˆw5Wz!ýN®F§RÓ¼Û;ÒD{!ê\©qÐCCŠÊ"tÇÀ†ÉÛwiDqs7u¦óúí;f Õ†ÜôzûÝ^r©\¸Q”EìY6P”~‘D—^#üåÐa¡Õªï6f Ewez±ÕÁ7‘\Q§JAxuŠcR †ˆ±ÎØ´‡µ`‚m3÷GZ;ò~ EöŽ·š&¨g„±vÞÔP{ØÀœ­R[SfǤԺ®Ý{ËâÜQ{xÙÍQÏ¢ÜF± Vå–\tŠ\åU¶ Å,Q}V®LCÖûiFï]ê¯r[ºìVôÙë_PGª–ñŠ´Æ>q•ìxãoJR{ÍŽèêU‰ û+wH6d ž¤á¥×©8º|ãºê³›&tð5c{ÌSÇa­¥¨4z#Dwi¾£›pÕÝ7*$vü~N«{—rfšý¹¨Î~ù¼Öyž—¢ã ŸYT‰·r'?5p)‰°Ž:·ß‹+êÒ½e»ŽEêa¤½µ‚¸©‰ð»Ð>0=ÏÈ8o%ÙÚbWð-já¿{Ÿ¼ù•a®j?l¾•¼¡L’}U=´u'Y˜Òõ«/Œ¤ÇKÀÖŽ{ÍôÈ0Ï×ÞÅÒ¦”®÷$ž÷4¼7–Ìn~úrMJ(y§©·¬÷8eùl¢‡+í†ýè´·ô*³ú›ª¹¯æYq,š3úš„â»¶dÃɇš^k§qÜ¿_4Ö' €…]³BÞ_´öîØ:JCCÄQ™ÑqEll™áŽ8-äð)@kÎÛ4oš×¹c+1Ù/ðBÉ•® ̶k\öS¤yÀ»k\óA:WÉR­”6“®:[CÊèTv2×V_Û^98ç4y¨iËP‹»QÃHê\ဣ®us2Vc„PþQ›u eÀþ9ÎZk߆ʊ]iØáê˜4ˆìz”3æ˜-\â¶W¾»µ+ú•Ý…ö‹·{ÈiÈ3]ì”:2C¼à¿N)#Òü(.ëifš»—Tó}Š áGN_ 5ìWÂg~HãöfßõÌq 6ÂíÅúD?ŽAzY‘;˜Ê2€(“ö°!ÛŸþjÕ{ÿù<%Jµ7G–œ­ ÁÛáÒ¥¤ )²Ny±¹Ì~Ê”àhX8u-å(ë4ƒHÀ„áÒrZ×Ã7ƒ\Æî°¨ŒrqVù}Í×$Ô¦kKºOýú¶w§xyXÿE¾}P˜t7æ˜ñý„§1õ:º2Lç®~{ƒ¸ô¦Ú?èƒPÑ»ä"yû:Æñø –À·ÔÉ_w¥âYR`‘ÓH$þ’ ²j_}h»À©4`aáeèUÐñÑxÌ><æk€Ö…ÁGA„Ò ’ú ‹éΧñ¾°¿ ” „ž·(ŠeŸß£JÀH|?‡ KÀ¶ÿ¹,Çó;Ëo%`$>ZÍtc¾'¶Û;Wü]þ‘\Ö+•{›šñØN»æË¦¡l¶§”V3¾Ôo‡âUGñ;̽J@—júXÉòº÷®>> b®]âlœŸ¾ý‰:Üí× ‚õ%"íöaLÕUj„ïí½}:`WF‡Û+ÿ OÅZ¦Ç ,I…¹.Íëµ º¯)ƒðÀ5ͪ2¶G7"DÇZóœºå!~q"ëx“Ê•¯Ù6¾öÞ ô^4~t›ÞÂsܦ{·L!ø Æøíˆûç*1º®vL8ô{™òÅ é’Þjå¹Òwá„1 úN£yòË õ²è‚QLqMïú§¦d¯JwÙó2Oß~1¿—FdÇÑîX£¨L†ÑÞ9J7®ùäÍVóXpe X*>HÏáDše_prtYÁð*7£%†W×,O#¯rÕ&×LÞ-z{V^Êí݃ û|O§g﯆sGâ7ßs‡`­ÏÞÿ^< ýT¬l®Ûö˜´_Ç,ìÓ½ÚÙÓá™ïR×ÔÙYp§õ`Þ½lÞˆu‰Dyöù°K’j\ô—k˜©„ƶÍñ@K9å™pº÷ÎõIRºíwËØw^”¿×kòr­>_`ÆñàY—y,© yĺV@äû™.-<\¿OØö×$ÂWÙÃÆGÓlÇÝÈoY·`ÞØ‹u{K]×Ý}¿\×Y,¦?·˜~9Ú“ðÛ8U¦­\¬¼¯v!Üëu.¬³‡$ÿʼÜÞ†«ì_ÙžÞƒÂËÄ;꟨ˆ+.Ø/2‘#àÙ8û¹WãúS&̾ìÈu~á¶k¸jÅ4\÷R· 6âýˆÃ—{SMÜì;ó[áÏó)šcH¬ ÈYË€n»]L8¼ÂQ6úÞT}Ýqäi_R±›Sök[G®c°g‘8\×<ô”Áxžt.Ø0Mè^ ÷»P%ŒéZpm‹Í³C×W0²Š°‰wÿÂÓ–ÂÊ~Øö÷£‡oG=©gÒÅr ÔÎê¾Ïz·nmóà®^ùœêˆÿ2e'¯À¿‘ÖE7sŸÐqPjP‚$Â8O¤Õ¥EŒS'Iv=B]'†9æ\h³”2 êø´l¯ókÀ~ªÛ%û/kÀžÖ€Á|ÉÞyüVvƒìÞi @2÷ŸkÀ›ÿE XÂo5`UÿPfÿÇ0åëÛYlg5`B¿×€­þ±læŸkÀ|þU Øöo5`ù?×€Eïîþë0;ŽF¼ÒŒ»ŒÓýïÊ–Š_×׳´¼{£®€Ëi¼<ëÏìÁ!û•ãñô~½…Ê÷<²BÕ Ð 1S’Ê«sf‘¤Ã½Ž å­.J̇Ô\ (º£0k<ùþ[UnäN ÅmLU^R¢†7ñ’V^Pö¾¸},GðlÔHbø9+Ü«Ù"úºf¬žÓó¯ŒÄö©=^>ô”¹tk«´¡ÀgŸÂƒŽíB$|…t^•7g0{Gv/ż¡[]à ¬ŽÎ¨¨c)QçƒÆ³¶Õ‚±æÌ+ÞAÁÜ)Þaú£œÒòøZ··®üW5`^²ÿ\ÖtVFHâäùïjÀhƒÝ^5ñ]O½äqí›d}§2óÔJY×<™¤»ãÿ˜™7#KІ–/‚„e·/;7vÐâÍ÷7¶6UÒ«™\ÍSý¼©Ÿå¦§Ú²!8‡Äýž™Ä))J\ºÀp9ÊÒ¯@a…T78áÈeWôÈ÷†V@¡KíGŠd¢ì\Ñ-QSÎëÍzbªÜ6xÐv;*Ž^5Äw¥²Ë37¤¸Ðô§Üß¥à˜²!£³Ûúâtý»œ­üà—´ Çĸ$¼tUPSÀt^”¨èXdð{A ‡à=,%[§)GÿªÑgGYü]©\¦7[Sª—ý—GôÄJ-4lqã¬ïÈ~E¼°\·]5¶1ëäÓQ]È&]ûVžºº+¥8Läñä½ 1¸‚ëÕsÕ帗ç̓ìVö6Ô” †ŸªÞ¦¿pMÂdU5¹¡”›>‹X$dê»$»˜¢0ýy›ú{­Ý/5’»]Öœ}™ïA/F{ß 8únöu&,"8–mp8%ØY‘ë =ÖQ%¾a ‰ÑF§ºê“¾b’+ÔyýÒýú;[¬Ô’ kF¬JQnr÷n°¹b°¤»×=¢|÷ÃÎ f_|V((yÑg-IMÃÛÏ|‚NåI…ʵ{½^û°dœ>#^ÉÏWȧéPH˜¼*Å3Ä ª]6Ë ÂÈ¢~»Î1ñ4å}ŽÕúºAØ‚ŒëÛû SÐr ×íÏ]#+”n6'èfQrU{¦òÔE4Þ}ÐùÀóæˆÓ×ÌËNÊ„ÞM_xpY¢ïí%|SñhG2’CƒNŽ<09­#Ü’ß@ê–ž1Ú¦~Ѫ¥’óY©^q›}"ÙunùzcÞ¤‡Ýâ_ßd·Éããçãµ~1Lræf‰ÂÄ0–¿'U\ðÂYS%?ò]0€pƒ¬t‹¼¹m9мEå½…¯ƒ\6C‹÷ÐUÄù[#”/ï%|#ñ0}¹XÍŠ{R¸ñÍ»üðŠ«·GktÍê´cȧùܧWÍò/ñÙ¨[à–; hG”ûmMÛŽÒz2ÃÛ½Rí´Ê2¯ß/× À+¼ýHLê³FBÆÔóêÌ)1˜`\Ðv©þWÍ£ ‚דyÕŸîÖ½'Ôfè fŽgœ ‰[¦p—f%æˆGoÒzÙ@Ïãð¤¤oøúɱâ_¡Y±K;N#¨o¿ÿ¹@âá ]Ú v÷ƒÒGý ¹²}‘»&`gq©›ôT/)Ó¤ž$>Ç»3{ŸT̬îâ8É*‡¦”Šÿ•Zuã/â ü&¢eP?yÇ»—Ü-¼@IAñ*!l/±†còjä ®ÂÙTü6·ë1ÔäN…)ÊeÁviiGyw˜K>€n a35-|é)?I¿·¼ìœÕwññùY÷UA=ýCÖ(ou’6ÈG¢‡‚°Ã'Rãï¦!¹]×ä—©Œ}¼¤…cC L¦ýeùw»§\5ƒ‰Æ«ª_Œ?ÅHm¶ºpB¯â8•¿Ø…®“ý½ ¬þU`„ÿu˜*æÈèæ£ãŒ-p¼¹Cû¥»ƒN£+ÄÿfI¶f¤Å.â:vèůf‚ƒ½dG:ÑPóÏöó¤d_F²Zä'5^9XU+¢•y¥[Ê'³¢±—0ÇÈÌ!f«Û¾ÊÀ6þîC­ãFgU“§xuºÄS¶´Ý®ƒMóMê”寽7$^0ë´ž±òáïòô0X˜ñ8_ëCÌ2]ï3~Àæ—C¾9Bÿ]ü蛫ç5ðÞ›­Ä>×ðùî+]Ó' ψºá¡ –›jô'Çæž’à©â{UéŸé6°ÃÙ0ê¯ÀSïr8ϪÀÄ}¯ƒ?x'¾Ñ¿»~ ¤ÒP|£\€§ÒÅ7¾(F£&u} ”rkêºÖ±kCÓzÎÁêÒn™U(Ë-›ý½o[N˜wóK©ý0úd}¯½ª¯öªž [@ð8ûã”8‰hŠÕ[ìî[a¼@ëúÊ,ÔB`Ë]LäÊÇÈœ]Rfò«F‚Ùó.ȵ¼é:·èI55¥ª{™YÈœÜÉO<åhßIdþóÃyë ª_ê‰[/ªÝß*³ =ô "ÓrÚIUõ¾›üVãryè‚‹'¸.)ªA¦Ã“ŒV¡?~9–´¼ðn‚_jëö‘5Û›­}8¥ÙôDX.œohµ0^ø<ü-õ¡ ól?>îÓ§ÝÐ(q†“uŒ{Þ²¨20«³2°o¨2°ZãÞÙßËÀ`ÿ¢ ì€0C÷{a¾û20KÉ:ªe`Ĩ2°ÝQVd@±Ö`—×Úµp-¥ ×!ÌTÿFh ’½µwðˆá ¼ TYÔÔÒò†Ê]A£—ö±Õ—sïi?–AÅLÅ@´{Ö¾ËEÉÅçsRïmeTBV¯½ˆ†ái_Z].åJê#ª­Ö§NI –L±k›õ½ßz>ÑLq.ʃ%¦Ø‘xÍT&™ÚÔðn_7|Bmº`)Ù.y‘ÆI<Á„í»¯T¼OñD)è1©ÛpoÔfW8s5fåEÁW bChÔ3÷cðž1úEÞ\—ñŒÔy¨€Ÿ4åmϳFA½3YÈ>bÚ+â^ŠùäNÒ¥ñÒ¶ ¯h¤÷ån^û‚Ìã’oúzÙ]ÅçåC ¡óž`;ÑÌǰ^yø„°¤äx@<®­ž÷PᛘoÁ¸YZ|ªØòEª-óª1>¬ðå”&› PöKO⪙ü)IÆÞïwCYr1j(ÞtæO¯…„x>ê1V ÚðÔ^»Pм¿VTxÅü~õ&ao”·EÙ>¾ÑûþsTW;q/Ä6s¿i”~Ë>È´›a·o²»,tÛs'v*1¾ôNWõ‹Õ§+ÕÉÀ¤T;g±c£úëŇÃ8k–Ã/ïZ‚,<©tÁòsÙõSóù6oÛ­ëY±~½%߆T³?÷š·|È5_uÏZt±² œGéž86ãÆ¤Ñ¨Ú2»K¥˜ÉJ|e‰]ûRæMmø y©¯ytù“ÂP€Ú#ùw©œˆOGºï~­£Þ²V/õÕxDÍ>,®ÀÓ5šcG!»w‡ÕÑÑ ãäèÛëoRÅŸzï“ÇÓÍ0Qpõ‡-$_¨A¨ˆŒ÷›͉$šDÈÍœ+H²l¨£a·éÝ­ÛÞ1°&1·¦~[¾3j»œvAd‹ñ/»¢1Kí .څ׋wùc¨=Ó¿¿)˜ŒJŽO­ Ûx-¡È—ía{a1¶–ö\|j+•Sfiè—$[¼ßùz¿_¡î(Nµn&UÄKíSx;I_¤ºD_¦™ðEù£Qݧ#S5•)¢Ï+i;(jz†#Ë|h’#7VÊ_?šhPèP ºÕP{ÓEU1U +t¢Ý]Wù£K{ð+ÿ‰Ç Å­8KRß.ãðÙ¼0xLüÂ-@~ªGú (QeX¨¤I¨Ö}c*¶`±nb¨Ð5ùM‰âÅ=ØÎ[q}%—Lx:ö[3¥ßq0 uÆSfã_Þ¶9xp<È ”b»ž`¢ðµpO]øRj¿b~éIMÜl© ®YÂÀ™“‹ßWcöMÒ”­è}.ñíþèŽÃ›¬[* íÏv{Ôß ­±©Ø‚­¥á¾€¶¤ïá'ônKž“Ä»ËsOËAbê²bŸ¯Æ­½7»ÏˆHïÌt(ü¼Õ\“¡œËàU+i»³’¬3] ìÚ÷¨x ÷ÞùvÃd…¿ÚO}Qˆ,šH¤Góu_·žŽ0,ÖENÊ»ÿ­éS•`ð-3êÚ'ÁÞï`Ò~™r’’à™‡*9í %*ÑÒÌ4{Ò!"·2#ª"mø:»5Ù£÷¾rn‘•ø ™ùšÃ>Ä“ýöš[à¨ËŒ¬ÌLæxªû;IÔóÖÿ ÀþdþW p–ÿ„‚ ˆÔ´ˆ @¨0 †ADÍÍ……„… ¿ðþ'°øù_A¡¿ó¿EûéýOÚ¦ªô€Ë~=%I3©« ŸÉÃ+ û¼åqõCðB˜%æ,ê®Ù Z’ØÝ<Ú`#«~t/Á¶ØÉ´·w47Nfü,"ô“…Z4xêÛ·{¦ôræûÊHyM8ŠèÄcdf0N.ÁФø†“¾\5í)ÏXîà L–Nã<\»'J™=úí\D§sV;¯¤tgƒøcD6qg¯HHÒmù4æå4Ï>õ{äôä^û˜WôÜ—} 'åÜ[ž ? Ù­¥}—ë;jl“¿:Ð|%#_’±H¦ß¨?Ôj 8:¯}±åL½S—ãáæqUÎ÷ØŸÙý¼X•Êݧøí²‡ý­“–€Þ&ïÜÁU:áìÂ÷ù.ÎÝד1A6.q'K›¾•œ¢6Íž\)%HSØ@$«êH(‡|C @•¸«I¦ð|ÔL"§]ÙFx ’¡ïÖK¿Y¤nÔÐá‰3ô)‡ò6æÿ,ÂÿÐþÿ‹ 9S :Ûÿ+ €a AQa!¨¥9(,´@²?BQÛ…,!æ¿Àÿøüþ]ÿù—´ßù¿^Ïž*@æ·h`’u]Š”JT>h«ý¬05aÉ'9ÛÚ­ ›û6ËøU¹ñ“oÅՋʆdœ À„ÆâzúSÖ½ŠMffYœÛ"å.Yd>ÎUJ­[¦ÓBTØUA«·÷ÞÞ‹#¹ÁÂá¢ÉœÃhóîÒ\sN ’Rõm_BãÎÂO°Ó-µm µ “¦ýÚX‡RZðã“^g÷zeùÙ—|ž;·iöðÒ¬ötQH† æ†ÐÀééÓ¾59U‹«õw–ìÞ.ó˜ûñó/ãM/$\¸wþ•ŽaÉÝ/KÜoe°P´^¤\йÔ/g[^éý‘&M âð»þìç¡utAON$²©"^ùìÝ‘±r VvÆm jOËr”EŠ÷ ¶¾ýö(ºN,î!ŽåT«Žø3Ö`êêž2¨Dï—#XÿÎhô˜ÅHÌÃ>2çÃ¥‘d/ÓÞN£ úè¯8êâa˜ñÓ¾í®€¨vóºÞ@}6Aì›}š›J£åAúúJ‡ÁLz*JÏçÃ3ëlóHŸyˆ.íé]ˆ vA€SÖ,Ú+¾C*&”ÖO9|)Ä ÃžŒwf$€*¢¶Ã< èâ;À¾œÜD‡•x9ôr…Ï'.¥§xКʶ™5:/…±IUÐàH:o>¬ˆ´qóÖ,¾NaŽQÙþhœ·:Ï—Ò¶ŠÞ•éfQ6ž· íro©d”{Øv…`j£»¨¿%O-™„†rDV|Ì÷í¡«÷D=±H–=>u½h·~Þ¹µÇ–yûž+Ÿ5¢JhýIQDæq™?VQªõÐÖÅÿYBÿ»ýËö§ä¿€ ðCþƒöš°9€Y AÁ@Q Šˆ‚@@(Ò0„Í…--…~¥þOyíöøoûï/i?ÕèMÁ.û÷˜9‡ï>z!äJK4ð–-Ÿ‚ê~³œ—tÞÊÄ\¿¡úÚíkÙ¥ßÓýf«úoÙxãS&º÷>¦ol;=YÌv€^3çÜ$¼¡pƒïåi†‹Ž:ô`eȹ1&ú9Ác’Ž>]dSÙ鮸û<`(ðæ=y­Nài·Lgâ«cʸ€ñûNséoÞaJ‘ô ­}åH!]K .“OžlׯÓ÷÷3;VÙAšjF¼àjf 5\¬RÝ—7Ê©#¤;ã…ójȺ¢ð2ò/·OK»rV¨öï/Ütt7˜Š5Іr©^·4ìµ :²ÄLËväÓtCîæ·An“Qêìc}$Ká`Öõu”<fbh&;ô¸.?vY›¼û£õ›¸R·À*‡¤ìå|`Ø-¨•Á”å剾¦œÆÈ -\•Ʀ±u¶çºÝ~aÚ»B!iÀg! FM£ÔÏ_S¾¯óx©>ÈýV橒칬N {ˆMTxnäüeîd?¾'An@pîâX‡D Ûƒ¼0fiý’Ãößžíä \ªNö«¿Äð¬ñá×@¦b¨ô|vwŸKŸç+jÊ&ÊH`ãe“YdÑ®>qšo’Q¥KòŠú-bzKAyq S,AÛókéö}Ši£}'Ï‹|ÇKCö3ßîrö (ï˜Ü_ô1Œâ;þ^Po?Vµ­=|Ѹ˜ÈjGÅ¡UsáÝ—ž 6@µB¼Ö…ÛJ¬Ÿ.†êòϰy`OzùæOs­Gz¿ÑW¦®ùèßó’ŸVJîöÕ'2çºJŠƒ/… ´'¥ŒrŤqwR–ñ;>î+®V1…HN^г0.Z“7OÊu\4>”À—Åw,¹ØÞOàœY %ã__<}—a”Q€Õ÷è¹n6Œóü#ÑÍ÷41æFCúú8Öa®«zEÎvk7Üc•?> ;r¿êC=èyãÛ ?°ø«Õj½õq7ö€:Éóüüø¥[”Ò {##ð –y½ˆŒŒômJ|)®à ÿËÕÖ¿”ÿ.0Kÿ_(!/Œ´ñÿÿ/ð¿ÿ"|NFj€sŒàÿ¾!üûöÿ¸üÿ÷ø7·q„¸ØÀÿû}ü§øàOõŸ‚Èó!á¿ßÿò×4Fž½-mìaŒ.0+˜§B ׄÏÉÑê*òCó†"êÃÊõWÑõ× j‰¾"§€ú°uBß§¢©xz;;”?}Î}¯¢2ú^×Ó#Ýߎ~¢N{TG™ŸÉœY)ž9i¢ÌœP2ꚨ‡Óq«ŸŽ‰[tÒÚè;½è;Ñè)¡gämƒ†`¬Œ†`{úŒÊé38ꯎê/õG ÷tAtOWÄát ÔO×Àál ÔÏÖÀæ„ò) ˜' õ!o(ú€Â-Pr²èköè#y5ô‘“úHÓyôÿ7üÿüw±q´úïèã?Õ „þÈÿ‚B€¿ùÿ¯hHþGãùüËÂÂÂhwpBžua„8Bm]a.HÊ@þ=ýîƒÚ@\aè¸,ŒÖ„ÌÞž‘ÃÊÚ‚óôKˆò’ ŸµÍUô_^s8Üõ~ö…nn ³p=‚¼€¾jÂgáE]ur#¯ †wÅf§àœÌàWêy«• Ä9hw˜ Ä 5„ßOl-áh©ã‰~yõ¸%ÜÅÕâÈ臺ÙÃ~òuù ›'£ÌņêÚîÇÈÐ7 ¿_Åå¸åËω„êàd†ìawDp\EžB>Ì…¼ÿ #ÄæÈîÊxÊRŒæ^ŒP˜%ÄÍyfqCÀ]­a^Œ6VÖ®ÈÍaŒªprT¨¡!ì!®(°Œ.ä].È[‘N‡t6jÔ꣇^1/Wk¸##Ìbàa´…¸Cý!Ñd‡ÂÐBå¦Üô'acaA ~Çl{s´ò¿Æh?=AMuÁ·G9ÔBq ó…ø"¥š/îküáDA;£(£7Âyàhicåæ‚žÈokìíaºSîà€<«¦¬£Éwsur;£jeѧQUדUCuh Aø"ÿ·÷E8!¥•¥¯§ˆ%²K4Åš»ÙØCÑ·;A,ì V¨ÕFx!\a¨5²€˜CìÿxQðqDJ{äPyì¬xO‡Š’û0W7§‡,ŒÈ{‘Òzä´#¨ Ï)Öá(dþÀ0jè0$=x™Ã¡^ȧoAm®ü¾WQtqs…£qJ<¨CAW kØ)õ ¯œvŽœ²=ÜÊ9W7zml,\ล+£ÌœɰHRGQ£»  9:„«ÔÎès…@!®Ô8‘¨…£ŠkbæîjcfáˆR½è¯NîhF´‚9"Åx:0>˜;æÄëCÏ”ëô$g¹"qмs„"Õ à-¤CŸáàŒ PHwuA’ÊOëï~6eY}Ói"ç쎰±rDRûÕÓÎ(IvvhØ,ÈóH¥tú ¶ìÙƒ<î¨ûnæg½ýàC„»ãös€¹X¸¹Ø@ì\³¶úqÉÊÆõÇIä×gͽ]Ð6‚ ´Å>udtʈ֧§OuåOØB.êŒ Ì ~zöÖÙ^äôx 6öWqyOϘ#©ÓÍéæM1¨ rb¦¦Üh8º!™ÌÂú‡ ·/Ïlw9Qäô,Ð<‹ðp:“<êº?Àõ´‰ßO§øPgxm ¿ %sW;].§×el\Uч?=#‹0V0ØÙ ‘ê`ƒ°@JY¤„»¡Py:3VöGÛV;´m%­ŠC¨"#’â,±?*.0´€A xäù«h"³EÝlȈ€¹ ç‡<Ãwú ÉÖhš³q@‰r$§;àš°œO×ÚÍÁ\[sÔ³î6?(Æbu†ÔW_]iE»œ!çæ-~S´\BJ1¨›ƒÓé½¾&|œgÔ‡'®6(ÞvÛÁÎÄ#‡ª²ò!'/F¸ìT€!Pt‹ºõÄòôNä$`ŒÖ®®Nbüü(aËg‡[ÙÃø’߉yÿ:A~çý÷|¦Ü¼?SÂ?Š x=.6Nèî3e„#E£ ’ý\~Ü$§c¦ãŠžÄ¯ëÿoÿ9À]¡ÿ=6ÆòÿþÁÿ?µÿþþýŸ¿¨ý{ü£ÙƒóîOà ú#þA@¿ñÿW´ŸÖ™)ÏVü§”ð3uüâçÌþn¿Øþ=ÿŸ¹((1ð¿Ùǯó?ò*ðoþÿ+Úßüÿÿvû÷üþûßÒÇâPðù!àïý_I; X ƒ|§ßq]aWF7Ç‘5T$ä·Œ‘—× é¥1²±ýóMè`Áß‚âÿCí_ñ¿%ÜÅâúß×ÇÔÿàô?ü›ÿÿŠvð ü͵ÿO¶Åÿ6Žî¨`0*\üß² ä—öÐù?a¡¿÷üí?á½T  ˆA¼@!a¯ˆ%RL›[-€@s! °0T$ ƒÌÁ–B0 Ïö€þ×òÿ#þB`Àßñ¿¿¤Ý¼‰pwäu…Ÿ&&¥A¦¸NpÂÆÜÆÞÆÕËîÉÅõû€q•mÐr'¸‹+®)#î?ü/À ËIpeíaÈ5…2"íFÜ•°up„8º"-]àŒÖ ;T*Ín;Ë{¢Ò³.HÛô,çÃÈJG»ÚXÚ  ®žfÿõxÀ¦¸0 >;¸Ço#9+lÃe”†BeÑy=t(ÿ_Cú7DÁ€Sö60GÄiù_ƒþw‹òã7öÑ€³A¸9¡–G„ óÙ¨¥pp³wµqBZꮨ´‚nɃXX3¢ØâbwšùDñ®¨Û!è$,ÄÅwDÝ‹Z"Wø¿šÈ14ôë_þ_¨pº3z¸®^N0FTâŠtHœ1B>¥›£:aò¯»ý·]ž½qIiN.pwd§¨åatC òA¨T>º{k˜½#Üé´Æ!š¬à.gè¸g´‡;Z!iIQSW‰MFU¸£¸<Ÿò‹”¹ *— wäƒXð¹ÙIüRö ƒ…ÀÂ((DCetä@À÷¯@A¸‚(h?8Éfwòá:ÚXÀí!>'8Ò‘²‡¸@¥¬PyCTéçÇE@ Ôã².0Ô sÙ·=Ä Ž¢þ_ˆ(’‘ô˨‹ôùøo¼¼hrù¡Î6xá2z¸@œœ`.ü?Ý9ÀÙ%Fˆ Ü ‰›Ïâ2žå<£Rä3p7ä 6ŽŒpä ™£»CâËÑ+u$Úoœ.;âHº†ÿØ/Î,¢Àë8!iŽQÞfg³ÿøœ2šÎΦöË„~Ð Š Ïv  SìŒ;ŠtxN·ð0Â\-8©$k‚T6ææ¿H„Hm+B¯…µ7Å9UäôÏvC0º9"!Š“‘†y"WËÂÆÕuÇ/uDÀ¢h|"gË(‡ÂÌotp¶Gä!EA"hâGò<ÜÞŠâ4æàް³Ý¿Ê‘ (, ŠË¨€$DG¸ÏïT`ƒ`D8 æw³²Fí¾Am»@väÈh‹´d‚$TW$£¸5#´ÚB’3Ââ‚”Fæ6®(á„ʳŸí›AÊJ§JBîÜqº™)ÝÑ@Üm<Ïv³ÀPç•d…ø„Ðd)Ä'Âü•‰Š„€¢‚ 4Ç#a+o”l*ÆÅÂÚÆ¹xjgtﳄ¹ G…Z](òŠ+J°£f¯ƒÞÐÁ§ GØx"¼áŸ‡Ê zW ãdD>‡ÎÈõBØ @¢f€û;ñ¡¶@¡÷å@ ¹ž(pª&~[äºýâLÁ@€R…0BÑ]Ø!ñÊèaíŃäBWäY æ€"x7GFK˜RnýÖÏŸtŠ©SÙ/‹ „¡6!o@mVr€CQ&ˆË™ƒ ¶/9"×ñtüHýåàôKR=r.#rˆŽ¨µ…¢öc …*JL98@PÄaoƒd'¸9Rˆ¡·ä £ã©áDTÁÞ©] ÈQ!¿¥=IsVÈy82þ ¿:"-h,‘FËJ$œ3öE¥•µ ¥¸rw(£6Jþ{1ŠCÑŠÀKê´CG˜ëA  @Â!HÙõ4Tô‘ï×Áh@(íÒý¿Y@ȹŸ­#ÂÕMA¿X(" €bÔ»!¡9ìÌ䄹œ’òÈÝ…˜ßºD±Z.x¸ÀQ‡ÖÈ5‡¸X¹¡iÕ"Å©ƒ9ìÔÊsBídä@ÒÍéÞ>F¤RBA€8˜ÛX¹!sžRÞoSûfÆŸà/N eVöòcôH¹n³FBAµi…Ú#ŵ…íÌ6A^ã93/áVèýfî0{¤=ðc@hû¥ãP÷ ¿œUžN¥ì~¢×Óá#A;! ZuýÚ,ÀhûGæ€2Ü‘òz¦]‘¶¡ Rθ¸Y lQ4Sþ°Yþ7LT§`RC¨£Ú°„BKä’ýH j~&¿Ä‹ Œ.pû3=€¤Ôn)¾3³9&d÷p(/r!QF9*ØŽJµüâh@èovR†iºÀ‘´„0@ .e´Xú¦Ì¯v!üMu£Mi”˜Fñ”TÚÅ Áü<í‹Ãâ√-Rݹ¡Mþ_2d} O…9 â†ôè¼~óå~…,h%éNiÐÕÆ†Ö¤¿Ëö_  "uˆròHNFTfG‚>Û †Ry̧ÔÏŒÆ#r•PŒR-h'I¨½thÞA 5Ä R˜6§ÂÉñTH2Þ@jIŠX­‘«…Ð0s·SÊ9SV¨NH«Àõ7+9/$ÜßQüÄFR%ßï4ÊFRƒY"G†ú¦Z~Fqnn NTG(«ŸOý Ÿš Â¥Wþ<ê@HW Šr¡5Ñ}£99(ä,lNÕšEÑl€2/‘î=ÜÃñ‡•ðÓPÿÑ6äC©åᯠøi%~è7KËŸGrº…úAƒà™E;“Å<§:hËîTT¢ðñ»µ‹r’‘f 6 }J #×Ú qê«þÐþüd€¨¼*½€D$*¼Ìˆ.MBG6½½x•5PE®H ‰ŠÒ1¢7Br \Q! ”mxfe¸¢Ã@g±;ƒ³Øˆ•0ü³“BêC´ÍÅŠ¼[!…®•Òôø§»‘Ž€ XŒŽÏò ´öoìaø¯Ÿüé©?xàÿéY‘Ó·ì´< ‘?9/J’ñ0Z#¥²*€B*1ó_#¥äY<ØÍ-ñÿë»A§Ö”:tZ«‡2?N‹´‘¢U)S‘|„Ê:ü‚{×Q¤…-ú{rjƒ”›–¿ P„+æâr¡º†Ä¹«› ÒjteúµNËjëêüžG@®ÂÉæÔ~C‡‚¬~”¯£¶e¢è×: ˆœÆA ¨ÈÚY•¬·@ 1´9›9ì4ž‡š’æÑªéGLî{þÐFÚòÒrêòÿÂÁU 6)ÈA¬ó‡¢>¤P6€ •=úYa#a"?§IEy”*F§çPˆ$½_Hk !•è·‘Ìîäú{„Ȇ\xdz<‚ÃŒŸÿ ˆ4øÑ£”…8¡CÑæ?ÅaH"Eü¾]E\Œ¿”¾Gz`°ð©ŠúG)òäØЙ+"Æeøœí.a„¸˜Û¸¢Óƒÿ hmØB‚‚@´`¿¼m#!Ãlл|P&ú)égÛ¸"`ö–§{> î¨0Ôi†õ¬*÷çä’ˆŽ:‹² K¿ð $Ä©O`A ãOgÁû=¡27¸¨1 Ñ~:E4é#½[ÄOøP£—÷„ "yH¥Á{Öpÿ™€?d/ÑAhÚ±áusúÉôCê&ÖâFÆÿé'ãI^¨ýh-ˆ÷¿ÉÈëò£6v:lt]²ƒ º¿?böÿÇÞ“¿§‘cùóè¯Ð’̤H Ìíc‚§ ›ýlðîL>·¿t¹(ìš`ÊK•c¼þß÷R6$޳ꎩRIOOOדôŽ(+•g[ÔЂ8Ê="þ«lö·Ìp[ãÈš¶)ó‡wwn¥9QPGVEè8eëW|DËsa­²ÐžVàaŠf+¯¶oëòÊÞŠ‘'ëcýæGÉì Õ*ý¶Ìëå)Jõ;Îz`áâ‰kJL]’—Õ¬™Akå7(J<gùµåÿV“ÿö1_Ú.…òŸ;'o[Ã’]ØÎmW ƒÝ=´¬á`àØ;•¼U²w‹ÖjòŸ9ýœ‘ÿÜ.ä6ú?ÏzZ=À›jšæ,˜=Îúµ™3óëö?æWq¡EVIø:+f-d•M9å·™Áëñ}ÆýÊ‚YÂ-W„Ì›òÔw∢à“c p6ÅÉçu³¦¶BLÙ¹×îÿ%°¨°éÅËãi‰§= ˜[Ba‘øæÍ¶øB8¶¨à,ŽÆ}¾ÐVrë-^ûßÃn”…Wýûq`M×Sáë£w·×7¡í`Á/ÖwSD®ô 3Ð&ṵ̈âü_Ê—ó…âvvp±›w²È-Ýrɱá×.åvó9tPÎ,ÛÙ)•+—·íÕæÿ\¹Rœÿs¹üÿ³„åóaÝÑÏwDŠ7Â)/6»¸À‡&iìk9>"ëké˜=º€Qš§¾Ç§1°°ø24ßÅ5 Þ)«¥XñpgRóÌÞ-˜ ù>+ïŒãõBÖ( €b?»Éaåñ¿ Å®âÿ슕+•ÊÛ•üN±¸“+åK»Åaqw°c+Ûðxq±m•Ê«ŽÿíܬþO©¸±ÿú,áñŸàíÙE:?@¦JÝ5”ѹûØ|ŒÉŠK›x~לº°ù^}ÎÁ.Y.m y@·°éÇ](Ÿ[°˜ìó©ä­âÊë07Ôû™ýN6‰!}ËFí…Ç…´ JjüŠN¥°[¶ËkgXæ‹ùa~Û.—óv±Pؾ°w+ÅòÀr+ŽÿJ±2§ÿWÚ¬ÿÏÿëpj m;7 f}¼Æ"£‘x7‡Ÿú+‰áaŸ]Áþh­aY)äJ…BQÈîíx怌ôâ” {xÀ‹VóšSǾ%‘c:_' q¶kî)¿O͈Ð*‹sœÄZP5ëYf‰ÕÇa·˜Sã?—Ï K–SÊËN±¸½›¿(^ä¶ ÅJ¡4Ìålkw· ¸½³âø/VæÖÿbn³þ?Kxhü×벸@D·fkíNîY‹wfô­7  óåæ–ßµA ˆùϦ÷ÿ´ðÐø¿¢2ÿ…rÜþÛ€­Øfü?Gxpü¯s¬—ˆP¥1”$È\ƒþ¹3Þðî(¾L€CÏ›BéùÊ-!ß> %¹Û…­Gx Ê’M$ÎŒ€|kžoD”—Ó¬ ¨˜WRà7# Å»]øsTkœÖšòfbAŸSgõ“~«Óî}BõÛ½¬±r9»¹Jn¥å•"¡Ëvíµ/Yh”Š7n¢VKÓ®‰@žUõõþØÓÊ!¯±êHLjjöFzÅÒ` ¯ú*OÔ¿Bõ«ØI ™çBØŠßÁØö—Ömù±Ô MSpâè×:ñnm(Ú¥WYR ëz,­x B™ËEÔÏ Ë9;OT•Æ^z&!ƒ¥œú€²œBbxzóFžMÏUͰboÞì ¥: 8(JX²ºÃÆÒ)ªRÑF:÷„˜À dgÖ9þ\¤ã/œp ;¤OhX ðÂPÅþ„Ñ6Þ¢Ó½©eÐÛ°B«;„$U`­è æ‡*aõ¢È3¤U|ÚØý˜ÿ•<â÷¯Ìÿ¨ÿ3³þo*›óßg d_$ö¶Ùá%Ì¿—Þ]Ö™¾|‘ýS,\"´°jr‘X´Œ8më%—…·¿Àº@~É4ª¬_ähX¤Ú_0‡õÈ^OFÛÁ¨3Ž;§H6<&” Áªâõ†¡¾Á4ÈO4ߺTxV陼Ciãìè q/Ã7;Q\ˆÊ·”Ç™rTX"¿&‹Ô$14MhÆWÏ+”Jù…RLX&½Q‘Ö_b„^[%´à_U& ‚€ñi -ÑšôC„Õ™!2·«±5׸«üÇJ›¦N߯Q»&\çIÓæ»à ØëÅH$ú©† ‰5¨¶wƒ«4À™K_¡x§†RfÀ/½}ø‚Èyq¬bE»ñ ó#?¨†_U5‰1PSܘƒ–^Њ€R1;Z™jHd(Bå%"3@)‡¯äÛl,Õb/gb/)VÁ5à« ¡aÿÈÆ¹ÁE5€—Õî >ž/¨bÚ¸.³•€Ç=øGœ[ŘÉw_À¬»©ÕМÇ'$¨)y8­6¢+öׂœ\=–Fî6ذ¤?6,çÿžbçÏáþ¯Rfoæüg{ãÿïyÂ"æn†©‹Ù³˜‰¢iý»¦QË(ýg¼éP¶Hn#‰@e£N[ÃÞ¢Z$›8ÓæË|²ˆü„©o†HÊzÏLIA>Ãõÿý-°áÆŸÒ:QÝК<)x;¸ø›IffÔBÚêdäÈ­Nz¦Î­Ž4€!ƒ©1su¢~ë#Ïw2WN€Q½m6—®ºÖßÞ{õžA¨V¤e®¢ÓKêPClfZ }\(Ó™h:M'àÐå ÝÂÑ5f†lwIÍëDÖª±ç?(y Mo!·ÑB›1Å6¿ŸÓ0ç°v¡`’ ).ŠñÐLsF³Ì”צ• Zð}¿*ß($©£zMŒL¥pÝM¥p“A_–”¼¼¼:r¦¤âé³ñ"\¦¹ @QÄrp³ËT—õCMÓ”)ˆ9"øÉ‡oÀ¨Žï<¼Ñz‰'@téÙ»’€ÞCÐéÌÑXgÂ3*mßÜ™LÒÈ¿,²è˜DODLM<3D³¥BUòT~•¯à¿ß‘sý;nÑEìTÈÙðU’ÈÎë;tF$!´}¼h‹í9¢=>áY@æ9`جQ"ÎθqѺ¿‡•ºZÁß+M–ùÑi{l!Bý,5H%€ ±4d1’^•ßq(!>ˆ úN2ŠÎÕ*ÿ¦¡‰u ¤)êÍÏ€Èx«V©‘g3kŒ¼ Ãü‰‰‚®šcí+Çþ ýà ØrI ˜f‚óMtÁN²Q”ØÛ-z’«Vmx·#'‘‰ï³‡04R ¿cÝè²ÜGŠD÷ýc½^pžô|/ä`óDR©ìÕÓãÜVþ%Oqð•,@VB¡Ö^´{Ï„ª|éˆ ÉÄ@Ï:µØúÊŸó$ÏÐ:J¾ >:ÀY¤îᯟÊ,Ã|aAÀ<-u?ß ¤aÝËÔÀºÿf‡¨™‚¾öá—ºvÇ·óÍ0zŽ-S¾M=ðSçKaûpÆÇ 4ÓaWÀÓüšú,Ù¬ýÚ2 ËL=„ÎÔ'PÆB`)|IÃ^…ôØm‹ÌZ¦2ðÙ¤é_s#Ðõ¦¾ž”/T*²q,“Ñ kU´3F°æÉÜ*¤ hn¡‚M#Dá›Â.'½tŃ3‚®ŸI9Äkú ]…?K¾O¥q¿wOÞû7o¦oÞ$?ÞÃ0$óC\QÒ3‰«ÑJjÊø‚;Z ¹…ŃìÒÒÊHŠƒQ©N%'0%²õ£ ÄЇײPç6ˆ-‹9A°Â÷JYˆ@aÐ÷zÜM±¨ažJ$ Ûáþ o¤ÁãÛîµF‰bi r4áE‘8¼91áÜ„ªÊOÏMÇ"î02}/Þjº©9Ÿbðb íÑŒÜÿrÂø—Q]sá˜8'û¢qB~ñ=-âÚR¤K´°Ý->¿L¾2—¯&ã(œŒó™ Ÿ¦§B&(@wƒþ¨†µ…ø¨¥¡@ã$ÈËßa$Ú°VÂö»„ÜQ_Æ =çàb—âX 4U“ï"ör¼|Ìçr@ô©Ü’÷°úþìM_,$öÿ¡õZÒ¢|²2Ùÿ—æïÐô×fÿÿï3öf§þÐuM&ÐRqGìÿ(ù=#é/YÉ ?µêÍv¯)ØÎñL™ ,‹c f{øçÄ¿ ;,¥üåÒó.GÎåÄ»½ñIOˆº2˜–(¢ÁpÉ¿Pï~ìÝø®ŸHhyפ¨w9BÎzDÌÄY”'D™l*b:¶óÀ>·” ¨™íÛÎâ5÷ îÐÍÚÍS‡¾žr|¼kºaëà2ó†ï ªN˜¬rÕB†xÈÆ ¹8ë’è°n–Z²w,Ÿäxo}´À:ºö`~µ|Š^ >jKJ)š=ÑJQVÕ7lyÓ„¿…”)[|p´„/DCNWÚ‡¥œç@' åuö6¾‹Ö¿»‰,!v€Æ;.ÙRe$»I #úÏÿrì€ôÀl<r/n—BC›]èFÚ¡¦XƒS9ÔGã˜ë5 š“}¤-t´/–;"í5hÝ·Ëœ·ë1²oŠCeƒ/Ñ×ãùx‘5¨›0ã–ïЛF¶ÏÊÖ퉊gg&‡ýªÌ›Ñg €¸É2Ö«UòV$Äû‘$Aÿ[ï`óDÕOŒ¯zdÌÍ:)ón΂ƳÐ$\¤Å{¤=“A  Yå@i/.u ÈiÁã¿ýM¾UêMÔ¹Ø?Žb1³à°\TDëœêøÎƒØ·yÿ?ò3¿•˜Ó?ŒÐ„4.Pë˜Na!Yâ¼oA×Xxøh:ºˆè¥'«œåíI²ù(DL2rØvèg{d=Ûp'ÖÌhC;b} —íOÝÅ7W“l >Çc>F’9Ãl (3—fM ÍW–51xa!JXˆ–¨I2[$·vât4RŒ¢¨Œ¢Ge<’íû ‡tБZ –õVcšù„$FEœÉÿ-äÿŸøhýûŸr)·¹ÿy–°¹ÿÙÜÿlî6÷?›ûŸÍýÏVò<ÿÉÖ˜‡×ÿ|©Xž½ÿ)+ûÏ^Èìë¬Ôø"Ä‹' þ‹Ý!×j—0çúä.YØL Þû”GI–ËœY¦÷žãh™õ¸˜»z¾s?»±® éáÿˆ¯žf} ×I׬9¹^üU`)%E“òï½4”BCzK+4@ÎØAçIè鳯”o&º‰z¾HÔX7o6«iÅâÔÕl6L‡bÙÕˆRéG3°˜x–­¿þqÜiœ5·Ì­­?cÔ"¨º)Ž›™s>z·ã‰FÓ JÐí\rˆ›ÚJA\‹õgR<°®¤UCçDZ7'&ˆŽ{TàÝdý‰ªš2Eì©["6§K;ðbƹép{0²ü+ f˜ÙÃC$è]·ÀloeÌÌK#8žyusåŒ ¯ °ÙE`<Þ i~úÊ·½9x÷y :&‹1ØÃÔ» ïáý·wíÍmIþoãSLÁÊ’tHHrgÃXNäGׯqN²7UGÉ2H‚"V À¤‰rŸýú×=/€¤ääö²{ub%€yõÌôôkfº!m'Õ¢GħÇÔ"XÌæfDFýmzC>Ü2bŒbñ]T  3Ѧ‹dHè’þ6MI¶_"„W5š³ù–h-ÕÆ3UÓ2\° ù£€›$@Þægyq‘¿¥W!b¼Âõ¤‰æ›|^ªšê¥¢×?)süéhäÔ¹¾ª®UrJʕꥪ…:û-úÅ¢—¨Vµ=È8Äûǃ٫ãAò☖h‹&€I’nÁ£EfyP˜¬‹JtY¤ù(0É«P \­wƒA¿¢RIÿøøãÁ~ï?;½/èoÜû%¢/ï¢ã:Z?ØÚj™^uå„ú‹d`@•$X_§šˆ€¬DUÔÌG1£Zr/FÓ(xzðú'¢1´Zf“â2¾«ž þÑGóhvv€&fpÊ1¹‚öËËÖŒHï9·"Mð§È­¾è”V!p¸&¾?JÃ1OÓT?¨§A1Ý®¥;†×·<„swjü†FŽ4Ý^¶’羊³4®’VtN×1Í{W*¾gø®t|«íX´ñ:’¥h3ëïhRŒÅD-/Š+‰ÍQ&?ó‚´™)µ¡í±½Òäs¬Î13Póh—‚a“{̤b}ë%Iý Hp¯œ©^9áÁ”—I£‡*²qv{ó³SÃMOÞ#¸—ŠT IëA4M[ªW¸÷¢õ>ÌFïïX·ºHséžÿ—ì <8T‡Çƒôåñ x}Œ%­—±Lµ)îVɹ iãã­‚çusêe­MtÀ£ÑWræÁ´ îNGÄ[™’Ú¯ø >Ê}môÖ#á0Å­¬5ÀÝ·„ˆQ…°)!÷ ˜õj‰9PÔÝî:Ê¡IK-³×ÕÚ÷Ž`mÅÛ[Ú‰œw8|¢6·ñ"åÏF„’ÖçñBø¨Á?ЦU·Ù”K*ð!²HM°°³0+=)aúÂQ_“|Ü+&=„˜Äh"ÀP‘£˜°h% ‚™©¯1^( )Þ¼~þ:¸GYrµ/öŸ¿zaS­…l¡ÝÄË:©wÙ-Êer_½–kÍL¯Û$ö ãavS BJÑKl=v«eàEÞ¾˜´ÄÔ‘’¶§‹Yæ­Nz“–ÓYšÅeÆ7»ÁçÅRXm¯ˆ¨OU´ö%>h(>p’d‘"ÓL‹÷°»­xsª*f‰Eúi|})A¤/T4†µpœdÉjK(û5*·Í¼IÓÎÍäÜWFö3Ü>ÇdÜÉÆ†ÐÏKâ‘<öd»èr©˜ ¾¾ ·b[mH<¯WD¡þö”z²-Q÷´øPm{ÂÆ½ŠÆÅU8;ƒL×›«[*ÚFŸCùbêm´,K0~K`çptz®L;$]].ÉÏ%ºvÊHWƒæl=xQ½±'!õ¼jïAˆ\›Q;Ñé/|ø¸×ÛÁ=;Jp"˳ó›Û´9©×ûøÇú:þ¨(Ç!÷=4S\MI.&q o!è\‰:Ä#á¿&ˆÓ¨Œxˆ<ÞùjµFL•Ú±(µ¹2ë:ÍEGãfeëø'¬°˜ÚW‘X؃ù%MZë& O¤ðò èÈ(·N‹&HFÑ Pı° 1P¥VÔïqÂW{«ÚÄ­KÈM w^tƒµ|M0WÝBtX3ý`²£G¤Û >ªo5‡¼!¥ ´\OeõôÊ:¡÷ÇúmÜ~äÁ¬ÏÂ3v ˆÍLp†®” o·ðüjëÞlµµ†ÐÙÜ$Qøä’yÌ— Œš‹»ñªø=x]ƒ— Ñ_xÉ1€za¹Xih-Vr‚~Q,Œâõ%ñ™FÈßÐb«$›ô`ÅÈî¹ÅÎTI4";L$ˆ\…¡ØØ«Jû~Eß9Fµ ! š±&—ú0…žåå/â5kó‡êKZ«¨‹9-ajStúgk(L}këÛÞÚBÙzµB~N~`aë‡âB†„ £àzÏñWœ(óùóbD«êǤœÆó N\°áWÞIaveã™ eg.c>'e×z–FÁGŒH}õQp7 P±ÿ[Íàw…þ.è{œaTI®ÞúZm=É ‡$}pF0‘V"O¤ÈbmkÏ2bò¨”1ðñ‘•Xûb±’5~üÈ¥WÂÊ-$žk:N¸°ŸÎ=YÞŒ£åÛ;§ŽŒË«¡E'¡G‚Æšl”Ãdå§šÔmbEžèQÁI(·aAô‹DÅ2w‡“Òá¿^'õÙóC+ý:…&À™Ê´´È+ºþ 9ïkÛà«ãâ"Ù§8¶h¥œQó/F§åA‰­ŠªaÒkŸJVãL)O.‰W…øì!T©FÁh#k¶ê¶Q¥êü¯ÞkùwüÕöÿ¢a­âŸÝÆmñß>{´Û¼ÿµûùÝý¯?åw_=å9B!¹œûyîÞÞºÞîï˜lï˜Eíiz]t¶dkeÁ¡ŒÍI±ZÜWGÑ4ÝÒ{âXÈKá?ë?GÑh6æÊDgCÁ¦ !Ï ¯Œ ¢ £X«õWj†í=*8LÔ߈Z¿(ã¼Êb9ã«ögI™'™‘Ý"núŒ@À¿‚£ˆRéy+h¿£nE$¡Ÿl2œðìï‡òFyÏáYš¦Á9ŠîKúÁ3Þ=·UUç¹WÊ©©bøK©s>3ÿK‘hì6g| Ÿîÿ hdNñ·Lþ¡sŸWAKmFH¨.æ:áÕ¿í_©ÎéÑoÞ§_zéØïd—j ‘eb{ðüðäpÁ=åOÓÅß’dž”þÀpäkBñüj0*ŽL’1L«‡ôH½™.gÃê(u­Ìb?]$”“D£Ä«[”½¬8½†çeÕáA_Cº|6Ïë7ûßRâ} ùàÝö1'_ETº@õÃ\Ç×Éer]×ýëúD NH;C€ß­ §Ý;{\΃þ8=M°×s5“¸º¦ÿ³ëŠ„Ñäúò¯&¤À'Üú ÿÕ ¾ñ«Ñÿ†+«Ö=À?ÿõóOÞÝÿû3~7ÎÿЇ®?ÖÆÍüÿâöø/SÇÿÿ”ßÄÿÓ7â~,¾ô=Mù@J{Rd㲋ݻq&Ê]ýº»ae¿,ánY.ÿlŠÍ²!.ËA“ò†˜-+Íç(>Oj—ÿøj^;­^"áëIgÝÍ@(úo }ÐOÇÿèY}¢MÚá31ŸâkwœN&oß<ó+ã˜5Ø9ûßå³~cÑFÕh·o?étÓê ɸÍœÏÍùÕ‘سHž»•…ÌûX²aË~8HFKá<¹Á ?NÀ¢—)l`xµååÛæ²4:o@—W§« ©f×p}¨m.uñö¬'mïVQg]<ããû¼[-ÆàbãmPž¼}Þ8û×I9Б¹)â.‰þ¼Œ3³+Ì\ub=h®»DªÚ¤Üw>,°O;Š:+‘üÖ~äˆj^ÄŸ®â}·EX¨ÇŸìš nÀÓâºòù7?MËÄD"Â37ÂP½-³ìÃ(å"˜p¥CÉ˰éT `Wl?Ƥ>…g¤1ÿóÜúõÖ ’PQ{Þ‹ƒ‹°›ájΓ‹ÅÕ<‘"¯àóÞ<êr¯PBhݯïm®þßîË×*ÿÕËgà™³Ì±¤ºù¨«l+~j]­ú³Tçj†õ02ß—h|ͨM3Çz€mÖÞÓŸu¡žëN|] ¶l¹êWÕ† [–¹D E”X…”†ÎcŒ ¶>ª¬`c¬Þ冥>gûm•“ÕIÏ•gƒÌÖ^U¢_é0 fùx¸Ò÷zœÒß‚[Fêî×ZY pØ®¥sôiÌ‹l‰HO4@quV5q’Óq%—pX:.ŠãöYßÖì]i“r'ur°‡°@E©B¸¾ZæÉåœH5¸œØõÅ•9$úÑ…¸RÐ_Ë…Íý,k¢k°éIZbÇ„¦ô6‘Ç ™EÕ¹?ø-Ça¡_û˜/V+ù>&^.ô¢‘bÆ.¾FúKVÙùÆÞjâ(ßê÷ÿX¦ÉšÏâË~cS¯9±)ýàÍáÆ´ýr˜.ÀB-þüãñ_E>7ô{.6R#1bë†Wa'¨•Äõ/‹ŸC‹5õñaK÷'P^D§±ýk6ÖŠ[}s9²æKØ„ÿ„½-nÜš®-#F€¼ó¿T”d¢rÕºjé ?íÖ¸¥ú[Á¥ÙX`CW{ó&Ü–¦uü9ð‹ãüQ<ªa|\+ëabb—ä"É´ Ôh7”΋v«÷ÕF–F±¶^qgc±˜sPGãFQ³pf›iF…fÇ|n™ÏÅÈfœ^Wá¦%vÙÙ ûÇ”êºìª°‡Çfì*¼\ Êe 'êAÔü;ý†Aê|Á§úýŒnOàDæ‡Ô™°·!7ÔMŸ`‡´ürR 3\éŽI¾ÔÓ vóH,’¢¼Ì—Yf€»'@Dó!ÍÓ…ÏïMãü]ïË«o`F È\óÅËäÀuÙÜ7fmè»O¶ý^¹B®æf~פ½Ñ?WŸBq+Q„8l¼ÙôâÁƒ6‰^¼$Œ¤KÃ'zäARÁžM2àÁÍ‘?ýðskz.‘‹¨à™:Rž±‡†>»8Q6jø¸A0ó’tãRv‘.HøxaüJŽX†é9Œàü©®ÙÒ…µœpuÅÜ«m¥¤—¤È>c ÿåéÝR+CªIr;>?%3¨—³„ Éi_%³CKhâ*²DD£‹å8Àt„@È`¬èP]Nq u 5€°MMò ¡’¿2 t¡†RüxÃlCŽÊÄH@Ŧ»ŽŠfzXv‡»Õš¯Õ)1Bw'‘¥g % úñétÔWŸ~²ûùΧŸªá1€®úB}ûŒþüõÑÎî£mþ½Ø& %ZKÇÓ•jïJEUŒ½óŠ4ÔÝW8‰Àabv¢õò‡—oT›“,žW BÔÒëCõê­$|QOØ‘¿}Ö(¥úë“'vÓÏœ½Qáø 6ö]ÂÛļÏÐë®5 ¨-‘¥¥–µâb|ö°=.‹ùOSì–µ·÷Tˆ !˜°¯$n‹ßŒöIÿ²/^2†eŸ½&Yb»%‘WüÍžj^„]þ·£gìÜŒ¥(–ó#`ŽÏ_“,}˜Ú¡èNãRÄjN³˜R‹ç¹ÒWS<†hÿ<‹8ͨSœ¢Ú{{j$°á:ÏÎÛƒïåÒÎ ÊÉ–éræÞ±’Æ™¼ÈAÜš&ãmÄN™h¢©è0ý,À>þªÆËRN›éÃ75rÙ:ü€œœ èXwÐìeÑ6Íš¸<¯¤­‡pOíîìÜbuÑ ~HV ãžzø Ä)aXlõi5T¾ãe®¦r·g›#‚2º×Hù«œÌæiX¹Æ•Lk,µŒBÁô‘I‘¶´ºï$ “yÏ_¨öQŽ~IóßðŠ 10½ðãE¸î¨¶©jÚÁ‡ÁN鮦ÇÖÑa£=ÅY‡@  îð_‘aCP|¼Á´Y“Žd¡ÅÇo„$³G½K.˺.¡ÐÇygS_6ÿþ`gÚáˆ÷n•têsáw `YÄ÷»ñL>Ï”7·5rlBˇÙ^þ‰’i·#l›ç`:©·9±Wë"^{?m¢…Œ‡a˜t¸ï³ÉµÔC:K0ÈKvã„‹r|˜~°£¢ˆA÷'T'æDûsõžû½Fƒ]\öÔÕÑtK$¿zÐîk _©<·(oÓ÷lnÙ­‘kLjÙq}~A²Ô”}tÍåHkƒR­!Ò=§#²¾u½pák›£±6{Þ”¶§zʸx„y«Ž¡µÞyÅìpå2\mÖkÍÔkæd]ÑšÁ°¦ª§Fïk7G SF‰™ÑóF²ebT/o6µËÿnÕölF.y«¶Ç£dì1«øéY×â+k25H7O$‹¦|5‹þÚã°ô¬«¢'S;žI,ÉÇ=÷ŽÓ |Z[ðÍϲÈ2œù±÷Ù…-‘Ú*1p¹¢ë›¯qO+Kø09®RSn?ø'<Þ‰L @Γ’Åh f(±AËœË;olà‘Xé¼L&¼áòÔn¹í!3³²•ãæ9ÖQ³c¯ zÈ:¤(÷ÉyœéÍ%lMš­§¶Þ"ˆ)kµ4¥ÞfÝŠà k|-“ØW``÷…‘,(£)EÊì'ª¶Þ}R®–Hˆ¼PA Š,©Áб€þÄZpb¹ žJ·ÔÕ{»­ÿʘP}öüȼøñÖî¤]UÎäo4áƒÙÝä8•zÓˆŸ­Þç¾?ÒädìgdÅm tí;šã*×”yéŒ×œåZ}—ds]…Ûï{ñ³Ñ{\Ýò-osU¡+{¿«’è4ÒÁ w£è ¹ð!½ìPòb$Ö+ãçØÍ/7îÒü1!I&™?½R­n‹½šòÉËš“dd;¶ILnž/Õnë+ߟªþi·ª¶ëŸî²¥N¢ðÉü™pí¯ÕÖ}Þ’ê¡>Å©«7u{“ÓiÔmöñÍå¸fÕ©­ÚÛjpÞ`›s(Õ‡æ>ª¿=ƒ?:š,Ýf3¥mFl’vt´«[‹F!)ã¡îD,/ØÜcüž¹²lƒpnð˜›1-8ìáÓê‡oC;T¡q–׹Žô©}¾×’æçž‹uÝó—äãF÷ÆÁ¥ðn—þyØ¢|+sUUŒê† Ë­_ì‰ß݆]¦‡’B§qÔQbW¯¹¿ÊƹFß u¥ìxkZ¥Òâ¸-ö¶až‰ºâÚ; ŒlªÛ#IþmÅQ{ÙªK <;áÈI-Z2Ø&pÿ©M|:v ƒPüªð• çq}ĺÕÙñºl)bä²—{ÓQV…óðì½pi.¸X_ÔöRœßh LÆÑÆJðå…+ÞM¥ðJ{‘s´’‚™YN­o†Q@sa±£Ð¹!°^ˆÍ‡=gqe/ÈfØ­£^sŽ«~Ú'2WhkM¯u‰ÌüC%3VÙ‡. ÀbYZaNŽ¥5x­áü¾Í>{[flZñOΰ€µ˜¿Ï«'³´M]„+ÍØ“ìÛOÔÌÜáÇl—„x ­%žÝ\óZY–èš›ø9¹Úm]øh·wÖ•Áa÷4÷Ș.E ®ÍÏÞ‚VrÛ> Ì}×N¹9 þФ׽Õ2‰¯cªêúš °à¾á¤]­XӜ槭³œøémêsW¤kÞPqÂ]}Þ—¹8»‰ÀôP 6b3¦Ô½;ã2ÇT#-bÃI™TÓµæýsǦµôö²F—qÔÓåê{+ìTºTk@,oo@²Ô̼kW·óœê­V­¯Ÿ8¬áÒ<ð<оœ[ÏcúãÍ”^,£úy¹Æi¹=IßБúº=5KÙû4Ày?NÏß«O:ê³¥}­mMéÝç3e–hRG¬Æá»= Ô­†ÉÆ™¼=§7Þü8ÃPmOåqËZµr£—yªnÕÏ|®ÎI>r{2ÓX&«Îõµ»áSÏ7z»èæÝÁ1#ÂK3ûôÑànû¤{Ò—g=܉–‚)W½OH|Ͼ×;F ÍÇdôDÖf^ǃ´…½aŸ‰ùÙþ°*2ôAÒ‰rgaÈ¥Z†s>墿|Ò”ñ`JoJ«i”ž^3ìBÞhKc}âA«¶?¤™^„![æT·Û¹­ì$Í:udµÝ™a×AìRmQS’µå±[܈ÿ a‰í¯Lýð’ÍC«{+j¢‡·ÔÕ<äºÇ¼±Ö!‰ö¯Nô4n©#çÿŸ—‹,!·2ŒˆOÙê2JÛŽ­]#£þ8–â¼—­¶äqÒ±&_x?aonZ‹ feÛÕö+?f:sîÅêÎ<ˉ¡mN‹óÛQØûéc忯Ð@k&›ÃK'æÌfÙ©‘9+ãŽ9Ñ,¬«±apÔ+˜(,Û™ñ±þã§ÆÚf]ÿzÏf{ô¼eÁt`w­Ÿ¬9A¥ó\ʼ`™ÛßÛÃ6€`\r9Z½U Oª¯láV «}ÑŘÝÝî6ªiý»ÝÍû3~7Þÿú'Åøýñ}þ飻û_Æï.þÃ]ü‡»øwñîâ?ÜÅXáÿâ%éÌcnãÿŸ}ºÛŒÿúh÷.þßòÛS¯Ï‰™§É ØpÆwZÀÿ›Þ²q¸¿àØKLpcæílÃg •áo\. Ÿ}´LP,‡ ‰”ƬI\ZÆ8éÇçi±¬ŒÃp‡$›±G¼8”@”úû¢0Q5±û÷•âèà-ìh4#-qAÊ»Gú½ø]{nŸA‰ø)¾ªÔ|ÿ禤‘4®c/$ý`·£àì244>ÄŸSáczƒL=eÏ5ðq<ì¨o>[‰è2*J¤y!ûe•hÞ%éì1ü¨³Äž£‰cÁU&"ƒK´RÑ–vÔ¦2¦{|–#Ä.W »ßöŠÍ 9¸áx™v‹¢ ¾¦ªs³Ó=Ž>ÁnÏp‚‹½°•ÑÚ7Ð[B,y°þ¥Å w’;Á£Í3°Ði‡0}׬†>U†Ù¿WG®æí7Ø}ûó’(SûW#ìoZýØòm×Äô…Ý·¿ÄQþW‰ÆDãÏÚl+ÝfZ}{HFÉÆ;ød9QÙÊ þK²Rôí!}¶BÉþ®mû;«W®|ÅNø_²ŽÌÅeÃP“«J†€AH©/题bžÃ"«*“X“¢X$ñ*DÖà˜R5VHÊ{{”;B5ìOz‘Eq‡ñŸçÅ­ã?/‹ [Ãì$Wûyü?qɸðbÔIWNŠâ³ðŽçþýÜ…ñY=­¬ýQsìÅ;²·Œþë3“¹«î|eåoåé^Sþ‰ÜEG´\ÜzÆ!/~¹á“o¾ü웦ÞO6µñWÜ8ç±{åÓëÄ7×§/ûãó+;ß-|±éOCxꤩg}xÛ‘cŽn¾âÁŸôì1“~ÿÈœK­˜)»lýQñÎö“7.újå[õwîÝéØï0‚ÿŽkz¾iáDy¬Wfø?ìÿdîÿ«‚2öÇ‚Êj¢È§’†Æiœ˜B†jˆZ2•’ 5Å‹¼‚°K€ ‘>%ˆ° ¤¤TŠS•$,I)´`¹øÏnÿyY ñ¿ØÿGí]E(ö Êð?É2–9•ÇIQº¤c$§ä¤,J† »<^CH•’)X>Éi"6°$Á†ŽÕR†¡‰z £ÿõ#ù/s”ÿUÁþY=å°Åì¸ÑÏ.ì…^uçe—½Ë|ú‹…éÏ<üôç_=ññ¼ÙËï•/eï?ç²_=ð ÷Ü7³Ú.;ûž)Wß»æÔQ4¼Ê¼·øÜN\ðÕ¥WwìÝ1Qì:Êð_U$vŽ•EÌKI™ƒe’‚EU/±)‰²ÄrI¬‰HÂâD¸éEEÑåù?bÿÇKŠDù_ ç øÈègO»fÊš7ŽÙV_^¶ôïÎêO–_þõ¿¼{UaãM¿¹õöÇ}Îã±×-Ž»Ïa¼Ih‹_:pÃüñ¾ú»Ö³?z{죛Ø"¥ÿ¾ƒ2ü ÙHŠX”D Û–Õ5]A†µŸO‰ lÆ"ìD= û~ÁHb ‹)vïÜHI%Qöü‡F®ÿœÂQþW[øßúÊŠCGqãÆ¬{ëå5/œxØcW­fzŽ<©©çú:ß9tÓgüæGï½æÞ®ëøÛæ¬~ªðîQß?Æ9¨0ç¡·zÂìýȵ3ß9cýó°òƒoûW¿ï󚵿T×,~øãæ_,¿á¸ ®¾ñ؃.xª}Í…+ÞØÔ²¼{ù†Ã?Yu—vûÞ=Å6üÇFÅŸïþù Ë=ÿ©¶kÕ´yP!eâ?Ç+ÊÈó?‘ÞÿUµLWÆôÃÌbF³-™–Ç & ÛÆ6<ècKÇ:ãât> …ÁE<Ï´-o"c[˜q°«…ú°g`˜)aGò3LùZÆ´Ò ² ¤+?ƒ=<¼=r‘çåsнoC'‘|&p¿£#1õ–í3>¨ÑÝwe Ë'®É@½E‰ÐkKþÊÔ›ôcú à50^Þq²8@¾ ò¡™_pêÂOsY}Á`HÈÒÃKFÅiÓ²ÈL²[ómèÅu0S_ÛÀ ºK[¶‹uÒS'Æd–ð`½ÒÀ¶ ³¨cOsMLJі›ÌD¬;QŠSêÈ…šsŠÍíQbˆ/6ŸÇ‡ ÝÖŠSg·„ œÕŠ­m¥Ä .¶žÓ&Ò¦Qœ>cZ”*N?/¼4=»8£sv˜X€ÜâÌ)s¢„ƒ'§‹3;Z'O3rVºØ~F)”¶o)uæZjÚéÉ;æžÑ<½£§=ÊÖbÇÔH®=t”zp Z±ãÜHWТ¤°¯ØURÂU»Jºú¦aL.v͘6mr˜1TŒJ†L§xÞ 2={›>û<¶ÿmü¾b2ÊÄQæø‘ñŸUhü¯ *ÿw/ü˜Ù,DYÒÆÇD¡;ï3zž83?pHéúxä2LB7fæÇãYÛî‹CˆC©7ž1²(MV“ ß.5È ß³ðÀø °Ïw±f»úø-%ëïÓ I¬¶–¬¥94s=L &jÀßð–\ùÁÔcDÂÝ~kÔ§3ZCXÅ@u'2f]ð7®Ú¶O.íè ¬¥.ÀšuAiwBËé¤Ôqm(!ÃŽz‡R§7ìÎéµë†‰…ªiå@é~ì¢4¾ç$†õ`Z† Í|s0h ù¤9ÌïÂtæl=ŸÅ›õ€d]è’ùA¦»&¢ûJšàº.V?¯ØØ½æœ^Ì^}dAã P?ìXÇï3‘c¨°/ÁÊg!k(žNY`rf:ãCCðçY`HЊ¨æe‘øº ”€É÷3PªiMfŸ(ÌXœÂšÈàÒÀƒ ~ò|BL“qæjv,üäCË‚Ço±„9껡ILÖsPàbPàÛv–¸­•&UÍŠ¨H6° gá5ÔÅ6ûŽÎ y 3wƒlžã¡Ôl±s9Èm›ÑÙA¸ëä#oܶ%È& ´´ŸÙÒFÈ+Âo¶è9À6£8˜” x¬š7³zPÝAZJ“Ùö žsdŽ4¤¢ìVÎKÔ€`å£,¨wúÒñPUÈö°ŸwJÉZêXÀn=ê$¤›îÄÐj Ùb‚Ý" Õ1øCAµõ´ž§C¨o,Ö¿@y`.L¢:IæDƒ)–Á¡÷%¡prÖNA?ïs›35×ölÃg°:Œ·™~Ó˃vžŸ×M›Éa`ÐL|#+ÖÝÛšÞ^:ýÓä;[6*Öpq¿Ž¸‹ƒ‘&&„5€Y>ØJHì°4Òá¼îD˜ŽlÑ X \p•aóß ¹å¬Îp˜0æ~/ [ua…ÈsÁí´¾ ïZȇ 6œÓ5œØOê{y5’Vâ¡×o•è—îËÊ–Ê2éRQÚôK™pYÊU‡\Pþ]k%™-%¡µLßÃìp³3ÌZÝaô';¡0w^”‡á;ñ2³u±x˜£‚wæ¹s›thêé9%0•’i™°¿úîSŠ£¾û= ÃÓÎzNyÚ»†k°´î>XV‚äÄM}sPRM¿c²àåͦ?+HkÓ&;q41Qs¦§A”E¶óÄ”á"*/":©¨|4O™„!²rÃ’ óP6 *. ð_8ÙRùÆÃ.Œráp"øœ™#¡˜ž‹u׆êueò9Õƒ¹UIÛ~³ä1>JG¦©'—pC0½“Ð%2ÎÜy=A\‚(¦çsNX·ØhÐ"ïƒp⛄ۮ݇£0ÅÔÏš19°ÿppÀ<â·¤2i4€Œ°æDf2¾ï456’`›HÛvÖuˆ„N#Ôk,ù \Ç·Ø>ÑsJ|¸'låR„ñpá¨4Æ& Ÿ[ª4µ³·Ó±wöÛÝÿçl_¯ Œ²ßÿÙæüO”Dzþ_Œ°?ì+a­2ûqoéIPd”}þ»ÍýŸ,²ôþ¯*(™¹é»>é£G1û$Fð6¿pã^aeã?7òü_P$…ò¿ŸóÇ­-OI¼¿aÿCwè-½T¨ˆŒrü$aäúÏŠtý¯ *·þÏõtÏÐcÈCž>aÆæxøUhcfqrdÚÄÈRÒH©©T $膔L²zRåNTTÄ ªëabÄ›˜Íˆ¹¸¬ ¢(#ËŠ(&yij­¤$8•Šk%µ¤ÄK8¥j’jÈ<$4ò.‚¤ jR¢±m{Øæý?VZF9þ‹ò¶ßÿ`éûUÁé3ÄÒ5û½ð“¼ ²ôº®?_õÕŠ–…3O= ý¼Oºìà–Œ-¾ñµ/o:aÉÉæÔÄ–>J3~ÿöèšæ›ÿsüÑ·|ýéÚåöSu㙲Q¿õú¶»o\~Üàœ'Ïœêçœáò‡Ë|ñŸ¿çt¿Ô+›.º Uš°äñ®_tì5/mxrÝÜéÇ-½jjã¶íÆîŠÌÆÆRC± ó3-h ÷ÅžŸðÿÿÞyþCÎþ*ù¿vÿû_"§ÐïU;°?y&`ZéÄæó ï"£üù߈÷ÿÀú"ÿUÁÂØùtc´cçü¯ŒŒÝç¿$‘÷¿)ÿ÷<(ÿ÷oì€ÿ¼ïÞ…ç?ÊÈ÷€ÿå5°åýŸ3×N:ì"öšu§Þ·öÊÑ;×s\¿úÚëpùìcþù‹ÖìßúØ89q÷Òkï7o[ñ¯þâµÂ=÷}¾hý›/¥ÿrß —v¨Wp Mh÷óæÇ柸tÝ—£ÿqÏûg-“Þä¦6Ì2ÞÛxô%S¾ýàðcï:½2‹ß%þïÉÜÝþ/°<}þOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQÿƆHxdarcs-2.8.4/tests/data/braced.tgz0000644001765600176560000000635712104371431016175 0ustar ganeshganesh‹ÇvIMí\ pe?,U<EíHGQ>H(I›»Ûçímy”&-åhÚÄ&ÅÒ$Í|»ûíÝ6·v÷®I9žtE†A8¢ÀŒ@ÑAÁ(RƒèðÐòÔ* "SGÇ©‚ÿow¯MBÛkáz±fMrß~Ïÿÿû?¿Ý½*.V‰–IH0Ié'+‰ÌøÏ,+ˆÇñ"ŸM0,ÏL‰”ªeÏÇ.B‰BÙ(•pÙ${èW¯ý …ÊXîê 5Ø7ù‹ÇI<ÇQù \VŒåß L”¿ãžoX$]Ä^±anaÿå/ñb,ÿ¦`¢ü «B,ßv ÒH_°ÿòÏfy.–30Éþ±¯*{Šý—¿(±B,ÿf`²ÿ'zã³€}ÎÿX†c˜@þ¼”åß Dò_o(Jé@±Fœ„½È_ªÉŸi=ä,Ÿ@Ì¢g¦¹üCÁ'§šŒS„šýÛÿ3ö/öω±ý7¡àcûŸ®˜˜ÿé¶kb¿Ñkì›ýOÈÿ)¶ÿ¦ ¼ÑÛÿtÅäû?møuí_vʼn ÎÛ3pf_^¨•O‰>gÀï››¶t~ëßÇξqÇߟ¸Á~ õ¤»ý^»éÚîÛ®»á‹£+ï_µ8=5ôÆh,&Ú †k·Ç³F=ûØÝÿ§Ç€Øþ›€ÚŸB–ô¬Àj9ˆ2Gˆ¦c9«³Š" šŒu %YRNÖdVVu•Hª¤ð 'ɜΩLr@·íäRl¯ˆú ßǦƒKØD§‚ºÓ výbºdœ6oǰô_Ž•8‰c“(_°l—¤ü¢á-@"‘ á¢ð¢¬2<#æX]°Ä³¹¬Àˆjr%©ž.@‘ú°2—âUNÉI"áeQæ•\NR$×XÊaH/ÈYY&|VÎIY…áTÂpX!’Œ±š%ì´M€&Ú¿f}£B†kzш5êÙ?˲íôƒccûofÿSÍHŒ„Ýäÿ4üã’¡5lúçf\þÄ&Îÿ›ƒ½¿ÿѧP×ÿK“îÿ@З¸XþÍÀq_;,,Ì8ñ)ö¨ìa‰‡_¹çáì7_M|ò­Û®]¹mÇ¢üOž/ý®ç¡ÇþX¹Ð=3Ç/ÛŸK¿7xù/æÛ‡ð/ûù;ïé¨Ì<üäÕËfŸúîû/î¸ý\ Í;ñµ[oÞ¶ü\4¿¼â•-ÂG3÷¥K‡*[f߶ѺúÍÃÙtñÖ›§–ó{·‰dQÔe‘‘T‘°X°*hà DfY)+J¼¢b"`'f™¬Žµ–™œ”S˜8\£®ÿçùÉöÏKñóߦ`—ýϦç¬'óøD"ÿìŠË?5µTÅhönÿ9=§ÊJNÓyJ9,—y0n¢BQeXUÁ²ÓeE º¤È V±Æë‚¬‰¼˜Ó¹p`ÿ’?ÿi ÆÛwhÿýÌ1½±ýO¤3éÌéݶUè6¬‘´F팷‡O†²΂ 8ƒl6º=P³×¶÷úà»^ûAŠ=¿ÿ½óî*“ §9z²ºÂ)9põ9N9 ^›á æs/ š 벪rYY!œÎçr¼ Ê §ÊSÍdŒ=¢ò¯ÿ9ñÃù?'Åñ¿wþâÞä/˜£/zýÔž«Ïé½fsëõóO°Þx»í¨ëGÅ™æ÷ÞÙÑòçÌî»e®wÍW®×3üôÉ¿¤zƶþçÍ~cÞö+ϼ¾iëEÛ‡·~îèQõ™«Î½±¼ùÇø­RÿÙ3oŸÙòÕiýÕÇÑ¥§Ýþš"J#7vÜõ£¿ÞRø­rÙ5íó\­CîûΗß=¤ó–¾|]bÆIú£[nXynïóÏ>ñówæüWbì˜ï?4µ»ôÿ‹ÝÿÃ!–fX…­Qÿþ¯0ùù/'ÆùSp^òüiûì3FûOï|ü±ÖØoûçXNŒãSÛÿôÆîígîÿñ߬IÔ·N˜ôþ' b6¶ÿf`Wþ¿êÉSg]Â̾ìõöÆÓsîM=w ûØS¹“¿°qàþ_=Öyäs¹9l~¯e±÷ýíÛäìñ›¾ôaMîþ9÷n¾õñ£^xg³ùéžw³ù½ëè5ëÚç¼ýÒiGW½påüÞþÏæWÌí#òw'}DZå¹W§W=ºÂ)¬þÍ•Û}ëm_oËÛ÷-ì™uèMçï˜uÄ…L÷ßž=®G^]<ïçSº3Ó»ûþ¯iû{ù#±ŸïdƒïÿsÙøýϦ`wòW Ó[@Z£ŽüYN’&É_bùØÿ7-¨¿hxH7J©6dû†å!ŒJ†ç#[GdŽÑK ålñ<ö¼d[9ÄM¶@‹¤ZNiD™4—€CÂÖʇĂŒ`]ìy°¥òm˜$Zú7†4ìcÔfÙ>òŒv˜¾¿X>ÕMý.ȤCµ­),j3t˜Çða`ÀkG^ÙqJÄ„A°¾ ëÃ0¿ÆpúÂOg [#À¶´°ˆR0,‹2°Þv°…lÕ·a×!¨­¥a¦ Þ\ÖèL}„Ð]"£mR;ÒmvQ#žêŽÜÖÛÌtr0݆«‹Ú[iA1jçòÞèbWí\Ã…š­V÷t…¤¤V—t×.FIuÉê%áEÁЫKógDªKׄEó«ù¾žðbv«g-Z]8da¡zVï’…Kà Ó*T—¯¨]­Ëwµ:–Rp†ÌjïÀŠÎ¥½CË£jM¯ö.ŽÖu`†ÞÚ Î˜Zí='¢¨¨ÖWí¯á©ý5Z}C×Vûógœ±0¬ØPZ6NuMžnÏT›ÏAÝúÛmÜÍ¿D]ÿÏKlvrüÏrñûM¸¿@Ú¡ãü—ã-H&[Z¨?6¨u§hX>qA?àoX·m`Ÿ=ðEìR µŠj{ØEÝòÀ`‹Fkð7¥Ø¶O‹vTjA¶²Ž¨~4 4­ƒiÕÔh«ãÚÐBÉ‹f‡Vg8œÎ¶[Ç- ] .6è qqòâ9éq3–nÃ0ß FC=ŽÚwÁ·›¶V.‘tÀekÖÊ£h„¸¡KÔ( :@¹5Ù¶¶ši‡YMgÖ \y[+TÁàyÐ?œ† ë$…†…ˆmDÇåÔ—!,ApC¦Q(ú0P!hD Š’æ•°„K¢*l¾_„†¤ˆjºû”¸`ÇÆ BYˆ˜X…p¶W0¬çÓà®Ê÷Ø€jQ xе1x—$¼(‚_ õdT²ÃÄ;hðm»Dc¨U Õê¸Jƒ8õüàöÖäNÝÑЯH»nÊnÀÈÎ=Þ°^¥=»lÓ„Úî|_/²Ë¾SŽ´!ˆ¡]A5% kùª®nº Ž½*ü–ªž>K¯Žæ²:,h¬FªÝ¬ŽàÝmoÌó‰I÷HÅ .MP^J$<>.©)g¤ I…jøe§vÙ‚ >R‹& Ò ·#”¢i È-’0%€>Œ)¶6£×jŽ´eª­T/pÒØD/Tzi >Q`µHBí ZÂÅå’]¨~Ù öÖ4T×ölÝGë‰2.‰è@Ã+už_Ö ™ÄÇAt‚hƒÇºÉÁáŠo «hXt*!èƒ_…„ ¦]Rш“rIÀiz^Ø,Ë™B Md,•N¸v0^G2ˆÌ Èæ\P•qû_‰Xî:»/dx®xaÕvˆ4ÔN ænzMáÀ•]ÑÀŽ íï••hµšz«f~&qÕ²kàR­­X¨5 ¿V ÅZ­²Á‚ào0µZ[³¯«¶h ¢dXFÌqÒ “Q—8vX»6ªIûNÊÄF©5™ kÐβ30°@3€€CCóXe02µÎ×68¿ÚÍ]ñ<`ØS›õÖ;‘çYÞ?ž‚óèèÁóÇU¥iMÊÐv:%ÅðG¡I{ÐÞiøË‚ËqcºÀÁH‰6&ªix*xYl»LE2™ò”&ÐÎEË7D“&ˆK¡SqIà`¨ƒ‡úÖ@ÉÖÑΫ‘G\àjÒa l¢èœaRW–n&[Bòú‹eSñ`o:¶bÔ4ÆÇ…H4m´IåÒ>j.‘pÖf†¿^L+›NØ·:˜nW#íwâÔ¶]{„Dn µ-Ë÷À Ž0 ˜Gõ–v¦ƒÖc=ìÙLTô}gA&Cmº`Û8d€'Ì8è—©é ”S»dŸšŸ¯ TŠšAj}xŠL«È¦§0?·ÖiqßpŸ0±ÿñwùUá†þûòþçäÿÿ zÇù_S)Ú&É„_ÑÍPG•_,>Xň#FŒ1bĈ#FŒ1bĈ#FŒ1bĈ#ÆA†ÿŒ„è3xdarcs-2.8.4/tests/data/context-v1.tgz0000644001765600176560000001010612104371431016750 0ustar ganeshganesh‹žyÀLí\ |Õ¹`·”bêõ¿7Ð&ÝÌ{v €I€B0¨B^Ç™Ý!»;Ó™ÙÍÃE¬ZAÐkï¥ÒVЍÜÒúD¸¿Z{•6… ,*bÕª(>kÅ{¯µh½ß™Ù%KPö‡†M•ùC²3çùó}ÿï|sÎl,dE§$@à8üI ™û™EE±<”b)†)")Š¡ø"‚;År¹HÚŽdDQDJ ;úéåòåAaaý·©’¥Ø§Ì NJÿ$ ú§9Vðõ_äêßA Grôj3-ÝvôêŸ>°‚y–ýTýS£Ìž…‚ìŸîOŒÓ\ÿYMO¤U^¦9UVex‘gø0“r˜V’bI…YFcN s\˜cQ£9IãFREž=Ÿ¹ü7-¤ŠUàdü?+`ÿÏäûÿàxýã»_ûÈçÿI–é£gûþ¿¨ˆqTá ®Â5ƒ bÄMˆàü8]¾cÿ2ãxþˆ¥'"ýÙGþ3<ìeùOrðŸ£HÊç!PBT¹ú&4=† EP§iO JJJì Õ"¤„Jè Y`!ðÛ»Ž#U—äV´%DT²ÛQ,F”F¢J™WD“ÈjEõ±îï l¾42W%„!/BŠ“i2ÜÜæWq®iƒÅË´¹f›×œÙfŒÍéŠF,)B§%EðXl3”Ó‚žÐ ¨æènmHÇÕ5Ãr,)AÄ 5CGå€[œ “D;²wÝž•Ì-×c¥­éŠ2h5n¶A¿¶n$ìÒ±•ÇCy¯AB²Pâ[áQ‹»iR2)H‘’6"œ(ê"âz$ê@Eu†…@*,šƒg2h–°$(eAQÈðDÊHg çÎX—5åŠKŠ]N,’RôjR áqw5)F Š)øC‰I¶Ý« ÛUvL—-ÉÒ‘=‰ˆ^Š„3È0zgÇ*û·öÎ=¿×¦ži-ÿùŸÞ•V^´#õ·_mþuãYÉåݵÿGÁ7”Ý÷Ó¡ÖèËß=jÿÃcž?} 9·ûÑÕ­—ÏMxzFYåüu\óö ï±ϺuÏ›—½õßÇ|û½·k…Ìž¡÷¥øªQ ƒ]ü_ÍÅSÚÖ®ºéÖ ;A_rœˆÿ,¤Y)VcxŠBˆ¡$ZdiQÏRL8,‹”†\‘Te‘”À ȪH‡6¬i)KƒóòŸæ}ÿøïŸÿ½ü¿hûæW“Å¿üÑ”mkÆlûÇ ß¹|Í÷Rìˆé_ŸÁ6x³nçëí{ß:;q¸®§nÖŽ áÁ³ßÿèã‹6¯n,½®s;½cÛ-Å[»wÔU‡®ìÞuëÏGþø¢À¦[î~òOI”—ýqRí-+ï˜ûìÒuç&ΛòÔ9+v ¼½oΦ³É!¿¹øÅÖS½´»hêM;!§>‰ÿx3·?óÇÿlŸøãÁç!pE`±ÿ}ãü}ôsöqrüÇï ë¯ÿÏÿÓÇîÿy’Ej¿íÜþæ?Ç3þþOAp"ýËš ²F § ¥ FâH™!¹°ÂR"%Ë"KRˆãÚ³PD@)“K²ŠFi4í#¯ÿç¨>û?<>ôýÐûüǤ÷Ó¯Ò/Ó¯ÐèC›öm:H³û½ù»åç|}`eôqêp"þs ©ŠÊ€3Yà:¯p%ó<þ¡³Ï5Ëí5Ï~xþží©‡n»þdK üœúwV>ñvEÉ|‚ÝxÛ¦½‡í)~65{`äã¤p"þÞ¯„eûÈÏ®ïþ¯@úç?Aÿ·oüZ1üŒž[u³Ç˜òüH¥î’ÿY0õ7‡­µþᡵ‡¦Ý¾ÿÉ{ö³—×/¾•Žì-û¸âÆâ-Éï-¸f÷ÐÐë·¿øØ™sfϯòéÿ…‰ø/r<ͱ¼Á¾"Š” ‰ ¼*(¢FJ¤«Ò(âp <¯‘hžB¥XÄ)L¶üñŸýš'ÿ§ 8.þÿÞA:¹Ÿ¶_Íy8Ø+Eç ¬˜>NNÄÄȤ²´ø”B±¢¤A`¯„E‘×d‘fiAB,…Xže‘a‰9ð²æhB‚lyùO³Ç¾ÿÏÿ¼ÿ½ü2°‚øäò© ³MO¤¤˜ÞŸ¯€æ?ÿ9nÿ—üø¿ ÈÕ¿çö±àï‚Y]ýÕG>ý ¤ÐçüŸ'Yÿ· è¿¿ÿÒ¤'t'PãNѨ;Ž7¥˜'¾íMÝÅH²œh(¦O?ž&)øGS”@‡©p€¨u¿FÄß̘Hð’ *'òMÿ½0a*¨ C…YQ¡$)ŠHÓ$¯…%…V4VPä°È±Ök©a¤…U‘ ‹‡`àœH^ÿÏô±ú§yxðý!Ðÿ¯¹iÒ¥C¨‘×9òõËjÏ-}¦½æìýsˆE-“ãìo4îý·5ñµŸ¼®-ÿàU²íUÔ¹qÅKëß·ž;iÉs;?ð¿­™ü`Ë_ÿ û’ÁŸñà-#oµ^JOnrßo[ÖðÀ…ëî¬Z9z°?ô„ýËnºë*kæÖ#áY©Õ©’‡Íàžmc̽#ªÊ÷,[ø41gÈ¿/Ø÷â‚™å÷=½øîš;÷ºÿP õº­žzoêkç/yb]´èñ9WÜ8þ­Ýµƒ‡Õiño¾R±x_pï_©>´ìµÇ£?2¿æúAÏ<:N©o_}ûÍÃh- nx~Ìÿ&†_WquiüþŃvÖÿy‡ÿ”He ¶ÀÃz*ò4ËI”ÂðÅSªD*¢"k*£°É<æÂ £…e‰ªÊÁª‹9ÿûß9ûÞùŸ@ >ÿ ‚^þÛ¾qÄbäU/¯ùÅws‡œùè÷©Gv…']°tÂäk§Ý½ñá%ìß—<¿D¯{óí+¶é;ß]óîŽ#›¯ùëCÏìÚüöÒA7|4¸ý¬;nœ¹6ñ‡÷‚ʆø oôLÓ)¾zç¾ÀÐÚ)«²l÷WÌiùÕ]ï½—ÿ¸üå×¢£´Ü!½e89|Þö!ä—-ßZ6«ê÷ÿú»F‘ënûõ8T²òïEëѶàïvš¾´Èå¿fXqÉéÿ>ò?ÿ÷ýþ?#ðþþAà=óû¯€ž®8nÿïô‘÷ü_Èùþ· `þó”Ïÿ‚à’ÆZ6{Õ=> ¶s¶Öó«øë–}õê?ºøñk§ Í?¸¼±ëðÂÿcî]uÙ´PÑÑ3ÁÉ=³ð'Ž$n–ç-ªüÙOÿåÎ+—ÆÓkT>ýÎù±Ë£Ú__GüšâW¶ÎèÐe9ÖOXÚÇç†ËÿS¬“¼ë?“ËÎýûïþßÿ. ¨`le€« ðÕ!ˆêsl(úðáÇ>|øðáÇ>|øðáÇ ü?uã xdarcs-2.8.4/tests/data/context-v2.tgz0000644001765600176560000000623212104371431016756 0ustar ganeshganesh‹=|ÀLí\klÕ¶šÒ-D¢PQ/µ+ìà]Ï{vš;!5Ž ±÷ÎÌ݉wÌÌ®c³ Z”RZ‰þ  ”WU* ?*BŠR¡-âQD¡µ…ªE­ÚŠRzîÌl¼±C–„ÍZ(÷‹½;÷yιçqÏ™8 ¾×ÓvlÁTY¦ß¼*sõß5´ñ¼¤@/…Ä6ŽçE^iCò1æ+F9Œp€P[»$,~x¿FíŸPTÿ“&Œð˜™Á‘ë_ežé¿¨×DÜGv…LúF¶KšCƒ*X‘¤Õ?Ïóóô¯HœÜ†¸æ?<Žsý×4Ý+˜Š.Ȫdˆ’)*š"*y%Ÿçô¼`/qÉK¢%ª²‘—å¼,ªš%ÈØRD›š"«‹-ÃQ¡Þÿý€XÇb8¢ø/òàÿ¢¢¨,þ· õOk¦Òhÿ9ežþ%UTYüozŠžCzázb3ÈžãC.ðÍdÛ…Z‹Yl)Ž ý?ôÊAšú?ä|ç²  Ìÿ[ªÿÞàáQÑ?Z_ >IXèÿºØn¡™4ø¿¨òÊ|ÿç9æÿ-A;ê‹õ,»DP@ d§öf2íííˆú5Ô»&²Ýˆ`!ð™\;Ä´qDâa¦q8EJ%ÔY(]I ÃF’ÏíŽø3«{^D/½ôªyúbDé$зŽç Ǥ­~àA e/ZýÉd:Òë¨# ] v€é pÊú¹ºl×ò`XdïŒGC=nyA`9žY.‘|@‘¶ÂÀòN4E—PÒS5ÎâpÝ‘éÜ^íé‚Y膶ç†PƒWAÿdB„➡ĵ>ƒLbár jˆË!AQ‘Ì Ç.#¨4踢¬…%ÑiQ€¡W]¡!a)åš®>e.^±™¨è¹Ýˆ8Ø»Ñ\Á@Ôdx&¡rόޕ€” úe”pÎi"Œ•]²õ6 W£’—Ô`*mˆ<¯L€ t¡:aXWÉNR ½j ~p-µ͆E(¸–](± ÖxvÚ =û=ÇÚM#ÃÈ+G~9µªÔWSú‡.îßD Z8¬Âo©úµ¬êμbÉØbõ²]2ãî>6¦p®v8ÂÞD×ÈÀ:.d¼” Û…PV³þT!›° Õ!‰Ê~­ØŽ  QÒL'I™vÐh ¹UfMÔuö0£{æ ŒÞnÚaÔÙSí vË‘G1LŒ‡)"  lIb=qKBD.y…*0•Ãxmۼг"4Mt ¦N-¯Uì° Ü…QÙ´=ä›8”OP­GšŸ¬Dö¤á‚õ'—~%vÄq)”06ž HÅ$~6 ±¤¹UIð¬t -Ä5‰kÐ ·ç’rªƒÔ ¨Ò£L¥ný+©Èý—Œ$b‚Ì•Ð.¸`íI‡ÔrÁ쌩xîv¨‡Í)¸µ?Ø]¡ýòžR«ùaXqkîçÀ(6.ÕÚŠ…ZSÁŽj•pY«Õg`>ã©Í‘þÑvï“Iu²gÖi –ÖÐ 5©ÝžÖdij”u°]êÈd“¬³ìõš60Ð;1qn¬· Nf“ù:ÇÏ­v§sWÂñŒØgÃi?'‘M};ð¦H¦PçàÀäÏ Ï'I ©ÝÒÎtÐ4¶’žÝ AÅ(ò{{zh°Í<¯P"9ˆ„=~ôë©Ù \gçtŸ›87[o ™uƒìth¶“I‘¡Ñ÷ jÖLŽD±G¾ÿ"ÿÑHѼ£AþÇ ª:?ÿ“èó?–ÿ{´£Q8Ù%ÙØ¶C„aŸ#äY°¹D4ÒSç-”K°Ps» X¼çDCIœ(‘Bë’‰Àû‹`ªèfˆÝ:$/èÔG@r2ìŰíľÓG±BŽD·®Nº±FÀFL?Z„ `Wë„m]Õ“Ø&‹:m‹È€aì¾_" úЇaQMàô…Ÿ>kS± R’ýÀ%ìæ»\*À´ â@ÒåÁ ³>Aí]q>”ì]&i„¤ùs§Ú'°ï’ÄsévØ`1s4µÁÕu]4.vêŽ_íN ³Bµo›LϨ®ßÒŸ …«nØT+@ ¶áÒ I¡`[Õ¤…ÙêÆmÉ¥ IÚÀÈ–¤°Õ ×mM >Y[¨^8¼aíÆ¤Âq ա͵BÜ:4×ê¹zÁŸpªÃc›û6O ¥Õ¦U^ŸÒõa†áÚ þŒQ¾,帨1Þ¡:e"VGk¼F¶e­­Ž\pÁÚ¤b¶š¶ÌÚ~uÛ]žÅvŸO<ÆÿôhBšD£Ñý?NšÿOávþo ØÍýã ýßñ"³¹4úÿ‚÷$º3ÿoýþO‡EbNÚn…Þf>FúW¹yù¿Àñ"ÓKд÷2c¶kG™ñ2¡;аããvÐyÉÒOàÈ\Ì•ì5«V‚áŸÀóªçó4§ÑYš™÷"«*gÊš¢S-Y!šdpyM›QÅ|>32Ô@{Qí©òYlXRQ—ˆ`‰`PØT‰hœ¥H‚Ì˲"pšb‰ðeè8oh”J2cëúú‚{‘ŸÇ=kȉš¢Z†¢Ê"á`™$NeMTM,ë ¹—Ä,oèªÎKÀÏ"òXÐ$€—‰‰u7òЪq¦®qXUxÝÔ€¶”·,Ìé˜;ú=ú øOOl¤ùoùûŸ’UìýŸàPúo¢aÆ4ÅA8ðüOâ9ÿešYüo¾xã‰ÉÅÒ³tù7¹•çÿáý5ýèìÇþ÷ê%ßá—\syEZ¾á³Î Òðÿ2ø›ÿÜÞ÷çe›Ýw÷ nzâ&O}蔽ÿÁYÞ:ÒyÝÎÇ…'Ûµrï“÷zõþ«fŸºý'+n9+óà®ÝϾôW·»ë·«v}ÿî­/_ÿãϹ§¯yî´ŸRñÎë-;…[úðýè§gÏý·íµgÚÖ~oqä8Ãáü¿ ÛjL£¡ÿKÂ\ü硟ۻÿÛÌùÿWnX½|/·ò„÷¦3/Î|éß§}°¢/úÖ®S/Ê¿tCö לÚ~ÿ–õߨìúá£÷ܼê¶ñÏ vÜ2ºûÖí¹GnxûW“«—©/¾´/*ž¹ùåÞ§°ïº3ÐþÎÛÿó{ùìê»o{áùÁÝ£?ië§^yõÞ¶ þìZÞoú½³ß:ÿwïœóÏ+—¯xí­¿«{Û¾–¿³íí¶/ß¹äù«—=sÿçß_¢Ÿ>zóîÅ]œã‡òú0×v ¹çÁI£ñù_š—ÿ©²$2ÿo®È\ÉnðÇ8øþ_r/ —ÜþiÚ9ðÈÏôxÁέÀáô߬ÿÖ(þó‚\—ÿÉôü§òìü×Ìå'?þÀÉ{ÐI'ì¹Ýö÷xk^Ya ~õ—­}øÝàŽ‡~ýÈû×ßõƳß}ùÚÍßÚvÒ/… ]ôÜ´roùëm—]ó̲ܟîúý“Ÿ¾hóÅ}›W†#Ãáü_ƒC,)Xâ5CÓxk*ɫЩšÅaêM™X¼¦2E±8n‘Âä%"bFÃüO–æù¿Â©ìþK0çÿâ›ÂÂ>áò7…òB¸OØÿàë¾)H¯/i;ãÄ·ÚN_\6ŽçÿDÔ9C’-o¼ÁK¶tK2òš¦Xº&H‚ЉÄI‘4]%Kš qBWó² CJP£ÑÐÿ…yç?Avÿ§%˜óÿ¥‹Ëâ Þÿ›ûÔGüüŸW8ú÷_˜ÿ{°çÿìùÍÿkŽo7ù€£¸ÿó¿ÿÕÔëßòGͧÑ0ÿãçÇQUØû¿-A²çg’7Ù»¾ÇbÿŸ¶u½Ô¤?öv4ôqÁßÿ“Tvþk øŒ3ÒºŒÜ—Qú3j&ŸÑ2üÇH(Z†ÿvåxdarcs-2.8.4/tests/data/oldfashioned-compressed.tgz0000644001765600176560000001007112104371431021542 0ustar ganeshganesh‹LŸzLí] xÕ½_@ÄF+Ä EëÔDI ÙÌkgw£I !—ä*„83›!»;ãÌlHÂ"‚µ´\mo{A¸¨¨Ø*X¯½¨µ*BAð"Å|(`Á¶ ¼¬r?¤½ÿ™Ù…¿t³4ç÷%Ù™óúÿÏù?çÌìD K2o4(jIù¢ÑtdH*ð\@¿´>©vŸIx(Še8å#)ο$G{ß…d¢#Ä “× ÂQõ¨Ì‡ÃµKUÿ5…Úüë%^ £iÈßÏr~¿Ÿa(,7Bþ&Šš¼©4¡z%ÚǪޒ> KÀÛ±ü9–;Wþ4Ã’Œ‡ /üt¿Œn.ÿšf‚JDKF%2ub¢*6ò q[LÎ×Eæð¡Ci’"ÉÓÙde¡¨ª£|³A1 Š ÈˆgY¤$ûy_áý*Às )“Á@F‘Q#Ù„P:„(ª!Z$I‘‚”ÀRAZ$eÊ y*è‡NïP*àÓ¡E³íh!D‰$ÏÐë÷Ñ"CûH?Cù)V Ò>Ÿ(mbÕEc“už#ÛOJ‚Ù™çó}‚Hs>žFb€•¨€?@>kV_üSØ?œÊ]ŽiøÖï·ìŸd}Øÿ»‚NÉ_P¢¼® ãa«[ !ñ&OäDU“0\¾ºˆš–*ÐîÞ¯£¥Iý$rÆQL 0r #¦iaN@_úÐÍLNØ má§8ÌGíÀ”¬Èa )Ѩ5é L‡ªhª0Š®!"'+—àuÎvä’5RBÖ*¡æ.!«:¬¢„ QW4f›j1½µÞ>^”›m-^\^™8i¥ãÅShçDRÅø¨ %Î ‹ñÒñÉ“f/T꜄9>¦ltâ¤5>fŠs¨j¼¬j‚s2×ãc‹&&N44"[Y:bŒS‰†âåÉ»¶ül­VBZ]$^YSQ<¦²®dÍÅмmFP¢² ÝL¥Ùî åVwpÔ¦¾=¢J±0:Üf;a-ÖL4"=Š,ÒIÎìpœ‘35^ £F´z k»òœl(‚ÎC¡½3 *¢CL±#B€Ø†d>†$ò1K[ˆˆj0¡£€ˆqU€+‹5#Ì›v¸Ô!ªÂâ› Pá°”àÚZ}‹9{ÅZ BEóáEgÓø&è™Vp—5ï–Q­³fÁÃúÃÏJÂHD@A·#ê­DXuJx;ÞA…©ªa+†FCÖBå@·8·‚8õ0üð¹ÙgtG"Z+°ËJ(¦Û9³Æ­ÓE«e‰‰@éø²ªJB™Z,¡ v -±‹-JÊÿ­d¼EÜU~ÃqC%Ç›œ $mbJعÎÔx¸ Y«m´&ŠXk$ò>Gy-6 á1Á®Áýi¡|‡U(6Ó’§Y´‰‚K”ƒ8„$EÏs¤FXi È-!a‹uúÐ"¨R ôž*A:’S϶ô‚A‹h8ÊcFX(x±9Úc×8ÄaÊa5̘a¯mDuÕPe“˜Ž„6IDѤ1àÎ0c’¢dòv|‚hUK µõM¦R/FAûC­É6ĵ»£cµ^5IHËב=SïP§X– 2…+‘‰ŠÖ€Sk½ÎyB 3°³9T¥Íú7%¦\rg•3M˜s“áäPÙNƒ„æ‚Ú‰öØYP‘Èé8±$Ñ1¯ÉjoÄ„µ¤MѤùE.Æt…'ëBɪb& á0Y*´êÀüµ‡“4«J’D³;(:ÅN€l#­Z'Õ‘¦:¥S%ù0}-?Â+áìŒ|§DíŒi55…’ ÖÕ ³E‘‰ Îx9µÃây‰±› & Óm›5¦k ÏS^Ý–ƒVïÚ™mмVI¾"qJ‚b6"d%ív}±b޳OÛô)BU(±0¶P#Š!‚—å£HY¢t&0å{-ž¾Ñú(.g»!+ù'@ãÀù°ãTtd;ËÁCy¶­dӬƓé0?(ñ:G` ¶Î)Ë•ƒ¥G2j³öªbÁ€µ¬¾MJRcL>”MŽuIå˜*Ë\©™ZPgû%ðbR,¢9mãµÞ\1¡}àNLŲm]mD 7EäŒ+›4¸„ÑãÀ Ko­ÆV§é¼ì´ÌƒI ¢Á4µÂ‚ËÙzCª‚‹ ð„Z´+Hê 矕½·nX~[M8G¥,3ÈŸî\Eئϋ„j]½€ùéÉF£ªê«L{éÇÿNåÕ”ºc¤ÚÿýòþÅÐÎÿÜ@*ù[vŒº¸˜öýšôs$Þÿs”¿ß!±ñž¹””öÏ´—?ËÐøþ+¸ñ߯pz­8øôžžãÿùÔ_/»¸,a¸o·`äx5¯D¿"IßÁ'Iµ‹$Eù8ÊCŒÿŠø9Iû×UÕügíRÕMÑIÿîíß|Y >_‘(úEÙ„@@â|þï#EZ–X™¡Y‰gi? yÈ„[/ö41:€òOÿi†>7þ3d€8þ»³ñ¿|SÑ•sÈþž½§N 8–a–dn¾Æ|èê 3ß\V1éòÁÛgõí[ôbß53Fêù£{|ÿ1Îßkòmñ¥ò‘«ÿÚ¼¹ì–'ú®žÒ—y –úxZé}žÑ£¯¾oÃðÃ?¸gÇŠÿ‹ýã^qFÞð—û/bŽýÀª[>çåæ^wBزÁ<=eåU«w>ÿÅ/Œ¥_Ì©úcÆþœ“¯Uß@š›9sËúÚšá÷ÔýcL]Ï}ÇK<ú»ŸÍš±è)öÛƒ¾£÷\{ýë/휹xÉÖq×kWö)™6tͪ±¥5ýߨ^Í^[tÿâŠmoßû_ê‰^'\׳=.î*_ºHoÿïüh¤¿ÿW¶7€÷ÿº7pþóÿ4÷h6‘ÿIŒì§Yòó‚?È2b@XšŠéZ»?ˆç$‰$Îÿ/]¸!ÿÔûlûý? ßÿsmöÿ¶<—ñ*Ùï¾}§—î?8/¢—=8 ó.ÿ=æf½´k÷À¤!Çö ežÚ7øïÆÊÁÒùóöåÞìßú‰vëæ{ëÓšnÎ>ñëœ;”åoW7ªy“_Yç+Ÿü°±{—óØýBɰC7ô.©hy|õ Ënù¨¸j]ï_¡¸=Ĥ;ä¯úü­Y×øòNN8ðËã;‡üÞsÚËl\yq—¥ÛÇÿÓôÿTrÿ‡¢(Y}¿ìç‚<¢Š•%–â2 Ó”Ÿ ’¤È38þ_ºpCþ)ã?éo¿ÿÇáﻃ³ñ¿tƒÿ=ÛN¯ÙpÎ߼ϼéÄÿìéϬåf/*ÿbú˜>ýdŽ÷[CkŸ¿ö÷Žê™?Y±ôÚzxyù” åâ4Zlùs«üÊë‹õíå37|Þ£œÈXòâá/l˜ð»ÙcÑìMG¿ûÝ“=†ÜôÜÝ//˜5`ÍÑ^??=gõì‹»Ý)ŸÿU S‰¢.=jÙx§ßÿ‰?ISVJ€Ÿÿt•W4 -ù[q‚¦?ƒåï:/þ¼i¤Üÿ'éöò÷ÑøùWÀã¯PwktÖþÏãµOg–ýSvügœÿ»‚lÿݵÿ®¼ò¼ò?üþGWÐyù»œÿáﺜÿuotÖþ›»@ã¼ò?Û¿hÆöß­‘Âþ“oýUºò€4ò¿ÄóŸççpþç.ûÿì—ïÿûðý7†ýãï}á†üSå´ŸiÿüIâ÷?º‚6ßÿÙB]ý*y•ç•ÕϾöàeïVìXÅ÷îäÖϸxïÈÞ«&þÅó‡>ÛŸüùì[×<¸*tâן~zpÛGXùô¶?´û¦ÏO=¶“gÉ$Ffo¸û†w7öFÞ9ÿ-·uÁÚÂk,ûä7ÿ04ì{Âü]Å=~¼sSõÆ;fÝ´¾lÔ b÷úE×ÓËó•ÝXô%c?üŸù÷LÙ<⺗6-Ÿ7hýÄçü2¼©ä¿nC·1ö©Ÿõè9kÙÀÛñz. RÚ¿„ºrég#•ýs4Ûfÿ‡²ÞÿÄøðû¿]ÁUelòx~¨zÁ/õjÏ­Ïï?’ytaC¤ôÙ÷ûÿoõÃú<؇ZP9wåÉ%¿3ÊëñôLô»ìç­ã“ýnýÍŠ–¾<äÔßÅâÃÙOeÿ;5¯­;´öÊŸ=ð—+¦n9Û¯g›~ÆëIOÎýUÙøÇi²ª‡0çÄ®7—o6W´ìyìéï­ÝF ‰6|^{G+Éì¸í®÷ä?\“õÆ”û·¢cÏ][Ö÷ÑÙyìÃý³ß…ÎÒ” ×~çÿä7Ýw;uùÔoÜvtÄŸbß’©{g¬níûþÝë·Þ¼qt»ÞóÓ¡)¥y]:4»²ÉzžèdüïÊí¿”öOµÿ4ÅPøþŸ+¨2­·^&_roò¡ÂoÀ?5Áè4RØ¿¬ê¾«×½)÷)ºýÿñ1øùW༘ò’x¸[¢Óÿÿ-y'èvûÆ û=U §óà?r=$"!r‚æ)&Î h "Ë(Ogœ‹`òEüó–¢ò?„¾ÃÿÆÏ¼eËc좥ÇùÄ+û¿rû¯ýËÞüØóO½é¯—ÿsË#ûþì»å_Ýù®}¿täÈþkî'_ó5öÞßûŸ+6Ýp¸°ßÕút6þíKœÃ:àüò¿Ì?(޲æC¨Çø{.“·ÌY)Pt!h­)€× ócVþÇ«ü3‹NÉExQZm•Žc–ü¿îÿ £ÿ«eþ?¸–ÿãÚØœþÈ»+ÿãUþÉ£Pd¹s‘k“·¥Š¨Œä¨"7Þ©éÕÚø— +ÿC¨ÀÿÉ"ÿ²ÿW'´¡ùäÆOýaå¼êÁ^Û;âÜGc+§´Êá¡ÞëlNÖŸïþAÝÿDþËÕÙ‰ÿ''´¹W}ím•ÿñªÿG%íLâÜ1å†$ã‰yí3³Úº ­Žfê3ΟÉdõ¢.ÿûËõyßZþÏL7ÍM+/Kå¼êÁ²F€h÷ä8’Ì1í‚QÞFé¥õVóµñëðÿÖÿuÿoø/×ÿåkø_969¼ÔüÂu=Yù¯zð¸5Vú–ü <Šü©Q ¡­ˆä5b\Ïþ?ï¬ÿëù¯aTÈÿqJ°Ö¸rjBý»~ó›ÿ@ö‡¨šY½ÖÿJ9L2 ®”²Œ&<€£2­ÖÉd„b:­çæ­ÿ…ªùÿ *ñ?%Ø»v€Çò°Ô¼î=òQuaŠªYÕ'þ;%œ2ÀŒ28g„9íçà‚Õó¬À‰%=ý˜ÿºÿ7Jü— €²cÄ6Xlþà·N~¥ò?RõÙÿ\*žç/‘¸&Í÷•³.ÏFkh®ü#Õõÿ *ñ_6ÊŽOdþ75}ø¹³LþU/iõñÿ‘æY»Ñ/” ù^æÔßY•D Ä€H ÓÌÂ?«ùÿ *ñ_6ø?ù_hhòß?Zù©úäÿ`mõ!ñęДàÉXëó„`¬à½‹Öãÿïœÿ¼æÿƒ¨ÄÙ¸Ò1áñÌÿÆæOß÷Úg+ÿ#UþM»ÚV‘El÷5$ÐÞ8N&)ƒÓùËsÝÿ“y9Qù@%þËÀ•ŽW3ÿšÇÞüŽí•ÿ‘ªÿ—ië)€ñ™v ‰XLcÌÔƒq 2žÏuý/¡žÿD%þK@`¬ÿOfþ77Í#½ªò?RõéÿCJ£$X”KÜ÷Úq‚q10j?N}Æ,ûÿµþ?Œ ü*Õÿ3ÿÝøfB‡šfç/ø›•ÿ‘ª—ÿ/‘tIç·@(&´5m‹VeÐ!#‰>h³žþ_…øÏêù¿ATâ¿TÿÏ#ß1:–ù_jÝóåÍ•ÿ‘ªÿB UÈ‘Kæ¸Eò2FÉ#g 2ÞFçšÿ‹ºþFþù”ø¿Ö,šPÎúÚræý•ÿ‘ªÏþs*f8¹†(B²‰ÄÌój]ýºü×ýÿaTâJü_ëÿ•<ǾÔüû¼ú¾ÊÿHÕ§þ'ë ó @(E>9Ðy%àÃ<Ää÷Áy5Ý>Cý/ÿe啸/ùÿ2ÿÿ/oãÿbóë—ýŒ¬üT}üR+ä¸pšP'éì ‡¬ ÑD&ÚÛ_x²ëéÿÑÝÿS5ÿD%þKþ¿ÌÇÿËOdþ75»ŸêâÊÿHÕ§ÿg4àEpŠ{G‰YÐy!¥Š‰¥<ä¤@Ѻút÷ÿdíÿ3ˆJü—ü™ÿŽÿŸÎü/4¯ºu߇*ÿ#U¯þßB8gdÛ”ƒ„u/TübÆ{2÷ t^H7õçæºþŸšÿ¢ÿ%ÿßÂAw)ÿÉg^úÕ¯>ñ̳—^ü{önÿÔ¡½ÛøÌ 7WúG«>üK!I§ h² ´ ´ÎÉǤƒb ½LÜÌ7ÿ¯ñ•ø/ùÿ€íïÔÿùjŽÿšÕç¿ëdFª>ç0‘2&0ΘÒÊo-bâÈL ’¦¥U¢škýŸSõÿ ¢ÿeÿvüüdæs³zâ¾Ã•ÿ‘ªÿ‚Zd:£iÏúr)CÎýc¤À¢àΑËÿbê3fÙÿ§ZÿDþ–ëÿØÿg&t°i^óÝ•ÿ‘ªÿW*)´O€3“‹N`´½³‰XRFðœþO¿r†õ?ñÿQ‰ÿRýá§lyí¾»¿¸åW¾±ëë_ßò7ú­¯¹ùKoýÝæ¦­ÏÕÝ¿ñªÏþ?—&/úeã$·ˆE™ ÊzÓ†y~¾ûÿXÏÿ¢ÿ4%þwüOMršÖÐÕxQFª>÷ÿ/¢v*yn1ø ´ }b^xå89¿ ~=ñ¿“ÿsUãÿ *ñ_öÿaÇÿGÇ2ÿKͶ}—ì¯üT}öÿI)‘¬Ñ<çÿóL¿Ž.Ù˜‚ñ.ébdÓ»@ÏÀ?`=ÿ3ˆJü—ýØñÿQÿ›×?tã%•ÿ‘ªÏù¿¼Wž¡"n@G@$ïæW#c˜öš+7Oþªÿo•ø/ûÿ°ãÿ£™ÿMÍç–œ¥ùcÕKZ}ÎÿQoUA(J22fO*ÇœuyUàµÕ$ÃÔgÌ’ÿËÊÿ *ñ_öÿaÇÿG§3ÿ ÍÊñG®üT}úÿä´ŸÛ)—1Ho瘴Z(ÏyÛØ5çý¿šÿ¢ÿ%ÿ°Cú?Ïüol®ù©·§ÊÿHÕçþÆ„ @ÒsÃòªß† ¼V1J‹Ï5Ì·ÿ=ÿ?ŒJü—ý‡:õZÍüoh~|ù_¬üT=ø×‘éd…Ô>Ieä˜g¬ñµ!r—ù—ó<ÿ‹²ú†Q‰ÿ²ÿwãÿÉÌÿæfûŸ<¼£ò?RõYÿ‡öôŸã<9Æå×ù<ä?* ’Hž póìÿ+Yíÿ9Œ ü.×ÿy7þŸ™Ðᦹü–}VþGª>ý?´F1µ%@£â)y“¢±FP’³ 10?Ïû?$ÔþèĹþÏ;ýÿËü/5ÏÜú¯Ë•ÿ‘ªOü×Ñ92qó{ …ä^sÐ\X§"9§ óóÜÿG¡êù¿ATà¦Äÿ.ÿ§&y›Ée?WûU}öÿ­@Š¢²ò¯¶9C©0D«ÓÒ†œ˜¹îÿ×ó¿©Äÿ”øßñÿBŽÿ°Ô|né™—UþGªü;-˹ÈXZáŒQÁ;ä*¯ü¡=HŠƒaÁN}Æ üs¬ü¢ÿeÿïø¡ÿ‹Í“׿û¦ÊÿHÕËÿÇ™É!_«¼ð—^ÇY"­#€iRŒ™à“™ëý¬Þÿ=ŒJü—ý¼ãÿ…™ÿMÍ—–cÝÿ«zõÿ ĘG%´cÞ0®£4Š’Ë€veâ™Ý8×û°žÿF%þËþ?ÞñÿÂéÌÿB³ßû\å¤ê•ÿ[ß6üíe¬ï¤ó–„ÕFEâÎh¦ø\û)VùD%þËþ?ÞñÿÂñÌÿÆfï'^ýTå¤êãÿñ:ã¢k/Ã¥IdÈðÄ“O‘¬1j®çêùÿTâ¿ìÿ;ØñÿÀjæCóé?ºzoå¤êåÿ <$ÂÈ£3ím_“u¸‘A@ž4E˜gü— ëú•ø/ûÿvü?p2ó¿¹yä¡7½£ò?Rõ¹ÿÃJo”gÑßÞõ-PSP1ii0€7d ÷j®ü#Vÿÿ0*ð \ÿ§nü?3¡Móô]_¬üT}öÿ\ÙÀ| –"7ZAD05@T<͵þ/°öÿD%þËõêÄÿÇ2ÿKÍÓü¯ªüT}øg1¿Az‹Ú{Ñ{î"³1®µP •Òóìÿ…µþ?ˆ üË)ñ¿ãÿ;pjB9ëÛõîï©çǪü#µö42¦è„û"h@B)Y¢ólàyŠ>'ÿÎz¯ƒ#çÚÿ“Õþ?èÄÙÿGÿŸlãÿbóÞ#ÞVþGª>÷(© 2ÂÉI¡¹!æt.§&ok€Âé0ßþœjþ?ˆJü—ýÔñÿÉ™ÿMÍ{žßJå¤êÁ¿šöî4KŒñÚ€ÐQ1í9zäü\ùÇZÿF%þËþ?êøÿäéÌÿBóo~øHå¤ê—ÿ;‰6¿Ö©öC{ x¤¤˜‘L ˆ­bžþÿÚÿo(•ø/ûÿ¨ãÿ“Ç3ÿ›üþKV+ÿ#Uþ‘òZ?å?³’¡ÕäÉd “ αöXš©Ï˜Åÿ[û £ÿeÿßáNý_®fþ74ßûC?òÉÊÿHÕçüO3¿<‹BHÏYrSž@9¥X4ÎGHSŸ1KýÕý¿ATâ¿ìÿ;Ü©ÿË“™ÿÍÍ—]u–Å_ÕKZ}â¿Fix†=dîC L$§h”ŠN‚Q†»yöÿB)*ÿƒ¨ÀÿJ¹þÝøfB+MsùǼ§ò?Rõ‰ÿÖ ‡Ð¶eô Ù< b¨óÔ,*­æZÿ粞ÿD%þËõèÄÿ•c™ÿ¥æò÷»ß¯üT½îÿÌë}”Ae^+oµ@Úߌ@·muN¦>cÿ¯¨õ¿ATà_L‰ÿÿßÊ© å¬ïŸ&߸¸ò?Rõêÿ›r– aÚ«þrª/, ®õü)æYŒŒe^çÚÿKòºÿ7ˆJüO‰ÿþEŽÿb©yù®ýµÿÏXÕÇÿ›×üN²öšOÉlF×Xc„`Ô^ü¼ 1yai®ü«ZÿF%þËþ?èøEÿ›´ó?Xå¤êÁ¿Á xÔž¬±ù}@H1ð1E«7õ³äÿµÿÏ0*ñ_öÿAÇÿ+Ndþ75W¼îêÚÿw¬êsþ/¢OQbÒ< "Çþ”ÑÁ8ˆ8 Љ¹öÿSõþŸaTâ¿ìÿƒŽÿWœÎü/4îƒ?ÿ‘ÊÿHÕëþoãÈ«¼æ7.grÜ—Â{ßvS–¥˜Ý\ïÿf5þ£ÿeÿtü¿âxæãÿ²w¶¡ºW’{sb#¥hT’`i+b%¡:3k­Y3%Aµ¡¡ õ‹Z)Ô™Y35¤5µ 5A‘Z_ÚøÒF¨Õj„¢Q¼ïKµÖT(mO¤’˜êMnî½Æ[_gßÇ/ž=lÎÝlÝ0ÿ|yÎs›Ë=¿½ÖšõŸµ6·úúüŸµjÊù_¢hBJ*Éâ(%[¡M˜‘½+±¨à£›•c»ÿwµøoûÿôÈÿ ç+ÿG6¯ù÷oºÐù_©¦ølÎì<‚èà3g&ã :ˆKîCô¹À¬ýîó?—Q‹ÿ¶ÿïøÈÿç*ÿWo~ú_~ªÏÿ]«&ÍÿUb€E¤xñ†k@–HÄ©á[  ÙÌZÿSßÿ¹ŒüŸl÷ÿü?pqßžÜlnºù½WuþWª ü«Ps}-9"g¡&Þ&?¬et‚lL«gåߪÞÿ[D-þÛýÅÿ“g+ÿG77~~¯Ÿÿ­USæx£ K~À’Ѻ–.QÔ¾B@APÁäfíÿc¯ÿ—QƒnÇÅÿ“ÏïÛ þmñù—wþWª)çV‘@À°æýÙúì¬ÑÈÛœŒIà Zγîÿèû¿R‹ÿñäÿãÿùèæ±óõù?kÕ”ý_T‹Í:Cȉ#—àŠ&ô‘29/üœ÷ÿHé>ÿsµøoûÿhäÿã!þ_¹ùÔßþã5ÿ•jÒþ«”씯y>¡WVŠKì}ÎCS@ùdk°›ÖÜÿuþ—Q‹ÿ¶ÿFþ?~®ò¿·ùćnîóת)çÿ±Æ÷,5Ê«à ggåcE£.1c"§Yóæ~ÿµøoûÿhäÿã •ÿ+6OlÞø‡ÿ•jÊý_v…ˆ-~°#zÉ’Y§R‰Í%øXæÿEýþï"jñßöÿÑÈÿÇÏVþ¯Ú¼xç}þÏZ5åþåœ0¬•¿W BÉm`ÅVD‹Þë<çþ/R}þß2jñßöÿÑÈÿÇç+ÿG6?ÿî—?Óù_©¦œÿ1Ö¼?:c-Öâ?؜Ƀ3Q‚È T 4ëü/æ¾ÿoµøoûÿNúÿ|®òõæéûRŸÿ»VMá?Q-"*J²²¦h´Þã%Tì ´-ŧ9ýÿõ=ÓëÿEÔàÿñvÿÿô¨ÿÏ÷íã›ÍƒÇÞù]ÿ•jŠÿ¿Î^é"!S}˜”ìPXÏÌ1Û•Ÿ×ÿ‡½ÿ¿ˆZü7ûÿ¨Fñÿñ³•ÿ£›/Ýù«½þ_«¦ÄÿCú©V¢ '²dÄ$ö&[ͨ XLvç3ãÿéó¿—јÿcªÿQâÿãÏÿF8òvþWª)çÿ~ 7y!!RPѪ½Ïœ©Á:+·»tþu¯ÿQ‹ÿñÿ ÿç´:[ù?ºùóÇ~éuÿ•jŠÿ—Ó&–TßlÐ$—½3™¡~É…E“šµÿØù_D-þ›þ?Tý?§Õÿ¯Üì_Üül祚Òÿ+)Ö8ÏÚŠ /ÌÖFçÙØZ )”\lõ¬óÿúüß…Ôâ¿éÿCuÐÿsZ=WùßÛ<ùÌ+ëü¯TSü¿ •OÈâ¬-Ã2B(HP”b‘빤™ý?Øý¿‹¨ÅÓÿ‡ê ÿç´ºPù¿bó}{ééÎÿJ5Ñ1›P¢©+)*HÅ^Rò˜¼%¥¨f;Ÿqÿ6Ýÿ·ˆZü7ý¨úN«g+ÿWmÞ·yç¿uþWª)ó¯_ ‘¢ñò¥à!…aú—TÙÕaÎüŸêÿÑù_B-þ›þ?Ùù_©¦ìÿIè dSé¬\ DU¤HMû­Éµ à-;˜5ÿGîóÿ—Q‹ÿvÿÎÿ9}ìlåÿèæ)~ê ÿ•jÊþ¶²)’rª¨×× ]e ì0 ,óöÿ¨÷ÿQƒÜÿGþŸcÏïŸÁÍæÔ-×>Õù_©¦Õÿ‚I"1¯©xHÑëÿ,£½slí¬þêó—Q‹ÿñäÿÁÿñèæsúí¡ó¿RMñÿ•”ÙD–¬wÆ3 b±Þs±¢52 ÂÎgÆÿÛûÿ˨ÅÛÿ‡#ÿñÿÊÍÃ÷ÿèßuþWª ü)qræRËoØø—%”0,ÿóY'(õ=PùN;ŸqˆþŸÿQ‹ÿ¶ÿ¯Áÿs•ÿ½ÍO¼eï×:ÿ+Õ$ÿ_È ¤Ùë!G9aÔœÀ(; Ev<'ÿµþïóÿQ‹ÿ¶ÿGþ?¼Pù¿bsîëþál祚ÿk~O¶þPŸ¢-Å+>CýàÍ0 , ÓÁwÿ ‚ËýüµøoûÿpäÿÃg+ÿWm¾åƒïý³ÎÿJ5“µ6DZù ¬QÙSpÆHÄ@ DR!Î;Ÿq¨ú¿ûQ‹ÿ¶ÿïÔÈÿ‡ç+ÿG6ßøÀ÷~¸ó¿RM9ÿ¯?«Àµ °1$e¼¹4 <"z'ÅëZD%³îÿ®¯™Îÿjñßöÿùð\åÿêÍ7üÑ[oëü¯TSöÿ%±A’1zpýQ4E nÀ¢œ3R(®fÝÿMÜëÿEÔàÿT»ÿoÆñÿâþ™S›Íyé3ÿ•jÒþOÒ.TV SÅ5EN–ê§aìŸ@4$ó¬õ?˜îÿ]D-þÛý3Šÿ§ÎVþnî¸ó›ÿºó¿RMÙÿ㽂Âl¸&D¬ëÛÀc ‹7ÁÔA.çþŽ÷ÿöû?‹¨1ÿw 4#ð©ç÷÷~ooó®gxõîÛß]ÿŸ5©ÿ¯¢GúÖ›~R¤D‘­C0è-×_’Ë™ÿO#þ :ÿK¨ÉÿŽ`´´¾)ö÷n¼zó‹¿ÿÛ/{ýÿíߣëpšÀ¿ÁàrUr©V¾fþVêgÈ.$Uóƒ¤ÝåœÿäŸT?ÿ[FMþÛ@3ZZß—øÿá‹oz²ó¿JM¹ÿ£¹&üb¬8JÂÙñEqñ‘#8]¢-—“ÿâ?AÏÿQ“ÿ¶°Åÿs—øÿ“7ÝýªÎÿ*5¥þg˶˜è¨D&'9åd2atÉÆX«¶YÂÎg"þë~ÿw5ùoÍhp}S\âÿ‘ë¿ðöÎÿ*5Åÿ Ú Å‹+Êë‚]ŒÛ ÈVºÙÒ¬÷±ûÿ–Q“ÿ–ðŠ¿æúGï}êšû¾z×W¾rÍûßöÇïßû¶·=ýÝç7G¾ç÷túWª)õ¿¶,^kO’¸8ÐÅ:U –˜S!!…(årúÿ£üŸûüÏeÔä¿m4£ÀõMq)þÿ¤üÎû`•š²ÿ'SŽl3s⬲PñŠ!A«­üÞâåøÿÆõÿ˨ÉÛxb´°¾).ñÿà£éü¯RSòô,æ »òF%Ÿ²x°1k¬ð]ó€ú-”Ï8Ôù_ïÿ-¢ÿ;ž-¬oŠKü_ùÊüt畚2ÿCÑågMЉü°üO)pXÄ%x9õÿ¸ÿÝÿ·ˆšü·ûÿvÿmûÿ'¿xÝ+:ÿ«Ô”ùŸ®Tè1Š±Î£#Ágœ¦z6e¦8kügìñµøß1°Åÿ¶ÿÿ±ï|èÕÿUjÿž)Õ  è Ô<€S©¿±(§}ˆYÔ¬þÝóÿeÔäGüçÿ¸ÿú¿º³ó¿JM¹ÿ㌱–’ÏY½)…U°Ö[ppà¦yÏÿzþ¿Œšü·ýö ÿ¿ò¿ÿºOÜÓù_¥¦Ôÿ&—óehù›Ðb©¤rdŒ:º9ëäîÿ_FMþÛþ?;öÿãÖÿ÷޽¯ßëü¯RSæÿMÉš²N’r (N,“/¨óà vv^ÿ/wÿÿ"jòßöÿÙ±ÿ·þ¿/½þž×uþW©)óRÂ’…rk0ú t –ŠÃ<PƤÔœù?iÛç,¢&ÿí€vìÿÅg/ñÿš7þàßwþW©)ükd² ‡m¿âjâï­r† —X£ÿ0$¥Ý´&ÿïû?–Q“ÿ¶ÿÏ\ùßúÿ^vÛ-ÿÙù_¥&ðÏ!öZé(ˆÀ9Å>ª dÁFôŤâwO€8LþßëÿeÔä¿íÿkñ¿õÿýÓ ¯2ÿUjŠÿ_fè²HT¶Xíjí0FàÄú\³ä™Ïÿ{þ¿ˆZüïhÇþÜúÿâ÷ÿÖíÿUjÿ¢£N¦dH”D [Å.J ¹`ýCä r9û?Fõ¿éû?—Q“ÿvÿÿÌØÿsjÛÿî-¯½¶ó¿JMࣾèà£ÖÁ'Áa@MûÙ±(1V`Óœù?)ÝóÿEÔâß´ãÿ™±ÿçÔ¶ÿÿÚ#ócÿUjÊý¿ yÉtÒ&=$ Ôß ]Èq$íÐ;5ëüÕ÷.£&ÿíø¯ÇñßlãÿÇ_üLêü¯R“æCÂ9+@…<ü§‹+Hµ"p V•yïÿôý?˨ÉÛÿ§Çñßlãÿþç>»ßù_¥¦ÜÿÑ…¡ÖÖGņ0‡IsPâM¨ŸŠŠjÞù½þ_FMþÛþ?=öÿš­ÿ/?¹wS畚âÿ³÷*bH³ ŠÁpŽF'Î…¢ÓÑR³òo¹ûÿQ“ÿ¶ÿOý¿fëÿ»÷‡ïîü¯RSæªT©,¢ ‹5(ÙJɹb¥3#'DS4ÏÊ?QÏÿQ“ÿ¶ÿ¯ÅÿÖÿ÷{®½¹ó¿JMÙÿÚXg„²¦þ3>ø¤=¸ú'Æ³Ž óœû?±¾\:ÿK¨Éÿÿöÿm®¹î£¿yÝG?òÄòÐ…|Ó—_øøù‹7]÷žn¸á7Þsב|Å}ë:ý+Õ”ùÿÙ†â1ب’ÎQûêOŒ%1.tYýÿÑþ/îóÿ–Q“ÿ¶ÿOôÿ_uû»ï:òëG6'nxׯôÀ:5åüß²8…ž+ñNt)€¢ADLr)yN¡U;Ÿq˜úßtÿß"jñ¢Ýÿ×cÿ¯Ùúÿ~ä}¿ðŽþX¥¦Ìÿ,!’\¢Õdt¶µ!Ÿs‹"(,xVÿÆÎÿ"jò¿£ÿ?öÿžØöÿ_ºïܽÿUjÒüW3~'ɇX N˜]¢!Eg+’€¤ͼþ?ÕëÿEÔâß¶ãÿñ±ÿçĶÿÿ©ñT畚âÿMF‘M¼W!‰ÎI(…d‘\)ZX‘Ÿwþ'wþQ“ÿvü?>öÿØmüÿׯþxŸÿ½NMéÿK­Š-0X~JVÙ¨à‚O!‡Æâ‘Äà¬þ?²ýüo5ùoûÿhÿí6þÿÁ—ï~¸ó¿JM¹ÿ—t¨~Øú ³'[‚¶6{^jñOÞp˜óþ"ôþÿ"jòßöÿQ#þoý·}ñÓŸíü¯RSîÿ(*1“æ,(‡€£¡a*X¬ß«d¢ÜùŒCÄ0Ýÿ»ˆšü·ý4öÿÚ­ÿoïá+¯ïü¯RSú"Š ( ‹ÒÈQƒÇ ,Õ/”‰~Øní¼ñ¿û–Q“ÿ¶ÿ¯ÅÿÖÿ÷Ïo>Þçÿ¯SSÎÿhtÚ…J¾í-;’J)RE·¾ פ€ÝÎg†ìñ5ùoÏÿ£±ÿ×nçÿÝ÷'ÿ«ó¿JMÉÿ]*N‚(TšP딴ĘêY˜D\ÈfžÿÛù_DMþÛþ?Ïÿ¶Ûù_ðùÿUjÊüßH‚ V‹¦$g=æú.С€©±ŠäYçÿ£íùÿ"jñ¦Ýÿ§ñüo»õÿÝzÿ›®ó¿JMñÿ%ñžQ|›Mä+°30Ü *¨ '3ßÿêóQ“ÿvÿŸÆþß3Ûþÿ/¿õ _Ûù_¥¦Ìÿ•h{]|ô¢Ê5û眺à|‰:@Ï8”ÿ·ó¿ˆZüëñìÿ=ó?þ¿{¿ãÖÎÿ*5…ÿIç‚X,*)D^{ƒ>8°…sbÎõ§8ëþ_¤îÿ[FMþÛñÿôØÿ£·ñÿÉGïþšÎÿ*5eþW±Y¼Õ 8S¾–À8!¥ f¹R<çüÏZNôû?‹¨ÉÛÿ×âÿÿ›½³ý/©êøê"&¬’Ö†«)f>m9sΙÊH+ñ¡E·|ÃjžŽ‰¡h–J©µjJ¸˜ŠFZi¡îÓow[ÁÀVa)éÁTp3)¢v·èA£¹¿û…`ï|ðòÛËÅ óÞýÁ²»pÿù¼æÌ™óž÷|àAÿü°Áÿ!µæýŸéÙoðÆÙ¬•ÅǪí_Hû]”`RpÙŠT¶Üÿ“ÀÈÿÚE]þûþ¿—þ?3ûÿžôøŸ|ÅàÿZ“ÿá‘lU_ZßÏyŠ"°à¼AfƒF§‚}JßšÿEþÿï>êòßóÿÝ ó¥ø´;¯¿ô®»n»ãÎK/¹åå÷¿âM·œ{í§î•ïø÷qûÿ¨Z“ÿˆ„c¬½”Égß–I>’xÜ4ÿÃÒ¨ÿ»¨Ë×ÿ‡Ð©ÿ³ÿï÷ç³WàZãÿ+Ñ·¶¿ú)ûrq\MôÓC‰½•©ÿg<ù àÇûßû¨Ë×ÿ‡°ôÿšÙÿwó[Þ?îÿSkü?[ÕÉ×F|1.& 1i´)4ü7aÓþäÿí¤.ÿ]ÿÂÒÿkfÿßó¯{Àÿ‡ÔªùÌ6Sff‰êCƒYSRµ3²'S0«œüÆ…ðoÆþõø¿®;ÿGXúÍìÿ{y}έƒÿCjMþâ”b6ª©9¤ÈÁ…"Y’q._ NOnúþïxÿo'uùïÎÿ–þßëæùÿíïzÂçÿ‡Ôšù‰úìÑS(ÙÅ6¥¶ˆQªU´Ñ¹’Ê–÷Ú?Žþõøçõ¿Ãÿ<ÿÿtºnÜÿ;¦ÖœÿyÃ$1¶…@²& ^«ï@*p‰þ ¸éþ¿ýäÿ{¨Ëÿ‰ú¿ôÿó\ÿ?üÓ¿{¯Áÿ!µ&ÿ‚ìÅ•j¦aŸZ´ÕQ*Î Î9¿ñý7øßE]þ»þ?„¥ÿŸçúÿ·¯xϵƒÿCjÍþ?Zc¡Tv5$!0T¢ˆÏÈäUBÜôüŸÜèÿwQ—ÿ®ÿ¯]úyöÿ}ß¹¯½gðH­à_׈Òzäh¢:ðÅ»³Ólj±u²©ÿ‡eÔÿ]Ôå¿›ÿ‡×.ý?<çÿýÈWŸø÷ƒÿCjÿ—!54Më¬s–@{¶Ò¸¯%vÀJb¶Üÿ['Ãÿ»‹ºü÷ýÔ©ÿ³ÿïËzÉ×ÿ‡ÔšýB´¦qE `TÙºXMÉhÙPâm÷ÿ#ÿc'uùïûÿ¨SÿgÿßÕWåç þ©Uþßè‰Êtó·xCÆÇì[õ1× 6M9­G8ù ÙÿþuùïûÿzüÏþ¿—>ò‰ïüRkò¿}ëúYÙ§l’Ú\\+ý¤Ås.ÅO-€¨Ý2ÿqäÿï£ÿ7öçÿ´ôÿóìÿ{ßGþðeƒÿCjMÿ«.sÍÌ…ƒ'5­è{)TcðV"¶æ`Ë÷¿HxøvQ—ÿþüŸ–þÿçù?þÄç~iðH­yÿ7ÀgƒXÙ,…À%ª+m#Ø'bë¶çÿ0ÎÿwQ{¢þ/ýÿ7Îóÿ+_õÕ_üRkÎÿÐ[W}Æh2æ*¶-&…lAœPph¶Íÿ3ãýŸ}ÔåÿDý_úí\ÿìÕ?úúÁÿ!µæýOÁâsi…^sÈžÑWË”½K­îS4¡­Ù™m÷ÿ0滨ËßÿGKÿ¯ëÿ/¾æYïüRkòÿø4å~VIœc®Óî¿õh³ñÞRŒ‰€·}ÿËÁ8ÿÛE]þûþ?Zúíìÿ{ÝóÓƒÿCjÍýÿÅbëùmˆ ìk0eºì\ª/jcÜÔÿ?ò¿wR—ÿ¾ÿ¯Çÿìÿ{ëë?ÿƒƒÿCjÍý˜.ú–TL°‘kZ²×HÅÅÆ)XlÅÚ5 O~ãBöÿ#ÿouùïûÿÎ-ývöÿ½æ"ÿ®Áÿ!µæýOUÚ0õÈÙcnõÖ…$¶ÞÀ”•6=ÿ—‘ÿ±ºü÷ýç–þ;ûÿ¾ã豃ÿCjÍüϲ€KŒâÕ»(¡-V§w]ŒY¢ËN~ã‚æÿƒÿ]Ôå¿ïÿÃNýŸýzÁÇß=ø?¤Öœÿöê¢ju¿xÕd(X(3958=*›žÿMÿûàõø¿¡?ÿÇNýŸýøÒ“nüR«òÿÑXµbS&L16:]P¨Z!WPoxSÿ¿˜qþ·‹ºü÷çÿ¸ôÿÞ0Ïÿÿå¾ÏxÑàÿZóþŸ+‚õ^­U ¶ ;¶0¹’D©¦TpSÿýÿ>êñïNÔÿ¥ÿ÷†yþ닟ò•Áÿ!µ&ÿßkC±Õ|†d3KUiœz§m1È9ðô\GØôüŸÍÈÿßE]þOÔÿ¥ÿ×Íõÿ™ßýW_üRkîÿA„XRÌÉH)ÌlY€irY ¥õ¹ê–ó†qÿouùïûÿpéÿusýÿ~û7ÏüRkÎÿZ·Ï¹Új‚PNÙúL!¡fÂVªEŠÓMó?ÇþuùïûÿzüÏþ¿¿û?ß1ø?¤Öœÿ‚T)kŒÎX´ VÛÂÚäBJr–âïÉùÿâý_Gãüouù_øÿ.¾ê²ËÞñ‰Ç–·ýC}Ü?~ýý·íq~Ù×ò·þò /þ£‹~ãŸüSýÕÿŸ/ž8%KU§?hÔIÛÔšB“K)ñä7¾5ÿt÷ý¿‘QÿwQ—ÿ¾ÿïîÿ½ÏU/{áÅW_|Ñ«ß~ÑGÇpL­ñÿ‘ñ8 Òš€âl ¸¦¤è1Ú€5äñþÇÕå¿ïÿ»~éÿq³ÿïÁÏø»+ÆpH­éÿÑ%¶IÇd TCL&´\.Bì½kJÜÔÿcdœÿí¢.ÿ}ÿßõKÿ›ýw¼ôüRkúÿD554s"ÅK¬ÉJðRÁ€WãÆ´ñýßqþ·züßÜŸÿK§þÏþ¿çãËoüRkæœÔ¢É” αP6¹KÌ”*jT¡“߸þGþ×>êòߟÿ˲þß<Ïÿ?sï7þöàÿZSÿmÊ`k¬ ÔX-"⃠m ‚53¥Y7¾ÿ‡Ãÿ¿‹:üŸƒõ¿Ãÿ<ÿ糯¼dðH­9ÿ+ÎÆj+«¶6€”(bô1¥R#C¦B¢€›úÐŒú¿‹ºüŸ¨ÿ ÿ[)ÎóÿÞï½bäSkø÷.˜’˜ÄWI.ZIÑÚ\ƒ‹žÐ°¥ÂHvÛ÷?GýßG]þûþ?YøÿÛJqžÿ/„'~×àÿZ“ÿË>šêX1³ irGœ³YMj[­œ³ÛÞÿþŸ}Ôå¿ïÿ“…ÿ¿­çù׋ìÿ‡ÔšùŸqàdzÜ'Áâ$Z_"¨'.¥ýÇZ E·qþŸó¿]Ô忟ÿ' ÿo[)Îóÿ†¾úÊÁÿ!µæþ/‚ã,6&[É* HÈ9&)Ƥé/ÉÊ›ò/0ÞÿÙE]þûþ?Yä·•â<ÿŠŸ¶ƒÿCjÿ× &xŽ’½M b¦”Öh™ÞdnÍÀ¶ù?n𿋺ü÷ý²Èÿm+ÅyþæÉŸ|ÝàÿZóþ¯) |-˜BV[¦8Ïê´¥bŠ·h¥¸eÿÏfäì£.ÿ}ÿßM ÿO[)Îóÿ7|샃ÿCjMþm«¿ÖÔþ%eÕbj RZS 5—Š'¿qü·¥eð¿‡zü_ÛŸÿ÷øŸý¹æ¦—þ©5õ?ù¬9Ø„Óó_ÑNïþDþA›ƒÕDùä7†ÿïÛW]þûóÿ›þŸ¶RœçÿÏ®üâKÿ‡Ôšüou0÷™˜"×=¸€9¸Þ$_“3Zm9ù ¨ÿ0îÿí£ÿÔ¯ÿfYÿ¯çÿ÷ûüƒÆüï˜ZÁ¿b@±uù>–<1RŽžSað ™lZÿÅ÷vQ—ÿ~ý7ËúOsý7ñÜ_üR«üÿ­ð·2ORÙNª­êb!)Ùd"#m8ù ©ÿvøvQ—ÿ¾ÿÏ,ý¿4×ÿË>ù„ŸüRkü” ÌtÌ—R !P¨ 5.b U¨I³§¸åý?6vÔÿ]Ôå¿ïÿ3Kÿ/Íþ¿;ÿëmnðH­ñÿP™æÿj +±­–r¢Õ;ïj5uÛüO’Áÿ.êòß÷ÿ™¥ÿ—fÿßS?ñõ‡ þ©üc+üÕg±„T¹´¿!TU$±LÙê–ï0Žüï}Ôå¿ïÿëñ?ûÿ>ú˜ç=}ðH­àßjfï «ÇÜvÿRQ,BFm´œ”¤lzÿŸ‡ÿguùïûÿÌÒÿO³ÿïÖ<ç¿ÿ‡Ôšû? ŒÊä*~zü+q(d#›Àý”à)lšÿÃnøvQ—ÿ¾ÿÏ,ýÿ4ûÿ~õ{ÞqñàÿZÁ©dªD1"!t*<”TœQ-“Éîä7Æùÿ·¯züŸ;1ÿ_úÿiöÿýLJòªÁÿ!µæüߘ T%a‰Ö±­.ÀÔ¤b+ÄäRn=Á¶õŸÆýŸ]Ôå¿?ÿ¿néÿ97Ïÿåš?xÄàÿZÓÿ‡ØuŒÁŠ’‰V§÷I!A°¨JÉ&ªN~ã[ó¿xÿ‡qÔÿ]Ôáÿ?ÿïÞ×_~É%oþÌ%Ÿ½âM?õø|)>íÎë/½ë®Ûî¸óÒKnyùý/¿ü–s¯}ÚEO¿áoôTkø'âä0!ª)*ˆY’¤àlq¹r²˜Ó=¹ÿ÷÷Hÿû¨Ë¿þóÝëÿ}>5¿ÿó…¿þÜ›ÆpL­ñÿ[h¬[Ë®ªÔÜ–k-F—jh\rYJI'¿qAûÿqþ·‹ºü÷ý þÏòÿ>øâ§üÞX©5þÿ bÂtÇ?‰ñÛoÚ?dÄ”lŽU#åj`Ëû¿$Àƒÿ=Ôå¿ïÿã…ÿÏòÿžü̯üÛàÿZµÿŽÐ"©Õ¬.bjE_Дâ M÷êÆïÿú¿‹ºü÷ý¼ðÿãYþß}õð‡þ©5ó7¥|ØjÐj¬!š¶äšµL†à\‹A©qSÿŸq£ÿßE]þûþ?^øÿñ,ÿïžwÙmƒÿCjÕûß­ÐcU¶ `ç’,1¸ÂL±º³—¼iÿ/0ü¿»¨ËßÿÇ ÿ/žåÿ=ú·ÞoðH­Ùÿ»QU²Gc‹k? P+mbVñÕÛ¤÷dþ·àßòÈÿØE]þûþ?^øñ,ÿïÏè¿0ø?¤ÖÔS¢g“ Qÿ²DT d½*Ô†oôb6Íÿ`õõø?‘ÿÇ ÿ/žåÿ}çu¯û­Áÿ!µÊÿ³oÔ3h“ZÛ¯Ö¹ (V} !›¼íû?cþ¿ºüŸ˜ÿ/ù?Ëÿ{Ë—ÒÈÿ?¦ÖÜÿw™9°,ž0‡˜Œp>ýL55¦¼íý?;îÿí¢ÿ'òÿxáÿdzü¿knª· þ©5ý¡ØL#>/­6sˆ.†¶d- }ñ’"nyÿ‡Øùÿ.êò߯ÿ7.ý?gù¿ùóÿúÖÁÿ!µêýo "ƒ)rÂì|J¶N? 6µ¨-&¦õ_`Ôÿ]Ôå¿ïÿ»qéÿ9Ëÿ»ó•ßóÿcjÍý?ÛJ|ÉÕŠ qÚøÕ¶ä¨èY½ñD›æ“ƒÑÿï¢.ÿ]ÿŸ@§þÏþ¿?þߟýäàÿZóþ_pL…Bå²h@½¸)ÿŸÅ»0Ô$›žÿóÿ]Ôå¿ëÿèÔÿÙÿ÷‘ó ƒÿCjMýÇ8ú{Ïèª+FZ P %P"!Ñ¡n™ÿMŽÇþuùïúÿ–þß³ü¿‡Þõ¾Ûÿ‡Ôš÷ÿ0¶¾_Õ‚¦\¸æì+0T‰dÅLq`Á¤Mó?Üèÿ÷Q—ÿ®ÿO`éÿ=Ëÿ{ñm×âѯüRkÞÿ,1i«ò¹¤9ŠRPŸ›€ HXÔÚMßÿ£qÿwuù?Qÿÿ½s‹ýí¨ê8Ø‘HÖ‡B¶–ŠBmfÍšµÖ¬ Ñ7•¼€ j)ΈЃðàë%”jÚÛhs*hhÔP/眞˃SkjLÅ<`<…ÒbÒ@ð‚ó;Û§îù%;ÿîìd'óýçô\þ¿‡þ?{Íìõ™5sÿ×NõÿÏozæŽÁÿ.³äþ/ Šk_}%ï‘ÉYM¡¨22f¡=V­ÿ$£þo’.ÿ]ÿÏÌý;ÕÿË_¹å}ƒÿ]fÉù_‹T!—œ¡ÔZÀe$ãCÆèP|¨’*ýŒ“ôÿdÔÿMÒå¿ïÿ™û?vòÿèѼ|ð¿Ë,â߆Æ;_­æ˜¸‡œ©ÕŸœgѸêü?÷ÿn“.ÿ}ÿ¯Çÿäÿ½òªþïà—Yrþ?ú$ÑxÁ‡>±Ðaâw-E1ÄÈ>¬YÿÉð8ÿ·Iºü÷ý?×Yÿÿÿü¿×ýê_ þw™%ïÿ“çœ Úb«„‡ºïÈÛ’4Øj´- œböG?ãõßû¿·I—ÿ¾ÿç:õòÿî~ç§ÿ»Ì¢û¿£Å•Q´ÖäSŠ·ÿÙd c¦Rs{0¬¹þ';üßmÒå¿ïÿ¹¹ÿo'ÿOö{ïüï2KÎÿµÚî¡FA¯>«$u ¥BñÀè”<=§û¿fõÆú›ôø?×ïÿ»¹ÿk'ÿïâÇÿú™Áÿ.³dý/ÅaÎÖd2mÛßho»4Á«X%µW­ÿΨÿ›¤Ë¿ÿïæþ﹩ÿÇ[Þ3Îÿî3KÎÿ•j­óìj–à8( RЫ_wÿÏnøÿ›¤Ç?©ÿsÿ÷ÜÔÿÿ}>õâÁÿ.³äüOÌÉ–Œ>[áŠFH+y–œ‘#Ô’H1®:ÿCÆýŸÛ¤Ëÿ‘ú?矧úÿÛg>öØà—YRÿ³ÃZ 5„±xsXðg«sEïŠ×¶–"kÞÿÕþ8úÿ›¤ËßÿssÿŸ§úÿ—g?ùäà—Y2ÿ»­ð-îýÑT#– .yC©‚/åÊ‚VÿápœÿÛ$]þûþŸ›ûÿ<ù?zÏ/Þ=øßeíÿƒu`Ø2:Ek[ôÇdªFbY,†×õÿÆüïmÒå¿ïÿŸû?<ùoºþ…üï2‹îÿK…ªj) ÿŠ¥øj¢+"ÆC‡pÕóÿ0îÿÛ&]þûþßù¹ÿÓÿ÷à­æçÿ»Ì’úC0Áµ‚Op¸ü2$ð ‚O¶­þK]uþ§Ã±ÿß$]þûþŸíÔÿÉÿûÐ ~ò›ÿ»Ì’ù?%ä\07Ð]ôápþ H0ÑÖhYtåûÆûÿMÒå¿ïÿÙNýŸü¿÷¼æoað¿Ë,àüaäO(lõ0 8fW][´_êùGƒÿ]fÉú?+c8ÈþhˆÕ‚O¥P4Ik¦X•"T“Ž~ÆIÖÿ0üŸMÒå¿ïÿ›û?0ùï~äõ þw™üW¢¨-BrR sL’b²ŒißÌQ ­yþŸ€Gÿ“ôø?Ûïÿs§þOþß¿þÀ§nüï2Kø§’-ÖÌ¡ZEv©AŸST… êµ²í'dÕóÿÄ£þo’.ÿýþ?ÏëÿÙ©ÿÿƒçμcð¿Ë,Ùÿ[„$ŠÐ ¦"&ˆ§”™*„k†,ŽhÝù8Þÿm’ÿt¤þÏýß³Sÿß~åŸÞ;øße–øÿÞ…®Bûr•ƒ:pQ‹K6Fu£wëú?ÃÿÛ&]þÔÿ¹ÿKSýÑÓ÷^7øße–ÌÿŠÒà7® Õ¶È¡Ä`TrÕ‚&,5¬ºÿ7£ÿ¿Mºü÷ý¿ÿSý÷­×~ýà—Y2ÿcˆ¹ÙR©aꔀe†ö×Z‚·â’±«žÿwãþïmÒå¿ïÿñÜÿ§Éÿ{í5ášÁÿ.³ÄÿO®ε–’Àæ¬m@±íøs1Ûw3FÍG?ãDýÿ±ÿß$]þûþÏýšü¿nû›×þw™%ûÿ’ƒÇ„¡²)UKÛ `!OF3jôj¢)¸ªÿÇcþÇ6éòß÷ÿxîÿÓäÿýÒÕ÷ß<øße–¼ÿ÷¾§Ã•?…¥5VÉJ*$ÅçRœšWõxÌÿØ&]þûþÏý_šü¿/Ýxßïþw™%÷ÿ”`$+bIbs”Ãõ_$DªÅh,®âªóhøÿÛ¤Ëßÿ»8÷hòÿ®ùôçüï2‹æS‰Tе !çT+JP¬@2¶†¶5Xõþ‘ÑÿÛ$=þ/ôûÿçþMþß?þ3þw™%ïÿ4°oKŒLÄNÒüH>ÔàJe¿ªÿƒnœÿÙ$]þûýÿÿ¦þÿËÝ=ïüï2 ø÷–9yJmCòX0!•èŲ³±JÈ«®ÿÇû¿MÒãûõæëÿ Sÿÿu÷\úïÁÿ.³€ÿ¢ÔðW+ê‹3E¼8õ—ªI¢­ÆE£å¹ÌÿÀùüQÿ7I—ÿgÕÿ«ïúÓ×¾î±Wå{?[^ý¹§þð3O¾úºÛŸzéý/y×Û®ºéù?qç;Ÿ7èßi–¼ÿÁ—âÐp€ŒAŒ KÚžœj_cIÆI~.û÷ìþ¿…1ÿo“tùïûðlÿÿwzÛU÷]õ¼SüÚÆ`ŸYrþŸ‚4ükTP)Tl†©ójD46ù !«=ú'òÿÿ›¤Ëßÿƒ¹ÿ‹“ÿwÿ¥?ý¾ñØe­ÿYS[ò1í¼­ÁrÎÖT´.Rµ˜ñègœèýßèÿo’.ÿ}ÿæþ/Nþß¿þ‰4øßeðïk†BAÅP«mó0Sm mu`|J´êü/¤Qÿ7I—ÿ¾ÿsÿ'ÿïò—ŸþÍÁÿ.³dýYÔ4±mûMr©M ’8°6dÉ9­:ÿcø¿¥Ëßÿëñ?ù~Ï;~mð¿Ë,ñB+ȹ@á¸Î¥èj[x_jÎäR í?Ù®9ÿ›À ÿg“tùïû0÷ÿqòÿ®}ÓG~~ð¿Ë,ñ“ùpËO ÷j’=üDÄR8&]hÛ‚5çïÿ·Iÿ‡ôÿçþ?NþßÿvýÕƒÿ]fÉüÑÙêMâèàCv¬¹íÓ­‰‘"òª÷°ó?7I—ÿ¾ÿwvîÿ<<ù/{âô›ÿ»Ì’õÌx)Iû1†‚Çh±‚Z—äÊ+Ÿÿüo’ÿÒ¯ÿgçþïÓÿ÷]w>ðÉÁÿ.³äý_k4´Z"Á¶ý>cHÙ%ÛŠ?g“aåóÿvôÿ6I—ÿ~ý§yý—©þ¿â¡ó¿÷™%üÛ²!l|FÃI¼¶í€`ïJäR´L‡†ý±œÄÿóÿ·I—ÿ¾ÿGóú/SýÿáßxôÑÁÿ.³Äÿuhƒ£”j,@¡±KdÛ*@C, ´øT)®êÿȘÿ¿Mºü÷ý¿ÿ“ÿwá[Ÿø†Áÿ.³¤þ;b1®„¨ ˜ÕgµŒV"dÃmÁ(¯|ÿ÷à“tùïû4Ÿÿ/“ÿ÷Å7Þpyð¿Ë,™ÿ§Ôª»ujŠ"TµTM[ûkÍ1ǶUçk\wý?üßmÒå¿ïÿÑÜÿ—Éÿ{á·¿ä;ÿ»Ì’û¿œÏQDCR!kR䚬Ueï'Gëúÿ„£ÿ¿Iºü÷ý?šûÿ2ùŸJÿåÁÿ.³€Yœ·p8Ôý`]P/ím°Ú‹Á98ú'àßâ¨ÿ›¤Ëßÿ£¹ÿ+“ÿo~ë‡ÿ»Ì’û('ÛÿÞ§„,RSˆ‘™JÑ”sˆÙi¬kžÿ%kÇý?›¤Çÿ¥~ÿŸæþ¯Lþß¿?úËãþ¿}fIý[M0T3ƒ“kŽ%QÛ¤s­1±p ¬«îÿEFýß$]þôÿçþ數ÿûkŸú©Áÿ.³Äÿ÷µ­ÿ…‚͵ze ÆÏ>eH¹Ä 6ÆäͺçÿÆýÛ¤Ãÿ9s¤þwøŸúÿ¯øiüÂà—Yrþ¿xRŤ!RPÊBdª5imˆíKeÝ÷£þo“.ÿýúaæÿµ'Åþè¿î¿wð¿Ë,™ÿ›rH¹JûApà\ŽV#GÄ((X*çhœ®;ÿߌú¿Iºü÷ý¿ 3ÿ§=)®ðÓåûnüï2Kü¿lP|a­I$©5t¸û¢Ru†SæL ©Ä£Ÿq’õ?þ7I—ÿ®ÿ¦Sÿ'ÿïÒÕoÿà—YâÿÑt˜ò‘¥:NÎhÛýk´ígâpñOûgëÞÿ'ãþßmÒå¿ëÿéÔÿÉÿ{èÿîÁÿ.³€ÿ$Áæö¿¿ää°('Ÿ Nh«Xï9¶¿›V=ÿ'2æÿo’.ÿ]ÿÌÌÿmOŠ+ü¿èšßçÿ÷™%ûÿÀùðÐD«ÆÛè%V“][PÕ¬F0ºîý¿f¼ÿÛ$]þ»þ˜™ÿÛžWøÿw|øóƒÿ]fÉûã)f &'¬µí÷Cô)5\««m)™ FXuþºqþg“tùïú]þ'ÿïô>výà—YÖÿ«X‚*¹š3‹Q ×¶`(1{ö°îüqþw›ôø?Óíÿƒ™ùÿíIq…ÿsoø þw™%ïÿÕ:Š*‚R¬I$Ì‚-¢âH=reUþó?6I—ÿnÿÌÌÿoOŠéþ?¹{œÿÛg–Ìÿ³–A@ÛêŸ1EÓZ*y#1Yp,BZsþ¯s4øß$=þÝ‘ú?óÿÛ“â ÿ·}ú?eð¿Ë,9ÿ˜¬!#…¤Õ|j°ƒIž™ÑÈÁ f0AŽ~Æ øoO•Áÿéò¤þÏüßö¤¸ÂýâGlð¿Ë,à?K¶©Fþý.$ÅŠÞ²AÏA ª"±ãu×ÿ4îÿØ$]þ»þœ™û?nªÿ_só{ÿlð¿Ë,ῲqJp¹ÆÊ¨8µ½¿Åj\‰˜ ʪó¿ÈÐð6I—ÿ¾ÿwfîÿ¸ÉÿûÜ7]~lð¿Ë,™ÿƒ¥áJPj‚Mö!19%Ã1̪óÿ-ÿg“tùïû=þ'ÿïþù™ÿ»Ìÿ77¼sq5›bCÓ•èÃá>§¤j’5ïÿm?ncÿ¿Iºü÷ý?×YÿOþß·þ——þw™%çÿkBN… E‰ÈJP¬¥jÛèªïÿÇù¿Òå¿ïÿ¹NýŸü¿7üÅ?>4øßeðßÐM%·ßLm¥¾}Ùì²wYlt€2úTW=ÿÏ4üßMÒå¿ïÿ¹¹ÿï&ÿï?ü–üï2 øÄ8TMÍÖ«µÞGõdk+Ø~Õõ?Žú¿MzüŸï÷ÿÝÜÿu“ÿ÷ö—=ðªÁÿ.³¤þ3uµŠgs&LàH¡z ùàhpW½ÿ—dÌÿÞ$]þûý7÷ÏOýÿ[ï¾ù-ƒÿ]fÉû?3T%”ĬxW9™hŠ“Vû1)¯9ÿwÜÿ·U:üsþ¸¹ÿ{~êÿÿñ©Ïêà—YÒÿÿ?öÎ/d·ãªÃ‰$*H54jm1"­é¬5³Ö¬!µhÄR”Ôÿ4¢%ÌÌš¡Vc A„ZLµ­µØR/´%àEBZÑbÊ9'''µIk Ö¶ˆÛ  æFAIÛ¢¢±:ûìïnÏ ÛÏ͆ ó#üƒ÷"ïó®™YϬIZÚ?úÄ®QZ,z(kôN2i)TÅmÅ¿»ºÿ·£ÿ¿KºüŸ¨ÿ þùlþ_~òÞoü2kæ˜â€ª•X¢hÎjkµ®¢Ï„ Ϊ‡­ÎÿgþýðÿvI—ÿ¾ÿçþ?ŸÍÿûáOÜðÊÁÿ!³êüßZN6Mó~ÁA1§R£VFT*–‹n5ÿß]õÿ`Ôÿ]Òå¿ïÿ¹…ÿÏgóÿ~×Ç~pðȬyÿ§†à=¤Ö¤‰‰%šÌ!bÉ%´Ÿr,[ÿ»ùýïqþ·Kºü÷ý¿Ë ÿ‡Ïæÿýá+ž½cðȬÙÿ£´ïcaR¥}'ÈeŸ!{/µ0B øägœƒä±þß%]þûþßå…ÿÃgóÿÞðÆç. þ™5÷­cht¢õFƒFl«~¨Z gbõÖæ·šÿw•7æÿî“.ÿ}ÿ;õöÿÞòMþnðȬ™ÿrnÜ;3™1×DÎ5í›áÚ7#æ [ù3ÿ4Öÿ»¤ËßÿÃNýŸý¿w˜›¯ þ™5ü'ë+*©©*&•”½(´e”œÇäªåmÏÿÆûû¤Çÿ‰ù=þgÿïÚoùæŸü2«îÿ '¶E§…€7ž*IÁ•†¾Ï¡zH ›®ÿiìÿ÷I—ÿ~ÿþ?ŸÍÿûó§oùûÁÿ!³¦þK ­ÒS©A³m›4eº djº`SÚòüŸÐýÿ.éñbþ.ü>›ÿ÷¥?xÉ}ƒÿCfMýÇ uºîÇBшhà ’KªUc(6B)¯ÿ‡ÿ³OºüŸ¨ÿ ÿŸÏæÿÝÿÅw¿eðȬzÿ3‚M”c@N)¡rñ«õZJ¶ DŒpò3ÎÃ?Žû¿»¤ËßÿÃ¥ÿ{6ÿïE_}ïß þ™5þ_×È/.y‹¹ÆÄ ß5‘5Ã4Ø·MÀ–þ/õ—tùïû¸ôÏæÿ]|þµ/ü2kîÿ7\Н˜K’`'?wº\,E¬&c°[ÖçÌxÿg—tùïû¸ôÏæÿ=úÔsiðȬzÿ3`[T"±¡ç¶ñwQ9h¤rÖÚ?;ùçàŸÝXÿï’.ÿ}ÿ¯ÇÿìÿÝó†£Áÿ!³†ÿéö¯p,¥Ö()  AƒR¬¦ý2T(Q½w~ËþŒù¿»¤Ëßÿ»´ôÿÎæÿÝþøôàÿY3ÿÛ¯|I5Zo¤f2YótÀ1½:­+ÚMûÿ~ð¿Oºü÷ý¿KKÿçlþß_]¹õ£ƒÿCfÍýÎb(H7mûC[òç 5[m[‹žjŽäN~Æyü?øß%=þOÌÿãNýŸý¿_¹ý±›ÿ‡ÌšúŸUnµßVF(Џªì¬&_XƒÍ6U›·íÿãà—tùï÷ÿyYÿÏæÿýËgž½aðȬšÿQ(7€$¶ÑO£>¥áê³ 8µ-¬ðfó?Ïîÿ ÿ—ôøÇõéÿžÍÿû¥ ¯ÿ§Áÿ!³ªþ[´$«ˆ É'UA@g¸”ª \ÞÔÿqžÇùÿ.éò¢þ/ý_<{ÿ÷‰ß¾qðȬñAQªµà$„h²pH^Œ²ä²b‘¶œüŒsðoÇüÏ}Òå¿ïÿõøŸëÿ·^sãXÿ3kîÿpðQ§@ÎEÉdWI@‘Љ±ªÊþägœ§ÿÃÿÛ%]þûþ/ýœý¿½+^?ø?dVÍÿN5«A*Priü·…&´X´"lÿƒ‘-ýBþß.éòß÷ÿxéÿãìÿÝùuŸó?™5ïÔéù¿LÉûbÕhÛïç›ð;ü2«ÞÿBdڮ߻}56z¬IC¨œ´ØXZ½ÎFO~Æyöÿãý¯}Òå¿ïÿ]Yú?8ûéSÏ|ðȬàß$'>ÕÂÕ% ŸäÁÚ⦇’±ÔUY7=ÿ÷ãýß}ÒãÿR¿ÿeéÿàìÿ}éE÷==ø?dÖ¼ÿå‰m®#f[¢% ³ñ‘:I^˶þÿ8ÿÛ']þûýÿÿ—æþÿ[ßü_ü2+ø/¹ˆ!`ã§«þm¹ w#…Å’¢Ï¾–JÛ¾ÿ9='8øß!=þ¹_ÿa¹þ¿4÷ÿ?ýß7úÇÌšó¿` ­¸ä¦KÿÙM¾´ŸÁ¶Ý@H›¾ÿ~œÿí’.ÿýúËúÏsýÿ¯ÿ¹~Ìÿ>fVðï,Ç$¶$V[Iœæý‹$”©ˆ³©&ºMçÿ‚ûÿ]Òå¿ïÿÁÒÿç¹þñk÷ýÐàÿYSÿÉÕÚæßù“¥È5\}À¶†ØJ5“&Ÿ6}ÿ›`ð¿Kºü÷ý?Xú¿<ûáé?}ùàÿY³ÿ/ªÎi‹|\2cEQ À„AlM$Žþ?þ¯]¾ÿ7üß]Òå¿çÿ]ûkw¿û}_xêç¯ÿÞÿ¾üÂÛ¯ÿÛÞ”s¾íÞ‡ÞzÍ;_xòëýÍšû?ÉÛX£55’IB„)WMþÄéé¿¢ÖÑÆïØqÿ—tùïû°ôyöÿxÇ;ÿsü2+ø§°ZR/`lˆès*Ñ…@†¯® ¦ÙnËù­þ÷?wI—ÿ¾ÿ×ãöÿ®ó×ýóàÿYÿ-1…â"'—“¤ê’IÑEëk¨ÁG ªÄ~Óù?à†ÿ·Kºü÷ý?Xúÿ<û½êÏ^<ø?dÖÜÿÍ!ø<Íû¨Ö‹hÎ5Fç84­$c(Øtþûqþ·Kzü_9Ñÿ_úÿ<û¯þÐëÆûÇÌ:ÿG=TM‘³±š*D[Ѹ¼´R‚óUê¦þµÿbð¿Gºü÷ûÿ—þÏ•¹ÿÿԿƒÿCfÿï™sµ©¶E€mëÛ ¾úÊ!ÆRs†‚»¤°¥ÿOÈcþÏ.éñýúqéÿ\™ûÿ_¾ò» þ™5ïÕäŠÏª&~³fÈA¶’‘«ÞPˆÛÞÿs£þï’.ÿýúOËúsýæ¡oÿ£Áÿ!³æü¦ #h6\}ûà"ÁJcµ@JàPB0nÓû?†ÿ»Kºü÷ý?ZÖ˜ëÿGÞsã0Ž™5÷ÿ‚ImÑÙE6T£©"¡`tPM¦œÄ’u›úÞŒþÿ.éòß÷ÿzüÏþß÷7üÉàÿY3ÿÛ±ÁJ>p29–äŒ÷¡*Ú’°ý‘%eqÃÉÏ8ÿ0ú»¤Ëþ-ý˜çÿ]sÏ¿Þ4ø?dÖøÿ ÓmµZk±ˆAs2‚T9·/†ŠfnK„“Ÿq.þÇþ—tùïû´ôÿaöÿ^xùçÿaðȬ:ÿ—¢QÐ$Ç’N{~Ïâ¬@òÎ[”¢ñ[ú¿ÎÑXÿï’.ÿ}ÿ–ó¿aöÿ^õæo{õàÿYãÿDjÛq¬ÕCf6,‘ZÉÏ¡ý¨`ðj@qSÿ‡Æùÿ>éòß÷ÿhéÿÂìÿ}æ'Ÿø‰Áÿ!³fþ§ªÞ&fgJNÔب܊°¾dÈ›Îÿ¡ñþÏ>éñ±ßÿ§¥ÿ ³ÿ÷âÏÝõÉÁÿ!³æý-V¬Õ´–j“xñcŠ1¨µX2Ú@6õÿÀû¿»¤Ëÿ‰þÿÒÿ½8÷ÿÃ#ƒÿCfÍüô‚! “Äm½/’¢u!›©ù_£x#²mÿìà—ôø§õ¿ÃÿÜÿÿý¿|ü}ƒÿCfMÿ¿ˆm+~Íä=“±Óp!Jm Œ-:µO~ÆyÎÿÇýß}Òå¿_ÿ_ú4×ÿ_½õ¥ü2kúœ¶ÉwÒû6T£$)ï|2ÆúlÖï9çÇüß]Òå¿ïÿ=¾ôh®ÿ_½ö•£ÿ̬ÙÿÛÚ ¬Q%™à ç\ú¨‘ $ÉlJØôýO3æÿì“.ÿ]ÿL§þÏþßÃïùÍ/þ™5þŸj19@ Só?˜$Á™ Þ ÐR=5„•7íÿÿo§tùïúd:õöÿ>ù×ßsiðȬÙÿgT(Ókß!ÙJ)µš¬Ä”J½:ÿ“œK²éû¿–ÿ»¤Ë×ÿ#³ôiöÿnyÿýÏ þ™ü‡VóÙLgüÁ‰k;€”cãD 4…mÉ´©ÿƒfœÿï’.ÿ]ÿÌÒÿ¥ÙÿûÙ>ÿ‡Ì þŤ U‹7¦$åF|[Ci›~“SÛD“Ùtþ¯ïî“.ÿ]ÿ¯Ëÿìÿ½ÿº7=:ø?dVð•#ª1„<½ÿÇÁ3Dg§±Ÿâd’¬7=ÿg绤ÇÿãÝþ?™¥ÿO³ÿ÷ág®ÿÔàÿY5ÿ»CÓÈkŠdƒ%bŸ*%°ÅµßæÄnÓþ?÷ÿöI—ÿnÿŸÌÒÿ|îÿÓm¿ðÐàÿYõþO¨ˆ8]ùµ4Oϵ¿ PÀT²¹p´›žÿµ¯ÛØÿï’ÿöDý_úÿÏýÿGú?îü2kîÿÚZBÛÔ¥Õ~lìÆ >³ñl)¢Nh˶÷yœÿï’.ÿ'êÿÒÿµgóæe—ÿ‡Ìªù6ÅT•|oQËt÷šؾ.Ô¶û–Mçÿ þwJ—ÿ®ÿG–þëÿ³ïúÚƒÿCf ÿÁ:E›kj¸%4ˆ§¿7ÙVoâ¦ïõÿ.éòß÷ÿ.,ý;ûø‰7¾bðȬñ‹xUÍ•,ƒUŸ&ž&‚[õÞj#ãÉÏ8Ïù¿õ—tùïû=þgÿï¥o{Û_ þ™Uü+Ó“_CÆŒÎçL¹ªá‹©à’¡´åúŸÀŒù»¤ËßÿsõÿÙü?ûãÿ>ø?dÖœÿ ÕLÖY—‚ƒŠ‰ÈpÓ(0ßþ’èmp'?ãÿοmûŒÁÿéòß÷ÿ\§þÏþß{oºûµƒÿCf ÿ(’K\mÈ’£„Pl_TC*ܶ'?ã<ë7üŸ]Òå¿ïÿ¹¥ÿogÿï5ßð¡?ü2+øÉÖé~¿VuÙC´A Gö>–˜‚¶_ß’20îÿï’ÿõûÿnéÿÚÙÿ»xù¦Ïþ™5üWŸ 1aN`¢Ç\’V³AŸÕÖÈ'?ãüÛñþ×>éòßïÿ»¥ÿûØÙü¿[?<îÿ3kÎÿ¼Fu,¥°Ë)1à¤þÄZM ÆAä`%lùþï¸ÿ¿Wzüûõéÿ>6÷ÿïG‘Áÿ!³Æÿž@ÛCù…KNÑV@R§‘ÈE_tÓý?ñØÿï’.ÿ'êÿ’?×ÿßúü½_ü2kæÿÖöÿ¿BKµ‚eð§;ÿ•KUXb%Øôþ»ÑÿÛ%]þûþŸ[úÿ~®ÿÿÜ _ü2kêÿ„¦q^L®RjˆÖ»4 ÃP¤ˆQ| ·­ÿkÇþ—tùïûnéÿûÙÿ»ëß>öäàÿY3ÿ#³š‚Z}fp"‰€ FjiÌr5†\ÙÔÿ#?æï’.ÿ}ÿïòÒÿñ³ÿwÏO=ûÔàÿYsþ‹¶}+þ˜-# qL.€Jmiyz|Û÷ÿFÿoŸtùïû——þŸý¿G¾ó¹×þ™ü{¥MÆRÅ(F •\´\-DEc0ç,aÛù¿nÌÿÚ%]þûþvêÿìÿ=øö ß1ø?dÖœÿÙ ‰rbƒêQ"&ÛÖÌÉ$m[ã|ÙôýOÆqþ¿Kºü÷ý?ìÔÿÙÿ»ÿŽ›_7ø?dVÍÿÕVè9S´‰B‰5±KžÅ–T¹¶¿0ض'?ã<õGýß%=þŸè÷ÿqéÿúÙÿ{øo_ó¿Ž™5þ3ƚ཈Ç*’¥¸à]qž]ˆ¶V+ÓÀ¾S9ÿÀãüo—tùï÷ÿ;ü?1÷ÿ_sé–— þ™ü'ñ ÅÅJ\ `pÄ.¶?e&U( ¸íù¿ëÿ}ÒáÿŠ9Qÿ—þÿsÿ¿þâ·þ™Uþo¤dD—L4ÙA’ £!ý/{çëÛQÕñª©&üƒX‰ ÁW&e­Y³Ǫ̈ˆ±è4>•â¬y bHD >hk‹’m­U¨ÖPƒ&€½×{k Ä# ‘ ("ˆ¡Ôàƒ8ûìóßž_Ü9ÙÙÉNæ{ûÇÉM“ýÇ=ŸYóøÌžz'yKÿßÊèÿ¹OºüŸ¨ÿ ÿ¿güÿÎ+>õÒÁÿ!³æýO°:5þª.šl! Ûˆk@ŸÉdUe‘˜·}ÿ›Gýß%]þûþŸYø¿m¤8ãÿ½ÏûÇü2kÞÿôˆ¾2*Çbj³€JÑ€ žÅGtl‚¤à·ìÿa‰Çùÿ.éòß÷ÿÌÂÿm#Åÿ7ÝøŒ§ þ™uïÿˆsÆ“«NIÛΣGr„>l@æMùûÿ»¤Ëßÿ3 ÿ·gü¿úk^Wÿ‡Ì þÉ+¹ båÑK-’cÕ +Tk¡xâmÏÿhìÿï“.ÿ}ÿïòÂÿi#Åÿ÷Üß?ø?dÖìÿ1yÒ©ÅLNK¶ ÖUlTNY¤†ÈyÓ÷?ì˜ÿï’.ÿ}ÿ¯Çÿìÿ=òŒOŽþ?ÇÌÿ‡‚¨å¶$Óž?`ŽêP´±8×èGГ߸Hýûÿû¤Ëßÿ»¼ðÿÚHqÆÿ—=îûÞ6ø?dÖÜÿm8–”µS‹ ä2äb}%45„­âóÉo\äüoÜÿß'=þìŸÿK§þÏþßï¾ñïž4ø?dÖø?«Lï~!›U¼bv¡K¦”ˆ¤A¼Œþ?GL—ÿþù¿,ëÿƒóùÐK_2ø?dÖœÿG¯U4ƒãª¢CÛ곇ȫÍRᢰíù?þwI{¢þ/üß6Rœñÿì§¿÷‰ƒÿCfÍþ?PPë…±ÈôÔRÁ2¶E:Z©ê‚·¸íù߸ÿ³OºüŸ¨ÿ ÿ·gü¿æ[õ'ÿ‡Ìšûÿ‰ƒ·Õû¨§`m`"§Ê`À³¯I@6íÿÛF—Áÿéòß÷ÿdéÿÚ¹þÿþÍßùÖÁÿ!³ªþkšîùz£‘­¤â“7 `MLΔâ¬Ï>ñ¦÷ÿœçÿ»¤Ëßÿëñ?û7~ôGãàÿYSÿ½ UCð…[±ŸæümÂoµ•þÉ tnj²¦“߸ÿfÜÿÛ']þûþŸ,ý;û?tçãÿÏ1³fÿÏÙjRФ&ÚdŒjÎØæÖˆ‚“’rI´%ÿ £ÿç>éòß÷ÿdéÿÛÙÿûïÜ{ÃàÿYÓÿ×;òbœF,lU‰ 1•Z1‡ ¡htÓý¿6±üï‘.ÿ}ÿO–þ¿ý¿[þãîÏ þ™UüÇtÖÿ3¡‡B ¹ ÁÔäDJƒ?Uc6ÿ»áÿí“.ÿ}ÿï¡¥ÿcgÿï•æ‘ þ™5÷ÿRMÞ#[ K™”rò¦R±FÛÔ b‰(ìÝiZ/Àûyð¿Gzü_éŸÿ?´ôììÿ}ö^úÀàÿYÃq¤Ì-hÍ΋m ˆƒ¢ÁS%¨FÒ¦ü3Œû?»¤Ëÿü—õÿÊ|þÿÙ7¾gôÿ?fÖÌÿ[™‡:=ô«‰Rª%U’Òþp["¬ ɤMýßöÃàtøÇýÿpYÿ¯Ìçÿû®¿xíàÿYÃ?£sre©HÁW—ÛÌ«!_¨ ‹UmTضÿ¿ç»¤Ëÿ‰ú¿àÏûÿýÈ­ß|óàÿYÁ¿€º†k`ëUT*ÒQkFku:˜ž>ù‹¬ÿyìÿï’.ÿ}ÿþ?ž÷ÿ{ùmßñÜÁÿ!³ÆÿsŽ„ý$üTR-‰²ñh²5Ehêâf7õÿØŽ÷wI—ÿ¾ÿ‡ ÿÏûÿ½áíÿêÿ‡Ì þ¡0mH`|pÅØ©ùR1‘Ý´À€B6ÝÿCüï’.ÿ}ÿþ/ž÷ÿû†Ûï¾nðȬéÿkB`˜¼E"”êSöÎå\©¢á\S¤ [öÿg0cÿo—tùïû¸ðñ¼ÿßßÿï[>6ø?dÖÌÿ«S H(T2%®6S`"”‚¬fË›®ÿYÆú—tùïû¸ðñ¼ÿß}îá?ü2küÕ³•~¯5‘ç(íÏô ¸‹¢8-ÕáÉo\ þã¸ÿ³Oºü÷ý?\ø¿xÞÿïëþìe¿7ø?dÖôÿŒÕ"f£RrâÀ zç]Œ¶(c0 .µâä7.rþ7æÿû¤Çÿ‰þ=þgÿï7?uÓ+ÿ‡Ìšþߪ.ø¦×>‚Kíw!Õ6íoë~ŠÎ¶•z ´øMû1 ÿw—tùïŸÿ_ZøxÞÿïkùÈÓÿ‡ÌšóÿlbV½§Xc”ê(r¨iê R© ·=ÿëÿ}ÒãÿDÿ¿KKÿç¼ÿß·ßúá7þ™ü›b9”,6ç4–é¾ZW5¥ìk¡]0[öÿb Ñÿk—tùï×^ÖÿóþOyó_<ø?dÖôÿžºñ4 MJˆJ”Xœ0Ä" Ó+€Z5ƺéû_Óÿ>øß!]þûþ/ëÿyÿ¿çýì­0ø?dÖø?Ó?¿FJžƒÔÊ.ŠmÈ’FW}(~Ëý+£ÿ÷>éòß÷ÿxéÿž÷ÿû§{o|ÎàÿYåÿš˜Ég̘J;Øh@qmö&:ÆxòYÿùÿ>éòß÷ÿxéÿž÷ÿûŸw=ò˜Áÿ!³fÿψS6¨¶f›Jã+å5¤(Å’Ú(›ÎÿiôÿÙ%]þûþ_ÿÙÿ{Ì“_ø‚Áÿ!³¦þ§‚m€DPmNÆa…\‹× $Ѫãà#ñ¶÷Ý8ÿÛ%]þûþ/ýÿóþzÙënü2ëÞÿòÎ6ðÆEçÚpPb¶èˆ±Íj6õiôÿß']þûþ/ýÿóþôܯÿôàÿYÁqI ¬ ÿPÉÕ1B±³ %ûƒâ¦ï;3îÿí’ÿ'úÿñÒÿ?ïÿ÷±¿|ç—þ™Uýÿ‹7QeZ°AJÎCòÅ×èY‚`(mb°éþÙ±þß%]þOœÿ/ýßóþ7ãÛž0ø?dÖÔÿÈ’ÈT̹fòŰiSõž!'/­X‡ª›ÞÿwãþÏ>éñoúõÿêÒÿ9ïÿ÷À}w~ãàÿYÕÿÏ‘äRK›xï*h#ßsdJþìu `ü¶þ¯þÏ>éò߯ÿW—þ™ëÿÕßøÁþ™5÷‚ \Í5V9B›LÍ B®b°´©ÿãFÿÿ}Òå¿ëÿ,ë¿™ëÿè{Gÿ¯cfÍü?Q°®èäüsLÖˆ÷R4ŠÈÞ×Vû]6uÓ÷¿Øý¿]Òå¿ëÿuùŸý¿'Þ÷âÿü2+øgnÜû60˜D$5ÙšQÈUë«Öàì¦ûÿƒÿ]Òå¿ëÿtæÿ³ÿwí{þüÊàÿY3ÿ¯1D% ¥-ö«€;µè¨Š¹k³šByÓúïÜXÿï’.ÿ]ÿ`éÿ›Ùÿ{à×îþ›Áÿ!³¦ÿ'ƒˆOmP±ý0€ ± mÕO™ªuµfÝôþã¨ÿ»¤Ë×ÿ#Xú¿föÿþêÁ{oü2kÎÿ3Z“‹’z1©#!3] ¨%¦}Šê–þ/ú¿Kºüwý?‚¥ÿkfÿï¾ÿ[ü2kîÿG—5Çšr Åxß*¾8—Ú‚ ¨QLÞo)nÚÿƒ`ø¿»¤Çÿåîù?ÁÒÿ5³ÿ÷Ïÿ±' þ™5ó¬è•fÈ`·U€C¡z¯9%ˆ ±ä°­ÿ;îÿì“.ÿÝó‚¥ÿ{y>ÿÿèkó]ƒÿCfÿ1ƒS‰Ùª!£ä+ÅÈ6Moÿ8¢ZM YÓ¦þ?£þï.éñ/'ê‡ÿùüÿß_ý/ïü2kê?±šÌ…A i²±-°-ù£ó&WçcŒÅlÊûüï‘.ÿ'êÿÒÿ—¹þ¿ë%o}ßàÿYÁ¿õ”J¦ª%;m¿ ÍªÛ†kĸ̦þ÷¿÷I—ÿ¾ÿ÷àÒÿ‘¹þ¿åêËŸ<ø?dÖøÿÅøˆš=©p`•6@ÌE­Új³É9'H’N~ãõßÀà—tùïû.ý™ý¿ïþÅ¿ýžÁÿ!³¦ÿ—K1b«ðª9«w.çJ¦àœØö¡V²·}ÿoôÿÛ']þûþŸíÔÿÙÿ{Õ§_ôðàÿYŃÝp-.cNœMHàKeÅVô“‹Dm  qãú?öÿvI—ÿ¾ÿg;õöÿ~þW¾ßþ™5þoÎ’¢s)äj¼)±|´„Ò꾄èØJ±âN~ãõ_ÆýŸ}Òå¿ïÿÙ¥ÿ+³ÿ÷¶»¾åñƒÿCfÍûŸ¸-ðãtó-Z=±¥] ,Ùc$6ÿ[ïí’.ÿ}ÿ¯Çÿìÿ=ç™OøÐàÿYÿTK!…9ŠM|­©ÖÐê¾h#„Ûôý/ëì¨ÿ»¤ÇÿCýó»ôÿeöÿÞyÛ~{ðȬÙÿÑ«š‚Þ¡ñ6´5¿G19¨£¹­þ!Ø-×ÿ­þý¿]Òå¿þo—þÿCóùÿg¾ê©ü2köÿH¬‡¥жúb±[½Šº6aô%úMïÿ¢ƒÁÿéñ'êÿÒÿh>ÿ‡{ö}ƒÿCfMÿö>ok×f0¬¬‰Rö¦x5jR1rò©ÿ2êÿ.éò¢þ/ý_œëÿ'Ì^3ø?dÖ¼ÿЧjD¼“h2` Ä¹8×ðçcq$ÚV'¿ñÿóOËûÿãüo—tùïù_ôñ¾íõï{Ç‹¯}æ®|þ5×Þpý ®»î†ë_rÿO\sÏãß~iÐЬòÿHÁ›cð•kI˜S©¶dôÅG«à+mìÿõÿ>éòß÷ÿ®,ýœý¿—|àOkŒ‡ÌšýÿJå"N«ÄC›”Z}$±N Mû;ëÿ]Òå¿ïÿõøŸý¿ŸùÊG_5ø?dÖÜÿm%>å˜*ˆ’©ÙÔZ‘ŒFÒÅ`‰¶lzÿŸÍð÷I—ÿ¾ÿweéÿáìÿÝò¢Þ1ø?dVðï| ‘µˆI@â\ñ%„6À"àÛ¯G4ÌuÓþÄÃÿÙ%]þûþŸéÔÿÙÿû#¼ýŸÿ‡Ìšú/¬ˆòôâGlßçj†Nl«ÕÑ)H=ù‹ìÿûÿû¤Ëßÿ3ú?ûÏ{ìõwþ™5çÿÉ8¬UgJàm2Puê‘ÉRÍ6õˆFÿ¯]ÒãÿRÿüß,ý_œý¿Ÿûåw×Áÿ!³fÿß5‹õ¾M2dzG‰œ©ªl-ĘqSÿ‡ìà—tùïŸÿ›¥ÿ{i>ÿÿò—ÝÿÊÁÿ!³‚,ìÀ¦b$ujκ~i›cû› 1zãCÝ´ÿ¿³cý¿Kzüó‰ú¿ô/Íþß=?þš_ü2kê¿¥H9‘k¿¬®’e ÙCÈ¡iÉd}>ù‹ÔÿñþÏ>éò¢þ/ùç¹þßÿ©Ë?0ø?dÖôÿqbDT(ZëÃŒ€!§ÈSÿo®xsšÖ‹ìÿÁ¸ÿ·Kºü÷ûÿ™¥ÿÏsýÿëwÿñ'ÿ‡Ì þ!yͧ?ÎA[ûOêH5ÅRLȦXñTë–õŸaøû¤Ëßÿ3KÿŸgÿOßÿò¯ü2kø‹(%q˜úN¡-÷!×RÛD Øèj ¤¸éý–qþ·Kºü÷ý?³ìÿͳÿ÷Ó·|ðùƒÿCfMÿo›“÷$8“‰È 9"qd§ VLÌÛ®ÿqôÿÝ%]þûþßå¥ÿóÿw×5ÏztðȬàŸ+¤Ìm`µàJqÐê}ö•ØE Éb-~Óý1cÿ—tùïû——þÏþß'¿‰^8ø?dÖÌÿI}à$£†˜²æ’§{ÀÑï‚«ˆ5g:ù ¬ÿÑŒóÿ]Òå¿ïÿI§þÏþßÓžöúÏþ™Uçÿaªô5’• [àdM S0…éf`RÙ¶ÿû»¤ÇÿÕþù¿têÿìÿ½éîÇÞ:ø?dÖôÿq†}mÅ?$H™9ϱJ› „Bà7Ýÿõ—tùïŸÿwø¿:ŸÿÛç}ÖàÿYãÿDRÌml›ô{cm)Cˆ¾´¡AÈø ÍN~ã"ûÿ8öÿwI:Qÿ—þÿÕùüÿ_ú©ñþç1³fÿßHcL,ê žu‰A½CÇ]jôF›îÿû?;¥Ëÿ‰ú¿ôÿi®ÿWïxÓSÿ‡Ìÿ±wö¡ß^uwå²,«™Tþ±ÌÆÎÃçá|¬lÖ´Æj8é<}H¡A®=¡–̬˜•1‚Ýý{e¥”š‘Db+d AgË‚–äªÙùîë÷W×ùÂÅÏ‹+.8ïÁ`÷}³ëû÷:Ÿóð:Ÿ³‚ÿØfùBÙÛ¨}ió~4œ0g¦‹@±RûÕM×ÿäÆùß.éòß÷ÿhéÿú¹þëûøÉÁÿ!³‚ÿê„=t}ÊRd‡ŒW‚äòtúïìçSÿý?óÿ]Òå¿ãÿ=óηÿÉ7”_|¼¾èžø­O~êEW½þ‰·¿íy?ôÚ˯yÆ]ÿõèÛýÍšù@IhÕG1’CDª­M:Ýü)ÆìL…Ïkýcÿïÿ)]þûþý_ÿ÷Š;ÿ÷\þŒ?ë×Ü8€cfÿÓ“±-ökŒr2™Œ/6ø,P©¤ªS*yËýô£þï“.ÿ}ÿ–þ¯Ÿý?ûÔ5ïÀ!³¦ÿ¨ %ÚÈèÔ—X#(l|r’L› #WÞôþÓèÿ¿Kºü÷ý¿ÿ³ÿ÷ŠÞñ®Áÿ!³¦ÿ7Ñ*ÙÕ”=;¶bãµ*dÅ(c²'¿qŽúoÆûŸû¤Ëßÿ»¸ôÿüìÿÝÿæ½iðȬñÿÁ™êI}PК(†TNMÉ8U "eÛû4îÿí“ÿöÏÿ/.ý?û/‘WýûàÿY3ÿGÈ%)D&WÚZÔVõdkûñÈλ”QkÝôýŸöŸƒÿ=Òå¿þo—õÿÁùüÿ%×?ýeƒÿCf ÿÙ¤X2JŽàÅ× Èqj .TB£Ÿ nëÿñ8ÿß%=þ¹_ÿí²þ?8Ÿÿí·nœ3kæÿ^‚¤ 6±¶@@)Cõ…‘4Åj³5Ê'¿qžý?7úÿì’.ÿ'êÿÒÿå¹þÿøý¿™Uûmq¬—*m-€ _ļXÏ6(+si¿òçñÇû?û¤Ëßÿ³Kÿ—çúÿìW~ä‘Áÿ!³æþ_Rô2dÀP/Cj5:;[¬XIÞJÝØÿ绤˿ÿ_ÿ¹ÿß?þÏ“Ïü2ëÞÿIA¥ÔêL̹úŠ ~[}.Ñ( ÄjÜ–ü£ïî“.ÿ}ÿÏ.ýžûÿ}÷ûï2ƒÿCfÿŸ#6%«/Î( TF,±HÔâ´ܦüó8ÿÛ%]þûþŸ]öÿæÙÿ{çû.üñàÿYãÿ&&k‡` M°krSçŸ6&Ä”KŠʦõßÑðÿwI—ÿ¾ÿg—ý¿yöÿÞòÞ¿ýÿ™5ïpN-u‚­à»¶þ·~ê f äàB­ñä7ÎQÿÁ ÿo—tùïûvéÿòìÿÝö¦;îü2kîÿ%Ud­ I%—JÂ\ŠOãÔ ¼¨KÁº-ùGãü—ôø¸þÿÒÿáÙÿû—]ýÐàÿYsþ€$“i瀲ÏZ¨[J‰˜@õä7Îãÿ˜±ÿ·Kºü÷Ïÿï_ú?ÏçÿQnþÁÿ!³†ÿÂ9oÈÆÂ«uY¦k@ ¦ýÖ„m°1gwòçáôÿÛ'þï7ýúËúÿð|þÿ¼_yÃàÿYuÿ?3e „jÏÚ¦þh°Níÿćä\1›ú¿`Gÿï]Òå¿_ÿ—ü·‘âÿ¯§ÿøØàÿYsþgŠT4Tk+ËF‰­'’Åi›P²5¦´éû_l‡ÿ·Kºü÷ý?\ÌÿÛHq‰ÿg>çß^7ø?dÖÜÿ)ÅÏbö¢b‹54ÝVA‰!VñvËþŸ8µüï.ÿ}ÿþ).ñß½øÿ‡Ì þsd¦D•SvAØsl+ÿâ lµŸ«‡·ÿ³ëÿ]Òå¿ïÿáÂÿm#ÅìÿÜú+ü2kúIÆ1ÅJT9ÔZD‚x²ì|-•7½ÿ7úï”.ÿ}ÿþo).ñÿÙ—¿ñƒÿCfÍû?ÉF!Iœ¹k$%ÐXh+늣6ýw›öÿ‚±ÿ·Kºü÷ý?\ø¿m¤¸ÄÿOßvûÓƒÿCfÍûŸÄéá¯T4ktN£OÚÆƒšM[4dÕsÚ¸ÿÏðwI—ÿ¾ÿ‡ ÿ·—ø‡7üÁ þ™UýÿÉdƒÁD­mµs•â23DÉÔªµ‘O~ã\ëÿ±ÿ·Kzüßwâü¿Ãÿìÿ=ôš þ™UþòÓëŸEuzùÚ: I‘6¸hBɨÊEhãþÿ£þï’.ÿ'Îÿþ).ñõ¯?öGƒÿCfÍýãȈõT³ää$ ©É%W#k.\#ÂÆýÿ†ÿ»KzüC¿þ?´ôî›Ïÿ¿‚®ü’Áÿ!³ªÿG .EÉq.ëÔ°jƵx ŽãMïÿã¸ÿ¿Oºü÷ëÿCKÿæúÝ nJƒÿCfMÿ/cÄTT qj“ÕéÚ¿ñ$4íýcý–ï™Áÿ.éòßõÿØ,ë?ÌõÿSï»ùÕƒÿCfÿ1ç6—6õÏΦä0ÄZ gÈÑRu±-lÆMûÿõÿ^éòßõÿØtêÿìÿ}é›ÇÁÿ!³‚˜^úÍ¡–à|2L‚Fª©â“'ÍìcUJÛÎÿíðvI—ÿ®ÿÇféÿÂìÿ}×S×~rðȬ¹ÿ'R…j°FÄê]afN¤z¶Æ ¦mûÓðvI—ÿ®ÿ×åöÿÞûü{ü2kîÿ˜ ÍÿkdH1 q©]iÓÿˆmñOS€-ïÿ´ú?æÿ»¤Ë×ÿc³ôÿaöÿ>üÍ¿tùàÿYãÿY5™s¶¨’ñÞ%[2Y±r[ØÉJ'¿qþ[ÿ{¤Ë×ÿc³ôÿaöÿ~ö¶O_6ø?dÖôÿi>µ:\òÆHÌX²§RÕºT ˆdDN~ã<ûÿãþÏ>éñ¡{þÏféÿÃìÿ]ù7?ð£ƒÿCfÍü?4úÛ|ß"ÉlEc¢¡Äiã?å@Ò¶ïã8ÿÛ%]þ»çÿl–þï…ùüÿÏ®O þ™5÷ÿ\ÁIò¥6œ$û8YÄ@.xäHâ¸ý‰“ß8Ïþÿ—tøÇ~ÿ?6Kÿ÷Â|þŸy÷݃ÿCfÍýŸ’;©ä10cIªÚ¦P+•i0¨Ér‘²©ÿoÇýŸ}Òå¿_ÿï[ø?xÖÿïßóÆïü2kê?–Z£Ã .“)³Cc£ã’C,I\¨¤acÿÆþÿ.éòß÷ÿî[ø?xÖÿïîÛoÿìàÿYãÿ–k.Þ؈bPÃD°á¢>6P Ú°íû?4úï“.ÿ}ÿ¯ÇÿìÿýÈ£¯|ñàÿYÓÿ“a‹Ù(Œä‹!ë-[JlÚÿÝðvI—ÿ¾ÿwaéÿœõÿûÊw}ÿCfÿ5åjS”\ÈÆÌÖ"k«ÏD ¨´å€Ùrÿ¯ý¸þ»¤Ëßÿsú?û÷¾Ó^=ø?dÖø¿^BÍh%‘@Óa€‡é)ÐZÅš”R[œüÆyÖÿÃÿÙ']þûþŸëÔÿÙÿûË·~Ë=ƒÿCfMÿ¯"Â4Ñ' ©YÀæbƒ+^ÄëåM÷ÿìàŸtùïû=þÏÞÿ½æënü2kü?*䪙fýÈ’PK•+«ZIÁ y_pÓý?äÁÿ.éñ¢ÿŸ[úÿgýÿÿýÿ÷ÿŽ™5õ_É›kÌê@4FÎ^ð&'±%•ZmtuÓþßèxœÿí’.ÿýó·ôÿÏúÿÝñ²»ß=ø?dÖôÿI9'Vg£'_ †I %6I+ÕHaÓ÷?ÑÐØÿß%=þ݉ú¿ôÿÏúÿ=÷ÇÞó{ƒÿCfÍþŸr«ñ¦ÖŒê)3¦bÛ\ TLÆDСHÜôýo4cý¿OºüŸ¨ÿKÿ×ÍõÿŠŸüþÿ‡Ìÿšø£õW‹•‹1!©Ñ+¤)Ù P·ä˜FÿŸ]Òå¿ïÿ¹¥ÿëæúÝO<+þ™5þG©É¦ªíÇ@ ¡ YLqEŠAÏÊÜVë¹l»ÿgÿ»¤ËßÿsKÿ×Íþ߇^ú›Ãÿ9fÖø?¢Œšt2¡Y hôÐV¹L¿]ql¶]ÿ÷öI—ÿ¾ÿ×ãöÿ>úS?÷σÿCfÍý_±Ëyzç#™©¶ÁÀï— ÖÛ²íýŸöÿüï‘.ÿ}ÿï¥ÿçfÿ/\¦¯ü2kÎÿÁDªd5Ä ÉPK%õ–µ: ÜÖþ¹ýœÔMßÿe7ÞÿÜ%]þûþßKÿÇÍþßM×¾î‰Áÿ!³æü¯†ˆÉ2¤K)!'pÂRs¨à• ¬­§i=ÏúŸ†ÿ¿Kºü÷ý?êÔÿ³÷¯ûèwþ™5ûÕ$ŸÜtÛ×BhK~É ‘aê –* T¿íþ?ú¿Kzü?Ð?ÿ§Ný?{ÿ÷ž[üàÿYÃ?_l$G ÔGãÑdSÄÖDS`F³&¿iÿ´cý¿Kºü÷Ïÿiéÿ>pöþïMß÷‡ƒÿCfMÿïZÀÆäBö5Dá¶(ÈqÎUIJMêˆO~ã<ûÿ£ÿÏ>éñO'êÿÒÿ}`>ÿÿÄÕ¯æÁÿ!³îýïh¦®_ŽŠ5ª˜Ub¬¶PJRKÛ˜7íÿÙæƒÿ=ÒåÿDý_òOsýÿëwüüçÿ‡ÌÿÏjuÞE*ñÔ¨ýL°áP #§È”åä7Î1ÿ‡ñþß>éòß÷ÿhéÿÓ\ÿ/{âe×þ™ü·ÙQSI (àm%¸”DÍÔÔ ×-çÿàyÔÿ]Òå¿ïÿÑÒÿ§Ùÿûô#ÿtóàÿYÃŽªbÇZœäTBa J ‰Ù/ì¶ýÿØû»¤Ëßÿ£¥ÿO³ÿ÷Û¿ñ¿6ø?dÖôÿu‚ ê —Ôê›(ÙY :›ÈlºÿïGÿÿ}Òå¿ïÿÑÒÿ¥Ùÿ»åÑçþààÿYåÿ“Zçд"š}H¤ÑøX¸ÀLÁ´IÁÉoœ‡ëÿ]Òå¿ïÿ]\ú?4ûîŠ?ýåÁÿ!³‚²ÅVúÛ’?dj t 9©L™®Ôè¥n¹ÿ‡íO þ÷H—ÿ¾ÿwqéÿÐìÿýí7Åü2ëÞÿIΉoÿ¤DkÊZ5(xAW(жëÿÑÿcŸôø¿Ø?ÿïñ?û·~ùk¯ü2køGOÑ[õJ¸˜PP“ ÓC !U¬UE9ÙMÏÿóÿ]Òå¿þo—óÿ‹óùÿ­WüÙÿ‡Ì þ]$o*egÙ¡Ì5ãKŒ˜qŠm8Ýôþñ˜ÿï’ÿ¶_ÿí²þ_œÏÿ¿êš{ïü2küÏYJô]ã“RÊÞ—ÒþUM”iT¯5F:ùóÔ?îÿì’.ÿ'êÿÒÿ·sý¿ñ·rÉéÁ—ZÁÌš‚¶.ˆñÉ!êš÷'©o…¤ (®ŠÕ¼­ÿŸôðÿï¢&ÿmÿ,ýÿ0ûÿîùÜ+ß9øïRkâ¿e!û赊¨R±Ù³¨ú‹bBi vð_÷ÿÿOjòßòÿ=íÃWüÆÛîÿ³WŸsÉ“§žxã9ßwñ«^þlºø5ï½öÄ«øò“ƒþNµÆÿ¯t¶ÅF3¥úÆM§¡ÿÖQð–}’z ÈiÛþ3êÿû¨ÅÿÉvýÿäÒÿ³ÿï¾·ßñáñèRkú ÇÖ¯TÔÁcZ)câ–„ ¢ß´ÿ_ë1ÿo5ùo×ÿO.ý?'çúÿå¿ð—Ÿüw©5ý?ÎD؉ʜ­c6”*Ï…¢XÉIŸ½-aÓý2üÿû¨Å¿nǽŒÿ'çúÿåô÷ïüw©5þƒÁÔˆ)cÆ L­ÿ5è'$¤¨cPúà3Žÿͨÿí¢&ÿíø¯—ñ_Ïñÿç^tãÿ]jMü§P $F'9/>@ÎÎØà¼.¨Bð[ò¯ë·m𿇚ü·ý-þçøÿÌŸóðà¿K­™ÿ›(Bö€Êƒ+œ]ÁÌ}ªq:CTÉ€rnÓü_Ó˜ÿ½‹šü·ýzéÿ׳ÿï¶·>ø-ƒÿ.µÆÿ/Ñx…SÛËØsbŒb  ñBJÚ†MûÿŒŒúß.jòßöÿé¥ÿ_Ïþ¿{|ãO þ»Ôšù9ke0qΨ©úŸiï/G_¢¹„ŒÖ ÞÖÿ7öÿî£&ÿmÿŸ^úÿõìÿûôÇný«Á—ZÓÿ/†%o€¢ ”id!—°šÞ Z+µéü¿züï¡&ÿmÿŸ^úõìÿ{׿¾ã—ÿ]jÍý_`›4:Y(ĨTòª&ÿdÁZÁ¢=8y*þ¿åþ5úwQ“ÿöü?½ôÿêyþß ½ê†Á—Zsÿ'"%€Š6Q¬y@B‹Þ‹NÊiŒ®8׌ýà3ŽÁ?áðÿï¢ÿ§Ôÿ—ó¿õìÿ»ã²zlðߥÖðŸC=éןlâ©ç'EPB–êoR–dœ“¢xÛúÿ¸ÿÛGMþÛõÿÓKÿÏé¹þѤ;ÿ]jÿ_<¥éÂÏ «?£Ä¦³€ƒ@bü´LÔ¦ýÿ Ãÿ¿‹ZüS;þ·øŸëÿŸ½áãüß§Öøÿp¨ ~ ÊÓÐOªàKíBÎÎ[ŠÓ$p§`SÿÿèÿßIMþÄÿ¥ÿ‡æøÿØ[>2Îÿ}jMýß§} Æ)ª\JrÚqÊx1¹P= Ô AxÛþ3껨ÉËÿwR©eü§9þ¿ö÷žÿ·ƒÿ.µ‚ÑÅbÑÔ(¯Ù…`t6±YOŠb â]tå©ÌÿXöÿþß}Ôä¿åÿ{Úý'Ï}Þ½þ“ç^÷_W?þø¹o¾êÞÛÊ^õॸå}§oôwª5ü[ˆ…‘­±sB㢎²-E‰(–¨ˆ5mºÿ³>n𿇚ü·ü5þ/ý¿4ûÿþñ¿4Îÿ}jMý¿Ri”$¯))JY΄‚¬Š+* %n9ÿ›5ü5ùoùÿ*ÿKÿ/Íþ¿oÿeoüw©5û?”1‰!x]±ŒèÙÅ‹"Ë™sàšPÔ›Æ3îÿöQ“ÿ–ÿ¯ò¿ôÿÒìÿûÒ?ß2üÿ}jÍý¿‡œNÁ•¬JÒ…•skà9û¬|Æÿ]Oƒÿ=Ôä¿åÿkó?ûÿ¾ñ²?¹qðߥÖôÿX äCðÙBòAš®ü@gƒg­÷Öl;ÿÇ þwQ‹ÿ»[õÿÊÿÒÿO³ÿïÖG¿ûóƒÿ.µæþÏÅ$ž¡`deT‚)&Wœ3AC²E‡áÿëQMþ[õÿÊÿÒÿ÷\ÿùE’ÿ]jÿ¯XqJ'ËõWR`?5ÿykŃVIùâ…C<øŒãäÿjÌÿÚE-þÍø¿ôÿß=×ÿ_÷ýðoƒÿ.µ&ÿäÐÔWyË: ²²¶%/Z$ªb†à6ÿ4Îÿû¨É;þßµôÿ˜9þ_yÇŽþÿ>µŠ6* xŸˆÓô‘‚*½Pô¹d,²‰›Æä1ÿk5ùoûÿîZúÍÿ¿ó­ïõÿ>µ¦þ5ÁGU"jË6‹† Ù³eN9U²„àaãù_4òÿ]Ôä¿åÿ;©¸ÿçù]ÿMŸüw©5û¿…¬M€&ô,¡$“æ<¹‚3ê˜ n¼ÿsÜÿí¢&ÿmÿ_‹ÿÙÿ÷ØK¿ ÿ]jÍý¿IâŒJhØTTw98ï|4XJHÚ—mëÿzÄÿ]Ôä¿íÿãFþ?ûÿ¾î’³îüw©5÷ÿY¦¥ÅïŠÁ\ß%yðÁE Ó`Àz MÏÿ@Ãÿ»‹šü·ý¼ôÿ›Ùÿwþ÷üìgÿ]jÿÞú¨À†„ф̑*>#`©Ÿ¼hV–CÌÛöÿ˸ÿÛEMþÛþ?^úÿÍìÿûèYúÍÁ—Z³ÿ‹UŠ@5ç·.L™b`Z‡˜%cB•6Ýÿ«Çýÿ>jñO»þÏKÿ¯™ýŸ~àæ›ÿ]jÿ µøB*â¼Íä-RBvœÙ…šúˆõoÛÎÿû¿wR“ÿvýŸ—þß{æúÿ5üÇ›ÿ]jÍùßšäÑ{Ù¬S …rN­ÀõSv:yåhãûÿáÿÙE þO«ñéÿ½g®ÿÿâG?"ƒÿ.µ¦þ&£.¡L«€™cñ1£˜ìr‰šXœãMç ûÿ]Ôäÿ@ü_ð_ßgøóƒÿ.µjÿ§²)᜵V³Ÿ"+‰5#ÀÌÚ{'tðÇáìÿÚGMþÛþ?^øÿë›bÞÿýlûüÁ—Z3ÿ#±²‘¶fØ¡V–Ì48VhML1mÊ?ã8ÿï¢&ÿmÿß©…ÿ§¾)Îðÿöû_Šƒÿ.µæþ?ŠÇ€1%Z\Íþ)&ë ‚iÚ R¥¾>ãõ6cÿ×.jòßöÿZøê›â ÿ¿õk_;øïR+ø6F@ž°H2uÔ³€›~È)p&éúsãüÜÿí¢&ÿmÿ6âÿìÿ{ɯþú˜ÿÕ§ÖÌÿ×EBE¤ˆLÚë’$ À*#°V)½iý_pìÿÝEMþÛþ?lÄÿÙÿ÷÷ßðïƒÿ.µ¦ÿ§1'“\Fô9#“(‰1ìD$j€MûYÃà5ùoûÿpáÿ­oŠ3ü?ñç—>wðߥÖôÿ R^Yƒbh2h§ À`}²éÌ[Á™Më Gþ¿‹ZüßÕ®ÿãÂÿ[ßóüŸ§ß÷óƒÿ.µÆÿGÁ)ªx¶‘jº¯¢HʱˆWè½ÓÆÚiFøÁg'ÿ§Áÿ.jòß®ÿ7ø¿k®ÿáêóÿnðߥÖð?­ü-A+“µ/!BHY““)æì ©²åýŸ†‘ÿï£ÿ| þ/üÿõM1×ÿ_ý?<øïRkêÿìst¥žô­#Î&rÈ.é‚ JH.!¨õ•pðÇà_ɨÿí¢&ÿâÿÂÿ_ßgø¿üº{¯üw©5÷l‚+ò%íXic¢V˜k* CacLÈb>ã8üãà5ùoûÿpéÿå9þ_÷†¿aðߥÖÄkS&k806æb,‰õP Nrv´éùŸÇþ¯}Ôä¿íÿÃ¥ÿ—gÿßïüÀëŸ5øïRkü•sR±žú‹7±¦ X±MI²².1$Žä·œÿ]ãÿ¸ÿÛEMþÛþ¿,ý?<ûÿÞóùgã8þ_5æÿí¢ÿ§ÚõiÄÿÙÿ÷Ó7¾í;ÿ]jÿh|ÈĪæû&õ8ù"#¸l¼Ç-ã?ëÑÿ»šü·ëÿ²ôÿŸšëÿïø¡ëoüw©5óŠ®)~ýØ¢ÐI‚˜B–„`BìÅF@Ü4þ›qÿ·üÓù²ôÿžšëÿw¾âSÏüw©5ý¿èfôÊc¨Q?³ŽÚI&×SA*É«²u[îÿÓ0îÿöQ“ÿñáÿ¥£ù§ò ÿxðߥÖÌÿ É–<×@&÷¯ XOÖaœÖtát@™Ò¦ù?ý?û¨ÉÛÿ' ÿ/ÍÿûÐË.>oðߥÖìÿ©ôO{~rIÐE—ÄE©Ñ_©lÊt\Oùà3Ž“ÿÿï>jòßöÿµøŸý/úÂ×ý¿}jÿ ÖorΑs(Asr&Ú¤mNNèàí–ý?lFÿï>jòßöÿÉÂÿOGóÿÒ-ó5ƒÿ.µæþ_ã“ädx*óƒÇÀ5ÜÛ⥂փËzÛûÿ±ÿc5ùoûÿdáÿ§£ù7}öKÿ9øïRkø—©ôWêÁä4ge$™<)§ ä¼iþσÿ=Ôä¿íÿûàÂÿCGóÿžxÉ'ÿ]jÿ'‹Âù¹ø‹”i×—RAe“LBï3Of[ÿ¿ñ5ùoûÿ>¸ðÿÐÑü¿çž¸þêÁ—ZÃ?%ÖY%œ0WJkþ/œ£-:$b€ý¶÷õÓàµø?0ÿñöÿ}í}ì¡Á—Zãÿ!-!1{m£SªIÚL•É P‰-[Îÿ`ó¿öQ“ÿvý–ñÿhþßÍwþÁþ»ÔÿOö5þ *¦ÂŽ5mŒQ.jã¬lTJ[öÿ3Ð8ÿï¢ÿæÿµøŸëÿ÷¼ò¢QÿëSkêÿ衦úÁiŒÑÈ.%ÏÞ&„‚SeÐÇMùý?»¨Éÿø¿ðÿÓÑü¿ûæ.üw©5ù?*ðÁ±÷ÈS!ÀDÞ«RbŒÓ,°¤@É–ç­Ìà5ùoûÿ`áÿ§£ù·_zÖïþ»ÔšüßêÈ6Z,Ó࿨'/`ñì¤ä*+6^{ðÇâøÿvQ“ÿ¶ÿ–þÿ£ùÿò¬×Þ<øïRküRrŒÊ僂’ɱ ½’hMÅWѶþ¿šh þ÷P“ÿ¶ÿ–þߣù½ìOþ»ÔšóÿTüƒÀÁ!fŸŒ&ï” Ù£‹š”iø¶û?Gýo5ùoûÿ`éÿ=šÿ÷ŠóÞò§ƒÿ.µjþ‡É³QŠêA¿X+¬ê៪@ ±Nb|Æ1ø'÷ÿ»¨ÉÛÿKÿïÑü¿ó¿÷Mçþ»Ô þ³@"Îzr6†œ½‹1Q&FëSÒXÿÈÄŸñÕù§Eÿ?ùÿ»¨ÉÿWúÿÎ:÷æ+nºâ/.Lïül~ñç¹ý¡‡_|ÞµÜò¼[®¹úì‡Nüןü¶A§Z3ÿ;ä’ÑiÏ!ä(¬—3õÐd$£‰ìüS9ÿóâþO ÿï.jñ`þßɯôÿsîë®>û]gŸøÉ}|¼úÔ þ5Öè£W•÷è DMQYNÙ‡¤W„Mý†‡ÿo5ùo×ÿO.ý?Góÿþú‚ßóÿûÔšó?%çK‰Y|”¬cF‹Úð´úƒ¼M¤5oÊ?ó¨ÿï¢ÿØŽÿzéÿ?šÿwÑþʘÿݧÖìÿÖP¦ÑŸ”z‚ÿeïÜCÿKÊ:þOeÙUVISºÎs™Ì L)ÒJºHæ37bIC‘èJ µ"F­QIk„Xîí· ‰ÝP‹@*RSh-¤-‰LRæó;þwæ§o‡æ½Ëîï{þØßkž¹¼æ™B±$É*Î.MÀ‰¸†e×÷?™dòH†ü뿬ë?.õÿÛŸwï['ÿ§Ì–ý¿¼UöÒ‹<^ÆŽdšk–hBΧÜìÚÿWiòH†üý?Yû¿¸Ôÿ¯ùîwÿÊäÿ”Ù²ÿ]<ûè„ZD"4aiÔ¸l9ù]Ïÿçþÿ!ò?öÿdíÿââÿ}î§íŸ'ÿ§Ì–ûÿ©²Æ@-XöS%Äš„cÿÔ‡‚V¡îYÿ¥ÿ=ù?"CþÇþŸ¬ý_\ü¿ïzþ“þzòÊlòÿ³sY‹ö)€„‚.µ¬-›I¯übâÒžþ¯¸yþL†üý¿ÿ‹ÿ÷ð¼ý·'ÿ§Ìþ[â±ÿÏŽÍWÉvr –ÐWéÞÅ%¶Lþê7n²ÿçgý?$CþÇþŸ¬ý\ü¿?Í[¾yòÊlâ?†Š1WŠ%JòÕA©¡øœ“¨ÕBÁÑÕoÜ þÃ|ÿó˜ ù÷ÿ“µÿKÿ¿W½é'gÿsfËýïZ'²9k@}Ö¯ÍgפÄT<3s)_ýÆMæÿ³þ“ÿ\9ÿ_ûÿ¸ôÿûìSÿãm“ÿSf“ÿÍÖ€‰BÊÉ›\Zub[%CÝóý¿þžï’!ÿãóÿ[kÿçåüÿçŸòƒŸšüŸ2[ø¯"êÐqÌÊ9 w®$ËÍgvb1ð—»k¹‰ÿ7ïÿ“ÿ:®ÿ·ÖþÏËùÿ‹Ÿ÷¿4ù?e¶õÿÊÕ•Œ1–à…]¸ÔZÃÂY µÔvíÿçgÿÏc2äXÿÙ­ë¿.õÿCÂïNþO™-ýÌùŒÕbË1W­/ZJâ’–Ž®a’ÿÏýß5ÿóýc2äèÿ ùÿ|ÿ¿¼ùîÉÿ)³¥ÿóÑЛ‹(žbŠ¥ªo\sñ!Ô´çþÿ¼ÿsT†üý?vëù¿.þß÷¾\ÿeòÊlñÿ}6_¡ ß¾öÓ E˜3hÉ-b¨±ôÕ@ÞsÿOÜ|ÿ㘠ùúìÖþ¿.þß—>á¿iòÊlá?f䜴^é-:Ib…2BN.ZqÂêžëq4ûÿ’!ÿCÿÝÚÿ×ÅÿûdùÛwMþO™-ûÿäC*´å@HäZH˜ YÀجæÜZà÷íÿsÿÿ ùúìÖþ¯~¾ÿß·>ñÎÉÿ)³eýŸJåÒj†j508Qm¨Õ;‚æ¨Ïþ‹Ä}ûÿÀ¬ÿ‡dÈÿÐÿc·öuñÿÞó•÷½ròÊlòÿÌÀû¬¢)^Nü“ÄË€N­ƒ,„}ÏÿHçþß!ñÿððüŸÝÚÿÕÅÿ»óõ/ú­Éÿ)³åüO¤YòMùòpäÖ=‰Ìì[kd°oÿ?Õ¹ÿwH†ü_9ÿ_û¿/çÿw¿â;^;ù?e¶Üÿ‰•Ì»Dƒyæ½øVÆË-`ö–#\ýÆMê¿Lÿ÷Œø‡+õÀÿrþÿÞw}ð'&ÿ§Ì–þŸ} šj >nªÖ4ôùQ*ÙCKIÛÕoÜdÿo¾ÿyL†üëÿ}kÿ–úÿ'¿ùi“ÿSfËúŸ¼™f®}Q^§I›9ïªO.ï€ÕFûòÏsÿÿ ùû÷­ýXêÿÛ¾íoœüŸ2›úÿ¨ X³/©ÊD ±/"@uRá=ßÿeð³ÿÏ!ò?öÿxPÿÿ¯Á7Áäÿ”ÙÀF Ù‰ÂeÚOPƒ U¢¶Z«’¨aèK«ß¸ÉþßôÉÿ±ÿǃú¿ø?gw¿bòÊlñÿR”B™<—¡—fvª\;£^,¶ EM²ëýÆyÿï ùû¼öañÿþéYÿÕ“ÿSfÿ” ¼k)©f&SŸ£ær¹ôË­.׺gÿ¿¾þŸ÷ÿÉÿ±ÿÇkÿÿïžôþ{'ÿ§Ì–óÿ¾öGl®€4–Üg/瓳ا…âžþ/ëôÉÿ±ÿ7âñÿžÿÀg^>ù?e¶¬ÿSH%ÔNAÀK÷#怩r‘KK­Õ)ì:ÿ÷0çÿ‡dÄÿýãó^ûÿ°ø¹Ýû‹“ÿSf ÿ–­xl(äDBh œ‘|®T/@lßûÿ:ù?$CþÇçÿ¼öÿï_Îÿÿóž÷äÉÿ)³åü¯©/€¡"Gd)™\h%pZ#†ìïÚÿ¯ÿ›ü‘ÿr¥þ¯ýÿû—óÿ×ÿã[vòÊlyÿ—Å•¡æ‹íßWú}ªْQŽRœ šø}ë¿›õÿ ù¿Rÿ×þ¯,õÿ‘w=vÇäÿ”ÙÀ¿#—*”|Ÿö;ÃÀX‹–Nµ§lÍo”víÿG2÷ÿÉÿ±ÿ÷ÐÚÿ‘¥þÿÝáÑÉÿ)³¥ÿG3Î}šïƒI¡Ð1gh¥ZJ­ÿP!U¢¶«ÿÛ‡™Éÿò?öÿZû?²øñ÷üòäÿ”ÙrÿG2jòSDßÿÊÍÄèÒ¤¦”±4_;»mß÷?fÿßc2äìÿø_ü¿oüø­—MþO™-çÿ[ð}ÐDÉ™KÐ(&Ÿ„ú¬‰KÐÜžïÿ²Ìó¿c2äìÿá`þ¿ø÷|ô}ß9ù?e6ðÏV™¢'…«+¹––sJÁblAkeÔ]ûÿÁ|ÿç˜ ùû8¨ÿ‹ÿ÷ØŸ}ø““ÿSf ÿͨ”¼š%eµË3€èè2õ§Û6P‘Ë¥ «ß¸‰ÿKsþH†üý?\ûÿ²ø?úÁ¯úâÉÿ)³¥ÿ'CÍ& ]”–Åøòh(¾¯ äâèÕoÜhþ?÷ÿɈÿ[ãó\û¿²øÿÞ0ïÿ3[îÿ€«Š X¨5ʾ0ˆ–>€ªôÁ T¿kÿOu³þ’!ÿãó\û¿·–óÿ|ò©_0ù?e6õÿ­1fo¹µ¦ ÄìÔk£ê+(cõDûöÿÖ¹ÿwLFüÓ•ú¿öo-çÿÏxËû¦ÿwÎlzÿ3DçŠeÏÁ‹«¤Þs,Ú¡O•"Vˆ)w|¯~ãFþÏœÿ’!ÿWêÿšZêàW?}òÊlšÿçËö_)‰­:¦P¢o@@±¤æ²&ƒxõ7àßOÿ÷˜ ùû¸öÿi©ÿ_!Ÿ˜óÿsfÓþ.9wÊ‹¯>ˆkàcsMZ¥¾Ro¼ßµÿŸÊìÿwH†üý?\ûÿ´øŸyÜs¦ÿsÎláŸG¨â ¸†¦k…àjUI«DÖ »öÿëÃÊäÿˆ ùû¬ýZü¿Oÿ¾Ü5ù?e¶¬ÿcöI87àPÑƾüÅ’ô¥ÿ3`Ù©³²gÿ/7ýŸC2äìÿ=°öhñÿ÷þ/»gòÊlàßS«æ-Q°ÒÖ‘G—Wˆ´tBaWþfÿßC2äìÿé þ/þßKÞ{ÇG&ÿ§Ì–ûÆš2_Úþ—xyð“9ñÕÅ€ €D)ç]ïÿÃ|ÿç˜ ùû:¨ÿ‹ÿ÷Ðýé¯NþO™-ûÿ>Ki`*În¡ôñ©ö1õ Õ|õ7ÚÿŸýɈÿÇçÿºöiñÿÚ]/žý¿Î™-ýÿŠ¡·FŠ\|%añ¾ ,è,@“võØOþÉÿñùÿ€ÿ—óÿÿù‚w¼òÊléÿ•BõHY]s¡aH ÑD%Lú¯Zv=ÿg™ï’ÿþJý_ûÿ.çÿxÙŸ|ÿäÿ”ÙÒÿÓ‘y©jŒ$G.AÅZ"Álö=ÿŸïÿ“!ÿWêÿÚÿ÷KýîOû¡Éÿ)³eÿ?S_ó³DäêÀçD¹óË­˜ ÂS%×ö=ÿ—Éÿ!ò?öÿtíÿú¥þ£û–MþO™ ü_:~'ÃËÍ_ç]6ôZ¼ç¦Ø¼9Ób`˜®~ã&õßÍýÿC2äìÿéÚÿõ‹ÿ÷ºg>úu“ÿSfËý¿c¥Ð¸ß°iÍ‚¹èµVõÍ_Nú¿w½ÿ#~ÖÿC2äìÿéÚÿõ‹ÿ÷¦ŸyîOþO™-þo 59Í•ÕbÌV}-ì›6vŠ•’¦eÏûÿâ¦ÿsL†üý¿‡×þ_ü¿W}öퟘüŸ2[깬ú›z¨d26Ò¨!8•Z=—"ºkÿOšëÿc2äìÿø_ü¿/ÿžg~nòÊlyÿ}iXi[ÓR„Ô,"ï$s©¡9)»žÿOÿÿ  ùû¯ý?¿ø}åk~sòÊlàߌ‹’`éÅ?s…°/ÄrÆL1F×É»öÿóóþß1ñÿÈøüõñÿ>û´÷Þ9ù?e¶Ìÿk X­W~ BÙ'_/ hƒlÎð»ÖÓÿ9$CþÇçÿ°®ÿ,çÿw}è÷¾pòÊlñ}ÍQ)§’ÕKЋõOÉ blš‚¿ØeOÿOÎþ‡dÀÿƒîJý_û¿,çÿ?õì߸5ù?e¶ø¿A+IåB¥d±ㆩւkHTª€à®ûÿ0ý¿c2äÿJý_ù¿}¤¸Íÿ—¼àßæý¿sfËþ_Î}ˆ–/·þ‚±ÃP\ŸúKMâƒdI!†}ýš÷Éÿ±ÿ+ÿ·‹ÿç³^8ù?e6ùÿ’›C—³½ù(DÆæbí+ÿËn`ËÄ»öÿžóÿC2äìÿø_ü¿gßzâïLþO™ ü—šúÒßt.ø––72–fIIœ£Vìyÿ¿¯'æû‡dÈÿØÿƒ•ÿßGŠÛü?õ£ïüðäÿ”ÙÂ?)6dr®æÐúìßúh —u·˜€šÇ]ý_œï“!ÿcÿVþ)nóÿêw>úÎÉÿ)³éýo†’‚DNESŸíq^b–Òë´:Õ”w½ÿ‹~ú?‡dÈÿØÿƒ•ÿßGŠÛüêžÇ?ù?e¶œÿCÔ¬—µ¾¸ 9ÅT\4ç½KÀЙ‰íÚÿçûÇdÈÿØÿ»åÿô‘â6ÿÿ‘_Êäÿ”Ùrþ“@tŠ[uÞP±×ü¨R·V8 æ¼×ýºÍÿ<ÿ;&#þïŸÿß¿òúHq›ÿ××>°ŠÜú” JãVr3ß®~ãÿοOþÉÿñù¿¬ëÿ}Ëù¿û†»~mòÊlà¿&‰P¸ …–BQŸ:¾Ž"ÇÛjN9ìÖÿ›–ó¿9ÿ?$#þy\ÿe]ÿïûüûÏyÙMþO™-ó%%K ­JÄ©óšJéã)ƒÛëýÛüûyÿ÷˜ ù¿Rÿ×üóRÿ¿þ/ßò7“ÿSfKÿÿê8&ƒšr!((Kò$¦©œ8*xõ7à_aú?‡dÈÿØÿ“•ÿßGŠeÿï/ÞóØäÿ”ÙâÿºT­”ÒJËѲ%4Ð]î¿TÑIõ´Ú^þÏíõÿœÿ”!ÿcÿOÖþ?/þß¿~楯üŸ2[ê_äC'¶×üÑAèü—œtþURn,&àö]ÿÏûÿÇdÈÿØÿ“µÿË‹ÿ÷’¿zòÛ'ÿ§ÌþFŽR*jÜ:°­P•=QTg¦Â{Ýÿ_ÎÿæûÇdÈÿØÿ“µÿË‹ÿwï?ýÇ&ÿ§Ì–÷?[J`”Åê¬rELê1Š¥(Vt·÷?–ó?šóÿC2äìÿÉÚÿåÅÿ»ûß÷ “ÿSfËþ?bTFŽM]1i €Fh¼ôþ«.•¨©•=×ÿ¬³ÿÇ1ò?öÿdíÿòâÿ½ôuûÚÉÿ)³eýßp÷ƒÿ]j‘ÿG JÈÙ0«3UÈÅÚ’8ôlA™k9öçPÿõuùïùÿÿ3ÿ¯åÿ}ìÎÿ»Ô"ÿ¯ÔšKI9æœb ¥^=ZSJˆ@q­ûÿ¦þÿ¸ÿcuùïùÿÿ3ÿ¯åÿÝõå/üïRKîÿ2¹(úÆfÈ)øêŒÆ RY!Ä”ÛwÍšeÕõ?ð8ÿßD]þ{þ¿>ÿ“ÿï5/|Ó[ÿ»Ô’󿨘Á£k»|Tç½ZÉHH §êƒ†U×ÿLÃÿ»‰ºü÷üÿ™ÿ_Žòÿn¹êCÃÿ¿O-ñÿ*To|‰.:¶Û¦ßÙjs{H ‘Ä!êºý;Îÿ6Q—ÿžÿ¯ñ?óÿËQþ߯þÊwüÕà—Zrÿ‡¹x„â ir ÅpA’ñU‚Oë¹ð?æ·Qÿnþ_ãæÿ—£ü¿é±—þw©%õ¿mõc>,ò}r.ÙÂ*…‹aÊIb¨¥¯®®™ÿCVÆý_›¨Ëÿ1ýÿ™ÿWŽòÿ^zÁ»Ìà—Zrþg-ÇX²/žüá2`¯Ð% ÖvNTôYÝÿëfóÿvìÿ7Qÿnþ߉3ñ"øÙ'Ï\ôÔSÿø¥'/ºà£oþä…/þè=ïþ›ç\|ê¾6èß©­ÿ­h#ý0êW ”*º¶°Ñ©€%o³ÄUóÿpÜÿ±ºü÷ëÿ‡çþŸ£ü¿½õù¿;Þ»Ôÿ¦¶ÚŽ r(©±ompÕxWlÛhõLiÝý?ÿÏ&êòß÷ÿõøŸüW_~Û-ƒÿ]jIþO Pj’²“,é`øÁhÑXµ>pÕ5ó?FþÏ6êòß÷ÿáÜÿ”ÿw»¹ô‡ÿ»Ô’úïdÖ(&stPu’Òa $*ÎkƒUë?óðÿm¢.ÿ}ÿvêÿäÿûí7ÜZÿ»Ô¢ü?áz¸íŠÍd# ¥fO½õ •}ÆÿýüÚ‡ƒÿ-Ôå¿çÿ;qÕé“/¼ó7>ùög®{úé“7_ý±ÏÝü#Wæ'>{Þe?öãö½jÿX}6‰m¬ z²%(°Řô0ÄØ Mì±Ï8—ú£ÿ·‰ºü÷ý8÷ÿåÿ]ó¢Gîo€]jÿР7Ö7ÌMaö>¤ÚV‘½’+š„£Iíªù¿ ãüuùïûÿpîÿ=Êÿ{þ«þìžÁÿ.µÄÿÃrðù&"Á¤¶ýG4ÊÕ2Tˆ™ª­1¬›ÿ‰ƒÿMÔã¿›ÿ×øŸûòÿþð?_6îÿÚ§–ä‘sÄm¹±<ŒÕ!e£¡- ÖÍÿ7£ÿ·‰ºü÷ûÿ8÷ÿåÿ½úe—¼|ð¿K-9ÿ37~»œRÕ ˆŠ`bûn½ØJhÕü?çÛ¨Ç?Sÿ;üOýÿSŸý©Áÿ.µ$ÿ_„eâÚb?1x­N2X‰(Þ¯‡ƒ¬:ÿÇÃÿ³ºüSÿçþ˜êÿ{{OüïR ø'ç5'LQ¬KÎÐÁ3昂5h%%ÎëÎÿËèÿo¢.ÿ}ÿß=sÿLõÿqwímƒÿ]j‘ÿ¿jë] ™„¢‡¡¡ª ûö:°¾mÿ×=ÿ78øßB]þûþ¿{æþ˜ü'.üÊþw©%ù?&VCj$H0E  ¶íy)!yÞ ¥R¬×uý0ò?6Q—ÿ¾ÿ:õòÿýü]0ò?÷©%ó¿‡Ù¢hJêZÉ/^²/ Tp…jëªùŸ`FÿouùïçÿA§þOùw_‹ïüïRKöÿ©ýD@‰ƒjéÐ m×/®-þ¥ðÑÚ÷ÿ¡ùÛ¨Ëßÿóüo˜ü7^sÍéÁÿ.µäþ?ö\1!TiÛÿd™ y  í%p¸Ð”’Píºý¿áÿÛF]þûþ¿ÿ“ÿ¯>ñŽßüïRKø¯¹mû«§Èâ Qm_N…±°X…âmµäãºþõõø?ÓïÿÃÜÿ“ÿïÑW|ãÄà—Z4ÿ—\©Øª|q)GKÕ$•RÔ`äœ2eKòšóÿ„2ò?7Q—ÿ~ÿæþÿ3Sÿÿ‘ϼêMƒÿ]jÉùµ ߘ©z›­Ut1 m#P "§dCYõüŸìðÿl¢ÿ|LýŸûÿÏLýÿ¯Ÿ}Å3ƒÿ]jÉý_I0ÄP[‰÷.xÇ ¡…‚5[¡¡àaÝüÿqÿß6êòLýŸûyªÿw¼çúóÿ»Ô’þ?6F1ªdCfµÉ²cŸ‚Љ¦HDvÕù?Çcÿ¿‰ºü÷ý0÷ÿòTÿ¿ðÇ¿tïà—Z2ÿ'àKÌÆûÍ6g1‡Üã¡xu¤µ½VíÿŽú¿‰ºü÷ýgæþžü•ï÷ïSKü¿˜+XûÍ1 Ãliñ–$Z®¡ä\}Ûpx6ù_sþa𿉺ü÷ýgæþžüßFù§Áÿ.µ$ÿÇÖV%«jΤè 8ol=Ü V£$ëWÝÿ þ7Q—ÿ¾ÿ¯ÇÿäÿûêÃß~ëà—ZÄô6—²hô9eW#””s \%ÄUó?¨ýÆ þ·P—ÿ¾ÿ;ëÿÉÿ÷çû¼¯ þw©üK( Ȇy` Q2_=;:Ø~+rÁªFs\uþFÿuùïûÿ¸Sÿ'ÿßOù#4øß¥–œÿKDjö!q’ÄÈDôV«%Ä,¦½Ž}Æ9­ÿÿ›¨Çÿ}ýþ?Ïý¿<ùÿn¿þß:øß¥–øÿ\r”׆;¸”B±Õ¨ N|°*®„Zšü“÷n£.ÿýþ?Ïý¿÷Mýÿo½¯üïR‹ò¿TB*!P0µð¨yRë1Ô¶(HñØgœ ÿfäÿl¢ÿö˜ú?÷ÿÞw”ÿóð?7øß¥–ä+$dJŠ $Å·Ÿ4:ôÙ¶7FkÛø¸ªÿGFþï6êòLýŸûíTÿÿã™ïý™Áÿ.µdýŸ«BOì2IFÛVû™#€=ÌþºxHCõ«ÎÿŠ󿛨Ëßÿ×ãªÿ·_ùþ«ÿ»ÔÿO±Ö…ìS<ÜÿAjÂáè¼KÙ×¶ (ìLÆcŸ1ÎÿþÿªËßÿÇsÿ¿ü?øÚkÿtð¿K-¹ÿϵŪ¢i¥?N’ A1’¬ië~±–uù‡qþ·‰ºü÷ý<÷ÿÛÉÿ÷ã'ž~lð¿K-à¿T‰%¤†¾)Ö)·Õ@‰Þ†sN5°w’ܪùFÆþuùïûÿî›ûìäÿû»›ŸwÍà—Z’ÿg4ÚÃߊU#më¯Õ#™­ ¶ «Îÿ»ÑÿÛF]þûþ¿ûæþ;ùÿîüÀ‹üïRKöÿB„ ZcÚ€1ñŽ«í·):&ƒÞ¯zþvôÿ6Q—ÿ¾ÿÏvêÿäÿ{ä­ï¸að¿K-à?-U°'ŸŠ'd§1ú šKÉ¢µpä5ÏÿÛRcÌÿo¢ÿ§ûýÛ©ÿ“ÿïÕŸþÆÉÁÿ.µ¤ÿ²=$ýyV§.ª«Î¶-€i?¢óÆSH.•uódœÿo£.ÿýþ‡ÿÓSÿÿS¸xäïSKÎÿ™);ÒhÈQâ¤HCÛ;@jcͳ©ÿn¶þ§qÿÏ&êñOóúþÉS/øÄ¥ù÷>W.û÷G?ôÙ»ì7ã\ü¿ãþÏmÔãßõë?Íëÿ½SÿÿÍå_ þw©Eç6:—Œó¢ ê!ñ·ýAÙÄ\À±Z=öçrþ7ò?·Q—ÿcêÿ<ÿÛMõß?ñŇÿ»Ô’ó¿jcq3»¨x´>„ZÒa €)x@ŒVÎÿÇ1ÿ¿‰ºü÷ý4ÏÿvSý¿ò¡¯ÕÁÿ.µäþßYµÞA,9D &ÙVþ›(·7¹ŒAaÝú?ò?¶Q—ÿ¾ÿæþ_7ùÿžsÓûòà—Zâÿ°ØÒPE#†#iu±†dD3(âªù?4ò?¶Q—ÿ¾ÿ¯Çÿäÿûî+>øîÁÿ.µdþ¿pH¥’åBb­qll Ì¥ºà ÄJ!øUë? ÿÿ6êòß÷ÿÑÜÿï&ÿßãáÔ¯þw©%þÿÜðg4¶Ö`°¢ÉN£1T\û8ûöj¨R`ÝþŸ…1ÿ»‰ºü÷ý4÷ÿ»Éÿ÷×þ‰‘ÿ¿O-9ÿÌl4cÎz\ƒ DV=û²îþœÿm£.ÿ}ÿÍýÿnòÿ½ä[^ùà—ZrÿoðHNQ“GŒTJ1")„À©ZvÔ¶1®{þ?òÿ¶Qÿ³ýþÿ½sÿ›ügòäùƒÿ]jÉúÿPû‘µ­û—Õ[N çÒÞÜþ$›JB˺ªÿ·ý8øßB]þûýÿ{çþŸ³Sÿÿ’ë÷ þw©%ý?gm2=äHí«ØR,B¶ÒV™ê!þ3¯:ÿË<Îÿ6QéÖ4óúvêÿ?ðÆ_ù?ûÔ’û"D&‰6hÄÃÐ?°«©½ i,Ž)µi^ÓÿK‡HÀÁÿêòß­ÿhæõ_¦úÓÛ^òkƒÿ]j ÿÎdßg‹±”àÑhò 1rpÀ*b‰+ÏÿüMÔå¿ëÿëò?Õÿ¯úî2øß¥–ÌÿqÊõàùÅŒ¥½Ĩçö7nkJ´×¼ÿ‡ ÿÏ&êòßõÿ¡™ûÿeòÿ½ò¡òƒÿ]jÉüŸdˆEc1µÑ¬J²3ìœÓ’#™¼fÿÌðÿn£.ÿ]ÿš¹ÿ_&ÿßkoyðŸÿ»Ô’ù¿”5gåj½&öÎbÿÕ×\BP¯`‚ZÔ²îþß þ7Q—ÿ®ÿÍÜÿ+Gù¿ÿW þw©Eçÿ1 䘋7lx"* ¸Z•b9ôVÍÿFóÿÛ¨Ë×ÿ‡fîÿ•Éÿ÷ö¿ø©Áÿ.µèþÏ콩Sa­`¢R >‹ƒ \ ÇcŸq.þ;øßD]þ»þ?4sÿ¯Lþ¿OþÉ¿^8øß¥–œÿe.ÙiÈ…Èp³ ŠŠ)ÚÂ΄J5AXsþ ÿÿ&êñÿ1ýÿ¹ÿW&ÿßË¿ë oüïR‹ø¶æÿÀ—ÊÅZ‘†~vl½iŸs¦z²rì3Î¥þóàuù?¦ÿ?çÿþ©ÿÿ/ï|×§ÿ»Ô’ûªrV± H««¥ †Öìÿ!ò8ÿÛDþï7ÿÃÞÙ†~vTw¥–F›X#ŠÐ±ÌcÚjÓV($µ­†V4!ˆÄjÜ]7q#-´Ð¨„¤ƒ 4ÅÔ1´IÚjÒ–Îoï¾({ç—ÍåÂ…ù²°ÿÍ~/ö÷¹gæÎgÎé×ÿãsÿï‹Óùÿǯºð¯ÿ»Ìþ ÕhpÀÙDö¥úPÐ'´ˆ5Yç³# ø²æÏùþß6éò߯ÿÇgþO{Rœáÿß/ÿÀíƒÿ]fÉý¿èÅqr©h[ôûVò“ N‹ ™˜’m»þÈÏ8Ÿý¿Žú¿Iºü÷ý?šÕÿö¤8Ãÿ>|oð¿Ë,éÿ}ªE‚16‡È©.ý¹Ìí'µÞ‰H«Þÿc€qÿo“tùïûÔ©ÿ“ÿ÷¶þê‡ÿ»Ì¢ù_òÃÈO \ö­æCT 5b>¼ü³%c{ ¬zÿ—tœÿm’.ÿ}ÿfþo{RLþÏ{_9æî3Kîÿ„b¨ %)”kkýRŠp•ÄJ–ZÂÊþ¯ïÿ¶I—ÿ¾ÿG3ÿ·=)¦ùß—š1ÿ{ŸYÀ?.ÀÖ+ªš`bQŸK+þ‰"z+ÈQ‘ó‘Ÿqõyœÿm’.ÿ}ÿ¯Çÿäÿ}øK_<9øßeðo€ušÔQVÉ‚ P˜l¦X²B0˜R0u]ÿoôÿÛ&]þûþÍüÿö¤8Ãÿ?|÷Áãƒÿ]fÉü_tÑÕ¢‡þ?Þ² „ž|,ØvÔV®ùçÁ¿•1ÿ{“ôø?Þ?ÿ§™ÿßžgø¿æíW}uð¿Ë,¹ÿã?%y㢚LÎkÎ…’O†ˆkÛøÖíÿAãþÿ&éòß?ÿ§™ÿßžgøÿ“_sÕà—Y²þ¯.¢XGRõ Z©Ë¨8ñžmÌ!¬Üÿ{ø?›¤Ç?Qÿgþo{Rœáÿ³O½õáÁÿ.³¤þ·/©€•’jõ1'(±Rt•]Ö¨.G4«ÞÿUõ“tùï×ÿSsÿ‡¦úë+ÿÎà—Y´ÿYÔµ +*çÚ€× ¾æÆo<<hÍ÷ÿÜþãà‹tùïû§æþMõÿ¥Ÿùú8ÿßg–ôÿ·è5rˆm±OÑ™¤‡¶ŸN)XcjIÎÖö\ÀUÏÿxð¿Mºü÷ý?ìÔÿÉÿ{ϯÿöà—YÒÿCý=¥±ªD{¦ˆCÌ&T¨|èÕeªÁ„G~Æùøvìÿ7I—ÿ¾ÿ×ãòÿÞúùKhð¿Ë,ñÿÈ ¯rQ«†’¶Í~q5y¬A•ç2¬;ÿ[hœÿm’.ÿ}ÿ;ëÿÉÿ;þ(þ_ûÌÿ/™›s°Ee…¢ ÞWÏÑD)íIW½ÿG,£ÿÿ&éòß÷ÿpîÿÓäÿ}òk¿ýõÁÿ.³äþ_¢šCL­Ä·š|-…¥ý. ˜ÏŒê(Ú–«žÿ+Žýÿ&éòß÷ÿpîÿÒäÿ½ï™ÿü›Áÿ.³dÿ š©-ýKmb*&f6â©P ìmÒ\ãªý¿¿ þ7HÿSýóœû¿4ù¿åîýüà—Y²ÖF“\ÈYbuÑ ¸dM†*mÀœ‰tÕó÷·I—ÿþù?ÎýßSÓùÿC_~ðÄà—YÀ?x )Vu ~Ó*c—kn«€Ì}©!î뽬þÿv¶þûÿm2ç¿ß«ÿ}ìÄů½ëý_üG/^ÿƒ\|Ë»¿ôôm·½û‰+¿sÁWNþÄký;Í’ó'(’U^-”Úþl¬“jkÛ¸b Å—5ÿ{Æ?á8ÿÛ$]þÿý¿à}}ø’G~íÒ>œŽáÕÏŸ<ö >÷ü±K¸éŠK.9}êæç. ïß~Çà§YÀ¿õLÉäsñš#B*QØ#J.©= RL%èåðOsÿoœÿm’.ÿ}ÿÏõÿ/ºú½×¿â¯¸àÚk_ó§ã°Ï,©ÿ]$ÎâX}ªÅX4!W“B>Ì(´jÿ/µÃÿß$]þûþßÉsýŸûÌÙþ§n½þ³ã°Ë,¹ÿGÖHû÷OŽ%%obûVIèS†l5):Kò²Öÿóþ?vôÿÜ$]þûþßÉsýŸÆÿäÿÝóä?ýëà—Y2ÿ'r2TŽ©$¨3¡!’Òž 6.«ú?2úo“.ÿ}ÿO:õòÿnºý©'ÿ»ÌþEÅg®ré0@²æ€ÌU´b¶E5„°fÿõ“tùïûÒ©ÿ“ÿwáñïÝ8øße–Ìÿ`«ÙUN‰S­ ØD^ˆ©ò îðV`Ýù?<öÿ›¤Ëßÿ“sý߯ÿäÿÝÏnüï2Kú´zœ‡Èœ+AVÃRÅ`tÙš$«òvø?›¤Çÿýÿä\ÿ·ñ?ùþ5Ÿyvð¿Ë,¹ÿ×Öã‘ía€_5çàSPÎÎÚÌ%Z@_×Ýÿóà“tùïûþÏöÿ»ûé]ƒÿ]fÿ¡æ ™rIQjNª1zÞÛcÀ' ž‹s¸¦ÿËÿ›¤Çÿýÿä\ÿ¿ñ?õÿyýî85øße–ôÿRµm)ɲ$q˜Fɵ}9’#Ãl˪ýÿí8ÿÛ&]þ¨ÿçúÿ÷™³ýÿ.»áO þw™Eó¿€QÔøè\T1ÎøZÎ ¬KeÑ(Ù™UÏÿÅŒú¿Iºü÷ý?9·ÿwãªÿæ÷N¾4øße–ÔÀZ\°Š590Õ@@ëjû­ý‰C&³Yuÿoeøÿ›¤Ëßÿ“sý߯ÿäÿ=ñŽÿØà—YRÿÁ±BJêQ5³:Ó~S8Ìÿ†,IM1«öÿÂqÿo›tùïû÷ÏýŸ³ýÿûŸ>1øßeðßÖû’$öN«§¼š޶4VsEÌëÎÿæQÿ7I—ÿ¾ÿwÿÜÿ9Ûÿïò›ßuÝà—Y²þ/&&>,ÊKMÄÔ*ÛÚPT$ØHItÕù£þo’.ÿ}ÿ¯Çÿäÿ½]¾öƒÿ]fÿêCaÛ¶ø,êÛ/lû~5ØvUsûn´e@ûvØUç!Œ÷›¤ËßÿƒÎúòÿ.ÿæ†ÿ³Ï,êÿ™*@ ƒÀ\*‰LÌ‘MRW˜¸ÚuûŽùÛ¤Çÿýÿ Sÿ'ÿïÎ_7ÃÿÝg–ø?,9)äT]brAjµ•è0Yƒèwëú?0øß$]þûçÿ0÷ÿÏöÿûþüeƒÿ]fIÿ?05ÕªQ[ŒX!%ã¤q«Ù„Uçÿ°÷6I<¢þÏýßSÓùÿç}¤ þw™%ý¿ç)¸"É‘C°¢Ñ8ÁWë55jÔUý_¢1ÿw›tù?¢þÏý_œêÿëN?ü_ƒÿ]fÉþßð%§Â d«6±q±–Œ%˜2Z¶Å¯;ÿ{ÜÿÝ&]þûþÌý_œêÿŸþ»«ÿ»Ìþ[-Æö œ EWœWnO‚ê½Úl+XÅÔþ[Yuýoeìÿ7I—ÿ¾ÿ×ãòÿþ¾õgƒÿ]fÉú‹‹Æ[IT²0–c†-1›â¹ZÉȪþÕQÿ7I—ÿ¾ÿsÿ'ÿï¡7¿á7ÿ»Ì’ùŸÙ8I!‡#€rí™`ƒO^C¶Ù1DŸ×<ÿgþÏ6éòß÷ÿ`îÿãäÿÉϾîžÁÿ.³äý‰%Çì¤SR¶©Zã’ÔD–‰°ªàºçÿcþ×6éòß÷ÿNÌýœü¿w|ûËïüï2KüÛ͈‚ª‹Ü¾‡âoÙ©8ÏRcʼ*ÿãþÏFéòß÷ÿNÌýœü¿Óÿr£þw™%ó?Á¡ã€¯Ñ“%ÄÔSl Á V}ÿ‡4æÿl’ÿ'ûçÿÜ©ÿ“ÿ÷coñCƒÿ]fIÿO#JX‚†Š]¬TÅøàq >4–×íÿÃãýÿ6éòß?ÿçyý?9ÿßrï_~jð¿Ë,ÙÿS@AÈš”0xBIY-kEk¬ìV½ÿÇ8úm’ÿrDýŸû¿'§óÿ—žú·þw™%ó¿R5̾:ý6œRªÑÄT悇«ÀEüŒózÿ7Öÿ›¤ËÿõοLõÿ‘ë~ášÁÿ.³Èÿw1s„š¼7.E5ιê³'DL%V(«Þÿ=Œüo.ÿ}ÿçþ¿Lõÿô•øâà—Yâÿ ä$ú¶ô·>¤«« ßþ‚#Iˆ5ùçsþ£þo’.ÿ}ÿçþ¿Lþß ?zå÷ÿ»Ì’ùßhEÙY Z|hÅ>‡r< #¶(R8¤uýÿÁÿ6éòß÷ÿxîÿÊäÿ}÷MOŸüï2KÎÿ“JâRcû…hCà!˜Àà³ñ&«f(kÎÿâöüo‘.ÿ}ÿçþ¯Lþ߯^vzôÿßg–ø¿í`P $¯Q<çèT‹mπÀ€jÚ.ÀB:ò3ÎçüߎþŸ›¤Ëßÿã¹ÿ+“ÿ÷s¿xêwÿ»Ì’ý[ë³u5G F+˜\¸$¡l!(P&ËŽWÿÁvÜÿÙ$]þûþß}sÿG&ÿï+ÿûȯ þw™%õ߇à©5„‚Qª`õY]æjæh«—À.­yþÏÀcÿ¿Izüßß?ÿïñ?ùWýóƒŸüï2‹Öÿɺb æ²o;˜C«Ð ri£‡å„Uïÿ¶Ÿÿ[¤Ëÿüÿ¾¹ÿwÿtþÿØï½eð¿Ë,òÿŽ¿D#´:¬ABÌm`ÔX®Þ8H.Ô—ãÿÚÙûïÿ6IèÕÿ‹0ëŸ?yì…}îùc—ú¶ˆÖ)æ¶ð!¢‰)‰[uþûÿMÒå¿ïÿÑÜÿçÉÿû‘÷¿êÚÁÿ.³äýŸJ¨ý´6îM*&I…*H‘lªý‘Ÿqüƒç›¤Ëßÿ£¹ÿÏ“ÿ÷Éßþw™%ó?üá|Ï‘£P-‹GïA3䘔,”œåð:`ÝþVÆû¿MÒå¿ïÿÑÜÿåÉÿû©·=uÝà—Yrÿ/[Ï&W_’mÌ» ¤X@%bPŸªS]³ÿ';Îÿ7I—ÿ¾ÿGsÿ—'ÿïáßË«ÿ»Ì’ù?œbt\©Ò¡î§¡ŸJ@ð\Cjÿ˪÷@Çþ“ôø¿¯þOsÿ—'ÿï'ŸýÜÓƒÿ]fÿ±ÑkÛ?d[RQub¨èkl䯶ù.©]õüŸxôÿÞ&]þ8ÿÿ?öÎ>ä—ãªãÖh¥*؈ Õ(i{[ ž™9çÌk«Ò¤MIH|×J°œy H‹mÄ6R¬ØÔ·E¨V¨RÿRAnoî½Iªk¥Åˆ¤R«Ä(¾TEHÅVµèìÝß;?X–……ùÒæö¹î?ÏgÏ̜ϞYú¿×æþÿ#/üȸÿç˜Yãÿk,Ù×jk®‰D…‚W`[•(Ù(³­ÿïýøþ—ôøwgê‡ÿ¹ÿûÇ?xëàÿYÁ.Œ(›‚¡.E|.1båöy‰ž¶ìÿ!›áÿì’.ÿýúuéÿ¹¹þßþ ½wðȬÙÿK¶9—¶ÆoÀçL `Õ» œ•TJ4ZqÛý?Œþß.éòß÷ÿ®.ý7×ó¥¿÷MƒÿCfÿÊÙd)Æú袩¡æ¶ “r4ž\ÝtþǸÿg§tùïû¶Sÿgÿï—ï¾gÜÿq̬Yÿ³ÍÆ8ÈÞRÁÔÞ±H ©½8Ctjtöì3.²þçÿû¤Ëßÿ³ú?ûïºåŸÇüÏcfÍü"cµ‘ÈER4Åy ì§{½ñµFÝøüôÿwI—ÿ¾ÿg—þ¯›ý¿Û^sýƒÿCfÿ –Vþƒ­D½m/€ÚþpTÒ´3ÐÈôì3.À?Žóÿ}Òå¿ïÿÙ¥ÿëfÿï>ýÀ— þ™5ßÿ&€P1BÑZBj”r¦ ’)¨‰lÑê–þ?Ò˜ÿµOºü÷ý¿ÿ³ÿ÷øS¿òÑÁÿ!³fþ)¦Võ£É„Α«±æZjÉÉôÁ‚&M›Îÿ@?üŸ]ÒãÿÑ~ÿß.ý7û¿ø5øƒÿCfUýÏÜŽâÀ!e 2•ç45%ØPÚû¡4ž7­ÿ8öÿû¤Ë¿ÿo—þÿ£sÿÿóþñwžü2k¾ÿ¯ƒÍQ0³ ±rT’f&ö>›d%+†²éù¿·ƒÿ]Òãߟ©ÿKÿÿѹÿÿ¿ýäÇÿ‡Ìªþ¿´_ äRªŽÛ–@9PQ[lêÿùñýï>éò¦þ/ý_?×ÿ;~ÿ‘?ü2kúÿNmðL(“ôÇ!Ì.ûÊ¥:/bB²ÉY·éü/†Áÿ.éòß÷ÿ®,ý?×ÿçï¾sðȬàß:R[ª•ª:d‰ý§ORTÂRj1Ì[öÿÈÿŸtùïûW–þŸý¿?ýÁÿ~ñàÿYÓÿO9ÇÎAŽ­à«Øê`ÈÙûT)‘ø¼eý'Ccÿ¿Kºü÷ý¿ÿ³ÿ÷ô{þêÿ‡Ìšó?«mɱÇÅ%Í J6&*ÄJ¶ÿCÃÿß%]þûþwÖÿ³ÿ÷…îsƒÿCfMýWë †R3´]@ BT«0@R°‚)¹m¿ÿEõ—tùïûÜ©ÿ³ÿ÷æOæîÁÿ!³fþ¯q.k”F|‘3E 85ý“ÏÓ]@¥Lÿæì3.²ÿ§áÿí’.ÿ}ÿ—þ¿Ÿý¿þÛ7_ü2kü?Ë&&Û(WVȹ:UåF)ÐtW'ËÙg\¨þó¿]Òãÿ±~ÿŸ—þ¯Ÿý¿;¿ç‰qÿç1³†ÿb5¶ú>H©{qm7à0N÷b ª&úMÏÿçÁÿéòßïÿóÒÿ}lîÿ¿ý#/x|ðȬñÔT¬­Ü' !+ÆZ¢P‹¥¶µÿ¤+ØrþÇ8ÿÛ+þ/Ùú¿ô›ûÿ_ÿ¼ó?Ž™5ó­Ój¬EÒÈ%+%¶WBäâ«É6ÀÆßÿÿg—tù?Sÿü·7Å þïþßߺiðȬÚÿûVð++â)ûjKL¥‚-à"ºØÞuôÿ™.ÿ}ÿþ{SÜà?îÃ/ü2kÎÿÁÞøØþw6”*/F¡•éì¶-•-ùGËcþÇ.éòß÷ÿxáÿ·7Å þþðß5ø?dÖôÿʼnkÿ±±,%‹É–Ji‹Ì¦2LjaÛó¦Áÿ.éòß÷ÿ®/üŸö¦¸ÁÿO½ñ–Ñÿ?fVù?àCi¿WÒ(F\Ž\ÑDp*¥XŠ•7åßóèÿï’.ÿ}ÿïúÂÿioŠùüÿ…—Æ÷ÇÌ þ©€¡Vߣ´5.>j)&†(*j É1æ÷ÃøþgŸtùïû¦SÿgÿïמùÛÿü2kÎÿ'Á§Vt죩ɣx°¢PsðÕT‘â•¶]ÿýÿ>éòß÷ÿL§þÏþß[þîu¿4ø?dÖ|ÿã9xjJ/Ù$JF}ÉA8RÜôþ?2ãü—ôø¿Üïÿ÷øŸý¿OýÉ·ß;ø?dÖð&s,Æ;Í"Í!*˜ªÕkrìlÍeÓþŸu£þï’.ÿýþ¿YøÿíMqƒÿo¹ùî þ™UßÿJ®Ž4Nsù‹Íž§+?˜;rÈX6½ÿ Gýß'=þñLý_øÿíMqƒÿ[¼kôÿŽ™Uó?™äêCå̸-¼ T ¤llC9³°Ö³Ï¸Èúÿ»¤Ëÿ™ú¿ðÿÛ›âÿïøüOÜ3ø?dÖÜÿk™X]Ûò›â%ëkuµSÊt Èt8ñ¦óÛÿßàtùïûféÿâ\ÿÿëeOÿßàÿYãÿNY“—ˆÓu@%…d\¥I ´)ozþ7æÿî”.ÿ}ÿÏ,ý_œý¿o{åW=ðȬªÿX³wls jü‡©ØG¬–Ûµý˘ ÛÚàì3.²ÿ‡QÿwI—ÿ¾ÿg–þ/Îþß}oºüšÁÿ!³‚¨È±–ŒèA½aklª2]ú¥*°Š1gŸq‘þ¿þÏ.éòß÷ÿzüÏþßïþäM7þ™ü‹“’£¸Ú¶ýÞ¯9º€mr.䢟8„-ÏÿÆùÿ>éòß÷ÿÞ¿ôÿpöÿž|ý3Ÿü2kø·”¤rpÄÅ&TCD"è!/íê¦÷82ƒÿ=Òå¿ïÿ½éÿàìÿÝzÿ[ü2kîÿIä g¯nêü{.\ E IÛªP‚aï]gŸq‘õÿ¸ÿgŸôø¿ÚïÿS§þÏþß#ÿú÷¯ü2kæÛJ|£½ø )NW%q!ŠIÞ’ÍF ·=ÿcûÿ]Òå¿ßÿ§eý¿:÷ÿ¿î+ÞõÒÁÿ!³æü¿Xk«ä$8µ½€·6z¡\ƒ"J´Æºšp[ÿ†ÿ»K:üã™ù´ô¯ÎýÿGŸºô‰Áÿ!³æû_‚¨•b¶0û”L‚ì&•1R."vÛû¿ìøþ—tù?Sÿþ/žæÿ=ðîK·þ™ü­1Fb_²’7EµøX8'â0ý•“¸åýØ~üï‘.ÿ}ÿ¯Çÿ\ÿ_pëo~ÇàÿYsþŒEl5ŸP-&´µ>Ú¨š‹ÕŠ<° °©ÿ<ÎÿwI—ÿ¾ÿG ÿOóÿîxàÏ¿kðȬàë4ì+úi̯Á Ó‰ Á Gö÷®”h“ÝôüÏû?öI—ÿ¾ÿG ÿOóÿ^ÿ’·}ùàÿYóý_Ó¦œÑ' )hv<%P¬¬º”…Цý?üï“.ÿ}ÿþ?žæÿ}öÁÛÞ<ø?dVðo[ùGàà•IRq\"™0ÝRÐU$‰ŠËÿ7ü¿]Òå¿ïÿÑÂÿÅÓü¿_xÃËÆücfMÿ%mU $AŠÊ¹U~g´”’¼³ä¶íÿûöI—ÿ¾ÿwmáÿàiþß[ß{ß³ƒÿCfMýçj•Ma,•Sje¿mªæ¶ ¨±B¬˜6ÿ5æÿì”ÿgæÿ][ø?xšÿ÷ÜËŸy÷àÿYÓÿOª­ÒK#ž¼ ¹`$r>A›ðäeöòFÿ—tùï÷ÿ;üŸæÿÕ;¿õÿ‡ÌÿßOE©ÚTLÛ D®Y«&0Aµµª÷™ Ï>ãBçÿ£ÿ·Kzü÷çÿ1,×ÿ§ùÏý*ß6ø?dÖ|ÿ_ªq>Wƒ©ºì")Ƴ”ì({´¥1Ñnüýïà—tùïÖ†eý?ÍÿûÐ#?úÚÁÿ!³fýŸ%hNµFÛ õ¥fh…?’³Ùi X¼kä¦mçÙ±ÿß%]þ»þÃÂÿÇÓü¿yøEuðȬ¹ÿ§ºŠ·¥aPl ‘y5œÅ‘¯gŸqÿϺÁÿéòßõÿ–þïiþßM—/ÙàÿY³þ§¨iºÿ7`¨–c­P ±³Ñ¶c6ýþg:nüï‘.ÿ]ÿaéÿžæÿ=ñóviðȬšÿ)aɶ(’£*Q€ƒºhLD¨5qrfSÿÇÓ¨ÿ»¤Ë×ÿcXú¿§ùw|ê39ø?dÖôÿ#å¶ÞÏ\ØlkqÑkûÑ”¢0] bý¤ž}Æ…öÿcþÇ.éòßõÿºüÏþß«^ûÀ þ™5û`›°¡iœiK„ ¬Em õHÎg‘Mïÿ2~Ôÿ]Òå¿ëÿ1,ýÿÓü¿ŸyÃ_1ø?dV}ÿƒÅJã…éªOi?[ _]rBÙ1ŠIfÓû¿ÝøþgŸôøïÏÿcXúÿ§ùÏÿä«^=ø?dVðïrñ£/ÁÚ¤!ˆ¶_‰¨}—²ª/m É}ÆEÖÿnœÿí’.ÿýþÿå¥ÿsšÿ÷Îúé¯ü2+ø÷"Fe+\Q­‹ÓÐrµ¶Ÿ*»Ì 6­ÿ̃ÿ]Òãßöëÿå¥ÿsšÿ÷êk?vÿàÿY³þ÷ˆ6q[óûj„XÈGVª¾½09–š¼ÙôüÏû?÷I—ÿ~ýÇeý·§ù=ñ½ƒÿCfÕ÷ÉS[¤¶ÚO+XIìCu‰ÐÛ(®¸MûhÆ÷¿»¤ËßÿÃeý·sýÿ¢ß¸öƒÿCfÍü¯¤PsÉ•Õä„PsZJÐs©©m $nÊ{«Œú¿Kºü÷ý?\ú¿vöÿ.?þã_;ø?dÖøÿRR²9 ‘D6aúä?©²WDNÁÄmïÿq£ÿ¿Kºü÷ý¿ÿ³ÿ÷¾¿ÿ³ƒÿCfÿµÖbÄq´ÅeãŒpñB6D£¡hQÀ&õÛú?cþÇ>éòß÷ÿpéÿÛÙÿû¡/ø‘/ü2kü_OÓ> bt¡²§¤†Û¯„u¹ý6õÿqÌÿØ']þûþ.ý{šÿwïãü2kÎÿŠM¢b$I Šu„Ú–RD› Wð°iýg7öÿ»¤ËßÿÃ¥ÿkgÿïþ·ÜüÄàÿY³þO@2]ÉéÚ¯AI„ÉÔìk[óMäÈ‚  eÛù_n¬ÿwIÿ+ýþ?.ý_;ûמýôwþ™5ü»Vî%QkSC×µ=€a«ÒþÂ…àmÉ!ËÙg\¤ÿãüo—tù?Óÿ_ú¿Wæþÿ¥›ýÞÁÿ!³Æÿ“Ì€mŸ-Sâ‚jr…R)h}Ê®ø Ó…Ýçr‘õ?Œù_»¤Ç?÷ëÿÕ¥ÿseîÿåCw¾cðȬ¹ÿÓÀc©…­ËÕ%ñ)xõ7VÕxöV)mêÿ0Žõÿ.éò߯ÿþy®ÿ/}Þ;_7ø?dVñc®–­ XMe­¹ˆ§>âR‹›ÎÿòÆþ÷H—ÿ¾ÿwuéÿñ\ÿ¿ïå?;úÿÇÌšþ_(•Œ·dœsí=Õ ‘à±TŒ˜·ýþÌÿÜ']þûþŸíÔÿÙÿûúö±ÿ?fVðÏ6G¤˜„]Dò’A¢b%Àêsjo¨›žÿ£ûÿ]Òå¿ïÿÙNýŸý¿gùé1ÿó˜YÁ¿"ú¶ç—ÂAÔ›¶°%AŽ©3ÍLrrjÎ>ã"ëÿ1ÿgŸtùïûvéÿòìÿÝóƇÞ4ø?dÖœÿgk5Ž1ÚèÄYçÔ…l·1ºw~áæÙ›!7™oÒ¤ûì‹›MžÏ=3s>÷LŸ´ø‡õéÿß7÷ÿoxø¶‡ÿ»Ìšó?›ÌÑíߢC!MI†ˆ’ãœJÑ&›iËùzðß%MþÔÿ¥ÿsý¿ñ_.~xð¿Ë¬Yÿ[í¹¸(W ±'/ÀŒ™(“±‘,ƃÏ8Îþø}Òä¿íÿ\ú?0×ÿËôç^3øßeV🲇DAåœë[€3XÔŽ§¡ ZtŒ…T4bí¶÷óà¿Kšü·ý¿“KÿfÿïéKß}õà—YSÿsÝçGœ ‚Ò)é‚ASL‚A{ÌJóÆßÿ ÿ·Kšü·ý?jÔÿÙÿ{èÚ?û»Áÿ.³fþg +‰³/u¿_Ë?% ®œ É.Ÿqœú?æöI“ÿ¶ÿ×âöÿè–w~`ð¿Ë¬â_y좆ºHÌdcÐ,&BD£ëß—Mù¯¿rƒÿiòßöÿ¨±þŸý¿×}ä¦qÿç>³‚ÿìMˆL)ººÌONaq޽瓲œ £–xÛùßãü¯Ošü·ý?Zúÿ0ûO=xï¸ÿ{ŸYÓÿ“é¶Ÿ`S(!.RaN81rôÞG†âtÚvýoÇ÷]ÒâÿžvÿŸ–þ?ÌþßÏ_¤üï2«îÿ’”j­5ÙâÉ…€ ]Êœ’øPß)–²åü_40ü¿.iòßîÿÓÒÿ½gîÿ_õÁ›?3øßeÖÜÿÍu§ïÁrÐ6`ð. Õ*&ƒQ´‹VB·©ÿ§ÍXÿwI‹§"u P¼÷ÂÅ’Ò¦ð4 Tã¶ü3Žúß%MþÛþß}KÿgÿïÚÛ2ƒÿ]fMÿÏ ,( TD‹¯{€à8ZYÅL*ã–ßÿa} þ{¤ÉÛÿƒFýöþßkNÜ8øßeÖôÿ²I"‰%bö9ںȎ­$ím¨¯Åu°åù?ÿ§Kšü·ý?hÔÿgïÿ•;^:øßeÖð_teRtrÊÉ*ž>t±®‚¸H%6Ÿq þ5Žþ—´ø?ÝîÿÃÒÿÅgïÿ}檯 þw™5ü׺Y‡0D…Á¸ )L#z²ñÄ1КaÛû¿Fÿ¿Ošü·ûÿ°ôO?{ÿïEßùσÿ]fÿ`}ˆI‚“\iòßöÿ`éÿ›Ùÿû­Û?ü¯ƒÿ]fÍý¿Ñ…P7ý^£o B0‹*,A²3ˆ$jÓùŸvÜÿ×'MþÛþ,ý_3û¿xÆýñà—Y³ÿ71&@ïH±€pö×@29ª?Ë1oëÿà8ÿï’&ÿmÿÿcfÿï?üèKÿ»Ìšó¥r*èS0:3–â0rðIcý£Ñ¶ÿ=æôI“ÿ¶ÿwÏÒÿ1³ÿ÷’ð·w þw™5õšý™C"œD‚¨°è’19ÌP럔 úà3ŽÕÿþ—4ùoû-þgÿï?>ó_qð¿Ë¬¹ÿ\`#Ì¥¤RP¬Õ‰Iœ„,Š0Ó¦ý?¤Ñÿï’ÿ÷¶ûÿØXÿÏþß[~àþw™5ëÎÖæ”$¤bl, ±€G]7F¡žŽ6­ÿÚŽùß]Òä¿ÝÿÇeý¿wîÿ?ô‰5øßeVð¯*©LZǹҊd¼s‚Ó®à4Èéh6ýþÔèÿuI‹>Pÿ—þÿ½sÿÿsáoÿ»ÌšùzôïcÈÎû¨Š„Ö&ËV‹' uI@œeÛóõ¿Kšü¨ÿKÿ—çúÿ¾Ç¿}ÌÿÞgÖÌÿ*‹óà¼ÍX—ýEyaŽÞùê[A;—‚ÒjËõÿ˜ÿÑ+MþÛþ.ý_žëÿ›>vîíƒÿ]fÿkãHe­¼7•å¨%%6b0’¡ºüÏaÛù¿jôÿ»¤ÉÛÿÃ¥ÿ˳ÿ÷§|ëóÿ»Ìšý"„iîÏÑgÿœR`‹Þ¸ ÀæÂ&§rðÇ©ÿ4ü¿.iòßöÿZüÏþßoü¹'ÿ»ÌªógS™ºH%]ŠB•I×EA&›Ù‰››ÞÿE8öÿ]Òä¿íÿáÒÿçÙÿ{Á%WüÚà—Ysþ‡Ñ1Å™2E`?½ È(P.rN¤´2›öÿ͘ÿÛ'MþÛþ.ýžý¿÷¾êe¯üï2k¾ÿƒ}Ò9G“èìXB}ÔW‚ÆmŽ*ØtþŸóÿú¤ÉÛÿ;½ôxöÿnyâšoüï2kÎÿ««übH|©Ûÿ"¨Ä–Ñ“§”¦µzŽàòÁgÇÿUãûÿ.iñ»ÿzéÿðìÿ]òæ¿¿vð¿Ë¬™ÿ¯9ÕZ_WT ’Ų¬bý |q9°ÞôþÏqþ×)Mþ›ýPËúÿÜÿ?û†³?8øßeÖôÿLð¶H ˆaFÕª¤K-ûÌ…¥.6åÇü¯>iðJ5ë?¨eý¿îÿü—O¦Áÿ.³jþGq¦ä8‰±òON€}&mb¼%~Ëù¿¨Gÿ¿Ošü¨ÿ þë›âˆÿGßóºÿüï2+øç€Þ›h2CÅÝ4óߺŒ.8«½+>OBÐÁg§þëqþ×%Mþ›þ¨…ÿ_ßGü?}ßüï2+øÏ‚‚‰³uÁ'‡ˆ\VžJ´ÁP.bSØÖÿó¿;¥ÉÓÿµðÿë›âˆÿË®¼ùþÁÿ.³æû¼ BBÆÛ´vFg«À«úZÈ*[C1;Úòüßâðÿû¤ÉÓÿµðÿë›âˆÿÞøŸ¿3øßeVù?.AH‘””°îÎK¡Àf2‘êÖ?ØD›îÿAý—4ùoú þo}SñÿæKÎ\7øßeVð/÷º!7&źІȩ =Ojš&G¼­ÿgÆþ¿Kšü7ý?P ÿ·¾)Žø¿éw½að¿Ë¬â4'ÐÞgbÖÌ–Á;§¦  Á’‰¢LØòþÏÊÿØÿwI“ÿ¦ÿjáÿÖ7Åÿ¿Çà—YãÿE-h+ü.P¨C]ô+WꪠîýU.9P›új¬ÿû¤ÅÿÝíþÿÝ ÿ§¾)ŽøÞõoù¦Áÿ.³Æÿ+è¢Ò ¼U©–ÿ.†P)©•Z ø‚›Þÿkxø]Òä¿Ýÿoð÷ÜÿÿЋOdð¿Ë¬àß¡kTÔ䀵F°±nøÚèI bBUBÆmÏÿi|ÿ×%-þíú¿ôîžûÿ÷¿çäËÿ»Ìšþ¿å"š’+„XDJÆÉfÔXÈÒÞ!mìÿ ÿ·Kšü·ë¿]Ö;×ÿ»®~ìÖÁÿ.³fþǾc[’-Å«"&ëP*ûV‚ËX¢Ë)n9ÿ§â?úÿ]Òä¿íÿÙeý·sýÿÜ»þíÕƒÿ]fÍ÷ÿL±.òuýÏCŒ‘Œ6`JFÊA’N±î’?øŒãœÿû?û¤ÉÛÿ³Kÿ×ÎþßÏ^ûmgÿ»Ì þ¸™òdþUÖÎ)ð³‹Ù!£Ø¬$oêÿ(󿺤ÉÛÿ³Kÿ×Îþß»üûoüï2köÿ´a²Æ:ÍÉÍÞhí‘‹ªÈ¦¬(xMé0­ÇØÿƒç]Òä¿íÿÙ¥ÿkgÿï»®ø©þw™üí*õÁ™Ìšl*Ú¨ 4)¨]ÆD‰¼éù? ÿ§Ošü·ý¿ÿ³ÿ÷ÆÿÃóÿ»Ìÿ'%Ÿ‰C…™ƒÁ”ê– gãêö_°G%PÜtÿ¯‡ÿÓ'MþÛþŸ]úÿvöÿüý ƒÿ]fÍümÀOOÇü9rbFŒA<»˜’ª[‚ƒÏ8ÎþÆù—´ø?ÕîÿÛ¥ÿogÿï§¿ïO~eð¿Ë¬â(û…5 ›¸ÔWBˆN¢@±õ—C»mý?†±ÿï’&ÿúÿKÿÿÔÜÿÿê'ÿüCƒÿ]fÍù?ë@êï‚Õ¬ F¹"’ “¨,Å‚†i$ÈÁg|mþiyÿÇà¿K–ü+« <µ€N}á³ßñÜ'î¸óå¯þúþCFŽ•5ßÿû“F㕉dÑÇ”“Ï…‹Ê´µ%êb/dþçùü£þ_Ÿ´ùo/N/=çXמ8qöº_øíïýúþCFŽ•Uó?UήœVüÔÓ'À ´·E]7yãúoFÿ¿KÚü·@}~ý¯üáˆÿŸøì¿¿mð¿Ç¬ùþGB äŒ8Q1Fg[‘ºP*zŒb^ˆÿ¿àŸÕ8ÿë’6ÿm°Åÿ?ñÇcßó{ƒÿ=fÿÚE€â5ÉÊXÅ®Vüiê¤ä¼ábJÄú[sðÇàߎóÿ>ióßucýÿOGüßù²3gÿ{Ìšý?³’”Y° Ú\‘Ù$.>z•\öÀ6c]|Ʊêÿðÿ»¤Í[ÔçPùìˆÿ›_úÉ2øßcÖø?ÞxSHQ4&‡L@XK6 9ªb]V™êŸ.ÄÿYÖþ_—´ùo €úü*ÿñÿ»×¿èíƒÿ=fMýEÙ£øHº¾4d—É¡†B0µê|‰fSþYþ_—´ùo €ú|¸òöˆÿÇžû-ïüï1kîÿ‰146qöª£(¢„&iëmc<)¾ û?ìrþÿð»¤ÉÿÿxÑõ—^zë_^úÈë_ÿ«WÅËõ•çN^þÔSýås—_úÀ ï»ò‘N}ÿ7Ÿøü¯¿ÿéAÿ>³æþO§¼Ôõ=*0íÿ…²žFººôW`µ'#Î^ÈüEý×4øï’6ÿíþ¿>_~Î+NÏýÿÛ¿îÇÆ`YsþoS.ΗhCT1 !{«x:ï”›¦ƒ|Æ×æŸõ†ÿÓ%Mþ Ôç À8½*Ž^O^uîMã°Ã¬™ÿ_ VhïKÝèÛ Y™ÄI¦/€aÒÿYà‚îÿnœÿ ÿ§KÚü¨ÿçóÿ¿þß™oýÊØì2kæ(Ñä™)_—ÿZOs?tÉZy#Iy7)À:]È÷‹ý¿þ_Ÿ´ùÿþ߉/?r´ÿ¥,öÿ/<Úÿßþégnôï3kîÿŒ8ÏèMT %:qÕt hg ÝÁggÿoGÿ¿KÚü·ý¿“ ÿgöÿ¾ûK{åxì1kîÿ¨8êˆÓÕÊ¢µd\tXB] 0Ñ4Tè úþÁ¿ó¿ú¤ÍÛÿ£†ÿ;û~ûoüï1kÖÿqZâ—¬¼M%`Κîüf—¢²bK-¿ÿA5¾ÿï“6ÿmÿõöÿ.{áu1øßcÖôÿU6•HÏâ½s®˜â\faL+ýI•d¶­ÿ8üŸ>ióßöÿ¨áÿÎþß­WÿÑ‹ÿ{Ìšõ¿"±Æ‚·ÓÎß_áÔ¢$zc•˱$:ó¦ý£Ç÷?]Òæ¿íÿQÃÿý?zïSŸüï1+øW%B‰¹Ö~‚’ëŽßÅ18mLò*gÏž7›öÿpÌÿí“&ÿ¶øÿâÿ?rî‹oüï1kÖÿ¼«³±Å']TöÆøcÐ&ƒAeÕ¶õߎþ_—´ùo÷ÿiéÿ?ëÿ½ö‰«nüï1«æÿ[ŠN0šÈEJN‚¬£¨ÿaï|C¾Mª:îFù×,d"’0*ƒjΜ9sfX3M‹þ¸i‰¡éœ™3fÛ˜Ij…FH ¾rwuw[Èê¢E›oZ ÓèEEåßmwaÕÒšßs=H<÷ùÅÕý\\pÁ|yþÝ÷óÀõâù}æÌ\ó™3Äi,ý•Rrš®gý­ÿGã_Lþ÷ˆÉ¿?Sÿ¯mN§¡âÊð‰|æ³s8`ÖðÙ‡œcoƒÿN· î¥ÕAi¦>þÖ{JmÛþ_aúÿ»ÄæÿLý¿èÿ_õÿnyÃÏÝ3ñ?bÖôÿʬ¥×æ¹CÍ-ø ¥VêK8>cRpö—Øÿ“ÿ=bóo÷ÿ‹†ÿ»”ÿ}î­wLþ˜5÷c)Pq£Ô%/©&„Òb€êAy|+Bwáì3.SÿyÎÿw‰Í¿íÿÝ}¶ÿß»òquòĬéÿãBïÒz ^‘ƒÏªÑûS/é\°F& ¶|ÿ7êÿôw‰Í¿íÿÝ}¶ÿߟ¾ùsOŸü1kÎÿùܸõ&ÐRi˜z–ÒZî™jö ƒnYÿi|5ùß#6ÿ¶ÿgñ¿ø/xçëŸ9ù?bÖœÿi2¥&-(‰L“ÿ#fÍü¿j¡A/Üb+±´ªpå"À8Öÿ|sôì3.ãÿÆùþ—˜üßmïÿ“Qÿÿï[_ø²Lþ˜5ïÿ¢†Ô[BT½ïÐ[•ÈÞçê{ƒL:ÝoÊ¿s³þï›{ÿŸ.ú¿Wý¿Ÿºùî'Nþ˜5õ¿©´ZZ¦µy—b­œ#+EçS§ì®ëüÏÿçýûÄäÎÔÿkù§ÓPqexÞ“þí«s8`Öôÿ Ö{uÜ”c©O]ÊXüwÖ  ¨kˆ°éùð“ÿ]bó¦þý¿—úÿÞ[Ÿü_ÿ#fMýG')¤ÆÆÐ"¨–ÒÄ©J§O†TKØ´ÿ?»¹þß%6ÿ¶ÿGû_õÿn{Þ›~dòĬéÿC!Œ)zqâ87Ž”8ä€ÈUÈœ›×|ö—àfÿ}bóoûdøÿ‹ÿ÷±W=ðéÉÿ³æþOŸY³T.‰‡NZ©z5a.LžVÜ”šýÿ÷‰Í¿íÿ‘áÿ.þß ÿà;bòĬ9ÿÓü˜õsÁ¬ÒSUŸ˜Œ:å5JÑñƒê¦ý¿NÇ &ÿ;ÄæßöÿÈðÿï_ïæ§Lþ˜5óÿÒÕ»DÒ0'aí­…ètŒ ¾T‰%JÓ²iÿ/ ³þï›Ûÿ»ëlÿ¿{nu¯šü1kúÿi‰=8ÁT¡0¨Ä p,FM°HJgŸq‰ú?þ4ùß#6ÿ¶ÿgñ¿ø·<çóï™ü1«üðÐÔ"ObB)A;J+‘ƒ«¸íýß&ÿ»Ääÿ{ÿÿ®³þßkþö—¿}òĬÙÿÓœ}‰Ðºd*ä3W¬‘KÀJn à°ÔmùÇ9ÿß%6ÿæþ?¹‹õÿªÿ÷º··yýç!³ÆÿíÔJˆI)SL\q:Vü⺤x”àT®‡ÿ‹þÍú¿KLþɬÿä®­ÿt*® ½ùKÎà€Yõþ¿v)¡€—ª*SQö±t_™×]ÓŽíì3.ñþÏǹÿ¿KlþÏÔ£ÿ÷Rÿ¿ðº_˜÷2«ú¨s¹†~:ï×[õ]n1#:pêX ¤²éùžý?ö‰Í¿éÿ‘3üߥü?ô´{¿0ù?bÖ¼ÿ‹-&ùH°é˜ìgñž9%GªøNÉE³Ï¸Œÿƒ³þï›Óÿ#gø¿‹ÿ÷V¹ó¿'ÿGÌÿO»$ŸZt flY\ â‰Ä\ÇOÝrþhÞÿ»OlþMÿÏäñÿîÿÀŸ›ü1kúÿ3r+mÔ䨽¯URN=¡oɧÌ%fGª>oÚÿ?Ìû¿ö‰Í¿éÿ‘3üÿÅÿkwüå]“ÿ#fÿ^ÔÅñ¿¼ŽÉ~ÊŠ¹º$¤¾i…Š®×\7õÿÙÁäØü›þ9Ãÿ_ü¿ÿüô ¿4ù?bÖÜÿ§-¥R°ôªšhÌ9Ö £ò{9]ØbP7íÿ3†™Éÿ±ù7ý?r†ÿ¿øÏùЋ?4ù?bÖôÿh§£ÿÍu¤Ø%`æTBb­™H¸m{þožÿÝ'&ÿwÙûÿ·þïâÿù|Z˜ü1kÞÿ+'Ö\ƒ†€C-\@ncšž;Œ_BÊ›Þÿ1÷ÿwŠÍ¿½ÿûEÿ÷ªÿ÷•wþË+&ÿGÌšýÿ1õ¡rc®*–Š=–S«hȪäû¦þ_œûÿûÄäíú®­ÿt*® ¿ã¶¯Ìà€Ysþ/¦VJåÊ¥´257ý¹ºL5fŽZ ›žÿãyþwŸØüÛõÿÿ_óÿþäÑŸ¾iâĬÙÿËŽ{¨â8¡ä<ÕŽ|%OP: ¢`Û²ÿgˆaúÿ»Äæßöÿ‚qþo)ÿ÷þágÿCfÿ“ko=°jM±DŒ1"Pïšorzóç³w´iÿŸæü—ØüÛþ_0üÿÅÿ{Ã?&“ÿ#fUÿÿšku)BMj’Qø‹ø¦ DöÔò¦ç)Nÿg—ØüÛþ_0üÿÅÿûç|Ç·Mþ˜UïÿI¼i.žÚ|”x¨zª$rìk Mïÿ Dsý¿Klþmÿ/þïâÿ}ö›_ùåÉÿ³Æÿ‰Ô±H‡Ú|j œ‚øŠ-ÆÁ.5ˆÙa¡oêÿó¼ÿkŸØüÛþ_0üßÅÿû×ß>ïÿ8dVðï\ÇÞ+gð°tç´kdˆ ´!g©gŸq™ú?×ÿûÄæßöÿ‚áÿ.þß_È—ß2ù?bÖôÿÁʾç *zÊRzV×ûì‚FH|…$ïÓømŒºéúßÏþ_ûÄæßÞÿÿÙþ·ýÀ ¾iòĬyÿOZB@©EO?5A>5ýFl½{A§P8€\ÿ{­ÿG.Ì÷ÿ»ÄäŸíú: W€}ÛËçà³êþ?ßètÙgÊ•NGÿÁ…Bò» …º Цý¿hÞÿ½OlþÏÔÃÿYêÿ3¾øñwOü˜üÕšO‡ŠkRÝé:îrãª9 X}ê¼íúÞÿ±OlþmÿÏþïRþ÷ù/}åäÿˆYÃ?gª$½Ä6J¿ŒåoX]íâSv¢ÄÛöÿç¹ÿ¿OlþmÿÏõñÿ¾ûŸxÿäÿˆY³ÿÒ°'p6ȃRðcùº §@ ½jçm÷ÿgýß'6ÿ¶ÿç ÿwñÿÞóG_zõäÿˆYÓÿË×Ì€L0Öâ[šÒ€5T ãgA—mºÿL“ÿ=bóoûÞðÿÿ3Mþ˜UïÿC(”jàXP 5*( ¯D¥Å.è¶êÿãÿgÞÿ½KlþmÿÏþïâÿ}ò]¯~ÛäÿˆYÁ)±×¦,Œ)€jèNµyÇ)a)Zã úì3þÿüÌùÿ>±ù·ý?oø¿‹ÿ÷Ê7ÿà3&ÿGÌšõ¿`“ä&ºr/•sæ -’½S ­ÐVý?¯Ôžýÿ÷‰Éÿ=öþ¿7üßÅÿû‡ïù³×Nþ˜üçŠÃî]sä‹JOE}.r—%Î[íÿ/õÞÿ½Olþíýƒÿ«þß‹oýÈ­“ÿ#fÍùŸ\Ö4Jr÷q| (”ªPBðš3b µ6îzúѵõqöÿÞ%ÿ·»ÿUÿóÐo¹ÿÆ¿¾å–·Ü_oò?þð7=òÈß<ôðM7Þû+OzÒýß{ïûŸû-ùøKÞöщÿ!³¦ÿWèI9JCjÚ˜ @Ô1$§5PÏÿ-×ÿóüÏ^±ù·ëÿgûÿ}ðÞŸùù91köÿÈõ”Ðiv©Ÿ®ü þØs¢J¹*FªÎá­îÿºÂÀùþ—ØüÛþßgûÿ}ê7Íû™5þ Ç€T’/™\ìcÕOÀžzÌ.4W¶êÿ{…Ï“ÿ]bóoûѨÿ‹ÿ÷àßýÓ “ÿ#fÿ¨ÒJn}@éSÉ))–X´fðE›«P¸ÑXœ}Æ%Þÿy˜ëÿ]bóoûѨÿ‹ÿ÷ðSžðë“ÿ#f ÿ=†T8޵¿£1èÒ1J"mâ{ê¾$—aÓõÿø°Mþ÷ˆÍ¿íÿEÃÿ]ü¿O<óÆ/Nþ˜5ûÿ]KÁNX8«ôI#®ÿó­ ãziäÎÓz‰úïhÎÿw‰Í¿íÿYü/þßo¾âE¿=ù?bÖôÿ-R"ÅcZÎŒÑiMNrï¾”à±è={gŸq™÷ÿóüß>±ù·ý¿høÿ‹ÿ÷ì_ýºgMþ˜5þR©>·,سtÇNbëcXÐ\Ç¿ŽÏ>ã2õ¾ÿÛ'&ÿ·Ûþ_4üÿÅÿûÈŸß÷øÉÿ³Æÿo½5—[_”{&IÉ+\q‚ ÇñÉ…Ü·œÿÆYÿw‰Í¿½ÿ/úÿWý¿'|5ÖÉÿ³æþ/ŽN¤¦ìµÜˆ¤¨zèŒ^з†[Ýÿ»Ìÿçùß}bòÎÔÿký_: Kàò¾wÍà€YsþשwÙ‡S×?-ÿ‚cµï„ÇÜÛ9äP¶:ÿ¿ø¿sþ¿OlþÏÔ£ÿ÷RÿßñÔ›ûÄÿˆYÁM2Äœù$Wïµ;y $^Œm»éû¿éÿì›Ûÿ»ûlÿ¿ûtóþ¿CfÿœDTòXHŽrêÿY™;Iì.h‡*.·éù?ïæú—ØüÛþŸÅÿâÿÅþS“ÿ#fÍùé | Ô«:­àX €Æâ $ \¶ºÿcyÿ7ûÿï›Ûÿ»û¬ÿGûú?žü1kÖÿ˜còšÊ }Ë‘[ïI!õ µA…6]ÿG7çÿ»ÄæßöÿÀ¨ÿ‹ÿ÷üï{û³'ÿGÌšýáXH]-ÇPzÌ›žÿ “ÿ}bòÿ~{ÿ ÿwñÿ^ñW¿ÿÁÉÿ³îþo”ØÇœ¿Ö”B'ŒÄ^zÄ 79ûŒË¬ÿgÿï}bóoïÿÃEÿ÷ªÿ÷’žõÔÉÿóñÿí·~ÿÏ81>>>gùùÿàâÿ°÷PMfY*ˆPt)F‘Þ‚‚RFz¤&! RHB *Rì€Ò¬3*éM…RPDAZ(b”Ž$’ý’0³þÿîŒûŸÙõ?g×wÂ{ï¾[ß½ïÞ|ùNÂǧ©¥oÀÉÿߢð¿°ý—çÿWãEa xœð't|­þëëüÏøkkóïõÿ[4y'À ÎááHx8ްw·:ƒTG{+΀ŒäôVžœç‡àbÌ-9CŽKgíhŃà+ Å¥µ:Ä¥%ò ×ß _A.ŒÃ yí¸”™ñ $²âA8äÈ… hg0³sä hžÝv<»ØrU˜:s)#µ¹”žÜ»%îŽ"Q\ ž‡¸x<Ö<–Ó»8pz§3åÊå9Ä•ç4Ïv< W|`·âOÄ!ž x8œ3X±à ~Xg0w8ÈÅq! [.„‹àBŽôo‹ÿ×ó‹GaJÇWò_KWOûç?°ö=ÿ¿EòŸà¿Ë”·Wƒb±DÎû··óV‡¡ýÖɃv«b¹ìÇ(A¼3‚F€üàHH°‡ABpÑB£þD€ Ù`ñpDÄC0„ …Å@x@…HD ÐX¿@¾:Àä hãèüÕ á°~À\a²ICÈM4Î7Ž'p„)+K<ÄA7ІPH  Za·º<ï|p¿'ô7Q„PÌw įP¹ü•1ze…—?¿QB¹EÇÔ†ë6<Š[ðð€êP°Ðã¦;! ·‚°sýRw ÓßûøKêœ5”ß—›Üéx,â·˜»øº¹;å.˜¡ˆ6p8ŽÿÒ1€£‘p8ñW‹q^0ìÑ/ ,B “O¹ú‡ ¡ xAW¤BBˆX´.PB€Œ_Ȇa1Ò[]9‹$™F !¨pîñ[áW&B’«©• €”_±ÜËGã(MòVäà¹eS AH@%°¤ àY‘Ç­]D8§†† ‚Ö­T3(‚óòÚë‡B¢ˆ{UåŠA@$à/ˆDÀdR8X¡Â-º<ñ üÿÎÔOûjýGc‰¿ÿdÏ®}íúïï¯ÿ ôµ¾ÿç›´?ˆ?‹GCˆÿ_?ï÷_ºººÀ!ÐåÄ_S÷ûÿû&ÍBð‡û­[ ýh‘ûÞ~·ýAþ£0¡p pí|øÿswþO÷´t¸×ÿ@ø~ÿç´2þ˜ŽBO¬5„B!p°Ÿ& EêjëùijCu 0½ü Ð?¬ÿZš::º_Þÿ×ã|ÿ˜~¯ÿߢýíþ?±úy›RSjoùdÞû·èÚ–»kÉSw#õ7kv,Á¢%õòMħŒBìûý³iо#£À^ê^b3rÙT“Iö¢/{:¦Í2c/cÙjà×Y¢ ¯»]˜µìYV  ¨eH¯q„áŒö„É.Ï7ÑzÛÝU¢ì ¨Ec&¬¥Å{Ó&l ÃaÁGk¹êoës+$§†Šô¹ÅÙtæíÅf+& ¿®U]\8Ëè—ho-Ù%uzÒ8Á9.·a)ôm òe¥[Å]ŒuT«Ê}»(¿”hðv³pyð­w^ÚávœRêÖêõò%1îÉ“´ZÕTŸÙ‚)ô€&EV—†¯=þpáIFídFŸê£w¢üÈËžêÙ—²£ÝZ©· kˆÒKŸœ,œj`Mž-ñ5°´ëëwbd”oëøDÞó|dä`:9Æ}O»y©ðˆÛÙ’dÍ1áBÙÔëò×(‘Ÿ>]6ó%ƸLJ,תΤ „!ÙûI«K®L‘Ú%^CŸXýQ'ë|ª†Ò³§"{>œÿp­µßY†) €Mduøç±+¡1÷èä«û"ç´n;«*iU6¿©. ži†¥HN Ž_gé_cêü%÷’dîBº$,e £GÂ!%ëvxs€Jv?b©ôÕpP‚d¦Fë¥çi»†‘å¹êŠË”–RJÉ­%5†~&SGº]8·$êõë¶²Sr„áã(Æom™×{Ñó¥Ã=˜™vŒÛ†rÁ´£¿0d±þôäm’ô(~ã9 ïö0ôeÈ·UÕèԇ䩭&E-û¼-ª*Á¾Ö©ÙVKaM¥#ùj‘&‚¢±eõ i¡)ƒŸµ$Mn azŠK/z”²“Æ™ÉhÏb§)Iu–¾B*/w¥5¿!Oßký\¤dˆ,ØD=JŸ¨9rlh‡MðXqÊÿÕ‚ÊéWîšý3p£= Jò­Â O²—•£ƒ˜aïרdÝx÷nlp¶¢¸¥œä!j#3N?މêÍNº2i¸·Vµ+WÌ+ñ2˜ÞQUpZ1Fpìqa–û½¡Œ,{Ü›°ZŠö²ÈøÂÐ ÜÐðlb&ùH'³©“r±¹›ß×ÉLIw—ÁY¯WôÙ©b¹4æ6…˜Ý³#æg…-6*eô(¦5„4Þÿì]ÂLã˜ÀÚ€qÖÖyúÆ: ìÑô¶Å­KsÔ!ûw§÷E³ 86Øö‘–Ê%‡°¤Øx‡Ú‰bÝsm‰Êü§Óçïûéü¢o™eѦNÙLaÚï”LL’ɼc$i‘œ[«èÛõä¢ ­þ!%%Ú05i¶ÐX°¯‡}þ9WeñÄ%QuäÍÆ>ñùƒ¡²æ½ï=ÃTùÖÆØÔRØcA;Ý3é´ßk]èÕS»‰yêovõD©°Ñ¢ã‘›œc÷0Å܇…Û·Z2ÙŒ;Øgçªt b΋g¡¬èù³vJüÖ¹S²ªÍ›²ÞÕ›Ý5máÙ—8²hÑûswx9üرL"Ù‚y•”úÊR5‚Fò:Çöp9¾*ïA )ÔG–½?‘*ÞJ[gê$NÖí™åh—‹6Lýdã÷¿f@YXúh!ô½<ƒW÷#›ñœþ(gŠœê])HEŒÒe²´j/¼°SÀšŸße3šKHÂÒ„ý^Ñþ§pyëé‰bï !¬‹õ¤„÷cf¥ó'sçZœÁãd §ôz+×~>Sˆq³Ï<¸xpKÓ²±´ßñB+nw‡"ÎÅcù­^ËÄeô.~ ôr oó“½@aò߯²6¿Èªûð°½n¬ÄHÿ\̾œ¾.ñhAá´3æ•^îú¸•ymj{ÍÍôxÃKŸEóõAJemñ%ÍV-w³ËÈ=£Ý®p»N:~¯g#5ÂËA“®-ÐÞk=•?îvCÖÛ¥œo¨ aOnNgÜH™{”ãØš´Š~YžOwTÖjô$Râã ìxØý‰†ãmÎæL‡$0B‹¶kðýÓ9¥À…df*Óé Ûécú¾MZÕ‰)IëêQÜç}»òîÇZ5¦S[]j •€Ô0UP˜˜«YÍ„Æu‰7xMGöÛLBW÷Dµƒî‰Ên·­îÎßg1é9¯Ä¨¦ÊùøÙörÐ=öb°8öðúâ§># 5ë'V%×PžÔ³ëkû»Äcº.µ5šß0—½ÉµÄÔvQåÊ$>6«yCÑ2pìrèd9¦{ ÔA4švœÎ¿>MhÓ<áL†™ç9àÔM#ÕÕÊ`† 3Þ¶†R‡M¥m„„(MY߆¥%šÐbê.UÖ™ÖÍ{Eø‚PF[ZŽ%¬NØÃ×ÂI›ÄW5`„A•*l(®YRÁh$î]qà/ÔQ¡ÕóH*müËI²+“·eŽô›úêç³U»û§G25—çnqЀr°ñï ?mz+¾&_¯-YKè:»Ñü–k»_¾« h?‹‰PÙ?ã$%VÖ\?–-ü ߸Å÷ú3,íPâJ  ¾æÏ_ ;øCYÙÉÃqâàñ°3Í=‘ΚšIX¡›± oX^öt}›À®¨ÎÀßX.¥Ž ›,Ÿ=§e{@?Æ™TÁdR]N4¸R„;Î`–9ùtH+Nm¦ÅÞw¥éI¥ÞÐÇN›üä7 ƒs8ÙøÀÐr»lŽLnìÝ†êø¾‹ç(â!¸[«é«nÙ/S”Ͷ7å$µ SË¥­‹ã[ŒÁb÷¶ì_H¤qkÁ%xòöâÝý÷Ú«‘cãxo™ŸïœwÚu–’kâïØ×ëHf:m€nŒX˜õôÚ¶qN.¤‚£9¥fx›ªã­G9C£'s"D6ö‹[…=kâ—Ñ,ö-ÈË\+lv.äÉôÒÄ™ûÛf†o—ÿ¡òÚIt„×¹&]3ó7oŽ#~¦´?ƒ}.®8ïþiÕãH–;ôþ‹óhã]¯ŽDfZ¿Ü’tñ%)¾ql¾[~«ðÉ–|Òì6øq€]zö$íΤjJeùáfæ³rê„Hì‰á†iü"°· ,G­ M’`VÀÓî¢ö :¹½‹§ØFNÿ!ý¸h¾ã º¯#ê³*T—­a(o&,°ùi\þ KyÌrcóõ|ìN¿Ü1Gwñ¥ik°8èaÇÍyM>¬pîT èÄZ¿è|Ú7{ðŸ Ë~óìqßM¶rBÑFÞ²Z˜“æûª©œÝé€Uù?BÕá╌ó«ÍÙ狲ާ"&ñ#Àu@¤-WT`+RûÈÓ¨è¤Í Úò©!UøÀ@õ;ͳ‹å°:ñY3ÙµQ2/4¶¬¡4eJÅyŒåõíŸhÜexíxB[=YÍ'¦ÒKjÌ8HLÑêÃRáÉ™;HŸPÆ}·§ÃÍÚÖ+«^s–ÃÄ%u_Ò¡_w”¢ï6_:ÜYEŽ˜Ï6›åÿÐzSÂmÓøÆŸ%ÝÏ‹z—ôühÓ»RÒ'®m”!ÂbK»œw¹î<ÁvX—n'}K’dÌ‘ÿãô 3Ù·Áî`þ[½*šw!H#:v+*52ÊóœªêÓ˜0µ­.—™ÿ®³ç]Qý;Ôä[„«c,5`}G¸{Úc~1å3u`ߟ&~whx(3âÃä?zêŠ`ªÎýVU“µÞå)¸xß\¹ð—ÂåmtÀö¦òÁm`ýÑÅÀ¶ QVFûÞŠÌ­Ì3ò‘×t9oÀúc‚/Öšg$îŒnŸ¨É\ÝNöHmXüÞ¶1Èé@aÔ=2½³*J@ÔrRdL+n¿0èÀ2',m)Ø«kùâšœ¦ûçímšÉ‹ hJOj+528“åŒÊëD—7‡ÏÈ-mî£5J>"fR½[‹µ”¶Œ6Fòõ‘8ÆÈ–¾qL‘0_£@º$4¦ž.4^EhË1În›­:*º{X4®ÁCì¾>'×nOúˆ™Wq€K^OɰÂ^^+¢¬À>h>D v%=»Úi’X¨xÀz¦î'ÓµÇ>']iôWËÙ×_Ú׸w5Àb*N9¯=•¾ 8·Ó>kü³†ã\é|†®Ol7uX­xÛG™=Yp›×%’úq7Ö¨ À—àñ¦481ãî—Loúùx=S­3ã£nÍÕ­…wž”Ì%=>þ3-«ËÊi¨ƒXÑøcƒ”6DkérFA¦‘¹Ã!J>qG’ÞìVé§e!ËR§öU50ôA—B©T&BÅ®üíªØfkNcÚ´Üsö}Ÿ¤_×Ó˜ébé:~f¿³Ç}­å½ŠW Ou§ÜÊ?¿ëß凟:Òž6ùtfíâ:%êÄ¥¬xUvšã¦CQv°´_¨ÚÐ-BþR¡ù ‰ÛûŠø;¨|'&~ô˜ý+ûnд š™)fDZcff¦Ø1³SÌÌÌ3;ffffffŒ™™1;ã¼'­N»w+­´§“¾ùcK=Ý]ðÔSUÝ=–"d©Ð‹å­îëù‡D*)­aº®Ý>lÙN¸ž}µ¬Ý×;4N†×õ1æ¡)±+¥w1 ¹qÑZBš¼¹.½JaÝt2@só°kßš>ã@©€Ç½âf¼Oô‡•ÒR‹{Ê]î&2‡3ñ+"+üvjŒi‘ëªEZ€D¢{0A2^¥ëUÞÍÀXñ7õÄnüÛ:Á¿Ž–¯Š.])üîô# ×~Y.VM’Z݉të’e¹ýç±¾}ïÅ<ºã™íîMÈ“ ޤþ4§É²Ke,ƒsé¢×µËO $q»”¶ÉƒÆB8Ù¸M«t ¥Ü ?JË0õSeÏ@Íß-ì%7û²!ÀG¹Lù [Ui—\Ž0¦y>ÄSÊŽWÓAÙAµÙÙ5€>³$>‘Œ)ŒÓý…¼q Þj˜ö™›Î ‡´Ñ|„ä79ˆXÕ°Þ °»8ÙßC]¬úÁ9¤¢ 9$ë=ÍžJÇÌîßgâõf›oôNV¹o·:þŠ%cÚ<ý[¿Ùä±5`,@~e6E¸Ð \’'%k L­(¤}}RÐVgÏdßàÏm{Ñôý# ‡F*Ჩ(¨´ã;ÛÄÙFèå…¦ {3ñ¸ÛÑMŽ&ÊÑà‰Ž‰„1©óÞʤ“ z˜æ›þ^.xI¦Ÿô˜õ[}é—áazÆ®Qú±› ãÆù“¬¡ÇµfÀ醮;aòÏ…Õ}2œ’¨PܶÊ’¾dëó8N@¿±â¥_¯÷ÅEŸ)Þó•ÑèHcöÀÎV|Œò€Mâ0È¿ \v“Wõ^§SàK‚ÌFqfZø±‡HLì4}NfÅÍl®Îe~,„»+ãìÑ¿÷è82ø¯‡Ž±F]Zw¶¥ ›R;QA«…ŽÈ‡ô—Ñ0œ÷e‘@íu@#ÓŸ?^áO¶­Ò×µ’©²ýþ¦„µ]Lœõ*‹ã5êRœ¿¹$æ"eÅ®º¹ ÓXŠw5‰~*µ08Eõ@2®ùK­Ã^äíÎÒÞÒ$ œkb@ëÀ»ª8÷u/Ñÿˆ såf—¿ïEÔ²}lNòp›GÇnïGÏíñ­ÛfÓclM˜ÀhsÓÂú:fôiî×##ö÷Ží y²Îs•¤@ýè±kn&óTÝñÃ{ì;®onW#¼>‰¥ðµðì‰?3€Nfț˂- ò7eÿU¯)`C>üÅ8$˜ú¯ ©KÜO Ì*ˆË: eÉcýk†ýU4Y3ô±Þ‚ÇjÌ7û XŠ2ÆmR[ù­ 7||Yœ~­õÁ¾‡F²nc)F«0ö¶*|‰s¦Y¬ø&âŒ@øF¯#ZÉK°fcSÌ¡urû<ˆ’tôJ~´A‡A¯B¢+\º•¯.qG-w`Lùš±þ°ûçÙ=‡ÊKéÊ'[™ýŽÖê~ZÌ:<Œ¿“~ù›8igNÑ¥§ù3€8•‚Ԫ߰~>‰ê›¬öÂÛÌB hyÂûËÁסÛð~=Ó ãû; ÛoáЙÄ+‚îÆÔ¤ 0jd\ËœôPÖÍ‘]´¢Þ-Ft¬ ²©,šWr˳×$¦j(­SñnjôS^¾ÓëA¤Lh ‚ˆß† ’›ÌxÍûš©(ßUœ2º ñ?µMs—Õx 2Tæ‘ÒÞÝ»óQpŒ†A—LâÃu€ý鎕úÂðT%d5ŒžbÅhv‡Œ9Àçw¾¼ðŒ\+=Ÿ `@–ÕÅñû>@ß¾ë$­¥r‚…‘'ê@´Þ]é²Í8Â.a¤}’AÖ»½ù ÛþØŒ@€V¢=, l-µXbçURÚ£»ñF+C¶¶Ç:VH¡XèïOÊeC½V!ÄžpÐè<ú^^‡¯ÿüÓ:ôdZ©ÃK¸÷e¶ºª>ÄÇS çNçôÐ8µ±{éFIˆÐåû©ÃNaâÌ`©jz“1£ñ{¹<ŒX#ãçˈƒ3ýò©?â=55©C—ßô›«/«‘ßÑ’)D°côÂÖœR})ÃL%SÐÞ›îóo¼YŠIóeÌT»8à6Fô Ãù²)zÅ_è±ÖØ–T™” nï þ?AB…þÙlöö9MÇØ^Ð:]¨ªøÈ¶×ôqØCeÏ;Ž¢¡®fÇÅøG¸AD'ë¦P ®Ý,áK\ÚŒ÷ÓG–ƒV×ç/È<¶”õñ.c pݱæ&UßeH(Ë/ñAÿvxtû%hlOÙË”‘ý„I£V tKieÁÉ/˜\S*C*S”KÜè…UgïÕ˜á¯ô Á 6Y7‡ãùƒ kiíÏ4 ®a˜§)V‘hŒÏ„/ f³o‰$0öçݹˆ3œ4ün¥˜~ßäØÉ ƒØ{ûcªvºë•›.ÆÔÄ#?’ó]IY7 1àƒQД>@;5ø,›PmWäPwÚ.Ÿíªñ÷WØŸ¹ÆQñ£W˜*— $Ý·¢ûš±NHøîÝ¢lð–z'ÿ¢‰Ke-T;o×2%zAØh•SÂö³¡Ý¢|П ÈŠ°» /TµêHUH¤ËÆúÖÃB œÇ*v6£Núm^§]þ’(‘šÉÊÛeûkÝiOFįĈí*Y\ØxL4ã{êuh{œ2Êý`yÇ¢…ˆ“¥³jª`%]ëùâžGóy£ã‰ìd‰çL³^w1@r£M†‡J×nÑQÍÆ~ é@âÏÂhÖl‡!PöA+ÉGp›à{Qgǃ”œ’4™oqZ#KÉ@Ò´›óiLdÚûÉ¥úþ]¥ÇˆËLâÏwãT)oøO~ãòè49£(¾‘©U³¾y#ˆyxØÕþD¿×s;—b†å¥Vd|BõŽ7PûR<œ‰'[~Ù–ÎH"½œ(óÉàÇrrß«â×pf‘jIëÏx(Œå•îæŸü†ÉóTÇÅ/€`B/S™>A¢Ð.‘u {À¡1âßÓjW™ûi†4A›}v:t]0v‘ƒÕ£?Z¨÷:*׆™½2ÃÇŸ ¿ €ØŠöÔ2îªÓ#òüY¸?Ö¹Ô;J"4 ’'ʼ3 –“F!Ü4ìwóßzj£qŸ ÅDêE>ÃìX¡0º§aá¬}“×Í.”ï‘)üÌPµ-âP4FἦƆJA㯿:,×…!ËLmr-֦ȀX¡i…¼ÇWdŸTôöͨÕ&ƒL«qÂMMBCÖ)žË0ú²2þ-¤±xf¢ž´ÉÆ â$¦ÂXo'÷µ¦=Í̉<ÒU«¦„äýªM ã67ì>'"ìÂV¸;—=8%˜Il55ÐB{–b÷q7°Ê÷'”~eϹL³Êu0WKåÝ0}šÖŽ;¸¿½ry ÀbNnÀ¡ {NØÃÞ6¸¯¶Á¤k7Çî5ð§ôêBù¡‡Ë³búz ‡h{d熘#w‹  M~µ%‚/Œ¡—í0Ìk‚‚· éàÀ–xSã\¶X§$æØ§i|ÁëÈvžîì;àß½¯5cû‘Ë—˜âŠ@÷$‘×íÉÛL¡gÿ´ÐýŽŒ°µ¦õ×b>´Â8”8¿Ù÷ÖâÿT¡Lã×h‹~†`䆀šŽ2!˜¶€C[ó 9íט^¾Tdó×Íq€fnZß|Ÿ†¯½ï's‹åiæã ǯ~”‹¹ ˜Ý8[ JÑ}Ý-D{ÍØ&Ýy šÖ¤WïåÆ0*ô'¼ÕÎø uJWJKÄDú?ÕûŠÐ4Uy]NŠÉ‹‡$uce ƒÅ)Ø÷È~{ ã rŸí Æ' E¶æ„põŸƒ/M÷EiËsNjÉHdeœ1‚¹[íþjäX ‡Ë»G84m´ HEcü<ô_8í•‚ØÀîdˆÄ£â~­†/<^d&J󦢦´^ÿ̾Uôê·ò5Þ>Y.œ‹T@ùæí5m+ÁÜ=pºx{ ý!u·™lWŠs[MŸûÈÚ¥±ÆG%ŽïhÎ#ˆAȶÈÅyfx §+ãïÏšX±—ø–ˆBÎã_«]‘3!Z&¬¿°t5qéXàã?_j¹'n 1c©)aÖ¡’ &órŽòg‘x¦8µ÷œEçÙÐ~{%®ÒkÌú…ïnÖgµO¡çÊH“¯a©[ª¥ŸÄ.¤x§Z†åe¥’n½|©¾q™dowúgXt2çIíÁü&•ø–cÝäŠ[DNAÃn¬ßû#è7@aiv6Àáw!¦lý”ß»6‰&øf#sæ©Ì;ˆ%ÈœƒµSÚeTl ¾>yE´øc¥/€„CCôwø@ÉÈQPqüwµ¬ýÈEº¿ø°;q›¢=ÞüH|ˆÅN:9¶Ò©ñ-[¥Jj$])N¾xZ`IÍÍ€tÃñ70ÿcý*ª®ö¬ùh+$í/aSx5 X¼.ò>‰½ô§¨F˜`ÚI#íû‡ኴ@;c ¯Û Nΰ3üú A¦A\Mk³öÙ¸J”ö0ÿÊñßIкÕãÀ½#¹”1;-æ}¸ùH¨ç*‚.c¤*³&Žª'f‹Ëu:°ã‚ÁUUŸcš—É÷>ÖëSí…üzxöàô˜#ȦJ—Ë’ÚùCëërõ÷Ç¿aœqm Õܹmîç-)A·‹5Æ©¸®JXÅé Ü#QɃ3ˆSðY«<¯Ã¾|:A[0(½ Eý~Zš~ÃÛÄ~ÿØÜÚ•‘cÃ?qiË/ÆßÌ!ÛûÅB¾6ÛMyl‰÷9Œçtü(¹Y™ÿê©i·?¤‡¥{a•Ãq%ü¯Ç‡Ç¸ïô@Ýt|ü»b7 áÛµãyl¿€C]Òû.uÖ&ÝSÄÔ…·T«à«Ì«øcâUæŽH%îAÝÅ𿆃i²©d(įcñŠÌ…)c À³+y¥îzq~/Ë^gðC¢W¾›Þ÷8Ïð}ž+ ¬r·ÊÚ@TÅ,É2KEk.Q”Úë 0,­„`ÅÕº,Æø–Ê!×J“ÎiˆÃç…gNlïÍøÃlò7ÑÌÔÇ*Êö ¾È¢Ÿ&ë1úÈÚŠí`:§YOëÎÔå™Fâ.óÎ5~°Ê—U–(ᢒ¥Çh€QW*`úìeQvÔ´˜nÁ$©Ð¯\f‰ †7¦Þ\ºÄÊ+ßÛ˜.æ o`òWÂ|ZÚ’Ðæ ÝßjqïêÜÌvd>â5—ð qY/×n–X«^¨o{š…wÀÍöaL Ö²Šfª Aý}¹´\ “P}wR^þy|³€ªäõ¹"ìR@§{žã`öT]ÐÈœËVð8‰YA†Y„R ˆT0‘õà¼O_·å™Þ´ý‹Lœ×ƦôÞe¹ —3IqÄü“Ì[ÓMO¬ÙÈ2›³À°ò‰>DGnï_ÂÁû<Ñf+^7‚ãú–¿Óñ¶Ý!8óPÃsqÐè¦îðNÈápõ=ÞsÖ2­2ÄõããC·lZ©$+XôÚéöÓ »ø±ëÚGrI‰ÇÈ< ÞÍu³>úµù,æ•35Xq,Æ-ñ‚Á#¥Þ*žQ¿XÃgÈ×#ÄTp—D´ß!Lï¶‹›þþz(ØÕÄ'U±ØDÜœQà…E…Ä h0Œ5ÄôâTœڴAZ*ÙA'*;zf@3˜¿÷GZÐLmÛü‰/%=KrjAS§[CµÌl¿:ÍÄ3>š/Ó¥Ô¿trO÷ÏÀÏóÇžÑ[°‚z¡—Ìb÷”ŸÚñNÆT¾"¦Ð¦:{x%3ã÷Š€îÚé€<| ™u^…ººVÞ” MíW 7> Ø—¬ny8¿Â¥Ïöt~s&¥à1ó®ùÏÈ#a‰§ ¤%¹Bòµ4©ýä×€ÃJ¶ç¥‚DŽ6 âE²ªq|22ÂpíŸ¦Š Y¼B–W7C|¦Ë>*ȃ#ПKpïïlÛŸ- …•-ÚýÃ’^>T›‡û­”l`È ­½†ÊCö¬\ŠËÑ0@Þ XÝ)›îý+åçχ”£ë?Ç-ÎgÈŽ"N›€ èz£Š½kz0@}›Š7S(íD´"tYÀÉí#+$½úr*6!Úp_ ¥Hke:\R,ý~„º ÙGú ”}¿ý@Å›æpO#œîպݹ„¿|=$Ç6ç uvÈ¿c@íùĵÑzâÇ\r!O÷9ØtÐt’]x*’üùrwÓô23>Øsáüƒ1ü[}ãÂÆ?´Ë4ž#¶mz‚„°=V[ßâ>‘ØæØýc°fÝô Bƒ¹ÖxJ‘¢ŽËWIý<>iä}€[DJÇ+šìd8‡&ý­J¦øG™Jû ‹µXžŒùgeoýÊT¯T¨Ù¦,Ö<ŸÖå€/Êfɬ`\ðô¾Ìÿ„½å‰G–%;\dŠŠºÔê¾Ñ,­bÙ4WZ‘*‰×naoz¢Õ5qði1ñî,ý}ÃÝb)zwÂY¹ˆ_X v;FÙ¡aÝÆr»XH ³5b£åo»:·—ŽÖïü(á®| Ð±ÚØÎŽs58e}+Šh[˜ôOyÏT2/JÄsÖÐÿÞŽ;„áÝ¢U9Ì*¸|;å‹sç¤Å³>{cAÃŽÊ•æ$ÖL'ƒÅÝ?»Í󷦢÷¸ïŒœo BàÃÎÆRS™€XŠ{¢¸jìù5ĵ0‹Š^½| zá< ¥^‘·kˆÉslR5±¿Ëï¨OøãTr,ÓŠ¡8|{‡°; w`ßJi'Ü8'4Í…Z8> O ó(×óE2±g"iBioqLPIz“Gš¾Œè¶Ù¢|í"$¯8Š)ø7ï?ÐeÑó͹ ;{¹ X‡Ð:æ?—2”×]|Ýþ=º­‰BQ2åa†Ç½áÕZpm"!&к¼¦u¼­±&Õ{¡ي ($±dÃÁÎ6¶VG æ(cZ¹Ü@¥7¢*`ÏÚt^n,Av1~Ð,Õ?€ð1H!ÅþÐFè²¶›dcö¤J*í°F1w1n¬øv¥^‰+Ç卸k0îî_@Ú!{ caÑÑR±fî¹\÷Udi%Ik%ªÁ½¾ü§Kö)È`FñC+ü™}ó8¶úå0ƾ4gú©öáø…Ü +»2—˜ 0µÔÏ ‹§²%<$¾ùÀ–À\—-ã7^ ¨'.kZ[n‰å¢ Nç`ý*°SÒ nêjªŽP|•ÃD%)á¹jaz炽JŪýg÷/lü;Ji·ÊŸ —yœuu=t1ÃìØÃÃ× 2%;‡KaÖ„YRŽÒ W‘Âê Ú %_>È;¼º8K’R÷4{M†×Ä&'aV·ß‡ÈTìoóðcô (¥«Z\*¯†Ö6´V?^ÅéÍ”Oˆ,Á×”‰¡—HÝð ã¸l<Õ¶âÿ‚EÔçþ Püµz¿ ÝÌ*6o3cQV"E†«UX‹X/Ø…Ÿø–Z ÕªŠ£òd´ƒ¥ä¡2á†|XíAÅÜ#ƒ"sµ‘ëôšØ›é± „8RéxzŸi~gò çÑxT´È‹Y0ùîx(°œÁ§Ë 7çf±®× ™qfßO#¥<žr†Å>(+j!Á~3öøˆ†Om(¥é¤K°\hÊ ÇB!_Œ÷À±W?†åÍ‘ ÒÛ£V-xƒÆ¬S[T†õÙÇ!‰±–ŠÏ»ßÌŒx³-i†m÷‡!'ÿaQÇVEqð»/ø85cÜ="Íà{@Âo•ä­òå™Û`ü¡QÌXÁ+ M÷|N¦öS®ýå \­Ó¯;ƒ&¶ Tá&‹À ìb-´`êùe›ÇÀÄÉÏðcÊîƒ.Qó96‚9 Gn6ËUæ÷.+Œ¥Û¥mlÙÂIKæ†Ó&aöN|d0$‘[b³ÐæO'•òG/W‰ç_Èúës×ïû&ª¦4³¡ªÆ–Y}ÍŠ*{w7Ÿ3Û¿ $µF—TGrîc ÜH^ÎôžŠöZó}ezg"wlZyXÈ¢©=ÓgN`SÏlzãˆHÉME¦À¢7ÏDÿ*§)ZÙ –dˆ*l9¨–~ù—C­óþ ß“6ûIÁßæßãYݼa×r|-õÀÓU=Õrýçô¯%jR©M¾Qþv&£¹ÂSžúÍö!yÛƒƒ`;È\Oõ”#~‘€ÜùÖgI|ñr>„‚ ¿9ÍØEÝñÍ÷‘6ðû]bA†ÌLËhWœ6ÿþ/èÈuú ñ™³o‰¦€Î=@ß8™˜Õщ(;éjœAÙz©žäTÑÔÕ¾ÍÏô-ßu3 3†%ØÞ¿¡qrÒ¢ÚÚ¦4½æ1Ÿ«w|#-¤~Ëö"ú'ûÜî$ÜxFªÙ)ìµ "RðÙeÞp0&·9û¶RÙ)žé‹Q&=Úõu×÷é–wEÚøp©±wÿ±Ð]¶O|÷H BqX&(­¡þ±r ´á7É:‹;)>lÛ7A¨'=!~E‘¬áMßÖœÔ] 0Æ»©."déœ[Í¥`ª¹ø¼ivyõA}é¹3ñâ23)–v·ë¯lPJâçr1 g)1ÈúX$Ň½›-sQr:#…sšBâÃS€Åñ‘qÚ9o4É–D{@7ýМ_í†ð§KÎ9ÿ9u·]‹ò˜ÏÕyžë´Äî8[,n ¶Ìäô °»žïhwÌ¡fCŠYéM¿BÂýÛ’ña¯# tâå2{­’ÌÒ·½1ÈYÅÅ/ÐßôË4? ˪ê÷‰00Ýù©D²è½£™„Úí ¨uêËö?Šè±aþ¥è×ÏLü«¾7ò ä1¿jE‰úû,;Ù?ñ쯱¹Ý~/tI”ìõc~òàÿåJïXÈúq˜Ò~•Ú²Ž(ñÞõÁzwšº)A}gjKæŒ Œµ» a‚p°)-fR¸øŠˆ±Üò‰ØÈ`(àÁ p{(œƒÊRt#ZÐw:¯Rïâ92Ä_+ôîûç¥=K´žÏd6Çæ¥}ùœsÑ—¾_Ó*Rš¼?zЖ€«uòhÅJ/)‹e'®4]ã´Òy¾аÓ]7|Þ •rž1Øee6†œ+‚¬LrÌm­s=šã1W|^~ø HdÉ=7…—ÜŠÝO£ñBø‡ *å»öª‹ÇúÈtzÊp³%pµ‚Žˆs Óy6׋Q2Îõ!„únÊJåYñûf¿–·Ø ±]´ 0ŠUMÁöeòæR‘L¾ýÄÿáÅör.Ë=B&¾îÊ&㾪8[ÿØwœ*%-zʰûƒãû¨L·P±qiÔpqûRAó»y"i`7!ô.'®Ù o·´P2'¸ü%›NWàñ÷õ'^{d’Ö›o¦âËËjQ£v½Óé¤B ¼fßÓgr$«1f Y.]ÞmŸœöûüõ2èZô€•9Ot¡Äò»¤è”°ýcX«m©6)MCKÀs:°kJÑfs+µ Y €õ£Ðg>—§S*˜R=Ɉ’kQÞQ(}W=Ê .Ê›l gÀnjîdÀ¦î|íaòx&y>¿÷O4°vl62•¾Až›SÅ]:­¾ä¯Bû¤F Šëcü¸`‰¿Sî;üÆ]ïÔeÑï1 VªJŸKüä@³Œ>˜]¸òbâ b6ÖŠü+ÖËG51ä. §æ‡4ÂCÔ–¶P h˜nó¾'§¿Pù*ª5}db ñ¹qo&mŽº_vÒÓ±ùÇ=?Ñv‰¿^E±~4 WäÒK+$Eù%çº==·ÖÊô{\xÕ‘zåSЩe”í7n†œ|·†Ïè±c!xŽRu¬ö8›€êÊȪaÒK9b ÿq[4ºU›ÀÌöž‹¯”`áÐ=Ȱ‹PÞwi”¯pæ*ß×ZÅh÷”Æh5pΪÙÞXú]b¼|52MÙN™?ßÕ²„fpÇP±(¹{lY ëq@9®ƒ¹@âƒMi×ôQääÒ4ÀjÒx¿ÚóÏTϨèÈ¿[À3;î tzô²›/öëÆÔ6çõ>VìæqË9Ò‚ˆ_ôO žÓcJ³ú €(BçæéîÕøüÉ 1—¶ìÐ+p²k‘õÊÞ&µœ™ÇŒì9×$È 3iVÑLà­Â Ï“À.î·M)Y÷ÖUÏüaë¼ Ø~µPdw{µáèÀp×qZd „õŠ'¿¦ M/;3>ñà ȓβýcx×ÊPpña+ÏuÏjÙ"ÕLõj‡jw'¡­ÕÈï©Ip¸ªÎ/fezêK˜NèiûiÍñz4@ÑÈ.ʧ3wRqoرdÝI¦™î ¤2+%°-6Ãe½h7Ò ß3Or ^3—lÞM=0àù,|†ÿ×â¦Ø8Í–4@Z:·eë—uX'—¥çóܶµOÕ?¢°/‡¬Ÿ¦ÌqkREg˜•#W_² ÌϨŸXùfª÷ѵf·X0Kd€U®l¤iäwØC›×åûqæ®úÎ-»Îi$oÅ¿-«ÜáP™f ýnypHÕ£.j}Ã+ü{| Á­K^©í>¾oºùa7ÜÑò²<«Ü‚‹\³Sp&'ú³c–_\ö|Àq»9ªØ¤âb|QÓÎ J™Ö’9È1¥vóá¹; û­fž˜3/¤˜‡•Ð;Ÿ íF}ê[fT@×}smJ;“ö< ÊÅi «¡¨8³ò˜ÿO¶B÷ÔöFpª7Iw—e–\#œ9ëøÈÔïqÈ®$p!É¢ …/Ö³Æeb]9’ê“[)šÎ—Øþ0nWÇû‹j*‡p¥Ø‰ owQ¾qµâä—)ùê? Zeÿ‡Ýè÷¾6h= q±U¡1"/K à9ѹ“¼Öxnv|Ø•¥¨2óNu…H ‘š¾6Õ,¢ȇ‹KìUK=]ÀÆX¯¨ß8XÅRsRQ%ÃÈ?¬/jç¼Ðƈ|’¼ßî1ì÷9Ú+ÄúmŒ„5o/‘9XƱ<ù<ÈÉÙ¸&x¾b\)×yßIrôѤ´H{i “æçb^¸êµí%Á7"ŽdÓÁy­Æ÷ MiÌe‚ëÑä- +i¥Ê´îÍr,ÑùËÜ[ ÿ=`#ÑÀM,`,Dc„ëVnNqvøc¨Iž~ÜÙ@?n$À*Îbù‚‡•¯SÑœ¾û'г-H[êº} Uÿ´$PÙŸ3Áâ õÙ—Ð?g;ܻТóÐåÈ¢Mcv¤p\N¸lóè2 GW›õ ýxÿ1[ÊÜ<㳺θQœH(Aüö”u;^σ7Zñè«ÕüÃ4u„`Ú+`6çÆRË&ü6OÇÉûþ.x|x´tT[k/Lú7†ð7CÄ¿WB£Lž^ÚÂ`t·%bûc£ú[Ä9’$“Q±ÝÞä\þæÔÊí£íX øvÜå(‡+%],$„mCvëöâw]@Ú5´%Ért3ÉŠF¼@ù µ¬;1´” «ÍYºÇp‚Ž}ºWÍ+dh9öùÝÃÅñt¯fÿáëàâÖ¦Ð\RÛrfV¾bº2-³þòñ~ŠÓ,)wŠŠ>«E¢xÜëmÅB-ud9ŒûûˇèHëìT|u‰¨ %ï_ *“öA'Ì" ’Ç׎¢g/ᳪœƒd»wmqˆHM5YlÊ€¯s¼†Öç~hÖRR—ëÞî‡{yx²Œ­<¤ã aÌÒ O ¶‹ñÜ¢W¸._¤‰¯ïŽ…Å”HçKN\ Þæïßo_=&™îrÛ,,n}¢lÉè÷nÆÒ`YúW„å8òBl[gCt©~öjÊ£{u‰;*IüWÊ O˜£ü)aÄÓÚËVEãVSx¥;Œhàø8á<.ÈžþÜ8n®˜E9§¯@YqüyÐòZ÷è#Ôΰ¦FsXYsÒ6˜ÎScA£Ø-+^#˜aR^§ó±uK+(ôüçOð5¬Ó„› ÆxyIÞˆ7¨ˆ3$ýÝ´ëÕÁ+Æçe£+KDTÉ›4¨îÂã˜gÜìo¿1§¾¶^|¸ûSþ¶z¿å¯Õ%EiÙÉÄI<Ö:¸¹þ( {ö`ØÍ½;ðNNà–Y¿ÆÈ ¸‡½ôaJq¹j¢ó„Ç´öM°=e!0±°%èjîM¤êÆzÃmì^ Ÿ[û±¸ _&Þ‰¼ð;Ñù÷*’7?–¿Þð)‹”…Åeús~¼å!/í]"EËЉúïÄä.qÎÓ¹)ˆ}·È¼¯lJƒÜ˜)þ'KËæ¿@â£r äYû,ÔÀœw‚¤{>s„` |®'_Çln—©žîy•^ÚÍ72?I=¹¼MÝó÷ñãÂݬBË8QF!ÿ«Hð/UÙ`­à_Fr»5/ï ¹&'YÈi–ÙÝ(ò–ú¡fzŒ ñ-±#{nßù8ìÓ¿ÛîÞ½“Q!‘”e–ß1eSšÃŽìˆÎÞ¾?£9)Èö$˜s¾-?¦~ íAÅ¥g­Ò&4¯¥j/-¼¡r7¿ÝÎÀ­O‚×A—¯¥Ó1]DëTW÷4ó2‚}·ˆ“.jÖúe7S ý<¹¨ÉB+rDU ízƒ`¢úÔH u°‰0ƒ,ÈŽ‡–­ ®/å8¤¨ûYî¥&±þ¢pÿH5t3#„õzFQqAe]­!‡a-—ë…÷ïOq(÷Ok$  ÍlrÓZ:o­#ì¥b–¢Ò3̧·2Ý—•ç:óévød«Ä š¿¨«Úñõ½‹àã]ÛõF‹½?8:?­…yÏOs~ªï¿ºÆp'>´2s^ FàI••vLûÒ¯Ûþv8ð,ý¬£ø"OË÷:wÙKáÑ!K·ÕýWu¹Å#wîÕÍ?›Põ¿&e—»üÂÍ5'¼w&‚~ðÜGÜ׿þȃ•kb¨à¸‡Œ}ß!qýËãyÃÕÞ¸ÝYíS®‘¿ñâ¦ê’‘Å\€ Õä,Ý:»&PD…y˜Œ|÷XR?néY±îåip %vø*œ±ìŽSNmàÃÚš•SV!Ó…ìiós(Qˆ¢µ/ÅÎo)ĤÜ$Ÿ›ÏïÙ«>S¯Sq²úØŸ  ¸ò“¢¥ö/{+ys£,d]} ¥-øÚñϨ¥Â~pî§ø´²Ö*á"§§‰F±B™¢Ðm[`ðnL±n¶ðFà&lôùúz1ÍbΙ€s‘÷8ËþÌ >ôã­¡«5[}Ñ6•äI¥)Þ¤xOë5'ˆXSg&Àlõ®¾³<š•°ÌQ¹ÉM¸¥æ1|v—$±G¼ @½¯7TýÅ.M)¾–6e‹û2jÓ#{|JúQ?¸ÛfÚƒQG4,¯«× {CËy9ñUqY§üëž@¾æ$*±¢‚ÈÜ¢dÌ+ X(„ûtñ¬F~Ô@ÄõÜr ÀÒÀuG<Ù˳^€ÀømŒ’eVôïrwù±"°ä•®nþDø1rº¡­Gýé@ÉŒå2ð­<K°öžeÊvÉm lä^3¹ÕݽOpJ†Ý_ r @‚+‡ Š¹z³·0ÏS_Gž˜€•Í=©<è£ò{¥z+X¾ŸÛ‰™EÔV{fm9ðm`òÅQ/Ìh##kÞ×IÔýø”ídƇúdOÉ\Î$Á„ÉÔ°œYÄ`ÄIÍÒæJ³jó—ðÆ'Pÿ¨yEw\ '‡T¬-ýâpïŠðªãqä×-~ó¥lP«µŸî$ü±{ÌŸÍbþìãüâ§ÍyÕÖ5cļ¬,hû”SÏ‚c µô«×­Õ¿g¼¶¢½Í¹.šÇ±n½Í‰F\¬Ž /F¬vÜ7œ>Š*îX‚™!ÐÉÞqƒ"æ_Œ8ö/þÈÓð|lªR Š,ùòÃL±0³ï¨úñæ) ÷Ô£sÉRÙšáŽÜ¦82mjÀ²K P™x9]›s ý{­MÓ¼7-¥ÛIWóíÙþóéÕÈšyT—¬U™k7¦‰"öQ¤ öü°º9yÁ¢r݆-éº9¹Þ›âgy%f­ÚýÙÈ”awt›³Ð-F\YE§Å¢’b/ý»¢ Y©@åP°›‚¹ñð•+îÚRæF½Æ‘­ïLæºÉ ħ¾Gr¡ÒVKß >ìÜp\¨qK*ǧÙù (’Í’ó¸u|·ˆ÷Ê&Úwe”2nEÂÏaüV«~qàPojS\&Þ oï¹CÏÂ>U³§Hcœ ñV@‰Q¶‘ªˆÁ$>§#ØÏòùÙ‡)¸¶b‘)®ÄlïíÀÍï‘RàJJG1¥ÃËҕ'>Un3¬³J#çüCjbV]‘³âlÑ‘Æ3)Ú·‡Q[U–Q©¦ÓÌå•;G­Ÿä™ W¥)f´ôwe)æ7'þì~L~èP¬‹”Ø gЫöv^:m©<ŸmÝ4d°t=ÁÑh¨Çn·Ýÿý¼tËs"?9ƒmÚÇq©-/¼gäò0ž2î¾èæïæ¯5èª: ³nçÒÑÆyvLÁÌêZ\¾t\”È­X.Ž7㥠C50q$o]8}ÞHx5d€Î×­B–BPšÚk.à üt,E–û˜L\úô³Fáp†gcJÜN!©2¼¶´‰¿¥é`ÙSI«‘Ì[‚Ø' ¾|ô«Éðtiá“öÒ.‚8} 4ºY«¾Èi¾bWœp ¯QŒÙuà~w^²!d&jv}·½;-—ÐÆéùÇ ²1ÔÏ?3u>ÔLàòßÝ—yÝVäÙ]/fUåj51óUÁäUv$O½ éc¦–d 1½& ãréª%ѪĊ„ÃÍH@à í~ªOiiéH{ ß–ôO°µ2/„ˆ'|>û»ßO)“ðjíŽ;³ñ.1#©AÐÀÓ°‹î¾&˃ökœ[K®‘Mãe‡†÷¬hÕ5¦éÛ8<|® V¹ÈWû¿ ‘îÖøÇú®­%ÚÁsgæ$p·ØÕn¬Ÿé‹K“»WåÑ»r®LŽóZÜ.¤| Y3¸š¯2ÍÕÎ?.ÃÃ7¸¯ÃÌ@A‘éÆK‹»„—½ë™Æ¤±PDÆþEošòH÷>Äȵ€Î•¸™+uö¿#±ñåH¹ï…ŒBmv·xÓ 7%6¬ dŒW€ÊôM¼ü%IÂfµØf°° UI88·µÉ•iüã¼ÏÊn® §gb~l;!g€ÚqêŽÿ+ç7e¿îVG@øü6 B±)ïŒyÌîªNÄ£°ù"饋KY Ûôß³ó÷Q+qK8äÐs’ükœñ@Z^ s§©²•S¯'í ×Êî™äÕ¥ÈÁÏ`MIÙÀÑÁÚX)¡ÅsÊ…M:s]Jfu½=ÄòñM“ÅÇÓ4€l|†…Ð –G$mÚlU:6\¿<<¡êEëþNÓG3´¬¥FŒHˆ<­‡…p;\<ª,¬9ÔìÄýÔ*ŸB"~_œà%ù$è¼7<ºÎ1ßü>—ãpð‹úû3³)€aî%O¦IÓGB!§z~Fðˆ”`~ ¡¤ÿ¯óÊbæWD*k ËRr-pu• D‰gX(âîÎ…åŸ)œf§Ò˜qÝÀGèÙ©mL7îDŽ9òþ;9TuØ?æÌ'ÁœõÿýŒ®6•㋌¬J³Õ{èÒ­·Ú¥‹_ÚDåpõG ‘Ì5RtgVš•íÌD8,ð6®¤ _<¾$½oüSlýøÈÕ®BIÇw©yNvwœ‹X&íØ3œíßÙö;¢åÒggi!UÛö d¶1~;†+ ÂN!¹ÿ<ÉÕYÉ)ûùÈÿ]Ë’9çÓÃL]N¢cïÚ`‡äÎ3¢f¸4îTyWÏ%POD!Å—“fé:Ò58¸°žØ(( ]Ú.í{t|ø Ó“œ‰Zà‡ÇiLÐ ¨¦ßxfÃ$† g€éSËᔋ)ñ žkaÆzïB½ƒ( E;€aÚ J3~„†NS((°#Q cëñmç÷ úOk æº‹¸AGÊ™•¦írc˜’ašàÇñeûû¸Æ?׋—³qÛ`iÉ}¤v“Ûb“kôB\Š kàÍü¸çÏžÖ£šU^&ÖlÏm5¨çR«~˜¨V~Š ÿPüÂ~¾úB‘ÙÃY¢MùªD­éd½i$éP¶ ËKý‰˜.+¶Í §ŽBwzˆ¸³P˜>°ö¾8žB2‚ëæ_ueJgALg$â.õ—‡åé޿ƬÙ|…ËÛäñ`Ãßÿ&~oj»¶X¿E¡³æõײoi[rÉg†Ï^‹ˆ²O¨[×R¡Z>ø÷"9wW¦V–!ïI6\§Bþ¨æ9q Œ„øË§C²‹öÜý‚ôsé6ä=Ÿr{õÍÏëA*æÀ çýï¼£ÑpânêÛ¢òèVÓ߯C²ñchªäqsëóÊCM¨@JSË›ZÉYÓµ› ¥pÔ³{:d-öÐöW£¾GµP¾Òͽ,ýPÆZ×÷†¬Ähï¨ÁËú¡ƒÌÏô’'§sŠ%i’~WZFµXëø«$äi=¿ÈÂh~4à²oåÆÏÝ^ ·¯'\°¾'Ñçz(ÂwÄ ôA$òAVwÂ|ž* ¦¬b’éHgX`{!`Gê#lŸ:Ÿö%G6‡’J?§ eíÉÊ :v¯i6ì½²µÝ^ï3;Ì>gNH¾Õçn6‹²!×Î;½ly(ËDºßà´¹{³3à î·îfëmžÊÀ\v§ôJé;H~ÈfÕ ²H Ÿ}Q)1éÔp4åIçJ—^Ó~öÖñ„Àû÷p7NJ>%0]íËÐí¯X@("ˆcÝÊäÇ'àî¹tÎÇ”^^ÞΖ'YJ!Y&›Ù *4F.ÀÝå+Q¸ü†ÇRK–šDéøo«ÑÑ{ŠÂO¦Ï^<^bªq²³£@CÚdYÈŒÑHgÃ~DC@½@àá ­ú|paçìëš¿^…ç NƒS8Û‹vfXÅÜ{jXjÍ'ܨ±FÉ®Çýöŵ¬$œ%I ’4Ýè@i$yCÃóÑŸ´hˆ¦'#¤ü`­ŸÅ7H—€vÔ5§qòéš„Màû†&^C¸KCšæsÐtDè½D öú¾vßÂc23šM¢‡æ|¾€Þ¸¼€dö Ï[k޾\hòl¥,8çÀ#YËÒX•„c?Sûðt,ò¡Apô¸–,@/ ¸qÌòç>wÏ/*‡4p ˆ¸j`/žU±óï÷¿‰† ¶Œà?Ã3A–ôæ¦0Ö‚[r¨î¥7Èeت0ýþ™ys&^p1ÎcGûÉ;’©:ó!`_Ã^.‹>1.9¬L–Ïß÷½pÄQ\mS[Ëå[&—4\@n]„Ó`w¢Ñ5gÌ >ªCHAMY®å|̧“F77\­ñç]æ¡‚«q…+Áî~@ ´Ùì„d6®"5]ÉŽðñF¢dBGÍ.3Äß0$éx"Ù+AE~S$¨³ª€Ý{£¤çÁp°;#Ž=IU›®yà±SͦÇVØõ?Dooò„ºìó™06Ùxf¼O"€?»ÆÉàÂ`vìç”’FHL\Sì% ,µ)õ¡{°\)ZBH&P3 ïÎ/¶÷´—Ë“Ÿm”ÒÕ’gˆ3Ë—žîsu›SŠ’mzK'½Ä¶jˆp)I)d¬°ùÝ®q’d^>ÀPšÃÏÎus1òâ²xB¶3ˆ!PuWÈMËV|Ø­\f÷“‘„ãùÜ`Ó©L\ºò7þ¶+‹Úä—€a^—” •š:ŸJÞ”Íà·<üÀ“äNuÃrªŸîIFÇ;Vߨá´J~zª° ‡öͦeˆÏ{Ý»Ÿz|‰›üœjtOUö+ôE}ȾD­)rô†Äit!¬@ètµo’|BWÎô"JuÖ©‹ÆµIvg~S .ô™xjL•UÿZìÁô/o\Î3“JôÈ?ÀF„ñË„¬QÿÃ4"ÉQº³!ñ½ØÑ¬ý…ÇÇÙ˜Ž¡e€pQ—FûZÏuçi ÃG”À“i*AU…­%÷ãcŠÇí.óçíKz¢âëW¾Ê*$ Hlòü‚æ0U·|šwkœfÞcuÌó§…„Ï‚ñ‰|Ø«‡dú×ê¢qï÷ §ÎÞ/1Gò|塽T\‰‘ H\•ú% õ¶;?›ÑþX] r1Ì#­|õ‹$J›óh³DÆÖûKÛ?çYa%¥IƒsÄÇ(Ÿä )òN¦†*ÐÚ®}’©\^>ë]¹‰ð.Û»bTðtC6[Þ*çö Ëýcý<,óçm*Ýe—<ý”V;(°võÇ{*ŒGÅr€þ_¹Ùa†brœ5è‰5Þ$2‡dß¼g¡?0‡ûÝtÒ!wwëMYGÇadUe8«sœG ,0ʬFˆâœ~ÐÙø§K'r¶Êâ—eæÈ¥ŸZè~Ppó‰¢Âÿr­Ÿ„@pž…f]Dæªè˜íýý#^¡Jh÷O>‘&0˜:`qðOÚá}3û(OÒâä—ä[ó\Ëè °ç÷n-‰Z8r¡_øþ¹½‰€K®Šä\nh.擜„*dí;˜Ù§Þ5¼ ^ïUl—o³èJ"ýŽĊ¸ë{U²l¥–)HD>P!. Í0LÓÀÅg‡¬ð7RÝœýV¾iì Ú}»s¼7…f®~Œ¬gl °ÐÌŸ[¸Ž¥‹â(ºôìn×pÊü#UŠ"ßt¦x¤Phñ&»ñ¬h—çsϹéöÃþ—«»žë±SfA•–À‘ŽŽ< ½Â[- W°Ê4ÀG†ºÃ¶Õþ(L`¢¡’v–5ÁŒó ·ÍTHÖB Ül´D¥^KQWå¾ìÈ/¬Ô©Øf ÆG@áµ}¥|5|ÑVÂw4ÙìááaÔUØ%ÊT2Lr!­SMl3 Ððꎑ«î½à®>†³{Àyæü·7j,c2 îw ¥ª2³!çc(øg£”a~÷ã~ÜdtûžQmž†‰”ŽwÍ™ôŸCF±¬xL2…5¶ @$gÉëŸçùM8¾=`ƒ¡ßçøRŸ’£lÏzãi·¶ïdËý™üÞ|M{:=êèV Úb®š¯Õ2¡@7yr $Z•Rô§¹0~*YBœJ«.ŸDý/–éh‰ÌîËÀìï}{:t:rØÈPs‰ŽfÄÇðEß8÷Ålb8]ŒÞ䬚¶¤@v‚÷´±Ô$<ÑÛÆÓ¥_é…/ÓkW:ªE´.Ù,¬ çLÂFzω-ÜÉ‚Îë#…18aÛd‹ñv `q£ÉûL²è:&áni*.,YGi`9TJûªÑ®ýk£¤¹› ôqïæ??€‡þ×¾HýPØö3¬¼h1Põ¹_µ¬Þ¬Þ*þˆ–‰oøt›]i~äž×Y’ñ‚Ø:M2ù?>¥0Wgþô”É—;rrft~·4ñ3¹ Í\™”R 'ÕšŸ‰×ŒJS.ž«HIòÒd¤ '¡+>Üè"/Ãj™…ÃõÞQ$²uÆ"·¡ö=Ý&™Ê=?örVöCµÃÝfgÝßv&ÑcªO¬t©|w¾_®£74ÿ-®ä4£Üœ=£ßõ·¬L› “M½gü!œhÓXóÙŸÚŸ>/aŸ?Ó4gÝOXT |KÌ4T´çÒ¹ŽÐg©JSÕÛ€æPa6â¶B&ã&Í; jŠæ³(ÍÁE7è[ã|¶´¼üo*[S4€0þÈ[þÒŸýåζ…jKÀTêëï§£eŽŸ>y01>§—¦Òö=[&óÕôå÷PÐZ€<ÀuÄø›Ptr@dp!a¯ó¤FÏMÉÈbnsÝÜèÜ$ôú{ðÚÇ8Cþkzæ:Ì$*™@‡ó>’¯b‡©ò2ïi5›À^»È™L¸<:žý«) °úÚ0‰‘Ä|q‚&oëRÕ‡{ 0hòÚŸ6n‹TýÁê]RpyG8Óß›¯Ž«'3YU,¬ùüëqÜ Ï‹´Q“G˜«¾Ë‡M…Òç“6ûÖKät¶¯›Ùf§~÷_X|5fÉðˆxrÌáãü¯C6¬q—šã¦”MôýÜlB­_v¯"Ò¨T j÷;߆n‹¦'M¼s™+èo'🠢eYà¨ÜùdÙÜ:ÏÆ/ ÄyÃà`ƒ4­6${#J`öŠÊHU+ååÑÄ¢òrß)£žhðº@’Þ•ŽÕ(ÐSÚc/š¶í™[t—·¿^Fg{CéT¼ne ʰ rªâ§%`t‰g³çg¢ÑÑÛ]©KÓ2ëÖ΄1eÆk- ûs™} Š,¢ã‘T˜öœç2VUN4ÔP ßšZ«h¼|aõAÅrF˜ÇX” `&Þ×YñÏä Au.’, ;m;’ÏÜb^‘ò„[Rb݆èöiŸ£ŠJç̘•÷ø‹A—¨<æÚ\éOì%ä_AÏŸÞȃdH”¤€‰§Aül/>£E²¦Lµa¡S Yå¶•‚FÙ9™íï%Iïº]{uÊÚ¬\qc-v‹,zB 3Y]L ëûû>³Zj´p´¦¤¼£Þ6›Š[Â3;L ¦Q³ #3LJa/Æ [ÆŠ : V'c抢»J'Ìàä£JaôYVS'ÿXF¹•¦“³ˆ«Œ—YËf”Eh¯ÃýÂ*^J ?›ÇàŸ¨7YÎ%ÓÝ—÷vî¶·?èé7ìjÛ[¥`=rX?a®ç€¼iTÀ††“uþ Çë^ò¦ûZ7D úi~”ìN6ˆ}º‡š‘Ù§öM(k·¹E›å“®ÎPÖcŒ¬áv3F6)mÙF`ZPMC}>4êj ðÝ¥9ùe6@PÉCGóV¯ïý²;Α¿~^ó"íºq„ñfçTxÇ| ïÔ^ÏžÙ­)v¯E)™ïÁ8RëƒñÔÑ$BeñZ÷pñp´yž T´ *Hˆ{Öw~æE|6¥Ñ f´AÂP™§cLîÄÂIß•“ÕÕ²ƒ àUä·¦–MGìŒ.KL=»c7müƒ!rR‡æ° Y]ø¾ƒm¢‚dÝ9ýA¹ç#‰<ìÎ}¿ÝÏù3ˆ)н¿,qüâ-÷^è:œÊ[™ª¶Iî²à>Þ’”Ë4Õ«1`õMUØàѳêÀhffrbb-2¹¹7²Óää=€S-Þ8}ýTµ²®mŠù,"¤ËÞVåóÁÂKÒòª[Ý#©gzÙæÃ _UÒ†crzû¤Žj=EºôžÜ !#Æ0qWZÑw®b· íh|!.ØÕí­Õ1‘ä¢vÃcó›ÏYcnê÷›ø“–y̨oaøÜÔ˜ÑW>ùsöƒôG}b<ú®š8Nƒø²1”ÆíÚÞG r¬°<§]IµE­iE Ô4ðm>ì³Øw·¬C㈠Æ4°Oäu;i4ÀQ=¤ ±AP€”wFE¥¿0ªâ¸zLEîôÎq©”°ÍœºÕ2¼dùî–:£Îi"/ƒÛn!m8GÚž_¼›ÛCÝ¢ÎN#·W«ìï¦$¸@ƒ{^´Ûí…b›y+g»ÔP™Þ7@uuºZQ[³cÜ.¯ä_£È|oê¤TAŸÍèyè èX~vÈ{`ˆøêeü-÷´ÎMYYÕ}£1"þyîS˜s2÷ÛûG\K5‘?ÒÓèÎRÆTÜ–”Zr/éð×3}d{7®b;™(FðHÿÓRÎÇ·P6 ÖÌò®pj$Vö–ö;ÔÝw·†ü’UéNEqS®›ßû(’ÇAÐKÿ|RAÿ Ÿ·ë@ “²l-*½"ÌZ O½d} <‹}dp/,) Þn“Ó/ißM¡Bƒ|àÉšV’gî'ŒqŠeD_s‡´"·íÀÙ«Ôx '-Âæ#Ž€ñ÷LÌåBÊɾJØ1,Òk´Ç]²Ú…tè ,¡ýÛG A]0F­ÿbNÙ­TÏ’&/Â%¥K~蕬ÉòÂf–3—®üM­[t s¢}ü°v] é‚…ÒŠÔÊm»ÅÁÌuÄOP‹tPä@ÂÔŽíýJFФ,ö¢y µ(Ê`tÿXtzèeHŽA&/TÐÊÊ_N~Þ¹u%c|Q˜)¬ ^™›þ¤‚æz‡g6ÎMÅý²Uýt›kò¼a›È¢Þ„º€‚‚ù$d”‡t™£ÝÅ€«þî¢ü VNO˜XqˆCdN[Í™>‹ú¥±¨Dg‚çGÒ›šCIã=ÁŒÞ›1κϤ›T£¦Ä}Ñå웇ºŒ”\ã½í˜SS9º)Ó‰N¡Z6aJE Þv?çGquó‰þÜôãRA‹5^ØÒWÆ¢F$ºÖèFçÆåU1†§ŠËáÑÅ—ª›ßî2= )⸜ þCS^¯ÉÆr¦g…뾈ƒÐ¸o_7øãt|õ¡"™¢;4€S_EY‰êM_ï /Eìk#RÀúìÜæÇt“ ah×lóµH³}–/Çd`Ä¡³{#GÓ?ž5¼ ¿í"è +•]7­wqÄ4Þ8*É¡’ºq-ÙÛÊo&-Ñø7H¡$GÛ>_£¢(³}m±qb^áÚnc¡?õ¬S0Á{åÆ1 Ycˆ{Ruœ]È1µÓ°qã¬_E0uÂx5*¨hpò FÚ€ý¦0‹§uÄýÛEÆI•¾èf¼ržfL>ÇÈ+£Ìÿ¥úf,|f¶žø< ,{¢Åî†{©šiÉÛ¿œPvÁ•C OŸPtœ%Ä© &úë@Ò·àРã`vËM¼„Ûùf£óQÇöŒpœ}q¿±Ð˦ײoˆ^éh¬ÙÁ´ ½ µJní ˆZ{~I€IUm˜ç= ÇkÖ¯¥ö–¼q+ÓšôûÆe×Jº({õ`v}E˜ïµ5Nrá²õUã)‡Ý9Ùm?ÓË—.ÞïIZékƆ®*â(I[o½4Å%󩈤‘z‡´)Ž3Ç?¢ÉùX]OõÉ¡_ß÷,û˜ VS4%¼éKw×ÚÑÿ/H÷h|î/fÊý<Á”KeÈŽYë'VÍÉ<9ÿÏ­ªò5Ú1*JH~0Å.ü¨©§0ó0T¾É”8nú¶h/˜A<=º•Þ:ÿ»µ'¨`Fã!ɸy/pyÂ;^7kxu8‘¢ø$5'¢">]GÙ©)ÈÜÆ`¥Ì\{äW•Iù½ð¡plUß×|‡+&½`ßí#ÞjËú”ÊÝÝ®)¿QùMRÿÝtÈ«þ¸¯áãÍ©¨W•]›K³Ã_ %ýÆÑ¹Ï§P ,û(VÜéä%Ü‹(B1ûî1fhúkÚó-ÿ]@L‘Ì3#æ×ÆF7b“\” ç\2ÝÊ &µj]‘ÙÜHek™¦ÎÈh1£xre»ƒ¶ßDE·*É¿#´Ý€x]?ã¨Ú0jw+k‰6æ¬M÷Ú(ÿ+Ã1¶Frû¡ºcÅ3%wß Ôjd@ Æ©’Ikõ ;Dn | ¸ÃI•2¥9Zbˆ-ã¥p(HXf«ÕÃ"a1«`ªÜŠÍ4Iºõ®u$ŽsÿÎ>ìt±û1§¿çÿëÐ\?˜d²Ñ“Jˆk¡×ûJ‡5MXcìÊ1ã?¼¯ïª+íŽPPq9zàëÇP³z¯¡©)yº[Ó@9£êÃ<„OY EƼ§ëvîÄY>ßü£PÚ®é…ô¼È×5f¡ •ŽkÙ@£ÂZ¥ÝŽÁk¨–¢"»ª¬V¸Ì¼’ „[8·u®à L·&§E›4?Y¥·r°Z*g¬¼CqòƹôqF‡ûvƒ‰p¼~Å©Žn=ü:Å@å@«Rw¬â’ºURxÀ¿ç$ÎYM’ÎôêéÌÌÒ*Èã ÷ëýao×#~Ø`<`‘&2û S¶Z›£à^ ¢ó—WóÿØAN.ê,¸ ,çaeäù¹sÌJöU$»¥±õtu˜ÛJÈmVÍBÝšEáñ:c±jÔ¬7U×îcYúV'lr²ÚÇß¾mÒ<âR^q‰ÊíW:•ÀÚÖ2ÝŠb÷tµFîäŽè-Ö¼ êéRIQ ‚Êm¨M"*ãÀ#"@‰—ßÍKAÞ´“£-È™ô+´_ívv’áê˜×ÂÍk`ÕõâL é"”z‚DbUÇ•_¥+¯?,†3×ááùU"ýÅýnZÉíxëZoy×êãıÝ}¿‡që.yä§~Ä»Zº³ÀÚø„¥CóG+ÓñÈÛQPÒX»Ä…±íùÆH\  ÓœÆ àMV iŒv™Ïë駯ßj¿øM^X9=7K&tDÂì)ÌX`ŽäŸ|-òËþÎFå±íÍ )@5ÐMÇÏQòü*äJÂEeH®[9¨ˆ_¤Èß·âñSÂæÐV²©ÔÁPp,nª¨ZáÏ÷€»6+*Ë/Yp¡lö·H¡” ¥˜â&МM`‰´õ?ø£Œ;éŽÐ•peÅÛZ¦”2µ{ ï…€Xq:“íçE ’¯£ã2º;ê`±#c()Û¼N‘šÌâãm2µw€Ôý=*%¡*ô +µ³Œ î\{a¤h$üDÓ9¥¡¼(¹ûœlO×rÉÎ2‚FŠâ•J‚k_ï4}ôã>3i)š‰6y¡R‘Â]èH$Ma…ŒšñÃÚ݇Yî4¶4Ë5±oÊr Hj¢'æ[wýD““–€ ²Â3Å·Á¶œì®¬t}QØÊªØñœØõOÉò}ÎaÄóøB¤TU½3?ÙTžòý¶°éı{äž`à´ÌµžŒYá|Å>¤ÚŒ¤ò]ϧç54C¨x· ÿƒðÈå©[‘oWNu¾¼DXm¨°·&&¨C´Aò/*€ý$ EÓѳf%kè¿çjî6·Ê°ˆL˜çÝQ]„ÉñäÁ¤<´[µßóï 4ó<¹C×JàN(ЏH·9ÒšÏ_»±»îã\¼–ÜÿÊǧÁ¾™˜‹mðhHÈ Ÿ±¢¹H`5/_:µ²¨kK…•_7Ü<î ÑA¤êhþs- )w£nŒ²'4¾«D#f+ó'Œ“‡4÷Nå÷Üâ½+=<…JT½ÇÔ,~Ü—\¢™ó¦^‘@ mŠ!‚Æ'Lâøb”DOø´z#ªÛ«Ùò¹l×±>“/#Ú9wÏŽU×})nYSVÍ|gÐL?‡cW6¿=“,g]0íÉÊuÄÐâ€óÿUØÙÏ]ì¦Ã•Í/û|ÿU_ Ûih‡Ä™÷‡CØ·ü«9{îA-omf«^ÌèéFæäýÆPÝÉ{{ß³¥õÅKî³ÕvÍ(?ʇևF±Í ƒ–Ít^!†- {4VhÅÆÊs§¸Êl®’AÀð¹ÁÊ&<×ÚHÖkq¨’ åx5>V6C9ÌM±s±Íwƒúo-[Xå (8Öºª"£Ý½Qyo£‘“ú·grêoˆ’Eøè^rØÏ çøÎÏÏÌ2WMeÓâÉVw&TÈK;Yn72…(ïä6:çrd X–G¸¹ÖfÂLgÇY¸ßÔÄ0ƒåÆí.ñ¢³¯K=ª‡ûà†§p=Ýã¹\=GÓû’¾ºåÆ ¶„wå)¤c…Š ¤Í¤O$ttŒäXm*q‡=“M]ÎéJÐ2=‹ãÔW±¶õƒX6•GõŠ^ùŽä ŸS`Ú—~ÎµŽª¡=‰žúÉÙœ—öã§&-u/uí!ÅÁìÕÁ·MBC·ã+ø [^ØÈ‰âpO—ê†ö´ØU¡%Ÿk2ÒÙºŠs‘79±Æâè„¿Êó0K“)ì&ª ¬Ã@Q”*äœæ±Pô¯~¯fFîQs0®lDYV)á½;HëàÁvìaw&à5¼zø¬‡#Ø&`fÌ(£l9æø›0{¾Ò¿¤„TDYyös^1ÎïÐ ‘vî—<ëXášñË®ò%Ê…¸Ñ?¦ˆ= ÉZW2¢ßì‰J{€F; :©ÆàŒÏ†¼­ ß"ÀIu¯ÎýÖI¢¿Òðöl"\cNêÎËuŠ·ßw̸ó¤£(ïžKRD6w ð¨|óÙò¯ôk¹¥·!~¸–´Xþg£ÐÒŵÑQ ÝáŒÇ˱1eÊìþô ÁƒÝ·õ”É-×>e"ßÌ®ü>EÙÑh¦I¤9¦?8З² LfˆiM£"ýC `WmS¹õû5Ó…­éAžtDOøyîtjz ôÍÔ“è2ía£^¤½2;‹7ÏÌø!³e(§èßÏœ ÖQLÒ¶[§‡˜ r©pè2æ¼Tš·êR çÉ!ìæ@áý÷\Ç»VP]cð é2Ñ{·Gk1è¬ëøÿJ;K¦“­ÌIÚ^OŒ §cqFþ½Óßë(oõzõƾ `M6¼R%gƒl7º~wtxOýB?´cÂ¥‹SnOtÂXÓŸ‹lVb8r¦½ŸnÏ¢ âôôîá¨pçžO ¬üYK˜ä ;aç¿Ó úöÞ«ÏÜoÑ~aº’zýÝœ§ºØ2«š¸­P‘hTù¨ b䋤дµQÿÎdÇŽŸØNÇiãÆ™#–1å‚$ãjÈ ^u¶£aÝ·}C5É&êÀçŽhÜÈWü©Ðq;ê¸'„±/_ÝÑíRK«L‡Z—¿ŠËçòö¬6cìWSiÇŒì2ÿÀ2*-Òu8¢k†QL æ KB7ŠÍâÎ:´ŽWskæ;Œa™éVí4,hDÄá×ûw¯?#-Ñ`$*%s·ì®¿Aijß'#q¶]ñÂ'zLÁ·ªŠ¬l_Ú•`·GZ 3Ñ^ã§3X*ŽÝœzÒ0Ðfè}OWÎ/ÄíÐÂ^xØ\ 6x^Ž;±« ‘4Úz;q/RP$u…—>µ¡9ôŒ#Š55ÉÌr9wR‘/r:L€¾'µdQãgs|¥%4FÊ ÎSQ*¡úûa– g«2ùj]k2òjÓ÷ 'Rߣ¿Ki>ýôK…$q>å?˜qÀÂÚUÑ*4ǘ·Ú98ù»%_ 땚C>ƒw™ñªÖ¿•LjøCþŠ-r™&Ö ý³BCG¥Ÿ V±âQBÞ~XÉ*Kº¨]̸¼5”HCºÝ>: J[íAÌÝ2Vò/¬C•á–W;ó[iß¡‚òôh¤ïù¤õ©²#ªâÖ¶-xcäJ‹"Á€@uSjð™w\ŠO¹s©H1Ò«mŒÑÉJÛÊNŽo°\Í1ÅdmÊÓGëlWíO(Ëš|Ép{©Çœ¥”Ÿá_󮊛[ÇÇ›øbŠ_(I7ªà¨ß‚¿™u4º øê÷x+wóu-ªïE±ÙyN¼âÅdlžÎ)”*Že2çºJá½[ÁZR„Íòœö5Ë#Û¤nïoðê6N"šÒ–w/OÈÊGBäkœ­þ$R¬¥.Úuˤ1LJ¤šš_ò“{á}6Ñ=îK©ybæÚï q©O›–D0åO£ˆex7IV?]&àî‡*| ·&{Aç3”ÚœÏi¼Ä,ÏWƒ/2›u0æJÒòü”½ñ×HÔb¨"z,{žG<~ þ{±Öip'·—C…,o®üNaøäê÷ç°]Õ×n8“ïo*vŒtî*|€3X—#íƒüëwš\%'¶Û%Í3nOf»ªïq§X' wÑ·S‘BSUe\˜‹wäŨË,-ʳ§¿ºØwjü÷=¦¨!‘¿.’;Ðe+ž ABކ¢¨Óнz¬*ÆêÌUhy/-uMQ0dܹìæÊß“ÀiÉýLHõLbËÞ[ºÝÕŒV>ËðÄØK‹<Š6¢{ËÖ3fÙ¿¤Š5j‚qm™.€·o ÿoù£$eny Ì)Nà†?ÿÈüa¤ú1êß~;”]ýI•zo•Ÿ{˜ u—« gÒÏW y¿&®6󽑉0¿ÀÈö?ìK”ö§ÇæÐß&2ãõLTLI ÿ¨;mÀãçÿ{&?&yÖª Sä;ÜTP§ãŽQ7¨W¹¤²[³|;;4Í$°L¹¡Ä{èÙR&ÞŽþ.=*Þ¿kù M1uÀÚe}f¨˜ñÆ’ê… J~’Ê¥%«ƒlF1°³v´2pýŸ~ïÿmüÿ§¢0˜ÿ€;&sGê6#ŠÞ¨÷÷EŠ k2âÿzvI[ò9{ë=p”SÈêfa˜ŸW.{ ÍuW÷>±¿Ñùûèù÷e³óÍúíÁû„ßû),HÎß5Œ¶¿óïû*Ñ[§÷ëÝC¶kaÛA’Yfí‚FA8•m<Óºÿ éIcgÿsç{µòEèQáOÂþöy½}³$uQÄá¯ÉÖ7±,ÃÅ¡O…Û+Ë4KùõyùE.¨Å¥í-gŒ3HRJÞTÇ­?ŸŠÛ —¾•ï«?Pñ*ŽTÍ÷†òŠÁ®(¾cobžþ´N\ÿy–ogFIÊOlØ/÷ú’y_¶>ÉYàÜÿ¬Èx¯XêþRSÌ]±F}`áxTaù;A Ñ5³qâ"ô¬0§žÀ­‘´¦Õ6©Ù`±.µñk«…¶¶fQû_%šÉPδPÃ<“üÒ—Oå, e†ÒŽy–M{™¡÷ü˜œ$ô%úõt’ÐÊR=®‘PŸ6Š£NŒŽ[s2µÚ-•‘ÙÚF&Î[z‹HÔJÖeŠ罨œû{ÇÎi%ç”ÆûðÓΓÇÅt\wùÜæÛÍðTƒ;³‡¡q‡¿…Þ/Ü<†Ê“ˆòáÛªçÅmSåÔMަ¦¤UÆtÕÝDšñ`m£Øšb)œg8‡éØHvTCãe÷®§°‰ájŒÅ<.—’{E'V•¦ÇZ[]o‰ŒÄ0…kR§lq鎶*¶ì-k6Kvt7K)(«‘‘a‰ºøî/”/°Ð[µ#{‰èc# [=¡; …Ÿq7/ùBK4Qá*›Tä[–—%xwTôËÀmå º@¯¬CAâÒ|-kŸšþžâí7¤müä =>¥‘×\{ûÅ3gsŽ´e7•>’=Þön/ŒPòXtr?ã$­Ufšcrã±Ä„Öîk!£yë¾Çaö.(Ó@@™©‚šHÃ蹡n Kr¾`Áwéƒþ;Qä¯ÈÑ´LeÅ55R4Å·Å&¢Ó&ß³3œÎØ{N ƒ“næ;ióâö4kQ‰ÿa&ù’.?x«·ïÝšÇfª˜6ÿ†izÒ)páYÑ ”Vrîu«ªs+wkV5+üi?PIF7ûˆÛBòæÐA¤B 0Z£=Ë&Ö÷å Z?dÝÛñ‹È—OÉÏ¡8…»Ý¸·ÈÛ¬|+ÿ:_ bH3±˜tæ?½TñÉ{–$8#Ú©zLæ+ƒ×„MEô~“CωáŠà(“±kâO|*¡NYm·r&òÛXõ~ʧq$^NÍHÇ)?4Ú1ßÁºçï½/bå¢{í{¿ÙyíBy&>¡ùЇø™1°öÔMôEd70`»HvÅO¦|¯8va¶Iӷ˘Ñ=ËšÞNb$@ÇmwŠ9¹!f8¬Á<©£lÔYghê’7ùa(Zf¸òr— ©ÿÑ-Žä7“Á_™(eË—B¹Û‚SÑG»×˜°é¹+»°g,]hö£ìñsï5®y¾nJÀA|<óIóýé)gãHèSݺìgi骶Šé(|·G‡SEIBl>™ªß¹¹¸Y¤Ü‡Æl{‡†³¹Á-Bë¼F̳|ðŒûð8ë߯G ÔãÇÄ×¶S yoûžŽ¢K­CeLü_çóꆈpû'­Ýn§ü“¾j™z{B¸G5\¥Ðö˜TÛ¥°ÙY»UÄÆÐõ=g±µ„k†$s«‡NÍ sFR†ÛïIG~.ßÿø-óõGzP¥°™+EÕ>“Ç‹›=cãö59h˾œ× üqk—HFžÏ·GY þFíïmøhTЀ¿òÊM‘y…Øðbq6ÖTýFê«¶£éQ±Suìü=½º,GbiCý_æwi;‘«ÖnsŸ®(N˜èÒ·ö—Å‘æJ)äY“2c>6V^B<ÙÙüü;Èí|†1Ñ~H5Š^Ö®Kœm&sÊþ+srþ¹_¿Î_«PÑY¤¹žEÖŒ—ºï^j†‹¾,Ó7µòˆÉÇ~‘2ãÐÅ5´«Ž„‡%­kiY«é à'ž»?9 ÞW)e¤–L¦j´…ô7€¹ÉÝ>ú¥PzxÈ´æŽmîƒú6ûøOÈÖ\…g(ñõ)ŽªéD5•„è?{…Ú&=Kªyœ KNè6U©Á>`Lþ}ŒÎþ Š2ê3ÕF§®¤‰–*XWSŠ4‹~ó›“\Žÿ8ŠlÙâ혓Ҭ·‘rt–&Dƒälö܈Éç±'ŠA"ûbЭ›^Î:=’“–ÐQ$D“z2Ûm0.dòÄ\¯‹×,z¥m"ÜAƒä֥Фï©”Ý;â˺÷Yª:GÆæmŸp”o…ƒ;)uù2:¥þe‚¸ŒØjánj†ƒhqЇÇß<Œ¸­UqËï(àÇ5eªª ¼ D½fãxMdªy× A¡Û©ÅNñ“ÿò“ôpë!O'£²v‹Õf «íŽ^›Åû¥±¹ÈŸBÿ7ådÕÖvôí!`­mãMÿåùÛ= þótxþÓöÀZŒÛ´5—ÍÅø\è¶«Øâ{µáÙO†™ÚÀH;'Èíó‰ÍÅ‘ ½Žt—BûÍà-õúE¾Ð MÔuÖžgx˜ÂY¦«–<&€èýÖœ·ÆÚƒÿÕpÝõ|]£”»k¶ÄqÇhÅíýñâ.êj²3“¿—ûç{ˆšJzmc>W}CUX_±Ä³QºªñxìÎsö&ê¨lŸ}˜’ißFí•íöªéKF¶s¹GoÈ~Ô=‚êw‘:å TQÍå³ .¡Ô-71Ó< ÿð5¯/Î"o!-‰ÅÅ+KõøL:˜'ß²e^2ÿè{½$m¢®Êö1Ø ·¯sGY5ÅO/[Š[4f´iP†÷ ±ñèÓuDêõ–ÑWJª-ʾô ý0MûïB5â•t»xtEÒÛ°N5ß÷W•Õn¨fÖYû4¤ŽyVd‡ØíF‚û±ÿøÞ'P×·±ŸéÓläF9nk #xFvúN@Xqÿ†úJŠ‚³z¬hÖ¹bÇëÎö¾B0 ÏÍ ,ÖÕú缆AoH£·™œ[Z?SLÍ3duô“ ÌSwµ@]ŠÄ9šx„~ïæ µDÚÌùùMU{6Ýïßô·( øntk÷´AÑñoøé™’+7cÙ‰mN'|Cð¼¯ É A ¤ðj 'Tœh’§¶‹HL;‰¯´?´‰w¡‡ÉXÄÊM¯âqÇ-|©K$õ‘rƒò#'÷ …¼|vóÎzfâ„Òœ°Æ˜ô²'HÍ'óïàŸ„‰ù*fâ¿0W±÷_ ÏŠª–å'>[Ë]»ºªl›–PBrϼWR¯U ÿ©”æÕû•%JFLI¼ë0;µ´R+? Ö ÷F•ÌO‚ÂÎBHE4"Sgè“ÌS6´Écï/ƒë ’5aвŌ333ƒÅLZ 333“ÅÌ’Å 333[Ìè=GîîÛ÷Þ™ÙÙØù"6æüt¹ª²²2³²Þ§žTò2¬,W_ás/[ìGÜ»¯%§áÓ‹k݇¡ønB*î‰K˜1 “mq ¢ÁçRCÇWW‘™9Eg¼²RõTiб”i_²”œS0;òçe¼¶aEå^&•Â’f?‡¢èåús¤PfU_§îu,ÇW=P&³»mgNîðí ™& êÁ•Š.r7QÖá%@vÆXßô"ðš(5/‹¤ ´³=7³Ò—Z}dQ$ß¶$ŠîøÛœf–VÜfÓ@+ôËiKãÚª” Œi—~›÷Rxl´EH•!CF¾Ö¹ÜPÄÆI ¦"Ü–ð}YŠí¶ ¨ š²Ù°C*,ŸoMjpË"UGÞ„:¦Pøo(NÐjª#íœÔq½²f/}p¤[DÊÍ>J9ó¼OÜ–ÞUOŠÏÍažWF)€Ï¹N@ƶ3|‰÷89#kêœ/döyú@ ÿ…  Mr½˜@ŒŒpDÌê½9¾árµ™’‡’&÷º¢™½ÏC"ìº,æ½õÓ#ÎG <áD÷¯¦c™¿Ì«%×IŽŠ¦7m QÔCn|-w)Šâ Mhª¡D>B±*Hëy’gnÆ"Äp!ßþéõßxaÌáŒsÍ9¨gb‹ÞèD™°¾„¯ÉÅWª ƒß\èýS> ­‚뾘uh·=Œt­*´ÐW?ý¢›múK£ïê¶ÝÊ9ê Ïö‰‰p¢{ø¡Sa~V™Þ¯©^)­ü÷hÛ6o®ÕÖ Þ^ʇT[ùUãæòÁ J`eXÊB±ï‚UuŸŠg}äqZ¼ž÷-þ"ìåö#ËПy°S0ÚÞØ–ÚÁ…ùϨ•˜7Yi` ±ðíÈ}‚õM>B µ/9TѽQ7½‘¯J[bfõ}û”ç »Û4Ä vAžž´=ü±l­³ÌÎPµõ0ŒìIrò^dæn¯®OM¬ LmdP” íÓ{ß~Ý =Žüå }>MÆ— òÜûÝd@©Ô+HßÑ {c««OÖëÇÆ{(«¿hÆD²?ákëêÞÓÙÁ1–f¬ôÈ#÷<,ÑÐøò'nuÖžÅ1å´p¨'-‰9Ίš(6/´‡»-üDAæ}`\PŽ ¸Óç" m“ÜÂ@8q‘¡*7Jt+Ñ/W$±ð3ã÷`ó%Öj-5*Q§¡‹B¹œ·dÛSß9¿³ƒ¼¾,]^ÅF‘)*J'Zʬ2‹ŠQ{ÙUû„íÚФ@Côòò9M^üDL[d³bœÅ G{ÿ+Å06ï£0Âj<å¼*õv®Ý#¬R7«¡|¨ìÄa>}è16¯zú¨þ¹< GƒÀ-¸H3©yë…uñbøwÔåN”Ÿ€±uéG¸k geÞªúY>ªÐg©êǪÕêK+ÉRÁª°PCÙeزG%Þ"!ÇrÝDöñ6 "(íÚ€+ôç­ÛI“+:f+@¿t)¼q†=‰F›3mÇëÅL¬©!gưD ¨Qê“ß@9züÕV»_ù¹\j©“ï>3£ˆú{¬òˆd<ô΄Ö,`æ´X¾-ºqA¶"ùåù)]êòƒ~ßE®ÞKÀN Üb¢•äTÔ M扅³4‰‰NqGìÆÀ@ü¸|sk)‹¡¸ÉÇŽÞpFßÓƒÙÿ~þù÷\ ²¤¦vOCÇÔW$†‚¬SÖÛÞ.£ß¾²ïxêªEoj™½´U9§æž6?=•^ÊZ²äß'z"*DLhºCO‰·`–p›ƒÿÙÃŒ¿B§ÀáP6@(â`òZâ“gÞ+6¹*¬I–ô§ñ_J‘ Ë‘}£¯4Eu—3ø(G€Á—BžoÖf„L|Iïåï-a®¥´‰áöo½»5:ëgs…FF~ŽQùŽ|sÇzÀCŒcöúUÛjËú¦É˜XB"c^#NœHñ:Ÿƒˆ9Vrqft鯵S(Ð<®K\ZkeŒ>µûýÊ¡Ü,Ã7èI»ØÁPpÌtIÖ_VfìØœ>JG '¡gªOŽÍW@…:‚PÍmÕÏMC©ÐUÞS{"¡ín¶¯qB{æ’?¨{¹…8Gû?õå ¤—·)Ž&Xò® ý,{‘sÈèâ<Ø\ú<²±uL´a”G!Q¢ÃOU’»ž¾e.w#²Ð¿5„.mظo:nJ·-=®+\M÷ 1‰~š‰á¡ãiò]¡jTE‹R´€½\cûËêÈz÷cP•À9t>¦9×\íŨÁë+³º}l±Êœ¤èèµ(â­ b/äªF?žaG_²Æ¬‰jÿÎ^–œÐÜTÃøæ,Zl˜EÑp§Øn¬¨öµGÙ£´’«ÌÕyŽÚJbX›wÁÅ:l>€¸/Wýq²üm÷Æé"0ŠpŽ–[^O;Ü0H} Ýà”¦)Á¥qLÈ-“ÑûrwÉdzҀšf°5ª/ÚýÙÜ^ºµvЖ­3˧Y”PÊ(SÂ(ÁÉbÓª•¨©r­ú³Š°e|ÚÄÒ'}¯Åt¶ Å\ß²Ý%X.‚Ý ‘ßa }_£^–78ì*„Òzã|¤°(}lh”¨¦þ’9MáFËîq‘ÉwÁˆfÌ-Âí,J†»¨þ ,$¹_Ûìg¾ÒÞš˜úÍà—º©\3®2\ÎÆð·íŸ§|þ§©&Ç oØ8Í+‡;?ÀÕÍ2ÚÌ|’ÙT04C,B²êÖnÆÝ?¶Àf::)…Ìg¢ìÓ`'×¶>¶S¦Ð5Þ݃ 9Њ'ìy® þ€-ÅBHQ×åuñRT¡¼î²½r%4Ö “ELËD‘†-ò ;k;Ýï¶bÕ¶©aî0AÌ=ÁHra|Ïj9çüæøÈB„RTl¬Dýáà f³<‹ýM_”»|±¤[±€X\‰‡ŽÃrŠ•hhÀVÉ‘ˆM•ÇÞ?ùA¶:S™/‰kóú:’x!´Ê¡ Õ,åê@4‚DåP£cLׯtϧ oý±æDJÂý<8 ‹9þ˜é5œ2Øc±Êú™{ôæÞ;ƒ}†×å¸0e+þ¶+j8OU vùc,xFï~—{ß÷[¿ ~qõW†X¬zšñ¹·ÿ9Xûjocá@âÌæ*%6ß8:š¦æÚ#ì"fXuu?ý¾»¼ –5—?vQDçSÆwÝ£¸;b$×M¨ÓŠ£&{o9ª’2-²¥á8GªQ‹ç04PMóÐ|r¹é7€y'F0VÑA#8|Õ«$FŽ*\ûa†‡Ú”éu ðËoW5ÑÁj–܇\"Õ‰+<ðÛ¬'K+*Y lçz`øÌ£ (Ùç%ùNܼVÜa ®Ñx–)ã[¯Sî‚Zþ-`Ĭ‹°tbÔ•^÷+\OûÈð7ÉÙf/§Ýµµ‚Ÿ6!¨ô,_Çɪø¾1—`:?Oª¬N:ÞÕ©°Ò(ªN¬âk4£ÀmíûYlâH`á6Ùè’·Š R,·Jó„¡ø˜g£AN[Á.»“Iu^JA(_Å[ 6^½L AµYnþH¸ÝœWì0Žê/ær‰¨¾­WÞ@wíIIë%+Iö(Zžb¸aj%Kê,ÎÆ¦tï šAQaú'j„L82™²ÙO û·WàM=qAg㯼u•YZ=J‘*5kñÛÈ&ª5„kKñŽYw¼õ›ú¤Öêä¸Ï”šrvü”4Me8(A**¾Ít |î½-×[ÞDèÆ]Iî®ç^Hÿ­$[´?DI{²Ø …x¬Û{=솖½‘*²]s¢ú™ø¥{Ò¿ò6tˆÉT‹çè‚r±„êÉKT°ÇüdÁ,ÉÃOæÏÛØ¼-¶¬Ëø˜h¸ÜNÆ:€—/­½a«”–ˆó¾›^LÊNdŽ.cå HfAêåËØÃàöHaÎÒŽçK`¶¯»dC®p"[P)©_µ § Ù¶do(%{]ï/ü¢C­ ¶ñÊ}›{š¨kÀ¹{üõÅ)Ü]Ç«* îoüHø#оÇd‚£n¥G°ýÚÁä°\ËÚœÝ{q÷ÔŠ~J ­E Ë ^™<'&• É%¥¢´¾&øÖ5Ìv°:Lî–isMØÝwÈzÓZ)Û«Á”B0\úv €Î³çnôÓä+ˆc¹.ÒXÑ’ëñ 0noy»€ûØd´t8=T|V¥i:ÁxºïºŒ?kÉ8^ Ìs®zׇ‹Ëröcu~W9¾R:›*.B&gc‚Û¾ÖÄA{7dóZ-‹Uhõ1«Ç[²›ís¾xÂìº9„Y”öFo\‰ýZküúÊiÛVSÃŽC÷0Á·é<+•øß=‰e{ qGœ­‘5š=-BGG²çÑë°Ûn³ˆšjùÿB­ï)ÑIT#ZR>#†ÊT<§LZ“)µ°í­hDwo´ÌëùÍ:í5lT~ÁârŸs/hNµ¸$²Ù^2/ãZß[ì…Á^l¡8N²ÂP>þ÷R{¥íÕ°A$Ù}]‡VP§`<ÿdoº~ì”Ø·Ï[ÓJ‰ÒÓJªRGøÜ ñµšˆ)VTõóHB-úéÕ 1W)NÚš=èWpi/]dq[µwO˘f‡©‰÷`Ñîu?ÂóVŽ àË–qÉ.U€6Öö<5ÜxJͯyœøIÞó©p˜Gð(LÉx?Oõ ƒë™D×(•Ã5Ò^Å'¼Ó¯ƒìvWÿ5—Uöî?{‹áŸôÖ“a&8ªmHZê$ôŸ}{Â|äùšfçØÈÜŸÁS¿*b÷^xŽ—´´yä‘{RºGÏÔ% ç Æ]ïLPr‚ê(žuîüEãíÇ–ÿ‰¦Ž/~³%ÜXVq9ÿwðQÉ5² \…ø7Wq–‚bU4×–hYæŽùì|K»]e¥-­üˆE‰rÉ+öf™z*úU:½pĪ ×ß ù¶´RY_Ø£¿sÛƒØkª0dHË÷ƒ:Ó°q´æª û7ýE5¬´f+ ûGÆÈåƒvUßQ@œ²HÕ« €Êë_ûÙ®–\<>ÙÉŸ W—BѬ¸W½•ìø[íJè¢Ú/„¡E츻·×øåAˆyñž8+2ÇóA0í³+¶”ìFBÛ"3yïZß ã­õ +íŽ\˜ª‰±&uPîK±Œÿ W9LRvÓõ<ƒTδ_sY[ýæ¤õ÷ê$¦å :§v„¨þ¢€ÊaÆÕ½dˆÚ0$³"Œ·ž—7¢Ñ>åÂ%ÈñDžöñQRQÔ3î0m¾\?¼>oÆ¡Iò¥z s\N:ÉÞ‚U"Då‹{Þò½ÝòÄj„£Æý뇉öçÆù@ÀÃ’JrÐht6Nœ\Ö‘ŠèÑ\?«v‹U¹Å8eÚ!õVŒ¥«í{˜·Oϵs0…‹q’ùã 6þ8ÀšÍ™?¡ôSSéŠ]ÿ/0`Ò_ðž‰è£w]ì›ÞÁèvåä­ø sëšôiJñçaðØ­d”5¥Ž©<|tÕrȲç#Yd@p/³ê¾ý†®ì °“‡ÿ‚ùf3ŒÏ5"Éû:(wHh8hu¾í³»Í†v}0".ûlŒ ‡;¡Á4uö)²+µÇæ¿îM½NƇ òÜFÜd„•.S=kRø[‰.xnN!ð^|5Gß²G!ÚOò|€ùL‡@ŒuÀ`öøü)§hvú)y·03¯¤Çâ+9Bô²Z’¸xË)G'@l7Ô‡]«mìL)ÞsR8á-Ø$CAÝ÷±up#1†Säå—È äšMqREM½tåù#b'Ö*«5*A‡£‹Â»œ×ü…oÒ|¼ž~»xå‰ñ߈Ì¥²Ä†Y~V´'Ñêßv×èúÕ›·Ä¿‡ÔK’ä=^e(¨üoóèˆl?d„VaÀ+lÞ# Hñ¬LÕÇ( ÏFÎÈœ”ÐANdw‹ãøÑ·œcjcá{ ¢¨„)þ€ôßÖ%:„¾};Í]–y»ˆâ€fº¾±,Æ@\¾é3ñ2ÑŽ´ÌCñEŠ,'Ù…ðJÛP]¬ÿ‚gQJ¸&)ÀÞ6‹•þà|qÍ`żbp–õ9°¢’Os (ÏO¹†òÒ~G“¤²ŒTæN´›ÕÐÅ™© é~¸Žß‹Ä[0ÞÞ¶AßdÓáÿY_‘×¥¨6‰ep‚8Üæ“rñÈe·i™ L7³$ðûÁÁ[xbÎÝnA2Â?>™gT$ÐÚ'ý;÷kWU˜×uÎ0we hÚÚ= mqÀŽß|Ìs(EW)íåVÃew¾z¼~ö”—0ꇶýÓ+uI²2åcX,Iì~b,ÈМ°‚ØÞ®ÀævÑlñf<¨§­@¹£"´PâøµPùKœ[é쎩ÔHê æ/pÇ>ÌÊÂõk)c«v'Øü¯Œ ï8¡H‡»Æa›®,o‚çJ÷‹â‚ø§×­W~=íÿVL“Ì /''LGØßêœØÑ¿‰F›³Å%ÌiÔ¨Žˆ˜¥¢Š’)B¹§>°y®ÿ”b§& {ÂsêìÕa¦v¸ nMàfOü~·ëy×;‘ÀÄN¾RK³VŸí>­RÍ£¬¹%½YTzqÙŒ®æG»‡ú¹›¢ä ω±Lvëg8_þ;Øæš“¢’t›bEŒÝQù„Â;å~îo¢ÙößHw¥Í—ðôX‘ v»«ãžKÞ†''Þ¡KÔÊ*¦4L,퀴± ûõÄO§Ò“0ë0´ë~Î9î3؉Ìdu_ñMŠ’Ò}ÍIÔ’#Üò;Z7­_Ôåo…èbNk¤O úê§Å·ŒQßûóZïr5Û}«<hVšÇª  ÷òÅ:RlçBÑÆ¶p5\¥|i®*n}ÇÅŽbªƒb\ÿ;ȈînªU²Åyä~ùCŽER£Mc.}®àÑjŽ´ûôs"„ç8au³óÐùvUœ ߊºyÖcÓ Éñ†äe2éˆWûÀÜ­ árºQ¥Qo¥Lšž­ÖXþøÄ›”Ȭ…ßÑ>8Kù ÷Ÿµ3mîBf°Áʳä` P'€#kÇͪÜK4^9”…›V=‹•®*ô·Y¤Ö«b{'°ù’Žf­îŒJ4úœDôܱG ½wã[ã[Å?ÀÀëRÈ‘¬ÿ:‚uЙ{ç‘»ÝÀn¦od÷s:Š k+9Qí#ø¡K©r"|Çó8tûŠÑ%&EÇ /?™ƒFs•“xw·&^vÉ—LHz“°¤õ£ú¤Øƒ¸9ë˜F­âˆ}ú 0²þÚƒnê•~ƒ®@p_ßrÐwa7òqØgjÔ÷fj wS? ÆQû:6šµÉT‹á銗M@ë%õ]=ãï0¸Â [ž”œÙPá‚2έŠ[pø æ¸lÑæóÿ~ÿ'hò/4R+ˆòÑÀ•·xÃÿ@i:Nÿ¢jïhà€VVĽZu³gÏ…hL8”÷e v—ïË›QWð»Z<'»x~Nãðíù[PÌÉž ,šÃDÒy.;¸çÐPÕ´Ûx×°.Š–{ŒßCÔ‘n Ò°<+Â$Ói¡‚ÂêÐ]¸d4¨Àš ú5ÑÂXÏÉüZÞiÁb_Cy zßÕø'¶žSlíQö0-n„f'cÚÔÁ®@S^ìcØ&”|áÐAç«úä:íQþ_‡ÂûB¿"‚?—V=u‹™ý _: á¡ï,]~Ôa½Q³sï1hÝo²šÙ€ZÔÅ#iˆ×œ8Xì²f”1Í-&[2<3éÿØ0•kIR”÷ÁLjÿþf¥Ïtø6f(3ÌÖÜE®ÃáãÃk¹è½ÂæÄù‡‡`?øþ£BR:¸ÑŽý^wb˜fËX…)®Œ»¸,òÀÁ.#›XÂD-iß¾Úƒ1#¡^m=gá©z>Gšð«O^LQ“Üh“$7›M£6¢Öš}Eв*[V-DïK§eGh¾È't‰Z A¸ä%jQ4NÑ‹sà7_´e’$XÐ\<+CYøÅu²¥TWɼÃúÕ‹.÷§_å)ñ‹„ËÍ(LG¿Æë'l(ò ù©›ÖZÃûcOøÁÓ¿œ¦. ÎÉ_V”“¾-ß1«-y•»ª¾¶þ³b瘙'ª¨-*uù®X8ð0uZè¼þ rÊ‘`†¦6ÍN¬î.?¥ÖPk˜zeü`Ž»H·eµµ“1×\0”ò|¥pÐP~Îe“¥’Ì÷vóQB¥`b`è) ŃO‚°ÁM–±m‚ÿ²!©l Ñ¡khü!S0¤Ò e§/;YýaQÅçÙô{à Ù›®RØãT` yg0`tLèo:\`œ‘Fg ÊŠ8¿"Êd YÒZ¹zÞgñ‹k¯µ„›àTéŽ÷@²NG­'t¦ò¿ãBñÀ|bqV¼ä¬s΀C¬ØÝ&ŠLHØÔ™Í]S˜/åú¼æª4Ž¿½QÔ)ÒŠ7¿…N;õZ“Zô¯Wik6Ȱ¨á¼??jÄžÀ#vn…#×ö*µH@c`år±o~«–,kI÷Ž&YßUqYi¨.‰ÿ²™†SL©òo€ ÷¯ØžýáEŸÉò–¿€`Cºªê/lg¸ª°÷ý…6Ã…øP%aÏò€ä1UÅ™§§‰žÌnx œz9Ö½OaZŽÝj?€›Â¹7®çØfƒÆøL1øùìÜ6àð)–œà~>ä‰ñlÌO†X•„¡ŸÁ¤µ1àC@éÛÎfeýÍx Ç6 ƒ¢qR¯å?jÕRú'ݧ™Ìä£x‰JxgNv? ‰KUì»Ð`gføKÞXDíäëEÑEÑ_+ãq*‰Mª«öt^nÿ¬*Š“OX“\tÛÙ4vi9^˜»¿—]ï°Z¡]è¶C$jÆ–N+f„iœðëæ¥oFÎÅ÷]­­ Û=CIæTš‡:‰Iµ:uîÏYpýq¯,ä1®ÛúM¼ÐA š£k•Xµ‰¸ZÇdÎíaé¦åŒ7iÓ`%ï0v(„#ÂøàöŸˆàš™ßRß˧¨Õo-"†d¦äÉÆ(B%ÛljÛ!DÚÚ?¼ïÉ£zoåêi$,"E6Em° ÿ;"HöŽBþ|a5ògú5à±-¾jaÔÝ.e€)ÇÌoƒ§èÀò-Sy؃Jsâw?ëF-ÔvKÍ5$ [Þ„SH.ÊÃÏÈ8D&¢ãW7>[’®çm_jŸ¿ÐÄAa“)‡ãVóYÖ¶õ­Ö‚»œ$Xð/ëƒíËßÜ~`ì#QÒôÄïÜ»øEO›k€ ›Îm‰Æ»øÊs‰±wˆ†ÍüÓQnA/ôüÔvì› ÝL¸ÊÏH_Ikµ ÉÒHÊ]ÞRK´0÷û{¿&+úAó_EjEãÈTŠƒÂV}+*¿ o_×í<ä(BÌïõi‹W‚@Nª3pš¼ š±6Šü«êK|<ù7{ö+Ná;\©â " dÙyêË=#¤¡YSîiþ‰ ¢}ȱ&²þY¯#0¬Ä“éON7^áV¤Z!(ÂõAD/ÞØfxŸÅ’EŒe€åÚչ?«6^>‚ï4T?ö€Ʋ͸$ÜÚ2np„­£×†ar3|íµùäŒ7Åbl™ÚÎ÷ˆíAÈ[DÐÁÊ[™.·_k·~aÛR¼8=,kòk\>"’Õ‹qÃzÛmée‰ÃèåÈùø×´#öo1¢«_(’%‡¶¯¼%•ñZ[LC¢8qåJºð¾_i5¤Hx]·M®€Ï2 #|\²[ŸÌps8RÅ~Hb½c‚ok€æö]£áò\ÜÜëÅ´a‚ªÿ ¢N:Ÿ~*Y“^YŒ"’^ÏÃ.´wñ¾ÉTE\ȶê‡có™ +Ûh0_vÌ·ˆG¸@9v9â­$¨ö¼øXu÷öT*Ãtæv@cwÈxqöÞ¬/>-b‚GTÅŽ^ÐLmo´pŸ^Õ=hBN ,¸`K¹&OgÑH!žF Ü(%Cê¶;§~+fO'^ž›àðc^€®^'Ÿ Ÿzs¾‹dà÷Åž:âBÞ¸iO£Å×Ûþê@ˆz_S#UìqI“qZàNÃ\­˜~ñ.èªíÊo±ã´Á3êøööqUOVQÈyã `7,#Y!ïC¢Ø !öYïPÿwPð›X4®.4»ƒVUCà¾Hp<ò¤ÛÒœùòý¢_Þí"¥4ö‹`“Á3‹ÖнŒYQº¬DüϺrƒƒ¿8PHcÓ…DêxýŸxj#æ f$²Á¥ûé ˜m÷YT8LâÉ زÌ(’úu–iCS1~º?‘o>Ä y SNÐ Ãužb¨æa¼â™Ž–ÌýËå»ï‡î ¹°‘‰bð‚t"“ÐC¸Š›ðR¶ ÐeÔQóo+pYW ä”¾< µ*Óa0„¿ÈVCù¾„r <ã}»`œªP^õgepÆpœ×5q‘‡…2¢Ü¿m»Éü†xÛã¢qôc+JIöû é'žLß™~Ï(YíñÎôÞÛâèØ]4‡®Mp¯|Ê”„h´‚Œ³ucÉ@–>ßx,$Hé:1Ñ<+H;­•<:â»Æ¯©ËiwA­èT~D3ÆöE2Òº¤œ|øc™>£SÈÂ'·›L]ĹqÈÕ¶ßm1™Ët­w83N™E¯þnãïÇfV„Õ˜ræ¢&žë,ÏU8ZC%ÿüX3ÌÖÕ5o`ÙÒªŠ[Ÿëæ,–¯*\ÈÌkNÁ+FY‚u&ø7ÝOƪO5?#6Uº7λ·âÎUA Ô¿ÚNÞ£ú¿Ì1Á<§&»zÔ ÔÌÚ5ŠVêÝJg7ï< æ´Øý{¥ü`ÏZ¯Ä$TŒz¢Ù‹½¾ãNsÎ nË{L[¨ÆúÖšáN(›e^Çã$,„ÉùIî=…ËÃ3œb¸Ö€×`–«“ýPÚ¨øªÙˆª iö!Ó°îÊïKŒ¥ŽwëJyÕ×t‹.,‹m#ûÀ·/ZÔ.dü%XjQÊ÷Užg iN$¸à•+ûÓ—¬g¼#›a§‘D픃ž™mì7ö Rj}úWªìsã߃îüðnëãƒCÐQq­ñÄý-’↑2¡Mj«¢ø7f€`çÉ2…üFÒ#›•÷õ(.âR¥¢ê÷þ¼›ÎÌwPÞr wR£ö“É<­²ÀÞÇÉù>–Ä——¼^ߨD͸hVŒKn”W Ã}Ø ”Kh¥:îyü›ðê—™—…¸ÈÔÍÇo”j<ã+í¬Smm…/¯2MZU]™>ï±cÙFÞîpªìX”UÙ ÿ_4œ:õžl>^—:áÔéj 5 ªͺ–~êÌMnàzö¾…ì­hôèÑÀ‰\>bÉÏÓðbȼffÉbÌAÏ;Q˘KþʺÿÅJg ’œ€¡Wµa‹÷dõÂ$õ=e[ÃB )ŽéîÙ× _ú&úrŸE¼¼ÚBÓêñ Ûm1Úò±#ÓFS3TÚî Öƒð„ì í,) Þ{Šê#¬HÓÎê†S¸(¾ðôóh<žŽÞa‹uœ{Z~ê‡÷Þµ‘ MÀù ¿ØН»ÿÓjØ=SPkƒ{Á¨vþeÁƒ›&®×)N{«9Ò=êè®~ öJ1™«¼bRÉÈÕó*b#æºÉ`ÍÑT(ÞM/v.0u¡4½ ÂçBV9éˆ\]†*q§¿i³D½ ÑBU¬UÙÀD²×>ÅËrºšdÖç ?WZÍœMòÓæ2é÷‚HÏ&yŸ ç[a`ƒÔš=…„ô­~Ãü<ÞÍW£&ïËL–¹6쟳w7åõäTµl_šãæí ›jEô°¬6­áýðÓòoï’å­dK“_ŸFÄžìaƒ®b¥~NÛ“»¿Øaö¶¸§ÙâËŽz½t«lÁi„Öí&]8·ÎÌ÷=ƒß]AÆÈ·Üö­^=ŸØŸ˜gºÔ„!?0¾ÛåÈ®<Ç\Zp’¢D^1Bà v95‹2vf\³_µ©i{?ö4^‡Å¾š®îKƒÆO]¿ŸNãþbÁ÷€==ŸºDªïE§óÁQ1À~jœ(tb4«Ca~Ã~“uçw3.ÊR{³€r%TH'KÅ6)›©»÷ñ,úXúþ}@¡è£«h†šï¹užlJþ˜Á"%Û:Ñæ—Õ·V@ ðn…NffJ%«ð?‹ñ–-&Ä×*®Q$‚àâ i€Àé7fm¼U+¥5náç+Ô?À;Œ§õ*ööáʶ†;_è¸} Ñ|mÎo5ä÷Þ2k¾œñ«Aœ~ã­p©2+|G‡ uô·pGyV_€²?¯Û¯¼ª-Žà3ç»/1"Œ¸X¶9ПhrÿÃ&'”HoôÖÂÃÄ«Œ,Òæ"œñj~WåL¼;cýZ³ òÕÒ0¬‘Š´s”õÙa¯-•âÕ Û×_–€=)vä¦qÔÇCK:ýU€ã—káÃÙJmü7JÊåœ2(Ò^ eŸR4YÍ鵤d»óº~o^soÈø¸âwlL} ׿Ü'[ïm'È)ýà;îe"Ã|fÉ›žk2¢Á΋1 M¬y×7Þí¢Ëi Û o+0/[ûm±Š¸Ê[DL²’üâ=ÒƬ ¹u¡¦D¸%׫@£•Ò§l,c”È9CÔ#ô„ñ×ât±¥>·M'ì–šþøE¬H²>ÏeÔ€áù ëFZ{¾×œØV(šÐzð¥€;,š¥~ú vžO‰Àͳô^?´Ú|²7 ¿¨›hi~TêIJkþy*¾È™9ð°$×ýy!Â☙ÄÙ$0{܉{t$víA+•*^´žÔNìé(ã²ÓN}É0§Ò±b´ @Û_»-´jÔ‚¸š¶:ˆdLù°•¬yãvÄ;ãלú³Ÿ¢`³¢hIÓâ¾€¥mb‹á9ÓDÉe|lðWl^^[ó{JaÿÝko?\þSûø)c× ŽÃÕªõæ;åÖÆ!¯´Ñ8kN“ž?Àîç2tÚ¼Ÿ¨$œ¿@?æ`é…øOhýŽAYÂzmå·Mðë”ø ÄeiS€÷ÝþÖè~^5l¥Äé¬n¥WÙîÞmÄ=“°¹£1ìU±.þÚMÛ méø!0(½È%ÿj'[k `x$ ÷gHè1läñ ƒ`‘Nš_)û`¯ñœŠ¡ö=ý±Ë"”ÂRµ›õ‘ß [ýÉL…Ù§q?ç±´µÛª¸PøF%KmùÐFѦõÙ\‚´0wÓÓ¨ÄóÔx Ì‹q;!™1ÆZ/u7p—J™¶$Ÿ’•£¼,©¸¾ÏÞßX]ýù°ÐH8›Pmż!+ˆÊˆJUÄÞ±.c´6ÒöšGà¹ÑQ™öQp ´[š"ãc”€NyU»ÄV£z,ë„'¶’âäÊqEMõ¢‡þÈõöwq…,uj ­c=Î0ꌈ-!M¬!$Ø„ßþxzå<~ÔÿôÝÔÿ¿üþ7ßÿ1èé°3è³°è1°s0q22±þÁˆÕ€EϘÃÈ˜ÓØ˜ã8Çÿúý3 +ó¼ÿcdø[ÿãÿ¾ÿû?òû·÷#•dVùÀúóÃçÉ®‰]4/Tc¢EݼGM¼?¡ÑüRšƒSÉ7mšgæÊ¸ìXÿsÏÿç5ë¾óíÿýÛ³÷øŸçFo˜qÖáKÖ;Ô?ü.ñw:ÿìx¿Úz,ØØï¦ËÚŸÏk,y±â¥t—eß©<Àÿãþ:ð0áÍÿÇÁ:üˆ>üŸSW8]t2`èd²ŽÛ“Pãt¼Õo¬ÃéÃö5âÃ{î3…(»&¶=ÿñ PÛÙÒ[Ö:|>ÜMÊY©˜öÜI³rÌÑLýÖy;dª•AñyDßC³Ü[§}_Ý» ÚlˆômŽ^GÖÁèøO`lð`cß]òvEÙö5n¹µ­þx1ƒ sî­¯‰²fÎÆqëðWúðzvQ™õ õQ­+Ø£»¥èν««œV¶~Ï#3úNY}5ŠåFœr¦§›’Ô{nЧœù JОc©jÔ6>¿ê|VÏSR+BÀ¿ÈVU‚˼ղ¥eóHÀÚgâžYÿÜs°uÛ°d 93ÇšÖé:n³f627Û¿ÊY0%ûgDß[ø0š/HÙ¬¥6ÍeâÌ12þ+žyÜɈË6Ëã§È‰¡d†§A©þªX¢?-Û%HraEåIÓl+ ñµêïog5‚í×úö^oÚ[Fêóž¥;ôâù]x<æÏ´u¸Q°ÜFcÿùPȶqnb›ý±g,ŒpÁg -cã2Ht4EÏ·‚“¬Ð}=Ýà Ç`:ñó‹íò’ÚÀ~2õõx¼<Ò9ÝxrœÁÁÔÓ£¨ì[Õá+ÏdÇ8ºæ2kÐÊ€Ú ®gùÎBªî¡pãŸO| NZ8>1U*…ÖeòO´‰µ&;Þl+×ݲvãÙHtúÎ:)"ƒŠ«Íä¸D·žTº·h£¿ü‡¢~hg¼RxYl;‚‘ŒO«‚´UÒì$Óßè2aÜhÝ5Ÿz¦9Ó©ÎÛ;x}-çÛ•”5o´ºvɈÇ'0¨ù¨Fb‘œ81´šìyßêsä,¾ŒîÆðRÓ*A¼Àâ}uSÏäD š0)9¹­ÊzÉÓ6 ˜?æ¥dÒi΀Ôfý[Š¡Q*…Ô¡¿êN«ÞƒLç°kb0Q“thÑ„ºi¹áÐà÷Lt8·#þÙö5P²XÜy¾3õžÔ@-lj›£méëCFàðÆ5– áéÚQ¤Q×"ˆ!8ØJx"±;&WxÒ^‡ ËÍuR eÏl9ŒpçãVÐKªÓнó¼m’–ŸƒJ8¦Ç ?aǤ…L…Þs™½\EâýÉ)úÍ+^ ü9Qà³ÝzÛ §QëäÝ–¡ó鎩þ›]-{ ˜K‘ÜOœ)ŒÕ3©;ÈæÑ¾÷wøö®Àá1}/šäø 9$oDàj‚VclóÌ×*>¾üíŸ.³o†bŽs¿\~Pù=Ö‘8ÊHhìæùQ4úÏdíPC쨔‚U°O—Ó>n0CÝþš¡#r¾TÖ»ÛKp&Lʉ]‰ß‰ÐJµÁ0¿Zn-SVŽÆ÷Î(#·ám*].ÍÓòMhQ_Þ~Ð ˜å%¶ñÇ[ß< ð&Þù`?þnãºôŒÀu`˜Gó«!«bY¹öî‰ÞYìØÛ2“Ðu¨‡ž»Z‹•ùÓ7ò *÷09eîÜan¼z€ñ™oÅäJìŸÎÀø£sóóÆ!¾Û¶*N*áêÑG["‘ƪqú2zÏøÑ¯!^^˜LS(|7ˆ£ŠGÃÑ>zp÷•^[©¼~s{u¶ÓÑSÒ¢mˆÇÂuPE5ÔŒµ]ÙæðÁ© d¸rÖ71Ž"W.!â:ÅDì…ÊføüS®y¼þ8ñ´è&%Zš ­âàöÑAyí¡r£P«?·òžå4×ÊÙd@˜'~-ËðÄAQÒ¦ïèX8½l›B팘dnDæ2k™Ó6 žT¦ hªÿ®¥þ#Ú2ŸÝMˆ•~l[! ròÆ—íZËŸgÖ—”@EN'Wü]4‘À•>¥ÐUçÜÚOŠK„Á/g¤¼C½õˆ_AxEÅï¼=^4€Ê»Ž;²€•XýQ«ÊÀ0ezð9&ÅRR |o/ƒ°Ñl·Ù@ÐJ»W"3„k)T@àÅxñùa4¯X¯2ëpŒ[ÛÈÅEä.Ó"{‘™¨°cú§º,€+#¸HÉ—Dí‡hêÁðÄåN\zë’4BúŸÎÆ¡ÕáoQ¶mz•> 'iä,*™x•hâwoa ¶¡Ë´%9.šÛôdÒf_ŠGÞÀ<†§ƒˆ>xNÒ¼»žÜ²PéÒØDißFxOCñ¬G\äs¢~f$Sg~ p¾äúJ=ŽCYÖHîÖF¹cÉ/‡á þ–¾b¨­2­áYE™¡‹“1Âsorè=ìòU¼ â#4!Ã8ý%ÑOTjNî·_ ôo"ÑìFmÍ  ÎA ®s9Ô±V!'3ÂÑ\” K¸ÞÑR±cA&ȵìÁùz ’ØA^BˆÝŠïY¼GTE³ ËGÌB‚ÜAÛ–Öó}ϾGFפå\×Ë7Ñè’æ.Zèr`ÉïTg¹‹®Ãµ.|âßñ Y!‹‘•}ž)‰åëeçNF’²É-Œ…P«FÏWþ¯ç[IMë„‘`WÑþrX-'¸Õn•«ðì²ñ+ZgýoëŒø€ßmT½Wìú‚&ÑÜ"!O„ÑyåÔ ›e5wìnm_&>Œ/ÕBÌM`Š™V™OË~y!¬ºC27úW¿hmë\Šv¯ 6g2Iog1"ϱ¼ä[°fHÂ¥ ¾]ÿ3ys=¨ˆ(+(ˆ$¯UÉ4Ƙ û{ó–©.Ïgåb‚]Wkyú«ÞVÞ¡¹€“oØLO.å—f¦ <úx÷´cE ŒFK¢÷ã ®w¹Zj¢'vòê¡Óð0$‚9žœÙP¡‚²ìEŠgpøJæ¦g > ÃÌ=(“û•EÕÁ¼°qøÜØiÖ/)¥iD"rVÊ-)}©®p«\o0/¸Ú †ÃV4ãIÉà e´ª¾¨¿ï]°4ûÝi6F›s܉I¼.k°»A^7Žkt ž©˜D¿_Tضvš¹‚A·˜Œ8#ã²ô Œ•¬-ÉðO$K¹"€º´œùÅä&$1ýá”hÁ ­?áŸU×ãÃo+¬4kÄfxggŽI¹ž†êßÏèâö2 >X*º./ÄFýa‡çp:ª¡ß žk!T$œ!€ܱó³=ßÒâ X5¤×gÐ…áC™]½ƒ!͵ î"üÄõÕŒKä{”´`4é6^F”ðVK1R'JU#,¯$°jHmæDƒçêT€‚L›Ä±Ip$¨Ež+.I!|01ˆ«Áu$±Òßg‚ë)—© sÍ]Iô¨>™l»Q‘‘üØU[íˆRC0¾5SÍ[ÈÔŽ š-Oªú¸´Nɰ¤wãŸ,¼\îMñ3-GHýŸÔ™³²«Ô¢J˜ÃwMjOûc)Q¯Fw˜K"f£`W-Ñ!æ0Í+UŠ-ût¯—Ü}ÆÒ”^e8HqšXž üà?Ú Ý…Éùµõ»µÓÖP2ð¸ú“FtvfÜgY–ûCm¾YPú»O Çö{|`là$xÈCèŠÃy6b[‰@¡º1º}pÝ*’‰DuÂ×ù¡ƒHçqŸC¦ó·3‹BP(’vkÇØ@AÕß™&F°\<[¯8‰ëñÞ]g?96ôhT(‹[r&\šLïKv#Õ<ÁÃôœŒ·5ÿM™>†çpúÚª%Ö÷SÓv27]dh×ÖÉâFúW­P]iqz'Á²B²Û’H`ÜPý*e<¿š¨¥Yã`¦Á©y°?~Ê÷î8XQÙ++!âPXž[öØœ%DBÿÀ1w áÀ×…›tn¸%/#êáÝñŒØF)²½Óm8`Aã½.frQvSΙk0ôižƒƒ)qPh9ì>,±×šùŽl¹¾À ·kû»[¬µùìÃeš‹‚ü[¤`™|ƉüOñ•ȉNM¤¶’/WTm–+ƒ³CDUäÁ“ T9JC]dó¿˜#Æø7uí ‚Hç›.Jªø¥ÄdËH7o[¹rêæR" ¾ÈýAwgßæeò‹°§¨°BüëHš®¥E‡­áp¬û£ÂôO,v{!Ün‰jœ«÷—‚9ðµççN ÖDZ‚‡ðÓ!/ï/EˆŒ†&Ö k7Á‡jY4$ÞL:eUB( ²é.7¾Ęètÿܽ¡!LÿB —)Žõ•.8E,õgrçÇ%ŠÊ4OovZP%9:«¦ê¡~V’Œø\H"÷¤xDDëò!®Ùç3*¶Ø8öŸ(Ñt Í'\T `Á;È·5e{uç ºf³äìsŸlÅî¾8;î§æZqfÄ‘µÖ)W3̉ÕlPS ó!?e|ÎÛ¿3±îÇøDd”®¥ùéH˜®ùb‰ÏSFäÒDj;GòŠsàÓp´‹[Ñ#gSø6†f³f–ä‚} Žg2­1&ÚšÝM*·’ðÏg€ívcÊù-}u‘Z':ˆ§VÀž{ „zžÂ6ßîŽîWBžÌÓ%!i.-l‘X÷âò¹Jâw@V·HD';½ZÚ…*Ó™ –8î“v6ë &ª Ð²”}‹£¥–›3}€iÚ¥N“ ™jœ$ñ{ ËY`‘‡—VOÂ¬ÛØ%cß ”•ÍsbQEñ@©XƒåiÒþƒW˜.¶Zcñž’Ç Dó,¡bÒä—ÝX$ŽÔ¦+]ÈBÑ1|›úú è #­à‡ÂÜmÅGßJ–|nÎ €G\msСÈ]¡Cl»ÇQ"ŸPúó+³¶x‘÷h2ÿ¸OS‡cCxÕT¹%_ëúagL8>Ý1ëÞI4|¨ý´ºÓ_a³|UaJ†¶äD\>ʬ |0hf)6>uI ² iTéî\~ï¤='¼³|ÇuØNøR!ºö¹œìØnÏl(’‚¯h†"+iÏ.ÚYÃóÆÊ ¸Œ®ý‰ØÞÐÅ‹9¹ÇW‰3¼ú¶¶yµuOX€-ZÊGv•^vž¬Ã8=iåí533ö&Æ2_°¼[ñ/:\è‚Ýfªk·#Ž|{"¨¼Íd¢¸Òx]ö“3¹0ÃínjR¥îÑü’»\† ·ÁvÌ¥M•kòG ´Ð¡véçÂR¾Ÿät&Ju¢ÀýXybs´ˆsfTÅæ?.š³N²Ë'·þ2pk¯'%ÞGä†Í¾4näÌ,\Åz\–ƒŽk}fóñ`VJbÿ‚aB|ÔXOæÅÙT)ïÛ× ϑ빿”)&QŦ¶œxßÍw ×IO=Φ\3D> F&æcÃz]ï³3¿pÕkÍzü Ô€^Y2Uf—!#YÕ(²hâjM÷}úÖÚ¢t$Wi(¦C ù[‚ƒÕ´A»Œþ £Ìå?ÚÅ;‹ÅH<væ—Öìœìbö¤®¿g$¿® f'ýL7[0 0ñmB~^XZÙu½ÅÂpÅXxդϕËïÝ~–ÂSÐ2еaÅ­ˆ\É-ùƒN=ãì/À)ÿ¾§ÊŽF'ðM˜ÕòÞ ºâøÍ7Xng.ÑžãïÍfÎtë‚ÓM¥¹I%¶T¯ ¼¿±š²?¶kO8óû׫CÜX‚‰¯€„AôÛuvödᎈXÓ&¤-ÁE;^‡ÏôtÔôãhA¨ÐCà taMÍûþy†w€…ü¯E™™>ï#£ŸÄ-ë–ÝBC’=˜¼à­b·u>cæ6¶`àëIý¶Ù­ÂÂ=ÜàÓœ] o·]ä}ú{ßïNö(ݘ¥öFܪ@–Žm„]Ô6Ö;ñwè"Nùs[Dõ«ÿÉV¡xr&CŸC}K@þÿ\¼f`=[7¾áÀ%ýQ¤½˜¹ef'»_cârϬ–Æå“Bc¥Mé@Ä÷µÕ·-!wÞ⦾˜€¸;ëi@©T}Ê'EÂò5ëó¡0ËF8$áŽßÜcïûƒcÖ#åÑÊ*çØ°Óí¿jËÑ&þ‰I²ôÖŒ-¢tÉ“·ðei“!µaO€½Çwõ ‡‘iýÆ;è¯èxvÆFk¥+8f:%“Á¹þÙ­¨»d¹Å{Ž7<ß9x¦Ê‰¶lå G¶Œl…¥?HøPµ:”Ø^D3Á+Á¾jàXŸƒ®¦ø#`V”4üúÕËõÚ„®¥[M5wäÙçÑý}”?sq­°®m­Ýo p<]ði—]"À÷É‘2›Úä±$Š.õzò¯*fú[²ÁÞ#ÍêB®VO îùädDµ1 ‡ôÚÊxR,=·Ä}£PSäé–›ŽècÉŽk_qggê¯L´ c൫ˆÖPÙ<©kÝFˆ5Ÿ€ÇiþvWl7Ïp覩X·¿*–wŒjÍz qå‡ÍÑÛ¼V]$X÷,‚¹ÛméO;é¡XK¦·ø¢mV~u'{ÞV(‰-›’¹¸9óD˜`pP ÅÎú¬¶°Ɔ„~Y±Â’Ù)P­Žç)ψäãs2¬ÈmÁ«¿·÷xóÍ“k¹ÎÞÝÛTRL! ýŽ,6¯òã*Xȯ0·X3­ô¯3À×à¦cnJÝÕk£õm4tX+)[Þü‡×9y¨çâ‘DœÔ.ß.[ ‰W}Ï ¤ ÆÊòƘÁ-دÎÑ—åX6Ö ØÚÍþ#ŸæÔµ³È‘@Þ/ÚûÛÆdmZ_s­D¾À€ ÎýîÆº¸9 ô¤˜„Èæµù:%fpý¼âñOëj£˜:MÊ*'ÌFͧ‚Pý»N©³AÆR©Æ§"³‘ýµ `üj—›2 øÀÞjËâWN‰õÝLu•2¹ðDèhî(œŽE+HÎ/Ú²á…Ä·Û£y—_WÞ£'™;¡gåÆ!vêHŠ=åVÒ\À›Y^´åò?†Ö|rÓbaúb)ÓÙØ»¿OcÎ ™wÝl¶‘‡W¶ñÜšX.dzŸÑ!<²ÑÆÉþ ù E·¶÷C8Å4‚fò7q»>MmÀ±Š²2׿ÆnJ¤°í@þ>N±3à{A­åûñ€×œÐ®3à-æ,ÒÍç5¬røš²×^y÷˜ {4Š”‘ñ°+3ƺã¨VÂ8Hã­Xc…Qr\¨gR^þO"öAÈÀÐ>ß~0ïA³»'ÛÇëÀqlØfF¿&åhŽÂÿ®¹âƒ’®Ûœã/$¦˜+ýÚAÜ x5í‘Y}1µÙ¥ÆÒ¨¥†*—û»é÷/¸¸ÊÝÄĤÜV‘ÄJìŒÊ '-4ŽxxàIŽ[Šèù fºãƽÒ÷ì6ÆyÓGÉ€{ªŸ€kö¨‘Úk¤oPÕºãÝ›î3³‰‹ñ›™tÜqmDÇx‡ÁöN_ÛŽ×ÙY™ÀEHºù.Ö’eù>Ûv¢„)H·¸›_¾™„ž:¯ojö"}[„H1ƇáÎYÄ%&UByŸ<,Ö\dý»´ˆh»”Q¢PÐqøàO&Ñã™Q]xàâÜk©sp胗ÝBNÍZ'ºä¾Ë„ ¬99ìµfu-Þ^õÖU9 7oªÕOn±ÇùÄcÁʼOð7ä=³†‚Ýð(#Lâ"Zâ…_pû™hGí>ˆPû¬ j-oÉ4bù¦É8Ÿ[>‹îÇ[@#½æn1³œq^*îÊÔ„ÜM|2θê”W?4üÖ0߈a&Izu榴`¬cÆõó^4ŸÝúq`3œÜÁ©k[ÑøWÂ$[ <»Hêå®”p§¬aÏiAž÷Ì$JyVÂ>Ž T_ÇÎà«¢]×dyœ?«{²Ž÷-zl.÷Ú^­b=Õ¹G¾¥¸tråäìr§×ÎMȤ{{ß÷'[ñøËÇ]‘\ ³ !‚Èe6Æ¡¬ŸŸ ¦gøPd˜i•×5?M¯.KÚq«Ü˶rÆý8Á˜ÜÐl»Ádt›Õø†Êö4EÍÜ —Ü•ø^Q¶ôºÇûðgxh‡Ùlä; “‡¬e D]mÁt¬]8‘g€}#áVh,åÍTže±û‚úf8–m[-˜9A!jÆÆöLJ˜Yñ«¶7ZA"Ûe›È¶z9锈\î§Ø‚†æ`ø/rb¬1:Êý\òS™Nø³oæ²Pìöûd:nt ¦m¼<ªµÕk·ÃP©ƒé’µ{ÀĺAc^rM¢‘Еä êƒROOŽ2?ËàÂû¡ ]QøzÎhŒn÷" d ÎÇæÜrè.&ø½ýž ˜¤•QO,Z>CJa¿œÆ§kh3XõÂþj&çK;lšÑ„×+…Q*W‹2`„è‹€ÛÜûõt©7Û¬føt_x ´i*M54—žûÌû×PmØ/\¬rYî¾Ú_y àacTÂû±`,lì÷ pÛš-V‘ál+0_tœ±@ »Lˆ$ m96fJ1¿_b˜,„eØHòJæÛ„éŠÑ`ÙºzD/1þÞ"#²“ïšZl8Ycô¬eŠ 4+«ìÝÝ0|2lÿôÇVc¶U:˜òŸd|èlýê­dÑú@ý)|: x‹¬pGw ΕñÛ:tà4õL+^Ù—%£5 jœÈŠuÍ.¹°Zƒ-f¡Dƒ-l`µp&:u&1‡Æç€æ¸ »/ÉŸKí°¯¿~Þªå@+!ôÀÖÿú[Ýõo!“²ZÓ´®Ì–K Èuus5™FîT@B¦{ÿú}¼>6öq2å* çĦX@ñìõ3…$ŽXlQ$p?Íf­ŽCnðXæGq;B9Â.IbŽX¦Õ4ëN;€@Œ—Øé.¤¸»)Ž–´Òxè8“°Yêoã À¹#îD6Ä•½f®+9Ž¿xÙÏ)hÂblÚ†höN“@¾LOl•òŠ‹veg:÷6]~¿]»ï|-žw14»[u€OyãÓð"Öå&úÎäzý×G³µUšKîó¸Ržè‡„ïû}@ºóB>’á·4SážõÚZN§Š-ù4$eGqƒ™;£È¶ø®™<øÝÁgCvG:¾`©Àˆ*~9$Ü3”€·\ÆÁ©‰ñ|¹÷XïZjFû†2Lºx†›¢!õÉä¯^ÇŒ†óÉ¿±Ùz²ÿqÄòW-%vÎ/™"-g øŽ”à=<,GÚì­7 Ñ(⿟J?€^¥´þº|—;k«‰-¶‡N þæs\J²pÿ—²ÂŒ¬¿~æTš¿ÑÆc±»æ¸ ÷U»ë¦4c3 ü¸-}¢ÛÍëûÎÚuÅF«&Šéb½ï"Z0]ÏèröLjÏßzØXÇk…W2S£úÈ‹­éXµõÅü˜iŸÑÊ×ì¥Õ>Ó^æFð:U×)t„ÍœÌYÐêŒñŽg±¥¨¬ŽÀ1‚AGܱ±:¯_Ó^yó-:ÍÓ+ÎÞÛÜiáç¶êz-3,‰2Ubž…²F ‰ja?”°Z[šmŸ˜‚`òïÆ>ÎÚÌYÒ¤)ã_?:Ðjùbt¸ÕÄȬ­ôÁdì²`…8‡ßµÑЕëzíÐ41WØ$@1}(7„ÔV%L‰úE5ñQ O‰úTÆ¥Žµ*åy“mFè7c}:vÔçÐp>»7—9MÖsæZµu…çø¦Å?Ýtk!¶ÜÍtI «T‘Y@'ÇçÖ›f'û¥’øYg7ô‘­Ï š6â\ ‚Ï…÷oéŽÖ»·Ú?ò3ä5ŽW†Ú—ùaz©aôy±kþšãéÇ!‹ÜÒJ:Z8‡Ë̇ÑñW«'Ÿõ—Œ×­²=‡¶<þ C÷e§­ÑšaѪQÆU“ŽãÉ%yûëÍtoùô§H,Š*& z ¯š¬RÍã¢g=‡QÙîœD»T¥D¸)r ž-Ób¡ÙS“¢Yí;0ÖhlÕ‚Yü饔[ß1]âÌM¦˜t1ïPMõ¹º=Jz{ q®bÁlï[t´ªcc–cøiø’‘¦ A5\9?5›†R´?iÈSM+uR៻^v¨MIÃí ÆRifqé•…ñù1Ø™ËDÞ ÐœøåÍ`f½.KkaGu/kÔqþ ÅÙld§™RRþTÆþÒQon7ðÞî¼¶ËŠÚßÚm´”}ÇËõ÷·Ò®S<ÿ ½)Ô´„Ùâùgçϧ½­ý¨i¿ÿGYÿ¿ûýoòX9X Y8Ùõ˜õ9 8Ùõ 9XY 8ŒXYô 8™X ˜ Ø8 þ¿âÿ°±²±ÿWþ+óÿýû¿ÿG~ÿ‰ÿÇ—~Z›‰vŽÞ¶öÏšÇçô>¸ó›#ñc±»¨¢”2Zx,f,,ÙŸçÅgï×ó?ç@úÏÆÛÆcçŸó—¬?Ñ›Zö|¨:r—Þ/ϯ7Þ<ÿ§üŸ·ç§‰ËÎ?Î÷xŒ¯ÌúߌÆ×U+j“öà׿øIÍ«€î.ð?݇_•Ÿ† «Ë¾}_ýÃfÞ,Cò#Ó)¯þƒªK»åv·ƒãؾu&³Vã²k=£³ì÷:ÀQXÝ)ö/©1»:oë«ì7×ò©nÞ úÚîì!|SÙŽ€)±oXŒŠ»EÔ™Xê— sŠ\wÖ³»ÆÈ …iÖ°õó[Zζ®üž?éö¯OmO;7ª†ð-x¨ÿ; (H²d·º NC®ôÕûêà5€ÅhÖ°Ÿ»vמB¸ñ‹Q¸eÚ_V‡m¾úqo¸íšD¹·5üº`wѵÎ;ȃ˜Ü[íÆ ÏtÃÆ?œö«çÔ€æ-’oþÒ\†á&gå>F«1ü¯OâÊ4ÒªY97ššT&ý,ø&`¸‡8ýEµ†¬y2þ"JÚç=Bœ*=W)û©»†ô²™UÇZÓT‹ß-óßîÓ‹ , ^¸h4¿à ‹ ëF·ñо½Ã›ò¢ò ô§@š‚U‰/ÒQgÅ÷@Ñ=Ÿ9ÌœÇt #Ðß0ìB ž‘éEhͼ Í Ä /úª)‘³’±‡iÎõ^_!{ùìZ60ÿÄ£ö½–ÝHñkÖÖW25ŸPaßðb·§*ÁÄÜ»$iÐpùé ãùfg[v-˜»ãûÛ¡žxü ¼=þ}¹Þ˜PÇE$&GïÍ ðõayˆþG €iC ŒÈ4vNœIûÖ¤~âB»‹°{‚¨œ^^“=1øn>Nt§È]ê²sžiò>5ðךC§á³‹cá@&N“ƒÔ©g2ÎwÄß}¸¡[™ÞÃÞçt%Ö“'‘ýW"PÖCè3Ô¼¿øf%~W·ß¡_ÖÎÌwÉÚ\ܤ§j—‰k8«XÄ„ŒhÞvËÑ`¥Y–_뤜CŽˆîìÄüÿ” Ô2ŒÍK‰‘Ú·Úe*oõ.D1œªõÿk ºa·N[ÛT¼EP[ÛúÒ~º§îþ-50‚B.2 Iâæ[Àª¢)»i¯Fe-¨ZƒÈל¦Œˆá,¿g)5¶ˆ•%.;J0‹¼®g=4°3Ä €ü"¨PôFvèÌ”ºÊ ’ÙKÂC8²Úó)TÉ–*+ pª¸I'2&ñ”Žêd¹OŒÏì5©ýw:Z`ë¼Þõíµ†&\¡+;GX àÌ:dt쇞+®(jRÏ)ÊL&¾ ˆ=Á…¶› ü$óôãÖ2Ãp£ÆŽÕyŽG…†$çÎ^´qËØ]WF¹˜˜»‰p8ùÈ *Ì­hpdYš¯¤DC¥È yt»‰*ìDü+²ÓQ0w½h¶x ^èELÖ´uWt:÷(2cj^f4ðoKWÛõÉVuq„`š–"´òIý-Îûú%÷  ¶n/Ï{–×®ôêç†ÀÒŸÕ°ˆû÷B=óP±Wv)ÕbM(Ìàh›ÜÔîH Xx•oZF1Ý ,’FòÊ–SµB@Ü,•DÌ”LÊõ½jø"1†ÿ¿#ýøwBPcópÇK`ÇU†¶îUÃm$lÚ7&ïuóaqÛ±¿(d^60 Rñ¯=¶ø¾)@¦·¹þP)¼ i¬Æê(}Bá]WþgÙp§Fºy÷EɤÙóè 5]kÑ‹úwRÎe@ù¿1‚.eÆu…béU&ÙwÝ—Zžds}nŒ'è¾ß)‡¿-œÖ–ÿ„0 {ðOƒ¯\Ìk ‹H‚>ü‘غšê/îón.âÚ±ÄD šåÍ¿¶ëCù°'ËùíÀ,Ðõ{W¼vv0zÂeCy÷'ï ËšîJªï|ÿ ½ÏžpYÓý’"àGgox›â‡ÊÝ‹ß0=mï­û¢‰àIÌuce|ÚÍ‘ÂZYxn³Íã^—ÙJš‘0Õ{âÌÇ»ŒÖE‘ùàÛŠ ÜfkwL˜[!F Q†P\}M?;kuÕ±}”Î,h0ýÖØR3+›ðækî}ûk( nÎjÑHw}»S ß9Aûø‚mïnÚ’ñcôŧú~×$7ï¼ÙÕmñ–’c*¡èsTÔõ2,eÄ?n*z/i#À³&.&ãk ÚÛ|¤ÚäÒ:ˆ —“>¥Æ`ì:ÔRï­_0~iœÝ÷‚(æaæ±¹n,ÅÛw*xŒ‘€ ÜG¥y‹)ɵÍ"øÀõqÍe,Å燞R%;Ï2np·£ñ‰®5¦[‚ÀñGc¾¬þþwZjüì<6Ô¢èõ²¸4.¼ØÇׯ£ìQÒ‰U m.Ó®Æsù4àY9p®êÿÔ[Z̸̿üJÁ_‡ñ­IhC¤ÀÎÀ¦«VÔ¬*iD>1­n5¤¨öæBÀ¸îi{¾°Ð”bèf¿†‚NSÙOY®÷bãΈ&D('1ÈÃ?,~:økÍÉ×Fû´z_#pY–-kýSÿKçžµ¾B·¯”x-Ñ!»²ñOH‡=Œñ÷—æÊ䪈½."«jœK„ˊ»”h¹ LûþÏ¿¢Ô‘È;PLd'ó…*=[„‰Œö˜›AæÜÙ €û¢áÜ¥O™‰ïªî#{V¼Â7à£M”zÞwnþ}>ò6‚S-¡r¿DÓZ6Ô3$¬!òÚf;ËhéJƒ6L5rbt7—C²MB•r5:õXw9€ ¡»>³†ðc'O!8òùò\=Bv§5Ä­÷QB•tŒ%~ã3h–%òâ1§¬!—?düZЩàE¡~Êë—÷òáÿ‰T+•ÏÄøh)tQhˆ1ù”3£¦XDSâ—ºCU$~ ˽-f< ^®Ô‘æQ2Íg´ao5Xz5§Œ”Nqj6ðo´ ½'ÿ.ˆ¬MøçŠañ<~cÏOÈuT"õÿ -ÈÉ 6ªØÀ:(˜³D…å»ÃŠ€ÑÅ4Ó…¤†Pðøž??78˜ !B6z÷í/Š ‰X|µ‚ݾPU˜Í¿¬„mÊÐÆ}ݲ\-”%󵶃”)Aæ*HıЇS ¼¦ç`ZÔÂÄŒÑ e¥›ŸU[É* -RA†ºxÒÆUè‹ø7^PíèÖ&yvx‡¨ðß â]ËÀfJ±³=1‰N³ÕQ(Gù³ Ò>»ÁOæÍÁ\£ÎÞ+Hm%bx9ÜâÄW:CÈ:ÏUSbF~Âøˆh3vx‡qË¥îPÊû+© ¦6œ=I? È"Û•þ@Éjø1iCwNïô3êêPÍ ÆöVä@W'.Ôº2g4[7è7n©a*/Úέ—«l‘;«Þ÷±™Òcº±ˆãÑÎÌ º®D’‘ÒBgX×=¥½¼Ý‘=®Í]ò`F|CvéRÑÔ7á.i„š"¥¬•ü?òJ•ÉŸñ)ü &U;MyU+ä¾ã~ Y0ýÑHÝ•&Y4S‰ž@¹‡#Éàz&ÿ³{A½Ï‹•ö§û òï”GäP½›ICq¡Úë§|§Ç]?Í/)€èÑ»$…þ%ÀØïÎÝî»dAزno„C—ÖÑÝZt¡VÚáב±Úï [D]Ã=¢i†EÆcÌ„)mDFA·×°>l§9_±ýìçW"3Õ[dôî×ü!žÃYD‰Ç­§ ¬!^ð¨œ:añ;ÕÚZˆAeÉõ# GÞ„†Ñ3Ù¬Þ7u ŒiáãS>[Ôô¹¾O*†ðj _t)IbS<Ôw%dS€ƒ[‹ˆ Îân»gß—¶ß0!öÄ«QćJY»ûá*¥Í-ƒ~]s>¤Ît‰°Û†«ù±ÐRTRõÐÈO˜¢OoK—ãQú•mr;®«ž*Mh=ϬŒ!ÅÙÕ¯äί Ü#ŒÊQƒ# Wü²1÷”ÊNÉÑ«µñ÷| îp»8 Ó]fÞé.â {\Ù¥'¤fìbp½Â01|6kKç‹1%(WDÆ®#2YÚÄè‰J®ïú7ÈCŒ°fþHðypjP1Øý1ÆŽ&‚ô¶}$ù±X ™’(>P\8ŒÇƒ¨Q‚™ÂˆRFÝ^h”oìeø<«ßðJ9Š´t„o#¤É’†ï)ÆÇŒMì>3Àõ×õ‰!ö¯ ­6ljK‘ ¾ÏÜ<•똘 Zg UÙö|ïòPOsI§£i¨«™Á1аˆÜH±Îb¨ÿŽðfXtÓéf‚#ÞBgÀ ‘ !ɳßڙݥgnZ,­J MY®‚ãûÐáÒEE[}¨N>ÿ 6)1¬ò—-ß³ã²ïÜD¹¦©QL‰,â.p’'ïÏÊ̆¤„VàÛà§]oö¯vÎ4•ƾiz&­´A;I³‹…út ðe/Ÿ:t¢Šw—»?˜ ;À—E¯[êBÏŽQ#…ìÙôÍËf=åRLºö}è Hmºi UÊá;ôí®ró65ñ¬3.G>ãrØcßâZzW§ÂIr¤ª šZ—äA–OxÏÁ±Ï|´ûÈËJ¢t$g¶¶9ûà1ÏÆ| µ"ü}tâ1)¥àtØ«èûKçt:ùrd‰#½R-³Ny#¾$aærñ»¥ÍWKuÈBÑŒ-IxË%«ˆ…h\yÌn(êÚáôÄñtîÖ?w4üå9èo‰à¢$‘ÔÉ£Äc #ü>\£”¨ cÎÞiŸýJÈÑÙW w°âî$@c­ÿÒ‚FßiAN´‹ŒiAðÿF ª%<1ú:ò}㟴 £ß&âçÜÖe{…TW®f6x"ó^Eœ1£ì¸7õwæ fBS2¿ÚŠ‚Îÿ%-È+pνӂêÏÿäJüN^ãý!ïDæê2¦,A¼ +Q>= dOæ,}²¾¨{)¸2½pBŽ-K`ޫĵŠÑæÂW³&5F¹Rp¸¥Œ)¬oÎîzé| ¦®gÒ°¶F»°<ïy Ö­.Úa©eSǦWg?5Ʀ¸ÙÉH G9œün/ûV0,ÿ‰ÆSË÷Vß?YAæö@VÐÓ"£ÿÝÿŒÔøƒpëvnHx&"ŠÝ™æãÁn‰½KŠ ‰1s5™WÇÏ´ˆVl]á±tjÙü‰è”j#u›‚kuüæ‰Vж 3• Ü|ÖOðÿ[F¼‚=ÉåÏ3èIòmæª,¼æ·Rªã˜¡”_LR*v#ÐöAYµ8&ü;)¨ÎúŸ¤ Â‡‹; #)jyú\Ø|6ù¥ƒë«N’Êãö_R0©ÀŒÿ0±­0 “‹æw¢¡7ëªÜMØÑÜÀ9ôì~ƒFlB¸zõÈc‡ë‰Jf¡\4“v¥áñ×M•½„O‘‡9Ç HDq™²K]{“>ŸEsš=¿ÏþM%ýíËLî×/HçÜšQ÷ÒÕ çlÔ÷ü;²…â—4BšyFù“[ CQW7–ÔŠÝÈ_ÍàBaoRd,:"FÊÁå.&‰Š= ‘Š{,T¼÷ΙÑj¬I=›ƒ2#r û€vuxmºÍüVx¼·¡³º$' $ô|`®'Úçb&oWæ¶WÀ®´Ûk_ý“dJþ¬ cî÷öb‰øV“Ÿ{ÿ„ 8ÿä[fïwÈ1Eå-¾‚`’ušgúﬠ}MÇ"Zf–ÕXDÉÒtðÖÿ`¥g¨M¡+ n-KªxMèßßÞL¾Üaÿ“ôsM^å?XAmʳ1û°Ìû(bS³ÅڣĜcG¿ÌÞÊç|ò‰ŠÔÚ%î÷I¬]ž1§¨ÀçÕÍÆœ ‰ÓMˆ\#¾ÀYAYùç5YA1ÒŸ=&¢FÅp.ñÖ³™h~j¿Õ“HK{Ÿ + LØ«¯è;ý,k÷\¯q*“_¯1-2Þ¿>5 iå…¹b_šßäÁÀBâQ/¶B2þÒ6E¡C€•ÕE‚Ý¥°Ÿô†µ}öçY°Ö|É2t5d‡ºí7í˜Z™@”‰ä:¤¸!dÎ ]ùò³?nÎ.è!BžN=±Ás•q¾øŽÔ²Kô$z¬3†‡ÅåmçÀN’€¹oM0Æ.íáˆÅG{Ó5ñ ¸;Kkö Ö¥ ‰Y¿³À²Dõ²ŠG¿tÓ°R?Ë"ü8QðtÀZâTƒh{jƒsž›I~Z°8ÉY€ûJ@ù€%Öç¶÷gëHh„𗥯ßÿ’‚"ÿ+)ˆmKÓÚ¬}&þ'd»”Ïϱä”:Ýæ±¿ SÁõZâút–"*ZÜiÀ­åÇë¬í9ÞdiÔs'ÏýƒäDõz€wgîÀª%ï»>~°2¡;Pþé©á#Rþ釾OÍûQF¹Ÿ%Ç]¯­tÕþt’’@;È™+ÏÍCü©aÏr«ßr€aoçò¾iÂ+ä”¶Õt%p¢ÿ*#~ÞÕÞõ èÞ>×wá‚ ¹ ƒ._6ôvZû%Crî¤7âU#o­—gJðÍ‘ò› ~ó£D¬‰T*ëø+¹þçâû@ŽšÇSÁÃ[³ìÝ!L&‡j`ðœ½ð«f7Óx¶^Æ%óêW*³˜°™ã,v³_º™“´¥€4YM@%*W,ÎЈUv%\Á`*|`‡m;ðIÊÚ%u´“O¡8±|†L Öá'®¡;`ñÙvuañsÑâ0•l³4¸ñ沨¢¤aoñ‘yôõwªTv¬É ס8ŽèZƒÖïò1‚{×âÈö· @ðQVW¯à#|– äCµäÈ( `Gú¸9¼+-~7<¨Ù\=iBzОFã‡Å 6|ŽRYМ¾d¹ÇaX7 ×ügNÐüûžÝÂm8a­Ñ¦Œ‘¿9Afhët 'Hú?s‚ZÿÅ hÜ}ÒŒÔJMù(Û–ð—|¶¬æ7L#‘í¦ÂÔ¿KkÄÕÂ+?~â …Ô퉲 71¾²ÑM<Ÿ¤8u!$ )NÕn"^æsß:5©2y¢…ôðÚψ‹±`³GMÄÿþ ;|iæïÒ>‹ˆC-šÅí9^¸±Ïÿ¨ÆâPÑd;Ô=/}ý{ ñ¼Ï†2SâÚµ5-âÍ,Ú-À•ÉìÎþ°»X»tžä¤ÝNó»ÚÍ»ûº2 0ÄxÞ¾Þ„óß1pŽnD£Í jÿ¢#¿{Úí‘Ùô4¹é`ú.2Vý¯~zNwî]nL†TÆw–¬2d&¸jÈ}c,¹È÷k ®¾~MŽº%ï÷]Sª°Qÿ/” (VñO#󽻀їéþ %hí/%(*¤Ë ˜ñ®aß‚s>Qê5QM!pÊÇ–õX0pö¾÷.äwû%(ÂXi…—úž´SÐ3wI ÷Ï›çða\Q„m2`‰_1þ.p/±²Ü>xŽn™XZø¥ß”Åý «-“ÌGm‚ '64þÃ^+2±i„ø4T–‡Êših(ˆ Ð'^ Š5`{ì F”Äcü¿Øûë¨:Ÿ¶KÆ‚$8‡`AC‚»»»»»»{p'¸…àÜ!¸»{pw÷ïœÃï™÷y§{¦{zVw¯o­áßâ>wU]RWÕ]{ïâB'üDvn$$È!vÛ"Hù@ ìäj3:´7—É%¸°f‡´-¶"_Ä fv©d«šI{³êjµóûšw39ˆ*;‡®§å£…m"ðòAµþÊc¾p¯oˆà<ù¡Ým^F´Ðòi >züèªzK;–ἂëÎÚùá ÍjÏ@ü çžÚ.×д–›£6ªoeçòN7+*S¶…_ÄÞe ·ö (”ˆJÒÌR£§‹®|ˆ5X`5Ëž€è¬Á*Yò9~|ÚšO¶s:Vu‹“î²ÖÃpå`|ïéŒ` U˜’šu„ò7Ásk诅›ð³yÉdˆS§.é¸`—ënÙ$1§0ê9Añ.ŠµÇ‹ì½§pÇ΀ªÝòÙåŽÜÚrÇ1,8ʼnó"¨‰þœ=ô< £Ú„G"fâÙT̼RÂ…ÑuÌäÃB+íúU‰—ƒ° °z ù œ£gøšrÌ× ÿˆÁ¸Kyš’@Щ+’=_‚íûîy’Æ ÷qdAêOo€ ì5OÑ]°èÛ•øK­]î‘ÕÏ“lLí6QyÜåJP'Du¶spo€ ²i¾½¡Îï ÏòYféŸ/?ëKŽ·íNšç-lt#ûáíAÀbXK¨ÄǺ¢zÄ\[4†>g–Á”/iã …¸d™ʼnô»’n€üU£ìÜí—§õÚÁï!A(¨»|/EÓ9e>½›¿[Ê[ͦUT'('B¿õf¡@mr0EZ¸ìnnYmÆùóàRär²ƒ{ŒÂtöií¨šœ¸0íËØÈ'¾  sÀÙ‹Vá¢9“Í`ç¢BaY‚Œ^è„„ Ÿa3Æb]}Eïci®ñ9zÅñlã`m;{:"Qò² kC#ŽùŒ>Û¬Šµœb/ðXŠaGÇÖpTŸbr€ÓëÊÿ Ò­°Õ aVÞ@³9ñÅŸÄãFü¶ÿª8ÿOµSÓ¼Ä_˜(J¶Â5  «õ¿4LCеó+/›|å¸>'#ò×Xcæ<fÅrÅ£x¦¸ our権¨Ž±ÇuP8V߉þ†u>¢ìØuDñ…TL§1ªü;È\ç)0£±9A(PW“*0_ pèÊN®t‡>¶-g@ëz,áµEا ª¯¥}×V†Ö¦ñž¾¾ òøÕô–…ÙÖðåì=’Ûšæ š6©i+‡!2óÔVÀŒS.jrÊA5įD1ÄOó_ªþ¶È êxy<œêp¥ãð@Ç,ËÆ/ÿŽÒv{ó´øÏõÒ•?YTÆ?’efi¯¦Ôtšök뎣5øt !›vÑÍ;WùB¬ñVã'…^ím:ó›ÁV¦1ö¹LKS8<ÑìÐ7ň §Šò*¹'êÖž~¾ËaN.·ÙĹþWÿ JäÔ6[^Á„%ààM ™¤‡¾ÎA”|ß¼uûÒzàØ»øšgd§mšŸ'âI«ìÕ‰7QáîÅ,–<ãŤ5ž¹AòM,‡ïgpƾˆŽd¦ÎƒO­å1í±Bԑđų¬2Ä»ãb÷~©Úhìm݃vR¤\HhØhâ÷ÉžWWÔ¸å~tQÕ*åFO¦Â'ŽËfÜ’Ýc,ȳü}óŸð@µßþ´4EÙ,ùÿ ´¢åøQˆlz]Cê™á-{9(¦\Nˆ©WK%¶¥½.FòQÏÄrÈç*r¼! ßð@ÓûZäÍŽE}p¤Î+T`~œ;_lßÌR½SS.µõ;\>²õ;éI÷vŒÚ/¥‡7«y4«¿Ÿ´Ñ&`¾8a?ü]¥€Äô è/m+ô6¯Íó¢é¿àD£ תf52¾%J)W,¦Ã£%­‚rãb[ 甡ÌÎ=ojjÓ©»k&ç¬y‹Ðå"›ÒZÎ(<Ý’*¤áj½;OWcÔàË㈷Ý[÷t&°{)»6R`»åúÁ6äU­Š?æï㢽M}‹P~m«Ä ¢-iÆögtL}ž·oNLo^Õ-u|] ü*9L$&Åõ¸s*N}mf—ïŒ|üyU?bZËå_p ŒJ"Ò X„2Z‹Т‡À0Ú^.ýGR~•o”JÇAΨmÕqùOp ß%[ylÓ1Wà¨Òs) >½žÀ“ƒÅÀó#Ùþb•öÏÜ 1XÎêé¶&þ%×Ýo«å׋:ÚMqQ— C4!'±÷ErÌih€Yæj]«L0£ ñ³å&'¸ŽÂ#>Ó‡E{yG`­QUäaƒ¯tÝz¶jŸþ-Â|R=¿-ò¤ßÔ¬×sƒ"­év›„í¸ß‘FÚwq¼bn®xI䦱ý%c鮸pX­xtèG%ëeɱ€à@ìÿ58Ð]“U¸Œìš¦9{wÿè÷žš#U`q\ÝH©ç9bbÍdZÖöƒûŸá@uYmߣùb{£굞|óžÕËœÚíãsë?îÌŒ¹¶YÕiëXPD ÷)û“TÆà/ªJô©ƶà@ïRøÖ®eÎdOiòg>::~ÍøUµ¶wlÒŸr¼ñnLÞÞ诊Ô$0 ú"éÑÌKŸVX\)* ÕBÎ}¹íMîçô¾Òrê”8pm9–W¥sâ³|¡D‹ƒÞ¸/J¸ñ¤Ñ¡>oõd9vÍðÑ(Õ aŒ·+µþ8´Üzáˆ8pUõ\ïë¾ ÿ I­~Ç'ÊLòÑzš&cfvøÅä‹û†?™ÏJFCFø¾h“6Îd'êFÿ2P?6²æ8—&¢Á70ÐN™= ô„ªyTUVìÚC«–Ô"Ÿ¹õгamQUÉå˜ÅÔ€=±6³ È›dâ”êÊÙ×>jýÈ7gŠ «cb á kÝ>ž[Pâ—¶NYÆ0>(ö{9@hov–õ½ÈcNJ[@/}iyöcØV ŸïëÇOùßšf®°"UÀ»13ÏÖ‰¿Å|hêål‚+5õùn¦[7‚}Xî·xZJe®“q圂baè(÷3­“é³Õ1ƒuŸ²Îæ×så(‘î**keΨÝ;¢«àO"i4ð¤¡Âm¦§ý¶Ü]m,¾s*ôë±[v5º³Ãª0˜áEÚ™â^½ý¤í/ÚþŒ‰òW-O.u`óf²8ŽŠÇ£¹héPÕŸœÎñé;é?ô<¿œƒ¶¬„ ÷oZÓ Ò¸ÛÞ@€É)cy„HÔéÊÕ˜ÐVý¼ÆI½4…mnro¢Qàœ¹œ|’IˆÉgާ"æÇ’6ýÅTÅ1¾Îp- `(ÆkNo% Õž¨î.P7B[8J.üpú©F#úbÛjŠ­ò{ÈzOr >ž¼£¯¤Ž¥@¹ñ4}x¾XçU=o{ì&ÝPê¤\0ž5=Ý~rõ‹(?Õ"yd8¦ê=ÛðéWޤŠÉE?·ëE‹:éGÐÌÍÖ.‹›³˜?p[³J™óöÎI4³k 2g¨e gŽ—\´Ï6è­U¯Êf4[˜óÕ6ÿ@KbGSà–UÇbUÞV½êñvR÷»ÁÍÈ÷Ô}ß3·¿ „ïZôÕ?8&øzÏ¥ð±«&P–™ZmL‚z÷¸ë‘ÖZIýŒ¼n4Ñ4ôó¥|r jjZ` lŽ‹œ#&Žõõƒ9>vº CÞ³+ˆ6º5´ãY!ý 43*<}ï4}\Wò ¥¿˜fµzþØ%žŒÍúžìµ1ºCØÉeF>Êý€øÈ°«ÙÙisRQà„Ya7ýüï0 4@:¨â“žas©]!ÿ©‰Ö>­`PCÙˆËØãê ê}dÓ9ëÉ Þ¨g¨ÓºX%ž÷ý³àEëW>/ÒIPySà>-VËûǽÙér6æl~z«8Š#Ô=ÿ”Ï4˜ ¶áÁÆLN[mÒes郾.ÏEN„Å&½ øÚŒblôO!o5†/=e¸ Îï LÇ\J„ä˜(ZAYös1d@gµÓ Qqá¹µ<‡áK÷±†Œ npÊÒ ü¨<ú\óÔ˜¯bâLE^Ë[\‡éRJ¸qÍÝž¹kZ U&š'èijh¸þ4~¶'µâ?£vær[Ý´¿ÑN÷f“ztá¹óž|©°ì_U__Ïõ‡ü¹_µë“&™êfƒÛÓ·ES c…-J¿Wòz´¢Ad¤ºy?X‘X>¯ ŠJEÛÚnð%GÇê×Ó—º¥+oô»ëÂ~¾m§Ñ¯(7t¦\dö-çµ¼œ½bë6z••|Àòb>B눈µú»õ$AFÖ¬Ð`­¨¥ñä±i¹“7hÉ'É€M!­‹fï5•Qœ{ÄyÇͯIåÓ"ŠÁÇTõ3ø¦o³H­X!1 ÒMߟšûŠ"¥³œWÛ ~/#AißôA»˜5í$¾ósi‡ÈUI@4½lŽòÅh‰F‹nþ´ŽTÂüR$”‡ƒZ=¸8Ž4BôÏMù/SK¸dÜ7䯉æii…”["‹(| ÆKc¬GpÖõ|¿ ô~Ik1á±Õ(®ˆ[ÝO2ÚnýW©¯Q[3qëAG¾åϪâäg¸ÀMSÏt¡Jð§÷ÐV^2—ÚÑë&67|¯ù³à‰øó¥\àá‹›÷œÚ쟆&‡ Iu¿±=g²ëÈ ìÂ9Íöçt…Û %’÷ŽœÏ)ùö˜°²jûdZ¥a¿˜ÖžM(êN&°)ÉÜhÝnç8ÉrQu7Ú?䲸Z?¦Ëà}ìnJÀdŠÓ¨bËoŽÕxa`ýš¹vfWá_»åè˜ÌŒß?þ„Ósm:‚U}÷ÎÏ£wòû¥“…C/Q+¨ÿ©ª§vsÚÏù—,Ƶ¨û õŠCékÀéü>­ƒó¸:ßn _ ³7Žž! zkÆpFû>0!þ˜üY€= ]]dV®cƒ³)˜•žÇ¥1YÀŽ68Óèbz´Á½=ªhõ—!òÊ”“E<Ýp–nßÓ‡¨aµˆüüèß#ádÊæIàn].cMíÓVÏÊžÏ$õLö›–…£è"=€Á.Ù ­ (ž+þžòv\ÙÉB@Aë´N·ž ¶RZKê½ãúu>ù 8·9_qxinªJÞQðO}¦ÕVAŸAépŸö-R½ž¬"{“XãX![ëYE:8™ï¦?%TФÆ“Ë z4…üþMÑz“.Ó.rJJVÀÏÁ Üäh“eÞµìÒ³N'*àqÂ)}ÏÖLL¬€‡ÃŠ<ê¹S) m”¼ÍR”pï!·xòS—Žš¦d@ózðË‚?6³P±|TmÅÙ²ì|2ÒÃéôŸ«™~*iñîo3§©]X\v,*Žh‡uØ.&&Çi¯H>4»6â·ÓÎìù{F$Gå[ÑÄ…áLoàëËäìaàV úè?kTII™<:ãõ¢¨|‰Zõ†æÈdÍ ¼ãÃþ1"홑•NO3¤¬›R€¾U:ÙõUÄ£ð†)®ëx¤6õtdø.J÷õŽÒä¢áµå&š,½õÈèÄÂ#´TÝý-©S6úm{Å%®<'@ñ‚!áëùî"Xâ S} ´¼¸ùhãˆÃ´Ñ’VÞdœs躗Ѓ˜€îƒë(6WÇú¹ 4i¾DŽžu$̪¯B.eo˜þ¤œ*ö´^ÔÒtÇ$Èf‹ŸÐ¿ärü 1»3‚Wöýª- yA‡ã¿` Œ¶"|;A¦Eß-5Ec–¾ª&Ø ygÉ|å@¢Ó?XUèÓÍ[4›Í'æ‚è b¨²·;Ño òs+Q)IŧÚ&²ê‰E¯ìű ì÷Z$Ÿ—€„(«˜jŽ ¥8Ä¡èUÊ3†'ˆn)ÅΘY¹¤§¦¸ßB‰ÈúÃõ ûÓ9i.­GÜ%üž~öíèh«¬Ëo¬¿S*44’`óܤf2j-=#û»sGÞoÅ=¿}ü ·?/Ý`î´:*Ê/0¡Þ‰ÄQÿ~€*R·&úˆ>M™{qýƒøä‡Qè[—B#p!>Åô©Àõ<݀νˀé'SQèksuLõÌœ^…[´õѵdàãN6¹¢Î6ácë¢ûé'k¯gcçä¡ '© ™]Á› ¥äK‚ox 6å‹+´ö)– ¡õq¡øçÓMÉã‰)u¿ÜRˆš nŒ\ºÿ€lèÄ÷[0=ìýf@¡D^ÈÿJ¼å°S³>¢¥žÁwL 4»‡‰Ô CIõ·J¦éœŸnÙ–ð Þ1^|º‘w†“™rFØÅI«;ö'Û];ÞÀNÀ‡kÞ4·Û¡³íãzïé‡ÖÑ ™èùñûŠk©mÛsåg¦¿™µÙNF…‚°A’JgÏ>ÿ×A‚2k÷‘<`´4Õ—+ÊÂØë9ˆÅáJ;û;×;o¯.³w¾Ýƒ£˜·ÓŸ›cÏ,ˆ‹•'¶]j,ÄÖJK¹™ÞæŽÉ¹³“F!,ô()Ò˜’:†O¬_çA¬ÓjÅC'‘Ý€fì;ÍõÕEî ™½º¯ñÿ"Ùs»±XXÐót d½r]ñUˆüºšø±b‹p.øñŸŽ°0«ö $-†„é²üê‚,àÔšO›G¸##¶•N•,ÆðvŠMË–©kPÕÕÝ€Rì‰Ô#_ ÙçëÐ8ÌG¹fhèeÜüL©µä«·öæò˜Dï£Eµu=³.rb+G3¤lÁ[|+PŽmÒT6ÙzïàŽ.S ?)Â-.’Ñ€à òÚÓMÑ:*M<µ1k>¢|ÂSýÄWžú7ëKÐê‰h…oaf tG¦çH‡~Y#—90 )$å°ÌqO¤³ ù¢8^Ñ"˜RŠ3¯£QfefòìÝæ ˆ.÷êZ}1î/éåYâ¸ßm$`B6î73Þzo=­ýóBBE·!Ññw›ÑJn~¸© aôàƒ%¨ž,lòÛúP”òÑû3SÕ|¹@£;1i2Òi`™AævÌzÞÜ&ŸqTL…fWJŽ3žMU娭÷7 ?,Ϲ$Fˆ­Â(?îèþbÅú$5'J9|þbÀsXøNÉà„+âF¨Lxý«!ª†¹Ý™‹÷Ô˜á¯+ˆÂycü ø‚~—£N5Rç» GŠ~Î`¬Ë…7mý?›íꥃ Úß§…­IÛkkǾ Í1? ×”Ø}IúÊwÞ$ƒ³|T“8Š…±sU¼ Qw¿x¼³^Z® 0§ç1ºídë:Gš§)Êz_—צÏs£?ʃú’ÔíǶ‹°\VÝ0 ûØ»×›ƒQëàËEÝÝI Ñª–•aÁTqÔô$÷§'—ý¬¯< ÜvŠe,»RêÜkyÎȹ:,ΆR,þ®ÙÓ_^g~° Ëˤö¥pOó5I3Zˉæ'C“Eö«ÉÇögŸ®ä—¾_9ÿ{!ßÿéï¿ÿo¬GGË`ÄLKÇÆÀBKÇ o¤ÏÈd`HÇÆÌjlÌJǪÇ`ÄjÀ¤÷_×dý¿Çÿ32231þø¦ÿÿÿ¿äïÿ¤ÿÉöøÿÖ°Ÿï*p¬}soƒ¹q Ï ’µVöŠK%3CGV†Í_n+o_Ö^/×N}žçÚŸÛ/}^×;žm½™¯w·>cç>¯—íÏïïË×wúéf2vVËj«žÍ¹ËåoÒ­{µÆÚŸo¯³6}^Ç.OO¸ôLº[Ó[ËÔMhFŽñZ*Fß%åË8­²K¼¨ð¾:E¹ä!ÉL³úЏæñ>Š'üö¸Æk¬Ð¥Ìqåœè‰Aß5Zõ[Îfßú}íöÊ eWm£4MIæº4;¦°ùkÖɬð? ç3qOe:mé{ƒÓo .’§(K<$M±öÇ«nˆ,™œ8kuhÖ‡õé5©C·‡O•¯ úÇs‘rñ·.ŠÜÆ_Ý‚úÖìÝîǵp7³P†ºÚP†Ä+Qv8³k»äÕ)çâÍLjj3ä÷,fŸÆB®¹~½š¶M|!* F*‰€ž6n¨KÞQ0 ç·ŠÀ¯½¯¨ñH./_xq:TÖ(ÏgÞ¥Œt~à!¹¹ ùd|²7Ñ#^VÚ}DVbrÛÔ;@ͤÞPpm¤üŸT@è„ÞŽÃ „•å9jŒ²,¼D¦¦$Aùíïà ”9±Îii®Ê¬•H¸ {zhr4Ùô³X^ÀàŽ½Ïªõ˜› "pØòêØ$°"ó–¥8©{@¸ï•z±­Öïg¢= =u 1þýg/>(ʰ…Ëj,ª¢~Ögfl€Ÿæ£™â’æêb×ö#úf,Æfk )|5ºò×Ú¶2OË Á+¢glÏ¿}JàSÓ³ÎÏK¿ÊápW08…žÎ+«klñöÚ<ûË' ®oG¤»ð8à§Äη=`ñ°ja·¹‚%m2ïJÛüï¿ÑnÁôIþ,‹íù?逞¹i©kò?wéǬN—Z*/¸Dv]z§$Ë·jœÉx1ݱ. #Bcȃ…W]°±¥ÿ­:õNB¤FÜ÷8øY£öö3dqz})ŠÀùøÙQÞÀ>§AIŠó!@ôEÑ”ãò •õô*R†¶^^b/Bï¸Ñü>ÈD1P¾L%fĪ!9ÎìÍûÉ Ë[s¹èѶÓ§ë¼êÂúR—…juÌ7ÏÍxúNIÙnŽÊoJ ]1#†KXplÍxx—õ¨|¤Dö–A„ax<íD:{zýH\¼IΡ¿¯p·IQðªŸþ0pSù}ÙjqÛwtf@ù6à¿vŽ’ÛŒw©¤Áˆ"GÅïïˆØÈ˜ÅKú«áßRÿš<„ÑÁöy] þ‘ûEnô\«uhýve Ô¾`XμnüÇ®bäv™‰¦ÊŠ1[²)ÀK$jYeEz‰º°DD«Ëq%€¥~i]Å7™ ÿ_kbƒ:OžxˆéVâni—›mKþÄpW©|ñòÆPÔb£ËT;6Z‚¶Fî¶Ìc EDa!ÁÀ"x²Ç[Jj!ôôìCÅÒ*ƒ¸Š}râ3œò9Só¬Ù\ħ«fdúOb Øô>4 öî2VF†©w‚!Öt쯪^ûi†müW—C1ç‘™gÙÁº‰b*‡°X³¶§˜å $ª#_Jәï öm®’‰HJÞÔ@é©éÞÔ@£Þ1éIZ{1d‚`ö‡![¯›H¤^—I!;Ê^ÐtÛ•nO/#®î9äž¾‚UÙhøvÎ`ídÁ{êδ5?˽^ ËôCsu8”*qëkm†ðjSÏÔúoz¬X£áruœ Ár9Pgçäk¬|w†•ÚæÑHc;¥ÖÙ1ÀÝÌ” ¨výAÁøLØ8Â9GˆT«-'ª¤Ò•D1‰ËµI*·î\8¦H|›±ç6ä«èÜOÔî!&sá×þ;öÅŸ gø©<°Kãç‰óÄGÁãäß“Ð()¾:Q,2÷Â2O`1¨¦¨.î:ÄÞtD‡4·-§y·¿‹ñÿ“hèÈŽú¿+ØÖHéû’ ”`èã"©ëu®ÀàØH ¼vDþƒñ—GéV“]ÃÖSÂíÍÍ’¿'ˆyè->[zÓF0Á†Šæ†éN¢×ø‡„`äkÑdbõhl˜hÁôòû§¤)î`…æëtNNK3¢ÿ=PлgÚXã®&ÐÁñ…£fÚ¯[/ÔîÁ]Bú=èq¶O I±K|?u_ßlŒÅ_lþÒÙ÷ŒßîŽ6.“…7¢ÐæäÊßS;FYÀSM%ɦÇhw˜}M†sì “øˆæp½}YkðBƲ\ü*lÝ- (µÁ÷ŸÃž„eÆŽÄH-¶ß·÷Ç”%ÛÚÁ)vN¡qîkü#º±ôŸ(tþ¡`Ð^ÝcÐÖ>F5À|^Çß´-…@VÀÿô¿’Àó_Š •…‰òÂø¼?BxxÌeW÷茄_(Þ»Ð!é1<º••…Agñ3±áõÌÂá >’Ù ¾›OÏ*,—Ž+ÈŒd£xtö_#¾cÛëô#óxyǵb(Šå^Š¹æ‚”<RК6Uñ€¥·8ƒn H\ù“!ÈFÆ·)E<$Ñ CúÚµHP‡pIíD‡€æiU÷4ªýiôð°iÏ€ÞÝÿ HNã>M¢8tž>ù‚è°4íî¿© zɺ--®"åØW½aã° d]QÀN§.‰ëª(Ȧ^ûëÞž}Ú!ŠÍîjÃö‹{bÓÊ(FÉ»éÒ%òQè2«Û%?}‰ç,Éj¯ù]ñPõ;Ý1Óêüai¥I( ª&ß¾†£ï׊Ý1—¹wžчV¥«Õ3ñãÂM»;=½F¨é§ ÿZ àq“ÃŽï;“i|ÔÅèÙ“¸ò4á…IZõcùæã Ç“NR9pþhXP¢Q¢ü}%ÿ>”)þj/ãñ«o‰ž@±ÄCtw;Œl0þetæýåf¬qÑ]”–ò¿ƒò¿E0 lž^/õÔ×`2ù+À¹Sý?Hõ_§h3Â!á…%“èy­sQ—ϘùöîØ<²öæ$*zßã¨0£HpùPð´Ó¾xý÷R ó];ô¢à¥Ö( øÀ~™õ©ÅþG”áMÔÐÙþ«XH»‘ëtö'”CÀ/SnV*zö§Ìð ”}&¿ ,$‚•=°“Hè5e^|bü vù©-6+òkBP¾Ëòp%u|”@PÃztB•%ƒïÚ®ù¢5§>Ÿ›§qŸö¿‚€»íæM´ ‚qþòöœ1?âVµ-ÅKàV8;þ®gÈæÊgȨ£ûêPÑp4’pò¯Æö¢‹@ÿô,üGDZÄSRvk¨‡÷äh Æñß$i·ùP7<$!‡öà°éÄ!kÂ5›Í±\& æ|÷+Át]¦"î¡c‹v²O´=(gEvNˆÕVÝÀÆÉ ¼Zý&V (ÏP“,íxgÆ•6¾/K.¼‘}Z:§= ¼‹ù/eP,0åme½~ÕóÅßø™»Û*› ;3ïÝ=í[×'NXÑËÃqÎ9À=†Æs ä1Mé×.Í8î $Q¤°f ™Äž~ÇúZ1VDvO¯Û’‚ÑÚ‰á*%uV4Ht àeO£¶o±4H1Êz[ãWEmVGÒ±HOµ9èZó„÷ƒŽZ€Rñ 6gJ³–¬•oHVC¤Ç®ïY>DŠqŠÖ0þ䢂`úçym5Ž,–U6È_C-K~¥àPÉDÝ×ìÿ«Ò õï:ÈÓÂE êܣа£1Æt^êÒèuþK€ä#ßGS³Æ%²Ýø°ûæÿ-2÷Õûâ`Ž€.AüÁ c™:§æxB.¥’e¢œÆ ñ•èmⱇˆÈí¡˜=»eö¡ šBÌ4"^‡)ªÏ”Þ×ìHS'­è\ª‹”Ìð„ÚÙBN•ÿì(NÍ6ßS ºŠù»‘žž° ÕB³¤ ªñÚ  û‘ð¿ÐÁþ§tuÈðb"ÜGÕ]þßr\Ò9 9%»ý_qœü@ lƒ±£G„{Æ—VAþÝ¡™ï =¸•@É$J{2ß8ô~!6´ÇA¿?¼?1T3¤9?ëÝü»eSœ.‚«‡ Q‘ñÙèc{âšÃ×—óÿ­G¥êH¯Œÿ#Ñ<°öý÷;‡ŽšyìÐ%Ÿ™“Â.Ïñ×ësQ~…CQ#áZÅe¬¦2­ê¾/ìB¡C qA3—…±YXjÁáÉ—ÿóþ··zD=}öªÀ&Cf¾ëQˆ›ìÄ„«[¢¼qñWu¥E[+\‡¢Ñ.œç»u\¯º.Š¥9ºlÄËAñÎy›ö]4‘5-NÙw‚;²!e¡ ùQC‚?ÚKdN;†ÿaf: ®µÝ²ÙW,J|Cëàä 5 ¡Oi¸ª#Ÿ§«U+Ó’MÆXðr nÛí£ _%Ls+óH}îóˆæOyƒºKßDÛ_èn‰ÐJ„­YRE¹ÅU\÷>Àí¶ž(Ùü[¿ÅŸ‚Bù‚ïaPѶԋåÄ,J»õC/Dz°ùËá5„6)à‡ÒoÚ —ÿhƒ–F>?˜¹Y4°É|Þâë†*Hc­Uä"k<Èå W»´‰æ§mõýË’Y]Küáï`%mâ<ÃÕW¶ÿ¬ ö/mP£8ºGÆËO@H;v|4Hôæ^¸ÛÊ€n_Ú¾pDoûxÑãBóò#ƒ½î×è¿Ð'œ¿¨À㘥*Æœê0®n(¡4R XÒ…Ó‡M¶[Bûö;õ%¨92øɺûgï"ï™ÿÑu-qéõË=¤¿@qû+&Z”×m°ó|¬›§) `T…#'ª—Á¿Û}»ýVÙ,ThŒ½2ó ÐmJl½ŸTï‘Ut¤–PP„¦åòuZȪۯí+Hh³üZvþë3šÃ’ô Æ~-Õüfñ zyÇJù·A›8Ô× øŒuÁc™©ªñJ—î/U¯+gj(…ŸÖÒ|‘¦Â_‚©Ë½o!ÊÌæb«Ò‘ºÉ¹ C%lšùi?PÀ—Ü;×ñN‹XôR­— ¨x£•Çg§3TýU4DwæmPo(Mkâ‹’»’°p©¡--öm6ù3™Ç 9bÃÅÃκ²ÿP¬õsø@â|·Yåp… üª[zLZˆ•ƒ¯W:à‚yQj!UOU±õè†Eähƒ£¤H)TféD¡Jî l¿ žG™¬,5#Kr5nÁIË«CÊ»âé—änc ÖøJé“?¡“é3-µèöÖÇÙ!MòŒŸB”ñžý„EÔN*³Øœ\jEþÅ´9êš™2/'ÚII»mò³Fî“—¿BõÎÚ Ðd"ÄÒÃYäuk"¹1{kò$€·œ1ý™þ]´tŽäoë÷Êl¹¯8ÜíLŒ ºb¶®ÊX‡·ySÿGTjtà_Ê ;]©w÷ÎoÊ Ê?Ûj/ŒêÛÝvCjJ~˜†åìÙ>¾)ƒZ½)ƒÂÄ©ªÖ#çà}ÁôÅ |gÙZÙýXŸE¤Ú^z»åÜi7!ߣ ì÷¥:Pîs}é—‰+HÀR$%y#›"^ÜaCF쑌+ÈcŠ4Ï É†GC…4ÏÜ5Â\T§%×BJ Ø:äcX³WÀOØÃÉP®/žìˆêÈeÈš˜ð9£9¨ˆçÛjFÄ€Ðåä&ÅdßR,¶ë‰û—ýNWrÉ¿å2¤¨-Î#A_©säîßÕJPì2~ŠÁrê÷-ÞAÑØÐhàÙ)<^Ê’º+ iÏ«è:Ogúú¡œ¥Ü*6®ñR¾°“§¬ïwtæ9vµc£«÷zÒߙ붟3Aͤ–¾9Žús|Œù8Â*i"cR/¿‹ÇÜ•ký›2¨ÓJ Üÿ8€Íå±`,zMüÖ’m»ä焃duþª7ÐßrVªçì)Ë?&”³kæ—xh"Ž{©ªýzõ'É w!´äÿ{xûgñ¿T%ÐQa€Ü:—`PY1‚ä- êÿÞ‚D6ÝR‘›“+_ ¡ 5ÔÉ'¬UÏ{qq9¶gäGý*’›£e\*Û–Ýv&)?Þ±ì8îØÊûÄh¤ Ë>îüË7•>úòsgLA”Ýß'¬‡:ÁÑFú"x×Fm›VÜB ¶1j#ÁùðÂSTß¿=[Š´ÃÊöê†AÐ)ÎìgÌé‚Û^Éj®ãNòvíP{b ÄÏÈd¾áöuÈC-BzË©¶þÛï¬õÇA Œãéá[O ôܘK_ÓËù¯/1mI$>é²S„hËfÀëÁÈV~\;#ì•Ä=„c×K¯v¥´ÑGdÙ«X#x­o Qÿ& JóŸ„A?D ¯ÿW…Au‰’SÍÞþ‚÷0èýÝ®ÿR5m,‹}_ž`x ð¦ Â­ö™›úMè &é°|uÕéUL#ÁŒHAGÆ‘ EXL—˜y°»7±ÜË[‹nH7óðõ»/çëu€Œ‚#‡²q†\±xš°¦÷MWbq/ÔöÁA©çmI;Ä6t(­¼ÎŸåàºo†º[ô óK\z#P˜YO*cø5Ö{ít+Q‘½;z(°AptçÝ*vÀ*©4M?#÷ºÜåYôj|éôxGèз­ŒÊŒƒ÷üêÉmý}µAÊ^Ù÷8†ÌÖ7 ¨óÙQÉŠ¼çw"ŸVa²­8…!/ãae4µ)"sWî~ëÉßÏ+ˆ1ä.(&,–/ÅŽã Ⱥ²4ôÄvš :ïß`ËK€½#o»÷’ ![¦J„yúe Ü‘šž)0m[Ö—í¢Ÿ÷ˆþ\T„ص˜ù„zOñ/›@5(y´H*G~…ùq±ø]‰ç¤¥07Õ¾n$t—oõŠDkL'×.¤AF~1a-mâL0Ž5­(/h´#^ .huK6{PmÛ3b·r,P4í.Ã^!h»¹8p«ÖÎçO›ÿ7ž|VŠ?-&géê¬ç€)78`6Jâ¾ü¡>6‘ØæCÖ„6½–‹½î[Šh±èKú|À×ÙÀ=T>çÏoÏ%õüÅ‘u°ÉÎ"ZF4ihòˆ0™ùsQ;ËÑÀ)›1s톊ò'âoA3}lxkýÕ\l!®Üâ9?¯¨,S³­HMP™A\É¡¢Ü= s|&ÚIJڡ â™ôeÁ¨îû‡U‚æGâ'ݱŤƒU“:*‹¿ŠV - .ŽÇ«–ih[\šþÔ_±MÆFN±öfMÖNçÀ‘­¤õ1¬DýmÞ<ýé ÞÍrµÕ“"r\QwŸ 0ªä ï²B[µóô~(í®¼¾ÊCI$w›Ä?Q\P"ö‰:ý'Q°vÌ–}»Ô¤@äê‚¥J´º&œ‰œ7b°‡Žk³>NlüÊ¢Û¨í4J!ÙÁ3Ã–ŽŸõsBô!Ÿ&Dø¢¿tgAxÌÌô]¼FG7['…´›`vbhŽSnðÁþJ¡ÞN)S†hÔá'±Jð‚®³'*èéä—=?6…;AÖSúT)«,Ç;Šå¤'èëPc¤Ï-o² Ê>ÿ’¥É‚V%ä5Õ†f½‘Þ¸™ÛzºËÁ=DXUkþ›,èÛ¢s½¬‹Bÿ,h‘ÙÈ‚.eAò¥õ Í:©ÜqrÂ9ü“‡(ŠòËPw4¿GDâïÞß¼ÿ§¨.ÃÔÿàjéc{m7HäQc‹”ãŠÑìš)›­Í̬9ÛÉ “6§Ó4lHbT½¬Ò¾•$çÉ‚²eAߒÍÍì·#HÉšìèïã[ÑݱqEpoYFlË<Ö'"VîT^-/&ûø¢$"ö‘+¸Ø—±4£–d¤J­|j7Doq þt°ýº2ê5ohcÓ$òüïehƒß4©­²9nùÿt)3X!¾Ñ¿à®TÃSýÜÍv÷U?‰áõ¡¹¼ƒm§qm+b¦«"õD“ÍEøwM™q6볿”cï#NHä›h¾å£#qâVîËÃ~ˆ„PqVâuY±¨§µXw ;ùŠÄ§å,NNÎ¥N»×«¡¾gC#m@0¨É£,ÇÓ¹€wiËLb0'qøÌ·¼ìVa;Óy (Ç —ý]i€|c±‹‹¯×ð¡óFcu!ýšÊ±æp² Þ«›5“—zl£°¤r{ú¸ìþèý•Úî²4wŒðGn3gèSL$²àŸx“¯ì[Ýæ×@‚FñQgTÞÒØ*pVåmÓõuqËÒ3S_ûé½Z»@˜lè縹ûfqMs¡:v÷l¾]1‚¢'ôioXô9?Dszj°&äÖ&§yÒäÛñl²äœ |@{¾SÉÑyî¯üDê_gä%0‘á‹‚1'‚tòÕ 0:ÓöC EYMèîgÔ¤¡ ¸Ð öœO÷ÓÌ. `›™ˆÂÉÆˆµÄ7vÐà*·°ûvLVºy´0st w5VÆbœåF+t ò¹¡.ŒË÷üΨÒuøÓ÷Ìlvœoüƒ’u†¥´¿“9' £É/}ÜÒngغPUšÐ/-p!úô,?5X Ý“Ô»0¶LÿR½©‚ª~„ü… ¶~„ð€w Âjº 2^§ó!ÿ u"Å`“n¡é$P«g©‚‚ìvíÏR%øjoÅïøS³š§è"‚4Ä0ýG’ó‹£ÔÅ3¯Å´íETq–FßWö ðfªþ"ÏF/³ô¹@«(–\‰M!5ZEHòÿÐíöW/G“óGy\ÂC¿!ݼÿw}ÓTJr#üŸ›ŸÍþì–(ÇB®7MФö"¶;­§?iH³¾7fcÀéÿ3ã AnHI|¸É»Áµ¾|þïä°ùÍoºäö ØèÜG- Äl5X˰6$7ÅrÃ¥MO/Œü}R'5AKôÞ4AíüGm‘GÆ­™Ð™ðŽÍ>W¤¡¥ÿÒĹ…_3Œ›J|‘mGzƒ€Ž4ñ×ö2|¯ÞÍgpþsåb†Àå{’;°5ò– øš‹ ìŽ „ÙþÏš €®Ï¶Ž½à+c– ½Ë‡÷ 1¤@`C€Ÿ0£Äý‡ŽòÞ™{Aê8|lU_o‡A0A—bàÆ1 ˆñDËÀ·nf®tŸ’wÁÔŠ…sr‡éQV… -ã)åsš;ÆÍZÆçî´;Œ‹;mE¡S΀®½{”tˆh…uÐ"9¹Ï |Õ:°ƒÕªÏKÍöïŸEã¾,Èíèú:¯ Q(‡›a¢©Ò-^õÎ[{y¢ÿUZRpdKó(ûQñæ´@$wÂO4Í Ð¼Þ|eFÝ-2…ˆ#Y¨·dšQÞ ÏS°O™)a&ïêÎ¥ÆZö„Sª1Æ´‡(aî˜üü“f‚LòèZ°É ü„ìç{†Ó‹ÊìY™»Ž*zj¢¸³º…oQo£“H…eéb5RåDóSå8H†åÕ|_"UÛÉèeð–DÞ$AëÞ$A«ÿIГš7HAZCÑÊÊßé=s_Qy…±¶ûæIq/õô"- _­ýV&ÌiõØœð΄²‰%¬9¿õ¿º".+JÐ~'‚û`¶Ï´+Z£@ šX&i]‚,¬ÎávYmb¨¥‹TnfˆL¤D^¾SNd'YtÀb$Ÿ$ Zu0cJ‰‹Ú%Žv"i[»ð–¡þC4ÓòWá –“9_Yž}‹»¥$¡Pa.›ô›Q:9¯­£y{×F5Ÿ†tØhÄ}·³ÓiYNqæNFÃlÇ}\Wa×O£ƒ¥½¨ˆÄ(tÈÌDò-ì ¦ƒ¼[Û”W¸«Æž¯O—{OAPøÃÕÝðMÙOÕ&Óý>lˆ4â#ÏøAßrXÿa3½GvÍPô(ëÝF»JÇàRÐÉ[g?Cf9%˜˜Dœ&WOãÿý›Õ‹C‹À³SGHå3ƒ­™LêÛÖ<‡÷Ÿ[p@z €¿öhN­ ˜^n:î7W0R¹VÈœËßl±¥ö,e’–Xj9u*þO¤€—¹³©d ¯@)×´wšüµHcø „Ùû¸V«eü‡(× ­í×#ÄŽ;žMà>Us£¬ .*³¼¼Mã˜4d$–Ê{W£¸Å¸Wʦ8ü¿ H)ÓqÑ9 ½:` Núj<¶*{4 ¤‚ئ¹B¨“FƒŸuÜT:C}Dôç7vª5ôT˜{Šì™Z­“l5›ÚuŲ^±„V]ëü¹°Hv¤^´lÜJ31âH!8þòjyXó†ÛvTçmò æ™1ö™á4ù¦¥À&êZi‚¥Æ…§âUÎârjx}žÓŒ¢L«Bd,Ù.íg0irÞ£8/ Œ0ý¡uCõl1÷p0OxÅÎ|ºa0\bÑi©›qÀ>‹I=ZŸRàè7Q¶ý£:ŒªÉ¬1 Ôm|Ó-™j‚‚­¾|[YI¾YnêVΩËL’ÞøÛñ#Ê‚£±èùB'QýüüM ªG§ýíj9QMRŠ]hR¸€v¬ËµØR½LÛHßð\Nø·¢ ?avÎWÖŽ(ìõË03šáX%ˆ-è}ÃX%n3))! ÁŒåÁ*Ï¿¤@MAR ZÐ×. QÖ$ÉùÀ`6T¸]M°lÁ@a‹€Zg7µ©ˆgñãÕ g÷úÒüíò†aËÔYi:›`¡È™¹‰¹¿"Ǻ^ëù!òÔªåÁu{ã€ÝËý˜×Ó Ý¤GCI¢ý´ ŠèHÏr[Öœú@Äκ7ËGíæ£t'ŒÜ92z&t´ Øc1ûâÑÆ’nvðíÔ»ïtœ©‘\ÊÞ®øUP&Šì³»Ýµ5&›ýNÞcž´Owê×´O hçé äœÉ‘.~1»T–VØ—O¦â´,6Íà…ôÆÐܤÁÉXRDrëdÞº£Ý‚»'S)Çõæ³eùa’þ÷F#¿Ñë­)Óq­•aÍìå\†–Xˆÿ~l–¦”ˆ;[Û'iô뼨lýóíª\<9µœOÓòXYNïVGóÞ¿Òzˆƒ×°aÖSSeJžŠ=öTàéæ½jƒ>;ýq ¼©sC«¹>´3‘"š#nB¯¼ò;0‘gîê@ÄÖbòü£.Ï\@Þ')9úª¹DþÆ2Æt—¦Q³¾­Ù] ¥µˆÃ¦ŠýÃˉ·òœ§üËhØZA{ìmó5btŠŠ³Û<Ú–jã»»N”Ç@2’o']P鑪öFíÐŒ‹]¾büá2Ï\‘’i‘Ü*»ðê£Ú¥~ë{Ç™ý‡Í"Õ%Ênam£Ê˜—päšdÉ"r›màÙÖ·Zìaå;Ô3@Ÿ}Ý<¼À®ï:ÂÒ¡ö}î÷˜ ö›ŒÁ´fÚñ¨õ]Ðù,×d(rŠ˜þc¡AÄMîŒkk…Ü_’î¼ #ÿÁªßGÖâ›üVþë¦GŒÉb_JÅ>M\}–2r8Ù¼PL«oMCô=…<Ý4Á‡(9¤Z\»WDÿ#~wA'‹Ò&]1ª™˜d¥Ù ×dÐ1æJs&Æ–¶ZÓápßçïð|TÇüŽN$¬©ê²îod"ËÞ½z2¶KM¨øМŠ×û³ó”Í«1¨aËÖ…Öv'3{;Òµ’Dyv¿5ÝK PO¸•ýé÷œÄÑ;úƧò¹‘ƒ½® žˆÌˆ52PQpÙ<šúºw&ƒáÇì{Oáz†"ô1QèÆ‡c8•e™@îçæ>fjø(cB3¯ï 8˾¾zYÊ-nÍ"h`Z¼Õ˜¬:¢0´W-ÂÖH»¥]ÏÂd&OU„d7ùE¿\»Z›1þ?B°ÓŸέŽGÎÞ(,ò#¥" Eù*É"7˜|ÑbÕQ¬g6Á{ƒT»‡^¸ÏȘ²û˜*SÇrÏØJÔ¶ Ü¼¡ gÁ§˜ !Ë>:Jãv[l ÏòOXXt,ß§Áä;¼ØRPî©|V´i©;ƒïà`Šè´CÜTä–=€<¿§F&sQr{˜|@#=Á¥UÏŒÝõç<Üþ·?½ÇÔüv©ÅTŸ©Àû'†eØcöY(ÛzIƒˆª¾!ÕÓ‡–Àû _øÉ°4“‡¼±X»Ãøí°òƒ§,–ÞA§A?&uõ Šš…ØSÆéç&]ƒ ÐØšLÁj‡‹–†Ê1~ÂJ%ýqÕ’S!ýôîRê Ø»’ÚnY+#dìx­Ã†¯½@bB†š1±ZEÆ`âmøðÑQ§½j`ãÛrn‹‹Í=¬€/¿aK‰±^!¿*™á³«*wh¯‚aäÌxGÊ"ŸâP.)oÚú¥éÏ ‹åÆÔ“9¸ô)Ö6ƒõíÛ¥fÞìƒR‚F¡Êlsyv„ýÁþ¢Íüü …ð,e»—åcºOÇDðˆçÊb“ ňNéIz±É–… ™•2aÒQ ˆ;íë`OuØl}eAjffY2‹¹éÇb ¼câ7‚ç}÷_ÄÔ.饃 1h£˜Lä„/Eƒ¦ÀbŽÔg{ísŽ×O8bìé3-S·b ,™™@ƒ7vƒÐxâ…Všü®ú˜I¶—׳ͻŒnJ—‘g|PïOºü”€^~2®!S¬ç™ÉÃHnç@ÿGÿ qÆË¥&ýËV¡Uwi B?…t‡aa·©gûÛà½çSBÐC,0QèWØH­\x’”Md9à+ïĪZüãðÁ‘Ä‘&Âut¡·¶Ð(sŸ*xäSß-È)„Ðj2œzYÅÈiPØ ‡ÜÙ‡Ùù»ˆ“€×~qÁx[v!iÁ£Ì0çï}ù" +[D]¢YÞ7?õj˜Ä'ûæ‚`PNAbÛ´FýöFVº¥*A9ìv6áý¯ÖW˯bö]Òã'‰QËi"ó .>À39§ëÌ&CLzLo)Áª¦§(gšý´„™‚Ü·?b¿ÿ…p}N´‰;Sè[|LË$Zh¨ú-E?ؘ#l ÍuäBÇkÁÑhΈëâ!}o òåÀB7tҰŒ'D© ºÎ4gÊb“ÉÛ~¹øpÐé|:‹ˆ²11ú>:ÒôâóAØÁm¥—Jû{&³΀ίƒE^Hj¿Vó¶Ä†ö;6é>oöÙu¼fdå©W,™sZù³{Ñw1{CÇX!\ï”ø¶¿J¼hVÓˆ¿G!8ÀÓûFÑy¸#Ðfí¸à :sWÖÒ8Òó=yyø ¬hùxì¹—Z”kÝsœÌõü–ý¥Œ¦=B\ÎŒ2´g‚ p„¥~™Ï,ÊWÖÖ¾‘Ø4åà 2†îÜëq†,2Ñþ]åe¼¶|èÍ}k_sb ®¹2˜}$Ëb–#áû¹étüÎl èµÓÛUì$*wù•w޽¶r§C‡ÀC ~¿$w”aIgOìõºþû‹¯Æ÷¯S4 ÏñëÌo`»ó•‰ÌÊ6¨Â,¨‚t2¸Û)éœÓªÝ[ @Ëh/›º8ý*ëŽ-¦ÉUuÂÓƒTÙÁ> 5‹äY}¥X§’&¢ƒVF4ü±¢wu޾™<'Eÿ°´0?ï½£jw|d!s¨1+eÞâ sQX:öv°¸ØŒ'Ú“ÚøMþ 4¯×«I(bl]¾©Rx‰xaçvÃÔQàöƒ¢–|^/Sd[XyªŒÊ,S$3ŽfµÀºH-WŠ.¯“%™±WdŠIþýšëkå§Û7ŸÍjŠèÏiÁà§Žq—Ó™ñ…LÓiÎŒ¼eæ÷ê¹!BÑŽJBU•Ðý儉.ŽáÜ÷;£©Ë)zèޝ4 Ë̕ů?ìWt’ýZw™ÊÆK:²é‹Äs“¯y²-'ñÐ,ey AßmÜgŽ>/¯9(.…k*LOè;‹è¸\<È|Ò©wÌAøYoÀmgØ×’‘àÇ9xÁ‘S( ¯±›±ëïãád²|Záq˜C/ÅEw¡È+¾˜¤Ù¯f,ðõëóÔ¶ ð¦øÚø°ELkh·Ù±Ñÿê°7ªô²v_ù›bòb  ;cðBh‰Øw3 Œ ]üç2Ž$5‚µ-΀Âø8ñüㄉõòÅm‡´ŒžGs[’×–Ò;žš€Ýcq‘Üá 9øï½ˆy—»Èa -ÊÑ_]G;VÀö2¹Ã …ŸïÍ­/cSm¦¸ Øk†XÙ£&ëA"'b| ÐÏÊSJÊ3nÇ(ãbKDðÛÌ9OÀãØw›¥øN†ú†¬+Væ-;Ž2¾P|BÓ™® ¦°UK(ëå¢HÍ_MVB:NZs¥ƒÝ”Äa^£,Q/{=ÇC×#ó ±ˆQ,ÄœÌIŸo ª­ÞVÇà“wªºø Lm¶´õåØÖeDغƒ %¨Ž\ÌTÛ„4ªŸó ú³¦’K²)J¥ï7¬VÐ5ÍÈT» ’â2º‰¤˜¦­®”B'96Ãs…Çt¼œZIsZëyOr™2L´¤kcÔS×.œ Ü%v@\U—†‚qžŸ[_QÉÅTø:¬Z>\è¼mh–È_‰‘ †²œ RO(+ÀšùŒ§ÀaœèAWãNÃ[ ÍUbà(Ñ­)"2¦ÎÆà[ïH8¦Èy9pFÃGôï÷kÑ'w„ï¿ë¬ƒS…œÈöâŒlS€d¾Úœ6Hrv …„ÞEåùlØ*`juÈ0î^"2Ìí)°Ÿ÷/ÌC? 8ܾ­<¶€Ä‚ç{“ݽÈž–*šä–ò©})—$á;:GÉïdöÕ’W[î…\gdn­«˜“5»‘bÆþbŸ‹au¸ižlbFè8´h|¹µòÄ}h.öû…k­ä©ùéúâÛ›fç*®PW-±Y:ªîâ²?ÓZNP–šÐ@IZ¦ƒ¢Ä…êUBYR‰:!ÄÅEöÔ[Z—ƬªožXP²Jr‚‡ªõ¥ŠÌfçµXÜùÉýwIu,0=ŽÌJDÆòsqg5epjVFºÎÄá{M[³ƒ˜°#ÙaK³š¨«œƒñ,J„î«á—ŠYh¦,¾¶·Sxí\"ÚÄyùÅeM•–Fz5"N {’A˜$ó¼ša¸{ãZ·í—§ìmjN3ÊÓRîÆÀÂûj#Ñä=a OÒE¤€,æªi>ÁFŒÓ¶¤}³¢áamÊkºAôa)µp~1‘¬[£–R÷g0j&&s—åˆxâ4©]ÖÏaëöØO¦}šÐhÇo¥L9£ÖENóóÖ™ 6a‡ó-¬‘̴왋0裬¹ù´RÔ=€Æy “ðœ×|;\ÈWɶSÚÇE½^¢–( !¹x‡ ÿf[üVªA)ñ1©ØÉÌe—¶Õ™ä{éS¡Ýaò5?›ZS(&|è»âîWk¹ÄP:2ò—„×&D¡m0LÒ¼Z€ßâ«V˜¿O– °0—5⢢ü²/]½žƒ'Zà€¸9»KBûdë¯t•˜£°ÖZ½¬§Á’úÕ¬ ; 8µ'ðWàÖÃ]1ß©Üõ‡RåyôDÇ;<¢A¹å¸g%F˜“8ë7 6º/ºTã_UÿWlªz Ÿ~޵[?¼¡öKj|胕ȨS4;23ŽH­~û.è›J.FFCØÅC îÙEl6!’U¦'b Š•PDÖjÅ™i`ö0;®o"£¡I9tœØgë¯é”0ʦ[+¾âøudÇ•žÐ„¢¤¢g#Æ yËG«w€_z¼z…`÷°LIŸxûOF«2î8~^T_ú͸ÈòŠä~ô«Ûϲ.`ò¹Šg‰³šÄ+HÂÀ‚®¶™O›ï}(ñØ7Ïγ¨ÃÏN¿j¶€•@lèÀqD¾—WûÕ?ÇÙš%HÁÈ|ۼߓ´ùéON¶Ñå‡/J4Ãbך2úR(?ïp¹]ª\}€qâ1—ødø+ѱ]€»P"ƒ¯©¥óÙÚÛÈ+å9ÒìéàŒ¥B­5/ÎýÐÜ2z¿5«ÚêÉôôé~ìP=“˜D&É0e0Q'ƒ™ÁÉœñäåÐ#\dã°èªr,aãzÅZqÔÙ4¢Z'ޏôïA Êq.“kÕo$ 1樿ÙÝðõC¨I„ZuÈÚA·^t¯Ùq!™WŽ„¸&‘ƒöÔÛŽh6°ƒDÍn­9¾Ž)¸iQWà „>ƤÓ2§ž‰ÎÄñ¸×ƒîôyÈðOØò­S¬&6•®š–çqàû§²y™0´­½y3?êN—ôîŸö™°±Ïòkü¸kn¢9é Ó&'þ\uÏÁ»Þ"kpá¨Á†å|ižÐƒûÝ·Ôè+hJ¸1mE1u˜/€äéiñyù .è”Ю®åzªÈ¡½a¢gWòªŽeÕy9‰Æý‘CÄÏ膄ãÌ‘¦.åÆÿ¸ÐÑS†|c`1E[ ŠT™VRaM¡¨;áåŽ<|‚ˆ(éúLG uZƒ®µµö\šp_ÛÅ.nVfîéà y¾°ÆHib+8”¤cž›ú±â¤4£Ø^éîÄ[žhØjw‘·0Y8wÃéœOÿ¸RkýcÏÞ®ãT4kÅuˆã’‘ì±4åÖ×eeï µŽH“¿2Ðôì3[¦äÂÃxŽÃÄ$»ï´‘[=ž“Ôèwó°â^e8\Ýž fñCÃqsXXÌnäøúi÷ElR‹<ó•>Å]h?—ÖDÛNÇ6™˜å”g <À–jG#Ÿý;úݲ8]ôð%/éò W±R(îÞ?N¥õ ³ôܯÙHý)Qèµy>L@{Ýtí92G·5u¡ ­¡ø’ýd­ûè×-MGûÄï±ÖÅÚ«ÞXì)C·gT¥ó ¦Äª:áQ*ˆU©ûàNÕtö”†Êe÷Ôv¥þgµ0.ÂâL«]ƒç¤ƒÈÛ¼¤õú!}¾ÇÈaç£zHô??o`m9?ÛÍ KSíXç½ÃŸ}ÕyÙ€µþ€¹¡lªQt Â´| #”š8–z\áâ“MÛïiE±ß~þÓôkÆî-YÀ ìÑBh[‘óÂn2…l23ÐWkqæ<áæ]•UçyïÍSÞ0ô}¤¡ù”Â~Ô¶œ¶oÖ0M˜¡?¥òŠÎØÝ¾7‹I9<•Ãa“èÇŽ) $d–œkl±v±Lx¯A3¢Þ.v/K¯0?!eDí»ÿçð?ý÷òééëÓÑ2è1³ÒÓ2éÑëÑéë332Òê01ÐÓ°±0ë3ýð1ѳ°Ðÿÿÿ‹Ðüÿñý/øûþ/ÇÖ¡Qò¨åÆÓ‚½ZeïöáØê³wfTÚÉGo ¦B´3N'i%å|”uéÉkÒ×ÇùÇ×û¬×MžÓ××sŸÑמÝ×g›WÖ¹t¤ž¹y…§ö×Kž‹'À?´¿8|÷œ³uØJ>v8U_ðfú¤Bé!ͲY¾ËóòøPqÎóÚw/s«M÷ܬ¯m4ºª\V¸ãŒ¸ª²ë/1UÀn“ñùûÖ\;õÃmØýÚDZ‘Z2ÌàS®ïòþY=΋m&ÓÍÊM'wÈ/Zt-*_^Ë ëY¾/^XßþX_Ô,HT³%Âjý@Rë£qúñ°:Jû²´2ròÎ|àóËì7iG£Xûiò*uŠ#ÉöôRëå4¾5§c›ƒùò¬ ›SÒéiÙ¥GÏËiX­‹°ÔêšÜ}rãöäqõ'Ÿ¡ím«•/c«ËT•Ãj#hwáÊð£&Å3=‹ŽðëTïø¨”ž~|n§¾ˆ4†ÓËàöü U›j~æ9öqN¿K¤Hïk5Ãq«þ]Æ™ûÒKàþAêȧIƒuí¶¹¹ÁIú¤iÁk³¾OÅ]u ‡û]®<59]óÀþBk¹ÝÅ A$Ɖ™W Ú sêNVü7½«Ø$ ƒHôû¥2‘é¹®ƒæ”kÆõ3[–m¤ÉÖmtÓêÁ+=ÛÏW­M?ú†ëûjsiî™ÓžpÇàÞHÀ@$`•}\‹’O?e—­®ë·–¬/Ƭ•ᡵ&îñmLï"°1ê˜ú ÷3o÷z¾Ü3ãUçRÓÜmÖTWFð”sÈh µ4³êˆGeˆ<º ÔooeѸó@#ÕØ4tô$:G®ßÐaðäD;=©£á>¨Õ¿†ï?EiÀüÎuI-?ÂLÕϘP<Ï&.TŸWŒÜ´X’³™”¢ljÝ´©ênIØíf:ž™ÎÜRϨЮ]q~¹gè‹È)‹íñ€=¹ì½“HÏ^YÙ]¿lªnôTC’€6àJò²öXÛÉO8eco§žÍ4¶ÿ\P«ÁrNÔRüÙÛ ³ì;úo¡egµût Øíƺà ý'dÖªSOS}qƒóà:rüäŒd,a3w—gU‰Oؤ>T5nתvé.½äÉKŸ{œzßhÖ>%»ðo¿­ GÏн nÞPwŽý€õxµ¹!½ÌáýÂìƒ!‡çcƒ ‚ÆÆwO¿™ö“*ÆèÑPŠ^ðà¤ë߆ ÌÂéB£_ûPûž¤‰1BÃñÒò81„"²Ú?ëÌvÅñvÔ8˜a"Ú]”l.AAüpºkK˜oƒ\i¹[rs×lÊ»i㣊úÍ`Û™ ä‹ìÛ»rí^Xq½˜pÚ©É»³3$Ú‘ÈR¨Kƒó+M{ŠZ‹³9<ç9hܙǀéÛ Eü«ÛëØ+m~Yƽºô3zð®“x¤¯¨\Ú…ëÎø‚Ë{ê.Ô`°>me}¯¥»–Ä*iº Ãÿ°ý²î6åOñ­‡ã| ¹¯#x­Î”ª‰Ôöô°å€Â°4Yµ³°X•R$çmºÒxë!¦AùP^˜9¸xÖ>õ JúJ‰ßð[ÿB·„–‹ç]ïY;e>F=¥xFÍS»½&zjD¿ªÉl{ATFz:kã¿r‡n"²b¾ç“C«f\º¾À›-êXBŒ»í/®V™þÉý¡ÿŸü×û¡»ºÌ³êLgÍfã(ã;¼tºöØq)RÁ42‰,‡p›C8Àû5¼Mƒl >Ü…"¯è;½T>L²tx~ßÛýÆß[˜uýwXžuÿO/ˆi¹ùáÅMH™1¢²tšÀƒÀ¾Í!„°4Ñ8Œ š´‘Š¾qt€ ¸ÈŒ¹òòñ«»†Ì¶!~ìÏx®Í êxúŸƒš±?»µœÌÑk>™«³hÞÐp‰!‚äÓìGXO©gŸÚ~%@(=žÜ =^oYJÞ0P;(2\’á…GИۤüÓÓ«b aÓMC†öŽblYü¬p_Ù%_S¡lcÖXÚsk0é>;òªH  $c|&l’‚!IÁd•Tº¾ÉæÇ·ñÑæAòýÚyf=<¯ ÞEsÒé§»]æIÒ>Z†vê“3 —-Ûwòd…ßû‰ô®'mŽ(´•‘Bƒïó_Ò“«6¨'}ÿY´8÷5‰S=¥æ­%÷1 $|xÉÖùB¡Sõkòû6¸M<Õ£š§Q#o FÝñõ*?¥UA7&e´',}]¯zÛ?¯Í¢ùÌÆ‡Ir^Ã_e (ÖòI>P&œ‚Ú¤—?Ü.ó®šàIÅó¯á/X" ʵCH2¿z´ÀëÎM¸òv”ÿ´ãYo°%/Ž8on­óáJÀÀ‰ÖG~µ9 å9ô“ûßü‡ïϵ憛¡'ú°îw¨ï_À†a$3fi¡6ØðÄ åÜö_©²˜ØÜº6Ù¼·âš¬V¼³.@çÎÄ]èhêÌ ž_;ßN£}¾Ê6^®ÍÊ•¿ÇvŒ²ˆÇšJÒb Cd]õݰPQ‚ûåɘ’8àB¹a°c7®²kXçg¿Í¡ 'Ü’ú×ê×ìWŠwmhTòŸBcÝw \r—§¥ ·ùåWÉö‹Eø‡ºââ÷×&ˆÖdûìçúÍm+®áþ¡Ã 5ý#ž¼(ßÅ>èÉëg`<‰Ñù¹ÁL©šùÉ—;åP Ià­ì²ä€ÑXÉ&ü ?/˯¤§5`5.ºÍÉ6ê2Gú¹ðfÉ8”̈ÝQ¸ÍF\ñN4ûa.Vä t¢]´ÛÐCP.ˆ7ŠÈ«¢Z«k5ÙÝ·×Ä+΋‘ƒ! ëËâ1•]5˜Œx’Ã:ÑÿÔi|{©®ÀýÝÞÚ’5¢l“Õ˜j¶°©esê27v3ÝÍÖЄË]úÀ1i×ë·tJ Ò`áø£ºÎO²/~c_Ô¸8<(}"mN ´rÓˆ`ä\Xð2.îë7¸©jŠQ9†ìt‡λ[‹»¶â"›QuO²ƒÅ½±ƒÍ“`Á ƒá¾ŽygÒ <Œµåi9£|®A}êoÜ<á'Dîb;¸ç xŒÍ2]–.™Ò”Ñ:ݼ{¾|Œø–!kù!Hæ•S𼳿7ؿу½»ÿ\nO¤?=o_ð——?˯©æïÁú|ÒÉ«;ÙmCúo/Àæ-YÔ‹Ê(ù)RV?ññ©îÕ+7¿_€¹1„VàÌpBÓA‘$€ñ†àÔħƒ:­¼^m]ßŽŽ•üHÿ«Ìa0#¦<}/ʤçÔ~P¸KÛ–—J"¶×©s–Jø>µÁPýýÛºBöPC`Ã~1•Ñî7þ ý]ß@¦¿Úv5Á:³t×·’@;}€ÃhG5¶O³æ.—%òg‘ƒÇ2"Œñ4"Ïc3®ÕÜsWþѤUÔl©òÖþáóñ w?e1ï¨÷ê·¦Ü[ªÝ®3ø/ÁF~}T~/·PŒq/4?T¾dÏd*sxN "Ãs4𫟕'S$ö}•yŸ$…›ƒñÎüýüs_~üEÖo*¬à9Ë”}‡še„ß¼ý°Ì¢Ü=Ô£YÌZŽwá6Gÿd9¤þ.‘W/AbÎÛŒÈqHÙ}¡¹ô~ÒU%±™"ä«ÎßïÚà*ú®ÎO~zÚO Îï%@G1ü¡æÕlŒ´ ÐÉ"p†k=¹ô} q›õþ®.Îb4é%yŒ½) ë)„Äýç-#pfÞ…‡L†%öîÙ?iK»ý¸óénKÍ<|§ç0r¼eÕwS-H§ˆ»tþÜp„¼ªÕ@³ŒFÚ¤ô‚ùȯ]KK V?|·‚hVß,}‰r÷ødã}óOG…¥‚Gô­ÕÃ^\%UdžV*º—ÇÄg+.c1Mgíº÷¸Ù?«ûð!Ÿ‘ûôf?~;ªº©¿vµà‚tÍä*ôeå‡ÔBs¦ÚBòïQCþÍ ŒµÜsÞ#ëkJ#L¶Ÿ‘ÉÈ6?` œ(H_}oÛ´r„Mñ„–}æ¿øSÄ«{`žÐkúu8.™±w*³=~ß›|aäaƒ’n¡¯ˆ¥Ó÷o¾É^Õ_'3jûÍo’±ÒTaá}I7’˜«Å`ÖÛW~Ù<íÿHi­bê«0ÌrRL]ÈþŽò`ëHéŠz_Ú#xöÅð_¨†ÆC³£u¤Ýõ¾Qã‘úçäÒ4NA±¾BG¢p¦K,Üî§g̸3Ž–ÞÒ{fÂxçÍÍCk7J©ÆÅ jä ZîÌÞÄs‚!›½U ÃÙnŸó*Ü?àOkòj¿éžÙ?§8t…2ž)7Þ¬¬‘Ú»±…9%žvsXÃ>¼'ßL0ŽOø)E»Ï±á!e8±I¯cŠÙä¹ æ{’¯vi%H–3WÖì±’·§þI]9µ9\×m·Ã—9›óøp$Õ†š~ŸóïbJmw7¶¦ïlµ]¢3„#ÁݨÛñg«êá=“”º¾&œ_ÀŠíK¾¹~¹tÕšG»¼(9OeZs6D}£ ;fE.ÿ€sÎAw“è''¡¥Ÿ)³ÐñÉ⽩!YØ‘I0Â;Ë7-Ò|Ä 0ÝKÀ¤á§|Ñ«p;Ͻì.SD¨óìûªá{u²²}Rpý“ÊãñuPþÂÿ§¥«uøVGâ×ñÒœž“8¿î—"NÝ‘¬V¤±:'ÒÇ/G)2¼ó¥Œ}ÓBÕ §÷u$ñ[”v)}&üØÙø8 K_ÁÊK8f5KJë>¤Éƒ[¼X:ˆ¯ugCA&År÷°þ=¬MT|6H—îu èžböU=0äMÛÍ-C˜c+¢CñØ‚áÚC!H«ÍÆßÓï¢r28ÀãWoöý~Äõ!ü®[iÌ»Ùëž.ˆ(¬0HÑf[£³Â D6" s6´Îy¾ÒQP(ÖæìYOb–ÃR‡µ…¹ïÒðž‘A‰ÂúñÇÓ?ßËk«±€ˆÂr‡Z5üþJ½G%u]“ýΧøFÖBàíªw9z·UÕAŽ.Æ $ ÊBDÿQø^º_ÆKß™Aòó÷ŸIjóG8´·“öõRwdè—.˜2Fž¥iÿ\ TvK³‰£@sØõ*‰û‘­Ì`;íÆ„kœq±ÒIt¬põTúEGêc'ÜT9¨•“Ôb ›Vºè…÷¬ƒüw×EžøØä^4[– ¾?K¨èèfa =8îPVceÃ]ÁûëR¶NƒPÈ϶ã~CâzhèËÔ%5Çëp©•,«å4ZoLa€æ\â9|Õ§^ô¬ž¼ò³íwÙç©Í”vÖä¡lìc[ÞÛ,13:] ÌÇXˆœ£,ßâE³°¥Nõ©$1H£€¤§¨ìíIÁ±x¬vÜ®'Ón/é*IºsU,x "äŸßl;ºgh…Øs²K‚^¶#«™A/'¹½ÈÉý†ËâàÿƒÃS¬oÃvÍsxYßxmÍÊæ"¶|q:䎎K²m#ýª0ƒ˜áTz‹*Ý‘½¬kv1÷óÀA.ßÄ’ÕXõ³€3B›;ý®4ÈÒŒ%¤Vƒ×–|€Ø$4˜æU™Ô5~›³ v Ìuå eñ]íS¦Ãy4 Y• .ÌÞ¬çR¬˜Ã(E)Ý©Üz¹²;žŒ+v6ÖæJ_÷m=Y‡‰„N½u8KËo<_Ñú)Œ_œˆ2¿¨÷Þ§?S†h41ûØ¿BþÅ!ª8­‚µÏ±Ï»àÓ9Î×KåÏ®ñûŽM×ôyqp;'Ùø{JóJ‡ëYù=N6jþZ :œt!Éð!¦ÎÚYã_3ÒhÁœKÀªÕ.¾~2ùÅ/Eõ‘«‘‘2Pþ»ÕY(Wˆ£Ÿc‡ÑÍJ–3ºä ˆ+l2ñ¿£>%9(œ• ÇêWÆjÓÚ` .ja×:Æ)ÙøO¨/mnäV—æOÉô•ÐÒ¾Z—f"¦ÔhG\ŒÜ›f}ˆY0èø‘I»Fuâk ¸;iÈ’ÊΙ`ð0[&L8J«¼ðÑöh+rI¿ìƒ_ßxpS°…Ô‚á½oƒ눓 ¦½ÿÍo=€–jMglöx»‹Ç*çrvêµ\r29H‹$£‹í/Ùû­uÎYJKù=WÈñÓJG…ëÝ`(‹¨±öa&YׯÚC n\ë]#ü7xÔbí^Yè¹bÃ÷nÑÅ%º«Ï4²°dKáÛLà Ôa¬Ñ¶ÔËåü, »õ.C/e€æ•µ„ú6¡à‡RˆmÞ8S•¿kC}½T±¯uŽöLÒêë8æ/ù \%7 'ûþªd4˜Ð™¼”ÉÁ ×cÓžEî”wúm«ªJìa»&}[[j{\Š’DM¡ÄŠÛÕ _vÆOó£ 7OEÓ¿1ÛáY}¶1–âΜ¬tuØÅ%¨ìÉG‚ë÷cVðþqjôµú–äŠälH7X–Q*4B󩫇t>› þßEûv]fwžÊ£¸>é_)êjª¦°]M4# #Û™Öø¿ëÚO<ƧOúܲþtÔêô&$Fâ´£¬ýá:ÜÖžð¾Ã0ÎÂô·¤4 ?½µüáK[øÇ£Të(Tº‚G0óú©çÄzX‡“Ž„I¶/<î%ýÅdYÈ ‚Xº’>ª´{èèÂ~ Ý‘sžKØ4òÓb@~¢øRr ã\ç;lÑKµQþ‹ºÝnnà8Ÿaê¯!á§å醔EöŸ`³º–#ê>ÞT ·¿ûбU˜ ÙTëP8zi¥¤…bo ¢ ニQ>"h=îß*Ìs×OER€Û’|GU­†8ú‘tÁÄàÔf€Ÿ–í^ÙÞvÈÙ ÅûèO€8r”FŠÒF©ãÎrGú}½1ÑBëß FWfN3ÍFu¦Õ%{ÒÄÁú8ƒy,7lKk´}Í%]²nHHÙù½̸u$;{‰H°K°Få.¥·Î æ¢ë u40^%XŸØêx™äzJ>³ü:K·Îq´PMâZ5»ŸÐèt§ogf;ôl——Ñ‚ÜUî„ –¥¥oGu•=H×~šÅñ'ˆ/Lé¶“Ý«|âbûÓÆ`?ö%#pÜ*„)0 iI„œF+ݤрûÙ„ª7ˆ WìC 0Ù\¢°S·†É)—óqD†‹_o@ÇŽÖ¤hv*›gØ/ßuBZq o1ƒ™äûÛô5)*ÒΆ&@‹aÏ}OŠ÷ärkÄG‹³J鋽Ú1¼±k86ÀÕt” ´y[7‘YÉi>Çvp’p§!Y<íjŒFæ®%æ÷0;´ü²“Â!œ«‘‡'ÿé{ð¨\Ì™ý¸Ú½>«ÓÝÑôîÓ6o#–iG.­† éùK™ ¬ò·C®J|¼ºÅsÅy¢Oú‰jÝ…¨Êw\&®‡€É‰„&w`d @ÄË;tʈ݂úƒñHÂl¸!\HýÌí(Ìõ¥ã´¤éáWZñ`TE¼ ¼…{õÎRÔp*+0Œ †&F¬<œ.HnWî=Ìë{íÅü¸KÀÛÉNÐ{‰†DFý›9ñ½ÑÉLgÌx…Ìh¼ß¦}½ðÉñó‡T$ÙvR^¥Ëš šfžüéàã"­Åœßö¨s˜ËüéDvi©êö\>3ñEUâx@Â0°7Â06 a˜®t@Sb9ˆ0Œƒží déOÔd¨ÖwSK¦ ] œ¯L»~žiy$®Bæ,}C”c3lÜdziJýB_‘,jŸiËöãþÖŠ¯ºŠO±+Û~[? iU1ÃN”XïÇžÂÓÖACË8Œ›MõI³é Ïý™FºôH\yé:F7Òêü6±hd.cÚ}y Ê?štSʯÙÀnùŒ:0’^{¢à¿­‚×Ã} ¬Û\…4ù°5nç¯ôògµþÓ(÷îTÔ¯™;*‹6"Q^2—`íÔÖic[(O&Þ¯)ªx«îA¦öÓ­*”rm¿¾µPt×&ße~?9Üφ¼;&à:¦HÅsBh^QGT2ÁÛ_´ÅX&°Ô¦2uR[…ZXž"ú© ÇH–/¥3´bÁ—2•®ßãN¤>Ûº~”ªô>§fö]L zEFÒ®ÀÅØ‚%1¬µÀ%ëb$?|÷‹Á{!Xþ™j5÷õn3~ Ôµ»KÍÄÛ8¬ŒþÃk*¿Ò%ªäzÒÅ¢”ÓûYÁ´œÌwîØ†mž„ÔT´£îìø¥Dm Î?^ùî&™¥D_H=œ/ý°žæe“U`QŠ·•.•Ëýû×€Lÿ'b’ô­;aØÙò¶ÿ~'jgÝØ=&}µ*áÄÅÂ$„õç,—aÿ_Ý…°n¦ºöÅ£Ý9HQ¸;³õMänf}°ë\ÅŸÂðFþj¼1¡1†,µêá·ë$7¨'Qh%FÂÚ¦ wÜ?e@;WB--G[j®Y®•arDn,É>Õe™ëŽwv“áÛQbƒa\g¼+® ã]ÁÕ'…d ¦²J¾6fxµ™|ô}86æ­SñÈ­á#IÉŽ0º•#ÀwG±+}l·œñåà&¡ž®€:{# Û¯N[|Žó®=;,ŽŠˆ0Ìç@¯]X¥ëÝç½ã[O ÅœÀÖ”ÿÔàûºÎ«žÜ6?-TJÞÍú`h»g̓ÃöfÆŠ|£@}„Šþ¼˜IDá[¾G yp}&Q*Óo¯‹pbÌCÔE^Ã’ë0É£’ŒK®–›ÀËmÜèXWç×ýc̳}-åjá²Ý•†ç¹Âñ±FöSº”xÎï«·zB;;–i—X#^=Aã¸Öw×ñ ø·FðDfG }ö¸ïRÃgjÐ=BH›}N³>Ï:ÿq@´Ä é„X¼ŠîTŸÙQ^ôá0,PšBä"D—™]Á%ˆp·Ó“Ã?dá8"j 5E»äʰX?øâü…ä¸Éu”UA?WT>– þ4OCn,TØn4*©øð5F7›ÒX“+*GHøk¯Î£Æ¬¾œÓ½¸Ï& i“»Œa >PVrm“÷CÂã«Eï&k)l³™w6oŽŸ«'n1l^à+/1öB ÏßÅ&u±¶ÛAyáVU‹þ Bœ -iñì§ JD}Ú%À¤óL\r]õÂ. .C_E}!'¤¬l‰¿¾VŠøTædµ"q-»FÈprz»u0ÆYovA‹mk\__·kJk¸ü³p²²÷x€»–›Q2Šßfê“ü›Å×ò©ÊÀžÊÃÏxå9+°fXw‡àŽÔøL™sÁúvâÏ £Ÿ·òêT°Qøµ\÷Ÿ7äè_i;„L„ËÖ¶äÆu¡‡-QaÐSú¹á²3Î|pÙÅ0±r·‰¾ŸöÝ_ˆ# »½P§ÊŸVáƒûâ»$¿rµ\Ã;pR`gý¢›¶É5*‹ÍÞ}wÃA¨!Äo4T Ì«t£t·2é%âL-0ËG÷}³_MÜ–AQÈQ(!+}Ë‹p4ÝÁtçßTè;—[F_gÍ:§" ƒœû‡0 H–)W [ÎQT‰ßz ?±õF¶Ç÷§[¢|® ‘¨13߃ ‘ °Á0 ©‹íÂ.?!ØTc²myg¥h“اhâä•CkñÒeùeÔÄxÃöïÒádç0dÅ‘¯Ë(VY­g@£ùyý„áÎr- 5Å+Á{·-‚ó·Wÿä®ÔõæïòA]0óæqÛJ÷ò­¸‡ÃÊŸÒiÒ\|@VÉÊLZäÕ]>ê•ûPEf“[®¦¦•«™Z®¡ýÌ·½ÅùKëž.Oï3¦:ÛÅ\HiF9Í}jG€A®_õn_@ô~q^¶€|9]"Ô å)p¯‚ùa>?‘µ8ðB•xniVi÷­„ ã…ï½C–øÖB}'JA•‚ô»Ý}pýù÷//Ì„VJ–-ß“oAC›yŸd€˜âhD+¥³ŒÂIö TŽÃZ×KÞøuçP¬¯¿=Q޲éߦî_ü=Èoré=Fr„w^T@«¿YþLôªmPqeñ§ï‚ •‡-ð:{¢‚V…ñ…Ùrœ¢¦Jie9žQÌ'ÝA_…î ~ö}Ķ·-´AP ßõ̇]±•çAic(€ÉÑ=GóÓ ¶"¯?·ÁÞ\r¢_ð—%+›ç·fu.Ö@K”òÒ÷ûÒæêêz"}ßòÎBDêp;?5…¬ÁB§øYÁ0~F5‹yßc~w`¦1~³ZÚ¸À²”‰nºùKï/ ïæú¨y¼…‹`rlq9Ucy×ä¨=ïÙW›ýŠOå¾›­6d§^ $ú`‚Ä{ñ— “#}§.štbµõ³«oÞ.]‚ÐòýÓúw/°Pæ»JKò+œ{»\C{ˆ·,Ѩ¾•Tàk8ÝüC™R°°íìIÜ —[ i`Á’‘ò{i¶þѹ›¤=ñÔ€h3)_4á&«ÃA`~Ä^Ü^97Ó+áo´-³È£qÝ厶7Ïá{Ë]3!|pWœ?d‡ð!öæè££Ï´:.µF€KKXA¶Ö¤Š"ÕëXk^¨5 Æ…ùÜZô\›€™‰‘\õ°œÙuQ*äÄP…ÛˆUr€¯[±µÚ¨ÌõX¨yn.­E%Cµ›šÅ·Ò`:Ö«y€‰c[ N]Yþ´!@ú·¬Žó/Šz©7% SØc@WÛ5üÀVá’ìÇßïóì•NOÀ’玻LøŒÚ*“™²œ ç¶þn5Î\™ Ýà¼Ð±=ËóC¸°šHŒïFfb)Ü­9!UâN. .ý‘õ29äbÑ f[êE9ûºx°\GñyS‡ë¼¶Ú„¿ÎÅÒÍè W׈€y¬XWÚ —. Óa–Nwü£hœò÷X?BÓÞšOôüMèÉÁÞè“oeåÐú'΢c[ˆjRºpå—SúÈw?ÐÛmÙ)æÒ‚•½P ¬ChœòJhËjÎw?oéÂPCC)Š'¢=Íq9VÝ¡›ó/LE"eÃyë–•£6Ô—%êáY5šq… –lYY˜§!–kH!œ¤Í*Ú©ôUx˜NÊLDÉNGv%zFßÂßCõQH°Ü¶¸n n%ÛšßR9f@½ˆ£'Nd£ÂW¯ØõlHä)çç°ìÆß’12êh)Û0tž­ø)Ð5“¤·‚â¯Â¹8µMñÍÏd@öGÍ×Ͼ¼^"Þ‹u(ù5q_}{ü‡œLkû|2×ÞØ pÕ4B|Ú¹#™bN¿<(à–ÀR—93 7õ¸Ï¦ô–œb«9eìö¾Ú%àNI#¸¡+º¡2RáIö#8I1çEPý ;ÜyFõÛ¼3ól*¦_)aÂÌïqºèêzê~ ﵇g‰4_ÔIoî͇Û@ý”p’;P“×+þœJÞ­0E?ÅYßée/Ks™ÚþJÓíñýd&|‹»šXüÀáo È%KZìÊOF6¶4ÖšO"ßÌ•ô'DVËJD0ó¤îxñì¶^jÎë?^!ö#k%9^ªÜ鯝DÃE3·Î„Ë]ËìCP£M@–fÁhÖ"6³ö¡&‡~%ÖýÕ*"(œ™M&©¹(ô8¡ Y»U¶ð̤ÈZªg?º òç ¿Ë/&ŠR<˜ØáÙDšÿ±ØI . ÒÜOØŽU ìž?”Ødk Ô,gˆ`˜Ñj½dÉ4l“Ö¤<`À2òŽc~0ðËÉAæyðžp¤”¿ŒjX*ÈŽþ7ù ƒPsº­}ÒLî[D¼fq®ß~œÓ«tšZPEtå\€¢á‘ÇFßZlƾ³PŽ£uôy³ÏÔN^ž*ÂtÎX.‡åÿ%?kñì=Ô8 ìØý#dÑ$ËŒ? ´ÈåªB™òÌöYb¹ñœT«”­m¯siñô@ú0Ì€taãA‚ÌP9Ŷ³-_EßC§þÕËQä|Û2…þIºi ú]˜Fùowdßc»×:’jã3ª}YáYDo—o^ ›ïòü¤»&£€ß:˜Oµr1„Ò :'Ž!ƘõêGS Í€Eo®©Áy vCŒ’9I?U.l™!ıÚeg°éÂü%>\ýCvRÍú¹ÜWWåHËíÍhŸë‹Uÿ¦Q›ŠQ$¹}9ÇUObEõ¼åÖ‘¯l:Ÿ³rÜ ¯WöäƒPO¤Œ>?ho6s'!w$<‹ÄÕ@¼×8°~Gs³RšEçµW}‘ü¶g}(B¶rÜi,Ä/ù_=eðLRˆ˜œœ€}']Š7Ä/ý‡.lü|ÇV?c7ÕoŜœvàl/{b¨ll4(vv© O¹ 'jmb¤ÔÏÙÞŸÞúƲû~gì‹ìHfšùí”)'bðñYî@7p=Liqñk¦ú¢ £L~ÀÜòó0ðësG‹^™Ôħç€ÿ:Û÷GÇ)X,|.QD8;‘(±²ð¶à5ȸˆ8+Ün84@©%ßÃó}F¯âÊØÐÓ 4 ƽ,—*$`lŸ^Ê¡ /—>%\3¿È:¥¾ŒœÉ"‘Ò“©VöW+O»ÌÐåŠ"'²±òÇ© dº+”àÆÚÊ–>->š”Fƒ=J¥óåÌÇ`­8­l—sdŽóBtàkþ¨.OöýxÅ'loFÝjÕ¢ywÀò ×Íe†ý¨Øþ [8ëý8\©éÑ3àíθ~—Ьà±{u©æ%—=ò š;WÅ#´ÞûÀÞ‰”Io7‹3H]AµuÅ"ý,*z,‡Ù3(ëÕM,“ŠK<&Á÷ —ûbñÂk´¶FjTbp›´Ç·ÑjË¢àßÃ@RÛuv—÷{Q‘ZrŠ…ì­ûá6XîIóøD‹·{>bzò„¸}s*`¦´ž§5­ HG¾ô@ßA1]¥­‰R_›Ù‘¹ cízU?b\‹ôýòÈᜲÑE°¸¨`heàÁ ðõÐØ»%hÆ4à/_½K|ЦɤBFW¿yì€ÎK;çiz½ÈDm,JºóئcÏü>§—§6øÌö Mç+F¥1 Þ– ÈØÎìéº&é%3Ý §a!úzQG¸&á2i¸)ÄÄcònºð]mT"0Ç\U»Ô¢:°ÿÈÍ‹¸„‹*¾á ð6¿h¯ïh·Â[Œ¬™O§ŠÈIÅ…G­ f­–ùêätuƒu^¯‰ïx}Uã ¶kËìiÕ€žU²~4Ú$aYuŸ¼Õ½´¹å5u¯¢¤Ê!À¡ ãs }Ȇ±{íg §{mkN–oÇ&SfòºþÆkÇFc3©K¤éiœù£Ê3®™ß¨˜ªÔà8¾&w;€,ñ:î±ÉóÎäÏ uiÌK,˜µŠ"a±¿<øOãYPf¨8„:†šŠ³&¿ÄˆóÁðUI ½þ‰]õ–Cê?@UÕ4Qñª›ïmp½¤dôÚ¬«5!öRø¬qyú¨[DŸÏ£™@› ùsr©ùE’¼âÝÎÎ+¥oÛ츕¯ˆ]€ò)èÈ*ÚŸFLƒöWž{!Zܰh(®“Än “C;ö º2¶.†Ÿ~ç­9w·!Ó¬onwCËÎ]‚?{ØÝJ³RÞüQ/[>dËQ:¸©¶ŽÕî,‰Õªc›xªFk}‰‹èHÙRT.³’½Ož›Uñ—¾M#….,`Ï=âJ«˜˨p€Ta¼·¾_JþLìGÍOfMj7¤5ïXå˜ê+y½¤å§mÞvÏ.‹¹n`ݘÖâ²ÒÍ„ÕÛ8b)KšòîîÛ=­×İâ”-È! Ñ88;º„Ô 1"p˜àJ÷¼¿ý™cfú teÓj6SØ< ’§üdºu }¹:d³íÃØp—d[BÖ±~Þ9³×<# 1WÉÕÑZi4´ ˜8Ë‹Õx-2y‚Z|…Ãq¾³³öLLN\^9Ò)æ· úí·" RdÀÚkÅ«R¦P%K­Ò±ÒÙ})Jr5 ?ù=ŽŠË£¹h©žÚüGVg´ôôÆzŽ_€]#;-›ÈDØLùdÁñ ™ ¿Î—ȪŲ\‹ñx댱NÄ6(lÙB¼q+m×#”PàïÕò²°00³™Ï;ªƒ5µoÈÔ.è0-HÌÍäº#nh©¢°ûYÏ—R§>ö1e&ÖñüRãZ<&`åwôÓH•¨ûksvk¯%ƒh&اŠÅÕtõ¼6hàæuáfD™áOí.Ûºý,Û"¯¼ÂkÓGt–y/mÈ,·ŽiZÔ… Bϸ¯ êºäÚ#;fk yÃ*+͵ÎÉ?Í1ïò„9;>` ±dwà¶ÛOSÅ%á ™µ—S*KÇ2O¿Vlµ˜¾f¿¥LÒC †ÙÔ@‹°OÅÿFÖ= \Q›¸ŽË MXÄCo 8;›a‚Œº‚Âäâ]Þ[ß <ÒZë!©žÅ=\sŒ±§m~Då£HÆ#¹’À©8£ö‡h<áÎ7–°Á4ßœ ¡ îÄÖ$@»} WÕ,t6Áb‘33îÖœ\ýRù XˆùÒ[ Zb‹Çª÷ŒYî³é=]/W”“Á ômŸMY®?1?ÞûóSã»òä Õ9TZÆzøx=°ˆª#(*vP)ñr…f:§~feNû•†"®DJ`…¸Ñ›'¶Æä³ïþE†zʵr+jÃÕõÉ"ó@Ž|ìðxvD²Ó@!¾„ý¤û0¥ fäRZ¤]4É3Ó±ìµÚâ«‘û2|\À­†äª†ÔÇ(ü‹¡”u k)Iˆ$ì,ç ˜ÿn1Š¿¼EŸAЭXgk @W?}³¹û¾š§0õ±Ð2¼l…êËÑK@Â7æY)+]w·W `K°ÜM{ð#pÄû5†áS`Ù¾ ØåÈ N|lKd=uÝàÔ¥ˆ©4ïDÕ|Ñœ*ahž€q[_d^*Œö&#ˆ=%G_ÿàĪ=}ì+UÂ5tøa[Ëaצ‡ÓJGý׎LœFÈ»_g=A-’ÅÒÚ—JB3Bx=ç¢÷òÖ®9£‡Ý'æ¿–°*I‚.Q$Yt ­v`'r—GÖîÿ?vÎ*.ª/Š÷tw;„  J)HƒÈ H ‚ÒÝ’*%Ò (=t Ò]ÒHKˆxç ÿûtïç~îÓý܇á‘óٳ㬵öo¯½ÎuìF08öJÂÁw1¯û¼m„¸8N•ü9…^ Ój¦H7t®mJÑk„¾dQŒýƒHGxlñÃKûô,'ì¼çµ·Â·ÛIçmÊ}ÇdUä™ÿ¨ÿ4fpTšºølUi³ç*§`I5+½Í'ùü|߆æ€À¿äêð*#[_IËÿ»ã @„TÝAß8’e'8®Þ¾º¤*<¡I4€f“‡ÍÙó{ÉÕì¿¿AxÝã¥âƒ`_`Ý.Þ~ yæÎöH.6Ö%}¦­ æXO¬É¹E>ä°ÒÎÊ‹pKô’-3.ê»Þaª“*è‰ æõá¢\… <°GMæ“>?%¬âù@e¢¤,œ=<¹´dbW0Gë*!›WÎN8!ì(¾ëžü}æ^ÛãÏV\w•›%Î+§£÷»-œõvŒ*úú|JO^„ÜVÒPrHŽíë=ú«S•Nn$5X™£®wOcWnE²NÇ,!W6ªÏ'd —[£5»Û@g\çWV¢.üIìEµåòÅ™/bÄæ¤™ãßÞ÷4—ãÆä¸&}·ØT¿ç"½WœÂöD ¥cõsu²?î`l¯œž×º ^ÇEõACÀÚ3øêã•ìÜß„’ñ†è~†ÄÊ{ÝC5À_WË›/ !§¢õ–5T[Ú¤u‰ßŸŽN8Öeæ¤0Õ©Í’ÖëjfˆÐUDg…3ê+U”á ‹¢ŒS(•âD8dÎT<˜DDE¢eÞäHqº] *h'ØÑ*…Lø-½ýiIÃD‚\qã:B€6ˆŒ%(>Ø\“#Šv ÊÝõ™ºÊÕ¬Û{ø¹õ˜ùÄW `—æaÈ„GN“SékD~ ù:Ýößm|˜  ?ø€á »ï“–”UÀ†O$ﳬ+ ï<^™‡.Û¿ãËpYåÆ)*(ÝV •©c'¨ÇSk`Þ¯“Ò´©£“?]o™¾MùHànSØûƒR·Õà¸nš*2g£wT.ãæVyûKK÷jP1l¸ÇÕ&säCöŠE¬Kk<€K³¶Þݬbqù*8»¶UÀ©k×Eþ_ó?KëŸ`Pûƒ:BT…[º:™²¶ôš“¹"esÈ:ÎâãàÂrè93L`Ý_9>mËb… O‡¶¶l—Ô±bWQ5y¨™ÁK¿&äù4SÇlîÌ2F|3ññ†#Ã'—Èþ`^ñQ©DY¨ çµ[QÉ}²_83îSÈÈß½~Cksź¡ƒÁ3»nè`7",ÏÂM gÅ!§MÕ¿>Ÿ÷ÊóýÀVi*î„ÊÙlSü(`4þ™£G%ùLëŠw3¾§V •ß.Ìe­ëÁvˆÑξßCd®uÿÎ6k¯Ý‘éÊÕöÈIèF˜û“s…})C¨³Û‰­e¤•Bø wÿ*6A©¬“çG ’yªôÓÔÝ…©Œ˜÷e¯…sªõ¾ Xm RÅ}xBAq/là[Twñ)èêe©x4Ô7p°H6ågÍuàûÎ(Ysn1šÿ ¬@ŵö©´oyL†à tòN/,ò»yŸØ t»IÇå‰PU©Ø¿x±{dækéGó½¨+ÆËYË{;RJÕãt¼RÉ¢í)‚KPNä“´#œû¨×M_°¢ßm÷f~F¢1œ<Ì®&šè~kë"úðç‰kW©QÎwI’êS1G4ù¡ÇŠƒ„ý‚©ž'ÀÌ#M.çðÓY©d›S§Â’‹àá‡*nõ×bm¬ëv?§Ó’(ú3t}ÛŸ©•úñÏòK¨Ÿ?Z ü§Aüñkããr0Púô!ë­¨›ŒÉiò„ŸG=Š fÓõiOæž•`¢™0|鯑¤¹Ý{ØqÍO°ÊÕJFäï™þÛ"±ŽÊõ ÕB6ÎYú~‡eíÒ““Ã<óë ;ZqlmðÚÄ­?x0¼¿Q‚¥Ykf½_Ûšçk¾.²¿GªgËþ¼Æ"âvMZ:D”™…0¦4£>!d{ç¶gr]Sõƒí~¦%o?V¸¾¥µ”™ÏÎGy4¦­=¥‹xV›Ë¿'ñGꟙ2žý{-fˆæ¨ñ™É߯~Ñ2%;EȘjÁùì_¯k@%öÛ]étÀ˜Ó¦z-œ×m̨º¶£E¸K6õc~¼‡¶6f6¹ÕÞÔmkµ €†P³€`ïH¥i@ÜÒït›6ÄüÝì1Š¡Þki*òŒ_ƒŽòfýµÎ]H²M}Þ|ɽgËu.™wx|³&ÜÝW)9Ÿ=߀òlX~{°aŽàöù­“®?—Díƒ J”Ø M.5PÈçD©˜g%}À.©G€ç/þñÖóÌÌ–ˆ(¤Ä«÷Ž€4D/ÈsÓÆm…¥žïÏ" WjŸÅVÑ %®¼5Ó²+þ(¬ý:· –{=• ±ù…§ˆS¼p§Äão*‡$;+²óɵb½KÏ7qp°EQ¨ËU×cª´îY?@!@m,³ÉMÍY¹t–‰«Œ†/)Ë䃉|v™Pae>ºQ6ÖSAú…!×:ÆýT­v§B‹k+.„õÔU4³[´¼%ëÑÑtºí„³ø´Ôvv ñž5ÓdªÖÐËA¤¦x…[u§ÂžƒqX9ëQµ×‘8†R}¬xrÙj¼öƒÆáV á¼ÍûX* µy/í|À¿%•ÌûhQ/DIæà5gY§VÂLÇíÃ(”~ðqÊrbÃâÆŽ­¿1‹ÐÿJ€¯éï.])ázszÂàÌMÖSb¨Ÿ„QdŽYiQnØjE•¶IoÌǩłü–]ùbé @>¤;?ó¦ph>08F^2 ¦VÓ<-ˆW ¼Wáår›é½¦ihÔ 92+ÍL&+{¿äRºõÐKõOk÷œ 5¯H³$õ}vn•ö¡h`yÉ…ßðÝK$:s–i¥]õ_Êæ7óvÀÀ° ‚o``ËÍYUŸÚ0dãÿ``à|ÎaÊõÄŠ•®g5…ýT‘æ²G¢Š%÷‡°2‡uúDYNRUÁ ãàåƒZß+oOó{ï„Ã7Ý×¹G!ot‹{{Ð÷㪢%x²LoÞµŠþT%„¡Ãæ¢VÛúýu&Ô?MóN^™ý6Ÿšî†¯œaŠ¿°[¦,ãô?±¿)ërRìÄmÈó4ÜŽ÷îlH¶”À»iý²tmEEµý؈®ÁˆŒ!LJe·RÚ̧¡-¸¢-ÇJ!%¤7{ Q¾¯êy}¥3<®ôŽ‘µvQV×Ö—óã› (ßQC-¡Áíd ê?Iuݸ½d@(ú´Ç šî*æmò(eæ»®r¬Ÿ xHrßÛhØËf%T£û×è|Ü×ÉJfO8ݼú£Oû„~SQÿ™z¥{¡ž*hY¦åÚçÖ_äŽÊùFü²zðî[ öƒ?ÔªÛÜ+œ†åò.:q lèî½øëJÊ ÕÑ2®ZKíó¡v„[G- €4´Ý§‹KKüÍO‹ÃeÆ=Ÿ~E*‡bäºiÙXõzfÒikìi¶œ‚ö ²¯.>¢'Aù°¼ðrj k¤Ü½ F­Sí©SjøÃ÷‰í¦È…q©¥c‡ss¾SÂ*ão&­á çhLsò0-«øˆ‰ÜŸÃ-'¦aiz˜æáD¤ƒÆFÚŸRÃYä˜Äôyæ7|çÞ»»I~È<Û=ãï„ÔßÙà7¬ð¾\ éG¾táùœÂÈÕWZŸ~í‹ÙÓ42Õp(±¶ÉÛ;>›ÜW=œe5R0#ãåzéySbÙ[QÙ﻽Òìæô´¿ÛáG­ç—ý1 pEËãE·ÏÉf.pÂû–„éÌ/êßÂB@¬V#ŸQZvߣödN’{¹’{Í@.gV6HÇ7ðÕMÂ2¾P¼Ön;×5³:÷H.Â1 Ob îJÛa0Aêlá„3wVÈioïÙê±Øþ3I+UX<[ºspö] zJ2¸V,uèýà]ÐÜ÷û sr8Á®ƒÔ÷Nd™–k¦{Îz©}^ƒP°€€‰M¿¢\i=ë‹8«[åÊH‰ñi1M›FPyÂD¶)Q˜õ2ƒ,&a$‹§9-3éN¯îî#ð ²pW-Þœ–øË44¶7 #¥ ÙØ«Ùê˜ÒÎxM¨A¬^ðÑz|y|ëó‡·.ÿ¾a¶Co¿žŒÈ/hÒ{̃`gªY[^†¯?°›©©FÕÅe^$—¨³á>ªÓ`wñì'à ¬ó{k [Q“²úÞ{’›Ó*Ö€xÛ•ÔxôBüdÉTÙƒÀîå›< ®·lÒÕ^ ²R:T¶ÐJ8«¸oˆÐùâ4Á»Æj ø$évs×iô°Nãij~Ý^& ñ"‚cû¨éV0ðJOƒ=ü;Ù„dk”Éþ£€i5Àgÿ±é ²ï ef#¤õ‹n÷t+AÈÒ[-¾òDùÚ"ãóÈ´‘âm®dø ½Ê{4ëšìèv`·ßþn/|Š£Ã ý%n&ñÝÑ¡¿I»w†Já˜O I I]‘ÆxR¿÷ìäUÎøCÕÏýétÓ:÷KÈ;WÓd%ì}Ñw&ɼð@{xÊ3:>Tºë¯Ò}¿²Ú ò¤ ³%¿õz¹†‚ŸìЈfQ_`Õº÷dìžV¹a¦SÌ餂ޖ%èÕ§÷Š v!%iÞ«ýìï,‚f«tıÑ鳫ç¢éJ+Ñx>(sk^.9VP×ä°ÇZ™´q¢8)L5‰ Ñ /Ù¹\•øvÚ[ø^RœU¼^õ#Å7£* j™XHº±ÇÞ‰X‡Ð±k(‘z[Xkƃ9á#ðqµ·ÁG€½ç]_)™>¢‘OÖÇtO½Û³ËëòÆhú/ÀõÀ嬥„–éªèyàös‚8'ûí£§ Žþ¾ÿ1tbÅuó^BÅ×W9Žþé«jbÏT)˜Êœ?O¨³ÿ-Ž"ºŒÖÕ_¯Õö0aÞÆ÷´VXa Ç {¼¢*T#÷•À/ñToëø«wû°Ó)í0Ö„­O£å`è³·_xVgfW­Äj-12žX„Q¹ö÷|Enç\³’÷_&ywhp0RþUB4&ÏU–l|Þ£×YDZóÑbU;|‚`¢@¦ú«mÔ«¥ïRÓ«ÆÚÌmЍëš8øŸf,GoÖA¤¿ºÜ}RÛã˜Ñ¹QÔÆá½ÉêEÐÄ%û.[¬ìAç Vcâ„KBöÂ`*RúßÁé'.…–y]Å‚²YÚƒ:“¹{j-!(1î2ѽOph'oÙÇrV3a„±8‡ÁuÀ—°L€š4]RXh¦²;Ó1=B„§§"m–P 6¿ oB›Ë&hr0®˜p0X_L·f—…9nQ'ñoøëwCϵ÷6=‹ó¥NÅ 5p”}É'Þ“žp“€Ùb”÷ŒV>V¾¨56ósBeð䳦¼Qî@`„Ïél‹”Åð8ά‚œ|•âR½ ÙD ¯›Î“oɤ•–õOÓBbbŠ3`Cô+ü0„<÷ÆR“³«‹=´Ç‹· .9¨žœ}wÒcþþ´•Íœûã,snlö*T4á36_Óàš¨[ú±†j|Ö¢]§²ÈÇÿâK`ŸÇÌ.¼â×xãÒK~;¯[µ5 ÍNë.gNí@‡Ç˜Ž^w‰<‡Êÿ´ô4B>Oô™öñ1îõÒÇ&@8{¶4‰ïm³Å ½*Ÿ/ÔżíÄ´P¢K” •Ló§°‚F/,¹?”¡4Ÿ´”Ÿìá ²¤*×(cÞ áyM7º‡½;ª!¹}W²Ëª@SÔ—éW—š°ZÄ#~ybçÏÑû颚½Ñò¶úß$%zéêÃRÕ˜È ˆüNsYs‚9ê¼ôþh^1”/p 8·€Ô<¦ÂY„n×"±ÖÜžžÇâè~iÔ ³Â3û1VÈ#ˆ Uó™•òžƒŠzíëiVÒèaAuWUwýqùÞ̨ãÒôú1»%äñ~Q¥šªT*–±fÇ Âw6Ó1,66߀ø"…/<ƒž°Jý éŽtàú3Ú‡»”ñÚ ‡ˆÔ `38æÚGµkÔ> Ê„ï©±Þ JkÖ‰üY} µW<ïõ¾þÉ 1qÞ+ºÏ FW.ÿHäµâ|˜{Pi}¯ÆÒç2{6ìD' 2_¼Á¬2,|%eÛ«räÐÛr_mçý÷]Ÿ±€3%{³¦mžýB]†Ç,JÉF[cb’ó–•´ÉÏÔ@6(n<‰C*vöÀ£}çãHÆäPÙÚ‹§;ç&%68§©V$ ×ä|²Á8Š£e{\ê^ĸ+pˆT¦›"ÊŸÿ¤¨8Ì—ôµQêÈGä5Öû€Qù>{牶[C“+I¹=·Ýr¡!«¹ÜÕ F6½ÃXîÉæ7ŸÑµ¦‰ÝQ×Ðm°¿Žš9 ¤:ð Nªèû‚r„bö‰:®ö¬ ëO«c±®SRus©äû˜R®o&†ØÞò£t.×1 ši˜ÐXëÁ–`SOßö‹¹Ém_“ÚͰz@äôœšËÉE;ó°´ÊiþW4’g2—û9Úìü±š±P.ýÙXun²£[çBojäcŠCÖ >Üù‡—¥x·Ã"K†­3L ¼wn]Þ–z¢“ &Ü™ôÊ ÿC]¹t³ò^¨¢lÐÏÙ.@Í·ÌÚR¼s3¾Ÿ)6®Éa:¾¿\!//þQRóæ& e€²É üÛ /Òj(¤¿pËÜšIœÿSw³éÄTøv¼Óh$v½Ï—¹ãÔŒ›ÑFþé%ðeÒK%TkÝë“úkÊæ:§eG'àÇÚ×Ö I:ŸfCôëšÇΫÅß΃bÉPÅ2(å-¶Én>OÄ#… Dx¶-7‡ÊIýóQÇþ:/Rá-XBaÃWyØÐI½’4'óü`9tn·´K[à 6sfn:m ß‚eU¼nÖ -W6ÄÞNü´¾Ê´2[@þøgIG:cÍ'ʽ<ƒJšË"šuþ¤3qQ µRY¨{þœÑÜã°Y6Ãæ<8¡Eij/gC_`ï#•Qßw™ü²¯-äë¡ÒE;,5 ªßAÔa¤l µ!¼úôGìè§çïy2÷xÞR»ŸÅžÚjnØg_¤9îaâ `›…·eA²qF3™“A3ÝŸ£óMÿE>¯u ’ÿì‘Üe$Œñ¸þ—üD¹!¼éÈqBÁë bìošñÀÈÃ'ÎYˆ}ë’T=5h¬×Ï=»qS‘œ7%¥^¥ÁŸ¡cÇn}½Lî‰fç¾|Ú¼»ßœWh^¸™þ ÒDú"ð³‹þ+¢<¼U×P8×ÿ&Ýx•±BøIšÀAm?MYÿ~¨ô÷²šÁK!¹=ïlqÛ’ç/þ³ñ­0C‘¤÷¸$´×°U ],›Ì%è&Ô#l)ÒûöÌmLªe“œmö+_»fÿì8˃æ*_ÓDP‘˜S¸ÓŸ¶ÌÙ/MVçáÀ¾ºâOþ²çþxÑ©Ÿí4°0N®æpƒvŒYÃØ´ø‚Ø¡ÀãK¶,iwƒ hÐÜ•œrãÉ#(+Bû#ßúŠP[¹xô‘¨à:–BÉÜ1!7ý¹Á¼¡Š¶§VÒ!a-¢…þp¾a•ù ø¸÷eì1yyæRŽ7‘د«Ê‘³ëë¶8—Jè%½ÕAðÂÞíëêW}±˜‘-ªÎ¼ ¡s«ªyýÄ Wn£Bå­dšÉ¦ôtoѯO­Ý¿ÈÇ¿¯Fûî}0å»,vïPx·EÉyG*]VÒL·²ñqØ4GÙØd¦uÕdÇs]>µ1¤_B% 5$É©}n>è¸.ôl:œNÚn±ÁY,½÷Øu&Œp¹w•þbaøX’Èfqd¤7PÁ>®'Ÿ>ÉbîáÓ÷f–®¯°¬/tõä~þOþëÿ%ÿWH,Ìoñò%¿¸°¿€°0?ÿK1Q±—âbææü‚à—fÈš ˜ÿo³ÿgþ¯ˆ€€ÀÿÂÿBóÿ_ü¡ù¿hþ/šÿ‹æÿ¢ù¿hþ/šÿ‹æÿ¢ù¿hþ/šÿ‹æÿ¢ù¿hþ/šÿ‹æÿ¢ù¿hþ/šÿ‹æÿ¢ù¿hþ/šÿ‹æÿ¢ù¿hþ/šÿ‹æÿ¢ù¿hþ/šÿ‹æÿ¢ù¿hþ/šÿ‹æÿ¢ù¿hþ/šÿ‹æÿ¢ù¿hþ/šÿ‹æÿ¢ù¿hþ/šÿ‹æÿ¢ù¿hþ/šÿ‹æÿ¢ù¿hþ/šÿ‹æÿ¢ù¿hþ/šÿ‹æÿ¢ù¿hþ/šÿ‹æÿ¢ù¿hþ/šÿ‹æÿ¢ù¿hþ/šÿ‹æÿ¢ù¿hþ/šÿ‹æÿ¢ù¿hþ/šÿ‹æÿ¢ù¿hþ/šÿûÿ9ÿ÷noüžâ;h(Dœé¯¨ì½ :òS›œW÷¯•õh Y1ïR銦Õ7Ù¸yw?4´° ’ïxÌP¤bû~/f°îöG7ö+Þ’³×.0ýmÉӎͤÜDÅÿ`ïNá|ÿ€Û·Ÿ-cI–²„0c_F¶±d %¤BvI™”e”5di ²ïk¥„!K”u,C¶!ŒÊnügüßë\×9×yqÎyñš‡B&½(ä%JUÕ±™ÈI®»Å&çÔ2?=X-˜øs¼)âÅ‹ £ôòx“3(ÍÇݲ¯a~ðÒ^6ð÷hëa—¡J(h}7ò„˜¡a92Ã>ðÛ]IÂä.çÅܪ)3¸“HóÏWÃ]¾…Êôî¼WFB|›Háñ^&¨‰˜1#g¸#éLýRñÓ Gùöò¬ö¦VÎBåÁÝ&ÝMÐ÷0íþv§f³€q«¨ªÜŒÅÑõEb” HóMv´@Q²äÕmƒ7Œ§EvìÔîS“½¦î“HÌZLŠu¤!2=û^ÿ6e¢æ¯‚u·ÁTMæÐhÐáëåÀï +2N7j»_ ,Ó¹Ÿ™¹Þg¹°ÀF°X[<öTêÌÑáÉÕŒS†¥Éº÷g“0ÏMVÿøO–§dSk‚˜ø“ùb%Ž™vÆÒ4¦œR7-=.ÌÌb~Ù¯Gq«MX0QÎ7òu$dÑ™”µ«F jZ p·,AHp¨ÑÇ3]²§ XA[™Ëú²xn~ΫBêîÏ&×WöºLM¯&aþ:%1•.4~Æ£Æ/d&ú4¤HâT«Ö Û¼Ëôú±ÓmÉJMùÊ:Q÷3ÌHÔ× Èñ1|w¨Ç!‚«h‘‚W‘ச#Pfõ|"äY ízÿ{m[tï5fŸg•µh †§/úÊ%q2ˆ½XKù)b‘Dçe‹óbéÚî†Qö[°®û}Â"«¿¹;Üi½K\"G?v+I+þ:k…y£{ñÛoÂhÿ{•ŒƒÆÓ¼€Ë->-ÀmLo¤²ðkª+]«~ /1ȹ\~çØë¸-¡'ƒ3­!0¤Š×ÁNFnÒ„…DŠÖ,e7ßù`j“ý«6HÅ`ÊÑ\À32 V6üf ½çøƒ´º^hȇ£Ä58tÕW/µÛÍ\ùb{Ç7ŠïɹkÁ› î»zìNb;úß922:ÜK”Ömn ‡År(3L$=´à­ Ùfmm?èÊ,³wït̶‘çû£v È$†4·w뙹í>GæXOã‚Â#æ]iœ–t“Ê™E÷shè {ÇžY:Ž7ý0…|²[¿/K^2¬{çn’ø!a°Hœè…Ý0D™u,L$\›<ÿaO¬×:æ=ÛðFxq´P/"“}'?óôlªå‘;~8Ý©=Î×>°Š#Ô•ãÌ[—Y:y7ýð@&bWðA²Q²ïš.ÊUÍ# ÎúôÕ%A 3»ï~7 kã0á¡Õ£}ÅQæþ{¶S'Í,=¬=ÇLSçI1Lãò½†ŸÛÑ¢/g›«ãx\Ó´„l$Ôº`ŽHÃ*ײGI¨rß” ÿ½úebÅ·¸¦ú["…Ï2'(R0ƒæé‡ž¡Ò–êïá z]º.úZo‘œSéJKÚp®­7öù2³ù¨¨zÎA4dôbK}ý3Ò©`Ubá¶¿K[¦;éE˼{Q¿ŽhâeœE µ£‡ä¤KK²EÚÎ}“¸[³ñÒ3]ME‡ªÈH{låI*÷Î>qcšÎ×Fªí±›?ŸoG—õ…dhÚœžù¶ÎlÅaL¹ÿ¹c=·Û³oÐy·/×U^#wx•DHa¦Ñ¸/ú%¶T©¦g,xöî§6üÓôéʳøö®”Ö±þBÂãêB±Ûz]Ó s8_HÈ&á…|Qžâ¹êg}NÔè ¤ž[Ù™1${þ³hY\oÈþë™ÌWù(Ô n÷ó¿•ÆÕcÛA£Ó§mJúb¢%‚]m–UûÒÍó¹‰2´à“(¬Lä3¥wäZaÙ-®óâßžŠXQ~Ú‰y^o©6Îy a×ÅpÚ –-ÞRóÌ嫯¾Oà/¸Ö™ñ\_Ð íf>&å*ÄfÛ_ÿ¦¨Àz¢J91.Vo½B:íiÑAcöÆžHîn{”w>Õ3Z0Õ#eÐz"sv¬ÖÙÈ7€Åçǯ¥ z&Âæ­kmî…®‡¢*:÷ud«SW0¤tõ𿳩Ųˆ‹Ýdqà,¡•™·OdH$z´ë¹í>&%ävcMîgþk«Vv…ÉK]–ÿXÊñ ×ÜPt/›*:ýª£¥Nöˆ@õ»ðOJ³«~nÞ½Éþv¸ä½™fØAGñ‡QQ××Âv1ÄÀ—¶!#·Ò%(ð‹*ëèr›@i:I’. ôõ^Ôü·›üìÙ¯n¡|•C7zÅr„»{GýÜ%КõØ3ëÌxEr7‘LI×'¿’º`®~ܳ$¦ÉõòEËolr÷>@¶˜*S¿L8QèixBÊ„·¾#èÄÀ½ûwN1v¡Þ³dP&ë ÊXX@Þ9¸‘æN—`gýÜ0‹\®ï5É@Xë#—+v¤ÙÛüÎTj“á%%Q”,Iesâw5Þž,"wý+n땵¶Vq´Î‘y»¡ušêrÃÇÙfÐMR¹åW\ìÓ•=4}H ë3ü»[hv¥ jÞÿ¥j„fM—õ_>}w,1GSd~ç xïqK]žgåµ~vOI$§µ$(Ã*¯áaÝÄiKc$ãÑr•K´o ¿â¢‘~•ÏõÓŒ6;-M‘ZþºpƒóÕx‘Ñ^ÿ¾™$#ôº/b9N¿Coãûtå3²7=í½ðÏóñBµÿþ&¸>f˜ú(lЩ6áäÚˆ¯*m†ÔÃ-¹ïJ§=(ÀeWå ë—˜ƒÉïÈX씳xçþ-E…Ÿä‹¯M…2ø…7t¨bcÄ2Ó9,)|O¼-4r‘ÙÿíéÅUó™WxÏMd…¨û´Ê, %;sc¦ô–³²Øéµ=fr•Î|}0Ì¥ˆªx||2ØÝ d»ŒHsí¹ó»Ã«®¾›NY»hÀ¦_”U¿Uëw‡-EUvE& Š)Œ%»x1eyâ•Xó ‡x-«·‚Ók‡N,ªÒØ;ˆ}fNÝ6õÀtË߲χ)S¢­3ó0 £Å, äo9gR…¶ž«UÇ-\4îÞ×*!U¢”Òñ(®ã`Y¹¥hwã8¬d*7¯™Æ;C޼³½3Bf½É² EÌ#nýµ-å¹èþ¯G/ ¨œ~,ÁR2,=õr-Ö)Øæ,8 ©ÝJ2f¦ÝçÉû6D?¤º,wN0SŸ¤ k•rr@d™+?$-l¨à7»W=ØÝ?lC`¿¢½BÒó¡cß»1!”QR/NØé(ÿo àù>ÿMÿEâ${ßY,w_Ññž‚<ØÑÉIYAÎÉIA+:)ÞS+ß“¿ùOßñ_ø/Jr¥ÿè¿((þËÿÊø/€ÿø/€ÿø/€ÿø/€ÿø/€ÿø/€ÿø/€ÿø/€ÿø/€ÿø/€ÿø/€ÿø/€ÿø/€ÿø/€ÿø/€ÿø/€ÿø/€ÿø/€ÿø/€ÿø/€ÿø/€ÿø/€ÿø/€ÿø/€ÿø/€ÿø/€ÿø/€ÿø/€ÿø/€ÿø/€ÿø/€ÿø/€ÿø/€ÿø/€ÿø/€ÿø/€ÿø/€ÿø/€ÿø/€ÿø/€ÿø/€ÿø/ÿßýÃ'“l¸UÈ›¨¹» 'ÿà¯Ô”ŠƒÊMF Ååßœˆ9†G}™ï½1‰KêH7¼2ú©èÕ»ó™; ¦/¼¹6ÉÿOì¢ãDœ[ ¿™Ü¾=*'ÚYïCíuE%!J¤!1šZŸÁn Cp•=Ò°£/M¾Óår³±aƒ÷‰ (\¢n^¼óÓÍ>Êïl,ÏÊÙ¼9žèͰ_·àæF•pɰ —8\õiµCµS¡«ÄÖ˜=±l“qY"DÇ©"ÒM;,ªM»CûØg,¾zkâ×`7¦¿w’Ïš•ªNLó„}}+~¶`Eµíh%nVœ8ªO Q’åÓ^ø‚ÏsŠœé^3åÂkHz²"™¿ÿE¥(eçÙMy»;Üâ9Ó¢€+ÛCãÑ~ú»Ov;ÀÛÄX±ûзëá//Lˆmrñ™[Ðô~Ãfg€àhK˜áx·àßúK‘ƒÞ¡ cÍgGÏÈÓñ¦<7=MeéqvøM+j•BAñãu¬“ýˆ¨¼¢ˆì¶Åë=Æïøk’Ûz2ZTÔ-tý£Ä¶ñöï G÷Úåù\éY+PÉPÛõõ‰n-pÛÒ§arì2¿QjÁÂÏÞÕ¿‚ŒÚ²Ò SZ‹­õ•%ƒ«j¾Åûxƒ Ì“nY^²Â cݤZTõSöú…u}r¶æaâZÇ™ÏhŠFÌïåòršJ…ÓðñQ/”ƒp ÅšÌýð404sEŠð¹Þ˜+BÆ%ìÁ¼6Í%v½'< ú!ס4Óî²g-§#Tz9e9ƒ_š@qvxÀ—alr+–=“jb nv}ë°á Í¥+¹JG-Åu|¡ÓzØà˦†­—Í[o,ˆ"á1ôι!FGËavZlUs¿ÄSŒ×»S Ï#©Y-êÑÜÜ´@4n’á§©]\2wÕ˜' Ò´_©µ¦C$G„Ñ·EÝNL‘“+¢šBOx8fU'öpsî)j *òÄd2Z …‡˜™ª4 ð†gæxÒà†'dHú~-¦ìiAþz§ýN,ü7¾tØîHÿåþ×î=MóÄï¿1·€‘!Ù¿¤KÓ:à6¾AhRšRÚ‹|ÁZñE²WÿPšŒ^\Rײ?Ù‘e^ã£KއÄ3\“ L§\ þ‹: ˜ÄÖ>ø/ÇÙÂf|5" Õä‚eI~ŒY Á¯‘ÑUß,Sx£IFsÑF5~Þ3îÈ"ßö±^õ"f-×>Ž{ýÿ…b·ºèçûx±ãÖ’‹.pj½O…;Kê–/Þä©ð¾zów-5nÚÅ§í¤²¬®Y9æ@`Œ`û®ÿÊD¡š™drUFRö÷ð_2øÔLGOÁt3cÛoòã4Kòòåë"ÞdÓí°ÑÙŽaº að õÞ? ×Wa~Ò$øÃË:Wòœ8tÅUÚ-Táb^ÀÕB`ô£OıÒg²Óå™páº[ê˜~îûXUž¶Çij¾ŽÏ;å5B°Üà_÷ê*Á×çwzFI6WòÝ|¸6-qO^ܸ¤ÿ4#—ë¦Nõíe•š<½¡ƒ)ø§cz ýa‰”2…Ɔ¾·õÍ’äš¼4 À£Dõå«è“y'6Ü…Š/Ÿ<ç8í’¹Â#`uô]0*âƒi0(\/©>“ðn눮Îçªù$×9l®ôçýi-ñµ¸Ï´xËB®RrYäì6ÄA']åcý‘ïÕBVì¨ Ï[±@ýæ½sNãÈ𤫚Û®¨ý~ãÀ´'Ãkrî=æn.>.K`¬Öà‘¢Åš˜ÂÅùÏ-x/Qt-»{ˆþZ¯ÇK²÷—ž)ÞàWgz$©?® ^AMí»õ‚×’ˆ¥b›éÞà±”–û €i|ÞI/ày$^®÷1ªxð)OIOÁÜÿ륃ôŠÏmMÛ±Ýl41Þ˦Ê×n>r Û-¬ínj"ŽV¥½¶tÙºîIû(²ÍRz¨›_Úm~8B2|'¤]A@9jõü£žaºr\7ç nÓ¡âDìšÁö0²Uäf¨6%(”câåT·)榖öšqÊ]ì–MŸÞ ž»ç•¦M4îüš:ÿ±³^·êlžíršn÷ÛN#cÄšúÛ_€ÞDwôÆ¥óù³;OšZFÆæ ÀÍÂí§ø¼Ú€ñ‘‹oë}—‡¿\ÌM4põ<~ìĽpdS¡Tt.¦s±ø®ªòìNãËbKÕäPz¯¦²fä|P¾ålvତ²™´Vž†&l§îõ ïª ¾Ì§>•ÁÜx·ÄÇ”èGô܇ ë7?áALnmg,-ÇSFSù~-Ùê8q‰1wèØ;ð×1ëá_@` ØÌXæX²æ‘ Ökä˜8Ä%T/Ôû´S[ë‚”OeÁÞ3h£ß¼ éÉ„ë‘óaÒNšÿm"ÔLö³Ì|\ICrÕc÷N´ƒ´™¤|°|¤ÁÇ£³ž#q±zM~­ Òå/4n^…Râ¢#ÿÏ!¤µƒ§ç¬ElnÊÂfÏ|Ð}?5Ûÿ†º~á(ú3úV¡›é¸Î5J¾Ñ9Çüp¼ÊëC«³Ò(ÔmRfÿ½ÜCJH.ÆÂA O(+l}}ŒElöÓ$p4X#*î7oϦ«ØUAÕEÙ£÷pRˆ@%R€i¿´úœ0\Ï¡󪞬R¶#™ÿý¾øZ|rùñ"†‹c‹|)2¿ºXS R-:˜ÇG_›ËÚÅSY4¬}JøÇglJøY š¡Ðrž¼X1ÿèqCÏO@—’c†ø(Qš12{t.öÁæ@e›1„caß·5®5 9M¬Ëë"ñ3­8m0ÑÀÚ-t:Ë^„--+ðX?z̼ø#ƒúS-×q–tœ0gËo£îø'à)Í=ÿÎ(Çõ츜58m7pú1ÅJÇcòÞ•˜ÜîÜ›ÇÍ·²Èyè[s0hÌU×´„ØSšc=<Ö «»Ã]*¡¸L>3t‘¼Åîr"ýri’ÿ¹Vc+&çãø$1LÀÍ3Jc÷BŠzÚÙ ¿ÜpZJc7P+j^à V1ÜT­éUžÿ8|¶šŠ\Œ:—õ\±.<¡z2Ì•Í0ªÒœýÃU›õ@½'‘¨éC…Z t—HÖ@„3¿12f*¦µÚ"Û¿\Å ÐÊR¥uɶT¯?ZžÞW ï–X_³'Å^›kk€œ4¶ZMؽA(¡æüÄÄt(o~ÔªþjlH/­kµÒ̾㘗෤KÝ4zïkãcÕ€GW‰2ì×#=qáë& xoZ‚jœòBAm«‘ß^Û>•~‹ wxRÖÞ2z5o¹^û(-dÉdá’d8ë¡É™¨ÐGÿ†Ÿw‘ ]Z²„³ôË{lj· ¸1º=ô¦ÉÒH­Vl5PšÀ:žbêæ’!õør@!t[,&>3±¾oÅûïZ†pöi:Çm#1¬ç‰¡TºŽ¡Êö$ð©.Ö®3Ié¿t0ó[ ­ôHEÕÓ{‚Á¼òâ×ÿïfŒæÎ#w"ð|òÏð¦Òx{âJ3¡û`Ç»e^ƒ‘šÈ=÷wÅJfy…7¤«ÁqD¹w¹XÄiˆïe@…²â)©s;?T¨üXP8¿#ýd,E¹2)ö¤‹Ã#Wgì…å1ëºóšÂjW‰ÝlAŸ_ojŒÏY¥ƒSGö’ס¡”î¥ü÷úßÔ5÷Ü(K¡ÒúïR¯¤ÒÉlæP ãFõ_âbSfR0|áNŠ!p«]’¬ú}<-ÁÿR¹I”x†LíÉb_±‘‹"Ÿ¶·×I-M2%çåàýfç ¸Z3L²Åb…$À?th½7p¿¶ùa ÈLéy«cÿ ¶EÝYëãøø•-52Ï8± %c ;þ€ZK—OÅ÷õZß½¿ÁJÇdú6O¸~(V “½4¸"U|jÀÒ3cl6´N5ü{0¼¡ˆýwNtnL£“½’æ<à&"gìp³’®ô'_RS[ŠÜ‚l|â"ÛÓRü{X›²K7ñÑ}Aö)¦Iª_+~ÒÍÔ†.&ã–C=)?¡g—TÃ6è„~¶ âðÏ!÷¦4“Õ¶èˆbÈ\ëÕÙø¸w#ÌþBö"u!j*vp'zNÐÓ¿PXŠÈØ2¨í!áP|¹zÛŽ…½”ƒÄÅÉpÜšëã?¶êŸ“–>šQ¿¢­¯”Ãc7g/:˜ÛZð£U°žÙ/¯˜K;çÊhÕ¶þææÆà§P·–“£­*ü=Á Ú©«ÏÖapÛ¾ˆô0m½¼À >³ 0Øsd)á/C4ª5dT.DÓÝNxWEðbÙ;îg-„Gôlok0\îåŒnÃûJIqÇ—wœË‘O(¼w§†oNrMê/åE«SÇu«£TŸó¥çèí97;ž| ŸÐFrÓê á}i\Ç׫aÅPþ’hCÖEŠZz¥ˆˆÌ“›æÛzS³È,“—)‹=Õ³'˜¸kKö¥M½¬Ó g1·Øù÷ìŸz%\R)[ñÞ¾iŠGˆJŽ’:˜͇¨zGë7{šUpö@GÎÓ¹  yP辑é$GÎútâUÿ¡Ð7® Ú$JÎuNì#N‰°–Q¾ñŽ´ÉÄá†æƒSÄaÍ…8³§ Ù§ ™`Ö7%½ ¥e¿Õ–¬!èˆÁ+Á*8)åŽÌᦴ+ÒÅ¥ˆC-¯»K4¾t•"ÇnŽrS v|~N,&ÓÇV=?/W¨×=‡§)âAöÊ‹#VwR߆Îã14•xÄ”–×l«9UšmnJ¶n‰‹8–n1 ]àå~ó̽“h+ñ»2à"po'ÙçB©’ÃRpü ‘Ûj·ÖÒ±¯¼¦» 1JÆ×Ö ˆ¤¥­Ò›_°S:õ ÇÍ1HŽÈ.Î1î M±P±±ãeåØJëÿT•üE9³Ê«õÚnë||nŽäA“×P-ÍûÇ5Ï~=ÙšE§êÒó2Û—þáç£Û2”ä®yäÕr€?±æ'DéñþØ.r¬<œ|#.¸Ô&yßÊU±ŽˆšæÃ0Kê&”UEX•ô1ã ?$yA Ć˚¾"7;f²üÏq\ýiÇímœòþz˜¼ÿÛõ'Ü ÌÆÒa9iÒƒ¿D5B*¯'ZEp,s ¿—ßž Y« òh|dC>L¥9·U~æXÞ{÷ùF·cÈJ ¤N #y[è³µ›ð¢µHÅ·6îëSDŠ*Ùmí7¼šÎP³®h‡”rÌòù(ºnÀB{í«’ö Wsмö훽PÌÜ\sýç#-‹h DñQö3½J*°ýëÛnz¥IÕø „7R“›âgÚœ¹1ÙÔ9ƒÜGÌ¢;ŠŸy-àþæé;€år¨>¶i.Öçø´ËH+BÎ_w°ÔÞ%˜©®œd{Ëx¹6߸âlNC™ ª¢ŠÀ?»/ÃAÛîæ(ÿ†eíÁàW@@éBDÔ°ÌòÆ zä–z|fÍEFÉê>ø ËŒ¥H•kt*„~×FOR­ú2ý$äï*AÏÛÃéäËÚ³j…Ù¿¤îëHëxü;ú—„2¬#?¡¤âÎ )²ù0ÀX”rz'Ï1Kg@"±ìv›è÷SQ`ÂN|;ÖIÓs¨4Œqʵ—ïl·0¬íð™vƒМ­=nG—hqÁËÖŠÔhôÂP"âFÑJ…®‘uiòž2|힘3Ú .A«¤Ð3“ƒ#d®÷˜Ü¡"9FW»Ìé½¾‰YÕÆP%+µ6TCGh¼MÎZEôð\˜üƒßfÚ¯üÎáã3½8ÛŒð™ Hã¹:õϰgôÇé3vðœSšË„—ùkãÝnŽXºOóþ¼BáÿcþýG0˜ÓlÂÎcÈÁnhÄÊfs#~5ä³ò¹LÀo¸ØØþcüßýG.NvŽ7ÿÍdüG0;;ÊüÿñƒòQþ#ÊDù(ÿå?¢üG”ÿˆòQþ#ÊDù(ÿå?¢üG”ÿˆòQþ#ÊDù(ÿå?¢üG”ÿˆòQþ#ÊDù(ÿå?¢üG”ÿˆòQþ#ÊDù(ÿå?¢üG”ÿˆòQþ#ÊDù(ÿå?¢üG”ÿˆòQþ#ÊDù(ÿå?¢üG”ÿˆòQþ#ÊDù(ÿå?¢üG”ÿˆòQþ#ÊDù(ÿå?¢üG”ÿˆòQþ#ÊDù(ÿå?¢üG”ÿˆòQþ#Êüî?ôzƒ‰n2Gíõ#Ûá7’ï—Uq¥•ŠÇÌ´¿eyaNÝ¡"(I-«k¤ áŒ×«3•¡«z úÙÇ0ÍÔN>XK“üÈEåL·è”­úÚyAä¯ÇàYVE•¥ƒ”&Žòõ·BÉyò.kPª•›m©‘\7Ê(MC¹2³µå¾h œßÙ8Ÿty€Ž(OÑ燢yzø’9Mçøó[A/JÃG-«ñâx©yg˜0‘`ý‚9NÃÎÍ*Á¿Î#Âëä„àkÝ`’ÅQ 4›ò}²k—a±år± ¼°ø¾²4¬Ãw‘®mrȪ¢kVG3¤qbrX‡;µáÔ FlÒ"ó„ò°e`ïÓÓ}âRžpn‰Âjäàí|fnr-qϘ\ОS¯“ETÄŽÍîé ÙÆy¢¼€î²8¬’DsóÉ­~vë]?Þ)«WÞ-ˆ³ÇŠúÓg¤C3¿Òt.êÎòÒn‰)VÛ¥(Z1’s4!kàP·š\ÈÅ[Ï=K¤ÑÚ úË#½Ìë,z)°èmb-a¾a,ôlŸ$¢7³÷øÅ ¿VþVìîÿ-@2³V×Z8,ÛþÆ ]vöÔlkiƇ@’ê­áˆ¹©‡ñ­¾².Tx¥–ƒ­ÛŸýôÅSg‘ý4eí€?¥KA˜/“ŧ8ØàiIùÙ¸JUMA¤´ž—i,‚Fè+ÃfYcб۲ÌЈÉCmñY%•{7À§ìð^3¡òþó¥O°•Ù>f,<«HôgÒ8.*ßg°ó“®/V8ì».ŠQ¤.htâÎ*×,àâÑ:D£†æîUÕo+´³¤Špü4+Ip¯PèÀKomF“1ø~_¢jføæðùô›9k4á!W÷8'‰õ%¾”±Ì®Ü¦ó’µ™×«’UÎ÷ — ¼¥ =Câ9´^ h‘ÛϸÎ>ä÷µvåzœ¾±TöGAåM¬iB£QU13Cz^‡”ÌC}yϲƒÏ\ðÆT"G‰ƒ‰æqªßÿë8GÌÿ§ú!LBV39ÜÕм WË©ASé?fÝú²ÃŽÆS§…ð""çU¶6À4 ÊÅâª0­ìS‡“òÅdÉY•íFÐü}¥sm~ï»)éÛö 5»àѽ8#;ŒtÑœ­ùKæ–$ÁønòÖûoþã”°l6ÿr©,†¡Ò­ÿ(;Ÿê½¢ÅÜÃú8ð‰R¬’„ü4å XªÎñ«,Î2¥'©É¤âÜâÜ]–^2¹¤¼À‘ìÆcºõ3Ѳÿã?Þ)Ê¢À´y»i2㨺R±¸±iá̹û_þ#…™ò;ç uÏ?ÉY&~'Ù|—ìŽc9F`‹&‡ßÇ©ó,ÜÙ–è³%UžHT¥¸¬îWÄèß­A=YígrªûÏÙŒ:^Æ­Sþ˜Š ƒtÝú.€ÿÈîK‡íŒô£¾Jîkš'Ò@ÜÑq‰– V²x©%ÿç‚÷G»Ð‹Ò¼²¬}j‘2^À<üÿ¨ ø~ÃÞØ~¹–Ý}qÞ˜.ß ‹ˆ°ø¯Zæ@Ú*®Ã·™ ¼Ù±.T}§˜±5Ïê}ŒÈiú É6ƒÕ½Ñ±Vn¶·Þxa5³JàK·–+Ž(”#Ö…õ£2ù È;—½±îºù0¼tµ `wµ…)Çé>bzg¦*”ŠKæ6ñ—Œãäm¸çؔجÙS­¤âIêU{9‰§ 5òRÓÚù2›‰ÕùÝyÿnöÁ)]¦0Xn_M“˜ì½®ZeO¸.¹a’PF!8U’ ŸÂg¾|oGö†‹¬"”ÓKüÓ´&µ¹‡ в§`|°@©@ÿmèô_ÙéòL!›/#½½Ü¿¶žYƒ@ä8Šñpßóu|.® ‚Uï¶zË?žð‚·Ò©Õ«3EýÉgåˆÑ‹†z‡v%Ûyt€è ÖZ×Ñ^› º¸ŸuµìÔæõòú¤çñ/ÂWXÁÿþ>w¢ËmúàcˆF0'SØôŠueDßþ¾rXË4æ©ÜòìŽB Fô|A’‡íÅI$¯ùEy¾¼_CC]>Kú,ÃŇziLý¸y™qϾ}È¿yù1¡Í_·7ò%+K¡ +·þãà­ÿ˜‰ôóÿñ'à?v1n¾Þ ^½TZ¦=gg~Äž®†éÄxµðÆ’²ëf•í¦ýø]ë7Æ‘Ol!Ð ¿ú«ñ çýüäèq#q×iUÆÆü§=;n%djöÂÈ•E0;Ù(€VHòüƒmªJIg"7º†SþŒKº ánpö›Ø~7C ÕªÉíj5ì8˽.W ®WÒòÜK*ðN)É‘‰¬A¦D*G´L¾,j w=—PnÅìÑ<| R ÷ð5~ÏCJ"‡3ž¨8cL Í»¡è᱑õa“c<&M hZ‘!ÕÍn¼•iÉýꈯ/•3 \TÕúþ9æsf4ë‘_˧‡ËÜTó°Ä D£xã)lÕÌ ÄÉäBrœõe®<‡Më¦þ¿Ø»Ë¨*ƒðAà‚ HK‡tJH×E:E‰K))yéîFº•.HwwII(Ý„ˆt·¤{ßËîþÿ»gwÏ~Ú³._¹Ì;3ÏÌ3ϼpø­ªíÁH¾m¢±Ù—µOظ!µtC4AÎõ<†Q>#¿áiÇ8‰˜Ìhr•õQЇ¨xÐG¥Øñt@´6º"vùmý¡â¯NÓRœNŸHÎúC·ÛNØ)Ðõon÷/)ÁÛ`ÎJ/i}Ô× [ìÜ‹ô~>v …w­‘oÖHžç*Sª?6ÅýA\®Æ2Ì8¨ï ß‹2wfêž­‹ƒ·º† £¤lø$FeQô2ª À•/«¸^"ýúƒ*y]¯ÄJE¦C YÓrT†œ9á" ïXJé>züs,ƒx); ÷J—Ÿ$=¯™ãùNÅ)”t©½Ž½;>'DF_³•è=«Ì®"M9îeo<º_é«‚@‚çîùQ†‹%QŠR°âgû‘Õ$;xaà8´ë´«½‹~v¦ÎþúEaë9›JÜšÙÜ]x"MÂí·š'1,ÿý K íà9ï龿ýñ5O ½oH»}#í^£¬ûzDY,,H‰¹‘{_ôà÷R«77Ž–öû'ÚØìùðæª]©ß¡f¼yßNÛŒ*_µülc[Yœ¢w‡ —×Ĺ©µ @]RÍgÉ`.ÿ쇻RJ¶Áª×¤ ¹€œ¤z‡yÎÔýÄ`'ÍŸÒÿZ}©-çSpÙœ8lÇ ˆßÕWzø§RÞÿÍä‰ÞtN` 9z’dÀê…ÝNRÍÓÛÎnÉéµ d“,<ýýû–bÐg+@Pˆ˜ˆAó>²!LÜ?Î353£sGÛÿTb ÝÇŒâsj<zf¬£?îjÚ8ªyAªýíA­ÃðÓj¿œ&¿þ˜m–“³jBÒüÞçÁ§Hñb|#ÇL¤…Cc“êQ9Ï0ÿtÈîWÖUl=½Ï¾”g’7ñQßY3 ŽÊkÌŸ»«˜{˜üuÙZç©yDÔÝBHƒm#û4eä´6U¿¯«6Ÿ€m#·õs v‘ D®sO!éJ»Rk:ÚÆâÜÉàÅÒ´¶ ¬#õ¢Üg~ÿ4Y¢§¢òjähä.Å+LJVÀõtù&áöªÀi/â—ÝÛd’›¼E '±V,WR&TíßG¸½ r•é]µÒ(ÅV0¨¸Oü²b9—Y2zï7ÓDi3˜ Ô×½Ó­O}¦ŽüRŒö$bÀãmXhqÁ¨¦MÈ©Ænò –üˆ=fxúnö›hmÒÛþ©À·œãE¾.Õ÷ä¼ ™Ý%Y*|Ú¾xŸ)Šñt$Ü”×fmú7ÉôÑà›¿­*`ët;.©šÓ»«)0oã9ßÑê°ú‹çé7³Þ'¤-E^8&r Äéy6E›m–i5¬¬Üìl²NæVi/ØʼX¶hÒk²ùÕ,@ÜÔ~] ^âÚTå²È°•3Vxæ_û Ïª3"©ý~,ÞáßúGVácÚ\l^a)ˆÖä› ˜pa²$›t',äJÆ/{‹W²N[Mê+m‘––I}c霾Êó¬Ì^–1,úºúЭH÷?ïDýIPhMëõ±`™úËŸ­^vt!Ñ1ô,`A5¢Ÿ¸²JµdÒ—–õÔ±ÌÈÓ˜7ÅÅT!g¨¦bÙ£‰‘ØÉÂOßJÎ-ÑÁKÐŒy9ÂçÕ³l Ñ‹WNv¨ÔNe =*Za=Œt(ô|ǽ„*c1—3ðs CºŽÇ—8!Á?áJ׋gýCé~°a¯A¼Ü’°çuÕ#‘O­šÙÒ¹Sn"¸lQî·Âç&_&W«ô2nV;?Êú‹‹jPAð^©]|1Vÿj©™ùàGh5ùB<ÞëñÚ#cë–t[À§” ÷ÏL}ôÓ%®¦”®˜Ô­å¸±ò´Î ¤ã¦ö…£³k÷¹¯åI<–¶n] ¬ú¶N¸j–€q—1>9)wÉ;1BO4C"E?ñqˆÄKœýkq°|¿à´å¯­MµÊž‘õ/o¢Î¨øüÒ¤yn=¥ÚÛ(¢sé¦ë’!œ[…¶<<•’8}¥ÙÝY< +Ã@™Ã&ðs‡ÊT¦áôNA<^í*jUÁࣔĮŸ|ž@)a6© -ýµó×qdñq] ÃEÇKXÄRÉêˆã 4æº USö\ÏìZ4 MÚ>4—uRÁ½Òů ûÆJ4¡ '<¼qSd¬)»Îô--[Øb™^ŽÅdp_CUÀI:îšNîžo'ÕPøÖk9¤ï I¯*k Ǿ1x¶Eq+Úx潉L‹D¬ùýN!$àåÖ;ŽÕÒFêˆ %J)ÇÀMêjSô¤c¶ß˜]ãáXWJú(,Þ(v×´+,åu‰$É…3ßû+EúEyT²74—îkî¤þÜsÏD¸™Ùɧ$ Âÿ°sÞÏ!±šLkÍŽþ’ ÙÊ µn¯«"A©ƒbÇ´ÁHµœ|¸‰g¾Ô}¼ã»©ŠÈG@™TìÌâ«ÇúûMÀ2«sø°ê%lþ-‰óèÈ:O­8Sr J_°öHwï“)jÒê›È ׿LŠŽEé[*FÙ²¼a.%b&|²UdÞòzó¤¯wéôM' w®4O4vU#°\õsÉß`žDÝ^:ß.?¢í&x‘+Æ“¦–YJWÉÎÔìíÇ;ÃOÖ®€~Žîͦkæ‚ÖúQlç9)Pí\©=o^‚n}§3mÑas.~À”îàÞÊ2¾»ÛÄß½óôZ¹"÷V­àG<4ØqÂY7õ̧kÒx.êÝ\ªyµÇê¨Tå‚5i¼ÉkM„B@¢Ù®WIÅ7•"qŽ“êŒ[XBß§ ®³X¹ìÝýX¶ö t¸™˜Úê 0@ÿìý S|ÜbG˜ûãëý;,LóIºY™ýdôºàÐñsoù³¥ïëöCÄûóãùSÃø‚©M/yîßS Çd:óÄœ$ԷןyÒô¨—-c )‡‹t ̺ө?MY{Í„¥?cæ[E=)‚Ö Ôc‡Š×«zuP–X¡ùؘ"L ?JS ˶ëGào;ôÑÔðÜíÁfyDa—ŽöØÎòå)‚ÿ`3>0¤‰>©K6ÏGn#ã)X'‹¬lÕ8êR(K¾¬•í%´¹]®æRfWêW m#µò] Žò¥†'Ð5Èë1Ó­õC[µÊf‚pÇb^]Ï. K`Rk(3•E6z(¦÷s[HH_9BJ¾¸’ù¤ÞG[´kÙ96dGÁðÏ9ò_g2Œ0ž1Ô$ LZøë;k%nÃÉ΢#WÛ\É/ŒÌ„4R% C×wà—^Žx•+vý¹D2±žOB+0z¸ÀvÛfúÍI@¿w–Ê‘„eåÍGYH”KìÖõYž°R¤€öËà¯IÜLQr}†ÂÎo±7CÐD³-˜ä‡Ê¯ïó醱Íi ËIÔLŒÂ:R¿vúðh…Gd|û s†“çDœzÐúolFe¤YJý2·ÊóºY†=›¯|n2êó›à\Yêœ5þš³:ñŒ= ç³½¶ô܇ ª……èT˜‰r¥v’_G~ÃŽHšwŠx=aHÃòÅŠq­©±ÿ¾ŽiJÿ.`u„ºøùÊ‹#W]`j¶Oe?‚„_­¢ÕçüQÚ¹/šª¾ “\#•í±Là:ÎP‡±,ë3˿װ暌ìWž–¤¾§%à×›–Ç’Ô½HÉCºõ÷yñXQ$D÷Ü?RŒ&v-'ýñžÝÂëžV­œû´"צٸ8ŠŠ÷‹!«"•D#¡¥Œöðé|W׬ΠT<ÏTš¯ßõP°Vä¨iM.Oîv71IðÑ–£1¯³w½´e©wN€‹ÅP9@@žÞa"Ë¿z;dÜ\A[«v7²ð:q{Ék­Ÿkò®XúÈäí§‰],¿“ÍyÐ,p@1ö=ñL¸s|&…§[HPØzØø©i4L+ç6* QÉß;×rsgÅ¥åç-väÏÏŠ#ݠ·wðQOG¦šƒwG µ;25ˆÔ~+¼žõbi4´øË ü§ˆt¸ÿ/¨ÃI›]ô7fÔwM¼mÍ[Ow`‹œÓÅŽ=`áýˆfŠ”Kó–“%k´„éê3ÉW‹‡àkiQ|¶æE'¤×£0q]VøÊ£P–ÁѵY~áúˆSãVáÉ<ŒÁ7]ºðº¼ˆlßžƒ о7BÉ#ôý ̱°ÆüBÀþaàwµóÓúw‹É@ÇK¨²[6åãœxZ,M9wZèš±ýïàõó®ž(Ö·œw¾Å×rþq1i´}-Jò=ƒêÛ@B|%¶=Û¦c¡>(–>Ð3\&ùk[ºäUgÝ’aË6ˆòˆå…›O‹þÊ⢽¡ýž‘½#l!fOÑ éIþVÔ¶;´©Û<0†Ä|Ù7ã¼>2 «ß/sVyõ!FÁ$µPG°¦S]ZáJ}ýŒ¢h]í"?*È3Ã5öxÿVcú©dT/ôtìœôÇúÄÇì"°•0D u”_ÉØE šgtÎüGy`ƒé{|¸y`oÂmµÔ ¶Â¨è¥tˆ|Þi¸–c(ÏK‡2 òG¾bÜÎ-¨ž ¶¯p¦ßYúK‹—Ï•_ߢwp¼P¯#LV(—S*Çrÿtü7«ìå –K×Ð>, ¼.v¤B”'AugÁ‰âú·)Ú'1 ´ÛãžYï+0¯ËAã˜d æš¶œˆjÄ+)w0‡Itéýà4½CQ +³>=7yFkÉÕL<šx«“0Åa–Ll/˜ š¬H¥¶ô úÄÙ%®Õâòg÷M§òyÂÇZ]|#»ÜVŸíø¶ðíº* ÅXÈ€nÕ©ûŠRØ;6Yˆ¿kô✽ИÆÃ“"楦EUŒ!Їï쬩‚^k±Z›^OZÈöªÿe8xv–.듦²¾ë´îeõ<†;[Òiå=7¸ê=æ.ØñåpØPvÍìâR¿¯ÇxúÄéGii¡úvOçð+¡hU[4á‚"ø³[IG—Bù%g)Ö-¤'Q$ 'ršNáÚ±˜‰Ã R‹ç‹v¿¾è1r]tЧD‹ÔætøÜä´qqi=²I¢fS¦[=]££fž²mvÎ ™_ŸÂrŒg*±]þ¿G¦w Rƒ3!’/Íit‰½ex/Þq/’e0WdœIÀMôf_7×(.®4qæÕøº:tç }åA»WyWáÚ[ÍX[™Ï¿7ÿ|tH©Y…Ïû-_*ç!)™«ºRà'{ã^ÙýÖæØü8øm¨w©}¾úP5¼›%á!H%ÈÝV×pí…nfL칊*kñ“µç¹Z榞¯0~ÞÿþQ8S®ØŒ 4¬ ¹dÕRƒ—Ñ90ªLȹ±<9¤Ù*´r’$ƒjIè{¤ï›9©c¡Ïï¹ ܵ~uúz¶®Ù–Lß{6â|åÑp§$8¸@¬×2—rmh…‘M …\§<º«B­ÞBâyÀXg!Ðû¨¡¤Fi…K@d`­»œÞKšW8¾œK×’÷„jˆ‡ofÃÇ“ªQL+<Àh·6ÀÕRakõ#íÜÍê,ä2{ôM†`Þ£<”,øe{Ì2“ûXUåݺê‹Ü ³mê,esô]Œ—6Û'·÷)òÛØtZ5yÌÍ„äfÛ±r0¤ UýO[<®Ñ_™‹+3›ñ2rKCb/Ð=A¡ç„ž®Óö÷› c„Óp~c)¢DÅ,qy‡Íõr|fä}wH×…ãpl)tC ¥E–Cæ/Á–eÚ~)’˜ã… Ÿø¢2‡¶´ª±ŒŒNÔí¯ãõ~©÷úWñö'ðâ [¾\•¥îša{¹†§#Ké1êÙ¬g/lì{-½žª gˆ#ö÷ ïÄêéàzÉ/ ­‡?_sÃ.ðó¹—›óöÔêih6Ê›˜eætž§w©Ÿ á.@ë|–{§Cþí)Øúh ÿ¦”øhl5C([Ñr’ШÞMUŽ3ëzzâé§©¶ K4|õ¾²¯MÖÏkÚa…q!X«c.Ð1`‡âù6¡óº.¸š$RôŠþÓù?kiX­ÇËóbgg?É÷7×·i´Á¼Hô|ÒÔ R‘_‘bQeº§½Leì«ýûÍØlöâÙª x@ßêô¡‚ó’ƒOÃØ÷}F|þ7¥iØhÛzÔ‚7tw§'¨E“¶$r©mDì¦×‹h5Ÿe.Šá/ëµ£7؇ž{°J‘„8uwqÔ?ú»ÎC_B…—@gMÂT D¥zÑ£¦þÒI?<ÜÔ—°Z×) Ý0j»A*Ó'mB“VâÖ‡©d$kD¼iÔ*ä4ÇÕ{ÈHá»àI?î‰ Ð7dH½¸„µ.ÌÁv@¤HÒ/$Ÿ`€š÷ÝÚ¿ôôõ“..ÝXr¦W»}Ò·[]×ÌC§{ð›ª÷m¶ñö›¬Ó¤@P¶—(±ÎƒTt)·Ü/;4°Eÿ¨¼+«–‚÷ÍŸIQZPÅfÆ‘º¥ (¼ƒ›¦ä}Ñf‰tþÁNä¸"°Ý2®¾˜û§¶v®Ú§‚—ÞÜ!½8×;ï_‚dìoµeÚ‰_ K~¤a6lŠñ@y,¨ßÐQ ¿±?le <÷÷¯wj¢1öX Hú>ã*o*Ö»€•ƱïÏ_Œ&B§²Ø|íZcœÚn±ýóWkÙà˜´½„ª²«UðtMr ÿ:›¬ƒÒ¯HÑ—ô9w'ï›ùªåhüÿ‹¯ÿ[ÿ[€‡OÂkÂgÄË)áæãã1â22æçåçã€pq›ðü¯Åöÿ£ÿÎÅÉÃÃ)ð?ûïÜÿýÿÉÂGøïÿá¿#üw„ÿŽðßþ;ÂGøïÿá¿#üw„ÿŽðßþ;ÂGøïÿá¿#üw„ÿŽðßþ;ÂGøïÿá¿#üw„ÿŽðßþ;ÂGøïÿá¿#üw„ÿŽðßþ;ÂGøïÿá¿#üw„ÿŽðßþ;ÂGøïÿá¿#üw„ÿŽðßþ;ÂGøïÿá¿#üw„ÿŽðßþ;ÂGøïÿá¿#üw„ÿŽðßþ;ÂGøïÿá¿#üw„ÿŽðßþ;ÂGøïÿýÿsÿÒ÷ùOãÓÛKAœ•Æ ½Ê ƒxo0ÅO.Niô6>Eùõ€û€æKxR­à¬ÎvN% ›Ä5|ø?®þøõùÍ‹ÉëY] ¢Ec9?4‰ ‚Ö¶ÿÀ_ßð æig%¥,35.aÅá—‹y…Ö©TXh_•™]uø>8½Ù=ù°óißWêŒF•#„¼äb{&%ê£9mÁ'‹ª†M±G„¼޼¥ÕïÍOÜ~‰9½®Ð¿Ü›\BÒ›¹¦¬"áÒ± SO·vÃßrz¼Îã/<^¤UŶîݶ]bŠüÛüÿúGJpÚ;ÚÞÓ°8ïàGT(Ûп—ÀÓs^¸m3?÷ýáKàçf³”©ži¾Œ™5­Éqž®Àô ¦Ï6ʼ;­ÂÇïÜ(ŒÚÅÚ»° Ò¬¬Há-ʼŒfxô‘ºŸP]£?“fõjãÀÑíƒGÞbþGr·‡Th¤]xç{¦•<]»¦%v¢R Ú Ï …oi=J‹£x“µ±Qi²ð!êýÐ%mŸcR3,1úÂ^¶Îôð²…ï¼>d!ì^ÌO³F.éøÅï„OØ´¥¾‰“(²QwJŽE‡#Ë“,®ëç‹^böº@yľØöÖ™Ê7‹K£f¿¼mÎ6V‰€Nf°Ð¿Œ_gÛX Ì(.ß¹[ûÆâp6U((B? é)&±5úxFÙU·—­æ&ú4Ù;äkŸÊ¸©»ó$ª¾ü57jqWN mŸêà¬sU×ózѯ·{bqŠ9^œ(?)POÔ@S¯sÓÆh gªí¥&‘j–þ²†êó°ŒJÞ’ºáôa¸˜óTð Jˆ¯zô¤­óùvüÈ7ç±öRk–ßY$ºíT3Ó¿¨>ë—xCÇ ¹åžaÊøPç·ÜËŠR7öSQP‚JŸJ™Æ´ å¹ej}·"4Uí^Oxª£}=&Ya²Œ(î£f¦Î˜ý'>0àKòÀg:/}¹þÚšŒË…wƒîÑó•u`Oûoаu!ýÛœæ¹Zªjú:<µÇmìü…º^%ÝAò€+´0É(05†^:²›ÄpWela­kC0T29>ÇC#Káªç]A¿‹œÞ¡¾žû« "zPNm§¼7÷ìéâ… nö„K¢X6Q%t”AsõÏ/w<=Éô†àÒøÑê‘DÇwí`¼‰¬D¨;?¨ð÷æpæt Ôù†h‰•„F—F.5R0Jgýtâ-ìé]§IIÚ£·}è5£ƒŽ_b¤ZŽ Î À9ƒÖF‰G‡ÝþÃfæ«?®¸Î“)0öŽCIÓÅáÈë Ñ¨ºvxl|cÛ“CNÜ'¬¬›^¡*%x‰÷Fº¶_ûª¦6­Ã9ûáܵ½zÚ;è8•DF@ç4¥Bí»JF|e±Wª©È\ëÕžÓ3+_Ø’ˆy“&+]ÿ7ô<Ëÿ€ß…ð¯¤ÅZŠm­k ×€<<«ŽªÞ؆sU_|«a‰±äˆù0Ye× 2ðã†Ú~Þ ü|BîÍÚùèßk8Ð~ÎRq­ÕëTü®1fà„Ι{`:2_r÷g÷8§àõêFue ü €Ï;²ª{“Æ‚«„W­ÓF#ísOØò0OTPÊø+­*1å|î>Çëim™5¸Ù¬ÖšÆ'BÙϾ Š7Åå—t,4o¿sÓ}'”zÕ 'r·|zr´g)þùÜU£ê¯Ï\‰*¼ãÄîðP¦ÎÆnü{^ƒ¾(‚u’ã°æ×• ÿ€ÿüºà+cåÿÀOü'¾ yû\ùlErN4~wr1ÿqœ}‡?8ÌlqYZ°•ðÖ0éŒÐ­ÑЭc>ü6ùïK³‰žÐ§l%,\Á7Š«¼bâ¦$ìP¯røªlŠÀìnAOA¡)ÿîɰó®Š2Çø~óáÜFÉ—ÜO[ÈÆ6(°Š/';=Zþšt÷öãë8Jú¯¨­2ß+O´“ãzsì„Ï)nÞ…àkdx‡P¥º½¯ýDgõâ¹U¥)ð¾lHUÖb(òæ¾ß'îûÉ%A†LÔýO¢Ãi bJá ÌL÷k‹îUš›)͹ìÖ„Ó·®éÅ„.¡K„s)l»h)â1ÔÎ|L”D©yc3,äY*IôTtq¥xŸþá¡þ}ÈAUôãøF´¢›•„)/¿)ò-e¿çø3¶;ïcÒj‘m-ÂV—Ó‰Ô ŸEI~n2kÉÄßOïºù]Çn/D‡Ë"ºX@ŸcT±AÆÅÖªuÃå«éFM\m_Uôà ï¥¢ÆQÛƒúbË[ËÅÚöì~´‘üÃbÀªØÏŒ,.Iî™¤ÙÆ%Sn3çîŒö–ãµûCáþ{Ù„_UÌZ æ’HfÜ<$ÿÞ7eÉ>="ò‚7°žK¤juõ›Å`Î=×8å¿°÷×ÑŸ×8J¸H.‚¬»ªËp×@ap©ê®Æ™‡<Á=Á‚Ã08 îÜ]‚;l°·÷‡Ü|÷W³ÞZo½ÞZ/äÞÀ0Sßî®:çì}jŸsnØù§“Þ´ñ—Ÿ›áËõ9î·KºåOúù½Çž½Ç&‹ýrîM¾ûÅjgÜ»önßî÷øDæ¿_¾ýÁËùï÷ÍyÂú'î¾Ùb8ð”w×:)ÜðûÙ/>ãìuNäàÝß:ÿÓ™¼ôÀ¿pÓìóαü“Í"oN¿ÒÚ~×~÷ÝÀ^:f‘§ß|o½™ç;±Úv×™|wвï<ÛêÛ àÉiǯûÌòï¬{ÃãÎÜëâÅÏŸåÉ7Æï8çõþœŸ f`˧¿vŽ%Ö¹|Þ×¹÷‰cg^gµ 'ûݤÛÍ|Ç ³=5˜ ýùˆ?>;þ¬/sÔ«þi•ÑK^}Lj3ÿ¸æ³ λÒàT¬ºÖϪ»Ï{w‘k–Xfç_œ¼Þ÷Gm¼½ûbŠu¯}à_°öýo;{¿—ß^á±7»ïż²œc‘'?Üa¯N_yÖõ÷¼ýõÁ ñ#w?ã_kžê4ë^ûÁúï¬wÁ6“}ûû—&¬¿ó¹»ÿœ#ÜOø`³nª¿ì5*îõîîÍxþå›/÷Î&³n¹nó‹Ï×ûv,Ìñù/fºxÓ]ÿ羞xÛá¯nô¯õšqºiç»åâkþà`ÔË˧Nn.Xð×gMwÒð;v\y¯ î3ËQó˜…Oe»k¶~‡¿ùÁû¯¹ÿ&ûO÷ܯmjw™jªŸo<­vñˆ3®'äZ[^1÷ÖÇÞ½Þ5}3j†s6Þï©Q?0ÃÏ_+|°Ç÷wýÀé3<ü÷)ÿvýBn søò°ÿy%œX¯™O›ý¶/ß<þácnz£{î&Û¬¹å~W~°æÏþõöRõ*gÞ7ÕŒó¯÷‚ý–|æºí‡çðÐîùÛ¯šeÒé??{ÿ…ߟoëi^}|¿_÷[ÜÀIâöœtòw×}²èûÞ¿ÛÞcrýöž·ùõ­·Ø“ÿ~ï]:ÚMÿÕ‡/;ì÷¿™õ²nýóIí<;~tút'éQÏ2úïvÌ;S¼ï'§Þ÷ö¸êÊO?]¿Lõ·iÚÙ·>çëízŒ|•Å·ùà ·è˜óÿâdK¿=߸‹¶9â¤ýþ°ïžw ÿz™3þôúZG_¿òUçLû«'=üâY?Xm—ŸÇŸ½±»=âSï°Ø`ÐøÕî³üᬹWYúæ~¹YîõN·î»~¸Ùj·¿ÿz0íûøÃOÞrøÝ϶æÛù¦ßŽ[cû½GüìÝ;^þìÀeᇾßzì×kn¶Þ+ÿ< _öÑõ݆þüù]¾¼âå±¾ráCÒWŸ}±—o=mŽÆ-°ï'g®qÂò³lyíÚçm6ó)ÕÖƒiàzæ¯ÎXæœûÞû ÿð­)_;ä¡tò­Óm¿Á| ­7ŒcÎÕÒÛ ÛrÆM¦Ä|ƒùïž™ñÝ÷.œ°Èug~þЗ/·úIgäõwYšnÄ/°Â–+̵æeÛn8þ ë[Ñú¹o¼@-R-µõµ›~6t¾ýãÓ\wè‘£?þ•—ùã¢K/ûí #^yd˜ñ :¼ràZs¸Î¯®0v̤#®¾z·Ï=fíwÖÿjæ}TýÿøE§.zç„O^æÊ;Ï=ôö'|yÇÂï´ØjnÖ~ÔÃnîàß…‹?>í+ßv÷£Ï²;uÐè]å/uÚìw/võ;«ßzÏ^W5aíO÷¸è´—‡ýaþCŽÿêCüëtÌ£¿Úÿã)Þ[aÙæÁ7Gùò«4g¯?lãE^›~ØÕ\üºgž}Äø‡§š~ª§;q¶M·[ç¢\ø†‹>í¶;ˆ†¾Öbk/¶ëU_¯}ä"¿ïŽü`ùK–ûÙêgí÷Ï8ÛÙ»üÀ±–XÄ-°ý*3,7ï“Ì}÷ŠÓŸ;Õ#k»W&¼¼íkƒÓzþ¯î^âúo¿Yùá»WºçŸ¿øÅ‰oÜòÝ$Wƽ‡¢Ûû‰9n;Éé—œwñö©¶˜ìÝYï=ðÈâö[êyGœÁ _ê݃¿\àùYßpiýƤ›_÷ÿ˜ÿ>öç¿Ï±Êþ³ÂùïÿóŽkþ;ÿ}¼œÿþÝ`þûåÿgþûè-óßõå¿[w0ÿý¼ù®ÛÿjBäÓ÷±÷ýéÓǯÛý®Q™i™+·;yªƒùÒlëè#\ö›{ÿ`Žÿ÷¦n»Ðµ‹ßµ¤]á†y^ÿøÈÓ†øÙ‰cßxkÜ-ßÞ;~ô£oó§·ÏÑ—.>þ¡Ù¿:ÿ˜ß7SµÌïíÞ·|ðàÖÿ>Õ¥ŸrŠC6Ýé¥5î8rÌÏß}ñ|^¶ÎÛëN7Ç*GŸÇçþ|ôÓ~xþ&Kï9ù¼ù³‹¸r½Åº`—YžÞöÆ7¶ßáf.¿Ë'ÏNo¿}`š[ÖÿäuÈÙ“ír8Nä#—¦Á$ñ¥^¾=Ô¿óíg ÿ?ãßÇ‚ýíùø¿¹÷¨Ñ‹-µæ=ë=ºï“Kl½á'åM6:â•GžzàÒqƒþü#v|lÅ¥¶^yŽó;áÇ¿ÏqŹÃþwüû;CãßíOÿaüû« ;úô0ÿ¾ôÐø÷4Ë`üûÌß.pÈÚó_“çšU?xã„ÜõÜW^_}Þ«Õׯ.3ÓÁ>?|‹)Õîßμñ´#™ï™ÜÓÞ“O~ä3ì³ôæWŸvùt6mñ÷ËΜdÉOæãhžÕk†_½ð$g¾¾ïä3¼væÎë>4{µäf{l:ëï¿|[ºî5›lqÔÊGüéÞ·^~ÕkŸÜûÕ×§\÷ãõ/Üxä\¿þÓj?Xªß>tñ®G©ïâÒ=&|wqý캗ÞuÊ/¾:áóÆáéžûÅGÜtÅÒÛœVM56]iÁk?šõ²w{á¤¥ÏØïËc_9ôÚO½}ÕgÎÜã¦É_™{¥3>ýdô¬cþòüçVW|øàÖ?±ì¯=ž¯¿ýôí§:cÂ7O=¾Ä*»Üú•õf;ÿžÇ8íxï'[ö¯/O=ÿ ï½<ý‰Ë?ßué ÷_:ù¢wl»ûŠWqrïovëúù¯ŒÿóñË}¼ù®Ç|¶×*ã—úú¸ý6žã^Žý}üœù_šòñ­&ùÍÒãF…÷NéÂy¶˜üÚ-–yíó»9üĸ·Ÿœñš¹®Úb…•ÎÚxåÏûæ˜ô²?}gŠ«øb¿3—?²ë‰»¬»ÈTsoxæ•sÍ3Ý“¿l™gíìc‹±ÌKûOóÆ*ŸÌ{ÐI'Œœzæmç¾á†S×¾ìß›µ×CÌ9ùã_Œ¸{ø]·ýáóÿqä‹S.´ÏE{m¼ñæÛ?}Ù:olõðc}À‹3ÿõÞ+Ùp¹ñ3®¼ã“«üdјt¶{§3Ûõc·þîUoû|ô·Ã÷:w¹Nœsû•ÿg{ÞÝì¶çÖŸç’»úõ³û|÷­ûÈxµí.÷/ ûŸ3fù nþhýêOW^ùÚW.¼æ‡óPžg³'ç}çˆßXb“_Œ|÷« ^xaú_O~ã¾ýæêyû͘ç'þî-vÛú£U—¿õ¶ý6¿ù¡¿ï¹Ñ§ËÀŒ·ÿt®3Ø{ãÏ_žýáÏý‡žöÛÿûåÌË콑žþ9ìÉ¿>Øl¾Íîºú¤³§›júÏ~½Ñª³^³ê³[ÿt“ñ/Ü7Û‚¼»Þ³OlqÙ°WÞt§9†_{÷ê÷NuÄÉ[½õrÿÞs§><ÍG_¿Ëˆ]y|š'Yz×åú`ÜÔ3~¦}þ¶GŸ6v,Ç3ã<#7Œ‹,y$ÎË—›Ìh<ê¾l²s†¼³î׋T³õë¯tÿ„å–š3¯–—|z¹¹>>ê¼[îºó˜Á[vnuïfïÞ=ö¨¹Þ^uª)¹öÆ¿ºôÙ­Þ;åÓ¯èXw|äù[\õÀIž¶ÝnþyO:ùíÙwxrÏÕþÁyãÇ^wàˆË¯÷øŸ'O;þ¹NytásÎþë“kü˃Ÿ|õu.}ó¸U7ÝqÎo—™õÙSO^h柮ٟtø6çׯìùKw>'Txø®ÿ±Á“7/ðÕ«+í9ò½Éý÷Óîúv#ÏYý?ùýç§_c†'¦Üxƒ³¿›l÷ëíç›ç½òíÑ;1¡3ù¦3Ï{ø·ïŒî¯™i¡ O?úžÙþÒ-Î8Ú¤Ïo„Úzlqsì´ÞçÞ{ôæßžn¾o±—îûû]}LÏøÜï¯pݶK\úà„kÍï^±Ãˆ‹ßáI›'oü˜'e£®YïînλǹøìözrÖ¯3ãÝ _>|Xuÿ?¸Q÷¬´ó˜©œæŽ©|ö‡÷ÚÒž5~Ó'YmÑÃæùì§ŸÿjË™jÏyé‰3öú`cަÿ`Ô ¯Nöþ ³ßnìù“_÷Ó}ù»‡nùÆ#ï÷CžäĘðò­n?âª>Üc9·Ò¿§]kɰÝv8J8§8Ksnß>µÒ™ëœwÏV7í>¼þÕ:O½õÎ"ßž2n£¬÷Ç_{ŘÕnÙcÞI÷Ûß0¦™ìôñÿ2?õ¾¯ÇÍ<åcœoàþõ¿Î›ý¯»%Ÿo·Xþó¿ô?sOóú$›=Ð/¾éžãožÿ5~±Ø¨[ï:ã˜{?Y÷á?wž·ëÈ›üáçÎÙêÎ_Øi›)î¼{Å):ä¸Gž^ëâak¼ôùß¶_yåéŸýgüCÿgüGbü ËlzöUÏ_<ÛÉëÞvýUý-ÿgü«ƒ ð÷ÿøy÷ݶóþš|ßnÚùÃfÙn¿ ÎÚóÊ…ïÝöók~zë-{í´ðŽs¾Ïèxüë“-½Æ÷¾?ê¼IVßx¾a‡ÌµÝâK-Ö-Ö¤›×Ýopæœûã¯üöœ÷¯Ú{ƒ 6õÒ¸#O˜ðÄÌÿÿø&ÀÏøÃø17M€gÖ‡.üÅ>§ÿkÜ$—,³Ì«¿¸˜à¿[ïý~•‹‡å¦Ï¦}ý»½¯ylö1ϯuËú«nû‹%>ýÛ›Ó¬ñî!?{æ‡=û륋Ñžûú®slyʳ#W^ë¹͘c¦Zø™‘㙋ýîËjÔcFúêë´޹éõS†M7ùKÞwæãD’Œz¯>~ý‹çüí9÷n~Ô«;ÿ»|£¥òÃ;þä‘ïÐþ&̽ĨÃÿ:_pÏ/|ÒÍÿ\éæ#¦èßXrÌó·Nýö~„ÐÞtÿ?Ùs†ûG.¿Û÷oÏøÈÎÏ]ñø|'?=Å;?}Á{|è¦Í×v»sOøù§o°úF·mò“Gf|è¦Gÿç}¬}Õ)ómöÞO]tékÓ^öêÎOßóÞŒ/½øË™úôb?]€s“µŽ»ã·óÏ7õ«|½é[k>½ÊOªþó/G¿ÿöŸ~ºË2œ ýõKÃ~¶Á n0Ï{›-ÿÙÞ·ž<ãùó¬÷ØWúôÛÿŒƒ“ov;Î÷Ä×»6|L2òÖ†Ÿ9ó°­wÿí;ç¼ZuÁœ+cKþø›÷ÏŸrŒ>àïÿß ðûÝ8®~‚Wý`±q¿ùȱ¬|óaç}òçi7žçÄU¶~c•G¯«¶þޝvà'ÿé½ÅØz—5}훓îØóÍ‹~2ÝO®ë¿~ñŒ?ÍpÉü=þ† Æœs눗Þyço=ð„{~5ÇSŒ=ÛN»s|ð;£î¿wŠû~¶Ì£ï=ñèÌ#¦žt¯ÏfÛîÁ%‡-ùõG_ñÕøs¶™ðÒÏ9¸ÙøÚiŸšfšÙúj…þÜŽ?äßgoqkõëã‹?ºäË©§X'®8÷ú÷ú•žØb£=?sá¯Ç³åCƒÀk½¼é½ðöCëý^>v­&Ì÷ò°û·{‡;¹Ä½üöàÝæ¸oÌ'³}ûÚö Ûãà½7XlåG¦ÝñÚf\óè{Æß6þè%n[f•·ÓË,1bºã¶~ê•{Û fZø—óÞû)1úÝý‡[_rù±ùýõŸ=☠ÿ½á /¯þÙ?–ß7/xü’ðÉxø 3¬:ãºñÚ?Œšü±ÛŸ[|¦ÏGûßl}ç›[:ÈŽ?ÿÅ¥'/xÛa…vÄÇ}ÛÆ·Î=e•ߎ›ú âåÁ_d›VüÙ^gmÿÂQÛ½ÙÌóîü“Î}ØãoÜ÷Σ›MØúÿ1þÂ&À¯qÜü÷ƒo»îËf‘¯Ysš“¶>æ>™všáïÚß^ÿ‡ÝõsËðÛ½ôÔ]§~pËò'î÷Ïi>ÝíÌi~µÉ½K>=ù–Ó>¸ôô+ÒÇŒ}tŠMŽÐüv¥·<|éMN¼tØ"³žwþ}»ÞH¾¹b³ïȃ&ûüÛþñÞåíÊŸÍxÂçnzìyþ¾oêµÿ÷Õ_¾|Š©Î8+®údóó)ÜI;¼þÒ¨‹˜nÛ1ÏØbÂÅï¹ÄÙ‹Nµø‰£ß=s…°Õ¤+ÿå­“ïþÛÝÍœ¨½ã˳8þÉëú7;úÝ]êM¦ wÿ·™¦¿øÑÎâ(ðçnwåk3î°àaŸ¶ÓÉ7ܼàÑ/Løú´å~~ê†×<¹ôÛ|¸¥·»kó¾=ù¥÷=ní›ûûß>Ýuš×wZkôYÏŠÏÞ®ÿóß-7öË+w_çˆß_Ý]þà)oßvöY7¦Ó/yæ£ï>Ÿ÷†Å¯|àŸ»|éñ ÍwÃø?mºêç ›s­©ï¸w‹ß=ãÁ5íñîÆqíi¿Úõ®vÿÎzwþ)–ŸqåSޏvžÛn}á/~ø kݾÉ\w]¨Î™ë!uòqò›qìk~EÐ?ùön¸î•[tÇŽ>õ?¿pÏeÿµðÂÌxî #Vï×ÉÝãG¿qhµêéÇܰÈT#ÏûÝÈ}²ü훌{{Þ»íïàò¿ùlé½GNµñ”+>áïí>çèe¶ÚòËß?òÈäçŒ{ŠHY}gï)/?c¡ß]ðÅ÷,2éóí¨¥·m‰cOœþü7÷ØÛا/Þõ®k®~ɨ½?y{¡ßÍ9쀇þþå]Ͻbp_³ÌÒg_zõ†ÿþ…'NÛyöçî=l¾Õý-o.³Þ…„} >7j±uîYmÔè›ñ®Ãúd†ÇùÅ]WÞtîÁ;þp9Ç#ó>©yÞØãŽ7˼]¼Â…gÿ[¿`åÿ~#°îJŸsÔ#×¾ö–£ŽY¥?a©6ØyLwãßæ=~ÄÉ;r‹½y^_üÀ]áÍåú›özââëÙzÉ{Æžþ§—.ù~hüov»t‚ZhÉ;ŸûéóGtì ïßæ†k~ÏMvÎÁë p7ë©kn»È;Ïpü˜&À?û&Àoû÷µnøì†ûŽo~¶ËáùÙ…Ë-2êÝpà¾-ûͽOÜ5é'÷_øë^ü黦¹yät‹>y·þá¼Îýâëý¾‡-±Û>³·Ç.lö{aº†ï;j†5¼\ÅÛçþb³¯Î¬Fo½ôû/½¸ó¨¹—úöØ3þ}Å·@̽Ÿ²ÌÇg­¹ìQÕžÛpÏíî_þÍ?o¼ð¯ÌÕàÉŽ¿iñ{Ÿ{bó¯_l_©æøyäø'9~ü‰‹öÕÓ_²øSŒÙâÓ³§ìëço|ø‡÷ÌèW¯^íñ3V^aòM^™á‘÷†M9ë«knýófÝŸõÉùfpï½k.O^óêc®|xø{tøÞï¾òÎÏ6œl¶g_ßiq¼iÔ›·×/ÍôÙÉ÷¥öÈïþ<Ýé{,÷ƒí¸ëu*só/}óùcÆ}f‰ÙN8òÍcöý¶žû2¸Ó³Ç}Ä›¬Sæ;v‹‹ÿüÍû3ÿöüÕÇ®~ð<œ?yïî_õï^‹;ù7»M=ãíüã)}Ô²3úÏSžõ»e÷8w£aû¼ºŸ…“ºû¶Å–õc& FÀûïøe‡FÀyyøÍÕ`ü–‡]zà2_üú…{¦Xm–S¿ìç´ù¡Û}?z½‹†Msá‚_þü³‡fZ鯻¾8púÁ¿ß}Ëùî[lÌgžðÇO¹HÝ´Ï?ßøë$;…=æóÜ#H~{ÿƒkoõÚÆçOzÜ}LsÊ«Ko²ûQ›êU¼qí±Ÿ!4ó»£O9ñòÃÞ:|¦So¹xØ”nñÔ}£ï;â½M÷8åšK®æ“zbµ)n¿õÙ1¯=û‹MNYÿã‡T¿Øk0þgÿ?üG#à¹àö׎ÓmýÅ Ÿ >Ëg›¼²é%›Î2îÓ‹Ïîæ½ò˜‡ž¼áõV>ùï'>CØíú«fö‹ ®~ÏgŸõ×%þzæé¶+OqÙåÇ=ø5‡°¿8óÉëÞ¹ÇásÿâÉÙW˜oØåßñXrËøê¼^™e±Ua+ǽ3ꌃºÝŸ]âÅ“g¼tÝ`ü{¿‹¾ýóÁø ÿwü/9þÉKÆ €ßx0~½IÓ¼‡M·eiŽ›sÒkîú|Y¾ùÞO<ïzúW¿9w¿›¯¸êÿwüå?Œ€gÝ3><ùæ­vZî­ÁøÑ[]wÔ¾??v?þÏx{Ï;÷þg<Ø•_ÏsË»›Ÿ¹ðØ‹VÜà›—öžã­}>ûÙô“¬õÎFÀOøaüÖÓÈða©ùÎùáœî±î{Ÿ°ßeûì»ÂÔc6ÜïvØìó1ÿžnû¥OýxÞɦ~y•_þä„þͬûÏ0昇þ|ýòûýrã]6úã2{¾z•™pèÏþrç=n{ü+ÆÎ9υ׿0üŸžñ]µééNé6Ø~ükœ¿Öƒæ©mo?óœÝfØÜOyà_.¸eÜTK^¸÷–Kœµìï'|þÛvø,»ßûÚ¼{,½Ù®—Oºúy?±Ë’÷l¾ßz§;f<æÑqúä7ǶÕßï²ÿ¯ ñé»ÿ½äÏß´éÑ,ôÅ _Œ[åå—ºë_>}éªWfX{—éºægë»ìÃÝ¿ì¬%ÆÜƒýa÷ÜËS-ñ¯E2Ÿ¬:ÉÑ_Ï{ȳ'l´Œ±y_^åÕVyù»îêÕºþàWfºäšif¹Õ†+ÝÛGŸûíýG=üe;þƒuÎßøÛ_®1zöéÿ´Î,GNørµk>œ}Õ&LÐw¯ýñµ?:nÕ“wúl›a¿zæµ3÷~éÓµ/˜æ»þpþ–®3ÿz3íøÎ¯Ï¹ÝŠêƒwÏüõê­2ã¡ë<¸ó¿g;æ¬õ?¹hŸ+þyç”ÿ|ä×ûŽ:¡^âĽö}çíûO¿óï¿Ýûœãï½çú#n=w½Óg:ü¾·çüM^išÓ;ý¡o¾ù¾óîÞéåá“.yø„F?òï'¶ZmQ5áÐUg½úrsãí[o=ÉŽ×Ý{É1SÞ°òÇûßwÞŠ.8ã.ÍuÎÈ£¯\ô½c™yòpݹ§m–6]tá;ûö ¾õΜS|üÖê/ÿ&ïýÔÖOõÑ—žâ¨‡Žûˆ}÷¼âš›N;î¾ WxæÏŸÌïç{üªK?\éÛuVwá1'~¿Á“?æáSÜ6~t¢ù'wlÁ‹Ö;ûýs›a“Üõüï®Ð¿º}£]·¾lÜ4ÏŽ³ôgovóÒ÷ͲÛín9–Î1×ð)g]çà—Ûnëzí v|`·¿ÕøÓOuÙoŽ3ßJlðø\—Ïvá¬;ì£=÷Yé¯nɯÏyÜŠW>øï[/ùzøB÷­wüýÿÚö—·_sò毽òê»ÌyÑíühïòÞ3„Κ|üe‡­úʳž:êŠ3V^ý–yÛç®ùvÂÈSV¼rûùF-½Äû³½yç»KüƱ_m¹þº£Î:gÞÑó?ñ vtÝó÷øàÙ¿œþÉ:ϼ·÷‘+,;å§ÍiÇMrý²úÃ.zú…ûïçwŸ²¿æž/™eƵ/Þù_w¬0Õ¤Ÿßxûr¯óìØ¯ÎøÕgøì|÷ÈB7ÛnÓ97} ½çî;O›ä© æÏ3Ž\dÄZ›­‚ïºÉ«Ûλ΋Ÿ¿°íS¯<úØòKþË}§zrÉÓ^|¹¦ùÔ÷޹x‹öwLýÆÅ;7;|»ï×3žpß ÛݼÁOw?æoÂz#Vkýñ•÷ßžñÄkÖ9uÊé×Þ~éa›N6~ã5«OþÇ_Ýö|øùÆ^ÞúÜ´{;ÛÏv[ìŒéïxõþ±ëϰØÈ«–ý~­=V;ÿàÓçî‰5þøÉC÷ÿ«ÓWoöøÕß^»ëŽÝÖÝ雿u/ÃkÚÙ.¾GwÖÞ#»kÔôSí»^{ÁÓ½û›÷†ôþ’ûNÿ›ã¶MOÛV™umï˜yüÇÌ1õñ1~>å°_?1á½óGÞ} £Ö½à–)v{rž­_ñ·GÏsøwwl1»¾k‡›>Úî'ÏúÉ1¿Û~©+.ÜñÌ+æ¾ñ‚õ缃w.Ÿì¾yÖXáÑ‘ý]¯=|;ã:‡¬qü• ümùo¹iº™>¿qõ_ýó°í¿>kΛg_òÈq/·~Zïæñ÷ïöÆ 3¼¹î7_sÌžcsÜ‹M{ÕyÏO}œŸrÏßNñÁSüã¿\{ÑÍýþÙeß—qýdkyÕ¬+¿V×ü뉟9ì¥ ·;þƒ›7ç©·Ÿ?çÊ'oÞúç»éÅž?i¹_í¼É‹¬´êT/Þ¹Ïøµwº|•—ïüÙö'ä=Þ^¡ùí„Û^œ0õèg™á¤á'/yýë/~;Ù îÓ¹Ož:Ü0ú£>XzÊCOÚç­G¦ºéž WzîÕïŸoÇf£eínß,:ˆQ·Á5{ïï/ñ?o=¶ëL3½>bó ¶ŸáÉ^{ë½ï_Y÷üßÿé§§ž½Àc³ýûôɾÙè®WNž/o¶îÇö¨g9îOÓϵÞ57_vÀŸæéÂõß9ñÜ7G/1阧mN_y£I;öÁuGþt¥kNßùÍé§™æÆ±oûÙ³3]õ«¿Ìôöˆ^ÿÍ΋l?~­ýï=ÿ’Ó™úwçÍ1ßÕ§þþ¾ WùÇëg›ì†?½Ò¡0Ô½‡_³ï7½¾Ò¶_V'O{ÙyW\qå/ZjÌT‡îõØ.ÞxÑË,=ìÔ»w_ì°–xço£ÏÝjºv«g¼â„ÍwÛ}ñû–fvXjß±s]ùÎ+Ž|ÕMù×F.pîONsÂ{[½yÛO®Ûx¹çŸèÎSüÍÞï×?{w¶~ºQÝ3§ŸWë×—:ðÏç|÷Ñ7ß|sÁªù¢W6oWžqþ…_›ü¤i^ýå™îØiÿ«8oì+ÃvõåË+ýe‡_¿ùþå /µäÂÃ<`µeW¸e‘E–Ž OXè—žüÛgߺéç9õ¨¯–¹á%WZ~üS´þ1·ºô‹ÛŽzùšÃÏå±ß¯uð½×ä›§8ï€mßÏyß‹ŽYqÓÃî{âõ1µ¾ïݾ_êøÝ¾ß®½éºoN?åè/Yñí‘{ÿdûÙ:‡Ÿ÷Ô¢ß󸹝œ±™u‡IÿòÝö«ŒÙõ™ï]øµEWœâ¨ÙN?p‹{®þÍgýŠ3®9qí5óð¤'>qËMO¬uÆ>ã³%ÖÿjŸqÝ9Oœ:õ±k=c}ÌÉÃ_Ý`÷vûvŠ%®;öÂ}æ¿ñî v}ôíÇ7}5ͳ›.sò”oœún¸h¡¹¦úæÜ/¼î†¼v™c§¾ðë…æ{é ¼ú[³n<÷øÿùv»›Çí9Í÷··ï·ÁmËÜúôÆomèßXlÕ›g™ìëmxrÉ)w?ë'ÃŽo>û“Ë×ûî¶õF®±’ÝñÃE¿9sŸ³¶¹êï}þÕYOšnø++ìwÇR}dšA@\fÜãW̼҅›o¼ò­ãÕ&ÿœoÎ O=oÌïÂ’O}÷øI£ŽŸçÊmw]à¤3^xiéO'û¢?߸ùj‡.”ú#Ÿjï5Ì[)þô·G,³ÞCã·yã[h‹pð„Ó–þhîfÂÇ÷ÌñõÚ/_õóí‡ß¼ÖºË.tÇ ŸL½ð¿Žväí;Þ>á¾}6›öû'¾¹ÅJ׌Z`—u¦ü’ë.ûÝ‚ù«;à_oß´áþ{LùÏ3–ùþÔYŽ]ëœç§:hIoýs½èë~ó»EξÜWËÙñÏlúÁ’ûêyw¾üwÇ?ôþLïUŸ3þ‘ŽZá­¹ü­‹—˜ñéÏøè– §}¶¹~ƒÇßÿË­S»×®<ðÍ}Yxò©÷9ìà]/Ùéê·Æ?xä½ç?zÉOœõ“ ïÝø¾sŽøôª“žùê·‹6aÙ—Þ䚷Ưuþý·Û.ùú5ë­|è“#÷½úïoÿtí7 ¿:oú9&í«—ßÿËnå)Ç/:á›§Øu±³Ö¿à½©'ŸüþæÙx‘žÙg4¾ê*î°=–¸`ÇÏ×Zó“Ï¿wë[žÝ{¯eo?1ì¸ä„ÅêÕ*Ïî÷ÊV·]QïôçóŸjîYžyz©õÿ°òß_üâ?wËÏsê*ã6t‰—Ùö©ÿÙú¦W—ÿçßúŸëÿ5|Ííw|÷'Œ)»ÿONÿZû_õ°Íî?ðÚ#Æß{Ö3¯:íÂo<¿ì’w3¾½Õ³WäÇNÿð¹É—~÷·'=Ý2ßο’þzŠ·~×o®Ö]t×éÇ}þr‹?IÏvûC—>²Ú?Øz³«Þ¿f¶e—ýþƒun¹É?¸a½-GïÿÏkÏ¿jË]˜áª{âeÏlõ×ׯ|vüƒÇÝû¨ZîÙ…^¾ôÛû^ñª7MÿÝZ÷¯z×ë;þmêéÖ?õnxí‹ï·Ý?¦½eÆKOØz/¨¾~À»npјçïyè!Û¿´Ô_wøõ‹ùçÿzcž.;pD'¼¼Öj÷ÍöðŽ ~3þ‡ òÛý‹ó [f‰•w¾t™iwXêy=Ù>Ÿm=Åö»n²ß5‡ýIÿGñèK®\wÚÿºWÕ7ëÁË|·ËÏ÷[s½/—˜t¿ÏߺåÂéž]cç§_}s³†9õëïÞ¬&»`Ò_ßkÆÌ~Úï~òs~·“¾øàÚßNùþœ«­zŒºcì"¿¸û€Mæw™)öZq¨]t£ù÷óÂ.Wlyèw:ÕkNX`²Eî=ÿ¾¥ŸûÕgýš3ã»ãn}Ü‹ç¸á—=qÿ½Wlõç=²ëŽ~¶ó^Úõ¯;œwóŒïï3Í3·L³í[Ýw{Ýy×KjÿmÞuíµwÛ¨úøÍ5»‹öšnÔ£o}8u¤q¦z¼¼ •ñ¿+Ú⊦ZѶv6ª”²ò>ã(µq¹qÁ¨ÆwM£B›œù¼býßñ’UªÍ!Ö 'ȻƩß³Õm‹ Ö©ÔŠñåÕÐ w½O¡W*U®M¾îMJª¯Zߟù˜:Ó4ÑçðßCyÅ!›écеVu'ÑT §§ ®Ù´&¶Ñ«>ûЊ^63d4µij«bˆ¦åbX£ÑøÛVg§q’t¶­oš<´ÙuÙjŒ_Øô¦×Ê9«*Tº­ëTW5&&ÓÝvºZ²l6fÈljœðäB]…¶3p A÷…=vѧ?HÙª÷nhɲݘ!»iµ2NaÙVWu§{åá3’ja[)&,LƒK– G,YY¯ê\qgµ‹þ±5xçW¡ûÎÂ]Z£í¿K–-Ç Ùb]Ljêz‡«}Ó9­úc‹Ÿb›ë¶M°¡!ë®'b:CÆøåt„ñÀH°U8˜µoCR6ôÎ76wÉã_‹í)ÙNƒð7ÍÕ!Ña…V‰oY2,9dŽŽÖinSG[Çþ[ KLÊ÷]HŸ—1ghÉ’õ`I%¬§Ç>û®ë}]UÚá{ƀߥ]hRSYÓ´">¨’õ`É!ƒÔº[S‚-ÂmÛÖälTV•©CÝÙˬ;Õ ½¸*Y–2ÈP%¸1Ä_g“jD[;_aU@hlªh«Ö ®JÖƒ%‡ JùÎàÕµƒãìSíñ RW5X®S«¶K­³CK–¬Kdk¼CIJ'o׆c—C®4qêãÿU%ëÁ’"e|{Ý%@þd/j/áÓ{ *àÑq"¬pÀªd=XÒ‹h«5œ…1•ÑVÇ48‰°H¸ÈØa©…Ÿ†–,Y–²˜¶±¾‡Çqª½ërí €m3¾¯Cloƒxñ²õÔCÖS5½u!t@*ÂN„†iöª©Bàï‚8—e멇¬Çv]Ì^4ã£Â‘)c:¼tζ«R‰X—ð;†–,[O=d=Æ8£}‹ƒSÃe€ƒ¤›»¦M±‡óuA+¼w=„\ÊÖSYOTp]6.E×ðˆUç""®®|¨Z@8´dÙzê!ëÉ"—OÀf0Ç®íð=;×´ˆºF£lxK€GCK–­§²žÑV#ò·«ªS úœú˜á†ÚÔwˆêU3´dÙzê!ëéaÌ®­›n(ë¾£Õt¹ ÀB­K–­§²mûºEÜr°qÛ›\! ©Þc!þ$|ŽÖGoM7´dÙzê!ëqx_…Óè£Éiü{B¯µk•bÔ„YŠí)[O=d=øe»Úš€_0Ú6ÚzCMÝWŠ`³ò—ºl=jÈz|®|µÁÑ48>ο¡‘Ü#‚d•°¤rnºl=jÈztG?””êS¥à'”®Z¬Žtµ ‚y«t†"¤.[²8³Få¦ç9‚:Õ÷mè5ƒ†­,Ót8¤C(½l=bISèo£²Ã®hƒ=VµWpt¾ÂJ@LU;´ãMÙzÔAº¨ÿsÒ;üE ™«›.Gø¢i}îrTó¤VÞ‚ò…®íƒ`snØp0¶Ç1´dÙzDžÑj8Ýá„f—Q¾GEãúH'¸†–œˆõ!еëÀñC”Ãç®óµÖHÛ‰„­-[È4‚ˆbg»œ—ë¤ñ˜Á¶ÈË…š˜‹­‡–teë©F|bJÇ5Ú2IoàñykØ#0r°ñйteë¹F˜"Âulà~ðÂن쭪£1îN)bp—‡ +[H6&P10S Aá3À©¢Ö¾¯ É}2ÙøÐOy"W¶‘lúè볯^Ð4¡²]ï[_Ä5s‹÷Ö®l="ÙèžôÕ)¯*—qìmÓ4©†eþÕµâÅËÖ#’8”ˆÓÎíxR›„à˜ ¨zÚ`oBꇅ+[È 6&#ê´}ƒ¯L®#üð°«ÀÿkØzµàã®l="3˜Xs±b7>d„9™€Îœh§s«—+CK–­GdSk˜ÉÁ¯µ^çʪ.„^….b%8Ø÷A0 W´žZfqÊs¨ê¾‹èŽonÌ>k&nÃiʪ­§™Á”Rijµxý®ê]‹ó®: J©ÁoUÚ½ Âç‹ÖS‹4žç$209Ú4&V ¸{’#>(¨ ø*ˆÐÐ’Eë©+™WïåkêEX)ˆJð j¿öÒ¹®6"kà‹ÖS‹4^Ó· OÚÁ{ç¬M  ø?7ªÇ¦Åèl={|Ñzj™Æ  =ç¶'N€QvÑ}U9ä…_@ŒGÝ­§i¼®NYÅ>)ü¹ªCTèSZmˆØ”g¬«Ê็–,ZO-Òx=-0‚@Ä<¼ WtÀ1ÜTøQ¼xÑzj‘ÆKX©Âql«™\é= üzªBn%w¼h=µÈ¹Á3àä÷YãŒùÀã³ÆP%|ÔQ×€ÞIœË²õÈœ€†B„± Qˆ_:U}×wx_bþŸœ¬óZ¼x([ȹ[X Ö®ks‹?wo€u]eœG ô‰+–,[ȹá[61*‚„£R®w|Ã>®këBk–íHä+0 tã3P B9x+¾%ø5ï3ðeCfòÌÉwŸˆ‰Ûè:Õƒ´N)3{:Û ~©C-lϺ겡È&ÙˆÜZC£AÎúR¼2o>{ݧ¤@ºÄ»—µHA "¼wT‘©ˆ¨†nb¯¯?ŸUæ+á“Ë„º‘±86ŽÍå\ ë (սáè*;벡CS÷ è6Yl¶S0÷è›¶ê}?èŠñw=<•ðÉeB-R† \_ä&¶d§8J 6Á;*P4z¼<Ž’ÁVñ{!×,k”Èʦ¬ðc¼’ÏX¥«]L€©§”KÖõò{íHU’G°xfeá+@°è’˜jÕ*㛡©·bÍ¢©J^A˜”"œh•áßCŠ&8Þ¥ÛÂk–HÈ$üRYž ×äe5oA´Ýc¨À¯ðÄ1Ú¬{E™¹s]–º¬OP"Ù ?gÀ …ª=e *xP†Ê;ÊL¯ •x÷²@A‰l/,ÏÃ|,3u<8pEÎCõÜÎn2Ï/ï–ë²BA‰t/¨"vG1 Ë¼É¯ï@¹<ö'ÀÂÚ0D)£žˆ Ùfï|±çU&ÂcÂN;ø©–écÀ¤ÊUäžVœù²FA ݦ†ßÔx{íh¡…!m±Ñ3àéñ½å»—íH$‘…†èy°EUWØ ˜2™&¥9J›ºIæGï^¶#±&>Ó±ðê”Ï{x\[lz¤€Ð&Ñâûˆ5ËvTK^Œ¯h@R[ƒpÃÜñˆÌÚx¾>Îo%sAe‚’©éØ«ìá'Mnéà›(ÖzÛ59Â;ÃÅPÖ8´fY¨ Dnº†ýQNYò:‚Ò ûñÀ .ÅY«³Ø÷²RA‰L²S,§ IµÙÂs(ø÷¶¶°`¦–pèqN¤&¿lG"• bÀ, ¨oCëy¡Áh‰mÊb¹f•¢Õ0ú CÔö9Ô½‚0Î=ð¨錒•Õ J$¨}E§o_¬Ø†¾ka­Mçbc¨|€Â~©,WP"CÁ,–åûvz¯®©‰;‹®êû^¶#‘¢æ?ÂEàÔ(ë`–ÞEð#€Åç\¬N^–ÕeÁ‚9jÐÞZWQÏ×±ê !îÏĶq=‚@š•{T¶#‘£¦ÒËj„t•˜@¶.ô€Êج œ¡Í ɵö^–,(‘£6ÀJ¸¥ïµîëØ)<(áp+ÉQœÕä”:%Î|Y³ ~$ í¿šˆgƒ'Õ­±>aÞõø`‡¦Q¶ bßË¢%òɶŠUìjxO F ±g¦¡è>tø&m–yÚ²jA® *Ù›6ë̦ª¯X°ö-0'p8ŽܺíœÄ´eÙ‚9êØ5U¢ðÀ´OW=ï\Í*§l›„]j™±k–íHä¨Þ|c`>nrÏÿSuï6›œ 8œ³Ì¥—… Jæ¨,te@Ü$«Î”¹¦W^E€[¹G±#‘£¦´e¼*ñÞˆµ©C¥LrmGbìµ’Q¾{ÙŽD>®,'Äá65a1ƒËd„Ó(ö1I_WÖ.(‘O¶&ÁN𦅹Ù²M[·¢¶ ß | $"8lY¼ ×nEÄÍ d‡ugk@gð  ${MJUÛK¿TV/(-ÅxNGOßa„›&ªè#ì1G0m°`§âÌ—å Jä¨3I%˜x¾ ø=jâ€% uÓ‘—ˆ3_Ö/()f5 Ù™^µÆ…D ¥št©Nxd¦æ(üRYÀ DŽ r–xÑ'„Pg£ÆÑcR±eúÆÉxTV0(‘O6¸¦e½Î ж°k=câÍsâ_@ÏF®Y¶#‘On5ˆ„8Ÿe ƒùdœJDøÜ)`^wt§Þôœ‰I¶Îí¤&Eù='bG’kWˆ9¼¾ÅÛP6µ}ßi×÷¥T8¶,-«ÔrÔ¾ªÑ,®l}SEM<ÇÛ(ÞÚ¶2A÷Iò£²ŒA‰5[Õ <"|Î š. dT•Cp¯ÁÁ û,s,eƒ9ê^@ˆ¯†Ϻ¬R½I©l4æ)Ö,Û‘ÈQGœ¢Hòj3°¦IÀ:Lµw´m¦*!A­ËJ%òÉ®iYF•É[S¡ Ø´;ÓYÐx`°Ô·Ôqˆ5Ëv$u­°gœOD PŽÆu‘÷Ü ¼i¤ ¼\Ê2Æ•µ rMÅ»Q@oä²éðß*äh TÑÞêÑN`†²˜AÉuÏÊC€ :¼y…CPUÔR"rÔ@ž>VøÏ²šA‰uÛS :ž|Êí{“L€ñVÉhåéGÁÃå÷,Û‘ÈQó /ÃÁ­± «·ðQP. Ô¤`¶µÄ×e=ƒ’zÙºFl‡;VµT:;°C|Œ³4$F±¥UCÏ©Êz%rÔš"f` @¦æˆŸÞ›­ú¾Ið!YˆâUYÏ DŽZóJ?DžÑ,¡îzÖÕ[ÞT9ìx›MÒªMµX³lGbM8xüy­YjAZp+­µŠ.e¦pà_—:QÉYÖ3(‘÷†C¦LîÛWƒ®ƒ©4Êê4@Ej-†Ö,Û‘ÈQƒ£âØ.ÁæìkŠá"¨lÑ‘|Óî³(µ-ë”ÈQ·ŽžèKawØž ƒ¸Ã+S¼ÇÌ þ …X³lG"Gí=H…X<¬q.á´Ûsq°bËk¹V~ϲ‰µ†Û€5Y¢a«hl­‡K5¦”@àëåY*Û‘ÈQ{ð4o€[qšúž’¥à© Cx¬MôöG5Ûe;’yïž0,þ0U£$ [)Ë{ü žy(nª²žA‰¼·q-µÖø·¦ð"âMRíc5ˆÄU ×Ve=ƒ9j„É.˜šÇÅVÞ2u€eÓ7 Ë p¨LÉâò‰Ø‘àÅ‚Û,m‡{W8[@N:aUÁÞ»:Vò9‹v¤¥Æ—Yó ©ê#_{*^™#ÀWÈ5"«²žA‹uŽJÔ_ZxQWoã»!ºw9¨À/÷¨hGZ䨊ÜmïrT;‘¶]•’WU±yeCšÅšE;Ò"G]©ˆïˆ˜V±öl>·­‡IVpþ¶5CI¨E%¯*ë䚎 £¦m{r–âYß»¶Æ‡Ä«àw€M‚°£²žAW²Œ )ÓçN·àHÜÀšc¯Îþp$„O.ë´ÈQßÛÖ5%FYãuy·OÙ€ám˜7%Úß³¬gÐ2G,è¥V”­Ã_Ø–ÞµâGV®‰ˆ}>¹¬gв±@SoX±B­EDœ ½oñŸ '¬íF@íµ{TÖ3h‘£V,…ΈŒàľ_ÕÖ°å ü3ˆ²…é‚%¨N>çDìH¯À-s×in5µé´!EŒÒ >â ˆœª*ë~¼&(º©ŒÑÑSÇŸZ`{LЪc| ?.&âQYÏ EÞ»žçEaH`™-¦u†Ñ7ÕsA³Žv’ÏY¶#™£n=¯w5{g4½Ñ|¾ÆxPâwü@t'”õ Zä¨A*”Ž5€— }O½AB¼ZâE¦Ï=³òÝËv$rÔ|ÊöÁ³õNhj¢×ÃÁ;_[Ýð@b›²žA‹uãXüÒ±¼jÙQ‹_áÃØàT0§G>gYÏ EŽºÊ=N‚FÏ,ªMl§êẠ˜ —ß³¬gkºøÖ*xß)@<ؘ ýàò§Ó6oµ`rB³§Êz-òÞpvÏÛRˆÌzh6«`ˆ=[sxöbêsâdUÖ3h‘£lOøE’‹¶Gh"k}p0‚ûò9¼ö^Ö3èZòbàøh ;laä@5¼ÐïCòšµ ÊÕ¬˜‘{4;ا'!ž±ú Ÿßð@öp¢`šÀÜ`¶:ñ´ ÿYÖ3h‘£®Ø‡лp Xª»Ú×l T#N€x¹fÙŽ¤Ž¸ vØ4ïßx; ÿ©³u5ÈvR=;¹Z{ª²žA®É ˆ„iU`M MM¹»6XKi: t/ÏRÙŽDÞ;Ô.QJÈ„ŒÔ¸GÕj…³Pøž${Ò”íHä½q†@½=[:–A9Ÿ<0gçXžjþ‹°,õuª¬gÐ"ï kÄ3Ö,tµ†Ý¶*p6U¸7‘mdj¡ÿTe=ƒ9jôdËR¨,¹vYÏ EÞ[ëS—á'rÏJ5ø঳5þ±ÏÑÖ¶•äqe=ƒyoÅ.–:Ý jÐu uàø‚¼¨¯i:–±Á¹Êz-Û8dpmݲŸAÏþmKo <ÃjDºPQU-쨬gÐ"ï½Ïµm =0úÚP®çBŒËžý,X*Î|YÏ e#‡+×­sëŽ7¡ Kî€åaªÉU!å@¬9;’±Øäd‡N9K¢z ¦­{(g*ÕG-û쩲žA® ¢màó@¼cÐ8¬–Œ&”Mn´âŽO•õ Zä½½²¶…áàtl’U³òÅÕUlsòŽÒÀÄܲx÷²žA‹¼w¦e7v#³™§7b×,Ã.RU“ª yqYÏ eÞž“5Ýœo§…ÎM ÿFݵ8)³ýU'¾gYÏ Y‰”û6Øé n®j˦N ú­!v¢–X•õ Zä¨s`“>œp8 *ôUBÑY ñ1»«@ßµX³lG"GÝX8Ï@ ¶ß{Ä BZ#«Øð¸ˆ¸We=ƒ\“­pqÌAæ*„e`š¦ÍÀª†‰*Ôpl…O.ë´ì+QgËVË ³ý=œÝT»ÎÀíGvDTrßËv$òÞ`oG&Œ%z¦ç¥S΀"=‹Ù€ìðI„O.ët󣘩Q½9‚;š%^ŸàQ`_Ä7@-îPTYÏ eÞ;uìz9 Cº‹¬ ƒûeì)/íZæ­…ÿ,ë´ÈQ§ìT"³ ŸÑw8®Ú;(<¤íª®–þ³¬gÐ"GÍž8„Ø6›*Û:î†MKØQ®[¦ð‘Ùn°lGbMVb0£X,•kk 0ÂKHÁEQÀlD‹UÖ3h‘÷FèAÜmr„q²m'¸1,Z¹Tw•­;±ä›e=ƒyï o x4‹+M_á½/85û ää»—íHä½ûÆ#bˆh OœÇ.´¼ùhá÷\1ko¥½—õ Zä½+Þº{à-ø¼p­€D=ø1mG§ñGtl‘(ë´ÈQ#³E^öð ®o™V±ˆP¡…çg£ Iô`Ve=ƒ–ÚlWŽSdW» ßNÑ5¦•œ`¤l]YÖ3È5•ïñîðiªc…²Å±j*o} ÞÙeà°Ö‹6ª¬gÐ"ï ÞÏF L ›È|[î €Zæá# ®àñ]Åš±#Ùá²ëy#Á:šcpŸZì ¨;L=Uè§Êz†Fä½c6D¹sß:Pyp b%Úc`Û\qY¬Y´£F6·ˆ¥Âóv®o»\W8—ìÎ[×~Ù×/•õ M%ûPcwðÇ3âƒFÀk}[<‚³_Š÷жú‡-ë‘£ö‘UÀ,”2޽»ÐGê«®ÁsBe|_¶skíH®‰ƒcRǦO­Æ^ƒ$œ~*¡É;•sGA_-ü|YÏЈ¼7ÎR¯s„+iú¶F ψF D0O<³e‘Nk-ß½hGM%; €”& W\V>µ¡eßZ‡à–ëNSèë­Êz†Fä½µâ/Õ¬œï[«[¶"kø‚œGðhì€A‰¸YÖ34"ïj°À Ð&œÀ]³[—µ–„¹‹,jr¼£¬ghdG]GyµŒe=ƒ\“y´ÌF¨– ›ÅlUÇÕ¶òºky›ÐæJÖ®ª²ž¡yop¸*v ÀM-E UÅ´Wòƒ„*ÂTíšÀue=C#òÞø<}Ëbg „ ò Ã,]êR_žT È1©Ü÷²Im6%kÖu «!ñHøKÁ0Ù<ð«Öðlä+ügYÏЈ¼7Bƒ¯]eØÛ a¸ïNEÐU0Â<àƒj¤†\•õ È{[ƒ€Æž3 V%–Ä‚ÎÃgö^=âܲh4 Ù».ë‘£NU™Ö0Á35\ˆµ H˜«©sãðŒ,V‰5Ëv$cãñr‘ó#@ß3` NöѱmWÇ2þ®]®Y¶#Ù:¤Êø½ö1Û:²ŠC³<²W®5ð× ¿h1[Ö34"ïmÉæ“NŒ“µãÅl4å>ÂÀðY,ªmÜP—õ M-ë¤öb0 ‹uM⥥ò šR ±æDìHØ»¢ ʪlŒkPîŠ=hàD6G+*ø/t¿º¬ghDÞ;!ã—¬Ò®êuÞÖ=ö®¥Š=üG°lU"Ö,Û‘lX!°‰è‘+žÔ×ghó_@z±mE;]Ö3ühÍw„è`B¾J9Òw5W¶ eB¸éµ•{T¶#‘÷¦lÍX;>°ã ¹©ÙQÝ3š¨ ]Ö34"ïÍÖøx"“ûбÃ.>„ª2 Þ³jGª Zæ?uYÏÐ(Ù£¸ƒnÈz+Š`C]w ¼3ò¹Æ†‰w/ë‘÷fÛMm7èFJ©†åXvèë0rn5ÛD%ôŸº¬ghDÞÛ aµÜ"ØÅtDª¨J9>€°Í²ž¡9jΡYÇÞc}òA+ƒß–x­bbç9±@>gÙŽ¤Þ/Íü§{󚼸ŇlÀi 1.!hÚKb͉ؑ¨Å §£x:÷}„cg©lÀD¶wT=/‚ØWž¥‰Ø‘¬½â™àØ4æé{6ºèZ?ŒNŠJ…¨åše;yïÎxË)4ðð¼øŒ¯ cdO |¸hN2¢ƒzYÏÐȼwb«Uv9ìm`³kÏÞ&pq`ŒÙv`$š¥Nâ|–õ ìÒd´A‘ ‚‘c8óuº@)ÐVSÅ#Ö,Û‘ÈQ(ð¥.ö,¸LlÈÐuìNÛª,v®K5€ìq_¶#±¦ªYÒÁö˜>8ø.ÔÔ7ù øNÒ@ÙÃÒ²X³lG2ïm©W–›„ÃÛ퀶ö ìÖW‡Œ\T4{/ë-cq3¨”a©%aÙ­Ê]î©Hº±wâÌ—õ ìIÒ.µ@_l¿Quø~-ܧ­˜¤àë쬼+×e=C#òÞˆ’«XÀ7[Å&ʲŸžé Â~# ú ±fÙŽDÞ;UŠ½Ø¦¼ÁB}…¥”Cè- ŠŽ™­>¦Õe=C#rÔUâiŸÁ±’ À› GZç†$UliÌ-êä¾OÄŽD}‡ ˆɺí˱ËÂ'§Mªñìì&콬ghdO’6ÃÚk6LQ|ñ tÜápÂ:UiìfCQÁÊz†æG=I4NŽoqá4áòžñË{Šäx¥ÙïC¬Y¶#‘÷ƹkÕ9YPÍ`¤o\ˆISÁAp/F @à(xÊz†Fæ½s7(V'ªWHø@ÄÒ †>èøÆÛ,ë‘£Vˆ—î³ê£©ïÅS¬…dr$TBidO']Ö3È5Á³U¯Mç-•È]貞¡‘zïÈF Ð3$,(Ö¬ @à¡+Ä™/ë‘÷26ƒ®N0k ð;[wì_JµIÅD¹í꺕g¾lG"GMŒíµîrè$pêwˆK)²! Â,!ÖÄýwͲžA®ÉK˜:TVˆSÏ~KزH2\ñp;ùJí.ë‘÷FˆÓx[ c—^Q“ /ʹxV€¶ æÑkNÄŽ†ì­D+vj¨¥Ô)+Ví øÄ)hmEF'Ö,Ú‘yªu°Øwøµ;o©0rª‹€eìÛXe -ÅšE;2"ïÝc“*ÞÈNªíkç8}¤Ëý g'ôÞº¬g02ïÝÅd"Ã4'”!þtI³22÷ƒ.Ÿ¼|÷¢‘£x6€ìmh<¯Å¬ÞWg;²±8L­œ‚UÖ3È5}•HŒ38bN´ºÚÕ™€Ck„&ÛTÉw/Ú‘‘í§{‹Í€“ ¼Æ×ì·më”6hµêÖxRzùîE;2•ŒÅ}® ݰ®²gWl‚zä˜:¦E™b±¢O©.ëŒÈ{çÌ™Šî ì΃½·ðYë\W¬Ð-«¨ä•õ Fä½+ÝÞÉäØ ´¶¼Ã±tèIUƒ¹u2gUÖ3‘÷¶5œiuÆáX2MEßÉèÄ+¥Ð“1YÑÕZ—õ Fä¨?˜3KÏ6 5o £U5øgvé4ìÒ!pHYÏ ×l“õžóØÔ—XSÃ»Ć•pÎ!@à ¾YÖ3˜é½á? g€ý[Õªæ `WYˆ²`† &Ö,Û‘È{ƒ^÷­AÐnÀ´¨Û1x Ê?-€—¡‰Å²bͲ‰¼w¥ÌXUϤ– ]êþ;7¨f¢íD¿_]Ö39¢.ýñ‚ãmZD9ÏŽh8’ÖñÂ"!ȃ”è­Y¶#‘÷¦Š¿á„­.*¶TåŒjaú½c/e—UŒaÒe=ƒyïTuØ%`·°cªuùL­e`§š½ö¼ÌÓ–õ Fä½9–›YIÞF¥:DÇ § a÷šÎUD–*q>Ëz#rÔ,’Hg9 Ó~S¬*FVÍR`&WW¾u=º¬g0²'I;h3æ=…kŒ¬/ìw^)?Â~\ ¶"n–õ rM MYÏð£5ž\f'U |ï:¼5@¸ölråbŸàõD߃¦¬g0"ïm)õ5`–gGî¾b뵊iÀ¾ƒé'žB=±fÙŽDÞ›M± <ä=Î ŽbljJ]£²åoÇEN𣦬g0"ïMR­°(p6§°ª†Áìu0tß ,&vÄše;’üTÌ„±é ¨A,ÖvÞ…õ?`å6Dm`SÖ3©Í†±³– æX²mú&dЃ‡Xs Œ¿kŒüže;’=IHWðåXÆï Ol"˜L$dtœ°.Ÿ{Ñ«³)ëäš!öM]ãüØÜÁ•² ‰ 1Í`V%åÙ°\ùî±#‹9¸Ø‡–!¸VƒoræagÁÁìgvÍGˆZ³¬g0"ïÍ.C*–/z^RD&•9ü§&Z¦éãç9”¶¬g0²wÆä„+P¢›b¦ÏHëS‹Ðg6Ï¢'^SÖ3©÷fw@ø$øe8y*.€,D†…5¥>ÅØ‹ Ìe=ƒ1’ã&`Í2ËÆ}€t;t6€Ñ9N¾£n›²žÁi›*²¸¡«9W¾áAh";öe‡7¯TwcËz¹&ïHˆHjH¶3;ÆðNš×C-ðü’ýÑ»—íHä½u [Æná{›®U®æP²ìL´ˆšÿQ‹¾ÄMYÏ`dÞЗBäÆ+XŽÃÈ ß5‡AáiÙœ¦|³)ëÌf²-Â#¨±b·FÇKlQɆÄ8e>rÆCk–íHæ½]öŠê•–³ÎjÝ’! Yßs :»‘8Š\PSÖ3‘£s‡k8·ŽÓ ÁcD+vÕ¨C­ãTjqÙ”õ Fj³ ü|ǡɶBðíÙ’ËEÊ+?@)Ž_ØfYÏ`EŽº À‡Áõð½0Ø:·æää.±ô¡~ˆ¡z›¦¬gkæÁ8k¸5Ø8»s*뽞át&öÂ3"‚ôbüvYÏ`EÞØ¤€åé=Т³¬i²} `Z©o8XŒVì{YÏ`eÞ@#ò¦Á¯4QU@âƒÒâ€îäsíÈŠ5ð00ãI9©”¦r¡«q€@à4T¯‡o+'ÃíÈŠ5°f£º N„ÇaG0+E'ÐçØrà¼eÞZÔ84e=ƒ9êÄ&Ö]ìÛ® YyÖßÀ5³•HHl¸Å\^£EýfSÖ3X‘£f©O`\K±NÏ‹7Ò¶`ô¼Z3›²žA®ÁŒz“Û`z6Í¥ Äi݃ƒ°W‡´÷²žÁм7‹ž)òäÍ8{¿ÆÄÞ¢ˆ œÓÕ;OaX•\s"v$j1<›>möàÄlN]ðWzƒ}7œ_¤\'{K6e=ƒ•=I°1Tƒ¼¾¢°: ”böš¹0±fÙŽDŽÚb#†Jx ð…“騈tÎ6ø»:X])é“Ëz+rÔ– °eŽëjÊÕ ‚瘚#Š\ÔˆGJjJ›²žÁŠ5§&·‘å"Û§‚fö_ÉÀ `1³A \»)ëäšÔÜãƒQ·À  {ôHº.èÎ2«Ê¶×bͲÉ>'  ›ó„¹:@Ãqî=%6åj0ÕTØQYÏ`EÞÛ‡è Ak益¦XÕ#~Àrê›ÜT¦ âN¿)ë¬ÈQ[ެàéá•lÏ:«ÞgN å Î@´c÷>±fÙŽDŽL… h™`]$ÕfÉ~uØ0Ÿ˜³'c˜¶¬g°"G­BíARáCªcÕ?¥ã¦™g9GÒ&/îô›²žÁÊ5¬¼í"8Ž)¢%Îiî›ÜÕ>{ › ~EÚQYÏ ×$]eÙI潞…¢ðhгQû"ßó#TB£Û”õ Væ½ñ(,¿UM€‘LüóN“Sª¬À¶›,ýgYÏ`eÞÛ·!š”0+‚ïìÙÝ<[^ÏÂUŠlÑ ×,Û‘È{GkØõ¿#JøRˆUÃ.üð"§Ëq˜X³lG"G rîšì8f#°<´§Ä,I.èŽm©ä•íHä¨=‡F¹ygÙŽä¼HËI±lˆDPˆ³Ê&s}¤–Éñv'è$zÚ7e=ƒ9j·ìçc(5•zû 4Ö0FœSüöØÉ眈 ٦髶ã¡&åìêrv¼5}Õ ‰ /+@—ä¾—íHä¨+MOk«Ä-v‰MOsGŸòP~¤wMYÏ`EŽºÎOÔ#Ù>fÃ墮¶lNÿÇ,£ˆGe=ƒ\ñË †Œ†N Ak6­SÞ$v ÃS‡¬‡Ö,ë¬È{ÃOdßb;j¯š&çPìÆÃªz1¿£)ë¬È{døÅ!U?ðÌà‚¢œþäZ¶ÀÌPk–íHä¨;JÝ».WÇ^ÍkDÃш(IdŠQè~›²žÁŠuf±3<’‚gKDˆí6ªáu`nËÓ©ØC¬Y¶#-gÖ˜ ;ûÂw¶ì“ PëÔÓsúc«À‘ô=Ëv$rÔ„ ¼ÎÊ1憕– :ˆ˜º MÆ®ƒˆ ÈVî{ÙŽ´¬ƒÎàl±Ž ¡Ù6Ʋ¦ ¥zJåŒË"ŸÜ”õ V佃…ÇÍ`‚¬abú‚Ù,ˆö&²›¸è5×”õ Vä½9R¨m4×r“eÅÛ-–¹ô½ñÄN¾{ÙŽDÞ›£»Ä!»sjÐD”­¢í ´«%¿i ûÔ ­YÖ3X‘£Æq 8@Ì)¶±áäx[øžÈðX{LXnľ—õ V΋ÔÁ³5LHd9¦ñ@²m.ìØJ æªØ»¬g°"GG©-S_: ¾&1“¯ªÞÀ|zü1Óñú0Ïéªã0 ±fÙŽDޛʧºJÎ{ŠC« nOÑÃsò!Ü 'ºtrͲ‰ur[\Vý ¿ ‹õƒ›Ž™jØ­Øgq§ß”õ V䨛Ä4jŸáY½Ê p6‰ŠÌUóJEæÖÊz+rÔÁsL S‚77?úEØ® vL´ FôiÊz+rÔ¡s­¯@-ëØ¹€®Z^øhPí+á¼C¡§mÊz¹&‡Ë²FÎâ›fÃÇéáÃd†£¿¬@q„m–õ Vä½s…`ËÄE¦ô¬·`ˆ¢vÑPÿßô6±rئ¬g°"ï­€9:í¬­Þ„í@AèóxQn“#‹ˆWÖ3XÙ‹Ühüˆã’v,GèH—Á3º¬›6þèÝËv$rÔàˆºŽÝYeëp¹A·@á}Ë"4§¾)ë¬ÈQûTÇ`å[ŽÀ¨|ÃÂzo8Iƒh;…8Jé³X³lG"G]WF!øÔ¤®‡1*öÄbã>NÃ稚¦×.É5Ëvdd|·U k¬"ç 8©bc×ÄÐZŽšozJ×ß,묑öž8¥¦EØ$R²ø ŒëƒÓy„|ãîG÷qe=ƒyoÎ4ä0¢Ì«ÑR½`\™Ù€ 4ßv.G#´¯MYÏ`¥6»”(28H¥Úž)÷­î´ñðTJ̬iÊz'çE*ÎÆÅþNT}êžn¤a0éŠKöåkíÈÉy‘m˺ÿ–CPjΓ†ÝtMÛ²ÆÐâ›ölöbd<*ëœìÅÍ*êF³´˜ÝáÁ¯âzf§Ž£k9ÑF/×,Ú‘\³8™¹¡F™zg0ª¬UGqë¹€¿kvgÚƒ¦¬gp"ï­°ïpËxw¶‘M¼7q,ÙUûØðÁÐ??kíÈIm6ëM\ÛÖ¦oYd€4èÆZW;ω 5­Bä.Êz'òÞ €l°¤q tU…ØÐî¸.÷µ¢œ©cы̖õ N䨕ǦÀiÀ—{kCëêÀbhà±A“ïœØ³¹õq¦¬gp"GÍ‘Õ4@Ë»–½Ý9ãŽÌ`ºdœ–Åì¢ÆÖ”õ Næ¨9aV1ƒj<5Uͽçíâd–£„N>çDìHÞI*EõžSM[Û:ÖkG.ïAiƒí½°#SÖ3È5A bn;Í’‰h€ézÏÆkç´G€ @¶'ŽbͲIm6›«AZÉ6ŒÕì¶¥kÇq]É174ÇÊç,ÛÑzq×¶¯»6iïz é€ñ¢Ž5¶%ú2‰}YT'Ö,Û‘ÈQGÎhá‚Yp5h|QÙ÷}Ç1ÃÞ{P e#Ÿ³lG²'‰ò5k$2Á<à ˜°cÞ!‹°¦x¹¢—û^¶#‘£Æ:±rÌ­a»[!­šZåÕö`cFâSùœe;’9jŠÔ€¸ÞBÔÔ|²!â}Ê@eׂ݈ޒ¦¬gkö&aÅŠ)y÷Îù‰œ`lSWŠÚã^¬Y¶#‘÷¦ìÿÂĊß91sÊ;Àv°LÏv2k–íH΋ìÁª+ZÙ€ ©^Y¬n8ix †nñI’©DŸ|SÖ3¸ZêC^˜„_w dAµ§C%Ë<àRÅÌ`+Öœˆ‰ºÈ–z×NQÄ£j8bxü G?ëX%ºzÌZÔ•›²žÁ‰5d®€ |„÷TTK„`R C­íð)*¹Ge;ú‘6›©% „šãt‚çìR | 8ÆDb¢f½yMYÏ ×6"×ÂK²sS¶Ñ±¦««=àev\IÙVîQÙŽDÞ[ÁÒ¾1g½™¾BrD¡fËôÀöþØB¹Ge;yïÀ›ì¸íIYctÀõšmgÕÁa×lÁ%쨬gp2GØ2;¹^Q¤%}‹Ôñê(õ»ÓGë3e=ƒ9ê¦gï‘*g:m)Mî°ÿ=;eͪAvv6k–íHj³ùÒ°Ø(—k“]WQÃ¥}Ô=[²ƒù¾ÉrͲɵ6°uâ¬H*Ð1ߨ"uš†‚mæ›ZÑkΔõ rÍz*~CC¹Õ /¡ñÌÚ²KÇ( îá*ù='bG{[¸GØÈ%±‹îB=¨gù¦ã¨-ÍIzb͉ؑèÅMÍ|¶L§e`0ÞEdVM€Òs°+¾%üA•åY*Û‘È{óÎ 0qÆ@ }›Àb]È,Lн㥀˜5lÊz'rÔU®’É€g«Ï:N’b`9ûá9YË}/Û‘ÈQWÖsÈgûQác Ö…ĘÑlHÕ}ÒÂÏ—õ Nä¨ó1)ßꌨça.$täC—S¯Ä½¶)ë䚃rF ÐÀ†h#Ç`3eFÌþÁ‰9M¦¬gp"ïÝוÅó(Ö9xŽ0€«¯`S•ƒÓì¡U8¢¢)ëœìIÒ 8TÙsÚ(p¶®HXƒ—,`30û²ÝËw/Û‘Ôf·‘#”’‹œØÔ¦Îƒ"¨ô–Ro7h†ÐȦ¬gp"GmÓ_Mßr&Ž éšÎ-PWב"±d+¹ïe;9jÎ ¬°1QÈ/$ÛãL±1;$°°Gα5e=ƒ“½¸=¨ŸÐ·(R”¨‚Ù¢ùçÈt«Xs"v$I ‘¥„\G¦¶Ïì Ø8Ê[ù=Ëv$òÞØTËŠ+M­?»‘tð|ˆP>e“3#¸8Ÿe=ƒ“yï§™lkN˜AðÈœ‰Ë±Jp-ÔGFüˆFôž2e=ƒyF€à›È”,ç–h ˜¤Nð“‚îIÄše;’½¸sìAXªá~ÈúÎPvR÷P>|`vÞk–íH䨔µ¨ªÑàˆ¾ „Ù†Ô°ˆ3y*ÅX@ Ÿ³lG"G͵Åén9Z¨åØk°es3˜5Š‹Ð[¹Ge;’k6`‚¬/¥$Š8¹M9xðƒL Áâý zq›²žÁÉ”Ùèd|HÖ±…9B}@¬ÄO™‚ƒÂßàs7ÒÞËz'òÞÎ7uÂFµœ¬E>`—¬3Œ^Q &¿â|‰5Ëv${’°¼gñ7^ÓJuØØª‰ï!çNúϲžÁ‰¼w—jU[û˜8¤Å¤¨R¢ÂijáÅܠͤèSjÊz'gP"0K[eŽ‚#"5nØ«ÁÛÜQ±½œ#fÊz'rÔ¹žLug‰2UÓuâá:¥•n ¨h-æË˜²žA®É¬5kc`›U –=Ò@ ÁkñmÕ"ªJ)Ê5Ëv$òÞ¾Óm§ª9VžCá÷rTìÀ 3Y-âGòÝËv$òÞ ®(VŠîH÷¾ ”zƒsµœé ØÔ‰í;½Ðýš²žÁ‰¼7<$ܼꚜˆ5;ÕÏ5}-¸qŸ2¨µ¦¬gp"ï ÉŸ>¶°RNeE8Õ¦NÄŸe=ƒ9j8$¸v„ÎÜX8 %ÕœtXÃ|jï­ê e|ÂŽÊz'rÔìÂÛ'¶ã…ÿ´8Ü쿦"=U0¦ãĉº±rÊvd¤ ÑOçµïú®ÚaÏà=V¾ëJôJ2e=ƒ\“þ¬ã¦°›(ܼåh!|‡P'mA"#Ž•¶¬gp"ïÍH5¯yñGjÎâDXÏH•ÙLW¬Y´#/òÞ85Åà1Oc»ÀQU‰ýÆ\f §ñÚF®Y´#/òÞ [;SާKÉwµ½&éªt |‡ð„ÆÌ”õ ^ä¨D‹žS}÷ ÐÎx P03µ¶â4lФ+ë|%k1tå¨âH`¦û馀 ÉUoàtêÅ SÖ3x‘£î+üV³€Ñ€ EÎ]l[‰x=qÀÉj|΢É5»Èn ,)˜.…>WÀ }WTU0Ûšõô¹3(MYÏàeO`6NŒ™“by#mEö”Ãïc„kíÈË”ÌØ°+`gÅÚ=pÖ ðØ 7ªÚ F>馬gð"® ;4š.ôÝ ’îƒ2®®Šðû¸;3e=ƒyoÓê –Õ½`nlÉ ÌïÇÎÊm•:柂|ΉؑЇ´ â8Wì4õ+‰—3=ûI&"#ì‘r¶ò9Ëv$rÔ”E®Œ‡eý.Ÿ„ ‘(%Ö2v”õ rÍ¿æ;„žŒ¸Æ ¬¸žK ½"‹g} ˜…mÊz/óÞ®³ÁU›©J ÅXÎa8ÄÖ)6@6@·bͲ‰¼w€uLÒöd@e¬ rM¡P @£ TøZ~ϲÉž$žsl}âEiÊM«™Ê÷½f§IÆx©ÍÂוõ ^ä½+ MöLJï‡ÏÃy‡µãL±JR©l³âxÊFôÉ7e=ƒ9êñ:¶@l/ÇLªW$pž8Bˆ#xm/ã{YÏàEŽ:{™Ž‘m¸ƒØè½k,û\±å;Ø>÷5¼kã"à¢X³lG"Gê®ëB3N· 8k*B‰m=°I]i­¥•õ ^ä¨#R OJ ((6,˨RŽ »Ô°ç&‚rk–íH΋déžbëS׃7ÀO€ªkY1ÖqÖ”X³lG2GmëNƒøúH±D‡¶esðVqˆþe#8‚-ëäš–e!*˜Ø° 8œ7KëA7³¬àTek[Ö3x‘÷6*pT7v„MhZ0KPä­ËL»ð?BiËz/{’hjï{vMmmfp„&BM¸À²£µ1\³lG"G]l ›Μ?Šo(vgSd`èì}0V®Y¶#‘£ÎžW›LÝ–q)vAp|¢ÑœyÆ!6¢þÝ–õ ^ö €4¨Î1_g91RkÅvVÆôð*L·M¢‘-ë¼ÈQSPjÙ»ÉsÔ´³!!Q÷‹ãÎ:h,Oá²|βiïmßY­ð¨§»J H}£…BWw•Àɶ¬gð"ïÝ'Ò:DòÐ&´X€åäê°ëµ«z÷¾˜Ö–õ ÞÈZŒàqæ[ö± &¹Ìž¥F™ìã€÷,*{ÁãlYÏàeÞÛ¹^±7X_á¼³é][Áó™§=¤áLEÌ–õ ^j³YÀ‡8ÜÉV {L)vß JqYhÉL¸Ð]زžÁKm6h;¢qÕÍ4pÍlñAû¦m8 *í؉5‹vDޱ!ÂVœì:ïLSá§4¬ì9¡ ls@rÄšE;’k†X±¿R ÉÙD<ÇcÄNÏ¡õuåwDŽÅ–õ Aê½+"ÛâkÕWÎnÌ0²¾˜.·góamYÏDÞ˜3º œÝ \GÏÎ ˆ-§ô$3 ŠM×Ê=*ÚQyïZÅf·,JwD†+a÷­ª)Š]ÅŠ,¿gÑŽ‚ÈQ[í( ó°FP­ÙF(–z jç±ó"¾—õ A΋³nº>sXwhnê Œ—ÐŽ#=+7ïŒèÁnËz† rÔì°UÖê{¢U<‘ 6_ñ‚ÚûèýÎRÑŽ‚œ 7Éya*Z΢¥ˆ ÿ†A)Gß÷:Ö2•õ rÍ>°ê5R ämD=" ˜ë9 €¯aW3iËz† òÞ ‹êÌ©“ìêÝ5½µ GÏ­uêà?ûšÃr{±æDìHè½5>¨e- ÀCÕ¤žS#³ÿleh<1NFk–íH΋ôè*·®K€°¹ùä}…?bË[*Åše;9jœm ŠYqŒ^Y×y0¢ Hѧž…«ºWÀ$"•õ Aæ¨y£TW±ŽG` ]wÏF¦FØfYÏDŽpa§çÌâ¶Ñ¯€®(ÉiX%¨êªÍ"GmËz¹fਸ¤®6`–-ž¿âÜw˜{„‚Waa¤X³lG"ïÍù/ÏlS¨jÅèuÓ ŽÀb Ý´ÍØ¨Z¾{ÙŽd/îØ+–USB èÄ+4íðs30¢<«5˶¬gµœQe]W+ŽgãôÙ®åBßwÁ“mÀ‚ÌÃe‹xTÖ3‘£®S±ï˜6õ5_Va¿Àé@ä ܧb[Dùœe;9êJW¼4`KMÇYŒ‘ƒ1sgyÏãˆq+x.-jplYÏDŽ†Ø´xEÇñ"ÚãåC;˜+ïñ·¶N™=“Äš±£¡5Îå `§X)†¥é™sJ-›_dû^Ö39ƒ²¢t_ 7@@1u¯ãÙ¨‹½áhR%gÎÚ²ž!H½7@2¬¯n¨AhÀ¿ÚÜ‘iͱ³¡÷¬˜T’o–õ Aä½™™ïºÌN4lplY…¦U¥ùÚz`¡ck–íHä¨6áˆpz ËuÍ ˆÿP<AŽçWäXÊz† rÔÔ×2ÁozÖXë–7Ò†÷Ülkë? Ë¢¿·-ë‚ÈQ{—Chrzª¾bgË~"½Î@'ˆÙÕµÖ2—õ rÍ0Úйs:‹ëy}ÐùkLx­~AY¬Y¶#‘÷ÖuË-êxQ þ¦Î¶º&÷â´"ßÀÕEqgËz† òÞ /rZÏÁ²Ù4öµcƒü…ÑÅ?³u¾ñ¨¬g?êIšdD3¸Nì+†[gŸÞÌv¤ €åFÄ£²ž!È¾ÙØ @Ö¶§âY9pÇ)”1|Jð×È¡Q̰e=C9j‡3m8\ÀE¦~·Ì`Ö‚ˆU”› {z­Y¶#‘£¶qÐ>€a¨nº@Ðż¸q¹ ^qìü@Û ÿYÖ3‘£Ö”­õY ü$5V½‡³ï(·±t1áAµ¨Ûµe=ƒ\“%þ.R·Ò±1‡gíL?†£I8b¨][Ö3‘÷ ä€î§¦bEšT›Yv³«á+ñ#Åù,ë‚Ì{s aMU%¸é\mX=?JM~Ÿ´Qð.^œÏ²ž!Ⱦ٭¦ÊÙÀ¯äŠuqmÒ 5›uTTT‚àÃa‹óYÖ3‘£fôMÀqðrˆ->.§Š†*p¯*²%9—À´e=CøQßlV¨RMéA{›[æXÿÒÅœF"ùk–íHË`i/1å8(fÊô_ÃñË:Ùb/ügYÏ ×ô†Y³>ŸÓzA1[Õ³´Ø{@kØÜœÃóDŒ+ë‚Ôf+œÅJ±¤#À+ÎF`á6 ®4`Ë,Nêäù,Û‘È{GŽc™.˱Õf7ÃV­!àØ²üHÄ£²ž!ȼwîÙ±o fÜ!!–°Š—Õ’€»u{jÄs–õ Aä¨)ð†Ñ´‰å–™ŽV®ØÝ`¬§§ŠÞtÂŽÊz† rÔ5@6°TyƒÀçˆ6wªe;Ýñ"I‰}/ë‚ì›ÀÁÖ;-½‘ 0^þOˤÌ\ƒiMòAô¶e=ƒ\3U¦Å¾0V@Ì … Ü§gÒš7w)«F>gÙŽDÞ»ËlÝSqö )ýã[^‚°t™}KuG ügYÏDÞ»ÓœŽÙèªâ½I]+„aÛª2üMØðWjlYÏdßløÝ.‘X3ÓKmY‹ˆ b÷ŒcÙm•Ã'Äše;9j÷Û²{'WÙ–ÙãŠù!6ôjt]®"Q®Xs"v$æI±ûR€·@@ ¿ÊQåx¶@¡jÃúÝ^YÔªÛ²ž!Èž$ÎåTGÎ`?׿† ®UÓgb€²Õ‹ÐHزž!Èþ!ƒþ¬§åY*`]ªØGÛ+EzGš[D>‹Ëz¹fÛ ~³9Qb43h¨^ºkkÒùNèÒmYÏDÞ›Cýp^L¬sj;]wÆkNæTפúÎ{<®¬g"ï=¸éعoa¡1©XÛ* È>ÖdŽdÈ¢O©-ë‚ì›VãRcý‡§çt¶T±ï³5©Å‹¦–¹ß²ž!˜õÉg,áxQìÄ!‚¬Aw”Á+€:ª×„ÿ,ë‚ÈQÛ>á(Áêá;çÛ¬B%ІŽE¨Î[‰Êz† rÔ­R “Yo ²Ñ[˜|Äf7¬Î4.Pn(¿gÙŽÄšš2ô)"‰=&SH†ÙR$9OÐSc(Öœˆ Ù;Ì`a×csu牀Œ›T ìläÌ 1—Í•õ AöânŒ¶ÃÁbÁ2šÈªeeÙH脵s r"·æŠzøY¡Q ™سáÔsÞÅxl ‹`+¦,ûLŠ kùœ%;âÈ¡3ÏRm0eO,B„–ÝX1À9’ £¸—qE=Ûu‰3+à,Ø6Ø%@¡3@„ažù;‹c`­¨ÓwE=cŒ°MöÅfí+|\P€/׌¾©ûPeeÄ]+ê~´&Ð å³[ܵƒ&Vì³X™ÀØ‘#Yå»—ìk m62 “";Ìàœš-¹€']t*Û¶÷!ùî%;š¢ïAl¯xSNñ™î6ìEÂYËÀ Lî{ÉŽ°ææÃ2s¡ÀÔ=¦Sƒæ¼PeÅ¢°DŸ=WÔ3°ºhè9'ñ ô RÀe›+„8vb5ˬ‡ü¼+êXV2´G5\0˜ N¡òÀ Øxl:@)Ã4µv‘•^b͉ؑ¨Yöö=èõÔÃb€ŸxÃaÁ£€ö5¶]>çDìHèÁxM\Z‘ ;´œjY þ¦sݲÞÐ[#îe\QÏ`*‘÷Fb#À/e:í:Çáv^ ’;œF H8œS¬Y¶#‘÷Ö¾rÉUMZWÄšE=Ö”³\Ùö¹GL‚ˬËÚrVü2H=§4²µŸÀÞE=ÖüNn€¬ÈN÷.{ü]LlŒ_cõ†µ›”û M”+ê~´fßõì…äÙÎðÞ o 䤨ç|0›Q¥}k–íHä½S®yÿĺJ*ìD¹=ʳbˆµÙjÞ(7bͲ‰¼71uÆyGâÜ(l=ïså8û)µŽÝ)š,×,Û‘ìI‚ æöËÁæ5‚&ÛÏx¶Tà`t@q€G-âQQÏÀ&Cñ«æûÕpë„¢Æ BSêl8dð¤FIüYÔ3˜J䨓ƒwv0®„-ˆšÆit‰eò¤ ¿Ý{¹ïe;9êbîü0HG‹£dÎkL M`9w.öÙJmŒ+ê~´&|ÍÈãÁŠ£æp]ãõ+ü-ØBå͠ɢôóE=ÖwÐìJ›˜pˆ…‹ì<Ø!‡ë"À#ˆºrWÔ30u:äë8Ü‘…¿ ˆ Ö±¦¾N@£ˆTôÒ¹–Ø»¨gÀš¢Nªe«5ì8,'ᘚ€˜Á½ø¶‡+¨³“k–í¨‘uŒŠíHÙïÔöL1åÏé¬9Sÿ_äÁ\QÏ€5Eÿݹ®§T¯oa_p­-5fU䬞~ëÚG"Ö,Û‘ì› úÃΩ;•±ÔyðMs®ÍÁB¶pÕ|÷²‰µñ8ŠäZÏõ=Ž 8 ó"7:ƒu {/ê~´&"ãpmî.yA ÓÄÀ†?s[ulI-Öœˆ ÍI´œAY³Û¥î-{cÇ࣌Þw™Yœ”üže;yï4hpq ¨Žè#\&Ž<€BÓƒ0ãØí"Š{CWÔ3`M½A.=6ºë,رªÙ~¨»ñ™SbomÇÎZ¬Y¶#‘£fPëìL{âFJük­«Ôe¥Ëþ,êXX4´G=E:5/åú`¨ô8Xàîœòhe$à ‹‹z¬)z÷¾f4;܆„p‰Sþc:ü£É”|βYé›y×Àòäíl¬€í;]#â˪ȹTCk–íHæ½ëZfl6Ž…¶â›{ @òž#.”—ÏY¶#‘÷怚láØ%¬‡ëàåÁˆÁ2<5G6±¨Yž¥²‰µ¶–Ò vBK:†Íô–9¬.2°Êþ´®¨g`ÞXä=ÛY4±E´¤ø7ÃGsüY¶eM@¾IIîûDìHÜIñËKÝÆ8°ÛVÔ+F6žiAã`Â6‹zSKm6‡Tma÷§}ádœ'–€y± C\'¾gQÏÀD¸“R8ÛŽãÏ…!TÂöì ìcâÃ?EQ¯íŠz†¯©áËðçì``>n…/«(w `Ú6à,넾Îõ XSöêdûÔžöˆ8™±¸«"Ð0L¶¶¯+¬JÌesE=¯ƒDN Ó~ãXú Œ üÄfµb]‚Ö:æŽ}_ÅY*ê°¦èÔv±ë˜¢òØjèÁL²ïáÙË_U!Öð©ò{í¨9j¯Ù;šÍC=À"ÇŒ¶æÂVˆíœ0Æs cqQÏ€5E c Ny6£Žƒd€Šlã&‚ÐA=S¤ªCp„¢žkŠXÌúEDœ~©†ÿu¼Þ‚Y5mª9:ß·?ŸE=ÃÿY3Ô=ýˆ',ר×ëÐæÔïFôáqE=Öš+Ó+ÖÙ±ámníA(0>p¨\šg©¨gÀš¢.ò‡þŒ ×]•LÈ=0® ,£8ÄŒ¤Ñ¤JbͲ‰5™/ˆ%ª…ÒyxDàÌ6*©m)ÉðòNª¨gÀš'§ÐöήFlGgä;ƒ¿.³G(Q?Ê'õ XSôÉÇ6Â.ÄÎè)2K5èWì9é¤Ù²®åše;9jvÙizÐ PÎôψš–E§À&-psŸãl³¨gøÑš¼f®ØlGékvØcÙíµÁ%vfç*갦М}´øLc?a^űmpÃÆ{ aŠÅsB»åŠz¬)¸6"}æDÔ4hÂkê†×ÒiÐ?…£p˜,šWÔ3`M¡K„ @µ-/40ØV‡³ÏÒM3èòø$|rQÏ€5eßl ÖÁ”錕Xé7Êþø±FÔµ.±TJ¬Y¶#™£kHdlæÏÄ¢(ªñkvCõ¼9¢R¢7š+ê°¦ÀÉ*vÖy< ñ±‰>°ûޝût¾ÁI\¸û^Ô3À‰þ!T|Rum’¯Z§ƒ3›¨+„’–Ãø€Jåše;’ÚlËfñç‰né•=§Ô°[¥agåªÇy¡¨gÀš"7• ìÝ—æðDޱÍìV€ƒ×ßÂ`=›Î‰5Ëv$rÔª­Râ˜8PÍtcf$Ц*Qëß'é—Šz¬)ò`'S‹GÁ³±¢# Ù¶äØ6 *ÏgÙŽDŽ:°aSŸÎŒìYVÞRÁîlM Z»5b®¨gÀšBGݲù'§1Ú|&ÁbQ ÈS…cº¦ú:_Ô3`M1³†*ˆÔ;6âÀa˜añž¶c­dæ´¦FI͉/ëj‘£n=%P-ŸÆéšsóO¶×=¾ýÕ¹I+ú²žA®©ƒ‰U_˜a«šË$µlô‚õ[„$˜\s"v$úäs¢ì ~Ú¸O¡E­9j™ ñ^¤4C¬9;ZÍøÍ™¦…soáï8º²@ƒ’Søj:kôîe;9jöÏðuĦ³\èuä‰|ÃDãœÏlD¿__Ö3Ô"G,ˆ‹[zÓ! {²"vŽ2r® Í¢Qôcñe=C-sÔ`„WW5œ¢zÈÒ6Á6¦É™å:ž_¹k–íHä¨MS›šn³N†Â囹;Ç2˜Þ‚rmkåše;kæÁÀbÍÂ÷ =BQäÍ^t¦óZw&'À%ø“¡5Ëz†Zä½#ÛŽ€æÇÞ½u.¥Vf°4°‹C½³Þ|YÏP˼7¸IP:çVã0YÜy8þÚ²}ŽX­…†Ç—õ µÈQçXö^ ÀÆq0SüPTÀöäF Ç•8Ÿe=C-rÔÈ€EpŸŠÅÀu¤ÐÿƒbÑ©¦ÔR¬Y¶#™£®a”5k#Èr´ °5þÇÕÄŠugá–\•«J¬9;Ú­*xŽ&¯™Pq}à`èpdA5“f™PÇVµÂÞËz¹&Å!l·Ôhð†°Ú1W‰¿a#2ËZ®ÖŠ_Ö3Ô"ïÍ9t†¥šØ N?gK G¸ÃYm”ÆãÂȘ¾¬g¨eŽºm{ÞiòŒÍQ3í`PK—86ºåÝ,€˜èùàËz†Zö1–Õ¤Tµ žxÈ5ä +í»€O.Î|YÏPKmv]õ-xb¯9 ï¦èÛ¶òÀâaO~ø˜**±fÙŽDŽšÃ ÛH§—àhÊ_=Ìõ¼—Eœ¶“¶YÖ3Ô"GÝW™8/wm¦þJ;SÀžÜ7ˆ±ã×äše;k"Ð*BÐŽ¶>$¬Î¦šºÓ=,Nµøµ,ß½lGìÝ—=‡v³t—³€‘SŸ*x?cª°å¬ó³Þ|YÏPËž$œw…[Ä‹Tnd˜˜-oQ4ˆMäý»/ëj‘£ÒΘ¨UÅÊƒÑ •g×Þ*4p[ÎY¡!÷e=CÝÈšeÎ…T*±¢Ú'ÃxHNÁ² 3M9ÜY¬Y¶#©Í®ñ› ¼›ªàDÝ OŠÂ‰ÄNøÇÙ³2ÖrÊv$rÔ†Ý]9%m;Þ÷¼ç‘¹Á%ñ'”ôóe=C-rÔ5gÙŽ¤Ž©‹àmŠÆ5xgN ¢þµ­]Ò V|ϲžA®™Ù@™ãe9ÿ&×¼Äs6ôþà <¬¨ õe=ƒªe]$µŠmÛÂ+q`">ÇQª®fgŸ¤˜¢ç­¼X³lG"Gm'µ»L¸ÇZU›Ù…+æ†íbj¨Îï£è_çËz%sÔg¹‰€š6¨ˆÐÕAuœÎþºbͲ‰5sþp‘}1Æ:žs T®M< ):N%pNĸ²žA‰umfUòðhÄç# qœÎÙ ±-~‹ð!e=ƒ9êDb`x©«s›A² EW]Ã<Ûä©Ö糬gkúÈÜ~ß+³öœò.VˆGf‚sÐã±å‰Xs"v$î áìp̫Ȯ9¹ñƒ¦Á±T´áè&Ë …Nâ䲞A‰¼wÍÞj]Æûa‘®cÍT¥"‡Ì´•fÏ4V8öBãËz%çEV‘ÃjŽª®C[Ll¼×áTõ@\{‹ž$¾¬gP"GÍy{@‰€ZÊ€%â'pVkͰ¬íØd±"»k–íHI^̶؃>ª†S‹Ôò@†Âf¯ÆÕØ>Ž“û^¶#‘£FjwÛªo}Ûõøø|Ð.~•˜¬¬ãóe=ƒ\SsJߤŠ×f!ö™ÃÔµí8b¥3>ÂA“Í {/ë”Ôf#d$ÎÃH5˜• Ïèú bÜ*•R¬enå»—íHä½uËÜ4ð¼æìÛÓ à±V.Ï»YN©­xβžA‰¼÷ y︚ŽW^=8 [;wÖX‚îV¿²»†X³lGr¶# ;8|¥}•;ßÜS»ÖâÐâäÆD8kxy&Ö,Û‘ÈQw:*ÐUÓõÝ lÝõÇ8øRÏ\‹ZM_Ö3(©£çWÀJ‰¥=ìÝŸXà•húœ_ Õg6kNÄŽ†ÖtØŽ¬-¬àÝ‘i"`à99]4¦í ¼•ëäs–íHä½[6ÞmªÔ4•F¬Äqþ ¼5‡)Ul¹*ü|YÏ ¤6ÈWMÄ©é(-BXd 'öà©• ªZúº²žA‰¼7Ùt1¬ßÁ–¤Ñ7<”­cÏF>ÌöG¹ ²žAIm6~v„?Éz¶Hm7§`Çh™$2cÁe-tA¾¬gPr¶#zÂs´Ã8L/jžh¨9ãœ6‰þ6¾¬gP"GcÝ7=[ÃP˜=>+Ä9Ñ…&9ˆH¬Y¶#±f"f·pæxo¤T\Ä&›C§|%Ÿ³lG"ïÝsJèm â,¼ˆëç÷•Ê'ê%üÌ^ž¥²žAɼwe+;xPmŽia»ìàL‡t(!ÜË5Ëv$òÞŽ#ñ_ÅÙ×ÑÞ…ºSìøÈžv0ÔÆË}/ë”ÈQ#>:ÏZ€BPÈñÚdž@Û8ô+õV®Y¶#‘£6T{Ž*Âûvl˜3b| œ†Ž:ìÔrþe=ƒ’=®y¨9Àr*$‹grCßÏv}Ý6 7ò9Ëv$ÖÈö$2Ô_€·2Qáà>8TŠ:bü!¶î“x¾¬gP²'IÅ«œšT›$»ópGõ ­Õlñà¹Ä¾—õ Jä½[¶Rí˜M šha‚*³†Õ#š}É…•õ Jä½[œøãÞùLÐ î .¬¿«‚ð«ð-‚s•õ Jä¨ ¼#ÙÖ›3ÛµiàŒî3D„‹FÌeóe=ƒ9j›ÙSƒ—=ÄŃF"m­ñ<ìýMóB¸{TÖ3(‘£®ÙÁˆ¥pg/íùP€³Ê6ì¯ÛpTQSËüRYÏ ×ÄɶÌðcƒ€ÞjËFtŠ3wÙÐú6’úy_Ö3(‘÷†¹g  ÿÔóÆ("|ú†Ô®ã¸‘¤á¬­÷r&bG¢?˜2-\×TÄæÁàÈÈ‹nS!ÒëÁ¼ñAoD±fÙŽDÞ»kã1¥ýD1›Ê²fðm$ð÷5o+e¬¬gP²'IVx”0ИU Ð Šhø6µ2{Êz%óÞH¼Ôý³³SX ¦ë}lš°cºoÅ~(ë”ÈQãÃ%ö¢èT ÒŠ Z°«Û¦öNàwTX ½M(ëäšÌ¦„ÜW€ß´Ø|6gàhŒÖXÏ_ÒAÔˆ…²žA‰¼76æg³¾b×m÷ÄQŠ‘™ùžÉ!vR:ÀPÖ3(‘÷n˜õåýCrÓWÜiÖ~Ãk2=ä4ˆœj•Ü£²Imö@Óuƒ×cÇy FgÀ½`𠉀ûA“X³lG2ïÇl*øúh ;rÛ ¿ì‰8X¼15k[dߘPÖ3(Ù?g¯eEŒ›Ó+ZìIbû2V0#Þ‘Ý*΀Zs"v$°·ôÌðå½e×ýŒOÀ”S§“$©¯€tÄL¥PÖ3È5Y×2Ù×±))y§C†³†¬,ϽèÊz-{’ðZ/s¼j›k6¯âån­ûî½êUOWgNe=ƒ–=I2/1)â3êã|™µÔ†s|@;B”8Ÿe=ƒ–yoÐA„J¶uvDõxÀdà¦4[IgÇ9¼¢Y(ë´È{3Äî}8EàYQ7Pu¥¼13 HgŸ(Ö,Ú‘9jçÈÙT <A(krXD`o—’ÂÿÏu-}HYÏ EŽºêyû4¸q†³0=|), j‘jbàÈ ‹s!Î|YÏ ×Tpfx×β>›·A§Áp˜šõÕŠíšå¾íHËž$̽q8 œJŽGn*©ƒ„ÅGåDÝPÚìPÖ3h‘÷Æ"Y!Ô s8úÀÊ Ï ŠZM§ë¶ÎbÍ¢i‘÷Ö{!%ÜPmŒë Y#Ÿñ¢è‘Êz-òÞðïÂmÀe+Ín/w ‹õ{ VßVâ9Ëz-òÞ@Æœ,œYæ_¶w`õ‰éVnZ66b‘m-ö¨¬gÐ"G­lë`7øãm¯àêÁ\, #{Ã^±E,”õ Z䨪Ùè¢ë-»c5@ò¬uȰXÐb„a6äùÑše;kšÛVulË¢]&ÜŸ…g¨¯Y¨%bGYÏ EÞ[‘Áˆ,‹ »ŽÔrìö€Çµ¯¨“ß³lG2ïí ½G$¤¤ X‘uÌ;7à4 Ü8rNS(ë´È{s@{ˆ8È-ûû ÎÜDÍî&!ðÓ¶‡Ñ³çÒКe;’ýCZÞuPãªá=[À­º'7f¿ÁNL[Üõ„²žA‹u¯N–ao,ÏBÆTÛT×#ЩÜyÑÛ'”õ º–¼¸ãô_æo …ù8PlÔ²½³k©WdÏ=áCÊz¹¦g&¨Mœ\c•ùj9GË1«J• B“cu¼8Ÿe=ƒyo6èúî¹2g¬€_Q²ÊÖ­lK‘ùµN"v”õ Zä½Å&øL¶§a#aÏ!&„à D“@¶Åše;yoŽìÕ8¢Þ/Y và(9` Oïà<¼“Ø÷²žA˼7»¤·×Ì×£Ø.––RR3.µ¬`Õâ%”õ Zæ½{À ?ïfx×§a‘~_ÂÉ+ì{Êz-rÔð»Tõæf()»³çyÊlÈí=PCç³lGbM 0M[Û¶Sðñ³†Ø¦MìËÊ­vÉ[¹ïe;’ó"mJœ.p2d[|_ØJÅ!%†hj ¨¡5Ëz-òÞM0psðÈ9ÀlG°›ÊÂÓ6W¤3wú¡¬gÐ"ïí`-"ÅšaÙœ%±JÊÚ΃Ì:µ,›õ\¡¬gÐ"ïÝÃKºžm‘ZD!$ü}¤^ŽÎ²•BkQ'Êz-rÔ°C*G+ w¬ ¼ÕæÖ[BÕ¶½Å&¥FròžA‹uŸñÝZ¶¥`*&»WdT_Ôƒ††•ýÖBYÏ ×4œtØs¦Ã÷ÃcZ€íØÕxVÏëDŽœœ«¬gÐ"ï͹f6À·ùl½fNžýR­>·æ?Õ‘bͲ‰¼wšÝµºÖã;rNÓÈð$ p¾3!6ÖÉ}/Û‘–÷\D±é"H‘vìxѰó[³°(–ÓK¼êäs–íHä½û‘â™"™mØÞ"FÓ%Ç/?… BÄͲžA‹µvørÀý.ª&–’›LL¦®a Þ yFôKe=ƒ–³“ËŒl³îkv³ @ž>çšÓéSßá߇‰{„PÖ3h‘£6;Ó˜ŠÍÚ"§#ÁÙhWºs¿ Œ*Ö,Û‘X³Ekpì}ÅI`xPÊ™ZÃi3•Ål4*°MYÏ eßl†aNÚuƒ«<,Çz}ã5› Ú.á9•|ΉؑàÅJ†Éò³Oxý>PðÝ7€eºwŒxlÔ#Ö,Û‘È{«¦oj*ªl´ 8>Ë"ÛÆ×¹jÁo³äïe=ƒ9jM¤­Éì0ˆgÍœ½ÛÁìðð#å¾—íHä¨5¯7°Å™Yú˜Áì=Ü“o+Š9¨¬…… .SÖ3èFÞ#<2•©6ˆÂ1u¬Y¶Yì¨Ù³Sô=e=ƒ\3¶]ŠØ¥žšùØ5L}%€½š–‰ ª¿Å÷,ë´È{«Ž]ñ¼fÒŸƒ„,e… @/€²ˆ¯ÉJØ{YÏ eO’ˆMf{)JXR .„è“HX'”öÀêNäçCYÏ Eހ÷}º*ÃÎk–ÐW­éaŸpÍÎ’…ùfùœe;9j RUQ@|°Ž¼× Ыw)â\±®œ5Êz-rÔÀ3œ0]›àmå(±PÆGîù¯å6Ë=šˆ }H«†ÁwQs¦À€Më"G'"žfÇТ|Ήؑȭ1¾åرÿ|j-§@õªÏ¦ã•~¹Å?‡ <_Ö3h‘÷n8’K'Ç.µ}€Ô0ÿ|SSààRE j–ù²žAËy‘.7MFè‰àã¡LÊêZöVÐ ‘^ñs‹ç,ë´ÔfW`ï+õ\®ð †ï™f¢û÷@fÂוõ Zä¨qÒ;ø‹Ù#ðV𠬿ê×°¹™xt Œ"ö½¬gÐFÞIeÀ„PûÐdYœK*©ym£â%28³|÷²‰5»,¹–mlVUlEÝ*Ä|&D@µÅ«ç(ügYÏ ×¬:–q%NB†Ûdµ2/Àaµg‹¤œËáø‹\eYÏ EÞ»f¡vÏÝG€Ä¹ï{l¨'žù`džœä.Ö,Û‘È{à GÝ{m²-'ÖàX]Õ!nÇ™ÛìË%Ö,Û‘È{÷T· ì-·œ:«RÄúø1Ê´mCV§kù='bG¢'‰f.@>…ž˜“M vløl»nPdÛÖ^𸲞¡9j£ŸxÚšåø)§.”ÕÏ­XõÄCk–õ œí¨#gùQ£ŠíÊ‹º"S®ìñxð.áEäšE;’k²7´îÁß@_X¦ZGëvŠYlwy !Ö,ÚQ#òÞ.‚ûkP-GR0h‚¿²s6 boëibÍ¢5r^$;»€uPRÆkSãéaK•Il€ksŸÖI‹5‹vÔHmvClœl‚CÍTÊÃß³—]Å[³Šœ¹Í^ò÷²ž¡9jŽ„…?o™b«{Ž*RUßs¬ X¦nãN›Nrí²ž¡‘9j¶¤§çdPë+7aGjjô­Ì–õ ì¢À:*N²ulüи^¹b”1Ò ˜¤’sîBYÏЈuÛªÁh]Ër»š£(9H§Ç·ä "1Gb‹5'bG¢ïAo€ 6¥Á1wì¡Éî$€v5V¤ðp+F|ϲž¡‘ó" ;âW-‹0À9€H@°Ãš–³ èCZŽPÖ34"ï¶Ì¶N·á×¾åo€­ò:ŒSg, (dž¡¬ghDÞ»æbžÝwvЂɳu<ì 0¨ììP¬Y¶#Ù7ÛÙÖppøÙ¶@œˆ‚Àg9·š-?l­Ì–õ ÈQwµgãõL Ÿ÷ZÃ8&Ú: “Ì1bͲ‰u5«/X7€sJ BÐJ°ôçdêð¹¦-ëäšZ±ö$²<@±·³í•®89G–âǨu›Z'÷½lGr^䀽tÎê‹ï:|ŽœüƒáÔ¶ò{–íHä½-AmÍ6ë,Dé)Õä„/fÇ9€/Öá±e”X³lG"ïmÁ\3âo[O¹?&¶œ¸\ƒá5ëé…±ÁayQ!åÈçšmå€t"¥̯±­9Uqµªé§å¢±$9A®o©Ó4:p>DvÙ‘%÷ØúÌÚê¦oUß8¹hÙ”Dšš×XÙƒFØÑ…G!Òãá÷`'°÷'ôGOZ¶%±(0l„ÅkÞõð¢ƒ#@ž»ªx×oÚ¤;¡À¢ÿ¯ö®uU¯ã†úwŸÂ/`27Í%/æ †Ö.öI!oßµ&´Ab’Î&ÆNæìËHZÒHkÙÆ¤ŠßH‚=Õ϶·Cv_*‡ßY¾]«¶˜r^Ô¶&UýnÔb'Ü©$@fdsìÔm³¹UakdÅíëEmsRåïÉvÀ“eä7Ï8̆ÀrÙØA‘|+º,jÛ“æ&ꆛ,µ…ÈñjET žý‘,ÿRã3>µ J«ï Ò1à¸ÑˆOÊÖ%q…„¯?blL§^Ô¶(U­îéuÏ{¾Ó„ ÎðäŽÌDˆ¢5µ¨ÝÚT¹: G–AÆT3ûHC‡àWøÅ'V õ¢¶E©E"¯Ïür;qÌ’|£ƒžr“Jeh,ŠE_X”"ApwØWøúH—*µ}SÔ,j—P¡ÒRƒjjÁ¢/,J±…Íîá>Ц‹<Bb7™|åÒ‘î(euª€Em‹Ò%ëÈ/JääbrŽuVA„GdÁ.@ÌÃÿâãNm‹R5ë=ù„g»–GG6Œ]¼XêšAå¦Ú¡Ø I­‹ÛÊÑmfȈÿÈjìG‘E´‹÷J™äÇÚ¥YJF ø6SlœáXt£®7ÙB¨Ýå±Om‹R‹:à›37î2û³ITÊf@$ò©Â8¹1»Ô¢¶E©Zxé,®"K"©*rìFæŒÉwÜ>’‰Wœ¾S»É!ébxà©û@*JQ“ÃÁÓ€m…ZñIIu·«B/j[”ª†ã¶à9¡ô’Gà,6Ö¤> ‚~#i]úëÛmIËH¶²±Ù;'f[)LOšÿ9àµ'ytÕ€Z‹Ú¥j×žŠØI:Ü^Ãkú›gÁ) ûo¿zÔ¹<}aQ*a¦zÜXðQaÇÞ´ Ãˆ*kTÿøP/,J±ò‡Æä{!·õ±Fé+VNÌ`DRJñƬÙı¨mQª$ž ªë+Ò=¹tHžN…¾IÖ;ì+@¬ŸÝë4_É¢ÂÓYÄhvë¯Ó ”©ùZ8°Cz©Ç–²-Jų£‡WZ@mHL¸[ËFÚ OY‚~öðœxÓ‹Ú¥*Ølyž#PvVäú&;——Äañé©)Ê^Þ¨ßnwHª„¹©â`…JØ“äÜÝ<Ïž½.ˆÛ·û’ªaS± y‡ÕSr)ž“(è“*5PWŸ»x§ß©ÝðT»Ô~„Ì€>“ߎ´ÃapX˜º‚ð¥<ÍÔîxЋ"MÄî¯@]%ÃØsGÊÏ‚Y“Û >ï»h€f·<$UOTjëäØÞîù u˜e‘LBÑ/ΊÇÇÚ¥ùº3öÆÂ’Õs³Á¡t¤&y Åßu%4ì±›’&×ö>5Þ¥C`B¼ôÓ5ÄB2Ì“ÅúèDÂîzHš¹ЖÕv"‰ ‡—Ð~Ä“BwäWx”õا¶Eiêrj¤ÅQÄ•WÏ}N]P•ñN‘›,wµÒõ¢¶E‰æ¾çêâ¸l=¤Ó¢b!y´È›(ïä½¨Ýø ¥Øy!*}çÙú d±™dXBfîX%oîáPì·¤*äÔ¢>“lï84Ë/ôl_HÒ»‡QÅèµ?µ[’*‘KtÀ´>ÏS÷1³ó²¯úÀ^Ex*ájahÛ·{’ªgzWŠ£ ²dV¨ßº25xR7=ÐÄ [ƒ^»ù!©‚ö§Ôn§²!_y NÒ"ëí¦ŽÏDÂî~Hše{<4Bg¾¨VY¯:|çv2Ü þ‘©÷©ÝþTIñb7F®Ø°öaÑX§êØ]=#wë¯ÿ¢T|w*ERo°ß ÀRž“¤W„¿}T¤íˆ$Úö‘Ð/’EbWz©Ñ ¶r|šŽ ,À^"£ìÑ•rÎ'@ðŒ&]ðÙ&Û>ØhAÞ*¬»ìS/j·@ˆ*k'R¦\7)µ«OˆWoq¸Ì[]+zQÓ¢D׵ׄ¥îÃàŒxɕЕ¹“È£¸°9OºšwÅ¢¦E‰*lK†ÇN?ôJp&R Ñ{÷©†ö§v„¨Ê6Û›øŒ@"ãjB"U ±Žyì9 íueÂnƒÐ‹nÖØ£æ7œIl‘ÃîAdGüÚÇ7-J4‡w‰…¬0‚ˆ(FŒ }j «ÊžäF…«Ðôæ·!DÌ©a—yï”P p"mýR°t‡zf›ÚöíNQóµWÅwˆ€è›;“ŸÝÓeïSW”žÚóÛ­¢Kæ‹®0º¬”or¨^™99rL!3sY;}aQš÷¯TÊ›ÃÞ™óQ»µý €M¥æb©6 &ìfÑ„&JÑßb$R‡7¬2žÜàx¢³É×q´EÙÝzÑ“+R§ ‹§€JjW—ºâSðS^g ž¯š´—²Û!D•Í+2R¼Bí½†Ÿ€9•Ï ¯~à]°{—|v?„xÝO†Dù¤²÷¬pÈ?©_6w·x2ŽO„MꉄÝ!ªp.¤" ŸÕ·7‰à¤ö¿"aïÄׂôG/j[”ªrç [ €},Ì•Ó3×e "Iõ*3ÉKÙ-¢ÊÜ øñÞhÁþ7O‹G˜P™ú‹'‘mzQÛ¢TÛaÛ¢”†¨`z8ZÉI>mæ‚4e¯XÚ£,g7Eˆ*t'ŠŸœÖ<ç‚ < H‡SÄœ5¦.èÎE‚aQÛ¢T¡ñ1Ó“+74—vöˆ)ÌÏ©óBe=~»­ß©Ý¡…m3©LÃò6%àIUÛ€õùxDüÈ÷í¾Ѻ“D±­¹M¡+¥ø’‚àX{/ïL$u~»1BT¡Û„7:€ÎŽi˜üg¢%ÊÙl=E¿S»3B‚î4iœÝ¢&n’5ô³"Ð9h¨sV’ëòˆûvk„¨B7ršI°Ã“q¬CÎù€WJ8p Yµ:EïS»7BT¡q©± IÎDå8O­‰š_°R_<÷¨¢÷©Ý!ªÐ}¹¤ÎTÈÃê¾ZL¬¶\‰t„líùíîÑJ‘}“uþãy.ÙNŽÛL((VD’ÅìÂãCÙ¥ Ýd¼Ã>­£-–$7| löÎÖÃúI\)iéÑw,j[”Z”úŽ]pTŒëDÓÔ… ls츂ô”¦÷©Ý !ªÐí&€ÎU˜¦<°àw¦| 8 NÕ4çb> µ-J+P&ܽ¢B}ÂñÈøì Ñ\Ü)Ákô²½eJbg—YHÎgrÙ-×o[TÔ  €ö ¡/”ÀɏаŸ±à´û¦®X§ˆäÔÑÔî’¨;@©)^‘=à}:Á­žÁþ›*É䩇$NmªEm‹ÒßÈyz¼®LϲvæÜSHÑ‘­"oïKœ.ÌØ}¢ ݹàIæÇF+1súß 6)/Zn%ÃO ;ëEm‹R…nÊM’Å»ÆÕ ÷ò>øYÀ¥?EÛ¢ Ý}!m„GF`îŽBo Ÿœà¾6ÀŸ~|»UB4%wÉnŒ H…¼¹­;‡8È\"ÒÁ¨‹Ð‹Ú¥û¾O‰õÒ¤öYfƵFŽø$ÒêEm‹R…nÀ2˜Sá9õu¨A¼y`Ü\»DÀ€lÈÜ£þPv·„^´°õnA¯åÁÀ7‘¯”ÑcÀÀ¡ájwÚKÙí¢©¾áì|Ø?l¤ƒóÏ=Nê–L{RçH*]ƒ »_B4çIlŸ»93¤’¨r˜ DÝž| »žPD†— wüíÃÿàõþå·Oçóß÷÷OŸVÿ6¿ ?ýrÿðÓÛþòÖß>ÿkÿòÏoŸ¿¿}þ²ÿËŸì,'ñ÷à³×¿ÿ~áÏDm9ÓWÄøÛ$åÃG÷CŸôÅõë÷·þíãÇëÛ×_¿¬ß^þwô÷ÿ§×>íÏð£qt6S»í*GÝ–<ŸWj„l" ó¯¾á÷ë‡^–ýŸ¯_èÏøCûwò´<*ïöÿg\7ÀýÕ7ñ~½_ï×ûõ~½_ïןzýÏÜ‹¨darcs-2.8.4/tests/data/many-files--hashed.tgz0000644001765600176560000051223012104371431020320 0ustar ganeshganesh‹Òw›Gì ÌfEuÇŠ µjÀ¤i+ ¤¡$KÏ™™3E-Óh‘ÒÆ*Ñh`ÎÌ™°Eв`SR“¦EÓJ‘ÓÚ4¶š˜4qùX(±&|EmXiƒØÆªñÖPE ­ç½K­ûγÏåÝÛKn2¿°¼Ëò&÷…ûüóŸ3ÇK~wwÙóVÙ»{÷…qï…’a×Ô@Å _­ù‘¯Ù…àŒµNÁ.@èvD“ÿ$ .ß{Y¼ô¤“v]/½èpß·éß/”‹·ßÿós¼4íðcðôï¿Ñ¤úýŸƒõ÷ÿí—îÙ{ÙžKäô#~,<ýûïŒé÷ÆßÿuˆZ„IJaÈZq‘Èú±dÂök¬n°5fÜý¯7!ஓ`Žÿýþ¼ÿI¥ I; ºø`Á9#¦ÈRŠŠÊK¡lLÛ¯±ñþküQÿ)×ïÿ,¼ôªc‡ß<[›}7=ð¬]xÊß¼íègögêÌÇÓxþËÁ$,Öj­­IVŠ‚h³ (Ɔ¶>$¶_c“ÿtˆÿ«ßvÿçà‡þ}û+ŸwûœÛ>öѾï·~Û|ñ]gÞöƒ/ýâ{¿õ¼}èï^Dw\þö]t×]§ü׳÷|þÄ'áïÿîOsö©ú™ýù;GÆaü—¥ eŠyàÓÿ[Çÿ¶>0úø6ߣ“f[Ø„H:yo iKN±ÔR £c,„!óúkl|þ£=dü¯µÓýù??|þ_õk÷¼úÀÙç¾VãÀÓ^³ûô×ì¾÷^¥`Ô{¢MÿøõŸ:õÓw¿áŸ?sîÝÿt÷óÇ=Ùý_"#üÎ1äb”S>†:Þ×±NûS@%CÂè2Išvÿ«ßÞýŸ¶ÿíüŸ]›ÿ{ìÅÏ}g÷‰löŸqHÖ‹#MRË ¶#„NQ±L†è×_cþ÷üÏL´ýoçÿìÚüß#ÿzÿQÝÿ%²ÙEP¼× |IÎÙ<% I´¥*²S믱ÿÑvÿg¡í;ÿwC£þËÿ_¸ïÝ—tÿ—Ȉý?¦ÔÚoWÑßœÐaÖEa`-&&uàO% ø‰çÿ½ÿã<´ýo¯ÿßШÿÃúÿí·¾áÂîÿÙì?$³•õQ¦([?T½ŒÆ( AkoRÊP믱ÙÚ6þ·}þ? mÿÿÏúÿ®G»úÀqŸ>眫¤Ô¯>và ?þ™G;á¸[/;þø»o½é•?¹ë³ç]óÉ®ÿ"‘ÿ‰&B­ùT.>Š ÑbH, vaÚýÖôþ³Ðòni×uhþ÷ó¯Ûû‰½ý°DF¬ÿ³.ÆhÏ!3ú"®ÄäBp³¨!“#ÉúkìÀC}ÿÿ,´ýoçÿþÌÿ}ñ´¿G÷‰ŒéÿiKÊ⸠!äÀJÄÉ œ÷:FIÔ´ó§zýŸ…¦ÿ®ÿSÛóÿOõÿ{Ï/Üý_"#öÿ’1‘|Z…}5cÎky6Z±«¢˜maÝ:÷ç)và¿êý¿ç¡í;ÿ§ùÿ!ÿ÷ù^|M÷‰ŒXÿS)8ÔŽ0¥Züs0â}uÕ$m믨Á{šlÿ¿®þWýûþßYhûßÎÿ©FþÈÿuíÔý_"#æÿš³.ÞU%³¬Žf­ó}µ.”cð†K’âòúk<}ÿ5õñÿ<´ýoçÿT#ÿ;äÿ>òWß¾¸û¿D6û.P".ÑfÀ}É:A*\ \:¢þÛýïûÿæ¡í;ÿ§ùŸ!ÿwê[Ÿ û¿DFøOuÜ_çü1Bæ´êÿ ÅÙ% ÆV¾¸ÉÞÿmùozýŸ‡¶ÿíüŸZÛÿï}¯zãÝÿ%2"ÿO*Sä$>$ ¾ÔA€IÆxXÕu©#M¶þ¿å¿²ÝÿYhûß^ÿ¿©Qÿ‡õÿ“Ÿü쇻ÿKdÌû‰ÆhNQ\r,ƒµÎ¥(Ö A>Ìa­›ýwÛÆÿ½ÿÿ<´ýo¯ÿßthý'7€W_óî€2¢þ뤭 M*¨F,z4*¡ñlR¾~ 2Ùù[þC?ÿkšþ߸¦þoÿÌÿ]þò×þD׉Œ:ÿÛ©²IZQàXªïYÁE¯X¬£içÿ}ÿÏL´ýo×Óèÿ=äÿžx\Žîþ/‘û èR’ ¨ÐèX$‘ËÕQëŒdíOºþ¯5tÿg¡é¿nçÿL#ÿ;äÿ>Åß¹ºû¿DF¬ÿ[*:rÁ”•Ï‚ÎVIgk«º”Ñ¥])Ó®ÿ£ºÿsÐö¿ÿ3üïÿûÖïíûn÷‰Œèÿ+ÄJ1g°©Š­×â))Jl=z§’¡<íü_÷õÿyhûßÎÿ™FþwÈÿ=ü ¾Óý_"#ÞÿçRo1y +ù™EVY´Áë\]QÓæ4ö÷ÿ³Ðö¿ÿ3üïÿûÃ3Oéçÿ-’ç…Tr1N$y­¶ÖD"Ye&—ƒ hÚúoúüÚþ·ó¦‘ÿò¿å=}ùo‘ŒèÿÀ“œ×‚ÏQ¤h2*ÕaÆâXkÖy²þ¿ßÿ÷õ¿YhûßÎÿ™µýÿný‹+_Üý_"›ý/¶*“K.ÆM  ¦ø P²ÁY6„Ù›Éúÿõßõùÿ,´ýo¯ÿ›µýÿþö‰ß<¡û¿DFÌÿ£Ž&jL.;—f-:&]l¬Ÿ‹A„ê2Ùù¿óÿ}ü? mÿ׬ÿ7òû‡Àc×]þ½þX cÞÿ;ï$$#Æh…¤MŠ.cÈ0¬3>Qþw{þOõõ¿Yhú¿¿]ÿ÷mÿÌÿ}ï/<¿ë¿D6ûŸrv3Ô9¿-†<:ç|ZÈä$"ÁÕ[ÀõרÿÊvÿg¡í»þïkŒÿ‡üŸúÒKL÷‰ŒÈÿHö>ÖI@I"Þ Øl2mPL¦øl‹Å4YÿÏ-ÿëý¿g¡é?µóÐÈÿù¿3ïxÝÝÿ%2¢ÿ Øzó’ÄÊ Ñ!g•%aÒPRHÓÖ£»ÿ³Ðö¿ÿƒFþwÈÿý÷×êçÿ,’ëN»³!m‹R)±_5Ð*{僫£ &;ÿkÿCÏÿÌBÛÿvþùß!ÿ—¯ÿÇýÝÿ%2"ÿ#…&åsªr²:‡:ã‡lX±eê/™6ÿ¯zÿÿyhûßÎÿA#ÿ;äÿ|ü¾ÿìþ/‘ïÿmöQi.H¬³°ÀJ9ç=PÄ:%(äÁ"¯¿ÆNüwýýß,´ýoçÿZþù¿÷ò ?èþ/‘ëÿVB2E,HÉI±…Ä.Û°Ú¥ “„àã´ý¿¨¯ÿÏCÛÿvþùÿaùÿÑ—ÜúÍîÿÙì¿Ë©p4'vÖGqÊÆ¢V‡+ñ²=éøßôõÿ™hûß^ÿ‡FþXÿÿæ{þ£û¿DFôÿY5ú7Ö ² DË™¡(ÆWSÂÓæÿ¨÷ÿš‡¶ÿíõ84ÿC®ÇœñíGú`Œÿ×Ὂsá@‘TXuÕɺht"t:NÜÿ_ÛžÿŸ…¦ÿׯ©ÿkûÿ]qm~¸ë¿DF¼ÿCT˜8 Y´^st«öEsŽlµ3°j ²þ;ñ¿Ÿÿ=mÿ›õ÷7öÿ ù¿Kÿå·¶û¿DFìÿ“hW~hŸ0:6ÕN1¨IèU+pÔ‘ýÄûÿúùóÐô›ù?ÜßÈÿù¿sÎüÆGºÿKdDÿï‚\D'Î:xvRr6Dg«bbmÄIó?úþßyhûßÌÿ5ýò·ì…‹ºÿKdÌûUMwQáâ“(ïÐPȘ,G©Qš¶ÿ©~þ÷,´ýoæÿùÿ!ÿ÷ПŸÑû,’ù?œN€àYa©Ã~J ¬§ÌÎEGмNzâýº×ÿYhûßÌÿ!5òÿCþïÜüÜÙÝÿ%2æü?c]MΣËÎ’w&$ƒD0¸•L꿲}ÿï<´ýoæÿùÿ!ÿwÏE÷}½û¿DF¬ÿi`oüª €Óu&€"1fV«#AiõÁP–R4ný5vòþO÷ñÿ,´ýoæÿùßaùÿò³Þý+Ýÿ%2¢ÿåR¸Rígo©pd²EÐI¢# d­qÚþŸ–úûÿYhûß\ÿGjä‡õÿî}A?ÿc‘Œéÿ/œSÌžEÌN²oSrÁ:! Ê àŽèýÿöþýüïyhûß^ÿ§Có¿dàæapÖñÿþýþX #ò¿VŒ/ÙkdŸ”*Xrbë” I•Œ$(.jÚþ?ÔÏÿš‡¦ÿ7¯©ÿÛóÿó¿qÆÍÏïú/‘õ?I0&c‰.ÛmÌI0&H«ý€`PeȤqâþ_Øçÿ³ÐöMý_›ÿû©sßüñîÿÙìÈ>ä¨U0â%1[S\1L3¥DhÙÛŸÿgu¯ÿ³Ðôß¶ó´6ÿwòçî¤îÿ“ÿälÖÖæ:Ô‡X'ýH˜ @0š£ŽÚª2íþÄîÿ,´ýoçÿ®oÔÿ!ÿ÷‚ûð›ºÿKdLÿZÞ™³óÅc äE{›Y¢Îº Tviý5vRÿ{ÿyhûßÎÿ]ߨÿCþïE·¼ãÍÝÿ%2âýŸÊÖÆXÖ'@ uPŠöiù­óИ“S¬§=ÿÃèþÏAÛÿvþùß!ÿ÷컢û¿DFÔ“L) Î ”È®ÿgÃEíœ;Œ¬;ð_÷ú?mÿÛù?lä‡üßã¿é˜îÿ±ÿÇÇBu~¯Py´Ñï3‡Zñ9ŠŠdç|ž¸þ»þþÚþ·ó-ÿ‡åÿÿä•wuÿ—Ȉþÿ]°™bPž¼èRŒ‘ŒG,Ñ ä˜Ä!LÛÿß@¯ÿ³Ðö¿½þüÿ°þÿg×½ö¥Ýÿ%2bþ϶@¬–­]ý´ àƒ¢Ä?þI”È%im¨:ûlõìùqvÏÙÙd'óM€{Îyøq“óÙk֞Ϭéýÿ:ióßÞÿ×ûýuv\|ý‰þ¡?6˜÷ÿ)!NÕ|¨=«X’ÓYÿaͱxàœíÂçÿ}¯ÿ«¤ÉÿÙõêÿ?ïÿ½õ²cìøo13üŸV£Ä ÚG–½øRŸü)’v¢”¤Aܲóÿ ßÿµNÚüï¨ÿùߣÿwË5ϼ¢ó¿Å̘ÿ—E‘EŠdSÁìë×A"öšüp/f8ÚùŸéþ?ôú¿Jšü›¶ÿ§þÏèÿÙoÜðcÿ-fFÿŸƒHyØëóQGBS¹¯M¢#VXt4V;Æe×ÿªÏÿX'mþÛþŸÞ9ÿïãûÚ~ÿÇ&3cþ ÙgÉI‹¶u!³% )æ$ St-×eáóÿ¦¯ÿWI›ÿ¶ÿwO£þþ߉OÝtyç‹™1ÿCHÊÂ`Šõ`B)ÎvÕ >Zv:åDzÙþßõû×I›ÿ¶ÿ×âôÿþàOõý¿Mæ`þµ À¨Äæ(‘˜¬Ž¹¶èltñõ[N‹Z¶þƒéó?WI›ÿ¶ÿwOcý?úŸyÛEÜùßbfø?Á—(œÍ!ƒa 61§„Â6ØúÛ‘Ó²þŸCèü¯‘6ÿmÿÏ5üÿqûÿª§n¹«ó¿ÅÌ¿µÁ@N2{!(9Æ”UÊŒJ¬‹c .îÿvÿo´ùoïÿ»†ÿ;îÿ_yóÏÞÛùßbfðoÀ1%äaç?I©¥ÞN =Õç@A"•|¡eçÿaŸÿ¿NÚü·÷ÿÝ~ÿA÷ÐýÐ-fÆùŸèU~½ Ùˆ*¡. D{æhlÑ ªeßÿÕŸwþ×H“ÿs;êÿtþ÷óþß[žû×Ï\¸ôâûN}䊗ßwî­ßy춇ž»¹Ó¿ÍÌ8ÿ+ºèCh¼²Ù礊vº¸XWê }Ò~áýÓù_%mþÛþiøÿ£ÿóàwõký °ÅÌ¿ò®aØ»öScrè(ÏÅæH‘Q:ìþŒƒùŸø¿µµèü¯‘6ÿmÿgÂ?‚:3ú¿OŸ¸ðŽþØ`æ?’ Éê€* ® @H®˜èD•Ê.˜àl"XØÿé÷¬“&ÿgvÔÿéùŸçýß[?ù¶Žÿ3cÿŸ¹D´} J¬5”jwžÑf$YœòéH÷ÿMú«;ÿ«¤ÍÿÿÖÿ—\ñŧÿ|¯ÿ?Á“þÿá½þÿK¿öѾúßhfÌÿeQP˜Sfþ”ht¡â§ 8 %%¶GZÿOÏÿvÿg4ùWmÿ×LÏÿ<ïÿ>zÑw½¿?¶˜ó¿‚ Vœrl+ýÅi‡Nçbµñ¬jP\ýjYþŸ ó¿BÚü·ý?ÓðÿGÿïS׿â½ÿ-fFý÷^¥\|BAú;¼öó8¨L%h™–ÿ ¶ïÿ¯’6ÿmÿÏ4üßÑÿ»ù²/Hç‹™ñþŸXk m*j¸˜ƒÄ¤¶.r}x±Â8Ü×µ3‡à_C?ÿ·JÚü·ý?³sþç¯yð±Îÿ3cþ_ŠÑe²ÉiJй–zòRPV©XÛäd3¦ÝŸq¨úßù_%mþÛþŸÙ9ÿóöGßô;ÿ-æ`þ«RHŒR°†rô:Ò&€˜ºàTâ²çl÷ÿÖI›ÿöüÏÿãöÿOÿÕ\ÓùßbæÜÿ'œ“õhkÅg8—ŠxQƒ l–õÿÐuÿg•´ùoïÿŸk¬ÿÇýÿÇN~è·:ÿ[ÌŒû½ÉQ§ú›ÆG°Ñ*’”²õ.©’´Ñ^®ÿ úþß*ióßöÿÎí¯ÿçÏ ã?o¿¨6w¼îÍ/î_¤çP™±þ7Ú• Z¼ñÉÛ˜½8c#S]öëœÔ_ CwÆÁüã„ÿ~þLù?snÇøOدÿVükùÿ¾‹Žýçþô“?ðâþ=z—9üÛ¤up]É,…}ö‘c ž8k)¹p´óÿþ±¿ÿ_'MþÛåöë¿çÏÁ—÷øÿ¹ü£_îüo23üŸœCV.*,>ZÌ9k*ÅRL9¡X |$ÿg¿wÝÿ]%-þwŒÿ„ýãÿ+ÿíñÿïþdìüo2sîÿ l%’-Þ8Èɉ±Ãé_ÅÕ…‰ÖrbÿcAÁ¿íó¿×I“ÿ¶þûõßÊÿã{ü_õé~iç“™1ÿ#衃2¾> Œ¯‹}Ðs@\.ÊÅ`\>’ÿ³Ÿãúü¯uÒä¿­ÿµøtÿï¿üÚWvþ7™ïÿ5±.µ÷7†‘Ìp  q!ô˜ ¨T–}ÿçtßÿ_%MþÛúì×ÿ+ÿÿ¶ÇÿÂG?Öùßdæ_¼cÌhê?A3³³Æj+]‰iÿÉÈÁåeûìþÿ:iòßÖÿ`¿þ_ùÿ—=þþºïy°ó¿ÉÌ¿&qH$ƒHP’l‰@˜P¤H…iØØýß<ÿ Tÿ¿Jšü·õ?دÿTþÿuÿ¿ÿÀSoîüo23úð’jƒ?<PRÖ þÛÔg@ˆÎBw$ÿRÿM÷ÿÖI“ÿûÿSýÆýÿ;ßýèéÎÿ&3ãüR«Ø8ÒÞ˜ú{À,”êª? Ö¶@I,¸ðûÝßÿ­’&ÿíýÿ3Óúf¬ÿ÷ÞpöuÿMfÆý‚Äj˜ð *ïYïÿÉ•JIY"åƒ,ìÿiÓûÿUÒâÇø¿3Óúf¬ÿŸ|åùßëüo23ü6 ‡Í~†~²‰Î²"1JTUDë¢ղõ»ÿ³Nšüï¨ÿSþÕèÿ½ôúw}Gç“™1ÿßÔbœµ õà}]Àpø·ýrgS⺠ˆGšÿ3á_uÿg´øß1þOMý5ú¿Žßú½ÿMfÿJkKž¹ —:G*šàbpŠж,ä<ìþŒÃð_Üù_!MþÛþŸšúÿjôÿnzÙoïüo23Îÿ#e3{Ĩ%gîü—£†R[—BŒÝÂþO_ÿ¯“&ÿmÿOMý5úï<þàÉÎÿ&3ãþOˆbrÉÙq°­©¿*a.j˜È…ÜÂïÿûþÿ:iòßöÿÔÔÿU£ÿ÷Ù¿ñÛÿMfÆþ º¯kÿÚð"Ã>*Î C´®H‚vÿÇ´þ÷þ4ùoûjêÿªÑÿ»äŠ›ïíüo23îÿ‰‚e[¼NÚ#¹PAŠ&8 °YØÿÁÞÿ¯’&ÿmÿOMý_5îÿíÔå_êüo2sæ Y)£¦ÄìutT¡8c9#ǬJaÙþßCïÿWI“ÿöþ¿šú?jÜÿä†ùïÎÿ&3ãþO ¾¯KZ’­ü[•‹E•h*Þ‹OPŽvÿw£ÿïþï*iòßÞÿŸò÷ŽõÿO>~6wþ7™þŸñwÑ‘uTµÑ/‰¢¯¸þÀä Tb­Ö óºû«¤Á¥ºÍÿÄÿ{ÇúÿØÛûÑÎÿ&3Ãÿ³TË»X—‚dŸ%¡J ¢9¸àr‡¶p]ìþŒÃ¼ÿƒ^ÿWI“ÿfýwç§õßþßñwþÓuÿMfÆùÿZù'gJa›•6…|Š뚀 2Ca•­¦ÝŸñÍóõ—®ó¿FZüû¦ÿçÎOë¿ý¿=yõ·wþ7™9þ[g+ì¶2ïXû Úg•Vľd§LÐÎ.ìÿù~þo•4ùoú'þ/øÑÿûð^óCÿMfÆüOäDkDªâ y.®v”È0ç#Ýÿ1ÿ¯úü¯UÒä¿éÿ9œø¿àGÿïeÇ/¿¥ó¿É̿ʵ$“@y“}Î%jƒ¥¢ƒÖPÄÛ’ÿÓßÿ­•&ÿMÿÏáÄÿ?úw\õ‹Ovþ7™û`k©w¢É£B°e6)go“EvÖÕú_â¢ý¿5}ÿ4ùoúMþGÿïõg¾­ó¿ÉÌxÿ/…‚¦“gQ!yÏ‚ÄÀÑ娌ZøþŸîÿ¯“&ÿMÿÏáÄÿ?îÿ¿ãsÞÛùßdf¼ÿ3!+¨¤ •¤( ƒ“‚sXœ/ ûÿ½ÿ_%Mþ›ûÿ'þ?øqÿÿ#¿úþÎÿ&3£ÿW¨’2äK… D)j2$hbýa»¨ÿo†ý„Îÿ iòßÞÿljÿwõÿ¾ ño:ÿ›Ìœ÷ÿ äœb[‹½6(:ÕFÀä„6e‡Ãë½ìúßû^ÿWI‹ÿ»wÔÿ©ÿs÷Xÿøü±¿èüo23Îÿ;ŠÞÖ–_$‹`0Ù»D “Îè“ò¨±¸e÷ÿ­éçWI“ÿõêÿØÑÿ{׿ï‘Îÿ&s0ÿ&øèKÌ.DJìô0óËHÁLXtý6ׯ”ËÖçúû¿UÒâß¶ý¿»¦õߎþß×ÿò¿¸ó¿ÉÌXÿ+U²`ÈÑšâµõIy˜þ™¹~Ë£5)ºÝŸqÿºÿ·Jšü·ý¿ÿ£ÿ÷ªøwvþ7™õß&=4øÈ)Ÿtò%8&lɶÄèê÷ —…çÿè¾ÿ¿Jšü·ý¿»ëÿÑÿ{ß?òªÎÿ&3gþD…BAkQG›X”øS!‹è’Z¶þë~ÿç:iòßöÿôÔÿ·£ÿ÷KÒvþ7™çÿ2K"ŸL T´X.ŠQ$Ô?•hzS–}ÿç}ßÿ[%MþÛþŸžúÿvôÿ~ó¶O?Ñùßdfø¿1Vö=kLH\—ý0•"1‡<"$й¼¬‡Yÿ›~þ•4ùoûzêÿÚqÿÿ §ê’Îÿ&3£ÿÏ¢’£0h]e”Ä)•ÊP¢V²lý‡>ÿk4ùoïÿë©ÿkÇýÿ÷ÜqÍïwþ7™ïÿ!DÎ)R*´×1C€JŠ#´ŠYQŸÿ½É4ùoïÿë©ÿ{~¬ÿOñjÝùßdæß2,&JÄÈ £¥˜rDm\±ÁyŽVS »?ã0õß÷÷ÿ«¤Åÿùõ¿ÁÿXÿ_ý’×þ{ç“™Á¿˜’”ÍE#¥XrÉ{ƒ²!VÃ]ÄN²øEïÿ¥{ý_%MþwÔÿ©ÿ£ÿwþ¹_íüo23ø/6§”}ªë€P²¤BR}8„h@”ÇÀËžÿ÷}þß:iñmÿOOýý¿kÓí—uþ7™ïÿ@@g ºV{7Ì QQ$Ï@º(.ÑfÑ…>ÿ‹}ÿ•4ùoûzêÿàèÿ¾úØÿMfÆüÿÀRÉ¡ÔÚ³–0lü ¸ ªx²2¸ðý_}þÇJiòßöÿîiÔÿÑÿ»îÖlç“9˜J©}1ÚRâ\LHV9§J¶.'daþmŸÿ»Nšü·ý¿{õôÿn{ú¹/vþ7™ó¿Ð°I%Vº®ýKðõ!=gÈ¥þ\²§¼û3Sÿm¯ÿ«¤ÉÛÿsSÿGÿï7Þò‰‡:ÿ›ÌŒõ¿7™Õ0è§.þ•7¦v"F)›½B¤Rë¿Z¶þ+ìû«¤ÉÛÿkñ?îÿßô•Ïïüo23æÿ%g"Zò¤ƒ µüç@¥h›„“äú3øöÎ/Ô·ãªã´ÑH@Ð*Uú'­|X³fý™±¶UblJBãßj¥XæoPRLSMƒ ÑJ­’ˆ>T+¨T_ú"'·¹·‰ÿ &(QJ©Q£(‹Š©&jÑÙÙçmϳ{ØlØ0ß„{ïÃ~¹Ÿ³ÖžõÙkýÆûÇüŸtùïÏÿeéÿó<ÿ¿áÉßþ½Áÿ!³bþ§ÕÒ€8x˜R¶lLŠèav›Þÿ‰:ü¿}Òå¿?ÿ—¥ÿÿð\ÿïzá[ÿ‡ÌŠùŸÄœ}†`…ªgv¹hÎÑ­1§º­ÿO0öì“ÿŸ¨ÿKÿÿá¹þßþ‹?õÔàÿ¹˜>‰Ê¡†líåŒF³²&ï}RSn}ÿ×øþwŸtù?Qÿ—þ¯™ý¿Ÿx)ŒýßÇÌÅüoCRÉÉÀ쀫sê)ºéZÍUÙÝxþÇ£ÿß%=þMßÿ“¥ÿkfÿï¹ßýø þ™çÿD¦ .¡ñ&gmì¦ j´É$¶Øþ¼n[ÿ ýß»¤Ëßÿ“¥ÿcfÿïæþäÿ‡Ìþ…b4YK¬>:ÈŒN²pÈ&)»È¶¸lýÆýÿØÿ»Oºü÷ý?Yú?föÿäwhðȬØÿUZ5NÈZ*˜>ü«PJäÙ˜€žÛ‹n»ÿÇÒØÿ±Kºü÷ý¿ÿ³ÿ÷Ä=þwƒÿCæbþsiM¿(¥T—´j €J«ý1¥*l$Úvÿg{©üï‘.ÿ}ÿïJ§ÿŸý¿ç¿ü½oü2+ê?¡×F~d]µ¢^|”`\åTDŠXJB¼í÷ãüo§tùïûW:õžÿ¿ ÿæÍƒÿCfÅü² \1E U0Ùc¶"’]´ÎAN”©È¶çÿ"ÃÿÛ%]þûó\ú¿fžÿßûÙëŸü2+îÿó±”\‹OÚ 9‰5Ì‘œCö›úíà—tùïÏÿqéÿ^›ëÿ>ùËO þ™ý¿Äl¶¾Ú„¾¤@ä|uÕÛÖ°i?Lämýâáÿí’ÿ×NÔÿ¥ÿ{m®ÿw>õ‘¯ü2köÿ§BVŒ¤Œh#©p1*)fhÿ«’ÕèdãýŸ8øß%]þOÔÿ¥ÿ+³ÿ÷Ÿæß¯ü2+úÿ•ª™vþuìMÑêkªÙ.|pN­xú—9ÿ×áÿì’ÿÒ÷ÿzüÏþßû^þÂßþ™çYc­Æ EŒ­1÷íåÜë²Q†ÔgÏ™¤œ~Æ¥ÞÿÇþ¿]Òå¿ïÿáÒÿ—Ùÿ{Ãm?ÿ·ƒÿCfEÿO¤6y_Äù ¦`Ic*Έ 6UÈÉsú—©ÿ8êÿ.éòß÷ÿpéÿËìÿ½í®Þ=ø?dVÜÿ‹¹XæàXØ‹ÄÓÆOUªš:€ºíù¿‘ñýß.éòß÷ÿpéÿÈìÿ=+OÅàÿ¹˜pÓúO0:õ[+h 6âÛ›?{ïR©)oêÿ¢ÈðwI—ÿ¾ÿ‡KÿGfÿï?êýw þ™û5Æ\±qï¨5ÿ¦J¨¹x4–R„¬ŸÿÿoŸtùïûtêÿ<ÿûë>ôüàÿYÿJÓð"hsµÉkrt²tc5*Šž~Æeø÷ÿî“.ÿýùÿ#ú?Ïÿ_ó’¾uðȬ8ÿ÷Y€}Fá$…‚ÉÓì/•B¨)ۢΠoüýŸïÿ»¤ËþßáÿÊ\ÿ¿ú[ß?ø?dVø–‚õ®ø€˜àÅos¢ ¾ý†uÎzÂ’]Þvþ:¾ÿß%=þ¯ôë?-ýÿ+ç÷ÿÞøãýÿ˜YÁö“âßj²–Ä”LÍZ1[F@¡lìÿëèÿwI—ÿ~ý§¥ÿç÷ÿ>ûÜwþ™û &¼ñÉW'® åÖH„”"a*Rƒ‡é¾Þ“¹Lÿ?öÿï“ÿØ÷ÿhéÿãùý¿ï¹ñ±Áÿ!³bþ§Ì¡x„[ïU”[ñ—ö7}°¥ýoãû¿Œþÿ.éòß÷ÿhéÿâùý¿w<úçƒÿCfEÿ_k1¾|,6k¼õŒ.šàJ(Á:hïºmý'ýÿ.éòß÷ÿhéÿâìÿýà—üȸÿë˜YsÿwI söÌ>ŠqŽBL!ˆä§»‰$97Þÿ=öî“.ÿ}ÿ–þ/ÎþßGïû¾1ÿ?fV|ÿ—T \r•`r"¨¹@-Å…s©‰úh7ÿ“…ñþ¿Kºü÷ý¿ÿ³ÿwöèïÿ™5÷%eˆ”lÊ ÁSœnrÕfb&ÅèmÙ–kh|ÿ·Kºü÷ý?Zú8Ïÿ¿ì7¯þóàÿ¹˜ÿ¤D˜¤ j5žÅ³F \ÕFÛ~(€_“šmßÿõ—tù?1ÿ_ú?8Ïÿïyà±ïü2+ü¿ÚŠ?P ‚^jkö÷ÑÛZÛ¯ªØ, ¶ýþŸÌ8ÿß%]þûóÿ³eýd®ÿ7_ý±;ÿ‡ÌŠû¿sQ'Q‹CLÁ9ߘ'çX³oo!hWC²§Ÿqþeð¿Kzü?Ò¯ÿgËúÿÈ\ÿ?ø/øÚÁÿ!³¢ÿ'*襢ٷ_#°V›¬çl…¼IfÛúoÆþß}Òå¿_ÿaéÿÒìÿ]ÿ™7Ý<ø?d.æ?‚`¢F¦±¾xn?ÀïP!P˜.bÛZ¿í÷ÿ:öÿì“ÿÔ÷ÿ`éÿÒìÿýÜ»þ`Üÿy̬8ÿœ!S–"jÈ;ð6jh¿4¥„ÖúKFÍQ¶öÆü—tùïû°ôiöÿÞô–{ÆýßÇÌ ÿ·ÆVôKÆ•\}ô0íý‹ÆD jM’¬ÙvþÇ0êÿ.éòß÷ÿzüÏþß-Ÿûü_ þ™üs íEߢ#WQb­P ³Æˆí¿ÅÜÖÿg绤Ëßÿƒ¥ÿO³ÿ÷Ø/|ê¦Áÿ!³âý¿ÚêŠb±"Û €kïbYƒ‘ìíôuè¶û¿ ú¿Kºü÷ý?Xúÿ4û×ýŸÇÌ ÿ?{rª5bcTKÍ ‘-fŠ£¢íƒ¦mïÿ¦±ÿsŸtùïû°ôižÿÿëƒ/¯ƒÿCfEÿ_ª±š«¡Tm¶‘Ÿîÿò%[ÎJXjñ&b=ýŒËôÿ4öí’.ÿýù?,ýšçÿŸ|è½oü2óŸQ./Þ^ 'ŽRs0¶×Ú€ŠµÕ,¼íù?ãà—tù?1ÿ_ú?gsýáWåõƒÿCfEÿŸBHÖø«u¹Pd¶/Þè ³ñMÞúþïqþ·KzüŸuë?^]Öÿ³¹þ×[ßüƒÿCfÍ÷ƒ˜"Tª¤TbAHµý4ÈÖÓ´  B¬”Òég|ñü“û?öI—ÿnýïñ³ÿ÷Âëžùðàÿ¹˜ÿöÞߺ~ ˜ $Oƒä`[WJ)I-²ÝöüÏâøþw—ôø‡®ÿ‡W—ý?Ìþß½¿þÎgÿ‡ÌŠú?É} Nƒ°OÅJ‰lúÖ­Ä›·õ¬õ—tùïúÈKÿÎ÷ÿ½ëµŸü2k¾ÿÁ”3ij¿km¿å*¶. {nÁÆû¿Æ÷?û¤Ë×ÿC^úÿ0ûÏß÷ú»ÿ‡ÌŠý_µ55j´¡ª`¼3ѵ@"øöû¶”ˆ ùô3.sþ?øß']þ»þòÒÿ…Ùÿ{Ç«ß÷²Áÿ!s1ÿ w$JÄ×b\kc¹`¨ä@AŒƒmçÿhÆüo—tùïúÈKÿfÿï–{þâ»ÿ‡ÌŠû?C1²hÈÞ«)!ErbqÓoYÝég\¦þýŸû¤Ë×ÿC^ú¿0Ïÿoxåo}ÇàÿY1ÿgˆ¡rÌèeMÉ´^Ä&JÁ§H‘sñ~ãï„Çü—tùïÏÿ{üŸïÿûðMß6ø?dVÌÿ "VŸ“w ‰_\úÕs®.MîÚÚÞ N?ã2ý?áàtùïÏÿyáÿŸïÿûøS7}zðÈ\Ì)¨>z—ŠfH1X’ä­‹^Á'EÆlSÚöü`ìÿØ%þÏúûÿþÏÙùþ¿¯ÿªŸ}ÍàÿYáÿ'Ööª¯ÁbVQ) R O?ã4 U[·žÿ ÿg—tù?QÿþÏÙùþ¿‡>ûOoü2+Îÿ±õüUÜ´“C &ãBp‘˜ÁGµ†[s`ÁÕïÿ„qþ¿Kzü÷÷ÿáÃËú¾ÿï•wÞûààÿYÁ¿õ%Go+jUS4äha¤”sáé*MâÜÆßÿÿŸtùïûwêÿìÿýé;žùÌàÿY³ÿ$Ö’‰‚!Sõ!µ,Tà½ñæô3.ÓÿýŸû¤Ëßÿ3 ÿ÷ì|ÿßïüôu7þ™çÿ†jV+˜s$Ûþ+­úW”öoh3“ÙøüÏИÿï’.ÿ}ÿ¯Çÿìÿ½óÝgß>ø?d.æ_Ф%JíUŸl(É%cÇè8Ó÷ÛÎÿØŒó¿]Òå¿ïÿ™…ÿv¾ÿï[Þø5×þ™5õß“°Ûj¼)­3O¨µÚZ¦ 2g¨N¦–àô3.Óÿû?÷I—ÿ¾ÿgþÿÙùþ¿ÿzíÓÿ7ø?dV|ÿWE,äªÓU"NEÇÅ@ÊÑ´ßõ6öÿiœÿí’.ÿýù¿YøÿgçûÿÞÿÒO¿mðȬà|®–C$R-“Pk†ÂN,[*›ÞÿeÇþŸÒå¿?ÿ7 ÿ÷ì|ÿß+î»í¶Áÿ!³‚0Yb1jC&Ù„ìbSCÕ¬Xœ.-›îÿ²ªÃÿÝ%=þOìÿ3Kÿ÷|ÿß7ßxûØÿq̬à_Å)øŠÀ¥FG–úl'´dç%rÜØÿõŸtù?Qÿ—þÏùþ¿Ï=ù­w þ™÷ÿ¨Zª•¬h45)yôj®´šê}ÑÀÛÞÿM8êÿ.éñbÿ_ÿÙÿ{Ï?¾õ—ÿ‡ÌŠï v±D¯Þä¢1”b¢‹>B¥àØg%ÊàO?ã2ó?þÏ.éòß÷ÿÌÒÿ;ßÿ÷kÏüÃÿ þ™‹ù×êJûK1Iå½ñvZ F&‚ ¾äXeÛúÏf|ÿ¿Kºü÷ý¿kú?û÷åM8ø?dVðï­·Óý¿±˜à©”ÜÚäRÂYL‰‘Zpú—éÿÍèÿwI—ÿ¾ÿw­SÿgÿïgîzÅíƒÿCf…ÿZÄé$údé‚kïH)«#Šý¶çÿ0Þÿ÷I—ÿ¾ÿ'Kÿ÷|ÿ߃ÿð˜ÿ3ó_QÛ»ƒÞ7j9kÅS©€l$;-®°-ÿ2öÿï“.ÿ}ÿO–þïùþ¿ü…Ç_=ø?dVœÿã´ø[ZE&Fxºû£RR”¨úâ3:§Ÿq™ù߸ÿgŸtùïÏÿeéÿžïÿ»ý?vÝàÿY±ÿ+˜{’¼s9´f¿µR©N¼·`9ØÖÿõ§tùïÏÿ—üÃ'æúÿ /ùþ_ü2+úÿ‚!†èA“”*‹z\±m¬ž¢ ÁDݶþë¸ÿcŸtøoT÷ù_øÿð‰¹þßÿÇ7<:ø?dÖ¼ÿ‹‰ Å—^‚I®6´†iÒƒœÙøü͘ÿï’.ÿ'êÿÂÿý¿[¿ç±O þ™çÿÆÚÜê?)ÞÅÌ18ª5–¤ÙÇ\Ú;@™þäô3¾xþ `ÌÿwIíû²ðÿAgÿïOþí›®þ™5þªjÍ€±:f¢Ð~¸öÖŸ §”,Óég\ªþËàtùïû²ð@gÿïîç>?æÿÇÌšïC.‘¨:+ŦXòÙ˜ F\Æüï˜éòß÷ÿdáÿ€Îþß—þå _ü2+êÊ®X±r´êC(!RÖêrVM•{ÍÛîÿVõ—tùïûW:õöÿžþÈ_?1ø?d.æ-,µuþ\§Ë|Ô*1šB.ÅÀTJ-FdãóÿñýÏ>éòß÷ÿzüÏþߟýÀ¿jðȬ¸ÿÇt*L>¨ÍâÚË@¶­þK©­ðÆ%Lí¶õÜÿ³Sºü÷ý¿+þžÿ¿*÷­ƒÿCf…ÿ¾ý `°Jv)¥j¥ÆÄ!²KÌèʶçcÿïNéòߟÿãÂÿçÿ·üþCãû¿cfÍþOCsôÿÏÞù‡þ~Õu|" ²©#¸4µbøGK:¯×yý8‡~™Ù´eN ¡Ã8?ר±²õ‡Eá F?ÔRtаD˜&•óÞ»»íj ö‡Œ-ÃUS¡á—¬Û*oÿˆû>î›ïÞ¼á çÉ…ïîîeï?öy|^ç¼_ó:”]¬À–K YXT3$ô9+ëÎÿ%ûÿMÒå¿ßÿÇ™ÿoîšêÿïýåÿ0øße.οMY¿ñ úgï<1aÊ¢w­ðTYwþÈà“ôø¿ëHýŸû¿wMõÿ’¯ýÕƒÿ]fÿ×û1a ™ép3W5×RKNXHšÃU`zü'ðÆùŸÒåÿHýŸû¿vòÿÞý²Ïüãà—YRÿq•¢ÉžŒµ¸Ô •ÃÍ>³ ¥ñÖ­ÿ¨ÃÿÛ$=þmßÿùÿk'ÿïüç>pÿà—YÐÿ@Åšì°’óAÛJjûaÉŸœ„(âV>ÿkÇüMÒå¿ïÿõøŸü¿ë§¾kð¿Ë\œÿÀ å™m䆱œ¨É…ôpˆ «®ÿ-Žýÿ6éòß÷ÿpîÿÛÉÿûÁ«ïùÔà—YÐÿÌm È…’ ‹wÞ…”5H6ÑZS£]ùý?Òà‹tùïû8÷ìäÿýá÷~ý ƒÿ]fIÿ?Èa•Ÿ}9\ªÑF¨®6ø¹)G`£lëºó?P‡ÿ¿Iºü÷ý?œû?vòÿÞûú7ŒùûÌ‚û}ÆœKR#åCÛÏ<¨€&‹>•!T‚ãÏ8ÿbÇû¿MÒå¿ïÿëÔÿ©ÿ—ýÍþw™ëÿ¼7Á°¤ÿ꤯¹´¯ƒ*‡Ë¿ÕG]ùü¯þÿ6éòßïÿŸëÔÿ©ÿÿš«îýóÁÿ.sqþ]ˆ%k­XsMìƒg×–þ‚Ð}†@̺÷ÿñxÿ¿Mºü÷ûÿ4÷ïžêÿkþô•ƒÿ]fÁü߯mÿ÷#Û’Šª³CE_c7’Mѵ½¬ýþø?›¤ÇÿÝýúßãªÿzù}ßüï2 öÿœbt\©RŽIS šR žkHí¯¬»ÿ×ñþ›tù?Rÿçþ?Oþß÷?ùñÇÿ»Ìÿ'[Ï&W_’mì» ¤X@%V[} êSuíÛàø3N²þýÿmÒãŸûþÍýžü¿ãu/üï2çßxgœuä(ÔÆ¥GïA3Öd¡ä,¾xëîÿaœÿÝ&]þûþÍýžü¿xÃc×þw™óUB%­)hµNM*&I…*H‘lª×õÿEFÿo“tùïû4÷yòÿþãRùôà—Ypþ_ FJ)µï€ì£o«þؾ0C4>ÄõàI®<ÿCÇþ“tùïû4÷yòÿ¾óm/ºvð¿Ë,ðÿ,j/”¹ÆTÉ[)©diÿ`X­EÖÿEÃÿÛ&]þûþÍýžü¿×½øï?4øßeœÿ­5ä`Ø£°QpüaÃf„-SâºûÄáÿl’.ÿ}ÿ¯ÇÿÔÿÿë?ñóƒÿ]æâü3Käë~‹‡ûþÜáÎ[¥Äèb+ýèJÀ•ûÿÌãýß&éò¤ÿ?÷ÿxêÿñÖ/eð¿Ë,xÿW…„‚àäð& BÉ«J?°z®ÇŸqþ-Œýÿ&éòßïÿŸž×ÿ3Sýÿ»ÜõÚÁÿ.sqþužmTãkLªÀ)åRm ElVɇþ`Y¹þãèÿo’ÿgúõÿô¼þŸ™êÿcž÷î3 üÿŒISÛì“%×8ƒ !s$ >”*ýºþ?ê˜ÿµMºü÷ë¿™û¿0ùá¡¿wð¿Ë,˜ÿ“ƒp© ÊÞZÑL.ÇêÁGUm©9ÅãÏ8Ñûÿñþo“ôø‡¾ÿgæþ/Lþß“¿ýŽ'ÿ»Ì‚þ_C³z É{` :Ôâ,FdS³ó!(¡•çà¨ÿ›¤Ëßÿ3sÿ&ÿïoü©Sƒÿ]fÁþ_±UxŸ¤T¤R™Š€9 Am;Œ5ÄœãºçX`ð¿Eºü÷ý?3÷aòÿ~èškïüï2 æÿ—CÃÏ«‘’“w^ЪxÓ¶¹ý>ÕW®ÿãüÿ&éòß÷ÿzüOþߣýï§ÿ»Ì‚󂔈ƒqdY xfX£«ÉæÌÀɯúþ•†ÿ·Iºü÷ý?3÷ÿaòÿòoó?÷™þu „ ¥ïýlM%G† ‡¯„@šjòEÜñgœ þ‹ûÿMÒå¿ïÿ™¹ÿSÿÿ]w¼âÌà—YÀ¿SòÎÔà¹ÑZlªÎeSÑ;YÛWC.Ñ–ãÏ8Éú¼ÿÛ&]þûý3÷`êÿô#¯þ³Áÿ.sqþ=ÄœDs¨õÕa b¬FåêƒäB}Ný?;¿ÿ{ð¿Iºü÷úÿ—b:…×<}öÔ3Ï<üÔÓ§.ûäͯ|Ç+?yî–žwÇ­Ü>èßi.Î?šd]1s ÙwxûÏ–äÒþDCf++Ïÿ áÿm“ÿ÷të?Ý=¯ÿ÷Lõÿ‘WÜyëøØeðïC8¬ÿk£ÔVù}V—¹š€9Úê%°K|ü'à¿--ÿ[¤Ë×ÿ£»çþ¯LþßÕÿüÙqÿÇ>³àü/ ¼«9J0 \ápï_IBÙBP L–¯Ûÿ÷ÿl”ÿÒõÿºüOþßýÿûÐOþw™%ëCmÕ!yâ9G§ZlÏ–84R±…U碎ùßÛ¤Ë×ÿ#žûÿ2ù?úç~mð¿Ë,8ÿs˜ôÄ¥Æö Ñ†ÚØ‡`ƒÏÆ›¬š¡¬{þ—ÇùŸmÒå¿ëÿÏý™ü¿Ÿ¹âü—ÿ»Ì‚ùhEÙY Z|ˆUsÐö‘ùVùQ¤pHëöÿÛwð¿Eºüwý?â¹ÿ/“ÿ÷õW?~~ð¿Ë,Øÿ ä$ú`}H1VWA*¾ýG’!êºóÿdð¿Mºüwý?â¹ÿ+“ÿ÷Ìw¿jÜÿ³Ï,¸ÿ\Ì\¡&ïKQs®úì SiK€Ž?ã$õߌó?›¤Ë×ÿ#žû¿2ùç_…Ïþw™÷¤j˜}A¹°°áìR&¦â0 tõù?£þo’.ÿýþ?Ïý_™úÿ]ÿã?;øßeÔc*(Y“Ú& ñîC()«e­‡¡ ±²[·ÿ2Îÿm’.ÿýþ‡ÿ³SýÿÖcÿþöÁÿ.³Àÿ7¢„%h¨ÙÅJU<€Þ—à(–uçÿŒùŸ¥ÇÿÙ#õîÿêÿ­w¾ûƒƒÿ]f‰ÿïÐqh5Ù¨ñ=Ù¶ïI=ÅöÛØ?ã$ýÿ1ÿk›tù?RÿçþNþß÷¼ñÙ?üï2 úÿ¶ñ™#U¹}&Š Þ²Sq$ž¥Æ”yÝû¿ ÿ“ôøÇ¾ÿwf^ÿqòÿÎÿËM:øßeìÿK,9f'µ˜¶é·©Zã’ÔD–‰°f„ƉÞÿ ÿg“tùïûg:õòÿÞôÕûÞ2øßeø¿Ù8I!‡#€rK€ä5d›CôyÝþŸÐ¨ÿ›¤Ëßÿƒ¹ÿ‹“ÿ'?òÒ þw™þ·’¨d#`,ÇÍAþgSÿ[ƒÿ]fÿß6÷äp˜w‡›Àsð>jv­ðG[%Wļ®ÿƒfÌÿÜ$]þûþ_ÿÉÿ»ê–7_?øße.ÎÇ A(µµ¿jfu¦ýPHU-d HjŠY÷þßqþg£tùïû÷tÖÿ“ÿ÷ÈÿÜø¾Áÿ.³`ýX‹ V±&Æ¡h]m?Úï8d²1ü'Yÿèÿ›¤Ëßÿ“¹ÿO“ÿ÷¥7½ì=ƒÿ]fAýÀ(j|t.ª˜¶¨Å»T©b,•E£dgÖ½ÿÃÚñþo“tùïû2÷ÿiêÿ›_?û­Áÿ.³ þ«Z¶”dY’8ÌN#CÛ÷·ÏFrd˜íÊóŒŽù_›¤Ë¿ÿ/sÿ—¦þÿ7~aÌÿßgø?5‡C¦( 5'Õ½aÏŽÑ'<Ü îÜÊþ/ó¨ÿ›¤Ë¿ÿ/sÿ÷ôTÿ¯üÝÛÏ þw™ëƒÙR’r°ýrhà§ œµ™K´€¾®»ÿokŠÁÿéñúHýŸû¿§§úÿÑßÿÉ7þw™ó? 88‘9W ‚¬†¤ŠÁè²5IV½ÿ Uÿ›¤Ëÿ‘ú?çßLþŸ¿üÃÃÿÙg.Îf«ÙUN‰S­×D^ˆ©ò ®- êº÷ÿá8ÿ»Mzü›¾ÿ'sÿßLþß={ùð÷™‹óEÅg®r)¹T$kÈ\E+f[TCëú ãýß&éòß÷ÿdîÿ˜Éÿ{Þé»ið¿Ë,à?r2TŽ©$¨3¡!’b²¨pYyÿãüÏ&éòß÷ÿdîÿ˜Éÿ»ùý=:øßeÜÿE¶QΔKJÞÄö¡0’Ч ÙjRt–$¯ÚÿGý¿mÒå¿ïÿíÔÿÉÿûØ£Ÿû×Áÿ.³àþo‰.gq¬þ°Ó/žÀ¢ ¹š²÷µ<Ìë=š“ÔûÿMÒå¿ïÿíÔÿÉÿ;÷®þbð¿Ë,˜ÿå9˜’Éçâ5G„T¢°G”\’xN1%µøœê?ÍúÿvÜÿ³Iºü÷ý?¼Ðÿ½ôšß¼áùï{þ%×^{ù ü÷™õß Š$æLj¡TÓ˜7ÖIµ5³qÅ*ŠÏmýogþ?ÿ“tùÿÿýÿKÞúÎ/{èç^øÎÓ)¼æé³§žyæá§ž>uÙ'o~åe—?wËS—Ð7ÞûÀ§Y0ÿÏKH±ªËYŒ‰A¸fL%³E_jHÈôœü¿ÿ<Îÿm“.ÿ½þÿ¥ï9ó‚—|äm_|Áï<{Ã7¿ù‚[¯ûÔã·ÝvÝ—^õµKî?û}/üï4 îÿLÖÚh’‹í+ V½€KÖd¨R=V¤ëú¿vÜÿµMæü›{Ìÿà ý¾÷Ûóÿ¸ï³gÆ7À.³€ÿÑÔH†R©ÑVùÛ*€Û6€ •ÀÞ&Í5ÚãÏ8ÿ¬£þo’.ÿ}ÿ/ôÿùÞoÏÿûewç'ÿ»Ì’ùŸTsˆ È$Á×RXÚOIÀŒ$l‹çVžÿÉ£ÿ¿Izü™ÿ‡ú¿ÿÉÿ{ëÿù·ƒÿ]fÁýŸÉÄh<ØœCCÝµÚ EA½okÿh¢5ºþûÿmÒå¿ïÿá…þoãòÿ>ðù_ù§Áÿ.³àüôµB.jµm4¢)®¶µ@ ªœ¨ÿÜÇŸqþuôÿ6I—ÿ¾ÿ‡ú?ÿÉÿ;ý0?3øßeìÿ¥D0bL U¢µ¡¡ë³ *#ƒ5Õ`ZùþOý¿MÒå¿ïÿá…þOãòÿ^ÿ‰~Çà—YÐÿ·è5rˆâ„¢3ÙGÄ)Û¾Jr¶VTÌÇŸqþqÜÿ±Mºü÷ý¿ÿ“ÿ÷–›®üêà—Y0ÿ Cu!„Ø8? p¨Õý{gûÙQÕñZÁU‚hT4A£/¨¤sΜ‡‰‰¢m µ"D $Ø2Ú4!RPD¢ -^Ð’´Q4¦ûÐ-!©š`#‰jbš¢61¤á¡mˆh[çÇÝW½óË^ÿ{s“›Ìw“Ýv÷Å}±û¹gæžÏœšÁ×Üð.k¤uùçÁÿ6éòß÷ÿÎuÖÿÓüŸ'®ú§Ÿüï2 æ´¿R+%ÕêcNPb¥ è*ÐW—#šuûÿ4îÿÝ&]þûýÿsú?õÿÿé|fð¿Ë,8ÿW]D±Ž¤ä\@µR1–5ж%ðžmÌmupü'úþ7öÿ›¤Ë¿ÿOOöÿùž óÿ>ôo?ù‰Áÿ.³ þGÌH‚’¼qQM&çµ½ (ùdˆ¸&ûÿfÔÿMÒãÿÈü?zòüïÆÿTÿo}Ûµ× þw™%û]-ê0GïYBO>¬É+ºB+ßÿ£ÿ·Iºü©ÿsÿ÷Âü¿kúšþw™ë`g&u”U² &›)–¬ ¦L]wþ?êøþ·Izü™ÿGsÿ÷Âü¿¿þÜ}w þw™þŸál[•W5ÁÄ¢>;ÌÜþè­ GE^÷ûû½Áÿéòß÷ÿhîÿ^˜ÿ÷¶Þsfð¿Ë,¹ÿ«˜Ãðÿ$…²s1»ÒVý"\%1¤’¥–`òªßÿè0dð¿Aºü÷ý¿ÿ“ÿ÷åg˜?üï2ç_³õ_¿îÏ—=™Q5ÔØ–Ö[2z€•ïÿç·I—ÿ¾ÿGsÿÿÂü¿g¾îé£ÿ¿Ï,8ÿ}ªE‚16‡È©†”ÀeæÃýß¾‘o$"…uùó?7I—ÿ¾ÿGsÿçÂü¿ŸzÚÇgð¿Ë,¸ÿ#zq|˜ûßVâC IȧE°­R²©í V>ÿ'cþ÷6éòß÷ÿhîÿ˜©ÿÿ¾8øße.Î?ªÑà€³‰ìKõ¡îýlkôš¬óÙµšuïÿþÏ&éòßïÿßÕ©ÿSÿÿÑ+ã=ƒÿ]fÿ6®ès ˜ ))ªGAm1@Ø«átü'Ùÿïۤ˿ÿ׬þë=Sý÷5Où“Áÿ.³àþŸì¡–Ê€®T)ªÔVüVÀ™ö;‡O€Õ1èñgœ€ÿÃ<ñÁÿéðߨîòofþ¯Þ3Õÿ}Óo}rð¿Ë,á_J¶Áç ­6ö} Ð^PÄ_¹&ôëÎÿ3øß$]þûõ¿Ã¿Nþß‹¾å5¿2øßeÌÿðGçT9|}ú†Š&NÞeµèƒ”"+û4ú›¤Ç¿öý?3óÿU'ÿïïþøßŸ1øße.ο³1*昋3rx€D ÑÖ8–R/mþÿ|ý/ƒÿMÒå¿ïÿ™™ÿ¯:ùo¸ë‡Æü¯}fÁù¿”CÎA*¸ÄYg(Sp5ïƒ mm€BYwþ·Èøþ·Iºü÷ý?3óÿU'ÿï™ïùÞ«ÿ»ÌÅùšÛrœŠ&¡bjar ˜­km(9òÊþ¯eüo’.ÿ}ÿÏÌü_ÕÉÿ{Å­û—Áÿ.³àûŸ¤LX÷ü¶Â_j5ÁIû•½ÏÁæƒÒºý?Áqþ“tùïûfæÿªNþßKî/0øßeœÿ±&»Ôpj[}ïÈ„ä0Ä(þ0ÔWö,מÿ1æÿo’.ÿ}ÿÏÌüÕ©ÿÿÕO}¸ þw™üGŒÂÁ‡HÎE±5(†C,V¸½JÈ+ïÿ‡ÿ·MºüéÿwøŸúÿoýµ¼nð¿Ë,ùþL¥Ãün?ùÐ0 h)&sµ©à¥Ýÿ=¯ÿ0øß$]þôÿçþßÙ©þßûÚ_xîà—Y0ÿ_Ä’`²%> þ–Ôh.t8t8 ˜J"•ÏÿŽó›¤ÇÿÙný7wÏëÿÙ©þ?ï/Ãwþw™çÿÚ–Ÿmh¬;"¤È¥U}Õä½—TA,ƒçËñgœ¤ÿoÿ›¤Ë·þ›»çõßNþßÙ;uùà—Y0ÿC Êa )g68g­R½’F ¡ VWÖžÿ=ú›¤Ç¿íú†çþ¯ü¿|ë^8øße¬ÿ³OEÈ@­ÞP¥¶Ñ.mÛ/Ù¥R«äu÷ÿ"Ãÿß$]þ»þŸá¹ÿk'ÿïoÜ#/üï2 æÿi/€Ê …ÀÎæxÎRªõÖ`¬ì#£[·þ£ßÿ6I—ÿ®ÿgxîÿÚÉÿ{ØßñKƒÿ]æâüºÃ  ³Õ@FDn«þ`cõÉhÈhåû¿‘‡ÿ³Iºüwý?Ãsÿ×Nþß·]ýþßüï2 ú9z†Îb,ÙG@“ lá\}{)dòWÞÿÿw›tùïú]þ'ÿï)o}güï2 ¾ÿUˆÅe±öâÜÁNœ$ {‡DQ¼¬ûýÜÿ±Qºüwý?ÃsÿßNýÿëîÿß:øßeœÿs­MŠÆ: ¨˜ª-¾-4bsA+Ö®ÿcý¿Iºü÷ûÿ<÷ÿíÔÿwô™ÿ¸òÙ7?tǯlü—ËÎ~éM:ðßiœÿ÷(Jvlhû~Û–ñÐlì[gûtê?ãû†Qÿ7IÿÓGêÿÜÿ9=ùŸ|ßsO7À.³äþÏPªRaÇ.ÇŒ$6Ä輆ܶj‘(—Tÿgüë˜ÿ·Mºü÷ý¿ÿ0ù/ûÔ×N þw™ýeñ*…À˜hD(uVª‹‡¡Ð­°!çV½ÿuÌÿØ&=þ¡ïÿÁÜÿÉÿ{ðõo¼yð¿Ë,ðÿLˆ –‚Ñ,mñïˆ|ˆYÀ!rR`ôëÎÿ1cþÇ6éòß÷ÿÎwêÿäÿ}ð}Ïyxð¿Ë,¸ÿ±j,>µâo Ø ö`ý88Üþ—Sõâ¬&›?ã$ýçÿ6I—ÿ¾ÿw¾Sÿ'ÿïïoyÖõƒÿ]fÁ÷( „@|m/¤Ù0£ Œ‹­ú«·TÖõÿ‘Gýß$]þûþŸÌý_˜ü¿¹â±Ïþw™ûÿÐ*¾KQÕÆc$‡Î¦ì*…R{“×åߎïÿÛ¤Ëßÿ“¹ÿ “ÿ÷}¯¸at÷™ý¿\u,öpà—Ú" d‰ˆ`)6GÁ­ûýŸhœÿÙ$]þûþŸÌý_˜ü¿Û¯{טÿ¿Ï,™ÿ‰„S ¶)×âÚ…hÉe@S)ÚXÅcÛÆIøó¶I—ÿ~ÿ¿ÇÿÔÿÿâãßyÍà—Ypþ¯iµ2qñÉ`hÔ—‚­ä_8´ÚïkÒ”âñgœÄÿó?·I—ÿ~ÿ_æþÿù©þ?üÀ›¯üï2 Öÿ6Y“ÔPmJ¾@5Áz«ÎCÐÃ4àö.8þŒñ?¾ÿm’ÿçÔÿùüïóSýÚmrãà—Ypÿ¯F²¾f"&i¥¾-÷Ùèá# ´B#5«¡•çÿï¥Ëÿ‘ú?Ÿÿ-“ÿwûM?÷úÁÿ.³`þŸ/ȽxŒš¹¸êIJi›þÚ¸§LÈqÝóÿí0øß"=þ¥ïÿÉÜÿ‘Éÿû‰ÿüÈþw™ç]tÐiŒ‚YYCt9e[#–”s{1Tõ±¬Ë¿Ê8ÿ¿Iºü÷ý?™û?2ùþ·ÏúÊà—YÂPC`]´&E‹Þ:Õù\jÔnÝóÖŒïÿ›¤Ëßÿ;Ó©ÿ“ÿ÷ÄßôŽÁÿ.³Àÿ¡\ ©²7r˜öŠÖÃT0_r®ÎYi›ƒãÏ8ÿȃÿMÒå¿ïÿõøŸü¿oäüóà—Ypÿ¯¶@ÌÆ¨”%«Ñè«qX\°ˆjP³îüÔÁÿ&éòß÷ÿÎtÖÿ“ÿ÷íå{îüï2 ¾ÿSC”bPvžÁg @¬¸äöу‰ÖõÇùÿMÒå¿ïÿáÜÿ—©ÿÿ¥üü݃ÿ]æâü›¤ä[½÷98ëÛZ?Sa,T3˜ˆ¾´ nåù?0îÿÜ&]þûýœûÿ2õÿï|ËM—þw™ó¿ÙA5#e®2@ “Ã¥IJÐ^ÇŸq’õ? þ7I—ÿ~ÿçþþõì‹üï2 ü?L¶T*%›r®&-%˜ÃTÀ”9K[ÆÿŸÿö/nôÿ7Iÿ3GêÿÜÿ=3Õÿ?ýÒ_üï2 æÿ×lJ¨Ž£¨+̵ý°¡ñ[D!`i«`×½ÿ‹ÌØÿo’.ÿGêÿÜÿÅÉÿ{èÅ_»bð¿Ë,à_œ|ýÃUŸ9´e¿C®hÙ'8\X÷üo[R þ·Hìû8÷qòÿê#oüÍÁÿ.³`þ_jÿ "’ÆL>„Û†>hR+ˆZ"°[ùþoó·I—ÿ¾ÿ×ãòÿÞ|ýõcþ÷>³àû_û«7m›ÏQCJÁæ"Åiv%a¥b¥ºîü¿öjüo‘.ÿ}ÿçþNþ߇o w þw™ýëaì—zõ¦F¬d ŸœǘR)àºßÿ-û6I—ÿ¾ÿ‡sÿ'ÿïg¿ÿ›ãà—Yàÿºª¦|Ùè3{ô%ˆµª\ƒ´Å"8SÜÚçÿÆùŸMÒå¿ïÿëÔÿÉÿ»â_ùŸÁÿ.³`ÿo]ȉRT°ÉÂøÑ;¡“C )µÁñgœäû¿ó6I—ÿ¾ÿw®Sÿ/Ìÿ±7Ü6øße–ÌÿRöœQ‹Å˜“  ÕjFÐHê,ºšSªº®ÿG0üŸMÒå¿ßÿ§¹ÿ‹SÿÿíŸKüï2 üã™Ø{À<ø@ ql?&§PY<¯Üÿ³cþ×&éòßïÿÓÜÿ=7Õÿ;¾ðª;ÿ»Ì‚ó‡vŸPL‹¡\"y‹µÌÎ¥ &xcVžÿcþï6éñîHýïð?Õÿ—]õ¼ þw™ó¿EƒÕšÄîÿH,%¤‚`m[®P£_÷üŸÕÑÿÛ$]þÔÿ¹ÿO“ÿ÷Þÿºêƒÿ]fÁüŸÊ`ÀÑÁôqΧ©Dqm I%š"¬üýøÛ¤Ç?õý?šûÿ4ùßúÒ?;7øßeÜÿW]6I V_Ú« ø€b5´ A€öÒ^ ”ȯëÿ[þß&éòß÷ÿhîÿÓäÿ]ÿœÏþw™%çÿDU*×±@fhÕ?´WAvŒÑ9 #S¸¤ù_v6ÿ|ÿÛ&]þ{þß/?}ê»>øëœzÃã7>öØ©[^ýÑÏÞòƒ¯þô~æ²+øŸ6èßi.οuF³„¨&K´ Ð`5%N%”ÄÅZd´1ûuý?ÂÑÿß$]þûþÍýšü¿ß}Í;Êxì2 êòXjÒ‘³Õ¬É“8TòH@8/5¬zþ¿½UFýß$]þûþÍýšü¿ÛÍó`ð¿Ë,¨ÿ!I1Ñ2£!ñ%‘uþÿØ;×ÝŽ«Ž#´´IÔJˆ!–ÚHM©%Κu™Cé‡B´ÅR¯µknH0jK…* ´T¢RB¼Ä€S­"ÕžäÍIh«†x)& Pª˜VûáS¡ ij1EqöÙï·=gçt³aÃüÎåÃóåý=kfÖoÖ`5 $µzá´ñüŸáÿì“.ÿ}ÿïB§þÏýÿ¿í7ß?ø?dÖøÿJàÔ1m™_§Ú¾Š@DuTÙEwú3®†;ÎÿwI—ÿ~ÿ¿ÇÿÜÿ¿å×^~ïàÿYqÿ@b,Ù¶ž}IA¼zK˜8@ûV@tê4MþïâüÏŽ÷?÷I—ÿ^ÿÿ¥Åë훾ôÐõÏ?ÿéç¾tý5{÷ß]ûº=|ד_÷Êûßö?ƒþƒf…ÿãªÄœª>!&(¢®´pNÓ;¥¯X·­ÿnÌÿØ'=þ/ôë¿Yúÿæúë5wšñ pȬYÿ‡\¼³dK[óg‹ØC¶ÅbpÉøê‚ÛxÿoÆüÏ]Òå¿ïÿ™¥ÿkfÿï±çþýÖÁÿ!³¢þ«­Þø1¢RrˆP Sž:5DvH¤Ïÿ§1ÿc—ôø7}ÿÏ,ý_3ûwüôuŸü2+æÿKJÙzÂéò¢÷ κLLœÛj`ÚhØøþ¿ûÿ]Òå¿ïÿ™¥ÿkfÿïýoùÃþ™ç&%ßÐ 9_Ñh êj[„˜rû]³fOƋ矌ëÿ]Òå¿?ÿÏ,ý_3Ïÿû¡îçÿ‡ÌŠ÷¿Œ«5—’rÌ9Å$4H½zk5¥„h9n;ÿSdø»¤Ëßÿëñ?ûþò_Ý<ø?dVø? †\ÈÙˆ(šêD7ÝýImç﬊Ôm×ÿf¼ÿ·Oºü÷ý?³œÿmfÿïãPÆüÏcfEý5©¯“dÐþ4ÙÿZœe  ÁÎeÓõ?Šç»¤Ëßÿ3KÿÇÌþßµþÇãýïcfÅùŸ•Fff¤”=0Wô²åŒj™® lzþoõ—tù?Ñÿ_úÿfîÿ¿çþ¿vðȬ˜ÿEì!z >°aO¤6‹Xñ‘ÐW’TÚÊ€eÓùÖÉðwI—ÿ^ÿÿAº¸¨ÿgçóÿîyó¿2ø?dV¼ÿÄ2‹/š0{q•Œ*ÁNÏÿÑdKŠ÷ÿÝ8ÿß%þϺóÿÿ‹úv>ÿO?òÖ{ÿ‡ÌŠó¿êÀ©ÚÀ%Äо"9­SŠRT÷ÁkrÛ¾ÿÇ4ÎÿwI—ÿ~ýç…ÿ{v>ÿïÒŸüçßþ™óÿ­ B–B“•«XÅÆ³µ”K™.J¬yãùŸ<öÿ»¤Çwþ_ŸÿÙÿ{Çû¾pýàÿYáÿÖA1E ÅhÍΧbmgcƳØâ¼ømçÈXÿï“.ÿ=ÿ¯ñ¿ðÿÏÎçÿÝý‰ø¥Áÿ!³fþ_ €>f(,JµñZ3NÁ!f°bT…iÛù¿vÌÿÙ']þ{þ_ãáÿŸÑìÿ=ðñWÿÄàÿYãÿxc!q¬ x«S4sŽ©+ƒÁÓŸq5ëýÿ]Òå¿çÿ5þþÿÙùü¿·òÃÿ?fÖø¿±hn°çš‚&‰Á¤öOÅ.½ÝtÿO8îÿî“.ÿ=ÿ¯ñ¿ðÏÎçÿýë ïxïàÿYQÿ‹¡JL!³Ç¶pÈ*ÑV HÞcÞöüiœÿí’.ÿ=ÿ¯ñ¿ðÏÎçÿ]÷×O<3ø?dVœÿ R‰¬Q#A-õ±ás6èQ4ë¶óظÁÿéòßïÿóÒÿ9Ÿÿ÷ó¡ñþ×1seþù2e‹¾FŸÅEcÛvß[K¼šPRL>m¼ÿëÿ}ÒåÿDÿÉÿ…¹þÓî/€3Wæ?8W"¨ÂÞt©L¯KµT \©æTÕmûþ·¸QÿwIÿîü¿ÆÿÒÿ;Ÿÿg^{û¯þ™ëÿ‚ëm Æ©+âƒp6Tk¦Ä6¥mïÿþwI—ÿ~ýpYÿÏçÿÝué†ü2+îÿ@$¡{6^R 1› Æ9Ä[£ÊºÙúŸæùcý¿Kzüwçÿ5þ—õÿ|þßu?òß>ø?dV¬ÿ AŽžÅÌ­<‡š<Ç!q1m-…6óÿ.óoÆûû¤Ëßÿƒ¥ÿ{>ÿïË÷=sÝàÿYqÿÅÖ©#oJò g4ja_©†X¥ÓŸñâù·ŽÆú—tùïû°ôÏçÿÝùØ¥Çÿ‡Ì þKŒ9™Üˆ÷®Æ*ÕfH˜iz\ÁZ læÿ\®ÿÆú—tùïû°ôÏçÿ½êéÇ>7ø?dV¼ÿa8UcM2F“‚ºäѲÕLgmh;‚É×9™«àߎù?û¤Ëßÿƒ¥ÿ{>ÿïõoüÝÁÿ!³ÂÿMÉK š|N䕌Öý¦}p‰ì<'Ž>x8ýWÁ?ºñþ×.éòß÷ÿzüÏýÿÏÜtÛ›ÿ‡ÌŠù?~äBsÛ[²Rµ±”l“->b. l·­ÿ2úû¤Ë¿ÿKÿÿ|þß7üàüêàÿYÑÿwÓ“¿˜bN Wñä0ªB[ùKô.ñ×öþï‚ó?öI—ÿ~ÿþ?>:×ÿŸ}ýo]ü2+úÿ¥z[´JPϘ\t%¤ R¡mÀh%n³ûÿ—ù§ñþÇ>éðߨîó¿ððѹþßþ/¿÷ÒÁÿ!³âý/¥,È6+ø”ÕäéÄ/±¦d†L5˜9Ééϸšú?îÿï“.ÿ'êÿÂÿA7û_½ùÉ›ÿ‡ÌŠó?ër5¸r¨màc€X5X@gÌ4pz$o[ÿ-ÿg—ôøw}ÿï‘eýw³ÿ÷ô»îúíÁÿ!³býŸ 8¨â `[XL¶¢ñÞ0 —â(g–ÍÞÿ›ýßqÿwŸtùïûtêÿìÿ}ã÷¿æÿ‡Ì•ù§èK4’ ‰¶¥¿W2¹*Ó;¶`”˜o{þÏ4æÿí’.ÿ}ÿ¯Çÿìÿ½û«ýâàÿYQÿ}ezé'{Wm•’üåkÿNJW¹§7ANÆÕôÿí¨ÿ»¤Ëßÿ“…ÿnöÿ~ç=oüÉÁÿ!seþ9'ŠÚ~g’Z'Ù9ªb«S£’ÔFÞØÿÁQÿwI—ÿ¾ÿ' ÿÝìÿ½ï5—^9ø?d®Ì¿KHS‡?X*ÓI¥ˆ ¨f5žÉS,hêf÷ÿçó¿±ÿß']þûþŸ,ütsÿßš[¿0ø?dÖøÿ¨|,+YOœy¡ØêkD¶Iy»÷?æú?ü¿}Òå¿ßÿ—…ÿ‹nîÿ¿ñ†›ß6ø?dVø¿Ñg1‰©ÆWë#A0 AÐF„í_U+nëÿYþÏ.éòßïÿËÂÿųsÿÿŽ?{ËàÿYáÿæ¶åo€£ÏŒ1yA&v.W ¶†@=TN~ëþÿ¸ÿ³KzüŸ¨ÿKÿ÷l®ÿÿý’O<5ø?dVÌÿw‰ì*lœ¢R¦:ÝÌñòM€³5X¶½ÿO4øß%]þOÔÿ%ÿ8ûõöKƒÿCfÅûŸJïFPdÀ“Gî˜àm@LÛÍÿžçÿŒ÷ÿöIìû²ôÿpöÿ~þ/Æý¿cfÅù?ffТN#zÍíošL#Tª¶ŸÉ­ü3úÍÞÿ˜Ïÿ†ÿ³Oºü÷ý?Yú?8ûoò†Ïþ™ó?Cr‘)µý¾/Ö¡ ŽBÈÙh?íË@ŒæmùþÿNéòß÷ÿêÔÿÙÿ{ÙS×Þ7ø?dVø¿)0@a“ÁT«©ð¦1¥p ñ¼qÿÜÿÛ']þûþßCú?û_ù}¾}ðȬ࿦œ’'Ì®8Ϧ‚ Õx«\ËtO¿BPtnÛþ?™1ÿc—tùïûvéÿâìÿ½ð²7Ü1ø?dVœÿCʹøœ#i1„>WCŽÕ$nß  Ûöÿ ‡ÿ³Kºü÷ý?»ôñüý?þâKÿ‡ÌŠý¿ú`LÖäÈ;6ez›B@Œƒ-bjôžþŒ«àÌXÿï’.ÿýþ¿]ú¿8÷ÿ=ÝùêÁÿ!³âþŸ+Ó ¦ZçÙÿ!qR±¸B¶8h_a[ÿÇûû¤Ë¿ÿßáÿâ\ÿoùЧ~aðȬYÿ›"6M£?µbr™€%+GQ¥š‹Ûöþ?Ž÷ÿöIÿ‹'êÿÒÿ¿8×ÿÏ?ûª±þ?f®Ìuè‚/,©?Ý®‰òí· –3È.ƒÝvþŸ¥±þß%]þOÔÿ¥ÿϳÿ÷ñžwþ™5çÿŠÓ Õ($êmDk0Ù\§ûí¡l»þg7êÿ.éñÏ}ÿÏ.ý_žý¿ýìË¿~ðȬà_ a H>S19•\SJŒÑkÕK)d¥œþŒ«àß™áÿì’.ÿ}ÿÏ.ýžý¿gþòsÏþ™5ïÛêÛ*ßT4j"T ÑÅVô+jeÛê_Ͷó?í8ÿÛ']þûþŸ]ú?<û÷=ý©ïü2Wæßr²¤¬k¿RUV$0\bœ6®4tëÿëUõÿÇú—tùïûwêÿìÿ}׿]þÏ1³âþ_UJÁzç•3zÎizþ§æ¢1ÖöGXk=ý/ž;ÎÿvI—ÿ¾ÿ×ãöÿÂ-÷ýÊàÿYñþšd¬ÇŒÑMsµžlÉ’Ô“VãbÜØÿQÿwI—ÿ¾ÿ÷pgý?÷ÿ?}#\ü2+æ›ìÁ—DD!d)V$iTL³ak•ݦ÷ÿ†ÿ»Oºü÷ûÿ´ôÿyîÿ?úø37 þ™ó?«Lý}_,KÓ4p@ãkŒ”¶1HÎ[%{ú3®†3æÿì’.ÿýþ?-ýÿçúÿú£áÿ3+æÿiÒìlµŒ†Ùû L©mPÁbv€uÛúoaÔÿ]ÒãÿÁõéÿ>8×ÿçî{bÌÿ:fVð}̾×lÁ†ËÆ‘·±Pf¦í@1Ÿÿþß>éò¢þ/ý_˜ý¿TøåÁÿ!³¢ÿoK²¶šÜ¾ˆ“6hmò) jF„°­ÿƒ4üŸ]Òãúþ-ý_˜ý¿7=ôÂÏ þ™÷’‚35F‘D¨âR°)×+UrlÁ¤R¶ÿ%fœÿï’.ÿ}ÿ¯Çÿìÿýé·=õÀàÿ¹2ÿ%Θеʟ€À‘¡BÒÐoÅ¿øŒA"o»þ‡ñþÏ>éòß÷ÿhéÿÃìÿýómÿð-ƒÿCfÅþßfH†ªø4]õ1¾pêc­…#Vë·ÿ‡nÌÿÝ%]þûþ-ý˜ý¿_Ô»Çý¿cfEÿÏ‹ñ¶$—cã“<²¨µÎq(F|ã5Ó¦óÿ¬³cþß.éòß÷ÿhéÿÀìÿUx þ™óЩ¶­Al(Ö€ÓägŠ‹ ìcQ[*nêÿ"»qþ·Kºü÷ý¿ ú?÷ÿ?ò=÷Þ;ø?dVÜÿ©Áa‰ÞJð.eª":m¬¶EN*hŒ²-ÿ2ÞÿÙ']þûýÿ ú?÷ÿ?óŠÞ<ø?dVÌÿ Î j[úïY¼:Úÿ®foCReršœþŒ«9ÿƒáÿí’.ÿýþ¿Yú¿ÌõÿÉÇ?ûSƒÿCfEÿŸ¹jt­Þ µ½ TÛ߃#ÏaºPkE…¸íü²ãýï]Òãÿ‘~ýïñ?×ÿ»ßù½ïü2kæÿª‚sH2«!úÈAB¶ ZÞ«÷uÛùŸcý¿KºüŸ¨ÿKÿ_fÿ寮õþÁÿ!seþ5æB¹– E‹Ÿ&ˆT+ŵ¥b5È”3o<ÿ›ÆüÏ}Òã_úþŸYúÿ2ûO|ó…w þ™ó?Ðù˜ÙKM-¢©>ÚQÛî¿jI©VïÁmëÿòð÷I—ÿ¾ÿg–þ¿Ìþßw|÷7 þ™þ_H–RŒPSv GÖLÉBŠ&h6Lè˶ë–QÿwI—ÿ¾ÿg–þ¯Ìþß³ùïü2+øwI]l)r®ƒóD $§¬/!·@ÚÖÿe绤Ëßÿ3KÿWfÿïšoý/ü2+öÿƵJ€¶š`ÙaðŒAq•J[x_âÆó†ÿ»Oºü÷ý?óìoÈoYUǧ±(¦È²²1S‹L™ZkíµÖÞ»ÌT,Òš° 3“bÿ­uLr jJĬ°4ef2%+g‚´q¼†½1I-H“4!IÆI³„r&ÍÚgÎóʳÜÓãáÀý}qŸß½¿çÅ}>gí?Ÿ½öÒÿÑÙÿ»ö¹úñÁÿ!³æþO°‰Jð5ùTÔ¬6HQ¬#£¹‘(ʶýÿdôÿÝ']þûþ,ý÷ÿo}ê^1ø?dVìÿ¤D 9MÍ>œ†"mÄ_¼«•2'Áé(ð¶óÖqþo—tù?±ÿßáÞÿÿèÝW¿~ðȬXÿo´+°OÊÉ‘È1¤*'™l´HÛöÿ£qÿÏ>éòßÝÿ‡³åøÿ޹þÿô“Ÿö˃ÿCfÿчɱNÿ¹˜bþ³©Ü€%ªÅÌ Ë¶ëF‡ÿ»KzüßÑ­ÿp¶¬ÿwÌõÿ%ßú÷ þ™5þŸ­°B¨hB­6A%”ø?dVÜÿ+X]E5û³ñùþƒ@Ôh2†‹s^tÛóÿƒÿ]Òå¿¿ÿ/Kÿ‡æýÿÇ>ù· þ™ý?Mö¡ÖT4$-â=39Ë®85! Ó†ó?Îÿì“.ÿ'öÿ—þÏ¥¹þ_ó£¿øcƒÿCæòü y6)PthR¨˜Ä$pœKˆY€¢o?6îÿ'0ÖÿvIÿKýúÿÖeý¿4×ÿ÷>êõwþ™5þo©…¼ޱ$Mè‚b©ÖÓÞV ÙÄ>|Iû¼ìÿ3Îÿí’.ÿýúÿÖ/®ÿ_qÕõ×=à5¸â§>tÏ}ÿcfÅúŸ¶9?Fï‚ñ.ÅR‚O©D›’ 9 µ/Ù|IçÍÂÿûÿû¤Ç?±ÿwåU7?ã¦güÕ£óï~¢<æ_>yë]w?æê|ò–‡Üòüëp×ÿð…ÿù¶ÿA³bþomqT,€É€Õ9eP DcR5,Y]Þöüð8ÿ»Kºü÷ý?\úÿ|Þÿïû_zÕx2+úÿHŒ‘£'*„![1ÁL÷~ù$ì±jL²éþ¿açwI—ÿ¾ÿ‡KÿŸgÿïéW¿ü/ÿ‡ÌŠþ?˜söLàKM±Šñ %€&g½`ŒqÛú¿ãüÿNéòß÷ÿpéÿóìÿÝûÄ}xðȬñÿ%±KŽ*Ý¿ì—D¥ÔØk-¡´±z°éý¿FiôÿÝ%]þûþ.ý_žý¿}Ðónü2«úaˆžC –6ߓǠ֔µWBݶÿÿ¸ÿs§tùïû¸ôù¼ÿßã¯ü½Áÿ!³bþO«D!ôb£µBìs\6”I‰¸”¶íÿgdð¿Kºü÷÷ÿqéÿò¼ÿçÏ}í£ÿ‡ÌŠñ?+K%˜š~y6ÅZ >‰õN"[ÈySþIGÿÏ}Òå¿¿ÿKÿçö¹þ¿ã'¯ý?Ž™ãÿéÒßÌÄ¥å¬5‹ÈÆ$°@]ÝÖÿ3ãþ}Òãÿöõ¿Ãÿ\ÿo~Ë|nðȬ8ÿoòTÿs›þg* RšF%¹6)Ȇ#z yÛùÿØÿÛ)]þOÔÿ¥ÿsÿ¿¯zêûïü2+ø/ T#ðtùW+ýà @ToŠÍ6S…j0O?ã"üû?öIè÷ÿ{û²þÃÜÿïÁWÜxÝàÿYáÿ)LËþŒ6y‹Ù ph4ÛƒKÙ¶þŽùÿ.éòß÷ÿÞÞ©ÿ³ÿ÷ùÇ=êŠÁÿ!³‚°6d-Ùr(†6þ‡\\ ŠÉtêXôô3.2ÿ‡QÿwI—ÿ¾ÿ§Kÿfÿï¦O|ö¿ÿ‡Ì ÿ*Mr.%q‰5 2go“ËâJöêÛk lìÿ±üï’.ÿ}ÿO—þ/Ìþ_¾åo¿|ðȬØÿ/Î`˜œ¿Ì‘<4ÉgõI%W€b+‹…­×ÿdø»¤ËßÿÓ¥ÿ ³ÿ÷íŸþš±ÿwÌ\žÿd´½`-6±d’už’€²jÔ“·ÿƒ÷í’.ÿ}ÿ¯Çÿ¼ÿÿ®'~×ÕƒÿCf…ÿC!S¡mâ&–$¡j¶E°r°ŠóÛÞÿ§<êÿ.éòßßÿ×¥ÿóþÿ¥òˆ?ü2+üŸ*%¶âOSP ¯SŽE3¡QKP—hãþÿ8æÿ»¤Ëÿ_þÿÙyÿ¿·<ý£_?ø?dÖôÿ±ž6m4.`æR f"&ôņ@¯ÿóû¤ÃÿÙ‰þºðÿÏÎûÿ½ú)7Þ:ø?dVø?Icé+ãjòÉzÁiÒŸjöx””Ál[ÿiÜÿ¹OºüŸ¨ÿ ÿçŒgÿïg_õ›ß9ø?d.φ>E©ÈPɬ.G¯ V¡šMh“ƒ4‰§Ÿq‘ù?Œõ¿]ÒãÑÿïœÿ…ÿsƳÿ÷G?pôÿ>f.Ï¿‰‘DÕç `(­þÛ6ˆm>@ZÕIIÕ×ÓϸÈü¬ÿí“.ÿ}ÿïŽNýŸý¿oyøíÿ9ø?dVôÿo³eJ äRs¥”«i5ßÓt ˆ³.ùýÿ±þ·Oºü÷ý¿ÿ³ÿ^kGÿÿcæòüƒ¦h %Œ5ØT+7ðØå¬œÏŒ™“ Ûöÿüï’.ÿ}ÿïŽÎøöÿ~ÿSü¦Áÿ!syþ+¢s¹g9Zl¥ÞL=¿Åö^6PÄR¼±§ŸqþÑŽþÿ»¤Ëßÿ£…ÿvÞÿï·àÅü2+ü]Æ”²Ô«x±6 P™Ú~ÇÊÖÚX6¾ÿS†ÿ»Oºü÷ý?ZøÿgçýÿnxÉ^2ø?dVÔ%ùÊ^7<À±øö2 À³Ï„ã¶çÿ»¤ËÿŸþïÙyÿ¿¿áÏü2+îÿ¦¤©¶¡¾-â1´¢ß`/b¼ædR)¹¨æô3.ÂÿèÿµOºü÷÷ÿiáÿž÷ÿ{ösþ—ÿ‡Ì þM´Q+ÔÀmîï BRÍ%U @!x±ÎU°ÛÎÿÍ8ÿ»OzüŸèÿGKÿ÷¼ÿß§¯{äßþ™þp–Ôбä,f2ˆŽ)d— Q(ÞnºÿOvìÿí“.ÿ'êÿ’ÿóþ×廟;ø?dV¬ÿUc˜³Íþ~Ò³µš"K4F­åIL‚˜Òég\ þÓÿï“ÿ'úÿÑÒÿ?ïÿ÷ù¿|üƒÿ‡ÌŠó¿R5–XU«ÅÄF‚¤˜5SD†ŒmBàÀÆ÷üï’.ÿ}ÿ–þÏyÿ¿¾õ•Ÿü2+ú¸”¸“³Ô¤\üôÏÙx@o³´ŸÛ®ÿ™áÿì“.ÿ}ÿ–þÏyÿ¿ÇýʯýÌàÿYáÿ% )• *ê§ Sv¡†”K Õ­)o:þgç÷I—ÿ¾ÿw©Sÿgÿï·~õî þ™ûÿ­+XÚ´XÂ̾Mϱ &§Æ¬môçmë?ÊðÿvI—ÿ¾ÿw©Sÿgÿïwî| þ™ý2¸Ü¦ÿ\Š‹!'Ó&ÿšŠqTXBðºõøœÿÝ%]þûþ/ýßóþÏþ÷ÐÁÿ!³âü/ÙBRamÕ?2·@*¤¶ø’Q“VïyÛó¿mp1øß#]þûûÿ¼ôÏûÿ=Œù̓ÿCæòügs ,·jﱚRò+rûT¼äéN0>ýŒ ðÏãþ}Òå¿¿ÿ¿ä_Þ1×ÿ¾ï=:ø?dVø"RŒ¹ª®˜àÈdbÏ…}DЊ©}'Ûò/4æÿ»¤Ã£ºÏÿÂÿ—wÌõÿùú— þ™ëÿ 9¡ÉVœO•r1“þ“€œ'*Z(dÆm÷ÿÉŽþ»¤Ëÿ‰ú¿ðÿÅÎþßÇ>tóMƒÿCfÅý?.$@3% '#hB!¤Ú>Ç1•mýÆÁÿ.éñoûþ/ü_±³ÿ÷¾+ßõƒÿCfÅü¿¨·®V[ƒ¯–J„DXsÀ}rí]`Û$ ›mý_÷ÿì“.ÿ}ÿþ¯ØÙÿ{äcþŸÿ‡ÌŠó?6·ä6$÷ýÚ\ pôÁ‡d©Ö˜%Ômûÿ)Œõÿ]Òå¿ïÿñÂÿ;û_ý}W¾{ðȬ8ÿ£Æ¹ŒdK¤ Èk¶9N;Å‘­…¤½hÛõ?cíàtùïû¼ðÄÎþß½Oøü2+öÿ1Ô0Yÿ$Ž]QÁ‚%°cÎ%7°3Æ0n{ÿ_û<øß#]þûþ_ÿÙÿ»ëÆo÷ÿ3—ç_[ˆ¤!dÃyúh"TNAM ¥•ÿʱØÏÿÚ±þ¿Oºü÷ý¿Û;ãÿyÿÿ»_qÛ‹ÿ‡Ìþ'«Lp,I‰Á¹jœ *ª bN£ß¶ÿ7ÿgŸtùïïÿßÞ©ÿóþÿ3ßüG=ø?dV¬ÿW×à—ì¸ýákŽ´œÓ€Úô@9n[ÿÅŒñÿ.éòßßÿ‡…ÿ/o›ëÿõOÂü2+Öÿ}Ê+% %*åbÙøê½ „‚ÙU‰ÛÖƒcýo—ôø[¿þÃÒÿ}Û\ÿŸvæÁÿ!³büï4šc(sÀÔ†æ Á'”âR´è ÁY:ýŒ‹¬ÿ™1þß%]þOÔÿ¥ÿkfÿï ÷|ï§ÿ‡ÌŠûC¤9–6ÇÏÑ×5Keð¾Qm…K(°ñý:æÿû¤Ç¿éû°ôÍìÿ}ݵþªÁÿ!³¢ÿX›cN8 I1U0Ž —ÈÔ$ §Ÿq‘ú?îÿÚ']þûþ_ÿÙÿûìÇoý¿Ž™ûÿ J šƒ˜bµ¸€ÞÆJ UÔ)ähbMåô3.2ÿ‡áÿî’.ÿ}ÿ–þ¿™ý¿ï¸íÚ—þ™ëSebg£’Éú$ cqµ~Ö†Ål[ÿQÆúß.éòß÷ÿ`éÿ›ÙÿûÇþÂØÿ?fVð“Ou2}=û­›ª1.0)Çi1Ð×xú—çß,æÿãüÿ>éòßóÿ¾ìη^õ?~ñ‡¯ºá¿¯»ï¾«^ö¬w¾©þà³>òø»®¸ågoô4+úÿ{ë%äh=eÒìÅsŒ`ƒÚRMNX4(o|ÿ—ãÿ]Òå¿ïÿÁÒÿ1óþÿó^÷пo€CfÅúFŽÈÊ2õû F=jRñ±œI©–62À­ïÿõ—tùïíÿ£=[ú¿fÞÿ¿÷åïyåàÿYáÿi0yjÈcÉ·ŸISŠR¸½âtLjNaÛþŸÈƒÿ]Òå¿·ÿßø_Öÿ³¹þâ•óÿcfEÿïéŽàŒËœ¥bñƒgÚ¿ä¢Ùz¯xø‡Lÿ³õ¿Ãÿ\ÿ¯ù‘ü–Áÿ!³‚U­!¹lŠR˜nÿuZÙÏàE² 6=ØÖÿƒqÿ×>éò߯ÿ²ôÿeöÿÞ|í?Ý;ø?dVìÿGvYÈOc~S D4*’qèœR•€^óég\düoÆý_»¤Ç¿ôü¿ÆÿÒÿ—Ùÿ{Ä=Ïóÿcæòü“¶©¿›Úü™¢ÅÚ~¦#€ÓÊ ”Bí÷ MN?ã"õÆý¿»¤ËÏÿkü/ý™ý¿×üÛ«Çüÿ˜Yqþ§K™'Ò½ö3-¦PSˆ¥ÆBÎÒÆýÿÇý_;¥ËÏÿkü/ý_™ý¿½ÿ ãüÿ1³bÿ_“ @¶¤lªc83%µm `ƒÆ˜³¸ûÉXÿÛ']þ{þ_ãéÿÊìÿ½ó#¿4üÿcfÍýŸ&!UB‚6Ïÿ?öÎ-f»£ªãVóIÅCÒŠš(m‰…µÖ¬Y3 m$"¨M¥R⣭‘F (ImHZí…QB…Ô ­Ò·~m= ÄRÄÈ…ŠzB‚"Ø ‰ÚQq¶û½ÛóäÛùØÙÉNæß¦yûÞ<7ïïY3³~³¦rÑJ…#…Ll &ÈAuÛó?’1ÿk—tùïùÿ¥ÿkçù¿yçß}ÃàÿYqþg2b­˜9ˆ*%Ö !b)ê|Ô`+AŒaÛþ_ûað¿Gºü÷ü¿ÆÿÒÿ±sÿÿª{žõ‰Áÿ!³âý/GÑÅh)*T£CBΩ­(·Bm’ME6îÿÓ˜ÿµKºü÷ûÿ=þçþÿ-×ÜóÔàÿYQÿÕ%›Y ¯ÌÎä†s5I¼” 1”àkÜxþŽú¿KºüŸèÿ/ýŸ³¹þ¿Â<ñ–Áÿ!³ÂÿHú@²1P[ 4‚½Î蘶ûÿ8ÎÿwIÿ³~ý?[Öÿ³¹þ¿âGÿôÿ‡Ì ÿlñÕ'Ltz ³fñjbð²–’Ó¶ïÿŽ÷¿wJ—ÿ~ý?[Öœý¿÷Üý; þ™KóïÛ¼GÅäc±¥T­.â¶çvœÿí“ÿœ¨ÿKÿ瑹þß|áÏß;ø?dVð_S$RÓþ‰QÔ·í¾«qšúí+›Êj)‹—mûÿvøÿû¤Ë¿þ?²¬ÿ2û7?ã‡_0ø?dVÜÿñ -¸ìröI4EK‰9’–Ì#h,ÁhÙØÿ5cý¿KzüKþ_ÿyþßß|sø¯Áÿ!³ÂÿW©HdÑsMÎ¥0¡}%0³sâ!ûmçÿ!Œõÿ.éòß÷ÿY®ÿeöÿèŸýÚàÿY1ÿO+©åZ©-"äF½x§ÓÄ–0 lûþ'ØQÿwI—ÿ¾ÿ'Ëùß2û7}ø™·þ™÷S¨U!ºP2µå+õª¹Šãè‚ÑЖÛîÿÛßÛàtùïû²ôÿeöÿ~ë7¾é­ƒÿCfÿŒ¹Bñ¢^Zé7X„¼Ë9ŠŸÔÏ®‚5uÛûÿHÃÿÙ%]þûþŸ,ý_™ý¿O>ño7þ™þOÛ‹§RÉW‹¾ˆCTl\`ÎÙYƒ“ïÿ£ûÿ]Òå¿ïÿÉÒÿ•¹ÿÅ“/½vðȬ˜ÿK9@% $¡V›ª†P0KŒZrQ A]Ú´ÿÏmW1øß#]þûýYú¿2÷ÿ?ð¶{>;ø?dVÜÿ+m"ùdJn¬† ,äR[ˆæÛ×öëkÆüï]Òå¿ßÿïðÿÐ\ÿ?võ«ÝàÿYáÿˆ7ƒD®&€± +–(6µß)Öh¶=ÿ';æÿí’ÿ¨ÿKÿÿ¡¹þ?~ÃüñàÿYÁh"EÉyôŪ©rkٔȱ8åbÌéϸœúOãþÏ.éò¢þ/ýšý¿+ï½É þ™ûÿâƒè8¶u  Ù§È¤NKò…Mm(#–mïÿ˜qÿwŸôø§¾ÿ'Kÿ‡fÿïM×}ð;ÿ‡ÌŠûÿ AŠ`õ¡pi)R ºZ¨úipj&eÓûÿ†í¨ÿ»¤Ëßÿ{¨Sÿgÿï†koyrðÈ\š5Å¢ Kälš„E[-š<½œ £Áœ·}ÿÆû¿û¤Ëßÿ{¨SÿgÿÏ_Q_5ø?dÖøÿÕÙ•òQ IÙ×`8—’òôer°­ÿoí8ÿß%]þûþ-ý_šý¿þÜ›ÿ}ðȬ8ÿ3VKÄXjû+P‹>)djäƒ5®:GSN§?ãrÎÿÍðvI—ÿ¾ÿ×ãöÿÞ÷â·_9ø?dVø!Uj«ýÀä Úâ2€Õø`*G$¢¯\6>ÿÇÁÿ.éòß÷ÿhéÿÓÜÿ¿îõOƒÿCæÒüsm{üm±o«‘älÌØ¾|± ·dUoË¿Œùû¤Ë¿ÿOKÿŸæþÿ…ŸþÁ þ™ý¿˜­KÑUÂ`Ädž‘¶íb- µñnÛý¿Ð¸ÿ·Kºü÷ûÿ´ôÿ/Îõÿ™?õ‡0ø?dVÌÿ¯S™¶¬5—Œšl!EÅÛÚ·íüïöïàôø¿x¢þ/ýß‹sý¿ã¥w¿cðȬèÿK*EÐ:¶ņ»«5z£b,·¯ƒmÏÿŒëÿ]ÒåÿDý_ú¿<ûÿ£ÿ=ü2+êV޾‚õÂ2½øç”1eô ¨FÕx4$iÓþ?¹±ÿß'=þ¹ïÿÑÒÿáÙÿãk¾ñæÁÿ!³âüϨO\ÓÔýª^LcÚ/j(E¼¯oûþ'þ÷I—ÿ¾ÿ×ãöÿþò—®¿wðȬðb*ƒ¦,’CšvXH‰lErµ ÛÎÿgþÿ.éòß÷ÿhéÿñìÿÝÿ^=ø?dVø?)q&Lžiþ“4µ¾˜qÚ`®Ål<ÿdœÿï’.ÿ}ÿïb§þÏþßWÿî+‡ÿsÌ\šÿ)“­ Ž£è<¥ÌÄ0ÝÎ9‘¶ú÷ÛžÿYþÿ.éòß÷ÿ.vêÿìÿ=ýóO½lðȬzÿG\µÓ¤OGÓ$0h ~Ÿ|(YmbÕhaãû?fÌÿÙ']þûþ/ý_žûÿÿù­wÖÁÿ!³bþÈ l£žÁ Çš„­3ÂiZxEñ±ê¶ópÌÿß']þûý^ú¿<÷ÿßøì_|bðȬðÿm,Ó‘¿¯Õ…ض5k¦ª¦jÔ*±EÝöüÏÁà—tùï÷ÿyéÿ>8×ÿ>÷þç þ™÷ÿ¡á]¦I_ªÁ@ž®ÿ«sbÁƒV“Ô”ºíüËcÿ¿Kzü?x¢þwøŸëÿ_üÕó¾tðȬðÿä NïƒL¥ýA µ¯1©j-–¬ D<ý—sþoGÿ—tù?Qÿ—þ?Ìþßk_ðâgþ™ó¿Éc)ŠPnß.!:&ÿÆÊD”¥Š åôg\Öùÿà—ôø‡¾ÿÇKÿfÿïŽÏ|Ý—þ™Kój@Ÿ -ÐVãÁ¶­Í ¦xïsÅêœÝ¶þ[çÿ»¤Ëßÿã¥ÿ³ÿ÷–÷þ^ü2+üßVÛ+æwÕXëä`œËVR ÖÛX åÓŸqü³þÏ.éòß÷ÿxéÿÀìÿ=üøß¾dðȬðl‡6Qæì¬˜ ‚²Jtj|dSBmë?Œ÷ÿöI—ÿ¾ÿÇKÿfÿïå¿ÿÑqÿ4ÿ&‡PR6 ŒÁ*Øê³.W„% WôeÛþ[ þ÷H—ÿ¾ÿ÷`§þÏþßø»_8ø?dVÌÿ±¹”@ÖWò’$G0Ëɇ•|‘êͶõŸa¬ÿwI—ÿ¾ÿ×ãîÿß}ûíŸü2+öÿ9FGZÄ´­¿³9ÖZ½(—"Y“I%¢›¦€ŸþŒËà_ÆúŸtùï÷ÿì¬ÿçþÿǾ÷ ß6ø?dV½ÿm“­UŒ'MqBÞ»ˆÖz!o¬ ¢Ó» öôg\ÿHƒÿ]Òå¿ßÿ‡…ÿv>ÿŸzÇ݃ÿCæÒüS+öÖxK¼ˆ&‡ZC”8L¶Ää%sܶþóð÷I‡ÿ³óÿ`áÿŸÏÿ{ü«Ê§ÿ‡ÌŠù_ÿÿìgû h4$›“aªZ*R,™3ÕÓŸq9çãýŸ}ÒåÿDý_ø¿gçóÿ®üÐýäàÿ¹4ÿˆ’K mMÁŠ˜•“ ¢ó‰Ñ ¤mç ïî’ÿ'æÿÁÂÿ=;Ÿÿ÷¦Û>yÅàÿY±þWï9i*Áq ÞŠËÅ´ýJiëÑì¶ÿmhø?û¤Ëßÿƒ…ÿ{v>ÿïýßò«_2ø?dVÜÿUâX¸€-AÔ±µÅPÞ±'ÕbØ·ÿ‰8æÿí’.ÿ}ÿþïÙùü¿w}ý½ þ™÷Ú ß°I¾dO&6rÕ‚(j¢‘šœ ¥JÜöýþÿ>éòß÷ÿzüÏþßw~úÚü2+îÿ¤dk[ÿ'ÂÉNs¿8%N¡m(Ô”§6À¦ü3¸±þß%]þûþ,üŸ³óù_ù³·ƒÿCf…ÿK!sUà¬T1b­!&0¢êÚÖ ¸±ÿgÌèÿí’.ÿ}ÿþÏÙùü¿O¼ûÆWþ™óRð¯ªD©º*Tj²K6Ö“#ÚøýOCƒÿ]Òå¿Ûÿ7wêÿÜÿ¿î97Œû¿ÇÌ þ•”¶ ˆ¤Þ:¯%R¤\[þ»ìÆïý¿]Òå¿Ûÿ7/ëÿùü¿gÉ•_1ø?dVÌÿrÑõ)×kPqÉEÍZ°íýÁçI vYeSÿoìÿ÷Jÿþü?c—þïùü¿«ïûÈŸ þ™÷&»¬‡Pó.¤¢™’s4I&É\1ˆnëÿó¸ÿ³Oºü÷ë¿]ú¿çóÿ~íÅ þ™þXÒ€ž8æéÑO¢L¬Ñ¥’ °ƒé ÐÅmßÿõ—ôøïÏÿëòþþïO¼ó‹ÿ‡ÌŠûÛª_ï®dÏqº h9׌ÔVE •mù7nø?»¤Ë×ÿ3véÿŸÏÿûùÛnÿÌàÿ¹4ÿ49 EtzÄ—’U½ËÆ'àD¦äâÜéϸþÇýŸ}Òå¿ëÿ»ôÿÏçÿ}êåoøöÁÿ!³bþ_pN¢ÛbŸ¼:ãhÎÄ%ÛˆÅÃ)À¶çÿ<ÞÿÚ']þ»þŸ±Kÿÿ|þß7ÿú_þ™÷r†lœøŒVÅ¶ê¯ µD©ªj5øÐ6¸íýáqþ·Kºüwý?c—þïùü¿¿ì…¿<ø?d.ͬł”¡ŠCbRMÕ*UÃUÚ ĸõüïñþ×.éòßõÿŒ]ú?çóÿžvÕß2ø?dVÜÿ£ä$!‹E.žWklA—pšN”7^ÿ#ó¿]ÒåÿDÿéÿœÏÿ{üÏßþ™ó²K †ì4¤¤¾ºVùaº÷ߨõR¢ÓŸqüÓ˜ÿ½OºüŸèÿ/øÇGçúÿµï¿òEƒÿCfÿÞ3k4!ª€EÇ8™T³4nsÎÁFVk·}ÿ›ÌðwI‡ÿFu—ÿ³ÅúëÐ{ðȬðÿb­ÖÕbl-B1G›r6±m¦s¥è‘6}ÿƒÛÿ þ÷H—ÿ~ý?[Ö7ûÿñ¾«ü2küÿSÛû³ƒJj39ëÑ´M€,¬É“/¿ÿƒ2ÞÿÝ%=þ]ßÿÃ…ÿnöÿnû™;îü2+Îÿ¢„è¼޾ÚJ$ÐRsšäéмñüþï.éòß÷ÿpáÿ¢›ý¿7¾ëÿyðȬèÿ¥àÀAcÝd‚j•KegmYCm˶ `¢mïÿÛqÿŸtùïû¸ðÑÍþßï¾øØàÿY3ÿ£íï«æRBJÅÛŸC1)b­N9ؘÿöãàtùïû¸ðÑÍþßw½ç.ü2+æý{çúíUÖñ•¬À?²\’Ú´À™ëǹι"§°’X$-ûÃ…óS M'¦Rêfš£¶liË•ƒ˜ìÙžç¥DTIV¤«%j¡•:qšöc¢u>»÷×îóñ{óÝÍ7œ÷{¶çÜÿ|_÷uÎ}½ÎubµT8qBÏF“¶ý{`BÈ  ‘@×ÿGF†ÿ·Iºü÷ý?˜ù¿à&ÿïóÿûåïüï2 ú’ABe -j9YcÐÚèIøêªs¹ýýñgœåû ÿo“tùïû=þ§þÿ·]ùÑ»ÿ»Ìéü[R¯±0ÄÃØ¿™=KL\(;+5† L]÷üÛ±þß$]þûý˜ùÿà¦þÿké_êà—Ypþ'år²š“³J%5>YkÚâÀÛZ\¶kÏÿýÿMÒå¿ßÿ‡¹ÿsûTÿŸôìûoüï2 øokþ+ת?Z(¹B©$PÚOGB˜Ú`åùÂcý¿Izüß~¤þÏýŸÛ§úÙ|ý±ƒÿ]fÁúŸQÄ’J¾òáÜoð±`Õ`£¬ÕzÕ +ßÿ £ÿ·Iºü÷ëÿɼþÓäÿ]¦Ïûêà—YòýÏk-š ×Z:¨>4\KåTmPoC\÷þ1ÃÿÛ$=þ©ïÿÌë?Mþß¹7|üõƒÿ]fÁúß®9@p+åP‚dÎÎPD¦R°Îºâ¾¬gñ`ôÿ6I—ÿ¾ÿ'sÿ—&ÿïŠgýáûÿ»Ì’óÿ8[B(œ¢Ib(ƒ§¤\$ÇR‹1§•çÿËXÿo’.ÿ}ÿ¯ÇÿäÿÁ}Où³Áÿ.³dþ¿Õh¡z5š|°R4Äz¸ØÇšÂá}ÿçùüÏáÿo’.ÿ}ÿOîÿ_üÖ«^ò¨ß~ÔEw¾í‰?9ðßgøÿ¨Žl¶mQN1eŽÁ¡mšªpÄdX…áùô0þÑú¿Mºüwü¿o}ë;ïxj¾þ3åÒÏÝsË¿öÒÇ¿òžwÞð„ÆÿS.ºöOŽîß^³`þ7Û*Y%„Š–²Ám4hˆœEÚŸ®;ÿsÌÿÞ(]þûþŸÌýšúÿõ¯^õåñØe¬ÿQ´•x %:S‹¸Ã-€Ñ;p–Á£bVöÿÇýۤ˿ÿ/sÿ—¦þÿ…·¼çÒÁÿ.³àþŸ@òáPÎæp —¢ |!‡B苚úÈöÿcþßÿWºü÷ûÿ2÷/Lõÿæßøå þw™çÿÚvß'‰QC@ “Xkú¶€¶3ˆY ¿®ÿ3¾ÿm”ÿŽÔÿ¹ÿsaªÿ?öµ/=sð¿Ë,¸ÿ³&}ÙVáYj(–MŒE‰‡)@¶¤²îþŸeÌÿÞ$]þÔÿ9ÿvòÿÞsýc®üï2§óo(zµILm £i¿ä¶ÐàÐ;u ÿšóºë‘Qÿ7IÛ÷ÿdîÿÙÉÿ{ÚÓ®½ð¿Ë,ðÿ«IÙ2ÇR|#·g"H>¬ \`“jñë~ÿ#ç6I—ÿ¾ÿw[§þOþßg~ˆ^8øße|ÿ眼'Cj3F~ÉÈf%FÎ äuïÿ:ü6øß ]þûþßmú?ù×]ôÌ/ þw™ëiµ_J²êÁå¤Á£É5©ÎAáàjQŠ+Ÿÿ£qþo›tùïû8÷í4ÿïW®¾ûùƒÿ]fÿÉÇìáðË9ã%JYSM¡ÔŒ…ÅS­ëÖËcþÏ&éòߟÿ‡óùßvšÿ?zÕwþw™÷H4âE¢P`ö­ìg0 9›’ V]ik‚ãÏ8ÿÀãüï&éòß÷ÿp>ÿÛNýÿøðŸùÿûÌÿG0R œÈµ]%¶¤ÙÍZUZ2±_·þŽú¿Iºü÷ûÿ8÷íÔÿ¿é ·ýìà—YÒÿ·Îp*(Y£‹è1W«píOTBðèµ®|ÿ‡ßÿ7I—ÿ~ÿ¿Ãÿ¹©þ¿ã^÷»ƒÿ]fAýwDRØû 6Û ÆþÄyMÑAŒ–Ù„aåùßfôÿ7IÿsGêÿÜÿ?7ÕÿoùM¯üï2‹îÿq¬ÌÑaQ«Fƒ­| Î%9L¨¹˜uçŽó?¥Ëÿ‘ú?÷ÿaòÿÞð›ó¿÷™Óùoe?= ûÎ9 ¦ ÏÓlô@±Åö&ˆFêñgœ¥þ»ÑÿÛ$=þ¡ïÿáÜÿÉÿ{îcžþöÁÿ.s:ÿΧèß"˜ ‰sÅU[ÔHÛ ´ŸŽ€¶- Ž?ã,üû¶I—ÿ¾ÿ‡sÿ&ÿïOáÍŸüï2 꿜rHÕH$¬k­Ð6èEm«(‹®Ë¿÷n“.ÿ}ÿï|§þOþßÕ/¾û-ƒÿ]fÁüïbäpÊïÁÉ4«R*µú@^[¡®){<Ìë<š³|ÿ‡qþo“tùïûç;õòÿ~õ;¿ôšÁÿ.³àû¡h°pê«­%Ü^\2øÒÑøJ²î÷?7ü¿mÒå¿ïÿõøŸü¿—Ýõ—ïüï2 æÿ+øTQÄ; x8÷KÉæâœÇbÓÿIôñ­ÿ>ÿ“ÇüÿMÒå¿çÿ}Ó§Ÿ÷¦k?ò—^üŒÎßÿº‹/ú .¹äò§¿ì¦W^ôŽÇ½ÿÜ §Y0ÿÇŠõ>«çjÌá¸Úhãá@{øˆPÁuÏÿ Œú¿Iºü÷ûÿ<÷ÿaêÿÿ+þÉEã °Ë,èÿ“°£Èá2®¾04n«ñ%øUýt8öÿ›¤Ë¿ÿÏsÿÿdòÿ>à~üÆÁÿ.³`ÿ¯¡­î±€w€ž5¥Ãä/ÌÙ`ÌÔ~³FyÝý?Œýÿ6éñr¤þÏýß“©þå».½kð¿Ë,øþ[¥gÒ¤%Ø œ¬ùZS­ZXb1ªäpÝùvÜÿ¹Mºü©ÿsÿW&ÿïƒoz× þw™ü+ÙdR°š0p4æÃüoCÉ+Ÿÿ·4æm’ÿ·©ÿþ§úÿÏoÌ× þw™óÿƒË1‡šrÒ‚Þgªâ\ ‘4b„äQ=SXÕÿcCcý¿Iºü©ÿsÿ'ÿï±ÏÉÿ»Ìéüç Œ¹DŠÞHÑ‘ Š«%¤| ¢?ã õ_Ìèÿm’ÿØ÷ÿÌÜÿÇÉÿ»ñÓŸ/ƒÿ]fÁúߟBòmå3ßiÐ┉Új€]­9®;ÿíðÿ6I—ÿ¾ÿgæþ?NþßßßzËÿ»Ìÿ·’ Ú–ûÒçZÅxadÁ!—œ#ÊëÎÿ·ãþŸmÒå¿ïÿ™¹ÿ‹“ÿwóï\ÿƒÿ]ætþ-k[õWW1'˜ˆ¤&®„\e_cUÇë~ÿcõ“tùïûfîÿàäÿ]|çßœüï2§ó_)»­Üތ⽔罝x¸ëºõŸÆùŸmÒå¿ïÿ™¹ÿƒ“ÿ÷„_ú_ƒÿ]fÁú_QM+þ¹&ëáðaeï\Ε* Í5RYwýoÇú›tùïû0÷ÿÍäÿ}òëïýÔà—Yàÿ”bP¬O½º‚ ¨`°‡;€„@W=ÿÂãüß&éòß÷ÿ`îÿ›Éÿûþ7_Éà—Yâÿ::4üɘJ1–D=`æ¿ Ø”BvaåþŸüo’.ÿ}ÿæþ¯™ü¿w½ÿž1ÿkŸYÐÿ7Ñ€ZöQ¢TS(lÍÀc$+àÖÝÿ#Œýÿ&éòß÷ÿ`îÿš©ÿÕ›žuåà—Y2ÿœ+&W+HýaÍ=T$_¨€ 5rˆfÝó¿4îÿÞ&]þûý˜û?fêÿÿü5O}Åà—YÀôÞT5 1QJµ¤JRÚ/Kª…ª‘„ÉÆøgßÿ6I—ÿ#ýÿÿ'ÍÿûŽŸøÛ7þw™Óù‡âÚ6ß`kv^¸ý‰#Δ¨ž*™Š’ÖÿÙVƒÿ-ÒáÿäÈü?˜ù'Íÿ»ï÷î|Îà—YÀªÉ{°lˆ)S¤œÒá¶ ð.@ ‡ó@neþÇüÿmÒå¿_ÿOæõÿ¡ù÷½õoüï2 Öÿ>¤`–ÞR °UÛÚkr"%PL1ÆYÖÿ<æÿl’ÿGæÿÌëÿCóÿ^÷~bð¿Ë,áß‘t1€bùð½ŸR©²f£%¶W@\÷þ/¦ñý“tùïû2óOšÿwõ^ÿ•Áÿ.³dþ?WL©1Ž¢ˆ9C°Ì(±\R.‰Ö­ÿ‚cþï&éòß÷ÿdæÿž<4ÿïîºáòÁÿ.s:ÿγ֨ê‹5ÿÇÞÙÅìvTu¼hk½ðÆ´ !€¢Ä£´³fÖZ³&E¢õ#DRÑ¢R£¤Îš1 5 !ƪ¨HñBŠM¸()%„¤ØszÎ)JAä+&ZáÂÆí‰¦h£F+:»û½Ûóøn;;ÙÉüsš¼çôâ¹8ç÷¬™Y¿Y#€ìÁà¤5^[P=§¬›òoý¸ÿ³Oºü÷ý?^ø¿WÎæÿ½úw?ý-ƒÿCfÍüMZ§IÚj>§"I¬ÖDÎÛRéòßïÿóÂÿ¿r6ÿïû_òÄóÿ‡ÌŠùß&Wfpٲì, Ù‡RÚZ àN oëÿ:üï’ÿ'æÿñÒÿ9›ÿôÂ×þ™óù'‹®¤¬¥ØZ081&›\Pª[CÙcɧ?ãjê¿þß.éò¢þ/ýŸ³ù|ï_¿pðȬ˜ÿé+’#¡CÖE•`\eÀX¼§\Àlûþ·þß>éñbþßÅeý?›ÿwý7¾òÃÿCfÅüorâ´1Š×’±±š¢2Æiús ±}ÔÓŸqü“÷vI—ÿ¾ÿw±SÿgÿïK·|ñ3ƒÿCfÅù¿¨óÙ° @Q¸1É“¶M j*¢)∶}ÿkú£Áÿéòß÷ÿzüÏþß}¿0ø?dVÜÿ«“çgÅùêÕiûåeèyz$Z°}3жý?6£ÿ·Kºü÷ý?»ôÿÏæÿ½åùo¯ƒÿCfÅü_J sˆÉZ¬.ZƒAˆ%‚'8Ùöþ˜±þß%]þûþŸ]úÿgóÿ~ö·Ü4ø?dVôÿ ªzvÕG›ÑD&ŒP¡ìlVUbŽyÛþ?™ÑÿÛ%]þûþŸ]úÿgóÿžxÕS7ø?dVœÿùHê…VùÕD“T4L½€”Úî?%1yã÷¿Æùÿ>éòßïÿÛ¥ÿ{6ÿï¡_zúõƒÿCf…ÿÓvûž¡`¬ÄÅ€ HŒ±ý(1å …Á–xú3®fý?îÿí“.ÿýþ¿]ø¿üØ\ÿë/ß~ëàÿYQÿÑg‚÷"ÞV± I Ä!ºZßôþŸõãüŸtøoT÷ù_ø¿üØ\ÿ_vñÏü2+üÈ1[NR(‘bVž.ý‹+Ó½àöÃtagÛþŽû?û¤Ëÿ‰ú¿äßÏþßûþæ™ÿ‡Ìùü£« ””3H#={+ѪKU˜Õh› ú²ñüÿ±þß'=þ}ßÿ³ ÿýìÿ½ñ¶ç½|ðȬ¸ÿŸIŸÿYÅdL;®Ú²Àæ”$lëÿ¡õ—tùïûváÿ°Ÿý¿ûïydÌÿ9fÎç?Æ’ùVïmšæò q«Øö’²IœNÆUðoqôÿwI—ÿ¾ÿw©SÿgÿïÁo{jÌÿ?fVÌÿMœM±¹úÄ€"‰@[ôGjiÈr5†pãó7æî“.ÿ}ÿïR§þÏþß]?ùäãƒÿCfÅý߉̶×iöW©!:¨ ÕˆFÅÂmßÿ?ÞÿÝ%]þûþ.ü_ö³ÿwÇ¿~ø£ƒÿCfÅù_mýª8®Üôدµ®¤Ê¥fXb%Øxþϸÿ¿Oºü÷ý?\ø¿ìçþÿG>{ýçÿ‡ÌŠú/qcØQ´X­ÛøýÁÿNéòßïÿ›¥ÿïæþÿã?ý­—ÿ‡Ìùü—jÃ1©[Ùç|ûÍ$šj…\*l<ÿgÌÿÜ']þûý³ôÿ/ÏõÿáŸú÷Ûÿ‡Ì ÿ_k1T$´My‘äÛ€ˆ½VRpk ÌʸíýŸöYƒÿ=Òãÿò‰ú¿ô/ÏõŸn~ý˜ÿu̬zÿ'R¡ÆyHÕ¸ÈÁ3Dt!g ‘¤ì¶õ¿-ÿ{¤Ëÿ‰ú¿ôiöÿÞÿÄuü2+æMPsñÆÍlMñࡘRLÒŒU³ñûŸnÌÿÚ%=þ©ïÿ™¥ÿK³ÿ÷Îk_óðàÿY3ÿ7L’Ÿ (Ø6þšbƒ"†Kû6 žfЦó¿¬wcÿ¿Kºü÷ý¿ÿ³ÿ÷sº7þ™þO²Š-¹umÓKvYDÕRmögˆºíùŒóÿ]Òå¿ïÿ™¥ÿO³ÿ÷‚w¾ñ‰Áÿ!³âýÏœÛJ?À4ò+·µ€¶u€©à½p\ª§FpæçÿŽûÿû¤Ëßÿ3Kÿ‡fÿïcõ’qÿ÷˜Yñþ§« ÑÀ9fi«„”RñèmŽT@%±)@OÆÕìÿyœÿí’.ÿ}ÿÏ,ýšý¿÷½íw¾<ø?dVøÐ@IÅ–ä´Øl2‰¦Ð¾Ôç“™æœþŒ«òÆýÿ]Òå¿ëÿÁåNýŸûÿÿòœïºqðȬØÿq1'òžÉ¸bÚnŸ*EÁHÈ%×l7žÿIcþ÷.éòßíÿÃåNýŸûÿ¿vÓ‹ü2+æÿZïÚ¶Ÿ(„êÛàE4: É( ­Q¦Þþ/°^Åù?ó8ÿß%]þ»ý ¥ÿ{a®ÿü‹Ëïü2+öÿ¹8q.—k©NÅ‹·±Õþ²smK`] Û¾ÿÇ~ð¿Kzü_è×ÿÿgóÿ8<8ø?dÎç_%PõN™Ñ”1sÛ ¸˜¹mþƒó%e€´-ÿÖù»¤Ëÿ‰ú¿ôÿaöÿžûÙ;>6ø?dÎçßEòlÍ1ûiè—a‰”§ à³´ý@6íÆïÿù±ÿß%=þ¡ëÿ-ý˜ý¿OýÄc?>ø?dVÜÿõRrk'@÷,Ó õØ–%S4~ãû¿fôÿvI—ÿ®ÿ´ôÿaöÿnyí7½tðȬ™ÿ!"j³Ëµ–éb>„<]¶T9µYÚbÀè¶ýÄQÿwI—ÿ®ÿ´ôálþß‹?÷ÅÁÿ!³ÂÿC6¶’¬&Å¢h¼Sï¨m¿’èôü·ÝvþÏðÿvJ—ÿ®ÿ´ôaöÿ®¹ëŸGÿÿ˜YÑÿ­¸;Œ‘ ÕhªH(6"T“(©8ò’·íÿMÓÆÿ{¤Ë×ÿZú?0ûßûð§ƒÿCfÅüH%{¶ÏNü«Þ%ÇÓ0i¨–é,­„`0þŒ«àÆû_û¤Ëßÿëñ?÷ÿzÛ _?ø?dÎçßWÅâÓ4í;¹ œ“‹ „œ$$Âê …˜OÆUðïÆùÿ>éò¢ÿ¿ôÿ`îÿ?ñÀ7ÿÑàÿYsþÏœªÓê“u*m+`Lö•CŒ¥¦Z£ó¨6}ÿýÿ]Òå¿ßÿ¿°¬ÿWæúÿå+ï½wðȬ˜ÿ9-ÿ¡fœŒËZ!ºjÛâ?x1–B@_¥â¶þ¹QÿwIÿ+ýúaYÿ¯œÍÿ½ï+<ø?dVø?)„VúÁæê¼HNiz 9kÚŠ@Úr€bmý´cþ×.éò߯ÿ°ôyöÿ^úž—ß=ø?dVœÿ¹5Œ¬˜Úú¿¢Ø–ý5Ôà#Mƒ@Ùoûþ7£ÿ·Kzüsßÿƒ¥ÿ˳ÿ÷è-öÜÁÿ!³fþw°ÕQöÆ…h}ÒMÈÈpÉÊFp[þaÜÿÝ']þûþ,ý_žý¿kýµÿ8ø?dÎçߪw±Fgj$£Bd5¬¦*•hcJ%;$ÝÖÿõcþÏ>éòß÷ÿzüÏþß½¿úÖÿü2kÞÿ™j¼‘(à-—ĶZÉ@`#гó?•Zù÷§?ã|þݲþû¿»¤ËÏÿ{ίßù›ïøüã¿pÝwÿ×¥gî¹îûn~MJéæ×=ð†kÞúÌGG÷ÿ¨YáÿÖ\ªèCTGqzŒ*s#‚gÊêu[ÿÏâ8ÿÛ%]þûþ,ýžý¿ð‰O¿x|2+æÿ4ÌU\Qή’ët#HjÖdƒM¦šˆÛ®ÿÛƒÿ=Òå¿ïÿÁÒÿç¹ÿÿ…¯ÞýCƒÿCfEýެlÔcÌh‹D€jœØÐzpmk |ú3þïü[?ÞÿÛ']þûýXú?<÷ÿÿó¿¯ûùÁÿ!³ÊÿCÀÆ‹Þÿ+ >)ŒÎ>ùZ*mìÿ Žù¿»¤Ëÿ‰þÿÒÿ¹8×ÿOþý÷\7ø?dVÜÿóÁ‰ ÊTmŒ6¹aLÆGV‹Ò¾ʶ÷È þwIÿ‹ýúeYÿ/Îõÿ ¯}×[ÿ‡Ì ÿ_Q¼Ö•Â4ý»­ø]A›Õ8J–j漩ÿïp¼ÿ¹Oºü÷ë‡;û_úº»?1ø?dVÌÿœžã#cz¤LÓÀÛª9„ÊšKÛX²Él{ÿíðÿvIÛ÷ÿ®,×ÿvöÿôãOdðȬ8ÿ“˜k̶ý;h¥"[öQ}û*`¨­N'ç#*oûþ‡õãüo—tùïû¼ôÿíìÿÝï»ïü2+êM‘}"õ¾¸lòÔõÓ€lRðsÉfš·}ÿËóà—tùïû¼ôÿíìÿ=}çýß>ø?dV¼ÿ¡í KJ*%“Í’¨•è’«cÛÿ´ÁȦó?§±Âƒÿ=Òå¿?ÿ—þ¯çÿÝþ5ŸùÁÿ!³âþ/Å2 œÿ&a%Q¢,&ÆR¦Àÿ—ÿ»œÿƒÃÿÝ%]þûþ/çÛÙÿûÑ;âèÿ3+îÿ@¶R”¢I9Zòb¤#lÕòܶçÿf¼ÿ³Oºü÷ý?^ú¿vîÿ¿ðš®ü2+櫳Ž$Ç*b‚z%ÈY¦y ‚†K©YSÜvþÙ±ÿß%]þûýÿÿsÿ¿>öû7 þ™çÿX(™éŽ¿²‹Fi´ú”ÐÄœœ°ÆÓŸq5çÿfôÿwI—ÿ~ÿŸ—þÿ¥¹þ¿é‘þ‡Áÿ!³¦þ#U®Ñ¹ÊÁElû}tY}á\rZ]ÚvþѸÿ¿Kzü_:Qÿ—þÏ¥¹þÿÓ§žëÿcfÅù? '1ÓñŸ Õœƒá”Ôi8ÑôTgM±ñz2Wsþgÿ»¤Ëÿ‰ú¿ôpöÿ~åÖGŸ7ø?dVÔ_|¶ÁF}©‰Lʉ22„l±Aݶþ?âà—ôøÇ¾ÿwqYÿqöÿþòÊMü2çó/ŢޥÔEƒÅrÈ«‰ÁV(1{~[þyð¿Oºü÷ý¿‹ú?û·þö»>9ø?dVðß(O€UÚb_\(ÀIë4 P[`Û d íÏNÆÕÔ3ÎÿwI—ÿ¾ÿg—þ/Îþß]?ò*ü2+Þÿ2ÆZ(¾ÚXT‚³d`:(Žbž†$ܶý?pÃÿÛ%]þûþ_ÿÙÿ{øñ§tðȬèÿµâoY ªw6ý{çúÛqÕñƤV‹ÔøÔ MÓxib™µÖÌZ³¨EñA¼Q«-xK£s­M[l©*­—bZ¥ELÀpbU¼¥Ösþið†@Eb½åA!bšjÚ†$’R¤Î/ûÿÔ=?Îο› æ{9ça?äÿÙkf¯Ï¬©!²A!G'¡&€Œ„\×ÿÇ2ü¿MÒå¿ïÿáÜÿ·“ÿwáéïzÅà—¹8ÿ! èRÛpŒf.¢\Ir)‰ \Ûÿç¶I—ÿ¾ÿ‡sÿßNýÿ/ö}þw™þoÛý×ìmfï‚ñ>+k«ú>•XkZ(@)¼nÿŸqÔÿMÒå¿ßÿǹÿo§þÿ­¼÷æÁÿ.³àüê ¸R5'_rÊŠ¦¦êQ}mK«×½ÿö?üo‘.ÿýþ?ÎýßóSýæ¾nÜÿ·Ï,¨ÿŠâ˜J&MIÌs£ÿMTk²ç%iˆÖíÿŒú¿IzüŸ?Rÿçþïù©þ⯮~bð¿Ë,¨ÿ‘¤bvÙ´]€‰%&ñ¹íøÛª %åÃ}´òúßÉðÿ7I—ÿ#õîÿ˜Éÿ»äÊ—ŽùßûÌþ[ÙÏš-©ºb\PRÎZ çD½öƒR‚•ç™qÿç&éñoúþ_ÿÉÿ{¹êþÁÿ.sqþ•,Cƒóp)w{´Âïj.…5¡ ‰2ǰîúxìÿ7I—ÿ¾ÿ‡sÿÏLþßÍ—Ÿlð¿Ë,8ÿƒ¾ýH0>(ÿ¥ýH8›$Añ„¹0B=Œ:þŒ3ðoÆþ›tùïûëÔÿÉÿ{ýòüà—¹8ÿ®ªŠ8#êk9²cLb XRQ¶d5…²îýÆú“tùïûëÔÿÉÿûÈõÿòƒÿ]fÉü"ŽkM ¢‚š1Århüµbv…¸äµÏÿõÿ&éòß÷ÿìÜÿ5“ÿ÷{¿òÑ1ÿsŸYpÿ—)\% Cð9§Lµ’­(É®¢,°®ÿk‡ÿ³Mºü÷ý?;÷ÍÔÿÿ¾?{Ñ ƒÿ]fÉüï|8$²mB"XƒXŸ\.Å@¿òýŸ4æn“.ÿýþ¿û¿fêÿ§?ûKÿ»Ì’û¿bCê©„’˜Š·•“‰ÆA±bÅSR^÷\ÿoÜÿµMºü÷ûÿsþONçÿ}äÖOëà—Y°ÿẇ®­Ò¶û1gG ¬S¨žBvFІÃPÐãÏ8ÿ„ãûß&éðrdþŸùÿ'§óÿnüÀ ?1øßeœÿçàAŒ«ÑUS3Zãú?¢÷Q½Ãz´Ú÷ÿçø7ãþßmÒåÿHýŸùÿ'§óÿÞzõ]¯üï2K¾ÿÛÀ¹ýfªTm¿0ÛÃ@Áh$fã)§d8¦ö‚0ùø3ž?ÿÖÀ˜ÿ»Iºü÷ý¿óú?ùÿûOÿuíà—YÐÿ¯l¬„l®±2)NX©[ÚÒ¿düg¨ÿ £ÿ¿Iºü÷ý¿ÿ“ÿ÷Ù¯yìãƒÿ]fÿ’1ÕhØ·ßÅIñÅEß¶ä9TUrlY?ã,ý3ü¿MÒå¿ïÿï¬ÿ§þÿ—Ýð®?üï2 Îÿ%4‡>¿“€Å!˜ä™™°¦ÿe0AŽ?ãùó2öÿۤ˿ÿofþÿÉéü¿úìÿèà—Y0ÿ‘A@kML)š¤IKuÞHL–C{%¤u¿ÿ# ÿo“tùï÷ÿÍÌÿ?9ÿwÓ§þSÿ»Ì‚ùߊÖE•¶É/ècƒe m- *Ö©'ãlY{ý?øß$=þÌÿ3sÿ÷tþßµòoüï2çß_©UgkÊT¢@®#C‰Ù³‡uù·0îÿÙ$]þÔÿ¹ÿ{:ÿïä OÐà—YÀ¿9È>LNÔv™Cô)5Z«­±”Ì…"¬êÿ[#ƒÿMÒãÿÈü?3÷OçÿûÕ¿|ùà—Yrÿ'gïTMt‚jZÍ÷«É6KuUk@`tµùÓù;üßMÒå¿ïÿõøŸü¿wËï<=øßeÌÿ€¹ýß/9Y*ÊÉ'¨aôžcûƒiÝõ¿Ãáÿl’.ÿ}ÿÏÌýÿÓù/¾ü7ß4øßeø¿A4¥\«÷V…“5Ê>iÄö#APKûcyÝúoÇüßmÒå¿ïÿ™¹ÿs:ÿïž7~âÛÿ»Ì’û? ‰/¬5‰$EãŠóÎEuÕN™³SH%Æ™¾ÿþÿ&éòß÷ÿÌÜÿ9ÿ÷Àeo}÷à—Y°ÿO9¤\¥ýX°6ǶßçH…Ä•Ê9«åø3ÎÂÿ8ÿ·Mºüwý?¾¯Sÿ§þÿuÝqÝà—YÔÿsª”4DÔe$£Ùæ×È ±ýRY÷ü?Ñøþ·Iºüwûÿ|_§þOýÿ×ÿ÷·þw™çÿ}ëÅ̵zecç¶,€”K Š1&oìñgœ…ÿqÿß6éòßíÿ³›ù¿øÀTÿ_y3=3øße.ο¬&W3ƒ“ÕKrÖZ®5&.ëjóÿ§ïÿ£þo“ÿêÅüOõÿ–×>ùSƒÿ]fÁý?.'TS¼O‰X¤¦۲ߕ¢)ç³ÕX×ÿ+nÔÿMÒåÿHýŸùÿ(“ÿ÷ïýÒ»ÿ»Ì‚ú¹­ÿRðN"Ú ^¸¦ŒÛ¾ßR°Ž?ãùó"£þo’ÿÒõÿØÍü”Éÿƒ7½ùCƒÿ]fÁüësQ¢BÈš”þˆªì½å$`]^÷ûò˜ÿ½Iºüwý?v3ÿeòÿM÷ùÁÿ.³àü¿: mÛ(AUtÕˆ·Z³%Ê‘Ñq5®»ÿG3êÿ&éòßõÿØÍü_”ÉÿûŠo¾jœÿÛgøÖ±[BTÊê³"¶­@6 ¹°11¸•ç!Žó?›¤Ë×ÿc7óQ&ÿïÙ7^óØà—YàÿYj}0êR\ç°f¯!–Z|ªm…pügùþ?Îÿn“.ÿ]ÿÝÌÿA™ü¿û^ñøWþw™õCÊÆQÃ3š¶Ù÷- Ŷ(’M±mÖÉ®¼þ÷ÿm“.ÿ}ÿ¯ÇÿÔÿÿÁ_è¡Áÿ.³€ÿ"h48B èK«ü™j$—mBˆŽ³É@ëžÿ#ûÿMÒåÿHÿæÿ¡LýÿWÞó÷· þw™óÿbæ¥$=Ü÷)ÆO©‚¢Í råUçÿó¨ÿ›¤Ë¿ÿa^ÿïêÿ·Ýv×?þw™‹óÚ‚¿z“8zÛÞím²eÍØÖ&J[Dâ•ïÿµƒÿMÒãÿÞ~ý¿0¯ÿ÷NõÿêÇÏóÿûÌÿ¿!™Å¢¦­&áá"–ÂÁU£ ¡Öuçÿ:;úÿ›¤Ë¿þÃÜÿ¥Éÿ»ë“/¿lð¿Ë,Xÿƒ.84ú Z›¢­5ƒ?|h/„Ãd{p?ã,ë÷l’ÿÔ÷ÿ`îÿÒäÿ]ñ#þùÁÿ.³àûe¶Ïd¢ºh’MÅaB(äÄbÈ’sZùüþß&éòß÷ÿ`îÿÒäÿÝýo{ïà—YpþŸ©•ûB!¥¶Ð÷1V ”].VqAŒOÉ­zÿ¯3Öÿ›¤Ëßÿëñ?ù}þ©ßüï2ç¿(ëáì*Éc ÈA8£©„6§Š´²ÿÃÿÝ&]þûþÌýšü¿kí‘4øße¬ÿ[…/–jÔ†q5J­Wc!’Á䃆¬ëžÿEõ“tùïû0÷ÿiòÿî|à£ß=øßeø¿!øÒ^†dj«}!›´-ý9Õ*¾Æ’Œ•ü%Íÿ³³óÿãûÿ6éòß÷ÿà‹ýÿ¾ÿÖ·\zÇ¥/¸õ}/ºfà¿Ï,Yÿ»ä¢¨/ÖñÒ6±jª&¹±–/éû?Íæʘÿ¿IºüQÿÿ²÷ÿÖ¹+Ï]ùñWåÛ?]®ÿì“ðÄg®¿ò–'_vçUïxË¥×]òã·½ýÿfÁü_dn/€d$ç| È&¤½ [ŒUB^×ÿ'ßÿ7I—ÿ#ýÿ¹ÿsßäÿ}ïøŸñØeø?ä4°%FvŽ­$PƒÑøPƒ $•ýºçͨÿÛ¤Çÿ}}ÿïþ¹ÿ{ßäÿ}½ýà;ÿ»ÌÿG\‰®D…sÛô“¥ªáðg°†Ã5@ÇŸqþÿg“tùï×ÿÿnòÿ~ñÇ~úáÁÿ.sqþ¥„¶ôW¢’sP'ÎY¨%ŠÑXl¥•ÏÿÚqÿ×&éñïúþßýóõ¿›ü¿Ë?õô½ƒÿ]fÁ÷ï pRRX*¸†ªóÁ%'ÅçR¬ºöý8úÿ›¤Ëßÿã¹ÿï&ÿïs×ÞñÛƒÿ]fÁü¿’ƒ§D¶-òÙ”ª¥£Ã€F3iôj¢)kŸÿþï6éòß÷ÿxîÿ»Éÿ{ÏewÞ0øße|ÿK¶ε–’sVµà¢u.#±ým¦Ø¶kŸÿëÿMÒå¿ïÿñÜÿu“ÿwÍMýºÁÿ.³àûÅsqKuR«œu™¡ýg-Á£ØdPŽ?ã,ûÿ1ÿs›tùïû<÷Ýäÿ½öòpùà—YpÿO[Áضê¯HC DÁ¨äª5n»Vþþ?îÿÛ&]þûþÏý_7õÿßyã_5øßeìÿ½ Ú+ ý²•C[þÛ(‰Å:ŒQ­§èíºó?ÀŽþß&éòßïÿ÷øŸúÿ/~êö+ÿ»Ì‚ïÿÆ$J…RÄ»”ù0ý§Æš!‹un]ÿ‡dìÿ7I—ÿ~ÿŸçóÿ/LõÿïÇýûÌ‚û¿\ÉH5s¨¨Ä6%crŠªD}ríÚnÝ®<ÿcÌÿß&=þ/©ÿsÿçÂTÿàäüÛÿ»Ìþ}ˆ¢X(„d¥æ˜$%¢„Ð^í/sHëîÿeÌÿß&]þÔÿ¹ÿ“ÿ÷oßÿè˜ÿ½Ï,8ÿŸ•)T-ÇŠàS©”LÒš']„jVöì¨ÿ›¤Ç?ôý¿“yý‡Éÿ{烯{pð¿Ë,Øÿ§IS c$Î6Ï6' ˜«ãªó¿ˆÝ8ÿ³Iºü÷ý¿“NýŸü¿s_øÌþw™óÿ ølƒšT,WW¨’‹*˜¬·9—Öõÿ`øÿÛ¤Ëßÿùÿ “ÿ÷…ozÍMƒÿ]fÁú?rIULÍ!©QUfpkâ9G¨ëÎÿ¶£ÿ¿Mºü÷ý¿ÿ“ÿ÷’‡oûÊÁÿ.³€u†)‹w6u^½!IÉ¥jCÈÜþ6G»öý߃ÿMÒå¿ïÿáÜÿ‡Éÿ{é¹WÏà—Yàÿ[Š.ºì$‰¥”¢“Ú6èÁÇšÊáf jÔ¬ëÿŒùŸ¥ËßÿùÿSÿÿ÷ùñóƒÿ]æâüsth0‘rˆ\“IdH],Š ¹í ÀÇãÏ8KÿøÛ¤Ë¿ÿsÿ¦þÿ#w?sÉà—¹8ÿY´-< æ >úFlŒDXnû‡ë~ÿC†Ñÿß$]þûýœû¿÷OõÿgŸúð›ÿ»Ìÿ$²ñm ¬÷ÀŽœõÛ*àðM “ŒqíŸãÏ8 ÿcþÇ6éñÿ‘ú?÷ïŸê¿>ü·¯üï2 úÞSäPÕ`Иmµ ý«Ö3Gœµ\×íÿã˜ÿ±Mºü©ÿsÿ‡'ÿïsW<ø»ƒÿ]fÁþßA 9ÊèÔF¬VO…ZñX#² èºçÿi|ÿß&=þ¹ïÿõøŸü¿ŸyÍßüÂà—¹8ÿ&†`‚5U€å¹U_¢ x×^ Pêºýàáÿm’.ÿ}ÿçþOþ߇^ø“_;øße–ÌÿNÅUÕR˜.»R+•âG „H‘²÷ëò/f|ÿß$]þûþßÇ:õòÿî¾ÑüÜà—YPÿK8ÜÇÍÈd9­ÄñÿÙ;·˜ß޲7ì )FÔ †HË3ïa1QƒPl ‘‚Á(ÎéE‚Ö´E¡j‹±PŽm°%\@=¤»»_«¥ M I£FSI¨Ø˜m£Òg±¾xÁšöÊוe&™_»/š^¬›ýüßwfžy'¦ÚDW1 VcQÆþÆIê?Žý¿]Òä¿íÿ5êÿìÿýÔ÷>ù݃ÿ.³bþ—öu‰¯1[Ÿ$b –’óV1GíJAeë `ÛûÿÚŒú¿Kšü·ý?Zú¿föÿ.ýÀ¯¿ðßeVÔÿL(R¸ŒÅ) ž3ø€YÐQq>hRì¶÷ÿIõÿ.iòßöÿhéÿšùüÿÏo½ïëƒÿ.³âýŸ`1'(]kä›å^Ø›s] h)‰=n|ÿwÜÿÙ)MþÛçÿ´ôÍ|þÿ¡ÓöùÁ—Y³þr†$Û@&òô˜ 6ˆNÁ—º:ÐF\Þöþ©áÿí’&ÿíóÿÿgæúÿQsåSÿ]æìü“-„9ƒÊ¬’ÉäÙ&ƒ £vlü´ð(›îÿ¥qÿg—´ø?s þ/ýÿ3sý¿ú o¹vðßeVø¿Óéž–hÑy—½Mž´´¢‹¶N¬¿Ž£>ü“ð?üß}Òäÿ@ý_úÿ0ûw|é/üw™çÿƒƒÖ‹$—R,ZÇŒ€1N:@V´mýG‹£þï’ÿÐöÿhéÿÃìÿù·þøuƒÿ.³¢ÿOÎä¬ TÌkóÏÄJòDyðuM€¯ÿõxÿoŸ4ùoû´ô`öÿÞÿ‹ïºrðßeÎΊ.Ù¨œÁ…¤]2vÚÈQûR<† ¬7½ÿ‡ãþßNiòßöÿhéÿÀìÿ}ã¢ßúìà¿Ëœ3'µØÇd¤š©0h\"g¬ûãüŸ4ùoû§õöÿžêãßüw™5ü#‹Î%g]DŠ&͹þ¸1z£]›dÛúÏ8úÿ]Òä¿íÿµøŸý?þ‹kŸ5øï2+æÿù˜t¡úÎNعi8?øŠ÷µþc¦¨#d8üðãýï}Òä¿íÿnôÿóùÿý½äWÿ]fÅû9DaN)Ç8™îÿ§E™´(UáÄMýóÿwJ“ÿöù¿Zúÿ0Ÿÿßõ܇®üw™ûÿÑ8Å:ª"NÀ:ÉI™h X •Äëÿ˜ÿ³Ošü·ÏÿÕÒÿ?šëÿÇ/xÁÛÿ]fÍü_Ï&iJöa) sЉã4¼vm|ÿŸí¸ÿ·KZü¨ÿKÿ÷h®ÿðºOß0øï2+îÿ`ˆÚKɘT!£Ðˆ/*!©bL6•Î~SÿÁÿ—4ù?Pÿ—þ/ÍþßÍô×ïüw™ü'+ŽR’Ú•ËôSàÄ& ŽY ›5»Ä.oûþéQÿwI‹jûjéÿÒìÿ]wÕû~gðßeVÜÿƒà)‰8u™Ÿ2—”\Q\‹] Í‘½×qÛù4üß}Òä¿íÿµøŸý¿Ëî½å5ƒÿ.³¢þCHJGçl©åÞDHYÅè@åÀÞ‘TÙxý¯ÿ»¤ÉÛÿSKÿŸfÿï™ÜüÀà¿Ë¬¸ÿç-S&_8ú„´glª×€q¶xð%šçÿëqþ·Kšü·ý?µôhöÿ>õÉÇÆýß>³fÿ\Ω Á $h”ñ s ŽÅiG„ùð7NÒÿÓØÿÛ%MþÛþŸZú?4û¿ÿ??}÷à¿Ëœÿ’Á{š7ù)Õæß’r1b™þ^°.Y0ë°ñû¿8Öÿû¤ÉÓÿƒÛõ>ÿøm>{ðßeVÜÿÏ”=k“‹1ÊÕå>°6øÚ$ɱ6ÎÄ¿ÿ3æï“&ÿÍó¸½Qÿçóÿß~ÿ}pðßeVÌÿ¶‰ÙPŠÅCvɇ8-²Î•.º„˜¶­ÿ`Fýß%Mþ›çÿÀKÿ÷ô\ÿo¹£Ü9øï2+îÿKH†œI†•L'¤¼ µEAqÑ#¨¤Ó¶ûhÆú—´ø?Ý®ÿ¼ôOÏõÿ÷Güw™÷uŽuÊ4íûÙé @@À:U*½Áã$ü«±ÿ¿Kšü¨ÿKþÕìÿ}û­×¼kðßeÖ¼ÿ—O}r0½TÿF(Aã#³WFÙÖÿÓãý¿}Òâ_5ý?à¥ÿ¯fÿï³ßÿÆŸüw™õßPDpž­Øo33…b}HBœS<ü“ÔÿqÿwŸ4ùoúÀKÿ_Íþß žvÏSÿ]fÅúßRΈEJ(>èât*I2’ò©(ÎL Û¾ÿeq¬ÿwI“ÿ¦ÿ¼ôÕñü¿×Ÿïà¿Ë¬èÿM°TK?‘)}(¤l€hSm tÎNS¦épðð7NÒÿóxÿk—4ùoúÀKÿWÍþß“ž÷ìqþßgÎοe´ÇH1í,д¨]ˆS((­6žÿAãü—4ùoúÀKÿGÍþßË^ýÕüw™³ó¯QEÙ1%)¢‚ÅW¬=MÓÀó¶ëïî“&ÿmÿ—þšÏÿ?qÙËÇýß>³¦ÿ·F|  ¾öAtLýMð³M…#Bz|ïÑ8ÿÿJ“ÿçÿßÊÿÿêŠ7ºáÔ9÷ýí—ß;ðï3+ø÷¡"j<!P‚ ™DEåD(ÖµA¡Çuþ‡Kÿoð¿KšüÿßùÿÎ\xî¹ïûâ¹_ºø½?ñ}é<¸èá3ç=òȽ=|Þ¹w¾å©^xçÑÕóÊÛ½~àßiVÜÿÓÚ !´ŒÅzÅÎN/V*D“J°íü°cþç.iðÔžÿ·.úÿ£ãù¿|ËG/¿]æìüçBº˜€(V *§rÌV²É¢NÛÞÿá1ÿoŸ4ùoûzáÿÏÿûO>ãíƒÿ.³ÆÿW Æg%²s"ÓÀ¯LX{Fp1—àÈo[ÿk0øß#-þÛóÿ@/üߣãù¿úÝ7žüw™5ï§©Ýgq¼'U{}¥bȆ´`@ŽB&o|ÿÏŽû»¤ÉÛÿÓ ÿ÷èxþß=ßöÚÿüw™ï‘Äâ’V!ûX8ו/".h§·ÀfëËÆþßxÿ{Ÿ4ùoûzáÿÏÿ»ë…¯åà¿Ë¬¸ÿO™‹72龊lÞ{¤ɫ⬳¤è"xø'©ÿãýß}Òä¿íÿµøŸý¿W|îÁïüw™ûÿ”¦³ÿRÛ€+ûä‹’2g£U,ªDIŽÂ¶ëcÿ»¤ÉÛÿÓ ÿÿèxþßÃÿu½üw™ïbˆ!ºB¦°Ë2ª`&ï?éD¤2[¿ÿ5öÿwI“ÿ¶ÿ§þÿÑñü¿óïþÁŸüw™þ?x°*F¥\ÈÉéè|LÁq̬œTô™£ÚvþÁ¨ÿ»¤Éûü_/üÿ£ãùúó¯ûÁ—Yáÿ‹U 8èÚp)Á©ºäOÓüÿ ¦ß‚­–²ñüoæ1ÿc—4ù?pþ¿ôŽçÿ=å+ßñ´Á—Yóþ·K’øï2+ê¿ÎQ¹’!ú$˜£ïX¬dBúæp˜f„mçÿšáÿì“ÿæÿµøŸý¿?¼öÓŸüw™ïÿ‘Îÿu¥>˜ä0F¼×9CbÉ)gÇl1¹Ãß8Ñþ߸ÿ³Kšü·ý?³ôÿçÿýäËî¾fðßeVø? ,'ƒ!ÖVŒ2>M‚Ñd­ãôIÂëþãýŸÁÿ.iòßöÿÌÒÿ?žÿ÷¼ð…1ÿ¿Ï¬¸ÿ£m¥5* dkº”8âœëÿ,YS°a[þÁÿw—4ùoûféÿÏÿ»ön¸dðßeVøì‚.Óc߉­HçmmùEÇA ×_ÜvýOjø?»¤ÉÛÿ3Kÿ÷xþ߇ߌãü¯Ï¬xÿ×ÙºÚLÆm@b*ÞG )3nëÿù¿;¥ÉÛÿ3Kÿ÷xþß}þ¥ß9øï2kÞÿ¶ ‰Æ’Õ¢ïBœîý³J”½äaÛþ¿þÇà4ùoŸÿ›¥ÿ«æóÿ=ëâ þ»Ìÿ?&…%QTQÍÆçµ7Þ‰’˜bTIhÛûÿ8êÿ>iòß>ÿ7 ÿ‡þd®ÿ7]zɹƒÿ.svþ Gqš(Ò¹(kÙPÒ©›(’* A̶÷ÿ†ÿ·SüWªWó?×ÿ/>á=ïüw™õ?R©?¦H6gB‰XË¿)J+'Úi Ñn|þÏÃÿÙ%MþÔÿ…ÿCvöÿ~æÑüÐà¿Ë¬8ÿ ´Fˆ¨UÑĤ½Ž6eC윭rØ”°0ÎÿvI‹ÛöÿÎ,ë¿ý¿‡.ësÿ]fÅþi‡Š“&o°èl±x§¸Ä¬HÀA@ŧ­ßÿýÿ.iòßöÿÎ4êÿìÿ=ýUñà¿Ë¬yÿ;;âä…ŠL@‹5.Q)Ñg#J§œóãšÿ±xÿÇêÑÿï’&ÿmÿ¾Õÿ}âuóû?ïøÐ9w üûÌŠõ& % ÁÖE*A©'£õÅP,*%“ÝãêÿïÿððöI“ÿ…ÿwêºóÏ¿ñs/Ê×ÿSyñ??ø|ýÅO¿âÁgÜôÌ+ßtê÷ÎùÍq¯øwšëë…S©­¿·J‰òVkõ÷$pmÕM¶[Ïÿûû¤ÉÛÿƒ…ÿKvöÿ>ó‘ÿ¼qüt™çjzï/†4™¿&gfF6Š)r (>ÇD©È¶þùßû¤ÉÛÿkñ?Ÿÿ?ÿîÒÁ—9;ÿÓ…£)x©]yÄĦˆ©˜:+!CJž ŒòÛîÿ«Áÿiòß>ÿ‡…ÿOv>ÿõwýÍ×ÿ]fÅý_›½òèœ Š®ÈOO€YFòmŽF¨Ä˜aÛ÷?hÌÿØ'MþÛçÿ°ðÿé¶¹þßsÙË¿:øï2+öÿh4Xû|ˆ![{OÅk%E¥¢ÄiÞöþòØÿÛ%-þo;Pÿþ?Ý6×ÿ}Ò«Þ<øï2+öÿ2;± ‚V¤ÅåZþ£&*sHdECÊÞ›mý?´Ãÿß%MþÔÿ¥ÿƒ³ÿwÁý?òÀà¿Ë¬˜ÿm Ø(Œegƒñ#Š %Ú’ 6‰?ü“ôÿjôÿ»¤Å?¶ý?Xú?8ûüÆÏ|dðßeVøì‹1øÀ89H˜j€Öo‚rQç ÊÖ÷ÿÆúŸ4ùoûGú?ûO~>½hðßeVøªÂ/9fí1pI^rr(Û@l‚UÆ‚Þvÿíxÿg—4ùoûGú?Ïÿ»ê÷áÁ—Y1ÿ?ƒ@Þ£¢Ø¯³·>[[ŒUE—ÃÆóÿÇþß.iòßžÿG‹ù¿„óü¿¾ó+/üw™û±öøµ÷WÅLÆO*ÞsV.A]8‡B¬«õ­ïÿÒðvI“ÿ¶ÿ×âöÿ®ùÑǾ0øï2gç?È.åÈN¦À\A¦äl´ÆPÐ&«ãáoœ¨þýÿ]Òä¿íÿÑbþ7á|þÿóW½fÌÿê3+æÿV¾m©õ>è©Ô:ú¤ (®KC¾.ÿÕ¦þÔ¿nƒÿ=Òä¿}þOKÿçóÿ~ǽsðßeVœÿí|í÷+ö94­‚ØœÐÖ¶ ×>˶ûÿ0æí“&ÿíóZú¿·Ïõÿ’·í×ÿ]æìüc(ÎÛÄ%1göŽDG4ÎLï{‡&€RaÛþŸÔxÿg—´ø¿ý@ý_ú¿·Ïõ~ìË¿0øï2+îÿ¹  »˜tLÙÖ²O’Ooÿ•´§„ãüÛqÿoŸ4ù?Pÿ—þ/ÏþßÍŸúÝ+ÿ]fÅû¿98"Æ)Ÿ²Ó¤]HΪàC*IamÄZ·±ÿÃÿÙ%-þ¹íÿÑÒÿáÙÿ»ü9/½iðßeVìÿEÔÓ`Ĩ¬¼böµ EçÈš"‡ßÿþï>iòßöÿZüÏþß ×¥×þ»ÌŠõ?«XÉÔ®Òim]™ÏŽÑÔ`jþÙ*2zSÿþ—½sÙìªêø3vz!R›´ „jŒ+º÷Úkíµ·¡ÑV‘@hƒ~P1\û†MÁ*¡š’Ó‰ÊM¹$È¥4Mšªˆ™f¦¢Á+|@R/Sƒi¥XZÚ¡¦~(ÔD0^öáøÅ9ûéÞ99r’ýŸLò¼ï|8æùµÖ^ÿ½éÞÿ[EMþÛþ?œúÿhôÿ=ôá›Îtþ7©só_jn/` -h)¬\rìcäuNª¾œ&»°ÿ_÷óÿUÔä¿íÿ;Úˆÿ£ÿï…Ÿ¿æ³ÿMjFþ/ÃîïdU&Î>XT“Xë"GV1I±~áüzý¿Žšü·ýGñôÿ]yâÌíÿMêÜüz'T³ÿ”µ NŠã @a ‰uBÏÌŽ—õÿkèñ5ùoûÿÔÔÿKcÿÿŸn¾ýh瓚qþ_³ûZßÚbc à]ÉZ9V6+JÂ)x }ÿÇ&Õä¿ÝÿWSÿ/ýÿ?üñwêüoR3òÿн‹úY¼2!X"‘áZ0OÀõ ÒþgÄÿ£»ÿg5ùo÷ÿÕÔÿ{lŒÿŸ Çþ»ó¿I͸ÿ(‰ZTÖ9ú 4ÜþµÑÍ,Ú%%¤ÆýÏ8ÿÔ笣ÿÇöÄÿÿcüô}Wÿ]瓚qÿ?I4#AúVŠó•åB)µJ@u‚X–ÍÿûüUÔäOüŸúÿõèÿ{}þ‰¿éüoR3æÿg( ¥Ô ïƒËH.i–`”„"¦–þµÓ~Ùó2}þÿ*jñ¯Ûþ?5õÿëÑÿ÷3ǾåÁÎÿ&5ÇÿkœS>»l=ª˜˜²7|/J}˜úPŠ`ÿ3À¿êõÿ:jòßöÿ©©ÿ_þ¿{Þ~÷‰Îÿ&5gþ¥-’ ÑBöä´ ]t.¥¡%ˆÖÁ²þÕçÿ­£&ÿmÿŸšúôèÿûàÛî}w瓚áÿu5¸£É¥ÂE*I+DUuJýµè¢ù¼øŸìÿÛý¿«¨ÉËÿwâ¥ðÒ/¿ô©§îûâ—.ý¦¾þ›¯{ËGOÜúׇâÿíÕþjFÿ/'då4›X2Y'¹Ô_ØúµH^ÏÑyLËÖÿÆôø¿Ššü7ýx²ÿGÿßµßû¢›û`“š±ÿ¯X@NÞjex˜ê#yg ¸DJÌj¨ÿ•ìÆ×Î?0ôú5ùoúÿðäÔÿ«Çþÿï>û‰çtþ7©ý¿Hç‚X,ªTˆ¼ö€^Üpï?Gæ\ ËÎÿëó¿×R“ÿfÿ¿ÉÿØÿ¿ï®¿¡ó¿IÍéÿëØëâƒ'‘Zùçç,èÄ'ãKÐbʲù¿íþŸuÔä¿ÙÿGšúÿOñÿÏoù¾k;ÿ›ÔŒùÿÃzO®Å~06ƒ­É¿ç ÜpFç  29jÔKßÿéó?ÖQ‹ÿSíøOSÿÿ©1þ¿í×|c瓚áÿ ”kFnX„õF˜kö§‡Ë€"lJÊËÎÿèùÿ*jò¿'þOý¿vôÿ]{ëË~­ó¿IÍØÿéâÐãK •®ÌÖ1êZÄúcNL) {€Í²÷úüÏUÔâß6ýHSÿ¯ý÷ú¿ýÏÎÿ&5Ãÿ'F£ÓNCM̽e§%ªUrƒ6…sÍ–Ýÿªó¿Ššü7ýHSÿ¯ý·Þø±~ÿo›š1ÿ;%ÅŨT!/J×·€6+¯T¡ øLDÖ.{ÿúþŸuÔä¿éÿCšúíèÿ{êeÇ®ïüoR3òE%dÒœ ÕP/¦&ãp 0“ЬI ÷?ãkçUŸÿ¿Žšü7çÿ5ùçÿ¹ã‚Ë;ÿ›ÔŒýŸQ‹EB¯l ÌžlmÑØìÁøÄÉ–eã¿îþßuÔä¿íÿ£©ÿÏŽþ¿ú/?ÙùߤfÌÿK±H±ÅrÉ*ƒ'>J–CñH pÑý_h ßÿ]EMþÛþ?šúìØÿÿðn¼£ó¿IÍ8ÿ‹Ti$›è½’˜tމ¢Äš¸RtbE~Ùý?Ôýë¨É»ÿ¬ÿÇþÿ¿åèüoR3öÿ‚KŠ]Š^‚ϳ‹„ÌÄ6¥¨ŒIQøýÏ8ÿØù_EMþÛýÿcÓøüýO`¿ÿ¿MÍðÿ¡”K°š@3@4Ï9‹ÉE‘)œLäeù¯Ÿ:ÿk¨Åÿñvü×Sÿïñ1þ?ù†GnéüoR3ú–“S8˜~Ñ%]ŠÁ¤MJ ¢‹±æ¢â@ñþg€ÿZtþ×P“ÿvü×Sÿ/Œþ¿Ÿ}ã¯÷ ÛÔŒùÙÖ´ÅVþMÔ9ÔjÀg©?1–Èd¼áBé¼Îÿ±ÏÿûR‹hûÿôÙþß‹^ú 7~÷áÝñ+^ûöŽÿ65cþ×°ŒÇA¢ì¬M‘4zñQ{ãê¿€gŒÎçåÿÌÿQÝÿ³Žšüÿ_ÿßîâËÞû¾ËÞûžOz×cùª/<~÷£g®ºìu_qÅï¼î†ÃùÐO}çÇëøoT3æÿ×ô‡¡_ÀɦlSɹ±Ò™‘#"”¥ïÿÕûÿ«¨ÉÛÿ§§þ_ýo¾é’ö7À&5£ÿo1€÷* Ä€D±Îtä\(8,eY–„>ÿk5ùoûÿZüþ¿[n»ãÆÎÿ&5cþ—.l‚ ÖÅ@ÅaTƒHTò õSQA-Ë?éîÿ]EMþÛþ?=õÿÂèÿË÷¹ªó¿IÍ8ÿ÷‚(qÎʈÔÔ\òðGWR"ÇÆª²¨ÿÏ÷ü5ùoûÿôÔÿcÿÿô§>yºó¿I͸ÿ锜DG "ºdQJÍÐ.•ý0,ÿónÙùŸ}ÿßZjò¿§ÿ?õÿÀØÿ¿û‰OÄÎÿ&5Ãÿ[s_´ø µGãcÂਈìê«Á”€ .íÿëû¿WQ“ÿvÿÿÔ4þŸãÿóÿãÏwþ7©÷ÿtІ°O±fûÆd«Ø…$¬ÿˆœÍùõÿ§÷{ý¿ŽZüŸhÇÿSÓøbŒÿ¿üù—tþ7©óUaö]N)([¬vä‹`Η¬ÏÞ*äeçíþ¿UÔä¿ÿíÔÿ‹£ÿ/üØû_Úùߤfìÿ!íµÒ!!ÎQóþ YcúZ“ü²ù¿Q=ÿ_E-þ±íÿ³Sÿ/ŽóÿþõñçA瓚1ÿW#ƒd“¹D“\$U#¾2¹8Ú—õÿ#öü5ùoÏÿkñ?Îÿ{拯þ¯Îÿ&5ƒÿaÒWN”ÅXÀàEé(–ŠÃ žÅ(€(¢žÿÛ÷¯£&ÿmÿŸÎÿÆÑÿ÷í?ú“ÿÜùߤføÿj„‡’5eSÌA0ÕªŸÉ¬× 9g—ÿo ÷ÿVQ“ÿ¶ÿÏNçãèÿ{ðnzA瓚3ÿ#òþlDSK~ jUlRFÜÂþŸ^ÿ¯£&ÿmÿŸúqôÿ½úȳtþ7©þ?W3KÑça¸‡RÈ k}±%g¼Â¸ôù÷ÿ¯¢&ÿmÿŸúqìÿ¿ÕýÉMÿMêÜü{¦H±„b(xFª¹@ ‘c©_ŽP”Ó^BN ïÿµ¶ÇÿUÔä¿Ýÿ·SÿŽýÿ»üß÷ùÿÛÔŒû?®XçÑ%Hâ³§)ˆ ¯¬ÆÌ–ÿ‰Üù_EMþ÷ôÿ§þŸ£cüÿÀ÷¿ëÊÎÿ&5£þW5úSÊ*@ûõU`UPÊDGb–äb2aáú¿çÿë¨ÅÿÑ=ñ¿Áÿÿ?òéËžÕùߤfÌÿD_ŒÅŒV+*ú˜“76d•]Ñ Ký­Y6þCÏÿ×Q“ÿvü?>ÍÿÕèÿ»à¹¹ÏÿÞ¦fÜÿË”[ƒ™9rV9QñŠ(ÕW‚{‹Ëžÿ™>ÿoµøWmÿßñiüW£ÿï­w=vg瓚áÿ×–“×ÚSŠ\œÑÅ:U"Ö¸òPP­SYxþõûÿ«¨ÉÛÿSÿ¿ý¿”>ø–Îÿ&5#ÿ7Ú5&Ÿ\Q^Ì!²E¶Â͖ΫþŸÌÿ„ÿ×Q“ÿ–ÿïÐ;Ž]|ù]·Üñ¾r׿|ñ›^ùÇo:ò]¯|à‡Ýþáw^ÝéߨfÌÿäŠwáÎ`r)ÇaØùÁE‚ žmNËÎÿ°Øù_EMþÛþ?˜úÕèÿ»óò{_ÕߛԌùÿšY—4¸|)&æÀ’/Š‹äÓ%ز¬ÿ¸Ïÿ^EMþÛþ?˜úÕèÿûÓ—Üø¼Îÿ&5£þO ÅåZ]”2l6¸h²“¨¼÷Q»…ý?ºûÿWQ“ÿ¶ÿ¯ÅÿØÿÿé3/¹¯ó¿IÍØÿák†¨Ùë҉$E:i-è-×ïˆÙÿŒƒÄÿîÿ_GMþÛý˜úÿÕØÿÿ?¸ý™ÿMjFý_ã»ÑQf`Q-Py”$ºxÔ’Î+ÿŸìÿèùÿ*jòßîÿÃÙþÿ“Ãø¿ß?²{ígn»òiÆ¿t}kÎüoÒ®fýʪÄTiÃÀªŸ¬U>™Á¤Ì¼ÿ8ÿWÔý«hÊÿÑ=ãÿàlûÏÉ>uâÂÝu×?çžæ¿ëëY3øÉJŠÚY+ $GNY*Ê9H…Báúá¼úÿþ ôù«¨Åÿžð¶ýç$ž©üïv×½çÉOtþ7ªól)Y GÉ6HTà!'çS@ô.¯mÉA¥E÷¢îçë¨Áÿžñ'&ñ9} Ÿ±û¶?zÅ‹;ÿÕŒù?Yk ÒÊ£Œ•=‰¨/¡hRŠ…Œáó:ÿŸÄÝ÷ÿ¬£ÿmû߉iü´òxwém?òÎÎÿF5ãüÙ­_ ÉÇ!pÆŸMýà­°›õ²õ?vÿß:jñßÿ‡gÛOâç*ÿí¾ã-¿üÿj†ÿ·&þõ 0ôÿX‡`åˆAsÚt%;…ìø¼öLëÕëÿUÔâ¿mÿóÇÿžÄÇ*ÿ‡v|ë¿<ÔùߨæôÿEŽ$Н¡ž%')B¾XŸu4Å{®x/Ë?sŸÿ½ŠZü·íx¶ý÷$>\ù?²»ùåG~»ó¿Q͘ÿQbfœ²ïÀHJ'[¹/6i]ë[ÙÝÿŒÕÿýüoµøoÛÿü¾òÁîŽ[î³ÿjÆù2(1¥‹×T¼‰±}-hïÛŠó^€èû?ÖQ‹ÿvÿ϶ÿžÄ‡*ÿî>õgß-ÿjÆýŸÂCxO)æ,k"ŒŒF«ÌIv(H‚eÙû¿¦ïÿ\G-þÛý<Ûþ{òèÿw»W_r磚1ÿ3¢“¡Â‰†“ ª¤’¢! YKäP_ ÎȲüc¿ÿ»Žüïÿ‡ûïÑÿ^¸»Ÿï¿¦ó¿Q›ÿb”V*Ž?&ÊÊ&#ƒЫˆ‘¡Xwaáúºÿwµøßÿ'þu¦ò_ÿ{áÎuþ7ªYõ¿"°¥C5ù¯Ÿ].ÎçЭ•xV_Åv¯À}Jç 5øß3þïè”ÿGNŸRÏØÇk¥ó¿Q͈ÿVX Õ Ÿx#YêWBµ¨ã°˜*ºzáüŸL?ÿ_E-þÛþ¿£ÿŸz´òx÷‘g½ê÷:ÿÕ¹ùO:d Ä¢RQ’˜%ÅèÅ0yKd”¢àžæèø·}þç:jñßöÿ©‰ÿO}®òÑî»×üG磚ãÿCå#rªEÑâ±&$S*Ä,ë/r}5,Ë?öþÿ:jñßöÿ©‰ÿO=Vù?´{Ñž| ó¿Q›,1¬mJè ³µ5Ú3X¡Pt"lõÂómïÿ­¢ÿmÿŸšøÔÕÿ#»û>óÜuþ7ªþ?JNC(Ñ{À]ö2›úKæ8iRËúêOÿ5Ôâ¿íÿSÿOý{J]°;}f÷«ÿjÆþ?À+†*ýIÔ°0xŸ¥æ€6‚ Ÿÿkìü¯¢ÿíþ¿šøÔC•ÿ wõ¡ß|A磚Ñÿ A”…ˆâ’*É$ˆ\Ó«5ë ÓÂýìý¿UÔâ¿ÝÿW“õ÷ ñ·{óáwaç£:7ÿ\€k K’L!Äh­XÏÌ0CÂþgäüOuÿß*jÌÿ¼gOüŸ¬ÿ»ç¡Óöž w^ÿ[±ó¿Q͈ÿ‘\¡€Š¢3¹fE£õ¾€O"dÈh[Š‹Îÿªü÷ø¿ŠZü7ã¿:9‰ÿ|¦ò¿Û½õèk~°ó¿QÍàŸkæ_‚›Ð¢²IlÎäkéR- LŽF…ú"ØÿŒƒøºÿwý{çêÙuÕñ}ïÜ™Ñ1!B›Æ[ˆ‚©Veïµö^{o ø—¨uÚŠ¨¡&"û¯RPRI,±}Q[‹1¨ ±¢Bš<43™;­ „*Á‡Ò§«(MÄÎÌ;CµEIŠÚV×ÉcÎþÍ~s8ôÀþÎÀ½3w†óòûœµÖ^ß½VƒÛôÿÉýQü·‡dOŠ?˜Ž:ÿ+Õ„þŸ)%éTu´ÕË„¡–!ý·Ò"RÎ*ûè½*nó3¶ñÿ@ïÿ-¢ÿMÿŸ4£õ¿öˆù?&>ò›7ÿk祚pþo9ý7– ZŒ¾ ý>—\¬J•-uØ 4¯ÿÇÈîÿ[D-þ›þ?iÞèÿ1ö"ó\|å=ïîõÿZ5aÿOô9¾>ñ[r`Á´EúÈDë¨j  Ú4oÿß`¯ÿQ‹ÿ¦ÿOšÑú_{…ùß/ˆ»?Õù_©&ø)‡Ã˜O¥šaûg®.YïKј•ô‰Pâ5`Ý‚ÐÝÿ»ˆZü7ýÒŒÖÚKÌÿ ñÜãwa祚pþg*êaÂwÁP’¶DW•Á¬}4Å »@ÐÏ|þ×ù_F-þ›þ?iFë?íeæW|î¥ÿ8Õù_©&øIšŒAÇ  ™B¾8ŒñT@B_5Ù2oþÏíü/¡ÿÍþ¿4oœÿcìæO<}ôô~祚²ÿÓŘ+Xd@)çµK&*O’'þA® BØüŒmòÕçÿ/¢ÿíþ¿õÿŸâ¿?ý_¸¹ó¿R]Ÿ”J*—¨mQm±ž’Q£&€`Hj^ÿöù¿Ë¨Áÿ³âÿ¨ÿÿ,Çÿg÷Ä|áÄÇ;ÿ+Õ„óÿ$3 Í9WŸ=ؙ듳“Ãß*.ëX˜—~tþ—P‹ÿvü?3Šÿx•ùâw=t¼ó¿RMðÿS)–“~Ì*øÂá߀Ãè [C‚ZW@Åy÷kKÿ%ÔàÛþ¿3£ø‡„'Å#ÿýð—:ÿ+Õ„ó?.ö!¤$9ð—ìLJ93›tÑÖ»« >ºy÷Ë^ÿ/£ÿmÿŸùÿðˆù?&îø¿·\éü¯Tö”,écÎÑ“•S"~/øa ¬¥’ŽóÞÿ1}þÿ2jñßöÿ©‘ÿ/2ÿÇÅ»þþ—ß×ù_©&Ìÿ-:ÕbtuP³Sè«•ªdUAUU¤l%Î|ÿ×tþQ‹ÿ¶ÿOüx…ùßñ~µŸÿ­Uöÿ(”ž³}—(ø×g+­°(ª¢k Öj?ïü?Ùãÿ2jñßöÿ©‘ÿ/1ÿ'ÄÛÞ~ç·wþWª ÷ÿr6ÑHé’32HP>xÎ$™uN1—š0мý#{ÿoµøoûÿÔÈÿ‡—™ÿ]Qïù/Ùù_©&œÿ¹jK,‘=¿"b9CÊÊ$K‘QÏìÿéó—Q‹ÿvÿ_üxùß7ßÿÌcÿ•jÂýßì(IEÌ©LΦ µCíòð[¿¢Wü5>ÛäÿÔïÿ.¢ÿíþÿ˜ÿý!þ ñ/߸©ó¿RMˆÿÁkP9j4*S’ÕJôÚ“ÔÎx¨A[gçíÿóèü/¡ÿûâÿÈÿ³ÏñOÜþáøçÿ•j‚ÿÇi†<‘Ê5†œ “o*Ÿˆƒ>WFyë¹(ØüŒmòÛïÿ/¢ÿâÿÈÿc®2ÿBÜþÉÇ>Úù_©&Äæ’?¨¸ÔG4 $¿tÍȯ­•ÅÇTTÝüŒ-øÇ>ÿ{5ø7mÿßùQü7‡dNŠ·ÝvGŸÿ³VMˆÿšjI…¨$-ƒ‘:8Jä¹øW¦†£Œ2q5°ùÛœÿ÷ù˨ÅÛÿw~ÿ˜ÿcâ»ð®OwþWª ücŽF%)D5åHUªVz#ª:XIJù[åÿÝÿ»ˆZü·ý4òÿš‹ÌÿqñÎï½¥Ïÿ]«®Ï¿Ç ¥ö.UÑÉZ”÷Éy…®Xéèä4Åke€Ûðßûÿ˨ÅÛÿG#ÿ¯¹Âüïˆþñ:ÿ+Õ„ùÖ8RLpx’ÑUäD@ûL©‚Œ.«™ûª÷ÿQ‹ÿ¶ÿFþ_s‰ù?!yíC}þÏZ5)ÿw®Z¥ª6FVÊ¥h=ÜûMÚ©Rr\@™·ÿ7Ìéü/ ÿmÿü¿æ2ó¿+~÷…:ÿ+Õÿ/i`â½)µDL™i.ü©°É[oœË©^ÀÍÏØ‚E}þç"jñßîÿÓÈÿk.0ÿ{â~¹Ïÿ]«&Üÿ“ìÙ¤ ]JQ•” ‚²$Á9´V[ëæåŸ?qÿ%Ôâ¿Ýÿ§‘ÿïÌÿ…¸ÿáïªÿ•jÿ s  Š6Ï»ÿ‹ÿÔù_B þÏlˆÿ£þÿŽÿgöÄWÿú§ÞÔù_©¦ìÿ0œè'Y¼OèµEí(ÛRñ:«äÉ{HV™ÍÏØæüzý¿ˆZüoˆÿ£þ¿ºÊü ñÕ‡>¹Ûù_©&œÿ©lUR•t}(*']CT¼É\©§ê¨ÌÌ?õþß2jð¯Úþ¿³£ø¯HÏ=ñ#}þÏZ5eþ¯«ÞÇ]F«< S¿‚"ò0ôþ˜þBÁ{;ïþèó?—Q‹ÿ¶ÿïì8þ1ÿÇÄgÿêÎG;ÿ+Õ„ý_.¤ ¥/ Œ*x•¢‰)çm!ˆÞI óÆÝçÿ,£ÿmÿŒüê"ó\<ú©7÷ù¿kÕ„û?˜IÊÄ…¿ŒþÃeã-Õ˜“sÑh3¬¢2ïü¿¾ÿk!µøoûÿ`äÿSW˜ÿqþðÕÎÿJ5áü_ƒôÖFgkM&¹’‹¬\Ÿ3þA:²œäTý¼þczý¿ˆZü·ý0òÿ©KÌÿ ñ⃥ÏÿY«¦äÿˆÒ(‰ )`äR?§¨ÁæŠÊ!1´ ¼Ì³Îÿk{ÿµøoûÿ`äÿS—™ÿ]ñÒÏ<|o祚pþÓû¢Š *ó/Mœ hcu.ÁUéLÈÞ%?oÿ_ËÎÿ"jñßîÿÃÈÿ§.0ÿ{âó{/÷ù¿kÕ„ý® Ë>¹Ì‡2¬DÉr€!:©5Åh½LóîÿPÐù_D-þÛýùÿÎñ_ˆƒÛ~åcÿ•jÊü_7\¨5p˜/ÅB­É×âƒGÊÙ€ÌFg™æÿE}ÿç2jð~CüóÏñÿüžxùýÿö`祚ÿsÂ#À0è7dJÕð­"Ÿ+ÖÄñ:^Ö­Îÿúùÿ"jñ¿!þü?t•ùâößx²Ÿÿ­Uü?EºÐ8†^S@ƒ”.Ÿ¼vsh‚3´ù[ð}þ×2jðOmÿŒü?tx@tRœþ›§~©ó¿R]Ÿ¦CVdxJ ¤sÆäl)&hU%ðW7óüÝýÿ˨ÅÛÿwnÿ˜ÿcâ'üÎ/vþWª)þ†n¿)Ù$Ÿ•I)ÉУM*cõhç=ÿïóÿR‹ÿ¶ÿïÜ8þ_dþ‹w¼ûçûýßµjÊþïªRˆÁf´TM‘2D¨¶ú(cˆ\üó›Á‘™õü_Ë>ÿgµøoûÿôÈÿKW˜ÿ±ñù§:ÿ+ÕÿMR[¯•rEiM)¡æOFÉÞ‹AÁÆYïÿpøïü/¢ÿmÿŸùéóB|þÁ¨ó¿R]ŸÿLÖâÐü.2£™­+±†R³O±æa °.rÞûÔóÿeÔâ¿íÿÓ#ÿ/]fþwÅ÷<ñÞ[:ÿ+Õ”ýŸ ‹‹–3ý sbúù  S• “@ÑñOUšuþ—–Øû‹¨Å»ÿ¯Gþ_ºÀü}ò–g:ÿ+Õõù`¼ÍÅå£0\Í+¦¢Ì6$—Q:/¨4÷ù_¿ÿ¿ˆZü·ûÿzäÿ=;Ä!èNýmÿ•êúüc Û?çÿXj,u Y§*Éj=xsCñ_úÿýþï2jð¶ÿw~áÌ©·>ù;_<õÁoÜÿõ¯Ÿúƒû>{÷[î{ñî?÷þЫÒé_­&ìÿÈ9”ᢟ-^y“Á.üS)”%Wþ1Rä±ùÛÔÿÝÿ³ŒZüoˆÿ£þ?\= ³Bœ}Çï?Ðß+Õõù—º’õ>K`j 9… uåÝg"ãA“1Ú¦ÍÏØ‚~Xç 5ø‡¶ÿOúÿpx@pR]úØùÎÿJ5áüß !W™Ïªr6墠TªËVVLå`ó3¶à¿ßÿ]H-þÛþ¿gÆñÿˆù?&Ž^ûŽÃÎÿJ5ÿŒ£7F$ ÑGôÚ[É5@ȤB§K5qó3¶©ÿUŸÿ¿ˆZü·ü;gã­ð®WÎÞúµ¯ýã˯ÜzÓß~àÑÓŸ9÷èé?þ»Ÿ»¯Ó¿ZM8ÿ粸h! ›¿ƒrN•bl©²JéÑZ¥˜æyëìñµøoûÿäÈÿW8þïˆ7½ÿÉ~¸VMØÿaœMŠâ°æ—1çH†qÀ2„\|‘˜µWPÃÌù÷ÿ-£ÿmÿŸùÿàóB<ðÚ—nêü¯TSæÿjpÙÔaü¿¥T£rÕ©˜¥Î†ÿ„rLvÞû¿{þ¿ˆZü·ýräÿƒËÌÿ®ø½Û~ÑtþWªëóïe´…ÙNûMTHšBfŸÀsñ¯e ™lœwþ¯¤Þÿ[D-þÛþ?9òÿÁæOüç÷¿¹ÏÿZ«&ÜÿC¬ FFš’áê H£¼ÊäÓ° ô¼÷ÿU¿ÿ¿ŒZü·ûÿräÿ;7Ä!ž8uõÃÿ•jÂý¿P3röŸ9ë—­D< }Rˆç>qG祚pþ‡!F‚Ö¬uª*—|ò•ßTrtüãyçÿb¯ÿ—Q‹ÿ–ÿï¼ÞÇÿ#æÿ˜øÜ½ït祚ÐÿS!hs… \ûëlª!Ål|HE¥‹ª³žÿë~þ¿Zü·üÌÿ8þ_dþ‹§?ôÖW:ÿ+Õ„û?ä@w´‹}—Œ·2[±f’ŠÈ WóîÿPØïÿ/¢ÿ-ÿßymFþ?}…ùßtð??Úù_©&øÿ¸·`1&”ì_päd„Äe 1Àp'8økM€Û¦þW¦ó¿„Zü·üMþ/1ÿ'Ä'žzÕuþWª ùdö­WÒ§lrŒÍp"*æà¢F°@²^ë°Mýß÷/£ÿ-ÿó?òÿêËÌÿ®ø‹?=üJ祚°ÿ# û~«©8lå~ÝúI©¨¸Ð&DS=¦Œóžÿ)èùÿ"jñßêÿ3ÿ#ÿ¯¾Àü?bžïü¯Tâ¿ÑŠ ø`’t1§à4ò· ‹Et %§u¹¡þ?Œçÿõø¿ˆZü·úÿÌÿý¿ûCøâ¡|óŸ®qù£ë[ZSü‚&kU$#ãðð6…b’áBÀA-ΧòÿÉÑýèõÿ"óÿ̆ðÿFûïþ…ƒó{â×ø‰—®1ú½ë[\ÎÿluÑW€(mŠNU#T™\bdÝÐÐ:¸â7?c þIöü5øßþGö߫煸wÿæïü¯WSêÿ ØhÕ”–:aJ.×@bº±ù#þûùßBjäÿ-ûó?²ÿÐIwüï{:ÿëÕÿ/%–ÄXÀ¹RSHÚØ¢­7 ]Ö|Šö†æŒù‡>ÿg5øoÛÿÌÈþst@Çħæ/;ÿëÕþ}•!X­T 6(oÈDÐÕG_T¥šl/]›Ÿ±ÿÚôû‹¨ÁÛþwfÿ/Ðqqåã¿ý@罚àÿ ÚhïjÅf¨XLp^kë Tç+œ4õ†ÎÿÇü÷ó¿eÔà¿mÿ;3ŠÿWhG˜ï»;ÿëÕ„ùŸÞšhÑrD™ë~þV%E%Åá áÆæÿŒøÕïÿ-¢ÿmûŸÙÿ.Ð ñÊË?ñX罚2ÿÛ9Y5Xg²«…‚t1KœøY0 * aæó?­{þ¿ˆü·íjdÿ»|@»â¡ÞýµÎÿz5aÿo5Öj‰\ú{ D ")åŠËµ„ÿgïJà¡\Û>*Ò¢ETohŠB ³)YŽì{!šÝ`3cŸ©di=([ëᜢE’d«ÃdïPRd_’²Efæ{fFçíwêœÎûuÞ¾ï}ë§ç~®{¹®ë¾îû=÷³tÁ@ñ`¿®ß¥/âŒøtÿÿ¹çÿß„>ƒÿÏ¿ÿ‡|üùŸÄ–zX{=|¾ÈÛ-¿„ÌÁÿ?˜þÄþ?8­ƒÄ h ÆÂ´ ¬†¢!P@áZЯÚÿ ûdÿϹç߆>ƒÿÏ¿ÿ‡üöó?¸ˆHô#ɪ?øÝ×9úÿOâû-ƒ£Q0``¡hþýŽ…`m ŽE£Áhm,âkîÿÁŸþþçþ¿ }Œ ³Šjsçïªê>ÿ$ÞQd‹YUµ™ã㉟ÄDrŠ[ÎÌ¡ÿ?œþÿ4ž®ùWèàû]üôþµDÀ¡%úƒO þ:ú›ãÿKã&’Q4"Žþ5:¾ÿáPÄoÆ¡5÷û¯ß†A†üñ爆#à©ôm‹Ü4¨d‚ØX™òB0ÿhêÂ?R±xA‰‘ ?ñ¢ êí¶1r¸YÖXØŽ(¨kj&¨Ër¿rXO%“„-ZÈ 9‚3rT!g#àÐ$*?1´´á'$¡Ý–B»±¨0°Ô ÖÔt$‚. zLHp1Hð¶Ù-lC§ðöÖü#Š0È:ÄAè’ЖBf}`9ë¢P„™P.ÇOŒ÷ó,ÃOŒ¬w Ê|œ±…€£ 8›½÷oÿ/âŸB#’ _§ã ø‡@aZ¿Á?p6÷ý×7!ÿ‚þÿžD%ÁQM¡0ø§”ž nVi‘"h‹†7EМBÑpdeH8i@è ‡Gùù98 ÊŽ1J‹Ô…9hÆÛêêº K$ÛöíSˆÁ£èLàŸ“Nªá™H8^UtQ4Æçþ_#õßC_Šÿ$ ûµ:¾´þûtý׆ÎýÿŸoB_ŽJùªÅ¿ÈŸxþ£õÉõ[ÿÒô¤pšüÎi~‡¢{ã||4ýÈ€KÐÀj`v>0ptÆìDÐüxºP|°ê@ .³8¬:‘ì#š ÿÒ8ùßJ_ÂÿìŽ?úÿkÿ:þˆ¹ýŸ¿ ÍáÿïM¿<…FB1þ _^ÿýöù Ÿ{ÿóMH8æs ý»ÒïãÿCD'â¾ö-пöþÆ_ÿ#´´çÞÿ| úsãGhc´!x Gë tÐ(‰ãh¼TG †k¡µÑØïìò‡ñÖæßìÿfÿèÜúïÛÐ?ßÿ3 «j•+â[ò‡2^å:…W_]˜3|5¾\?… •…eêKëúY8:ý¶¢Ãª>–¬Ä›jšâqÒy]úC¼IÞHX-oF¿7Má©#Ÿ¥,+{ÖdÏ-æ½ÓŸñæŠgèQÌgTzwÒk+úP£ËóPØzgÕ+DWvŸþÌÔäõ}‹c=á™.@»ãj[²rzý¥Zû"Ì2¶QR7Eu?+V›œ8Æi“©«ÉݼúÈ^”]DzÙ”ÿ‹"“§{ƒìå3û ÷·ò²3󈨣ä‰3/Ü2ë¨Êñk +æ†9ÇÉ «Å»¿»v3®žíU±i¦QÓÊ{Í‹:ù0©x(©UíN˜3C±çIsá»'òdÝ h¤ÜÒHÑ!‡†²Þ…”Í Ëõ@˜X¶¶Ùr’ò»×Ö¿ÍYVÕÓ³+€æ¼µN&g*kÓ±ÜXpŸd–||ýîü4‡©ßž1ôÈé s¾6$3]¬6‡—D¥î`¶ÏÏ=ç5̬“y†~hú#J#Gûm!š:Üüq¨ÿõ¹š6]Â]rn—f0¥Þ3ƒW€»ÎÎ9»=x rÙNMRPÑÿ¼0Ûw´';HEJ²Iä"È—#ô—e=Óc…÷ΰªóX¹—¦Ô9ðd®öº:ÉôÜgÏjïV w¸ÉÒ{aÁ=oÓBÏën&Ö‘–ä‹'ìû…#OñdÇ®•½caûÓ&^•måÀår.«©³»nçÜŒ¯ÑÏ®Þníf|¿é±;>Õt* "¯§;]=X_|ÙmÊÝÒ²ÿ¸Ž÷YýKÇý¸.Òë&÷æñbú¹±7ªÊÂGö+ùÈH4ä=%¨L7&T>Ϲ^óþ¾²áÚŠ®}ìÁ¢=û;7˜ûö¥1†=ŸN¨yê nÅénåh³b/e|˜:­êà xµÀ<åÂË—}ïîݪÎgî]f.ŽÑK<@iëMù~Hg[±Zcž¶)#×1²áþµ#›ÂÄ×bdE­ºaÜâ¿—“"gE}PlÎÒš–êŸèìÀé n&ÇîiàV4°NU6‰zØ*C7#޹>e¿¾¥À]«¶åvjÐøß”€Ér夿M e~å7Þ»årø&Ì,¡õ8Ijiÿü|·×Ý;#k'×LuuZ½<²=tÁ·Á´9u—°Ô[¶3ŠÂ ´.¼=^­R.z$qüVû¸IŠq­k%‹kµQ6:F.ùŠ®¬qlzñ&Ƈ§ôJoÓ‰«—ÕúŽf v5Ï;ãÇ.ú¾©haÜËûìæ`n]°Û½+ï‹ ¶ÄßЦ>Hê]Z1ÇzÅžJ±‡õ’ôfz¸!_—­WFm}±újÌÓíï$K†™]KæÆ·¢ ŒèTä÷6ÉJ°º¢¥Ú÷—3Ê­¼ãcÞe鉷6óNT ˜”è ž^¦!»RÏ=2³Ã_Þ¨å•K€šÈÂ0ó¢,ïZŸÏFçäýÚÕ¾×k&Z`êÉ?{ž=˜'©;©Î¹£ÀËI³¼gäÎ ¡nŸ/ëChõ¥îònµtPÞyoÌUhájLvÕ•c–Ê¢»Ó‡åÕ*W¤¼,5¼nP-´/ºgҸ姦À|òÍ]™XcîYfüSµ ^Óõ8o¯uÏy7ã˜þîò¼Ñ]RÈ5‹ l¥s ÍïøÚBuâßš»‹ì(jW‘\·/ ýJ‘3QòSž“6œ“æïV ˆÇ÷²åR Å'[*QŒNHo6ïM§ÇP$ý®¡ž‡©‹ÙÑË_¢ýfnNÖ#J™Q¯ú4 ËóÆ¥·WÛ!û_Ë¡ÃZ &x¿?š…—r²JÞ5¹«Ÿ217±ÚðX‚"m…sFãGRDMŸÉIxE$µL¾ vµf¯ÅÊŸd‡qE/SfV>N)y}»®¤/W~¼-l{Zk£t¨¸dÂQ£]ÊO¶u¾YÃ=7¼¾èbb¤˜ãÔàûe“€zŸkÊwk#s+M«¯¦Sx4pùžÓyæëÍK»‚\­Ál-±º–ÝÙýNäÝìóE:ñVÌîÊDÎ…¸±;i651órÏ(Š@§AwktŸ¤rÝ­%mjÚ\æwΠS†,1i±€Ö6’–·d'NBn´ ‘­´žÝ¯÷¸Æk« Ë‚fÎî£.°Û¾93êF¸iyGbW}Q–2 ƒMíJƒcEó¹èˆFé2×AÉà6ó!”cAwspgèú2ù%Š…M™Û‡\Æ•9E’]r{ÞÜæÖâB]­¡ûwÜ w\|kéá÷„,péà¼ØRëa)¯¤¼xS[£tXãécºãKÆRW8äXLª~?$šII©\’= L»4vŽ×Ù{u;]Ô›p€-º8AbÅ8ýh’¡Ëñ½À¬!è]éu*)–#wê$½¨ñïêî0Xg.!ù]^ÜâZÊ@´þ@¸mÉ邃’q·Î QwUõþ¨ùQ[Eªù°‰~Z„Ä#î«a:#*e•t{"^Þòþ¥«Wbþ8¡‹CÒûåPŽ›œ±jGں祅URÕšÚFz’ÁÓc—øÅ€rw¤Þ¯tÞ®x!‡<§Xª%[Lo<¶ÔùB`;6ÓÁ´c†‹WÝ9j»zùÝÊÒ¾TÉ›™zÕçQÌ€˜0¡‘‹Žò0zäx:`×wwïrŒhFö­l¶ƒc(Ãoê\D˜œqqxÅ»'V˜D»0×ÕCÒ«0yT5ºý&Bÿ>F.Þþ`™KB¼þ(yš'3H„úhµ•ç–ƒCÊ-þlW`—|Ómùh¼©c²^>M.=üjYadë©ã,i?ê¥ùìy—¬¦Y*€f‹S+Òbûj%»ò×í~ M«ÖC.¿¾jCŸôDô€ œÆÅ^©»µ¥íz]!¡¯Ÿæ&÷Ó•¶›±Òõ=mZ1õ±\Û5ƒèõðï\\×.ÝE#û c³º¡üPÓ½VÍæÒ´ÎÞCiÁ^RKÛ¤M²Uˆ®–wäu{\ËH^(ixÜïáÈÔà…ÑkGoÐ'×+~Wpî)ÈõxÔÐèùóøŸXu0ïoÝ;áüvÞƒ`±ê+ì¶Sã$½ÍO÷'ïî²*æÔfdyßx“âÉCoLDÖñjq€æ0ô±C'©ú÷‡U§o¯ä>Êï4-¨óšc9 ôÍ'Å’¤ê –bЧxýÜ”]·qB;½eò°5O×ho90}TšrOmêÎΦlß% Þ¨ žè€ ½ÏéŒö†éá™°Ûí¯;šÏÔ±mz<´4gøÅÝ6+3¼+n¾ž/f× „Óßý¸áçÖ± °ð‹€o°âö;ŒRý¤=VX(H„ŠéºÉC–p‡nŽ·vtñ{§T}ƒÖÀIpNÌ£W¦žÈNyO(¢õë€` <5ûš…TñÝìCæ¦I¨áÚÛ _‚MÞV hG¦Œ6¤‡È=Ö\µ€U‘¼:boOŽBÜê¡æÕ \+’^[š£îV຺OÏgù&Ó×SYd'o`¾%êµ^ 4¬]¬tKMçœ9"¦é´6û¼Íjö£WyÝ Á÷s‚ÆS ߉¾®¹(ã´È¶éO²㦪ìfÂi˜§õÀÈæ¸ÄÁsºKå˜ð¼F»Íò¬%Z®»$Ë‹ÑãËÿaä ¡ü‹]HMg¤è¥UÖ€[H34| 1>8Äå8‚xÿmŸdWmI:=9óÆU;—«ËàWºb/ÑÏöͨsëëˆÊ-W9Z‚ôhr¯uFúsÃQî\ñ½‡¿×¾Q£¦¿Ð-?Žé‘®øD2¿v Ø^‘ß±Éaß9å]›´l&©nÛ½ä5Ü£ŠÁç' ü 0¼OüñB£$±è¡eýƒEÉ2½ëÙÝ{½bz˦¿×.õ±Ý™r=‡Ýp?Dl™ÉT$b‡$hçžþ°ÔÆQΖ/‰¨°i·2¯Ì™Œ"‰¸t]›‰æd>§à<Ãþ¹ãQ…©UÝ­åë÷,×/Ü™™J˜&éáÍÜüÝeösR×]8ŸÃ’3š^ÎB5ÊhWÝzŸ7è­7^›¦—Z‹4œ·OÚK÷²ˆ²½ËoÀùX»<²³ó y\Õ·Zç|\’ùòNÊ™… ~*J¼ƒ~€f³._棳 úÑY›vî-ùÑ`áþ×¾1ß—{j¼à÷ëÖu œË0áQ÷JØ-<œ8!>¶Ñ*¥ÿ½¦ÍXÞxÔ=¼©kóÿ°ïæÑ\¾íÛ(¢B$RÆ$R!}æÁ”’”"³òeˆ2#D"Ê<Ï"ÉÊ’!™3ežÉëmF¸äµ;7«S,ù}‘ Ü•V['ÿHWe¬¡NYNšÚ]P,ü5 Â2qØ–Žª ™;õma6Ö{‚ØVé<÷û õfŸªö{è–øÙP‹ oÄÍÂåž>!¢¹ÆÓǪ1d¶RÂôð:ùÁ`rP„û¥Šñ+4Š„¦Aþø¡‡'‹¬›SNÏ$HdRÿ¤r™IÒ^xtM(üPû»O=‰c:|:šaŸ|õíFË\P±’Ó“õaf"°qÉß¿Bs++9ï¹´å<‰d¶¦±<jµÁnú죜‘uc¡Œú.’¢Tiæé—l‰¢ ¶zÌ óésaÈ>k"«½£yIÓ4†%“‘kNºâ*OKïnÐZÔÎ2>c†‡n)BÉ7§ ¼˜èLâíô“˜=¨ô@ÒxCEqYvs Uu©7µk™ò˨x?^ùkõȤaSÍöKØe‡K˜ZÕy·[Ó‚U½²±…Œø¯3®•Û©’úõÑ%Gó¬Ý-E§BïÈtd ª["åæs:g×ò‚Î]xZmp•3–—« KŒ*3]¢í^zF;!üÎ4µñ¶‰…B_e,í7d>Û®²¦ïëîó§ý©…F8­€å©Ç¾¾‹£b<öxpˆxhúÿ¤Â«ä×¾÷¿??Ú;qàùYĪ|¤usoáò8³ëë Æj¦÷y=Ÿ@Þå…þŽéŸÈ­naNñTf6Ö-ϲŠ.{3-ÿ-Ǩoë’5Ñ4~kñŽ»ZZÝ}ɯýoP*:‡M¨žGøÙ^”ù#t ”ªWÃûã—šGÄÙ5ÕûÚèht/ö@Â÷â ]×ߊ ¬‚7lûT_=»¢>èÚ\¥+>õô)«ýBÃêP>mÙ9n_yLž½?‡?óñÆÛyá°ñÔc®‘Ûï®ü"¼ÝzóF»cŠ ²ÒôÓ<_qµLèø‚ÍÉ;$Çy]ߊµ/K²çN'gW*aŽ”xR¥¡à*ÔÓÊiM97$79r¾§2ÈZmYjÔ3Cô"{9}sæÎUIA"M#'D)u[æOÙ¹÷ó‘çyƨ~޽ÄF›ñº¡½o4 œ…Qs.ÌŽ‡¯&3,e`Ë Þ–K§kˆgqlÇ»EÒ?N÷ëÒ‡e£{3/ê±1I3ÿ…ƒË gÚyïnV=8í~9‘QõwìõQñuC ‹‘>UZ3óWÅ f](„Õü±Ž wcöö ™C2lÆauaÎÙ„pÙ°óÙU_C¹Œ7r,‡?*œ¡ºÿ9½"ý-¥œ?¼¢þÈ|àË{ìˆþ¶ßr²âñ±é^ß¶‡ýrP;X™O¸Ä¶pã}-áx3›gàqŸc]·,/¹¯ÏœÖlþU5õsËóU(„ãvé€÷q¡Ï3šoŸêÂÌ$`ÆŽé×-s,‰ß´Ÿó¨•r IgÌaD‡à£)ó-’ÐCŸáé|Àý¨ä¢·`(_öP„mJ !=h8_Í}è8¯ß›Ñó¤<…>8wáˆn8ËmMë¨/‡xN7Hd|pâeƒd%ŠŽS/-;HOŸÇ|÷=”AÕÈÃPJóœª,ðÖÈÚû«¦ßØÂL¡Æ”Ët¯Fy0*6fü»Óg~~÷€½£Ïév»êRÉ0½µ¢žæä‰ã r–|=eY¶ÐZoô òýÉ(¡Š¾uýÀ’ÕÂ#—ް¦Ýÿ&#k¦|°=È`÷2-½\¿wë¢òa¡.ßad]òyµdwwÌËÇ"Ý™WÑÁ£ù6ß·ßË=Œ¹§ñfÞÔ“MŠÌ¥Oe ¹6š³ßçz»8Ýå\z05fžŸ'ѱ ~õ”íí)ËÁäŸÕ_µ"  ÛïT_Ï焞þã7:Mx÷£ÜøîÝ[cœ¶o.õu•ntùßf =#pçÛmÍîzÁ×P!Œ ¿l8r¹wë‘uüI…áê7GÍnç±óy?4sÚÜ{AôûŒì»úLß¼ùÔFPÄOçµLŒ¥^ùÓÓgŽJ>¹ûÚ¶®ôs0C1ÐøáûÛJG.d¨ýá¡þ[êXæ¬3ðÃB)Cè/€Ið¨ò‰g‡ŠÒ³’&ŸŽ7& ²üá hë²qîzõíì¥`¯óy¼ycÆê«©»ó“"J2×Eóì|Ù§ÂLýY¡ë§6¨Œò›·Bò[Ì”Å3ýÄŠ^¶Ogw»©Œ>—쉮xãήõÙ÷ΰýÕ‡×GWÏI§ÌÝ2+¼ áœ8Àw^4}åužK»—q•ð@fœÈç'íßf(ùôÑùûÜ÷w‹‡*ô»¦üøæá÷ÛLfý­”åuŸéˆRbåZ»§4,<ÒÐ;fþØÙ.CýÒúÍ©S%Ó5C)‰–Ôøà7ŽªÑ©nÐ çh37¼gì4 Ìš}» ÁNÑ4üÝšPütê‹»‹¿n¨Æ@†åHwYÄZ>™“Ÿ©äwÂ%ix¯Çñ®ôþSª)H²ò=ôÆö‰‹´AwÄL ²½«‚=Aå‡Ï8„‰žî-]šìœÖÍÕo÷Pè-V’Ö7o·ºûØ„±ŽžyôÆï¶ï™'šKI”µW+™*¬xìµ,gc5—¡t3HO§¶#”Bšæ-.ù!°‘ ¼¸Ö_ÆmÍr²¸Íß·1á·œOºÕ«°‰Æ}gqõ÷x_ÕìšPË”À­Ã‘íÎ÷¦'þsÇ«o*·~)¹øà&zU†9Úð7å=’þSycPæñ^ghe?Ríì øµl³ÓÜ, tç{¡ï²ŒOº};÷F2;èuÕñS‡:… ×èX.v•²92°By–/Þoì¦ë]pÈè´õ˜ u›Œ­òazÜ¥úñ¶Ü§ãïînò™3âái|1{ž¶ÿõuŽGú/ ¾|Äñ9á“Gê>SöýòF„à[:É—f>¿ä çg½yaèûæ-üoÛ%Zr½‹§Ú“H»4)6ðª¯ØÚ7Ù°#7ê~a¹ívù·Ñ±û&A,:ߟóðn†úÜ?Äs;wnìþa¡èê»Ôûç£h‰Q}¢[æQC7ª9»FåèQšAôÓúk§útO‘?$ÿø^ÊȸÜÏ\÷ÎWјïÉÿÖ–xØÙšÊ¡»`XI·”½!A°Ë´ 8tä}…q óFÆÖCŽî:LÊt°ÉX±6ºÑ_wñS:G9v"O©ò58ý,:îO„i¼¥ñÝïR½†kMºU`á\Õ#m‡†½ÿŒÊ ŒÏ1Zô3§ò£‹«GîöŠ{ê›· -cª~§ÏÍj¬”‹;e6Íwsò ÔÖp. (=r(åPòÃçÅ!ÚêØ2!­ºôTϱâj9éÓœE8Á‘µT¿nU©k0+e…š~iãZå^6¢÷óÉN¶z× J¡¾au´Çâ\±á¡ŸW~‰½ñ÷{bvÑ]>fz|LQffa¨ÞYïòÉ´¢nùOئm}9A©=Ð8Es_Ʋ¸psîâÙWî’ÒáG7GuëÁÎìõnº®·}{Ó½=*q=A7‘G6ˆï™W׎\Œocï-ãìoS¨,+¢ã–)äxX–Ñ5œÛ~gpXóÒ¤T6¯ OÞGõ9õ~>>D»2…UWsUÊÀvlLEÞûmÙ‰XYš U‹ò;7W„¤<š+½x|ŽšIɧˆlI[^—-›M/Z O«õÏ 28blŸ3Òå_†±Ýv|!|èb€&U¦/ÔSeT…áÐ_†û¿’ÀÓ…f™ŽWñ—opûDÚ´ä}z\è¡z«¡ŒœáŧÿÒÞŸ²éöëìk‹°£Ê/Äe4ž_œ¿øérRË2åvù’4ÉKc"ï%Œî|)g±)þPéPÛýÇÀåøŽç±2–T¦zvüª];MZdÐWrwG†d‡lEb'žw}ñÿé­÷ì¡ òù }].1ä(ãëÓôBz)ÀÕ+n¶ÌBdÿÓrŸâ"-/âÜbòyºf¤$KL_}óUÏðyס˜Ó»'}f40«Ì›¾áý;[‹œ l s7«öMˆ ìóÜ8“½`Û­/±þ—X6!›ÆûÕ‰š¯‹&ôC3™,±T+WHe'ÞüýêäR/u>½¨GÞ`ïÆ!ÚOÜ4¶¿ôæó5H6ûǵ® —òß²ñºV2¡¤E~L눔 ½ËÓkïùм¥D낊DiÜ¥âó•¹Ái«QÏf&Çc¬NŸ’š>ÆcÅ$û©G‡YÃHžgü—iÉîS&÷…nXxjñÑ4”¢Çá(S›>j²Ñ ¹éµp'ÛöYàŒâY3°ô©0 †ømtédz>꾕Ÿ Úd29sØ” JÂ2/à6ã3ÇFÿïÔò<Û§ºcÂþíbyèƒúv–¶ºp/d%#²frÂôÁ׌.á·ù‚¿RCg×Úà×Âã£èì9݉ƿÍ6å´ï®ß÷_}rUÑýÆãä¹o øG?ºå·èt¼œŽï•ˆÉü‹ÛƒÜ©_Š2%Ð0)ûIθo*‡‚¯òˆ(Ð[5Õ¾hð§‘eØm¼œµ<¯qí¤ì«ÈÝÓMóSL?iLÏFÛÔ¹ÅU¦¶{èî®ožmÕBñ¼½5¶º)a0šÑ¤±Ì£÷oó‰§,bä&ÝFÅ^×Q+• 'AnÕû”6±Wç‹_ת ;;6½âH91+ª>Í/îy]l;îά|Úì̾½Úæö³þ¾-%k—[] H9¥S/,~d. )¯v)ÉÁÿØ9¯ü(þ0ä{§yß3''YÉÓ—|ŽÝžJ\*@/oƒ‡›ÙA1½î!ýn¯Ü,c7LTrécí5ê:¤Ö}y9§êÇC+á—çÖr˜‡¾z—#ʺ!]«_/þ:ÄŽÚþ‹û—À¾SŒ%÷™^K>9sàà1ŠïÒæEèO1…·m…›zÍEϽžàï‚ß³bNë=îà™U–™Êøü›—h¬ˆ‡Òyùù@îcÙ Ib³¤n„ÛÍÎL¾~­L/ñâ#ñÞ •wF®ß$¿-'ØYå`áÓˤŞ^cÎTW˜^«vkø³)=‹ÔÂÎ,ã•Á¢°åÅGâMuŬÈ— É–ëUÜ[;iSY€‹LhjXÜ(Uu=*w²ñJîñJ¡â`ÀíX£òOƒ?þLë„ Áçy¼4Ït!ªʦ¤u¬€¤þÊ<\iq‡eiå®l‘FA˜íͯ?1׎½È_GÚ”R©È¼nÃH´Xðþ{Ãå@“â£SψýÍ–wÎŽ.9*Íßmû³þޤäS»2D é`ÅÁ›ÃºÉK”‡É9üBìŽIù™]EGíî*®gGz{Ìu0lSõ߉÷% ¿£Ú\Ïôý#£*™ÅÑŠýN?¥}å!…9;M9Cb(Õ Ì)^¹º,qZWî*é{.…!æ{¡ Е²;é HšâCÝSkÕ×´‰Øuï P"å–ü+¥¦eÏ–2äª[QŠK{Â;Xž)¦\Äíu ÝÿÖÖ‘Ìõüc!gÌ£Tr¼Ê”HMóã-Y:Ò4T"o\ýæìØ•/Ò·2ÛK™ù £’žžfFƒað<ïUgæÌ©AmäãbºGêæ‡BªÕ ¬œ¢<AŒ·¿ú›ˆ6ÿ~.8qý­u1 z½X÷±GÑ%(‡æJåôÚãt´m²àCžôzºay®ßUø™Õò¥z¦z³âP‡Qà°Æšj ÷dæY¦ˆÚ‹á6Î;§õæ—Œ~÷T• ã!³„Lmm½„{a™º÷7)ܸRe‘–ÔÕïh³ÉÙ\þù¦àÅI#çÜz ÈñèÆeo¬50w('ŸëޏåMÝôËB­w$…`Š)O¹£$­„Q’e(9ü#…ñÔ»³ëJŸ·KSÆŽRP¢§Æw0lo£ƒèÖÞb¿/m^hÀâWÂÆçO$ÙTMµºvĺ( ùÞ÷è/MÕÚÂRÑW#F©ä2}:e¬YwºÂÛí1W¬Z“¹‡Ä,k˜¢^´åŸóoV.z0Ÿ¥¬}¤dTÓYtlXÞsàTÚ‘Š­+œYC‰Ì D!Gû(®{|µ÷Õeܤ ]<ío˘]½D»™mý»¬#…Æx˜è†ff0Œ+éèàä«/%þy~ã[7p~ÚjÁµ)Vì·x£½¹’Øï¥É0œ`:…fÔðT×ÎŒ-lü¬¯.Ÿµ¹}q37¿­÷_µ+åÏ0?ãëæDåZÍ69·Èµ&ð$hNóEh u†"=“]ˆ-Ÿ^k^¸–RúgS ­xt˵ôúÌs%lMC»»Ù›1…0÷—†Š.l׋MÖRø‘ó×pÏœ!.ýjáãŒ@ãÄ‹¶£Òw%Õ_ùǭϯÐ/J¾>ªü—f¬öòå½²½zÊ`©‹Ãóqa–© º|N?GŸëÇrŠD’´Ljd&àv¯ƒIGÀPƒFŠ$ì]úWGòz?ø@ßPù¬‰v6%©éßsï¥Id­(Qy<0íH‰Ãvy…õô¿äüý.Oò÷1Œ§˜f>î¥KG¾ ¥t)³¿gH4ט¡ZÛ>]iap…Tšõ«ð-2ÚšØ>ô{¨°uÑPn™kŠÝR½zà› ÆàÖQ¿h€¥@@î!¦’´gæiçen,¸(I •WlÉ­ÀRÿR1Ï ¢J°T(P½óÐb)±47ø·uÚ„Ò§ãjß—˜AÞAïàX¼u?xÁ&¸ ÅÇÄjõê6IÕ5Ž×Þáÿ.Ïà\™ZÀÎQ°”Y«^{»¢¬ÂVÓôÇì­Ó¿HcÞöªŠÚwö+«A­îU_š”ß´)æˆíÌ è‹V‰ëéwçFϼù> Ëêí}>­é¥£·D¯ýÁOIóåý”}eò|:»5_N ètßʧŸÄè~âB`é1j¡éþ(Hc¥d˜ÕYê!Œ«Õ’±@̼3¸!4[?ZxëkÇ‘5Úêó·Ð+ŧlX‡Þ>6Z©~ñ›NªD*W ü@– .Íóç»ü¦××_ÐvƒV„ˆzšfðò?=®jPª"jˆj¾«¸æÿì\ uIŠ‚³¸±&)àcVëºÎŒ½²HkZËYY¥ü@|”©y’€mÕ+Oß»á§y!íSwÒ$\i)–Àä€>*ê wµÓå/\Èˆâø´GíšœŸ«s»(NI׫ âeA¶ŸÚ¦2ûQj4ÉyÏ"ض8ý\ø‰œy?ƒº<¨±¨qòPǘ¤¾¾£>»o•ùô py>O)mp¬Ã×ìmÌ-+Eª9YmÕûTigƒwÈûEÉ¡Ô þTl·’ÔÃÇqÁõôú_]ø ¯¯p÷í$–×£îR0Kz—ž¸‡æ&ÉìñEÓ{›ò—Œ4ð” Ñ£Ýü‡:íy’ƒÄ;i[÷¿þK3î—{[â/ØøföH%o67›‘i}B_T5“öÅÁ,JèŸä)ZÄì[›¹·Á¤kºiMŽ–ü1ɨ"š°„c0.שּׂh;FîÊŸšçw“€­&¥ñû«O4\Hs›V¡š à¾x´=æp¢Ãgnú^¬¥×T'daf'-f¹zÞ?­eÑ#§¾_˜øaCÏ1š‘’G%À±eฃ†“Å,é‘´Á?zqV ª‰#W½Ï àèÚ¹¬bÌÌDŒ,1xÙe"åYg^¤ù€®§ã?Ñ1 6Þê°ð³ÖÕ¡ë;ðÕ÷hèo„6‡‹¥ÛrÒÎ Ô:4.%½ÂÌóIA꽫dK/ôžm*4Sê ]‡D,¬$ÍP|¤3“Koêì`õÃ'ªªÂ/¶;RØl·OÒßçþ;V5Lâ_L\(ý"g\¤Œâm¡œÈB¯Ú;ÍÖá?!™ävÅÅÇO Uj¨‚i-ß")0Ûæ'þ𼆢O{ÜVì.vƒá`Øo\¼ºä?ˆ|~úË›åá‚£š÷ùEÍÝÌ÷ö,.ÓOþæ äÿ+;ÔµI0?µ¹ä¤fñûÓj¢«RÅOʻԬ^‰£rá´åMÓÖ4?ÖQ¸üz&æÐ‚CŠèMxH˜óà,Ð0¢¨§éôÌ¹Ô n™c3RÚá·eÁB·[Œ‹‰Ëܦ ['fr0gS©¹õµ¦ôìþÛÙü´»¿ÃEzܲ9FÁÚR¯,ï šzpA†×™~uñï~Qú{Ô¤ )?È9š•ÎF¾H½-ö4Ý9µEH‰éyïÞK#;óÒòŽ‹UNëB7O§W&b[<þ¸žÈ +pnßñ Es=¤Œµ¬§·L:Y8­Å#ô "Ò[OUî š_l>ïô Ï-›ŸÄA9$:À€®%….×?„Â1‹96¹¬Vâ¯_,ÐRù§-KœjÄðËoI®Oæ%­ô k,•¼Ÿ]Íõ¼tá…QÇ»I¥~37¶9þRAÙÍ~ÂöÔXò*É-{•¥Ñ,¿\øàoãÅ^P65¨Ù¨|ÍûÆzRe´T¼°@ãžçÞSÔÆÌ‰Z!ù;”Ìa‡.µæÜÕʉð[ŠrS¡{˜Ûß•Êì)«W<6x@^Ò"ýŠñR+Ÿ¢$•—ýU¶/Öâ;wçm-^49¨”9Éu9­ÏzîÀëå\ɧÃB f}[†òw_~7¯hŠLÊ4¹J-et;ògœBöñæd8ÒΡ’Æ&—ºÓ+7ªíRVND·òͪK°¼IK™:U²sY¯¸#çm„¡_Æ©éOõ‡?Ô÷u‹‡ç€•}¬ÿ’íçéw‘"Õª†ÂkJrçô.,‰T©ßÖšE Š?è,TÇYeÞz°e²êñÇ™î•Æ‰Ÿ¡­‰¿(Ú±l¨¸p´¥E‹«c*ûTë{Ö“wE¨¹\ VGKüýá0x™Îà˶HFÀö+*S-õÓin*G¨cÈm;Ì.›5[K;MÛhznáD ó ­ï¥Îÿ8$Ÿ‘6‡>½HXFÇhl@j;4rCØUãÙݼñNl"ßRï »éýøÜ\‘· ˜8QŽgâ?;÷¹c&TçÎ)vüHIL›Ñ//_4Ó¸4,Îý—¹È'Ï©G/Ý.Þ¼&‰K´Ï;ÍXwÛÛêÖèG¤ÅgÎ> ®È¦iGZèžjøuð¬È|ºÏkôd".ÎÛ¶ |ЊúÚ…å/:ïº'±ñË9¦¯î—§¿ÒËö‚JÕ-ÉO¿‰¾Qÿ®Ë?¥a®q9ÑîQšhõ I­‚ƒ²r‡ÀŒÈ wÂ\nsc¦Ñô/MãþM kнÜÏK§µ¦…ÅÎåß6a„[ Ë|v¬@·WRtcx±MO%’£ª°þ‘Ÿ²`’ßsºÕKk§¦:õfd§ RØ$$Ë*ätNŸ´fòsçBÒgŒ=}Öø¥…üM)eç‡9Øè (:nþˆÀQGÕŸ¦°LŸd!ë«÷æqºPYÿ\yëØ§V%šžì«þe%Ù¤ïƒ q&ó½AzBª§ryÕ&Ÿÿ¸’løçsÔIInÁfÔ?ñ~mW•ås@þ›©SSö­hílËlë«ý]þ·{Ãyß2piÙlÝÈÀiw°c¬Ù"F" _ã,E)Kš}×Å4ε€>qÇA  ¶”t+:ë‡Iß‹;OAµ¶’¼6~k)Òm¬P8>J”ð>-;Íó×dá#h (¬Q‡¥‡UÑç;¹·Ú[ì™îOiï °2Nè«h†Uµx£æƒoHLK.R:¤ä ¸nþQê¹pÛAOÎS¿R­Q\ÜCí*ù]™ÛG©žžëúGA]è›AùŽAÛÝÕfU7fû3ujUîðÞðpjøÜñ*´;ÆhÂkìKŒî3ÍŸÛÂsLü´á‘ý¾?ò)"*ïÜ·Ô4 ­t'[š:äœÈy=<.ü˜‚Ú Ïs;–Âýrp&ù1ù\ݹ¯æ«¾oÆÏ±Î"i{_Ý0“ªà3¦‰šP9×JC59ÝV¯{ œ ”.>S9Zzh|§¤ô+.žzÛÚòjC<÷¾…Â^¿ñ;‘®HQ¬Æí^]EöNZÞùï¡ýçMÕ]ˆˆ“è{wB®õOü"…ÿVN¤2‹24´o 8þB?«ï¶Ôýø]…©w6‡VŸõÓ«5³§¸ð}×#,:µí| Õ¦øHß~§Z SiÏ4ܱÁ&£áë®§,yâÚ©8^8'›|.çk{iD-æOƒí€¤>L6 Û¨œõÞö½ætx e&m:µ ÖPœÆtsËóíËÅú´×’Üßsg·;̾ëî«ûàêá’ÌÃ}-uá n}SVõç*ÿ¶9îœhúwe½a_Å7Çeo’˜þÎ]ýszz?_v§žð¡~›ÖzsÍÆ_ ªVbñ„jFeaÊÔ~Çv+:0ôç;Æî‚Øz:Ú'ï!±Iv£í·õ ÍóŠßÞÁ”ÁTH§äü6º0õØŒCŠÒ¾i‘[ÙS®çqzN¸”1ug:þ¼rC–wCi¸^ã±<¼míÁ{ã Ë«×ȬÒñ†Èû³ÆÇÿ~šº97³3‘-xÏY._I*¹ºÄ¥`ÍU#r¥EpóåÃuÖd ŠÑÎÇÇDøÍ¨¿§n>?°µÌuðks¶éHÉÛÚËP÷»Öü’WýÜ‹šLwU}‚#¯sc96SfXá+™Ét©Z!äȵ‚Êê‰zL×´Ð0—øot;PáAÖM³1;Dtµ!nØŠÞhIM÷ð IKmƒQÊÑ(þô©ñCó'´}é!<¢hÁC–Ó²x«ÍLÞœ’/_}ßî;û•h®5y/ëÛ7‡´Eœ;ßõ;×Í‚(¶}d­J{°íý«Ñ#‰¹4QM–BK~œÞ§Û_ôÌú|spŸæ§¾ó9櫎z³úL9ÍkÍ¢›î¸ä>ppø…^*¿Øp¼Û!¾Ù§õ„«ÂÔ‚ÛL½•®ÓÒÓ)oy¶w™ÞÚ©*¦¹ü,ø•?Juå÷ª‰¥ÕûŸ·ñϤNA^@8þ|ý–¡z­M‡ÕyÔÁ[ìnô&åÙñb:2-&–ÓéN_mfáÈ:&gum@å}ØÏÅËm-CHu±­ÒìaM­ÎÖ.œú/߆¶ô4N¦ì…z)¾ÛEtVÊ7dVšÎÜX÷ÿ5(V›–6»Ãaßh-£~¼I?0@ô³øx˜Q+9nd45F©ŠÙžõ‡n1¥ã‰g5U=¤Œnª"µ×G>ý—ö“~®–¶öŪ…i9EÓiÞPŽP5)õlì|?…5zëÃõCøRLÑÔzò‰­_&wÃk;}¡·7v–Î܃¾!,ý1äX^ÚöYÞ¬·#Ô FþÄÐúîq°ôؤæ U¬Ã—~LÒµ[ ã…ã&}Jz0›>¹ñ;;+JûïPâÆøgl²“C׫æ­¢ÐçyÔl}|Ê&Cš¸+³Ç³ÛVÉ©˜gh;¬ÅÛœó)éšh”ýbIÓ—œúiíBQÔWçÂãž:ˆŽ",žh%E;`KûEëôÓ‚±MÛWuãiatÿ ŠlƒñËï4(·Þp¬«Ä]ÕM±±Àª<ÌÎ8;‘Ût:¿ê€Ù µ˜ U Õ ´§«Íëï@múè‘?xkCâŽÇÜÙbÊd¤¯»Ct§¶(*F£å˜¼z¼ÓáQKׇõ­-xÒùÅHÕDóà»g¥42Þþ©˜ã#<·ÈÂrîY]Ï×BÆ%®ÍµJ=xœíEñvZ+ÒÛ¯m†±í©¿Ñù?6~&”OÖ¬ï›î"¯±žÊHûÖÍû¦Ñ#æòÄ>")Ùéßyè>1¼ }­¢ å·uÐoš™01ßU½óŠq½“\júˆé˜ÂBÄÁ4‰ä‰¶Ãë\±Þ7ß°ÿ8ûivç¸O&h}ô¼«CMñNcH#7ò#CË×—&èW˜·l[J5 –Pj{1<ÁcA®žþs-,Ìv‘²sïkܰ_‡"N³^) k{’\ä9ײuíý‚Y=ÃÅ觪§?åµ^=¡*ž¼Ñ°Í÷”ç3ÛåáÌоðó½.þwè¹`¿gFCûÝhUÓn]„|æôù71Y iq²)ˆàC¥Wf4¼vüœì5QÔ÷HÒÂÖUt’]-§¯æIx%L2ëÏü?bäEù\Oå#ÜØF8è3ª×EµÃö·¥±€}¾•8” Fe^§}côöuéÇIqÔqè£Vlè’‘ŸºÊ Û °·¸Ýûquø`PdL×ÅàÂîp]¯ŽÎo¨Œ¢¸>0¾e|À¦’ë#öÀ°õ³¶¶“ÑScJ±¥`Å"$D pÝ Ô^ŠýÓ­á z7ª¾(į ¾/JR‘/α²û¹ßdüÄz¯ -ø æÔa+¦ånWY8_z~‰]bŽ÷í|ªGU½1©66^èÄg wbÌü#êê«÷ªº}ÖJÄ´úƒ¼å± Sˆïuÿ|àRº½ÆIÖÇHo®ZI…¯#mÿ ²Äð6[€á@ýÂe7é˜ç¿ï÷¾}8ѹèwèr(v¢tÒˆÙh¼:3’íTˆ˜ã™–ë²φÙ<\ü8NFFC }‹æè¤GÊå¥äy?óÄ`ªP};Y}Ì$¸ÕC#{ûʯ¯¢[ÎE¤4çyDÇÈ”y¿ðH´ý¬òù­Ø=æéV3:'ÉäÅåû–cTd—/÷L¦ÒGö˪VÏŽ§×³v±$EeG½m[ìÙéãL5Ð×4:5ÎpÑ=3»Ewmnš,½ST)]‹ñ'c6>ÒÈ0©Û&ˆdŠëqÅçì|ï,?­ÇLû@¦¾û$áÈ„wb•SØ™ªÑÇzî&SRÛYµ2p¢mÌs„Q)U•àvý\üHs°eý ‰Æ³jjF'pj7Rÿ0 ½p_ê·ô (G÷:wWÿ+hd³rÅsÉ:ã+ibOVY½fÂĬåNrv>|Ð :åÀt“ÖƒçÌÊýmƒ§t1ÁÔ6MŸÜ–¢ÿ²{u%çIgtfjPÿúxV·PB¸åù¯‰ëóáÈhkõéâš\õ•ÏÚ¯ÆQëœf4¨¨cs:ùRgU<åîûÝiqJ*‰_'˜~ž©\ŠWºÌ%Ÿh:Ÿo,=]“i'qnAÐðu¢§J$G^å±´Qg+ô/wÀêA+ÌS¦¡6ZÜ©Ai=2Ÿc¹ž’)ó–Ü_&­á-¹Ž¥·ä¬©²¸%>6´'yŸ¾¯‰3? Jigv8†KTŽYÝ2óeplý=›Ì£ðGì%<¿ÁÆýÅ(ºd×Kf‰‹NZP„í”ñ¼S’=êœßP3Fæ-\Úˆ¦eëNLgrÚë{Žû<9ÁžÎÕÔ€zx|›GgÌ#ÓŸêÇÂÌšyhاçø×ª¬ïôU™Ä2•ÏaFE Å·Ÿ¢ë‹ùÈûEÙnýš2ú¨‘¯ tý`sOR•±’ůC§Ÿ[®¬ `-½Þó½ÆQCö®š³i]š‹ƒEd A¥cajS¥Óc/ïw—ÞûÜþâÝ}úñ/¶n í«ìÒ.ÝêøvýqÏå£fYkûj¹ëÔl¼[Çæò:Ç©!Ÿ·3J0Ö®õ«Ýo¦Û³þ3i¨.=`)éÙù>9yD+X—ðég@ÑPEh@ŠŽ€%ö«mD˜I|Ày·ÈtÇäKÇ!¢ôoGROš³a´&Øß¡è»¢\òkǯ%ÆOϸ²%Ū(ësϺ}¬nÿ™ r~åÕüÇ@ñvsÄ|ó{îï&•ÏÉR|ÔTq cº5»NhÌÕ~Ïò í ÏËÐÅ º©ÛÑ›”|›-ñ»žl˜›DÊœ(ÿÆŒô¿ýålrÝoÅzßÖ ìµ:ämëV}lpŽWþoeÒA=·SwVÃÀ0¤Éû¹K>¥!Rý90Ë™Båa IõˆM4‘~–ã°˜ùc§ÂEW–âªñŤÎÄcŽGxÔâ¼ïʵð$¡ÍžR|¿¾À“‹÷U#Õ85z]èßþDëc™Çk?€›ÁÆÈ"ê\qè¶Œ|G^•”SÏÝ´¾/f.o›ÄöÄS¦P6íŠyçX²DjůӵË粿 ÓðªX6*#Q”] J^ªæÐÆ-Hësí[Þó+ºZò §¬Gý9øRÆØ ËV‡ÊHÙ_¹ŸCõÛ¬jÝê=³}çÞѬ¹ö†&„å—ɦ瘴Lîç½ørÃý)Ô’ç…SµÝ©÷Éè¹Rýk¢#Î2LÛíÑpxÈ8ò ¥ GƵ|ú¢.›ÿ©¦Ö¦Ùs7/Ò/¾!õ/Ðád·@uáq”r“Þʃ­OµèôëäÂw~ÉÔp䎊ø´K™åÉ'êHêÄv}­Ò³Û_xw¾k›ï-²p?@Ãvrð¢‰q9Þø²ðíçùª_ê¸vvedÓý"àˆdøE«ˆ3_õ _lUÝ£yÁ6]ú™òEžž!×||çSÕU‹#1úŸžgÇ39¿*?·ð/'Â_7߯¾³}Îo|jÙ†ŸúÝ·§¦‘û;}0«ûú±\cÐÊÛ´§¸Üß½–zqwKÂi6OA~–mTŒ¸WÒ±ƒö^Š…>ÍÝ2)ÂìþãÏÞRï(èæ.¡Ø|½¬³éÀ uw4ã{κØÒ)ì}ʇµ~M!W Ûb½gÊѦtŸIµÙ ã”8 Þ:”b¡µ.Ò#RƒEº“=,&Y«ì. ²†ít¢(crÌQ}Â)ÏóêýŒ9÷^¯K—ucp˜âÙ¡•.ßOWül¯IãtYÏP]S-{’DÜ68ßcÔ¶éËkå+K>=?ßaÒbËm—šˆqaœ6âiõÙùÖÐÎ •›2 ¬0™e*ÈÝ(ïA#ùÑnKu½À Ò–k7ëÚ,I«›E§}ZÀ•îaüJÚü@à¸T0eßó½Zî×eþž?›^xJtæõãò;s>‚;úÁáIô~á~|T=ÚØœ)?µ–~/nöÏ=Q QG£RZ|ÆõÓ@õب‰ªOªËéÑ.ÿÛþ:L\Ný–—üNèp90MN0k£=þ†ã±/%H¶ÛÊK‰×èÏeÙÙ»óñ¼RÖ÷ðYù4þ5’²2å(S§´#ëJCçž$=VÞdŠ–ÐvpžäLûæÐ²IŒI¢òʪ9d*^ÛÏ>¾Y»£(›eAêU9t–ö'šD7ûI#“àƒý%Ñ9ï(߆›gÇ+χ"Î6y]Î2j ]É E8),€r™>¢@#+t÷„ âúayA£ˆ–ôØàœÄîú†cÿjt.³,è™æVàÚKíß*¦Ydïq OÔ;†nî|ÑâÖšŽ:Øe™sré†;G¹ñZžšÑ«ß#<;ÿâ§Ø¦ë‰]T­qF±çÀ 5g‚é?–~öé¢é¿Ï:¤žÈUÐÆÛêNÚW†Åi‘Vª dËÏ;¬6ëçUYïÙ@}LÞ*=ê–G)ºtåº{*SÝ¿x/AÇQaµà½ª"µ§Ú™{FjÉÑ•ãÙ« ÿHQ¶<—MüŽð#®ÚÅ0Ë1(_Ÿ=úV•Á5 É¿+¶Iã½´ó¸ Õùâ‘ ö÷íŒ<î|iêòÿÐê~Œ×¶èD—Ò<·ƒ«u üPqríŠÒ{ë$-ÕÒœ7Ð 3+X‹kºêè5c PÃï¢&êå´“uãsIíqb½O{ŒOœÃmY2VQׄëåŒ4û‡}s`{\däÓ庣fÝž’–ú”°”â)Ól{ëP) oªÆßæì¸º;"Ø{sM›?q=Ýó°@üÇmñc3“ÖÛÚh~dZ<~»âö­'až_½.Ó‰±È;!P$|6à:M:¤„)÷¬§à§ð'6úI˜¬PjП=Éæ-íµ¨ ž Lõz÷ÔÞ] ó~ŸøñÖæóF:‘ºbPZpð—éï• B‰ïÿ®ã“bOŽ$…Ôé‹G‹‹\BçÏßé‘}0U3&«y†¹¬°ÊÿgÖm½†{KAÛBgØ–¯aßP@(O®àu—/²¦ï¶Î*Ìuž¾w Ï,vždûï³ruV®â¶iõPùëY[S¡r'_-§˜Ðg(’z­ÞÜï Á[Ñ_ ÓGðâ ^j¸s6øñnGËÎ:Q½×¸ùKâôþ÷ÂC:Wc;¯Ä3¨;º<ü7° LÂæ=šˆ³Œú7Õë±s¼¸"Y>ÉñèlDЊõiÅ¥êê•ÁÌì] @þs·*5¡æs—·Ö¥HÍÙ‹¸þú~!è×UZ7Ëz¶s‹WxúsÛ«V€ÞÚÇ &åùë±³»s˘Srœ´–Ñš¿g¦ü' 12zÃÕŽÃä[\)~8½î"Èü"èG¸HIx”€ÓC¡Ùžk‡£é‰Ï—RŸÊ/JJ*ªKúk eß´qóE;~DÙIGÆÓðgLÇÝG§s§)ß1…¯ˆ=`ãR¤©FÎM”ý¼Æûæ¥ÅßêRÊÒK†­^ ‰ÅZ—Ezxr‡úû‹FDuäæ4î|µ’ªÄO'™¯Z'`a[ËLEŸïôÒHcà¶” åÙÓ7ãb?c {^VšÇaûôåïQ~DzOù®—.½ÕÒ£8ÖÞý™¾SnV—ƹ·dŸk0Nù'I|±¼•K¾êUÜ-wk5«yX°É‡L}Ú?#)GºÔëfnó´‚av%÷:7ó¯Ö’'‘pGÕ¢NŠˆ-^Qtñ ´ôUáå§gwò-³µJí¹rÒ ÷¡íÖz¹ï{‡þ&zc¿X2*¤ª–Ÿ>>¢˜;pÀ·ŒÒ­á؉麗%ZuaEô 4BÉLk2©~òÂ:ûôÊ·ÐoÚdzaˆƒcm+Ää#7X«Šâ†Ÿü»;.Û=ÀR?äúY tñAˆX‘‹iÑÛ»'.íŒ Ïo]¿à”ž×r48ßç4Rpµ0qX@Å«íHÉÚ×i™G·r¬¨#X~©‡q½LÒ*ÿ¨FÃ*$8ó½î Š\;ÑHïçÑ9¸ŠŽ¸>ðÉ÷ ÃN¹•ô§.\SR4¥h5~²˜öÀë¸z=Æ3uòX\v"üeQ÷Áàò¢ÓØ”¢œßo#s"T¸J´tÿ«Çê–Drø‚¥ƒÒ—gŸ#Eq±ž?Ššo¿t›§Ô{üözòu}Éã²!ÚÔÖaBUý? ¬œ~ÙäÍnç äŒ(VøspTµS{Iåî9¬à‰q*r§ ñü—($¢¨­À2†¹zýü(¤8ÒUi†—‰ªhyñ<\ûªô‰¾Wš`”êUÖA» ëÖ(|Ú‰c·TßUšýk=çů£íZ¯Y;:z•`”¹ºNf~ò=™My=°ÞIWÕD¯ºLÜ?ìÿÄtbþVácÉ­W¿ Îÿ;ìÈ àüƒ¶‚òŽœkú2«÷ƒ>bL—±@ lxUÞQ2Ê«â¡æ;dktm€ã$õ³Ë ðÜ«Ã;üT[¥/åoü´øO–ØiZLTE>="¿¡,½“ó5ÎvîcÌ\L΀Ÿj7÷ªñ«emÕÐÎÏwJ\ Û—ßäu9¶…–oèùòë}êè»é“ê½ šç{sÊŠZ·$Ê|ü`âó°ï»Tû žï¹×5þE%6w¢Û+ÒüñV…(]½©Íd2 ÷¢éWÓNã°;mw¸øü•€LºhE=œæÓë‹ ˜îú0 ýÎhlYGÌ÷‹Yb\£]N•¹V„Wå‘wĸEË×ÙÃsdñÞßN­ä¶Ü£êýuÐëüŸKAý‡w6}"ø™G”¼ªõã/”HUVx'=F£k°¨x§Ø,ƸZëýSèëÝ´¯"O =Цn&æ‹ÿm|xú;X ÏóÓ[í-þöla4:¯.a«"‚þ `¦áܲ¶¾ò òkyzxäY™ƒ²Ñmö;_¸Sˆ±è—ú*ý…ÈãŽA®'Ž×ýÃì’øQIÛ%”‡/— cHK¯mgW|ñš©Ñp2kÒƒT<÷¯RCb>¦Ø¨5§Œë¬ ²Þ\ùþD‹ñýVÁÎ4³ó׆¹Ìªþ· <¹KñüO=ÂÐó-ù} ¿‡vn^)Uûè£÷—íRûͦcª(k¦ùS òÈn’S'/—£äÉÈ›õŽEÉI•ÆŸ<󆕘?÷Ud‡É¶÷Àõ°z‡v{w{w½j;­æ‡{ÌmK‹±Óü~p¤Ý{JøôzMj¾'<Ý©š AR!Ç7’²Žk= ©õàî‘£ÜÞJ–íò®s%³fj_”¦%T+Šžhñ˜>0UvGbBH^qêôµãÉߢœò“5ï+>tôT°:cí£À'2ŸÒVðõ“7¤ÙæÒ^xG*ÊN–¤á "P ßÞLkCYw“#ss´û|Ýã”R®Û6mžOÁùò@b{†JÊ"âO=¶^¿W­apÿûçGØ•ÛRö¿TÐv³ÍZÊ9ºì‰Z4*šƒ SOé.½úÑ¡Dw¼úic2¯UP¼X¶kÛûë)²/Œ¨™ãµè¦èFð-Š«8÷Á8á÷ZŒ«i¬CÐÿŒî3}8æŒÒÍBÓmŸŽEgÖ?¶n Yß²w€"Ð’¾,:Ë(cð§Ÿe›Tþ¯°£³kÔo·{ÿm¬gbÜé˜y¦ú׎–;CUÄù•"&œ^ þͶ·™uœ¶Q¼ªõ¤$ó(ªî²9dNçÔç«ÊÿóÑHüƒ_qï|ñ«—oë=‚Ç\ùù1.ä±UEwuðÎÊm~Ê5q‰:'Ì­§\ã{æú§Ñ(ò¢¤ý$ç:ŸÔMõ ÛˆŠà‡øCù™Ò%òÓrW\‡;+)¨«´Ó„%ÀJïB”ì³fuÅXøÂ…þ,YY´g¨„ò¿3 †G"ïÅ0'>-Ó] Ïe‘ΖáìxÝÚ¼‘ÿ¯é¼Èrr)¸ó‰ÑòÂ¥¨É'%t~‘_Žf(ÿ² T\!Ïú²6ÓSU®ô®Ç˺æá?c|ƒù%™æSªU1xµ¿§V“àŸô‹ñv _¼ «‡Îõx]ÊÃç{¿È0ÝàJæÂz#Q"äѹ†L¦§ ;¶?ßÎŒ ±¨ªQÞsmÔQ˜ õ°M ³íråáú¦ØÍVƒÕOæ“=,m‘“UÕ¯þyÒ1âXºsnìNç0Ì—ÉÜs¼§ÈNíy°à ·Ñ7dÜþw,üƒFênÚµœÃuK>Î^–’¡r¥˜ûäÉS‹Ö³²‰&_‘¼‘ôà‰ãÍÁ7ƒ¢lx3ÊÎõÛM¸<Ç5¢³ K”ëØ3|uL¼ÎáŠ2ÀwƒàïPOè)ß”¯±©¿®ÜRÎÊÔáï”'½óž?¶ 'ܬÑɯ[_DOÌ¿›½Ò­±öÊ[~gã³­Ù³jpG›•¬si:¬“=?©ÞŽmXôMåÖo¿¦ŒTóïñ2çD^²Y¯ø-™¨6>¢x_PŽÓÔtÐú‰óž_¢ch›¢xC¸:¾¾óMÐ_Þ×óÌP®²ïlBŠU¸é_Ølÿ ¹)_èY{†Œ¼_@ºÅ©ý,¶ü3DéÊ£àa¶ª‘®—·_]ØkÙ踧q¢‡ ï|øJÖñ’ÒÜ1÷ G/Ã6”LøœPx¹”ž!Üžcõ<Í{­'1Å„Üú=ÐÍwëeO©7'Åé]'fp,²Küª—<Tz=M—d¥4Û ‘×é"™y§OÐ {ÓŒk×:¢N~^;Ò6¢PÛWó6ýtXMÌðå+VeݺyÛ¨âÅù¸eó 95ºáÖ©íºÜø¾B9ÔÑœV+Ï~G;Iþ œEãÎh÷•‘OC±ÏþïSJ‡çO•…U(x,vÖfšw?¬]ă;›u£Ñ:oü‡“˜Xdö«’é­Òµ#Rdž‚nݽö,òÅçŽÏòÑNèg…®®Qž/f3qþÂÓª§ÇmMzĨ{Ç<ì;Û¦)J¶¥<]%‹EÜí[]xZGœØåÅl6¶òÑ”“?˜¦77^esÆÆ¾¤ö.¾ƒ2`lö½@{pƒ–›G–’ÕõÑYsW»Äž¤—Ü6øs&7W°.O“ÞÃ+¦HéfÒ²ù:ÝÐ8‰­3vi/ou˜éø©cÙȣ굡½:NóœÇ ˜. ¦Ôˆ–Gy¿íþŠpâòÔç½øÝáü±¸üƵy”̶ĂèkÙ/2ÇEO—_mòó¦^¾‘ÆÑ3r?IzíHU(ürÄãGÝÖD\½ŠÌ5ºØŸ’[ŸâÊ>¡ÍYw¤`«V…Š:êJ…Éçi­¾ÂJ¾5Sæåõ ¨×»–ðÔ„¡^&úÝz¥ƒÓÍ1Q†6&®»4Nï[·—ßð}Kê'3žf„Ñ¥UćÁÏ|Ó£«ë°Ì®¸0™']´5}ér b¼„¶‹M· &Þz+¡'²é ®ýÃcÙꜾ­aùk9|! rʉ½ê¸¶?Þ—-[ŸõÓz>U÷k1µ\žjübÙôy4ÃDxàð•J3Õ˜(óUžÚ+· ä­K íç¢]³ûjDhÓ›.QÄ\á»Ï§wš†ŸTH~a'™l÷˓ɅÙSÍöꇋæ9úÏ™b|Ò*TèbÂÛ @½ø8¥9Ú+•ÙƒcÞWàÓgU–t%ŸBÍ:P+°¥o5 ‹%ÁÏX ¬› vÕE"ß§uVÃ$LâÙgEG¨¾§ÄõÞì¢ïo[§aˈÓyÊQO4ÉTP¯”7øè…iù¤ÙzIó‹'‰þ°ìèñ##:dFå˜K!A¡¾w¤ÝM¸¶“k­äåY‡yÙïëÙÞŒWdðˆÿX~ö ž.“ò½Ûæ1{¯4•ðÝÝ;ây<ìk“ùöö\zõëC𚤹zÕ¹+e_užgmŽ µE‰§ÜÕwk(}QŸÏzÊÊ]÷ ‹»Ó›Ã‘Ü×by¦¸ý09Ö¬ž^ñR±•†Ó’ã³ß„“ æ‹yIFŽp£¦º_hÂÎÒK \®üSéÒ`ðp°jºü–—qzÞ‹3JÔ±¹ÿC]ÇûUPA)ý ½ˆ¡È˜ƒ—r:k°w4eg:Ο5uÎ.ë<µ ‚ç﬘r\¶Ÿç|«´qròðcÆæ–2q¨‰®rýˆpY¦²gÓ̼½S:I¾a5ÓR]0¥äË©qóÚåâ4S“œÐ˜Íu:õ‚Ò£ëyi[FŒýŽîG¼UžÒ÷Ë^[ø^_Úµ…fÐKÃ;i"¾ù|={ò:asxùÇêFPãépò²pÆsŸ í‹´»þß,aßÛ|“®NuU6ž‹¾‚ªçE8TÒY ¹»*°!ïmF ³(±~Ð-åö¿¶“œ 2ü|sÖ)9¥áJçâC*—Y«‹¥‹;ô7Ǿ(æäÑcãx"èd _á“Ò+ݺ?Mܵ¹w¾^`ûÁpïT¯ÓÁû×iûÝý‘öui…)þ¡Xóæ)‰ôìn8… Ÿ{ )ȇ±=,Tzp|MC0ÕG¤åÒ_JÍ()„;8㨙Cn% ½jzðø¨ªo)%ûÍ+U·6˜`æ2½øq²§Ö…;KýêgÈ[Þü”àÛ +¿^þ¼8‰zöÜ §ï¦„} ÷f‰Ý¦gSÖ²³ýÒ_{;‚íC‰¦ CŸm*".È8.†:dîTeaÏ‘¿b†0Zþ̯ög‡ýï–ò!Où%,P¶ÿé;{çhzDBÀ8 áÑ(-P|ñqQýnlpNmÛGŽ*Ý¿yÚ8ÆòÁæÏÜl8ÇK“ÞŠcÛžlÑŽž|á6>p>u€o©ò'»4¬å‡ßÑ>›êû‡ÇÛ™è·é¸s§kGéý¼ùÉ—•¼»ÏŸûWÓLU|‘6$þåëãͳŽ÷H+Í÷Ø­|,3\´YÏæŠ/9•¤ù‚¯¢ o¿çÐS¾÷æ¸8?=ðç_jÕü¦tÖ{æãtç“ }µNÕÚÿäÝvœçü—šÐf¯2^k >}åuˆ4Gטa^[.h{¹mÊÆyãոʊtÃ;Ÿ añUfñ,Bš‰jÌÁ(|! }5;•jö›¤¢ÆÜsQª—÷/÷÷¥é<¾è|ÆÕp™R31¾iéo«[ø'XNªœš8Ÿ0ù£&“µxÞ%T„Âåïš³ý‡ýl+IÅþ"'ݣBŽ[œ;á°`$ᄪñú€°~§m!ì“ùAšíÕeáã«jïÀþÏJ ¯„®yg£#ÆÄ¯³}äFt’Õ–só¡šãÚ (˜,U^š t¾ðQ C6}oü¬ùÁDƒ E`d˜æÕò½V ¶¾'öØ=lB1ûéOFtœrä”ÙÎÞG“NžÏtÿÓ]Â#À{¥!:ÂvMi.eµ½½ƒ×ƒi¢í#“ª'ƒ!†–'0DËæÜ7väIDJÇ•q•O/òcì2.%q´/>â+ÂÄÚþwäl¼âÊïf”kZ^T¾¡E—³Mct²¢›»R¯LËšO:cWÄÒüÝåŸ^O‘È­ÐŒyr«ó¼ÀµªW<©JœÍ—6?ªú×_Û½B¯RP÷ Ýµ,ιoìêϹ{µ=Qý2(^ÑÖ»ºH9N5Ûò¡J|?ëèß·’ÂYT ¦ÕÆU“ÒnÝé]W3O°>¼Œí{úzú‘ñ¹ÎnÂÚƒ=齞̸çÄ‘eÕ­Ç®•º–j¿—ùÜý­ÚÀÎzLðsFÁázéQ ÜúÂéÉç¹bYCÔ+ÉÙiT¦qøŸAŠ„såŒS¯÷Ìõ–«Ž+믃º( FÆÃÚšèšÑy€Iýdó¼ªRÍóØt8¯íÜæ ]wüðÐ(vÚæoÅ˺ÈãoÞ]ÐÒ€“°«>ú±ÁÐ[¤ž²Õ‘ Æ€’arN‚ÎÃ[œ?Lß:ô{Lz=¦–‘]Hµ5 £B˜Ipk°&m­ypа-ǹŠL ° 4;s‘ïÿŒŠÇ‡nÎ_œjúneŸC]d¬•¨WÔ *Öúgr‚B´šélk-¾—…ïœâÌ2ýâB8óh6’5îÐIéþVãôS5óáµcùØXÉÒ7,ƒø £†Ÿ”Û¯_z8¾˜–t§‡VjL0?ýá‹çÇN¶_Õ7¤£Ÿ)¾,’ûìè#ß Îé‡q‡†­Q/ž0›ˆ=ÝiakŽÇ±ü×¥JÉ25˜TV• —F„¾Õ[®~ Mù†>P¯êô¹u.ß¼äl¾‚±½æ¡‰Š¾%÷Ë€‡þälܺ§ÚÿÍ”5[DÔrYî²XÍîËiêOÝAKÃM±¾/¼nùçœæc^_áxP ”xïdÄ`œ~r-Z:¾vrš<3Ê0èÙ€ýÂj¬!xAU˜3Üì2LÊHø»Ãkñ9f…?k¿â .<ñúy6!Êñ`'c·l¥MåŸvì§-m|^ÎväãPa‡ÄÀ?Íwv¶664 ·Ñc>ú0 .Ik ).½äzf> W÷_pu럅±? ù/ÿfdhsˆ³£´ËëW^ðõ9R4Ÿyý”ÅÔzûÄdêºhaÌrƒÉ{™›!Ñ$5 ) `Î]}põô­,C­EBY†¿8& ‘4(Ð]¢lM͸™¥ÐË/e­¿^úÉE©Ë[Ç5ûˆït‡~wÅÓîÊÓWsÒh4ss­–›”ÆÕÖN: k”ÛÓÃ/V®? •þP™àU~~}µBd2Dìš3x‡àZ„¿°>»Í˜‹8"WVµ’‹2õ÷Hqkºþ¥"xªÄrÇo~©¶ûè¿®´`“Ñ'üXÈ3hm\Æ4u£Ÿ¼zQ?¢é×7P‡ˆSÖdÎ¥/ì|Æ£¹ØÈÈÆØÃÌ­k¤œ^w^äSúÑȃtE1%1ËJ~¢wˆ~ÓWÞɺëü ÇgñÏc‰‹¢Ï_?.#0MÅ_%Ë–ÀøC Ý¿Þg8¸S­IG«ÄÇ¡oNÉ5V]«þväHððçmª8{u ‹Ù·ð–%I°I\" 3Þ§à¬q÷ëÆ?€ hFS\râÙê¹._-)ø0^áCúy[å‡ vÉÄU«éšâà‰Êbv~fÞ뮜ž‹õ¿Uä%M(Y;Ò»˜¢åN“kÆ%U‹ÜV+œ›`z?Ö`Ò41“vÏåt85“rÿØÛ+Õµð÷·U|øN]J,tÍ¥HäHGTíÓ…æBë¯ÏOH0 e|ÆÔË­ Qy³æ12èn½á…‚K_%PW?šó‹Ö<œ3<šÿy«f1¥©ñáÓ±xxæ¥Åžµ¤€;aé;(ûÏÓõ’ä¥|è=uM{*üÒ§dje)©°ò^™HY÷rŠÆ±™$)[:ÒRzÝÕK’-8Ú ‹‡MJ)á-æ;ÙP[u,ŸÕæ?Á<ãh-|AEþÈÄ?W;$ûÊñ!äñ­¥tuDA'7röÄ`ƒƒØ…¨Íàþl›WNÕø§ˆIÞªVmrj7ÐÒ!éÜ}Ñÿ£­.3ü@׊棟²’r¼I?_»Ú¨ý^¡[cáÍNçb¾Üiñ¸Jt?ü×-'†uuóÀ!™2—’–ëÂ/#±Ñ ­h©‰3Ä/r*ìÝ-éxŽŽ£Ï=×OnóTP¿Eiã_p—u8RÚ}Î{¦‡2&—š.³Ä~FÑŽˆ­|¨m.·nC÷94³oiç}ÜÛ9ùå³râxÌ·w#w(êÖý;ùš7<=Fþ’Çë:$:ùܨŠ7KRLt+—à¼Ñõ2°uFÂ/±çÅ̇v½ãÇ·Ì­“'ƒà£ë’\tt™®"ë²Þ…+þ‰ŽÐgµ9.GüÖJ ä¼…M6?®Ìþ+¸‹ Nyƒ5™™†Í–ÜŒS¤§Ï3ºè)ÛÛëx0zªæÀ/ûö¶z~¨öÝX/"£¦JÿNÃZsÊ‘…„O/¡Irù¿_›Lbµ ËNÞäx¨Élö¹i‡âgjC$‰th›Ê73ÒcLQüçSÏt`þRê-~ùêü a ᜘òß6c+#Ü·l›„7 @ôª$]-z¯ïÓÙÏàðsüüzBÊ?•·„¦BC‡Á¡¬šlñb]ÕÜ´ôbæ§J›ø)flu©$Ò¼Hk‹H¤lÝtù¦@.lc@úijú.õû 0ë­“ÚÇÌ~vü£'{::¿ºãŽRz¹ïYë÷ßfÅPIÌ Îþ«Õ<õ\ª˜!'ºãƒ1æ* <‰{6ºœwV;Á‘ªäéÜ÷—{ñ´†ÝàŠ|A«ýÀƒÊœZª¶Ùi®§7þ!A~«!ÃÒ?þ½%Óf};Ú©’ù5ìÈÚëñÄ|°º_GÄ_”dK=Œ€0æàœ´P×ÎÌrfMv‡HE;¯¾ê÷*`/—)¡ë翽0ŸÂ™ö¼Ë$’=SopXórå`3©¨<Ò˜1z}³­Yüºµ™A¿*wRõÏ^GO}ûŸËÞ}ÌB¯'ûØ‚¯t‘×2¯~Ϥ»Xah-ûÍÿö”ùÂá•þE— ™9=Ë€%»ë‹’ÎÚ¼5 ¯´ÍñB½ ÍúT§¤ò°“‘½©gîÓÜ—\®êëÁ­r[òÇZÙóN¼õZ¬¶Ü2Ù„—&Ë%gœþ#ec·‘ïX[¨ˆ2òkÅ|8}†µuýR–t'Š'g'øŠt¯+Ëðõy×fÌ' ù?} WÊú£·f×ÌG×¼¢Y¥þµìñr}”_ÃÇt;mm=ãö,åaýÆŸÍ/ÝzNz×dÿÐ’Yd—{ÔzúbO w swQŽÁö¸|ÙrÊ–º]‚Lw0Ÿ±Üåê‰{e¿Ôμ«:¸Ñé¸6ŽIWù±3´ø~åu·k|Ú•ärõ&èÀA9¹‚þÔ¼‰i ¹×*0þ¢gX\çˆÙÄšFw7]±S0D§rÏü<•ÖEÃVußÊ`VþÊ—2g½Ò†·¶w¤ŒNÇÔÙk/÷ñ4>Jˆ‚ÛòÝf:)mÎö œÉïé{‚÷¾æ†Ä±2²-qÝ•çÌ“ï48¨³Ø]˽#A&T;[îg ÷‹èšòªTݬa|ª?Ú‡[œüÞÈbò²ÈBÓ2 ™¥ETÊòŠÇt>ó ßTWYS;µÓ,7ÙϘiáD%ü@½¬êyáük5Ýt)3C·q• Q7YíÚ÷uI>Ò ’D»Ìé9ÿÄÏ_+vv½”©¹7Q•ãzLž‘áGAñ‡ÌNýɰ…5 ±>úÑõ © iŠ0²Â „„Žñ˜´ÚÞˆâ…Zè®ù¾js 5"è×¹°&‘ø8ïVÅgLÏZ†(¡KóåuñmIsv†‡^8yð9Ä÷a´ß– ÚYÙŒ¯¥».J£µôÜÚÀ5[³I:Ìßc®‘Ffñ7ÿ§§ºØŽ·0hkÄmÓZ³C…rHÆRL):Ý“¾[ã)ä¼R#_zºugÞ~‰Ä/ÚiµÁ?mòyMU—Sk^êmùâKkÅzkß~m˜£0ã¯SW Å3ë× ¼HÙ&šSÝž4ˆÖâ9J¥Ü5ÍS­"òU-¦eÄùè·rnœb¯y¯. ù^üÏÀ9TË™éØJØ L.ž•$“ͺë?ÐWŸ\ˆ0“–…8ÍÞ‘t—ÈüX8_”v3Àº÷ìI™†´*íÊyÙH0|H÷´É.Ì Ç/<û”gùÐʼš¶,ÖøoNµä/r¯>uP2qṲ́ä~ T#ûc“1½gz'%)v-ikîï?šÞþæÒ^¹Ôù@ô°ÕQXÕßÓÅFrë(&»F—¶W$8‰Õ3*hZX˜ÐVï£iÕ5JiE—¼7ýC0¯Óã:k*ÔžÚ_Û~ßm²Å¾öjûæHçÁnÓ<ý—*Y‡Õ9 =O¶PVn#‘&mßðR"£ù¦ôƒíÀ rΠ&r±ŽÍèp’¼“ççñ3Líå5ÓtB'X âÅ$î^#RÄMG„zyʳæÁéî϶õ*ÌÓ˜ÝY*˜ë;ÿíë*vQ·˜êÆEŸ3K—>8éOˆïm‰¶›Ö¶ûšvø4@;uœSÝ('‰®ð “—ÙmM¯Ã?Ô‹òÿÍI‚Ù_¬÷}™1Öü8;c#ƒ¾ö瘢ÖÈ”¨SPK|Æ„¶k1ʉÕú%ÖêУÊm£ã¢[aùwÿ¡÷HPAvÚÏ64¶þæ›S&œ4òº&’GAŸ£MRKFÊàD+à4…N)½ª‘zYŸy©×M¢wºœŒu|€«slQðu9UýÔã’ø-Ù+Ú’;÷Þ¸›-ü…óBî…6j˜ù>Ä/Ÿ›–rb =2^ïe¼Ðªˆ¶þp|‘6Xû‹‡¨º&¬Yà˜žù ü¿2Ll޳u4þ”† \ü<C\[Ø9ëÙ‹6—¯ò«Ì›¯¥uã>vep‡ª”}$nâ{J\,»zŸÁêbùs©¾š29ëÚŹ.ô¶¡%áN³%æÃ>Fα¶Dj —ó~ùlg*òˆoŠÒƒ†h¥þbÈþ‰T7µ…=O]’#Š!ð¥*Î;µÀÇ?·Q¿?õÑ^CCË¡7ßïõzËI_›P‰­íØæþPeêN§,Fƒ]m@áV‡CZ©;ÎpµUoð5ÎÙzÄ1òw>Õ;ié#Uw ÛªSäë;ÅR²tlhÛ>ï'OZ—âg5yÃ#â oFX&<uü;3ïÌK+„„!KÞafrŠ¿d‘iŒ"f‹”Yìö*Ä!9-Åk X™PŸV2&ÌJ·"QÓLQ’Ó“Ð µ ¾³ñ5zþæÐïïJ’M|[ýÆ)ø[çwðõÄ¢»DBJ¿]+}AO–HëúÂ<æL‘Ðî%ß“©m7»bõwŒý‡ù¯ìfÁÐvúñ·‘ ;û õÒEl Œ^n‰Ô¸y·L‡ú{CIÓ)ûc˜à½IÞ¶ôÌÁcYæíÕ“ì½=L'¶‹ê6QTf_¦ÕcN XŸ¶*™OÉ“SSI ið×Iï…¾Ÿÿ%dÕó×¹8:Toðáï†ü&•ïÐ}c;{ã­M›çÞ4¶yf¯!&÷ãØ£‚:ö[/«ËÖ)÷¿/“¾>†ïs×d 4hë¯!hœa¨Y hô*òŒÁ»÷¯HSj/Rÿhﻹuʼnt>Hp2Xüúqyv\ÁcºŸå¿.XNÁœ2¨Ñ÷Ú™Žw­d†ž/óñÀ45Ô…·¸Ñ„°ëgó™=zš[úvn}8+{È.Ö¸ÛßhqfBˆ†ß§y¸v¼éÞ:EÃk^&>i§®F Û‹•]tNõkâ¾Ç ¬P“ö±^ïÎNnUúÞvˆºçÝb 1x²>ŒE}u¶è±5ü—4%w½m_ç?_ vþƲ`ÃrT§F¢îÁ±z)6Y Çä4ÑëÕ#Ï^cà+¥œ),Ê™˜TkYLñ›²'3Úå­Ù¨É÷¹%ö× º¯1µ›P¥ÿ{ë}ïé£cqò­ˆÃôè“¡^‡t7VôÔ¿ž1å'w‘ñRpÊDÌU¬>ÜóQM:פ1béHû£>îàÅÖBò̽—PleЛlMݱ‹ ¢•æd79ï³àcú©ôüËîõ™ÃáZy­Rc”ÅI}Õ»»Ú;å¨TâóöÍ‚%Ë©bJl×H;Aíðm™œÕÖÊ/îäßׇ•ÅÅã#ßuÌn/ |ºô¡î›õ\fÐÁO‹Ouå…ù™+jˆ®ßA“Í„6NéØšåW‚ëtì„ýv¹°gʾt¯üûÅrÓ_Sañ§`¡Â$4{Ž›’o6ÞØúïXµT>Ü'¾ÒTgv;œj{ù·ˆÈö„ãš7ÉJi€ãšS†½ ò‘ŸDÍo›9Q_)×ɨ'WPŸZ’²7cÔf¸–òúí]k¾iý«w~ü ‹Ïo£(exθ=Ãûè ·“W’«EiºRƃ⯂ْFìwð–Óžaù5/OýƒýüØ…Û|Ân"û,²wÞ×HKÅeæj5ßén‰0çùUã#xóyDZ5•"ûÎÿrS®¾árÞ‡ý«¯ÇüñŸ¢G¾~(Ixöèß HÞ­p¦ÄœÀ€|ÙŒ«©q`‹ÉÊWÞ­{­9Þ_ÃL©à³ÀuòkÉsæiÄâ7|)‹š¡oüîÛSêµg“suD†\b×’Q` Qù´÷Ý_%L]·ÀâÎÖ­2×a$*ìò÷xu|Jýá§‘I4mü3? î8ÃoŠŽw ½dÓh¤Î[&w¢rp'FïëAM½3E¾Uü´ô©6;²dáûüPªŒ¨ÃÖÝ©áòfMËW…Pòš¦·]òÓíi–R3VQßüÀ9– è¿zåïÒVª=/,nåÈCx%‚tîf½«îä`Bik`sä채#÷Öb )RS½=æü’[¯¢ÿdoÍ수š%O鹨[—ý!¶?óµl¾_qÑ9ŠÌ­+ *¹¤iŸŒø}Ä€ÔEÿWfžq¸†ð›¹“¡Øú–0] ‹XËf{wIƒ>íþBÜ1Ú®âÆב2{£9Zî*Nÿñ“ œ· _åt¦¤µUs½¦æÖ\è­Ü€êgpJ¦]×­/ü£Ð‹_šÚ"?pûovïÎj–ÎßyFNÎQ*­Þy-ð²(%Åü}Ì'†è„4Ïà•' ö=â^ ìöÖíÿÑ cã{ܯÑ^ŸteŽÃç'϶I_ýù@b´]/>Χσ´¾÷¯<Ÿ:~ Ãú^Û꽸ÊÚ¢ºê Ï24Îf]Ï‘ÙMÑÑéïé&<æGjeíÆ/Ó{qSDڵ楌!Ÿœ8U‡,*Õ¸¿Rºó,<–ÊÊ/§½ŠXf|3Î%Æ·ÀÕ-ÞW ¥æŠ}dPO:Zlºc>v›$Oô@Sµ^6;Ÿþ2´ê'”aëÿLzweçÜÚnö‰®r'_˜—SɲN£’[“ãøºãjÉç¬hي̤x©µ#o½} ¹¢Qœy¬àšf½ eD$^pbQ€Ôùs½¯âî_ÁF{>÷ùzw±¹2·@i=äÆèµqA†$1?õŠ*ÏkZõV›ŠYó;™Ÿæl)ut:{#rÃa©IÝ~¢ü-wçéÎıÄa¤Ú{b)´OðÛva´‘é®oxdY¸ceJWžI•&¥åçtˆs¿ö pÚ‚òg:ËŸ¥¼É |u?ÃesêäÙ¤›97Ÿñº5’fÍj¬×È`c¡§¬˜ÙË“£Úàþ—7S\bo_¶I¸+ì8àŒ$lTU™ØeLÚúæU;qaÒ9ý¬j5žµË•¿×_åz£,‹ÓúÔK!Iò†j|2Ý¥W¸º«éop„ß¹¬4«çeô7E5]˜%õüêá0`ÎN\+þºâζsÝú`­XšxÌë'ÂÒa%Žß†½©L±6B# ~@œý^¯¤?¨DX[Ç6 ¥cí¯ —¯/VÊY­!àö˰à÷>£¾'Â?g3ÌÜo«M©}1©k–÷.—²r‡–ôå_:Ó;è„©ÍizBŽØUV4]Ê;´:LçcU0á8—¬îÁ§ºäSë/š\~^ Çj°Ò½´“–%~Ýwºù qD ­Ÿ†ÜäBßwP Ñò¨é á#ëçoVÇÅz‹{ÇDºäè³ÞÖo8.pöœ U©´ñå?ÒÊsUPøý³ŠŸx´ŒæZ¢[?‡˜<ÀJà¸C´ѺS¼'”=Óf]£UÈL˜¼s)_æ]ÐÌ)ÓR‡êë{§Æm×Ê4˜¤‡”µZߥÉRÔ†&úSH°6m1ÝåvU¼€ëœ2&ïëòeÊÎí[ºÐíGO%8—fôdǬ9Â<5j†Þ”ÿ”FÏ„–ê›ÊŒg¸ú’?E¿Ð߉ö´ûýü²;sù9çÜç\\ò, ùÅQÕã5WŸò@3 Ó(öaãÌç ½‘œtYÍ^{ÞQÇ¥ClTŠãEÿçµ(òä+m–á«­lCê¢×Ÿ(ýöÅJ Æÿ«S•aû×ÎYŽNW™Ó´œëîšÜ[NûÃj,>'@ËÜw‰úupã)N×ãi .EWœ™´-î>‘¶øˆ\÷:×ÉdnSÖ\—Ãw&µ¨[ý›Vô6D7r†­a¼8­¤Xl3,‰·:®‡apžü9ŸQ"Õþxìå;ëËg êÖ5ƒ6R÷,ßÓÜLœk±¨Ös¾7­`hʇ‡Žäûè7.[¸Nª÷´Wý‘˜î*Ñ}évaåÓJþõ¾^bQ_¤ÔUHÿq% V¢&òZ~ÖŒuPV¬xZ5¸éŸcÎSg`S2–Ö¥]Ô¾™ òFSïÎ4lWÿå×1»W܇¬Ä¢Ù*¾ç¨3ûxù¯¢Í¤g‘B¿ZžÌ7Ô&¼‰°9úfðk…•ŠéæÜº°&Š;]݆k¯)öÕÑI•ìÆ:qjR}vJ‰íT !¾ezSÙ°âäât/s·Ì ÌÕ²>™dVåŽLƒ©$¦·j=cpIöìË3¾Û÷yà_MJf¨…ÏÜ6–ÌN}“Í_œ¬Æ÷]cü=mí…«Mf䯃A *&¬N¢¦ê/ÕÃý:Ù•=‚>œ{seîs ë‰åâ›G¿ùoÄò•òHøå÷&ªáUK¿[ _=>¢’]š`›s*PCìØÇÄ.æ@ ƒíYúédú¨ºçé¥?ït^™Ñ,¢UôûÈ)×Mz ËûÝr(ͧ7Õ(hºTo¼m¬+þCk©Áa+¸XWˆÌQsÑkòŒ=•Ž‹J¦ï¯÷U2~M²»Š8»^ֳΜÒ!z žîRJ¼û¥[IånÓßRãxøvÀí[ºkx·p:›)ñ£?-OœÒÔK6>Þj:8:ù·_%éÎÓƒáqç~rÿ‰¤Ý¼ûµ?TtOeåß)ø”í´j^i–ÛS©jãÁ #)â4isÇ‘rw©Ä^Õ«˜¼–i>ÂÆÂRœ3új©óÄÇ£ÏOŒi~+Ú45^Tt­IzÀ|;‘W07üN­–¼Ù“"nÚºsêí×¼PíÕóœ¦K†®®BBe%fg8â!™Æèe÷Ó¢¾8ý…´”px•µ˜Ï¬øø›”}Ö»VPöì×zVÖ—je„‘&’N9§?Œ›Èš  ¼ëÌÎ%(´²¼žÔ)£.Ô–éêj¨ ?ˆó;e?=4ÁMfu vD&BáC’î.ñÛ³›››Éò¤ô~=‚»È ]È1‘›}'*L]sÏ%æô [:¬ö]{nÂ52õ^DRBDÝÝíÆå«ŸEE¥p"ëR{[ß,m¡Ù΄û¯I—¸ve±‚ÙC- ÌKªÇС/Ï7fñ뿊ÏjòH¥ô‰n†S$’Sz€¬®OmËP^[gõWrpˆÕ_#BIáfdØËžw²cföÔ&¨%eßĶ‹omƒø?°#8Mhžo_O³ì˜«¼(KïÏé~¿:÷ÔYön|>"XéÖ©Fšà–Ï%-ŠÑ .ÑKâjkŽùÄø–pæWŠ]ÅЀPõ ëY«-zñÂW©ŽBÅU–Mã=¨¹’5–N]éP†áð lú…ÓŒ› s©…Ÿêë ¤_1§n\ìõ[åÔæ_<°eTšoËâöPî¬Q&ý¥]{ø%’ÂÎÃbò¥´ëZ%¬c©…ƒqóïU·ËTÍ®¡Í\ÜŒqŒ}øqø¯W×g«zÿUç Iï,; Q:¿9ûäµT=m¹/‹0o‚|Zá‰i·±mÛÍ!Ag>Zž ‰îî•Z áOw)Ö»áuOöëd´W@ºéÃ(OÓ”VmX|8ì9óóÂ}ì³õ©Y~Äú\5ï†RßÇÃÆê¥Š*—/T¼žgùýJدüQùz­ã½c[6Ìî_Ës8g¡|Œî]aÖíó¤5w·ßc%Z®6 ߢ¥ÿ†s¼RŒïbô°¡ù⽸¢²y[4^]fMµØ¡;-á0;¨aêÄ$d)`ñǬÿÕÑó?Þfˆ³·/›ýœz¬Q¤Ñ<õü 3zðƒûˆã:fGŸg–ïLsGëýj’šÞ·ÄR§Öhׯ¿XøÒ±vöÒÒúå)¼ÑEEp}ËPb(OUΫÕÌ)÷íØA¥óZØ£‰l¼4Ük}SÏMÐr ‹×7ÛÏYŠÅª%O2ÓÑ}÷aÑÛtLY½Žö±O~´¬xkþ|RÁçN{»ËåÁØGëb Õîw:÷ë—eCM]’:ù9:Ú%ÕË ÿÍè‰jF_9~=_—F¼ÏÓ°í€AÉÀ•oo<ýV¿eüh‚šÒS¬ð¿•~C…ï}w/x±X›}Rþ˜Èp×e‰*J7ÓïÌ&ýŒœùE'5q6¤«PzKè|ƒ~ôÎו‘Äô¯‘qI2—CàÜå ™?n|«3¸÷q*ûòå¿Ó*M¬2tÓŸT¤¸~+HúøÀòÅñÕ¸¬}ï¡‹õ5M0™Î ½êRcNEò%lÛŠßå¿=zÃ̪^X;£2ß(êØgöÌ× ÚÉu7Kô´®ê†¹WÒÛ„«‡tø÷ð™º,wMn½OñF-wã£ó›‹}v yŒÜ#(,-.gž)}ÌD² Në¸d@ol©ãœçó~”âËwTŽi{ÛAœÏ¤·-;ßR]§q^ýœÊÚ©`Þ>0rÏM=-|c{B›LÃUƒLã‰p›˜?LÉ[ÈÊtÁY†)¾ò°ŠÑ#Un:Òôv²;ºéâ]!›´n‹ì^¼•^Œƒ3ëçhEk’j¥~]"ߺÏ>‘_žxÿRPe¾zVË÷šl}—ß?,a¸{-½MKÙ§Y:>³Ž·í*¿öÂ\ _Z*)YÝ…ÌÜ"¦Û±:4Î0ã<ÕÙt™o±>¬ŽÏÍ{Pšm6þ)@9“ŒGL´¿<æûêî°Êc‚n‡pã;ÑÎëh!ç¸]Úéõ´gmw| µ½[1SïåP+†‚J•RæU{ì?/9ÿ8ýCmÇ«îõ ô™÷Lü@G=[gá¸á4Tðzž]W_êNìó¸ó|2Gl¶ÿÒlM,7¤¦ú?¿þÛ¯G8S»‹dC’ÅÅ‹qIÄKˆ8s‚Å¥z`hjM2µ43·ûÿþ ø…B vþ‹Fý¯ÿ…ÀP$A… (AB¨ P4 …¢: ùÿo›ÿý—•…%Îüôisãÿ§Ÿû»þ¿é¯Ç憖†¦$q"…Ç"P2 ‡ÃQŠD†AÈ(ŠˆÀBIA`]‘hhjpšlfÆ`I²°$™ à   CAÑp,®wšR<â§ 0$™€ƒàqH8MDà‰D ƒ"B (œ€BñxND“t q¦¤Óý#"þI@áñX Æ£Q ƒBÑ ˆ <Æ“Ñx†€þºDä"’ÈH4ã X,†BÁ xŠ!aˆdM&d ƒý'"lÿˆ¨ÿD¤ìBFÀÐ$C&¡p ž@B£hB‚ãàp(†C`þ¾Dô"â°h$ ÇàP5~ %@Q$8…§ü†CÂpøÝ<"öˆùODD`1d2ž„&ÂÈp‡yFcH02KF‘ IÞÝ5rÿˆØÿDDcÉ€BÉ84H&…ÄÃd,K5E›‡a!î?QûFDBv#¢8…ƒáñ$C¥D@ Ñ$‹„!0D†%àÑÈÿDDïúŸˆ Gx F aqP¨ †AA> p8…†á {N³DØn…£É<– ƒá!h%#ñxBÀŸapx"ÀaHØÿDÄîq3d…Ã(4T"‚ÕCÄ¢ 8’€Äp™„ÁöTøþ AD@Q0‡$P‚8ø-NBÃA%ÁI( í6tÔ ‘{2 ˆ #ÉpÆA Xœ…â¡X4Äá‘d,œ@„CvCîä.l  Âñh,‚%‘€°p$ìà‘ˆÃààA0„ŒAï†Ü7È]Üà0$Âà(N†agàa€-<Bc‘Dµ'äþÀÙ‚ÂÀ $ådáhü‘€{ƪ€“‰(@—($ –öŸû#¹‹E(‡ "’a€pá ‡‘±8<‹# `hÝÐÿ]0b)™ƒãxHÀQ„bX< …%£1‰ˆÇ€Ë{Žg?ì @{ÞE#/p7–àC¢P™„ FCC±x aa °=¹Ü< ä.‘€hÑpPÜH(Åð(€D< C&bñ$^JÏÙ ¹z@HØôÁ9cˆD2 ÀÑ Ÿ8,ø)8‹À# ($‚@Ä`÷ôØ~è!w ‡#­Á0€E@Û(’DBÂH0Š…QX€L(†ØÝ8l?ô€»€ÄBð€Æ@¯Á@IH<t[Ž\‚aAkD@p(½‡Ïaû¡„Ü$¸ †!"ÁÖáh@œd<R€'B , N8Œ@ÄШÝû¡„Ü$‰Aƒ&ƒ‡Áñ¨ ·tŽHÂ’ pŠ.€‘q»ü Û= äžFF¹‡ñ@òãQ _@1 $Àéd 4 X°tP¨= Û= $fO·…ÃY ‘$Çáw* P$ŽBA¢@Çï†Ü= ä.z´‘( 08('(M$A1x PÈ/ôvhØ=ß=Ð]ô@d‹%¥mH@“ C@°DÀXÀ÷@£÷Ôåþèî¢E$âH8Í ©€È`H$lšDB!xàKÐëðà'vCîè.zH4Ž!€Â&"q€‡#H8"‚€Ç‘ù¢±pØ7tW¹ìè.zp0@D’(h8°è":.‚ÁB0 wCîè.zHDй0x Í‰"È' €®  ¡ð@¼á<Ú ¹?z »è!‚n p; B„Á@@ OÆ‘ ðd"èê AB»!÷Gt=df4‚@L#(‚ŠÜA€Sˆ€DÄ-DÀ ²'äþè"C  o¡ÆQd$ ÚŒŒ ô€m`$488œ1 Š¢Ã@@Aáb‚vO±?z`»€Dãà ÿ“ $ ҉ࡉ²A$áça8"X>v÷Äû£¶ H %€o‡B(ªÇcà xà@¡‚ªŠ…w¥?bôÀ{Ѓ`ÁÂ0hD$C"’ € ”J…`PÀòa‰2vãÙ=°=úä„€> !`!0 PŠ 1ƒG"@’Ñ 3»j±?z`è=2 ,…D@x(47<OÀ>„Á¢I(°ª4l·Q öGl€ÈX }ð”FÅö$£p@Tb8?M øIà]Ú@üôìqfP"J1ö@â“ðXŠ\¦‡ª´ ÀÈ€ðQ$èžUîø. ÀJO!a±Šðƒ#€­]ƒÄ"€½Ç¢°X½7äþèï’ …a†¡hj8(2žbï0h( ÅA pŠÚ­Käþèïƒ@Ù@V€ÙJ"`x Ýq@c€œ†þhãÝû£¾‹Šq ¤/T(&ÊSÐ @Ôc@U"®Ý ¹?zà»èü…Áð!#€ˆ!£ˆ$ðpyÀˆBñ8Š1¦•´'äþèFbP@ÿ‚âýhjC†ãÁâÚ P H:â Fîø.z€£>K0@=dÐϱ ¤Cg@€!€…D¹rôÀÑ{7`‡ƒBP8<  ‘" I(2ÐnH4uãÈýÑßÓÎ(7 ’Á!!À{£€Î)ÍžŒÛ™7è#ví8rôÀwÑ¥èt8Õ¶J‡.ƒ~F àG#ï†Ü=ˆ=V ƒŠÜO¡@g Ì£È@P$Ày$<0h, ¿Û(û£±‹À=Ь)½J’€F@!8ŠFA•@§#€NÚ-"ÔþèAÀöÈ,; h€cƒ€î @„ÀÀ)cð Ø <…B±»'ŽÚ=ˆ½’ ¶G£àp,Eþ€=ÂqP1hH04»µrôì1mÄ#!5…„à@‡í ÚŠ"Ù@"R¼µ'äþèÙ;c„Â!€ÉgªôÔ 'AA×4 < 8jv×Q öGÏž!#ðÉ€¹‘2X°BPæP +Á9ÇúÔµrôì™2ÂQX<Š€ùÃâ‰D<¬ '€¢"PZ ¿+ Pû£gϘÜ .œŒNI ) ÊÌ 8plX@»!÷GÏž9#H 4‹€A…’Ð$4†ÜÃ!Ñd…ä€\ ™°ò¿ »§C…GÇDZ04X,˜'"¡ü-J½g`‹Ú={&Àˆ‚“%’ð4 ЇƒebQ,Ey¡±8`XI0à\PÐÝèýѳgÔˆÂbð”‘GQ†Ô ^(À#ÐH@!Cp0 wë½?zöÌA»Æ!ý€ “PXƒâH, ; 4bà9Ф]i€Þ={†x`Å€3jŽœ<Ç¡HйÇ#IH –üô.¡÷GÏža#P?@ô‘Il‰ÀBPD2†Ì/èk  €1Gýï kôþèÙ3lÄàÁ*@Aû $*†AÐ$Pö(‡¥Ì_Ñ„=ß={† (AŸF£p4¥HEàAs2H%`Oàl°xòn£@ïž=“A’ºŒYšŽ<ô0zÐÿP€u,ºÇ£÷GÏžÉ  ÀE½$à„Ä‚–N™‰á$|çåÊnÈýѳg2ˆ' )“ðw œAÁÈ Áa±d–ˆ‘@’ÉØ=޽/z {'ƒ ÊIX”LÄ‘€ú'Ø9 434H+‰¢Û@5ìNÕ÷EtÏdÇãÀÚ`ûDMõ#E JjçGapPo{ f_ô@÷ŒñÀ A½‰¥ G$‚ºœ  ¬ ð«Àí†Ü=PÈÞ¹:Ã@aÀzƒ hàJQÁb€Uƒƒ¿î…ˆ&B‘{¦˜}ÑÝ3ÆC x°àA‰d4…Â+úŸ„€‘Á¡ápht·÷`öEtïH!,°= £È@ID ádÊ üè‘{J³/z {ÆxD(žÑñ0p„ºMi°8p(X@Æp Ö½r_ô@÷ŒñȤ€ÄŒŽ´Óx½¢0ôp$Ü€Û³ñ}ÑÝ3ÆÃ+…r² J™¹BÆ€vxò Z.dï‰ï‹èž™`Pù€ÛPH4 àø¤‡…ààqp ¤7~O]îž½37 4` Ã €‰ý އ‰d"Ø/Eóã'ãQh |ÏÆ±û£gÏÌ h P­D"Dwƒ½#€„C!$Pp >AvOÈýѳgær‰Àá`@àA©@w^ï`”9+”° dju·Ô±û£gÏÌ J&K‡§LWÑç£Ð;šØ \x:š2ßÍ%vôì (I@a¹S7D"âÈ8Š Â’@Î X`wÊŠÝ=нèÁ8#¡à ÐP<Žƒa€ºm Ì0X (ÂzOÈýѳgŒ”88]4ÄS¦‹ @1 ç‚&~CãÐ8JKÞÖØýѳgŒJ C"AõãAoEÁ€)Aâ©Cœ:œHq¥pøžíØýѳgŒGYðÊ”(àB!0À@” |9¤è$<„¸Û(°û£gÏŒ=  P-Ìœ-Œ¤`‰ Á``DЖÈhð›]1ˆÝ=°½2 ÅàÈ 7Bˆh`  ï Z@° §ïy+Ù>{†n,`s(D Ö tðæ,GÄAÉX4 (ŽˆÜsü왺Q‹@PÊ…¥( ‰Ãb$R^ÿÁý|Íž˜ûhÏØ $Ÿòn™@S0ÐâìÁïá$ 82°³ç½!dí‰ ø l–ÿDÊWà`°deÈŒÄÁ½…"ïÝûþÚ3ËÄ€èÆcd<`G"0è X ¡|Î2lžñ hˆûÇÜK8PNñ2°kd 7‚òŽ ”( îð{bî¢=Ó<àuÑD,”ò.…òZØ2B&€fIÆ“€ˆ •#ˆd螘û£hÏ8È5‚#@ €h%uB€;ÒòÔ+… î‰ù_`´‹L€I PU–|$…'A)/lqP°^ð·pòž˜ûãhÏ@¤œ²Cåí8pXŠ4? ÀŽAy„H%4íÉ羟ü/1)B(*<¨&Šû!ˆÀbp(åE" 4hó{bî£=SB,I+Å“áHP5$åË päà Àžb€ý§¼6ÞSóû~xbî∅B€A!Ÿ #®¤¼‚Ea)ß­ÀÑ8  Aì‘ÄÐ}¿<1wñÞ¬H)Iå;pfP°HʘOyg€â1{ó¹?Žö Á*e’ HÐÊ@k6ˆ!¢€à"SÞ±"Ñh j1¨=ØÜ÷Ûs›xÊ÷M (FÁx,0(2¸L,Uà+q8ÈÞ½ï£=£BÊ—X0ˆpE¸ÊAB€íÅÀ”WŠ`•Š&ö||°ÿ×{c¢9bÑ≠“H€ÑX<„)¨|\pmD,vOÌýq´gþÎ…#0$ j@+¾äøkÊû Y,‰24 'pÚè½1÷ÇÑž9$0€9aœ”¯þ€‚‡A@; XÐ…a(R8”´§>÷ÿºg êGJ…bƒ%á‰G$øXO4|,è{ësí™D¢@Û*‹Q0D(ð[`3ˆDÀvå5$üÚsíEÈ8€x"à  ƒ’PXФ ˆŠD†÷ ¬½§æ÷ÿºg ¶v‹!›ŠIgBÔ„@ê¤x%P¨Œ=1ÿ Žö`“€6 T"úÿ¢î_sEI–ì<¿{œ!?4Ÿ‚ÔÅF±š€fßߊ$¸m ¾%èG­›uëfž<ÇwD¸›Ù2óeËââLµýYºrZ%¯ßÕáUÌšo;2ÕÈZ'À°9æ`ðÈ‹†xFCW“ýËgmÖ|Û‘)GîåGI_5næDvPîð%ÅrˆÃ}ó1su˜}Ó¼©G ;¤FÄÁ`òO¤ˆ2ùu·Â,ƒdÖ|Û‘Y“kF·Ç¨×‰Ò‹'Tí´\]˜]¸±ûœo;2E΄!¥FšÀjø7v#±v îDYä,ñð†ãàߌoªœGa¯›%E¿–ßs.þñ‰ìÝÆ!õ0k¾íÈ”9çV‘¯EŠwµÒãàx’—á›ñÓ5Þ}L|s|¶éëÖmñ&/, ’»Ì´…(Ïnˆgá­_z“¼¥@îYZr÷I–9RÕΉ×‰cºc¿ÓxM.óf%xSétºõ2¥[’#ÌÝ“ w WawV­‡š×½i vÍ|ñÄ z`2 ŽD³óú„vñä `· 0›5ÿ°#s—.ˆÌÄÚïÉ¥‰!”*ٟ؃HH\fßýiGÁÔOcs9¤(nß|K!ÓpgåA£Mi§·dÍ73!˜êpx̄Ż 4(‹oÞ‰Û¼?¦L¬`×|ÚQ0ÜÊDöŸñ4ùc‡ÏŠŽÆËs”2[¥ï™ ]óÍM¦*;OàŽ Þè³VÙ¾Ž t˜WT–ô€zû=ŸvœÍ‹Yž9|K.‰Àäà ¹%OhºÅ¬ù´£àìDžsàDÝÁ¿÷9r¯ºK/“„yxËd2~éMO°kê²Z·  -¢ûèŽüŠ'£œxƒhæµîi*,þÍO¦Ø‹ŸËä…ADÕ+hè”Áµ*šBÞ£êª0˜w‚©öby ó)ªÔéààŠ"Î#ÜJnWI7Uç·wËþÍP¦ÜKjAÄÞ"Ö£›|ý&åjìOÇÂÖ&öaiÔØÑmÞÚî`ÏS yà1±ÓŸZ*“\uÊ=‹9óoŽB0¼Íˆo0_/?€ì0§P\7ûþ&-SO.n¸±‰Æ5$Ý“’Dö,'Y@¼}óMÖ±uÚ7kÁ®I*yó:ñ¨É]×É‚c[`Np8G·^vµ˜öM[¦F=vrSÄ€;i_tWw®)ªËé”4Ù¥¥ŠYómG¦F xk)c>)¦sõßào%l¦s&€„œ çlkéoâB°5j‚Et™D ã&IXãé@RÕÒ -ŒØÁËîÑvdjÔ¢¶ b˜ºw±&ß]ȳ®­Ä¸Uq%‡}÷·™z2®ìLâðš©FˆJ±Jo Î(Þ1­¯{s‚©'—<±“”ÖG²UÒò Z°M|'ø$brØ7yÁ® n%âRe‡~` é JBBØKsºu­_z³B´d¼Ç3ã; A8¥FØãdÚd}b§æÌ¿é ÁÔ¨’8Q0 xß~1B*X‚`ÓV^bÎü›¿,™5NÍ7¬\û”…Š ­tÉO™¤iaŽÆ/½ ÁÔ¨ù®áÅ6 ¡µŒÈÑÁ¿©¨¸T~ÀÁTÞ †`êÉ€›—ú…âI í°[`Ï1uó<õè9Û5ßvdêÉàÖLäñ½åQVÍ¿øÂªúîÀL9ó!Ìù|s‚©'s*‰ðg°Ç[î´å[É™TdÛ ·2Óö{þaG6×vÄ]ßòÉ6B™ëÞë½]­b8®mÛAß,†ð«Fݨ&ª¹rµäFžÓm”n Ër¹Ç;m~ô¦1S£Æ±¹õAy"ü9$šµ2œ«wO¶Hnx­±¼y ÁÔ¨oè@ÁWãß«ï…uú\£å¹3>Ä•‘3æiÖ|Û‘©QNÑPòZX3O°ŽÃTo%èJ„)g(¨þÍd¦ž\ÓRÕQÞ:{侀igì¼ i<lÞ%‡YómG–׊=s>‰¤©î¡{î„7í@:¸®Ë¥ccÜ›Ë`× ºzû›küç›ÍLz]QúÖÉÝþæ™;F¤[¥C“%·ßómG¦F­+¼ƒ3­©!‰ƒu >Êr1ЂIa¶ÞPâý›Ï,_Ö{b;î8lq©â©d‡|Œ‰Yf%F•زÂÏs†7Ÿ!˜u‰l:I`RiNø)éÞ¤ÇpošøcHñáÍg¦Fu¥ß‡Î¨'Kðûª¯¾è¦ª²ãëäÚެù¶#³&ž?£ÚA I+×Åè󨄃/mÓÉùæ3S÷ ãå#gÁݲ}žtü(LШºÓ€ŠâZü¬ù¶#S£&Gå$—PÎi>bÔ!ªÄ#¶’oÙý1­¶o>C05êUåyA_Ý‘< “¸ã•EÞSå†?¤0k¾íÈÔ¨[ã(¤ð°¹ÖÉi/£Ws¬±t-·ì÷|Û‘©QGÜv”NìjDc«A´ÛÒp©9_ ïÚ³ô¶#S£näi-ƒ[9M÷jƒH²ž:E ðèóhåWÏöÛŽlÝûêFÍÙ]ŽHŽ„ Ö…¢{¾Ã3ÿÄÍðæ3S÷Îu‰kͿͷãERÐM’oÃ}‘Øy¼ç˜æ^;¼ù ÁÔ¨ “»g¯ãR\+*]u°LWù†t9÷AeÁ6—ÿaG&/Þ· ,$mǽÎÈ  ã«ü!{ß~8ûœO;Š–ã«ªù&A2¹;ôÒìUwº2#GÀWä’‰ÅáÍgˆ¦FÝ{µã+ú‹’¸¶Rß³Ð}==t¿Ý£§ES£®ah·[Ë¡Šíˆ#]ÛÍÙ‚ÛƒÍKE‚4g˜5ŸvMÚ…Áw$¦9õþÍŸµ&épþ)¯PÒ½éä o>ƒ]³Ša”Öºrµâ•vëò|H^€¿MÁmìèÍgˆÎ6’i¡ïÙq9àˆÃ߃ÔsÌñÚåŸ#a|ò›ÏMžËò^£y]Ýí‹6u[Eæ-Švjæ{¾ù ÑÖ¨g!½ŒA´5ð7þ¢,,}/Gü8¡¦A$¸Óøä7Ÿ!Za=æÍêX×bçúm‹ÿ8N˜'í& Þͽù ÑÔ¨ƒZ¡‘‘œ¸]òÕX²$gðÏ$ÊÓ%KÛ>çvdšW°@¢åÙ¤ÜJ>ï˜E‰Q‘ä¡ ‚©©†7Ÿá÷š¤èÙåG.°=“ôF옶ðƒäb&½ù ÑÔ½x^…}’e.f©YÑwzÀ\ÒÑi`'ûœo;²5êÕt½¥‘nŽz¾”)qÇ݃Ÿd=n#Xðæ3DS£&©qx€Wí÷Šo0‰ %]ôD0ý¹ªbØwÛ‘©QëDs¬±õ&éž|%Ñ»8øÚ|‰IwÛ¼ù ÑÔ¨SUóËV¸[RÔÒ×Ä!>ré5ôÜ9=ö9ß|†hjÔî\NA㪊Z¦äTúÇökt .¨@o¿ç›Ï`׬ø¶¤íÄÃÆr¿ßåÏŽe’o-29ÃÙ o>C4uoξº-%@õCK¬¢“!^Is4i1Ýs 99¼ù ÑÔ¨í“_Tr±.¡ D¶Z¯ÁľÚ9߃{cïo>Cô6/Ç{Ð;\0rP.ôoŸ-ª7!T¯Ž»GØ‘ÁÞœžIÉÈxÃÿ o>C45jrfEݪnÑW*ð¡èâ9¨—‚Ø„µ¸îÍgˆ¦FMxw¾]Ë¢|f\žãЊd›ÆØ`uòæ3D«Š@<÷1ÞpÕEC/ ¤2q© JÁx»9Ÿo>ƒ]Ó5|Ûit·@67Ÿø8Ý$ó€qù×ýaG?ö>ø„äÆc4l~âáñË‹L#é6>lT¾uZ_÷æ3Ä`{Ž€CÆ Š*k\$`d NW^™ÌˆÀqM})¼ù ÑÔ½oS—V~}×Ex 1žWŒÎùj{VšYómGVm!“%H° ôÞ¥öÈB¤‚àØQ;Г_"%ã?ß|†hjÔ·j—ͪ‘é0¥¼váÔ;/YRM9[q§·™uo ø‘®ç/Â8@Ü'eÚ•ß›Éáñ$q6SKo>ƒ]3ÏÊ‚Ž°Íñg¨ Äøö;H¶ŠˆÊ6×~ó¢©{Ç8ÇÜ?q®:Õðp³‹çï X»œÍãÞ|†hêÞA*E<ÝCj°7I¹_Pä5i«­›œëÍgˆVÆákÇ%=ƒ+ý6ÂRämÁ3ê–!Òu'Vµ±£7Ÿ!šº÷híø²=×gÑõÚ§’ëiÒ³Ps¨9óo>C´Bg¸º{ŒgÕÀñ´QËXSÕõyÀ¬ù‡ÙXœÏÌÄáÀ)WKÔdÚñ@P5»pG´:{áÍg°kú( |>òNI¤q¬6s”i€‹¹ã o>C4uïJY`K$Ë«ó¥z7Ö™­Š8U[6ïþæ3DS÷>=/É@`ÜìÆ‘Y“7’jV–Š”KÓu›¿ù ÑÖ½ñœêév8ß¿Fç´ðo≋3䯶ùžo>CL¶!})ßÙRzÂ͹”8–ÉOýÕFÛô‡7Ÿ!šõééã„ã4ÄÐ b Z@ã—˜½é;0š5ßvdjÔ©à<=@ [ÁßßFœ¤Íc¨‹·pä"æþ=¼ù vMIárÌIæaL“Öw‰~j€Ž­ñÉo>C´*Ãü…?ERËIÕþ˃KMuïŒÛRD vßßvdêÞdo€£/f‰«ò| qž¹jfÙñIŒO~óbú¥9S¸äwÞE4›º>éàQ°/ñ èÍJxó¢­{Ï-},ÒË/Š{¨3 ÷GÊxE/ÝKukã?ß|†hjÔóÔàúPõ¢ôÛæ¸Æ víÈ®ÉÁÉsKôiEöšücrúÅ„’ïpΡÏ?ÿæ3$S÷æ,Ýx®$Ýå ä‡hDB„yòÌEMNœVoßýiGÉY%’Ò)âJ=¡ÍÕ—tk+ÁíTõv1¦’Ñõo>C2uïôK^ów•¸$E¶:ùBεo>ƒ]Su´#!Ô"­f6·¥Q]\‹{é6ag{WÛÏLÝ›ÎMjnZ":§²×l_A•0å+ ¹\÷æ3$S÷æóÜ¥fçB&ùǨJ7÷¼xâÉ1áÔîûÛŽ,7[”µRwR7$Ä_Ôx8ðËGü‡„|ÿ|ó’©{š¯.KÛŒ0|wàT €nÀgoÀ‡,‡<¼ù ÉÔ½K& Is†„ „©–XÒy|æmôȹUÓèü±÷øæ3$S£žnr¦#&xƇ‹X›H:È\³?©òŒ–Ìšo;²Àl°šEc9&7Œo>Cò¶OªãèØ‹o K}MñŽCYb^ªE•0kþaGÆÞƒXP%œ0ö¤ÜN48ÑÊæ°bÀ4Ãûo>C2uïBæ—JˆÕí.B+þ²7¸7.þ£I•˜5ßvde€»:ä›DãtR®/Ë.œê_ ½±–‘óo>ï5'îˆØ˜PsóL ýöO”Ïí[ »|ˆàŽ ¾©kˆ#•z´õÏøæ3¤`5 ÀrC¥åá)BéÞïD"ïºCöl˜y÷7Ÿ!™º·dW¢¸Ý¤sNå)ô]Æ9+J`ÃÿŒo>C2uï‚bµ“‡»1AGJ€:ƒP¢ÈYùÆ6ß|†djÔšCC²ÎÞ³Çm¶Cæ·M]«ä±›æ‚ ìs¾íÈò½yiÕ?Ù[‹Ê‹2‘Óda\AÐ Ú›fÍ?ìÈôbÈÓ‰<}î8vµz`yHÞ1\]Iמ¥?ìÈö^iŽL¯MÇ<Û•ÐÅ^2~Œ'%¦ÂˆvÍ·™º÷έh ~ÏËgì¼.Æ(M >.ZÓ…²QPó’­{OI­Jåð–.±ë&m\ã)›Œ$ªÕÉœÏ7Ÿ!Yýt2hC$‚QU8kÞ‘.ˆ šàa£XtZÊÆ6ß|†djÔx9pŸîŽì¦îÅçp‰daæ3•@(Éj:Å7ŸÁ®IžnÌ»6¡zÐü’º‹FQd\ÞA¾ÕÔ?ã›ÏLÝ;G•)„NÒšmrôÝüç6†\©ŽÜIEJµk¾íÈÔ½%ðQ—|0ÈCJïêìÒPìš*€<¦8¾ù ÉÔ½9ó[‚k“tØEe„ƒ|‹”¸ã—CæˆV©ç˜3ÿæ3$S÷vµR¿yyØÈ»«×aWµS }*@'°¢±÷7Ÿ!ÙYlÎSÉ ŽDß²%ª-å‹¥.¹Ìé•ÌÉ0~éÍgH¦F-¥ò]Å™&zßÉ‘ ©I}׃óı–ð–YómGfÍÕÝä…Gaç]¾êjý„oîÈÊœ„HÀÛæ¾8¾ù ÉÔ½/a"Ü âañLÄÚÉŽñø¥°Ú”¦Ñ‰o>C2uïâ›<ÆŽºÞ%v0’zyqÅßbÞKê´fÍ·™º7~S·»ÁIè_Ùß &;ù´’N‹3µ‹øæ3$Ë÷R0 @wÍ(¤tmdmuÖt<4°Âœù7Ÿ!™º7È8ªN˜µø»ø-ýR±MœˆÎÚÞ/{æßvdjÔÂØ-Æ}ú&Hpêk«Ä¥9$HBøÀNWOÜÿXóÍg°kêÆw—±BN½ô–ز¡dØép‚q®–{ß|†dêÞ„¸ÈÛ‚Œ+.݉“ÕÜ@žP# j-³ævôcï’uRJâRÆyG]û?5m9etfͧeS÷ÞjUõ½°ïøµŽ/1ŒjØX&ÝFwD´4k>í(›º÷e“œndº'†ÚÈ_¯¯UÓGö¹Ÿ~ç6|ïøæ3d[÷^ ˜#dØgÔ„2âÏžQ‘ç~1Ž\~6ûîO;ʦFÝy6@{ÛSÓµøÄê›KMMìdȹp˜–‚õæ3Ø5››JŒ9â™[­ÕW4ñê MÛéì»?í([ùé[Ø œ\×5~”Þvñ”öI­u¿rSJoßýiGÙÙX|ËrÃÑ&U6¡€5¦NeQ•XŠÑ)o>C6uïs4 3Ƚ‘ýã<¤½ÅgõÇ;õÄ¥.*»Go>C6uo/ö¬LNÒX8P_t!DZ¬ôÜ7·ÎÖ¬Þ|†lêÞÅã„4HkçʱT™J¾SÑIWJý*c*FÕ:¾ù ÙÔ¨ÁŸ s&c¹’õº1­;÷ý³T:³T: yóìšk–Ö4ÿ@¢¾âÀf…ï)ÁJ\`­hžÉ7ß|†ü‹ïÿœû¯°Bú‡¸]Qƒ¨F1€šYómG¦îMz}W&h'2-ñv2o!úgxe™Xš!kÖ|Û‘©{»@0›dUW HK‚.ÞãŸÙ¹¯X]ˆe½ßøæ3d;¢nþSñÂñ¦E”kRDãH–ª ‹I')‰¿Ö|Û‘©{‹ÅŸ4ak IUÝÁ„…éß*-å:±ÿ“w¼ù Ù[‚-JD;dDKýlA&$š‘ 7RKç´5s¿ß|»fnê Ô~UØøâE»^ µ8{2:>«Öö¶#S÷N7D1öÀZ­Üë9£Uìö³n_ÂKÈ.Ûšê›Ï-ß[ãÁ¥´íÖmGT›*ºªŸâ¼6u–ãñ²éaŒo>C¶š$«l:a«Š† ŒÜa“{,«ÁÑéŽÏØÑ›ÏM݈½ÅíWï*.'·Ll 3uÕ@¿zÃ7k×ÄŽ7Ÿ!›ºwÝÄ52Œs›Û¡HL ð_ñaú¢™©Fc0¾ù ÙÔ¨;<ÁÃE\ v ƒ5 ¬è~…ÏÀ×6=àñÍgÈ¿¸ÙœOį:ÃÈŸ”4§¤Œ«ÖÀî ÿ3¾ù vÍ%ܪIpx¼p5únµ“6GY!ÇàÞØ²ÍãÞ|†lêÞ“]&RÉŽI:"tÐiü·çEž  (¢i›5ßvdêÞDÊ<ã×Å£d·>u_ì“ԫϬXºØ=;¡ðmG¦îÍL«»} kXvŽÝ§9g.eK|ó²©{k´gÃø¦ÆüÅÓÞH´L½éÒçkÛ7ã“ß|†l¹Ùcù“n%÷šb.ùæ9ÙN$ÈP;Ç?Û:í›ÏMšl:’Zº¿æOÉ쯚çì¥ëjRšƒ¸{–Þ|»&±¨‰1KÖºcgKWr Î蘢)«¡Y’£fÍ?ìÈZ&+$±Ënh¯1Û ’'ÀÇ+Ù›S«ØwÎàä7Ÿ![Ýl‰®=Ï —³Î‰vú“šôënïd4øT3†)¾ù ÙÔ½§ÛìXAÍ-ÒoœþëËWi퀼´öš­Ó¾ù ÙÔ½5–[UIÝFMßGÕ„Ó$2v/íê4ˆl:s>ß|†ljÔj’˜©©Ee¿®)VN‘5ªÕÌT½kÉôõÄ7Ÿ![M’õÉŒµ&âšâ‡úK‡ôÎ]ˆüéq‘Øš¸ùæ3Ø5#x^>­…9²J@ß83@'‡¬òIkj*Z¿ôæ3dS÷þxo³÷v@¥_k/›fÔ,ƒúÒÑ4‚iê!o>C6uï]‰Æká‘ÃH˜{‘‚ööê¼ 8úZ¤ô±ì½Ì›Ï£Õ ªXfxÒNÉÙhl_Gj·]úˆi'Û¾ù ÙÔ½Û7I“·|ÿÜÇoÆHïá®ZÊ‘¦I„}Î?ìÈLî[w5é!:0èV£•¸¿*|“‚ÍÎðEèÛ¬ù¶#«IrªúÜ%µOž@æšø•~œ„ѦÒÍHJS ‡'½ù ÙÔ¨ãîÇpf'Ö'Årø‹—é'ï5ÝèH¤7Ÿáך€§z¤¤Z`½Ýºyk@xl¹ªãN¼žÑ=Ho>C6uï"nñÀ¬&Eîë$½æT¼ÓŸ:‚zfÍ·™º·DÙòË™á(nMTÚ)œ¢;ß-‰¢jò£ôæ3dS÷VRXœ­)¬!)‘½~Cçøb`©°cÖ|Û‘àzW%L¢+¤,¶v«da÷¬|±±nzÓ›Ï-7cW/¬æÔ²oê‡ô ã½À`ü;eû=ßvd5I”®ðåÔÆwÆçA&3«&,‘ËŸk´:Ó›Ï`×ìã&ï9?ål\©dHê7Ä|¤oV¥èÙX®}÷?ìÈÄb .n} !ôº"ù¦fÞd) ~³Ÿ¥šOˆÿYóÍgȦî-•¡0ºÚ›.)†ŠÊþã…–eúü¼n‡Ò¾ù Ùjq6àl®.ŠîG>c¦zçâÜ#ñìn4ñÒ›Ï-ß[ê€ø$ü2N^Œ pBA,L¨iÞ9Æ5˜ß|†œm^Ì'œ`™¨6"á¾ #Ýî»t2ºªÉWfÔmzór¶¶†ú€Á Ûk®|ÒAHCŠ}§òæ. rG3ÖùÍg°kêŽt’ˆÌ¤dûH1FwÒ^ïkð~©üz÷·™ºw\Ø {á{Ó^¡z %; dË jþG4ºÄéÍgȶîÍúŠˆœZÀr*?â~{ ƒâi%NsM¾™Þ|†ükæ –]¤ÆAjU–$Q)AbNYšñ0Íšo;²uïzZ{eiÖ™K2©´«èR#8šZPzó²©Q“¹}ÄasÛšI uRÕpÄÐR5•ÚÜE¦7Ÿ![nvÆÏo M.Žà{%ÉÁrCt@×>”ÒqüÆ6ß|†bjÔ«ƒ{½ø^L&wIçzMNÞS­ü0z2|›ôæ3Ø5Ï7η†K3”Ö xFÓ™¤Å3A®¿ýæ3S÷Û“¨=ý‚kQOS¹ PYé& V%£5ûþæ3[÷h Ý<øx÷ ©ø7@zâ¶Ïù´£bjÔàa 0ó¤šTAJãjßžDP¯Ç·µ“áŸvTL¬™Â>ä„ < ;¬‚œÀ=cià|QÝÚô8¤7Ÿ¡˜õ”ˆõwíÕOhê¿Á5KJ¤O n©–—¢éßLo>C15j5˜¶™äZA}ÚX¼.~nd-2z]-˜™¿éÍg°k2£I‚žf f“h®X`ã%‘V‡µ÷7Ÿ¡˜º·šžEòÔ͸´_Ç”¶(Dsºnm"†ùìšØ‘éÅh}m^rb‰S»LþHoØ÷¬ùE¡n«-™Þ|†b5IؘAª! ÃÄë«çÇÄØAÕkÕÂÌšo;25êÂ2Œ05ððÅɬbDÖZç{‰.XŸüæ3S£.Z@’9u{ÑÕ¡iŒ×ˆ¢:"ñ(XNizóŠ©QkjòjÙ’O%ÍèÒ_9`Ø#f&ɵӛÏ`×çž&Þ‚Ð}´’¾£ö¸‹ªª’½6k¾íÈêœL@·æ }µ: NÖ8÷+ŠA£Ì㾩¦ÆŽÞ|†bêÞ­&ê[_ZdÕFüÀruS"7.»nîôÓ›ÏPLºh ¤ÃÓã•ÊUŸÕmGh5H3ˆvRï3k¾íÈÔ¨ÉT$@«º€ú"Å6›Yé×fÃÚTÍ^ƒÁ´o>C15êÐ}#IŇÖ2ÂV׿¨ãÓ<ÀYÍ‘,³™;ýôæ3[£ÆÊ tr8Ž)Ñ’szn:Û·Ó@7¿bíèÍg°k*]UÛÉѽ^Á ‰xôi6ÆÖIä¯>‚3Ýôæ3[÷æQÔ~Eª:„Hþu§©)î²ít¬ÿ|óŠ­{·ÕGž‡€é¾O“ºù)ºžÅ¹†$ìšo;2uïQ²Tø[(ðˆ.I…/’9]U³ÀÌšo;25j’óš: pÕ˜®öÐ+ŠYRü.è’Æ¶8»Go;25ê¦¡Ñ ·ÆoŒS )ÆJƤVXÔAŽÛÔÁÒ›ÏPLÚ2X@w([ŒÒðE N€/H€|ŒFÂl±÷›Ï`×TSGQBû$ yÖUƒÙÍq¬. q);&S«Lo>C1uï©6X`’nšÕT‰§'qbÈŒ¬Xœ»P¯ÁŸo>C1uo@1ÁÈë¯Z]Ùhí¾ÈÚÏQþ®’ís¾íÈ΋,š+A$BΪDæî—©êvŒÓã4šöéÍg(¦F p[d¯œw¡Œbêiì7hlw2FÎ)¿}lûœØÑmæëÖÖ¡4Ïi ºsªnH_#ibÒeé’Ý÷·™µ‹bñ¬â6‰ÛØS¢§gËçZêâG¶¹›Ho>C15jºžèÈÊ'kFy bÂù"qüŸªŒ&½ù vMâWþ†ŒöAN‰ ^¢u¡å)Õ0žºŸvþYóÍg(¦îŸÈîm±¾…”Îé¾³ÿ‡ÇïÄO¹kæw¤7Ÿ¡˜º7 «ãS‚† ¸ûyfrA‚¨¦?Õ% Ìo†¢YómG¦F½Euß\ÎrÔ5bÖh"Š“3*1ÞozóŠ©Q5;㑞mj!ÛCÒu0wétÉa˜5ßvíÌšÜg–²/¾s5²O  úyå9Ûcrä_ßómG¦F-˜ ë¬3ÆIê´$Ñ!bÆÕÓa×ID3(rÙ}ÛQ´}Їœmø¡ÁQ²1E½°˜BJ]Qår=¦žœÞ|†bêÞ½àqO—&¨&•/4œ©h€èÍCjâFk.½ù ÅÔ½5RA Ô傿’Rn0Ù ºÝR›Ë½¹u;ûîo;2uo^ÜSCvsá•TtùZ»–ò›•¥S󳿛ÏPLšãÒ9@ª)®‘49>ž…ï Ï]½Ç‚åÙìû›ÏPì¼ÈØ›¤a<‘¨hLj Ù•È…«¤Æñ@¨k°÷›ÏPLšGñE¥¯Ø‰ïÀdcγ関z6 O:jbñ›Ï`׌óæÈÉL¸"uñ­ÝWW”ÞÇö]zi0k¾íÈÔ½Á!Ò‡'ý'ÕZfAòF$"ÒiÀô%Ç»æÛŽLÝû,ÕzÝ–ø|p7c>—?–·®y5º­afÍ·™º·˜OÞÍÚšÈàPçp{A^“q+šè²íšo;25êY5¶ØƒÝýô+Ylûn>4f*I­¸s§ŸÞ|†bjÔiªŒzþ¼¬îU]HÃH$j¨V­+[[{óŠ©Q÷¦1M@¦‰7Ïÿú€"’k`Á½1ÑÔ³ÑIo>C15ê¾ëjŽÔÒ];'<,]øDR íÁ•hÞ¡áÓ¦7ŸÁ®©á²ê‘+|ÓÓ8|š0ù(uür Å1¶ùæ3S÷>Ž`«ÂÅõì2ÄÄ]Ìâÿ§[¦ô“§Á6o>C1uïæØ±–6VoâF7)ˆ|ž.Ê31yHXÄĸ7Ÿ¡X-nrw)ÑVüHÕR¬jGؤ+óŒõĴƯwÛ‘©Q“_u«ÔÕe[9‹@nÒ-Rø¶Ô@ϯ9õéÍg(¦Fݦ½å—F`¸–ÔXß²&©iíÄQQŸÍšo;25jïr øjæ¾c&–„û4EŒÏáRº±N»æÛ޲ïÅ-¬Ñ ͨR%ašF_E£æÓuÍä›o>CÉÖÞ§¦Ô,¦RáL2Ö'§k„¾ñþu÷æ3S÷ÖLC #òd^‹D+zÉ¸Žª4¿v=#îkzóŠåf¯!Š@PÇ a]¦sW&Þ17C5uïÀ¾ã–ywÉÈNÝ›TµìÂ>þ ýÓð3³æÓŽªåf«ß¤®åó]j² }jì¤u¾6Mñ² S»xóª©{“J`)r ¢s}¬LÚÀuçú :ÓVÓ‹­¾ù ÕÔ¨CcSpøòVJ_Õw5CƒÇ>‘ï3¥ÙœL\~óª©Qkdµ °¨ÇnIÛ]3îÔÀL¦«Œ³¨™ÝôØæ7Ÿ¡Úµ&ÌUPs§ŠÐ|›æ¨i—pÔŽÒ·}Î?ìÈÞI•Gýjªé*«ª_{rùFJÛ å6cGùÍg°k’Œ³vTËÄÈ`ºÛ$¼æ4§}‚€"’'fÍ·Yn6 [õ$­Ê6r‰RÛŠ¾j\׬ŠÄ)’æûœo;ú¥ÅíËõ{ÍØê‘Œ7"86—%ô•§tYÂ6k¾íÈÔ¨‡æ,\°®>á ²¿wkÌpk”¤œís¾íÈj’„æÕ#qæ7dÂUu‡I.¢žðòÑÛ}Û‘©Q³ÎpUµ5¶{i©K>œIµ.ÙXYøÔ>çÛŽlZ$57è­(Χ ‰÷ó€Ê4þn‘ÝmÉüæ3Ø5ož¬èT’¯¸wÍO$p’ihØÆ» îñ5k¾íÈÔ½Eûä_äá4üYÓ4§¼Jvc™M R24k¾íÈ΋¼dÕ®’V&R¡pCaõ¬IÃzñIfvF'?¿ù Õ[~Hà…õHüz $ amM‡šEu&à’Sep™5ÿ°#Ó¹ÄwÝA$žàqÄx|ÇÑ?q¸©A— ÇM_y~óª©Qã ŸüÀ{±%!L*bh)›Oáì½íè7[¥%‚×8Þ4»4‚c*4«ˆšÃhóæ7ŸÁ® 6R®ÅKJ¹é”QÕÓµ}îˆfÉ•BYvÞvdêÞl…ZCôÆšõ–¯# ÕC¢à%™Þ%ïÏÚ=zÛ‘©{wÝd{ñºJYǨàú(Y©Yu8l/ .cGo>Cµ5ê)ÉìYo(%Û"m]Í{Ø;J3,¿ù ÕÔ¨Ó•öˆ;‡@‹¨É›ý¿RÊ"› Ÿ»”Ìšo;²Ül½4¶1R¨ÇçS·‡+¶¯$ÙÉÚMÇ®ù¶#[£Žë§fEÖîHÇÚêØ¢xšY„mÕ›–ÑšËo>ƒ]óô+ÆoOâ‘—HòÒSSÕVj,[Q˜Ü£:û=ÿ°#ƒ½ îÛ ¹6PÓ]÷_ÿ»Ú7«FmEMÒ3kþaGF‹[œùSTN;`0ÝEuMÒk°+ßàŽ=Ko;2uoݹ‘?0FZØÖ$‹­ý¨1!ÞªK3k8¿ù ÕÔ¨Ýq3’dàÙ|jêãTR –ËØnÌEÀ8ÑîûÛŽLÚ•¦!?ší'†?Ç€lwOb¬èI6üÑøù7Ÿ¡šuc~ÌÐVós¯ß|»æ×n£ˆAè1ÄLƒ­’=±ô;{5sšò›ÏPMÝûzWxž >‡¦¸z‡M¹ŠÓÜ@¨*ŽÑBÌo>Cµš$‰ààNÓ´QpvôõàÍlsH—=ÇkßýmG–›½†F(Í:4±iÍÝH*·ˆê]?1„dgä7Ÿ¡šuî*¥{9§Fì”pn]Ä8ï‡Hb³8»ïo;25jÍ ôlÌÃ…*ùÂ,—3%=b)$¨±ÇαÍo>CµZÜÔˆGä¶%‚b$ES,8ΔÌÿ •[ÍšØQ·8d"/ÍÉF}בsÝ#\h—pT+ö{¾íÈÔ½ÙÔ¢Ž«(®¿ÔH6žxhóäsŒä6æ|¾ù ÕÖ½Nól½&Ì<Žfâj¬®EüÈÁHF{*¿ù ÕÔ½¯€àÓPIVsKb&E à„ŸÔãU’`Ö|Û‘Õâ>ã’¨ 4â~dwgÑNü@ùÙùÀRÞ4k¾íÈÔ¨JD-±j"œèKBxJŸIMœ³‰)¦ûœo;25j 4úÂé^-´4öš¬#”“¾Y¤¸Ä€[ì½íÈ®™ÈÕ_*J”pòš§7òƒ£$¡æýn´¸ó›ÏPí Ê“ãÌ­ÏR%aN¨ïÄJ~g Åß𹓵÷7Ÿ¡šºwmÉO6ji pøš|È.Õg84¼Â}“_9_fÍ·YM5€_5óšµ+P*¨·.a«4ïýœmýç›ÏPMÝ{OFX¾©!-yŽ0§†$žIsŸÌ¤Ñ)Ío>Cµ3( ™`YÜÑ!‘Rã$­†VÎco4;G,¿ù ÕÔ¨r ž,ìÃY#x¹Nn‡âʤ¢ÞÌ—Éo>ƒ]S¬^½1ئ›½H#ļ–o;Å nÎa×|Û‘©{·—穼ÆÊkb(~Æ&'<Êj‰½ÛwÛ‘©{O\ÑpAî(Þ–º¨Þä\K3‚D$ßÙ ï7¿ù ÕÔ½ñ¸ù°Ó9 â(¥Zá¹Dè[äÆwÂh0½ùÍg¨¦î‹”ħˆ +Õ`ÒQu„‹mêô“8=¾ù ÕÔ¨qH¸vBçI%NMC™^“=æã[+áfÑøŒ½ù ÕÔ¨¥Â{§äxñŸ…Ã-ýµ0Äèq=ç­‰>»Go;Ê–FtàéZl;ÉoìÚ‘fxOï`íŒVR~óìšòg[›"5QÜ|Ñh!¾C÷3’È!€Slûæ3TS÷ÖNL¯«D]¼ãHº×,NÂúé@¢¨,1]³æÓŽš©{pºzŠÉc4ž¦ì®QUSzcõ¨‡@ÓxK²k>í¨™ºw’´³èø< nlÎJÞµnTÒåâß>»á˜å7Ÿ¡™u"Z\Mõ­­ ]íx R0 3-Åi¶HRƒ½ù ÍÙ^Œèª˜@ ¬Æô6$KL’ìnÆÝ™â¼fP~óš©Q_WÁo^ Œ™Thhîâš’izHâÀÉZÙ>çÓŽìš{H퀔eö¼g¿ÇnÂ9‡ÙzõÓgfPæ7Ÿ¡YM0›&Ž£I±º¿çȳ-¤ÈMt¸ÞÚx³æÓŽšA©ŠT¡€N½{ä¬ðÓ¥…;‚ÏßÈG3w ¿ù ÍÔ½*Ò.K¡1ï~÷×ɆÇ}ˆÆµÝÀï'sw–ß|†fêÞyÅ*ËFB/™›$™Á\x?)+/7·êOÝ>çvdø!+‡È¹ÆŽâ¯L]Î\éI‘ {J9—}η™µ(F#€ÀCnä°êß㳑p‰9¸ ”ámìxóìš¿Ö6¡çפРŽKðÜL„û ,^ýfv~óš­{×]zu[ŒÍé&I1KàìÃ}¬$€œA·fÍ·™º÷ÀViï ‡UI®Eš4ª@ňö{¾íÈj’4ͱmS¥ó¤U:„û¥4™%ˆ7×1¾îÍgh¦îí@šÒÇÇ÷ãó8ïX;gJ]’!œr‚ÆS&£“Ÿß|†fjÔžx=È@òrª¤¶ ]óÄ }$Žäµ×Æ÷7Ÿ¡™õi2=†d¸¿Á?zß©HçJ’ïx–áz´k¾íÈò½9E!sDýÄKI¢Hâqš4}¥w£Ù˜ß|†fêÞMé ø³`œLb}ª¤\^|ž\­ƒct£ÿ™ß|†fêÞwûÚtK^ÔMðß’y·OLaÅÈóöÚvÍ?ìÈÖ½Ë'B£Ià¸FÞ\4÷¡rè7¿ãòqî¯à›ÏÐLÝ[“V}HZÊ{éYéáH’‡‡ëš³´É®}η™õÌ·L)…ðÜJ1Ìá);$Üö=JªÄ™~Øüæ34«I¢¡¿8¹ÝÈ•»òa9ôß`G\meGûîo; –«éÜpšÄUW»²‹Þ·þ&‡ÕOêÕž¥·™5}$í ®_|¦*Þ ÆR¶s@äœ"Ì»)^ÿ¬ùæ34Ë÷”»ó¡y ê5Úä ]êëœá“ÚÕͽù ÍÔ½o<”Ä[ŒR„$Tô­ ÆK¥v]œyÃáÉo>C3uoòJÜ<'‹Ì¦s8È8>’S˜7ÕŠ,Ï¿ù ÍÔ¨/»Ñ¤ ¨RšnÜc8·jØÖ©/RéW´ßómG¦FYÏè8÷äo`Ä››É‘7ìr¤Ü—0Öm÷æ34S£.;H’ÌÒhà}î’ìËÒEÐMËâ¥7ŸÁ®Åß(¥oõ–ú¡¶Sì»ÏW(·´|Dê°÷†o>C³ZÜÔ¶4[ÀIB›J“𸔼ÂÝ„¦9¾‘!fÍ·E{]fö$#6žoñœ¤q‘3{ÿ†ÓH|wÑ`ï7Ÿ¡™º7yê<‘‰›€xi-‚Þ”øuHAÝŒc˜¾žòæ34[£¾ùHå6¨ÖÑA¥Î‚còuÎrFiøBÓsWÞ|†fjÔ_¦.®ž™§#Tp.ùÛÉ"j­;Íh”7Ÿ¡™õ§Ÿñ¤²Ì °Ó41—Æ­ëÓÆ·}÷·™5‡ô*ÁœKUg¥£°¾Žr’X²*yyóšA©jŠšÎY¤x(MkÒd¾Ûù&ä9LÏHyóšåfãv¨Nâ)&$1žÇjWòS½ˆX’z%~Ö|Û‘©{‡¢ct“WOdÇÇw²Jc›¤‘溻xûîØÑm¦#6~ƒ(õBpŒsS—_ª…ãéwFŸ¡¼ù ÍÔ¨æ˜É÷kd)A°g)á{MÒâ¸Ùç|Û‘Õ‰¹ÌÒÈm9>ðÔˆÄ1. Ä•fz…Ê›Ï`×ÔSñœ€…¯/4qõÏÔlb+»mf—”7Ÿ¡Ù”axåiAãAgÅ¥¾76ðId…tÊÆ²k¾í(Ù;)U•zÂO$€ý7GÎÝ»–dؤykõ‚Ê›ÏÐLÝ{6².iºˆV–Mí{¹çz¼kª¸hÖ|Û‘©Qw¿÷îé#N¯I>Q ÆI()«M¼‹1Z;zóš©Q$O¯” ˆPœÕ–áæ]JÒÜ$(w³æÛŽì¼HµîIŸF>Ü%Nà' Gpà°¥Ž±­YSfÍ·Ùuñ;’ø¶!²ÄdûZ omƒCø—ÉäåÍg°kµ…„žG’8ÎC›ã§fvNÕj\—7Ÿ¡™ºw]£ºÙ‰Ð,2KREò¶Ï Ód·:ÿc8åÍghV“$Š{¥šºÊ‘F8¡)P .¨í%ǘs²k¾íÈÔ¨}fcoñhþ(ß¶‹ì.Qd0ôi­çb×|Û‘©QŸ¦«M•n³Ú¸‡=R#ŽÏÈQ3Ï4ÄÆô¿—7Ÿ¡Yý¤© ºªz]ÑÄȃä¬r¾x‡é®i4ˆÊ›ÏÐLZ„Ò"í¦¦QÓµôI$ï—ã®>h–qÙ>çÛŽ²µ÷å€ð»ÄÀ£fN·›¤Hw‘?¢Pß~;ƒ“Ë›ÏÐLÝûN¥uDò~ ‹ÔN¾Ãf×}ußý.ƒiË›ÏвíÅè3¿¤cÓó¬Gš¥9äÓˆqà½"Aåfò¸òæ34[÷®õiƒ]Çy—è Ýrx¾¼9íÒÆ™š:Xyóšåf«8î””ÂdEžékÅU£¥*á†wQÞ|†f¹Ù¤íDc—@3 ×,‰ÁØqÓJš5ÉövfͧuS£&v"ŠÓdϾ[ÍÉñS’º¯&´‘m~IŽYóiGvÍ>œô•FH>¥ñªZŒ‰MC뽫ÀSc)o>C·|oWû,~ ×uœn”Ìp¨¿LwÖ&ályóº©{ƒ9G=àìô¹Ž+ebàÒ´€«d†D1íe÷èiGÝÔ½O_Ab·jJ¯¢,áJì~/’ÐØN Ç~ϧuS£.±ŠÖ°FR‡%# rbY¤·¤v7ñýÍgèv^$™uÚ÷hX÷4'ïHÁt ]5ÒÓEÞ|g£Á^Þ|†njÔRØòØ’Oìq%èDN@lÞ邺µÑÚ¯³ô´£nçEâ&5/,Œ¢Y´"qñÏý3 Q9î½qxÞ|»æíêzbµOFè1€bõj@€<^’ª™Á´o>C7uïÀ¢ñhê¤T½wº¥5ž;ƹñŸ×kXî5kþaG†ïù E½€€—æÕTà¡ê¿¤ sÆ9³æÛŽì¼È@gÕ= @°9‘|yH_ñG’¼ãЬù¶#S£ælGRL§1B¼rôçÑRlóªq5Þ&1ñèÍgè¶F­û˜HpÛI@„ãSÈÔC‡£»¸{ ™fc›o>C75jà açjfñJQã•:èúŸ–œ¤.ÁàÝ:¦F]Þ|»fר\Òö™Ìrñ´D|§¹ï˜ûÀ?áUÔiÖ|Û‘©{kþËnG2…ÁE÷S"Ž`±Ynº6ÊÛwÛ‘Õâ lÔV- 1ÐIWh±òsŠ(‡g¦g¹¼ù ÝÛU¥n4žMÓg÷ÒÂvwoÊ6p $ó¸lÞ|†njÔ>e'Ý2mñ#¼^6°_ät$ò÷$‹hŸómG¦Fí¢Ó¥$5«f1 Æ<»èž§ ã:¼çìcô½Ë›ÏÐMºÕÓû"ä\±¾±sIOäÆ:!Nœê}Œ6¿ù vÍþ mØ wMBWs½®6™ä`âµ<~… lÖ|Û‘©{G¿´E[Åäÿdê’͈^¹—¦µ„«æ>®¼ù ÝÔ½“.rVÓ`ÙSI¯¯ÈÿR˜˜ ÿ,éüjâÑ›ÏÐi’¨'™h†+ÑIJbܺtzä„•‚˳‰Go>C·ºÙlu]1žC%§©šB9fæS’¿ Ýfî@yóº©QWÎtÖp:TúoåoÖBøÈªe`S–¦÷Ïšo;25ê2>ù…!ŸvèR]<×ãz ;XËøÏ7Ÿ¡›umí~´ü¤8V·áì·è6¥‘.N4š¾Ýòæ3Ø5Õâ_‡x+[ÂM½˜$?F£€$1´ G·¼ù ÝÔ½н85N=r"iŠmV¤fçñή ~¤9Ÿo>C·uo 4ôbU’»)óYÝøQqòïŒ9à]š9Ÿo>C·ºÙ+Šåœñ+Ç©/nÍHÒá%ÖáĨ$ÁÇa›óùæ3tS£Vôà8¼qñq5UȽÜ$r.ƒiß|†þK7[ªbS6ä[Î"0×+þ¤K5©äˬù¶£h5 ÈÒœ.1Ár4ŽhúÇ—4~9Î2Iìÿ|óìšMÃ0½úó5­—s…«ÖâÖ€:%KÜ\ÃóLŒ{óºåf΢ jéèxå®ÙjÜêÖO€í¨9iÛóù¶#S÷¦6]µ²Õ;JM Kê`ÅÞ;ÇVíG&½ù ÝֽϕbßÇføîˆ%êâU·$p×»qÅ0Ïùæ3tS£Á£YSí–GNV'ÙÝ7Ö³‰EŸ·±£7Ÿ¡›µÄ €Ë›þl%ˆöì°$`·.’‚Ù÷7Ÿ¡[Ýl‡¤w–¼Q Œwþ»dÒQ­!¯<[7ÂåÍg°kN—û`t fÒBRîÆÇ¹*Zëæ®«d•ìs¾íÈÔ½÷‘tÓì iþã—.AÔº,ÝÒxqƾù ÝÔ½wÔtÌÓ½‰÷0 °u.ë¤Û%øk¹FåÍgèV7¿»§kUzÅ-[DdCÜ?§HmUÃ'Ìšo;25ê†û]RïÓ䪲T=vªIÐ+EÏ.»!”kÖüÃŽÌ<)©/u¼­küªF•ól]DÕ¤þÝ…W6½êåÍgèV“¤Ö3ýÐ|éù×u’®CºG䇒z1‰òæ3t«òé³jœVS«@©ÓIG»… ôGz‘ÏÆâ7ŸÁ®¹ñ[2æ$DS2hùT /˜{³vT:¿ /½¼ù ÝÔ½5Ôó’‡?síèwnQ“‡5Õu†ûá|²'“ǽù ÝÔ½¿˜-Aæ»°Ð1Ãðev‚¼Xs4’áÒòæ3t«›ÍGó|Bq,Ø<½¦³M'Ýç’çâŒìmí÷Ígèù—N¾b‰Æ‹f°“†ª{„ _Eƒ€:±×Œÿ|óº©Q—;9JøÏØþw×¶N„J Šö­&ÔÚŠÅ o>C75êB—`²úMI6nÁä›Ô!|i\ÝÐ~Ï·™5£hècˆDÞ§4&g’ñ!—HCó›8†fÍ?ìèÇÞ1wÀƒÚJ~öÈã‚Éd8…¡Øx6!!eL3Æ:ÔéeÖüÃŽLÏrÓ°ïOët±ð“n8 Ùá¨èæÙvûœØ‘áƒéšØ‘Z);,Mµô=’¿Åã—ú [Éæ^¦>ù Ù™º7QH"FÀ¯w¬»j¸] _qGÓhä]Ã9Íšo;2uïØ\ÝeÌêv™1: M¡<㬬Ä"Å>çÛŽLÝ[ýȵ\!ÃpˆÄ~¦3$4ײ¦ÕÅr2}‘õÉg`MÃÿ$]wªHJy‡Ä«ƒ—Øê4• ŠZ⓹ï¨O>ƒ„ºÌ}‡®ÂÛ@^"hó¤SÓ–#ž¿~£§§ÑÕ¬O>kÛ,U6\¬¤ÔZÕ¯‰$ jº³/³æÛŽLº‰[ &r —äFºnAµM¢  G±EL]±>ù ¿Ö$ÈB‡ñ›¨ÞGÒˆ—¤<¯Œ\4kì›YómG¦î½t#Àƒt>C7Ö±§Þ±Ð®~˜á Ô'Ÿ5M/†ŠJ+©å$®¯< ‰„•´qúÞI¨•@eüç“ÏÀšÖÞï¸U%‘8û|ö3ä8*'–¥øª³5û=ßv,WSj&ºáeÛÏÈ!\͇;Û‘ åU½ÆŽž|u§ýø:¹”µÁ4uhœ&š>N/Œ)Øeýäúä3°¦Ñê”ü ©ÎúW³Ó"®³DxñJÞØf3÷ïõÉgøµ&PÑõ}`oÉýIµA8!ßÀÂLRìÐE³æÛŽ,7ûn÷O+t©øúŒ7Éøâ’¤-0RþêöÐØû“ÏÀš¦÷*¬(÷³$ÏI²p.Ïèd–͇V†Ø·ñŸO>kš;hÍìL5&Tù ¬ig¹Jöù“p™.¨­íœ ÁoýÔkJ£¤ý ö~òXóN^ 5¤t_OãïÆ”0¾gõ¤ÞMÑý 'ª>ù ¿Ö¼ûJ ©I.ëÞŒ79霳ùˆ*‰ôɬù¶#S÷žÇëþI}•bØDµ=¡©cH½§DÝ('³æÛŽLÝ[Œ8ïD!Íbëuï|\Õì§¹ªÔ)Ò±k¾íÈj’ÔêdX›MÉÏ4I*h0:PðMέøa’ŽÅQÊó:&iÙÆ9»Ž{ŠåÆÔ'Ÿáך8x¯ÈÓÈŠGÔðèy}Çß’-¸–?‘EëçŸ|Ö4wÐ…ì*æ19D]ÄE)u)¤shX—O0}åõÉgPéôÇ×i¸£'HPÛê)ÇÁû %RÉKo±÷“ÏÀš¦OjIj'ÕÄ#ŽiîÄ ôfðíÅøSíšo;J¶oBQ"HŽTz§åª ¤’¿¤OÔLuþ¿©ƒÕ'Ÿ5~HÜu_Qõî¾p­K374kE§¿Ô5q$fÍ·YÝlÒ)§v\.â5òM svŸ8X?W컿íÈÔ¨sãü%×ï5‰@Uõµ»Ê )L]²„?Ïr[’ÔfÍ?ìÈpNFÑ J/µËx‹4Ù1|TÇèÛ>ªâŒì÷|Û‘©{ÏOàvp Äޏ—É‘(¤KÂÌ/Híb˜{Ãúä3°¦ÁÞ$—Þ»/ùPwjGSÆ-eK!š5ßvdjԪƸÈÎb«ã#Ç(RòwêµvsŸÁe>ù j,úÙ£+’Ž×¥ÜíYÈÆÁ"w×”ÇÜ5(c‚'L,~òXÓh÷_²ª Q ·}.9E#ðŸ¼ù)9*wö9ßv”m_d óö`yåíV˜`» ¥k">^4 Í¥úYómG¶î ¬[ª”“«/ŠÓ—r.HH~5â"4ûœo;2uo ¨9o$•°D·ñòdÄd O­‘Mjj¶gémG¦F]ÁÀ¥ˆZ!%´Ç7læ Ô°º¡Àjõië“Ï º±©+6ÉY¤±ˆ–"ÿ|´ÆŸõ^–z ùyN»ïØ‘¹“Ò3¦¢KÝ”+ÙLYN|Å!á9Ò˜E‡!Û|ò²·Ül ©m±ûSÓ¾8‡ó¤62/©0)Ämó=Ÿ|jÌTàlW?Ÿ"†ˆ {¥ vÂ@|üÓ0ýÚõÉgø½fÄ—ñçÊ7°‡ëø²At×N¦]:g)—jøuõÉg`M«Õ)ùÔ+{$N¯nˆaJÚÞ;–3sÙê“Ï ë SØQÃoªZ¿ÁÈà'I˜ù ¾„ã8[º¯æ,=ù ¬iô‚Ö{«DÕØêôP%¹]¼±´üƒëÃãSí÷|Ú‘75ê¥-ñÐXÔ˜Ñ.iv ¶k˜ÎÅO>kšÆ.\h£_1 É8‘‰:Ägbu˜áÉg`M‹Õ¿HÄÙø%ÿ­ºÞ¬Қ^£Ùø»~áÏ'Ÿá·f÷W~‰ÄS–=ûºX@ûÍ9üØïÙèðÔ'Ÿ5 ç$—oPŸoOúäA ”Œ®#•ë  s–ž|Ö4}‘ÿè3’^o7s?ŒºË ±&#IQ©’YómG¦F­Ì—D GÉA-¨œG#ɨ̵DÉhöNêÉg`Mƒ“g_WÀ¥j$i<9£¶3.#³'”„_õä'Ÿ5N>ÛÜ»ˆ£‰d6=é׸šôÉEÉCzo×|Û‘©QKe']Ò RÝ>þ3Q³¨él²ÀÍ÷Œ_¶ùä3üZS×Ì>ÇÎfWQ_Oe[r‘Ú»zƒ%;Ë&çzòXÓpN@_ ÅgÚUzÂºŠ“lp’ðiXPóœánÕ'Ÿ5M®­‚È=šˆ:?Þì“®¥ç§Ÿ¢Q8*ÎI}òXÓðÁ¦ ¨véB³’“mmξ4¤SúTþOÆ'?ù ¬iu³A¬ß”éÃJêôÀJx¢né@º©V)³æÛŽlš,)‘)Gc<§š¢ÄÆ÷RCmº9Q£VŸ|Ö489Œ]jãI„óh]ê;ÍßM:¿Ip¦Nfߟ||ÑãS¬ ^4ÍæVßàÌ4¢#”, ã•Ú5ßvd¹ÙE1¬ðçÁÄ [yå¦)5R«ÌRVv—ódr„'Ÿ5M,N.ti÷5kš™5bAÌ[%ÄÁąùŒ§Ýê•<šÖ”‚圴7ŸÁ›õj¢@-=M^Ê9]õ§rãå hП?i¬ØÞ|»fìy¸C¾˜‘Ž•Wò’Z ½°þ"$avÍ?ìÈèäk¢ì×?kÇß‹há£F-ëBa ï Q3ؑ̚áj&ð[ÍiáÜþN¡]y|-§øê@:[~½ûÛŽLZúÍ6]íú wõ‘o%òI…‚ª9Ÿ'½ßöæ3xS£ž…DBÍ-7oÂpSV$å¨L«z¢Ãè±´7ŸÁÛ5ánäêÁ㌈ê—ȲR/)§sÔ®Óô•¯YómG¦F“Ï^nÓÏ,âwJ~Wµ¡`n!9ÔÚUìšo;2kžo`±†fñýú% Ýìšw‹qç3Kø“Ÿ5ß|oêÞC²#ä…gq,ñî«Ö9;YYfi°˜šC[3³ÞÚ›Ïàmݛܤ‡xΊ¦ÒˆÀ»áø}‘|G,‘EGÃáio>ƒ75ê3|–öRŸ›ªIÀ*ñ @‰{•‘;s>ß|ojÔd ‹¢ ÜäS©Ø ùþIM§QTK³æÛŽlÚc”^ƒµ ²­¶æªVô»à–ª;Ι5ÿ°#ÃÝr½i4¹WA¥Þ®ÁÐ}rdI5gT›Ð–T­±÷7ŸÁ®)rˆä–R$/Lº€UµJþFBdE½\«˜œöæ3xS÷Öº¬VMvCÓÏ%©QE¯œÕ"‹‡1˜íÍgð¶F½ÖÕ¦ÎhŽ5³¾A-{jlôÒÝ,@Ìh>´7ŸÁ[ý\ÔM*fÐ"Dxnò8’9qÈ“:íwç“›3ÿæ3xËÍöî.ø”Ö\Ä»EýZ®ÅS–&?>Æ`Ö|Û‘©Qkô¢iz  ŠþÚ$0wu/KœÛYÛ|ó¼©Q_w„óÎ^Gü«X#§@šÜ;Œ±5äõt»æÛŽÌšÚ ºÕ`Û 9³ºD5㎋ ‹_;öÝßv”¬vßiÚ­Ö]Í>#Ï;Þ/gw:[®>3ë­½ù Þj’hÞr,âÅ•g€Œ ó}é%’ØøiïßÛ›ÏàM¤}6™©•“†ò7zÁ5©>èV!á¶j-†CÞÞ|ŸlϲæB†0ÕQÝfÖÀ RS° ‰C×LS w6k¾íÈr³=¿)ã݂ÉÖO'%pâØ“Cš•ÃÛ=zÛ‘©Qg©»jJžd·îˆ¯î¹ûPmð  $"X?ÿæ3xS£ö yµ*{1ªH³=¨ãµ*ùÍ%¼Ò*üYómGfM·.G—Ûcƒ³zNB’t ¤Iõ[nÏô,·7ŸÁgkï’8%xòÒÃE~Øš&±öoF ˜²Zs–Þ|o¹Ù'ÔÊìK÷±RؼôÈØù7T$ØfÍ·™õ 8¬.øz:¹XIÅ4 ½¨¿B ØÁ’Œ½¿ù ÞÔ¨Û"kÇHÉûãPæBÌbv¸î6ülÖ|ÛQ¶Z^NƒýÀg‘Žp«õÄ©+Dü'¡™/ ?¤½ù ÞÔ¨#ï™ çtÖ0µëû¯1&;bZ“M™Zz{óìšÃØ›¦fQoXßU"pî{ÆK^’Û²çó;2ü·bÃ}„-ôÎWIô9//5C’¸­‰Æ×½ù Áê‡xÙt™®èε…O}~ó´N-»·kàR¦ÆÒÞ|†`jÔøŸ¤w&Äôï‰Dж5|ײk‘–á4³!Ú›ÏL:k(ˆîÃUN€â»TAf{Fôzö…}YÈöæ3S£–¿Óhñèu»—3ßôN’xp>¾Úí½¿ù ÁêfŸÉ^ôꊦ ´^B”B3IöVÛº¼gSho>ƒ]3Õ ¦«œ+ŲrT"J¢šyÙ²m8fíÍg¦î}¼BÄŒ°# -oŽ.ÒBvw7N/ø®üzΧS÷&b’q¨9ûf¯‰Ý¸íÕ¼Y]kç-ÈìYzÚQ°ó"%r ú }•¢6¹Q–n֑Ⱥ³gþiGÁÖ¨ý$=Âwâc­ÒäX ¬=%ªÔØÄ~6ûþæ3g5 Sen „à.8J:qS…c¤’pÃSmo>C05êœË”pU gš]ÎÑRó&ÏOrsOhJàís¾íÈò¨ñH{·u{òÎÞNÀ‰ÿº|1éaÍ÷|óìšGÊ/«ù7Çë6’çLòþ…¿Ñ…kzBۛϼí‹Wq­…WÒÀD>ƒÆQ†í¥ì3ƒJôº•7k¾íÈÔ¨KÕ¤özÉ„/k¹u¤Â5N’¼À˜Iìü;Œ~]{ó‚­Qwr@ÍÒC"l¿9Xµ5\úºfÍ·™µjþ¸ÈÛIŒY§inA8¾–©Ã0GÕT‚ZMŒ{ó‚©Qû ˜ ³áÑ2¤çSR5kH ñŽÅo1>äÍg¦F=•d]êÆ³ô£Ѹ¼Ç<×lbëšóùæ3Ø5ÛPmÿÞ f¶,Í©V‡#i˜ ç`“ãIòĬù‡™;hœÇÜ ©æœÔ>ÑŒ^Õ*š4º©hBaµ8ùÍg¦îí¥­¶ïÇ"{«gÊ…¡!3ËEi¦©ÃñnL{ó‚é†&†yªö=a‹SÂ{›àüGväÞF“¤½ù ÁÔ¨5o”Ô ™,‘Ÿ YEê5cÙ²%²è”ݘ5ßvl^,YìOG5kjAí|4‰½æêÙ>³ûþ¶#S£&¥ïn;ÜDô©’»ü>Ÿ´K_eÌbûøÚ›Ï`׌š…rÓtº6ëã SekÄÊÎmà •Í{ó‚åf2¦æaLOfI‚É3ö=$Æ+h¨TP/ó²ïþ¶#S÷ŽKµið|ÔìÍö$žzåfoº›Õ$_Ìs¾ù ÁÔ½?ñ Ýq¥­+¯KN"iç]rè^üUêfÍ·ÙÙŽ@vrx›;»á›¯¸k‹CËÉSp6ëò̬ù¶#S£ÞqÒÕœºŒ§´ýµ­×+rLÅ—6ÕZ‚áj¶7Ÿ!X59+MµöH»ªÁkÊô5¿udÌšØÑÏš•í8±`-€÷ªL“€Ásjº i̺oU·}η™º÷’ðnr3%Àƒ‹ÄJ6Hó_ðrâÎé$¹jüü›Ï,7›¨¹485[Ô"¢z8Ù#ÀÓ.t‚j´¾îÍg¦î-!›=fg|‡$IGK:”«J³QƒOùU zó‚åfó+ØRýlCÜnMÁ£¨H”SUÃ¥7¼ öæ3;Û‘}òœw˜Ó©òbÔà‰C­·ä´ÓèÛ´7Ÿ!˜õþ¦+i¸N ƒÙðÕi ×D™ìÐ "³æÛŽÌšS™°ÔÂUãíº‘ ý»ˆåTˆa‡æìs¾íÈÔ½¯&¡ô[<¤¼H½Aó‡¯ Çi¢Þäg^{–Þ|†`ëÞ®8€žT[cZ$×À>|m²~Ò¡I¸·k¾íÈÔ½«F0òA³¯5¢}w¿ƒtC€Ò´ÃPS³ûþæ3S£&>Ö¦^@!©ÇÐxíH2/ Ìöt ýš·Ø5ßvdjÔYLâ¦QE¼ï–à9ÄøÙ5 gŽ6;õ«æÿæ3«q­C­ÑES!Õ<Èíƒ|‹<»^»è³}η™5ÙM‰Œøä­*TT܇†J‰GÌ’tŸÅóo>C°š$N#VœQ©¶’ìÝpGþëF[Q?ÏeöýÍg¦î½$¥ºU zi–`B••¬î‘(]rcGo>C0uïÅiÁßÚ.™Љ¯ˆ‹õo âWñ-&çzó‚©Q x#%ë­™í1¯œ‰÷ˆ(ä ¸˜Í\¶öæ3S£.Gšz¤ºì.þ„D–<´¿e^„{³Go>C05j/#µÂí&-ØôPÀÙP’ôu“F%oëKo>ƒ]““]Tágƒ@o¾Hˆ.hæ® ňåÏ·7Ÿ!˜º7æ~@!ÿtuc4Ÿ-)µÛ72#κ´f÷è;2ú`!/\]‹bÄžopäÐEwvDúøÍÿ´Íšo;2uï½rÕ±¨ý•DñdW$§ÙÛþÍë¶ÒÖÁÞ|†`5INàQúÇ1s ˆ""Q{ð8È4bö¨¿ù ÁÖ½Hü~}ÿRvZ½’ÕÕž÷m#¥>Ù±x—¹Óïo>C05j>Ü”Å]L+1hÉbJ\i½'ù–†oÓß|»¦j†s¯~hÙ|‰3h4ÆÊ¥é—b7=býÍg¦îÍ&`þ<[iNªÛ÷ä(¡ÊüUqHJê†Øß|†`êÞIU_Ý)$§ë´ÓêýÆkªC°ú!œ½¥Ž$Œ[Ó+{2%_¦fâ²Û Ð?kþaG{—OðàËo‘êþá¨ä´cW‘d^Ò13•ú›Ï`×T?ÜR±oKT)‚òÎJÆYã]ѹ7z€ýÍgˆV“D×zGãU×ñ¯Òå®×ãÞÝ W ®] Nîo>C´š$G—˜"qíoœ¯ª68À˜5LJ´£ûÌù|ó¢­{“’*%ë\…êyÀ™qSQRÒ§j¯Ñ1ëo>C4uo•‘¤ÞÇ)"ïC4uoü»H€¸ \&È8D©½hÜ=@—õo!«_Î<ç›ÏMÝd¬ÉÂGmþ¾KÞAÝ'ùVVNKÂFj²õfÞ|†hjÔ¡¬ŠÝðÇׯ+w\=™K:J.능Çcê`ýÍgˆ¦FÄ>–ОEêX $¯^‡ƒÅ’†%ÈókÍ·™5s?k…-YÆ>‰fr™¸¿‚W¨÷jÔ'B™Øñæ3DS÷f+QQsáö8Ò¢±_ØCr<Έ͉f¿çÛŽlÝ»fy H˜3f²¢RU?;'rRn„ÓÔß|†hêÞÐÞyI׸ræ4¢ÔM!øér1zi.ý¬ù¶#«²t×!ŽkÄ{.à–¿Ê¥7¸p*d2ms×Óß|†hjÔ7&M–‘¶KË«‘qúòHu.œÝŒ¶Oó¢·yñÖôß@æ_²ˆù(‰-É;×%¾¢4÷ŒyóìšM• 55¹¦„Hòµ4G«ªª*– ¡©ª;ÞœÏ7Ÿ!šº·„öýçžëhÆ ù•(«’n•,Å!òÇ8Mìxó¢©{Í&ø,v$§‘pÓÜ{o(‘&ɶYómG¦î­‘½‘#Ú2x©D²ƒ*Ê:P@<·âÞÉìû›ÏmÝ[*é«ëš¹ëz”íRk©È!^qi©ƒ5š;”þæ3D[÷&:^`CÁÏãݲîú"¹ù}¢É+Ûêô7Ÿ!š5~W¬þ¬Ú쇒N½xÌ«ót$Èݨ¡Ûóù¶#³&  Y|Y;àãS-YØfMéÁJCyÅ:[±ûþ¶#;/²Ì©éâ“ ’]|ßÖ%¥R‰GS‡adŠúYóÍgˆ¦îzÆÍá‘OǶÙMAC4uïšÀZBŠ“4£HœeªKª”ÝHfNKms¦Ÿ«¿ù ÑÔ½/^²^É"­H ?ÄWÆÑI)¬’LŸTó¢©Qc‡bŽ:;+ƒ·RVm} ‚„µna“f²¹á›ÏMú¾Û’,…D¨Lv”}ˆ}á?ACŒÞZóìšY“®'€ýL0ßÇ,€í±=ÏÚt¨‘&çzó¢©{k®Yéø¶¶ÈÖ½jòÒS˜>T >¯üß»#Íšo;2uïÓ£Ôµöj¼âVΉᨌŒ'IàüšûH¥Ú}ÛQ´÷\B#íAR«/’”§$Í¢¦XM/iaÛç|Û‘©{é‘òLƒpV’ä-ÆÈ;“(U)¼ ~Š27ß|†hjÔ±òåÀýu„4²ZÉs"“#“ñ; õ&ÍËF/½¿ù ÑÎvœ—9$³Þ¼Ô¬:ȳã5~ÞÍ¿‡™{„þæ3DS£Î•IÙI¬mhÚ gG¢í⮿Œ£š5ßvdÖ\„±Ä±oNId<¨èL+kÚ̳XB£Û¼ù Ñêf+ kÒný®òXNýú¹E‰‘ –=yÎ`Ÿó;2y1@)«X¾I1ïäõoáû&`Y¼UOB=fÍ·™ºwH7y *re’NŽS[äJÍ·‹ä·Çæïo>C45j JW>RäYfïnÌ„Çü„í¾¿íÈÔ¨£®7Øâ£*ý8`ðÄÞãžÚr"sˆY‹…š\æÍgˆÉÞUJâ g¢ð˜[=ËåÄN’=¢4;îAóìšä˜cí9Ø¥+ÎüØI¥/²²×¼TûÛ|Ï7Ÿ!šºwØRÅkQE *¢N€^')T_:eìýÍgˆV“d°É’—…e.r!¢Ï$¨OhöA`~›ú|ó¢©{8Úº“uÃÁνZèÝÊûÄ5;ÎRÁ|}η™u!©rbAwŸDV£‘÷q½nƒs%=\;k¸¿ù ÑÔ¨Á3š0ísoÅUQgIlÊ|p7É¿vÖ±{ô‡~ˆÃª1ø=¢fŠŽ6«N$žžªÐ=‡}Î?ìÈÔÖßÎØÒŸŸ«h Ô ÷ä­+~yñOàpƒçß|†hêÞI#¹â¬R©½€”Tÿž-yêt¢ [yó¢YOJ‡Ð3È94Æ#äKÊZ—´â$Ò}nóœo>C´ÜlGöîÔ©Wã †ßT3Éý7™ñuo>C45jNúÖ€¿q×áAÕµSM7+ƒG/`³ïo>CÌöNêºo=€,çRÌG1AI^׺D&g¶ïþ¶#S£–ÊR]’=('¸Þ%E½1_’ÅXxõ3Œÿ|óìšn«kj2nSÝʺ4"‡MIžœ«rüM­òÍgˆ¦îíÕ¨}µûHÎý½l©'¯zp•`£&¹›5ßvdêÞ=ëÂ1ÞÙ¦²4±†P¢óNwkæ¶t¹Ìšo;2uï+öøšdogiêl ÍÁúü˜×JÊꢷßó;2š$QµX€üìWJLSÅ&; >—½¿&Ûå›ÉãÞ|†djÔ9T>yZ¯vüyæGÄ…ªû¹KŠ¥ŠOü³æ›ÏìlÇ84ËOU¶”7¢S¦ìö<~ N^Ä®ù´#»¦´¡ã%#}Q›ª¥MvJU¶{ ÝÇ$ÌšO;J¦î]¹$Õª8"’‚ Iþ*ål â-¾YóiGÉ΋”² Y‡(eº6Í•H-¹<%€[ÎI}Òfͧ%ËÍNÂÆ³Lif /-;§[3§œyfó÷7Ÿ!™µFÂâÏ—JlþjTQp÷j¬ Yf\߸Ӵm®ýæ3$[£–” 8›<^“AKs$oe€aG¼8úÅÖß|†dõC9Âãä”*á‡T=^Ù)ʑŠ&qvÎ]ó’©Q¯¾ÑºEív^£(5¤sù–º`!k$¶Yó;2º7ƒ ›’8æUšR'Ú9q¬”ÂãV²ùžo>C²ó"³ñÝR9ˆ„––fdÒ/†c¸ýÍgH¦î}’$³Ëætgp½K¿[Õu˜¦Î5PØ:ÛÏLÝÛk±&õÝ$¥(L^ÒñØÁ%Ô%»%;4k¾íÈêfײ²oàçZ MD!ðÍ­–äÀ¶Øúç›ÏLzû&áõ# âÏ7 ­Ñœ|>à 29saÖ|Û‘©QŸîÕ}¡¾Ω(=†@ÂræñøÜÓ¾ù vÍÔ{2Ô¤í\nˆN“ã8²"?Ž×\ÕîûÛŽì¼È/{teÍê ‹ß›ÏqΗ¨ N˲ßómG¦î]j½dÖÕˆrEÕrâ‹¥8øRž$£Ìšo;2uïBæzˆ¿[Ÿ"ÕËK—=^ÒXÏfìH‡ïE T#Ÿ½dR¨ !ê†êk’5+Î/?mýÃ’ì¹»ÄÓ̱k>D"»ÜÊ’/[Ô[î 7U»èÛ”L™Z×X§AGëRtÑQòxüÞv"{_œÐ_Oú¶%³(v`ñQw=ºèÐ$RãÉs;§»þ¼f܆+À¢oc2Åo’`¯éç€íãÈîkSó»Ê·{·)÷»÷·‹¾­ÉT¿»æ‰ ‡;Í ÈL6'¦n_Ý톭Iu”Ç·‹¾ÍÉ”¿—耷8‘?<Ý©™Àò©±AI¾Ü ‹¾íÉj“€ºÁpK¥¶ÕÞ Y-/~¤Ê¿šñ-ú6(S¬þ%HÇÀ¸ÑÈæK²uç¸Cb÷gŒ]É㲋¾-ÊT«G#=Ðòy¯o:AøŸÀoî¤LDméšEßÔ†dÊÕ ,CƪYNüÉÐüªvlªcEÁÐ.ú¶(³è$òúÒ¥/w’Ú,¥7:åù4.#¨S©N‹EYô‹2"Žpǹb÷I—šfû¦4³¨‚ M– ©…Eÿ°(£¶†Ç}v5 -u+Db·”|HåÒIî(s«À¢o‹²%ë¤/*ää1¹Ä¶Z&ÂY8Ä<þHˆ¿žômQ¦f}–Þð×ptŽ,ÂØ‡kÛËT¾Â:”7Á!™¢uu'ò¢jÝV†Lü'«ØÏš·Ð.ßUc’=éÛ¢¬J щ0 €Ò×L±«DmÑ]s½Ad›P{ê¯sú¶(³¨ßÜuxÊâï‘P©È€$ò€Ô®Á8•ÜX×]fÑ·E™Zx*®’%IT•œF»Q9ã"ùŽÇG)ñfgŸôMrH¶të>IE5Ôäªñ´°mÖ¬xGRÒÜǪ°‹¾-ÊTÃy,< IÁ;,6÷Ò|‚~—ŒiÛv÷ß4‡dÇHöz8ì[̉Õw ËKæM¼ö’ŽP ÔòkÑ·E™Úµ×Dì”n¯óA?¸yœÝö ¿zͽ<‹þaQ&aÖô¸¹ñQáÄŠ ´Ãž ¤*{6ÿk£þ°(£Êº’ïMnëc‹yìØÔ1ÀºDRâŪ‰³èÛ¢LIPUø¦ä&Û}³Òí¢o‹ÊVû^M¨[í²mz$§¥‰…ÒÑ’nb>|“ì¢oâƒ]TÃî¤ ÑôCwë;HÅfIa‰ÌÜ©JÞÝ/‡òf>$S!×,껤öÁ¡%ß9ø ÷ø*‘¶8$SÏžò®Ž6¥’Ùt¡þÕ=ÈÔð¤nyÐÄÇ‚Þ7ù!™‚ö „SÍn×( ²‡,½ò 9I[¬›:þN$Þì‡dU¶wॠqêùÒ´ÊöM§Â¨o§àVø¿¼ì9}Ó’)i/¦p30rÇÎ8WEg° nÕ9]£»_»ÿ‡E™:ùš=%½!¾ÀO£8¼:IÕ®ˆ¿c6‹¤ßˆ”­í“Ðo‰Er*=AjŽÊ Ç— é,`q‰lŒz3 ²­”«?A‚wö<2Û¶DûÑBºU¬Ž]Že}S ²)k'I¦ÒŽ$µ›OÄ«ÃWœî€ùÕ5©Ba}ZT¶uí½0¢4|˜ê¯¥ibeò¨.õ“žkú]YôiQÙ¶sÁ¿sÒ¯¼Î$hÔÅÄc]9»WÊ@¤ÖŸ¾YÙT¶EoÒ;‚Dæ7’T5b˜yâ€Ü Ðö¶2ñ¦AØEjì1å7êIìQÍî3CÎ3ùïùõúO‹ÊVûÆ*U˜LÄ FL¾-†Ý‚Æž”® W¡ÛÃÿ&BdS0× »¢g×Õ€éô«¥'l¼Aõ®¾¬í¿™ÙTÌ÷Ù}ˆ@ô£§H_ì鮲÷m»¥—õüo*D¶%ó-W LÓ\Vo9´…WVNNŽ™¥Ì\÷¯'ýâ¬î_mo޽+çÓìÖú›€­I=ÊÅRëL¼ÉÙ š Mˆþ+F’:ìx°ÊxË ÀéFçH¯ãZ‹z³!좷4R§…Åk€Jêß\êÆVø5^gÏwKÖK½éٔ͛2)^Õì½ÎOàäFuå«Ãk\¼ §wÛÀ÷æCdoùd$Ê7ÕsVÃ!~ÒøÔÜÝÖÍ8[Ä!u¿‰7!"›Ây–¬ôýj¾·x$—Çÿ•„}_gÒ»èÛ¢L•»l1ûT˜«w­+ ‘¤y *+å_XêM‰È¦Ì½ÁÄ ¼ÑÆþn‹gX¨¢ ý-æI Á.ú¶(Sçv{ JíD€éUk¥:ùtµY*iÊÙ±ö_e¹7)"›BwÒð“Û»W¿@È$·ƒtÔE¬^cÍ=¥A0}[”)tˆ™^Z¹¡»tŠ'¦(?ל÷šêñÇûMß´»(¶­¤~* #䀗Ti·õ‰|º"þ•ï¿yÙÎÌ$J´æ¾²\©†?§Ú{¼+‘üUç#²)t{@x—bLc>øÏ¤a”8”d‹{«ý¦ofD–iÒÕ»¥q˜<¤jèwGйh4ç¬:’ëú+î¿©ÙºÉiv”ÀŽnÆYGšóO*8ð)ªju«=§onD6…nâR ˆ$gGÕÎÓZÒÌ/¬Ôó_Ý{´lÏ雑M¡ûÓvÈm¥*V¿Ùµ˜T œ¢\å<'ëùßìˆl'Eú–êü×'é\ŠN®;J(4¬H"‹Å…_õ¶(Sè–âç´Í¾U’<ølöë­Çú%\™Ó¶­ï,ú¶(³¨æ_8±à41nMk.0°¯y&p…ôÖnÏé› ‘M¡Û-€Î7aZã3Ÿx(åKà€œji­­|À.ú¶(;2©áðq×X.#½äÐ4•òíß:fÑ?,ÊÐÁ²Ó”IwºkWè‘Xn×õé×!š5ŸpþÊøÞ‰lµ¸SÂkzEo9³IØÙR²ú3®´ì¶¿^ÿmQÑ@öÐjPg\#ìŽN{Í"¹l4}³$r´ PÍod|O—yÔ;Å¿iùLÞvUARצYômQV⛜gÄo„«Ò3BÖ)ê{*l•¼}ììlaæÍ“ȦÐ]/0?­Æ¢î7ERÞ²Ü&…ŸN±‹¾-ʺ5nR*>œ"Œ«O 6žíÕ|ùY`®ÒŸÍ¢ßL‰l Ýc“6â‘ ÌCM#Y­ÐÇáoI¸¯ø³¯ÿ¦Jd+É]‹›s©È›ûþú0€SAÈ5’N :a}[”å};ÝÍHH™Å³,jŒjjñI’7´‹¾-ʺe˜SÕ=—æëhñÑ…qwý²‘¹G»Qo¶„]´Šú%èõ2øùJ½j9‡¦kÃY/õ¦Kd+õ³ó°E¤SýÏ#.Í-L{IçäT‡o¾D¶š'±¶»; 3¤š4å°TD;^:Zkûå[úõMßeR’ã~*F£~õhÕLj‰‹7¶…Mzn}[”-tKfl–‚¥ÑW-*ý¤xÖ&'KÓéšu(oÊD6…î!Õ1œsĪ8åáV¢ÊØQ±õSö®K¸Ø.ú¶([èõI` õ‘ã"äã[Äzž ˆ‚—Á$†;ÿÿáÿÿóÿÿú¿ý§û/ÿëù¯ÿé?éuÎþŸþóÿ¶þëÿôïç_ÿ}üû¿ü·óŸÿùõÿü/ÿúßø¥ÿòoÿÛÿÕŸö'ËIßÿÖòû](êÍýBmÃs©üGÍå?üG÷ÿ‹þßÿçÿó_ÿ}üÛü|ˆû_þ~ßÿÙ¿ÿ¿éþßÿö/ÿõßÿå_ÏÿŒo!“$='±’ž^T±æDqÇ>î–ú@sìý/ÿúÿü÷¿ü—‡eh‚ê³M¬¡©hQªýsïÖZÙJcã*eÏém†Iõ 4¬hçÃá_{ÓhŠZ¾¶2¯ºjpiúž­J´’ц~EV4ê_7ך\-…RˆY¸švšpB½k {3YôbXÑaÞÒ  Û7,¬‘h©Iï ©·ÇèAm¦ZñŠ/¬ø G¯hÒ>íÈM@äo53ýDW¦þ' ü˜QÔz‰sü@àAAÞwç©;ÜxÄxÒàÄ*Ñ´5Ãý¼õ+²°¢Q 3 e¢ºHêé—æ®ä¯Ò:°ÊWX‘(êÏŠe¥Hd × µ(ºž¤ÎöÔ6x,ÀÌ¥xÅV4¤) Q”"{j¬M“ë¼F\‹ ¯½ì¤ ÷ŠVÃVŒ®˜ĺ¦á6S·ÚŸ‰Û§ô­™;‰W4aEÓÉ?zôb#T…?uD´¹{]º0ަA%}Ùý^Ò <m”?²Š››5ÀljyM¶ƒÑMî4B‘O®Kš>þènîJ¼T$<ÜëÕ¥<&ÉN\;šÿ6ÛZ0Õ¤BŽÔ×θ LÖxOb!".‰E!2h÷m7æF•X´ø%d Ÿ1IÓ“‰>M\’£^ûd ýZÒi†ÍqÚÙXÇæ% ‰‹ãŽD×’ ´ü%ß–c5z4½ªåþjoÒøÈÛÇXüŒ®Ìt-A “8ÿa:†©/§hJj59Â_ßT”(ýÖoàÜ$Ë·—Ï/ÛIÎÜ¿T§‰œ›Ä[E=<¤šïIGÓ¬•èòQû æ[¾Œ‡%ÍÍ«0]äpgM†j“a‰34)BkÚ‡Oý,ù²–4¼eÂT¼moU´¾!ÙM`ÕÔ›\ÉiíÖM|x2ƒXÒ´ Æ„[Ó1ŽÎHeeÕ°IM²š‹z‹üæ.óÉ bI“؉K$©æIG,© Ì$AhLn§RßÏ’/ëaI#jSP`ÛQd»« Â&•Ïš÷Ã’ ôO^ó䱤ѸÊMÍ‚3è^˜¬˜”î3t‰quÀýN]óüï“Ä’&¾=ɬ¨Ub‡øÆ8ê™?j†ú8ϱ}ÉšUÌ%a£«U ]Šß.lš‘ÃOÞOr–Aÿ©VÅÌÑÌNýÛI¿qkXSjDæ'ó³äÛz̵BÜòC3„;]ÀO„øÉ óª mÑçCôó'B>9?,itIýÃIWç3¬áÞ¥Ét:l5s°rÚΰ>žŒŸ_KÆ&ûˆ·QÅ©]–Sã[)C³'ˆÉ­Ÿò}XÒ¨SH£RR§Uêí4%“öøaR¯ÉöÒuuJÇŒÁ7ÇÑÿUs%óäö°äõHô$7ïÑmoØ &ý”Ê÷Ô7Ne×þ,ù¶Kg»éVÔßµ^ö9êý¾GzSƒM·ú˜Í’oëù5u3·¢Þœ;‰ç`j7Û“‡ïŸ„€¤ÛÆ?Y=Ò«·y²¦l¶€ë‘Ú\_ iͤ"”ò,Ó ExrzX²ÚÇì†dH&.¨¨ÓÎrÁnÙµèqóƒõÇÆŸŒ–4á,¾›Ä• ZªP­,ܹ‚ý_½I¨?éø“ÏÃ’FåA8=¦è9íŸV´D’î ù³V'öà1$ö'›‡ogR©–@|ëã² "ƒêQWš¯åàó¤úÊY f°ò“ËÃ’æ–|ôD°V¬ðKƒÍ4Di —°JpzªÍ\½?™<,i¨,ûSÛÆgzGôþ¤»¢Ê.üŸDx8%›ó³äÛz’—×;³ÄØ‚¦t;Éeð;zïÀ¤[?K¾­Ç”Áyf'4%ñ ‘ƒ¢ÄA61­•û ÓHýä𰤩1úèðäø \­ô3½O>OÔ‘gR]°¦þ“Q<<,iÂÙIRøõ›”„'ä˜{p ^)zÍ‘"¯0;OþKšÞ‰‰­Ê÷ëš Öyº—$C2êüŒZ~–|[_™ w-Ÿc÷óZš¨í½bµ³áWóyŒ(Ò“»Ã’Æ µõ7'ôÔ£îѨ+g5æËÉ0ágÉ?¬ÇÜ‹-z¬›¿ï¤3ŸIžöV3ÁÞ^dåTMÁöÉÛIÎTID½ìÍTŸ‘Çìeu!¯Ú ë d.Ũ™ÅšbQ‘šoÐø¼{#æ—˜r蓳ÒÆzŠ#\„ûɺ´î§•àGÎw˜œ£šÎ—'c‡%L°æå^)ãÆÏ §16M’!¹ŸùäÖuólF¼¿­Çª£ |C¼§¹Î æÔ]Ù’ªë¸Æ1 1/Ñ™Êà“­£±Ðæ&”§8âþ; j -¸z8ö%¥$‰‹¡úk5Ü‚'W‡%í…u#N×’cÕ Ooj0û>ÏuiËQ7ó³ŸL–4Œ²|ˆ:ë&¾"˜<üDÒØbøßkÄY÷&òtXÒðÉ*ìb.e'Iƒï9åNHWMtdzâw¹ò³äÛzLep®¬J¿¶šf‡K€ëýjXæLïí&£xrt.&œi0Iwþîq@¿Rþ)zsµ}V>ëns†›ûdè°¤£1çø—‡fJÖÅyš( …~kˆô–í˜ë÷’F¤ë’$²«8ªAÌnŠ´À¹|Pµÿ…N"ô³äÓz¼³uõBóajîk¬d¥$*½‘ªE~‘ìeK/ÕT žÜM‚ÿ9DwMž†tc·ÖR&©DÿŸ.›6Ä¥·óßKš2žØN¤=„ór…0J©¯sµ‚¼øb¤ÿ´o9Î~JCm†+=T¢Â®*i­>Ø”^Ä6[ÇNÝz/id)ÀAE"0ÎxI¯ä€+1ëènbðêi’Åò¶[s[ê8>¡D¿âÔ¬˜Íû ó|ò,µÅa' ¼—4ë[‹Ô/ö:j:âÝÓ7ªÐÎc}@€°fÉ·õ˜šß2¡‰“£â¿ë–Tgõ«h]o³ju›ßKšŠõ]¤tSÕU= {WGC¯dAüôªÂ¸‘O{[Y—WX~çF(èH„S€¨â¸æã¬âê{Ik=sΞ=¨~N2mz±\4?¤9k+–ø^ÒÁy±,iú¦èÖ:Þܯ•g'›;i? In ‚…¦Óš5ßöcªnò]2? Ü.d±fcƒ·®ÿB~WÜÏšo2e7>¾î–—Ê”«-¾!®HËVõq¶LZ³VÌ?µJ~­‰ÿâe·ŠòÚbY4ÉiðT¯]là­rí»¿M(ØÞR±îÙòU’µ¸%Q—s’„§ròNš°µ.½×4f=.Cø¾Û%]»iˆ…—tÇ¥! Ðí\z‘¥“ám ­Ï_»>iYiîJøYsð®ôž’Äï,ù½¦‘¿ ŸµDé­-@ëÙ¸-5)¾s^5U×R8ßkš¶z€Á×â^Dxt«/òȨi^º°~kÍúM¶|®i z|r½¡Ô:® ñ;1ö&‘Ô„¥.5ŠÀÛŽ¬ †ÚQ§4`‹²Ÿ6)`Íë"1õ ŒšmsÝ“wÀš†jX¥<%pæÔ¤,æÆ7çV æ¸Ò]›3ÿ$°¦™}ˆ£,%/”MžîÍßléâ­hêiìJnÖ|Û‘©zržmëHñXØ3Ÿ€°YeŽ©;‹¤YsfÍ·Y èPp™ÇgB¡4p·]\Ww¬¹VY­f»þ¬ù¶#;§Pü&¥„ZC’0އÜÈ2{%QÕ‘á컿íÈ” ÅÄ €€'';ÒÞ²®yJ¹èµ ùàÍ>°kV’ß5Ä|'`ÒÁ;×>Ý!ròù¸AóxŒÞ½Ó¼©?j6@í15é˜:uå5¾%ùµî3Ú7Õ¹Hܬù‡™Ûh?ýWÖà”ª²OqR! K´™™ê‰Û°wÞo*iJqä.µ¯IÎ’|©ÚI›îX˼û›àM òˆó‹ÏõˇATã5Ý:¼~^ƒ§49Çøä7Á'‹GŠAê‹Ç G74zähÀqÊ| $pvú7Á›Ša\Ò‹lv ˜ûhi¹Û&ùÁ&ówOe|ò›„àMÉ0hC' §±”r”4Ý|âŒ%?›xWgØ5ßvdÖl˜uÊwK-CÚ§ì{Î YU¾š* '™¶m}zÓ¼©CJ‹ºH(þˆõ‚Rš&¤w¢p(¡H5ܬù¶#Sˆä<Ž ’)°±ü™;:cjÚç]S‹•8`ÏçÛŽììCÂ&(¸WViÛ“o%ÒŒ½ñvméšhðqœm¨x3¼)E®;$p¿(>5Ñ Rà¡qTçjö©ÒªæÌ¿©ÞÔ"yÞ¶mÒTuû±'×”*®S¹’“pæàd˜5ÿ°#«D¥1'”ø qcm>ATIÒµ{½êmk曌àM52€ÖÉ$ꤹ.ꂚ-éêAcnóÆY›5ßvdÊ‘{ùQÒW›9‘”;|I±â°ubî¡Ú^Š7Á›zäq:õ ?ƒÉ×ù‰ëâ‘.ÌÂ10 ý7Á®ÉF€5£Ó¨ªëDéŪöZ®.Ì.ÜXŠ}η™"§Ú‘S#M`µ ÑHµ}ú@p ±÷œ%Þpü›‘àM•óè"làu³¤¨â×’>ââ™ÈÞmœi{üß”oõ-¦ä€4G¤øpW+=Žú‰}â›ñÓ5Þ}L|s¼S¸¶n‹ÕBT@$«í…PåYÀ R,N¿üÒ›”à-rÏ¢Áâöfј@µsâõǧºû~Äkr™7+Á›J§Ó­)Ý’™ æþ‘½ »³4M6)Þ›5ÿ°#« ‹'ÑIË ͯÕU²~ yÀn`6kþaGæ.]˜‰µK µ‰!”*Ù†¤¦f/á\“íš~‚©ŸÆæ4GWÜ2¾#ø–0B¦á"ÎʃF›ÒNoÉšofB°Ð™°x7³·°xuÏêR«ñcÊl’½vͧí”qhMbòÇŸ'i¬ÆË‰Ä$qbèšonB°s OàŽ Þè³$Yä:&Ða^QIXÒêí÷|ÚQ°s ÷XlšƒÆøH°ä’L^s>[ò„¦kZ¼Þì„`õ'fžóé>ø÷>G–ØL!}%ažÀ2òᄅ7=Á®©ËjÝ‚‚´¶Æ8 -e,ªœxƒhæµîi*,þÍO¦Ø‹ŸËä…ADÕ+¨„´:ESÈ{T]óîo‚BpVlR£aZQ¥NWqáj¾G%ÝTßÞ-û7C!˜r/©{‹ (ù"‚ß’[#ÊKÿ|«Ë6·½) ÁÔ{5$z°ç©„<$ààÚÆO-•I®:åžÅœù7G!ÞfÄ€À7ž·íYå–ca-¡gà]¾|oûîo;2Ed¢aHž‡-rÛul†LY™¦¨9!fŸfþõîo;2kòñTŽÅ«‹>ßð¸m,6}ˆ@´‘R›dpÈ›¦¼Í‹‡tr›Ë“pcî<¢*Jmš^Ÿóël-èÍS¶4=n8 ?)%‰K·tA±¥M4Á;ãbDküYóMT¦6í‡ú“™ŒêqÒuû5D‚K©¥D3×Ä¿™ ÁT’khd™œF2$%ÔXüûò Vi‰C¬F¹S‚)%oMò^{ª£³¯¦ëˆHF£™,’ !àIÎÏªí¼¹ ÁÔ’ÕX:Û¸Ðyôæâãî[SÍ^W}Û¼É vM7G‰Ò­Œ}µ¥û»åíœ{ðh#é6?z³‚SèäÔðfør°âêw/¬5í:RóÿÄ5~éMW¦B}È Ëêýš ²È5cU⮦+¿‡åÍšo;²üc–Èo–2@¸ÆÜùQ³`ý¨ö²Ì¿ ÁÔ¨Itkí†ä؈æêº"äàþòX©^‚ ­Ø=zÛ‘S褢K$¤k<¶ú…ú•Än÷îjŠI²ÏÆÞß”…`jÔR§qä–íFM¤ØÍßxÝÒÌbšs[ͺ7g!ü¢†^ðW<ž4jì>0_/?@r!)µÿ¬ù¶#SO.n¸±‰Æ5$Ý“fõ·—“, Þ¾ù&ëØ:훵`×\š°N¥5¾ÑW$[%-¿4ÞÛ”ø[P.nrØ7yÁ®©YUNRçWÙ¡ßXC:S4Ò$h>íœn]ë—Þì…`ç²+ƒã™ñ… œÒ£)Å?2í¤ ^©[Å–7}!˜õQ' fÏãÛÀïmpzÕémå%æÌ¿ù Á’Y3 áTMÒ̵OY¨¨ÐJ—üä‘IšæhüÒ›ÀLš?àj^lŸiÑìÔSQq©ü€ƒ©6½ ÁÔ“3Wc•†Z@Û`·–Dµtó<õèÙÊ?½) ÁÔ“Á­™Èã{Ë£¬š~iNePJ'Ì”3œÏ7‡!˜z2§’v{ܸåN[¾•œIE¶Ý¢ ç°ßó;²¹¶Òu}Ë$Ûe®{5©òvµjˆá¸¶m}³¯u[ š¨æÊÕ’QxN·Qº5,šÐï´ùÑ›ÆLÇæÖå?Ýô¡.„ ç*ÁÝ“-’Þck,oC°šÌ¡kf;_¯¾Öés ‰jf|ˆ+#gÌÓ¬ù¶#S£œ¢¡äµ‰yO°ŽÃTo%èÒ(&g(¨þÍd¦ž\ÓRÕQÞ:{ï©kêøØyÒxéÜ%‡YómG–׊=s>‰¤©î¡{î„7íNrôºù"¹µ1îÍe°kݽ È]"×üŸëç‚–¼æ%é~ní fx“‚­Q_u^@t¼¹ã8'.¥ÔÈAžlìLÿf3S£^WT ¾uòE·¿yæŽéVIªdò£äáö{¾í(Y¥G©;²ûa¨!‰ƒu >Êr1ЂIa¶ÞPâý›Ï,_Ö{b;î8lq©â©d‡|Œ‰Yf%F•زÂÏs†7Ÿ!˜u‰Y†:I TÈ®ðSÒ½I×·4ñ!ÇâÛÏL:êJ¿QO–à÷ý”ÝuSU£ÔÞòŒaMoÖ|Û‘YÏŸQí …¤€ëbŒaÔyTÂÁ¿‚—¶éä|ó‚©{…qÈò‘RŽ#UOº.Iæ95nŽd«Þ|†`jÔä¨ü‚äÊ9ÍkX" JC0uï\—¸ÖüÛ|»FÝ$ù6܉Ç{ŽiîµÃ›ÏLš0¹{ö:.ŵ¢ÒUËt•oH—pTlsùvdòâp›ÀBÒvÜ{àlœ:N°Ê²÷퇳Ïù´£h9¾ªšoIÎE×ÐK{ Ó•9¾ —L,o>C45êÞ«˜¨_Ñ^”ĵ•ªøž…îëÑüèYì=í(Zíå0´ÛMÄvÄ‘®íælÁíÁæ¥"A3c,¼ù ÑÔ¨]|Giù«÷gIÆNãÂ5÷rhà’B‰tDÍšO;²kÖo ÈZ@®V¼Òn]žÉ«ð7°‰ h}ÛÏm$ÓB!ß#LàˆÃ߃Ôs¬Ù+åŸ#a|ò›ÏMžËò^£¥¿¥Æÿ¡N‘™•y‹¢šùžo>C´5êYH/5eÆ-ð·c-,}/W4©¦A$¸Óøä7Ÿ!Za=4’o­-®…4Íûm‹ÿ8N˜'í& Þhfˆ†7Ÿ!šµ†$ûCd$'n—|5M!"jtå‚é’%ØÑEáÍgˆv¦ H´<{ƒ´€[Éç³ hÔÌ"2c]¦¦Þ|†ßk’¢g—sM<þ¹ÀöJY>vL[øAr1Þ|†hêÞ <¯‹Â>É2³hx}ÙS Î=JG§ìs¾íÈÖ¨WÓõn”v†4Òô|Icq£á:êM=n#Xðæ3Do"gˆC:kµß+¾Á$^€–tÑÁô窊aßýmG¦F­gͱÆÖ›¤wºf­I¾i­î,¶yó¢©Q§ªæ—­pÇgd…úµÁ>ré5ôÜ9=ö9ß|†hjÔî\NA㪊Z4t-ö°_£KpAzû=ß|»fÀ·ð m ^ÔØöû]þì¨y²g‘ÉÎ^xó¢Õog_Ý– Žú¡%VÑ5e^ÒMZL÷CNo>C45j`ûä•\¬oà% Së#˜ù~ƒõàfjExó¢·y18^Êáì°Ô5¥4J8¿}¶¨Þ„P½:fìýaG{sz&ñLÝO|þ¬yq¢dš`n2[IŒ7ë?ß|†hjÔN:,@ï pXòŸfãõPòĉ À»Ø5ßvdyÔà‚±7Ù´îßt;ŒÿŒ§ÔoÞF¸ß7oš=ÛÏ`×ÔÄäC–ÐB')Gò¢Hµ¡QÓÐמ¥·Ù …¾NQ U°ÃH‹s7ÕŠ³¨Yš"î¬&ÍÛŽLÝ›3DêÝpU±ª JC¬Áœ[“t¢´@+aÙòë›ÏMÝkä½]ËÃHmËÅÎÙ pŸ‡dd¼á†7Ÿ!š5ùM7Æuð/D_©À‡¢‹ç ^ b^Ôâº7Ÿ!š5áÝqhøv-‹ò™qy’íÉ6±‹f M+Èóæ3D«Š05Ä{]ÞpÕEC/ ¤2q© JÁxfsxóìšž¨áÛN£»²¹ùÄ(Àè&™œˆË¿öè;ú±÷Á'$7£aó_^dI·ñaƒ¤ò­Óúº7Ÿ!Ûs42nPTéXã"#uºòÊSz»À“˼ù ÑÔ½oS—V~}×Ex 1žWŒÎùj{V;Q"¼ù Ѫ-d² –Þ5l^e5RApì¨è¥W“ñŸo>C45j I[µÇËfÕÈt˜R^š àÇ—,©¦œ­¸ÓÛŽLº·üH×óa î“2íꤴ<'žDÓ3Í™óìšyVtä°€mŽ÷ÐDßáHŒ5ŸdKƒÜ¯Íµß|†hêÞ1Ρq7Y=¯®J!Ânvñüã=£k—³yÜ›ÏMÝ;H¥£ˆ§{H ö&©#×à ꢂ¼&íoþ¯É¹Þ|†he¹v\Ò3¸Òo#,EÞ<£n"]wbU;zó¢©{KÝÚ—%èAÀ¸>‹®×>…\O“ž…šCÍ™ó¢r8ÃÕÝc<«Ž· MþT‡¯”ï«ëó¤k…7Ÿ!F‹ó™8åj‰º‘L;^ªfîˆVg/¼ù vM @%áÏGÞ)‰4ŽÕfŽ‚ò…Ro1w|áÍgˆ¦îÝB) Ãál‰dyu¾TïÆ:³i$uÐŒ ÓÞ|†hêÞ§ç%Œ[3Ö%AÖ䤚¥I"×¥éºÍ‹ß|†hëÞxNõt;œïŽ_£sZø7ñŽÄÅ™GòWÛ|Ï7Ÿ!&Û>„”ïì€ )=áæ\JËä'‰þj£mz‰Ã›ÏMút‰ôi¢ ŽXÝb Z@ã—˜½é;0š5ßvdjÔ©à<=@ [ÁßßFœ¤Íc¨‹·pä"æþ=¼ù vMIárÌIæaL“4,Mã7cþ:Ô [ã“ß|†hU"† ø 4€…ؽ4nvköðÝšd¿†ƒÝ÷·™º7ÙàèË„Yâª<ŸBœçE®šÙ@v|ã“ß|†˜~i`În#9Âwͦ®O:xìK|úDs‡Þ|†hëÞsK‹ôòK†¢fû}Âf¤ŒWôÒ½T·6þóÍgˆ¦F=O N:ßA¼?5o ‹Ÿ1ƒY¶ÛÞúÏ7Ÿ!šµ478„l[™®¬JÒ$ZZÉŽŽ_*á‘’•|Û‘YSª¨u5KŸ‡e5\ªA %s63áÍgˆ¦îMè!î¦30NÉv’cÑ¡N¿&zsÄæÈ6ß|ó¢©{÷žuS +¨¿yæ×ñÞ]œQºG¹€¦}÷·™º÷MM³û OÎãîK7 ¿ß‹&²,õÞZ{ó¢©{;ݺ7ð~„ö$Úª¦¨ð™{üÞ557Ÿ!š5\y§á)H2ê]*«"T_x~•1RŸFƒ9¼ù Ñr³kÐÐÕ ²óõàÛEºçàË´&À #ÝVºòÍg°kjfIV«C¹ͪl¥iVÀ>$ A£ŒÌAxó¢©{“÷KˆAôíÈ®™þ_9H64Ó‹ücrúÅ„’ïpΡÏ?ÿæ3$S÷æ,Ýx®$Ýå ä‡hDB„yòÌEMNœVoßýiGÉY%’Ò)âJ=¡ÍÕ5 pW‚Û©ê;íbL%£ëÞ|†dêÞ1è—¼:çï*qIŠlõ£‹uC²S3Mš3$%LµÄ’Îã3o‹š²TšFç½Ç7Ÿ!™õtsksÇN.bmºš5í²?©òŒ–Ìšo;²Àl·o)ìò!‚;2ø¦®!ŽTêÑÖ?ã›Ï‚Õ(wÈ •–‡k¤¥{¿‰¼sèÙ³aæÝß|†d§b9QÜnÒ9§ÇrŠú.ãœ% 0‚áÆ7Ÿ!™ºwÁ ±ÚI€C‚ݘw¨å„QB‰"gåÛ|ó’©Qk É:{Ï·Ùz ™ß6u­’Çnš B,°Ïù¶#Ë÷æ¥Uÿldo-*/^|ÈDN“…qA'hoš5ÿ°#Ó‹!O'òô¹wàØÕê ä!yÇpu$a\{–þ°#Û{¥92½J4ólWB{Éø1Zœ”˜ #Ú5ßvdêÞ;·¢)4ø C25ê@¼¸OwGvS÷âs¸D²0ó‚J ”d5â›Ï`×$Ï7æ]›P=h~IÝE£(2®Nï ßjêŸñÍgH¦î£Ê”GB'iÍ69únþsC®TGî¤"¥Ú5ßvdêÞøÐH{1ɪ”ÞÕÙ¥¡'Ø5UyL/p|ó’©{sæ·×&鰋ʇ¦§ÓñË!sD«ÔsÌ™ó’©{»Z ©ß¼ XÑØû›Ïì,6ç©äG¢oÙÕ–òÅR—\æôJæd¿ôæ3$S£–Rù®âL=ïšhjRßõàC2uïK˜7ƒ8EX<“±v²c<~)¬6%…itcâ›ÏLÝ»ø&±5ÄdSš[½¼¿Œï1ï%uZ³æÛŽLÝ¿©ÛÝà$ô¯l€oHP“fßüFZI§Å™ÚE|ó’å{) »fHRº62¶:kH:XaÎü›ÏLÝdœ?U'ÌZü]ü–~©Ø&NDgmï—=óo;25jaìã>}$8õµUâÒ$!|` §«'î¬ùæ3Ø5u ã»ËX!§^zKlÙP2ìt8ÁÎ8WË=ˆo>C2uoB\ämAÆ—îÄÉÆ‹jn Ï ¨‘µŽ–Yó;ú±wI‰:©%q)ã<€£®ýŠŸš‚¶œ2:³æÓ޲©{oµªú^ØwüZÇΗF5h‚»—n£;"Zš5Ÿv”MÝû²IN72]‡Cmä¯×תé#ûÜO¿s¾w|ó²­{/PÌ2ìS“‚ñgϨÎÈs¿G.?›}÷§eS£î< „½í©éZ|bõÍ¥¦&v±/¦e§`½ù vÍæ¦㣠îsK µúê&€C=¡ `;}÷§e+?}5u'×u¥·]ü¥}RkݯܔÒÛwÚQv6ßã²Üpt§I•„M( G©SYT%–btJã›ÏMÝû È rodÿ8ioñYýñN½q©‹ÊîÑ›ÏMÝÛÅ‹=+““4Ô]Èq,k=÷Í­³5«7Ÿ!›ºwñ8! ÒÚ¹r,U¦’ïTtÒ•R¿Ê˜ŠQµŽo>C65jðgœÉX®d@½n GëÎ}ÿ,•Î,•ƒCÞ|»æš¥5Í?¨¯8°Ùcá{J°X+€gòÍ7Ÿ!ÿâ{ã?gÀþ+¬þ¡nWÔ ª†Q  fÖ|Û‘©{“^ß• Ú‰LK¼Ì[ˆþY^Y&ÖCµ¼ã›ÏMÝÛ‚Ù$«ºj@ZtñÿÌÎ}ÀêB,ÛèýÆ7Ÿ!ÛuóŸŠŽ7-¢\“"G²T]XL‚CþÅÍæ|JcnDÕFø¤¤9Ý e\µv‡`øŸñÍg°k.áVM‚Ãã…«Ñw«°9Ê 9÷Æ–m÷æ3dS÷žì2‘òHvLÒ¡ƒNÓà¿=/òlEMÛ¬ù¶#S÷&Ræ¿.%»õ©ûbŸ¤^}fÅÒÅîÙ …o;2uov`*h\ÝíKXò°+pì&8Í9s)ÃðXâ›ÏMÝ[£=Æ75æo,žöF¢eêM—>_“0ؾŸüæ3dË;Ë'˜t+¹×sÉ7ÏÉv"A†Ú9þÙÖiß|†ljÔdÓ‘ÔÐý5JfÕ^ÉÞœZžs'¿ù ÙêfK píyN¸œuN´ПԤ_w{'£Á§š1LñÍgȦî=Ýf—À jn‘~ãô__¾Jkì䥵×löÍgȦܪJê6jú>ª&œ& ±{iW§AdÓ™óùæ3dS£V“ÄLMí(*ûuM±rЬQ­.`¦ê]K¦¯'¾ù Ùj’¬Of¬5×?Ô_:¤wîBäH‹ÄÖÄÍ7ŸÁ®Áóòi-Ì‘UúÆ™:9d•OZSSÑÚø¥7Ÿ!›º÷Ç{›½·*ýZ{xÙ4£fÔo”ަLSyó²©{ïJ4^ FÂÜ‹´·WçMÀÑ×"¥eïeÞ|†­QÅÚÀ0ÓvJÎFcƒü:R»íÒ@L;ÙöÍgȦîݾIšÄ¸å›øç>~3FzwÕRŽ4uH"ìsþaGfrߺ«IÑA·­ÄýUᛄlv†/BßfÍ·YM’SÕç.©}ò2×įôã$Œ6•nFRšb8<éÍgȦFÝxw?†3;±.8)–Ã_¼L?‘x¯!èFG"½ù ¿Ö<Õ#%ÕëíÖÍ[Âc“ÈUwâõŒîAzó²©{Ñp‹f5)r_'é5§2àݘþÔ9Ô3k¾íÈÔ½%ªÈ&è_Î Gqk¢ÒNáÝùnIU“¥7Ÿ!›º·’êÀ¢àlMa IÁˆìõ:ÇwK…³æÛŽì¿Ð»*a]!5p`±µ[% »ÿ`å‹uÓ˜Þ|†l¹Ù»za%0§–í|S?¤‡è5ãß)Ûïù¶#«I¢t…/§6¼3ž82™!ÈX5a‰\þ\£Õ™Þ|»f7yÏù)gãJ%CR¿!æ#}³*EÏÆrí»ÿaG&kpqëK¡×É75ó&KYð›ý,Õ|BüÏšo>C6uo© …ÑÕ¾ØtI1TTÖð/´,Óççu;”öÍgÈV‹û°g“puQtç8ò3Õ;à‰gw£‰—Þ|†lùÞRÄ'á—qòb\€ â`aBMóÎ1®™Àüæ3älób>áËDµy ÷ évߥ“ÑUM¾2£nӛϳµÍ0Ô nØ^så“BRì;•7wa;š±Îo>ƒ]Sw¤“Dd&%ÛGŠ1º“–ðz_£€GðKå×»¿íÈÔ½ãÂVÀØ ß›ö Õk(Ùi “XQ“ð?¢Ñ%No>C¶uoþ(ÐWDäÔ–Sù‡ôÛkO+qškòÍôæ3ä_3±ìBx$5Rk¬°$‰J sÊÚÐŒ‡iÖ|Û‘­{×Ó‚Ø+K³Î|\ÊH¥] D—ÀÑÔ‚Ò›ÏMšÌí#{œÛÖ4HòX¨“ª†#†–ª©Ôæ.2½ù Ùr³3~~khrqß+I–¢ºö¡”Žã7¶ùæ3S£^|ØëÅ÷b2¹K:×kròžj}Øà‡Ñ“áÛ¤7ŸÁ®y¾qÖ¸5l\꜡´VÀ3šÎ$Ý(ž‘rÍøí7Ÿ¡˜º7Øž¤@íé´X‹zšÊ]X€ÊJ7i°*­Ù÷7Ÿ¡Øº7@c覘àÁÇ»ŸxLH%€Ä¿Ò›8·}ΧS£K€™'Õ¤ RWûö ¸€ºx=¾­ ÿ´£bjÔ`Íö!'áiØfäîKç‹êÖ¦Ç!½ù ÅÔ¨§D¬÷¸k¯~BSÿ ®YR"}JpKµ¼MÿfzóŠ©Q«Á´Í Ø × êÓÆâuñÓp#k‘ÑëjÁÌüMo>ƒ]sMô4ƒd0›DsÅ‚ƒÔ/9ˆ´:¬½¿ù ÅÔ½Õô,’§nÆ¥ý:¦´E‰ šÓuk1ÌŸ`×üÃŽL/F“è#hó’KœÚeò×@zþgÍ/ u[mÉôæ3«IÂÆ R )&^?ˆX=?&ƪ^«fÖ|Û‘©Qöxa„©Ç€/Nf#²Ö’ø;ßKtÁúä7Ÿ¡˜uÑ’̩ۋ®€MC`¼FÕ‰GÁrJÓ›ÏPLZS“×P»È–|*iF—þÊé3À13èL®Þ|»¦8÷|0ñ¤ €î£EôµÇ]TU•ìµYómGVçdº5Oè«Õq²Æ¹_Qe÷M55vôæ3S÷n}4APߪøÒ"«6â–¨›¹qÙus§ŸÞ|†bjÔEc ž¯T®ú¬n;š@«9@š9@´“zŸYómG¦FM¦"ZÕÔ)¶ÙÌJ¿6Ö¦jöÊ ¦}óŠ©Q‡îI*>´–¶ºþE¯˜æÎjŽd™ÍÜé§7Ÿ¡Ø5Vî¡{ÃqL‰–œÓsÓÙ¾ºqøkGo>ƒ]SéªÚNŽîõ NHÄ£O³1¶N"õœáè¦7Ÿ¡Øº7¢ö+RÕ t Dªð¯;MMqp'm§cýç›ÏPlÝ»­>ò<L'ð}šÔÍOÑõ,þË¥0$Ñ`×|Û‘©{’¥zÄßB €¯@üpI*üx‘Ì骚fÖ|Û‘©Q“œ×ÔI€«Æltµ‡^QìÈ’âwA—4¶ÅÙ=zÛ‘©Q7 ¹5xcœM1V2&µÂŠ rܦ–Þ|†bjÔþÁºCÙb”†/bp4xAäc4f‹½ß|»¦š:âˆÚ'ɳިÌnŽcuIˆKÙ1™ZezóŠ©{OµÁ“tÓ¬¦J<= ˆCfdÅâÜ…z þ|óŠ©{Š F^ÕêšÈFk÷EÖ~Žz(ðwlŸómGv^dѤX " rV%2w‡¸LU· `œ§Ñ´Oo>C15j€Û"{å¼k eSOc¿Ac»“1rNùícÛçüÃŽ~l3_·¶†¥yNÕSukDúI“.+H—쾿íÈÔ¨]‹g·IÜÆž==[>oÔÐ*P?²ÍÝDzóŠ©QûÓõD—@Vî8Y3ÊSΉàÿTe4ñèÍg°k¿ò7d´r‚Hõ­ -O©†ñÔýD°óÏšo>C1uoü¤@vo‹íð-¤tN÷ý?ü8~'~Ê]3¿#½ù ÅÔ½YŸ4dÀÝÏ3“ D5ý©.I`~3Íšo;25ê-ªûîär~Ü£®³FQœœÉP‰Ñð~Ó›ÏPLú¨ÙðlSƒÙî’®;€¹K§3Hìù¶£hgÖä>³”}ñ«‘}JÕÏ+ÏÙæ+#ÿúžo;25jÁ]g1NR§%‰3®ž»N"šA‘ËîûÛŽ¢íƒ>älà †ˆ’)ê…ÅPêŠ*—ë1õäôæ3S÷î{º„0Aõ0©|¡áLEDoR7ZséÍg(¦î­‘ R .4—”rƒÉNÐí–Ú\îÍ­“ØÙwÛ‘©{kôâž² ˜ Ÿˆ¨¤¢Ë×Úµ”߬,šŸ5ß|†bjÔ—ÎRMq¤Éññ,|ÏPxîê=,Ïfßß|†bçEÆÞ$ ã‰DEã`RÉ®D.\%%0ŽB]ƒ½ß|†bjÔ<Š/*}ÅN|&ƒsžM·Õ³iø{ÒQ‹ß|»fœ7GNf©‹hí¾º¢ô>¶ïÒ«HƒYómG¦î ‘><é?©ÖÒ0 ’7"‘N¦/iü8.Ø5ßvdêÞg©Öë¶Ä烻ó¹ü±¼u} Ì«Ñm “0k¾íÈÔ½Å|ònÖÖD~‡:‡Û òðš|ˆ[ÑD—m×|Û‘©QϪ±Åèî§/XÉbÛwó¡1SIjÅí˜;ýôæ3S£NSeÔ{ðwàeu¯êB‚F"QCµj]©ØÚÚ›ÏPLº7i2M¼yþ‡Ð‘\ žnLzóŠ©Q÷]Ws¤–~ìÚ9áaéÂ'’Úhh®Dó Ÿ6½ù vM —U\ᛞÆáÓt€AøÈGá¨ã—)ޱÍ7Ÿ¡˜º÷q[.ލg·!¦ îbÿ?Ý2¥Ÿ< ¶yóŠ©{0ÇŽµ´±"x7ºIAäótQž‰ÉCÂ"&ƽù Åjq“»K‰¶âGª®bU;Â$]™g¬'¦5~½ûÛŽLšü‚¨[¥†¨.ÛÊYr“n‘·¥¢x~Í©Oo>C15ê6ýè(¿4õ¤Æú–5IMƒhw ŽŠúlÖ|Û‘©Q{—ÁP3÷Ń4±$ܧ)b|—ÒuÚ5ßv”m|/nanh¾@Õ* Ô4ú*5Ÿ®¨k&ß|óJ¶ö>5¥f6…” ß`’q°>9]#¤ð÷¯û¸7Ÿ¡˜º·fj‘'óZ$ZÐKÆuT 8 ùµëÙp_Ó›ÏP,7{ Q‚28dë*0»2ùðŽ¹á©‚™Y“Þ|†jçEÍÆeº¦N†ë§¿r›$ ߤC1.¥ËoÖ|ÚQµó"×RßÿÒ¯yÒØÍNk©Ç°ðM¯Ä^²Go>CµZÜê¢NQ­ÅR‡'¿îÄõ#¥£[šhƒÑÛ5Ÿvd×¼“y’8Êâ;“Q¶Èêç{©³îAzóª©{ö·Ì»KFvêÞ¤ªe7öÙðo蟆Ÿ™5ŸvT-7[ý&u-ŸïR“éSc'­óµi"ˆ—U˜ÚÅ›ÏPMÝ›PK‘ëceÒî®;×Ñ™¶š^l ðÍg¨¦F›‚ÓÀ—·Rúª¾«<ö‰|Ÿ)Íædúãò›ÏPMZ#«e€E=vKÚîšq§f2]eœEÍì¦Ç6¿ù ÕÖ¨5a6¨‚š›8U„æÛ4‡@M»ü€£v”¾ísþaGöN ¨48êWSMÿ¿í½k®eIrY¿{œ!?4ŸÑÝ”@–höúÖ. a·áÑ¢ÕâÔ##3#üî³ÝÍl™ù²e«¬ª~íÈå)m0”ÛŒå7ŸÁ®IZ0ÎÚQ-#ƒén“ðšÓœöŠHžx˜5ßvd¹Ù$lÕ“´*ÛÈ%Jm+úªq]³*§HšSìs¾í臷/×ï5c«WD:0ÞˆàØ\–ÐWžÒe Û¬ù¶#S£š °pÁj¸ú„/ÈþÞ­1í5Rr¶Ïù¶#«IšWÄ˜Þ WÕ&¹ˆz ÀËDo÷ýmG¦FÍ:ÃUÕÖØî¥!¤.ùp&IÔºdc9dáSûœo;²5j‘Ô@Ü ·>¢8Ÿ0$ÞÏ*Óø»Evc´%ó›Ï`×¼y²¢SI¾âÞ5?‘ÀI¦¡QP`Ç׬ù¶#S÷í“‘‡ÓðgMLÓœò*Øe658HÉЬù¶#;/ò’U»JZ™H… …Õ³& dèÅ+™Ùüüæ3Toù!/¬GâŸ×@²ÖÖt¨YTg.9U—Yó7vdú"—ø®;ˆÄ<Žï8ú'75èôx¢é+Ïo>C55jäñ €xÏ ¶ ¤ƒIE -eó*œÝ£·ýàf«´Bð§Ó›f—Fð1pL…&bQsmÞüæ3Ø5ÁFʵø’Rn:eTõtm߀;¢ÙEr¥P–Ý£·™º7[¡Ö}cÍzË×…ê!Qð’Lï’÷g í½íÈÔ½»n²=x]¥¬cTp}”¬ÀÔ¬:¶——±£7Ÿ¡Úõ”dö¬7ˆ‰’mƒ¶®Žæ=ìÎ¥ –ß|†jjÔéJ{ÄC ‹EÔäÍþ_)e‘͆Oƒ]ÊFfÍ·Yn¶¾4¶1R¨ÇçS·‡+¶¯$ÙÉÚMÇ®ù¶#[£Žë§fEÖîHÇÚêØ¢xšY„mÕ›–ÑšËo>ƒ]óô+ÆoOâ‘—HòÒSSÕVj,[Q˜Ü£:û>cG{Ü#¶Ar)l ¦»î¿þwµoVÚŠš¤gÖü-nqæOQ9í€ÁtqÔ5AJ¯Á®¼Kü;ö,½íÈÔ½uçFLüÀia[“,¶ö£Æ„x«.̬áüæ3TS£vÇÍH’gó©©SI1X.c?º1ãD»ïo;25jWš†üh¶ŸþR°Ý=‰±¢'ÙPðwFãçß|†jjÔUŒù1C[ñ5F×<ìïB  ’ïûÌ̽v~óìš_»"i Ç3xh ¶JödÄÒïìÕÌiÊo>C5uïë]áy‚úšFàê6å*Ns¡ªX8F 1¿ù Õj’$‚ƒ;MÓFÁÙÑHÔƒ7 °Ì!]ö¯ýîo;²Üì54BiÖ¡‰MkîFŠP¹ETïú‰!$;# ¿ù ÕÔ¨sWù+Ý+È95‚d§„së"Æy?D›ÅÙ}Û‘©Qkf `c†(TÉf¹œ)éK!A=vŽm~óªÕân¤F<"¯°-s )šbÁq¦dþg¨ÜjÖüu‹Cf òòŸ9Ù¨ï:r®{¤ € íŽjžϷ™º7›ZÔqÅõ—ÉÆó¡mž|€‘ÜÆœÏ7Ÿ¡Úº÷Ài‚­×„‚ÇÑL\Uµˆ9øÉhOå7Ÿ¡šº÷Õ |*ÉjnIŒÀ¤tœð“z¼JÌšo;²ZÜg\µFÜ€ìî,Ú‰¿(?;/XÊ›fÍ·™5@‰¨%VM€}IOé3©‰s61ÅÔ@`ŸómG¦F-F_8ÝK£…–Æ^“u„rÒ7k‚—p‹Ý£·Ù5™ úKE‰N^óôF~p”„#Ô¼ßw~óªAyrœ¹õYª$Ì õXÉOâLá ø¯;Y{óª©{×–üd£–¦‡¯É‡ìR}†CÃ+Ü7ù•óeÖ|Û‘Õ$QøUó7_³vJõÖ%l•Ὗ³­ÿ|óª©{ïéÃË·15¤%ÏæÃÄ3ébî“™4:¥ùÍg¨v%!,‹;#„#Rjœ¤ÕÐÊÙbìfçˆå7Ÿ¡šµS®Á“…}8K¢q/×ÉÃíC\™TÔ›ù2ùÍg°kJ‚Õ«7Ût³i¤‘’×òn§Ø"ÁÍ9ìšo;2uï¶ãò<•×XyM ÅïrÂØä„GY-ñ£wûÝßvdêÞW4\;Š·¥.ª79×ÒL‡ Q'Éw6ÃûÍo>C5uo<$n>ìtˆ8J©Vx.ú¹ñ‡0Lo`~óª©{ã"%ñ)âãÂJ5˜tTáb›:ý$NÅŸo>C55j®ÐyR‰SÓP¦×¤CùøÖJ¸Y4>cGo>C55j©ðÞ)9^ügápK- 1z\Ïykâ„OÅîÑÛŽ²åƒxºÛNò{v¤™ÞSç{'X;£•”ß|»¦üÙÖ¦HM7_4Zˆ÷ÐýŒ…$rà›Ã¾ù ÕÔ½µÓë*Qï8’î5‹“°~º(*KL׬ù´£fêÞœ®žbò§)»kTÕ”ÞX=ê!Ð4Þ’ìšO;j¦î$í,:>Oƒ›³’w­•t¹¸Àw„Ïn8fùÍgh¦FˆWS}kkhW;^ƒLÃLKqš†-’”Á`o>Cs¶#º*&F«1½ É“$»›qw`¦8¯™”ß|†fjÔ×Uð›Wc&𻏦¤Dš†’8p²V¶Ïù´#»æR; e™=ïÙïq`†›pEÎa¶^ýôÇ™”ùÍghV“̦‰ƒãhR¬îï9òl )r®·6^Ĭù´£fgPªb#U(`§Sï9ëütiáŽàó7òÑÌÈo>C3u´ËRhÌ»ßýu²€áq¢qm7ðûÉÜå7Ÿ¡™ºw^±‡Ê²‘ÐKæ&If0ÞOÊÊËÍ­úS·Ïù;2ü•ˆCä\cGñW¦.g®ô¤¿‰È„=¥œË>çÛŽLZ£@à!7rXõïŠñÙH¸ˆÄ\PÊð6v¼ù vÍŽ_k›ÐsˆkRhPÇ%xn&Â}P¯þ@3 ;¿ù ÍÖ½ë.½º-Ææt“¤˜%pv„á>V @Π[³æÛŽLÝû`«Š´w „ê$×" ÍU âDû>ßvd5I𿨶©‹ÒyÒŠª ÂýRšÌÄ›ë_÷æ34S÷v Méããûñyœw¬3¥.ÉN9Aã)“ÑÉÏo>C35jO¼ d y9UR[ˆ@®yâ„>GòÚkãû›ÏÐLú4 ™C2Üßà ½ïT¤s%Éw<Ëp=Ú5ßvdùÞœ¢9¢þ ⥤Ñ$qÈ8 Mš¾Ò»ÑlÌo>C3uï¦tPüY0N&±>ÕR./>O®ÖÁ1ºÑÿÌo>C3uï»}mº%/j„&ø‚oɼÛ'¦°bäy{m»æoìÈÖ½Ë'B£Ià¸F¾¹hîCåÐo~ÇååÜ5À7Ÿ¡™º·&­ú´”÷Ò³Ò=‘$×5gi“];ûœo;25ê™o™R )๕b™ÃSvH¸í{”T‰3ý°ùÍghV“DCqr»‘+wåÅrè¿ÁޏÚÊ$Žö»¿í(X®¦sÃiWu^íþMÈ.zßø›V?©W{–ÞvdÖô‘´ƒ¸~ñ™ªxƒKÙRÌ‘sŠ0ï¦xýkÍ7Ÿ¡Y¾· ÜßpÍ[P¯Ñ&íRo\ç ŸÔ®nöèÍgh¦î}Ó8à¡$Þb”"$¡¢oe0^*µ;èâÌO~óš©{“Wâæ98Yd0ÃA.Àñ‘œÂ¼©V|`1xþÍgh¦F}Ù&M@•ÒtãùUã@À¶N}‘J¿¢}Ÿo;25jÌzFǹ'#ÞDØL޼a—#径±®hó¸7Ÿ¡™uÑØA’t`–Fïs7d_–.º€nº˜X/½ù vÍ(þF)}«·Ôµbß}æ¸B¹¥å#R‡½7|óšÕâv ¶¥ÙºNÚTš„Ç¥äî&4Íñ 1k¾í(Ú;è2³'™±ñ|‹ç$‹œÙãø7œF⻋{¿ù ÍÔ½ÉS牜 HÜÄKkqô¦Ä¯C êfÃôõ”7Ÿ¡ÙõÍG*·A­°.ˆ*u“¯s–3JÚž»òæ34S£þ2uq•ðÌ<¡‚pÉßN±PChÝiF£ ¼ù ÍÔ¨?ýÔŒ'ÅeV€¦‰q¸4n]¯6ž¸íwÛ‘YsH¯¼Á¹TuV: ëë('‰% Ѩ"±á—7Ÿ¡Ù”ª¦¨™áœEš‡Ò´&MæÛ¹ob@žÃôŒ”7Ÿ¡Yn6¾q`‡ê$žbBãy¬v%O1Õ‹ˆ%©Wâךo;2uïPtŒnòê‰ìøøNöâ@il“4Ò\w/b¿ûoìè—m¦#6~ƒ(õBpŒsS—_ª…ãéwFŸ¡¼ù ÍÔ¨æ˜É÷kd)A°g)á{MÒâ¸Ùç|Û‘Õ‰¹ÌÒÈm9>ðÔˆÄ1. Ä•fz…Ê›Ï`×ÔSñœ€…¯/4qõÏÔlb+»mf—”7Ÿ¡Ù”axåiAãAgÅ¥¾76ðId…tÊÆ²k¾í(Ù;)U•zÂO$€ý7GÎÝ»–dؤykõ‚Ê›ÏÐLÝ{6².iºˆV–Mí{¹çz¼kª¸hÖ|Û‘©Qw¿÷îé#N¯I>Q ÆI()«M¼‹1Z;zóš©Q$O¯” ˆPœÕ–áæ]JÒÜ$(w³æÛŽì¼HµîIŸF^Ü%Nà' Gpà°¥Ž±­YSfÍ·Ùuñ;’ø¶!²ÄdûZ omƒCø—ÉäåÍg°kµ…„žG’8ÎC›ã§fvNÕj\—7Ÿ¡™ºw]£ºÙ‰Ð,2KREò¶Ï Ód·:1Èòæ34«IŽ¿RM]åH#œÐH¨Ôö’cÌ9Ù5ßvdjÔ>³1„·x4”wÛEv—(‰2ú´Ös±k¾íÈÔ¨OÓÕ¦J·Ym\éÇg䨙gbcúßË›ÏЬ~HÒTP]U½®hbdŒArV9_¼ŠÃt×4DåÍgh¦F-Bi‘vSÓ¨éZú$‰÷ËqW4Ë‹¸lŸómGÙÚûr@ø]bàQ3§ÛMR¤»ÆÈQ¨o¿ÁÉåÍgh¦î}§Ò:"y¿À„Åj'ßa³ë¾ºï~—Á´åÍghÙöbôÆ™_Ò±éyÖ#ÍÒòiÄ8ð^‘ r3y\yóš­{×zƒ´Á®ã¼Kô€„n9<_ÞœviHãLM¬¼ù Ír³ÕÀGwJJa²Ç¢bßôµâªÑR•pû(o>C³ÜlÒv¢±K ™„k–ć`ì¸i%Í‚šdû;³æÓŽº©Q;Åi²gß­æäø)IÝ‚WÚÈ6¿$Ǭù´#»fNúJ£ $ŸÒ‰xU-ÆÄΦ¡õÞUàŽ©±”7Ÿ¡[¾·«}H?†ë:Î7Jf8Ô_ ¦;k“p3¶¼ù ÝÔ½Áœ£pvú\Ç•21piZÀU2C¢˜ö²{ô´£nêÞ§¯ ±[5¥WQ–p%v¿‚Ihl§ŠcßçÓŽº©Q—XE kX#©CŒ’…9±,Ò[R»ÆÎ›øþæ3t;/’Ì:í{4¬ûš“w¤`º„®éé"ß|g£Á^Þ|†njÔRØòØ’Oìq%èDN@lÞ邺µÑÚ³ô´£nçEâ&5/,Œ¢Y´"qñ÷ý3 Q9î½qxÞ|»æíêzbµOFè1€bõj@€<^’ª™Á´o>C7uïÀ¢ñhê¤T½wº¥5ž;ƹñŸ×kXî5kþÆŽ ß;òB‹z.Í«©ÀCÕIæ&Œs"fÍ·Ùy‘ €Ϊ{^€`s"ùò¾â$y+Æ¡YómG¦FÍÙŽ¤˜Nc„øÊÑŸoDH±Í«ÆÕx˜ÄÄ£7Ÿ¡Ûµîc"Á!l'ŽO!GPŽîâî%dšm¾ù ÝÔ¨3„«™Å+EWê ë¿µä$u ïÖ15êòæ3Ø5»F5à’¶Ïd–‹§%â;Í}ÇÜþ ¯¢ÆH³æÛŽLÝ[ó_v;’) >(º˜q‹ÍrÓå°QÞ~÷·Y-î±ÀÆAmÕ¢t…+?÷€¡ˆrxÖhz–Ë›ÏнQUêöAãÙ4}v/ !lw÷¦lJ2Ë6ñèÍgè¦FíSvÒ= Ó?ÂëËö‹œŽD>ã>ƒdís¾íÈÔ¨]tº4¤fÕ,Æ¡Á˜gÝóTa\‡çЦ§¼ù ÝÔ¨1Ä´øŠUãEbãË÷õ LÀÊ/¿,~i&™5cG¿Ö œŸ¢AÀ$35¨S€ +Ê3Ÿ9—Ä/Ž›}óºAéDå Ü ÂÅø¿ñl∛5š4Ø™³åÍgè–ï HÆú|!‘­³•i樱³ý6uL›o¾ù ÝÔ½U™ßûH‰FÇE]h1¸¨¯? ØYŽÅ¬ù¶#S£þ&lâˆ8=YíºùkbÓÿ%Èã r:¿¦Æòæ3tS£Ž¤¾Eþ|Õc—n¤³î¹%k>¼çìcô½Ë›ÏÐMºÕÓû"ä\±¾±sIOäÆ:!Nœê}Œ6¿ù vÍþ mØ wMBWs½®6™ä`âµ<~… lÖ|Û‘©{G¿´E[Åäÿdê’͈^¹—¦µ„«æ>®¼ù ÝÔ½“.rVÓ`ÙSI¯¯ÈÿR˜˜ /éüjâÑ›ÏÐh’¨'™h†+ÑIJbܺtzä„•‚˳‰Go>C·ºÙlu]1žC%§©šB9fæU’¿ Ýfî@yóº©QWÎtÖp:TúoåoÖBøÈªe`S–¦÷¯5ßvdjÔe|ò C>í.Ð¥ºx®Çõ4v?°–ñŸo>C75ê(ÚÚýh5øIq¬nÃÙoÑmJ#]œß|†nëÞhèŪ$wS:糺ð£âäßsÀ»4s>ß|†nu³WË9ãWŽS_Üš‘¤ÃK¬Ã‰QI‚Ã6çóÍgè¦F­è;Áqx9ââåjª04{¹!Iå\Ó¾ù ý‡n¶:TŦl$È·œE`®Wü;I—jSÉ—YómGÑj¥9]b‚å4hÑô+Ž/iürœe’Øÿùæ3Ø5›†azõçkZ/)æ W­Å­uJ–¸¹†ç™÷æ3tËÍœEÔÒÑñÊ]³Ô¸ Ô­ŸÛQsÒ¶çómG¦î=4:Lmºj;d«w”š@–ÔÁнwŽ­ÚLocGo>C75j(ˆ+–7 üÙJíÙaIÀ.n]$³ïo>C·ºÙIï,y£6ïüɤ£ZC^y¶n4„Ë›Ï`ל./öÀè@̤…¤Ü—sU´ÖÍ]WÉ*Ùç|Û‘©{ï#é§Ù'Òü[Œ_ºQë²tKãÅÿùæ3tS÷ÞQÓ1StN÷&ÞÂ0ÀÖ¹¬wn—à¯å•7Ÿ¡[ÝlüîžJ¬Ué·l‘I qÿ`œ"µU Ÿ0k¾íÈÔ¨îwI½O“«ÊRõØ©>$A¯=»ì†P®Yó7vdæII}©ã-h]ãW5ªœgë"ª&õï.¼²éU/o>C·š$µžé‡æHÏ¿®“$pÒ=jÄ ?”Ô‹áH”7Ÿ¡[ýOŸUã´šZJN:Ú-¥'8Ò³ˆ|6¿ù vÍ•ˆß’1'!š’AËŸ yÁÜ›µ£ÒùmxéåÍgè¦î­¡~œ—<ü™kG¿s‹š<¬©®3Üç“=™<îÍgè¦îýÝÀl 2ß……ކ/³;ä=À𣑠Çè”–7Ÿ¡[Ýl^šçŠcÁþãé5m:é>—<gldok¿o>CÏ?tòK4^4ƒ4DPÝ#ù*|Ô‰½füç›ÏÐMºÜÉQÂÆ~ð¿»¶uB TJP´o5¡ÖV,fxóº©Q¯º“ÕoJ²q &?Øì¤ásHãºè†ö}¾íȬECC$ò>¥19Œ¹Dš'ØÄ14kþÆŽ~Ù;æ˜'ì667î&|2N§‡öíehf†™ËVß|†nµ¸Sn`;¾K–‘†º–C‘èD½s¤r¦¶VŸ|ü¬á‡’ÌöLšz®»˜ÆÖ¨ Ö©dyR„èís¾ìH y ”Z`•&– Â’¢›:4G’dt›{™úä3H®ËœùáÀYØ6Ù% °æ!!$Ì«~W8¥˜>ýúä3(ÆÛ”.¶z_ñ¸ Ž/ãMŽ–|Õá8„lîzê“ÏðcMЌ賕-Þë±’Î"°n¨€ØïC#YíwÙkn6È”rÎ(Iî 0Ó¤‹NY·õÑíwÙk݃lwº)˜ŸÒ)/Qåî,-ÍZ7D˜Ý÷—±æù°ª\2õF†YÃ'þÐÉ Ã jú!©ÝèìÕ'ŸAÝE¿ž³jR‘¾ "~õ”ãqRR7‚Ú¬ùùúä3¨­ä×y\0™ §04pϦ"$¤ŒiÆX‡:½Ìš¿±#Ó³Ü4ìûÓzÄ],ü¤ŽBv8*ºy¶Ý>çoìÈðÁtMìH­” ‚–¦ZúÉßâñKý†­ds/SŸ|†ìLÝ›($#àWÈ;Ö]5Ü®…¯¸£i´@ò®áœfÍ·™ºwl®î2fu»ÌN¦PžqVVb‘—bŸómG¦î­~äZ®a8Db?ÓškYS€‚êb9™¾Èúä3°¦á’®;U$¥¼CâÕÁKlušJaE-ñÉÜwÔ'ŸAB]æ¾CWáí @/´yÒ©iËÏ_¿ÑÓÓèjÖ'Ÿ5m–*.Ö RHê­ê‰×D’µÝÙ—YómG¦FÝÄ-P¹†Kr#]7ˆ Ú&QУØ"¦®XŸ|†k’ d¡ÃøMTï#iĈKRž×ÆF.š5öͬù¶#S÷^º€‘ à‰A:Ÿ¡ëÇØSïXhW?Ìðê“ÏÀš¦CE¥•Ôr×׆DÂJÚ8}ï$ÔJ 2þóÉg`Mkïwܪ’Hœ}>ûr•ËRüÕÙš}Ÿo; –«)5Ýð²íg䮿C‹íH…€òªÞ cGO>ƒºÓ~ù:¹”µÁ4uhœ&š>N/Œ)Øeýäúä3°¦Ñê”ü ©ÎúW³Ó"®³Døâ•¼±Ífîßë“ÏðcM2 ¢ëûÀÞ’û“jƒpB¾…˜¤Ø¡)ŠfÍ·YnöÝîo­Ð¥âë3Þ$ã‹K’¶À Hù«ÛCcïO>kšÞ«°¢TÜÏ’<'ÉÂuºù ¬iî 5G°3ÕH˜Pñ<Î¥ßI‚pÈnùn8õÉg`M«›­F™~yéÐN'K-IÓKœúõÅ‹ ÆŽž|Ö43kÈQÊÁª)õt•X$÷NëŽ +g“¿×'Ÿ5M^Ì>rawü·ýe^æWú>öò Ý4óÎê“ÏÀšV?d_u•Ë•¨qoeu å:}Áó“$‘Åå/¿Öü™;)"y÷þŠ4¼¦\:òš !þ ÷HjÑ7û>ßvdêÞ²¿B9HÞb«‡—G~8 Ä?a|È“ÏÀš¿ì½öC¸Õ¸Mñ¬ûëWm…v5¾â7ì,˜úä3°¦™‰ïЫÁ²*)䯧ù¡ T5£%sÏUŸ|Ö4wRQ r#¯"M‚×Òx%bI—X¾5%fÍ'Ÿ5í,WÉ>_b.Óµµ4ø­’zMi”´ŸÁÞO>kþÀÉ+²†”îëiüjL ã{VOêÝÝßp¢ê“ÏðcÍ»¯´š$á²îÍø¦ § óo6Q%‘>™5ßvdêÞóxÝ?©¯R ;€¨¶'4u ©÷㔨ådÖ|Û‘©{‹ãç(¤¹Ql½î«šý4W•:E:vÍ·YM‚ZìËaó‘ )ù™&I FŠ£‰GO>ƒD~Å#r,¯ïçqë‚¢ƉÐ4wñġ̓æ`ñç“Ï©QÏŠ¯åW" ¢´Ø0M£›j“Ï$MüöÖ쾿íÈÔ¨{çVü0IÇâ(åÀy“´‰lãœ]Ç=Årcê“ÏðcM¼WäidÅ#jxô|}Ç/É\ËŸÈ¢õóO>kš;èBvó˜¢.⢔‡ºÒ94¬K€'˜¾òúä3¨túË×i¸£'HPÛê)ÇÁû %RÉKo±÷“ÏÀš¦OjIj'ÕÄ#ŽiîÄ ôfðíÅøSíšo;J¶oBQ"HŽTz§åª ¤’¿¤OÔLuþßÔÁê“ÏÀšF?$¨zwa_¸Ö%Ž™šµ¢Ó_êš8³æÛެn6é”S ;.qƒù¦†9»O¬Ÿ‚«Nö»¿íÈÔ¨sãü%×Ã5‰@Uõµ»Ê )L]²„?Ïr[’ÔfÍߨ‘ᜌ¢”^j—ñi³cø¨ŽÑ·}TÅ=Ø÷ù¶#S÷žŸÀíà@‰q.“#PH—„™ µ‹aî ë“ÏÀš{“\66zïBv¼äg@Ý©M·”-e„hÖ|Û‘©Q«ã";‹­Ž£HɯÔkíæ>!‚Ë þ|òÔXôk®H:^—r·gq ‹Ü]Ss× Œ ž0±øÉg`M£Ý|ɪ&D)ÜöI¸äÀ'o~JŽÊ‚}ηeÛقļ=X^y»„&Ø.H隈 Cs©~­ù¶#[÷Ö-UÊÉUÅi€K9$$¿qš}η™º·Ôœ‚7’JX"‡Ûxy2b2†ƒ§ÖÈ&55Û³ô¶#S£®`àRD­ÚŒã6s‹jXÝP`µú´õÉgPÝØÔ›ä,ÒXDK‘>ZãÏz/K=€ü<§Ý÷ߨ‘¹“Ò3¦¢KÝ”+ÙLYN|Å!á9Ò˜E‡!Û|ò²·Ül ©m±ûSÓ¾8‡ó¤62/©0)Ämó>Ÿ|jÌTàlW?Ÿ"†ˆ {¥ vÂ@|üÝ0ýÚõÉgø¹fÄ—ñçÊ7°‡—ëx³At×N¦]:g)—jøuõÉg`M«Õ)ùÔ+{$N¯nˆaJÚÞ;–3sÙê“Ï ë SØQÃoªZ¿ÁÈà'I˜ù ¾„ã8[º¯æ,=ù ¬iô‚Ö{«DÕØêôP%¹]¼±´üƒëÃãSíû|Ú‘75ê¥-ñÐXÔ˜Ñ.iv ¶k˜ÎÅO>kšÆ.\h£_1 É8‘‰:Ägbu˜áÉg`M‹Õ¿HÄÙø%ÿ­ºÞ¬Қ^£Ùø»~àÏ'Ÿáÿ±f÷W~‰ÄS–=ûºX@ûÍ9üØïÙèðÔ'Ÿ5 ç$—oPŸoOúäA ”Œ®#•ë  s–ž|Ö4}‘Óg$½Þnæ~.7t – bMF’¢R%³æÛŽLZ™/‰Ž’ƒZ0P9F>’Q™k‰’ÑìÔ“ÏÀš'Ͼ®€KÕHÒxrFmg~.#³'”„õä'Ÿ5N>ÛÜ»ˆ£‰d6=é׸šôÉEÉCzo×|Û‘©QKe']Ò RÝ>þ3Q³¨él²ÀÍ÷Œ¶ùä3üXS×Ì>ÇÎfWQ_Oe[r‘Ú»zƒ%;Ë&çzòXÓpN@_ ÅkÚUzÂºŠ“lp’ðiXPóœánÕ'Ÿ5M®­‚È=šˆ:?Þì“®¥ç§Ÿ¢Q8*ÎI}òXÓðÁ¦ ¨véB³’“mmξ4¤SúTþOÆ'?ù ¬iu³A¬ß”éÃJêôÀJx¢né@º©V)³æÛŽlš,)‘)Gc<§š¢ÄÆ÷RCmº9Q£VŸ|Ö489Œ]jãI„óh]ê;ÍßM:¿Ip¦Nfߟ||ÑãS¬ ¾hšÍ­¿Á™iDG(YÆ*µk¾íÈr³‹bXáσ‰A·òÊMSj¤V™¥¬ì.çÉäO>kšXœ\èÒî;5jx¢ÆØ©ppý ƒm3k¾íÈÔ¨ÃrsjÌ4ªb<*‚títS\ÿ;­_zòXÓÔÁ4NzÌÅ£ðlêè8Y Ceù¯> Ù0՞Ϸ™u—`ÓI3#¯ÚÊ—xRÏ<ØÈ]líkzÄê“ÏÀš†G½$þ©iŒÅ“ÏLL ‹Ç …æœwJ†_מ|Ö43kÄ‚˜·JˆƒÃ˜QóO»Õ+y4­)Ë9io>ƒ75êÕDZzš½”sºêOåÆËР?Ò4X±½ù vÍØóp‡|0#+¯†e%µzaýEH 욿±#£“¯‰²_ÿt®/¢…µ¬ …-¼7DÍ0kþÆŽ W3ßjN ç¾ðwší Èãk9ÅWÒÙò㻿íÈÔ¨¥ŸÑü`ÓÕ®zWùV"ŸT(¨šóy²Ñûmo>ƒ75êYH$ÔÜró& 7eERŽÊ¹zA¡‡ :ŒK{ó¼­Q“îF®<Έ¨~‰,+õ’r:Gí:Moùš5ßvdjÔ9ùìå6ýÌ"~§äwU æ’CM ]Å®ù¶#³æùkhï¯_BÑÐÍÞ¨y·w>¸„?ùµæ›ÏàMÝ{Hv„¼ð,Ž%Þ}Õ:g'+Ë, SshkfÖ[{ó¼­{“›ôÏY‘ÃTx7¿/’áˆ%²èh8<íÍgð¦F}†ÏÒ^ê`S5 X%~(1`¯r#ÒcgÎç›ÏàMº€ tQT›¼*5û!¢!áïÔtEµ4k¾íÈÖ¨=Fé5X› «Ñ*`kþR½°¢ß·TÝqάù;2Ü-×›F“{Têí Ý'G–TsFµ mIÕ{óìš"‡Hn)Eò¤ ØXU«ä"+êåZÅôà´7ŸÁ›º·æÐeµj²š~.I*x嬦y\<ŒÑÀlo>ƒ·5êµ®î4uFsÔ¨™õ jÙSc£—îfbFó¡½ù Þê‡ä¢nR1ƒ!‚Äs“Ǒ̉CžÔi¿;¯Üœù7ŸÁ[n¶wwÀ§´æ"Þ-è×r ,ž²4ùñ1n³æÛŽLZà× HÓKøQô×&¹«{Yâ4ØÎÚæ›ÏàMúº#œwö:â_Å9ÒäÞÜ`Œ­!¯§Û5ßvdÖ$ÐAЭÛvÉ™Õ%ªw¼X\Xü³c¿ûÛŽ’Õî;MC»Õº«ÙG`äy§ÃûåìNgËÕçcf½µ7ŸÁ[MÍ»"@ŽE¼˜ ò Qa¾/Ý¢D?íý{{ó¼©Qƒ´Ï&Ó"µrÒPþF/¸&ÕÝ*$ÜV­ÅpÈÛ›Ïà“íYÖ\Ȧ:ªÛÌXÁCj V!qèšiªáÎfÍ·Yn¶ç7e¼[p8Ñúé¤N<{ò·cH³rx»Go;25ê,uWMÉ“¬àÖñÕ=wª ž”äOëçß|ojÔ$¯Ve/Fi¶'õo¼V2ß ¹„WZ…¿Ö|Û‘YÓ­KÀÑåöØ ä¬ž“$](iRý–Û3=ËíÍgðÙÚ»äN ž¼€ôp‘¶¦I¬ý›QE¦¬Öœ¥7ŸÁ[nöI#µ2ûÒ}¬6o#½2vþEÆã  ¶YómG¦F½N#« ¾žN.VR1MB/ê¯Pv°$cïo>ƒ75ê¶ÈÚqRò¾Å8”¹3‡˜®»MÄ?›5ßv”­–—Ó F?0ÅY¤#Üj=qê ÿIhæ DÃio>ƒ75êÈ÷Ì„s :k˜ÚõŽýד1-ÉÀ¦L-½½ù vÍÀaìMÓƒÆ ³¨7¬ïª 8÷=ã%/ÉmÙóù;2ü·bÃ}„-ôÎ[Iô9//5C’¸­‰Æ×½ù Áê‡xÙt™®èε…O}~ó´N-»·kàR¦ÆÒÞ|†`jÔøŸ¤ï.Lˆé߉ mkø.®e×"-ÃifC´7Ÿ!˜uÖP݇«œÅw©‚ÌöŒèõì û²:íÍg¦F- ¦ÑâÑëv/gÞé$ñ$à¼|µÛ{ó‚ÕÍ>“½èÕMAh½„(…f’ì­¶uxΦ&ÐÞ|»fªAMW9WŠe!ä*¨ D”D5ÿò²eÛpÌÚ›ÏLÝûx'„ˆaGZ"Þ]¤…ìînœ^ð]ùñœO; ¦îMÄ$ãPsöÍ^»q)Ú«y5²ºÖη s°géiGÁ΋”È1è+HôUŠÚäFAZºYlDv oèΞù§[£ö“ôG܉µJcu.°ö”¨RcûÙìû›ÏœÕ(h¼L•¹1‚»à(9èÄMŽ‘nPH Oµ½ù ÁÔ¨s.SÂU=*œiv9GKÍ›|?Ù[=S. ™Y.J3MŽ×pcÚ›Ïì¼H741ÌkTµï [œÞÛ¼ç?"°#÷6š$íÍg¦F­y{ D VÈd‰üÍ*R¯Ë–-‘E§ìƬù¶£`óbÉb:ªYS‹j磡Hì5WÏöiŒ˜Ý÷·™5A(}wÛá&¢O•üØå/ø|Ò.½•1‹íãko>ƒ]3jÊMÓéÚ¬{4L=–­+;·ƒV6oìýÍg–›MȘš‡1=™U$ &ÏØ÷¯ ¡RA½ÌË~÷·™ºw\ªMƒç£fl¶'ðÔ+7{Óݬ&áøbžóÍg¦îý‰gèŽ+m]y]rI;ï’‹@÷ ä¯R×0k¾íÈÎv²“ûØÜÙ ß|Å][ZN³Y—gfÍ·™õŽ#®æÔe<¥í¯m½^‘c*¾´©Ö W³½ù Áò¨ÉùXiªµGÚýS ^S¦¯ùÅ@¨{$ cÖüýZ³²'¬ð^•i0xNMW!Y7ã­ê¶Ïù¶#S÷^ÞMn¦xp‘XÉiþ ^NœÃ9$WŸó‚åf“5—§f‹ZDXT'{xZÃ…NPÖ×½ù ÁÔ½%d³Ç쬂ï$éhI‡rUi6jðá)?jAo>C°Ülþ vÄŸT?Û·[S°Ç(*åTÕpé /¨½ù ÁÎv$AŸ<çÇætª¼5xâãPkÆ-9í4ú6íÍg¦F}†¿éJ®“Â`ö|uÄ5ÑE&;4ˆÈ¬ù¶#³æT&,µpÕx»n¤Bÿ.bg9•ÃbØ¡9ûœo;2uï«I(ý©/RoÐüáëÂqš¨7ù™×ž¥7Ÿ!غ·+`‡g ÕÖ˜É5°_›,‡Ÿthîíšo;2u戴ü7höµF´ïîwnðQšvjjvßß|†`jÔÄÇÚÔk($õ¯Iæ”Ùž®¡_ó»æÛŽL:‹IÜ4ªˆï»%x1~vMÀ£ÍNý¨ù¿ù Áj\ëPk4@ÑTH5Ïrû ß"Ï®×ß.úlŸómGfM@vS"#þy« ÷¡¡Râó‡$Ýgñü›Ï¬&‰ÓˆUgTª­${7Ü‘ÿºÑV”ÄOÇs™}ó‚©{/I©nUc§†‚ž@š%˜Ae%«{$J—ÜØÑ›ÏLÝ{qZðÇ·¶K¦tâÁkâbýÛƒ‚ø§ø“s½ù ÁÔ¨¼ˆ‘’õÖÌö˜WÎÄ{Dr\Ìf.[{ó‚©Q—#M=R ]öB"ËGžGÚß2/½٣7Ÿ!˜µ—‚‘Záv“–@lz(àl(IúºI£Š’·õ¥7ŸÁ®ÉÉ.ªð³A 7_$D4sW‚†âGHDÈòçÛ›ÏLÝs? ˆºº1„Ï–”Úm™g]Z³{ô;2ú`!/\]‹bÄžopäÐEwvDúøÍÿ´Íšo;2uï½rÕ±¨ý•DñdW$§ÙÛþÍë¶ÒÖÁÞ|†`5INàQúÇ1s ˆ""Q{ð8È4bö¨¿ù ÁÖ½Hü~}ÿRvZ½’ÕÕž÷m#¥>Ù±x—¹Óïo>C05j^Ü”Å]L+1hÉbJ\i½'ù–†oÓß|»¦j†s¯~hÙ|‰3h4ÆÊ¥éÅnzÄú›ÏLÝ›MÀüy¶ÒœT·ß“£4†*óWÅ!)©`ó‚©{'U}u?¦œ®ÓN«÷¯©òP$ra»Go;²Üì³wªx=)΃k&÷Â4Iû]Ê Ó¬ù¶#[÷æ1“Ã×’¥È]~¹ 7h°xÊ^½-V7¦¿ù Áê‡pö–:’0nM¯XìÉ”|™:˜‰wÊnƒf@ÿZó7vd°wù4¾ü©î^JN;vIæu 3S©¿ù vMõÃ-û¶ÔH•"(ï¬aœ5Ð{£Øß|†h5It­w4^u/ñ*]îúx=îÝÝpÅàÚÅàäþæ3D«Irt‰)™ÑþÆùªjƒŒYs|H;ºŸÁœÏ7Ÿ!Úº7é I¡R²ÎU¨žœ7%%}ªæð³þæ3DS÷VIê}œ"òÎÄp;Ñ ‰™ }8>ìù´£hjÔç¡ÙT<ƒ 4ÁšÑ¥mRç üÿñÞú7Ÿ!šµ»º}únœqùâK±€5D*®‘…saÎü›Ï`× 83¾ë.êÏÖ-EóãÕ_- $×l÷ýiGÑj’8Ì=UŽ‚¦’óÈɵ!$?8ÊS¼¡n¸ÙýÍgˆ¦îÍ"'|R­“£V€¼ú5µæ‰Î~ùcÖ|ÚQ4u︥…45p#¬Ný…ê‘Â' ð"/`¬þæ3DS÷Æ¿‹ˆÛÀe‚ŒC”Ú‹ÆÝtYÿ²úåÌs¾ù ÑÔ½AÆš,|Ôæï»äÔ}’oeå´$l¤&[oöèÍgˆ¦F滯 |m¼rÇÕ“¹ £´á²®Xz<¦Öß|†hjÔIìc ]ì[¤Ž•@òêu8X,i1aX‚C4uo¶â5n#-û¥=$ÇãŒØœØaö}¾íÈÖ½k–—Ј„9c&+*Uõc°s"§!åæ@Ø9MýÍgˆ¦î­í}p—tÛ!gN#JÝ‚Ÿ.£—æÒ¯5ßvdõC–î:ÄqxÏÜòW¹±ôN…€L¦mîzú›ÏMúƤÉ2Òv `y52N_>©n#Ð…³›Ñöéo>Cô6/ÞšþÈüK1Ÿ%ñ %yçºÄW”æžñ!o>ƒ]³©´¦&×”I¾–æhUUUÅ’!4UuÇ›óùæ3DS÷–À¾»ç:š±B~%ʪ¤[%Kqˆü1N;Þ|†hêÞ_³‰>‹†Éi$$Ü4d#÷Þ[J¤I²mÖ|Û‘©{kdo䈶 ^*‘ì Šr Ï­8†w2ûþæ3D[÷–Júêºfîºe»ÔZ*rˆW\Zê`楿ù ÑÖ½‰ŽØPðóx·¬»¾ˆEn~Ÿ„hòʶºýÍgˆ¦Fß«?«6û¡¤S/óê< r·jèö|¾íȬ h_ÖøøTK¶YSz°ÒP^±ÎV쾿íÈ΋,sjºxçd‚dï·uI©TâÑÔaÙƒ¢~­ùæ3DS÷N=ãæðȧãÛƒì&  ž&K\QÎÀÜé÷7Ÿ!šºwM`-!ÅIšQ$Î2Õ%UÊn$³@§¥¶9ÓÏÕß|†hêÞ/Y¯d‘V$‰‰¿â+ã芤VI¦Oª¿ù ÑÔ¨±C1GÈ•Á[)«¶¾AÂZ·°I3ÙÜðÍgˆ¦F}ïmI–B"T& »Ê>ľ🠡 Fo­¿ù vͬI×À~&˜Ž÷ÇcÀöØžgmºNÔÈ “s½ù ÑÔ½5׬t|[[dë^5yé)LªŸWþÝ‘fÍ·™º÷éQêZ{5¾âVΉᨌŒ'IàüšûH¥Ú}ÛQ´÷\B#íAR«/’”§$Í¢¦XM/iaÛç|Û‘©{é‘òLƒpV’ä-ÆÈ;“(U)¼ ~Š27ß|†hjÔ±òæÀýu„4²ZÉs"“#“ñ; õ&ÍËF/½¿ù ÑÎvœ—9$³Þ¼Ô¬:ȳã5~ÞÍ¿‡™{„þæ3DS£Î•IÙI¬mhÚ gG¢í⮿Œ£š5ßvdÖ\„±Ä±oNId<¨èL+kÚ̳XB£Û¼ù Ñêf+ kÒný®òXNýú¹E‰‘ –=yÎ`Ÿó7vdòb€RV±|“bÞÉ׿]„eñVE< õ˜5ßvdêÞ!Ýä5¨È•QH:9>Nm‘+5Ü,’ß›¿¿ù ÑÔ¨5Xt* \ùHag=š½»1{?ò>¶ûþ¶#S£ŽºÞ`‹ªôã€Á{{jˉÌ!f-jr™7Ÿ!&{_LxT)iˆ3œ‰Âcnõ,—;IöˆÒì4ºýÍg°k’c޵ç`—®8óc'•¾ÈÈ^óR!Hìoó>ß|†hêÞaK¯Eý5H¨ˆV8z¤PM|é ”±÷7Ÿ!ZM’Á&K^J–¹È…ˆ>“@¢>¡ ØùmêóýÍgˆ¦î àhëNÖ ;÷j¡w+_ì×ì8Kó=ö9ßvdjÔ…¤Ê‰ÝI|YFÞÇ ôºuΕôpí¬áþæ3DS£Ïh´ϽWE%±(óÀÝ$_ü³³ŽÝ£ßØ‘á‡8¬ƒß#j¦à`³êÐèDâé© ÝsØçü™ÚšâÛ[úósMºáž¼uåÁ?^ü8Üàù7Ÿ!šºwÒH®8«Tjï %Õ¿gK^‡:(¨ÇÖCÞ|†hçEÖ“Ò!ô rñù’²Ö%m…8‰ôA¯Û<ç›Ï-7Û‘½;uêÕãø›B†á7AÁLrÿ df|Ý›ÏMš“¾5àoœFàuxPõ_íT“ÄÍÊàÑ Åìû›Ï³½“:À„î[O ˹óQLP’×5‚.‘É™íwÛ‘©QKe©.É”\ï’¢^˜¯‚Éb,|õ3Œÿ|óìšn«kj2nSÝʺ4"‡MIžœ«rüM­òÍgˆ¦îíÕ¨}µûHÎý½l©'¯zp•`£&¹›5ßvdêÞ=ëÂ1ÞÙ¦²4±†P¢óNwkæ¶t¹Ìšo;2uï+öøšdogiêl ÍÁúü˜×JÊꢷïó7vd4I¢j±ùÙ¯”˜¦ŠM$v|.{M¶Ë7“ǽù ÉÔ¨s¨"|ò´^íøóÌ ˆ U÷s—KŸø×šo>C²³ãÐ,?qTÙ~PÞˆN™²Øóxø:ù"vͧÙ5¥ /ùé‹ÚTý(m²Sª:°Ýkè> aÖ|ÚQ2uï:Èý#©VÅ‘|MòW)goñýÈÌšO;Jv^¤”]È:D)Óµi®DzlÉå)ÜrîLê“6k>í(Ynv6žeâH3Chø{iÙ9Ýš9åÌë4›¿¿ù ÉÔ¨5¾TbóW£Š‚»WceÈ2ãúƦmsí7Ÿ!Ùµ¤ÅÀÙäñš Zš#y+ £8âÅÑ/¶øæ3$«È¶'§T ?¤êñÊNQŽÄ(N0‰³sîú›ÏLz­ðÖ-j·óE©‰È Ë»Ô ‘X#±Íš¿±#£{p3¨0°)‰c^¥¡)u ÇJ)ßvdêÞE ÖKf](WT= '¾XŠs€/õáI2ʬù¶#S÷.d®‡ø{±õ)rP½ü˜±4qÙ“á%õlÆŽ$pø^Ô@5òÙKF … Ò¢n¨¾&Ys±â|ðòÓvÑßX’ w—xš9v͇Hd—[Yòeëz«Ó]á¦j}›’)Sëë40èh]Š.: CßÛÁNdï‹úãIß¶dÃ,>ê®GDj56"(É·‘;aÑ·=YmP7n©Ô¢Ú4+¢åàÅTùW3>ãEßeŠÕ_£éø7Ù|I¶îwHìþŒ±+y\vÑ·E™jõh¤šã@>ïõN'ÿ8ã›;)E[ºfÑ7µ!™ru GËq€j–¿A2t¿ª›êXQ0´‹¾-Ê,:‰¼¾téˤ6KéNy>ËêTªÓbQýEG¸ã\±û¤KM³}S šYÔ?A…&K †Ô¢¿±(£¶†Ç}v5 -u+Db·”|HåÒIî(s«À¢o‹²%ë¤/*ää1¹Ä¶Z&ÂY8Ä<þHˆ?žômQ¦f}–¾á=®'àèY„±/Ö¶—#¨|)„u(o‚C2EëêN䋪u[2ñŸ¬`?kÞB»¼WIþñ¤o‹²*%D'Â(Jo3Å®~µEwÍõ‘mBí©?Îé̢ۢ|s×á)‹¿GB¥"’ÈR»ãTrc]w™Eßejáu¨¸J–$QUr ìF匋ä;¥Ä›}Ò7É!ÙbxЭû$ÕP“«ÆÓÀ¶Y³âIIs«Â.ú¶(S ç±ðDh€þ%yï°ØÜKóYú]2¦mÛÝÓ’#Ùëá°o1'Vß),/™ÿ5ñÚK::@5PËEßej×^±S¸½ÎkýàæUpJtØ3üê5÷ò,ú‹2 ³¦ÇÍ 'V øh …ö¼` PÙ³ùõ‹2ªü¡+ùÞä¶>¶˜ÇŽMs¬K$Õ(ÞX¬š8‹¾-Ê”ÄÓ–@uÛs§Y‡—–ŽÄÓ5¡oIõŽsåÄ6ð½¹Éê•lMØQ:KŒ[ß~R¤æ[UÃŽä¥~©·E™¢88;z¼Òµ‘˜è´ÖCÚÐ×X‚qÏôêx³‹¾-ÊT°Ey^3hìV䯑:—ÏIÍâËk¦¨¸¼Ñ~ý7Ý!™všÒ¦&ÄaU“>8“ÒÜ=º/^\bãÛó’©akbyGÕkäR¼7i Ojš©@@Ýcê}§oÂC2EìÚÆÍR$lø"};ɇ©faÍÄÔúÓLߌ»(i"§¿ºjÁØË åÁ³ð7{é˜á³yßÕ´7å!™ÒxÒ¤¶! ð§>–Kê°eQJBÑoõŠÇOú¶(«×]4aon–l^ݘ‡2HMÊžº Š›+aaÏ›ô¬¸¶|ñå4Óxó.‰xé—ëÄB)ÌKÅúÚDâÍzHV¹h«j»ÄÁá•ÚOSx2KÄüН²œÓ·EYéij¤­VÄ]ö(c§>PUx§ä&Û}³Òí¢o‹ÊVû^M¨[í²mz$§¥‰…ÒÑ’nb>¼“ì¢oâƒ]TÃî¤ ÑôCwë;HÅfIa‰ÌÜ©JÞ݇òf>$S!×,껤öÁ¡%ß9x¡÷ø*‘¶8$SÏžò®Ž6¥’Ùt¡þÕ=ÈÔð¤nyÐÄÇ‚Þ7ù!™‚ö „SÍn×( ²‡,½ò 9I[¬›:þL$Þì‡dU¶wàKâÔó¥i•í›N…/PßNÁ­ðß¼ì9}Ó’)i/¦p30rÇÎ8WEg° nÕ9]£»»ÿ‹2uò34)zJzC|'€ŸFqxu’ª]ÇlI¿ )[Û'¡ß‹äTz‚Ô•#@Ž/AÓYÀâÙõf@d[)W‚ïìyd¶m‰ö!¢…t«X»Ë.ú¦@dSÖN’L¥Ij7ŸˆW‡·8Ý ó)ªkR…Â.ú´¨lëÚ{aDiø0Õ#^KÓÄÊ2$äQ]8ê'=×ô»²èÓ¢²)lç‚ç¤_y%œIШ‹‰Ç"ºrv¯”H5¬?}³ ²©l‹Þ¤ï™ßLHRÕˆubæ‰r3@ÛÛÊÄ›a=ª±Ç”ߨ'±G5»khÌ 9ÏpäçÇ×ZT¶Þ5V©Âd"^Ð0b‚ôm1ì4ö¤tM¸ Ýþ7"›‚¹fØ=»F¨œH? _ ,=aãýªwõemÿ̈́Ȧb¾ÏnìC¢Í@8E2øbOw•½oÛ(½¬çS!²-™o¹R`šæ²j|+È¡-¼²rrrÌ,eæº<éo,ÊêþÕ¦ñæØ»r>Ín ¿éØšÔ£\,µnÁÄ› ‘­ ÉÐ$€è¿b$©ÃŽ«Œ· œntŽô:®µ¨7Â.zK#uZX¼¨¤þÍ¥nl€_ãu&ñ|·d½Ô›‘MÙ¼©!3‘âUÍÞëüNnTW¾:¼ÆÅ»pz· |o>Dö–OF¢|S=g52à'OÍÝmÝŒ³ER÷#‘x"²)œgÉ I?Яæ{‹GBpyLñ_I؇ðu&ý±‹¾-ÊT¹ËÁ°O…¹zGѺ¢Iš× ò°Rþ¥Þ”ˆlÊÜü@¼Àmìÿè¶x†E€*ºÐßbžDÑì¢o‹2unDZ¢ÔNT˜^µVª“OW›¥’¦œkÿQ–{“"²)t' ?¹½{õ „Ly;HG]Äê5Ö\ÐSªcÑ·E™B7ñˆ˜é¥•ºK§xbŠòsÍy¡©ܱïôM‹°‹bÛJê§Ò0BÞÑxI•FpXŸÈ§+âùþ›‘íÜÉH¢Dkî+Ë•jøIApª½WÀ»Éuþ71"›B·„w9€!Æ4æƒÿLF‰Cù@¶è±·ÚwúfFä`™&]½[‡ÉCª†~wKFsΪ#¹®?âþ›‘M¡›œfG ìèfœu¤9x¥‚Ÿb¡ªV·ÚsúæFdSè&.uÑ€HrqTí<­%ÍüÂJ=ÿÓ½GËöœ¾ÉÙº?m‡ÜVªÒaõ›]‹IÕÀ)ÊU΃pÂ!°žÿÍŽÈvR$ o©Î}’Î¥èÔ麣„BÊ$²X\ø±Qo‹2…n)ÞqNÛì[%ɃOÁf¿Þz¬_•9mÛú΢o‹2‹jþ… Nã†Ð´æBûšgWHÿgíöœ¾ ÙºÝè|¦58óЇR¾èÀ©–ÖÚÊì¢o‹²(“îwé2ÒKMsqðX)ßþ­cýE:Xvš2éNwí =òËíº>ý:D³æÎß›#‘­wJxM@¯è-g6 ;»¢BJVÆ•–ÝvãÇ×[T´P }'ô…Ô×û…c„ÓGsņ†H.Mß,‰-T3ÅÙïÓeõNñoZ>$“·]UÔµi}[”•ø&çñáªôŒuŠúžJ E'[%o;;[˜yó$²)t—ÀËÌÏA«±¨ûßM‘”·,·IᧇSì¢o‹2…n›”ЧãêS‚g{5_~X£«ôg³è7S"›B÷ؤxdóPÓHV+ôñŸAø[îëþì×S%²•ä®Å͹€TäÍ}}À© äI'P‹°‹¾-Êò¾n‰‚椤ÌâY5Æ µFµø$ÉÚEße ÝÀ2Ì©êžKóu4ƒøè¸»þ ÙÈܣݨ7[Â.ZEýÆôz™ |‹|¥^µ€CӵᬗzÓ%²•úÆÙùØ¿"ÒΩþç—æ–¦½¤srªÃ‚‰7_"[Í“Ø ÛÝ„RMšrX*H¢/­µýò-ýx§o‹²)Éq?£Q¿z4€j&5ÄŠE‰ÛÂ&=·‹¾-ʺ%36KÁRè«•~RÅÿE¨­`x.•¿ˆ<ëë_þÎý{~Ñß}þË¿üuüóßý/âŸÿÏÿ·ß÷¯ýûÿM?ÿsoÿ#¾…L’ôœÄJzzQÅš{Åyû¸[êýõÿùü»~öÿÓú÷ýÿªý»üËþ³û Y îýÿñùÜÿê‡øóùóùóùóùóùóùóùóùóùóùóùóùóùóùóùóùóùóùóùóùóùóùóùóùóùóùóùóùóùóùóùóùóù7þ;¿ôÖðdarcs-2.8.4/tests/data/minimal-darcs-2_4.tgz0000644001765600176560000000656312104371431020056 0ustar ganeshganesh‹{.Lí[ylÕ7 X”ÒþÁà ›ÆÞõÌì»|$Á$NÜ8ØŽófæÍîÄ;3³¾² …@Ó–BUJ¹"Ü U=€†ÒBÅQ­Bªp¤‘–Vâ (m T$ê÷ffÇÁÙ»k¹™ŸÖž™w~ï}ç{óÆÐMÝÀ¹¸ŠÅs ¾®bÜÁ0Œ$È¿ŠÁ•áøà±,ϰ '1"‹–OJLÆŸ”£‘w=ì)=V8F9(¦iÇÈÇqè:I`Åÿnÿv<ÅàDøÏ2Ià¿ rÿË‚£ù¿xNCsëœñìæCäùÑù¬/ò_”‰òŸÄ ÄŒ'£á$çÿ’¬î"øa‘~lØ9‚, aäÛruÏrâìÉD³‚¼,A¦åæòŽíÆú,§é¦çXj^2X󈃚©0!¦Dl¢ÇáØÕþ¯ ìK¥ôŸa¥þ_b’|¤ÿå@»Y¢ÆBöGêz²aTý£[7{‰IÝÀú(¥ÿI‘?2þãX–•"ý/lGw=Ý$õEf¤Òq>•Æ8ͱi™N0ª&I)«²ÀrI…g•$Ÿä•”HãÙTJ•°ÌŠÉ4#0I-Öƒj˜AfÍ‭Œd9–y6†Z2&DqâŽz¤*²JT) £ñ)œfSªÊ&‰Ê§’|¬ Ũ Ö£:Ž㬤Ðõ„È <ÈŸä”Èq<ü¶FÀ)‰Árº•€@Â&U–S0fRc‘Ñ‘†Qõ_7UÒ?>}”Œÿ¥áë?êÿE‘âÿ²àêö¾x_d÷øÛ¼é»ýÒ;2÷}Õ¼å ~{³ºóßkÛ/ª³z†È®ÿvÿUÍ‰ŠŠUaùã§. ×3àïέŸtZko~Æ”×§O=ç|–ùú ùÕ_ÍèÞòØoß~{Í}sÇya 8¶þS÷sº:¶>JÆÿ#÷8ÿ#ý/ ŽÁÿ ðÓɘ÷OxÿbQˆöÿÊQùocOÉŽ÷'ÌVâx)â90:ÿ¢Ó[€á°ÿ#J<ñ¿8ÿƒ…a"Ø‹$|û׈ÿåÀ¨ü÷ÀûcOï%ÝEIøÂ}”\ÿqÂÈý^d£ø¯øŸìÿLô "7F±öã( Çóþ—=Rÿ“˜€I®ÿGÖñ&||pñ¦3‚›)ñí—ŸýM4µbǽOÞ½µñ¬|òŽ—·_pÕì?¾?ÿQ¼nïó{û¤ÖÜtÿG—ÌXV{~ͼÇÄé4ˆŸ.ë¼^}éö{ÏÿŲ™.žz¿kÓ]õÛÿtÖvïO®Ø±E(úŸãiQSyUK ЍIj ³`˜¤š†«Âr,N²I&I„”È©’,²Š aVd…ð„—ä49ýŽÒ^à"ý/ëÿ´ß?;m=3ýÔgf/ÍvÅôK‡næm¶7^ysKÕ§ë÷ýó/oi~¶{Í=7/?wÛž—wîoúrü7{¶¿{‰3ó‰çômÿºþÂì•ÿóÒ½ŠPsÅ‚K~é½+œ²¡½âúU:ÄÇÀq¯ÿTœLã$!e^fÔ$'²F´´ 2l*Í`MM1“þœ>Jéÿ°õÇ&iü/&ùèüGY0 ·IRfžçÒ)Ma–OcMÖ ÄKƒ7ÓÏI˜ð,áE>-§!öÃ|ZH§YBCNN G®ÜKòŸãÜÿI²Ü¤_ÿM:û?eb ‰0!(±ÿ+ë&¦¯€ÆÔG ýg9iÄù?ŽáéùÿI­ÿ“•È?¬é9‚Ëô°nº£¸z˜ô{ÄT‰Š’Éç° ®«[¦[‹,“ ›8±J(¾¡† !{YdÐHº™AØ MyYâ’áõýcÇ®›7 yÏ‚FÂþ‘/tHÅFÕ¦å!Ȩæ—d¡Ó£‰ ÜººD «E)EÕºíètpk›·í1 ôoAÿPÍ+8eáטÃf?6ÕàÉ$£›&@ŸÃÁ&²Ï‚V› êÊ„hÎ?Í¤Ò–Ú ¡³Dú«¥¤YÌ¢J\ÅÑmF[j2±ÎD5.4ÔTÑÙ° ­máà Wh¼Ž TK)4/j HN)ÌYP|è'…9+æ]+Ìk™> æ]Üê®Uhi_<¬ÆNᚆÅáƒMfg ×´Í™=/H0ÌL¡uañÁÏm=œkw˜rÆî2 m çµuµ†ÉªVhkûµ¡…¶b ö€Rh»6¤¨(ÚWXR$ÂR—iõtM›]XÒ2wîì a°æ êváº:=­>“¥ì¿å€Œ±ö?)±âHûÏ Qü_€ùóYnß~Ùn},VYIí±aCªãEÝôˆBA¿ïðïÁlëØ#~Eì¬zH.‡ª3Y¥&(¢a²:Y½Êÿ—-Ë£·VxW‰,y5Q¼°Èðs;Š¡Ò\Û± ‡’¶¹vwМÝmU ëŠflѽÄÁ:×N kA75 ªyz¿_Òiu0Ôž¶Ý°Ô|Ž¢«·–ïG=Ä1 íº§H™_î«bÕ+ u5ЪawC¿¾)¯®‚$¨< Ê RWaÎôP MHßF4œÏA QpÞõ?ª@†žÉzPQ&h>x Š’ææ°ç»K¼*L¾—…Œ€¤j:û”8ÆÀC™µˆXw¶÷bèÏ£Î]%tÜŠÕEG΃^”øàÜpC(;¾G½å¬ ûþ2<ËÊQjfèDUCµ.PçF=?\S;$;*t³Ô±kz&ïø94ǃ} -Ùd¤.hioCVÞ³ó¡4ø>´ÉO¦4µ.mZ@;Ô°[€¿\ÁµÁPi…þ”¨A—¾ÄÊy=§úÅm¬ôà mwÀõˆAçHÁ2Î!¼” x<œRãvO& É.ñòvñ±A £6t¤êNmÀ5DÃà[ÈaJ:y-uj¯T!©®+TQ¹Ày#`Ý@xè£Á{X•, ¤ÇÏ :‡!ç¬Lðò®?·†®8–kiê#ò° ¢õên¨s½¼ª[È öƒ( XëŸåŠuv÷zz·b‚ô·v¯¯ˆzÚËBa ‡ôªÄŽ;ÄibVP4‹~ 941ÚàÊÎDðò T?šs@T†Ío8ä¦eíÁ0a̽nCUBɱSzü¶+!üQPqqSX±¶—–wórØ[QÝ^³¨~q”¼£ã\1/›)fet¯˜·ÅTyЂà¿ß´Rì³½©Øi%ò]c¸ÉaÜê ‚Qúá\º2L‰Ãðí¸õ\U,ô³2HgÞîè¨Wu  ¾«ë2Ÿf”LÉíUw^V¨ Ûîu]( OñuÖí³CËÓºd8khíεÒ4%®«‡Œ’¬{=„РÝÏoÔ½ùþã°:M``2¤„ã3ÕÐ]¬,6‰•§¬ ªò:J“Œ{襱a¾o†hð@â@q.0*ñ 5ð^å ÙjZxr‰ピDp:‘õeb0å éF¬³2 oI6oÈ.Ì­LëöêE‰ñp&dM5½… r^;U—9+ëº|»VLÍvP¶Ð™¨QBésâéT·«‡„f UÏoY•lXÂØ$0`.•[Z˜VêÃZP²APÖóìúº:jlËÊÀ",a]åêŠr÷ñüOt]. GˆUƒx_°ŠðU+È¢«P?§X¨¹½»Ýóqâþ¿DügXÞÿVœØùßðû?‘Îÿ–#N{7dÇá3›Ã}”â?'‰#Þÿ1‚½ÿ+ ïÿ^yÛ#gÿŽ™Úüqá–ÌôéS†rW3ÌÃHܶjõ†e;†œÅ§Ü°èkC û–ã¡w=óËk—¾ûhç®'vjÆÖ›þöÜé{æ¼ûŸ_Ÿ¶úÃm[õ÷o³ó3µâîsÞÙüâk»ºÝñ^÷Ôíû ¯}°èô]­?µØõÙ÷—Þ¾þ¢OÖ?w÷ž·*ú§>²¨á©ÿhÚxæÞ÷÷¥†n{vÃ'›Õï¬>xö¾›ßœy&ÿØyw­Xõ½sеVñäÐ=Ëÿ8±÷‚’ç¿id7Æ-€Òöä÷Ÿà¢ýß²`Mlm´‰vãxõ?qè<ð‰÷qâúωìd÷ÿ“‘þŸÜøœ¯ýНe…tœÁ’¬’´*)’,òrR!ŒkÌ0ª€%5©ð)ŽO1¢šJKjŠå%)%NM+2QC})ÿsÜÈóܤÿþsÒÅÿ—þžÿ›zÕËk~üÂyg¾¸0÷üà ™‡™Gj®ÜqÍŽK‡žòæÓã§æíVΡŠåµW7Þ½ïƒOÎ`×=þj:óᦠ·¼þÚŸ‰[žP¦ÍüÙ.J½¦û­NS·½²…=‹møÊæþoÔÜòÂ+û=÷µ­7Æ÷ï7^´âÂùÒ”iÉš;×%¸Ÿ?}ÿÄNF„"Dˆ!B„"Dˆ!B„"Dˆ!B„"Dˆ!B„"Dˆ0Ið_$[(µxdarcs-2.8.4/tests/data/many-files--old-fashioned-inventory.tgz0000644001765600176560000025224712104371431023644 0ustar ganeshganesh‹Üz›GìmŒ×UÇ7 $%ªø–Zi *BU“{î½ç¾ Eª„¨jlÚ¦Ô ªJá¾&¦É:µˆ4E@‘ Mê𠄨 ŠÄ‹ _b˱RT$T ¥– B%€b;NÜJ)D4õ…yf<®³sÍì4×3Êù}Yëykwuö9¿9óÌùÏnãžÝùÀíéðîÝo»³;|Ûƒ)î>°qwÚ8rðÐ=7®M„5hÄî«’/ûzž5`Z*¥9z’B­]‡S¿ñ«á®ÃGÜ¡ë®[»ÃúÈ+½n»çʯ¢þ¿Ý¡pxçã믕ª FÔÿÎC9°‘Fÿ!Œ®?äôþ¯ÂNêŸõ=VVR¾Býñ¢ú«¦þ MýÙkô;¿Œ×yýY{õåþ!ˆËƘ÷¿;nK;8ØAÿœQÿ¯ÁêgÚˆ6n}õßcûþ/·ÔŸ+ÔÿkpïÕ¿NíÿuÌÎßÿ7ižvGܶûãßÿÍ?½ÿk@ïÿ×77ÜxÃïØwpãÖ}6^«¿ïþï_W§û^v,ÈP5óß¾×èçyýûÿÐÁƒG^éuÛ=¿PvÐÿ9c†W …•b·ó2šÝAy@›™ÌE– œtÚC´ÉÁ¬gˆQd+o¸õc—ûW&.¢Fý·ó?0ÑûŸAë­Wóùÿµç­÷¿¡ûÇÜÿî}{þþñ½·¼ë±/Ÿ»~ÏîöìÞÜäœ=Ôq!õI ì_»~ÏcïÙÿ•'¯úÜúÚ›ÍOý ¿¼?=1ò?ùJÿ—çû?”ô2¤Øü3û(- #šÿ„4Ée«Èÿó¢Fý·÷¿úžÿ%[ù_ šÿ«p±ÿŸx×ã{ß³Ÿ*ÛÿSû¿ôö|ì_yò=}ùvvSZ_{ZþÚŸÓ!À’!ÿ“ÿ§ô<ßÿËA±$j™´ÎØ8€KƒŠÍ“næCAþŸ5ê¿­ÿ]äXù_ Iþ¯AÁÿgËþ?z‘ÿ¯º~Omª³ëkß³ëù*ŸÓ¯ äòÿ”þ¯Î÷ÿhœ7è}ÓèŪ¢ 8›43*ꦟG+­wŠü?3jÔ{ÿÃEþç+ÿs$ÿW¡àÿ3eÿß¿eþdz›êÌúÚS§¾þ-:X,äòÿ”þ¯Ï÷Fh-´Š2DžÊå¨}–¨¼H^æcäÿ™Q£þ;ð¿Pôù þ®ìÿßÛêÿ3›ê¹õµGÏ=ÿ&òÿb!ÿ“ÿ§ôs¾ÿ‹-zlº?ãš™ ë胇ˆ‚k¯ ÇàГÿçEúó¿Xùiþ¯CÁÿ§‹þ?ö»[ýÿܦ:½¾ö¿K$ÿ/ò?ùJÿ·çû¿öQ›àU œ®¥7F!ȘPÍ쯘˜’òÿ¼¨Qÿqþ—­ÿ9'ÿ× àÿgËþÿôVÿŸÞTÏ®¯í•›÷’ÿ ùŸü?¡ÿ#;ßÿmä&“ŠÎ:¯U3ñ› µ‘˜È I­Éÿó¢FýÇùÛëÿå?U¡àÿgŠþÇÁüÿì¦zf}íó¸ïVòÿb!ÿ“ÿ§ôè?ÿE¯pÙ< ¢yA+¢—žk§EædЉÎÿÏŒõçÿUþ£^µò þ/oÿã`þfS[_ûÓÏî9Jþ_,äòÿ”þÏûþŸ‚E#MbÙI½“èP7Ï·<ÄfžK T&ÿÏ‹õçÿ6ÿæÿ* ýÿPyÿïÛêÿs›'O­¯}ð·o|‚ü¿XÈÿäÿ)ý¿Ïã9C™6¢QÓ¹ýx¼ÕÊ:©™5ÜkiÈÿó¢FýGùÛüÁèúÿ*ü_ÞÿǶøÿáS›'Ï®¯½óÀS§Éÿ‹…üOþŸÒÿûü7æuj†6p>Úf|“1å$æÐˆaµ(,“³DþŸ5꿽ÿùEþ‡.ÿW“ÿkP8ÿ//q`kàÃg7¯üËZ»ÿZÿ-}y bÇÿÉÿSúÿ…ü7ÙôyŒ&Y.˜t6gd–Ùy <°ì­CÍÈÿó¢Fý·÷ÿEùÿØîÿ+F×ÿW¡äÿKœ8ºõyjóÊë¯\ûôä/™Ëû[;…üOþŸÒÿûü7”<&ÏBæ²±¼Ïªù½ã< n-r¶zPéDþŸ5ê?Îÿíþ¿Ôtý_Jþ/â PžmýÇOâ1òÿB!ÿ“ÿ§ôÿ>ÿMH$Ó):“s>±Õ`0pfÐC† Ðõÿs£FýÇù¿ÝÿW@óJþ/â Pžiýÿ·»nþù¡ÿÉÿß—þoŸ’ÀÒyel`*²ì}£üd9$ºþfT©ÿ(ÿ·ûÿ¨‘ü_ƒ’ÿË€ÿ?×úÿ«ñ}ß&ÿ/ò?ùJÿïó_­RX Ì©oLÀ„e -˜˜…ÎÉBp\[òÿ¼¨Qÿqþo÷ÿ¹ ëÿ«Pò9ðáA<Ýúÿhºî0ù¡ÿÉÿSú¿½°ÿÅÀÅh¬Q&%¥Ñ²ð YÒZ9 ™iÿofÔ¨ÿ8ÿ·ûÿJÑþJþ/><’϶þüÝÏ‘ÿ ùŸü¿ãþ¿Jv½pÿ·¨³DÛ4qßx¼d dl¿^]îø¬’ÿçEúò¿j÷ÿ ò Jþ/cÃùÿ™ÖÿoÿÌÿpòÿB!ÿ“ÿ§ôÿ>ÿ…Xé-­¢JÆZ!˜lÈ9£È‘ü?/jÔœÿÎÿW¤àÿ¥ýÿÆÿÃùÿ\ëÿ‡ßû¶GÉÿ …üOþŸÒÿù…û¿a< !\ É;TžcÙ(„Íru 8òÿ¼¨Qÿqþïöÿ9ÍÿU(ù¿´ÿßø|¢Ûÿ¿ý£?ücäÿ…Bþ'ÿOéÿ}þ«–qÅ­ †{åX3ô )±Ñ{ˆÎž¢¤ëÿfFúó·ÿOùÿu(øŸ_bþߌ'ºýÿýu×~òÿB!ÿ“ÿ§ôÿ>ÿ5XmyÖZ0-¼0«ÔíçÖ9-uF'%O÷ÿ™5ê?Îÿíþ?§ýÿ:”ü‰ùkþ/ònþÿ…o|mü¿PÈÿäÿ)ý¿ÏM«›¾ Þ)Ð%ˆ`•Ö'#¸¨02 ÿÏ‹õç\c¢‘íÿW¡äÿRþ_ãÿAþ/ïæÿ¿¹F•ü¿PÈÿäÿ)ý¿ÏÍ.§¤2Òä$b,j¬ÓF'ɲ’Zƒ0Y“ÿçEúó»ÿ¯%ÿkPò)ÿ¯ñÿ ÿ—wùo}ñé»Éÿ …üOþŸÒÿûü·,UóçÙó)d9°Õ]`8š€< #ÿ-y³â*ôU ""KÆ9-œG%Òþß̨Qÿ1þ_‰ŸòÿêQò9ÿOòÿT—ÿ÷ÑïÞý)òÿB!ÿ“ÿ§ôÿ>ÿ-8&…Ø|Í\ Æ-OMÛÖÆµ‰JE‰týÿ̨Qÿqþoó)ÿ¿ %ÿ—òÿ€ìÿ«Ó­ÿâ;?xù¡ÿÉÿSúŸÿ&= ¸E›„H††1%]Ð^7Ó`”ÂHŸù^Ô¨ÿ8ÿ·ù?Í‘ù¿%ÿ—óÿN öÿU—ÿ÷WþÛÿ ùŸü?¡ÿó>ÿ-dc€‹@0£#:„N^ïÏ™£Ñ”ÿ?3jÔœÿÛüNù?u(ù¿œÿLJó—ÿw߃_ûyòÿB!ÿ“ÿ§ôÿ>ÿCB+”«‚°&ÅQÀ´vÖú(ÁgŒü?/jÔœÿÛý®4ù¿ÿŸ,ïÿóáüßåÿíúÕ›!ÿ/ò?ùJÿïóß´gQ`¶€MÃmqu÷ä¢K9£9ãÉšhþŸ5ê?ÎÿÝþ?ÐþJþ/ïÿóû¶úÿd·ÿÿÄÞ]Žü¿PÈÿäÿïGÿ^za…0P7ϯ>F‹™{4¯Õ P òÿ̨Qÿqþo÷ÿ9Òü_…‚ÿáóÿÐÿÝþÿÇÿë7?Hþ_(äòÿ”þßç¿¢åÎ0Ž1Êhe­ ‹È%À܃«ü_Úÿ›5ê?ÎÿÝþ?Jò Jþ¿Äü?Èÿ…nþ·O¤ýÿ¥Bþ'ÿOéÿ}þ+hl†AáA 易!û$´U^qÚI£%í(ÿofÔ¨ÿ(ÿC»ÿ/hÿ¿%ÿ—óÿø ÿºùÿwî:ú6òÿB!ÿ“ÿ§ôÿ>ÿU*Ǥ:bN6ûèU’Q眽B|d2 C×ÿÍŒõçÿvÿ_ Úÿ¯BÉÿåü?>Èÿ….ÿïú_üðûÉÿ …üOþŸÒÿûüW%RÓÂ…Ï"y0ÌYRZÁ„5Ú‡, Häè)ÿwfÔ¨ÿ8ÿ·ûÿ«‡Èÿ(ù¿œÿÇù¿Ðåÿ½ù?CûK…üOþŸÒÿûü× Ùz’ Ú¨hÄ* 6 «ôR2íE ÉMŸÿÏŒõçÿvÿ_ÍÿU(ù¿œÿÇù¿Ðåÿ=ø+$ÿ/ò?ùJÿïó_™5QI`à7Vh4Á+É}4†³È:™Ñ’ÿçEúó»ÿÏæÿ*”ü_Îÿ;>Èÿ.ÿïÁ{ÿóZòÿB!ÿ“ÿ§ôÿ>ÿ5(J¡uܧ¬d‚”™Ê.Šh›G\3Ñù^Ô¨ÿ8ÿ·ûÿJ’ÿ«Pò9ÿïø ÿºü¿7~ঠòÿB!ÿ“ÿ'ôÑç¿:ðN;ˆ V÷ûc"h–L3f&’ð …ev5’ÿçEúó»ÿ/‘ò«Pðÿ±òþ¿Îÿ]þßÃÆóäÿ…Bþ'ÿOéÿò_Š"8€11§Chz~L““Ü[“mÄØøü?/jÔœÿÛýÿæ€ü_ƒ’ÿËûÿj0ÿëöÿÿ÷߃ü¿TÈÿäÿ)ý¿ÏHàM2Á蜬qR&g¥b}Ö&g•QqÊÿ›5ê?Êÿœuùÿ”ÿS…‚ÿñóÿ ÿïX·ÿ¿ëѧ¯$ÿ/ò?ùJÿïóßDÃ4%-f¡ w(ASÛä¹t’Ó¼ÄSþĮ̈Qÿqþ‡nÿü_…’ÿ/1ÿòÿ°›ÿoûâ©»Éÿ …üOþŸÒÿûü7}‹Ñpå3 8ÏÆû¤`NIªœ³öÿgFúó»ÿ’òÿ«Pò9ÿO òÿ°›ÿÿå¶õ%ÿ/ò?ùJÿïóß27&mMÒŒòÎdÍ­e^눘ÑíÿÏŒ*õïÁiþ¯BÉÿåü?5ÈÿÃ.ÿïÞŸý§ÿ ùŸü?¥ÿ÷ùo\t›[Ýô¢`bT‘…`„õLG óÿ3£JýGù¿ÍÿÑtÿŸ:”ü_ÎÿSƒü?ìòÿö~öñCäÿ…Bþ'ÿOéÿ}þ›7ÒyãÓ!å¦z:Ë¢,šV.°ÎAd†ü?/jÔœÿ›ÇEÛÈÿ(ù¿œÿ§ùØåÿ½ðÂBþ_(äòÿ”þßç¿)0<‹Õ¸'×k¯XÎÚ{Á”0µ ÕêÔ0ù^Ô¨ÿ8ÿ·ù?‚öÿëPò9ÿïä`ÿ»ü¿²ûIòÿB!ÿ“ÿ§ôÿ ùoÙ¸”„V^'ïWw‚Ü[®;'xïCÔÂSþß̨Qÿqþoó4]ÿ_‡’ÿËù'ûÿØåÿýÒÞã7“ÿ ùŸü?¡ÿË>ÿ-+l• [k›>žQz ­Ð2 )Ýÿ³w]WŸVL4"R)[‹Zm¥¸÷^kíµwŠÒV|[©PªÔÒf?Á±Z,± bF„JÛ¤ b« $E™4s›ˆöE äŸ"m,BM,AA‹M#Áó;Çs ÷ì!œ9ãî9°¾æug†Å¬Ï]çìõÙ¹¦RÅÿ·³ô¨ÿ:þþPFøß# þŸµ÷ÿõrþŸüŸ|åÍ.ü?h„ÿÂÿ-ý_Ÿûß™-D¥(˜¬Jt>Q %ù`CªÈ™kð@âÿÛYzÔÿaôÿX#üï’ÿÛûÿz1ÿŸMûÿ—þô»„ÿGð_ø¿¥ÿÏþ·‡_N.å¡ý7Ð^!•œ2‰‚5.+o= ÿ÷•õ_ÇÿÑÿƒâÿí“ÿá*óÿÂÿw6íÿÛ‡~þeÂÿƒFø/ü¿ý_S1\\1)満  yÅ9X$v:Ëûÿ¥KýWñÜÿGyÿß'-þ_eþ_ð¦ùÿþü ÿá¿ðKÿŸý¯ ƘP3WC9W-f@E ,Zþï+=꿎ÿ0ùäù—´øßöÿé…ÿ¦ùÿncß/ü?h„ÿÂÿ-ýö¿º¬«'T2¤‚>J-e_W]0“Üÿ³³ô¨ÿ:þãøþ_ÎÿõI‹ÿmÿŸ^øaòÿ½î5Êùÿ£Fø/üßÒÿgÿkñ^Q¦˜*ÃÌŒ13”¢sæ’K4ü!p²ÿ¿³ô¨ÿ:þûÿÈâÿï’ÿÛþ?½ðÿÂäÿû¹Ÿ~ú=ÂÿƒFø/üßÒÿgÿkБIU—ÉPIÑSŒ¢2Æ Ÿ#g‹25áÿ¾Ò£þëøo'þËù¿.iñ¿íÿÓ ÿ/Lþ¿Ï|ñ"ü?h„ÿÂÿ-ýö¿jÖ¬²båÕÐô¹ ѹ€1Zã«J*:yÿ¿³ô¨ÿ:þûÿÅÿ×%-þ·ýzáÿ…Éÿ§/ýÔÛ…ÿð_ø¿¥ÿÏþ×ZSä”LT£í§2jò 5Sf½SÖ¢ÏIîÿÛYzÔÿqÜÿ'ÿ—´øßöÿÝ»ðÿÀäÿû¥ï{Hîÿ;j„ÿÂÿ-ýö¿"‡T!ëì¢Ó*‚eOêÔÎÝiõ²RÞhfÙÿßYzÔÿÇýÿáoþ÷Hƒÿ÷µ÷ÿï]ø`òÿýû»n•ûŽá¿ðCÿ§ÙÿŠÑã0ía¤”rUV!G¶¡jEYW¨*/üßWzÔÿ§ý–óÿ]Òâ{ÿŸóÿ}Óþÿ»ÿþÉÏ ÿá¿ðKÿ?÷¿¦hu-¬ª¤]Œ£ÎX4¡cB¢JVüÿ;Kú¯ãÿ¸ÿVü?]Òà?·çZÌÿ÷Mûÿõ…ñÓÂÿƒFø/üßÒÿgÿ›/AkÍ Ùçh,äS© Œ²!›ÁU›@ø¿¯ô¨ÿ:þãÄþ÷H‹ÿW™ÿþ?žæÿ|ª¾UøÐÿ…ÿ[úÿìËà½Ó• #á0èûì0ø€šœg6ÃpX’çÿ;Kú¯ãÿ¸ÿoHÎÿuI‹ÿmÿ-ü<Íÿ_üîÝ-ü?h„ÿÂÿ-ýö¿e‡æ ÅRªÑŽu±É T!V”"•ýÿ¥Gý×ñÜÿgý¿.iñ¿íÿ£…ÿ'ÿßW¾ö'oþ4Âáÿ–þ?û߬S•3U2¡Ö@›èMTl-T³·5Fà þ¿¥Gý×ñÜÿ·(çÿº¤Åÿ¶ÿþ?žü7ÿÀ/þ™ðÿ þ ÿ·ôÿsÿd­¼7 íÐ,Œæ ð¤‡u‰ÂiÌi°!Eyþ¿³ô¨ÿ*þÓ¸ÿ¯´ø»¤Åÿ¶ÿþ?žü¿ûÄWýðÿ þ ÿ·ôÿÙÿFKˆV“ŽCû%š ˜5–â±QˆÁjÿÏÞÒ£þëø¯åüÇ´øßöÿÑÂÿÇ“ÿï–oþÔ«„ÿð_ø¿¥ÿÏþ·bس¯â€8œžü몪…ãIø¿¯ô¨ÿ:þûÿy„ÿ=ÒâÛÿw¶ØÿçÉÿ÷­oÂ× ÿá¿ðKÿŸýož•óIEVdCÖ.¸è­7tšsaŒž+FÞÿï,=꿎ÿãþ¿ÑrÿO—4øÿ@{ÿÿl±ÿÏ“ÿï/ß÷Ø…ÿð_øíý_«Ùÿ–5fkUt ¼Ë~øl­QɦBc 末ð_éQÿuüÇiÿOÞÿwI‹ÿÍýT‹ùÿiÿÿŠûäÃÂÿƒFø/üßÒÿgÿ—äûÊ^ëjÀ9J˜“ö:€Òk ˆ^æÿ¥Gý×ñÚÿgyÿß%Kþ_VÍùÕbþ`Úÿw÷îþ4Âáÿ–þ?û_ z“Àcp ƒ5*hΠ )Ÿ³qI³Î\„ÿ;Kú¯ã¿æ¹ÿ§KZü¿ÊüÑÿs¦¦ùß¼è%ü?h„ÿÂÿ-ýÿÜÿBÊ8ãKº©@TqÉ+øä¢9:ñÿï,=꿎ÿãþ? œÿë’ÿ›þ?Tý?gjšÿçì—ß ü?h„ÿÂÿ-ýö¿bâ’²©1C_Ec†Ä¡wx­SrV9ÿ¿»ô¨ÿ*þÛqÿŸÄÿÛ'-þ7ý¨.úÎÔäÿ{ñw½\øÐÿ…ÿ[úÿìq©Öâ)D—”NºÄù%1cçP\2¼øv–õ_Çÿqÿ­œÿë’ÿ›þ?Tý?gjòÿ=ïÕ¡ðÿ þ ÿ·ôÿÙÿ’“#7´õä]!U Ø’¼r6(°ÑzÎ9„’‚¼ÿßYzÔÿ§ý?–ûÿº¤Åÿ¦ÿÕEÿÏ™šü÷¼üÉG…ÿð_ø¿¥ÿÏþ—d|)ª²‰Õ#Dï•®¦T5¥Îk“r6ÄÂÿ}¥Gý×ñÜÿ#ñÿõI‹ÿMÿ^¾¸ÿw¦&ÿß=½àáÿA#üþoéÿ³ÿÅVM#šFpÚû §ãß§ p7Lsz€‚œÿÛ[zÔÿi:ÿ'çÿ»¤Åÿ¦ÿ/_Üÿ;S“ÿïÆ÷ÿÍ7ÿá¿ðCÿ×çû߈ÁW5ºèѳ®Îª¬ lL€ÄÖƒð_éQÿuü÷ÿ@Éóÿ.iðÿr{ÿ—üŸü_ûÞûž/ü?h„ÿÂÿ-ýßÌç¿}4UëJ*S2´Œ”Qg Þ˜hÃ0†$üßWzÔÿ§ý?°Âÿiñ¿½ÿ¿}‘ÿ—§ýÿ8ûÀ#ÂÿƒFø/üßÒÿgÿ >‰_<¥zº÷­ Hì­ª‘âéú]œøÿö–õ_Å÷ÿ4Èóÿ.ið¯2ÿ/ü?—§ýÿWÄç>-ü?h„ÿÂÿ-ýö¿‡¢-dƒµ5¶øêœåH•3"¹ÿwgéQÿuüïÿ-û]ÒâÿUæÿ…ÿ§ùÿùté{…ÿð_ø¿¥ÿÏþ¦BÞ©¹æˆi¡b=Ý —s©µ(+ûÿ;Kú¯ãÿ¸ÿ ÷ÿuI‹ÿmÿ.ü?8Íÿ_zä3 ÿá¿ðÿzô3´z ÃÀÖG°P2fK:r œUöÊ ó`ÈÂÿ}¥Gý×ñÜÿ· ó—´øßöÿ5ø?ùÿÞò[/ýzáÿA#üþoéÿ³ÿ-3}Âg—€b¬®@ ±ªTc`C5`–ý¿¥Gý×ñÜÿ·h„ÿ=ÒâÛÿ‡ ÿNþ¿W¾¿FøÐÿ…ÿ[úÿì«Î@TÁc!Z)p:hvY[ðƒu!'eµþï+=꿎ÿãþ¿f9ÿß%-þ·ý¸ðÿáäÿ{JýÊç„ÿð_ø¿¥ÿÏþ7Ç!gå4G›Á3q*ì†_LV†BH9øZeÿogéRÿUü÷ÿQËüß%-þ·ýWþ?œüOÝõ7 ÿá¿ðKÿŸýo)j`gr, @ \3»b<"Ÿ‘tD-û;Kú¯ã?Oçÿdÿ¯KZüoûÿ®,ü?8ùÿ^û|§ðÿ þ ÿ7ô£Îï±~hû)iL¡P>¥‘†QÐYð>FFT¾ ÿ÷•õ¿þkñÿuIƒÿWÚûÿf9ÿOþ¿—<üë7 ÿá¿ðKÿ?÷¿êaÖ«®ªd T£©D§‹²‹Í‘uV™­ìÿï,=꿆ÿ Fÿ*yÿß%-þ·÷ÿÍbþ¿2íÿÿÇwÜ*ü?j„ÿÂÿ-ýö¿FGÀ‰‹WÚ[±»½fÿRM¬Á¬¡Èùÿ¥GýŸÿø þOþ%÷ÿuÉ’ÿ ÕU,ÀWÿÄ wßpéž;ÿë97yÿ’kŒð_ø¿¥ÿÏþ×h)›jjhhá$„Iư*Uð€ÕrTòügéQÿgç?=ƒÿ“ÿGÉþ—4ù•À4|¥ð‰^z㥇þøÁ»^ñåýwH®-Âáÿ–þ?û_‡ù¾Ôè“R)%¬§Ó_Ž,WòЪ„…‡%çÿw–õ_Ǹtz çÿû¤Éÿ¶Ð\ü|äÿþ÷ƒþ2Âáÿõèÿ1F œl¿”´r†T­l«!g´)ÙÿÛ[zÔÿGÿ²ð¿Kšüo [üÿ—‘ÿ?ñŸÏ{¡ðÿþ ÿ·ôÿÙÿZK4ž!9ÙJžmvê«l«œ|T,üßWzÔÿGÿµrþ¿Kšüo ÍEðÀÿùÿã_ýÚ›„ÿ‡Œð_ø¿¥ÿÏþWÅ¡bô‰r‰t’Àª’ìiŒ“F¥ø8t‘$ïÿw–õvþ?óüÿäÿa%üï‘&ÿ[ÀçüÞ½7}ã‡õozÛ—~æÉ'ozÇ|Ç /yã§¿å‰K?ûןýˆÐÿ þ ÿ·ôÿsÿëÐü±>]ù˜Ù‡¨’c ˜ÌÀ†“ÎZñÿî,=ê¿nþ÷ÿäù—4ùßš‹àaþbœÿŸ~Í÷Ü._2Âáÿ–þ?û_aÊ”-ëT£/ª@Ä ¢õà X£Bˆ5VÊ üßWzÔÿøOÂÿ>iò¿-üèEÐÀÿÏŽüÿÈ‹nû ðÿþ ÿ·ôîAήS„à•·ÉX°ª8o‹¦-)ïMFáÿ¾Ò£þ«ø¯Gÿyþß%-þ_nïÿô¢hàÿçFþè¹_ñOÂÿCFø/üßÐÿaö¿Ö¨!`…EEµƒ€Ã§¢=] W+„Z# ÿw–õ_Ç=ùÿÅÿÓ%Mþ·÷ÿírþ¿<íÿ¿õ.ß"ü?d„ÿÂÿëÑÿ} ­§ª²É!Y3 ‚VyÐ )éL£crAø¿¯ô¨ÿ:þOþ-÷ÿtI‹ÿØžÿ[üŸöÿ¿ÿ×~ø/„ÿ‡Œð_ø¿¥ÿÏþ÷ÀQ›è +G˜©ÐDè|©5aãt €„ÿûJú¯ã?Œïÿ ÿ{¤Éÿ«ÌÿËçÿ8ÍÿüÆ·¿WøÈÿ…ÿ[úÿì'È¥ÈɤRbÐ1+¯ŒÑ!o’³9AŽÑÿw–õ_Çœöÿ…ÿ]ÒäÛÿg/úÿþOó¿}õ½rþï˜þ ÿ·ôÿÙÿ>ÔÐ MžªÂ0§P9dçÁ[®9SÈZùœ…ÿûJú¯ãÿèÿñÿôI“ÿmÿŸ]úÿqòÿÝúÏ7>&ü?d„ÿÂÿ-ýÿÜÿ>`Þ`!£tÉ`%ªªÚ Žc­|aS„ÿ;Kú¯ãÿèÿ€#üï‘&ÿÛþ?»ôÿâäÿûøßÞù°ðÿþ ÿ·ôÿÙÿ Y¥¡Ó—<4|ÒÅf6¦ú¢üð&ÈAL@Nø¿¯ô¨ÿ5ð<ÿï’&ÿ[þ¿ÿKÿ/>6òÿöW…· ÿá¿ðKÿŸý¯ÁXG)Ç¢sL†bM*›ü`jîTÐ’2UÙÿÛYzÔÿGÿ³ìÿuI“ÿmÿŸ½}ÉÿÉÿ÷–ßü ÿá¿ðÿzôÿ¢Ã0í _£ö.qNžJÐCûOV%]BÔÚ$å…ÿûJ—ú¯á¿Q“ÿ_æÿ.iò¿íÿkñòÿýÕ;ßôoÂÿCFø/üßÒÿÏýï’ƒJT<ëTOÃ÷1¡Ñ¿Ó¨ åþŸ¥Gý×ñòÿìÿwI‹ÿW®²ÿ¿ôÿãäÿ»ÿ÷_üáÿ!#üþoéÿ³ÿ=Û ä¬s*Û¨’Òž8ã¢á¬¼8KÒÂÿ}¥Gý×ñôÿ Âÿiò¿½ÿÿÒÿseÚÿ¿ãC¿MøÈÿ…ÿ[úÿìc`g9•œ²i¢”j!Ï) ;%çÿv–õ_ǘžÿ ÿ»¤ÅÓžÿï_ú®LûÿOåûîþ2Âáÿ†þçþWÂ4ÞܪèRYéZ]06%›-ÙÌÅ+Ïÿw–õ¿þ´Âÿiò¿=ÿëåüo¦ù¿pÃÛ„ÿ‡Œð_ø¿¥ÿÏþ×ì …CÝ|Ê&±ÍÆPI%¯³¨=ØÀ\„ÿûJú¯ãÿèÿÿÿ ÿÿÿÓäÛÿ§—ó¿™æÿ?ºíÑ7ÿá¿ðKÿŸý¯†fïVä†@Aˆ6&tÙ:g‚¢ð_éQÿuüŸü çÿ»¤Éÿ¶ÿO/ý¿fòÿÝñ¾oû:áÿ!#üþoéÿ³ÿµÅ’­–ŒgTqø&e òð ¶…’«²ÿ·³ô¨ÿ:þÿŸÿGÎÿwI“ÿmÿŸ^úÍäÿ{×/”oþ2ÂáÿõèÿÌJUÅ‘Áãÿ²wn±Ÿ]UŸvRÄ JÆéÔØB'ÓìÛZ{o1FŒ(ÔH ÁPñiíÁúЋbð’:©V(å*è•pÞEŸKr‘LŒÁ 2X*!ù¿­ô¨ÿ óß<Ç=úŒ`þ÷H“ÿÿßÿwäÚc§?|ìôÿüæôà3ùÄ.<üôùÇî¾püø‡î~ç}=r× §ÞÆøßg˜ÿÌÿ5ýò¿(F %+T²Úê¨T¨ó ÑÂ9_Œ´Á'ËüßVºÔÿåøþŸŸÿwI“ÿmÿŸ|¾ÿÿš[ïøÿš'ìw1ÿ÷æ?óMÿ¿äÕ¦(U¤NZ(„ƒë~$O1&ŠÞ&åœÎ%Dæÿ¶Ò£þ‹žÿëÁÿcïÿë’ÿÏ´÷ÿåÜÿ«Fÿßm_¼ú^þ°Ë0ÿ™ÿkúÿäÍ9’¢Úå‹ðý¿w^y—s²%¢©5Ö-ócéQÿeüöÿÏÿ÷I“ÿ‡ìÿÏý¿gÆýÿxÓ+¾Îüße˜ÿÌÿ5ýÿ’ÿÕE-ÀcÉÙF€D^’V9©PJT§PçCÅüßVzÔÿ‡ý«yÿ¿KZüÇöüÿèÜÿsfÜÿÿû/}Ëï3ÿwæ?óMÿŸü¯VC)R–âSÑ/ƒ5¦’eð*%E.9оDÌÿm¥Gý—ñØÿ·ìÿë“&ÿÛóÿ£sÿŽóÿ½ôŽSÌÿ]†ùÏü_Ñÿaò¿º1xÔèm ІÀ…\jç@!BŽÆ™dýÍüßVzÔÿ2ø¯ùþ¿>iò¿íÿƒùüãüË™—fþï2Ìæÿšþ?ù_ã•I¤Ðjuè—ÊK`SFI¦`6¨1ÿ·•õ_Æÿ‹þÃüï‘&ÿÛþ?hÌÿ£ÿï]/û½Ï0ÿwæ?óMÿŸü¯ÎERÊT€ÊÚ D§D$’Úy(6”„1jÃ÷ÿn,=꿌ÿƒÿ§þïÌÿiò¿íÿƒ¹ÿGÿß‹úø?1ÿwæ?óÿJôÿär”“XœöP I ¼%©ië#ñý?Kú/â¿ý?’ïÿí’&ÿÛþ¿ÿGÿßgN½ñ=Ìÿ]†ùÏü_Óÿ'ÿkäB6j˰6 2Y“–&#RT6Õ:(öÿo-=꿌ÿƒÿÇæ—4ùÿù6ÿçþ_|zàÿ›^ü[aþï2Ìæÿšþ?ù_Ác%º]ðF¦ƒÓƒ'+@g#òþÿÆÒ£þËø?ø´åçÿ]ÒäÛÿïóÿóÿþ…oü#ó—aþ3ÿ×ôÿÉÿêÉf°)%o„OºøÆQPp¶Aaþo+=꿌ÿƒÿÇßÿÓ%-þŸkïÿÃóý¿•ÿ£ÿï~æW?Êüße˜ÿÌÿ5ýÿ’ÿ5QÙ|@Â䘄,’ 1P±ZY T4û6–õ¿ þ#ßÿÓ'Mþ·÷ÿaîÿ=7îÿÿç…Ï:æÿ.Ãügþ¯éÿ“ÿÕ‡½%kŸŒöƒ±`1«’D°¾¨*$Éçÿ7–õ_Æ3ÞÿÇþŸ.iñ_2ÿÏý¿çÆýÿ·?ûßìÿÛg˜ÿÌÿ5ýò¿’uâ“.Åb´tN5>ÉKª(6Ùl}àóÿ[Kú/ãÿàÿÅ÷ÿtI“ÿíùÿìÜÿ#Çùÿöÿºæ$ó—aþ3ÿ¯Hÿ·ÊØBe„¦P ]ts•QZJ:{~þ¿±ô¨ÿ2þþÔ|þ¿KšüoûÿZüçÿŸ~ò/Ÿeþï2Ìæÿšþ?ùß“2JaÒ ­“E ¤Œ0Š˜]ˆõo¬v˜˜ÿÛJú/ãÿEÿ?ÿï’&ÿÛþ¿³sÿŸýGã|þoŸaþ3ÿ/¿ÿ×/§ó_"Š\<˜b’‰Ù€T é¤1XMRP(`þo+=êÿÂü×ÏñÏÿÓäËÿw•Š×©[¿r溯~õÓ_þÊu/yâç^úïâñ×ýÍU÷ýÙ·=Ãôßi˜ÿÌÿ5ýò¿{[j×vÒ;²ßð:æÀ˜úƒÆk“´$ÍþŸ¥GýÍÿ0ø´`ÿ—4ùßôÿ)јÿGÿß_½þËoáO» óŸù¿¦ÿOþW >fm½@•(ÆÚäPæâbð™ŒWˆ<ÿo,=꿌ÿý?¼ÿ×%Mþ7ýJÌý¿rôÿéß(ï`þï2Ìæÿšþ?ù_ɸ„õ©,PA@B™,0È‚s9A3ÿ·•õ¿ þòóÿ.iò¿éÿSbîÿ•£ÿïŽïû‡›˜ÿ» óŸù¿¦ÿ_ò¿F_l2@É %¸à#Ë14ŠŒÉÇüßVzÔÿGÿŸfÿo—´øÿhsÿ_‰¹ÿWŽþ¿O?}Wfþï2Ìæÿšþ?ù_e–7D1¹ìG9k«éàۉÒÚ¤-ó[éQÿeü7ãþ?ó¿Kšüoîÿ+1÷ÿ>:îÿãä;þù¿Ë0ÿ™ÿW¢ÿg+<È |ý»— Œ ‹Îõ‹èlýaá æÿ¶Ò¥þ‹ø?ø ûú¤Å8dþoðÜÿÿëýÎ2ÿwæ?óMÿŸüïIJãl¨S~°¥Ž}!KQ@ %"&@ .jGÌÿm¥Gý—ñðÿXÉçÿ»¤ÉÿCæÿ¹ÿÆùÿ–ãx”ù¿Ë0ÿ™ÿkúÿä„6&S¤ Ή‚AÀkïWFfG—Ò|ÿïÆÒ£þËø?øøü_—4ùßôÿ)1÷ÿÃ8ÿòå{™ÿ» óŸù¿¦ÿOþ×PHT˜’FHY'‘%I‡Eze ä\¿¥Øÿ»±ô¨ÿ"þ£Ÿÿóüß%Mþ7ýꑹÿFÿߟ¼é[™ÿ» óŸù¿¦ÿOþW›‹ÇŒÊ+PÆ&8ˆ&Ö9ЇD2Xç¬EÞÿÛXzÔÿrø|þ¯Kšüoùÿ*ÿçþxfàÿ—^[^Åüße˜ÿÌÿý_NþWa½'RK“e†úïP”7ÚGaa–©(U˜ÿÛJú/ãÿàÿ˜ÿ=ÒäÛÿgóÿèÿûÑ÷}ÿo2ÿwæ?óMÿŸü¯.# Ê1ê˜Dè $JBk*>Hm„’ù¿­ô¨ÿ2þ«ÑÿÏþ¿.iò¿íÿ3ùôÿ}êê?Ãüße˜ÿÌÿ+ÓÿM¬ÎT’ÇFFmCýS"æhs€P¿àýÿ¥Gý—ñ_þ?~ÿß%Mþ·ý-þþ¿W½è¶ë˜ÿ» óŸù¿¦ÿOþ÷¤#¦œÉ¨,Îi,˜ÈF%(è |Š&jÅþÿ­¥Gý—ñðÿX¾ÿ·OZü?ÛÞÿ7sÿ?Œþ¿_zó/þ ó—aþ3ÿ×ôÿÉÿîh ^: µï£J^ˆ”jC§(‰&ƒT™ù¿­ô¨ÿ2þþÞÿï“&ÿÛûÿfîÿ?;îÿ¿íƒ?û¿Ìÿ]†ùÏü_Óÿ'ÿ;• (U´Q¸âQ#•¬]•ËÑzå=$>ÿ¿±ô¨ÿ2þ_ôÿðù¿.iñ_2ÿÏýÿgÇýÿî{òæÿ.Ãügþ¯éÿ“ÿÕ(¤AŠ£$B6Úù(È¥,¬“|Œ¢0ÿ7–.õ_ÎÍüï‘&ÿ™ÿçþ_=Îÿ÷¾û=?Âüße˜ÿÌÿ5ýò¿’’RÙP›E(™D †Ë_ ZU²£B‚·ÈüßVzÔÿí¸ÿÏïÿ»¤Éÿ¶ÿÏÌý¿zœÿí^yó—aþ3ÿ×ôÿÉÿ*“Þš3Ô–oóÎA(]1YQ,YÞÿÛXzÔÿ­ïÿãûº¤Éÿ¶ÿÏÌý¿zôÿ}öúJæÿ.Ãügþ_‰þŸM‰Z—Úõ)‘–.V H›’–´–bV‚ïÿÙXzÔÿåøüŸ÷ÿ»¤Éÿ¶ÿ¯ÅÿÑÿ÷Ö×íO™ÿ» óŸù¿¦ÿ_ò¿{•ÈK…ÂŒÚ9ŸÁ“)>œÁïÿ7–õ_ÆÿÁÿc4Ïÿ]ÒäÛÿ÷øÜÿ§GÿßËõ×_Éüße˜ÿÌÿ5ýò¿ãÁÛ_#щ@³S!¡ÔÙÊ>éìÑ:a™ÿKú/ã¿ïÿáûÿº¤Éÿ¶ÿïñ¹ÿGþ¿û?yã0ÿwæ?óEÿW“ÿÝˤ¢Ôh¼@-µ$e0Ä “*Ñ/ 0ÿ·•õ_ÆÿÁÿ£øþß>iò¿íÿSùôÿ=tìäiæÿ.Ãügþ¯éÿ“ÿ5'é5f“<†ì0Õ†` È œ5>J™ùüÿÆÒ£þËø?ø´àý¿.iñÿ±öþ¿jÌÿ£ÿï#×¼å<ó—aþ3ÿ×ôÿÉÿªKЂYkmÖ4&“(ÙP3gØÿ»µô¨ÿeð,ßÿÛ%Mþ·÷ÿÕÜÿûظÿÿ÷ûÏ3ÿwæ?óMÿŸü¯ÉBŠZMÎ*Ì“ˆ$b”%xÂi!hÍÏÿ7–õ_Æÿ‹þ?Þÿï’ÿí!óÿÜÿûظÿëCϾ‰ù¿Ë0ÿ™ÿkúÿsþרJ@ï}´(|V$É,cD,Úh)ñý[Kú/ãÿàÿAàù¿Kšü?dþŸûí8ÿßsêöŸbþï2Ìæÿšþ?ù_ \ÆR;xÑ–H؃à2ÛlЦ¼6‰ù¿­ô¨ÿþ1øаÿ¿KšüoûÿÔÜÿkÇùÿü‹ï7ó—aþ3ÿ¯DÿW“¤ ­1 Q{/ƒ ^iD–ÙÈ"ó[éQÿeüü?š÷ÿû¤Éÿ¶ÿ¯ÅÿÑÿ÷ê—œüæÿ.Ãügþ¯éÿ“ÿ=9#i];}1!ûR¨u œŠX´’!—üücéQÿæ¿ù&þþŸúŸ3ÿ{¤Éÿ™ÿïè×_ÿ¡¿¸9=øL>ñ… ?}þı»/?}Ã=ï¼ïÁ£Gnÿã?Çøßg˜ÿÌÿ5ýò¿†ÎameöNXð6UŒ±NÿXe£.Ìÿm¥Gý—ñðÿhäý¿.iò¿íÿSÏ÷ÿ^óÀÝÿ¿óµŸ»ƒù¿Ï0ÿ™ÿkúÿ䵊RxpœbÂÉHކ“ÿ¤œG2$ƒcþo+=êÿÂüÿæçÿƒÿÇXöÿtI“ÿmÿß™¹ÿÇŽþ¿~økßÍvæ?óMÿŸü¯ÊCÅyÕ÷0ÿwæ?óMÿŸüïQ@¦k-AòÍŸlˆIH J¢ö4HÍ÷ÿl,=꿈ÿrðÿXæŸ4ùÈü?óÿ×O ÿßøÞ_Ëüße˜ÿÌÿ5ýò¿XŠÉ$Àƒ£~Æb²r x Ó¦þPˆÚßÿ³±t©ÿ"þËÑÿÏÏÿ»¤Éÿ¶ÿgþÿúIaàÿ?¹çfæÿ.Ãügþ¯éÿ“ÿÝ)¤ W<‘Œ× ­·6D0Y)§]ˆä™ÿÛJú/ãÿàÿQ–÷ÿ»¤Éÿ¶ÿgþÿúIa࿹÷†Ÿdþï2Ìæÿšþ?ù_KÔ)ò€ÁÆÚîe¦B!:'Ô>’Šdþo+=꿌ÿúˆÐ•9|ÿO—4ù?óÿüŸùë'…ÿ'~ýí¯cþï2Ìæÿšþ?ù_‹U±v} *%i¥…R$Q‡ÙS¥L†ù¿­ô¨ÿbþ×ù_1ÿ»¤Éÿ¶ÿß7çÿ¿üÿŽ7\xŠù¿Ë0ÿ™ÿkúÿä­t—)äH #…¬¡€ÑT¤VÆŠ"2<–ßÿo,]꿈ÿƒÿÇ ~ÿß%Mþ·ýø|ÿoåÿèÿûð“öO˜ÿ» óŸù¿¦ÿ_ò¿&ï‹ôÙYH>ælú• Ÿt²>©ðùÿ¥Gý—ñðÿûú¤Éÿ¶ÿïÜÌÿS?) üÿ»¼ëYæÿ.Ãügþ_‰þŸÊÁ¿˜4 ’ÞCPÊå½-ΨäŠJ= öÿn,=꿌ÿƒÿ,Ïÿ]Òâÿ#íýÿÿGÿß›_ýŠ;™ÿ» óŸù¿¦ÿOþw£°PV(%k–DôAè:‚Êu(ÌÆÚl™ÿKú/ãÿàÿÑŠýÿ]Òä{ÿÿÜÌÿS?) üÿå§®þæÿ.Ãügþ¯èÿæ’ÿJŠÙ“OÁAˆ AªßìQe³Š øùÿÆÒ£þ‹ø¯ÄpþŸïÿë“ÿM{þ—óùÿ‘qÿÿüÇŽÿ8ó—aþ3ÿ×ôÿÉÿŠ"a¶Ù Õïäd“r–È()¢$Ð'ÿìmÈnYYǧ,,:AΤ½àdo¤M³Öu­k½|PÑ^„r*Ét$ƒÖ˵Ò,†˜(?AŒö¡© B£ÀÈhæpfÊJÙ:*9ÕfÓTÔTꇘ [÷½Û§h¯ÙgŸ{Ãõ‡a˜ó<œ/óÿÝ×¾÷ú­¢äüÿÎ2bþëøöÿÜÿ7&]þ÷÷½ÜÿÍ´ÿ¿áeweáÿ!#üþoéÿÙÿÚ¿Ô O9YO`Rö„Åe Úh¬Ùèä¼SYöÿeÄü¯ÿ(þß1éò¿ïÿÓKÿ¯™öÿûîý›Wÿá¿ðKÿÏþWŽÔv6°¤¶ –ÚÕb ÐÅdUÑx2ÂÂÿ}eÄü×ñdÿ˜.ÿûþ?½ôÿšÉÿ÷°~ùÍÂÿCFø/üßÒÿ³ÿŠ÷Á`Â'ĬBÔÙ©èM#ŽÜvCñÿí-#濎ÿgÿ9ÿ7$]þ÷ýzéÿ5“ÿ/Ýü§Ïþ2ÂáÿõèWA£ñ¤y•Úâ§cÊ–MbÆbTÒläþßeÄü×ñßLÏÿåüßtùß÷ÿõø?ùÿþÀÞözáÿ!#üþoéÿÙÿ^Ráལèc1:†¨¢m?°Ù&¶¥P‰¨ÀËù¿eÄü×ñÿìÿ±$Ïÿ‡¤Ëÿ¾ÿO/ýÿfòÿ=÷ÿí»…ÿ‡Œð_ø¿¥ÿgÿ»ÍŪX T*Idƒ™B _É¡CŸ¢M1dáÿÎ2bþëøöÿX%ïÿ I—ÿ}ÿŸ^úÿÍäÿûêWÜø•ÂÿCFø/üßÒÿWýZÛÆjÃéUµ g¯+Ö4yªÈ÷ÿ;ˈù¯ãÿÙÿc¬ðHzü¿rÁùÿ¥ÿßLþ¿g|׫ðÿþ ÿ·ôÿìõ¶¿W!fÈÖgŠÅµmF Õþ]Ð$«åý¿½eÈü×ó ÿG¤Ëÿþùÿ–þŸ+ÓùzÓ½÷ÿá¿ðKÿ‡«ç¿|ÈØWIQ®©(jËŸM!d§Ø]…ÿûʈùnþãÿðÕùþ?yÿL:üuuÿÿüË·^ºô¶‡/}àö·¾ô›óMðŸº|Ó§?ýáO~ê¦Kï¹óÆ[o}Ï•½ÿó|ºýÃBÿƒFø/üßÐÿ4û_ÛrÏm±ˆ1¦„U—ªÓœ½*œl°Õ©,üßWFÌÿsóßü/þŸý?Nöÿ1éò¿¿ÿÓÿÝÿ¿ðýo|í[î{Ú Ïÿ¹z®|8f„ÿÂÿëÑÿ¦’ŠgvN;ï•õhÈ[„”³i¿Åÿ·³Œ˜ÿªçÿxöÿ(+ü’.ÿûþ¿ÿ©}R8?ÿÁ;oûgùpÈÿ…ÿ[úÿªÿ=8cbÖ0cvh!†€PÛò}†ÄŠXNÂÿ}eÄü×ñÿìÿyÿLºüïûÿháÿoŸÎü¯Oû¥ßþ2Âáÿ–þŸýïŠ&EÖG_ œ®‚¡U˜bV!·Æ·†„ÿûʈù¯ã¿™ü¿²ÿI—ÿ}ÿ-üÿí“™ÿ7_þùw ÿá¿ðKÿÏþw$.£v9·æ¯ìBÔ *2 Þ§X,Wñÿí,#濎ÿgÿÏé5@áÿ€tùß÷ÿÑÂÿß>)œùÿƒæuÏþ2Âáÿ–þŸý¯º`®jÑ–sVåt Üæ*‘®ÚÚ€2hþï+#æ üw(þ¿!éò¿ïÿ£…ÿ·}R8óÿ'~èuOþ2Âáÿ–þŸý¯ÎT§*x4r²ŽªW.•&²5)*œÛoÿ÷•ó_Çÿ³ÿÏñÿI—ÿ}ÿ-ü¿í“™ÿ·¼ï±—ÿá¿ðKÿÏþךD Š]®Žt0º8Ï•ó•M!B Âÿ}eÈüWñòÿ¡œÿ’ÿïïûÿháÿmŸÎüÿŽûþþ6áÿ!#üþ_þ\`Q[ªJÎ#µ–­ÙK*:µ½¢F9ÿ¿³Œ˜ÿ*þ›³ÿGÉý?cÒåÿçÿ—ü¿òÿýçSŸøáÿ!#üþoéwõþ—ÜŸMI¹ D†«ƒŠmÃrLÑ’“çÿ;ˈù¯ãÿäÿyÿoHzü7ìÿ ÿû¤pæÿ«{úÂÿCFø/üßÒÿ³ÿ]GÄl²j«_v‚«9Š…©2¹bj4*’çÿ;ˈù¯ãÿÙÿÓþjáÿˆtùßßÿ\úÌ´ÿ?úÁ_¶ÂÿCFø/üßÒÿ³ÿ½1¾*EçÔ~œ1„”Û꟱:OxrÁ ÿ÷•ó_Çœîÿ“çÿCÒåßÿ÷àÒÿc¦ýÿöW½øfáÿ!#üþ_{ÿ£šý¯Ž´v*aCÄÁY dKÖ²†`T8½¦X ÿ÷•ó_Ç3}ÿ¯…ÿ#Òå×ÿgUgÿŸü÷ÿÀoÜ(ü?d„ÿÂÿ-ý¯¯žÿò!xÛ@š£móóÉÙÒÀ¨bMÌ`Ð;þï+#æ üoŸ„ÿ#Òå×ÿgUgÿŸü¿óο}–ðÿþ ÿ·ôÿìÕÕ¢õ&ÖÊÆä¬õ©åUµ1¹”|.Á•(üßWFÌÿÏþ°òýÿtùßõÿYµôÿšÉÿwϾò÷„ÿ‡Œð_ø¿¥ÿgÿkREíÛ’Ÿ(dÐ[²‚†´VYHJû¡ð_1ÿuü?ûÀÈ÷ÿCÒå×ÿgÕÒÿk&ÿß³ÿÙ_þ2ÂáÿõèÿÀ%US«†’|aŸmSØ™D˜4CPÁP`yÿog1ÿuüw7(Tm]Âê•‹x¥b66¡ -p‰ˆIü?;ˈù¯ãÿÙÿ£Üÿ3$=þ?Ð?ÿo;ûÿäÿ»ôœ?û>áÿ!#üþoéÿÙÿŠˆÞqÑ™*ª@CQºTí1š³ÖÊûÿ;ˈù_ÿ¡ýXø? ]þ÷ÏÿÛåþÿÀtþÿ–üØG„ÿ‡Œð_ø¿¥ÿgÿ+Æœ!(S•cÓÖ}"H:–œMˆ d‹ªb‰Âÿ}eÄü×ñ§÷ÿÄÿ7$=þÓûÿÒÿûÀtþÿÉŸ¹ë)áÿ!#üþoéÿÙÿê’S•!¸Z5 $¶&g«¢=§BÁyäüßÎ2bþëøöÿœ^þH—ÿìÿKÿ/MûýɯxDøÈÿ…ÿ×£ÿwPLÒ^T“8²-º(•œFdt@•N üßWFÌÿÏþ£äùÿtùß÷ÿõø?íÿüòGåý¿cFø/üßÒÿ³ÿiýs*R :‚N.¹P#UÓÊ>Ød¹ ÿ÷•ó_Çÿ³ÿ‡œø‡¤Ëÿ¾ÿÏ.ýÿ4ùÿÞú¼~DøÈÿ…ÿ[úŸ®îlƒ?™ß¨_еNþ@PÕÔʦ­ÿÞGáÿÎ2bþëøöÿ ˆÿoHºüïûÿìÒÿO“ÿïÞýëO ÿá¿ðKÿÏþwc8ÚXª.ꧤ­ÊÁ· ѬMÄÿ³³Œ˜ÿ*þë³ÿÇXáÿtùß÷ÿÙ¥ÿŸ&ÿßï~Õ·þµðÿþ ÿ·ôÿìEãkô.'w:åÄ\ª·m?ä µÍ ík Âÿ}eÄü¯ÿòüHºüïûÿìÒÿK“ÿïkßþ+Ÿþ2Âáÿ–þŸý¯Õe—±è¶ä“W $o²¶HÈ4p-€Åÿ·³Œ˜ÿ:þëéþ?þH—ÿ}ÿßCKÿMþ¿»þø¯>*ü?d„ÿÂÿ-ý?û_“R9±³€±2µèRP¹¨ê\L¬¡ÅÅ"üßWFÌÿAÎÿLÿöÏÿ?´ôÿÐäÿ{ó_ü{çú]VÖñ!«‹ì€¢YÌ)#ÉZÏzžg­ÕÉ ‰¨¼¨@AŠÆu4½h¢Èõ¤†ˆã±1rPƒ9¼ÓŠM3"• ¤`†A‘¥Q4)Lë·wû%f¯Ùï~Yì Ïæðþç¯7|?ûÙ{¯Ï~ÿ‡„ÿ§Œð_ø3úßV†¡еµx¦š=Æè//…•’¼ö.:yÿï`1ÿmüŸý?(þß!éò¿þ¿ÃÿGæóÿ¿ú¡¿þŸ2ÂáÿŽþÇÅÿ^Ø¢oE‘/`LŠÁר5m­WÑq1•ðÿX1ÿmüÇùþ¿œÿ’ÿMÿ×ëûÿÌçÿßvë‹îþŸ2Âáÿžþ_üï.•s1!¡µ)±O•}ks—Hëªj´þ+#æÿùÿÿ4Ÿÿ—÷ÿ‡¤Ëÿgìÿßü¦wßûü{Ÿÿ‰;òÛ¿X^òå'?ø¯_zÉóõÉï~Ï­¿òº+oÖ-¯ýÂ/JðÎÿ…ÿ{úñ¿+JNÅ”\ŠmÕªÆËÁ¿”´u\ ¬.N8yÿÿ`1ÿmüŸü? ²ÿI—ÿ}ÿŸ~¦ÿÿ[Þt÷ÄÿûnûŸ¯ ÿÏá¿ðOÿ/þW¸l¢§€ ÚJè²SQYþ+#æÿùOÏä?‚øÿ‡¤Ëÿ¾ÿO¯ý¿föÿ}üÊ+>"§Œð_ø¿§ÿÿk¬ÊpðPLµ)&ÅÄÉ¢¶Å|iëP¬uþ+#æ¿ÿ“ÿïò€ð@ºüïûÿôÚÿkfÿßëïÿÌ[…ÿ§Œð_ø¿§ÿÿ«Ptl3å ì³ÆXzòEqѶÂÿceÄü7ñ&ÿ!yþ?$]þ÷ýzíÿ5³ÿï¶Ûïø~áÿ)#üþߌþÏ9yjFB]k Ñ׆¥K(Ö[¢Órÿÿ`1ÿmü×·(sù™ðDºüïûÿzüŸý·Ç“_þŸ2ÂáÿžþçkßOΚâÙ·&7µh€\N±­ÿÑdW}u>ÿ•!óßÄÿÉÿc˜„ÿ#Òåßÿ§×þ3ûÿžû/Ïý3áÿ)#üþïéÿÅÿn‹Jƒ Ù¸ìµO.[ƒ,ü?VFÌÿqòÿ\nÿ¤Ëÿ®ÿO«Îþ?ûÿþü§ÿôµÂÿSFø/üßÓÿ‹ÿÕPaˆY±*‘TÎ*cŒ66J›škmU"ü?V†ÌÿFø/ïÿ I—ÿ]ÿŸVýöÿ}ðÁ¯Ü-ü?e„ÿÂÿ=ý¿ø_K© R¡œ˜œW1Ö‹Þò 3Í kN&ÿ•ó߯ÿÉÿGVöÿ!éò¿ëÿÓjåÿmW ÿ¯üÖŸþŸ2Âáÿžþ_ü¯©T*%ëYû¬&ü?e„ÿÂÿ=ý¿ø_=ÄêÛÜ*UK ½ÍIG§Ëåû¿\K޾T¹ÿ°Œ˜ÿ ðŸ•ðHºü¿Îþ¿òÿ¶+…‰ÿßöKw¾SøÊÿ…ÿ{úß]ûþ+Vô”ªkUÈ^1Eª¡ËÁp› _•VÂÿceÄü·ñßÎþ_áÿtùßõÿéÖþœ÷ÿ{žókÿ ü?e„ÿÂÿ=ý¿ø_m*¹ÌE{Б d®ŠµæhZ‰äöK‚ âÿ=XFÌÿiöÿ<ÿ’.ÿûþ¿ÖþœýŸ|ø±û„ÿ§Œð_ø3ú¿(W”Grs$§c6 *h«6dK̬|ÿç`1ÿmü×óùÙÿ‡¤Ëÿ¾ÿ¯ÇÿÙÿ÷ò¿ï.áÿ)#üþïè½øß#:ò%)ˆ-Þ–‘”XBŠ:×ê„ÿÇʈùoã?Ü¢LcŽœÿ’.ÿûþ?ìÜÿŸýOÝùØ? ÿOá¿ðOÿ_ó¿ûˆ1ú£#v–U.©@€…Û °Ö(ü?VFÌÿ'ÿ±Üÿ’.ÿûþ?ììÿ³ÿ/|ö{þŸ2Âáÿžþ‡kç¿¢˜Ñ“¨šªH–§ Œ¥€ ¥BÿßÁ2bþÛø?ùÚÿ±ðDºüïûÿpíÿÇÙÿ÷ª—ýó;„ÿ§Œð_ø¿§ÿÿkA µŸ4ÊmL´ÆWsÑL-9Ø\Œbñÿ,#æ#ü-ü‘ÿ¯öÏÿãÚÿ‹³ÿïÎÛßûeáÿ)#üþïéÿÅÿšb¦ ¹&ç1ø 1¥Èf&Áb¶ÞË÷–ó߯šžÿƒìÿCÒåÿü?®ý¿WçóÿÛWþŒðÿ”þ ÿ÷ôÿâm?ÌIaö¡@\[kR tZû¬­ (Ïÿ–ó߯ÿÙÿòþßtøÏê:ûÿÚÿ{u>ÿÿÂïzË¿ ÿOá¿ðÿfô?9OJQ•1SnÕ•¢&úòYx6Lì8ÉùÿƒeÄü·ñßÎßÿ‘÷ÿ†¤Ëÿëìÿ+þ·+…‰ÿóóá‹ÂÿSFø/üßÓÿ‹ÿÝT”ÅÔV7.Ú«A׆… õUTÙS…$ûÿÁ2bþ›øÏ“ÿGËù¿1éò¿ïÿÕÿ¿])Lü×ïyê3ÂÿSFø/üßÓÿ‹ÿ=f¨¾.Ž‚nÿ¢1ÚMÌ!Ôä\0Àrþÿ`1ÿmüŸü?Lòýß!éò¿ïÿÕÿ¿])LüÝ¿üáÿ)#üþïéÿÅÿ® GpÑ6"de¹¨+R¾ü[áÂÕ[ÒÔþ ü?VFÌÿaöÿÉýÿ!éò¿ïÿ»ºòÿ´+…‰ÿ¿©Ÿ’çÿçŒð_ø¿§ÿÿ«Ï(锲GgŒi¿@ û³ÂÿSFø/üßÓÿ‹ÿ]Ug9[wç\MŠQ•jJÖ!*¾jCÂÿceÄü·ñnQ—7„ÿCÒåßÿÇkÿ?Ìþ¿÷ëÇ^*ü?e„ÿÂÿ=ý¿øßu¡`ÁgP‰©æB•r¦ ­ª¾µGd²þ,#æ¿ÿ³ÿGÉóÿ!éò¿ïÿãµÿfÿßG¿þô ÿOá¿ðOÿ_ó¿ÛÀÈ0”ì9€©Œ…ŒSØ6ºdJq¶hÃâÿ;XFÌÿq>ÿ'çÿ‡¤Ëÿ¾ÿ×þ˜ýïÖ¯¸WøÊÿ…ÿ{úñ¿Öä«OÌ*gƒùÙ;·Ý®« §”VR/ZAÑ‚Ô*Á:ÇsŒ9g0,D/-ŠgÁy¤â©P<á!ÑÔ6Õ´ÅJR+V›¤9¨mð,êE[ŠJõB¬Š1­R£×ÿ-VÖÜÈÚk3Y Æ a‡Ÿï›ï³Æ÷Íù,†i´Æ´lm¡XcÌÉŠAÏÿ,#æüŸ,”ÿ#Òåßÿ'kÿ/Îþ¿OýÝ7¾WùÊ(ÿ•ÿ{úñ¿²äЉcH­ŠOÓú—Ò„o\(–‹DˆÊÿceÄü·ñöÿ~þ?$]þ÷ý®ý?8ûÿ¾öɽAùÊ(ÿ•ÿ{úñ¿&ë(:ÉžÅæŒ -Sm•ÄDQ$P)ΰÞÿ?XFÌÿeÞÿõþßôøÿPÿþÿ£kÿÎþ¿/æ]O)ÿOå¿òÿFô?ºi½±YÇÅÍ%Ã%ÈäÙp™kKYßÿ{°Œ˜ÿ6þ_ü?Vôý?CÒåÿþ‡ÿÍ÷ÿÿí-¿qòÿ”Qþ+ÿwô¿]üïžs«ƒ3ÁÖØ¤êsdt5”œRXE$(ÿ–óßĸøœ~ÿ?&=þKÿ‡õçÿÍ÷ÿ¿óÃOåÿ)£üWþïéÿÅÿ.5y´ÓÚl3miŽ[ Øú 2·ÜôóÿƒeÄü·ñæ÷ÿêçÿCÒåÿ‡õþ/óþÿ‰ÏÿÐg*ÿOå¿òOÿ/þwëfpÕ•$\ ²8t½/P²™šSN ÊÿceÄü·ñ¯øO¬ûÿtùß÷ÿÁÚÿ/óþÿü'¿ô •ÿ§Œò_ù¿§ÿÿkÍ ’§½/Uï¼4Œèéê+®TæÔZ³zÿï`1ÿëà?êù¿1éò¿ïÿƒµÿWfÿß×ÙÇïTþŸ2Êåÿžþ_ü¯¶Q4±¦Z,[SBÁDÙH0>]½6„JÓ2XÕÿw°Œ˜ÿÿÏú?ü¿øÿuÿ’.ÿ{þ¿çýø×üÔ=|ß·½àöO>ü??ô‚W¿òsί¼ó¾û¦§¿ãÛïPúŸ4Êåÿžþ_ü¯â"§èê-°‚̾oCœPÀ¡@ €Î¢~þ°Œ˜ÿ¶ýÿâÿ¡éGÊÿéò¿ïÿƒµÿWfÿßûÿõ¾×'€SFù¯ü¿ýŸ!µ|y,ºR¡ùبM;aÃé?7‘¡bL‰Hù¬Œ˜ÿ6þ³¾ÿg`ºüïûÿzüŸýÿÉW²òÿ”Qþ+ÿ÷ôÿâwd[¤X¥µ rAïs)•€ÅrQ’òÿX1ÿmü¿ø„•ÿCÒåßÿkÿ¿Ìþ¿×Ñ;¿IùÊ(ÿ•ÿ{úñ¿Î>aHÞšd¬ ‘D‚­”$OÑ™\b*Í)ÿ•ó߯ÿ‹ÿ‡Ôÿ3&=þ?zûÿkÿ¿Ìþ¿ŸÀ¿~©òÿ”Qþ+ÿ÷ôÿâ‡XÈ…ê±’Y¢±à¡aï3ˆÌFßÿw°Œ˜ÿ&þãÅÿ3Gù?"]þ÷ïÿ?¸öÿ<:ßÿ¿ÿEò1åÿ)£üWþïéÿÅÿj|Å«}«ËÕº’‡”’n𮳤¹TcSþ+#æüWÿÏ ôøýýÿÁµÿçÑùþÿgÜüÙQùÊ(ÿ•ÿ;úŸÿk±`9%jÛ|ã"rŒ„ ¦fw)gkõüßÁ2bþÛøñÿ éùÿ!éò¿¿ÿózÿ‡yÿÿ—¿xüaåÿ)£üWþïéÿÅÿZ±®(û`! ñ±SÈû\"€͸¢þÿƒeÄü·ñöÿè÷ÿcÒåßÿÇëýæýÿu_’ߤü?e”ÿÊÿÑÿdkôEb³ÞC«<çœ\(£Óß!ÔóˈùoãÿìÿqzþHºüïûÿzüŸýï»ãÏHùÊ(ÿ•ÿ{úñ¿ fô@¦©P\$à%š~J6Û† Õÿ{°Œ˜ÿ6þ_ü?òDºüïùÿ¦!­ýÿðÏþÿå3ˆÊÿSFù¯üßÓÿ‹ÿ¼'ˆ¹ú¼Í¦´Ì6Ç0-ƒ¡BOI*O¿ªü?VFÌÿùŠÿLzþHºüïûÿxíÿ‡Ùÿw÷wÝv—òÿ”Qþ+ÿ÷ôÿâGh)S2>•’½½ZÿØG#Ø’ÄAý¿Ëùo⿨ÿ`ºüïûÿøgÖüŸý÷¿ü¶·(ÿOå¿òOÿ/þWË"òTÿ!rˆ†cɱù‚%øVk )é÷ÿˈù_ÿÉêù¿!éò¿ïÿãµÿfÿß³wßó·ÊÿSFù¯üßÓÿ‹ÿ5Æb2'/M¨KÒ<™Æ)[—›m¦Jp­(ÿ•ó߯ÿ‹ÿòHzü°ÿŸ×þ_˜ý¿üß{PùÊ(ÿ•ÿ{úñ¿J2’}ƒ˜S è¦öÏÉr%É!†ªÍ^ù°Œ˜ÿ&þ“™ù¯çÿ†¤ËÿkÜÿ_ûœïÿ?ðYïåÿ)£üWþ߈þoÁSJ-‘%Ž‚àR®hCpŽr05M@Ȩçÿ–ó߯ÿ‹ÿÇ’~ÿ?$=þó5öÿÿçûÿw½ù«žTþŸ2Êåÿžþ_üïSíg)Ù†5 Á˜ÄZ3±T1mêwñMÔÿ{°Œ˜ÿ6þ_ü?,zÿHºüïïÿ¬ý<ïÿÏÿÅ¿z§òÿ”Qþ+ÿ÷ôÿâ—(ÄŒ JS} Q¨õj¬µTŸ8¹À”ÿÇʈùoãÿÅÿƒúýÿ˜tùß÷ÿ=²öÿð¼ÿß÷9/þiåÿ)£üWþ_ÿ³Yü¯66ñB’«í|NjN`í´ÿS¼úTWù¬Œ˜ÿ6þ_ü?¢ßÿI—ÿ]ÿ›Îþ?ûÿ¾åeÿy¯òÿ”Qþ+ÿ÷ôÿsþwAR Íd—#N»~´8íqhšs*Œ¥Ýÿ–ó¿þ[PÿÏtùßõÿ±éìÿ³ÿï{?úÈÝÊÿSFù¯üßÓÿ‹ÿ5@áâ¨YÈ®”ê²md _}ŒÐÈÆjPù¬Œ˜ÿ6þ_ü$Êÿ!éò¿ëÿc³öÿòìÿ{ͼðó”ÿ§Œò_ù¿§ÿÿkb ®X“sÍ6áÔd‚˜Sb—s+¦DÑ÷ÿ,#æ¿ÿ2ïÿ ü‘.ÿ»þ?6kÿ/Ïþ¿?~ûß¼PùÊ(ÿ•ÿ7¢ÿ½n 1c†…®®ûWŽs!EÚ‡˜•ÿÇʈùoãÿìÿq¤ü‘.ÿ»þ¿.ÿgÿß‹~ýu¿ªü?e”ÿÊÿ=ý¿øßÁ•d²±Á  —T‰K&4•j•–CñÖ•fÔÿs°Œ˜ÿ&þ[3ïÿzþHzü¤{ÿŸÍÚÿϳÿï¡òÁTþŸ2Êåÿžþ_üÃåS`t¾Öâj©!fW ª \Ë õüÿÁ2bþÛøóùåÿtùß½ÿÏfíÿd¾ÿÿ+ïú£¢ü?e”ÿÊÿ=ý¿øßŠw\(ˆ’Ûôƒ‰Ü FfW¬µÊÿƒeÄü·ñÿâÿA=ÿ?&=þÓ5öÿµÿÿ‘ùþÿÛnùä[•ÿ§Œò_ù¿§ÿÿk -‘©žš >efÊI{ÁõóÿƒeÄü·ñÿâÿ±¢ûÿtùß÷ÿ=¼öÿ¸Ùÿ÷Ñ—ÜñÃÊÿSFù¯üßÑÿøœÿ•¸`ÉK…\Ɇ aúsÚÿ!ט VÐóˈù_ÿ¯~]ù? ]þ÷ýØÙÿgÿß§¿íåïUþŸ2Êåÿžþ_ü¯djÌ¶š˜ ‡Ï.'´¹ÊP§¿ÃÊÿceÄü7ñ_.þŸé™Aù?"]þ÷ýØÙÿgÿßW¿êÞÿVþŸ2Êåÿžþ_ü¯Á徊É> ¶ˆgki"€Ï¬³¥@€ª÷ÿ–ó߯ÿ‹ÿ‡ôóÿ1éñÿ±þý\ûÝìÿƒo~ǽÊÿSFù¯ü¿ýŸ§–ÇSB$fì‹°•3ÄæTˆôý¿ˈùoãÿÅÿC¨þŸ!éò¿ÿ¿ÃÿÇæûÿ¯ÿ”ßVÿÿ9£üWþïéÿÅÿŽ6r¦œE|³&Øì]ãI –ÄnZèR©€ºÿ,#æ¿ÿ¤çÿ¦ÃÿGÍ5öÿµÿÿ±ùþÿÏþüí¿¤ü?e”ÿÊÿ=ý¿øß]ä–|mÍ™bȵ\}L§‘PƒòÿX1ÿmüŸý?¤ü’.ÿ¯±ÿ¯üÿÓ“Â…ÿ?öø Þ¤ü?e”ÿÊÿ=ý¿ø_ƒåìÈQªµYs®Ñ66\l‹¡ºàcë¬Þÿ?XFÌÿyöÿ«ÿwHºüïûÿpåÿž.ü‰ýÈÃÊÿSFù¯üßÓÿ‹ÿµøÒ$ œC†œ§Þ÷bÙVÑ…©Þ£#åÿ±2bþ×ÁvzþoHºüïûÿpåÿž.üÿÜ¿Å?(ÿOå¿òOÿ/þWphÓTö©a3Î9ŸJaç*¸`jñ¡Jä$ÊÿceÄü·ñÿâÿ#åÿ˜tùß÷ÿáÊÿ;=)\øÿůhO+ÿOå¿òOÿ/þ׿! %fŸ/ºʆb´T(Nÿ—§¥Î)ÿ•ó߯7ŸÿÓóÿCÒåßÿ÷ÐÊÿ3=)\øÿƒ¯yí­ÊÿSFù¯ü¿ýOKôL2(TKFg“Ï)@Ù'ÇõüÿÁ2bþ›øï.þ‹ºÿI—ÿ}ÿ_ÿ³ÿï~ä·žRþŸ2ÊåÿžþϽÿ-…†P1bmœd‡P¬óVØ#ÑÕ«”ÿÇʈùoã?Ìïÿåÿˆtùß÷ÿ=´òÿMO þßòw/}—òÿ”Qþ+ÿwô?-þwŸ‚ 1¡­D…\«©U SÉÕ…ŠÍ×$¡êû–ó߯¼É1¨çÿ‡¤Çÿú÷ÿ¥³ÿÏþ¿?ó§O*ÿOå¿òOÿ/þ÷iÍ $YgS”&|„š}5ÉJ¡Ö2û¨þ¿ƒeÄü·ñŸÔÿ;0]þ÷ïÿËzÿ`¾ÿÿ_¯úÀÊÿSFù¯üßÓÿ‹ÿÕdŸ£diÁûÆfêVpÚÿ"fX1L,Pþ+#æü·¬ïÿ’ÿí5öÿ•ÿwzR¸ðß}žZùÊ(ÿ•ÿ{úñ¿R´Å “\­l)Šaô”<9'™± @Rþ,#æ¿ÿÿTþH—ÿרÿWþßéIáÂÿ'~çÅߪü?e”ÿÊÿ=ý¿ø_9ù‚NÇ ™‹TS&¸19ëÌ•h*÷””ÿÇʈùoãÿÅÿ#¬þß!éò¿ïÿ“µÿ×Îûÿ[Ÿ}ñ÷(ÿOå¿òÿFôÍžÅÛ˜Z‹"µŒáJ,»ÿeïìBËÊ:>ÓhCÕ¤¢ • ëYëyžµVoH‚†E76"¤ ëõ¢4Êèš$‡†Ìf0)ɽÞS:çðŸCب£•¥PÐdÑ@5N/jeS¨•­ßo»O{ý‰}öi±7<ߘsþ¿Ã¹y˜ïç÷ì½×gcu®  Q$üßWFÌÿÏþŸö áÿˆtùß÷ÿõø?ùÿîþïßýsáÿ!#üþoéÿÙÿ®©õ|5{"T-¦B–\>}ÐþpQP„ÿûʈù¯ãÿÙÿ$þŸ!éò¿ïÿã¥ÿ'ÿßËŸòÙ?þ2Âáÿ–þŸýïÕfߪ?GÆ™’ Y›,;å9yD¬š#iç„ÿûʈù¯á¿U“ÿGîÿI—ÿ}ÿ/ýÿ8ùÿ~ð#/¯ÂÿCFø/üßÒÿ7üïÉ+rÀ‰µ9=ô Ú‚JZ{TèSÃCÍÉËýÿeÈüWñÿìÿ%÷ÿ‡¤Ëÿ¾ÿ—þœüŸ{ñ/½TøÈÿ…ÿ[úö¿*Hš $[ÙĶûå’ `ôè4Z¯kaŽÆ ÿ÷•ó_Ç=ùÿåüÿtùß÷ÿ]_úpòÿýÎWÿÅk…ÿ‡Œð_ø¿¥ÿýó_Á°.À '\È¢ àRqʸì‹F¹þ¿³Œ˜ÿMðAÎÿIÿýóÿ×—þœü¿ö•¿u—ðÿþ ÿ7ô?ÎþW£ÚÌDÈ’·ÙPŠØÖ¸œ£(`|kõ¬‚ð_1ÿuüŸüFü¿CÒåÿü?,÷ÿ‹éüÿ•w¿XøÌÿ…ÿ[úö¿ÆÚÚ»Ôl‰ £&W€2¨ÓuÿŠdu­m®òþßeÄü×ñ'ÿ¯¼ÿgH:üÕßÿa¹ÿ_Lçÿ¿þŸx•ðÿþ ÿoEÿ[=„‚*1ê’×Á&Ð !˜ÄÂÿ}eÄü×ñÿìÿ!”çÿ†¤ËÿKöÿÿÛ7…3ÿ_ö‡_õ<áÿ!#üþoéÿÙÿn-–öÍŠ“61XŸ[WM…*ز-^Éþ¿³Œ˜ÿ:þŸý? <Âÿéò¿ïÿƒ…ÿ¿}S8óÿá;æYÂÿCFø/üßÒÿ³ÿµ/ŒE§l!z›O·‚½i4pÌÞûLžT¤*ûÿÎ2bþëøöÿh¹ÿ?&]þ÷ý°ðÿ·o gþâWõÝÂÿCFø/üßÒÿ³ÿµ­÷À\ÕN“¦¶øY4Ön?´FSÛƒ‘çÿw–ó_ÅPÓùÙÿ‡¤Ëÿ¾ÿþßöMaòÿÝ÷ž7ÿá¿ðKÿÏþWʦ¯ CM¹b#~1 ±X•kPmm¿ QžÿßYFÌÿ&øOVžÿ’.ÿûþ?XøÛ7…3ÿoÊ÷~TøÈÿ…ÿ[úö¿ŒÖW’ü—¨Cõ:·µŸ]ò–5͵°3. ÿ÷•ó_Çÿ³ÿŒø‡¤Ëÿ¾ÿþßöMaòÿ}ø‘/ÿá¿ðKÿÏþWëX%P¬|):¹ÓÑoŸMѨ¨3»X( ÿ÷–!ó_Åÿ³ÿÇ ¼ÿgHºüïûÿ`áÿmßÎüWþ±ÿá¿ðÿVô?Úl¶‰i“75™è̘Úo|4šªð_1ÿuü?ûH‹ÿwHzü¿rÉùÿÿ'ÿß·þÍ3Ÿ/ü?d„ÿÂÿ-ý?ûß¡fÃ*úܪ¾”“9’§˜l ŽA)’<ÿ·³Œ˜ÿ:þ·Ÿ›öCyþHºüïŸÿ¿ºðÿµo gþ?÷žücáÿ!#üþoéÿþwjOmýÓ  r.•mŽ€…³‹L¥ÀÑÿ÷•ó_ÇÿÉÿ£dÿ’ÿ±¿ÿ_]ú®|ñüÿ#w}FøÈÿ…ÿúŸfÿ»v˜˜LÛør®ÖØŒ«ÎNGoO†×ZQû*×ÿw–ó_Çÿ³ÿÇhÙÿ‡¤ËÿþþOËý§ýÿ#Oÿ« ÿá¿ðKÿÏþWɨjJIžS*qŽUÇÛV4g.Ž]"ñÿì,#濚ÿ¦ýõÂÿ!éò¿ïÿ£åþÓþÿšû¾ôáÿ!#üþoéÿÙÿêt_ Õ© ÈE_²sÌ\ ok ¯ÁÉùÿeÄü×ñßNïÿ•óÿCÒåßÿGKÿ/Nþ¿ïÿϽMøÈÿ…ÿ[úö¿¶…­D®­ÃUЈ֛ Ð޷߇˜@GÂÿ}eÄüWñ_Oþ?ñÿI—ÿ}ÿ-ý¿8ùÿ~ô­¿÷Fáÿ!#üþߊþ¤­³®T¯´¶ÖM‰±L>Ö:AfUœ\ÿßYFÌÿÏþ yþoHºüïûÿzüŸü¿yõžG…ÿ‡Œð_ø¿¥ÿgÿ{ uhTí\ŠѤ’j(®R± üÅrM®ÿ÷•ó_Çÿ³ÿÇjyÿïtùß÷ÿÑÒÿ“ÿï'îùáÿ!#üþoéÿÙÿ®bÉMÎE—“ëß ÑÛ¢“3¢…£ð_1ÿuü7çóÿVžÿ’.ÿûþ?Zúÿqòÿ}ìeÿô ðÿþ ÿ·ôÿì÷µ€oåI£ŠH­Glp.•X±”JeÿßYFÌÿñüþ_+þß!éñÿ¢þŸ–þœü×îúë'„ÿ‡Œð_ø¿¥ÿgÿk²À¬/F¡QäQSRš­ñ‘Nÿ±±æ¬•øÿv–ó¿ þ+%ü’.ÿ/9ÿ¿ôÿ^LçÿßùØG£ðÿþ ÿ·ôÿìµMŒ‘lÛüª5¥zC`SVÎ5´öwDѳ¼ÿgg1ÿuü?ûÿÚß,ü‘ÿuÿhéÿ¹˜ÎÿáÓßó¸ðÿþ ÿ·ôÿìu‘³vրϬ¹ NZé`sDS(%[•K%{yþg1ÿuüŸü,çÿ‡¤ËÿþþÿÐÒÿ£§ýÿiϺóç„ÿ‡Œð_øóýÏjö¿rN¹D“LU^Õ¬¢B¶Å´V )Ôžœþï+#濎ÿgÿÏùÿáÿÿºüïúÿŒZîÿzÚÿoÿðãÿ"ü?d„ÿÂÿ[ÑÿÅqÌÆ+E&¥hM`hŸ:ãY…Ì퇞}Âÿ}eÄüWñßœý?šäùÿ!éò¿ëÿëòòÿý釾ó•ÂÿCFø/üßÒÿ³ÿjdƒ!Ml­ãj*SDÕ6ÿJ•öy6 Åÿ»³Œ˜ÿ:þŸý? -Âÿéò¿ëÿ3ªsýòÿý™û²ïþ2Âáÿ–þŸýï*•ȾzãØ³Ö!4Øj4cQœª2Ø–ÿâ½ð_1ÿuü×ÓýáÿtùßõÿµôÿëÉÿ÷ä“ï•çÿŽá¿ðKÿÏþ×¢=XJ©•¸³±¶MŸCò(ŸþÉ 'F/þŸeÄü×ñßLû¿ø‡¤Ëÿ®ÿϨ¥ÿWOþ¿poþ}áÿ!#üþoéÿÙÿj"Tæ\ j X“¶ÁC±Ñ†Ó3]ÉUë|F/çÿv–ó¿þ³œÿ’.ÿ»þ?£–þ_=ùÿÞtÇ—?,ü?d„ÿÂÿ-ýÃÿš" Y…èÙçcÎD4™ì±æÄ®†Ð( üßWFÌÿ'ÿÿ‡¤ÇÿkÝóÿF-ý¿zòÿ½ñkäƒÂÿCFø/üßÒÿ|ãý/5¨êU“jq8zk}뢋öš¢k…ÿûʈù¯ãÿÙÿCZ®ÿI—ÿÝóÿF-ý¿×¦óÿzÇ‹^!ü?d„ÿÂÿ[Ñÿ'ÅÔÈI£÷”mNÑxV;Ž…3y]­ÊUüÿ;ˈù¯ã? ÿ¦Ç¾dÿïð:ÿÿo_ó—oþ2Âáÿ–þŸýï¡­yD>h­ôƒv\4*ÙTjß|Urýg1ÿuü?ûÀ*áÿˆtùÉþ¿ôÿó´ÿßû·ïýuáÿ!#üþoéÿÙÿž=PÅD1i•bðJÅ¢s1ÔVAGFa âÿÝYFÌÿñìÿ¡öÇ…ÿÒåßÿweéÿáiÿâí¿øIáÿ!#üþoéÿÙÿ^‚OÁøÌ¾€µ•Fkx›‚*5¦ˆ¶äö ÜÿßYFÌÿÏþ&¹þ?$]þ÷ýW–þžüïûæç¿GøÈÿ…ÿúfÿkŽP¼Q\ª tzõkU¶1!×Úö¬½w^ùjŒð_1ÿ›á¿ìÿcÒåßÿ‡ýòÿÝóï¼OøÈÿ…ÿ[úö¿V,)„ R%RÐÆR*80-|ºö¯] âÿÛYFÌÿÏþ?6rÿHºüïûÿ°³ÿOþ¿gþcáÿ!#üþoéÿÙÿjÀ8Û'L¡êJN‡Á¼ ¦¢Ê5E… ïÿÙYFÌÿÏþ4òþŸ!éò¿ïÿÃ¥ÿ—'ÿß§¯½ûáÿ!#üþߊþ×­àÛ–_ ”¬)º0¦T¯ Ô> Q%OÂÿ}eÄü×ñ'þËõÿ!éò¿ïÿëñòÿ=ïú¿"ü?d„ÿÂÿ-ý?ûß)9ã“ÂÀ•¬Å½Î L`ͦ¢­¤„ÿûʈù¯ãÿÙÿ£-ÿG¤Çÿëýóÿ¸ôÿóäÿûÆßþ‰Ç„ÿ‡Œð_ø¿¥ÿgÿ{[î!©ÌÕQMÖ{O*Z"Dêé\˜SÕä$üßWFÌÿÏþ£dÿ’.ÿûçÿqéÿ¿>ÿ¿xÿ• ü?d„ÿÂÿ-ý?ûß™{ôØP\A  yW¸‘ß3öV+gåúÿÎ2bþëø/þŸ‘éñ.Ùÿ—þÿëÓùÿ;Þ÷Žþ2Âáÿ–þŸý¯ZrT…„\"€¢@qæ £I¦jyÿïÎ2bþ7ÁTrýHºü¿dÿ_úaÚÿÓ—|ìéÂÿCFø/üßÒÿ³ÿIåbuªÑ{‘päƒS˜™XAi_l Âÿ}eÄüÿoþ›ÿå?ýˆÂÿ!éò¿çÿ»ýï^uÿ>üÚ§~Û]üç½O}É _óŒg¼ä…¯û…×ßö?ÿ´ýá¿ðKÿÏþWkJˆAWˆ®b-K®Ê£r9DÁ¶9kÿÏÎ2bþ«ö‚Û”QJ ÿ‡¤Ëÿ¾ÿïbéÿÉÿ÷®Ç¾ëvùpÈÿ…ÿ·¤ÿ]ÉmIœÉFkLqŠ ä”jMÞÞèŽX®ÿï,#濎ÿ“ÿDzðDºüïûÿzüŸüßtÿ³ÿUøÈÿ…ÿ[úö¿c¤²¿»(­ÀVÞzvV¡OZ©Ëóÿ;ˈù¯ãÿÙÿ£øÿ‡¤Ëÿ¾ÿïbéÿƒÉÿîøÔK…ÿ‡Œð_ø¿¡ÿõì'ª6[N7¹ÔàÑ… ¥­€.1ú˜IeWQü;ˈù¯ã?Nû¿\ÿ’.ÿûþ?ÝÙÿ'ÿß›ßüàO ÿá¿ðKÿÏþw¨Ù•R«Ó¢ó†“·ÉªhL)uÕ5gº ÿ÷•ó_Çÿ³ÿ‡åþÿ˜tùß÷ÿéÎþ?ùÿý†oyDøÈÿ…ÿ[úö¿†\³aƒ.i‚¨€TU9jOˆ­ÎƒöÉ(%ïÿÙYFÌÿ&øoŒðHzü¿Ú?ÿ¯—þ_˜üoøŠßþ2Âáÿ–þŸý¯|MÕCµd£;‰á˜="ª^; êLÑÈõÿeÄü×ñòÿ! ÿG¤Ëÿþù½ôÿ^Îÿ¿ýús^$ü?d„ÿÂÿ-ý?û_³6UW—¬â 4S0ž¹†*E•µÍ1*AžÿÛY†ÌÿÏþ²âÿ’ÿé’ýéÿ½:ùÿÞôÝ_'€cFø/ü¿ýäÁB(Z·ƒ£¼ªÕ¸Œ9xÎdð,üßWFÌÿYMû¿ðHºü¿dÿ_òŸ¦ýÿ—ŸýŠOÿá¿ðKÿÏþ÷ä#³v9 Q“gŠàSPÔ„Š’É”Šøÿw–ó_Ç8ûÿ¬œÿ’.ÿ{þ¿Æÿ¥ÿŸ¾èÿçƒ ü?d„ÿÂÿ-ý?ûß#S[ñ³Ñ‰Ûº_²:½õ­TŸ¡¨¤1*],d–ûÿ;ˈù¯ãÿäÿ1rÿHºüïûÿôÒÿO“ÿü‡ß*ü?d„ÿÂÿ-ý?ûß[ósbД\-Þk3dU»ìI S¬:‹ÿg1ÿuü?ûÈÈûÿ†¤Ëÿ¾ÿO¿eÉÿÉÿ÷‚ÕýÂÿCFø/üßÒÿ³ÿ•\±Ncö®X£r«x ºfÐFÕPÚ~³µ(üßW†ÌÿÏþ÷ÿŒI—ÿ}ÿßµ¥ÿ‡&ÿßë>ÿíß'ü?d„ÿÂÿ-ýïoôÌÉøäØêXcUÙGjÛŸË5ru&e’<ÿ¿³Œ˜ÿMðßÊûǤËÿ¾ÿïÚÒÿC“ÿﳯÿøO ÿá¿ðCÿ›þWÀä-xåLN–Œ7ÎE2‘JuÊj?à ÷ÿw–ó_Çÿ³ÿ§€ðDºüïûÿ¸³ÿOþ¿Wÿýgnþ2Âáÿ–þŸý¯„†¹Ä2åR ·©ý"&M¦}’-çÿw–ó_ÇžÞÿ+Ïÿ IÿõÏÿsgÿŸüwþŸþ2Âáÿ­èdoÚÑ“Q² •MÛåB4 Çâ)G²Âÿ}eÄü×ñßN÷ÿµðDºüïŸÿïðÿ¡éüÿ§Þö³Ïþ2Âáÿ–þŸýï‹È1$cµÖ©FÛýZs$‹.øì59áÿ¾2bþ«øoÏþdñÿ Iÿæ’ýéÿh:ÿÿÉç¼ÿqáÿ!#üþoéÿÙÿŽÊ`‰1 ĶðûŠø?ì]ÈnÇU€#A[“¨`Z›J©ˆ(֢̬µæ¯xJcA4Ô´¥Z«Ö™Y3Zñ´„\^ØÞ¤ô%ê!(½‰íÔ“äK"X½6U‘BjÄ‹h Ñ¥ÒP1÷»·û ÙóQö·?‡½a=ÐÐós·8ëÙó~ï<;ùzúPXƒÉiéÿíŒó_çÿ±ÿ3þûÿÿÿÓôÿ9çÿeÿ§óÿmϼxŸøÿˆÿÅÿ[öÿÜ-…”>½öÕk-™ªu&›äâéüçRuË÷ÿvF§ù¯ðÿØÿ1 þïBÓÿíþŸ]öq:ÿ_yìÅ?ÿñ¿øËþŸû¯±7ÕØ\õi‰DFmK ‡qZ,ƒª^>ÿß=æÿ­ýO¯ô?jùþ_šþoôÿ^õ±žø1¾ÿ¹òæþ³ÏþÛ›oûÐó\}ýÝüÈý7ÞP^sûWDÿÇDü/þß²ÿçþ+T‚œs ¥jf BŽ6°)Q_лlµ âÿÑcþëü?öÿIÿ¿ Mÿ·ûö•ýßoÿØäÿ×þÉÿ(þ?&âñÿ–ý?÷_«rgÅ•|M¬ŒU>dfþ¿2!T—Åÿû¢Ëü¿¥ÿÿïçÿcÿÇ*ùþšþo÷ÿì²ÿ‹Sÿïý?ôH–€C"þÿ_Æþ·.ÔÆ˜’†šˆ"“ö†7 ÑFUkˆAü¿/zÌÿÇþ‚ôÿºÐô»ÿ×òÿÔÿ»ë–ß|PüHÄÿâÿ-ûî¿s‚¤Ù)C®xðÀïT(”}ÌZeÏ!çTÅÿû¢Çü×ùߎþ·òùšþo÷ÿ[öÿpêÿ½úýú“âÿC"þÿoÙÿsÿ½d¬ÎŒ‹ÊT d]“+ѹ’J²Ãé0pñÒÿß=æ¿ÎÿîÔÿÓòùZþ¤}ÿÿ±eÿ§þß·½ýÎÄÿ‡Dü/þß°ÿiî¿£ª^%£IçTÂé¥?¡²òlÈçH:f éNü¿/zÌ…ÿõøïÿtÿ_>ÿïBÓÿíûÿzyþdºÿÿºyPüLÄÿâÿ-ûî¿Æ¨HëL‘Dëu… %púü8ÜUŸÄÿû¢Çü/àBùü¿ -ÿ»öù_/ÏÿL÷ÿûÒÛþFüHÄÿâÿ-ûî¿Feb¤BQ³ÊÁ ÿ«ÃW¨³öŒžbäYü¿/zÌÿÇþ‘ôºÐôÿ9çÿeÿ×Mçÿwß]¿!þ?$âñÿ–ý?÷_«Žžò°çµ Öâð‡%r©ÖDˆjø3£\"(rÿogt™ÿ*ÿý’þOšþo÷ÿô²ÿë¦óÿ_úó'Åÿ‡Dü/þ¿Œýï½tYí«cäSδÌÏÕk¯3‰ÿ÷Eù¯óÿØÿ'çÿ.4ýßèÿãÿgFÿßôò­ÿñ¿øËþ§ëïEŪÉú„Ñ’1ë`~O˜Çâ˜Gñÿ¾è1ÿuþû?`åüß…¦ÿÛý?½ìÿ»çFÿ?øÏÿ%ñÿ!ÿ‹ÿ·ìÿëý÷ˆëðÛ™µÖP hbC¶pNQAUÙ+÷ÿvFù¯óÿØÿ¡a ˆÿ;Ðô»ÿ§?±ôÿÔÿûÚ]÷|UüHÄÿâÿ-ûî¿£q¹ÔÐûÙød¢Áb#CH©¤l!(d'ýŸÑcþëü?ö¬ôúÐô»ÿ§_Ùÿü?õÿ^óé}JüHÄÿâÿ-ûî¿’·ÅSrÊUcŠ¢”bÌ=ò“2¦Q¾ÿ·3zÌÿÝèÿᯋÿ;Ðô»ÿ§—ý_7õÿÞq寊ÿ‰ø_ü¿eÿÏý׊·6WJV•Œà¸pÖ¿ö&$£¹ª‹üügô˜ÿEü¯äû]hùÿñöýÿ‡–ý7õÿ~æžþ”øÿˆÿÅÿ[öÿÜÕìj0Öçµ*‰ÒpîÏ”X¿kùþßÞè1ÿUþ×cÿÇ9éÿv¡éÿöýÿ‡–ýŸÇ§ûÿ|Ûß¾ZüHÄÿâÿ ûߨëïóBˆIQÐ.蔜 è]‚Jl†Ó`U&€ø_ô˜ÿ:ÿýeäüß…†ÿRíó¿YžÿŸîÿ_ýÌËïÿñ¿øÿ2ö¿£TTµ %טkF2†M¦Dk¨µ8Uµø_ô˜ÿ:ÿýk¤ÿß…¦ÿÛçÿ¥ÿ‡'…Ñÿ~íUÿñ¿øËþŸûïIq¶^UF¢àNÿñIOÕ$¶h­D­ÿï‹ó_çÿ±ÿƒFîÿw¡éÿvÿÏ,>ÿžFÿÿ`ý§?ÿñ¿øËþŸûï®—Ä.¤ì£M%Õ ´÷ÿïBÓÿíþŸYô‡'…Ñÿ/üÄÛ«øÿˆÿÅÿ[öÿÜeºûͤ‡s~°˜}@“”µÁøÈºx\¦è¼ø_ô˜ÿ:ÿý?TÒÿëBÓÿíþŸYô‡'…Ñÿ¿úÙ?þiñÿ!ÿ‹ÿ·ìÿ¹ÿZ dEųvŽKŸJ2Õv ‚Ö1úRµœÿwFù¯óÿÔÿqÒÿëBÓÿíþŸYô‡'…Ñÿïº3Þ*þ?$âñÿeìÈ1sŒÊ ¼d]J"ª§;à˜9kˆÌ§¿Aü¿/zÌ•ÿaø÷JÉ÷ÿúÐòÿµsîÿ7ü?õÿþþ7Þ'þ?$âñÿ–ý?÷ß]RUX‰#!Œæd²¤âéCbTâÿ}Ñcþëü?öHËýÿ.4ýÎýÿEÿxRýÿÌ•×~·øÿˆÿÅÿ[öÿÜ·‹Š¶$o,ŠÚÔ)¤‡ßO6T $þß=æ¿ÎÿcÿÇÈûÿúÐò?µÏÿ.û?צûÿwþÇw|@üHÄÿâÿ-ûî¿{8³Á08m½q.†¢C.µK¶z.œ’ôwFù¯óÿÔÿ!ùþšþoŸÿ]öh:ÿ?ñº_¿WüHÄÿâÿ‹ï§®÷_ „ u&Qœ k0¬øôΟ EÒ¥–\Åÿû¢Çü/âóšþoöÿœZžÿi:ÿ¿øÖgoÿñ¿øËþŸû¯1yªÉ‡avdB(©€Gg9x`*kÈ8H@ú¿;£Çü×ùìÿ¡•ïÿw¡éÿfÿÏ©ÆùêÿýÙ½çâÿC"þÿoÙÿsÿ•tȾ°‚utäK¬ÙªŠ&zJ^Çœ²­™Åÿ;£Çü×ùêÿ)ÿ÷ éÿfÿÏ©eÿ—¦þßÓ?þ¾Ÿÿñ¿øÿ2ö¿U1„˜¹˜X€2i Ù$…Pe(¦$Y¾ÿ·3ºÌ•ÿ­|ÿ¿#Mÿ7ûMÿOý¿¿ëóoÿñ¿øËþŸûïE“²µ*ª%Xk‡Cœ-Á[ %(ç“RÒÿÙ=æ¿Îÿcÿ@Îÿ]hú¿ÙÿsjÙÿ§©ÿ÷‡Moÿñ¿øËþŸûïà+{ÏÚ¢Ì5žÞøW´RhMÕž¼:ŬJâÿ}Ñcþ«üjêÿË÷ÿºÐô³ÿçÔ²ÿOSÿï·ÿû¦ÛÅÿ‡Dü/þß²ÿçþ»Ïìªu…2Œ:’+6ZDþ.ðð)ª\¢ôÿwFù¯óÿÔÿ+þïAËÿgÍûÿN-ûÿ4õÿî}ÿñ¿øËþŸû¯É(ƒKÖì’.œ© †2ü>YçµIQü¿/ºÌ•ÿÇþÉûúÐôóþ¿SËþïÙtÿŸÊ›>'þ?$âñÿ–ý?÷_+eЬÙŸ´ Jí¡xŸ H\sQIA•ÏÿwFù_Àÿ Åÿ]høß¨sÎÿËþïÙtÿÿÉ»¾.ïÿ9&âñÿ–ý?÷_Y»Z< ‹ßæ Þ¦Dˆ‰¡Æ¼Éº8+ïÿÝ=æ¿ÎÿcÿLjÿûÐôûümÑÿžFÿæ/þ¾øÿˆÿÅÿ[öÿÜu”ɦ2ßN×ý-†RK²®XJ`9g ƒ­(þß=æ¿Îÿcÿ‡P~þß…¦ÿÛý¿k‹þÏð¤0ú¾ò¦GÅÿ‡Dü/þ¿Œý_ÀaBKÙ„¨"W°¡pÐ96H˜MQÕdGòóÿÑcþëü?õœ¼ÿ· Mÿ·û-ÿOý¿o~ùw¾WüHÄÿâÿ û_Ïý÷┋ºæh1:.1rÉ Ø$§¹:Ö&ùd´ø_ô˜ÿ:ÿýg¥ÿÓ…¦ÿÛý?j|þ?õÿ~àõŠøÿˆÿÅÿ[öÿÜÇT¬QƇZ³-˜óà{L*Öë°Ù+¹¢Oo†ÿï‹ó_çwƒ:½1Püß…¦ÿÛý?jœÿ§þßÏ_ýô}âÿC"þÿoÙÿsÿ5šè«/%³rÞèÉÔ¬uõºœºÿ`TPL çÿÑcþ«üOcÿçô×Åÿhú¿Ýÿ£EÿwxR˜ÞÿóË7^üHÄÿâÿ-ûî¿V¥f`Æá׊mdÁ Gÿ¨ÃR²†@ü¿/zÌÿþwÒÿïCÓÿíþ-ú¿Ã“Âôþß—þòeñÿ!ÿ‹ÿ·ìÿ¹ÿŠÌÄ–½5>ú¨kJlRÆÛLkd°Íâÿ}Ñcþëü¯§ûÒÿïBËÿ×Ú÷ÿiÑÿžFÿ¿Ó¿á¯Äÿ‡Dü/þß²ÿçþ+QåŒàƒ±‘¢SLIke0±v%ÚP ù(ïÿÝ=æ¿ÎÿÿÛÿ“Ïÿ»Ðôûþ?-ú¿Ã“ÂèÿüŸ7ñÿ!ÿ‹ÿ/cÿ‡˜1˜â=c!Š!{¤X©bˆ”R¬ K±Äÿ;£Çü×ùêÿ |þß…–ÿéœóÃÿÓýÿ_¸û…gÅÿ‡Dü/þß²ÿçþ»/1jv6¦`LÒÃÖ'•"'Bt%Y•4ªhÄÿû¢Çü×ùìÿ¹ÿׇ¦ÿÏ9ÿ/úÿÓÂèÿ‡¿ôäSâÿC"þÿoÙÿsÿ¢ã̃óZ+ʼnAGOZWG¼× |,ßÿÛ=æ¿Îÿcÿ‡äû}hú¿Ýÿ£EÿxRýÿ#wÞü’øÿˆÿÅÿ[öÿÜ×5[]ŠÆ¡‹1ºÈ!ë„§ÿz_jŸÅÿû¢Çü×ùêÿ(éÿv¡éÿvÿïlÙÿ¡©ÿ÷á7Üñeñÿ!ÿ‹ÿ·ìÿëý÷`ƒ¶1Ú˜ ­·†Làš5_"§¬½ÿïŒó¿€ÿ•ø¿Mÿ·ûgËþMý¿ßxîæ'Äÿ‡Dü/þß°ÿaî¿&*¡ÔZ´Nùt¨¾>Ýù;ýTXçb’·rÿogô˜ÿ:ÿ»±ÿcäûÿ]hú¿ÝÿƒÆùêÿ½ïWÞy¿øÿˆÿÅÿ[öÿÜ (W¦Ò¥”1#fR©©`€ŠˆÞËûvFù¯ò¿QÓ÷ÿÄÿ]hú¿ÝÿƒÆùêÿýÝó¿{&þ?$âñÿeì¶Ñ%ƒ­€)Z¨¬¬SÉ*7œcŬ²UZúÿ{£ËüWù_Oßÿsâÿ4ýßîÿµü?õÿnüê[nÿñ¿øËþŸûïèµ³½I:VÊÙà°2W…‰gã• ¬Äÿû¢Çü×ùêÿ€¼ÿ· -ÿŸµïÿòÿOSÿ¯üÅ÷ü–øÿˆÿÅÿ[öÿܧ¤´Ï6X`4l‚‰É3û\Ce ˜ t©¨ªø_ô˜ÿ:ÿý«äüß…¦ÿÛ÷ÿaÙÿ?›îÿÿì‡_/ýÿc"þÿoÙÿsÿ½øñøçÑ&T‘À·iP@&u::LºéÿìŒó_çÿ±ÿ3ˆGü߃–ÿáœóÿ²ÿ6Ýÿ¿ÿ×Î~TüHÄÿâÿ-ûî¿:W:•(¦ŒV'g½ª6f±o”RåóÿÑcþð?¡¼ÿ§ MÿŸsþ_öa:ÿÇßûæO‰ÿ‰ø_ü¿eÿÏýW `!8Uœrá~ÍÎdMâ J UÁðŸhÅÿ;£Çü×ùìÿ¡’þ_šþo÷ÿ`Ùÿ…éüÿÀ»>x¯øÿˆÿÅÿ[öÿÜeç°) ÉptTÆ ÈÞd­­%°%ê þß=æ¿Îÿcÿ¥ÿ߇¦ÿÛý?XöaêÿýõןvâÿC"þÿ_Êþ¯Á¦4üÁ`ùP •À#›Z†õá¹h…&[ðâÿ}Ñcþëü?öÉçÿ]hú¿ÝÿkùêÿÝñ¹|AüHÄÿâÿ-ûî¿›¯¹Øä(£]u>šTª \˜ÑqÈYÞÿ³3zÌ•ÿíØÿ± ýÿ.4ýßîÿ=¼ìÿÁÔÿ»å©O|¿øÿˆÿÅÿ[öÿÜWªºZ½âCHœ5cáý°8jÖ¢Í9ø¬Åÿû¢Çü×ù_ßpº1 åþšþo÷ÿ^ö`êÿ]}÷{Þ"þ?$âñÿ†ýsÿ ‹Xµ¶ aFz÷qÚȆ#ÉýÿÑcþëü?ö@ú¿}hú¿Ýÿ³óÿÔÿ»òÅ·Ý.þ?$âñÿ–ý?÷_S°>xVš<ðÿ°wv1»U§‰UÓhb5h *õ næc­53‰µ$L4A-^€ afÍŒQ@¢­R#[1Ô@Jˆ"Õ„’ˆ¤žžSið‹4Ô¨Q "E.0i !jœ÷Ùî#Éž²Ï>™ì¬hÞ>w+ùÿžµŸ™ß†„ª€¬‹V\tû¸%AÎÿï,#æ-ü×rþoHzü¿Ð¿ÿOýòÿÁ?ÝþƒÂÿCFø/üßÒÿ³ÿÕä­$Û¿­«CÛöUU!EÜh`ÿÿÎ2bþëøòÿ5ÚÿG¤ËÿþýZú/L÷ÿï|%?$ü?d„ÿÂÿ-ý?û_}H®ý=9ÖTƒŽÛBXo‘Û?Ù—V"Âÿ}eÄü×ñòÿ ÿG¤ÇºÊþ¿ôÿ^˜îÿÿãÝ¿ý.áÿ!#üþ_þ7ÀW`´&GŠUòX"%Šè­ÒòûÿÎ2bþëøòÿ€þI—ÿWÙÿ—ü§iÿÿÈó¾ðSÂÿCFø/üßÒÿWüïˆÑXë”­º¶2÷)$…)T£bTÁ“³Š­—ýg1ÿuüŸü?VÞÿ3$]þ÷ý´ôÿÓ´ÿö_x±ðÿþ ÿ·ôÿì×h£Q–"•¶ñgŸÙC‚ÛJ˜j²íïʹÿ¿³Œ˜ÿ:þŸü?ˆrþoHºüïûÿhéÿ§Éÿ÷ðÇ^x£ðÿþ ÿ·ôÿìo{_T> cnµÚÿR @\bANÖ&8;ýWäüßÎ2bþ«øïNþÿϘtùß÷ÿÑÒÿO“ÿï±Wÿè×ÿá¿ðKÿÏþW« 9pä¶êGDW=föÅW뜩…)ºì¬ð_1ÿkà?Éý¿1éò¿ïÿ£¥ÿ—&ÿßÛ?}áœðÿþ ÿ·ôÿìµ¾¤ÆxWÉ”à«"¤Œ¾–ÓëÿL­ªóè“ð_1ÿuü×'þ[ñÿ I—ÿ}ÿßå¥ÿ‡&ÿß·>ðž/ ÿá¿ðKÿÏþ×”Üé½o•g­«Í‘ˆmfŽ…böåÌé‚…ÿûʈù¯ãÿÉÿ㌜ÿ’.ÿûþ¿ËKÿMþ¿—Þö ÿá¿ðÿzôm[Ÿã@d¶!‚) ¥ä±-…”(»Xмÿwg1ÿuü·ÓùùýHzü¿Ü¿ÿßãÿäÿûè½?v«ðÿþ ÿ7ô?Ìþw§t6&j¯œò†cälåà±*.½¯­LXø¿³Œ˜ÿ:þŸü? Åÿ?$]þ÷ïÿëåóÿËÓýÿÇ¿ïAáÿ1#üþoéÿÙÿYÕèU-Ì5ƒò^åTbŒÕ(Û–Â33¼m”çÿ;ˈù¯ã?žÞÿrÿHzü×ýý_/÷ÿËÓýÿ×?÷­ç…ÿ‡Œð_ø¿¥ÿgÿ;“©Z;²+@%U†"ÄXÈÖ@Âÿ}eÄü×ñòÿœÿ’.ÿ¯²ÿ/ýÿzÚÿo~÷_ÿˆðÿþ ÿ·ôÿìU•»ÌFiï‚A—0xÈ•#ųŸþ7Ž iáÿ¾2bþ×Àáÿtùß÷ÿé¥ÿWOûÿ=ßôœŸþ2Âáÿ–þŸý¯JŠ©Tð%Y"qÈì4:•"ø¤m(1å$÷ÿv–ó_Çwzþo”ðDºüïûÿôÒÿ«'ÿßkñÎg ÿá¿ðKÿÏþ×È&¥ b$Ô¤átì˧Œ509Ì£M,þßeÄü×ð_«“ÿPîÿ I—ÿ}ÿŸ^úõäÿ{ã»èáÿ!#üþ_þO‰¢go’Ò%s.ä¢U%{å˜Ú¾8"yþ¿·Œ˜ÿ:þŸü?NÎÿI—ÿ}ÿ_ÿ“ÿïO/=y‡ðÿþ ÿ·ôÿìO®h(6€mÿÏ×èBÉtе»Ñ6NÊñÿî,#濎ÿfÚÿÅÿ;$]þ÷ýzéÿדÿï'ï|ÉÏ ÿá¿ðKÿÏþ÷P˜¢æêÈ£A³ ¶•ªÜ0P±fáÿ¾2bþ_ÿö+ø?ù”ø†¤ËÿžÿüžûžüÐko¼í¿þ¯»o|ÑóúeßbŸÿºw¼áßðO?OèÐÿ…ÿ[úö¿.)¶ AQðPMJ’O:ƪ¨záÿ¾2bþëöÿÉÿ#÷ÿƤÇÿóýûÿç—þ=ùÿ¾ÞߥäÀ!#üþoéÿpåü7çT‚³£!•ÙZ\…öAíÚ2HÙª*çÿv–ó¿þ£ðHºüïßÿ?¿ôÿœŸîÿïÓ¿ðˆðÿþ ÿ7ô?Îþ×¢ääb²)sâ mI\k1†\ P‹CÎâÿÙYFÌÿ'ÿŸüþ?&=þcÿÇåþ~ºÿ׿¾@øÌÿ…ÿ[úö¿êdŠ&l½N³s5ç€Ñæ Éaõ¦:O,Ïÿw–ó_ÇÿÉÿ§Äÿ;$]þ÷÷\îÿ8íÿOû‹þ2ÂáÿõèÌ5qô¥ýÝÄ„‘MâÌ…¡$° šT„ÿûʈù¯ãÿäÿQ²ÿI—ÿ}ÿ_ÿÓþÿyûæ— ÿá¿ðKÿÏþwŸ¸¶Ú¶%§€Öƒ®°j­‹ùìd8EJrÿg1ÿUüדÿ‡¬ðDºüïûÿpéÿÇÉÿ÷ØÇïþFáÿ!#üþoéÿÙÿ^­.D%Õà Q×j£jió juÂÿ}eÄü×ñÿäÿAyþ?&]þ÷ý¸ôÿãäÿû—[o{–ðÿþ ÿ·ôÿìOJv¤Ébá¨ Ú rW°T£É*…(ïÿÝYFÌÿOþ¹ÿ?$]þ÷ý¸ôÿãäÿû®7=û~áÿ!#üþoéÿ+þw"ˆµ¶ 7ì”ÍœT¯SnQ˜(j§«’ó{Ëù¯âÿÉÿƒZüÿCÒåßÿ‡Kÿ/Nþ¿KŸ{ì‚ðÿþ ÿ·ôÿìÕ)Ÿb›gëïœBHÁ¢oû`ð‰ ±2,üßWFÌÿø(þÿ!éò¿çÿkü_úñßNüË-þß…ÿ‡Œð_ø¿¥ÿgÿk² ª´­/úÌ:´òO©ú 89Õº,«âÁÈïÿ;ˈù¯ã?ÈùÿéñÿÒUîÿ¿}ÉÿÉÿ÷¶¯ýá?þ2Âáÿ–þŸý¯©æÙGr0FbÂÖ膫±…¨±Àaá$üßWFÌÿñlÿ'%çÿ‡¤ËÿþýÿKKÿÏ¥éþÿûè}w ÿá¿ðÿzô?!§hMåBFy P›à¢ñZA-‚j-"üßWFÌÿOþƒrþoHzü·ýý¿ÇÿéþÿOüÌß¼IøÈÿ…ÿ[úö¿Cp5gËÙ#_*&CMÚT×>¼OQr¼ÿog1ÿuüw§óVöÿ!éòÿ*ûÿÒÿc§ýÿ½ïýÍ›…ÿ‡Œð_øíý²ÿQ[ïe_!Y »Òpà]û/^Ÿ¡¡øj…ÿûʈù¯â¿Q“ÿW~ÿ’.ÿ{þ¿óJ-÷;íÿö5ß‘„ÿ‡Œð_ø¿¥ÿgÿk Ù7X§UEˆ¹¤à´OgÒ¿&EïõŒ×|äO¾[èÐÿ…ÿ[úö¿‚S.¥Vú‘)¶¥Ïq0µ} jlÛ\Õ\Ñ{.rþg1ÿuûÿ‰ÿ–”ðDºüïùÿÚþ¿ôÿÚÉÿwË]ø=ò àþ ÿ·ôÿÿ+*,0»½u>¥ NÛѰ1ÉTãAø¿¯Œ˜ÿ:þOþ?yþ?&]þ÷üÿKÿ¯ü?þ?¯ø=áÿ!#üþoéÿÙÿ«É6ijSß–Uv%€r¶T¯3å”-s)(¿ÿï,#濎ÿ'ÿEáÿtùßóÿ5þ/ý¿vòÿýòû_ñVáÿ!#üþ_þ¯œSM”¨Æ`‹-ZûZ*G´^‘cÒ!ËýÿeÄü×ñòÿ8yþ?$]þ÷ü}þOþ¿GúÜ „ÿ‡Œð_ø¿¥ÿgÿ{ÊTbˆème4®º k€3¬I¬=Ó`‚‘ó;ˈù¯ã?N÷ÿÄÿ?$=þ_ìÝÿoü_úÿíäÿ»xñwïþ2Âáÿ–þŸýïäñìAo޵©–B5•bÌBÒÞÇl ñÿì,#濎ÿ4ÿþI—ÿ½ûÿÿKÿÿÅéþÿÓêc%ü?d„ÿÂÿ-ý?ûß]àXÎ~÷åÈ!Wã=œ]£C2*Y×p€ìåüßÎ2bþëø?ùœðHzüwWÙÿ—þÿ‹ÿçÿû6ü²ðÿþ ÿ·ôÿì¬|0)Fà}¡XÙ:L”tˆÊå`+ʈÂÿ}eÈü×óŸ@~ÿ’.ÿûûÿ¹¥ÿÇMûÿß?û¡ ÿá¿ðKÿ_ñ¿šXbq%6ÎcΔ¬×¡*gMûtÐDÁr4Âÿ}eÄüWñßžüHâÿ’.ÿûþ¿sKÿ¯›öÿ¾ó—Þ-ü?d„ÿÂÿ ý¯gÿ+'2ž4Ú¶ûa€`³Âœ˜«*)k”®1³œÿß[FÌÿõtÿ_žÿI—ÿ=ÿßyýÿ“'þ?õuüIáÿ!#üþ_þ/*Ví4ÙäÛÂÆf(¤*¡£È”jëaþï+#濎ÿ'ÿ#ü‘.ÿûþ¿ÿ'ÿßë^y»¼ÿç˜þ ÿ·ôÿìçJ¶¦èM±žª+à2Y„‹¶!Ùj 3%-þŸeÄü×ñßNçÿ„ÿCÒåßÿçÿ“ÿ﹟xüAáÿ!#üþoéÿÙÿ^œ‰Þµ×\”Ê!@Òì‹fhë?úÆ…³_…«þï+#濎ÿpòÿüþ?$]þ÷ý°ôÿ»Éÿ÷‰çÜñáÿ!#üþoéÿÙÿ®Ï÷阔s ”©¹bÌÛNH–ÖQ…b„ÿ;ˈù¯ãÿÉÿÂÿéò¿ïÿƒ¥ÿßMþ¿{þüSþ2Âáÿ–þŸý¯XUv!ùT\¡DíMÃýÙa°6J]4øZ3W9ÿ¿³Œ˜ÿµð_ ÿ‡¤ÇÿGú÷ÿaéÿu“ÿï¶_ñýÂÿCFø/üßÒÿ³ÿÕé䬅bKmIAtª} 2×bUˆªu•ó;ˈù¯ãÿäÿÓ$ü‘.ÿû÷ÿaéÿ}dºÿó¥—=SøÈÿ…ÿ[úö¿‚5:8´®¤jŠ¥*|õìŒÎùì#5“N²ÿï,#濎ÿ'ÿ5âÿ’ÿ/©«ìÿKÿï#Óýÿßø•ß)ÂÿCFø/ü¿ýïLËd¨Õ~qYEëB Y;ÄF™Òß9-þ¿eÄüWñNþ£ðDºü¿Êþ¿àû¦pâÿ·¿á/…ÿ‡Œð_ø¿¥ÿgÿ{ˆ`#8¦"´¨¼kP>f69“15¢<ÿßYFÌÿOþ£äùÿtùß÷ÿÁÂÿß¾)œøÿøå< ü?d„ÿÂÿ-ý?ûßOXµ6b \ka‹¾fP`Ñ í¸XyÿïÎ2bþëøòÿ ìÿcÒåßÿ÷ðÂÿÓ¾)œøÿÎOýÇ%áÿ!#üþoéÿÙÿnPéZ«K9VeR-NG`VÐ`PUø¿¯ ™ÿ*þÛéý¿Zø?"]þ÷ý/ü?í›Â‰ÿ÷}çþHøÈÿ…ÿúßÌþW8¦€ŠCælœ3Aå•mÁÐv¢†“Iø¿¯Œ˜ÿ:þÃÄñÿ I—ÿ}ÿŸéìÿ“ÿïÏ~ÿ3Ÿþ2Âáÿ–þŸý¯è9ur6¢#Ÿrnë_ 9inÕŽÑ€ÖÂÿeÄü¯ÿèä÷ÿ!éò¿ïÿ3ýòÿ}ÿÍôwÂÿCFø/üßÒÿ³ÿ5º`Jʶº+F2Æ{εò©¢fk,¶Ï‰ÿg1ÿuü?ùåþßtùß÷ÿ™…ÿ·}S8ñÿ–ÿ|â^áÿ!#üþoéÿÙÿmÌÈV;«s¬©šd¢Šœj …Yg¥RbyÿïÎ2bþëøòÿ ˆÿoHzü?׿ÿoþßöMáÄÿo~êÒ—…ÿ‡Œð_ø=úŸ ’ŒÊëÄRa6ÚV­ ‘Ñúì'ëÈþ¿³Œ˜ÿ:þOþ+ûÿtùß¿ÿßáÿ¹éþÿ¿í/Þ#ü?d„ÿÂÿ-ýWÞÿZœ¯!CQìÚŸ”±kÕµª`8FhýnåþÿÎ2bþ«øJžÿLÿp•ýáÿoßNüÿàëKîÿ3Âáÿ–þŸýï@\Y7Ѓ ¶†¨Ù¸Ö㓳JaU!sIUöÿeÌü×ð_Oïÿ•ûCÒåÿUöÿ…ÿ¿}S8ñ_ß÷™G„ÿ‡Œð_ø¿¥ÿgÿ+å²2Q[C)a²¬¬ÏÕpáfOÄÿ··Œ˜ÿ:þOþþI—ÿ}ÿŸYúaÚÿŸxéÝoþ2Âáÿ–þŸý¯¨“·=TC. 0CpÂÙ©î¢ë…ÿûʈù_ÿµBáÿˆtùß÷ÿ™¥ÿ&ÿßýŸ}âÃÂÿCFø/üßÒÿÿïEÄTbÛQ‘6¦Vå¹Vð‰½ÞùXÛB(üßWFÌÿ'ÿÈïÿCÒåßÿwaéÿÉÿ÷æOßý!áÿ!#üþoéÿÙÿª!)p)„Ú@`"E•}*>d¶:ía Ú8áÿ¾2bþëøòÿXÿÏtùß÷ÿ]Xú`òÿýí«ÿ—½s ý-+ëøÐ ¢á€Õ4!IEÉX¸ÖsY ƒÊH!3ðRàºZ††VCAt#Pp^ £Ñ…†´T<3œ™L`P)uè]tzQiƒV† ‚ÉÔúïí>Èìu}öa±7<ßáü™óûÿæÕ3<Ÿß³ëù¬ßùfáÿ)#üþ_þŽ‚ÉÚïÊ…>›ˆÅ—šUN™(’acdáÿ±2¢þÛø?ûÄÿ?&]þ÷ý=þÏþ¿¿yÉRøÊÿ…ÿ;ú?.þwŒ1»ö#pI¡X !{Õ^ \Ú[k±…¢®QÎÿ,#ê¿ÿæu±1"þÿ!éò¿ïÿ3çÿ³ÿïõÿôÓ—…ÿ§Œð_ø¿§ÿ/þwgXyÅ®\<óõèQŠP §±‚÷ž°uùþÿ`QÿmüŸü? ßÿIÿ—ûûÿ¦3ÿÏþ¿ü±ÛþVøÊÿ…ÿ{úÿÿ{,Á*ã\Ž­vÚ«L¤‹còÖqû’uÅ$9ÿ°Œ¨ÿ&þ›ÉÿƒJ¾ÿ’.ÿûûÿfíÿ¿<ïÿÿ ßüjáÿ)#üþïéÿWüïÆšÂ EåŠn¼OÖ”èÉs2Á™„ „ÿÇʈú_ÿY‹ÿH:üGu•ùíÿ½<ïÿßöòwß(ü?e„ÿÂÿ=ýñ¿FW9)ÆÚêÉ.ibòŽ0‡‹0FU"%yþ°Œ¨ÿ6þOþ?Ò2ÿI—ÿW™ÿWþßöIaâú©7=.ü?e„ÿÂÿ=ýñ¿º ±T.ÁGŠ• ÞDLÆ%%_¹´ß ÿ•õ߯ù`ºüïûÿÌÊÿÛ>)Lüÿò?¾÷áÿ)#üþ_þ*G£É$pì*|"ÝZG µD`‚ÄÂÿceDý·ñòÿh+ûCÒåßÿ×ãÿìÿsÜô«ÂÿSFø/üßÓÿÿ{-Ñ[US¢0–š.`ÐÞ1Ç£õ’•ý¿ƒeDý·ñòÿX°Âÿéò¿ïÿ3+ÿû¤0ñÿ'~ñ©¿"ü?e„ÿÂÿ=ýñ¿WÍŠ[÷'V6ª„Z©T|(¶¢O­Ûg]´ìÿ-#ê¿ÿ“ÿ§ýß"ü‘.ÿûþ?³òÿ·O ÿo|ô±‡„ÿ§Œð_ø¿§ÿ/þw•©:[_Á&WRT µ²SÀ6Çì<±‰¶Ê÷ÿˈúoã¿™øÏrÿÏtùß÷ÿ=°òÿ´O ÿï¾ãÓ¿+ü?e„ÿÂÿ=ýñ¿BqÎ×h³ŽÕfïmûÑÞX¢ þcÖ©¢ðÿXQÿkà?Ëþÿ˜tùß÷ÿ=°òÿ´O ÿ„×}LøÊÿ…ÿ;ú?-þ׸:CÕSjª #gÌÊ·ß%Ì9ådåþŸƒeDý·ñòÿ ÿ‡¤ÇÿKýýÝ™ÿgÿßÿØ£?$ü?e„ÿÂÿ=ýñ¿†âL*¢jÀcKI`kÐ)Ɔáÿ±2¢þ›øo'ÿYáÿtùßßÿ×ëùÿÒ¼ÿÿ™·þ߇„ÿ§Œð_ø=ú?`B ¾–P£¡ÀÅæàbªä3ª„LÑke@¾ÿ?X†ÔÿõtÿFáÿˆôøOW™ÿ;üŸ÷ÿ?ÿ´'¿VøÊÿ…ÿ{ú?\Ùÿ¾¸í%aPEƒŒ ­)–²¯h]pŠ\®^ø¬Œ¨ÿ6þOþ”ý¿1éòÿ*óÿÊÿß>)Lüꇞõ*áÿ)#üþïéÿ‹ÿ½Tç£wž\½P¿E"er0%´?Ö˜ 9²ðÿXQÿmüŸü?¤„ÿCÒåßÿ§WþÿöIaâÿ;àñÛ…ÿ§Œð_ø¿§ÿ/þwŽ]@45’Ð6±õTT@¥ jáÿ±2¢þÛøOâÿ˜.ÿûþ?½öÿÓìÿ{ãOÞõ$áÿ)#üþïéÿ‹ÿU‘q5©TuÊ¡ ÈÕ'›2hë9°–çÿˈúoãÿäÿa#ü’.ÿûþ?½öÿÒìÿ{Ã_|êfáÿ)#üþïéÿæÊýïIûZ AñµjŒŠ"úâFe5¸³ª%‹ÿÿ`Qÿkà¿Qâÿ’.ÿûþ?½öÿÒìÿ{ñíù’ðÿ”þ ÿ÷ôÿÅÿÊÊqhsSƒ¼ªÖ¸ö/Æz•ÈÆ¢ ú¬ƒœÿ?XFÔÿÍ|ÿÌÿCÒåßÿ§×þ_šý|éƒwÿOá¿ðOÿ_ü¯ÈX4+ëL-*Ô‹Ëà1€KŒJZQ@ ö’ìÿ,#êÿùO_ÇÿÉÿƒ,óÿtùÿDÿß7=å¯xÇ+>r[¾ó³å9ÿþè»þísϹåMÞýw¿ñçëÎoxËÿïÿçŒð_ø=ú¿” “ bÖ„ÙfßuÕ4Š´c9ÿw°Œ¨ÿþƒR³ÿ„ÿ#Òãÿåþþÿ½Oôÿ=é)¿4ñÿ[o}糄ÿçŒð_ø¿§ÿ/þwf "4Æ£¡¢Úo ØâsÈÁ¨b%ü?VFÔÿ󟿎ÿzšÿðHºüïïÿß»öÿ\ž÷ÿýß½í]òà”þ ÿwô^üïK:ǘukß*`Žªx›’ÅÐÆ@pí¯9³ìÿ,#ê¿ÿ“ÿÇÈý¿cÒã?ôç^ûÿ/ÏûÿïþîWþ²ðÿ”þ ÿ÷ôÿ+þW•m𵵊R<ÿG¤Ëÿ¾ÿ×þ_˜çÿ?½õ·Ÿ-ü?e„ÿÂÿ=ýñ¿êP|ˆÁÅê|ªº¶öϦh•0«Xµ.|”ùÿ`QÿmüŸüåþŸ!éò¿ïÿãµÿfÿß〟þŸ2Âáÿžþ¿ø_m€ªMáätö&s‚œ½Ë5ït Eé,ü?VFÔÿyºÿOîÿ“.ÿûþ?^ûaöÿ½ôß÷£ÂÿSFø/ü¿ýŸj¬ÕWÊ5g‹Êf“u©`ÛX´Ë‘¢µµøÿ–õ߯3ñ…ÿCÒåßÿ×ãÿìÿ{ë_¿èéÂÿSFø/üßÓÿÿûÅ-/… xÒŽ*aÌÁåHgò•]Ñ*:cdÿïhQÿmü·âÿ˜.ÿûþ?^ûÿaöÿÝbÞ®„ÿ§Œð_ø¿§ÿ/þ÷T‚)Õ¢F`vV'çkàà/`”Çb‚&­ðÿXQÿMüדÿ‡X ÿG¤Ëÿ'úÿ¾ÆÿµÿþeâÿsÿùŠðÿ”þ ÿ÷ôÿ+þw$öè#8(!³/)¨‚¥W=…*5ë çÿ–õ߯ÿÉÿÃÈÂÿéñÿ¾«ìÿ¯ýÿð¹‰ÿß÷à3nþŸ2ÂáÿžþÅÿê5ðE±7àO!¥6ù±¯Æ¦œ-Ì’ìÿ,#ê ü’çÿCÒåÿÿþµÿç¾yÿÿ¦¯<ö˜ðÿ”þ ÿ÷ôÿÅÿšZƒ² Ú'g8%v®x0&*c4Zg ˆÿï`QÿmüŸühðDzü7ýùÿþµÿ羯íÿææOÿOá¿ðÿÚû¿W‹ÿµXΫ ‘·7`®Ù›Ø&À ä#¦`¢ðÿXQÿmüŸü?„âÿ’.ÿ»ó?©õüoæùÿ-¿ñ%ü?e„ÿÂÿëÑÿ¯Î„—ÖÇ9AL6jG ÎG“ƒõÎËùÿƒeDý·ñòÿìÿI—ÿ]ÿ_—ÿóüÿ{ïÿ¯Û…ÿ§Œð_ø¿§ÿ/þw,&›îâŒl¿ˆ¼Ë\­ INÆS0ÕÊùÿƒeDý·ñŸ§órÿϘtùßõÿ‘Z?ÿ7³ÿïá§½òyÂÿSFø/üßÓÿÿ{¢ÎòVUô”zÎP”M˜’.öÁ…ÿÇʈúoã¿™æ+ûCÒå×ÿGjíÿ7³ÿï>ü²ç ÿOá¿ðOÿ_üA›ø²]mÑ.Ú†ލ²†à WðQÎÿ,#ê¿ÿ“ÿ§Gø?"]þwý¤Öþ3ûÿ>ÿ¼÷¼MøÊÿ…ÿ{úÿâmuK&8TD¬u)UE_ “J”ZI)'ü?VFÔÿaòÿ€øǤËÿ®ÿÔÚÿkfÿß'Þðž;„ÿ§Œð_ø¿§ÿ/þW[}"¢/ž ×ZÀå¤ pΦ¤bÊ­ÌN ÿ•õ¿þ7´ÿG¤Ëÿ®ÿÔÚÿkfÿß]=óaáÿ)#üþïéÿ‹ÿÕkŒX«× %» ‘cˆ¼1¾ÔìlÉ ÌP…ÿÇʈúoãÿìÿÓÂÿ!éñÿîþ?©µÿ×Ìþ¿/ÞýìÿOá¿ðOÿ_ü¯ÉFòBPlbï8”|áþwÁåà++[­ø–õ߯ÿÙÿ£Aø?"]þ_eÿíÿ}`ÞÿÿôË^ðÃÂÿSFø/ü¿ýœQ¥TB²»jTÊÛk¬“ µ½ÏÊùÿƒeDý·ñòÿX™ÿǤÇ}•ù¿Ãÿyÿÿ«_þ– ÿOá¿ðOÿ_üïº$P–É×þªõŽ˜ ‚Ê{mk“ðÿXQÿmüŸü?ÊÊù¿!éò¿?ÿ_Zûô<ÿ?þ¥¯|\øÊÿ…ÿ{ú¿¿Òÿ]ªÀÉzO1Qù‹5 û>’bˆÞˆNîÿ;XFÔÿy¾ÿWžÿI—ÿ}ÿߥµÿGÏóÿënÿÞÿþŸ2ÂáÿŽþ¯ÿ«ErºÍm¾$6Šc0 œ[óÐöâ –¢°ÿ•õ߯ÿÉÿ£Aîÿ’.ÿûþ?êÌÿ³ÿï“ÿiïþŸ2Âáÿžþ¿ø_ÉFS{½Jà|rh²Íà4kC¹MƒÎ ÿ•õ¿þƒ‘û‡¤Ëÿ¾ÿ:óÿìÿ{øoþMáÿ)#üþïéÿ‹ÿµ$[”ÕX¨$¥­5¦Ø\ ‹•¢3Ú.áÿ±2¢þÛøoçûÿäüßtùß÷ÿÑÚÿ«gÿßÿüÃG¿GøÊÿ…ÿ{úÿâ­Éb&CÉYh j²9.\.öþ´ÑÉsDáÿÁ2¢þ›ø“ÿ ÿG¤Ëÿ¾ÿÖþ_=ûÿ^óÒï¼QøÊÿ…ÿ×£ÿg5]~¬S*@aVù¢qÔš’3ÄF«Häþ¿ƒeDý·ñòÿ Êù¿!éò¿ïÿëñöÿ½ÿå—îþŸ2Âáÿžþ¿øß @Mìrä’ÉŪLuÞA›KT™lMDœÜÿs° ©ÿ&þÃìÿþIÿ÷ö÷ÿiíÿ׳ÿïÛï¼ù³ÂÿSFø/üßÓÿÿ;*Ÿת)ïY«ì )çK@S®¨M2âÿ;XFÔÿ'ÿ+9ÿ?$]þ÷÷ÿiíÿ¿wÞÿþÏÜ„ÿ§Œð_ø¿§ÿ/þ÷ª1µ¢·:Ù«¦ZÀ»d°´9ЂN¥ý;ËùÿƒeDý·ñòÿ0 ÿ‡¤Ç¾Êü¿öÿß;ïÿ?¦þì%ÂÿSFø/üßÓÿÿk 1º” ä#;ϳµXç šâÚC,ûÿˈú_ ÿåþß1éòÿ*óÿÚÿËóüÿëÿèk…ÿ§Œð_ø¿§ÿ/þWåÁU Ñ’ãlh´V™¢cÌÎùHø°Œ¨ÿ6þOþ?вÿ?$]þ÷ý—×þžçÿ½ü…þŸ2Âáÿžþ¿ø_ƒð–J`ƒ¬S¸x¬89°.Y¯2æµÔ,ü?VFÔÿ'ÿ™ÿ‡¤Ëÿ¾ÿïòÚÿóÿïÃßöª× ÿOá¿ðÿzôL>úìÚÐG 2äl+‡‚m̾A¡Æê¢ðÿXQÿmüŸü? Jø?"]þ÷ý=þÏþ?zñ“ÿ@øÊÿ…ÿ;ú?,þw—6¼›Z;&t:iгE`ŽÞfÛÆÂ$ûÿˈúoâ?)ñÿL—ÿ}ÿtžÿÏþ¿ú‘‡„ÿ§Œð_ø¿§ÿ/þw‡RÆdlªE%dp\R$_«. \K{ƒìÿ,#ê¿ÿ“ÿ‡åùÿ˜tùß÷ÿAgþŸýw¾ð÷¿ ü?e„ÿÂÿ=ýñ¿k‡®–”`U¤r„Ú^®Œ¨«v‰U*9iMÂÿceDý·ñöÿ-ü‘.ÿûþ?XûÿyöÿýÉ{_ó—ÂÿSFø/üßÓÿÿkT>j`ÙÙ£Á’«s„ÖÚl.@èÁx¬ÂÿceDý¯ÿÄòýÿôøÿÖþ_žý~ïw}DøÊÿ…ÿ{úÿâMNgí %íA3êDÖh¹ ‚ÐÚzIQ£wA ÿ•õ߯œ¿ÿÿïtùßßÿ‡µÿ÷þyÿßÞó©_þŸ2Âáÿžþ¿ø_SÆ@YS„\³#‹&kU¸†BP,RõdåþŸ£eDý·ñòÿ’çÿCÒã?^eþ_ûïŸ÷ÿ_ïy»ðÿ”þ ÿ¯Gÿ×Vk´¨s ­«çâQeÔ¡¨ ÁøöC«IÎÿ,#ê¿ÿ³ÿ‡äüßtù•ùÍœçÿ‚/Þ*ü?e„ÿÂÿ=ýñ¿;N6^ÜöF¾äèb1&¤öÃÙä#$]°($„ÿÇʈúoãÿäÿ1(þÿ!éò¿ïÿƒµÿçùÿÁ¯æçþ?{gú[VàÆF´I%Å3äÐÅ0ÔÐǬõ¾ë]ïZs£c5 VD4ësP, „2û I#)²±tFJ/:sæ?ÔË`è0ÑE9j8eŽd#eíßÞ탰×Áö{ÃûxwÆ»Þg¯ß¯g‹ÿ‰ø_ü¿eÿÏýw[ÜpÊ÷ºjÀœ‹×‰•þ‹²ƒòð&C6Kÿoô˜ÿ:ÿóôþŸœÿ»Ðô»ÿËþ?Ný¿ßÍoÿñ¿øËþwW÷ …t-¶QË5XÑ@ÔhlAç¢üþ¿3zÌ•ÿIM÷ÿäý¿.4ýßîÿ]ZöpêÿýÚç‹ÿ‰ø_ü¿eÿÏýW{úî;±áª\ ÃñM{oµ«:%WT±UÏÁñÿ¾è1ÿsøÿt PüߦÿÛý¿KËþNý¿?ñ®‡Äÿ‡Dü/þß°ÿqî¿‚&•uáÄ©@IXÁyk‹6GTXlÔ±zUÅÿ;£ËüWùìÿùþošþo÷ÿlãü?õÿÞÿO?&þ?$âñÿ–ý?÷_Md –\@a¦ZdÔ˜#äâˆBJdÅÿû¢Çü×ùêÿ°ôºÐô»ÿgçÿ©ÿ÷ù¿¼÷ËâÿC"þÿoÙÿsÿ5cÑ*j]Öç[6±:çµU©T«89ñÿ¾è1ÿuþû?¤¬ø¿-ÿ?Ò¾ÿo—ý_œúïø½ò€øÿˆÿÅÿ×cÿkBòÿ«Bñú‹:)b&Œ.¡ñÿÎè1ÿuþû?ˆÒÿéBÓÿíûÿ ÿ?2Ýÿ¿ó‹?ùâÿC"þÿoÙÿsÿ]•4§ª‰sÄ Ù˜Aý¦‚Ò•ÙÙ’JÕ^ü¿/zÌÿ§þÉ÷»Ðò?_ãü¿ìÿ?2Ýÿû•·=.þ?$âñÿ–ý?÷ß!”h’÷j¶»õÁ%4®ºPJ²¨Äÿû¢Çü×ùìÿ –÷ÿºÐôÿ5ÎÿËþ?OçÿËÿæžÿñ¿øËþŸû¯´3¨¨ú¤:Ÿ|±ÁcœI©Æš•N>éÿíŒó_çžü/÷ÿºÐô»ÿg—ý_žÎÿ·¿éé/‰ÿ‰ø_ü¿eÿÏýW•brºTƒÚ[2dìpîWSt±ª`‰9ùýgô˜ÿ9ü,çÿ.4ýßîÿÙeÿ—§þßKó–?ÿñ¿øËþŸû¯©¤jˆK *A!¬Ã>׺j†”ˆb_#ë ßÿÛ=æ¿ÊÿVMßÿ“óšþo÷ÿì²ÿËSÿïë_÷ãÿñ¿øËþŸû¯I»Ó—_½ µ(ŒÙísuc² ¼-.cà*÷ÿwFù¯óÿØÿa’÷ÿ»Ðô»ÿ÷Áeÿ‡§þß|Óñÿ!ÿ‹ÿ¯Çþ¯F{Î1™Šl3§aõ.‘M†HQ{ T£WÒÿÛ=æ¿Îÿcÿ‡•üþß…¦ÿÛý¿–ÿ§þß=øÀ{Äÿ‡Dü/þß²ÿçþ;g³K.ë@\lÐÊ›˜‡cܰÉm@È ¹¨ þß=æ¿Îÿcÿǹÿ×…¦ÿÛý¿.û<õÿnþ­[?#þ?$âñÿ†ýo®öß«m G}¥‚K€|Ê&’KŠkò¥SUú?;£ËüWùêÿéÿv¡åÿËíûÿºqþŸúwüÃ{¿QüHÄÿâÿ-ûî¿#•RNÅpzÕ¯žþŦb2']‹Á‡Yü¿/zÌÿÇþµÒÿíBÓÿíûÿzyþ¿<Ýÿÿº;ýñÿ!ÿ‹ÿ·ìÿ¹ÿ|D¨®ècaƒe˜bq1s…¢'r¡ ¼ÿ·3zÌÿ\þ—óþD]ãü¿ìÿ^žîÿßÿÏoøWñÿ!ÿ‹ÿ·ìÿ«ýרIË?Y¬Æ9U2Áy…Épf« ÆVñÿ¾è1ÿuþŸúFÞÿïBÓÿ×8ÿ/ú¿Ã“Âèÿ¿ûÚ·>!þ?$âñÿ–ý?÷_ÉU±Z®^å1¢#R:8 Þ+ÊHÿgoô˜ÿ:ÿóôþŸ¼ÿß…¦ÿÛý?½èÿO £ÿÿóGß*ýÿc"þÿ_ýŸ‘Kí(É« J"b¨6)ÅnueñÿÎè1ÿUþg5ù_ú?]hú¿ÝÿkùêÿñÝö:ñÿ!ÿ‹ÿ·ìÿ¹ÿžc€ÌÎ%J%²C è“3AaÆZq°@ÿï‹ó_çÿ±ÿcIÎÿ]hú¿ÝÿÓ‹þÿð¤0úÿåœ~QüHÄÿâÿ-ûî¿ûèu4kÊ)z®.h*&2ecÉ–0¨¢®rþß=æ¿ÎÿcÿÇjyÿ¿ Mÿ·ûzÑÿžFÿ¿ _yJüHÄÿâÿ-ûö¹8Äd Õ±§<[§²÷9DŽÅ°¶‰œÿwFù¯óÿØÿ!Câÿ4ýßîÿéEÿxRýÿ»Ÿ{Ñÿˆÿ‰ø_ü¿eÿ_í¿j FQ¨*ÇZ°rA—’Ó*dBω¼5AÎÿ;£Çü×ùìÿ0Èïÿ]hú¿Ýÿ{xÑÿžFÿ?þÑükñÿ!ÿ‹ÿ·ìÿ«ý×R­W‘•',ƒ J¬6ã“‚äµÍà]¢Œø_ô˜ÿ9üOâÿ>´ü±}ÿÿáEÿgxRýÿçïQ$þ?$âñÿ†ýOsÿ5g FÛêtÆá ¦úª­%§Oé¿ì¢³rÿgô˜ÿ:ÿýM(þïAÓÿíûÿ´<ÿ_œîÿ_¸ïW_*þ?$âñÿ–ý?÷_sµUuÞ(oX9Ð\-ÒrÑÃy0DÈÒÿÝ=æ¿ÎÿcÿGyÿ¯ -ÿ›öùŸ–çÿ‹Óýÿ³7ß§øÿˆÿÅÿ×cÿ§­©Qy]ƒŠ)äü©ý–PÃ!P:}.Nü¿/zÌÿÇþ³|ÿ¯ Mÿ_ãü¿ô¿™Îÿ¸õæO‰ÿ‰ø_ü¿eÿÏý÷¬+W´¨SŽ jÔŽ¼¯§ûßΓN÷ÿåû¿;£ÏüÿÿþG5ö¤ÿÛ…¦ÿÛý?Zôÿ‡'…Ñÿ÷~æWäý¿c"þÿoÙÿsÿ5ÔáŸÒ°,x8ìg(!k한OJʼnÿwFù¯óÿØÿQ(çÿ.4ýßîÿѲÿo¦þßó_i~GüHÄÿâÿ-ûî¿:Ì:Væ˜5‘1*…h²6’·”CŠ=øRÄÿû¢Çü×ù¦ó¿|ÿ¯ Mÿ·û´ìÿš©ÿ÷¾û?ð˜øÿˆÿÅÿ[öÿÜÕ–Ý ùâ¢ÑT;£r´^Ec%ÒZü¿/zÌÿþþOšþo÷ÿhÙÿ5SÿïsŸ~õMâÿC"þÿoÙÿsÿU‡½ÂÁcQYkm}4l@[c*VrÀ):'þß=æ¿ÎÿcÿÏ€œÿ»Ðô»ÿGËþ¯™ú7ßþ‰Wˆÿ‰ø_ü¿eÿÏýWÎ.û”†¥ª¬wæônL¾hg+é’!%gƒÿï‹ó_çÿ±ÿƒ ßÿëBÓÿíþ-û¿fêÿÝóË?õKâÿC"þÿ_ýѱ19hÏTcÄÓÎÖ’ £³…0£•û;£Çü×ùìÿ •óZþ?»Æýÿ†ÿ§þß•»^òYñÿ!ÿ‹ÿ·ìÿ¹ÿN˜‚EïÙëÀ%BöÃAbr&¡&or‘ßÿwFù¯óÿØÿAÿw¡éÿöýÿG—ý¿³éþÿ¿?ç™ç‹ÿ‰ø_ü¿eÿÏýw* xD9`•J£ÀÕD18—¢vQ~ÿß=æ¿Îÿ<õÿÅÿ]høŸUûüÿè²ÿs6Ýÿÿ†»^þ¨øÿˆÿÅÿçÞÿ§Í>÷ßXeƒ)M.sIAùÂÅE§ -ذTþÿÎè1ÿUþ×cÿ‡äþ_šþoÿ‡Y/ÎÿÓÂèÿçýØí¯ÿñ¿øËþŸû¯Hl=šD•­&’g•L%Ç`ŠVÑ8­,f¹ÿ·3zÌÿþ—þ'šþoõÿ†Y/ÎÿÓÂèÿß¾òßß/þ?$âñÿ–ý?÷_+ƒuÎ["}à`Q5~Øý<œQEG´ÿïŒó_çÿ©ÿgåýÿ.4ýßêÿ ³^ô‡'…Ñÿú^&þ?$âñÿ–ý?÷_‹öû’¼g¢¤£K™bb«TePŸÞ —þßÎè1ÿuþÿ¿þŸ|ÿ· Mÿ·úìýßáIaôÿG>þÊŠÿ‰ø_ü=ö?rNÁ#{wúÛmQ>P( *ؤ2êaåÇXø_ô˜ÿ:ÿ£ø¿#Mÿ·úmÿOý¿ûÿþÁ׈ÿ‰ø_ü¿eÿÏý÷¨LrÙxW ø¢uJù?šT ÚhOŸLì¢ø_ô˜ÿ:ÿýÖ,þïAÓÿ­þß0ëEÿxRýÿªËÞ-þ?$âñÿ–ý?÷ßÁ£c®ì}ö¸'dÎ:…è¬óÅ•Ä(™,þß=æ¿ÎÿSÿ‡Åÿ]hú¿Õÿf½èÿO £ÿo¹ð’Äÿ‡Dü/þß²ÿçþ»‹õ©_B5UÙP0h¤@dœõ^©ZµCñÿ¾è1ÿuþû?FË÷»ÐòÿÅÖýÿaŠ‹þÿð¤0úÿç¿ó[^+þ?$âñÿ–ý?÷_5™}‚”ªOÚêXc ÑSRÞ¨yðôÿvFùŸÃÿDòþšþ¿ÆýÿEÿwxRýï¯ëÿñ¿øËþŸû¯‰BtÉxkœ±)8W#¡s:z¬:y4ÞSóÿÎè1ÿ¯îü ÿóôû¿ø¿ -ÿ›Öùÿ¹—âø¾g.]øÂþêóÏ\xÁ‡Þøø ¿íCgwÿÅ ÿußmûñ¿øËþŸû¯E™¸*Få’d«×ƒ¬É!Å¢-8M‰cÿï‹ó_uþ‡©ÿ§äýÿ.4ýß>ÿ_\öÌtþãÞóNy8$âñÿõØÿÀ`•­ÚdëU$ârº>YíOÿ³Ñ–þÿÎè1ÿuþû? ¤ÿ×…¦ÿÛý¿–ÿ§þßϼý7îÿñ¿øÃþ×êêû_zXéÁâpØä™ ÅÀÊ™b•¯%FÌÉ&#÷ÿvFù¯óÿØÿÿw¡éÿvÿÏ,ûÿfêÿ=qË»¿UüHÄÿâÿ-ûî¿;GÊê’°î©"g}D“òƒ e{éÿîŒó_çÿ©ÿcäïÿ]hú¿Ýÿ3óÿÔÿ{üSO½BüHÄÿâÿ-û5A,^Ê2eçl*ˆK­~XðÅ|ÿogô˜ÿW÷ÿW¼ÿcÿ‡¤ÿ߇¦ÿ[ý¿ç¾úá›^öЛþ榟ûÒkŸ}ö¦·Ü÷á§ßòÍ÷=yëg¿æ¿ýõïûñ¿øËþŸû¯DP\ÁRS6Ñ[(Ö[kŠñ‘MÉDd’ÒÅIÿggô˜ÿºóÿØÿ1$÷ÿ»Ðô»ÿg–ý_3õÿ~áÁKÉÀ!ÿ‹ÿ·ìÿ¹ÿ"jÏÑ ’±dðŽ#y Yg´•ÐfÅâÿ}Ñcþçð?‚ôÿºÐô»ÿg–ý_3õÿÞñ·O~LüHÄÿâÿ-ûî¿úD®ÏBq ª3&b®`lqkÌ1PA%ßÿÙ=æ¿ÎÿSÿåüß…–ÿÏÚý?³ìÿš©ÿ÷®O<ô§âÿC"þÿoÙÿsÿ5F›R‚T)Çl-þ \ž*pXì`ðò÷ÿÑcþëü?ö˜Iü߃¦ÿÛ÷ÿͲÿ{6Ýÿÿäw?ûâÿC"þÿ_ý%WEôpî‹mÎ5',U­BÁH&„$ýŸÑcþ«ücÿÇÊûÿ}hù®qþoøºÿÇï¼MüHÄÿâÿ-ûî¿g>8}¼j¢‹+a#¤ÄHMÒ.{¨^ü¿/zÌÿÇþ¢ø¿ Mÿ_ãü¿ìÿÃtþ¿òÔ'¿GüHÄÿâÿ-ûî¿{­‹o} ’±ºì8ÌÕêb¡µ…4¤(ïÿíŒó_ç˜Þÿÿw¡éÿvÿïlÙÿéüÿ½ïûâsÄÿ‡Dü/þß²ÿçþk®ŠƒöÃpøãSø5£õsLÎ’u©[\Mâÿ}Ñcþëü?öåïÿ]hú¿Ýÿ;[ö`êÿ½øÆ»_%þ?$âñÿ†ýsÿU1:H§ÂOV™šmµHÀ¥: ÙEËJÞÿÛ=æÿOâÿ4ýßîÿAãü?õÿ~úËvQüHÄÿâÿ-û˜¡¸8E1YpjR:i,F¶d\òÒÿß=æ¿ÎÿFîÿu¤éÿVÿo˜uãüÿéÑÿwýìwÝ(þ?$âñÿ–ý?÷_É©˜P‡ØSðE…T b¥•ΨŒ/L•ä÷ÿÑcþëüO“ÿ•ø¿Mÿ·ûð¶¥ÿ§þßÇ>|E‹ÿ‰ø_ü=öd0Öd¥KIÌd“U*`§¡0{m C âÿ}ÑcþëüoåýÿŽ4ýßîÿµü?õÿ^ôØ›ÿñ¿øËþ¿Ú¯9梜O !ëb½r®fÀ\‘­¡çBùýgô˜ÿ:ÿý«Äÿ]hùÿRûþ?,ûÿ0õÿž÷ÞÿIüHÄÿâÿ-ûî¿ûšrð¹ž>Ýž’ö¤0˜šj­¬³ ¾†0Lø_ô˜ÿ*ÿ5½ÿ/¿ÿw¡éÿÿeï\CwËÊ>Δ„A"¥ aÐ'óB±žÛº4V”] 3•Bƒ\W5¨L‹$#¬¬>‚‚M_R±(LÛ™Ò0$F"±üP¨TPÞ@êCí÷ÝìAÜë ûìÃbox~03gþçœO<¿w½ï»~»ÿ×ýÿæûÿ÷ÝxìÅêÿS¢þWÿïÙÿòøù/À´½ƒxSr¬Ó¾w©4†à!G_Âô·¼õÿ±1ÿmþŸû?zÿ =ÿÛ›œÿ×ýÿæûÿ÷¼å™¯RÿŸõ¿úÏþ_ú¯ž³/}cȱT¢¤Pc• Á:ÊN*E«þ?#æ þÐûCèúÿ&çÿuÿ×ÎçÿO}û7¼TýJÔÿêÿ=ûé¿2:`Šl=4# 2{cSp“ò³eqnúßšœQÿ‹óßæÿkÿõóÿ1týßïÿáºÿkçóÿóßû±_RÿŸõ¿úÏþ_ú¯™›GCžËÙef×Lb¬6TC 8!´¤þ?#æ¿Íÿ×þêóÿÆÐõ¿ÿ÷Àºÿcçþß·þÏ[~ZýJÔÿêÿ=ûé¿2S &¤¨rv?Û8‰ñ¥PŽ¢ŸÿŒóßæž?ÿ×þϺþï÷ÿX÷ìÜÿ»ó‰{úÿ”¨ÿÕÿ·cÿ{°¨Hn¦BÆIúrùý›çhµì)°-êÿc1bþÛü/óùߪÿGÐõ¿ÿ×óÿÜÿû§gðÝêÿS¢þWÿïØÿ´ôßãäwïb4‘S4â#²\¾ œ¡QhÆ%'Úÿ?#æ¿Íÿ×þêóÆÐõ¿ÿg;ïÿÏý¿G~ÿEw©ÿO‰ú_ý¿gÿ/ý÷Øš+ÍÇš23OÿøË[þ-pó¹y‰¦ažIý,FÌ›ÿÝÓ«Šé%€ú]ÿ÷û¶sþŸûÿqÏ—ž§þ?%êõÿžý¿ô_]ŠY¦_A6MuÁ9ÁpùxÅP©VIÚÿ?#æ¿Éÿríÿêù=ÿßèßÿ·ëþ¯û¿ý³=GýJÔÿêÿ=ûé¿"R"Ì5DÛ2Ô\s â ÆèBiR|f¯ýÿ£1bþ·à'êÿ!týß¿ÿo×ýßóýÿw¿ûïQÿŸõ¿úÏþ_ú¯>FÏ`,:ç 5 Ä]$®Æ&_§Ÿ«ÿňùoóÿµÿcXû?Cèùnrþ_÷oÌ÷ÿßõ†gÝ©þ?%êõÿžý¿ô_É„ÄX|½ÜþÂ&R ­°…èÀçc*ÉcPÿ‹óßæÿkÿGôýÿ1tý“óÿºÿ óùÿ=¿÷ì/¨ÿO‰ú_ý;ö?ûÚBa±)ÃtÒG²Þ‘T‘êƒ5d±·¦ˆúÿXŒ˜ÿ6ÿ_û?¤þA×ÿýþ_Ïÿóùÿ}øyýüÿœ¨ÿÕÿ{öÿÒ5•üt곎ªÉ9·X+dž £/®8‰EûcÄü·ùŸ/ßÿ£þB×ÿýþŸ]÷ÿaîÿ½ýGžúkêÿS¢þWÿïÙÿKÿ½ˆÏ•™$!EŸMô©qjQ0Eª„Œ5^ßÿ?#æ¿Íÿ×þCíÿ ¡ëÿ~ÿÏ®ûÿ0÷ÿÞüàK~FýJÔÿêÿ=ûß?þüWS062èC ÀqZý>EöÉ1;²…«Sÿ‹óßæÿkÿG¬ö‡Ðõ¿ÿwcÝÿ¹ÿ÷áG_öúÿ”¨ÿÕÿ{öÿÒm–wù·aWX@BŒÁå4 Ѥ8­|ÕÿÇbÄüoÁÿÀúý¿!týßïÿÝX÷`îÿ½ôGßôVõÿ)Qÿ«ÿwì~¼ÿ ”-¹%R+1\nýU´%Å8ýyß<Û”ÔÿcÄü·ùß]ßÿ7zÿo]ÿ÷ûÐ9ÿÏý?wïG_¬þ?%êõÿžý¿ô_SF¡ê=V‡“rä !XJDŸ[ µÿs0FÌ“ÿíµÿÃÚÿCÏÿ÷÷ïÿCçü?÷ÿ¾çí÷§úÿ”¨ÿÕÿ·cÿK ÆûÖ(R¦Z„³Khjõ&0sƒj£ Úÿ?#æ¿Íÿ×þ;õÿºþïßÿïøÿþùþÿ½ÿõSÿŸõ¿úÏþ_úïÖDrAÄ´ZÅÒRl9—PCMÙÕÒ¦9Ûªþ?#æÿÕýÏ_æ¼>ÿŒú=ÿËúüÿ5OºïîGŸ]Þú™úœÏ}þ?ýÙçÜýÚÏß÷?ùÚWÿæ[ïºã÷}Ó+TÿçDý¯þß³ÿ—þ;ÛBÄ{@o¥kCÎÞz!¨*Díÿóßæÿkÿ¬žÿ‡ÐõÿMÎÿ_ÙÿÿÚ'ÍþÿëW¾þùêÿs¢þWÿïÙÿKÿ³ÉÕÇÜZ¨ˆ®¤Æ>5Š­—B •Åèóÿƈùuÿùûÿ|ýþ¡ú]ÿ÷û°îÿËÜÿû ½þ'ôÀ)Qÿ«ÿ÷ìÿ¥ÿjHBö –â,^w>äé(ÿw]ÿ÷û²îÿÓÜÿûówÜëÔÿ§Dý¯þß³ÿ—þ{-š Tjfl…m–È$â+Ûš²øép(êÿc1bþÛü?÷Ôÿcèú¿ßÿ“uÿŸæþß¿ÜE¿¬þ?%êõÿžý¿ô_)3g¥°q0´ì…R U¸Äè*ÉFûcÄüoÁÿ$¨þAÏÿöïÿ?¼îÿÐÜÿû·ÿà+Ôÿ§Dý¯þß³ÿ—þk‰…B%¬‘¦ÝÝ"G[ciž}28 C)®%§Ïÿ;#æ¿Íÿ×þŸ=ÿ¡ëÿþýÿ‡×ýŸçûÿóŒ?û¬úÿ”¨ÿÕÿ·¾ÿÁ,ý×àX¦F¥Dgsš¤/è)¸P0Õ©2Û¬þ?#æ¿Íÿ×þß$õÿzþwÝó?›õùÿÁùþÿcï¸ûÍêÿS¢þWÿïÙÿKÿ5PH>ÅÜBI6Rm‹3D!3ÕJV ¦¬~ÿÿ`Œ˜ÿ6ÿÏý§÷ÿ†Ðõ÷üÏf}þwóùÿ~êß§þ?%êõÿíØÿ¾ÅiŽ%Ç&—'ÀY¼”`Ù;—8¡EL@.–¤çÿƒ1bþÛü?÷¬žÿ‡Ðõ·ÿ×õÿ|þÿá×=ò*õÿ)Qÿ«ÿ÷ìÿ¥ÿ.54€i‹{tI¢M¦¹T¦£_Ê4ý¾›Z˜~¨þ?#æ¿ÍÿsÿÇhÿ]ÿwûlÖý7÷ÿ^sß ¾[ýJÔÿêÿ=ûé¿c´µ° Þ ´ÂÉ $&F”ì3¶F`|"½ÿw0FÌ›ÿÝüý}ÿ]ÿwûlÖý7÷ÿ~þOz–úÿ”¨ÿÕÿ{öÿÒÍŽ’¿dÛEJ–Ø'¡ZŠ8 9—l!Ålôýÿ£1bþ›ü×þ¨ÿGÐõ·ÿÇfÝÿusÿïm÷|Ç;Õÿ§Dý¯þß³ÿ—þk(HR˜ ›Doj­Ó’Û2ÇÅ¥¨þ?#æ þgõÿºþïöÿجû¿nîÿ=áÿü õÿ)Qÿ«ÿ÷ìÿ¥ÿ<²¹%"ã¶¡Rr”Ûd±èÑ^£þ?#æ¿Íÿ ïÿ¤ëÿnÿͺÿëæþŸ}ù“ÿAýJÔÿêÿ=ûé¿Ibv +¹Ì“ñ›õ>g@ˆ.”+N2Pÿ‹óßæœÏÿêÿ!ôüÿÈMîÿ¯û¿nîÿ}ï½æOÕÿ§Dý¯þ¿ûß›r@ÈØ\r. Áe\óÑO¡ªÿňùoó?ÍŸÿkÿw]ÿßäþÿÚÿÌ÷ÿßôÌ7ü­úÿ”¨ÿÕÿ{öÿÒ/6ãåž_ŠÉ…X-ñT[õ—L™N„¹L[Dý,FÌ›ÿy~þŸ~þ?„Žÿ1ýóÿû×ý¿Gæûÿ¿õãOTýJÔÿêÿ=ûé¿ Xº8 ™ZB޹át"¤œ29ŽÖ¡±>ÿç`Œ˜ÿ6ÿËÜÿgõÿºþïŸÿß¿êÿL¯®þÇ¿úï/ªÿO‰ú_ý¿cÿÃÒ¯¾ÕX’O.‘]Æœ0;þPœÃ$’PïÿóßæÿkÿçòÛêÿtýßïÿñêü?½R¸úÿåwüú¿ªÿO‰ú_ý¿gÿ/ýWΕJeÛ|ަMÞ 4/ ŠGÂ&(ÜôùcÄüoÁÿLVý?‚®ÿûý?îœÿçþß]ïtïRÿŸõ¿úÏþ_ú¯µJm…!cðÙ››ʦã úZcå àŠèùÿ`Œ˜ÿ&ÿãµÿêÿ1týßïÿñªÿ;½R¸úß¿íѧ©ÿO‰ú_ý;ö¿0]>ë•bÑaO¾yÇb!›d‹¹„Šêÿc1bþÛüíÿÑïÿ¡ëÿ~ÿ¯çÿ¹ÿwÏžøwêÿS¢þWÿïÙÿüøç¿Þ&¬ro˜Ü¼§"ÓaÈÍ«þ?#æ¿Íÿ×þŠžÿ‡Ðõ¿ÿÇ«þÿôJáêÿ¿ôçÞ«þ?%êõÿžý¿ôß™[›6xˆ-HL6•¸i§û<ýJrÎX½Wÿ‹óßæÿkÿ‡YÏÿCèùÿýýûÿ¼êÿO¯®þÿä?>åãêÿS¢þWÿïÙÿKÿÙ%¦„Þ^Þü5bƒ¦Íä¨Æ× CPÿŒóßæÿkÿ¬ú]ÿ÷ïÿóªÿ?½R¸úÿí/á÷©ÿO‰ú_ý¿gÿ/ýW2|–†VRñ•›DHÍ!F4Ä•–ƒ-©¨ÿňùoó¿Ìýíÿ¡ç¾ÉùÕÿ^)\ý~õO~EýJÔÿêÿ=ûé¿Ú€ž” Îz®ÅxR+ƒ)’8û¹N‡:Vÿ‹ó¿ÿ#êýÿ!týß?ÿ?´îÿð|þÿË_@¯þ?%êõÿžý¿ô_`ó(­aN©&šM‘§Ý-SÉ.`0¤÷ÿƈùoó¿½Ã\ŠÁúý¿!týßïÿ=´îÿð|þæ¿p·úÿ”¨ÿÕÿ;ö?.ý×D6L œ“›|âAZô­Ö†ŽX¤UF®™¨þ?#æ¿Íÿ×þY}þïºþï÷ÿ°sþŸûO~Ùg?¤þ?%êõÿíØÿµ@±¾dŠÓ ÅZÉ×l¦µÁ&$KÜ(L?Qÿ‹!óßâºö.Rÿ ëÿ~ÿ¯çÿ¹ÿ÷æ'~ð…êÿS¢þWÿïÙÿKÿ=DÛrI²¯%ÆäC…*§µÖ „ dôùcÄü·ùÿÚÿ±zÿ ]ÿ÷ûØyÿîÿ=öÆïÿ’úÿ”¨ÿÕÿ{öÿÒÇ Ô’•’7 fÇ–1I„Ë›ÃMý,FÌ›ÿ¯ý‡êÿ!ü?{çzÙuÕñ : é„ì`û Lk©†îµöÚÿBHbÿ$VCRTŠtÿ…>­´Ð‘¢mim R$E âK¥øÌ0“šJÚúPÐ’¦bÔ ÒlÄ?4ͤj*¶î{wOæì!œ9ÃæX_˜ÉoîÜÌË‚ïç®sÏþœ.ÿûþ?œûÿ©ùÿÌ-ÿð0ó—aþ3ÿ×ôÿäu6¤dª„u<øÛ²‹”bA‡TT™÷ÿeÄü—ñÿèÿ©ÿ2óDºüïûÿpîÿ¥æÿû¥Çßzó—aþ3ÿ×ôÿä‡ßEòIk/•'‘µršBšêV¨0’$’ìÿÝXFÌÿ©ÿ7Ìÿéñÿ|ÿü?Îý¿ÔüùËG˜ÿ» óŸù¿¦ÿÕsßÿ ”ÒCàë#™úK+ã¥ô)äræÿ¶2bþWÀÔ‚ù?"]þ÷ÏÿãÜÿ{¾ÿÿß}ì6æÿ.Ãügþ¯éÿÉÿœ‹9êŠz/ƒÓ*Öí”Iu•Óàc¨’•ìÿÝZFÌÿ…ù/ŸÇÿæÿ#>ÿ7$sþWà÷öÿ“={íË?~÷?^ûžo¾íÙg¯ýÀ[>õä½÷¾åŸÎ|õ¾éÃôßi˜ÿÌÿ5ý?ù_“VÛ,y[²Ú IàðLï­‹ÚBÌÿmeÄü—ñ_ýÿ’Ïÿ I—ÿÏßÿOüÊG>õ…Ÿ¾î#ÇÓxûÅs§ŸyæÑ§/ž>õà;¯?uêÏÏßüùk¾œ¿õÌÿ†ùÏü¿ý¯U¾ÔÎ×Xÿ^JçCÐ*iŸ­/Zd´øúÿÖ2bþ/Ìzÿ›ÿG²ÿwHºüïûÿðRÿÿÉÛßñ¶ßøíï9ñ¥Ûoü;þ°Ï0ÿ™ÿkúò¿—T+L®¨—ÁeOIÆd”/ÑÉúæ,‰¯ÿo,Cæÿ‚üÞ÷ÿtôÿâïÿ‡¤Ëÿ¾ÿïÜ¥þŸ õ“Âñûÿ¾ìW¿Åvæ?óMÿ?ç×Ê[4¥wпÈ,³VæPKÄDå dÅüßVFÌÿþe˜ÿCÒåßÿwîRÿOåóÿ}ì_nü7æÿ.Ãügþ¯è9ù_- 1UÄ[I ‘¼É”ëJh!ŸÿßXFÌÿþ%™ÿCÒåßÿ§;ûóÿ½â.Ÿ™ÿ» óŸù¿¦ÿ'ÿ«'Y²TÊë¬m,é€c &Äbb• 99æÿ¶2bþWÂÁßÿI—ÿ}ÿŸîìÿÍÿwáŸ?ó:æÿ.Ãügþ¯éÿÉÿ V)K1¦¤dô—~)årŠ.…`EQ&)bþo+#濌ÿGÿßAÀü.ÿûþ?}©ÿ·ò¿ùÿ~o} ó—aþ3ÿ×ôÿäÍYÙ"ƒ*˜¬ñA@$5© u@í!x“<_ÿßXFÌÿ‰ý¿Óãÿý}ÿŸ¾Ôÿ[ùßü~ÍkßÎüße˜ÿÌÿ«ÑÿÅÔŽ·™ŒµJGIg †’Ñ•lmiùù?ˈù/ãÿÑÿ# ïÿCÒåßÿ×áÿýÍÿ'n6×1ÿwæ?óMÿOþw1fê F‚ 6ä mJB‚¥ c2QæÿÖ2bþËø¯›ÿŸý?CÒã?]fÿ¿Ôÿ_ùÿÄ‘ÿgþâºïgþï2ÌæÿšþŸüï>+49z‡ÑÖÍ,©„ ‚ŠMB¸â(‰ä"ó[1ÿeüoþÌÿéòÿ2ûÿ¥þÿ õ“‘ÿŸx½ó—aþ3ÿ×ôÿäOT«ÞÚ,Š%G$bð6ú”¬ÕuóOuªBòýˈù/â¿jþÃûÿtùß÷ÿéÏùßöÿ7¿ï/eþï2ÌæÿšþŸü¯è-t¹hòÙø(ȉÅêºJ•1Ë∯ÿo,#æü'>ÿ?&]þ÷ýúRÿoåóÿ½è•·þ,ó—aþ3ÿ×ôÿ䕃+¦8­" Ž_âzãÉÆ˜LŠ ²@Þÿ7–ó_Æÿ£ÿO_ÿ’.ÿûþ¿æþjþ¿—ÿÄ7^Íüße˜ÿÌÿ5ý?ù_Q…hzè”÷ˆ€åà‚ uùA&‚LB$dþo+#濌ÿØîÿãûÿ‡¤Ëÿ¾ÿï¹ÿ‡šÿï®?:õûÌÿ]†ùÏü¿ý/DÝõ*æ)(¯ƒ …ˆ²;<&`)ÚKå5ó[1ÿeü?úPæÿˆtùß÷ÿõøßüw¾ÿ‹?Ïüße˜ÿÌÿýOÏùß}„RI[b‚ºƃí/c]ù©¾ßK]¥€aþo+cæ¿„ÿGÿ&¾þ?$]þ÷ýйþßüòMïçýŸaþ3ÿ×ôÿwýïIXBÒH*£¥¤£‹1äZô.ÄœÍáæ…|ÿ߯2bþËøßü?Šïÿ’ÿÏ÷ÏÿCgÿoþ¿îüæW˜ÿ» óŸù¿¦ÿ'ÿ; D峉& ,Úhã1‘Ähbñ K(˜ÿÛʈù/ãÿÑÿ ™ÿ#Òåÿü?ÌýÿçÛùÿ»ÿößÁüße˜ÿÌÿ5ýÿœÿ=XWW?‘’- ƒ tvíño&C©Ÿ FÁ÷ÿo,#æü'äïÿ‡¤Ç¼Ìþ?÷ÿžoçÿO¿ôï—ù¿Ë0ÿ™ÿkúò¿–Š]L¥ÂY¬?Úäñ}ébÅJíó[1ÿeü?úÿÀðó†¤ËÿËìÿsÿ/¶ýÿNyË™ÿ» óŸù¿¦ÿ'ÿ+i‘t%½Éä½ ±PiacP‹$¬ÌÿmeÄüñ_ý?J0ÿ‡¤Ëÿ¾ÿæþ_lûÿç>ußטÿ» óŸù5úßDÔZ ™¹PÇBÖ䜡֊ ”eÿÏÖ2bþËøôÿ(äûÿ‡¤Ëÿ¾ÿ¯Çÿæÿ»öÓæÌÿ]†ùÏü_Óÿ“ÿ½ˆœ°9„ì1õ§hØBN¢ VcùúÿÆ2bþËø'„¬ïgÿïtùß÷ÿÁÜÿÍÿ÷ž¿ö6æÿ.Ãügþ¯éÿÉÿ^PJÞ“1YÇ À¦R×}²îˆVÊDäËÌÿeÄü—ñÿ;þÍü‘.ÿûþ?˜ûÿ±ùÿàCŸû?æÿ.Ãügþ¯éÿÉÿn±È\$LE°õ5Q_s•þúð<ù¿±Œ˜ÿ2þý?Rðù¿!éò¿ïÿ;;÷ÿ`óÿ}â©ÿø$ó—aþ3ÿ×ô¿û®ÿ¥î|2ƒð&Ö5ПuV±˜X’°N)QBfþo+#æüWšýÿCÒåßÿwvîÿÁæÿ{ê®_øoæÿ.Ãügþ¯è5ù_U°èÚúP@ñ¤´)- ’!g°ÿwc1ÿeüoþ?âûÿ‡¤Çÿsýóÿª³ÿ7ÿß÷ÞýÞ³Ìÿ]†ùÏü_Óÿ“ÿU•¢‚Q9†F˜.SJdS|)ènXöÿo-#濌ÿºÿãýHºüïŸÿWóýÿ\;ÿÿª³÷jæÿ.Ãügþ¯éÿÉÿš³rÂ&¢ºþië Ù&]¬0PJ:Ÿ´ðŽù¿­Œ˜ÿ2þý?Ä÷ÿIÿú2ûÿÜÿ{®ÿòKöeÌÿ]†ùÏü¿ý¬ñFÄì·.$Ì–TVu–¨E]³µÌÿmeÄüñ߈výŸý¿CÒåÿeöÿ9ÿuÛÿŸýÀm1ÿwæ?óMÿOþw(&aA›2´¥Ì6ÆÃµ…DôÖUgþo+#濌ÿÍÿcøþÿ!éò¿ïÿSsÿ¿nûÿÛ_ü1¾ÿoŸaþ3ÿ×ôÿäëb}Y™¤M6’ÐÆË:ÉZõJãc”:òó·–ó_Æ<ð_H~þïtùß÷ÿ©¹ÿ_7ÿßû~ùÛdþï2ÌæÿšþŸü¯9wxįÑIY_"¡HJëM 1©t6ìÿßZFÌÿ ø¯5óHºüïûÿÔÜÿ«›ÿï÷~óÓ÷1ÿwæ?óMÿOþWç”Ñå†"tÐÉÔÿ@Ñir9SÈQjÉüßVFÌÿþ?’üýÿtùß÷ÿ©¹ÿW7ÿßgÞpÝÌÿ]†ùÏü_Óÿ“ÿÕg[·6§‚€ä3í,täUKRio=ó[1ÿeüoþ?Åü’.ÿûþ?5÷ÿêæÿûñGý!æÿ.Ãügþ¯éÿÉÿêjG`ö)¦`PZ¥H—ìKFáhLÞm²Gæÿ¶2bþËøôÿh~þï˜tùß÷ÿ]˜ûtóÿýÚ}5Ìÿ]†ùÏü¿ý‚2¥ºý—sŒI(- ˆ(=BTÙ‡x¸,ÌüßVFÌÿ›ÿ‡ÏÿIÿôÏÿ÷øßüÿØSÊüße˜ÿÌÿ5ý?ùß•S"äDÉ(ç’¯x‰ JVÖyi|6:ÃþÿeÄü—ñÿèÿ‘†÷ÿ!éò¿þÿÂÜÿ÷@;ÿÿðמ|5ó—aþ3ÿ¯¼ÿëÓõ_1{M˜‰²U±([WÂúWÑÔEPÕ×U0¾ÿoc1ÿæ¿|ŽÿJý?‡Û˜ÿÒã?ôöÿ“OãíÏ~æ™GŸ¾xúÔƒï¼þžë<óç¯y⯅é¿Ó0ÿ™ÿkúò¿KŒ"‡¬ ˜Búpæ+G§¼Ô®dk,‘¶"ŠÀÏÿÝXFÌÉþ_?)¯ÿ+öÿ I—ÿÝýÅ|ÿ‡¶ÿÿû-O_ÇŸvæ?óMÿOþ× |Ð.:鬋ÞZã¨Øä£OÖ š(ÆÈüßVFÌÿ ø¯¯ÿI—ÿ]ÿйÿšÿï%ï-–ù¿Ë0ÿ™ÿkúò¿JÞ ÇhJÀlœ‰ ³M†„#kr6Á ìÿßZFÌÿþÉçÿǤËÿ®ÿÅÜÿ Íÿ÷Æù›w3ÿwæ?óMÿOþ×%pŠbT„Ïáð´?ôÂêäEv¹doˆù¿µŒ˜ÿ2þËvÿ¿`þH—ÿ]ÿйÿšÿïÉ“w¼™ù¿Ë0ÿ™ÿW£ÿ-ʤSt`JÊ"U …(‡K¹ŽHä$rÌZ0ÿ·•ó_Æÿ£ÿ‡€ïÿ’.ÿ»þ¿.ÿ›ÿï†ýãÌÿ]†ùÏü_Óÿ“ÿ=><´Å‹ ¬ÊÁ½wY™’ :I1[À8æÿ¶2bþËøôÿ>0ÿ¤Ëÿ®ÿÅÜÿÍÿ÷gò®3Ìÿ]†ùÏü_Óÿ“ÿƒtI%“¬4J¡*=%g i(Þû¤¢µìÿÙXFÌÿþ©ùúÿtùßõÿ¡˜ûÿ¡ùÿ~çuzó—aþ3ÿ×ôÿä'Ð ,æˆu4­À“À"¤£à@ §ñ|ÿÿÆ2bþËøoÚó5óDzü?Ûõÿ¡˜ûÿ¡ùÿ~ëçþëû˜ÿ» óŸù¿¦ÿ'ÿ+yÑ*SœÓV&*•˜S²Pâáa06Ö÷óó6–ó¿þ“âýHºüïŸÿ¿îÿ=ÛÎÿŸ}ë~•ù¿Ë0ÿ™ÿkúò¿BHÉiã  F‹¶.DTAgoëÿ“(˜³äûÿ7–ó_Ä8úÿòþ?$=þ«þþÿÜÿsö;çÿßpñËÌÿ]†ùÏü_Ñÿ0ù_–T”’¥0 ’£º§ ¼N‚¯ÿo,#濌ÿЮÿóýCÒåÿ§ùþ¯ÚþŸï¹á Ìÿ]†ùÏü_Óÿ“ÿUÄ3X²Y Š9å‹K±î„2 TEŠä}àçÿl-#濌ÿxBÈú~Þÿ‡¤Ëÿ¾ÿæû¿jûÿ×O>ñŸÌÿ]†ùÏü¿ý£² j‹+A ³4‰¼E+E]d)QjËçÿ7–ó_Æÿ£ÿ˜ÿcÒåßÿ×ãóÿÝtÍ·3ÿwæ?óMÿOþwïDÒ’p)ˆ þuƒÿ§ øþßþOV›¸&bò¤<—äüe.´Âëb Gàÿ=XFÔÿÝäÿ…ÿLºüïûÿzüŸýÿö¡¿þŸ2à?ø¿§ÿ/þ÷Ø~c¨zëEëäÄQ´V8§C‰EðÿXQÿMüW“ÿ‡ÞÿIÿ·úûÿríÿW³ÿï'ø¥O‚ÿ§ øþïéÿ‹ÿÝ[ÊQe¯r&kb#²Ï^ÊBòIrårÁþßÁ2¢þÛø?ùücÒåÿ_®ýÿ·æýÿ·ÿÕ½ü?eÀðOÿ¿ò¿·‘Éœvcb¥kkª¶Õ~\UEy©ÀÿceDý·ñÿkþøÿ†¤Çw‡ùíÿ¿5ïÿ?óì­W‚ÿ§ øþïéÿ‹ÿµ˜*+Y‹-2Pª"Eú±p5¢rJYVÂù¿ƒeDý¯Á§°ÿ7$]þßaþ_ûÝ<ÿ‹×}Vƒÿ§ øþïéÿ‹ÿÕ‘Ž—·üÕ'aZ·wìÚ׿~W\ ¢ˆ²¯E‚ÿÇʈúoã¿‚ÿw`ºüïûÿn®ý?nžÿÿòÁ/ÿ:øÊ€ÿàÿžþ¿ø_GJ—W½‘µq:‡jCÖ,ld\bVœj²ü?VFÔÿ'ÿ28ÿ7$]þ÷ý7×þ7ûÿžÿü^þŸ2à?ø7ú?'eû°ª¤£ÎÆñ¥®£*mô¯YÊþ,#ê¿ÿ“ÿÇ8œÿ’.ÿûþ¿ÿgÿß;>öÊ¿ÿOðüßÑÿÕâW®UÑŠ(LÑV²w"ëb[SODÞÓþƒ'™áÿ=XFÔÿ'ÿÁÿ3&]þ÷ý¶óþöÿ}ú¥oøðÿ”ÿÁÿ=ýñ¿S3±O"R›óµM%Jv©4(ß°`u ¨ îÿ9XFÔÿÝ|ÿÿG¤Ëÿ¾ÿÏvæÿÙÿ÷–wÿQÿOðüßÓÿÿ»h#~5óeäœKòÑDÎÖòJEK©øHðÿ,#꿉ÿzòÿ8ƒóÿCÒåßÿg×þ7ûÿÞö³Éÿ§ øþïéÿ‹ÿ•¹j’5'g}ÖÕ“PÕÔÂVjE²š³ AkðÿXQÿkðß8ÌÿCÒãÿÓýý»öÿºÙÿÇo¿÷ÁÿSüÿ÷ôÿÅÿJ%(U³sµ#bÌÆë¬tˆ*‡ZL6ªZ“=üˈúoã?Íü‡ÿgHºüïïÿÛµÿ÷éyÿÿ¿ó?|ü?eÀðOÿ¿ò¿fr2Pû„•ñÄÁ¯\ ™E– ²NÎðÿXQÿmüŸü?RaÿH:ü¿!î0ÿ¯ý¿OÏûÿ_ùƒ¿þŸ2à?ø7ú¿ò9™ó:ÊHöÙ¤l/wÿú噃ÿ–õ߯ÿÉÿã´ÿG¤Ëÿ;Ìÿ+þ·'…‰ÿÿ'ÿðÿ”ÿÁÿ=ýñ¿KYd  [ÃND)ŠöÁ˜"$åÕeþ+#ê¿ÿ_óÿ`ÿoHºüïûÿìÊÿßž&þßÿÈ}¿þŸ2à?ø¿§ÿ_ùßmµÂ…誤±zIfÒ¹$’ÕÖ¼Âü°Œ¨ÿ6þOþ­ðýÿtùß÷ÿÙ•ÿ¿=)LüÿÅOþ¡ÿOðüßÓÿÿ»f‘¬,‰™²’’ÉÒSMAYÎVÈJÍ*cþ?XFÔÿ'ÿÕøþHºüïûÿžZùÚ“Â|þÿ¹ûÿOðüßÓÿÿ«Z'“T‰I™êˆª”ª•S¶&J-¤7‰÷ÿ,#ê þøÿǤËÿ¾ÿï©•ÿ§=)Lüÿ®7þÎÿŸ3à?ø¿£ÿëÅÿ*Š3ÁWrìkÒ))r¾$]ÛX˜J9Ê$üˈúoãÿäÿÓøþLºüïûÿ¨3ÿÏþ¿G?òü›ÁÿSüÿ÷ôÿÅÿ*ÈT ì¢-5³ Ö¥`<¹jkáhŒH2ø¬Œ¨ÿ&þ›Éÿ£ÚGàÿ€tùß÷ÿQgþŸýÿxÏ÷½ü?eÀðÿnô‘ˆÙÇdI(-£pÙIåø5'é¶÷ÿ,#ê¿ÿ4ïÿcþ’ÿoô÷ÿ{üŸý=ù¿ þŸ2à?ø¿§ÿ_ùß}Ñ£º|ÜÀíטXz#¤¯lBÐûÿGˈúoãÿäÿ± ûÿCÒåÿŸVþÿö¤0ñÿì;îÿOðüßÓÿÿ»²¶†ïrÊžkÊ¢F–%[A. uˆBDQqÿïÁ2¤þ›ø¯^$”„ý¿!éñ_ßaþ_ùÿÛ“ÂÄÿ?}ùc¯ÿOðüßÓÿÿ»÷VhB­ìDªÑ­‚÷ÂèÆEpžm+5ø¬Œ¨ÿ6þOþ‰óÿcÒåÿæÿ•ÿ¿=)LüŒî'ðÿ”ÿÁÿ=ýÿÊÿ®„•²š6êG¢JÑ&ÑÀ†MqUWáSþ,#ê þÃÿ7(]þ÷ý´öÿêyþÉ3Ï¿ü?eÀðOÿ¿ò¿&QŠ“.“L(\P\¸„Xj%“•`òü?VFÔÿ'ÿŸuðÿ I—ÿ}ÿ­ý¿zöÿ½þM/û^ðÿ”ÿÁÿ=ýñ¿;[C–Îw®²,­ÍQF/Û_´'þ+#ê¿ÿ“ÿG9ìÿ I—ÿ}ÿ­ý¿zöÿ½ú‰~ü?eÀðÿnô-Œ!Ù˜”µØ*càä…•šƒ'r¡DY*æÿƒeDý·ñöÿàþß1éò¿ïÿëñöÿ}õ}ñõàÿ)þƒÿ{úÿâ§LmÚÚ¥…vÚ‡j|Ö³64&0«Â¬ÁÿceDý7ñßNþÂý?cÒåßÿ÷ѵÿOÏþ¿òÅwýøÊ€ÿàÿžþåO¬ò娷’ºz+TоÃ%FÒE뤃•N`þ?XFÔÿi¾ÿçÿ†¤Ëÿ¾ÿï£kÿžý¯{ؽü?eÀðGÿ7‹ÿ=*C.Û”S–>mla«‹)^YÕ†Áâ‚I¸ÿï`QÿmüŸü?ÆiðDzü¿Ýßÿ7ùöÿ=÷+ÿõ£àÿ)þƒÿ{úÿâ%%«§l„5®Ôh%sÔ.²5>W«UÔ^±N˜ÿ–õ¿ÿ ßÿI—ÿýý³žÿoÏûÿÿqëžÿOðüßÓÿÿkb–¥ù6EÌ–„I!h2tY·EWœgÜÿ{°Œ¨ÿ6þ«ùüæÿ!éð_‹;Ìÿkÿïíyÿÿ­Ÿxë#àÿ)þƒÿ{úÿâ•A³àÄŦZ´«©õsr¢˜Ë­p!¶™.ekÁÿceDý·ñòÿðLºü¿Ãü¿òÿ¶'…‰ÿß,?ø~ðÿ”ÿÁÿ»Ñÿ}Þ»*«s2ª¼IåȤ¢Iìƒ:iòàÿÁ2¢þÛø?ù”€ÿwHºüïûÿzüŸçÿo½÷-?þŸ2à?ø¿§ÿ/þ÷”e/Ū 9gŒJÒ4àçBÉš$I›¨Mÿ•õ߯ÿÉÿ£É‚ÿ#ÒåßÿgVþÿö¤0ñÿ“Òàÿ)þƒÿ{úÿâW”U¨¥ål2Ùä”%§¢®l¤’±Æ(½3àÿ±2¢þÛø?ù¬Åù¿!éò¿ïÿ3+ÿ{R˜øÿ¹þü·ƒÿ§ øþïéÿ‹ÿ½ýž“ .Èl S mÞWŒÕJ2irpœ|ÿ•õßÄ7ûpÿϘtùß÷ÿ™•ÿ¿=)LüÿÔ›Ÿ}øÊ€ÿàÿžþ¿ø_s0¥÷ÅYY³sÑi޾” m1’7RKÿ•õ¿ÿÁü?$]þ÷ýfåÿmO ÿßôϯzü?eÀðOÿ¿ò¿]”õVUa•¦˜r’íS­(Êr E5ü?VFÔÿ'ÿ |ÿ?$]þ÷ýO®ü?íIaâÿ‹ë'ßþŸ2à?ø¿§ÿ/þ×Ú:·±U8å¹PkÒ^y¥0ɉš½TþߣeDý·ñòÿHùHzü¿ÑßÿråÿiO ÿ_öWü?eÀðÿnôŽ%Åì…OÒrmŸS›÷K6ÊÔöSDHŘ” ü?VFÔÿÕìÿÅþßtùßßÿïðÿƼÿÿÔWïû]ðÿ”ÿÁÿë÷%ÿ{6N'Á1'!E*¹ NRE¡,%WUÔ.)†ÿÿ`QÿmüŸü?Öáþ¿!éñ_wç+ÖïÿoÌûÿ7ù1ÿŸ3à?ø¿§ÿ/þ÷ª/Ò–Z„U%[¢ ‰”‘1¹’ãå5°åÖÖ±ÿ°Œ¨ÿ6þOþ#pþHºüïÎÿV¬ç=Ïÿßý_úWðÿ”ÿÁÿ=ýñ¿WQIú,LUlª´"ÅËàgHeá“2ÖØœÅùÿƒeDý·ñòÿ()Àÿéò¿ëÿ³båÿoO ÿŸ}ð§¿þŸ2à?ø¿§ÿ««ý/¢ªÌ‚sûRû=„(Ôå8¸fUK”\’ÄþÿÁ2¢þ×à¿&¼ÿ’.ÿ»þ?+Öþ_=ûÿ~ÿóŸyü?eÀðOÿ_ü¯Þ’o³ŸKš·Ù­d …5Q©d| ÆÅÌðÿ,#ê¿ÿ“ÿO9ìÿ I—ÿ]ÿŸkÿ¯žýîo|ü?eÀðOÿ_ü¯Áv޳.ë륌A±(J‹3IoLP¥$ðÿ`Qÿ-ü·bòÿ(…ïÿ‡¤Ëÿ®ÿÏŠµÿWÏþ¿_}èiøÿÏðü¿ý_ähȤË[_›}c>³r1Ù`¥·ÒæVädRàÿ±2¢þÛø?ù´ÿ‡¤Ëÿ®ÿ¯ËÿÙÿ÷Οù…/ÿ§ øþïéÿ‹ÿ=ii %ËÞ^^ó3ÛÄÁdÖ”XPäìSiOàÿÁ2¤þ›ø?ùœÂù¿!éò¿ëÿ³bíÿ׳ÿïû}ÏŸÿ§ øþïéÿ‹ÿ½¨ªKMNIò&µ–!È'JÕ´ù/dËÔfÁ$Îÿ,#ê¿ÿj~ÿ¯Áÿéñÿööÿ×þ=ûÿxì…ÿOðüßÓÿÿ{"S”#.±ú6šTZ ½ãbŠ«2‘¢lœ4˜ÿ–õ߯=ûÿÀÿ!éò¿¿ÿcíÿ¹=ïÿ?ò¡o±àÿ)þƒÿ{ú¸ºÿ¥ÖP´*¬³¬u"ªªÙDï¹rÈ5ŒÃý?ˈú_‡ÿçÿ‡¤ÇÙŸÿo¬ý?·çýÿoÊü/àÿ)þƒÿ;ú?-þW]8§Rm¦”ÊÙZé%iƒcjÓ ‹¤Yø–õ߯ÿÉÿg-¾ÿ’.ÿûó¿^Ïÿržÿ_ü×ï}?øÊ€ÿàÿžþ¿ø_­ðJ)Ž…´¯¢ †9´?ÅèÔZ}Œ¹Èöakïàÿ±2¢þÛøoçûÿ0ÿI—ÿ}ÿŸ^Ïÿržÿç5?þðÿ”ÿÁÿ=ýñ¿ A’·F¶y/hesjó ¢à’7Y0kvü?VFÔÿgÿüÿcÒåßÿ§×þ_9ûÿþüÓO|ü?eÀðÿnô—œ2²Í|‰]HÕŠL¤3Ûjk‘¤BÞTÿ•õßÄšü?Z‚ÿCÒåßÿ×ãÿìÿ»ÿ/|#øÊ€ÿàÿžþ¿øß9'WbaQs¢†˜…ÊÕc5ÙÚÊ& Üÿw°Œ¨ÿ6þÓ‹„’ðýÿtùß÷ÿéµÿ_Îþ¿òŠ{>þŸ2à?ø¿§ÿ/þ÷’5£©¤jŒV:VMª”¤H5acluÿ•!õßÄÿÉÿc±ÿ?&]þ÷ýzíÿ—³ÿïîyü?eÀðOÿ_ü¯•­sÖ›cv¹XËÊëjÈqð5[g¸’ˆ†ÀÿceDý·ñòÿ þI—ÿ}ÿŸ^ûåìÿû¶æsàÿ)þƒÿ{úÿâ±PöI •JÁ°pƪ:© Š ‚IIåðþÿ`RÿkðßðDzü¿Ùßÿ×kÿ¯œýï|ò7ß þŸ2à?ø¿§ÿ/þW—Éë\”ŒRPÉf]„­!ÊH‘e‘QE÷ÿˈúoãÿìÿ1 ü‘.ÿï°ÿ¿öÿÞœ÷ÿì×þàðÿ”ÿÁÿ=ýñ¿j[!eV1j’N•T$;¬ñ’JÑÅÄXñýÿá2¢þÛø?ù¤Áù¿!éñßöçÿÛkÿÏÍyÿÿÿ>üžŸÿOðü¿ý?¦är¥š}6Q–^µ¬*‚ÙŠ`ÿŸ½s Ùì:ëxŒÚ‹#¶‘´ ¢’ ëYÏ:¢¢PA5¶RZ ëØÐÔÔC0/j-5mT¬7- ­¢u&™ÉˆçRƒ¼Qz(jÑx ^Ø’ëÝÛ={ÍÅž=,ö†ÿÿâãý¾yçêÿï}ö»×o7(„(ðüߣeÄü·ñòÿX²àÿˆtùßßÿ;ü7óþÿwÿþÂûÀÿSüÿ÷ôÿâÏ2… ƒr좪X§P’‘¦FŸYDɾÂÿw°Œ˜ÿ6þOþ£pýHºüïûÿ®­ýfÞÿyÇ×_ÿOðüßÑÿrñ¿ ¢ö)Vã“ÍVè”}Žš³¡ rVÅǽJàÿ±2dþ[ø/Å|þ÷ÿ I—ÿ}ÿŸììÿ³ÿï¿zÍW‚ÿ§ øþïéÿÅÿ®]ðùâø+5+r±5\BnotV•L"bøÿ–ó߯ÿÉÿs©ð@ºüïûÿdgÿŸýßýêºü?eÀðOÿ/þ×$Š*&ae0†É'AZhÊ…\ŠÆýˈùoæ¿´’Áÿ!éò¿ïÿ“kÿ¯™ý~æS¿ þŸ2à?ø¿§ÿÿk*: ©m’,] ÁÇR„wš8†ê.Vouÿ•ó߯‰óÓåßÿ'×þ_3ûÿ^Ìw½ü?eÀðOÿ/þWŸÜEŽ’H¤ì3…(¸(VÙ¬Aãùˈùoãÿäÿa‹ýHºüïûÿäÚÿkfÿß=÷>ø"øÊ€ÿàÿèÿÊ¢0igXêìÉJeeµ‘)™¶ –’б¬kÿ•ó߯ÿÉÿ#…ÿG¤Çÿ§ûçÿ{üŸýýÊK+øÊ€ÿàÿžþ×7÷¿œƒ½Üì•(WZã;Áì}#@,¶\ž Û^zðÿX1ÿmüŸý?F‚ÿ#Òåÿü¿\ûÿŸžÏÿøÁ¯†ÿÿœÿÁÿ=ý¿øßÍåA¯D* +Œ¶*ç\h0%pÍårxÍ ×ÿ–ó߯ÿÉÿÃøþLzü§[ìÿkÿÿÓóùÿw¾ú' øÊ€ÿàÿžþ_üïÑP1PñR3'éª1Õ˽‰Ip.™,Îÿ-#æ¿ÿ“ÿGáþÿ1éòÿûÿÚÿOóþÿÃñŽÇÀÿSüÿ÷ôÿâu2,yII×Ä—[ÃvÎ*UCû%êªK5¸ÿÿ`1ÿÛà¿”øþHºüïûÿž\ûhÞÿÿå7¿ïcàÿ)þƒÿ{úñ¿g•­+­û#+oHSFŠêµi(PΩ¶‚ÿÇʈùoâ?Oþ¿ðDºüïûÿž\ûhöÿ]ý²çßþŸ2à?ø¿£ÿyñ¿Z¥)Hë‚SBx£cæÚêœEÎ>:GÚ{Üÿw´Œ˜ÿ6þOþ"|ÿ?$]þ÷ý¦³ÿÏþ¿>þ…ÿOðü¿ý/j!ú˜“ôÅ„Ô@Ð~¹ä ùËáp¥àÿ;XFÌÿåüü?øÿ‡¤Ëÿ¾ÿ¯ÇÿÙÿ÷ÞO?ÿ_àÿ)þƒÿ{úñ¿g&]|ȉr JgKno‘Êé¼5.«P¥àÿ±2bþÛø?ù”Å÷ÿCÒåßÿg:×ÿgÿß½oõ þŸ2à?ø¿§ÿÿ;%#‹$¥w$¸Øè(OÕ9ÑÚ£žKÄýˈùoãÿäÿ!‹ëÿCÒåßÿgÖþšý¯y÷3?þŸ2à?ø¿§ÿÿ{(—¿8c“§ ’6ÂÛšÛ‹,IV¶I´­ü?VFÌÿ'ÿÿG¤Çÿ«ýóÿfíÿ§Ùÿ÷uüÿÿOðüßÓÿ‹ÿÕ„"U)U·ª72Çí]^*¥H“×¹ètrü?VFÌÿ6øO÷ÿI—ÿýóÿfíÿ½:ŸÿÿíÇ~ô{ÀÿSüÿ÷ôÿâuB:m¢W*H[<9%t`­p5 Ã5šê²Çþ°Œ˜ÿ6þOþ?a±ÿIÿúûÿÚÿ{u>ÿÿŠßø¥ÿOðüßÓÿ‹ÿµæÀÙÅBE»¤e¾ˆ`UqÁµ¿BªžSØÿ–ó߯ÿÉÿÓ^‚ÿ#Òåÿ-öÿµÿWÏûÿ¿òÊwÿ§ øþïéÿ›þ×˽ßÞšâcŠÉµ]°¶—U{Œ©Âå9°øþÿp1ÿMüW“ÿÇœÿ’.ÿûþ?³öÿêyÿë/<üøÊ€ÿàÿèÿª¼º¼ÒÞz›r°¨¤”KI5r`oE ¨+ø¬Œ˜ÿ6þÓ]‚áù¿cÒåßÿ×ãÿìÿ{âýÏüøÊ€ÿàÿžþw7Ÿÿ’bN"±QÑfá2»$M`­”:ºjlÉlÀÿƒeÄü·ñòÿh<ÿwLºüïûÿž^ûôìÿ»ñ{ü?eÀðOÿßô¿;kåå¦oЉJûM±eJÆ—ö·lHg]cfþ+C濉ÿ“ÿGhÜÿ7$]þ÷ýO¯ý?zöÿ½xïϽü?eÀðGÿ«ÅÿÊÉä |4Q¥uÌ!]rMEeÅûìSôþ߃eÄü·ñ_M×ÿø?$]þ÷ýÔÙÿgÿß÷¿ð‘ÿ§ øþïéÿÅÿšT\8³2ΓIZÉ™U®B6ú«ªü?VFÌ3ÿ¥Uü’.ÿûþ?êìÿ³ÿï¥o¼ïïÁÿSüÿ÷ôÿâ­ÒIa¥¨%ç@©²¶!1µ÷Šöf#Un4ÿ•ó߯ÿÉÿ£Îÿ Iÿ×ûçÿiíÿÕ³ÿïm_rÿÏ‚ÿ§ øþïéÿÅÿ*d,œ‰¥.–|ιUy°ÄÞ¬¶XËε"!ðÿX1ÿmüŸü?²ý3ø? ]þ÷ÏÿÓÚÿ{}>ÿÿíÏ|ë—‚ÿ§ øþ߉þ·Òù67!‚s¾”"SŒT’eãYætyœ/!áûÿƒeÄü·ñòÿ°Æþ?$=þó-öÿÿçóÿ¿ûÄwƒÿ§ øþïéÿÅÿ^“ Þ›kë‹Ðú>[EÕD]£òÛ>ggÿ–óßÄ-æó8ÿ?$]þßbÿ_ûÿyÞÿÿç§þøÁÿSüÿ÷ôÿâWÞiÉ"Ùà‚™\0dEŠÎ‡FV#JG™Àù¿ƒeÄü·ñŸæý×ÿ‡¤Ëÿ¾ÿÖþž÷ÿ‡^öÊGÁÿSüÿ÷ôÿâ·bT±c”L†Rå Û`EOQ·>¿Èa*üÿˈùoã?ü?#ÓåßÿGkÿ?Ïþ¿7ýÃ?}-øÊ€ÿàÿžþ_ü¯::[«PÂK劳ÎÕ¤”Ð6Úl”µ%‘¼¨ÀÿceÄüoƒÿŒçÿŽI—ÿ}ÿ­ý¿<ûÿ^ûU6àÿ)þƒÿ{úñ¿²Ò\ž«©8]efU(k[ ÛÜVÜu2ªHðÿX1ÿmüŸüLàÿtùß÷ÿ]]ûxöÿ}ñÿöÏàÿ)þƒÿ{úÿÿù_}$ÎÖº’s 5'XÄâ­w^ʪ“È*ðÿX1ÿmüŸü?VÀÿ3$]þ÷ýW×þžý?ÿè'ÀÿSüÿïDÿ{T[ñk‘Qr#~vÑy“\ …\ 9(!eÄþ´Œ˜ÿ6þOþƒëÿcÒåßÿ×ãÿìÿ{ó§ÿæíàÿ)þƒÿ;ú_ßô¿—3Õ o)ˆªmÐB¹’4§À2Y‡çÿ,#æ¿ÿ“ÿÇàù?cÒãÿSýóÿºsýöÿýú'^òàÿ)þƒÿ{úñ¿‡,\H†¹JcEšþ#s¶±J_¥ŽV”ˆëÿˈùoãÿäÿÑðÿŒI—ÿýóÿz½ÿ?5Ÿÿÿ黾ü£àÿ)þƒÿ{úñ¿®¹FS¢o?Øg!YjëUi‹aqµ-†–TÈü?VFÌÿÍäÿQšÁÿéñßÞbÿ_ûÿŸšÏÿçÛþà'ÁÿSüÿ÷ôÿâõµd%¼¡e9 “5µ'Ed¼®"x©«Ã÷ÿˈùßÿ%öÿ1éòÿûÿÚÿkçýÿî#àÿ)þƒÿ{úñ¿“…¨¤kÌÎ$+˜j*Ù ’½Ì‰U{ ü?VFÌÿ'ÿŸðÿI—ÿ}ÿŸ^ûí¼ÿÿã3ÏÝÿOðüßÓÿ‹ÿ5ùlMÔ†J¨$‚T­J©´¥?°K¢ødsHü?VFÌÿ'ÿÏå1€àÿ€tùß÷ÿéµÿ×Îþ¿ßKþøÊ€ÿàÿèmWí³4œMöŽ’¦@¢ä`ÖÚWS3·åü?VFÌÿgÿàÿˆtùß÷ÿõø?ûÿô7»/ÿOðüßÓÿ‹ÿ]*_[Q¸TƒM!;® ZpŒªJÅ‘M.ðÿ`1ÿmüŸü?í3ø?"]þ÷ýzíÿ·³ÿïåŸ}ì ðÿ”ÿÁÿ=ý¿øß]ÁÓ^ÆËCß«Á)Ê™5—„^3žÿs°Œ˜ÿ6þOþÍàÿtùß÷ÿéµÿßÎþ¿÷¼óuïÿOðüßÓÿ‹ÿ]”lYReT,)•"t‰ÎGQ­7Nøöºý/ÿ•ó߯ÿÉÿcžÿ7$]þ÷ý××þ;ûÿžý¦¯ø-ðÿ”ÿÁÿ=ý¿ø_…÷¬snÅÝZ_˪K,-{¹ó/©Rœ•ÕGðÿX1ÿÛ࿲ ü‘ÿoôÏÿ__ûììÿû¤xè9ðÿ”ÿÁÿÛï%ÿ« >ù_?£¹\Êeíµ16ˆ 2öÿƒeÄü·ñßÎþ_ðHºüïžÿ'±ÞÿoÌçÿï{ýû^þŸ2à?ø¿§ÿÿ«Ê‰ ÙHI5’‰9E]“®,seJR•TÃÿ{°Œ˜ÿ&þ[1?ÿþŸ!éðÿšèîÿ$Öûÿùüÿ«>u×Ãàÿ)þƒÿw¢ÿ3''¼$«ª³ŠJ,Þeá«ÈQ³ ®Q:‘ø°Œ˜ÿ6þOþ…ïÿǤËÿ[ìÿ+þ·O ÿåûÿóøÊ€ÿàÿžþ_üï¥TÏ®² N‰Ê>&ÃA‰àV¦(­EÑQI<ÿï`1ÿmü—àÿÀtùßõÿ‘XùÿÛ'…‰ÿúº·¿ ü?eÀðOÿ/þwEQ8]¥‰UcR6»=sR¾ýª)°PQÿÇʈùoãÿäÿÑ„çÿI—ÿ]ÿ‰•ÿ¿}R˜øÿøç>ù1ðÿ”ÿÁÿ=ý¿øßIøÙeÅ"º¨+IVc£ R³ uÂC¶ü?VFÌÿø?0]þwý$VþÿöIaâÿ·=ûÿ þŸ2à?ø¿§ÿÿk(Â$ãØ–‹ð§ÖV +)z㥒í?8ª'ðÿX1ÿÛà¿dÜÿ7$]þwý$VþßöIaâÿ#¯ÿÃ7ƒÿ§ øþïéÿÅÿZŒ¦õ„íi+K6y_9¬Õfé*žÿ{°Œ˜ÿ6þOþ?‰ýLºüïúÿH¬ü¿í“ÂÄÿ÷þâýÿ§ øþïéÿÅÿªØöºF+’â˳àÉöäÉåj9‡h8ª ÿÿÁ2bþÛøoæý÷ÿ I—ÿ]ÿ‰•ÿ·}R˜øÿ—æ÷ƒÿ§ øþïéÿÅÿʆr Ìí§)º¥gS³V±ÖÄ6èö~R¸þ°Œ˜ÿ6þOþ+qýHzü¿Ò?ÿeåÿiŸ&þÿù_ßó-àÿ)þƒÿw¢ÿ‹vd‹*Ö”Z¤²ÊKïóÉçšUuíÏ)fïÁÿceÄü·ðߊÉÿÃÒ€ÿ#Òåÿü‡ÿWæóÿ^¿ïMàÿ)þƒÿ{úñ¿SaS’PÙ UpûÇd«V•“`åd5–äpþÿ`1ÿmüŸý?„ýHzüW·Øÿ×þŸ+ÿwþÿç?ÿðÿ”ÿÁÿýO‹ÿ]RœdÛö‚nõïe(VzEz£N¦;eáÿ;XFÌÿ'ÿãûÿ1éò¿¿ÿ«õþ¯æýÿ÷ÞÀ€ÿ§ øþïéÿÅÿZ¹)"i–E™gcB)ëÌí·d&'ðÿX1ÿmüŸý?ðÿI—ÿ}ÿŸZïÿjÞÿ¿áÙÏüøÊ€ÿàÿžþ_ü¯Údtµ¨ rM¥¯I ëJÐZ‰˜õå¡®ðÿ,#æü·¸þ?&]þ÷ýjíÿU³ÿïUþå_þŸ2à?ø¿§ÿÿ+Ï­ú­u$)H]½…¥pÁF¯uPI ªÿ•ó߯ÿÉÿà Ïÿ’.ÿûþ?µöÿªÙÿw×Ç¿÷ðÿ”ÿÁÿ=ý¿ø_‰T½M±R•%KU…/ÅH²÷5øËeðÿX1ÿmü×ó÷ÿàÿtùß÷ÿ©µÿWÍþ¿Ïÿò£ÿOðü¿ý/½Ò2¤’‰Kq¢)l¬^×r)™£ñ‰ª€ÿï`1ÿmüŸü?–áÿ’.ÿûþ¿ÿgÿß 7®½ü?eÀðOÿë›þWwyÔ›ËZ)вíúÕ9|tª’ó®UH&Iü?VFÌÿí|þ÷ÿ I—ÿ}ÿŸZûÿÕìÿûÐ=w¿ü?eÀðOÿ/þw—[ï§BÉ9V‚"å¨eÌÊÔhÙJA‘Ã÷ÿˈùoâ?ÍþìÿcÒãÿµþùµöÿ«Ùÿ÷'¯µ?þŸ2à?ø¿§ÿÿ{”5ÊRRhå²´Eeeeð¡Òå¡°^Èj4Îÿ,#æ¿ÿ4Ÿÿàÿˆtù‹óÿkÿÿµùüÿ¿=ö5ŸÿO™ÿeïìB=»Î:< &¥fµi‹7E”¢®õ¾ë3ÐXBŒÆ^T¡VEÖg *‚ $-**~´i-Ö ‘Ôè…i¡É0 ´ÐxÓ*uª  µ_Ú"jm j±©û¿÷ÙãxÎ: {ö°º7ü~¹˜™ÿ9sqò&ï³ßµ×zøþ¯éÿ³ÿ5 ˆÒ—d“2‡u_c2i—dL¾úZɦÊqÿÏÆÒ£þ׿¿9Áó]r’ÿB Ñ^¸xRtñ³¿õ½/9s×û¾N¯ùÆþ Èuüÿ×ôÿÙÿJrè÷Ñ(¶ÖÔ ’¬T¼pš‘2“KÐ<üKú/ã?M÷ÿâý—´ùß^¸x\tËú?~ëð¯å?òºÛîþÆþ ÈuüÿWôšý¯Ž´Êv€üzç$%)r®% ë³$¹GCsÿ·•õ_ÆÿÑÿc4Öÿ»¤Íÿ¶ŽÏÿÿ?;òÿ[þóóÿ÷ðü¿ýŸLÑ*/k2ÙørtÞP•9JoUU©Æá¯àüÿÆÒ£þËø?ú´eð¿GÚüo [üÿôÈÿ»éžÇÀÿ=üÿ×ôÿÙÿîIädU R¥(Y»÷²ï²>&ÿRù þo,=꿌ÿ£ÿÇ( þ÷H›ÿm 5Öÿÿiäÿkßf¿ üßcÀðMÿŸýïžµ6Ö‰aÐÏ1(2¡h!™„Ò‰À9…ê³Åù¿¥Gý—ñôÿÁú—´ùßÒñ þjäÿû~襟ÿ÷ðü_ÓÿùÊý¯É¦$Œ^–è½­YxN.-“a_ Çûÿ6–õ_ÆÿÑÿcöÿuI›ÿm ¿`àÿçFþ¿ü¿_úðÿÁÿ5ýö¿­ŠÒXOIÇà]D‘бº¡|±©Ö0ÿo,=꿈ÿ4úcý¿KÚüo é¸xàÿgFþ¿åcüßcÀðMÿŸý¯.Z> oÑS‰œr‘’gí×lB ¶Jk*ƒÿÛJú_›ÿê8ÿÙ`ÿ_—4ùÿÄÿÿ¿ù—Ïž}ô£gŸ½ÿþG~,ÝN÷}ùÂí_ùÊß~éË·Ÿ}úüoÜ÷ìÓŸyå™Ë¿zïëAÿ}üÿ×ôÿÙÿ3gïLôUÊ$“Š"ø"cu"“•¬m‰Ž™àÿÙXzÔÙü/§ýXÿï’6ÿÛçÿ鏸–;.Mçÿßúøý4žöðü_Óÿgÿkˆ6±ÕFéP•Š2—¢±&B( “¿9l¨àÿ¶Ò£þ׿¿½Šÿ4­ÿƒÿ]Òä¿jûÿè¸XÆóÍâf<ì0à?ø#úâm%m<«ÄÆñÐFr ©#B…&‚•àÿ¶Ò£þËæžü¿à—´ùÊüœÿWü|øUÏÿ{ øþ¯éÿ³ÿ]k&—™JñÁ%Ϧ$m¢-B ½†Z4«8Ìuàÿ¶Ò£þ׿ÿÕïÿÕôþüï’6ÿÿŸÿïÌ—žßÿßO¼ÿ?7¾ÿ÷ctôßgÀðMÿŸýï,Kr9%g0ºQ+[‹À0|—Ê:“ªÿ·•õ_6ÿþepÿo—´ùßöÿ]hø&ÿß…÷|ß¿á `ÿÁÿýŸgÿ«uñðú—)s9¬úRp%GUl%qx1̲f,ø¿±ô¨ÿ2þ›iÿîÿë’6ÿÛþ?ÓðÿNþ¿3?ðÅW€ÿ{ øþ¯éÿ³ÿU8R&Öd"s.qürÈìØe#üÁ[‹ÿ·•õ¿þ+Và´ùßöÿ™Æü?ùÿž{Å{žÿ÷ðü_Óÿgÿk4‘§*T)jVΊ¨Œ¢”eÕÃh˜«ŒÄ¸ÿocéQÿeüýJâü—´ùßöÿ™†ÿwòÿ½áçþúOÀÿ=üÿ×ôÿÙÿê5R¸àJÉ2%-£Ù ¯taªÄ*þ¿¥GýñŸGÿY¬ÿwI›ÿmÿŸiø'ÿßù. üßcÀðÿFôb…Ž’#™”\åhжN§¢kõ2بK¶JƒÿÛJú/㿜Îÿaþï’&ÿ/¶Ïÿ·øÿÏ#ÿÿâÕßþï1à?ø¿¦ÿ_ñ¿ç0Œ÷6èl4‰”‹¡šaàW1 R†£ÕZ¬ÿo,]꿈ÿ£ÿçp øß!mþ·Ïÿ›“þÿ#ÿß¿ßö;÷‚ÿ{ øþ¯éÿ³ÿ]Ñᆿ ËÕÉaì#‚.f®: VNöÿo,=êmþ_åÿãÉÿcÀÿ.iòŸN™ÿ=éÿ»8ùÿ¾çwÕ³xØaÀðMÿŸýï¥xö•\L¹¨¢×s-º–¨BÔÑKëIxþo+=ê¿lþ>?hƒqþ¿KÚü?eþ?éÿ?òÿÝ]ÎÝüï1à?ø¿¦ÿÏþWy8êm£¦}b)’±AWY –ŠÑÊH*læÿ¥GýóŸ,kœÿë’6ÿ?ÝæÃÿ;ÿ?î§Àÿ=üÿ×ôÿÙÿ:LyZ…DFœŽ2V¡jIÄY0QL÷ÿm,=꿌ÿ“ÿoøüï6ÿÛþ¿§þŸÉÿwæ%7ÿ÷ðü_Óÿgÿ+:¾È‰M ’ô:§àÈ{'#™Xc4Ž*îÿÛXzÔÿGÿ–üï‘6ÿÛþ¿§þŸÉÿ÷k8ÿ.ðÿÁÿÑÿCÎA*'2‡áëÞë‚bëY$œ’ÁH ëÿK—ú/â¿Öÿñþ¿KÚüoûÿZüŸü—|×ýàÿþƒÿ+ú¿šýï2Fɲˆâ¼ ž£J‘„‹Riãtt•\:(œÿÛXzÔÿÕèÿaÆú—´ùßöÿÉÆúÿäÿû‰;~ö2ø¿Ç€ÿàÿšþ?ûß­Õ\³r†¥«ÙÆaŒNiqØ^‚ÍRrÙð[éQÿeüý? ÿoŸ´ùßöÿÉÆü?ùÿzÙ=‚ÿ{ øþ¯éÿ³ÿ½°z…±J˨“uC¯C77št.™¼±¤cvðÿm,=꿌ÿ£ÿGhœÿï’&ÿ/´Ïÿˆÿòÿ}ávàÿþƒÿkúÿ앺kB¦äI³-ÎqhéièÁxãD­ÎjìÿßXzÔÿ:øO„õÿ.ió¿}þ_žôÿùÿ~ðAÿ÷ðü_Óÿgÿk CÛ—±’LA²’rèj€¿•ÈššŠÊxÿ¿±t©ÿ5ù•ÿOþ?¶üï‘&ÿÍ)óÿqÿ¯><*Œoy>ÿvðü_Óÿgÿ«Ó5kçw¾Xç¤Ræp|ðÖÖ$¥/žC!bÿÿÆÒ£þËæÿÑÿC8ÿß'mþŸ2ÿ÷ÿ^ñÿ½ð…]þ÷ðü_ÓÿgÿkˆškÔáðò7¡j5YÚR­ÔÙ³ÎEÉR9`þßXzÔÿõÁÿ+°ÿ¯OÚüoûÿdÃÿ;ÿ¯ÿ{?þï1à?ø#úvŽU $ƒ Á*cvR ÎÅkŸj"üðgìÿßXzÔÿáÿé™6ÿÛþ¿ÿ'ÿ_|ÓMoÿ÷ðü_Óÿgÿ»u1«,²Ê%åŒ.>¸’hø§<çcq÷ÿn-=꿌ÿ£ÿG ¼ÿï’6ÿÛþ?ÙðÿOþ¿ïº|þÛÀÿ=üÿ×ôÿÙÿîB<\óÂÐù]TìMb›•–…ö+–M²üßVzÔÿõèÿ9\ þwH›ÿmÿß“ ÿÏäÿû…›èðÿÁÿ5ýö¿ 2râèBÎFi[k1ÃèWi˜«’L%Z&œÿÛXzÔÿ:øoÿ=ÒæÛÿ÷dÃÿ3ùÿþþƒô§àÿþƒÿ+ú¿žý¯"R•1yK¦$›©¢¼Ž²æšeȬ³TÉGÿ·•õ_ÆÿÑÿgàÿé“6ÿÛþ?ݘÿ'ÿŸ»øÛïÿ÷ðü_ÓÿgÿkU¬£Y0M<²¾º¢¢OY’¬¢dï†ø¿­ô¨ÿ2þþMXÿï’&ÿŸjŸÿ×ùòÿýÞ­?ÿ½àÿþƒÿkúÿìÍù0 ªƒ>Ù’‚ Òâ¬r Ä^ÅRæÿ¥Gý—ñôÿhþwI›ÿíóÿú¤ÿ÷Èÿ÷W—Ÿø~ðÿÁÿÑÿc2$£•”}(ÒŠ,½—2ié UÁ9»hø¿­ô¨ÿµù•ÿOþ­ðþ¿Kšü—§ÌÿÇù¯ ãÀÅÿç<ì0à?ø¿¦ÿÏþ÷࢒Y0IªÊzÏ^[a£$§¼Ê‰-bÎXÿßXzÔÙü¯Çû ÞÿwI›ÿ§Ìÿ'ýÿGþ¿?øó{Îÿ{ øþ¯éÿ³ÿ=XÉÑ;Uƒ«1䜅•Òù4ÇH’9•Ø(ð[éQÿeü7Óþ?ø»¤Íÿ¶ÿO÷ÿ_ñÿ¥[^|ø¿Ç€ÿàÿšþ?ûߣIŬƒ®Ö;¶É¤*ÅPIæZSЇb*ü?Kú_ÿ ü]ÒæÛÿ§þÿÉÿ÷º×|êÇÁÿ=üÿ×ôÿ+þ÷"ÈT•J)C'/ÙWá³´µˆâœàâ¸:ëçÿ7–õ_ÆÿÑÿg1ÿ÷I›ÿmÿŸnø'ÿßm¿òõ¿ÿ÷ðü_ÓÿgÿkT&ù œ` ¼ Ÿ«IZ$¼’àÿ¶Ò£þ׿ÿUþ?3úþß>iò_7ç-ŽÏÿúð¨0><öÆ{ÿ; øþ¯éÿ³ÿÕæH¦¦\“> ƒ~dN^›ÃpY“*:­=ð[éQÿeóÿÀÿÃŽìÿë’6ÿO™ÿOúÿügÞñö›ÿ=üÿ×ôÿÙÿš-ŽÅ±‰ž¬S¤sõdQI´ ’t¬üßVzÔÿGÿR˜ÿ»¤Íÿ¦ÿO‹†ÿ÷HÿçÛø¿Ç€ÿàÿšþ?û_sd[”ð.fΡ0qv%¤’²÷lJ&Å2(ãÁÿm¥Gý—ñߎó?ÎÿõI›ÿMÿŸ ÿïäÿ{vàÿþƒÿ7¢ÿ‹Tª3Dʫ䆖ï[é´u2Gª¾Ú"¨’Çþ¿¥Gýñߎþ©±ÿ¿KÚüoúÿšüŸü—~æó þï1à?ø¿¦ÿÏþwO"Ί\©ÕXÓáÒšcpd´%Åðÿo,=꿌ÿ£ÿ‡ öÿwI›ÿMÿŸ ÿÿäÿKoúàCàÿþƒÿkúÿìμeíRÕÎ'Sì|É6x©´ 怅õÿ¥Gý—ñôÿ ¿‚ÿ=ÒæÓÿ§EÃÿ?ùÿþõÎç^þï1à?ø¿¦ÿÏþ÷4ev&P®6ÈÊÁW}Ñ%ÈlYŠt°üßVzÔÿGÿU˜ÿ»¤Íÿ¦ÿO‹†ÿòÿ=óy/ø¿Ç€ÿàÿšþ?û_•sY°Ñ"˜Xc)¡tÿ›¬þ}T*EÜÿ·±ô¨ÿbþöÿIð¿Gšü¿Ô>ÿÿDÃÿ;ùÿ>úZõUðÿÁÿ5ýö¿+”ÙÊ\…ËÆêP¥ vØye†oáákÌàÿ¶Ò£þËø¯àÿé˜6ÿÛçÿŸ8éÿ=òÿ½ÿë?Àÿ=üÿWô9û_£/IÙƒNÖ}• žŠ’Z3º–’bMÃPˆýKú_›ÿWùÿì‘ÿOÿ=Òä?·çu|þׇG…ñàÏþæÝ߉€üÿoHÿçHÙºìÌ@ÇÅ%®Cã/Uæ~SMf=4“þo+=ê¿lþý?Ã+à´ùßžÿOðÿŠÿï÷õ›?üï1à?ø¿¦ÿÏþ÷8|”pÁÐ@û¨Ša⢠ùXrÒŽsɪT þo+=꿌ÿvºÿëÿ]ÒæÛÿ§÷ÿMãÿ«Þöæ_ÿ÷ðü_Óÿgÿ»¯¬¤ñ‰\ÔY³–Ž,%§Jz}rƸlƒ÷ üßVzÔÿiüÿŸ¿‚ÿ=ÒæÛÿ§þÿÉÿgôÜ'Áÿ=üÿ×ôÿÙÿ^è zQ²8á} ÕkN¥¨äYÄ }!—‰ ÷ÿn-=꿌ÿ£ÿG ìÿï’6ÿÛþ?ÕðÿOþ¿ùâC? þï1à?ø¿¦ÿÏþW"—H$—…w”¤ Å9YQ¼7ÑêaFÄý¿K—ú/âÿèÿÑ þwI›ÿmÿŸjø'ÿßå¼óÁÿ=üÿ×ôÿÙÿ*m0®ÖZª9Ù‚’ÁE!-UokÈÁ'Ysÿ·•õ¿þ[‰ý]ÒæÛÿ§þßÉÿWοó¿Àÿ=üÿ×ôÿÙÿjs,ñÙ;¿I®«ŒûZ)FrP@Dƒ¼Ûx×uϹ÷Ö-KH¬ÿde›ÅVÖBïÚÉ­º·fÇ»óG3³Æk6„G„!O(RÄ…Ä1–“<€DA ð’‡À"/<ÆyàÄíªéMÚo²´Û.ºážÄ3ÓÓgºg¾»}¿ïWÝuÚèÒú¢®[ì[¶©¥!¥u,Ë Èå×ÿ¯XM±þ‹ù7ÿO—ùü¿I û?žÿ§Áüß~þßÁëßù£ìÿëXÙÿ³ÿ/³ÿÏ翦Ý•uѪÆÖM©"—¤B$VªðÞÓ¦M$Ïÿ_±šbýóÿnþVùøÿ$ýÿÏ9ÿÌÿíçÿ}ë‡~ì®ìÿëXÙÿ³ÿ/³ÿßœÿj¢ªØ[ßjT Kèg”ªKU5u ïc²ÿ¯VM±þ‹ù¿éý?ÿŸ¤°ÿãóÿ_»õüÿ£ù?ýüãÙÿ×±²ÿgÿ'öÿº5DÊ놹‰Ny§}(Cúª¬,±©9êè0Ÿÿ¿b5ÅúßÞÿËÿ÷ó²ÿOSÐÿKÌÿ·ø¿™E….üåï¼úDkXÙÿ³ÿ/³ÿÏç¿s[hS¨PTmú_(œ­bL6àJÓ(_X_iö1dþ_±šbýãÿnþ—&ûÿ…ýÿþózþÿ§ß÷ÛÙþ×±²ÿgÿ_bÿ§ùüWSFU“µ±2eã}“\¬Z³©°­á–böÿÕª)Ö!ÿWÝü6Ùÿ')ìÿxþù¿=þß÷©/\Ìþ¿Ž•ý?ûÿ2ûÿ|þ«uµµ*’®jª[•K®¯÷«*eTÛ¨¨˜möÿÕª)Ö1ÿWýüßüú¿I û?žÿG€ÿûù?ü™ÏýHöÿu¬ìÿÙÿ—Ùÿçó_ɾj¸‰-×…ö!rÑh­Õì²M– ŠôeˆÙÿW¬¦XÿÅü¿;ÿߪÌÿ“ö<ÿÀüß~þß™{åSÙÿ×±²ÿgÿ_fÿŸÏ­M[ë<{ßxUmÛÔ>”Ê·¬½m«–‚ eÌçÿ­XM±þ‹ù?ßQp‘"@öÿ) û?žÿG`þo?ÿï÷¿ùDzÿ¯ceÿÏþ¿Ìþ?Ÿÿêmi|aÍÞò%8ïŒj+ß’7ºiêÐ2•më<ÿÅjŠõ_Øÿg¯ÿÏïÿ3IaÿÇóÿÌÿíçÿmôÃ÷dÿ_ÇÊþŸý™ý>ÿ•CäØF¦Â°-ª¢¶ºl´.Ù²k¸¬šÂkgu›ýµjŠõ_Ìÿ»ù?”ýšÂþçÿ˜ÿÛÏÿ;sáƒÏþ¿Ž•ý?ûÿ2ûÿ|þk©É’5¥.Öuí½ã ªÊEÒ¶ô¥©C•ÈÐç÷ÿY±šbýóÿ~þæìÿSôÿ/âóÿ Ìÿíçÿýã{ÿæëÙÿ×±²ÿgÿ'öÿÆkM{gB4ԺИ2ø‚\[ÍÎwÖ—®t:?ÿ¿b5Åú/æÿýüŸÂfÿŸ¢°ÿãóÿÿÍÿûÜW¾ö•ìÿëXÙÿ³ÿ/³ÿÏç¿GgŒ¥à\X…Tļ.cÅE˜J›.˜Š²ÿ¯VM²þ·õ3ðÿ²çÿüþ?“òÿWŠÿßñÝ;?ñæß8wîo6wÓo½z÷÷¾÷Oß}ëî;¿|øž÷¼yê˯ýÕOÞñŸÿ“¯fû_ËÊþŸý™ý>ÿÕÕ­o‚ÕÊ…t¥åÆù²IX.ÓÎ^‘.L›ßÿoÅjŠõ_ˆÿ©›ÿcM~þ’ÂþùÿU0ÿ§çÿ;?ýíÉ`+ûöÿeöÿùü×´ßSTÝVºtÖ•¤L¥-ù¢-\¬j›çÿ®XM±þ‹ùÿlþ-Ëìÿ“ö<ÿïU0ÿ§Ÿÿ÷¥|û/²ÿ¯ceÿÏþ¿ÄþÏóù¯Î{§ÛèJNë‚)ÙÔ­‹Éµ!¹¿÷«òüß«)Öqÿ/KçÿMRØÿñü? ø¿Ÿÿwá'®|2ûÿ:VöÿìÿËìÿóù¯Ñ«RWZ± ±‰T†*x.œfeÓjº­Ž^7.ûÿjÕ뿘ÿwóÿ˜óûÿMRØÿñü? ø¿Ÿÿ÷³ŸýÀû²ÿ¯ceÿÏþ¿ÌþO7ç¿§-¾Ô‘”6‰ý\›L ©¬ Ñz«lYZ׆Öå÷ÿ]±šbýóîßÿ/ÿŸ¤°ÿãùÌÿíçÿ}ý£ßÈþ¿Ž•ý?ûÿ;±ÿ+¸ šœ õìe_VºRÄÑ4u]7ª*T¬óëÿV¬¦XÿÅü_÷çÿåãÿ“ö<ÿù?ÿ¯ù™ßý|öÿu¬ìÿÙÿ—Ùÿù&ÿµM«uðU©¢)ŒÓ¶ÐÖ7³³ÿ£Ž¥oMËE›çÿ¬XM±þ‹ù7ÿ‡m>þ?IaÿÇóÿ,˜ÿßÏÿ{êý¿õVöÿu¬ìÿÙÿ—Ùÿoί­r•o؇’Ò·ï]©+"vÁy6Q×iU¹Èþ¿Z5Åú/æÿýüŸìÿÓôÿWðü? æÿ÷óÿþô3ßúÅìÿëXÙÿ³ÿ/³ÿÏç¿Ûº(CS¨:±>7mmEKÆÔÖ;.LÝ*ç­«óü¿«)Ö1ÿ/{ÿÏó')ìÿøü{ëüÿ£ùoüæå'³ÿ¯ceÿÏþ¿Ìþsþ»÷V«Â”¦h[Ó¤+Z|éI—ESpUº’+ïòûÿ¬XM±þ·÷ÿrìÿÉo²ÿOQÐÿõ1ü?žÿkfQ¡ ç¾ùÙ»rXÃÊþŸý™ý>ÿµ2¦©›„€¡òUãJ›>†B›šò• E£²ÿ¯XM±þ ñ?÷óÿŠ|ü’Âþ ÿò¸ùÿþ¯?úwÙþ×±²ÿgÿ_fÿŸÏmû@±ö•ªmB@L ºÒE™–²m[W6i{Ïþ¿Z5Åú/æÿýüÊþ?IaÿÇóÿ^ózüÿ/ýÔfÿ_ÇÊþŸýÿØÿkcZgL•6nå\ÚÊ+­µwmÙt“alSÕ!X•çÿ¬XM±þ‹ù7ÿ'…ÅìÿSö<ÿù?ÿï}á?³ÿ¯ceÿÏþ¿Ìþ?ŸÿÞ´ep†´­•*ÛR‡ªh}ÉŽÑ”e$‚.ÒÙÿW«¦XÿÅü¿›ÿc(?ÿ?IaÿÇóÿ^?vþß¿öÕý+ûöÿ%ö=Ÿÿ^E«‹2´Dm¬)¶¡RuãTã©ò®¤½š½ gÿ_­šbýóÝÿ·Ùÿ§(ìÿxþŸüßÏÿÓw]x$ûÿ:VöÿìÿËìÿ7ç¿×¬Câ?o\Û(¯\hbiZïj›®nÛÊUõl|öÿÕª)Ö1ÿïæÿØüúÿi û?žÿ§ÿ÷óÿ~ãÏ.ldÿ_ÇÊþŸý™ý>ÿµnjÕÖ­'mmŠè•i,EgŒ3¡ Ô²ómC!ûÿjÕëÿvüŸóóÿ“ö<ÿOù¿ýü¿ßÛ}àãÙÿ×±²ÿgÿ_fÿ¿9ÿÕ;n4“QŽjͺæ¦ôMB² ®fg´eeÿ_­šbýó›ÏÿŸ° ÿ¿†ÏÿW`þo?ÿïþù¯ßÈþ¿Ž•ý?ûÿ2ûÿ|þk¨<תP…occÛ¦jcwÎqë­nyÛPk³ÿ¯XM±þ‹ùÙ?ÿŸßÿg’ÂþÏÿW·Îÿ=šÿ÷Þÿúû¿Íþ¿ŽµÈã?¶¾ûèïÆûøŸyþÑã¿PÝñ?UæŽ óŽÿµ þŸ?þ^ÿzkÇïoŃîãvûÿìÉ^¹þd8ϤîÙxx¶ ×7fÿ6öãf|iïà¡—NïílžLŸžþå³³O›/Ï>ž}vöq/´Ý5~pöé…½®ï‰§Ïö—âÑÅÇúŸÛêzÏ>Þõö—ž¹yi~±»¼·³Ýßã¹îRÝ_z¸¿´Ù_:Û_Úë/=Ý]ª·÷fŸ>÷ôìÓvÿ{Ÿëï´¶Ý]œùP×ù2uÏvŸº?©û‹^ÞênáÙÇ»[x¡ÿ™'úŸ9Ø}<ÿÔ죟}8ÓÝn/È3½"Û½çz ¶48w¤ÁV÷·_гO]xlö)ì6³O>õHwÝÕîÒc¿Ô]Ú»Þ]zúÃéÒ»¶þ‹?þw÷·v6ºÛ<þ•64~ü“Êó&©ôøïô–Çÿå­“ÝÇSußÙ—»ßÿªûpét³Nž¸gãþÓWv»?Øðûqçç7ú#õõ[íjúNlüµƒ¸qx9^ߨÞÚ¼|˜~°ŽOîîG¿³q¸ïw®úÃô/ï`cß§®ýÔš®¸÷wâÕíÝp-ÝþéôC—Ò½ÍîÿÊüH¸Ý¾>yâÞçoºUípw[ÆÔé"n»ÙÝi·6/¾÷êîæôH;¼vp_'zH¿ÄN8úù{ýæÁgΜ=Ÿ®¼çè7¿øüƒÏuW߸t:ÝÎ~·mÞ»[¿pÃßH›èƒÝWÓÿýÑíÍ$?u·÷Nmû­«'Oœê¿SûæÊµ½‹ [›[‡=÷ÜÏw7“¶¹é¿«7öR[{ã%gÛûºM×ïâüß~¤¾;µðþ¿½{¼Ûå?ÿ­Íü?I-°þíîþ¶;Ç@o»þjìÿéRöÿIªßæÔéâÿèþ–ë×ÿù7ü/vhñã?D3þÏÇÞýzë}Ñûøû¿R¥¦rtü?ù~ýß$u⢡ã¿Ý݇ñà0îßÿ÷ŸááJós'.6#l¸EZn1ƒÂ-vи¥´hÜâ-·Tƒ [L1h)q‹´8ÜBƒ– · ÕUX^#äÅú𡾠l†+¬°*¬°Ä²kl†Ë Žy¸ ©<;sh؃dN=ÕPHçÔ3\ B:§žáZÒ9õ ׂΩGü[G:§žáZÒ9õ u&¤sêêLHçÔ3Ô™°Îj¨3aÕPgÂ:«¡ÎŒuVC묆:3ÖY uf¬³› ÖY uf¬³êÌXg5Ô™±Î4Ô™±Î4Ô™±Î4ÔYceÖ™†k¡±Î4\ u¦áZh¬3 ×BcIìðXg®…>FçáZh¬3×Bcy¸ëÌC Ö™‡:¬3u6Xgêl°Î<ÔÙ`y¨³Á:³°R¬3u6Xg=ÔÙ`õPg‹uÖC-ÖYö`E¢±Xgi,ÖYd‹u¡ÆbEª±Xgkì1:‹\ƒu–Áë,’M‰uѦÄ:‹lSbE¶)±Î"Û”Xg‘mJ¬³È-%ÖYä–ë,rK uV"·8¨³¹ÅA•È$ê¬D&qPg%2‰ƒ:+‘IÔY‰Lâ ÎJduV"“8¨³yÃaEÞ¨°Î"oTXg‘7*¬³ÈÖYö`E&©°Î"“TXg‘I*¬³È$ÖYd’ ë,2Iú×›H4a¥I–ZDŽô øŸ4a±E0IÜ$ȨÀr‹h’¸IpOqŒà| ¬¸H' ¢á-MXq‘a„ÃÔ$ÖÒajkñ05I\ÅŠ‹£ ¦&±,˜ÇMXqwfD%òŽÂ¨DàQ˜•H< c¢‘GaNT"Ï( ŠJ…IqÜ„—Gr0+*-5`ÅEðQ˜•H> ã¢ÑGa^T"û( ŒJ„…‰Q‰ô£02*fÆqV\ÂÔ¨ä ŒJÂܨä1 Žjt+.ð`t7£¸X; $az$y$ã#‰CA ó#‰Ü¥0@’^ $‰ä¥0BŽ› â$ò™ÂI…<8'‘ÐÆHMaŽ$qÜHa$ä&ÉqV\Ä=…Y’DÞS&I>…i’DšS'IÄ9…y’DžS(ÇMÇ(.¬£¸X;Ì”$rŸÂPI2øaª$ü0V’ ~˜+If: –$3&ËqV\?Ì–$ƒ†K’ÁÓ%Éà‡ñ’d¦Ã|I2ÓaÀ7aÅeðÈI2øaÆ$ü0d’ ~˜2If:Œ™$3æL’™ƒæ¸éÅÅÚaÔ$ü0k’ ~6I?L›$3ÆM’™óæ¸ +.ƒ&N’Á#'Éà‡™“Dð#Ìœ$‚aæ$ü3ç¸ +.Ò!aæ$#ŸlŠ‹àG˜9I?ÂÌI"øfNÁ0sŽš0s’H‡„™“Dð#Ìœ$‚aædü3'‹àG˜9Y>ˆ™“GOBÅÇMPq–Obædù\!fN–Obædùl!fN–Obædù|!fÎqV\>«ˆ™“åÓŠ˜9Y?ÂÌÉ"øfNÁ0s²’OábÅGMXq‘ 3'‹àG˜9Y?ÂÌÉ"øfNÁ0s²~„™sÜ„é0s²H‡„™“E:$Ìœ,‚aæd’Ï¿cÅEð#Ìœã¦ck‡™“E:$Ìœ,Ò!aædü3'‹àG˜9Y?ÂÌ9nŠ‹tH˜9Y¤CÂÌÉ"fNfùâ ¬¸~„™“Eð#Ìœ£&Ìœ,Ò!aæd‘ 3'‹tH˜9Y¤CÂÌÉ"øfN–¯ÞÂÌ9nŠ‹tH˜9Y¤CÂÌÉ2bæd™1s² ~˜9Y?Ìœã&¬¸L‡˜9Y¦CÌœ,Ó!fN–é3'Ëà‡™“eðÃÌ9n:Fq±v˜9Y¦CÌœZ¦CÌœZ¦CÌœZ¦CÌœZ?Ìœã&¨¸–é3§–é3§–é3§–é3§–é3§–Á3ç¸ +.Ó!fN=zÑV\¦CÌœZ¦CÌœZ¾î 3§–/<ÃÌ9nŠ˗§aæÔòõi˜9µ|fN-_¡†™SË—¨aæÔò5j˜9ÇMXq‘3§&ù’A¬¸H‡Œ™S‹tȘ9µH‡Œ™S‹àǘ9ÇMÇ(.Ö3§é1sj‘3§é1sj‘3§Á1sŽ›°â,_ï‰é1sj‘3§é1sj‘3§Á1sŽš0sj‘3§é1sj‘3§é1sj‘3§Á1sŽ›°âòÌœZ¤CÆÌ©E:dÌœZ¤CÆÌ©E:dÌœZ?ÆÌ9nŠ‹tȘ9µH‡Œ™S‹tȘ9µH‡Œ™Sù"j¬¸‘¯¢ÆŠšŽQ\¬fN-Ò!cæ4"2fN#Ò!cæ4"2fN#‚cæ7AÅH‡Œ™ÓˆtȘ9H‡Œ™ÓˆtȘ9M!_ŒâbY0sŽ›°â"2fN#Ò!cæ4òœÌœFž”€™ÓÈtˆ™ÓÈà‡™sÜ„—é3§‘é3§‘é3§¿€—é3§‘Á3§‘Á3ç¨ 3§‘é3§‘é3§‘é3§‘é3§‘Á3§‘Á3ç¸éÅÅÚaæ42bæ42bæ42bæ42øaæ42øaæ7aÅe:ÄÌid:ÄÌid:ÄÌid:ÄÌidðÃÌiDðÓ˜9~3ç¸ +.Ò¡ÆÌiD:Ô˜9H‡3§ÁOcæ4"øiÌœFžý‰™sÜtŒââ "ÌœF¤C™Óˆt¨1sü4fN#‚ŸÆÌiDðÓ˜9ÇMXq‘5fN#Ò¡ÆÌiD:Ô˜9~3§ÁOcæ4"øiÌœV?™sÜ·"jÌœV¤C™ÓŠà÷ßíÝÍ®…EaóžGÝPçïiŒ° vd$ÞžŠ•AÖéÕ) Q’ª Bl 8ÅEûÜÚ‡›3Qü7g¢ønÎDñ;Üœ;¤O´ÃÃÍ™h‡‡›3Qü7g¢ønÎDñ;Üœ‰âw¸9wÈ/Žvx¸9íðps&ŠßáæL¿ÃÍ™(~‡›3Qü7ç=¹8Þ›3Ñ7g¢nÎä/¯º9“¿½êæLþúª›s‡üâü%W7g®ßrõ‹ó×\ÝœÉßsus&ÑÕÍ™üMW7g¢ønÎrs&ÚááæL´ÃÃÍ™(~‡›3Qü7g¢ønÎDñ;Üœ;ôäâxwnÎD;<ÜœÉvèæL?7g²ø¹9“ÅÏ͹C~q¶C7g²º9“íÐÍ™,~nÎdñss&‹Ÿ›3YüÜœ;äg;ts&Û¡›3YüÜœÉâçæL?7g²ø¹9wÈ/ÎvèæL¶C7g²º9‹ÅÏÍY,~nÎbñssî^¼ØÝœÅvèæ,¶C7g¡ø…›³PüÂÍY(~áæ,¿psî_í0Üœ…vnÎBñ 7g¡ø…›³PüÂÍY(~áæÜ!¿8Úa¸9 í0Üœ…ânÎBñ 7g¡ø…›³PüÂ͹C~q´ÃpsÚa¸9 Å/Üœ…ânÎBñ 7g¡ø…›s‡ž\ïÎÍYh‡áæ,´Ãps?„âæ,~ ÅÍYüŠ›s‡üâëƒ)~q~1ÅÍYüdŠ›³øÍ7gñ£)nÎâWSÜœ;äç·UÜœ…vnÎB; 7g¡ø…›³PüÂÍY(~áæÜ!¿8Úa¸9 í0ÜœÅoǹ9 í0Üœ…ânÎBñ 7çùÅÑÃÍYh‡áæ,´ÃpsÚa¸9 Å/Üœ…ânÎBñ 7ç=¹8Þ›³ÑÃÍÙh‡áæl¿ps6Š_¸9Å/Üœ;¤o´Ãps6Û¡›³ÙÝœÍvèæl?7g³ø¹9wÈ/Îvèæl¶C7g³º9›íÐÍÙ,~nÎfñssî_œíÐÍÙl‡nÎf;ts6Û¡›³YüÜœÍâçæl?7ç ¹9›íÐÍÙl‡nÎf;ts6‹Ÿ›³YüÜœÍâçæÜ!¿8Û¡›³ÙÝœv˜nÎFñK7g£ø¥›³QüÒ͹C~q´Ãts6Úaº9í0Ýœâ—nÎFñK7gó«znÎò‹¯oïùÅùa=7góËznÎæ§õÜœÍoë¹9›×ss6¿®çæÜ¡'Ç»ss6Úaº9Å/Ýœâ—nÎFñK7g£ø¥›s‡üâh‡éæl´Ãts6Úaº9Å/Ýœâ—nÎAñK7çéÅí0Ýœƒv˜nÎA;L7ç ø¥›sPüÒÍ9(~éæ¿tsîГ‹ãݹ9í0Ýœƒâ—nÎAñK7ç ø¥›sPüÒ͹C~q´ÃtsÚaº9Å/Ýœƒâ—nÎAñK7ç ø¥›s‡üâh‡éæ´ÃtsÚaº9Å/Ýœƒâ—nÎAñK7çùÅÑÓÍ9h‡éæ´ÃtsŠ_º9Å/Ýœƒâ—nÎañss®›sØÝœÃvèæ?7ç°ø¹9‡ÅÏÍ9,~nÎzrq¼;7ç°º9‡ÅÏÍ9,~nNnD¤›“+éæÜ!¿8Û¡›“séæä Dº9g}{ùÉÅñZÜœœ•H7'‡%Ò͹C~q¶C7'(ÒÍÉ Štsrƒ"Ýœ¡H7'&Ò͹CO.Žï9»99DQjÎàE©9ƒS¥æ nQ”š38FQj·]<8YQjÎàfE©9ƒ£¥æ ®V”šó ᵨ9ƒ»¥æ|ùÅÑKÍœ·(5ç»Ss.JÍ\¸(5gpâ¢ÔœÁ‹Rs>„üâh‡¥æ Na”š3¸…QjÎàF©9ƒk¥æ N]”šó!äG;,5gp£ÔœÁIŒRs71JÍÅ(5gp£ÔœÁYŒRs>„üâh‡¥æ ®g”š38ŸQjÎà~F©9ƒ¥æ .h”šó!äG;,5gph£ÔœÁ¥Rs§6JÍÜÚ(5gpl£Ôœ;¤æ Îm”š3¸·QjÎààF©9ƒ‹¥æ Nn”š3¸¹QjÎàèF©9BO.Žw§æŒµÍ¡æŒ5Ρ挵ΡæŒ5ϡ挵ϡæ|ùÅ¹â¡æŒ=ãá率š3Ö‡š3Ö’‡š38åQjÎà–G©9Bzñ;Û¡š38 RjÎà.H©9ƒÃ ¥æ .ƒ”š38 RjÎRsDJÍ\)5gÜYüÔœÁ‘Rs‡FJÍ\)5çCÈ/Îv¨æ Ž”š3¸6RjÎàÜH©9ƒ{#¥æ Ž”š3¸8Rj·_œíPÍÜ%)5gp—¤ÔœÁÉ‘Rs'GZÍy†0¶ãæääH»9wèÉűÉãæä.I»999ÒnNNŽ´›““#íæääH»9WÈÍÉ]’vsr—¤Ýœœi7''GÚÍÉÉ‘vsrr¤Ýœ;äG;l7'wIÚÍÉ]’vsrr¤Ýœœi7''GÚ͹C~q´Ãvsr—¤ÝœÜ%i7'wIÚÍÉ]’vsr—¤Ýœœi7çùÅÑÛÍÉ]’vsr—¤ÝœÜ%i7'wIÚÍÉÉ‘vsîГ‹ãݹ9¿äЛ›“»$íæä.I»9¹KÒnNî’´›s‡ôâ_®Ù8½8wIÚÍÉ]’vsr—¤ÝœÜ%i7'wIÚÍÉÉ‘vsî_í°ÝœÜ%i7'wIÚÍÉ]’vsr—¤Ýœœi7ç=¹8Þ›“»$íæä.I»9¹KÒnNî’´›“»$íæÜ!¿8Úa»9¹KÒnNî’´›“»$íæä.I»9¹KÒnÎò‹³º9¹KÒnNî’´›“»$íæä.I»9¹KÒnÎò‹³º99^ÒnNî’´›“»$íæä.I»9¹KÒnÎò‹³º99^ÒnNî’´›“»$íæä.I»9¹KÒnÎzrq¼;7'ÇKÚÍÉ]’vsr—dÜœÜ%7'wIÆÍ¹C~q´Ãqsr¼dÜœÜ%7'wIÆÍÉ]’qsr—dÜœ+äæäxɸ99^2nNŽ—Œ›“»$ãæä.ɸ9¹K2nÎÒ‹s¼dÜœ/7'ÇKÆÍÉ]’qsr—dÜœÜ%7'wIÆÍ¹C~q®»9¿Z3Å~qn»9¹K2nNî’Œ›“»$ãæÜ¡'Ç»ssr¼dÜœÜ%7'wIÆÍÉ]’qsr—dÜœ;äG;7'ÇKÆÍÉ]’qsr—dÜœÜ%7'wIÆÍ¹C~q´Ãqsr¼dÜœÜ%7'wIÆÍÉ]’qsr—dÜœÜ%7ç=¹8Þ›“»$ãæä.ɸ9¹K2nNî’Œ›“»$ãæÜ!¿8Úá¸9¹K2nNî’Œ›“»$ãæä.ɸ9¹K2nÎò‹£Ž›“»$ãæä.ɸ9¹K2nNî’Œ›“»$ãæÜ!¿8Û¡›“»$ãæä.ɸ9¹K2nNî’Œ›“»$ãæÜ!½8ÇKÆÍÉ]’qsr—dÜœÜ%7'wIÆÍÉ]’qsr—dÜœ+äæä.ɸ9¹K2nNî’Œ›“»$ãæä.ɸ9¹K2nÎò‹³º9¹K2nNî’ÜoŽN“œ©'7¦üè\,¾¹;R~vß\ž\'9S~xNßÜžÜ'9S~zîß\Ÿ\(¹ßœŸ\9S~ûzr{¾G(WJΔߞÇ77(wJΔߞûÅ7W(GHΔß~§üöÜ9¾9D9Vr¦üö\:¾9E9Wr¦üöœ1¾9F¹Er¦žÜ~¥üöœ;¾¹G¹Yr¦üö<¾¹H¹Zr¿9I9[r¦üöœ3¾9J¹Ir¦üö;å·çìñÍ]Êí’3õäö|C.S®—œ)¿}ð ¹M9Mr¿9NR~ûà{tžrÂäLùíƒïÑÊ“3å·¾!'*JÎÔ“Û¯Ô“Ûó=ºR¹dr¿9S9er¦ôöÜ29Sz{)½=‡JΔÞþ!¥·çžÉ™ÒÛsÐäLéí¹hr¦ôöœ49SOnÏ7ä`å^É™òÛï”ßþÎ÷èfå®É™òÛßù]­\69S~û;ß»•³%gÊo¿Ú£Ë5V{tº>¤žÜžïÑñ«=º^cµGçk¬öè~Õ°±Ú£ 6V{tÂÆjnØrÄÆj®ØXíÑ«=ºccµG‡l¬öè’Õ²)¿ýjŽÙXíÑ5«=:gcµG÷l¬öè Õ]´©'·ç{tÓÆjŽÚXíÑU«=:kcµGwíçY“ÿ/Ï_^¿ûùÕ·oxóñÕ«÷?|óêÛ׿{ûþÝ›o^½}÷Ó›wŸÞøù‹¯¿yýáÏ¿øtþéëOozóõ_?¼ýøéí»7¿ñïq;Ÿ<ŽÏ¬ä??_Ý_üíÿ¡™õåYd_œÀ9ÿçóâåíßúoþ÷çÇŸ^xùò<ćïÿYî×þúéóÝï¾ù§/¾}ÿþåý¯>ÿäüñóOÆúìz~—ç·üüŸÿqüK_ýù¿Å?üüç‹Û½î_]?ÿ¿Ësý¬_Ïõ\Ïõ\Ïõ\Ïõ\Ïõ\Ïõ\Ïõ\Ïõ\Ïõ\Ïõ\Ïõüï=¿æÃ;P#darcs-2.8.4/tests/data/old-with-checkpoint.tgz0000644001765600176560000000575512104371431020632 0ustar ganeshganesh‹%ªJí\pUB¯ÀTAFgYHÒ4wÙ·»wa›&%„644)”&i|»ûîn“Ûîî]záJªÃ8e„Ö2ŒÀ "X…2üA‹u¨ÀTF‘‘?˜u¦€ß÷v/¿(¹I/ïÓfwßïï{Ÿï÷ûÞ¾Ý='oÄÇÍ ×sXsÓÚ<@UyrTyƹ‚A“jRTxâ…¤"I œ¼Ø‚ ?@Ç5ä v€LûóUKÿˆÂ9 ÿÈv‚öâ3£ B°¢Ì‹Y•Tà_’|Ç/FãÕÀøÿ‹Å{µð/ „9©JŒÿzàhüÈÓýÅ›jñÿ‚ ÿ ¯¨Ìÿ×sð`èq`ñˆë™~`ÚÖ)Ô`ÿ!ÿàDÙ=0ÿ. rü@íö¯Ê‚Â쿘ÿ"ϧáŸÈ§DYâHK©8R3É4Ò$&¥”¡fÒº¤a—S)È%FF §3‰ìDUûkŸ¹þ—x^T™ý×gì:1¼8î ¿ë8e'·¢á×çÞýܽߊïÚs×»·:¹‰Ínüö“¿øÜ{ûnLÿáµ Ÿyö·^úÁ+·Çû‘ûçÄ9Ùß—®=á–ïm¼éš½‘G_G§4ù«‡ZϺygÞ³âÔ_츮tœóÂ-;>}ÿ¹7ü¤çùm:ò©M/Þ½Ç]ÚN3LböïbÛ0ílbr=PkÕçÿä¬ù_â‘Ù=pyl{l©e`X:Ìßþ?|µØ?ÿE—Ùü_0ûÿd£¶õ¿$+Ñú?Ãc9ͧܤàæNÔuUÃXLc¬Èr&-(I¤#-­ÌgýÕNîÿ)R’¬ÿ¡MfÿõÀÔúß:tÞòÇøWþí+Ö¾r•ûÈþººÜÏßÿòu×Þyòõ—<ŸydzwõúÛoÏþñ²/¿uó›Ïp»Vï¾ïàÆMßxõWŸÛr8¾ó¡¿ì+íþÒ]zúÿ=_Mx£Þ÷¾þ—>ãì9ñìV¦Vß°oèžG¤‹o:ã;'ÿë¡sžøöö[s£Ïæ'ÝÔõðw»ÿs•ZnøÙ[£/>°´ãòIAmöÏKjdÿIYà3RRJ¦$MRæyIU]UŒ$°¢i)Þàõô¼îÿåÉù_–eæ•íÿ× Óîÿ<ñÙ+ù“ž¾|ß«—õé-æk'<É}å홋=ÿÎÅ¥«ï?¸rÓcßoùêõ¯ÿ°£á½÷ÄÇ[ÎsþYðÇKg÷ž~¨ïéÝûVÿøµ»…®uJã7]}ó®/ÿô—ïnxäÈáM_[Ò^2|æ°Ó.¿㙠ݮyÿWäÁ±°ýßz Ñ–h[½Þ±³ëM{ìµQáøÎàÿgê/²"4pë‘<3Páßsœ`®|ÕÒ?¢˜§ý/ø€áÿõà¿êúOfú‰O*ìþ¯.4m30Q>`?À^KËÌÕ~ŒëÉÚŽ‡ãAÎôÛ9Eå%!#¦”´‚4QOé¼”NjXDšª¨†¨Ä†¹¥îCM˜‡ý—ÚF5û—qöúO&™ý×ýÐûÀ´³Q.@ÙöØà@G77¥\{øhî&‚Yî!Åc©R2­+†¬È)’O22 ©Ƽî!6è:~0­ú£Õ,ˬšåŒ–ÔR8© B–‡‚¤I¢¦#œB©’Õs<sØÆñ,´kުϦì_Uúþ¯$°ù¿. TÇ…Ïž}"1‡ýOÅ,Áþ/°ýŸz`žü/h-XõùŸ*Íâ_”¶þ« ŽñbïXÖ¾ÔC÷±Ûÿeû¿óðÿlÿ÷cŠzð_uÿWß·ÿ+±çÿuÁÔóÿ]§|=¸ô‚'/è}2qð©C«.>xAü´ôÄ=ñÇE‘ÿùñk[Þ¨÷K‰eOýûá#· üuÏ5‡´UË–ïøM—¯Ÿú„qïiýRÿòëÚÿ¾wÿþÛ»ÞÜûÌÀÎÓîÚüÍßîÝ»ÿÐÍËÎÛ¾âÀ²†ŽýåGóKÛi†IÌõþOôÕß‚?«åþ/üþœ ûþ¿.˜ÿ ý=€ªû³¿ÿáíÿÕóá¡¿P ÿôû‘—6ÿ×sò3‹ò+5øÿðýOòù7ûþ·.¨Ê¿åÆÛ¨ÉþUjÿ /Ìþëªük¦È+@ h£ÿJRÍ¿*³ß¨ ¹5„àG&yÎÃY¼ÍõÛcC ×Î6Á©ï¢nrÊNc÷rt Mé:ŸœF]šï¾î0„£àÚ°œIóv÷мA˜ U‚4ìÚVØb/ iahMʆ¡î0䆡>Ò,—œÖôö‘“ÊÝÊ ÜÒ&:6Òœ"͹…žh—h&LZÖZÃhXæÂ°ŒïcÿrDäÐAë d +ƒÞp ¬h z£10Ã*zÂ:ð6LNk7¯%'ÃÑÉ©kC'MËÓÐÚõ4ä–h¨ï23þ«Û¿ã-èãφªö/©0Ùϲÿ¤$3û¯Àþ)Á³ì?ÖØØÈéŽåB¬Ç!Ûà@1°*ÇðÚ†‰L ú±F.‡ü1œÏsÍÙœ¾2Ì’A:$ %rf=Æ5Ç È¥]5rŽ6Šõ ªhêPB· ’êz¤ñ¢Ú‰YŒ„Õ¹#NÓ´f!kÖC]ÄÊ’¾ønbZ ¦q¨×ÙFKC<)žq¼ÀC6g9F!'å€ I…‚…mÜölLš«HF3ÀuS¬yk¹m%Ôj¹#Юo:¶ßÜQP¸ò‡rÈÃö9Ú§•8gP!1XGsp]â,3›   †¹uއA*"šŸG©–ó¹ ‡¬ŠIMFŸGG¬ä»•ÃÒýVn´4鎩SÔáiÎFÏ#ߟb§dçMÍ£³þ¹\Þ céI'B@GÈ@5C±2*ƒW+ûN9ÿÑJR[¤;7áç `gÌlÁ£™ã‰qäìt, b×÷ô÷qN!p ‘6j¸NMèìÝÔ¹ž4˜A~þòeß7•)oK)h’j¬V0óÍî"} eÉhû%?À#i(?Cy‰¦  ¢ÆÝ±l<•ø}ÜJ°‘ƒ<6¸E#ª$lÈ0½Ö5Îv™†‰èô¡¤9F Jo5àVº¹­ÜDô‡ ¢* ZÉœp¨=4%lºœw²e (øtl-S÷ßÉÜ8Ö80XPu¢y­\Ñô  Óá, ˆÈ ÔÒ7¹cC#ÅÀÑm2õÒK·H 1Kžï;\(ØPÂÃE»qÓž&ZÂ`Yp )Ø6°­“ ·Â,FÑÒTeÚø£.w^Òvú\ôMúÜ·)Ìi.¨>Fën„x˜Â‚;£‚­E’ß/hQk;ô‹vÅü,ìé¼Ú¥å²•¤¬T"ᲫMxtàѪõJ›ý•F9:1†Ñá$9-ãa× c·F1qè¾·™oŠÅà ´³à¶&Ð><¼ŠR`ÀÈô\X_óЪrkTwÑ÷¡£Ð=Ú¬?îFž§w`º—“ÒCÛ§E%HLÜ4&’fcèòÂô5f°Ž§•é“Åý8Jªeú:xYdc§@¨ ;™òtm…ÆèÚªcuCäÛQ4LåC§âaê`ˆƒ‡ø&ªd£$ófÎÇôbáØDŽêœiW–nņCñrKóal5R¶hV4&@ÙˆšfrYèèî'æ‘3¸µm˜ú%ðbFÁrüå¡ÄJ=Ò>—¼ KlÛsÆp䦸æu= [â‡Ì'zK2“Bã(æl…N`.n{[q¶‰¬ãdó8ž°Ímƒ|m=ëø÷‰áUñéš0C¥ˆÄÇ}Ý3]Úô”sÀ5š`~^%SWÿH@;Qûü_uýG¨p¼­1ªßÿ+³¾ÿå“ì÷_ëƒðeœ¥–‚a©0¯ßÿ\à— Õìÿý߈ûý¿ú€}ÿÁÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀðñÂÿ"Žxdarcs-2.8.4/tests/data/oldfashioned.tgz0000644001765600176560000000651112104371431017404 0ustar ganeshganesh‹,šzLí] pÕRü8;E¬X­S}c¢\ wÙÝûØ¢HB‚’*„øv÷íÝ’Ûîî%¹p¨ –Öê8íø5*ŒøU[±ŠmUêG ­V-~V:X¡jmu´¡8ý¿Ý=rICâÉq›ý‘äÞ¾¯ÿÿ½ÿç¾»=ô´$c+¥è‘j+Žcè+;ì5 –Fâ16ưñ †ðSbG‰Ÿ!ÈX66ªPuS“q:}¸~cµI¡Ê¿[¦h•\ Š’”ùCõå_Œ$Ã$r)µ ùGyžùÇ# ïË¿8¼üEæB¬#§AVþ,2"Ža"ñ Ä9é±1Áå_‰ÚSŠ…d%M¨k6V4 a”V,é2"ý6Ñ$"!“$3iØ(ÒÚaY /V ¥A1•Ð_#a„æ¹ØN!ÛbJÑ’kY:•")€.¶¬Œ ÓÛ:LâÑGŽæe‘„mŒ‚šn#ب†éÛS0fS­DÐïòÚ°«°yUEAE†yÈÀ¬jde #MTôu Ãìü‚ÃÐ~êÓXëqVKšä‘@’ЦÑô)°¬!]´u˜Å4 VV#lÂtIM7‰Dgj#„îéòÕHÖMØE‰X¢©6¬v¬Í :ÃAœ›W]E ‚jäê[Z½‹.W¿‚s/$]ÌÍ_Òà^´˜k\”¿è'¹ÆeîER‘s 𛼋܂nQ±ô\sÛ÷b6sÏ[ê]dn2wqkãÜn…ª%s-‹óNkË`«Ñ¡ I£K͵v,®_ÐÚÕâUKr®u¾G×€Zó3Y1׺Üã¸È3Ö—kÏ3a«íy^mE–çæÚ››šæº9¯e@1r+šéöŒ·ù|é1Šÿ×MPþRÐÃÿGxÈù‡Æ>Æq¾ÿ/Àý9rv·ã¿ kv PYIý±j@­é8EE³‰ šÝ2¸mÛÄhÿKa«‡¤Ó(˜L‰Õn‹ÐÔN)UÎß ë6-ê^©éÂ*"ÚÞ$Ðà´v†EU¢­†©C eÏ›Znw:£[¯* ]“&Vé^bâ$]‹e„ fP4Y‡a¶Òz:µm‚oWu)“&‡ø€Ë*7¬eúQ15BI÷ä9s:@¹*\™«­†YU£è:®ùö_œõƒãÝÂä–?Ì;qsJÅ[Lß›–nl˜¶ã‘ûú¯-Yóò¦ÅËŽ=cÇS§Î{têÖÕš¡¦_~´gœŸ¼|ÎâÜFyïW¯ÿÙŸ8§ùÜ{Nšý€ôsSEí†ÛÏ×oyó‚©ÁÕ[?Ú]þü}÷¬¹÷þW–¶mºzÚMß=nëÚ¯ýù‡ì®)ïukËÖžß­ïÑ÷ÌžvÁ¾)ÓQÅþ;ÇuO&>Gü?bÅdž²¾ý—~üŸØø¼ñŸ‹zñ_ŠÈ<‘% |"ë)Êá„È2|‚F‚ãD’D¦¨ø?ÜþùHÜ·ÿ²  þ?ÿPàiæ¤+wܸçÝkU³ùºéÓ.å¿3}}å¯v¾¿fÙŒý»¦Ï·ì>ã3kói‰Æ¯Ý´¶½|ÊÀ‡ÆyÏ^~‡¹ªÿ´g«>þYð"åÞ×Ú{ôšåO>kY~³õ—]ñà]W ³ÞÿÖ”†ÅÙ»ŸØ²éܿ׷=3å¬'Ùø.´ì’½¡_|òÊ'Çj>]òÎ?zuÆãÑí›Çw[& >¯ý³¬gÿ,ËÊ‚«ãe>žÀ„‹Àø(dÿ,Ž0u2Çòl‚aD)Æþ~Ðþ9'ÿg¢þû¿eÁ ý7nsì¿âO·îywÝ¿Ãn™æÚU߃OÅ×ÞÚòŸ¾ýׇëÂ'Ìì|äÔÇßÙgN»á¯w¾ôöÍ÷¶¬XÒ"~ïûMbö½ùÉçî0w´¬ÙöɤØðè«·l[òëG£ûµªí½ûÎ<óÓI3Î~è²ÇnºbúÖ}“o;¸î‰µã»#Ÿÿ+–­h¤TÀEÿRûgypþùo90ªüK¤ÅŸÿC†éþ»,Cþ¸4ƾÿç†ËÊ~ü/°÷?¡1ªýgKC£(ûgøÿ|û/²¾ýOhŒjÿ%z"ô åþóŸeÁò¿üÏÿüWYàç£Úih|¡üñí¿è÷íBc$ûW´^ú0}\¤$ `ùß¡çÿ"1?ÿ+F–¿DJäúŒåÿã\tØ÷Ä9Æþ¿,¸¨­9š/ß8É} ¿ìÓǼøÈž½ÓöÝ’Rþæ)l?~Öq×ÇÞÔº~ó§^0?\QqŒ7î+· ,Ê;ïá¶l|lÆÏÄíâÍUÛ>X9ãêovüþ™÷Ÿ:ñG×üãø¾¦ìà¸c ÆYÏÕ-»oýýÍ‹îæ˜¶Iºw¾¼¡þEáÙÅÙ]wýtû›› ðyêELä¥9—¾!ÿæäÊV\µãt.óЩÍSïüú«ûÿ¶gíëóÉ ½Ó=zSàw}ý ¿;ûÊóÙcW®~aξ¹ogNÙwÞZýÄÀÔ7/ûí‹çlovö}c14¥Ašß(†f‰î·ŠÁhþ¿DÇcÚ”¿ÿc£~þW:ú‡ó²Vb›h©.ö`ÍQÉ…ù‡5b_0sæÐƒP³óÔfˆ~™ÆlÄÆëd‚£‚,r‘yKD0_ÇÖáx„‘™D]  :ÜsI1„Xv!Nd1"$X!Ê&8A&ñ#³±:³ ^\:µØ¥T‹‹¡ÅE‡Ñ"„áâQ>Ɖ.Æðª™b‚‹ÅD9ÄÆ[zGŽ‘ì_ÖMÛ¥£1æýËýÏ÷?ñþûeû<2füûÀ ‰‘ìÿÐó~Ýù“ #£1¦ýóÃ?ÿË2¬oÿe–$ç›_Âô°?Êh=n±Y80ØJ[I¾u¼y÷qäbÿ%ûÄßPõþ_„ÞÿGçüóŸ£aò?*÷ŸEÿ»òçüü¯<ð½øÄÆû/ÕÏ0eÿLÔñÿŒÿù¯²Àÿü×ÄÆû?Jÿ@QùÇ»ùŸÿþ_Y0LþãŸÿ¹òøþ¿<ðó¿‰!ö_Ê7ý P\þÇQûgxÿýÿ²Àÿü—>|øðáÇ>|øðñÿÿŠx†'xdarcs-2.8.4/tests/data/simple-v1.tgz0000644001765600176560000000606612104371431016567 0ustar ganeshganesh‹[ˆ¾Lí[ylÕ·‰°”%Q%Ú¨O±[ìĻ޹vvB µÄ8‰ƒe›røÒ›™7»ïš™ÝØf@=…F¨ ¨ån ªÄP E$‚V@[DAZŽ•¶@!ˆ£H”C$m¿73koâÖkѼ_œÝwß{ßõÞ›Y¸NGÓÂ" %‰~s²”­ý®¢‰ãD ÊDŽš²ðÁg›´À|E(ûöj*`›øÅn7Wý§•ÿ¸Ž=Í_05˜—üyäÏKÏäßÔÊ? v€³BÆ]ÏôÓ&õ¡AœÅ”?ÇñÉ?'få&”­ù#ã(—UÒkÑÀ"¯HF–¨ªžU^Ò‰ jž“EI0d¢bU—ò²nXWUª Iæ0‡³6ÄÔbÏ„áã Öþ] æÿ…œÌüCp¨üUÇ3íB=iÌáÿ™Ë$‰ËŠÌÿ7ͨ+’72ÌA)I×_“J577#ͱ\(õ¶udÚñ@Cà3N[D7q@¢Ž~ª±?AJ%ÔZ(jmqkP5’)š-ÑgZuœ€&$ÕŒuÑ‚d¨ˆjG2š¥ÓZ×s †²—Œµîx<œ;î´Ô…¦[Àt…x¸@çâ»™šLÛp [`NF½¡œv7/ð°,G/—È ¥µÐ±<‰&ˆgJz¢ÊYÔÒ-©Ö±°£ FµÜq ë›Ží·¶@t^íãöˆ}F€bÓBê‚؉Ë%(!.ûE2…,³P  £JÐfÇ#ÀeÍ/Áž †E†V4…Š˜¥„kºú”¹hŦ‚¢c·#baÍoGÛp=“æè„Î{jXsFé HI£_Z ûþ¬$üHØ%Sõ°gÿLTrâL'A+Ç)0ºP­Ð-Ä!™$¡ï„%øÃmt´Dwt4í!cf¡ìE™YãéímÙíX”néìGN9pˉ6PѠ2ÐÝw^÷JÐÀ~ÿK¡ï‚×2ÂÉ|Î’‘ƪe³¤GÍ]¬Mà]mʈE×HÃ*. ¼” ÓPVÓîD!³ Å> Ên5ÛŒ  ^RO‰ é¦×K ÙfU”uú0¥:úôÓa—ÕÚ¶P½ÀåÀ¡‹èÇÊC³–ÖŠ$Öž¨&&S.9…Ê~´¶–©yŽïÚNT ªN5¯UL¿ ÜùAY7d‘ë8À”O­C𝿏fƒöÇI·b6ÿŽƒbÆF2©èÄM{$šifUÜ,+™B ±ubktÀ±‘LœOd˜zàªÔ¬%™r÷Wãiœ+¾Y°AÛ[â‰æ‚ÚiÑØÍPÁ)î8Ðtl¯Ðö~YM¨UíЯØU󳈧•=—ªuÅBµª`ÕBHVKÕi‚Ïhh­Js°»J´Eq2.Žcf´`h ¨qéXR’†é»i ›¥–T:.QA;ËîððÝÖŒŽ®ŽD`—ÁÈ´b<^ëÈê°=»âû0Q˜žÙ¬¿ÝMp'ImÛs&Hâ¦PëæÞs¡“;…—Ä̧zKÓNÛ±·l‡IT wMGu¶™‚ãJ$ž°Ãí€vU=tzVö™ÑÕéZM8@¥¨¤·ûšgº9˜)rÀ5š`~^µÑúÁñÁ šÄüãÿaö 1ê)ê·Ç˜cÿÇñ²|ðþO¤÷lÿ·ðhFCEÓwÔcc‡Cœ÷ä\êé©ñÊ%X¨ÙhïØQWm”H¡Îx °þ"¨*¸ ±=E‡‚Í ltjú#  {2Äb;‘mFôQ¤°G¢¡«•ÖØhƒá‡Š0DÐNãèÒŽØÁΨ,j5 ê4 ðÛ B¸n‰XÐ è;@ºÕ g -üu[›ˆfSŠw?„h¾Ë¦ØnÂt`Óå@ …Q<— Öæ¶h?Ç.Ž4H’ýs«Üm î’Øri8œc13tkƒÃÎ6ê[UË »úú“Ì4v]ÄÇÝÑÂõçvÇØÂ…¶T3°ÛpÁ†8S0°§wc’™{.Š“&lÒzÏ3Û°nêH2.YW7õoX×Xv!ìÛZÍDµ}³µî°­ÜQ+ìÞÚÕÓ?Ú—ëFØ¿>¡ëÂýÕÜ)-ì¿0Ḩ2Ö®:a"V‡ª¼¦a¬ ‡z7n\L‡IÍ´é†õÒåYlóùÔãPÿo9^_sÝÿzÿ#JbŽùÿFàùSMê8ÿç?þ9vÿ×NþÕ}™$¦E^"<§‰"eQW.oª”ã9óyÝÐàȪ‰Š$‹Šªåu¬k$/e9MÍ^â5.јËþy^uâêå'äïÙ{ö³ä]üü7†ÏìùÖéË_˜üÕžWOX±÷ôWïÜõÐð\fý‰/o;ûÝ'þ°ÿ¤sÚÿñïŽYv»Û}Ýâ.ÇQ‡ÃÙ?½Ì©ç#€¹ãÿAöÏIpdöß\œº„m¢bÁþ33ïƒ|Bó·YÙ󿆀ÙÿÑÏÿñ»@™"ö‹D¯Û9pþç?)'²÷?‚#É?oä5E…cž @*¯ Š CBƒ¤FÏyX󆢊ÄU%‹5¬ †¨è’ å ¾JcNÿ/ÿd^`û¿†`öü·ú‰-›í}ù˜¦¡ìçú_\®…#Ù?Ô¬&м’74NãDª!jyEɪ‹¼Œ‰È1'*ª"ˆIQ8UÎK¼š—fÜ÷œö_{ÿCïù/³ç Á¬ý»¸Œ0, ŽdÿŸô•ð*¹ìŸã‰ÿ\Žÿ‚Yû?éáÎ¥ %Ç=pßOïúöÆW ôÓN{kÿ¥7>å¾1ýç{¿6ú»âÞ;{ߺÍËËÿö©×Ï_9²cizéäUßmºùªµß·ÿ³«y÷ÖÅ Ã|Qkÿô¥¢ÉqÓ®à’YÏGÀózþŸÿ„,‹ÿ A­üc·O€¾ êMÕ‹Æ\ò9áàßeÙý_cP¿ß o7UµDR=ÑB¡A3°åâ¶ÐÚxñ¾B°3%óìU«ø,ÿxP ˆþ\ õF/R¥é»Yk!ÇeóY kXƼž’—Ïe%‰R£(E•u ªã£ê£óô@ÿ¾Yçw@>ÆýÇÉìþ¯ø(ùW KÒyž#r^ƒû’µ\NEu8¶!'0+ ö”㵬A4Ž“2tk¼,fóRì÷üþ‡tÈû²À~ÿÛÌîÿ¿tùc©‡²§4½õÁ7œøè›•{w¬ü{ßÚ‹—|}ßže¯;üÏ÷–߸û3þÔUÜÖçVüë¦W^{âÅ»_}ã¶kþ²Ï~ÿÝO?3ðÌS»œÓÙ·©iÅÀ•ß|Ù‡/î<óŠWnïI­<îéüú’{Þ|mô»í³öuþmù5z—öøóþéËölÜ»ä¶[ÕŸ÷ï&ù÷]{teÉ7<Ò¢?»ûäŸ,ßñàâ.Óÿ-jíßp< õ§1÷þÿà÷ÿ9'0ûoâ=ÿѹ÷a8ÌùhÌiÿríý¿ýþŸcÏÿ‚s{gîi×&ßôIÀ‹wþºëû¾°ìºßyäZgwËwt¾¤_Í–[w^ûùÉ]ç­Ï,¿ õEdÿñÉ}ÁhÌ#þ 9ZÎñpdöß$—6‹ÍÃÿˆÿL‹iGxdarcs-2.8.4/tests/data/simple-v2.tgz0000644001765600176560000000546612104371431016573 0ustar ganeshganesh‹ð{ÀLí\]lG(‚êhS©E*B( µçÄ÷±_·wn!Änâ:‰[Shk;ÖìîìÞÆûÅîÜ9çnCUB@©*¡ò@B¢P¨Ô‡HUÚH¥¢}húB¥J| ¡ŠÂKÿÙÙ/Nš«ÛËYUæûnv¾þÿ™ÿç쮓(¬í¹¼¨tMcß’®Õû¿ ì‘$µÁz5dè'I |!í2ó•¡“P#´ÇÁIÚoßoPûû1“ÿš…c3¹lj°sùËZ£.ä? ôËŸ’€bêvÉZ» u2LÀ U}[ùK’´Mþ UR÷ úpÈ_W¸ü IO)ªU¹¥ÙubV½Õ’5‹(-ÅhJºª)¶N lXZS·l[†aC³­é–pÝÆ¶ºÛ xWè·ÿ(&öåˆ;ñÿº"ƒý+ ½!üÿ(p¡üYM2Tý½±Mþª®6„ÿjíÐ'5¾¸Z¦3ô#Èà~i¯tÉ.L[äÒn¯BàÝâBûOÂNl’az€ö/+Ûò?M©KÂþG&ÿ©w`á´í&אָpï'\hÿF»3Lì_Ñ¥ÆvûgGBaÿ#ÀšÎäl×#(&9%S¥ÒØØbv µ1Â…Ü€’4>yÙ'–‹)É&¥1ÔÆÉ:ñ+FRV óÒ “Ĥù$е®TMßb­QB c/ŸZ£5>]´Ž÷‘…®NŒ}`ºKbì°µ$Qµo7°CFÝSÙh¨gÃí0¦1Zœã.Y+ ìœBë$#½^p–u€òx©|"­MÀ¬~´t7 ’ò8TÁàýПOˆpL‚ÏPÄM =ggÜñ †˜¸“DÛ¤‡|×iSht,Œ pÅXK·¸€Â:¹60Ñ ™¬š103ÿř㌠“~½4‰ÀkÙé©fÃ’™Æ׳²î6×±Ãv;é%›Ø™ØÀÞyÊËØpð°Z‰Ö gªB;Qq9† O^ÒÊ'á„,7žäRCAÈ„YH˜±N@zFhõ`ô ËMh¹–Ž3½À²ML¸ò°K_¥DÍ6áÚ“µpâ°d/tR`€v’lo}׌Ã$´)Ú ƒUgš7‰ºnÒîÚ±Üù„b SÌøцL ¥•µ.u×Ì´Ÿ£nfˆ €)Ä[©Æ¤k‘¨“l¥Õý¼X™B ,˜lÂ+U~Ë 7&tƒªôí7_òÌ—ù2aÍÝÄuÐöqÞ!×\P;s=›{ ê!8ñwÎä'»¬Ò1rj…&Ý 0?ŸÄf'v±W´µ¢ÉqiQ Å¢ÖØŒ!øÌ¦6 š‹3Ñ1”ÅI^ÍcfŸ´`X ¨¼öD^Sa©QÅÇ®7^ªð´³-/OY.00µºz AÐ#3Û|¾òÊt2Ÿ»›$°PXž™Ùl²åžg~©Ÿƒ{Ùè•ûúªª¬¦âZ眒áÒuâŠyû´Ke—}cfÀÁ8d‘ä“ Õw¼,ÄÀ°ÃDÉ›òiÆ“×Ù×ô¡c™ÂÔl#Ð80Aìq§“ÌÁ0õã™’dïB ‰a}PSå%°‰v¦s®Ï\9Xº_Zãì-µ;¾‘ÀÞll×-4†b'M™Ó¥C³‹Ì\rá,Ÿ¨­f~ ¼˜Õñ#Þ7]©N˜¹ö;¡.³í8\'¹›BåcswÀ ¨‡Âˆp–0½eÙ  lóž“°‚Ú”FSµs¶U' TÁÖ¢ô«zåÊ–ì««*ýšpžJ13¨l$fìF9X) Á5º`~qÑéÖŵEš-bçñÿ"ùHŒyŠáåò?IÖõíùŸÊžÿ‰üïòc -ÁÉŽgÌcc‡CœO( m.”yzf¼Nǃڊ6 ña@s%Y¢Dªâõ·AUÁ°`ˆƒ› ’HtúÆ#  ¹Gb1„Ì63ú(Ó@È‘Xè*³ÀJ ˜~© @Tí„0ŽN׸ƒ=§²¨ìÚÌiP  H& BD‘G|ôC Ãh±à*ô…ŸipkëÙ `I<û"Dsð][À† ˤ+„ ³ÄA屉,â±Ëb3-’<.ëYq—pËeápÀfVYjƒÓCÌ/– ?J§çò‹M9¾GæVh¦·Þ1Ã/ …K/. ;|×a~á¸v:;w$¿ØLgïáE’´¹Å;øÅI§GÝ™_Dä “]8|p–Wø“Îß^\d­ó[­Ñr`8ѪŸ.,ß>=»°:ŸW[vºpkN7‚Š¢ž™.Üó \L€õ«Î™ ÀêRÁ+umû`º4wäÈA^±™æ-›n”Þ3Ƕg·Íç} ý~4a C¢1èþ_]Ý~ÿ¯!)âü?ˆ›ûW6.´?¤Öpi ´ÿ ÞÿQ5Mö? \üýŸ6NÚÄZsƒ.»+÷ÞAòW¥mþ_®KŠÈÿG‚¡½ÿSZÞp Ã#¥Ùl£Ð¢K)ö#ìaÝÂ7ïóÍíªç~nÿ~1ü“A1$Y‘Jh.K¤+,7ŸB¶jÛ’ToÖ5lbËV3+ÚR³Q×4Y)­¢SÑ)T!µzE!J“˜ bIZK6TÈP$¶‰I]Ó›¦Þ0U£+!¤Ñа¢h-Ãj™ZCÒ±Ú¼2ãÜyþŸØÈðßÚùûŸª\×Åû?£ÀÅä?D£Êh òÿ²Ü'‰ùÿ†¬×…ÿ>ùí«yáªÏ>øÄÞ¯×?zø?§ŸûôÚ½Ïæ5_Q^üîÙ?áå?,|ëkÿêÚ7Î>úú£g^ýÛ'ý'_{öù÷U?åìÛ÷‰Þý3Oy³/,¾I®™ÿÂm?¹îú'>}÷Ã÷'ß?ûüÏ~uÝû^ýmë¦Wûï‹7?r¤ö×Û~÷Ø÷öÚßìÆ?¿qæß/½ò¿ÜöøÓo~È>ùÓ7ÙÝ­¸"q1ûgsÜÀ©žËß#Áù¿ºÍÿC´…ý÷–î»2 çŸÿùY ÊCËwžÿi MüýÏHp)ù7í¦Ù2špàkA©iÃP‡‚ E³.™n©M»e¨ÄÖVNk–b«-KS´¦-4úEÙ–ÿé²¢ ÿ? lå^:~ô×s¯`ÏRýÆ…ï.W£Â¥ìŸ(FÝTU¹Õ´MɔԶ [5›­VÃ6Z²*똨QjËh)ª‰Õ–ÖjI†ÞÔd£©sßí_Þ–ÿ±óŸ¸ÿ7lÙÿU»ËˆÀ®àRö?¬? dÿçýýÿ’.žÿŽ[öíÙC{ŸAWð™3?â#ï²n¸áŸoþáËÑ?6ÿøÔý«¿iÿåsÿRfÜo¾Ð|þå¿ù¦•÷Vöžzè;K?zè–³gÞºþÀÓ¿¼}wW#°SôÛÿpŸúmaÇÏÿ¤F]Üÿ Äó?ñü¯°ÿÂðÝ!?|÷$ñÿÿŒýò·ÃØÇtø4žÿ¤íï+ºÈÿFóKüÍ?ñ®ß‡Ìþyä¾l4?ÿÛnÿ²&þþw4È“¶ÝfC@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`ø?å\xdarcs-2.8.4/tests/data/split--darcs-2.tgz0000644001765600176560000000552712104371431017414 0ustar ganeshganesh‹­1âLí\klGwUÕñˆB%b]õœø»·;Hc×1nâÆªMÔÆv¬ÙÝÙ»‰÷ÅۖgBUù@ BP•¨@"µ© B…JÄè ”Gûñø‚„ügñ£Ž¯N.kBæ§Ä·óüÿgþÏÙ; Ê* ‡fT‘k—u€®ªüSÒÕúæÏ’¤èu¥QפÆ@]jÔ%y©—…›mèF ‡ ´±G¢Î…ûõj¿Bm•¿M¢ô›°¦({‘¿.k¨ÞoFv‚ÿvùKý¦qQòoùmò_JúöîÿYQ…ÿ/;ËŸaFWÈRÒˆQ\ ^ö/IÒVùËu©. û/¹|Gm¥ÑĘH £ÞRmYÇ–ª´4IµT³U×4Õ2ºeÊXÅêZª¤Ju¥ejZ]n`C/DV}ÇÎö„Äî_Ø»ÿWš"üØMþ! ü¨4zæÊ6ÿ/iJCþ¿Ô:¾Kjéâ ì»Am«F”ö›AËŠÝì?ò»¡I.ÝôÌÿde»ýëš.ì¿p?ÚÓ °^UÏŠGV…˸‚°›ý~H½ö¥Óèaÿ ]Ò¶Û¿ª‹÷…`%RFüÍ I›œ ¢ÑRipp™¾@mˆ°g!ê1‚^ÀÏôÙ%ÅŒ$£Ò êàh™8*·;æpÚÅÆ>J ÕJ~V ßgüÑÏž‘oœ&&Ë&†¤u¡jºo BZ8{ÙìÐ,¥ÓKþÐ&²Ðµb˜^!!nóµDAuÓ Ô³}Æè™d4Ôóá¶²{Èõ­®CÎóEÞ »gÐ2 =ÂI/çœ%ày¨T>׆aV7Xºõ½¨<U0øôO'D8$ÞM ¥…Œ5dw¨!&îF±YC.mw 4:ꇸâ¬Ef|ZbèBWhHYʸæ»Ï™Kvlu|o›Ñ:W0Ð1™¾Eøº×æM‘¯€8&ÿ0E’ˆa;ÔqHIt3rü´óEðæû0 áU†a1ŽÉG~ìÀ?<ÌgËtÇBëQ žMÛÝ0YÈù=^_5yÏqßu¡öØÔì ò»,èfÚÀEƒÆ“jÎÀøôÇq‚6ŽbøïÄQ¾ÊŽÏ45H&kt©c%Ýl.ã6ßíh-‚@Å÷ÈÄv¶(/gƒzà`µ,·+)«PÖ òâ ‚>øF+›$%dÑp$•ò|.Ì\œuú°føÖŒ>eш•kñ× Üe>ßÄ(U^tF@ØìT{’–”8,ÙñÛ10ÀºQ²·.5C?òm†V‰À`AÕ¹æ u»ˆu-ê#—0la†9Ÿ ZŸ ´´°´Âè’éö§ÁJbˆmâS(el¡’‹•$+­H{€e1)´Ï"žÉ'<µPMË™ 23àBg!¨Ê¦ý_É–<~b6]&¬y%¢m´}(íi.¨¹œÌ=õ’ÒwŒgGVxÿ¨kdÔr;ŒV¼Üü\šÝb'oë´ó¦6ey%<æµÆz ÁÏdj3§9;žDItL«ÓH¹IZ° ¼†§Iií©¬¦Â󤊋©3TÊ­ÚÙ æçG- Œ..LDàuÁÈÌN:_yá`<’ͽE°PXž™Øl´džgzn3wóÑ ÷lªªòš µÎ;%ƒ²eâ Óö1ÊŽ&ÅMcÆÁÁ´É,É6&ªK#¼,Ä@¿ËE™. 3å{9O^æc‡&n3³ƒ@ãÀ±“:•$†;x¨J”ì4ï|'ŠH냚jú6ÑItŽºÜ•ƒ¥»¥…Á”½¹N×5"Ø[ƒ]¡¹Æ0ÜÎDSæñÜáÉYn.™pæOÕ¿^ÌêºAÚ7^¨›™ö;a”Ûvè/“ÌM¡òÑ©ã0(XC~@Rq½åù Ul§=G`u Fk5îl«mßo;¤ ž°Ô _-×x®lȾºx°²Y¶¨7ƒÊjd†4HÈÁJ‘®‘‚ù…y§[g—fY²ˆ½Çÿ]ó?÷—šcôÈÿ$Y×·åº$‰÷?…`ÍÁÙ.Íþ¸ÇƆ81äÛ\÷ôÜxÛ]6j#Ú€ÆûAÜ•$‰©"t8¬¿ª .€Cì­ñ© yDgÓxt!÷èB,†°“ØfB%z9]eX°1 ÓÏu`ˆ* “ÆÑ½µÔÁžWTT¦6w ÈÀ¢aˆAà}èÃ0–/¸ }á߸µåd°¤4ûGˆæà»<¾€U ˤˇ ³„AåÁá$Jc—Ågš%Yþ\Ö‡“â.I-—‡Ã›Yå© Žs¿X6Ü ›žÉ ërRHÒ¦f§…Ó8Œo;|GVÈ¡v|ÛÌġɴÂõÚñôíy!iÞh æ=£,ºñÌüíc“3‹ÓYµeÇ3·ft˜a&Ÿ!X3ã™»2^‹œ °>pÕ XËyeÔ¶ÅsSGŽJ+Öã¬eñÉ)¾=ûm>WŠdÜÔl¬[“ºlKf«i©z³®ë„¨v·J‹¨Äuså§Èf½BTY!Ø0õ¦ÞhÖ›M©eó†fè&Ð0¤–,«u©Õ¦&º…¬S¶ 1[6|\…ÁîþŸŸÝH¿n]ÄýM÷ AµV­ÝrÌ÷ÚǨ·|™hä2¾À'ˆ[Þ¢ àT­1€Ž]&~¶ —èûl·~½Ú¯Pìnÿ}ô­û½PQ„ü{åò¦û?@þY…øþ¿¼ûÓ×¥×.ž;[úqýúO¼ø¾ãš¬<ÿÒO›šxfú‹ïúÉ‹†÷…[N~ýgÿz´û_¾?wßM/?ýì3w-tþðÎß¿ýèWÿ6ý©#Í7º¹qîÆ_ ?òømSŸýäóSûÞÄ5¿Æëç~pð=/][~âK7ýñówxð¿u¿©Ü×ÝGxæé§žúÓW¼‡Ÿ}˾vâ¾Ú“é¡õß¼ùGßÝßí¸ê°»ýó¯u©×®ž?^ÞçeûùOnˆû…àîÒ=Wá©G Ç…Þÿ¥oªéëŸK<îýü§7â÷ÿ ÁÿÄùOÑ_yþÓÅù¯¼:û' £n*ŠÜjÚ¦dJJ Û†­˜ÍVK³–¬È:&ŠDMi­†bb¥¥¶Zp hª²ÑT 1d‹Aòï™ÿmÿýY×$ñýO!Ø8ÿ]»¿Œì Düñ¿·ÿàÿEÈ¿Wü—”óŸ$éIü¯‹û¿…`#þëçßã‡ëoxÍÓÐoÿãïkÎ[çŸüø3ÿV¯;‚Î=ô¹—ßöìÃ>1qö…kþün»1þLåÒ_è#¯}Çëã>tý_}ü“¿{é9FNœ°ÿùå^÷ûÏ*×ìïÚzcgûïÇ­Ÿ ô²ÿWÜÿVEØ!÷ÄýŸWÚnø´/w€öþþWÓÄßÿ,;ËßöC÷í¸Óóý´ý÷¿TEßÿ‚4Ò—Ämÿ«;üýW¹ß4zÚÿNÿUüþO!ØAþ~Ó¸(ù‹ûÿ{Æý;:Yxdarcs-2.8.4/tests/data/split--hashed.tgz0000644001765600176560000000611612104371431017410 0ustar ganeshganesh‹¹1âLí\ U‡‹*J¡”¾b˜ ;3Ý=}̬HH6É’…]fw³¾î~=ÓÙéƒîžIviRŠ‚pUJå¨B !‚TŒ\ª-5XˆHQJJ°°âø¿îžì‘Í›LfÁ¼¯’~çÿ¿÷Ÿ¯§{|·lét û%¢gçpE’è'¯HÜÄÏæñ¼¨pbŽãyeÇç0I‡É¨øöšWÄ6ñKûîW¯ý ’ü ³LĆӠ–Eq6òWyâÎÉ4`òŸ"¾á4öKþ9&ÿf`²ü‡tìi~£ÃÀìý¿(ˆóÿÍÀ´òˆàÀ¬’!×3ýÀ´ÉѨgÿ<ûIò8ž˜ý75wb.1ás*W AÁº$d^Ò%­Àɲ¤k*§k–0†º‚ÄK<'4Yæ„V®e®W°?˜Öþ] Œ³÷ÿRN™ÿof¿G\Çoºù_Nœ"Y„*æÿ›€lɱH6^Ä}ËÍÆá”uæÑÌ`ÿªã™v±4êØNáå©ö/)ìüß´¢E‘˜=ú#É×ïliimmEšc¹Pë!lëÈ´âbÀßøÚ"º‰ ô[Z¨Ð0)—QªXÒÚã.Ö i S2Û¢¿iÕqzé$W­ÈQ×-H&†¨u £Y:mu=Z({ÉìÐêÅÓ¹CN۲еèa ˜®éZ|73aÓ6˜¢ÑPO‡ŽxØF–£WÊdP¤­0°² Ï&”ôp³¨\·µ¤Ö†Ùv˜Õr‡€®o:¶Ÿjƒ*<úÇ"ìûÌÅ…Ô¤WÊPC4\ñ JdYf±À@• åŽG€+Êš_†£L‹< ½<è 1K ×t÷)sÑŽ%Çî@ÄšßÖá*z &ÍÑ ]÷H¿æ Ò²F?´2öýqIø‘°Ë¦êaÏ$þçPÙ‰k0]m§ LÀBèF¥`XˆC²„¾–án§³%º££Q¿Û0‹/ZÈž=]¯Ñž]ŽeAíŠe½=È©n%Ñ*ÔUSºV~¡k%h`?„ÿåÐwÁYᆼlÉHcÕŠYÖ£î.Ö†q‘î¶?âC\£{¤a—')/eôÁ”Õ´;\LǬBµO‚Š[+¶"ècƒsÔ“IbBºéuÄRC¶C…Y“0e€>Œ¨Ž>£×êpÊJeÃ6ª¸8týXyhÑ¢ÀZ‰ÄÚµÄÄaÉe§AÅöÖ25Ïñ#@뉊À`AÕ©æu ªéW€;?¨è¦ƒ,`˜ò ¢u¨@[†ª9¤Ù ýñ¥[ ±g~ÇA1cTuâ¦=­43?î–€L¡…Ø:±5:áÚL\Nd˜zàªLØÿj²ä®Õ½ñ2aÍUß,Ú ímq‡DsAí´áhîV¨‡˜¼¨+ØQ¥ýýŠšP«Ù¡_µkægO«x&.×ÚJÅZSÑ j•pY«UG=`þFSk5š½]5¢­( qu*'H ¶ÖЬ9®]›Ô¤iZ•¶°YnkIÇ5*hgÅíïïÔM` spð¬HvŒL+Åó¥Î ;’¹«¾ …åi‘ÍúëÝÄó¬ì›ÈÁetôÀåª2´&mê{œ’jÃÄåÅí‹Ì`yTœ0¦ L‘ô’dc"¡Z¦¯—…èT¨(ã$¦¼‘ò¤âaú±háòÈ á@+!Ð80A\ŽŠG"C<Ô·EJ¶Žv¾ùăõAM&¾›(E:gZÔ•ƒ¥[-­1{}¥Š¥ú°·*[5kàb"š½ ûv÷RsI„Ó¿6;ù%ðbzÅrã¾á@¦]K´ÜI`RÛöœa’¸)”Z¾l rGã’ØùToig:h=6âž°‚JAàvf³ÔÙfŠŽS,“ x¬›…~ÙšžÀuz\ö™Á³Ò5a’JQ3H¯÷5Ït#r°Rä€k4Áü¼Z§Å½C½A´ˆÙÇÿ™ò?uœcÔÉÿxAQ¦ä ½%Èò¿& õ•L?Îþ¨ÇƆ8ïÈ1 ¸ÔÓSã-VʰQãÑ4Þ± ¢®$J”H¡…ñD`ý%PUp4b{„NÉ $:Æ#  ¹Gb1„È6#ú(R<È‘hèJÑÀí0}_ &€¨J amÌÆv¦¢”iP§X€ßÂuËÄ‚A@ßú0,¨-8}áß"pkÃÑ `Iqö—ÍÁwÙtëMX$]ÄP˜Ås Jµ¶GùP»t:S/Iòç”Ò%wIl¹4ÖÙÌ Mmp¸°úÅ”j¹á¢•=IaT­â‚îháâU]qR¸pÉŠZR°%—,‰ EÓ»—-M £a÷šøÒ„$mY視°{áù /J .YP ÏïY² ;®°ìb¸ò‚Z!j]9ÞêöÛjѴžþ u÷ ®Lªu#ìYœÐua†žÚ îˆö|1Ḩ1Ö®:a"Vûj¼¦a,û–-]º ® “–QÓ ×,£Û3׿óÇ þ?9£Ð„æÀhÌþþŸ"óìüß°û‡6f°Ë ô†Ð˜ýó² rÌþ›éåOS7Ò°o÷ãû?Yaßÿ53ÊŸÞÕiÀWõí¯ø/ä$fÿÍÀe-—³8#“ÍdÏ]áØÅ¦=|hÔ|ü>>ÁÝó“b8I桉ŸI¨Ù¿ç8ÁLýêµ@1£ÿ¯É'/¦qŽpÖ%É \N×t•“ˆšSr˜ ¸ Ȳ¢jX/p˜H<'26ò’–ç ÑH^ëu2LfÈ¿^ürSò?AÙù¿9øìuÇÄG îàO¸Š;qÓKooüéæóOûçü1õúKsÏݰý%õ±#ÇÆìíï~7_ý÷›Ÿö2íÕ±kžvûÈ-¿}Yúæ¶—¯;ú3oŒ½ýzÛÙßúá©OoM=|Ú’Å›…¾‹ÜðÚ=¯v|ýW×<Ö½ã‘7Ê·?˜zýµç×\üéo_ÿÑ{Ÿzå“»voºôXõñÁM_Úrísï|ä…¯öýý_‡?´k×¥Íí–Rx/ùfÏóàûGcÖù¿À 9…Ù3ÀòÿCû¸ÿ¿iÌk¡³¿ÿ£ärìýŸ¦à}qþå½Ï2;ÿ5ïÉþINå4Q yCã5^,`C5D-_(ȆZDAÁDä‰(‹µ5,¤BW•¼$¨y©)v̰_h†üëæÂÔüO‘vÿ·)?ÿ1·Œ0Ì Xügñ¿®ÿ?Ðwƒçz‘ ûDSä_'þóâ^÷e…=ÿÛŒÇÿûñÄñWrþÐï4üÇ›#å÷?ò•mïHÇ,E;¶Üöê'~vëß[²uça¯œwòÉî=§‡7¥7·¼žC_>êSÇ…Wm9é¯ß¸oóš?þåÙ€¬^mì¾kçÑ÷nÚ*6·kc¨ií?. ™v•¾ä zö/îõþ§"‰Ìþ›‚ÆýþG?Öõä… îh¯P¯Ørq[èìxÿÎ%Ø J™²yÎüùôW^xž—9…—D¾-‹ž¥OÓÇó;‘€ó²` ¯òº¤ä9E!D2ò¸Ð2ˆZ¨šv¢ZiÀ—Ô‡àðií¿føfcžœýý_Yf¿ÿ×¼/αn°óß ®ý×dTÓD0ÎIBK">T-ä‚óàW l¨XV°ª9ˆBž— 9’σSx%'Y“%ö ÐûͽüO”©ç?Ab÷›‚ñóßé?Ê~š;騱«^:åØÀyú­î›/oûÃVu·zÅö›¿ÿ¼‡¶¶ (”"!Ô>À*5 E<ô%Tõ¡ˆ¢ ! Àvö’³¡=ï%½e~²};ŸÿïÿÌŽw/ôÊs9æX¹:”yÄÊQ¯E<΂ÂÀ•@P«TħV«;?Ûдr­XÖkÕ’>PÔª¥ReU®õ.h† ØØ#aãýûuk¿F~°ýëÔ!åË¥! \-—SØ¿¦W´T¼vƒ²7ûk—K#•ýõš´¿®ìßt±ÿŠ…3¼Ìe Uþ¯…ý+5]åÿ~`göçPÄœ¶ÈŠÐS¤¡Ñ-þµ-ùüD/•õŠŠÿ~[–Èñ(/S}fkYßV.m+—3W›…ËÃÎâßH½÷U Uþ×!OèÅšVTù¿HcƒÔ³ÓÓè’ÿËUMßf]Óª*ÿ÷ƒh¡ACçt“Á*O½aäÀ*X‘uXú-b¡€ØMEÖÁÂü$Eà,È'Afú{$&ä<>æ äbn6À]ö6ÄL¼ABÒ9­QÇAc8 ˆÓ°&GVSx:{‚õfh­A<1 :žË9Œ­æê,ÈAk8Œê¶áã0Œ§á¬=|­y葵a`ÃBÇb²ÀÎ#˜ñx@Iˆ¨‡NòÒÓ¥£,­Ã<”à‰p…Mßwˆ C€ ’PÁM¢¹<ô…ŸI{«±*@7‚^| "ÚÔóĬkƒ=ÄLÎ`–À'(;8‚pÓÙˆ™æ ê&ëÙÚ)Á Í€úôÖÍ*ùLfppléúÀYóA=P0ô€¿òÚ%ņ®k¡ƒyìë„(Ÿ7 A²”p-´/˜‹5¶Ná"âb<èna ÇE`ZDȽ±h²e!qLña:àñ—,&NgXøõ]Èa²Ç. œ1G¸­g EeaX„#²N¢Eüà1[â;Ú ")Ô©Ý bA.êxsÍ=§˜ëBíìÌüœˆ]¿™xCì¶Sqµ``êðýS³‚ ,1ü:QèC´Õ£õ±jHÆk4©cÅÝ}l®b[h;Ü9q…ŽLl`g‹ó 6 Yqì«9ÕÎIV¡:$¼é·‹ƒúxÝV2‰$dÑ`TZ yL³maÁ:Ø0˜µ£Y²…hHønBä‚Cé<¢è–9S`³A¤÷Ä-’8ˆì0;x3ŒuëR3`!«s´FŒŽ¸E-6»7-ÊK8¶0Ç‚O0-Í,­´8]1=ð~yé·â@´ÅjÍdl)–Eü\@bIó»dˆ,6…‘;hÓž8æ5½m‡½Ž&FDnÍ®MžK ›z4yT—‹™Ñ¾#S²ÛÀhÿl»Û¸ýî—›Ö£é™Ia3š>*/)lôfæÈ D'îK >ÙkGçöï–®gG‡ïmâÖ×ZýEϰýe7š[¼wrznùpRmÕ£¹} ]f˜kÏào˜ÑÜ^‹6}î&8°ºÐæ•Óz}o´0sàÀ^Y±%-›ÔŽÎõ\íð¹æ‘&ÿ»Œ[½ÐH÷ÿ?‘ÿµJµ¬ò?°Cû‹\Nz=Nuþ[© ûëºzþ£/Èò…{f™gÏRoõC¢Ñ¶ñû|µJm‹/5¨) Ù‰Ÿ-hÛ?`ŒP¿ní×(ÒÅ¿^ÔÀ8ZµXÓ*e-7¦†ž³HÙ,6­qË,x¬4nk¤8V©lèe³¢™d|¼’·7¯¶´ ÛÑûw[ÿKzµ#ÿC¿R±\*©õ¿øÌ£7ßü½Âïgn¸¬ØX~Uûø—‹·ž¾ðÞ©Ÿ?~ðοî:o<öPéÜW_¹`üàüçÏ{¯üûù±ÖßÿòÙ_4ß<ÿÈÄOo|íwoTžyùGoúô;çß{{èîoÿôŽŸý0û£;÷ï{\_xàÆõ·¾õæèS¿yäÅéWüŽóô Ù·ßúõÑnî±O|ç'üÔŸþvzå¡[Œ—–O?ó•sÿúØoÏ.üùK…C™sÇ_ºÚ*½¦.þÅQqúwßÿ—·=ÿ£Wª*þû‚“™‡ÕMôuŒžâ?ñyÀÑHÿåJU=ÿרø¿¾±Óó?ùÔoo@©Îâø×Ê%õü__Òþ=½”êüWîÿJeuþÛô`ÿÔïõdõþW_Ѓýõ´4z²¿zÿ«/èÁþ¥´4z²¿ºÿï vfÿ‹=Ñèf­ªoßÿUÔûŸýAf[Vò,àt,"š§œc×ÇvÑÝRì{x#ïÐÏíÚµõœ8ƒfâG`r⩚=HÇcÕ:®Y“¢^×Ìñ1«R+Öj„Têcx<³Œ®¶Ä Hÿ´§gRÝÿ%ïÿˆçÿÔý߇ٿÎ÷üïï®ëÿ½ÿ Cÿõò™v-_T§€×%všÿ-²Þ3nñ_®”·~ÿƒ^_¢â¿øüüÌÅó¼ÑÈÏà÷ݱï^¸ë–•áï/|ã¶×~ùQòú ¯ï:úìkgn»uæ•ãƒÏùûò—æxRïÙŽtöO¾ÿ«¨ì¯                                       ð¿ðõ8ÿ~xdarcs-2.8.4/tests/data/metadata-encoding.tgz0000644001765600176560000000612412104371431020311 0ustar ganeshganesh‹L³äPí][ˆ$Wž ±Mž Ñ7ÌíÞLw×½ºÆÄÍîdw™ìL2쌚dfvæTSݵÝu¡êtÏ%•'a]dA$’€Qƒ €‚à“Á‡<‰¾ˆ_"DÿS—Ýž™ÌöÜR“Ý­ÙîªsûÿsþÿûÏ©SU½.e˜`†ëÔ³|âxíæØ±CèºÊ¿E]†¿sŒ‰’ ‹¢,Šº>&ˆ². cH=~Uv£1"4ÖÆ:{—•‡ÂÝeÛéÑã•Á ¬iÊ쯨„ãUããQÚ‡ýW ­è8ÃÀÁù¯Šª\ò¿ìiÛ]ÌŽEÆHþ‹úý5°¿&krÉÿ"ÐÁQ‡’JbóºT9iuJŒ=ùŸ:ƪ㠨Çüpó2Fñ_Ö´íñ_U)ù_‚Љ˜ãÑ©Ü-½ÑWtS[À‡hÉbKZ,S0ZSE¥:‘)Ö$lô¬A!Ë’©-Be‰ÑˆUžùGè»ôôi Öó‚(€…¡¥‚fÚžÒ:ë8Ñ¢Š IM¨!ØÀD³ ªØ†@D“´¤VeU¸+N¡\AC®D—ˆHí–M5¢bÅÐDPF4Ù0tbJ˜Ú !r‹Rj´$Ò‚‰Ö¢†­)XÑZ¤ s7±'ÿƒÚÇ´ <øúO“t©\ÿö7‡Ž$cDü%]Û¾þ“ Q+ãG‹‡¿èG–ï1ìx¨³òmD7õ%(¤í~Šn€cD‘ã{Ñ$ò=ŠVÆ¡¼GM 0ë ¸z°:àP{›¼)Ö¡®@.Ž¢¾ Í3Éä£Äé6wKTõ|†¨Qk€¦PßcÜ{¥ÙH]5wRTulhÆa ôj(êAºP Äû ª±¼¿ ( çzØë&€a¤‡È¤mÇó¸þëô{È·˜­„EÕñÂ!4—Le„·´@)$ºQÕk.ž` ¬Ð tvÔX6*Ë*ŽÏÖ&øéñ¹¹ùìdKŠÏ½(¥'Ä·â§Ÿ›NOhÏŠÏÏæ'4>ÿüùô¤íØñÅ™ ÙÉV|ñÅôЉüxfá¹ôä*ãgÎ^ÎNz¦?3þÌÅ4ÁõÚñܳùI’;w+7XòÌv°âÆóKÏž»8¿2—%;ž:“@ óy Á¦Ï¿é ZäJùâÅ\ ª.æº2ǶÏÄ‹3.œI¶â,gË âgøðœ4{î|Œˆÿ„Ú¸ßc! üÃËyý¯¨;×ÿªTÆÿBÐìÀ½™v®™Z~—K”4»{1‚ÿ®ÏÈ‘elÿŸïÿé"„„’ÿ`„ýyà?Úâìñ_Ôe¥Üÿ)eü¿·1‚ÿ‘ß­#^þæ¿*í俦—ñ¿ð?U{£öÿüÒŽ(cÿ]Tw®ÿT¡¼ÿ[Žuÿï`ÛëN¯‡LÊë0RÍø}†HŸ»ZKÜaBN ­w(ß»£h­^ïù~·nûar£SÈîá6ßL p%Í0?¯¾ÞÁ,òèú©dgo-¤–’S·ÙJLüýŽÞH¬Œó­T7ÍÂDǃñ…ð™»”8˜%#O#ÙÁQ—‚1ªíŽUK‹Ø¦ýÊr£ãL$ŸuÓ÷?ô³#0–y•Z,k2’Üå†åž„>äðng­Cn°š6¬úCb¡h;Ä.(= !nóîGAc¨dz}¨Æœ¤6¤óê06,„át}ÒïÑ›zÀéDê‘ý Ô¥¡G¹èn®YRŽ'*Õ+q³­ºÁ*ÈMF¯:IPù4”OäÖñN1”9†¹‰²-1°«…ûà à“›ÈuÚÁ/!A+®ZÔÃ,qõƒÏ:‘ª”iÍGŸ+—ŒØ&8…7‰¨‹-ð «x€Aã¼$”÷{sÉòWxhÏâ_Vþ–%¢ÌéÌ0Ù ÿ êùi N\ 2˜ï÷¸Ûzm>PU¨ã˜oG~܃?\›¨Üô‚¶¢ ¶Óî‡IGnŽñÖºÅKNû® ©³3 óœºA?ó†Äm§“d®ÀôÜצg¹@G1üëÅQl³ã–fƒÈÄc;Ó#Iñ[]Üæ£mFŒº|Œ,lâÞ6çåj@¬b¸ªÖƒn»žª Éeý ?GPÆv“¬‘TqÂÉÔjˆßa»eæªSð‡MÓ'›Pû PmÆÜ/p˜ ƒ¥ÎÃO]…Q0¶:4õž$']îùí`ý([×±B?òm†Ö©9ÄÛI4p¢>h±>q|”OË\O0­Ï ZY^0gÕòÀûÓÃ`±ÍŸÐðQªØr#¤BƒzH“ž6N§%€Y l 9ê›™´œ‡ÑÀËéçÒЂY÷ò¼N;Ïj;,O„Ã<ÕÜ A!øLš¶r™ Ó¹Ðq”Ä÷49]á Yk9þ|-œ¦^ÉRêÐý îb§7Q©§)&xg?XZš"(0µ²òxb¯$³:i{ÕåÇãɬíAAG¡{VÂÙh=È"ÏÜâ°/ñÚË/%5xJÝ!7ƒ’é°.¥|¾MòÏ9ìRr:TgL›.Ðl`£ºNdA”…å‹ßç¦L;Qù®“‰»üëÜÙKIâ7̸Ð=÷Ò Ò$Àð鉓]å…ŸG ¡ÒH€Äç—‡r`º[YOÕ[ìô]3‚±5yÝ“{ ÃíÌ4U~/ž½¸Àé’géJs%‰KÅHß Ò²ñr£feÞá„9œÛ¡ß¥Y˜BÕK3ÏA¥–MXÄý–æ•Ö±–œ„NPÔa,˜j6y°m´}¿ ó:DÂfЄrÍÜOà¸~Ëö•ÇëÞ°Í¥8 êëéÄP[Èç  _˜zzaueHÇ" i”/’ª0÷w™DI»Ó¼RRS7É©¦¢jgu;lïõ?wƒU®ìÆQŸ9øóº¢ˆåóE`_öçq•Ïb‡{1`Ôþ$í¼ÿ'ªrùü‘xŠª¦®ŠŠb¨6¦ ¢­Ù‚bʦb‹Èþ ¦ S ë-L$]3l…EVdlÈY;÷eßOnè¯.Ȳ`Ô5Eò$˪ ?â§JÜæZË”%Ü2° ›-›èæIÂ=ˆ}ñßV]ZÆÈý_]Ùyÿ_“ô’ÿ"çíá÷¿îÛ3÷¾±wöLJ%‚ÿºVÞÿ-·çÿîÔ’ÿw öÅæ÷áøÐ`ôý_yçú_æ×%ÿ ÃL^””¿±'ÿõà‚ßÐÕü±CËÅQÚ9ÿÃ…cyÿ·|ïÿtŸJì{ò?ñסG~ ðû¿jùû/Åàöë¿£Ûžãàö×4¡|ÿ³4šæS³¾×žu¼î'$#·ñß‚¨ªÛ|AEUÓÆÐì'¤Ï6äö}ÿ¶¿v2*ÿÅHþçV9†×îOº¯%v£û\ÿ«ùú_Òe b¤ëåû?ÅàË×Lî¿Þ˜©7þúáÖ ßûá~ò%kÞZgíÁ×ë;ýÈïýëÃë—û—$éúϹ<÷пýêŸjoÞøýk7®Õì?Üxó1çÆµoÎÔ½ðèò[•kµšó}ãÍÊÖÑ·>?f}ôÏ'VN¶›%öÀHþóÇà ¹qs?àà2Fîÿ ;¯ÿ¥òý¿‚ðRååòÍŽ{ûØÿ;ò/âÿîßÿ’T¹¼ÿ_Êßÿº·q›÷¿RÇh¤ô?Ê>Ð÷$ARÊß-ŸŠýícöôrÿ§ì›ÿÇ8?œtŸKÜBö¹ÿ#é;÷´òú¯ÜÚÿyòÝ·~Ux賿ýê;ÿýµÿ¼ÿدÌÏ]û_÷ÇoÿíƒW>úóï¼öëß­/Ìo½ñú«?ýÑwŸýNå4ûùÃïiíã_ì¼þ.{/øåGŸ™þõïþòíP‰¡œÿËùÿ@ñ_êT6KQ$£e[¢%*¶M[±Z†¡Ù¦!)’3€HM1LCV,¸@S C4õ–*™-µe}‰ý¡û'ó¿r›ý_þü—¨iº$ÊšÞÿ)ÿÿ—bpkþ¿ÿd)q"øTÌÿª´{þ—Ëù¿ì;þ—“þ]‰"ì?êú_Øöü·6&È‚$”ï‚rþ/Q¢D‰{ÿ4¡ Íxdarcs-2.8.4/tests/data/README0000644001765600176560000000025512104371431015076 0ustar ganeshganesh Larger or more complex pre-built repos are stored here for testing. They are stored as archives for space efficiency, and to emphasize that they are meant to be read-only. darcs-2.8.4/tests/data/braced.dpatch0000644001765600176560000000062712104371431016626 0ustar ganeshganesh1 patch for repository /home/ganesh/temp/empty: Mon Oct 18 18:27:21 BST 2010 Ganesh Sittampalam * foo New patches: [foo Ganesh Sittampalam **20101018172721 Ignore-this: 5e9ee20eb359c030581f54a73186405c ] { addfile ./wibble hunk ./wibble 1 +wibble { addfile ./wobble hunk ./wobble 1 +wobble } } Context: Patch bundle hash: f427e3af1c3f5486cf570a5c7bdb826a0a2eb3f8 darcs-2.8.4/tests/data/context-v1.dpatch0000644001765600176560000000117612104371431017416 0ustar ganeshganesh2 patches for repository /home/ganesh/darcs-comp/temp/empty: Thu Oct 21 18:28:18 BST 2010 Ganesh Sittampalam * init Thu Oct 21 18:28:31 BST 2010 Ganesh Sittampalam * ABC New patches: [init Ganesh Sittampalam **20101021172818 Ignore-this: 6a770d5966ed23f56e94c08977507388 ] { addfile ./wibble hunk ./wibble 1 +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 } [ABC Ganesh Sittampalam **20101021172831 Ignore-this: 157403967fc6753e0f2540535937da5b ] hunk ./wibble 4 1 2 3 -4 -5 -6 +4A +5B +6C 7 8 9 Context: Patch bundle hash: 0a20411489222e188722666cf0db4c5de2539aee darcs-2.8.4/tests/data/context-v2.dpatch0000644001765600176560000000117212104371431017413 0ustar ganeshganesh2 patches for repository /home/ganesh/darcs-comp/temp/empty: Thu Oct 21 18:28:18 BST 2010 Ganesh Sittampalam * init Thu Oct 21 18:28:31 BST 2010 Ganesh Sittampalam * ABC New patches: [init Ganesh Sittampalam **20101021172818 Ignore-this: 6a770d5966ed23f56e94c08977507388 ] addfile ./wibble hunk ./wibble 1 +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 [ABC Ganesh Sittampalam **20101021172831 Ignore-this: 157403967fc6753e0f2540535937da5b ] hunk ./wibble 4 1 2 3 -4 -5 -6 +4A +5B +6C 7 8 9 Context: Patch bundle hash: 846f06469d8639ad0762c33e2030e5c24ebb1832 darcs-2.8.4/tests/data/simple-v1.dpatch0000644001765600176560000000057312104371431017223 0ustar ganeshganesh1 patch for repository /home/ganesh/darcs-comp/temp/empty: Wed Oct 20 07:12:31 BST 2010 Ganesh Sittampalam * wibble New patches: [wibble Ganesh Sittampalam **20101020061231 Ignore-this: f4ff110805aca7a2d8805acf18605523 ] { addfile ./wibble hunk ./wibble 1 +wibble } Context: Patch bundle hash: 3c6e5041f7e4b286c8884247a155a5d80d0dd77b darcs-2.8.4/tests/data/simple-v2.dpatch0000644001765600176560000000056712104371431017227 0ustar ganeshganesh1 patch for repository /home/ganesh/darcs-comp/temp/empty: Wed Oct 20 07:12:31 BST 2010 Ganesh Sittampalam * wibble New patches: [wibble Ganesh Sittampalam **20101020061231 Ignore-this: f4ff110805aca7a2d8805acf18605523 ] addfile ./wibble hunk ./wibble 1 +wibble Context: Patch bundle hash: 497c8eb610ad9a25b30ceafd3b4f5c1ff744d21d darcs-2.8.4/tests/data/split--darcs-1.dpatch0000644001765600176560000000062512104371431020044 0ustar ganeshganesh1 patch for repository /home/ganesh/temp/empty-old: Tue Nov 16 07:15:41 GMT 2010 Ganesh Sittampalam * add files New patches: [add files Ganesh Sittampalam **20101116071541 Ignore-this: 2a86fa7deae02f1c98d578077ee5f8a9 ] { addfile ./file1 ( addfile ./file2 addfile ./file3 ) addfile ./file4 } Context: Patch bundle hash: 947100f54fce0fb3cb5debeca8702b119ee17d8a darcs-2.8.4/tests/data/split2--darcs-1.dpatch0000644001765600176560000000126312104371431020125 0ustar ganeshganesh2 patches for repository /home/ganesh/temp/empty-old: Tue Nov 16 18:32:25 GMT 2010 Ganesh Sittampalam * wibble Tue Nov 16 18:32:38 GMT 2010 Ganesh Sittampalam * 'nums' New patches: [wibble Ganesh Sittampalam **20101116183225 Ignore-this: 5e5df9907f191511650c2ed66754d17 ] { addfile ./wibble hunk ./wibble 1 +A +B +C +D } ['nums' Ganesh Sittampalam **20101116183238 Ignore-this: e865de7aa7e896c759dabccf510c59bf ] { hunk ./wibble 1 +1 A B C ( hunk ./wibble 3 +2 hunk ./wibble 5 +3 ) hunk ./wibble 7 B 3 C +4 D hunk ./wibble 9 +5 } Context: Patch bundle hash: cdfc4f7087525b0298d4f08e6e497f925f85e406 darcs-2.8.4/tests/data/example_binary.png0000644001765600176560000001512612104371431017726 0ustar ganeshganesh‰PNG  IHDRBHBÏ#ŽsRGB®ÎébKGDÿÿÿ ½§“ pHYs  šœtIMEØ `ïAÖIDATxÚ½|{[Õ™çïœ{î½zuKê—ºÛÝíö£›6ñ#iÆŽ‰aìa–É`×$^j¶BeHÂfþHX¨­¢6l­–Te7›R“T­¡ àIMrv—!ƒy”“Ø116ÆÆñ«»Ý/÷SRKº¯óØ?®¤–Ô’Zí!£®¯Ô-{¾ïüÎw¾ó½l¢”Béë׿þ5¾óï òóáKÐ ÀÀX²¦ÌÈp?)æ¦iâñÇdž jŽa•d³Y ]„PJA€8€›lSJ X¯”êRJ5`J)@B<€ !dŠ2à}BÈqgLRJH)W,W €ã8uÇ,"‘HàÎ;ï\æççÍ3gÎÜâ8Î_¸ÀM„(cŒÄb1D£QƒAèºÃ0 iPÏóç<èºn,—Ëõ$“É­étú¯„–Rê €w4Mû?ëÖ­ûMwwwš1!DÃò†X,V • VJ­J)’Édàç?ÿùmo½õÖ—Ïž=»@[$!«W¯ÆêÕ«ÑÛÛ‹U«V¡³³MMM0Mº®ƒR BÀó"«AXtEÇfvv¯¾ú*^{íµì§?ýéÿùè£~·µµ5ûG¶mtèÐSýýý_ýêWñ©O} J)H)‹ö`9Q`1T—P5~QU9 %›WJ ÆÖ¬YƒX,ÆÞxãÏ\¼x‘oÛ¶í7¡PH~b@¼ú꫃?øÁöôô¬þò—¿Œ!ªÃ:ÊE˜‚ÖĪò—’‚ÏQ(Ñ ‘Íßb„ôõõ!‰°×_ýÓ¶m~PðU–{±z_ž:uªó‡?üá“ñx|ý}÷݇[n¹e‰G§@¨Õ )@H@ Rf$‘V(HHIËŸ×òlÙ²œó%š …$ô(5%õ…–.OiàYmq¹‚’Ò«Þ­*$—rq K°(5ò<¤ÏÃK2ˆ]b3n¿ýv ­yî¹çžX³fͽ›6mº¶¬­©õÅË/¿|çñãÇÿfÇŽôöÛo‡B)%hˆÃh·AC  ("*@ô6ZØ+Ž®wD]â¶‚pU z› ,ᡠР—çÍËdâœC×uìÝ»@àO_xá…Ç!×ÄåË—Û^yå•G‰DlïÞ½ƒE»à(P w ˜€¬ò£4-æL@J!Ü$…àªêx ÁócDž‡&ÀânmL€Å@óyäB ‘H`ß¾}ôÔ©S_}ã7¶®Ïóð£ýè¯ÆÇÇwîܹ]]]p]×ßÕ‚VðÓƒ„¨I08ˆéA )ÜÀš¢\B•ŒS\š¢p3€”>˜|y¦ðyˆò<7nÄúõë{^zé¥çææôqîܹöwÞyçoúúúôÏ~ö³Å+ª”„”P†E꫹"J%ϺóÖ„îÉâ8Á%¬I î<-ãÆâ—ñ(lšaؽ{7&&&ö9rdÛŠ€8zôèŸ-,,lDKK <Ï+CZäwWJQw§Š¤ü±¥Ï;óö¤æÏ¡¬i gŽ”óùgàრ–ÈéyÖ­[‡o¼±ãµ×^ûë\.GbffÆüÕ¯~õÅX,fü…JmRB /‡eÁ(ìXµ9œ$ñ £'áÎHQ…O~Žº@HžSUŸB@Ó4lݺCCCw>}zuC×çG}tÓèè莭[·"‘HÀ󼚪$S[ô(¯`*@ˆ¥!2‚P4oܤPK#PæA‚×5r^†ÁIJV÷À¤”X»v-B¡ÐÚ·ß~{×­·Þ:T-AÃ*·;=ÏK¬]»š¦ÕO‡ ;ÂìãЛEÍ0šÓ mº8FT—€îAi J×!rZÙTW !²&Ê<«!wUƒpê;j¡P½½½ìÌ™3–Ífÿ1‰ˆš@ÌÏÏë'Ožü\("ÝÝÝàœ/P‰ À/Ðã,Ê¡™‹0@3$à`mö¨ ÅÝm³ÍÒ=€z»/€tIñÀ­t!  É @à;TàigJ‡tò»R/ŽÐ4ô÷÷ãõ×_ßvõêÕ® 6ŒÖbdd¤urrr ‹!Wõ"¡|u'Äw…¡Î \‹‚Lê ´Ü%fM¡Õ6Œ®,`ºà Zñs=ÊQH?h-AÝ…—fP è­¸K €§T¼œøåEoSIâ+Y‹tvv‚sÞsþüùõu˜ššêÏd2]ýýý0M³ª} š‚ç0â4 ¡;ËàÎèPÞÒ³á帧£ic¬Ík]ÌFÉŠìmö`6•|/2—ƒp&)P£(€h€ÑáÂl÷@ éP¸s:Üi²BB"‘t]ß àíš@ ÷K)›Ãá0”Rà¼ÜHQ]"¼Î‚™ð@Jâ­•€4È^ B¹dÉnˆY#­`´ze6BºÔˆŸ§ †,{–ç4XSRð¥ è á5ÝnQ­ ¶4®#{>äç4È"º®#“sçÎÝ`Û6@Í£Ñ'¥Ô ÃXfÖZл¬¼:—H¬)«¨<ÿ98Ó:r~P€EÂë-m°¸Pð<ቒù¨.YgÁèq ‰*—…¬ÝƒéH,œ CùB®SÓ4d2™^!„QYIc%êÓYˆÞJPÊTïÌBÖ £ `t{™?„ ²Ô)˜.´˜™_ _ÐúÈÏ$oä<ð,Ñmô¨ÿ]Xc&T\-$¼Á‚Ñí ^z“µg žbeaº¦i°m»Ã¶m=/"ïFG !àœÃó¼E $ÀBTÀ®£€u¹hjÎÁ× h=* ™ÊÛ…ÌxVR‚T€ê¥6F‰ºEÉ79`] <ã_­FœC ðåbI@È‚7(ðšÆÇÇC£££Fe^“@2™Ä…  BÇ)Š@‚4&~©×ˆØÅ?eÅùv2Üãþ­Sök å.j»h-.hËâô ú às?{åº.\×…RJWJéU%ç–e‹ÀŽã€Rꃡˆ/¼ð@Ø2I 8× Øã& =ÎXå@+”€  ³%97BÒœ+\:ö¸wÖ—;ÐíÂL¸eƺVØÉúš]"—ËÁ¶íše?±X 7Üpƒ;44„T*…l6‹@ 3 á´€ÞâÕ¨Ä((A9Fú£ ïEetQ´ìHA û{ÉV à…;ÏJRq„ Ö½žßséPÌkFn(PT+zACÓ‰¦l~SªËÂs ¹îùÚEA:†eY ”ò|õ})º®# ¥`aaét𦇗’ç⃹ª»¡Aút©L(!ʘ֡µþNÓ¨‹æíéþÿ! ÌvM[€°W|Ò™7¾L¡x‰ÌpoÂ㢛3Õ5T鋬yé«hþ˜™™eYX»vm¶§§Ç­éG(¥®å »˜žžF$)±ÀüA 4d¡…$QP„¥!}*ŒôiÚTÜù†„ XàpŠÇCK8ˆµf ²”$~ÁG—à%ކ4%uÀ] ¤bÎÙ÷ ¸®‰Ø– ´ (xҥȜ!yÒ€t¼2?âÚµkàœ#̃A¯&ÍÍÍ#”RÉ9§ãããèîî.éÓÇL¤.P˜ ," 5f¹f@I¯Ìfª¼tMksÐÚÀ•|üxAùœ£‹ä¯êÂ$êÂèg°~Aé!( qNÈŒ‡ê·AM ¾À`Op& (ÎË6Äu]LLL´c¤Z7Nˆ+𦥕R±‰‰ ¤Óé%Þ¸ãÀ˜ž¿£òrSZX€šÒOµK€2…@ƒæíi¸\!ý~¹aD‚}vQ³?nÈ `]5!]=ÎѼ1‡Èg¦áz²AJ?X# </Ká\$H_ú~Z¾>¥B¡ÐئM›.Ô"{[·n}ïüùóû`zzhoo¯޳fØîk vÍö7`aœ!7Ç¡¯ð$¬ºÆa¥=¸Êã™ ½ÏªYI$­bw¸H&ÀSÚ­ „`xxÙlJ)ôôôü¾¯¯obÙTÝöíÛß;|øð”뺜sŒŒŒ £²EI ¸z¬'õ›Ü\¶í–Y~¥ÝzÔäF޳èxXiØõ“.««Md×TöÎüÍiÚá"5¤0÷›hÑð)8V£<œE‹yÌÍÍ»önºé¦×.7\Þ±cÇë?ùÉOÞO§ÓÛ ÁÊØØº»»¡ëºo/$Aò"wmP£Î­Â &Ûñ«Øhýl ‰w ªY hbÃ@û~Vº É÷›|[! ÒW%Ú<D¯ÃÃ%H^RE„d³Y\»v­˜s5 cê®»îúq(R x6lØ0}Ûm·=/Äbj(—Ëarr²Ù®™Ósg 8rð`-!ŽRC³§)l׆m90ÖϢ㯇¡š–ŒG<ö{†AZS°-ŸÇì‡ó@]sÌœòy8Žƒt:ÉÉIxžWLÈlܸñÿîÚµëýUºcØ¿ÿ+G =Éd0;; ˲າ3—E‘*š+03-påÇÍX—póÇ(~ç8H< v•…Ù`½IDþä×ë:ÈL \þqéq¹ ŽR# —_ˆ";-üñ™ ¦§§áºn1iËÝ·oßÁx<î­¸c&‘Här¹Ü̉'> P£´!„@* ëEò#Jç aBq¸)`öD—ŸiÇÜûAé×6Y›…Î{&@#$øRðà9 ÓoGÀ]!r㩳&`º !Br8I‚™ß†qå`;Rç )ŠÚPH:çµAÞvÛm÷Àü“iš××(²oß¾_=zôǧNú[ÆX±Òq!`š¦ßÈuŽ"u±F{ z3Ïjùz¡n±}Ðä BYxuR+ ˆhàĆç,[³§5Ìœ€Ùî‚5 ðŒgÊðë Ä—Çqœ¢M(‰ÎÎΣ<ðÀÓÍÍÍËvÌÕ"‘H¸_ÿú×ÿÇã?¾errr{¡ë¾á.ä !€ØCP,_{¨ÐBIàØ.<áðêøÃ Ž­ÃιnÅ©õ;SÊÃ-^“…ki³k0œ¸÷Þ{ÿÛÀÀÀøuµŒŒàèÑ£…ɇ[ZZ˜˜xÀ곂³^³wÁÊŒdÆæ¸ U…¹ 8ié'ùÈò­Ð•2äÁÈ%“É'>ü–ã8‡ÃÀš5kP-àªÚgùæ›o⡇B*•ÂÌÌ Ã@ssó¿M$ÿ@é(cEíËŠ sß Ö?r,R=žú Œÿk?¬«ª±C½æÓ¹¼¹¹¹ï]½zõçÜ6 ƒÕÙÙ‰`ûöíèíí]â-Èd2øÅ/~ññq|ë[ß‚mÛ¤äÌ‘®®®:;;¿C‰—‚Ñ0ÊÍÛî˜Gç¾Y?¯–y³ óÇ›1þr¬‘@¾!•¬`îE’ÉäÁáááoqÎÓ¥©‡Ãؼy³:pàš››188¸ˆŸýìgxðÁaYÉ'rIꬫ«ëÞD"ñmJibå`((åx´€ÑÆÁÂÒ#ðæ¼$ók—ׂ577÷ëW¯~›sžª¡øÎƒišØ±c‡zâ‰'pë­·.qþüyÜÿý8v쩈¤I B‰Ä¾D"ñmÆØºëiþV¥¢©r.„\J©ùÙÙÙ¿ûÎy®„jTæ®»îRO?ý4V­ZmÏž=øÊW¾‚'NŠ…Ó ÒÐL&sÞ¶í߃Á^]×W +ÑBJˆæ)ÿw£ øBàyÞÇãããÿyrròóÞ°Vºyk"݃äøñã„¶iÓ&<ÿüóµ*PòÎÇ™L§Óïj𿙦¹žR®PÓ?ê«p3,,,¾zõêcóóó¿VJ‘h•Å“j€NNN’[o½¤©© ¤õ„F?“H$þC8ÞE áÿâ¶mŸžššzfnnî—BˆlÉQ%ïU>/‹ŽŽ¥™¦ ×u—@Ë«øÚ¶=‘J¥ÞvçcÆX1ÖF1?éÕ+¥Çq>œššzzllì©t:}Rù–žUÈZM *“àewsss3HKK ™››#%A)9¥ ”­Â\išijjº%‹íŽD"bF!$°" X¾xs~-—ËL&“ÿœN§çºîLÅÂji¨ø]ThHá9ÕÛÛ Ò€]У$fšf[(º1* ݨëú*ÆX\Ó´03ïžøå g=)eŽsžâœOZ–u1›Í~˜ÍfÏÚ¶=¡”r*xÔ¡rñ¯‘ÕÂw÷–‚@*€`5Ž­¡¤bÇ¥4 iZÄ0Œ¸¦i-„°®ëƘ!¥®ëZJ)K1ïºîœ"#„°JŠé¤Õ€6T‚P©ËQij¡•,¾R+hµëªÊù$5²oÕÎt-’54‚×£Ò€*ø¡ÜÒÑ:‚W PXtég¤ä½–áZÎfÈ2©HÖp¢ª­g1ú¬ÑXZmr²Ì.«*ö¦–õFÝX|éïõÀ¨¥²ŽgY6?c ¬©© ÉdR5BåZq ./i") >> system ("echo " ++ show j ++ " > ./j") >> -- system ("sleep 1") >> hFlush stdout >> system ("darcs record --ignore-times -am '" ++ show i ++ "'") generate :: [Int] -> IO () generate = mapM_ (uncurry stamp) . zip [1..] main :: IO () main = do args <- getArgs let js = (read (head args)) :: [Int] generate js darcs-2.8.4/tests/bin/hspwd.hs0000644001765600176560000000015212104371431015532 0ustar ganeshganeshmodule Main where import System.Directory ( getCurrentDirectory ) main = getCurrentDirectory >>= putStr darcs-2.8.4/tests/network/0000755001765600176560000000000012104371431014774 5ustar ganeshganeshdarcs-2.8.4/tests/network/external.sh0000644001765600176560000000140112104371431017146 0ustar ganeshganesh#!/usr/bin/env bash # Some tests for launching external commands . lib rm -rf temp1 touch_fakessh='./touch-fakessh' if echo $OS | grep -i windows; then touch_fakessh="touch_fakessh.bat" fi export DARCS_SSH=$touch_fakessh export DARCS_SCP=$touch_fakessh export DARCS_SFTP=$touch_fakessh rm -rf 'fakessh' rm -rf 'touch-fakessh' # make our ssh command one word only echo 'echo hello > fakessh' > $touch_fakessh chmod u+x $touch_fakessh # first test the DARCS_SSH environment variable not darcs get example.com:foo grep hello fakessh rm -f fakessh # now make sure that we don't launch ssh for nothing mkdir temp1 cd temp1 darcs init cd .. darcs get temp1 > log not grep fakessh log not darcs get http://darcs.net/nonexistent not grep fakessh log cd .. rm -rf temp1 darcs-2.8.4/tests/network/changes.sh0000644001765600176560000000016212104371431016737 0ustar ganeshganesh#!/usr/bin/env bash set -ev # Demonstrates issue385 darcs changes --repo=http://darcs.net GNUmakefile --last 300 darcs-2.8.4/tests/network/get.sh0000644001765600176560000000053112104371431016106 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp temp2 temp3 #"$DARCS" get http://darcs.net temp darcs get --lazy http://darcs.net temp2 darcs get --lazy --tag . http://darcs.net temp3 cd temp2 darcs obliterate --from-tag . -a darcs pull --tag . -a cd .. diff -u temp2/_darcs/hashed_inventory temp3/_darcs/hashed_inventory rm -rf temp temp2 temp3 darcs-2.8.4/tests/network/ssh.sh0000644001765600176560000000610012104371431016122 0ustar ganeshganesh#!/bin/bash echo 'Comment this line out and run the script by hand'; exit 200 . $(dirname $0)/../lib . $(dirname $0)/sshlib # ================ Setting up remote repositories =============== ${SSH} ${REMOTE} "\ rm -rf ${REMOTE_DIR}; \ mkdir ${REMOTE_DIR}; \ cd ${REMOTE_DIR}; \ \ mkdir testrepo; cd testrepo; \ darcs init; \ echo moi > _darcs/prefs/author; \ touch a; darcs add a; darcs record a --ignore-times -am 'add file a'; \ echo 'first line' > a; darcs record a --ignore-times -am 'add first line to a'; \ cd ..; \ \ darcs get testrepo testrepo-pull; \ cd testrepo-pull; \ echo moi > _darcs/prefs/author; \ touch b; darcs add b; darcs record b --ignore-times -am 'add file b'; \ echo 'other line' > b; darcs record b --ignore-times -am 'add other line to b'; \ cd ..; \ \ darcs get testrepo testrepo-push; \ darcs get testrepo testrepo-send; \ " # ================ Settings =============== echo ${DARCS_SSH_FLAGS} echo ${DARCS_SSH} echo ${DARCS_SCP} echo ${DARCS_SFTP} # ================ Checking darcs get ================== darcs get ${DARCS_SSH_FLAGS} ${REMOTE}:${REMOTE_DIR}/testrepo ${DARCS_SSH_FLAGS} # check that the test repo made it over [ -d testrepo ] [ -d testrepo/_darcs ] [ -f testrepo/a ] # if the above test is disabled we just init a blank repo # so that the other tests can continue if [ ! -d testrepo ]; then mkdir testrepo cd testrepo darcs init cd .. fi # ================ Checking darcs pull ================= darcs get ${DARCS_SSH_FLAGS} testrepo testrepo-pull cd testrepo-pull echo yyy | darcs pull ${DARCS_SSH_FLAGS} ${REMOTE}:${REMOTE_DIR}/testrepo-pull # see if the changes got pulled over grep "other line" b cd .. # ================ Checking darcs push and send =================" darcs get ${DARCS_SSH_FLAGS} testrepo testrepo-push cd testrepo-push echo moi > _darcs/prefs/author echo "second line" >> a; darcs record a --ignore-times -am "add second line to a" touch c; darcs add c darcs record --ignore-times -am "add file c" c echo yyy | darcs push ${DARCS_SSH_FLAGS} ${REMOTE}:${REMOTE_DIR}/testrepo-push # check that the file c got pushed over ${SSH} ${REMOTE} "[ -f ${REMOTE_DIR}/testrepo-push/c ]" echo yyy | darcs send --no-edit-description ${DARCS_SSH_FLAGS} ${REMOTE}:${REMOTE_DIR}/testrepo-send -o mybundle.dpatch # check that the bundle was created grep "add file c" mybundle.dpatch cd .. # ================ Checking darcs put ==================" cd testrepo darcs put ${DARCS_SSH_FLAGS} ${REMOTE}:${REMOTE_DIR}/testrepo-put # check that the put was successful ${SSH} ${REMOTE} "[ -d ${REMOTE_DIR}/testrepo-put/_darcs ]" ${SSH} ${REMOTE} "[ -f ${REMOTE_DIR}/testrepo-put/a ]" cd .. # ======== Checking push over ssh with a conflict =========" ${SSH} ${REMOTE} "echo apply no-allow-conflicts >> ${REMOTE_DIR}/testrepo-put/_darcs/prefs/defaults" cd testrepo echo moi > _darcs/prefs/author echo 'change for remote' > a darcs record --ignore-times -am 'change for remote' darcs push -a darcs ob --last 1 -a echo 'change for local' > a darcs record --ignore-times -am 'change for local' darcs push -a > log 2>&1 || : grep -q 'conflicts options to apply' log cd .. cleanup darcs-2.8.4/tests/network/lazy-get.sh0000644001765600176560000000067012104371431017067 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp temp2 temp3 darcs get --lazy http://darcs.net/repos/franchise temp darcs get --lazy temp temp2 rm -rf temp cd temp2 test ! -f _darcs/patches/0000003700-fb09ec6a61b35ac7aa77e65388b1a0c182fddca9a908f1a08d0bc5653f2f2d2a darcs annotate -p 'initial minimal version' test -f _darcs/patches/0000003700-fb09ec6a61b35ac7aa77e65388b1a0c182fddca9a908f1a08d0bc5653f2f2d2a cd .. rm -rf temp temp2 temp3 darcs-2.8.4/tests/network/issue1503_prefer_local_caches_to_remote_one.sh0000644001765600176560000000261612104371431025737 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1503 - 'Prefer local caches to remote ones' ## ## Copyright (C) 2010 Adolfo Builes ## ## 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. . lib rm -rf S T darcs get --lazy http://darcs.net/testing/repo1 S darcs tag --repo S -m 2 darcs get --lazy http://darcs.net/testing/repo1 T darcs pull --repo T S -a --debug --verbose 2>&1 | tee log not grep repo1 log darcs-2.8.4/tests/network/issue2090-transfer-mode.sh0000644001765600176560000000331012104371431021534 0ustar ganeshganesh#!/usr/bin/env bash ## Test for darcs transfer-mode ## ## Copyright (C) 2012 Eric Kow ## ## 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. echo 'Comment this line out and run the script by hand'; exit 200 . $(dirname $0)/../lib . $(dirname $0)/sshlib # Clean up after previous remote runs ${SSH} ${REMOTE} "\ rm -rf ${REMOTE_DIR}; \ mkdir ${REMOTE_DIR}; \ " # Set up a repo to test darcs init --repo R cd R touch f g darcs add f g darcs record f g -a --ignore-times -m 'add some files' -A moi darcs put $REMOTE:$REMOTE_DIR/R cd .. # Now try darcs get darcs get $REMOTE:$REMOTE_DIR/R S --debug > log 2>&1 COUNT=$(grep -c 'darcs transfer-mode' log) # with issue2090, this was 6! test $COUNT -eq 1 cleanup darcs-2.8.4/tests/annotate.sh0000644001765600176560000000042112104371431015445 0ustar ganeshganesh#!/usr/bin/env bash . lib darcs init mkdir a b touch a/a b/b darcs add --rec . darcs record -a -m ab -A test darcs annotate a/a echo x > c darcs add c darcs record -a -m foo -A 'Mark Stosberg ' darcs annotate c darcs annotate c | grep "a@b.com" cd .. rm -rf temp darcs-2.8.4/tests/EXAMPLE.sh0000644001765600176560000000320412104371431014731 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issueNNNN - ## ## Copyright (C) YEAR AUTHOR ## ## 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. . lib # Load some portability helpers. darcs init --repo R # Create our test repos. darcs init --repo S cd R mkdir d e # Change the working tree. echo 'Example content.' > d/f darcs record -lam 'Add d/f and e.' darcs mv d/f e/ darcs record -am 'Move d/f to e/f.' darcs push ../S -a # Try to push patches between repos. cd .. cd S darcs push ../R -a cd .. darcs-2.8.4/tests/add.sh0000644001765600176560000000032112104371431014363 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp1 mkdir temp1 cd temp1 darcs init touch foo bar darcs add foo bar for (( i=0 ; i < 5; i=i+1 )); do echo $i >> file-$i; darcs add file-$i done cd .. rm -rf temp1 darcs-2.8.4/tests/add_in_subdir.sh0000644001765600176560000000055612104371431016433 0ustar ganeshganesh#!/usr/bin/env bash . lib rm -rf temp1 temp2 mkdir temp1 cd temp1 darcs init mkdir dir echo zig > dir/foo darcs add dir dir/foo darcs record -a -m add_foo # Create second repo inside the first darcs init --repodir=temp2 cd temp2 darcs pull -a ../../temp1 darcs changes -s | grep "A ./dir/foo" # no differences diff ../../temp1/dir/foo dir/foo cd .. rm -rf temp1 darcs-2.8.4/tests/add-formerly-pl.sh0000644001765600176560000000264612104371431016645 0ustar ganeshganesh#!/usr/bin/env bash # Some tests for 'darcs add' . lib rm -rf temp1 temp2 # set up the repository mkdir temp1 cd temp1 darcs init # Make sure that messages about directories call them directories mkdir foo.d mkdir oof.d darcs add foo.d darcs add oof.d not darcs add foo.d 2>&1 | grep -i directory # Try adding the same directory when it's already in the repo not darcs add foo.d oof.d 2>&1 | grep -i directories # Make sure that messages about files call them files touch bar touch baz darcs add bar darcs add baz not darcs add bar 2>&1 | grep -i "following file is" not darcs add bar baz 2>&1 | grep -i "following files are" # Make sure that messages about both files and directories say so not darcs add bar foo.d 2>&1 | grep -i 'files and directories' # Make sure that parent directories are added for files mkdir -p a.d/aa.d/aaa.d mkdir -p b.d/bb.d touch a.d/aa.d/aaa.d/baz touch a.d/aa.d/aaa.d/bar darcs add a.d/aa.d/aaa.d/bar a.d/aa.d/aaa.d/baz b.d/bb.d 2> log test ! -s log # no output # Make sure that darcs doesn\'t complains about duplicate adds when adding parent dirs. mkdir c.d touch c.d/baz darcs add c.d/baz c.d 2> log test ! -s log # no output # Make sure that add output looks good when adding files in subdir mkdir d.d touch d.d/foo darcs add -rv d.d | grep 'd.d/foo' # 'adding a non-existent dir and file gives the expected message not darcs add notadir/notafile 2>&1 | grep -i 'does not exist' cd .. rm -rf temp1 darcs-2.8.4/tests/addmv.sh0000644001765600176560000000047512104371431014740 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp1 temp2 mkdir temp1 temp2 cd temp1 darcs init touch foo bar darcs add foo bar darcs record -a -m add_foo_bar -A x darcs mv foo zig darcs mv bar foo darcs mv zig bar darcs record -a -m swap_foo_bar -A x cd ../temp2 darcs init darcs pull -v -a ../temp1 cd .. rm -rf temp1 temp2 darcs-2.8.4/tests/add_permissions.sh0000644001765600176560000000321112104371431017017 0ustar ganeshganesh#!/usr/bin/env bash ## Darcs should refuse to add an unreadable file, because unreadable ## files aren't recordable. ## ## Copyright (C) 2005 Mark Stosberg ## ## 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. . lib abort_windows # does not work on Windows. mkdir temp1 cd temp1 darcs initialize touch unreadable chmod a-r unreadable # Make the file unreadable. not darcs add unreadable 2> log fgrep -i 'permission denied' log # Testing by hand with a directory works, but darcs-test gets # stuck by having an unreadable subdir. #mkdir d #chmod a-r d #not darcs add --debug --verbose d #fgrep -i 'permission denied' log darcs-2.8.4/tests/addexitval.sh0000644001765600176560000000070212104371431015763 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf tmp mkdir tmp cd tmp darcs init empty='test ! -s' nonempty='test -s' rm -f foo darcs add foo >stdout 2>stderr && exit 1 || true $empty stdout $nonempty stderr >foo darcs add foo >stdout 2>stderr $empty stdout $empty stderr darcs add foo >stdout 2>stderr && exit 1 || true $empty stdout $nonempty stderr rm foo darcs add foo >stdout 2>stderr && exit 1 || true $empty stdout $nonempty stderr cd .. rm -rf tmp darcs-2.8.4/tests/addrace.sh0000644001765600176560000000037412104371431015226 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp1 temp2 mkdir temp1 temp2 cd temp1 darcs init echo zig > foo darcs add foo #sleep 1 darcs record -a -m add_foo -A x cd ../temp2 darcs init darcs pull -a ../temp1 cd .. cmp temp1/foo temp2/foo rm -rf temp1 temp2 darcs-2.8.4/tests/addrm.sh0000644001765600176560000000041212104371431014723 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp1 temp2 mkdir temp1 temp2 cd temp1 darcs init touch foo darcs add foo darcs record -a -m add_foo -A x darcs remove foo darcs record -a -m del_foo -A x cd ../temp2 darcs init darcs pull --all ../temp1 cd .. rm -rf temp1 temp2 darcs-2.8.4/tests/amend-record-back-up.sh0000644001765600176560000000267512104371431017531 0ustar ganeshganesh#!/usr/bin/env bash ## Copyright (C) 2011 Ganesh Sittampalam ## ## 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. . lib # Load some portability helpers. darcs init --repo amend cd amend echo 'file1' > file1 darcs record -lam 'file1' echo 'file2' > file2 darcs record -lam 'file2' echo 'file2:amended' > file2 echo 'nkya' | darcs amend-record darcs changes -p 'file2' -v | grep amended darcs-2.8.4/tests/amend-cancelling.sh0000644001765600176560000000045512104371431017024 0ustar ganeshganesh#!/usr/bin/env bash set -ev # This checks for a possible bug in patch selection where the no available # patches case is hit. rm -rf temp1 mkdir temp1 cd temp1 darcs init touch A darcs add A darcs record -am A echo 'l1' >> A darcs record -am l1 darcs amend-record -a --patch 'A' cd .. rm -rf temp1 darcs-2.8.4/tests/bad-match-pattern.sh0000644001765600176560000000145312104371431017135 0ustar ganeshganesh#!/usr/bin/env bash # This is a test for issue761, which pointed out that we didn't check the # syntax of --match patterns until after having spent considerable time # doing considerable work. So here we construct a very invalid repository, # and check that darcs fails *before* it notices that it's pulling from a # bad repository. Thus we verify that we aren't doing any work prior to # checking the flags. set -ev rm -rf temp1 temp2 mkdir temp1 cd temp1 darcs init touch foo bar darcs add foo bar darcs record -a -m 'add two files' darcs tag -m tag rm foo bar darcs record -a -m 'rm two files' darcs tag -m tag2 rm -rf _darcs/inventories/* rm -rf _darcs/patches/* cd .. mkdir temp2 cd temp2 darcs init ! darcs pull --match 'foobar' ../temp1 2> error cat error grep foobar error rm -rf temp1 temp2 darcs-2.8.4/tests/amend-record.sh0000644001765600176560000000366112104371431016205 0ustar ganeshganesh#!/usr/bin/env bash # Testing amend-record. . lib rm -rf temp1 # set up the repository mkdir temp1 cd temp1 darcs init cd .. # do some work here cd temp1 # Plain amend-record touch foo darcs add foo darcs record -a -m add_foo echo 'another line' > foo echo y | darcs amend -a foo | grep -i 'amending changes' darcs changes -v | grep 'another line' # amend-record of removed file touch bar1 touch bar2 cat > bar1 << FOO a line b line FOO darcs add bar1 bar2 darcs record -a -m add_bars rm -f bar2 echo y | darcs amend -a | grep -i 'finished amending' # Special case: patch is empty after amend cp foo foo.old echo 'another line' >> foo darcs record -a -m add_line foo | grep -i 'finished recording' mv foo.old foo echo y | darcs amend -a foo | grep -i 'amending changes' # Amend --author, -m, etc echo "another line" >> foo echo y | darcs amend -a -m new_name foo | grep -i 'amending changes' darcs changes --last=1 | grep new_name echo "another line" >> foo echo y | darcs amend -a -m new_name -A new_author foo | grep -i 'amending changes' darcs changes --last=1 | grep new_author # check that normally the date changes when we amend echo "another line" >> foo darcs changes --last=1 | head -n 1 > old_date sleep 1 echo y | darcs amend -a foo -A new_author | grep -i 'amending changes' darcs changes --last=1 | head -n 1 > new_date not cmp old_date new_date # check that --keep-date works echo "another line" >> foo darcs changes --last=1 | head -n 1 > old_date sleep 1 echo y | darcs amend -a foo -A new_author --keep-date | grep -i 'amending changes' darcs changes --last=1 | head -n 1 > new_date cmp old_date new_date cd .. # check that the identity changes with --keep-date darcs get temp1 temp2 cd temp2 echo "another line" >> foo darcs changes --last=1 | head -n 1 > old_date echo y | darcs amend -a foo -A new_author --keep-date | grep -i 'amending changes' darcs pull ../temp1 -a --skip-conflicts | grep -i "Skipping some" cd .. rm -rf temp1 temp2 darcs-2.8.4/tests/amend-unrecord.sh0000644001765600176560000000424312104371431016545 0ustar ganeshganesh#!/usr/bin/env bash ## Test for amend-record --unrecord ## ## Copyright (C) 2012 Ganesh Sittampalam ## ## 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. . lib # Load some portability helpers. darcs init --repo R # Create our test repo. cd R (echo x ; echo y) > foo darcs add foo darcs rec -am "add foo" (echo 1 ; echo x ; echo y ; echo 2) > foo darcs rec -am "insert 1 and 2" (echo yyn) | darcs amend-record --unrecord (echo x ; echo y ; echo 2) > foo.expected darcs show contents foo | diff -q foo.expected - (echo yeny) | DARCS_EDITOR="sed -i -e s/2/2j/" darcs amend-record --unrecord (echo x ; echo y ; echo 2j) > foo.expected darcs show contents foo | diff -q foo.expected - echo 'ugh' > bar darcs add bar # use amend to check it's still a short form for amend-record # if we make amend-unrecord visible rather than hidden that would change echo y | darcs amend -a darcs show contents bar | diff -q bar - # test that amend-unrecord alias exists, and --all and specifying files works echo y | darcs amend-unrecord -a foo (echo x ; echo y) > foo.expected darcs show contents foo | diff -q foo.expected - darcs show contents bar | diff -q bar -darcs-2.8.4/tests/apply-hunks.sh0000644001765600176560000000155612104371431016121 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp0 temp1 temp2 # step 1 mkdir temp0 cd temp0 darcs init --darcs-2 echo m1 > foo darcs add foo darcs record -a -m m1 -A moi --ignore-times cd .. # step 2 darcs get temp0 temp1 cd temp1 echo a1 > foo darcs record foo -a -m a1 -A moi --ignore-times cd .. # step 3 cd temp0 echo m2 > foo darcs record -a -m m2 -A moi --ignore-times cd .. # step 4 cd temp1 darcs pull -a echo m2-a1 > foo darcs record -a -m 'Fix conflict m2-a1' -A moi --ignore-times cd .. #step 5 cd temp0 echo m3 > foo darcs record -a -m m3 -A moi --ignore-times cd .. #step 6 darcs get temp0 temp2 cd temp2 echo b1 > foo darcs record -a -m b1 -A moi --ignore-times cd .. #step 7 cd temp0 echo m4 > foo darcs record -a -m m4 -A moi --ignore-times cd .. #step 8 cd temp1 darcs pull -a echo m2-a1-m4 > foo echo y | darcs mark-conflicts cd .. rm -rf temp0 temp1 temp2 darcs-2.8.4/tests/ask_deps.sh0000644001765600176560000000232612104371431015433 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp mkdir temp cd temp darcs init cat > _darcs/prefs/defaults <<. ALL author test ALL ignore-times ALL ask-deps . # add three depending patches for file 'a' # expect no dependency questions # 'q' will abort and cause future failure if an unexpected dependency is asked touch a darcs add a echo q | darcs rec -am a0 darcs ann -p a0 echo 1 > a echo q | darcs rec -am a1 darcs ann -p a1 echo 2 > a echo q | darcs rec -am a2 darcs ann -p a2 # add some patches for file 'b' # expect no dependency questions for file 'b', # but every time expect questions for the three patches of file 'a' # every 'n' should continue to ask about the next patch # the first 'y' should make all following dependencies of 'a' implicit and stop asking # 'q' will abort and cause future failure if an unexpected dependency is asked touch b darcs add b # test 0 echo n/n/n/q | tr / \\012 | darcs rec -am b0 darcs ann -p b0 # test 1 echo 1 > b echo n/n/y/q | tr / \\012 | darcs rec -am b1 darcs ann -p b1 | grep '^\[a0' # test 2 echo 2 > b echo n/y/q | tr / \\012 | darcs rec -am b2 darcs ann -p b2 | grep '^\[a1' # test 3 echo 3 > b echo y/q | tr / \\012 | darcs rec -am b3 darcs ann -p b3 | grep '^\[a2' cd .. rm -rf temp darcs-2.8.4/tests/bad-format.sh0000644001765600176560000000134212104371431015653 0ustar ganeshganesh#!/usr/bin/env bash . lib rm -rf temp1 temp2 gunzip -c $TESTDATA/many-files--old-fashioned-inventory.tgz | tar xf - mv many-files--old-fashioned-inventory temp1 echo '' > temp1/_darcs/format # ensure that we successfully get repositories even if they have a bogus # format file, as can happen if no _darcs/format is present (i.e. it's # generated by an older darcs) and an http server fails to produce a 404 # error code. This is issue757. darcs get temp1 temp2 echo intentional-error >> temp2/_darcs/format cat temp2/_darcs/format rm -rf temp1 not darcs get temp2 temp1 2> err cat err grep intentional-error err grep 'understand repository format' err rm -rf temp1 temp2 darcs-2.8.4/tests/check.sh0000644001765600176560000000344712104371431014724 0ustar ganeshganesh#!/usr/bin/env bash ## Ensure that "darcs check --test" succeeds when run in a complete ## repository with a dummy test that always succeeds. ## ## Copyright (C) 2008 David Roundy ## ## 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. . lib # Load some portability helpers. rm -rf R # Another script may have left a mess. darcs init --repo R darcs setpref --repo R test 'grep hello f' not darcs record --repo R -am 'true test' --test darcs record --repo R -am 'true test' --no-test touch R/f darcs record --repo R -lam 'added foo' --no-test darcs tag --repo R -m 'got f?' echo hello > R/f darcs record --repo R -lam 'hellofoo' --test darcs chec --repo R --test rm -rf R # Clean up after ourselves. darcs-2.8.4/tests/bad_pending_after_pull.sh0000644001765600176560000000147412104371431020314 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -fr temp1 temp2 mkdir temp1 cd temp1 darcs init echo abc > A darcs add A echo def > B1 darcs add B1 # darcs record -all --name patch1 # this way it doesn't trigger the bug for i in 1 2 3 4 5 6 7 8 9 11; do echo y; done | darcs record --name patch1 darcs mv B1 B2 darcs record --all --name patch2 cd .. mkdir temp2 cd temp2 darcs init darcs pull --all ../temp1 darcs whatsnew | grep 'No changes' cd .. rm -fr temp1 temp2 # issue494: note that in this test, we deliberately select filenames # with a backwards sorting order mkdir temp1 cd temp1 darcs init echo abc > b darcs add b darcs record --all -m patch1 darcs mv b a echo def > a darcs record --all -m patch2 cd .. mkdir temp2 cd temp2 darcs init darcs pull --all ../temp1 darcs whatsnew | grep 'No changes' cd .. rm -fr temp1 temp2 darcs-2.8.4/tests/binary.sh0000644001765600176560000000075312104371431015130 0ustar ganeshganesh#!/usr/bin/env bash set -ve binary=example_binary.png function checkbinary(){ cmp $binary ../temp1/$binary } rm -rf temp1 temp2 mkdir temp1 temp2 cd temp1 darcs init cp $TESTDATA/$binary . darcs add $binary darcs record -am P1 cd ../temp2 darcs init test ! -e $binary darcs pull ../temp1 -a checkbinary darcs obliterate -a test ! -e $binary darcs pull ../temp1 -a checkbinary darcs unrecord -a checkbinary darcs revert -a test ! -e $binary darcs unrevert -a checkbinary rm -rf temp1 temp2 darcs-2.8.4/tests/changes.sh0000644001765600176560000000211012104371431015241 0ustar ganeshganesh#!/usr/bin/env bash set -ev # Some tests for 'darcs changes' rm -rf temp1 mkdir temp1 cd temp1 darcs init date >> date.t darcs add date.t darcs record -A 'Mark Stosberg ' -a -m foo date.t #### darcs changes date.t > out # trivial case first cat out grep foo out darcs changes --last=1 date.t > out cat out grep foo out darcs changes --last 1 --summary date.t > out cat out grep foo out darcs changes --last=1 --xml > out cat out grep '<a@b.com>' out # check that --xml encodes < and > ### # Add 6 records and try again for i in 0 1 2 3 4 5; do date >> date.t darcs record -a -m "foo record num $i" date.t done darcs changes date.t > out cat out grep foo out darcs changes --last=1 date.t > out cat out grep foo out darcs changes --last 1 --summary date.t > out cat out grep foo out ### darcs changes --context --from-patch='num 1' --to-patch 'num 4' > out cat out grep 'num 4' out grep 'num 3' out grep 'num 2' out grep 'num 1' out ### date >> second_file.t darcs add second_file.t darcs record -a -m adding_second_file second_file.t cd .. rm -rf temp1 darcs-2.8.4/tests/changes_send_context.sh0000644001765600176560000000057312104371431020031 0ustar ganeshganesh#!/usr/bin/env bash set -ev # RT#544 using context created with 8-bit chars; rm -rf temp1 mkdir temp1 cd temp1 darcs init touch foo darcs record -la -m 'add\212 foo' | grep 'Finished record' darcs changes --context >context date > foo darcs record -a -m 'date foo' | grep 'Finished record' darcs send -a -o patch --context context . | grep 'Wrote patch to' cd .. rm -rf temp1 darcs-2.8.4/tests/changes_with_move.sh0000644001765600176560000000162212104371431017331 0ustar ganeshganesh#!/usr/bin/env bash # Some tests for the output of changes when combined with move. . lib darcs init date > foo darcs add foo darcs record -m 'add foo' -a mkdir d darcs add d darcs record -m 'add d' -a darcs mv foo d darcs record -m 'mv foo to d' -a darcs mv d directory darcs record -m 'mv d to directory' -a echo 'How beauteous mankind is' > directory/foo darcs record -m 'modify directory/foo' -a darcs changes directory/foo > log grep 'add foo' log grep 'mv foo to d' log echo 'O brave new world' > directory/foo # darcs should also take unrecorded moves into account darcs mv directory/foo directory/bar darcs changes directory/foo > log grep 'mv foo to d' log echo 'That has such people in it' > directory/foo darcs add directory/foo darcs record -m 'mv foo then add new foo' -a darcs annotate directory/bar | tee log grep 'O brave new world' log grep "mv foo then add new foo" log not grep "unknown" log darcs-2.8.4/tests/check-read-only.sh0000644001765600176560000000311512104371431016604 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue2001: check is not read-only ## ## Copyright (C) 2011 Florent Becker ## ## 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. . lib # Load some portability helpers. darcs init --repo R # Create our test repos. cd R mkdir d e # Change the working tree. echo 'Example content.' > d/f darcs record -lam 'Add d/f and e.' darcs mv d/f e/ darcs record -am 'Move d/f to e/f.' rm _darcs/pristine.hashed/* # Make the repository bogus cp -r _darcs archive not darcs check diff -r _darcs archive darcs-2.8.4/tests/convert.sh0000644001765600176560000000405512104371431015323 0ustar ganeshganesh#!/usr/bin/env bash ## Tests for convert command based on previously checked results ## to generate new test material for this test, ## see bin/convert-writer.sh ## ## Copyright (C) 2009 Ganesh Sittampalam ## ## 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. . lib grep old-fashioned $HOME/.darcs/defaults || grep hashed $HOME/.darcs/defaults || exit 200 runtest() { rm -rf temp mkdir temp cd temp mkdir repo cd repo darcs init darcs apply --allow-conflicts $TESTDATA/convert/darcs1/$1.dpatch cd .. echo 'I understand the consequences of my action' | darcs convert repo repo2 mkdir empty-darcs2 cd empty-darcs2 darcs init --darcs-2 cd .. cd repo2 darcs send -a -o ../$1-darcs2.dpatch ../empty-darcs2 cd .. diff -I'1 patch for repository ' -I'patches for repository ' -I'Oct 1' -u $TESTDATA/convert/darcs2/$1.dpatch $1-darcs2.dpatch } runtest simple runtest twowayconflict runtest threewayconflict runtest threewayanddep runtest threewayandmultideps runtest resolution runtest tworesolutions darcs-2.8.4/tests/diff.sh0000644001765600176560000000055312104371431014552 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp-$$ mkdir temp-$$ cd temp-$$ set -e darcs initialize echo text > afile.txt darcs add afile.txt darcs record --author me --all --no-test --name init darcs diff darcs diff --no-unified -p . --store-in-mem > diffinmem darcs diff --no-unified -p . --no-store-in-mem > diffondisk diff diffinmem diffondisk cd .. rm -rf temp-$$ darcs-2.8.4/tests/conflict-doppleganger.sh0000644001765600176560000000324112104371431020105 0ustar ganeshganesh#!/usr/bin/env bash . lib # Tests for the doppleganger conflict bug. # For Zooko, with love # Also, for issue81. check_conflict() { cat out if test "$format" = darcs-2; then not grep 'conflict' out else grep 'conflict' out fi } # check doppleganger conflicts rm -rf tmp_dopple tmp_ganger mkdir tmp_dopple cd tmp_dopple darcs init touch a.txt darcs add a.txt darcs record -A base -am 'adding a.txt' cd .. darcs get tmp_dopple tmp_ganger for repo in tmp_dopple tmp_ganger; do echo working on $repo cd $repo echo "text which appears in both places at once" > a.txt darcs record -A $repo -am "recording an identical change in $repo" cd .. done # Now that the conflict has been set up, try pull one patch from the other. cd tmp_ganger darcs pull -a ../tmp_dopple > out check_conflict cd .. # Checking resolution dopplegangers conflicts rm -rf temp0 temp1 temp2 tmp_dopple tmp_ganger mkdir temp0 cd temp0 darcs init cd .. # Create a conflict darcs get temp0 temp1 cd temp1 darcs show repo echo temp1 > a.txt darcs add a.txt darcs record -A base -am 'adding temp1 a.txt' cd .. darcs get temp0 temp2 cd temp2 echo temp2 > a.txt darcs add a.txt darcs record -A base -am 'adding temp2 a.txt' cd .. # Resolve the conflict the same way on both sides for repo in tmp_dopple tmp_ganger; do echo working on $repo darcs get temp1 $repo cd $repo darcs pull -a ../temp2 echo "text which appears in both places at once" > a.txt darcs record -A $repo -am "recording an identical change in $repo" cd .. done # Now that the conflict has been set up, try pull one patch from the other. cd tmp_ganger darcs pull -a ../tmp_dopple > out check_conflict darcs-2.8.4/tests/conflict-fight-failure.sh0000644001765600176560000000153512104371431020170 0ustar ganeshganesh#!/bin/env bash # # Test darcs conflict fight scenario. # # Set up two repos RA and RB. Create conflict in RB. # After resolving conflict in RB, pull new patch from RA. # Repeat, rinse. # # Author: Pekka Pessi # set -ev record="record --ignore-time --all --author X" rm -rf RA RB mkdir RA cd RA echo 0 > file darcs init darcs add file darcs $record -m0 file cd .. darcs get RA RB # Create conflict in RB cd RB echo let it b > file darcs $record -m B cd .. for i in 1 2 3 4 5 # 6 7 8 9 10 11 12 do echo Create new patch A$i in RA cd RA echo a$i > file darcs $record -m A$i cd .. echo Pull patch A$i from RA and get a conflict cd RB time darcs pull ../RA --verbose --all --patch "^A$i\$" cd .. echo Resolve conflict and start fighting by recording B$i cd RB echo let it b > file darcs $record -m B$i cd .. done rm -rf RA RB darcs-2.8.4/tests/conflict-fight.sh0000644001765600176560000000213112104371431016534 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp0 temp1 temp2 # step 1 mkdir temp0 cd temp0 darcs init --darcs-2 echo temp0 > _darcs/prefs/author echo m1 > foo darcs add foo darcs record -a -m m1 --ignore-times cd .. # step 2 darcs get temp0 temp1 cd temp1 echo temp1 > _darcs/prefs/author echo a1 > foo darcs record foo -a -m a1 --ignore-times cd .. # step 3 cd temp0 echo m2 > foo darcs record -a -m m2 --ignore-times cd .. # step 4 cd temp1 darcs pull -a echo m2-a1 > foo darcs record -a -m 'Fix conflict m2-a1' --ignore-times echo a2 > foo darcs record -a -m a2 --ignore-times cd .. #step 5 cd temp0 echo m3 > foo darcs record -a -m m3 --ignore-times cd .. #step 6 darcs get temp0 temp2 cd temp2 echo temp2 > _darcs/prefs/author echo b1 > foo darcs record -a -m b1 --ignore-times cd .. #step 7 cd temp0 echo m4 > foo darcs record -a -m m4 --ignore-times cd .. #step 8 cd temp1 darcs pull -a echo m2-a1-m4 > foo darcs record -a -m 'Fix three-way m2/m2-a1/m4' --ignore-times echo a3 > foo darcs record -a -m a3 --ignore-times cd .. #step 9 cd temp1 darcs pull -av ../temp2 cd .. rm -rf temp0 temp1 temp2 darcs-2.8.4/tests/filepath.sh0000644001765600176560000000544112104371431015437 0ustar ganeshganesh#!/usr/bin/env bash # Some tests for proper handling of filepaths . lib DIR=`pwd` rm -rf temp1 temp2 # Make sure that init works with --repodir darcs init --repodir=temp1 test -d temp1/_darcs # add some meat to that repository cd temp1 touch baz darcs add baz darcs record -m moo -a cd .. # ---------------------------------------------------------------------- # local vs remote filepaths # ---------------------------------------------------------------------- # trick: OS-detection (if needed) if echo $OS | grep -i windows; then echo This test does not work on Windows else darcs get temp1 temp2 cd temp2 mkdir -p dir darcs add dir cd dir touch foo:bar darcs add --reserved-ok foo:bar cd ../.. rm -rf temp2 fi # ---------------------------------------------------------------------- # repodir stuff # ---------------------------------------------------------------------- mkdir -p temp1/non-darcs # FIXME: This test does not seem to make much sense # --repodir is not recursive not darcs get temp1/non-darcs 2> log grep "Not a repository" log rm -rf temp1/non-darcs rm -rf non-darcs # get accepts --repodir. darcs get --repodir=temp2 temp1 | grep -i "Finished getting" test -d temp2/_darcs rm -rf temp2 # get accepts absolute --repodir. darcs get --repodir="${DIR}/temp2" temp1 | grep -i "Finished getting" test -d temp2/_darcs # changes accepts --repodir. darcs changes --repodir=temp1 | grep -i "moo" # changes accepts absolute --repo. darcs changes --repo="${DIR}/temp1" | grep -i "moo" # changes accepts relative --repo. darcs changes --repo=temp1 | grep -i "moo" # [issue467] context --repodir darcs changes --context --repodir=temp1 | grep 'Context:' # dist accepts --repodir. darcs dist --repodir=temp1 | grep -i "Created dist" # optimize accepts --repodir. darcs optimize --reorder-patches --repodir=temp1 | grep -i "done optimizing" # repair accepts --repodir. darcs repair --repodir=temp1 | grep -i "already consistent" # replace accepts --repodir. darcs replace --repodir=temp1 foo bar # setpref accepts --repodir. darcs setpref --repodir=temp1 test echo | grep -i "Changing value of test" # trackdown accepts --repodir. darcs trackdown --repodir=temp1 | grep -i "Success!" # ---------------------------------------------------------------------- # converting between absolute and relative paths # ---------------------------------------------------------------------- rm -rf temp3 darcs get temp1 temp3 cd temp3 mkdir -p a/b cd .. cd temp2 echo hello 1 >> baz darcs record -m hello1 -a echo hello 2 >> baz darcs record -m hello2 -a cd .. # can handle .. path cd temp3 darcs pull ../temp2 --set-default -p1 --all | grep -i 'Finished pulling' darcs pull --dry-run | grep hello2 cd a/b #[issue268] repodir with subdir darcs pull --dry-run | grep hello2 cd .. cd .. rm -rf log temp1 temp2 temp3 darcs-2.8.4/tests/devnull.sh0000644001765600176560000000255112104371431015313 0ustar ganeshganesh#!/usr/bin/env bash ## Test that non-interactive darcs commands work when stdin is /dev/null ## ## Copyright (C) 2011 Ganesh Sittampalam ## ## 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. . lib # Load some portability helpers. darcs init --repo R # Create our test repo. cd R touch wibble darcs rec -lam"wibble" < /dev/null darcs-2.8.4/tests/disable.sh0000644001765600176560000000057112104371431015245 0ustar ganeshganesh#!/usr/bin/env bash . lib # Some tests for 'darcs whatsnew ' rm -rf temp1 mkdir temp1 cd temp1 darcs init touch look_summary.txt # --disable works on command line not darcs whatsnew -sl --disable 2> log grep -i disable log # --disable works from defaults echo 'whatsnew --disable' > _darcs/prefs/defaults not darcs whatsnew -sl 2> log grep -i disable log cd .. rm -rf temp1 darcs-2.8.4/tests/directory_confusion.sh0000644001765600176560000000070612104371431017731 0ustar ganeshganesh#!/usr/bin/env bash set -ev T=temp rm -rf "$T" mkdir "$T" echo "$T" cd "$T" set -e darcs initialize echo text > afile.txt darcs add afile.txt darcs record --author me --all --no-test --name init mkdir d darcs add d mkdir d/e darcs add d/e darcs mv afile.txt d/e/afile.txt echo altered_text > d/e/afile.txt darcs record --author me --all --no-test --name confusion test ! -f _darcs/pristine/afile.txt echo y/d/y | tr / \\012 | darcs unrecord rm -rf "$T" darcs-2.8.4/tests/dist-v.sh0000644001765600176560000000033312104371431015044 0ustar ganeshganesh#!/usr/bin/env bash set -ev # tests for "darcs dist" not () { "$@" && exit 1 || :; } rm -rf temp1 mkdir temp1 cd temp1 darcs init # needs fixed on FreeBSD darcs dist -v 2> log not grep error log cd .. rm -rf temp1 darcs-2.8.4/tests/dist.sh0000644001765600176560000000103612104371431014602 0ustar ganeshganesh#!/usr/bin/env bash # run darcs dist, then extract the resulting archive # and compare it to the original repository content . lib rm -rf temp1 mkdir temp1 cd temp1 darcs init for (( i=0 ; i < 5; i=i+1 )); do echo $i >> file-$i; mkdir dir-$i; echo $i >> dir-$i/file-$i; darcs add file-$i; darcs add dir-$i/file-$i done darcs record -a -m add_foo | grep -i "finished recording" darcs dist mv temp1.tar.gz .. cd .. rm -rf temp1/_darcs mv temp1 temp_orig tar xzf temp1.tar.gz diff -r temp_orig temp1 rm -rf temp_orig temp1 darcs-2.8.4/tests/failing-issue1327.sh0000644001765600176560000000141612104371431016715 0ustar ganeshganesh#!/usr/bin/env bash set -ev # See issue1327. # results in the error: # patches to commute_to_end does not commutex (1) at src/Darcs/Patch/Depends.hs:452 rm -rf temp1 temp2 mkdir temp1 cd temp1 darcs init echo fileA version 1 > fileA echo fileB version 1 > fileB darcs add fileA fileB darcs record --author foo@bar --ignore-times --all -m "Add fileA and fileB" echo fileA version 2 > fileA darcs record --author foo@bar --ignore-times --all -m "Modify fileA" cd .. darcs get temp1 temp2 cd temp2 darcs obliterate -p "Modify fileA" --all darcs unrecord -p "Add fileA and fileB" --all darcs record --author foo@bar --ignore-times --all fileA -m "Add just fileA" cd ../temp1 darcs pull --all ../temp2 echo y | darcs obliterate --dont-prompt-for-dependencies -p "Add fileA and fileB" darcs-2.8.4/tests/double-unrevert.sh0000644001765600176560000000120012104371431016752 0ustar ganeshganesh#!/usr/bin/env bash set -ev # This demonstrates a bug that happens if you revert followed by # a partial unrevert and a full unrevert. It requires that # the second unrevert is working with patches who's contents need # to be modified by the commute in the first unrevert. rm -rf temp1 mkdir temp1 cd temp1 darcs init echo line1 >> A echo line2 >> A echo line3 >> A echo line4 >> A echo line5 >> A echo line6 >> A darcs add A darcs record -am A sed 's/line2/Line2/' A > A1; rm A; mv A1 A sed '4d' A > A1; rm A; mv A1 A sed 's/line6/Line6/' A > A1; rm A; mv A1 A darcs revert -a echo nyn | darcs unrev darcs unrev -a cd .. rm -rf temp1 darcs-2.8.4/tests/emailformat.sh0000644001765600176560000000224612104371431016143 0ustar ganeshganesh#!/usr/bin/env bash . lib set -ev switch_to_latin9_locale rm -rf temp1 rm -rf temp2 rm -rf temp3 mkdir temp1 mkdir temp2 mkdir temp3 cd temp1 seventysevenaddy="" darcs init echo "Have you seen the smørrebrød of René Çavésant?" > non_ascii_file darcs add non_ascii_file darcs record -am "non-ascii file add" -A test cd ../temp2 darcs init cd ../temp1 # long email adress: check that email adresses of <= 77 chars don't get split up darcs send --from="Kjålt Überström $seventysevenaddy" \ --subject "Un patch pour le répositoire" \ --to="Un garçon français " \ --sendmail-command='tee mail_as_file %<' \ -a ../temp2 cat mail_as_file # The long mail address should be in there as a whole grep $seventysevenaddy mail_as_file # Check that there are no non-ASCII characters in the mail cd ../temp3 cat > is_ascii.hs <>= print . not . any (> Data.Char.chr 127) EOF ghc --make is_ascii.hs -o is_ascii ./is_ascii < ../temp1/mail_as_file | grep '^True$' cd .. rm -rf temp1 rm -rf temp2 rm -rf temp3 darcs-2.8.4/tests/init.sh0000644001765600176560000000034712104371431014606 0ustar ganeshganesh#!/usr/bin/env bash . lib rm -rf temp1 temp2 mkdir temp1 cd temp1 darcs init test -d _darcs not darcs init cd .. # Some tests for the repodir flag mkdir temp2 darcs init --repodir temp2 test -d temp2/_darcs rm -rf temp1 temp2 darcs-2.8.4/tests/get.sh0000644001765600176560000000057012104371431014420 0ustar ganeshganesh#!/usr/bin/env bash . lib rm -rf temp1 mkdir temp1 cd temp1 darcs init touch t.t darcs add t.t darcs record -am "initial add" darcs changes --context > my_context DIR=`pwd` abs_to_context="${DIR}/my_context" cd .. rm -rf temp2 darcs get temp1 --context="${abs_to_context}" temp2 darcs changes --context --repo temp2 > repo2_context diff -u "${abs_to_context}" repo2_context darcs-2.8.4/tests/external-resolution.sh0000644001765600176560000000153012104371431017661 0ustar ganeshganesh#!/usr/bin/env bash . lib rm -rf temp1 temp2 mkdir temp1 cd temp1 darcs init echo "Conflict, Base ." > child_of_conflict darcs add child_of_conflict darcs record -am 'Conflict Base' cd .. darcs get temp1 temp2 # Add and record differing lines to both repos cd temp1 echo "Conflict, Part 1." > child_of_conflict darcs record -A author -am 'Conflict Part 1' cd .. cd temp2 echo "Conflict, Part 2." > child_of_conflict darcs record -A author -am 'Conflict Part 2' cd .. cd temp1 echo | darcs pull -a ../temp2 --external-merge 'cp %2 %o' cd .. grep "Part 2" temp1/child_of_conflict diff -u temp1/child_of_conflict temp2/child_of_conflict cd temp1 darcs wh darcs rev -a echo y | darcs unpull --last 1 -a echo | darcs pull -a ../temp2 --external-merge 'cp %1 %o' cd .. cat temp1/child_of_conflict grep "Part 1" temp1/child_of_conflict rm -rf temp1 temp2 darcs-2.8.4/tests/failing-issue1266_init_inside_a_repo.sh0000644001765600176560000000300712104371431022620 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1266 - attempting to initialize a repository inside ## another repository should cause a warning, because while perfectly ## legitimate, it is likely to be accidental. ## ## Copyright (C) 2009 Trent W. Buck ## ## 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. . lib rm -rf temp1 out # Another script may have left a mess. darcs init --repodir temp1 darcs init --repodir temp1/temp2 2>&1 | tee out grep -i WARNING out # A warning should be printed. darcs-2.8.4/tests/failed-amend-should-not-break-repo.sh0000644001765600176560000000412212104371431022263 0ustar ganeshganesh#!/usr/bin/env bash ## Test for keeping the repository in consitent state in case ## of a test failure on amend-record. The bug was almost introduced ## when trying to fix issue 1406. ## ## Copyright (C) 2009 Kamil Dworakowski ## ## 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. . lib set -ev rm -rf R mkdir R cd R darcs init # first patch: new file A touch A darcs add A darcs record -a -m 'A' # second patch: mv A to B darcs mv A B darcs record -a -m 'move' # third patch: modify B echo "content" > B darcs record -a -m 'add content' # amending 'move' results in commuting 'move' patch # to the end for removal. The commute changes the "add content" # patch to modify A instead of B. But the amend is interrupted # because of test failure. Check the consitency after the operation. darcs setpref test false echo yy | not darcs amend -p move --test darcs check # Note: Amend-record in case of test failure is broken as described in issue1406, # though when trying to fix it I almost managed to break darcs even more. # This test is to guard against such regressions in the future. cd .. rm -rf R darcs-2.8.4/tests/failing-haskell_policy.sh0000644001765600176560000000313612104371431020253 0ustar ganeshganesh#!/usr/bin/env bash ## This is a pseudo-test that runs tweaked hlint on the source code. ## ## Copyright (C) 2009 Petr Rockai ## ## 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. . lib explain() { echo >&2 echo "## It seems that hlint has found errors. This usually means that you" >&2 echo "## have used a forbidden function. See contrib/darcs-errors.hlint for" >&2 echo "## explanation. Please also disregard any possible parse errors." >&2 } trap explain ERR hlint >& /dev/null || exit 200 # skip if there's no hlint wd="`pwd`" cd .. hlint --hint=contrib/darcs-errors.hlint src darcs-2.8.4/tests/failing-index-argument.sh0000644001765600176560000000324612104371431020202 0ustar ganeshganesh#!/usr/bin/env bash ## Currently tests if --index works on every command that is supposed to ## support it. The information about what command should support --index is ## taken from http://darcs.net/manual/Darcs_commands.html ## ## Copyright (C) 2011 Andreas Brandt ## ## 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. . lib # Load some portability helpers. rm -rf temp mkdir -p temp cd temp darcs init touch a darcs add a echo "test" >> a darcs record -a -m "record a" a darcs annotate --index 1 darcs changes --index 1 darcs diff --index 1 darcs show contents --index 1 a #### failing tests darcs show files --index 1 a darcs dist --index 1 darcs-2.8.4/tests/failing-issue1013_either_dependency.sh0000644001765600176560000000262512104371431022446 0ustar ganeshganesh#!/usr/bin/env bash set -ev export DARCS_EMAIL=test rm -rf tmp_d1 tmp_d2 tmp_d # Preparations: # Set up two repos, each with a patch (d1 and d2 respectively) with both # an individual change and a change that is identical in both repos, # and thus auto-merge, i.e., they don't conflict in darcs2. Pull them # together and record a patch (problem) on top of the auto-merged change, # so that it depends on EITHER of two patches. mkdir tmp_d1; cd tmp_d1 darcs init --darcs-2 echo a > a echo b > b echo c > c darcs rec -alm init echo a-independent > a echo c-common > c darcs rec -am d1 cd .. darcs get --to-patch init tmp_d1 tmp_d2 cd tmp_d2 echo b-independent > b echo c-common > c darcs rec -am d2 darcs pull -a ../tmp_d1 # no conflicts -- c-common is identical echo c-problem > c darcs rec -am problem cd .. # I want to pull the 'problem' patch, but expect darcs to get confused # because it doesn't know how to select one of the two dependent patches. darcs get --to-patch init tmp_d2 tmp_d cd tmp_d echo n/n/y |tr / \\012 |darcs pull ../tmp_d2 darcs cha # This is weird, we got d2 though we said No. I would have expected # darcs to skip the 'problem' patch in this case. # Try to pull d1 and unpull d2. darcs pull -a ../tmp_d1 exit 1 # darcs hangs here (2.0.2+77)! echo n/y/d |tr / \\012 |darcs obl -p d2 # The obliterate fails with: patches to commute_to_end does not commutex (1) cd .. rm -rf tmp_d1 tmp_d2 tmp_d darcs-2.8.4/tests/failing-issue1014_identical_patches.sh0000644001765600176560000000215312104371431022430 0ustar ganeshganesh#!/usr/bin/env bash set -ev # Set up a base repo. Our experiment will start from this point mkdir base cd base darcs init --darcs-2 printf "Line1\nLine2\nLine3\n" > foo darcs rec -alm Base cd .. # Now we want to record patch A, which will turn "Line2" into "Hello" darcs get base a cd a printf "Line1\nHello\nLine3\n" > foo darcs rec --ignore-times -am A cd .. # Make B the same as A darcs get base b cd b printf "Line1\nHello\nLine3\n" > foo darcs rec --ignore-times -am B cd .. # Now we make a patch C that depends on A darcs get a ac cd ac printf "Line1\nWorld\nLine3\n" > foo darcs rec --ignore-times -am C cd .. # Merge A and B darcs get a ab cd ab darcs pull -a ../b darcs revert -a cd .. # And merge in C too darcs get ab abc cd abc darcs pull -a ../ac darcs revert -a cd .. # Now we can pull just B and C into base darcs get base bc cd bc darcs pull ../abc -ap 'B|C' cd .. # Now we have base, B and C in a repository. At this point we're correct. # Let's try merging AC with BC now, here we discover a bug. darcs get ac abc2 cd abc2 darcs pull -a ../bc darcs changes test `darcs changes | fgrep -c '* C'` -eq 1 darcs-2.8.4/tests/failing-issue1196_whatsnew_falsely_lists_all_changes.sh0000644001765600176560000000036012104371431026113 0ustar ganeshganesh#!/usr/bin/env bash set -ev not () { "$@" && exit 1 || :; } rm -rf temp1 mkdir temp1 cd temp1 darcs init touch aargh darcs add aargh echo utrecht > aargh darcs wh foo foo/../foo/. > out cat out not grep utrecht out cd .. rm -rf temp1 darcs-2.8.4/tests/failing-issue1190_unmarked_hunk_replace_conflict.sh0000644001765600176560000000343512104371431025205 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1190 - conflicts between HUNK and REPLACE are not ## marked by --mark-conflicts. ## ## Copyright (C) 2009 Trent W. Buck ## ## 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. . lib rm -rf d e # Another script may have left a mess. darcs init --repo d/ printf %s\\n foo bar baz >d/f darcs record --repo d/ -lam f1 darcs get d/ e/ darcs replace --repo e/ --force bar baz f darcs record --repo e/ -lam replacement printf %s\\n foo bar quux >d/f # replace baz with quux darcs record --repo d/ -am f2 ## There ought to be a conflict here, and there is. darcs pull --repo e/ d/ -a --mark-conflicts ## The file ought to now have conflict markers in it. grep 'v v v' e/f rm -rf d/ e/ # Clean up after ourselves. darcs-2.8.4/tests/failing-issue1406.sh0000644001765600176560000000615512104371431016720 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1406 - failed test on amend unrecords the ## original patch ## ## Copyright (C) 2009 Adam Vogt, Kamil Dworakowski ## ## 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. . lib # Load some portability helpers. rm -rf R S # Another script may have left a mess. darcs init --repo R # Create our test repos. darcs init --repo S mkdir R/d/ R/e/ # Change the working tree. echo 'Example content.' >R/d/f darcs record --repo R -lam 'Add d/f and e.' darcs mv --repo R d/f e/ darcs record --repo R -am 'Move d/f to e/f.' darcs push --repo R S -a # Try to push patches between repos. darcs push --repo S R rm -rf R/ S/ # Clean up after ourselves. #!/bin/sh set -ev . lib rm -rf temp1 darcs init --repodir temp1 cd temp1 echo "test exit 1" > _darcs/prefs/prefs echo "a" > a darcs record --look-for-adds --no-test --all --name=p1 echo "b" >> a echo "y" | not darcs amend-record --all --patch=p1 # There should be one patch in the repo test 1 -eq `darcs changes --count` || exit 1 # Another check: there should be nothing new after a is restored echo "a" > a not darcs whatsnew -l cd .. rm -rf test1 # the following section of the test does not create a new repo, # it oprates on an existing old-fashioned repo; no need to run it 3 times if grep 'old-fashioned' .darcs/defaults; then # check that we do the operations on checkpoints tentatively rm -rf old-with-checkpoint gunzip -c $TESTDATA/old-with-checkpoint.tgz | tar xf - echo "test exit 1" > old-with-checkpoint/_darcs/prefs/prefs # this amend will fail echo 'y' | not darcs amend --repo old-with-checkpoint -m 'no longer a checkpoint :P' -p "checkpoint here" # check that the patch has not been removed from # the checkpoints inventory grep "checkpoint here" old-with-checkpoint/_darcs/checkpoints/inventory #NOTE: checking the file is a rather white box way of testing it, but # I could not think of any other way at the time, please improve rm -rf old-with-checkpint fi darcs-2.8.4/tests/get-http.sh0000644001765600176560000000271012104371431015373 0ustar ganeshganesh#!/usr/bin/env bash # Written in 2010 by Petr Rockai, placed in public domain # This file is included as part of the Darcs test distribution, # which is licensed to you under the following terms: ## ## 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. . lib rm -rf R S && mkdir R cd R darcs init echo a > a darcs rec -lam a cd .. serve_http # sets baseurl darcs get $baseurl/R S cd S darcs pull ../R | tee log grep "No remote changes" log darcs check darcs-2.8.4/tests/failing-issue1317_list-options_subdir.sh0000644001765600176560000000257312104371431023015 0ustar ganeshganesh#!/bin/sh # Test for issue1317 - darcs mv --list-options returns results from root, and # not from the current directory # Copyright 2009 Marco Túlio Gontijo e Silva # 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. . lib rm -rf R mkdir R cd R darcs init touch abcd mkdir foo darcs add foo cd foo touch abcc mkdir bar darcs mv --list-options | grep -x abcc cd ../.. rm -rf R darcs-2.8.4/tests/failing-issue1325_pending_minimisation.sh0000644001765600176560000000354512104371431023204 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1325 - hunk patches interfere with pending patch ## minimisation ## ## Copyright (C) 2009 Marco Túlio Gontijo e Silva, Eric Kow ## ## 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. . lib # Load some portability helpers. rm -rf R S # Another script may have left a mess. darcs init --repo=R darcs init --repo=S # this is expected to pass regardless of issue1325 # and is here to provide contrast cd R touch file darcs add file darcs record -am ' file' mkdir b darcs add b darcs mv file b rm -r b darcs whatsnew | not grep adddir cd .. # this is/was the failing part of issue1325 cd S echo file > file # we need a hunk to make this interesting darcs add file darcs record -am ' file' mkdir b darcs add b darcs mv file b rm -r b darcs whatsnew | not grep adddir cd .. darcs-2.8.4/tests/failing-issue1363-mark-conflicts.sh0000644001765600176560000000404412104371431021627 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1363 - mark-conflicts should report that there is a ## conflict to mark if apply/push say there are ## ## Copyright (C) 2010 Eric Kow ## Copyright (C) 2009 Thorkil Naur ## ## 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. . lib # Load some portability helpers. rm -rf R S T # Another script may have left a mess. darcs init --repo R # Create our test repos. darcs init --repo S darcs init --repo T cd R touch f.txt darcs add f.txt darcs record -am "Empty f.txt" echo f.txt contents >> f.txt darcs record -am "Contents of f.txt" cd .. cd S echo yn | darcs pull ../R rm f.txt darcs record -am 'Remove f.txt in S' cd .. cd T echo ynn | darcs pull ../R rm f.txt darcs record -am 'Remove f.txt in T' not darcs push -a ../R > log # should fail because of conflict grep "There are conflicts" log cd .. cd R darcs pull -a ../S darcs revert -a darcs pull -a ../T echo y | darcs mark-conflicts > log not grep "No conflicts" log cd .. darcs-2.8.4/tests/failing-issue1396_changepref-conflict.sh0000644001765600176560000000075712104371431022713 0ustar ganeshganesh#!/usr/bin/env bash set -ev . lib rm -rf temp1 temp1a temp1b mkdir temp1 cd temp1 darcs init darcs setpref test 'echo nothing' darcs record -am 'null pref' cd .. darcs get temp1 temp1a cd temp1a darcs setpref test 'echo a' darcs record -am 'pref a' cd .. darcs get temp1 temp1b cd temp1b darcs setpref test 'echo b' darcs record -am 'pref b' cd .. cd temp1 darcs pull -a ../temp1a --dont-allow-conflicts not darcs pull -a ../temp1b --dont-allow-conflicts cd .. rm -rf temp1 temp1a temp1b darcs-2.8.4/tests/failing-issue1401_bug_in_get_extra.sh0000644001765600176560000000360312104371431022273 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1401 - when two repos share a HUNK patch, but that ## patch's ADDFILE dependency is met by different patches in each ## repo, it becomes impossible to pull between the two repos. ## ## Copyright (C) 2009 Trent W. Buck ## ## 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. . lib ## This bug only affects darcs-2 repositories. fgrep darcs-2 ~/.darcs/defaults &>/dev/null || exit 0 rm -rf d e # Another script may have left a mess. darcs initialize --repodir d/ darcs initialize --repodir e/ touch d/f d/g e/f darcs record --repodir d/ -lam 'Add f and g' darcs record --repodir e/ -lam 'Add f' echo >d/f darcs record --repodir d/ -am 'Change f' darcs pull --repodir e/ -a d/ darcs obliterate --repodir e/ -ap 'Add f and g' darcs pull --repodir e/ -a d/ rm -rf d/ e/ # Clean up after ourselves. darcs-2.8.4/tests/failing-issue1522_trailing_slash_borkage.sh0000644001765600176560000000241212104371431023464 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1522 - Trailing slash borkage ## ## Copyright (C) 2012 Andreas Brandt ## ## 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. . lib rm -rf R mkdir R cd R darcs init --repo R touch R/d darcs record --repo R -lam Yow! d/ cd .. darcs-2.8.4/tests/failing-issue1442_encoding_round-trip.sh0000644001765600176560000000415112104371431022743 0ustar ganeshganesh#!/usr/bin/env bash ## -*- coding: utf-8 -*- ## Test for issue1442 - if we disable Darcs escaping and don't change ## our encoding, the bytes in a filename should be the same bytes that ## "darcs changes -v" prints to the right of "addfile" and "hunk". ## ## Copyright (C) 2009 Trent W. Buck ## ## 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. . lib rm -rf R # Another script may have left a mess. ## Use the first UTF-8 locale we can find. export LC_ALL=$(locale -a | egrep 'utf8|UTF-8' | head -1) export DARCS_DONT_ESCAPE_ANYTHING=True ## If LC_ALL is the empty string, this system doesn't support UTF-8. if test -z "$LC_ALL" then exit 1 fi darcs init --repo R echo 'é¦–é  = ×â‚€' >R/'é¦–é  = ×â‚€' darcs record --repo R -lam 'é¦–é  = ×â‚€' 'é¦–é  = ×â‚€' darcs changes --repo R -v 'é¦–é  = ×â‚€' >R/log #cat R/log # Show the humans what the output was. grep -c 'é¦–é  = ×â‚€' R/log >R/count echo 5 >R/expected-count cmp R/count R/expected-count # Both count files should contain "5\n". rm -rf R # Clean up after ourselves. darcs-2.8.4/tests/failing-issue1461_case_folding.sh0000644001765600176560000000401612104371431021410 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1461 - patches to files whose names only differ by ## case can be wrongly applied to the same file in the working directory. ## ## Copyright (C) 2009 Eric Kow ## ## 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. . lib # Load some portability helpers. touch casetest test -e CASETEST || exit 200 rm -rf lower upper joint # Another script may have left a mess. mkdir lower upper cd lower darcs init cat > a << EOF 1 2 3 EOF darcs add a darcs record -am 'lower init a' cd .. cd upper darcs init cat > A << EOF 1 2 3 EOF darcs add A darcs record -am 'upper init A' cd .. darcs get lower joint cd joint darcs pull -a ../upper cd .. cd lower cat > a << EOF one lower 2 3 EOF darcs record -am 'lower modify' cd .. cd upper cat > A << EOF 1 2 three upper EOF darcs record -am 'upper modify' cd .. cd joint darcs pull ../lower -a darcs pull ../upper -a grep one a && not grep three a grep three A && not grep one A cd .. # clean up after ourselves rm -rf lower upper joint darcs-2.8.4/tests/failing-issue1632_changes_nonexisting.sh0000644001765600176560000000327712104371431023040 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1632 - 'darcs changes d/f' should not list any changes, ## where d is part of the repo and f is a non-existent file. ## ## Copyright (C) 2009 Ben Franksen ## ## 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. . lib # Load some portability helpers. rm -rf R # Another script may have left a mess. darcs init --repo R # Create our test repos. cd R mkdir d darcs record -lam 'added directory d' # darcs should not list any changes here: darcs changes non-existent-file > log not grep 'added directory d' log # ...and neither here: darcs changes d/non-existent-file > log not grep 'added directory d' log cd .. darcs-2.8.4/tests/failing-issue1609_ot_convergence.sh0000644001765600176560000000515212104371431022001 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1609 - standard test for the TP2 property ## in the Operational Transformation literature. ## ## According to Wikipedia: ## For every three concurrent operations op1,op2 and op3 defined on the same ## document state, the transformation function T satisfies CP2/TP2 property ## if and only if: ## T(op_3, op_1 \circ T(op_2,op_1)) = T(op_3, op_2 \circ T(op_1,op_2)). ## ## Copyright (C) 2009 Eric Kow ## Copyright (C) 2009 Pascal Molli ## ## 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. . lib # Load some portability helpers. rm -rf S1 S2 S3 # Another script may have left a mess. darcs init --repo S1 # Create our test repos. cd S1 cat > f << END 1 2 3 4 5 END darcs add f darcs record -am init cd .. darcs get S1 S2 darcs get S1 S3 cd S1 cat > f << END 1 2 X 3 4 5 END darcs record -am 'insert X before line 3' cd .. cd S2 cat > f << END 1 2 4 5 END darcs record -am 'delete line 3' cd .. cd S3 cat > f << END 1 2 3 Y 4 5 END darcs record -am 'insert Y after line 3' cd .. darcs pull --allow-conflicts -a --repo S1 S2 darcs pull --allow-conflicts -a --repo S2 S1 darcs pull --allow-conflicts -a --repo S1 S3 darcs pull --allow-conflicts -a --repo S2 S3 darcs pull --allow-conflicts -a --repo S3 S1 # TP2 is just fine for conflict resolution itself... diff S1/f S2/f # no difference diff S2/f S3/f # no difference # But what about the conflict marking? darcs mark-conflicts --repo S1 darcs mark-conflicts --repo S2 darcs mark-conflicts --repo S3 diff S1/f S2/f # no difference diff S2/f S3/f # no difference darcs-2.8.4/tests/failing-issue1610_get_extra.sh0000644001765600176560000000407712104371431020760 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1610 - another bug in get_extra problem ## This is an offshoot of the issue1609 test ## ## Copyright (C) 2009 Eric Kow ## Copyright (C) 2009 Pascal Molli ## ## 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. . lib # Load some portability helpers. # this test is not relevant for darcs 2 repositories (not grep darcs-2 $HOME/.darcs/defaults) || exit 200 rm -rf S1 S2 S3 # Another script may have left a mess. darcs init --repo S1 # Create our test repos. cd S1 cat > f << END 1 2 3 4 5 END darcs add f darcs record -am init cd .. darcs get S1 S2 darcs get S1 S3 cd S1 cat > f << END 1 2 X 3 4 5 END darcs record -am 'insert X before line 3' cd .. cd S2 cat > f << END 1 2 4 5 END darcs record -am 'delete line 3' cd .. cd S3 cat > f << END 1 2 3 Y 4 5 END darcs record -am 'insert Y after line 3' cd .. # please compare this with the issue1609 test darcs pull -a --repo S1 S2 darcs pull -a --repo S1 S3 darcs pull -a --repo S2 S1 darcs pull -a --repo S2 S3 darcs-2.8.4/tests/issue1039.sh0000644001765600176560000000237312104371431015311 0ustar ganeshganesh#!/usr/bin/env bash . lib # pull from not empty repo to empty repo rm -rf temp1 temp2 mkdir temp1 temp2 cd temp1 darcs init echo a > a darcs add a darcs record --all --name=a cd ../temp2 darcs init darcs pull --all --dont-allow-conflicts ../temp1 test `darcs changes --count` = "1" cd .. # push from not empty repo to empty repo rm -rf temp1 temp2 mkdir temp1 temp2 cd temp1 darcs init cd ../temp2 darcs init echo a > a darcs add a darcs record --all --name=a darcs push --all ../temp1 cd ../temp1 test `darcs changes --count` = "1" cd .. # send from not empty repo to not empty repo rm -rf temp1 temp2 mkdir temp1 temp2 cd temp1 darcs init echo a > a darcs add a darcs record --all --name=a for i in 1 2 3 4 5 6 7 8 9; do echo Change number $i >> a darcs record -a -m "change a $i" done cd ../temp2 darcs init echo b > b darcs add b darcs record --all --name=b for i in 1 2 3 4 5 6 7 8 9; do echo Change number $i >> b darcs record -a -m "change b $i" done echo no | darcs send --all --to=random@random --sendmail-command=false ../temp1 echo yes | not darcs send --all --to=random@random --sendmail-command=false ../temp1 not darcs send --all --to=random@random --sendmail-command=false --allow-unrelated-repos ../temp1 cd .. rm -rf temp1 temp2 darcs-2.8.4/tests/failing-newlines.sh0000644001765600176560000000071112104371431017071 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp1 temp2 # set up the repository mkdir temp1 cd temp1 darcs init cd .. cd temp1 echo -n "from temp1" > one.txt darcs add one.txt darcs record -A bar -am "add one.txt" echo >> one.txt cd .. darcs get temp1 temp2 cd temp2 echo "in tmp2" >> one.txt darcs record -A bar -am "add extra line" lines_added=`darcs changes -v --last=1 | grep '\+' | wc -l` echo $lines_added test $lines_added -eq 1 cd .. rm -rf temp1 temp2 darcs-2.8.4/tests/get-http-packed.sh0000644001765600176560000000123412104371431016620 0ustar ganeshganesh#!/usr/bin/env bash # Written in 2010 by Petr Rockai, placed in public domain . lib rm -rf R S && mkdir R cd R darcs init darcs show repo > repo grep "Format: hashed" repo || exit 200 # not supported with oldfashioned repos for f in `seq 1 200`; do echo $f > $f darcs rec -lam $f done darcs optimize # FIXME the pristine.hashed in the basic tarball has extra files # without this step darcs optimize --http test -e _darcs/packs/basic.tar.gz test -e _darcs/packs/patches.tar.gz cd .. serve_http # sets baseurl darcs get --packs $baseurl/R S cd S rm _darcs/prefs/sources # avoid any further contact with the original repository darcs check darcs-2.8.4/tests/failing-issue1702-optimize-relink-vs-cache.sh0000644001765600176560000000605012104371431023520 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1702 - an optimize --relink does not relink the files ## in ~/.darcs/cache. ## ## Copyright (C) 2009 Trent W. Buck ## ## 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. . lib # Load some portability helpers. rm -rf R S # Another script may have left a mess. darcs init --repo R # Create our test repos. ## Create a patch. echo 'Example content.' > R/f darcs record -lam 'Add f.' --repodir R ## Get a hard link into the cache. darcs get R S ## Are hard links available? x=(R/_darcs/patches/*-*) x=${x#R/_darcs/patches/} if [[ ! R/_darcs/patches/$x -ef ~/.darcs/cache/patches/$x ]] then echo This test requires filesystem support for hard links. echo This test requires the hashed (or darcs-2) repo format. exit 200 fi ## IMPORTANT! In bash [[ ]] is neither a builtin nor a command; it is ## a keyword. This means it can fail without tripping ./lib's set -e. ## This is why all invocations below have the form [[ ... ]] || false. ## Confirm that all three are hard linked. ls -lids {~/.darcs/cache,[RS]/_darcs}/patches/$x # debugging [[ R/_darcs/patches/$x -ef ~/.darcs/cache/patches/$x ]] || false [[ S/_darcs/patches/$x -ef ~/.darcs/cache/patches/$x ]] || false [[ R/_darcs/patches/$x -ef S/_darcs/patches/$x ]] || false ## Break all hard links. rm -rf S cp -r R S rm -rf R cp -r S R ## Confirm that there are no hard links. ls -lids {~/.darcs/cache,[RS]/_darcs}/patches/$x # debugging [[ ! R/_darcs/patches/$x -ef ~/.darcs/cache/patches/$x ]] || false [[ ! S/_darcs/patches/$x -ef ~/.darcs/cache/patches/$x ]] || false [[ ! R/_darcs/patches/$x -ef S/_darcs/patches/$x ]] || false ## Optimize *should* hard-link all three together. darcs optimize --relink --repodir R --sibling S ## Confirm that all three are hard linked. ls -lids {~/.darcs/cache,[RS]/_darcs}/patches/$x # debugging [[ R/_darcs/patches/$x -ef ~/.darcs/cache/patches/$x ]] || false [[ S/_darcs/patches/$x -ef ~/.darcs/cache/patches/$x ]] || false [[ R/_darcs/patches/$x -ef S/_darcs/patches/$x ]] || false darcs-2.8.4/tests/failing-issue1790_darcs-send.sh0000644001765600176560000000506012104371431021023 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1790 - darcs send --context foo should not require ## a remote repository ## ## Copyright (C) 2009 Loup Vaillant ## ## 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. . lib # Load some portability helpers. rm -rf R S # Another script may have left a mess. darcs init --repo R # Create our test repos. darcs init --repo S cd R # populate R (optional) echo foo > foo.txt darcs add foo.txt darcs record -a -m "foo" # create a context file to represent R's state darcs changes --context > ../R.context cd .. # copy the repository the hard way. # normally one would use `darcs get A B` to do that, # but when no central server is available, this sort of # hard copy may be perceived as simpler: Just tar xcfz # the repository and send it via email. cp -r R S cd S # Make sure there is no _darcs/prefs/defaultrepo file # If there is one even on new repositories, that would # appear to solve the issue, but I think this is not a # good solution: the absence of the defaultrepo file # is useful to indicate the absence of interaction with # remote repositories. # # Of course, at the time of this writing, the following # line has no effect rm -rf _darcs/prefs/defaultrepo # make some further modifications (optional) echo bar > bar.txt darcs add bar.txt darcs record -a -m "bar" # try to send a patch to the first repository, # using its context file darcs send -a -o ../bar.patch --context=../R.context cd .. darcs-2.8.4/tests/failing-issue1819-pull-dont-allow-conflicts.sh0000644001765600176560000000151412104371431023734 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1819 - pull --dont-allow-conflicts doesn't work ## ## Dave Love , Public domain . lib rm -rf R S for repo in R S; do darcs init --repo $repo cd $repo echo 'Example content.' >x darcs add x darcs record -lam 'Add x' echo $repo >x darcs record -lam 'Change x' cd .. done darcs get S S0 cd S0 # the 'echo |' is for the external merge prompt 'hit return to continue' prompt echo | darcs pull --all --allow-conflicts --external-merge 'cp %2 %o' ../R cd .. darcs get S S0b cd S0b echo | not darcs pull --all --dont-allow-conflicts ../R cd .. darcs get S S1 cd S1 echo | not darcs pull --all --external-merge 'cp %2 %o' --dont-allow-conflicts ../R cd .. darcs get S S2 cd S2 echo | not darcs pull --all --dont-allow-conflicts --external-merge 'cp %2 %o' ../R cd .. darcs-2.8.4/tests/failing-issue1829-inconsistent-conflictor.sh0000644001765600176560000000374412104371431023610 0ustar ganeshganesh#!/usr/bin/env bash ## Leads darcs into creating an inconsistent conflictor. ## Public Domain, 2010, Ganesh Sittampalam, Ian Lynagh and Petr Rockai # This file is included as part of the Darcs test distribution, # which is licensed to you under the following terms: # ## 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. . lib rm -rf r1 r2 mkdir r1 cd r1 darcs init echo Line BB > file darcs add file darcs rec -a -m "Main patch 1" echo Line DDDD >> file darcs rec -a -m "Main patch 2" echo Line A > file echo Line BB >> file echo Line CCC >> file echo Line DDDD >> file echo Line EEEEE >> file darcs rec -a -m "Main patch 3" cd .. mkdir r2 cd r2 darcs init darcs pull -a -p "Main patch 1" ../r1 echo Line TTTTTTT >> file darcs rec -a -m "Alternate patch 1" darcs pull -a -p "Main patch 2" ../r1 darcs revert -a echo Line XXXXXXXXX >> file darcs rec -a -m "Alternate patch 2" echo Line XXXXXXXXX > file darcs rec -a -m "Alternate patch 3" cd .. cd r1 darcs pull -a ../r2 darcs-2.8.4/tests/failing-issue1845-paths-working-copy.sh0000644001765600176560000000315412104371431022466 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1845 - darcs wants file paths from root of working copy ## ## Copyright (C) 2010 Guillaume Hoffmann ## ## 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. . lib # Load some portability helpers. rm -rf R S # Another script may have left a mess. darcs init --repo R # Create our test repos. cd R mkdir subdir touch subdir/subfile darcs add subdir subdir/subfile darcs record -am"add subdir and subfile" cd subdir rm subfile darcs record subfile -am"delete file in subdirectory" # fails because darcs wants subdir/subfile darcs-2.8.4/tests/failing-issue1928-file-dir-replace.sh0000644001765600176560000000273412104371431022032 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1913 - test for directory diffing ## ## Copyright (C) 2010 Ganesh Sittampalam ## ## 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. . lib # Load some portability helpers. rm -rf R # Another script may have left a mess. darcs init --repo R # Create our test repos. cd R touch foo darcs rec -l -a -m "foo file patch" rm foo mkdir foo darcs rec -l -a -m "foo dir patch" cd .. darcs-2.8.4/tests/failing-issue1926_amend-record_ignores_--index.sh0000644001765600176560000000414612104371431024414 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1926 - amend-record --index ## ## Copyright (C) 2010 Iago Abal ## ## 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. . lib # Load some portability helpers. rm -rf R S # Another script may have left a mess. darcs init --repo R # Create our test repos. #darcs init --repo S cd R echo 'Example content 1.' > f darcs record -lam 'Add file f' echo 'Example content 2.' > g darcs record -lam 'Add file g' darcs put ../S # S as a copy of R echo "y" | darcs amend-record --index=2 -m 'A new file f' # Since --index is ignored this command works in # interactive mode, and the amended patch is the one # with index 1. darcs changes > changes cd .. cd S echo "y" | darcs amend-record -p 'Add file f' -m 'A new file f' # -p works as expected and amends the right patch. darcs changes > changes cd .. diff R/changes S/changes # Shows us the differences between both 'darcs changes'. darcs-2.8.4/tests/failing-issue1932-colon-breaks-add.sh0000644001765600176560000000561512104371431022027 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1932 - "darcs add -qr ." should not break on files with colons ## ## Copyright(C) 2010 Dmitry Astapov ## ## 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. . lib # Load some portability helpers. rm -rf R # Another script may have left a mess. mkdir -p R # Create our test repo. cd R darcs init darcs --version # Colons could be in repo names and in file name. # Colon in repo name is an indication of special case - remote repo. # Colon in the file could be there under unix and requires no special treatment. # Repo name with ':' is either scp repo or http repo. # Let's check scp repo first. ( darcs get user@host:path || true ) > log 2>&1 [ -n "$(fgrep '(scp) failed to fetch' log)" ] # HTTP repo ( darcs get http://www.bogus.domain.so.it.will.surely.fail.com || true ) > log 2>&1 [ -n "$(fgrep 'CouldNotResolveHost' log)" ] # All following files should not be added unless "--reserved-ok" is specified, # but should be added with "--reserved-ok" just fine mkdir funny touch funny/0401:19d2 touch funny/c:src touch funny/c:\\src touch funny/user@host:path touch funny/droundy@host: touch funny/host:path # Try to add those files. None should be added, darcs should not fail darcs add -qr funny darcs wh -l > log 2>&1 # Check that darcs didn't drop dead as 2.4.4 does [ -z "$(fgrep 'fromJust: Nothing' log)" ] # Check that no funny files were added [ -z "$(grep '^A \./funny/.' log)" ] # Now let's allow colons and add those files darcs add --reserved-ok -qr funny darcs wh -l > log 2>&1 # This should add all those files [ -n "$(grep '^A \./funny/0401:19d2' log)" ] [ -n "$(grep '^A \./funny/c:src' log)" ] [ -n "$(grep '^A \./funny/c:\\src' log)" ] [ -n "$(grep '^A \./funny/user@host:path' log)" ] [ -n "$(grep '^A \./funny/droundy@host:' log)" ] [ -n "$(grep '^A \./funny/host:path' log)" ] darcs-2.8.4/tests/failing-issue2017-missing-tag.sh0000644001765600176560000000506012104371431021131 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue2017 - apply should gracefully handle tag missing ## from context (complain, not crash) ## ## Copyright (C) 2010 Eric Kow ## ## 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. . lib # Load some portability helpers. darcs init --repo R # Create our test repos. cd R echo 'Example content.' > f darcs record -lam 'Add f' cd .. # variant 0 - this passes trivially darcs get R R0 darcs get R0 S0 darcs tag 's' --repo S0 darcs get S0 T0 cd T0 echo 'More content.' > f darcs record -lam 'Modify f' darcs send -o foo.dpatch -a cd .. not darcs apply --repo R0 T0/foo.dpatch > log 2>&1 not grep bug log grep missing log # variant 1 - tag in shared context darcs get R R1 darcs tag '1' --repo R1 darcs get R1 S1 darcs tag 's1' --repo S1 darcs get S1 T1 cd T1 echo 'More content.' > f darcs record -lam 'Modify f' darcs send -o foo.dpatch -a cd .. # sanity check: should be able to cherry pick darcs get R1 R1b cd R1b [ `darcs changes --count` -eq 2 ] darcs pull ../T1 --match 'touch f' --all [ `darcs changes --count` -eq 3 ] cd .. # the test: can't apply this due to incorrect context not darcs apply --repo R1 T1/foo.dpatch > log 2>&1 not grep 'bug' log grep missing log # variant 2 - tag created after the fact darcs get R R2 darcs get R2 S2 darcs tag 's2' --repo S2 darcs get S2 T2 cd T2 echo 'More content.' > f darcs record -lam 'Modify f' darcs send -o foo.dpatch -a cd .. darcs tag '2' --repo R2 # only tag after not darcs apply --repo R2 T2/foo.dpatch > log 2>&1 not grep 'bug' log grep missing log darcs-2.8.4/tests/failing-issue2066_add_and_remove.sh0000644001765600176560000000277412104371431021735 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue2066 - darcs record fails when deleted file and added file are specified on the command line ## ## Copyright (C) 2011 David Caldwell ## ## 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. . lib rm -rf R mkdir R cd R darcs init echo a > a darcs add a darcs record --all -m "a" rm -f a echo b > b darcs add b darcs record --all -m "-a+b" a b darcs changes -v | grep 'rmfile ./a' # the remove doesn't get recorded even though we told it to. cd .. darcs-2.8.4/tests/failing-issue2086-index-permissions.sh0000644001765600176560000000310412104371431022372 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue2086 - _darcs/index permissions are not preserved ## ## Copyright (C) 2011 Eric Kow ## ## 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. . lib # Load some portability helpers. darcs init --repo R # Create our test repos. cd R echo 'Example content.' > f darcs record -lam 'Add f' --umask 022 ls -l _darcs/index | grep '^.rw..--...' chmod g+w _darcs/index ls -l _darcs/index | grep '^.rw.rw....' echo 'Example content 2.' > f darcs record -lam 'Tweak f' ls -l _darcs/index | grep '^.rw.rw....' cd .. darcs-2.8.4/tests/failing-issue2100-add-failures.sh0000644001765600176560000000311412104371431021236 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue2100 - darcs add should not fail on first failure ## ## Copyright (C) 2011 Eric Kow ## ## 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. . lib # Load some portability helpers. darcs init --repo R # Create our test repos. cd R mkdir d echo 'Example content.' > d/f not darcs add d/non-existent not darcs whatsnew not darcs add d/non-existent d/f darcs whatsnew > log2 2>&1 grep "./d/non-existent does not exist" log2 not grep "addfile ./d/non-existent" log2 grep "adddir ./d" log2 grep "addfile ./d/f" log2 darcs-2.8.4/tests/failing-issue390_whatsnew.sh0000644001765600176560000000113612104371431020553 0ustar ganeshganesh#!/usr/bin/env bash # For issue390: darcs whatsnew somefile" lstats every file in the working copy and pristine/ directory set -ev if ! test -x "$(which strace)" then echo skipping test since strace was not found exit fi rm -rf temp mkdir temp cd temp darcs init date > file1 date > file2 darcs add file* darcs record -am "test" strace darcs whatsnew file1 &> out # we should be accessing file1 grep file1 out # but shouldn't be accessing file2 if grep file2 out then echo A whatsnew for file1 should not involve a 'stat' call to file2 exit 1 else echo Yay. We pass. fi rm -rf temp darcs-2.8.4/tests/failing-issue612_repo_not_writable.sh0000644001765600176560000000143712104371431022432 0ustar ganeshganesh#!/usr/bin/env bash # Test that darcs fails appropriately when the target repo inventory file is not writable. # See issue612 . lib abort_windows if grep old-fashioned .darcs/defaults; then exit 200 fi rm -rf temp1 temp2 mkdir temp1 cd temp1 darcs init touch t.t darcs add t.t darcs record -am "initial add" if [ -e _darcs/inventories ]; then chmod 0555 _darcs/inventories/* chmod 0555 _darcs/inventories fi if [ -e _darcs/inventory ]; then chmod 0555 _darcs/inventory fi cd .. darcs get temp1 temp2 cd temp2 # this block may fail so we'd better make sure we clean up after # ourselves to avoid a permissions mess for other tests trap "cd ..; chmod -R 0755 temp1; rm -rf temp1 temp2" EXIT echo new >> t.t darcs record -am "new patch" not darcs push -a ../temp1 2> log grep failed log darcs-2.8.4/tests/failing-issue68_broken_pipe.sh0000644001765600176560000000061112104371431021127 0ustar ganeshganesh#!/usr/bin/env bash # For issue68, 'don't report "resource vanished" when stdout pipe is broken.' set -ev rm -rf temp1 # Another script may have left a mess. darcs init --repodir temp1 cd temp1 date > f darcs add f darcs rec -am firstp for (( i=0 ; i < 500; i=i+1 )); do echo $i >> f; darcs rec -am p$i done darcs changes 2> err | head touch correcterr diff correcterr err cd .. darcs-2.8.4/tests/failing-merging_newlines.sh0000644001765600176560000000167712104371431020615 0ustar ganeshganesh#!/usr/bin/env bash set -ev # Note that this is fixed, the lines marked # BUG HERE # should be moved back into merging_newlines.sh # trick: requiring something to fail not () { "$@" && exit 1 || :; } rm -rf temp1 temp2 # set up the repository mkdir temp1 cd temp1 darcs init cd .. cd temp1 echo "apply allow-conflicts" > _darcs/prefs/defaults # note: to make this pass, change echo to echo -n # is that right? echo "from temp1" > one.txt darcs add one.txt darcs record -A bar -am "add one.txt" echo >> one.txt darcs wh -u cd .. darcs get temp1 temp2 cd temp2 # reality check darcs show files | grep one.txt echo "in tmp2" >> one.txt darcs whatsnew -s | grep M darcs record -A bar -am "add extra line" darcs annotate -p . -u darcs push -av > log cat log not grep -i conflicts log # BUG HERE # after a conflict, darcs mark-conflicts should report a conflict darcs mark-conflicts > log 2>&1 cat log not grep -i 'no conflicts' log cd .. rm -rf temp1 temp2 darcs-2.8.4/tests/get_tag.sh0000644001765600176560000000255612104371431015261 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp1 temp2 mkdir temp1 cd temp1 darcs initialize echo ALL ignore-times >> _darcs/prefs/defaults echo A > foo darcs add foo darcs record -a -m AA -A x echo B > foo darcs record -a -m BB -A x echo C > foo darcs record -a -m CC -A x darcs tag -m 1.0 -A x cp foo foo_version_1.0 echo D > foo darcs record -a -m DD -A x echo E > foo darcs record -a -m EE -A x echo F > foo darcs record -a -m FF -A x # Check that get store commuted patches cd .. darcs get --tag 1.0 --repo-name temp2 temp1 cmp temp2/foo temp1/foo_version_1.0 rm -rf temp1 temp2 temp3 mkdir temp1 cd temp1 darcs init cat > file < file < file </dev/null; then cat _darcs/patches/pending exit 1 fi fi cd .. rm -rf temp1 temp2 darcs-2.8.4/tests/failing-nice-resolutions.sh0000644001765600176560000000107512104371431020553 0ustar ganeshganesh#!/bin/sh set -ev mkdir temp1 cd temp1 darcs init echo a > foo darcs add foo darcs record -am addfoo cd .. darcs get temp1 temp2 cd temp2 echo B > foo darcs record -am B cd ../temp1 echo b > foo darcs record -am b echo c > foo darcs record -am c cd ../temp2 darcs pull -a cat foo grep b foo && exit 1 grep a foo && exit 1 grep B foo grep c foo echo C > foo darcs record -am C cd ../temp1 echo d > foo darcs record -am d cd ../temp2 darcs pull -a cat foo grep b foo && exit 1 grep a foo && exit 1 grep B foo && exit 1 grep c foo && exit 1 grep C foo grep d foo darcs-2.8.4/tests/failing-pristine-problems.sh0000644001765600176560000000365612104371431020736 0ustar ganeshganesh#!/usr/bin/env bash ## Check for correct behaviour with missing files in pristine ## ## Copyright (C) 2010 Ganesh Sittampalam ## ## 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. . lib # Load some portability helpers. if grep old-fashioned .darcs/defaults; then exit 200; fi rm -rf foo mkdir foo cd foo darcs init echo 'wibble' > wibble darcs rec -lam 'wibble' darcs check roothash=`darcs show pristine | grep ' ./$' | cut -d' ' -f1` wibblehash=`darcs show pristine | grep ' wibble$' | cut -d' ' -f1` rm _darcs/pristine.hashed/$roothash not darcs check not darcs check # At the time of writing this test goes wrong at the line above # I'm not 100% certain if the rest of it is right. darcs repair | grep -v 'The repository is already consistent' darcs check rm _darcs/pristine.hashed/$wibblehash not darcs check not darcs check darcs repair | grep -v 'The repository is already consistent' darcs check darcs-2.8.4/tests/failing-record-scaling.sh0000644001765600176560000000330312104371431020141 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issueN - darcs record shouldn't access old inventories! ## ## Copyright (C) 2008 David Roundy ## ## 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. . lib # Load some portability helpers. which strace || exit 200 # This test requires strace(1). rm -rf R # Another script may have left a mess. darcs init --repo R # Create our test repo. touch R/a-unique-filename strace -eopen -oR/trace \ darcs record --repo R -lam 'A unique commit message.' grep a-unique-filename R/trace grep _darcs/hashed_inventory R/trace not grep _darcs/inventories/ R/trace rm -rf R # Clean up after ourselves. darcs-2.8.4/tests/get-http-packed-detect.sh0000644001765600176560000000214712104371431020072 0ustar ganeshganesh#!/usr/bin/env bash # 2011, by Petr Rockai, Guillaume Hoffmann, public domain # Tets that darcs get --verbose reports getting a pack when there is one, # and does not report when there is none or when --no-packs is passed. . lib rm -rf R S && mkdir R cd R darcs init darcs show repo > repo grep "Format: hashed" repo || exit 200 # not supported with oldfashioned repos for f in `seq 1 200`; do echo $f > $f darcs rec -lam $f done darcs optimize # FIXME the pristine.hashed in the basic tarball has extra files # without this step darcs optimize --http test -e _darcs/packs/basic.tar.gz test -e _darcs/packs/patches.tar.gz cd .. serve_http # sets baseurl # check that default behaviour is to get packs darcs get $baseurl/R S --verbose |grep "Getting packed repository" # check that it does really not get packs when --no-packs is passed rm -rf S darcs get $baseurl/R S --no-packs --verbose |not grep "Getting packed repository" # check that it does not clam getting packs when there are not rm -rf S rm -rf R/_darcs/packs/ darcs get $baseurl/R S --verbose |not grep "Getting packed repository" darcs-2.8.4/tests/gzcrcs.sh0000644001765600176560000000313212104371431015131 0ustar ganeshganesh#!/usr/bin/env bash ## Test for gzcrcs command - check and repair corrupted CRCs on ## compressed files ## ## Copyright (C) 2009 Ganesh Sittampalam ## ## 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. # need to do this before loading lib as that sets -e darcs gzcrcs --help > /dev/null if [ $? == 2 ] ; then echo gzcrcs not supported by this darcs ; exit 0 ; fi . lib # Load some portability helpers. rm -rf maybench-crc gunzip -c $TESTDATA/maybench-crc.tgz | tar xf - cd maybench-crc not darcs gzcrcs --check darcs gzcrcs --repair darcs gzcrcs --check cd .. rm -rf maybench-crc darcs-2.8.4/tests/harness.sh0000644001765600176560000000143712104371431015307 0ustar ganeshganesh#!/usr/bin/env bash set -vex # Print some stuff out for debugging if something goes wrong: echo $HOME echo $PATH which darcs command -v darcs # Check things that should be true when all the testscripts run test -f "$HOME/lib" password="AKARABNADABARAK-KARABADANKBARAKA" grep $password "$HOME/test" || grep $password "$HOME/harness.sh" if echo $OS | grep -i windows; then if echo $OSTYPE | grep -i cygwin ; then real=$(cygpath -w $(command -v darcs.exe) | sed -e 's,\\,/,g' | tr -s '[:upper:]' '[:lower:]') else real=$(cmd //c echo $(command -v darcs.exe) | sed -e 's,\\,/,g' | tr -s '[:upper:]' '[:lower:]') fi wanted=$(echo "$DARCS" | sed -e 's,\\,/,g' | tr -s '[:upper:]' '[:lower:]') test "$real" = "$wanted" else command -v darcs | fgrep "$DARCS" fi darcs-2.8.4/tests/issue1041.sh0000644001765600176560000000030012104371431015266 0ustar ganeshganesh#!/usr/bin/env bash . lib rm -rf temp1 temp2 # this should fail, since temp1 doesn't exist... not darcs get temp1 temp2 # verify that temp2 wasn't created not cd temp2 rm -rf temp1 temp2 darcs-2.8.4/tests/issue1110_get_hashed.sh0000644001765600176560000000037412104371431017451 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp1 temp1-h gunzip -c $TESTDATA/many-files--old-fashioned-inventory.tgz | tar xf - mv many-files--old-fashioned-inventory temp1 darcs get temp1 temp1-h test -e temp1-h/_darcs/hashed_inventory rm -rf temp1 temp1-h darcs-2.8.4/tests/hashed_inventory.sh0000644001765600176560000000570012104371431017212 0ustar ganeshganesh#!/usr/bin/env bash set -ev # We'd just use `diff -x _darcs -r' if -x was portable. diffx () { { find $1 -type f; find $2 -type f; } | sed -e '/.*\/_darcs\//d' -e 's;^[^/]*;;' | grep -v darcs.tix | sort | uniq | { while read part; do diff -c $1$part $2$part done } } makepristine () { rm -rf pristine mkdir pristine for i in `darcs show files --no-files --no-pending`; do echo mkdir -p pristine/$i; mkdir -p pristine/$i; done for i in `darcs show files --no-directories --no-pending`; do echo darcs show contents $i ">" pristine/$i; darcs show contents $i > pristine/$i; cat pristine/$i; done } mkdir temp1 cd temp1 darcs init --hashed touch foo darcs add foo darcs rec -m t1 -a -A tester echo 1 >> foo darcs what -s | grep -v No\ changes darcs what -l | grep -v No\ changes darcs what -sl | grep -v No\ changes makepristine cd .. darcs get temp1 temp2 cd temp2 darcs changes makepristine cd .. darcs get temp1 temp3 cd temp3 darcs changes cp _darcs/hashed_inventory inv darcs optimize diff -c inv _darcs/hashed_inventory rm inv makepristine cd .. cat temp3/pristine/foo diffx temp2 temp3 diff -rc temp1/pristine temp3/pristine diff -rc temp2/pristine temp3/pristine cd temp1 darcs record -a -A tester -m t2 darcs push ../temp2 -a darcs push ../temp3 -a makepristine cd .. cd temp3 makepristine cd .. cd temp2 makepristine cd .. diffx temp2 temp3 diff -rc temp1/pristine temp3/pristine diff -rc temp2/pristine temp3/pristine cd temp1 date > foo darcs record -a -A tester -m t3 makepristine cd ../temp2 darcs pull -a makepristine cd ../temp3 darcs pull -a darcs check makepristine cd .. diffx temp2 temp3 diff -rc temp1/pristine temp3/pristine diff -rc temp2/pristine temp3/pristine cd temp1 darcs put ../temp4 cd .. cd temp4 makepristine cd .. diffx temp2 temp4 diff -rc temp2/pristine temp4/pristine cd temp1 darcs tag -A tagger -m atag darcs check darcs optimize darcs check darcs changes | grep t1 cd .. cd temp3 date > foobarpatch darcs add foobarpatch darcs record -a -A silly -m foobarpatch darcs check darcs optimize darcs check darcs pull -a ../temp1 darcs check darcs optimize --reorder-patches darcs check grep 'Starting with inventory' _darcs/hashed_inventory cd .. cd temp1 darcs pull -a ../temp3 cd .. diff -c temp1/_darcs/hashed_inventory temp3/_darcs/hashed_inventory cd temp4 darcs pull -p foobarpatch -a ../temp3 darcs pull -a ../temp1 darcs optimize --reorder darcs check darcs push ../temp1 cd .. diff temp1/_darcs/hashed_inventory temp4/_darcs/hashed_inventory darcs get temp1 temp5 cd temp5 darcs obliterate --last 3 -a darcs pull ../temp1 -a darcs obliterate --last 3 -a darcs pull ../temp2 -a darcs check darcs obliterate --last 3 -a darcs pull ../temp4 -a cd .. cd temp4 darcs obliterate --last 3 -a darcs pull ../temp5 -a cd .. cd temp2 darcs obliterate --last 3 -a darcs pull ../temp5 -a cd .. cd temp1 darcs obliterate --last 3 -a darcs pull ../temp5 -a cd .. darcs-2.8.4/tests/hidden_conflict.sh0000644001765600176560000000066412104371431016761 0ustar ganeshganesh#!/bin/sh set -ev rm -rf temp1 temp2 mkdir temp1 cd temp1 darcs init --darcs-2 echo first > a darcs add a darcs record -am 'first' cd .. darcs get temp1 temp2 cd temp1 echo second > a darcs record -am 'first to second' echo first > a darcs record -am 'second back to first' cd .. cd temp2 echo third > a darcs record -am 'first to third' cd .. cd temp1 darcs pull -a ../temp2 | grep conflict grep third a cd .. rm -rf temp1 temp2 darcs-2.8.4/tests/hidden_conflict2.sh0000644001765600176560000000153012104371431017034 0ustar ganeshganesh#!/usr/bin/env bash set -ev # A test for a missed resolution, inspired by bug #10 in RT rm -rf temp1 temp2 mkdir temp1 cd temp1 darcs init cd .. mkdir temp2 cd temp2 darcs init cd .. # set up temp1 cd temp1 cat > A << FOO i m b v FOO darcs add A darcs record -m 'add' --all cd .. # set up temp2 cd temp2 darcs pull --all ../temp1 cat > A << FOO J i C2 m D b v FOO darcs record -m 'change2' --all cd .. # generate a conflict cd temp1 cat > A << FOO I i C1 m b FOO darcs record -m 'change1' --all darcs pull --all ../temp2 # we should have a marked conflict now. grep 'v v' A # we resolve it simply by removing conflict markers. sed -e '/\^ \^\|\*\*\|v v/d' A > temp mv temp A darcs record -m resolution --all # now mark-conflicts shouldn't find any unmarked conflicts darcs mark-conflicts | grep "No conflicts to mark" cd .. rm -rf temp1 temp2 darcs-2.8.4/tests/hunk-editor.sh0000644001765600176560000000312512104371431016071 0ustar ganeshganesh#!/usr/bin/env bash ## Test for hunk editor ## ## Copyright (C) 2011 Ganesh Sittampalam ## ## 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. . lib # Load some portability helpers. rm -rf R # Another script may have left a mess. darcs init --repo R cd R echo 'version1' > file darcs record -lam "version1" echo 'version2' > file (echo e ; echo y ; echo n) | DARCS_EDITOR="sed -i -e s/version2/version1.5/" darcs record -m "version1.5" cat > expected < log < out cat out grep Proceed out darcs whatsnew echo y | darcs record -a --logfile log not darcs whatsnew darcs changes > out cat out not grep 'My private secret' out darcs changes --xml > out cat out grep 'My private secret' out cd .. rm -rf temp1 darcs-2.8.4/tests/ignoretimes.sh0000644001765600176560000000110212104371431016156 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp1 mkdir temp1 cd temp1 darcs init echo -e 'foo\nbar\nbaz' > f darcs rec -Ax -alm p1 echo -e 'foo\nbar\nwibble' > f darcs rec -Ax -alm p2 sleep 1 # ensure the timestamps would differ after this change alone echo -e 'baz\nbar\nwibble' > f # check that wh (without --ignore-times) sees the change now darcs wh > whatsnew grep 'foo' whatsnew # the problematic unpull darcs unpull --last 1 -a --ignore-times # whatsnew will now think there are no changes without --ignore-times darcs wh > whatsnew grep 'foo' whatsnew cd .. rm -rf temp1 darcs-2.8.4/tests/illegal_mv.sh0000644001765600176560000000050712104371431015754 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp mkdir temp cd temp darcs initialize echo text > afile.txt darcs add afile.txt darcs record --author me --all --no-test --name init mkdir d echo The following mv should fail, since d isnt in the repo. if darcs mv afile.txt d/afile.txt; then false fi # Now clean up. cd .. rm -rf temp darcs-2.8.4/tests/impossible_unrevert.sh0000644001765600176560000000147512104371431017746 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp mkdir temp cd temp darcs init echo ALL ignore-times > _darcs/prefs/defaults echo a > foo darcs add foo darcs record -a -m aa -A test echo b > foo echo y | darcs revert -a echo y/d/y | tr / \\012 | darcs unrecord # since the unrevert is impossible, we should fail if it succeeds... echo y | darcs unrevert && exit 1 || true # now let's try a possible unrevert, just for fun... echo b >> foo darcs record -a -m bb -A test echo f/b | tr / \\012 > foo darcs record -a -m 'aaa becomes f' -A test date >> foo echo y | darcs revert -a echo y/d/y | tr / \\012 | darcs unpull # Now add the date back on at the end: echo y | darcs unrevert echo 'M ./foo +1' > correct_summary darcs whatsnew --dont-look-for-adds --summary > actual_summary diff -c correct_summary actual_summary cd .. rm -rf temp darcs-2.8.4/tests/issue1012_unrecord_remove.sh0000644001765600176560000000046312104371431020554 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp1 mkdir temp1 cd temp1 darcs --version darcs init echo temp1 >File.hs darcs add File.hs darcs record File.hs -a -m "add File" rm File.hs darcs record -a -m "rm File" darcs cha darcs unrecord -p "rm File" -a darcs cha darcs record -a -m "re-rm File" cd .. rm -rf temp1 darcs-2.8.4/tests/invalid_absolute_paths.sh0000644001765600176560000000356312104371431020371 0ustar ganeshganesh#!/usr/bin/env bash ## ## Regression test for patch178 ## ## Copyright (C) 2010 Alexey Levan ## ## 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. . lib # Load some portability helpers. rm -rf R # Another script may have left a mess. darcs init --repo R # Create our test repos. cd R if darcs move /non_existent_path/a /non_existent_path/b 2>&1 | grep 'bug'; then echo 'Not OK 1: darcs move causes a bug' exit 1 else echo 'OK 1' fi if darcs move /non_existent_path/a /non_existent_path/b /non_existent_path/c 2>&1 | grep 'Prelude.init: empty list'; then echo 'Not OK 2: darcs move causes an error' exit 1 else echo 'OK 2' fi if darcs annotate /non_existent_path/a 2>&1 | grep 'Pattern match failure'; then echo 'Not OK 3: darcs annotate causes an error' exit 1 else echo 'OK 3' fi cd .. rm -rf R darcs-2.8.4/tests/issue1057.sh0000644001765600176560000000275312104371431015313 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1057 - when pulling from a symlink to the current ## repository, Darcs should detect that it *is* the current repo. ## ## Copyright (C) 2008 Thorkil Naur ## ## 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. . lib rm -rf temp mkdir temp cd temp mkdir repo cd repo darcs init cd .. ln -s repo srepo cd srepo DIR=`pwd` echo $DIR not darcs pull --debug -a "$DIR" 2> out cat out grep 'Can.t pull from current repository' out cd .. cd .. rm -rf temp darcs-2.8.4/tests/invalid_pending_after_mv_to_self.sh0000644001765600176560000000043512104371431022371 0ustar ganeshganesh#!/usr/bin/env bash # A regression test for issue567 set -ev rm -rf temp mkdir temp cd temp darcs init mkdir dir touch dir/t.t darcs add dir darcs add dir/t.t darcs record -am 'initial add' # grand finale? Can we move the file to itself? darcs mv dir/t.t dir/ cd .. rm -rf temp darcs-2.8.4/tests/issue1017_whatsnew_stack.sh0000644001765600176560000000037512104371431020412 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp1 mkdir temp1 cd temp1 darcs init printf "File contents" > foo darcs add foo darcs record -a -m 'foo' foo for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16; do cat foo foo > foo2; mv foo2 foo; done darcs what cd .. darcs-2.8.4/tests/issue1043_geteff_a.sh0000644001765600176560000000211312104371431017114 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp1 temp2 # creating the fork point mkdir temp1 cd temp1 darcs init cat > foo << FOO original - apple original - banana FOO darcs add foo darcs record -am init cd .. darcs get temp1 temp2 # do some work in the mainline cd temp1 cat > foo << FOO conflict 1 - artichoke original - banana FOO darcs record -am 'conflict 1a' cat > foo << FOO conflict 1 - artichoke conflict 1 - brocolli FOO darcs record -am 'conflict 1b' cd .. # do some work in the branch cd temp2 cat > foo << FOO conflict 2 - aardvark original - banana conflict 2 - cougar FOO darcs record -am 'conflict 2' cd .. # in the branch, pull from the mainline and resolve the conflict cd temp2 darcs pull -a ../temp1 --allow-conflicts cat > foo << FOO resolution original - apple original - banana FOO darcs record -am 'resolve conflicts 2,1a,1b' cd .. # do some extra work in the mainline cd temp1 cat > foo << FOO original - apple FOO darcs record -am 'conflict 1c' cd .. # in the branch, pull from the mainline again cd temp2 darcs pull -a ../temp1 --allow-conflicts cd .. rm -rf temp1 temp2 darcs-2.8.4/tests/issue1043_geteff_b.sh0000644001765600176560000000210512104371431017116 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp1 temp2 # creating the fork point mkdir temp1 cd temp1 darcs init cat > foo << FOO original - apple original - banana FOO darcs add foo darcs record -am init cd .. darcs get temp1 temp2 # do some work in the mainline cd temp1 cat > foo << FOO original - apple conflict 1 - brocolli FOO darcs record -am 'conflict 1b' cat > foo << FOO conflict 1 - artichoke original - banana FOO darcs record -am 'conflict 1a' cd .. # do some work in the branch cd temp2 cat > foo << FOO conflict 2 - aardvark original - banana conflict 2 - cougar FOO darcs record -am 'conflict 2' cd .. # in the branch, pull from the mainline and resolve the conflict cd temp2 darcs pull -a ../temp1 --allow-conflicts cat > foo << FOO resolution original - apple original - banana FOO darcs record -am 'resolve conflicts 2,1a,1b' cd .. # do some extra work in the mainline cd temp1 cat > foo << FOO original - apple FOO darcs record -am 'conflict 1c' cd .. # in the branch, pull from the mainline again cd temp2 darcs pull -a ../temp1 --allow-conflicts cd .. rm -rf temp1 temp2 darcs-2.8.4/tests/issue1078_symlink.sh0000644001765600176560000000066312104371431017062 0ustar ganeshganesh#!/usr/bin/env bash . lib if echo $OS | grep -i windows; then echo this test does not work on windows because echo windows does not have symlinks exit 0 fi rm -rf temp1 temp2 mkdir temp1 ln -s temp1 temp2 cd temp2 darcs init touch a b DIR=`pwd` darcs add "${DIR}/../temp1/a" # should work, just to contrast with the case below darcs add "${DIR}/b" # this is the case we are testing for cd .. rm -rf temp1 temp2 darcs-2.8.4/tests/issue1101.sh0000644001765600176560000000116012104371431015270 0ustar ganeshganesh#!/usr/bin/env bash set -ev DARCS_EDITOR=echo export DARCS_EDITOR export SENDMAIL=`which true` rm -rf temp1 temp2 mkdir temp1 temp2 cd temp2 darcs init # setup test cd ../temp1 darcs init touch foo bar darcs add foo bar darcs record -a -m add_foo_bar -A x # Test that --cc is also printed as recipient in case of success darcs send --author=me -a --to=random@random --cc=foo@example.com ../temp2 2>&1|grep -i foo@example.com # Test that --cc is also printed as recipient in case of error darcs send --author=me -a --to=random@random --cc=foo@example.com ../temp2 2>&1|grep -i foo@example.com cd .. rm -rf temp1 temp2 darcs-2.8.4/tests/issue1105.sh0000644001765600176560000000137112104371431015300 0ustar ganeshganesh#!/usr/bin/env bash . lib rm -rf temp mkdir temp cd temp darcs init darcs changes echo changes summary > _darcs/prefs/defaults darcs changes echo changes summary arg > _darcs/prefs/defaults not darcs changes echo ALL summary > _darcs/prefs/defaults darcs changes echo ALL summary arg > _darcs/prefs/defaults not darcs changes echo changes last 10 > _darcs/prefs/defaults darcs changes echo changes last > _darcs/prefs/defaults not darcs changes echo ALL last 10 > _darcs/prefs/defaults darcs changes echo ALL last > _darcs/prefs/defaults not darcs changes echo changes author me > _darcs/prefs/defaults not darcs changes echo ALL author me > _darcs/prefs/defaults darcs changes echo ALL unknown > _darcs/prefs/defaults not darcs changes cd .. rm -rf temp darcs-2.8.4/tests/issue1300_record_delete-file.sh0000644001765600176560000000351112104371431021070 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1300 - record --delete-file should only delete ## after a successful record ## ## Copyright (C) 2009 Eric Kow ## ## 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. . lib # Load some portability helpers. rm -rf R # Another script may have left a mess. darcs init --repo R # Create our test repos. cd R touch f darcs add f # no test touch log echo 'no test' > f darcs record -am f --logfile log --delete-logfile test ! -e log # passing test touch log darcs setpref test 'exit 0' echo 'test pass' > f darcs record -am f --test --logfile log --delete-logfile test ! -e log # failing test touch log darcs setpref test 'exit 1' echo 'test fail' > f not darcs record -am g --test --logfile log --delete-logfile test -e log # should *not* be deleted cd .. darcs-2.8.4/tests/issue1111-pull-intersection.sh0000644001765600176560000000354612104371431020761 0ustar ganeshganesh#!/usr/bin/env bash # This file is included as part of the Darcs test distribution, # which is licensed to you under the following terms: # ## 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. . lib # This test script is in the public domain. # This file is included as part of the Darcs test distribution, # which is licensed to you under the following terms: # rm -rf temp1 temp2 temp3 mkdir temp1 cd temp1 darcs initialize echo A > A darcs add A darcs record -a -m Aismyname echo B > B darcs add B darcs record -a -m Bismyname cd .. darcs get temp1 temp2 cd temp2 darcs obliterate --last 1 -a echo C > C darcs add C darcs record -a -m Cismyname cd .. mkdir temp3 cd temp3 darcs init darcs pull -a -v --intersection ../temp1 ../temp2 darcs changes > out cat out grep Aismyname out not grep Bismyname out not grep Cismyname out cd .. rm -rf temp1 temp2 temp3 darcs-2.8.4/tests/issue1139-diff-last.sh0000644001765600176560000000065312104371431017160 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp-$$ mkdir temp-$$ cd temp-$$ set -e darcs initialize echo text > foo darcs add foo darcs rec -am 'add foo' darcs annotate -p . echo newtext > foo darcs record -am 'modify foo' darcs diff --no-unified --store-in-mem --last=1 > out1 cat out1 grep text out1 grep foo out1 darcs diff --no-unified --last=1 > out cat out grep text out grep foo out diff -u out1 out cd .. rm -rf temp-$$ darcs-2.8.4/tests/issue1139-diff-with-no-args.sh0000644001765600176560000000055012104371431020530 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp-$$ mkdir temp-$$ cd temp-$$ set -e darcs initialize echo text > foo darcs add foo darcs record -am 'add foo' echo newtext > foo darcs wh darcs diff --no-unified --store > out1 cat out1 grep text out1 grep foo out1 darcs diff --no-unified > out cat out grep text out grep foo out diff out out1 cd .. rm -rf temp-$$ darcs-2.8.4/tests/issue121.sh0000644001765600176560000000336012104371431015215 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue121 - amend-record --ask-deps ## ## Copyright (C) 2009 Ganesh Sittampalam ## ## 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. . lib # Load some portability helpers. rm -rf R darcs init --repo R # Create our test repos. cd R touch a darcs add a darcs rec --ignore-times -am 'add a' (echo '1' ; echo '1' ; echo '1') > a darcs rec --ignore-times -am 'patch X' (echo '2' ; echo '1' ; echo '1') > a darcs rec --ignore-times -am 'patch Y' (echo '2' ; echo '1' ; echo '2') > a darcs rec --ignore-times -am 'patch Z' darcs obliterate --dry-run --patch 'patch Y' | not grep 'patch Z' echo 'yy' | darcs amend-rec --ask-deps darcs obliterate --dry-run --patch 'patch Y' | grep 'patch Z' darcs-2.8.4/tests/issue1248.sh0000644001765600176560000000046212104371431015310 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1248 - darcs doesn't handle darcs 1 repos with compressed ## inventories ## ## Placed into the public domain by Ganesh Sittampalam, 2009 . lib gunzip -c $TESTDATA/oldfashioned-compressed.tgz | tar xf - cd oldfashioned-compressed darcs optimize --upgrade darcs check darcs-2.8.4/tests/issue1162_add_nonexistent_slash.sh0000644001765600176560000000026412104371431021743 0ustar ganeshganesh#!/bin/sh set -ev not () { "$@" && exit 1 || :; } rm -rf temp mkdir temp cd temp darcs init not darcs add a/ 2> err cat err grep 'File a does not exist!' err cd .. rm -rf temp darcs-2.8.4/tests/issue1269_setpref_predist.sh0000644001765600176560000000077512104371431020604 0ustar ganeshganesh#!/bin/sh set -ev not () { "$@" && exit 1 || :; } rm -rf temp rm -rf dist1269.tar.gz mkdir temp cd temp darcs init printf "Line1\nLine2\nLine3\n" > foo darcs record -alm Base darcs setpref predist false # It is a bug in darcs if the dist succeeds. It should # fail with a non-zero exit code not darcs dist -d dist1269 # It is a bug in darcs if the dist file has been created # it should /not/ be created if the predist cmd returned # a non-zero exit code not test -f dist1269.tar.gz cd .. rm -rf temp darcs-2.8.4/tests/match.sh0000644001765600176560000000451112104371431014734 0ustar ganeshganesh#!/usr/bin/env bash # Some tests for the '--match' flag . lib # set up the repository rm -rf temp1 # another script may have left a mess. mkdir temp1 cd temp1 darcs init cd .. # create three patches - the property we exploit to determine # if a matcher does the right thing is that each patch has a # different author cd temp1 touch bar darcs add bar darcs record -a -m "first patch" bar -A author1 echo foo > bar darcs record -a -m "\"second\" \\ patch" bar -A author2 echo blop > bar darcs record -a -m "second" bar -A author3 cd .. # ------------------------------------------------------------------- # single matchers # ------------------------------------------------------------------- cd temp1 # matching on author really matches on that, and not something else darcs changes --match='author "first patch"' > log not grep '.' log # normal changes shows both authors and patch names darcs changes > log grep author1 log grep author2 log grep author3 log grep 'first patch' log grep '"second" \\ patch' log grep -v patch log | grep second # exact darcs changes --match='exact second' > log not grep author1 log not grep author2 log grep author3 log # name darcs changes --match='name second' > log not grep author1 log grep author2 log grep author2 log # author darcs changes --match='author author1' > log grep author1 log not grep author2 log not grep author3 log #hash darcs changes --xml-output --match='exact "\"second\" \ patch"' > log hash=`grep hash log | sed -e "s/.*hash='//" -e "s/'.*//"` echo $hash darcs changes --match="hash $hash" not grep author1 log grep author2 log not grep author3 log cd .. # ------------------------------------------------------------------- # matching on combinations # # uses the setup from the atomic patches # ------------------------------------------------------------------- cd temp1 # or darcs changes --match='author author1 || author author2' > log grep author1 log grep author2 log not grep author3 log # and darcs changes --match='name second && author author2' > log not grep author1 log grep author2 log not grep author3 log # not darcs changes --match='not name second' > log grep author1 log not grep author2 log not grep author3 log # grouping darcs changes --match='(not name second) || (author author3)' > log grep author1 log not grep author2 log grep author3 log cd .. rm -rf temp1 darcs-2.8.4/tests/issue1210-no-global-cache-in-sources.sh0000644001765600176560000000256212104371431022276 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1210 - 'global cache gets recorded in _darcs/prefs/sources' ## ## Copyright (C) 2010 Adolfo Builes ## ## 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. set -ev . lib cacheDir=$HOME/.darcs/cache rm -rf R S darcs init --repo R darcs get R S not grep "$cacheDir" S/_darcs/prefs/sources not grep "cache:" S/_darcs/prefs/sourcesdarcs-2.8.4/tests/issue1224_convert-darcs2-repository.sh0000644001765600176560000000332212104371431022431 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1224 - Attempting to darcs convert a repository ## which is already in darcs-2 format leads to inconsistent result ## ## Copyright (C) 2009 Tomas Caithaml ## ## 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. # this test is not relevant for other than darcs 2 repositories grep darcs-2 $HOME/.darcs/defaults || exit 200 . lib rm -rf R darcs init --repo R echo File contents > R/file.txt darcs add R/file.txt --repodir R darcs record --name=add_file.txt --author=me --no-test -a --repodir R # This should fail with repository already in darcs-2 format. echo "I understand the consequences of my action" > ack not darcs convert temp/repo-2 temp/repo-2-converted < ack rm -rf R darcs-2.8.4/tests/issue1277-repo-format.sh0000644001765600176560000000376412104371431017553 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1277 - repository format errors should be reported ## correctly (ie. not as some totally unrelated error) ## ## Copyright (C) 2010 Eric Kow ## ## 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. . lib # Load some portability helpers. rm -rf R # Another script may have left a mess. darcs init --repo R # Create our test repos. cd R darcs init --repo R2 # Protect the darcs darcs repo with R cd R2 echo impossible >> _darcs/format echo 'Example content.' > f not darcs add f > log 2>&1 grep "Can't understand repository format" log not darcs whatsnew > log 2>&1 grep "Can't understand repository format" log not darcs init > log 2>&1 grep "You may not run this command in a repository" log grep "Can't understand repository format" log cd .. not darcs whatsnew --repodir R2 > log 2>&1 grep "R2 looks like a repository directory," log grep "Can't understand repository format" log cd .. darcs-2.8.4/tests/issue1290-diff-index.sh0000644001765600176560000000323112104371431017315 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1290 - darcs diff --index ## ## Copyright (C) 2010 Eric Kow ## ## 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. . lib # Load some portability helpers. rm -rf R # Another script may have left a mess. darcs init --repo R # Create our test repos. cd R echo '1' > f darcs record -lam 'one' echo '2' > f darcs record -lam 'two' echo '3' > f darcs record -lam 'three' echo '4' > f darcs record -lam 'four' darcs diff --no-unified --from-patch one --to-patch two > d1 darcs diff --no-unified --index=3-4 > d2 # the numbers go backwards diff -q d1 d2 cd .. darcs-2.8.4/tests/issue184_add.sh0000644001765600176560000000047412104371431016041 0ustar ganeshganesh#!/usr/bin/env bash . lib # For issue184: recording files in directories that haven't explicity been added. rm -rf temp1 mkdir temp1 cd temp1 darcs init mkdir new mkdir new/dir touch new/dir/t.t darcs add new/dir/t.t darcs record -am test new/dir/t.t > log not grep "don't want to record" log cd .. rm -rf temp1 darcs-2.8.4/tests/issue1392_authorspelling.sh0000644001765600176560000000336112104371431020431 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1392 - .authorspelling processing. ## ## Copyright (C) 2009 Tomas Caithaml ## ## 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. . lib # Load some portability helpers. rm -rf R # Another script may have left a mess. darcs init --repo R # Create our test repos. cd R echo 'Bad\, Jr. , Foo' > .authorspellings echo 'Example content.' > f darcs record -lam 'Add f.' -A 'Foo' darcs show authors | grep -q 'Bad, Jr\. ' echo 'Bad\, Jr. , ^Foo\, Jr\..*$' > .authorspellings echo 'Ex. cont.' > f darcs record -lam 'Change f.' -A 'Foo, Jr. ' darcs show authors | tee output.txt | grep -q 'Bad, Jr\. ' cd .. #--rm -rf R darcs-2.8.4/tests/issue1332_add_r_boring.sh0000644001765600176560000000324612104371431017776 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1332 - add -r ignores --boring ## ## Copyright (C) 2009 Eric Kow ## ## 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. . lib # Load some portability helpers. rm -rf R # Another script may have left a mess. darcs init --repo R # Create our test repos. cd R mkdir d touch core f # this is already known to work darcs add --boring core f darcs whatsnew > log grep 'addfile ./f' log grep 'addfile ./core' log rm _darcs/patches/pending # this fails for issue1332 darcs add -r --boring . darcs whatsnew > log grep 'addfile ./f' log grep 'addfile ./core' log rm _darcs/patches/pending cd .. darcs-2.8.4/tests/issue1446.sh0000644001765600176560000000443212104371431015311 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1446 - darcs amend-record -m foo destroys long description without warning ## ## Copyright (C) 2009 Dmitry Kurochkin ## ## 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. . lib # Load some portability helpers. rm -rf R # Another script may have left a mess. darcs init --repo R # Create our test repo. touch R/f darcs add f --repo R echo 'patch name' > R/patchinfo echo 'patch description' >> R/patchinfo darcs record -a --logfile=R/patchinfo --repo R darcs changes --repo R | grep 'patch name' darcs changes --repo R | grep 'patch description' echo 'y' | darcs amend-record -p 'patch name' -m 'new name' --repo R darcs changes --repo R | grep 'new name' darcs changes --repo R | grep 'patch description' echo content > R/f echo 'another name' > R/patchinfo echo 'another description' >> R/patchinfo darcs record -a --logfile=R/patchinfo --repo R darcs changes --repo R | grep 'another name' darcs changes --repo R | grep 'another description' echo 'y' | darcs amend-record -p 'another name' -m 'one more name' --repo R darcs changes --repo R | grep 'one more name' darcs changes --repo R | grep 'another description' rm -rf R/ # Clean up after ourselves. darcs-2.8.4/tests/issue1337_darcs_changes_false_positives.sh0000644001765600176560000000310512104371431023427 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1337 - darcs changes shows unrelated patches ## Asking "darcs changes" about an unrecorded file d/f will list the ## patch that creates the parent directory d/ (instead of no patches). ## ## Copyright (C) 2009 Trent W. Buck ## ## 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. . lib rm -rf temp1 darcs init --repodir temp1 cd temp1 mkdir d darcs record -lam d d # We use --match 'touch d/f' instead of simply d/f because the latter # prints "Changes to d/f:\n" before the count. test 0 -eq "$(darcs changes --count --match 'touch d/f')" darcs-2.8.4/tests/issue1344_abort_early_cant_send.sh0000644001765600176560000000461212104371431021707 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1344 - abort early darcs send if sendmail is not ## available ## ## Copyright (C) 2010 Gabriel Kerneis ## ## 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. set -ev . lib # The mail sending code on Windows uses the MAPI API unconditionally # so this test fails. # If it's possible to discover in advance whether mail sending would work, # the code and this test could be improved to do that. abort_windows # Skip this test if sendmail is available if which sendmail ; then echo "Sendmail found (in path), skipping test." exit 200 fi if [ -f "/usr/sbin/sendmail" -o -f "/sbin/sendmail" -o \ -f "/usr/lib/sendmail" ]; then echo "Sendmail found, skipping test." exit 200 fi DARCS_EDITOR=echo export DARCS_EDITOR mkdir temp1 temp2 cd temp2 darcs init # setup test cd ../temp1 darcs init touch foo bar darcs add foo bar darcs record -a -m add_foo_bar -A x # If --sendmail-command is provided, no warning darcs send --author=me -a --to=random@random --sendmail-command='true' ../temp2 # If --dry-run is provided, no warning darcs send --author=me -a --to=random@random --dry-run ../temp2 # If -o or -O is provided, no warning darcs send --author=me -a --to=random@random -O ../temp2 darcs send --author=me -a --to=random@random -o test.patch ../temp2 # Otherwise, fail early darcs send --author=me -a --to=random@random ../temp2 | grep "No working sendmail" cd .. darcs-2.8.4/tests/issue1373_replace_token_chars.sh0000644001765600176560000000355012104371431021363 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1373 - check that --token-chars [^ \t] is allowed. ## While we're at it, check some other things *aren't* allowed. ## ## Copyright (C) 2009 Trent W. Buck ## ## 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. . lib rm -rf temp # Another script may have left a mess. darcs init --repodir temp replace () { darcs replace --repodir temp --token-chars "$1" x y; } ## These are not well-formed tokens. not replace '' not replace 'a' not replace ']a[' not replace '[]' not replace '[^]' ## These are well-formed, but allow tokens to contain whitespace. not replace $'[ ]' not replace $'[\t]' not replace $'[\n]' not replace $'[\r]' not replace $'[\v]' not replace $'[^ ]' not replace $'[^\t]' not replace $'[^\n]' not replace $'[^\r]' not replace $'[^\v]' rm -rf temp # Clean up after ourselves. darcs-2.8.4/tests/issue1427_apply_gz.sh0000644001765600176560000000122712104371431017214 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp1 temp2 mkdir temp1 temp2 cd temp2 darcs init cd ../temp1 darcs init touch foo bar darcs add foo bar darcs record -a -m add_foo_bar -A x darcs mv foo zig darcs mv bar foo darcs mv zig bar darcs record -a -m swap_foo_bar -A x darcs send --author=me --output=funpatch --dont-sign -a ../temp2 gzip funpatch cd ../temp2 darcs apply ../temp1/funpatch.gz cd .. cmp temp1/bar temp2/bar rm -rf temp2 mkdir temp2 cd temp2 darcs init darcs apply ../temp1/funpatch.gz ## Also test that "darcs apply" can accept a patch on stdin. darcs obl -a darcs apply < ../temp1/funpatch.gz cd .. cmp temp1/bar temp2/bar rm -rf temp1 temp2 darcs-2.8.4/tests/issue142_record-log.sh0000644001765600176560000000302212104371431017330 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue142 - darcs record --logfile foo should not ## let you record a patch even when 'foo' is a missing file ## ## Copyright (C) 2009 Eric Kow ## ## 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. . lib # Load some portability helpers. rm -rf R # Another script may have left a mess. darcs init --repo R # Create our test repos. cd R touch f g touch log darcs record -alm f --logfile log f not darcs record -alm g --logfile missing g darcs-2.8.4/tests/issue1473.sh0000644001765600176560000000333712104371431015314 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1473 - check that darcs annotate works with and without ## repodir and with "." argument. It should fail with the empty string as ## a single argument and without any arguments. ## ## 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. . lib # Load some portability helpers. rm -rf R S # Another script may have left a mess. darcs init --repo R # Create our test repos. cd R echo 'Example content.' > f darcs record -lam 'Added f.' darcs annotate . darcs annotate f not darcs annotate not darcs annotate '' cd .. darcs annotate --repodir=R . darcs annotate --repodir=R f not darcs annotate --repodir=R not darcs annotate --repodir=R '' darcs-2.8.4/tests/issue1465_ortryrunning.sh0000644001765600176560000000555712104371431020163 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1465 - ortryrunning should try RHS if AND ONLY IF the ## LHS wasn't found or wasn't executable. ## ## Copyright (C) 2009 Trent W. Buck ## ## 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. . lib # Load some portability helpers. darcs init --repo R # Create our test repo. FAKE_EDITOR_HOME=`pwd` cat < editor-good.hs import System.Environment import System.IO main = getArgs >>= \[name] -> writeFile name "fake" FAKE ghc -o editor-good --make editor-good.hs cat < editor-bad.hs import System.Exit main = exitWith (ExitFailure 127) FAKE ghc -o editor-bad --make editor-bad.hs cat < editor-gave-up.hs import System.Exit main = exitWith (ExitFailure 1) FAKE ghc -o editor-gave-up --make editor-gave-up.hs cat < vi.hs import System.Environment import System.IO main = getArgs >>= \[name] -> writeFile name "vi" VI ghc -o vi --make vi.hs cd R mkdir d unset TERM DARCSDIR=$(dirname $(which darcs)) # the /dev/null stdin redirection is to make vi or the fallback editor just fail DARCS_EDITOR=$FAKE_EDITOR_HOME/editor-good \ darcs record -lam 'Initial commit.' --edit log-1 darcs changes > changes-1 darcs unrecord -a grep fake changes-1 # Bad editor: fall through to the next choice DARCS_EDITOR=$FAKE_EDITOR_HOME/editor-bad \ PATH=.:$DARCSDIR \ darcs record -lam 'Initial commit.' --edit log-2 darcs changes > changes-2 darcs unrecord -a grep "Initial" changes-2 egrep -i 'vi|emacs|nano|edit' log-2 # Normal failure (eg. user hit ^-C) # If Darcs did the right thing, the output won't make any mention of # the fallback editors. DARCS_EDITOR=$FAKE_EDITOR_HOME/editor-gave-up \ darcs record -lam 'Initial commit.' --edit log-3 darcs changes > changes-3 darcs unrecord -a grep "Initial" changes-3 not egrep -i 'not found|vi|emacs|nano|edit' log-3 darcs-2.8.4/tests/issue1472_read_too_much.sh0000644001765600176560000000344412104371431020202 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1472 - running "darcs record ./foo" shouldn't even ## TRY to read ./bar. ## ## Copyright (C) 2009 Trent W. Buck ## ## 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. . lib # Load some portability helpers. rm -rf R # Another script may have left a mess. darcs init --repo R # Create our test repo. mkdir R/d/ # Change the working tree. echo 'Example content.' >R/f echo 'Similar content.' >R/d/f chmod 0 R/f # Make R/f unreadable, so that # attempting to read it will result in # an error. darcs record --repo R -lam 'Only changes to R/d/.' d rm -rf R/ # Clean up after ourselves. darcs-2.8.4/tests/issue1705-show-contents-index.sh0000644001765600176560000000305712104371431021227 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1705 - darcs failed: Pattern not specified in get_nonrange_match> ## ## Copyright (C) 2009 Thomas Hartman ## ## 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. . ../tests/lib # Load some portability helpers. rm -rf R S # Another script may have left a mess. darcs init --repo R # Create our test repos. cd R echo 111 > 1 darcs add 1 darcs record --author="whoever" -am'add file 1' darcs show contents --index=1 1 cd .. rm -rf R darcs-2.8.4/tests/issue1473_annotate_repodir.sh0000644001765600176560000000052212104371431020722 0ustar ganeshganesh#!/usr/bin/env bash set -ev . lib rm -rf temp mkdir temp cd temp darcs init mkdir a b touch a/a b/b darcs add --rec . darcs record -a -m ab -A test darcs annotate a/a darcs annotate . > inner # annotate --repodir=something '.' should work cd .. darcs annotate --repodir temp '.' > temp/outer cd temp diff inner outer cd .. rm -rf temp darcs-2.8.4/tests/issue1488_whatsnew-l.sh0000644001765600176560000000271212104371431017467 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1488 - whatsnew in non-added directory crashes on fromJust ## ## Copyright (C) 2009 Marnix Klooster ## ## 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. . lib # Load some portability helpers. rm -rf R mkdir -p R/Foo/Bar # 2 directory levels needed cd R darcs init cd Foo/Bar # and now the real problem causer: darcs whatsnew -l . # a "fromJust error" in Whatsnew.lhs darcs-2.8.4/tests/issue154_pull_dir_not_empty.sh0000644001765600176560000000313112104371431021207 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue154 - when applying a patch that removes a directory, ## don't remove the directory from the working tree unless it's empty. ## ## Copyright (C) 2008 Mark Stosberg ## ## 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. . lib rm -rf temp1 mkdir temp1 cd temp1 darcs init mkdir d darcs add d darcs record -a -m "Added directory d" darcs get ./ puller cd puller touch d/moo darcs add d/moo cd .. rm -rf d darcs record -a -m "Remove directory d" cd puller echo y | darcs pull -a .. > log grep -i "backing up" log grep -i "finished pulling" log cd .. rm -rf temp1 darcs-2.8.4/tests/issue157_rollback_conflict.sh0000644001765600176560000000175512104371431020766 0ustar ganeshganesh#!/usr/bin/env bash # issue157: A test for how rollback handles dependencies and conflicts. . lib rm -rf temp1 temp2 # set up the repository mkdir temp1 cd temp1 darcs init --darcs-2 cd .. # do some work here cd temp1 echo a > foo # Create three patches darcs record -lam AA echo b > foo darcs record -lam BB echo c > foo darcs record -lam CC # Rollback the last one darcs rollback -a -p CC -m 'rollback CC' grep b foo # reality check cd .. # Now get just the first two patches into a new repo...ignoring the third patch and the rollback. darcs get --to-patch BB temp1 temp2 cd temp2 # Now in the second repo, rollback the second patch. darcs rollback -a -p BB -m 'rollback BB' grep a foo # reality check # Finally, pull the third patch and the rollback of it. # Because the two patches should cancel each other other, there should be no change here. darcs pull -a ../temp1 # expect a conflict between the contents being 'a' or 'b' grep "v v v" foo grep a foo grep b foo cd .. rm -rf temp1 temp2 darcs-2.8.4/tests/issue1558_xml_output_gz_extension.sh0000644001765600176560000000275512104371431022417 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1558 - xml output for patch hash includes "gz" ## extension ## ## Copyright (C) 2010 Gabriel Kerneis ## ## 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. . lib # Load some portability helpers. darcs init --repo R # Create our test repos. cd R mkdir d e # Change the working tree. echo 'Example content.' > d/f darcs record -lam 'Add d/f and e.' darcs changes --xml | not grep "\\.gz" cd .. darcs-2.8.4/tests/issue1584_optimize_upgrade.sh0000644001765600176560000000315612104371431020745 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1584 - darcs optimize --upgrade ## ## Copyright (C) 2009 Eric Kow ## ## 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. . lib # Load some portability helpers. rm -rf R # Another script may have left a mess. gunzip -c $TESTDATA/many-files--old-fashioned-inventory.tgz | tar xf - mv many-files--old-fashioned-inventory R echo x > R/foo # Unrecorded change darcs optimize --repo R --upgrade darcs check --repo R grep hashed R/_darcs/format not grep darcs-2 R/_darcs/format darcs whatsnew --repo R | grep 'hunk ./foo 1' darcs-2.8.4/tests/issue1611_amend-tag.sh0000644001765600176560000000310612104371431017215 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1611 - amend-record should prevent adding new changes to a tag. ## ## Copyright (C) 2011 Iago Abal Rivas ## ## 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. . lib # Load some portability helpers. darcs init --repo R # Create our test repos. cd R # Creates a patch echo 'Example content.' > f darcs record -lam 'Add f' darcs tag V1 # Creates a tag echo 'Another example content.' > f # Edit repository # Amend the tag should be illegal echo y | darcs amend -ap 'V1' | not grep 'amending patch' darcs-2.8.4/tests/issue1740-mv-dir.sh0000644001765600176560000000303612104371431016501 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1740 - darcs mv on directories should work after the fact ## ## Copyright (C) 2009 Eric Kow ## ## 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. . lib # Load some portability helpers. rm -rf R # Another script may have left a mess. darcs init --repo R # Create our test repos. cd R mkdir d echo 'Example content.' > d/f darcs record -lam 'Add d/f' mv d d2 darcs mv d d2 # oops, I meant to darcs mv that darcs what | grep "move ./d ./d2" darcs-2.8.4/tests/issue1599-automatically-expire-unused-caches.sh0000644001765600176560000000367012104371431024212 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1599 - 'Automatically expire unused caches' ## ## Copyright (C) 2010 Adolfo Builes ## ## 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. . lib skip-formats old-fashioned rm -rf R S log && mkdir R cd R darcs init echo a > a darcs rec -lam a echo b > b darcs rec -lam b echo c > c darcs rec -lam c cd .. serve_http # sets baseurl darcs get --lazy $baseurl/R S rm S/_darcs/prefs/sources if [ -z "$http_proxy" ]; then echo "repo:http://10.1.2.3/S" >> S/_darcs/prefs/sources fi echo "repo:$baseurl/dummyRepo" >> S/_darcs/prefs/sources echo "repo:~/test1599/S" >> S/_darcs/prefs/sources echo "repo:$baseurl/R" >> S/_darcs/prefs/sources darcs changes --repo S --debug --verbose --no-cache 2>&1 | tee log if [ -z "$http_proxy" ]; then c=`grep -c "URL.waitUrl http://10.1.2.3/S" log` [ $c -eq 1 ] fi c1=`grep -c "URL.waitUrl $baseurl/dummyRepo" log` [ $c1 -eq 2 ] c2=`grep -c "~/test1599/S" log` [ $c2 -eq 1 ] darcs-2.8.4/tests/issue1636-match-hunk.sh0000644001765600176560000000341612104371431017350 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1636 - primitive match type: hunk ## ## Copyright (C) Kamil Dworakowski ## ## 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. . lib # Load some portability helpers. rm -rf R darcs init --repo R # Create our test repos. cd R echo 'first line' > f darcs record -lam 'one' echo 'second line' >> f darcs record -am 'two' darcs changes --match 'hunk first' > log grep one log not grep two log darcs changes --match 'hunk line' > log grep one log grep two log darcs changes --match 'hunk one' > log not grep one log # test searching for lines in the remove part of the hunk echo 'first line' > f darcs record -am 'three' darcs changes --match 'hunk second' > log grep three log grep two log not grep first log darcs-2.8.4/tests/mv.sh0000644001765600176560000000161612104371431014265 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp mkdir temp cd temp darcs init echo hi world > temp.c darcs add temp.c darcs record --all -A test --name=hi echo goodbye >> temp.c darcs whatsnew darcs record -a -A au -m bye echo bar > bar.c darcs add bar.c darcs record -a -m one -A ex darcs mv bar.c zig.c darcs whatsnew darcs record -a -m two -A ex mkdir baz darcs add baz darcs whatsnew darcs record -a -m three -A ex darcs mv zig.c baz/bar.c darcs whatsnew darcs record -a -m four -A ex darcs mv baz temp darcs whatsnew darcs record -a -m five -A ex darcs mv temp temp 1> stdout 2> stderr || true grep 'Cannot rename a file or directory onto itself' stderr cd .. rm -rf temp mkdir temp cd temp darcs init echo hi world > a darcs add a darcs record --all -m lower cd .. darcs get temp temp1 cd temp darcs mv a A echo goodbye > A darcs record --all -m 'to upper' cd ../temp1 darcs pull -a cd .. rm -rf temp temp1 darcs-2.8.4/tests/issue1618-amend-preserve-logfile.sh0000644001765600176560000000322212104371431021640 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1618 - amend should preserve the logfile ## in case of failure ## ## Copyright (C) 2009 Kamil Dworakowski ## ## 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. set -ev . lib rm -rf R; mkdir R; cd R darcs init darcs setpref test false darcs record -am foo --no-test export DARCS_EDITOR="echo 'new log' > " echo yn | not darcs amend -p foo --edit-long-comment --test 2> out # the msg has the format: "Logfile left in filenamehere." LOGFILE=`grep "Logfile left in" out | sed "s/Logfile left in //" | sed s/.$//` echo $LOGFILE test -e "$LOGFILE" grep 'new log' $LOGFILE rm out; cd ..; rm -rf R/ darcs-2.8.4/tests/issue1640_verbose_stdin.sh0000644001765600176560000000416012104371431020231 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1640 - ## ## Copyright (C) 2011 Radoslav Dorcik ## ## 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. . lib # Load some portability helpers. ####################################################### # Test preparation ####################################################### # Create repository darcs init --repo S darcs init --repo T darcs init --repo T2 cd S touch foo bar darcs add foo bar darcs record -a -m add_foo_bar -A x darcs send --author=me --output=funpatch -a ../T ####################################################### # Apply from stdin and check message ####################################################### # Message when --verbose cd ../T darcs apply --verbose < ../S/funpatch | tee output.txt grep "reading patch bundle from stdin..." output.txt || exit 1 # No message when no --verbose cd ../T2 darcs apply < ../S/funpatch | tee output.txt grep "reading patch bundle from stdin..." output.txt && exit 1 exit 0; darcs-2.8.4/tests/issue194.sh0000644001765600176560000000115212104371431015224 0ustar ganeshganeshset -ev rm -rf temp1 temp2 mkdir temp1; cd temp1 ; darcs init ; cd .. darcs get temp1 temp2 cd temp2/ ; echo 'x' > _darcs/prefs/author ; cd .. cd temp1/ ; echo 'x' > _darcs/prefs/author ; cd .. cd temp1/ touch test darcs add test ; darcs record -a -m 'test' darcs mv test best ; darcs record -a -m 'test -> best' darcs mv best test ; darcs record -a -m 'best -> test' cd .. cd temp2/ touch test2 darcs add test2 ; darcs record -a -m 'test2' darcs mv test2 best ; darcs record -a -m 'test2 -> best' darcs mv best test2 ; darcs record -a -m 'best -> test2' darcs pull ../temp1/ -a cd .. rm -rf temp1 temp2 darcs-2.8.4/tests/issue1620-record-lies-about-leaving-logfile.sh0000644001765600176560000000313712104371431023664 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1620 - record does not really leave logfile ## after a failure ## ## Copyright (C) 2009 Kamil Dworakowski ## ## 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. set -ev . lib rm -rf R; mkdir R; cd R export DARCS_EDITOR="echo 'a log' > " darcs init darcs setpref test false echo yy| not darcs record -m foo -a --edit-long-comment --test 2> out # the msg has the format: "Logfile left in filenamehere." LOGFILE=`grep "Logfile left in" out | sed "s/Logfile left in //" | sed s/.$//` test -e "$LOGFILE" grep 'a log' $LOGFILE rm out cd .. rm -rf R/ darcs-2.8.4/tests/issue1645-ignore-symlinks.sh0000644001765600176560000001701412104371431020442 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1645 - Since Darcs does not version-contol symlinks, ## it should not follow them, ESPECIALLY symlinks to directories ## outside the repository. All these tests are passed with darcs-2.2 ## ## See path_resolution(7) and symlink(7) for more info, especially ## the former. ## ## There's a second section to this test for systems that support ## case-folding. See issue1645-ignore-symlinks-case-fold.sh ## ## Copyright (C) 2010 Trent W. Buck, Dmitry Astapov ## ## 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. . lib # Load some portability helpers. rm -rf R S # Another script may have left a mess. darcs init --repo R # Create our test repos. darcs init --repo S darcs --version add_to_boring() { echo "$1" >> _darcs/prefs/boring } ## These are the simple does-the-wrong-thing errors. cd R touch log add_to_boring '^log$' unset pwd # Since this test is pretty much linux-specific, hspwd.hs is not needed abort_windows # and skip if we are on win32... # Case 1: looping symlink to non-recorded non-boring dir mkdir non-recorded-dir ln -s ../non-recorded-dir ./non-recorded-dir/loop # relative symlink ln -s "`pwd`"/non-recorded-dir ./non-recorded-dir/loop2 # absolute symlink darcs w -l >log 2>&1 # should not loop darcs rec -alm "added ./non-recorded-dir" >>log 2>&1 # should not loop darcs changes -s --patch="added ./non-recorded-dir" >>log 2>&1 # should report only dir, not symlink not grep -vE "(^ *$|^\+|[0-9]:[0-9][0-9]:[0-9]|./non-recorded-dir)" log # Case 2: looping symlink to recorded dir mkdir recorded-dir darcs add recorded-dir darcs rec -am "added recorded-dir" ln -s ../recorded-dir ./recorded-dir/loop # relative symlink ln -s "`pwd`"/recorded-dir ./recorded-dir/loop2 # absolute symlink not darcs w -l >log 2>&1 # expecting "No changes!" not darcs rec -alm "should not happen" >>log 2>&1 # expecting "No changes!" as well not grep -vE "(^ *$|^\+|No changes!)" log # Case 3: looping symlink to boring dir mkdir boring-dir add_to_boring '^boring-dir$' ln -s ../boring-dir ./boring-dir/loop ln -s "`pwd`"/boting-dir ./boring-dir/loop2 not darcs w -l >log 2>&1 # expecting "No changes!" not darcs rec -alm "should not happen" >>log 2>&1 # expecting "No changes!" as well not grep -vE "(^ *$|^\+|No changes!)" log # Case 4: non-looping symlink to non-recorded non-boring dir mkdir non-recorded-dir2 ln -s ./non-recorded-dir2 link ln -s "`pwd`"/non-recorded-dir2 ./link2 darcs w -l >log 2>&1 # should report only "non-recorded-dir2" darcs rec -alm "added ./non-recorded-dir2" >>log 2>&1 # should add only dir, not symlink darcs changes -s --patch="added ./non-recorded-dir2" >>log 2>&1 # should report only dir, not symlink not grep -vE "(^ *$|^\+|[0-9]:[0-9][0-9]:[0-9]|./non-recorded-dir2)" log rm link link2 # Case 5: non-looping symlink to recorded dir ln -s ./recorded-dir ./link ln -s "`pwd`"/recorded-dir ./link2 not darcs w -l >log 2>&1 # expecting "No changes!" not darcs rec -alm "should not happen" >>log 2>&1 # expecting "No changes!" as well not grep -vE "(^ *$|^\+|No changes!)" log rm link link2 # Case 6: non-looping symlink to boring dir ln -s ./boring-dir ./link ln -s "`pwd`"/boring-dir ./link2 not darcs w -l >log 2>&1 # expecting "No changes!" not darcs rec -alm "should not happen" >>log 2>&1 # expecting "No changes!" as well not grep -vE "(^ *$|^\+|No changes!)" log rm link link2 # Case 7: symlink pointing outside the repo ln -s ../S link (cd ..; ln -s "`pwd`"/S ./R/link2) not darcs w -l >log 2>&1 # expecting "No changes!" not darcs rec -alm "should not happen" >>log 2>&1 # expecting "No changes!" as well not grep -vE "(^ *$|^\+|No changes!)" log rm link link2 # Case 8: symlink to non-recorded non-boring file touch non-recorded-file ln -s ./non-recorded-file ./link ln -s "`pwd`"/non-recorded-file ./link2 darcs w -l >log 2>&1 # should report only "non-recorded-file" darcs rec -alm "added ./non-recorded-file" >>log 2>&1 # should add only file, not symlink darcs changes -s --patch="added ./non-recorded-file" >>log 2>&1 # should report only file, not symlink not grep -vE "(^ *$|^\+|[0-9]:[0-9][0-9]:[0-9]|./non-recorded-file)" log rm link link2 # Case 9: symlink to recorded file echo "some content" > recorded-file darcs add recorded-file darcs rec -am "added recorded-file" recorded-file ln -s ./recorded-file ./link ln -s "`pwd`"/recorded-file ./link2 not darcs w -l >log 2>&1 # expecting "No changes!" not darcs rec -alm "should not happen" >>log 2>&1 # expecting "No changes!" as well not grep -vE "(^ *$|^\+|No changes!)" log rm link link2 # Case 10: symlink to boring file ln -s ./log ./link ln -s "`pwd`"/log ./link2 not darcs w -l >log 2>&1 # expecting "No changes!" not darcs rec -alm "should not happen" >>log 2>&1 # expecting "No changes!" as well not grep -vE "(^ *$|^\+|No changes!)" log rm link link2 # Case 11: dangling symlink ln -s /completely/bogus/path ./link ln -s ../../../../not/exist ./link2 not darcs w -l >log 2>&1 # expecting "No changes!" not darcs rec -alm "should not happen" >>log 2>&1 # expecting "No changes!" as well not grep -vE "(^ *$|^\+|No changes!)" log rm link link2 # Case 12: self-referencing link ln -s l l ln -s "`pwd`"/l2 ./l2 not darcs w -l >log 2>&1 # expecting "No changes!" not darcs rec -alm "should not happen" >>log 2>&1 # expecting "No changes!" as well not grep -vE "(^ *$|^\+|No changes!)" log rm l l2 # Case 13: link to device file outside the repo ln -s /dev/zero l not darcs w -l >log 2>&1 # expecting "No changes!" not darcs rec -alm "should not happen" >>log 2>&1 # expecting "No changes!" as well not grep -vE "(^ *$|^\+|No changes!)" log rm l # Case 14: link to fifo mkfifo f ln -s f l ln -s "`pwd`"/f ./l2 not darcs w -l >log 2>&1 # expecting "No changes!" not darcs rec -alm "should not happen" >>log 2>&1 # expecting "No changes!" as well not grep -vE "(^ *$|^\+|No changes!)" log rm f l l2 darcs-2.8.4/tests/issue1645-ignore-symlinks-case-fold.sh0000644001765600176560000000617112104371431022277 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1645 - Since Darcs does not version-contol symlinks, ## it should not follow them, ESPECIALLY symlinks to directories ## outside the repository. All these tests are passed with darcs-2.2 ## ## See path_resolution(7) and symlink(7) for more info, especially ## the former. ## ## This only covers the case-folding test cases. ## See also the issue1645-ignore-symlinks for the main test ## ## Copyright (C) 2010 Trent W. Buck, Dmitry Astapov ## ## 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. . lib # Load some portability helpers. rm -rf R S # Another script may have left a mess. darcs init --repo R # Create our test repos. darcs init --repo S add_to_boring() { echo "$1" >> _darcs/prefs/boring } ## These are the simple does-the-wrong-thing errors. cd R touch log add_to_boring '^log$' unset pwd # Since this test is pretty much linux-specific, hspwd.hs is not needed # Skip the case-folding tests on systems that don't support it touch cs-test ln -s cs-test cs-Test || exit 200 rm cs-test cs-Test # move file and symlink out of the way for real tests # Case 15: case-folding link to non-recorded file touch non-recorded-file2 ln -s ./non-recorded-file2 ./Non-Recorded-File2 ln -s "`pwd`"/non-recorded-file2 ./Non-ReCoRdEd-File2 darcs w -l >log 2>&1 # should report only "non-recorded-file" darcs rec -alm "added ./non-recorded-file2" >>log 2>&1 # should add only file, not symlink darcs changes -s --patch="added ./non-recorded-file2" >>log 2>&1 # should report only file, not symlink not grep -vE "(^ *$|^\+|[0-9]:[0-9][0-9]:[0-9]|./non-recorded-file2)" log rm Non-Recorded-File2 ./Non-ReCoRdEd-File2 # Case 16: case-folding link to recorded file ln -s ./recorded-file ./Recorded-File ln -s "`pwd`"/recorded-file ./ReCorded-File not darcs w -l >log 2>&1 # expecting "No changes!" not darcs rec -alm "should not happen" >>log 2>&1 # expecting "No changes!" as well not grep -vE "(^ *$|^\+|No changes!)" log rm Recorded-File ReCorded-File darcs-2.8.4/tests/issue1727_move_current_directory.sh0000644001765600176560000000365212104371431022172 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1727 - darcs move . target' fails as an attempt to ## write an 'invalid pending. ## ## Copyright (C) 2009 Sean Erle Johnson ## ## 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. . lib # Load some portability helpers. rm -rf R # Another script may have left a mess. # Create repository R darcs init --repo R # Create the test repo. cd R mkdir d # Change the working tree. # darcs move empty current directory to existing directory d not darcs move . d # darcs move empty current directory to non-existing directory e not darcs move . e # Make file to be copied echo 'main = putStrLn "Hello World"' > hello.hs # darcs move non-empty current directory to existing directory d not darcs move . d # darcs move non-empty current directory to non-existing directory e not darcs move . e mkdir e cd e not darcs move .. edarcs-2.8.4/tests/issue1726_darcs_always-boring.sh0000644001765600176560000000464112104371431021326 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1726 - Files whose names start with "_darcs" are considered ## boring, even if they don't match anything in the boring file, and even if ## you pass --boring to the command. ## ## Copyright (C) 2009 Daniel Dickison ## ## 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. . lib # Load some portability helpers. rm -rf R # Another script may have left a mess. darcs init --repo R # Create our test repos. cd R ## First test expected failures with actual _darcs files/directories function bad_add { filename="$1" touch "$filename" not darcs whatsnew -ls --boring not darcs whatsnew -ls not darcs add --boring "$filename" } touch _darcs/foo bad_add _darcs bad_add _darcs/ bad_add _darcs/foo bad_add ./_darcs bad_add ./_darcs/ bad_add ./_darcs/foo bad_add "$PWD/_darcs" bad_add "$PWD/_darcs/" bad_add "$PWD/_darcs/foo" bad_add "../${PWD##*/}/_darcs" bad_add "../${PWD##*/}/_darcs/" bad_add "../${PWD##*/}/_darcs/foo" ## Then test expected successes with files that aren't in _darcs # Passing --boring should definitely succeed. touch _darcsfoo darcs whatsnew -ls --boring darcs add --boring _darcsfoo darcs record -am 'add _darcsfoo' _darcsfoo # Without --boring, this tests the default boring file. touch _darcsbar darcs whatsnew -ls darcs add _darcsbar darcs record -am 'add _darcsbar' _darcsbar darcs-2.8.4/tests/issue1756_moves_index.sh0000644001765600176560000000340112104371431017710 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1756 - moving files between directories breaks index ## ## Copyright (C) 2010 Petr Rockai ## ## 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. . lib # Load some portability helpers. rm -rf R S # Another script may have left a mess. darcs init --repo R # Create our test repos. cd R mkdir d e # Change the working tree. echo 'a' > d/a echo 'b' > d/b echo 'c' > e/c darcs record -lam '.' darcs mv d/a e/ darcs check --no-ignore-times cd .. rm -rf R darcs init --repo R cd R mkdir d e # Change the working tree. echo 'a' > d/a echo 'b' > e/b darcs record -lam '.' darcs mv d/a e/ darcs check --no-ignore-times cd .. rm -rf R darcs-2.8.4/tests/issue1737-move_args.sh0000644001765600176560000000326312104371431017275 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1737 - command line filtering on darcs move ## yields suprising results with shell globs ## ## Copyright (C) 2010 Eric Kow ## ## 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. . lib # Load some portability helpers. rm -rf R # Another script may have left a mess. darcs init --repo R # Create our test repos. cd R mkdir d touch d.txt darcs record -lam 'Add d and d.txt' darcs move d d.txt d 2> log || : # this can happen if eg. you darcs move d* d # d.txt isn't a directory; we should probably just say that you # can't move a directory on to itself not grep "target directory d.txt" log darcs-2.8.4/tests/issue1749-rmdir.sh0000644001765600176560000000323212104371431016427 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issueXXX - darcs remove corrupts the patch sequence ## ## Copyright (C) 2009 Eric Kow ## ## 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. . lib # Load some portability helpers. rm -rf R # Another script may have left a mess. darcs init --repo R cd R mkdir dir touch dir/file darcs add dir/file # adds dir too (which is fine) darcs rec -a -m"add dir and file" darcs remove dir # removed dir but not file - should be nothing to add not darcs rec -a -m"remove dir" darcs obliterate -a --patch "remove dir" | grep 'No patches selected!' darcs check darcs-2.8.4/tests/issue183_mv_order.sh0000644001765600176560000000320312104371431017116 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue183 - mv and other patches should be in replayable ## order ## ## Copyright (C) 2010 Eric Kow ## ## 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. . lib # Load some portability helpers. rm -rf R S # Another script may have left a mess. darcs init --repo R # Create our test repos. cd R touch f darcs add f darcs record -am 'Create f' mkdir d darcs add d darcs mv f d darcs record -am 'Create d and mv f in it' cat > expected << EOF A ./d/ ./f -> ./d/f EOF darcs changes -s -p 'Create d' | grep "d/" > log diff -q expected log cd .. darcs-2.8.4/tests/issue1739-escape-multibyte-chars-correctly.sh0000644001765600176560000000432212104371431023670 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1739 - "Char.intToDigit: not a digit" in darcs changes ## ## Copyright (C) 2010 Reinier Lamers ## ## 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. . lib # First, try to see if character set is UTF-8. If we can't find out or if it # isn't, we skip this test. if ! which locale ; then echo "no locale command" exit 200 # skip test fi charmap=`locale charmap` if [ $? -ne 0 ]; then echo "couldn't determine locale character set" exit 200 # skip test fi if [ "$charmap" != "UTF-8" ]; then echo "locale character set is not UTF-8, skipping" exit 200 fi # we want escaping, otherwise output of non-ASCII characters is unreliable export DARCS_DONT_ESCAPE_ANYTHING=0 rm -rf R mkdir R cd R darcs init echo garbelbolf > aargh darcs add aargh echo -e '\xe2\x80\x9e\x54\x61\x20\x4d\xc3\xa8\x72\x65\xe2\x80\x9d' > message.txt darcs record --logfile=message.txt -A 'Petra Testa van der Test ' -a > rec.txt darcs changes > log.txt cat log.txt grep '' log.txt grep '' log.txt grep '' log.txt # locale should not matter LC_ALL=C darcs changes > log.txt grep '' log.txt grep '' log.txt grep '' log.txt cd .. darcs-2.8.4/tests/issue1873-apply-failed-to-read-patch.sh0000644001765600176560000000335412104371431022312 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1873 - apply should complain about the right ## patches if it says some are missing ## ## Copyright (C) 2010 Petr Rockai ## ## 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. . lib rm -rf R S mkdir R darcs init --repo R cd R echo a > a darcs rec -lam a echo b > a darcs rec -lam b echo x > x darcs rec -lam x echo c > a darcs rec -lam c echo y > y darcs rec -lam y echo d > a darcs rec -lam d cd .. darcs get R S darcs unpull -p x -a --repo R darcs send -p x -a --repo S -o R/x.dpatch darcs unpull -p y -a --repo R not darcs apply --repo R R/x.dpatch 2>&1 | tee log not grep '^ \* d' log # does not complain about an unrelated patch grep '^ \* y' log # complains about the offending one instead darcs-2.8.4/tests/issue174_obliterate_before_a_tag.sh0000644001765600176560000000071112104371431022111 0ustar ganeshganesh#!/usr/bin/env bash # issue174: behave better when we want to obliterate a patch that comes before a tag. . lib rm -rf temp1 mkdir temp1 cd temp1 darcs init # Setup: Create a patch, a tag and another patch. touch a.txt darcs add a.txt darcs record -am 'adding a' a.txt darcs tag "first tag"; touch b.txt darcs add b.txt darcs record --ignore-time -a -m 'adding b' b.txt darcs obliterate -p "adding a" -a > log not grep "no patch" log cd .. rm -rf temp1 darcs-2.8.4/tests/issue1765_recursive-remove-on-root.sh0000644001765600176560000000310412104371431022265 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issueNNNN - ## ## Copyright (C) YEAR AUTHOR ## ## 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. . lib # Load some portability helpers. rm -rf R S # Another script may have left a mess. darcs init --repo R # Create our test repos. darcs init --repo S cd R mkdir d e # Change the working tree. echo 'Example content.' > d/f darcs record -lam 'Add d/f and e.' darcs remove * -r darcs-2.8.4/tests/issue1763-pull-fails-on-non-ascii-filenames.sh0000644001765600176560000000456012104371431023614 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1763 - When you pull in a conflicting hunk ## patch to a file with a non-ASCII name, and then pull from the same ## repo again, darcs crashes. ## ## Copyright (C) 2010 Reinier Lamers ## ## 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. . lib # This test should work on Windows because the codepoints in the filename # are all <256. However an equivalent test with codepoints >=256 would # likely fail. # abort_windows rm -rf R S darcs init --repo R export LC_ALL=C function check_consistent_filename { count=`darcs changes -v | grep 'hunk .*\.lisp' | sed -e 's/.*hunk //' -e 's/.lisp.*//' | sort | uniq | wc -l` test $count -eq 1 } # Set up a repo with 3 patches to a non-ASCII-named file cd R touch kitöltés.lisp darcs rec -l -a -m "Add" echo hi >> kitöltés.lisp darcs record -a -m "First edit" cd .. rm -rf S S2 S3 darcs get R S darcs get R S2 darcs get R S3 cd R echo hi >> kitöltés.lisp darcs record -a -m "Second edit" cd .. # From another repo, pull the first two, edit, pull the third to get a # conflict, pull again to get the crash cd S echo hello >> kitöltés.lisp darcs record -a -m "My edit" darcs pull -a ../R darcs pull -a ../R check_consistent_filename cd .. # duplicates cd S2 echo hi >> kitöltés.lisp darcs record -a -m "My duplicate edit" darcs pull -a ../R darcs pull -a ../R check_consistent_filename cd .. darcs-2.8.4/tests/issue1825-remove-pending.sh0000644001765600176560000000344312104371431020230 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1825 - buggy pending when reverting a removed ## directory and file. ## ## Copyright (C) 2010 Ferenc Wagner ## Copyright (C) 2010 Eric Kow ## ## 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. . lib # Load some portability helpers. rm -rf R # Another script may have left a mess. darcs init --repo R # Create our test repos. cd R mkdir -p a echo foo >a/b darcs add -r a darcs rec -am "add a/b" rm -r a darcs add # NB. not darcs add per se, but any operation which # causes the pending patch to be detected (eg. remove, # record + unrecord) # We have a legitimate pending patch so far. Now what? darcs revert -a a/b darcs-2.8.4/tests/issue1845-record-removed.sh0000644001765600176560000000072512104371431020230 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1871 - darcs record f, for f a removed file should work ## ## Public domain - 2010 Petr Rockai . lib # Load some portability helpers. rm -rf R # Another script may have left a mess. darcs init --repo R # Create our test repos. cd R echo 'Example content.' > f darcs rec -lam "first" rm -f f echo n | darcs record f 2>&1 | tee log not grep "None of the files" log cd .. darcs-2.8.4/tests/issue1848-rollback-p.sh0000644001765600176560000000300712104371431017340 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1848 - interactive selection of primitive patches ## should still work with rollback -p ## ## Copyright (C) 2010 Eric Kow ## ## 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. . lib # Load some portability helpers. rm -rf R S # Another script may have left a mess. darcs init --repo R # Create our test repos. cd R echo 'f' > f echo 'g' > g darcs record -lam 'Add f and g' echo ynq | darcs rollback -p 'f and g' cd .. darcs-2.8.4/tests/issue1857-pristine-conversion.sh0000644001765600176560000000300012104371431021323 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1857 - upgrading the pristine format should either ## work or have no effect) even it happens before a failing operation ## ## Copyright (C) 2010 Eric Kow ## ## 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. . lib # Load some portability helpers. rm -rf minimal-darcs-2.4 tar zx < $TESTDATA/minimal-darcs-2_4.tgz cd minimal-darcs-2.4 darcs check darcs setpref test false echo 'hi' > README not darcs record -a -m argh --test darcs check cd .. darcs-2.8.4/tests/issue1860-incomplete-pristine.sh0000644001765600176560000000316512104371431021303 0ustar ganeshganesh#!/usr/bin/env bash ## Copyright (C) 2010 Petr Rockai ## ## 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. . lib # Load some portability helpers. rm -rf R S # Another script may have left a mess. darcs init --repo R # Create our test repos. cd R mkdir tools darcs rec -lam "add tools" mkdir tools/cgi echo bar > tools/cgi/README darcs rec -lam "add cgi" darcs move tools contrib darcs rec -lam "rename tools/ to contrib/" rm -rf contrib/cgi darcs rec -lam "drop cgi" cd .. darcs get R S cd S darcs show pristine darcs unpull --last 2 -a darcs show pristine cd .. darcs-2.8.4/tests/issue1865-get-context.sh0000644001765600176560000000062712104371431017557 0ustar ganeshganesh#!/usr/bin/env bash . lib rm -rf temp1 temp2 mkdir temp1 cd temp1 darcs init touch t.t darcs add t.t darcs record -am "initial add" darcs tag -m tt echo x > x darcs rec -lam "x" x darcs changes --context > my_context abs_to_context="$(pwd)/my_context" cd .. darcs get temp1 --context="${abs_to_context}" temp2 darcs changes --context --repo temp2 > repo2_context diff -u "${abs_to_context}" repo2_context darcs-2.8.4/tests/issue1871-record-dot.sh0000644001765600176560000000321012104371431017344 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1871 - darcs record . should work for tracked changes ## in a subdirectory even if the subdirectory itself is not known yet. ## ## Copyright (C) 2010 Eric Kow ## ## 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. . lib # Load some portability helpers. rm -rf R # Another script may have left a mess. darcs init --repo R # Create our test repos. cd R mkdir d # Change the working tree. echo 'Example content.' > d/f darcs add d/f echo n | darcs record echo n | darcs record . > log not grep "None of the files" log cd .. darcs-2.8.4/tests/issue1879-same-patchinfo-uncommon.sh0000644001765600176560000000166312104371431022053 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1879 - we should at least notice that when a patch claims ## to have the same identity (patchinfo) as one of ours, then it should not ## depend on anything we don't have. ## ## Public domain - 2010 Eric Kow . lib # Load some portability helpers. rm -rf R S # Another script may have left a mess. darcs init --repo R # Create our test repos. darcs init --repo S cd R touch x1 darcs add x1 darcs record -am 'x1' darcs changes --context > ctx echo hello > f echo world > x1 darcs add f darcs record -am 'hello world' darcs send -a --context ctx -o foo.dpatch ../S cd .. cd S touch x2 darcs add x2 darcs record -am 'x2' darcs changes --context > ctx # create an evil wrong patch sed -e '/Context:/,$d' -e 's/x1/x2/g' ../R/foo.dpatch > foo.dpatch cat ctx >> foo.dpatch darcs apply foo.dpatch cd .. cd R not darcs pull -a ../S 2>&1 | tee log cd .. darcs-2.8.4/tests/issue1875-honor-no-set-default.sh0000644001765600176560000000314512104371431021267 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1875 - corner cases in which darcs may accidentally ## set default even though it's not supposed to ## ## Copyright (C) 2010 Eric Kow ## ## 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. . lib # Load some portability helpers. rm -rf R S # Another script may have left a mess. darcs init --repo R # Create our test repos. darcs get R S --no-set-default not find S/_darcs/prefs/defaultrepo rm -rf S darcs init --repo S cd S darcs push ../R --dry-run not grep '/R$' _darcs/prefs/defaultrepo darcs push ../R cd .. darcs-2.8.4/tests/issue1877_noisy_xml_output.sh0000644001765600176560000000352512104371431021044 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1877 - pull --dry-run --xml-output is noisy ## ## Copyright (C) 2010 Lele Gaifax ## ## 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. . lib # Load some portability helpers. rm -rf R S # Another script may have left a mess. darcs init --repo R # Create our test repos. darcs init --repo S cd R echo 'Example content.' > foo darcs record -lam 'Add foo.' cd .. cd S # This does the right thing... at least until the second command is executed darcs pull --dry-run --xml-output 2>&1 ../R | not grep "Would pull" # This does not, never darcs pull --summary --dry-run --xml-output 2>&1 ../R | not grep "Would pull" # From now on, this fails too! darcs pull --dry-run --xml-output 2>&1 ../R | not grep "Would pull" cd .. darcs-2.8.4/tests/issue2049-file-in-boring-dir.sh0000644001765600176560000000257112104371431020666 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue2049 - adding files inside a boring directory ## ## Copyright (C) 2011 Iago Abal, Ganesh Sittampalam ## ## 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. . lib # Load some portability helpers. rm -rf R darcs init --repo R # Create our test repos. cd R mkdir foo~ touch foo~/a.txt not darcs add foo~/a.txt darcs-2.8.4/tests/issue1888-changes-context.sh0000644001765600176560000000334312104371431020413 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1888 - changes --context is broken when topmost patch is a ## clean tag. ## Copyright (C) 2010 Petr Rockai ## ## 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. . lib # Load some portability helpers. rm -rf R # Another script may have left a mess. darcs init --repo R # Create our test repos. cd R echo a > a ; darcs rec -lam "patch_a" darcs changes --context | grep patch_a darcs tag -m "tag_a" darcs changes --context | not grep patch_a darcs changes --context | grep tag_a echo b > a; darcs rec -lam "patch_b" darcs changes --context | not grep patch_a darcs changes --context | grep tag_a darcs changes --context | grep patch_b darcs-2.8.4/tests/issue1913-diffing.sh0000644001765600176560000000301012104371431016703 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1913 - test for directory diffing ## ## Copyright (C) 2010 Ian Lynagh ## ## 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. . lib # Load some portability helpers. rm -rf R # Another script may have left a mess. darcs init --repo R # Create our test repos. cd R mkdir foo touch foo/foofile darcs rec -l -a -m "foo patch" mkdir bar touch bar/barfile rm -r foo darcs rec -l -a -m "bar patch" not darcs whatsnew -l cd .. darcs-2.8.4/tests/issue1978.sh0000644001765600176560000000072212104371431015321 0ustar ganeshganesh#!/usr/bin/env bash . lib mkdir future cd future darcs init touch titi darcs add titi darcs record -am titi cat > _darcs/format < foo.c darcs rec -Ax -alm init cd .. rm -rf temps darcs get tempc temps cd temps echo server >> foo.c darcs rec -Ax -alm server cd ../tempc echo client >> foo.c darcs rec -Ax -alm client if darcs push -a ../temps; then false fi cd .. rm -rf tempc temps darcs-2.8.4/tests/issue1898-set-default-notification.sh0000644001765600176560000000407012104371431022221 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1898 - set-default mechanism ## ## Copyright (C) 2010 Eric Kow ## ## 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. . lib # Load some portability helpers. rm -rf R0 R1 R2 S # Another script may have left a mess. darcs init --repo R0 # Create our test repos. darcs get R0 R1 darcs get R0 R2 darcs get R0 S cd S # default to no-set-default darcs push ../R1 > log grep '/R0$' _darcs/prefs/defaultrepo # notification when using no-set-default grep "set-default" log # set-default works darcs push ../R1 --set-default > log grep '/R1$' _darcs/prefs/defaultrepo # no notification when already using --set-default not grep "set-default" log # no notification when already pushing to the default repo darcs push > log not grep "set-default" log # no notification when it's just the --remote-repo darcs push --remote-repo ../R1 > log not grep "set-default" log # but... notification still works in presence of remote-repo darcs push --remote-repo ../R1 ../R2 > log grep "set-default" log cd .. darcs-2.8.4/tests/issue1909-unrecord-O-misses-tag.sh0000644001765600176560000000062012104371431021375 0ustar ganeshganesh#!/usr/bin/env bash ## issue1909: unrecord -O in tagged repo makes a busted bundle . lib rm -rf R mkdir R darcs init --repo R echo a > R/a darcs rec -lam a --repo R --ignore-times darcs tag -m T --repo R echo b > R/a darcs rec -lam b --repo R --ignore-times echo c > R/a darcs rec -lam c --repo R --ignore-times darcs unpull -p c -a --repo R -O cat c.dpatch grep '^\[b' c.dpatch grep TAG c.dpatch darcs-2.8.4/tests/issue1923-cache-warning.sh0000644001765600176560000000377312104371431020024 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1599 - 'Automatically expire unused caches' ## ## Copyright (C) 2010 Adolfo Builes ## ## 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. . lib skip-formats old-fashioned darcs init --repo R cd R echo a > a darcs rec -lam a cd .. serve_http cat < fake-sources repo:$baseurl/dummyRepo repo:/some/bogus/local/path repo:$baseurl/R SOURCES darcs get --lazy R S1 && cp fake-sources S1/_darcs/prefs/sources darcs get --lazy R S2 && cp fake-sources S2/_darcs/prefs/sources # make sure we do warn about things that are under your control darcs changes --verbose --repo S1 --no-cache 2>&1 | tee log-local c1=`grep -c "$baseurl/dummyRepo" log-local` [ $c1 -eq 1 ] c2=`grep -c "/some/bogus/local/path" log-local` [ $c2 -eq 1 ] # now what about things that aren't? darcs changes --verbose --repo $baseurl/S2 --no-cache 2>&1 | tee log-remote c1=`grep -c "$baseurl/dummyRepo" log-remote` [ $c1 -eq 1 ] # always under your control not grep -c "/some/bogus/local/path" log-remote darcs-2.8.4/tests/issue1922-obliterate-o-context.sh0000644001765600176560000000333212104371431021354 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1922 - obliterate -o does not give the right context ## ## Copyright (C) 2010 Florent Becker ## ## 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. . lib # Load some portability helpers. darcs init --repo R # Create our test repos. rm -rf x mkdir x darcs init --repo x echo a > x/a darcs rec -lam a --repo x --ig echo b > x/a darcs rec -lam b --repo x --ig echo a > x/b darcs rec -lam a2 --repo x --ig echo b > x/b darcs rec -lam b2 --repo x --ig echo c > x/a darcs rec -lam c --repo x --ig rm -f foo.dpatch darcs unpull -a -o foo.dpatch --match 'name a2' --repo x --last 3 cat foo.dpatch darcs chan --context --repo x darcs apply foo.dpatch --repo xdarcs-2.8.4/tests/issue1951-add-outside-repo.sh0000644001765600176560000001053312104371431020454 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1951 - darcs should refuse adds from outside the ## current repository ## ## Copyright (C) 2010 Eric Kow ## ## 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. . lib # Load some portability helpers. rm -rf R R2 R3 R4 R5 R6 R7 R8 R9 R10 darcs init --repo R # Create our test repos. darcs init --repo R2 darcs init --repo R3 darcs init --repo R4 darcs init --repo R5 darcs init --repo R6 darcs init --repo R7 darcs init --repo R8 darcs init --repo R9 darcs init --repo R10 # test if adding files outside the repository fails OUTSIDE=`pwd` cd R echo 'Example content.' > f echo 'Bad' > ../junk-for-issue1951 darcs add f not darcs add ../junk-for-issue1951 not darcs add $OUTSIDE/junk-for-issue1951 darcs whatsnew > log not grep junk-for-issue1951 log cd .. # test adding a file that: # * is in a subdirectory of the repository root # * is referred to with a path relative to the cwd, when the cwd is the # directory that the file is in cd R2 mkdir subdir cd subdir touch f darcs add f darcs whatsnew > log grep 'subdir/f' log cd ../.. # same as above, but now the relative path is valid both from the cwd and from # the repository root. Darcs should add the file in the cwd, not the one in the # repository root cd R3 touch f mkdir subdir cd subdir touch f darcs add f darcs whatsnew > log grep 'subdir/f' log cd ../.. # now test that adding fails on a file that # * is in the repository root # * is referred to with a path relative to the repository root, when the cwd is # not the repository root cd R4 touch myfilename mkdir subdir cd subdir not darcs add myfilename cd ../.. # test adding a file by relative path from the repo root, when the cwd is # outside the repo # It may seem counterintuitive that this succeeds and the cases above and below # do not, but that's the way it is. We use this feature ourselves in our test # suite. touch R5/myfilename darcs add --repo R5 myfilename darcs whatsnew --repo R5 > log grep 'myfilename' log not grep '\.\./myfilename' log # The case below makes the R4 case (of using a repo-root-relative path in a # subdir of the repo) look even more like the R5 case (of using a # repo-root-relative path outside the repo) by usign the --repo flag. It still # failed on darcs 2.4. cd R6 touch myfilename mkdir subdir cd subdir not darcs add --repo .. myfilename cd ../.. # Test adding a file by relative path from the repo root, when the cwd is # outside the repo, and the relative path also exists from the cwd touch myfilename touch R7/myfilename darcs add --repo R7 myfilename darcs whatsnew --repo R7 > log grep 'myfilename' log not grep '\.\.myfilename' log # Like the R4 case: try to use a path relative to the repo root from a cwd that # is a subdir of the repo root. In this case the path relative to the repo root # also includes a directory however. cd R8 mkdir subdir1 mkdir subdir2 touch subdir2/myfilename cd subdir1 not darcs add subdir2/myfilename cd ../.. # Try adding a non-repository file using a non-existent repo subdirectory name # followed by two ..'s touch myfilename cd R9 not darcs add nonexistentsubdir/../../myfilename cd .. # Try adding a non-repository file using an existing repo subdirectory name # followed by two ..'s touch myfilename cd R10 mkdir subdir not darcs add subdir/../../myfilename cd .. darcs-2.8.4/tests/issue1977-darcs-repair.sh0000644001765600176560000000034012104371431017666 0ustar ganeshganesh#!/usr/bin/env bash # Issue1977 darcs repair complains when there is no pristine.hashed directory set -ev mkdir temp1 cd temp1 darcs init echo "a" > a darcs add a darcs rec -am a rm -rf _darcs/pristine.hashed/ darcs repair darcs-2.8.4/tests/issue2013_send_to_context.sh0000644001765600176560000000355612104371431020565 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue2013 - darcs send --context --to shall not ask email address ## ## Copyright (C) 2010 Gabriel Kerneis ## ## 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. set -ev . lib DARCS_EDITOR=echo export DARCS_EDITOR mkdir temp2 cd temp2 darcs init echo foo > a darcs record -alm add_a -A x # setup test cd .. darcs get temp2 temp1 cd temp1 darcs changes --context > context touch foo bar darcs add foo bar darcs record -alm add_foo_bar -A x # Test that --to works with send --context darcs send --author=me -a --to=random@random --sendmail-command='grep "^To: random@random$" %<' --context context # Test that a default preference will NOT be used when no --to value is specified echo "default@email" > ../temp2/_darcs/prefs/email not darcs send --author=me -a --sendmail-command='grep "^To: default@email$" %<' --context context cd .. darcs-2.8.4/tests/issue2012_send_output_no_address.sh0000644001765600176560000000316012104371431022126 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue2012 - darcs send -o shall not print a "will be sent ## to" line ## ## Copyright (C) 2010 Gabriel Kerneis ## ## 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. set -ev . lib DARCS_EDITOR=echo export DARCS_EDITOR mkdir temp1 temp2 cd temp2 darcs init echo "default@email" > _darcs/prefs/email cd .. cd temp1 darcs init touch foo bar darcs add foo bar darcs record -a -m add_foo_bar -A x darcs send -a -o test.patch ../temp2 2>&1 | not grep "Patch bundle will be sent to: default@email" darcs send -a -O ../temp2 | not grep "Patch bundle will be sent to: default@email" cd .. darcs-2.8.4/tests/issue2035-malicious-subpath.sh0000644001765600176560000000244612104371431020736 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue2035 - malicious subpaths ## ## Copyright (C) 2010 Eric Kow ## ## 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. . lib # Load some portability helpers. gunzip -c $TESTDATA/badrepo.tgz | tar xf - not darcs get badrepo darcs-2.8.4/tests/issue2041_dont_add_symlinks.sh0000644001765600176560000000411412104371431021063 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue1645 - Since Darcs does not version-contol symlinks, ## it should reject them when a user is trying to 'darcs add' them. ## Thist must hold for both file and directory symlinks. ## ## Copyright (C) 2011 Alexey Levan ## ## 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. . lib # Load some portability helpers. rm -rf R # Another script may have left a mess. darcs init --repo R # Create our test repo. darcs --version cd R unset pwd # Since this test is pretty much linux-specific, hspwd.hs is not needed abort_windows # and skip if we are on win32... # test for file touch test-file ln -s ./test-file ./test-file-link1 # relative symlink ln -s "`pwd`"/test-file ./test-file-link2 # absolute symlink not darcs add test-file-link1 # darcs must fail to add symlinks not darcs add test-file-link2 # test for directory mkdir test-dir ln -s ./test-dir ./test-dir-link1 ln -s "`pwd`"/test-dir ./test-dir-link2 not darcs add test-dir-link1 not darcs add test-dir-link2 darcs-2.8.4/tests/issue2049-dir-case-change.sh0000644001765600176560000000321512104371431020217 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue2049 - adding files inside a directory ## that's had a case change. ## ## This is not the exact failure reported in issue2049, ## but was reported by another user on IRC around the ## same time, and is closely related. ## ## Copyright (C) 2011 Sven Strittmatter, Ganesh Sittampalam ## ## 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. . lib # Load some portability helpers. rm -rf R darcs init --repo R # Create our test repos. cd R mkdir foo touch foo/bar darcs add foo -r # two stage case change so it works on Windows mv foo fox mv fox foO touch foO/bar2 not darcs add foO/bar2 darcs-2.8.4/tests/issue966_diff.sh0000644001765600176560000000101112104371431016215 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp mkdir temp; cd temp darcs init echo "aaa diff" > file darcs add file darcs record -a -m "aaa" echo "bbb diff" >> file darcs record -a -m "bbb" darcs diff --patch "aaa" | grep "aaa diff" darcs diff --patch "bbb" | grep "bbb diff" darcs tag release-1 darcs optimize echo "ccc diff" >> file darcs record -a -m "ccc" darcs diff --patch "ccc" | grep "ccc diff" # here is where we have a problem darcs diff --patch "aaa" | grep "aaa diff" darcs diff --patch "bbb" | grep "bbb diff" darcs-2.8.4/tests/issue2052-default-unified-diff.sh0000644001765600176560000000301012104371431021243 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue2052 - Ensure we use unified Diff by default. ## ## Copyright (C) 2011 Owen Stephens ## ## 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. set -ev . lib # Load some portability helpers. rm -rf R darcs init --repo R cd R touch a darcs add a darcs record -am 'Add a' echo testing > a test `darcs diff | grep -c "diff -rN -u"` -eq 1 test `darcs diff --no-unified | grep -c "diff -rN -u"` -eq 0 test `darcs diff --no-unified | grep -c "diff -rN"` -eq 1 darcs-2.8.4/tests/issue2066-record-file-not-exist.sh0000644001765600176560000000023612104371431021427 0ustar ganeshganeshset -ev rm -rf temp mkdir -p temp cd temp darcs init touch a b darcs add a darcs record -a -m "record a" a rm a darcs add b darcs record -a -m "record a" a darcs-2.8.4/tests/issue2067-diff-blanklines.sh0000644001765600176560000000255612104371431020344 0ustar ganeshganesh#!/usr/bin/env bash ## Test for 2067: inexistant files result in empty lines in darcs ##diff ## ## Copyright (C) YEAR AUTHOR ## ## 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. . lib # Load some portability helpers. darcs init --repo R # Create our test repos. cd R darcs diff a b c d 2> /dev/null | wc -l | grep "^ *0$" darcs-2.8.4/tests/issue2076-move_into_dir.sh0000644001765600176560000000265512104371431020151 0ustar ganeshganesh#!/usr/bin/env bash ## Copyright (C) 2011 Lennart Kolmodin ## ## 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. . lib # Load some portability helpers. darcs init --repo issue2076 cd issue2076 touch file1 darcs record -lam 'file1' mkdir dir1 mv file1 dir1 not darcs mv file1 dir1 # we require dir1 to be added first darcs add dir1 darcs mv file1 dir1 darcs whatsnew darcs-2.8.4/tests/issue2139-mv-to-dir.sh0000644001765600176560000000320212104371431017117 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue2139 - darcs should accept to mv to the ## current working directory ## ## Copyright (C) 2012 Eric Kow ## ## 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. . lib # Load some portability helpers. darcs init --repo R # Create our test repos. cd R # move dir to root mkdir a a/a2 a/a3 darcs record -lam 'Some directories (a)' darcs mv a/a2 . test -d a2 cd a darcs mv a3 .. not test -d a3 cd .. test -d a3 # move dir to non-root dir mkdir b b2 b3 darcs record -lam 'Some directories (b)' darcs mv b2 b test -d b/b2 cd b darcs mv ../b3 . test -d b3 cd .. cd .. darcs-2.8.4/tests/issue244_changes.sh0000644001765600176560000000045312104371431016713 0ustar ganeshganesh#!/usr/bin/env bash set -ev # Issue244 # darcs changes should be able to pull up the history for a file # using its moved and not-yet recorded new name rm -rf temp1 mkdir temp1 cd temp1 darcs init touch b darcs add b darcs record -am 11 darcs mv b c darcs changes c | grep 11 cd .. rm -rf temp1 darcs-2.8.4/tests/issue2136-changes_created_as_for_multiple_files.sh0000644001765600176560000000517312104371431025034 0ustar ganeshganesh#!/usr/bin/env bash ## Ensure changes --xml reports correct original filenames for multiple files. ## ## Copyright (C) 2012 Owen Stephens ## ## 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. . lib rm -rf R darcs init --repo R cd R mkdir tldir touch tldir/f1 darcs rec -alm 'Add tldir/f1' echo foo >> tldir/f1 darcs rec -am 'Modify tldir/f1' darcs move tldir/f1 tldir/f2 darcs rec -am 'Move tldir/f1 -> tldir/f2' touch f3 darcs rec -alm 'Add f3' darcs move f3 f4 darcs rec -am 'Move f3 -> f4' darcs move f4 f5 darcs rec -am 'Move f4 -> f5' touch f6 darcs rec -alm 'Add non-changing file f6' mkdir tldir/d1 darcs rec -alm 'Add tldir/d1' darcs move tldir/d1 tldir/d2 darcs rec -am 'Move tldir/d1 -> tldir/d2' mkdir d3 darcs rec -alm 'Add d3' darcs move d3 d4 darcs rec -am 'Move d3 -> d4' darcs move d4 d5 darcs rec -am 'Move d4 -> d5' # Ensure all original names are reported, both forwards, and reversed. xmlChanges=$(darcs cha --xml tldir/f2 f5 tldir/d2 d5 f6) xmlChangesRev=$(darcs cha --reverse --xml tldir/f2 f5 tldir/d2 d5 f6) # xmlChanges needs to be quoted everywhere, otherwise this hack to retrieve the # 2 following lines won't work. checkRename () { echo "$1" | grep "" -C2 | tail -1 | grep "$4" } checkInXML () { checkRename "$1" "d5" "d3" "Add d3" checkRename "$1" "f5" "f3" "Add f3" checkRename "$1" "tldir/d2" "tldir/d1" "Add tldir/d1" checkRename "$1" "tldir/f2" "tldir/f1" "Add tldir/f1" } checkInXML "$xmlChanges" checkInXML "$xmlChangesRev" # But don't mention unchanged files. echo "$xmlChanges" | not grep "]*'\./f6'" darcs-2.8.4/tests/issue27.sh0000644001765600176560000000130112104371431015133 0ustar ganeshganesh#!/bin/sh set -ev rm -rf temp1 temp2 mkdir temp1 temp2 cd temp1 darcs init echo first > a darcs add a darcs record --pipe --all --name=first < b darcs add b darcs record --pipe --all --name=first <> a darcs record --pipe --all --name=second <> b darcs record --pipe --all --name=second < foobar darcs add foobar darcs record -a -A me -m add_foobar # Test that editor is called when --output is used with --edit-description echo This is a note > note cat > editor <> \$1 cat \$1-temp >> \$1 echo >> \$1 echo finished editing >> \$1 echo I am done running the editor EOF chmod +x editor DARCS_EDITOR='bash editor' darcs send --author=me -a --output=bundle --edit-description ../temp2 echo === beginning of bundle > === cat bundle echo === end of bundle > === grep ' add_foobar' bundle grep 'finished editing' bundle IFS=' ' darcs send --author=me -a --subject="it works" --to user@place.org --sendmail-command='grep "^Subject: it works$" %<' ../temp2 cd .. rm -rf temp1 temp2 darcs-2.8.4/tests/issue279_get_extra.sh0000644001765600176560000000137512104371431017301 0ustar ganeshganesh#!/usr/bin/env bash # issue279: a conflict case resulting in "bug in get_extra" with old # format repos and "Malformed patch bundle" with darcs-2 repos. . lib rm -rf temp1 temp_a temp_b temp_c temp_d mkdir temp1 cd temp1 darcs init --darcs-2 echo 0 > f darcs add f darcs record -am 00 cd .. for r in a b c d; do darcs put --repodir temp1 temp_$r cd temp_$r; echo $r > f darcs record -am "patch:$r"; cd .. done cd temp_d darcs pull -a ../temp_a darcs pull -a ../temp_b darcs pull -a ../temp_c cd .. cd temp_c darcs pull -a ../temp_a darcs pull -a ../temp_b echo rc > f darcs record -a -m rc cd .. cd temp_d darcs pull -a ../temp_c > log not grep -i "no remote changes" log not grep -i get_extra log cd .. rm -rf temp1 temp_a temp_b temp_c temp_d log darcs-2.8.4/tests/issue436.sh0000644001765600176560000000075212104371431015230 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp1 temp2 mkdir temp1 cd temp1 # this test fails in the darcs 1 format darcs init --darcs-2 echo A > f darcs add f darcs record --ignore-times -a -m A cd .. darcs get temp1 temp2 cd temp1 echo C > f darcs record --ignore-times -a -m A-C cd .. cd temp2 echo B > f darcs record --ignore-times -a -m A-B echo A > f darcs record --ignore-times -a -m B-A (darcs push -a || :) 2> push-result grep "Refusing to apply" push-result cd .. rm -rf temp1 temp2 darcs-2.8.4/tests/issue458.sh0000644001765600176560000000132012104371431015224 0ustar ganeshganesh#!/usr/bin/env bash ### http://bugs.darcs.net/issue458 ### darcs get --set-scripts-executable ignores umask set -ev ## Windows doesn't support proper permissions. if echo $OS | grep -i windows; then echo Windows does not support posix permissions exit 0 fi rm -rf temp mkdir temp cd temp mkdir repo1 darcs initialize --repodir repo1 printf >repo1/x '#!/bin/sh\ntrue' # make a shebang'd script darcs record --repodir repo1 -lam x x umask 077 # DENY ALL access to group, all darcs get --set-scripts-executable repo1 repo2 # remove trailing-dot for xattr ls -l repo2/x | cut -f 1 -d\ | sed -e "s/\.$//" > mode echo -rwx------ > desired-mode diff -u desired-mode mode cd .. rm -rf temp darcs-2.8.4/tests/issue53.sh0000644001765600176560000000063412104371431015142 0ustar ganeshganesh#!/usr/bin/env bash . lib if echo $OS | grep -i windows; then echo This test does not work under Windows exit 0 fi # pull from not empty repo to empty repo rm -rf temp1 mkdir temp1 cd temp1 darcs init echo a > Aux.hs not darcs add Aux.hs darcs add --reserved-ok Aux.hs echo b > foo darcs add foo darcs record -am 'two files' not darcs mv foo com1 darcs mv --reserved-ok foo com1 cd .. rm -rf temp1 darcs-2.8.4/tests/issue538.sh0000644001765600176560000000604512104371431015234 0ustar ganeshganesh#!/bin/env bash # A test for issue 538 - that an executable test script will run successfully if # it is recorded with --set-scripts-executable. set -ev if echo $OS | grep -i windows; then echo I do not know how to run a test program under windows exit 0 fi function make_repo_with_test { mkdir temp1 ; cd temp1 ; darcs init echo "#!/bin/sh" > test.sh echo "echo 'hello world'" >> test.sh darcs add test.sh darcs record --author=test@test -am test darcs setpref test './test.sh' } # test record with --set-scripts-executable rm -rf temp1 make_repo_with_test touch blaat darcs add blaat if darcs record --set-scripts-executable -A test@test -am blaat --test; then echo "ok 1" else echo "not ok 1 recording second patch failed (because test failed?)" exit 1 fi cd .. # test record without --set-scripts-executable rm -rf temp1 make_repo_with_test touch blaat darcs add blaat if darcs record --dont-set-scripts-executable -A test@test -am blaat --test; then echo "not ok 2 recording second patch succeeded though test script should not be executable" exit 1 else echo "ok 2" fi cd .. # test amend-record with --set-scripts-executable rm -rf temp1 make_repo_with_test touch blaat darcs add blaat if echo y | darcs amend-record --set-scripts-executable -A test@test -a --test; then echo "ok 3" else echo "not ok 3 amending patch failed (because test failed?)" exit 1 fi cd .. # test amend-record without --set-scripts-executable rm -rf temp1 make_repo_with_test touch blaat darcs add blaat if echo y | darcs amend-record --dont-set-scripts-executable -A test@test -a /dev/null --test; then echo "not ok 4 amending patch succeeded even though --dont-set-scripts-executable specified" exit 1 else echo "ok 4" fi cd .. # trackdown with --set-scripts-executable rm -rf temp1 make_repo_with_test if darcs trackdown --set-scripts-executable | grep 'Success!' ; then echo "ok 5" else echo "not ok 5 tracking down with --set-scripts-executable failed (because test failed?)" exit 1 fi cd .. # trackdown without --set-scripts-executable rm -rf temp1 make_repo_with_test if darcs trackdown --dont-set-scripts-executable | grep 'Noone passed the test!' ; then echo "ok 6" else echo "not ok 6 tracking down did not find failure even though --dont-set-scripts-executable was given" exit 1 fi cd .. # check trackdown with files that become scripts during trackdown rm -rf temp1 mkdir temp1 ; cd temp1 ; darcs init echo "#!/bin/sh" > test.sh echo "./helper.sh" >> test.sh echo "#!/bin/sh" > helper.sh echo "echo 'helper speaking'" >> helper.sh darcs add test.sh darcs add helper.sh darcs record -am 'valid helper' -A test echo 'this is definitely not a valid script' > helper.sh darcs record -am 'invalid helper' -A test darcs setpref test './test.sh' darcs trackdown --set-scripts-executable > trackdown-out if grep 'Test failed!' trackdown-out && grep 'Success!' trackdown-out ; then echo "ok 7" else echo "not ok 7 either no failure or no success (both should occur)" exit 1 fi cd .. rm -rf temp1 darcs-2.8.4/tests/issue525_amend_duplicates.sh0000644001765600176560000000067612104371431020615 0ustar ganeshganesh#!/bin/sh set -ev ## I would use the builtin !, but that has the wrong semantics. not () { "$@" && exit 1 || :; } rm -rf temp1 mkdir temp1 cd temp1 darcs init echo first > a darcs add a darcs record -am 'first' echo replace first with something else > a darcs record -am 'mistake' echo first > a echo on second thought >> a echo ya | darcs amend-record -a darcs changes --last=1 -v > output cat output not grep first output cd .. rm -rf temp1 darcs-2.8.4/tests/issue588.sh0000644001765600176560000000131212104371431015231 0ustar ganeshganesh#!/usr/bin/env bash # For issue588, "amend-record --look-for-adds end up with two "addfile" entries" set -ev rm -rf temp1 darcs init --repodir temp1 # Setup f with contents foo. echo foo > temp1/f darcs add --repodir temp1 f darcs rec --repodir temp1 -am p1 # Remove f, and amend p1, but only the hunk not the rmfile. # Here we use look-for-adds to trigger the bug rm temp1/f echo yyd | darcs amend-record --repodir temp1 --look-for-adds darcs changes --repodir temp1 --last 1 -v echo show the buggy pending cat temp1/_darcs/patches/pending echo bar > temp1/f echo y | darcs amend-record --repodir temp1 --all darcs changes --repodir temp1 --last 1 -v darcs check --repodir temp1 --no-test rm -rf temp1 darcs-2.8.4/tests/issue691.sh0000644001765600176560000000042612104371431015231 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp mkdir temp cd temp darcs init echo 'record name' > _darcs/prefs/defaults # name requires an argument echo 'ALL unified foobar' >> _darcs/prefs/defaults # unified takes no argument darcs record && exit 1 darcs whats && exit 1 rm -rf temp darcs-2.8.4/tests/issue706.sh0000644001765600176560000000037112104371431015225 0ustar ganeshganesh#!/usr/bin/env bash set -ev # for issue706: "Filenames with spaces issue" DARCS_EDITOR=echo export DARCS_EDITOR rm -rf temp mkdir temp cd temp darcs init touch 'A B' darcs add 'A B' darcs rec -a -m 'a b' -A me ls darcs check cd .. rm -rf temp darcs-2.8.4/tests/issue803.sh0000644001765600176560000000067312104371431015230 0ustar ganeshganesh#!/usr/bin/env bash # http://bugs.darcs.net/issue803: Darcs 2.0 regression on manual renames . lib rm -rf temp mkdir temp cd temp darcs init touch a.txt darcs add a.txt darcs record -a -m "First" -A me mkdir subdir darcs add subdir darcs record -a -m "Second" -A me mv a.txt subdir/ darcs mv a.txt subdir/a.txt darcs record -a -m "Third" -A me darcs changes --last 1 -v > stdout cat stdout not grep 'rmfile' stdout cd .. rm -rf temp darcs-2.8.4/tests/issue595_get_permissions.sh0000644001765600176560000000253412104371431020530 0ustar ganeshganesh#!/usr/bin/env bash # Issue595 # # A test for running "darcs get" when the parent directory has restrictive # permissions. The bug is that darcs trys to "chdir" to the current directory # using the full path. The permissions on the parent directory prevent this # from working, even though the current repo and the remote have sufficient # permissions. # # The real-world case where this would happen would be a web-server with # restrictive permissions on "/home", with a user running darcs within that. . lib abort_windows rm -rf temp1 temp2 # Set up a "remote" repo mkdir tmp_remote cd tmp_remote darcs 'init' cd .. DIR=`pwd` # Set up a directory with restrictive permissions mkdir -p tmp_restrictive/liberal cd tmp_restrictive/liberal chmod 0111 ../../tmp_restrictive # sanity check that we can cd out and back cd ../..; cd tmp_restrictive/liberal # TODO: we avoid this test on Solaris because it seems we can't create # anything in tmp_restrictive/liberal touch can_touch if [ -e can_touch ]; then if hwpwd; then darcs get "$DIR/tmp_remote" 2> log not grep -i 'permission denied' log else echo "Apparently I can't do `basename $0` on this platform" fi else echo "Can't do `basename $0` on this platform" fi cd "$DIR" # We have to fix the permissions, just so we can delete it. chmod 0755 tmp_restrictive rm -rf tmp_remote tmp_restrictive darcs-2.8.4/tests/look_for_add.sh0000644001765600176560000000133512104371431016263 0ustar ganeshganesh#!/usr/bin/env bash cat > empty_pending < dir/foo echo zag > foo mkdir dir2 echo hi > dir2/foo2 darcs record -a -m add_foo -A x --look-for-adds check_empty_pending cd ../temp2 darcs init darcs pull -a ../temp1 cd .. cmp temp1/dir2/foo2 temp2/dir2/foo2 cmp temp1/dir/foo temp2/dir/foo cmp temp1/foo temp2/foo rm -rf temp1 temp2 darcs-2.8.4/tests/issue709_pending_look-for-adds.sh0000644001765600176560000000154012104371431021454 0ustar ganeshganesh#!/bin/sh set -ve . lib rm -rf temp1 mkdir temp1 cd temp1 darcs init # Here we check whether recording just one of two --look-for-add # addfiles causes any trouble (which it doesn't) date > f1 date > f2 echo yyd | darcs record -l -m ff cat _darcs/patches/pending not darcs wh rm f2 # Try recording a file add without --look-for-adds, with a setpref # patch present that we don't record. darcs setpref boringfile .boring echo bar > bar darcs add bar echo yyd | darcs record -mbar cat _darcs/patches/pending darcs whatsnew -s test -z "`darcs whatsnew -s`" # Now try the same thing using --look-for-adds echo foo > foo darcs wh -l # remove any files added by profiling or hpc... rm -f darcs.tix darcs.prof echo yyd | darcs record --look-for-adds -mfoo cat _darcs/patches/pending darcs whatsnew -s test -z "`darcs whatsnew -s`" cd .. rm -rf temp1 darcs-2.8.4/tests/issue70_setpref.sh0000644001765600176560000000405312104371431016670 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue70 - unrecorded (pending) changes to preferences ## should coalesce; if you set the same preference more than once in ## the same patch, only the last change should actually be recorded. ## ## Copyright (C) 2005 Eric Kow ## ## 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. . lib rm -rf temp1 mkdir temp1 cd temp1 darcs init darcs setpref predist apple darcs setpref predist banana darcs setpref predist clementine darcs record -a -m manamana darcs changes --verbose > log not grep apple log not grep banana log grep clementine log cd .. rm -rf temp1 # not sure what i'm going for here - if coalescing happens strictly # before commuting, no problem, but what if patches are commuted # before coalescing? mkdir temp1 cd temp1 darcs init darcs setpref predist apple darcs setpref predist banana darcs setpref predist apple darcs setpref predist clementine darcs setpref predist banana darcs record -a -m manamana darcs changes --verbose > log not grep apple log not grep clementine log grep banana log cd .. rm -rf temp1 darcs-2.8.4/tests/issue885_get_to_match.sh0000644001765600176560000000126612104371431017756 0ustar ganeshganesh#!/bin/sh # Issue885: Regression: "darcs get --to-match" does not work anymore under 2.0 . lib rm -rf temp1 mkdir temp1 cd temp1 darcs init echo first > a darcs add a darcs record -am 'first' firsthash=`darcs changes --xml | grep 'hash=' | sed -e "s/.*hash='//" -e "s/'>//"` echo second > b darcs add b darcs record -am 'second' # Pulling that patch works ok cd .. rm -rf temp2 mkdir temp2 cd temp2 darcs init echo darcs pull -v -a --match "hash $firsthash" ../temp1 darcs pull -v -a --match "hash $firsthash" ../temp1 # Getting up-to that patch does not cd .. rm -rf temp3 echo darcs get -v --to-match "hash $firsthash" temp1 temp3 darcs get -v --to-match "hash $firsthash" temp1 temp3 darcs-2.8.4/tests/issue844_gzip_crc.sh0000644001765600176560000000044012104371431017105 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp1 temp2 mkdir temp1 cd temp1 darcs init echo > a darcs add a darcs record a -a -m "init" cd .. mkdir temp2 cd temp2 darcs init darcs pull ../temp1 -a darcs optimize --compress for f in _darcs/patches/*-*; do gzip -t < "$f" done rm -rf temp1 temp2 darcs-2.8.4/tests/justrm.sh0000644001765600176560000000025412104371431015164 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp1 mkdir temp1 cd temp1 darcs init touch foo darcs add foo darcs record -a -m add_foo -A x rm foo darcs whatsnew cd .. rm -rf temp1 darcs-2.8.4/tests/nonewline.sh0000644001765600176560000000051012104371431015631 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp1 temp2 mkdir temp1 temp2 cd temp1 darcs init echo -n zig > foo darcs add foo sleep 1 darcs record -a -m add_foo -A x #sleep 1 echo -n zag >> foo darcs record --ignore-time -a -m mod_foo -A x cd ../temp2 darcs init darcs pull -a ../temp1 cd .. cmp temp1/foo temp2/foo rm -rf temp1 temp2 darcs-2.8.4/tests/issue864_replace_in_moved.sh0000644001765600176560000000115012104371431020601 0ustar ganeshganesh#!/usr/bin/env bash # Issue 864 # darcs mv file1 file2 # edit file2 # darcs replace fails if new token includes some existing edits # Regression in darcs2 - it works in darcs1 1.0.9 set -ev rm -rf temp mkdir temp cd temp darcs init cat < file1 aa bb cc aa bb cc EOF darcs add file1 darcs record -a -m "0" --author X cat < file1 aaaa bb cc aa bb cc EOF darcs replace aa aaaa file1 > out cat out grep 'Skipping file' out && exit 1 darcs mv file1 file2 cat < file2 aaaa beebee cc aa bb cc EOF darcs replace bb beebee file2 > out cat out grep 'Skipping file' out && exit 1 cd .. rm -rf temp darcs-2.8.4/tests/issue942_push_apply_prehook.sh0000644001765600176560000000332612104371431021225 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue942 - remote apply prehook not invoked on darcs push ## We also test for posthooks along the way even though that's not part ## of the issue. ## ## Copyright (C) 2009 Eric Kow ## ## 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. . lib # Load some portability helpers. rm -rf R S # Another script may have left a mess. darcs init --repo R # Create our test repos. echo 'apply prehook touch g' >R/_darcs/prefs/defaults echo 'apply posthook touch h' >>R/_darcs/prefs/defaults darcs get R S cd S touch f darcs add f darcs record -lam 'Add f' test ! -e ../R/g test ! -e ../R/h darcs push -a test -e ../R/g test -e ../R/h darcs-2.8.4/tests/nodeps.sh0000644001765600176560000000357012104371431015134 0ustar ganeshganesh#!/usr/bin/env bash set -ev # Test the --no-deps option with Send, Push, Pull, Obliterate and Unrecord. # # Create four patches with dependencies. # file 'f': patch 'fa' and 'fb' # file 'g': patch 'ga' and 'gb' # The 'b' patches depend on the 'a' patches. rm -rf tmp1 mkdir tmp1 cd tmp1 darcs init echo 'record no-ask-deps' >> _darcs/prefs/defaults echo 'record ignore-times' >> _darcs/prefs/defaults echo 'a' > f darcs add f darcs rec -am 'fa' f echo 'a' > g darcs add g darcs rec -am 'ga' g echo 'b' > f darcs rec -am 'fb' f echo 'b' > g darcs rec -am 'gb' g mkdir d darcs init --repodir d # Try to Send all 'b' and 'g' patches. The two 'g' patches should succeed, # but the 'fb' patch depends on the unselected 'fa' patch, an should be # skipped. darcs send -o bundle -a -p '[bg]' --no-deps d grep '^\[ga$' bundle grep '^\[fb$' bundle && exit 1 # Try to Push all 'b' and 'g' patches. Expect same result as for Send. darcs push -a -p '[bg]' --no-deps d cd d darcs changes | grep '^ \* ga$' darcs changes | grep '^ \* fb$' && exit 1 # stay in d !! # Try to Pull all 'b' and 'g' patches. Expect same result as for Send. # already in d rm -rf *; darcs init darcs pull -a -p '[bg]' --no-deps .. darcs changes | grep '^ \* ga$' darcs changes | grep '^ \* fb$' && exit 1 cd .. # Try to Obliterate all 'a' and 'g' patches. The two 'g' patches should # succeed, but the 'fa' patch depends on the unselected 'fb' patch, an # should be skipped. darcs get . tmp; cd tmp echo y/y/y/q | tr / \\012 | darcs obliterate -p '[ag]' --no-deps darcs changes | grep '^ \* gb$' && exit 1 darcs changes | grep '^ \* fa$' cd .. # Try to Unrecord all 'a' and 'g' patches. Expect same result as for # Obliterate. # in "top" tmp repo -- destroys it! echo y/y/y/q | tr / \\012 | darcs unrecord -p '[ag]' --no-deps darcs changes | grep '^ \* gb$' && exit 1 darcs changes | grep '^ \* fa$' cd .. rm -rf tmp1 darcs-2.8.4/tests/perms.sh0000644001765600176560000000120312104371431014761 0ustar ganeshganesh#!/usr/bin/env bash set -ev uname | grep "MINGW" > /dev/null && exit 0 rm -rf temp1 temp2 mkdir temp1 cd temp1 darcs init echo record author me > _darcs/prefs/defaults echo ALL all >> _darcs/prefs/defaults echo ALL verbose >> _darcs/prefs/defaults echo ALL ignore-times >> _darcs/prefs/defaults touch foo darcs add foo darcs record -m add_foo echo hello >> foo darcs record -m mod_foo cd .. darcs get --repo-name temp2 temp1 cd temp2 cp ../temp1/_darcs/prefs/defaults _darcs/prefs echo y/d/y | tr / \\012 | darcs unpull --interactive test -f foo -a ! -s foo chmod +x foo test -x foo darcs pull ../temp1 test -x foo cd .. rm -rf temp1 temp2 darcs-2.8.4/tests/lazy-optimize-reorder.sh0000644001765600176560000000211212104371431020110 0ustar ganeshganesh#!/usr/bin/env bash . lib rm -rf temp1 temp2 temp3 mkdir temp1 cd temp1 darcs init # this test only applies to hashed formats if cat _darcs/inventory; then exit 0; fi date > f1 darcs add f1 darcs record -am 'add f1' darcs tag -m 'tag f1' date > f2 darcs add f2 darcs record -am 'add f2' cd .. darcs get --lazy temp1 temp2 darcs get --lazy temp2 temp3 cd temp2 # Run darcs changes so we pull in the inventories (but no the patches) darcs changes # Remove original repository, so we have no references to changes f1 and f2. rm -rf ../temp1 # Now we should be unable to read some of the history darcs changes -s > out cat out grep unavailable out date > f3 darcs add f3 darcs record -am 'add f3' darcs tag -m 'tag 123' cd .. cd temp3 date > f4 darcs add f4 darcs record -am 'add f4' darcs pull -av # Here's the point of this test: we should be able to optimize # --reorder without being able to read all the patches in the # repository. darcs optimize --reorder # Just a double-check: we shouldn't be able to check in this case. not darcs check cd .. rm -rf temp1 temp2 temp3 temp4 darcs-2.8.4/tests/mark-conflicts.sh0000644001765600176560000000144212104371431016554 0ustar ganeshganesh#!/usr/bin/env bash # Automated tests for "darcs mark-conflicts". # The builtin ! has the wrong semantics for not. not () { "$@" && exit 1 || :; } mkdir temp1 cd temp1 darcs init echo "Conflict, Base ." > child_of_conflict darcs add child_of_conflict darcs record -am 'Conflict Base' cd .. darcs get temp1 temp2 # Add and record differing lines to both repos cd temp1 echo "Conflict, Part 1." > child_of_conflict darcs record -A author -am 'Conflict Part 1' cd .. cd temp2 echo "Conflict, Part 2." > child_of_conflict darcs record -A author -am 'Conflict Part 2' cd .. cd temp1 darcs pull -a ../temp2 > log grep conflict log grep finished log grep 'v v' child_of_conflict darcs revert -a not grep 'v v' child_of_conflict darcs mark-conflicts grep 'v v' child_of_conflict cd .. rm -rf temp1 temp2 darcs-2.8.4/tests/match-date.sh0000644001765600176560000001401612104371431015650 0ustar ganeshganesh#!/usr/bin/env bash . lib rm -rf temp1 # Some tests for the '--match' flag, specifically the date-matching fmt_offset() { if date -d "now${1}days" >& /dev/null; then date -d "now${1}days" +"%Y%m%d" elif date -v ${1}d >& /dev/null; then date -v ${1}d +"%Y%m%d" else echo "Can't do date arithmetic on this system :(" >&2 return 1 fi } reset_repo () { cd .. rm -rf temp1 mkdir temp1 cd temp1 darcs init touch bar darcs add bar } create_entry () { echo $1 >> bar echo "$1/tester/a///" | tr / \\012 | darcs record -m "" --pipe bar } create_entry_now () { echo today >> bar darcs record -m "" bar -a -A tester } # parse_date just checks for parsing, while match_date checks for an actual match. # It's better if we can use "match_date", but we have to be able to construct such a date # based on a date dynamically generated by this test script. # alternately, it might be more useful to build a random date string generator # using QuickCheck... for any n random CalendarTimes, have it generate some # possible variants and roundtrip them to see if they match parse_date () { darcs changes --match "date \"$1\"" > log not grep fancy log } match_date () { darcs changes --match "date \"$1\"" > log grep tester log not grep fancy log } nomatch_date () { darcs changes --match "date \"$1\"" > log not grep tester log not grep fancy log } mkdir temp1 cd temp1 reset_repo # this block of dates should all refer to the same thing year=1973 mm=02 dd=04 hhmmss="15:08" create_entry "$year-$mm-$dd $hhmmss" match_date "$year-$mm-$dd" match_date "$year$mm$dd" match_date "$year-$mm" match_date "$year$mm" match_date "$year" # week dates. note that 2007 was selected as it starts on Monday reset_repo create_entry "2007-01-04 15:00" match_date '2007-W01-4' nomatch_date '2007-W01-1' match_date '2007W014' match_date '2007-W01' nomatch_date '2007-W02-1' create_entry "2007-01-08 15:00" match_date '2007-W02' match_date '2007-W02-1' create_entry "2007-05-20 15:00" match_date '2007-W20' nomatch_date '2007-W21' nomatch_date '2007-W19' # ordinal dates. eh... why not? match_date '2007-004'; # fourth day of 2007 match_date '2007004' nomatch_date '2007-005' # midnight and zero reset_repo create_entry "1992-10-15 00:00" match_date '1992-10-14 24:00' match_date '1992-10-15 00:00' # all the same date/time reset_repo create_entry "1992-02-12T22:32:11" match_date '1992-02-12T22:32:11' match_date '1992-02-12 22:32:11' match_date '1992-02-12T223211.0000' # english dates - the old hard coded from < darcs 1.0.6 reset_repo year=`date +%Y` mm=`date +%m` dd=`date +%d` hhmmss=`date +%k:%M:%S` tz=`date +%z` create_entry "$(($year-1))-$mm-$dd" nomatch_date 'today' nomatch_date 'yesterday' nomatch_date 'day before yesterday' nomatch_date 'last week' nomatch_date 'last month' # note: this test might fail if you run it just before midnight reset_repo create_entry_now match_date 'today' nomatch_date 'yesterday' nomatch_date 'day before yesterday' match_date 'last week' match_date 'last month' fmt_offset -1 || exit 200 reset_repo create_entry "$(fmt_offset -350)" # english dates - new possibilities nomatch_date 'yesterday at 14:00:00' match_date 'last 3 years' match_date 'last year' nomatch_date '2 days ago' nomatch_date 'last month 13:00' nomatch_date '3 days before last week' reset_repo create_entry_now match_date 'day after yesterday' match_date 'day since yesterday' match_date 'week after last week' match_date 'week since last week' create_entry "1992-10-02 00:15" match_date '15 minutes after 1992-10-02' match_date '15 minutes since 1992-10-02' reset_repo create_entry "1992-10-02 00:15+05" # note that earlier dates will always match match_date '15 minutes after 1992-10-02 00:00+05'; # same time match_date '15 minutes after 1992-10-01 23:00+04'; # same time match_date '15 minutes since 1992-10-02 00:00+05'; # same time match_date '15 minutes since 1992-10-01 23:00+04'; # same time nomatch_date '15 minutes after 1992-10-02 01:00+05'; # 1 hour later nomatch_date '15 minutes after 1992-10-02 00:00+04'; # 1 hour later nomatch_date '1 hour, 15 minutes after 1992-10-02 00:00+05'; # 1 hour later nomatch_date '15 minutes since 1992-10-02 01:00+05'; # 1 hour later nomatch_date '15 minutes since 1992-10-02 00:00+04'; # 1 hour later nomatch_date '1 hour, 15 minutes since 1992-10-02 00:00+05'; # 1 hour later match_date '1 hour, 15 minutes after 1992-10-02 00:00+06'; # same time match_date '1 hour, 15 minutes after 1992-10-01 23:00+05'; # same time match_date '1 hour, 15 minutes since 1992-10-02 00:00+06'; # same time match_date '1 hour, 15 minutes since 1992-10-01 23:00+05'; # same time reset_repo create_entry_now create_entry 1992-10-02 00:15 # english intervals nomatch_date 'between last fortnight and day before yesterday' match_date 'between last fortnight and today' match_date 'in the last 45 seconds' match_date 'after 1992' match_date 'since 1992' # iso 8601 intervals parse_date '1992-10-02 00:00Z/1992-10-02 00:16Z' match_date '1992-10-02 00:00/1992-10-02 00:16' match_date 'between 1992-10-02 00:00 and 1992-10-12 00:16' parse_date 'P3YT3M/1992' parse_date '1992/P3Y3M4DT5H3M2S' parse_date '1992/P3Y3M' # stuff from the manual reset_repo create_entry_now nomatch_date 'between 2004-03-12 and last week' match_date 'last week' parse_date 'yesterday' parse_date 'today 14:00' nomatch_date '3 days before last year at 17:00' # We can't in general parse the raw date output by darcs. If we change the # format to not include timezone information, this would be possible. But # maybe that's not desireable. For now, we just won't test the raw date. #match_date "$raw_date" parse_date 'after 2005' parse_date 'since 2005' parse_date 'in the last 3 weeks' parse_date 'P3M/2006-03-17' parse_date '2004-01-02/2006-03-17' parse_date 'P2M6D' # cvs dates parse_date '2006/01/19 21:14:20 UTC' # We can't handle all timezones in the old style dates # so this test will not work everywhere # match_date "$year/$mm/$dd $hhmmss $tz" reset_repo create_entry '2038-01-01' match_date 'after 2037' match_date 'since 2037' rm -rf temp1 temp2 darcs-2.8.4/tests/merge_three_patches.sh0000644001765600176560000000172112104371431017635 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf tempOld tempA tempB mkdir tempOld tempA cd tempOld darcs initialize echo record author me > _darcs/prefs/defaults echo ALL all >> _darcs/prefs/defaults #echo ALL verbose >> _darcs/prefs/defaults echo ALL ignore-times >> _darcs/prefs/defaults echo A > foo echo B >> foo echo C >> foo echo D >> foo echo E >> foo echo F >> foo echo G >> foo echo H >> foo darcs add foo darcs record -m Old cd .. cd tempA darcs initialize cp ../tempOld/_darcs/prefs/defaults _darcs/prefs darcs pull ../tempOld cp foo temp cat temp | grep -v A | grep -v B | grep -v D | sed s/E/e/ \ | grep -v G | sed s/H/h/ > foo darcs record -m AA cd .. darcs get tempOld tempB cd tempB cp ../tempOld/_darcs/prefs/defaults _darcs/prefs echo 7 > foo darcs record -m BB darcs pull ../tempA darcs record -m "conflict resolution" cd .. cd tempA darcs pull ../tempB darcs annotate -p B darcs annotate -p resolution cd .. cmp tempA/foo tempB/foo rm -rf tempOld tempA tempB darcs-2.8.4/tests/mergeresolved.sh0000644001765600176560000000177612104371431016515 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf fooOld tempA tempB mkdir fooOld tempA tempB cd fooOld darcs init echo record author me > _darcs/prefs/defaults echo ALL all >> _darcs/prefs/defaults #echo ALL verbose >> _darcs/prefs/defaults echo ALL ignore-times >> _darcs/prefs/defaults echo Old > foo darcs add foo darcs record -m Old cd .. cd tempA darcs init cp ../fooOld/_darcs/prefs/defaults _darcs/prefs darcs pull ../fooOld echo A > foo darcs record -m AA cd .. cd tempB darcs init cp ../fooOld/_darcs/prefs/defaults _darcs/prefs darcs pull ../fooOld echo B > foo darcs record -m BB darcs pull ../tempA echo A > foo darcs record -m "ok A's fine." cd .. # At this point, tempB and tempA should agree--since the conflict was # resolved in favor of tempA. cmp tempB/foo tempA/foo cd tempA echo AA > foo darcs record -m "AA -- upping the ante." cd .. cd tempB darcs pull ../tempA cd .. cd tempA darcs pull ../tempB cd .. # At this point, tempB and tempA should agree since we have pulled both ways. cmp tempB/foo tempA/foo darcs-2.8.4/tests/merging_newlines.sh0000644001765600176560000000134612104371431017177 0ustar ganeshganesh#!/usr/bin/env bash # trick: requiring something to fail . lib # A test for darcs detecting a conflict, inspired by bug #152 in RT rm -rf temp1 temp2 # set up the repository mkdir temp1 cd temp1 darcs init cd .. cd temp1 echo "apply allow-conflicts" > _darcs/prefs/defaults # note: to make this pass, change echo to echo -n # is that right? echo "from temp1" > one.txt darcs add one.txt darcs record -A bar -am "add one.txt" echo >> one.txt darcs wh -u cd .. darcs get temp1 temp2 cd temp2 # reality check darcs show files | grep one.txt echo "in tmp2" >> one.txt darcs whatsnew -s | grep M darcs record -A bar -am "add extra line" darcs annotate -p . -u darcs push -av > log cat log not grep -i conflicts log cd .. rm -rf temp1 temp2 darcs-2.8.4/tests/mutex-option-precedence.sh0000644001765600176560000000335312104371431020406 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issueNNNN - with mutually exclusive options "ALL foo" and ## "bar no-foo", "darcs bar" should mean "darcs bar --no-foo". ## ## Copyright (C) 2009 Trent W. Buck ## ## 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. . ../tests/lib # Load some portability helpers. rm -rf R # Another script may have left a mess. darcs init --repo R # Create our test repo. darcs init --repo S # Create our test repos. cd R echo 'Example content.' >f # Change the working tree. darcs record -lam 'Add f.' darcs send -aof.dpatch ../S darcs obl -a cat >>_darcs/prefs/defaults <&1 | grep "already exists" # case sensitivity series # ----------------------- # these are tests designed to check out darcs behave wrt to renames # where the case of the file becomes important # are we on a case sensitive file system? touch is_it_cs rm -f IS_IT_CS if test -e is_it_cs; then echo This is a case-sensitive file system. else echo This is NOT a case-sensitive file system. fi # if the new file already exists - we don't allow it # basically the same test as mv ping pong, except we do mv ping PING # and both ping and PING exist on the filesystem echo "case sensitivity - simply don't allow mv if new file exists" touch 'cs-n-1'; touch 'CS-N-1'; touch 'cs-y-1'; touch 'CS-Y-1'; darcs add cs-n-1 cs-y-1 if test -e is_it_cs; then # regardless of case-ok, we do NOT want this mv at all not darcs mv cs-n-1 CS-Y-1 2>&1 | grep "already exists" not darcs mv --case-ok cs-n-1 CS-Y-1 2>&1 | grep "already exists" fi # if the new file does not already exist - we allow it echo "case sensitivity - the new file does *not* exist" touch 'cs-n-2'; touch 'cs-y-2'; darcs add cs-n-2 cs-y-2 # these mv's should be allowed regardless of flag or filesystem darcs mv cs-n-2 CS-N-2 darcs mv --case-ok cs-y-2 CS-Y-2 # parasites - do not accidentally overwrite a file just because it has a # similar name and points to the same inode. We want to check if a file if the # same NAME already exists - we shouldn't care about what the actual file is! echo "case sensitivity - inode check"; touch 'cs-n-3'; touch 'cs-y-3'; darcs add cs-n-3 cs-y-3 if ln cs-n-3 CS-N-3; then # checking if we support hard links ln cs-y-3 CS-Y-3 # regardless of case-ok, we do NOT want this mv at all not darcs mv cs-n-3 CS-N-3 2>&1 | grep "already exists" not darcs mv --case-ok cs-y-3 CS-Y-3 2>&1 | grep "already exists" fi # parasites - we don't allow weird stuff like mv foo bar/foo just because # we opened up some crazy exception based on foo's name echo 'refuses to move to an existing file with same name, different path' touch 'cs-n-4'; touch 'foo.d/cs-n-4'; touch 'cs-y-4'; touch 'foo.d/cs-y-4'; darcs add cs-n-4 # regardless of case-ok, we do NOT want this mv at all not darcs mv cs-n-4 foo.d/cs-n-4 2>&1 | grep "already exists" not darcs mv --case-ok cs-y-4 foo.d/cs-y-4 2>&1 | grep "unadded" # --------------------------- # end case sensitivity series touch abs_path.t darcs add abs_path.t REPO_ABS=`pwd` darcs mv "$REPO_ABS/abs_path.t" abs_path_new.t darcs mv abs_path_new.t "$REPO_ABS/abs_path.t" # issue608 touch 'gonna_be_deleted'; darcs add gonna_be_deleted darcs record -am 'added doomed file' rm gonna_be_deleted darcs record -am 'deleted file' touch 'new_file'; darcs add new_file darcs mv new_file gonna_be_deleted darcs-2.8.4/tests/mv-test-suite.sh0000644001765600176560000000062412104371431016367 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp1 mkdir temp1 cd temp1 darcs init date > foo darcs record -a -m add_foo -A x --look-for-adds # add a test file echo 'test ! -e foo' > test.sh darcs add test.sh darcs record -a -m add_test darcs setpref test 'ls && bash test.sh' darcs record -a -m settest -A x --no-test darcs mv foo bar darcs record --debug -a -m mvfoo -A x darcs check cd .. rm -rf temp1 darcs-2.8.4/tests/mv_and_remove_tests.sh0000644001765600176560000000206012104371431017700 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp mkdir temp cd temp darcs init touch fee fi fo fum darcs add f* darcs record --author me --all --no-test --name add mkdir d darcs add d darcs mv f* d darcs remove d/fi cd d darcs remove fo echo let us have fun > fun darcs add fun darcs mv fun fum .. darcs record --author me --all --no-test --name mv cd .. if darcs show files | egrep '^./fee$'; then false; else true; fi test ! -f fee darcs show contents d/fee | cmp d/fee - test ! -f fi test -f d/fi if darcs show files | egrep '^./fi$'; then false; else true; fi if darcs show files | egrep '^./d/fi$'; then false; else true; fi test ! -f fo test -f d/fo if darcs show files | egrep '^./fo$'; then false; else true; fi if darcs show files | egrep '^./d/fo$'; then false; else true; fi darcs show contents fun | cmp fun - darcs show contents fum | cmp fum - darcs mv fun d darcs record -A me -a --no-test -m "fun again" darcs show content d/fun | cmp d/fun - test ! -f fun if darcs show files | egrep '^./fun$'; then false; else true; fi # Now clean up. cd .. rm -rf temp darcs-2.8.4/tests/mv_then_add.sh0000644001765600176560000000064512104371431016114 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp mkdir temp cd temp darcs init touch fee fi fo fum darcs add f* darcs record --author me --all --no-test --name add darcs mv fee foo touch fee darcs add fee darcs record --author me --all --no-test --name newfee darcs mv fi fib darcs record --author me --all --no-test --name mvfi date > fi darcs add fi darcs record --author me --all --no-test --name newfi cd .. rm -rf temp darcs-2.8.4/tests/nfs-failure.sh0000644001765600176560000000116712104371431016057 0ustar ganeshganesh#!/bin/sh set -ev rm -rf temp1 temp2 mkdir temp1 cd temp1 darcs init echo first > a darcs add a darcs record --pipe --all --name=first < b darcs add b darcs record --pipe --all --name=first < log grep -i 'missing argument' log cd .. mkdir -p temp2/one/two cd temp2/one/two # darcs push should work relative to the current directory darcs push -a ../../../temp1 | grep -i 'No recorded local changes to push' cd ../../../ # darcs push should push into repo specified with --repo cd temp2 darcs add one darcs record --name uno --all cd .. darcs push --repodir temp2 --all temp1 | grep -i 'Finished apply' cd temp1 # Before trying to pull from self, defaultrepo does not exist test ! -e _darcs/prefs/defaultrepo # return special message when you try to push to yourself not darcs push -a "$DIR`slash`temp1" 2> log grep -i "cannot push from repository to itself" log # and don't update the default repo to be the current dir test ! -e _darcs/prefs/defaultrepo cd .. rm -rf temp1 temp2 darcs-2.8.4/tests/obliterate-add.sh0000644001765600176560000000030012104371431016510 0ustar ganeshganesh#!/usr/bin/env bash . lib rm -rf temp1 mkdir temp1 cd temp1 darcs init echo foo > foo darcs add foo darcs record -a -m 'addfoo' darcs obliterate -a not darcs whatsnew cd .. rm -rf temp1 darcs-2.8.4/tests/obliterate.sh0000644001765600176560000000151712104371431015775 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf tempA mkdir tempA cd tempA darcs initialize echo hello world > foo darcs add foo darcs record -a -m hellofoo echo goodbye world >> foo darcs record -a -m goodbyefoo darcs replace world bar foo echo Hi there foo > bar darcs add bar darcs record -a -m addbar darcs mv bar baz darcs replace bar baz foo darcs record -a -m bar2baz echo Do not love the baz, or anything in the baz. >> foo darcs record -a -m nolove darcs mv baz world darcs replace baz world foo darcs record -a -m baz2world darcs whatsnew | grep 'No changes' grep 'love the world' foo echo y | darcs obliterate -p baz2world darcs whatsnew | grep 'No changes' grep 'love the baz' foo echo y | darcs obliterate -p bar2baz grep 'love the bar' foo echo y | darcs obliterate -p nolove grep 'love' foo && exit 1 || true cd .. rm -rf tempA darcs-2.8.4/tests/obliterate-formerly-pl.sh0000644001765600176560000000121412104371431020235 0ustar ganeshganesh#!/usr/bin/env bash # Some tests for 'darcs obliterate' . lib rm -rf temp1 # set up the repository mkdir temp1 cd temp1 darcs init cd .. cd temp1 touch a.txt darcs add a.txt darcs record -a -m 'adding a' a.txt touch b.txt darcs add b.txt darcs record -a -m 'adding b' b.txt # extra confirmation for --all echo an | darcs obliterate -p add | grep -i "really obliterate" # --last=1 echo n | darcs obliterate --last 1 | grep -i adding # automatically getting dependencies date >> a.txt darcs record -a -m 'modifying a' a.txt echo n | darcs obliterate -p 'adding a' > log grep -i "modifying a" log grep -i "No patches selected" log cd .. rm -rf temp1 darcs-2.8.4/tests/optimize.sh0000644001765600176560000000035312104371431015500 0ustar ganeshganesh#!/usr/bin/env bash set -ev # tests for "darcs optimize" rm -rf temp1 mkdir temp1 cd temp1 darcs init touch foo darcs add foo darcs record -a -m add_foo darcs optimize --reorder-patches| grep -i "done optimizing" cd .. rm -rf temp1 darcs-2.8.4/tests/prefs.sh0000644001765600176560000000053012104371431014754 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp1 temp2 mkdir temp1 cd temp1 darcs initialize echo ALL ignore-times >> _darcs/prefs/defaults cp _darcs/prefs/boring .boring darcs add .boring darcs setpref boringfile .boring darcs record -a -m p1 -A me cd .. darcs get temp1 temp2 cmp temp1/_darcs/prefs/prefs temp2/_darcs/prefs/prefs rm -rf temp1 temp2 darcs-2.8.4/tests/oldfashioned_refusal.sh0000644001765600176560000000343612104371431020025 0ustar ganeshganesh#!/usr/bin/env bash ## Test that darcs refuses to work on old-fashioned repositories ## for certain commands. ## ## Copyright (C) 2011 Guillaume Hoffmann ## ## 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. . lib # Load some portability helpers. rm -rf old gunzip -c $TESTDATA/many-files--old-fashioned-inventory.tgz | tar xf - mv many-files--old-fashioned-inventory old cd old not darcs add not darcs amend not darcs annotate not darcs apply not darcs check not darcs diff not darcs dist not darcs mark not darcs move not darcs pull not darcs push not darcs put not darcs record not darcs remove not darcs repair not darcs replace not darcs revert not darcs rollback not darcs send not darcs setpref not darcs tag not darcs trackdown not darcs unrecord not darcs unrevert darcs-2.8.4/tests/output.sh0000644001765600176560000000233212104371431015177 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp1 temp2 temp3 mkdir temp2 cd temp2 darcs init cd .. mkdir temp1 cd temp1 darcs init touch foo bar darcs add foo bar darcs record -a -m foobar -A author darcs send -a --dont-edit-description -o ../temp3 ../temp2 test -f ../temp3 darcs send -a --dont-edit-description -o ../temp2/patchfile ../temp2 test -f ../temp2/patchfile mkdir subdir darcs send -a --dont-edit-description -o subdir/../../temp2/patchfile1 ../temp2 test -f ../temp2/patchfile1 cp ../temp3 correct cd subdir darcs send -a --dont-edit-description -o ../patchfile ../../temp2 diff -u ../patchfile ../correct rm ../patchfile darcs send -a --set-default --dont-edit-description -o - ../../temp2 > ../patchfile grep -v Creating ../patchfile | diff -u ../correct - darcs apply --repodir=../../temp2 --dry-run ../patchfile > out cat out grep foobar out cd ../.. cd temp2 darcs apply --dry-run ../temp3 > out cat out grep foobar out darcs apply --dry-run ../temp1/correct > out cat out grep foobar out darcs apply --dry-run ../temp1/patchfile > out cat out grep foobar out darcs apply --dry-run ../temp3 > out cat out grep foobar out darcs apply --dry-run ../temp3 > out cat out grep foobar out cd .. rm -rf temp1 temp2 temp3 darcs-2.8.4/tests/oldfashioned_support.sh0000644001765600176560000000305712104371431020077 0ustar ganeshganesh#!/usr/bin/env bash ## Test that darcs can get, pull and send (from, to) a remote ## old-fashioned repository. ## ## Copyright (C) 2011 Guillaume Hoffmann ## ## 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. . lib # Load some portability helpers. rm -rf old hashed gunzip -c $TESTDATA/many-files--old-fashioned-inventory.tgz | tar xf - mv many-files--old-fashioned-inventory old darcs get old hashed cd hashed echo "yyyd" | darcs unpull darcs pull -a touch tralala darcs add tralala darcs rec -am "patch to be sent" darcs send -aO darcs-2.8.4/tests/optimize_relink.sh0000644001765600176560000000252112104371431017043 0ustar ganeshganesh #!/usr/bin/env bash # For issue600, testing optimize --relink set -ev ## We don't support hard links on Windows. if echo $OS | grep -i windows; then echo darcs does not support hard links on Windows exit 0 fi ## compare succeeds if there are hard links compare () { echo 'use File::Basename; $res=0; while ($fn=<'$1'/*>) { $fn2="'$2'/" . basename($fn); @fd1=lstat($fn); @fd2=lstat($fn2); $res += ($fd1[1] != $fd2[1]);}; exit($res);' | perl } rm -rf temp mkdir temp cd temp mkdir x darcs init --repodir x cd x date > foo darcs add foo darcs record -a -A me -m 'addfoo' cd .. ## Does the filesystem support hard linking at all? mkdir z1 echo "hi" > z1/foo mkdir z2 if ! ln z1/foo z2/foo ; then echo No ln command for `pwd` - assuming no hard links. exit 0 fi if ! compare z1 z2 ; then echo Filesystem for `pwd` does not support hard links. exit 0 fi # workaround for SunOS cp which does not support `-a' option but also # doesn't fail when it is encountered. cp -r x y ## Now try relinking using darcs. rm -rf z darcs optimize --verbose --relink --repodir x --sibling y rm -rf x/_darcs/patches/pend* y/_darcs/patches/pend* if compare x/_darcs/patches y/_darcs/patches then echo darcs --relink is working, hard links were done. else echo darcs --relink is not working, it did not make any hard links. exit 2 fi cd .. rm -rf temp darcs-2.8.4/tests/pending.sh0000644001765600176560000000106212104371431015262 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp temp_0 mkdir temp cd temp darcs init date > bla darcs add bla darcs record -a --name=11 echo hello > world darcs add world darcs whatsnew --dont-look-for-adds > wn1 cd .. darcs get temp cd temp_0 date > bla2 date >> bla darcs add bla2 darcs record -a --name=22 darcs push -a ../temp cd .. cd temp darcs whatsnew --dont-look-for-adds > wn2 diff wn1 wn2 darcs record -a -m 'cleaning up for new test.' date > foo.jpg darcs add foo.jpg darcs whatsnew darcs remove foo.jpg darcs whatsnew && exit 1 cd .. rm -rf temp temp0 darcs-2.8.4/tests/overriding-defaults.sh0000644001765600176560000000250012104371431017611 0ustar ganeshganesh#!/usr/bin/env bash . lib rm -rf temp mkdir temp cd temp darcs init darcs setpref test false darcs record --no-test -a -m 'add failing test' # should pass with --no-test darcs check --no-test # should fail when test is run not darcs check --test # should pass with --no-test in defaults echo check --no-test > _darcs/prefs/defaults darcs check not darcs check --test # should fail with --test in defaults echo check --test > _darcs/prefs/defaults not darcs check darcs check --no-test # check global defaults cp ~/.darcs/defaults defaults.backup trap "cp defaults.backup ~/.darcs/defaults" EXIT rm _darcs/prefs/defaults # --no-test works in global defaults echo check --no-test > ~/.darcs/defaults darcs check not darcs check --test # --test works in global defaults echo check --test > ~/.darcs/defaults not darcs check darcs check --no-test # Verify that per-repository defaults override global defaults # --no-test in repository defaults overrides global --test echo check --test > ~/.darcs/defaults echo check --no-test > _darcs/prefs/defaults darcs check not darcs check --test # --test in repository defaults overrides global --no-test echo check --no-test > ~/.darcs/defaults echo check --test > _darcs/prefs/defaults not darcs check darcs check --no-test trap - EXIT cp defaults.backup ~/.darcs/defaults cd .. rm -rf temp darcs-2.8.4/tests/posthook.sh0000644001765600176560000000223512104371431015507 0ustar ganeshganesh#!/usr/bin/env bash set -ev . lib rm -rf temp1 mkdir temp1 cd temp1 darcs init touch foo darcs add foo # Check that posthook works... darcs whatsnew -s --posthook 'touch posthook-ran' test -f posthook-ran rm posthook-ran # Check that posthook works with defaults... echo ALL --posthook touch posthook-ran > _darcs/prefs/defaults darcs whatsnew -s test -f posthook-ran rm posthook-ran cd .. rm -rf temp1 # POSIX-only section # ---------------------------------------------------------------------- # Things below this section do not appear to work on Windows. # Pending further investigation at http://bugs.darcs.net/issue1813 if echo $OS | grep -i windows; then exit 0 fi # Check that DARCS_PATCHES_XML works rm -rf R S # another script may have left a mess darcs init --repo R # Create our test repos. darcs init --repo S # Create our test repos. cd R echo 'echo $DARCS_PATCHES_XML' > hook darcs record -lam 'hook' chmod u+x hook cat > _darcs/prefs/defaults << END apply run-posthook apply posthook ./hook END cd .. cd S echo 'Example content.' > f darcs record -lam 'Add f' darcs push -a ../R | grep 'patch author' cd .. darcs-2.8.4/tests/pull.sh0000644001765600176560000000670412104371431014622 0ustar ganeshganesh#!/usr/bin/env bash . lib rm -rf temp1 temp2 mkdir temp1 cd temp1 darcs init cd .. mkdir temp2 cd temp2 darcs init mkdir one cd one mkdir two cd two echo darcs pull should work relative to the current directory darcs pull -a ../../../temp1 | grep -i 'No remote changes to pull in' echo -- darcs pull should pull into repo specified with --repo cd ../.. # now in temp2 darcs add one; darcs record --name uno --all cd .. # now outside of any repo darcs pull --set-default --repodir temp1 --all temp2 | grep -i 'Finished pulling.' # temp2 is not relative to temp1 # set up server repo date > temp2/one/date.t darcs add --repodir ./temp2 one/date.t darcs record --repodir ./temp2 -a -m foo # set up client repo for failure if echo $OS | grep -i windows; then echo this test does not work on windows because it echo is not possible to chmod -r elif whoami | grep root; then echo root never gets permission denied else chmod a-rwx ./temp1/one # remove all permissions not darcs pull --repodir ./temp1 -a 2> err chmod u+rwx temp1/one # restore permission cat err grep 'permission denied' err rm -rf temp1/one fi cd temp1 echo Before trying to pull from self, defaultrepo is something else not grep temp1 _darcs/prefs/defaultrepo #return special message when you try to pull from yourself DIR="`pwd`" not darcs pull --debug -a "$DIR" 2> out cat out grep 'Can.t pull from current repository' out not darcs pull --debug -a . 2> out cat out grep 'Can.t pull from current repository' out # and do not update the default repo to be the current di not grep temp1 _darcs/prefs/defaultrepo rm -f _darcs/prefs/defaultrepo not darcs pull 2> err grep 'please specify one' err echo . > _darcs/prefs/defaultrepo not darcs pull --debug 2> err grep 'Can.t pull from current repository' err not darcs pull --debug ../* 2> out cat out not grep 'Can.t pull from current repository' out cd .. # now outside of any repo cd temp1 echo a > foo darcs record -lam AA echo b > foo darcs record -lam BB echo c > foo darcs record -lam CC darcs rollback -p CC -a -m unC cd .. rm -rf temp2 darcs get --to-patch B temp1 temp2 cd temp2 sleep 1 # So that rollback won't have same timestamp as get. darcs rollback -p BB -a -m unB darcs revert -a darcs pull -a ../temp1 2> err2 not grep 'Error applying patch' err2 cd .. cd temp1 echo -n foo > baz darcs add baz darcs record -am newbaz cd ../temp2 darcs pull -a | grep Finished echo -n bar > baz darcs record -am bazbar cd ../temp1 darcs pull ../temp2 -a echo -n bar > correct_baz diff baz correct_baz cd .. # my $test_name = "when a patch creating a directory is attempted to be applied # while a directory with that name already exists, a warning is raised, but # the pull succeeds."; mkdir temp1/newdir cd temp1 darcs add newdir darcs record -am newdir cd ../temp2 mkdir newdir darcs pull -a --set-default ../temp1 &> out2 cat out grep Backing out2 grep 'Finished pulling' out2 grep newdir out2 cd .. rm -rf temp1 temp2 # A test for issue662, which triggered: # darcs failed: Error applying hunk to file ./t.t # Error applying patch to the working directory. rm -rf tmp; darcs init --hashed --repodir=tmp touch tmp/t.t cd tmp darcs add t.t echo 'content'>t.t darcs record -am 'initial add' --ignore echo 'content: remote change'>t.t darcs record -am 'remote change' --ignore darcs put tmp2 cd tmp2 darcs obliterate --last 1 --all; echo 'content: local change'> t.t darcs pull -a ../ darcs w -s darcs revert -a cd ../.. rm -rf tmp darcs-2.8.4/tests/prehook.sh0000644001765600176560000000063112104371431015306 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp1 mkdir temp1 cd temp1 darcs init touch foo darcs add foo # Check that prehook runs darcs whatsnew -s --prehook 'touch prehook-ran' test -f prehook-ran rm prehook-ran # Check that --prehook works with defaults... echo ALL --prehook touch prehook-ran > _darcs/prefs/defaults darcs whatsnew -s test -f prehook-ran rm prehook-ran echo Successful. cd .. rm -rf temp1 darcs-2.8.4/tests/pending_has_conflicts.sh0000644001765600176560000000162712104371431020170 0ustar ganeshganesh#!/usr/bin/env bash . lib rm -rf temp1 mkdir temp1 cd temp1 darcs init date > date.t date > date_moved.t write_buggy_pending () { cat > _darcs/patches/pending <&1 | tee out grep 'pending has conflicts' out echo pending should now be fixed but there are no changes not darcs whatsnew write_buggy_pending darcs revert -a 2>&1 | tee out grep 'pending has conflicts' out echo pending should now be emptied darcs revert -a write_buggy_pending not darcs record -a -m foo 2>&1 | tee out grep 'pending has conflicts' out darcs changes -v darcs repair 2>&1 | tee out grep 'The repository is already consistent' out write_buggy_pending darcs repair 2>&1 | tee out grep 'The repository is already consistent' out cd .. rm -rf temp1 darcs-2.8.4/tests/prefs_binary.sh0000644001765600176560000000065212104371431016325 0ustar ganeshganesh#!/usr/bin/env bash # Test that _darcs/prefs/binaries . lib rm -rf temp1 mkdir temp1 cd temp1 darcs init mkdir d touch d/t.t darcs add d/t.t darcs record -am "initial record" echo 'some change' >> d/t.t echo n | darcs record --interactive > log # pre-test: plain text files are not binary not grep binary log echo 'd/t' >> _darcs/prefs/binaries echo n | darcs record --interactive > log grep binary log cd .. rm -rf temp1 darcs-2.8.4/tests/printer.sh0000644001765600176560000001035312104371431015324 0ustar ganeshganesh#!/usr/bin/env bash # Some tests for 'darcs printer (the output formating)' . lib rm -rf temp1 mkdir temp1 cd temp1 darcs init touch a darcs add a darcs rec -a -m add env # clear all output formating environment variables for e in DARCS_DONT_ESCAPE_ISPRINT DARCS_USE_ISPRINT\ DARCS_DONT_ESCAPE_8BIT\ DARCS_DONT_ESCAPE_EXTRA DARCS_ESCAPE_EXTRA\ DARCS_DONT_ESCAPE_TRAILING_SPACES\ DARCS_DONT_COLOR DARCS_ALWAYS_COLOR DARCS_ALTERNATIVE_COLOR\ DARCS_DONT_ESCAPE_ANYTHING; do unset $e done env # make sure the locale is c export LC_ALL=C test_line () { rm -f a echo $1 > a darcs whatsnew | fgrep $2 } # First check escaping and coloring. Use whatsnew, since that is the # most common use of escapes. # test the defaults # - no color to pipe # - don't escape 7-bit ASCII printables, \n,\t and space (we can't test \n) # - escape control chars with ^ # - escape other chars with \xXX test_line " !#%&',-0123456789:;<=>"\ " !#%&',-0123456789:;<=>" test_line "ABCDEFGHIJKLMNOPQRSTUVWXYZ_"\ "ABCDEFGHIJKLMNOPQRSTUVWXYZ_" test_line "\`abcdefghijklmnopqrstuvwxyz"\ "\`abcdefghijklmnopqrstuvwxyz" test_line "\t\"\$()*+./?\@[\\]^{|}"\ "\t\"\$()*+./?\@[\\]^{|}" # skip ^@ and ^Z since they make darcs treat the file as binary # don't put any space control chars at end of line # ascii control chars are escaped with ^ test_line $(printf '\x01\x02\x03\x04\x05\x06\x07\x08\x0B\x0C\x0D\x0E')\ '[_^A_][_^B_][_^C_][_^D_][_^E_][_^F_][_^G_][_^H_][_^K_][_^L_][_^M_][_^N_]' test_line $(printf '\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19')\ '[_^O_][_^P_][_^Q_][_^R_][_^S_][_^T_][_^U_][_^V_][_^W_][_^X_][_^Y_]' test_line $(printf '\x1B') '[_^[_]' test_line $(printf '\x1C') '[_^\_]' test_line $(printf '\x1D') '[_^]_]' test_line $(printf '\x1E') '[_^^_]' test_line $(printf '\x1F') '[_^__]' test_line $(printf '\x7F') '[_^?_]' # other chars are escaped with test_line $(printf '\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F')\ '[__][__][__][__][__][__][__][__][__][__][__][__][__][__][__][__]' test_line $(printf '\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9A\x9B\x9C\x9D\x9E\x9F')\ '[__][__][__][__][__][__][__][__][__][__][__][__][__][__][__][__]' test_line $(printf '\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xAA\xAB\xAC\xAD\xAE\xAF')\ '[__][__][__][__][__][__][__][__][__][__][__][__][__][__][__][__]' test_line $(printf '\xB0\xB1\xB2\xB3\xB4\xB5\xB6\xB7\xB8\xB9\xBA\xBB\xBC\xBD\xBE\xBF')\ '[__][__][__][__][__][__][__][__][__][__][__][__][__][__][__][__]' test_line $(printf '\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF')\ '[__][__][__][__][__][__][__][__][__][__][__][__][__][__][__][__]' test_line $(printf '\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD7\xD8\xD9\xDA\xDB\xDC\xDD\xDE\xDF')\ '[__][__][__][__][__][__][__][__][__][__][__][__][__][__][__][__]' test_line $(printf '\xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF')\ '[__][__][__][__][__][__][__][__][__][__][__][__][__][__][__][__]' test_line $(printf '\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF')\ '[__][__][__][__][__][__][__][__][__][__][__][__][__][__][__][__]' rm -rf temp1 darcs-2.8.4/tests/pull-union.sh0000644001765600176560000000077212104371431015747 0ustar ganeshganesh#!/usr/bin/env bash . lib # This test script is in the public domain. rm -rf temp1 temp2 temp3 mkdir temp1 cd temp1 darcs initialize echo A > A darcs add A darcs record -a -m A echo B > B darcs add B darcs record -a -m B cd .. darcs get temp1 temp2 cd temp2 darcs obliterate --last 1 -a echo C > C darcs add C darcs record -a -m C cd .. mkdir temp3 cd temp3 darcs init darcs pull -a -v ../temp1 ../temp2 darcs changes > out cat out grep A out grep B out grep C out cd .. rm -rf temp1 temp2 temp3 darcs-2.8.4/tests/pull-dont-prompt-deps.sh0000644001765600176560000000133212104371431020024 0ustar ganeshganesh#!/usr/bin/env bash set -ev # Check that the right patches get pulled using --dont-prompt-for-dependencies rm -rf temp1 rm -rf temp2 mkdir temp2 mkdir temp1 cd temp2 darcs init cd .. cd temp1 darcs init echo foo > f darcs record -Ax -alm foo1 echo bar > b darcs rec -Ax -alm bar1 echo foo2 > f darcs record -Ax -alm foo2 echo bar2 > b darcs record -Ax -alm bar2 cd ../temp2 echo y | darcs pull ../temp1 -i --dont-prompt-for-dependencies -p foo2 --dry-run > toto #on the previous line, we get asked about foo2, and we take it grep foo2 toto | wc -l | grep 2 #we don't get asked about foo1, but we take it anyway, so grep foo1 toto | wc -l | grep 1 #and we don't send bar grep bar toto | wc -l | grep 0 cd .. rm -rf temp1 temp2 darcs-2.8.4/tests/pull_binary.sh0000644001765600176560000000311412104371431016156 0ustar ganeshganesh#!/usr/bin/env bash # This test script, originally written by David Roundy and Ian Lynagh is in # the public domain. # # This file is included as part of the Darcs test distribution, # which is licensed to you under the following terms: # ## 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. set -ev rm -rf temp1 temp2 mkdir temp1 cd temp1 darcs init printf "%01048576d" 0 > foo darcs record -l -a -A author -m xx rm foo darcs record -a -A author -m yy cd .. mkdir temp2 cd temp2 darcs init echo yn | darcs pull --set-default ../temp1 rm foo darcs pull -a cd .. rm -rf temp1 temp2 darcs-2.8.4/tests/pull_compl.sh0000644001765600176560000000724712104371431016017 0ustar ganeshganesh#!/usr/bin/env bash ## Public domain 2007 Kevin Quick ## ## This file is included as part of the Darcs test distribution, ## which is licensed to you under the following terms: ## ## 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. set -ev rm -rf temp1 temp2 temp3 temp4 temp5 mkdir temp1 cd temp1 cat > foo < foo.tmp mv foo.tmp foo darcs record -a --ignore-times -m "$2" } cd temp1 chgrec 's/line2/line2\nline2.1\nline2.2/' inssub2 chgrec 's/line4/Line 4/' Line4 darcs changes | grep ' \*' echo done with changes on temp1 > /dev/null cd .. darcs get temp1 temp2 darcs get temp1 temp3 cd temp1 chgrec 's/line1/line0\nline1/' line0 chgrec 's/Line 4/LINE FOUR/' LINE4 chgrec 's/line7/line7\nLastLine/' LastLine chgrec 's/LINE FOUR/LINE FOUR\nline4.1/' line4.1 darcs changes | grep ' \*' echo done with changes on temp1 > /dev/null cd ../temp3 darcs pull -p LastLine -av chgrec 's/line1$/FirstLine/' FirstLine cd ../temp4 darcs changes | grep ' \*' echo done with changes on temp4 > /dev/null darcs pull ../temp1 --dry-run | grep ' \*' darcs pull ../temp1 --dry-run | grep ' \*' > p1.out cat > p1.req < p2.out diff p1.out p2.out darcs pull --dry-run --complement ../temp1 ../temp2 | grep ' \*' > p3.out cat > p3.req < p4.out cat > p4.req < p5.out diff p4.out p5.out darcs pull --dry-run --complement ../temp1 ../temp2 ../temp3 ../temp2 ../temp2 ../temp3 ../temp3 ../temp2 | grep ' \*' > p6.out diff p4.out p6.out darcs pull --dry-run --complement ../temp3 ../temp2 | grep ' \*' > p7.out cat > p7.req < p8.out grep "No remote changes to pull in!" p8.out # because duplicates are stripped before performing action, # this is the same as: darcs pull ../temp1 darcs pull --dry-run --complement ../temp1 ../temp1 > fooout cat fooout grep ' \*' fooout > p9.out diff p1.req p9.out # so the "null" pull must be tested this way: darcs get ../temp1 ../temp5 darcs pull --dry-run --complement ../temp1 ../temp5 > p9.out grep "No remote changes to pull in!" p9.out darcs pull -av --complement ../temp1 ../temp3 darcs check cd .. rm -rf temp1 temp2 temp3 temp4 temp5 darcs-2.8.4/tests/pull_conflicts.sh0000644001765600176560000000335412104371431016664 0ustar ganeshganesh#!/usr/bin/env bash ## Test that pull --skip-conflicts filters the conflicts ## appropriately. ## ## Copyright (C) 2009 Ganesh Sittampalam ## ## 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. . lib # Load some portability helpers. rm -rf R S # Another script may have left a mess. mkdir R cd R darcs init echo 'foo' > foo echo 'bar' > bar darcs rec -lam 'Add foo and bar' cd .. darcs get R S cd R echo 'foo2' > foo darcs rec -lam 'Change foo (2)' echo 'bar2' > bar darcs rec -lam 'Change bar (2)' cd .. cd S echo 'foo3' > foo darcs rec -lam 'Change foo (3)' darcs pull --skip-conflicts -a ../R test `darcs changes --count` -eq 3 cd .. cd S darcs pull -a ../R test `darcs changes --count` -eq 4 cd .. darcs-2.8.4/tests/pull_many_files.sh0000644001765600176560000000073512104371431017026 0ustar ganeshganesh#!/usr/bin/env bash . lib rm -rf temp1 temp2 if grep old-fashioned .darcs/defaults; then format=old-fashioned-inventory elif grep darcs-2 .darcs/defaults; then format=darcs-2 else format=hashed; fi mkdir temp2 cd temp2 gunzip -c $TESTDATA/many-files--${format}.tgz | tar xf - cd .. mkdir temp1 cd temp1 darcs init darcs pull -a ../temp2/many-files--${format} > log grep -i 'finished pulling' log cd .. rm -rf temp1 # put things back how we found them. rm -rf temp1 temp2 darcs-2.8.4/tests/pull_two.sh0000644001765600176560000000073012104371431015504 0ustar ganeshganesh#!/usr/bin/env bash # This test script, originally written by David Roundy is in the public # domain. set -ev rm -rf temp1 temp2 mkdir temp1 cd temp1 echo foo > bar darcs initialize echo record author me > _darcs/prefs/defaults darcs add bar darcs record -a -m addbar cd .. darcs get temp1 temp2 cd temp1 date > bar darcs record -a -m datebar cd ../temp1 echo aack >> bar darcs record -a -m aackbar cd ../temp2 darcs pull -av darcs check cd .. rm -rf temp1 temp2 darcs-2.8.4/tests/push-dry-run.sh0000644001765600176560000000104212104371431016211 0ustar ganeshganesh#!/usr/bin/env bash set -ev # For issue855: wish: avoid taking lock if using --dry-run chmod -R u+w temp2 || : rm -rf temp1 temp2 mkdir temp1 cd temp1 darcs init cd .. mkdir temp2 cd temp2 darcs init touch x darcs add x darcs record -am "test" cd .. chmod -R u-w temp2 cd temp2 # need to capture this failure so that we can still # chmod -R u+w the directory even if we fail darcsexit=0 darcs push --dry-run ../temp1 || darcsexit=$? cd .. chmod -R u+w temp2 # so that other scripts can cleanup if [ $darcsexit -ne 0 ]; then exit $darcsexit fi darcs-2.8.4/tests/push-dont-prompt-deps.sh0000644001765600176560000000131612104371431020031 0ustar ganeshganesh#!/usr/bin/env bash set -ev # Check that the right patches get pushed using --dont-prompt-for-dependencies rm -rf temp1 rm -rf temp2 mkdir temp2 mkdir temp1 cd temp2 darcs init cd .. cd temp1 darcs init echo foo > f darcs record -Ax -alm foo1 echo bar > b darcs rec -Ax -alm bar1 echo foo2 > f darcs record -Ax -alm foo2 echo bar2 > b darcs record -Ax -alm bar2 echo y | darcs push ../temp2 --dont-prompt-for-dependencies -p foo2 --dry-run -i > toto #on the previous line, we get asked about foo2, and we take it grep foo2 toto | wc -l | grep 2 #we don't get asked about foo1, but we take it anyway, so grep foo1 toto | wc -l | grep 1 #and we don't send bar grep bar toto | wc -l | grep 0 cd .. rm -rf temp1 temp2 darcs-2.8.4/tests/push_lock.sh0000644001765600176560000000064012104371431015626 0ustar ganeshganesh#!/usr/bin/env bash # For issue257: push => incorrect return code when couldn't get lock set -ev rm -rf tempc mkdir tempc cd tempc darcs init echo foo > foo.c darcs rec -Ax -alm init cd .. rm -rf temps darcs get tempc temps cd temps echo server >> foo.c darcs rec -Ax -alm server cd ../tempc echo client >> foo.c darcs rec -Ax -alm client if darcs push -a ../temps; then false fi cd .. rm -rf tempc temps darcs-2.8.4/tests/push.sh0000644001765600176560000000044712104371431014623 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp temp_0 mkdir temp cd temp darcs init echo tester > _darcs/prefs/author date > bla darcs add bla darcs record -a --name=11 cd .. darcs get temp cd temp date > bla2 darcs add bla2 darcs record -a --name=22 darcs push -a ../temp_0 cd .. rm -rf temp temp_0 darcs-2.8.4/tests/rmdir-formerly-pl.sh0000644001765600176560000000117012104371431017221 0ustar ganeshganesh#!/usr/bin/env bash . lib rm -rf temp1 mkdir temp1 cd temp1 darcs init mkdir foo echo hello world > foo/bar echo hello world > foo/baz mkdir foo/dir darcs add foo foo/bar foo/dir foo/baz darcs record -a -m add rm -rf foo darcs show files --no-pending --no-dir > log grep 'foo/baz' log grep 'foo/bar' log darcs show files --no-pending --no-fil > log grep 'foo/dir' log grep 'foo$' log # now without... darcs record -a -m del darcs show files --no-pending --no-dir > log not grep 'foo/baz' log not grep 'foo/bar' log darcs show files --no-pending --no-fil > log not grep 'foo/dir' log not grep 'foo$' log cd .. rm -rf temp1 darcs-2.8.4/tests/push_conflicts.sh0000644001765600176560000000336512104371431016671 0ustar ganeshganesh#!/usr/bin/env bash ## Test that apply --skip-conflicts filters the conflicts ## appropriately. ## ## Copyright (C) 2009 Ganesh Sittampalam ## ## 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. . lib # Load some portability helpers. rm -rf R S # Another script may have left a mess. mkdir R cd R darcs init echo 'foo' > foo echo 'bar' > bar darcs rec -lam 'Add foo and bar' cd .. darcs get R S cd R echo 'foo2' > foo darcs rec -lam 'Change foo (2)' echo 'bar2' > bar darcs rec -lam 'Change bar (2)' cd .. cd S echo 'foo3' > foo darcs rec -lam 'Change foo (3)' cd .. cd R darcs send -a ../S -o ../S/applyme.dpatch cd .. cd S darcs apply --skip-conflicts applyme.dpatch test `darcs changes --count` -eq 3 cd .. darcs-2.8.4/tests/put.sh0000644001765600176560000000100412104371431014442 0ustar ganeshganesh#!/usr/bin/env bash . lib rm -rf temp1 temp2 mkdir temp1 cd temp1 darcs init cd .. # put should not set default repo cd temp1 touch 1.txt darcs add 1.txt darcs record -a -m foo 1.txt darcs put ../temp2 test ! -e _darcs/prefs/defaultrepo cd .. # put to self cd temp1 not grep temp1 _darcs/prefs/defaultrepo DIR=`pwd` # return special message when you try to put put yourself not darcs put "$DIR" 2> log not grep temp1 _darcs/prefs/defaultrepo grep -i "Can't put.*current repository" log cd .. rm -rf temp1 temp2 darcs-2.8.4/tests/query_manifest.sh0000644001765600176560000000551412104371431016677 0ustar ganeshganesh#!/usr/bin/env bash set -ev check_manifest () { : > files.tmp echo . > dirs.tmp echo . > files-dirs.tmp for x in $1 ; do echo "./$x" >> files.tmp echo "./$x" >> files-dirs.tmp done for x in $2 ; do echo "./$x" >> dirs.tmp echo "./$x" >> files-dirs.tmp done darcs query manifest $3 --files --no-directories > darcsraw-files.tmp darcs query manifest $3 --no-files --directories > darcsraw-dirs.tmp darcs query manifest $3 --files --directories > darcsraw-files-dirs.tmp for x in files dirs files-dirs ; do sort $x.tmp | sed -e 's,\\,/,' > expected-$x.tmp sort darcsraw-$x.tmp | sed -e 's,\\,/,' > darcs-$x.tmp diff -u expected-$x.tmp darcs-$x.tmp done } rm -rf temp mkdir temp cd temp darcs init check_manifest "" "" "--no-pending" check_manifest "" "" "--pending" touch a b darcs add a check_manifest "" "" "--no-pending" check_manifest "a" "" "--pending" darcs add b mkdir c check_manifest "" "" "--no-pending" check_manifest "a b" "" "--pending" darcs add c touch c/1 c/2 check_manifest "" "" "--no-pending" check_manifest "a b" "c" "--pending" darcs add c/1 c/2 check_manifest "" "" "--no-pending" check_manifest "a b c/1 c/2" "c" "--pending" mkdir d touch d/3 d/4 darcs add d/3 d/4 check_manifest "" "" "--no-pending" check_manifest "a b c/1 c/2 d/3 d/4" "c d" "--pending" darcs record -A test --all --name "patch 1" --skip-long-comment check_manifest "a b c/1 c/2 d/3 d/4" "c d" "--no-pending" check_manifest "a b c/1 c/2 d/3 d/4" "c d" "--pending" darcs mv d e check_manifest "a b c/1 c/2 d/3 d/4" "c d" "--no-pending" check_manifest "a b c/1 c/2 e/3 e/4" "c e" "--pending" rm c/1 check_manifest "a b c/1 c/2 d/3 d/4" "c d" "--no-pending" check_manifest "a b c/1 c/2 e/3 e/4" "c e" "--pending" darcs remove c/1 check_manifest "a b c/1 c/2 d/3 d/4" "c d" "--no-pending" check_manifest "a b c/2 e/3 e/4" "c e" "--pending" darcs mv c/2 c/1 check_manifest "a b c/1 c/2 d/3 d/4" "c d" "--no-pending" check_manifest "a b c/1 e/3 e/4" "c e" "--pending" darcs record -A test --all --name "patch 2" --skip-long-comment check_manifest "a b c/1 e/3 e/4" "c e" "--no-pending" check_manifest "a b c/1 e/3 e/4" "c e" "--pending" darcs remove c/1 check_manifest "a b c/1 e/3 e/4" "c e" "--no-pending" check_manifest "a b e/3 e/4" "c e" "--pending" darcs remove c check_manifest "a b c/1 e/3 e/4" "c e" "--no-pending" check_manifest "a b e/3 e/4" "e" "--pending" darcs record -A test --all --name "patch 3" --skip-long-comment check_manifest "a b e/3 e/4" "e" "--no-pending" check_manifest "a b e/3 e/4" "e" "--pending" darcs mv b b2 darcs mv b2 b3 check_manifest "a b e/3 e/4" "e" "--no-pending" check_manifest "a b3 e/3 e/4" "e" "--pending" darcs record -A test --all --name "patch 3" --skip-long-comment check_manifest "a b3 e/3 e/4" "e" "--no-pending" check_manifest "a b3 e/3 e/4" "e" "--pending" cd .. rm -rf temp darcs-2.8.4/tests/record.sh0000644001765600176560000000251612104371431015121 0ustar ganeshganesh#!/usr/bin/env bash # Some tests for 'darcs record ' . lib rm -rf temp1 mkdir temp1 cd temp1 darcs init # issue308 - no patches and no deps for record should abort darcs record -am foo --ask-deps | grep -i "Ok, if you don't want to record anything, that's fine!" # RT#476 - --ask-deps works when there are no patches if echo $OS | grep -i windows; then echo This test does not work on Windows else touch t.f darcs add t.f darcs record -am add echo a | darcs record -am foo --ask-deps | grep -i 'finished recording' fi # RT#231 - special message is given for nonexistent directories not darcs record -am foo not_there.txt > log grep -i 'not exist' log # RT#231 - a nonexistent file before an existing file is handled correctly touch b.t darcs record -lam foo a.t b.t > log grep -i 'WARNING:.*a.t' log grep -iv 'WARNING:.*b.t' log DIR="`pwd`" touch date.t darcs add date.t darcs record -a -m foo "$DIR/date.t" | grep -i 'finished recording' # issue396 - record -l "" touch 'notnull.t' darcs record -am foo -l "" notnull.t | grep -i 'finished recording' # basic record date >> date.t darcs record -a -m basic_record date.t | grep -i 'finished recording' # testing --logfile date >> date.t echo "second record\n" >> log.txt darcs record -a -m 'second record' --logfile=log.txt date.t | grep -i 'finished recording' cd .. rm -rf temp1 darcs-2.8.4/tests/record-interactive.sh0000644001765600176560000000050312104371431017426 0ustar ganeshganesh#!/usr/bin/env bash . lib rm -rf temp1 mkdir temp1 cd temp1 darcs init touch foo darcs add foo darcs record -a -m addfoo darcs replace one two foo darcs replace three four foo darcs replace five six foo echo sa | darcs record -m cancelled darcs whatsnew darcs changes > ch not grep cancelled ch cd .. rm -rf temp1 darcs-2.8.4/tests/record_editor.sh0000644001765600176560000000256012104371431016466 0ustar ganeshganesh#!/usr/bin/env bash # Some tests for 'darcs rec --edit-long-comment' . lib abort_windows rm -rf temp1 export DARCS_EDITOR="/bin/cat -n" # editor: space in command mkdir temp1 cd temp1 darcs init touch file.t darcs add file.t echo y | darcs record --edit-long-comment -a -m foo file.t | grep '2.*END OF DESCRIPTION' cd .. rm -rf temp1 # editor: space in path mkdir temp2\ dir cd temp2\ dir darcs init touch file.t darcs add file.t echo y | darcs record --edit-long-comment -a -m foo file.t | grep '2.*END OF DESCRIPTION' cd .. rm -rf temp2\ dir # make sure summaries are coalesced mkdir temp3 cd temp3 darcs init cat > file < file < test-command << FOO #!/bin/sh echo EVIL FOO chmod u+x test-command echo y | darcs record --logfile='; test-command' --edit-long-comment -a -m foo file.t > log not grep EVIL log cd .. rm -rf temp1 darcs-2.8.4/tests/recordrace.sh0000644001765600176560000000046712104371431015757 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf foo1 foo2 mkdir foo1 foo2 cd foo1 darcs init echo zig > foo darcs add foo sleep 1 darcs record -a -m add_foo -A x #sleep 1 echo zag >> foo darcs record --ignore-time -a -m mod_foo -A x cd ../foo2 darcs init darcs pull -a ../foo1 cd .. cmp foo1/foo foo2/foo rm -rf foo1 foo2 darcs-2.8.4/tests/remove.sh0000644001765600176560000000343012104371431015134 0ustar ganeshganesh#!/usr/bin/env bash ## ## Copyright (C) 2009 Roman Plasil ## ## 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. . lib # Load some portability helpers. rm -rf R S # Another script may have left a mess. darcs init --repo R # Create our test repos. cd R mkdir d e # Change the working tree. mkdir d/f d/f/g echo 'Example content.' > d/f/1.txt echo 'Example content.' > d/f/g/2.txt echo 'Example content.' > e/3.txt darcs add -r . darcs wh -s > before.lst grep -i d before.lst grep -i e before.lst grep -i d/f before.lst darcs remove -r d darcs wh -s > after.lst not grep -i d after.lst not grep -i d/f after.lst not grep -i d/f/g after.lst not grep -i d/f/g/2.txt after.lst not grep -i d/f/1.txt after.lst cd .. darcs-2.8.4/tests/repair-clean.sh0000644001765600176560000000050112104371431016175 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp1 mkdir temp1 cd temp1 darcs init touch baz darcs add baz darcs record -m moo -a cat _darcs/patches/pending darcs changes -v darcs check # check that repair doesn't do anything to a clean repository darcs repair > out cat out grep 'already consistent' out cd .. rm -rf temp1 darcs-2.8.4/tests/repair.sh0000644001765600176560000000067712104371431015133 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp1 mkdir temp1 cd temp1 darcs initialize echo ALL ignore-times >> _darcs/prefs/defaults echo A1 > foo mkdir d echo A2 > d/bar darcs add foo darcs add d darcs add d/bar darcs record -a -m AA -A x echo B > foo darcs record -a -m BB -A x echo C > foo darcs record -a -m CC -A x for i in _darcs/pristine*; do echo Empty the pristine directory: $i rm -rf $i mkdir $i done darcs repair cd .. rm -rf temp1 darcs-2.8.4/tests/rename_shouldnt_affect_prefixes.sh0000644001765600176560000000337712104371431022255 0ustar ganeshganesh#!/usr/bin/env bash ## Renaming a -> b should not affect any filenames with prefix b, when looking ## for the original name of the files in changes --xml, or when annotating. ## ## Copyright (C) 2012 Owen Stephens ## ## 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. . lib rm -rf R darcs init --repo R cd R echo -e 'a\nb\nc' > a cp a bb darcs rec -alm 'Add a bb' darcs move a b darcs rec -am 'Move a -> b' darcs cha --xml b bb > changes.xml grep "original_name='./a'" < changes.xml # Ensure we've not used a prefix of the filename for the move. not grep "original_name='./ab'" < changes.xml # Ensure that we are able to annotate bb (if the rename has affected bb # internally, we'll not be able to annotate the file) darcs annotate bb | not grep unknown darcs-2.8.4/tests/repair-corrupt.sh0000644001765600176560000000263212104371431016620 0ustar ganeshganesh. lib rm -rf bad mkdir bad cd bad darcs init echo foo > bar darcs add bar darcs rec -a -m 'foo' echo hey > foo darcs add foo darcs rec -a -m 'more foo' hashed=false test -e _darcs/hashed_inventory && hashed=true cp -R _darcs _clean_darcs # produce a corrupt patch echo 'rmfile foo' > _darcs/patches/pending $hashed || echo -n > _darcs/pristine/foo darcs rec -a -m 'remove foo' not darcs check # unapplicable patch! cp -R _darcs/ _backup_darcs darcs repair # repairs the patch darcs check rm -rf _darcs mv _backup_darcs _darcs # get the bad patch back # stash away contents of _darcs cp -R _darcs/ _backup_darcs echo here > bar darcs rec -a -m 'here' # corrupt pristine content corrupt_pristine() { $hashed && inv=`grep ^pristine _darcs/hashed_inventory` cp _backup_darcs/patches/* _darcs/patches/ cp _backup_darcs/*inventory* _darcs/ if $hashed; then cp _darcs/hashed_inventory hashed.tmp sed -e "s,^pristine:.*$,$inv," < hashed.tmp > _darcs/hashed_inventory rm hashed.tmp fi } corrupt_pristine not darcs check # just a little paranoia darcs repair # repair succeeds darcs check # and the resulting repo is consistent # *AND* it contains what we expect... darcs show contents bar > foobar echo foo > foobar1 diff foobar foobar1 rm -rf _backup_darcs mv _clean_darcs _backup_darcs corrupt_pristine # without the unapplicable patch not darcs check darcs repair darcs check cd .. darcs-2.8.4/tests/repair-corrupt-add.sh0000644001765600176560000000322312104371431017343 0ustar ganeshganesh#!/usr/bin/env bash ## Test that we can repair incorrect adds ## ## Copyright (C) 2012 Ganesh Sittampalam ## ## 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. . lib rm -rf bad mkdir bad cd bad darcs init echo foo > file darcs add file mkdir dir darcs add dir darcs rec -a -m 'initial' darcs changes --verbose --patch 'initial' # produce a corrupt addfile patch echo 'addfile ./file' > _darcs/patches/pending echo 'yny' | darcs rec -m 're-add file' not darcs check darcs repair darcs check # produce a corrupt adddir patch echo 'adddir ./dir' > _darcs/patches/pending echo 'yy' | darcs rec -m 're-add dir' not darcs check darcs repair darcs check darcs-2.8.4/tests/replace.sh0000644001765600176560000000256712104371431015264 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp mkdir temp cd temp darcs init echo "X X X" > foo echo $'A A,A\tA,A\vA' >> foo darcs rec -alm "Added" # These should fail until replace handles tokens and # token-chars with leteral spaces in them darcs replace ' X ' ' XX ' --token-chars '[ X]' foo && exit 1 || true darcs replace $'A A' 'aaa' --token-chars '[^,]' foo && exit 1 || true darcs replace $'A\tA' 'aaa' --token-chars '[^,]' foo && exit 1 || true darcs replace $'A\vA' 'aaa' --token-chars '[^,]' foo && exit 1 || true # Check that replace is not fooled by duplicate file names # (i.e. not trying to performe the replace twice in the same file) darcs replace X Y foo foo darcs replace Y Z foo ../temp/foo darcs replace Z Q foo foo --repodir=../temp/ darcs rec -am "xyzq" # Try to "overwrite" a hunk with a replace. # # v1.0.8 accepts this without error or warning, # but should perhaps require the --force option? # # current unstable sometimes(!) fails with bug: invalid pending # which is surely a bug. # this succeeds echo "x" > foo darcs rec -am xx echo "y" > foo darcs replace --ignore-times x y foo # this fails echo "hej" > foo darcs rec -am hej echo "hopp" > foo darcs replace hej hopp foo darcs whatsnew echo "src" > foo echo "dst" >> foo darcs rec -am hop darcs replace src dst foo || true darcs replace --force src dst foo darcs whatsnew darcs whatsnew -ls cd .. rm -rf temp darcs-2.8.4/tests/repodir.sh0000644001765600176560000000100612104371431015300 0ustar ganeshganesh#!/usr/bin/env bash ### http://bugs.darcs.net/issue496 ### _darcs/prefs/defaults ignored when using --repodir ## All these commands SHOULD fail (hence leading NOTs). . lib rm -rf temp mkdir temp cd temp mkdir repo darcs initialize --repodir repo cd repo date > foo darcs add foo darcs record -a -m auth echo > _darcs/prefs/defaults ALL disable # try to disable all not darcs changes not darcs changes --repodir "`pwd`" cd .. not darcs changes --repodir repo not darcs changes --repodir "`pwd`/repo" rm -rf temp darcs-2.8.4/tests/rollback.sh0000644001765600176560000000130212104371431015424 0ustar ganeshganesh#!/bin/bash set -ev range="0 1 2" rm -rf temp1 temp2 # clean up when previous run crashed mkdir temp1 && cd temp1 && darcs init touch f && darcs add f for i in $range do echo $i > f && darcs record -A me --ignore-time -m p$i --all f done cd .. && mkdir temp2 && cd temp2 && darcs init set -x : Demonstrate problem with regrem for i in $range do darcs pull --patch p$i ../temp1 --all if darcs whatsnew ; then : Resolve conflict - rollback our patch darcs revert --all darcs rollback -a --name x0 darcs revert --all fi : Create local change and record it echo X$i > f && darcs record -l -A me --ignore-time -m x$i --all f done cd .. rm -rf temp1 temp2 darcs-2.8.4/tests/replace_after_pending_add.sh0000644001765600176560000000031712104371431020750 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -fr temp1 mkdir temp1 cd temp1 darcs --version darcs init echo a b a b a b > A darcs add A if darcs replace a c A | grep Skipping; then exit 1 fi cd .. rm -fr temp1 darcs-2.8.4/tests/replace_after_pending_mv.sh0000644001765600176560000000035012104371431020637 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -fr temp1 mkdir temp1 cd temp1 darcs init echo a b a b a b > A darcs add A darcs record --all --name=p1 darcs mv A B if darcs replace a c B | grep Skipping; then exit 1 fi cd .. rm -fr temp1 darcs-2.8.4/tests/repoformat.sh0000644001765600176560000000414012104371431016014 0ustar ganeshganesh#!/usr/bin/env bash . lib rm -rf garbage future mkdir garbage cd garbage darcs init echo gobbledygook > _darcs/format cd .. mkdir future cd future darcs init touch titi darcs add titi darcs record -am titi cat > _darcs/format < log grep -i "can't understand repository format" log rm -rf temp1 log # pull from garbage repo mkdir temp1 cd temp1 darcs init not darcs pull ../garbage 2> log grep -i "can't understand repository format" log cd .. rm -rf temp1 # apply in garbage repo mkdir temp1 cd temp1 darcs init darcs changes --context > empty-context darcs tag -m "just a patch" darcs send -a --context=empty-context -o ../bundle.dpatch . cd ../garbage not darcs apply ../bundle.dpatch 2> log grep -i "can't understand repository format" log cd .. rm -rf temp1 bundle.dpatch # add in garbage repo cd garbage touch toto not darcs add toto 2> log grep -i "can't understand repository format" log cd .. rm -rf garbage ## future repo: we don't understand one # alternative of a line of format # only look at future vs darcs2 if grep 'old-fashioned' .darcs/defaults; then exit 200 fi if grep hashed .darcs/defaults; then exit 200 fi # get future repo: ok # --to-match is needed because of bug### darcs get future temp1 --to-match "name titi" cd temp1 darcs changes touch toto darcs add toto darcs record -am 'blah' cd .. rm -rf temp1 # pull from future repo: ok mkdir temp1 cd temp1 darcs init darcs pull ../future -a darcs cha | grep titi cd .. rm -rf temp1 # apply in future repo: !ok mkdir temp1 cd temp1 darcs init darcs changes --context > empty-context darcs tag -m "just a patch" darcs send -a --context=empty-context -o ../bundle.dpatch . cd ../future not darcs apply ../bundle.dpatch 2> log cat log grep -i "can't write repository format" log cd .. rm -rf temp1 bundle.dpatch # record in future repo: !ok cd future touch toto not darcs add toto 2> log grep -i "can't write repository format" log cd .. rm -rf future #No future! darcs-2.8.4/tests/revert_unrecorded_add.sh0000644001765600176560000000017112104371431020167 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp mkdir temp cd temp darcs init echo stuff > foo darcs add foo darcs revert -a darcs-2.8.4/tests/revert_interactive.sh0000644001765600176560000000201112104371431017535 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp1 mkdir temp1 cd temp1 darcs init echo hello world > foo darcs add foo darcs record -a -m add -A x echo goodbye world >> foo echo y/y | tr / \\012 | darcs revert darcs show contents foo | cmp foo - # Now let's test a trickier revert where changes commute nontrivially. cat > foo < foo echo "nyy" | darcs revert DARCS_DONT_COLOR=1 darcs wh > whatsnew cat > correct < bar echo hello world > foo darcs add bar darcs replace hello goodbye bar foo echo "cnnnyy/y" | tr / \\012 | darcs revert DARCS_DONT_COLOR=1 darcs wh > whatsnew cat > correct < foo/bar darcs add foo foo/bar darcs record -a -m add cd .. # get temp1 into temp2 darcs get temp1 temp2 cd temp2 echo hello world > foo/baz cd .. # remove a directory from temp1 and record cd temp1 rm -rf foo darcs record -a -m del cd .. cd temp2 test -e foo/baz test -e foo/bar test -d foo darcs show files --no-pending --no-dir >> files grep foo/bar files darcs show files --no-pending --no-fil >> dirs grep foo dirs cd .. darcs pull -a --repodir=temp2 > pullresult cat pullresult grep 'Warning: .ot deleting' pullresult # get temp1 into temp3 darcs get temp1 temp3 cd temp3 darcs obliterate --last 1 -a echo hello world > foo/baz cd .. cd temp3 test -e foo/baz test -e foo/bar test -d foo darcs show files --no-pending --no-dir >> files grep foo/bar files darcs show files --no-pending --no-fil >> dirs grep foo dirs cd .. darcs pull -q -a --repodir=temp3 > pullresult cat pullresult test ! -s pullresult rm -rf temp1 temp2 temp3 darcs-2.8.4/tests/lib0000644001765600176560000000476412104371431014007 0ustar ganeshganesh# This is a -*- sh -*- library. ## I would use the builtin !, but that has the wrong semantics. not () { "$@" && exit 1 || :; } # trick: OS-detection (if needed) abort_windows () { if echo $OS | grep -i windows; then echo This test does not work on Windows exit 200 fi } pwd() { ghc --make -o hspwd "$TESTBIN/hspwd.hs" > /dev/null "./hspwd" } # switch locale to one supporting the latin-9 (ISO 8859-15) character set if possible, otherwise skip test no_latin9_locale_warning () { echo "no ISO 8859-15 locale found, skipping test" echo "try (eg): sudo locale-gen en_US.ISO-8859-15" } switch_to_latin9_locale () { if echo $OS | grep -i windows; then chcp.com 28605 else if ! which locale ; then echo "no locale command, skipping test" exit 200 fi # look for a ISO 8859-15 locale. locale -a shows iso885915, on ubuntu at least latin9_locale=`locale -a | egrep -i iso8859-?15 | head -n 1` || (no_latin9_locale_warning; exit 200) test -n "$latin9_locale" || (no_latin9_locale_warning; exit 200) echo "Using locale $latin9_locale" export LC_ALL=$latin9_locale echo "character encoding is now `locale charmap`" fi } # switch locale to utf8 if supported if there's a locale command, skip test # otherwise switch_to_utf8_locale () { if echo $OS | grep -i windows; then chcp.com 65001 else if ! which locale ; then echo "no locale command" exit 200 # skip test fi utf8_locale=`locale -a | grep .utf8 | head -n 1` || exit 200 test -n "$utf8_locale" || exit 200 echo "Using locale $utf8_locale" export LC_ALL=$utf8_locale echo "character encoding is now `locale charmap`" fi } serve_http() { cat > light.conf < /dev/null 2>&1 || exit 200 baseurl="http://localhost:23032" } finish_http() { test -e "$1/light.pid" && kill `cat "$1/light.pid"` || true } skip-formats() { for f in "$@"; do grep $f $HOME/.darcs/defaults && exit 200 || true; done } grep -q darcs-2 .darcs/defaults && format=darcs-2 grep -q hashed .darcs/defaults && format=hashed set -vex -o pipefail darcs-2.8.4/tests/send-dont-prompt-deps.sh0000644001765600176560000000131412104371431020001 0ustar ganeshganesh#!/usr/bin/env bash set -ev # Check that the right patches get sent using --dont-prompt-for-dependencies rm -rf temp1 rm -rf temp2 mkdir temp2 mkdir temp1 cd temp2 darcs init cd .. cd temp1 darcs init echo foo > f darcs record -Ax -alm foo1 echo bar > b darcs rec -Ax -alm bar1 echo foo2 > f darcs record -Ax -alm foo2 echo bar2 > b darcs record -Ax -alm bar2 echo y | darcs send ../temp2 -i --dont-prompt-for-dependencies -p foo2 --dry-run > toto #on the previous line, we get asked about foo2, and we take it grep foo2 toto | wc -l | grep 2 #we don't get asked about foo1, but we take it anyway, so grep foo1 toto | wc -l | grep 1 #and we don't send bar grep bar toto | wc -l | grep 0 cd .. rm -rf temp1 temp2 darcs-2.8.4/tests/rollback-no-record.sh0000644001765600176560000000427212104371431017323 0ustar ganeshganesh#!/usr/bin/env bash ## Test for rollback --no-record ## ## Copyright (C) 2010 Florent Becker ## ## 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. . lib # Load some portability helpers. darcs init --repo R # Create our test repos. darcs init --repo S cd R mkdir d e echo 'Example content.' > d/f darcs record -lam 'Add d/f and e.' darcs mv d/f e/ darcs replace Example Kestatepa e/f echo "Blih blah bloh" >> e/f darcs record -am 'Some changes.' cat <> e/f Kestatepa EOF cat e/f darcs record -am 'one more line in f' darcs changes --context > context darcs rollback -a -p 'Some changes' -m 'rollback' darcs send -a -o rollback.dpatch --context context ../S darcs obliterate -a -p rollback darcs rollback -a -p 'Some changes' --no-record darcs record -am 'rollback' darcs send -a -o rollback2.dpatch --context context ../S #check the effects not ls e/f ls d/f grep Example d/f not grep "Blih" d/f #check the content of the patches #"diff rollback.dpatch rollback2.dpatch" fails because of #the order of the hunks. grep "replace .* Kestatepa Example" rollback2.dpatch grep "move ./e/f ./d/f" rollback2.dpatch grep -e "-Blih blah bloh" rollback2.dpatch darcs-2.8.4/tests/rollback-nothing.sh0000644001765600176560000000036712104371431017102 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp mkdir temp cd temp darcs init date > file1 darcs add file1 darcs record -am "test" rm file1 darcs record -am "rm" echo yd | darcs rollback --last=1 -m 'oops' | grep 'No changes selected' cd .. rm -rf temp darcs-2.8.4/tests/sametwice.sh0000644001765600176560000000117512104371431015624 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp1 temp2 mkdir temp1 cd temp1 darcs init echo record author me > _darcs/prefs/defaults echo ALL all >> _darcs/prefs/defaults echo ALL verbose >> _darcs/prefs/defaults echo ALL ignore-times >> _darcs/prefs/defaults touch foo darcs add foo darcs whatsnew darcs record -m add_foo echo hello >> foo darcs record -m mod_foo cd .. darcs get --repo-name temp2 temp1 cd temp2 cp ../temp1/_darcs/prefs/defaults _darcs/prefs echo y/d/y | tr / \\012 | darcs unpull --interactive test -f foo -a ! -s foo echo hello >> foo darcs record -m mod_foo_again darcs pull ../temp1 test -s foo cd .. rm -rf temp1 temp2 darcs-2.8.4/tests/set-default-hint.sh0000644001765600176560000000374512104371431017025 0ustar ganeshganesh#!/usr/bin/env bash ## Test that set-default hint messages are produced at the right times ## ## Copyright (C) 2011 Ganesh Sittampalam ## ## 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. . lib # Load some portability helpers. rm -rf R1 R2 R3 # Another script may have left a mess. darcs init --repo R1 darcs get R1 R2 darcs get R1 R3 HINTSTRING="issue the same command with the --set-default flag" cd R3 for command in pull push send do # R1 should be the default for R3 darcs $command ../R1 | not grep "$HINTSTRING" darcs $command ../R2 | grep "$HINTSTRING" # can disable message on the command-line darcs $command --no-set-default ../R2 | not grep "$HINTSTRING" # or using defaults echo "$command no-set-default" >> ../.darcs/defaults darcs $command ../R2 | not grep "$HINTSTRING" darcs $command --set-default ../R2 | not grep "$HINTSTRING" darcs $command --set-default ../R1 | not grep "$HINTSTRING" done darcs-2.8.4/tests/send-encoding.sh0000644001765600176560000000325712104371431016363 0ustar ganeshganesh#!/usr/bin/env bash ## Copyright (C) 2011 Ganesh Sittampalam ## ## Test that darcs send uses the UTF-8 encoding for emails ## when non-ASCII characters are in the message ## ## 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. . lib # Load some portability helpers. switch_to_utf8_locale darcs init --repo empty darcs init --repo send cd send echo 'file1' > file1 darcs record -lam 'file1' LANG=en_GB.UTF-8 \ EDITOR='echo Non-ASCII chars: é è ỠΨ Þ¡ ß à¤¹ ჴ ᳠‱ ₠∰ ✈ ⢅ .. >' \ darcs send -a ../empty --to=invalid@invalid --edit \ --sendmail-command='grep "Content-Type: text/plain; charset=\"utf-8\"" %<' darcs-2.8.4/tests/send-external.sh0000644001765600176560000000176512104371431016421 0ustar ganeshganesh#!/usr/bin/env bash set -ev DARCS_EDITOR=echo export DARCS_EDITOR rm -rf temp1 temp2 mkdir temp1 temp2 cd temp2 darcs init cd .. cd temp1 darcs init date > foobar darcs add foobar darcs rec -a -m add-foobar cat > saveit.sh <>saved.out echo \$6 contains: >>saved.out ls -ltr >>saved.out cat "\$6" >>saved.out echo End of \$6 contents >>saved.out grep add-foobar \$6 CNT=0 while [ "\$#" != "0" ]; do CNT=`expr \$CNT + 1` echo \$0: arg[\$CNT] = \"\$1\" >>saved.out shift done echo \$0: Total \$CNT arguments >>saved.out echo \$0: Input: >>saved.out cat >>saved.out echo \$0: End of input: >>saved.out EOF chmod +x saveit.sh # foobar darcs send --author=me -a --to=random@random \ --sendmail-command='bash ./saveit.sh %s %t %c %b %f %a %S %t %C %B %F %A something' ../temp2 cat saved.out grep add-foobar saved.out grep 'addfile ./foobar' saved.out cd .. rm -rf temp1 temp2 darcs-2.8.4/tests/send-output-v1.sh0000644001765600176560000000406312104371431016455 0ustar ganeshganesh#!/usr/bin/env bash ## Test that we produce exactly correct output when sending v1 patches ## ## Copyright (C) 2010 Ganesh Sittampalam ## ## 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. . lib # Load some portability helpers. grep old-fashioned $HOME/.darcs/defaults || grep hashed $HOME/.darcs/defaults || exit 200 rm -rf empty mkdir empty cd empty darcs init cd .. rm -rf repo gunzip -c $TESTDATA/simple-v1.tgz | tar xf - cd repo darcs send -o repo.dpatch -a ../empty day=$(grep "<.*@.*>" $TESTDATA/simple-v1.dpatch | head -n 1 | cut -f1-3 -d' ') diff -u -I'1 patch for repository ' -I'patches for repository ' -I"$day" $TESTDATA/simple-v1.dpatch repo.dpatch cd .. # context-v1 tests that we are including some context lines in hunk patches rm -rf repo gunzip -c $TESTDATA/context-v1.tgz | tar xf - cd repo darcs send -o repo.dpatch -a ../empty day=$(grep "<.*@.*>" $TESTDATA/context-v1.dpatch | head -n 1 | cut -f1-3 -d' ') diff -u -I'1 patch for repository ' -I'patches for repository ' -I"$day" $TESTDATA/context-v1.dpatch repo.dpatch cd .. darcs-2.8.4/tests/send-output-v2.sh0000644001765600176560000000401112104371431016447 0ustar ganeshganesh#!/usr/bin/env bash ## Test that we produce exactly correct output when sending v2 patches ## ## Copyright (C) 2010 Ganesh Sittampalam ## ## 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. . lib # Load some portability helpers. grep darcs-2 $HOME/.darcs/defaults || exit 200 rm -rf empty mkdir empty cd empty darcs init cd .. rm -rf repo gunzip -c $TESTDATA/simple-v2.tgz | tar xf - cd repo darcs send -o repo.dpatch -a ../empty day=$(grep "<.*@.*>" $TESTDATA/simple-v2.dpatch | head -n 1 | cut -f1-3 -d' ') diff -u -I'1 patch for repository ' -I'patches for repository ' -I"$day" $TESTDATA/simple-v2.dpatch repo.dpatch cd .. # context-v1 tests that we are including some context lines in hunk patches rm -rf repo gunzip -c $TESTDATA/context-v2.tgz | tar xf - cd repo darcs send -o repo.dpatch -a ../empty day=$(grep "<.*@.*>" $TESTDATA/context-v2.dpatch | head -n 1 | cut -f1-3 -d' ') diff -u -I'1 patch for repository ' -I'patches for repository ' -I"$day" $TESTDATA/context-v2.dpatch repo.dpatch cd .. darcs-2.8.4/tests/send.sh0000644001765600176560000000343112104371431014571 0ustar ganeshganesh#!/usr/bin/env bash set -ev DARCS_EDITOR=echo export DARCS_EDITOR rm -rf temp1 temp2 mkdir temp1 temp2 cd temp2 darcs init # setup test cd ../temp1 darcs init touch foo bar darcs add foo bar darcs record -a -m add_foo_bar -A x # Test that a default preference value is not needed to send darcs send --author=me -a --to=random@random --sendmail-command='grep "^To: random@random$" %<' ../temp2 # Test that a default preference will be used when no --to value is specified echo "default@email" > ../temp2/_darcs/prefs/email darcs send --author=me -a --sendmail-command='grep "^To: default@email$" %<' ../temp2 # Test that the --to parameter overrides the default value in the repository darcs send --author=me -a --to=override@default --sendmail-command='grep "^To: override@default$" %<' ../temp2 darcs send --author=me -a --in-reply-to=some-thread-id --sendmail-command='grep "^In-Reply-To: some-thread-id$" %<' ../temp2 darcs send --author=me -a --in-reply-to=some-thread-id --sendmail-command='grep "^References: some-thread-id$" %<' ../temp2 # Test that the --subject parameter sets the subject # Test that the --output-auto-name parameter outputs what we expect darcs send --author=me -a --subject="it works" --output test1.dpatch ../temp2 darcs send --author=me -a --subject="it works" --output-auto-name ../temp2 cmp test1.dpatch add_foo_bar.dpatch # test --output-auto-name works with optional argument. mkdir patchdir darcs send --author=me -a --subject="it works" --output-auto-name=patchdir ../temp2 cmp test1.dpatch patchdir/add_foo_bar.dpatch # checking --output-auto-name=dir when run in different directory cd patchdir rm add_foo_bar.dpatch darcs send --author=me -a --subject="it works" --output-auto-name=. ../../temp2 cmp ../test1.dpatch add_foo_bar.dpatch cd .. cd .. rm -rf temp1 temp2 darcs-2.8.4/tests/send_apply.sh0000644001765600176560000000117612104371431016002 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp1 temp2 mkdir temp1 temp2 cd temp2 darcs init cd ../temp1 darcs init touch foo bar darcs add foo bar darcs record -a -m add_foo_bar -A x darcs mv foo zig darcs mv bar foo darcs mv zig bar darcs record -a -m swap_foo_bar -A x darcs send --author=me --output=funpatch --dont-sign -a ../temp2 cd ../temp2 darcs apply ../temp1/funpatch cd .. cmp temp1/bar temp2/bar rm -rf temp2 mkdir temp2 cd temp2 darcs init darcs apply ../temp1/funpatch ## Also test that "darcs apply" can accept a patch on stdin. darcs obl -a darcs apply < ../temp1/funpatch cd .. cmp temp1/bar temp2/bar rm -rf temp1 temp2 darcs-2.8.4/tests/steve_and_monica_rollback.sh0000644001765600176560000000122612104371431021007 0ustar ganeshganesh#!/bin/bash # Issue578: A conflict rollback case for Darcs2 set -ev rm -rf tmp_steve tmp_monica mkdir tmp_steve mkdir tmp_monica cd tmp_steve darcs init --darcs-2 echo A >foo darcs add foo darcs record -Asteve -am 'Anote' echo B >foo darcs record -Asteve -am 'Bnote' # Show the history as Steve sees it. darcs changes -s echo "######" cd ../tmp_monica darcs init --darcs-2 echo A>foo darcs add foo echo Z>bar darcs add bar darcs record -Amonica -am 'AZnote' darcs pull -a ../tmp_steve darcs changes echo "######" darcs rollback -a -m newpatch -A me --match 'exact Anote' # previous failure result: darcs failed: cannot roll back a 'rollback' patch. darcs-2.8.4/tests/set_scripts_executable.sh0000644001765600176560000000220512104371431020401 0ustar ganeshganesh#!/usr/bin/env bash # Some tests for the --set-scripts-executable option. . lib abort_windows rm -rf temp1 temp2 mkdir temp1 cd temp1 darcs init cat > script.pl << FOO #!/usr/bin/env perl print "Hello\n"; FOO chmod 0644 script.pl date > nonscript # pre-tests test -r script.pl test -r nonscript test ! -x script.pl test ! -x nonscript darcs add script.pl nonscript darcs record --name 'uno' --all cd .. # sans --set-scripts-executable (should not be executable) mkdir temp2 cd temp2 darcs init darcs pull -a ../temp1 # sanity check test -r script.pl test -r nonscript # nothing should be executable test ! -x script.pl test ! -x nonscript cd .. rm -rf temp2 # with --set-scripts-executable mkdir temp2 cd temp2 darcs init darcs pull -a ../temp1 --set-scripts-executable # sanity check test -r script.pl test -r nonscript # script should be executable test -x script.pl test ! -x nonscript cd .. rm -rf temp2 # now let's try the same thing with get darcs get --set-scripts-executable temp1 temp2 cd temp2 # sanity check test -r script.pl test -r nonscript # script should be executable test -x script.pl test ! -x nonscript cd .. rm -rf temp1 temp2 darcs-2.8.4/tests/setpref.sh0000644001765600176560000000065612104371431015316 0ustar ganeshganesh#!/usr/bin/env bash . lib rm -rf temp1 temp2 mkdir temp1 cd temp1 darcs init echo 'test file 1' > foo darcs record --look-for-adds --all -m"Patch 1" echo 'test boringfile' > bar darcs setpref boringfile bar darcs record --look-for-adds --all -m"Patch 2" echo 'test file 3' > baz # there should be no -R darcs record --look-for-adds --all -m"Patch 3" > ../temp2 cat ../temp2 not grep R ../temp2 cd .. rm -rf temp1 rm -f temp2 darcs-2.8.4/tests/several_commands.sh0000644001765600176560000000060712104371431017164 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp1 mkdir temp1 cd temp1 darcs init echo hello world > foo darcs add foo darcs record -a -m add -A x echo goodbye world >> foo darcs diff darcs diff -u darcs whatsnew darcs whatsnew --summary echo y | darcs revert -a darcs show contents foo | cmp foo - mkdir d darcs add d darcs record -a -m 'add dir' -A x rmdir d darcs revert -a d cd .. rm -rf temp1 darcs-2.8.4/tests/show-authors.sh0000644001765600176560000000065612104371431016311 0ustar ganeshganesh#!/usr/bin/env bash set -ev darcs init echo zig > foo darcs add foo darcs record -a -m add_foo -A x echo zag >> foo darcs record -a -m mod_foo -A y echo bar > foo darcs record -a -m mod2 -A y darcs show authors > authors grep x authors grep y authors head -1 authors > first-author grep y first-author darcs show authors --verbose darcs show authors --verbose | grep y | wc -l > num-patches cat num-patches grep 2 num-patches darcs-2.8.4/tests/show-bug.sh0000644001765600176560000000076012104371431015375 0ustar ganeshganesh#!/usr/bin/env bash ## All these commands SHOULD fail (hence leading NOTs). . lib darcs show bug --debug 1> stdout 2> stderr || true cat stdout cat stderr echo The following test will fail if this version of darcs is marked as echo obsolete. echo ================================================================== not grep 'please do not' stderr # The following test fails if HTTP isn't present, but would be a nice test # to have in place. #not grep unable stderr grep 'fake bug' stderr darcs-2.8.4/tests/show_contents.sh0000644001765600176560000000134312104371431016535 0ustar ganeshganesh#!/usr/bin/env bash . lib rm -rf temp1 mkdir temp1 cd temp1 darcs init touch foo darcs add foo echo first > foo darcs record -a -m "first edit" -A author1 echo second > foo darcs record -a -m "second edit" -A author2 darcs tag t1 -A moi echo third > foo darcs record -a -m "third edit" -A author3 echo fourth > foo darcs record -a -m "fourth edit" -A author4 echo unrecorded > foo darcs show contents foo | grep fourth darcs show contents foo -p third | grep third darcs show contents foo --match="author author1" first | grep first darcs show contents foo --tag t1 | grep second not darcs show contents foo --match "hash bla" 2>&1 | tee out grep "Couldn't match pattern" out darcs show contents -n 2 foo | grep third cd .. rm -rf temp1 darcs-2.8.4/tests/show_tags-remote.sh0000644001765600176560000000317412104371431017133 0ustar ganeshganesh#!/usr/bin/env bash ## Test for show tags --repo ## ## Copyright (C) 2010 Eric Kow ## ## 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. . lib # Load some portability helpers. darcs init --repo R # Create our test repos. darcs init --repo S cd R echo 'Example content.' > f darcs record -lam 'Add f' darcs tag 't0' darcs tag 't1' darcs show tags | grep t0 cd .. serve_http # sets baseurl cd S darcs changes --repo ../R darcs show tags --repo ../R | grep t0 darcs show tags --repo $baseurl/R | grep t0 cd .. darcs show tags --repo R | grep t0 darcs show tags --repo $baseurl/R | grep t0 darcs-2.8.4/tests/show_tags.sh0000644001765600176560000000100212104371431015626 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp1 mkdir temp1 cd temp1 darcs initialize echo ALL ignore-times >> _darcs/prefs/defaults echo A > foo darcs add foo darcs record -a -m AA -A x echo B > foo darcs record -a -m BB -A x echo C > foo darcs record -a -m CC -A x darcs tag -m 1.0 -A x echo D > foo darcs record -a -m DD -A x echo E > foo darcs record -a -m EE -A x echo F > foo darcs record -a -m FF -A x darcs tag -m 2.0 -A x darcs show tags > my cat my cat > ref < foo darcs add foo darcs record -a --author=me -m "First patch" i=1 while test $i -le 100; do echo foo $i > foo; darcs record --ignore-times -a --author=me -m "Patch $i" > bar i=`expr $i + 1` done darcs tag --author=me -m 'silly tag' i=1000 while test $i -le 1096; do echo foo $i > foo; darcs record --ignore-times -a --author=me -m "Patch $i" > bar i=`expr $i + 1` done darcs --version darcs changes | head cd .. # rm -rf temp1 darcs-2.8.4/tests/split-patches.sh0000644001765600176560000000376712104371431016434 0ustar ganeshganesh#!/usr/bin/env bash ## Test for correct handling of Darcs v1 patches with nested { } ## ## Copyright (C) 2010 Ganesh Sittampalam ## ## 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. . lib # Load some portability helpers. if grep old-fashioned .darcs/defaults; then format=old-fashioned-inventory patchtype=darcs-1 elif grep darcs-2 .darcs/defaults; then format=darcs-2 patchtype=darcs-2 elif grep hashed .darcs/defaults; then format=hashed patchtype=darcs-1 else exit 200; fi rm -rf split--${format} gunzip -c $TESTDATA/split--${format}.tgz | tar xf - cd split--${format} darcs check cd .. # .dpatch tests: .dpatch files for darcs 2 split patches were # broken in darcs 2.5 (and probably always broken) so we don't # bother to test them. if [ ${patchtype} != darcs-1 ] ; then exit 0 ; fi rm -rf temp mkdir temp cd temp darcs init darcs apply $TESTDATA/split--${patchtype}.dpatch cd .. rm -rf temp2 mkdir temp2 cd temp2 darcs init darcs apply $TESTDATA/split2--${patchtype}.dpatch cd .. darcs-2.8.4/tests/utf8.sh0000644001765600176560000001601012104371431014523 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue64 - Should store patch metadata in UTF-8 ## ## Copyright (C) 2009 Reinier Lamers ## ## 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. . lib # Helper function: do a darcs changes --xml and grep the result for the first # argument. If it is not found, exit with status 1. Otherwise, continue. The # second argument is a text that describes what we're grepping for. # If a third argument is given, it is used as the value for a --last option for # darcs changes. grep_changes () { if [ -z "$3" ]; then last="" else last="--last $3" fi darcs changes $last --xml > changes.xml if grep "$1" changes.xml ; then echo "$2 OK" else cat changes.xml echo "$2 not UTF-8-encoded!" exit 1 fi } # This file is encoded in ISO-8859-15 aka latin9. It was crafted with a hex editor. # Please leave it this way :-) switch_to_latin9_locale rm -rf temp1 mkdir temp1 cd temp1 darcs init # Test recording non-UTF-8-encoded non-latin1 ("funny") metadata from # interactive input echo 'Selbstverständlich überraschend' > something.txt darcs add something.txt echo 'l33tking¸0r@example.org' > interaction_script.txt echo y >> interaction_script.txt echo y >> interaction_script.txt echo '¤uroh4xx0rz' >> interaction_script.txt echo n >> interaction_script.txt unset DARCSEMAIL unset EMAIL set darcs record -i < interaction_script.txt grep_changes 'l33tkingž0r@example.org' 'patch author from interactive prompt' grep_changes '€uroh4xx0rz' 'patch name from interactive prompt' # Test recording funny metadata from command line echo 'Sogar überraschender' >> something.txt darcs record -a -A 'Jérôme Leb½uf' -m 'that will be ¤ 15, sir' grep_changes 'that will be € 15, sir' 'patch name from command line' grep_changes 'Jérôme LebÅ“uf' 'patch author from command line' # Test recording funny metadata from a log file echo 'Am allerüberraschendsten' >> something.txt echo 'darcs is soms wat naïef aangaande tekstcodering' > log.txt echo 'en zulke naïviteit is tegenwoordig passé, aldus ´i¸ek' >> log.txt darcs record -a -A 'Jérôme Leb½uf' --logfile=log.txt grep_changes 'darcs is soms wat naïef aangaande tekstcodering' 'patch name from log file' grep_changes 'en zulke naïviteit is tegenwoordig passé, aldus Žižek' 'patch log from log file' # Test recording funny metadata from environment, export EMAIL='Slavoj ´i¸ek ' rm _darcs/prefs/author echo 'La la la, the more lines the better!' >> something.txt darcs record -a -m 'Patch names are overrated' grep_changes 'Slavoj Žižek' 'author name from environment' # Test recording funny metadata from prefs files echo '´ed is dead' > _darcs/prefs/author echo '483 bottles of beer on the wall' >> something.txt darcs record -a -m 'Patch by ´ed' grep_changes 'Žed is dead' 'author name from prefs file' # Test amend-recording funny metadata echo 'No, it is really 484' >> something.txt echo y | darcs amend-record -p 'Patch by ' -A '´ed is even deader' -a grep_changes 'Žed is even deader' 'author name from amend-record command line flag' cat < editor.hs # create an 'editor' that writes latin9 import System.Environment import qualified Data.ByteString as B str = B.pack [65,108,108,32,109,121,32,164,115,32,97,114,101,32,103,111,110,101] main = getArgs >>= \[x] -> B.writeFile x str FAKE ghc --make -o editor editor.hs export EDITOR="`pwd`/editor" printf "y\ny\n" | darcs amend --edit -p 'Patch by ' grep_changes 'All my €s are gone' 'description edited from amend-record' grep_changes 'Žed is even deader' 'author name taken from draft in amend' # Test rollback recording funny metadata printf "y\ny\n" | darcs rollback -p 's are gone' -A '´ee´ee' -m "No patch¤s by ´ed!" grep_changes 'ŽeeŽee' 'Author name from rollback command line' grep_changes 'No patch€s by Žed' 'Patch name from rollback command line' grep_changes 'All my €s are gone' 'Patch name of rolled back patch' 1 grep_changes 'Žed is even deader' 'Author name of rolled back patch' 1 # Test tag recording funny metadata rm _darcs/prefs/author # Make tag be taken from EMAIL env variable darcs tag -m '´ is my favorite letter' grep_changes 'Slavoj Žižek' 'author name from environment with tag command' 1 grep_changes 'Ž is my favorite letter' 'Tag name from command line' unset EMAIL printf "´ors\ninitialcomment\n" | darcs tag --edit-long-comment grep_changes Žors 'Author name from interactive prompt from tag command' grep_changes 'All my €s are gone' 'Tag name from editor from tag command' 1 if grep ´ors _darcs/prefs/author ; then echo 'Author name stored locale-encoded in prefs file after tag command, OK' else echo 'No locale-encoded author in prefs file after tag command!' exit 1 fi darcs tag -A Ad¸e -m 'La¸t call' grep_changes Adže 'Author name from tag command line' 1 grep_changes 'Lažt call' 'Tag name from tag command line (take 2)' 1 cd .. # test that UTF-8 metadata doesn't get mangled on get rm -rf temp2 darcs get temp1 temp2 darcs changes --repodir temp1 --xml > temp1/changes.xml darcs changes --repodir temp2 --xml > temp2/changes.xml diff temp1/changes.xml temp2/changes.xml # and that it doesn't get mangled on push rm -rf temp2 mkdir temp2; darcs init --repodir temp2 darcs push --repodir temp1 -a temp2 --set-default darcs changes --repodir temp1 --xml > temp1/changes.xml darcs changes --repodir temp2 --xml > temp2/changes.xml diff temp1/changes.xml temp2/changes.xml # and that it doesn't get mangled on pull rm -rf temp2 mkdir temp2; darcs init --repodir temp2 darcs pull --repodir temp2 -a temp1 darcs changes --repodir temp1 --xml > temp1/changes.xml darcs changes --repodir temp2 --xml > temp2/changes.xml diff temp1/changes.xml temp2/changes.xml # and that it doesn't get mangled on send rm -rf temp2 mkdir temp2; darcs init --repodir temp2 darcs send --repodir temp1 -a -o temp2/patch.dpatch darcs apply --repodir temp2 -a temp2/patch.dpatch darcs changes --repodir temp1 --xml > temp1/changes.xml darcs changes --repodir temp2 --xml > temp2/changes.xml diff temp1/changes.xml temp2/changes.xml darcs-2.8.4/tests/tag.sh0000644001765600176560000000043512104371431014414 0ustar ganeshganesh#!/usr/bin/env bash . lib # Some tests for 'darcs tag' rm -rf temp1 log mkdir temp1 cd temp1 darcs init touch one darcs add one darcs record --name 'uno' --all darcs tag soup > log not grep failed log grep TAG log darcs changes --last 1 > log grep tagged log cd .. rm -rf temp1 log darcs-2.8.4/tests/unrecord-dont-prompt.sh0000644001765600176560000000122612104371431017742 0ustar ganeshganesh#!/usr/bin/env bash set -ev # Check that the right patches get unrecorded using --dont-prompt-for-dependencies rm -rf temp1 mkdir temp1 cd temp1 darcs init echo foo > f darcs record -Ax -alm foo1 echo bar > b darcs rec -Ax -alm bar1 echo foo2 > f darcs record -Ax -alm foo2 echo bar2 > b darcs record -Ax -alm bar2 darcs unrec --no-deps -p foo1 darcs changes -p foo --count | grep 2 #foo1 is depended upon, we don't unpull it echo y | darcs unrec --dont-prompt-for-dependencies -p foo1 #on the previous line, we don't get asked about foo2. darcs changes -p foo --count | grep 0 #yet, it is unrecorded. darcs changes -p bar --count | grep 2 cd .. rm -rf temp1 darcs-2.8.4/tests/tentative_revert.sh0000644001765600176560000000350712104371431017236 0ustar ganeshganesh#!/usr/bin/env bash ## Test for clearing tentative state after a failed transaction ## ## Copyright (C) 2009 Kamil Dworakowski ## ## 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. set -ev . lib rm -rf R darcs init --repo R touch R/foo darcs record --repo R -lam 'foo' touch R/bar darcs record --repo R -lam 'bar' echo "this change should stay uncommitted" >> R/foo darcs setpref --repo R test false echo 'y' | not darcs amend --repo R -am 'change everything' R/foo --test darcs setpref --repo R test true # if tentative state was not cleared, the previous changes # from failed transaction would piggy back on the next echo "xx" >> R/bar echo 'y' | darcs amend --repo R -am 'bar2' R/bar --test # should have uncommitted changes darcs wh --repo R > changes grep "this change should stay uncommitted" changes darcs-2.8.4/tests/three_way_conflict.sh0000644001765600176560000000103612104371431017507 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp1 temp2 temp3 mkdir -p temp1 temp2 temp3 cd temp1 darcs init cd ../temp2 darcs init cd ../temp3 darcs init touch foo darcs add foo darcs record -a -A author -m add darcs push -a ../temp2 darcs push -a ../temp1 echo A > foo darcs record -a -A author -m AA cd ../temp2 echo B > foo darcs record -a -A author -m BB cd ../temp1 echo C > foo darcs record -a -A author -m CC darcs pull -a ../temp2 darcs pull -a ../temp3 cd ../temp2 darcs pull -a ../temp3 darcs pull -a ../temp1 rm -rf temp1 temp2 temp3 darcs-2.8.4/tests/toolbox.sh0000644001765600176560000000047312104371431015331 0ustar ganeshganesh#!/usr/bin/env bash . lib DIR="`pwd`" abort_windows # set up the repository rm -rf temp1 # another script may have left a mess. mkdir temp1 cd temp1 darcs init touch foo darcs add foo # trick: hitting 'enter' in interactive darcs record echo n/ | tr / \\012 | darcs record cd .. rm -rf temp1 darcs-2.8.4/tests/trackdown-bisect.sh0000644001765600176560000000675512104371431017117 0ustar ganeshganesh#!/bin/env bash # A test for trackdown --bisect option. # In general it construct various repositories and try # to find the last recent failing patch and match it with # expected position. # # It runs the same tests also for the trackdown without # the --bisect. ################################################################ set -ev if echo $OS | grep -i windows; then echo I do not know how to run a test program under windows exit 0 fi ghc -o trackdown-bisect-helper $TESTBIN/trackdown-bisect-helper.hs function make_repo_with_test { rm -fr temp1 mkdir temp1 ; cd temp1 ; darcs init touch ./i touch ./j darcs add ./i darcs add ./j ../trackdown-bisect-helper $1 } function cleanup_repo_after { cd .. rm -fr temp1 } # You can remove --bisect for compare with linear trackdown trackdown_args='--bisect' # Function return true if given patch was found. # It expects that last line has finish with # For the linear it is second last from the end, and last line # is sentence if trackdown failed or succeed. function is_found_good_patch { if [ -z "$trackdown_args" ]; then tail -n 2 | grep " $1\$" else tail -n 1 | grep " $1\$" fi } # Test command - Success condition is that file 'j' have one inside (1) # That means if it has zero (0) it is failing test. test_cmd='grep -q 1 j' ############################################################################# # Section with test-cases ############################################################################# # TEST01: Repo with success in the half testTrackdown() { make_repo_with_test $1 if darcs trackdown $trackdown_args "$test_cmd" | is_found_good_patch $2; then echo "ok 1" else echo "not ok 1. the trackdown should find last failing patch = $2." exit 1 fi cleanup_repo_after } # TEST01: Repo with success in the half test01() { testTrackdown '[1,1,0,0,0]' 3 } # TEST02: Repo with without success condition test02() { testTrackdown '[0,0,0,0,0]' 1 } # TEST03: Repo with with success condition at before last patch test03() { testTrackdown '[1,1,1,1,0]' 5 } # TEST04: Repo with with success condition as first patch ever test04() { testTrackdown '[1,0,0,0,0]' 2 } # TEST05: Long repo with with success condition as first patch ever test05() { testTrackdown '[1,0,0,0,0,0,0,0,0,0,0]' 2 } # TEST06: Long repo with with success condition as sixth patch test06() { testTrackdown '[1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0]' 7 } # TEST07: Long repo with with success condition very nead the head test07() { testTrackdown '[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0]' 54 } # TEST08: Long repo with with success condition very nead the head test08() { testTrackdown '[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0]' 55 } # TEST09: Long repo with non-monotone errors / success distribution # This test only tests that it will not crash... test09() { testTrackdown '[1,1,1,1,1,1,0,0,0,0,1,0,0,1,0,0,0,0,0,0]' 7 } ############################################# # call test-cases for trackdown linear ############################################# trackdown_args='' test01 test02 test03 test04 test05 test06 test07 test08 ############################################# # Call test-cases for trackdown bisect ############################################# trackdown_args='--bisect' test01 test02 test03 test04 test05 test06 test07 test08 test09 # only for --bisect darcs-2.8.4/tests/trailing-newlines.sh0000644001765600176560000000125012104371431017270 0ustar ganeshganesh#!/usr/bin/env bash . lib rm -rf temp && mkdir temp cd temp darcs init echo -n > no_newline echo -n > newline darcs rec -lam "empty" echo -n foo > no_newline echo foo > newline wc -l no_newline | grep 0 wc -l newline | grep 1 darcs wh > diff1 darcs rec -am "add bits" darcs revert -a | grep "no changes" echo -n > no_newline echo -n > newline darcs wh > diff2 darcs rec -lam "bar" darcs revert -a | grep "no changes" darcs check cat > diff1.expected < diff2.expected < temp.c darcs add temp.c darcs record --all -A test --name=hi mkdir d darcs add d darcs mv temp.c d/ darcs record --all -A test --name=mvetc darcs show contents d/temp.c | cmp d/temp.c - echo y/d/y | tr / \\012 | darcs unrecord darcs whatsnew # darcs show contents d/temp.c | cmp d/temp.c - darcs record --all -A test --name=again darcs show contents d/temp.c | cmp d/temp.c - cd .. rm -rf temp darcs-2.8.4/tests/uniqueoptions.sh0000644001765600176560000000120712104371431016561 0ustar ganeshganesh#!/usr/bin/env bash echo echo Checking that each command expects each option only once echo set -ev if echo $OS | grep -i windows; then echo Noone knows how to handle newlines under cygwin, so we skip this test exit 0 fi rm -rf temp1 mkdir temp1 cd temp1 for i in `darcs --commands | grep -v -- -- | xargs echo`; do echo -n Checking $i... ' ' # only output actual command options, i.e. lines that contain a -- darcs $i --help | grep -- "--" | sort > $i uniq $i > uni$i if cmp $i uni$i; then echo passed. else echo failed! diff -c uni$i $i exit 1 fi done cd .. rm -rf temp1 darcs-2.8.4/tests/unpull-formerly-pl.sh0000644001765600176560000000150312104371431017423 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf tempA mkdir tempA cd tempA darcs initialize echo hello world > foo darcs add foo darcs record -a -m hellofoo echo goodbye world >> foo darcs record -a -m goodbyefoo darcs replace world bar foo echo Hi there foo > bar darcs add bar darcs record -a -m addbar darcs mv bar baz darcs replace bar baz foo darcs record -a -m bar2baz echo Do not love the baz, or anything in the baz. >> foo darcs record -a -m nolove darcs mv baz world darcs replace baz world foo darcs record -a -m baz2world darcs whatsnew | grep 'No changes' grep 'love the world' foo echo y | darcs unpull -p baz2world darcs whatsnew | grep 'No changes' grep 'love the baz' foo echo y | darcs unpull -p bar2baz grep 'love the bar' foo echo y | darcs unpull -p nolove grep 'love' foo && exit 1 || true cd .. rm -rf tempA darcs-2.8.4/tests/unpull.sh0000644001765600176560000000036312104371431015160 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp1 mkdir temp1 cd temp1 darcs init cat > f < f < foo darcs add foo darcs whatsnew > correct cat correct darcs record -a -m 'addfoo' darcs unrecord -a darcs whatsnew > unrecorded cat unrecorded diff -u correct unrecorded cd .. rm -rf temp1 darcs-2.8.4/tests/unrecord-setpref.sh0000644001765600176560000000044312104371431017127 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp1 mkdir temp1 cd temp1 darcs init darcs setpref boringfile foobar darcs whatsnew > correct cat correct darcs record -a -m 'boringfoobar' darcs unrecord -a darcs whatsnew > unrecorded cat unrecorded diff -u correct unrecorded cd .. rm -rf temp1 darcs-2.8.4/tests/unrecord-remove.sh0000644001765600176560000000052012104371431016750 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp1 mkdir temp1 cd temp1 darcs init echo foo > foo darcs add foo darcs record -a -m 'addfoo' darcs remove foo darcs whatsnew > correct cat correct darcs record -a -m 'rmfoo' darcs unrecord -a --last 1 darcs whatsnew > unrecorded cat unrecorded diff -u correct unrecorded cd .. rm -rf temp1 darcs-2.8.4/tests/whatsnew-pending.sh0000644001765600176560000000324512104371431017125 0ustar ganeshganesh#!/usr/bin/env bash ## Ensure that darcs whatsnew only lists relevant bits. ## Public Domain, 2010, Petr Rockai ## ## This file is included as part of the Darcs test distribution, ## which is licensed to you under the following terms: ## ## 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. . lib # Load some portability helpers. rm -rf R # Another script may have left a mess. darcs init --repo R # Create our test repos. cd R mkdir d e # Change the working tree. echo 'Example content.' > d/f darcs record -lam 'Add d/f and e.' darcs remove d/f not darcs wh e # | not grep f cd .. darcs-2.8.4/tests/unrevert-add.sh0000644001765600176560000000043712104371431016243 0ustar ganeshganesh#!/usr/bin/env bash . lib rm -rf temp1 mkdir temp1 cd temp1 darcs init echo foo > foo darcs add foo darcs whatsnew > correct cat correct darcs revert -a not darcs whatsnew darcs unrevert -a darcs whatsnew > unrecorded cat unrecorded diff -u correct unrecorded cd .. rm -rf temp1 darcs-2.8.4/tests/unrevert.sh0000644001765600176560000000043012104371431015506 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp1 mkdir temp1 cd temp1 darcs init echo hello world > foo darcs add foo darcs record -a -m add -A x echo goodbye world >> foo cp foo bar darcs revert -a darcs show contents foo | cmp foo - darcs unrevert -a cmp foo bar cd .. rm -rf temp1 darcs-2.8.4/tests/unrevert-replace-moved.sh0000644001765600176560000000070612104371431020235 0ustar ganeshganesh#!/usr/bin/env bash . lib rm -rf temp1 mkdir temp1 cd temp1 darcs init echo hello world > foo darcs add foo darcs record -a -m 'addfoo' darcs replace hello goodbye foo darcs revert -a not darcs whatsnew darcs mv foo bar echo hello my good friends >> bar darcs unrevert -a darcs whatsnew > unrecorded cat unrecorded grep 'bar .* hello goodbye' unrecorded cat bar grep 'goodbye world' bar grep 'goodbye my good friends' bar cd .. rm -rf temp1 darcs-2.8.4/tests/unrevert_cancel.sh0000644001765600176560000000046312104371431017021 0ustar ganeshganesh#!/usr/bin/env bash # From issue366 bug report set -ev rm -rf temp1 mkdir temp1 cd temp1 darcs init touch a touch b darcs add * darcs record -A moi -am init echo plim >> a echo plim >> b echo y/y/y/ | tr / \\012 | darcs revert echo ploum >> a echo nyy | tr / \\012 | darcs unrevert cd .. rm -rf temp1 darcs-2.8.4/tests/v1-braced.sh0000644001765600176560000000314212104371431015403 0ustar ganeshganesh#!/usr/bin/env bash ## Test for correct handling of Darcs v1 patches with nested { } ## ## Copyright (C) 2010 Ganesh Sittampalam ## ## 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. . lib # Load some portability helpers. grep hashed $HOME/.darcs/defaults || exit 200 rm -rf braced gunzip -c $TESTDATA/braced.tgz | tar xf - cd braced darcs check cd .. rm -rf empty mkdir empty cd empty darcs init darcs apply $TESTDATA/braced.dpatch cd .. cd braced darcs pull -a ../empty | grep 'No remote changes to pull in' cd ../empty darcs pull -a ../braced | grep 'No remote changes to pull in'darcs-2.8.4/tests/what_sl.sh0000644001765600176560000000042012104371431015274 0ustar ganeshganesh#!/usr/bin/env bash set -ev rm -rf temp1 mkdir temp1 cd temp1 darcs init touch foo darcs add foo darcs rec -m t1 -a -A tester echo 1 >> foo darcs what -s | grep -v No\ changes darcs what -l | grep -v No\ changes darcs what -sl | grep -v No\ changes cd .. rm -rf temp1 darcs-2.8.4/tests/whatsnew-file.sh0000644001765600176560000000165312104371431016421 0ustar ganeshganesh#!/usr/bin/env bash . lib # Some tests for 'darcs whatsnew ' rm -rf temp1 mkdir temp1 cd temp1 darcs init date > foo mkdir bar echo hello world > bar/baz darcs record -la -m "add foo" echo goodbye world >> bar/baz # goodbye should show up precisely once darcs wh > out cat out grep goodbye out | wc -l | grep 1 darcs wh bar bar/baz > out cat out grep goodbye out | wc -l | grep 1 darcs mv foo bar echo not date > bar/foo darcs wh bar bar/baz > out cat out grep date out | wc -l | grep 1 darcs wh foo > out cat out grep date out | wc -l | grep 1 darcs wh foo foo foo > out cat out grep date out | wc -l | grep 1 darcs wh foo ./foo ../temp1/foo > out cat out grep date out | wc -l | grep 1 darcs wh foo bar/../foo > out cat out grep date out | wc -l | grep 1 # This one fails actually, but it's not my fault. Filed as issue1196. #darcs wh foo foo/../foo/. > out #cat out #grep date out | wc -l | grep 1 cd .. rm -rf temp1 darcs-2.8.4/tests/whatsnew.sh0000644001765600176560000000177412104371431015510 0ustar ganeshganesh#!/usr/bin/env bash . lib # Some tests for 'darcs whatsnew ' rm -rf temp1 temp2 mkdir temp1 cd temp1 # RT#505 whatsnew -s after removal of file without a newline darcs init echo -n foobar > foo darcs record -la -m "add foo" | grep "Finished record" rm -f foo darcs whatsnew -s | grep R darcs record -a -m "remove foo" # RT#245 --look-for-adds implies --summary touch look_summary.txt darcs whatsnew -l | grep -i "a ./look_summary.txt" #whatsnew works with uncommon file names if echo $OS | grep -i windows; then echo test does not work on windows exit 0; else echo foo > \\ darcs add \\ darcs whatsnew | tee log grep 'hunk ./\\92\\' log fi echo foo > "foo bar" darcs add "foo bar" darcs wh | tee log grep 'hunk ./foo\\32\\bar' log # check that filename encoding does not botch up the index darcs rec -am "weird filenames" not darcs wh # whatsnew works with absolute paths DIR="`pwd`" echo date.t > date.t touch date.t darcs add date.t darcs whatsnew "$DIR/date.t" | grep hunk cd .. rm -rf temp1 darcs-2.8.4/tests/workingdir.sh0000644001765600176560000000300112104371431016010 0ustar ganeshganesh#!/usr/bin/env bash . lib # test for working dir woes # the setup... rm -rf temp1 temp2 mkdir temp1 cd temp1 darcs init mkdir a echo temp0 > a/x darcs add a darcs add a/x darcs record -am "aa" darcs mv a/x a/y darcs record -am "x to y" echo temp1 > b darcs add b darcs record -am "bb" mkdir d darcs add d darcs record -am "dd" darcs tag 1 echo 1-b2 > b darcs record -am "b2" cd .. # try to move a file that we don't have the right to do darcs get temp1 temp2 --to-patch aa cd temp2 chmod u-w a darcs pull -a test -e b chmod u+w a cd .. rm -rf temp2 # [issue319] try to overwrite file(s) in our working dir darcs get temp1 temp2 --to-patch aa cd temp2 echo temp2 > b echo temp2 > d darcs pull -a -t 1 grep temp1 b grep temp2 b.~0~ grep temp2 d.~0~ # now make sure we didn't overdo it darcs pull -a grep '1-b2' b test -e b.~0~ test ! -e b.~1~ cd .. rm -rf temp2 # [issue298] backup working dir files with conflicts darcs get temp1 temp2 --tag 1 cd temp2 echo 2-b2 > b darcs pull -a grep "v v v" b grep "2-b2" b.~0~ not grep "v v v" b.~0~ cd .. rm -rf temp2 # [issue440] a) try to overwrite a file in our working dir darcs get temp1 temp2 --to-patch a cd temp2 echo temp2 > a/y echo old-bak > a/y.~0~ darcs pull -a grep temp0 a/y grep old-bak a/y.~0~ grep temp2 a/y.~1~ cd .. rm -rf temp2 # [issue440] b) try to overwrite a directory in our working dir darcs get temp1 temp2 --to-patch a cd temp2 mkdir a/y echo old-bak > a/y.~0~ darcs pull -a grep temp0 a/y grep old-bak a/y.~0~ test -d a/y.~1~ cd .. rm -rf temp2 rm -rf temp1 darcs-2.8.4/tests/xmlschema.sh0000644001765600176560000001056312104371431015625 0ustar ganeshganesh#!/usr/bin/env bash ## Test for XML schema - ## ## Copyright (C) 2011 Radoslav Dorcik ## ## 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. . lib # Load some portability helpers. repod="$TESTDATA/../../" xsdf="$repod/contrib/darcs.xsd" tmpf="changes_tmp.xml" if [ -z "$(which xmllint)" ]; then echo this test does not work on this machine echo it needs xmllint for XML validation. exit 200 fi if [ ! -d "$repod/_darcs" ]; then echo this test does not work on this machine echo it needs source repo exit 200 fi if [ ! -f "$xsdf" ]; then echo this test does not work on this machine echo it needs $(basename $xsdf) exit 200 fi ####################################################### # Test preparation ####################################################### # Create repository with all kind of operations darcs init --repo R # Create our test repos. cd R # Add File and Dir mkdir dir1 dir2 echo "Example content." > dir1/file1 echo "Example content." > dir2/file2 darcs record -lam 'Add dir1 and dir2' # Modify (add) echo "Example content." >> dir1/file1 echo "Example content." >> dir2/file2 echo "Example content." >> dir1/file1 echo "Example content." >> dir2/file2 darcs record -lam 'Modify dir1 and dir2 (add)' # Modify (add,del) echo "Example content." > dir1/file1 echo "Example content." > dir2/file2 echo "Example contentx." >> dir1/file1 echo "Example contentx." >> dir2/file2 darcs record -lam 'Modify dir1 and dir2 (add,del)' # Replace darcs replace contentx contenty dir1/file1 dir2/file2 darcs record -lam 'Replace contentx contenty' # Modify (del) echo "Example content." > dir1/file1 echo "Example content." > dir2/file2 darcs record -lam 'Modify dir1 and dir2 (del)' # Moving darcs mv dir1 dir11 darcs mv dir2 dir22 darcs record -lam 'Move dir1 and dir2' # Remove rm -fr dir11 rm -fr dir22 darcs record -lam 'Remove dir1 and dir2' # Complex patch Replace and Modify, Add and Delete mkdir dir3 dir4 echo "Example contentx." >> dir3/file3 echo "Example contentx." >> dir3/file3 echo "Example contentx." >> dir3/file3 echo "Example contentz." >> dir3/file3 echo "Example contentx." >> dir4/file4 darcs record -lam 'Complex patch (prep)' darcs replace contentx contenty dir3/file3 mkdir dir5 echo "Example contentx." >> dir5/file4 darcs mv dir3 dir7 echo "Example contentx." >> dir7/file3 darcs record -lam 'Complex patch (done)' rm -fr dir4 cd .. ####################################################### # Testing ####################################################### # Darcs produces XMLs with non-UTF8 characters. echo '' > $tmpf darcs log -s --xml-output --repodir=R >> $tmpf xmllint --noout --schema $xsdf $tmpf || exit 1 echo '' > $tmpf darcs log --xml-output --repodir=R >> $tmpf xmllint --noout --schema $xsdf $tmpf || exit 1 exit 0; # Comment this out for next long running tests ## Next tests are disabled by default because they are long running (~10 minutes) ## But they are be helpfull for manual verifications echo '' > $tmpf darcs log --xml-output -s --repodir=$repod >> $tmpf xmllint --noout --schema $xsdf $tmpf || exit 1 darcs-2.8.4/tests/issue2199-get-dirty-tag.sh0000644001765600176560000000301612104371431017773 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue2199 - "darcs get --tag" gets too much if the tag is dirty. ## ## Copyright (C) 2012 Ganesh Sittampalam ## ## 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. . lib darcs init --repo R cd R echo 'wibble' > file darcs rec -lam 'wibble' echo 'wobble' > file darcs rec -lam 'wobble' cd .. darcs get R R-temp cd R-temp darcs unpull --patch 'wobble' -a darcs tag 'wibble' cd .. cd R darcs pull ../R-temp -a cd .. darcs get --tag wibble R R-tag cd R-tag darcs changes | not grep wobble darcs-2.8.4/tests/issue2286-metadata-encoding.sh0000644001765600176560000000250312104371431020653 0ustar ganeshganesh#!/usr/bin/env bash ## Test for issue2286 - darcs cha fails when reading non-UTF8 encoded ## metadata ## ## Copyright (C) 2012 Ganesh Sittampalam ## ## 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. . lib switch_to_utf8_locale gunzip -c $TESTDATA/metadata-encoding.tgz | tar xf - cd metadata-encoding darcs changes darcs-2.8.4/tests/README.test_maintainers.txt0000644001765600176560000001137412104371431020357 0ustar ganeshganesh The following is provided as a reference for those interested in understanding how the test suite works, and how to add and maintain tests. Overview of types of tests ========================== Darcs has tests in two formats. Unit tests that directly test Haskell functions are written in Haskell and live in modules under src/Darcs/Test. Functional tests that test the darcs binary are written in Shell and live in tests/. Haskell tests -------------------------- These are QuickCheck and HUnit tests primarily testing the Darcs core. The Haskell modules containing these tests are under Darcs.Test in the module hierarchy. They are called from src/unit.lhs using the test-framework package from Hackage. More about the Haskell tests can be found on http://wiki.darcs.net/Development/UnitTests. Shell tests --------------------------- Shell tests are useful because they are easy to create from a copy/paste of actual shell commands executed. They are considered successful if no bad exit codes are returned from the commands in the script. If the name of the script file starts with 'failing-' however, the script is expected to return a bad exit code. If such a script returns a bad exit code, this will not be treated as a test suite failure. This is useful to document bugs and to-do items. How to run tests ============================= To build the unit tests, pass the "-ftest" flag to "cabal configure" and then do "cabal build". To run them, do "dist/build/unit/unit". They take a while. Output like "[OK]" and "[OK, passed 100 tests]" is good. Output like "Arguments exhausted after 33 tests" is a shortage of QuickCheck test cases, not a test failure. "runghc Setup.lhs test" causes all the functional tests in "tests/" to be run against repositories in the old, hashed, and darcs2 formats. Because "runghc Setup.lhs test" can take a long time to run, it's useful to run fewer tests at once. To help with that, 'runghc Setup.lhs test' accepts arguments to run only a specific group of test scripts, or only named test scripts: runghc Setup.lhs test tests # all tests, excluding bugs or network tests runghc Setup.lhs test bugs # all bugs (the 'failing-' scripts) runghc Setup.lhs test network # the network tests # and this one runs tests/issue279_get_extra.sh and tests/repair_corrupt.sh runghc Setup.lhs test issue279_get_extra repair-corrupt Tips for writing (and reading) tests ==================================== - Avoid including a repo format type to "darcs init" This insures that all three repo formats will be tested. However, if you know that the test only passes under some repo formats, *do* explicitly include a format option to "darcs init". Tips for writing tests ---------------------- - Copy EXAMPLE.sh as a template to start from (don't forget to customise the headers!). - Simply call darcs using "darcs" as you would in the shell. It is the responsibility of the test harness to ensure that the darcs we are testing is first in the path. - Always use Bash explicitly - this improves the portability of our tests. - Always add this near the top of the script: set -ev The "v" causes the contents of the script to be printed as part of the run, which is helpful for debugging. The "e" causes the script to exit as soon as there is an error. - Try to avoid defining functions where possible. This makes them harder to run and generally harder to use. There are certainly cases where it is appropriate to define a function, but please do not do this just to avoid a little duplication. - Also try to be careful using certain utilities; 'yes' is prohibited since it can cause infinite loops on Mac OS X; 'find' can be very useful, but options and behavior can differ from GNU find to the BSD finds to Solaris's find and so on. In general, stick to POSIX flags and functionality. - There is a utility script intended for factoring out common calls and functions, called 'lib'. It can be invoked by adding a line like '. lib' to your shell script. lib provides 'set -ev', a common definition of 'not', and 'abort_windows' for use in scripts which shouldn't run under Windows. You don't have to use lib if you don't want to, or if it causes problems. - If you need to skip a test for any reason, the darcs-specific convention is to "exit 200". This alerts the shell harness that the test was explicitly skipped and not passed. - You can use the trap feature from bash to make ensure that darcs executes some command even if the test fails. Trapping ERR lets you have your last word just before a test fails. Trapping EXIT lets you do the same before any sort of explicit exit (such as the explicit 'exit 1' in the 'not' helper function). For more details, see the bash man page or just grep trap in the test suite. darcs-2.8.4/GNUmakefile0000644001765600176560000000412412104371431014214 0ustar ganeshganesh### XXX we eventually want building of the manual to be part of Setup.lhs # hardcode some bits RUBBER=rubber DARCS = dist/build/darcs/darcs PREPROC=./dist/build/darcs/darcs --preprocess-manual PREPROCHTML=--html TEXSOURCES = doc/src/darcs.tex $(wildcard doc/src/*.tex) $(filter %.lhs,$(DARCS_FILES)) doc/manual/darcs.tex: $(TEXSOURCES) $(DARCS) mkdir -p doc/manual $(PREPROC) darcs.tex $(PREPROCHTML) >$@ doc/manual/darcs_print.tex: $(TEXSOURCES) $(DARCS) mkdir -p doc/manual $(PREPROC) darcs.tex >$@ %.pdf: %.tex cd $(), (<.>), splitDirectories, isAbsolute ) import Foreign.Marshal.Utils ( with ) import Foreign.Storable ( peek ) import Foreign.Ptr ( castPtr ) import Data.Word ( Word8, Word32 ) import qualified Control.Exception as Exception -- Handle exceptions migration. We could use extensible-exceptions -- but Cabal can't handle package dependencies of Setup.lhs -- automatically so it'd be disruptive for users. -- Once we drop older GHCs we can clean up the use sites properly -- and perhaps think about being more restrictive in which exceptions -- are caught at each site. #if __GLASGOW_HASKELL__ >= 610 catchAny f h = Exception.catch f (\e -> h (e :: Exception.SomeException)) #else catchAny = Exception.catch #endif main :: IO () main = defaultMainWithHooks simpleUserHooks { buildHook = \ pkg lbi hooks flags -> let verb = fromFlag $ buildVerbosity flags in commonBuildHook buildHook pkg lbi hooks verb >>= ($ flags), haddockHook = \ pkg lbi hooks flags -> let verb = fromFlag $ haddockVerbosity flags in commonBuildHook haddockHook pkg lbi hooks verb >>= ($ flags) , postBuild = \ _ _ _ lbi -> buildManpage lbi, postCopy = \ _ flags pkg lbi -> installManpage pkg lbi (fromFlag $ copyVerbosity flags) (fromFlag $ copyDest flags), postInst = \ _ flags pkg lbi -> installManpage pkg lbi (fromFlag $ installVerbosity flags) NoCopyDest, runTests = \ args0 _ _ lbi -> do cwd <- getCurrentDirectory let isabs = isAbsolute $ buildDir lbi builddir = (if isabs then id else (cwd )) $ buildDir lbi darcs = builddir "darcs" "darcs" <.> exeExtension darcstest = builddir "darcs-test" "darcs-test" <.> exeExtension (flags, args1) = partition ('=' `elem`) args0 (what', args2) = partition (`elem` ["bugs", "network", "tests", "unit"]) args1 what = if null what' then ["tests"] else what' opts = [ "--darcs", darcs ] ++ concat [ ["-t", x] | x <- args2 ] ++ [ "--no-unit" | "unit" `notElem` what] ++ [ "--network" | "network" <- what ] ++ [ "--failing" | "bugs" <- what ] ++ [ "--no-shell" | _ <- [()], "tests" `notElem` what ] ++ [ "--threads=" ++ drop 8 t | t <- flags, "threads" `isPrefixOf` t ] ++ [ "--plain" | "output=plain" <- flags ] rawSystem darcstest opts >>= exitWith , sDistHook = \ pkg lbi hooks flags -> do let pkgVer = packageVersion pkg verb = fromFlag $ sDistVerbosity flags x <- versionPatches verb pkgVer y <- context verb pkgVer rewriteFile "release/distributed-version" $ show x rewriteFile "release/distributed-context" $ show y putStrLn "about to hand over" let pkg' = pkg { library = sanity (library pkg) } sanity (Just lib) = Just $ lib { libBuildInfo = sanity' $ libBuildInfo lib } sanity _ = error "eh" sanity' bi = bi { otherModules = [ m | m <- otherModules bi, toFilePath m /= "Version" ] } sDistHook simpleUserHooks pkg' lbi hooks flags , confHook = if buildOS == Windows then confHook simpleUserHooks else \genericDescript flags -> do lbi <- confHook simpleUserHooks genericDescript flags let pkgDescr = localPkgDescr lbi let Just lib = library pkgDescr let bi = libBuildInfo lib bi' <- maybeSetLibiconv flags bi lbi return lbi {localPkgDescr = pkgDescr { library = Just lib { libBuildInfo = bi'}}} } -- | For @./Setup build@ and @./Setup haddock@, do some unusual -- things, then invoke the base behaviour ("simple hook"). commonBuildHook :: (UserHooks -> PackageDescription -> LocalBuildInfo -> t -> a) -> PackageDescription -> LocalBuildInfo -> t -> Verbosity -> IO a commonBuildHook runHook pkg lbi hooks verbosity = do (version, state) <- determineVersion verbosity pkg -- Create our own context file. generateVersionModule verbosity pkg lbi version state -- Add custom -DFOO[=BAR] flags to the cpp (for .hs) and cc (for .c) -- invocations, doing a dance to make the base hook aware of them. littleEndian <- testEndianness let args = ("-DPACKAGE_VERSION=" ++ show' version) : ("-DPACKAGE_VERSION_STATE=" ++ show' state) : [arg | (arg, True) <- -- include fst iff snd. [("-DHAVE_HTTP", "x-have-http" `elem` customFields), ("-DUSE_COLOR", "x-use-color" `elem` customFields), -- We have MAPI iff building on/for Windows. ("-DHAVE_MAPI", buildOS == Windows), ("-DBIGENDIAN", not littleEndian)]] bi = emptyBuildInfo { cppOptions = args, ccOptions = args } hbi = (Just bi, [(exeName exe, bi) | exe <- executables pkg]) pkg' = updatePackageDescription hbi pkg lbi' = lbi { localPkgDescr = pkg' } return $ runHook simpleUserHooks pkg' lbi' hooks where customFields = map fst . customFieldsBI . buildInfo $ darcsExe darcsExe = head [e | e <- executables pkg, exeName e == "darcs"] show' :: String -> String -- Petr was worried that we might show' = show -- allow non-String arguments. testEndianness :: IO Bool testEndianness = with (1 :: Word32) $ \p -> do o <- peek $ castPtr p return $ o == (1 :: Word8) buildManpage :: LocalBuildInfo -> IO () buildManpage lbi = do let darcs = buildDir lbi "darcs/darcs" manpage = buildDir lbi "darcs/darcs.1" manpageHandle <- openFile manpage WriteMode runProcess darcs ["help","manpage"] Nothing Nothing Nothing (Just manpageHandle) Nothing return () installManpage :: PackageDescription -> LocalBuildInfo -> Verbosity -> CopyDest -> IO () installManpage pkg lbi verbosity copy = copyFiles verbosity (mandir (absoluteInstallDirs pkg lbi copy) "man1") [(buildDir lbi "darcs", "darcs.1")] determineVersion :: Verbosity -> PackageDescription -> IO (String, String) determineVersion verbosity pkg = do let darcsVersion = packageVersion pkg numPatches <- versionPatches verbosity darcsVersion return (display darcsVersion, versionStateString numPatches darcsVersion) where versionStateString :: Maybe Int -> Version -> String versionStateString Nothing _ = "unknown" versionStateString (Just 0) v = case versionBranch v of x | 97 `elem` x -> "alpha " ++ show (after 97 x) | 98 `elem` x -> "beta " ++ show (after 98 x) | 99 `elem` x -> "release candidate " ++ show (after 99 x) _ -> "release" versionStateString (Just 1) _ = "+ 1 patch" versionStateString (Just n) _ = "+ " ++ show n ++ " patches" after w (x:r) | w == x = head r | otherwise = after w r after _ [] = undefined versionPatches :: Verbosity -> Version -> IO (Maybe Int) versionPatches verbosity darcsVersion = do numPatchesDarcs <- do out <- rawSystemStdout verbosity "darcs" ["changes", "-a", "--from-tag", display darcsVersion, "--count"] case reads (out) of ((n,_):_) -> return $ Just ((n :: Int) - 1) _ -> return Nothing `catchAny` \_ -> return Nothing numPatchesDist <- parseFile versionFile return $ case (numPatchesDarcs, numPatchesDist) of (Just x, _) -> Just x (Nothing, Just x) -> Just x (Nothing, Nothing) -> Nothing where versionFile = "release/distributed-version" generateVersionModule :: Verbosity -> PackageDescription -> LocalBuildInfo -> String -> String -> IO () generateVersionModule verbosity pkg lbi version state = do let dir = autogenModulesDir lbi createDirectoryIfMissingVerbose verbosity True dir ctx <- context verbosity (packageVersion pkg) rewriteFile (dir "Version.hs") $ unlines ["module Version where" ,"builddeps, version, context :: String" ,"version = \"" ++ version ++ " (" ++ state ++ ")\"" ,"builddeps = " ++ (show $ formatdeps (externalPackageDeps lbi)) ,"context = " ++ case ctx of Just x -> show x Nothing -> show "context not available" ] where formatdeps = unlines . map (formatone . snd) formatone p = case packageName p of PackageName n -> n ++ "-" ++ showVersion (packageVersion p) context :: Verbosity -> Version -> IO (Maybe String) context verbosity version = do contextDarcs <- do inrepo <- doesDirectoryExist "_darcs" unless inrepo $ fail "Not a repository." out <- rawSystemStdout verbosity "darcs" ["changes", "-a", "--context"] return $ Just out `catchAny` \_ -> return Nothing contextDist <- parseFile contextFile return $ case (contextDarcs, contextDist) of (Just x, _) -> Just x (Nothing, Just x) -> Just x (Nothing, Nothing) -> Nothing where contextFile = "release/distributed-context" parseFile :: (Read a) => String -> IO (Maybe a) parseFile f = do exist <- doesFileExist f if exist then do content <- readFile f -- ^ ratify readFile: we don't care here. case reads content of ((s,_):_) -> return s _ -> return Nothing else return Nothing -- Test whether compiling a c program that links against libiconv needs -liconv. maybeSetLibiconv :: ConfigFlags -> BuildInfo -> LocalBuildInfo -> IO BuildInfo maybeSetLibiconv flags bi lbi = do let biWithIconv = addIconv bi let verb = fromFlag (configVerbosity flags) if hasFlagSet flags (FlagName "libiconv") then do putStrLn "Using -liconv." return biWithIconv else do putStr "checking whether to use -liconv... " hFlush stdout worksWithout <- tryCompile iconv_prog bi lbi verb if worksWithout then do putStrLn "not needed." return bi else do worksWith <- tryCompile iconv_prog biWithIconv lbi verb if worksWith then do putStrLn "using -liconv." return biWithIconv else error "Unable to link against the iconv library." hasFlagSet :: ConfigFlags -> FlagName -> Bool hasFlagSet cflags flag = Just True == lookup flag (configConfigurationsFlags cflags) tryCompile :: String -> BuildInfo -> LocalBuildInfo -> Verbosity -> IO Bool tryCompile program bi lbi verb = handle processExit $ handle processException $ do tempDir <- getTemporaryDirectory withTempFile tempDir ".c" $ \fname cH -> withTempFile tempDir "" $ \execName oH -> do hPutStr cH program hClose cH hClose oH -- TODO take verbosity from the args. rawSystemProgramStdoutConf verb gccProgram (withPrograms lbi) (fname : "-o" : execName : args) return True where processException :: IOException -> IO Bool processException e = return False processExit = return . (==ExitSuccess) -- Mimicing Distribution.Simple.Configure deps = topologicalOrder (installedPkgs lbi) args = concat [ ccOptions bi , cppOptions bi , ldOptions bi -- --extra-include-dirs and --extra-lib-dirs are included -- in the below fields. -- Also sometimes a dependency like rts points to a nonstandard -- include/lib directory where iconv can be found. , map ("-I" ++) (includeDirs bi ++ concatMap Installed.includeDirs deps) , map ("-L" ++) (extraLibDirs bi ++ concatMap Installed.libraryDirs deps) , map ("-l" ++) (extraLibs bi) ] addIconv :: BuildInfo -> BuildInfo addIconv bi = bi {extraLibs = "iconv" : extraLibs bi} iconv_prog :: String iconv_prog = unlines $ [ "#include " , "int main(void) {" , " iconv_t t = iconv_open(\"UTF-8\", \"UTF-8\");" , " return 0;" , "}" ] \end{code} darcs-2.8.4/darcs.cabal0000644001765600176560000006476712104371431014245 0ustar ganeshganeshName: darcs version: 2.8.4 License: GPL License-file: COPYING Author: David Roundy , Maintainer: Stability: Experimental Category: Development Synopsis: a distributed, interactive, smart revision control system Description: Darcs is a free, open source revision control system. It is: . * Distributed: Every user has access to the full command set, removing boundaries between server and client or committer and non-committers. . * Interactive: Darcs is easy to learn and efficient to use because it asks you questions in response to simple commands, giving you choices in your work flow. You can choose to record one change in a file, while ignoring another. As you update from upstream, you can review each patch name, even the full "diff" for interesting patches. . * Smart: Originally developed by physicist David Roundy, darcs is based on a unique algebra of patches. . This smartness lets you respond to changing demands in ways that would otherwise not be possible. Learn more about spontaneous branches with darcs. Homepage: http://darcs.net/ Build-Type: Custom Cabal-Version: >= 1.8 extra-source-files: -- C headers src/*.h src/Crypt/sha2.h src/win32/send_email.h src/win32/sys/mman.h -- The contrib directory would make a sensible 'darcs-contrib' package contrib/_darcs.zsh, contrib/darcs_completion, contrib/cygwin-wrapper.bash, contrib/update_roundup.pl, contrib/upload.cgi, contrib/darcs-errors.hlint, -- documentation files doc/src/best_practices.tex, doc/src/building_darcs.tex, doc/src/configuring_darcs.tex, doc/src/features.tex, doc/src/gpl.tex, doc/src/darcs.tex doc/darcs.css README, NEWS -- release data release/distributed-version, release/distributed-context -- testsuite tests/data/*.tgz tests/data/README tests/data/*.dpatch tests/data/convert/darcs1/*.dpatch tests/data/convert/darcs2/*.dpatch tests/*.sh tests/bin/trackdown-bisect-helper.hs tests/bin/hspwd.hs tests/network/*.sh tests/lib tests/data/example_binary.png tests/README.test_maintainers.txt GNUmakefile source-repository head type: darcs location: http://darcs.net/ flag curl description: Use libcurl for HTTP support. flag http description: Use the pure Haskell HTTP package for HTTP support. flag static description: Build static binary default: False flag terminfo description: Use the terminfo package for enhanced console support. flag threaded description: Use threading and SMP support. default: True flag library description: Build darcs library default: True flag executable description: Build darcs executable default: True flag color description: Use ansi color escapes. flag mmap description: Compile with mmap support. flag hpc default: False flag test default: False description: Build test harness -- We need optimizations by default, regardless of what Hackage says flag optimize default: True description: Build with optimizations (-O2) flag warn-as-error default: False description: Build with warnings-as-errors -- If base >= 4.4 is used, the standard directory functions -- do Unicode translation. Use a flag so we can -- detect this situation and use a workaround. flag force-char8-encoding default: False description: Allow base 4.5 or above on Unix. base 4.4 introduces a change in the behaviour of filenames that requires API calls in base 4.5 to workaround. So base 4.4 is not supported at all. -- Note that the Setup script checks whether -liconv is necessary. This flag -- lets us override that decision. When it is True, we use -liconv. When it -- is False, we run tests to decide. flag libiconv Description: Explicitly link against the libiconv library. Default: False -- ---------------------------------------------------------------------- -- darcs library -- ---------------------------------------------------------------------- Library if !flag(library) buildable: False else buildable: True build-tools: ghc >= 6.10 && < 7.8 hs-source-dirs: src include-dirs: src cpp-options: -DGADT_WITNESSES=1 exposed-modules: CommandLine Crypt.SHA256 Darcs.Annotate Darcs.ArgumentDefaults Darcs.Arguments Darcs.Bug Darcs.ColorPrinter Darcs.Commands Darcs.Commands.Add Darcs.Commands.AmendRecord Darcs.Commands.Annotate Darcs.Commands.Apply Darcs.CommandsAux Darcs.Commands.Changes Darcs.Commands.Check Darcs.Commands.Convert Darcs.Commands.Diff Darcs.Commands.Dist Darcs.Commands.Get Darcs.Commands.GZCRCs Darcs.Commands.Help Darcs.Commands.Init Darcs.Commands.MarkConflicts Darcs.Commands.Move Darcs.Commands.Optimize Darcs.Commands.Pull Darcs.Commands.Push Darcs.Commands.Put Darcs.Commands.Record Darcs.Commands.Remove Darcs.Commands.Replace Darcs.Commands.Revert Darcs.Commands.Rollback Darcs.Commands.Send Darcs.Commands.SetPref Darcs.Commands.Show Darcs.Commands.ShowAuthors Darcs.Commands.ShowBug Darcs.Commands.ShowContents Darcs.Commands.ShowFiles Darcs.Commands.ShowIndex Darcs.Commands.ShowRepo Darcs.Commands.ShowTags Darcs.Commands.Tag Darcs.Commands.Test Darcs.Commands.TrackDown Darcs.Commands.TransferMode Darcs.Commands.Util Darcs.Commands.Unrecord Darcs.Commands.Unrevert Darcs.Commands.WhatsNew Darcs.Compat Darcs.Diff Darcs.Email Darcs.External Darcs.Flags Darcs.Global Darcs.IO Darcs.Lock Darcs.Match Darcs.MonadProgress Darcs.Patch Darcs.Patch.Apply Darcs.Patch.ApplyMonad Darcs.Patch.Bracketed Darcs.Patch.Bracketed.Instances Darcs.Patch.Bundle Darcs.Patch.Choices Darcs.Patch.Commute Darcs.Patch.Conflict Darcs.Patch.ConflictMarking Darcs.Patch.Depends Darcs.Patch.Dummy Darcs.Patch.Effect Darcs.Patch.FileName Darcs.Patch.FileHunk Darcs.Patch.Format Darcs.Patch.Info Darcs.Patch.Inspect Darcs.Patch.Invert Darcs.Patch.Match Darcs.Patch.MatchData Darcs.Patch.Merge Darcs.Patch.Named Darcs.Patch.OldDate Darcs.Patch.PatchInfoAnd Darcs.Patch.Patchy Darcs.Patch.Patchy.Instances Darcs.Patch.Permutations Darcs.Patch.Prim Darcs.Patch.Prim.Class Darcs.Patch.Prim.V1 Darcs.Patch.Prim.V1.Apply Darcs.Patch.Prim.V1.Coalesce Darcs.Patch.Prim.V1.Commute Darcs.Patch.Prim.V1.Core Darcs.Patch.Prim.V1.Details Darcs.Patch.Prim.V1.Read Darcs.Patch.Prim.V1.Show Darcs.Patch.Prim.V3 Darcs.Patch.Prim.V3.ObjectMap Darcs.Patch.Prim.V3.Apply Darcs.Patch.Prim.V3.Coalesce Darcs.Patch.Prim.V3.Commute Darcs.Patch.Prim.V3.Core Darcs.Patch.Prim.V3.Details Darcs.Patch.Prim.V3.Read Darcs.Patch.Prim.V3.Show Darcs.Patch.Read Darcs.Patch.ReadMonads Darcs.Patch.RegChars Darcs.Patch.Repair Darcs.Patch.RepoPatch Darcs.Patch.Set Darcs.Patch.Show Darcs.Patch.Split Darcs.Patch.Summary Darcs.Patch.SummaryData Darcs.Patch.TokenReplace Darcs.Patch.TouchesFiles Darcs.Patch.Viewing Darcs.Patch.V1 Darcs.Patch.V1.Apply Darcs.Patch.V1.Commute Darcs.Patch.V1.Core Darcs.Patch.V1.Read Darcs.Patch.V1.Show Darcs.Patch.V1.Viewing Darcs.Patch.V2 Darcs.Patch.V2.Non Darcs.Patch.V2.Real Darcs.PrintPatch Darcs.ProgressPatches Darcs.RemoteApply Darcs.RepoPath Darcs.Repository Darcs.Repository.ApplyPatches Darcs.Repository.Cache Darcs.Repository.Format Darcs.Repository.HashedIO Darcs.Repository.HashedRepo Darcs.Repository.Internal Darcs.Repository.LowLevel Darcs.Repository.Merge Darcs.Repository.InternalTypes Darcs.Repository.Motd Darcs.Repository.Old Darcs.Repository.Prefs Darcs.Repository.Repair Darcs.Repository.State Darcs.Resolution Darcs.RunCommand Darcs.SelectChanges Darcs.SignalHandler Darcs.Ssh Darcs.Test Darcs.TheCommands Darcs.URL Darcs.Utils Darcs.Witnesses.Eq Darcs.Witnesses.Ordered Darcs.Witnesses.Sealed Darcs.Witnesses.Show Darcs.Witnesses.Unsafe Darcs.Witnesses.WZipper DateMatcher Encoding English Exec ByteStringUtils IsoDate Lcs Printer Progress Ratified SHA1 URL URL.Request URL.HTTP Workaround other-modules: Version URL.Curl c-sources: src/atomic_create.c src/fpstring.c src/maybe_relink.c src/umask.c src/Crypt/sha2.c src/system_encoding.c cc-options: -D_REENTRANT if os(windows) hs-source-dirs: src/win32 include-dirs: src/win32 other-modules: CtrlC Encoding.Win32 System.Posix System.Posix.Files System.Posix.IO cpp-options: -DWIN32 c-sources: src/win32/send_email.c build-depends: unix-compat >= 0.1.2, Win32 >= 2.0, regex-posix >= 0.95.1 else other-modules: Encoding.IConv c-sources: src/h_iconv.c build-depends: utf8-string >= 0.3.6 && < 0.4 if os(solaris) cc-options: -DHAVE_SIGINFO_H if os(windows) build-depends: base >= 4 && < 4.7 else if flag(force-char8-encoding) build-depends: base >= 4.5 && < 4.7 cpp-options: -DFORCE_CHAR8_ENCODING else build-depends: base >= 4 && < 4.4 build-depends: extensible-exceptions >= 0.1 && < 0.2, regex-compat >= 0.95.1, mtl >= 1.0 && < 2.2, parsec >= 2.0 && < 3.2, html == 1.0.*, filepath >= 1.1.0.0 && < 1.5.0.0, haskeline >= 0.6.3 && < 0.8, hashed-storage >= 0.5.6 && < 0.6, vector >= 0.7, tar >= 0.3 && < 0.5 if impl(ghc<7.0) -- haskeline 0.6.4.7 doesn't build with ghc 6.12 build-depends: haskeline <= 0.6.4.6 if !os(windows) build-depends: unix >= 1.0 && < 2.7 build-depends: bytestring >= 0.9.0 && < 0.11, text >= 0.11.0.6 && < 0.12.0.0, old-time >= 1.0 && < 1.2, directory >= 1.0.0.0 && < 1.3.0.0, process >= 1.0.0.0 && < 1.2.0.0, containers >= 0.1 && < 0.6, array >= 0.1 && < 0.5, random == 1.0.* if flag(optimize) ghc-options: -O2 else ghc-options: -O0 if flag(warn-as-error) ghc-options: -Werror -- Note: "if true" works around a cabal bug with order of flag composition if true ghc-options: -Wall -funbox-strict-fields -fwarn-tabs ghc-prof-options: -prof -auto-all if flag(hpc) ghc-prof-options: -fhpc -hpcdir dist/hpc/libdarcs if flag(curl) extra-libraries: curl includes: curl/curl.h cpp-options: -DHAVE_CURL c-sources: src/hscurl.c cc-options: -DHAVE_CURL if flag(http) build-depends: network >= 2.2 && < 2.5, HTTP >= 4000.0.8 && < 4000.3 cpp-options: -DHAVE_HTTP x-have-http: if (!flag(curl) && !flag(http)) buildable: False if flag(mmap) && !os(windows) build-depends: mmap >= 0.5 && < 0.6 cpp-options: -DHAVE_MMAP build-depends: zlib >= 0.5.1.0 && < 0.6.0.0 -- The terminfo package cannot be built on Windows. if flag(terminfo) && !os(windows) build-depends: terminfo == 0.3.* cpp-options: -DHAVE_TERMINFO if flag(color) x-use-color: -- if true to work around cabal bug with flag ordering if true extensions: CPP BangPatterns PatternGuards GADTs TypeOperators FlexibleContexts FlexibleInstances ScopedTypeVariables KindSignatures RankNTypes TypeFamilies if impl(ghc>=7.0) extensions: NoMonoLocalBinds if impl(ghc>=7.6) -- in ghc < 7.6 we need to import Prelude hiding (catch) -- in ghc >= 7.6 catch isn't in Prelude ghc-options: -fno-warn-dodgy-imports -- ---------------------------------------------------------------------- -- darcs itself -- ---------------------------------------------------------------------- Executable darcs if !flag(executable) buildable: False else buildable: True build-tools: ghc >= 6.10 && < 7.8 main-is: darcs.hs hs-source-dirs: src include-dirs: src c-sources: src/atomic_create.c src/fpstring.c src/maybe_relink.c src/umask.c src/Crypt/sha2.c src/system_encoding.c if flag(optimize) ghc-options: -O2 else ghc-options: -O0 if flag(warn-as-error) ghc-options: -Werror -- Note: "if true" works around a cabal bug with order of flag composition if true ghc-options: -Wall -funbox-strict-fields -fwarn-tabs ghc-prof-options: -prof -auto-all if flag(threaded) ghc-options: -threaded if flag(static) ghc-options: -static -optl-static -optl-pthread if flag(hpc) ghc-prof-options: -fhpc -hpcdir dist/hpc/darcs cc-options: -D_REENTRANT if os(windows) hs-source-dirs: src/win32 include-dirs: src/win32 other-modules: CtrlC System.Posix System.Posix.Files System.Posix.IO Preproc cpp-options: -DWIN32 c-sources: src/win32/send_email.c build-depends: unix-compat >= 0.1.2, Win32 >= 2.0, regex-posix >= 0.95.1 else c-sources: src/h_iconv.c build-depends: utf8-string >= 0.3.6 && < 0.4 -- need to list this explicitly to get cabal to run hsc2hs other-modules: Encoding.IConv if os(solaris) cc-options: -DHAVE_SIGINFO_H if os(windows) build-depends: base >= 4 && < 4.7 else if flag(force-char8-encoding) build-depends: base >= 4.5 && < 4.7 cpp-options: -DFORCE_CHAR8_ENCODING else build-depends: base >= 4 && < 4.4 build-depends: extensible-exceptions >= 0.1 && < 0.2, regex-compat >= 0.95.1, mtl >= 1.0 && < 2.2, parsec >= 2.0 && < 3.2, html == 1.0.*, filepath >= 1.1.0.0 && < 1.5.0.0, haskeline >= 0.6.3 && < 0.8, hashed-storage >= 0.5.6 && < 0.6, vector >= 0.7, tar >= 0.3 && < 0.5 if impl(ghc<7.0) -- haskeline 0.6.4.7 doesn't build with ghc 6.12 build-depends: haskeline <= 0.6.4.6 if !os(windows) build-depends: unix >= 1.0 && < 2.7 build-depends: bytestring >= 0.9.0 && < 0.11, text >= 0.11.0.6 && < 0.12.0.0, old-time >= 1.0 && < 1.2, directory >= 1.0.0.0 && < 1.3.0.0, process >= 1.0.0.0 && < 1.2.0.0, containers >= 0.1 && < 0.6, array >= 0.1 && < 0.5, random == 1.0.* if flag(curl) extra-libraries: curl includes: curl/curl.h cpp-options: -DHAVE_CURL c-sources: src/hscurl.c cc-options: -DHAVE_CURL if flag(http) build-depends: network >= 2.2 && < 2.5, HTTP >= 4000.0.8 && < 4000.3 cpp-options: -DHAVE_HTTP x-have-http: if (!flag(curl) && !flag(http)) buildable: False if flag(mmap) && !os(windows) build-depends: mmap >= 0.5 && < 0.6 cpp-options: -DHAVE_MMAP build-depends: zlib >= 0.5.1.0 && < 0.6.0.0 -- The terminfo package cannot be built on Windows. if flag(terminfo) && !os(windows) build-depends: terminfo == 0.3.* cpp-options: -DHAVE_TERMINFO if flag(color) x-use-color: -- if true to work around cabal bug with flag ordering if true extensions: CPP BangPatterns PatternGuards GADTs TypeOperators FlexibleContexts FlexibleInstances ScopedTypeVariables KindSignatures RankNTypes TypeFamilies if impl(ghc>=7.0) extensions: NoMonoLocalBinds if impl(ghc>=7.6) -- in ghc < 7.6 we need to import Prelude hiding (catch) -- in ghc >= 7.6 catch isn't in Prelude ghc-options: -fno-warn-dodgy-imports -- ---------------------------------------------------------------------- -- unit test driver -- ---------------------------------------------------------------------- Executable darcs-test main-is: test.hs build-tools: ghc >= 6.10 && < 7.8 if !flag(test) buildable: False else buildable: True build-depends: extensible-exceptions >= 0.1 && < 0.2, regex-compat >= 0.95.1, mtl >= 1.0 && < 2.2, parsec >= 2.0 && < 3.2, html == 1.0.*, filepath >= 1.1.0.0 && < 1.5.0.0, FindBin >= 0.0 && < 0.1, QuickCheck >= 2.3, HUnit >= 1.0, cmdlib >= 0.2.1 && < 0.4, shellish >= 0.1.3 && < 0.2, test-framework >= 0.4.0, test-framework-hunit >= 0.2.2, test-framework-quickcheck2 >= 0.2.8 hs-source-dirs: src include-dirs: src c-sources: src/atomic_create.c src/fpstring.c src/maybe_relink.c src/umask.c src/Crypt/sha2.c src/system_encoding.c -- list all unit test modules not exported by libdarcs; otherwise Cabal won't -- include them in the tarball other-modules: Darcs.Test.Email Darcs.Test.Patch.Check Darcs.Test.Patch.Examples.Set1 Darcs.Test.Patch.Examples.Set2Unwitnessed Darcs.Test.Patch.WSub Darcs.Test.Patch.Info Darcs.Test.Patch.Properties.V1Set1 Darcs.Test.Patch.Properties.V1Set2 Darcs.Test.Patch.Properties.Generic Darcs.Test.Patch.Properties.GenericUnwitnessed Darcs.Test.Patch.Properties.Check Darcs.Test.Patch.Properties.Real Darcs.Test.Patch.Arbitrary.Generic Darcs.Test.Patch.Arbitrary.Real Darcs.Test.Patch.Arbitrary.PrimV1 Darcs.Test.Patch.Arbitrary.PrimV3 Darcs.Test.Patch.Arbitrary.PatchV1 Darcs.Test.Patch.RepoModel Darcs.Test.Patch.Utils Darcs.Test.Patch.V1Model Darcs.Test.Patch.V3Model Darcs.Test.Patch.WithState Darcs.Test.Patch Darcs.Test.Misc Darcs.Test.Util.TestResult Darcs.Test.Util.QuickCheck if flag(optimize) ghc-options: -O2 else ghc-options: -O0 if flag(warn-as-error) ghc-options: -Werror -- Note: "if true" works around a cabal bug with order of flag composition if true ghc-options: -Wall -funbox-strict-fields -fwarn-tabs ghc-prof-options: -prof -auto-all if flag(threaded) ghc-options: -threaded if flag(curl) extra-libraries: curl includes: curl/curl.h cpp-options: -DHAVE_CURL c-sources: src/hscurl.c cc-options: -DHAVE_CURL if flag(hpc) ghc-prof-options: -fhpc -hpcdir dist/hpc/darcs-test cc-options: -D_REENTRANT cpp-options: -DGADT_WITNESSES=1 if os(windows) hs-source-dirs: src/win32 include-dirs: src/win32 other-modules: CtrlC System.Posix System.Posix.Files System.Posix.IO cpp-options: -DWIN32 c-sources: src/win32/send_email.c build-depends: unix-compat >= 0.1.2, Win32 >= 2.0, regex-posix >= 0.95.1 else c-sources: src/h_iconv.c build-depends: utf8-string >= 0.3.6 && < 0.4 -- need to list this explicitly to get cabal to run hsc2hs other-modules: Encoding.IConv if os(solaris) cc-options: -DHAVE_SIGINFO_H if os(windows) build-depends: base >= 4 && < 4.7 else if flag(force-char8-encoding) build-depends: base >= 4.5 && < 4.7 cpp-options: -DFORCE_CHAR8_ENCODING else build-depends: base >= 4 && < 4.4 if !os(windows) build-depends: unix >= 1.0 && < 2.7 build-depends: bytestring >= 0.9.0 && < 0.11, haskeline >= 0.6.3 && < 0.8, text >= 0.11.0.6 && < 0.12.0.0, old-time >= 1.0 && < 1.2, directory >= 1.0.0.0 && < 1.3.0.0, process >= 1.0.0.0 && < 1.2.0.0, containers >= 0.1 && < 0.6, array >= 0.1 && < 0.5, hashed-storage >= 0.5.6 && < 0.6, vector >= 0.7, tar >= 0.3 && < 0.5, random == 1.0.* if impl(ghc<7.0) -- haskeline 0.6.4.7 doesn't build with ghc 6.12 build-depends: haskeline <= 0.6.4.6 if flag(mmap) && !os(windows) build-depends: mmap >= 0.5 && < 0.6 cpp-options: -DHAVE_MMAP build-depends: zlib >= 0.5.1.0 && < 0.6.0.0 -- The terminfo package cannot be built on Windows. if flag(terminfo) && !os(windows) build-depends: terminfo == 0.3.* cpp-options: -DHAVE_TERMINFO if flag(http) build-depends: network >= 2.2 && < 2.5, HTTP >= 4000.0.8 && < 4000.3 if flag(color) x-use-color: -- if true to work around cabal bug with flag ordering if true extensions: CPP BangPatterns PatternGuards GADTs TypeOperators FlexibleContexts FlexibleInstances ScopedTypeVariables KindSignatures RankNTypes TypeFamilies if impl(ghc>=7.0) extensions: NoMonoLocalBinds if impl(ghc>=7.6) -- in ghc < 7.6 we need to import Prelude hiding (catch) -- in ghc >= 7.6 catch isn't in Prelude ghc-options: -fno-warn-dodgy-imports