From 93bf1148ae6948178d8f2432e872c7b8d1ea8820 Mon Sep 17 00:00:00 2001 From: Avi Deitcher Date: Sun, 1 Sep 2024 12:50:52 +0300 Subject: [PATCH 1/4] fat32 tests expected data auto-generated Signed-off-by: Avi Deitcher --- filesystem/fat32/common_internal_test.go | 3 - filesystem/fat32/common_test.go | 509 ++++++++++++++++++ filesystem/fat32/directory_internal_test.go | 29 +- .../fat32/directoryentry_internal_test.go | 291 +--------- filesystem/fat32/dos331bpb_internal_test.go | 6 +- filesystem/fat32/dos71bpb_internal_test.go | 10 +- filesystem/fat32/fat32.go | 6 + filesystem/fat32/fat32_internal_test.go | 18 +- filesystem/fat32/fat32_test.go | 27 +- filesystem/fat32/fileinfo.go | 14 + .../fat32/fsinfosector_internal_test.go | 4 +- filesystem/fat32/table_internal_test.go | 180 +------ filesystem/fat32/testdata/.gitignore | 1 + filesystem/fat32/testdata/README.md | 51 +- filesystem/fat32/testdata/fat32.img | Bin 10485760 -> 0 bytes filesystem/fat32/testdata/mkfat32.sh | 99 +++- go.mod | 5 +- go.sum | 2 + 18 files changed, 709 insertions(+), 546 deletions(-) delete mode 100644 filesystem/fat32/common_internal_test.go create mode 100644 filesystem/fat32/common_test.go create mode 100644 filesystem/fat32/testdata/.gitignore delete mode 100644 filesystem/fat32/testdata/fat32.img diff --git a/filesystem/fat32/common_internal_test.go b/filesystem/fat32/common_internal_test.go deleted file mode 100644 index a7feffb1..00000000 --- a/filesystem/fat32/common_internal_test.go +++ /dev/null @@ -1,3 +0,0 @@ -package fat32 - -const Fat32File = "./testdata/fat32.img" diff --git a/filesystem/fat32/common_test.go b/filesystem/fat32/common_test.go new file mode 100644 index 00000000..8d5698f7 --- /dev/null +++ b/filesystem/fat32/common_test.go @@ -0,0 +1,509 @@ +package fat32 + +import ( + "bufio" + "bytes" + "fmt" + "os" + "os/exec" + "regexp" + "strconv" + "strings" + "testing" + "time" +) + +const ( + Fat32File = "./testdata/dist/fat32.img" + fsckFile = "./testdata/dist/fsck.txt" + rootdirFile = "./testdata/dist/root_dir.txt" + rootdirFileFLS = "./testdata/dist/root_dir_fls.txt" + rootdirEntryPattern = "./testdata/dist/root_dir_istat_%d.txt" + foodirFile = "./testdata/dist/foo_dir.txt" + foodirEntryPattern = "./testdata/dist/foo_dir_istat_%d.txt" + serialFile = "./testdata/dist/serial.txt" + fsstatFile = "./testdata/dist/fsstat.txt" +) + +type testFSInfo struct { + bytesPerCluster uint32 + dataStartBytes uint32 + dataStartSector uint32 + bytesPerSector uint32 + reservedSectors uint32 + sectorsPerFAT uint32 + label string + serial uint32 + sectorsPerTrack uint32 + heads uint32 + hiddenSectors uint32 + freeSectorCount uint32 + nextFreeSector uint32 + firstFAT uint32 + table *table +} + +var ( + testVolumeLabelRE = regexp.MustCompile(`^\s*Volume in drive\s+:\s+is\s+(.+)\s*$`) + testDirectoryEntryRE = regexp.MustCompile(`^\s*(\S+)\s+\s+(\d{4}-\d\d-\d\d\s+\d+:\d+)\s*(.*)\s*$`) + testFileEntryRE = regexp.MustCompile(`^\s*(\S+)\s*(\S*)\s+(\d+)\s+(\d{4}-\d\d-\d\d\s+\d+:\d+)\s*(.*)\s*$`) + testWrittenTimeRE = regexp.MustCompile(`\s*Written:\s+(\d{4}-\d\d-\d\d\s+\d\d:\d\d:\d\d)`) + testAccessedTimeRE = regexp.MustCompile(`\s*Accessed:\s+(\d{4}-\d\d-\d\d\s+\d\d:\d\d:\d\d)`) + testCreatedTimeRE = regexp.MustCompile(`\s*Created:\s+(\d{4}-\d\d-\d\d\s+\d\d:\d\d:\d\d)`) + testSectorListStartRE = regexp.MustCompile(`\s*Sectors:\s*$`) + testFSCKDataStart = regexp.MustCompile(`Data area starts at byte (\d+) \(sector (\d+)\)`) + testFSCKBytesPerSector = regexp.MustCompile(`^\s*(\d+) bytes per logical sector\s*$`) + testFSCKBytesPerCluster = regexp.MustCompile(`^\s*(\d+) bytes per cluster\s*$`) + testFSCKReservedSectors = regexp.MustCompile(`^\s*(\d+) reserved sectors\s*$`) + testFSCKSectorsPerFat = regexp.MustCompile(`^\s*(\d+) bytes per FAT \(= (\d+) sectors\)\s*$`) + testFSCKHeadsSectors = regexp.MustCompile(`^\s*(\d+) sectors/track, (\d+) heads\s*$`) + testFSCKHiddenSectors = regexp.MustCompile(`^\s*(\d+) hidden sectors\s*$`) + testFSCKFirstFAT = regexp.MustCompile(`^\s*First FAT starts at byte (\d+) \(sector (\d+)\)\s*$`) + testFSCKFATSize = regexp.MustCompile(`^\s*(\d+) bytes per FAT \(= (\d+) sectors\)\s*$`) + testFLSEntryPattern = regexp.MustCompile(`d/d (\d+):\s+(\S+)\s*.*$`) + testFSSTATFreeSectorCountRE = regexp.MustCompile(`^\s*Free Sector Count.*: (\d+)\s*$`) + testFSSTATNextFreeSectorRE = regexp.MustCompile(`^\s*Next Free Sector.*: (\d+)\s*`) + testFSSTATClustersStartRE = regexp.MustCompile(`\s*FAT CONTENTS \(in sectors\)\s*$`) + testFSSTATClusterLineRE = regexp.MustCompile(`\s*(\d+)-(\d+) \((\d+)\)\s+->\s+(\S+)\s*$`) + + fsInfo *testFSInfo +) + +// TestMain sets up the test environment and runs the tests +func TestMain(m *testing.M) { + // Check and generate artifacts if necessary + if _, err := os.Stat(Fat32File); os.IsNotExist(err) { + // Run the genartifacts.sh script + cmd := exec.Command("sh", "mkfat32.sh") + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + cmd.Dir = "testdata" + + // Execute the command + if err := cmd.Run(); err != nil { + println("error generating test artifacts for fat32", err) + os.Exit(1) + } + } + + // common info + var err error + fsInfo, err = testReadFilesystemData() + if err != nil { + println("Error reading fsck file", err) + os.Exit(1) + } + + // Run the tests + code := m.Run() + + // Exit with the appropriate code + os.Exit(code) +} + +// GetValidDirectoryEntries get directory entries for the root directory +// +//nolint:revive // yes we are returning an exported type, but that is ok for the tests +func GetValidDirectoryEntries() (entries []*directoryEntry, b []byte, err error) { + // read correct bytes off of disk + + input, err := os.ReadFile(Fat32File) + if err != nil { + return nil, nil, fmt.Errorf("error reading data from fat32 test fixture %s: %v", Fat32File, err) + } + start := fsInfo.dataStartBytes // start of root directory in fat32.img + // we only have 9 actual 32-byte entries, of which 4 are real and 3 are VFAT extensionBytes + // the rest are all 0s (as they should be), so we will include to exercise it + b = make([]byte, fsInfo.bytesPerCluster) + copy(b, input[start:start+fsInfo.bytesPerCluster]) + + entries, err = testGetValidDirectoryEntriesFromFile(rootdirFile, rootdirEntryPattern, fsInfo) + + // in the root directory, add the label entry + if fsInfo.label != "" { + filenameShort := fsInfo.label + extension := "" + if len(fsInfo.label) > 8 { + filenameShort = fsInfo.label[:8] + extension = fsInfo.label[8:] + } + de := &directoryEntry{filenameShort: filenameShort, fileExtension: extension, isVolumeLabel: true} + filename := fmt.Sprintf(rootdirEntryPattern, len(entries)) + if err := testPopulateDirectoryEntryFromIstatFile(de, filename, fsInfo); err != nil { + return nil, nil, err + } + entries = append(entries, de) + } + + return entries, b, err +} + +// getValidDirectoryEntriesExtended get directory entries for a directory where there are so many, +// it has to use the extended structure. Will look for the provided dir, +// but only one step down from root. If you want more, look for it elsewhere. +// +//nolint:revive // yes we are returning an exported type, but that is ok for the tests +func GetValidDirectoryEntriesExtended(dir string) (entries []*directoryEntry, b []byte, err error) { + // read correct bytes off of disk + + // find the cluster for the given directory + dir = strings.TrimPrefix(dir, "/") + dir = strings.TrimPrefix(dir, "\\") + dir = strings.TrimSuffix(dir, "/") + dir = strings.TrimSuffix(dir, "\\") + + flsData, err := os.ReadFile(rootdirFileFLS) + if err != nil { + return nil, nil, fmt.Errorf("error reading fls data from %s: %w", rootdirFileFLS, err) + } + scanner := bufio.NewScanner(bytes.NewReader(flsData)) + var cluster int + for scanner.Scan() { + text := scanner.Text() + match := testFLSEntryPattern.FindStringSubmatch(text) + if len(match) != 3 || match[2] != dir { + continue + } + cluster, err = strconv.Atoi(match[1]) + if err != nil { + return nil, nil, fmt.Errorf("error parsing cluster number %s: %w", match[1], err) + } + break + } + + input, err := os.ReadFile(Fat32File) + if err != nil { + return nil, nil, fmt.Errorf("error reading data from fat32 test fixture %s: %v", Fat32File, err) + } + start := fsInfo.dataStartBytes + 1 // start of foo directory in fat32.img + // we only have 9 actual 32-byte entries, of which 4 are real and 3 are VFAT extensionBytes + // the rest are all 0s (as they should be), so we will include to exercise it + b = make([]byte, fsInfo.bytesPerCluster) + copy(b, input[start:start+fsInfo.bytesPerCluster]) + + entries, err = testGetValidDirectoryEntriesFromFile(foodirFile, foodirEntryPattern, fsInfo) + // handle . and .. + if len(entries) > 0 && entries[0].filenameShort == "." { + entries[0].clusterLocation = uint32(cluster) + } + if len(entries) > 1 && entries[1].filenameShort == ".." { + // root always is 2, but it seems to store it as 0, for reasons I do not know + entries[1].clusterLocation = 0 + } + return entries, b, err +} + +func testGetValidDirectoryEntriesFromFile(dirFilePath, dirEntryPattern string, fsInfo *testFSInfo) (dirEntries []*directoryEntry, err error) { + dirInfo, err := os.ReadFile(dirFilePath) + if err != nil { + return nil, fmt.Errorf("error opening directory info file %s: %w", dirInfo, err) + } + scanner := bufio.NewScanner(bytes.NewReader(dirInfo)) + for scanner.Scan() { + text := scanner.Text() + dirEntryMatch := testDirectoryEntryRE.FindStringSubmatch(text) + fileEntryMatch := testFileEntryRE.FindStringSubmatch(text) + var ( + de *directoryEntry + ) + switch { + case len(dirEntryMatch) == 4: + filenameShort := dirEntryMatch[1] + de = &directoryEntry{ + filenameShort: strings.ToUpper(filenameShort), + isSubdirectory: true, + } + if dirEntryMatch[3] != "" { + de.filenameLong = strings.TrimSpace(dirEntryMatch[3]) + de.longFilenameSlots = calculateSlots(de.filenameLong) + } + if filenameShort != "." && filenameShort != ".." && strings.ToLower(filenameShort) == filenameShort { + de.lowercaseShortname = true + } + case len(fileEntryMatch) == 6: + size, err := strconv.Atoi(fileEntryMatch[3]) + if err != nil { + return nil, fmt.Errorf("error parsing file size %s: %w", fileEntryMatch[3], err) + } + de = &directoryEntry{ + filenameShort: strings.ToUpper(fileEntryMatch[1]), + fileExtension: strings.ToUpper(fileEntryMatch[2]), + fileSize: uint32(size), + isArchiveDirty: true, + } + if strings.ToLower(fileEntryMatch[1]) == fileEntryMatch[1] { + de.lowercaseShortname = true + } + if fileEntryMatch[2] != "" && strings.ToLower(fileEntryMatch[2]) == fileEntryMatch[2] { + de.lowercaseExtension = true + } + if fileEntryMatch[5] != "" { + de.filenameLong = strings.TrimSpace(fileEntryMatch[5]) + de.longFilenameSlots = calculateSlots(de.filenameLong) + } + default: + continue + } + dirEntries = append(dirEntries, de) + } + // now need to go through the more detailed info from istat and find the dates + // ignore entries for . and .. + dirEntriesSubset := dirEntries + for { + if len(dirEntriesSubset) == 0 || (dirEntriesSubset[0].filenameShort != "." && dirEntriesSubset[0].filenameShort != "..") { + break + } + dirEntriesSubset = dirEntriesSubset[1:] + } + for i, de := range dirEntriesSubset { + filename := fmt.Sprintf(dirEntryPattern, i) + if err := testPopulateDirectoryEntryFromIstatFile(de, filename, fsInfo); err != nil { + return nil, err + } + } + return dirEntries, nil +} + +func testPopulateDirectoryEntryFromIstatFile(de *directoryEntry, filename string, fsInfo *testFSInfo) error { + dirInfo, err := os.ReadFile(filename) + if err != nil { + return fmt.Errorf("error opening directory entry info file %s: %w", filename, err) + } + scanner := bufio.NewScanner(bytes.NewReader(dirInfo)) + var inSectors bool + for scanner.Scan() { + text := scanner.Text() + sectorStartMatch := testSectorListStartRE.FindStringSubmatch(text) + writtenTimeMatch := testWrittenTimeRE.FindStringSubmatch(text) + accessedTimeMatch := testAccessedTimeRE.FindStringSubmatch(text) + createdTimeMatch := testCreatedTimeRE.FindStringSubmatch(text) + switch { + case inSectors: + // just split the line and use all non-whitespace as numbers + if de.clusterLocation != 0 { + continue + } + sectors := strings.Fields(text) + for _, sector := range sectors { + sectorNum, err := strconv.Atoi(sector) + if err != nil { + return fmt.Errorf("error parsing sector number %s: %w", sector, err) + } + de.clusterLocation = uint32(sectorNum) - fsInfo.dataStartSector + 2 + break + } + case len(sectorStartMatch) > 0: + inSectors = true + case len(writtenTimeMatch) == 2: + date, err := time.Parse("2006-01-02 15:04:05", strings.TrimSpace(writtenTimeMatch[1])) + if err != nil { + return fmt.Errorf("error parsing written time %s: %w", writtenTimeMatch[1], err) + } + de.modifyTime = date + case len(accessedTimeMatch) == 2: + date, err := time.Parse("2006-01-02 15:04:05", strings.TrimSpace(accessedTimeMatch[1])) + if err != nil { + return fmt.Errorf("error parsing accessed time %s: %w", accessedTimeMatch[1], err) + } + de.accessTime = date + case len(createdTimeMatch) == 2: + date, err := time.Parse("2006-01-02 15:04:05", strings.TrimSpace(createdTimeMatch[1])) + if err != nil { + return fmt.Errorf("error parsing accessed time %s: %w", createdTimeMatch[1], err) + } + de.createTime = date + } + } + return nil +} + +//nolint:gocyclo // we need to call this function from the test, do not care that it is too complex +func testReadFilesystemData() (info *testFSInfo, err error) { + info = &testFSInfo{} + fsckInfo, err := os.ReadFile(fsckFile) + if err != nil { + return nil, fmt.Errorf("error opening fsck info file %s: %v", fsckFile, err) + } + scanner := bufio.NewScanner(bytes.NewReader(fsckInfo)) + for scanner.Scan() { + text := scanner.Text() + dataStartMatch := testFSCKDataStart.FindStringSubmatch(text) + bytesPerClusterMatch := testFSCKBytesPerCluster.FindStringSubmatch(text) + bytesPerSectorMatch := testFSCKBytesPerSector.FindStringSubmatch(text) + reservedSectorsMatch := testFSCKReservedSectors.FindStringSubmatch(text) + sectorsPerFATMatch := testFSCKSectorsPerFat.FindStringSubmatch(text) + headsSectorMatch := testFSCKHeadsSectors.FindStringSubmatch(text) + hiddenSectorsMatch := testFSCKHiddenSectors.FindStringSubmatch(text) + firstFATMatch := testFSCKFirstFAT.FindStringSubmatch(text) + switch { + case len(headsSectorMatch) == 3: + sectorsPerTrack, err := strconv.Atoi(headsSectorMatch[1]) + if err != nil { + return nil, fmt.Errorf("error parsing sectors per track %s: %v", headsSectorMatch[1], err) + } + heads, err := strconv.Atoi(headsSectorMatch[2]) + if err != nil { + return nil, fmt.Errorf("error parsing heads %s: %v", headsSectorMatch[2], err) + } + info.sectorsPerTrack = uint32(sectorsPerTrack) + info.heads = uint32(heads) + case len(hiddenSectorsMatch) == 2: + hiddenSectors, err := strconv.Atoi(hiddenSectorsMatch[1]) + if err != nil { + return nil, fmt.Errorf("error parsing hidden sectors %s: %v", hiddenSectorsMatch[1], err) + } + info.hiddenSectors = uint32(hiddenSectors) + case len(dataStartMatch) == 3: + byteStart, err := strconv.Atoi(dataStartMatch[1]) + if err != nil { + return nil, fmt.Errorf("error parsing data start byte %s: %v", dataStartMatch[1], err) + } + sectorStart, err := strconv.Atoi(dataStartMatch[2]) + if err != nil { + return nil, fmt.Errorf("error parsing data start sector %s: %v", dataStartMatch[2], err) + } + info.dataStartBytes = uint32(byteStart) + info.dataStartSector = uint32(sectorStart) + + case len(bytesPerClusterMatch) == 2: + bytesPerCluster, err := strconv.Atoi(bytesPerClusterMatch[1]) + if err != nil { + return nil, fmt.Errorf("error parsing bytes per cluster %s: %v", bytesPerClusterMatch[1], err) + } + info.bytesPerCluster = uint32(bytesPerCluster) + case len(bytesPerSectorMatch) == 2: + bytesPerSector, err := strconv.Atoi(bytesPerSectorMatch[1]) + if err != nil { + return nil, fmt.Errorf("error parsing bytes per sector %s: %v", bytesPerSectorMatch[1], err) + } + info.bytesPerSector = uint32(bytesPerSector) + case len(reservedSectorsMatch) == 2: + reservedSectors, err := strconv.Atoi(reservedSectorsMatch[1]) + if err != nil { + return nil, fmt.Errorf("error parsing reserved sectors %s: %v", reservedSectorsMatch[1], err) + } + info.reservedSectors = uint32(reservedSectors) + case len(sectorsPerFATMatch) == 3: + sectorsPerFAT, err := strconv.Atoi(sectorsPerFATMatch[2]) + if err != nil { + return nil, fmt.Errorf("error parsing sectors per FAT %s: %v", sectorsPerFATMatch[2], err) + } + info.sectorsPerFAT = uint32(sectorsPerFAT) + case len(firstFATMatch) == 3: + firstFAT, err := strconv.Atoi(firstFATMatch[1]) + if err != nil { + return nil, fmt.Errorf("error parsing first FAT byte %s: %v", firstFATMatch[1], err) + } + info.firstFAT = uint32(firstFAT) + } + } + + // get the filesystem label + dirInfo, err := os.ReadFile(rootdirFile) + if err != nil { + println("Error opening directory info file", rootdirFile, err) + os.Exit(1) + } + + scanner = bufio.NewScanner(bytes.NewReader(dirInfo)) + for scanner.Scan() { + text := scanner.Text() + volLabelMatch := testVolumeLabelRE.FindStringSubmatch(text) + if len(volLabelMatch) == 2 { + info.label = strings.TrimSpace(volLabelMatch[1]) + break + } + } + + serial, err := os.ReadFile(serialFile) + if err != nil { + println("Error reading serial file", serialFile, err) + os.Exit(1) + } + decimal, err := strconv.ParseInt(strings.TrimSpace(string(serial)), 16, 64) + if err != nil { + println("Error converting contents of serial file to integer:", err) + os.Exit(1) + } + info.serial = uint32(decimal) + + fsstat, err := os.ReadFile(fsstatFile) + if err != nil { + println("Error reading fsstat file", fsstatFile, err) + os.Exit(1) + } + scanner = bufio.NewScanner(bytes.NewReader(fsstat)) + var inClusters bool + for scanner.Scan() { + text := scanner.Text() + freeSectorsMatch := testFSSTATFreeSectorCountRE.FindStringSubmatch(text) + nextFreeSectorMatch := testFSSTATNextFreeSectorRE.FindStringSubmatch(text) + clusterStartMatch := testFSSTATClustersStartRE.FindStringSubmatch(text) + clusterLineMatch := testFSSTATClusterLineRE.FindStringSubmatch(text) + switch { + case len(freeSectorsMatch) == 2: + freeSectors, err := strconv.Atoi(freeSectorsMatch[1]) + if err != nil { + println("Error parsing free sectors count", freeSectorsMatch[1], err) + os.Exit(1) + } + info.freeSectorCount = uint32(freeSectors) + case len(nextFreeSectorMatch) == 2: + nextFreeSector, err := strconv.Atoi(nextFreeSectorMatch[1]) + if err != nil { + println("Error parsing next free sector", nextFreeSectorMatch[1], err) + os.Exit(1) + } + // make sure to drop by the data start sector, and add 2 for the root and FAT + info.nextFreeSector = uint32(nextFreeSector) - info.dataStartSector + 2 + case len(clusterStartMatch) > 0: + inClusters = true + sectorsPerFat := info.sectorsPerFAT + sizeInBytes := sectorsPerFat * info.bytesPerSector + numClusters := sizeInBytes / 4 + info.table = &table{ + fatID: 268435448, // 0x0ffffff8 + eocMarker: eoc, // 0x0fffffff + rootDirCluster: 2, // root is at cluster 2 + size: sizeInBytes, + maxCluster: numClusters, + clusters: make(map[uint32]uint32), + } + case inClusters && len(clusterLineMatch) > 4: + start, err := strconv.Atoi(clusterLineMatch[1]) + if err != nil { + println("Error parsing cluster start", clusterLineMatch[1], err) + os.Exit(1) + } + end, err := strconv.Atoi(clusterLineMatch[2]) + if err != nil { + println("Error parsing cluster end", clusterLineMatch[2], err) + os.Exit(1) + } + var target uint32 + if clusterLineMatch[4] == "EOF" { + target = eoc + } else { + targetInt, err := strconv.Atoi(clusterLineMatch[4]) + if err != nil { + println("Error parsing cluster target", clusterLineMatch[4], err) + os.Exit(1) + } + target = uint32(targetInt) - info.dataStartSector + 2 + } + // 2 is a special case that fsstat does not handle well + // the start and end might be the same, or it might be a continual chain, + // with only the last pointing at the target + for i := start; i < end; i++ { + startCluster := uint32(i) - info.dataStartSector + 2 + info.table.clusters[startCluster] = startCluster + 1 + } + endCluster := uint32(end) - info.dataStartSector + 2 + if endCluster == 2 { + target = eocMin + } + info.table.clusters[endCluster] = target + } + } + return info, err +} diff --git a/filesystem/fat32/directory_internal_test.go b/filesystem/fat32/directory_internal_test.go index c0442086..d32be321 100644 --- a/filesystem/fat32/directory_internal_test.go +++ b/filesystem/fat32/directory_internal_test.go @@ -5,20 +5,18 @@ import ( "fmt" "testing" "time" + + "github.com/diskfs/go-diskfs/util" + "github.com/google/go-cmp/cmp" ) // TestDirectoryEntriesFromBytes largely a duplicate of TestdirectoryEntryParseDirEntries // it just loads it into the Directory structure func TestDirectoryEntriesFromBytes(t *testing.T) { - validDe, validBytes, err := getValidDirectoryEntries() + validDe, b, err := GetValidDirectoryEntries() if err != nil { t.Fatal(err) } - // validBytes is ordered [][]byte - just string them all together - b := make([]byte, 0) - for _, b2 := range validBytes { - b = append(b, b2...) - } d := &Directory{} err = d.entriesFromBytes(b) @@ -34,24 +32,18 @@ func TestDirectoryEntriesFromBytes(t *testing.T) { for i, de := range d.entries { if *de != *validDe[i] { t.Errorf("%d: directoryEntry mismatch, actual then valid:", i) - t.Logf("%#v", *de) - t.Logf("%#v", *validDe[i]) + t.Log(cmp.Diff(*de, *validDe[i], cmp.AllowUnexported(directoryEntry{}))) } } } } func TestDirectoryEntriesToBytes(t *testing.T) { - validDe, validBytes, err := getValidDirectoryEntries() - bytesPerCluster := 2048 + validDe, b, err := GetValidDirectoryEntries() + bytesPerCluster := 512 if err != nil { t.Fatal(err) } - // validBytes is ordered [][]byte - just string them all together - b := make([]byte, 0) - for _, b2 := range validBytes { - b = append(b, b2...) - } d := &Directory{ entries: validDe, directoryEntry: directoryEntry{ @@ -71,9 +63,10 @@ func TestDirectoryEntriesToBytes(t *testing.T) { case len(output) != len(b): t.Errorf("mismatched byte slice length actual %d, expected %d", len(output), len(b)) case !bytes.Equal(output, b): - t.Errorf("Mismatched output of bytes. Actual then expected:") - t.Logf("%v", output) - t.Logf("%v", b) + diff, diffString := util.DumpByteSlicesWithDiffs(output, b, 32, false, true, true) + if diff { + t.Errorf("directory.toBytes() mismatched, actual then expected\n%s", diffString) + } } } diff --git a/filesystem/fat32/directoryentry_internal_test.go b/filesystem/fat32/directoryentry_internal_test.go index 3e741c4b..d0ea9d15 100644 --- a/filesystem/fat32/directoryentry_internal_test.go +++ b/filesystem/fat32/directoryentry_internal_test.go @@ -3,10 +3,11 @@ package fat32 import ( "bytes" "fmt" - "os" "strings" "testing" "time" + + "github.com/diskfs/go-diskfs/util" ) var ( @@ -84,271 +85,6 @@ func compareDirectoryEntriesIgnoreDates(a, b *directoryEntry) bool { return *c == *d } -func getValidDirectoryEntries() ([]*directoryEntry, [][]byte, error) { - // these are taken from the file ./testdata/fat32.img, see ./testdata/README.md - t1, _ := time.Parse(time.RFC3339, "2017-11-26T07:53:16Z") - t10, _ := time.Parse(time.RFC3339, "2017-11-26T00:00:00Z") - t2, _ := time.Parse(time.RFC3339, "2017-11-26T08:01:02Z") - t20, _ := time.Parse(time.RFC3339, "2017-11-26T00:00:00Z") - t3, _ := time.Parse(time.RFC3339, "2017-11-26T08:01:38Z") - t30, _ := time.Parse(time.RFC3339, "2017-11-26T00:00:00Z") - t4, _ := time.Parse(time.RFC3339, "2017-11-26T08:01:44Z") - t40, _ := time.Parse(time.RFC3339, "2017-11-26T00:00:00Z") - t5, _ := time.Parse(time.RFC3339, "2022-10-14T17:38:42Z") - t50, _ := time.Parse(time.RFC3339, "2022-10-14T00:00:00Z") - entries := []*directoryEntry{ - { - filenameShort: "FOO", - fileExtension: "", - filenameLong: "", - isReadOnly: false, - isHidden: false, - isSystem: false, - isVolumeLabel: false, - isSubdirectory: true, - isArchiveDirty: false, - isDevice: false, - lowercaseShortname: true, - createTime: t1, - modifyTime: t1, - accessTime: t10, - acccessRights: accessRightsUnlimited, - clusterLocation: 3, - fileSize: 0, - // start: uint32, - longFilenameSlots: 0, - isNew: false, - }, - { - filenameShort: "TERCER~1", - fileExtension: "", - filenameLong: "tercer_archivo", - isReadOnly: false, - isHidden: false, - isSystem: false, - isVolumeLabel: false, - isSubdirectory: false, - isArchiveDirty: true, - isDevice: false, - createTime: t2, - modifyTime: t2, - accessTime: t20, - acccessRights: accessRightsUnlimited, - clusterLocation: 5, - fileSize: 6144, - // start: uint32, - longFilenameSlots: 2, - isNew: false, - }, - { - filenameShort: "CORTO1", - fileExtension: "TXT", - filenameLong: "", - isReadOnly: false, - isHidden: false, - isSystem: false, - isVolumeLabel: false, - isSubdirectory: false, - isArchiveDirty: true, - isDevice: false, - createTime: t3, - modifyTime: t3, - accessTime: t30, - acccessRights: accessRightsUnlimited, - clusterLocation: 17, - fileSize: 25, - // start: uint32, - longFilenameSlots: 0, - isNew: false, - }, - { - filenameShort: "UNARCH~1", - fileExtension: "DAT", - filenameLong: "Un archivo con nombre largo.dat", - isReadOnly: false, - isHidden: false, - isSystem: false, - isVolumeLabel: false, - isSubdirectory: false, - isArchiveDirty: true, - isDevice: false, - createTime: t4, - modifyTime: t4, - accessTime: t40, - acccessRights: accessRightsUnlimited, - clusterLocation: 18, - fileSize: 7168, - // start: uint32, - longFilenameSlots: 3, - isNew: false, - }, - { - filenameShort: "go-diskf", - fileExtension: "s", - filenameLong: "", - isReadOnly: false, - isHidden: false, - isSystem: false, - isVolumeLabel: true, - isSubdirectory: false, - isArchiveDirty: false, - isDevice: false, - lowercaseShortname: false, - createTime: t5, - modifyTime: t5, - accessTime: t50, - acccessRights: accessRightsUnlimited, - clusterLocation: 0, - fileSize: 0, - // start: uint32, - longFilenameSlots: 0, - isNew: false, - }, - } - - // read correct bytes off of disk - input, err := os.ReadFile(Fat32File) - if err != nil { - return nil, nil, fmt.Errorf("error reading data from fat32 test fixture %s: %v", Fat32File, err) - } - - // start of root directory in fat32.img - sector 348 - // sector 0 - boot sector ; indicates: 32 reserved sectors (0-31); 158 sectors per fat - // sector 1 - FS Information Sector - // sector 2-31 - more reserved sectors - // sector 32-189 - FAT1 - // sector 190-347 - FAT2 - // sector 348 - start of root directory - // 348*512 = 178176 - start := 178176 // 0x0002b800 - start of root directory in fat32.img - - // we only have 9 actual 32-byte entries, of which 4 are real and 3 are VFAT extensionBytes - // the rest are all 0s (as they should be), so we will include to exercise it - b := make([][]byte, 8) - // - b[0] = input[start : start+32] - b[1] = input[start+32 : start+4*32] - b[2] = input[start+4*32 : start+5*32] - b[3] = input[start+5*32 : start+9*32] - b[4] = input[start+9*32 : start+10*32] - b[5] = input[start+10*32 : start+11*32] - b[6] = input[start+11*32 : start+12*32] - // how many zeroes will come from cluster? - remainder := 2048 - (12 * 32) - b[7] = make([]byte, remainder) - return entries, b, nil -} - -//nolint:unparam // nothing uses the content, but we want to keep it for future usage -func getValidDirectoryEntriesExtended() (entries []*directoryEntry, content [][]byte, err error) { - // these are taken from the file ./testdata/fat32.img, see ./testdata/README.md - t1, _ := time.Parse(time.RFC3339, "2017-11-26T07:53:16Z") - t10, _ := time.Parse(time.RFC3339, "2017-11-26T00:00:00Z") - entries = []*directoryEntry{ - // FilenameShort, FileExtension,FilenameLong,IsReadOnly,IsHidden,IsSystem,IsVolumeLabel,IsSubdirectory,IsArchiveDirty,IsDevice,LowercaseShortname,LowercaseExtension,CreateTime,ModifyTime,AccessTime,AcccessRights,clusterLocation,FileSize,filesystem,start,longFilenameSlots,isNew, - {".", "", "", false, false, false, false, true, false, false, false, false, t1, t1, t10, accessRightsUnlimited, 3, 0, nil, 0, false}, - {"..", "", "", false, false, false, false, true, false, false, false, false, t1, t1, t10, accessRightsUnlimited, 0, 0, nil, 0, false}, - {"BAR", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 4, 0, nil, 0, false}, - {"DIR", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x2e, 0, nil, 0, false}, - - {"DIR0", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x2f, 0, nil, 0, false}, - {"DIR1", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x30, 0, nil, 0, false}, - {"DIR2", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x31, 0, nil, 0, false}, - {"DIR3", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x32, 0, nil, 0, false}, - {"DIR4", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x33, 0, nil, 0, false}, - {"DIR5", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x34, 0, nil, 0, false}, - {"DIR6", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x35, 0, nil, 0, false}, - {"DIR7", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x36, 0, nil, 0, false}, - {"DIR8", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x37, 0, nil, 0, false}, - {"DIR9", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x38, 0, nil, 0, false}, - {"DIR10", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x39, 0, nil, 0, false}, - {"DIR11", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x3a, 0, nil, 0, false}, - - {"DIR12", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x3b, 0, nil, 0, false}, - {"DIR13", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x3d, 0, nil, 0, false}, - {"DIR14", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x3e, 0, nil, 0, false}, - {"DIR15", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x3f, 0, nil, 0, false}, - {"DIR16", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x40, 0, nil, 0, false}, - {"DIR17", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x41, 0, nil, 0, false}, - {"DIR18", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x42, 0, nil, 0, false}, - {"DIR19", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x43, 0, nil, 0, false}, - {"DIR20", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x44, 0, nil, 0, false}, - {"DIR21", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x45, 0, nil, 0, false}, - {"DIR22", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x46, 0, nil, 0, false}, - {"DIR23", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x47, 0, nil, 0, false}, - {"DIR24", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x48, 0, nil, 0, false}, - {"DIR25", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x49, 0, nil, 0, false}, - {"DIR26", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x4a, 0, nil, 0, false}, - {"DIR27", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x4b, 0, nil, 0, false}, - - {"DIR28", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x4c, 0, nil, 0, false}, - {"DIR29", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x4e, 0, nil, 0, false}, - {"DIR30", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x4f, 0, nil, 0, false}, - {"DIR31", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x50, 0, nil, 0, false}, - {"DIR32", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x51, 0, nil, 0, false}, - {"DIR33", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x52, 0, nil, 0, false}, - {"DIR34", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x53, 0, nil, 0, false}, - {"DIR35", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x54, 0, nil, 0, false}, - {"DIR36", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x55, 0, nil, 0, false}, - {"DIR37", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x56, 0, nil, 0, false}, - {"DIR38", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x57, 0, nil, 0, false}, - {"DIR39", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x58, 0, nil, 0, false}, - {"DIR40", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x59, 0, nil, 0, false}, - {"DIR41", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x5a, 0, nil, 0, false}, - {"DIR42", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x5b, 0, nil, 0, false}, - {"DIR43", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x5c, 0, nil, 0, false}, - - {"DIR44", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x5d, 0, nil, 0, false}, - {"DIR45", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x5f, 0, nil, 0, false}, - {"DIR46", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x60, 0, nil, 0, false}, - {"DIR47", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x61, 0, nil, 0, false}, - {"DIR48", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x62, 0, nil, 0, false}, - {"DIR49", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x63, 0, nil, 0, false}, - {"DIR50", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x64, 0, nil, 0, false}, - {"DIR51", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x65, 0, nil, 0, false}, - {"DIR52", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x66, 0, nil, 0, false}, - {"DIR53", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x67, 0, nil, 0, false}, - {"DIR54", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x68, 0, nil, 0, false}, - {"DIR55", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x69, 0, nil, 0, false}, - {"DIR56", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x6a, 0, nil, 0, false}, - {"DIR57", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x6b, 0, nil, 0, false}, - {"DIR58", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x6c, 0, nil, 0, false}, - {"DIR59", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x6d, 0, nil, 0, false}, - - {"DIR60", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x6e, 0, nil, 0, false}, - {"DIR61", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x70, 0, nil, 0, false}, - {"DIR62", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x71, 0, nil, 0, false}, - {"DIR63", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x72, 0, nil, 0, false}, - {"DIR64", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x73, 0, nil, 0, false}, - {"DIR65", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x74, 0, nil, 0, false}, - {"DIR66", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x75, 0, nil, 0, false}, - {"DIR67", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x76, 0, nil, 0, false}, - {"DIR68", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x77, 0, nil, 0, false}, - {"DIR69", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x78, 0, nil, 0, false}, - {"DIR70", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x79, 0, nil, 0, false}, - {"DIR71", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x7a, 0, nil, 0, false}, - {"DIR72", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x7b, 0, nil, 0, false}, - {"DIR73", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x7c, 0, nil, 0, false}, - {"DIR74", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x7d, 0, nil, 0, false}, - {"DIR75", "", "", false, false, false, false, true, false, false, true, false, t1, t1, t10, accessRightsUnlimited, 0x7e, 0, nil, 0, false}, - } - - // read correct bytes off of disk - input, err := os.ReadFile(Fat32File) - if err != nil { - return nil, nil, fmt.Errorf("error reading data from fat32 test fixture %s: %v", Fat32File, err) - } - - // start of foo directory in fat32.img - cluster 3 = sector 349 = bytes 349*512 = 178688 = 0x0002ba00 - start := 178688 - - b := make([][]byte, len(entries)) - for i := 0; i < len(entries); i++ { - b[i] = input[start+i*32 : start+i*32+32] - } - return entries, b, nil -} - func TestDirectoryEntryLongFilenameBytes(t *testing.T) { for _, tt := range sfnBytesTests { output, err := longFilenameBytes(tt.lfn, tt.shortName, tt.extension) @@ -530,12 +266,7 @@ func TestDirectoryEntryUCaseValid(t *testing.T) { } func TestDirectoryEntryParseDirEntries(t *testing.T) { - validDe, validBytes, err := getValidDirectoryEntries() - // validBytes is ordered [][]byte - just string them all together - b := make([]byte, 0) - for _, b2 := range validBytes { - b = append(b, b2...) - } + validDe, b, err := GetValidDirectoryEntries() if err != nil { t.Fatal(err) } @@ -571,19 +302,23 @@ func TestDirectoryEntryParseDirEntries(t *testing.T) { } func TestDirectoryEntryToBytes(t *testing.T) { - validDe, validBytes, err := getValidDirectoryEntries() + validDe, validBytes, err := GetValidDirectoryEntries() if err != nil { t.Fatal(err) } - for i, de := range validDe { + i := 0 + for _, de := range validDe { b, err := de.toBytes() + expected := validBytes[i*32 : (i+1+de.longFilenameSlots)*32] if err != nil { t.Errorf("error converting directory entry to bytes: %v", err) t.Logf("%v", de) - } else if !bytes.Equal(b, validBytes[i]) { - t.Errorf("Mismatched bytes %s, actual vs expected", de.filenameShort) - t.Log(b) - t.Log(validBytes[i]) + } else { + diff, diffString := util.DumpByteSlicesWithDiffs(b, expected, 32, false, true, true) + if diff { + t.Errorf("directory.toBytes() %s mismatched, actual then expected\n%s", de.filenameShort, diffString) + } } + i += de.longFilenameSlots + 1 } } diff --git a/filesystem/fat32/dos331bpb_internal_test.go b/filesystem/fat32/dos331bpb_internal_test.go index eeb966e9..02ad982e 100644 --- a/filesystem/fat32/dos331bpb_internal_test.go +++ b/filesystem/fat32/dos331bpb_internal_test.go @@ -11,9 +11,9 @@ import ( func getValidDos331BPB() *dos331BPB { return &dos331BPB{ dos20BPB: getValidDos20BPB(), - sectorsPerTrack: 32, - heads: 64, - hiddenSectors: 0, + sectorsPerTrack: uint16(fsInfo.sectorsPerTrack), + heads: uint16(fsInfo.heads), + hiddenSectors: fsInfo.hiddenSectors, totalSectors: 0, } } diff --git a/filesystem/fat32/dos71bpb_internal_test.go b/filesystem/fat32/dos71bpb_internal_test.go index 4f0fab4a..3b1f6336 100644 --- a/filesystem/fat32/dos71bpb_internal_test.go +++ b/filesystem/fat32/dos71bpb_internal_test.go @@ -11,7 +11,7 @@ import ( func getValidDos71EBPB() *dos71EBPB { return &dos71EBPB{ dos331BPB: getValidDos331BPB(), - sectorsPerFat: 158, + sectorsPerFat: fsInfo.sectorsPerFAT, mirrorFlags: 0, version: 0, rootDirectoryCluster: 2, @@ -21,8 +21,8 @@ func getValidDos71EBPB() *dos71EBPB { driveNumber: 128, reservedFlags: 0x00, extendedBootSignature: 0x29, - volumeSerialNumber: 2712131608, - volumeLabel: "go-diskfs", + volumeSerialNumber: fsInfo.serial, + volumeLabel: fsInfo.label, fileSystemType: "FAT32", } } @@ -118,8 +118,8 @@ func TestDos71EBPBFromBytes(t *testing.T) { valid.volumeLabel = "" valid.fileSystemType = "" if !bpb.equal(valid) { - t.Log(bpb) - t.Log(valid) + t.Logf("%#v", bpb) + t.Logf("%#v", valid) t.Fatalf("Mismatched BPB") } }) diff --git a/filesystem/fat32/fat32.go b/filesystem/fat32/fat32.go index 1f968f07..b13c42aa 100644 --- a/filesystem/fat32/fat32.go +++ b/filesystem/fat32/fat32.go @@ -65,6 +65,12 @@ type FileSystem struct { // Equal compare if two filesystems are equal func (fs *FileSystem) Equal(a *FileSystem) bool { + if fs == nil && a == nil { + return true + } + if fs == nil || a == nil { + return false + } localMatch := fs.file == a.file && fs.dataStart == a.dataStart && fs.bytesPerCluster == a.bytesPerCluster tableMatch := fs.table.equal(&a.table) bsMatch := fs.bootSector.equal(&a.bootSector) diff --git a/filesystem/fat32/fat32_internal_test.go b/filesystem/fat32/fat32_internal_test.go index 4b300061..919141e8 100644 --- a/filesystem/fat32/fat32_internal_test.go +++ b/filesystem/fat32/fat32_internal_test.go @@ -8,6 +8,7 @@ import ( "testing" "github.com/diskfs/go-diskfs/testhelper" + "github.com/google/go-cmp/cmp" ) /* @@ -58,6 +59,7 @@ func getValidFat32FSSmall() *FileSystem { bytesPerCluster: 512, dataStart: 178176, file: &testhelper.FileImpl{ + //nolint:revive // unused parameter, keeping name makes it easier to use in the future Writer: func(b []byte, offset int64) (int, error) { return len(b), nil }, @@ -122,14 +124,14 @@ func TestFat32ReadDirectory(t *testing.T) { fs := &FileSystem{ table: *getValidFat32Table(), file: file, - bytesPerCluster: 512, - dataStart: 178176, + bytesPerCluster: int(fsInfo.bytesPerCluster), + dataStart: fsInfo.dataStartBytes, } - validDe, _, err := getValidDirectoryEntries() + validDe, _, err := GetValidDirectoryEntries() if err != nil { t.Fatalf("unable to read valid directory entries: %v", err) } - validDeExtended, _, err := getValidDirectoryEntriesExtended() + validDeExtended, _, err := GetValidDirectoryEntriesExtended("/foo") if err != nil { t.Fatalf("unable to read valid directory entries extended: %v", err) } @@ -159,8 +161,7 @@ func TestFat32ReadDirectory(t *testing.T) { for i, entry := range entries { if !compareDirectoryEntriesIgnoreDates(entry, tt.entries[i]) { t.Errorf("fs.readDirectory(%s) %d: entries do not match, actual then expected", tt.path, i) - t.Log(entry) - t.Log(tt.entries[i]) + t.Log(cmp.Diff(*entry, *tt.entries[i], cmp.AllowUnexported(directoryEntry{}))) } } } @@ -274,11 +275,11 @@ func TestFat32ReadDirWithMkdir(t *testing.T) { if err != nil { t.Fatalf("unable to read data from file %s: %v", Fat32File, err) } - validDe, _, err := getValidDirectoryEntries() + validDe, _, err := GetValidDirectoryEntries() if err != nil { t.Fatalf("unable to read valid directory entries: %v", err) } - validDeLong, _, err := getValidDirectoryEntriesExtended() + validDeLong, _, err := GetValidDirectoryEntriesExtended("/foo") if err != nil { t.Fatalf("unable to read valid directory entries extended: %v", err) } @@ -321,6 +322,7 @@ func TestFat32ReadDirWithMkdir(t *testing.T) { for _, tt := range tests { fs.file = &testhelper.FileImpl{ + //nolint:revive // unused parameter, keeping name makes it easier to use in the future Writer: func(b []byte, offset int64) (int, error) { return len(b), nil }, diff --git a/filesystem/fat32/fat32_test.go b/filesystem/fat32/fat32_test.go index 3217f431..62c6e3ad 100644 --- a/filesystem/fat32/fat32_test.go +++ b/filesystem/fat32/fat32_test.go @@ -297,6 +297,17 @@ func TestFat32ReadDir(t *testing.T) { } else { fmt.Println(f.Name()) } + // determine entries from the actual data + rootEntries, _, err := fat32.GetValidDirectoryEntries() + if err != nil { + t.Fatalf("error getting valid directory entries: %v", err) + } + // ignore volume entry when public-facing root entries + rootEntries = rootEntries[:len(rootEntries)-1] + fooEntries, _, err := fat32.GetValidDirectoryEntriesExtended("/foo") + if err != nil { + t.Fatalf("error getting valid directory entries for /foo: %v", err) + } tests := []struct { path string count int @@ -304,20 +315,8 @@ func TestFat32ReadDir(t *testing.T) { isDir bool err error }{ - // should have 4 entries (Volume Label is not returned) - // foo - // TERCER~1 - // CORTO1.TXT - // UNARCH~1.DAT - {"/", 4, "foo", true, nil}, - // should have 80 entries: - // dir0-75 = 76 entries - // dir = 1 entry - // bar = 1 entry - // . = 1 entry - // .. = 1 entry - // total = 80 entries - {"/foo", 80, ".", true, nil}, + {"/", len(rootEntries), "foo", true, nil}, + {"/foo", len(fooEntries), ".", true, nil}, // 0 entries because the directory does not exist {"/a/b/c", 0, "", false, fmt.Errorf("error reading directory /a/b/c")}, } diff --git a/filesystem/fat32/fileinfo.go b/filesystem/fat32/fileinfo.go index ca0b1b26..cf319ac1 100644 --- a/filesystem/fat32/fileinfo.go +++ b/filesystem/fat32/fileinfo.go @@ -17,16 +17,22 @@ type FileInfo struct { } // IsDir abbreviation for Mode().IsDir() +// +//nolint:gocritic // we need this to comply with fs.FileInfo func (fi FileInfo) IsDir() bool { return fi.isDir } // ModTime modification time +// +//nolint:gocritic // we need this to comply with fs.FileInfo func (fi FileInfo) ModTime() time.Time { return fi.modTime } // Mode returns file mode +// +//nolint:gocritic // we need this to comply with fs.FileInfo func (fi FileInfo) Mode() os.FileMode { return fi.mode } @@ -34,6 +40,8 @@ func (fi FileInfo) Mode() os.FileMode { // Name base name of the file // // will return the long name of the file. If none exists, returns the shortname and extension +// +//nolint:gocritic // we need this to comply with fs.FileInfo func (fi FileInfo) Name() string { if fi.name != "" { return fi.name @@ -42,16 +50,22 @@ func (fi FileInfo) Name() string { } // ShortName just the 8.3 short name of the file +// +//nolint:gocritic // we need this to comply with fs.FileInfo func (fi FileInfo) ShortName() string { return fi.shortName } // Size length in bytes for regular files +// +//nolint:gocritic // we need this to comply with fs.FileInfo func (fi FileInfo) Size() int64 { return fi.size } // Sys underlying data source - not supported yet and so will return nil +// +//nolint:gocritic // we need this to comply with fs.FileInfo func (fi FileInfo) Sys() interface{} { return nil } diff --git a/filesystem/fat32/fsinfosector_internal_test.go b/filesystem/fat32/fsinfosector_internal_test.go index a6cdb39c..ced877ab 100644 --- a/filesystem/fat32/fsinfosector_internal_test.go +++ b/filesystem/fat32/fsinfosector_internal_test.go @@ -10,8 +10,8 @@ import ( func getValidFSInfoSector() *FSInformationSector { return &FSInformationSector{ - freeDataClustersCount: 20007, - lastAllocatedCluster: 126, + freeDataClustersCount: fsInfo.freeSectorCount, + lastAllocatedCluster: fsInfo.nextFreeSector, } } diff --git a/filesystem/fat32/table_internal_test.go b/filesystem/fat32/table_internal_test.go index 50e1cf07..119f05ff 100644 --- a/filesystem/fat32/table_internal_test.go +++ b/filesystem/fat32/table_internal_test.go @@ -3,8 +3,10 @@ package fat32 import ( "bytes" "os" - "sort" "testing" + + "github.com/diskfs/go-diskfs/util" + "github.com/google/go-cmp/cmp" ) const ( @@ -13,147 +15,16 @@ const ( ) func getValidFat32Table() *table { - sectorsPerFat := 158 // 158 sectors per FAT given in DOS20BPB - sizeInBytes := sectorsPerFat * 512 // 512 bytes per sector, - numClusters := sizeInBytes / 4 - // table as read from fat32.img using - // xxd -c 4 ./testdata/fat32.img - // directory "\" is at cluster 2 (first data cluster) at byte 0x02b800 = 178176 - // directory "\foo" is at cluster 3 (second data cluster) - return &table{ - fatID: 268435448, // 0x0ffffff8 - eocMarker: eoc, // 0x0fffffff - clusters: map[uint32]uint32{ - 2: eocMin, - 3: 60, - 4: eoc, - 5: 6, - 6: 7, - 7: 8, - 8: 9, - 9: 10, - 10: 11, - 11: 12, - 12: 13, - 13: 14, - 14: 15, - 15: 16, - 16: eoc, - 17: eoc, - 18: 19, - 19: 20, - 20: 21, - 21: 22, - 22: 23, - 23: 24, - 24: 25, - 25: 26, - 26: 27, - 27: 28, - 28: 29, - 29: 30, - 30: 31, - 31: eoc, - 32: 33, - 33: 34, - 34: 35, - 35: 36, - 36: 37, - 37: 38, - 38: 39, - 39: 40, - 40: 41, - 41: 42, - 42: 43, - 43: 44, - 44: 45, - 45: eoc, - 46: eoc, - 47: eoc, - 48: eoc, - 49: eoc, - 50: eoc, - 51: eoc, - 52: eoc, - 53: eoc, - 54: eoc, - 55: eoc, - 56: eoc, - 57: eoc, - 58: eoc, - 59: eoc, - 60: 77, - 61: eoc, - 62: eoc, - 63: eoc, - 64: eoc, - 65: eoc, - 66: eoc, - 67: eoc, - 68: eoc, - 69: eoc, - 70: eoc, - 71: eoc, - 72: eoc, - 73: eoc, - 74: eoc, - 75: eoc, - 76: eoc, - 77: 94, - 78: eoc, - 79: eoc, - 80: eoc, - 81: eoc, - 82: eoc, - 83: eoc, - 84: eoc, - 85: eoc, - 86: eoc, - 87: eoc, - 88: eoc, - 89: eoc, - 90: eoc, - 91: eoc, - 92: eoc, - 93: eoc, - 94: 111, - 95: eoc, - 96: eoc, - 97: eoc, - 98: eoc, - 99: eoc, - 100: eoc, - 101: eoc, - 102: eoc, - 103: eoc, - 104: eoc, - 105: eoc, - 106: eoc, - 107: eoc, - 108: eoc, - 109: eoc, - 110: eoc, - 111: eoc, - 112: eoc, - 113: eoc, - 114: eoc, - 115: eoc, - 116: eoc, - 117: eoc, - 118: eoc, - 119: eoc, - 120: eoc, - 121: eoc, - 122: eoc, - 123: eoc, - 124: eoc, - 125: eoc, - 126: eoc, - }, - rootDirCluster: 2, - size: uint32(sizeInBytes), - maxCluster: uint32(numClusters), + // make a duplicate, in case someone modifies what we return + var t = &table{} + *t = *fsInfo.table + // and because the clusters are copied by reference + t.clusters = make(map[uint32]uint32) + for k, v := range fsInfo.table.clusters { + t.clusters[k] = v } + + return t } func TestFat32TableFromBytes(t *testing.T) { @@ -162,25 +33,15 @@ func TestFat32TableFromBytes(t *testing.T) { if err != nil { t.Fatalf("error reading test fixture data from %s: %v", Fat32File, err) } - b := input[16384 : 158*512+16384] - table := tableFromBytes(b) - if table == nil { + b := input[fsInfo.firstFAT : fsInfo.firstFAT+fsInfo.sectorsPerFAT*fsInfo.bytesPerSector] + result := tableFromBytes(b) + if result == nil { t.Fatalf("returned FAT32 Table was nil unexpectedly") } valid := getValidFat32Table() - if !table.equal(valid) { - keys := make([]uint32, 0) - for _, k := range valid.clusters { - keys = append(keys, k) - } - sort.Slice(keys, func(i, j int) bool { return keys[i] < keys[j] }) - t.Log(keys) - keys = make([]uint32, 0) - for _, k := range table.clusters { - keys = append(keys, k) - } - sort.Slice(keys, func(i, j int) bool { return keys[i] < keys[j] }) - t.Log(keys) + if !result.equal(valid) { + diff := cmp.Diff(result, valid, cmp.AllowUnexported(table{})) + t.Log(diff) t.Fatalf("Mismatched FAT32 Table") } }) @@ -197,9 +58,10 @@ func TestFat32TableToBytes(t *testing.T) { if err != nil { t.Fatalf("error reading test fixture data from %s: %v", Fat32File, err) } - validBytes := valid[16384 : 158*512+16384] + validBytes := valid[fsInfo.firstFAT : fsInfo.firstFAT+fsInfo.sectorsPerFAT*fsInfo.bytesPerSector] if !bytes.Equal(validBytes, b) { - t.Error("Mismatched bytes") + _, diffString := util.DumpByteSlicesWithDiffs(validBytes, b, 32, false, true, true) + t.Errorf("directory.toBytes() mismatched, actual then expected\n%s", diffString) } }) } diff --git a/filesystem/fat32/testdata/.gitignore b/filesystem/fat32/testdata/.gitignore new file mode 100644 index 00000000..849ddff3 --- /dev/null +++ b/filesystem/fat32/testdata/.gitignore @@ -0,0 +1 @@ +dist/ diff --git a/filesystem/fat32/testdata/README.md b/filesystem/fat32/testdata/README.md index 7ae1a654..ec6acd14 100644 --- a/filesystem/fat32/testdata/README.md +++ b/filesystem/fat32/testdata/README.md @@ -1,49 +1,20 @@ # FAT32 Test Fixtures This directory contains test fixtures for FAT32 filesystems. Specifically, it contains the following files: -* `fat32.img`: A 10MB filesystem img -* `calcsfn_checksum.c`: A C program that generates correct short filename checksums +* `calcsfn_checksum.c`: A C program that generates correct short filename checksums. +* `fat32.go`: A Go program that creates a basic filesystem; see below. -To generate the `fat32.img`, based roughly on https://commons.wikimedia.org/wiki/File:VFAT_directory_entries.png : +All of the actual test artifacts are in `dist/`, which is excluded from version control +via `.gitignore` in this directory. -``` -$ docker run -it --rm -v $PWD:/data alpine:3.6 -# apk --update add dosfstools mtools -# dd if=/dev/zero of=/data/fat32.img bs=1M count=10 -# mkfs.vfat -v -F 32 /data/fat32.img -# echo "mtools_skip_check=1" >> /etc/mtools.conf -# mmd -i /data/fat32.img ::/foo -# mmd -i /data/fat32.img ::/foo/bar -# echo 'Tenemos un archivo corto' > /CORTO1.TXT -# dd if=/dev/zero 'of=/Un archivo con nombre largo.dat' bs=1024 count=2 -# dd if=/dev/zero 'of=/tercer_archivo' bs=1024 count=6 -# dd if=/dev/zero 'of=/Un archivo con nombre largo.dat' bs=1024 count=7 -# dd if=/dev/zero 'of=/some_long_embedded_nameא' bs=1024 count=7 -# mcopy -i /data/fat32.img /CORTO1.TXT ::/ -# mcopy -i /data/fat32.img '/Un archivo con nombre largo.dat' ::/ -# mcopy -i /data/fat32.img '/tercer_archivo' ::/ -# mcopy -i /data/fat32.img '/Un archivo con nombre largo.dat' ::/ -# mcopy -i /data/fat32.img '/some_long_embedded_nameא' ::/foo/bar -# -# i=0 -# until [ $i -gt 75 ]; do mmd -i /data/fat32.img ::/foo/dir${i}; i=$(( $i+1 )); done - -# fatlabel /data/fat32.img go-diskfs -# exit -$ -``` - -We make the `\foo` directory with sufficient entries to exceed a single cluster. This allows us to test reading. Since each directory entry is 32 bytes, and a cluster is 4*512 = 2048 bytes, we need 2048/32 = 64 entries to fill the cluster and one more to get to the next one. - -You now have the exact fat32 files in `$PWD` - -**Note:** Certain data should be copied over to your "valid" test information in test files, notably: - -* volume serial number is generated by creation date/time; you cannot "pre-plan" it. Thus, it should be copied into the appropriate place in `getValidDos71EBPB()` [dos71bpb_test.go](../dos71bpb_test.go) -* free data cluster count, should be copied over to the appropriate place in `getValidFSInfoSector` [fsinfosector_test.go](../fsinfosector_test.go) -* last allocated cluster, should be copied over to the appropriate place in `getValidFSInfoSector` [fsinfosector_test.go](../fsinfosector_test.go) -* allocated FAT clusters +To generate the artifacts, run `mkfat32.sh`. This will generate a `fat32.img` file in the `dist/` +directory, as well as all sorts of information files about the filesystem and its contents, +generated using standard tooling. +The go tests for fat32 automatically generate those if `dist/fat32.img` is not there. +if it is and you need to regenerate it, you can run `mkfat32.sh` and then run the tests, +or just remove the `dist/` directory and it will regenerate everything the next time you run the +tests. ## Basic Builds In addition to the usual test harnesses, this directory contains a file that generates a basic fat32 filesystem. To build it: diff --git a/filesystem/fat32/testdata/fat32.img b/filesystem/fat32/testdata/fat32.img deleted file mode 100644 index 9443498fb8a1a041e46880d65f929867157fb0e5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10485760 zcmeF)Taz4R83*tVDuh4|$|>R4oR3+_fdGn_O$dTOg3AWM17VYFk~PUr++DyRru+b2 z_zA4?N~QEl@2s-?0#tcpl^?*n+<3{A@#%SIdS)kY7gQK4TRp$6JlnJT%=C2s{?oHF z-EXEZzV+*~r%x8#8hJu_cc^O!2j*U!w)Ezg$=i_7y%tNJI-bk3bSU(PKa z-?-u2(){vrTs&W%ob=$xEeSS+Werpk>QRxPI=asr1xo|&1O&UO5*JpxNh z({m3WEQ$-4t!YgwNqX_jx7L*S_HG ztNVOs4D;xWVIEhq{=>J4Mes#{009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5)GL4i*%UD|vps+v9*%U4~#Hm27_t&h4sYD3fwQ8z|yjM@~nIciH(b^WStipw`g z-4bfh&;Okewgx3BK=oiWU#GlqFw$@&l9CKkaL0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyum%NQJank+eQjA^{Qmh5U-|HrqC5RkcWL)^VsfebwYhjZ zT}a>4uh*><^TkqeEWSs7sW?*1b$>h+H(My)FJ=$S>_0GbVMlczMRD)mH2-S)m7>^M z6#Ea&%pQvF>|3+Z-_`3^)2|lWVjlZD#Z+-TX1Wsd|8sv)swGI5uURb0VzKBHXRH3v zxbOM+#hJK45tmOE>kdb^>@HOFj}@o7OVx>A6|vBr;_$)gnf)(a*zv-2b^m*M_g_uF zRup#@#mUb0;|t5DPb`<^`l9&fuMQqQcsNaC1}*rS>Zf0pTTw){XO~qQ~mza`Tm}M|CxOM>3;v&eE*q#e@72+ z#OK+%-vb=!f1}$U#9QTmd48+&AMW>_ALe80JRTd}@!0;}JrWz+Tx^Q-#Xn;6uC~y1 z%iV2rKAsq&eEYFc);ziKYN2oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjX*zrgJL;{4gpa{1n3Ik$A|)WZ9n@>pkSrL*Dl&%!kc z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0tCh=u=?{qFaLbj)t~=4+)tnXImSgXtE(WeI{(W*e|L5M!+rT*g}BCk zm(BU7&sUcJ*vZ$_44d;$pPw!NH5J#`7p6J?^!e!WA3OP)nqhPP>GSX9zoz0E`@%Hm zpU!U}|FM&=sTnrspUz()|1}lY*cYZb|8#y5`H!7^P0g@5|8)Kt`LC(C#=bDk`KR*> z$$#wRYifqg`KR+o$$w47HTH#R&cAnlu)!7L{9yL~jy-^@Ji|e})%o9s^ZjOb$!z~u zIiUaZ-N*SEcl1u6IC6f#lz-Lloj`G<|E=zlRsG%x6i52c*ZtlJ6i52suKT?cD30{^ z*8ScI6i52gb-#B4#gYELy5Bp2;z)mgzrQno{=^sRe*XN42kL&_@5Q>G_xn!W&-=Yp z_w#-)*ZsWTck6!MFHXZ5U(MTp%GdVaWoqrW=KRz4EC1F;-(9ih{L}NZ{3kX4z3K5W zcz}$&J~aNL4UddLyrZxG)9WkSe;ZP6UWexV)9YvXH`}$L)0}^Les5VE=C$0v}n2LA;~;e_!oh)Am0C*0LXC z{Kn4w_=%K%)z6QgIM|hl{;vG^i9>ZiKYrr%x}P6E@x8jAA3rfu_w(Z?-l+Te@e{Lk zKR`%n4W{<}=A z{nng++J5EV+UP%H`%ll$@}JcF)8AkDPip?@^_Bc5HUISbS^krne|mo;|4Ge1z5kW} zq~@RYZ^(aA^H2M)JB9@e?Wks-GV}ailw!s-GV}@owGEkDr*U`}y$` zN9%rm{KT<-|Ec`=iQ{!YKYn7q?&rr(oT&Tx@e?QOe%|j?-Ou|i)cw5QPwIZ&?{wYI z`<X>$`u9IQKimFW82ZpEHRqrH z{>py{tA!Vv^G~m@tx|LTY5%kQhp<|Bu{r;Ad_n## z41H*on)6S`kK{ju)xwL-`S*?w4zA$%&qU?F*j-!Oe+xq&TBR7ju_r%%BIRH8^W!JZ zb>~v`^W!IeTKDtgCzk4de*DC8-OrDoSgHH@@e}XW{rvce_v?Os{KN-!KRu32-YX0f{k^Cn$|MdP>{*#)2+P@+HNzFg) zzmor?=AZUY%70SxPy3(cKdJer;|ubi)cn)&Bl%Bi{=MUag9Ajyf3*9dVC@JHAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0tEiY4jl*p00000`M)+of&&K*95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*AcIZF`0001BkiYdkzCy@=0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM a7%*VKfB^#r3>YwAz<>b*1`HT5Fc}ECrVbYX diff --git a/filesystem/fat32/testdata/mkfat32.sh b/filesystem/fat32/testdata/mkfat32.sh index da35aabc..b235e2bf 100755 --- a/filesystem/fat32/testdata/mkfat32.sh +++ b/filesystem/fat32/testdata/mkfat32.sh @@ -1,20 +1,89 @@ #!/bin/sh set -e -set +x +set -x -cat <<"EOF" | docker run -i --rm -v $PWD:/data alpine:3.8 +INSTALLDIR="$1" + +if [ -z "$INSTALLDIR" ]; then + INSTALLDIR="$PWD" +fi + +mkdir -p $INSTALLDIR/dist +cat <<"EOF" | docker run -i --rm -v $INSTALLDIR/dist:/data alpine:3.20 set -e -set +x -apk --update add mtools dosfstools -mkfs.vfat -F 32 -v -C /tmp/boot.img 10000 -mmd -i /tmp/boot.img ::/A -mmd -i /tmp/boot.img ::/b -echo testfile > testfile -echo sub > sub -dd if=/dev/random of=large bs=1M count=5 -mcopy -i /tmp/boot.img testfile ::/ -mcopy -i /tmp/boot.img sub ::/b -mcopy -i /tmp/boot.img large ::/b -cp /tmp/boot.img /data -EOF +set -x + +apk --update add dosfstools mtools sleuthkit +dd if=/dev/zero of=/data/fat32.img bs=1M count=10 +mkfs.vfat -v -F 32 /data/fat32.img +echo "mtools_skip_check=1" >> /etc/mtools.conf +mmd -i /data/fat32.img ::/foo +mmd -i /data/fat32.img ::/foo/bar +echo 'Tenemos un archivo corto' > /CORTO1.TXT +dd if=/dev/zero 'of=/Un archivo con nombre largo.dat' bs=1024 count=2 +dd if=/dev/zero 'of=/tercer_archivo' bs=1024 count=6 +dd if=/dev/zero 'of=/Un archivo con nombre largo.dat' bs=1024 count=7 +dd if=/dev/zero 'of=/some_long_embedded_nameא' bs=1024 count=7 +mcopy -i /data/fat32.img /CORTO1.TXT ::/ +mcopy -i /data/fat32.img '/Un archivo con nombre largo.dat' ::/ +mcopy -i /data/fat32.img '/tercer_archivo' ::/ +mcopy -i /data/fat32.img '/some_long_embedded_nameא' ::/foo/bar + +i=0 +until [ $i -gt 75 ]; do mmd -i /data/fat32.img ::/foo/dir${i}; i=$(( $i+1 )); done + +fatlabel /data/fat32.img go-diskfs + +# now get the information we need to build the testdata +# root dir info +mdir -a -i /data/fat32.img ::/ > /data/root_dir.txt +fls -f fat32 -p /data/fat32.img > /data/root_dir_fls.txt +i=0 +cat /data/root_dir_fls.txt | while read line; do + if [ -z "$line" ]; then + continue + fi + type=$(echo $line | awk '{print $1}') + if [ "$type" != "r/r" -a "$type" != "d/d" ]; then + continue + fi + inode=$(echo $line | awk '{print $2}') + # remove a trailing : + inode=${inode%:} + # save the istat info per the order in the directory, so we can find it later + istat -f fat32 /data/fat32.img $inode > /data/root_dir_istat_${i}.txt + i=$(( $i+1 )) +done + +# foo dir info +# usual mdir info is helpful +mdir -a -i /data/fat32.img ::/foo/ > /data/foo_dir.txt +# to use fls to list the references, first, find the "inode" of /foo/ +foo_inode=$(awk '$3 == "foo" {print $2}' /data/root_dir_fls.txt | tr -d ':') +fls -f fat32 -p /data/fat32.img $foo_inode > /data/foo_dir_fls.txt +i=0 +cat /data/foo_dir_fls.txt | while read line; do + if [ -z "$line" ]; then + continue + fi + type=$(echo $line | awk '{print $1}') + if [ "$type" != "r/r" -a "$type" != "d/d" ]; then + continue + fi + inode=$(echo $line | awk '{print $2}') + # remove a trailing : + inode=${inode%:} + # save the istat info per the order in the directory, so we can find it later + istat -f fat32 /data/fat32.img $inode > /data/foo_dir_istat_${i}.txt + i=$(( $i+1 )) +done + +dosfsck -v -l /data/fat32.img > /data/fsck.txt + +fsstat -f fat32 /data/fat32.img > /data/fsstat.txt + +# get the serial number +dd if=/data/fat32.img bs=1 skip=67 count=4 2>/dev/null| hexdump -e '4/1 "%02x"' > /data/serial.txt + +EOF diff --git a/go.mod b/go.mod index 4516a458..c3fd0694 100644 --- a/go.mod +++ b/go.mod @@ -14,4 +14,7 @@ require ( golang.org/x/sys v0.5.0 ) -require github.com/klauspost/compress v1.17.4 +require ( + github.com/google/go-cmp v0.6.0 + github.com/klauspost/compress v1.17.4 +) diff --git a/go.sum b/go.sum index 52b0b56d..ebd27995 100644 --- a/go.sum +++ b/go.sum @@ -7,6 +7,8 @@ github.com/elliotwutingfeng/asciiset v0.0.0-20230602022725-51bbb787efab h1:h1Ugj github.com/elliotwutingfeng/asciiset v0.0.0-20230602022725-51bbb787efab/go.mod h1:GLo/8fDswSAniFG+BFIaiSPcK610jyzgEhWYPQwuQdw= github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= From 7cda4ac30c647181efa869a80386b60a7fccacf7 Mon Sep 17 00:00:00 2001 From: Avi Deitcher Date: Sun, 1 Sep 2024 22:16:14 +0300 Subject: [PATCH 2/4] bump linter Signed-off-by: Avi Deitcher --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 24bbc2f4..40325898 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ GOENV ?= GO111MODULE=on CGO_ENABLED=0 GO_FILES ?= $(shell $(GOENV) go list ./...) GOBIN ?= $(shell go env GOPATH)/bin LINTER ?= $(GOBIN)/golangci-lint -LINTER_VERSION ?= v1.55.2 +LINTER_VERSION ?= v1.59.0 # BUILDARCH is the host architecture # ARCH is the target architecture From ada4a2bd5a2c135dc33a8b2bdf82850d703bec9e Mon Sep 17 00:00:00 2001 From: Avi Deitcher Date: Sun, 1 Sep 2024 22:23:02 +0300 Subject: [PATCH 3/4] lint fixes Signed-off-by: Avi Deitcher --- filesystem/squashfs/lru_test.go | 1 + partition/gpt/partition_internal_test.go | 5 +++++ partition/gpt/table_test.go | 6 ++++++ partition/mbr/partition_internal_test.go | 5 +++++ partition/mbr/table_test.go | 6 ++++++ 5 files changed, 23 insertions(+) diff --git a/filesystem/squashfs/lru_test.go b/filesystem/squashfs/lru_test.go index 1b62e021..e72d4907 100644 --- a/filesystem/squashfs/lru_test.go +++ b/filesystem/squashfs/lru_test.go @@ -58,6 +58,7 @@ func TestLRU(t *testing.T) { assertEmpty(true) }) + //nolint:revive // t is unused, but it should be kept here for the signature t.Run("Unlink", func(t *testing.T) { assertEmpty(true) block := &lruBlock{ diff --git a/partition/gpt/partition_internal_test.go b/partition/gpt/partition_internal_test.go index 72758585..b423bed3 100644 --- a/partition/gpt/partition_internal_test.go +++ b/partition/gpt/partition_internal_test.go @@ -347,6 +347,7 @@ func TestWriteContents(t *testing.T) { reader := bytes.NewReader(b) expected := "error writing to file" f := &testhelper.FileImpl{ + //nolint:revive // b is unused, but we keep it here for the consistent io.Writer signatire Writer: func(b []byte, offset int64) (int, error) { return 0, errors.New(expected) }, @@ -379,6 +380,7 @@ func TestWriteContents(t *testing.T) { reader := bytes.NewReader(b) expected := "requested to write at least" f := &testhelper.FileImpl{ + //nolint:revive // b is unused, but we keep it here for the consistent io.Writer signatire Writer: func(b []byte, offset int64) (int, error) { return len(b), nil }, @@ -412,6 +414,7 @@ func TestWriteContents(t *testing.T) { b2 := make([]byte, 0, size) reader := bytes.NewReader(b) f := &testhelper.FileImpl{ + //nolint:revive // b is unused, but we keep it here for the consistent io.Writer signatire Writer: func(b []byte, offset int64) (int, error) { b2 = append(b2, b...) return len(b), nil @@ -447,6 +450,7 @@ func TestReadContents(t *testing.T) { writer := bufio.NewWriter(&b) expected := "error reading from file" f := &testhelper.FileImpl{ + //nolint:revive // b is unused, but we keep it here for the consistent io.Reader signatire Reader: func(b []byte, offset int64) (int, error) { return 0, errors.New(expected) }, @@ -477,6 +481,7 @@ func TestReadContents(t *testing.T) { b2 := make([]byte, size) _, _ = rand.Read(b2) f := &testhelper.FileImpl{ + //nolint:revive // b is unused, but we keep it here for the consistent io.Reader signatire Reader: func(b []byte, offset int64) (int, error) { copy(b, b2) return size, io.EOF diff --git a/partition/gpt/table_test.go b/partition/gpt/table_test.go index 2d10eb39..38592e54 100644 --- a/partition/gpt/table_test.go +++ b/partition/gpt/table_test.go @@ -106,6 +106,7 @@ func TestTableRead(t *testing.T) { t.Run("error reading file", func(t *testing.T) { expected := "error reading GPT from file" f := &testhelper.FileImpl{ + //nolint:revive // b is unused, but we keep it here for the consistent io.Reader signatire Reader: func(b []byte, offset int64) (int, error) { return 0, errors.New(expected) }, @@ -125,6 +126,7 @@ func TestTableRead(t *testing.T) { size := 100 expected := fmt.Sprintf("read only %d bytes of GPT", size) f := &testhelper.FileImpl{ + //nolint:revive // b is unused, but we keep it here for the consistent io.Reader signatire Reader: func(b []byte, offset int64) (int, error) { return size, nil }, @@ -165,6 +167,7 @@ func TestTableWrite(t *testing.T) { table := gpt.GetValidTable() expected := "error writing protective MBR to disk" f := &testhelper.FileImpl{ + //nolint:revive // b is unused, but we keep it here for the consistent io.Writer signatire Writer: func(b []byte, offset int64) (int, error) { return 0, errors.New(expected) }, @@ -181,6 +184,7 @@ func TestTableWrite(t *testing.T) { table := gpt.GetValidTable() var size int f := &testhelper.FileImpl{ + //nolint:revive // b is unused, but we keep it here for the consistent io.Writer signatire Writer: func(b []byte, offset int64) (int, error) { size = len(b) - 1 return size, nil @@ -420,6 +424,7 @@ func TestReadPartitionContents(t *testing.T) { b2 := make([]byte, size) _, _ = rand.Read(b2) f := &testhelper.FileImpl{ + //nolint:revive // b is unused, but we keep it here for the consistent io.Reader signatire Reader: func(b []byte, offset int64) (int, error) { copy(b, b2) return size, io.EOF @@ -448,6 +453,7 @@ func TestWritePartitionContents(t *testing.T) { reader := bytes.NewReader(b) b2 := make([]byte, 0, size) f := &testhelper.FileImpl{ + //nolint:revive // b is unused, but we keep it here for the consistent io.Writer signatire Writer: func(b []byte, offset int64) (int, error) { b2 = append(b2, b...) return len(b), nil diff --git a/partition/mbr/partition_internal_test.go b/partition/mbr/partition_internal_test.go index 92c50810..6f6cde22 100644 --- a/partition/mbr/partition_internal_test.go +++ b/partition/mbr/partition_internal_test.go @@ -145,6 +145,7 @@ func TestReadContents(t *testing.T) { writer := bufio.NewWriter(&b) expected := "error reading from file" f := &testhelper.FileImpl{ + //nolint:revive // b is unused, but we keep it here for the consistent io.Reader signatire Reader: func(b []byte, offset int64) (int, error) { return 0, errors.New(expected) }, @@ -179,6 +180,7 @@ func TestReadContents(t *testing.T) { b2 := make([]byte, size) _, _ = rand.Read(b2) f := &testhelper.FileImpl{ + //nolint:revive // b is unused, but we keep it here for the consistent io.Reader signatire Reader: func(b []byte, offset int64) (int, error) { copy(b, b2) return size, io.EOF @@ -248,6 +250,7 @@ func TestWriteContents(t *testing.T) { reader := bytes.NewReader(b) expected := "error writing to file" f := &testhelper.FileImpl{ + //nolint:revive // b is unused, but we keep it here for the consistent io.Writer signatire Writer: func(b []byte, offset int64) (int, error) { return 0, errors.New(expected) }, @@ -283,6 +286,7 @@ func TestWriteContents(t *testing.T) { reader := bytes.NewReader(b) expected := "requested to write at least" f := &testhelper.FileImpl{ + //nolint:revive // b is unused, but we keep it here for the consistent io.Writer signatire Writer: func(b []byte, offset int64) (int, error) { return len(b), nil }, @@ -323,6 +327,7 @@ func TestWriteContents(t *testing.T) { b2 := make([]byte, 0, size) reader := bytes.NewReader(b) f := &testhelper.FileImpl{ + //nolint:revive // b is unused, but we keep it here for the consistent io.Writer signatire Writer: func(b []byte, offset int64) (int, error) { b2 = append(b2, b...) return len(b), nil diff --git a/partition/mbr/table_test.go b/partition/mbr/table_test.go index 5336e7f9..285f7ead 100644 --- a/partition/mbr/table_test.go +++ b/partition/mbr/table_test.go @@ -99,6 +99,7 @@ func TestTableRead(t *testing.T) { t.Run("error reading file", func(t *testing.T) { expected := "error reading MBR from file" f := &testhelper.FileImpl{ + //nolint:revive // b is unused, but we keep it here for the consistent io.Reader signatire Reader: func(b []byte, offset int64) (int, error) { return 0, errors.New(expected) }, @@ -118,6 +119,7 @@ func TestTableRead(t *testing.T) { size := 100 expected := fmt.Sprintf("read only %d bytes of MBR", size) f := &testhelper.FileImpl{ + //nolint:revive // b is unused, but we keep it here for the consistent io.Reader signatire Reader: func(b []byte, offset int64) (int, error) { return size, nil }, @@ -157,6 +159,7 @@ func TestTableWrite(t *testing.T) { table := mbr.GetValidTable() expected := "error writing partition table to disk" f := &testhelper.FileImpl{ + //nolint:revive // b is unused, but we keep it here for the consistent io.Writer signatire Writer: func(b []byte, offset int64) (int, error) { return 0, errors.New(expected) }, @@ -173,6 +176,7 @@ func TestTableWrite(t *testing.T) { table := mbr.GetValidTable() var size int f := &testhelper.FileImpl{ + //nolint:revive // b is unused, but we keep it here for the consistent io.Writer signatire Writer: func(b []byte, offset int64) (int, error) { size = len(b) - 1 return size, nil @@ -370,6 +374,7 @@ func TestReadPartitionContents(t *testing.T) { b2 := make([]byte, size) _, _ = rand.Read(b2) f := &testhelper.FileImpl{ + //nolint:revive // b is unused, but we keep it here for the consistent io.Reader signatire Reader: func(b []byte, offset int64) (int, error) { copy(b, b2) return size, io.EOF @@ -398,6 +403,7 @@ func TestWritePartitionContents(t *testing.T) { reader := bytes.NewReader(b) b2 := make([]byte, 0, size) f := &testhelper.FileImpl{ + //nolint:revive // b is unused, but we keep it here for the consistent io.Writer signatire Writer: func(b []byte, offset int64) (int, error) { b2 = append(b2, b...) return len(b), nil From c4d6f4ec9a9d9b0d84225aacfa3015a6341e58f8 Mon Sep 17 00:00:00 2001 From: Avi Deitcher Date: Sun, 1 Sep 2024 22:25:48 +0300 Subject: [PATCH 4/4] fix high-level disk test Signed-off-by: Avi Deitcher --- disk/disk_test.go | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/disk/disk_test.go b/disk/disk_test.go index 7e6ef640..990be177 100644 --- a/disk/disk_test.go +++ b/disk/disk_test.go @@ -10,6 +10,8 @@ import ( "crypto/rand" "fmt" "os" + "os/exec" + "path" "strings" "testing" @@ -57,11 +59,11 @@ func tmpDisk(source string) (*os.File, error) { func TestGetPartitionTable(t *testing.T) { // this just calls partition.Read, so no need to do much more than a single test and see that it exercises it - path := "../partition/mbr/testdata/mbr.img" + imgPath := "../partition/mbr/testdata/mbr.img" tableType := "mbr" - f, err := os.Open(path) + f, err := os.Open(imgPath) if err != nil { - t.Errorf("Failed to open file %s :%v", path, err) + t.Errorf("Failed to open file %s :%v", imgPath, err) } // be sure to close the file @@ -577,7 +579,19 @@ func TestGetFilesystem(t *testing.T) { } }) t.Run("whole disk", func(t *testing.T) { - f, err := tmpDisk("../filesystem/fat32/testdata/fat32.img") + tmpDir := t.TempDir() + // Run the genartifacts.sh script + cmd := exec.Command("sh", "mkfat32.sh", tmpDir) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + cmd.Dir = "../filesystem/fat32/testdata" + + // Execute the command + if err := cmd.Run(); err != nil { + t.Fatalf("error generating fat32 test artifact for disk test: %v", err) + } + + f, err := tmpDisk(path.Join(tmpDir, "dist", "fat32.img")) if err != nil { t.Fatalf("error creating new temporary disk: %v", err) }