From a1d95ab1459c3e3b0d8665e1232f5e51ac3abb0d Mon Sep 17 00:00:00 2001 From: Cameron Trando Date: Wed, 21 Aug 2019 18:02:44 -0700 Subject: [PATCH 01/16] Preliminary zip file --- .../Resolution/MainModuleResolution.cs | 5 +++- .../Resolution/ModuleResolutionBase.cs | 26 +++++++++++++++-- .../Impl/Interpreter/PythonLibraryPath.cs | 2 ++ src/Core/Impl/IO/PathUtils.cs | 1 + src/LanguageServer/Test/ImportsTests.cs | 19 ++++++++++++ .../TestData/AstAnalysis/Classes1.py | 27 ++++++++++++++++++ .../Zip/__pycache__/zipped.cpython-37.pyc | Bin 0 -> 475 bytes .../Zip/__pycache__/zippy.cpython-37.pyc | Bin 0 -> 488 bytes .../TestData/AstAnalysis/Zip/test.py | 4 +++ .../TestData/AstAnalysis/Zip/zip_user.py | 12 ++++++++ .../TestData/AstAnalysis/Zip/zipped.zip | Bin 0 -> 169 bytes 11 files changed, 93 insertions(+), 3 deletions(-) create mode 100644 src/UnitTests/TestData/AstAnalysis/Classes1.py create mode 100644 src/UnitTests/TestData/AstAnalysis/Zip/__pycache__/zipped.cpython-37.pyc create mode 100644 src/UnitTests/TestData/AstAnalysis/Zip/__pycache__/zippy.cpython-37.pyc create mode 100644 src/UnitTests/TestData/AstAnalysis/Zip/test.py create mode 100644 src/UnitTests/TestData/AstAnalysis/Zip/zip_user.py create mode 100644 src/UnitTests/TestData/AstAnalysis/Zip/zipped.zip diff --git a/src/Analysis/Ast/Impl/Modules/Resolution/MainModuleResolution.cs b/src/Analysis/Ast/Impl/Modules/Resolution/MainModuleResolution.cs index 86364d9dc..336afc82d 100644 --- a/src/Analysis/Ast/Impl/Modules/Resolution/MainModuleResolution.cs +++ b/src/Analysis/Ast/Impl/Modules/Resolution/MainModuleResolution.cs @@ -178,8 +178,11 @@ internal async Task ReloadSearchPaths(CancellationToken cancellationToken = defa var paths = await GetInterpreterSearchPathsAsync(cancellationToken); var (interpreterPaths, userPaths) = PythonLibraryPath.ClassifyPaths(Root, _fs, paths, Configuration.SearchPaths); + var stubCache = new StubCache(_services); + var cacheFolder = stubCache.StubCacheFolder; + InterpreterPaths = interpreterPaths.Select(p => p.Path); - _userPaths = userPaths.Select(p => p.Path); + _userPaths = userPaths.Select(p => p.Path).Add(Path.Combine(cacheFolder, "Zip")); _log?.Log(TraceEventType.Information, "Interpreter search paths:"); foreach (var s in InterpreterPaths) { diff --git a/src/Analysis/Ast/Impl/Modules/Resolution/ModuleResolutionBase.cs b/src/Analysis/Ast/Impl/Modules/Resolution/ModuleResolutionBase.cs index 110340cf6..61d88341d 100644 --- a/src/Analysis/Ast/Impl/Modules/Resolution/ModuleResolutionBase.cs +++ b/src/Analysis/Ast/Impl/Modules/Resolution/ModuleResolutionBase.cs @@ -16,6 +16,7 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; +using System.IO.Compression; using System.Linq; using System.Threading; using Microsoft.Python.Analysis.Caching; @@ -74,7 +75,7 @@ protected ModuleResolutionBase(string root, IServiceContainer services) { public IStubCache StubCache { get; protected set; } - public IPythonModule GetImportedModule(string name) + public IPythonModule GetImportedModule(string name) => Modules.TryGetValue(name, out var moduleRef) ? moduleRef.Value : _interpreter.ModuleResolution.GetSpecializedModule(name); public IPythonModule GetOrLoadModule(string name) { @@ -90,7 +91,7 @@ public IPythonModule GetOrLoadModule(string name) { moduleRef = Modules.GetOrAdd(name, new ModuleRef()); return moduleRef.GetOrCreate(name, this); } - + public ModulePath FindModule(string filePath) { var bestLibraryPath = string.Empty; @@ -105,11 +106,32 @@ public ModulePath FindModule(string filePath) { } protected void ReloadModulePaths(in IEnumerable rootPaths) { + var stubCache = new StubCache(_services); + var cacheFolder = stubCache.StubCacheFolder; + foreach (var moduleFile in rootPaths.Where(Directory.Exists).SelectMany(p => PathUtils.EnumerateFiles(_fs, p))) { + // check if zip file and then call PathUtils.GetFromZip which is also a generator + if (Path.GetExtension(moduleFile.FullName).Equals(".zip")) { + CreateZippedModulePath(cacheFolder, moduleFile); + continue; + } + + PathResolver.TryAddModulePath(moduleFile.FullName, moduleFile.Length, false, out _); + } + + foreach (var moduleFile in new[] { Path.Combine(cacheFolder, "Zip") }.Where(Directory.Exists).SelectMany(p => PathUtils.EnumerateFiles(_fs, p))) { PathResolver.TryAddModulePath(moduleFile.FullName, moduleFile.Length, false, out _); } } + private void CreateZippedModulePath(string cacheFolder, IFileSystemInfo file) { + var dest = Path.Combine(cacheFolder, "Zip", Path.GetFileNameWithoutExtension(file.FullName)); + if (!Directory.Exists(dest)) { + // Extract zip folder to stub directory + ZipFile.ExtractToDirectory(file.FullName, dest); + } + } + protected class ModuleRef { private readonly object _syncObj = new object(); private IPythonModule _module; diff --git a/src/Analysis/Core/Impl/Interpreter/PythonLibraryPath.cs b/src/Analysis/Core/Impl/Interpreter/PythonLibraryPath.cs index 7f04d8f3a..e6ebbeff1 100644 --- a/src/Analysis/Core/Impl/Interpreter/PythonLibraryPath.cs +++ b/src/Analysis/Core/Impl/Interpreter/PythonLibraryPath.cs @@ -221,6 +221,8 @@ IEnumerable fromUser Debug.Assert(!fromInterpreter.Any(p => !p.Path.PathEquals(PathUtils.NormalizePathAndTrim(p.Path)))); #endif + // TODO convert zip to regular folder + // Clean up user configured paths. // 1) Normalize paths. // 2) If a path isn't rooted, then root it relative to the workspace root. If there is no root, just continue. diff --git a/src/Core/Impl/IO/PathUtils.cs b/src/Core/Impl/IO/PathUtils.cs index 6bdaca414..26039dece 100644 --- a/src/Core/Impl/IO/PathUtils.cs +++ b/src/Core/Impl/IO/PathUtils.cs @@ -283,6 +283,7 @@ public static IEnumerable EnumerateFiles(IFileSystem fileSystem, stri dirs = dirs.Concat(EnumerateDirectories(fileSystem, root, true, false)); } + // TODO convert here from zip to regular file foreach (var dir in dirs) { var fullDir = Path.IsPathRooted(dir) ? dir : root + dir; IFileInfo[] files = null; diff --git a/src/LanguageServer/Test/ImportsTests.cs b/src/LanguageServer/Test/ImportsTests.cs index ab7d34a2a..15cb34173 100644 --- a/src/LanguageServer/Test/ImportsTests.cs +++ b/src/LanguageServer/Test/ImportsTests.cs @@ -19,6 +19,8 @@ using Microsoft.Python.Analysis; using Microsoft.Python.Analysis.Analyzer; using Microsoft.Python.Analysis.Documents; +using Microsoft.Python.Analysis.Tests.FluentAssertions; +using Microsoft.Python.Analysis.Types; using Microsoft.Python.Core.Text; using Microsoft.Python.LanguageServer.Completion; using Microsoft.Python.LanguageServer.Sources; @@ -830,5 +832,22 @@ import module2 comps = cs.GetCompletions(analysis, new SourceLocation(4, 9)); comps.Should().HaveLabels("Y"); } + + [TestMethod, Priority(0)] + public async Task ZipFiles() { + var root = GetAnalysisTestDataFilesPath(); + await CreateServicesAsync(root, PythonVersions.LatestAvailable3X); + var rdt = Services.GetService(); + var analyzer = Services.GetService(); + + var uriPath = Path.Combine(root, "Zip", "zip_user.py"); + var code = await File.ReadAllTextAsync(uriPath); + var moduleUri = TestData.GetTestSpecificUri(uriPath); + var module = rdt.OpenDocument(moduleUri, code); + + await analyzer.WaitForCompleteAnalysisAsync(); + var analysis = await module.GetAnalysisAsync(-1); + analysis.Should().HaveVariable("i").OfType(BuiltinTypeId.Int); + } } } diff --git a/src/UnitTests/TestData/AstAnalysis/Classes1.py b/src/UnitTests/TestData/AstAnalysis/Classes1.py new file mode 100644 index 000000000..3c6abdf26 --- /dev/null +++ b/src/UnitTests/TestData/AstAnalysis/Classes1.py @@ -0,0 +1,27 @@ +class C1: + """C1""" + pass + +class C2(object): pass +class C3(C2): pass +class C4(C1, C2, C3): pass + +C5 = C1 + +if True: + class D: pass + +if False: + class E: pass + +class F1: + class F2: pass + class F3: + if True: + class F4: pass + else: + class F5: pass + F6 = C1 + +def f(): + class X: pass diff --git a/src/UnitTests/TestData/AstAnalysis/Zip/__pycache__/zipped.cpython-37.pyc b/src/UnitTests/TestData/AstAnalysis/Zip/__pycache__/zipped.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..48707d5c2e8e83305b6547733ff3a1b80d52a508 GIT binary patch literal 475 zcmZusu};G<5VaGxjjC2id<7X=Z%h?J1&OT;&?Ta>toSIAQYY9>rFNyC!4L2a{E1g4 zW;Q0y4J`{Ny?2*)_nf=waM&jp=kJTf6!S;;I7E!aCBmK}-4I0--63A0jHu|2q;Zb= zF^y3M=^r)12*~le~aAFOH zTa)v-F5Ep>XL;aj=_JQ(9=1hYgBsTx&m8LEG8-Wgx=pY@4&n?~PlV8N1w#0~5UWZx zWvB;2JU6mzJ0_TYTxjP{gpgWSPP(GfRtS?|>u>qC>ILm^^ZwpG9nifpOWXXP#V3>Y K{};jgg&;qD6lu}` literal 0 HcmV?d00001 diff --git a/src/UnitTests/TestData/AstAnalysis/Zip/__pycache__/zippy.cpython-37.pyc b/src/UnitTests/TestData/AstAnalysis/Zip/__pycache__/zippy.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a2512df1069f7559c7df33d416dfe416bf272d0e GIT binary patch literal 488 zcmZutu};G<5VaF0jjC2id<7la4?q>7EfQN6=n}cItk{%DsS|9cQo7R5;0IXvAP+1| z%xp}Y8(J1ldhagp?%BS~hr>RCcza*1=8!-9$1y@Et^wv8=oSei@E-6SWJm;eXcXq4 zpW-xq0g^-+7AOmrFrS5z$VdcJB#8)LuplDZlPnf7oY8Y(R@9#{cpT;<>|!l#qg9T7 z5BAw(0WbteAh6-|703}I%Lg5SdZ2H*xTH%XwV`&LbE~r*>j7g=4KKTn_GT9r%DOYgxKfqnwy2b0OefI#+oY>{UOWDP!}5JR Vzy~EAb@@MwOQzlZSKj*tKtJkKaM%C< literal 0 HcmV?d00001 diff --git a/src/UnitTests/TestData/AstAnalysis/Zip/test.py b/src/UnitTests/TestData/AstAnalysis/Zip/test.py new file mode 100644 index 000000000..431ee28ca --- /dev/null +++ b/src/UnitTests/TestData/AstAnalysis/Zip/test.py @@ -0,0 +1,4 @@ +class Zip: + a: int = 6 + def test(self) -> int: + pass diff --git a/src/UnitTests/TestData/AstAnalysis/Zip/zip_user.py b/src/UnitTests/TestData/AstAnalysis/Zip/zip_user.py new file mode 100644 index 000000000..61c1b77c6 --- /dev/null +++ b/src/UnitTests/TestData/AstAnalysis/Zip/zip_user.py @@ -0,0 +1,12 @@ +import sys + +#sys.path.insert(0, "/Users/t-catran/dev/python-language-server/src/UnitTests/TestData/AstAnalysis/Zip/zipped.zip") + +#print(sys.path) + +import zipped.zipped as zipped + + + +h = zipped.Zip() +i = h.a diff --git a/src/UnitTests/TestData/AstAnalysis/Zip/zipped.zip b/src/UnitTests/TestData/AstAnalysis/Zip/zipped.zip new file mode 100644 index 0000000000000000000000000000000000000000..d547d496905b35706cdd125d816c91f128e0adac GIT binary patch literal 169 zcmWIWW@Zs#U|`^2=qVNT-?%SW$rQ+Q0%A@euF5PZNKMfzsPsPPsiPOxaY|>yqacPR z7wy(FdxTh{S%VGCRZV>ts%+iive?2@-8b0rI-d%6ASV;6!`>K%0B=Sn5eD3*11(@+ Y1QB2Ww=2M#l?^1q2!!T9ItDBa0I4S Date: Thu, 22 Aug 2019 14:10:03 -0700 Subject: [PATCH 02/16] Refactoring and adding .egg support --- .../Resolution/MainModuleResolution.cs | 17 +++++++++----- .../Resolution/ModuleResolutionBase.cs | 21 ------------------ .../Ast/Test/PathClassificationTests.cs | 14 ++++++------ .../Impl/Interpreter/PythonLibraryPath.cs | 20 ++++++++++++----- src/Core/Impl/IO/FileSystem.cs | 2 ++ src/Core/Impl/IO/IFileSystem.cs | 1 + src/Core/Impl/IO/PathUtils.cs | 4 ++++ src/LanguageServer/Test/ImportsTests.cs | 21 ++++++++++++++++-- .../Zip/__pycache__/zipped.cpython-37.pyc | Bin 475 -> 0 bytes .../Zip/__pycache__/zippy.cpython-37.pyc | Bin 488 -> 0 bytes .../TestData/AstAnalysis/ZipEgg/egg_user.py | 10 +++++++++ .../TestData/AstAnalysis/ZipEgg/test.egg | Bin 0 -> 3338 bytes .../AstAnalysis/{Zip => ZipEgg}/test.py | 0 .../AstAnalysis/{Zip => ZipEgg}/zip_user.py | 2 +- .../AstAnalysis/{Zip => ZipEgg}/zipped.zip | Bin 15 files changed, 70 insertions(+), 42 deletions(-) delete mode 100644 src/UnitTests/TestData/AstAnalysis/Zip/__pycache__/zipped.cpython-37.pyc delete mode 100644 src/UnitTests/TestData/AstAnalysis/Zip/__pycache__/zippy.cpython-37.pyc create mode 100644 src/UnitTests/TestData/AstAnalysis/ZipEgg/egg_user.py create mode 100644 src/UnitTests/TestData/AstAnalysis/ZipEgg/test.egg rename src/UnitTests/TestData/AstAnalysis/{Zip => ZipEgg}/test.py (100%) rename src/UnitTests/TestData/AstAnalysis/{Zip => ZipEgg}/zip_user.py (84%) rename src/UnitTests/TestData/AstAnalysis/{Zip => ZipEgg}/zipped.zip (100%) diff --git a/src/Analysis/Ast/Impl/Modules/Resolution/MainModuleResolution.cs b/src/Analysis/Ast/Impl/Modules/Resolution/MainModuleResolution.cs index 336afc82d..c93f058ad 100644 --- a/src/Analysis/Ast/Impl/Modules/Resolution/MainModuleResolution.cs +++ b/src/Analysis/Ast/Impl/Modules/Resolution/MainModuleResolution.cs @@ -174,15 +174,14 @@ internal async Task LoadBuiltinTypesAsync(CancellationToken cancellationToken = internal async Task ReloadSearchPaths(CancellationToken cancellationToken = default) { var ps = _services.GetService(); + var sc = _services.GetService(); + var cacheFolder = sc.StubCacheFolder; var paths = await GetInterpreterSearchPathsAsync(cancellationToken); - var (interpreterPaths, userPaths) = PythonLibraryPath.ClassifyPaths(Root, _fs, paths, Configuration.SearchPaths); - - var stubCache = new StubCache(_services); - var cacheFolder = stubCache.StubCacheFolder; + var (interpreterPaths, userPaths, zipPaths) = PythonLibraryPath.ClassifyPaths(Root, _fs, paths, Configuration.SearchPaths); InterpreterPaths = interpreterPaths.Select(p => p.Path); - _userPaths = userPaths.Select(p => p.Path).Add(Path.Combine(cacheFolder, "Zip")); + _userPaths = userPaths.Select(p => p.Path); _log?.Log(TraceEventType.Information, "Interpreter search paths:"); foreach (var s in InterpreterPaths) { @@ -193,6 +192,14 @@ internal async Task ReloadSearchPaths(CancellationToken cancellationToken = defa foreach (var s in _userPaths) { _log?.Log(TraceEventType.Information, $" {s}"); } + + var zipFolder = Path.Combine(sc.StubCacheFolder, "ZipEgg"); + foreach (var s in zipPaths) { + var aliasedPath = PathUtils.GetZipPath(s.Path, zipFolder); + _fs.ExtractZip(s.Path, aliasedPath); + _userPaths = _userPaths.Add(aliasedPath); + _log?.Log(TraceEventType.Information, $" Aliased {s} => {aliasedPath}"); + } } public async Task ReloadAsync(CancellationToken cancellationToken = default) { diff --git a/src/Analysis/Ast/Impl/Modules/Resolution/ModuleResolutionBase.cs b/src/Analysis/Ast/Impl/Modules/Resolution/ModuleResolutionBase.cs index 61d88341d..b3e0181b7 100644 --- a/src/Analysis/Ast/Impl/Modules/Resolution/ModuleResolutionBase.cs +++ b/src/Analysis/Ast/Impl/Modules/Resolution/ModuleResolutionBase.cs @@ -106,30 +106,9 @@ public ModulePath FindModule(string filePath) { } protected void ReloadModulePaths(in IEnumerable rootPaths) { - var stubCache = new StubCache(_services); - var cacheFolder = stubCache.StubCacheFolder; - foreach (var moduleFile in rootPaths.Where(Directory.Exists).SelectMany(p => PathUtils.EnumerateFiles(_fs, p))) { - // check if zip file and then call PathUtils.GetFromZip which is also a generator - if (Path.GetExtension(moduleFile.FullName).Equals(".zip")) { - CreateZippedModulePath(cacheFolder, moduleFile); - continue; - } - PathResolver.TryAddModulePath(moduleFile.FullName, moduleFile.Length, false, out _); } - - foreach (var moduleFile in new[] { Path.Combine(cacheFolder, "Zip") }.Where(Directory.Exists).SelectMany(p => PathUtils.EnumerateFiles(_fs, p))) { - PathResolver.TryAddModulePath(moduleFile.FullName, moduleFile.Length, false, out _); - } - } - - private void CreateZippedModulePath(string cacheFolder, IFileSystemInfo file) { - var dest = Path.Combine(cacheFolder, "Zip", Path.GetFileNameWithoutExtension(file.FullName)); - if (!Directory.Exists(dest)) { - // Extract zip folder to stub directory - ZipFile.ExtractToDirectory(file.FullName, dest); - } } protected class ModuleRef { diff --git a/src/Analysis/Ast/Test/PathClassificationTests.cs b/src/Analysis/Ast/Test/PathClassificationTests.cs index b6dac71eb..fbb3703a4 100644 --- a/src/Analysis/Ast/Test/PathClassificationTests.cs +++ b/src/Analysis/Ast/Test/PathClassificationTests.cs @@ -52,7 +52,7 @@ public void Plain() { new PythonLibraryPath(venvSitePackages, PythonLibraryPathType.Site), }; - var (interpreterPaths, userPaths) = PythonLibraryPath.ClassifyPaths(root, _fs, fromInterpreter, Array.Empty()); + var (interpreterPaths, userPaths, zipPaths) = PythonLibraryPath.ClassifyPaths(root, _fs, fromInterpreter, Array.Empty()); interpreterPaths.Should().BeEquivalentToWithStrictOrdering(new[] { new PythonLibraryPath(venvLib, PythonLibraryPathType.StdLib), @@ -84,7 +84,7 @@ public void WithSrcDir() { "./src", }; - var (interpreterPaths, userPaths) = PythonLibraryPath.ClassifyPaths(root, _fs, fromInterpreter, fromUser); + var (interpreterPaths, userPaths, zipPaths) = PythonLibraryPath.ClassifyPaths(root, _fs, fromInterpreter, fromUser); interpreterPaths.Should().BeEquivalentToWithStrictOrdering(new[] { new PythonLibraryPath(venvLib, PythonLibraryPathType.StdLib), @@ -108,7 +108,7 @@ public void NormalizeUser() { "./src/", }; - var (interpreterPaths, userPaths) = PythonLibraryPath.ClassifyPaths(root, _fs, Array.Empty(), fromUser); + var (interpreterPaths, userPaths, zipPaths) = PythonLibraryPath.ClassifyPaths(root, _fs, Array.Empty(), fromUser); interpreterPaths.Should().BeEmpty(); @@ -134,7 +134,7 @@ public void NestedUser() { "./src/foo", }; - var (interpreterPaths, userPaths) = PythonLibraryPath.ClassifyPaths(root, _fs, Array.Empty(), fromUser); + var (interpreterPaths, userPaths, zipPaths) = PythonLibraryPath.ClassifyPaths(root, _fs, Array.Empty(), fromUser); interpreterPaths.Should().BeEmpty(); @@ -163,7 +163,7 @@ public void NestedUserOrdering() { "./src/something", }; - var (interpreterPaths, userPaths) = PythonLibraryPath.ClassifyPaths(root, _fs, Array.Empty(), fromUser); + var (interpreterPaths, userPaths, zipPaths) = PythonLibraryPath.ClassifyPaths(root, _fs, Array.Empty(), fromUser); interpreterPaths.Should().BeEmpty(); @@ -200,7 +200,7 @@ public void InsideStdLib() { "./venv/Lib/site-packages/what", }; - var (interpreterPaths, userPaths) = PythonLibraryPath.ClassifyPaths(root, _fs, fromInterpreter, fromUser); + var (interpreterPaths, userPaths, zipPaths) = PythonLibraryPath.ClassifyPaths(root, _fs, fromInterpreter, fromUser); interpreterPaths.Should().BeEquivalentToWithStrictOrdering(new[] { new PythonLibraryPath(venvLib, PythonLibraryPathType.StdLib), @@ -236,7 +236,7 @@ public void SiteOutsideStdlib() { "./src", }; - var (interpreterPaths, userPaths) = PythonLibraryPath.ClassifyPaths(root, _fs, fromInterpreter, fromUser); + var (interpreterPaths, userPaths, zipPaths) = PythonLibraryPath.ClassifyPaths(root, _fs, fromInterpreter, fromUser); interpreterPaths.Should().BeEquivalentToWithStrictOrdering(new[] { new PythonLibraryPath(venvLib, PythonLibraryPathType.StdLib), diff --git a/src/Analysis/Core/Impl/Interpreter/PythonLibraryPath.cs b/src/Analysis/Core/Impl/Interpreter/PythonLibraryPath.cs index e6ebbeff1..1859855d1 100644 --- a/src/Analysis/Core/Impl/Interpreter/PythonLibraryPath.cs +++ b/src/Analysis/Core/Impl/Interpreter/PythonLibraryPath.cs @@ -210,11 +210,12 @@ public static async Task> GetSearchPathsFromInterpreterA } } - public static (ImmutableArray interpreterPaths, ImmutableArray userPaths) ClassifyPaths( - string root, - IFileSystem fs, - IEnumerable fromInterpreter, - IEnumerable fromUser + public static (ImmutableArray interpreterPaths, ImmutableArray userPaths, ImmutableArray zipPaths) + ClassifyPaths( + string root, + IFileSystem fs, + IEnumerable fromInterpreter, + IEnumerable fromUser ) { #if DEBUG Debug.Assert(root == null || root.PathEquals(PathUtils.NormalizePathAndTrim(root))); @@ -245,6 +246,7 @@ IEnumerable fromUser // Pull out stdlib paths, and make them always be interpreter paths. var interpreterPaths = stdlib; var userPaths = ImmutableArray.Empty; + var zipEggPaths = ImmutableArray.Empty; var allPaths = fromUserList.Select(p => new PythonLibraryPath(p)) .Concat(withoutStdlib.Where(p => !p.Path.PathEquals(root))); @@ -268,10 +270,16 @@ IEnumerable fromUser continue; } + // If path is a zip file, add to zip paths and handle separately + if(IOPath.GetExtension(p.Path).Equals(".zip") || IOPath.GetExtension(p.Path).Equals(".egg")) { + zipEggPaths = zipEggPaths.Add(p); + continue; + } + userPaths = userPaths.Add(p); } - return (interpreterPaths, userPaths); + return (interpreterPaths, userPaths, zipEggPaths); } public override bool Equals(object obj) => obj is PythonLibraryPath other && Equals(other); diff --git a/src/Core/Impl/IO/FileSystem.cs b/src/Core/Impl/IO/FileSystem.cs index a88edb77c..8bcdcce04 100644 --- a/src/Core/Impl/IO/FileSystem.cs +++ b/src/Core/Impl/IO/FileSystem.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; +using System.IO.Compression; using Microsoft.Python.Core.OS; namespace Microsoft.Python.Core.IO { @@ -47,6 +48,7 @@ public Version GetFileVersion(string path) { public void DeleteDirectory(string path, bool recursive) => Directory.Delete(path, recursive); public string[] GetFileSystemEntries(string path, string searchPattern, SearchOption options) => Directory.GetFileSystemEntries(path, searchPattern, options); public void CreateDirectory(string path) => Directory.CreateDirectory(path); + public void ExtractZip(string source, string dest) => ZipFile.ExtractToDirectory(source, dest); public string[] GetFiles(string path) => Directory.GetFiles(path); public string[] GetFiles(string path, string pattern) => Directory.GetFiles(path, pattern); public string[] GetFiles(string path, string pattern, SearchOption option) => Directory.GetFiles(path, pattern, option); diff --git a/src/Core/Impl/IO/IFileSystem.cs b/src/Core/Impl/IO/IFileSystem.cs index 509c7c282..338c424b6 100644 --- a/src/Core/Impl/IO/IFileSystem.cs +++ b/src/Core/Impl/IO/IFileSystem.cs @@ -48,6 +48,7 @@ public interface IFileSystem { void DeleteDirectory(string path, bool recursive); string[] GetFileSystemEntries(string path, string searchPattern, SearchOption options); void CreateDirectory(string path); + void ExtractZip(string source, string dest); string[] GetFiles(string path); string[] GetFiles(string path, string pattern); diff --git a/src/Core/Impl/IO/PathUtils.cs b/src/Core/Impl/IO/PathUtils.cs index 26039dece..e867270af 100644 --- a/src/Core/Impl/IO/PathUtils.cs +++ b/src/Core/Impl/IO/PathUtils.cs @@ -436,5 +436,9 @@ public static string NormalizePath(string path) { } public static string NormalizePathAndTrim(string path) => TrimEndSeparator(NormalizePath(path)); + + public static string GetZipPath(string zipPath, string cacheFolder) { + return Path.Combine(cacheFolder, Path.GetFileNameWithoutExtension(zipPath)); + } } } diff --git a/src/LanguageServer/Test/ImportsTests.cs b/src/LanguageServer/Test/ImportsTests.cs index 15cb34173..a1fcdfe65 100644 --- a/src/LanguageServer/Test/ImportsTests.cs +++ b/src/LanguageServer/Test/ImportsTests.cs @@ -836,11 +836,28 @@ import module2 [TestMethod, Priority(0)] public async Task ZipFiles() { var root = GetAnalysisTestDataFilesPath(); - await CreateServicesAsync(root, PythonVersions.LatestAvailable3X); + await CreateServicesAsync(root, PythonVersions.LatestAvailable3X, searchPaths: new[] { root, Path.Combine(root, "ZipEgg", "zipped.zip") }); + var rdt = Services.GetService(); + var analyzer = Services.GetService(); + + var uriPath = Path.Combine(root, "ZipEgg", "zip_user.py"); + var code = await File.ReadAllTextAsync(uriPath); + var moduleUri = TestData.GetTestSpecificUri(uriPath); + var module = rdt.OpenDocument(moduleUri, code); + + await analyzer.WaitForCompleteAnalysisAsync(); + var analysis = await module.GetAnalysisAsync(-1); + analysis.Should().HaveVariable("i").OfType(BuiltinTypeId.Int); + } + + [TestMethod, Priority(0)] + public async Task EggFiles() { + var root = GetAnalysisTestDataFilesPath(); + await CreateServicesAsync(root, PythonVersions.LatestAvailable3X, searchPaths: new[] { root, Path.Combine(root, "ZipEgg", "test.egg") }); var rdt = Services.GetService(); var analyzer = Services.GetService(); - var uriPath = Path.Combine(root, "Zip", "zip_user.py"); + var uriPath = Path.Combine(root, "ZipEgg", "egg_user.py"); var code = await File.ReadAllTextAsync(uriPath); var moduleUri = TestData.GetTestSpecificUri(uriPath); var module = rdt.OpenDocument(moduleUri, code); diff --git a/src/UnitTests/TestData/AstAnalysis/Zip/__pycache__/zipped.cpython-37.pyc b/src/UnitTests/TestData/AstAnalysis/Zip/__pycache__/zipped.cpython-37.pyc deleted file mode 100644 index 48707d5c2e8e83305b6547733ff3a1b80d52a508..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 475 zcmZusu};G<5VaGxjjC2id<7X=Z%h?J1&OT;&?Ta>toSIAQYY9>rFNyC!4L2a{E1g4 zW;Q0y4J`{Ny?2*)_nf=waM&jp=kJTf6!S;;I7E!aCBmK}-4I0--63A0jHu|2q;Zb= zF^y3M=^r)12*~le~aAFOH zTa)v-F5Ep>XL;aj=_JQ(9=1hYgBsTx&m8LEG8-Wgx=pY@4&n?~PlV8N1w#0~5UWZx zWvB;2JU6mzJ0_TYTxjP{gpgWSPP(GfRtS?|>u>qC>ILm^^ZwpG9nifpOWXXP#V3>Y K{};jgg&;qD6lu}` diff --git a/src/UnitTests/TestData/AstAnalysis/Zip/__pycache__/zippy.cpython-37.pyc b/src/UnitTests/TestData/AstAnalysis/Zip/__pycache__/zippy.cpython-37.pyc deleted file mode 100644 index a2512df1069f7559c7df33d416dfe416bf272d0e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 488 zcmZutu};G<5VaF0jjC2id<7la4?q>7EfQN6=n}cItk{%DsS|9cQo7R5;0IXvAP+1| z%xp}Y8(J1ldhagp?%BS~hr>RCcza*1=8!-9$1y@Et^wv8=oSei@E-6SWJm;eXcXq4 zpW-xq0g^-+7AOmrFrS5z$VdcJB#8)LuplDZlPnf7oY8Y(R@9#{cpT;<>|!l#qg9T7 z5BAw(0WbteAh6-|703}I%Lg5SdZ2H*xTH%XwV`&LbE~r*>j7g=4KKTn_GT9r%DOYgxKfqnwy2b0OefI#+oY>{UOWDP!}5JR Vzy~EAb@@MwOQzlZSKj*tKtJkKaM%C< diff --git a/src/UnitTests/TestData/AstAnalysis/ZipEgg/egg_user.py b/src/UnitTests/TestData/AstAnalysis/ZipEgg/egg_user.py new file mode 100644 index 000000000..ea19d570a --- /dev/null +++ b/src/UnitTests/TestData/AstAnalysis/ZipEgg/egg_user.py @@ -0,0 +1,10 @@ +import sys + +#sys.path.insert(0, "/Users/t-catran/dev/python-language-server/src/UnitTests/TestData/AstAnalysis/ZipEgg/test-0.1-py3.7.egg") + +#print(sys.path) + +import test.a + +a = test.a.A() +i = a.test() diff --git a/src/UnitTests/TestData/AstAnalysis/ZipEgg/test.egg b/src/UnitTests/TestData/AstAnalysis/ZipEgg/test.egg new file mode 100644 index 0000000000000000000000000000000000000000..2ae9babc1274238f04d9b3b68fe20c6d2ac843e0 GIT binary patch literal 3338 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 E0Kunj2LJ#7 literal 0 HcmV?d00001 diff --git a/src/UnitTests/TestData/AstAnalysis/Zip/test.py b/src/UnitTests/TestData/AstAnalysis/ZipEgg/test.py similarity index 100% rename from src/UnitTests/TestData/AstAnalysis/Zip/test.py rename to src/UnitTests/TestData/AstAnalysis/ZipEgg/test.py diff --git a/src/UnitTests/TestData/AstAnalysis/Zip/zip_user.py b/src/UnitTests/TestData/AstAnalysis/ZipEgg/zip_user.py similarity index 84% rename from src/UnitTests/TestData/AstAnalysis/Zip/zip_user.py rename to src/UnitTests/TestData/AstAnalysis/ZipEgg/zip_user.py index 61c1b77c6..deef80f64 100644 --- a/src/UnitTests/TestData/AstAnalysis/Zip/zip_user.py +++ b/src/UnitTests/TestData/AstAnalysis/ZipEgg/zip_user.py @@ -4,7 +4,7 @@ #print(sys.path) -import zipped.zipped as zipped +import zipped diff --git a/src/UnitTests/TestData/AstAnalysis/Zip/zipped.zip b/src/UnitTests/TestData/AstAnalysis/ZipEgg/zipped.zip similarity index 100% rename from src/UnitTests/TestData/AstAnalysis/Zip/zipped.zip rename to src/UnitTests/TestData/AstAnalysis/ZipEgg/zipped.zip From e1eb8866417447befc8cbd1e49f05db6a1a1732a Mon Sep 17 00:00:00 2001 From: Cameron Trando Date: Fri, 23 Aug 2019 10:47:48 -0700 Subject: [PATCH 03/16] refactoring --- .../Resolution/MainModuleResolution.cs | 2 +- .../Resolution/ModuleResolutionBase.cs | 3 --- .../Impl/Interpreter/PythonLibraryPath.cs | 9 +++---- .../TestData/AstAnalysis/Classes1.py | 27 ------------------- .../TestData/AstAnalysis/ZipEgg/egg_user.py | 5 ---- .../TestData/AstAnalysis/ZipEgg/zip_user.py | 7 ----- 6 files changed, 5 insertions(+), 48 deletions(-) delete mode 100644 src/UnitTests/TestData/AstAnalysis/Classes1.py diff --git a/src/Analysis/Ast/Impl/Modules/Resolution/MainModuleResolution.cs b/src/Analysis/Ast/Impl/Modules/Resolution/MainModuleResolution.cs index c93f058ad..49289df52 100644 --- a/src/Analysis/Ast/Impl/Modules/Resolution/MainModuleResolution.cs +++ b/src/Analysis/Ast/Impl/Modules/Resolution/MainModuleResolution.cs @@ -195,7 +195,7 @@ internal async Task ReloadSearchPaths(CancellationToken cancellationToken = defa var zipFolder = Path.Combine(sc.StubCacheFolder, "ZipEgg"); foreach (var s in zipPaths) { - var aliasedPath = PathUtils.GetZipPath(s.Path, zipFolder); + var aliasedPath = Path.Combine(zipFolder, Path.GetFileNameWithoutExtension(s.Path)); _fs.ExtractZip(s.Path, aliasedPath); _userPaths = _userPaths.Add(aliasedPath); _log?.Log(TraceEventType.Information, $" Aliased {s} => {aliasedPath}"); diff --git a/src/Analysis/Ast/Impl/Modules/Resolution/ModuleResolutionBase.cs b/src/Analysis/Ast/Impl/Modules/Resolution/ModuleResolutionBase.cs index b3e0181b7..d5a0ae64f 100644 --- a/src/Analysis/Ast/Impl/Modules/Resolution/ModuleResolutionBase.cs +++ b/src/Analysis/Ast/Impl/Modules/Resolution/ModuleResolutionBase.cs @@ -16,13 +16,10 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; -using System.IO.Compression; using System.Linq; -using System.Threading; using Microsoft.Python.Analysis.Caching; using Microsoft.Python.Analysis.Core.DependencyResolution; using Microsoft.Python.Analysis.Core.Interpreter; -using Microsoft.Python.Analysis.Documents; using Microsoft.Python.Analysis.Types; using Microsoft.Python.Core; using Microsoft.Python.Core.Collections; diff --git a/src/Analysis/Core/Impl/Interpreter/PythonLibraryPath.cs b/src/Analysis/Core/Impl/Interpreter/PythonLibraryPath.cs index 1859855d1..52cc98b65 100644 --- a/src/Analysis/Core/Impl/Interpreter/PythonLibraryPath.cs +++ b/src/Analysis/Core/Impl/Interpreter/PythonLibraryPath.cs @@ -222,8 +222,6 @@ IEnumerable fromUser Debug.Assert(!fromInterpreter.Any(p => !p.Path.PathEquals(PathUtils.NormalizePathAndTrim(p.Path)))); #endif - // TODO convert zip to regular folder - // Clean up user configured paths. // 1) Normalize paths. // 2) If a path isn't rooted, then root it relative to the workspace root. If there is no root, just continue. @@ -246,7 +244,7 @@ IEnumerable fromUser // Pull out stdlib paths, and make them always be interpreter paths. var interpreterPaths = stdlib; var userPaths = ImmutableArray.Empty; - var zipEggPaths = ImmutableArray.Empty; + var zipPaths = ImmutableArray.Empty; var allPaths = fromUserList.Select(p => new PythonLibraryPath(p)) .Concat(withoutStdlib.Where(p => !p.Path.PathEquals(root))); @@ -271,15 +269,16 @@ IEnumerable fromUser } // If path is a zip file, add to zip paths and handle separately + // Egg file counts as a zip if(IOPath.GetExtension(p.Path).Equals(".zip") || IOPath.GetExtension(p.Path).Equals(".egg")) { - zipEggPaths = zipEggPaths.Add(p); + zipPaths = zipPaths.Add(p); continue; } userPaths = userPaths.Add(p); } - return (interpreterPaths, userPaths, zipEggPaths); + return (interpreterPaths, userPaths, zipPaths); } public override bool Equals(object obj) => obj is PythonLibraryPath other && Equals(other); diff --git a/src/UnitTests/TestData/AstAnalysis/Classes1.py b/src/UnitTests/TestData/AstAnalysis/Classes1.py deleted file mode 100644 index 3c6abdf26..000000000 --- a/src/UnitTests/TestData/AstAnalysis/Classes1.py +++ /dev/null @@ -1,27 +0,0 @@ -class C1: - """C1""" - pass - -class C2(object): pass -class C3(C2): pass -class C4(C1, C2, C3): pass - -C5 = C1 - -if True: - class D: pass - -if False: - class E: pass - -class F1: - class F2: pass - class F3: - if True: - class F4: pass - else: - class F5: pass - F6 = C1 - -def f(): - class X: pass diff --git a/src/UnitTests/TestData/AstAnalysis/ZipEgg/egg_user.py b/src/UnitTests/TestData/AstAnalysis/ZipEgg/egg_user.py index ea19d570a..23ecb90c4 100644 --- a/src/UnitTests/TestData/AstAnalysis/ZipEgg/egg_user.py +++ b/src/UnitTests/TestData/AstAnalysis/ZipEgg/egg_user.py @@ -1,9 +1,4 @@ import sys - -#sys.path.insert(0, "/Users/t-catran/dev/python-language-server/src/UnitTests/TestData/AstAnalysis/ZipEgg/test-0.1-py3.7.egg") - -#print(sys.path) - import test.a a = test.a.A() diff --git a/src/UnitTests/TestData/AstAnalysis/ZipEgg/zip_user.py b/src/UnitTests/TestData/AstAnalysis/ZipEgg/zip_user.py index deef80f64..fd909c37f 100644 --- a/src/UnitTests/TestData/AstAnalysis/ZipEgg/zip_user.py +++ b/src/UnitTests/TestData/AstAnalysis/ZipEgg/zip_user.py @@ -1,12 +1,5 @@ import sys - -#sys.path.insert(0, "/Users/t-catran/dev/python-language-server/src/UnitTests/TestData/AstAnalysis/Zip/zipped.zip") - -#print(sys.path) - import zipped - - h = zipped.Zip() i = h.a From e9e5c729ec25da692981bfe2728c8cc0aa837549 Mon Sep 17 00:00:00 2001 From: Cameron Trando Date: Fri, 23 Aug 2019 12:00:40 -0700 Subject: [PATCH 04/16] More refactoring --- src/Analysis/Ast/Impl/Caching/CacheFolders.cs | 11 ++++++---- src/Analysis/Ast/Impl/Caching/Class1.cs | 8 +++++++ .../Ast/Impl/Caching/Definitions/IZipCache.cs | 5 +++++ src/Analysis/Ast/Impl/Caching/StubCache.cs | 3 ++- .../Resolution/MainModuleResolution.cs | 13 ++++++++---- src/Analysis/Ast/Impl/get_search_paths.py | 21 ++++++++++++------- .../Impl/Interpreter/PythonLibraryPath.cs | 14 ++++++------- src/Core/Impl/IO/PathUtils.cs | 5 ----- src/LanguageServer/Test/ImportsTests.cs | 12 +++++------ 9 files changed, 56 insertions(+), 36 deletions(-) create mode 100644 src/Analysis/Ast/Impl/Caching/Class1.cs create mode 100644 src/Analysis/Ast/Impl/Caching/Definitions/IZipCache.cs diff --git a/src/Analysis/Ast/Impl/Caching/CacheFolders.cs b/src/Analysis/Ast/Impl/Caching/CacheFolders.cs index 3ee3508d0..f55e148da 100644 --- a/src/Analysis/Ast/Impl/Caching/CacheFolders.cs +++ b/src/Analysis/Ast/Impl/Caching/CacheFolders.cs @@ -38,10 +38,7 @@ public static string GetCacheFilePath(string root, string moduleName, string con return filePath; } - public static string GetCacheFolder(IServiceContainer services) { - var platform = services.GetService(); - var logger = services.GetService(); - + public static string GetCacheFolder(IOSPlatform platform, ILogger logger = null) { // Default. Not ideal on all platforms, but used as a fall back. var localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); var plsSubfolder = $"Microsoft{Path.DirectorySeparatorChar}Python Language Server"; @@ -103,6 +100,12 @@ public static string FileNameFromContent(string content) { .Replace('/', '_').Replace('+', '-'); } + /// + /// Given a path to a zip file, extracts it to a cache directory and returns the file path to that directory + /// + public static string GetZipCacheRoot(IOSPlatform platform) + => Path.Combine(GetCacheFolder(platform), "Zips/Eggs"); + public static string GetAnalysisCacheFilePath(string analysisRootFolder, string moduleName, string content, IFileSystem fs) => GetCacheFilePath(analysisRootFolder, moduleName, content, fs); diff --git a/src/Analysis/Ast/Impl/Caching/Class1.cs b/src/Analysis/Ast/Impl/Caching/Class1.cs new file mode 100644 index 000000000..f048076a5 --- /dev/null +++ b/src/Analysis/Ast/Impl/Caching/Class1.cs @@ -0,0 +1,8 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Microsoft.Python.Analysis.Caching { + class Class1 { + } +} diff --git a/src/Analysis/Ast/Impl/Caching/Definitions/IZipCache.cs b/src/Analysis/Ast/Impl/Caching/Definitions/IZipCache.cs new file mode 100644 index 000000000..95deef2af --- /dev/null +++ b/src/Analysis/Ast/Impl/Caching/Definitions/IZipCache.cs @@ -0,0 +1,5 @@ +namespace Microsoft.Python.Analysis.Caching.Definitions { + public interface IZipCache { + string ZipCacheFolder { get; } + } +} diff --git a/src/Analysis/Ast/Impl/Caching/StubCache.cs b/src/Analysis/Ast/Impl/Caching/StubCache.cs index 170bebd21..63de4ab02 100644 --- a/src/Analysis/Ast/Impl/Caching/StubCache.cs +++ b/src/Analysis/Ast/Impl/Caching/StubCache.cs @@ -20,6 +20,7 @@ using Microsoft.Python.Core; using Microsoft.Python.Core.IO; using Microsoft.Python.Core.Logging; +using Microsoft.Python.Core.OS; namespace Microsoft.Python.Analysis.Caching { internal sealed class StubCache : IStubCache { @@ -32,7 +33,7 @@ public StubCache(IServiceContainer services, string cacheRootFolder = null) { _fs = services.GetService(); _log = services.GetService(); - cacheRootFolder = cacheRootFolder ?? CacheFolders.GetCacheFolder(services); + cacheRootFolder = cacheRootFolder ?? CacheFolders.GetCacheFolder(services.GetService(), _log); StubCacheFolder = Path.Combine(cacheRootFolder, $"stubs.v{_stubCacheFormatVersion}"); } diff --git a/src/Analysis/Ast/Impl/Modules/Resolution/MainModuleResolution.cs b/src/Analysis/Ast/Impl/Modules/Resolution/MainModuleResolution.cs index 49289df52..452628e79 100644 --- a/src/Analysis/Ast/Impl/Modules/Resolution/MainModuleResolution.cs +++ b/src/Analysis/Ast/Impl/Modules/Resolution/MainModuleResolution.cs @@ -193,12 +193,17 @@ internal async Task ReloadSearchPaths(CancellationToken cancellationToken = defa _log?.Log(TraceEventType.Information, $" {s}"); } - var zipFolder = Path.Combine(sc.StubCacheFolder, "ZipEgg"); + _log?.Log(TraceEventType.Information, "Aliased search paths:"); + var zipRoot = CacheFolders.GetZipCacheRoot(_services.GetService()); foreach (var s in zipPaths) { - var aliasedPath = Path.Combine(zipFolder, Path.GetFileNameWithoutExtension(s.Path)); - _fs.ExtractZip(s.Path, aliasedPath); + // Alias ../test.zip => ../test folder + var aliasedPath = Path.Combine(zipRoot, Path.GetFileNameWithoutExtension(s.Path)); + if(!Directory.Exists(aliasedPath)) { + _fs.ExtractZip(s.Path, aliasedPath); + } + // User path has the .egg or .zip path, redirect it to have the new alias path _userPaths = _userPaths.Add(aliasedPath); - _log?.Log(TraceEventType.Information, $" Aliased {s} => {aliasedPath}"); + _log?.Log(TraceEventType.Information, $" {s.Path} => {aliasedPath}"); } } diff --git a/src/Analysis/Ast/Impl/get_search_paths.py b/src/Analysis/Ast/Impl/get_search_paths.py index 53cec1cf0..49cd42e2e 100644 --- a/src/Analysis/Ast/Impl/get_search_paths.py +++ b/src/Analysis/Ast/Impl/get_search_paths.py @@ -68,13 +68,18 @@ def clean(path): BEFORE_SITE.discard(None) AFTER_SITE.discard(None) +import zipfile + for p in sys.path: p = clean(p) - if os.path.isdir(p): - if p in BEFORE_SITE: - print("%s|stdlib|" % p) - elif p in AFTER_SITE: - if p in SITE_PKGS: - print("%s|site|" % p) - else: - print("%s|pth|" % p) + + if not os.path.isdir(p) and not (os.path.isfile(p) and zipfile.is_zipfile(p)): + continue + + if p in BEFORE_SITE: + print("%s|stdlib|" % p) + elif p in AFTER_SITE: + if p in SITE_PKGS: + print("%s|site|" % p) + else: + print("%s|pth|" % p) diff --git a/src/Analysis/Core/Impl/Interpreter/PythonLibraryPath.cs b/src/Analysis/Core/Impl/Interpreter/PythonLibraryPath.cs index 52cc98b65..b8e052ac3 100644 --- a/src/Analysis/Core/Impl/Interpreter/PythonLibraryPath.cs +++ b/src/Analysis/Core/Impl/Interpreter/PythonLibraryPath.cs @@ -210,7 +210,7 @@ public static async Task> GetSearchPathsFromInterpreterA } } - public static (ImmutableArray interpreterPaths, ImmutableArray userPaths, ImmutableArray zipPaths) + public static (ImmutableArray interpreterPaths, ImmutableArray userPaths, ImmutableArray zipPaths) ClassifyPaths( string root, IFileSystem fs, @@ -250,6 +250,11 @@ IEnumerable fromUser .Concat(withoutStdlib.Where(p => !p.Path.PathEquals(root))); foreach (var p in allPaths) { + // If path is a zip file, handle separately but still classify as user or interpreter + if (IOPath.GetExtension(p.Path).Equals(".zip") || IOPath.GetExtension(p.Path).Equals(".egg")) { + zipPaths = zipPaths.Add(p); + } + // If path is within a stdlib path, then treat it as interpreter. if (stdlib.Any(s => fs.IsPathUnderRoot(s.Path, p.Path))) { interpreterPaths = interpreterPaths.Add(p); @@ -268,13 +273,6 @@ IEnumerable fromUser continue; } - // If path is a zip file, add to zip paths and handle separately - // Egg file counts as a zip - if(IOPath.GetExtension(p.Path).Equals(".zip") || IOPath.GetExtension(p.Path).Equals(".egg")) { - zipPaths = zipPaths.Add(p); - continue; - } - userPaths = userPaths.Add(p); } diff --git a/src/Core/Impl/IO/PathUtils.cs b/src/Core/Impl/IO/PathUtils.cs index e867270af..6bdaca414 100644 --- a/src/Core/Impl/IO/PathUtils.cs +++ b/src/Core/Impl/IO/PathUtils.cs @@ -283,7 +283,6 @@ public static IEnumerable EnumerateFiles(IFileSystem fileSystem, stri dirs = dirs.Concat(EnumerateDirectories(fileSystem, root, true, false)); } - // TODO convert here from zip to regular file foreach (var dir in dirs) { var fullDir = Path.IsPathRooted(dir) ? dir : root + dir; IFileInfo[] files = null; @@ -436,9 +435,5 @@ public static string NormalizePath(string path) { } public static string NormalizePathAndTrim(string path) => TrimEndSeparator(NormalizePath(path)); - - public static string GetZipPath(string zipPath, string cacheFolder) { - return Path.Combine(cacheFolder, Path.GetFileNameWithoutExtension(zipPath)); - } } } diff --git a/src/LanguageServer/Test/ImportsTests.cs b/src/LanguageServer/Test/ImportsTests.cs index a1fcdfe65..b246959c2 100644 --- a/src/LanguageServer/Test/ImportsTests.cs +++ b/src/LanguageServer/Test/ImportsTests.cs @@ -835,12 +835,12 @@ import module2 [TestMethod, Priority(0)] public async Task ZipFiles() { - var root = GetAnalysisTestDataFilesPath(); - await CreateServicesAsync(root, PythonVersions.LatestAvailable3X, searchPaths: new[] { root, Path.Combine(root, "ZipEgg", "zipped.zip") }); + var root = Path.Combine(GetAnalysisTestDataFilesPath(), "ZipEgg"); + await CreateServicesAsync(root, PythonVersions.LatestAvailable3X, searchPaths: new[] { root, Path.Combine(root, "zipped.zip") }); var rdt = Services.GetService(); var analyzer = Services.GetService(); - var uriPath = Path.Combine(root, "ZipEgg", "zip_user.py"); + var uriPath = Path.Combine(root, "zip_user.py"); var code = await File.ReadAllTextAsync(uriPath); var moduleUri = TestData.GetTestSpecificUri(uriPath); var module = rdt.OpenDocument(moduleUri, code); @@ -852,12 +852,12 @@ public async Task ZipFiles() { [TestMethod, Priority(0)] public async Task EggFiles() { - var root = GetAnalysisTestDataFilesPath(); - await CreateServicesAsync(root, PythonVersions.LatestAvailable3X, searchPaths: new[] { root, Path.Combine(root, "ZipEgg", "test.egg") }); + var root = Path.Combine(GetAnalysisTestDataFilesPath(), "ZipEgg"); + await CreateServicesAsync(root, PythonVersions.LatestAvailable3X, searchPaths: new[] { root, Path.Combine(root, "test.egg") }); var rdt = Services.GetService(); var analyzer = Services.GetService(); - var uriPath = Path.Combine(root, "ZipEgg", "egg_user.py"); + var uriPath = Path.Combine(root, "egg_user.py"); var code = await File.ReadAllTextAsync(uriPath); var moduleUri = TestData.GetTestSpecificUri(uriPath); var module = rdt.OpenDocument(moduleUri, code); From 17924b1efc94a441618775d0304a43c0ddfca963 Mon Sep 17 00:00:00 2001 From: Cameron Trando Date: Fri, 23 Aug 2019 12:36:30 -0700 Subject: [PATCH 05/16] removing irrelevant classes --- src/Analysis/Ast/Impl/Caching/Class1.cs | 8 -------- src/Analysis/Ast/Impl/Caching/Definitions/IZipCache.cs | 5 ----- 2 files changed, 13 deletions(-) delete mode 100644 src/Analysis/Ast/Impl/Caching/Class1.cs delete mode 100644 src/Analysis/Ast/Impl/Caching/Definitions/IZipCache.cs diff --git a/src/Analysis/Ast/Impl/Caching/Class1.cs b/src/Analysis/Ast/Impl/Caching/Class1.cs deleted file mode 100644 index f048076a5..000000000 --- a/src/Analysis/Ast/Impl/Caching/Class1.cs +++ /dev/null @@ -1,8 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace Microsoft.Python.Analysis.Caching { - class Class1 { - } -} diff --git a/src/Analysis/Ast/Impl/Caching/Definitions/IZipCache.cs b/src/Analysis/Ast/Impl/Caching/Definitions/IZipCache.cs deleted file mode 100644 index 95deef2af..000000000 --- a/src/Analysis/Ast/Impl/Caching/Definitions/IZipCache.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace Microsoft.Python.Analysis.Caching.Definitions { - public interface IZipCache { - string ZipCacheFolder { get; } - } -} From 9eefbf7dbd3f92a670b44a66449c96a5f8980751 Mon Sep 17 00:00:00 2001 From: Cameron Trando Date: Fri, 23 Aug 2019 16:30:45 -0700 Subject: [PATCH 06/16] Preliminary working in memory --- .../Resolution/MainModuleResolution.cs | 2 ++ .../Resolution/ModuleResolutionBase.cs | 17 ++++++++++--- src/Core/Impl/IO/FileSystem.cs | 24 ++++++++++++++++++- src/Core/Impl/IO/PathUtils.cs | 21 ++++++++++++++++ 4 files changed, 60 insertions(+), 4 deletions(-) diff --git a/src/Analysis/Ast/Impl/Modules/Resolution/MainModuleResolution.cs b/src/Analysis/Ast/Impl/Modules/Resolution/MainModuleResolution.cs index 452628e79..85070eaa8 100644 --- a/src/Analysis/Ast/Impl/Modules/Resolution/MainModuleResolution.cs +++ b/src/Analysis/Ast/Impl/Modules/Resolution/MainModuleResolution.cs @@ -193,6 +193,7 @@ internal async Task ReloadSearchPaths(CancellationToken cancellationToken = defa _log?.Log(TraceEventType.Information, $" {s}"); } + /* _log?.Log(TraceEventType.Information, "Aliased search paths:"); var zipRoot = CacheFolders.GetZipCacheRoot(_services.GetService()); foreach (var s in zipPaths) { @@ -205,6 +206,7 @@ internal async Task ReloadSearchPaths(CancellationToken cancellationToken = defa _userPaths = _userPaths.Add(aliasedPath); _log?.Log(TraceEventType.Information, $" {s.Path} => {aliasedPath}"); } + */ } public async Task ReloadAsync(CancellationToken cancellationToken = default) { diff --git a/src/Analysis/Ast/Impl/Modules/Resolution/ModuleResolutionBase.cs b/src/Analysis/Ast/Impl/Modules/Resolution/ModuleResolutionBase.cs index d5a0ae64f..83ef9c43b 100644 --- a/src/Analysis/Ast/Impl/Modules/Resolution/ModuleResolutionBase.cs +++ b/src/Analysis/Ast/Impl/Modules/Resolution/ModuleResolutionBase.cs @@ -103,11 +103,22 @@ public ModulePath FindModule(string filePath) { } protected void ReloadModulePaths(in IEnumerable rootPaths) { - foreach (var moduleFile in rootPaths.Where(Directory.Exists).SelectMany(p => PathUtils.EnumerateFiles(_fs, p))) { - PathResolver.TryAddModulePath(moduleFile.FullName, moduleFile.Length, false, out _); + foreach (var root in rootPaths) { + if (Directory.Exists(root)) { + foreach (var moduleFile in PathUtils.EnumerateFiles(_fs, root)) { + PathResolver.TryAddModulePath(moduleFile.FullName, moduleFile.Length, false, out _); + } + } + + if (PathUtils.IsZipFile(root) && File.Exists(root)) { + foreach (var moduleFile in PathUtils.EnumerateZip(root)) { + if (!PathUtils.PathStartsWith(moduleFile.FullName, "EGG-INFO")) { + PathResolver.TryAddModulePath(Path.Combine(root, PathUtils.NormalizePath(moduleFile.FullName)), moduleFile.Length, false, out _); + } + } + } } } - protected class ModuleRef { private readonly object _syncObj = new object(); private IPythonModule _module; diff --git a/src/Core/Impl/IO/FileSystem.cs b/src/Core/Impl/IO/FileSystem.cs index 8bcdcce04..b7ca42c40 100644 --- a/src/Core/Impl/IO/FileSystem.cs +++ b/src/Core/Impl/IO/FileSystem.cs @@ -25,7 +25,29 @@ public long FileSize(string path) { return fileInfo.Length; } - public string ReadAllText(string path) => File.ReadAllText(path); + public string ReadAllText(string path) { + try { + return File.ReadAllText(path); + } catch (Exception ex) when (ex is UnauthorizedAccessException || ex is IOException || ex is ObjectDisposedException) { + return HandleZip(path); + } + } + + private string HandleZip(string path) { + var eggIndex = path.IndexOf(".egg\\"); + var zipIndex = path.IndexOf(".zip\\"); + + var endIndex = (eggIndex == -1 ? zipIndex : eggIndex); + if (endIndex >= 0) { + endIndex += 4; + var zipPath = path.Substring(0, endIndex); + var zipFilePath = path.Substring(endIndex + 1).Replace("\\", "/"); + + return PathUtils.GetZipEntryContent(zipPath, zipFilePath); + } + return null; + } + public void WriteAllText(string path, string content) => File.WriteAllText(path, content); public IEnumerable FileReadAllLines(string path) => File.ReadLines(path); public void FileWriteAllLines(string path, IEnumerable contents) => File.WriteAllLines(path, contents); diff --git a/src/Core/Impl/IO/PathUtils.cs b/src/Core/Impl/IO/PathUtils.cs index 6bdaca414..ac428ef56 100644 --- a/src/Core/Impl/IO/PathUtils.cs +++ b/src/Core/Impl/IO/PathUtils.cs @@ -14,8 +14,10 @@ // permissions and limitations under the License. using System; +using System.Collections; using System.Collections.Generic; using System.IO; +using System.IO.Compression; using System.Linq; using System.Runtime.InteropServices; using System.Threading; @@ -308,6 +310,20 @@ public static IEnumerable EnumerateFiles(IFileSystem fileSystem, stri } } + public static string GetZipEntryContent(string root, string filePath) { + using (var zip = ZipFile.OpenRead(root)) { + var zipFile = zip.GetEntry(filePath); + var reader = new StreamReader(zipFile.Open()); + return reader.ReadToEnd(); + } + } + + public static IEnumerable EnumerateZip(string root) { + using (var zip = ZipFile.OpenRead(root)) { + return zip.Entries.ToList(); + } + } + /// /// Deletes a file, making multiple attempts and suppressing any /// IO-related errors. @@ -435,5 +451,10 @@ public static string NormalizePath(string path) { } public static string NormalizePathAndTrim(string path) => TrimEndSeparator(NormalizePath(path)); + + public static bool IsZipFile(string file) { + var extension = Path.GetExtension(file); + return extension.Equals(".zip") || extension.Equals(".egg"); + } } } From a867af38d12a6be1b7f38563ae57a0738f147f97 Mon Sep 17 00:00:00 2001 From: Cameron Trando Date: Fri, 23 Aug 2019 17:12:40 -0700 Subject: [PATCH 07/16] More things to make it work --- src/Core/Impl/IO/FileSystem.cs | 9 +++++---- src/Core/Impl/IO/PathUtils.cs | 11 +++++++++++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/Core/Impl/IO/FileSystem.cs b/src/Core/Impl/IO/FileSystem.cs index b7ca42c40..a6715d042 100644 --- a/src/Core/Impl/IO/FileSystem.cs +++ b/src/Core/Impl/IO/FileSystem.cs @@ -29,15 +29,16 @@ public string ReadAllText(string path) { try { return File.ReadAllText(path); } catch (Exception ex) when (ex is UnauthorizedAccessException || ex is IOException || ex is ObjectDisposedException) { + if(PathUtils.IsContainedInZipFile(path) == -1) { + throw ex; + } + return HandleZip(path); } } private string HandleZip(string path) { - var eggIndex = path.IndexOf(".egg\\"); - var zipIndex = path.IndexOf(".zip\\"); - - var endIndex = (eggIndex == -1 ? zipIndex : eggIndex); + var endIndex = PathUtils.IsContainedInZipFile(path); if (endIndex >= 0) { endIndex += 4; var zipPath = path.Substring(0, endIndex); diff --git a/src/Core/Impl/IO/PathUtils.cs b/src/Core/Impl/IO/PathUtils.cs index ac428ef56..fc7063c06 100644 --- a/src/Core/Impl/IO/PathUtils.cs +++ b/src/Core/Impl/IO/PathUtils.cs @@ -456,5 +456,16 @@ public static bool IsZipFile(string file) { var extension = Path.GetExtension(file); return extension.Equals(".zip") || extension.Equals(".egg"); } + + /// + /// Returns index of zip file ending if file is contained inside a zip file or -1 if not + /// + /// + /// + public static int IsContainedInZipFile(string path) { + var eggIndex = path.IndexOf(".egg\\"); + var zipIndex = path.IndexOf(".zip\\"); + return (eggIndex == -1 ? zipIndex : eggIndex); + } } } From 773f0d6fc1bbab546a424d8f8d3dcedea72a9baa Mon Sep 17 00:00:00 2001 From: Cameron Trando Date: Fri, 23 Aug 2019 17:46:25 -0700 Subject: [PATCH 08/16] Getting rid of comment --- .../Modules/Resolution/MainModuleResolution.cs | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/Analysis/Ast/Impl/Modules/Resolution/MainModuleResolution.cs b/src/Analysis/Ast/Impl/Modules/Resolution/MainModuleResolution.cs index 85070eaa8..efea9c7b4 100644 --- a/src/Analysis/Ast/Impl/Modules/Resolution/MainModuleResolution.cs +++ b/src/Analysis/Ast/Impl/Modules/Resolution/MainModuleResolution.cs @@ -192,21 +192,6 @@ internal async Task ReloadSearchPaths(CancellationToken cancellationToken = defa foreach (var s in _userPaths) { _log?.Log(TraceEventType.Information, $" {s}"); } - - /* - _log?.Log(TraceEventType.Information, "Aliased search paths:"); - var zipRoot = CacheFolders.GetZipCacheRoot(_services.GetService()); - foreach (var s in zipPaths) { - // Alias ../test.zip => ../test folder - var aliasedPath = Path.Combine(zipRoot, Path.GetFileNameWithoutExtension(s.Path)); - if(!Directory.Exists(aliasedPath)) { - _fs.ExtractZip(s.Path, aliasedPath); - } - // User path has the .egg or .zip path, redirect it to have the new alias path - _userPaths = _userPaths.Add(aliasedPath); - _log?.Log(TraceEventType.Information, $" {s.Path} => {aliasedPath}"); - } - */ } public async Task ReloadAsync(CancellationToken cancellationToken = default) { From dfefa83703ec3cf060273e2fa5ff8ac265a9961d Mon Sep 17 00:00:00 2001 From: Cameron Trando Date: Mon, 26 Aug 2019 12:13:59 -0700 Subject: [PATCH 09/16] Refactoring --- .../Definitions/ModuleCreationOptions.cs | 5 ++++ src/Analysis/Ast/Impl/Modules/PythonModule.cs | 5 +++- .../Ast/Impl/Modules/PythonVariableModule.cs | 1 + .../Resolution/MainModuleResolution.cs | 1 + .../Ast/Impl/Types/Definitions/IPythonFile.cs | 5 ++++ .../Impl/Types/Definitions/IPythonModule.cs | 2 +- src/Core/Impl/Extensions/IOExtensions.cs | 4 +-- src/Core/Impl/IO/FileSystem.cs | 27 +++++-------------- src/Core/Impl/IO/IFileSystem.cs | 2 +- src/Core/Impl/IO/PathUtils.cs | 24 ++++++++++++----- 10 files changed, 43 insertions(+), 33 deletions(-) diff --git a/src/Analysis/Ast/Impl/Modules/Definitions/ModuleCreationOptions.cs b/src/Analysis/Ast/Impl/Modules/Definitions/ModuleCreationOptions.cs index b49e555dc..ffdfdb28a 100644 --- a/src/Analysis/Ast/Impl/Modules/Definitions/ModuleCreationOptions.cs +++ b/src/Analysis/Ast/Impl/Modules/Definitions/ModuleCreationOptions.cs @@ -33,6 +33,11 @@ public sealed class ModuleCreationOptions { /// public string FilePath { get; set; } + /// + /// The interpreter/user path used to the find FilePath. Can be null if URI is provided. + /// + public string RootPath { get; set; } + /// /// Document URI. Can be null if file path is provided. /// diff --git a/src/Analysis/Ast/Impl/Modules/PythonModule.cs b/src/Analysis/Ast/Impl/Modules/PythonModule.cs index aeeaa41af..7555030ab 100644 --- a/src/Analysis/Ast/Impl/Modules/PythonModule.cs +++ b/src/Analysis/Ast/Impl/Modules/PythonModule.cs @@ -104,6 +104,7 @@ internal PythonModule(ModuleCreationOptions creationOptions, IServiceContainer s } Uri = uri; FilePath = creationOptions.FilePath ?? uri?.LocalPath; + RootPath = creationOptions.RootPath; Stub = creationOptions.Stub; if (Stub is PythonModule stub && ModuleType != ModuleType.Stub) { stub.PrimaryModule = this; @@ -174,6 +175,7 @@ public virtual IEnumerable GetMemberNames() { #endregion #region IPythonFile + public virtual string RootPath { get; } public virtual string FilePath { get; } public virtual Uri Uri { get; } #endregion @@ -482,7 +484,7 @@ protected virtual string LoadContent() { if (ContentState < State.Loading) { ContentState = State.Loading; try { - var code = FileSystem.ReadTextWithRetry(FilePath); + var code = FileSystem.ReadTextWithRetry(FilePath, RootPath); ContentState = State.Loaded; return code; } catch (IOException) { } catch (UnauthorizedAccessException) { } @@ -562,6 +564,7 @@ private string TryGetDocFromModuleInitFile() { } #endregion + private void RemoveReferencesInModule(IPythonModule module) { if (module.GlobalScope?.Variables != null) { foreach (var v in module.GlobalScope.Variables) { diff --git a/src/Analysis/Ast/Impl/Modules/PythonVariableModule.cs b/src/Analysis/Ast/Impl/Modules/PythonVariableModule.cs index 0fd55a169..80da6c3ec 100644 --- a/src/Analysis/Ast/Impl/Modules/PythonVariableModule.cs +++ b/src/Analysis/Ast/Impl/Modules/PythonVariableModule.cs @@ -38,6 +38,7 @@ internal sealed class PythonVariableModule : LocatedMember, IPythonModule, IEqua public IDocumentAnalysis Analysis => Module?.Analysis; public string Documentation => Module?.Documentation ?? string.Empty; public string FilePath => Module?.FilePath; + public string RootPath => Module?.RootPath; public bool IsBuiltin => true; public bool IsAbstract => false; public bool IsSpecialized => Module?.IsSpecialized ?? false; diff --git a/src/Analysis/Ast/Impl/Modules/Resolution/MainModuleResolution.cs b/src/Analysis/Ast/Impl/Modules/Resolution/MainModuleResolution.cs index efea9c7b4..05a527615 100644 --- a/src/Analysis/Ast/Impl/Modules/Resolution/MainModuleResolution.cs +++ b/src/Analysis/Ast/Impl/Modules/Resolution/MainModuleResolution.cs @@ -108,6 +108,7 @@ protected override IPythonModule CreateModule(string name) { ModuleName = moduleImport.FullName, ModuleType = moduleImport.IsLibrary ? ModuleType.Library : ModuleType.User, FilePath = moduleImport.ModulePath, + RootPath = moduleImport.RootPath, Stub = stub }; diff --git a/src/Analysis/Ast/Impl/Types/Definitions/IPythonFile.cs b/src/Analysis/Ast/Impl/Types/Definitions/IPythonFile.cs index 897c7bf48..cdd3a3848 100644 --- a/src/Analysis/Ast/Impl/Types/Definitions/IPythonFile.cs +++ b/src/Analysis/Ast/Impl/Types/Definitions/IPythonFile.cs @@ -22,6 +22,11 @@ public interface IPythonFile { /// string FilePath { get; } + /// + /// Interpreter/user search path used to find the module. + /// + string RootPath { get; } + /// /// Module URI. /// diff --git a/src/Analysis/Ast/Impl/Types/Definitions/IPythonModule.cs b/src/Analysis/Ast/Impl/Types/Definitions/IPythonModule.cs index ae86bc87f..6f917a1ef 100644 --- a/src/Analysis/Ast/Impl/Types/Definitions/IPythonModule.cs +++ b/src/Analysis/Ast/Impl/Types/Definitions/IPythonModule.cs @@ -47,7 +47,7 @@ public interface IPythonModule : IPythonType, IPythonFile, ILocatedMember { /// Global cope of the module. /// IGlobalScope GlobalScope { get; } - + /// /// If module is a stub points to the primary module. /// Typically used in code navigation scenarios when user diff --git a/src/Core/Impl/Extensions/IOExtensions.cs b/src/Core/Impl/Extensions/IOExtensions.cs index 3221295d0..4af4d1e21 100644 --- a/src/Core/Impl/Extensions/IOExtensions.cs +++ b/src/Core/Impl/Extensions/IOExtensions.cs @@ -109,11 +109,11 @@ public static FileStream OpenWithRetry(this IFileSystem fs, string file, FileMod return null; } - public static string ReadTextWithRetry(this IFileSystem fs, string file) { + public static string ReadTextWithRetry(this IFileSystem fs, string file, string zipPath = null) { // Retry for up to one second for (var retries = 100; retries > 0; --retries) { try { - return fs.ReadAllText(file); + return fs.ReadAllText(file, zipPath); } catch (Exception ex) when (ex is UnauthorizedAccessException || ex is IOException || ex is ObjectDisposedException) { Thread.Sleep(10); } diff --git a/src/Core/Impl/IO/FileSystem.cs b/src/Core/Impl/IO/FileSystem.cs index a6715d042..4e2475558 100644 --- a/src/Core/Impl/IO/FileSystem.cs +++ b/src/Core/Impl/IO/FileSystem.cs @@ -25,28 +25,13 @@ public long FileSize(string path) { return fileInfo.Length; } - public string ReadAllText(string path) { - try { - return File.ReadAllText(path); - } catch (Exception ex) when (ex is UnauthorizedAccessException || ex is IOException || ex is ObjectDisposedException) { - if(PathUtils.IsContainedInZipFile(path) == -1) { - throw ex; - } - - return HandleZip(path); - } - } - - private string HandleZip(string path) { - var endIndex = PathUtils.IsContainedInZipFile(path); - if (endIndex >= 0) { - endIndex += 4; - var zipPath = path.Substring(0, endIndex); - var zipFilePath = path.Substring(endIndex + 1).Replace("\\", "/"); - - return PathUtils.GetZipEntryContent(zipPath, zipFilePath); + public string ReadAllText(string filePath, string zipPath = null) { + if (PathUtils.IsZipFile(zipPath) && filePath.StartsWith(zipPath)) { + // According to https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT, zip files must have forward slashes + var relativeZipPath = filePath.Substring(zipPath.Length + 1).Replace("\\", "/"); + return PathUtils.GetZipEntryContent(relativeZipPath, zipPath); } - return null; + return File.ReadAllText(filePath); } public void WriteAllText(string path, string content) => File.WriteAllText(path, content); diff --git a/src/Core/Impl/IO/IFileSystem.cs b/src/Core/Impl/IO/IFileSystem.cs index 338c424b6..394c886e0 100644 --- a/src/Core/Impl/IO/IFileSystem.cs +++ b/src/Core/Impl/IO/IFileSystem.cs @@ -30,7 +30,7 @@ public interface IFileSystem { void SetFileAttributes(string fullPath, FileAttributes attributes); DateTime GetLastWriteTimeUtc(string fullPath); - string ReadAllText(string path); + string ReadAllText(string path, string zipPath = null); void WriteAllText(string path, string content); IEnumerable FileReadAllLines(string path); diff --git a/src/Core/Impl/IO/PathUtils.cs b/src/Core/Impl/IO/PathUtils.cs index fc7063c06..44e519058 100644 --- a/src/Core/Impl/IO/PathUtils.cs +++ b/src/Core/Impl/IO/PathUtils.cs @@ -310,9 +310,24 @@ public static IEnumerable EnumerateFiles(IFileSystem fileSystem, stri } } - public static string GetZipEntryContent(string root, string filePath) { - using (var zip = ZipFile.OpenRead(root)) { + public static bool IsZipFile(string zipFile) { + var extension = Path.GetExtension(zipFile); + switch (extension) { + case ".zip": + case ".egg": + return true; + default: + return false; + } + } + + public static string GetZipEntryContent(string filePath, string zipFilePath) { + using (var zip = ZipFile.OpenRead(zipFilePath)) { var zipFile = zip.GetEntry(filePath); + // Could not open zip, bail + if(zipFile == null) { + return null; + } var reader = new StreamReader(zipFile.Open()); return reader.ReadToEnd(); } @@ -452,11 +467,6 @@ public static string NormalizePath(string path) { public static string NormalizePathAndTrim(string path) => TrimEndSeparator(NormalizePath(path)); - public static bool IsZipFile(string file) { - var extension = Path.GetExtension(file); - return extension.Equals(".zip") || extension.Equals(".egg"); - } - /// /// Returns index of zip file ending if file is contained inside a zip file or -1 if not /// From 409eb3387cfb741b1cc94526157fd035193ee383 Mon Sep 17 00:00:00 2001 From: Cameron Trando Date: Mon, 26 Aug 2019 12:28:34 -0700 Subject: [PATCH 10/16] More refactoring --- .../Modules/Resolution/MainModuleResolution.cs | 2 +- src/Analysis/Ast/Test/PathClassificationTests.cs | 14 +++++++------- .../Impl/Interpreter/InterpreterConfiguration.cs | 2 +- .../Core/Impl/Interpreter/PythonLibraryPath.cs | 10 ++-------- 4 files changed, 11 insertions(+), 17 deletions(-) diff --git a/src/Analysis/Ast/Impl/Modules/Resolution/MainModuleResolution.cs b/src/Analysis/Ast/Impl/Modules/Resolution/MainModuleResolution.cs index 05a527615..3bc1b684c 100644 --- a/src/Analysis/Ast/Impl/Modules/Resolution/MainModuleResolution.cs +++ b/src/Analysis/Ast/Impl/Modules/Resolution/MainModuleResolution.cs @@ -179,7 +179,7 @@ internal async Task ReloadSearchPaths(CancellationToken cancellationToken = defa var cacheFolder = sc.StubCacheFolder; var paths = await GetInterpreterSearchPathsAsync(cancellationToken); - var (interpreterPaths, userPaths, zipPaths) = PythonLibraryPath.ClassifyPaths(Root, _fs, paths, Configuration.SearchPaths); + var (interpreterPaths, userPaths) = PythonLibraryPath.ClassifyPaths(Root, _fs, paths, Configuration.SearchPaths); InterpreterPaths = interpreterPaths.Select(p => p.Path); _userPaths = userPaths.Select(p => p.Path); diff --git a/src/Analysis/Ast/Test/PathClassificationTests.cs b/src/Analysis/Ast/Test/PathClassificationTests.cs index fbb3703a4..b6dac71eb 100644 --- a/src/Analysis/Ast/Test/PathClassificationTests.cs +++ b/src/Analysis/Ast/Test/PathClassificationTests.cs @@ -52,7 +52,7 @@ public void Plain() { new PythonLibraryPath(venvSitePackages, PythonLibraryPathType.Site), }; - var (interpreterPaths, userPaths, zipPaths) = PythonLibraryPath.ClassifyPaths(root, _fs, fromInterpreter, Array.Empty()); + var (interpreterPaths, userPaths) = PythonLibraryPath.ClassifyPaths(root, _fs, fromInterpreter, Array.Empty()); interpreterPaths.Should().BeEquivalentToWithStrictOrdering(new[] { new PythonLibraryPath(venvLib, PythonLibraryPathType.StdLib), @@ -84,7 +84,7 @@ public void WithSrcDir() { "./src", }; - var (interpreterPaths, userPaths, zipPaths) = PythonLibraryPath.ClassifyPaths(root, _fs, fromInterpreter, fromUser); + var (interpreterPaths, userPaths) = PythonLibraryPath.ClassifyPaths(root, _fs, fromInterpreter, fromUser); interpreterPaths.Should().BeEquivalentToWithStrictOrdering(new[] { new PythonLibraryPath(venvLib, PythonLibraryPathType.StdLib), @@ -108,7 +108,7 @@ public void NormalizeUser() { "./src/", }; - var (interpreterPaths, userPaths, zipPaths) = PythonLibraryPath.ClassifyPaths(root, _fs, Array.Empty(), fromUser); + var (interpreterPaths, userPaths) = PythonLibraryPath.ClassifyPaths(root, _fs, Array.Empty(), fromUser); interpreterPaths.Should().BeEmpty(); @@ -134,7 +134,7 @@ public void NestedUser() { "./src/foo", }; - var (interpreterPaths, userPaths, zipPaths) = PythonLibraryPath.ClassifyPaths(root, _fs, Array.Empty(), fromUser); + var (interpreterPaths, userPaths) = PythonLibraryPath.ClassifyPaths(root, _fs, Array.Empty(), fromUser); interpreterPaths.Should().BeEmpty(); @@ -163,7 +163,7 @@ public void NestedUserOrdering() { "./src/something", }; - var (interpreterPaths, userPaths, zipPaths) = PythonLibraryPath.ClassifyPaths(root, _fs, Array.Empty(), fromUser); + var (interpreterPaths, userPaths) = PythonLibraryPath.ClassifyPaths(root, _fs, Array.Empty(), fromUser); interpreterPaths.Should().BeEmpty(); @@ -200,7 +200,7 @@ public void InsideStdLib() { "./venv/Lib/site-packages/what", }; - var (interpreterPaths, userPaths, zipPaths) = PythonLibraryPath.ClassifyPaths(root, _fs, fromInterpreter, fromUser); + var (interpreterPaths, userPaths) = PythonLibraryPath.ClassifyPaths(root, _fs, fromInterpreter, fromUser); interpreterPaths.Should().BeEquivalentToWithStrictOrdering(new[] { new PythonLibraryPath(venvLib, PythonLibraryPathType.StdLib), @@ -236,7 +236,7 @@ public void SiteOutsideStdlib() { "./src", }; - var (interpreterPaths, userPaths, zipPaths) = PythonLibraryPath.ClassifyPaths(root, _fs, fromInterpreter, fromUser); + var (interpreterPaths, userPaths) = PythonLibraryPath.ClassifyPaths(root, _fs, fromInterpreter, fromUser); interpreterPaths.Should().BeEquivalentToWithStrictOrdering(new[] { new PythonLibraryPath(venvLib, PythonLibraryPathType.StdLib), diff --git a/src/Analysis/Core/Impl/Interpreter/InterpreterConfiguration.cs b/src/Analysis/Core/Impl/Interpreter/InterpreterConfiguration.cs index 1ed4f6331..4b218636f 100644 --- a/src/Analysis/Core/Impl/Interpreter/InterpreterConfiguration.cs +++ b/src/Analysis/Core/Impl/Interpreter/InterpreterConfiguration.cs @@ -69,7 +69,7 @@ private InterpreterConfiguration(IReadOnlyDictionary properties) } else if (o is IEnumerable ss) { sp.AddRange(ss); } - SearchPaths = sp.ToArray(); + } } diff --git a/src/Analysis/Core/Impl/Interpreter/PythonLibraryPath.cs b/src/Analysis/Core/Impl/Interpreter/PythonLibraryPath.cs index b8e052ac3..50dd91fdb 100644 --- a/src/Analysis/Core/Impl/Interpreter/PythonLibraryPath.cs +++ b/src/Analysis/Core/Impl/Interpreter/PythonLibraryPath.cs @@ -210,7 +210,7 @@ public static async Task> GetSearchPathsFromInterpreterA } } - public static (ImmutableArray interpreterPaths, ImmutableArray userPaths, ImmutableArray zipPaths) + public static (ImmutableArray interpreterPaths, ImmutableArray userPaths) ClassifyPaths( string root, IFileSystem fs, @@ -244,17 +244,11 @@ IEnumerable fromUser // Pull out stdlib paths, and make them always be interpreter paths. var interpreterPaths = stdlib; var userPaths = ImmutableArray.Empty; - var zipPaths = ImmutableArray.Empty; var allPaths = fromUserList.Select(p => new PythonLibraryPath(p)) .Concat(withoutStdlib.Where(p => !p.Path.PathEquals(root))); foreach (var p in allPaths) { - // If path is a zip file, handle separately but still classify as user or interpreter - if (IOPath.GetExtension(p.Path).Equals(".zip") || IOPath.GetExtension(p.Path).Equals(".egg")) { - zipPaths = zipPaths.Add(p); - } - // If path is within a stdlib path, then treat it as interpreter. if (stdlib.Any(s => fs.IsPathUnderRoot(s.Path, p.Path))) { interpreterPaths = interpreterPaths.Add(p); @@ -276,7 +270,7 @@ IEnumerable fromUser userPaths = userPaths.Add(p); } - return (interpreterPaths, userPaths, zipPaths); + return (interpreterPaths, userPaths); } public override bool Equals(object obj) => obj is PythonLibraryPath other && Equals(other); From 3df60fee8f5907c2e288b3bba54b4f1142f18573 Mon Sep 17 00:00:00 2001 From: Cameron Trando Date: Tue, 27 Aug 2019 11:41:43 -0700 Subject: [PATCH 11/16] more changes --- src/Analysis/Ast/Impl/Modules/PythonModule.cs | 2 +- .../Resolution/ModuleResolutionBase.cs | 6 +- src/Core/Impl/Extensions/IOExtensions.cs | 4 +- src/Core/Impl/IO/FileSystem.cs | 8 +- src/Core/Impl/IO/IFileSystem.cs | 2 +- src/Core/Impl/IO/PathUtils.cs | 48 +++++++++-- src/LanguageServer/Test/ImportsTests.cs | 81 +++++++++++++++--- .../{ZipEgg/test.egg => EggZip/Basic.egg} | Bin .../TestData/AstAnalysis/EggZip/Basic.zip | Bin 0 -> 3338 bytes .../egg_user.py => EggZip/BasicEggZip.py} | 0 .../AstAnalysis/EggZip/EggImports.egg | Bin 0 -> 3546 bytes .../AstAnalysis/EggZip/EggRelativeImports.egg | Bin 0 -> 5125 bytes .../AstAnalysis/EggZip/EggZipImports.py | 13 +++ .../EggZip/EggZipRelativeImports.py | 12 +++ .../AstAnalysis/EggZip/ZipImports.zip | Bin 0 -> 1054 bytes .../AstAnalysis/EggZip/ZipRelativeImports.zip | Bin 0 -> 2518 bytes .../AstAnalysis/EggZip/simplejson.egg | Bin 0 -> 120933 bytes .../AstAnalysis/EggZip/simplejson.zip | Bin 0 -> 120933 bytes .../TestData/AstAnalysis/ZipEgg/test.py | 4 - .../TestData/AstAnalysis/ZipEgg/zip_user.py | 5 -- .../TestData/AstAnalysis/ZipEgg/zipped.zip | Bin 169 -> 0 bytes 21 files changed, 148 insertions(+), 37 deletions(-) rename src/UnitTests/TestData/AstAnalysis/{ZipEgg/test.egg => EggZip/Basic.egg} (100%) create mode 100644 src/UnitTests/TestData/AstAnalysis/EggZip/Basic.zip rename src/UnitTests/TestData/AstAnalysis/{ZipEgg/egg_user.py => EggZip/BasicEggZip.py} (100%) create mode 100644 src/UnitTests/TestData/AstAnalysis/EggZip/EggImports.egg create mode 100644 src/UnitTests/TestData/AstAnalysis/EggZip/EggRelativeImports.egg create mode 100644 src/UnitTests/TestData/AstAnalysis/EggZip/EggZipImports.py create mode 100644 src/UnitTests/TestData/AstAnalysis/EggZip/EggZipRelativeImports.py create mode 100644 src/UnitTests/TestData/AstAnalysis/EggZip/ZipImports.zip create mode 100644 src/UnitTests/TestData/AstAnalysis/EggZip/ZipRelativeImports.zip create mode 100644 src/UnitTests/TestData/AstAnalysis/EggZip/simplejson.egg create mode 100644 src/UnitTests/TestData/AstAnalysis/EggZip/simplejson.zip delete mode 100644 src/UnitTests/TestData/AstAnalysis/ZipEgg/test.py delete mode 100644 src/UnitTests/TestData/AstAnalysis/ZipEgg/zip_user.py delete mode 100644 src/UnitTests/TestData/AstAnalysis/ZipEgg/zipped.zip diff --git a/src/Analysis/Ast/Impl/Modules/PythonModule.cs b/src/Analysis/Ast/Impl/Modules/PythonModule.cs index 7555030ab..58ffd0883 100644 --- a/src/Analysis/Ast/Impl/Modules/PythonModule.cs +++ b/src/Analysis/Ast/Impl/Modules/PythonModule.cs @@ -484,7 +484,7 @@ protected virtual string LoadContent() { if (ContentState < State.Loading) { ContentState = State.Loading; try { - var code = FileSystem.ReadTextWithRetry(FilePath, RootPath); + var code = FileSystem.ReadTextWithRetry(FilePath); ContentState = State.Loaded; return code; } catch (IOException) { } catch (UnauthorizedAccessException) { } diff --git a/src/Analysis/Ast/Impl/Modules/Resolution/ModuleResolutionBase.cs b/src/Analysis/Ast/Impl/Modules/Resolution/ModuleResolutionBase.cs index 83ef9c43b..f2a74507d 100644 --- a/src/Analysis/Ast/Impl/Modules/Resolution/ModuleResolutionBase.cs +++ b/src/Analysis/Ast/Impl/Modules/Resolution/ModuleResolutionBase.cs @@ -110,10 +110,10 @@ protected void ReloadModulePaths(in IEnumerable rootPaths) { } } - if (PathUtils.IsZipFile(root) && File.Exists(root)) { - foreach (var moduleFile in PathUtils.EnumerateZip(root)) { + if (PathUtils.TryGetZipFile(root, out var zipPath, out var _) && File.Exists(zipPath)) { + foreach (var moduleFile in PathUtils.EnumerateZip(zipPath)) { if (!PathUtils.PathStartsWith(moduleFile.FullName, "EGG-INFO")) { - PathResolver.TryAddModulePath(Path.Combine(root, PathUtils.NormalizePath(moduleFile.FullName)), moduleFile.Length, false, out _); + PathResolver.TryAddModulePath(Path.Combine(zipPath, PathUtils.NormalizePath(moduleFile.FullName)), moduleFile.Length, false, out _); } } } diff --git a/src/Core/Impl/Extensions/IOExtensions.cs b/src/Core/Impl/Extensions/IOExtensions.cs index 4af4d1e21..3221295d0 100644 --- a/src/Core/Impl/Extensions/IOExtensions.cs +++ b/src/Core/Impl/Extensions/IOExtensions.cs @@ -109,11 +109,11 @@ public static FileStream OpenWithRetry(this IFileSystem fs, string file, FileMod return null; } - public static string ReadTextWithRetry(this IFileSystem fs, string file, string zipPath = null) { + public static string ReadTextWithRetry(this IFileSystem fs, string file) { // Retry for up to one second for (var retries = 100; retries > 0; --retries) { try { - return fs.ReadAllText(file, zipPath); + return fs.ReadAllText(file); } catch (Exception ex) when (ex is UnauthorizedAccessException || ex is IOException || ex is ObjectDisposedException) { Thread.Sleep(10); } diff --git a/src/Core/Impl/IO/FileSystem.cs b/src/Core/Impl/IO/FileSystem.cs index 4e2475558..22be38f4b 100644 --- a/src/Core/Impl/IO/FileSystem.cs +++ b/src/Core/Impl/IO/FileSystem.cs @@ -25,11 +25,9 @@ public long FileSize(string path) { return fileInfo.Length; } - public string ReadAllText(string filePath, string zipPath = null) { - if (PathUtils.IsZipFile(zipPath) && filePath.StartsWith(zipPath)) { - // According to https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT, zip files must have forward slashes - var relativeZipPath = filePath.Substring(zipPath.Length + 1).Replace("\\", "/"); - return PathUtils.GetZipEntryContent(relativeZipPath, zipPath); + public string ReadAllText(string filePath) { + if (PathUtils.TryGetZipFile(filePath, out var zipPath, out var relativeZipPath)) { + return PathUtils.GetZipEntryContent(zipPath, relativeZipPath); } return File.ReadAllText(filePath); } diff --git a/src/Core/Impl/IO/IFileSystem.cs b/src/Core/Impl/IO/IFileSystem.cs index 394c886e0..338c424b6 100644 --- a/src/Core/Impl/IO/IFileSystem.cs +++ b/src/Core/Impl/IO/IFileSystem.cs @@ -30,7 +30,7 @@ public interface IFileSystem { void SetFileAttributes(string fullPath, FileAttributes attributes); DateTime GetLastWriteTimeUtc(string fullPath); - string ReadAllText(string path, string zipPath = null); + string ReadAllText(string path); void WriteAllText(string path, string content); IEnumerable FileReadAllLines(string path); diff --git a/src/Core/Impl/IO/PathUtils.cs b/src/Core/Impl/IO/PathUtils.cs index 44e519058..462dd2222 100644 --- a/src/Core/Impl/IO/PathUtils.cs +++ b/src/Core/Impl/IO/PathUtils.cs @@ -49,6 +49,8 @@ public static bool IsValidFileNameCharacter(char character) public static bool HasEndSeparator(string path) => !string.IsNullOrEmpty(path) && IsDirectorySeparator(path[path.Length - 1]); + public static bool HasStartSeparator(string path) + => !string.IsNullOrEmpty(path) && IsDirectorySeparator(path[0]); public static bool IsDirectorySeparator(char c) => Array.IndexOf(DirectorySeparators, c) != -1; @@ -56,6 +58,13 @@ public static bool PathStartsWith(string s, string prefix) => s != null && s.StartsWith(prefix, StringExtensions.PathsStringComparison) && (s.Length == prefix.Length || IsDirectorySeparator(s[prefix.Length])); + public static string TrimStartSeparator(string path) { + if(HasStartSeparator(path)) { + return path.Substring(1); + } + return path; + } + /// /// Removes up to one directory separator character from the end of path. /// @@ -310,22 +319,49 @@ public static IEnumerable EnumerateFiles(IFileSystem fileSystem, stri } } - public static bool IsZipFile(string zipFile) { - var extension = Path.GetExtension(zipFile); + public static bool TryGetZipFile(string filePath, out string zipPath, out string relativeZipPath) { + zipPath = string.Empty; + relativeZipPath = string.Empty; + var workingPath = filePath; + + // Filepath doesn't have zip or egg in it, bail + if(!filePath.Contains(".zip") && !filePath.Contains(".egg")) { + return false; + } + + while (!string.IsNullOrEmpty(workingPath)) { + if (IsZipFile(workingPath, out zipPath)) { + // According to https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT, zip files must have forward slashes + relativeZipPath = filePath.Substring(workingPath.Length).Replace("\\", "/"); + return true; + } + workingPath = GetParent(workingPath); + } + + // Filepath had .zip or .egg in it but no zip or egg files + // e.g /tmp/tmp.zip.txt + return false; + } + + public static bool IsZipFile(string rawZipPath, out string zipPath) { + var path = NormalizePathAndTrim(rawZipPath); + var extension = Path.GetExtension(path); switch (extension) { case ".zip": case ".egg": + zipPath = path; return true; default: + zipPath = string.Empty; return false; } } - public static string GetZipEntryContent(string filePath, string zipFilePath) { - using (var zip = ZipFile.OpenRead(zipFilePath)) { - var zipFile = zip.GetEntry(filePath); + public static string GetZipEntryContent(string zipPath, string relativeZipPath) { + using (var zip = ZipFile.OpenRead(zipPath)) { + var zipFile = zip.GetEntry(relativeZipPath); // Could not open zip, bail - if(zipFile == null) { + if (zipFile == null) { return null; } var reader = new StreamReader(zipFile.Open()); diff --git a/src/LanguageServer/Test/ImportsTests.cs b/src/LanguageServer/Test/ImportsTests.cs index b246959c2..733ad917a 100644 --- a/src/LanguageServer/Test/ImportsTests.cs +++ b/src/LanguageServer/Test/ImportsTests.cs @@ -833,14 +833,16 @@ import module2 comps.Should().HaveLabels("Y"); } - [TestMethod, Priority(0)] - public async Task ZipFiles() { - var root = Path.Combine(GetAnalysisTestDataFilesPath(), "ZipEgg"); - await CreateServicesAsync(root, PythonVersions.LatestAvailable3X, searchPaths: new[] { root, Path.Combine(root, "zipped.zip") }); + [DataRow("Basic.egg")] + [DataRow("Basic.zip")] + [DataTestMethod, Priority(0)] + public async Task BasicEggZip(string eggZipFilePath) { + var root = Path.Combine(GetAnalysisTestDataFilesPath(), "EggZip"); + await CreateServicesAsync(root, PythonVersions.LatestAvailable3X, searchPaths: new[] { root, Path.Combine(root, eggZipFilePath) }); var rdt = Services.GetService(); var analyzer = Services.GetService(); - var uriPath = Path.Combine(root, "zip_user.py"); + var uriPath = Path.Combine(root, "BasicEggZip.py"); var code = await File.ReadAllTextAsync(uriPath); var moduleUri = TestData.GetTestSpecificUri(uriPath); var module = rdt.OpenDocument(moduleUri, code); @@ -850,21 +852,80 @@ public async Task ZipFiles() { analysis.Should().HaveVariable("i").OfType(BuiltinTypeId.Int); } - [TestMethod, Priority(0)] - public async Task EggFiles() { - var root = Path.Combine(GetAnalysisTestDataFilesPath(), "ZipEgg"); - await CreateServicesAsync(root, PythonVersions.LatestAvailable3X, searchPaths: new[] { root, Path.Combine(root, "test.egg") }); + [DataRow("EggImports.egg")] + [DataRow("ZipImports.zip")] + [DataTestMethod, Priority(0)] + public async Task EggZipImports(string eggZipFilePath) { + var root = Path.Combine(GetAnalysisTestDataFilesPath(), "EggZip"); + await CreateServicesAsync(root, PythonVersions.LatestAvailable3X, searchPaths: new[] { root, Path.Combine(root, eggZipFilePath, "test") }); var rdt = Services.GetService(); var analyzer = Services.GetService(); - var uriPath = Path.Combine(root, "egg_user.py"); + var uriPath = Path.Combine(root, "EggZipImports.py"); var code = await File.ReadAllTextAsync(uriPath); var moduleUri = TestData.GetTestSpecificUri(uriPath); var module = rdt.OpenDocument(moduleUri, code); await analyzer.WaitForCompleteAnalysisAsync(); var analysis = await module.GetAnalysisAsync(-1); + analysis.Should().HaveVariable("h").OfType("X"); + analysis.Should().HaveVariable("y").OfType(BuiltinTypeId.Int); + analysis.Should().HaveVariable("b").OfType("A"); analysis.Should().HaveVariable("i").OfType(BuiltinTypeId.Int); } + + [DataRow("ZipRelativeImports.zip")] + [DataRow("EggRelativeImports.egg")] + [DataTestMethod, Priority(0)] + public async Task EggZipRelativeImports(string eggZipFilePath) { + var root = Path.Combine(GetAnalysisTestDataFilesPath(), "EggZip"); + await CreateServicesAsync(root, PythonVersions.LatestAvailable3X, searchPaths: new[] { root, Path.Combine(root, eggZipFilePath, "test") }); + var rdt = Services.GetService(); + var analyzer = Services.GetService(); + + var uriPath = Path.Combine(root, "EggZipRelativeImports.py"); + var code = await File.ReadAllTextAsync(uriPath); + var moduleUri = TestData.GetTestSpecificUri(uriPath); + var module = rdt.OpenDocument(moduleUri, code); + + await analyzer.WaitForCompleteAnalysisAsync(); + var analysis = await module.GetAnalysisAsync(-1); + analysis.Should().HaveVariable("h").OfType(BuiltinTypeId.Float); + analysis.Should().HaveVariable("i").OfType(BuiltinTypeId.Int); + analysis.Should().HaveVariable("s").OfType(BuiltinTypeId.Str); + } + + [DataRow("simplejson.egg")] + [DataRow("simplejson.zip")] + [DataTestMethod, Priority(0)] + public async Task SimpleJsonEggZip(string eggZipFilePath) { + var root = Path.Combine(GetAnalysisTestDataFilesPath(), "EggZip"); + await CreateServicesAsync(root, PythonVersions.LatestAvailable3X, searchPaths: new[] { root, Path.Combine(root, eggZipFilePath) }); + var rdt = Services.GetService(); + var analyzer = Services.GetService(); + + const string code = "import simplejson"; + var uriPath = Path.Combine(root, "test.py"); + var moduleUri = TestData.GetTestSpecificUri(uriPath); + var module = rdt.OpenDocument(moduleUri, code); + + await analyzer.WaitForCompleteAnalysisAsync(); + var analysis = await module.GetAnalysisAsync(-1); + analysis.Should().HaveVariable("simplejson").Which.Should().HaveMembers( + "Decimal", + "JSONDecodeError", + "JSONDecoder", + "JSONEncoder", + "JSONEncoderForHTML", + "OrderedDict", + "RawJSON", + "dump", + "dumps", + "load", + "loads", + "simple_first" + ); + } + } } diff --git a/src/UnitTests/TestData/AstAnalysis/ZipEgg/test.egg b/src/UnitTests/TestData/AstAnalysis/EggZip/Basic.egg similarity index 100% rename from src/UnitTests/TestData/AstAnalysis/ZipEgg/test.egg rename to src/UnitTests/TestData/AstAnalysis/EggZip/Basic.egg diff --git a/src/UnitTests/TestData/AstAnalysis/EggZip/Basic.zip b/src/UnitTests/TestData/AstAnalysis/EggZip/Basic.zip new file mode 100644 index 0000000000000000000000000000000000000000..2ae9babc1274238f04d9b3b68fe20c6d2ac843e0 GIT binary patch literal 3338 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 E0Kunj2LJ#7 literal 0 HcmV?d00001 diff --git a/src/UnitTests/TestData/AstAnalysis/ZipEgg/egg_user.py b/src/UnitTests/TestData/AstAnalysis/EggZip/BasicEggZip.py similarity index 100% rename from src/UnitTests/TestData/AstAnalysis/ZipEgg/egg_user.py rename to src/UnitTests/TestData/AstAnalysis/EggZip/BasicEggZip.py diff --git a/src/UnitTests/TestData/AstAnalysis/EggZip/EggImports.egg b/src/UnitTests/TestData/AstAnalysis/EggZip/EggImports.egg new file mode 100644 index 0000000000000000000000000000000000000000..5e267304eec4280635e8b4182dd5169f15b88261 GIT binary patch literal 3546 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 VCqV`j77V5eUII|D3d+K7{{s^3?!5p2 literal 0 HcmV?d00001 diff --git a/src/UnitTests/TestData/AstAnalysis/EggZip/EggZipImports.py b/src/UnitTests/TestData/AstAnalysis/EggZip/EggZipImports.py new file mode 100644 index 000000000..5a4db3e06 --- /dev/null +++ b/src/UnitTests/TestData/AstAnalysis/EggZip/EggZipImports.py @@ -0,0 +1,13 @@ +import sys + +#sys.path.insert(0, "C:\\Users\\t-catran\\dev\\python-language-server\\src\\UnitTests\\TestData\\AstAnalysis\\ZipEgg\\Imports\\ImportWithinEgg.egg") + +#sys.path.insert(0, "C:\\Users\\t-catran\\dev\\python-language-server\\src\\UnitTests\\TestData\\AstAnalysis\\ZipEgg\\Imports\\ImportWithinEgg.egg\\test") + +import a + +h = a.h +y = a.y +b = a.A() +i = b.test() + diff --git a/src/UnitTests/TestData/AstAnalysis/EggZip/EggZipRelativeImports.py b/src/UnitTests/TestData/AstAnalysis/EggZip/EggZipRelativeImports.py new file mode 100644 index 000000000..651a1ce6c --- /dev/null +++ b/src/UnitTests/TestData/AstAnalysis/EggZip/EggZipRelativeImports.py @@ -0,0 +1,12 @@ +import sys + +#sys.path.insert(0, "C:\\Users\\t-catran\\dev\\python-language-server\\src\\UnitTests\\TestData\\AstAnalysis\\ZipEgg\\Imports\\ImportWithinEgg.egg") + +#sys.path.insert(0, "C:\\Users\\t-catran\\dev\\python-language-server\\src\\UnitTests\\TestData\\AstAnalysis\\EggZip\\EggZipRelativeImports.egg\\test") + +import a + +h = a.h +i = a.i +s = a.s + diff --git a/src/UnitTests/TestData/AstAnalysis/EggZip/ZipImports.zip b/src/UnitTests/TestData/AstAnalysis/EggZip/ZipImports.zip new file mode 100644 index 0000000000000000000000000000000000000000..853615d98f9b5f1fa418ee3cec7250c0f2789dc9 GIT binary patch literal 1054 zcmWIWW@Zs#0D)6UV*X$Tln?;YC8@RJN?psd`(3kYb;UMQ8ZTei@yb^A`{B@c zs#{uDJayuHXyv3M6%)45PUump=IXQEe&yER6;51oG`Rh7o97$jR~;oQ!^&2^u7A_G z-TjltG{L);2js48`xkP2pU1qAP}9n3$5Q*wX1|`X(Q4nWlql0nyMz@}V$H*DRR&AH zf6!2IT`uQMoICqN>(=DDQ+14pIC!2V<=_7}tt=22_Q^oZ35$b7U|@S|pE@7v5p?2= z?g@RZz>WuxP6ccT?YMB^$tsphl2xiJkE%NGg%|lH6>e-=EIOS@KqX2u<=NDRnVKsz zxe`o|uC&aY#kH$UL9#ueNzMqT)9;*Nf`e_IZ*{^%B| z6y={2K5P5Ld$p`{7DXvnk_-$0lF(0< literal 0 HcmV?d00001 diff --git a/src/UnitTests/TestData/AstAnalysis/EggZip/ZipRelativeImports.zip b/src/UnitTests/TestData/AstAnalysis/EggZip/ZipRelativeImports.zip new file mode 100644 index 0000000000000000000000000000000000000000..f1b82a292ae410c2b7377c19dba864e2ae68a653 GIT binary patch literal 2518 zcmWIWW@Zs#0D)6UV*X$Tln?;YC8@RJN?psd`(3kYb;UMQ8ZTei@yb^A`{B@c zs#{uDJayuHXyv3M6%)45PUump=IXQEe&yER6;51oG`Rh7o97$jR~;oQ!^&2^u7A_G z-TjltG{L);2js48`xkP2pU1qAP}9n3$5Q*wX1|`X(Q4nWlql0nyMz@}V$H*DRR&AH zf6!2IT`uQMoICqN>(=DDQ+14pIJlB1?SD*FiY*uz_Dw*{35$b7U|@%ya^z}I5O90= zcg~~sZI>!)f!ny{{cz%waY&FsuUF473am_<<~N(kd=ZO3TklNiBjW z6->oan2NEcNSy>!OQf;s!{)VgcRq9pNmyCynGx*gi$nVo30*i&o8gJX4V_7C(^U!R(r9eyw6R?xx+t<^>H zCoR>(&!#auJ_xV;&GcOTRwu(Jp&)r?o{OeJ9uGvHNPA9H(46MNru0J5F+bptTJ`;T z3?5UG8iUHE_a{5LY*?f@^-Ot)!3!rrCij$&8VAinF6o3?9?Uk{b8esV5(cKjsYXAN z0_qhi9JlH$JGIv4&zx`PH!YmzmA=gOWbdidJ|~W!@yNYZWcJy0+4RSmp&TnW6+ZuW zGRR!Tuc_kV^MWgdi|cc5I7mM&6<%}Wm@}_pLu%i$(`73b&)Q|(pnrVM^q)>edD3(A zwKnR+)Smcx*hv4{?1VTeQOiR&4jzo3xOUR5h%eug?r{A{3H$wj--b7SVy>nhE9S4B zR&K7l>dp=2bDuY@@yUA@y3+Fg@%+bexgTn@odUFfvBJ_02ZI_gc6iTUJAE1$EAN4r zK0O zzP!w9<~6O&D~&$v``%@K*yc->xx(k-1=A=05dR~sI;-Q6!-E40+qrndPHC_Nxe3c1 zOqnwGv%i7v$88l4uZVd4?cEfjbxiWP^rwAwTGlsdc%xj{;g zILF-(uN{4I@81+J5y-t9e{Qxx{pP-Vxv#!u?)}GY_D*c|Eo-ha%NunChU>Dne=eCH z*U|bQEPd5duD{%fFwq8vNz7ye(I8-WR0FXv5ToU%Bw(KQKIf^U7uK=iQ4mAZlq)8! zlde1x>V0%&j)^a8taa;|JwhEK93o4nO%Z#lIiqNyhMCI>Jw44s0c%-ALLNOj<#G1p z$?ZWNr%(Fp1a1g5xMKW(i2>mRWuOy8-rU*|1GKsgyAzT@PS8GeKJpCS6kDMTF-QSO{lsq& zzR<;1o*)dK&Vmt4@$m>3qL(g+Amm`cmMK97L!xapD~7?KEQ)LZwk(A(K#vW>08j=C U@MZ-{FfecfAuBTj!)`DS0DTcZ#sB~S literal 0 HcmV?d00001 diff --git a/src/UnitTests/TestData/AstAnalysis/EggZip/simplejson.egg b/src/UnitTests/TestData/AstAnalysis/EggZip/simplejson.egg new file mode 100644 index 0000000000000000000000000000000000000000..98b135dc643de2cb15d97bb95ba7220bc7b15b3b GIT binary patch literal 120933 zcmZU(Q;=xEvaZ{{-UxH^F@z zx}@2SS$Ng@IB*UVQiZ6O zl)R>O$30jrJr&~ZaOw))uhX;UC36nV!^rqhOF#3spGYtQ7Jn#6a^o1zbYJ1()^X7} zWi)f zD6fzTfU1DdQ!QT0ODT-I`5+UpQ$A*y2w{297+LMiC(q=cxjU1_eq5O#pSeYUa_ppf zGYj8ze9)=$O+7A~H@UtntSOQf`BF(E=7--U zpd9Y_%D`4HN9-v zJPVd+z-kbf$me}VenYCC%uS}#inT4zHu)5GKcmi?#5 zq044QVgG#&{V&k|TjpZ#pl@U9W@_`FY}7MTwBwS~R5P>xD{sxe1>j_xAzJ<=d^Y@_ z1)MEy9c)akobB!C_4O_7EM4^V=^Q+-b!?pv*^+*4sD8myZdye=O>M6v$tah(T-PT` z+*;ktmAI3uIv?6eB0@+;Q6@+wyi+)TUoX)CKq#c#c$~f0xwz?x1PkWR>{vSS6aIh& z59sgodeRp4jbp#F)h;xm*`x7SwWHNVYpqx&#t-AKy6VdP-i7D8Cdx-yJ=aLIBnYuX z*H|gi#K(89cxA6X1V`xgzHPdfpU%#XG*KZ^NoJ}Ps}hm4&MYi<_Nu=5Cys03;g@>W zRC>@prXo!iZH#+4`MCJ7Y@;P>l^1p}GLBPo1RM zjEV)p+viWk!QU1TXCT=`Pd5CKaVMgau}wTV7_;pOyEsigHEyu55|_ru9~mhFQKUCO zc~+w_@rf07gzY8bD{il#N?l!dBUvF3%&mQJ$sA>>6Rn^^(!i@aB+lFt$kd_aMY|9? zK41eCnlmn5^bwsxBefDXI{=NPD-Q$!EtD=zDqA9XOZU_vSu-JY#nSeJYK?QPG>BpR zIy*4!7SK!DM2VCYBsvlAN%<~dWltft>x zg=IS7dvvPjYvsS{)=(W4TOJOXovAvviN&GO<8^3Ri-2Csf%SX_y;OQBHQ)nW6;Q$6 zjU`-_C~wrL^c*{dh1$Xey#b@ZJtj_{fLTv$8gr$Njkrcw@9oLPhtH4gkK+e9`naqC zlRtF3>aN~13MMO%Rhg1n9WA9VGQ{}Bj2q`>Vx!5v1g;NPrXLGF3%*!)oAHfLtvaMb zO3N4asr&3MHfIV6l1t9;O&>O#*#z`M_z6T77@!XD6;=2C1NZ)^mkAk5_uBwue-&dp zmC|G5b#k>F2h}J<#z4r$?6C`i7a0wGl^9t7@G-GpGT0%VoUY9(O!a;@!rrf^|0$o1 z&ik^JOEsOdr+1w{BE`BGCO3pOx$LQGz*QN-MlM$&UWDqlsN*TY1q*h$n zk1JDVoME99W5y~E;}r4xklgu}t2Y-eIsq3djGsU;|?j%VKs z9~=)`zlJr_6W|MgySYQ;)BeMk9S7W}0p;|HsH5+E+zJCy?)T5vsiOEHfkHu=CZgYL z+jmT^>`Z^bfT9JfwveW;VP$e?rgbfwR{) zCH-Qm^LSXuz3jTUB%C;Mesl{wUJU0bMiU7>^xucY`4k$D-72~$nAl9At=6fg7^H(* z*+OsC6k;@%s$8Wbr7cbV=u~>>KxWuTSTf)QZv)#3Uu_heCEVLC+#9+&?G**Bc9M{P zfNxJ1&6DZzh2D?BGsxNgrR9Udj=;PNi}J&&{UE&}RuQbcGH4`HEQ4%ZS<5 z0}PZ4D3gfn*y_ow%-wTz5-5pCX^V8W50)*98eM=FB}6q^!qhGHPZ=h|*&XkrQq zbG9gX^3ITeylQvYA=@hcBJExa6!TrKPJ`j=!W|S%Tn?n}#?K;AWLV40-t3&-oNV=Z zg0a(ic*wy`M$jeDeA2{%z4VdFWX*&*pVg{oU^tbeIGqhWbdmRB52#=d_Irm|o7d0I z9FGx3LI-6xaZkx!ZF@Sr!aN{xd*f4ip`aXXjft})n>U#P$6<8mrDo|^FnnuGzx}*f zurWuHEd?qZtRG!*(r{_OVN#~*Vxc*J)LYEgjY2oWepX$7aEin#68xd^S=&hpZWA4i z?@+U+YFD0kwbU_2RlBjtRLi>grL%89y>ksE206jX_(gsEDmNn3OEm>dE=2IxL5cna zkUE!*3S4a?NesSh^5jt*&u@+A_Suw5?aob{&a?_+{N&gVyhU;ZS>ps}jiDL+nT8jA zK6Us1yu3%uYE)dALQcxQ3xnfmhT+uSf!w5>S?K+pl%7=AE~cMFW+6GG$)3rGXtLglS%3) z-tI)^8jOrYWazg2iaVEbrkEbVT$~_a?!83n<%(8m zonJO=_@5UX1qkqz44~er#9l1TRXN^I2N2iH_>N9azSiFW)oyIV3Pyb4_cNz40Lmr< z0`y@>Ii$wpjQRA^e^4aL81m)qsL!aerccW|DIFh-n;T`AU9(D8*>o^vZ7?3JDCMd% za}eU7lZM+l!Hv$I0=W2si6p*EODTd4Gmsat4vUN5aWb-I$L1<0lwELqfFJgwtH;%S zL^X-@=?JEdsZrK^?2JM-QHWkbi9Tr|kyl!hAj_08O!p&5njJgPU^emN?N3V6YqgF*ugsO-!$e=vV z{^KGI)gDVa#l8hwfIyg_bq48mY=%Dw)L3#P)9~wXGqwMQiai!b#`v7%>rzjYT#*8H z8(^Hw(anyq6gaYlB^nLk)d4DAEQIYAXBB?m?50yN|3ywzo0g%PEFA?>^lM_)-g020 ziXc}tKUD~Ay)NC$QCgMwyvV`LNLC=iCK}v;jV~Ii2N@Fz2oS>WpbiwA(O`er{Ar*9 zHrVRvhV31ykU@;8lmLl(y;KSUotbX6>2m zMiZ?29l8FONZ#B;8ko?ZOr?xtKm-+=z`U3ZnqkL5=`)jE1H`TaKr@*hQ2&nvg}%-D zv4g(>YH83GucfT)ga<8?YcW#_CJFJ`IoV8V1ca&iN*1C8#~}+W6nm)Ivjp}XpeqBn zL4L}9YoJMQOU!^zs6d)qj-4r}Gvij|AezkIBZB6p6H+%RHO;6+BU;Des6Fj=A?_u5pd2QXR2szCp8BaX%$X4sn1a}aP5+6}NGfK-*X z3bKPx0REE{lOV~aU%^o{D=V5-QDgAo!)-5I1m6VA<2}xd_=aKDn6#tgVOOJ}6y&b- zNDHVZsLqCXkIlN;uh9PFVfkA>j_)#3i#!AX%d(lq2})zeuxXua4IQw6f)=7O(6o?q z-lrK10Fcdh7$;dnBs*V|i6BCg z;z=;7pp^rZaFqIa^gZ08v0)YEAfa++E3UEQ3@D3%K)h3Df^-EaFtB<>hU{cF+5?&~ zImT<@*?})kNaHE-JJiCSwyD@on)aQF;QGhhh=x9YC}M4}Ib@8}Xh*HTm#sP||0*-l zH1Rr7-^d-dG0RZDN%N@89zJ`)m}RdC+j4h^%!`M1MqaMhOKis=w|0fi928i5*FNWn zQvG5-lzYMA9p|V(yPI+W1l$^jOJpDNc7MoW6)7k_=YUj4hLyf7@6c0sNsNijE@&C# zgVoSg%>vemR*?Ami*!_Bd})>PP9>M20X0ScB zagI`sF_FDJCyD}peU7ZoGxL1}##?ot$Py&N`iLJ(a*chQ>2`e8-$!aT_D_!vcgkyC z3#mjQ%q-)uv5DOi8uU}Z>;zf^o7Lb`P&CJkiqAyRMk`gQ+a9|Ep&-0}bVFq6Ac}-H z3lh4=M77RjXeD9UUySwv3ZM)olXqRX4Di)GiaElH5F_~voKYZo9X}5wGl|+ayvs6% zx(ewyqV0aAWyqie0&q@_tOELM=bhD5&^%cH(1uFOwHf0VpDoJK@9|tsdy0bNeiUMe zS_#8c-Rl_p#s$}TO4!5?IN3F5y4zGmyy5l2+oOa}LPU3JS%3MVFqU?CIn8YR$m{~i zmIix-FnI@x?iQ)If@!Hau}T(2zq0+&-?*JJp(cA5U7G@Dc>e6R%jAe95FwR_P>rj! zKX$n2)r)LS7OQkjzUf8dA^M0z715Gty~&0`_DYwZ;n;I z)UlZfH`!D;1=IJk@h`VV2;5Lme1hNzpK9kg&r!%alR*VvJnrrHKnS>HL;|D-L*nKv zwWb1bO7rWD1)+07Bq__|)qZlbFyCQeSUBy*Iz@Y;VO+-vHx@LFwt-L6+%`ev)>E~PUzXe#S0(D~1sjppZ2f#E zO^M-6TZx5Tx`P=$v%4?|vPS@TLU#Smsh7PCmT~)+dcK8f#sdppih_eb*bn8%2|2KK z;&>gFbUAfW{JEZZGMamE+7K#w&RCiPD&Aokm2W#2tI>I{sjr$Z1*-OK%WvpvJCqkJ z8-l0YpgWnIBWk)fjt7Drg1h8o!B01$=}OUdZ0WmPKLB@s4&=0fygzO6yGc1sKmeFx zn5VTwGw^OHiJL?EOXC?Bt{}=Zw3(2mOy{fB76_0VCW|5Sh3AkdHCf-W<^1Nfa78BI_;yB~Xi=ULZ~^-YMO(jc0sS$cLxUB#(naL)(zgoCoggJUKxI+EVlOUdi9S^P&2P!F!>9Y>jT^8QS0Y z!v`M8alRnI{Rand;chI~fqQI^9zuNh33tO2?GLrx6mD^s?CFPlz;{~d`^>qlF8Pr5 zescC+f&;H{X}U@s`Tu-l2z(YAywm|V`ol)}V)XlAc=$rJ_rf>((HKk{xEeGLi~+p> zCqn;jCX83)Bx?L_F5=!bzRosNm};H3=7x(ck`KMPd6!qAiSL}Vyz#UQf$>Y>-b}qF z+#7pohNE!HTr=tg_w!+y-w3qrQeOwQow(ZT;1iC^-gwV%8hP2hGew4c<2ejRh&dRD z?n*mG2Cdf@+Cp%h4b`Hv)s_NFB4`YvP{bG`)Vc^_VaEcdD{UW?BkX2`f{(T_kl36s zA$p8M;2kHT3(=-?)N3bWGUK;0L)YJsq+Db3-8djb@bCG%QQ!r|p0=bUye~%5g1Pn3 zR$71BLY)GJfGa$0Cs{b=A}PypO@p-GIIT*pF)t@G(t+!V85VQN5YfnuB~lw!&+(2D zim7n#4qHsxHxPt-tC_r*nB zK8AS?t`m@FvH=){MM^U{SQE@QI^;)7URlwUQEZ(1%$~YB@e{-{mmw8_(tta#37{CPPyk%WLnu zZC+Cc(#G8S?g&m7cdzeBaUHBWx|2isyA13A$vYGQ0}@P>6spjc>^Pa6#x|uP06(=t z$ZbKrV3s7FcybtkMc*f5e~=*epydf9E;@qn$cQyt*tPyq4wj~(*i+vhMbmZg zHa`=@xi|pnK)3F!$~B{VfU*BHn#)ZBH&MpX z4V!O{d$Q-t;=@3(#zuZrp^OVsf#x3>{IB6}osr>I+Qkh) zN5UxmlgIh42-HDeK?V8cXO>pi^<^jS^NkzK&pIvUEK|2_mM}Jp86{&lp6JK^Ci9I9 ziE1%w>Rk3s0VZotyoE?RwdJ+TvWh#qe{9mK7?F*r50OKQd}3t`wnTkRqTg!8bg-Vhk702ek#N}iw~JL>vjM<-=Xv$(E)RDCPo*4~9cQhC2SPRGBNIC2M$o(}l6R~s z@|(OmQaHRilJ~SavbT6;xOZ`7cn5e@WH;0L28QW(cR(4z2!i%CgK^geEGz8&GV-rZ5iMm6?Uw=I*drel@m65xti+Gj-BB(~KbPqw0 z>Viy-#t>B*%Vfgp+*=Ug4X+AY5UPX?V6yA>8a>G*2p?m1v##!RTY5(m8p)!p_BAQ~sTt}`b>`52#aO4Cw=S5+YkEd*nV(n=QIGI#+NtL&HtHS;q(^x8njFwn({Q2-)! zFVyU*l7oAR$ht~yZlyPTbSZHff2k8&@2{zAUpRR&X6Rjg2A4@}g$9#` zi6}vuvFGWVGmaU}36)HuDUrk%DdHMk(`B6r+(*@VO(6S( z{*p070~>#H;KkqWF0u#ghqsb~Tswf7zX!|mh4 zyBJF+FAiRP8s zaX%Sk*$7$<1IMlfs^}XCelL5sOS^8weTzQA_!y$|CO%^9#d(M}22vnKfWyVlgOL{p zA40VIh6ioy0Y)wY!C1e!JlFjm`6$@Ggs&%o3k$v7{X_=LkK4h6_viUK-@Y>+kxWUT zIMLg9@!I^o^1#f$zE_1^acKNGeAuhzrC`SJPq*n1*}E=3cV-M3F~nVmVq z`w0#YcloWiz00VySN=k){6x4#cFo`Ot-Mk0o?Y@?Ve{zY@p1()V&lWY%j*uo1%RvJ zfp*VpjVYjAZKa!_JDh;|4Up-N2COth2PJ@N9H5x?Tt#X;FIdAFA2KpftY`x`ncBY= zM>D;h}21Bxqg-awO3Q9Vh{yL9JuOPRtr zV}grL!t4{vhJlBYV0cyLA5VFaItllP7WSVM9o?T17rso^?O$ax0o~Uf3{;VZOCE^R zd3R)K5@&o)mHg3$dm1tfkiQT|vh%+`+|tkq0fifyW$FcB&VVdaK^O(LgQ{I$aQqV) zkL`UNoJHsa2|P5c%)g?IESVP7zC}cn>olxXZNQ!=+kwY~N8Ur~8=OcpIgn_nWvK!K z)Er91OI@O}C*>6cK$-P24r*0pN&@v7C}gS`eXtmydc0guCr?MJwd(wAbVZ-uJ|*CP zQDOe<_?MoDg`dM9{JJ8&iqnF6vq`Nq(?SAG>%tZr^3`ZuI4h*6q*eA)7-b zK472!X@$WVB4~s}t!QU|Eec^e7L-CL+#MkzW(5-@6rTtaQ8JE0U4LuQ%uDH5KiyM- zQyOA)9Jlo2PK@&lH`PSZH2{)wh?l!Af?ExTYwr0*z<8_7z~;nSy0Ze*8dg$xHOL=J z(d7Y*!rBg&CQlZE>{~mNET`WEBk!x3ce{cd;n<_Ucr0^Hgo>eBV;dn$ZsWc3if0$d z*~ggui9Vf`g$k*vsr8)7c14R*cN7zz?<28vki9Sr7jFRlGqgbGe-LRESuMIf(RZb& z+vZS;13tx+s)XiDqjk(s^r?cep&c{nHBaP?ZzRBO;McR&JG99`6JanS!mK_3$@0`C zN+TYa_1P0a>Y`L~a(n6|Z(q;b5TNFo!GVqK&t-LGTKgl}kY;h!hB*D<)m`N-#VQQp z`LY3?=Cusr!Wsy&#nB(b4OpoGtN|E4i!>3wAuxzYhh#{k6uqZanqT$+=ucR~ zywrRq@|wuw@%g=Cb}BQE{EfR-4ePt2X?A+@1TU6&(uQTC*M2x5K_o1@CPn~%UuXxm zR-5v2*x{B3J9Y_jy@a)dUb)*Z;6o3e?a-FUs_(4Qc%pGWOCfI9#|;8sz#1)TXIZIN zMj;EKg7z6BY-MYr)zFc*a9 zk7a(yWj8$FjR@yYZ~(QzMjkR9t7Gt`3no@t%5pNryTCSjrjVf)qLH@KB2clMnP{ZS zeNd4CKtdKVK+(9CS+q{|7;0yqF|t_ zQ1AGw!)9E^?{NnhE@vb*mfinlsLtZD4X6}yPZ3i`B!OrarB$8wAb9X+136=r6p1Q~ zw38rBJ&@YtAW+Rdo3{;)obRkPqf-CrhwHJ~XB<=;a{%6gL9iAhR>C6uSPFnAWoLIz zC$Pcl#ZQDOB%o7nIHGi*yhqQt0BuO9++jrK#9&hmOQ^BKjXJd6no~`Ms$VfR^q5%H zr8RC#nT+YU;6QG1D=zW|0snE4!33j6;2JnGZ8lNr7aQb(Jd+^o=SprrIM4ZHR>5zW zDiVF-R>!&)ZUrp+cj#QsDc=fHN2z!4oJil}cTw89XhPF^j?buS{;0_#-mKL^DE?3t zvn{g34(iOjMN2otBH3fK!QnBOghJj*iZt4@wJa69=w1(6BHd>uXGZ{k)gzwMjid={ zf03)5L)csp_p8@yAv#_xWssM|lD&4ZE0f9%}wj9 z_&Lby;W6`%{OX}1=>D$fqi$7rm3>uZo`ZDLwDq*?Ah-u2WI$f zJ|dovn1%v8_|}^v7~e!@vm%T``fc624|g8FgtEWwpeMD*FWEhNCM!2XFL7g+YBf9J zF?aCRsz45I{uj%N1QU70QzDwH%p6s2+b1hq<+f@O#VXIfius9dTBJdeD3^U3RfU^p zR*{;UoHAB%p)7CGgi8V1`cSMTZ~;gc)Ti&0lmMP(ps0rdbpxufd^0K|eBi=SBT-&Y*yBZ{>b~O3l|*_M%;P1@TP_sa8 z0Lc>Ktfvh59?6o~T;W;*Z&Y z^rG=3L!SbCQKiAVY^AAMyN*~@J5VO8skikaOtAslq8d3FMZg~dfY{)*N{Ats&9)Kn zR0)B^*76zxa;#a>8}J>kb3-RFle1uQNeL{i*$dO1!0iq8`BO!u9!AXT6o+b+op0A8vS1-7?SI3m(x zLzshd!GQ_}!H&p~huh^5IUQnAW?%;h#le{Usg!`U7rCQ37|bAxp=L?P9DPwuVn^aW z;%og>i^R+HGn92hE|u`E<6{F%9$y@_WIlOHQD%h)6(OvBU{(Pk=Fy|5W+w8xK1|YG z5qEke2NdDU8K?6mkCLKCwD*MoXip@jSw$^GMI#s%^%~)L?m1FwR#shRsl+L6m zv`9Y`{MTnH8fBo;uScl&#+m#edbS{3XvN z`v^GkCB6`uP+tIxkFfpggS}9&+1alrmd^3_l|5BDDg#vm#`!e2FI4nL^3TX#-e~t{a%79WwL3m z0lWJjq{bNIB#K0HHV!CTK)jYNwkdX=mQEekMI0(l!NqIeKVfTaFGUBT_eQf=mUh&{ zS5Vo?qSkoks36!@eyN;ku_5y>$asK|m(}=F z3U+f1O<>>7kg3e$*-%-XT|G#>Re9D6%DTuBoFFF)KZx@tM1mK*`1S-$`2-#0qAXmF zJdIG(uGaLf^iJu+|^8!#=1tTM4?tHIl|hu6~E zL$^)>Eygxe$`@Rua+MCPgL2Q&KrPVu*S8$GpHf9v+gwG*ZV$mNDiZVa4HsYR6u|f6 z%NPRWTvqX`XV(EN3^fOvDRsKaU$|iz2_4Yw``yxn8%@^D*$3h4v`?&dQXRRWwz&O} zMw^f;AMN9$6A+90EH+PS`heP|vl=Y}Hqp4GO!BU2T2k=YABY@=1g?Yh0VnEND;fm~ zl2f34wLw~na8io%P^8}blhUXTn7`Y`+P@y1kx0$d%RjA&M{-RY>YdM|sN`ACwjd2z zE6s-{ndV_zW&51KK<&wMVgwJN(s6yA?H)c z_yo4Cn*#f5nYrt+A9$>UY%OD*ro~A+CUXc{L+W!#1ZSH zt6`3QUyPnDSi?4TQNp7C(Vh}`TKP8_v_`QCR7JXR9(TQR7Yjgh=Z%kSGr&M zg!>s1Urc~rH{K5H24kP$(|{#b>8WQb%KTi(KQlaipbm6A_T%OB z4rv73oZs{LZGMs*fG53~+mR^zeQ$cRDmi&#vug2pvrYUKjF^|sh9%w59T-YH*UF#*w0y| z&x8Av{qbZvX_qFOow83do1L?7BAcDGkMe$6d=I@6Fd}Pw$b~eVT>Vw9nFE)7Tn<_@ z=qyxK2~IF5{N5r)pmJA!M(*eP;?MxffXxu{R-DKEcd5?cK){DI?A}9U^WzDh92c950*2G-4U@|6tgUG`1rI-360nogb$Pej^O@NP?e7S6};FiKn4J!@}V9B zkfD*0VGYocrikX7U_J`btLV>(A`)8YTvah(lDeTt)AocX20GH2H|%8sUDUs3@)y#M zmtrm$;1@PXK=Q&#NrJD-&>3PuD}vUJq4yAv7Pd%XmN!OlD}3ucz)8Zh>{xJ+|E6W3dvju2?&aS za`E#Y+cNA@Ut!_0DxRv=q2$D%LflbrNA=iTpv^ESnmN`W`k>c8^3@%iy6FwQ8pQ7Hi?xOGc8Scxt*x) zHb=gbk?+GX;FRz03ORT&BkT6B+a^oFw-4~-BR!-xn3skizg(;yOE^F|yV~*@$^5H1 zy|(57WSF&BnX6rE*t6_0CSJOR9DoCb!L~8SgDsvk{Gy&UBx7UjGN%1Qzy3Oa%GXL| zqTTZ(UIE}$Pda(OOtWLG$T#^sE1dBF3Tqrgp&4QlWvYfy8Zs`+?W?wo@Dv~vY%=gk zHcAUf+!cXl3jJ;DCx$?+&O7gLC%+!^bx#lfDZFRMHSnBi&qNJYZ(FoNE$0H$OTSgjXYCvR!A$Bdla6^|D^Y z4bmV|=)^H&xG%Ke97al#t@8QZ6Rf|##-=IAW}w}1mME;iAXjxlNQCeXP_^q%D-$`5 zDvX7CVweOz=hx%o#(sW&eA)G0LrQi*!e#=rC^KU~KzLtg0{3S&GvnN21rPGDrB2aq z+62;?8=}3T6eDp1M({FKy_RUJLl_W;owhq-jj0Qwh$Eh=WX2-{V$nL(0)whQx&{`b zfcM_;IZ#Bt<9Df8rvm+WK#Xg@kTe1Kltn&75L^doBih;@^R>m%Z08p#>xKZ2VLDHcVa}Y%&2$j)l zsy0-_rb>ak1*N~B3ry*540SyW*wAxF7#5oZwi~e`)*1K%qbNdXiV+%XEbS63UrQP~ zqW~CcD+Hd3=@{C#G)_tn=?38Qm_z<^P-3czX4t3^G(ITzMIdMq;*u4Cr%sg48BmI2 zMMS?Ex0ac#^#s@70&Zv|#JWY6i5A6G-2~BY9dU+DbgBRDOQlPWKubg$OwvpG%yn8C z&^O@*UY3v+v7ZWYFBstowaQRz5gG-4k%u#^d$hX`)trV(_%>+&)V zNCHEc`a`}1xRWxtm`bC)c}xw7wPKjAnnh6NrcMuVr>LKV@db?r*6$O9X3J|fyO%7e zMUkc|1vM1|b_E5+pX#cfwyP+r&?RUoQhNrNYSc(wMZCVn)k%=O2r?QbP{@<0Yp5#R zRRE=_X0qwF@^=VBm9KQ_%41%lfyFaM8B(sh|1SsvbWzswOf%KEHDSdwRKd0lM`BW> zpKXS&xP_nRw~N#6$Z7<8iz2FUZUJ${9nirmqmRl^*+oAZ3Cuma4wxypc5B_UCEYqk zg)WFSTW^G7-yCs$AA*n98U~X>^P{r@M1OqFKy^#EbQHaUodr|P(pppm7QyK$1M+rw zq9H3|*uH_J8ww0MEH}ulP(U=0a5Ed%b@IrcX+?KMpbf1@IqI_B!);lpW=C#W@3uvz zTByGf796vD5)qmV-DDM2k31|42>}CM2?2oF8#7}9oGb}$j&4m!V1~m(Cu%X5J6+DF z^t(yEdSg{BEQgyq1;WZJeuKcgXB0izPA0?a9Bo+rPGR9eCZ>v)n_M9UJR?EupnRa< ze6g^$?@sy`Lus&1SM4!@4VCpwGU8mMlG1JleV85s7(i$$ilKRLzMxuA9KeAU!p-l` zA-%V-2&lxJw2i5dOfME8k_44O+eCiToidp+Iat<)a|+-_U15h*GeG&Fd`Cz@GgwH% z`%+*FCOCBk_gl3?9W;byvh_@G#vCEemUHJ;`5f!-2oTMACeSXrMu1{QTk!%ZpKk$) z)LjrTU>*db(i>dVp{$Vs99%kUex)_zu5LZz!J2kVaGn({1%NJMFGp87FsGcv(1Jtn zoB_Q2;@WVLaQ+!{<%%`5v8yaHAQwDpgY`;FCD4gW_X#NSc)w2;PPcWhS5rn(FLQLN z3jMNGfuR$R7&5=PT!5X%_rX@8Vn=kz$IUaP=B`@TG4)K#nW^nu#JM^yCnV)FXJpdZ zteDx+y14~YStcWx#$H>Q=l;2ldhTqGUYzD-hk<5s(oSM+I^Z%EJI1b;r@-BWf^X1Q#d3oFf}%8EH2c#ep&g{AOJ+fqBk)1Ve) z{M(7aI_E46tYRA&7@Z>Wk`KeiWR(Qzw~efTXX;lX(+|F_71rGh3avqMd>x+ZGxO#a zj7-JNTO?Vf`#X_lQ1_-Pa93(#ZERCK#poB7)+(m@3uSd_*k$rmS?y7$#?I{L@tumI zRT0XO>`e4rC3&u>q7H){8@izo$1`+@!WR&@1AR{Rgf%H04@Zx*K&$o zB3O4_)>3Y`v|O*5x1=@m`n)AdcpUK}-d229_d7(Pg}G{X7wYniRjXL>lZz&{o@ z1pI!vJ>3*H;0MPM2Fu;xug(*Rs;Ha71;su)4x&E6DUmjgItv)}Kt4h@ty#1snyAs& zQy&Eyn$a{JX55uxfb~xGzCezyHfe6RA1+qFd^gxhh&^3o7UN-g;ZFVQfO?>*eatP> zome@91Gxz{oK(T;m^Ah`!dSJ>Ag|eG^y~x=Jgw4%&0)7DUtX#)xm905EWZuv5D7p? zpf|!ChFEcHoCp~Aho{Kq!Y;HgbFFI@?5Hz}3?((eiJTwbpmq-n2klvEq+B6lrL7!L{3=nI17SfxinHAj;&WGacVySY?jr=jrm_ZAmk zKjhiki-!wIfE?eYp)x}R0<732GUiX$ju$~|%F#P#4APvt;d|*{`3wR^yFt&&m>s;v z_k7O79R2)QU-izP?-suHP`}E)?ibSR^(~_%w66X%a?_O*`&M+NDil0;l;zNCLeputO2XUYA!Codk9hS zA8KRWiBqY+y@u#Fe+uC*R*+PJm0lGzDzBv|rGB=ng9_uqcp6MP?zVcOO#mgap`%?r zu&*Vhg^;4vk#|A_;G!7tEHh%^m(Vda??HErq+u}2nJMUCfz`+$600X0@-w5dbNMtW{(hsaYo=`gm0WGf6G3@#@yf*FN9qgSoU0Y#WZ=tk9^2J$$io{NjKxMQBoE@b&Wod2v zXt1bmX($?C=cJmr< z3GJV;nW}=@+Y@No^3)nCQzRP7p-=Mqm?KpBy?>Vf#lWhI$$JvF+;)+3gb2ZjhQe-d zKSHE?@0~D{13v;HToxR({tkTrqHLiZDL@2$AVRq~tA$bDN^_<>O~|f&^T{*B@O99S z9|2~{f{)EdcC&Bb0vMk#ciy`At&S z)|d|g7U47K#wR+El@P&fwL%}2LmLfvw7Gb&jB1tu@zXorciZl^SNxjX_9lP5S#S%=1fYLPLPe__bSfQ`>6OzSlzwjuOS5*DXunP&GQL+u_3|1J$ z&J?JI^y3=p>UE(sL_)XZge31<8LLk&$^r)K1f1nyxS%h?RR+e#<;#2)G`)RV8TNS7 z?*A=@rV`D3Y-1|NCUF6d!VYTRh&rLrBq9tyYBHUDJ2 zs7%dB8<|?dtgRyw5_i4Zt>~>_ee>#f&y$zC`F3UCviKY9^|x(4P#KR+`KTYAOxgSn zu!V#F%j&LG2v((PPF%iuhx@(D?7`g@rDH(|Ih(tL_EfLyq5p6c_<9gH9v&X254W9< z+v1DW=cU~YIPE-NbkBW6upAqX>#J^5vP;WY?AjhUz6y5ZX1N}G>|jhh{?`wzl}J~n zkv4;#N2vU=ZoKUllyaMD;-r9gYa`VJ(T5Ff?)5rbT~><4nh$F?TXjG4c@b?I0~d$` z9j>0;Sgb7%=DL`V`eW4to8Ihx@N4sHJ|^=U8Ef=U=M~d`B*ucyVx{uYIhnNb&0WkN zt0A!5j6?oQ+_o`ye2t!+adB7SWo^@xoZkxh1Kjh9z*Bt9D=mK8;LOc^ZMELqr{dyl zC9o&g2&{96L0pm|5#rC+Mmjx~WOLM;(0S{F>s)%L_&SBsm8_COa4in-tXOlo%y?77 zk@Z%Ba-m(yz_gi|u^*VH`Z~^YXBA2c@igjXw-STt!j-5RtDXZtAh%W3N5BN+73cdZ z+yidbM!7P`<ve1WQ_Oo&$KcjN_z^9Gs}|crJ<; zZ#Cdn$KY@=z=G|fP^iNOqRXX4uK4N=&AlGc!EfSzR`KX__fkQp41y|xI&Eq^6&RDPdj>8tQq}{TtdOidx55BD zTIPu(u<$_bZWGnCu}x=R3d+`)WOxZx{H9>xt05j(IxiejF&LNlX^ZHNIiMfpqZZQt ze|)`TtSCVjrn_yOZQHhO+qP}nw$HY0+qP}n-uHZyJDK_BW^U4*^uJE0R;}t<>wTZ< zK7GjTa`lpU23GqVE10KD&}Of;VsUN`s*WE5uWPK(1r~r@2M5Wb_X>ztzX}pe`|;M_ zxN7kEGWh)S)}=U$iClgYqLbV00-cG)+>*8s(#R9#Lbo`p9oNCi6Ys(**e0NimgsraNy`_r1T1OLFnWn?+wjiUXcu`5w1HI~%E3`gLEd-QJYuKx6zd7M@ z-agK|65gE9#vx}HEL6(vQth&B@}k!NWVGz`G#QJ(*S5V(!^)t`b+BvQe^Y7`jz;*_ zA)I0J3f_imtM6|;%Ksg^jt4EPS)Ug$5EIDH^72V&gbj>cTQRW z%MU8XexHI{1ot0kIoCsEr$jnIg~qM6q3jijW-N6N$ZJ?5=Y`l{+{A`Mr$<&em9+qb zaZ_t6Je`u)5H?|BG5bY$Wi-3)q^s;vH>iD9b)~;jYA%_0t9yn;>1G-Qe%eOVU^XY| zvj7<%Dgk`UA+Lj7IIAqU+BA7wH8bS?(--oUq^4&yBx-C)RTnnLeYJ8|12z zd@Mt*LoS<7{4iUgAQ^a(j4M%fQj? z1YT4Sribr>?Y%Pb%(E}-dM$6bOUZf{I~NdOj6)FAQFaKA@?{{%G>nA%CKO~ENk@DJ z0nSbQ5(;>YpbtOTWxMP0uHlzizY1;U#d8CHm=wzQF3scKVqcq@%Z& z`waFC>%BU~4DAetn0CpYkOQ`fs~I~iH&K3Z3HpKNzuHIM7=$;)yvwcLLD2?FC!K}I zl8h5;d@-$L$J!#Zx_YMEw4IQh& zz6Jk(kP33}|BsB=#L>~t(dj=jVr3b-O?sGa@G(DpMvxW;HuYLS$4y!;=PQrcgq7}hDxSWRDI6mASLldj$k@ZK%{$5P1xrw=e87r-nISoDQH0Zpr*BBBj&Nby0 zHiB8-tg2u-NU+>}UIG=S05^NS^hY7vLh!&@^Cet5{TsqGrIL|XqlRENbWby|2F8q; zh&-oizv*+mfplp|^NZ~u7WZsbj{Bb^-@pVk&Z5^5gHn?aj}}*Ccpr`t-apP$>65k;tdwS9+NA+Snv8eOn$qVy2s19oSMk%*7U{`u2$j{IH11hlnSwCP25>% z*YJCl30pc5v2dpdc42O$Wg78>5vW|~vYJf4BrdtBg~m(MaoEjgO0}#nNj%&z%}TM$kuB-PV#1hnJ>KmUPRv)Icj|$RxlR1RoSwEex&${HjcJgqYa%|w!EqQY=a>a=wG#Wf-=QQSW^!D=2&e;1si~%M; z^h)L$KNjzU3d_X1V3bZj6AO2L4IwAMi_(!jrYQ}aX+pmG-?%LQ5x%QobjI)e6TP4P zW29jIxA5K0@t@w>#8}VR!stKp_hwa_s6$qSpPss3gR%N5r)SdX6y0-ySkxMMa+`c@ zzG4FN>hYRzYA+HKyY0gtFEe7Y7VBG7sOPYu9JXohS@WWG>z97j=NLx)`jvt{#F#K2 zll-!#k%7vIw&7dV0+DwC6kJ=ZHz8&d6XLJv9V(}=mxqIggPqThZAT4dM6|#!+ug{lHyHso5tZ7=hmln!>xiD5?RTCWz_^+QzPsPw_D4Oh`osW#7 z+%BffUL&SFu>)LJE|cWlYsN6o+(9dYTkP*{Uhl+MntY!nT;|N^WhZy|%A80%s$`+J zwWYVD=9KB0`*Koh`M^7Q)tN!4vDYzug|E(u!IZAhO4_q7=rbE8h}m%(S1#s;q(h~E z<}keO){B?3!vQ7V5K)6h-7kEemBhZ8g}~1-VYZg*!#NWmtMJ||8#;Ju@uZi3%o6{=dduWtE&#)9Z|?V=I5N zdky=o8P-y8Z8|;qx=$5u2);_dXG^_`87NbrpAv@sJ4EwS6T)iA#`4Q(#4I9{nKZ*5 zdP~|r{1&uHED*7zjirdDMSFkD#j2;FWuKh0EqnDB;aF_pFmDG~vq@5$?P?ZV@`z>Y zgym7C9a-TYlTg8zkQ2sbmUN=$8py6js*UIIs?S|s;}Jcm?E?`;`tEr*upbb-oYrgy zpE$B#oZuDpRwU$3lav>5-_@{8vUeG*k#7~$S5Qiswi#DD zv4gmEVmHXU^UiY3GGxwjJlB&9Z9^=tiYUlD zk#T;+M)q|{IV&J9lQnSJ#Am0ZMqyk8)iGtL7a+NrCP}Tkwl^_dmV3Mm>_n~U>a|?vVZ+BVskP?@|!!uleXc1j0U{W_p$?X6a9i7KpgAd@FWgrH?p9)n!yqbeslaFGF zqyshP&3vkjzcY(@he69%t$tw+2Ij$jsafvw3SL&}*5V1;G#%o#vA=08Yvd-g_A-eX zG6kmB0bLh;K7t0~V3({<;ctvhybZINGF zTVfzSywdBhZCa!12zqtXL-(XdH|v7y(WGfD3M$Q*k0TLw(3(`9za&9;t`$XrG=znw zF29fz0kJPW!$cCk6UM0`S&s@H68XT!P`Uc1@x`I*b&C$FZfT`u$0w}An^ChT@PDt# z7 z-50e4xZtdZEu>$RP%TObnkb87&F33dWW1PIT;fSTwV&Y>$}~7>&irw@IUPv;0}(xz z&Io46jvgaAD4?3GO-`uKE)GgJ1`@m{m^e}M%_}s8ly329AI~pI$b~ViAb>|u0r9QR ziH-1;>|XP8KHDJL03zOUoU``K?GIX3txra3fF@Kvw#A+$UqVw0YStEcm^ZfjcODLW zPyl(JJC0D8hR1CMI$~A5qjdo;>Q;|$#fO}4 zy+dv$u&+0Fi|n*Nr8jupl7m-ICnFzC6Ae$|=kK;}*E=gwFZ1E*KOWHI<$D39Z%_ND zy$?>hzRknr>7mO|HpN;w=Q{}sBH_;+uwe*;Y9rF>6;L_CQ+o)LDjI3Z*jh(OqbW3X zStQ$^O;mW&%THmMDPa|n&~t9m3K`Tq$hd3?Parip z^*R~Nrv0yZ0nQa7bqOW{uD-B#N)vf|@ZzwJ3C{^@CY^)uMs)A2vv}iiT6;{qS4#pH z*6#HhVbH%DWSMsTT>7zYg+J(#!&nuS#vW_Zgyo;F=+~ z!5}wn5HcBGN7}Dq7Oh8=3~&w4Ow4fesU0MFnvri+T|Ki-aXvoyt3h|4CCYpuN$QB? zq_*~#qKFsZB3@Mqi`%aj-U?1F6JBlQP}@MaoF@5fbxU2K6D0=P7&$D)_UeJG5D0W# zm`85bQ!-r}P_b{h_{{y4fQhut_nNjffQUP|N;CEDjqZG}FFXQpEh)Gx%K&QL*tW(r znZU^wL-nt8xbu*DTYFJ)Qar4v8uOxdUTWaAcJYHcWbHnQPjM2_R2^p)qD?N|Lpr?P zbiWGZytfE^Erv(^%6M%j^*SD^1%KY}E9sJUcSzc#tAEfuw&%P=Or>o>5t;!BEdY-I zS)V8dM+z6v`4TQ%!bb7_{d>dIjpwtr1^7PL``gILL9y?M3f1 zHJ(@3hDc-sSMLwj6QSgAiYiyom{Y=SRZo+MmSKIs}VLMclMetWQ`yC~r}gur2CZHzT5@A}7Uw2zfI z(zS90+?x9_CpXtj8UZBNS;awRs#qRE)=C1;{YVjci$EU4GH9mxaRcIbZ*u#3_1u{A z-S!=IafvQqgsacHl)xM6MYR$i_UW6~9c~|Ose01_^bxA6%rb&E=grA;Pl@lHfj@un zWpftos!lxhT;}24E?sRD(}`>;l{U|cxdwEYN;<#u9LSL-OR^uaziVpmonoPE#Ke1&uPZxSLraP#EP8 zz2x&|)DHz1#N0j~&sp6q@+b9Su#eMh@?@@$08B{<(M z9XGE<<&~u69)F(W-?+~m5yC5CmbK9*T{ZcPar&z%=JfA1j&5KBM+m9t(NNOX*%tT4 z$hl9{x!(Fsf~bs|+7Y~$k$@N!YYH(m_+0hxOorwuXfi8e&rt8B1YuGoGkNr_xC9tH z)a3Wg@<)U3ts=oAkMx5F$-l}6YC6m0BrU0TLzh&Q*$9k!7|@}?IefCD$$I}cmgIjx zf}Jn`kUr=D0KAF-0JQ%dE_!j5r3|O`Ek#?Zq^Vao5>-+gxg1pwWdtQe0)?HxFcI>w_M*w16wBSM zsL)C&(~cTa8tBR;DZ{XpIEo*{h*jE1)4qWn9sbp%YdZn&2rP_8$2%Ac?#%P>^!&bg ze7{*dcl5NWt?q7je=>RA;&k91t2yW2;wk96wg+J|+^6$(BVZQI#)(@Q^@ZUpV> z>&0Kqwu^ThjoMom)B~P4KELRiM<`q`oT?o*di3>zmoQqa^&0f@cBAgRAmI`^Kzh-R z-;e2JHO#K@*7@q3dY7H3ZW6yM zzA>8~1HU`E0o2C4)R1dTS~tLN@{7TwM0 zU_Q0@e(neRUN3leeOB#(1{nhdxb*Y)-6qQi`sbjl#YCTju=u>}d>$`K96~n18gUdB z@%38_3=CG+x1r%Na$q;1sv8bNqTODo?b0xGa$l?JbZPCLy}c??*t>fs>z-5lai72a z1z>aTcSc)dYL=a}M-N2LjE=bh9HZ^yFa*p!T0m_&WwW%r$ty23xYruDP?K9>@5^qT zUvyR&@fqwjwr%%!r+#GuVH~kH%Sz~dEtVNG1vI< zUh?n&Ci(6-dtyL0RQH^b8G7O)c)|pJIqe}^S|&_@f4V%qHy<-66+KYWW#y;Uu=x*ANB_dn1VHhV@bM?}9Jr`MR{aMP7r9PLmXYXxsq#=1L9 zwt_B=#Jzx5Rod~edCG=po;mDWGcE0&c~u?oqOuAWmXgTOu#|7$Sy^klG$NoC9wDzh+!KGDSGTi@8$PULHfOTx$7N_f> z85WBk+d^F5?(`%@r`l=9<*H7fGXxSq3C{30^TY5@Qo>uxk4dY@@0#of9K)%z;Fi=Q zR?_1iV~K-7z$PI+dm{oPf*bE_mf5V-Eb&%$K_)(^PM2wiTyBcNn?j-{1Hd)(3|G&c z_CH$|gY{NNaty0UG*)>%PcK)uT2`v5weE-tQ2I@2KwO9qzHAxG!M}iMRYr?7glUTPSbd5)UHZEWY;KIRJ=}`f^Nec zVa^8s@+X6DF)6ZaSMuX&D_cmi^H{YK##B?1L-%_{=nh{HGy}G( zb8Ok-s#qGqLYy$adi(u)F31T8yBx+$hn>7Z0HftosyW=0h|dsP7WM!ZK(pfOPt$Tk z*G_H`%RcBDGsQ9a?@qbz11L(M!V@mB@r1**nF>?lkXEG~3?YF(;2KvFg;|N~<6wO0 zdtXtL>5t6R&GPPToi0ZTJ3*-K<==by?~ObP%}e=9FWFRHH$>ilC^w$_t>H(vS%C^P zLb~NF8%>vRXo&{jZ!+)Dv*zjb!CUQxu8w*XT-}jwK+>a9(8;>shk%Ho*Yf6vc8E`g z<|rBzEBc*r={~QaZ~=UeP~|Fky(0~%Qa~er^iTz-%Aesn=?ppVQRDcxMgpixdOPu44Sb}A;wbm@{a*I~u zaRd4ApMp1i05JCB9GKey_C2T913F&7dFD8P_MPMU-^w6$k(Objo&hr9l+D$B&*Xu} z(u9Xd>-!~gRguwG;BpOhx@5J>!n4~hYCXQE#5DCvG^^(C>k9@U91a*UCf&8*J^?yJ zZ8169oYAk!YN3!b(VX<>h0)zqyM6_r)$oe5C6a=NDj%(Fuy@=JM@%~(KoKWj_Co#h zSXoEs4&Z~5%j`lzOBj(%&#h3S5*pi^Ga_)OSk3ksk)A1ma&iwV78hA4-uS2zkODHU zvkzzlN!r8~*YrgTP@Xxw>(Ks!6#|yv(r8@+5OW&K^jD0AP(8;~KF5%UB@25LkWK8D ziF#men&Y-hpGDo9b4bK5qu3RPM4a5(x6yx=EJ7B7GC)n&4E|#peYU%VYvA>M_3X0R zzJBtK729WlJIHp_?4AiT(nU@NwoUDm3`*HY$d+#O96!Rl`Mxa1 zMtU3X^(C^=e>k8N;&oKFZzQl%M>mCi=+KmgWPCIBR$09@GP$lyzc`9@)WkS@|Au8& zZ!b@6v5IlNCGPD8(s`~m$ZOS67z~k6$U#zR`cFnrF-I4)$_pUp0lYy`;;fb0Zm9Z#!|1e$Q zGm0%nd5Y4VNqq#)%nEUygyftIV`hg^A%ib?e*EdewqRh>P1>3}_%Uleta+{SSwW5s z%vu*MFF#rM0&?~KVVxK44hO6{cLqoUWR_f<&!NX3{C$R&wiyTF!oSb>MzgAx}7Wb4n`YloMh_dN7!CNcNzW( zmI8;ubXl3cEHl}+0W%)}2uXmNGir4&4xGFrU>&3qGR-hN^-Q&aGn5Z0VZ_nASQ|sEOI?V?MC>;d?#fbPH1Af$Pk8eJ2F?&M)r6nchD0 z1js)5z+cgJuKMCq`SUi6?F>C_CytJG2XRe?8176n5zzJM1V% z#;Z0$=tkOy_@^Wv=k0c)&6h+v2W2#rPM$$B&avqG{8kw|Wz0n3`}}~pgR^TBvnFnJ zv}}y5kj%PXF7DsY%BkGTiX5?1u~R!s_|#b1=qI|yLTJ5!8lR6@KY+{#Pt)rlTXMI) zXjN$SUCRgrOb@_6ltPVkq-1Bfn$@;=j4Ct@Vb!YN@xY6frj^aOFdyWWXX+iXlPfxA zdLF2awA>@tHT5M$mNA3|{_%gN-Q`gz*_C5%_x?yXQ_n!iM4JB*oZ|0$Q-y}GY_^m) z-{T;kCj=y-ven+*L~#pV9Jawi2yYu)H>)I({>TR=uYk3O8oN-Er-8^YAu1E;it4V< z6OZ=HpOnyB@D%ty*R%ydLb>=8z}!0;J+srd2@i9m96pPJR-T!|GIXNE!+>lHZ;1|0 z5)Ny^jSZ^?I!z3{7lIvLDZQMk^cFu{zPbpNP4-h#?QHK$& zq6+F@U&kR0+_7##u-spdi1cxWa5h?>$^ux91C5M5SO&w9da&AdoIcL*jA%-tBRD?B zN3NpEFEGs49v@x~D2!}9T>-|VNRth!A5y1<`f@b`c!*CL=I9Sv+ugwHN>#j8Fw8*-~vI&}UN{1?NCM zE|F-u-8L!QXH3ITXT>b(5Uu+M%5v(Z3fN2@pp!w3HVg9K9e^lOzXd=TqhuV-(VJgs85}-1JEU?3h3Y*Bu0qlmaTqBzr6is)s^>kV?SQ9yfF*YJIjtFDok|v58OuoqGYW zG+_HsZe`mjDryk;fP%l`WcIUjyo?21-6G&$tP-;)OHN6}bsTTV7UB6hHrMrJl6IS=i=Uq`2B>AExkyn~?JIpw|LR zZu{J+%!AK24V;w=GSDjq?jK)WM&T&iUgJZpo*FLz&N&p+Sjj*!s;{HX_g? zx_f5t5HSNJ8dn<%V1fAINds-*m?A}k*dQpjqSCcg7nic#51NHD8MFwjp@q}mBoB@# zz^;(VL%R|$$7gQwR^p&+Cb>iKmr|owR?*uQh=AOPXFQRBNP`XtOXD*lN-FwFXX1}9 zqnjw+mK`^ZmGB=hWgNx?95XzU>pwckI}MCDXR8Y$YfBWJt76JXfeaynaDf$HuKlUU z6rseEqm-v^GirQN7I5_m>%kMCzyrzO4N6rqXi`1!jHavvUH~yBTC1*rF?ZN@ z`?APD5~`LDxd1W{N9XdN#g38R^H-E&wdPCBFJAl-fsyYHE={|C0_OfkkORxn?O&wK z(H&m2a`(iM;~P){J=82#pLR#V%XA;$$MORIm02%^__#877Ag z#5C#n)-V>)*qe7S7iw^am1BY+oG6_7F;G^{;h0cT*C*5;ZM6UJissfCR9CJnLwk<; z(C`r$?F8jX(-=d3#@<5P%U)zc>J98krn&sv$e8Lvi!=El7Hx74h-bo%XR<%mpHRw< zly*-_YozI|T%?YQmtx!jGs=w(ZJ!;$iMp>IXoL}q!Ymc*k`3k1V#sU>)kBo5D@ilQn_q_lZ&isza^Uqhd zt0l|gL)miL;sJ7_7p_=2>EXzwt3&pH5@!L91WEAB1s!vyD*$LtRXtgHp2O}=Hrw4C z7S=<7{Ppek>u9KE&HCzG(oa7M+M>L9q(i|`Nbq5}lg*GI#ppjtF8wJX@?H}4ynr;QvdoHQJ442h$s^yyw4O;%E9QRYxKkdMhjAU8|ECQ-G5h! zvc;`GG#Zh9O+1OoaD$h2(DpJeVlFZyHs}_eiObUU*)fU+Dj=TCQ$0bdTsYmIB}+fi zgn>VmG0_22ytS`(K^5T}^yo#Aji=)nFnUxLg&Lam8LuPPT&@dsx+z?+)@kx#1s-jlgikf#n(fDxA8EAGQ~GN>rmw!LMQL< zjc|+5i8P!4gdhn5pk5E%zqb4Nt172Ua;V-X2liAYn<7@{#7h%8f1l#*(g$N~BVnaa zLHZI`5Xpz7T|r~#&QI+rSTiB<7W-F9jjg6gC+4g$9j)fyapoZk`@dbdnT1CE6*>Kv z_ikLIkw(-vK*ibitP`6Vf>nLRz0Q56hfU>Np2H zl)SI$t1%BcSq!l3FX^wX0Levh_8ssk^2ID9sfiDn_SwlvH2^gquQB%Bce7#Jg6OA% z?WRF7;xmte{Ns?i!R11K4&15v!&4Uo{~Q(KFbsqfrB@H_k4E|zrHntdH0wlsQVl>!&hD4dpGKes42i zOra}WtZr9O>_Bj^id?|V)a4KA1W`H#+Vdx9rcLpO%Y9>D@%Dg%HcPOuG0zlN)~~cO z?zlGjxIwFw*nxm|hC&;CA4n@SwUZa~{2?=CwX5sos2RW3=|K~Q7c(U=P7&IyphPb? zqY!3U@j$09gM{lbR|75Jie|mtZKyyi;+I5!A@OgRbHIWhFhsL4 z8otiaFX7~uQhM_#@9M8Iyvn+?T4NN^_PkheJxN=liz(D37}P|h2q8jLMx_*FaLS#E ze=HJ&7m$G*{uN{}Pe2_R!VAbi4*%LMMesH%!s7<>jJLK_eew@+)WKR6ACW-%@>FS$ zPErXQW!0qF3-e;X8NZ#*F+5S4(2)hvrm)PODSms(aAg4&;cB3__j#v_A^phOUe=vvxx3>f$aGWyD2vIv|`sl|9ogy9|{(VbW8Q(z?EF;emyJD&PvfeaiIql7j zjg8&i(|Z0#tXsPs%`v~ZUjKmA^fWjE7l1?{FtCzjKu%C@YXz#uWxq_cC{-RsG@ zxqVt=U^8;YjbQW{hi~$ld<`lJ0j|MdPh?=2BDOdSloa3PfcbDv^|JBUG>4F_D~qar zihmMmK4eo-1B2&|Q*a6i$W)8glE&2Uaqdgsc6fvd&WLi&hapVLvxjS~LW%;uv#5+C zoffUcl6nnQ7nAfnm{Six-+R1cX7Et;zU}^3SNlJW3>$QsJN17`vy^|GZR-DfBjf*t zSN?Y!Lq%cMZjm0jjrQ*3vxt>+SfpXy=DtML~9+eR0{_|4AVY~;|i{ia~W7C{i%?&c~?oL8=B`l+9sBh^&*mp!kp9spr4u?*~NQ&_qG~l!e6zOE54-G3ub?oW<^*%== zD%fs$%CgS$s3E=TJ?V-%*}A38=LzNOSWV=?I=U0~fTwL~s5mkWZuXnE1*QR)^}MS^ znX?|W-Q>ENx%qiui=MaHlvOGzv9RP(!occ1-hd!cA~2iq1Q*j{iMy7j)19kxc8dyG zI7X^YS&^9bA{|y{u;n80(+?)>1KC6fjULUeoQd)0YzYMO=i7$S30*wHP z^`3dAL}EWNs{V__YSASLJv`%xfaHSLKIWgNu1=U7tMeC}&3bfxnL2Ii{W2aFkC__& zuaGHL-zdS20l%OBf;%D;yugx30jfz70 zf_(Z!Q_IFYW@e;IcQu>y2P-C+4;m(@X`Nu_8U>3aPNTs9cM!_vaqMy(CsGWgd0P5= z`9j&)|| zUG~98(qh$wS&n54lXap@J!Y0E(-laT3EBGA?9_;cYsEd#;<|-zYVJDE=*(5mnAFyq zPq~Vr**bJ?MNFDU^CyR2y8%*_6UZgXi{T;n;yYF6>DznijIJTw;M8rAP0acgin*S< zn8B&WyHZHXyIb7TNTsx%(#7t1Z_~ngi$~aJ0+vUB9XQSBsFjawa-@C>_KTg4_ng+b+Dbe%XaoxR=tt*vZ=@bC3l zU_W3<-0D}j#Et(*=Os)-5qW|O!YWEs75TCi1%l~L*x1$>7OV|4dSQf$t|}!r6bC9L zJoD*4$St_%axkVt6G}EhT*~k)y{IVa`{F#x`<)QGnpGp3RWjr>$a)sdH9U&|D~*K6 zu%FdhtvzleuK}(-9whT_Z@zlH6Y2$@HMwUwyA^0iJlqgT6GXIva{%BUfkotOxyS~U z-KN2aHyzX6MRS(mwjf)yoU44Adb&u9{_0cu2C$Kk#skShN?CyRlh1{B%r~8aTMc`5 zqD(4EC}#4Bp1s~4!*(7$XgI_tc_pIvLF)=aURBE(#SG_x)@_scr zel@n-YI-oEh}apk z#|h($PYDNBuPJRKl3pKX6>R{Q(QROtB?jA-bu(Lyd49A!)+gj6&MfwOG;6D76}zU# zLYO8S6x7v96S?N%p!#!bAj@V2j@n#`8lViJo%b-6Hx?E)h*kx;`}{M6IYHxNKoClO zDM%DLNW!bT#$1?x`SKeT;D30$y6oWq_DDNTJ?-%i}Ehw(xQ`*qe;`G^QU}b+T(B2BF0(cqLQu&UIN2~regqNsR(Dv zxZu+PwjMdqhiSu_uUo#yY`m!X##0Mj$M9a-c84tZW9+*TD)8E_bDm&9ps?eyM7kDZ zuE^_(VFSW(#xf403Ru`=E=oCC|s|klqiou@4CaupAQyp$<+8o^-y`Zr|xw?!DPC2S`Yf z0?o~bKj>tE7_*8sWu(Wa%eKLCL1sk+Fq)&wckj*t607X~d-5^bf>-SXZ%^NMd1CYn z_B9&_4)2$bqV(00w^UYTjwZ@0G3w1`D&Hp`K~IujVUD_BLC;X2>d2oFyyR|TL9Z=$ zs<2R(&yxByxrIqac>}JkR8g)EtT6GhwiCws33acVW4mfl!C@ah?^2SUqbMMv3c{jh z1jXK|D#b=UJfLM4wogcDgAtuDw6qkjbV#w->-mAx&Tdyj#&Uo(!?uu9wvS$6Xmqjn zmOB9IqmAMNd({LSWW$h~&@jK^9x|MJlk0ccXJ_BtcMtuOog>gT_h*nCUC|!@^B46z z7$vZj2-uYoR9V{JL-de`MG~G<*Pi3FH}b?9PM<2)h)aDShY9Ki`^4Jh+o&4^XWs<9 zFJvkJnqh4JxfohvJCv3Ju)_+V^q~kKc~x^m$sP(^jad8W-!P}?h5nre#5MzG|KV|Y zDIT4p{cfUBy{~hG;CRK|hbyJ8ll!DkHIB%-9mtU($H3Li1RCfL<`4PC0@GhxN#!)M?9ce}<#xmo{ zn70bElF*@vVr2fy~IFCMQKYGD?Rq?l}Z}Oda`8e|;Lz}ZVj5ABj(vpUU zlAD^0%wGrfHBlrpe?b(mk_r&Xsvv<*P&ay^mmo%}yr~enSrC_HVPL|Rfj;q+vAOpI zC`y>eacg9^W+A6vHT}#wF(M|daGB`GJz0D1A3a~#FHla_kmOj9*awTU!|H=xKtF{V zIrs;}mOl1#V}4XHD>1L$;76h3eIoWY&WxnXjB(GmGu|(yD$P7#)kN^C_78tJAwOGp zMDe&Y5bkueR);&PxbdL(jsz}DJ7cjz+Xyc8-l$e2>L4rmOg zUwyL34yoGiP>kqderr9MLNx-StxoN}=RBfXplSdk17jCre0~chFmmF@5ffn(JDjz0 z3C%cIA$6tZc zD8kwK^_KxVSf-eBaQb|oaoNIIJE+B5mzF(Z?O^w|Sev&V;Lyz{_xTao=DO8<@Phmu`Utf4GO4GpmT4m&Jh7hWPd(fhE#U1FIDmXCTF+>)QdcF!8^TT%W zyZsp;9|p`_(21PdW?b4Q1UME}4rsuX5#&Hw&dYx3^W$Wik5K0jOmCD1)hcc$-J-6F zu7q9>u>p*Z>e9cb?$MW?kH$ls8r5oB*G4jPYi zFKA@YR1*h5l#lnj(d%(hsHM=>^WFNQ+nu z(w1lh4}2_q3BY-iH`anWCNIXnssnc*3HD0oX=`ycG8y*84)2x%Hec`zX2%B56NZy) zLwee%ld^RSAjOCQIzJ>n5!V_E34%_ut`)&NXy%^bkKtwq2Ba%#oUiREE~ra=a>H=cDcaV)0H%8y=L{`y$#N_x&3p;QHW#nPAYDMGaP17 zZOuUr6nqdTKbh4{55>uW5vuKOyLnkUb4jSTr8@-LXE?Qn)StH7>orJ9`~qi=+=GTa zm}?N+<$nrw2d)Eh(Q>UiYq#(SF@A@h1M4620GG^aq?(yIk*GOjE=<}T)VMyg2jO5xA=pefWO zUvPxJuqNw?HmW}vfN2M@b5JIK$r)H{#0Bm!BaZkl?Q;e z^=)#rnAOm0R<Pl^OO)Uu$9I0hrxidCd2KF+;1cX9np+W-D!oa*wQ$j(WR-8Ab9GQgT zFeWXn>Faq%20DRVtK$-PI2pSba zm~BD*8upN0mWLnlq5KjWnrjFh_k(`hd?>5pKo;!S1Xh;d8-W&=Rj=b9`?$2PL5cVkA#89PclAh=iw6pQGsY z?9p+8;UJzZGc-p6GGl^wNs-)XWO@v;D4%j3NE!hup}tcQj>W!U5!1K$w{S=$XdU;; z3rsy8iv0~n8-1Sp*&lBle3TtUIF?_aC**uHy`Q^)lm(bB37@$U4SaV5gDNE1Yl-vn zfeAm!cAZx||AVY^t^@ML>s0@?lS|2joG@`$Mn^29JnzM1&BF~lZCnq&WJ+cLmJ-Rr z*$90GVhMfRkglbF3O?SC9>8oa3+D}9eyQ7fA9WVfwc;#}JpRVz0q9ZkuY@|6WUi+D zu652Ci-y`gYty3QYAGnDh z?VlppS=a8S$lT}Uj*u2)Jc7Ozt=L6K_1c){$V2X{_G{;&BX)eC(LXedh;`$`o%cH%*H%`ylBb)4q?AiY=$xVCf*kiA|=(@?xO3&&81mZ*d+}P4J z^Py7%C}@ArA*b!=d8(z>Jt1!BOebP8mw5S;ntFz|dWi#AipSQ$nX+x9%NmQNlqqhh z??mcQrctFxwtvMxNPX>vB~zsgRnYPjC371qc`gM-!MpZ2+5USEz@DXw$C$s*>C5%z zX^z(|$1ca|4wtuscURTkW9#q6|HIciuxHjbi?-<`9iwC0c849?w*ADmZQHhO+qP}9 zqm%bK`<(T?>)LDmg*mHgR^7AiFPDYO|Bm<)jl~`sw-t|eC$811e;j~*`pjt+gM?@#yKQ{)mmNKoQBvPzbfuS?2T0#W!Oy8&LZvzT)IE5x8yTK z%%j=&pGJ#}v+HEK%aJmu2_-Z5Z-2;QQqW^nc7>|kXpPa ze%o4e$n1QInQXX@Vbt4C%}-S*I8sh!+($57Q?rFn+P>MoVVim`O=+o=Wv_ZYG&(gO zHsH|J05|WaW){6Bo>$X#?y+z*5sl%^ho~%`gfyNxt9SO4wqII_fJ%^4wfoL%+xzt( z;FT*@{z7rfT31DzT`4-P=4oa*}~j@nQb}$Ih97Vx4zM6&9yFS zoC<;2qMeu8>_p;^(wt` z#u>hH{3vT`P@EJAL+_723F!Z*s8;VnsyBXxT@Dmg#gf+I7IN0!m+mGM6j4<2dW=S~ z1=WG)ZeO$4c#2e7fAk-0uWHt9yrlE`461K(>URd1TEF643rm{TwxdW55vABE=Hb@0 zl&7ipZU<0Ci8nznb9|a>Bem{fEor4CUxqqcS!D5a+Zf#2Phzo7ZEkQgzQK70UwhmK zwccE&FJ3YzwuqvnO{TA}MPju~?Wzwh4jk?xw)mOd`nv7=x?TC2amiA}s(a-`efz}l z(oNmkZStQFUZ<_Y_FDi4dlb2~6J!c^2ywC~Xuy&}Iag+T4nB~zvFmbH-FOH5Mk=rk zk#R0OGgs%icLYU~?&;>{B_GBy-8wn)>1Q1n$nnmd(`46RgGEhp18<|8dO>r7vK`hp zZ>(lba|fLe?6zEh~->97tX?RBW7 z*kpcL+VmHTV|PCL-Mu(`HH#9A-h$W`>3n+MfS2~_wX@(e3Nxwr$8vQ=ufx9*beisk zpLY`Da$ZsnZd#ItU6wy*e#POWO2%QM_I``d*pfp_h9)ht*U8eulQlAf7VoO5hZf5X zWcjxr-+S&br4w{Ep+uu)Ip@^2!yY-T&K^fx9s|!GtLbz)(NR2x5hEWc-r5bXm%u4UM z%MWM%&c#eq&0$#FV<3T~B940``{EH#GDZWY(7+sBs&eD6g{IaTyhKAhy_-O*>V8-= zhsLRHeEi~_yJG;YE7;7Hle?lKHsL%=LMR~^$Lf&*d2u9p$qhcMYReDAbgK>-|IO?- zG42>BPAkvjaB$ZRca^Q89Wb;av@zacg*AiSSt|EoO`e6?Zz^_o7EOnV0b`18giRHg_>`Ya1PO)h88`SZ*mfQCY1KYu8AfL8XkB_ zbM^*9C5Ulj3WNj*Q$j4iQoN zmYJk}K$}EaKTC~41lew)B}K*sTPb8d`2L}f%xtLO1$dNqX*X3I8%M(*)G{wI1mdywg=~;_T7dhbRQbuu?2x-}V)2P^fu1ut8_W(#e%gDP|3RC@&<4N>pq%`>s zFUPc--lIw7VU2Xw^vWm{+01lE>1k@3aD?wDQ91!`c>1u5IV~=$kzc%bcA_mcT3;6$4(?=MYD+6s`TaebkOqc`7Q(Nx3U9H&j%M z=x|MquA0dc<>M0Y1)k>E;Ru(i7Wb=LUl{9evZYjp8t0U*){Zm*f2xlAxa9v(6HNvi zh(hcA1TbXqn+5EPO6-Ep*|~t8ssKhsTLM;s=m}csV}fiFw7eGLjEv6(_SZfef^EjegGF*r*zIpX0J{Gb2hY z&2_w{9hgYK4f5NiKe(w1&bp5u|7Nfp4+txtYI7XEyupvJsQVD++OSEt67Yi-%vrZ1 zV7{lQRicoDCC4%L7Y-6C+PvlKZ8OlahG@o0Ij~<1T_)^ZbUK*y-QR^9=x5w+Q1A2| z5+k&0QS}yHOx}ADv}ZI(h~+vVg@kQ0gj~LTj{Fr1)NT{Xdptg8x`S6#ziM8)0AT{l zjXKSq*WQyH5j#*UsCs*dPkJIlqhCSqNgRMKc~WcXL=M(eSs9p9??Z=44Uwo($#=-hw+}E$XFD!hrgnJ0;PT-Mx7FBQ-A0dnobVxA)%4Sl+lkT5Fu)%xRiQYBcLvXI}Bxr-kDc7UG z!D*VT>}04(Djlu~8oZS)Q?^YD?^QBgJ@8##U=v0HyIl@V5{$bj&w(Zwe#@IICl5XCNTjLd z=u>Ehogglui57BgoQ!Y{R}PwCOJI~_9Dk;z6U{gM>|x)0`3S6slD8&+$VDm~ig+HC zSWSJDBXl6HHhKm_hVPm)L zYuh3qUD5z#xMw8ffsYa`!GVT$DlA-Q2Ra zYRk#>@$1XQ6#<&*NGDD&fQ++nX z2yu$ck_5N+S=Avwp?UCCUsHYb)cpK68>Teu!6H)+Q942*gsc*-lpfO~-H&96^#+q) zC(1WZ}Qk{_|Q4=en20chJd)ZHUU3CJr$4}OO8k-N1XOX=j*3V*b<6M?J9dH_P8>k#KD zLN6x&Z&08)!`1xLG!tEm7*>v+=!W*tY=?l)2HMX+yRD z>`IpVpQowxj#@qLQ+PU4Lr~q)v~Y1ibRObBoMDKQ@wp>#v|DFcX!UK7s)++pgyQ+N zn5p9y+}z@&0k}=dSSzj$_3^d=JG|1CSZ2NfQU|AKd76EPM9HgtgE_ic`&!f(i{rvO zl-bc>IG^tmQZ*HyoLBw=gc7I8Ii4ve`@+=E!kmo-Q%4r^z*a3svSDkl^{H(I9pa@q92J=DicK~4fQ{oxwIG@LP#|JC~#|NC0vbNG*7W` zX4)rDI8Rlo?`?F1R$tn)I)mNaJ`k{EO|2xlAUUT-r{mw15$!<>20Fn|A*KMrHT;Yi zdI69%4h5mk1Fw>iF`7agkmd;{M2M%&991fdYJvk;ij9gg_?(o?OYU1iJYgk2#ZFS7 z*mEpZ3l+h{rOS*GyI?10$n+nm&DRywV&mwF$aqdd#%=}kXv-UrJS7lNR8~h_+h~q8 zQA|KAMV=q1sImwc-;t!4^R@60~pHOO+Sr&$#y?;;AI5O_?9R;Xh8tfGK1#49>S^Z z9>_9Gv)A5|m`CFoy0=;$C?wjLW*t!UO+N|6Fi1V_i4 zz=^!lk9Z6vim^?nxTiIjPNI#*1HmMhH(qc;ufK?pTynCi3(Y3=d4En$c6@m6^z(n! zYbi1Ydn^I`p}c<`LqfRswuf+f3Lu$S!a4&j(nq(ma|XB9FZ62l(3t5!wiuk~N<01H z_n2IgGv`qBJ+l-EBI)RpG+=y#L#u!ce>qMcY9qnM3)J)frWjnd=nYn@_ z^V=I;b)Muwg4D-9ie1pP3MUbKd?Qv`UWw+8T!QSHa=AjmRVo;1u>$2h3xu^1KUDK6$cMOt9ywb|uED65i#N^4H< zB4LE%gzxoCMaNsO^>c`7dFz)#DXaJu8P~hplLwxA!<_F26iIbq)m0%##@a$Q$*~&a zAu+clGX>6@UUD$ zVo$=#EAmuM13w? zavE&&jWDhWF*}iA>MRCZOJSi`$F-l$imUH2Xlm@_wpoVEF=%>hrPVnx%?j-~p=d0r zNOAmnHxRQl6T#>b5C38Du-bFc4V88gTH6gc$n&F$*BWpv%|WL;zq@$!L|L7l_OP|L zLk@&CymoS%m3Th6PqW6(v`>=NqaKgN}gM5~nsO(=3p@ zoJpe|NP38uz!b@xboJWc0D`;Wo_!csFWQ`%++E+QNnPXH&G0HG z?!n1|mK8vaBbvRG6voMV)bB@v$3D;@!Qx+^nqFO8%DHaNMx8DL)@w7f%KKZPrao&5 z!^+hF1e1_oJ&soP>=T_88}F3wtRLJs^~Lh3!8*xDxjGra)(7745@AiT+%&63soqF! z9&ZO4b;AY{@C(H!KD)2?Xk9P7oz(Tyzi~@c_A2Iyq`jZkzml%R`1js;qOQFw)1vP@ zOobd2JY1YK0q*q8F9lnNT$zw-B8#zy$*bSOyZOMsvCiz zfEWo75i@~!&AVlTvS6!3)n&{a3P3aV=eWxp$Yr2xGfrr!xK-r>JbZ{!TYR!CTug_Q zat9&9-6;YQxXYZX3|QnmQni=yVCl|{tlyCK=e4Xw$0E41sC^qF?5UB!^F4r4j~n%*$20aN!M zkO`@hm&he@Uc8ss$uf4YLLJEo$-NR8+Zk{Y^frl^wKfrdZDra&&NNOIH6ZqHmuM)o zwiI%unS$b;#q??6#9+p^*`oU-HP5-l*6inIe#kU9TUlkh0=8Z0=beCC*rGmoJ%bnJ zGX(2Als1T2<^ba$4A_l;@1vwdYI~n-dBQkyhaxD!Wgb5^}>Ksf3C9fB1XMqwxCBkf`mO1RroF zJU~cDkFS(e5rZFf3qb~RA@_+Cx*?v*{a!sIC#AtDg}2s$uoFKaQ>5TtD1GZE>9BC> z@Y+e5i2XZ~C0UrYIXoMh_Cm^%*V;6|7#~-yP#4ROMYq|>enGb(aMuiK)jj#?7vUWF zAag|3GKM+K1kvdLw*usO217S4RTCYniSjoTq>6%<$kJKTZbx~RTqO2U@gh1QmH!8? z`Zo$4c>c0A80d6F751Znf`!{#YG@dUKgpLH<(lpeXJLPWs5RfaA)=n&-o?WW?XT+LZf3_mHp;$m$$dMipTJGBpfOE zJg1bsKrik0lygKp9_ewJXUAJSpRq7jNb5kl_J{!Dc|6Xm%6b z&1~lYB|O|jo#<40d8RZKJ3Z%gY=690BYtCqH*=lX=y^g-`;*2+n-IHfWt3QJwhXA& zI}*j^_fqA{v7)G75<;D?DXiqNpoQ+{5vn_GjqN9)464u*6E&p~OZ^6a9*6{Gpcs^@ z&}Nor2pbGbOxn_D1;CTAdAcDhOzQl0p&<*Cp|ZFDV1&-K(Q-r|$j(?dXHf$XT8)C6 zPYaHHryZ2UqogkZ`1=tGar+-y$|yMYw5BPSZ8n&rxz6dg3(;+zL1GaCCKmR ze@brlMn^>$MAs_~MTa&%3kG`FtHjRO+yie3Zl%3Iz6PYLs~ReNI_IcvVVoylmwu|v z&>(3|$;9mvFb$BRGi+RD2fKPquMJ6WQH_)oO&^8YBV}Yk3={vnCC!Q)HEH(VDvqY)60e^*s=E6^a<5V)haO~Q53Us~|T!1@v&b7-M*~oirVT!SlXHu4P z_;9%8z4}I5UK@1mH4z4zym!0 zS(zD}_9XhDJk&t6^ac_{!cQzr4k=qr?8GeZTvkXvZK9HgNKrF^`qC1EbBde*Bia2T zlHidXr`4A~N^a6$@BxSNZXo_wysqz+n}ny}K*yF7E7mPIm3!ld6H%OoC_wJrEQh4aF02$)I^=v$z?Ae10=6j9bL&TF2!R^o?@SU*fpvs3A(|e zwWfHtdh%IWJCQw3abwxM`~vIaeZqHDh&ks zXsTa&3IlXINBvnLIu=<$;ZvCI@Nj8Z{EOK6g&o#K-*}Ujtx)9Lu`nkt<2r5ckQ61C{%&Y$0Y;0@v;j zQ}(BHA&^@^Ts6o$xKK%<-Ht#Fwa0_R<1Gy_GQj5)t(k1ObPauk+8mKO8kq)j7(-8dbO&|G#d3n= z{cwqjZ*jgf(+Gw__@t5&@VXA-)TSq(*T56=Q{lREY;ymmT&zdW-M-`FO!G)i^0GGq zb-kb|y8XfF?A5hWxU-(4(37|mDXlFn_CNNhQ({YoyAv4|Rhf=VtH$%JgI$+)!+-so zZ&=6JcM}XCYcc4qxcy6h_=rENTWS;gPQI!1M_bRo|6atsEMcCsxT?cA%eD3C-CncZ zElVX8pi#A&zt8yChA)5s=nIXIR>1|{cio4Kgt}v;@$>lTZE80Ra4p1pz4sQC=UimF zaK6-+3VjxEhZ`-7+TY8R*c?`@?6KTM>Ul@k_Y5o^JeOf{NLKn`Ys>A^=$_ zwM>rOJoJ!MM)$_V6lo10wM;stctlULE!UMVDKlkaZus>{_wVHg54?0Quy0Ca-8Y;4 zf4MRDe>m;`-hBvElCUNc`gL^$h#p1?*6OQ+MDWuVEO@Cw2u9&YP$$Sj1hHmtI!w5XHFv$^#I>CydF z*2Qyyct^JS!WJQ;n*z@(%19U|eHtQ8nrY6cKNpX4sy!cjj}ogTR=ulvOJ%YU`yK$} z7EY#PnrV(elFKj_GDl7^l-xIP$|c7XZ{qc_a~^LUlwD4qJmyE#WZMkA&(!h79un38 z^cJV|FcdpQt5yf~&SvuWBW$fP{!$TH)**1szcWl}D!`Z3Lsj96MBPh_4@Pw}^p26r zOl3G#kq6f0a)hfa)78q1HIymw5JIf(oi(qS_pmzO7K7~0f!aU;TWer-o<0$en^S52 z^pvAOAy6+R|J7(yh)VZIKmG4Zn`9yGH`@Va)U;7Z)Z1sil51Q2~6Rzv79y+&9VYw z%h)9!a#T1=Q_b-4W>W&z5HHsciD}MoFB+rwdKbFFJrji=5Kj2ddgnkS_XN_f zmQU7WY^3q}A{0JIFND%Tos~ho;R6VHEelwFVV+!w!Yv#n?SYa<65lb~k-dW)h_N?y zpuP%vpphC0=-48lndGr4=*N+X!4ap1$&R&z+*3;qXdc@ahO4F;Y@^-ywh!-V_$03q zF9TGOWeJn`2$hBc6pZwEC%}Rh{mL1Y)Ch*4E~f=x1C4BZHo;87WYPK%v2Z|PZEcGh z>U0&;0&M3f`8cphQr^46*d+TUTGU|fC1ERkkF+qcl0f9D8X51o;!9KxPLhSzOw4^~ z#6FS!PP=cLp#AB(oDRc#)^X5Sri9OzmWYzpNWuEX4g8hR2$CKo`3T&m4-*mwzF;Qa zsgd!6OF)O*$O~tq=23N}cgqo&a{mkN-nWi~H>A9jj71eHbP5Bm*lp#$Xv220{F!Fl zhz4qlipHnQUKx9N4qPYRw6LU9u+4i5QR!%ArO4Q-aJm>a*NzXz@Q$M)?Y>~?y)ukj zJGj-|_B=aQ8PX(HU`c3+_-u)lz3Y=OiNAqSU_L~)(PYX2y6u(|;rKIma~I#x@VY6x z5#E$!T=ZuzQ^&|>=*-}!<+Cz<$HXABu^yB}L(EZ~q|Fw*AKo}UK&Fiks1YbF1*Y@s z?DAYuFUQ5SX5HO$>bt!k3?n zr*)DOoVzX?0704^ z+BCZnour#&W9P`cPf8EMNxw-_+eQ3rQ0`7p_!fl6p&$fg8OalYvKUEhINXodWh}a{ z;5PAqAL?`9Iia4_q01@wgZyABnV*8^0t&ERoe+j+ZRv`D28-6kfgEa=XzC*8Edezh zEmZe7S{#l0@m{Ra^Z~Y6Io}Y0^tr`zCt!^lk_z%lhR&ys+(Qp~pVklo1J*VjZbN&6 z*u0~8U}V+bI*{!0a|+cvn(qF*8c;q_?(s8grDI5Cw}Y7SZCQP}hqgJXSKC?(T*FeS zx2i$8XGxu^^@D>w*Sko-UGj;*Zd$AbfN1n! z@rpt6f)&qnk3F>=8}k8q^#pCeVeDOqoCg<<#c6HRJNvdr9s~q+)iQP}5^Bfoq`8Wt z8xa2{%_={orA=2PjNjMrZh;<7R}f*?HkWnVxrs_3lk8oY@bC;~##pfPvo8@~`^z4} zZc}tp5Hxck;52^W!gD&_`&TQBbcbgP>kUX(`|yV#OV@KhxK%cfTMJd&=H|fluUuPA2W#>{!Ko8sBuv=qCTwZL)5U$Q;$E$S*BBiwIb0){$CBnaSE&7NE#c zH6*#-bW$@QdKR%D&_x?7$wmCwFxHV#&}26yEU;rT4#+8T4$mpswKoXgta+{d z6kMhNZevVBkP;wv@WvqN6pRvVC^WvN6yX$1TjYKXP?BYq7}c=;1(?BD^#Fg_jPMX8 zQ`jA9ztkz7}mhpHu5uw#mEWs z0-dciHx5S?vJk|&%`RsIU>G0RZi&%c@Xv0o-(M=pRKHMd$qj*Bx4diu*PD+vyU^b) zq&bDFGKbfm3-WSi^?I=tsPhcSvrH~B0-6}_&JBV{kmCIOvUo*sz|dEwOi|)7Ff*uv zqq5oZ@XGZ%W7NBm`YWc?T9ND&&cRC)nwe%#H5ouy<9-byk-{lt)xKqS$mQT3SUI#b&?L~;3xdefG-G!k_Hiy3W znQQotph6?9=-zs2?0@8uc~n&C`G;slnJmK;zDir(3+QP5YX~C9-K0uEn!@&hku2va zzmdU{Ut2Lpgx@cEl9auKEBLAeZJJqD6qZg@9y)$y6FOjOCEfyc1`s+%%zb;!no3`iM<&Uw3_}8pI;IpY#G@eGRH{TOtHc&;Ybt|(X^ zGA*uVkTE?A(CgW6D%ugUOxEijSlTvFt%qMRWQzA?J$S>k%$W24Sz$dsS>=<3K5j`D z?JFkie4I}McZA6Nm1kAhl&#y;noCC9M#3Oix(mi<7V)ksL1R8UXp!b|tQfLDWeYIy z4csG1UFB4=)sSnyn8ZGu*PKWI$B9rfzBQ2;)6qsSyP*t7IGH%H)?@L|DxQ`dx*mxZ zRTlV*fCqX5jJ4j|14|kjxF~r2^#CV!O?A+2dX@9afN9}n2Ms%K--{a>9>ocfAb9QQ zFBa|wl4SbCIGH!$W6?6E%@^x$uJv#*?21|_(MI_c=!RnZDkfdBkp=F>=lsbdHrE4f zoLHHsG$%4jtJY+Me7X^>_H$gfLB1jE?>f#%Iif`*A$&Bl#`L@r$?5Vn@X(n z6}e3?hlhjT6B9&6{v&Avo~y{eo;(@xyVP>b=HiGu*qJAGCf^HMhP2Ti*W*UJUt;@u zdi>Dkf(R-5`u%j=qg#$nGaik!97F*q@C57!Se+0ro0mO5@D$9?tG_qD=@_%@OATle z3e2SO_7*oUyv~X}x#ouV$p^sVf#7iHMKzGyb}&2mm@bNzm!pj|XH?~B6@FruT*}J= zEJsf?6Ojc+6{K9VY=8*R6h+Ij*_9e;%`V>-1jXHeEwt4TmY%_^e=#k=&}4zNU^og| zs8L|V3{|@Prn?*gr@Z9wii%e^{6&IK`9}@X75Ui44e@r6uq;5!KQm&?WszSpYLz!!pm>(F}C9f7H)%9KaToi1Oqz93`bUhp$PAxu|NLv;%AAz zG%fC}W2n=%w(F^2(f}M*cS^Oi$i~U9BdqI-=)V~k4{Zl%|DNOA-OY66e|~c%ApX}S z_W#fA@$Wb0sPx@(2_a{tew;RD7D$;w@RL9l8e+vY<>dh@Nnx1@mMtX4H6ahjHm+h6 zM_p=}JAsJRu&E7Q49DKH1Pt9aHr2>1QH?{HBl^Ji|13qoKic|}ZgC~}q?%|UH+ z79BNwX%u3Dxn84Zq=J}H;}a=JD1@5?<{6GyVoIVqq*&#(y0W?39opZsz+O_L$9mQN zMSq1YK^8WQJ~ODV$%sqOQ&7?4I`Wa5E^pocqS@vKyQ9m`9+uVuGWL6omm^GUb615v z&KoN37)q;hL`;>%)+D?doisNY(26sCnHVU3@1b)F^y6AdoFcOJjN+?(Dk!d z9X3cA?^!U`1YvVHMoT_U=4qeZ>S%pARZi8m-+aB3Po-@czfZ5IX>4t&X{;#XmW~z~ zN)9Gi7TE@An5D&J^KsDyj^q2iX=WUJ1vwqBn;wI5pzkER*9;%W32nNWZA_P#r3!3wv%% zJ3hje&hpKlaSBK!ifZ9KK6cG6w)`XYJ`<%R2yU0OL@16xxW?t@v(EH^9CwHTC*AF+UvotvwzuB!`#M z#fLUn&yHGA%DgIw-@A`_QyuDv7xZ*5NF7pms{=lzU#*MZQw5>kQ>`eI-|N+slwPH8 zZ8~bU^}RHqos7G0G2Jgfr%T0AUfPj5C~Rz~!}AKj-6Ml~YG(|(hO;0v|0F39N0cpx zte^qE3>vuJOQ_FML3OxMU#Hio_?yv`41$xn+^TN%^-t`{9-Q^5!IH156jqH%r*Luw zNaHi3%CZtokRR=&&X_sqq(s~sHz?GBG~vC`anaf+s5asob4DaTP(FL8Hg6+hn#87~ zMNvMBqrXV5Q2Th1O7Xq<4kmt2H97CbF&wL5{WrnGGG7(TH+Qhqob0 zTvMGO3`vsj^db6mA;Dv2L=XD0Vx&6>BP7+Kjl0y5B7=v+W#zUKec(X$bsX2FO$Fsc z%t3UBSULm0vwTuL+|jb^CibvxYd|8fyI`;>Qqke;UcAnCH2XE$<{>;q7d8v$nJ`$u z?V8xBN4o+ks))Ezh&bA4gQf9E27!(Ib@qu&5sNFentHr9iIa)hS>D0!*(PYmdAH+r ze&p>P-XjW|;4>0!cX3(HG-dhM+l=gPd<`+HA053q0xbFZV2$ct9%jY$I_tE51&MQY zQ#!JeP>aXh-bE9)AXdR{+J)BO4>D-7eBRDT)l|PL|K`RPvT3u^GrU}QdCX-Rt)iT} zWz|oOyVX{{P5b&FQ>ltFdbKZgAY~6nDjf$r~J! zR;lg}d9J4Cd3Y<#XNdbp%e}6xNu3(vzIUJOd3ouD25|gzVs4rRe%R$%j4{^<)=pI| zO`N%0+u`2?KujNL=PX=({`zlz4I?50Z18U+Rm}H68|D8z6g&K*X8Ctzj#Ln{UigMm z#Y>V(aiTPY2W3uCkTM*v?2Galh#lJSQu}RIvubzfH0wrq1Yb#?2LTv z@Zi6Wm3sRkP3I;M(z3ZtKRu&%(~MUtN9cOKjj-~7LU@V{CxJU)m0SQDlmw$2YX{j^ zAL}_kF?Am=yU&={_^@o{X^*5+Z`?k>;$9KW+%3ztr@o-)a#BtsjiNFVurr7o^^A-Y zBT+MC_yi!QVKHfvH^c;OXtZ}@4o8m{Ot){ck=7hR%7BMydi`nEqGVsrRM1$r-yb&= z49mqJ7elp^59=6diFe+>YTP_eYj-piH52QoJQTa|I(w>7sf1JS87Wa_fU+?XY&OIor?}3XKewK;3@A|m*o`K~~82x>KH~tzEoj6ot8?AH=38w%+7?46I5gT;7Qty@#ck%^89$?Y0!M?GE5RXaHY}}7QXElCC{w56 zd#=0Qj8r%mbakT#5Fo%{77%ItYWZXN5g~D&j1P^t=?%at)Z<_K_1k3vY{n6=->3&^ zskw^e(*jw`SA=Lxc5ObyV&W`hX7NruO4*gyIQM(cogy$N5mq%3t*N#=aQBzQ3l-8j z*Tlfzm;tl`I$mC$Dk~*I11t^6gra(?1OB*rtYuc0?(SO?Hr5Rrr?6buJHe57tB|Ue z+P-EvK!?_mF5qMC27sPeYVI{hy%kv(s=6j|)bdvy5pfTdzs;)2NBL{>#L zQrj>QGZAj^v@fsYceA*rkOKKQ&g|=}x2vhi3@!g(YNry#0YII!75Cpqqeq1*d9U2u zW`~8dTT~lRHGQ9(bLK7anuL9ooog;evKsa>sNwSNgB-7i(yW;fNw01!m=mV@IA+TpAT$M8re{F}Ru%7@jmqf?3r zWh4)3j<4n-;6#6icts-)*`kWfR#Ie7P&VIqMMAdd8+t&jd7$8J zKYFWajAbVcPd~(zkJ>@tgA8_f#sq7Y(QW^$9cuI>NR=9IV$w0DXPK6@*mW;O{;T*X z6oQOJDQSsghXbxoqqn}?4P733ftVN)x%ELuNuKYeoyppT!@|mJNtw5rSVUdQ@dF~L zi&SurC2ufn3?_nT4Q!5QyHNdXgN1UaV8vlQqGf39i!Ah0Vx6_R69Glq>Gk<0$754HFIG(pTY`)r!soa~{=TGjXdA_zqXc-HD zX^fX!Xc6*-qSraO13NY4gPCXJY!=43#`R>Xa(4Z@(q5hvztad={@+*-AWY5Z=>Hu5{>d*p zJ6&JU@6qoEBoGkA|1H1%$ub>%fC<3LK}XMC$KJsXU}f^Hf;#*!iLY+E|KSvzMKPaV zKBq-L948FU3@#XQU@nJvo>DEB1THG_>ot+3i5ND~TVI=iV~pYLpS#ckE~-bwGEH@= zh@Y+04uD;-XX{pk{$86ITnx>`7Yhft4WLRxY&gcj$Wln_1I?qS#@437iDQfXeyJdk zo?BqT6?*Z^!{^jN`2Yf?H$`ny&zpV(_IQ>Uc z3_;0mw)*0ZJ!oN6JB0)wl9L0*9Mr-l$`(s@y${RyFQ{6K z@L_|Z>0yh+--qAhNA(-Pz-Pd5*+mJvh#|CP*y0Vti!n@k!hPWU{G=1RdA4@#IYX)K zFH3Y5%XJs=2a!AVJSe`*@qoAyRdFl7`>$I~WwaPAhX4GYK zXG1EbH06h*br^PkglxUk^lZv$TmX6udyM5mnfQ~nF#QEA{6I7C+aY+{X>vh2m}$kz zTVBI;m!f8^00ivas&y_avwWHiYp}Gu&+4Wl118=rOXc43P9pWDjcxnE($5=#`oTGa1=Zv#>?vTapW%3VK z*QU{7ZC@|64rG^Zp~L^F|-&b+XN4E5Xit0xAi{eff3zqcp5yP@7DGwO!970)qT2 z6NeM9H&CVc15y6D2Cv@QWUB+C-Np&BP)-mLa>33Br#EuD8-@I>)63eNzuW8;rSgYw z50%c7dn#(kqCaa`(OGfF?+47{gM`#zPM+CdktHxi{G^U^!!`a%L2xiftgbKF2j zU0#e9SSWK4X)>^EB}VK?I9;xn)0yTthX*n81oYq6t{W99cVq15d-I%EBYN7jDyl-V zLGr#7%AP4+a*7Nc%yJS?0i`sMO0)`O6PiVVvVWOVL4vMnv^=Q-x%XUjUJtl9@>FN% zl@HLbQm=Y49pY7HYxAE#)f1l!L-{^cUzd(C72nU7u9v!KXmBse1s>unxPFJ_i3FFV za+8V|TZv=~G&`y9W``X|zLS;Sc%`veH{){Yrf)4Vx&x!IC332)ZpXf<*q}+ebf3nw zgDnhC#xHVo#-D>fNaH2B(UE?wuuVgPqA;#BpbpY$g?Q(UeC59V2L<+@pu4Q>Dk1+q zzN-K35y<|>`t|L!GceaN0N5EgTIkt*SFg&rUMqikn4oLX4go7z#J!n)V(G;vAcaO~ zesWl02{eeXNxihED+!+lbLc+~0{pdJug%?TRuzEN845yP{j$qQk|yU{Y5aj%>KslM z>{$m%{CgAZK{;4h`)+h*rLdkbe=sY!;RA}OlsD=bUCttuIdb>t1z=mV8@M}z;tK4B z8m`68+?`c* zgZW!=wLcAiine~|(HcZFw+_vmFofOlj|y%JsMw>CM%zesvA_W~=5w&#<|Lb%1y+Mf z-;20TeHWqOd#8pLhtro1f*v*f&>#ll8DXgsb*h)NsytVzOTJ{7vOc8+or)6gsD4J}G_2s^;QjccatL{_)!o(!HTO8?$FEuuCE;2_) zA){HD+s1D|RdktJ93N680)2rL6LrKza0{x?+6(h8p&+Bpl;9z3P#E+BHgm0Hp{&W4 z@}s7f=A*}?v&ShSFb)JknUL@DZ#|nOtW=nIdWb`k?XE0q?-bKdY(pr>aeu;(TyVYk zEkjG8V>pivR|qg6z>QfR75C9qYk(@vf<8f`-hB{?`jX5uYDk_H`rql^Gsa&cU zyAY{2Ku}t*13728)klyv33E=eKSBBgS&a}srW7pcj#11r1=Di${Qn{Boq}x9mM-Di zWxICSwr$(CZSS&ebC+$~wr$&X{dKzk=;(VR&esp?aXqY=D|3zUrY*KN(-@H~H%4KK z?f!bH!Qj!S}C!?UzQ0U04Zm_lNEWjSPCOx6yXbdP~75zqIt{^w#Pp!#7g}ilduRy?yrO#dRXfGfRXW4#Ct}x=r z7N+LYWgc;)P(dSPn+jM65fH~~)z`f6@KC&yN4#bd4T~xUj4M_#E4oLu1wCa8)$ZrR z@bz-)!$}l`k{N9gyKuq}7-Ypo#bZ*txqm;di6VU5CXN`Fq@b7YF8NxDrx`sk#x$m} z$%HDL&{h$!5X$D9#Sq(dj1uM#RFXXe4~v51j1>*h@TZllF+3tj?gIJdUlVMKrHL}! zD1_SynT7ReqUe`2Kns@dGs}_J2ZTd+F5Aax5=gRNSVu8^eQD9@wtH9l$;wkOr6UM8 zBxmU3vI7_?_$bRbGYA@U%enjcK9>_5(G&9HyHYwHAr2&|lN<}BFNHbHKsZp(&1sdh zWDrq3%WTe&#^=OsV)7G!D_6}!xktw^5THO6&lHOiv%P3_bW(d}BdKyJrx(yWMw#GV z3TD*mdLQ&uBFNvE*NiA|j$}nKb1f1=dBlK#>{xGg?kMK3>j#X;8KqCZb_+Sim0_H2 z&%k&XAf{fAa5ykXKUZLy;I(r7k85l1&}MpVM3EpyX(t5GuqQ&;GK0ks%^P zc88`F30O)}<7f3YlC&BMIRXoio4RPW9lC+%U9CnvwvMT;sM0U(*X`Fm8}B(v(+MVU z*Q>2+*Zn1J`ncC1rB*B87F&=dMRsWgnQzGT+5#KtBQc!S8&s+<(xS906*{aMITRrp z9>Trf{(=toK7*&QzYBm-KZpe> zt;ss^%}j4yq&h~1+lRHYcLa{o*`#nni-&_2p6+i9O~+_R$9nLM{G?%i-~^$>j6vw{ z96C<1q;?)Ym@w}5^z7#e$`czt=DDiO5$i;d$MTTojK;SyoNa%1PBdHI&xH{@X&iic zqj;#%$2u_`6mdew6G-fXNf)0E+2JjN754&Z!5>?a)JRh*Z)kkYQn@;hJM?fgoM%*&GkaG|e#6Qj;irQmLyQ9~c(KOTE*t71x^GUY50=fXd zp0%d$Mii>ytC{M##M=VKv-dX7J1_N}Qm*PZ){zH0&jQx{5vBR){6~CWF1D#@cC!as z8Uv|Tk{K~!NCYz5JHEpPYynwQlt}#)xP#uswH1R#ci%4X=ljY`9?DfO+Zey9w^nRO z;)<1mSdf4^cGI2hj1p(Pl*6Jzk~>dSq|zZtS2yXqq1f z(1d8JLGf4t*pDCbcw0I+F5xo6Vs>&c?KS)qc>V$=D!T6GM!V5wEWc8(CwDDA!rCpC z8SBsZ{3o0AeUWn?`csdOem;2rLtQq}ceZl+Da_8&oUr|P(3^2B0iv;aSUC#CO{^z6 zxdsJ7@MJ84wz^md&SRQcm(TVk?ELG$O^AYtleEyYyt>#0DjP6J&#>$ZJNyXYf8Szb z&)Rew+ELfB=RM`2IQ@afTcqWM4y4D*<9ljt);k<7ZZ-Rg=i`~|DijFr1|db`UJfr@ zJ6)i<%c@zjc>KRcw*TBN-xPm#_kZ{>>z{@l``>?sv$fsNPncBKwB2Xej9nz+ecd#Ne56OsNoHah| zxSz`u(N8Q6C<{IWa+@rV26YFpk4t8HY|5BPrw%=mI2Qcn`sQbM*L-5#cWbclaUW%B`JVPs zAWg!YM$DfCI$l&G7vS1ZE(i4!Iy)Ub*~&7e}~ta^9G z2HsphNv|4q$Hj^2EP|k=B}dddOWM&AH47tSn6MKDDBoE%aTk;Zpy=ku7( zL#j)&Dxf14<0_=qeX%0YA;5{oMKgg zkD#jTBuMw-jJL`WORVXExlv)UM{_rzvUkgsTa5_U;pc&^=ux96R%npG%b&e1 zR$@_@#1mH9f{R+C@1s&FRe5t=A;SC{6arQA5_&mt$^N7mdO^1^kvvJD3I4lT>-HrM z9%zE4hE>FrlADLPBLbmjo^Ix(j$1KH2EU4+_g@Q#-THW7z*x)vYJ^P6UdQ1FrsqZ+ z!w=;S-f;t1R8!)_O=4g4S_N4#9t5(`f&U68>=FLrP*x#3*`-l|tSP;JkTUd5 z#X;v@zvr&qQg`i^tw=X^dETN5Rm9-(&`B;HI+JtIjqY0DQsyZtj%+s_(tmvRqZ4?C zJCT@JQ-RZRwZoDg?a5F8a*xlWWsIm}k8qRr#!>n$lt@~~s2QU*gJ%85-mfV2zKx@! zr-26wnqB&f9~2U?gC{nO%Vz-MA@NQQcFBkyITS~H*}n@>#%FD4`}+AjbbQp-?gb>} z2_9BpG#ain#J*SVO&Cou6|xaLGWJd`E$jrp*<$vU_e?AYi&V>{|{GC`sBLFZ;tos$Qzqn$Nx z!WN|@%>9$K!r)C82gPz5$D_SktL>O;0b0WFpt$$O5g;lEchC?OjUj%)PF(fwF}`Y$ z6k~s$>tbp9Z#gF`MEI@y(|V2|H2cLs@sbzUC608RZMb5E-wx<~OZjEDf={g<(4NMG%so6;h|^ zMd_$%W5KJuKDF~xKoDk%@`wi2d9KwoI3T{xC?;q_0%Y5V8}ZbCgHew}u`}v5cVR5% zGf_l~@3`!Pdwu`7~}kmM7BLUF8b<>7AgCTmibF5Ahv;W567{x9<1YB z6Maa$)HrO!1mN17*;l`8{|&?CS$Lz|Rj=BSl2CWrxYe4lREy_z2qkeS>H8*Z=`B7J z@T=1X$g89+L-oWGjr{Y^+!tc=yRb<=x;DT;<9p#La^oDlZNZgtQF8UnGdUG4xC^B9 zmGwR29M6h{EV;&Vz+J&tlI^y_0-1#coOA_ibPTV!ZS}Yt^&pimz9SrkaYArRQC+IE zL%*yn<&P1^>%6K;D&(*|v32}%1ItNB`G)4w!VyPh4Y}4mPhq7+G;euJsq~l4VdbJR zmGymsi+C0*DoVqZt_z46kjnk5|{JpyayPSt_pzMRue`j}QgI&XAKk#sSnXG=@qt35(sD1w7?lswFcfWu7 zyDD1rYvGK+ZcrCO2{K8jP(Ex2U>_|2G<2idAl1dk5uQrhmTtho>EjM1c^?VU*GkBc z7*&M08x~46E6MUulU;SI&?A6%g0c4wWEtyRoY7w-oT75b592B*4s4kT`Gf>PbwrR{ z8fYwXbOJ9juKkfgdnVDOFSVM<@E62pNWkGJbg-A2T2?j2T4+8o0hti8u-H9|O8W5I zNm~`F8<6YYE;BByQcWhi=5K%fozl2WD}_pxvBGp)J^m(va9e%F?O%G|2)Exgyd%pi zrMrEZ6K{@WhR2f#i8cP$Z#zZvgk=}m+`kttJ3PwkrMZdZqW_tpqE_5E(1VkB50`IbT&QPDfhNg!i1$?G z9DeFhS?EzIUlS{mv@y4?1Ytvo`A*upJta<9*mB1?OWT{tgcK}ALvq>>4ORei1SScD zN(M`Yg}=zHvvsHer9?9G`L6*_a6;@$+z;1|015y=_W#N(6I%yeGbihRXy8J{QJMZ9 z8d&v=SB-rkOev{M3_Q01)hq~p+|QvLxplMw&0o9Y=5xiljmW;umo|Um&SWbC`cuO` zH`YXnJhp7pqPfIT+|cnQHWQy9u8}46NJxT-xzsTE4w^)3LpB?yABJx_*d{FSWT=Sn zo;RFVgz+5Cfu~!16>WvFZdj%Gh{jCnDZDiUxK1Wqbx(fYN$koZVHh=Q6gc# zv8Uko&RhsmJSOZrGF7{g43RVx6)!d+960mW5)m8-tV!E8t`c|p@g|0!+o(D=V;HCVsb34J$!-uXTgm01V*I#VfBrFTFQSXEC2tk zz#p|>su*DqP(r*#gEU~3A1NmIBmGNi(n5@r=oIHLhu_+7Uz^+Z`&GEck+ssV5Z zRAT;e&z3Pr_Zvw`p7^&dx24-EseHdf9SFlT&YZQ|)AIr(I?`o)af3htX%y}no1RYz zZO8|Gqrj!@eH-OYi9G|?N%03E2T0?5NB$sFBfY@iOHR?I+(!Tt zi(=^7au)2GKj)^`<&l{U46AP(sMRue2ZKg z7u{p;-c0Czds#3@yh-Yt8;K2jc;|b-5L|%;LX^S?tHtM_fAD|ppZ>#JsL)brL;cha zcl7^>w=mH+|EFkds#(Wmu)%+I&3%F4DklmN(-N7x(zcbIHENb}J9{Xs)20Yff&~ZC z=vib~JIH^(N5K&Bt+@P^aGksT1GNicDCL zD}NqxXC&jONQG??28ptVJ|R0XO$33(DwJXksWM$m;W)e)$UN4AIS8^XORe|$qZl%{ zA3lLAlT)IRm_!!MSlbEU^F2tl=3_yodTUq2)IGN%zk28Qgp z5_FEx>r_c&P-(%Px_M@>>f{{fzao-5{w+)@Q3lf2zJYw)Nnt)frg(CzGw2zV>7J?x z$uAfzkRJO|6TOy6>MdsCo08q||$>5hMCiP!BV>}Px zry?R@)%S+A%?{-$bJYYc&oh;tEY1Zmq>UL;e%UskEwWl1I#|Q1)rwlGsPzARRBq*= zpO&{cW=lh?JyqCVl-ai8c+3!b%&_h-QRt=;Q?_VI{=gm&266`DyhFI`zX0KGafl8| zKe0~?=I#NwVhptM;nX5gI2nAT&V;iBkCP$D<{X-32+Q!MLk`-dldFuRZeSOYwDu>T zp=uGj>K<2e>T`wy*h&NVtipC2PpyEgwmBoJMXX13VmX|%T<4F#Lcd$(^C z57o4-3te}xvIhi-gB!l?uup(#R=L+YpHb2CYp^TJw=2HlWe<(UF6&ooSwm0N!xZjI zzOaqN6P>grASmayx0~S%-bHKQLs@$TcO52_GXa~-{5D<^8S9bdZ3L0_JdzR`ZDxzB zya34dVQ7k^0JfmB&;w0Hx|NpLkw{Tl5T(D`_EUd=l>BWfM)xIFdrCf*Rktp7wr~Op znl4%$8);EC@0>1W#UnHeggJtI+O<*YB(xq{ABX0fZZWkl5{gCnIck-qvQ+jnL;eJJ z3jRe3^QJ2Lt}FjlFKQ)>TWI6IV*2-LLVaW3ED|z{vZ||q>4J|}zmG&laE|Gw?2yI; z&Sdy9WeSf!HdpjRxnF zuCY~T%Bi7pA9)}eb)OxUi-}kKQ2x%G1T`a^?Sqt}N=CC#UIqL;8|1}&rSUwH@xyA7 zZP7ND1*5RfiHZ(gS$NF_vvNrro^31=)A+(9f&^wF+29kIPy=~D>7D9)T0o(yker4o zs!6}OXjV2{b31!$u+!mL>h?}ePxVlWO_J`^UOX2;uYB4kOJ8>6oA?x_#f-(>wXNNS z_qa+szrBdpNtK4xtEJt+57#(rK6V>S{avVd8FJnHW&lWVMlXvWI6ZvXrew=~HMuQI z$GW6|C2U}fh6N-<#-QT}Z^@_b1gqYxfk(!Y1qS~LZ&rIjFh$qmYLZYT0=LP1?DfDB zZ@KK9a{6!`w37Ha$E8Owx$Yf$$+CDYbi)unn)0!mi<7~CcGYa)+ak#7wn=2Ev^?j( zXRFL1wO>6yD75uwzKZj&DAdHtR{tLce=$+s@&~O9Z^L}SvOdwZ&qr=nK|~&zH`Jua ziJXq3@edpi2qts=?V#TFCT*>qU(&>TCemDxY{^KSI{aN_D%Ev{4_*d$C%7W~8l{vY7Efb0kBlh`r-{q9`>)>>~ zBpFP+_pu(Ok3JoDxws^^$vq5}o<A2|o&C1;pc2&dnYIQ-)VC;={Iw4BO?d?bd232pzolgq3LOFD&YPVW;9isx zQ?JS^kZ6KXnjlH~y}-lz#!~;mMa78YEt(T=a3UNJ7){;YJN-1! zV(#X|-sj_P!6iqj_sc;xIgEnrM#UpN?cj^7IAk(;RTa&YV5%3F#W)i5uLCPMr-Im4 zoq&x0?m#4bcg*E}peh{{0092K$Ns1FuyC}s`3Zlcigd*PQlQ-70(;cJkT|Vt;uX6* z%SpfyHxq+fS1@Tb#8Zw^jmLj)p|?sL#B9Cmx>FCFMfD$6D*!tBOA~XI#fsCxa2I z(<2n)$ZqorLYwFol%Sh-NY94mxbJ-`fucz$aZN}XOZMU@YI9frKDngCIkdX^i4DJviB_V?#ywQA?vj(S?3zuF0?c31RvMkzY@#oMWM# z7bU?QX-ZIh5;9|r%C_p2$|!X;mSKVzMutq)L)%WW(y%N?N}#76)2Nl68;}s{VN!wg5^%R<5c~dsqIdyLG0`ex0nW zS~Kf{RvYtmGbXvt0%_x7ez#xoO%x{7`bN|Js!mqy9Q(!IZxCwI)y7w6m|%M3?j)8! z8*obIqSy`Sy6=<_L7(#9@t>2T{g`sT8kElWSL$b$eEEi7EmGh3N9D$Y zyQoD$R;e|3yw4gAHqfd3BgafkhPZZf+-hwgHJrfX`PIHBZCBSHK&+y=h|W4G5#9gU zIWh7o!SVi3O*%h%sDJOA%x#Q}ZT_i6jVhbA8FcVIF$>?jLb!Ms!hU$xWeXwZ7KL36 z2}{lJ$~370=PS?|Ci02jUZ!F_u`yLi!9qPz(YSuC1~c+kD#{DIf`;ru)O5(%T-y*Ex~StAeW1Wvt3dB?`-2wn8y_q(R7!ykXmNw#KFr zC@Hyg?of;iC#~9mDd@U*-zIZ+c9@jZkZP@S$u5p{1={Me($LIj)&ZwHg-b-W!xL{_ zZo-qCf*!s3ass>+=hXJ;xgxtmRKgjlt1OgGwk?Z2{*J3_3Tc?QZ1ot+)89+v_c3qO zQt$tywhr(LsP8i34lO8}o_k31pA^qXmu;wx-RI$e)a;YTUkrST#YjpzL);HfJh?oZmd>Y8$u1q5XsIR z8Q$`W(RY`=X9vhk1gz1Djvw)qsB4!B3bd~WSq7}HlpGqYujW|!xi+LzR?_*ionT_r z6Lmu9f)ejXk zPJ}a3r!Y@TPdTlh`^MAuZjf`3zh*yY@3&@d42@->^|WbM|G?ykg@?s>ryK z-RhtTC4IQ1x(m0~Rxe{w-SQZ4))kl1)OXQ+QAYkTAZxbIqv$NECY)oRP(JgTjuekk zz83g|K(*&I{xEY)rdHq5f3YdLg?TXSMAXwT299qNLdF^W2af7G@b^V%OvA&)NV?E)69ds1;JSAJbDn>f_NGyc#Eo*0DHma(f^Mg0eEatzjf(69p)Ak=2;PC?kNdEOIFn2Px)^)UXaMHCj zcKb=eL8WckzMmBl(p?|3Gr?w~-H-uYA|AB;fR_^6V5;F0y_wZj7c#^z*X!_5ypjR5 z465bprS>h?ZR^rmc1m1^;{s=@aVTr7_Wn;|HT6m*N?V!;mC?9GIA|(D&B_Agawzj2 z^ZLli%n2~WdGv4@WVQ2q?fmcGa2q4$H50f^BkZgLnEyGcGVGq4fVoba13u=><6aWPF#q$06# z2Q=^xg-8xiyts3AP=9VEobcB&*s}8Ah5~!l7~&GW$MED-`<*V4EIVDoXE*z4dRkE_ zW~7322*t_3S`&XKYJP5_1N0kd&<#esXU>2tEur(mSgA(uG*lMf5lSS@L_D1F(^jA7 z+HHL?|H{$091-5c-1|mo)NlO$!KW!_mbUM|8klER<{xb)9-}pHTK*zph!?!ZoMu;f z_2S>Mr{p6ZUV8iDnAz_l%|#DL3NX#k>l%7ozm&bRI)PZ6s%kFXy<%JSSIdbxs;j-F zahuZ`3mYDf#4VRko@Q8{FiLQma%wYEbsut9iNC7JOH4NUo)A~kb#=Y-&JS*Ec_7ZHWjh zmRy`*O>G@xo-80NM<%Ff9$Pk#@NTSUrU2?{R8%zAI!b|d`$t=GZqQEuZ8#LcYz-c@ zlD&p&xoG2u*RmIH!A8BH`rw{f;njji%;;)jqZi4*T2k5Iy(KGhnu=E(joPi=FS)%z zNa&81Twr(@1Hl99`R8)lQNLuB0|-SFf!)z(1ea+JNL&~(E-cn^ksf_8o@gti(b zgEd5WU~f(f49iQ9R^#}4;=iG?4dY>3+#e-CMlt}6nZE1(So(kR*K2u_)X*}|!2ijx zV3n_--(AU?CkhxB(eacW?|`4M9*F2!IYZ-Y(kQal zLxn-zgFyzQJOq_ES|VbKt<|iyHU?r`;F7S6it|KjO-87>$rFvVICq}MeO5n_ED+mn zNny)f(s6@cl_t?;<>l<^N#EuB-onN88*k9jP;|y34Np#nAKiuc-l3M#<1wq2qV!Ih z9F;jTEt9ypjLW2rtLzq${1s)dWwchIr!84ep<>B1q#}_)&Yud*Q4u%+uOU!Y;6~Zz zj38r0Td?z_L6jhXCc}v}i36VjlB#(28W4dO;t@C!To~f{Q5UEV+P}8my0MFMBMGJj z4wIXtS3nUcg;8baHX}qnMDHAdKA0tCJ1!F#7gaJQ;fopEqaa6pv)%URp9z1x33Je+UMYV_ zgqh-P#L#VD@bQ9rt6M6K3UHkJcJM4NxcOW0VVbPLQki+_#@05a`=3d3rpf~t`-4`| ze=NKHy>YhFcXXuxsh8HumaZ7A@SjucA0eYZav<7wUl1UdIf3wuHuJqDa}Nz6t=iC# z&Wox?aF>$z^>PHNt;+giJQzn)5yI0cv!Mi(l0W3cNQlYhOuL9Y7OyZU6)?V{XRG-}X9 zjSCMJ97r%*df4kL-R+hNRb+Y85L5xO)~_<1#^Jx!#e@lxa?{bDiCs zvodG(28wPz_4qo z>9?BO<6nsad8G23?3o)CAtfqk5lFSvfq2q5x|zTUF)6kTf8KVSXpxU}Bx&-d?eDcv9LkGIX+ z-!J#o{;y8#x)My!Ps7?1RK~k=TFH;i-`5e>6x$siPIgM19XwUtYf2u39v?5$rH)5k zUrjqrde0{9ko|~3eqm=$??8EUlzDcHLbd8Mv@iIR4TjOyBGzQZk8Wq^0I$W5>=-uF z&~8-_aC9^q_2f|H&A#xUMY#DXo>s}HGWmCOc(BikHaaE%_ z)_^6M*g>Yl>*W8UeVlF|&PDIx7nUprVckR27D}i5yvLUh_~MKC$P z¬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 DFQl&r literal 0 HcmV?d00001 diff --git a/src/UnitTests/TestData/AstAnalysis/EggZip/simplejson.zip b/src/UnitTests/TestData/AstAnalysis/EggZip/simplejson.zip new file mode 100644 index 0000000000000000000000000000000000000000..98b135dc643de2cb15d97bb95ba7220bc7b15b3b GIT binary patch literal 120933 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 z¬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 DFQl&r literal 0 HcmV?d00001 diff --git a/src/UnitTests/TestData/AstAnalysis/ZipEgg/test.py b/src/UnitTests/TestData/AstAnalysis/ZipEgg/test.py deleted file mode 100644 index 431ee28ca..000000000 --- a/src/UnitTests/TestData/AstAnalysis/ZipEgg/test.py +++ /dev/null @@ -1,4 +0,0 @@ -class Zip: - a: int = 6 - def test(self) -> int: - pass diff --git a/src/UnitTests/TestData/AstAnalysis/ZipEgg/zip_user.py b/src/UnitTests/TestData/AstAnalysis/ZipEgg/zip_user.py deleted file mode 100644 index fd909c37f..000000000 --- a/src/UnitTests/TestData/AstAnalysis/ZipEgg/zip_user.py +++ /dev/null @@ -1,5 +0,0 @@ -import sys -import zipped - -h = zipped.Zip() -i = h.a diff --git a/src/UnitTests/TestData/AstAnalysis/ZipEgg/zipped.zip b/src/UnitTests/TestData/AstAnalysis/ZipEgg/zipped.zip deleted file mode 100644 index d547d496905b35706cdd125d816c91f128e0adac..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 169 zcmWIWW@Zs#U|`^2=qVNT-?%SW$rQ+Q0%A@euF5PZNKMfzsPsPPsiPOxaY|>yqacPR z7wy(FdxTh{S%VGCRZV>ts%+iive?2@-8b0rI-d%6ASV;6!`>K%0B=Sn5eD3*11(@+ Y1QB2Ww=2M#l?^1q2!!T9ItDBa0I4S Date: Tue, 27 Aug 2019 14:58:22 -0700 Subject: [PATCH 12/16] refactoring --- src/Analysis/Ast/Impl/Caching/CacheFolders.cs | 11 ++--- src/Analysis/Ast/Impl/Caching/StubCache.cs | 3 +- .../Resolution/ModuleResolutionBase.cs | 10 +++-- src/Core/Impl/IO/FileSystem.cs | 6 +-- src/Core/Impl/IO/IFileSystem.cs | 1 - src/Core/Impl/IO/PathUtils.cs | 45 +++++++++---------- .../AstAnalysis/EggZip/EggZipImports.py | 5 --- .../EggZip/EggZipRelativeImports.py | 5 --- 8 files changed, 34 insertions(+), 52 deletions(-) diff --git a/src/Analysis/Ast/Impl/Caching/CacheFolders.cs b/src/Analysis/Ast/Impl/Caching/CacheFolders.cs index f55e148da..3ee3508d0 100644 --- a/src/Analysis/Ast/Impl/Caching/CacheFolders.cs +++ b/src/Analysis/Ast/Impl/Caching/CacheFolders.cs @@ -38,7 +38,10 @@ public static string GetCacheFilePath(string root, string moduleName, string con return filePath; } - public static string GetCacheFolder(IOSPlatform platform, ILogger logger = null) { + public static string GetCacheFolder(IServiceContainer services) { + var platform = services.GetService(); + var logger = services.GetService(); + // Default. Not ideal on all platforms, but used as a fall back. var localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); var plsSubfolder = $"Microsoft{Path.DirectorySeparatorChar}Python Language Server"; @@ -100,12 +103,6 @@ public static string FileNameFromContent(string content) { .Replace('/', '_').Replace('+', '-'); } - /// - /// Given a path to a zip file, extracts it to a cache directory and returns the file path to that directory - /// - public static string GetZipCacheRoot(IOSPlatform platform) - => Path.Combine(GetCacheFolder(platform), "Zips/Eggs"); - public static string GetAnalysisCacheFilePath(string analysisRootFolder, string moduleName, string content, IFileSystem fs) => GetCacheFilePath(analysisRootFolder, moduleName, content, fs); diff --git a/src/Analysis/Ast/Impl/Caching/StubCache.cs b/src/Analysis/Ast/Impl/Caching/StubCache.cs index 63de4ab02..170bebd21 100644 --- a/src/Analysis/Ast/Impl/Caching/StubCache.cs +++ b/src/Analysis/Ast/Impl/Caching/StubCache.cs @@ -20,7 +20,6 @@ using Microsoft.Python.Core; using Microsoft.Python.Core.IO; using Microsoft.Python.Core.Logging; -using Microsoft.Python.Core.OS; namespace Microsoft.Python.Analysis.Caching { internal sealed class StubCache : IStubCache { @@ -33,7 +32,7 @@ public StubCache(IServiceContainer services, string cacheRootFolder = null) { _fs = services.GetService(); _log = services.GetService(); - cacheRootFolder = cacheRootFolder ?? CacheFolders.GetCacheFolder(services.GetService(), _log); + cacheRootFolder = cacheRootFolder ?? CacheFolders.GetCacheFolder(services); StubCacheFolder = Path.Combine(cacheRootFolder, $"stubs.v{_stubCacheFormatVersion}"); } diff --git a/src/Analysis/Ast/Impl/Modules/Resolution/ModuleResolutionBase.cs b/src/Analysis/Ast/Impl/Modules/Resolution/ModuleResolutionBase.cs index f2a74507d..87b54462f 100644 --- a/src/Analysis/Ast/Impl/Modules/Resolution/ModuleResolutionBase.cs +++ b/src/Analysis/Ast/Impl/Modules/Resolution/ModuleResolutionBase.cs @@ -110,10 +110,14 @@ protected void ReloadModulePaths(in IEnumerable rootPaths) { } } - if (PathUtils.TryGetZipFile(root, out var zipPath, out var _) && File.Exists(zipPath)) { - foreach (var moduleFile in PathUtils.EnumerateZip(zipPath)) { + if (PathUtils.TryGetZipFilePath(root, out var zipFilePath, out var _) && File.Exists(zipFilePath)) { + foreach (var moduleFile in PathUtils.EnumerateZip(zipFilePath)) { if (!PathUtils.PathStartsWith(moduleFile.FullName, "EGG-INFO")) { - PathResolver.TryAddModulePath(Path.Combine(zipPath, PathUtils.NormalizePath(moduleFile.FullName)), moduleFile.Length, false, out _); + PathResolver.TryAddModulePath( + Path.Combine(zipFilePath, + PathUtils.NormalizePath(moduleFile.FullName)), + moduleFile.Length, false, out _ + ); } } } diff --git a/src/Core/Impl/IO/FileSystem.cs b/src/Core/Impl/IO/FileSystem.cs index 22be38f4b..66c38bbda 100644 --- a/src/Core/Impl/IO/FileSystem.cs +++ b/src/Core/Impl/IO/FileSystem.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; -using System.IO.Compression; using Microsoft.Python.Core.OS; namespace Microsoft.Python.Core.IO { @@ -26,8 +25,8 @@ public long FileSize(string path) { } public string ReadAllText(string filePath) { - if (PathUtils.TryGetZipFile(filePath, out var zipPath, out var relativeZipPath)) { - return PathUtils.GetZipEntryContent(zipPath, relativeZipPath); + if (PathUtils.TryGetZipFilePath(filePath, out var zipPath, out var relativeZipPath)) { + return PathUtils.GetZipContent(zipPath, relativeZipPath); } return File.ReadAllText(filePath); } @@ -54,7 +53,6 @@ public Version GetFileVersion(string path) { public void DeleteDirectory(string path, bool recursive) => Directory.Delete(path, recursive); public string[] GetFileSystemEntries(string path, string searchPattern, SearchOption options) => Directory.GetFileSystemEntries(path, searchPattern, options); public void CreateDirectory(string path) => Directory.CreateDirectory(path); - public void ExtractZip(string source, string dest) => ZipFile.ExtractToDirectory(source, dest); public string[] GetFiles(string path) => Directory.GetFiles(path); public string[] GetFiles(string path, string pattern) => Directory.GetFiles(path, pattern); public string[] GetFiles(string path, string pattern, SearchOption option) => Directory.GetFiles(path, pattern, option); diff --git a/src/Core/Impl/IO/IFileSystem.cs b/src/Core/Impl/IO/IFileSystem.cs index 338c424b6..509c7c282 100644 --- a/src/Core/Impl/IO/IFileSystem.cs +++ b/src/Core/Impl/IO/IFileSystem.cs @@ -48,7 +48,6 @@ public interface IFileSystem { void DeleteDirectory(string path, bool recursive); string[] GetFileSystemEntries(string path, string searchPattern, SearchOption options); void CreateDirectory(string path); - void ExtractZip(string source, string dest); string[] GetFiles(string path); string[] GetFiles(string path, string pattern); diff --git a/src/Core/Impl/IO/PathUtils.cs b/src/Core/Impl/IO/PathUtils.cs index 462dd2222..7e0b73f81 100644 --- a/src/Core/Impl/IO/PathUtils.cs +++ b/src/Core/Impl/IO/PathUtils.cs @@ -14,7 +14,6 @@ // permissions and limitations under the License. using System; -using System.Collections; using System.Collections.Generic; using System.IO; using System.IO.Compression; @@ -49,22 +48,12 @@ public static bool IsValidFileNameCharacter(char character) public static bool HasEndSeparator(string path) => !string.IsNullOrEmpty(path) && IsDirectorySeparator(path[path.Length - 1]); - public static bool HasStartSeparator(string path) - => !string.IsNullOrEmpty(path) && IsDirectorySeparator(path[0]); - public static bool IsDirectorySeparator(char c) => Array.IndexOf(DirectorySeparators, c) != -1; public static bool PathStartsWith(string s, string prefix) => s != null && s.StartsWith(prefix, StringExtensions.PathsStringComparison) && (s.Length == prefix.Length || IsDirectorySeparator(s[prefix.Length])); - public static string TrimStartSeparator(string path) { - if(HasStartSeparator(path)) { - return path.Substring(1); - } - return path; - } - /// /// Removes up to one directory separator character from the end of path. /// @@ -319,22 +308,26 @@ public static IEnumerable EnumerateFiles(IFileSystem fileSystem, stri } } - public static bool TryGetZipFile(string filePath, out string zipPath, out string relativeZipPath) { + public static bool TryGetZipFilePath(string filePath, out string zipPath, out string relativeZipPath) { zipPath = string.Empty; relativeZipPath = string.Empty; var workingPath = filePath; // Filepath doesn't have zip or egg in it, bail - if(!filePath.Contains(".zip") && !filePath.Contains(".egg")) { + if (!filePath.Contains(".zip") && !filePath.Contains(".egg")) { return false; } while (!string.IsNullOrEmpty(workingPath)) { if (IsZipFile(workingPath, out zipPath)) { + // File path is '..\\test\\test.zip\\test\\a.py' + // Working path is '..\\test\\test.zip' + // Relative path in zip file becomes 'test/a.py' // According to https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT, zip files must have forward slashes relativeZipPath = filePath.Substring(workingPath.Length).Replace("\\", "/"); return true; } + // \\test\\test.zip => \\test\\ workingPath = GetParent(workingPath); } @@ -343,6 +336,10 @@ public static bool TryGetZipFile(string filePath, out string zipPath, out string return false; } + /// + /// Returns whether the given file path is a path to a zip (or egg) file + /// The path can be of the form ..\\test.zip or ..\\test.zip\\ + /// public static bool IsZipFile(string rawZipPath, out string zipPath) { var path = NormalizePathAndTrim(rawZipPath); var extension = Path.GetExtension(path); @@ -357,7 +354,16 @@ public static bool IsZipFile(string rawZipPath, out string zipPath) { } } - public static string GetZipEntryContent(string zipPath, string relativeZipPath) { + /// + /// Given the path to the zip file and the relative path to a file inside the zip, + /// returns the contents of the zip entry + /// e.g + /// test.zip + /// a.py + /// b.py + /// Can get the contents of a.py by passing in "test.zip" and "a.py" + /// + public static string GetZipContent(string zipPath, string relativeZipPath) { using (var zip = ZipFile.OpenRead(zipPath)) { var zipFile = zip.GetEntry(relativeZipPath); // Could not open zip, bail @@ -502,16 +508,5 @@ public static string NormalizePath(string path) { } public static string NormalizePathAndTrim(string path) => TrimEndSeparator(NormalizePath(path)); - - /// - /// Returns index of zip file ending if file is contained inside a zip file or -1 if not - /// - /// - /// - public static int IsContainedInZipFile(string path) { - var eggIndex = path.IndexOf(".egg\\"); - var zipIndex = path.IndexOf(".zip\\"); - return (eggIndex == -1 ? zipIndex : eggIndex); - } } } diff --git a/src/UnitTests/TestData/AstAnalysis/EggZip/EggZipImports.py b/src/UnitTests/TestData/AstAnalysis/EggZip/EggZipImports.py index 5a4db3e06..7e4142a36 100644 --- a/src/UnitTests/TestData/AstAnalysis/EggZip/EggZipImports.py +++ b/src/UnitTests/TestData/AstAnalysis/EggZip/EggZipImports.py @@ -1,9 +1,4 @@ import sys - -#sys.path.insert(0, "C:\\Users\\t-catran\\dev\\python-language-server\\src\\UnitTests\\TestData\\AstAnalysis\\ZipEgg\\Imports\\ImportWithinEgg.egg") - -#sys.path.insert(0, "C:\\Users\\t-catran\\dev\\python-language-server\\src\\UnitTests\\TestData\\AstAnalysis\\ZipEgg\\Imports\\ImportWithinEgg.egg\\test") - import a h = a.h diff --git a/src/UnitTests/TestData/AstAnalysis/EggZip/EggZipRelativeImports.py b/src/UnitTests/TestData/AstAnalysis/EggZip/EggZipRelativeImports.py index 651a1ce6c..6e5d3b947 100644 --- a/src/UnitTests/TestData/AstAnalysis/EggZip/EggZipRelativeImports.py +++ b/src/UnitTests/TestData/AstAnalysis/EggZip/EggZipRelativeImports.py @@ -1,9 +1,4 @@ import sys - -#sys.path.insert(0, "C:\\Users\\t-catran\\dev\\python-language-server\\src\\UnitTests\\TestData\\AstAnalysis\\ZipEgg\\Imports\\ImportWithinEgg.egg") - -#sys.path.insert(0, "C:\\Users\\t-catran\\dev\\python-language-server\\src\\UnitTests\\TestData\\AstAnalysis\\EggZip\\EggZipRelativeImports.egg\\test") - import a h = a.h From d31c4f5b7c660f729c98c786cc3c9d9612b00b95 Mon Sep 17 00:00:00 2001 From: Cameron Trando Date: Tue, 27 Aug 2019 16:00:06 -0700 Subject: [PATCH 13/16] Removing unneeded changes --- .../Impl/Modules/Definitions/ModuleCreationOptions.cs | 5 ----- src/Analysis/Ast/Impl/Modules/PythonModule.cs | 3 --- src/Analysis/Ast/Impl/Modules/PythonVariableModule.cs | 1 - .../Impl/Modules/Resolution/MainModuleResolution.cs | 3 --- .../Ast/Impl/Types/Definitions/IPythonFile.cs | 5 ----- .../Ast/Impl/Types/Definitions/IPythonModule.cs | 2 +- .../Core/Impl/Interpreter/PythonLibraryPath.cs | 11 +++++------ 7 files changed, 6 insertions(+), 24 deletions(-) diff --git a/src/Analysis/Ast/Impl/Modules/Definitions/ModuleCreationOptions.cs b/src/Analysis/Ast/Impl/Modules/Definitions/ModuleCreationOptions.cs index ffdfdb28a..b49e555dc 100644 --- a/src/Analysis/Ast/Impl/Modules/Definitions/ModuleCreationOptions.cs +++ b/src/Analysis/Ast/Impl/Modules/Definitions/ModuleCreationOptions.cs @@ -33,11 +33,6 @@ public sealed class ModuleCreationOptions { /// public string FilePath { get; set; } - /// - /// The interpreter/user path used to the find FilePath. Can be null if URI is provided. - /// - public string RootPath { get; set; } - /// /// Document URI. Can be null if file path is provided. /// diff --git a/src/Analysis/Ast/Impl/Modules/PythonModule.cs b/src/Analysis/Ast/Impl/Modules/PythonModule.cs index 58ffd0883..aeeaa41af 100644 --- a/src/Analysis/Ast/Impl/Modules/PythonModule.cs +++ b/src/Analysis/Ast/Impl/Modules/PythonModule.cs @@ -104,7 +104,6 @@ internal PythonModule(ModuleCreationOptions creationOptions, IServiceContainer s } Uri = uri; FilePath = creationOptions.FilePath ?? uri?.LocalPath; - RootPath = creationOptions.RootPath; Stub = creationOptions.Stub; if (Stub is PythonModule stub && ModuleType != ModuleType.Stub) { stub.PrimaryModule = this; @@ -175,7 +174,6 @@ public virtual IEnumerable GetMemberNames() { #endregion #region IPythonFile - public virtual string RootPath { get; } public virtual string FilePath { get; } public virtual Uri Uri { get; } #endregion @@ -564,7 +562,6 @@ private string TryGetDocFromModuleInitFile() { } #endregion - private void RemoveReferencesInModule(IPythonModule module) { if (module.GlobalScope?.Variables != null) { foreach (var v in module.GlobalScope.Variables) { diff --git a/src/Analysis/Ast/Impl/Modules/PythonVariableModule.cs b/src/Analysis/Ast/Impl/Modules/PythonVariableModule.cs index 80da6c3ec..0fd55a169 100644 --- a/src/Analysis/Ast/Impl/Modules/PythonVariableModule.cs +++ b/src/Analysis/Ast/Impl/Modules/PythonVariableModule.cs @@ -38,7 +38,6 @@ internal sealed class PythonVariableModule : LocatedMember, IPythonModule, IEqua public IDocumentAnalysis Analysis => Module?.Analysis; public string Documentation => Module?.Documentation ?? string.Empty; public string FilePath => Module?.FilePath; - public string RootPath => Module?.RootPath; public bool IsBuiltin => true; public bool IsAbstract => false; public bool IsSpecialized => Module?.IsSpecialized ?? false; diff --git a/src/Analysis/Ast/Impl/Modules/Resolution/MainModuleResolution.cs b/src/Analysis/Ast/Impl/Modules/Resolution/MainModuleResolution.cs index 3bc1b684c..86364d9dc 100644 --- a/src/Analysis/Ast/Impl/Modules/Resolution/MainModuleResolution.cs +++ b/src/Analysis/Ast/Impl/Modules/Resolution/MainModuleResolution.cs @@ -108,7 +108,6 @@ protected override IPythonModule CreateModule(string name) { ModuleName = moduleImport.FullName, ModuleType = moduleImport.IsLibrary ? ModuleType.Library : ModuleType.User, FilePath = moduleImport.ModulePath, - RootPath = moduleImport.RootPath, Stub = stub }; @@ -175,8 +174,6 @@ internal async Task LoadBuiltinTypesAsync(CancellationToken cancellationToken = internal async Task ReloadSearchPaths(CancellationToken cancellationToken = default) { var ps = _services.GetService(); - var sc = _services.GetService(); - var cacheFolder = sc.StubCacheFolder; var paths = await GetInterpreterSearchPathsAsync(cancellationToken); var (interpreterPaths, userPaths) = PythonLibraryPath.ClassifyPaths(Root, _fs, paths, Configuration.SearchPaths); diff --git a/src/Analysis/Ast/Impl/Types/Definitions/IPythonFile.cs b/src/Analysis/Ast/Impl/Types/Definitions/IPythonFile.cs index cdd3a3848..897c7bf48 100644 --- a/src/Analysis/Ast/Impl/Types/Definitions/IPythonFile.cs +++ b/src/Analysis/Ast/Impl/Types/Definitions/IPythonFile.cs @@ -22,11 +22,6 @@ public interface IPythonFile { /// string FilePath { get; } - /// - /// Interpreter/user search path used to find the module. - /// - string RootPath { get; } - /// /// Module URI. /// diff --git a/src/Analysis/Ast/Impl/Types/Definitions/IPythonModule.cs b/src/Analysis/Ast/Impl/Types/Definitions/IPythonModule.cs index 6f917a1ef..ae86bc87f 100644 --- a/src/Analysis/Ast/Impl/Types/Definitions/IPythonModule.cs +++ b/src/Analysis/Ast/Impl/Types/Definitions/IPythonModule.cs @@ -47,7 +47,7 @@ public interface IPythonModule : IPythonType, IPythonFile, ILocatedMember { /// Global cope of the module. /// IGlobalScope GlobalScope { get; } - + /// /// If module is a stub points to the primary module. /// Typically used in code navigation scenarios when user diff --git a/src/Analysis/Core/Impl/Interpreter/PythonLibraryPath.cs b/src/Analysis/Core/Impl/Interpreter/PythonLibraryPath.cs index 50dd91fdb..7f04d8f3a 100644 --- a/src/Analysis/Core/Impl/Interpreter/PythonLibraryPath.cs +++ b/src/Analysis/Core/Impl/Interpreter/PythonLibraryPath.cs @@ -210,12 +210,11 @@ public static async Task> GetSearchPathsFromInterpreterA } } - public static (ImmutableArray interpreterPaths, ImmutableArray userPaths) - ClassifyPaths( - string root, - IFileSystem fs, - IEnumerable fromInterpreter, - IEnumerable fromUser + public static (ImmutableArray interpreterPaths, ImmutableArray userPaths) ClassifyPaths( + string root, + IFileSystem fs, + IEnumerable fromInterpreter, + IEnumerable fromUser ) { #if DEBUG Debug.Assert(root == null || root.PathEquals(PathUtils.NormalizePathAndTrim(root))); From 84ab8fe13c3e685d7313c4706ae9661f02676e98 Mon Sep 17 00:00:00 2001 From: Cameron Trando Date: Tue, 27 Aug 2019 16:01:35 -0700 Subject: [PATCH 14/16] adding back --- src/Analysis/Ast/Test/ImportTests.cs | 2 -- src/Analysis/Core/Impl/Interpreter/InterpreterConfiguration.cs | 2 +- src/LanguageServer/Test/ImportsTests.cs | 1 - 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Analysis/Ast/Test/ImportTests.cs b/src/Analysis/Ast/Test/ImportTests.cs index 5ce08f316..5c6a33dff 100644 --- a/src/Analysis/Ast/Test/ImportTests.cs +++ b/src/Analysis/Ast/Test/ImportTests.cs @@ -13,7 +13,6 @@ // See the Apache Version 2.0 License for specific language governing // permissions and limitations under the License. -using System.IO; using System.Linq; using System.Threading.Tasks; using FluentAssertions; @@ -23,7 +22,6 @@ using Microsoft.Python.Analysis.Types; using Microsoft.Python.Core; using Microsoft.Python.Parsing.Tests; -using Microsoft.Python.Tests.Utilities.FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; using TestUtilities; diff --git a/src/Analysis/Core/Impl/Interpreter/InterpreterConfiguration.cs b/src/Analysis/Core/Impl/Interpreter/InterpreterConfiguration.cs index 4b218636f..1ed4f6331 100644 --- a/src/Analysis/Core/Impl/Interpreter/InterpreterConfiguration.cs +++ b/src/Analysis/Core/Impl/Interpreter/InterpreterConfiguration.cs @@ -69,7 +69,7 @@ private InterpreterConfiguration(IReadOnlyDictionary properties) } else if (o is IEnumerable ss) { sp.AddRange(ss); } - + SearchPaths = sp.ToArray(); } } diff --git a/src/LanguageServer/Test/ImportsTests.cs b/src/LanguageServer/Test/ImportsTests.cs index 733ad917a..a2406f1b6 100644 --- a/src/LanguageServer/Test/ImportsTests.cs +++ b/src/LanguageServer/Test/ImportsTests.cs @@ -16,7 +16,6 @@ using System; using System.IO; using System.Threading.Tasks; -using Microsoft.Python.Analysis; using Microsoft.Python.Analysis.Analyzer; using Microsoft.Python.Analysis.Documents; using Microsoft.Python.Analysis.Tests.FluentAssertions; From a6430c2bbf4e26fac31d321a409895aa4d74883b Mon Sep 17 00:00:00 2001 From: Cameron Trando Date: Wed, 28 Aug 2019 11:27:08 -0700 Subject: [PATCH 15/16] PR feedback --- .../Resolution/ModuleResolutionBase.cs | 6 +-- src/Core/Impl/IO/PathUtils.cs | 18 +++++-- src/Core/Test/PathUtilsTests.cs | 53 +++++++++++++++++++ 3 files changed, 69 insertions(+), 8 deletions(-) create mode 100644 src/Core/Test/PathUtilsTests.cs diff --git a/src/Analysis/Ast/Impl/Modules/Resolution/ModuleResolutionBase.cs b/src/Analysis/Ast/Impl/Modules/Resolution/ModuleResolutionBase.cs index 87b54462f..176ae2464 100644 --- a/src/Analysis/Ast/Impl/Modules/Resolution/ModuleResolutionBase.cs +++ b/src/Analysis/Ast/Impl/Modules/Resolution/ModuleResolutionBase.cs @@ -104,10 +104,8 @@ public ModulePath FindModule(string filePath) { protected void ReloadModulePaths(in IEnumerable rootPaths) { foreach (var root in rootPaths) { - if (Directory.Exists(root)) { - foreach (var moduleFile in PathUtils.EnumerateFiles(_fs, root)) { - PathResolver.TryAddModulePath(moduleFile.FullName, moduleFile.Length, false, out _); - } + foreach (var moduleFile in PathUtils.EnumerateFiles(_fs, root)) { + PathResolver.TryAddModulePath(moduleFile.FullName, moduleFile.Length, false, out _); } if (PathUtils.TryGetZipFilePath(root, out var zipFilePath, out var _) && File.Exists(zipFilePath)) { diff --git a/src/Core/Impl/IO/PathUtils.cs b/src/Core/Impl/IO/PathUtils.cs index 7e0b73f81..d712e27a9 100644 --- a/src/Core/Impl/IO/PathUtils.cs +++ b/src/Core/Impl/IO/PathUtils.cs @@ -117,7 +117,7 @@ public static string FindFile(IFileSystem fileSystem, int depthLimit = 2, IEnumerable firstCheck = null ) { - if (!Directory.Exists(root)) { + if (!fileSystem.DirectoryExists(root)) { return null; } @@ -185,12 +185,17 @@ public static IEnumerable EnumerateDirectories(IFileSystem fileSystem, s var path = queue.Dequeue(); path = EnsureEndSeparator(path); + if (!fileSystem.DirectoryExists(path)) { + continue; + } + IEnumerable dirs = null; try { dirs = fileSystem.GetDirectories(path); } catch (UnauthorizedAccessException) { } catch (IOException) { } + if (dirs == null) { continue; } @@ -323,8 +328,12 @@ public static bool TryGetZipFilePath(string filePath, out string zipPath, out st // File path is '..\\test\\test.zip\\test\\a.py' // Working path is '..\\test\\test.zip' // Relative path in zip file becomes 'test/a.py' + relativeZipPath = filePath.Substring(workingPath.Length); + // According to https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT, zip files must have forward slashes - relativeZipPath = filePath.Substring(workingPath.Length).Replace("\\", "/"); + foreach(var separator in DirectorySeparators) { + relativeZipPath = relativeZipPath.Replace(separator, '/'); + } return true; } // \\test\\test.zip => \\test\\ @@ -370,8 +379,9 @@ public static string GetZipContent(string zipPath, string relativeZipPath) { if (zipFile == null) { return null; } - var reader = new StreamReader(zipFile.Open()); - return reader.ReadToEnd(); + using (var reader = new StreamReader(zipFile.Open())) { + return reader.ReadToEnd(); + } } } diff --git a/src/Core/Test/PathUtilsTests.cs b/src/Core/Test/PathUtilsTests.cs new file mode 100644 index 000000000..66319c3a0 --- /dev/null +++ b/src/Core/Test/PathUtilsTests.cs @@ -0,0 +1,53 @@ +// Copyright(c) Microsoft Corporation +// All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the License); you may not use +// this file except in compliance with the License. You may obtain a copy of the +// License at http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS +// OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY +// IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, +// MERCHANTABILITY OR NON-INFRINGEMENT. +// +// See the Apache Version 2.0 License for specific language governing +// permissions and limitations under the License. + +using FluentAssertions; +using Microsoft.Python.Core.IO; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace Microsoft.Python.Core.Tests { + [TestClass] + public class PathUtilsTests { + [TestMethod, Priority(0)] + public void ZipFileUNCPath() { + PathUtils.TryGetZipFilePath(@"\\server\home\share\test.zip", out var zipPath, out var relativeZipPath); + zipPath.Should().Be(@"\\server\home\share\test.zip"); + relativeZipPath.Should().BeEmpty(); + + PathUtils.TryGetZipFilePath(@"\\server\home\share\test.zip\test\a.py", out zipPath, out relativeZipPath); + zipPath.Should().Be(@"\\server\home\share\test.zip"); + relativeZipPath.Should().Be("test/a.py"); + + PathUtils.TryGetZipFilePath("\\path\\foo\\baz\\test.zip\\test\\a.py", out zipPath, out relativeZipPath); + zipPath.Should().Be("\\path\\foo\\baz\\test.zip"); + relativeZipPath.Should().Be("test/a.py"); + } + + [TestMethod, Priority(0)] + public void ZipFilePath() { + PathUtils.TryGetZipFilePath("\\path\\foo\\baz\\test.zip", out var zipPath, out var relativeZipPath); + zipPath.Should().Be("\\path\\foo\\baz\\test.zip"); + relativeZipPath.Should().BeEmpty(); + + PathUtils.TryGetZipFilePath("\\path\\foo\\baz\\test.zip\\test\\a.py", out zipPath, out relativeZipPath); + zipPath.Should().Be("\\path\\foo\\baz\\test.zip"); + relativeZipPath.Should().Be("test/a.py"); + + PathUtils.TryGetZipFilePath("\\path\\foo\\baz\\test.zip\\test\\foo\\baz.py", out zipPath, out relativeZipPath); + zipPath.Should().Be("\\path\\foo\\baz\\test.zip"); + relativeZipPath.Should().Be("test/foo/baz.py"); + } + } +} From 26ac805bd2fec96192c34ad725e1f1be98da1354 Mon Sep 17 00:00:00 2001 From: Cameron Trando Date: Fri, 6 Sep 2019 13:17:56 -0700 Subject: [PATCH 16/16] Test fix --- src/Core/Impl/IO/PathUtils.cs | 7 +++++-- src/LanguageServer/Test/ImportsTests.cs | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Core/Impl/IO/PathUtils.cs b/src/Core/Impl/IO/PathUtils.cs index d712e27a9..ff73cd966 100644 --- a/src/Core/Impl/IO/PathUtils.cs +++ b/src/Core/Impl/IO/PathUtils.cs @@ -316,8 +316,11 @@ public static IEnumerable EnumerateFiles(IFileSystem fileSystem, stri public static bool TryGetZipFilePath(string filePath, out string zipPath, out string relativeZipPath) { zipPath = string.Empty; relativeZipPath = string.Empty; - var workingPath = filePath; + if (string.IsNullOrEmpty(filePath)) { + return false; + } + var workingPath = filePath; // Filepath doesn't have zip or egg in it, bail if (!filePath.Contains(".zip") && !filePath.Contains(".egg")) { return false; @@ -331,7 +334,7 @@ public static bool TryGetZipFilePath(string filePath, out string zipPath, out st relativeZipPath = filePath.Substring(workingPath.Length); // According to https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT, zip files must have forward slashes - foreach(var separator in DirectorySeparators) { + foreach (var separator in DirectorySeparators) { relativeZipPath = relativeZipPath.Replace(separator, '/'); } return true; diff --git a/src/LanguageServer/Test/ImportsTests.cs b/src/LanguageServer/Test/ImportsTests.cs index a2406f1b6..fd3b4824b 100644 --- a/src/LanguageServer/Test/ImportsTests.cs +++ b/src/LanguageServer/Test/ImportsTests.cs @@ -851,8 +851,8 @@ public async Task BasicEggZip(string eggZipFilePath) { analysis.Should().HaveVariable("i").OfType(BuiltinTypeId.Int); } - [DataRow("EggImports.egg")] [DataRow("ZipImports.zip")] + [DataRow("EggImports.egg")] [DataTestMethod, Priority(0)] public async Task EggZipImports(string eggZipFilePath) { var root = Path.Combine(GetAnalysisTestDataFilesPath(), "EggZip");