From ade4b611555898d83fbfe0f590c33c3b9cc7957e Mon Sep 17 00:00:00 2001 From: leo Date: Thu, 11 Sep 2014 19:55:34 +0000 Subject: [PATCH] Added builtin library as a zip file. --- common/lc_application.cpp | 10 +- common/lc_category.cpp | 2 + common/lc_file.cpp | 11 ++ common/lc_file.h | 2 + common/lc_library.cpp | 398 +++++--------------------------------- common/lc_library.h | 7 +- common/lc_zipfile.cpp | 13 ++ common/lc_zipfile.h | 3 +- common/pieceinf.cpp | 4 +- common/pieceinf.h | 1 - leocad.qrc | 1 + resources/library.zip | Bin 0 -> 47780 bytes 12 files changed, 91 insertions(+), 361 deletions(-) create mode 100644 resources/library.zip diff --git a/common/lc_application.cpp b/common/lc_application.cpp index dae76f90..5809bfa9 100644 --- a/common/lc_application.cpp +++ b/common/lc_application.cpp @@ -248,10 +248,12 @@ bool lcApplication::Initialize(int argc, char* argv[], const char* LibraryInstal return false; } - mLibrary->CreateBuiltinPieces(); - - gMainWindow->DoMessageBox("LeoCAD could not find a compatible Pieces Library so only a small number of pieces will be available.\n\n" - "Please visit http://www.leocad.org for information on how to download and install a library.", LC_MB_OK | LC_MB_ICONERROR); + if (mLibrary->LoadBuiltinPieces()) + gMainWindow->DoMessageBox("LeoCAD could not find a compatible Parts Library so only a small number of parts will be available.\n\n" + "Please visit http://www.leocad.org for information on how to download and install a library.", LC_MB_OK | LC_MB_ICONERROR); + else + gMainWindow->DoMessageBox("LeoCAD could not load Parts Library.\n\n" + "Please visit http://www.leocad.org for information on how to download and install a library.", LC_MB_OK | LC_MB_ICONERROR); } // Create a new project. diff --git a/common/lc_category.cpp b/common/lc_category.cpp index 1aedae13..ff014c27 100644 --- a/common/lc_category.cpp +++ b/common/lc_category.cpp @@ -74,6 +74,8 @@ void lcResetCategories(lcArray& Categories, bool BuiltInLibra "Baseplate=^%Baseplate\n" "Brick=^%Brick\n" "Plate=^%Plate\n" + "Slope=^%Slope\n" + "Tile=^%Tile\n" }; lcMemFile File; diff --git a/common/lc_file.cpp b/common/lc_file.cpp index 52062d71..b6af3561 100644 --- a/common/lc_file.cpp +++ b/common/lc_file.cpp @@ -186,6 +186,17 @@ void lcMemFile::CopyFrom(lcFile& Source) Source.ReadBuffer(mBuffer, Length); } +void lcMemFile::CopyFrom(lcMemFile& Source) +{ + size_t Length = Source.GetLength(); + + SetLength(Length); + Seek(0, SEEK_SET); + + Source.Seek(0, SEEK_SET); + Source.ReadBuffer(mBuffer, Length); +} + // ============================================================================= // lcDiskFile diff --git a/common/lc_file.h b/common/lc_file.h index 256bc347..4ef92d13 100644 --- a/common/lc_file.h +++ b/common/lc_file.h @@ -37,6 +37,7 @@ public: virtual size_t ReadBuffer(void* Buffer, long Bytes) = 0; virtual size_t WriteBuffer(const void* Buffer, long Bytes) = 0; + virtual void CopyFrom(lcMemFile& Source) = 0; lcuint8 ReadU8() { @@ -457,6 +458,7 @@ public: size_t WriteBuffer(const void* Buffer, long Bytes); void CopyFrom(lcFile& Source); + void CopyFrom(lcMemFile& Source); void GrowFile(size_t NewLength); size_t mGrowBytes; diff --git a/common/lc_library.cpp b/common/lc_library.cpp index 7925307f..2d54ac3b 100644 --- a/common/lc_library.cpp +++ b/common/lc_library.cpp @@ -144,10 +144,23 @@ bool lcPiecesLibrary::Load(const char* LibraryPath, const char* CachePath) } bool lcPiecesLibrary::OpenArchive(const char* FileName, lcZipFileType ZipFileType) +{ + lcDiskFile* File = new lcDiskFile(); + + if (!File->Open(FileName, "rb") || !OpenArchive(File, FileName, ZipFileType)) + { + delete File; + return false; + } + + return true; +} + +bool lcPiecesLibrary::OpenArchive(lcFile* File, const char* FileName, lcZipFileType ZipFileType) { lcZipFile* ZipFile = new lcZipFile(); - if (!ZipFile->OpenRead(FileName)) + if (!ZipFile->OpenRead(File)) { delete ZipFile; return false; @@ -1975,363 +1988,54 @@ void lcPiecesLibrary::GetPatternedPieces(PieceInfo* Parent, lcArray& } } -void lcPiecesLibrary::CreateBuiltinPieces() +bool lcPiecesLibrary::LoadBuiltinPieces() { - const char* Pieces[][2] = + QResource Resource(":/resources/library.zip"); + + if (!Resource.isValid()) + return false; + + lcMemFile* File = new lcMemFile(); + File->WriteBuffer(Resource.data(), Resource.size()); + + if (!OpenArchive(File, "builtin", LC_ZIPFILE_OFFICIAL)) { - { "3005", "Brick 1 x 1" }, - { "3004", "Brick 1 x 2" }, - { "3622", "Brick 1 x 3" }, - { "3010", "Brick 1 x 4" }, - { "3009", "Brick 1 x 6" }, - { "3008", "Brick 1 x 8" }, - { "6111", "Brick 1 x 10" }, - { "6112", "Brick 1 x 12" }, - { "2465", "Brick 1 x 16" }, - { "3003", "Brick 2 x 2" }, - { "3002", "Brick 2 x 3" }, - { "3001", "Brick 2 x 4" }, - { "2456", "Brick 2 x 6" }, - { "3007", "Brick 2 x 8" }, - { "3006", "Brick 2 x 10" }, - { "2356", "Brick 4 x 6" }, - { "6212", "Brick 4 x 10" }, - { "4202", "Brick 4 x 12" }, - { "30400", "Brick 4 x 18" }, - { "4201", "Brick 8 x 8" }, - { "4204", "Brick 8 x 16" }, - { "733", "Brick 10 x 10" }, - { "3024", "Plate 1 x 1" }, - { "3023", "Plate 1 x 2" }, - { "3623", "Plate 1 x 3" }, - { "3710", "Plate 1 x 4" }, - { "3666", "Plate 1 x 6" }, - { "3460", "Plate 1 x 8" }, - { "4477", "Plate 1 x 10" }, - { "60479", "Plate 1 x 12" }, - { "3022", "Plate 2 x 2" }, - { "3021", "Plate 2 x 3" }, - { "3020", "Plate 2 x 4" }, - { "3795", "Plate 2 x 6" }, - { "3034", "Plate 2 x 8" }, - { "3832", "Plate 2 x 10" }, - { "2445", "Plate 2 x 12" }, - { "91988", "Plate 2 x 14" }, - { "4282", "Plate 2 x 16" }, - { "3031", "Plate 4 x 4" }, - { "3032", "Plate 4 x 6" }, - { "3035", "Plate 4 x 8" }, - { "3030", "Plate 4 x 10" }, - { "3029", "Plate 4 x 12" }, - { "3958", "Plate 6 x 6" }, - { "3036", "Plate 6 x 8" }, - { "3033", "Plate 6 x 10" }, - { "3028", "Plate 6 x 12" }, - { "3456", "Plate 6 x 14" }, - { "3027", "Plate 6 x 16" }, - { "3026", "Plate 6 x 24" }, - { "41539", "Plate 8 x 8" }, - { "728", "Plate 8 x 11" }, - { "92438", "Plate 8 x 16" }, - { "819", "Baseplate 8 x 12" }, - { "3865", "Baseplate 8 x 16" }, - { "3497", "Baseplate 8 x 24" }, - { "4187", "Baseplate 8 x 32" }, - { "397", "Baseplate 10 x 16" }, - { "3867", "Baseplate 16 x 16" }, - { "184", "Baseplate 16 x 18" }, - { "210", "Baseplate 16 x 22" }, - { "3334", "Baseplate 16 x 24" }, - { "10", "Baseplate 24 x 32" }, - { "3645", "Baseplate 24 x 40" }, - { "3811", "Baseplate 32 x 32" }, - { "4186", "Baseplate 48 x 48" }, - { "782", "Baseplate 50 x 50" }, - }; + delete File; + return false; + } - for (unsigned int PieceIdx = 0; PieceIdx < sizeof(Pieces) / sizeof(Pieces[0]); PieceIdx++) + lcMemFile PieceFile; + + mSaveCache = false; + + for (int PieceInfoIndex = 0; PieceInfoIndex < mPieces.GetSize(); PieceInfoIndex++) { - PieceInfo* Info = new PieceInfo(); - mPieces.Add(Info); + PieceInfo* Info = mPieces[PieceInfoIndex]; - strncpy(Info->m_strName, Pieces[PieceIdx][0], sizeof(Info->m_strName)); - Info->m_strName[sizeof(Info->m_strName) - 1] = 0; + mZipFiles[Info->mZipFileType]->ExtractFile(Info->mZipFileIndex, PieceFile, 256); + PieceFile.Seek(0, SEEK_END); + PieceFile.WriteU8(0); - strncpy(Info->m_strDescription, Pieces[PieceIdx][1], sizeof(Info->m_strDescription)); - Info->m_strDescription[sizeof(Info->m_strDescription) - 1] = 0; + char* Src = (char*)PieceFile.mBuffer + 2; + char* Dst = Info->m_strDescription; - Info->mFlags = LC_PIECE_GENERATED; + for (;;) + { + if (*Src != '\r' && *Src != '\n' && *Src && Dst - Info->m_strDescription < (int)sizeof(Info->m_strDescription) - 1) + { + *Dst++ = *Src++; + continue; + } + + *Dst = 0; + break; + } } lcLoadDefaultColors(); lcLoadDefaultCategories(true); gMainWindow->UpdateCategories(); -} - -bool lcPiecesLibrary::GeneratePiece(PieceInfo* Info) -{ - const int StudSides = 16; - - bool Brick = !strncmp(Info->m_strDescription, "Brick ", 6); - bool Plate = !strncmp(Info->m_strDescription, "Plate ", 6); - bool Baseplate = !strncmp(Info->m_strDescription, "Baseplate ", 10); - - int StudsX, StudsY; - float MinZ = Brick ? -24.0f : Plate ? -8.0f : -4.0f; - - sscanf(strchr(Info->m_strDescription, ' '), "%d x %d", &StudsY, &StudsX); - - Info->mFlags |= LC_PIECE_HAS_DEFAULT | LC_PIECE_HAS_LINES; - - Info->m_fDimensions[0] = 10.0f * StudsX; - Info->m_fDimensions[1] = 10.0f * StudsY; - Info->m_fDimensions[2] = 4.0f; - Info->m_fDimensions[3] = -10.0f * StudsX; - Info->m_fDimensions[4] = -10.0f * StudsY; - Info->m_fDimensions[5] = MinZ; - - int NumVertices, NumIndices; - - if (Brick || Plate) - { - NumVertices = (StudSides * 2 + 1) * StudsX * StudsY + 16; - NumIndices = ((StudSides * 3) * StudsX * StudsY + 28) * 3 + ((StudSides * 2) * StudsX * StudsY + 24) * 2; - } - else if (Baseplate) - { - NumVertices = (StudSides * 2 + 1) * StudsX * StudsY + 8; - NumIndices = ((StudSides * 3) * StudsX * StudsY + 12) * 3 + ((StudSides * 2) * StudsX * StudsY + 24) * 2; - } - - lcMesh* Mesh = new lcMesh(); - Mesh->Create(2, NumVertices, 0, NumIndices); - Info->mMesh = Mesh; - - float* Verts = (float*)Mesh->mVertexBuffer.mData; - - if (Brick || Plate || Baseplate) - { - const lcVector3 OutBoxMin(-10.0f * StudsX, -10.0f * StudsY, MinZ); - const lcVector3 OutBoxMax(10.0f * StudsX, 10.0f * StudsY, 0.0f); - - *Verts++ = OutBoxMin[0]; *Verts++ = OutBoxMin[1]; *Verts++ = OutBoxMin[2]; - *Verts++ = OutBoxMin[0]; *Verts++ = OutBoxMax[1]; *Verts++ = OutBoxMin[2]; - *Verts++ = OutBoxMax[0]; *Verts++ = OutBoxMax[1]; *Verts++ = OutBoxMin[2]; - *Verts++ = OutBoxMax[0]; *Verts++ = OutBoxMin[1]; *Verts++ = OutBoxMin[2]; - *Verts++ = OutBoxMin[0]; *Verts++ = OutBoxMin[1]; *Verts++ = OutBoxMax[2]; - *Verts++ = OutBoxMin[0]; *Verts++ = OutBoxMax[1]; *Verts++ = OutBoxMax[2]; - *Verts++ = OutBoxMax[0]; *Verts++ = OutBoxMax[1]; *Verts++ = OutBoxMax[2]; - *Verts++ = OutBoxMax[0]; *Verts++ = OutBoxMin[1]; *Verts++ = OutBoxMax[2]; - } - - if (Brick || Plate) - { - const lcVector3 InBoxMin(-10.0f * StudsX + 4.0f, -10.0f * StudsY + 4.0f, MinZ); - const lcVector3 InBoxMax(10.0f * StudsX - 4.0f, 10.0f * StudsY - 4.0f, -4.0f); - - *Verts++ = InBoxMin[0]; *Verts++ = InBoxMin[1]; *Verts++ = InBoxMin[2]; - *Verts++ = InBoxMin[0]; *Verts++ = InBoxMax[1]; *Verts++ = InBoxMin[2]; - *Verts++ = InBoxMax[0]; *Verts++ = InBoxMax[1]; *Verts++ = InBoxMin[2]; - *Verts++ = InBoxMax[0]; *Verts++ = InBoxMin[1]; *Verts++ = InBoxMin[2]; - *Verts++ = InBoxMin[0]; *Verts++ = InBoxMin[1]; *Verts++ = InBoxMax[2]; - *Verts++ = InBoxMin[0]; *Verts++ = InBoxMax[1]; *Verts++ = InBoxMax[2]; - *Verts++ = InBoxMax[0]; *Verts++ = InBoxMax[1]; *Verts++ = InBoxMax[2]; - *Verts++ = InBoxMax[0]; *Verts++ = InBoxMin[1]; *Verts++ = InBoxMax[2]; - } - - if (Brick || Plate || Baseplate) - { - for (int x = 0; x < StudsX; x++) - { - for (int y = 0; y < StudsY; y++) - { - const lcVector3 Center(((float)StudsX / 2.0f - x) * 20.0f - 10.0f, ((float)StudsY / 2.0f - y) * 20.0f - 10.0f, 0.0f); - - *Verts++ = Center[0]; *Verts++ = Center[1]; *Verts++ = 0.16f; - - for (int Step = 0; Step < StudSides; Step++) - { - float s = Center[0] + sinf((float)Step / (float)StudSides * LC_2PI) * 6.0f; - float c = Center[1] + cosf((float)Step / (float)StudSides * LC_2PI) * 6.0f; - - *Verts++ = s; *Verts++ = c; *Verts++ = 4.0f; - *Verts++ = s; *Verts++ = c; *Verts++ = 0.0f; - } - } - } - } - - if (Mesh->mIndexType == GL_UNSIGNED_SHORT) - return GeneratePieceIndices(Info, Brick, Plate, Baseplate, StudsX, StudsY); - else - return GeneratePieceIndices(Info, Brick, Plate, Baseplate, StudsX, StudsY); -} - -template -bool lcPiecesLibrary::GeneratePieceIndices(PieceInfo* Info, bool Brick, bool Plate, bool Baseplate, int StudsX, int StudsY) -{ - const int StudSides = 16; - - lcMesh* Mesh = Info->mMesh; - lcMeshSection* Section = &Mesh->mSections[0]; - Section->ColorIndex = gDefaultColor; - Section->IndexOffset = 0; - Section->NumIndices = 0; - Section->PrimitiveType = GL_TRIANGLES; - Section->Texture = NULL; - - IndexType* Indices = (IndexType*)Mesh->mIndexBuffer.mData; - - if (Brick || Plate || Baseplate) - { - Section->NumIndices += 10 * 3; - - *Indices++ = 7; *Indices++ = 6; *Indices++ = 5; - *Indices++ = 7; *Indices++ = 5; *Indices++ = 4; - - *Indices++ = 0; *Indices++ = 1; *Indices++ = 5; - *Indices++ = 0; *Indices++ = 5; *Indices++ = 4; - - *Indices++ = 2; *Indices++ = 3; *Indices++ = 7; - *Indices++ = 2; *Indices++ = 7; *Indices++ = 6; - - *Indices++ = 0; *Indices++ = 3; *Indices++ = 7; - *Indices++ = 0; *Indices++ = 7; *Indices++ = 4; - - *Indices++ = 1; *Indices++ = 2; *Indices++ = 6; - *Indices++ = 1; *Indices++ = 6; *Indices++ = 5; - } - - if (Brick || Plate) - { - Section->NumIndices += 18 * 3; - - *Indices++ = 0; *Indices++ = 1; *Indices++ = 8; - *Indices++ = 1; *Indices++ = 8; *Indices++ = 9; - - *Indices++ = 2; *Indices++ = 3; *Indices++ = 10; - *Indices++ = 3; *Indices++ = 10; *Indices++ = 11; - - *Indices++ = 0; *Indices++ = 8; *Indices++ = 11; - *Indices++ = 0; *Indices++ = 11; *Indices++ = 3; - - *Indices++ = 1; *Indices++ = 9; *Indices++ = 10; - *Indices++ = 1; *Indices++ = 10; *Indices++ = 2; - - *Indices++ = 15; *Indices++ = 14; *Indices++ = 13; - *Indices++ = 15; *Indices++ = 13; *Indices++ = 12; - - *Indices++ = 8; *Indices++ = 9; *Indices++ = 13; - *Indices++ = 8; *Indices++ = 13; *Indices++ = 12; - - *Indices++ = 10; *Indices++ = 11; *Indices++ = 15; - *Indices++ = 10; *Indices++ = 15; *Indices++ = 14; - - *Indices++ = 8; *Indices++ = 11; *Indices++ = 15; - *Indices++ = 8; *Indices++ = 15; *Indices++ = 12; - - *Indices++ = 9; *Indices++ = 10; *Indices++ = 14; - *Indices++ = 9; *Indices++ = 14; *Indices++ = 13; - } - - if (Baseplate) - { - Section->NumIndices += 2 * 3; - - *Indices++ = 3; *Indices++ = 2; *Indices++ = 1; - *Indices++ = 3; *Indices++ = 1; *Indices++ = 0; - } - - if (Brick || Plate || Baseplate) - { - Section->NumIndices += ((StudSides * 3) * StudsX * StudsY) * 3; - const int FirstVertex = (Brick || Plate) ? 16 : 8; - - for (int x = 0; x < StudsX; x++) - { - for (int y = 0; y < StudsY; y++) - { - int CenterIndex = FirstVertex + (StudSides * 2 + 1) * (x + StudsX * y); - int BaseIndex = CenterIndex + 1; - - for (int Step = 0; Step < StudSides; Step++) - { - *Indices++ = CenterIndex; - *Indices++ = BaseIndex + Step * 2; - *Indices++ = BaseIndex + ((Step + 1) % StudSides) * 2; - - *Indices++ = BaseIndex + Step * 2; - *Indices++ = BaseIndex + Step * 2 + 1; - *Indices++ = BaseIndex + ((Step + 1) % StudSides) * 2; - - *Indices++ = BaseIndex + ((Step + 1) % StudSides) * 2; - *Indices++ = BaseIndex + Step * 2 + 1; - *Indices++ = BaseIndex + ((Step + 1) % StudSides) * 2 + 1; - } - } - } - } - - Section = &Mesh->mSections[1]; - Section->ColorIndex = gEdgeColor; - Section->IndexOffset = (char*)Indices - (char*)Mesh->mIndexBuffer.mData; - Section->NumIndices = 0; - Section->PrimitiveType = GL_LINES; - Section->Texture = NULL; - - if (Brick || Plate || Baseplate) - { - Section->NumIndices += 12 * 2; - - *Indices++ = 0; *Indices++ = 1; *Indices++ = 1; *Indices++ = 2; - *Indices++ = 2; *Indices++ = 3; *Indices++ = 3; *Indices++ = 0; - - *Indices++ = 4; *Indices++ = 5; *Indices++ = 5; *Indices++ = 6; - *Indices++ = 6; *Indices++ = 7; *Indices++ = 7; *Indices++ = 4; - - *Indices++ = 0; *Indices++ = 4; *Indices++ = 1; *Indices++ = 5; - *Indices++ = 2; *Indices++ = 6; *Indices++ = 3; *Indices++ = 7; - } - - if (Brick || Plate) - { - Section->NumIndices += 12 * 2; - - *Indices++ = 8; *Indices++ = 9; *Indices++ = 9; *Indices++ = 10; - *Indices++ = 10; *Indices++ = 11; *Indices++ = 11; *Indices++ = 8; - - *Indices++ = 12; *Indices++ = 13; *Indices++ = 13; *Indices++ = 14; - *Indices++ = 14; *Indices++ = 15; *Indices++ = 15; *Indices++ = 12; - - *Indices++ = 8; *Indices++ = 12; *Indices++ = 9; *Indices++ = 13; - *Indices++ = 10; *Indices++ = 14; *Indices++ = 11; *Indices++ = 15; - } - - if (Brick || Plate || Baseplate) - { - Section->NumIndices += ((StudSides * 2) * StudsX * StudsY) * 2; - const int FirstVertex = (Brick || Plate) ? 16 : 8; - - for (int x = 0; x < StudsX; x++) - { - for (int y = 0; y < StudsY; y++) - { - int BaseIndex = FirstVertex + (StudSides * 2 + 1) * (x + StudsX * y) + 1; - - for (int Step = 0; Step < StudSides; Step++) - { - *Indices++ = BaseIndex + Step * 2; - *Indices++ = BaseIndex + ((Step + 1) % StudSides) * 2; - - *Indices++ = BaseIndex + Step * 2 + 1; - *Indices++ = BaseIndex + ((Step + 1) % StudSides) * 2 + 1; - } - } - } - } - - Mesh->UpdateBuffers(); - - return false; + + return true; } diff --git a/common/lc_library.h b/common/lc_library.h index faaf7225..a53773e1 100644 --- a/common/lc_library.h +++ b/common/lc_library.h @@ -122,8 +122,7 @@ public: PieceInfo* FindPiece(const char* PieceName, bool CreatePlaceholderIfMissing); PieceInfo* CreatePlaceholder(const char* PieceName); bool LoadPiece(PieceInfo* Info); - bool GeneratePiece(PieceInfo* Info); - void CreateBuiltinPieces(); + bool LoadBuiltinPieces(); lcTexture* FindTexture(const char* TextureName); bool LoadTexture(lcTexture* Texture); @@ -152,6 +151,7 @@ public: protected: bool OpenArchive(const char* FileName, lcZipFileType ZipFileType); + bool OpenArchive(lcFile* File, const char* FileName, lcZipFileType ZipFileType); bool OpenDirectory(const char* Path); void ReadArchiveDescriptions(const char* OfficialFileName, const char* UnofficialFileName, const char* CachePath); @@ -163,9 +163,6 @@ protected: bool LoadPrimitive(int PrimitiveIndex); bool ReadMeshData(lcFile& File, const lcMatrix44& CurrentTransform, lcuint32 CurrentColorCode, lcArray& TextureStack, lcLibraryMeshData& MeshData); - template - bool GeneratePieceIndices(PieceInfo* Info, bool Brick, bool Plate, bool Baseplate, int StudsX, int StudsY); - char mCacheFileName[LC_MAXPATH]; lcuint64 mCacheFileModifiedTime; lcZipFile* mCacheFile; diff --git a/common/lc_zipfile.cpp b/common/lc_zipfile.cpp index b494fd55..52bd35b1 100644 --- a/common/lc_zipfile.cpp +++ b/common/lc_zipfile.cpp @@ -38,6 +38,19 @@ bool lcZipFile::OpenRead(const char* FilePath) return true; } +bool lcZipFile::OpenRead(lcFile* File) +{ + mFile = File; + + if (!Open()) + { + mFile = NULL; + return false; + } + + return true; +} + bool lcZipFile::OpenWrite(const char* FilePath, bool Append) { lcDiskFile* File = new lcDiskFile(); diff --git a/common/lc_zipfile.h b/common/lc_zipfile.h index 524a533b..96f68fcc 100644 --- a/common/lc_zipfile.h +++ b/common/lc_zipfile.h @@ -54,6 +54,7 @@ public: ~lcZipFile(); bool OpenRead(const char* FilePath); + bool OpenRead(lcFile* File); bool OpenWrite(const char* FilePath, bool Append); bool ExtractFile(int FileIndex, lcMemFile& File, lcuint32 MaxLength = 0xffffffff); @@ -71,7 +72,7 @@ protected: lcuint64 SearchCentralDir64(); bool CheckFileCoherencyHeader(int FileIndex, lcuint32* SizeVar, lcuint64* OffsetLocalExtraField, lcuint32* SizeLocalExtraField); - lcDiskFile* mFile; + lcFile* mFile; bool mModified; bool mZip64; diff --git a/common/pieceinf.cpp b/common/pieceinf.cpp index 9fe91639..b86b8523 100644 --- a/common/pieceinf.cpp +++ b/common/pieceinf.cpp @@ -49,11 +49,9 @@ void PieceInfo::Load() m_fDimensions[4] = -10.0f; m_fDimensions[5] = -24.0f; } - else if (mFlags & LC_PIECE_GENERATED) - lcGetPiecesLibrary()->GeneratePiece(this); else lcGetPiecesLibrary()->LoadPiece(this); - } +} void PieceInfo::Unload() { diff --git a/common/pieceinf.h b/common/pieceinf.h index 2f6d5e4c..0ef7bfe1 100644 --- a/common/pieceinf.h +++ b/common/pieceinf.h @@ -15,7 +15,6 @@ #define LC_PIECE_HAS_LINES 0x08 // Piece has lines #define LC_PIECE_PLACEHOLDER 0x10 // Placeholder for a piece not in the library #define LC_PIECE_CACHED 0x20 // Piece is saved in the library cache -#define LC_PIECE_GENERATED 0x40 // Mesh is generated in code #define LC_PIECE_NAME_LEN 256 diff --git a/leocad.qrc b/leocad.qrc index d1d01cae..22059896 100644 --- a/leocad.qrc +++ b/leocad.qrc @@ -66,5 +66,6 @@ resources/piece_show_earlier.png resources/piece_show_later.png resources/time_add_keys.png + resources/library.zip diff --git a/resources/library.zip b/resources/library.zip new file mode 100644 index 0000000000000000000000000000000000000000..4c88564ba75f998d49a2b61742fa79f388f053f6 GIT binary patch literal 47780 zcmbTebyStj-akxtcSuS11~!d!m$ZaP2uO#3(%sT2B_SOW(kWfi4I(WiBHi%2@IKE` zxp8^k*R{r_f9z}K^X-~Zl7ogpg1Gs!p~)!m;~)R|3l8EQgr(7QgO{x8YKRcf<13hI z6TotGLWY2ZS%-#z`0{Ny^@;6k=!tm zzHrJ`7_RFVJkoFM#}kIafN_Wnm}GyQNeH#@mJoKqLI%5K5NmaYQtuGY%pJqNr(<&w zXSei&<``K}0L2$&m20>goIg*=U+!1P0-Uk}SUA6&(%!-G88g@k{I_FrsDZ$$Aa*4X z1ZDsdoPJRHD>>Ow$1sM_0~IW}8Wa(8M;T=ljY7HT9`QUlh~M}AaOEiQe|zKI-kXif ziH+-j+PxHXYjcM>t%;N-sp4)_%X0s`ZgLjvqE`WtcL z9%;q5k)xdN(ARkF-;>=)KG(BU>0XkcS+rsAMw*hAweO|2%ZxVfmAfirENRXi+@s&Q zxNLe3U;6mj`%olRt>- zpcq+qnFMwx_TToF|F`A(XK(Otd#nCu-%W>Lbp(xExr$&IHK<$W;Mv^z5i77~JFxy` z4mjAIIDX&x4x4$iGxU9ESZI)0o<2kXLS0Q3Sa))$sC7u5mAcHY4x@*taY`%1>1@cbeSE@m(N3e@FX>%+D$FKvRU2|=0$HM6 z$IE9_O83FuqEgY1rsmR4XF0IYs`ncrQC!Q2j5{zU(^CyLA1*t1>UOT&d%!k{*Fj(Y z!kjkgEiudMP=Q`aR>ToCn0n38$F`q$iP7wq$i6kJy$`wig(Wv=HVl$z{QxwQ02<{wC~V8~>>xMpkcmcQppXsz#0I-jFs#Z7;K*mE3( zG?ycY0u$mF6YUaxaZu9K_RL5;CCyz^CcuhmystCkyBRz4vip;O$*19AW6sZc4_&79 zA7z1gWe2jv+wMQIH%R#U+?pKK#NyrDn-!lu@5_wH%?i^;o@HxTN3g#$=nHSVT?7E> z>MjOxas6~Te_&A9pzaMKh=rFAqmaduW?&;0QH{zM`=;PDrgjyo)HLSA*2P3m_C_J9 zGx{H3FnyqfGWZtHDVOVIT^9cCNA68-=K>iLc zWssK^`aGBb1) z_>3eGmO8yL^S*w0*Da-)M!>DP*`0ijaw*#L;r{6%&!XMcMJh|ZS7{(JDd{QhLdioN zPsO#ixy99rS3!s@ET$gJ$rmKzNd6NeJ?O;$PCT`u>)v6KBnsY!WHcN3b)N@dtkSkglcSckk07?)@q576D8ZJM?!Ue8wqAv<@1DpF~M6 z?cPtvb57;EAf_%^A6?(l7l+h*IV6Dop?A~&rvdu|{oPf6sLSO%{c~^O$qo|X25)Yq zBMLMcpM_oBxuhH!KAa+FR#vMgSPOitC5Qt%U6+UsJ_vdQ3*~Os`(qM8Fk)UO*E!I| z@Pv}#PvJ_**TrCagzu@Ak{v@Iy$vn#d=y3`0!{DNVP5<|USG~~*8~-xk}v%59Be#41MxqI4u_JhER!O0w+xevIuMfQDS;{$*kQ^X!ccI8hm;^w zSy<>5CON@{An>T143l>r7Z|!{gD7cXOkd5wFaMJl)v5_qKG%H-PMHvy=kR78R9p~_ zsLbRP2xG>UCJ^doP}yPLpL^(~BOdmaKv+QD5_}nThPhY3;gj!T5I65n!}A9}5f=_H zNEk)@`a#EIa%1eRk*7}3`I={{mMyqPCp1a%R$GD55ro~z@=ya}$$SXxOWrM*YVcE_ zsx#@qH&k+t7NdcesTa$160?!(8b0=6g>MLRuGkglF8RLPw;w@@o#;%$G<4(9p^ z>t6*c^bcZ42YjcAne#I{Zg^u&1&(Tu zTNhW*}~jyC5%=K!veD`j3N*F3c?ktiol)y0DU2iVW!Hl zZa0OTtX#hiJ;7Zlg{;eiLDwovSkaZi!$j4uM1IjV+m!a&ua5asYz{4bgO_e^Z~2lg zSIrC?v7g+|h|-gyOx)Y9f3G+o>;(WE4dCc)*U!bl!}U`j|G-kKFcCB$l7ZQ2Fcezo zRU8Qlv@OXK&cnLTYrAmT-k}yIEclhwq#^VhM+AoD_b}o6-5dl|p?MM|l@6i24@+XZ zR#U6GhDvg3f*?Yi_$Ym|YhGcF(TO6zT5_Hn>aoGR@?CfGj7@rros}fe(mG6Xl3bDx zwf#HyOmQ;CGXM}+cW{r3jqRsB{sV@vsQ+^BF?o4?*st8<{=q%08}7ZYr}(N@y-yN~ z$;1c;&tu}l(s_MKD!5(u01fdIVQq2LEJ1B&H{m(Ruv6_Rc4s1il;ssWUgJbhP%cdH zpwIX9lE8P(0uSdj>z2MOLS;oIDqyN4UQ}nLvtElkSky4&FeT!Z%4un7H1xqe;x~a- z-OwfKZDrtV#r_@cFpg@`5&-ul%)fcY31$cVw3C0p>#m}M21S8#ag5U_Oj(*t`hn32 zW;t+Jd^w@(ktS*C2&eZPC>0GPpT56*S~s%cUjNA~7-vJ(gpVaq+$@`bZsj3qFi!xQ zO&`0Xe_1TQRE7+y+7@#E9&uBywVeN89(Aoq71^s+%{?VLN)%IEj6!-ND&#K=+BF$s z!rcee$(qCrJ>4%xzM^skv11cOM&KLSzb1QG3_;T#_5sZ?MIY<1!>d2++t<8-J~SQL zD5m$AY<%{D0xI@(+T3&+!VcOKb#RwgC|`$Q#HRGBtn$h$w#vhXg#s0PuBMR}cRya< z(r(|oCSAzIf#@*>BOxYp^g{O~&JIiwX817&93IwW(mBnLBQ>Z_Dx z+zicg69}KtuL2b0u%>tt_Os}zo95NAoy~Gx1fgX_I^ktnhfj<@snI>+$Wq;ue^Q}w(O^t&8H|KeI zIY4ax^^kwye3+UQ5c#28HmjaMiJXq0L45MU4lNeKz?LYb2!AM@)b62JXl_0!*xc0a z@q(%G@!DW8Y4hiS9ULgwGlj{0H_t}J1F&bxL!r@@DE{bbqidUR%d5ldo!QGhTi!V& z8`}P_WwuNZu)x^OF0cSB-ctKbd+{XgEMh!M5;FCgjisylY*RzZk?+XH ztV7OdDb`e;Y8I8$sZM=3*f#xqo4RrZ_OJ}X&$8hix5c`bQ7_xd2khoXyM=YXXsJfl zvP*tNiK_fQTDgQWz>Xhrp@h6z(XsGA-)F&q&KtXqmUa;6SIwLvld) z0jDxj3O|ufFBCPLFnSeDAcdjK5r39~Wf0cxUA4SAWutlF8&Q!}SWp^Eo{*SOcsxniEK*ug#Kld;16C9HmKa^?LXimpVg!b}<3wECKfT=_q{v@Y z`G*wE)4O@6^8~v7r_F=k&Q7PtzN8Z_)esJEl**CA)=tw6%py z1X*M-8^ZBjvCjJkW7*C6$+SA#@lq|g6c8(7ePK?Ha((dhh%H+wq~IdV)RrXG-MGt{u- ztMFs9VoR32HVnz`-}U&)>kaV)!K;emYepC&}@)iY;i1@D)#TPPLqe)NJilTx0<=hzKs$Afa{tYR=ZIlkW@ z3{D-!&$vG~>!jGeJR=~6p)zIrDCagYv~ccvk~aSZ!4K*J3B=o@}%BZe7TT1 zI2uAmKU-cG8LHx@gRo8weorLdD7@*GnMZWH5zm<@IMxV^DcuPAz8%Pir))n_7!% zvtl?j}Ml!{OwJ)UlOTp_0{(qe*rQKNkAkw?=$sFu#d#9|9b?9S`wvbMpMv zw{j>U{1cq3128Asv`$$eD$WAah0d!h|QhEMYl9 zQ6ghEM2o%3mDD#|V>dJN{TVsgh1W$iLROH}9EFWjA8Kj99F6akSdzz6G)6i@-1(EudxsUH_hV*Y5I)ck%MYRUP>= zqYH{=L?h9Vpg!`Tt;y@-uAN=m3pcgTuPVO#JP~C;a28oJNc^~UkFlu*Pgf>x_C$ol zl)nOV#1Cqk#%$!f0Ku4-3J#ra&v3DYiZyXK*IShj_qj%R?VhBNpmAN9F53vXC_SWj z=1JT7fbB%|-~m!5eBYyonb>bybcl|kGoaY>ASHY=v9u>tjCFC1leNs7k>x*zNl!kF z@y>S6IVD^#c$;+S7MlNj+Oq!(8sW?WVsS!nxw2icN@k8`utQ7%N+7NEr1v+IWOeJt z?pkii^Tc;;&Ki(Ur6P6YEBn*8m!wb*dpoYsf0v}Zl!ifafZoz~(3^wn?WHep6HW)@J7duJ;Uk}qCLPN4~c;=k8E&vp1Fw*Eo zS*cxWFXi{y!+>xtU9&0Dux0sd|W>g5YG%t3W z5>-`w`^=aC?b}J@ac6ya#=Pe81JORcXqD&(Z_36}t5)VPFBmD#xtlN^+Vs4fS*?vn z-0t3V&J0qhVsnaiR_@+xJqjDgxLuOb0fmv^1JstegW6y)*I(7vG3Lgl0STOINUfLh z*ML}?cOMWjw&9`jadCo|m)pZ%KC_G!FQXaUnoI5XOBmeR_E{@Au0~HGjr#uTb=oq; zeU{gIxciOF7w6|!_8vUVpV1M`B!dc*a;)rnN7N2X&A5!`OUfp&!P-&vPMQ6YbB|S<;9xm9BOhxpzrxbkE0r{hc!@^YwDq8c+0`3* zI6m|{CA7t^)qNvDY3gB%iMFMnc888}T<;esv2wU8F^pfd$20R~mV23VIt>Hs&AC*H zsN-|q1iHdhXn~qh_8|o-#RThk=P53)p#?*k9U6(%Xy1S4XDpSw60&h@okoO(Ud#A8 z#7R=-sC1jio$=^mE`V_q1PJ}FNCpJ@88_Ty$&7cEiMJ5FKq!9K{1SM1E3z99Eccr* zl-1n4mMzT33t*xt-4c*h**PWT(!(&k^@DX6xz~)Dm)Ug`Wksq+I9fIdNykLXBg=AL!|1C7_>XE7A;_#}M$6*H9yv9SY%Z+L-C>&02a?18Liw9J)u+)M5cg43Qh$U1^ucS1+2kX``GrU=3aT zgS~X5q5`l*AgN>Z&oiYKdgM)0s*@`DVvP?`#_=bI%E-K5^;-MbJ#rH@gLbKe=I_M* zO6Jb=D0rlYK_C$^jO;tju!7gy1*PFDP8EZeHh8~IqE9f(-bk<-k0Px_bS2Zckd!b^ zN#QyQh?rj5m_RaeAcN-*hk1`OX;rxb+uW!gnNU2xa5f*z0*J0|&A*IK&AiY5=+UwcQt zrZ=TZKtU6{#C|hvFvQ8G1R){@>+nx|FSAt?XzsyePC!vXj(CZc$@n8C8Qve?BqH(- zgWF{Dse{kM&uRH6Op#0eK#;x}stEd4{Id_qWqVWU!nlL@TwEM~jkAG57m}|qip24Q zj%H!1C^o0aZxVKNu=y-?-%n_WUQrt3U1NVv9&~ETMQK5DM-Uh3)sF;a9epVYt7xle zsB`W~Gk8*1b{#NE7oCWa53LaOqK2^tmqT0pb)MkTTUX2`VTTLP*l3{86)hmLyiRtK z%u4Ue^*gCePIbFN0Su{7|0Xp%+h27%?nj;LpEjM6jA1uqLy#KKrQ^}`zc)XQ1EWik zjZVKJcQQk^m{e`1`#jML2j%rcH5(bsO^TCZ9q0bwG3mjG$0;=VjpCn3Fk)B-)@vN> zxURa`0=N^e_9*d5R5qITKNv|<)l4s@S6GDlV_$xigpZN`NV;mx;u99D!Rl(SwKjWc zmKMeRJFt*o_3m5%SQ`NB-=2m2XCwR%Rx55u`KF%=w{V<#AHQ3=T+=0VPM?RSsT*fP zB%-^rADSbH2esXJ%UbR<6OQ{hD3@0G$P_e}U%V z{Qq1SPy%r+-Sh%b`+sQ$z{@@&NZQDziWiQJ$&Ok87tnI_W7U>OQgh#ZM}ioG2DGEDO=BCURz+oS1C|0&!=5yUTC5~(k)atali4-e#O z3pY`I7c$6YvQ7j5kR}i#-p=hfKwz-p-+ZIHs?|+X7^t4DKzSE;lK#`T6T2r5)3RLu z&LX)4)!&MhwPZtXq|GX6p7OEaU>EW_3Zw_gF3D^Fg5%x$Y<_}|Hj6ZM4sF(4~LcZo3v$IlMJA7tfM z2k=izi+%A%jG2Ft;@d4P?}G&;8)XCUcS+J6b&@pt??sa2)5D?4(<{oNyhZ<1_sY#| z8*2tmsRi^2ZhI>3UyRHjDlKs%x;I7!{`(IjW13mT+i4BD7sAR8Z$GqLLWajLp|RT{ z>}hr-j{B+e#W#@;P{aOSVEyb5LNK$(u2(2@8t-)Zr7SKWH^n~2KayuKwNI~4wY=&h z@OlWF7Xqzh;HA2c%o0{g{_M4f`6VoWSm^=>g|cQ$4Qi=&B-K~Lu#!c=#0|CbN1S1@yG}MT}MN`DpbWyTyTCMR|s{zg^tDP5|RC|oS#mkwh zx!o$8z(lGLq^!J-R5Mok6!T9~T`g()FFxw#Uy$&+wZs+*#0%64XR{%8jtUu6Y03~^ z+^Y3=TGF5112E;@kqB~d{nB9l6RsF#v{v#TK9bc7vc3OV$pT{Nev4`5aH5l2m;TVz zSUVH(%Dhy@<*V$r?JJ(qD`#Ha{Q2nI!3%4R@W)aE(P3m#FFZC+i00c|c*27@JiXqy zkuSgHb6?6zqe?!Ih&T7En-ehlTnc-NegPV_gJOQWRYSzFRDc0JD*Kwt#A*8M|F@rGw@nRCHbDF7)?k=mp8WuhONW99;Mr4oC-KO8(uI z+I>do?M8@S5+Sy@{89$fKk+^-dQ44}l>O|6D_7a82L4|e|eu#nIc5x*?Ps+J|hBePJc_% zo2Q=lI%l^8{CYPVE{Rg%zhy~xe3qd!i~U$;_(-&z9`)6zy;{Lyw?3{8=_{`=WyH>9 zpM`=B?U{vJF}rjV9%c)G(hz92{mV&%*nftNf3R+GKRUzz7jr$;a0Nnk?5-yP#5@^Y z)!P~x+-@iI72Y16dog|+Tov|G;ZVVEn6#uMUk8th#q*?XyAP&)HXYi3pNh<~A$L83 zm6cf>XzE?0=^xD@%DB=_ksk#o$`#oj^wg3`DJ=ujFd3S zXXiYQC0zvOdcg3-fpEu68HrL1LP>agXtXHzl5NFQm@}qm=TAJZv>x(xwzbJM#V_xP2`N# z$z;i}dJ`_}Y7}+vwP;e%!oe#or$_ASrtNa31hOP8^F8V@SC#POtap^uF8pku{jJ)W zknFO7R5A$y683R}Oi$nCpr2*6U&WYg5_bPkcd@}s;fj*^cfn~=77ouhVOjp5?(nxH(qr$XlM6jn18%3P2!#hwWnrgMX%C ze~?w6g2z#}%U#|Gf0nYb>U5Q| zv9Wh`Bog=l^*~NSFyg@NERnTOU>hkes$3x7=#;r6qOloh7Z|wch8_!9rF%ch_bnOB%i6;UR?uh5yg$0LaFL)ueq2Yx4(;h|fc)BKZCIZqx;A691rOS)&sT{Gtui zE7vr5OM|K*sc6pcj79m+!UfdZY0e4m_sr25IU00zY6m^~U2a0U%CRB=xyij#Za_aL z5B@;$umKUk+hD*Bxj)=x1(^^;LOWr;EjA170>qvKmz zT*4!D?MZ!HRlZqM5i#l6EYimnHZp9FWz8TWQN(Gi$auZ1Jj%uTsK6@gmhHndg;e$j z&}rU*4k#u4%mV(P?8f20T6n_B{z}&SS8U>TVzdXllMZlCr6?|?2W4bSJ?92qVsw)e z!-WeUe&6(Xm_|z7cl1034@*L?;&~S9BrLY<7TZyvL4)8!u@@R480M?G&*C>`%!|`C zTKd+FL>%*H9WJB&1PWm4rbbM8-kp%Kth5UW)UsAuiah(BVT(_DzuZ&-ZfeE1a{wN0 z5cf|V`2!}a@c)zn-Yn^nQ+MjGk$;oOmli2_#UkK=-4mpp*l`Wo*=;lZJPOf*#4H=j zDNTriCAqi6Dls!y5xU)glIHP*tmGT9th$)U#GB~hZrLjw$Bxj7+~iG;raIh3Xh}BA zZFv>Rjn;2@Q4WEm?|AG3E^lRLlARvNZ~%bUcj!3>ke>ZLkI}g)WdQRZwZb2yzC&bl zucK;T(BU%qi$>@b&waIw##M8mNi0gt%I<3rpyg})Rt=8|eR!a?v%l9gpgO9`I#z9K zm4@(sDFtBwrAy5OYdDO!M(`N_n`Has;CvVge=mqZ!~D{KLeH?P5LY0M5C?ltd&9=6 z1pF~>NO)d6A*<`T3{BUiK(ep1{rhASqA|IS`uG=4uJpq^6Ve>!!ZjV$eiYNen?@(( zm=!UHG`M^v54?xUX{YuqW3ra2XbzH>ZCz!e#u36DYe-5_D;ETW_)wlR(V7VPF>o3T z@t{>pMc*%^H^EWV=AhP2r&RTs<7MwCRv5?Ozuraa$oPEz1^IWuaHu9?yD6;%+#wje z>|lC5WYF;eav?d!Pj2P;`)8$ozm1Q48 z3IS^>jYp51ZK%z3{+XKsmCV2~h4m4-?AOZdQGSaTbkvcq`+T|yj&7gg)pA|X;gLv5 zW_9bMH@7KP!PyidbpAPxzHU`Eaj%mK((5e2xQg)Ct6HNrq?@dqT%)&&D@LO}TetwM zr+0`8n4RZm2=fPIj;cE0K!^E!4W~(1BQa|evIdG)_yfFQw(f2ukD&WtC~Y2@0!df! zQ|{&O=f|EcR~`@Mlo%O4N2Ut9tSr(KvZH=I-*rp%9Oznmm+m0Vp2_*pcd`Bpp`Jm6 zVwQK|g%KVT2ROtT9DJZ&N|pbg=^#`nV#Z3(SC=luga zO!890$jkLloK1Jd;KCbH)4F@g4ngfUu(dPu1tJo5dC(m`hAid8$b=4IZN@A4b@;C} z@$XwjsKdRPKq_>HE+86rn;0JbxcZuT_8L*`gvPiqpfgv1QQ7U3HhOfD1|}Tr!EkcP zqhcR{nlN@v0FDatwUM#kqQ|~p*E%chbUq}*a&XJ@CP_0R+%)?R?jSJ-h~sA|=TCkh zM){_>Dt>JrQVW5rzX^SS#4CccMk$-EQB1jd(!%9EXF#b{Wh5Yg_u|*L{55vP7{+gxWmDs2Nooe(8{|1-&a*;wtuRTK0M9K`r2s97$37Cfb$ z#~|f*L}C5q95!sc@h|H7OsJ>zdq%7l;;S z$2RZ#*{0K&W=CMBK25-IY}oEK7s=|8PSOeD@4Bjw{*vRSNq<)m3e0o;6zD%tI}Whn zfI#1rav$qc?T7ISv)*643zV~_gM_&(*Zpy?MyBKtxIkyx?~9OBMjR_+)+ z_hiSauTi+K{Vpb3EB*6%n%^7Azy=dd^?UPcFN= zp~TM+X|9#dcLsaBTd8vUuEH`ty+Q#1>FSP>H8;mkM1Qb7agje-9{;&nA{TWu{whe3 z@TSb*;ucdgz|L(-PnF@Occ$udxj*yi1BN&YF|-N1DWY^CLmQgompjn%)fK z*GC4#+xK4J+QMqr;Nh~MFloJ7M5-{cQhy?L)-l2~EUldY*Hm}Bow3Clp^DGJYD-g0 zGli&#zB~Tuxgpy?p%{@Gt-B(0C`a`@e5ChwEgxiBglJW>7L%~bosb)Dr;TQ%jI*i$ z7Z2}h!*Ts`qvj7H8up(y+zv3+gH+x~aCr>XD4L!jMD0K3f3LZmw9p+<)DSVEb4JUI zrnT$%um-Y~Luf}R;(U9z>O;AhCZ%|H8&ugv=Y{KqyZ>SB6TuQGYJ6*_sC!S0OG*uO zTG-WL2yr5PPm2Xm(9K1bD#r81)4L0$q^oND1}>3!@-6WYxI3`15sjyg*dLWPRyfb{ zCUueTrsGk0w00{S>9bC$uXygMnSvs44>@1MwvymN$>-?T!rBp9Y0(QyX1T886c@bz z*qDzVz<%nzGAqa+rFWpe_oXx$eQ@PFlT$b=)t1wS#miin%t#gyl1v&z$ggzk>n2I- z_k5&Qp`yEydUjA-l!T5jYIj?eooVjTK)%1kdMHkjXlRsRttC0@uuEmn5hwL#FHgl2 ztA{8o^c$VpTt;ep%$F&#z>mj){ga=_XteD;^VCk^l)a-#Pj6Z51xliPk9wl#;_*@e_jCbn zlGdW{nZBzSYb%dUVOU#UyMfSSHoD>lUlI{qAzBhUL_+}V$v>%6BZto1IrxT0^X}!`SG17wC*epP+PLwca25E9d z#!E3mzdHQ5ndYT-I9@c_lpAN9%xQHEgXD%k{g&bgF;~ur_zEfUEE=Zkz=L7xa7x87 zJe7t1`m?EzI{YIj$`W@_87R4f{#tT(jG03P zibQ_%iLJ;m)XM7+MIT@goP^1}PofCYB6G@iu*PH+O7!l{uDML>+8oDNlC8B#j7Vm> zQ5E_4$+$I%Hubd%rj;DqxqoWbP&UNE_b@*&j+%d)b|@iPDV(VOIT7^`+1)mVDn9~5 z$V_X-NlC39e|fKvN^IDq_LY=2)=U`Zs)dr0D#^q~#sDwVYDU-+DQimT$-85S>aU0| zge}3hD1l}MI6CfjqhQSSFWA=uoV?C)xQj9h|X=#KvT`uYy1SztpP2hYQ)`!vFG*I;Mp%zw2$cL6gM>2V&xMH?unk$ ziYOXm9nlbOJvaEi{w}bpUf|(&sd>SJdvuB#)BZUS=cCIx$4<4}J7wJRBGCemEGHtr z#Hz)`v*)OI+EpBovD(lZ`%(Vx>$_4{oiYK85J1iTEcalQf(OT5WHCgYrJR;`QbU($1p5fk+Eux32Iz z*jl)i4}!ud4zS4(&!EByuGr%pQfMd#7{<&(AMNwa0l~Upd@)W(f7C8j7~NL6_l4Of z<;aMgF9g{=HM3z6p;m}Qj>AQU3IPfVo(5I^U*TEI^Sco|ZY6ha1rQE5g?WEKZEgbw zCcMFatwr4=B0qwFA6FM=DjWoN?zbsmPQNavKRBV$u2j>@ioJ?tRlxb=xxIx7L&~HV zV>W~qiPJqC*>r7S87Z);&dYQJCBcY$+Mwh;M+d{=e)eVf@bGy0G_Q;2GYYTO7%l|? z-+|@^8^>oK@T_xe=o75`*M5g@_(Pt?}SqrFSeC?aFlO#}AU{(hqVmWor$2qUH0Y5rQu=X~mvlmLp( zRe2XmEr6T^cKhOF$Lrq7*`}Mn41^A3-03xVBQl7npY+PX>6kO-y=86Qd&$p(DYbYnkvKzoSB;j7EKWNYn1qE+eU#K<70Br=_^( z?=YXB$R;@gFwySh9~bXmO`cU)%T0DJzH=FJ>Mf0hzboc~FDC(`j81ythTR{}!klaj zw@1_Fq__{!0_l#B1xfEK(kg9zQJGPdSY4)5ZQxuib@=T#XzF1)TqRths0832vALK< znQ}ib#wB20`K$|iCP%+TQIRnj;yHu&*p%x{zjec8OS${#ru}OJV7Ma={cC|CZs13N z4LkJ1u*l?y^#d1z)tKgRbU-%|wxXQ&oHU*%`OY&eThjVZzRKi*K~p|F9~9dK$xeAO z@C85DU6gq$Vbzy)soKU19GavA_JNO&x6}$`M@5DCQk^p1pn9seGt5X^XscR=S-GR% zV~}iW%`MLI9~pS3Mtzw%&RV57eal*2Vvge7fV#=>Z-WA|hQI37e>z^0K*wtbicq2G z!3UQ6o1GZO#MZ6hHg!bYk6`FC$QB!^&{mgSYQ5P+D$w}h;4%2yyQZ$%PKrV{!8G3< zhEly)R@ynrr!yOdx@0W*+SD#`% z%9K>Xv`AuCRG8mYN&#-CH{I$~zT@mLxKSwLI~0nGhllO2(|Wot8SvM_s#Zf- z@yl+>o*ky5N87T5?oNtoH`!hFd5 z>^%lP(*A=rwt@WxDNUFfU!QXFeqaCz$BF;Y<77>oZ++S7yVfjt*s~1AtkhxQ9nk}_ zmz*zjUJ)qAzqjw`$_A=U@s1682}6F0We>VF=_m=euvGSNN9b`l&}ioAw?=X*oLx1o zHHlQ+x2bVu$&M7>X6cQM;kn}9)-!k9sU1duS1EVYLI6Ae*T6bVRZg)3gfaW$j#46c z6LPBT3rx@pZ(%P|SUb0ooSq9PQC%Z*-fvEwVKtu4u6lN^?k;YfV1rg}gqJ0HTaG#j z$lfOHdww{`q!EFG5!?2)TBKZGE+Y=BHAQ<7aE_mbNa4yU@1ikQJa6q8a2?;kowR-3 zN1XaB3HG&#w7hUEVJ6GsL9|HUb_k!0uW~@soVN9Q@}t;fT1fa{ixL^|VMKT2J+2PAFxzA!epuxIIas}MZj9`V)#Lj$ZiKjX& z$@d#Xm644d9am_o?xUw}tt5M)(?7s)w~>!Qk_o&dr#~fykfOLo7IFU=xH6ev+mK8$ z8H8A1`WY)ZN2YcrG+PF}1*6CRLr&tO^IK!BoK)30CL5eIaG!c0#c}~jlZ8g%K7Oyy@MOSl?AdeyEYVaiyrce1Mi@vS*Z1SA zF$>;9PyuGPYNi@(S9L>JYA$M5viimc8mZu5)f667SpKE45@}eA$ zAADaS?J#1=2YaIU_zXDq0!)clz;r+9$VmZRZk)uHu0H4?xo*TX9NvD&muKm9Rn}Es ztmG;CIwrsmr8(e)N@r*aLPIJQg99?X9AY+605lA zAYtM&3G3f2g7s(>sw0_IjOfy0r4c9Cz2*)ICsEeJVoOlK50oq88U(Y;J zW3wf-%onK1!3M*f-D@*$S#Z&6S#^8hj(u4h6==-I7)@LlE&usZnG))RjFx$9Hrx{^ zQEWV`P&bp)?)#7QQb)3+m(5|Thop6;^7QS4P;3g7_wi9zeEr#aZS@9b@ z_pq$4q%`qyqkIC=dd|#}x@Ip4V}@^~;&uq8OgCe(@c=<@J7x|p_Md^_pVFA$ddksR zobcc8XC?>HS+Dz%%)hXj%M%P0q>5!dZJQD*=|}a!w5G&>rl%AX(ba3KpR4MksC6`7 zWq-b#;AfB$d^Q65cDXuqxYm_VjL%{IoxDx)S>oi@U{Kn-vYM(f&}L4`>twz~>MWe- z`WclLwJlb(_^aj9cx||oTW+gif%~B(fa>mRe{6qkp8Yl!#Rc3Z0%t+~DJL0pMD!LHzHBg?Ft?(i~CP>s5xW?QwptkycYrwB+kV5lj zuD|;(K?41K67Bb}wI`JA3ox9(5N{pAOhD1at(rq!%)+E~;oUG8+E!_!f-E8_0OIlT z@fGak(%YDeGU63XGSaxJ=3jqSWQHjH{bh3O#FzeDW~<;=o>oC+(@ypxIEwoH4=dxnmGxt}F@pT8kwIBk#kb zK1|1Gm9|y2af^r}Mc>!BITqSE%rYFZu;(J!GR;cWkIPoEZa=~B&YY`99Y7}oe}_r^ zrIY@L><}oJDz<}AE^eAsN}JjbAW~o;MG+9Q%B5Z1MySHlw2EIOS1ij|(sB^KIU1Z~ zC9jEJJAHQTF;9l4$tC@oLW~fv`><<&XLW~i5tnTK2}{`H+6~3$bqQf!W0Y#S0g+x< zGNo?gz|931uwd2FW0GEW*LNjc^)2Bf#C$T}DDTA_wp0CK6Rd;E0($Y z??zeJEqn&{Fk<7qj0ywH)??6K$~23=%cI&sD!#PMWqGJ*9AjI(Vp@RU403z@zV}34 zMLOP?jx<FjvKfL7#v>hwB=!CKT2>TV$KIVm zpRkU5@a~;GFq=utux+4!HWPf|B=^7@*Jh)u)|Q6inQ-CTTbV5aPJ&u0AcHk`SP$Tt zg}+*~u#sQNO&>mz8&0`kzMUX=TNXBv)s>KsQEEw}3!<<&Gk`L*I$u!q%~Xe#xQYWDe4x!6d@T5^Gatqd}jK~*7j z-IlhNc0?E*Q`u65h-CDY)n@0oCrL3>d~v((YGW7ARmRO@YPHT<6E_Eho+ysZNH_nU z#7p#w)V%|sKD^^a2@VkZ&lvU(F6m~{9%u#!%)h*O-)n}B^eHz138Oo`g#nttRc4{u zry~qMf~8|xp{RxOP&+7e#84qZM6XUPjC65mwE;V!WeZ6~x2A})rIfT2R;w5*vyq{q z=S!T$#ZVg4L*NOX3HMj#gT1Uw@Aj+U<@gB-gc&M8VhE}qI8?zvBzNS>&F1t!FRA3 zm?HW)8Tu#e5kKlr|6q?ck^n~Wh3{eO86jz`?8`cOnq6TurCm@s$u|-Ue}L`_ z^VSij@%c_5t2@V)>16h#QO;JUrT5wrRy!(vlRcbJ)RZk&I9UyTl>Nm%dqdiLq2vkz z+{OhKLd62#5hFu}%Og`C-mg`5$Da{Xl|Lpw*BN?kcd>~682QPvUKEnX@U5Gf_OB!% zQ~`k9!1`Cb0p|THbAR>BKW?l5^UD9+SOIg~b!FwXQ(V^T0t+Lk=#fg`5z8`=7X#Sa z41y?DHIg(fRu6LG_A@&rWuGqOfy1TTbwHk9u8#h}7XIsi;AM6gETlR-I3#k@JTJu` z(Sx>{=K9UGfU)RwwaFnADp>ZpscwjZA($LUx`aQSOk6Yn5C$;Pe|Y)oXFKl?vH?t( zq4@}-H0+0Xq$BFDLUxj!K%>G_B6ha7uOTnJcs9#|sb-S1Jz}O)C%HM-^D8hI~2 zckp@I+OZ>1@*9_oCVvZe@z=O(;Sp%RR$%o!6tX`J zvzR~-YC|u&XBUWra3)Y>$*4BiFWiDvSo;V{Cv`hYZFa&>(4MI}0Y^D(fhSN0Qb!4U zt#+6q^3uWZNHk9c8!q%|?Sp6>Wd*im+mR&t;ia#MSYJQBp|{p8$ceQlV^yR&XyVrU zUE8udLm|!pKFi&ew1L2XP1@X5TW%U87aachrLlgIkeZNO!tQEnnVYY6&CE#nt5m)7 zYU)$w?C&kGxqpHD)_39})+FM`O6A0|EP$E-LobFj%YEfJ*~}&lTuBfo=U7+$h=JJ` zkgyyqk*TTS3n!&e!847sl`5jMW7;*1fs4;YSb^M_tQep+)6i?Fe_i#pVLORn4iNoc=mn;{D^{R2n1;?+5=CC>Txq`WR%OB^SC>2Jn zSU(eBI9M%zSWKP&nbyYG&7jfN!PD>K*@}t(5sLzKQ_Q;Tt0&4$Un^@Kms?-FXdY%Kl|hPh<@d#RJPQHKBuAGg@w500pp=6*yA# z26Mjwk7p&lvoM4_VhJh-b9fbSdXJDtrT842WL+SY;@!%O7-#k5Zte#C!La>|ZT@K3 ze#|NS9wHz>9u(l%7KcTzO|(J7Xv0*ymGaTOY!On9Y>d{* zs#eezJ-Y`j+tnep;_7%3P2`2Pndlq11?+TFIl-+J_)3X}O9IFu#m^|DbXPJy=^W$O zOQwq!(cIu>ihg1YsijQrHS1100%ihP**S5{8+7?9(d)qgJU3yF8o=z zINJ-e5S5)qn|l$ajyoQ|D`g|Oha?d|)!w_567^6+1VkLl+2Lq$OzdovscR|qnoU(6orU{kddS^3Yn4heScIw z=X}zy)BnHjN8Nfn?)&+;&UMatpZB<~*Xs+;sxKe^1gaM!dC5a9wD53#@Wq%8W17U< z&rDrv29Nhjw*`^B$H%st&m$Z3emDF|gKu@UYx=SWLr>${!>{WZ6-VcH$oYS!lq~8r z`o7ESNo}E$MfBa*LPNoLZh;5S(d?dCyW*!1;}FcrPn_RWl006n-AWnAn@*meDy4bD zxG+U?WwGyDT1)o5%#qx^EH9`v7!~*!uTKdZ?h8Jp_v8~xtY+#X?VKHKr!G}Il~1lS zV&pIx#D77Ol;hGStbISN!T3#E-oZ=b8T4X8F*xz(Dt8Xdir!lcXwuLs)lA_s`f@<> zNy?eMq@Z8tWLKx-i*G5dH^)1k|M#MQDmyH3VodynDCNgRHH}q_)!~f2oEkaEGfMpc z^UM$wGl-)f-#?6gpu`WAXiyP)6DCZn{GbTsG>DA zQV`i={+M4T3y*n9PLt!KSE^!#eWc~?*A-Jcdr!Da?mXFLe3yLX z#RJ_SvJi{vuNjSY=DR-VOGPmhmV)^*DR*m+f|fKEUb~58{TuQQ;np~Y-3xTa=h+pi zE81V=jnm#9ThJ?Yk^0|6hwcCpY<8kF*?SMUb9`#T=M0VmPT zQMdi?@5!OU81eYH8oNEfHI0F5`fV00is+KiN|b`ypmAH^-Op*TAW)>%YDdj=b@{R6 zaShJtfPvWZl(A)2LbTqF*GAU3@xt}@o}|_7P?1n(o@wS$zD)X*r}AksnYQLFeVua} z$xJGwGL$%lOtLd(#zrVv%5)#uxL=b}sG>AVzIbAdeQ^X_N!~Vkc;X@wfA9J7j8-E9 zb0~#xw@i4AqB5EY-VyJ^E&@d+dJZ1S@;V!JX;znR7!HiH-kQ2Gir3h);87nPHKTN| z$LkGsERL$2oaVwE683Cu+yC}=G7sj~pG{9M%l#m9gQ}zBi+dIs7e_IRr>8xwQ|dil8PN3 zzIfAhm8s}jTb0wA&|6$C!F7!9v|)Cc0!kfu_clvBP(O~YsrbX=41`uedoQSUb~!#{ zn38on9qhO&J)!XR})D9Ft!14+~Nr$)1-P z(+*Qfa$F9`=P#Y7v??!46OU+E?&4=$o9tTX8O@|WEgx4Gq<#HiKm*n{v5{=guD2Q@ zFD9tWo?kvx9Vndrl(#&V|Ks-{zf7CzFVQVn7;AUvG01N(tC+CZU(XA}|Nk5W={X1o z*V%3zFo1mCrpyu4cl~`sS@*0aj=+yyyGSvADJ**&O|8B)8C`DFth>Z5V$zIF*M?~% znBisb1$U|Yh9pv+wbMu0k3?s;EV!L{Y1bHVr|0F`luN};%jAnD@B8}|_8CsjjXFsW zFkQ)hdU@kOrA^i$rl#el`EeC2CH<6lc%qilBQ2>^M#M#5MZ{ZoI?luk)h$@8ADp?V zew{cHTkYAygwC5*Jnhf(v=7Gl9ZSh0;`|b`u5=r_SNnl;%Je{fr};@1=i@Z=)C_hv zoDMBZdA7#szN}Dr<8Zs-t-WBvJnPSP_?ES zo=g@F%`&zpcEWW$;UiqUJCi>Nzm351IKEgV`3yGY>o3+W21f^ME1rr(X$+UDMUu5V zCVR+xrh9SXc&dw-0mIz*&OyO;?$LI+ssvRRjgy=bt$Vy?jg*qg%nNwBF;+#ABdPJI z7d>vfL7ra_Jumpviw-+?Ry@WfrDUh2L-Bw}C1uYMFNXAIz1+T`V(-L`65qHtheLz? zDJ_*jnX9SOa&GeI0f%>&hL&3&cqrF1Ptm*9MX698aN&%(s+q@MFmm}!&~mANZUBSz zk-FiAfKS4!JtmzZyqY{5x0Sk^x^)Y4X+Ba{^r>;i(ygRxcaRs{@2zTj1fN|N%@E3= zPBT`wyEt)(kH8-$JzIrRKSU!0qufI`MI){gUuhrVOLE{EWQ>(w4e+`~3FM+1$Z#q6 zZ__-)C&j%&(|qoI@i7%guaZ|br9)E*1kzFuxMHMIcN0d{zq@xJsG?Tmve?_~*f=_a zV|gO>2W~D@HyzJ@5OJ#R(9ot*bPdsk-JT&ss-g4^a@UIVS3`>pRPTMokg%t4G%80q zmn?wam>+1cm_lz;{o(SUi>b|RDxePWW19+mpMO_Y$?f%ZEoEhAdrs7#w4WnV?L|r- zDV4er-3wAGlqelaB|;Ko3UMg>61F3Vju?DKF#G9+Ap2;42rw>E09BWv2tFcwS}JME z7JMw!YI|i?4=l#ZF$nleQ8QrT;omQd7Y|ljh~H*F?}+m+?`9<4a^8 z9J(~JX1>3EAAhMjyj7rN;z8qLgSzW34qlZr7dcEh7ef3phg_>NW3e%d2h+a{TsQXjbM?mpr{ z`o-{R|F@UZc-fyv8}~XYH83@Y${hT#Sq8AsvtjqGad~0Y%TPk1DWLwH&rM1lS@uxL z&K8sPHiy@!^5&4&H8Vei{$_#D-=2#dj>(rZP99LzPIEfc=(5ast3Pn0HJ7R|INV9| z)?SMQzwo1dOQ$WoHl_XuhVRf!$SpDA4L_NkP;si``Whctb0Nnk%u3-^T8@8wU+$N@ zG;6NV#j3|fwxAfG^=C0aRRkyoFjeQ;ECy)e$3I^9cB>e`_xECe22?SCTQ~Lyx)^{4 zRSbYJ$ewQc9OVF>BUCy0ZxarFQSrZ4{B0H}p(-11gZXDzj6cCeCPi|ejLfxtqmmI?e;p1pX2dy6sh#e)FfEmB2sF?WQ zCrn$*^ffGeLQ$y|JVT>=g7jdeOYi3b#Ba&bU7|i{-w6<#b>f zC6_=_MwNO6$R)_&H5Hv|*|*D5(C@;*>o)XqclZ=4E~gebo)jTfb9pPQt#)v*;!Gk9 z|7e}fYii&;JHTU+afqcNn`)m$;1f9l8{h~kcK@%@aVUmu;zPno&zyu!=aK- z-)Ge2;;0=D@7=L6@TTlT;+6TyinBfG0?%5OhgcMd`u2UDF1DU?9?WXAaXxAFH5{uH zn~~KxPM+J4nOaWTR5n|}oMRt##CksINq#Kuyl#_*-Z9^rXLt1ycnjvgVn~F2G2Ow2 zI+*XqcD?d>u80yA9)Of^i zaL&C_cK17a{KJt#?Z#azBGqT3_vg(SE9bAi}N)uE}X^;z*N zsgY%5dw_;CtJ<6ME$R$Nqeh!gAm z!|Mn$TZoSQjEtr)8VMlQoayH5jZTUeRCInK`CwNi6Z`4ULBG4k5M0oyBr@ zi=3r=jtm<&b+OJQ-P{+I-6d@mm zN9cT%c3e7{)>z$bd1>E%ysS%Yok<@UK9XEbiM++}iqp{H(~dF>{gn2Fyi`a<6^<0XJmztQRVAYQ;G;>V*sg<%4@u75YI{D`I3*Z1xh9!$GP{jSM*8vXT$4;Q z15f9tk`-xR*$Q&Y8W%P94pSEk@RS#1Bz3fTS;o(Ye*d`lYyxIkB8PVFIO_EJ;C8Q{ zgb4betEbdkT<<0f zFDJ^ATa^T#G%q*4D_40U$bEB(cOyMF@85Lo3x#pKEyhhMXp^Wpw_X~ z6B2nwJLgn_cQb2^XiemV0}HL;dEW`axXkYozNhUIE4kx6_?crHj$@5Z={MnXT@1ij z;5SoAV597JwrzhGl=$oJ1>Alo@Q3}*>TUu`*{@6YZ8bVs8NQ@n<#W3@7mbzR<~BGy z?=^5Il0so=#}l{ZbE7M}nJKh@{m!gUx1WEM12^s|d{0pDtb78$@#4{U;wm0%c)Fx? zssh~IR+IcbJVnEU#PPXdR0j(6KbBUW-e<0ApJJ1y^8Qj1Yn& zK{4Zl&x@{<%UjFyJ#5>x3x}a4s&ALCriOs!SP-z^sZwkW3%R)n?03e1{f-N;-?`K& zqWH45R?aI2lm%n#BKOQ@WT84wYPWs$A=)l~7^TD8o}dJM@ZVJ(p8?&c9RU+>fF_hY zO7G#zj7?d0_(bY_q}HPkyG%E#@7V1QYY&$>l4IUW`C&n%`ev>K*(;SKF0;&gR<-dp zBg(h30v)FLg6`WfW!s)>?P4UJ?X6U7SeUX<$i7rvpdk`A5o=npxgQktb3Z85FLT4S zf-T{HT7(MZeiorI;-bucDKP64deE#&e)p70WTX!eVi8mft&UpD6!wIO>~G1|c$ zB*^_xZEzafjqFhE=RZBS?VBB9KX)?&SxooU(!K#-;ri$hSsp&ZOr6Kc!xo3gtO-J*b{MTmK&^11=e+M%_tp9@H-uA zTU(aKMi;a?-Nm)^^NW%yJKnCxKAaShc5Y>+#;0YGFZXZ7e)aa+ajRo^Iy@xm5$jK0 zF6pz)LkwI|d)!H7f!|%gHEyR~3e?-t^?!f3fpGOw+J=i{9iI2tGxxs^Ah}_uW9ncD zbW41`eG;<$&%xU$;5@F543IA^WO%!J(aa=lZce(jzUpRo)-~?ob0mT}GJRB*5wY{> zW~X0h{g5xc%i`f{xp9q8?zxPTG%%m7Wu_fuE@*m ziPZBk#BEuV@{%-b>~C=hD=e^ZmQtPAC8{e^qk1Vj!HF%bE3oRq{)1k+=OSd=80B5S z;5pY-Rq1AQP77uRqYr{KXkFP7omGvd^&=R6RHCaYn@h5naVS`! z;N*iPrddX!k;RMjtYL+rGNfjt_-uhWVs|AUDVH!JvndIeNU! zWq{%1uTS5m@7IqB#W^FkH{7r7_*kqmubYIPYML2*mLaSpOT>z^^45BvXnE%_sjUBK zK#-lxC4$3@)6hwE&?Iu_sY?|OOgC1p+c05;#SlSVvr|7iN+}roF7xl*xr&0+z4;=%X5i*HQe z63n55JTB$sW+(g*@^C(Q7R#5cDH7C-;!zq{fCkEGk0 z>~^opoTupUr6T{##VmbS;B8Oi_`>`n+v=~o(qsgEbxW!zGCb4)XymW(oG12a18vTyhRdhamuTY(|M*kp3u!Z;DmR}Q}>X#@U*XwXjxINyL-ek;|n(-gTu>Q za}_Hb2eR-b$%+RRD%PwhH!zlTNjW@NsK!Spkm=usUC{Z6-rxDt2NJANA+~+>@5{k@ zKnJz_1`Wl720VF85By2rh{fPqPmhk^g%Q0kHL=Ha@II8 zu(5+AE0tt}_n9=y<&W|lIYk_zr&eScoWK{_)}wHPXE0xIdZtFjLC-fff%Rmuu2Jr| zm^JrW;L-A~3?DxDn3Srdsi6g~ND9=8V?H~ALJ;-jKV8(%f-jW9hSDNuGxj^y>$5(Q zGQ^7Sm&Cok^q+jqYTIBsoi7wKyu9SPg6m)FUhBbRINg{j^M*N&ly)Lr#`Y-VHQU;r z?9ZPIDCzm6WYll)liSm?m!%$HPw}V7x0~GK3jEEo3m$fRKghq+Z+LdlXf%Ssfa;sj zkzp!AZku+-h2FLzzmW@J7ZNNF8wMN_N}Zv6%UVffzvmX`L_jKO&>gSdV{yuXcZY*z zLX-s9Z#K$%B|k6J(TWVqnD8Z4sa9>k`)veP9M_9iRW`Ghb=uLMuODhw9$+>|Fd>qVb39`I^6BN6vk_q<@)fh1v5i-!h|*kN9_0<- zBB{XAXTofdvg0bqMD2;+#p|pUFM&&UHPqiW7n(`RGM6 z2k*N_CA&oxGJ4(|Q`J?UKlhA~e#p4g#f)VZ1GxJtn}O5Gi#PX1PtR~V-K`Yf%}&YdQx~3b%f7?qdstXl z)^x`Wv)%?Psz&|O4C*aQi3!6Cw=Q3JwO6giMA5+6zC@vT%tlP)5O;%)8qPibMZ)Pt z*8kX1CjE|Y3wJjBIV(5t^duum*fiS;B+Z-%=F&xp|;kxao^shno2ak5+m4lf{B2g;?}->=Lm>N z50lw=J{?s~o_GB`Vs$Oy8Y$bMMTO?wA9n`o&~^%*|8(J@;izuVZ07zU*=lROa`$Kh zWgfF6EJHey{;98TYpyhlh{!tkTXNpIvR+@DH9gQ{Xl0#+G1z@Mc4QGX0o$(48))sK z>#qMWMS-o~lww-PijT5XKHt>ZeJSQJc}kLLU*^0_TWf(|{ha=g_Y=P{9x+^2?>L;p zxXUYaZ+RY!rb+BfU#YDy;Rw-)bZ+K#JxrEzb;|SVm+vhj1Iw%>ugPTC(#D#lWuAv> zU0`kM#N)0ApnCFNR ze_z{pp6Iu!2PM$osLpxk6bRC$Oyb|(FR)6^dOZ|NK+tRLdIqHmZT!y9z;Z~rZ2l_! z2L5;VbKkk1`|POs^v%NKjvbEYjc@D1JLj<<3s)!0$g-Cd#`DzOvX8*E2=wF>iW-X` z5x-W>G!=3EW&eU=;Lgm%5Bc*8fdSUncmAhTsB7My6uCfsJa3xwx%ze1k_5{z9sLI7 zH;MJdsxS74o$egRf84)trfV)H)#kX?2D`jzKv0JdiDUqmD2md?RR+CJ3d~q;1Sus^r z-O_6Dqa+(gezFPU{!V@EYU4q!5TWd=iUJ4pc~sx{OywUmuu`(H-@q8%Cb;lL7(v2M zZ#VA}g}5dC;oIr_)0=7(cvFQcw14*=1m0AEBJ6>CCfhH_-#sc8aUs}I`{@;;KyrEW zjBj%bSF?Khdq#sl1SC!^yH~BYmS2!2rPR1e*E2-5c=zMC#HF^X`bI%e^80?K=;MMz z^JvjK;=?8O9S!FPwiBmLO3O)5PF_#?pm*Lnm{>Bwl4!)ER&(y_Lk+b!sw4Z< z>0}B6Di^#~65dNsE;(HyidNQ9%>88Woz~FYF`)Wl=9zoTrSunaqpd1MUR6HDkgTrz zY88Z1vPJ34V1Dg@Ug=*Co@~Me$iUVD?g}t&HZn8JA7PAU#KU7|#iinK^=dQH(%iqd z>RDLA3|#}6FZK7`%D9^{GpD{pTNs6@4ZTnkE1lE#d~1064moj1j$h0K$FNBb?HT2- zO?UbNHEb1^cBQSYomY(@i&UM(5<2Gc4hXr^eh0S;dj}&9=$Z$=#`U-qH-Gr~2R;_f z&!2Wtj8u$^b#K#vxv$nS|G_iC2p|}geL;ybg zz(0={1p>dRU|@E@|8dFoe3zY^EqH`of9}j8BR^huKJtsa2S(1oBnybT3jD0jL&h$n z8xuiQBN+hFUKpDNylcOrMy12f{(|j4ri90i>K}@5BB(0<`Jn@`qCRwgA&(m;AMyueC6HEX*b|`y z*89*{g#|=@Z4?1Cf}lT1Jas^wg{%WK{IQ@Vgrk8?C;A;h5cI7cz8XP5od&lGPF}<$ z^ZzQaN0tt!+xOH^N1i|0lc0&d0`4y~9bg|F{lFoJIis7v40U+Y^;2T>&oH-8J+ZYLZJ%p89fEFgO{jt$IO z<^gia=1Czm&B|nOvY_yYza9s{sA`$Z?PY9yHjX z{HKuv-{hW+Ie0Rnz&HU9dK!Z)Apv@Kwmv8bf`&V}Lm!U}FeXBuXtb|8vP{Dr*`Z`n zY7Fw0KRYrq++G|?uHW+;89mw|$Ohah8%ov&e}QHLVw{aEXt-B36wO5oN28sqk&)r9 z%uw=8Iyf2a(G18422!{KF_cWS4^Bq=5hIHkZo3O5+cLn(;46zB?-0ZcH^POIMHw;3 zXj@!lLBoA$p=b&wI2!Fri!9M_7gZ?v{(d+ah)4a?&;fTcg_8Z5;p8n}Q)J12dyhiF zTr6-f+KChy8SV%QB~N3JxBNkoWf|_s2?aMDfQJmWR?(AZ1P>kD_7Y02VZ|VCnP4JI z2Hdq0O4eh;Aa8kCBFhHcIuc6eIfzN#GLl4whTA7X(f)@p&|7AT$jETJLnxV-9Zudd zKSY*ixOX5FEXe@}3vD?GA|u1y`=DeBu-<}xQ_x<1$jETFIw;wL3r%N24YGkp&Ic)rXQ}{w9!lm`fRoV*^vGg{3%^6j*kGd<_MP35fk#G$>#ak{A27%e z^>t+T5H5obMdv8NgGP&@BMTZXIu0er9)pw766DBYhRR96H+6Taz{zNhZDcXSMWmrI zyQ;#;V!tG%k%bHwREC0|slmZ$d1YiF!$pmuR;J{$E1H z$YO@80z=7UnwaEY71_wha8X_;dHi?sKg~$tVz^Lp%W-(jVvwmWf=xTPhAR|oqYVe6 z6Ygp%z~V#LfZ{7;icxD+LnTzBd>@;}XG;Npx>GO->8c}uDh zSvKH`gHZAfaCi^BgJ}IhWMsG^Ae5}44=003BYIJYU{U~A#e)xgF(r7MsPAjCk$CW z;1XI;w3sm*jTY2G7BqCi0YAW^GQl9D)vS;O4VPj%{FAF$%OC|>y7%o`@1xs0C zfVTu}kfj-}90MiqzKB8I(vd+%hRdTs$pKavWVBccGBjMd1d3L?1V=-3Ops+7uGRrX z=Uc3=ivmjawZ$a=DiB1LXt*i_l&oX-8~LA(AmOqM zP%;-N9)W(qg|oT23Vpnn?{GrHp$S1_ zn--zy6$~`Gg%KGU-f#ycCtbq`8r^<}3=QvvgQCxPW1@d`#vvoa`_iD~Lq2daq)QE; z5j-C7W-usvr!O20wjV?(1+gy0ZgWI^eAnQ1S`}8Qn