diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3bcd603 --- /dev/null +++ b/.gitignore @@ -0,0 +1,140 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +x64/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Roslyn cache directories +*.ide/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +#NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Installshield output folder +[Ee]xpress/ + +# NuGet Packages Directory +#packages/* +## TODO: If the tool you use requires repositories.config +## uncomment the next line +!packages/repositories.config + +# Enable "build/" folder in the NuGet Packages folder since +# NuGet packages use it for MSBuild targets. +# This line needs to be after the ignore of the build folder +# (and the packages folder if the line above has been uncommented) +!packages/build/ + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ + + +# Microsoft Fakes +FakesAssemblies/ + +# LightSwitch generated files +GeneratedArtifacts/ +_Pvt_Extensions/ +ModelManifest.xml +/.vs/VSWorkspaceState.json +/.vs/slnx.sqlite + +*/packages/ +*/.vs/ +.vs/ + + + +## Ignore eclipse and maven build artifacts +.metadata +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.settings/ +.loadpath +.recommenders + +# External tool builders +.externalToolBuilders/ + + +# validation artifacts +*.json + +# Java annotation processor (APT) +.factorypath + +# sbteclipse plugin +.target + +# Annotation Processing +.apt_generated/ +.apt_generated_test/ diff --git a/AddIn/EABridge_Example_AddIn.sln b/AddIn/EABridge_Example_AddIn.sln new file mode 100644 index 0000000..4c98cac --- /dev/null +++ b/AddIn/EABridge_Example_AddIn.sln @@ -0,0 +1,50 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.1.32328.378 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EABridge_Example_AddIn", "EABridge_Example_AddIn\EABridge_Example_AddIn.csproj", "{9865ECCC-F07B-447A-BD11-C75B081EEBA4}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EABridge_Example_AddIn_Tests", "EABridge_Example_AddIn_Tests\EABridge_Example_AddIn_Tests.csproj", "{7B90E5BE-58B0-4326-BD48-815220DC0D3B}" +EndProject +Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "EABridge_Example_AddIn_Setup", "EABridge_Example_AddIn_Setup\EABridge_Example_AddIn_Setup.wixproj", "{788CC963-0BEA-4CC6-826C-589AEA2AD2DB}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9865ECCC-F07B-447A-BD11-C75B081EEBA4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9865ECCC-F07B-447A-BD11-C75B081EEBA4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9865ECCC-F07B-447A-BD11-C75B081EEBA4}.Debug|x86.ActiveCfg = Debug|Any CPU + {9865ECCC-F07B-447A-BD11-C75B081EEBA4}.Debug|x86.Build.0 = Debug|Any CPU + {9865ECCC-F07B-447A-BD11-C75B081EEBA4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9865ECCC-F07B-447A-BD11-C75B081EEBA4}.Release|Any CPU.Build.0 = Release|Any CPU + {9865ECCC-F07B-447A-BD11-C75B081EEBA4}.Release|x86.ActiveCfg = Release|Any CPU + {9865ECCC-F07B-447A-BD11-C75B081EEBA4}.Release|x86.Build.0 = Release|Any CPU + {7B90E5BE-58B0-4326-BD48-815220DC0D3B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7B90E5BE-58B0-4326-BD48-815220DC0D3B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7B90E5BE-58B0-4326-BD48-815220DC0D3B}.Debug|x86.ActiveCfg = Debug|Any CPU + {7B90E5BE-58B0-4326-BD48-815220DC0D3B}.Debug|x86.Build.0 = Debug|Any CPU + {7B90E5BE-58B0-4326-BD48-815220DC0D3B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7B90E5BE-58B0-4326-BD48-815220DC0D3B}.Release|Any CPU.Build.0 = Release|Any CPU + {7B90E5BE-58B0-4326-BD48-815220DC0D3B}.Release|x86.ActiveCfg = Release|Any CPU + {7B90E5BE-58B0-4326-BD48-815220DC0D3B}.Release|x86.Build.0 = Release|Any CPU + {788CC963-0BEA-4CC6-826C-589AEA2AD2DB}.Debug|Any CPU.ActiveCfg = Debug|x86 + {788CC963-0BEA-4CC6-826C-589AEA2AD2DB}.Debug|x86.ActiveCfg = Debug|x86 + {788CC963-0BEA-4CC6-826C-589AEA2AD2DB}.Debug|x86.Build.0 = Debug|x86 + {788CC963-0BEA-4CC6-826C-589AEA2AD2DB}.Release|Any CPU.ActiveCfg = Release|x86 + {788CC963-0BEA-4CC6-826C-589AEA2AD2DB}.Release|Any CPU.Build.0 = Release|x86 + {788CC963-0BEA-4CC6-826C-589AEA2AD2DB}.Release|x86.ActiveCfg = Release|x86 + {788CC963-0BEA-4CC6-826C-589AEA2AD2DB}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {C3020ED3-76DD-48D8-8380-FEBD30D0B75C} + EndGlobalSection +EndGlobal diff --git a/AddIn/EABridge_Example_AddIn/ApplicationHandlers/ExampleHeadlessApplicationHandler.cs b/AddIn/EABridge_Example_AddIn/ApplicationHandlers/ExampleHeadlessApplicationHandler.cs new file mode 100644 index 0000000..ce7c81e --- /dev/null +++ b/AddIn/EABridge_Example_AddIn/ApplicationHandlers/ExampleHeadlessApplicationHandler.cs @@ -0,0 +1,195 @@ +using EABridge_Example_AddIn.Utils; +using System; +using System.Diagnostics; +using System.IO; +using System.Threading; + +namespace EABridge_Example_AddIn.ApplicationHandlers +{ + public class ExampleHeadlessApplicationHandler + { + + public event OperationCompleteHandler OperationComplete; + + public delegate void OperationCompleteHandler(ExampleHeadlessApplicationHandler sender, ExternApplicationEventArgs e); + + private Process p; + + private Thread thread = null; + + + public bool IsThreadRunning() + { + return thread != null; + } + + public void StartExternValidationOperationAsync(string guid, string path) + { + string reportFile = ExampleHeadlessApplicationHandler.GetReportFilePath(); + string[] arguments = ComputeArguments(guid, path, reportFile, false); + StartExternApplicationAsync(arguments, reportFile); + } + + private string[] ComputeArguments(string guid, string path, string targePath, bool isVerbose) + { + string[] arguments = new string[5]; + + arguments[0] = "validate"; + + arguments[1] = @"""" + path + @""""; + arguments[2] = @"""" + targePath + @""""; + + + if (guid.Length > 0) + { + arguments[3] = @"""" + guid + @""""; + } + else + { + arguments[3] = ""; + } + arguments[4] = "-v"; + + string executablePath = HeadlessApplicationUtils.FindExecutable(); + + if (!File.Exists(executablePath)) + { + Debug.WriteLine("Error: " + executablePath + " not found."); + throw new FileNotFoundException("Error: " + executablePath + " not found."); + } + return arguments; + } + + private void StartExternApplicationAsync(string[] arguments, + string reportFile, + DataReceivedEventHandler outputActionHandler = null) + { + string args = string.Join(" ", arguments); + args += HeadlessApplicationUtils.GetExecuableInIArguments(); + thread = new Thread(() => StartExternApplication(args, reportFile, outputActionHandler)); + thread.Start(); + } + + private void StartExternApplication(string arguments, + string reportFile, + DataReceivedEventHandler outputActionHandler = null) + { + p = new Process(); + + try + { + Debug.WriteLine("Starting headless application: " + arguments); + p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; + p.EnableRaisingEvents = true; + if (outputActionHandler != null) + { + p.OutputDataReceived -= outputActionHandler; + p.ErrorDataReceived -= outputActionHandler; + p.OutputDataReceived += outputActionHandler; + p.ErrorDataReceived += outputActionHandler; + } + p.StartInfo.UseShellExecute = false; + p.StartInfo.CreateNoWindow = true; + p.StartInfo.RedirectStandardOutput = true; + p.StartInfo.RedirectStandardError = false; + p.StartInfo.FileName = HeadlessApplicationUtils.FindExecutable(); + p.StartInfo.Arguments = arguments; + DateTime startTime = DateTime.Now; + p.Start(); + string standardOutput = ""; + if (outputActionHandler == null) + { + // read cli output and save it in a temporary log + standardOutput = p.StandardOutput.ReadToEnd(); + } else + { + p.BeginOutputReadLine(); + } + + p.WaitForExit(); + + DateTime endTime = DateTime.Now; + + + + + ExternApplicationEventArgs eventArgs = new ExternApplicationEventArgs(); + eventArgs.ReportFile = reportFile; + eventArgs.ReturnCode = p.ExitCode; + eventArgs.Duration = DateTimeUtils.GetTimeDifferenceInMilisec(startTime, endTime); + + if (!string.IsNullOrEmpty(standardOutput)) + { + try + { + string logFilePath = GetReportFilePath(); + var sw = File.AppendText(logFilePath); + sw.Write(standardOutput); + sw.Close(); + eventArgs.LogFile = logFilePath; + } + catch (Exception) + { + // do nothing + } + } + + if (this != null) + { + OperationComplete(this, eventArgs); + thread = null; + } + } + catch (ThreadAbortException) + { + Debug.WriteLine("Validation aborted."); + } + finally + { + p = null; + } + } + + public void KillProcess() + { + try + { + if (thread != null) + { + if (p != null) + { + + p.Kill(); + } + if (thread.IsAlive) + { + thread.Abort(); + } + } + thread = null; + } + catch (Exception) + { + // ignored + } + } + + public static string GetReportFilePath() + { + return Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); + } + } + + + public class ExternApplicationEventArgs : EventArgs + { + public string ReportFile { get; set; } + + public int ReturnCode { get; set; } + + public long Duration { get; set; } + + public string LogFile { get; set; } + } + +} diff --git a/AddIn/EABridge_Example_AddIn/EABridge_Example_AddIn.csproj b/AddIn/EABridge_Example_AddIn/EABridge_Example_AddIn.csproj new file mode 100644 index 0000000..b696d68 --- /dev/null +++ b/AddIn/EABridge_Example_AddIn/EABridge_Example_AddIn.csproj @@ -0,0 +1,112 @@ + + + + + Debug + AnyCPU + {9865ECCC-F07B-447A-BD11-C75B081EEBA4} + Library + EABridge_Example_AddIn + EABridge_Example_AddIn + v4.5 + 512 + true + + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + true + true + false + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + false + + + true + + + + + + + + ..\..\..\..\..\..\Program Files (x86)\Sparx Systems\EA\Interop.EA.dll + True + + + + + + + + + + + + + + + + + + + + + + + + + Form + + + CLIPathForm.cs + + + UserControl + + + ValidationIssuesControl.cs + + + + + + + + + + + CLIPathForm.cs + + + ValidationIssuesControl.cs + + + + + 6.0.4 + + + 6.0.2 + + + + + "%25Windir%25\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe" "$(TargetPath)" "/tlb:$(TargetName).tlb" /codebase /silent + + \ No newline at end of file diff --git a/AddIn/EABridge_Example_AddIn/ExampleValidationAddIn.cs b/AddIn/EABridge_Example_AddIn/ExampleValidationAddIn.cs new file mode 100644 index 0000000..ef68220 --- /dev/null +++ b/AddIn/EABridge_Example_AddIn/ExampleValidationAddIn.cs @@ -0,0 +1,279 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.IO; +using System.Threading; +using System.Windows.Forms; +using File = System.IO.File; +using EA; +using EABridge_Example_AddIn.UI; +using EABridge_Example_AddIn.Utils; +using EABridge_Example_AddIn.Reports; +using Newtonsoft.Json; +using EABridge_Example_AddIn.ApplicationHandlers; + +namespace EABridge_Example_AddIn +{ + [Guid("95251B40-21BA-449B-8E51-0745339E755F")] + [ComVisible(true)] + public class ExampleValidationAddIn + { + const string AddInHeader = "-&YAKINDU EA-Bridge Integration"; + const string ValidationMenuEntry = "&Model Validation"; + const string ConfigurationMenuEntry = "&Configure CLI Path.. "; + public const string RESULTS_TAB = "Results"; + public const string VALIDATION_TAB = "Model Validation Results"; + + private readonly ExampleHeadlessApplicationHandler applicationHandler = new ExampleHeadlessApplicationHandler(); + + public delegate void ShowValidationViewHandler(System.Runtime.Remoting.Contexts.Context sender, ExternRefreshValidationViewArgs e); + public event ShowValidationViewHandler ShowValidationView; + + private Repository repository; + + private SerializableValidationResult ValidationReport; + + private ValidationIssuesControl validationIssuesControl; + + public ExampleValidationAddIn() + { + ShowValidationView += ShowValidationViewMethod; + applicationHandler.OperationComplete += OperationCompleteMethod; + } + + public String EA_Connect(Repository Repository) + { + this.repository = Repository; + return "EA repository connected"; + } + + public object EA_GetMenuItems(Repository Repository, string Location, string MenuName) + { + if (MenuName == "") + { + return AddInHeader; + } + if ("MainMenu" == Location) + { + return new string[] {ValidationMenuEntry, ConfigurationMenuEntry}; + } else + { + return new string[] { ValidationMenuEntry}; + } + + } + + bool IsProjectOpen(Repository Repository) + { + try + { + Collection c = Repository.Models; + return true; + } + catch + { + return false; + } + } + + public void EA_GetMenuState(Repository Repository, string Location, string MenuName, string ItemName, ref bool IsEnabled, ref bool IsChecked) + { + if (IsProjectOpen(Repository)) + { + if ("MainMenu" == Location || EARepositoryUtils.IsCLIOperationForContextObjectAllowed(Repository.GetContextObject())) + { + IsChecked = false; + switch (ItemName) + { + case ValidationMenuEntry: + IsEnabled = true; + break; + default: + IsEnabled = true; + break; + } + } else + { + // not a valid choice for operations + IsEnabled = false; + } + } + else + { + // If no open project, disable all menu options + IsEnabled = false; + } + } + + public void EA_MenuClick(Repository Repository, string Location, string MenuName, string ItemName) + { + string operationGuid = ""; + bool isValidationOperation = true; + this.repository = Repository; + if (applicationHandler.IsThreadRunning()) + { + if (DialogResult.Yes == MessageBox.Show(Win32Window.GetMainWindowHandle(), "The CLI application is still running. Do you want to abort the current operation ?" + Environment.NewLine + Environment.NewLine + "All changes will be lost.", "Abort current operation ?", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2)) + { + this.applicationHandler.KillProcess(); + } else + { + return; + } + } + if (ValidationMenuEntry != ItemName) + { + isValidationOperation = false; + } else + { + isValidationOperation = true; + } + if ("MainMenu" != Location) + { + // get the context element + object cxt = repository.GetContextObject(); + operationGuid = EARepositoryUtils.GetGuidOfPackageOrElementOrDiagram(cxt); + } + try + { + PerformOperation(operationGuid, isValidationOperation); + } catch (FileNotFoundException) + { + MessageBox.Show(Win32Window.GetMainWindowHandle(), + string.Format("The CLI application could not be found at the expected location '{0}'. ", HeadlessApplicationUtils.FindExecutable()), + "CLI application not found", + MessageBoxButtons.OK, + MessageBoxIcon.Error); + } + } + + + private void PerformOperation(string contextGuid, bool isValidation) + { + try + { + if (!isValidation) + { + var cliPathDialog = new CLIPathForm(); + cliPathDialog.ShowDialog(); + } + else + { + repository.CreateOutputTab(RESULTS_TAB); + repository.ClearOutput(RESULTS_TAB); + string path = repository.ConnectionString; + repository.WriteOutput(RESULTS_TAB, "Starting Validation of " + path, 0); + applicationHandler.StartExternValidationOperationAsync(contextGuid, path); + if (validationIssuesControl != null) + { + // TODO: lock on this instance of the add in + // because validationIssuesControl has a weak identity + // c.f. https://rules.sonarsource.com/csharp/RSPEC-3998 + lock (validationIssuesControl) + { + validationIssuesControl.UpdateValidationViewState(contextGuid, applicationHandler); + } + } + } + } + catch (Exception e) + { + if (e is FileNotFoundException) + { + repository.WriteOutput(RESULTS_TAB, e.Message, -1); + MessageBox.Show(Win32Window.GetMainWindowHandle(), + "Please choose a valid path to the CLI validator first! (from the ribbon menu)", + "Unexpected Error", + MessageBoxButtons.OK, + MessageBoxIcon.Error); + } + else + { + repository.WriteOutput(RESULTS_TAB, e.Message, -1); + MessageBox.Show(Win32Window.GetMainWindowHandle(), + string.Format("Unexpected Error:\r\n {0}\r\n {1} ", e.Message, e.StackTrace), + "Unexpected Error", + MessageBoxButtons.OK, + MessageBoxIcon.Error); + } + } + finally + { + repository.EnsureOutputVisible(RESULTS_TAB); + } + } + + private void OpenValidationIssue() + { + try + { + repository.HideAddinWindow(); + if (this.validationIssuesControl == null) + { + this.validationIssuesControl = this.repository.AddWindow(VALIDATION_TAB, typeof(ValidationIssuesControl).FullName) as ValidationIssuesControl; + } + this.validationIssuesControl.UpdateValidationIssues(this.ValidationReport, repository); + this.repository.ShowAddinWindow(validationIssuesControl); + } + catch (Exception e) + { + MessageBox.Show(Win32Window.GetMainWindowHandle(), + string.Format("The validation issues view could not be shown. \r\n{0} \r\n{1} ", e.Message, e.StackTrace), + "Validation view could not be shown", + MessageBoxButtons.OK, + MessageBoxIcon.Error); + } + } + + + private void OperationCompleteMethod(ExampleHeadlessApplicationHandler sender, ExternApplicationEventArgs e) + { + repository.CreateOutputTab(RESULTS_TAB); + string logFilePath = ""; + try + { + + string reportFilePath = e.ReportFile; + logFilePath = e.LogFile; + if (e.ReturnCode == 0 && !File.Exists(reportFilePath)) + { + repository.WriteOutput(RESULTS_TAB, "Validation finished in " + DateTimeUtils.GetHumanReadableDuration(e.Duration) + ", 0 issue(s)", -2); + repository.EnsureOutputVisible(RESULTS_TAB); + return; + } + if (e.ReturnCode != 0 && !File.Exists(reportFilePath)) + { + throw new Exception("Error: Validation incomplete, view log for more information"); + } + this.ValidationReport = JsonConvert.DeserializeObject(File.ReadAllText(reportFilePath)); + repository.WriteOutput(RESULTS_TAB, "========== Validation finished in " + DateTimeUtils.GetHumanReadableDuration(e.Duration) + ", " + this.ValidationReport.Count().ToString() + " issue(s) ========== ", -2); + File.Delete(reportFilePath); + repository.EnsureOutputVisible(RESULTS_TAB); + ExternRefreshValidationViewArgs validationViewEventArgs = new ExternRefreshValidationViewArgs(); + ShowValidationView(Thread.CurrentContext, validationViewEventArgs); + } + catch (Exception ex) + { + if (!string.IsNullOrEmpty(logFilePath)) + { + repository.WriteOutput(RESULTS_TAB, "Validation failed. Check the log file for more information", -1); + repository.WriteOutput(RESULTS_TAB, logFilePath , -1); + } + } + } + + + private void ShowValidationViewMethod(System.Runtime.Remoting.Contexts.Context sender, ExternRefreshValidationViewArgs e){ + OpenValidationIssue(); + } + + public void EA_Disconnect() + { + GC.WaitForPendingFinalizers(); + } + + public class ExternRefreshValidationViewArgs : EventArgs + { + public IList issues { get; set; } + } + } +} diff --git a/AddIn/EABridge_Example_AddIn/Install.bat b/AddIn/EABridge_Example_AddIn/Install.bat new file mode 100644 index 0000000..cbe5baa --- /dev/null +++ b/AddIn/EABridge_Example_AddIn/Install.bat @@ -0,0 +1,14 @@ +echo #################################### +echo ### Administrator Rights Needed! ### +echo #################################### + +set dir=%~dp0 +set assembly1=bin\Debug\EABridge_Example_AddIn.dll + + +"C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe" "%dir%%assembly1%" /codebase + +reg ADD "HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Sparx Systems\EAAddins\Example Validation AddIn Dev" /f /d "EABridge_Example_AddIn.ExampleValidationAddIn" + + +pause \ No newline at end of file diff --git a/AddIn/EABridge_Example_AddIn/Properties/AssemblyInfo.cs b/AddIn/EABridge_Example_AddIn/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..9b5984b --- /dev/null +++ b/AddIn/EABridge_Example_AddIn/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("EABridge_Example_AddIn")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("EABridge_Example_AddIn")] +[assembly: AssemblyCopyright("Copyright © 2022")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("7A0AE073-B3BE-4293-8E5E-2AD62D152514")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/AddIn/EABridge_Example_AddIn/Reports/SerializableValidationResult.cs b/AddIn/EABridge_Example_AddIn/Reports/SerializableValidationResult.cs new file mode 100644 index 0000000..bb1d1d4 --- /dev/null +++ b/AddIn/EABridge_Example_AddIn/Reports/SerializableValidationResult.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EABridge_Example_AddIn.Reports +{ + + public class SerializableValidationResult + { + public List resourceIssues { get; set; } + + public List loadIssues { get; set; } + + public List umlIssues { get; set; } + + public List customIssues { get; set; } + + public int Count() + { + return resourceIssues.Count + loadIssues.Count + umlIssues.Count + customIssues.Count; + } + + public IDictionary GetAllValidationIssues() + { + var result = new Dictionary(); + resourceIssues.ForEach(issue => result.Add(issue, ValidationIssueCategory.Resource)); + loadIssues.ForEach(issue => result.Add(issue, ValidationIssueCategory.Load)); + umlIssues.ForEach(issue => result.Add(issue, ValidationIssueCategory.UML)); + customIssues.ForEach(issue => result.Add(issue, ValidationIssueCategory.Custom)); + return result; + } + } +} diff --git a/AddIn/EABridge_Example_AddIn/Reports/ValidationIssue.cs b/AddIn/EABridge_Example_AddIn/Reports/ValidationIssue.cs new file mode 100644 index 0000000..28f4eae --- /dev/null +++ b/AddIn/EABridge_Example_AddIn/Reports/ValidationIssue.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EABridge_Example_AddIn.Reports +{ + public class ValidationIssue + { + public string severity { get; set; } + + public string type { get; set; } + + public string id { get; set; } + + public string msg { get; set; } + + public override string ToString() + { + return msg + " | " + severity + " | " + type + " | " + id; + } + } +} diff --git a/AddIn/EABridge_Example_AddIn/Reports/ValidationIssueCategory.cs b/AddIn/EABridge_Example_AddIn/Reports/ValidationIssueCategory.cs new file mode 100644 index 0000000..7ace5b2 --- /dev/null +++ b/AddIn/EABridge_Example_AddIn/Reports/ValidationIssueCategory.cs @@ -0,0 +1,10 @@ +namespace EABridge_Example_AddIn.Reports +{ + public enum ValidationIssueCategory + { + Load, + UML, + Resource, + Custom, + } +} diff --git a/AddIn/EABridge_Example_AddIn/Reports/ValidationIssueSeverity.cs b/AddIn/EABridge_Example_AddIn/Reports/ValidationIssueSeverity.cs new file mode 100644 index 0000000..5a2535d --- /dev/null +++ b/AddIn/EABridge_Example_AddIn/Reports/ValidationIssueSeverity.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EABridge_Example_AddIn.Reports +{ + + public enum ValidationIssueSeverity + { + Error, + Warning, + Information, + None + } + public static class ValidationIssueSeverityUtils + { + + public static ValidationIssueSeverity GetSeverity(string severity) + { + switch (severity) + { + case "E": return ValidationIssueSeverity.Error; + case "W": return ValidationIssueSeverity.Warning; + case "I": return ValidationIssueSeverity.Information; + default: return ValidationIssueSeverity.None; + } + } + + public static int GetSeverityLevel(ValidationIssueSeverity severity) + { + switch (severity) + { + case ValidationIssueSeverity.Error: return 2; + case ValidationIssueSeverity.Warning: return 1; + case ValidationIssueSeverity.Information: return 0; + default: return -1; + } + } + + public static int CompareSeverityLevels(string first, string second) + { + var firstSeverity= GetSeverity(first); + var secondSeverity = GetSeverity(second); + return GetSeverityLevel(firstSeverity) - GetSeverityLevel(secondSeverity); + } + + } +} diff --git a/AddIn/EABridge_Example_AddIn/UI/CLIPathForm.Designer.cs b/AddIn/EABridge_Example_AddIn/UI/CLIPathForm.Designer.cs new file mode 100644 index 0000000..2afe786 --- /dev/null +++ b/AddIn/EABridge_Example_AddIn/UI/CLIPathForm.Designer.cs @@ -0,0 +1,140 @@ +namespace EABridge_Example_AddIn.UI +{ + partial class CLIPathForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(CLIPathForm)); + this.cliPathTextBox = new System.Windows.Forms.TextBox(); + this.browseButton = new System.Windows.Forms.Button(); + this.okButton = new System.Windows.Forms.Button(); + this.cancelButton = new System.Windows.Forms.Button(); + this.label = new System.Windows.Forms.Label(); + this.pathNotValidLabel = new System.Windows.Forms.Label(); + this.chooseFolderDialog = new System.Windows.Forms.FolderBrowserDialog(); + this.SuspendLayout(); + // + // cliPathTextBox + // + this.cliPathTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.cliPathTextBox.Location = new System.Drawing.Point(12, 38); + this.cliPathTextBox.Name = "cliPathTextBox"; + this.cliPathTextBox.Size = new System.Drawing.Size(635, 20); + this.cliPathTextBox.TabIndex = 0; + this.cliPathTextBox.TextChanged += new System.EventHandler(this.cliPathTextBox_TextChanged); + // + // browseButton + // + this.browseButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.browseButton.Location = new System.Drawing.Point(664, 36); + this.browseButton.Name = "browseButton"; + this.browseButton.Size = new System.Drawing.Size(108, 23); + this.browseButton.TabIndex = 1; + this.browseButton.Text = "Browse"; + this.browseButton.UseVisualStyleBackColor = true; + this.browseButton.Click += new System.EventHandler(this.browseButton_Click); + // + // okButton + // + this.okButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.okButton.Location = new System.Drawing.Point(550, 117); + this.okButton.Name = "okButton"; + this.okButton.Size = new System.Drawing.Size(108, 23); + this.okButton.TabIndex = 2; + this.okButton.Text = "OK"; + this.okButton.UseVisualStyleBackColor = true; + this.okButton.Click += new System.EventHandler(this.okButton_Click); + // + // cancelButton + // + this.cancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.cancelButton.Location = new System.Drawing.Point(664, 117); + this.cancelButton.Name = "cancelButton"; + this.cancelButton.Size = new System.Drawing.Size(108, 23); + this.cancelButton.TabIndex = 3; + this.cancelButton.Text = "Cancel"; + this.cancelButton.UseVisualStyleBackColor = true; + // + // label + // + this.label.AutoSize = true; + this.label.Location = new System.Drawing.Point(12, 13); + this.label.Name = "label"; + this.label.Size = new System.Drawing.Size(493, 13); + this.label.TabIndex = 4; + this.label.Text = "Select the path to the YAKINDU EA-Bridge CLI Application which executes the actua" + + "l model validation."; + // + // pathNotValidLabel + // + this.pathNotValidLabel.AutoSize = true; + this.pathNotValidLabel.ForeColor = System.Drawing.Color.Red; + this.pathNotValidLabel.Location = new System.Drawing.Point(12, 72); + this.pathNotValidLabel.Name = "pathNotValidLabel"; + this.pathNotValidLabel.Size = new System.Drawing.Size(405, 13); + this.pathNotValidLabel.TabIndex = 5; + this.pathNotValidLabel.Text = "This path does not contain the YAKINDU EA-Bridge CLI. Please choose a valid path"; + // + // CLIPathForm + // + this.AcceptButton = this.okButton; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.AutoSize = true; + this.CancelButton = this.cancelButton; + this.ClientSize = new System.Drawing.Size(784, 161); + this.Controls.Add(this.pathNotValidLabel); + this.Controls.Add(this.label); + this.Controls.Add(this.cancelButton); + this.Controls.Add(this.okButton); + this.Controls.Add(this.browseButton); + this.Controls.Add(this.cliPathTextBox); + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.MaximizeBox = false; + this.MaximumSize = new System.Drawing.Size(800, 200); + this.MinimizeBox = false; + this.MinimumSize = new System.Drawing.Size(800, 200); + this.Name = "CLIPathForm"; + this.Text = "Select Path to YAKINDU EA-Bridge CLI Application"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.TextBox cliPathTextBox; + private System.Windows.Forms.Button browseButton; + private System.Windows.Forms.Button okButton; + private System.Windows.Forms.Button cancelButton; + private System.Windows.Forms.Label label; + private System.Windows.Forms.Label pathNotValidLabel; + private System.Windows.Forms.FolderBrowserDialog chooseFolderDialog; + } +} \ No newline at end of file diff --git a/AddIn/EABridge_Example_AddIn/UI/CLIPathForm.cs b/AddIn/EABridge_Example_AddIn/UI/CLIPathForm.cs new file mode 100644 index 0000000..0f76022 --- /dev/null +++ b/AddIn/EABridge_Example_AddIn/UI/CLIPathForm.cs @@ -0,0 +1,71 @@ +using EABridge_Example_AddIn.ApplicationHandlers; +using EABridge_Example_AddIn.Utils; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace EABridge_Example_AddIn.UI +{ + public partial class CLIPathForm : Form + { + private string CliPath = ""; + private ValidationConfiguration validationConfiguration; + public CLIPathForm() + { + InitializeComponent(); + validationConfiguration = FileUtils.ReadValidationConfigurationFile(); + if (validationConfiguration != null) + { + cliPathTextBox.Text = validationConfiguration.ValidationCLIPath; + CliPath = validationConfiguration.ValidationCLIPath; + } + ValidateContent(); + } + + private void ValidateContent() + { + if (HeadlessApplicationUtils.IsHeadlessApplicationDirectory(CliPath)) + { + okButton.Enabled = true; + pathNotValidLabel.Visible = false; + } else + { + okButton.Enabled = false; + pathNotValidLabel.Visible = true; + } + } + + private void browseButton_Click(object sender, EventArgs e) + { + if (DialogResult.OK == chooseFolderDialog.ShowDialog()) + { + CliPath = chooseFolderDialog.SelectedPath; + cliPathTextBox.Text = chooseFolderDialog.SelectedPath; + } + ValidateContent(); + } + + private void cliPathTextBox_TextChanged(object sender, EventArgs e) + { + CliPath = cliPathTextBox.Text; + ValidateContent(); + } + + private void okButton_Click(object sender, EventArgs e) + { + var configuration = new ValidationConfiguration + { + ValidationCLIPath = CliPath + }; + FileUtils.UpadteOrCreateValidationConfiguration(configuration); + this.DialogResult = DialogResult.OK; + this.Close(); + } + } +} diff --git a/AddIn/EABridge_Example_AddIn/UI/CLIPathForm.resx b/AddIn/EABridge_Example_AddIn/UI/CLIPathForm.resx new file mode 100644 index 0000000..f05451c --- /dev/null +++ b/AddIn/EABridge_Example_AddIn/UI/CLIPathForm.resx @@ -0,0 +1,2890 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + + + AAABAAEAyMgAAAEAIAAIhwIAFgAAACgAAADIAAAAkAEAAAEAIAAAAAAAAHECACcAAAAnAAAAAAAAAAAA + AAD///////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////9/////P3///n8///9/////f/////////////////+/////v////v////8//// + /P////v///79/////v////////38////+P////f////4////+P////v////7///9+////fr///7////+ + /////v////7////9/////f////3///79///////////+///+/f/+/Pv///79/////v////////////// + //////////////7+/v/7/f7/+/3+//3////9/////v7+/////////////////////v///fz///79//// + /v////z////8////+/////v////6////+v////r////7///+/f/+/v7///////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////9/////f////v9/v/8/v///P7///39 + /f/9/f3//v7+///////////////////////9/////f////3////////////8////+f////v////7//// + +/////z////8/////v////7///7+///9/f///P7//v3////+/////v////7////9/P////v////+//// + /v////7////+//78+//7+/v//Pz8//39/f/////////////////9/////f////3//////////v7+//r6 + +v/7+/v///79/////v////7////+//78+////fz////7/////P////z////+/////v////7///////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///8/v//+/3+//z+///9////+/7///v+///7/v//+v7///r+///4/v//+P7///X7///z+f//9Pr///f9 + ///7/////f/+//3////8//3/+/78//v+/P/8//3//f/+//3//v/9//7//f/+//3//v/9//7//f/+//3/ + /v/8//3////8///++f///Pn////7///++v///vr////8/////v////7////+/////v////7////+//39 + /f/8/Pz/+/v7//r6+v///////////////////////f39//39/f/////////////////9/////f////3/ + ///7/v//+fz///j7///9//////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////v7+//7+/v///v///f////3+///7/v//+/7///r+///6/f//+P7///b8 + ///3/f//+v7///r+///6/v//+Pv///v9/f/7/vz//v/7/////P////v////5////+P////f////z//// + 8P///ez///ro///65v//+uT///nj///44v/y5M7/797J/+zbxv/t3Mf/69zJ/+zdyv/15tP//vDd///2 + 5P//9+X///jm///55///++n///7u////8v////T////4///+9////PX///32////+/////v////8///+ + +v////7///////3////8/v//+v3///r+///4/v//+v7///3///////////////7+/v/+/v7//v7+//// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////v3////+///////9/////P7///n9 + /v/5/P//+v3///v8///9//////////z6+f/9+vb////6////+f////j////4////9/////X////y///y + 4P/q2sP/0byh/8GoiP+vlG//qoph/514TP+NZTT/gFUi/3ZKFP9yRQz/b0IJ/2xCDf9oQAz/aEAM/2tD + D/9qQg7/Zj4K/2hAD/9uRhX/a0MT/3FLG/9+WCj/jGY2/5x2Rv+tiVv/wJxu/8iof//Ywqb/6NfC///z + 4P////D////x////8f////T////1////+P////v////8///////7/f7/+Pz///j+///6/v///f////// + //////////////7+/v/+/v7///////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /v////7///////7+/v/9/f3//f/////+///////////8////+f////b////0////8f///+7///LZ//Tf + xP/SvKD/uqKE/5Z8Xv92Wzn/Zkkk/2REG/9pRBj/b0cW/3NHEv9zRQv/d0QG/3hCAf98QwD/f0QA/4FG + AP+BRwD/fUUA/3tEAP98RQD/f0gD/31GAf94RAD/eEMA/3lFAv93QwH/ekYE/3xIBv94RgT/dUID/3VC + A/95Rgf/d0kP/2tHGf9nRx7/a0wl/3pdOP+Welf/vKF//93Fp//x3MH///Xg///86v////T////4//// + +/////v////+///////+/v7//v7+/////////////////////////////v7+//////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////v7+//////////7////8///89f////L////t///2 + 3//z273/zbCL/6SCV/+GYjT/fVYi/3FGDf9yRQj/cEMG/3JDBv9zRAb/dEYG/3VFBf92RAL/cz8A/3VB + AP94QwD/e0YD/39IA/9+RwL/fEYA/3pEAP99RQD/fUUA/3xEAP98RAD/fUUA/31FAP9+RQD/fUYB/3lC + AP94QwD/ekUC/3pFAv95QwL/eEQC/3hEAv95RQP/dkIA/3pGBP97SAn/d0YI/3BCCP9vQw3/c0sX/3ZS + JP+IaD//ooZj/8uzlf/u2sH///Ld///+7P////H////3///9+f/9/f3//v7+//////////////////// + ///+/v7///////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////f/////////9//////////3//////////f////v////7//////7////////////////+//// + /v////7///////3////9/////f////////////7////+/////v////7////+////+/////r////4//// + 8///9+f//+/Y/9W/o/+tkW//gGA3/21JG/9uQxD/b0IJ/3FBB/96RQb/fkcA/4BIAP+ARwD/f0YA/31G + AP99RgD/fkcA/31IAP+ASgP/fkgB/3pGAP95RQD/eUUA/3lFAP95RgD/ekYA/31FAP9/SAD/gUcA/35H + AP+BRwD/gEkA/35GAP97QwD/fkcC/3xFAP97RAD/e0QA/3xFAv97RgP/e0QB/3pDAP+CRwD/gUcA/4BG + AP9/RQD/fkYA/3tGA/94RQb/c0QH/29CCf9pQQ3/Z0MV/21LIP+DZD3/rZFu/+LHpf//69D///7u///+ + 9f////f////5////+/////z////+//7+/v///////f////3////9///////////////////////+//// + /v////7////+//////////////////////////////7///////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////7////+//// + /v////7//f/+//3//v/9/////f////3////7/////f////v////9////+/////3////6////9v////P7 + ///9/v/////////7+/////z////8/////P/9/f3/+/////r////6////+/z6/////P////n////5//// + /P///vn////4////8f//6dP/1reY/5x3Uf9ySRz/bkEO/3FCCv9zRAf/dUUF/3lFA/96RAP/fkQD/4BE + Av9/RQD/gUgA/4FIAP+ARwD/fkcA/4BJAP99RwD/ekQA/3tEAP95RQD/eUUA/3pGAP95RQL/eUUC/3lF + Av95RQD/ekQA/3pEAP9+RgD/fkgB/4BIAf9/RwD/fUUA/31FAP+ASAH/fUUA/3xDAP99RAD/fUQA/3pD + AP98QwD/fEUA/4BGBP98RQL/ekMA/3tEAP98RQD/fUYB/31GAf96RQL/eUUD/3dEBf92RQf/dEUH/3FD + Cf9vQwj/dEcO/3RMG/+aflv/y7WZ///t1P///+/////z////+P////v////+//z+///7/v//+/7///v+ + ///9//////////////////v////7///++f/+/fn////+/////////v////7////+/////f////7///// + ///////////+/////v/9//7//f/+//////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////7////+/////v/9//7//f/+//3////9/////f////3////9/////f////3/ + ///9/////f////v////y+fz/+P////3/////+vv///7+/////P//+/j///38//3////3+/z/9/38//v/ + /v////v////3////9f////T////t//3v2f/Qu6D/jXBR/2dDG/9wRBX/e0kU/3M/A/95RQP/ekYA/3pG + AP98RwD/fEYA/35GAP+ARQD/gEUA/39HAP+ASAH/f0cA/31FAP97RQD/fUcA/35IAf99RgH/f0gD/31G + Af98RQD/e0QA/3lFAP95RQD/ekYA/3pGAP9/SAP/e0cA/3tEAP93QwD/eUIA/3tFAP99RgH/f0kC/39G + Af97RAD/fkUA/39GAf9/RgH/fkUA/35FAP9+RwT/eEAA/3pEA/99Rwb/fEcE/3pDAP93QAD/e0MA/31F + AP9+RgD/fEUA/3xFAP97RwH/eUQB/3dDAP95RQL/eUkJ/29DDf9fOQn/Z0Ua/5Z5VP/UvJ7//+7X//// + 8P////j////7/////v///////f////z+///9/f3//v7+/////v////z////7/////v////7//f39//38 + /v///v////7////9/////v////////////////7////+/////v////7///////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////+//// + /v////7////+/////v////7////+/////v/////////+/////P/8/Pb//Pn1///9/P///f7///z+///+ + ///9////+/////3///////z///31////9/////T//+/e/+TNs/+njGD/fFwn/2Q+CP9uRgz/d0kP/3A/ + Af9wPQD/eEcD/3dGAP93RwD/d0cA/3dHAP95RwD/ekYA/3xGAP98RQD/d0EA/3hEAv95RQP/eUUC/3pF + Av97RgP/fUYD/3tEAP96QwD/fUQA/39HAP+ASQD/gkgA/4JIAP+BRwD/fkYA/3lCAP94RQD/fEcE/3xJ + A/99SAX/fEgC/3pFAv94RAD/fUYD/3pFAv99RgP/fkcE/31GA/97RAH/ekMA/3tEAf99RgP/fEUC/3tE + Af97RAD/fEUA/31GAf9+RwL/f0gD/3xFAP95RAH/ekUC/3pGA/95RQP/dUMB/3VCA/94RAL/gUkC/39I + A/97SAn/c0UL/2pCEf97WS7/r5Ry/+DMs///++n////1///99v/8+fX////+///////8/Pz/+/3+//n9 + /v/6/v///f////3////////////////////9+/v///7//////////////////////v////z////8//// + /P////7///////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////v////7////+ + //////////////////////7////+/////v////7////+/////v////7////+//////////7///75///+ + +f////7///7///r5/f/7+////f7///r8/f/9+/r///72////9P///+//+ujR/8u2m/+NdVn/ZEUe/2xE + Cf90RgD/d0YA/3hFAP94QQD/fEUA/39IA/98SAL/eUcA/3dHAP93RwD/d0cA/3lHAP96RgD/fEYA/3xF + AP9+SAf/fEcI/3pGBP93QwH/d0EA/3hDAP97RAH/fEUC/31EAP9+RQD/gUYA/4FGAP+ARgD/gEUA/39E + AP9+QwD/fUYB/3pGA/94RAH/dkIA/3ZCAP94RAH/e0YD/3xHBP93QgD/eEMA/3tEAf98RQD/fEUC/3tE + AP9+RAL/fUYB/39IBf98RQD/eUIA/3lDAP98RgD/gEgB/35GAP97QwD/fEUA/3tEAP98RQD/fUYB/3tG + A/97RgP/eUUD/3tEAP9/QwD/gkUA/4JFAP99RQD/dkIA/29BB/9tRRT/bkwh/490Uv/Pup////Ld//// + 8v////f///rz//349f////7/+/////r////7/v//+fz///z+///9//////////7+/v/////////+//// + /v////7////8/////P////z////8//////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////3////9//////7////+/////////////////v////7////+/////v////7////+//// + //////////7///////////7///////b5/f/1+P//+vz///r9///29/v///76////9f///+7//+zN/8Sq + hf+DYzj/Y0AU/2U+Ef9uRA//dUUD/3pEAP9/RwD/hEkD/4JHAf+BRgD/gEUA/3tDAP98RgD/ekYA/3pG + AP96RgD/fEcA/35HAP+ARgD/gEUA/3g/AP96QAD/fkQC/4BGBP+ARgT/fkQC/3xCAP97QQD/gEYE/39F + A/9+RQD/fUQA/3xDAP+ARQD/g0gD/4RLBv97RAH/e0YD/3tGA/96RQL/eUUA/3lFAP96QwD/d0AA/35H + Av9+RwL/f0YB/39HAP9/RgH/f0cA/4FGAf9+RgD/d0AA/3tFAP+BSQL/g0wD/4FKAf+BRwD/gkgA/4JI + AP+CSAD/gUcA/4FHAP+BRwD/gkgA/4NJAP+CRwD/gUYA/4VLAP+ESgD/hEcA/4FHAP+DSQH/hEwF/3pF + Av9tPAD/aj4I/2pEFP+GZj3/xquJ///u1f////D////0////+P/9+fj/+fv8//r9///7/v//+v7///j9 + ///6/v///f///////v////v////7////+/////z////8//////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////f////3+/////v////7///////////////7///// + /v////7////+///+///////////////+/////v////7///r8/f/7/v//+v7///r9///7/v////7///// + +/////T/9uPI/62Sbf9uTB7/aEAL/3RHDv9zQwn/cEAG/3VEBv93QQD/fEUA/4FIA/+ARQD/fD8A/4FD + AP+FRwH/gEQA/4BFAP+ARQD/fkYA/35GAP9+RgD/fkUA/4BFAP+ARQD/g0kH/4FHBf9+RgX/fEQD/3lD + BP94QgX/eEQI/3hIDv9wPwf/cEEL/3FCDv9wQxD/bUIR/2tAD/9oPg//Zz4N/3RMGP97Ux//glom/4Rc + KP+DWyb/flYh/3dNGP9vRRD/bUEM/21BC/9sQAr/az8J/29BC/9xRAv/b0EL/20/Bf96SAb/ekYD/3hE + AP92QgD/eEIA/3lDAP98RQD/f0UA/4FHAP+BRwD/gUcA/4BGAP+ARgD/gUcA/4FGAP9/RQD/dj8A/3pD + AP+BSQL/g0kB/39FAP9+QgD/f0UA/4RKAv+BTAn/bTwA/29DDf9oQhL/akoh/7WaeP//8tT////r//// + 9f////n////+///+///6/v//+P7///r////5/v3////8////+f////j////5/////P////7///7///3+ + /////v////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////v////7////+ + /////v////7///////////////////////////////7////+/////v///f7///3+///7/v//+v7///r+ + ///7/v///v7+////+/////X/7drF/7GVdv96Vyv/ckgT/24/Af91QQD/ekMA/35FAP9/RgH/eUMC/3tF + CP91QQX/eUIF/35FB/+CRgT/hEUB/4RGAP+AQgD/g0UA/4FFAP+ARQD/fkUA/3xEA/96RAX/ekMG/3pD + Bv96RQb/dkAD/3E9Af9uPgT/ckMP/3tQH/+HYDT/jWxF/6SFZP+tknf/vqiP/9G9q//i0sL/8OLW//ru + 5P//9Oj///Ti///35P//+OL///Te///z3v//9N////Td///x2v//7Nb/9+PK/+bSuf/RvaT/v6mQ/6uW + e/+WgGf/jnRQ/4NbJv+CUxX/dkcJ/3FCBP91RQX/eEgI/3pIBv94RgT/eUUD/3pGBP97RgP/eUQB/3tE + Af98RQL/fEUC/3hEAv93Rgj/ckMG/3RBAv95RAH/fUYB/4BGAP+BRwD/gkgA/3g+AP+IUAn/eEQC/24/ + Av93SxX/akIO/4FbK//EpHv//+jK///55P////X////6//j6+//4/v//+P7///r///////z////5//// + +P////n////8///+///7/f//+v3///3///////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////v////7////+/////v////7////+/////v///f////3////9/////f////3+ + ///9/v//+/7///3+///////////7////+P////T/+ejT/7ykhv9/Xjf/Zj4O/2o9BP92QwT/gEkE/4FH + AP9/RQD/g0kA/4RJAf96QQD/ekUG/3dEBv96RQb/fEQD/3xCAP+ARQD/gkYA/35DAP+ARQD/fEUC/3lE + Bf91Qwf/cUIK/3BBDf9sQRD/akAR/3tUJ/+MZzv/q4hd/86uhf/ry6j//ODB///u1P//+OH////v//// + 9f////j////8///+/v/9/P///Pz///3+///9/f3////+/////v///vr///79/////P////z////7//// + +/////j///75///+9/////n////4///68///8+P///DQ///iu//nyaD/x6d8/6aFWP+HZTf/dE4e/2pD + D/9qQAv/b0MN/3NFC/9zRAf/dUQG/3hFB/96RQb/d0QG/3FCBf90RQj/eUYH/3hEAv95RAH/fkcC/4JI + AP9/RgD/g0gA/35EAP98RQD/fEcE/3VCA/9wQQP/c0MJ/29DDv+IYTX/yKiF///v1f////H////5//// + /v/7////+P38//3//v////v////5////+////////f7///r8///6/P///f7///////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////9/////f////3////7////+/////v+ + ///7/v//+Pv///v+///7/v//+v7///j8/f/7//////79////9f///un///je/9vAnv+GZDn/Zj8L/3RH + Dv9xQAL/d0MB/31GAf9+RQD/fUUA/4JHAf+CRwH/fkMA/3tDAP9/SAD/fEcA/31IAP9/SgH/fUgA/3tF + AP95RQD/eUgE/3NEBv9vQwj/akQO/2hHFv9qTSH/f2Q//6yTcf/QvqH/8OLQ//zz5v////X////1//// + 9/////f////4///+9/////n////7/////P////z////+/////v////////////3////7/v//+/7///v/ + ///9/v///f////3//////////////////v/////////+/////v////z////+/////v///////v/9//// + +/////n////1//704//p2MP/2MKm/6qOa/+IaD//b0gb/25DEP9xQgr/cT8D/3RBA/98SAb/ekUC/3tE + AP9+RwL/f0gD/3hDAP93QgD/ekUC/3xIAv97RAH/fEcE/3xHBP94RAL/eEQC/3tHBf96RgT/dEED/3ZD + C/9rPQ3/jWo//9zBn////OX////0////9v////z//P/9//r9+////////f////3+///7/v//+/3///f5 + ///9//////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////7////+//3/ + /v/9////+/////r////6////+v////b7/v/6////+/////3////7/Pr////+/////P////b////o//fX + s/+dek7/YjsH/2xABf96Rwj/d0MA/4JMBf+CSQT/fkcC/3tEAf96QwD/fEMA/3tDAP9/RAD/iE8E/4FI + AP99RgD/eUQA/3ZEAP90RQH/c0cH/29GCP9nQgr/YT4M/3JSJ/+XfVj/ybSU//fmy////+v////u//// + 9P/7+vb//f////3////8/v7/+fv7//7+/v/////////+/////v////7////+/////P////z////8//// + /P////7//f////v+///7/v//+/7///3+///9/v///f////3////9//////////////////////////// + /v//////+/7///H7///u+///8vz///b+///6///////+////+P///fD////w///+4///5sf/1raS/557 + UP95UiX/a0MT/2s/Cf92RQf/eEMA/3hDAP96RQL/e0YD/39KB/9+SQb/eEMA/3lEAf94QwD/eUQB/3tG + A/96RQL/d0IA/3lEAf9/Sgf/dz8A/4BKDf9xQgz/aEIS/5x9Vv/t2br////u////8/////v//f////v+ + ///6/v//8/b7//b2/P/9/v////7////+//////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////+/////P////z//f/+//3////7////+v////r////6////+v////v///////z/+fbx//// + +P///vP///vu///y2/+4l3D/dUoX/2Y5AP+CURP/eUUC/3M9AP+ASQD/e0MA/3lCAP97RgP/e0UE/3tF + BP9+RwT/f0QA/35EAP+BRwD/fkQA/4ZQCf93RQP/bUEC/3BJEv9jQhH/cFQr/6SMaP/kz7P/+enS//// + 7/////T////1////9P///vT//Pz2/////P////7////+/////v/+//3////+/////v////z////8//// + /P////z////8/////P////v////7/////P////////7////+/////v////////////////////////// + //////7////+/////v////7////8/////v//////+v3///j+///6////+f3+//n7/P/9/f3////+//// + +/////j///70////8f////L////x///w3f/Ou6b/oYdp/3JOIP9zRxH/dEYM/3ZHCv92QwT/dkEA/3xE + AP9/RQD/gEYA/4NJAf+CSAD/fkYA/35HAv9+Sgf/eUQF/3A8AP9+RwT/eD4A/3VAAP95SQn/cUQL/3FN + Hf+ymHT///fd////9//z8fD/+v////X7///7/v////7//////v////z///////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////7////8/////P////7//f////v////6////+v////r/ + ///9///////7////9/////T///7r////7f/Vwqf/fmI//2lAD/94Rgz/dkME/3E9AP94QgD/gksC/4JL + Av9+RgD/ekMA/35IB/97RQb/dkAA/3lDAv9/SAP/f0gA/3pEAP95Rgj/azwE/21CD/93UyX/kXRN/8m0 + lP/97db////t////9/////n////8///69//++vn////+/////v/9//7/+/39//r8/P/8/v7///////// + //////7//v7+//7//f////7////+/////v////7////8/////P////z////8/////v////7///////// + /v////7////+/////v////7////+/////v////z////8/////P////z////8/////P///v3////+//// + /v////7////+/////v///fz//fv6/////v////v////8/////P////v////7////+f///O7///LW/8+w + if+ObEH/ckwc/3BEDv90RQj/fEcE/39HAP+CSAD/gEYA/4BGAP+BRwD/eUIA/3M+AP91QgP/gEwK/3xF + AP+DSwT/gUcA/31FAP96RQL/b0AD/3FMGv+CZ0L/2six////9f////z////////9/f////7///34///+ + +f////7///////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////v////z////8//// + /v/9////+/////v+///7/////f//////+/////f////x////5v//8dH/qo1o/2pIHf9sRBT/cUIM/3hE + CP93RAX/eEcD/3xJA/97RwD/eEQA/3pEAP95QgD/fEQD/3xDBf95QwT/eUQF/3ZDBP9zQwP/ckYL/2c/ + Ff94VTT/spR3/+7Wvv//9uX////1////+f///v3//fj6///8/////P////3////+/////P7///7+//3/ + ///6////+P7///j+///6/v//+f3///j9///5/f//+v////v+///7/v///f////3////9//////////// + ///////////+/////P////7////8/////P////z////8/////P////z////8/////P////z////8//// + /P////z////7////+f////n////4////+f////v////7/////P////7////+///+/f////7////+//78 + +//8+vn////+////+/////b////y////6v/v2b3/spVw/39bLf9uQgz/ckED/3ZBAP99RQD/gEgB/4BI + Af9+RwL/e0YD/3lFA/94RAL/dUEA/35IAf99RgD/fkQA/4FKAf93QgD/ajsA/2lAD/9yUSr/r5d7///z + 4P//++3////3////+P////j////5/////v////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////v////7////////+///9/v///f7///3///////7////5////7////+3/9tu5/4hl + Ov9oQAz/ckUM/3A+Av92QAP/ekQF/3pGBP92RQH/dUQA/3lHAP98SAH/fkgB/4RLBv9+RAL/ekED/31H + C/92Rw//aUEM/29KGP98XDP/yq+V///r2/////L////0////+f////v/9fX1///+/////f////v///35 + /////f////3////+/////////f////v+///6/v//+v7///r+///7/v//+v3///v+///7/v//+/7///v+ + ///9/v///f7///3////9/////f/////////////////+/////v////7////+/////v////7////+//// + /v////7////+/////v////7////+/////v////z////7////+f////v////7///9+v/++/f//vz7///+ + /f/9/f3//f39////////////////////////////+vr6/////v///Pj///v0////9P///+7//+rO/8Om + gf+FYjb/bEQQ/3FEC/90QwX/dUID/3dCAP96QwD/ekMA/3pDAP98SAL/ekYA/3hCAP99RQD/gkoD/39G + Af95QwL/f0wO/3BBC/9mPg7/jWxF//bewP///+7////x///+9P/+/fn////+//////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////+/////v////////7///3+///9/v////7///// + /P////f///Xi/7yihP9pRR3/az8K/3lGCP9/RgH/gUYA/4JHAv9+RQD/eUQB/3hFAP94RQD/fEgB/35K + AP97QgD/eT4A/4FEAP9+RQf/cD8H/2Y/Ev+BZkH/zbue////7v///vL////2////+P////n////7//3/ + +//9//z////+/////v///f7///z9///9/v/9/f3/+vz8//n//v/7/////P37///+/f///v////7////+ + /////v/////////+/v///v////7////+/////v////7////+/////v////7////+/////v////7////+ + /////v////7///3////9/////f////3////7////+/////v+///7/v//+v////v////9/f3///7+//// + //////////7///3////9/v//+/7///v+///7/v//+/////v9/v/5+/v//f///////v////7///////// + //////////38///9+P////j////1///04f/DrpP/jHBN/147D/9jOQT/ekkL/4BJBP+BRwD/gkgA/31I + AP97RwD/d0MA/3ZCAP96RgT/fUcG/31EAP95PgD/gEQA/4RKCP90Qgj/cUsb/8ivj////ev////7//v/ + ///9//////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////7////+//// + /v////7///////3////9////+/7///3////////////+/////v////7//////////v////z////+///+ + /////v///f3////+//////z////1//Xgyv+dgV//Y0AU/29FEP93RQn/eEEA/35EAP+FSAD/fUMA/4FJ + Av99RgH/e0QA/39IA/97RQD/eEIA/35IAf+ASQb/dUIE/3RFEf+XcUf/172f///24/////j//vv3//// + /v////z////8////+v/9//f////7//3/+//+//v///38/////P////z////8/////P/8//3/+P////r/ + //////7////8///++////Pn///36/////P////7///79/////v///v////////////////////////// + //////////7////+///9/v///f7///3+///9/v//+/7///v+///7/v//+/////v////7////+/7///v+ + ///6////+/7///3+///7/f7/+fr+//z9///9/v//+/7///n8///5/P//+v3///n8///7/////f////z+ + /v/7/f3////+/////v///////Pz8//v9/v/9////+/3+//3////////////7////9//87tv/yrSY/4hp + Qv9oQA//b0EH/3tHBf94QgD/ekQA/3lFAP96SAb/d0cH/3VCBP95QwL/gkcB/4dIAP+JSQD/hEYA/31E + AP9wQgj/aEca/6CLbP/q4M7////3/////P////7////+/////v////7//////////////////f////3/ + ///9/////f////3///////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////+/////P////n////5////+/////7/+/7///j+///2/f//9vz///v9/v////z////7//// + +/////7///76////+/////z///7///f5///6/P///v3/////9f/p07f/gl4w/3FFCv91RQP/dEMA/3VE + AP98Swf/d0MA/3xIAf94RAD/gEoD/4FJAv97QAD/gUYB/4FHBf91PwD/dkQI/2xCDf+EYzb/y7KQ///3 + 4P////f///38//v9///6/P///f7//////v////v////4////+P////n////8/////v/////////+//// + +/////v////7/////v/6////+v7///////////7////+/////v////7////+/////v////7////+//// + /v////7////+/////v////7////+/////v/////////////+///9/////f7///v+///7////+/////3/ + /////////////////////v////7///3////9//////7//////////v////7////+///9/////f////3/ + ///9/////f////3///////////////////////////////////////////////////////7////+//// + /v////z///75////9v////T//+/Y/8Sri/9/YDn/ZUET/3BEDv95QwL/gEcC/3lFA/95SQn/dEEC/3tF + BP99QgD/hUgA/4RJAP+BSQD/fkcC/3FBAf9vQgn/aUEQ/5JwQv/w2LT////0////+/////z/+/j0//// + /P////7/+vr6//3////7////+/7///r+///6////+/////3///////7////+//////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////7////8////+f////j////5/////v/7/v//+P7///b9 + ///4/v///////////P///Pf///75/////v///v3///35/////P/6+fv///7////+/////vT/1b6k/3FP + JP9xRQr/d0QA/39LAP96RgD/eUUA/3tIAv9xQAD/eEQB/3tHAf93QQD/gUoF/3xFAv99RAb/eUQL/20+ + Cv98VSj/vaB7//zny/////D///7z/////v/7/v//9vj///j8///4/f//+/7//////P////n////5//// + +////////f////3////////////7////+f////n////8//v+///6/v///f////////////////////// + //////////////////////7////+/////v////7////+/////v////7////+/////v////////7///3/ + ///7/v//+/////v////9/////////////v////7////+//////////////7////+//////////////// + //////////////////////////////////////////////////////////////////////////////// + //////7////+/////P////z////+/////v////7////8////+P////X////w//3ozf+wl3f/akcf/3RF + Ef9vOwD/fksN/3RBAv98RgX/fUYB/4JIAP97QgD/fkUA/3pDAP9/SAP/e0cE/3xJCv92RQf/b0AD/4Bb + Kf/axan//vTj////9/////n/+fj0//7+/v/9/////f////3////7////+/7///v+///7/////f////// + /v////7///////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////7////8//// + +/////z////+//3////7/v//+fz///3///////7////8///9+f////7/+/7///r////7/////f////// + /v////b///7p/7qcef9iOgr/dUgP/3FCBP95RwX/ekYA/3hDAP+CSQD/gEkA/3lFA/+ASwz/gkkE/39H + AP90PgD/eEYK/2s/Cv9kPxP/pIdi//Pbvf///Of////y////9/////v////+///////8+/3/+v7///T9 + ///0/f//+v7///////////////////r+///6/v//+v7///3///////v////4////+P////n///////3/ + ///9/////f/////+///9//////7///3////9/////f////3+///9/v///f////3////9/////f/////+ + /////v////7////+/////v///f////v////7/////f////3////////////+/////v////z////+//// + /v/////////////+///9/////f////3////9/////f////3////9/////f////3////9/////f////3/ + ///9/////f////3//////////////////v////7////8/////P////7///////z8/P/////////8///6 + 8/////T////x///95v/24MT/k3dU/188Ef9xQQ3/fEUI/3g/AP+FTgX/eEMA/31JAv+CSQT/eUAA/4BH + Av93QwD/dEMA/3tLCf92QwX/azwE/3JPI//DqIb///rl////9f////7/+f7///n8///2+vv////+//// + /P////7////+///////9/////f////3///////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////+//////////////////////////7///76/////P////z////+//3/ + ///6/v//9vz///j////3/Pr////z///64P+ggFf/ckYR/3dGCP94RAL/e0cF/3xIBf96RgD/gksC/4RJ + Af97QAD/eD8B/3dBAv95QQD/dT8A/35OFP9mPwv/eVsy/9rDo////+n////0////+P/+9/T///z7//// + /v/79/b///76////+//3+vj/9v7///b9///7/v/////////////9////+v7///j+///6/v///f////// + /P////n////5////+////////f/////+//////////////3////9/////f7///3+///7/v//+/7///v+ + ///7/v//+/7///v+///9/////f7////+/////v////7///3////9////+/////v////9///////+//// + /v////7////8/////P////7////+//////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////+/////v////z////+//// + ///9/////f////3////9///////+////+f////b////z////7v//9uP/3MSo/31XLf9wQQv/eEME/3hE + AP9+SgP/fkoE/3xHBP95QgD/gUoH/3tHAf90QAD/ekYD/35IB/9+SQr/cUEH/2tDEv+vlXH///bg//77 + 8//9////+/7///3///////7////7////+/////v////+///////7////+/////3///////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////9/////f////3+///7/v///f////////////7////8//// + +////vn////7/////v/8/v//+Pv///j8///3/f//8vr6////+P/86Mn/nXtN/3FDCf98SAb/f0oH/3Y/ + AP9+RgD/fkQA/4BGAP+DSAL/e0EA/3pAAP+DSAr/fkUI/3hCBv92RxH/aUMT/6qNZv/+7tH////v//// + 9/////7//v3////9/////f////7////+/f////v////4////+f////7////+////+/////n////5//// + /P/9////+/7///r+///7/v///////////v////7///////r+///6/////////////v////7///////// + ///9/////f////3////9/////f////3////9/////f///////////v////7////+///9/v///f////3/ + ///9/////f////////////7////+/////P////7////+/////v////7///////////////7////+//// + /v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7///////// + //////7////+/////v////7///////3////3+v7/+Pz///r+///7/v//+fn5///9+f////v////5//// + 9/////L/9eLH/5qAWP90TRn/cEEE/3tGA/9yOwD/eEUA/3dGAv97RwT/e0YD/39FA/+ARQD/eUEA/3tD + AP+ARwL/ekoK/2U9DP+bgV3///Th///99v///////f///////v////z////5////+P////v////+//v+ + ///6/////f////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////3////7/v//+v7///r+ + ///7/v///////////P////n////5///++f////7//f////n8///4+////////////P////f/8OTM/49y + Rv91SQ7/ekUC/31FAP93PwD/g0sE/4NJAf+ARgD/gEYA/31CAP95QQD/gEcK/4BHCv9yPAX/c0UW/35a + Mv/Wupf////l////6/////T/+//+//X8///4+///+vv///j1/v/++v////7/////+//7/PP////4//// + +/////v////5////+f////n////7///////7/v//+/7///v+///9///////////////9////+v7///r/ + ///////////+//////////////////3////9/////f////3////9/////f////3///////////////// + /////////f7///3+///9/////f////3////////////+/////v////7////+//////////////////// + /////////////////v////7////+/////v////7////+/////v////7////+/////v////7////+//// + /v////7////+/////v///////////////v////7////+///////9////+/////v+///5/f//9fv///n9 + ///7/v///f/////////7+fj////8///99v////T///rg/8qwjP9+WCj/ckEJ/4BLDP92RQH/e0oG/3ZE + Av90PgD/f0UD/4ZJBf+CRwD/g0kA/35EAP96RAD/dUYI/2c/Dv+Td1T//u3Y////9v////z////+//// + /P////n////5////+/////7/+/7///r+///9//////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////f////v+///6/v//+v7///v+///////////7////+f////r///79//v+///6/v//+v3///// + /v////j///zp//fhvv+Kaz7/aUEM/29AA/98RwT/fkYA/4JKA/9+RgD/f0YB/35GAP+DSQH/gEUA/4NJ + B/97RAf/azcC/29EGf+IaUr/9uDH////7v////L////3////+//7////+v////n8///7/v////3////+ + ///5+fn//P37//3//P/8//v////+//////////7////+/////v////7//f////v+///7/v//+/7///3/ + ///////////////////9/////f/////+//////////7///3////9////+/7///v+///7/v//+/7///v+ + ///9/////f/////////////////////////9/v///f7////+/////////////////v////7////+//// + ///9/////f////3////9//////7////+/////v////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////3/ + ///7////+fz///b6///6/v//+v7///r+///4+///+/7///3///////7////8//v49P////j////x/+/a + u/+La0D/ZT4H/3BBA/98SAb/e0cF/3pEA/98RQL/f0QA/4RFAP+DRAD/g0gC/3pEAP9+RgD/fEgG/2o+ + CP+TcUb//OjP////9f////z//////////P////z////8/////v/7/v//+/7///3///////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////9////+/7///r+///6/////f///////v////v////5//// + /v/9////+P7///X7/////v/////4///65//+5MD/gFgj/3JDBv93SAv/ckED/3pEBf9/RQP/ej8A/4FG + AP97RAD/fEUC/31GAf92QQD/ekcI/29ACP95TyL/uJl4////7/////f///30////+P////r/+//6//3/ + ///5/f7/+/////n8///8/v///f////3////9////+/////v////9/////f////////////////////// + /////v///f////3////9//////////////////7////+/////v///////f////3////9/////f////3/ + ///9/////f////3////9/////f/////////////////////////////////////+/////v////////// + /v////7////+/////v/9/////f////v+///7/v//+/7///3+///9//////7////+/////v///f////3/ + ///9/////f////3////9/////f////3////9/////f////3////9/////f////3////9//////////// + /////////////////////////f////3////7/v//+/7///v+///5/P//+Pv///v+///7/v//9/r+//j8 + /f/9//////7//////v///vf////y///83/+ymW//cEgX/3BBCf92QwX/f0sJ/3tHAf96QgD/h0gA/4hI + Af96QwD/fkcC/35EAP+BRwD/gUoF/2o+A/+Ja0L/+ejO////9/////z////+//////////////////v+ + ///7/v///f////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////3////9////+/7///3/ + ///////////8////+/////z//f////j+///0/f//+P7////7+P////H//+XC/4BYJP98RQL/gUYA/3tF + Bv94RQf/e0UJ/3tCBP9+QwD/gEUA/3xFAP97RwT/cUAC/3NHDP9nPwv/fVou/+HDoP///+r////4//3/ + ///9//7////+/////v////7////+/////v/9//7/+//+//v////7////+/////v////9/////f////79 + //////////////////////7////+///7+v////z////8/////P////7////+/////v////7////+//// + /v///////f/////+//////////////////////7////+//37+v////7/+/n4/////v/+/Pv////+///+ + /f/////////////////////////+/////v////7////+//3////6////+v7///n9///6/v//+Pv////+ + /////////vz8//////////////////////////////////////////////////////////////////// + /////////////////////v7///38//7+/v//////9/n6//z+///9/////P7///3////9/////f////3/ + ///9/////f////3////7/v//+P7///r//////v/////+////+/////f////z////7f/Uupz/e1ku/2o+ + CP91QgP/gUoF/39EAP+AQgD/f0QA/3lEBf94RAL/gEYA/4RIAP+DRwD/f0gD/21CCf+IaD//+eXM//// + 9////v3/+/z///j7///7/v//9fj8//3///////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////f////3////9/////////////P////z////8/////v/7/v//+P7///b9///9///////1//3l + x/+FXy//eEUH/4JHAP+ERQD/fEIA/3lDBP97RAf/fUQH/4FFA/+CRwH/ekMA/3FBAf9sQwz/Y0IU/4Vr + Rv/u2rv////r///97P/9//7/9v////r////9///////////+//////7////+//3//v/7//7/+v/+//r/ + ///7/////f/////+/////v////7///v9/v/8/v///f////////////7////7////+f////v////7//// + /v////////////////////7////+/////////////////////v////z////8////+/////v////7//// + /P///fn////+///////9////+vz9//3//////////////////v////7////8/////P//////+/////r/ + ///1+///9vr///r9///////////8////+////fj////+/////v/////////+//////////7///////// + /v/////////+//////////7//////////v/////////+/////P////z////+//v7+//9/////f////j6 + +//9//////////////////7////+/////v////7///////3////4/v//+P7///3///////7////8//// + /P////r////3///+7v/jzrL/j29E/2pAC/9xPgD/fUYD/4NIA/+CSAb/ekYE/3hEAv98RQD/gkgA/4BG + AP+DSQH/cj0A/3JGEP+IaUL//+zT////9///////9/v///f7///9/////f39//////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////7////8/////P////7///////n9 + ///6/v//+Pr7////+f/7587/k3FG/3VGCf94QQD/gUYB/35DAP+ARQD/gUUD/31DAv98QgH/f0MB/3tC + AP+BSgX/dUgL/19AE/+Pe1z/9e7b////9f////L////3//v//v/4////+//////+/////v////7////+ + ////////+/////j////4////+P////3///////7////+///+/////v//+v3///r+///7/v//+/3+//v5 + +P///vn////3////+f////v////+//3////7/v//+/7///3//////////////////v////7////8//// + +/////n////5////+f///fX////6/////v/9////9/v///j+///y+f//9/3///3////////////+//// + /P////z////8///////7////+f7///j9///7/v/////+////+////fP////x////9P////n////8//// + /v////z////+/////P////7////8/////v////z////+/////P////7////8/////v////z///z3///8 + 9/////z////+///////9/////f////z+///////////+/////P////z////8/////P////7///////v+ + ///6/v//+v////v//v////z////8/////v////v////5////9P/4583/kXRP/2o/Dv96RQz/eUMC/3Y/ + AP9/SAP/e0YD/3ZDBP94RQb/dkEA/35HAv+BRwD/fkcC/21AB/+Ydkv//u3Y////+P/9////8/f8//3/ + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////+//// + /v////z////8///////9/////f///////v////j//ezX/4xvSv9qQg7/ekUC/4ZMBP98RQL/fEQD/4BG + BP+BRQP/fkIA/4BEAv+CRwL/eUIA/24/Af9tSBT/pZFu//nv3f////n//f/+//z89v////v/+//+//r/ + ///9//////7////+/////v////7///3////6////+P////j////6/////f///////v////z////+//// + ///8/v//+/7///z+//////z////4//Hj0f/+7dj//OrT//rq0//36df/8+ja//Po2v/z6Nr/9+nX//fp + 1//16df/9enX//fp1v/46tT/+urT//zr0f/869H//OrT//vt1//47Nr/7+fa///89f/9+/r//f////r+ + ///6/v///f////////////7////8/////P////z///////v////7/v//+////////v/++PH/8ebY//7r + 1v//7tL//+rO//zp1P/46db/+OnW//jp1v/46db/+OnW//jp1v/46db/+OnW//jp1v/46db/+OnW//jp + 1v/46db/+OnW//fp1//37N7////2///68/////z///////n7/P/8/v///f////////////7////8//// + +/////v////8/////P////7//f7///v+///6////+////////v////7////+/////v/8//3////7//// + 9f//897/nn5b/3FHGP9xQQf/ekYD/3tDAP96QwD/cUAC/3ZHCv94Rgr/ekQD/4FHAP+CRQD/gUoF/21B + C/+VeVb///fl///9+P///////fv6/////v////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////7////+/////v///////////////v///fj///vu///+5f+WeVT/aUEQ/3BB + BP96QwD/fkYA/3tGA/95RQP/eUQF/3lDAv+AQwD/g0cB/4FGAf9zQgT/aUUV/7ulgv//+eX////3//// + +//2+ff/+/////r+///////////+/////v////////7////+/////v///f7///r////6////+v////v/ + ///////////+/////P////z///35/////P////z////5////8P/34sf/cFEq/2tFFf9zSRT/c0oT/3FJ + Ff9wSBf/cEgX/3NJFP93ShH/dUkT/3BIF/9uSBj/cEgX/3FJFP9zShP/c0oT/3NKE/9xSRX/bEYW/2hI + Hf92XDj/8Nu/////8P////T///zz///++f////////7//////v////7////8/////P///////f////X3 + 9/////v///73/9bJuf9pVDn/XkIf/2xHG/9zSxr/cEgX/3BIF/9wSBf/cEgX/3BIF/9wSBf/cEgX/3BI + F/9xSRj/cUkY/3FJGP9xSRj/cUkY/3FJGP9xSRj/akgd/1pGLf//+uz////3///89f/+/Pv//f////z+ + ///8/v///////////v////z////8/////P////z////+/////v/////////////9/////v///f////v/ + ///9//7////8/////v////7//fn4////+P//++j/qZBu/2xEFP93RQn/gUgD/4RMBf9zQgT/bkAG/3ZG + DP92QwX/fkMA/4BDAP99QgD/ekYE/2xEE/+kiWf///nm///+9f////v///z7//////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////3////9///////8//// + 8////+v/qYpj/2lBDf92Rwr/e0YD/4BJBP96QwD/eUUC/3ZEAv93QwH/ekUC/4FGAP95QAD/c0AB/3JK + Fv/FrIr////r////9f////v////7//b4+P/6/v//+fz///////////7////+/////////////f////3/ + ///9/////f////3////9//////7////+/////////////////v///v3////8////+/////j////w///v + z/9lPw//cUIF/3pFAv98RQD/ekUC/3pFAv96RQL/fEYA/4FHAP+ARgD/ekUC/3dFA/95RQL/ekYA/3xG + AP98RgD/fEYA/3lFAv90RQj/a0EM/2pJHP/64Lz////r////8f////b////7///+///9/v////////// + /v////7////+/////v////7////+////+f////T/3822/2BEIf9oQhL/dEYM/3ZBAv95RQP/ekUC/3pF + Av96RQL/ekUC/3pFAv96RQL/ekUC/3pFAv96RQL/ekUC/3pFAv96RQL/ekUC/3pFAv9uQgz/WT4c//// + 8P////H////4/////P/8/v//+Pv///v+///9/////////////v////7////+/////v/////////////+ + /f////7///7////9///9/v//+/////v////7//7//f39///9/f///v7////8////8////ef/uZ17/3FJ + Gf9yPwH/fEUA/31ICf9yQQP/dEIG/3dEBv+ASQb/hUoE/39EAP98QwD/d0gL/2lBEf+2m3n////w//// + +P////z////+//////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////3////9/////f////3/ + ///7/v//+/7///3///////v///vo/9S5l/9oQAz/eUYH/3xFAP9+RgD/eEMA/3lFAv90RQH/d0cA/3xF + AP+DSgD/f0cA/3A/Af+DXiz/s5d0////6P////P////5//Tz7////////f7///v+///9/f////7////+ + //////////////3////9/////f///////////v////7////+/////v////7///3+///6////+v////r/ + ///7/v///f7/////+////u7//+nL/2M/Ef91Rw3/ekUC/3xFAP95RQP/eUUD/3lFA/96RQL/gEUA/4BG + AP96RgD/ekYA/3xGAP9+RwD/gEYA/4BGAP98RgD/eUUC/3BDBv9sRRH/cVIr//Ldwf///+3////5//v9 + /f/5/v//+v7///v+/////v///////////v////7////+/////v///Pf////3////8P/hyav/aUUX/29B + B/+ARwL/gkgA/35GAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/fEUA/3FDCf9ZPBf////r////8f////f///z4//v9/v/7/v//+v3///v+///9/////f////// + /////////f////3//////v////79///++/////z////+///+///9/v//+v7///r+///6/////f////// + +/////b////1////9P///Oz/v6qL/3lOG/9tOQD/f0gF/4RLBv99RgP/eEIB/3pFBv92QQL/gksI/3lC + AP97RAH/dUQG/3NLG//RtZb///7w/////P////7///////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////f////3////9//////////////////////////////////////////// + ///////////////////9/v//+/7///v+///9///////8////9f/eyKz/akYY/3dEBv+CSAD/gUcA/39F + AP98RwT/eUUC/3pIAP97SQD/fUQA/3xGAP9yQwX/bkkX/7KXdf///+7////1////+f////z////+//79 + ///6+///+/v////9/////v////7//////////////f/+//3//v////7////+///+/////v////3////+ + /////v//+/7///j////4////+v7///j8///3+///////////9//+6c7/akQU/3FAAv96RQL/fEUA/3lF + A/95RQP/eUUD/3pFAv98RQD/fkYA/3xFAP96RgD/fkYA/35HAP+ARgD/gEYA/35GAP96RQL/dkcJ/2M7 + Bv9tUCn/7tvA////9f////7/9/z///j+///6////+/7///3//////////////////v////7////+//// + +/////f////x/+DHp/94UBz/eUUD/4JFAP+FRwD/gEYA/35GAP9+RgD/fkYA/35GAP9+RgD/fkYA/35G + AP9+RgD/fkYA/35GAP9+RgD/fkYA/35GAP9+RgD/c0QH/2FBGP///+j////x///68f////z//f////r7 + ///7/v//+/7///v//////v////////3////9/////f/////+/////v3///77////+/////z///////3/ + ///7/v//+v7///j9///9///////7////9v////j///30////+f////L/vqB9/3VKF/90QQP/f0gF/3tC + AP95QgD/fEcI/3ZDBP94QQD/gUkC/4NIAP96QwD/cUIK/3FPJP/r1rv////0////+//////////+//// + /v////7////////+///9/////f////3///////7////+/////v////7///////3///////////////// + /////////////////////////////////v////7///////3////7////+/////v+///9//////////// + //////7////+/////v////7//////////v///fz////+//r9///6/v//+v/+////+P////T/69i9/3pY + Lf9tPwX/gkcA/4hIAP+ERwD/f0QA/39IBf97RAD/hEgA/35EAP97RAD/cEMK/2tIHf/AqIr////x///+ + 9f////z////+/////v/////////////+///9/v///f7////+//////////////////////////////// + ///////////////////////////////////9/////f////3////9/////P7///v+///9///////6//vp + 0v9pQQ3/e0YD/3xFAP98RQD/ekUC/3pFAv98RQD/fEUA/3xFAP98RQD/ekUC/3pGAP9+RgD/fkYA/3xF + AP98RQD/fkYA/3xFAP96RQL/cUMJ/3BOI//y3cL////3//7+/v/9/////f///////////////f////3/ + ///////////+///////////////8////+f////f/3Miv/3NLF/96RQL/f0QA/4BGAP9+RgD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3tEAP9yQwb/Y0AU//// + 5f////j///79//////////////////3////9/v///f///////v////7///////3////9//////////// + //////7////+/////v////////////3////9/////f////////////7////8/////P////z////+//// + +/////L/uqSI/2VBE/90RAr/eUQB/3xEAP+ASQT/fEUA/4BFAP+DSQD/gUcA/3xDAP91Rgn/aT8K/4Je + MP/+4sP////1/////v/7+vb////7/////P///////v3///v+///4////+v///////P////n////7//// + /P/9////+v////3////////////////////////////////////////////+/////v/9/////f////v/ + ///6////+/7///3////////////+/////v////z////+/////v///////////////v/++fr//f7///j8 + /f/7/Pj////1///w1v+Mckr/akAL/3RAAP+HSQL/h0YA/4RGAP99QgD/f0UD/3pBAP9+QgD/ilAI/3FC + Bf9nQBP/xqyO////7v///PX////+///+/////v/////////////////////////+///9//////////// + //////////////////////////////////////////////////////////////////////////////// + /v/+/v7//f////3//////v3/9+nT/21BDP9/RwD/fkYA/3xGAP98RQL/ekYA/35FAP98RgD/fEUC/3pF + Av96RQL/ekYA/35FAP98RgD/fEUC/3pGAP9+RQD/fkYA/35GAP91RAb/cU4i//Ldwv////j//v7+//// + ///////////+/////v/9////+/////////////7//f////////////7////7////+//YyLH/dUoX/3pG + AP99RAD/fkYA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/e0QA/3JDBf9lQBT////l////+f/6/v////7///////////7///////3////9///////8//// + /P///////f////////////////////////////////////////////////////////////////////// + ///////////////////////////+////+///+ur/spd1/21HF/9wQQT/e0YD/35GAP99QwD/gEYA/4JI + AP+BRwD/ekMA/3lGB/9zRgn/ckUM/598UP//7tz////5////+f////n///z4/////////v//+/7///j+ + ///6///////8////+f////v////8//3////6/////f////////////////////////////////////// + //////////////3////9////+/////v////9/////f////////////7////+/////v/////////////+ + /////v///v3////+//////7////7////+P///+7/qZFt/2I9C/91Rgn/f0kI/3xGBf96QAD/gUYA/39F + AP+DSAL/fUYB/3ZBAP93SAv/aEAP/7WYc////ef///vu/////P///v///f/////+///////////+//// + /v////////////////////////////////////////////////////////////////////////////// + ///////////////////////////+//7+/v/9/////f/////+/f/36dP/bUEM/39HAP9+RgD/fEYA/3xF + Av96RgD/fkUA/3xGAP98RQL/ekUC/3pFAv96RgD/fkUA/3xGAP98RQL/ekYA/35FAP9+RgD/fkYA/3VE + Bv9xTiL/8t3C////+P/+/v7///////////////7////+//3////7/////////////v/9//////////// + /v////v////7/9jIsf91Shf/ekYA/31EAP9+RgD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP97RAD/ckMF/2VAFP///+X////5//r+/////v////////// + /v///////f////3///////z////8///////9//////////////////////////////////////////// + //////////////////////////////////////////////////////z////5////9P//9+L/p4xq/2dB + Ef92Rwr/f0gD/4BGAP9+RAD/fUUA/39IA/97RgP/dUEA/3dHB/9tPwX/Z0ER/7ScgP////D////1//// + +f////7///7///79///8/f//+/////3///////7////8/////v////7//f////v///////////////// + /////////////////////////////////////////f////3////9/////f////3////////////+//// + /v////7////+//////////////7///3+///6/P////7////79v////X////y/9LAo/9gPhD/dEgN/3lF + A/97RgP/dUIE/3pEB/+BSAP/fkQA/4FHAP94QwD/eEsS/2E7C/+dgFv////m////8v////n/+/v7//v+ + ///9/v///f////////////7////+/////v////////////////////////////////////////////// + //////////////////////////////////////////////////////7//v7+//3////9//////79//fp + 0/9tQQz/f0cA/35GAP98RgD/fEUC/3pGAP9+RQD/fEYA/3xFAv96RQL/ekUC/3pGAP9+RQD/fEYA/3xF + Av96RgD/fkUA/35GAP9+RgD/dUQG/3FOIv/y3cL////4//7+/v///////////////v////7//f////v/ + ///////////+//3////////////+////+/////v/2Mix/3VKF/96RgD/fUQA/35GAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3tEAP9yQwX/ZUAU//// + 5f////n/+v7////+///////////+///////9/////f///////P////z///////3///////////////// + //////////////////////////////////////////////////////////////////////////////// + /P////j////0////8///+eb/lHhV/2hAD/91QgP/fUUA/31GAf94QwD/ekUC/31IBf92QQD/d0MB/3pI + DP9uRA//aksk/9W/o/////H////3/////v/6/P3//f////79//////////////////////////7///// + /////////////////////////////////////////////////////////f////3//////v////7///// + /////////////////v////7////+//////////////7///3////7/v//+/7///v9///5+Pz////6//// + 8f/24cL/elks/29FCv93RQP/eEMA/3hDAP92QwX/d0UJ/3RBAv94QwD/gksC/3lHBf9hPQ//jXRU///x + 2P///+/////5/////v/7////+f7///v+///9///////+/////P////z////8/////v////7///////// + //////////////////////////////////////////////////////////////////////////////// + /v/+/v7//f////3//////v3/9+nT/21BDP9/RwD/fkYA/3xGAP98RQL/ekYA/35FAP98RgD/fEUC/3pF + Av96RQL/ekYA/35FAP98RgD/fEUC/3pGAP9+RQD/fkYA/35GAP91RAb/cU4i//Ldwv////j//v7+//// + ///////////+/////v/9////+/////////////7//f////////////7////7////+//YyLH/dUoX/3pG + AP99RAD/fkYA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/e0QA/3JDBf9lQBT////l////+f/6/v////7///////////7///////3////9///////8//// + /P///////f////////////////////////////////////////////////////////////////////// + ///////////////////////////8////+P////j////8///+9f/97Nf/iWxH/2s/Cf95Rgf/fUkH/3hE + Av90QAD/ekYE/3xHBP93QgD/ekUG/3BDBv9pQQ3/fl41//3ozf////T///76//f7/P/7//////////// + /v////7///7///v////6////+/////////////7///////////////////////////////////////// + ///9/v///f/////+/////v///////////v////7////+/////v////7///////3////9////+/////r/ + ///6/v//9/n////+/////vf///vk/5h2S/9vRAv/eUcF/3tFAP+BSgX/fUYD/3pFBv92QwX/b0AD/3dI + Cv93QwD/b0IF/3tfPP/26NL////y////9v/+/Pv/9/v8//r////6////+/////3///////7////8//// + /P////z////+/////v////////////////////////////////////////////////////////////// + ///////////////////////////+//7+/v/9/////f/////+/f/36dP/bUEM/39HAP9+RgD/fEYA/3xF + Av96RgD/fkUA/3xGAP98RQL/ekUC/3pFAv96RgD/fkUA/3xGAP98RQL/ekYA/35FAP9+RgD/fkYA/3VE + Bv9xTiL/8t3C////+P/+/v7///////////////7////+//3////7/////////////v/9//////////// + /v////v////7/9jIsf91Shf/ekYA/31EAP9+RgD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP97RAD/ckMF/2VAFP///+X////5//r+/////v////////// + /v///////f////3///////z////8///////9//////////////////////////////////////////// + //////////////////////////////////////////////////////7////6///++f/+/v7//vz7//// + 9f/s2b7/hGE2/2xACv90QwX/ekYE/3hEAv93QwH/fkkG/3hEAP98RQL/eEQC/3ZHCf9lPQn/pIVk///5 + 5/////n//f/+//j9/P/9//7////+/////v///v//+v////j+///4//////////////////////////// + //////////////////////////////v+///9/v////7///////////7////8/////P////z////+//// + /v///////f////3////7////+v////v+///4+P7////+////9P+6oYH/dUwV/3ZCAP9/SAD/gkgA/3pC + AP96QQD/fkUA/3tHBf91Rw3/cUYN/2Y6AP+DXCj/5dK3////9f///vb/+/r2//3////6////+f3///n+ + ///7/////f///////v////z////8/////P////7////+//////////////////////////////////// + //////////////////////////////////////////////////////7//v7+//3////9//////79//fp + 0/9tQQz/f0cA/35GAP98RgD/fEUC/3pGAP9+RQD/fEYA/3xFAv96RQL/ekUC/3pGAP9+RQD/fEYA/3xF + Av96RgD/fkUA/35GAP9+RgD/dUQG/3FOIv/y3cL////4//7+/v///////////////v////7//f////v/ + ///////////+//3////////////+////+/////v/2Mix/3VKF/96RgD/fUQA/35GAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3tEAP9yQwX/ZUAU//// + 5f////n/+v7////+///////////+///////9/////f///////P////z///////3///////////////// + //////////////////////////////////////////////////////////////////////////////// + //////7////+//////////7////7///76v/cxKj/dFIn/21AB/95RQP/f0oH/3lCAP97RgP/eUUA/4NI + Av+DTAP/dkIA/3lKDP9nPRL/0rWa///+8P////v/+f34//3//v////7////+///+///7////9v////j/ + /////v//////////////////////////////////////////////////+/7///3+/////v////////// + /v////z////8/////P////7///////3////9////+/////v////7/////f/////9/v////n/69S+/35b + M/9vQAL/gEkA/35FAP+BRwD/gkcB/39HAP+BRgH/eEIB/3BCCP9lPgf/cUwY/8+ziv////H/+vfy//// + /P/9////+Pz9//r////7/v//+v3///3///////7////+/////P////z////+/////v////////////// + //////////////////////////////////////////////////////////////////////////////// + /v/+/v7//f////3//////v3/9+nT/21BDP9/RwD/fkYA/3xGAP98RQL/ekYA/35FAP98RgD/fEUC/3pF + Av96RQL/ekYA/35FAP98RgD/fEUC/3pGAP9+RQD/fkYA/35GAP91RAb/cU4i//Ldwv////j//v7+//// + ///////////+/////v/9////+/////////////7//f////////////7////7////+//YyLH/dUoX/3pG + AP99RAD/fkYA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/e0QA/3JDBf9lQBT////l////+f/6/v////7///////////7///////3////9///////8//// + /P///////f////////////////////////////////////////////////////////////////////// + //////////////////////////////r8/f/9///////+//z79////fz////5////7/+8o4P/bkYV/3A/ + Af99SAX/ekQA/35HBP97RAD/gEYA/35EAP9+SAD/eEQB/3NDD/+AWzX/+eTO///98P////v/+/78//// + /v///v////7///3////4////+P////3+/////v////////////////////////////////////////// + ///7/v///f7////+///////////+/////P////z////8/////v/+/v7//f////j8/f/9/////f////r7 + +f////z///35////8v+Rb0v/bEAL/3hFBv98RgD/f0YA/4BGAP+GSwP/fUIA/35FAP+ASgn/dEUH/2Q+ + CP+iiGD////p////9/////z////+/////v/9////+/////3////9/////f///////v////7////+//// + /v/9/////f////3///////////////////////////////////////////////////////////////// + ///////////////////////////+//7+/v/9/////f/////+/f/36dP/bUEM/39HAP9+RgD/fEYA/3xF + Av96RgD/fkUA/3xGAP98RQL/ekUC/3pFAv96RgD/fkUA/3xGAP98RQL/ekYA/35FAP9+RgD/fkYA/3VE + Bv9xTiL/8t3C////+P/+/v7///////////////7////+//3////7/////////////v/9//////////// + /v////v////7/9jIsf91Shf/ekYA/31EAP9+RgD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP97RAD/ckMF/2VAFP///+X////5//r+/////v////////// + /v///////f////3///////z////8///////9//////////////////////////////////////////// + ///////////////////////////////////////////////////9////+/7///v+/////v3////8//// + /v////z///71///96P+ff1b/bEAK/3tHBf97QwD/fkYA/4NJAf98QgD/g0kA/4NLAP93QAD/fEUI/20/ + D/+fg2D////u////9f////z///7////9/v////7////+//X6+f/6/////f7////+/////v////////// + //////////////////////////////v+///9/v////7//////v////z////8/////P////7///////r8 + /P/7////9/v8//3///////7////7///+9f////T/xayS/3VLHP9zQgT/eUUC/3xGAP9/SAD/gUcA/3xC + AP+BRgD/e0QB/3VAAf9wQgj/lHJE///z2P////T////7/////v////7////+/////v////7///////// + /v////7////+/////v////7//f////3////7/////f////////////////////////////////////// + //////////////////////////////////////////////////////7//v7+//3////9//////79//fp + 0/9tQQz/f0cA/35GAP98RgD/fEUC/3pGAP9+RQD/fEYA/3xFAv96RQL/ekUC/3pGAP9+RQD/fEYA/3xF + Av96RgD/fkUA/35GAP9+RgD/dUQG/3FOIv/y3cL////4//7+/v///////////////v////7//f////v/ + ///////////+//3////////////+////+/////v/2Mix/3VKF/96RgD/fUQA/35GAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3tEAP9yQwX/ZUAU//// + 5f////n/+v7////+///////////+///////9/////f///////P////z///////3///////////////// + //////////////////////////////////////////////////////////////////////////////3/ + ///7/v//+v3////+/f////z////+/////v///vn///7w///t0f9/XDD/dEYM/3tEAP+BRwD/fUMA/4ZM + Af+ARwD/fUUA/4VMAf9+QgD/eEMK/2hEFv/ZwqL///7t////+f///fz///7////8+/////z//f/+//v/ + ///8/P///Pz////+////////////////////////////////////////+/7///3////////////+//// + /P////v////8/////v/8/v7/+f3+//v////6/Pz////+////+v////f////y///ozv+AXTX/aDoE/3hE + Av99RgH/fUcA/3pEAP99RgH/gkkE/3pDAP9/SAX/d0UJ/3ZOGv/v07D////y////+/////z////+//// + /v////7////+/////P////7////+/////v////7////////////9/////f////3////9//////////// + //////////////////////////////////////////////////////////////////////////////// + /v/+/v7//f////3//////v3/9+nT/21BDP9/RwD/fkYA/3xGAP98RQL/ekYA/35FAP98RgD/fEUC/3pF + Av96RQL/ekYA/35FAP98RgD/fEUC/3pGAP9+RQD/fkYA/35GAP91RAb/cU4i//Ldwv////j//v7+//// + ///////////+/////v/9////+/////////////7//f////////////7////7////+//YyLH/dUoX/3pG + AP99RAD/fkYA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/e0QA/3JDBf9lQBT////l////+f/6/v////7///////////7///////3////9///////8//// + /P///////f////////////////////////////////////////////////////////////////////// + //////////////////////////////3////8/v///v7+//////////7////8/////P////f////x/9S8 + nv91Tx//eEcJ/3tBAP+FSQD/f0cA/3tFAP95RAD/hE0E/4JHAP9zOwD/b0IJ/4BgNf//9Nr////0//// + +/////7///76////+/////z/+/78//3+///9/v////7///////////////////////////////////// + ///7/v///f////////////z////7////+/////z////+//z+///7////+/////z+/v////v////4///8 + 7////+r/t5du/25ED/90RQj/d0MB/31HAP+BSgH/d0AA/3tGA/95QwL/e0UG/3U/Av92SBL/yqmC///6 + 4/////n/+/39//////////7////+/////v////z////8/////P////z////+/////v////////////3/ + ///9/////f////////////////////////////////////////////////////////////////////// + ///////////////////////////+//7+/v/9/////f/////+/f/36dP/bUEM/39HAP9+RgD/fEYA/3xF + Av96RgD/fkUA/3xGAP98RQL/ekUC/3pFAv96RgD/fkUA/3xGAP98RQL/ekYA/35FAP9+RgD/fkYA/3VE + Bv9xTiL/8t3C////+P/+/v7///////////////7////+//3////7/////////////v/9//////////// + /v////v////7/9jIsf91Shf/ekYA/31EAP9+RgD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP97RAD/ckMF/2VAFP///+X////5//r+/////v////////// + /v///////f////3///////z////8///////9//////////////////////////////////////////// + ///////////////////////////////////////////////////////////+///////8/v///P7///// + /v////z////+////+//+9+7////u/7ibdv9oPgn/gEsI/3xCAP9/SAP/eEQA/3pEAP+BSgH/e0EA/4JH + Af9/TA3/ZT4K/8KohP///+7////1/////P////7///38//z9+/////7//f////z+//////////////// + //////////////////////////////v////9///////+/////P////v////8/////v//////+/7///v+ + ///4+//////////++f////X////x/+nQsP94Thn/d0QF/3ZHCf90RAT/fEYA/35HAP97RAD/fEYF/3hD + BP94RAj/bj8J/5l0SP//89r////3/////v/7/////f/////////////////+/////P////z////+//// + /v/////////////+/////v////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////7//v7+//3////9//////79//fp + 0/9tQQz/f0cA/35GAP98RgD/fEUC/3pGAP9+RQD/fEYA/3xFAv96RQL/ekUC/3pGAP9+RQD/fEYA/3xF + Av96RgD/fkUA/35GAP9+RgD/dUQG/3FOIv/y3cL////4//7+/v///////////////v////7//f////v/ + ///////////+//3////////////+////+/////v/2Mix/3VKF/96RgD/fUQA/35GAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3tEAP9yQwX/ZUAU//// + 5f////n/+v7////+///////////+///////9/////f///////P////z///////3///////////////// + //////////////////////////////////////////////////////////////////////////////// + /v////z////8//3////9/////////////v/////////+/////v////b//+zT/45uRf9vQgn/dEAA/31I + Bf96RQL/fEUA/3hCAP+ARgD/hE0E/3dAAP91RQv/dVEj///mxv////H//Pnx/////v/9/////Pz8//// + //////7//f78////////////////////////////////////////////+/////3///////7////8//// + +/////z////+//3////7/v//+v7///f6/v/////////5///+8P///+r/nYBb/3NDA/99RgD/ckAA/3lJ + Cf95RgD/d0EA/4BKA/98RQL/d0ID/3xLE/9vRhn/99u8////9f///Pv//f////r+///7/v///f/////+ + ///////////+/////v////7////+//////////////7////+///////////+/////v////7///////// + //////////////////////////////////////////////////////////////////////////////// + /v/+/v7//f////3//////v3/9+nT/21BDP9/RwD/fkYA/3xGAP98RQL/ekYA/35FAP98RgD/fEUC/3pF + Av96RQL/ekYA/35FAP98RgD/fEUC/3pGAP9+RQD/fkYA/35GAP91RAb/cU4i//Ldwv////j//v7+//// + ///////////+/////v/9////+/////////////7//f////////////7////7////+//YyLH/dUoX/3pG + AP99RAD/fkYA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/e0QA/3JDBf9lQBT////l////+f/6/v////7///////////7///////3////9///////8//// + /P///////f////////////////////////////////////////////////////////////////////// + ///////////////////////////+////+/////v///////3////9/////f////3////9//////7///// + +/////D/5Myu/2xIGv9yRQz/dkIA/3xFAP98RQL/e0QB/39JAv96RQD/fEQA/3hCAf9rPQf/sI1l//// + 6/////X//P7+//v+///8+//////////89/////v////+//////////////////////////////////// + ///9/////f///////v////z////7/////P//////+/////r+///6/v//+v3//////v////j////u/9K8 + o/9tSyD/f0sF/4FGAP96RAD/e0kH/3RGBv90QgD/hEoC/39EAP96QgH/bD0J/7+ggf////L////7//// + ///2+Pn/+/7///v+///7/v///f7////+//////////////////////////7////+/////v////7///// + //////7////+/////v////////////////////////////////////////////////////////////// + ///////////////////////////+//7+/v/9/////f/////+/f/36dP/bUEM/39HAP9+RgD/fEYA/3xF + Av96RgD/fkUA/3xGAP98RQL/ekUC/3pFAv96RgD/fkUA/3xGAP98RQL/ekYA/35FAP9+RgD/fkYA/3VE + Bv9xTiL/8t3C////+P/+/v7///////////////7////+//3////7/////////////v/9//////////// + /v////v////7/9jIsf91Shf/ekYA/31EAP9+RgD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP97RAD/ckMF/2VAFP///+X////5//r+/////v////////// + /v///////f////3///////z////8///////9//////////////////////////////////////////// + //////////////////////////////////////////////////////7////8////+/////z///////v+ + ///5/f//9/3///r////4+Pj////7////+P//++j/tZx8/2xGFv95RQP/fUIA/3xCAP+BSwr/bz4A/35M + BP9/RQD/gEUA/3tFCP9zSRr/4s6v////9f/5/f7/+P3///f5/////v////72////+P////z///////// + //////////////////////////////3///////7////+/////P////z////8/////v/9////+v3///v+ + ///9/v///vv3////9P///+3/i29N/2hADP98RQD/gkUA/4ZPBv91QQD/dkUH/3tICf+CRwD/f0UA/3RC + Bv+KZTn///Lf////+/////z//fv6///////6/P3/+/7///v+///9/v////7///////////////////// + /////v////7////+/////////////////v////7////+//////////////////////////////////// + //////////////////////////////////////////////////////7//v7+//3////9//////79//fp + 0/9tQQz/f0cA/35GAP98RgD/fEUC/3pGAP9+RQD/fEYA/3xFAv96RQL/ekUC/3pGAP9+RQD/fEYA/3xF + Av96RgD/fkUA/35GAP9+RgD/dUQG/3FOIv/y3cL////4//7+/v///////////////v////7//f////v/ + ///////////+//3////////////+////+/////v/2Mix/3VKF/96RgD/fUQA/35GAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3tEAP9yQwX/ZUAU//// + 5f////n/+v7////+///////////+///////9/////f///////P////z///////3///////////////// + //////////////////////////////////////////////////////////////////////////////// + /v////v////6////+/////7//f////n+///3/f//+v7//////////Pj////7////9f//79b/eVgx/3FB + B/9/SAX/fkcE/3ZBAP94RwP/ekcB/3xFAP9/RAD/eUAC/3FCDv+bflf////n////+f/6/v///fv////+ + //////r////5/////v///////////////////////////////////////f/+/////v///v////7///// + /v////z//f/8/////v///f////z////+//////v////w/9O9mv9tQg//fUcI/4FIAP+BRwD/fEQA/39I + Bf97RQb/ekIB/4JGAP96RAP/aEQU/93IrP///vb/+///////+/////n////6/////v///////f/////+ + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /v/+/v7//f////3//////v3/9+nT/21BDP9/RwD/fkYA/3xGAP98RQL/ekYA/35FAP98RgD/fEUC/3pF + Av96RQL/ekYA/35FAP98RgD/fEUC/3pGAP9+RQD/fkYA/35GAP91RAb/cU4i//Ldwv////j//v7+//// + ///////////+/////v/9////+/////////////7//f////////////7////7////+//YyLH/dUoX/3pG + AP99RAD/fkYA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/e0QA/3JDBf9lQBT////l////+f/6/v////7///////////7///////3////9///////8//// + /P///////f////////////////////////////////////////////////////////////////////// + ///////////////////////////+/////P////v////7////+/////z////+//3////7/////f////// + /////fr////3////7v/UtZT/cEca/20+Bv94RAH/fEYA/3lCAP97RAD/fkkA/3tHAP90QQP/ckMN/3ZO + Gv/qzab////x////+v//+vr///7///b5/f/6/////f////////////////////////////////////// + ///9//z////+///+/////f///////////v/9//z////8///9/////f////r7////9////+j/iG1B/3ZE + CP+ARQD/fkUA/35HAP99RAD/fEUC/31DAv+GTAv/ekAA/3FCCv+ghWD/8+rW//v//P/1/f3//Pv3//// + +f////v///z5/////v////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////+//7+/v/9/////f/////+/f/36dP/bUEM/39HAP9+RgD/fEYA/3xF + Av96RgD/fkUA/3xGAP98RQL/ekUC/3pFAv96RgD/fkUA/3xGAP98RQL/ekYA/35FAP9+RgD/fkYA/3VE + Bv9xTiL/8t3C////+P/+/v7///////////////7////+//3////7/////////////v/9//////////// + /v////v////7/9jIsf91Shf/ekYA/31EAP9+RgD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP97RAD/ckMF/2VAFP///+X////5//r+/////v////////// + /v///////f////3///////z////8///////9//////////////////////////////////////////// + ///////////////////////////////////////////////////////////+/////P////v////5//// + +/////v////+//3////4+////f///////v////j///7t///64P+Pb0v/a0MS/3REAv98RgD/gUoH/3hB + AP95QwD/fUkC/3A/Af92Rgz/dUUL/6Z+Tv///+r////0///++v/++Pn/+v7///b8///9//////////// + //////////////////////////////3//P////7///7////+///////////+//3//P/9//7///7////+ + //////7///3v/9rIqf9gPxH/dUMH/35DAP+ARgD/fkcA/3pFAv95QwL/fEQD/3dBAv95Rw3/dk4e/+zX + uP////H//f/8//r////9//////38///9+v////z////+//////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////7//v7+//3////9//////79//fp + 0/9tQQz/f0cA/35GAP98RgD/fEUC/3pGAP9+RQD/fEYA/3xFAv96RQL/ekUC/3pGAP9+RQD/fEYA/3xF + Av96RgD/fkUA/35GAP9+RgD/dUQG/3FOIv/y3cL////4//7+/v///////////////v////7//f////v/ + ///////////+//3////////////+////+/////v/2Mix/3VKF/96RgD/fUQA/35GAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3tEAP9yQwX/ZUAU//// + 5f////n/+v7////+///////////+///////9/////f///////P////z///////3///////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////+/////P////v////8/////P//////+/////r+///5/P///v7+////+/////H////t/+HJ + q/9qSRz/eksN/3U+AP97RwH/fUkD/3tDAP97RQD/e0cF/3ZDBP90QQL/c0kU/+fOrv///+/////7//78 + /P/9/v//+/7///3//////////////////////////////////////////f/8/////v///v////7///// + //////7//f/+//v////9/v///fr8////+f//+uf/jHNL/2dDDf93RAb/fEMA/31GAP+BSwT/e0YD/3hC + Af9+RgX/cT0B/2xDEv+rjmn///3o////9//+/vj/+/////r////4+/////v8/////v////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /v/+/v7//f////3//////v3/9+nT/21BDP9/RwD/fkYA/3xGAP98RQL/ekYA/35FAP98RgD/fEUC/3pF + Av96RQL/ekYA/35FAP98RgD/fEUC/3pGAP9+RQD/fkYA/35GAP91RAb/cU4i//Ldwv////j//v7+//// + ///////////+/////v/9////+/////////////7//f////////////7////7////+//YyLH/dUoX/3pG + AP99RAD/fkYA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/e0QA/3JDBf9lQBT////l////+f/6/v////7///////////7///////3////9///////8//// + /P///////f////////////////////////////////////////////////////////////////////// + ///////////////////////////////+///////////+/////v////z////+///////7/v//+v7///n9 + ///3+v7////+////+P//+ef////t/5l+Wf9wQwr/eUQB/3hFAP98SAH/gEcC/3o/AP+ASQT/eEQA/3dD + AP90Rw7/mXhR////6v////n//f////z8/P////////////////////////////////////////////// + ///9//7//f/////+/////f///////////v/9//7/+/////r9/////v////3z/+nUuP9oRxb/bkIF/3pG + BP98RQD/eEIA/4FNBv93QwD/d0MB/3tFBP92Rw//bEsk//jky////vD////5////+//5+/v/9f3///j9 + /////v////v6//////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////+//7+/v/9/////f/////+/f/36dP/bUEM/39HAP9+RgD/fEYA/3xF + Av96RgD/fkUA/3xGAP98RQL/ekUC/3pFAv96RgD/fkUA/3xGAP98RQL/ekYA/35FAP9+RgD/fkYA/3VE + Bv9xTiL/8t3C////+P/+/v7///////////////7////+//3////7/////////////v/9//////////// + /v////v////7/9jIsf91Shf/ekYA/31EAP9+RgD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP97RAD/ckMF/2VAFP///+X////5//r+/////v////////// + /v///////f////3///////z////8///////9//////////////////////////////////////////// + /////////////////////////////////////////////////////v////7////+/////v////7///// + /v////7///////v+///3+///+P7///j+///3+/z////7////9////u3/7Ne7/21FFf97SAr/gE0H/3I+ + AP+CRwL/gUQA/3xCAP9/SgH/ekYA/3VGCP9xSBv//eLH///88f/6//3////8///++v////////////// + //////////////////////////////3//v/9/////f7////+///////////+//3////7////+fz////+ + /////+//n4Ng/2tCC/93RQP/d0IA/3xHBP96RgD/ekYA/3VAAP98SAb/d0QG/2c8C/+wmHz////z//// + +P////z////7//z8/P/2/f//9vz////+/////fz///////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////7//v7+//3////9//////79//fp + 0/9tQQz/f0cA/35GAP98RgD/fEUC/3pGAP9+RQD/fEYA/3xFAv96RQL/ekUC/3pGAP9+RQD/fEYA/3xF + Av96RgD/fkUA/35GAP9+RgD/dUQG/3FOIv/y3cL////4//7+/v///////////////v////7//f////v/ + ///////////+//3////////////+////+/////v/2Mix/3VKF/96RgD/fUQA/35GAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3tEAP9yQwX/ZUAU//// + 5f////n/+v7////+///////////+///////9/////f///////P////z///////3///////////////// + ///////////////////////////////////////////////////////////////////////////////+ + /////v////7////9/////v////7//////v///////f////n9///4/v//+P7///X8///5/vz////7//z7 + 8f///+3/rYlj/2Q2AP95SAT/e0YA/39CAP+GSQX/fEMA/35HAP98RgD/c0AB/3FCDv+1lXH////y//3/ + +/////v///36/////v/////////////////////////////////////////+//3////7/v///f3///// + //////7//f////3////8/f/////7//Hbwv9sSR3/d0cH/4FLBP94QQD/e0YD/3xIBf93RAD/eEIA/31J + Bv9xQwn/c1Al//zr2P//+vP////8//78+/////z///////j9///y+f///fz///////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /v/+/v7//f////3//////v3/9+nT/21BDP9/RwD/fkYA/3xGAP98RQL/ekYA/35FAP98RgD/fEUC/3pF + Av96RQL/ekYA/35FAP98RgD/fEUC/3pGAP9+RQD/fkYA/35GAP91RAb/cU4i//Ldwv////j//v7+//// + ///////////+/////v/9////+/////////////7//f////////////7////7////+//YyLH/dUoX/3pG + AP99RAD/fkYA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/e0QA/3JDBf9lQBT////l////+f/6/v////7///////////7///////3////9///////8//// + /P///////f////////////////////////////////////////////////////////////////////// + //////////////////////////7///3+/////v////3//////////v/////+/////////v//+/7///f7 + ///4/v//+P////r////1+vj////8////8//13ML/b0gc/3BAAP+FTgX/gEMA/4JGAP+ESgL/ekMA/3pG + AP93QwH/eUUJ/3hRJP/16NL////4////+/////z////+//////////////////////////////////// + //////7//f////v+///7/v////7///////////////////////////f/rJNz/2xEEP9+SgT/fEIA/39I + A/93QwH/dEMA/35LBf+ASQD/d0MA/2pAC/+rj2z///3x/////v///f3///79/////v/8+vr/+/7///r9 + ///9/v////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////+//7+/v/9/////f/////+/f/36dP/bUEM/39HAP9+RgD/fEYA/3xF + Av96RgD/fkUA/3xGAP98RQL/ekUC/3pFAv96RgD/fkUA/3xGAP98RQL/ekYA/35FAP9+RgD/fkYA/3VE + Bv9xTiL/8t3C////+P/+/v7///////////////7////+//3////7/////////////v/9//////////// + /v////v////7/9jIsf91Shf/ekYA/31EAP9+RgD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP97RAD/ckMF/2VAFP///+X////5//r+/////v////////// + /v///////f////3///////z////8///////9//////////////////////////////////////////// + /////////////////////////////////////////////////////v///f7///3+/////v////////// + /v////7////+///////8/v//+/7///j9///6////+/////r+///6/Pz////5///66v+ihGH/dkcK/3pC + AP+DSAP/dzwA/4dMBv97RQD/eUUC/3dDAf97RgP/bUEL/8SvkP//++z////5/////v////////////// + /////////////////////////////////v//////9vv+//r+///9/////f39/////////fz////5///1 + 4v95WTD/dUcN/35EAP+ESAD/ekMA/3tHBP91QwH/e0cB/4BHAP94RAH/cEwe//fixv///PP///////// + /////////////////////v////7////+/////v////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////7//v7+//3////9//////79//fp + 0/9tQQz/f0cA/35GAP98RgD/fEUC/3pGAP9+RQD/fEYA/3xFAv96RQL/ekUC/3pGAP9+RQD/fEYA/3xF + Av96RgD/fkUA/35GAP9+RgD/dUQG/3FOIv/y3cL////4//7+/v///////////////v////7//f////v/ + ///////////+//3////////////+////+/////v/2Mix/3VKF/96RgD/fUQA/35GAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3tEAP9yQwX/ZUAU//// + 5f////n/+v7////+///////////+///////9/////f///////P////z///////3///////////////// + //////////////////////////////////////////////////////////////////////////////3/ + ///7////+/////3////////////+/////P////z////+/////v///////f////3////9/////f/////+ + //////7////5//Dawf9wQQ3/f0UD/3xFAP97RAD/fUYD/3pEA/91QgT/eUYH/3lDAP91Rgj/jW5H///x + 3P////n//P7+///////////////////////////////////////////////+///////6////+v////n8 + ///7/f7/////////+/////T/0byg/3NNHf94RQf/gEUA/4RIAP97RQD/eUUC/3pGBP94QwD/gEkA/3ND + A/+dgFn///rk////+v///////////////////v////7//////v////7///////3///////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /v/+/v7//f////3//////v3/9+nT/21BDP9/RwD/fkYA/3xGAP98RQL/ekYA/35FAP98RgD/fEUC/3pF + Av96RQL/ekYA/35FAP98RgD/fEUC/3pGAP9+RQD/fkYA/35GAP91RAb/cU4i//Ldwv////j//v7+//// + ///////////+/////v/9////+/////////////7//f////////////7////7////+//YyLH/dUoX/3pG + AP99RAD/fkYA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/e0QA/3JDBf9lQBT////l////+f/6/v////7///////////7///////3////9///////8//// + /P///////f////////////////////////////////////////////////////////////////////// + /////////////////////////f////v////6////+/////3//v////7////8/////P////z////+//// + /v////////7////+/////v////7////+//////////Xl/6N6Tf93QQT/dkIA/3tHBP96RAP/ekUG/3RC + Bv93RAX/gEsC/3ZCAP9yShr/5Myw////9//6/Pz///////////////////////////////////////// + /////v3///////v////2/f//+v7///v+/////v/////3////7f+Tdk//bkIM/3lDAv+ARAD/hEYA/31H + AP94RAH/e0cF/3M9AP9/Sgf/dksS/93Gpv////T////7///////////////////+/////v/////8//// + +////////f////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////+//7+/v/9/////f/////+/f/36dP/bUEM/39HAP9+RgD/fEYA/3xF + Av96RgD/fkUA/3xGAP98RQL/ekUC/3pFAv96RgD/fkUA/3xGAP98RQL/ekYA/35FAP9+RgD/fkYA/3VE + Bv9xTiL/8t3C////+P/+/v7///////////////7////+//3////7/////////////v/9//////////// + /v////v////7/9jIsf91Shf/ekYA/31EAP9+RgD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP97RAD/ckMF/2VAFP///+X////5//r+/////v////////// + /v///////f////3///////z////8///////9//////////////////////////////////////////// + ///////////////////////////////////////////////////9////+/////r////7/////f/+//// + /v////7////8/////P////z////+/////v///v////7////+/////v////7///r+//////j/4b6c/3VG + EP9yRAT/d0gE/3hDBP93RAb/d0cN/249AP98SAD/fEgB/2s8Bv+ti2f////0/////v////////////// + /////////////////////////////////v///fz/+v/+//b9///4/v//+/7////8+/////T//+/N/3JP + Hf9vQAL/fUYD/35DAP+ARQD/f0gD/3lFAP98RwT/dD8A/3RFCP+VcUH///nf////9v////z//f39//// + //////////7////+//////v////7/////v/7//////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////7//v7+//3////9//////79//fp + 0/9tQQz/f0cA/35GAP98RgD/fEUC/3pGAP9+RQD/fEYA/3xFAv96RQL/ekUC/3pGAP9+RQD/fEYA/3xF + Av96RgD/fkUA/35GAP9+RgD/dUQG/3FOIv/y3cL////4//7+/v///////////////v////7//f////v/ + ///////////+//3////////////+////+/////v/2Mix/3VKF/96RgD/fUQA/35GAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3tEAP9yQwX/ZUAU//// + 5f////n/+v7////+///////////+///////9/////f///////P////z///////3///////////////// + //////////////////////////////////////////////////////////////////////////////3/ + ///7////+/////v//v/9//7//f/+/////v////7////8/////P////z////+/////v///v////7////+ + /////v//+v7//////P//79X/jGU5/3JGC/90RAL/eEME/3hCBf93RQn/c0AB/3ZBAP+ASwL/fUcK/3xV + Kf/87dr////7/////v/////////////////////////////////////////8///+/f/8//3/9/////b9 + ///6/P////r6////7//ZuY7/bUQG/3dDAP+CSQT/fEIB/3xEA/99SQP/eUUA/39GAf94RQf/Zj0M/8qw + jP////D//v3z/////P////////7////+/////v//////////+/////v////+//v///////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /v/+/v7//f////3//////v3/9+nT/21BDP9/RwD/fkYA/3xGAP98RQL/ekYA/35FAP98RgD/fEUC/3pF + Av96RQL/ekYA/35FAP98RgD/fEUC/3pGAP9+RQD/fkYA/35GAP91RAb/cU4i//Ldwv////j//v7+//// + ///////////+/////v/9////+/////////////7//f////////////7////7////+//YyLH/dUoX/3pG + AP99RAD/fkYA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/e0QA/3JDBf9lQBT////l////+f/6/v////7///////////7///////3////9///////8//// + /P///////f////////////////////////////////////////////////////////////////////// + //////////////////////////////3////9/////f////3////9/////f////////////7////+//// + /v////z////8/////v////7////////+///7/v///fz4////8v+6n33/aEAL/3VFBf97RQT/e0UE/3Q/ + AP+ATAr/e0UA/3xFAP+ARgT/cEQP/8+5nf////T////8//////////////////////////////////// + /////vv////8//3//P/4////8vv///j7/////v7////p/555Rf9yQwD/e0UA/4JJBP96Qwb/eUMG/3tG + A/97RQD/f0QA/3pGCv9wTSX/+eXM////8f////n////8///////9/v////7////+/////v/////8//// + /P/9//z/+//+//////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////+//7+/v/9/////f/////+/f/36dP/bUEM/39HAP9+RgD/fEYA/3xF + Av96RgD/fkUA/3xGAP98RQL/ekUC/3pFAv96RgD/fkUA/3xGAP98RQL/ekYA/35FAP9+RgD/fkYA/3VE + Bv9xTiL/8t3C////+P/+/v7///////////////7////+//3////7/////////////v/9//////////// + /v////v////7/9jIsf91Shf/ekYA/31EAP9+RgD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP97RAD/ckMF/2VAFP///+X////5//r+/////v////////// + /v///////f////3///////z////8///////9//////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////f////3/ + ///9/////f/////////////////+/////P////z////+/////v///////f////39/f////z////4/+bW + v/9xSxv/eEUG/3pDAP9/RwD/eUIA/4BJBP+ARwL/fUUA/3tAAP94SA7/k3dU////8f////v///////// + ///////////////////////////////8+f////z//v/7//j////z/P//+vz//////P/64sr/eFAW/3hF + AP+BSAD/fUQA/3xFDP93Qgn/eUQB/35HAP9/QwD/dUIK/6OHaP///+7///zx////+/////z//P7+//v+ + ///9/f////7////+///////////+//3//v/7//7///////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////7//v7+//3////9//////79//fp + 0/9tQQz/f0cA/35GAP98RgD/fEUC/3pGAP9+RQD/fEYA/3xFAv96RQL/ekUC/3pGAP9+RQD/fEYA/3xF + Av96RgD/fkUA/35GAP9+RgD/dUQG/3FOIv/y3cL////4//7+/v///////////////v////7//f////v/ + ///////////+//3////////////+////+/////v/2Mix/3VKF/96RgD/fUQA/35GAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3tEAP9yQwX/ZUAU//// + 5f////n/+v7////+///////////+///////9/////f///////P////z///////3///////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////+///9/v///f7///v+///7/v///f////3///////7////8/////P////7//f/+//v/ + ///9//7///75////+//9//7///jp/6F+Uv96RAf/ekIA/4BGAP+BSAD/fEEA/39FA/+BSAP/fUMA/3hI + CP9uSyP///Hb////+f////////////////////////////////////////36/////P/4/Pf/+v////T7 + ///9/f////ry/9a6m/9vQwb/fEgA/4NKAP94QAD/fUcL/3ZCBv94RAD/gUkC/39FA/9uPwv/3MWr//// + 9/////n////8//3//v/9////+/7///39/////v////7////+///9/////f/+//3//P////7///////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /v/+/v7//f////3//////v3/9+nT/21BDP9/RwD/fkYA/3xGAP98RQL/ekYA/35FAP98RgD/fEUC/3pF + Av96RQL/ekYA/35FAP98RgD/fEUC/3pGAP9+RQD/fkYA/35GAP91RAb/cU4i//Ldwv////j//v7+//// + ///////////+/////v/9////+/////////////7//f////////////7////7////+//YyLH/dUoX/3pG + AP99RAD/fkYA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/e0QA/3JDBf9lQBT////l////+f/6/v////7///////////7///////3////9///////8//// + /P///////f////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////7////+///9/v//+/7///3+///9/////f////3/ + //////7////+//3//v/9//7/+////////v////n////6//b7/P////n/1LiZ/3FCDv99RQD/g0gA/39G + AP98RAD/gUcF/3xCAP98RgD/dEIA/2pBEP/fw6T////0/////v////////7////+///////////+//// + /v////z///38//v////7/v//+/7//////P///un/nn9Y/3JFCP98RgD/fkQA/31FAP99Rwb/e0UE/31F + AP98SAL/ckII/3lUKP//+eD////0///+/f/5/f7/+/3+//3//////v////7////+///9/////f7///3/ + //////z////8/////v////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////+//7+/v/9/////f/////+/f/36dP/bUEM/39HAP9+RgD/fEYA/3xF + Av96RgD/fkUA/3xGAP98RQL/ekUC/3pFAv96RgD/fkUA/3xGAP98RQL/ekYA/35FAP9+RgD/fkYA/3VE + Bv9xTiL/8t3C////+P/+/v7///////////////7////+//3////7/////////////v/9//////////// + /v////v////7/9jIsf91Shf/ekYA/31EAP9+RgD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP97RAD/ckMF/2VAFP///+X////5//r+/////v////////// + /v///////f////3///////z////8///////9//////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////7////+ + ///9//////7////////////////////////////////////////9///////+////+P////v/+fz///7/ + /f/26dn/b08r/3hEAv+BRQD/gUkC/3M+AP+ASQb/eUQB/3pGBP9yQgL/d0gL/62JWf///+j////5//38 + /v/9/f////7////////8+/f////5/////P////7/+/7///r9///////////3///r0P99Wi7/c0QH/31H + AP99RQD/fEQA/3xFAP97RAD/fEUA/3pGA/9pQQ3/pIdi////6f////f///////r9///9//////////// + /v////7//f////v+///7/v///f///////P////z////+//////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////7//v7+//3////9//////79//fp + 0/9tQQz/f0cA/35GAP98RgD/fEUC/3pGAP9+RQD/fEYA/3xFAv96RQL/ekUC/3pGAP9+RQD/fEYA/3xF + Av96RgD/fkUA/35GAP9+RgD/dUQG/3FOIv/y3cL////4//7+/v///////////////v////7//f////v/ + ///////////+//3////////////+////+/////v/2Mix/3VKF/96RgD/fUQA/35GAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3tEAP9yQwX/ZUAU//// + 5f////n/+v7////+///////////+///////9/////f///////P////z///////3///////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////7///32////+//5/P///f////z27/+SfGD/dkUH/4JIAP+ASQT/dUEA/31GA/94QwD/eEcJ/3ZF + B/93QwH/j2Yv///52v////X///////z8///+/f//////////+f////j////8///9/P/7/v//+v////// + //////X/4cmt/2dDFf9zQgT/gEgB/35GAP98RAD/e0QA/3tEAP9+QwD/ekUG/2dBEf/ix6X////w//// + 9///////+fz///z+///////////+/////v///v///f////v+///9///////+/////P////7///////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /v/+/v7//f////3//////v3/9+nT/21BDP9/RwD/fkYA/3xGAP98RQL/ekYA/35FAP98RgD/fEUC/3pF + Av96RQL/ekYA/35FAP98RgD/fEUC/3pGAP9+RQD/fkYA/35GAP91RAb/cU4i//Ldwv////j//v7+//// + ///////////+/////v/9////+/////////////7//f////////////7////7////+//YyLH/dUoX/3pG + AP99RAD/fkYA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/e0QA/3JDBf9lQBT////l////+f/6/v////7///////////7///////3////9///////8//// + /P///////f////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////v////v////7//n8///9///////5/8y3nP9wQgj/f0UA/31I + Bf95RQL/fEUC/3hDAP95Rgf/eUYH/3VAAP9xRg3/79y7////8P////7//v3////+///////////7//// + +f////z//vz7//r9///6///////8///+8P+1mXr/bEIT/3ZAA/+ASAH/f0gA/3tGAP97RwD/fUYB/4BF + AP93Qwf/c1Al///x1f////L///73//v9/v/7/v//+/3+/////v////z////8///////9/////f7///3/ + //////7////+//////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////+//7+/v/9/////f/////+/f/36dP/bUEM/39HAP9+RgD/fEYA/3xF + Av96RgD/fkUA/3xGAP98RQL/ekUC/3pFAv96RgD/fkUA/3xGAP98RQL/ekYA/35FAP9+RgD/fkYA/3VE + Bv9xTiL/8t3C////+P/+/v7///////////////7////+//3////7/////////////v/9//////////// + /v////v////7/9jIsf91Shf/ekYA/31EAP9+RgD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP97RAD/ckMF/2VAFP///+X////5//r+/////v////////// + /v///////f////3///////z////8///////9//////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////+////+/////v/+v3///r9 + //////v/+eXM/3dLFf97RAD/eUQB/3xHBP99RgH/ekUC/3VCA/92QwT/e0YD/21BBv/Bq4f////w//// + /P///v////7///////////z////3///+/v///v//+f7///j///////n///nl/4lpRv9xQg//e0IF/4JH + Af9+RwD/e0cA/3xIAf98SAL/fUQA/3RCCP+WdlL////r////9f////z/+fv8//v+///8/v/////+//// + /P////z///////3////9/////f////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////7//v7+//3////9//////79//fp + 0/9tQQz/f0cA/35GAP98RgD/fEUC/3pGAP9+RQD/fEYA/3xFAv96RQL/ekUC/3pGAP9+RQD/fEYA/3xF + Av96RgD/fkUA/35GAP9+RgD/dUQG/3FOIv/y3cL////4//7+/v///////////////v////7//f////v/ + ///////////+//3////////////+////+/////v/2Mix/3VKF/96RgD/fUQA/35GAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3tEAP9yQwX/ZUAU//// + 5f////n/+v7////+///////////+///////9/////f///////P////z///////3///////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////7////8///+/f/7/v//+fz/////+////+r/kmo5/3pHCP93QwH/e0YD/3xFAP9+RwL/dkIA/3ZC + AP+BSgX/ckUI/5V7Vv///+////75///+/////v///v7+/////P////f///39///+///6////9f77//// + 9//569T/ck4m/3E/C/+BRAb/gkYA/31GAP95RwD/ekkA/3lFAP98QgD/c0MP/8Opi/////H////5//// + /v/6+///+/7///z+/////v3////8/////P////7////////////9//////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /v/+/v7//f////3//////v3/9+nT/21BDP9/RwD/fkYA/3xGAP98RQL/ekYA/35FAP98RgD/fEUC/3pF + Av96RQL/ekYA/35FAP98RgD/fEUC/3pGAP9+RQD/fkYA/35GAP91RAb/cU4i//Ldwv////j//v7+//// + ///////////+/////v/9////+/////////////7//f////////////7////7////+//YyLH/dUoX/3pG + AP99RAD/fkYA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/e0QA/3JDBf9lQBT////l////+f/6/v////7///////////7///////3////9///////8//// + /P///////f////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////fz//v7+//r+///6/f/////7////8P+7mGz/c0UL/3hF + Bv94RAH/ekMA/35HAv96RQL/eUQB/35HAv9yQwb/eFwz///y2////vX////////+///8/v7////8//// + +f//+/3///7///j////3//v////0/9vLrv9sRRn/ekIL/4JEBP+DRQD/fUYA/3pJAP95SAD/dkQA/35F + B/98Th//69S+////9v////z//v7+//3+///6/f///f/////9/P////z////7/////P////7///////// + ///9/////f////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////+//7+/v/9/////f/////+/f/36dP/bUEM/39HAP9+RgD/fEYA/3xF + Av96RgD/fkUA/3xGAP98RQL/ekUC/3pFAv96RgD/fkUA/3xGAP98RQL/ekYA/35FAP9+RgD/fkYA/3VE + Bv9xTiL/8t3C////+P/+/v7///////////////7////+//3////7/////////////v/9//////////// + /v////v////7/9jIsf91Shf/ekYA/31EAP9+RgD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP97RAD/ckMF/2VAFP///+X////5//r+/////v////////// + /v///////f////3///////z////8///////9//////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////+/f//////+v7///r9 + //////v////v/+vMpf9xRxL/dUYJ/3hEAv97RAH/fEUA/3tGA/98RwT/e0QA/3NCBP9rSh3/4c+y//// + 9P///v3///////z+/v////z////7///9/////P3/9v79//r/+////+z/uaWC/2g9DP9+RAn/g0MD/4JE + AP99RgD/ekoA/3dJAP91RAD/gUsP/4RYL//97dz////8//7+/v/6/P3//f////n7/P/////////+//// + /P////z////8/////P////7///////3////9//////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////7//v7+//3////9//////79//fp + 0/9tQQz/f0cA/35GAP98RgD/fEUC/3pGAP9+RQD/fEYA/3xFAv96RQL/ekUC/3pGAP9+RQD/fEYA/3xF + Av96RgD/fkUA/35GAP9+RgD/dUQG/3FOIv/y3cL////4//7+/v///////////////v////7//f////v/ + ///////////+//3////////////+////+/////v/2Mix/3VKF/96RgD/fUQA/35GAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3tEAP9yQwX/ZUAU//// + 5f////n/+v7////+///////////+///////9/////f///////P////z///////3///////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////+///////5/f//+fz//////v////P///XV/3dRIf9wQgj/eUUD/31IBf96QwD/eUQB/35H + Av98RAD/d0cH/2VADv/Fr4z////y////+////////f/////++v////r///v+///+///6/////f/4//// + 7P+KcUn/c0MP/4BCBv+CQgL/g0YC/31JAP93RwD/c0UA/3pMBf9wPwf/n3lW////9f/9/////f////3/ + ///9///////////////////////+/////P////z////8/////v///////f////3///////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /v/+/v7//f////3//////v3/9+nT/21BDP9/RwD/fkYA/3xGAP98RQL/ekYA/35FAP98RgD/fEUC/3pF + Av96RQL/ekYA/35FAP98RgD/fEUC/3pGAP9+RQD/fkYA/35GAP91RAb/cU4i//Ldwv////j//v7+//// + ///////////+/////v/9////+/////////////7//f////////////7////7////+//YyLH/dUoX/3pG + AP99RAD/fkYA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/e0QA/3JDBf9lQBT////l////+f/6/v////7///////////7///////3////9///////8//// + /P///////f////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////f////b5/f/7/v/////+////9////uX/knJJ/25C + DP94RQb/eUQB/39IA/95QgD/eUIA/4JKA/92RAL/bkQP/56BXP////D////4//z9+//9/////Pr5//// + /P///f///vn7//v//v////b////i/3hbL/9yPwf/gUIF/4NDA/9+QQD/e0YA/3xMAP95SAD/dEUB/3FC + D//Jp4n////5//v+///9///////////////////////////////////////+/////P////z////8//// + ///9////+//////+//////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////+//7+/v/9/////f/////+/f/36dP/bUEM/39HAP9+RgD/fEYA/3xF + Av96RgD/fkUA/3xGAP98RQL/ekUC/3pFAv96RgD/fkUA/3xGAP98RQL/ekYA/35FAP9+RgD/fkYA/3VE + Bv9xTiL/8t3C////+P/+/v7///////////////7////+//3////7/////////////v/9//////////// + /v////v////7/9jIsf91Shf/ekYA/31EAP9+RgD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP97RAD/ckMF/2VAFP///+X////5//r+/////v////////// + /v///////f////3///////z////8///////9//////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////39/f/9////+/7///v+ + ///+/Pv////3////8P+xlnT/akAL/3ZDBP95RAH/fkcC/3tEAP97RAD/gEgB/3ZCAP9tQAf/jmxB///3 + 4P////X//f78//3////+/Pv////8///9///9+vz//f/+////9f/76sn/bEsa/3U/A/+DRgT/gkUF/3pB + AP97RgD/fEsA/3pJAP9vQQH/bUMU/+vQtv////z/+v7///3////////////+/////v///////f////3/ + ///////////8/////P////z////+//3////7//////7///////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////7//v7+//3////9//////79//fp + 0/9tQQz/f0cA/35GAP98RgD/fEUC/3pGAP9+RQD/fEYA/3xFAv96RQL/ekUC/3pGAP9+RQD/fEYA/3xF + Av96RgD/fkUA/35GAP9+RgD/dUQG/3FOIv/y3cL////4//7+/v///////////////v////7//f////v/ + ///////////+//3////////////+////+/////v/2Mix/3VKF/96RgD/fUQA/35GAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3tEAP9yQwX/ZUAU//// + 5f////n/+v7////+///////////+///////9/////f///////P////z///////3///////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////P7///3////7/v///f////z8/P////r////0/9W/o/9uRhL/dUID/3lFA/98RQD/fEUA/35G + AP99RgH/eEMA/3ZECP9/WSn/9uXK////9f////z/+//////9/P////7///v////+///+//3////0/93H + o/9vSBT/eUME/4JFAf9/RQT/fEUC/31HAP95RwD/e0gA/3NHCP9zTSP/+eLM/////v/4/v///f////// + /v////z////8///////9////+/7///3///////7////8/////P////7//f////v//////v////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /v/+/v7//f////3//////v3/9+nT/21BDP9/RwD/fkYA/3xGAP98RQL/ekYA/35FAP98RgD/fEUC/3pF + Av96RQL/ekYA/35FAP98RgD/fEUC/3pGAP9+RQD/fkYA/35GAP91RAb/cU4i//Ldwv////j//v7+//// + ///////////+/////v/9////+/////////////7//f////////////7////7////+//YyLH/dUoX/3pG + AP99RAD/fkYA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/e0QA/3JDBf9lQBT////l////+f/6/v////7///////////7///////3////9///////8//// + /P///////f////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////9/////P7///3+///8/v///////////P////j/69nC/3lR + IP90RAT/e0cF/3hDAP97RAD/fUUA/3xFAP98RwT/fEcI/3RMGP/l0bL////0//3//P/6//7///39///+ + /f/8+/////7///38+P////L/wqiA/21EDf98RQL/f0QA/3pCAf97RQT/fkgB/3pFAP98SAH/dkkM/4Vm + P///8+L///////r+///////////7////+/////z///////v+///6/v//+/7//////v////z////7//// + /P/9////+//////+//////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////+//7+/v/9/////f/////+/f/36dP/bUEM/39HAP9+RgD/fEYA/3xF + Av96RgD/fkUA/3xGAP98RQL/ekUC/3pFAv96RgD/fkUA/3xGAP98RQL/ekYA/35FAP9+RgD/fkYA/3VE + Bv9xTiL/8t3C////+P/+/v7///////////////7////+//3////7/////////////v/9//////////// + /v////v////7/9jIsf91Shf/ekYA/31EAP9+RgD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP97RAD/ckMF/2VAFP///+X////5//r+/////v////////// + /v///////f////3///////z////8///////9//////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////7/f3//f////3/ + ///////////+///++v/87dr/hWEz/3JBA/98Rwj/eEMA/3xFAP99RQD/e0QA/31IBf96QgH/bUEL/8q1 + lf////L/+v74//r//v////////3+//3+///6/P3////7////7/+wkmn/aj4D/39GAf+ARgD/eEQC/3dE + Bf98RQD/fkcA/3tFAP9tQQb/nIBd////8P//////+v7//////v////n////5////+//9////+v7///j+ + ///6/v///////////P////v////8//3////7//////7///////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////7//v7+//3////9//////79//fp + 0/9tQQz/f0cA/35GAP98RgD/fEUC/3pGAP9+RQD/fEYA/3xFAv96RQL/ekUC/3pGAP9+RQD/fEYA/3xF + Av96RgD/fkUA/35GAP9+RgD/dUQG/3FOIv/y3cL////4//7+/v///////////////v////7//f////v/ + ///////////+//3////////////+////+/////v/2Mix/3VKF/96RgD/fUQA/35GAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3tEAP9yQwX/ZUAU//// + 5f////n/+v7////+///////////+///////9/////f///////P////z///////3///////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////v7+//7+/v/9///////////+/f///fz/////////8P+ZdUf/cD8B/3lGB/96RQL/fUYB/3xF + AP95RAH/fUYD/3xDAP9wQQn/r5l1////8f/8//r/+////////////v//+/7///z+//////z////t/5h2 + S/9vQAP/f0cA/4FHAP94RgT/dkYG/3pDAP9/RwD/eUIA/2o9BP+4n3/////1///////7/v/////8//// + +f////n////7//3////6/v//+P7///r+///////////8////+/////z//f////v//////v////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /v/+/v7//f////3//////v3/9+nT/21BDP9/RwD/fkYA/3xGAP98RQL/ekYA/35FAP98RgD/fEUC/3pF + Av96RQL/ekYA/35FAP98RgD/fEUC/3pGAP9+RQD/fkYA/35GAP91RAb/cU4i//Ldwv////j//v7+//// + ///////////+/////v/9////+/////////////7//f////////////7////7////+//YyLH/dUoX/3pG + AP99RAD/fkYA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/e0QA/3JDBf9lQBT////l////+f/6/v////7///////////7///////3////9///////8//// + /P///////f////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////9/f3///////////////////38//z8/P/9///////0/7WS + Zv9zQgT/d0QF/3lEAf98RQD/fUYB/3pFAv97RAD/gkcB/3VGCf+Wflr////v//3/+//7//////7+///+ + ///1+v3//f//////+v///On/f1ou/3lICv9/RwD/fUYA/3ZEAv95Rgf/eUIA/39HAP98RQD/ckYQ/9C6 + nv////f///////v///////7////7////+f////z//f////r+///6/v//+v7///////////7////8//// + /v/9/////f////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////+//7+/v/9/////f/////+/f/36dP/bUEM/39HAP9+RgD/fEYA/3xF + Av96RgD/fkUA/3xGAP98RQL/ekUC/3pFAv96RgD/fkUA/3xGAP98RQL/ekYA/35FAP9+RgD/fkYA/3VE + Bv9xTiL/8t3C////+P/+/v7///////////////7////+//3////7/////////////v/9//////////// + /v////v////7/9jIsf91Shf/ekYA/31EAP9+RgD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP97RAD/ckMF/2VAFP///+X////5//r+/////v////////// + /v///////f////3///////z////8///////9//////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////+vz9//// + /////v3///38//////////L/yaqD/3VID/93RAX/d0IA/3pDAP99RgH/e0YD/3pDAP+ARQD/dEIG/4Zq + Qf///+f////7//v////9+/v////+//v+///////////5///23/90TBz/eEUG/3tEAP99RwD/fEcE/3pF + Av99RAD/e0MA/4JLBv9iOAP/69nC///9+P///////f////////////7////+/////v///////f////3/ + ///9//////////////////7///////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////7//v7+//3////9//////79//fp + 0/9tQQz/f0cA/35GAP98RgD/fEUC/3pGAP9+RQD/fEYA/3xFAv96RQL/ekUC/3pGAP9+RQD/fEYA/3xF + Av96RgD/fkUA/35GAP9+RgD/dUQG/3FOIv/y3cL////4//7+/v///////////////v////7//f////v/ + ///////////+//3////////////+////+/////v/2Mix/3VKF/96RgD/fUQA/35GAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3tEAP9yQwX/ZUAU//// + 5f////n/+v7////+///////////+///////9/////f///////P////z///////3///////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////3////7/v///f///////v////z////+////9//jzbH/Yj4Q/3RFCP99RgH/eUIA/3pD + AP98RQD/fUYB/3tEAP93Rgj/c08f////5f///fj/+////////v////v/+v3///7+/v////j//OjP/25G + Ev93QwH/eEMA/3xFAP97RAD/fEUA/4BIAf95QgD/f0oH/3BIFP/46db////+//////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /v/+/v7//f////3//////v3/9+nT/21BDP9/RwD/fkYA/3xGAP98RQL/ekYA/35FAP98RgD/fEUC/3pF + Av96RQL/ekYA/35FAP98RgD/fEUC/3pGAP9+RQD/fkYA/35GAP91RAb/cU4i//Ldwv////j//v7+//// + ///////////+/////v/9////+/////////////7//f////////////7////7////+//YyLH/dUoX/3pG + AP99RAD/fkYA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/e0QA/3JDBf9lQBT////l////+f/6/v////7///////////7///////3////9///////8//// + /P///////f////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////f////v+///7///////+////+/////z////3/+nX + wP9kRh3/dEQK/3xFAP96QwD/fEUA/3xFAP98RQD/eUQB/3VEBv9zSxf///XT///9+P/7/v/////7//// + +f/9///////+////9v/q1r3/aUEN/3hEAv96RQL/fUYB/3tEAP99RgH/gEkE/3hBAP96RQL/flYl///z + 4f////7///////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////+//7+/v/9/////f/////+/f/36dP/bUEM/39HAP9+RgD/fEYA/3xF + Av96RgD/fkUA/3xGAP98RQL/ekUC/3pFAv96RgD/fkUA/3xGAP98RQL/ekYA/35FAP9+RgD/fkYA/3VE + Bv9xTiL/8t3C////+P/+/v7///////////////7////+//3////7/////////////v/9//////////// + /v////v////7/9jIsf91Shf/ekYA/31EAP9+RgD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP97RAD/ckMF/2VAFP///+X////5//r+/////v////////// + /v///////f////3///////z////8///////9//////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////9////+/7///v/ + //////7////7/////P////f/+ObP/3JUK/90RAr/e0QA/3xFAP9+RwL/fUYB/3tEAP97RgP/dUQG/25G + Ev/54L7////6//v+//////v////5///+//////7////4/9rFqv9pPwr/e0YD/35HAv99RgH/fUYB/31G + Af+ASQT/d0IA/3VBAP+LYzL///jm///9/P////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////7//v7+//3////9//////79//fp + 0/9tQQz/f0cA/35GAP98RgD/fEUC/3pGAP9+RQD/fEYA/3xFAv96RQL/ekUC/3pGAP9+RQD/fEYA/3xF + Av96RgD/fkUA/35GAP9+RgD/dUQG/3FOIv/y3cL////4//7+/v///////////////v////7//f////v/ + ///////////+//3////////////+////+/////v/2Mix/3VKF/96RgD/fUQA/35GAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3tEAP9yQwX/ZUAU//// + 5f////n/+v7////+///////////+///////9/////f///////P////z///////3///////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////3////7/v//+////////v////v////8////9///79j/f2A5/3JECv96QwD/fEUA/31G + Af99RgH/fEUA/31GA/91RAb/bkYS/+jNq/////n/+v3//////P////n///39/////P////f/yLOY/2k/ + Cv98RwT/fUYB/3xEAP99RgH/ekMA/3xHBP97RgP/dkME/5p0RP///e3///////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /v/+/v7//f////3//////v3/9+nT/21BDP9/RwD/fkYA/3xGAP98RQL/ekYA/35FAP98RgD/fEUC/3pF + Av96RQL/ekYA/35FAP98RgD/fEUC/3pGAP9+RQD/fkYA/35GAP91RAb/cU4i//Ldwv////j//v7+//// + ///////////+/////v/9////+/////////////7//f////////////7////7////+//YyLH/dUoX/3pG + AP99RAD/fkYA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/e0QA/3JDBf9lQBT////l////+f/6/v////7///////////7///////3////9///////8//// + /P///////f////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////f////v+///7///////+////+/////z////4///z + 3v+Ka0T/ckQK/3pDAP98RQD/fEUA/35GAP98RgD/e0QA/3hFBv9vRxP/2L2b////+f/8/v/////8//// + +f///v3////7////9/+7pYn/bUEL/35KBP9/RgH/fUUA/31GAf96QwD/ekUC/3tHBf94RQf/poJU///+ + 8P/+/v7///////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////+//7+/v/9/////f/////+/f/36dP/bUEM/39HAP9+RgD/fEYA/3xF + Av96RgD/fkUA/3xGAP98RQL/ekUC/3pFAv96RgD/fkUA/3xGAP98RQL/ekYA/35FAP9+RgD/fkYA/3VE + Bv9xTiL/8t3C////+P/+/v7///////////////7////+//3////7/////////////v/9//////////// + /v////v////7/9jIsf91Shf/ekYA/31EAP9+RgD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP97RAD/ckMF/2VAFP///+X////5//r+/////v////////// + /v///////f////3///////z////8///////9//////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////9////+/7///v+ + //////7////8/////v////j///fi/5R1Tv9xQwn/ekMA/31GAf96QwD/fUUA/39HAP96QwD/d0QF/3BF + Ev/MsY/////5//v9/v////z////5/////P////j////1/66YfP9tQQv/fkoE/39GAf9/RwD/fUYB/31G + Af95RAH/d0UD/3VEBv+vjGD///7x//n7/P////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////7//v7+//3////9//////79//fp + 0/9tQQz/f0cA/35GAP98RgD/fEUC/3pGAP9+RQD/fEYA/3xFAv96RQL/ekUC/3pGAP9+RQD/fEYA/3xF + Av96RgD/fkUA/35GAP9+RgD/dUQG/3FOIv/y3cL////4//7+/v///////////////v////7//f////v/ + ///////////+//3////////////+////+/////v/2Mix/3VKF/96RgD/fUQA/35GAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3tEAP9yQwX/ZUAU//// + 5f////n/+v7////+///////////+///////9/////f///////P////z///////3///////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////+///////7/v//+/7//////v////z////+////+P///un/nH9a/3FDCf96QwD/fkcC/3pD + AP99RQD/fkYA/35GAP92RAL/bkQP/8Oohv///fb//f///////P////j////8///89f////P/pI9w/2k9 + B/99RgH/fEQA/39HAP96QwD/fUgF/3hEAv91QgP/dkUH/7mWav////X/+v7////+//////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /v/+/v7//f////3//////v3/9+nT/21BDP9/RwD/fkYA/3xGAP98RQL/ekYA/35FAP98RgD/fEUC/3pF + Av96RQL/ekYA/35FAP98RgD/fEUC/3pGAP9+RQD/fkYA/35GAP91RAb/cU4i//Ldwv////j//v7+//// + ///////////+/////v/9////+/////////////7//f////////////7////7////+//YyLH/dUoX/3pG + AP99RAD/fkYA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/e0QA/3JDBf9lQBT////l////+f/6/v////7///////////7///////3////9///////8//// + /P///////f////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////7///////v+///7/v/////+/////P////7////5//// + 8P+ihWD/cUMJ/3pDAP9/SAP/e0QA/31FAP99RQD/gUkC/3lFA/9tQw7/waWC///99P/9///////8///+ + 9/////v////4////9P+hiWv/b0EL/35HAv99RQD/fkYA/3xFAP96RQL/eUUD/3hFBv91RAb/wp9z//// + 9f/7//////7///////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////+//7+/v/9/////f/////+/f/36dP/bUEM/39HAP9+RgD/fEYA/3xF + Av96RgD/fkUA/3xGAP98RQL/ekUC/3pFAv96RgD/fkUA/3xGAP98RQL/ekYA/35FAP9+RgD/fkYA/3VE + Bv9xTiL/8t3C////+P/+/v7///////////////7////+//3////7/////////////v/9//////////// + /v////v////7/9jIsf91Shf/ekYA/31EAP9+RgD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP97RAD/ckMF/2VAFP///+X////5//r+/////v////////// + /v///////f////3///////z////8///////9//////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////v//////+/7///v+ + //////7////8/////v////n////u/6iLZv9xRAv/eEMA/31GAf97RAD/f0cA/39HAP9/RwD/d0MB/21D + Dv+3m3j///71//3//////vn////4////+/////j////0/6GJa/9vQgn/fkcC/31FAP98RgD/fEUC/3pF + Av95RQP/eEUG/3VEBv/Cn3P////1//v//////v////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////7//v7+//3////9//////79//fp + 0/9tQQz/f0cA/35GAP98RgD/fEUC/3pGAP9+RQD/fEYA/3xFAv96RQL/ekUC/3pGAP9+RQD/fEYA/3xF + Av96RgD/fkUA/35GAP9+RgD/dUQG/3FOIv/y3cL////4//7+/v///////////////v////7//f////v/ + ///////////+//3////////////+////+/////v/2Mix/3VKF/96RgD/fUQA/35GAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3tEAP9yQwX/ZUAU//// + 5f////n/+v7////+///////////+///////9/////f///////P////z///////3///////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////+///////7/v//+/7//////v////7/////////+f////D/spVw/3JFDP96RQL/fUYB/3tE + AP9+RgD/fkYA/39HAP94RAL/bUEM/66Sb///+/L/////////+v////j////7////+P////T/oYlr/29C + Cf9+RwL/fUUA/3xGAP98RQL/ekUC/3lFA/94RQb/dUQG/8Kfc/////X/+//////+//////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /v/+/v7//f////3//////v3/9+nT/21BDP9/RwD/fkYA/3xGAP98RQL/ekYA/35FAP98RgD/fEUC/3pF + Av96RQL/ekYA/35FAP98RgD/fEUC/3pGAP9+RQD/fkYA/35GAP91RAb/cU4i//Ldwv////j//v7+//// + ///////////+/////v/9////+/////////////7//f////////////7////7////+//YyLH/dUoX/3pG + AP99RAD/fkYA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/e0QA/3JDBf9lQBT////l////+f/6/v////7///////////7///////3////9///////8//// + /P///////f////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////7///////v+///7/v/////+/////v/////////7//// + 8f+6nnv/cEMK/3pFAv99RgH/fEUA/35GAP9+RgD/gEYA/3lFAv9sQAr/popn///99P/////////6//// + +P////v////4////9P+hiWv/b0IJ/35HAv99RQD/fkYA/3xFAP96RQL/eUUD/3hFBv91RAb/wp9z//// + 9f/7//////7///////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////+//7+/v/9/////f/////+/f/36dP/bUEM/39HAP9+RgD/fEYA/3xF + Av96RgD/fkUA/3xGAP98RQL/ekUC/3pFAv96RgD/fkUA/3xGAP98RQL/ekYA/35FAP9+RgD/fkYA/3VE + Bv9xTiL/8t3C////+P/+/v7///////////////7////+//3////7/////////////v/9//////////// + /v////v////7/9jIsf91Shf/ekYA/31EAP9+RgD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP97RAD/ckMF/2VAFP///+X////5//r+/////v////////// + /v///////f////3///////z////8///////9//////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////v//////+/7///v+ + //////7////+//////////v////x/7+jgP9uQQj/ekUC/3xFAv98RQD/f0cA/35GAP9/RQD/e0YD/25C + DP+miWT////2//////////v////4/////P////n////1/6GJa/9vQgn/fkcC/31FAP9+RgD/fEUA/3pF + Av95RQP/eEUG/3VEBv/Cn3P////1//v//////v////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////7//v7+//3////9//////79//fp + 0/9tQQz/f0cA/35GAP98RgD/fEUC/3pGAP9+RQD/fEYA/3xFAv96RQL/ekUC/3pGAP9+RQD/fEYA/3xF + Av96RgD/fkUA/35GAP9+RgD/dUQG/3FOIv/y3cL////4//7+/v///////////////v////7//f////v/ + ///////////+//3////////////+////+/////v/2Mix/3VKF/96RgD/fUQA/35GAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3tEAP9yQwX/ZUAU//// + 5f////n/+v7////+///////////+///////9/////f///////P////z///////3///////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////+///////7/v//+/7///////////7/////////+/////H/v6OA/2xACv95RQL/ekUC/3xF + AP9/RwD/fkYA/39FAP97RgP/bkIM/6aJZP////b/////////+/////j////8////+f////X/n4lt/21B + C/9+RwL/fUUA/35GAP98RQD/ekYA/3pEA/94RQb/dUQG/8Kfc/////X/+//////+//////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /v/+/v7//f////3//////v3/9+nT/21BDP9/RwD/fkYA/3xGAP98RQL/ekYA/35FAP98RgD/fEUC/3pF + Av96RQL/ekYA/35FAP98RgD/fEUC/3pGAP9+RQD/fkYA/35GAP91RAb/cU4i//Ldwv////j//v7+//// + ///////////+/////v/9////+/////////////7//f////////////7////7////+//YyLH/dUoX/3pG + AP99RAD/fkYA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/e0QA/3JDBf9lQBT////l////+f/6/v////7///////////7///////3////9///////8//// + /P///////f////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////7///////v+///7/v///////////v///v/////7//// + 8f+6nnv/bkIM/3lFA/97RgP/ekYA/35FAP9+RgD/gEYA/3pFAv9uQAr/qItm///98/////7////6//// + +P////z////5////9f+fiW3/bUEL/35HAv99RQD/fkYA/3xFAP96RgD/ekQD/3hFBv91RAb/wp9z//// + 9f/7//////7///////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////+//7+/v/9/////f/////+/f/36dP/bUEM/39HAP9+RgD/fEYA/3xF + Av96RgD/fkUA/3xGAP98RQL/ekUC/3pFAv96RgD/fkUA/3xGAP98RQL/ekYA/35FAP9+RgD/fkYA/3VE + Bv9xTiL/8t3C////+P/+/v7///////////////7////+//3////7/////////////v/9//////////// + /v////v////7/9jIsf91Shf/ekYA/31EAP9+RgD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP97RAD/ckMF/2VAFP///+X////5//r+/////v////////// + /v///////f////3///////z////8///////9//////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////v//////+/7///v+ + ///////////+///+//////v////x/6+Ucv9wRA7/eUUD/3tGA/95RQD/fkUA/35GAP+BRwD/eUUA/29C + Cf+wk27///vx/////v////r////4/////P////n////1/5+Ka/9tQQv/fkcC/3tEAP98RQD/fEUA/3pF + Av96RQL/ekYE/3VEBv/EoHL////0//3///////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////v////7///////////////7////+//// + /v///////f////3//////////////////////////////////////////v7+//v+///9///////7//no + 0/9rQA3/fUYB/35GAP9+RgD/ekUC/3lFA/96RQL/ekUC/3pFAv96RQL/ekUC/3pGAP9+RQD/fEYA/3xF + Av96RgD/fkUA/35GAP9+RgD/dUQG/3FOIv/y3cL////4//7+/v///////////////v////7//f////v/ + ///////////+//3////////////+////+/////v/2Mix/3VKF/96RgD/fUQA/35GAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3tEAP9yQwb/Y0AU//// + 5f////j//v7+///////////////////////9/////////////P////z///////3//////v////////// + /////////f////3////9/////f////////////7////+/////v////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////9/////f///////////////f///////P///+//popn/3FDDf94QwD/e0YD/3tE + AP99RgH/f0cA/4FHAP96QwD/ckQK/7ucdf///vT////////++v////v////8///99v////P/p49x/2w+ + CP99RgH/ekMA/3pFAv98RwT/eEMA/3tGA/96RQL/e0cF/7+Zaf///+////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////7////5///8 + 9//9/////P7/////+v////n////8///////7/v//+/7///////////7///////3////9/////f////7+ + /v/9////+v7///r9//////r/+ObP/2xEFP95RQP/gEYA/4BGAP96RQL/dUQG/3NEB/91RAb/ekUC/3xF + AP96RQL/ekYA/35FAP98RgD/fEUC/3pGAP9+RQD/fkYA/35GAP91RAb/cU4i//Ldwv////j//v7+//// + ///////////+/////v/9////+/////////////7//f////////////7////7////+//YyLH/dUoX/3pG + AP99RAD/fkYA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/fEUA/3NEB/9fPxb////n////8v////n////+///////5+/z//f////////////7////8//// + /P////7///////3////9/////v7+//3////3+///+P7///T6///7/v///////////P////v////7//// + /v///////f////3////////////+//////////////////////////////////////////////////// + ///////////////////////////////////9/////////////v////7//f////v+///6/v/////8//// + 7v+khV7/cUIK/3dCAP9/SAP/e0QA/3tEAP99RQD/f0cA/3pFAv91Rgn/wqJ5////9//7/v///f////v9 + /v////z////4////9P+vl3n/bT8J/35HAv95RAH/ekUC/3tFBP95RAH/fEUA/3pFAv95RQP/to5d///9 + 7f/8/Pz///////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////v////v////7//r+///5/f/////8////+P///vr/+vr6//n9///5/f///v7+///+ + /f/+/f///P7///z+///8/v////////3////5/f//+vz9////+P/+6tH/ZT8P/3ZDBP+BRgD/gUcA/3pF + Av91RAb/c0QH/3VFBf9+RQD/gEYA/3xFAP96RgD/fkUA/3xGAP98RQL/ekYA/35FAP9+RgD/fkYA/3VE + Bv9xTiL/8t3C////+P/+/v7///////////////7////+//3////7/////////////v/9//////////// + /v////v////7/9jIsf91Shf/ekYA/31EAP9+RgD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/cUMJ/2FEH////+v////y////+P/6+Pf//P7///v+ + ///5/P///v7+///+/f////v////7///+/f/+/v7//P3///z+/////v3//v7+//r+///2/f//9v3///j8 + ///7+/v///z3////+f////n////+//3////7/v///f////////////7///////////////////////// + //////////////////////////////////////////////////////////////3////////////7//// + /P/9////+v7///j+//////z////p/6CAV/9xQwn/eEQA/4BHAv99RQD/fEUA/31GAf99RQD/eUQB/3NF + C//JqYD////2//n9///6/v//+Pz//////v////v////1/7qlhv9sQAr/fUgF/31GAf96RgD/eUQB/3pF + Av97RAD/e0YD/3lFA/+oglL////w//z8/P////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////r6+v/6/v//8fz///H6///9//////76//// + /v/9////+v7///r+///////////+//3////7/v//+/7///3////9+/r//fv6//3+///////////3///t + 0v9hOwv/eEYE/4FHAP+DRwD/fkYA/3pFAv95RQP/ekYA/4NGAP+DRwD/fkYA/3pGAP9+RQD/fEYA/3xF + Av96RgD/fkUA/35GAP9+RgD/dUQG/3FOIv/y3cL////4//7+/v///////////////v////7//f////v/ + ///////////+//3////////////+////+/////v/2Mix/3VKF/96RgD/fUQA/35GAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP9wRAn/VTkX///7 + 6P////H////5///////7/v//+v7///j8///9/////////////v////7////+//3////7/v///f////// + +/////r///////n9///5/f//+/7//////v////v////5////+////////f////v+///9//////////// + /v////////////////////////////////////////////////////////////////////////////// + /////////f////////////v////8//3////6/v//+v7//////P//+eD/mXdM/3JECv95RQD/gEcC/31F + AP98RQD/fUYB/3pDAP94RAL/c0YN/9O0jf////X/+v3///r+///5/f/////+////+/////X/yrSY/2k/ + Cv98RwT/fUYB/3xFAP98RQD/fUYB/3xFAP98RwT/eUUD/5hyQv////D//v7+//////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////9/////f7///j+ + ///x/P//8Pn//////v///fb////5///++f///v3///79////+P////f////6////+/////v////6//// + +P////j////7///+9////+///+nL/2hADP9+Sgj/gUcA/4NHAP9+RgD/fEUA/3pFAv9+RgD/hUcA/4VH + AP9+RgD/ekYA/35FAP98RgD/fEUC/3pGAP9+RQD/fkYA/35GAP91RAb/cU4i//Ldwv////j//v7+//// + ///////////+/////v/9////+/////////////7//f////////////7////7////+//YyLH/dUoX/3pG + AP99RAD/fkYA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/fEUA/3FDCf9cPxr////r////8P///fD////5////+//59/b////+////+v////j////3//// + 9/////f////4////+/////j////y////8/////v//v7+//f6/v/9/////fv6//779/////v////8//// + ///9////+/7///3////////////+//////////////////////////////////////////////////// + ///////////////////////////////////9////////////+/////z//f////r+///7/v/////7///1 + 2v+PbED/dEUI/3hDAP99RgH/fkYA/31GAf99RgH/fEUA/3ZDBP9xRQ//3sOe////9//7/v//+v7///r+ + ///+/v7////8////9//axar/aT8K/3pFAv9+RgD/fkYA/39HAP9+RwL/fEUA/3pFAv94RAL/hV8v///6 + 6P///v3///////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////9/f3/+Pz9//X6///7/v/////1////7f///+3////u////8f////H////r//// + 6v///+3////u////8P////D////t////6f////H////x////6v//5cD/dUkT/3VAAP+BRwD/g0cA/35G + AP98RQD/ekUC/35GAP+FRwD/hUcA/35GAP96RgD/fkUA/3xGAP98RQL/ekYA/35FAP9+RgD/fkYA/3VE + Bv9xTiL/8t3C////+P/+/v7///////////////7////+//3////7/////////////v/9//////////// + /v////v////7/9jIsf91Shf/ekYA/31EAP9+RgD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/dUQG/2lDE////dj////m////5////+7////x//// + 7v////H////w////7v///+v////r////6////+3////w////7v///+v////p///+8P////v//f39//3/ + //////7////8/////P////z///////3////7/v///f///////v////7///////////////////////// + //////////////////////////////////////////////////////////////3////////////8//// + /P/9////+/7///3///////j//+/T/4VhM/9zRAf/eEMA/3xFAP99RgH/f0cA/31FAP9+RwL/dkME/2xE + EP/t0rD////2//v+///6/v//+v7///7+/v////z////3/+vXvv9qQg7/eEMA/31FAP+ARgD/gEYA/35G + AP98RQD/eEMA/3tHBf93USH///Lg/////v////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////+/////P////z///////r07f+3pY7/lXpY/5l6 + U/+XeFH/lHhV/5R4Vf+cek//nHpP/5p6Uf+YeVL/lnlU/5Z5VP+efVb/mHlS/5F4WP+Telr/l3tY/598 + UP9pOwH/fUgF/4FHAP+BRwD/fEUA/3pFAv95RQP/ekYA/4FHAP+BRwD/fEUA/3pGAP9+RQD/fEYA/3xF + Av96RgD/fkUA/35GAP9+RgD/dUQG/3FOIv/y3cL////4//7+/v///////////////v////7//f////v/ + ///////////+//3////////////+////+/////v/2Mix/3VKF/96RgD/fUQA/35GAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP95RQP/aDsC/62F + Uf+jfU3/nHpP/5F0T/+SdlP/l3xa/5R4Vf+WeVT/mHlS/5p6Uf+cek//mnpR/5h5Uv+WeVT/lnlU/5R3 + Uv+SeVn/saCL///67f////z///////v5+f///fz////+/////v/9/////f////v+///9///////+//// + /P////////////////////////////////////////////////////////////////////////////// + /////////f////////////z////+//v+///7/v//////////9//85Mb/eVMj/3NEB/95RAH/fEUA/35H + Av9/RwD/fUUA/31GAf90QwX/bUUV//nhw/////b/+/7///n9///5/f///v7+/////v////n/+ejT/25G + Ff93QwH/fUUA/4JIAP+BRwD/fUMA/31GAf93QgD/fkoI/25GFf/15tP////8/////v////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////7///rz//// + 9/////j///fl/5R3Uv9lPQz/bUEL/3JFDP9tQw7/b0MN/3RFCP92RQf/ckQK/3FEC/9vQw3/b0QL/29B + B/9wQwr/aEAP/2hCEv9hOwv/a0EM/3I/AP+BSgX/gEYA/35GAP95RQP/d0QF/3VEBv91RQX/ekUC/3xF + AP96RQL/ekYA/35FAP98RgD/fEUC/3pGAP9+RQD/fkYA/35GAP91RAb/cU4i//Ldwv////j//v7+//// + ///////////+/////v/9////+/////////////7//f////////////7////7////+//YyLH/dUoX/3pG + AP99RAD/fkYA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP9+SQb/ekYE/249AP92SA7/c0cR/2tBDP9tRRH/aT8K/29DDf9xRAv/ckQK/3JE + Cv9yRAr/ckQK/3FEC/9tQw7/ZT0M/18/Fv+Iclb///ro////+f////7///7+//////////////////3/ + ///7/v//+/7///3///////7////8//////////////////////////////////////////////////// + /////////////////////////////////////////////////P////7/+/7///v+//////7////0//LX + tf9uRhX/dkUH/3pFAv95RAH/fUYB/35GAP99RQD/e0QA/3RFCP9vSh7///LW////+P/7/v//+f3///r+ + ///////////+/////P//9OH/b0sd/3ZDBP98RAD/gkgA/4NJAP9+RAD/f0gD/3VAAP99SQf/YzwI/+nX + wP///vf////+//////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////v////n////2////9v///un/m3hM/3JECv98SAb/eEMA/3ZDBP94RAL/fUUA/39F + AP97RAD/eEQB/3hEAv95RAH/f0cA/31GAf9yQQP/dkgO/29BB/9xQgX/gk0K/3lBAP9+RgD/fEUA/3lF + A/91RAb/c0QH/3NEB/93RAX/eUUD/3pFAv96RgD/fkUA/3xGAP98RQL/ekYA/35FAP9+RgD/fkYA/3VE + Bv9xTiL/8t3C////+P/+/v7///////////////7////+//3////7/////////////v/9//////////// + /v////v////7/9jIsf91Shf/ekYA/31EAP9+RgD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fkYA/4BGAP+ARgD/gEgB/3lEAf97RwX/dUID/3dG + CP93RAX/eEQC/3lEAf95RAH/eUUA/3tEAf95RAH/eUQB/3ZDBP9xQwn/a0MS/4pvTf///un////4///+ + /f///////v7+///////9/////f7///v+///7/v///f///////v////z///////////////////////// + //////////////////////////////////////////////////////////////////////7////+//// + /v/7/v///f///////P////H/6syp/2Y+Cv92RQf/fEcE/3hDAP97RAD/fkYA/39HAP96QwD/dEYM/3JQ + Jf///uX////5//3////6/f//+v7///39/f///////fv6///87P99WzD/dkcJ/31EAP+CSAD/gUUA/4JI + AP95QgD/ekUC/3lFA/9tRRD/zrme////9f////z///////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////v////z////7///55v+de1D/b0EH/3lF + A/98RQD/eUUD/3pFAv+ARgD/gUcA/35GAP98RQD/fEUC/35GAP+DRwD/g0cA/35GAP95RQP/d0QF/3lF + A/98RQD/fkYA/35GAP98RQD/eUUD/3VEBv91RAb/dUQG/3dEBf95RQP/ekUC/3pGAP9+RQD/fEYA/3xF + Av96RgD/fkUA/35GAP9+RgD/dUQG/3FOIv/y3cL////4//7+/v///////////////v////7//f////v/ + ///////////+//3////////////+////+/////v/2Mix/3VKF/96RgD/fUQA/35GAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP9+RgD/gEYA/4BG + AP9+RgD/fEUA/3pFAv95RQP/eUUD/3lFA/96RQL/fEUA/3xFAP98RgD/fkUA/3xFAP98RQD/ekUC/3ZD + BP9vQw3/kHFK////6f////f////+//7+/v/9//////////3////9/v//+/7///v+///9///////+//// + /P////////////////////////////////////////////////////////////////////////////// + //////////79/////v///v3///////r9///6/P3////5////6//JqIH/cEcQ/3ZDBf95RAH/ekYE/3pF + Av99RQD/f0cA/3pDAP91Rw3/hmdA////6v////n/+/3+//v+///7/v////////////////////zu/5R0 + S/9vQQf/fkcC/39FAP+BRwD/gUgA/3tEAP98RwT/eEMA/2k9B/+4noD////0////+/////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////f////// + //////z///nn/517UP9vQQf/ekUC/3xFAP96RQL/ekUC/4BGAP+BRwD/fkYA/3xFAP98RQD/gEYA/4VH + AP+FRwD/gEYA/3xFAP95RQP/eUUD/3xFAP9+RgD/fkYA/35GAP96RQL/eUUD/3lFA/95RQP/eUUD/3pF + Av96RQL/ekYA/35FAP98RgD/fEUC/3pGAP9+RQD/fkYA/35GAP91RAb/cU4i//Ldwv////j//v7+//// + ///////////+/////v/9////+/////////////7//f////////////7////7////+//YyLH/dUoX/3pG + AP99RAD/fkYA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP9+RgD/fkYA/3xFAP98RQD/ekUC/3pFAv96RQL/ekUC/3xFAP98RQD/fkUA/35G + AP9+RgD/fkYA/35GAP98RQD/eUQB/3JECv+Sckn////n////9/////7//v3///3///////////////3/ + ///7/v//+/7///3///////7////+//////////////////////////////////////////////////// + //////////////////////////////////////7////+//78+///////+/7///7+/v////j////t/7GP + ZP9uQQj/d0QF/3pFAv97RwX/e0YD/3xEAP9+RgD/ekMA/3JFDP+YfFn////v////+f///////f////v+ + //////7//v7+//3///////b/r5Jt/2xACv98SAb/fkQA/39FAP+ARgD/fUYD/3tGA/98RQD/b0EH/5+B + Xv///+7////5//////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////3////7/v//+/7/////////+Oj/m3tS/29BB/96RQL/fEUA/3lFA/96RQL/fkYA/4BG + AP98RQD/fEUA/3xFAP9+RgD/gUcA/4BHAP9+RQD/ekUC/3lFA/95RQP/ekUC/3xFAP9+RgD/gEYA/4BG + AP9+RgD/fkYA/35GAP9+RgD/fkYA/3xFAP96RgD/fkUA/3xGAP98RQL/ekYA/35FAP9+RgD/fkYA/3VE + Bv9xTiL/8t3C////+P/+/v7///////////////7////+//3////7/////////////v/9//////////// + /v////v////7/9jIsf91Shf/ekYA/31EAP9+RgD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/ekUC/3pFAv96RQL/ekUC/3pF + Av96RQL/ekUC/3pGAP98RQD/fEUA/3xFAP98RQD/fkYA/35GAP97RAD/dEUI/5RyR////+f////3//// + /v/8/v///f///////////////f////3////9/////f///////v////7///////////////////////// + /////////////////////////////////////////////////////////////////v///fz///38//3/ + ///7/v//////////9////+X/lnJE/20/Bf95Rgf/eUQB/3tHBf97RgP/fEQA/4JIAP96RQL/b0MN/7Ob + ff////T///75///////9////+/7//////v//////9/r+////+P/Gq4n/bEQP/3dEBf9/RwD/fUMA/4BG + AP97RgP/d0IA/39HAP96SQv/h2c+///13v////n///////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////f////v+///7/v/////////46P+de1D/b0EH/3pF + Av98RQD/eUUD/3lFAv9+RgD/gEYA/3xFAP98RQD/fEUA/35GAP9+RgD/fEUA/3pFAv95RQP/d0QF/3dE + Bf95RQP/ekYA/35GAP+ARgD/gUcA/4FHAP+BRwD/gUcA/4FHAP+ARgD/fEUA/3pGAP9+RQD/fEYA/3xF + Av96RgD/fkUA/35GAP9+RgD/dUQG/3FOIv/y3cL////4//7+/v///////////////v////7//f////v/ + ///////////+//3////////////+////+/////v/2Mix/3VKF/96RgD/fUQA/35GAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/ekUC/3pF + Av96RQL/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/35GAP9+RgD/fkYA/3tE + AP90RQj/lHJH////5/////j///////z9///7/v///////////////v///f////3////9//////////// + /v////////////////////////////////////////////////////////////////////////////// + //////7////+///9/P///////f////v+///+/v7////z///x1f+DXS3/c0QH/31JB/91QQD/d0QF/3pG + BP9/RQD/g0kB/3xHBP9sQg3/z7qf////9////Pf///////v9/v/7/v/////8///////3+v7////5/+HI + qP9uRhX/c0EF/35HAv9/RwD/fUUA/3pFAv93QgD/fkYA/3hFBv90UCL/++XJ////+P////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////f////3/ + //////z///nm/6B8Tv9zQgT/fEUA/35GAP96RQL/ekUC/4BFAP+ARgD/fkYA/35GAP9+RgD/fkYA/3xF + AP96RQL/eUUD/3dEBf93RAX/d0QF/3lFA/96RQL/fkUA/4BGAP+BRwD/g0cA/4NHAP+DRwD/gUcA/4BG + AP98RQD/ekYA/35FAP98RgD/fEUC/3pGAP9+RQD/fkYA/35GAP91RAb/cU4i//Ldwv////j//v7+//// + ///////////+/////v/9////+/////////////7//f////////////7////7////+//YyLH/dUoX/3pG + AP99RAD/fkYA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP9+RgD/gEYA/4BGAP9+RgD/fkYA/35GAP9+RgD/fkYA/35G + AP9+RgD/gEYA/4BGAP+ARgD/e0QA/3JECv+Sckn////n////+P/9////+v3///v+///////////+//// + /////////f////3////////////+//////////////////////////////////////////////////// + /////////////////////////////////v////7////+///////9////+v3//////v////T/89u9/3hQ + HP93Rgj/fEgG/3VBAP93RAX/ekYE/4BGAP+BRwD/e0YD/29HE//l0bj////4///9+f//////+fv8//v+ + //////z//f39//r+/////fj//ObK/3JMHP9vQQf/ekUC/4FJAv97QwD/eUQB/31IBf+ARgD/dkEA/25G + Ev/s07P////3//////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////9/////////////P//+eb/oHxO/3VCA/9+RgD/fkYA/3pFAv95RQP/fkYA/35H + AP9+RQD/fEUA/35GAP9+RgD/ekUC/3pFAv95RQP/eUUD/3lFA/95RQP/eUUD/3pFAv98RQD/fkYA/4FH + AP+BRwD/gUcA/4BGAP9+RgD/fEYA/3xFAv96RgD/fkUA/3xGAP98RQL/ekYA/35FAP9+RgD/fkYA/3VE + Bv9xTiL/8t3C////+P/+/v7///////////////7////+//3////7/////////////v/9//////////// + /v////v////7/9jIsf91Shf/ekYA/31EAP9+RgD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3pFAv98RQD/fEUA/35GAP+ARgD/gEYA/4BG + AP9+RgD/fkYA/35GAP9+RQD/fEYA/35GAP9+RwD/gEYA/35GAP97RAD/ckQK/5JySf///+n////5//3/ + ///6/f//+/7///////////7//////////////v////////////////7///////////////////////// + ///////////////////////////////////////////////////////////+/////P////7///////r+ + ///5/P/////+////8v/Xvp7/b0UQ/3dEBf94RAL/d0MB/3hFBv96RgT/gEYA/35FAP97RAH/gFgk//fl + zv////n////7///////6/P3/+/7//////P/9/f3/+v7////++v///uP/gF0x/3BDCv93QwH/fUYB/3lC + AP95RQP/fkkG/4FHAP98RQD/bEIN/8Ophf////f///////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////3////9///////8///55v+gfE7/c0IE/3xF + AP98RQD/d0QF/3dEBf96RQL/ekYA/3pEA/95RQP/ekUC/3xFAP98RQD/fEUA/35GAP98RQD/fEUA/3pF + Av95RQP/eUUD/3pFAv98RQD/fkYA/35GAP9+RgD/ekUC/3lFA/93RQP/ekQD/3pGAP9+RQD/fEYA/3xF + Av96RgD/fkUA/35GAP9+RgD/dUQG/3FOIv/y3cL////4//7+/v///////////////v////7//f////v/ + ///////////+//3////////////+////+/////v/2Mix/3VKF/96RgD/fUQA/35GAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP96RQL/eUUD/3lF + A/96RQL/fEUA/35GAP9+RgD/fkYA/3xFAP98RQD/ekYA/3pFAv96RQL/fEUC/3xFAP9+RQD/fEUA/3lE + Af9xRAv/kHFK////6v////n//f////r9///7/v///////////v////7////+//////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////7////8/////P/9/f3/+/////r9//////7////y/6+Ucv9rQQz/d0QF/3ZCAP96RgT/dkUH/3ZD + BP+BRwD/fkUA/3pDAP+acj7///jj////+/////v////+//z+///7/v/////7//7//f/7/v/////+//// + 8P+Obkr/cUIM/3pEA/96QwD/fEgC/3pGA/95RQD/fkQA/4NLBP9sPQX/l3dT////9f////7///////// + /v////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////9////+v7///v+ + //////z///nm/517UP9vQQf/ekQD/3xFAP95RQP/d0QF/3pFAv96RQL/eUUD/3lFA/96RQL/fEUA/35G + AP9+RgD/gEYA/35GAP9+RgD/fEUA/3pFAv96RQL/ekUC/3xFAP9+RgD/fkYA/3xFAP96RQL/d0QF/3dE + Bf95RQP/ekUC/3xFAP9+RgD/fEUA/3xGAP9+RgD/fkYA/3xFAP9zRAf/cE4j//Ldwv////j//v7+//3/ + ///9///////////////9/////f///////////////f////3///////7////7////+P/cyK//c0sX/3pF + Av9/RQD/gEYA/35GAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP96RQL/eUUD/3pFAv98RQD/fkYA/35GAP98RQD/fEUA/3xFAP96RQL/ekUC/3pF + Av96RQL/fEUA/3xFAP98RQD/eUQB/3FEC/+Sckn////p////+P/9////+v3///r+///9//////////// + /v////7///////////////////////////////////////////////////////////////////////// + /////////////////////////////////v///vn////8//r8/f/7/v//+/7/////+////Of/kHFK/3NF + C/98RwT/dkIA/3pHCP91RAb/dEEC/4JIAP9+RgD/dUQG/6mHWf////D////5///++v//////+v3///r+ + ///9//z//P/9///+/v////7///v1/72hif9yPgn/gUYB/3lFAP94RQD/dkUA/3tHAP+BSAD/fEQA/4FL + D/9/WDH/+era/////P////7///z4/////v////7/+/v7///////9//////////////////7////+//// + /////////f////////////////////////////////////////////////////////////////////// + //////////////v+///1/P//+P7////8+f//++j/nH1W/25CDf94RQb/e0QA/3xFAP98RQD/fEUA/3xF + Av98RQL/fEUC/3xFAv9+RQD/fkYA/35GAP9+RgD/fkYA/35GAP9+RgD/fEUA/3xFAP98RQD/fkYA/35G + AP9+RgD/fkYA/3xFAP98RQD/ekUC/3lFA/95RQP/fEUA/35GAP+ARgD/gEcA/4BGAP98RQD/ekcI/2o+ + CP9wUCf/8t7F////9//+/v7/+P7///X8///7/v///f/////////////////////////9/////f////// + //////j////z/9/Hqf9yShn/fkoI/4JGAP+GSAD/gEYA/35GAP9+RgD/fkYA/35GAP9+RgD/fkYA/35G + AP9+RgD/fkYA/35GAP9+RgD/fkYA/35GAP9+RgD/fkYA/3xFAP98RQD/fEUA/35GAP9+RgD/fkYA/35G + AP9+RgD/fkYA/3xFAP98RQD/fEUA/3xFAP9+RgD/fkYA/3xFAP99SAX/ckMG/5d0SP///+L////0//// + /P/3+v//+P7///r+///9/////////////v////7////////////9//////////////////////////// + ///////////////////////////////////////////////////////////+////+v////z/+P7///j9 + /////v/////1///x1/90TSD/eEMA/4FHAP97SAn/ckMG/3FCBf96RgT/fkMA/35JBv9oQA//zbOP//// + 8P////f///76//3////5/f//+P7///j9+//9//7////+///8/P///v7/4Mi2/3hGEv+ARQD/ekYA/3lG + AP94RQD/ekYA/4BGAP9+QwD/fEUI/3dMIf/jz73////5///9+v///v3////+///+/f/8/Pz///////3/ + ///9/////////////v////7////+//3////9//////////////////////////////////////////// + ////////////////////////////////////////+/7///b9///7/v/////5///95/+Yd1D/ZzwJ/3ZD + Bf9/RgH/gEYA/4BGAP+ARQD/fkUA/35FAP9+RQD/fkUA/35GAP9+RgD/fkYA/35GAP9+RgD/fkYA/35G + AP9+RgD/fkYA/35GAP9+RgD/fkYA/35GAP9+RgD/fkYA/35GAP98RQD/ekQD/3pFAv98RQD/gEYA/4NG + AP+DRwD/gUcA/35GAP9yPwD/akAL/3BQJ//x27////7w///++v/6/v//9/3///v+///9//////////// + /////////f////3+///9////////////+f////L/5Myu/21GGf91RAb/fkQA/4NFAP+ARgD/fkYA/35G + AP9+RgD/fkYA/35GAP9+RgD/fkYA/35GAP9+RgD/fkYA/35GAP9+RgD/fkYA/35GAP9+RgD/fkYA/35G + AP9+RgD/fkYA/35GAP9+RgD/fkYA/35GAP9+RgD/fkYA/35GAP9+RgD/fkYA/35GAP9+RgD/fEUA/3RA + AP9wQgj/lXJG///83v////D////8//v+///4/v//+v7///v+///////////+/////v////7///7///3/ + //////////////////////////////////////////////////////////////////////////////// + //////7////5/////v/2/f//8/n///39/f////P/5sup/3BGEf9/RwD/gEYA/3dEBf90RQj/dkUH/3pG + BP9+QwD/eEME/2tJHv/lz7P////w////9f////7/+v3///j+///2/f//+vz8/////v////7///v4//// + /P/+6tj/fFAh/3hCAf98RQD/fUcA/3lFAP97RQD/gUcA/39EAP94QgP/bkIT/7ukiv////X////6//// + /////v///f/////////9/f3//f////3////////////+/////v////7//f////3///////////////// + /////////////////////////////////////////////////////////////////////////f/////7 + +P///u7////j/514TP9wQgz/fUcG/4FGAP+ARgD/gEYA/4BFAP+ARQD/gEUA/4BFAP+ARQD/gEUA/35G + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQL/fEUA/35GAP+ARwD/g0cA/4NHAP+DRwD/gEYA/3xIBv92SRD/dlIk//rfvf///+z////z//// + /P///////f////3////////////////////9/////f7///3////9/f3///34////8//izbL/Z0Qc/3FF + D/99SAX/gEYA/35GAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xFAP98RQD/fEUA/3xF + AP98RQD/fEUA/3xFAP96RQL/dkcK/3BIFP+UdEv////n////9f////z/+/7///b8///6/v///f////// + /v////z////+/////v///v///f////////////////////////////////////////////////////// + /////////////////////////////////v////v///79//j9///z+v///v7+////8v+3mHH/cUQL/31G + A/99RQD/eEMA/3lGB/93RAX/eEQC/4JHAf92QwX/fFs0///w1/////D////2/////v/2+f3/+v7///f9 + ///9///////////+/f///vv////7///45/+PbEH/dUYJ/3tEAP+ASQD/fEUA/3tFAP+CSAD/gEgB/3hE + Av9tQQz/kHRR////7f////v//v3///v+///7/v/////////+/f///v///f////3////////////8//// + /v/9////+/////////////////////////////////////////////////////////////////////// + //////////////////////7////4////8v///+X/nHlR/25DEP9yQwb/dUAB/3lFA/95RQP/eUQF/3dE + Bf93RAX/d0QF/3lEBf95RQP/d0QF/3dEBf93RAX/d0QF/3dEBf93RAX/d0QF/3dEBf93RAX/d0QF/3dE + Bf93RAX/d0QF/3dEBf93RAX/dUUF/3VEBv91RAb/d0QF/3lFA/98RQD/fEUA/3xFAv95RQP/cUIF/2Y+ + Cv9rSR7/9t29////7v////T////5///9/P///////f/////////////////////////9/////f////3/ + //////z////3/9vKtf9eQh//Yz8R/3JFDP90QwX/d0QF/3dEBf93RAX/d0QF/3dEBf93RAX/d0QF/3dE + Bf93RAX/d0QF/3dEBf93RAX/d0QF/3dEBf93RAX/d0QF/3dEBf93RAX/d0QF/3dEBf93RAX/d0QF/3dE + Bf93RAX/d0QF/3dEBf93RAX/d0QF/3dEBf93RAX/d0QF/3NEB/9oPgn/Y0AU/4htS////+z////3///9 + /P/6/f//+f3///v+///9///////+/////P////7///////3////9//////////////////////////// + ///////////////////////////////////////////////////////////+////+////fz/+P7///f9 + ///////////v/45qPP91RAb/eEQC/3xFAP97RAD/fkcC/3dDAf93QgD/g0oF/3NDCf+Welf///7p//// + 8f////n////+//f6/v/6/v//9/3////+///7+/v///79////+/////n////u/7edef9tRRD/d0MA/4NJ + AP9/RgH/fUQA/4FGAP9/RwD/eUUC/3BECf9zUCT//+vP////+P/2+f3/9/z///j+///9/P7////+///+ + ///9/////f////3///////z////8//3////7//////////////////////////////////////////// + //////////////////////////////////////////////3//////vr////2///y3f+SeVn/ZEQb/2VB + E/9oQA//Zz8O/2c/Dv9lPw//ZT8P/2U/D/9lQA7/Zz8O/2dADP9oQAz/aEAM/2hADP9oQAz/aEAM/2hA + DP9oQAz/aEAM/2hADP9oQAz/aEAM/2hADP9oQAz/aEAM/2hADP9nQAz/ZT8P/2U/D/9lPw//Zz8O/2hA + DP9oQAv/aEAM/2c/Dv9hPhL/YUIb/2pSNP/m1L3////x////9/////z///////3////9//////////// + //////7///////3////9/////P7////+/f//+/T/08a2/2BLMP9bPhn/ZEEV/2lBEP9oQAz/aEAM/2hA + DP9oQAz/aEAM/2hADP9oQAz/aEAM/2hADP9oQAz/aEAM/2hADP9oQAz/aEAM/2hADP9oQAz/aEAM/2hA + DP9oQAz/aEAM/2hADP9oQAz/aEAM/2hADP9oQAz/aEAM/2hADP9oQAz/aEAM/2hADP9oQAz/Zz8O/2A+ + E/9hRSL/h3JX///15f////j//v7+//v+///6/v//+/7///////////7////8/////v///////f////3/ + //////////////////////////////////////////////////////////////////////////////// + //////7////8///+/f/6/f//+v7//////P/148z/cUkV/3ZCAP92QwT/ekYE/35GAP+ARgD/e0QA/3pF + Av99RgP/bT8J/8Wrjf////D////1////+///////+v3///v+///6//////7////+/v////7////6//// + +P////L/3syv/2VEF/93QwH/hEcA/4FGAf99RAD/gEUA/31FAP93RAD/c0UF/21EDf/ewZz////1//j7 + ///0/f//9v3///38/v////7///////3////7/////f///////P////z//f////3///////////////// + ///////////////////////////////////////////////////////////////////9////+v////n9 + /v////v////1/93Puf/SvaL/2cKi/9vCoP/awZ//2sGh/9jAov/YwKL/2MGh/9jBof/awaH/2sGf/9zB + n//cwZ//3MGf/9zBn//cwZ//3MGf/9zBn//cwZ//3MGf/9zBn//cwZ//3MGf/9zBn//cwZ//3MGf/9zB + n//awaH/2MCi/9rBof/awaH/3MGf/9zBn//cwZ//2sGh/9S+ov/Vwaj/zb+t///26f////n///38//3/ + ///4+////f////3//////////////////v////7///////3////7/f7//v7+////+//58Ob/yLmm/9K9 + ov/ew6H/3sKf/93Bnv/cwZ//3MGf/9zBn//cwZ//3MGf/9zBn//cwZ//3MGf/9zBn//cwZ//3MGf/9zB + n//cwZ//3MGf/9zBn//cwZ//3MGf/9zBn//cwZ//3MGf/9zBn//cwZ//3MGf/9zBn//cwZ//3MGf/9zB + n//cwZ//3MGf/9zBn//cwZ//176e/9bBpv/by7r////3/////P/9////+/7///X4/P/9//////////// + /P////z////+///////9////+//////+//////////////////////////////////////////////// + /////////////////////////////////v////7///////n9///7/v////32/8iylv9tQAf/fEUA/3lG + CP93RAX/gEYA/39FAP+CSAD/fkcC/3VAAf9tRBP/893E////9v////n////8//n7/P/7/v//+v3///v+ + /////f////7//////v/+/vj////2////9P/07NX/dFo1/3ZDBf+ERgD/gEMA/39DAf+BRgH/fUUA/3dF + AP94RwH/dUUF/6qGWP///e3//f7///T9///0/f///f///////v///////f////v////9///////+//// + /v///////f////////////////////////////////////////////////////////////////////// + //////////////v+///2/f//9fz///f8//////7////4////8v////P////v////8/////P////0//// + 9P////T////z////8/////P////2////9v////b////2////9v////b////2////9v////b////2//// + 9v////b////2////9v////b////2////9P////T////z////8/////P////z////8/////P////3//// + +P//+/b////+//z9///4/P//9v3///j+///7/v///f////////////7////+/////v////////////3/ + ///+/v7////+////+P///vH////x////7v///+v////z////9v////b////2////9v////b////2//// + 9v////b////2////9v////b////2////9v////b////2////9v////b////2////9v////b////2//// + 9v////b////2////9v////b////2////9v////b////2////9P////H////w///78f////v/+/v7//v+ + ///7/v//+v3///////////7////8/////P////7///////3////7//////7///////////////////// + ///////////////////////////////////////////////////////////+///9/P//////+Pz///// + ////9ef/lnpX/3VDB/+BSAP/ekcJ/3NAAf+CSAD/gUUA/4ZJAP9+RQD/c0EF/4hlOf//9+T////5//// + /P/+/v7/+/3+//3////7/f7//f/////9/////f/////+////+/////f////0////7v+Qfl//ckML/4FF + AP9+QgD/f0MB/4NIA/9/RwD/d0YA/3tKAP96QwD/glYh///y3f//////8vn///L7///9/////vz7//// + /v//////+/////3///////7////+///////9//////////////////////////////////////////// + ////////////////////////////////////////+/7///L5///2/f//+P7///j8/f////7////7//// + +/////v////7/////P////z////8/////v////z////8/////P////7///////////////////////// + ///////////////////////////////////////////////////////////+/////P////z////8//// + /P////z////8/////P////7//f39//3////6/f//+v7///f9///1/P//9vz///v+//////////////// + /v////7////+/////////////P7///3//////////fv6////+/////j////0////9/////z///////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////8//// + +P////b////7/////v/8/v//+/7///r9///9/////////////P////v////7/////v///////f////v/ + /////v////////////////////////////////////////////////////////////////////////// + //////7///79/////v/5/P/////8//7s1f9zUSb/dUIE/3xEAP95RAX/cj0A/4NLBP+DRgD/hUcA/3pB + AP91RxH/polk///77f///v3///////39/f/9/////f////v9/v/9/////vr////+///7+/v////7//// + 9/////X//Pzw/8a5n/9rQA3/e0MC/4BGBf+ARAL/f0YB/31HAP94RQD/ekgA/4JJAP90RAr/0buf//// + +f/6/v//8/r///3///////7////+///////7////+/////////////7///////////////////////// + ///////////////////////////////////////////////////////////////////9////+/7///v+ + ///9/////f/+/////v////z////8/////P////z////+/////v/9//7//////////v////7////8//// + /P////z////8/////P////z////8/////P////z////8/////P////z////8/////P////z////8//// + /P////7////+/////v////7////+/////v////7////+//////////////////3////9/////f////v+ + ///9/////f///////////////////////v////7////////////9/////f////3////9///////+//// + /P////v////7/////P////z////8/////P////z////8/////P////z////8/////P////z////8//// + /P////z////8/////P////z////8/////P////z////8/////P////z////8/////P////z////8//// + /P////z////8/////P////z////7/////P////7//f////v+///7/v//+/7///3///////7////8//// + +/////v////+///////9////+//////+//////////////////////////////////////////////// + /////////////////////////////////v////7////+//v7+/////j/yrGR/2hADP+ASwz/fEMA/3lD + Av+BTAn/eUIA/39FAP+ISgD/fEUC/2lAD//bw6X////3///////9/////f////3////9//////////// + /////P////7///v9/f/9//z//f70////9/////n/7uTS/3RRJf90Qgb/fkYF/3xDAP9/RgH/e0UA/3tI + AP9+SgD/f0UA/3dEBf+fg2D///zu//z8/P/6/v///v7+/////v////7////+//v////7/////f////// + //////7////+//////////////////////////////////////////////////////////////////// + /////////////////////////////////v////z////8/////P////z////8/////v////7///////3/ + ///9/////f///////v////7////+/////P////z////8/////P////z////8/////P////z////8//// + /P////z////8/////P////z////8/////v////7///////////////////////////////////////// + //////////////////////7////+/////v/////////////////////////+/////v////////////3/ + ///9////+/7///3////9//////////////////7////+/////P////z////8/////P////z////8//// + /P////z////8/////P////z////8/////P////z////8/////P////z////8/////P////z////8//// + /P////z////8/////P////z////8/////P////z////8/////v////7///////3////7/v//+/7///v+ + ///9/////////////v////z////8/////P////7///////3////9//////////////////////////// + ///////////////////////////////////////////////////////////+/////v//+vf////8///1 + 5f+aelH/dEYM/3A7AP+ASQT/e0QA/3pDAP99RgH/g0sE/31DAP94RAL/dVIn///24P////v//f////3/ + ///9/////f////3////////////////9/////v///f////3///////j////2////+////e//lXlW/2tA + Df97Rgf/fEMA/4BHAv95QwD/f0oB/39IAP+BRQD/ekQD/3JPJP/z38b////5///////+/v7////+//// + /P////z//f////v////7/v///f///////P////z////+//////////////////////////////////// + ///////////////////////////////////////////+/////v////z////8/////P////z////8//// + /P////z////+/////v////7////+/////v////7////////////9/////f////3////9/////f////3/ + ///9/////f////3////9/////f////3////9/////f////3////////////+/////v////7////+//// + //////////////////////7////+/////v////7////+/////P////z////8/////v////////////// + ///////////////+///9/////f////3////9/////f////3////9/////f////3////9/////f////3/ + ///9/////f////3////9/////f////3////9/////f////3////9/////f////3////9/////f////3/ + ///9/////f////3////9/////f////3////9/////f////3////9/////f////3////9/////f////3/ + ///9/////f////v+///7/v//+/7///3////////////+/////P////z////8/////v///////f////3/ + //////////////////////////////////////////////////////////////////////////////// + //////7///38////+/////f/6ta9/3VNHP92QwT/dkIA/3xHBP9/RwD/fkYA/3xHBP95RAH/eUEA/3VG + Cf+egl/////x/////P/7/v///f////3///////////////////////////////39/f/8/f///f////// + +/////n//Pv3///+9P/LtJr/ZEEV/3RCBv99RgH/fkcC/3tEAP98RgD/fUYA/4JHAP94QgH/aUEN/8On + hf////L///75///+/f////7////8/////P//////+/////r+///7/v/////8////+/////7///////// + //////////////////////////////////////////////////////////////////////7////+//// + /P////z////8/////v////7////+/////v////7////+/////v////7////+/////////////f////3/ + ///9/////f////3////9/////f////3////9/////f////3////9/////f////3////9/////f////3/ + //////////////////////////////3//////v///////////////////////////v////7////+//// + /P////z////+/////////////////////////////f////3////9/////f////3////9/////f////v+ + ///7/v//+/7///3////9/////f////3////9/////f////3////9/////f////3////9/////f////3/ + ///9/////f////3////9/////f////3////9/////f////3////9/////f////3////9/////f////3/ + ///9/////f////3////9/////f////3////9////+/////3+///9//////////////////7////+//// + /P////7////////////9/////f////////////////////////////////////////////////////// + /////////////////////////////////////Pv////5////7/+1mnj/cEMK/3lEAf9/Sgf/eEMA/39H + AP+DSwT/d0IA/3ZCAP98SAb/cEYR/9W/o/////L////+//v////9/////f////////////////////// + //////7//P7+//n8///4+f3////+////+////vn////4//jp1v9qTiv/az8E/35IAf97RAD/fkcC/3xD + AP99RAD/f0YB/3U/AP9zRQv/jms////y2f////f///38//////////v////7/////v/7////9v7///r+ + //////v////5/////v////////////////////////////////////////////////////////////// + ///////////////////////////////+/////v///f////3////9//////7////+//////////////// + /////////f////3+///9/v////////////////////////////////////////////////////////// + ///////////////////////////////////9/////f////3////9////+/////3+///9/////f////3/ + ///9/////f/////+//////////////////////7////+/////////////f////3////9/////f////// + /////////////////////////f////3////9//////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////9//////7///// + /////////////////v////7////+/////v////////////3////9//////////////////////////// + /////////////////////////////////////////////////////////////////v////f///LZ/39d + Mv91RAb/hU0G/3lAAP98RQD/fEUA/31GAf94QQD/f0sJ/3VHDf95Vir//OnU////+f///////f/////+ + /////////////////////////////////v/9////+/7///v7/////v/////8////+/////j////1/455 + Xf9qQgj/fEgB/3lCAP+ASQT/fEIA/35EAv99RQT/dUEA/3tGB/9xRxL/27+g////8v///fz///////// + +/////n////+//v+///0/f//+P7/////+/////j////8//////////////////////////////////// + ///////////////////////////////////////////////+/////v////7///3+///9/v///f7///3+ + /////v////7////////////////////////9/////f7///3////////////+/////v////7////+//// + /v////7////+/////v////7////+/////v////7////+/////v////7///////3////9/////f////3/ + ///9/////f////3////9////+/////3+///9/////f////3////9/////////////v////7///////3/ + ///9/////f////3////9/////////////v////7////+/////v////////////////////7////+//// + /v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+//// + /v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+//// + ///////////////////////////////////////////+/////v////7////+/////////////f////3/ + //////////////////////////////////////////////////////////////////////////////// + ///////////+////9//Tupr/a0MS/3pFBv+CSAD/e0AA/4FIA/97RgP/d0IA/3tEAP97Rgf/ZzwJ/6+R + bv///Oz////8///////9/////////////////////////////////////f76//3//v/6/f//+/3////9 + /////vv///76///99v////n/yryl/3dRF/98SAH/eUIA/35HAv9+RAL/fkQD/3lEBf96RQb/fEUA/29A + A/+ef1j///fk///9+v///v/////5////+f////7/+/7///T9///2/v/////5////9/////z///////// + //////////////////////////////////////////////////////////////////////////////// + /////v///f////3////9//////7///////////7////8/////P////z////+//////////////////// + /v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+//// + /v////7////////////////////////////////////////////9//////7///////////////////// + ///////////+/////v///////f////3+///7/v//+/7///3////////////+/////v////z////8//// + /v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+//// + /v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+//// + /v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////vXo/45uSv9zRQ//e0UE/3tBAP+FSwD/fkYA/3tH + Bf93QwH/gUkC/3Q/AP9yTBz/69O1////9f/9+/r////////////////////+/////v////////////3/ + //////z//f////b5///7/f////3////8/P////v///76/////P/78t7/f14s/3lKBv95RQD/fUQA/39F + BP97QgT/dUAB/35IB/9/RQD/d0IA/3ZPIv/w28D///z1//////////v////7/////P/9////9v3///j+ + //////z////5/////v////////////////////////////////////////////////////////////// + ///////////////////////////////+/////v///f/////+/////////////////v////z////8//// + /P////7////+//////////////7////////////////+/////P////z////8/////P////z////8//// + /v////7////+/////v////7////+/////v////7////+/////v////7////+/////P////z////8//// + /P////7////+//////////////7////+//////7////+///////9////+/7///v+///7/v///f////// + //////7////8/////P////z////8/////v////7////+/////v////7////+/////v////7////+//// + /v////7////+/////v////7////+/////P////z////+/////v////7//////////v////7////+//// + /v////7////+/////v////7////+/////v////7//////////v////7////+/////v////7////+//// + /v////7////+///////////////////////////////////////////////////////9/////f////// + //////7////+/////v/////////////////////////////////9///////+////+f/j07z/akQU/3hF + Bv94QQD/g0gC/39HAP95QgD/e0cF/3RAAP+CSgP/eUYI/45sQf//8dr////7//v//////v////////// + /v////7////+/////////////f////3//v/7////+/7///38/////f////7////+//////7//f78//// + 9P+2nXX/bEYM/3pGA/97QwD/fEQD/3xEA/95QwL/gkoD/4VGAP9/RQD/b0IJ/6eLaP//++/////+//v7 + +/////7////8//v5+P/7/v//+v////j8/f/9//////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////v////7////+///////////////////+///9+f////3////+//////7////7///9 + 9f////b////4////9/////r////8/////v///v3///38//7/+/////z//f/8//z/+//9/vz///79//// + /v////z////7////+P////j////3////+f/+/vj////+///+///6+v////7//////P////v////+//3/ + ///7/v//+/7///v+///9/v///////////v////z////6///++f////z////+//3+/P///v3////+//// + /v///v3//f39/////////////v7+///////6+vr///79/////v////z///34////+/////z///////3/ + /////v/////////////+/v7//v7+//7+/v////////////////////////////3//////v////////// + //////////////////////////////////////////////////////////////////////////////// + //////7///////r+///7/v///////////P////n////7///+/f/9/////P7///39/f////7//v7+//r9 + //////z////q/6GDWv91SAv/dz8A/4RKAv95QgD/ekcI/3RBA/97RQT/dj8A/4FIA/9vQQf/za+M//// + 7//7/v//9P3///v+////////////////////////////////////////+/////v////7/v///f3////9 + /////v////7////+///+/v7////1//Phwv9rSxr/dUcH/4JLBv93PwD/e0UE/31GA/97QQD/hEUA/4lN + Af9zQgT/bUoe//fm0f///Pf///////b4+f////7////+//7+/v/5+/z/+v7///j8///9//////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////7////9 + /////f////z+//37+v///vn////5////+f////n////6/////P////7//////////v////7////+//79 + +f/9/vr//f/8//3//v////7//////////v////z///75////+f///vb////5////+/////7//v3///b5 + /v/9/v/////8////+/////7//f////v+///7/v///f7////+/////v////79///9+f////z////8//7/ + /f/+//3//f/////////9/f3//Pz8/////////////v7+//39/f/8/Pz//Pz8/////////////f39//// + //////7//vz7//r6+v/9/////f////3////9///////////////+/v7//v7+//////////////////// + ///9/////f////3////9//////////////////////////////////////////////////////////// + /////////////////////////////////v//////+v7///v+///////////8////+f////n////+//v9 + /v/9/////P7////+/f/7+/v//f/////+9f/y27v/cksX/3NCAP+GTwb/fkQA/3pDAP98SQv/dUIE/35H + BP9+RQD/fEcI/35TIP//6sz////3//b9///x+v//+/7///////////////////////////////////// + ///7////+/////3+/////v////7////+/////f////7///7+/v////f////n/6OHXv9uRgz/d0QF/3dB + AP99RgP/fEYF/3pDAP+ARgD/hEoC/3ZCAP9hOQX/p49x////8f///v3/+//////+///8/Pz////+//// + ///7/v//+v3///3///////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////f////b4+f/////////////+/////P3//fv7//j6+v/6////9f39//X9 + /f/6/////f/////9/P///v3////+/////v/+/Pv/+vz8//v////6////9/z9//j9/v/7//////////r4 + +P//+/z///z9//78/P//////+/////v///////z////8//3////7/////f////3////////////+///7 + +v///v3///////3////7////+Pz9//b6+//7////9vr///r+///7/v//+/////r5+//+/v7////+//// + /v////7///////z+///7/v//+P7///P6///1/P//9v3///v+///9/////f////3////9/////f////// + ///+/v7//////////////////////////////////f////3///////////////////////////////// + ///////////////////////////////////////////////////////////////////9/////f////// + //////7////8/////P///v3///////v+///3+v7/+/3+/////v/9+fT////u/6SGXf9kPAL/dkYE/31J + A/96QwD/e0QA/3lEAf9+RwT/fEMA/3pEA/9wQQn/vZpv////7f///PX/+v7///P6///7/v////////// + //////////////////////////////v////7/////f/////+/////v////7////+/////v////////// + +P///Oj/7dm2/2xLGv9sQAX/fkgH/3xFAv97RQT/fEcE/39HAP96QgD/ekUC/3pMEv9jQxr/89/G///+ + 9//9////+vz9//r6+v////z////8//38/v/9//////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////9//7/+fz6/////////v////3////9 + /////v//+/7///r////4////+v////3//P////r////4////+P////j////4////+P////n////7//v/ + /v/5//7/9/////n+///9/v////7////9/////f///vv9///////7////9vv5/////v////7/+/////v/ + ///9/////////////P////v///77/////v/7/v//9Pr///j+///4/v//+/////3////9////+fv8//78 + +/////z///73////9f////X////0///68P////b////7//39/f/3+///9v3///T8///v+P//+v7///3/ + ///9/////f////3////9//////7////////////////////////////////////////9/////f////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////v////////////////////7////+///9/P//////+v3///b6///9///////8///9 + 7//q1bb/bEcV/3hLDv93SQn/cD4A/31IBf96QwD/fkMA/4BFAP95QgD/eUcL/29IG///5cb///3t///8 + 9//7/v//+f3///3/////////////////////////////////////////+/////3////////////////+ + /////v////7////+//////7////3////9P///uf/kHZR/2Y+Df96Rwj/fUQA/3tGA/93QwH/e0cF/3VA + AP+BSQL/e0cF/2k/Cv+pjWr////x///9/P/6/P3//////////P///Pf///////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////+//v/ + +v/9//z//f////n4+v///f////3///v7///6+///+Pr6//r79/////b////0///66P/869b/+OPN//vj + zf/95c//+eTO//nr1f//+Ob////z////+P////z//f////f4/P/9/f///f3///39///7/f7//P7+//3/ + /v/9//z//f////3////7/v//+/7///////////z////5////+f////v///////f9///z/P//9P3///j+ + ///9/vz//fn0////+P////X////y///45f//7NP//+zQ///qzP/54cP//+nN///w1f//++j////0//// + +//9/f3/+/7///r+///7/v///f////v+///7/v//+/7///v////9//////////////////7////+//// + /v////////////3////9//////////////////////////////////////////////////////////// + //////////////////////////////////////7////8/////v/9/////f////3////////////+//39 + /f/1+f7/+v7///3////+9+7////r/5x8Uf9zRwr/dEIA/3JDBf90RQf/fEgG/31FAP+HSQD/fkEA/3pE + A/9xRxL/mX1a////6/////j////+//j4+P/9//////////////////////////////////////////// + ///7/////f///////v////7////////+///9/v///f/////+/f////v////5////8f/dyq//Xj4V/3VG + Cf99RAD/eUQB/3dDAf9+Sgj/ekUC/39FAP96RAD/dkQI/3RQIv/l0bj////3/////P///fz///z4//// + /P//////+vz9//////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////7/+f34//3//P/9/////f////3+///4+f3//vv9/////P////j////y//Xj + zP+0n4D/gGZC/21QK/9nRh//XjsT/147E/9tTCX/fFw4/5F3U//ArI3/+OjR////8P//+u/////8//// + ///09/v/9/r+//v////7/f3//f/8/////P/9/////f////v+///7/v///////////P////n////4//// + +v/7+vz/9v3///T9///2/f///f//////+P////H////s//fix//Hro7/k3dU/3JSKf9nRRf/akQU/2dB + Ef9hPQ//fVsw/4ptSP+3n4H//+/a////9P/+9+7////7///+/f///////f////3////7/v//+/7///3/ + ///////////+/////v////z////8/////v///////f////v//////v////////////////////////// + /////////////////////////////////////////////////////////////////v////z////+//3/ + ///7/v//+/7///3///////7//f39//n9///6/v///vz8////9P/kyKX/c0kU/4BMCf9vOwD/eEkM/3VG + Cf91QQD/g0gC/4VFAP+ERwD/c0EF/2pFGf/l0bj////z/////P///////f39//////////////////// + //////////////////////////////3+/////v/////+/////P////////7///3+///9//////////// + /v/7+/v///75////8f+JcE7/c0YN/3xFAP96QwD/fEcE/31IBf9+RwL/fEIA/4NMA/9zPQD/bkIM/5l9 + Wv//79r////3//v38v///vr////+//z+///5/P///f////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////7//f/+//X6+f/7////+v/+//r7 + 9/////j////v/+7Vu/+phmT/b0Ua/24/DP94SRH/cEII/2s/Av91SQz/dEcK/2o9AP9wQAb/dUgP/2o/ + DP9wSx//spRx//7pzv///Ov////4//3//v/4/v3/+v////v////9/vz///79///////9////+/7///v+ + ///9///////8////+f////n////8//r8/f/1/P//9fz///r8/f////j///zn//rhwf+jg1r/dlIk/142 + Bf9tQw7/eUsR/3FAAv9zPgD/fkoI/3lGB/9wQQT/c0cR/2hCEv9mRh3/p4to//nhw////+r////2//// + +/////7///////3////7/v///f////////////7////8/////P////z////+///////9////+//////+ + //////////////////////////////////////////////////////////////////////////////// + //////7////8/////v////7//f////v+///9/////f////z8/P/9////+v7///v/////+/T///bf/5Ju + QP92RQf/e0MA/31FAP98Sw3/b0AD/3ZBAP+DSQH/gUEA/4VLA/9vQw7/lXlX////8v////v///7+//v7 + +//////////+/////////////////////////////////////////////f7////+//////z////8//// + /////v///f7///3/////////+/v7//r////9///////4/9nFrP9rRBD/eUcF/3lEAf98RQD/d0AA/4BI + Af+BRwD/e0MA/4BJBP9zRAf/akYY/9rBn////On////3/////P/8/v//+f3///r+///9//////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////r8 + /P/9////+f79//v//v/6/Pb////1///86f/HrY//d08l/3dFEf94PgP/f0IA/4JGAP+ARgD/eUYA/3lI + AP99SAD/fkcA/4JIAP+DRwH/fUEA/3U/Av91SBX/d1Uq/9K9nv//+OH////3//v/+f/7//7//P7+//// + ///////////////////7/v//+/7///3///////7////7////+/////7/+fz///j+///7/v/////5///9 + 6P/TtZL/dlAg/2xCDf9xQwn/dEUI/3dEBf93QgD/f0cA/4JIAP9+RAD/e0MA/4BJBP90QQL/c0QH/3FF + D/9gOAf/hGAy/9G1kv///+/////2////+v////z///////3////9/////////////v////z////8//// + /P////7///////3////7//////7///////////////////////////////////////////////////// + ///////////////////////////+/////P////z////+///////9/////f////3//////////f////3/ + ///6/f/////8////8v/MsY//b0UQ/3dCAP+ARgD/g0kB/3E+AP91RAb/gEkG/35EAP+DRgD/d0MB/3FM + IP/jzbT////3///////+/v7///////39/f/9/f3///////////////////////////////////////// + ///9/v////7//////P////z////+///////9/////f/////+/v/9////9/3///n9//////z////t/5Ry + R/9wQgj/dkIA/39HAP+CSAD/fEIA/4NLBP97RAD/ekUC/3ZFB/9zRg3/gV0v///11f////H///75//r9 + ///2/f//9f3///3+//////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////9////+/////r//v/9//7/+frx////9P//+uL/s5p4/2hDF/91Qgr/gEMD/4lE + AP+KRgD/iUcA/4VHAP+ASAD/fEkA/4BIAP+BSAD/h0cA/4lHAP+KRgD/hUUA/3xEA/9wQwr/bEse/7ej + gP///+f////0////+P////7/+fn5///+//////7////+//3////9/////f////////////7////+//r8 + /f/9////+fv8////+f//8t3/tph1/3FHEv93Rgj/dUQG/3dEBf95RQP/eUUC/3xFAv98RQD/fkYA/35G + AP9+RgD/fUYB/3tGA/93RAX/dEMF/3RFCP91Rw3/bkgY/6+Xef///+/////1///99v////z//v7+//3/ + ///////////+/////P////z////8/////v///////f////v//////v////////////////////////// + //////////////////////////////////////////////////////7////6////+///////+/7///3/ + ///9///////+///////9/////f////////////b//+nP/3tYLP9zRAf/f0gD/4VKAv94PgD/fUcG/3tH + Bf98QwD/e0MA/35HBP9uQQj/m4Be///87P////z//P7///////////////////z8/P////////////// + //////////////////////////////3+/////v/////8/////P////7///////3////9/////Pz8//3+ + ///4/v//+P7///////////H/3cOf/3NMGP95SAr/fkYA/4FHAP+BRwD/fUUA/3lEAf98SAb/c0AB/3ZD + BP9sPwb/v51y////6v////f/+/7///b9///2/f//+/7///////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////3////4/f7/+/////v79f////X///zl/7ad + e/9sShz/cUMN/3xEA/+FRQD/iUYA/4pGAP+HRwD/g0cA/35HAP98SAD/fkcA/4FHAP+FRwD/h0cA/4lH + AP+HRgD/gUYA/3lFA/9uQgz/bEsd/7ikgf///+n////1//369f/9////+fv8/////v////7///////3/ + ///9/////f////3////9/////f////n5+f////n///zq/7mefP9vRxb/g00M/3o/AP98RQD/ekUC/3pF + Av96RQL/ekUC/3xFAP98RQD/fEUA/3xFAP99RgH/fUYD/3pFAv95RAH/eUQB/3xHBP91Rw3/bE0m/7ij + iP////D////1////+P///v3///7///r8/f/////////+/////P////z////+///////9////+//////+ + //////////////////////////////////////////////////////////////////////////////// + /v////v////7//3////6/v///f////7+/v///v3////+//X3+P/////////5///34v+2l3D/bkQP/3dE + Bf97QgD/fkQA/4dMBv91PgD/fUgF/4JJBP97RgP/d0gL/3BMHv/izrX////3/////v/8/v///v7+//// + ///7/f7//f////////////////////////////////////////////////7////+//////7////8//// + /v////7//f////3////+/f///f7///n8///6/v///f39////9////+r/oIRb/25CDP92QgD/gUcA/4NJ + AP94QQD/ekUC/3lGB/92QgD/fUYB/4FNC/9oPgn/+t24////8v/5+fn/+P7///P6///7/v////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////f////j/ + ///0+ff////4////7//ZvZ7/bUgc/2Q1AP94QwT/fkUA/4BGAP+ARgD/fkcA/3xFAP96RQL/eUUD/3lE + Bf95RAX/ekQD/3pFAv98RQD/fEcA/3xHAP9+RwD/ekYA/3dEBf9mOgT/ck8j/+HIqP///+7////4//z/ + /f/2+/z////+/////v////7///////3////7////+/7///v+///9///////7///97f/YwKL/Z0MT/3RD + Bf96PQD/iEgA/4BGAP98RQD/fEUA/3pFAv96RQL/eUUD/3lFA/95RQP/ekUC/3pFAv99RgP/fEUA/31F + AP9+RAD/f0UA/3pGBP9eNgX/a04p/93Hq/////D////3/////P/+/f///f////////////7////8//// + /P////7///////3////7//////7///////////////////////////////////////////////////// + ///////////////////////////+////+/////z/+/7///n9///8/v///v/9////+/////v///////// + +////+//5sup/21FEf9zQgT/dUEA/31GAf99RAD/gkcB/4JJBP91PgD/gEkG/3RDBf9kPAv/q5Ft//// + 8f///vn///////3///////////////v9/v/9//////////////////////////////////////////// + /////v////7///////////7////+/////v/9//7//f////3////6+////P3///3+/////fz////5//// + 8v/p17r/d1Un/2w+BP9+SQb/f0cA/3tEAP96RQL/dkEC/3tHBf+ASAH/eEEA/3BBBP+Tb0H//+7V//// + +P/6/P3/+v7///3///////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////9////+P////3//P////T/+OHH/4FdNf9wQAz/fEUI/4JJBP98RgD/ekYA/3dG + AP91RgL/dUUF/3VEBv93Qwf/d0IJ/3dCCf91Qwf/dUQG/3NFBf9zRgL/dUcA/3pGAP98RgD/e0QA/39K + C/9uPwv/h2M7///x1v////P////8//r////9/////////////v////7///////3////6/v//+v////// + /v////X///HW/3RUK/9yRQz/fkcC/4dHAP+LSQD/gUcA/35GAP9+RgD/fEUA/3pFAv96RQL/eUUD/3lF + A/95RAH/ekUC/31GAf9+RgD/f0UA/4BGAP+CRgD/fUUA/3hKEP9hOwv/iGtG//vmy/////T////7//z8 + /P/7/v///f////////////7////8/////v///////f////3///////////////////////////////// + ///////////////////////////////////////////////////////////+/////v/6/f//+v3////+ + //////7////8/////P////z////z///s0P+RbkL/ckMG/3Q/AP98RwT/fEcE/31GA/98QwD/gUYA/31G + Af94QwT/b0MN/21PJv/55sv////1//j38////////f///////////////f////r8/f////////////// + ///////////////////////////////9/////v////7///////////z////8/////v/9/////f7///r7 + /////v/////+///++/////v/+vjw////8v+0m3n/aUMT/3FCBf97RgP/fUYB/3tFAP94QwD/ekUC/3Y/ + AP99SAX/ekcI/2g+Cf+8n3r////q////+f/5+fn///////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////3////4/fz////5////7f+1mXf/aj4P/3pE + CP98QgD/gkgA/3xGAP93RgD/cUYD/3BFBv9xRAf/c0QH/3dDB/95Qwf/d0MH/3VDB/9xRAf/cEQH/3BF + Bv9xRgP/d0YA/3xGAP9/RQD/fUQA/3hCBv9pPxD/x6yK////7f////n/+P79//v+///9///////+//// + /P////z//f////r////7///////6////8f+3m3j/bEQQ/3NAAf99QwD/hUgA/4NGAP+BRwD/gEYA/4BG + AP9+RgD/fkYA/3xFAP98RQD/fEUA/3tEAP9+RgD/f0cA/4FHAP+BRwD/gUcA/4NHAP+ARgD/eUQB/3RG + DP9kQBL/v6SC////7v////n///////j7///7/v///f///////v////7////+///////9/////f////// + //////////////////////////////////////////////////////////////////////////////// + ///9/////f////7+/v///////////////v/////////8///58P///un/uJhv/2o+CP+CTQr/e0MA/3xH + BP94QwD/fUYD/35FAP99QgD/e0YD/3xMEv9gPAz/wquL////7v////f////7///////5+/v//f////v9 + /f/9/////f39//////////////////////////////////////////////3////+///9/v///f////// + /P////v////8//3////6/f///f7//////v//+/b////5////+//6///////7//np0v+DZD3/YjoG/3RD + Bf98RAD/f0UA/4JKA/96QwD/e0YD/3xIBv94RAL/c0UL/3NNHf/ky6v////y////+/////7///////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /v////b///Pd/3FRLf91RhL/cTsA/4NJAf99RAD/fEcA/3dGAP9zRQX/cUUG/3NEBv91RAb/ekQD/3xE + A/96RAP/d0UD/3NEBv9xRQb/cUUG/3NFBf95RgD/fkcA/4JIAP+CRwD/d0EA/3dIFP93VzP///vk//// + +P/09vb/+v7///v+//////7////7////+/////7/+/////3///////j///Ha/3lXLP90Rgz/ekMA/39E + AP9+RQD/fUQA/4BFAP+ARgD/gEYA/35GAP9+RgD/fkYA/35GAP9+RgD/fkYA/35GAP9+RgD/f0cA/39H + AP9/RwD/gUcA/4FHAP97QQD/fUgF/2xCDf+CYzz///Db////9///////+fz///v+///7//////////// + /v////7////+///+///9//////////////////////////////////////////////////////////// + /////////////////////////f////v+///7/v////79/////P////7///////3//////v3////0/9C4 + mv9yShb/eUYH/3tDAP+DSQH/ekUC/3dBAP98RQL/f0YB/4RJBP9zPwD/bEIN/39hOP//++H////y//// + +f////z//f////j8/f/7/v//+Pz9/////////v3///////////////////////////////////////// + /////f////7///v+///7///////8////+/////z//f////n8///9/v/////8///88/////f////6//T+ + ///x+v3////0/8uzlf9xTyT/bUAH/31FAP+DRwD/g0kA/35GAP91QgP/d0YI/287AP93RAX/dUgP/4hm + O//+7NX////3/////P////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////7+////9v/RuaH/ZEQb/2c8A/97SAL/hE0C/39HAP9+RwD/fEYA/3lF + A/95RQP/ekUC/35GAP+BRwD/gUgA/4BIAP9+RwD/ekYA/3lFAv95RQP/ekQD/35GAP+ARwD/gEQA/39G + AP98SQP/aT4F/2JCGf/k0Lf////3///////4/f//+P7///////////v////5////+//9///////+//// + 9f/Yw6f/aUEQ/3NAAf+CSAD/iE0H/3dCA/93RAb/ekUC/3xFAP98RQD/fEUA/3xFAP98RQD/fkYA/35G + AP98RQD/fEUA/3pFAv96RQL/eUUD/3pGBP94RQb/fEUA/4lLAP+ARgD/dEUI/2ZEGf/axq3////1//// + /v/7/v//+v7///v+/////v///////////v////7///7///3///////////////////////////////// + ///////////////////////////////////////////////////9////+P7///n9//////r////5//// + /P//////+Pz///v7+//26Nb/dFcy/3FDCf98RAD/g0kA/31DAP9+SQb/d0MB/3xCAP+DSAP/f0YB/3lG + CP9uSBj/3sOh////7/////f////3////+//7/f3/+/7///j+///6/f/////+////+/////7///////// + ///////////////////////////////9/////v///f7///v///////7////8/////P/9////+/7////+ + /////fr////5////+P////v/8Pr///T//////vn////w/5FzUP9qQg7/fkkG/4JIAP93PQD/gEkE/3xH + CP92QwT/f0oH/3pFAv90QwX/a0EM/52AW////+r////5//////////7////+///////9/////f////3/ + /////////////////v////7////////////9/////f////////////////////////////////////// + /////////////////////////////////////////////////v///Pz///3y/6OHaP9oQhL/c0QG/35K + A/96RgD/f0gA/35HAP9+RwD/fkYA/35FAP9+RgD/gEYA/4FHAP+BSAD/gEgA/35IAP9+RwD/fkYA/4BF + AP+ARQD/gUYA/4FHAP+BSAD/fkcA/3lFAP9yRgf/ZkIS/7mggP//9+v///7///v9///7/f/////+//// + +/////v////8//3///////7////0/6yTc/9pPQf/e0cB/4NJAP94PgD/fUoM/3E/A/95RAX/ekUC/3xF + Av98RQD/fEUA/3xGAP9+RgD/fkYA/39HAP98RQD/eUQB/3lEAf95RQP/d0QF/3dEBv96RQL/f0UA/4FH + AP90QQL/akIR/62UdP///+/////8//r9///7/v//+/7///3///////////////////////////////3/ + ///9/////f////////////7////+/////v////7////////+/////v////7////////////////+//3/ + ///4/v//+f7/////+v////n////8///+/f/7+/v///rx/493W/9jPQ3/fUkH/4BGAP+BRwD/g0kB/3VA + AP98RgX/gEcC/3hBAP9+SAf/bD8G/6yMY////+r///3w////+f////n///76//3////6/v//9vr///v+ + //////7////8//////////////////////////////////////////////7////+/////v///f////// + //////7////+///////9/////////////v////7////8/////v/7////+/7///7+/v////f/9du9/4Rg + Mv9sPgT/fEcI/3hDBP91QQD/fUYD/35HAv+CRwH/fEMA/3lEBf9xPwP/eEoU/8uqg////fP/+vz9//// + /P///vr//f39//r9///4/v//+P7///3///////7////7////+/////7//f////v+///7/v///f////// + ///////////////////////////////////////////////////////////////////////////+//// + /v//9eX/jGlB/3NDCf+BSAP/fkQA/3tEAP98SAL/fkcA/4BHAP+BRwD/gUcA/35GAP98RQD/ekUC/3pF + Av95RQL/eUUC/3xFAP9+RgD/g0cA/4VHAP+DRgD/gEYA/3lFAP97RwH/fEUA/4BMBv9rPQP/ooJZ///7 + 6////v3///7////+//////z////8//3//v/7/////f3////+////9un/jW1K/3VHDf99RgD/hEcA/4dM + AP9+RAL/ekMG/3lFA/95RQL/ekUC/3xFAP98RQD/fkYA/4BFAP+ARgD/gEYA/4BGAP9+RgD/fkYA/3xF + AP96RgD/ekUC/3pFAv98RwT/d0IA/3xHBP9yQwb/knBF////6v///fb/+/////v+///7/v///f////// + ///9/////////////v///////f3///v9///7/v///f//////+/////n////7/////P////////3////9 + /////f////7///////////v////7//3//v/8//3//vz7/////v////v////4///55/+3ooP/a0QX/3A+ + Av+DSAL/f0IA/4FIAP9/RwD/fUUE/3lBAP9/SAP/eEQB/29DCP+HZTf//unK////7f////n////+//// + /v/9/////f////3////9/////f////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////v///P3//////P///+7/xqiF/3dPH/9rPAT/c0EF/3xGBf95QAD/fEEA/4BFAP9/RgH/gUoH/35I + B/9uOQD/gFcm/+HQu/////j///32////+///////+/7///j+///2/P//+/7///////////z////7//// + /P///////f////v+///9//////////////////////////////////////////////////////////// + //////////////////////7////8///14/9+Vyr/dkEC/35CAP+FSgL/ekQD/3lEBf98RQD/gEcA/4FI + AP+BSAD/fEYA/3pFAv95RQP/eUQF/3dEBf95RQP/ekUC/35HAP+FRwD/hUcA/4FHAP98RQD/d0QF/3hE + Av+ESgL/fUYA/3RBAv+QbD7///vp/////P///v////7//////P////z/+/////r////9/f////7////u + 3/+KaET/b0AD/4BIAP+GSgD/gkcA/3tBAP9+SAn/ekQD/3pFAv96RQL/fEUA/35GAP9+RgD/gEYA/4BG + AP+ARgD/gEYA/4BFAP9+RgD/fkUA/3xFAP98RQD/ekUC/3VCA/96RgT/f0gD/3A9AP+AWir////p//// + 9//8/v//+/7///3///////////////3////9///////8/////v/9/f//+/3///v+///9///////7//// + +f////v////8/////////v////3////+/////v//////////+/////v////8//7//f/9//////////36 + 8v////H/07qa/3NPIf9zQQX/f0YB/4dMBP9+RAD/fkYA/3tEAP9/Rwb/fkgH/3RAAP94Sw7/aEMR/9a7 + lv///+3////3//38+P/9////+/////3///////////////////////////7///3///////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////+/f/////+///99P///+z/nHtU/2tADf92QwX/fkUA/4JJ + BP9/RgH/f0YB/31EAP96QQD/gUoH/3VCBP9sQAv/gGA8//Tgx/////b////+//r8/f/4+vv//f////3/ + ///7/v//+/7///3///////7////8/////P///////f////////////////////////////////////// + /////////////////////////////////////////////////v////z///Xj/3JOIP92QQL/f0MA/4RI + Av97RQb/dkMF/3lFA/96RgD/fkcA/35HAP98RgD/ekYA/3pFAv96RQL/ekUC/3pFAv98RQD/fkYA/4FH + AP+BRwD/fEUA/3lFA/91RAb/dEEC/4FJAv97QwD/d0QG/4BcLv//+Ob////8///+/////v/////+//// + /P/9/////f////3+//////z//enY/4ZkQP9vQAP/fkcA/4NIAP9+RQD/d0ID/3pGCv96RAP/fEUA/3xF + AP98RQD/fkYA/35GAP9+RgD/fkYA/35GAP98RgD/fEUA/3pGAP96RQL/ekUC/3pFAv96RQL/d0IA/3xH + BP+ASAH/cD8B/2xIGv///+r////5//r9///7/v///f///////////////f////////////7////+//3/ + ///7//////7///////////7////8/////P////7///////3////9/////f////3////////////+//// + /v/9/f3//f////T7/v/9//7////1/+vVuf+IXzL/cj4C/3xGAP+DSwD/gUcA/35DAP+ESAb/fEIB/3lD + Av9yQgL/cEQJ/2Q/Df+tkGn///vf////8v////n///////v+///7/v///f////////////7////+//// + /v////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////+///49/n///////// + 9//238X/gVww/3lHC/97QgD/fEMA/3xDAP98RQL/f0gF/3pBAP96QwD/e0gK/3NEDP9lOgf/lXVM//7t + 2P//+vH////+/////////fz///////v+///6/v//+/7///3///////7////8/////P////7///////// + ///////////////////////////////////////////////////////////////////////////+//// + /P//9eP/dVIm/3hFB/+DSAL/f0MA/3pEBf90QwX/d0QF/3dGAv96RgD/fEcA/3xGAP98RQD/fEYA/35G + AP9+RgD/fkYA/3xFAP9+RgD/gEYA/35GAP96RQL/d0QF/3VEBv92QwT/e0MA/39HAP93Rgj/hGE1///1 + 4////v3//f7///3+//////7////8/////v//////////////+f/97Nn/gmI+/3VHDf99RQD/f0UA/4BI + Af94Rwn/cEEE/3pFAv98RgD/fkUA/35GAP9+RgD/fkYA/35GAP98RQD/fEUA/3pFAv96RQL/eUUC/3lF + A/95RQP/eUUD/3pFAv98RQD/f0cA/35FAP93SAv/a0ke////6////fj/+/7///v+///9///////+//// + /v///////////////v////7////+/////v////7////////+/////v////7//////////////f////3/ + ///9/////f////3//////v////7////+///9////9fr5////+P//79j/gmE6/3ZDC/+ARQD/h0wA/4BI + AP98QgD/gEcC/4FHBv95QQD/e0cF/3BDBv9lQA7/fWA5///w0f////D////2//78+//7////+P3///v+ + ///9/////////////v////7////+//////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ////////+vz9//v+///1+///////////8f/ixqT/ckYR/3pFBv97RAH/fkUA/3tEAf9+RwT/f0gF/3dC + AP95RAX/dUIE/3xJCv9qPgj/n4BZ///34P////X////8//f39//9////+/7///v+///7/v//+/7///3/ + //////7////7////+/////7///////////////////////////////////////////////////////// + //////////////////////7////8///05P99WzD/eEYK/4FGAf+ARAD/d0EA/3lGB/91RAb/dUUF/3lF + Av96RgD/fEYA/3xGAP+ARgD/gEYA/4BGAP+ARgD/fkYA/35GAP98RQD/ekUC/3dEBf91RQX/eEUH/3tH + Bf99RQD/fkcC/3VGCf+Uckf///bm/////v/7/v//+/7//////v////z////8/////v////7////4///1 + 3/+BZD//d0oR/3pDAP9/RQD/f0gD/3VIC/9tQAP/ekUC/35HAP+ARQD/fkYA/35GAP98RQD/fEUA/3pF + Av96RQL/eUUD/3lFA/95RQP/eUQF/3dEBf93RAX/ekUC/4FHAP+BSAD/ekMA/3RHDv95WjP////t///+ + +v/7/v//+/7///////////z////8/////////////////////v////v////5/////P////////7////+ + /////v////7///////////7////+//3//v/9/////f////3+///9/v//+vz9/////v////j///Lf/41x + Tv9qQg7/d0MB/4BDAP+ISQD/g0YA/4FGAP+CSQT/dkEA/3hEAv9/Swn/c0YN/2tOJ//Ww6j////w//// + 9/////z/+/////j+///4/v//+v////3////////////+/////v////7///////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////3////7/v//+f3///b9///7/v/////5////6/+4lmv/bT8J/3pF + Bv+ASQb/e0YD/3dCAP97RgP/eEMA/31IBf98RwT/ekMA/3ZDBP9vRRD/spNs///z3P///fP////+//r8 + /f/9/////f////v+///7/v//+/7///3///////z////7/////v////////////////////////////// + //////////////////////////////////////////////////////7///jq/45vSP9zRAz/eUAA/4dM + BP94PgD/fUkH/3dEBf91RQX/d0YC/3lGAP98RgD/fkYA/4BGAP+BRwD/gUYA/4BGAP9+RgD/fkYA/3xF + AP96RQL/d0QF/3dEBf95RQP/e0YD/4RKAv92PwD/cUQL/6qLZP//+uz///////j////6///////+//// + /P////z////8/////P////j///3n/5J4VP9uQgz/eUMC/4JHAf98RQD/c0QG/3JGB/96RgD/gEYA/4BG + AP9+RgD/fEUA/3xFAP96RQL/ekUC/3lFA/95RQP/eUUD/3lFA/95RQP/eUUD/3lFA/98RQD/gUUA/4NJ + AP95RAH/akAL/5Z7Wf////L////+//r9///9/////////////P////v////+///////9//////////// + +f////n////8///////9////+/7///v+///7/v///f///////v////7////+///////9/v//+/7///v+ + //////z////1///24f+mh2b/aEAQ/3FEB/9+SwX/gEcA/4JGAP+FRwD/hkgB/4BIAf92QgD/eUcF/3RB + A/9rQw//t6KD////8v///vP////7//r+///4/v//9vz///j+///7/v///f////////////7////+//// + /v////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////f////r+///x9fr/+f3///v+ + /////f3////3///x1v+Xd07/cEMK/3RAAP98RwT/ekUC/3tHBf94QwD/f0cA/35EAP96QwD/fkkG/31J + B/9uQQj/w6R9////7f///vX///////3////9/////f////v+///7/v//+/7//////v////z///////// + /////////////////////////////////////////////////////////////////////////f////z+ + /v////X/up99/2xCDf96QwD/h0kC/31CAP+ARwL/eUUC/3dGAv95RQL/eUYA/3xGAP9+RgD/gEUA/4BG + AP+ARQD/fkYA/35GAP9+RgD/fEUA/3pFAv96RQL/ekUC/3pDAP9+RgD/gUcA/3VAAP9vRRD/0baU//// + 9f/7////+P////r///////7////8/////v////7//f/+////+f////D/v6uI/2c+Df95Qwb/gUYB/4BF + AP91RAD/d0gE/3xGAP+ARgD/fkYA/35GAP98RQD/fEUA/3pFAv96RQL/ekUC/3pFAv96RQL/ekUC/3pF + Av96RQL/fEUA/4BGAP+ERgD/gkgA/3dEBf9pQxP/wKqO////9f//////+fz///3///////7////7//// + +/////7///////v+/////v/////7////+f////z////+//j////2////9v////j////9/v////7////+ + /////v////7///3////6/////f/+////9f//+d//s49p/3lKF/99Sgz/cT0A/3dHBf92RAL/fEUC/4FG + Af+DRQD/fkUA/3xIAf93RwX/c0YN/6OAVf//897////4////+v/9////9vv+//j+///4/v//+P7///v+ + ///9/////////////v/////////////+/////v////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///9////+v3///v+///8/v///f////3//////Pv////1//Hcwf+DXjL/b0EH/3dEBf97RgP/e0cF/3tE + AP+ESgD/gUcA/31GAf94QwD/f0gD/3M/AP9zSRT/yq2I///96P////j////+//3////9/////f////3/ + ///9/////f////3///////////////////////////////////////////////////////////////// + ///////////////////9////9/z/////+f/kz7P/Z0ER/4FMDf98QQD/g0YA/4BFAP98RgD/ekYA/3pG + AP96RgD/fEYA/3xGAP9+RQD/fkUA/3xFAP98RQD/fkYA/35GAP9+RgD/fEUA/3xFAP9+RgD/gEYA/4RK + AP96QAD/fEkK/3BJHP/44sb////5//n+///4////+v///////v////z////+///////6////+//8//// + 9P/q2r3/Z0IW/3VDCf9+QgD/hUoC/3tGAP95RgD/fEYA/35GAP9+RgD/fEUA/3xFAP98RQD/ekUC/3pF + Av96RQL/fEUA/3xFAP98RQD/fkUA/35GAP9+RgD/gEcA/4dJAP98RQD/ckML/2xMI//k0rv////4//// + ///7/v///f///////v////v////7/////P//////+/7///3+/////v7///78/////P/9//7/+P////T/ + ///0////9v////v+/////f////3////9/////v/////+//3//P////f////o/7mac/90RRH/dkAA/4JH + Af+BSQL/dUMB/3JDBf91RAb/e0UE/35DAP99QwD/fEgF/25CBf+FYTP//+nJ////9P////v//P37//3/ + ///6////+P3///r////6/////f/////////////////+//////////////7////+//////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////9/////////////P////7//f////3+///////////1/+bO + sP9sSBr/dUcN/3lFA/93QgD/fUUA/4JGAP+GSgD/fUYB/3pGBP94QwD/eUUD/3ZDBP91SRP/tpdw//// + 6/////f///////3////9/f3////+//v7+//4/P//+v7///3///////////////////////////////// + //////////////////////////////////////////////3////3/f/////+////7P+La0L/azsB/4ZL + Bf+GSAD/hUcA/35FAP+ASQD/fkkA/3lDAP98RAD/fkcC/35HBP94QgH/eEQC/3pFAv98RQD/fUUA/31F + AP+ARgD/gEYA/4FHAP9+QgD/jlIG/31FAP9vQQf/nn1W////6v////7/+P7///r////9//7////8///+ + /v///v////7///j////4///////4///64v+UdU7/cEEN/3k/AP+KTQP/fUQA/31HAP94QgD/f0gD/35H + Av95QgD/ekMA/3tEAP97RAD/fEUA/3tEAP9/RwD/g0sE/4JLAv9+RAD/fkQA/4FHAP9/RgD/f0QA/31J + B/9nPw7/lntZ////7f//+/b///////v+///9///////+/////P////z////+///////6/v//+/7////+ + /////v/////+//3//v/6//7/+P////b////2////+v3///38////+v////3////+/f////n////0//// + 6f+niGH/d00Y/3NBAP9+RwD/gkUA/4RJAf94QgH/eEcJ/29CBf91Rwf/fkoE/3VAAP95Rwv/d08f//LZ + t/////D////4/////P////7//f////3////7////+/////3////9//////////////////////7///3/ + ///9/v///f////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////v////z////7//// + /P/9////+v7///r+//////7///7u/9C3l/9mQBD/dUYJ/31IBf+GTAT/fEIA/3xCAP95RAH/eUUD/3hE + Av98SAb/fUYB/3E+AP+KXij/t5hx////7f////j//Pn1///+/f////z///////f7///6/v///f////// + /////////////////////////////////////////////////////////////////////////f////b8 + ///8/v7////0/9nAoP92TRz/cz4A/31CAP+ESAD/gUgA/3tEAP96QwD/gEkA/4JKA/98RQD/eEID/3pE + B/93RAb/dUMB/3tEAP+BSQL/gkgA/31DAP99QwD/gkgA/4hMAP92PAD/eEUG/3dPHv/oz6/////0//// + ///0+v//+//+/////P////z////+///+///9/v//9v////b////6/vn////y/+XJqv9zSxv/dUIE/3k/ + AP+HTgD/g0sA/31GAf96RgT/eUQB/3pFAv+BSgX/gEkE/3xFAP98RAD/fUUA/3tDAP98QgD/fUMA/35E + AP+CSAD/g0kB/31FAP99SAX/ZjkA/21NJP/k0Lf////1///++v/6+vr//f/////+///////////+//// + /v////7///////v+///7/v////3////9///////////+//3//P/7//7/+v////r////4+///+/z///78 + /////v/////5////8v//+OH/sZh2/3BIFP9yPwH/fEgB/39IAP+BRQD/g0YA/3tAAP95QwL/dEYG/3BE + BP9wQgL/cEII/3FHGP/cvpv////w////9/////v////8/////P////7////+/////v////////////// + ///////////////////9/////f////v+///9//////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////7////7////+f////z////+//3////7/v//+P7///v+/////Pj////y/66Sb/9vRRD/eUUD/3tD + AP99RgH/fUgF/3lFA/93RAX/dUID/3lFA/99RgH/d0AA/3NAAf92ShT/x6iB///33v////X///z3///+ + /f/9/f3//f////b4+f////////////////////////////////////////////////////////////// + ///////////////////9////+P7///b6+/////j///3o/6F9V/95Shb/eEIB/4BIAf98RAD/gEgB/4JL + Av9/SAD/fkQA/3pDAP95Qwb/d0UJ/3JDBv93Rwf/fEUA/3xCAP9/RQD/hkwE/4JKA/96QgD/fUUA/35K + CP9uRA//sZJr///85////vX//f////r9//////7////7/////P////7///7///v+///2/v//9v////v/ + //////f///ji/6B/WP9qPgn/fEgG/4BJAP97RAD/ekYD/3ZDBP92QgD/eEMA/3pDAP94QQD/e0MA/4BG + AP+HTQX/gUcA/39FAP+BRwD/gEgB/35GAP98RAD/eEMA/3RGDP9sSBr/o4tt///25v///vf////+//// + /v/5+fn///7///3//////////////////v//////+/7///r+///6/f//+v7///3///////7////8//// + /P////7//f////r+///6/v///f//////+v//++v///vi/7icef9lPhH/bjwA/39IBf98SAL/eEIA/39F + AP+DSAD/hEcA/4RJAf99SQP/dUUF/25GDP9qRxv/tZt9////8f///fX////+/////P////z////8//// + /P////z////8/////v////7////+/////v////////////3////9/////f////3///////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////v////n////5/////P///////f////v////6/v//+v7///v+ + /////PX////o/558Uf9zRQv/eUUD/3ZDBP91RAb/eEUG/3dFA/95RAX/eEQC/3lEAf9+RwL/fUYB/3VC + A/9ySBP/uJhv///54P////X////7/////v////z////8/////v////////////////////////////// + //////////////////////////////////////////////3////6////9/z7///++v////X/+eDG/4Je + Nv9xQg7/dEMF/3xJCv90QAD/czwA/31GAP+ESgL/f0YB/3hCBf92RAr/ckII/3VEBv9+RwL/g0kB/35E + AP91PgD/dUEA/3tICf9zQgT/bUMO/4lpQP//7dH////1//369v/9/f3//f///////v////z////8//// + /v///v//+/7///j+///4/v//+/////v38v////L//ujM/4dlOv9vQw3/cUEB/3xIBf91QgP/c0MD/3pF + Bv9+SQb/f0gD/4BIAf+DSQH/g0kB/3k/AP9/SAD/gUkC/3tEAP94QwD/eEQC/3hFBv90Rgz/ZDwL/39j + QP/669j////4//v49P////7///76/////v///////f////v+///9///////////////9////+/7///j+ + ///4/v///f///////v////z////8/////P///v3/+/39/////v////n////y///94v+qjWj/bkUY/3BB + Cf98RgX/gUgD/3hBAP97RAH/g0oF/4JIAP+BRQD/fEIA/3xDAP9uPwL/Z0MV/6OMbP///+///vvz//// + ///7///////+/////P////z////8/////P////z////8/////P////7////+/////////////f////3/ + /////v////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////+////+/////v///////3/ + ///9/////f////v////7/v//+v7//////v////L///TW/5t4TP9xRxL/bkIM/3FDCf93RAX/eUQB/35H + Av99RgH/eEMA/3lFA/97RwX/dkIA/3VBAP95SxH/poZd///33P////T////7////+f////j////+//// + //////////////////////////////////////////////////////////////////////////////r7 + +f/9//7//f/////++v////T/9N3D/3JRKv9qQhL/a0EM/3JGC/96SAb/fUcA/4BHAP+BRgD/eUQF/3JA + BP9wQQT/dkME/39HAP+CSAD/gEgB/3xIBv9zRQv/a0EM/2lDE/91Vi//++bL////9P/9+fj//f////// + /v///Pv////+/////v////7///////3////9/////f7///3+///6+///////////+f////L/8dzA/3pb + NP9mPg7/bT8J/3hJDP91RQX/d0ID/3dCAP93QAD/fEQA/4BGAP97QQD/gEgB/4BKA/94QwD/cD0A/3NE + B/90Rw7/b0MN/2c/Dv9/Yj3//+3U////9//7+fj////////+/f////v////6///////7/v//+v7///v+ + ///////////+///////9////+v////r////9/////////////v////z///77///++////vn///zx//// + 8f//9Nf/m35X/2pCEf9yQgj/fEcI/3tGA/94QQD/ekAA/4FHBv98RQD/eUMA/39IAP9+RwD/fEYH/29C + D/+dgV////Th////+P/6/////f////z+///////////+/////v////z////8/////P////7////+//// + ///9/////f////3///////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////7////8/////P/9////+/////3////9/////f////3////1+Pz////////+9/////H//+rM/45u + Rf9oRBb/az8J/3lFA/98RAD/fkYA/31GAf94RAL/dkME/3hEAv93QgD/f0cA/4BLCP9rPwn/k3NK///s + 0///+ev////4///9+P////7///////////////////////////////////////////////////////// + //////////////////////7////7//7/+//5/f//+Pz/////+/////X/+uPJ/4psSf9iQBX/aEAP/25B + BP92QgD/e0IA/35DAP95QwL/eEUH/3dFCf94RAL/fEIA/31DAP95QgD/cEEE/2hAD/9jQRb/iGxJ///z + 2P///O/////8//j8///6/v/////7////+////v////7///3////9/////f///////////v////7////7 + /////v//+vr6////9////+7/9+PK/35iQP9sRxv/b0IJ/3BAAP95RAX/fkkG/3pDAP9+RgD/hUsD/4JI + AP99RQD/eEMA/3hFBv96TBL/cEYR/183Bv9tSRv/j3BJ///s0P////D////+//j7///7/v/////////5 + 8v////n///////r+///4/v//+v7///////////7////+/////v/+//3///////////////////////// + /v////v///73////9f///+3/9N7C/4tsRf9jOwr/cEMG/3pFAv94QQD/fUkD/3hDAP9/RQT/f0UD/3hB + AP94RAD/fUkC/3lHBf9wQgz/o39X///z3f////j/+//+//T8/P/9////+fn5///////9/////f////// + /v////7////+/////v/9/////f////3////9/////f////////////7////+/////v////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////9/////f////3////9////+/////v////9//////////// + /v////z//v35///79P////L/++jN/4dnPv90SBL/f0cA/4FFAP99QwD/e0QA/3pGBP94RQb/ekYE/3xH + BP9+RwL/dD0A/3ZCAP92SRD/i2k+//Hcwf//+O/////+//////////////////////////////////// + /////////////////////////////////////////////////P///vX////7/+/3/v/z/P//+v3////7 + +v////T//+vS/66Vdf9/XzT/ZTwF/3dFA/+ITwT/f0UA/3dAAP+BTA3/fksN/3ZBAP+ARgD/iU8E/3hE + Av9pPQf/g2E2/62UdP//8tn///zu/////v/y+P//9P3///X7//////v////2///+/////v//+/////v/ + ///9//7////+/////v///v////7///r5/f/6/v//+v//////+////fD///De/6mKaf9/VSD/dUUF/3dC + A/+ASwj/fkcC/3xEAP9/RQD/ekIA/35HAv94RQb/cEEE/2c9CP9lPw//eFYr/7+gef//9tj////v///9 + 9P/6/v//9v3///r+///////////5////+f//////+P7///b9///4/v///f///////v////z////7///+ + +v////z////+//v////4////+f/+//v/+v////b///zr/+LHrP+NaEL/b0ER/3JABP9+SQb/fkoA/31G + AP94QQD/eEAA/39IBf99RgH/gUkC/35HAv9zPgD/cEQO/4hqQf//7NH///7x/////P/9/f3/+/39//// + /P////z//f////v////7/////f////3////9/////f////3////9////+/////3////////////+//// + /P////v////8/////v////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////f////v////7/////f////3/ + ///7////+/////3///////////76/////P/////////+///9+P////T//+/T/4ZjN/92QwT/f0cA/3pF + Av96RgT/e0cF/3lFA/94QwD/fEUA/3pDAP+BSgX/fkYA/3hEAv9pPwr/clMs/8u6pf//+vD////5//// + /P////z////+///////9/////f7///3+///9/////f///////////////f////3////9//////////// + +f///vn/+P7///L7///0+///+/7/////+/////T////t/+vXuP+xk2r/g1wo/3JECv9zQwn/cUMN/2s+ + C/9kPAj/cEYR/3VHDf9uQQj/gFgn/7eXbv/x2bv////r////9P////v/+/7///b9///z/P//+v7///// + +v////n///7////+///9////+/////3//v////z////+///+/v///v////7///X7///z+f7/+/////// + /P////j////s//LTrP+0j13/fFQj/21FEP9sQAr/bkEI/3NFC/9wQwr/aT0H/3JKFv9tRhn/d1Qs/7SW + c//33b////7k////8P////f////+//r+///4/v///P7////++v////j///73///////6/v//9v3///j+ + ///9///////+/////P////z///77///+/v///////f////v////8//v////1////7v/MspT/eFQs/2o5 + B/96RAj/f0UD/4BGAP98RgD/f0kA/4BIAf9/RgH/fkgB/3RAAP96RQL/eEUH/29DDv+LaED/9uXK//// + 9P////7/+fv8//79//////7///v2////+//9////+/////v////9/////f////3////9/////f////3/ + ///9/////f////////////7////8////+/////z////+//////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////f////3///////////////3////9/////////////////v3////+///////+/v7////+//// + +///+vH//+/Y/4ZjN/91SA//bj8C/3dEBf96RQL/gUkC/39FAP+BRwD/fkYA/31GAf98RwT/c0AB/3NF + C/9lPQn/cU0f/7KWc///+uX////1////9v////z//P7///j8///4/f//8vf///r9///6/f//+/3+//z+ + /v/5/f7/+f7///j+///5/P/////+/////P///v//+/7///v+///7/////f///////P////j////1//// + 8P//79j/4s2y/72lif+ghWr/jXRa/4p1Wv+YhGv/uaSJ/97Ksf/+7dj////x////9/////n////8//// + ///9////+/7///v+///9///////8/////P////////7////////9/////////////v////////////// + /////v///f////3////9///////+/////P////n////y////6v/46tT/1MWr/7KfhP+bhmr/jnla/4py + VP+ji2//u6SK/+LMs///8Nv////w////9P////X////5///////9/////f///////v////v////5//// + +P////n////+//v+///6/v//+f3///j6+//////////8///+/f///P///vz////+/////f3///z3//// + 9P//9Nv/rZJt/29HF/9zQwn/eEMA/4JIAP9/RQD/fkQA/4NLAP9/SQD/gUcA/39HAP99RgD/eEQA/3dI + Cv9pQQz/hmdA//jky/////f//f////j9///2/f//+/7///////////v////7/////v/9/////f////// + //////////////////////////////////////////////////////7////+/////v////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////7+ + /v////////////7+/v///////////////////fP//+zO/5BuQ/9qQhH/ckQK/3pGBP98RAD/gUcA/39F + AP99QwD/eUIA/3pGBP91RAb/eUoN/3VGCf9rPAD/c0kU/4xtRv/u173////w///+9P////7/+/7///X7 + ///4/v//9vn+//z9//////////////3////6////+P7///f7///////////8/////v///////f////v/ + ///6////+v////n9/v/9///////8////+/////n///70////8v////T////1////9f////b////5//// + +/////z////+//39/f/9/////f////3////9//////////////////7////+//////////////////// + ///////////////////////////////////////////////////////////////////+//3////8//// + /P////j///zz///98/////P////z////9f////X////3////+P////n///34///9+v////7///7///3/ + //////7////8////+/////v////8/////P/9/f3/+Pr7//r9///7/v///f////7+/v////7///////39 + /////v////38////+P////H/8dm9/4RkO/9jOwf/ckMG/31JA/+ARwD/gEYA/4FHAP9/RgD/fEUA/3tE + AP+ARwD/fkYA/31JAv9zRAb/Z0AM/5J1Tv/76M3////0/////v/6/v//+P3///j9///7/v////7///// + /P////z////+//////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////v7+/////////////v7+//39/f//////////////+////+//++XJ/51+ + V/9qQhH/bj0A/4RMBf9/RQD/g0kA/4NLBP97RgP/d0QF/3NCBP90QQL/ekgG/3xGBf9wPQD/aj8G/39b + K//Qso/////p///+9P/++vn//f////P49/////7////+///+/f///fz///////j3+f/z9/j/+/////// + +/////v////8/////v///v///f7///39///9/P///fz///39///+/f///Pz8//z9+//+//v////7//// + +f////j////4////9////vf///34////+/////7///////3////9/////f////3///////////////// + /v////7///////////////////////////////////////////////////////////////////////// + //////////7///38/////f////3////+//////7////7////+f////j///73///99v///fX////6//// + /P/7//7/+v////3//v////v////5/////P///////f////r////6/v//+v7///v+///8/f////7////+ + ///////////////+/v/9+/v////////9+P////T///bd/8mriP95VSf/bT8J/4BPEf97RgP/fkcC/3lD + AP93QAD/f0gD/35JBv96RQL/gEkE/4JIAP95QgD/ckUI/2M9Df+WfFj///jh////9P///fb////8//// + /v///////////////////////f////3///////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////+/v7//////////////////v7+//z8 + /P/9/f3////+///99v////T//+7T/5t8Vf9wRhH/dkME/31GAf95QQD/e0QA/3hDAP94RAL/fEgG/3dC + AP95QgD/hEwF/4FJAv95RQL/c0YJ/21EE/+hgFn/+OHH////8f///vT////5///++f////v////8//// + +/////7////+///////5/Pr////8//3/+/////7//f/////+///9/v////z///38///7+v//+/r///v7 + ///9/v///f////3//v/6//v//P74///+9v////j////5////+/////z///79//39/f/9/f3//f////3/ + ///9/////f/////////////////+/////v////////////////////////////////////////////// + /////////////////////////////////////v///fv///78////+/////r////8/f////7////8///9 + +v////z////8/////v/7////+v////b////z////9v7+/////P////v////+//3////6/v//+P7///j+ + ///4/v//+/7///r7///6+fv//fv7///9/f///////////////P////X////u//Ldvv+VeVD/cEgX/29B + B/98SAb/dD0A/3tEAP96QwD/e0YD/3xGBf99Rwj/ekQF/3U/AP95QwL/ekQD/3RECv9tRhn/potp///u + 2///+vD////8//78+/////z////7////+f////n////8//3////4/v//+P7///3///////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///9/f3//v7+/////////////////////////////f////369v////H///7j/6WGX/9rQw//eUoN/3hE + Av97RgP/fEcE/3tEAP+ASQT/gUkC/3tBAP99QwD/f0QA/3xFAv94QwT/d0YI/21BBv+AWyf/1riP//// + 5P////H////4//338v////z////8//f49P/8+/f////+/////////v//+/////3////7/////f7///v+ + ///9/v///f7///3+///9/v////7////////////////+/////P////z///75////+v////v////8//// + /v////////////3////9/////f////3////9//////////////////7////+//////////////////// + ///////////////////////////////////////////////////////////////////9//////7////+ + //////////7+/////v////7////+//7+/v/9////+/////r////4/v//9v3///T9///0/f//+v7///v/ + ///9/////f////3////9/////f////3////8/v///f////3///////////39//76+f///fr////0///y + 1v/dwZj/dVUk/2dCCv9yRQj/d0UD/35KBP98RQD/fEUC/3dBAP9/SQr/ekQF/3M9AP9+RQf/g0kI/35H + Cv9wQQv/aEEV/66Sc///9+T///v3///+///7/v//+/z//////v////n////3////9/////v/+/////T+ + ///0/v//+/////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////+/v7//v7+//////////////////3////z9vr//f////// + +///++3///7l/8Ckgf9wTB7/b0MN/3VEBv9+SQb/f0cA/3xCAP+CSAD/gkgA/4FFAP+FSwP/fUYD/3U/ + AP98RwT/gEwJ/3REBP9uQwr/oXxQ//HUtf////D////1////+//+/fn////8/////P///fr////+///+ + ///9/v///f7///3////9/////f////3//v/9//7////+/////v////7///////////////////////// + /v////z////8/////P///v3//v7+//7+/v/8/v///P7///3////9/////f////3///////////////// + /v////7///////////////////////////////////////////////////////////////////////// + //////////////n7+//7/vz//f///////v/+//3//v/9///+/f////7//Pz8//3////9/v//+/7///r9 + ///4/f//+Pz///T6///4/v//+v////v////9/////////////////////f////v+///7/v//+fv8//r4 + 9/////n////1///35v/s1rr/lXRH/2Q/B/9uRAn/dkoL/28/AP99SgT/eEEA/35HAv9+RwL/ekMA/35I + B/91PwD/dD4A/4JJC/98QwX/azoC/25HIP/StZr///7t///78////v//9Pf8//P2/v/7/v////////// + +/////j////4////+//7////9v////b////7//////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////9/f3//f39//7+ + /v/+/v7//f39//3////9////9vj5/////v////j////t/9bApP9xUSj/a0EM/3NAAf9/RwD/f0UA/4NH + AP+FSwD/fUMA/39IA/94RAH/eUcF/39JCP97QQD/e0EA/3pEA/90RQj/eVIe/7CWbv/y4cf////3///9 + /P///v/////////8+P////z///7////+/////v/////+/////P////n////4////+P////n////5//// + /P////7///7////+///9+////Pv////9/f///v3////+/////////////f////3////9/////f////3/ + ///9/////f/////////////////+/////v////////////////////////////////////////////// + /////////////////////////////////////////f/+//v//P/7//7//f/8/////P////z////7///+ + /f////7////////+/v/9+vz/+/r+//78/////f///f3///3+///9/////////////////////f////r+ + ///4/v//+P3///r9///////////4////7v/74cP/tpNr/3BIFP9zRgn/bkEA/3tLC/9yQgL/dUUD/3NB + AP9/SwX/ekQA/3xEAP99QgD/hEkD/4BHAv9+SAf/eUMG/3JABv+DWi3/3sau///+8v////n////8//36 + /P/8/f//+/7///r9///9/////////////v////z////+//v////6////+v////3///////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////z8 + /P////////////////////////////////////////////v9/v/7/v//+/7///r8/f////z////y//Lc + wP+EYjf/c0cR/3tHBf98RAD/fkQA/4JKA/94QQD/e0YD/3lFAv95RQL/fEQD/3k/AP+CRwL/gkkE/3M+ + AP91Rgj/aUIO/31eN//CqpL///Dg///+9v///fj////7///++v////////7///////////7////7//// + +f////j////4////+P////j///75///+/f///////f////3+///8/f////7///////////////////z+ + ///8/v///f////3////9/////f////3////9//////////////////7////+//////////////////// + ///////////////////////////////////////////////////////////////////9////+v/+//n+ + /f/8//3//f/+/////v////7////+///+/f////7////+/////v////7///7////+/////P3////+//// + /v////7////+//3////9////+/7///v+///9/v////79////9v/66dT/waWD/4RdMP9wQQn/e0gK/3dD + Af98SAX/cz8A/3tJB/95RQP/ekUC/31HAP9/RQD/gkgA/4BGAP+BRwD/eEMA/3NEB/9rQQz/l3BD//nd + vv////X///79///+/f///v3///7+//39/f/9////+vz9//v+///7/v//+/7///v////9/////f////// + //////7///////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////v////z////+//v+ + ///6/v//+P7///v+//////z////0///pzf+mhl3/bUMO/3JDBv96Rwj/d0MB/3dEBf97RwX/fUMB/4FI + A/99RQD/eUMA/31JA/96RQL/d0EC/3xGCf94Rgz/bT8J/2hBDf+HZzz/yLOT///03v////j//vz7//j8 + /f/6////+/////f5+f/////////+///8+/////z////8///9+v///vv////8/////P/8/fn/+/78//3/ + /v/7/f3//f////3////9////+vz9//z+///9/////f////3////9//////////////////////////// + /v////7///////////////////////////////////////////////////////////////////////// + //////////7////+///9/f//+vr///v8///9/v///f7///3////+/f////////3+/P/+//v////7//// + +//+//b////4////+f////v///76//7//f/9/////P7///////////z////5////9P//8tv/zLCR/4Vi + Ov9pQA//ckII/3pFBv95QwL/dUIE/3dEBv96RQb/eEIB/3pDAP+DSQH/iEoA/4REAP+HSAD/f0MA/39I + A/9xRAf/a0cX/6qQbP//7NH////0/////v/7/v///f///////v////z////8/////v//////+/7///r+ + ///6/f//+v7///3+/////v/////+/////P////7///////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////+////+/////z///////v+///4/v//+v7///3///////v////y///74P/JrIf/d1Ml/2k+ + C/9yRQz/b0EH/3dEBf+CRwL/gUYA/31GAP96RAD/d0QA/3tHBP97RQb/eEAA/3pAAP97RAH/e0cF/3FF + CP9lQRH/dlw3/76pk///++3////5//v99/////z////8/////v///v////7///34+v///P7///7////+ + //////7////8////+/////v//f76//v9/f/8/v///P7///3////9/////f////3////6/P3//f////3/ + ///////////////////////////+/////v////////////////////////////////////////////// + /////////////////////////////////////v///fv////9/////f///f3///39///9/f///f3///v+ + ///5/f7/+/////3//v/9//z////7////+f////f/+/zz//3++v////7////+////+////vf////1//// + 7///89j/yq6L/49sQP9pQQ3/cEEJ/3dFCf98Rwj/fkgH/3lDAv96RAf/dkAD/3hCA/+BRwX/hEgC/39C + AP9/QQD/hEYA/4hOA/98SAX/aTwD/3VUJv/JspL////s////9//6+/f/+v////j////7///////+//// + /P////v////8/////v/9////+/7///v+///7/v////7////+//////7////8//////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////7////8/////P////7///////3////9/////f////// + //////z////1////8f/t2Lz/h2pF/2I+EP9xSRX/cEED/3xDAP+DRwD/gkcB/35EAv93QQD/eUMC/35H + Av+BSgH/hk4B/4FHAP98QQD/e0MC/3VDCf9qPgn/bUgW/3ZaMf+6qIv/7uDN////7/////P////5///+ + /f/6+f3/+/7///r8///6/P//+fv///r7///////////8////+/////n////+///////7/f7//P7///3/ + ///9/////f////3///////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////7////+ + /////v//+/z///r6///6/f//+v7///r+///6/v//+P3///f8///7////+/////3////7////+P3///X5 + +v/++/b////1////7P//58X/w6B1/4NbJv9zQwn/eUYH/3tGA/95RAH/eEIB/3dBAP92QQL/ekUG/3hB + BP+ARwn/gEUA/31BAP+GRwD/hkkA/4NIAP9/Sgf/az8E/2A8DP+QdlL/7+DG////9P/8+vL/+//+//r/ + ///6////+v////v////9//7////+/////v////7//////////////v////7////+/////v////7////+ + /////v////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////7////+//// + /P////z////+/////v/9////+/////f6/v/9//////z3////9f//9d7/t5x6/2xKH/9rQQz/dkQC/3xG + AP98RQL/fUUE/39HBv98RQL/fEQA/39GAP96QAD/g0kA/4NIAv9+QwD/fUMC/3xGBf95RQL/b0ME/2U9 + DP95WTD/sJNu/+jQsv//9uH////0////+///////9/z///b8///4/v//+v7///z9///6+fv//vz7//// + /v///////v7+//z+///8/v//+/3+//r8/f/9/////f////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////+/////P////v///79/////v///////f////v+///7/v//9/r///f6///6/f///f7////+ + ///+/Pz//vz7/////v////z////5///25v/gy7D/podg/3pSIf9vQQf/eUUD/3lCAP+CSgP/fUUA/3tD + AP+ESwb/gEkG/3dCAP99RgP/fkQC/4FGAf99QQD/gEUA/4dLBf95QgD/azkA/2tADf94WTL/uaSI///3 + 5f////X/+Pn1//v////4////+P3+//3//v/9//z//f/+//v//v/7/////f////3///////////////// + /v////7////+///+/////v////7////+//////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////3////9///////+/////P////v////7/////v/9////+v3///f9///7/v///fv6///9 + 8P///+7/586u/45tRv9qQhL/dEYQ/3JDBv9xPQD/ekIA/4VLA/+FSgL/f0QA/4BGBP9/SAX/e0YD/3xF + AP+BSgH/gkgA/4NFAP+ERgD/h0kC/4FFA/95Qwb/fE4Y/5Z0Rv/KsIz/8+XJ///96v////f//f/8//v/ + ///6////+/7///v9///7/f///f3///v6/P/8/Pz//v7+//////////////////7+/v////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////7////4////+P////n////7/////P/+//3/+fv7//r6 + +v/////////////+/f///fr////7////+f///fb///rt//fkz/+8por/hGdC/3BMHv9yRhD/d0YI/3hE + Av93QgD/fUkH/3I+AP94QwT/fkoI/3lCAP97QAD/hUgA/4ZIAP+GRwD/h0oA/4JIAP99RgH/d0QG/2g8 + B/9uSyD/hm1N/9nKt/////X////8//f8+//7////+Pz9//z+/v////z////7////+/////7/+/////r/ + ///6////+/7///3///////7////8////+/////z////+/////////v///f7////+//////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////9////+/7///v+///////////8////+f////v////8//3/ + ///4+///9v3///j+///6/f/////8////9f//++j///Xa/7ibfP9uSyP/YDkF/39SFf96RwH/dj8A/4FG + AP97QAD/ekIB/3hDBP93QwH/d0MA/3xHAP+ARgD/hkYA/41LAP+FQQD/i0gA/4BCAP94QQD/c0QG/2Y+ + Cf90Vif/nodh/9rIqf/z58/////v////+P////r////+///9///8+fv//////////////////v7+//// + //////////////z8/P////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////v////v////7//// + +/////v///76////+/////z////7////+f////f////z////8P///+7//+7W/9G2nP+fgGH/bkwh/21F + FP9vQw3/dEUI/3ZCAP94QQD/e0QA/3xHBP94QwT/eUYH/3pHCf95RAX/e0QB/4NJAf+ESAD/fT8A/4FF + AP99QwD/eEMA/3NEB/9oQQ3/cVMq/7Segv//9uT////5//n39v/7/v//+v////r9///8/v//+vj3//// + /P////v////7/////v/9////+v7///r+///7/v///f///////v////z////7////+/////z///////3/ + ///7//////7///////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////3////7/v//+/7///// + //////7////8/////P////7///////v+///6/v//+v7///n8///8/Pz////8////+f////P////w//Da + vv+afVj/Yj4Q/3BDCv98SQr/eUIA/4BKA/96QwD/fkoI/31ICf92QwT/eEQC/3lEAf98RAD/fEQA/39L + Bf92QgD/ekYA/31JA/96QwD/e0YD/3xHCP9uPAD/ajsD/3tSIf+dek//x6uI//Pdwf///+j////w//// + 9f/++vX////+/////v///fz//vz7/////v////7///79/////v////7///////////////////////3/ + ///9//////////////////////////////////////////////////////////////////////////// + //////////////v9/v/7/f7//P7////+///////////8////+P///vT////x///84//43sD/xaiD/5Fu + Qv9zSxr/aT8K/20/Bf97RwX/e0UA/3xFAP9+SAH/gUgD/4BJBP9+RwL/dD8A/3dBAP99SQf/eEIB/3U/ + AP95RAH/dj8A/3dAAP+JUwz/fUcA/3xIBf9rPwT/a0gW/6GGYf/v3MH////x////+P///fj////+///+ + /v/8+vr///7+///+/////v////79/////P////z///7////+///7/v//+/7///v+///9//////////// + /P////v////7/////P////7//f////v///////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////f////v+///7/v///f////////////7////+/////v///////f////n8///7/v//+/7///v9 + /v/9/f3////+////+/////n////y///86f/gxqj/i2hA/2pCDv91SAv/c0AB/3pGBP94RAL/dkEC/3dC + A/97Rgf/eUUD/3lEAf98SAX/c0MB/3hIBv94RAH/ekMA/4NIAv+ARQD/fEEA/4VJA/+CRwL/d0EC/3JA + Bv9wRA//b0kZ/31dMv+oi2T/z7iY/+vaxf/98d/////y////8v////P////0////9/////j////5//// + +/////z////8/////v/////////////////////////+//////////7//////////v////7////+//// + /v////7////8/////P////z////8/////P////v////7////+/////j////3////8v//7dz/5dC6/9K6 + nP+egl//hGI3/2xGFv9tRA3/c0cK/3VFBf91RAD/fkgB/4BGAP+DRQD/hEgA/4NJAP9+RAD/e0MA/3xF + AP98RwT/e0YD/3hDAP97RgP/fEcE/3pFAv9+SQb/fkkG/3A9AP9sQQj/aEMR/5NzSP/gx6X////l//// + 8v////b////8///+/f///fz///7//////v///v////7////8/v///v/////+/////v///v////7///3+ + ///7/v///f7///3////////////+/////P////z////8/////v/9//7//f/+//////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////f////3///////////////////////////////// + /////////f////3////9/////////////////////f////j+///3/f//////////9///79j/xquJ/4Vi + Nv9pPwr/cEII/3RBAv93QwH/ekUC/31GAf98RQD/e0QA/3tEAP98RQD/f0YB/39GAf99RQD/fUQA/35F + AP9+RQD/e0QA/3xFAv96RAP/eUQF/3dEBv9zRAf/cUMJ/3FCCv9uQg3/fVQj/4VhMf+efE7/wKB1/+HE + nf/6373//+7P///y2P///On////w////9/////j////7///++v///fz////+/////v////z////+//// + /P////7////8/////P////z////7////+P////b////3////9/////X///ns//7y4P//69L/9Nq8/9i8 + mv+4mXL/nXpO/4hgL/95TRf/ckQK/3ZFB/93RAX/eEQC/3dDAP94RAH/ekYD/3pGA/97RwH/gEcA/4RK + AP+CRQD/fkEA/4FGAP+FSQP/f0YB/3lCAP97RwT/c0EA/3dFA/95RwX/dUEA/3hDAP9/SAX/bj8H/4Fl + Qv+8rJX//e/c////8v////f////5/////P///fz//////////////v/////////+/////v////7////+ + //////////////////////////7///3//////v/////////////////////+/////v////7///////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////7/v//9fz///b9 + ///6/v///vz7///+9P////D/+ePH/7+jgP97WCz/b0cT/3BDCv93Rgj/d0MB/3lEAf9/SAP/fUQA/4BF + AP9+QwD/fEMA/35FAP+BSAP/fkcC/3xFAP97RAD/fEUA/3xFAP98RQL/fEUC/3xFAv98RQL/fkQC/3xF + Av90QAD/c0IE/3JDBv9sQAX/aUAJ/3FJGP+AXjD/jG5F/56BXP+mjWv/t5+B/8m0mf/bx67/69nC//no + 0///8t3///He///x3v//8d7///He///x3v//8d7///Hc///x3P/z4Mv/6dfA/9rHrP/KtZn/t6KD/6SN + bf+Od1f/hWpF/3NQJP91TRn/cEYR/3BDCv9yQwb/d0QF/3tGA/99RgH/fUUA/35GAP9/RwD/f0cA/3xF + AP95RAH/eUQB/3pDAP97QwD/gEYA/4FGAP+CRwD/g0gA/39FAP99RQD/gksG/3VAAP97SQf/cEED/3FE + B/95TBP/aT0H/4ddKP/OroX//O3a///+9f////n////6///8+P////z////////////9/////f////3/ + ///9/////f////3////9/////f////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////v////v////8/////P////z////7////+f////f////x//rp1P+4oob/cVQv/187 + C/9zRQ//eUYH/3pDAP+FTQb/eEEA/31GA/9+RwT/eUIA/3dAAP95QgD/fEUA/35GAP9+RgD/fkYA/4BG + AP+ARgD/gUYA/4FGAP+BRgD/fkYA/3xGBf98SQr/fEsN/3hHCf9xQgT/bUAD/3FEB/90SA3/cEII/3FF + Cv9zRQv/c0UL/3FEB/9vQgX/cUIF/29BB/9tQw7/a0MP/2tDD/9rQw//a0MP/2tDD/9rQw//a0MO/21D + Dv9uQgz/bUEL/3FEC/90Rgz/d0gL/3ZHCv92RQf/eUcF/3lFA/93QwH/dkIA/3VCA/92QwT/dUQG/3RD + Bf90QwX/d0QF/3hFBv94RQb/eUUD/3lEAf96QwD/fUQA/4FFA/+BRQP/fkUA/35IAf9/SQL/eUQA/3hB + AP99RgD/gUgD/3lDBP9xQAj/Zj0M/3ZXMP+6pYb/++3W////8v////b////5////+v///vn////8//// + /P///////////////////////f////3///////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////8////9v////f////4//779///////+fv8//j6 + +//////////7////9f//7tf/xq2N/4JgNf9tRRH/c0UL/206AP95RAX/eUQF/3lFA/98RgX/fEcE/3xF + AP99RQD/fEQA/4BGAP+ARgD/gEYA/4BGAP+ARgD/gEUA/4BFAP9+RQD/d0IA/3VBAP91QQD/eEQC/3xI + Bv98SAb/eEQB/3RAAP95RAH/eUUA/3tFAP99RgD/fUYA/39GAP+ARgD/f0UA/3tFAP95RQD/e0QA/3lF + AP97RAH/eUUA/3tEAf97RAD/fUYB/3xFAP9+RgD/fUUA/39FAP+ARgD/gEYA/39FAP+ARgD/fUYA/31F + AP98RQD/fEcE/3xIBv95Rgf/d0YI/3ZFB/93RAX/d0QF/3dFA/96RAP/ekYA/35FAP+ARwL/fEQD/3pE + Bf92QAD/d0MA/35KBP9+SwX/fEgF/3pIBv9yQwb/bEAL/5FrQf/ZvJ3///Tf////8v/+/fn//f/+//// + +v////v////7////+/////z////+//z8/P/////////////////9/////f////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////z////4///+ + 9f////v////+//r8/f/6/v//+P7///L4/f/19vr////8////9/////H///jd/97Dof+be1L/dE4e/3FC + Cv94RQf/d0QF/3dDAf94QwD/fEUA/4FJAv+CSgP/fkYA/35GAP9+RQD/fEUA/3xFAv96RAP/eUQF/3lF + A/+BSgf/f0gD/3pFAv94QwD/d0IA/3hEAf96RgT/e0kH/3lGB/95Rgf/eEYE/3hGBP93RQP/d0UD/3lF + A/94RAH/fUYB/31HAP9/RwD/fUcA/39GAf99RwD/f0YB/39HAP9+RgD/fkYA/35GAP9+RgD/gEYA/4BG + AP+BRgD/gUcA/3xFAP95RQD/e0QA/3tEAP99RQD/fUUA/3xEAP97QwD/gEgB/31FAP98RAD/fkYA/39H + AP9+RgD/fkYA/3pFAv90RQj/dEYM/3dFCf95Qwb/dkAB/3I8AP9xQgz/d08f/5Z5Uv/axqf///Xh///8 + 7v////v///////r5+////v////z7///++v/9+vb//Pn1///+/f////7///////////////////////// + //////////////////////7////+//////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////v////z///34///+/f///////f7///X5/v/0+v//+v7///v+///9/f3////7///+ + 9f//++3////x///34v/s1rr/sI9o/4VhM/9nPw7/b0UQ/3lKEv9wPwH/bzsA/3xFAP9+RgD/fkYA/35F + AP98RQL/ekQD/3lEBf91Qwf/d0QG/3lCAP99RQD/f0cA/35HAv99RgH/ekYA/3pFAv95RQL/eEQC/3ZE + Av92RAL/dkQC/3dEBf93RAX/eEUG/3pGBP98RgD/fkcA/35GAP9+RgD/fkYA/35GAP9+RgD/fkYA/39H + AP9/RwD/gEcC/39HAP9+RgD/fUUA/39EAP9+RgD/fUYB/31GAf99RgH/f0cA/4JIAP+CSAD/g0kB/4RK + AP+CSAD/f0UA/35EAP+BRwD/gkgA/31FAP98RAD/d0MB/21DCP9qQg3/bkIN/3BDEP92Shv/jGQ6/76b + ef/s1Lj////r///98P////n/+//+//j8/f/5/P///f7////+//////7////8/////v////7////+//// + /v/9/f3/+/v7/////////////////////////////////////v////7///////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////f////f6/v/7/v//+Pv///P3+P/9/////f////7+ + /v/////////+////+/////z////8/////P////v///z4////+/////j///Tm/9G+qf+Lc1f/aUgh/29H + Fv94ShD/dkIA/35GAP+ARgD/gEYA/35GAP98RQL/eUQF/3VDB/93RAb/fkcC/4BGAP9+RAD/fUUA/35G + AP9/RwD/fkcA/3xFAP9/RwD/gEgB/4BIAf9/RwD/fkcA/35HAP9+RwD/f0gA/39IAP9/SAD/f0gA/39I + AP99RwD/fUcA/31GAf99RgH/ekMA/3tEAP97RAH/e0QB/3xFAv98RQL/fUYD/31GAf9/RwD/gUcA/4FH + AP+ARgD/f0UA/39FAP9/RQD/fkYA/35GAP98RAD/fUUA/39HAP9+RgD/ekMA/31GAf99Sgv/bUAH/2hA + EP9yTyf/mX5c/9G/qP/77t7////4////+//++/f////8////+//8+/f////+/////v//////+/v7//v7 + +/////7///////39/f/+/v7//f39//7+/v////////////////////7////+/////v////7////+//// + /v////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////9////+v7///b8 + ///6/v//+/7///r8/f/8/Pz////+///++v////z////7/////v//////+fv8//v+///6/v//+Pz///3+ + /////v7////7////9f//8tv/18Cg/56AV/95VCL/bkIM/3NEB/91RAb/d0QF/3dEBf93RAX/d0QG/3lE + Bf97RAD/fkYA/35GAP9+RgD/fUUA/31GAP9+RwD/gEYA/39FAP+ARwD/gUcA/4FIAP+ARgD/f0cA/4FH + AP+BSAD/fUYA/31GAP99RgD/fUYA/3tFAP97RQD/e0QA/3tEAP99RgP/e0YD/3pFAv96RQL/ekQD/3pE + A/96RAP/ekQD/3tEAP99RQD/fkYA/35GAP9+RgD/fkYA/39HAP99RgH/e0YD/3lFA/91RAb/c0QH/21A + B/9sQAr/ckgT/3pSIv+qhl7/4MKf///12/////D////3/////P/7////9vr///v+///9/v/////////+ + /f////7///76///++v////z////////////9/f3//////////////////Pz8//////////////////// + /v////7////+/////v////7////+//////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////3////7/v//+v7///v+///7/v///f////////////7////+/////v////7////+//// + ///9////+/7///v+///9///////+///++////fr////7////+/////f///nu//3z4v/Swqv/rZV3/4Vm + P/9yTiD/ckYQ/3NCBP93QgD/e0QA/3tHAf96RgD/e0QA/3pDAP96QwD/e0UA/31HAP+ASAH/fkYA/35H + AP99RQD/fUYA/4BGAP9+RwD/f0UA/3xFAP9+RwD/fEcA/3xGAP98RgD/fEYA/3xGAP98RQD/fEUA/3tG + A/96RQL/eUMC/3lFA/96RQb/ekUG/3hDBP90QQP/e0gK/3ZDBP90QQL/eEQC/3xHBP99RgH/fEUA/3hE + Av9zQgT/cEMK/21FFP9wUCf/hWpI/66YfP/fzbb///Df////9P////X////3////9/////j////7//// + /v/7////+/7///v+///7/v///f7///////////z////5////+f////7//f////////////////////// + /////////////////v////7////+/////v////7////+/////v////7///////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////3////7/////f7///3///////////////// + /v////7////+/////v////7//////////////////f////////////v////7/////P////7//f////v/ + ///6/v//+vz8////+/////T///fk//bhwv/XuJH/sY1f/5dtOP+KXyb/cUUP/29EC/9vQgn/b0MI/3FE + B/9zRAf/c0IE/3NAAf91QQD/eEMA/3tGA/9+RwL/fkgB/35IAf+BSQL/gEoD/3tFAP95RQD/eUUA/3lF + AP95RQD/eUUA/3lEAf95RAH/ekQD/3lFA/96RQb/d0QF/3ZDBf93RAb/dkQI/3VFC/9sPwb/b0MN/3RI + Ev9xRQ//aT0H/2o+CP92TBf/glop/5NwRP+qjWj/z7eZ/+/dxv//8+P///3z////+f////z///////// + //////7////8////+/////z////+///////9////+/7///v+///7/v///////////v////v////7//// + ///9///////////////////////////////////////+/////v////7////+/////v////7////+//// + /v////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////3/ + /////v/////////////////////+/////v////7////+/////v////7////+/////v////7////8//// + +/////v////8///+/f/9/vz//P7+//3////9////+vv5////+/////n////1////8v///+7///Pe//nl + zP/exqj/yK2L/6KGY/+BZD3/cFAn/2tIHP9tRxf/cEgU/3BEDv9yRAr/c0IE/3VCA/93QwD/eUUA/3pD + AP95QgD/eUUC/3lFA/95RQP/eUUD/3lFA/95RQP/eUUD/3dFA/92QwT/dkYG/3dGCP91RAb/cEEE/3BB + BP90RAr/dUcR/3JJGP9sSBr/cU8k/4VmP/+kiWf/xa+T/9/Ntv/r3cv///vt///+9P////n////7//// + +/////v////7/////P/9//7/+//+//3//////v////7////+/////v///////////v////z//f/8//3/ + /v/9//////7////+/////v///f////3////9/////f/////////////////+/////v////7////+//// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////v////7////8/////v////z////8//// + /P////z////+/////v////7///z7///+/f////7////+//39/f/7/f3//P7+//3////9/////f////7/ + /f/7+fj///35////+/////z///73////9P////L////x////7f//+OH/+OPI/9/Hqf/QtZP/uJ14/6+R + aP+ffVL/kW9B/4djM/99WCb/ckoZ/2lBEP9pQRD/aUEQ/2lBEP9pQRD/aUEQ/2lBEP9qQRD/aUEQ/3NL + Gv96VCT/iWMz/5ZyQv+lgVP/tZNl/8ajd//QrYX/68+s//vjxf///OH////u////8v///fP////7//// + ///9////+/7///v+///7/v///f////7+/v///v3////8/////P/9//7//f/////+/////v////7////+ + ///////////+/////P////z////+//3////9/v///f3///39///9/v///f////3////9//////////// + //////7////+/////v////7///////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////3////9//////////////////7////8//// + /P////v////8/////P////z////8/////v////////////3////7/v//+/7///v+///7/v//+/////v/ + ///6//7/+f79//f6+P/7/vz////+/////v///v3////7///+/f////v////+/////P////z////7//// + +f////n////3////9v////f////1///67f//+Ov///ns///67f//+Ov///bo///35P//9+L///jh///4 + 4f//+OH///jh///34f//+OH///bf///34v//+uX///3n///+6////+7////x////8v////X////4//// + +f////v////8/////v/7+/v/9ff4//v+///6/f//+/7///v+///9//////////////////7////8//// + /P////z////8//3//P/9//7/+/////3////9/v////7////9/////v////7////+/////////f////3/ + ///9/////////////////////////////v////7////+/////v////////////3////9/////f////3/ + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////+/////v////7////+/////P////7////+/////v////7//////////////////f////v+ + ///6/v//+f7///n+///7////+/////3////9//7//f/+/////v/+//3////+/////v///////v7+//v9 + /f/6/v//+v3///v+///9/////f////3///////////////z+///9/////f////v////7/v//+f7///r+ + ///7///////+/////P////v////7////+/////v////5////+f////v////7////+/////v////7///+ + +v/+/Pv//P37///////9/////f////3////9/////f////3////9/////f////3////9/////f////3/ + ///8/v//+/3+//z8/P////7////8/////P////z//f/8//v//v/7////+/////3+///9/f////3////+ + /////v///////////P////z///////3////////////////////////////+/////v////7////+//// + /////////f////3////7/v//+//////+//////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////v////z////8/////P////7///////3////9////+/////3+///9/////f////3/ + /////////////////////////f////z+///9/f3//v7+//7//f////7////8/////P/7/Pj//v/7//// + /v/9//7/+/39//r8/f/6/f//+/7///r+///9/////f///////////////v/9///++v/+/fn//vv3///+ + +v////z////+/////v/+//3//v7+///////9/////f7///3+///9/v////7////+//////////////7+ + /v/8/v7//f////v////7////+v////r////6/////P7///////////////79//78+////fz///76///+ + +v///vr///38///9/P/9/f3//f////3////9/////f////3//v////7////+//3//v///////f////3/ + ///9///////////////////////+/////v////7////+/////v///////f/////////////////+//// + /v////7////+/////v////7////////////9////+/7///v+///7//////7///////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////+////+/////n////8/////v//////+/////v+ + ///6/v//+v7///r+///7/v//+//////+///////////+/////v/9/f3//////////v////7////8//// + /P////r////6/////P////z////+//v+/P/5/f7/+/////r+///6/////f7///3////+/v7///////// + /v////z////8////+/////v////7///89////fj////8/////P////z////+//v+///6/f//+v3///r9 + ///7/v//+/7///v+///7/v//+/7///v+///6////+v////f9///3/f//9v7///j+///7/f7///////// + /v////7////8/////P////v////7////+/////v////+/////v///v///f////r9///5/f7/+/////v/ + /v/9/////f/////+/////v////7////////////////+/////P////z////8/////P///v7////+///+ + ///9//////////////////7////+/////v////7////+/////v///////f////3+///7/v//+/7///v/ + /////v////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////AAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAA= + + + \ No newline at end of file diff --git a/AddIn/EABridge_Example_AddIn/UI/ValidationIssuesControl.Designer.cs b/AddIn/EABridge_Example_AddIn/UI/ValidationIssuesControl.Designer.cs new file mode 100644 index 0000000..3e0eb17 --- /dev/null +++ b/AddIn/EABridge_Example_AddIn/UI/ValidationIssuesControl.Designer.cs @@ -0,0 +1,155 @@ +namespace EABridge_Example_AddIn.UI +{ + partial class ValidationIssuesControl + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.ValidationIssuesDataGridView = new System.Windows.Forms.DataGridView(); + this.ElementNameColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.ElementTypeColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.IssueCategoryColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.SeverityColumn = new System.Windows.Forms.DataGridViewImageColumn(); + this.MsgColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.ValidationInProgressLabel = new System.Windows.Forms.Label(); + this.AbortValidationButton = new System.Windows.Forms.Button(); + ((System.ComponentModel.ISupportInitialize)(this.ValidationIssuesDataGridView)).BeginInit(); + this.SuspendLayout(); + // + // ValidationIssuesDataGridView + // + this.ValidationIssuesDataGridView.AllowUserToAddRows = false; + this.ValidationIssuesDataGridView.AllowUserToDeleteRows = false; + this.ValidationIssuesDataGridView.AutoSizeColumnsMode = System.Windows.Forms.DataGridViewAutoSizeColumnsMode.Fill; + this.ValidationIssuesDataGridView.AutoSizeRowsMode = System.Windows.Forms.DataGridViewAutoSizeRowsMode.AllCellsExceptHeaders; + this.ValidationIssuesDataGridView.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; + this.ValidationIssuesDataGridView.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] { + this.ElementNameColumn, + this.ElementTypeColumn, + this.IssueCategoryColumn, + this.SeverityColumn, + this.MsgColumn}); + this.ValidationIssuesDataGridView.Dock = System.Windows.Forms.DockStyle.Fill; + this.ValidationIssuesDataGridView.Location = new System.Drawing.Point(0, 0); + this.ValidationIssuesDataGridView.Name = "ValidationIssuesDataGridView"; + this.ValidationIssuesDataGridView.ReadOnly = true; + this.ValidationIssuesDataGridView.RowTemplate.Resizable = System.Windows.Forms.DataGridViewTriState.False; + this.ValidationIssuesDataGridView.Size = new System.Drawing.Size(600, 400); + this.ValidationIssuesDataGridView.TabIndex = 0; + this.ValidationIssuesDataGridView.CellDoubleClick += new System.Windows.Forms.DataGridViewCellEventHandler(this.ValidationIssuesDataGridView_CellClick); + this.ValidationIssuesDataGridView.SortCompare += new System.Windows.Forms.DataGridViewSortCompareEventHandler(this.ValidationIssuesDataGridView_SortCompare); + // + // ElementNameColumn + // + this.ElementNameColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCells; + this.ElementNameColumn.HeaderText = "Element name"; + this.ElementNameColumn.Name = "ElementNameColumn"; + this.ElementNameColumn.ReadOnly = true; + this.ElementNameColumn.Width = 91; + // + // ElementTypeColumn + // + this.ElementTypeColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.ColumnHeader; + this.ElementTypeColumn.HeaderText = "Element type"; + this.ElementTypeColumn.Name = "ElementTypeColumn"; + this.ElementTypeColumn.ReadOnly = true; + this.ElementTypeColumn.Width = 86; + // + // IssueCategoryColumn + // + this.IssueCategoryColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.ColumnHeader; + this.IssueCategoryColumn.HeaderText = "Issue Category"; + this.IssueCategoryColumn.Name = "IssueCategoryColumn"; + this.IssueCategoryColumn.ReadOnly = true; + this.IssueCategoryColumn.Width = 94; + // + // SeverityColumn + // + this.SeverityColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.ColumnHeader; + this.SeverityColumn.HeaderText = "Severity"; + this.SeverityColumn.Name = "SeverityColumn"; + this.SeverityColumn.ReadOnly = true; + this.SeverityColumn.Resizable = System.Windows.Forms.DataGridViewTriState.True; + this.SeverityColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.Automatic; + this.SeverityColumn.Width = 70; + // + // MsgColumn + // + this.MsgColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill; + this.MsgColumn.HeaderText = "Validation message"; + this.MsgColumn.Name = "MsgColumn"; + this.MsgColumn.ReadOnly = true; + // + // ValidationInProgressLabel + // + this.ValidationInProgressLabel.AutoSize = true; + this.ValidationInProgressLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.ValidationInProgressLabel.ForeColor = System.Drawing.SystemColors.ActiveCaptionText; + this.ValidationInProgressLabel.Location = new System.Drawing.Point(3, 0); + this.ValidationInProgressLabel.Name = "ValidationInProgressLabel"; + this.ValidationInProgressLabel.Size = new System.Drawing.Size(179, 39); + this.ValidationInProgressLabel.TabIndex = 1; + this.ValidationInProgressLabel.Text = "Validation of [Name] in progress... \r\n\r\nValidation results will be shown here.\r\n"; + this.ValidationInProgressLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // abortValidationButton + // + this.AbortValidationButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.AbortValidationButton.Location = new System.Drawing.Point(522, 3); + this.AbortValidationButton.Name = "abortValidationButton"; + this.AbortValidationButton.Size = new System.Drawing.Size(75, 23); + this.AbortValidationButton.TabIndex = 2; + this.AbortValidationButton.Text = "Abort"; + this.AbortValidationButton.UseVisualStyleBackColor = true; + this.AbortValidationButton.Click += new System.EventHandler(this.AbortValidationButton_Click); + // + // ValidationIssuesControl + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.AbortValidationButton); + this.Controls.Add(this.ValidationInProgressLabel); + this.Controls.Add(this.ValidationIssuesDataGridView); + this.Name = "ValidationIssuesControl"; + this.Size = new System.Drawing.Size(600, 400); + ((System.ComponentModel.ISupportInitialize)(this.ValidationIssuesDataGridView)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.DataGridView ValidationIssuesDataGridView; + private System.Windows.Forms.DataGridViewTextBoxColumn ElementNameColumn; + private System.Windows.Forms.DataGridViewTextBoxColumn ElementTypeColumn; + private System.Windows.Forms.DataGridViewTextBoxColumn IssueCategoryColumn; + private System.Windows.Forms.DataGridViewImageColumn SeverityColumn; + private System.Windows.Forms.DataGridViewTextBoxColumn MsgColumn; + private System.Windows.Forms.Label ValidationInProgressLabel; + private System.Windows.Forms.Button AbortValidationButton; + } +} diff --git a/AddIn/EABridge_Example_AddIn/UI/ValidationIssuesControl.cs b/AddIn/EABridge_Example_AddIn/UI/ValidationIssuesControl.cs new file mode 100644 index 0000000..b5a3ad6 --- /dev/null +++ b/AddIn/EABridge_Example_AddIn/UI/ValidationIssuesControl.cs @@ -0,0 +1,317 @@ +using EABridge_Example_AddIn.ApplicationHandlers; +using EABridge_Example_AddIn.Reports; +using EABridge_Example_AddIn.Utils; +using EA; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Drawing; +using System.Runtime.InteropServices; +using System.Windows.Forms; + +namespace EABridge_Example_AddIn.UI +{ + [Guid("E4F9A26A-5EDF-44BE-98A0-015E3D7C6E7A")] + [ComVisible(true)] + public partial class ValidationIssuesControl : UserControl + { + private Repository Repository; + IDictionary Issues = new Dictionary(); + private const string validationInProgressText = @"Validation of [Name] in progress... "; + private ExampleHeadlessApplicationHandler HeadlessApplicationHandler; + + public ValidationIssuesControl() + { + InitializeComponent(); + } + + public ValidationIssuesControl(Repository repository, SerializableValidationResult displayResult) + { + InitializeComponent(); + this.Issues = displayResult.GetAllValidationIssues(); + this.Repository = repository; + ValidationInProgressLabel.Visible = false; + AbortValidationButton.Visible = false; + ShowValidationResults(); + } + + private void ShowValidationResults() + { + foreach (var item in Issues) + { + AddValidationIssue(Repository, item); + } + } + + public void UpdateValidationViewState(string guid, ExampleHeadlessApplicationHandler handler) + { + HeadlessApplicationHandler = handler; + Issues.Clear(); + ValidationIssuesDataGridView.Rows.Clear(); + ValidationIssuesDataGridView.Visible = false; + var guidName = EARepositoryUtils.GetEAObjectSimpleNameFromGuid(Repository, guid); + string validationText = validationInProgressText.Replace("[Name]", guidName); + ValidationInProgressLabel.Text = validationText; + ValidationInProgressLabel.Visible = true; + AbortValidationButton.Visible = true; + AbortValidationButton.Enabled = true; + + } + + public void UpdateValidationIssues(SerializableValidationResult newResult, Repository repository) + { + ValidationInProgressLabel.Visible = false; + AbortValidationButton.Visible = false; + ValidationIssuesDataGridView.Visible = true; + ValidationIssuesDataGridView.Rows.Clear(); + this.Issues.Clear(); + this.Repository = repository ?? throw new ArgumentNullException(nameof(repository)); + this.Issues = newResult.GetAllValidationIssues(); + ShowValidationResults(); + } + + public void AddValidationIssue(Repository repository, KeyValuePair issue) + { + DataGridViewRow row = new DataGridViewRow(); + row.Tag = issue; + row.MinimumHeight = row.Height; + row.CreateCells(ValidationIssuesDataGridView); + UpdateRowCellValues(row); + if (ValidationIssuesDataGridView.InvokeRequired) + { + ValidationIssuesDataGridView.Invoke(new MethodInvoker(delegate { ValidationIssuesDataGridView.Rows.Add(row); })); + } else + { + ValidationIssuesDataGridView.Rows.Add(row); + } + } + + private void UpdateRowHeight(DataGridViewRow row) + { + string membersText = row.Cells[MsgColumn.Index].Value as string; + if (membersText != "") + { + int padding = row.MinimumHeight - TextRenderer.MeasureText("|", ValidationIssuesDataGridView.Font).Height; + Size size = TextRenderer.MeasureText(membersText != "" ? membersText : "|", ValidationIssuesDataGridView.Font); + row.Height = size.Height + padding; + } + else + { + row.Height = row.MinimumHeight; + } + } + + private void UpdateRowCellValues(DataGridViewRow row) + { + KeyValuePair issue = (KeyValuePair)row.Tag; + + row.Cells[ElementNameColumn.Index].Value = EARepositoryUtils.GetEAElementName(this.Repository, issue.Key.type, issue.Key.id).Value; + row.Cells[ElementTypeColumn.Index].Value = issue.Key.type; + string issueSeverity = issue.Key.severity; + switch (issueSeverity) + { + case "E": + row.Cells[SeverityColumn.Index].Value = new Bitmap(SystemIcons.Error.ToBitmap(), 16, 16); + break; + case "W": + row.Cells[SeverityColumn.Index].Value = new Bitmap(SystemIcons.Warning.ToBitmap(), 16, 16); + break; + case "I": + row.Cells[SeverityColumn.Index].Value = new Bitmap(SystemIcons.Information.ToBitmap(), 16, 16); + break; + default: + row.Cells[SeverityColumn.Index].Value = new Bitmap(SystemIcons.Question.ToBitmap(), 16, 16); + break; + } + row.Cells[IssueCategoryColumn.Index].Value = issue.Value; + row.Cells[MsgColumn.Index].Value = issue.Key.msg; + UpdateRowHeight(row); + } + + private void ValidationIssuesDataGridView_CellClick(object sender, DataGridViewCellEventArgs e) + { + if (e.RowIndex >= 0 && e.RowIndex < Issues.Count) + { + DataGridViewRow row = ValidationIssuesDataGridView.Rows[e.RowIndex]; + + if (row != null) + { + KeyValuePair issue = (KeyValuePair)row.Tag; + NavigateToElementInProjectExplorer(issue.Key); + } + + } + + } + + public void NavigateToElementInProjectExplorer(ValidationIssue issue) + { + Element element = null; + int id = -1; + object focus = null; + string type = issue.type; + int issueId = -1; + if (!int.TryParse(issue.id, out issueId)) + { + MessageBox.Show(Win32Window.GetMainWindowHandle(), "This validation issue is not navigable\n\n", "Reported issue is not navigable"); + return; + } + + switch (type) + { + case "element": + element = Repository.GetElementByID(int.Parse(issue.id)); + id = element.ElementID; + focus = element; + break; + + case "connector": + Connector connector = Repository.GetConnectorByID(int.Parse(issue.id)); + if (connector != null) + { + id = connector.ClientID; + element = Repository.GetElementByID(id); + } + focus = element; + break; + + case "attribute": + EA.Attribute attribute = Repository.GetAttributeByID(int.Parse(issue.id)); + if (attribute != null) + { + id = attribute.ParentID; + element = Repository.GetElementByID(id); + } + focus = attribute; + break; + + case "operation": + Method method = Repository.GetMethodByID(int.Parse(issue.id)); + if (method != null) + { + id = method.ParentID; + element = Repository.GetElementByID(id); + } + focus = method; + break; + + case "parameter": + Method paraMethod = Repository.GetMethodByID(int.Parse(issue.id)); + if (paraMethod != null) + { + id = paraMethod.ParentID; + element = Repository.GetElementByID(id); + } + focus = paraMethod; + break; + + case "package": + Package package = Repository.GetPackageByID(int.Parse(issue.id)); + if (package != null) + { + Repository.ShowInProjectView(package); + } + break; + + default: + MessageBox.Show(Win32Window.GetMainWindowHandle(), "The reported issue with severity '" + issue.severity + "' is currently not navigable:\n\n" + issue.msg, "Reported issue is not navigable"); + return; + } + + if (element != null) + { + Repository.ShowInProjectView(element); + Collection elementDiagrams = null; + if ("element" == issue.type) + { + Element parentElement = element; + if (element.Diagrams.Count < 1) + { + try + { + parentElement = Repository.GetElementByID(element.ParentID); + elementDiagrams = parentElement.Diagrams; + } + catch (Exception) + { + // If the element is not in a diagram and its parent is not found then we ignore navigation to diagram + // MessageBox.Show(Win32Window.GetMainWindowHandle(), "Element: " + parentElement.Name + " can not be identified by its ID"); + } + } else + { + elementDiagrams = element.Diagrams; + } + } + + Diagram diagram = Repository.GetCurrentDiagram(); + if (elementDiagrams != null && elementDiagrams.Count >= 1) + { + // we'll navigate to the first diagram for now + diagram = elementDiagrams.GetAt(0); + Repository.OpenDiagram(diagram.DiagramID); + Repository.ActivateDiagram(diagram.DiagramID); + } + if (diagram != null) + { + for (short i = (short)(diagram.SelectedObjects.Count - 1); i >= 0; i--) + { + diagram.SelectedObjects.DeleteAt(i, false); // There is no need to update the DescriptionsCache, because it is only a change in the UI. + } + diagram.SelectedObjects.Refresh(); + diagram.SelectedObjects.AddNew(id.ToString(), element.Type); + diagram.SelectedObjects.Refresh(); + try + { + if (!diagram.Update()) + { + throw new Exception("Failed to update diagram '" + diagram.Name + "' with ID " + diagram.DiagramID + "."); + } + } + catch (COMException e) + { + throw new Exception("Failed to update diagram '" + diagram.Name + "' with ID " + diagram.DiagramID + ": " + e.Message, e); + } + } + else + { + // do nothing for now !! + } + } + if (focus != null) + { + Repository.ShowInProjectView(focus); + } + } + + private void ValidationIssuesDataGridView_SortCompare(object sender, DataGridViewSortCompareEventArgs e) + { + if (e.Column.Index == SeverityColumn.Index) + { + // sort based on the severity icon + DataGridViewRow row1 = ValidationIssuesDataGridView.Rows[e.RowIndex1]; + DataGridViewRow row2 = ValidationIssuesDataGridView.Rows[e.RowIndex2]; + KeyValuePair issue1Entry = (KeyValuePair) row1.Tag; + KeyValuePair issue2Entry = (KeyValuePair) row2.Tag; + + string severity1 = issue1Entry.Key.severity; + string severity2 = issue2Entry.Key.severity; + e.SortResult = ValidationIssueSeverityUtils.CompareSeverityLevels(severity1, severity2); + e.Handled = true; + } else + { + // do nothing + } + } + + private void AbortValidationButton_Click(object sender, EventArgs e) + { + if (HeadlessApplicationHandler != null) + { + HeadlessApplicationHandler.KillProcess(); + ValidationInProgressLabel.Text = @"Validtion aborted"; + AbortValidationButton.Enabled = false; + HeadlessApplicationHandler = null; + } + } + } +} diff --git a/AddIn/EABridge_Example_AddIn/UI/ValidationIssuesControl.resx b/AddIn/EABridge_Example_AddIn/UI/ValidationIssuesControl.resx new file mode 100644 index 0000000..6ecd3cf --- /dev/null +++ b/AddIn/EABridge_Example_AddIn/UI/ValidationIssuesControl.resx @@ -0,0 +1,150 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + \ No newline at end of file diff --git a/AddIn/EABridge_Example_AddIn/UI/Win32Window.cs b/AddIn/EABridge_Example_AddIn/UI/Win32Window.cs new file mode 100644 index 0000000..2bcd44a --- /dev/null +++ b/AddIn/EABridge_Example_AddIn/UI/Win32Window.cs @@ -0,0 +1,39 @@ +using System.Windows.Forms; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; + +namespace EABridge_Example_AddIn.UI +{ + public class Win32Window : IWin32Window + { + private readonly IntPtr handle; + + public Win32Window(IntPtr handle) + { + this.handle = handle; + } + + public IntPtr Handle + { + get { return handle; } + } + + public static IWin32Window GetMainWindowHandle() + { + Process process = Process.GetCurrentProcess(); + process.Refresh(); + IntPtr handle = process.MainWindowHandle; + if (!IntPtr.Zero.Equals(handle)) + { + return new Win32Window(handle); + } + else + { + return null; + } + } + } +} \ No newline at end of file diff --git a/AddIn/EABridge_Example_AddIn/UI/icons/itemis_logo.ico b/AddIn/EABridge_Example_AddIn/UI/icons/itemis_logo.ico new file mode 100644 index 0000000..fb5883d Binary files /dev/null and b/AddIn/EABridge_Example_AddIn/UI/icons/itemis_logo.ico differ diff --git a/AddIn/EABridge_Example_AddIn/Utils/DateTimeUtils.cs b/AddIn/EABridge_Example_AddIn/Utils/DateTimeUtils.cs new file mode 100644 index 0000000..98d0614 --- /dev/null +++ b/AddIn/EABridge_Example_AddIn/Utils/DateTimeUtils.cs @@ -0,0 +1,35 @@ +using System; + +namespace EABridge_Example_AddIn.Utils +{ + public static class DateTimeUtils + { + private static long SecInMilisec = 1000; + private static long MinInMilisec = SecInMilisec * 60; + private static long HourInMilisec = MinInMilisec * 60; + private static long DayInMilisec = HourInMilisec * 24; + private static long YearInMilisec = DayInMilisec * 365; + + public static long GetTimeDifferenceInMilisec(DateTime date1, DateTime date2) + { + long difference = date1.GetDateTimeInMilisec() - date2.GetDateTimeInMilisec(); + return Math.Abs(difference); + } + + public static long GetDateTimeInMilisec(this DateTime dateTime) + { + return (dateTime.Year * YearInMilisec) + (dateTime.DayOfYear * DayInMilisec) + (dateTime.Hour * HourInMilisec) + (dateTime.Minute * MinInMilisec) + + (dateTime.Second * SecInMilisec) + dateTime.Millisecond; + } + + public static string GetHumanReadableDuration(long durationInMiliseconds) + { + if (durationInMiliseconds < 2000) + return durationInMiliseconds + " ms"; + if (durationInMiliseconds < 100 * 1000) + return (durationInMiliseconds / 1000) + " sec"; + return (durationInMiliseconds / 1000 / 60) + " min"; + } + } +} + diff --git a/AddIn/EABridge_Example_AddIn/Utils/EARepositoryUtils.cs b/AddIn/EABridge_Example_AddIn/Utils/EARepositoryUtils.cs new file mode 100644 index 0000000..8aaac25 --- /dev/null +++ b/AddIn/EABridge_Example_AddIn/Utils/EARepositoryUtils.cs @@ -0,0 +1,190 @@ +using EABridge_Example_AddIn.ApplicationHandlers; +using EA; +using System; +using System.Collections.Generic; +using System.IO; +using System.Xml.Linq; +using File = System.IO.File; + +namespace EABridge_Example_AddIn.Utils +{ + public static class EARepositoryUtils + { + + public const string EAPackageType = "Package"; + public const string EAElementType = "Element"; + + + public static bool IsPackageGuid(Repository repository, string guid) + { + try + { + Package package = repository.GetPackageByGuid(guid); + return package != null ? true : false; + } + catch + { + return false; + } + } + + public static bool IsElementGuid(Repository repository, string guid) + { + try + { + Element element = repository.GetElementByGuid(guid); + return element != null ? true : false; + } + catch + { + return false; + } + } + + public static string GetGuidOfPackageOrElementOrDiagram(object cxt) + { + if (cxt is Package) + { + return ((Package)cxt).PackageGUID; + + } + else if (cxt is Element) + { + return ((Element)cxt).ElementGUID; + + } + else if (cxt is Diagram) + { + return ((Diagram)cxt).DiagramGUID; + + } + else + { + return ""; + } + + } + + public static bool IsCLIOperationForContextObjectAllowed(object cxt) + { + if (cxt is Package) + { + return true; + } + else if (cxt is Element) + { + Element cxtCast = (Element)cxt; + return true; + } + else + { + return false; + } + } + + + + public static string GetAllRootPackageNames(this Repository repository) + { + var models = repository.Models; + List names = new List(); + if (models == null || models.Count == 0) + { + return ""; + } + else + { + // get the model where the requested package is + foreach (Package model in models) + { + names.Add(model.Name); + } + + return string.Join(", ", names.ToArray()); + } + + } + + public static string GetEAObjectSimpleNameFromGuid(this Repository repository, string guid) + { + if (IsPackageGuid(repository, guid)) + { + var package = repository.GetPackageByGuid(guid); + return package.Name; + } + else if (IsElementGuid(repository, guid)) + { + var element = repository.GetElementByGuid(guid); + return element.Name; + } + else if (string.IsNullOrEmpty(guid)) + { + return GetAllRootPackageNames(repository); + } + else + { + return ""; + } + } + + + public static KeyValuePair GetEAElementName(Repository repository, string type, string id) + { + Element element = null; + switch (type) + { + case "element": + element = repository.GetElementByID(int.Parse(id)); + return new KeyValuePair(element.FQName, element.Name); + + case "connector": + Connector connector = repository.GetConnectorByID(int.Parse(id)); + if (connector != null) + { + int connectorID = connector.ClientID; + element = repository.GetElementByID(connectorID); + return new KeyValuePair(element.FQName, element.Name); + } + return new KeyValuePair(String.Empty, String.Empty); + + case "attribute": + EA.Attribute attribute = repository.GetAttributeByID(int.Parse(id)); + if (attribute != null) + { + return new KeyValuePair(attribute.FQStereotype, attribute.Name); + } + return new KeyValuePair(String.Empty, String.Empty); + + case "operation": + Method method = repository.GetMethodByID(int.Parse(id)); + if (method != null) + { + return new KeyValuePair(method.FQStereotype, method.Name); + } + return new KeyValuePair(String.Empty, String.Empty); + + case "parameter": + Method paraMethod = repository.GetMethodByID(int.Parse(id)); + if (paraMethod != null) + { + return new KeyValuePair(paraMethod.FQStereotype, paraMethod.Name); + } + return new KeyValuePair(String.Empty, String.Empty); + + case "package": + Package package = repository.GetPackageByID(int.Parse(id)); + if (package != null) + { + return new KeyValuePair(package.StereotypeEx, package.Name); + } + return new KeyValuePair(String.Empty, String.Empty); + + default: + return new KeyValuePair(String.Empty, String.Empty); + + } + } + + + } +} diff --git a/AddIn/EABridge_Example_AddIn/Utils/FileUtils.cs b/AddIn/EABridge_Example_AddIn/Utils/FileUtils.cs new file mode 100644 index 0000000..e589e0b --- /dev/null +++ b/AddIn/EABridge_Example_AddIn/Utils/FileUtils.cs @@ -0,0 +1,90 @@ +using Newtonsoft.Json; +using System; +using System.IO; + +namespace EABridge_Example_AddIn.Utils +{ + public static class FileUtils + { + private static string ConfigurationFilePath = GetConfigurationFilePath(); + + public static bool IsPathValid(string path) + { + try + { + if (path == null || + !Path.IsPathRooted(path)) + { + return false; + } + Path.GetFullPath(path); + } + catch (Exception) + { + return false; + + } + + return true; + } + + public static bool UpadteOrCreateValidationConfiguration(ValidationConfiguration configuration) + { + try + { + JsonSerializer serializer = new JsonSerializer(); + serializer.NullValueHandling = NullValueHandling.Ignore; + StreamWriter sw; + if (File.Exists(ConfigurationFilePath)) + { + sw = new StreamWriter(ConfigurationFilePath); + } + else + { + sw = File.CreateText(ConfigurationFilePath); + } + using (JsonWriter writer = new JsonTextWriter(sw)) + { + serializer.Serialize(writer, configuration); + return true; + } + } + catch + { + return false; + } + } + + public static ValidationConfiguration ReadValidationConfigurationFile() + { + try + { + var config = JsonConvert.DeserializeObject(File.ReadAllText(ConfigurationFilePath)); + return config; + } + catch + { + return null; + } + } + + private static string GetUserFolder() + { + return Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); + } + + private static string GetConfigurationFilePath() + { + + string userPath = GetUserFolder(); + if (!Directory.Exists(Path.Combine(userPath, ".example-cli"))) + { + // create the config directory if it doesn't exist + Directory.CreateDirectory(Path.Combine(userPath, ".example-cli")); + } + return Path.Combine(GetUserFolder(), ".example-cli", "EA_AddIn_CLI_config.json"); + + } + + } +} diff --git a/AddIn/EABridge_Example_AddIn/Utils/HeadlessApplicationUtils.cs b/AddIn/EABridge_Example_AddIn/Utils/HeadlessApplicationUtils.cs new file mode 100644 index 0000000..60aa3f5 --- /dev/null +++ b/AddIn/EABridge_Example_AddIn/Utils/HeadlessApplicationUtils.cs @@ -0,0 +1,70 @@ +using EABridge_Example_AddIn.Utils; +using System; +using System.Diagnostics; +using System.IO; +using System.Reflection; + +namespace EABridge_Example_AddIn.Utils +{ + + public static class HeadlessApplicationUtils + { + + public const string INI_FILE_NAME = "ExampleCLI.ini"; + public const string EXECUTABLE_FILE_NAME = "ExampleCLI.exe"; + public const string CONSOLE_EXECUTABLE_FILE_NAME = "ExampleCLIc.exe"; + + public static string GetExecuableInIArguments() + { + string iniFileLocation = Path.Combine(FindHeadlessApplication(), INI_FILE_NAME); + return " --launcher.ini \"" + iniFileLocation + "\""; + + + } + + static string FindHeadlessApplication() + { + var config = FileUtils.ReadValidationConfigurationFile(); + if (config == null) + { + return ""; + } + string storedPath = config.ValidationCLIPath; + if (!string.IsNullOrEmpty(storedPath) && IsHeadlessApplicationDirectory(storedPath)) + { + return storedPath; + } else + { + return ""; + } + } + + + + public static string FindExecutable() + { + string path = Path.Combine(FindHeadlessApplication(), CONSOLE_EXECUTABLE_FILE_NAME); + if (File.Exists(path)) + { + return path; + } + else + { + return Path.Combine(FindHeadlessApplication(), EXECUTABLE_FILE_NAME); + } + } + + public static bool IsHeadlessApplicationDirectory(string directory) + { + if (Directory.Exists(directory)) + { + string exeFile = Path.Combine(directory, EXECUTABLE_FILE_NAME); + return File.Exists(exeFile); + } + else + { + return false; + } + } + } +} diff --git a/AddIn/EABridge_Example_AddIn/Utils/ValidationConfiguration.cs b/AddIn/EABridge_Example_AddIn/Utils/ValidationConfiguration.cs new file mode 100644 index 0000000..9b21da9 --- /dev/null +++ b/AddIn/EABridge_Example_AddIn/Utils/ValidationConfiguration.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EABridge_Example_AddIn.Utils +{ + public class ValidationConfiguration + { + public string ValidationCLIPath { get; set; } + // futher configuration options can be added here + + } +} diff --git a/AddIn/EABridge_Example_AddIn_Setup/AddInDependency.generated.wxs b/AddIn/EABridge_Example_AddIn_Setup/AddInDependency.generated.wxs new file mode 100644 index 0000000..cb82395 --- /dev/null +++ b/AddIn/EABridge_Example_AddIn_Setup/AddInDependency.generated.wxs @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/AddIn/EABridge_Example_AddIn_Setup/Dialog.wxi b/AddIn/EABridge_Example_AddIn_Setup/Dialog.wxi new file mode 100644 index 0000000..8610af8 --- /dev/null +++ b/AddIn/EABridge_Example_AddIn_Setup/Dialog.wxi @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + 1 + + 1 + + 1 + + 1 + + + 1 + + 1 + + 1 + 1 + 1 + 1 + + + + + + diff --git a/AddIn/EABridge_Example_AddIn_Setup/EABridge_Example_AddIn.generated.wxs b/AddIn/EABridge_Example_AddIn_Setup/EABridge_Example_AddIn.generated.wxs new file mode 100644 index 0000000..ff36655 --- /dev/null +++ b/AddIn/EABridge_Example_AddIn_Setup/EABridge_Example_AddIn.generated.wxs @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/AddIn/EABridge_Example_AddIn_Setup/EABridge_Example_AddIn_Setup.wixproj b/AddIn/EABridge_Example_AddIn_Setup/EABridge_Example_AddIn_Setup.wixproj new file mode 100644 index 0000000..b2ac65d --- /dev/null +++ b/AddIn/EABridge_Example_AddIn_Setup/EABridge_Example_AddIn_Setup.wixproj @@ -0,0 +1,74 @@ + + + + Debug + x86 + 3.10 + 788cc963-0bea-4cc6-826c-589aea2ad2db + 2.0 + EABridge_Example_AddIn_Setup + Package + $(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets + $(MSBuildExtensionsPath)\Microsoft\WiX\v3.x\Wix.targets + + + EABridge_Example_AddIn_Setup + + + bin\$(Configuration)\ + obj\$(Configuration)\ + Debug + + + bin\$(Configuration)\ + obj\$(Configuration)\ + + + + + + + + + + + + + $(WixExtDir)\WixUIExtension.dll + WixUIExtension + + + $(WixExtDir)\WixNetFxExtension.dll + WixNetFxExtension + + + + + EABridge_Example_AddIn + {9865eccc-f07b-447a-bd11-c75b081eeba4} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + + + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + \ No newline at end of file diff --git a/AddIn/EABridge_Example_AddIn_Setup/Product.wxs b/AddIn/EABridge_Example_AddIn_Setup/Product.wxs new file mode 100644 index 0000000..674961a --- /dev/null +++ b/AddIn/EABridge_Example_AddIn_Setup/Product.wxs @@ -0,0 +1,58 @@ + + + + + + + + + + + Installed OR NETFRAMEWORK45 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/AddIn/EABridge_Example_AddIn_Setup/packages.config b/AddIn/EABridge_Example_AddIn_Setup/packages.config new file mode 100644 index 0000000..83c4644 --- /dev/null +++ b/AddIn/EABridge_Example_AddIn_Setup/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/AddIn/EABridge_Example_AddIn_Tests/AddInTest/AddInTestConstants.cs b/AddIn/EABridge_Example_AddIn_Tests/AddInTest/AddInTestConstants.cs new file mode 100644 index 0000000..1a146a5 --- /dev/null +++ b/AddIn/EABridge_Example_AddIn_Tests/AddInTest/AddInTestConstants.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EABridge_Example_AddIn_Tests.AddInTest +{ + public static class AddInTestConstants + { + public const string ReferenceTestModelPath = "TestModels/Example.eap"; + } +} diff --git a/AddIn/EABridge_Example_AddIn_Tests/AddInTest/EAAddInTest.cs b/AddIn/EABridge_Example_AddIn_Tests/AddInTest/EAAddInTest.cs new file mode 100644 index 0000000..742cebe --- /dev/null +++ b/AddIn/EABridge_Example_AddIn_Tests/AddInTest/EAAddInTest.cs @@ -0,0 +1,53 @@ +using EABridge_Example_AddIn_Tests.TestUtils; +using EABridge_Example_AddIn; +using EABridge_Example_AddIn.Utils; +using EA; +using NUnit.Framework; +using FileUtils = EABridge_Example_AddIn_Tests.TestUtils.FileUtils; + +namespace EABridge_Example_AddIn_Tests.AddInTest +{ + [TestFixture] + public class EAAddInTest + { + + protected Repository Repository; + protected ExampleValidationAddIn ValidationAddIn; + protected App App; + + [SetUp] + public void SetUp() + { + LoadRepository(AddInTestConstants.ReferenceTestModelPath, true); + ValidationAddIn = new ExampleValidationAddIn(); + } + + private void LoadRepository(string testModelPath, bool loadAddins) + { + App = new App(); + Repository = App.Repository; + string repoLocation = FileUtils.BackupFile(testModelPath); + Repository.OpenFile(repoLocation); + if (loadAddins) + { + Repository.LoadAddins(); + } + } + + + [TearDown] + public void TearDown() + { + if (Repository != null) + { + Repository.CloseFile(); + Repository.CloseAddins(); + Repository.Exit(); + Repository = null; + App = null; + } + + } + + } +} diff --git a/AddIn/EABridge_Example_AddIn_Tests/AddInTest/HeadlessApplicationHandlerTest.cs b/AddIn/EABridge_Example_AddIn_Tests/AddInTest/HeadlessApplicationHandlerTest.cs new file mode 100644 index 0000000..7fd1fe4 --- /dev/null +++ b/AddIn/EABridge_Example_AddIn_Tests/AddInTest/HeadlessApplicationHandlerTest.cs @@ -0,0 +1,58 @@ +using EABridge_Example_AddIn_Tests.TestUtils; +using EA; +using File = System.IO.File; +using NUnit.Framework; +using System; +using Newtonsoft.Json; +using EABridge_Example_AddIn.Reports; +using EABridge_Example_AddIn.ApplicationHandlers; + +namespace EABridge_Example_AddIn_Tests.AddInTest +{ + [TestFixture] + public class HeadlessApplicationHandlerTest : EAAddInTest + { + [Test] + public void HeadlessOperation_Should_UseSeparateThread() + { + ExampleHeadlessApplicationHandler applicationHandler = new ExampleHeadlessApplicationHandler(); + applicationHandler.StartExternValidationOperationAsync("", Repository.ConnectionString); + Assert.IsTrue(applicationHandler.IsThreadRunning(), "Thread could not be started"); + } + + [Test] + public void HeadlessOperation_Should_TerminateWhenPrompted() + { + ExampleHeadlessApplicationHandler applicationHandler = new ExampleHeadlessApplicationHandler(); + applicationHandler.StartExternValidationOperationAsync("", Repository.ConnectionString); + Assert.IsTrue(applicationHandler.IsThreadRunning(), "Thread could not be started"); + applicationHandler.KillProcess(); + Assert.IsFalse(applicationHandler.IsThreadRunning(), "Thread did not terminate successfully"); + } + + [Test] + public void ValidationOperationOutcome_Should_BeValidJson() + { + ExampleHeadlessApplicationHandler applicationHandler = new ExampleHeadlessApplicationHandler(); + applicationHandler.OperationComplete += AssertHeadlessOperationOutcome; + applicationHandler.StartExternValidationOperationAsync("", Repository.ConnectionString); + Assert.IsTrue(applicationHandler.IsThreadRunning(), "Thread could not be started"); + } + + private void AssertHeadlessOperationOutcome(ExampleHeadlessApplicationHandler sender, ExternApplicationEventArgs e) + { + string reportFilePath = e.ReportFile; + Assert.IsTrue(e.ReturnCode == 0, "Return code of the CLI application is not successful"); + Assert.IsTrue(File.Exists(reportFilePath), "Report file path does not exist"); + try + { + SerializableValidationResult ValidationReport = JsonConvert.DeserializeObject(File.ReadAllText(reportFilePath)); + } + catch (Exception ex) + { + Assert.Fail(ex.Message); + } + File.Delete(reportFilePath); + } + } +} diff --git a/AddIn/EABridge_Example_AddIn_Tests/EABridge_Example_AddIn_Tests.csproj b/AddIn/EABridge_Example_AddIn_Tests/EABridge_Example_AddIn_Tests.csproj new file mode 100644 index 0000000..7ad3b71 --- /dev/null +++ b/AddIn/EABridge_Example_AddIn_Tests/EABridge_Example_AddIn_Tests.csproj @@ -0,0 +1,31 @@ + + + + net45 + + false + + + + + + + + + + + + + + + + + + + + + ..\..\..\..\..\..\Program Files (x86)\Sparx Systems\EA\Interop.EA.dll + + + + diff --git a/AddIn/EABridge_Example_AddIn_Tests/ReportsTest/ValidationResultTest.cs b/AddIn/EABridge_Example_AddIn_Tests/ReportsTest/ValidationResultTest.cs new file mode 100644 index 0000000..8ec9080 --- /dev/null +++ b/AddIn/EABridge_Example_AddIn_Tests/ReportsTest/ValidationResultTest.cs @@ -0,0 +1,82 @@ +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Newtonsoft.Json; +using EABridge_Example_AddIn.Reports; + +namespace EABridge_Example_AddIn_Tests.ReportsTest +{ + [TestFixture] + public class ValidationResultTest + { + + private readonly string ExampeleJson = @" +{ + ""resourceIssues"":[ + + ], + ""loadIssues"":[ + + ], + ""umlIssues"":[ + { + ""severity"":""W"", + ""type"":""Model"", + ""id"":""1"", + ""message"":""msg1"" + }, + { + ""severity"":""W"", + ""type"":""Class"", + ""id"":""2"", + ""message"":""msg2"" + }, + { + ""severity"":""W"", + ""type"":""Package"", + ""id"":""3"", + ""message"":""msg3"" + }, + { + ""severity"":""W"", + ""type"":""Class"", + ""id"":""4"", + ""message"":""msg4"" + } + ], + ""customIssues"":[ + + ], +} +"; + + private readonly string EmptyJson = "{\"resourceIssues\":[],\"loadIssues\":[],\"umlIssues\":[],\"customIssues\":[]}"; + + [Test] + public void ValidationResult_Should_HandleEmptyStrings() + { + SerializableValidationResult validationReport = JsonConvert.DeserializeObject(EmptyJson); + Assert.IsNotNull(validationReport); + Assert.IsTrue(validationReport.GetAllValidationIssues().Count == 0, "Validation result of an empty string is not empty!"); + } + + [Test] + public void ValidationResult_Should_DeserializeStrings() + { + SerializableValidationResult validationReport = JsonConvert.DeserializeObject(ExampeleJson); + Assert.IsNotNull(validationReport); + Assert.IsTrue(validationReport.GetAllValidationIssues().Count == 4, "Desrialization result of test json is incorrect!"); + Assert.IsTrue(validationReport.umlIssues.Count == 4, "Desrialization result of test json is incorrect!"); + } + + [Test] + public void ValidationResult_Should_HandleMalformedStrings() + { + SerializableValidationResult validationReport = JsonConvert.DeserializeObject(""); + Assert.IsNull(validationReport); + } + } +} diff --git a/AddIn/EABridge_Example_AddIn_Tests/TestUtils/FileUtils.cs b/AddIn/EABridge_Example_AddIn_Tests/TestUtils/FileUtils.cs new file mode 100644 index 0000000..734aa30 --- /dev/null +++ b/AddIn/EABridge_Example_AddIn_Tests/TestUtils/FileUtils.cs @@ -0,0 +1,52 @@ +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace EABridge_Example_AddIn_Tests.TestUtils +{ + public static class FileUtils + { + + public static string BackupFile(string testModelFilePath) + { + string tmpFolder = Path.Combine(Path.GetTempPath()); + string tempModelFilePath = Path.Combine(tmpFolder, string.Format("Copy-of-{0}", Path.GetFileName(testModelFilePath))); + return BackupFile(testModelFilePath, tempModelFilePath); + } + + public static string BackupFile(string testModelFilePath, string targetPath) + { + Assert.IsFalse(string.IsNullOrEmpty(testModelFilePath), "File to backup not defined."); + if (testModelFilePath.StartsWith(Path.DirectorySeparatorChar + "")) + { + testModelFilePath = testModelFilePath.Substring(1); + } + string assemblyFolder = GetAssemblyFolder(); + string sourcePath = Path.Combine(assemblyFolder, testModelFilePath); + try + { + Assert.IsTrue(File.Exists(sourcePath), "File '" + sourcePath + "' does not exist."); + File.Copy(sourcePath, targetPath, true); + } + catch (Exception e) + { + Assert.Fail(e.Message); + } + return targetPath; + } + + public static string GetAssemblyFolder() + { + var filePath = new Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath; + var folder = Path.GetDirectoryName(filePath); + return folder; + } + + + } +} diff --git a/CLI/.mvn/extensions.xml b/CLI/.mvn/extensions.xml new file mode 100644 index 0000000..63ce35f --- /dev/null +++ b/CLI/.mvn/extensions.xml @@ -0,0 +1,7 @@ + + + org.eclipse.tycho.extras + tycho-pomless + 2.4.0 + + \ No newline at end of file diff --git a/CLI/.project b/CLI/.project new file mode 100644 index 0000000..06520b3 --- /dev/null +++ b/CLI/.project @@ -0,0 +1,17 @@ + + + eabridge-example + + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.m2e.core.maven2Nature + + diff --git a/CLI/com.yakindu.bridges.ea.example.cli.feature/.gitignore b/CLI/com.yakindu.bridges.ea.example.cli.feature/.gitignore new file mode 100644 index 0000000..3523549 --- /dev/null +++ b/CLI/com.yakindu.bridges.ea.example.cli.feature/.gitignore @@ -0,0 +1,3 @@ +/bin/ +/target/ +/.polyglot.* diff --git a/CLI/com.yakindu.bridges.ea.example.cli.feature/.project b/CLI/com.yakindu.bridges.ea.example.cli.feature/.project new file mode 100644 index 0000000..6475a25 --- /dev/null +++ b/CLI/com.yakindu.bridges.ea.example.cli.feature/.project @@ -0,0 +1,17 @@ + + + com.yakindu.bridges.ea.example.cli.feature + + + + + + org.eclipse.pde.FeatureBuilder + + + + + + org.eclipse.pde.FeatureNature + + diff --git a/CLI/com.yakindu.bridges.ea.example.cli.feature/build.properties b/CLI/com.yakindu.bridges.ea.example.cli.feature/build.properties new file mode 100644 index 0000000..64f93a9 --- /dev/null +++ b/CLI/com.yakindu.bridges.ea.example.cli.feature/build.properties @@ -0,0 +1 @@ +bin.includes = feature.xml diff --git a/CLI/com.yakindu.bridges.ea.example.cli.feature/feature.xml b/CLI/com.yakindu.bridges.ea.example.cli.feature/feature.xml new file mode 100644 index 0000000..ed4ed23 --- /dev/null +++ b/CLI/com.yakindu.bridges.ea.example.cli.feature/feature.xml @@ -0,0 +1,34 @@ + + + + + YAKINDU EA-Bridge example CLI application. + + + + (C) itemis AG 2022 + + + + Eclipse Public License 2.0 + + + + + + + diff --git a/CLI/com.yakindu.bridges.ea.example.cli.product/.gitignore b/CLI/com.yakindu.bridges.ea.example.cli.product/.gitignore new file mode 100644 index 0000000..3523549 --- /dev/null +++ b/CLI/com.yakindu.bridges.ea.example.cli.product/.gitignore @@ -0,0 +1,3 @@ +/bin/ +/target/ +/.polyglot.* diff --git a/CLI/com.yakindu.bridges.ea.example.cli.product/.project b/CLI/com.yakindu.bridges.ea.example.cli.product/.project new file mode 100644 index 0000000..754f7f9 --- /dev/null +++ b/CLI/com.yakindu.bridges.ea.example.cli.product/.project @@ -0,0 +1,11 @@ + + + com.yakindu.bridges.ea.example.cli.product + + + + + + + + diff --git a/CLI/com.yakindu.bridges.ea.example.cli.product/com.yakindu.bridges.ea.example.cli.product.product b/CLI/com.yakindu.bridges.ea.example.cli.product/com.yakindu.bridges.ea.example.cli.product.product new file mode 100644 index 0000000..d748ae5 --- /dev/null +++ b/CLI/com.yakindu.bridges.ea.example.cli.product/com.yakindu.bridges.ea.example.cli.product.product @@ -0,0 +1,56 @@ + + + + + + + + + + -consoleLog + + -Xmx2g + + + + + + + + + + + + + + org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CLI/com.yakindu.bridges.ea.example.cli.target/.gitignore b/CLI/com.yakindu.bridges.ea.example.cli.target/.gitignore new file mode 100644 index 0000000..c50980d --- /dev/null +++ b/CLI/com.yakindu.bridges.ea.example.cli.target/.gitignore @@ -0,0 +1 @@ +/.polyglot.* diff --git a/CLI/com.yakindu.bridges.ea.example.cli.target/.project b/CLI/com.yakindu.bridges.ea.example.cli.target/.project new file mode 100644 index 0000000..ea8feb5 --- /dev/null +++ b/CLI/com.yakindu.bridges.ea.example.cli.target/.project @@ -0,0 +1,17 @@ + + + com.yakindu.bridges.ea.example.cli.target + + + + + + org.eclipse.xtext.ui.shared.xtextBuilder + + + + + + org.eclipse.xtext.ui.shared.xtextNature + + diff --git a/CLI/com.yakindu.bridges.ea.example.cli.target/com.yakindu.bridges.ea.example.cli.target.target b/CLI/com.yakindu.bridges.ea.example.cli.target/com.yakindu.bridges.ea.example.cli.target.target new file mode 100644 index 0000000..af184ee --- /dev/null +++ b/CLI/com.yakindu.bridges.ea.example.cli.target/com.yakindu.bridges.ea.example.cli.target.target @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CLI/com.yakindu.bridges.ea.example.cli.target/com.yakindu.bridges.ea.example.cli.target.tpd b/CLI/com.yakindu.bridges.ea.example.cli.target/com.yakindu.bridges.ea.example.cli.target.tpd new file mode 100644 index 0000000..9a19039 --- /dev/null +++ b/CLI/com.yakindu.bridges.ea.example.cli.target/com.yakindu.bridges.ea.example.cli.target.tpd @@ -0,0 +1,40 @@ +/* + * This target definition platform is created with: Target Platform Definition DSL and Generator + * It can be installed from: https://download.eclipse.org/cbi/tpd/3.0.0-SNAPSHOT/ + */ +target "com.yakindu.bridges.ea.example.target" with source requirements + +location "https://ftp-stud.hs-esslingen.de/Mirrors/eclipse/justj/jres/11/updates/release" { + org.eclipse.justj.openjdk.hotspot.jre.full.feature.group [11.0.13,12.0.0) +} + +// Esslingen mirror is much faster than eclipse.org! +location eclipse-2021-06 "https://ftp-stud.hs-esslingen.de/Mirrors/eclipse/releases/2022-03/202203161000/" { + org.eclipse.emf.feature.group + org.eclipse.sdk.ide + org.eclipse.uml2.sdk.feature.group +} + +location yakindu-ea_bridge "https://updates.yakindu.com/ea-bridge/updates/" { + com.yakindu.bridges.ea.core.feature.group lazy + com.yakindu.bridges.ea.core.ui.feature.group lazy + com.yakindu.bridges.ea.dev.feature.group lazy + com.yakindu.bridges.ea.uml.feature.group lazy + com.yakindu.bridges.ea.uml.ui.feature.group lazy + com.yakindu.bridges.ea.examples.feature.group lazy + com.yakindu.licmgmt.feature.feature.group lazy + com.yakindu.licmgmt.ui.feature.feature.group lazy + com.sun.jna.feature.feature.group lazy + com.yakindu.interop.enterprise.architect.feature.feature.group lazy +} + +location eclipse-orbit "https://download.eclipse.org/tools/orbit/downloads/drops/R20220302172233/repository" { + // let's add guava here, all other dependencies are automatically loaded via planner + com.google.guava + com.google.inject + com.google.gson +} + +location equinoxexecutable "https://ftp-stud.hs-esslingen.de/Mirrors/eclipse/eclipse/updates/4.23/" { + org.eclipse.equinox.executable.feature.group +} diff --git a/CLI/com.yakindu.bridges.ea.example.cli.test/.classpath b/CLI/com.yakindu.bridges.ea.example.cli.test/.classpath new file mode 100644 index 0000000..a42a828 --- /dev/null +++ b/CLI/com.yakindu.bridges.ea.example.cli.test/.classpath @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/CLI/com.yakindu.bridges.ea.example.cli.test/.gitignore b/CLI/com.yakindu.bridges.ea.example.cli.test/.gitignore new file mode 100644 index 0000000..3523549 --- /dev/null +++ b/CLI/com.yakindu.bridges.ea.example.cli.test/.gitignore @@ -0,0 +1,3 @@ +/bin/ +/target/ +/.polyglot.* diff --git a/CLI/com.yakindu.bridges.ea.example.cli.test/.project b/CLI/com.yakindu.bridges.ea.example.cli.test/.project new file mode 100644 index 0000000..b866ef7 --- /dev/null +++ b/CLI/com.yakindu.bridges.ea.example.cli.test/.project @@ -0,0 +1,28 @@ + + + com.yakindu.bridges.ea.example.cli.test + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/CLI/com.yakindu.bridges.ea.example.cli.test/ExampleCLI.launch b/CLI/com.yakindu.bridges.ea.example.cli.test/ExampleCLI.launch new file mode 100644 index 0000000..f1ddf4b --- /dev/null +++ b/CLI/com.yakindu.bridges.ea.example.cli.test/ExampleCLI.launch @@ -0,0 +1,318 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CLI/com.yakindu.bridges.ea.example.cli.test/ExampleCLITest.launch b/CLI/com.yakindu.bridges.ea.example.cli.test/ExampleCLITest.launch new file mode 100644 index 0000000..599d2d2 --- /dev/null +++ b/CLI/com.yakindu.bridges.ea.example.cli.test/ExampleCLITest.launch @@ -0,0 +1,225 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CLI/com.yakindu.bridges.ea.example.cli.test/META-INF/MANIFEST.MF b/CLI/com.yakindu.bridges.ea.example.cli.test/META-INF/MANIFEST.MF new file mode 100644 index 0000000..e28f252 --- /dev/null +++ b/CLI/com.yakindu.bridges.ea.example.cli.test/META-INF/MANIFEST.MF @@ -0,0 +1,21 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Example validation CLI Tests +Bundle-SymbolicName: com.yakindu.bridges.ea.example.cli.test +Bundle-Version: 1.0.0.qualifier +Bundle-Vendor: itemis AG +Automatic-Module-Name: com.yakindu.bridges.ea.example.cli.test +Bundle-RequiredExecutionEnvironment: JavaSE-11 +Require-Bundle: org.junit, + org.eclipse.equinox.app, + org.eclipse.osgi, + org.eclipse.core.runtime, + org.eclipse.core.resources, + org.eclipse.emf.common, + com.yakindu.bridges.ea.core, + com.yakindu.bridges.ea.uml, + com.google.inject, + org.eclipse.xtext, + com.yakindu.bridges.ea.example.cli, + com.yakindu.bridges.ea.example.cli.validation, + com.google.gson diff --git a/CLI/com.yakindu.bridges.ea.example.cli.test/Runtime IDE.launch b/CLI/com.yakindu.bridges.ea.example.cli.test/Runtime IDE.launch new file mode 100644 index 0000000..d789847 --- /dev/null +++ b/CLI/com.yakindu.bridges.ea.example.cli.test/Runtime IDE.launch @@ -0,0 +1,300 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CLI/com.yakindu.bridges.ea.example.cli.test/build.properties b/CLI/com.yakindu.bridges.ea.example.cli.test/build.properties new file mode 100644 index 0000000..e4688e2 --- /dev/null +++ b/CLI/com.yakindu.bridges.ea.example.cli.test/build.properties @@ -0,0 +1,5 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + testModels/ diff --git a/CLI/com.yakindu.bridges.ea.example.cli.test/src/com/yakindu/bridges/ea/example/cli/test/ApplicationTestContext.java b/CLI/com.yakindu.bridges.ea.example.cli.test/src/com/yakindu/bridges/ea/example/cli/test/ApplicationTestContext.java new file mode 100644 index 0000000..15b56c3 --- /dev/null +++ b/CLI/com.yakindu.bridges.ea.example.cli.test/src/com/yakindu/bridges/ea/example/cli/test/ApplicationTestContext.java @@ -0,0 +1,64 @@ +package com.yakindu.bridges.ea.example.cli.test; + +import java.util.Collections; +import java.util.Map; + +import org.eclipse.equinox.app.IApplication; +import org.eclipse.equinox.app.IApplicationContext; +import org.osgi.framework.Bundle; + +public class ApplicationTestContext implements IApplicationContext { + + private String[] args; + + public ApplicationTestContext(String... args) { + this.args = args; + } + + @Override + @SuppressWarnings("rawtypes") + public Map getArguments() { + return Collections.singletonMap(IApplicationContext.APPLICATION_ARGS, args); + } + + @Override + public void applicationRunning() { + + } + + @Override + public String getBrandingApplication() { + return null; + } + + @Override + public String getBrandingName() { + return null; + } + + @Override + public String getBrandingDescription() { + return null; + } + + @Override + public String getBrandingId() { + return null; + } + + @Override + public String getBrandingProperty(String key) { + return null; + } + + @Override + public Bundle getBrandingBundle() { + return null; + } + + @Override + public void setResult(Object result, IApplication application) { + + } + +} diff --git a/CLI/com.yakindu.bridges.ea.example.cli.test/src/com/yakindu/bridges/ea/example/cli/test/ExampleCLITest.java b/CLI/com.yakindu.bridges.ea.example.cli.test/src/com/yakindu/bridges/ea/example/cli/test/ExampleCLITest.java new file mode 100644 index 0000000..43a8ce3 --- /dev/null +++ b/CLI/com.yakindu.bridges.ea.example.cli.test/src/com/yakindu/bridges/ea/example/cli/test/ExampleCLITest.java @@ -0,0 +1,66 @@ +package com.yakindu.bridges.ea.example.cli.test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +//import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.PrintStream; +import java.util.List; + +import org.eclipse.emf.common.util.URI; +import org.eclipse.equinox.app.IApplication; +//import org.junit.jupiter.api.Test; +import org.junit.Test; + +import com.yakindu.bridges.ea.core.utils.URIToOSPathConverter; +import com.yakindu.bridges.ea.example.cli.ExampleCLI; + +public class ExampleCLITest { + + String PLUGIN_ID = "com.yakindu.bridges.ea.example.cli.test"; + + URI TEST_MODEL = URI.createPlatformPluginURI(PLUGIN_ID + "/testModels/Example.eap", true); + + @Test + public void helpOutput() throws Exception { + final String output = run(IApplication.EXIT_OK); + assertEquals(ExampleCLI.HELP, output); + + } + + private String run(Integer expectedExitCode, String... args) throws Exception { + // redirect System output (redirect error output if needed, too) + final PrintStream defaultOutStream = System.out; + try { + final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + System.setOut(new PrintStream(outputStream)); + + final ExampleCLI cli = new ExampleCLI(); + final Object code = cli.start(new ApplicationTestContext(args)); + assertEquals(expectedExitCode, code); + return outputStream.toString().trim(); + } finally { + System.setOut(defaultOutStream); + } + } + + @Test + public void noValidationIssueInRefModel() throws Exception { + // given + final String eapFile = URIToOSPathConverter.getFileFromURI(TEST_MODEL); + final File tmpFile = File.createTempFile(getClass().getName(), ".json"); + tmpFile.deleteOnExit(); + final String elementToValidate = "LibraryModel"; + final String[] args = { ExampleCLI.APP_VALIDATE, eapFile, tmpFile.getAbsolutePath(), elementToValidate, + ExampleCLI.VERBOSE_OUTPUT }; + // when + final String output = run(IApplication.EXIT_OK, args); + // then + for (String segment : List.of(">> Collecting UML Elements DONE.", ">> Validating DONE.", ">> Writing report")) { + assertTrue("Missing in console output: \"" + segment + "\"\n\n" + output, output.contains(segment)); + } + } +} \ No newline at end of file diff --git a/CLI/com.yakindu.bridges.ea.example.cli.test/src/com/yakindu/bridges/ea/example/cli/test/validation/ModelValidationTest.java b/CLI/com.yakindu.bridges.ea.example.cli.test/src/com/yakindu/bridges/ea/example/cli/test/validation/ModelValidationTest.java new file mode 100644 index 0000000..8643201 --- /dev/null +++ b/CLI/com.yakindu.bridges.ea.example.cli.test/src/com/yakindu/bridges/ea/example/cli/test/validation/ModelValidationTest.java @@ -0,0 +1,115 @@ +package com.yakindu.bridges.ea.example.cli.test.validation; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; +import org.eclipse.emf.ecore.util.EcoreUtil; +import org.eclipse.uml2.uml.Class; +import org.eclipse.uml2.uml.Model; +import org.eclipse.uml2.uml.Package; +import org.eclipse.uml2.uml.UMLPackage; +import org.junit.Test; + +import com.yakindu.bridges.ea.example.cli.validation.ModelValidation; +import com.yakindu.bridges.ea.example.cli.validation.ValidationResult; + +public class ModelValidationTest { + + @Test + public void missingReportFileArgument() { + // given + final Resource resource = new ResourceSetImpl().createResource(URI.createURI("mem:/test.uml")); + try { + // when + new ModelValidation(resource, Collections.emptyList(), " "); + fail("exception expected about missing report file argument"); + } catch (Exception e) { + // then + assertTrue("CLI exception expected", e instanceof Exception); + assertEquals("exception expected about missing report file argument", "Report file argument missing", + e.getMessage()); + } + } + + @Test + public void validationForSingleElementInModel() throws FileNotFoundException, IOException { + final Model model = (Model) EcoreUtil.create((EClass) UMLPackage.eINSTANCE.getEClassifier("Model")); + final URI uri = URI.createURI("mem:/test.uml", true); + final Resource resource = new ResourceSetImpl().createResource(uri); + resource.getContents().add(model); + + Package pack = model.createNestedPackage("pack"); + + final Class abstractClass = pack.createOwnedClass("someClass", false); + abstractClass.setIsAbstract(true); + + final Class childClass = pack.createOwnedClass("childClass", false); + final Class anotherChildClass = pack.createOwnedClass("anotherChildClass", false); + + // create inheritance connectors + childClass.createGeneralization(abstractClass); + anotherChildClass.createGeneralization(abstractClass); + + // when + + ModelValidation validation = new ModelValidation(resource, Arrays.asList(abstractClass), + File.createTempFile(getClass().getName(), ".json").getAbsolutePath()); + + validation.validate(); + ValidationResult validationResult = validation.getValidationResult(); + + // then + + assertEquals("Unexpected number of warnings reported", 1, validationResult.getCustomWarnings().size()); + assertEquals("Unexpected number of errors reported", 0, validationResult.getCustomErrors().size()); + List warning = validationResult.getCustomWarnings().get(abstractClass); + + // validation for the other two classes in this package should report report the same warning + // because the validator will validate all elements in the nearest package. + + // when + + validation = new ModelValidation(resource, Arrays.asList(childClass, anotherChildClass), + File.createTempFile(getClass().getName(), ".json").getAbsolutePath()); + validation.validate(); + validationResult = validation.getValidationResult(); + + // then + + assertEquals("Unexpected number of warnings reported", 1, validationResult.getCustomWarnings().size()); + assertEquals("Unexpected number of errors reported", 0, validationResult.getCustomErrors().size()); + assertNotNull("warning is not reported to the correct model element", + validationResult.getCustomWarnings().get(abstractClass)); + assertEquals(validationResult.getCustomWarnings().get(abstractClass), warning); + + // validation of a different package should not include issues found in the package `context` + // when + + Package pack2 = model.createNestedPackage("pack2"); + pack2.createOwnedClass("someClass", false); + validation = new ModelValidation(resource, Arrays.asList(pack2), + File.createTempFile(getClass().getName(), ".json").getAbsolutePath()); + validation.validate(); + validationResult = validation.getValidationResult(); + + // then + + assertEquals("Unexpected number of warnings reported", 0, validationResult.getCustomWarnings().size()); + assertEquals("Unexpected number of errors reported", 0, validationResult.getCustomErrors().size()); + + } + +} diff --git a/CLI/com.yakindu.bridges.ea.example.cli.test/src/com/yakindu/bridges/ea/example/cli/test/validation/RuleAbstractClassPrefixTest.java b/CLI/com.yakindu.bridges.ea.example.cli.test/src/com/yakindu/bridges/ea/example/cli/test/validation/RuleAbstractClassPrefixTest.java new file mode 100644 index 0000000..9d6e6e1 --- /dev/null +++ b/CLI/com.yakindu.bridges.ea.example.cli.test/src/com/yakindu/bridges/ea/example/cli/test/validation/RuleAbstractClassPrefixTest.java @@ -0,0 +1,59 @@ +package com.yakindu.bridges.ea.example.cli.test.validation; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; +import org.eclipse.emf.ecore.util.EcoreUtil; +import org.eclipse.uml2.uml.Class; +import org.eclipse.uml2.uml.Model; +import org.eclipse.uml2.uml.Package; +import org.eclipse.uml2.uml.UMLPackage; +import org.junit.Test; + +import com.yakindu.bridges.ea.example.cli.validation.custom.RuleAbstractClassPrefix; + +public class RuleAbstractClassPrefixTest { + + @Test + public void reportAbstractClassesWithoutPrefix() { + // given + final Model model = (Model) EcoreUtil.create((EClass) UMLPackage.eINSTANCE.getEClassifier("Model")); + final URI uri = URI.createURI("mem:/test.uml", true); + final Resource resource = new ResourceSetImpl().createResource(uri); + resource.getContents().add(model); + + Package context = model.createNestedPackage("pack"); + + final Class abstractClass = context.createOwnedClass("someClass", false); + abstractClass.setIsAbstract(true); + + final Class childClass = context.createOwnedClass("childClass", false); + final Class anotherChildClass = context.createOwnedClass("anotherChildClass", false); + + // create inheritance connectors + childClass.createGeneralization(abstractClass); + anotherChildClass.createGeneralization(abstractClass); + + // when + final List errors = new ArrayList<>(); + final List warnings = new ArrayList<>(); + new RuleAbstractClassPrefix().validate(abstractClass, errors::add, warnings::add); + + // then + assertEquals("Unexpected number of errors reported: ", 0, errors.size()); + assertEquals("Unexpected warnings reported", 1, warnings.size()); + + final String warning = warnings.get(0); + assertTrue("Unexpected validation error: " + warning, + warning.startsWith("Abstract class 'someClass' should start with 'Abstract'.")); + + } + +} diff --git a/CLI/com.yakindu.bridges.ea.example.cli.test/src/com/yakindu/bridges/ea/example/cli/test/validation/UMLValidationTest.java b/CLI/com.yakindu.bridges.ea.example.cli.test/src/com/yakindu/bridges/ea/example/cli/test/validation/UMLValidationTest.java new file mode 100644 index 0000000..679754e --- /dev/null +++ b/CLI/com.yakindu.bridges.ea.example.cli.test/src/com/yakindu/bridges/ea/example/cli/test/validation/UMLValidationTest.java @@ -0,0 +1,58 @@ +package com.yakindu.bridges.ea.example.cli.test.validation; + +import static org.junit.Assert.assertEquals; + +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; +import org.eclipse.emf.ecore.util.EcoreUtil; +import org.eclipse.uml2.uml.Model; +import org.eclipse.uml2.uml.Package; +import org.eclipse.uml2.uml.UMLPackage; +import org.junit.Test; + +import com.yakindu.bridges.ea.example.cli.validation.ValidationResult; +import com.yakindu.bridges.ea.example.cli.validation.report.ValidationReport; +import com.yakindu.bridges.ea.example.cli.validation.uml.UMLValidation; + +public class UMLValidationTest { + + @Test + public void validationWithoutErrors() { + // given: simple UML model without errors + final Model model = (Model) EcoreUtil.create((EClass) UMLPackage.eINSTANCE.getEClassifier("Model")); + final Package pack = model.createNestedPackage("pack"); + pack.createPackagedElement("someClass", UMLPackage.Literals.CLASS); + final URI uri = URI.createURI("mem:/test.uml"); + final Resource resource = new ResourceSetImpl().createResource(uri); + resource.getContents().add(model); + // when + final ValidationResult result = new ValidationResult(resource); + UMLValidation.validate(resource, result); + // then + assertEquals("unexpected validation results: " + result, 0, result.count()); + } + + @Test + public void validateWithUmlErrorsAndWarnings() { + // given: simple model with two identical classes in the same package + final Model model = (Model) EcoreUtil.create((EClass) UMLPackage.eINSTANCE.getEClassifier("Model")); + final Package pack = model.createNestedPackage("pack"); + pack.createPackagedElement("duplicateClass", UMLPackage.Literals.CLASS); + pack.createPackagedElement("duplicateClass", UMLPackage.Literals.CLASS); + + final URI uri = URI.createURI("mem:/test.uml"); + final Resource resource = new ResourceSetImpl().createResource(uri); + resource.getContents().add(model); + // when + final ValidationResult result = new ValidationResult(resource); + UMLValidation.validate(resource, result); + ValidationReport report = new ValidationReport(result); + System.out.println(report.create()); + // then + assertEquals("unexpected validation results: " + result, 4, + result.getUmlErrors().size() + result.getUmlWarnings().size()); + } + +} diff --git a/CLI/com.yakindu.bridges.ea.example.cli.test/src/com/yakindu/bridges/ea/example/cli/test/validation/ValidationReportTest.java b/CLI/com.yakindu.bridges.ea.example.cli.test/src/com/yakindu/bridges/ea/example/cli/test/validation/ValidationReportTest.java new file mode 100644 index 0000000..1f28a13 --- /dev/null +++ b/CLI/com.yakindu.bridges.ea.example.cli.test/src/com/yakindu/bridges/ea/example/cli/test/validation/ValidationReportTest.java @@ -0,0 +1,84 @@ +package com.yakindu.bridges.ea.example.cli.test.validation; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.Arrays; + +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; +import org.eclipse.emf.ecore.util.EcoreUtil; +import org.eclipse.uml2.uml.Class; +import org.eclipse.uml2.uml.Model; +import org.eclipse.uml2.uml.Package; +import org.eclipse.uml2.uml.UMLPackage; +import org.junit.Test; + +import com.google.gson.Gson; +import com.yakindu.bridges.ea.example.cli.validation.ModelValidation; +import com.yakindu.bridges.ea.example.cli.validation.ValidationResult; +import com.yakindu.bridges.ea.example.cli.validation.report.ValidationReport; +import com.yakindu.bridges.ea.example.cli.validation.report.ValidationResultsJsonContainer; + +public class ValidationReportTest { + + @Test + public void emptyReport() { + // given + final Resource resource = new ResourceSetImpl().createResource(URI.createURI("mem:/test.uml")); + final ValidationResult result = new ValidationResult(resource); + // when + final String report = new ValidationReport(result).create(); + // then + assertEquals("unexpected empty report", + "{\"resourceIssues\":[],\"loadIssues\":[],\"umlIssues\":[],\"customIssues\":[]}", report); + + } + + @Test + public void jsonReportShouldBeValid() throws FileNotFoundException, IOException { + final Model model = (Model) EcoreUtil.create((EClass) UMLPackage.eINSTANCE.getEClassifier("Model")); + final URI uri = URI.createURI("mem:/test.uml", true); + final Resource resource = new ResourceSetImpl().createResource(uri); + resource.getContents().add(model); + + Package pack = model.createNestedPackage("pack"); + + final Class abstractClass = pack.createOwnedClass("someClass", false); + abstractClass.setIsAbstract(true); + + final Class childClass = pack.createOwnedClass("childClass", false); + final Class anotherChildClass = pack.createOwnedClass("anotherChildClass", false); + + final Package pack2 = model.createNestedPackage("pack2"); + pack2.createOwnedClass("someClass", false); + + // create inheritance connectors + childClass.createGeneralization(abstractClass); + anotherChildClass.createGeneralization(abstractClass); + + // when + ModelValidation validation = new ModelValidation(resource, Arrays.asList(abstractClass), + File.createTempFile(getClass().getName(), ".json").getAbsolutePath()); + + validation.validate(); + ValidationResult validationResult = validation.getValidationResult(); + + validation = new ModelValidation(resource, Arrays.asList(pack2), + File.createTempFile(getClass().getName(), ".json").getAbsolutePath()); + validation.validate(); + validationResult = validation.getValidationResult(); + String report = new ValidationReport(validationResult).create(); + + Gson jsonHandler = new Gson(); + ValidationResultsJsonContainer deserializedJson = jsonHandler.fromJson(report, + ValidationResultsJsonContainer.class); + assertNotNull("json validation result is not written correctly", deserializedJson); + assertEquals(validationResult.count(), deserializedJson.count()); + } +} diff --git a/CLI/com.yakindu.bridges.ea.example.cli.test/testModels/Example.eap b/CLI/com.yakindu.bridges.ea.example.cli.test/testModels/Example.eap new file mode 100644 index 0000000..232bb5d Binary files /dev/null and b/CLI/com.yakindu.bridges.ea.example.cli.test/testModels/Example.eap differ diff --git a/CLI/com.yakindu.bridges.ea.example.cli.validation/.classpath b/CLI/com.yakindu.bridges.ea.example.cli.validation/.classpath new file mode 100644 index 0000000..e801ebf --- /dev/null +++ b/CLI/com.yakindu.bridges.ea.example.cli.validation/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/CLI/com.yakindu.bridges.ea.example.cli.validation/.gitignore b/CLI/com.yakindu.bridges.ea.example.cli.validation/.gitignore new file mode 100644 index 0000000..3523549 --- /dev/null +++ b/CLI/com.yakindu.bridges.ea.example.cli.validation/.gitignore @@ -0,0 +1,3 @@ +/bin/ +/target/ +/.polyglot.* diff --git a/CLI/com.yakindu.bridges.ea.example.cli.validation/.project b/CLI/com.yakindu.bridges.ea.example.cli.validation/.project new file mode 100644 index 0000000..bbaf2fd --- /dev/null +++ b/CLI/com.yakindu.bridges.ea.example.cli.validation/.project @@ -0,0 +1,28 @@ + + + com.yakindu.bridges.ea.example.cli.validation + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/CLI/com.yakindu.bridges.ea.example.cli.validation/META-INF/MANIFEST.MF b/CLI/com.yakindu.bridges.ea.example.cli.validation/META-INF/MANIFEST.MF new file mode 100644 index 0000000..49909df --- /dev/null +++ b/CLI/com.yakindu.bridges.ea.example.cli.validation/META-INF/MANIFEST.MF @@ -0,0 +1,16 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Example CLI Validation +Bundle-SymbolicName: com.yakindu.bridges.ea.example.cli.validation +Bundle-Version: 1.0.0.qualifier +Bundle-Vendor: itemis AG +Automatic-Module-Name: com.yakindu.bridges.ea.example.validation +Bundle-RequiredExecutionEnvironment: JavaSE-11 +Export-Package: com.yakindu.bridges.ea.example.cli.validation, + com.yakindu.bridges.ea.example.cli.validation.custom, + com.yakindu.bridges.ea.example.cli.validation.report, + com.yakindu.bridges.ea.example.cli.validation.uml +Require-Bundle: org.eclipse.emf.ecore, + org.eclipse.uml2.uml, + com.yakindu.bridges.ea.core, + com.google.gson diff --git a/CLI/com.yakindu.bridges.ea.example.cli.validation/build.properties b/CLI/com.yakindu.bridges.ea.example.cli.validation/build.properties new file mode 100644 index 0000000..34d2e4d --- /dev/null +++ b/CLI/com.yakindu.bridges.ea.example.cli.validation/build.properties @@ -0,0 +1,4 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + . diff --git a/CLI/com.yakindu.bridges.ea.example.cli.validation/src/com/yakindu/bridges/ea/example/cli/validation/ModelValidation.java b/CLI/com.yakindu.bridges.ea.example.cli.validation/src/com/yakindu/bridges/ea/example/cli/validation/ModelValidation.java new file mode 100644 index 0000000..b0f5bca --- /dev/null +++ b/CLI/com.yakindu.bridges.ea.example.cli.validation/src/com/yakindu/bridges/ea/example/cli/validation/ModelValidation.java @@ -0,0 +1,84 @@ +package com.yakindu.bridges.ea.example.cli.validation; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.uml2.uml.Element; + +import com.yakindu.bridges.ea.example.cli.validation.custom.CustomValidation; +import com.yakindu.bridges.ea.example.cli.validation.report.ValidationReport; +import com.yakindu.bridges.ea.example.cli.validation.uml.UMLValidation; + +public class ModelValidation { + + private final Resource resource; + private final List elements; + private final String reportFile; + + private ValidationResult result; + + public ModelValidation(Resource resource, List elements, String reportFile) throws FileNotFoundException { + this.resource = resource; + if (elements == null) { + this.elements = new ArrayList<>(); + } else { + this.elements = elements; + } + this.reportFile = reportFile; + + if (resource == null) + throw new IllegalArgumentException("Resource argument must not be null"); + + if (reportFile == null || reportFile.isBlank()) + throw new IllegalArgumentException("Report file argument missing"); + + final File file = new File(reportFile); + if (file.exists() && !file.delete()) + throw new FileNotFoundException("Failed to delete existing report file: " + file.getAbsolutePath()); + } + + public List validate() { + + // this already collects all load issues + result = new ValidationResult(resource); + + // add uml issues + UMLValidation.validate(resource, result); + + // add custom issues + new CustomValidation(resource, elements).validate(result); + + return result.asList(); + } + + public void createReport() { + if (result == null) + throw new IllegalStateException("Please call 'validate()' first"); + + final String content = new ValidationReport(result).create(); + + try (FileOutputStream outputStream = new FileOutputStream(reportFile)) { + try (final Writer bw = new BufferedWriter(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8))) { + bw.write(content); + } + } catch (final IOException e) { + throw new RuntimeException("Failed to create report", e); + } + } + + public ValidationResult getValidationResult() { + if (result == null) + throw new IllegalStateException("Please call 'validate()' first"); + return this.result; + } + +} diff --git a/CLI/com.yakindu.bridges.ea.example.cli.validation/src/com/yakindu/bridges/ea/example/cli/validation/ValidationResult.java b/CLI/com.yakindu.bridges.ea.example.cli.validation/src/com/yakindu/bridges/ea/example/cli/validation/ValidationResult.java new file mode 100644 index 0000000..7e89c0d --- /dev/null +++ b/CLI/com.yakindu.bridges.ea.example.cli.validation/src/com/yakindu/bridges/ea/example/cli/validation/ValidationResult.java @@ -0,0 +1,142 @@ +package com.yakindu.bridges.ea.example.cli.validation; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.resource.Resource.Diagnostic; +import org.eclipse.uml2.uml.util.UMLUtil; + +import com.yakindu.bridges.ea.core.EAModelError; +import com.yakindu.bridges.ea.core.utils.MapUtils; + +public class ValidationResult { + + private static final int DEFAULT_LIST_SIZE = 4; + + private final List resourceWarnings = new ArrayList<>(); + private final List resourceErrors = new ArrayList<>(); + + private final Map> loadWarnings = new HashMap<>(); + private final Map> loadErrors = new HashMap<>(); + + private final Map> umlWarnings = new HashMap<>(); + private final Map> umlErrors = new HashMap<>(); + + private final Map> customWarnings = new HashMap<>(); + private final Map> customErrors = new HashMap<>(); + + public ValidationResult(Resource resource) { + resource.getErrors().forEach(error -> addIssue(loadErrors, error)); + resource.getWarnings().forEach(warning -> addIssue(loadWarnings, warning)); + } + + private void addIssue(Map> issues, Diagnostic issue) { + if (issue instanceof EAModelError) { + final EObject element = ((EAModelError) issue).getContextElement(); + if (element == null) { + if (((EAModelError) issue).getSeverity() == IStatus.ERROR) { + resourceErrors.add(issue.getMessage()); + } else if (((EAModelError) issue).getSeverity() == IStatus.WARNING) { + resourceWarnings.add(issue.getMessage()); + } + } else { + if (((EAModelError) issue).getSeverity() == IStatus.ERROR) { + MapUtils.addToListMap(loadErrors, element, DEFAULT_LIST_SIZE, issue.getMessage()); + } else if (((EAModelError) issue).getSeverity() == IStatus.WARNING) { + MapUtils.addToListMap(loadWarnings, element, DEFAULT_LIST_SIZE, issue.getMessage()); + } + } + } else { + final String msg = String.format("%s while loading '%s' (line %d, column %d): %s", // + issue.getClass().getSimpleName(), issue.getLocation(), issue.getLine(), issue.getColumn(), + issue.getMessage()); + resourceErrors.add(msg); + } + } + + public void addUmlError(EObject object, String message) { + MapUtils.addToListMap(umlErrors, object, DEFAULT_LIST_SIZE, message); + } + + public void addUmlWarning(EObject object, String message) { + MapUtils.addToListMap(umlWarnings, object, DEFAULT_LIST_SIZE, message); + } + + public void addCustomError(EObject object, String message) { + MapUtils.addToListMap(customErrors, object, DEFAULT_LIST_SIZE, message); + } + + public void addCustomWarning(EObject object, String message) { + MapUtils.addToListMap(customWarnings, object, DEFAULT_LIST_SIZE, message); + } + + public int count() { + return resourceWarnings.size() + resourceErrors.size() // + + loadWarnings.size() + loadErrors.size() // + + umlWarnings.size() + umlErrors.size() // + + customWarnings.size() + customErrors.size(); + } + + public List asList() { + final List list = new ArrayList<>(count()); + resourceWarnings.forEach(issue -> list.add("[W:Resource] " + issue)); + resourceErrors.forEach(issue -> list.add("[E:Resource] " + issue)); + loadWarnings.entrySet().forEach(issues -> list.addAll(asString("[W:Load]", issues))); + loadErrors.entrySet().forEach(issues -> list.addAll(asString("[E:Load]", issues))); + umlWarnings.entrySet().forEach(issues -> list.addAll(asString("[W:UML]", issues))); + umlErrors.entrySet().forEach(issues -> list.addAll(asString("[E:UML]", issues))); + customWarnings.entrySet().forEach(issues -> list.addAll(asString("[W:Custom]", issues))); + customErrors.entrySet().forEach(issues -> list.addAll(asString("[E:Custom]", issues))); + Collections.sort(list); + return list; + } + + private List asString(String prefix, Entry> issues) { + if (issues == null || issues.getValue().isEmpty()) + return Collections.emptyList(); + final List result = new ArrayList<>(issues.getValue().size()); + final String objName = UMLUtil.getQualifiedText(issues.getKey()); + issues.getValue().forEach(issue -> result.add(String.format("%s '%s': %s", prefix, objName, issue))); + return result; + } + + public List getResourceWarnings() { + return Collections.unmodifiableList(resourceWarnings); + } + + public List getResourceErrors() { + return Collections.unmodifiableList(resourceErrors); + } + + public Map> getLoadWarnings() { + return Collections.unmodifiableMap(loadWarnings); + } + + public Map> getLoadErrors() { + return Collections.unmodifiableMap(loadErrors); + } + + public Map> getUmlWarnings() { + return Collections.unmodifiableMap(umlWarnings); + } + + public Map> getUmlErrors() { + return Collections.unmodifiableMap(umlErrors); + } + + public Map> getCustomWarnings() { + return Collections.unmodifiableMap(customWarnings); + } + + public Map> getCustomErrors() { + return Collections.unmodifiableMap(customErrors); + } + +} diff --git a/CLI/com.yakindu.bridges.ea.example.cli.validation/src/com/yakindu/bridges/ea/example/cli/validation/custom/AbstractValidationRule.java b/CLI/com.yakindu.bridges.ea.example.cli.validation/src/com/yakindu/bridges/ea/example/cli/validation/custom/AbstractValidationRule.java new file mode 100644 index 0000000..8a8093b --- /dev/null +++ b/CLI/com.yakindu.bridges.ea.example.cli.validation/src/com/yakindu/bridges/ea/example/cli/validation/custom/AbstractValidationRule.java @@ -0,0 +1,31 @@ +package com.yakindu.bridges.ea.example.cli.validation.custom; + +import java.util.function.Consumer; + +import org.eclipse.uml2.uml.Element; + +import com.yakindu.bridges.ea.example.cli.validation.ValidationResult; + +public abstract class AbstractValidationRule { + + public final Class applicableTo; + + protected AbstractValidationRule(Class applicableTo) { + this.applicableTo = applicableTo; + } + + protected void validate(Element obj, ValidationResult result) { + if (obj == null || !applicableTo.isInstance(obj)) + throw new IllegalArgumentException("Parameter has unexpected type: " + obj); + try { + validate(applicableTo.cast(obj), // + e -> result.addCustomError(obj, e), // + w -> result.addCustomWarning(obj, w)); + } catch (Exception e) { + e.printStackTrace(); + } + } + + protected abstract void validate(T obj, Consumer addError, Consumer addWarning); + +} diff --git a/CLI/com.yakindu.bridges.ea.example.cli.validation/src/com/yakindu/bridges/ea/example/cli/validation/custom/CustomValidation.java b/CLI/com.yakindu.bridges.ea.example.cli.validation/src/com/yakindu/bridges/ea/example/cli/validation/custom/CustomValidation.java new file mode 100644 index 0000000..7298b7e --- /dev/null +++ b/CLI/com.yakindu.bridges.ea.example.cli.validation/src/com/yakindu/bridges/ea/example/cli/validation/custom/CustomValidation.java @@ -0,0 +1,65 @@ +package com.yakindu.bridges.ea.example.cli.validation.custom; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import org.eclipse.emf.common.util.TreeIterator; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.uml2.uml.Element; +import org.eclipse.uml2.uml.Package; + +import com.yakindu.bridges.ea.core.utils.MapUtils; +import com.yakindu.bridges.ea.example.cli.validation.ValidationResult; + +public class CustomValidation { + private static List> VALIDATION_RULES = Arrays.asList( + // custom validation rules can be enabled here + new RuleAbstractClassPrefix()); + + private final Resource resource; + private final List elements; + private final Map, List>> rules; + + public CustomValidation(Resource resource, List elementsToValidate) { + if (resource == null) + throw new IllegalArgumentException("Resource must not be null"); + this.resource = resource; + this.elements = elementsToValidate; + rules = initRules(); + } + + private Map, List>> initRules() { + final Map, List>> retval = new HashMap<>( + VALIDATION_RULES.size()); + VALIDATION_RULES.forEach(rule -> MapUtils.addToListMap(retval, rule.applicableTo, rule)); + return Collections.unmodifiableMap(retval); + } + + public void validate(ValidationResult result) { + if (elements == null || elements.isEmpty()) { + resource.getContents().stream() // + .filter(Package.class::isInstance).map(Package.class::cast) // + .forEach(pack -> doValidate(pack, result)); + } else { + elements.stream().map(Element::getNearestPackage).distinct() // + .forEach(pack -> doValidate(pack, result)); + } + } + + public void doValidate(Package pack, ValidationResult result) { + for (TreeIterator iter = pack.eAllContents(); iter.hasNext();) { + final EObject obj = iter.next(); + + for (Entry, List>> classWithRule : rules.entrySet()) { + if (classWithRule.getKey().isInstance(obj)) { + classWithRule.getValue().forEach(rule -> rule.validate((Element) obj, result)); + } + } + } + } +} diff --git a/CLI/com.yakindu.bridges.ea.example.cli.validation/src/com/yakindu/bridges/ea/example/cli/validation/custom/RuleAbstractClassPrefix.java b/CLI/com.yakindu.bridges.ea.example.cli.validation/src/com/yakindu/bridges/ea/example/cli/validation/custom/RuleAbstractClassPrefix.java new file mode 100644 index 0000000..bf60aa6 --- /dev/null +++ b/CLI/com.yakindu.bridges.ea.example.cli.validation/src/com/yakindu/bridges/ea/example/cli/validation/custom/RuleAbstractClassPrefix.java @@ -0,0 +1,27 @@ +package com.yakindu.bridges.ea.example.cli.validation.custom; + +import java.util.function.Consumer; + +import org.eclipse.uml2.uml.Class; + +public class RuleAbstractClassPrefix extends AbstractValidationRule { + + private static final String AbstractPrefix = "Abstract"; + + public RuleAbstractClassPrefix() { + super(Class.class); + } + + @Override + public void validate(Class obj, Consumer addError, Consumer addWarning) { + if (isAbstractClassWithoutPrefix(obj)) { + addWarning.accept( + String.format("Abstract class '%s' should start with '%s'.", obj.getName(), AbstractPrefix)); + } + } + + private boolean isAbstractClassWithoutPrefix(Class element) { + return element instanceof Class && element.isAbstract() && !element.getName().startsWith(AbstractPrefix); + } + +} diff --git a/CLI/com.yakindu.bridges.ea.example.cli.validation/src/com/yakindu/bridges/ea/example/cli/validation/report/ValidationIssueJsonContainer.java b/CLI/com.yakindu.bridges.ea.example.cli.validation/src/com/yakindu/bridges/ea/example/cli/validation/report/ValidationIssueJsonContainer.java new file mode 100644 index 0000000..cce9dbc --- /dev/null +++ b/CLI/com.yakindu.bridges.ea.example.cli.validation/src/com/yakindu/bridges/ea/example/cli/validation/report/ValidationIssueJsonContainer.java @@ -0,0 +1,34 @@ +package com.yakindu.bridges.ea.example.cli.validation.report; + +public class ValidationIssueJsonContainer { + + private final String severity; + private final String type; + private final String id; + private final String msg; + + public ValidationIssueJsonContainer(String severity, String type, String id, String msg) { + super(); + this.severity = severity; + this.type = type; + this.id = id; + this.msg = msg; + } + + public String getSeverity() { + return severity; + } + + public String getType() { + return type; + } + + public String getId() { + return id; + } + + public String getMsg() { + return msg; + } + +} diff --git a/CLI/com.yakindu.bridges.ea.example.cli.validation/src/com/yakindu/bridges/ea/example/cli/validation/report/ValidationReport.java b/CLI/com.yakindu.bridges.ea.example.cli.validation/src/com/yakindu/bridges/ea/example/cli/validation/report/ValidationReport.java new file mode 100644 index 0000000..e9f5876 --- /dev/null +++ b/CLI/com.yakindu.bridges.ea.example.cli.validation/src/com/yakindu/bridges/ea/example/cli/validation/report/ValidationReport.java @@ -0,0 +1,115 @@ +package com.yakindu.bridges.ea.example.cli.validation.report; + +import java.util.AbstractMap.SimpleImmutableEntry; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.uml2.uml.Class; +import org.eclipse.uml2.uml.Model; +import org.eclipse.uml2.uml.Package; +import org.eclipse.uml2.uml.resource.UMLResource; + +import com.google.gson.Gson; +import com.yakindu.bridges.ea.core.EAResource; +import com.yakindu.bridges.ea.core.utils.EAResourceUtils; +import com.yakindu.bridges.ea.example.cli.validation.ValidationResult; + +public class ValidationReport { + + private final ValidationResult result; + private final StringBuilder output; + + public ValidationReport(ValidationResult result) { + this.result = result; + this.output = new StringBuilder(); + } + + public String create() { + if (output.length() == 0) { + List customIssues = createValidationIssuesForElement(result.getCustomErrors(), + result.getCustomWarnings()); + + List loadIssues = createValidationIssuesForElement(result.getLoadErrors(), + result.getLoadWarnings()); + + List umlErrors = createValidationIssuesForElement(result.getUmlErrors(), + result.getUmlWarnings()); + + List resourceIssues = appendResourceIssues(); + + ValidationResultsJsonContainer serializableResult = new ValidationResultsJsonContainer(resourceIssues, + loadIssues, umlErrors, customIssues); + + // create Json serializer + Gson jsonHandler = new Gson(); + output.append(jsonHandler.toJson(serializableResult)); + + } + return output.toString(); + } + + private List createValidationIssuesForElement(Map> errors, + Map> warnings) { + List retVal = new ArrayList<>(); + + for (Entry> elementEntry : errors.entrySet()) { + final Entry ids = getIds(elementEntry.getKey()); + + for (String error : elementEntry.getValue()) { + String type = ids.getKey() != null ? ids.getKey() : ""; + String id = ids.getValue() != null ? ids.getValue() : ""; + retVal.add(new ValidationIssueJsonContainer("E", type, id, error)); + } + } + + for (Entry> elementEntry : warnings.entrySet()) { + final Entry ids = getIds(elementEntry.getKey()); + for (String error : elementEntry.getValue()) { + String type = ids.getKey() != null ? ids.getKey() : ""; + String id = ids.getValue() != null ? ids.getValue() : ""; + retVal.add(new ValidationIssueJsonContainer("W", type, id, error)); + } + } + + return retVal; + } + + private List appendResourceIssues() { + List retVal = new ArrayList<>(); + + for (String error : result.getResourceErrors()) { + retVal.add(new ValidationIssueJsonContainer("E", "", "", error)); + } + for (String warning : result.getResourceWarnings()) { + retVal.add(new ValidationIssueJsonContainer("W", "", "", warning)); + } + + return retVal; + } + + private Entry getIds(EObject element) { + if (element == null) + return null; + if (element.eResource() instanceof EAResource) { + final String objectType = EAResourceUtils.getObjectTypeForElement(element); + if (objectType != null) { + final Integer id = EAResourceUtils.getIdForElement(element); + final String idStr = id == null ? EAResourceUtils.getGuidForElement(element) : String.valueOf(id); + if (idStr != null) { + return new SimpleImmutableEntry<>(objectType, idStr); + } + } + return getIds(element.eContainer()); + } + if (element instanceof UMLResource || element instanceof Model || element instanceof Class + || element instanceof Package) { + final String clazz = element.eClass().getName(); + final String fragment = element.eResource().getURIFragment(element); + return new SimpleImmutableEntry<>(clazz, fragment); + } + throw new IllegalArgumentException("Unexpected element: " + element); + } +} diff --git a/CLI/com.yakindu.bridges.ea.example.cli.validation/src/com/yakindu/bridges/ea/example/cli/validation/report/ValidationResultsJsonContainer.java b/CLI/com.yakindu.bridges.ea.example.cli.validation/src/com/yakindu/bridges/ea/example/cli/validation/report/ValidationResultsJsonContainer.java new file mode 100644 index 0000000..985c7d1 --- /dev/null +++ b/CLI/com.yakindu.bridges.ea.example.cli.validation/src/com/yakindu/bridges/ea/example/cli/validation/report/ValidationResultsJsonContainer.java @@ -0,0 +1,42 @@ +package com.yakindu.bridges.ea.example.cli.validation.report; + +import java.util.List; + +public class ValidationResultsJsonContainer { + + private final List resourceIssues; + private final List loadIssues; + private final List umlIssues; + private final List customIssues; + + public ValidationResultsJsonContainer(List resourceIssues, + List loadIssues, List umlIssues, + List customIssues) { + super(); + this.resourceIssues = resourceIssues; + this.loadIssues = loadIssues; + this.umlIssues = umlIssues; + this.customIssues = customIssues; + } + + public List getResourceIssues() { + return resourceIssues; + } + + public List getLoadIssues() { + return loadIssues; + } + + public List getUmlIssues() { + return umlIssues; + } + + public List getCustomIssues() { + return customIssues; + } + + public int count() { + return resourceIssues.size() + loadIssues.size() + umlIssues.size() + customIssues.size(); + } + +} \ No newline at end of file diff --git a/CLI/com.yakindu.bridges.ea.example.cli.validation/src/com/yakindu/bridges/ea/example/cli/validation/uml/UMLDiagnostician.java b/CLI/com.yakindu.bridges.ea.example.cli.validation/src/com/yakindu/bridges/ea/example/cli/validation/uml/UMLDiagnostician.java new file mode 100644 index 0000000..5ec2996 --- /dev/null +++ b/CLI/com.yakindu.bridges.ea.example.cli.validation/src/com/yakindu/bridges/ea/example/cli/validation/uml/UMLDiagnostician.java @@ -0,0 +1,86 @@ +package com.yakindu.bridges.ea.example.cli.validation.uml; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.eclipse.emf.common.util.BasicDiagnostic; +import org.eclipse.emf.common.util.Diagnostic; +import org.eclipse.emf.common.util.DiagnosticChain; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.plugin.EcorePlugin; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.util.Diagnostician; +import org.eclipse.uml2.uml.Element; + +/** + * Copy from inner class of UMLActionBarContributor. + */ +public class UMLDiagnostician extends Diagnostician { + + private static final String PLUGIN_ID = "com.yakindu.bridges.ea.example.validation"; + + public final static UMLDiagnostician INSTANCE = new UMLDiagnostician(); + + public Diagnostic validate(Resource resource) { + final List diagnostics = new ArrayList<>(); + + final Map defaultContext = createDefaultContext(); + for (EObject obj : resource.getContents()) { + if (obj instanceof Element) { + final BasicDiagnostic diagnostic = createDefaultDiagnostic(obj); + validate(obj, diagnostic, defaultContext); + if (diagnostic.getSeverity() >= Diagnostic.WARNING) { + diagnostics.add(diagnostic); + } + } + } + + if (diagnostics.isEmpty()) + return Diagnostic.OK_INSTANCE; + if (diagnostics.size() == 1) + return diagnostics.get(0); + return new BasicDiagnostic(PLUGIN_ID, 0, diagnostics, EcorePlugin.INSTANCE + .getString("_UI_DiagnosticRoot_diagnostic", new Object[] { " " + resource.getURI() }), + new Object[] { resource }); + } + + protected boolean doValidateStereotypeApplications(EObject eObject, DiagnosticChain diagnostics, + Map context) { + List stereotypeApplications = eObject instanceof Element + ? ((Element) eObject).getStereotypeApplications() + : Collections.emptyList(); + + if (!stereotypeApplications.isEmpty()) { + Iterator i = stereotypeApplications.iterator(); + boolean result = validate(i.next(), diagnostics, context); + + while (i.hasNext() && (result || diagnostics != null)) { + result &= validate(i.next(), diagnostics, context); + } + + return result; + } else { + return true; + } + } + + @Override + protected boolean doValidateContents(EObject eObject, DiagnosticChain diagnostics, Map context) { + boolean result = doValidateStereotypeApplications(eObject, diagnostics, context); + + if (result || diagnostics != null) { + result &= super.doValidateContents(eObject, diagnostics, context); + } + + return result; + } + + @Override + public boolean validate(EClass eClass, EObject eObject, DiagnosticChain diagnostics, Map context) { + return super.validate(eClass, eObject, diagnostics, context); + } +} \ No newline at end of file diff --git a/CLI/com.yakindu.bridges.ea.example.cli.validation/src/com/yakindu/bridges/ea/example/cli/validation/uml/UMLValidation.java b/CLI/com.yakindu.bridges.ea.example.cli.validation/src/com/yakindu/bridges/ea/example/cli/validation/uml/UMLValidation.java new file mode 100644 index 0000000..a439929 --- /dev/null +++ b/CLI/com.yakindu.bridges.ea.example.cli.validation/src/com/yakindu/bridges/ea/example/cli/validation/uml/UMLValidation.java @@ -0,0 +1,61 @@ +package com.yakindu.bridges.ea.example.cli.validation.uml; + +import org.eclipse.emf.common.util.Diagnostic; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.resource.Resource; + +import com.yakindu.bridges.ea.example.cli.validation.ValidationResult; + +public class UMLValidation { + + private UMLValidation() { + throw new IllegalStateException("Static Class"); + } + + public static void validate(Resource resource, ValidationResult result) { + final Diagnostic diagnostics = UMLDiagnostician.INSTANCE.validate(resource); + + if (diagnostics != null && diagnostics.getSeverity() >= Diagnostic.WARNING) { + collectErrorsAndWarnings(diagnostics, result); + } + } + + private static void collectErrorsAndWarnings(Diagnostic diagnostic, ValidationResult result) { + if (diagnostic.getSeverity() >= Diagnostic.WARNING) { + + // check current message + final EObject object = getModelElement(diagnostic.getData()); + if (isRelevantIssue(object, diagnostic.getMessage())) { + if (diagnostic.getSeverity() == Diagnostic.WARNING) { + result.addUmlWarning(object, diagnostic.getMessage()); + } else { + result.addUmlError(object, diagnostic.getMessage()); + } + } + + // recursive call + for (final Diagnostic child : diagnostic.getChildren()) { + collectErrorsAndWarnings(child, result); + } + } // else: only ok / info + } + + private static EObject getModelElement(Object data) { + if (data == null || data instanceof EObject) + return (EObject) data; + if (data instanceof Iterable) { + for (Object obj : (Iterable) data) { + final EObject element = getModelElement(obj); + if (element != null) + return element; + } + } + return null; + } + + private static boolean isRelevantIssue(final EObject object, final String message) { + if (message == null || message.isEmpty()) + return false; // no message - nothing reasonable to report + return true; // good location for a break point + } +} diff --git a/CLI/com.yakindu.bridges.ea.example.cli/.classpath b/CLI/com.yakindu.bridges.ea.example.cli/.classpath new file mode 100644 index 0000000..e801ebf --- /dev/null +++ b/CLI/com.yakindu.bridges.ea.example.cli/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/CLI/com.yakindu.bridges.ea.example.cli/.gitignore b/CLI/com.yakindu.bridges.ea.example.cli/.gitignore new file mode 100644 index 0000000..3523549 --- /dev/null +++ b/CLI/com.yakindu.bridges.ea.example.cli/.gitignore @@ -0,0 +1,3 @@ +/bin/ +/target/ +/.polyglot.* diff --git a/CLI/com.yakindu.bridges.ea.example.cli/.project b/CLI/com.yakindu.bridges.ea.example.cli/.project new file mode 100644 index 0000000..f98edd0 --- /dev/null +++ b/CLI/com.yakindu.bridges.ea.example.cli/.project @@ -0,0 +1,28 @@ + + + com.yakindu.bridges.ea.example.cli + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/CLI/com.yakindu.bridges.ea.example.cli/META-INF/MANIFEST.MF b/CLI/com.yakindu.bridges.ea.example.cli/META-INF/MANIFEST.MF new file mode 100644 index 0000000..235a22c --- /dev/null +++ b/CLI/com.yakindu.bridges.ea.example.cli/META-INF/MANIFEST.MF @@ -0,0 +1,19 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Example validation CLI +Bundle-SymbolicName: com.yakindu.bridges.ea.example.cli;singleton:=true +Bundle-Version: 1.0.0.qualifier +Bundle-Vendor: itemis AG +Automatic-Module-Name: com.yakindu.bridges.ea.example.cli +Bundle-RequiredExecutionEnvironment: JavaSE-11 +Require-Bundle: org.eclipse.equinox.app, + org.eclipse.emf.ecore, + org.eclipse.uml2.uml, + org.eclipse.xtext, + com.yakindu.bridges.ea.core, + com.yakindu.bridges.ea.uml, + com.google.inject, + com.google.guava, + com.yakindu.bridges.ea.example.cli.validation +Export-Package: com.yakindu.bridges.ea.example.cli;uses:="org.eclipse.equinox.app,org.eclipse.emf.ecore.resource", + com.yakindu.bridges.ea.example.cli.validation;uses:="org.eclipse.emf.ecore.resource,com.yakindu.bridges.ea.example.cli" diff --git a/CLI/com.yakindu.bridges.ea.example.cli/build.properties b/CLI/com.yakindu.bridges.ea.example.cli/build.properties new file mode 100644 index 0000000..e9863e2 --- /dev/null +++ b/CLI/com.yakindu.bridges.ea.example.cli/build.properties @@ -0,0 +1,5 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + plugin.xml diff --git a/CLI/com.yakindu.bridges.ea.example.cli/plugin.xml b/CLI/com.yakindu.bridges.ea.example.cli/plugin.xml new file mode 100644 index 0000000..cda15c3 --- /dev/null +++ b/CLI/com.yakindu.bridges.ea.example.cli/plugin.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + diff --git a/CLI/com.yakindu.bridges.ea.example.cli/src/com/yakindu/bridges/ea/example/cli/AbstractResourceProcessor.java b/CLI/com.yakindu.bridges.ea.example.cli/src/com/yakindu/bridges/ea/example/cli/AbstractResourceProcessor.java new file mode 100644 index 0000000..a313ab7 --- /dev/null +++ b/CLI/com.yakindu.bridges.ea.example.cli/src/com/yakindu/bridges/ea/example/cli/AbstractResourceProcessor.java @@ -0,0 +1,138 @@ +package com.yakindu.bridges.ea.example.cli; + +import java.io.File; + +import java.io.FileNotFoundException; +import java.util.List; +import java.util.Map; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; +import org.eclipse.uml2.uml.Element; +import org.eclipse.uml2.uml.NamedElement; + +import com.yakindu.bridges.ea.core.EAResource; +import com.yakindu.bridges.ea.example.cli.load.UMLElementCollector; + +public abstract class AbstractResourceProcessor { + + public void run(String[] args) { + Resource resource = null; + try { + resource = report("Loading '" + args[0] + "'", () -> { + try { + return load(args[0]); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + }); + run(resource, skip(args, 1)); + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (resource != null) { + try { + resource.unload(); + } catch (Exception e) { + // silent fail + } + } + } + } + + protected abstract String run(Resource resource, String[] args) throws Exception; + + protected void report(String task, Runnable runnable) { + report(task, () -> { + runnable.run(); + return null; + }); + } + + protected T report(String task, Supplier runnable) { + System.out.println(">> " + task + " ..."); + final long start = System.currentTimeMillis(); + try { + final T result = runnable.get(); + final long duration = System.currentTimeMillis() - start; + System.out.println(">> " + task + " DONE. [ " + getHumanReadableDuration(duration) + " ]"); + return result; + } catch (Exception e) { + final long duration = System.currentTimeMillis() - start; + System.out.println(">> " + task + " FAILED. [ " + getHumanReadableDuration(duration) + " ]"); + throw e; + } + } + + private static String getHumanReadableDuration(long durationInMiliseconds) { + if (durationInMiliseconds < 2000) + return durationInMiliseconds + "ms"; + if (durationInMiliseconds < 100 * 1000) + return (durationInMiliseconds / 1000) + "sec"; + return (durationInMiliseconds / 1000 / 60) + "min"; + } + + private Resource load(String filePath) throws Exception { + if (filePath == null || filePath.isEmpty()) + throw new IllegalArgumentException("File argument missing"); + final File file = new File(filePath); + if (!file.exists()) + throw new FileNotFoundException("File not found: " + filePath); + + final URI uri = URI.createFileURI(file.getAbsolutePath()); + final ResourceSetImpl set = new ResourceSetImpl(); + + if (EAResource.FILE_EXTENSIONS.stream().anyMatch(ext -> filePath.toLowerCase().endsWith(ext))) { + final Map loadOptions = set.getLoadOptions(); + loadOptions.put(EAResource.OPTION_READONLY, true); + loadOptions.put(EAResource.OPTION_REPORT_TO_ERROR_LOG, false); + loadOptions.put(EAResource.OPTION_REPORT_AS_RESOURCE_MARKERS, false); + } + return set.getResource(uri, true); + } + + protected List loadElements(Resource resource, String nameOrGuid, boolean verbose) throws Exception { + final List elements = new UMLElementCollector().loadElements(resource, nameOrGuid); + + if (verbose) { + if (elements.isEmpty()) { + System.out.println("No UML elements loaded"); + } else { + System.out.println(String.format("%d element%s found: %s", // + elements.size(), elements.size() == 1 ? "" : "s", + elements.stream().filter(element -> element instanceof NamedElement) + .map(e -> ((NamedElement) e).getName()).filter(name -> name != null).sorted() + .collect(Collectors.joining(", ")))); + } + } + return elements; + } + + protected String getNameOrGuidFromArguments(String[] args) { + for (String arg : args) { + if (!ExampleCLI.VERBOSE_OUTPUT.equals(arg)) { + return arg; + } + } + return ""; + } + + protected boolean getVerboseFlagFromArguments(String[] args) { + for (String arg : args) { + if (ExampleCLI.VERBOSE_OUTPUT.equals(arg)) { + return true; + } + } + return false; + } + + protected static String[] skip(String[] args, int index) { + final String[] newArgs = new String[args.length - 1]; + System.arraycopy(args, index, newArgs, 0, args.length - 1); + return newArgs; + } +} diff --git a/CLI/com.yakindu.bridges.ea.example.cli/src/com/yakindu/bridges/ea/example/cli/ExampleCLI.java b/CLI/com.yakindu.bridges.ea.example.cli/src/com/yakindu/bridges/ea/example/cli/ExampleCLI.java new file mode 100644 index 0000000..2915d0d --- /dev/null +++ b/CLI/com.yakindu.bridges.ea.example.cli/src/com/yakindu/bridges/ea/example/cli/ExampleCLI.java @@ -0,0 +1,68 @@ +package com.yakindu.bridges.ea.example.cli; + +import org.eclipse.equinox.app.IApplication; +import org.eclipse.equinox.app.IApplicationContext; + +import com.yakindu.bridges.ea.example.cli.validation.ModelValidator; + +public class ExampleCLI implements IApplication { + + public static final Integer EXIT_ERROR = 1; + + public static final String APP_VALIDATE = "validate"; + + public static final String VERBOSE_OUTPUT = "-v"; + + public static final String HELP = "YAKINDU EA-Bridge Example Command Line Interface\n" // + + "Possible options:\n" // + + " " + APP_VALIDATE + " [] [-v]\n" // + + VERBOSE_OUTPUT + " enables 'verbose' output" // + + ; + + @Override + public Object start(IApplicationContext context) throws Exception { + // set up the exit data property in the case of errors + // c.f. javadoc of IApplicationContext + System.setProperty(IApplicationContext.EXIT_DATA_PROPERTY, ""); + + final String[] args = (String[]) context.getArguments().get(IApplicationContext.APPLICATION_ARGS); + if (args != null && args.length >= 3) { + final String[] appArgs = AbstractResourceProcessor.skip(args, 1); + + final AbstractResourceProcessor processor = getProcessor(args[0]); + if (processor != null) { + try { + + processor.run(appArgs); + System.out.println("Validation successfully finished."); + return IApplication.EXIT_OK; + + } catch (Exception e) { + + // unexpected error - print stack trace! + System.out.println("Validation failed unexpectedly:"); + e.printStackTrace(); + } + return EXIT_ERROR; + } + } + printHelp(); + return IApplication.EXIT_OK; + } + + private AbstractResourceProcessor getProcessor(String arg) { + if (APP_VALIDATE.equalsIgnoreCase(arg)) + return new ModelValidator(); + return null; + } + + private void printHelp() { + System.out.println(HELP); + } + + @Override + public void stop() { + // nothing to do + } +} diff --git a/CLI/com.yakindu.bridges.ea.example.cli/src/com/yakindu/bridges/ea/example/cli/load/UMLElementCollector.java b/CLI/com.yakindu.bridges.ea.example.cli/src/com/yakindu/bridges/ea/example/cli/load/UMLElementCollector.java new file mode 100644 index 0000000..83d09dd --- /dev/null +++ b/CLI/com.yakindu.bridges.ea.example.cli/src/com/yakindu/bridges/ea/example/cli/load/UMLElementCollector.java @@ -0,0 +1,129 @@ +package com.yakindu.bridges.ea.example.cli.load; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.eclipse.emf.common.util.TreeIterator; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.uml2.uml.Comment; +import org.eclipse.uml2.uml.Element; +import org.eclipse.uml2.uml.NamedElement; +import org.eclipse.uml2.uml.Package; +import org.eclipse.uml2.uml.util.UMLUtil; + +import com.yakindu.bridges.ea.core.EAResource; +import com.yakindu.bridges.ea.core.utils.EAResourceUtils; + +public class UMLElementCollector { + + public List loadElements(Resource resource, String nameOrGuid) throws Exception { + if (resource == null) + throw new Exception("Resource is empty"); + + final List elements = new ArrayList<>(); + if (nameOrGuid != null && !nameOrGuid.isEmpty()) { + String[] namesOrGuids = nameOrGuid.split(","); + if (EAResource.PATTERN_GUID.matcher(namesOrGuids[0]).matches()) { + if (!(resource instanceof EAResource)) + throw new Exception("GUIDs are only valid for eap-files"); + elements.addAll(getElementsByGuids(resource, Arrays.asList(namesOrGuids))); + } else { + elements.addAll(getElementsByNames(resource, Arrays.asList(namesOrGuids))); + } + } else { + for (EObject obj : resource.getContents()) { + if (obj instanceof Package) + elements.addAll(collectElements((Package) obj)); + } + } + + return elements; + } + + private Set getElementsByNames(Resource resource, List names) throws Exception { + final Map objectsByName = new HashMap<>(); + final TreeIterator contents = resource.getAllContents(); + while (contents.hasNext()) { + final EObject obj = contents.next(); + if ((obj instanceof NamedElement || obj instanceof Package) && !(obj instanceof Comment)) { + final String objName = ((NamedElement) obj).getName(); + if (names.contains(objName)) { + if (objectsByName.containsKey(objName)) { + throw new Exception( + String.format("Name '%s' is not unique; it resolves at least to:%n- %s%n- %s", objName, + getText(obj), getText(objectsByName.get(objName)))); + } + objectsByName.put(objName, (NamedElement) obj); + } else { + // check for fully qualified names case-insensitive (issue #40) + final String fqn = UMLUtil.getQualifiedText(obj); + if (names.stream().anyMatch(fqn::equalsIgnoreCase)) { + // fqn should be unique, no need to check for collisions + objectsByName.put(fqn, (NamedElement) obj); + } + } + } + } + if (names.size() > objectsByName.size()) { + final List unresolvableNames = new ArrayList<>(); + for (String unresolvableName : names) { + if (!objectsByName.containsKey(unresolvableName)) + unresolvableNames.add(unresolvableName); + } + throw new Exception("Could not find names " + unresolvableNames + " in the model"); + } + final Set foundElements = new HashSet<>(); + for (NamedElement obj : objectsByName.values()) { + if (obj instanceof Element) { + foundElements.add(obj); + } else if (obj instanceof Package) { + foundElements.addAll(collectElements((Package) obj)); + } else + throw new Exception("Gathered objects contains invalid model element"); + } + return foundElements; + } + + private Object getText(EObject obj) { + if (obj == null) + return ""; + final String clazz = obj.eClass().getName(); + final String fqn = UMLUtil.getQualifiedText(obj); + final String guid = EAResourceUtils.getGuidForElement(obj); + return String.format("<%s> %s%s", clazz, fqn, guid == null ? "" : " GUID = " + guid); + } + + private Set collectElements(Package pack) { + Set collectedElements = new HashSet<>(); + TreeIterator contents = ((EObject) pack).eAllContents(); + while (contents.hasNext()) { + EObject eObject = contents.next(); + if (eObject instanceof Element) { + collectedElements.add((Element) eObject); + } + } + return collectedElements; + } + + private Set getElementsByGuids(Resource resource, List guids) throws Exception { + Set elements = new HashSet<>(); + for (String guid : guids) { + EObject obj = EAResourceUtils.getElementForGuid(resource, guid); + if (obj instanceof Package) { + elements.addAll(collectElements((Package) obj)); + } else if (obj instanceof Element) { + elements.add((Element) obj); + } else { + throw new Exception("GUID " + guid + " cannot be resolved to a package or element but: " + obj); + } + } + return elements; + } + +} diff --git a/CLI/com.yakindu.bridges.ea.example.cli/src/com/yakindu/bridges/ea/example/cli/validation/ModelValidator.java b/CLI/com.yakindu.bridges.ea.example.cli/src/com/yakindu/bridges/ea/example/cli/validation/ModelValidator.java new file mode 100644 index 0000000..0bf8955 --- /dev/null +++ b/CLI/com.yakindu.bridges.ea.example.cli/src/com/yakindu/bridges/ea/example/cli/validation/ModelValidator.java @@ -0,0 +1,44 @@ +package com.yakindu.bridges.ea.example.cli.validation; + +import java.util.List; + +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.uml2.uml.Element; + +import com.yakindu.bridges.ea.example.cli.AbstractResourceProcessor; + +public class ModelValidator extends AbstractResourceProcessor { + + @Override + protected String run(Resource resource, String[] args) throws Exception { + final String reportFile = args[0]; + final String nameOrGuid = getNameOrGuidFromArguments(skip(args, 1)); + final boolean verbose = getVerboseFlagFromArguments(skip(args, 1)); + + final List loadedElements = report("Collecting UML Elements", () -> { + try { + return loadElements(resource, nameOrGuid, verbose); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + }); + + final ModelValidation validation = new ModelValidation(resource, loadedElements, reportFile); + + final int count = report("Validating", () -> { + final List issues = validation.validate(); + if (verbose) + issues.forEach(System.out::println); + return issues.size(); + }); + if (count > 0) { + report(String.format("Writing report (%d issue%s)", count, count == 1 ? "" : "s"), + validation::createReport); + + return String.format("%d issue%s found.", count, count == 1 ? "" : "s"); + } else { + return "No issues found."; + } + } +} diff --git a/CLI/pom.xml b/CLI/pom.xml new file mode 100644 index 0000000..19562b9 --- /dev/null +++ b/CLI/pom.xml @@ -0,0 +1,137 @@ + + + 4.0.0 + + YAKINDU EA-Bridge Example CLI + + com.yakindu.bridges.ea.example.cli + root + 1.0.0-SNAPSHOT + + pom + + + 2.6.0 + 3.1.0 + UTF-8 + 11 + 11 + yyyyMMdd-HHmm + + + + com.yakindu.bridges.ea.example.cli + com.yakindu.bridges.ea.example.cli.target + com.yakindu.bridges.ea.example.cli.validation + com.yakindu.bridges.ea.example.cli.feature + com.yakindu.bridges.ea.example.cli.product + com.yakindu.bridges.ea.example.cli.test + + + + + + + org.apache.maven.plugins + maven-clean-plugin + ${maven-clean-plugin.version} + + + + org.eclipse.tycho + tycho-surefire-plugin + ${tycho.version} + + ${test.vmargs} + + + + + org.eclipse.tycho + tycho-maven-plugin + ${tycho.version} + + + + org.eclipse.tycho + target-platform-configuration + ${tycho.version} + + + + org.eclipse.tycho + tycho-compiler-plugin + ${tycho.version} + + + + org.eclipse.tycho + tycho-source-plugin + ${tycho.version} + + + + org.eclipse.tycho.extras + tycho-source-feature-plugin + ${tycho.version} + + + + org.eclipse.tycho + tycho-p2-director-plugin + ${tycho.version} + + + + + + + org.eclipse.tycho + target-platform-configuration + + false + + + com.yakindu.bridges.ea.example.cli + com.yakindu.bridges.ea.example.cli.target + 1.0.0-SNAPSHOT + + + + + linux + gtk + x86_64 + + + win32 + win32 + x86_64 + + + macosx + cocoa + x86_64 + + + + + + eclipse-feature + com.yakindu.licmgmt.feature + 0.0.0 + + + + + + + + org.eclipse.tycho + tycho-maven-plugin + true + + + + + \ No newline at end of file diff --git a/EA_demo.gif b/EA_demo.gif new file mode 100644 index 0000000..37f6c8a Binary files /dev/null and b/EA_demo.gif differ diff --git a/ExampleModels/Library.eap b/ExampleModels/Library.eap new file mode 100644 index 0000000..26348c6 Binary files /dev/null and b/ExampleModels/Library.eap differ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..49003cc --- /dev/null +++ b/LICENSE @@ -0,0 +1,79 @@ +THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE (“AGREEMENT”). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. +1. DEFINITIONS + +“Contribution” means: + + a) in the case of the initial Contributor, the initial content Distributed under this Agreement, and + b) in the case of each subsequent Contributor: + i) changes to the Program, and + ii) additions to the Program; + where such changes and/or additions to the Program originate from and are Distributed by that particular Contributor. A Contribution “originates” from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include changes or additions to the Program that are not Modified Works. + +“Contributor” means any person or entity that Distributes the Program. + +“Licensed Patents” mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. + +“Program” means the Contributions Distributed in accordance with this Agreement. + +“Recipient” means anyone who receives the Program under this Agreement or any Secondary License (as applicable), including Contributors. + +“Derivative Works” shall mean any work, whether in Source Code or other form, that is based on (or derived from) the Program and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. + +“Modified Works” shall mean any work in Source Code or other form that results from an addition to, deletion from, or modification of the contents of the Program, including, for purposes of clarity any new file in Source Code form that contains any contents of the Program. Modified Works shall not include works that contain only declarations, interfaces, types, classes, structures, or files of the Program solely in each case in order to link to, bind by name, or subclass the Program or Modified Works thereof. + +“Distribute” means the acts of a) distributing or b) making available in any manner that enables the transfer of a copy. + +“Source Code” means the form of a Program preferred for making modifications, including but not limited to software source code, documentation source, and configuration files. + +“Secondary License” means either the GNU General Public License, Version 2.0, or any later versions of that license, including any exceptions or additional permissions as identified by the initial Contributor. +2. GRANT OF RIGHTS + + a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, Distribute and sublicense the Contribution of such Contributor, if any, and such Derivative Works. + b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in Source Code or other form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. + c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to Distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program. + d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. + e) Notwithstanding the terms of any Secondary License, no Contributor makes additional grants to any Recipient (other than those set forth in this Agreement) as a result of such Recipient's receipt of the Program under the terms of a Secondary License (if permitted under the terms of Section 3). + +3. REQUIREMENTS + +3.1 If a Contributor Distributes the Program in any form, then: + + a) the Program must also be made available as Source Code, in accordance with section 3.2, and the Contributor must accompany the Program with a statement that the Source Code for the Program is available under this Agreement, and informs Recipients how to obtain it in a reasonable manner on or through a medium customarily used for software exchange; and + b) the Contributor may Distribute the Program under a license different than this Agreement, provided that such license: + i) effectively disclaims on behalf of all other Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; + ii) effectively excludes on behalf of all other Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; + iii) does not attempt to limit or alter the recipients' rights in the Source Code under section 3.2; and + iv) requires any subsequent distribution of the Program by any party to be under a license that satisfies the requirements of this section 3. + +3.2 When the Program is Distributed as Source Code: + + a) it must be made available under this Agreement, or if the Program (i) is combined with other material in a separate file or files made available under a Secondary License, and (ii) the initial Contributor attached to the Source Code the notice described in Exhibit A of this Agreement, then the Program may be made available under the terms of such Secondary Licenses, and + b) a copy of this Agreement must be included with each copy of the Program. + +3.3 Contributors may not remove or alter any copyright, patent, trademark, attribution notices, disclaimers of warranty, or limitations of liability (‘notices’) contained within the Program from any copy of the Program which they Distribute, provided that Contributors may add their own appropriate notices. +4. COMMERCIAL DISTRIBUTION + +Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor (“Commercial Contributor”) hereby agrees to defend and indemnify every other Contributor (“Indemnified Contributor”) against any losses, damages and costs (collectively “Losses”) arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. + +For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. +5. NO WARRANTY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. +6. DISCLAIMER OF LIABILITY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. +7. GENERAL + +If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. + +If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. + +All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. + +Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be Distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to Distribute the Program (including its Contributions) under the new version. + +Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. Nothing in this Agreement is intended to be enforceable by any entity that is not a Contributor or Recipient. No third-party beneficiary rights are created under this Agreement. + +Exhibit A – Form of Secondary Licenses Notice + +“This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), version(s), and exceptions or additional permissions here}.” \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..b997f7a --- /dev/null +++ b/README.md @@ -0,0 +1,65 @@ +# Enterprise Architect - YAKINDU EA-Bridge Integration Example + +The example contained in this repository demonstrate the integration of the Enterprise Architect (EA) modeling tool with a command-line Java application for **model validation**. A simple EA Add-in calls the Java application which loads the `.eap/.eapx` file, performs validations on that model and returns the result. Then the EA Add-in loads and displays the validation issues in a custom UI view including the possibility to navigate to the corresponding elements in the EA project browser or in existing diagrams. +The following diagram illustrates how this example works: + +![structure](./eabridge_example_uscase.png) + +This example may also serve as a template for further use cases such as custom model validation, code generation, or reporting. + +**Advantages** of this approach are: + +* **Performance**: the Java application loads and processes large EA models *much faster* (up to 50x) than using EA's API. +* **Standard compliance**: the model is loaded as a *standard UML model* and can be processed with *powerful languages* such as Java or Xtend. +* **Seamless integration**: the EA Add-in *integrates* powerful model processing into the UI of Enterprise Architect. + +*This example is tested with Enterprise Architect 15.* + + +## How to run this example + +This repository consists of two codebases: + +* The command-line interface (CLI) is a headless Java application containing the [YAKINDU EA-Bridge](https://www.itemis.com/en/yakindu/ea-bridge/) for loading UML models from eap-files; it further performs UML syntax validation and runs an exemplary custom validation rule. The result of this validation is stored in a json-file for further use with other tools such as the EA Add-in below. + +* The EA Add-in allows the user to validate the model using a UI integrated in Enterprise Architect; it further lists the validation results in a custom view inside EA without the need to use the command line. A *double click* on a validation result in EA selects the corresponding element in the Project Browser and opens the diagram containing that element (if such a diagram exists). + +Please follow these steps to try out the pre-built example on your local machine: +1. Download the [zip-package]() and extract it to some location on your hard-drive. +2. Download the [Add-in installer]() and install it (EA must not be running). +3. Start EA, go to *Specialize* → *YAKINDU EA-Bridge Integration* → *Configure CLI Path* → and set the path to the folder into which you extracted the zip-package. +4. Validate your model via the context-menu on a package in the Project Browser and select *Specialize* %rarr; *YAKINDU EA-Bridge Integration* → *Example Model Validation* → it will take a few seconds, then check the Add-in window for the result. + +![EA demo](./EA_demo.gif) + + +## How to build this example + +* Validation CLI: + + The validation CLI is an OSGi application written in Java. Simply run the following maven command to build it. + + `cd CLI` + + `mvn clean package` + +* EA Add-in: + The Add-in is written in C# and uses the [automation API provided by Enterprise Architect](https://sparxsystems.com/enterprise_architect_user_guide/15.0/add-ins___scripting/addins_2.html) to access the model and add custom views to the UI. The UI extensions are simple Windows controls and forms. The entire Add-in is a .NET-based COM application. + To build the Add-in you need the following tools: + * Visual Studio 2022. In the IDE, the following extensions are required: + * NUnit 3 Test Adapter: required to build and run tests. It can be installed using the extension manager in Visual Studio. + * Wix Toolkit Visual Studio 2022 extensions: The Wix toolset is required to build the Add-in installer package. It can be installed using the extension manager in Visual Studio. However, it must be accompanied by the installation of the Wix tool which can be downloaded [here](https://wixtoolset.org/releases/). + * [Enterprise Architect version 15.2](https://sparxsystems.com/products/ea/downloads.html) + + After installing these tools, open the solution [`AddIn\EABridge_Example_AddIn.sln`](./AddIn/EABridge_Example_AddIn.sln) and build all projects contained in it. To register the built Add-in `DLL` with Enterprise Architect, run the script [`AddIn\EABridge_Example_AddIn\Install.bat`](./AddIn/EABridge_Example_AddIn/Install.bat). This script registers the DLL built by the IDE with Enterprise Architect as the Add-in. It needs to be run only once. When the Add-in installer is used, the DLL in the specified installation location will be used instead. + + +# Contribute + +We are always happy to see suggestions, bug reports, feature requests as well as pull requests. Please feel free to raise an issue or contribute with a pull request. + + +# Further information + +The [YAKINDU EA-Bridge|https://www.itemis.com/en/yakindu/ea-bridge/] has a free 30-day trial period which can be used with models containing up to 1000 elements.
+For a (free) unlimited evaluation license, please contact us via the website or e-mail: bridges @ yakindu.com diff --git a/eabridge_example_uscase.png b/eabridge_example_uscase.png new file mode 100644 index 0000000..201965a Binary files /dev/null and b/eabridge_example_uscase.png differ