From 24fc5dedcddb7f8826d99f4107666bceab221724 Mon Sep 17 00:00:00 2001 From: Paolo Calao Date: Tue, 4 Jan 2022 13:10:08 +0100 Subject: [PATCH 01/11] Angry port --- internal/lzss/lzss.c | 194 ------------------------------------ internal/lzss/lzss.go | 199 ++++++++++++++++++++++++++++++++++--- internal/lzss/lzss.h | 6 -- internal/lzss/lzss_test.go | 14 +++ 4 files changed, 197 insertions(+), 216 deletions(-) delete mode 100644 internal/lzss/lzss.c delete mode 100644 internal/lzss/lzss.h create mode 100644 internal/lzss/lzss_test.go diff --git a/internal/lzss/lzss.c b/internal/lzss/lzss.c deleted file mode 100644 index 782a65e6..00000000 --- a/internal/lzss/lzss.c +++ /dev/null @@ -1,194 +0,0 @@ -/* LZSS encoder-decoder (Haruhiko Okumura; public domain) */ - -#include -#include - -#define EI 11 /* typically 10..13 */ -#define EJ 4 /* typically 4..5 */ -#define P 1 /* If match length <= P then output one character */ -#define N (1 << EI) /* buffer size */ -#define F ((1 << EJ) + 1) /* lookahead buffer size */ - -int bit_buffer = 0, bit_mask = 128; -unsigned long codecount = 0, textcount = 0; -unsigned char buffer[N * 2]; -FILE *infile, *outfile; - -void error(void) -{ - printf("Output error\n"); exit(1); -} - -void putbit1(void) -{ - bit_buffer |= bit_mask; - if ((bit_mask >>= 1) == 0) { - if (fputc(bit_buffer, outfile) == EOF) error(); - bit_buffer = 0; bit_mask = 128; codecount++; - } -} - -void putbit0(void) -{ - if ((bit_mask >>= 1) == 0) { - if (fputc(bit_buffer, outfile) == EOF) error(); - bit_buffer = 0; bit_mask = 128; codecount++; - } -} - -void flush_bit_buffer(void) -{ - if (bit_mask != 128) { - if (fputc(bit_buffer, outfile) == EOF) error(); - codecount++; - } -} - -void output1(int c) -{ - int mask; - - putbit1(); - mask = 256; - while (mask >>= 1) { - if (c & mask) putbit1(); - else putbit0(); - } -} - -void output2(int x, int y) -{ - int mask; - - putbit0(); - mask = N; - while (mask >>= 1) { - if (x & mask) putbit1(); - else putbit0(); - } - mask = (1 << EJ); - while (mask >>= 1) { - if (y & mask) putbit1(); - else putbit0(); - } -} - -void encode(void) -{ - int i, j, f1, x, y, r, s, bufferend, c; - - for (i = 0; i < N - F; i++) buffer[i] = ' '; - for (i = N - F; i < N * 2; i++) { - if ((c = fgetc(infile)) == EOF) break; - buffer[i] = c; textcount++; - } - bufferend = i; r = N - F; s = 0; - while (r < bufferend) { - f1 = (F <= bufferend - r) ? F : bufferend - r; - x = 0; y = 1; c = buffer[r]; - for (i = r - 1; i >= s; i--) - if (buffer[i] == c) { - for (j = 1; j < f1; j++) - if (buffer[i + j] != buffer[r + j]) break; - if (j > y) { - x = i; y = j; - } - } - if (y <= P) { y = 1; output1(c); } - else output2(x & (N - 1), y - 2); - r += y; s += y; - if (r >= N * 2 - F) { - for (i = 0; i < N; i++) buffer[i] = buffer[i + N]; - bufferend -= N; r -= N; s -= N; - while (bufferend < N * 2) { - if ((c = fgetc(infile)) == EOF) break; - buffer[bufferend++] = c; textcount++; - } - } - } - flush_bit_buffer(); -// printf("text: %ld bytes\n", textcount); -// printf("code: %ld bytes (%ld%%)\n", -// codecount, (codecount * 100) / textcount); -} - -int getbit(int n) /* get n bits */ -{ - int i, x; - static int buf, mask = 0; - - x = 0; - for (i = 0; i < n; i++) { - if (mask == 0) { - if ((buf = fgetc(infile)) == EOF) return EOF; - mask = 128; - } - x <<= 1; - if (buf & mask) x++; - mask >>= 1; - } - return x; -} - -void decode(void) -{ - int i, j, k, r, c; - - for (i = 0; i < N - F; i++) buffer[i] = ' '; - r = N - F; - while ((c = getbit(1)) != EOF) { - if (c) { - if ((c = getbit(8)) == EOF) break; - fputc(c, outfile); - buffer[r++] = c; r &= (N - 1); - } else { - if ((i = getbit(EI)) == EOF) break; - if ((j = getbit(EJ)) == EOF) break; - for (k = 0; k <= j + 1; k++) { - c = buffer[(i + k) & (N - 1)]; - fputc(c, outfile); - buffer[r++] = c; r &= (N - 1); - } - } - } -} - -int encode_file(char const * in, char const * out) -{ - // reset counters - bit_buffer = 0, bit_mask = 128; - codecount = 0, textcount = 0; - - infile = fopen(in, "rb"); - if (infile == NULL) return 0; - - outfile = fopen(out, "wb"); - if (outfile == NULL) return 0; - - encode(); - - fclose(infile); - fclose(outfile); - - return 0; -} - -int decode_file(char const * in, char const * out) -{ - // reset counters - bit_buffer = 0, bit_mask = 128; - codecount = 0, textcount = 0; - - infile = fopen(in, "rb"); - if (infile == NULL) return 0; - - outfile = fopen(out, "wb"); - if (outfile == NULL) return 0; - - decode(); - - fclose(infile); - fclose(outfile); - - return 0; -} diff --git a/internal/lzss/lzss.go b/internal/lzss/lzss.go index 897d8eb3..27dc6fc4 100644 --- a/internal/lzss/lzss.go +++ b/internal/lzss/lzss.go @@ -17,27 +17,194 @@ package lzss -// #cgo CFLAGS: -g -Wall -// #include -// #include "lzss.h" -import "C" import ( - // "fmt" - "sync" - "unsafe" + "bytes" + "io" ) -func Encode(source, destination string) { +const ( + ei = 11 /* typically 10..13 */ + ej = 4 /* typically 4..5 */ + p = 1 /* If match length <= P then output one character */ + bufsz = (1 << ei) /* buffer size */ + looksz = ((1 << ej) + 1) /* lookahead buffer size */ +) + +var ( + codecount = 0 + bit_buffer = 0 + bit_mask = 128 + EI = 11 /* typically 10..13 */ + EJ = 4 /* typically 4..5 */ + P = 1 /* If match length <= P then output one character */ + N = (1 << EI) /* buffer size */ + F = ((1 << EJ) + 1) /* lookahead buffer size */ +) + +func min(x, y int) int { + if x < y { + return x + } + return y +} + +func contains(buf []byte, el []byte) (ok bool, ln int, idx int) { + for i := 0; i < len(buf)-looksz; i++ { + + // } + // for i, e := range buf { + // Skip mismatching elements + // if el[0] != e { + if buf[i] != el[0] { + continue + } + + // Check bounds + ahead := min(looksz, len(buf)-i) + ahead = min(ahead, len(el)) + + // Count number of bytes contained + var j int + for j = 1; j < ahead; j++ { + if buf[i+j] != el[j] { + break + } + } + // store the largest result + if j > ln { + ok, ln, idx = true, j, i + } + } + return +} + +func putbit1(out io.Writer) { + bit_buffer |= bit_mask + bit_mask = bit_mask >> 1 + if bit_mask == 0 { + out.Write([]byte{byte(bit_buffer)}) + bit_buffer = 0 + bit_mask = 128 + } +} + +func putbit0(out io.Writer) { + bit_mask = bit_mask >> 1 + if bit_mask == 0 { + out.Write([]byte{byte(bit_buffer)}) + bit_buffer = 0 + bit_mask = 128 + } +} + +func flush_bit_buffer(out io.Writer) { + if bit_mask != 128 { + out.Write([]byte{byte(bit_buffer)}) + } +} + +func output1(out io.Writer, c int) { + putbit1(out) + + for mask := 256 >> 1; mask != 0; mask = mask >> 1 { + if c&mask != 0 { + putbit1(out) + } else { + putbit0(out) + } + } +} + +func output2(out io.Writer, x, y int) { + putbit0(out) + + for mask := N >> 1; mask != 0; mask = mask >> 1 { + if x&mask != 0 { + putbit1(out) + } else { + putbit0(out) + } + } + + for mask := (1 << EJ) >> 1; mask != 0; mask = mask >> 1 { + if y&mask != 0 { + putbit1(out) + } else { + putbit0(out) + } + } +} + +func Encode(data []byte) []byte { + bit_buffer = 0 + bit_mask = 128 + out := bytes.NewBufferString("") + in := bytes.NewReader(data) + + var i, j, f1, x, y, r, s, bufferend int + var c byte + + buffer := make([]byte, N*2) + for i = 0; i < N-F; i++ { + buffer[i] = ' ' + } + + for i = N - F; i < N*2; i++ { + b, err := in.ReadByte() + if err != nil { + break + } + buffer[i] = b + } + + bufferend, r, s = i, N-F, 0 + for r < bufferend { + f1 = min(F, bufferend-r) + x = 0 + y = 1 + c = buffer[r] + for i = r - 1; i >= s; i-- { + if buffer[i] == c { + for j = 1; j < f1; j++ { + if buffer[i+j] != buffer[r+j] { + break + } + } + if j > y { + x = i + y = j + } + } + } - var mutex sync.Mutex + if y <= P { + output1(out, int(c)) + y = 1 + } else { + output2(out, x&(N-1), y-2) + } - src := C.CString(source) - defer C.free(unsafe.Pointer(src)) + r += y + s += y + if r >= N*2-F { + for i = 0; i < N; i++ { + buffer[i] = buffer[i+N] + } + bufferend -= N + r -= N + s -= N - dst := C.CString(destination) - defer C.free(unsafe.Pointer(dst)) + for bufferend < N*2 { + b, err := in.ReadByte() + if err != nil { + break + } + buffer[bufferend] = b + bufferend++ + } + } + } + flush_bit_buffer(out) - mutex.Lock() - C.encode_file(src, dst) - mutex.Unlock() + return out.Bytes() } diff --git a/internal/lzss/lzss.h b/internal/lzss/lzss.h deleted file mode 100644 index a4a44622..00000000 --- a/internal/lzss/lzss.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _LZSS_H -#define _LZSS_H - -int encode_file(char const * in, char const * out); - -#endif \ No newline at end of file diff --git a/internal/lzss/lzss_test.go b/internal/lzss/lzss_test.go new file mode 100644 index 00000000..ffe122e4 --- /dev/null +++ b/internal/lzss/lzss_test.go @@ -0,0 +1,14 @@ +package lzss + +import ( + "fmt" + "testing" +) + +func TestContains(t *testing.T) { + buf := []byte("ciao a tutti") + occ := []byte("tut") + fmt.Println(contains(buf, occ)) + occ = []byte("ti") + fmt.Println(contains(buf, occ)) +} From 0881b348ccf7ac49ed9e52659a4e76b1b027393f Mon Sep 17 00:00:00 2001 From: Paolo Calao Date: Tue, 4 Jan 2022 13:42:36 +0100 Subject: [PATCH 02/11] Add test --- internal/lzss/README.md | 0 internal/lzss/lzss_test.go | 50 +++++++++++++++++++++++++----- internal/lzss/testdata/blink.bin | Bin 0 -> 11424 bytes internal/lzss/testdata/blink.lzss | Bin 0 -> 9583 bytes internal/lzss/testdata/short.lzss | Bin 0 -> 63 bytes internal/lzss/testdata/short.txt | 1 + 6 files changed, 44 insertions(+), 7 deletions(-) delete mode 100644 internal/lzss/README.md create mode 100755 internal/lzss/testdata/blink.bin create mode 100644 internal/lzss/testdata/blink.lzss create mode 100644 internal/lzss/testdata/short.lzss create mode 100644 internal/lzss/testdata/short.txt diff --git a/internal/lzss/README.md b/internal/lzss/README.md deleted file mode 100644 index e69de29b..00000000 diff --git a/internal/lzss/lzss_test.go b/internal/lzss/lzss_test.go index ffe122e4..5e0a226d 100644 --- a/internal/lzss/lzss_test.go +++ b/internal/lzss/lzss_test.go @@ -1,14 +1,50 @@ package lzss import ( - "fmt" + "bytes" + "io/ioutil" "testing" ) -func TestContains(t *testing.T) { - buf := []byte("ciao a tutti") - occ := []byte("tut") - fmt.Println(contains(buf, occ)) - occ = []byte("ti") - fmt.Println(contains(buf, occ)) +func TestEncode(t *testing.T) { + tests := []struct { + name string + infile string + outfile string + }{ + { + name: "lorem", + infile: "testdata/lorem.txt", + outfile: "testdata/lorem.lzss", + }, + { + name: "short", + infile: "testdata/short.txt", + outfile: "testdata/short.lzss", + }, + { + name: "blink", + infile: "testdata/blink.bin", + outfile: "testdata/blink.lzss", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + input, err := ioutil.ReadFile(tt.infile) + if err != nil { + t.Fatal("couldn't open test file") + } + + want, err := ioutil.ReadFile(tt.outfile) + if err != nil { + t.Fatal("couldn't open test file") + } + + got := Encode(input) + if !bytes.Equal(want, got) { + t.Error("encoding failed") + } + }) + } } diff --git a/internal/lzss/testdata/blink.bin b/internal/lzss/testdata/blink.bin new file mode 100755 index 0000000000000000000000000000000000000000..b3731ec4d007ce8cf0235293c6b84f995bfc8caf GIT binary patch literal 11424 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 literal 0 HcmV?d00001 diff --git a/internal/lzss/testdata/blink.lzss b/internal/lzss/testdata/blink.lzss new file mode 100644 index 0000000000000000000000000000000000000000..9d23a667416277b0475d42be10cddbf2f8c54522 GIT binary patch literal 9583 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 literal 0 HcmV?d00001 diff --git a/internal/lzss/testdata/short.lzss b/internal/lzss/testdata/short.lzss new file mode 100644 index 0000000000000000000000000000000000000000..54588ab54674960d020d7b3f95e433c84f88a910 GIT binary patch literal 63 zcmV-F0KosITkcj{Y=YBpx!qsPESCFY_ymIIX}U-(Hrp-ISs=07?bkakj_3g4b${@% V*&oy`H#;4s-Di+lZGZ$4=ukoiAaMWy literal 0 HcmV?d00001 diff --git a/internal/lzss/testdata/short.txt b/internal/lzss/testdata/short.txt new file mode 100644 index 00000000..4f006a88 --- /dev/null +++ b/internal/lzss/testdata/short.txt @@ -0,0 +1 @@ +Lorem ipsum dolor sit amet, consectetur adipiscing elit. From 4db57fd5394161e25a413a28c9e2d848b6afb39d Mon Sep 17 00:00:00 2001 From: Paolo Calao Date: Wed, 5 Jan 2022 14:13:45 +0100 Subject: [PATCH 03/11] Refine algorithm --- internal/lzss/lzss.go | 265 +++++++++++++++++++----------------------- 1 file changed, 120 insertions(+), 145 deletions(-) diff --git a/internal/lzss/lzss.go b/internal/lzss/lzss.go index 27dc6fc4..f14415f5 100644 --- a/internal/lzss/lzss.go +++ b/internal/lzss/lzss.go @@ -1,3 +1,5 @@ +// This code is a go port of LZSS encoder-decoder (Haruhiko Okumura; public domain) +// // This file is part of arduino-cloud-cli. // // Copyright (C) 2021 ARDUINO SA (http://www.arduino.cc/) @@ -19,26 +21,20 @@ package lzss import ( "bytes" - "io" ) const ( - ei = 11 /* typically 10..13 */ - ej = 4 /* typically 4..5 */ - p = 1 /* If match length <= P then output one character */ - bufsz = (1 << ei) /* buffer size */ - looksz = ((1 << ej) + 1) /* lookahead buffer size */ -) + idxsz = 11 // Size of buffer indexes in bit, typically 10..13 bits + lensz = 4 // Size of lookahead indexes in bit, typically 4..5 bits + charsz = 8 // Size of encoded chars in bit -var ( - codecount = 0 - bit_buffer = 0 - bit_mask = 128 - EI = 11 /* typically 10..13 */ - EJ = 4 /* typically 4..5 */ - P = 1 /* If match length <= P then output one character */ - N = (1 << EI) /* buffer size */ - F = ((1 << EJ) + 1) /* lookahead buffer size */ + threshold = 1 // If match length <= threshold then output one character + bufsz = (1 << idxsz) // buffer size + looksz = ((1 << lensz) + 1) // lookahead buffer size + historysz = bufsz - looksz // history buffer size + + charStartBit = true // Indicates next bits encode a char + tokenStartBit = false // Indicates next bits encode a token ) func min(x, y int) int { @@ -48,163 +44,142 @@ func min(x, y int) int { return y } -func contains(buf []byte, el []byte) (ok bool, ln int, idx int) { - for i := 0; i < len(buf)-looksz; i++ { - - // } - // for i, e := range buf { - // Skip mismatching elements - // if el[0] != e { - if buf[i] != el[0] { - continue - } - - // Check bounds - ahead := min(looksz, len(buf)-i) - ahead = min(ahead, len(el)) - - // Count number of bytes contained - var j int - for j = 1; j < ahead; j++ { - if buf[i+j] != el[j] { - break +func findLargestMatch(buf []byte, current, size int) (idx, len int) { + idx = 0 + len = 1 + ahead := min(looksz, size-current) + history := current - (historysz) + c := buf[current] + for i := current - 1; i >= history; i-- { + if buf[i] == c { + var j int + for j = 1; j < ahead; j++ { + if buf[i+j] != buf[current+j] { + break + } + } + if j > len { + idx = i + len = j } - } - // store the largest result - if j > ln { - ok, ln, idx = true, j, i } } return } -func putbit1(out io.Writer) { - bit_buffer |= bit_mask - bit_mask = bit_mask >> 1 - if bit_mask == 0 { - out.Write([]byte{byte(bit_buffer)}) - bit_buffer = 0 - bit_mask = 128 +func Encode(data []byte) []byte { + // buffer is made up of two parts: the first is for already processed data (history); the second is for new data + buffer := make([]byte, bufsz*2) + // Initialize the old-data part (history) of the buffer + for i := 0; i < historysz; i++ { + buffer[i] = ' ' } -} + out := newResult() + in := newFiller(data) + + // Fill the new-data part of the buffer + n := in.fill(buffer[historysz:]) + bufferend := historysz + n + for current := historysz; current < bufferend; { + idx, len := findLargestMatch(buffer, current, bufferend) + if len <= threshold { + out.addChar(buffer[current]) + len = 1 + } else { + out.addToken(idx, len) + } -func putbit0(out io.Writer) { - bit_mask = bit_mask >> 1 - if bit_mask == 0 { - out.Write([]byte{byte(bit_buffer)}) - bit_buffer = 0 - bit_mask = 128 + current += len + if current >= bufsz*2-looksz { + // Shift processed bytes to the old-data portion of the buffer + copy(buffer[:bufsz], buffer[bufsz:]) + current -= bufsz + // Refill the new-data portion of the buffer + bufferend -= bufsz + bufferend += in.fill(buffer[bufferend:]) + } } -} -func flush_bit_buffer(out io.Writer) { - if bit_mask != 128 { - out.Write([]byte{byte(bit_buffer)}) - } + out.flush() + return out.bytes() } -func output1(out io.Writer, c int) { - putbit1(out) +type filler struct { + src []byte + idx int +} - for mask := 256 >> 1; mask != 0; mask = mask >> 1 { - if c&mask != 0 { - putbit1(out) - } else { - putbit0(out) - } +func newFiller(src []byte) *filler { + return &filler{ + src: src, } } -func output2(out io.Writer, x, y int) { - putbit0(out) +func (f *filler) fill(dst []byte) int { + n := min(len(f.src)-f.idx, len(dst)) + copy(dst, f.src[f.idx:f.idx+n]) + f.idx += n + return n +} - for mask := N >> 1; mask != 0; mask = mask >> 1 { - if x&mask != 0 { - putbit1(out) - } else { - putbit0(out) - } - } +type result struct { + bitBuffer int + bitMask int + out *bytes.Buffer +} - for mask := (1 << EJ) >> 1; mask != 0; mask = mask >> 1 { - if y&mask != 0 { - putbit1(out) - } else { - putbit0(out) - } +func newResult() *result { + return &result{ + bitBuffer: 0, + bitMask: 128, + out: bytes.NewBufferString(""), } } -func Encode(data []byte) []byte { - bit_buffer = 0 - bit_mask = 128 - out := bytes.NewBufferString("") - in := bytes.NewReader(data) +func (r *result) addChar(c byte) { + i := int(c) + r.putbit(charStartBit) + for mask := (1 << charsz) >> 1; mask != 0; mask = mask >> 1 { + b := i&mask != 0 + r.putbit(b) + } +} - var i, j, f1, x, y, r, s, bufferend int - var c byte +func (r *result) addToken(idx, len int) { + // Adjust idx and len to fit idxsz and lensz bits respectively + idx &= (bufsz - 1) + len -= 2 - buffer := make([]byte, N*2) - for i = 0; i < N-F; i++ { - buffer[i] = ' ' + r.putbit(tokenStartBit) + for mask := (1 << idxsz) >> 1; mask != 0; mask = mask >> 1 { + b := idx&mask != 0 + r.putbit(b) } - for i = N - F; i < N*2; i++ { - b, err := in.ReadByte() - if err != nil { - break - } - buffer[i] = b + for mask := (1 << lensz) >> 1; mask != 0; mask = mask >> 1 { + b := len&mask != 0 + r.putbit(b) } +} - bufferend, r, s = i, N-F, 0 - for r < bufferend { - f1 = min(F, bufferend-r) - x = 0 - y = 1 - c = buffer[r] - for i = r - 1; i >= s; i-- { - if buffer[i] == c { - for j = 1; j < f1; j++ { - if buffer[i+j] != buffer[r+j] { - break - } - } - if j > y { - x = i - y = j - } - } - } - - if y <= P { - output1(out, int(c)) - y = 1 - } else { - output2(out, x&(N-1), y-2) - } - - r += y - s += y - if r >= N*2-F { - for i = 0; i < N; i++ { - buffer[i] = buffer[i+N] - } - bufferend -= N - r -= N - s -= N +func (r *result) flush() { + if r.bitMask != 128 { + r.out.WriteByte(byte(r.bitBuffer)) + } +} - for bufferend < N*2 { - b, err := in.ReadByte() - if err != nil { - break - } - buffer[bufferend] = b - bufferend++ - } - } +func (r *result) putbit(b bool) { + if b { + r.bitBuffer |= r.bitMask + } + r.bitMask = r.bitMask >> 1 + if r.bitMask == 0 { + r.out.WriteByte(byte(r.bitBuffer)) + r.bitBuffer = 0 + r.bitMask = 128 } - flush_bit_buffer(out) +} - return out.Bytes() +func (r *result) bytes() []byte { + return r.out.Bytes() } From e6459b23b0d11c184696e5455cd7d0cabb50d7f6 Mon Sep 17 00:00:00 2001 From: Paolo Calao Date: Wed, 5 Jan 2022 17:32:58 +0100 Subject: [PATCH 04/11] Improve readability --- internal/lzss/lzss.go | 50 ++++++++++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 13 deletions(-) diff --git a/internal/lzss/lzss.go b/internal/lzss/lzss.go index f14415f5..b13653de 100644 --- a/internal/lzss/lzss.go +++ b/internal/lzss/lzss.go @@ -24,17 +24,20 @@ import ( ) const ( - idxsz = 11 // Size of buffer indexes in bit, typically 10..13 bits - lensz = 4 // Size of lookahead indexes in bit, typically 4..5 bits - charsz = 8 // Size of encoded chars in bit + idxsz = 11 // Size of buffer indexes in bits, typically 10..13 bits. + lensz = 4 // Size of lookahead indexes in bits, typically 4..5 bits. - threshold = 1 // If match length <= threshold then output one character - bufsz = (1 << idxsz) // buffer size - looksz = ((1 << lensz) + 1) // lookahead buffer size - historysz = bufsz - looksz // history buffer size + charsz = 8 // Size of encoded chars in bits. + bytemask = 128 // Mask with a bit in 8th position. Used to iterate through bits of a char. - charStartBit = true // Indicates next bits encode a char - tokenStartBit = false // Indicates next bits encode a token + threshold = 1 // If match length > threshold then output a token (idx, len), otherwise output one char. + + bufsz = (1 << idxsz) // Buffer size. + looksz = ((1 << lensz) + 1) // Lookahead buffer size. + historysz = bufsz - looksz // History buffer size. + + charStartBit = true // Indicates next bits encode a char. + tokenStartBit = false // Indicates next bits encode a token. ) func min(x, y int) int { @@ -44,6 +47,10 @@ func min(x, y int) int { return y } +// findLargestMatch looks for the largest sequence of characters (from current to current+ahead) +// contained in the history of the buffer. +// It returns the index of the found match, if any, and its length. +// The index is relative to the current position. If idx 0 is returned than no match has been found. func findLargestMatch(buf []byte, current, size int) (idx, len int) { idx = 0 len = 1 @@ -67,6 +74,8 @@ func findLargestMatch(buf []byte, current, size int) (idx, len int) { return } +// Encode takes a slice of bytes, compresses it using the lzss compression algorithm +// and returns the result in a new bytes buffer. func Encode(data []byte) []byte { // buffer is made up of two parts: the first is for already processed data (history); the second is for new data buffer := make([]byte, bufsz*2) @@ -104,6 +113,9 @@ func Encode(data []byte) []byte { return out.bytes() } +// filler abstracts the process of consuming an input buffer +// using its bytes to fill another buffer. +// It's been used to facilitate the handling of the input buffer in the Encode function. type filler struct { src []byte idx int @@ -115,6 +127,10 @@ func newFiller(src []byte) *filler { } } +// fill tries to fill all the dst buffer with bytes read from src. +// It returns the number of bytes moved from src to dst. +// The src buffer offset is then incremented so that all the content of src +// can be consumed in small chunks. func (f *filler) fill(dst []byte) int { n := min(len(f.src)-f.idx, len(dst)) copy(dst, f.src[f.idx:f.idx+n]) @@ -122,6 +138,10 @@ func (f *filler) fill(dst []byte) int { return n } +// result is responsible for storing the actual result of the encoding. +// It knows how to store characters and tokens in the resulting buffer. +// It must be flushed at the end of the encoding in order to store the +// remaining bits of bitBuffer. type result struct { bitBuffer int bitMask int @@ -131,11 +151,12 @@ type result struct { func newResult() *result { return &result{ bitBuffer: 0, - bitMask: 128, - out: bytes.NewBufferString(""), + bitMask: bytemask, + out: &bytes.Buffer{}, } } +// addChar stores a char in the out buffer. func (r *result) addChar(c byte) { i := int(c) r.putbit(charStartBit) @@ -145,6 +166,7 @@ func (r *result) addChar(c byte) { } } +// addToken stores a token in the out buffer. func (r *result) addToken(idx, len int) { // Adjust idx and len to fit idxsz and lensz bits respectively idx &= (bufsz - 1) @@ -163,11 +185,13 @@ func (r *result) addToken(idx, len int) { } func (r *result) flush() { - if r.bitMask != 128 { + if r.bitMask != bytemask { r.out.WriteByte(byte(r.bitBuffer)) } } +// putbit puts the passed bit (true -> 1; false -> 0) in the bitBuffer. +// When bitBuffer contains an entire byte it's written to the out buffer. func (r *result) putbit(b bool) { if b { r.bitBuffer |= r.bitMask @@ -176,7 +200,7 @@ func (r *result) putbit(b bool) { if r.bitMask == 0 { r.out.WriteByte(byte(r.bitBuffer)) r.bitBuffer = 0 - r.bitMask = 128 + r.bitMask = bytemask } } From 4653690d47c1fed6a63bff9ccb493ae94c81550b Mon Sep 17 00:00:00 2001 From: Paolo Calao Date: Wed, 5 Jan 2022 17:33:16 +0100 Subject: [PATCH 05/11] Add test --- internal/lzss/lzss_test.go | 10 +++++ internal/lzss/testdata/cloud.bin | Bin 0 -> 92112 bytes internal/lzss/testdata/cloud.lzss | Bin 0 -> 74957 bytes internal/lzss/testdata/repetitive.lzss | Bin 0 -> 3728 bytes internal/lzss/testdata/repetitive.txt | 52 +++++++++++++++++++++++++ 5 files changed, 62 insertions(+) create mode 100755 internal/lzss/testdata/cloud.bin create mode 100644 internal/lzss/testdata/cloud.lzss create mode 100644 internal/lzss/testdata/repetitive.lzss create mode 100644 internal/lzss/testdata/repetitive.txt diff --git a/internal/lzss/lzss_test.go b/internal/lzss/lzss_test.go index 5e0a226d..c575b23e 100644 --- a/internal/lzss/lzss_test.go +++ b/internal/lzss/lzss_test.go @@ -27,6 +27,16 @@ func TestEncode(t *testing.T) { infile: "testdata/blink.bin", outfile: "testdata/blink.lzss", }, + { + name: "repetitive", + infile: "testdata/repetitive.txt", + outfile: "testdata/repetitive.lzss", + }, + { + name: "cloud sketch", + infile: "testdata/cloud.bin", + outfile: "testdata/cloud.lzss", + }, } for _, tt := range tests { diff --git a/internal/lzss/testdata/cloud.bin b/internal/lzss/testdata/cloud.bin new file mode 100755 index 0000000000000000000000000000000000000000..0bf2398affb51fafc93d4692d8770d6b7e00e182 GIT binary patch literal 92112 zcmeFa33OCN_CH?l^}ZzOBrM(8=Bv&j0++ z`JXe*sZ_nHTeoiAx>a>+yO4TfExCx0F@ui$AAS^O=tsl5F32~O|3ZJ91?WHvB9AIersNgW7v=ffmsd$>~)DwnOSrvXFe%q&LwDRqq_7qpE@{p-5J*XtC z_*ozG^c$^KBK4e=j*c{Ew5N<{6N75OBWyY}jI^3nM6sjEtvE$;_qt8T_hkN2n2KEQ z_9+5ywh}+{NHLj4Dy>9(v(F)9S{%HUs1Av3zThT7NeTe@VxK+xjn)F-KP>TruWd?@ ze*Y(JKWlkp^ho?xE!tk$y`YE3tT@$ zoNar&gor_7?jH}4KN9g@5-YCmWso~bVr)59M%)%n_#N;^;k#kbe>YlJKGnjCzl*Oe zBce4f6_D_w-9#K2*XBF(7(&y0@mDOq@&yRZMrfgh#yy0PlF+z#jEvn7uAWmMNIkrS z>V-FVj}f$aFIv`H8ZAVe70=?&`w?@kNbo z$Zp{DN%a#|_yaA}zoE*Eg?YceuvZp!b)QoHAsng;iu!*;pZLROu;xiN<#jYO00X}YtbL(*Ozcg27Tu%(yipt zcW6Iqm!$fAl9UcfRF`qYPHcoc!ie`oX-EOt_-AiA`cxlaXrUzC=qttudSE@;>k#Zh!0g}&$ML?l ziO4qG0D*pM!S@x{A;err5#H5SZc_Jnhwt)#Z*yXnpU5GlD;~{`bPw z!}Wll`Gncd1opZ|oHoueUg;2sLk-FgNK<)FR#K=QcngIY!ZMQXT9~t~WUlF)xsYcj ze;Topfws4SH z@z*R-Elc_$VnE8Pa!O`MiSUb(g3?nwEHs5Mfg_nrvESX5C=I6f+@ysi#7! zDNU=Z$|@Yh(bM)f(D03h5KWNSAPqYVL=S1ZMbbbftVqM?D{^sD8})l)rZx(vER&&j z5b*|y^(rbdcuiXfa!6(Is-wTgHCx8jiL`$&!zIUe|F8Ioa{T9rcLp~dG7=TWPJLWy z!x+Cq(So+zQDq&2wk4tz8ye$Phn%1g^3FZZYl$tJd-w{@tY{cV8Zx2+oQBt1yZ02v0@mbL>15R&AbU?zlxAt8-_<_qSW&* zNk29kE+9VSQO&0F%qdA(p)9u&M*IvCjkzlgeE_nwVKgDpU>3(+k$YvaFL$=4c!sa7 znDY^_qSrR(qXK0o!#R9hU6+UR<)A-38+X<*HX{1_r`8ep5BFQ;?`{2b{3qi5gZ@AI z6L9bLkEyfP5%I76dZhl;JEo4wv({C+i1=E+0rE80|u7MO#Ub{!b+=MacUo!XBiwsz|q$*)c+8^$<^QHjdbCaK=e)eZL?bpH^h z-y0;Zj%o6{zY0&qSBEr-Os_kb*@Tkm%(z-&CjAt#5lZ9D5@YR((E4;+laN*+-EFnH zq@Gf!2U3qmBI6SDU5dI8lIBehWZMXFxrHl`a}W~ zO|M1#rvp|p0&bjlSn-c z60s|7%mJy#A%_eIKP^RxR$mXrTO2- zq4qvH-rR|Jj1?8Cay5E^DN5`ruc|!5w`jhpjlqCMt|DYRWPdB*SbRH!x;eVp2ZhCo z#VG-jwNS|)6qw3DtB0@hJV6@xw|IA@la4bkQbMjFq$gOPpD~BoakHQ(zSI-YuI7ou z5gK{L`1e&!WayUhux~dL)(w3x>($!$b)}wXE!9Z9zE|l*dGAU+e*%@5FTw9_dHnKhAUl|ySlxu0H2Ra@ zd~a%4H=Dh+ClkFydYbpVACIxo@R@7I9NrDSZPGLKIj}W zY>#)(#ywkydG>7lKp5uk3o*H_iebLtb$M<@=$g7!tz=xZi^+Y2pI^7Em5lA}nl^j> z&*6=^=a~8RLn&ho!g3lNh4 zP2pmpp>%RVX|@YW%c{wlGuBm~m$fvj<{3}cQU&MdGrjZpd3B3hiKDlRa8j<}mXQ_S zTejWu?kyv*_8H+FS&=EE3Qg+8%&}z7H8&-VHF(lJX%*?4>N&SSIYD_SkF`qTGO8g7 zT6`Iai%~J;WtFr+33Zxi6h!KiB!!wGWaS4eW-4ngUr(%XfOf}iMUYCfumxJ;r}2xt z%+yBrwVmV3$5)i`?bh@fqRwP9^$Jh=Qj)9T9^egpy)C^)C&z-GrG551ucb!s$w0_b zvy-8reFzCYF} z{bjaOzIk_b=@>_EsGTF$#Y}qTcIc(K(W*gCC3%x8s_Hw|C16UpdC*-3FgDS8(LsMm z7O?=8d6DA+4^U4V^~;ERLF($23OR7BKYdg%0m=|XYk~0?w?=q~-ToEv5m|YW6eT;ph zYZ32kqw#86+OOi9D!+{+QjEV!SyXvWPGN1Te@kiNJHZ<|H;|d6#LS67ZSDe3YDKy^ z>pEs)W{An3M1ChUT-)YKs_0^x%-aQ(+YmMqKIh(&;}+KhQ{6_69PCn|ZS)?M3B>qLL9UqJOHirGlEnHl82DRYlo6Dk&Lb(w;bG|obQ zD)=7S_5gGTta$**h%aGZfhA+eV!;Xsx&k!huo#8E#=6`ruObyfra)&MF}Ur}iqhc( zx?ZuGoL;LX%sA4i&(l3K26$>>@3f|qDa9Jn)v6oAcBT_&aaSvIG1i6`eI2&Rnrv7y zK&QkUQ>Y9pgk!A-o zBPvY6bYWpueu$ZYvEN}2-|`~#{t6{_57JMiRWLRa8MeWQQPyf3woNJuXcrTkC$*uY z(&$aEXE=642GU;t{>q1SUR}j$o`%{>`y)f;VFo4&7P3F6@5y^pB(7q3->gSU#o*qY zTXG&PSz4+Rc4{sXCab4=CU^>YO`htR+&UsW!HjX)JZ^#HvY4@#C{jH(PYExg<=XQU z!n2AjAx%~2vU}Qdb;>7L8)V7CD}+VDFwYY7U{HtA8zUs*G6ZOzCr(!%*ThcvX0bn~ zutG<504cs%fVu0qhCPvS*G^eSC3awHpz-FrT$=WjM5tZon^lk8i`}Vr0rTxNcEPrK zIh|s?dK<=}!CdV_xgKn99m3yta!V^?wQTauVt~I1x-9iG;L~}V$yW+qZLzD!l_%&l zi!}z1!^81P;c9uO?tO`w+TLniBhNXQNB(c?ce)xiJHgsAgsmPb0j%J!S*%~oT0A?J z(%R2Oy&G#Nt!OjBR^bf#-4}(d74+|@3;yQFVfuGeIGMB98Ji++w=1)(J(uBkYaOnG zuD(f+xwa6U`3a(3c)-)1_n6B;6duFXbT2f+lj>bmKQsq9+jQJ8`oX7 z??;T>Nc)LM5@)uDBUIO;dLGsBsD4NFI;zu=k4ZP3XQPnu6f%NjL(-qbevj0nl(KBE z5QD2$V;6Kr+WPl$cENueb5TavWMjsYkan8UTkSCm?HDD-NgBINU|rj`%vE$LyNv0c zZTHv(g>w6rE~CrfQkXs4?}?)C(7BC{35;KRa8z9qNTKUty3VVS+U>cjor+%Be%6_3RNuP{<sq07a>e7f+V7cMG1e6Iiv5l)|x$2n)pL%jqOR~>iK56pf_sy`ap6T?N4lKR(leMhxk_pu_YXFh%bJ>Xf ztdFa$s%>6VQoLfO?S6}IkVXtpVyA)acKl4`0Z~ zInybx*bRnt*cr}i!i;UGyQ1!Khc0XzuL^7Iqspzo`COctM0W#ij^40!yaVx;@(jeE zi;eVV)Ge&jv8kS>x-?~~=X70~TJL!j8rW8McDQR@mnP#x+=@LG?9U}3$Kg1W$Bpj{ zpRLJb?KeYt?eLjP8z^+9+S@;l$tr>n^WTkV32tHHD)- zSR`z8j|ea1GwR-6r>{*j&#BGu5xZedsP$fV%BhEi1$B>-o`v@j#<})tX2JsBcM+C^ zuqWIb4)f6 z95pYj++D4mu*I+iM-&QSF0??F>!`hY-NqT1O={`7(Ue83jaIa!cPj}kz|3EOGf^QR z>l4tbyyeV7^Jbx5S#SI)@+I(7SUPsl{Z4w0p!S}FmY|)ujLEXpb4%BO`<|*=mOEQ( zYNN1XFpCs=Hyz3pG|*;P>|IoZM$2Up?2jr0JMX1@?H1QdRrX(|@j#(-HWUUUaE`CEp0TTp8|#*``jWbFH) zM1DW042NAdMPP!UEnduYn9b`LkENEeovLL59mw5;+)cN<9-*4(tC2@Q^H4oQ*>rE3 z?(y0Q!%026B?b~ncX=6k7uOejw-sx)vL(zGW{a7%T+QzgOmnowNv?WZxnhjRmA3;i zl>0k)Mp(pbHIG;~$uqom*Sb~ezLQw{ncqc!>^n&;^#W$cHd-F#nRFQuX@4L#Ive~= z+UF*x(C;`!c{5hO?=1Nj&a+~X1U$~L$aI;%DTM9}O~Uz57qi!0)JgItdAFjzte=b@ z8!ASBRQM%sh6_E{ubrp}&=zaPTFVw1=N(^e7Kqr;Q zfUCFfuBPKpQzbaKn{6awbsq^lu3W^Vc()h>X0~aZWl?2Q_2f*7kHV3FqAAf%to?ND z!gU*`qixYrnHI+11U;R$&ydX0xzpuNA-+_GXd%axXIUi4`yBI=ITiXWm4%|duUd8G ztC%^K)s+XUwG~#9?mCFjer3S0(-=^sdk$7oy=Mp~<$X`k;oD*GnZ7eG@d<9kEXEyZ*-jJ@49Dc3w1JB-^$5$g`nx)W{( z!tb^!%V~>mtESSst&;XV+SZJh#W|O677b%hwuHe*g*_92smQFMI(<6k3kB&bK2_aR zy#uY^Ro!kT8=&3E5=b?1QjIgZIO@vvP4HKCRNiObNuDrQ$)`x7m2o+zmAT7Ge6vI@ zld-t!Ikh!FcDwZg2LhQ7%oO?>jvZ&s+1?x+5 z{-#6hjsRA_?MvwXrN=X2&PYOcG_j{0b9%M5Zp0_{G^L(+bgcK2B{(ZB)P+-vyO&5f ztnJ~CB)dIo_SHTz4>}u`6AE3Yo9fDF$>JwY+DF_RdzXJ zUu=E=;i{{ug{`g!5n6gx29Nbd07q)5dtvW1uukfESek}28XDS*kXjDijh$Dr9Xr6) zj2-6*F@x7y4VnTUFOhn5ahf|nPDh=@Iy#RfWHg)^>*--|`3TqBDUau(b%{8vm&4ks zuXqt}B~2K0={Z3*(I3pLLo4_V@JB$8Gr~_HtUn1pP7^r~Pv@KlJ`D=Ef*dK3Hvt>-ZBP+BQ{ zl-?ffNN5MC&<#@YOS!4u6f#tDhCTbx zj_OLY_BMazR`C7o63Jo2?meZTUD6e(KiI}SXb+H`|$@fzUD08FCnouJ(w zx{u~H@5Y*M2X_A-vNZ|iWWV|9B~1b|;dpBkf2@_}ERks$^)rPz@^>=o%-G7^Uq&d* zjM$eEs?*V)O3%h}0DWm#%1@NANZ1XG6I@%}T$t|XcWF!~a=eR$E>&03S0U33x`${w zonlXSX=enqmWlwj7%~NlH;!H44?s0tDRf2x+V*1XDUrYeF|r64N4T1VN71(*vMrJ+ zzh?doa$UtJMi`v-CF+`my1pEy{R5{^(Qh%n(sgte99;(~Ky_l|QIZ|*jL_-ojppGS zPFGV7oc>?jO_lTo>N5}g8+WOWO6Q2r(XyyN=9u5btkBv9zX}+f0qqbaYD@_pg$IB#=iTHVY`qH&B+%` z#@?P1Be&FZ4ynp8h5IYy-q-ddUqq~+K@;zZ5H3-cg7@$Z{BG>RXfa!`@iByzM~*Hz z2R((?VmXMt>zEBG^fdGDIFpg7!3arrVQ78miDW#&f=Yux3e!V$*0={ZMaURU$W*85 z-XfR~W-? z+H#^>QcfP4$-YYG4Py6bx4CcaQ0TU~f7hYVZ*$M=P#Ctk3py0WZSJHF$*yD5j?ggM zk(Q=omxpMorGs?q^hXh5I^I>ZXUr{Wki*;LutyGiu&fmK0%vXd+P^Wif7(F+HK%BUtrMvc-h}U3J)x5kif1FvF%zjaeks3%e+T`156+Sl z=mYO%J?7C)QWN92oa4s47I${16I5)9=2Z+6z`rq;a4yzexG5Q?@mEBx{1|9fL@bYb zvK(O}=Oo2E5m!eQ-DKQHr;QxGFuoXs#hI2928ZI5f&ZI1k5_big$LY8;dGwny)J4c z8oR;CWpDQ!&4`2+xj(t;T%?LOl5ZkLQZ5{gD7d$>_IUQWKMvV4XpS_L))oHiAl>^w zJ8cJgE0eZ_6D^Tw2On;K(jLo!ruoRD2+Q0KIe4n$9Y8*|&QM1Ru}*X{MNRIWP$&aC zXhe@2lDHF4ObTOYGs3-zJ6kx(2rtN?lI5Ef4bs)i2=GG{PQ@6o6sr=tYYj}e!;mUX zBp6XZ=$)ycRqiYX534W9oesMUuODK_IK7p zHD$FgfB#|0YxizAaXRCRb7xjv9X#>FUpI9$T-&%Zz5T$7Wp~7u_J4V7`PM6!FvCu* zR9979k`n(hN&Dd2*3~m^Fjdb!SHhpXrS_)%;d6?MXPr=b`!^*WUlG(l89xx5w6d|) z{m)~sbh%=$K67?u=Y-pqe02FglK%O@!b`#jpK+ebpH4o!y8i0--yTsJdOi5V3pVbp z!`JTKb>tr@Pqw|Z_a(MKyIJ+S)>Fp6aABs=B^!ff{n!1TGlJd|2-J|Bl?AFf`pVrk{dtWM|hO;?bm-+i@9y>k7NOy(OuXg6N>R?3fmIdy3H zRp9>+sn?G^Ba-!tP zk1F2Z)p^OPx57{K{_xL^n)B73zEi6wmTtc3+0aY;={4h&Ge6B%6#s6v{^?_PCY`ys zR&~|WCG2RE$?)2JR^zd}pm5#cO*dP0CvJTC59ccXo*et|hQ?#3#@HJ}hh8}F{$EF4 za(LlANiU3_v83%!&#pYuZf$t!s}~Qy-emmbMMcx`=Wm@h>*T-wxc2yC!}Gh84I@5S zlV+$od+&^8k6c=_D(S$YnmY{tNIv(Nr1Ot{j_9A?tJyHqpCTS_*4{6C$K(vWsjj~M zx}`nu-n6{FcJfL~M7?75?U^SAx*Z)`7Ts~$^tXyLH{JZv%dyxuuRY{>?N1|5K6Hrx zy!oI1yvrYc{H-@Tr_TNEqbt9?>6P$J*S-4G8Flb7@8s69(~hLh*_rx3{#2ou%-^9b zIr%t-ADq!=zT-FNP5wlfyKAlSZ;DxlS6&{$+Aqpi zUGv(EBY!S1w6*SB^nycKb9l-BNbkQ{^p8+*+ul=Sv!DBL@u4@D1@gbE`f^Wm&24)B zDz-(f+jH6EORr$`}%m&`|}%=SG;*xF|9KHrvK>~!H4F|sxI$Z zyZX|Kn(%WUEc)lE8x0@1#2KAa<~{dn%b)kY^5Nb8Xq|Ol3OcjCYiry3=8<=t{=@U0 zYJMSCH92&|uYUi%G1q-K|MiZ0(gt*}9;h=J2Q3j`^AB5_J&^HP89SMTY8ep)959ECT@cQh$x96rJg z#Y1zZKbd~YpP~2!{zN?G=da@tC6h%dNO1QTJd|7-Ps`QI_*waz;uwlI$ni8L0Y~F$ zeG{BX&`-HB6t6;vp{+UUNY_R_=o|4)HC4$MPTIAp>%|{KDr1 zJf)WM^w;r5#3gF-@A$E6@|*F=gLvQ#wqpW+%71{*{9o`mR~U?=^iY1VgY~8Hw0)^h z>y39JkaHT7_)&QJ8){z~9>VqOc-kJnRbLAC<3##5@tcD4(Nz}{QVjoU_(gCna1X-$ z4vwCm9-fAG1vrnSXVOLZ7OBwTXG3~5;{O5vJvbZEhJJG{C*+z*gshoK$VG7Fa7-!o zy-R=#F3C+uGyL1&{=fRYi1%0f;an(CgMLrXI%LVG^?8#)tXBTU3fYPeGIb##3*gLf z|8M`!Sh44vOUUK<;6L0BxE8oK;B2D_nFhBDuEl{kxc+hA9o})~T|&rm@GOY@|NZ@! z1OMf~e>w194*dUw1NFq(e}a%t2i^aPY6>&-qv5Mh{*v#uzhe%6;g@fkejaWJFZIU( zhWeA>@_v;z1V`}?g@4PZ>Hnwq|A*+&4t~QnG2}nJ|9=56G@b4*tF4wgjrdX@-RHOB z!Vw8>Ih0ziI-nCj?^m^$%5-AM0R8%Xf3h5Vra#H6dYYd3vVMctSdJUMxQ#^o`Z8rP z5zTQ5dr!aa5COhNS21KJaNeqCN87Zk;fs!8WH_lG-GWMi$yip>G zgGBW9(|A|E(y9{I#lQ-2UtE0%=OanP`T-PR0k~=ThwXU(jWTeWRYt^TB#n3|ro$;f zdxp;2=+>WNY+CRpqwZ>##itPqK;gca74*@(lr9tW0GVI7O`ss|RSSwub(wVwT=Z)J zZex2^W%zuvJgXKsaYBv|P9*WQ5MM-w@~qmpDpR26bHwU*Cxsd_j*e_MFL3F_SL3#7 zCQmOuf-_VSR%LyTTQeJ10Uu8>WC{(-hp@Hd%belKX)K}lPH72LHk9PPL&kEUR3~cs z$K&MPMid8FQP&Iq=>li9%C1Xb_^dCH ze>}&EpT~=V0q3Z|ur#g&R-O2OjAKimm8fz5ZxV1^SpHx8ekuQ0{Fm|%%jK_@^RD>q z@`XhCPhC*{feXqn9V~ygjHCR5@+k!iid?I7Vsk%z!P?%MIEfwN$%YGPy88l}?w4uG zmGRjwpveiIB#~{0N>*u5-*@|x%Nh8KU<<=Wlm{qZmc$)I`Lw2m@+Av&DUnY4C{%wh z%@gmn62l=Ucue_&TYSL<&V`_F7y8^U)IK!$wM?e{@}Fs^ZGt;x;@wg3*gJ-B{PN`s zoI3G7)Oie9hR{6-`Pz)Yy#{wA)CX~khhxU#X3ND@IeSW~vXW+N_G+E5ow19VoD_x~ zkKVXlw|g#dZi{Mnv#{Tw$KQtNnl@JK?A6FI-$mZI30)`n;32g?4Yw`SWQjEi>wS$M zCHGTnAXB1tlHy%3f#V%@%a>0h>ArbB9cnwhZ$v=%w9-F3fcEwe3pjC0Bt5|RH38yR z2c({7B?{&1O~Q?ox6l`T!L5gA4K)W+NeVJxeD*Qap&2o58Sw%6$|AuKmQM9?)_Dn?+upO6(1^7 ziMrw*m^DYP>(M@X6G-a$W&n2zz2J^qyD@U@ejL2-^ILVR`Bga`gXR3sU^&L3EqG|- z#VP;LJ3m6EfX~UZQ!3CBHl?_G;9!lF7%OPlKk!AhmFVU0g98r27iVtPRuDgHTd~SY zlw!lc6v+Lp8e;teEDORqv6I<`nXpWrrvPMig)r>EZZ9VIKC#$B5B(u*-JM{&=b=Pg^l z?8#-HF3Vd!A5cq>Qjd4CbIDS`^~N~d_j&9_D|vxiNrJPPrX(@khuV=`swG4R?P6V$WKBU+&-L+>UBm20g6ZekH%~#QSN6b^n)8$IBQJP9x;2(s40DcSn$7_`0 zUYR2ib5#wMwr{)lmupel!I-vXDk#c{)2~G_%Bdlk@4I))FuMm~j517FjB;=Y=Ev?G zIrf!TevwXk0;za(yWO2i^C``EMG`?~31z{1t=w zkIDH{2J`<-&aaKFm2+GXJBPb_gfl!{X{IB`@qSuXELtn4UKacG-%|VK)PF^5KD^Q!#5#O{pF>|ewaEG3iC!;5nPOl58`LBH6z2Cb z%u7*L{7y>Lzb`shhL1)KEwt|6#qd@E{!>x<)f}ZVN5)m2CiYL}v*Ppsnjf0Cvm|8(5A&qx0CeP4VwRnGNt z)CTCRBAvJ+HWAzn#1hnH$lT?l{hy7O;hy{%ZbQrgxcdj;)H2-cXzypaGTaWpWff^6 zR{3kI{AG8s%Dcm}Q?}pm~SJ_C&m$;}2 zOIg_Gy#El{X?!|u^Zdyvq!ObN-i~12+8$j|num4|Z0099>ZjozA1iwLi{v?HXVkG7 z*12|5sTe*$=OL{a#^|L%Z=~a)OJK#b{n#zFvUoqyypnO!ckpVlysv6ygS)hNmEv{1#QJ{Zr$JiD%?z0UM@O8V;9ty2Ip3-Nv2!#z$zg^#ykjd0fa&61 zC&sr|F@CeSjk~pvzCon@p4dM&)0Ep|njBM@#++Ti;I`|iifk{Up_AKwy z$vBoosSdAn{t0(~DDMj(PdB4J`{6p^s4QkfmZ*M5>-d(LaP$@~@fV^ol;W+hpoO>c z*4x_(F}u*1{jl=#6Yfo_#07DR`&--vtjA0Azd+ByU3usv?7_K2-9p4a12Q8F+fRif z&*YOl(l>eOq}ChNEd|6N)(+57^^c3z)2dG^C z@u)e8%-}7=$SFw_GO-W3`xn_=+Ah+O@mT5V()Ij$;rooo+^REE1tqNNIDO3IAMsu- zW~LnPHfzOqaFHGkVd9|Oe zJeHwfQ@KI=!%82mskcul_l#lQVHLws(?7;&O)tVMPkTl`dWfN0Esl;mR$+bWP=~%) zX{vE~7U2C~fC3Un-$3!CDU_Kq)>83mx=EGb?@>XRZH& z7AW=nqyID6Hw=6t`@5tMWj|9o9m#+d0D1$QYDc)ck5<1_)^4cWOzR(#u!;S&WoX<* z{XkSB>#q4utvIruQt$-gO>I=iO6a0*VI1SZxN%Xd4w5KAp9eIIcm*Zqf* zNK!8E$OvP<=xN5!`k5A-povD%X9_dB={WKNw0uR2)@i(0D;oO8-bUm2KBmzi4hJ_h zkY5p)9zLYO9c5-G?06Oy4Ao?50;(1oAL^&N5q6yV=$ECB z$(uP*3r=GU>dRY0Q&RdU9wTU{dNC+)#KPJZE%?%l(fIo?N0@w9agOf>pEjUv!h6ap zj!Z4isnrIU-I-}s%Q-S1Uxot(6B+TFUW1JLfxi4TQ&FR7;2{Z50)_8I%F&Q&1?ihbCil)FgKsvhQ!s+dM;Ca%PzSDvk` z%3^X0$OmhQco*93TS%_>8~OJClCP23trv48j_^0)HC=I5Z2_vsBkwoJ`}J?+z4zz5 zHbMf-p86sKKbxne8gC(@2RTLL{3argmF2LAAUZIE;llMAs&CP@r*EeltwyB0-KQbi zDY*S>w_y!tz}_bHwMBI7*noM-Mz{?oySd2fbgUhX^zGQ2DwyIdo`#miPK3BZhMBRR zX_{J;zQ*O$+704efZ3mQ{Nb|VjQXr8%AaAc>7{T5Q_|Ns@XBmS@%#yjcN9m5+z>{0 z0*a)su|vhSkvk`(ZN3+n>WfVF%}#@OWgKg3P<}_>VZ4<+jQ890mbg-Q(yhZdpO0By z>bVtTt5&?BZz4twALLIA`VXo6ne?^KcC|m9Of1f<)9e^dGX9XYhwAb7caJBF%L^v! zAltiu-w1yozMwn>{)6$97W)0KUUobEo)M>CQ{!x)h~U0+czZYfj^G=T(Ly0k_olQ^ zOp!SK;$(Ph+*59D)QS&dKC*|+yJ`CRUUg0u!W8PS@o9o3@IYy%kkZ2Xt7c{pRiipU zZG)bV(R6}&0ve`d3FPw2_^0?B{!)HLR@dEBH$PB)zFI5(aljHV^A55Zbwhs$ImlF@ zzBmIn;n|%Ezh1n#pKVeEsO~~<`m>FS-KgupRG#j?NKcCEgt# z?4u)LR#+KOkpS+qj~t}d7qu5 zV>F{RxE6e*xZU8&?dZc)4(V7V!j9pe52?3XpS2&*?9lGi`N!5uJ^Kf0F(wDhAFM4r z0NZ^77ah#F!{MG-(}E+U*MA;y`9&J zPsfHGBz`+F9@OsEH0mEQJc9Ssz58I%=?c5@AYKR6)x%z>xnyR%x%C~@YclDi*j3G3%vG3eqsIl*(!O)5R(}N-1z{!XjyOb32*}i`a#&-9=GZ@P2 z|MOtz^8WUSE}(o=ffsbFUw;s~`|s6(LXx2D{(Q%yr{iRK}D!4$SLhd$zy?4!TE#o`X#lBDO+{PY$v6!_|I|K8)9;*wG>4m)J%2 zlt6=P>M#@kIN{Ss6)|F#qL_Y+Ds$9f5}?|hGQc(kGG_2rLU(1S^6`iQ(t~$NGZZ*; z@CAoMqjC#GNYA(-({Pf$Echw|8Z6K8^;S+G>gz3eybo&+gSa4yZ!7(VRU2}5P}`DR zXF0;|NU;q+qS#eE6PinSWTCEeMd`TY+bn0+C=V{mps$UTSV=Isuw@;V3Q1>H);YWg zGlVr>zk6rNT=x@ZhHG}2Cm+jr!eaEDi?9>Vwf+d1q&Hsf4rUXD06P!72V;qsr*^JLcqtU734cvAW< z!ti+MY%k$A@<&ns4$OsG=P2BQlX})jgaf4CN@n2eVdnJYiOP_rU)4KE&UO_ld#kXKA5EBw#@=lpbE+7NYH=V%|AxWgnrd??V3zA zc3`PA_! zvA*8qQMjI5^U0d#domrFry5|dyMT00rFdA*Xk&$?7gL%wup1RS+Ot?Lx)%|YgDjhRU7p}*9;7{%u>Bu-`c5q>DUGqJ|yEWr} z3J;qB>jaJ?oo0*;Kg5(U#*|{v>4^15Zr?r4Yo3cRD9KRQyasmrA~e@1N32ug8m!H0 zT;vZC3wBgils=Zt6tS?6q!-T*I5san5<;#|)~9>Ut~ndoh<);TS=eKM6?C1j4Re~M zP8x$<(P9rzxQ%NXc&brR+o8RY2EZ=L(uX##Z!grKZ#D4r#gSy+xF!K}3NSr*gENe< z!YFHc-L+W?*QGq_+)1n)&+`LqnGRz5HFV29#24UjVVai|szV2C2Cu%NoEXaV zu*3Vw`nej#Ngb?L&b56OSt@jxt9aVK?vzHfy|acPUd$yEZe_?B8iv0n$Z{BG?8)Q} z=!klk1u{Yklc4KcNipx>rJmnON!_s76mr8V5i`NfA6;XI{l8RjeMs6e>ZC#zyszTV zMn+ki*KhPtD?8Tgno_A}E|o0oLpk_=MWBT>Ir!~vHbnc#ClR|)DWnN=Gn(9|JBs)O zt?XbMcSJU#Uxp%L5QY%#S)^h8mP5=AT60w>&zoP7Up^Z3JswZSNXmqj2b28>jn02N z|0pZq1vkg}6i>4)$#^yYkfh4NPRnjGCL^S1YBRUFQ#&}!{RY^^I_TDRFo8}>N}zET z?G;wvMW74&7`}LJG|81h%} z*Mp&-@;4nT(=LtSM8kSDwT9(TpSsaT?ej@RBSHJE@ljlfV65X{WhY}gQ>ZwV<~3E+ z*uKH;=`hz8SUc2&6%(jDRrlMV!J3a`K@t@qy;oha+V%mYh^8&>XOKbymLuOpdQkQf zI9m29xX0k+eSpSF`R$$pe3{8NpiR%pb~vr}#0t|${2t8fp+{`6SzfV)Wkb{zXJv1go$OJokrt&j#TQ~F6z5}(Z zQg2-$w390S_O|`&_u*X|R>xh7$bR(1(_yK&dChl`=OK$b25F~qx{$@dhxhRfkoJ1C zxfYhXbme+b)*0KjUIHJqUS);0{KtqFqpQ?o#7-#1@eFX>gS?anU*UTr!p@+6&Za{+ z3<~S!q~xxg3F~URIP{4y)$zi#bs11d)YKyPWg7^Y0e5$B6Z%5|R^NDK-OuDGp*3UA zXn@X`R_-xR{Wwhs8>Rl5QjXA+_ayA~jZX_zm(njP_2`uf5!Q}1O1)n6^bxGW+DqR9 zt~0>314}f@D>?!uV+@3bgm;KH*@k;ZREz*VTa3O#9PUl45NtnT1f~{n2xkFJ^U<$T z@dk21mX+6w-}W*&PTmk=0(Q*5QqSc`WkXH@Ygnv(u%^r#r;ek}E6_*g!`%XR91e0H zV&Sk;GmGJSBZfMK5B8~l9V;mKXv9D^6#IfX)FQ%oW$4Z#eH|=-`I5Q~M3A+4ZD`JF zVk^kP9x3)Y*bpb=_Vi6F>TjP_|kNJA(Aa$#28_cI+tR zTv@~%(1^G9(VZcUxD+=LaKEQ_6xLm=9ZcrvTW{EP#>z$+E)=Y!W2Drxr`Jc{rC*Tl zN4hEuJLqIs(J|P@+nazOEaomnVM>TWk1~K8bZ5(GO%^ob9oSPTLW$G*@?eu!DUh)u zWEJsr-vR5H^LV$eu&ZE6I6=Wul%Nfd6X;I!b2zKQWgO6TH_Ab8gBC&mXA^~;fjvMg z=Fn8^@1@e!al1wg&>h~&I0w5rq^go|V<$9YCC@FbTH3sH9_(8&6S%6Xs^+S*RaMKH zmyMc`?z574KEID!ZfZM+wx+r^-Ql2?&y-G$80vkh@>5tyVV3%4mB10MVJTDThW!!- zA!^xTp{JyZ-t6%O$D)OCcOJT`I;0@uimA;MNR2%MW%$|}aE_T2PS`3W1wV$AIA?OK zXwO(t-RNFcat`w_gLlwM@s337iti(=0I#|LtHRj>%}4DTVfV>C78by5#o0ck=#i{d1)xq0 zrjQ2@sR&(Z(ene1I0|RDZ1~_xrug782e|_Gmb5MNa+*q*Ms@=1J;jwd!@~ssLyQ(H zoUQmu4m(gXU9lQN2UltjWUwn%9ye17T94FmXm7fL7?aIH<|g&#p&SjhmS2z@=5TvV zBfb{LISKsV_cDaS+}caOs^jb)>^NinYJ(KevhKt^8ukEonnD_JQM@CfflbrHbWIZ0 zh)epu7wGy1_LOq|0(!2H>A|?wLT%G*LC#kq>Oq>Fpz4LNf)uWzSTpeTMd%rMt(92I z=HL!R3c-yxLVL*vu*k1`M&s9eVacaO?Jpq3WHfZ-D%b+1vUwPL>h%6uVm59sHEhD$ zfO`p~f?7*WCYuNGycE}aaU;mD^HMBUG@9~JsmFzz7D`aDUB>baR^D2S;a?#CC>e*5 zY(;+jFFFTcS6qA)J3FugC+>_B&S=%5t={QXVkZkd2~?_|*5URYc1>j()mUYu0=pX6 zD+g$<_Lu^cwxJAqPi7V990x}@^eo5=vn&(V#Y~WgQCMe;xZ?gpMWA0JeiNI9nMNZ{ z>Gfn;Lhh`Cuq#fnmG{!QLxVj52GnW9GT2k2{(~{tybn=`%_xbUu+TG0jreYiNzA97O8|YCb%MvzKVDAi4OL=@J=1<=&sw*d2dwK6s zq)=LSLGMzN>E%r0aM1E5&K244VMy-bWm8r%*!jI!P(G@m|ML!~_aB6;Xt5r~eV7A{ zv%U}vh++JC|NpqhggBgXl|yEhD@Vd-5gT@w zW*2G1zsFSASJH@e@_A+g;u(p?=wttiV8^8;>3|Wfv=8?Jw08CYbi$|!AuU4hMOlPQ z2)!NE2hy9;aC=hkHv~)v3_H{5PI`Y5@O*}IbE)SZ+_%t(-O=ITCgq<~UNsI$=(ZTN z4M>(2k_APKWVbYm+e#%JZ=PpCWWz*TP~87Vu}nm`k67R;CIu*|bmX$N7?}jV-6)i=t6^ zY@#;4lz^X?#e^GRUzVQ^0`92kn{4=g4`){N4jk^`P9w)nZS(8W>vGvFkH0Qc zndRxIQ%=ZKbDqp2+V-zOKQo=eXpdzjD}7nUnZ7Ljy}qM9rSrQ;2)r2uYW3tQrxs_2 z?@LcDi!2MZsWD$$?YOVNtIDs!ttl`5*9gMxUv_qxsV!?QL;7w{tO@Wx&R{qDsv_A2 z+{%wv()|oE7{)bbBQYH?0poL$>7a$Aj!w^K{aaVeft8tP$-Si}QdKIJ?8N`{<#u^% zw1Tq8Y)&(4xB}9NROl4Noh4PJUuhS(1eeMDc9rYkHup!EAGQ7}LAzV$Zx(b-djDCB z3|zI*UsavtZ>~=EpRG>uf9h5EQvyn?<5d2nfZ7ieZp47wi+bE*R1BI=NFjSI&stOg_1+s?`0KjCr3^f4fxY+uo4=>@nVD6ku%JbH zN(_^~FUi4c$h%x4M)#K7;9>&lo>BOJhf-YWu2G)JkQKL=jXXT&*vO~kFb4p{G&o} z19nAI@k*5VfoKXU@-*DOrpcz@S7jFb!1hTkJsb71?vriPSuj!7leYInV<%tST1P2b z>k_rK){WJc#;CT|x@oeNr6ubFXAbo}30qgD;;-6_43e5?^-A<2AHVD5PipVAO=HH( zYBTD!J!v}vN|^~(o+nH{i9T_7n}fe8SH@~L%1ttASLkg4#nApMmA~2qP#gQz6YBl8 zF46cX=nmpK8FH&ZZcje?wNhSUGZmSF@1ZnP&^Y_O+I)70Y%4YeKdGf}%fuS+s9(X` z8kSc1O05lHn>?lHz1kJ1gL|}G$w%Mdb41Qp7Nd3MPNJh{wdJ-MyKLywaX_*OeX2t1 z9)yoDlU|mK8TGPUD9fgowM2Xv;{_Q>WKVN@R%tU+yNzzDHqeUN=b zeM{P!+t9n<3DkDGY-5I?4db>#ULu+t2E9C-7t)i>SOMVi04;f)gCnZ-$gM z{B4tup*FK#8$)e~C2PaDp|+iE!8Vg42X&ng4MDc&cEFQH?v>g*05OVRs>_JFR>(JE z)b18(+|n>^`52+Js*@PGwdfs(6iui@K;JmMHiG36+Y%8Yx3|CTr8ZNMP27%IX}~-; zVQdXS3b)&0wWh~1uKWCUzTj=c1^8G4-cEalCAdON2|B!8 z;wo6jObtF<*Sg?=I@Wd2n-&a;7rmyg^kD0PhwG#kW7h;d*4kp|%Fts6TQU(|Y`GEp z-T%< z%kW`n$4r*L3ADM~Zf8nAi8}`$y)&axmrjFqi*JR4e^N|uuvvUf4l$L&X2%KEU`z95XV{L|d@H5w^k$pQ_uo=>DurK_ znr%701lMTk$b81@Sn`yST)<$i#2j5YuV8<-z;fUL-0g`sH-$a&bUnDHhQrjR9mDnD z(-03&&|JVp_qfwShR5kFIj!F?P0+ZYC!8;m$fn@@rSsp&3OvKJNge~Vi#DRiq-e8- zL49knvxh58ns3<7wjo@P@E(LJLLb7_2v;NYB3zE}7KDosE=MRMya{17!W$5lAY6nn z4`DsREQAXX`g-T$e4#TpKJY9~Ig?g7im$z}CFt?#G9u7CVTFsE-HLas_ZT>8l(QW< z!O204+El8Seybj%`c~;NYQai9HrA$6y_HM#chv6d^%(VpbP`JSzEPV>_1<2q$Eg4F zhb7(0qMgBK18$yub<}3U_sB|G3v>Y}d=j`Yg;!u?==^01K<|DTowk2WzQFf+d zEl z7tSdd)N!3Z#0^i{G3#)*(RSg+UJB^F5EmON0KbbdR#?7rN~6Ic0EdN5{AvOBFB7Ce z?K3`x>{|ooQWwhSLcHtM$XPumxQ<5*sO@=3LcAEE8VL(|I4(Q$fJdijN=%;p)8rkY z9(^a-mQ?KtNJhcWCnVGyY?YnUUK-^f(L&!C-11vUDTO?}9`H9|VyVSy){xp6ABuWm8wZNYEMu6_sNNAOF?SydE$ zN0+l=4qcZfwzlq~Wc8(b(i)Zq(mZ!Ng-*ir`eDITQp<2NYsORZ=Du#v!U@2`P4CC! zy(q8p`pW7APRHy9t$xs?ZG>bo&CL4;X}wecV};C;9o)YL#-E3s!gu1E(VxTmjp*69 zpsm6URM5T}7aQeVN!{r#Jl(vGYJ;Q+aMucFTU}6p)-g}Cs8m|Fz~)aqBKom*2FvxQ zGW<2b-<(PN%3z_vb=~FEV0wrD_L<1qaJDX^)P8bKaQR3G=r*gJL=~)XayQ-I>_CKOf41 zw$mAm$s71R9F51bdW`7X#!&-i74$rygSNs;G)}7bPe?=UBt1H!d4L{OFKAPAA5QP$ zeR>+RbIu_L+UMEM<@khp<`lsDp!{RsY5o2kkTatU(7oG%5o>pkGHJi}qSwx(me!Vo zEtEdXpP)$z+WOJARI%}KNP0cEoMi5%p4sm;%uGF9!X(wC?HU%Wlc(B1@uBfIvWwsy zm_qzaP*`xcCfd#HMK<;3&fq6T|bZ{nG34l?Zw?padDR@nSAR*a?f^<*zX7Oc-# zqkNH2LSDomw;4@e1a3Qa3|f^x82O|v6%ybS-!(0@^ zF&BP|@bmTLEiOT6KZ@p}v|L^PgwuRT&$J&z<0a|gsmU_FHZnOGYZ);WQF%<;6wQXs z^h6!YM&Oq-n&IJ!_P9Sf0V)+zb2zy`b<$&XBdHkKw? z1ix)oI^!lSCb~TKp{M}Pm~-vxZS>R4c&$N+O% z#t3I8IZCtsWFFz|16UJdb+1O>@5Ap=9R@^Mvg!Qb^Ek&$p0`_cos?CDkdJ*IJM~ov zy^uHY^*)XCSg+a-F#{?5Iebx3xF#8%*F(CA!iQ}#&Ho^*1(#dVDJ}`mUY9&ErfRQ) zo;DY2>-^B`-N(A;Lwc0cYKIJkN*+7{X;Xmnm@uO!j+Cnb_{d5lnC;TheIAWl5q!#9|Y`4%SnO8!oq;_WQW=reZ!xssRSO``ftP#@&X;Nj7@VLekeFxcYFmg8qCD@!-M9r?spG zY2VX69_2Ch;w1$k6}0I}j9&Awpglfp#Cl8Y@2n&xEI^()RrdoXoaWHGKM#Kt8T+pD z!+Q+S;dcXaDu6NUA z^&0egFUADe5dU(2OTJL=fBlDgaj*ZE{toDHCQqK1!}*#~P*DNrqEH3qQ_mnTy+9}Z z_iHdODggC2(25UZUv9-)vCE-8=}WB`?IqvlM$MwP;&Pb(`!)=NM{%hQw+|Y=)Q0_N z!_j|f!@)1K;Y93$C>gJsk7}V)1o#YwL3TH^7rdpBU)Q0Cq+xpaF?A7Cp_o zaiTdHwXb4-oud17rMbY$Q$xnWXS+-8p*8k6I1fUYgYVeS!hl;Zlg4a_8+04uaY^{b zXbt(R#9pEAYXbEd>lSxL?I!G6v>yO3yeD2V2~wm}V^u|jVZMjGz!c)HCVCw0Lb0Jw zB940q0_z9iW%V1rB&-r^k`=|lwFLeG+TUT&3OW7kpmP2IOV0zRjhi4r_| z2_Hm0LbU{&X+1^{-|10tr|N{?fq{jiMqTfn_8L0(dv*Ms?jbwj>lyTZm!#ts^_%EB z_8;JhS-o=Gzuy7L7Aoymu!p1XRyvjjoSPNFMpFs=?t;fN7qEC>a7|0`H*VcR-cq8t z*K)i6HCG^+D=j2QupPD6ufq2UIJCiSl($vSJBqU+0Z%jF`Sl^kJv1}IQG!}xE_`wS zT{1kj|DM8FUfO?yYyVICFJyUV58J=tq){z1V(;bjz39k2p(z)a3_`h4jEK6Gile0d$*1=*VauXV6yG_el)(ei|U zAhg_WWvgH#eTzHgyyKoS9k05BxWwmM+j4VS^}8U=t%N;&13b9UEjli_y}~z$BY8-l zI|(1#(C-)~m|!hm=40EUb>ODm>Lq*Qi5vaD^RYdU%ySTQ`V7D`Cp=wcR~W+?^%m_b z!#{<*k=;wu)u|p0r@lk22{0`UyblxZ8}qlpjrM{ANS z!2emNai=@ll+|LZD*C}))%PBv!KY(4AfHpcNRu7vD6_C%92-#Og|nF<}v}A0Sx?niKo-b3NqMxYXzL5f2GA zuw%^5w2~OpeisuQC5V4>1SgIIvz%~ACx_TI!<^F&%m~u=!?2N#-)nlV3CQ)+ScWqb zw34;(R-Em#`AY0uCDRro&F^C5Q*{II*872*z~XD31Np+4PQF@TGXS3b zb|*$)r(XZ9D1(a`_4;3=o`XsOuY<9KXK4m4A%+_P(+&+&J5mob?RK;z?PuiYglQXM z!t@y|yZS1bn@yZyrd<((l&QvI6@J6qgslhcDX8PmLo{AAS{&+{V~9kkgQJDd%M2w2+t`&-3gyo_Q0LJ zQ^srGsn>ohYUhS{$8{*>MT|O!n-P2fV2pWv+#z$KU5C=A>TS3Iss91L7nO|CFU7aC zA^SGMwfnk5k;Ix?M}CVu8CdO;fo3P>T9aN^C33$q$UEwg_q%#sG_zJ=u5halR8TveuQIrXr`F|a}Z2|PZ7QjCPN;y1O1!`EGeTJ_Zz55p0_lH53AEn_A zixX$=0=E|}B6+M!ZOXfByeI1Ic{hsnKgc=ep*?lzG1Y`J3Tek-L${%>mj4W368Iyky<=sC&C!_d!@l_)m2gd+s#n_&b@T97PS0FeobmD*+g0TK^+GpsH(BAwxQo%aSUpyq zhC}B8@r#*eN4d{Nnd4f-?*(Mf>2D|F?NiXl-UkV3$+r%ED9n(fp}9}#mZI*LqU0Tm z$|O1%uRRQ_BPkxyFF<#Rc*$($K#142kH9JiZp8mQO_Ze@q8~uBg-(CEAJBa?tET|i zX^F1+OSo*bCr^^DFZ_zjSGdURs`2%@Bp(lYwqx<%OAMzusoW>|`xVItx{U*M#^?G$ zl_NVA`tw6^&QW0JwQb2T6i=l4V;mA(eqMVio{Fz`jFkGhBD=p$=C$YJ>Giy}9v<>2 z->;xMOQ9M!<84RG?8)~{okK=Y!$XZ56bY<}uDbR^?MS*2Kg z+=TpFhTxsmljEcFnetJ7Dr+n+ZVZ?mYwPmbIe1>@y3!h`EnkbJ!CnfL(jF)465yHZ zr9T3XWYB=oE)26=L&>LSti5dFCcPbF?IZddr`LZ|oUDPofV<0BeP--Ur`ykT@b$+r zPp%%yK%1x?gzLubu%8mQqn$q7hK$St{NfWpRL-T-#D|*=?JrCMoeok!Z{y1pokL<- zL_T6aA{-p|7cO+z{dssSPXfyU{STz41TF+Wu_*U9@in%iShaRP*|6cNAzL_$4}XXj z{0vmiOB9zGNc-b>Ywlxi!+A>kL!=#ua91SK?uip7gfU5lPEGs*WC^|p+TvJWw#V5F z7NY);*QRNVKSHfHvI}-@*A%@E`+;#mpUzHegRrT4;sK}RpR62llg=jT4M={js}ufy zNp|vNd^Vf!Ka$&pwh&!sO`MzkdBnk})n5Y*y&v-G2?$XgbjKq&-G(|y8+}x-!82aN zXQ1&e!?y|0)S*6(m2Esv<4_(i@o}?1OO}2mO8;9#>-qN6h9iGV_CeS+iMdezHOW4Z zyb)>p!+BtY^Qtniyp^GD3=e0~D%GtlNYN8zm`33q~I-)O*D?w_js25<-6 z8S=jwpo);MEZ4S!Zp#@i7`IQeL6c>atDfsS)cpzch^P%m(1vqp1L4>fqGJt2M=#B* z?MQuTUTqomVYY%=W+#07?om7DjDM8o%pIfL%*1^1CDUBc)3lA=Z@0@BXI+146=Yfx zsaEQ#z6HO_f6Gq?C9=W?`8x1|%+NTWAURXlEy#oaP-l8!MwjoLZzA{%`GJ|~D+AW# zo{#(Q2yS@;w~oXIxKYkAAMqFC9H>5!i5b{D8XsuHuO7b~&`{tf4e34@f!w^Fav1M3 zMv0D>*muB}g4FmxPd=OGG2`S<2OMbcj}NTWYpF)=S4Vh9HcHwRcL2+z`F8zi;-rIK z*r-r!s$Oj?VzXuPZj`P=Ek1A#I5=!K_@Z21eQQ4WI&m0QV@@k=Im|w zP4t+@%S_R8UqJ3nD6!<^$*#I2)**-@WD!$R@;{4q>7KF~P~r(y%E(LzYDA;*=d@6r4+ zeY|c3u9=4s`x|IFG~de+{|Z`GvMe!Hbh2=rW%>=9VMk8XzCSjbd9VJu`|Gu!LS6}( zM3kBi3uUyY{TVk+gM&L9A9x7&I)ft(v2PErE%<(|gZ-nML1s5F?41Srs55PEDxOvk zr&qse6Q&n2Nb!W?16K_vW*F((L!LjDS%}ufG9abjlH|z{~XUF2&1vwt~|EeRR;|wH|*VomfWp!>66N|B@8zH?WNeXWM0m*T<;_C(uj|j&=E}7l_59~A4TV9 zf?G@69`b3Qvk}^Y1gA+%7W}}@%1c6%Jn)ry0@6p4TE}*gtoW>txWcPW*{TSQ)|Spq{VBs?Yi~f=Fqi5` z0cXC;JLbjQ(%3W}H#L%X^Akv|j}v^9^VptvBfQ|I?kEtS>n!ZOW6&|*>3ahu8h@HrrllK#7u6!ad#JgBEzuztZ*Vj*qs9rz1(#CcuE>e7jfO$kF3;t2Q6^m+tRWq`MO7sFXc= zDNn}P6=`8MD+L-eL?4w}5-B)Wxo@EN0jXd3EW%)B3h0LXDv)Y|!(2SapO42asd#>! zT_8O9%ihr48<=D&W8q^PX#OWKX-J+so7XzPpWsMx0N8W_TOPArO1RZz&#%VhhTt7q zfc*bNNF9}Xi`dcGCCN7_`WriYr~;O3!1+`WE<{*?P(fIT@LGf-!Wx8hH_f`6!y2Yl z^~bm!=fZUCesu2|l6*Z3*0IQYX@O_j^+avG&U;-8*HWqHUxWOWdWpnit<>vihAlnL zc@_5ONucUWtF4|NuWnr}K{F!XSILUjtXV@Xs@Ky~8x^EKI2Cg^Udl?GTgpcZqmo|ii`sLKgw^-vEx zaogb_M^Cc!0y|VeINxNp-z7roqE9qy-yM{oW7BMtyuMz#4UyM+&Pke6??CsL=&^YW zl9p`$9G90#DO|R4Xm&Y#e+H(L@5%e!61(5|W{Op&n@)|=-(99wsyF17cz4_c4WDp{ z8bzsTY;9fhv%B(nXIdaW@SI+5Ca^n_CZju66{ZmB7SL_SF47%_wIzI<)9r=gBuA6H z$qalBE$cmQF0`mx@{?|CB1J-HfqKVjXNix8(muuxnUK5w3vN;L<}}_wyH=Yu%4vTX z5p<62yJu*geHbCxmPA=3>rLe<8%(5gKJY0{{lr{MwoKPK5TK3L=Yov~OnRdB;3R~W zg&kUC0z0g04e)sPcKp+bi9J2X1q}oE+J=sD0QPWJvo~{&RtTW3BWE~Zmzf#1^-8>4 zuml{wK5-tNUx>QYT$>9X48aWog!a1*RohgjN)VLDvM+9-&~yS7pRC8>R`FDacki4k z!r1J5*@Dv&d)Sq)9?9DRnY?}W2kH(j@Yb*|rh1d8{SeQsTXJqk!Mo+ zx<~bNHF`R-(c6LXC0#9n-Gjc8yga1z%ZJCG&%{5EL@|Fze`pfcDCp6J#M@2q5>1T! znHPh;_Y=1ny6(`o8&&f7(A=B3YV4;o-U+?8p&<9eHE)IK+aKb$t+@buNqP@Dc}OQt zU^$RXjt^8MTX((Qy7$3f{BkeMdN1;l>E`R{PV4EW^#C5wG%=v8bd;5K1*9SiM(|63ONZlrb1A3@u&RKD`{ro4;d zeXf^pE%063fbv2Mq37L-7A!|Ac}N0azeQ})g`8>7@jMfAoSl~H&cs^>yAS$#`zkqn zP1!b)w<_e#yo7Rp?Lfp-4jtI!uEaw5=z$aI@2|@BXM@sVQ>evnjD9zgg4Sf<>%T9J z!IRU^0vf^QD*Kobq?7SXub8~hMESx=Hi+PCTKUrTfR== zA?z3(E}Q?24Xs}X*&Gs~1hWjZ^1WLPuGrgjhN=~U_E6mWb?NJS(1Qh$iyOooiCtJj zYYz7b&~74cx3=B729OKSi|ko=aRb4y0%i2S{bd+Z%YO3q#SME3s04x#!H1yZge@X# zAXyGD-9#x9A_R$y(N;*y{UvNd-BcroUQp~$A+z-O+fKHvYNFcA0y${kiL}U5Z}-*x z!jiBFO7|cBDbnZZ@Xq&Iv>T%}D$t@LzI?{%BDQaK`8LiKgbZp)s661pshI5=vw+Ay zaeF@7ZE^5UYJoCbs_&pJ!`vgH9xLthAekTGz{P;{;D={2%1!!HVSLWw1+rYmLyh2 zVISE!dU5S<+hX2>>we>9vp~_;-XBaa%9(cpA9^ob^IaM#--{{Ztw>#F+^M6BX02oe;tTB&`g&-YVoduhgB!9LrITtu^C1@Vp zFqoJJsro#)iS)Pid0-i7y^V8y7;3%k;A)aI;))hk7y0_(x1ALwM)(wXBqXykg8OS4 z@Z@PdR%UGEcQ=w`%WeTTDWZN}l5M#iI$xxrMz>}Gw$$N97+40i_U!1Ly_cUm88~-d z1>OpZ7&OpH<^{USBy|U^czXLT?5Hv4B4E;EJtSJZi5;HfA}ptTO4!Jro?VK0dY`V3 zK6Xxk_tGn|qrgl^gB|vgW988K`v}%TTt12I#b|SORt`Id;hvU|hq-Ma80I^-g0f zp!HY^a$(6}i(3rs5ckztoSc;5&tui{nu4RXe@K&Ap!+${yNrvxa-h4Jar67TS=onS zuCnF2cfwk)5%+1@=h#!jYhwY4-BxFD)p*VNy#FLeD1NjK`W?Ot`P?phjXwk~yi<;A>{f!ECQ-tG13&@5xYb7k|B)` z{8#*0HKqo|E`Lm&$TzRFDtp{#!_TVlfenf5zYTHr*MOPQ$WClXtSGMv`nZ0l85`Sl zNF1F3H5f8WNvhl~+*DFR;9J_WfoFPEV=^yizXtc!{omqrJJjS4twQH1Km!1J-mk>R zI0+TK+{5f)I_E1KghdvkypKaXxRj8QaT4{DZ04|%cS2YT+Fkl>|M^j2&+FLvsjX-q zdQScOk&eYDFy-TMP0BThvf$|x;j3Gwksv-EV^6~)+eiAmAjuA4_cWHeFFvppH3(tC zeF>@t*g~++7zhWXe1$pI)%~M8xE*x&U2GQ*n)WH+l<$U&XiWutG$g2l8OZ;4y@kbb zqTby$dM2Wuu{$$SM?T9e%|9&^+KcmKVAyu5(Oh1?Ha}Fl}ru7MnNlrzRgY8_sAZ2 z$buoq{p#iy8Eyf<#C2)J1;ALQU>}={a3aDP2s04c5vC%XgwTZ0f{;g;)w_C}-f#}k z6=36&-ZGshnC+RknCJ|pdirXlFV#!9LXT0IWqOQiDbiz9uU(H(OL7q-ng-R8&>2d| zMun5IQG)gyB@7j&Gnmd$RxUQXbG_ zCVCEifgWSh8X;R!?zOXewB(^dl0O%8{r?Jt58$~FVF00s@E(Ne2>l3sz1zlNazcm6 zn#*7Udqhc?Q2Hm3zEm&a$9jy)+^@%|mY^P^dLPka)RJAmEX}0zIZxu$tq-~3mb)jKbQN{U|Dwe;hl&xG9$NPJt+t81T z;z}=3w_t6|KfOh|17XLH@36DhJ4So=0OpClP@Rz>>d6hso|uw7VcK)?OFdy)4`?~m z2ecEI#|2=h0t>(f)3EEDx`aIp7&ob#Z)yS^`b2k=_bkG*Ug8KE*wg}O#DvUVh*VKTMT5kvy!Ll@IEhNr(ngM5lyQaWmLEx4yy;qoLDmVYEcWgE==R=YYcGkDt zLE0cM+`>@%r;s)=g%kCjhVD%XtuTEw&I3cw23|t-6hWKp)%XkDq=S-=zI~9)@qAP$ zdJAp6m~8nkqkqG>AfjEr1iXEKCDl=g9Fuiu%s~ug;@zHTqRz*nG?(96&SuUA-Zfl( zu|-4Mk??$QAf@s1%FY!~_ z0iV7)Iw!zCl+v7h1HEmAH0nF)$@9a>LHY$;AIO;qjVC*Z`|)F!b)(MH$RhrN$&=#; zf5CUQgSZ%bJHSy5b_PO#y@R2G(@L zA!b{Vvba>X-H1I8oSlkZ2-YU}B?7q3Zt!_Pn6fsM3^FN;9f## zk!Er)A~Z`Mus(z)=}Gn+LZh^S{VHOR0!2L$L6VEQBfMlUdJ3!4Qgk$8@8A_@`znlu zRWUeQeUcwMk|a!?iO^Wwe+^@CAl30q{LJ`aTZv=apgk>}eMdYB`kqU5_=B*+3T(

7 zP*!P5=%Y`v9@zLyR;lqkFDZ9ILMXiI8Bn_=_kAER-zhp96+^>zaf417LJJGm-ib>f zN~SqXd6oNU1$UVZr?w)-LiDBIJbda{8{Zi0KIt7m9Uvdd0=^o;%AH&9Jl4Xwggc2p zd4G@4#{Z0{p!}|l-W|9TZF%s2wspCSu_KtAl`N~ms7WKhu{B}z_Kw##aW%^ew$?iD zW}SE^G3|SCR|oX_YWll*cqcG7hHo)@%Gjfz$mRg!XWFmzy!|62yZsK%CpPCc&etOr z6IJw=aTiWm`=$wt709=*SjM#5hUv}zO=Hhr8@4#So9ZC--iEJV9X5amWO@bi0XVf1 zeZK+g-rNHS>>~MRGoX-q3eelyYu{xZ!bgZ@)PTh;V>NCv2t>Jir+& zcWm8gsxjR8;zr?i zUh5m3Sa0=kU5a<2=ej$D&H2!&;Jt>H`Ha%#)EI9!+<9yxk9jwMwo*G;%GKVgIR)oNZ!aEJ`a&th)wqs8Ba1J}L_nS#h8{wm|RQv@#s6REvR^v$-q%VIN zdIWN3L3YKWJ#OduSq&&w%fP&Zw&aN5NJENaki<_%_O>d!S-N@;g}y^tJR-_Kla)He%Lu|8(RLsoW8yQ9o~=M|mDY9tz!h zc@kT+?YdB+{TkBo-OW= zLMaW9+_=D0gDcDX&xqmJ4)^fMH&H6HKMmzc`!_j8p=u@AFs&VDFv;2e7irLVL|`$A z`VdzsK8(5tdaU)F^MSgF4c0~9g&kL;8qBcD-0p4aDwX@;?u_~Jt##L`o$icqFRXrl z%bj|%*)~*EuRh7Xm20kFr}z{$p-&v`y&766VaP!TyKN||Nz@2*q zn)A@Ki$Z26Zq&Jf180UL?y4aB0G3TZ3DcS-z98*8!08*Uu&ZSCGVLvJRrNA^h&E6m z36A9od?$`@b4S9!j}`)Y3k#gSp1S&l4T{>SDu18z3(j?dJ*~_TJ=Q4UY=3{&|aT8jo)&e3QE=F!qHn z-1k66^?9`jrBp6Dw<@bJ5r6cdS&L>U`yLp3<_jNvC{RpqWTcpl)Rb;8H1?fcR-5Cp z+Va*GES@0;it<+Ftv#ybtrDb8Z?0#lcd5S_bnI9^>{Az}ZJgTZ*|=llD;uYHa=c_a zHW!w6yG+g8@eD~`k~xtliI0hm)^7$RHz=$MZe5tKGOGodP);{tra*px@Dt7m&vM52 zy@pi0GsEKOa6B%UIL6kW%Dz;>sn?a83#eJu408|=^<~LH{h_YP0`4gu!E!}f|`F{KIM zw{y-^rOC&7f&V!NBiW31ejd@J?6zEEngSc>Eld476dP>vr725&@Y8|1(JqbfhKv&K zbSCVoa}GP!%coIM%5t4@D73_^(zZ72Zm)ArHUT1&Ul?-vD+JOwv{a7DxkSuI`OoHwJPCd zCq-V1#Q2ho+~w*k9PbbtgJO;-S7n1gxJ7RAR`k+)lVjqS-gmY9Gm`j{{-rNXEpO^y zc!%)|U%I@fF&FeUE?~8y1S)OeawWUbD(3wcSDhQ;if6O0s#}-!$`cy-Ea}Kemf$L@Y3@97p5?lP<&TG9>6yHy#X`aD*cUXps62Tj*( zPyU1T^fU&aCvKu=q`*2abDV}$=k;+`_*o>ilns_k8qwm&;a`CAgN*JAk((QP5zP-&r=#fLx&x` zV(|H}x0gG^8=rxUXQRQ@>9(Gk2;YWTY|_2y*fH&nNju_|K}$1pDA`+2wxoNk0Z!uY z&A~UaDU$;0&zEe5LYTY6t~I>dEm*n2-%85sr5p(y{8ZSnJ0xjb)vCMb}D^^ zDTYJ515mPg1+__?q}+npiPm8!#%_mqIV#rDYiHX|m1F6Sg!Ao zbq3U~ujK9BoZa?K&@E7Y7wBXZ<{$*_SZq*1OqDC;A~nU_Y)(_k70GK*Z-jn24}YlK z+`ex6?fSWav*7<f=#OZN(2#=> zOT~Udb21LWVZm7e3SzdLrvjZ9 z!Au?&;MeV7c8Uw-Rfq?1$4Y$T%FDv*);6$gr9bs}cR$YLb*m&$maO5#*fb|gFoYT` z%xTBEIRQDN~S@KWw*WGoG{6O;|7mha#s8L4%z=opValbkuGshONvra&g2)ZNs_?DDyooL|d# z^qI!yC$%n-lOe(Ox;XzORt;?zNQ5N95tz@U_5F#6!%o;;_ zg)H;ZJ#7l$3jAnq)a-Pqyu4%k5~1JFpKeulY<8-GVdwV#bU95HL}lmZDE3FfMaZ8N zyg?nA=AVG3kVXX2Ue?C@oQ1~S!X)`wbNckD%2i6=bhGn$ex|{tUM&|X`H)?!RIPFj z{EY-5U*XYxIngbhWc)mOo0pB|p%oig8ZhD<@c6At+?nQ;)XDP7Rb(rjLl16Ti&e48 ztoOw^wvKd}q)e1ET`#9AGM#PeaF zpfKkh)p%8&ya!a1_n|9JeI&ja;pn*I6u*+s&Er{>e5!i}V<{EYDX_z8uFmsuH9OoN z;|4%_0BN|JkVK>dUa2jW6n_J8iziEupF`Z_5%u_A;&yvhZ~FcKlkr=CUp;=7U+|uN zby;&Q&v_Rb-(c)o)cx<|VtqZS#cBTCPv5qHcR}{ocNH{g$Rp!lhv(IEM@>8D))zX= zJ56@`U25H&#vgsdxp_|G9M6HxBlF|)1L6yKE6p=iP-wsFu%RwHnDe4fYHw{nczdmD-2%tAZP4*4zqfDRLEpiR zt#@(oBysSrwfCmkCopxvWaWSFsEs)8-9ERQg;Rl6CpZLz>`(xlWU3yxBC$bAyd#?ev zSiZ81v9)NMu6e;pt=M&`Y~vzHCEpbZd07FsBa#fDa?Q|0$b#Lb+B^X(i##G^^{%*A z)LZiRSTsUu^fiFHE!mTR^>1$`EJ_^PB7oSwwPk__ex1C(YXRBGCAC;8TJs&N?B26? zZIuqL+FWySRlp^+!d4aJ-?Az>tsh)RaAGiK+wSKW536S>z`vDyn>k3my7p~yD0??5 z_tLzeH=Hx>+Peu&{#MXiLgu!vTtr+4*X+2v?ZQ*0xrHh-m zC&XQCC5r-Fy4>g3ZgeQST8bNhK!`ra4J{>VGnaD>U-PJ zm-$~F12TrVNl zo8WP2$nk#lTc8Om8y2Yj-A&v9ahI9`TH;u5c6oOJhSZ;3UhKo7?6h?NlI`$Uggy)) zpBwpLyB1Q5S!x4UD<1DSZq7c{%$*QB)u17mo*t%i>eYBFFwfQv{oNK9jr{%2v+V=D zuWw+bQrN)`Rbu~VT+vb2TWi$1rQY~}FJ6qHcfhvn;W=E*rxl-7Hs!fOvwgh(s|6>z zQ+=tBOg5log28^=A8O!L5oAD=L$ah2^SYLL2?mS6wHqtxQ9R>{j%Q7rM=VJiuX2YMO{8;va7mT6B@PPTB)>l)I)u}JeR zfbR2V#pW|P^85~jwGHWhr;_T+@$+(y&zrpKUgfzOl!UMPmn8)AD{*Iab95Z*Wl7+Y^6ngG2#=)(#cQ}-hj$c+!W@BetFfAx_wpdjjJ50{T zJsn%-^WdH3Yy$p&>i$A=qeJf8WMKzE=LkrgvTNh6P0eoT*d+HMb_1)W^B(-~D2=!m zv`Xx)W|6*j+UD0k$yxNB2&J}M*UU?;M;Zf+UdiDZ2z ziuUqlH-{@4cd$LnNzN^?Z%6I$4GC*_)2}c0)OiK3jC0=t?T!8@Rfq`%@L4Ub zIk@KHnx)>8tF0TYUhA4gRo0D5H^!ai%qp+o+Qn_E_!W!GEce+1#<|KiZ-r_uZsu&a zJc*Id0JXeQvE3xGmJMFqENI1gT^?`ChF07>a@8ep(3IGfVJj2+GIZES%${3r{0Znp zBrD_|`4P^!%l9)c#_0m~dXfX-3Qe8^?8I{N^yNT$t~x%jA)cyJP^*zH>}1TK#tJ zxVV%%Ca!4N+h(cK_sSLlHFt@;bh7=%jx9C7{d7Jj?Uz)S#q%HwEeF-OL;$47cS%++ zXak-GZUuT9Fa**+k5D@(Z9-r3ZOHbdhfJO~Aya3mUd`p%0@A7uoPJ7cJ1pjr*zC#CbxgTV}ofJ`}cA2 z6<|cer~>4L`vB++*&_)2wK==RuqU@H0PaMu_$@*hZ6TWMEL8mTDnLBX$r}Lq}+) zXI6u#a?sJ5>6r?Ap3~+Gm3!Xk*lo7Hc6KHC?BeDQoZy^iZ)U+J&f$RsUfb?8n0RdA ziZ-|tUf7{W;;Ck5Z@zX`${7}v3!Av9NEdMKZJTJqEN=k>_riOsmKJBh9~qjsOwV>0 z^yj-~+L~Ir+UDd^d6bSp*FP~%JkGBb*i|sL7^z$v*V%=2LE|$%XK^&p{lb^cv3oH$ z31)ea6#E(Xxk$E(XfB)_{h&LgVFS0=c3aDlHcKO9k>n$Y9e`2V-RVKWsvOa6eT|iw zICHZ++|FEoCgiYT;VeACGlh|Vp_EYi_38E1+w9_Mo1pzjWHWmT+M0@A3gS`NjfQ@FAy-y>CJXIqfi}ln*yj5z3QKTKu0n>*o^`%Q z+!M~sgBC?EqRUIIG>^4ZdLkoSlYMZ6uDj&r+#yLB!Qrusuf51U6@1w8h zRotjxLyYmW(!x7Bj(5zcPXWD$ycX6LY=dT`^rgBK$Y z`MDV;(0Fq_+!J}eY{*srCBi}U@vrd0Hnmaojh)1Qj%@c+O%=n(BNWb!{~nU*nT>yh z4>e}*H$AWGIGrCp;D_z(`W$b3;Pt_mks_t>H)w+yXZ*1UvmeD8y9Y3M06*G`XuV4x z6FuX8q?FiEG{Kna=N*!OZ@-vO2OfCD&@mqQw)sog83qCYwAGDyiZ zf<6X;fRgDU>?j>e+}J6AX)Hl$ap$(YbSA`s zv*@q@9~!y@ITSi=vt?+{)L+acuBI# z!s@LEw?a#F0P}}1=p%!ySaxzjxas~yZkGFz+OlX0#mQ#YMS!W zL+Spef;YjhG=>v+^sYhDhO~lhPR|UQ`P&A|uv_e}vZ{wFf8ovuSs<66cBX`_$a_!B z_IjZiWT_y3a!Pr;lcMJF4PLzmEOKj_4b*@+xHZ-LOvgF(=~dV-bb4>w29Z-lz*D) z{vqmC>#W`*YoJ3gUh}8Pnpt>9WUTJ&@w%4{{sZ$o(I03aB>S@v{dom#x`-PWaU>SU z?HlN>Pw|Cu3A#l>=;Hb}Mf)c3#B~YJfu5<5<)iOc#;NCTMz3|UqKE5fJeuHttJgjG zgmVKcn+Pn~xuL<$%2Gq#x;NGz5VJSEv7W2qVM^W{e;?J) z2gZ5$M#7+JJ`vu_>9=jjtv2TB+O}3)MEf@Q79Oq;RN3B_<6C%4Z|BwxeImPeO!koa zz}iL!UWV5_Cu>~;TopL#;cAktl|XUeaj%E&CT_XIVM_NWP&G6=Cs)j?ch}eY7DAq! zv&jL;WDl~v?o{|7h`YFoz0ht4oqTRH-Z4ma`xa&*53_TnICtjN7i_Mr&m)?Fz%)qa zKr?dJQ5RXSCs`ataV?(8NIGY9;D^wyeiGE)#QVg%@8jK5&;jAgQ=t>rhp%zW9gCw* z`I)U9dA>PR41L`SytM(gqXQodijcE#`3vfslq1W2QQ6OlqQ#rn@TAx*;*Q|_Rb`sD zO??m~vF9pNy(D2Q1aS}~F_Zr8UThp}r!ITz936 zMLgF}9{kb~W-`8W0zv`0o?|w2Gj*x;NswRsE9j|SgeT*=?ydi*YkEtUZ*ASg4m&$b z;idv#PCLT8SNd}9NVKOKXU{-SKJ<4JwUG`l)pn`;44m{N!A>>&Bw53Of2pAWx*<-s z(ifMWt^)q!vwmZ=m&(4fhbSbFz?Hbpjn7;QZE2eEnV~J~R~E>SgXPz6zKO>Scgp8c*kb<4(Re2A&ELV@W>GT-KPKb;VmrM<9Wvrhf$^e?uX9O z)0kaxc9X*DL0*iz$yEM>$$32coNR>QjQJCn+{40G{vzttdL!!aX6sMvW^bi zs+SLIhsjzO=+9(_newh4B6(Bd2{71-EoP$wbwh{e&~4I%vMNKF(_N|zPuBzm=&?dS zbc&~0?Kk#M_&AhRLvkCLXKQ3jP0*6v7=+8-T$M^KL~U=N9r1w&;(v<-Eq$&u`nnuv zKlW^DT~(aYIfgiUlr*prw+=-k#LvvbkM8aSFM`4~<4{OVLLs%>cph4A)xSc2oqz%D zevktSkqriYCoC``zGBD$9ISf;;yR!vQfb@V!dVNvz<&q~mfk^HiMJ?pN*&9mIY-(i zhJ1Jg@uxb0BWjBVXF1Hcfig%%vEa30KRoeZ237Ba)v|wfz`vQ3Y4h<#gme&NyuK1> z=K2<@n0w&59WC-37X5F#rP=_04DR-=?G?Z)=^O8BRrX0W9XI)G7X z9i^l92B!g92N(2rNTXZbU=nfr5_v_)LXo{>R zw-`u^;{HIXEJ#%f|DDNH;Wt&%9k}$}tbd11dSDZ8sx#rIeTMJS*Fwa;YZY8GOz#dus-(J zSdGff5xlMb&$~HStM5a2zCEL|(pdPs7uL}*M;K@WT(NPnX;HcAf}AGJtzX1ud8yTX zb#}m@5I^EKO#pVjL*y`0x909k%FO2KGP97uDftBU=0)`B&>69pyht2Zy$ooGD)4d6o#gD;8_I>5YXla7uLgY_{(xG2y+8I=LNL#ueKrWo@lv8L!K-+;diP=!EP%B(Sju>;#`r+L zo`a}8($4Vm_FU_+{wfua%mWRJk%kNMNDQtA~((G-=TC~AK$;?2A-Tf1&I-V6>ogt zej1=xF*c@8AiWm)IKpE#rI9QEbX3#Bn^lpqQgbNFZ@jQw%|e_DiGJCg)oTNT+MvA_ z9faM2e}+Z&S!4@xK3w-8B!&VU=i*|_3P*tN>)-HLDIy$AO~K-S_{pe@+f4L%M= z3A_vc=MjVUv*;%gO4sQ&pE0QW0g)eo=E{Xw?iePFGDyQ1kV&MoAYF={682gDP0II? zasacD+c^pR@-8=bW(MYdIy}Py6C3@d`crqtnWsRzx&kX5R$2D++w%Q6K9_34o;Ez{ zQqSMa?HR@XL^@$vJtG6J#CYw8BO?Rf8|3UG18)pj7U5Piz=rAXk>Sq=dZV8Yycaci zSou&0r{MD>yH58nhJWB`X}^R$LJE5krr`~+IdG=m#;NB~Ijl90DthbnJ%QJHhM2xL z5!ak)kDz~Mc#kGbkM^Lea6-NTwKf-*TIf#b))?zYpj&poq0mErw_IW^N3UlfnH%g(`H_4)ioxkjf9 zc?Q&)yZDG(3-b(YS?vYb*Uo3NXWPzB_545b-aI^tD&HSIRlTOWvj^xU>GVQENE7HJ z>;dUig@UAkQE;w65W8v64hUujbu#137{D!nPDq23bg?)@y$U*F6tAPA+`(}~)Tt&i z10>N7OUfCyxQt0iLVll93Ck?^`Q7(@-v3^nr|C*{)j8j@eb4uNz8gz+BVxUgjG8~X zoOBoUrdMS68Q6JW#GU|~bKJ}8O{qx5z4tG*$t?M+tY0v-*yXcn(t*Siml40bb?HM$ zH8=8yW(^Hp))6u^lw3=FDrg><-S?13W?h)}%Vpp8{yuxdQw&7sS>D4Hq%FBkw^&bU z^Bz(8=ab!nPai0wRv@r1B`LM+%Rdsz_2netKg!8tW$YXD{?&UcuH929&-nnAj#?L&Zc(ncDc8Jm?N_ep(@d*Txju%{@jRut(4Z6nj_SFTH~`t z=MBlsVNA5{?p_vafsF5w?uF;N3K=`^|LFhUJ#%aPy<{SlbE*{5>f@I9h-6$>s+{{(NcEOSv5(x5XW+N}uuPAr@h&bQnXlw=w zr}#L=OL-acL($*bfWHB)pgJ*n?|4?v0m;OAEdg>ZQ>xytwn^We=D&^5yhV z`4$&=mLrSU1!OL}-jJ4bEcsr;*remhL;1AW6v!3I`$d;p7=%VufRb6hWe|)^A@pl*)p;oCDHQIXn7MxNkjQb5}7b6M)e|O zVkY8@XGq()aq#$OO3XfHIuP!OU*azxhrPStQcQV1KMBu%AsOR1YtLxn(JJrXP!lPT zrE~E9ltIC~ZxXkc$m%ON)^_ONe225F5(NmPlSUp2~_{ zp?nm6NkUsL#)zvPbw9_&QTKCP!qvLf*U|4iLJIx@x<8C<=H#n%e~Z2=WjS&zxg3-c z$1n2}&+N%Jovw8dHN)@9H?%+Q*ldmY=F{~O(-UyIibiw4{P@frzVGlZwA1%v&g9LO zj*a<)`BvZC$v_&rU%tH8m1ccBU)O%JMW0vPp`ZSsFUX@{8=!O1l7^Q<%W65E6EH#Th*4lTUbNx zGu)D#&96_qkbH0AZ-k@dRpBH#Xj?t^K1g}Dbr9GHJ{iA(jOIx!trG|;{@&a9u$32H zmtZxrO7G{6BbPL-HTT@w%y;}h)T~d8!ooq@`E~_DO8S=Q7PBRMn(?tXMoM}$zAm#; zQ<(_OMZ0%|_E$B_H=r9+MYICQm zr}3`})A7p(V*qhtUh@0W+oLQ2a?hGX<@S9gFX;xDRwN&SYOUf0Mpd zr*mbaB~7x3@}^&3UPpVJ#-Z?b+Q~e@aYK*q4Z(r)nlJZTt03%!?a>(IqNa6a^Y2s2 zV(N3WeiB>O>DL|A!>7}ITyIlZ;L$!8xyrNPiN(XSc$rSmk0)I6adQ8{RQ@RO>)zA< zy!9*-frJNjgAXRR{ByJoV&@abNxxTUO$O1*U$82 zk>8^>Z}}J2Lf=f^8(lY$yy*}5$hdu7(=oe`4>-J!bzPeYf3(r{K-WS|R}v{9TKF=N zf*?32k-k&L&DObEn1Peg4B7gF*SVib#bl_T>|s_c>2seN5x;v+pa_xs+M& zBsq2R7_79{xK~P-VYWVITP-Z=qW$)K+>tv^_}=}^Z;@~VKaKo{(Bk_K zdrRpUo)gac>de3GQv8jF?gtx4uKi!VV{MY}$4FI5wPVMsD>)}W4m{ozqciVBe7FTa zS@@T(d(j3n+Hg-7#Z3QkChDXCeJ1ANPXP|-`A)$}76^1E(s>wO_`9wwWmJxKk%Gz? zI333AT-U9bBZuO_g}>#pB|1ZX)K1&^c-)bbOun$bfOhK00km_WFq@x5ekeSH`9k-= zN6K{kTjpP5mfXaZmLVTN7o8_`7CzWzBr1#nkwT#H@6zz9`B~TS+|{{;XYWiOUAd>a zc&uED@A$>(q^j%xz7pB4si5>dsWztoeKekbTGsPaOZ+ryBC+{h!~F3YkMW-x9>)fZ z<6^GPs&lOtX8IZ~GO!?|{BDn&3CnHAEO~e?j6H8{@(q_bo&R|kTG2~3r6e>G`tmY@7t?-bLFDfKYBxf|8Kl8sr z#AW-0N`cly`8(^@=aO-xo{hXGpAe9tyouSxh*5zZKMsCcBvyNl8DA!?FNgI2a=pWf zWWw~0B|0LdpF63q6xx`CQ_F-q{1)Ffp%#96s2MrlGf4=iU0r*nuv&AQu96+Y+l;Fc z**ID>ZYgYiZK_P8G0~=R^BJ1u71K$&FOy#)tR`)`)%r}{Ni>IMjd0I{;Gc|ZF~_)V zHoAj6-$}U=8P_fkw_v42_nNKBuDR!uiWo~WG57E5%yP9_mkSIz>(kG8%$H7XQ`-A0 z-yA>5wOMK3vXRAdsjvj+t&(z)_890UkxJ-YOQ5|cE<4XUgEF1@qA(3BfX>cUoj!r- zuDV*!l1>)uMGqO~5g`j)=qBNe&xkulyt71zz*e7#IptKgRiS5;F?CKu9E2AIQg6y- zBdI{nfSwntF#>GFfM1RYc327K$V{=F2X5eW;EAYEix%5d2^B%P)?F^p9SiF|zD&Tk z^l{wC+f-wS&A4A+DsH5*6wdSv{5orZuPE^naNNIg-cQ7R2DX6Tst7qVmz+5fC$V?p zv&eh_a{ziE+5@ALY^C+{Tapd&Z@d9-ge^B6sIx8pS znbOo*rb;2hZ@>E$Cg!ZxYzXQKq|io}bI37flZcZI)2k zK1#L2$37seDVr~3V>7p@iRl*>v-w%Xw0r=)em`VtD}PH@t-AsvnvOBF84n0|RovC} z8nCk|vR`P|E!E$L^)RHHj8nl2T;0ieW%K4fS&CJ~J!x5OW=fvs>?fb#)}JP^SK?!> zqEG`@>g7USNfdkS4&jlmrI@X0eGc!ByHsScazBEMN-uZai2GXHk9IxHor}FXxBbjy zyuD1$_N-~YaRF(1Qdl7b%k*TsFO_V@ZgHc1bE%2X;Fn`(ME*o7QM+6|b-qS&k&LXJ zkO9iMO0$(+1y54CIupCLVx$c+?J=F4>_!AVte&omW3uROvxF1NF6rYJDG&V1#UGiM z*k9zvwLZ&@YF#Q>$wn%1w5z)qtUhZf`$N>wkWiy`CkHIQ@`eLnn8OG?!I@4C{xp;(YIV}og>|0&6 zbAQ)rCCBKx!!X}q+RlweIrf;Be?UNd z@z_k>Ev*trzEz6O9WUJ^;Dk7Xo=UILGXs*yMdg(Ho$Tc=fwE+rij(oCESchriz$il zW}I>_%D_1s#M3FY$us$`Saj}RVo!0W+MnVyZEte1(|Xt(yvdzBiJ9nzUpdaV@5}Gb z{R7UO@6P?M^&Oe^$OP{zGQnN(k0BG_lmj(}O`XkeOfKP>$XP!bhuzvO z3g44WWgb-(xcy?GQ7BLRA{jtR?7_H1^F_oq#(Ci^?5=Id39(psfBxd+2e5xFMo$FG zPLjGZC#mw09oq%QSzfkPNS;K_)W_d0e~bKS*;|kZXiY>~+X;za9Le1zh{AE$9)gF6 zLFAxdv0CqmtMLEjP9~2?6FTWiCx~1&N0pyA$N19xG|fz&RS;(qtt2s=gN(eFScvW) zcJq;XaGD{LNbIT3=@{svIPVVc+>c+kbFUQiGkyhr^O%oPwi|t5vkv#dFGhCmNcnc5 zvkd$~vUajA)`mCQ;rnzMi26)~lkE6$Ct~BE+-<%_A zOVeF`v9Q%wF6gbB%j<+qWl-A5_n}6T`a ze?VICnrelm!cTc$8N1_wx!N<2KoTlvw+r#IQi0tuRn3^Dg8xG@v)D~^k5lcike~9~ zVP$y_zozUNVJWXM%`N*0|18}zlsE4v8*kc<6Axf7Q-Qj`94tFnrrEJfQ14)xlGSre zdeaPY6VyQU0t;FaOxuK2{LlHavK3`d%pES{5rHdnnjR5?LV`L$DQg*asA~R~e6s0# z^H}wpmeplk*>>S2TBo}bdp)SfI5!GvahjSh6NQ6wpD$g@mdx(5lz%G%3*g}t{Cd^j?TY@Qc>gc#FTaOR64PCY4n5H?Z8OZrr!g*rZ{2bLBBiS{YO!sf-VsZ*> z(+hBJ@5(OlwNHU_|BYp%v9CVh`%>9iCu3**%=fRmDm@e1u&ds13VR`1QBG?S=cq()Vs_m->seLBvI5$yMf|AYJYb-gFtC}%tD#K);^T|Ni0 zbf=-On@4uTB3=hcbTr)!9nk60-7xQW*bQmVW@9%5lI7NdiYqighvvVmoO!P7dA&II z&{NOH3St%qVkRWtMhba55VLy?kcx4_d3VtoaulbTlVpA3eqobvf8uVTUidHYuiwQh zk+pK8PZYkiHP59O5}6q40H2UvjE5BD#@)HmPS^Wuoex<~ z^IpxpiSQq8pWk_h@R0R{?T~`Xy((mb4-HvMfFjy}tlic*jgOAtYCom#wqJ@i1|jKXe_g_GWzj2(ETAzOG`Uf~zI@>?63E9WB}= z+bKdR&6R!fDwI6)A4~4|ES`<>XLc5oI|N6`C%zKmn5dC_y74EEcF9OO&5jHJPF}8pJ%njH^2%>snYNq(RDtg^hNM0);0}T+kNs4 zBq;0v2Ji=Yg+MWm&NxLozLhotM|rN(>EDOiXLf$8U~P9PSljkaM@|y3l;8Re30hz& zAN%GCQ}~I%QqK6E@r4A6rc_#Y3toP-wFO)X`XQihv&qXq!RVYJ(uFRg|9kz_)=Bm7 ztE2nW)959e%BrAl?83TX)NR~@io5_wT*02`yrBr(%8_}~9e?+q5V%z%2;7H2;3fir zD*^)dY}Z@B-%@>)g66IwAaI*~B=;fUW=bx1@5ZhxGv*yDT}KpuTLJv-4nfOfA1zp^ z;BVh5bI#t0^8os6g8b|c-sJ9+?BwgNlz+hAqQ24mM*CjiZ^|kG{9|Zwa|Yc+Gc<{k76`ewFYIFu2C9 z|K*d`-SQTU+ieP}v=OKh&dn5g!+Me8!?fSG@Pn?Of%;5Pzov^!GD}DGi*#DP)^S`< zR1D^4NNCrqF+ZK;tZ;39GGmu0b2OFD^sQZZa2SCb_c9Q;WibUMi~YHa&YYI`Do|jT z=)Ad0LEwH31n%F@nkxw0_A)L1iurK`feV(+COKWRmAP4S6@U97P_e&*GCEh*cU?c9 zq0f#JgdE#n6Ju`y7?MIK0*euM6hpd0Xd=RmZ_hZa# z?4nb{<9G#s!EK9L&4rhaI;Oqd~jik>zVnx6%=kv*FTnn z)?TD@YScnz1cUo2`u5+KwFqU=+U)!t@*DZUPS;QMVbh{SRi>((RFVQ?dE!`OW#Wq%Yc1mQ(8z`vyn|58y!wcShb9nuJLr9I z_V6CgSZGlBNgAF%o=nCb>vRsV>H-;~igx%6#OTyp z|KOuS~}M zR-hmRdc|7TNww8CR$``IY8jfuN>sbZ#D}0w9M&)%hlWwlcORL;BL^qiWuQB|qZ@R8 zF4a1Ys=SEQ0Ub2Psghl4IM;GsZqv^qz1Stj6o1=BPjtn+J@ zytR&cqNVEsANgUUsctvICY@SHTs|VNC6i!5=AHZICzup*P`kl}BEk$7jByJbg^cLS3T~4R~VU z1=;7`Uzg4|Z#sx8BREm>CLi~doLogF{YEl|lLKuwYKz^VBQbwfGa|vDw)UOKkUSG~ z=8>n@9-0TQy7u8xKEeGtW}B6X{7q(v&ta^h7LTw9MP0-JEjRjb3-a&aukPD=jX>%X zVt0m3uI81*^QA<+ixE$G=x?$Hzc8`q!iYGDt1n}phd-BZ##r2q&t!aXLbz%vx@i-C z`|mfYf_!jG&_eXC6<*R^a7p7IyDGFw?Qh2CJU;Faofio{2DyJ3vL2r%d}v$>#0){S z%A>-XaSW{J!Z{W8A7Y0YPwqz4j?Mv^PnJ0I2@?2qwUYm1H*!`cIG=!R z=&y%ZSDG`9s|LgdZw{t|o}FkX>!hjS?`4zgsg*Q8Pk8b-vf4>KksF7+0oZ`XOl~zPLG8Uq;Q#Gkb9+u;P2j1(`9Mx^ zP4KCp9$6`9pGErCgq{jLwff@fzsj_3dJ;`~Sp}O$)j{=q^$FN1M@aX_1MDIF8!F@~ z9iH=Qf-NhT*)e}IMe)3_o?TpVqkpIHy_tblC5v=Ay(EDd?5Q8rf#r@5BCSIR!t6-g){XG}M| z>#iiX@r-z{WeECv;y%n(mJXSV+-wv+<*59P@_&w4CY0~fIj|icSpEB9 zV;hETEPTy|?_axj6n3}6_ckA*G7e4oaah&C_wUWYI6mG;cLH!FE@|;+KgZ4wXF*LCOii3 znw58#T|PhZE5$w87|+~x|dsmgR8&?RG3>HJd4I7tR_-^5=G_ax=%dsyf3=J}(t7tS7!@o4C^US@Btj zCgTc(0?*3yYE_^)@RDrC)qZe^BeIG98Vm*hD7&iQbr@ud#>9+nm1|9vI~cYHf~mzR zh}OFrYv)*h3FehPmUWea*G4FCR#^!%o|Q&d)RC=AUom$Dy251QpF4VvAfoVDGjdci zMV$dx(3JmMcxEakX9j{L#LGRcl>B%@EGYRVwkhiXDYRg^l0`i*SdHsYP(Kh+6#5^7BEJ_@5P(bY`5n zyHh0!*d-r{znd%M+)GsMEa->sj}MPhVgG+&9n_y+f*GVPfL>D}D9=$FwzZM-9M_vuSl zdS%H-uk5)*=k7?a%x<-!SKO+o$9I4`-$wI;4Uf#$OJsZ+Mn=HMG%9m`6W&`^x&h;) z7Ax^qrM$u2E^lytFaMXboWS}LXB-F`Qnjq#a}zYR+qiur?GQmZ_^PM8O}}@8kD15; zFG`4tRv!at~BsV9vD0y*5KJZiSanvmuHeTJ5h`0szeK= z`xW!NQ>y5Vb~86hnaz_xbwSKtp%QlrI|@T(WhQ#aqHf`a#wm$?xVe!{7>|>_g(49$2jfTuHb9v#a^WsznAZ|elP0^;qMPRd&V3a zS%Zpy%lH(@lDdeBJgma<{wze-Mpl4WD3B4LcS;dsy_rim;|vGPTexpyW@G^? zH9G@e%IRb|d{r1}Ki7B05?*S40`cD*;RN$ivn8;Zi^o#Ji}9o-fb1{w6X4b+w+C5t zX*rv5rXK#)8CVrq5qJ+YdC^vtyZZ14nR|Hs6y$9vu%9&LJj-RBrqKikFXdEZgq>K6 zme^QC7ohS7#i)Fj9f9$LUX>tss|WIvmlOx6Uxx}7t)HAVxr+l-nl*+iZI+LW$op#y zyl>74sN(+cb}liN4vB*8{?jD~&|9O|omI~tv&zzP?%a(RD_TY zoL{pc(>pUEfAtwMexj5cUj*t|P`@v{PhNoQ-MIcF+$2-#kmCg&GffhMeLtH@LQ_P! z)bGNn3sO2z40m86GKFYFOO`FH*@6COONglBmE8FNi#V3fFKwg*fpnwP!3uvfe{a_Rxu*!aN6Glr38!u_9P zj@=C2KsH}HQ)zK+z-QT1hWx3BQT9-HS=rN?mYjuEq1I-}!u%?58>=1ejJ+z?US61p z3@Bu7$ujWilqP2833Ey$;h-AvMOBe>kuZ@r`=^Cq&fRIyDr_Ed`4 zZ`MVGi5any8ZW%kZ~%8ZAhHegysB92Gwu}d()1`IVTrn^4KeC;k!#O9J>+%K=o&gP zAu^pLh@+xyw)6nydc^&Lyeu>(BJDCwDRI>+kMP_n&|r*M_axM_-Nn6#ol8tOJ53)X z?zD(IoK&9}No*STOHWwmI}N;K1$srsV)fE9dj|LXIr8P~--pT2V){J4@Mi@E3g zUXt8&x#!P_U*nB2u4fSAn%)`cDMW9LQ+m&<^j7%JUGb~XynDbo#={404{B6Pzd||f zrypB*7B*msO{>Cf#K_;2$;Wg>s{&~Uh*Q&$dO+3ScDV!E9f&UbY$&|g%r=k+El2(9 z1aOBlmmSDkq9IX!9`Yuqif1#~wpH*9o!i0A8EQ#wS~Dr0cm@6Ql6?ClODqIA z#nj;p(o-`nfkg?GC^1zexy@_Nz}5#5a9qxCDkP<7rYrc3e8;#{F)bQ_<%KKk4xZHg z6>oIOj1wH8z1)14l$ zo-*#eQYVm`Tv`IbQYOGCBAR1 z5$>~g+Dp${B3#OFKYf(8FI9ZgHe`jSwqqLVPi();e>;Zcm?D|+E3Gjq)c!Tr)OD3M zWpw@;tMB^PdLQayrldyGL{pOpt2%>Ev>rsgWwiG_Ec(&P6=C#7+Bnh=cXnN?i~=d|o8PngBEcAPt$ z?Hh-6#v|qh)$h8(4O;Il$V9LtfkZU=Jlc7|2JxYbxwk6J&&EXeXThh0?> zj_DAs$hR`?2ls_u}w!9e&TO+;1CHW+?sB1z%~^wC4{?9-wA zVo86R_Sp9L()@)|4&kQcS9{~D(dw%Fo|q+^6Ef_R@*DW%P z`$2qT{@r;0uKaANIzJwBxDvt!-UVszp8U~LP5xhCrBLIXi@XuRMXq=bv4*)Rsacjl zde~FVxYxvKnN`}>Q=}y()0*^I=72stQL8z1^CJDYyYg+4VVottUfXl3w&m~g+`>hR z4Ao}D(O|Mj*b*3}b)ISk?{dIm(-nXmkDRLxw<}CJxtkD$&xgXzkPw%)slm;5@J_Vg z<`}z&c$TB3#Wma%PxTMuKh(CN{4=sOoET2YDz7qwzKL4qlqJBT?*3DjTG%D;aR+}8 zw}vV8qmajTRhW80-G)7Yk$koQ{Po>IJQYo^o)xDYP~D_z)F^B026(-Tx=|nL6kat0 z=lN;M?6(vt&nPoxf<$MrPMO8s?a(;TS)BL0#O|4aegBP18&@#15nnW~C#Ij2pztb+ zjMF*9wtL<5H&(2)xr30Ll>JLBsxZ5ELS}wdnKud8y`11PMffC+V2aJa6q93S$K{@L zmlOO?gj9h9KjY#9djFPy(Y<98S_9mexSH2x1(zc#AH|uHia$6wIcwivyxwT0H(%%L?n zpVqMz>AvPoeW(}dkB9K&yxzmvWSgSp8BN+Wno~*c<0}!Z*3EP;=x?smK<7o@C?ZMj z&Xw2)x=;1@9-;4EsRP&pp5xGe8l~*&Bekx@4As5_*7T0llX6%owYzkH#zR#>)=|Sl zlH!eww@0QY@^Vh^>yg#~6RqmyC$(%ef`c!_#~*#Qok18s*~c z6+5Y3qqs+Ay!5GW5F>)dD(Xg`B*B_gQ_t*R8%&LpYcBU#2K6o&z1Q56neLk!E0{1f zb~y9y8br&Ov`R|B>h@01fscBSb8)HX=2*(OJ8Re}1^yZ2TeF#{A_F~#dtqWCB8{Id$mJyi?%3ue#S3+Cs7I`P7o z&x3hW4sz|WukZZvTE@MD)3mE%Eq4~KrPlQX>$*5V`E40WrR9H&)3Z9NNYtoKhuOcvk%u20pzs?hcDg4pe6} z%tN~mKYB=qKEJE)g>o&`Id!k@dw!wXo)~-H|9pix@I3O z8jn-MvRGdDa!+eNMUGcqF3m)QqMr84dDvHPin(ikQ$DkVu8s@lCn^jF=`*ijhm3a^ zK&!i^z{AHTmN1jmk7OsD_0$@0CT4d*Hv6^iK%|_$CE~3=bj)(ke5C#d zOZfapwl0Ky>46j9`G@^2t2_Y%w5^CBh$wJFJ@?~1bGs+pvUXkIXNaK* zn;8861R^4Sk6(66PhgG@^;{Z!R%TqD5_Q8ct^Xw(#Jd8+6cXvt_!Sz#TMxWt);*uT z#Zy~St3P0f7!I-x$VCWB^GR5tR6x0;<7e@g*4~cXQ^jix;xtf$mQ7Pf+%*$MdLyT1 zA#lo?xZTA*OV57^2S|g}WjMIlOiNp)l;j*#0eP*E*@Mfr`RzszIa7w~=(Z(xcxjxu z0oQHYw78lf&#wMy;I%+MT7D4`q;-f?3QC{VKX+oYyVel#)J*aiW22ocBwoWovIBj) zlZlj;Q~mK*1MI=GTW4V=xgHVCx&x_?Txn=Em^juOdCr4;$TU{kC4FBQ*YzB|Li|ZQC{7fjYXJPbW1%YJM)4xiygrMC@lKYjzo2 z#%CQsgKqD$qi2nK5R9z$Dd4PXtP6c?VR7+~Rqk&COi6K2Ep80%K-|cME-%jNM)$^$ zq2#3yaeo_nNJbv*U(~jgRQCpIWgha(jo4$C;v?Xi;Hs^un8LMqr>un?U47#W<~3)CD6gnGeAzK@t~-@l?s_!yTBEIZAka_OaCb849i_p zAzNmJDVjv!*MCsa%2S$ph6+JLGPP%LpIaGevFHjuI-^bfC_&+t(~9XXPi3^c5t=`f z$KmQz(A*_g>e5dI*Fh(Q)7G%{1~lnCO9zNM6dLPlu8ZJZTq|}T`Vo5#+Ly-I6V6)v zUPl^;(HDUq4|Ynlz7$pjub%|YUDqc7hCntg6%y7skGK46>8o0#c` zst%kPNNa90x2DZVm{}RcPhsD$q`DH4QOrhewW!5B z#CKbk$wc~l@&=gtL)>^tC9;jX1?}Uj1pRx6mKtqpxrw)#mhg2J10s9tB6gE1T-Oq9 z(TXR{h&^w$nAQp6wiDLWj7qa5qoKv7w(@FGyF-06G`IaEwVNrBG);78NCq~W-A40j z04*+7HDSjO>yJ0I{Lm6@IbhXHe!D4 zg{=Yh5L&W2#>`?x_3VROPwTAU37orVPNPXSDO)Q7m3QyaKCb&U zVgbfd9G82x_OjyARb_z(0_woqkWVVtTCg)2rR8D99r0BJwgo8K`)9-{p}%1lnB+Li zKwiENn4vDB+uh=KkuedgFUpOH9rC+?q-vGjf2@ky-aI_`oPTT-`oerxI)JP6fWFa2 zWgnCfm$iF!`v46<>oEf(`qhBOZUh!W%XnhsEm_)EF}BGNI4_$IG7$?9=ps_0Anl*_ zhKQ=ZGVyL{rs~%V(u^6rlRRGGC8Kxkg#vA-f3U~XyR%}aA2Qw`{qFDC2Bg)CXf1<1 zulDb#XuvPe4ALl66c6t2`8j^2zuk>IzYqWvl(-+UxoDR8>A1hQpIUGA_v{|v5rJ$D z5dDnE=t+sEHoyCn-Rg)#WX2|7KYAdp@vt3ath&U3dyRJNVz}4e^T$i~{3LI!S+qp= zn%DThF+1{;JA7`@y4x4>Ya72cpY}QU!Jdcu8Fyd-b3=kw%;t&P5KH*6Vg8fr^>&VH*0)Cin*@KtJ?4@UY)O8}TAOG)iCMP6u)o zBgzgaOfPme98{=gOa6{;dJo>{GE-O;SWKF6Clj%tlSF3)Q=9~SKptrWErmcyD#HUk zFAZpLc1RIdr!d7S5i&uJQB89`kgZcHz0onw9gcmRyF((r*6^l~@eXWeM!q|p*> z`Omq;Vz=+ZiZ*2pQ;ODt=Q6ojgw{Pa6@4mgj}y=DVi{DfjXfUM?$+%guHVDPhR)7A zaAHKP=y-zi>%(yqzDqma7>P18(8CWTiL@lzc9Zx^ds1Tx?0U*B(K$KLGkJixTCf5P zgD+Mj)hF*r+MT>-r;rT0rBRVA^a}9=mHr^E16UQmy6hsOl+yZp=FobjXU;t}Ke_1v z_{$mz?Kip(?8+~@&ZUXzyR{MBP79^%?268$Nu*<0XT*OAy}tsSRUOgnr1OllogSvX z+h0sDqEl{zze9rffSe*GHZ8Z`jjUY5PmuBD@M^3n@9%kbh_2p&9_MAf zNPA#ZgtlX_=NElytnEX6ln>B513f91M~U9aw`OKmCq!;u(v@TliP5Apq{iAl#G5T+LSOZnn zuiu>#b(5U}eTt67FipjM8qjompOLU5G`%zEoia+ysb(hA_nQ$np4Os|rYIUv;(~W2 zM%OlQr4{`>A%(Jg!&rnBJ206qZ)DeE#1%{)-UZZb057s(4+6aQsY3+-GgpKGcB%8i0Z|AGHGwjkI`TI zd;Zj~l!5a4d&Z#VeAt^@Df92x4;ksa&he27IW)j;5CPm%?Gl-3*@3Zi*2KClWCbo< zpzDjSL!_DT5u7~6)5W}Q#DgZxRBH`WWUbx~ zEB-HK;(8LTd+rk5b!ZDGg1(nP!#3$nIT0su5<44rL>YKd9*K`u{yrRU#92hW$FSQF zWt=C?(6>d|##S@M(**V~3HBCG-Z6Tca1OC$03!Rx9{Ee$AE=mDaof zy?&}xh>B=yR}ZM74ACmrANH%7QtIhlM}G>Ez^KLLHnlX|D>n|P>KP~ft))LzRM*pf zIo}D5t@38+fCKj!#Dv%!hX)rddXi!~(WZiKCpHFJ&2&yH8AN6ZQ*4MBp#w2SQboo= zJa@*7I5cFt&Awj(o3UBdp6ZTFx7lhC$C_{z-{Nr3F57GHCm!?yVXW{p6M*Kh|%3v;x3WZqI%cgtk6T{i00JDSF&Mu zg6Ng$2qo^FCaa^Xf%xK?sI4j`qAC`_ahKw>{{AHg+V-HV_Uw`j(ahrEk-T7THE)Nd z-QQ6o@yu?gl+5f%5KZ8sG>WOZNuyAE*Cq5Yq3xT9_K}VkE;>d1o=@N_2o1i{4~Vmk zC>>%KEk`501PR%qjLwWph06DoOOJM?DEzGxI~yYT;%rN~-PVhAPE&u0;Th5bE(sm( z1WiXFCMoTyX3R3k+L$*#LRKJxOkRbMgNv(7h0)9gV)9ZOQ0NzxXCLiPcpQ=CL<6Xz zsP)e;B{U`0s};&){Y50Dewf;ekQ9uOV`1-P4aNZSqVmMiej}pE(>gxxGm4IAI-dlt zhs+L`Ni!zoN_3}SIudsmPBw^?LvBJVU=`e!g=Dc=ybHF-TFf>(<`waL(E;gJ={vq3 zv;a5VfgOWwM@B^5C#PmiXp0#{133H)tkU6idxu2V=`D~{Zq1}6s5@p%_*`O8*Kyo4 zMKi1Q;%Cs>-2mz8%Is?HOAuA{FHvhy+)GeKqNy*TUP}zSejz6`(Yv%gzv{zC)f*7U zhW_z)$R$LswCgXI zhTD~ccI|0r(5~o5v?X46OMKUr1ISNn)V zvAad=e*)dnY#_3*%$|~m*w9}}OtcUuys1D|{vKnZo-nnUVI#Jh*`6KZAFtWQ^#d{gUZ#j)^e|r1##q6k6LIXv4dmG4%Zr7Wg7@tAfV@y+9bs*3x+B1n4)dud%QC z>Ish&=%kHn*M{4|4T_YMAIO5H2ib2(hI_Z5qiBO8v1)r+NI;fRZ&M5XzH<6aGKrSD z7V6<&X$}hd|K2V<$o;LIOtc|Z_(3iWG2f>nYspa0!$VHuu43vH{!~ag)Gzv+Kt^e{ zBxbiKOC;yb%#@Yz3!u4ORD?yS{>|t)n>xj7O=4ntuZ^`PGcmQ-#zgVWdPQ(4RU6~2 zB;+Fp^dmZ#idw7@t1nSv#$rBj8a$-}*FEoZ5Mv7T?*-Z6h|4q!9E1FWZlD`wK~<3E#xPc8kTl>4iO^^> zXLHa`ld5v7s=}{Z*vP@~Yp@|8XPLsGo`fNmyl%-TqWjKnfjHBNx;`{Ft2JZFTjVoK z#^hIE5!Y-{?P7M~^ei$>O05nt!z z(^_#Qd}?grER$VApNvZntM(R#)xa^T__3x0%W+GxT5KudRe{`w?6E%?YMT zv!+Q~pKVfmU*x(@Yn%KiMO~yWW+MA!Xe&xsd=pq6_Z-G5#Tg4L+M}0T^2S2!?lQvZYaamxQ`#bpAtKU|iP&K{h+dcR1r#V>FL*pf~sDn_f z2RJN^++K9qOB7yRSc!N#jU@F(ruaQseM0^A?z#P^|0)}*R8`)?qBSwrfOB|8;REJ6 zvwD_#2J8mHyMRwJZv5X$HE2(8-?UzmE4f}EU5U!xKyxh8ta=?oTDu-QI$dwSA7tDD zX0TExa-je>ZFA$WnFWM{i3G7;hk6bTP68Imh`CkA0vVHE!rEjbo~n##BIyUBuEO~w zquBAj`cF*5ftHlRV5%kn>C<{J}0P)U&Bmco2+Cz zr)gEsq!zhJk~a8;tbTt-ORy|4Bh9qfGAg64g~oKl^T$4wnH&BF|As8Ax(uSr)V`HFu!Z;}`P<Fi+auEXUQXc&Is*z)y z=7L1bi1C_ODxUZ|&X*40!qA__278|Dn~YNywZEM}4sqX{EW{WM_MGoi+dqf5QW4Il zf4xk-mS~*#^BC91;E6;zGIssQUT)UudiU14HslSPEU9u5s@&m9D+{Ymw((Z}v*cSX zjJO`?hRu8so&i~8iKgh(a9J<)Y3&I>V@m=)AjJFYU~hswj?M@+>Z}^*dEs(%T}Fk~ zSF7x4te6}8-kb|JKW6V2)~B%A_o6&zZxK!a4&WBQp?)O}(bf#)e6J-J*3tROOxuiE z7mqosDD~dHKVnb3AN@6K2ds%~tE0BS*x^sXD#(+Btd)a3cl1pUOb^037__lbW_o&n z+RXag_XYnaTVUazY=Ji@w!pvr7hB+`;tbAri@8<*gDvpQ^M`=-Qd{8c|Aj5^=zp;V zUIbfUvjiKXDKGwueeZ|=FYSB1Blf+RlaMF>oqcbfV&4m02!5X><^GTMy|-Vr?|mAm zSS9!W%)U2OvE7A?a_O3Vud%UGOFo(;GqC-bFk<7Y8+q>DK^jw<+V@^>*E?e+bfwS@ z`62&Z$w3pTb3oo&wXS*7hbLCJy(Vflw&01(pcs*SR4fKtgf2Av5i-3k4h_T9a?FmvtZh-GZYzPnE%P z-EATj5r5<%r|#f_$eV7aehg7R(^64ReCA5>`x{@ZSWmc{N?@ZvVmEgV^!#~1?<%SJ zW#&3f zKd&LhHNRnlE2_j(P!;>*Av}3ce6{Cv%;5T3uJ%laP1^?C+ZdmDy2|qbPHOYvwR?}} zE2+kFM%w6k8?h+8aoSVKmIkBdf$qP#?%FdPFml1XP8Pff?zInhc*ocqX3i0!x&pav960iIXD;9ZP z<1tvoo4^VDQA?I)hb{a^*cDrARkAg}$QoeW|8AUHq$uXZl^H?j17wH}2B(>4|Lya8 zrOiMywAa!5Q18=n68Hj%eb{xi74RV!W%z$%1>dEt;5+4t#5&EKLERCt?Hv;i@h;n=+nT(v*CecgrE1SDqBtK3gQ`q zXe!0A1n}O)+(qOqg-7H>Ppr9$f#)*gxO`-wN9fnPJYieSQ8QKt_f?GM)MTcnY4-#M<^G^FwcO^N$6cP0s>6&;`N`Y-+x=$NBhv&}) z_JdL)l~hAl>A#WD>qisa0rv^_@9*_P`mR#J6XhOU{nkYs&Edsl znO#*6{&Hp|^2n+pE8RoI*xg7bWL&V2ajvipmQz@vB8e1-bWEUD9{K0I{N&r@caM|2sFdq1nuyQMrO6;nMDCul|#$DG5o_!req`T zCycZWs7@nMW;Bs%<75{zO*QEqrDP^%0AEaTl5wGMpz64FzW=zHbU)Qg_Q3X)`apY1 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 literal 0 HcmV?d00001 diff --git a/internal/lzss/testdata/cloud.lzss b/internal/lzss/testdata/cloud.lzss new file mode 100644 index 0000000000000000000000000000000000000000..92d549eb222f7c99f94ea451e53221ffeafa94e2 GIT binary patch literal 74957 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 CuqrzM literal 0 HcmV?d00001 diff --git a/internal/lzss/testdata/repetitive.lzss b/internal/lzss/testdata/repetitive.lzss new file mode 100644 index 0000000000000000000000000000000000000000..3fb316f718829e2e11d41cddaaa4a1441944a7e9 GIT binary patch literal 3728 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 literal 0 HcmV?d00001 diff --git a/internal/lzss/testdata/repetitive.txt b/internal/lzss/testdata/repetitive.txt new file mode 100644 index 00000000..df7d4854 --- /dev/null +++ b/internal/lzss/testdata/repetitive.txt @@ -0,0 +1,52 @@ +This thext is highly repetitive - this is useful to test +the compression of the algorithm - repetitive +Each line - repetitive +contains - repetitive +at least one repetitive statement -repetitive +repetitive - repetita iuvant - repetitive +repetitive - repetita iuvant - repetitive +repetitive - repetita iuvant - repetitive +repetitive - repetita iuvant - repetitive +repetitive - repetita iuvant - repetitive +repetitive - repetita iuvant - repetitive +repetitive - repetita iuvant - repetitive +repetitive - repetita iuvant - repetitive +This short thext is highly repetitive - this is useful to test +the compression of the algorithm - repetitive +Each line - repetitive +contains - repetitive +at least one repetitive statement -repetitive +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse ligula dui, imperdiet ut vulputate semper, sollicitudin ut eros. Aliquam erat volutpat. In hac habitasse platea dictumst. Nam non tortor sit amet mauris rutrum eleifend. Pellentesque vel justo nibh. Vivamus sem risus, pharetra eget egestas eget, venenatis a ipsum. Cras ultrices aliquam sagittis. Donec lacinia urna ac orci congue ut adipiscing dolor fringilla. Nullam nibh magna, bibendum vulputate ornare id, hendrerit et metus. Nullam dapibus neque quis mi laoreet molestie. Mauris et dui lacus, sit amet egestas purus. +Donec accumsan elementum accumsan. Nullam gravida dictum diam non semper. Curabitur vel magna in velit accumsan pulvinar eget in lorem. Duis vitae ante velit, at hendrerit nibh. Pellentesque lacus urna, cursus ac semper sagittis, viverra at sem. Quisque ullamcorper odio dolor. In quis pretium lacus. Maecenas lacinia urna id massa congue blandit. Suspendisse dapibus eros sit amet neque fermentum imperdiet. Cras interdum pulvinar eleifend. Suspendisse molestie neque a risus imperdiet convallis. In interdum dignissim pharetra. Morbi lectus tortor, pulvinar quis eleifend in, placerat at risus. Sed aliquam diam at metus adipiscing blandit. +Integer tristique metus vel ipsum pulvinar dignissim quis vel quam. Donec auctor aliquet bibendum. Morbi aliquet malesuada ultrices. Vivamus ac leo odio. Nam tristique eros non arcu porttitor non volutpat mauris tempus. Proin vestibulum suscipit pretium. Etiam elit tortor, dictum a gravida porta, congue id dolor. Duis eget est vitae elit facilisis blandit. Proin tincidunt felis et ipsum pharetra tempor. Fusce imperdiet vulputate magna, vel lacinia neque volutpat a. Vivamus a elit dolor. Aliquam sollicitudin dui et leo elementum mattis. Quisque suscipit, lorem id eleifend imperdiet, ipsum lorem pharetra purus, vel tempus lectus ligula id tortor. Morbi eget eros vel sapien scelerisque aliquam pellentesque sed turpis. Duis vel lorem non eros semper fringilla vitae vitae erat. +Vivamus porttitor pulvinar tristique. Proin sed elit ipsum. Phasellus faucibus pulvinar dapibus. Praesent quis sem in purus ultrices imperdiet. Aenean ut nulla urna. In tristique tincidunt urna, nec adipiscing velit laoreet ut. Curabitur et ante sed libero tristique pellentesque. Quisque porttitor sodales ipsum ut rhoncus. Nunc vitae diam gravida orci aliquam cursus vitae ut sapien. Proin ullamcorper felis eu nulla dapibus nec faucibus odio hendrerit. Aenean lorem magna, fermentum in tristique sit amet, accumsan ut massa. Fusce tristique, lectus rhoncus commodo sagittis, ligula felis consequat arcu, id pretium enim dolor id mi. Donec facilisis pulvinar luctus. Pellentesque vitae condimentum risus. Nam quis elit a orci adipiscing bibendum. +Ut quis felis lorem, dignissim varius turpis. Sed convallis dui semper mauris fermentum porta. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aliquam erat volutpat. Proin lorem felis, scelerisque nec commodo non, porta eu metus. Nulla id augue a turpis mollis pellentesque. Aenean in lectus et leo tincidunt auctor eu interdum est. Nulla varius, lorem congue laoreet laoreet, felis quam ullamcorper ligula, non pellentesque dui ipsum quis odio. Etiam sit amet blandit leo. Aenean venenatis molestie eros, in fermentum ipsum dictum eget. Donec ultricies feugiat nisl, non molestie mi congue quis. Quisque mattis augue nec neque fringilla varius. Proin sollicitudin risus et elit pretium congue. Sed consequat eros sit amet felis pulvinar pulvinar. Morbi in turpis eu nulla cursus venenatis at ut urna. Donec vel lectus quis nisi aliquam varius. +Each line - repetitive +contains - repetitive +at least one repetitive statement -repetitive +This short thext is highly repetitive - this is useful to test +the compression of the algorithm - repetitive +Each line - repetitive +contains - repetitive +at least one repetitive statement -repetitive +repetitive - repetita iuvant - repetitive +repetitive - repetita iuvant - repetitive +repetitive - repetita iuvant - repetitive +repetitive - repetita iuvant - repetitive +repetitive - repetita iuvant - repetitive +repetitive - repetita iuvant - repetitive +repetitive - repetita iuvant - repetitive +repetitive - repetita iuvant - repetitive +This short thext is highly repetitive - this is useful to test +the compression of the algorithm - repetitive +Each line - repetitive +contains - repetitive +at least one repetitive statement -repetitive +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse ligula dui, imperdiet ut vulputate semper, sollicitudin ut eros. Aliquam erat volutpat. In hac habitasse platea dictumst. Nam non tortor sit amet mauris rutrum eleifend. Pellentesque vel justo nibh. Vivamus sem risus, pharetra eget egestas eget, venenatis a ipsum. Cras ultrices aliquam sagittis. Donec lacinia urna ac orci congue ut adipiscing dolor fringilla. Nullam nibh magna, bibendum vulputate ornare id, hendrerit et metus. Nullam dapibus neque quis mi laoreet molestie. Mauris et dui lacus, sit amet egestas purus. +Donec accumsan elementum accumsan. Nullam gravida dictum diam non semper. Curabitur vel magna in velit accumsan pulvinar eget in lorem. Duis vitae ante velit, at hendrerit nibh. Pellentesque lacus urna, cursus ac semper sagittis, viverra at sem. Quisque ullamcorper odio dolor. In quis pretium lacus. Maecenas lacinia urna id massa congue blandit. Suspendisse dapibus eros sit amet neque fermentum imperdiet. Cras interdum pulvinar eleifend. Suspendisse molestie neque a risus imperdiet convallis. In interdum dignissim pharetra. Morbi lectus tortor, pulvinar quis eleifend in, placerat at risus. Sed aliquam diam at metus adipiscing blandit. +Integer tristique metus vel ipsum pulvinar dignissim quis vel quam. Donec auctor aliquet bibendum. Morbi aliquet malesuada ultrices. Vivamus ac leo odio. Nam tristique eros non arcu porttitor non volutpat mauris tempus. Proin vestibulum suscipit pretium. Etiam elit tortor, dictum a gravida porta, congue id dolor. Duis eget est vitae elit facilisis blandit. Proin tincidunt felis et ipsum pharetra tempor. Fusce imperdiet vulputate magna, vel lacinia neque volutpat a. Vivamus a elit dolor. Aliquam sollicitudin dui et leo elementum mattis. Quisque suscipit, lorem id eleifend imperdiet, ipsum lorem pharetra purus, vel tempus lectus ligula id tortor. Morbi eget eros vel sapien scelerisque aliquam pellentesque sed turpis. Duis vel lorem non eros semper fringilla vitae vitae erat. +Vivamus porttitor pulvinar tristique. Proin sed elit ipsum. Phasellus faucibus pulvinar dapibus. Praesent quis sem in purus ultrices imperdiet. Aenean ut nulla urna. In tristique tincidunt urna, nec adipiscing velit laoreet ut. Curabitur et ante sed libero tristique pellentesque. Quisque porttitor sodales ipsum ut rhoncus. Nunc vitae diam gravida orci aliquam cursus vitae ut sapien. Proin ullamcorper felis eu nulla dapibus nec faucibus odio hendrerit. Aenean lorem magna, fermentum in tristique sit amet, accumsan ut massa. Fusce tristique, lectus rhoncus commodo sagittis, ligula felis consequat arcu, id pretium enim dolor id mi. Donec facilisis pulvinar luctus. Pellentesque vitae condimentum risus. Nam quis elit a orci adipiscing bibendum. +Ut quis felis lorem, dignissim varius turpis. Sed convallis dui semper mauris fermentum porta. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aliquam erat volutpat. Proin lorem felis, scelerisque nec commodo non, porta eu metus. Nulla id augue a turpis mollis pellentesque. Aenean in lectus et leo tincidunt auctor eu interdum est. Nulla varius, lorem congue laoreet laoreet, felis quam ullamcorper ligula, non pellentesque dui ipsum quis odio. Etiam sit amet blandit leo. Aenean venenatis molestie eros, in fermentum ipsum dictum eget. Donec ultricies feugiat nisl, non molestie mi congue quis. Quisque mattis augue nec neque fringilla varius. Proin sollicitudin risus et elit pretium congue. Sed consequat eros sit amet felis pulvinar pulvinar. Morbi in turpis eu nulla cursus venenatis at ut urna. Donec vel lectus quis nisi aliquam varius. +Each line - repetitive +contains - repetitive +at least one repetitive statement -repetitive \ No newline at end of file From 909c6421a351fd75b578235f556dde23b850f6c3 Mon Sep 17 00:00:00 2001 From: Paolo Calao Date: Wed, 5 Jan 2022 17:56:12 +0100 Subject: [PATCH 06/11] Update encoder --- internal/ota/encoder.go | 72 +++++------------------------------------ 1 file changed, 8 insertions(+), 64 deletions(-) diff --git a/internal/ota/encoder.go b/internal/ota/encoder.go index 7f28e3f6..a9ab891e 100644 --- a/internal/ota/encoder.go +++ b/internal/ota/encoder.go @@ -22,9 +22,6 @@ import ( "encoding/binary" "hash/crc32" "io" - "io/ioutil" - "log" - "os" "strconv" "github.com/arduino/arduino-cloud-cli/internal/lzss" @@ -86,10 +83,7 @@ func (e *encoder) Write(binaryData []byte) (int, error) { } // Compress the compiled binary - compressed, err := e.compress(&binaryData) - if err != nil { - return 0, err - } + compressed := lzss.Encode(binaryData) // Prepend magic number and version field to payload var binDataComplete []byte @@ -98,12 +92,12 @@ func (e *encoder) Write(binaryData []byte) (int, error) { binDataComplete = append(binDataComplete, compressed...) //log.Println("binDataComplete is", len(binDataComplete), "bytes length") - headerSize, err := e.writeHeader(&binDataComplete) + headerSize, err := e.writeHeader(binDataComplete) if err != nil { return headerSize, err } - payloadSize, err := e.writePayload(&binDataComplete) + payloadSize, err := e.writePayload(binDataComplete) if err != nil { return payloadSize, err } @@ -117,23 +111,19 @@ func (e *encoder) Close() error { return e.w.Flush() } -func (e *encoder) writeHeader(binDataComplete *[]byte) (int, error) { +func (e *encoder) writeHeader(binDataComplete []byte) (int, error) { - // // Write the length of the content - // lengthAsBytes := make([]byte, 4) - binary.LittleEndian.PutUint32(lengthAsBytes, uint32(len(*binDataComplete))) + binary.LittleEndian.PutUint32(lengthAsBytes, uint32(len(binDataComplete))) n, err := e.w.Write(lengthAsBytes) if err != nil { return n, err } - // // Calculate the checksum for binDataComplete - // - crc := crc32.ChecksumIEEE(*binDataComplete) + crc := crc32.ChecksumIEEE(binDataComplete) // encode the checksum uint32 value as 4 bytes crcAsBytes := make([]byte, 4) @@ -147,52 +137,6 @@ func (e *encoder) writeHeader(binDataComplete *[]byte) (int, error) { return len(lengthAsBytes) + len(crcAsBytes), nil } -func (e *encoder) writePayload(data *[]byte) (int, error) { - - // write the payload - payloadSize, err := e.w.Write(*data) - if err != nil { - return payloadSize, err - } - - return payloadSize, nil -} - -func (e *encoder) compress(data *[]byte) ([]byte, error) { - - // create a tmp file for input - inputFile, err := ioutil.TempFile("", "ota-lzss-input") - if err != nil { - log.Fatal(err) - return nil, err - } - defer os.Remove(inputFile.Name()) - - // create a tmp file for output - outputFile, err := ioutil.TempFile("", "ota-lzss-output") - if err != nil { - log.Fatal(err) - return nil, err - } - defer os.Remove(outputFile.Name()) - - // write data in the input file - ioutil.WriteFile(inputFile.Name(), *data, 644) - if err != nil { - log.Fatal(err) - return nil, err - } - - // Compress the binary data using LZSS - lzss.Encode(inputFile.Name(), outputFile.Name()) - - // reads compressed data from output file and write it into - // the writer - compressed, err := ioutil.ReadFile(outputFile.Name()) - if err != nil { - log.Fatal(err) - return nil, err - } - - return compressed, nil +func (e *encoder) writePayload(data []byte) (int, error) { + return e.w.Write(data) } From a43abb86512d88c4bd3fbf1671cc15237cdaabd8 Mon Sep 17 00:00:00 2001 From: Paolo Calao Date: Wed, 5 Jan 2022 18:36:05 +0100 Subject: [PATCH 07/11] Remove testdata format --- internal/lzss/lzss_test.go | 6 +++--- internal/lzss/testdata/{lorem.txt => lorem} | 0 internal/lzss/testdata/{repetitive.txt => repetitive} | 0 internal/lzss/testdata/{short.txt => short} | 0 4 files changed, 3 insertions(+), 3 deletions(-) rename internal/lzss/testdata/{lorem.txt => lorem} (100%) rename internal/lzss/testdata/{repetitive.txt => repetitive} (100%) rename internal/lzss/testdata/{short.txt => short} (100%) diff --git a/internal/lzss/lzss_test.go b/internal/lzss/lzss_test.go index c575b23e..8bb5dffd 100644 --- a/internal/lzss/lzss_test.go +++ b/internal/lzss/lzss_test.go @@ -14,12 +14,12 @@ func TestEncode(t *testing.T) { }{ { name: "lorem", - infile: "testdata/lorem.txt", + infile: "testdata/lorem", outfile: "testdata/lorem.lzss", }, { name: "short", - infile: "testdata/short.txt", + infile: "testdata/short", outfile: "testdata/short.lzss", }, { @@ -29,7 +29,7 @@ func TestEncode(t *testing.T) { }, { name: "repetitive", - infile: "testdata/repetitive.txt", + infile: "testdata/repetitive", outfile: "testdata/repetitive.lzss", }, { diff --git a/internal/lzss/testdata/lorem.txt b/internal/lzss/testdata/lorem similarity index 100% rename from internal/lzss/testdata/lorem.txt rename to internal/lzss/testdata/lorem diff --git a/internal/lzss/testdata/repetitive.txt b/internal/lzss/testdata/repetitive similarity index 100% rename from internal/lzss/testdata/repetitive.txt rename to internal/lzss/testdata/repetitive diff --git a/internal/lzss/testdata/short.txt b/internal/lzss/testdata/short similarity index 100% rename from internal/lzss/testdata/short.txt rename to internal/lzss/testdata/short From 03525f89c68605c2297aeab7910c4b693145f0fd Mon Sep 17 00:00:00 2001 From: Paolo Calao Date: Wed, 5 Jan 2022 18:56:47 +0100 Subject: [PATCH 08/11] Remove text testdata --- internal/lzss/lzss_test.go | 15 ------- internal/lzss/testdata/lorem | 9 ----- internal/lzss/testdata/lorem.lzss | Bin 1745 -> 0 bytes internal/lzss/testdata/repetitive | 52 ------------------------- internal/lzss/testdata/repetitive.lzss | Bin 3728 -> 0 bytes internal/lzss/testdata/short | 1 - internal/lzss/testdata/short.lzss | Bin 63 -> 0 bytes 7 files changed, 77 deletions(-) delete mode 100644 internal/lzss/testdata/lorem delete mode 100644 internal/lzss/testdata/lorem.lzss delete mode 100644 internal/lzss/testdata/repetitive delete mode 100644 internal/lzss/testdata/repetitive.lzss delete mode 100644 internal/lzss/testdata/short delete mode 100644 internal/lzss/testdata/short.lzss diff --git a/internal/lzss/lzss_test.go b/internal/lzss/lzss_test.go index 8bb5dffd..4a3996e7 100644 --- a/internal/lzss/lzss_test.go +++ b/internal/lzss/lzss_test.go @@ -12,26 +12,11 @@ func TestEncode(t *testing.T) { infile string outfile string }{ - { - name: "lorem", - infile: "testdata/lorem", - outfile: "testdata/lorem.lzss", - }, - { - name: "short", - infile: "testdata/short", - outfile: "testdata/short.lzss", - }, { name: "blink", infile: "testdata/blink.bin", outfile: "testdata/blink.lzss", }, - { - name: "repetitive", - infile: "testdata/repetitive", - outfile: "testdata/repetitive.lzss", - }, { name: "cloud sketch", infile: "testdata/cloud.bin", diff --git a/internal/lzss/testdata/lorem b/internal/lzss/testdata/lorem deleted file mode 100644 index c942efc7..00000000 --- a/internal/lzss/testdata/lorem +++ /dev/null @@ -1,9 +0,0 @@ -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse ligula dui, imperdiet ut vulputate semper, sollicitudin ut eros. Aliquam erat volutpat. In hac habitasse platea dictumst. Nam non tortor sit amet mauris rutrum eleifend. Pellentesque vel justo nibh. Vivamus sem risus, pharetra eget egestas eget, venenatis a ipsum. Cras ultrices aliquam sagittis. Donec lacinia urna ac orci congue ut adipiscing dolor fringilla. Nullam nibh magna, bibendum vulputate ornare id, hendrerit et metus. Nullam dapibus neque quis mi laoreet molestie. Mauris et dui lacus, sit amet egestas purus. - -Donec accumsan elementum accumsan. Nullam gravida dictum diam non semper. Curabitur vel magna in velit accumsan pulvinar eget in lorem. Duis vitae ante velit, at hendrerit nibh. Pellentesque lacus urna, cursus ac semper sagittis, viverra at sem. Quisque ullamcorper odio dolor. In quis pretium lacus. Maecenas lacinia urna id massa congue blandit. Suspendisse dapibus eros sit amet neque fermentum imperdiet. Cras interdum pulvinar eleifend. Suspendisse molestie neque a risus imperdiet convallis. In interdum dignissim pharetra. Morbi lectus tortor, pulvinar quis eleifend in, placerat at risus. Sed aliquam diam at metus adipiscing blandit. - -Integer tristique metus vel ipsum pulvinar dignissim quis vel quam. Donec auctor aliquet bibendum. Morbi aliquet malesuada ultrices. Vivamus ac leo odio. Nam tristique eros non arcu porttitor non volutpat mauris tempus. Proin vestibulum suscipit pretium. Etiam elit tortor, dictum a gravida porta, congue id dolor. Duis eget est vitae elit facilisis blandit. Proin tincidunt felis et ipsum pharetra tempor. Fusce imperdiet vulputate magna, vel lacinia neque volutpat a. Vivamus a elit dolor. Aliquam sollicitudin dui et leo elementum mattis. Quisque suscipit, lorem id eleifend imperdiet, ipsum lorem pharetra purus, vel tempus lectus ligula id tortor. Morbi eget eros vel sapien scelerisque aliquam pellentesque sed turpis. Duis vel lorem non eros semper fringilla vitae vitae erat. - -Vivamus porttitor pulvinar tristique. Proin sed elit ipsum. Phasellus faucibus pulvinar dapibus. Praesent quis sem in purus ultrices imperdiet. Aenean ut nulla urna. In tristique tincidunt urna, nec adipiscing velit laoreet ut. Curabitur et ante sed libero tristique pellentesque. Quisque porttitor sodales ipsum ut rhoncus. Nunc vitae diam gravida orci aliquam cursus vitae ut sapien. Proin ullamcorper felis eu nulla dapibus nec faucibus odio hendrerit. Aenean lorem magna, fermentum in tristique sit amet, accumsan ut massa. Fusce tristique, lectus rhoncus commodo sagittis, ligula felis consequat arcu, id pretium enim dolor id mi. Donec facilisis pulvinar luctus. Pellentesque vitae condimentum risus. Nam quis elit a orci adipiscing bibendum. - -Ut quis felis lorem, dignissim varius turpis. Sed convallis dui semper mauris fermentum porta. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aliquam erat volutpat. Proin lorem felis, scelerisque nec commodo non, porta eu metus. Nulla id augue a turpis mollis pellentesque. Aenean in lectus et leo tincidunt auctor eu interdum est. Nulla varius, lorem congue laoreet laoreet, felis quam ullamcorper ligula, non pellentesque dui ipsum quis odio. Etiam sit amet blandit leo. Aenean venenatis molestie eros, in fermentum ipsum dictum eget. Donec ultricies feugiat nisl, non molestie mi congue quis. Quisque mattis augue nec neque fringilla varius. Proin sollicitudin risus et elit pretium congue. Sed consequat eros sit amet felis pulvinar pulvinar. Morbi in turpis eu nulla cursus venenatis at ut urna. Donec vel lectus quis nisi aliquam varius. \ No newline at end of file diff --git a/internal/lzss/testdata/lorem.lzss b/internal/lzss/testdata/lorem.lzss deleted file mode 100644 index 07d0070c2dc5f4a6a09e9873e8f75abbbb122670..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1745 zcmV;?1}^!gTkcj{Y=YBpx!qsPESCFY_ymIIX}U-(Hrp-ISs=07?bkakj_3g4b${@% z*&oy`H#;4s-Di+lZGZ$4=><;fbGTV;z%Umu4haAeg`Vqdu)okTmdL7AR+(&599!ZAbb}$`~Wln9RL#mMGJ5wkS&G2<^;h(1|YcIKokME zK}-QK0e}IpE&%=j<`j@>3q^*;5yN5zP_Ti4Tmaw!PypmXi~*P}w=jtsa6JvU0|G&G zf8YyY00)p;Y#=BAUJ?tCLV#v~J&m%MF<9H0>DGqLlkV{+5%7k zDi$Ew5YZ4#fsg^M0TBT;3n15pplt+l0A&D1gfRpJgjR%SmdRllP_YOAiueaP51yg@i2t zH3W+QIKXYhk(hX1&L_ck9Iy%|ClLzu1#}a!BajI~0YMJ38lxPbC;%xzB7!7#BY?IO zXbv!lvJ~))c$63l*pJB-m=T~4uoY+y2$czuCfJ3gul#$2#~-_ zMAraV?3;k4#3n%CKwcKaZombi1iC#;4dg`7K1dq@awR1M2NSh7kS~BeAUv@v2n|;` z${>b2)i|IKa|8J}!4J>|5jLSUVLj(UASs|g5kb%p*EX>=ASmEBPyq2kp$lXX!9IpH zlRpMSK}JzGVF%MlfkAUWfwH6E3R@G&q*#vOj13%{5%3|9A-EOLBX9~JpirQRB}x>b zKdK`;q4Xnxrr{*v3fmBvBG3$gq{*Qmjf*0KD61SWAV8=X6L^Xf2h13dskje zc~*ERt9k(RMMg-z#N?`a1k}p(Mi56DhXy8|rI2DSi%e8mTxZlG$FKZxC#1JPm~6U9IH#gJs(gB62S zA;mC7rkP%$Ih|OYido}HsSHh)pyR**AosxgLc;)|;B{u4&~+&PB>7+hfX4!#CLm=0 z!sNy%FnQBK60s`L7xA|l@f+!(fvXfTj2J2?QKf_x3J?PWU=&3Kkd~Q%2?a4j7eRELmh4Rr}TS@poAK^F<+l_g0D-LVbqRb*6bVR_6g$*qX2 zz{7-@fIk2?5X(gB(02&7h_%F*#JIq^L{x;(1igTs1SN!bzYw0fR6}!fb&?mk-V9Elq*>jRBOokh~CUsXob+%h3ZA%EWgM? z5V4I`5pd9Q8HiZ}$o`xu!7)J1$oWla$y$(%g)#taWhKpZmDR|T*c4GVfWyf4K`KBS zMKnU#kLa3?NuY@=lY||R+emuqprp|V_Y#Mu|1Q@wQYL|fR3=93rYK$RMC$d3mCTGt nOfI-g>FhUTd?+pMC+wMSwPHJB4yd4L^TvSalZK;WCa|pP7H`TY diff --git a/internal/lzss/testdata/repetitive b/internal/lzss/testdata/repetitive deleted file mode 100644 index df7d4854..00000000 --- a/internal/lzss/testdata/repetitive +++ /dev/null @@ -1,52 +0,0 @@ -This thext is highly repetitive - this is useful to test -the compression of the algorithm - repetitive -Each line - repetitive -contains - repetitive -at least one repetitive statement -repetitive -repetitive - repetita iuvant - repetitive -repetitive - repetita iuvant - repetitive -repetitive - repetita iuvant - repetitive -repetitive - repetita iuvant - repetitive -repetitive - repetita iuvant - repetitive -repetitive - repetita iuvant - repetitive -repetitive - repetita iuvant - repetitive -repetitive - repetita iuvant - repetitive -This short thext is highly repetitive - this is useful to test -the compression of the algorithm - repetitive -Each line - repetitive -contains - repetitive -at least one repetitive statement -repetitive -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse ligula dui, imperdiet ut vulputate semper, sollicitudin ut eros. Aliquam erat volutpat. In hac habitasse platea dictumst. Nam non tortor sit amet mauris rutrum eleifend. Pellentesque vel justo nibh. Vivamus sem risus, pharetra eget egestas eget, venenatis a ipsum. Cras ultrices aliquam sagittis. Donec lacinia urna ac orci congue ut adipiscing dolor fringilla. Nullam nibh magna, bibendum vulputate ornare id, hendrerit et metus. Nullam dapibus neque quis mi laoreet molestie. Mauris et dui lacus, sit amet egestas purus. -Donec accumsan elementum accumsan. Nullam gravida dictum diam non semper. Curabitur vel magna in velit accumsan pulvinar eget in lorem. Duis vitae ante velit, at hendrerit nibh. Pellentesque lacus urna, cursus ac semper sagittis, viverra at sem. Quisque ullamcorper odio dolor. In quis pretium lacus. Maecenas lacinia urna id massa congue blandit. Suspendisse dapibus eros sit amet neque fermentum imperdiet. Cras interdum pulvinar eleifend. Suspendisse molestie neque a risus imperdiet convallis. In interdum dignissim pharetra. Morbi lectus tortor, pulvinar quis eleifend in, placerat at risus. Sed aliquam diam at metus adipiscing blandit. -Integer tristique metus vel ipsum pulvinar dignissim quis vel quam. Donec auctor aliquet bibendum. Morbi aliquet malesuada ultrices. Vivamus ac leo odio. Nam tristique eros non arcu porttitor non volutpat mauris tempus. Proin vestibulum suscipit pretium. Etiam elit tortor, dictum a gravida porta, congue id dolor. Duis eget est vitae elit facilisis blandit. Proin tincidunt felis et ipsum pharetra tempor. Fusce imperdiet vulputate magna, vel lacinia neque volutpat a. Vivamus a elit dolor. Aliquam sollicitudin dui et leo elementum mattis. Quisque suscipit, lorem id eleifend imperdiet, ipsum lorem pharetra purus, vel tempus lectus ligula id tortor. Morbi eget eros vel sapien scelerisque aliquam pellentesque sed turpis. Duis vel lorem non eros semper fringilla vitae vitae erat. -Vivamus porttitor pulvinar tristique. Proin sed elit ipsum. Phasellus faucibus pulvinar dapibus. Praesent quis sem in purus ultrices imperdiet. Aenean ut nulla urna. In tristique tincidunt urna, nec adipiscing velit laoreet ut. Curabitur et ante sed libero tristique pellentesque. Quisque porttitor sodales ipsum ut rhoncus. Nunc vitae diam gravida orci aliquam cursus vitae ut sapien. Proin ullamcorper felis eu nulla dapibus nec faucibus odio hendrerit. Aenean lorem magna, fermentum in tristique sit amet, accumsan ut massa. Fusce tristique, lectus rhoncus commodo sagittis, ligula felis consequat arcu, id pretium enim dolor id mi. Donec facilisis pulvinar luctus. Pellentesque vitae condimentum risus. Nam quis elit a orci adipiscing bibendum. -Ut quis felis lorem, dignissim varius turpis. Sed convallis dui semper mauris fermentum porta. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aliquam erat volutpat. Proin lorem felis, scelerisque nec commodo non, porta eu metus. Nulla id augue a turpis mollis pellentesque. Aenean in lectus et leo tincidunt auctor eu interdum est. Nulla varius, lorem congue laoreet laoreet, felis quam ullamcorper ligula, non pellentesque dui ipsum quis odio. Etiam sit amet blandit leo. Aenean venenatis molestie eros, in fermentum ipsum dictum eget. Donec ultricies feugiat nisl, non molestie mi congue quis. Quisque mattis augue nec neque fringilla varius. Proin sollicitudin risus et elit pretium congue. Sed consequat eros sit amet felis pulvinar pulvinar. Morbi in turpis eu nulla cursus venenatis at ut urna. Donec vel lectus quis nisi aliquam varius. -Each line - repetitive -contains - repetitive -at least one repetitive statement -repetitive -This short thext is highly repetitive - this is useful to test -the compression of the algorithm - repetitive -Each line - repetitive -contains - repetitive -at least one repetitive statement -repetitive -repetitive - repetita iuvant - repetitive -repetitive - repetita iuvant - repetitive -repetitive - repetita iuvant - repetitive -repetitive - repetita iuvant - repetitive -repetitive - repetita iuvant - repetitive -repetitive - repetita iuvant - repetitive -repetitive - repetita iuvant - repetitive -repetitive - repetita iuvant - repetitive -This short thext is highly repetitive - this is useful to test -the compression of the algorithm - repetitive -Each line - repetitive -contains - repetitive -at least one repetitive statement -repetitive -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse ligula dui, imperdiet ut vulputate semper, sollicitudin ut eros. Aliquam erat volutpat. In hac habitasse platea dictumst. Nam non tortor sit amet mauris rutrum eleifend. Pellentesque vel justo nibh. Vivamus sem risus, pharetra eget egestas eget, venenatis a ipsum. Cras ultrices aliquam sagittis. Donec lacinia urna ac orci congue ut adipiscing dolor fringilla. Nullam nibh magna, bibendum vulputate ornare id, hendrerit et metus. Nullam dapibus neque quis mi laoreet molestie. Mauris et dui lacus, sit amet egestas purus. -Donec accumsan elementum accumsan. Nullam gravida dictum diam non semper. Curabitur vel magna in velit accumsan pulvinar eget in lorem. Duis vitae ante velit, at hendrerit nibh. Pellentesque lacus urna, cursus ac semper sagittis, viverra at sem. Quisque ullamcorper odio dolor. In quis pretium lacus. Maecenas lacinia urna id massa congue blandit. Suspendisse dapibus eros sit amet neque fermentum imperdiet. Cras interdum pulvinar eleifend. Suspendisse molestie neque a risus imperdiet convallis. In interdum dignissim pharetra. Morbi lectus tortor, pulvinar quis eleifend in, placerat at risus. Sed aliquam diam at metus adipiscing blandit. -Integer tristique metus vel ipsum pulvinar dignissim quis vel quam. Donec auctor aliquet bibendum. Morbi aliquet malesuada ultrices. Vivamus ac leo odio. Nam tristique eros non arcu porttitor non volutpat mauris tempus. Proin vestibulum suscipit pretium. Etiam elit tortor, dictum a gravida porta, congue id dolor. Duis eget est vitae elit facilisis blandit. Proin tincidunt felis et ipsum pharetra tempor. Fusce imperdiet vulputate magna, vel lacinia neque volutpat a. Vivamus a elit dolor. Aliquam sollicitudin dui et leo elementum mattis. Quisque suscipit, lorem id eleifend imperdiet, ipsum lorem pharetra purus, vel tempus lectus ligula id tortor. Morbi eget eros vel sapien scelerisque aliquam pellentesque sed turpis. Duis vel lorem non eros semper fringilla vitae vitae erat. -Vivamus porttitor pulvinar tristique. Proin sed elit ipsum. Phasellus faucibus pulvinar dapibus. Praesent quis sem in purus ultrices imperdiet. Aenean ut nulla urna. In tristique tincidunt urna, nec adipiscing velit laoreet ut. Curabitur et ante sed libero tristique pellentesque. Quisque porttitor sodales ipsum ut rhoncus. Nunc vitae diam gravida orci aliquam cursus vitae ut sapien. Proin ullamcorper felis eu nulla dapibus nec faucibus odio hendrerit. Aenean lorem magna, fermentum in tristique sit amet, accumsan ut massa. Fusce tristique, lectus rhoncus commodo sagittis, ligula felis consequat arcu, id pretium enim dolor id mi. Donec facilisis pulvinar luctus. Pellentesque vitae condimentum risus. Nam quis elit a orci adipiscing bibendum. -Ut quis felis lorem, dignissim varius turpis. Sed convallis dui semper mauris fermentum porta. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aliquam erat volutpat. Proin lorem felis, scelerisque nec commodo non, porta eu metus. Nulla id augue a turpis mollis pellentesque. Aenean in lectus et leo tincidunt auctor eu interdum est. Nulla varius, lorem congue laoreet laoreet, felis quam ullamcorper ligula, non pellentesque dui ipsum quis odio. Etiam sit amet blandit leo. Aenean venenatis molestie eros, in fermentum ipsum dictum eget. Donec ultricies feugiat nisl, non molestie mi congue quis. Quisque mattis augue nec neque fringilla varius. Proin sollicitudin risus et elit pretium congue. Sed consequat eros sit amet felis pulvinar pulvinar. Morbi in turpis eu nulla cursus venenatis at ut urna. Donec vel lectus quis nisi aliquam varius. -Each line - repetitive -contains - repetitive -at least one repetitive statement -repetitive \ No newline at end of file diff --git a/internal/lzss/testdata/repetitive.lzss b/internal/lzss/testdata/repetitive.lzss deleted file mode 100644 index 3fb316f718829e2e11d41cddaaa4a1441944a7e9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3728 zcmWO7jU$tZ;{fnyk8NffW^CTsG@2QPowvI4Y$0#eNb*{xtYzHlNa4L@&+- zR{@%whor=%U*SoB9N>@=+1sCh!InIDmyGq)FUPs#0}Qtq?KI9H{A^M~JZsuxc7t?> z{LK7=#dj-XYkM1aTd%@T!wU$!zQ+EZ%3PJ8I;;9)bnWQg(Vo#yV?JYtr$l??L#Qld zqB-vL?4_~Ej4Nb52`1BtDv~zIQC{w7MNY6xM9sWTNKWo2D@<}@r&!GY;GF$SW|Al! zwMsG}p+alG!fJ5em`iDTbL8-gEyLWIP(;eG1BT)Mshft@`>z&x< zo^yHx@Ne*g9u?&2Ihp$43N$L2Z1-s9)ngbdUj6cu$`wP38~O_RjM>p(9LKllvY{eR zeiN$`NK*kp^KPAplkURv=C@h(J}O%uvV@`I#6t2TgIt7pm3j_(4c#Aa2k)h_ihQN* zwo+RKNk@#ef~|+hkjYSdr5R=^{lQ5R{2uIz)n&tnq^W@ifc>h&(%n>v_X<<%-|M66 zpP$a(q6wSbvfo%!0~_05Pq|Kf(T`X&=h(8b)68oHWLYQwUy-Wl9|Y5&D2`=!8bXXQNmXB(AYC#MsP`5&}r<2lU-np0R+(ppLZETalTdL8+pgfPhQZorB^!tMEncf|UvkX>Q?ZM`ucdE6+c zNazX!awMFsb5Wm*?OdS_wRSKibSZJ@^y-BLI>u`5e4<^s?ftgr%^t_-J%ByEIgas~ znhjGLd>_}SVwSh7wlf(nAue5Eg`#$I$4@SKorqU5_VG(rVoO^2zhHa$JF6UG4T!9; zmf0_~$c7EB7Q2BA*RpzOEKqg8qj6>uYVuOP1DDQs?y8o(o|0bW--l<%`Xo7S)1OaO z-ot9({M21pn#IGE-OcLe35SPn&){zOk?a{z;HDnC1z)6WUF=x=mz$MZ0M4aNl+LF; zUt9*K9QHcB6+8`I*p+fX!p+&XAtyP!IA|gDWr?rISIKPm51|5s^ugry4lakt<^HBa z8vnR!ed~s)zpl;oYhT0vwP|p*Wv^dCz+o?pkHz(61`qyZ*X1sfDm)+$XB+O1Y<67d zwPqsLc>NQK+0Ld`sB7`pPz3;_=GGmK^ z`UY8(o})u?MN61OcQAlDlIXJN^oJGQ#nvYFVrIi#8$y7Z+-@~cci(W9G=NuHumD9( z)Cv0Iizqa{RGhEBfZ}$qCTFS72wQGz+E$KC(+W#kG+tZ=+=5n?Rq4M)Ex!%hoA)wz zX;pUSVt~_yO_bXb7qmKzIVMP*bo--`=5%DXsoML&b3`%fOPysj7gC$HAWhBA5qKtl znzo|-gw^_5lVb0rb>SMyFuv z%yLaDY5ecB7~mrGa%offd!%l&*F>b)P+ZHiaLPh@BKxExV{N)TIHz6JtW`I(TnW6q z*ai;rha5@-H^E_5r$hSUF`$u>jl2bsLBiNLKZff;c~LPyHTv0>c)kvHro{YkmUHOH*~tEseU_ zuE7w$N=vLn^MX-}oC};vEuB4snHb{zVdxkCzrUOMp-C=+eVh z0u7^R5_|?~qu#wFV}ohu@hKr+ppm5qlog6->@RBCf&F>EMe(!92f6EGtpmk>70i%n z&d!-zUDsOr$DG^8-F_|-4b&$d{rcd#PYx zZE^bNgByPKfR^?CDv699cQt~kQ$zz1v*eeD(C6_BW4E#TqkCWz$XH@hVVG&8-K8{D z8F7ezV_>3`(kB>eD3jlJMYBV@4LuQJ%mZ`TbCWcL824lI{2{YEqRt#LZ?g0t!2R>Z zNQ@$c9)wKhF1r#Tt&7YZzx;dYCs{@3=j4|G@h0Y3yasb|-H!-)WIy`Lk7x z^;w%9+Z%Rw?4MCSP``6}TYdk$&TapA98SCZhp^DzAHl>lqiXA5Ab8=){hwjBEqIV!O%9dtrvFROxzV5iQk_%nm!x zfg#EYcIHE+d%WQcVs467uBDXT5%C*F?Wj`sX6OFo3Ca?`)tmPa)s{NTdP(;E;Yr(j z5ieL8s#h)*%Cs0yg*QRA=3pHiPWFvZr8J%-9IktG$wwM5`+~`{2&h2!ZtESqv?BFT zbQh;!?|63JyrNJS&+5(8$tg!6)X6mEIlbr7v(lt;2h0`Bi@FR?Wxovu2DFAy=IHf^ zjB$kO5Mpm&fiw`<0OfJsM;C(ST-}NBXXEA(^PQf$xh{YCTj4*L|Bn3?wv^f}k_%p7 z0(YktP%%Z0eTA>=Td2B0Qy8bC>PlhL-b+meGZzw!Yl$6^3RWna^I|UE!ZL_|HmImW zzig~MxN5S`AarX`-TQf61txgtL?>=N`FFb@g=+=RMl$JJ%*B4J6NTmf?uV^i;N6bY zp9ClCIGcDOO{jm$4(Z!e+niMz(hMa=t5}^;i2e|#SL3=#Vfzy&*GRq@iDW01R3uiZ zf6JA++TJq1HhDbs^ae$s1b6pH6bdo%amujfRK@CpP%(N1Gk{@XQfW)z41gCD0T@L~ zNEl`TMRRBsUk~YC3+!D7Y-N*f3RgI$K`%IWoio}YW+|CYW*ZYdE!bEO^nr}FZ*tc=6NykCHTrVP@d(cHf z%EXjl%4Q2AjcXyc6DzL4Qt*}H&BDz)TqSNfMlzQecb3~J!)E8FObK3wWo?N@@@aVY zV2seo1TmJPy`6abYjto&nts)$*oYA|l6u8$IlP+77cYjN*c9wGfouqhag*~^n_I)O zE8h0ZM!==P9XCNO>`z$$8V&XtG9s#hu<8A!jpNEr{Ag4c0g`WN-J2evt4X7y*IwS& z9X3|IewR@0U&$T+qMC+UUIU=Nu^p5r1UD$E$PN&mM13mcw+S}!CZlCSqiIM0f(Dfi zQDoIa4l}0}XySi%3@TRh}}l&;%cqHh$c!ywK{IYeo_Q) ngxTBljbH`Vg9pLJ{_Vtc{b6tf6cT&tuwc7hg?X3r9wGEU-Qp~Q diff --git a/internal/lzss/testdata/short b/internal/lzss/testdata/short deleted file mode 100644 index 4f006a88..00000000 --- a/internal/lzss/testdata/short +++ /dev/null @@ -1 +0,0 @@ -Lorem ipsum dolor sit amet, consectetur adipiscing elit. diff --git a/internal/lzss/testdata/short.lzss b/internal/lzss/testdata/short.lzss deleted file mode 100644 index 54588ab54674960d020d7b3f95e433c84f88a910..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 63 zcmV-F0KosITkcj{Y=YBpx!qsPESCFY_ymIIX}U-(Hrp-ISs=07?bkakj_3g4b${@% V*&oy`H#;4s-Di+lZGZ$4=ukoiAaMWy From 14ca88971e94ac296c1d76d9be3a93f27db3c53e Mon Sep 17 00:00:00 2001 From: Paolo Calao Date: Mon, 10 Jan 2022 14:33:48 +0100 Subject: [PATCH 09/11] Adjust brackets --- internal/lzss/lzss.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/internal/lzss/lzss.go b/internal/lzss/lzss.go index b13653de..3d27e35d 100644 --- a/internal/lzss/lzss.go +++ b/internal/lzss/lzss.go @@ -32,9 +32,9 @@ const ( threshold = 1 // If match length > threshold then output a token (idx, len), otherwise output one char. - bufsz = (1 << idxsz) // Buffer size. - looksz = ((1 << lensz) + 1) // Lookahead buffer size. - historysz = bufsz - looksz // History buffer size. + bufsz = 1 << idxsz // Buffer size. + looksz = (1 << lensz) + 1 // Lookahead buffer size. + historysz = bufsz - looksz // History buffer size. charStartBit = true // Indicates next bits encode a char. tokenStartBit = false // Indicates next bits encode a token. @@ -55,7 +55,7 @@ func findLargestMatch(buf []byte, current, size int) (idx, len int) { idx = 0 len = 1 ahead := min(looksz, size-current) - history := current - (historysz) + history := current - historysz c := buf[current] for i := current - 1; i >= history; i-- { if buf[i] == c { @@ -161,7 +161,7 @@ func (r *result) addChar(c byte) { i := int(c) r.putbit(charStartBit) for mask := (1 << charsz) >> 1; mask != 0; mask = mask >> 1 { - b := i&mask != 0 + b := (i & mask) != 0 r.putbit(b) } } @@ -169,7 +169,7 @@ func (r *result) addChar(c byte) { // addToken stores a token in the out buffer. func (r *result) addToken(idx, len int) { // Adjust idx and len to fit idxsz and lensz bits respectively - idx &= (bufsz - 1) + idx &= bufsz - 1 len -= 2 r.putbit(tokenStartBit) From 899bcb836c29d4bf9b266fe8d5898e8556e15352 Mon Sep 17 00:00:00 2001 From: Paolo Calao Date: Tue, 11 Jan 2022 11:33:48 +0100 Subject: [PATCH 10/11] Simplify fill method --- internal/lzss/lzss.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/internal/lzss/lzss.go b/internal/lzss/lzss.go index 3d27e35d..8bc8f2b8 100644 --- a/internal/lzss/lzss.go +++ b/internal/lzss/lzss.go @@ -132,8 +132,7 @@ func newFiller(src []byte) *filler { // The src buffer offset is then incremented so that all the content of src // can be consumed in small chunks. func (f *filler) fill(dst []byte) int { - n := min(len(f.src)-f.idx, len(dst)) - copy(dst, f.src[f.idx:f.idx+n]) + n := copy(dst, f.src[f.idx:]) f.idx += n return n } From c1ad862e0e5a22e1daeadec34f8389a3503c99a2 Mon Sep 17 00:00:00 2001 From: Paolo Calao Date: Tue, 11 Jan 2022 15:33:20 +0100 Subject: [PATCH 11/11] Move exported function on top of file --- internal/lzss/lzss.go | 68 +++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/internal/lzss/lzss.go b/internal/lzss/lzss.go index 8bc8f2b8..7aa7f6cb 100644 --- a/internal/lzss/lzss.go +++ b/internal/lzss/lzss.go @@ -40,40 +40,6 @@ const ( tokenStartBit = false // Indicates next bits encode a token. ) -func min(x, y int) int { - if x < y { - return x - } - return y -} - -// findLargestMatch looks for the largest sequence of characters (from current to current+ahead) -// contained in the history of the buffer. -// It returns the index of the found match, if any, and its length. -// The index is relative to the current position. If idx 0 is returned than no match has been found. -func findLargestMatch(buf []byte, current, size int) (idx, len int) { - idx = 0 - len = 1 - ahead := min(looksz, size-current) - history := current - historysz - c := buf[current] - for i := current - 1; i >= history; i-- { - if buf[i] == c { - var j int - for j = 1; j < ahead; j++ { - if buf[i+j] != buf[current+j] { - break - } - } - if j > len { - idx = i - len = j - } - } - } - return -} - // Encode takes a slice of bytes, compresses it using the lzss compression algorithm // and returns the result in a new bytes buffer. func Encode(data []byte) []byte { @@ -113,6 +79,40 @@ func Encode(data []byte) []byte { return out.bytes() } +func min(x, y int) int { + if x < y { + return x + } + return y +} + +// findLargestMatch looks for the largest sequence of characters (from current to current+ahead) +// contained in the history of the buffer. +// It returns the index of the found match, if any, and its length. +// The index is relative to the current position. If idx 0 is returned than no match has been found. +func findLargestMatch(buf []byte, current, size int) (idx, len int) { + idx = 0 + len = 1 + ahead := min(looksz, size-current) + history := current - historysz + c := buf[current] + for i := current - 1; i >= history; i-- { + if buf[i] == c { + var j int + for j = 1; j < ahead; j++ { + if buf[i+j] != buf[current+j] { + break + } + } + if j > len { + idx = i + len = j + } + } + } + return +} + // filler abstracts the process of consuming an input buffer // using its bytes to fill another buffer. // It's been used to facilitate the handling of the input buffer in the Encode function.