This commit is contained in:
Christian Wade 2019-09-13 21:30:22 -07:00
parent 392e6a7fee
commit fd682bcd78
54 changed files with 3141 additions and 732 deletions

View File

@ -168,7 +168,7 @@ namespace BismNormalizer.CommandLine
throw new FileNotFoundException($"File not found {bsmnFile}"); throw new FileNotFoundException($"File not found {bsmnFile}");
} }
Console.WriteLine($"About to deserialize {bsmnFile}"); Console.WriteLine($"About to deserialize {bsmnFile}");
ComparisonInfo comparisonInfo = ComparisonInfo.DeserializeBsmnFile(bsmnFile); ComparisonInfo comparisonInfo = ComparisonInfo.DeserializeBsmnFile(bsmnFile, "BISM Normalizer Command Line");
Console.WriteLine(); Console.WriteLine();
if (comparisonInfo.ConnectionInfoSource.UseProject) if (comparisonInfo.ConnectionInfoSource.UseProject)
@ -198,19 +198,20 @@ namespace BismNormalizer.CommandLine
Console.WriteLine("--Comparing ..."); Console.WriteLine("--Comparing ...");
if (credsProvided) if (credsProvided)
{ {
comparisonInfo.CredsProvided = true;
comparisonInfo.SourceUsername = sourceUsername;
comparisonInfo.SourcePassword = sourcePassword;
comparisonInfo.TargetUsername = targetUsername;
comparisonInfo.TargetPassword = targetPassword;
if (!String.IsNullOrEmpty(workspaceServer)) if (!String.IsNullOrEmpty(workspaceServer))
{ {
_comparison = ComparisonFactory.CreateComparison(comparisonInfo, sourceUsername, sourcePassword, targetUsername, targetPassword, workspaceServer); comparisonInfo.WorkspaceServerProvided = true;
} comparisonInfo.WorkspaceServer = workspaceServer;
else
{
_comparison = ComparisonFactory.CreateComparison(comparisonInfo, sourceUsername, sourcePassword, targetUsername, targetPassword);
} }
} }
else
{ _comparison = ComparisonFactory.CreateComparison(comparisonInfo);
_comparison = ComparisonFactory.CreateComparison(comparisonInfo);
}
_comparison.ValidationMessage += HandleValidationMessage; _comparison.ValidationMessage += HandleValidationMessage;
_comparison.Connect(); _comparison.Connect();
_comparison.CompareTabularModels(); _comparison.CompareTabularModels();

View File

@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers // You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below: // by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")] // [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("4.0.1.10")] [assembly: AssemblyVersion("4.0.1.12")]
[assembly: AssemblyFileVersion("4.0.1.10")] [assembly: AssemblyFileVersion("4.0.1.12")]

View File

@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers // You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below: // by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")] // [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("4.0.1.10")] [assembly: AssemblyVersion("4.0.1.12")]
[assembly: AssemblyFileVersion("4.0.1.10")] [assembly: AssemblyFileVersion("4.0.1.12")]

View File

@ -40,20 +40,20 @@
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="Microsoft.AnalysisServices, Version=16.3.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL"> <Reference Include="Microsoft.AnalysisServices, Version=18.0.5.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AnalysisServices.retail.amd64.16.3.0\lib\net45\Microsoft.AnalysisServices.dll</HintPath> <HintPath>..\packages\Microsoft.AnalysisServices.retail.amd64.18.0.5\lib\net45\Microsoft.AnalysisServices.dll</HintPath>
</Reference> </Reference>
<Reference Include="Microsoft.AnalysisServices.Core, Version=16.3.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL"> <Reference Include="Microsoft.AnalysisServices.Core, Version=18.0.5.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AnalysisServices.retail.amd64.16.3.0\lib\net45\Microsoft.AnalysisServices.Core.dll</HintPath> <HintPath>..\packages\Microsoft.AnalysisServices.retail.amd64.18.0.5\lib\net45\Microsoft.AnalysisServices.Core.dll</HintPath>
</Reference> </Reference>
<Reference Include="Microsoft.AnalysisServices.SPClient.Interfaces, Version=16.3.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL"> <Reference Include="Microsoft.AnalysisServices.SPClient.Interfaces, Version=18.0.5.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AnalysisServices.retail.amd64.16.3.0\lib\net45\Microsoft.AnalysisServices.SPClient.Interfaces.dll</HintPath> <HintPath>..\packages\Microsoft.AnalysisServices.retail.amd64.18.0.5\lib\net45\Microsoft.AnalysisServices.SPClient.Interfaces.dll</HintPath>
</Reference> </Reference>
<Reference Include="Microsoft.AnalysisServices.Tabular, Version=16.3.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL"> <Reference Include="Microsoft.AnalysisServices.Tabular, Version=18.0.5.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AnalysisServices.retail.amd64.16.3.0\lib\net45\Microsoft.AnalysisServices.Tabular.dll</HintPath> <HintPath>..\packages\Microsoft.AnalysisServices.retail.amd64.18.0.5\lib\net45\Microsoft.AnalysisServices.Tabular.dll</HintPath>
</Reference> </Reference>
<Reference Include="Microsoft.AnalysisServices.Tabular.Json, Version=16.3.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL"> <Reference Include="Microsoft.AnalysisServices.Tabular.Json, Version=18.0.5.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AnalysisServices.retail.amd64.16.3.0\lib\net45\Microsoft.AnalysisServices.Tabular.Json.dll</HintPath> <HintPath>..\packages\Microsoft.AnalysisServices.retail.amd64.18.0.5\lib\net45\Microsoft.AnalysisServices.Tabular.Json.dll</HintPath>
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />
</ItemGroup> </ItemGroup>

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="Microsoft.AnalysisServices.retail.amd64" version="16.3.0" targetFramework="net461" /> <package id="Microsoft.AnalysisServices.retail.amd64" version="18.0.5" targetFramework="net472" />
</packages> </packages>

View File

@ -0,0 +1,107 @@
<?xml version="1.0" encoding="utf-8"?>
<ApplicationInsights xmlns="http://schemas.microsoft.com/ApplicationInsights/2013/Settings">
<TelemetryInitializers>
<Add Type="Microsoft.ApplicationInsights.DependencyCollector.HttpDependenciesParsingTelemetryInitializer, Microsoft.AI.DependencyCollector"/>
<Add Type="Microsoft.ApplicationInsights.WindowsServer.AzureRoleEnvironmentTelemetryInitializer, Microsoft.AI.WindowsServer"/>
<Add Type="Microsoft.ApplicationInsights.WindowsServer.AzureWebAppRoleEnvironmentTelemetryInitializer, Microsoft.AI.WindowsServer"/>
<Add Type="Microsoft.ApplicationInsights.WindowsServer.BuildInfoConfigComponentVersionTelemetryInitializer, Microsoft.AI.WindowsServer"/>
</TelemetryInitializers>
<TelemetryModules>
<Add Type="Microsoft.ApplicationInsights.DependencyCollector.DependencyTrackingTelemetryModule, Microsoft.AI.DependencyCollector">
<ExcludeComponentCorrelationHttpHeadersOnDomains>
<!--
Requests to the following hostnames will not be modified by adding correlation headers.
Add entries here to exclude additional hostnames.
NOTE: this configuration will be lost upon NuGet upgrade.
-->
<Add>core.windows.net</Add>
<Add>core.chinacloudapi.cn</Add>
<Add>core.cloudapi.de</Add>
<Add>core.usgovcloudapi.net</Add>
</ExcludeComponentCorrelationHttpHeadersOnDomains>
<IncludeDiagnosticSourceActivities>
<Add>Microsoft.Azure.EventHubs</Add>
<Add>Microsoft.Azure.ServiceBus</Add>
</IncludeDiagnosticSourceActivities>
</Add>
<Add Type="Microsoft.ApplicationInsights.Extensibility.PerfCounterCollector.PerformanceCollectorModule, Microsoft.AI.PerfCounterCollector">
<!--
Use the following syntax here to collect additional performance counters:
<Counters>
<Add PerformanceCounter="\Process(??APP_WIN32_PROC??)\Handle Count" ReportAs="Process handle count" />
...
</Counters>
PerformanceCounter must be either \CategoryName(InstanceName)\CounterName or \CategoryName\CounterName
NOTE: performance counters configuration will be lost upon NuGet upgrade.
The following placeholders are supported as InstanceName:
??APP_WIN32_PROC?? - instance name of the application process for Win32 counters.
??APP_W3SVC_PROC?? - instance name of the application IIS worker process for IIS/ASP.NET counters.
??APP_CLR_PROC?? - instance name of the application CLR process for .NET counters.
-->
</Add>
<Add Type="Microsoft.ApplicationInsights.Extensibility.PerfCounterCollector.QuickPulse.QuickPulseTelemetryModule, Microsoft.AI.PerfCounterCollector"/>
<Add Type="Microsoft.ApplicationInsights.WindowsServer.AppServicesHeartbeatTelemetryModule, Microsoft.AI.WindowsServer"/>
<Add Type="Microsoft.ApplicationInsights.WindowsServer.AzureInstanceMetadataTelemetryModule, Microsoft.AI.WindowsServer">
<!--
Remove individual fields collected here by adding them to the ApplicationInsighs.HeartbeatProvider
with the following syntax:
<Add Type="Microsoft.ApplicationInsights.Extensibility.Implementation.Tracing.DiagnosticsTelemetryModule, Microsoft.ApplicationInsights">
<ExcludedHeartbeatProperties>
<Add>osType</Add>
<Add>location</Add>
<Add>name</Add>
<Add>offer</Add>
<Add>platformFaultDomain</Add>
<Add>platformUpdateDomain</Add>
<Add>publisher</Add>
<Add>sku</Add>
<Add>version</Add>
<Add>vmId</Add>
<Add>vmSize</Add>
<Add>subscriptionId</Add>
<Add>resourceGroupName</Add>
<Add>placementGroupId</Add>
<Add>tags</Add>
<Add>vmScaleSetName</Add>
</ExcludedHeartbeatProperties>
</Add>
NOTE: exclusions will be lost upon upgrade.
-->
</Add>
<Add Type="Microsoft.ApplicationInsights.WindowsServer.DeveloperModeWithDebuggerAttachedTelemetryModule, Microsoft.AI.WindowsServer"/>
<Add Type="Microsoft.ApplicationInsights.WindowsServer.UnhandledExceptionTelemetryModule, Microsoft.AI.WindowsServer"/>
<Add Type="Microsoft.ApplicationInsights.WindowsServer.UnobservedExceptionTelemetryModule, Microsoft.AI.WindowsServer">
<!--</Add>
<Add Type="Microsoft.ApplicationInsights.WindowsServer.FirstChanceExceptionStatisticsTelemetryModule, Microsoft.AI.WindowsServer">-->
</Add>
</TelemetryModules>
<ApplicationIdProvider Type="Microsoft.ApplicationInsights.Extensibility.Implementation.ApplicationId.ApplicationInsightsApplicationIdProvider, Microsoft.ApplicationInsights"/>
<TelemetrySinks>
<Add Name="default">
<TelemetryProcessors>
<Add Type="Microsoft.ApplicationInsights.Extensibility.PerfCounterCollector.QuickPulse.QuickPulseTelemetryProcessor, Microsoft.AI.PerfCounterCollector"/>
<Add Type="Microsoft.ApplicationInsights.Extensibility.AutocollectedMetricsExtractor, Microsoft.ApplicationInsights"/>
<Add Type="Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel.AdaptiveSamplingTelemetryProcessor, Microsoft.AI.ServerTelemetryChannel">
<MaxTelemetryItemsPerSecond>5</MaxTelemetryItemsPerSecond>
<ExcludedTypes>Event</ExcludedTypes>
</Add>
<Add Type="Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel.AdaptiveSamplingTelemetryProcessor, Microsoft.AI.ServerTelemetryChannel">
<MaxTelemetryItemsPerSecond>5</MaxTelemetryItemsPerSecond>
<IncludedTypes>Event</IncludedTypes>
</Add>
</TelemetryProcessors>
<TelemetryChannel Type="Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel.ServerTelemetryChannel, Microsoft.AI.ServerTelemetryChannel"/>
</Add>
</TelemetrySinks>
<!--
Learn more about Application Insights configuration with ApplicationInsights.config here:
http://go.microsoft.com/fwlink/?LinkID=513840
Note: If not present, please add <InstrumentationKey>Your Key</InstrumentationKey> to the top of this file.
--></ApplicationInsights>

View File

@ -99,20 +99,20 @@
<Reference Include="Microsoft.AI.WindowsServer, Version=2.8.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> <Reference Include="Microsoft.AI.WindowsServer, Version=2.8.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.ApplicationInsights.WindowsServer.2.8.1\lib\net45\Microsoft.AI.WindowsServer.dll</HintPath> <HintPath>..\packages\Microsoft.ApplicationInsights.WindowsServer.2.8.1\lib\net45\Microsoft.AI.WindowsServer.dll</HintPath>
</Reference> </Reference>
<Reference Include="Microsoft.AnalysisServices, Version=16.3.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL"> <Reference Include="Microsoft.AnalysisServices, Version=18.0.5.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AnalysisServices.retail.amd64.16.3.0\lib\net45\Microsoft.AnalysisServices.dll</HintPath> <HintPath>..\packages\Microsoft.AnalysisServices.retail.amd64.18.0.5\lib\net45\Microsoft.AnalysisServices.dll</HintPath>
</Reference> </Reference>
<Reference Include="Microsoft.AnalysisServices.Core, Version=16.3.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL"> <Reference Include="Microsoft.AnalysisServices.Core, Version=18.0.5.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AnalysisServices.retail.amd64.16.3.0\lib\net45\Microsoft.AnalysisServices.Core.dll</HintPath> <HintPath>..\packages\Microsoft.AnalysisServices.retail.amd64.18.0.5\lib\net45\Microsoft.AnalysisServices.Core.dll</HintPath>
</Reference> </Reference>
<Reference Include="Microsoft.AnalysisServices.SPClient.Interfaces, Version=16.3.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL"> <Reference Include="Microsoft.AnalysisServices.SPClient.Interfaces, Version=18.0.5.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AnalysisServices.retail.amd64.16.3.0\lib\net45\Microsoft.AnalysisServices.SPClient.Interfaces.dll</HintPath> <HintPath>..\packages\Microsoft.AnalysisServices.retail.amd64.18.0.5\lib\net45\Microsoft.AnalysisServices.SPClient.Interfaces.dll</HintPath>
</Reference> </Reference>
<Reference Include="Microsoft.AnalysisServices.Tabular, Version=16.3.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL"> <Reference Include="Microsoft.AnalysisServices.Tabular, Version=18.0.5.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AnalysisServices.retail.amd64.16.3.0\lib\net45\Microsoft.AnalysisServices.Tabular.dll</HintPath> <HintPath>..\packages\Microsoft.AnalysisServices.retail.amd64.18.0.5\lib\net45\Microsoft.AnalysisServices.Tabular.dll</HintPath>
</Reference> </Reference>
<Reference Include="Microsoft.AnalysisServices.Tabular.Json, Version=16.3.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL"> <Reference Include="Microsoft.AnalysisServices.Tabular.Json, Version=18.0.5.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AnalysisServices.retail.amd64.16.3.0\lib\net45\Microsoft.AnalysisServices.Tabular.Json.dll</HintPath> <HintPath>..\packages\Microsoft.AnalysisServices.retail.amd64.18.0.5\lib\net45\Microsoft.AnalysisServices.Tabular.Json.dll</HintPath>
</Reference> </Reference>
<Reference Include="Microsoft.ApplicationInsights, Version=2.8.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> <Reference Include="Microsoft.ApplicationInsights, Version=2.8.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.ApplicationInsights.2.8.1\lib\net46\Microsoft.ApplicationInsights.dll</HintPath> <HintPath>..\packages\Microsoft.ApplicationInsights.2.8.1\lib\net46\Microsoft.ApplicationInsights.dll</HintPath>
@ -208,7 +208,9 @@
</Reference> </Reference>
<Reference Include="System.DirectoryServices.AccountManagement" /> <Reference Include="System.DirectoryServices.AccountManagement" />
<Reference Include="System.Drawing" /> <Reference Include="System.Drawing" />
<Reference Include="System.Management" />
<Reference Include="System.Net.Http" /> <Reference Include="System.Net.Http" />
<Reference Include="System.Runtime.Caching" />
<Reference Include="System.Web" /> <Reference Include="System.Web" />
<Reference Include="System.Web.Extensions" /> <Reference Include="System.Web.Extensions" />
<Reference Include="System.Windows.Forms" /> <Reference Include="System.Windows.Forms" />
@ -226,11 +228,28 @@
<Compile Include="TabularCompare\Enums.cs" /> <Compile Include="TabularCompare\Enums.cs" />
<Compile Include="TabularCompare\BlobKeyEventArgs.cs" /> <Compile Include="TabularCompare\BlobKeyEventArgs.cs" />
<Compile Include="TabularCompare\PasswordPromptEventArgs.cs" /> <Compile Include="TabularCompare\PasswordPromptEventArgs.cs" />
<Compile Include="TabularCompare\TabularMetadata\CalculationItem.cs" />
<Compile Include="TabularCompare\TabularMetadata\CalculationItemCollection.cs" />
<Compile Include="TabularCompare\TabularMetadata\RefreshPolicy.cs" />
<Compile Include="TabularCompare\TabularMetadata\RefreshPolicyCollection.cs" />
<Compile Include="TabularCompare\TabularMetadata\Model.cs" />
<Compile Include="TabularCompare\TabularMetadata\Expression.cs" /> <Compile Include="TabularCompare\TabularMetadata\Expression.cs" />
<Compile Include="TabularCompare\TabularMetadata\ExpressionCollection.cs" /> <Compile Include="TabularCompare\TabularMetadata\ExpressionCollection.cs" />
<Compile Include="TabularCompare\TabularMetadata\CalcDependency.cs" /> <Compile Include="TabularCompare\TabularMetadata\CalcDependency.cs" />
<Compile Include="TabularCompare\TabularMetadata\CalcDependencyCollection.cs" /> <Compile Include="TabularCompare\TabularMetadata\CalcDependencyCollection.cs" />
<Compile Include="TabularCompare\Telemetry.cs" /> <Compile Include="TabularCompare\Telemetry.cs" />
<Compile Include="TabularCompare\UI\ComparisonControl.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="TabularCompare\UI\ComparisonControl.Designer.cs">
<DependentUpon>ComparisonControl.cs</DependentUpon>
</Compile>
<Compile Include="TabularCompare\UI\Connections.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="TabularCompare\UI\Connections.Designer.cs">
<DependentUpon>Connections.cs</DependentUpon>
</Compile>
<Compile Include="TabularCompare\UI\HighDpiUtils.cs" /> <Compile Include="TabularCompare\UI\HighDpiUtils.cs" />
<Compile Include="TabularCompare\UI\BlobCredentials.cs"> <Compile Include="TabularCompare\UI\BlobCredentials.cs">
<SubType>Form</SubType> <SubType>Form</SubType>
@ -260,12 +279,6 @@
<Compile Include="TabularCompare\MultidimensionalMetadata\Table.cs" /> <Compile Include="TabularCompare\MultidimensionalMetadata\Table.cs" />
<Compile Include="TabularCompare\MultidimensionalMetadata\TableCollection.cs" /> <Compile Include="TabularCompare\MultidimensionalMetadata\TableCollection.cs" />
<Compile Include="TabularCompare\MultidimensionalMetadata\ITabularObject.cs" /> <Compile Include="TabularCompare\MultidimensionalMetadata\ITabularObject.cs" />
<Compile Include="TabularCompare\UI\ComparisonControl.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="TabularCompare\UI\ComparisonControl.Designer.cs">
<DependentUpon>ComparisonControl.cs</DependentUpon>
</Compile>
<Compile Include="TabularCompare\Core\Comparison.cs" /> <Compile Include="TabularCompare\Core\Comparison.cs" />
<Compile Include="TabularCompare\Core\ComparisonObject.cs" /> <Compile Include="TabularCompare\Core\ComparisonObject.cs" />
<Compile Include="TabularCompare\PartitionRowCounter.cs" /> <Compile Include="TabularCompare\PartitionRowCounter.cs" />
@ -330,11 +343,11 @@
<Compile Include="TabularCompare\UI\TreeGridView.cs" /> <Compile Include="TabularCompare\UI\TreeGridView.cs" />
<Compile Include="TabularCompare\UI\TreeGridViewComparison.cs" /> <Compile Include="TabularCompare\UI\TreeGridViewComparison.cs" />
<Compile Include="TabularCompare\UI\TreeGridViewValidationOutput.cs" /> <Compile Include="TabularCompare\UI\TreeGridViewValidationOutput.cs" />
<Compile Include="TabularCompare\UI\Connections.cs"> <Compile Include="TabularCompare\UI\ConnectionsAlmt.cs">
<SubType>Form</SubType> <SubType>Form</SubType>
</Compile> </Compile>
<Compile Include="TabularCompare\UI\Connections.Designer.cs"> <Compile Include="TabularCompare\UI\ConnectionsAlmt.Designer.cs">
<DependentUpon>Connections.cs</DependentUpon> <DependentUpon>ConnectionsAlmt.cs</DependentUpon>
</Compile> </Compile>
<Compile Include="WarningList.cs" /> <Compile Include="WarningList.cs" />
<Compile Include="EditorFactory.cs" /> <Compile Include="EditorFactory.cs" />
@ -418,6 +431,8 @@
<Resource Include="Resources\Error.png" /> <Resource Include="Resources\Error.png" />
<Resource Include="Resources\Culture.png" /> <Resource Include="Resources\Culture.png" />
<Resource Include="Resources\Expression.png" /> <Resource Include="Resources\Expression.png" />
<Resource Include="Resources\CalculationGroup.png" />
<Resource Include="Resources\CalculationItem.png" />
<Content Include="Resources\LicenseTerms.txt"> <Content Include="Resources\LicenseTerms.txt">
<IncludeInVSIX>true</IncludeInVSIX> <IncludeInVSIX>true</IncludeInVSIX>
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
@ -434,9 +449,7 @@
<Resource Include="Resources\Warning.png" /> <Resource Include="Resources\Warning.png" />
<Resource Include="Resources\WarningToolWindow.png" /> <Resource Include="Resources\WarningToolWindow.png" />
<Resource Include="Resources\SkipActionGrey.png" /> <Resource Include="Resources\SkipActionGrey.png" />
<None Include="ApplicationInsights.config"> <None Include="ApplicationInsights.config" />
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="TabularCompare\TabularCompare.dgml"> <None Include="TabularCompare\TabularCompare.dgml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
</None> </None>
@ -448,6 +461,8 @@
<Resource Include="Resources\ProgressError.png" /> <Resource Include="Resources\ProgressError.png" />
<Resource Include="Resources\ProgressWarning.png" /> <Resource Include="Resources\ProgressWarning.png" />
<Resource Include="Resources\Processing.png" /> <Resource Include="Resources\Processing.png" />
<Resource Include="Resources\Model.png" />
<Resource Include="Resources\RefreshPolicy.png" />
<Content Include="Templates\TabularCompare.bsmn"> <Content Include="Templates\TabularCompare.bsmn">
<IncludeInVSIX>true</IncludeInVSIX> <IncludeInVSIX>true</IncludeInVSIX>
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
@ -470,11 +485,13 @@
<ItemGroup> <ItemGroup>
<EmbeddedResource Include="TabularCompare\UI\ComparisonControl.resx"> <EmbeddedResource Include="TabularCompare\UI\ComparisonControl.resx">
<DependentUpon>ComparisonControl.cs</DependentUpon> <DependentUpon>ComparisonControl.cs</DependentUpon>
<SubType>Designer</SubType>
</EmbeddedResource> </EmbeddedResource>
<EmbeddedResource Include="TabularCompare\UI\Connections.resx"> <EmbeddedResource Include="TabularCompare\UI\Connections.resx">
<DependentUpon>Connections.cs</DependentUpon> <DependentUpon>Connections.cs</DependentUpon>
</EmbeddedResource> </EmbeddedResource>
<EmbeddedResource Include="TabularCompare\UI\ConnectionsAlmt.resx">
<DependentUpon>ConnectionsAlmt.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="TabularCompare\UI\Deployment.resx"> <EmbeddedResource Include="TabularCompare\UI\Deployment.resx">
<DependentUpon>Deployment.cs</DependentUpon> <DependentUpon>Deployment.cs</DependentUpon>
</EmbeddedResource> </EmbeddedResource>

Binary file not shown.

View File

@ -114,7 +114,7 @@
<Target Name="AfterBuild" Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> <Target Name="AfterBuild" Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<!--Run tests (BismNormalizer.Tests.dll)--> <!--Run tests (BismNormalizer.Tests.dll)-->
<ItemGroup> <!--<ItemGroup>
<TrxFiles Include="TestResults\*.trx" /> <TrxFiles Include="TestResults\*.trx" />
</ItemGroup> </ItemGroup>
<Message Text=" " Importance="high" /> <Message Text=" " Importance="high" />
@ -123,7 +123,7 @@
<Delete Files="@(TrxFiles)" /> <Delete Files="@(TrxFiles)" />
<Message Text="- About to run vstest on: @(OutputDlls)" Importance="high" /> <Message Text="- About to run vstest on: @(OutputDlls)" Importance="high" />
<Message Text=" " Importance="high" /> <Message Text=" " Importance="high" />
<Exec Command="vstest.console.exe @(OutputDlls) /Logger:trx" /> <Exec Command="vstest.console.exe @(OutputDlls) /Logger:trx" />-->
<PropertyGroup> <PropertyGroup>
<ObfuscDir>$(MSBuildProjectDirectory)\bin\ReleaseObfusc</ObfuscDir> <ObfuscDir>$(MSBuildProjectDirectory)\bin\ReleaseObfusc</ObfuscDir>

View File

@ -12,7 +12,7 @@ namespace BismNormalizer
{ {
public static void Main() public static void Main()
{ {
using (Comparison c = ComparisonFactory.CreateComparison("C:\\TabularCompare1.bsmn")) using (Comparison c = ComparisonFactory.CreateComparison("C:\\TabularCompare1.bsmn", ""))
{ {
c.Connect(); c.Connect();
c.CompareTabularModels(); c.CompareTabularModels();

View File

@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers // You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below: // by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")] // [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("4.0.1.10")] [assembly: AssemblyVersion("4.0.1.12")]
[assembly: AssemblyFileVersion("4.0.1.10")] [assembly: AssemblyFileVersion("4.0.1.12")]

View File

@ -140,7 +140,7 @@ namespace BismNormalizer {
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to BISM Normalizer Warning List. /// Looks up a localized string similar to Warning List.
/// </summary> /// </summary>
internal static string ToolWindowTitle { internal static string ToolWindowTitle {
get { get {

View File

@ -125,7 +125,7 @@
<value>Resources\Progress.gif;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> <value>Resources\Progress.gif;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data> </data>
<data name="ToolWindowTitle" xml:space="preserve"> <data name="ToolWindowTitle" xml:space="preserve">
<value>BISM Normalizer Warning List</value> <value>Warning List</value>
</data> </data>
<data name="LogoSmall" type="System.Resources.ResXFileRef, System.Windows.Forms"> <data name="LogoSmall" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\LogoSmall.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> <value>Resources\LogoSmall.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>

Binary file not shown.

After

Width:  |  Height:  |  Size: 319 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 517 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 529 B

View File

@ -12,10 +12,10 @@ namespace BismNormalizer {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.1.0.0")] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.2.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { public sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); public static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default { public static Settings Default {
get { get {
@ -286,5 +286,41 @@ namespace BismNormalizer {
this["OptionHighDpiLocal"] = value; this["OptionHighDpiLocal"] = value;
} }
} }
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool OptionCompositeModelsOverride {
get {
return ((bool)(this["OptionCompositeModelsOverride"]));
}
set {
this["OptionCompositeModelsOverride"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool OptionRetainPolicyPartitions {
get {
return ((bool)(this["OptionRetainPolicyPartitions"]));
}
set {
this["OptionRetainPolicyPartitions"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool OptionRetainStorageMode {
get {
return ((bool)(this["OptionRetainStorageMode"]));
}
set {
this["OptionRetainStorageMode"] = value;
}
}
} }
} }

View File

@ -5,7 +5,7 @@
// The PropertyChanged event is raised after a setting's value is changed. // The PropertyChanged event is raised after a setting's value is changed.
// The SettingsLoaded event is raised after the setting values are loaded. // The SettingsLoaded event is raised after the setting values are loaded.
// The SettingsSaving event is raised before the setting values are saved. // The SettingsSaving event is raised before the setting values are saved.
internal sealed partial class Settings { public sealed partial class Settings {
public Settings() { public Settings() {
// // To add event handlers for saving and changing settings, uncomment the lines below: // // To add event handlers for saving and changing settings, uncomment the lines below:

View File

@ -68,5 +68,14 @@
<Setting Name="OptionHighDpiLocal" Type="System.Boolean" Scope="User"> <Setting Name="OptionHighDpiLocal" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value> <Value Profile="(Default)">True</Value>
</Setting> </Setting>
<Setting Name="OptionCompositeModelsOverride" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="OptionRetainPolicyPartitions" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="OptionRetainStorageMode" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
</Settings> </Settings>
</SettingsFile> </SettingsFile>

View File

@ -14,7 +14,9 @@ namespace BismNormalizer.TabularCompare
{ {
// Factory pattern: https://msdn.microsoft.com/en-us/library/orm-9780596527730-01-05.aspx // Factory pattern: https://msdn.microsoft.com/en-us/library/orm-9780596527730-01-05.aspx
private static List<int> _supportedCompatibilityLevels = new List<int>() { 1100, 1103, 1200, 1400 }; private static int _minCompatibilityLevel = 1100;
private static int _maxCompatibilityLevel = 1500;
private static List<string> _supportedDataSourceVersions = new List<string> { "PowerBI_V3" };
/// <summary> /// <summary>
/// Uses factory design pattern to return an object of type Core.Comparison, which is instantiated using MultidimensionalMetadata.Comparison or TabularMeatadata.Comparison depending on SSAS compatibility level. Use this overload when running in Visual Studio. /// Uses factory design pattern to return an object of type Core.Comparison, which is instantiated using MultidimensionalMetadata.Comparison or TabularMeatadata.Comparison depending on SSAS compatibility level. Use this overload when running in Visual Studio.
@ -42,9 +44,9 @@ namespace BismNormalizer.TabularCompare
/// </summary> /// </summary>
/// <param name="bsmnFile">Full path to the BSMN file.</param> /// <param name="bsmnFile">Full path to the BSMN file.</param>
/// <returns>Core.Comparison object</returns> /// <returns>Core.Comparison object</returns>
public static Comparison CreateComparison(string bsmnFile) public static Comparison CreateComparison(string bsmnFile, string appName)
{ {
ComparisonInfo comparisonInfo = ComparisonInfo.DeserializeBsmnFile(bsmnFile); ComparisonInfo comparisonInfo = ComparisonInfo.DeserializeBsmnFile(bsmnFile, appName);
return CreateComparison(comparisonInfo); return CreateComparison(comparisonInfo);
} }
@ -59,57 +61,136 @@ namespace BismNormalizer.TabularCompare
return CreateComparisonInitialized(comparisonInfo); return CreateComparisonInitialized(comparisonInfo);
} }
/// <summary>
/// Uses factory design pattern to return an object of type Core.Comparison, which is instantiated using MultidimensionalMetadata.Comparison or TabularMeatadata.Comparison depending on SSAS compatibility level.
/// </summary>
/// <param name="comparisonInfo">ComparisonInfo object for the comparison.</param>
/// <returns>Core.Comparison object</returns>
public static Comparison CreateComparison(ComparisonInfo comparisonInfo, string sourceUsername, string sourcePassword, string targetUsername, string targetPassword)
{
comparisonInfo.InitializeCompatibilityLevels(sourceUsername, sourcePassword, targetUsername, targetPassword);
return CreateComparisonInitialized(comparisonInfo);
}
/// <summary>
/// Uses factory design pattern to return an object of type Core.Comparison, which is instantiated using MultidimensionalMetadata.Comparison or TabularMeatadata.Comparison depending on SSAS compatibility level.
/// </summary>
/// <param name="comparisonInfo">ComparisonInfo object for the comparison.</param>
/// <returns>Core.Comparison object</returns>
public static Comparison CreateComparison(ComparisonInfo comparisonInfo, string sourceUsername, string sourcePassword, string targetUsername, string targetPassword, string workspaceServer)
{
comparisonInfo.InitializeCompatibilityLevels(sourceUsername, sourcePassword, targetUsername, targetPassword, workspaceServer);
return CreateComparisonInitialized(comparisonInfo);
}
private static Comparison CreateComparisonInitialized(ComparisonInfo comparisonInfo) private static Comparison CreateComparisonInitialized(ComparisonInfo comparisonInfo)
{ {
Telemetry.TrackEvent("CreateComparisonInitialized", new Dictionary<string, string> { { "App", "BismNormalizer" } }); Telemetry.TrackEvent("CreateComparisonInitialized", new Dictionary<string, string> { { "App", comparisonInfo.AppName.Replace(" ", "") } });
if (comparisonInfo.SourceCompatibilityLevel != comparisonInfo.TargetCompatibilityLevel && !(comparisonInfo.SourceCompatibilityLevel == 1200 && comparisonInfo.TargetCompatibilityLevel == 1400)) ////Currently can't source from PBIP to AS because AS doesn't work with inline data sources:
//if (comparisonInfo.ConnectionInfoSource.ServerName.StartsWith("powerbi://") && !comparisonInfo.ConnectionInfoTarget.ServerName.StartsWith("powerbi://"))
//{
// throw new ConnectionException($"Source model is a Power BI dataset and the target is Analysis Services, which is not supported in the current version.");
//}
//If composite models not allowed on AS, check DQ/Import at model level matches:
if (!comparisonInfo.ConnectionInfoSource.ServerName.StartsWith("powerbi://") && !Settings.Default.OptionCompositeModelsOverride && comparisonInfo.SourceDirectQuery != comparisonInfo.TargetDirectQuery)
{
throw new ConnectionException($"Mixed DirectQuery settings are not supported for AS skus.\nSource is {(comparisonInfo.SourceDirectQuery ? "On" : "Off")} and target is {(comparisonInfo.TargetDirectQuery ? "On" : "Off")}.");
}
#region Data-source versions check
//If Power BI, check the default datasource version
//Source
bool sourceDataSourceVersionRequiresUpgrade = false;
if (comparisonInfo.ConnectionInfoSource.ServerName.StartsWith("powerbi://") && !_supportedDataSourceVersions.Contains(comparisonInfo.SourceDataSourceVersion))
{
sourceDataSourceVersionRequiresUpgrade = true;
}
//Target
bool targetDataSourceVersionRequiresUpgrade = false;
if (comparisonInfo.ConnectionInfoTarget.ServerName.StartsWith("powerbi://") && !_supportedDataSourceVersions.Contains(comparisonInfo.TargetDataSourceVersion))
{
targetDataSourceVersionRequiresUpgrade = true;
}
//Check if user willing to upgrade the data-source version(s)
if (sourceDataSourceVersionRequiresUpgrade && targetDataSourceVersionRequiresUpgrade)
{
string message = $"The source and target are Power BI datasets have default data-source versions of {comparisonInfo.SourceDataSourceVersion} and {comparisonInfo.TargetDataSourceVersion} respectively, which are not supported for comparison.";
if (comparisonInfo.Interactive && System.Windows.Forms.MessageBox.Show(
message += $"\nDo you want to upgrade them both to {_supportedDataSourceVersions[0]} and allow the comparison?\n\nNOTE: this is a irreversible operation and you may not be able to download the PBIX file(s) to Power BI Desktop. You should only do this if you have the original PBIX as a backup.", comparisonInfo.AppName, System.Windows.Forms.MessageBoxButtons.YesNo, System.Windows.Forms.MessageBoxIcon.Question) != System.Windows.Forms.DialogResult.Yes)
{
throw new ConnectionException(message);
}
}
else if (sourceDataSourceVersionRequiresUpgrade)
{
string message = $"The source is a Power BI dataset with default data-source version of {comparisonInfo.SourceDataSourceVersion}, which is not supported for comparison.";
if (comparisonInfo.Interactive && System.Windows.Forms.MessageBox.Show(
message += $"\nDo you want to upgrade it to {_supportedDataSourceVersions[0]} and allow the comparison?\n\nNOTE: this is a irreversible operation and you may not be able to download the PBIX file(s) to Power BI Desktop. You should only do this if you have the original PBIX as a backup.", comparisonInfo.AppName, System.Windows.Forms.MessageBoxButtons.YesNo, System.Windows.Forms.MessageBoxIcon.Question) != System.Windows.Forms.DialogResult.Yes)
{
throw new ConnectionException(message);
}
}
else if (targetDataSourceVersionRequiresUpgrade)
{
string message = $"The target is a Power BI datasets with default data-source version of {comparisonInfo.TargetDataSourceVersion}, which is not supported for comparison.";
if (comparisonInfo.Interactive && System.Windows.Forms.MessageBox.Show(
message += $"\nDo you want to upgrade it to {_supportedDataSourceVersions[0]} and allow the comparison?\n\nNOTE: this is a irreversible operation and you may not be able to download the PBIX file(s) to Power BI Desktop. You should only do this if you have the original PBIX as a backup.", comparisonInfo.AppName, System.Windows.Forms.MessageBoxButtons.YesNo, System.Windows.Forms.MessageBoxIcon.Question) != System.Windows.Forms.DialogResult.Yes)
{
throw new ConnectionException(message);
}
}
#endregion
//Check if one of the supported compat levels:
if (
!(comparisonInfo.SourceCompatibilityLevel >= _minCompatibilityLevel && comparisonInfo.SourceCompatibilityLevel <= _maxCompatibilityLevel &&
comparisonInfo.TargetCompatibilityLevel >= _minCompatibilityLevel && comparisonInfo.TargetCompatibilityLevel <= _maxCompatibilityLevel
)
)
{ {
throw new ConnectionException($"This combination of mixed compatibility levels is not supported.\nSource is {Convert.ToString(comparisonInfo.SourceCompatibilityLevel)} and target is {Convert.ToString(comparisonInfo.TargetCompatibilityLevel)}."); throw new ConnectionException($"This combination of mixed compatibility levels is not supported.\nSource is {Convert.ToString(comparisonInfo.SourceCompatibilityLevel)} and target is {Convert.ToString(comparisonInfo.TargetCompatibilityLevel)}.");
} }
if (comparisonInfo.SourceDirectQuery != comparisonInfo.TargetDirectQuery) //Return the comparison object & offer upgrade of target if appropriate
{ Comparison returnComparison = null;
throw new ConnectionException($"Mixed DirectQuery settings are not supported.\nSource is {(comparisonInfo.SourceDirectQuery ? "On" : "Off")} and target is {(comparisonInfo.TargetDirectQuery ? "On" : "Off")}.");
}
//We know both models have same compatibility level, but is it supported? if (comparisonInfo.SourceCompatibilityLevel >= 1200 && comparisonInfo.TargetCompatibilityLevel >= 1200)
if (!_supportedCompatibilityLevels.Contains(comparisonInfo.SourceCompatibilityLevel))
{ {
throw new ConnectionException($"Models have compatibility level of {Convert.ToString(comparisonInfo.SourceCompatibilityLevel)}, which is not supported by this version of BISM Normalizer.\nPlease check http://bism-normalizer.com/purchase for other versions."); returnComparison = new TabularMetadata.Comparison(comparisonInfo);
} TabularMetadata.Comparison returnTabularComparison = (TabularMetadata.Comparison)returnComparison;
if (comparisonInfo.SourceCompatibilityLevel >= 1200) //Upgrade default DATA-SOURCE versions if required
{ if (sourceDataSourceVersionRequiresUpgrade)
return new TabularMetadata.Comparison(comparisonInfo); {
returnTabularComparison.SourceTabularModel.Connect();
returnTabularComparison.SourceTabularModel.TomDatabase.Model.DefaultPowerBIDataSourceVersion = Microsoft.AnalysisServices.Tabular.PowerBIDataSourceVersion.PowerBI_V3;
returnTabularComparison.SourceTabularModel.TomDatabase.Update();
returnTabularComparison.Disconnect();
}
if (targetDataSourceVersionRequiresUpgrade)
{
returnTabularComparison.TargetTabularModel.Connect();
returnTabularComparison.TargetTabularModel.TomDatabase.Model.DefaultPowerBIDataSourceVersion = Microsoft.AnalysisServices.Tabular.PowerBIDataSourceVersion.PowerBI_V3;
returnTabularComparison.TargetTabularModel.TomDatabase.Update();
returnTabularComparison.Disconnect();
}
//Check if source has a higher compat level than the target and offer upgrade if appropriate.
if (comparisonInfo.SourceCompatibilityLevel > comparisonInfo.TargetCompatibilityLevel)
{
string message = $"Source compatibility level is { Convert.ToString(comparisonInfo.SourceCompatibilityLevel) } and target is { Convert.ToString(comparisonInfo.TargetCompatibilityLevel) }, which is not supported for comparison.\n";
if (comparisonInfo.Interactive &&
!comparisonInfo.ConnectionInfoTarget.UseProject && //Upgrade in SSDT not supported
System.Windows.Forms.MessageBox.Show(
message += $"\nDo you want to upgrade the target to {Convert.ToString(comparisonInfo.SourceCompatibilityLevel)} and allow the comparison?", comparisonInfo.AppName, System.Windows.Forms.MessageBoxButtons.YesNo, System.Windows.Forms.MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.Yes)
{
returnTabularComparison.TargetTabularModel.Connect();
returnTabularComparison.TargetTabularModel.TomDatabase.CompatibilityLevel = comparisonInfo.SourceCompatibilityLevel;
returnTabularComparison.TargetTabularModel.TomDatabase.Update();
returnTabularComparison.Disconnect();
}
else
{
throw new ConnectionException(message + "\nUpgrade the target compatibility level and retry.");
}
}
} }
else else
{ {
return new MultidimensionalMetadata.Comparison(comparisonInfo); if (comparisonInfo.SourceCompatibilityLevel == comparisonInfo.TargetCompatibilityLevel)
{
returnComparison = new MultidimensionalMetadata.Comparison(comparisonInfo);
}
else
{
throw new ConnectionException($"This combination of mixed compatibility levels is not supported.\nSource is {Convert.ToString(comparisonInfo.SourceCompatibilityLevel)} and target is {Convert.ToString(comparisonInfo.TargetCompatibilityLevel)}.");
}
} }
}
return returnComparison;
}
} }
} }

View File

@ -18,9 +18,20 @@ namespace BismNormalizer.TabularCompare
private SkipSelectionCollection _skipSelectionCollection; private SkipSelectionCollection _skipSelectionCollection;
private int _sourceCompatibilityLevel; private int _sourceCompatibilityLevel;
private int _targetCompatibilityLevel; private int _targetCompatibilityLevel;
private string _sourceDataSourceVersion;
private string _targetDataSourceVersion;
private bool _sourceDirectQuery; private bool _sourceDirectQuery;
private bool _targetDirectQuery; private bool _targetDirectQuery;
private bool _promptForDatabaseProcessing; private bool _promptForDatabaseProcessing;
private bool _interactive = true;
private string _appName = "<AppName>";
private bool _credsProvided = false;
private string _sourceUsername;
private string _sourcePassword;
private string _targetUsername;
private string _targetPassword;
private bool _workspaceServerProvided = false;
private string _workspaceServer;
/// <summary> /// <summary>
/// Initializes a new instance of the ComparisonInfo class. /// Initializes a new instance of the ComparisonInfo class.
@ -73,17 +84,29 @@ namespace BismNormalizer.TabularCompare
} }
/// <summary> /// <summary>
/// SSAS compatibility level for the source tabular model. /// Compatibility level for the source tabular model.
/// </summary> /// </summary>
[XmlIgnore()] [XmlIgnore()]
public int SourceCompatibilityLevel => _sourceCompatibilityLevel; public int SourceCompatibilityLevel => _sourceCompatibilityLevel;
/// <summary> /// <summary>
/// SSAS compatibility level for the target tabular model. /// Compatibility level for the target tabular model.
/// </summary> /// </summary>
[XmlIgnore()] [XmlIgnore()]
public int TargetCompatibilityLevel => _targetCompatibilityLevel; public int TargetCompatibilityLevel => _targetCompatibilityLevel;
/// <summary>
/// Default data source version for the source tabular model.
/// </summary>
[XmlIgnore()]
public string SourceDataSourceVersion => _sourceDataSourceVersion;
/// <summary>
/// Default data source version for the target tabular model.
/// </summary>
[XmlIgnore()]
public string TargetDataSourceVersion => _targetDataSourceVersion;
/// <summary> /// <summary>
/// Flag depending on whehter source tabular model is in DirectQuery mode. /// Flag depending on whehter source tabular model is in DirectQuery mode.
/// </summary> /// </summary>
@ -106,6 +129,96 @@ namespace BismNormalizer.TabularCompare
set { _promptForDatabaseProcessing = value; } set { _promptForDatabaseProcessing = value; }
} }
/// <summary>
/// Flag depending on whether running in interactive mode. Command line execution is not.
/// </summary>
[XmlIgnore()]
public bool Interactive
{
get { return _interactive; }
set { _interactive = value; }
}
/// <summary>
/// Name of the app. For example, BISM Normalizer or ALM Toolkit.
/// </summary>
[XmlIgnore()]
public string AppName
{
get { return _appName; }
set { _appName = value; }
}
/// <summary>
/// Flag depending on whether credentials provided to connect to AS/PBI. Used for command line mode/automated build.
/// </summary>
[XmlIgnore()]
public bool CredsProvided
{
get { return _credsProvided; }
set { _credsProvided = value; }
}
/// <summary>
/// Username for source model for when CredsProvided = true.
/// </summary>
[XmlIgnore()]
public string SourceUsername
{
get { return _sourceUsername; }
set { _sourceUsername = value; }
}
/// <summary>
/// Password for source model for when CredsProvided = true.
/// </summary>
[XmlIgnore()]
public string SourcePassword
{
get { return _sourcePassword; }
set { _sourcePassword = value; }
}
/// <summary>
/// Username for target model for when CredsProvided = true.
/// </summary>
[XmlIgnore()]
public string TargetUsername
{
get { return _targetUsername; }
set { _targetUsername = value; }
}
/// <summary>
/// Password for target model for when CredsProvided = true.
/// </summary>
[XmlIgnore()]
public string TargetPassword
{
get { return _targetPassword; }
set { _targetPassword = value; }
}
/// <summary>
/// Flag depending on whether workspace server was provided. Used for command line mode/automated build.
/// </summary>
[XmlIgnore()]
public bool WorkspaceServerProvided
{
get { return _workspaceServerProvided; }
set { _workspaceServerProvided = value; }
}
/// <summary>
/// Workspace server name for when WorkspaceServerProvided = true. Used for command line mode/automated build.
/// </summary>
[XmlIgnore()]
public string WorkspaceServer
{
get { return _workspaceServer; }
set { _workspaceServer = value; }
}
#endregion #endregion
/// <summary> /// <summary>
@ -113,7 +226,7 @@ namespace BismNormalizer.TabularCompare
/// </summary> /// </summary>
/// <param name="bsmnFile">BSMN file to be deserialized.</param> /// <param name="bsmnFile">BSMN file to be deserialized.</param>
/// <returns>Deserialized instance of ComparisonInfo.</returns> /// <returns>Deserialized instance of ComparisonInfo.</returns>
public static ComparisonInfo DeserializeBsmnFile(string bsmnFile) public static ComparisonInfo DeserializeBsmnFile(string bsmnFile, string appName)
{ {
if (!File.Exists(bsmnFile)) if (!File.Exists(bsmnFile))
{ {
@ -121,58 +234,44 @@ namespace BismNormalizer.TabularCompare
} }
XmlSerializer reader = new XmlSerializer(typeof(ComparisonInfo)); XmlSerializer reader = new XmlSerializer(typeof(ComparisonInfo));
StreamReader file = new StreamReader(bsmnFile); StreamReader file = new StreamReader(bsmnFile);
return (ComparisonInfo)reader.Deserialize(file); ComparisonInfo returnComparisonInfo = (ComparisonInfo)reader.Deserialize(file);
returnComparisonInfo.AppName = appName;
return returnComparisonInfo;
} }
/// <summary> /// <summary>
/// Finds models' compatibility levels (and preps databases on workspace servers for comparison). This overload to be used when client is not Visual Studio - e.g. command line. /// Finds models' compatibility levels (and preps databases on workspace servers for comparison). This overload to be used when client is not Visual Studio - e.g. command line.
/// </summary> /// </summary>
/// <param name="compatibilityLevelSource"></param>
/// <param name="compatibilityLevelTarget"></param>
public void InitializeCompatibilityLevels() public void InitializeCompatibilityLevels()
{ {
if (_credsProvided)
{
ConnectionInfoSource.CredsProvided = true;
ConnectionInfoSource.Username = _sourceUsername;
ConnectionInfoSource.Password = _sourcePassword;
ConnectionInfoTarget.CredsProvided = true;
ConnectionInfoTarget.Username = _targetUsername;
ConnectionInfoTarget.Password = _targetPassword;
if (_workspaceServerProvided)
{
ConnectionInfoSource.WorkspaceServerProvided = true;
ConnectionInfoSource.WorkspaceServer = _workspaceServer;
ConnectionInfoTarget.WorkspaceServerProvided = true;
ConnectionInfoTarget.WorkspaceServer = _workspaceServer;
}
}
ConnectionInfoSource.InitializeCompatibilityLevel(); ConnectionInfoSource.InitializeCompatibilityLevel();
ConnectionInfoTarget.InitializeCompatibilityLevel(); ConnectionInfoTarget.InitializeCompatibilityLevel();
PopulateDatabaseProperties(); PopulateDatabaseProperties();
} }
/// <summary>
/// Finds models' compatibility levels (and preps databases on workspace servers for comparison). This overload to be used when client is not Visual Studio - e.g. command line.
/// </summary>
public void InitializeCompatibilityLevels(string sourceUsername, string sourcePassword, string targetUsername, string targetPassword)
{
ConnectionInfoSource.CredsProvided = true;
ConnectionInfoSource.Username = sourceUsername;
ConnectionInfoSource.Password = sourcePassword;
ConnectionInfoSource.InitializeCompatibilityLevel();
ConnectionInfoTarget.CredsProvided = true;
ConnectionInfoTarget.Username = targetUsername;
ConnectionInfoTarget.Password = targetPassword;
ConnectionInfoTarget.InitializeCompatibilityLevel();
PopulateDatabaseProperties();
}
/// <summary>
/// Finds models' compatibility levels (and preps databases on workspace servers for comparison). This overload to be used when client is not Visual Studio - e.g. command line.
/// </summary>
public void InitializeCompatibilityLevels(string sourceUsername, string sourcePassword, string targetUsername, string targetPassword, string workspaceServer)
{
ConnectionInfoSource.CredsProvided = true;
ConnectionInfoSource.Username = sourceUsername;
ConnectionInfoSource.Password = sourcePassword;
ConnectionInfoSource.InitializeCompatibilityLevel(workspaceServer: workspaceServer);
ConnectionInfoTarget.CredsProvided = true;
ConnectionInfoTarget.Username = targetUsername;
ConnectionInfoTarget.Password = targetPassword;
ConnectionInfoTarget.InitializeCompatibilityLevel(workspaceServer: workspaceServer);
PopulateDatabaseProperties();
}
/// <summary> /// <summary>
/// Finds model compatibility levels (and preps databases on workspace servers for comparison). This overload to be used when running in Visual Studio. Allows user to cancel if doesn't want to close .bim file(s). /// Finds model compatibility levels (and preps databases on workspace servers for comparison). This overload to be used when running in Visual Studio. Allows user to cancel if doesn't want to close .bim file(s).
/// </summary> /// </summary>
@ -202,6 +301,9 @@ namespace BismNormalizer.TabularCompare
_sourceCompatibilityLevel = ConnectionInfoSource.CompatibilityLevel; _sourceCompatibilityLevel = ConnectionInfoSource.CompatibilityLevel;
_targetCompatibilityLevel = ConnectionInfoTarget.CompatibilityLevel; _targetCompatibilityLevel = ConnectionInfoTarget.CompatibilityLevel;
_sourceDataSourceVersion = ConnectionInfoSource.DataSourceVersion;
_targetDataSourceVersion = ConnectionInfoTarget.DataSourceVersion;
_sourceDirectQuery = ConnectionInfoSource.DirectQuery; _sourceDirectQuery = ConnectionInfoSource.DirectQuery;
_targetDirectQuery = ConnectionInfoTarget.DirectQuery; _targetDirectQuery = ConnectionInfoTarget.DirectQuery;
} }
@ -250,7 +352,7 @@ namespace BismNormalizer.TabularCompare
filesToClose += $"\n- {projectItemToClose.ContainingProject.Name.Replace(".smproj", "")}\\{projectItemToClose.Name}"; filesToClose += $"\n- {projectItemToClose.ContainingProject.Name.Replace(".smproj", "")}\\{projectItemToClose.Name}";
} }
if (MessageBox.Show($"BISM Normalizer needs to close the following file(s) that are\nopen in Visual Studio. Do you want to continue?{filesToClose}", "BISM Normalizer", MessageBoxButtons.YesNo, MessageBoxIcon.Question) != DialogResult.Yes) if (MessageBox.Show($"{_appName} needs to close the following file(s) that are\nopen in Visual Studio. Do you want to continue?{filesToClose}", _appName, MessageBoxButtons.YesNo, MessageBoxIcon.Question) != DialogResult.Yes)
{ {
userCancelled = true; userCancelled = true;
} }

View File

@ -24,6 +24,7 @@ namespace BismNormalizer.TabularCompare
private string _projectName; private string _projectName;
private string _projectFile; private string _projectFile;
private int _compatibilityLevel; private int _compatibilityLevel;
private string _dataSourceVersion;
private bool _directQuery; private bool _directQuery;
private string _bimFileFullName; private string _bimFileFullName;
private EnvDTE.Project _project; private EnvDTE.Project _project;
@ -34,11 +35,11 @@ namespace BismNormalizer.TabularCompare
private bool _credsProvided = false; private bool _credsProvided = false;
private string _username; private string _username;
private string _password; private string _password;
private bool _workspaceServerProvided = false;
private string _workspaceServer;
#endregion #endregion
#region Properties
/// <summary> /// <summary>
/// Initializes a new instance of the ConnectionInfo class. /// Initializes a new instance of the ConnectionInfo class.
/// </summary> /// </summary>
@ -92,11 +93,17 @@ namespace BismNormalizer.TabularCompare
} }
/// <summary> /// <summary>
/// The SSAS compatibility level for the connection. /// Compatibility level for the connection.
/// </summary> /// </summary>
[XmlIgnore()] [XmlIgnore()]
public int CompatibilityLevel => _compatibilityLevel; public int CompatibilityLevel => _compatibilityLevel;
/// <summary>
/// Default data source version for the connection.
/// </summary>
[XmlIgnore()]
public string DataSourceVersion => _dataSourceVersion;
/// <summary> /// <summary>
/// A Boolean specifying whether the tabular model for the connection is running in DirectQuery mode. /// A Boolean specifying whether the tabular model for the connection is running in DirectQuery mode.
/// </summary> /// </summary>
@ -167,7 +174,25 @@ namespace BismNormalizer.TabularCompare
set { _password = value; } set { _password = value; }
} }
#endregion /// <summary>
/// Flag depending on whether workspace server was provided. Used for command line mode/automated build.
/// </summary>
[XmlIgnore()]
public bool WorkspaceServerProvided
{
get { return _workspaceServerProvided; }
set { _workspaceServerProvided = value; }
}
/// <summary>
/// Workspace server name for when WorkspaceServerProvided = true. Used for command line mode/automated build.
/// </summary>
[XmlIgnore()]
public string WorkspaceServer
{
get { return _workspaceServer; }
set { _workspaceServer = value; }
}
private void ReadSettingsFile() private void ReadSettingsFile()
{ {
@ -336,7 +361,7 @@ namespace BismNormalizer.TabularCompare
/// This method ensures the tabular model is online and populates the CompatibilityLevel property. /// This method ensures the tabular model is online and populates the CompatibilityLevel property.
/// </summary> /// </summary>
/// <param name="closedBimFile">A Boolean specifying if the user cancelled the comparison. For the case where running in Visual Studio, the user has the option of cancelling if the project BIM file is open.</param> /// <param name="closedBimFile">A Boolean specifying if the user cancelled the comparison. For the case where running in Visual Studio, the user has the option of cancelling if the project BIM file is open.</param>
public void InitializeCompatibilityLevel(bool closedBimFile = false, string workspaceServer = null) public void InitializeCompatibilityLevel(bool closedBimFile = false)
{ {
if (UseProject) if (UseProject)
{ {
@ -360,9 +385,9 @@ namespace BismNormalizer.TabularCompare
ReadProjectFile(); ReadProjectFile();
//Overwrite the server if a workspace server provided //Overwrite the server if a workspace server provided
if (!String.IsNullOrEmpty(workspaceServer)) if (_workspaceServerProvided)
{ {
this.ServerName = workspaceServer; this.ServerName = _workspaceServer;
} }
} }
@ -549,7 +574,8 @@ $@"{{
throw new ConnectionException($"Can not load/find database {this.DatabaseName}."); throw new ConnectionException($"Can not load/find database {this.DatabaseName}.");
} }
_compatibilityLevel = tabularDatabase.CompatibilityLevel; _compatibilityLevel = tabularDatabase.CompatibilityLevel;
_directQuery = ((tabularDatabase.Model != null && tabularDatabase.Model.DefaultMode == Microsoft.AnalysisServices.Tabular.ModeType.DirectQuery) || _dataSourceVersion = tabularDatabase.Model.DefaultPowerBIDataSourceVersion.ToString();
_directQuery = ((tabularDatabase.Model != null && tabularDatabase.Model.DefaultMode == Microsoft.AnalysisServices.Tabular.ModeType.DirectQuery) ||
tabularDatabase.DirectQueryMode == DirectQueryMode.DirectQuery || tabularDatabase.DirectQueryMode == DirectQueryMode.InMemoryWithDirectQuery || tabularDatabase.DirectQueryMode == DirectQueryMode.DirectQueryWithInMemory); tabularDatabase.DirectQueryMode == DirectQueryMode.DirectQuery || tabularDatabase.DirectQueryMode == DirectQueryMode.InMemoryWithDirectQuery || tabularDatabase.DirectQueryMode == DirectQueryMode.DirectQueryWithInMemory);
} }

View File

@ -237,7 +237,7 @@ namespace BismNormalizer.TabularCompare.Core
/// Generate Excel report of differences. /// Generate Excel report of differences.
/// </summary> /// </summary>
/// <param name="progBar"></param> /// <param name="progBar"></param>
public void ReportDifferences(ProgressBar progBar) public void ReportDifferences(ToolStripProgressBar progBar)
{ {
try try
{ {
@ -250,7 +250,7 @@ namespace BismNormalizer.TabularCompare.Core
//Wb.Sheets[1].Delete(); //Wb.Sheets[1].Delete();
Excel.Worksheet Ws = default(Excel.Worksheet); Excel.Worksheet Ws = default(Excel.Worksheet);
Ws = Wb.ActiveSheet; Ws = Wb.ActiveSheet;
Ws.Name = "Bism Normalizer Report"; Ws.Name = "Comparison Report";
int row = 1, lastDataSourceRow = -1, lastTableRow = -1; int row = 1, lastDataSourceRow = -1, lastTableRow = -1;
// set up headers // set up headers
@ -360,7 +360,7 @@ namespace BismNormalizer.TabularCompare.Core
} }
} }
private void PopulateExcelRow(Excel.Worksheet Ws, ref int row, ref int lastDataSourceRow, ref int lastTableRow, ComparisonObject comparisonObject, ProgressBar progBar) private void PopulateExcelRow(Excel.Worksheet Ws, ref int row, ref int lastDataSourceRow, ref int lastTableRow, ComparisonObject comparisonObject, ToolStripProgressBar progBar)
{ {
progBar.PerformStep(); progBar.PerformStep();
row += 1; row += 1;
@ -380,6 +380,9 @@ namespace BismNormalizer.TabularCompare.Core
//Type column //Type column
switch (comparisonObject.ComparisonObjectType) switch (comparisonObject.ComparisonObjectType)
{ {
case ComparisonObjectType.Model:
Ws.Cells[row, 1].Value = "Model";
break;
case ComparisonObjectType.DataSource: case ComparisonObjectType.DataSource:
Ws.Cells[row, 1].Value = "Data Source"; Ws.Cells[row, 1].Value = "Data Source";
break; break;
@ -404,6 +407,12 @@ namespace BismNormalizer.TabularCompare.Core
Ws.Cells[row, 2].InsertIndent(3); Ws.Cells[row, 2].InsertIndent(3);
Ws.Cells[row, 5].InsertIndent(3); Ws.Cells[row, 5].InsertIndent(3);
break; break;
case ComparisonObjectType.CalculationItem:
Ws.Cells[row, 1].Value = "Calculation Item";
Ws.Cells[row, 1].InsertIndent(3);
Ws.Cells[row, 2].InsertIndent(3);
Ws.Cells[row, 5].InsertIndent(3);
break;
case ComparisonObjectType.Perspective: case ComparisonObjectType.Perspective:
Ws.Cells[row, 1].Value = "Perspective"; Ws.Cells[row, 1].Value = "Perspective";
break; break;

View File

@ -4,7 +4,7 @@ namespace BismNormalizer.TabularCompare
/// <summary> /// <summary>
/// Type of object that a validation message relates to. For example, Table, Measure, MeasureCalculationDependency, etc. /// Type of object that a validation message relates to. For example, Table, Measure, MeasureCalculationDependency, etc.
/// </summary> /// </summary>
public enum ValidationMessageType { DataSource, Table, Relationship, Measure, Kpi, Perspective, Culture, Role, Expression, Action, MeasureCalculationDependency, General }; //General used for command line only public enum ValidationMessageType { Model, DataSource, Table, Relationship, Measure, Kpi, CalculationGroup, CalculationItem, Perspective, Culture, Role, Expression, Action, MeasureCalculationDependency, AggregationDependency, General }; //General used for command line only
/// <summary> /// <summary>
/// Status for a validation message, such as Informational and Warning. /// Status for a validation message, such as Informational and Warning.
@ -14,7 +14,7 @@ namespace BismNormalizer.TabularCompare
/// <summary> /// <summary>
/// Type of comparison object. For example, Table, Measure, Relationship, etc. /// Type of comparison object. For example, Table, Measure, Relationship, etc.
/// </summary> /// </summary>
public enum ComparisonObjectType { DataSource, Table, Relationship, Measure, Kpi, Perspective, Culture, Role, Expression, Action, Connection }; //Need connection for backwards compatibility when deserializing from xml. Set to data source. public enum ComparisonObjectType { Model, DataSource, Table, Relationship, Measure, Kpi, CalculationItem, Perspective, Culture, Role, Expression, Action, Connection }; //Need connection for backwards compatibility when deserializing from xml. Set to data source.
/// <summary> /// <summary>
/// Status of comparison object, such as Same Definition, Different Definitions and Missing In Target. /// Status of comparison object, such as Same Definition, Different Definitions and Missing In Target.
@ -40,4 +40,5 @@ namespace BismNormalizer.TabularCompare
/// Type of dependency. For example, DataSource, Partition, Expression. /// Type of dependency. For example, DataSource, Partition, Expression.
/// </summary> /// </summary>
public enum CalcDependencyObjectType { DataSource, Partition, Expression }; public enum CalcDependencyObjectType { DataSource, Partition, Expression };
} }

View File

@ -2712,7 +2712,7 @@ namespace BismNormalizer.TabularCompare.MultidimensionalMetadata
// Show row count for each table // Show row count for each table
foreach (ProcessingTable table in _tablesToProcess) foreach (ProcessingTable table in _tablesToProcess)
{ {
int rowCount = _connectionInfo.DirectQuery ? 0 : Core.Comparison.FindRowCount(_amoServer, table.Name, _amoDatabase.Name); int rowCount = Core.Comparison.FindRowCount(_amoServer, table.Name, _amoDatabase.Name);
_parentComparison.OnDeploymentMessage(new DeploymentMessageEventArgs(table.Name, "Success. " + String.Format("{0:#,###0}", rowCount) + " rows transferred.", DeploymentStatus.Success)); _parentComparison.OnDeploymentMessage(new DeploymentMessageEventArgs(table.Name, "Success. " + String.Format("{0:#,###0}", rowCount) + " rows transferred.", DeploymentStatus.Success));
} }
_parentComparison.OnDeploymentComplete(new DeploymentCompleteEventArgs(DeploymentStatus.Success, null)); _parentComparison.OnDeploymentComplete(new DeploymentCompleteEventArgs(DeploymentStatus.Success, null));
@ -2779,7 +2779,7 @@ namespace BismNormalizer.TabularCompare.MultidimensionalMetadata
PartitionRowCounter partition = table.FindPartition(partitionIdNodeList[0].InnerText); PartitionRowCounter partition = table.FindPartition(partitionIdNodeList[0].InnerText);
partition.RowCount = e.IntegerData; partition.RowCount = e.IntegerData;
_parentComparison.OnDeploymentMessage(new DeploymentMessageEventArgs(table.Name, "Retreived " + String.Format("{0:#,###0}", table.GetRowCount()) + " rows ...", DeploymentStatus.Deploying)); _parentComparison.OnDeploymentMessage(new DeploymentMessageEventArgs(table.Name, "Retrieved " + String.Format("{0:#,###0}", table.GetRowCount()) + " rows ...", DeploymentStatus.Deploying));
} }
} }

View File

@ -20,6 +20,8 @@ namespace BismNormalizer.TabularCompare
private bool _optionActions; private bool _optionActions;
private bool _optionPartitions; private bool _optionPartitions;
private bool _optionRetainPartitions; private bool _optionRetainPartitions;
private bool _optionRetainPolicyPartitions;
private bool _optionRetainStorageMode;
private bool _optionMeasureDependencies; private bool _optionMeasureDependencies;
private ProcessingOption _optionProcessingOption; private ProcessingOption _optionProcessingOption;
private bool _optionTransaction; private bool _optionTransaction;
@ -38,6 +40,8 @@ namespace BismNormalizer.TabularCompare
_optionActions = Settings.Default.OptionActions; _optionActions = Settings.Default.OptionActions;
_optionPartitions = Settings.Default.OptionPartitions; _optionPartitions = Settings.Default.OptionPartitions;
_optionRetainPartitions = Settings.Default.OptionRetainPartitions; _optionRetainPartitions = Settings.Default.OptionRetainPartitions;
_optionRetainPolicyPartitions = Settings.Default.OptionRetainPolicyPartitions;
_optionRetainStorageMode = Settings.Default.OptionRetainStorageMode;
_optionMeasureDependencies = Settings.Default.OptionMeasureDependencies; _optionMeasureDependencies = Settings.Default.OptionMeasureDependencies;
_optionProcessingOption = (ProcessingOption)Enum.Parse(typeof(ProcessingOption), Settings.Default.OptionProcessingOption); _optionProcessingOption = (ProcessingOption)Enum.Parse(typeof(ProcessingOption), Settings.Default.OptionProcessingOption);
_optionTransaction = Settings.Default.OptionTransaction; _optionTransaction = Settings.Default.OptionTransaction;
@ -117,6 +121,24 @@ namespace BismNormalizer.TabularCompare
set { _optionRetainPartitions = value; } set { _optionRetainPartitions = value; }
} }
/// <summary>
/// A Boolean specifying whether to retain refresh-policy partitions for table updates.
/// </summary>
public bool OptionRetainPolicyPartitions
{
get { return _optionRetainPolicyPartitions; }
set { _optionRetainPolicyPartitions = value; }
}
/// <summary>
/// A Boolean specifying whether to retain storage for table updates on composite models.
/// </summary>
public bool OptionRetainStorageMode
{
get { return _optionRetainStorageMode; }
set { _optionRetainStorageMode = value; }
}
/// <summary> /// <summary>
/// A Boolean specifying whether to display warnings for missing measure dependencies. /// A Boolean specifying whether to display warnings for missing measure dependencies.
/// </summary> /// </summary>
@ -168,6 +190,8 @@ namespace BismNormalizer.TabularCompare
Settings.Default.OptionActions = _optionActions; Settings.Default.OptionActions = _optionActions;
Settings.Default.OptionPartitions = _optionPartitions; Settings.Default.OptionPartitions = _optionPartitions;
Settings.Default.OptionRetainPartitions = _optionRetainPartitions; Settings.Default.OptionRetainPartitions = _optionRetainPartitions;
Settings.Default.OptionRetainPolicyPartitions = _optionRetainPolicyPartitions;
Settings.Default.OptionRetainStorageMode = _optionRetainStorageMode;
Settings.Default.OptionMeasureDependencies = _optionMeasureDependencies; Settings.Default.OptionMeasureDependencies = _optionMeasureDependencies;
Settings.Default.OptionProcessingOption = _optionProcessingOption.ToString(); Settings.Default.OptionProcessingOption = _optionProcessingOption.ToString();
Settings.Default.OptionTransaction = _optionTransaction; Settings.Default.OptionTransaction = _optionTransaction;

View File

@ -0,0 +1,116 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Globalization;
using Microsoft.AnalysisServices.Tabular;
using Tom=Microsoft.AnalysisServices.Tabular;
namespace BismNormalizer.TabularCompare.TabularMetadata
{
/// <summary>
/// Abstraction of a tabular model calculationItem with properties and methods for comparison purposes.
/// </summary>
public class CalculationItem : TabularObject
{
private Table _parentTable;
private Tom.CalculationItem _tomCalculationItem;
/// <summary>
/// Initializes a new instance of the CalculationItem class using multiple parameters.
/// </summary>
/// <param name="parentTable">Table object that the calculationItem belongs to.</param>
/// <param name="tomCalculationItem">Tabular Object Model CalculationItem object abtstracted by the CalculationItem class.</param>
/// <param name="isKpi">Indicates whether the calculationItem is a KPI.</param>
public CalculationItem(Table parentTable, Tom.CalculationItem tomCalculationItem) : base(tomCalculationItem)
{
_parentTable = parentTable;
_tomCalculationItem = tomCalculationItem;
}
/// <summary>
/// Table object that the Relationship oject belongs to.
/// </summary>
public Table ParentTable => _parentTable;
/// <summary>
/// Tabular Object Model CalculationItem object abtstracted by the CalculationItem class.
/// </summary>
public Tom.CalculationItem TomCalculationItem => _tomCalculationItem;
/// <summary>
/// Name of the table that the CalculationItem oject belongs to.
/// </summary>
public string TableName => _tomCalculationItem.CalculationGroup.Table.Name;
public override string ToString() => this.GetType().FullName;
/// <summary>
/// Find missing calculation dependencies by inspecting the DAX expression for the calculationItem and iterating columns and other calculationItems in the tabular model for validity of the expression.
/// </summary>
/// <returns>List of missing dependencies to be displayed or logged as warnings.</returns>
public List<string> FindMissingCalculationItemDependencies()
{
List<string> dependencies = new List<string>();
using (StringReader lines = new StringReader(_tomCalculationItem.Expression))
{
string line = string.Empty;
while ((line = lines.ReadLine()) != null)
{
if (line.TrimStart().Length > 1 && line.TrimStart().Substring(0, 2) != "--") //Ignore comments
{
//Todo2: still need to parse for /* blah */ type comments. Currently can show missing dependency that doesn't apply if within a comment
string whatsRemainingOfLine = line;
while (whatsRemainingOfLine.Contains('[') && whatsRemainingOfLine.Contains(']'))
{
int openSquareBracketPosition = whatsRemainingOfLine.IndexOf('[', 0);
//brilliant person at microsoft has ]] instead of ]
int closeSquareBracketPosition = whatsRemainingOfLine.Replace("]]", " ").IndexOf(']', openSquareBracketPosition + 1);
if (openSquareBracketPosition < closeSquareBracketPosition - 1)
{
string potentialDependency = whatsRemainingOfLine.Substring(openSquareBracketPosition + 1, closeSquareBracketPosition - openSquareBracketPosition - 1);
if (!potentialDependency.Contains('"') &&
!_tomCalculationItem.Expression.Contains($"\"{potentialDependency}\"") && //it's possible the calculationItem itself is deriving the column name from an ADDCOLUMNS for example
!dependencies.Contains(potentialDependency))
{
//unbelievable: some genius at m$ did a replace on ] with ]]
dependencies.Add(potentialDependency);
}
}
whatsRemainingOfLine = whatsRemainingOfLine.Substring(closeSquareBracketPosition + 1);
}
}
}
}
List<string> missingDependencies = new List<string>();
foreach (string dependency in dependencies)
{
bool foundDependency = false;
foreach (Table table in _parentTable.ParentTabularModel.Tables)
{
//Check if another calculationItem or column has same name
if (table.CalculationItems.ContainsNameCaseInsensitive(dependency) || table.ColumnsContainsNameCaseInsensitive(dependency))
{
foundDependency = true;
break;
}
}
if (!foundDependency)
{
missingDependencies.Add(dependency);
}
}
return missingDependencies;
}
}
}

View File

@ -0,0 +1,98 @@
using System;
using System.Collections.Generic;
namespace BismNormalizer.TabularCompare.TabularMetadata
{
/// <summary>
/// Represents a collection of CalculationItem objects.
/// </summary>
public class CalculationItemCollection : List<CalculationItem>
{
/// <summary>
/// Find an object in the collection by name.
/// </summary>
/// <param name="name"></param>
/// <returns>CalculationItem object if found. Null if not found.</returns>
public CalculationItem FindByName(string name)
{
foreach (CalculationItem calculationItem in this)
{
if (calculationItem.Name == name)
{
return calculationItem;
}
}
return null;
}
/// <summary>
/// A Boolean specifying whether the collection contains object by name.
/// </summary>
/// <param name="name"></param>
/// <returns>True if the object is found, or False if it's not found.</returns>
public bool ContainsName(string name)
{
foreach (CalculationItem calculationItem in this)
{
if (calculationItem.Name == name)
{
return true;
}
}
return false;
}
/// <summary>
/// A Boolean specifying whether the collection contains object by name searching without case sensitivity.
/// </summary>
/// <param name="name"></param>
/// <returns>True if the object is found, or False if it's not found.</returns>
public bool ContainsNameCaseInsensitive(string name)
{
foreach (CalculationItem calculationItem in this)
{
if (calculationItem.Name.ToUpper() == name.ToUpper())
{
return true;
}
}
return false;
}
/// <summary>
/// Returns a collection of CalculationItem objects filtered by the parent table's name.
/// </summary>
/// <param name="tableName"></param>
/// <returns>CalculationItemCollection</returns>
public CalculationItemCollection FilterByTableName(string tableName)
{
CalculationItemCollection returnCalculationItems = new CalculationItemCollection();
foreach (CalculationItem calculationItem in this)
{
if (calculationItem.TableName == tableName)
{
returnCalculationItems.Add(calculationItem);
}
}
return returnCalculationItems;
}
/// <summary>
/// Removes an object from the collection by its name.
/// </summary>
/// <param name="name"></param>
/// <returns>True if the object was removed, or False if was not found.</returns>
public bool RemoveByName(string name)
{
foreach (CalculationItem calculationItem in this)
{
if (calculationItem.Name == name)
{
this.Remove(calculationItem);
return true;
}
}
return false;
}
}
}

View File

@ -72,6 +72,29 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
{ {
_comparisonObjectCount = 0; _comparisonObjectCount = 0;
#region Model
if (_comparisonInfo.TargetCompatibilityLevel >= 1460) //Target compat level is always >= source one.
{
// check if Model object definition is different
ComparisonObject comparisonObjectModel;
if (_sourceTabularModel.Model.ObjectDefinition != _targetTabularModel.Model.ObjectDefinition)
{
comparisonObjectModel = new ComparisonObject(ComparisonObjectType.Model, ComparisonObjectStatus.DifferentDefinitions, _sourceTabularModel.Model, _targetTabularModel.Model, MergeAction.Update);
_comparisonObjects.Add(comparisonObjectModel);
_comparisonObjectCount += 1;
}
else
{
// they are equal, ...
comparisonObjectModel = new ComparisonObject(ComparisonObjectType.Model, ComparisonObjectStatus.SameDefinition, _sourceTabularModel.Model, _targetTabularModel.Model, MergeAction.Skip);
_comparisonObjects.Add(comparisonObjectModel);
_comparisonObjectCount += 1;
}
}
#endregion
#region DataSources #region DataSources
foreach (DataSource dataSourceSource in _sourceTabularModel.DataSources) foreach (DataSource dataSourceSource in _sourceTabularModel.DataSources)
@ -155,6 +178,18 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
} }
#endregion #endregion
#region CalculationItems for Table that is Missing in Target
foreach (CalculationItem calculationItemSource in tblSource.CalculationItems.FilterByTableName(tblSource.Name))
{
ComparisonObjectType comparisonObjectType = ComparisonObjectType.CalculationItem;
ComparisonObject comparisonObjectCalculationItem = new ComparisonObject(comparisonObjectType, ComparisonObjectStatus.MissingInTarget, calculationItemSource, null, MergeAction.Create);
comparisonObjectTable.ChildComparisonObjects.Add(comparisonObjectCalculationItem);
_comparisonObjectCount += 1;
}
#endregion
} }
else else
{ {
@ -269,6 +304,53 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
} }
#endregion #endregion
#region CalculationItems (table in source and target)
// see if matching calculationItem in source and target
foreach (CalculationItem calculationItemSource in tblSource.CalculationItems.FilterByTableName(tblSource.Name))
{
ComparisonObjectType comparisonObjectType = ComparisonObjectType.CalculationItem;
if (tblTarget.CalculationItems.FilterByTableName(tblTarget.Name).ContainsName(calculationItemSource.Name))
{
//CalculationItem in source and target, so check definition
CalculationItem calculationItemTarget = tblTarget.CalculationItems.FilterByTableName(tblTarget.Name).FindByName(calculationItemSource.Name);
if (calculationItemSource.ObjectDefinition == calculationItemTarget.ObjectDefinition)
{
//CalculationItem has same definition
ComparisonObject comparisonObjectCalculationItem = new ComparisonObject(comparisonObjectType, ComparisonObjectStatus.SameDefinition, calculationItemSource, calculationItemTarget, MergeAction.Skip);
comparisonObjectTable.ChildComparisonObjects.Add(comparisonObjectCalculationItem);
_comparisonObjectCount += 1;
}
else
{
//CalculationItem has different definition
ComparisonObject comparisonObjectCalculationItem = new ComparisonObject(comparisonObjectType, ComparisonObjectStatus.DifferentDefinitions, calculationItemSource, calculationItemTarget, MergeAction.Update);
comparisonObjectTable.ChildComparisonObjects.Add(comparisonObjectCalculationItem);
_comparisonObjectCount += 1;
}
}
else
{
ComparisonObject comparisonObjectCalculationItem = new ComparisonObject(comparisonObjectType, ComparisonObjectStatus.MissingInTarget, calculationItemSource, null, MergeAction.Create);
comparisonObjectTable.ChildComparisonObjects.Add(comparisonObjectCalculationItem);
_comparisonObjectCount += 1;
}
}
//now check if target contains calculationItems Missing in Source
foreach (CalculationItem calculationItemTarget in tblTarget.CalculationItems.FilterByTableName(tblTarget.Name))
{
ComparisonObjectType comparisonObjectType = ComparisonObjectType.CalculationItem;
if (!tblSource.CalculationItems.FilterByTableName(tblSource.Name).ContainsName(calculationItemTarget.Name))
{
ComparisonObject comparisonObjectCalculationItem = new ComparisonObject(comparisonObjectType, ComparisonObjectStatus.MissingInSource, null, calculationItemTarget, MergeAction.Delete);
comparisonObjectTable.ChildComparisonObjects.Add(comparisonObjectCalculationItem);
_comparisonObjectCount += 1;
}
}
#endregion
} }
} }
@ -298,12 +380,24 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
foreach (Measure measureTarget in tblTarget.Measures.FilterByTableName(tblTarget.Name)) foreach (Measure measureTarget in tblTarget.Measures.FilterByTableName(tblTarget.Name))
{ {
ComparisonObjectType comparisonObjectType = measureTarget.IsKpi ? ComparisonObjectType.Kpi : ComparisonObjectType.Measure; ComparisonObjectType comparisonObjectType = measureTarget.IsKpi ? ComparisonObjectType.Kpi : ComparisonObjectType.Measure;
ComparisonObject comparisonObjectMeasure = new ComparisonObject(ComparisonObjectType.Measure, ComparisonObjectStatus.MissingInSource, null, measureTarget, MergeAction.Delete); ComparisonObject comparisonObjectMeasure = new ComparisonObject(comparisonObjectType, ComparisonObjectStatus.MissingInSource, null, measureTarget, MergeAction.Delete);
comparisonObjectTable.ChildComparisonObjects.Add(comparisonObjectMeasure); comparisonObjectTable.ChildComparisonObjects.Add(comparisonObjectMeasure);
_comparisonObjectCount += 1; _comparisonObjectCount += 1;
} }
#endregion #endregion
#region CalculationItems for Table that is Missing in Source
foreach (CalculationItem calculationItemTarget in tblTarget.CalculationItems.FilterByTableName(tblTarget.Name))
{
ComparisonObjectType comparisonObjectType = ComparisonObjectType.CalculationItem;
ComparisonObject comparisonObjectCalculationItem = new ComparisonObject(comparisonObjectType, ComparisonObjectStatus.MissingInSource, null, calculationItemTarget, MergeAction.Delete);
comparisonObjectTable.ChildComparisonObjects.Add(comparisonObjectCalculationItem);
_comparisonObjectCount += 1;
}
#endregion
} }
} }
@ -538,7 +632,18 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
{ {
#region Refresh/reconnect source and target dbs to check if server definition has changed #region Refresh/reconnect source and target dbs to check if server definition has changed
if (_uncommitedChanges) bool reconnect = false;
try
{
_sourceTabularModel.TomDatabase.Refresh();
_targetTabularModel.TomDatabase.Refresh();
}
catch (Exception)
{
reconnect = true;
}
if (reconnect || _uncommitedChanges)
{ {
// Reconnect to re-initialize // Reconnect to re-initialize
_sourceTabularModel = new TabularModel(this, _comparisonInfo.ConnectionInfoSource, _comparisonInfo); _sourceTabularModel = new TabularModel(this, _comparisonInfo.ConnectionInfoSource, _comparisonInfo);
@ -546,11 +651,6 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
_targetTabularModel = new TabularModel(this, _comparisonInfo.ConnectionInfoTarget, _comparisonInfo); _targetTabularModel = new TabularModel(this, _comparisonInfo.ConnectionInfoTarget, _comparisonInfo);
_targetTabularModel.Connect(); _targetTabularModel.Connect();
} }
else
{
_sourceTabularModel.TomDatabase.Refresh();
_targetTabularModel.TomDatabase.Refresh();
}
if (!_sourceTabularModel.ConnectionInfo.UseProject && _sourceTabularModel.TomDatabase.LastSchemaUpdate > _lastSourceSchemaUpdate) if (!_sourceTabularModel.ConnectionInfo.UseProject && _sourceTabularModel.TomDatabase.LastSchemaUpdate > _lastSourceSchemaUpdate)
{ {
@ -614,6 +714,17 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
#endregion #endregion
#region Model1
//Doing before tables in case need to set DiscourageImplicitMeasures=true to create calc groups downstream
bool updatedModel = false;
foreach (ComparisonObject comparisonObject in _comparisonObjects)
{
updatedModel = UpdateModel(comparisonObject, true);
}
#endregion
#region Tables #region Tables
// do deletions first to minimize chance of conflict // do deletions first to minimize chance of conflict
@ -663,6 +774,19 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
#endregion #endregion
_targetTabularModel.CleanUpVariations(); _targetTabularModel.CleanUpVariations();
#region Model2
//Doing model after tables in case there are calc group tables created so cannot set DisableImplictMeasures=false
if (!updatedModel)
{
foreach (ComparisonObject comparisonObject in _comparisonObjects)
{
UpdateModel(comparisonObject, false);
}
}
#endregion
#region Measures / KPIs #region Measures / KPIs
@ -692,6 +816,34 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
#endregion #endregion
#region CalculationItems
foreach (ComparisonObject comparisonObject in _comparisonObjects)
{
foreach (ComparisonObject childComparisonObject in comparisonObject.ChildComparisonObjects)
{
DeleteCalculationItem(childComparisonObject); //CalculationItem
}
}
foreach (ComparisonObject comparisonObject in _comparisonObjects)
{
foreach (ComparisonObject childComparisonObject in comparisonObject.ChildComparisonObjects)
{
CreateCalculationItem(childComparisonObject, comparisonObject.SourceObjectName); //CalculationItem, Table
}
}
foreach (ComparisonObject comparisonObject in _comparisonObjects)
{
foreach (ComparisonObject childComparisonObject in comparisonObject.ChildComparisonObjects)
{
UpdateCalculationItem(childComparisonObject, comparisonObject.SourceObjectName); //CalculationItem, Table
}
}
#endregion
#region Perspectives #region Perspectives
//Restore perspectives that were backed up earlier. Having done this there won't be any dependency issues, so can start comparison changes. //Restore perspectives that were backed up earlier. Having done this there won't be any dependency issues, so can start comparison changes.
@ -759,6 +911,8 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
#endregion #endregion
_targetTabularModel.CleanUpAggregations();
#region Cultures #region Cultures
//Restore cultures that were backed up earlier. Having done this there won't be any dependency issues, so can start comparison changes. //Restore cultures that were backed up earlier. Having done this there won't be any dependency issues, so can start comparison changes.
@ -1026,7 +1180,56 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
#endregion #endregion
//DataSources #region Model
private bool UpdateModel(ComparisonObject comparisonObject, bool beforeTables)
{
if (comparisonObject.ComparisonObjectType == ComparisonObjectType.Model && comparisonObject.MergeAction == MergeAction.Update)
{
Model sourceModel = _sourceTabularModel.Model;
Model targetModel = _targetTabularModel.Model;
bool targetHasCalcGroups = false;
foreach (Table table in _targetTabularModel.Tables)
{
if (table.IsCalculationGroup)
{
targetHasCalcGroups = true;
break;
}
}
if (beforeTables)
{
//In this case, may need to create calc groups downstream, so may need to set DiscourageImplicitMeasures to true
if (!targetHasCalcGroups && sourceModel.TomModel.DiscourageImplicitMeasures)
{
_targetTabularModel.UpdateModel(sourceModel, targetModel);
OnValidationMessage(new ValidationMessageEventArgs($"Update model.", ValidationMessageType.Model, ValidationMessageStatus.Informational));
return true;
}
}
else
{
//In this case, have already had chance to create/delete calc groups, so OK to disable implicit measures if able
if (targetHasCalcGroups && sourceModel.TomModel.DiscourageImplicitMeasures == false)
{
OnValidationMessage(new ValidationMessageEventArgs($"Unable to update model because (considering changes) the target has calculation group(s) and the source has DiscourageImplicitMeasures set to false.", ValidationMessageType.Model, ValidationMessageStatus.Warning));
}
else
{
_targetTabularModel.UpdateModel(sourceModel, targetModel);
OnValidationMessage(new ValidationMessageEventArgs($"Update model.", ValidationMessageType.Model, ValidationMessageStatus.Informational));
return true;
}
}
}
return false;
}
#endregion
#region DataSources
private void DeleteDataSource(ComparisonObject comparisonObject) private void DeleteDataSource(ComparisonObject comparisonObject)
{ {
@ -1118,7 +1321,9 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
} }
} }
//Expressions #endregion
#region Expressions
private void DeleteExpression(ComparisonObject comparisonObject) private void DeleteExpression(ComparisonObject comparisonObject)
{ {
@ -1134,7 +1339,7 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
else else
{ {
string message = $"Unable to delete expression {comparisonObject.TargetObjectName} because the following objects depend on it: {String.Join(", ", warningObjectList)}."; string message = $"Unable to delete expression {comparisonObject.TargetObjectName} because the following objects depend on it: {String.Join(", ", warningObjectList)}.";
if (_comparisonInfo.OptionsInfo.OptionRetainPartitions) if (_comparisonInfo.OptionsInfo.OptionRetainPartitions && !_comparisonInfo.OptionsInfo.OptionRetainPolicyPartitions)
{ {
message += " Note: the option to retain partitions is on, which may be affecting this."; message += " Note: the option to retain partitions is on, which may be affecting this.";
} }
@ -1203,14 +1408,19 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
} }
} }
//Tables #endregion
#region Tables
private void DeleteTable(ComparisonObject comparisonObject) private void DeleteTable(ComparisonObject comparisonObject)
{ {
if (comparisonObject.ComparisonObjectType == ComparisonObjectType.Table && comparisonObject.MergeAction == MergeAction.Delete) if (comparisonObject.ComparisonObjectType == ComparisonObjectType.Table && comparisonObject.MergeAction == MergeAction.Delete)
{ {
Table targetTable = _targetTabularModel.Tables.FindByName(comparisonObject.TargetObjectName);
bool isCalculationGroup = false;
if (targetTable != null) isCalculationGroup = targetTable.IsCalculationGroup;
_targetTabularModel.DeleteTable(comparisonObject.TargetObjectName); _targetTabularModel.DeleteTable(comparisonObject.TargetObjectName);
OnValidationMessage(new ValidationMessageEventArgs($"Delete table '{comparisonObject.TargetObjectName}'.", ValidationMessageType.Table, ValidationMessageStatus.Informational)); OnValidationMessage(new ValidationMessageEventArgs($"Delete {(isCalculationGroup ? "calculation group" : "table")} '{comparisonObject.TargetObjectName}'.", ValidationMessageType.Table, ValidationMessageStatus.Informational));
} }
} }
@ -1223,25 +1433,43 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
bool fromDependencies = false; bool fromDependencies = false;
bool nonStructuredDataSourceLocal = false; bool nonStructuredDataSourceLocal = false;
foreach (Partition partition in sourceTable.TomTable.Partitions) if (!sourceTable.IsCalculationGroup)
{ {
//Check any objects in source that this partition depends on are also going to be created if not already in target foreach (Partition partition in sourceTable.TomTable.Partitions)
if (HasBlockingFromDependenciesInSource(sourceTable.Name, partition.Name, CalcDependencyObjectType.Partition, ref warningObjectList, out bool nonStructuredDataSource))
{ {
fromDependencies = true; //Check any objects in source that this partition depends on are also going to be created if not already in target
if (nonStructuredDataSource) if (HasBlockingFromDependenciesInSource(sourceTable.Name, partition.Name, CalcDependencyObjectType.Partition, ref warningObjectList, out bool nonStructuredDataSource))
nonStructuredDataSourceLocal = true; {
} fromDependencies = true;
if (nonStructuredDataSource)
nonStructuredDataSourceLocal = true;
}
//For old non-M partitions, check if data source references exist //For old non-M partitions, check if data source references exist
if (HasBlockingOldPartitionDependency(partition, ref warningObjectList)) if (HasBlockingOldPartitionDependency(partition, ref warningObjectList))
fromDependencies = true; //Need if clause in case last of n partitions has no dependencies and sets back to true fromDependencies = true; //Need if clause in case last of n partitions has no dependencies and sets back to true
}
} }
if (!fromDependencies) if (!fromDependencies)
{ {
_targetTabularModel.CreateTable(sourceTable); if (sourceTable.IsCalculationGroup)
OnValidationMessage(new ValidationMessageEventArgs($"Create table '{comparisonObject.SourceObjectName}'.", ValidationMessageType.Table, ValidationMessageStatus.Informational)); {
if (_targetTabularModel.Model.TomModel.DiscourageImplicitMeasures != true)
{
OnValidationMessage(new ValidationMessageEventArgs($"Unable to create calculation group {comparisonObject.SourceObjectName} because the target model doesn't have DiscourageImplicitMeasures set to true.", ValidationMessageType.Table, ValidationMessageStatus.Warning));
}
else
{
_targetTabularModel.CreateTable(sourceTable);
OnValidationMessage(new ValidationMessageEventArgs($"Create calculation group '{comparisonObject.SourceObjectName}'.", ValidationMessageType.Table, ValidationMessageStatus.Informational));
}
}
else
{
_targetTabularModel.CreateTable(sourceTable);
OnValidationMessage(new ValidationMessageEventArgs($"Create table '{comparisonObject.SourceObjectName}'.", ValidationMessageType.Table, ValidationMessageStatus.Informational));
}
} }
else else
{ {
@ -1288,8 +1516,15 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
if (!fromDependencies) if (!fromDependencies)
{ {
_targetTabularModel.UpdateTable(tableSource, tableTarget, out string retainPartitionsMessage); if (tableSource.IsCalculationGroup != tableTarget.IsCalculationGroup)
OnValidationMessage(new ValidationMessageEventArgs($"Update table '{comparisonObject.TargetObjectName}'. {retainPartitionsMessage}", ValidationMessageType.Table, ValidationMessageStatus.Informational)); {
OnValidationMessage(new ValidationMessageEventArgs($"Unable to update table {comparisonObject.TargetObjectName} because either source or target is a calculation group (but not both).", (tableSource.IsCalculationGroup ? ValidationMessageType.CalculationGroup : ValidationMessageType.Table), ValidationMessageStatus.Warning));
}
else
{
_targetTabularModel.UpdateTable(tableSource, tableTarget, out string retainPartitionsMessage);
OnValidationMessage(new ValidationMessageEventArgs($"Update {(tableSource.IsCalculationGroup ? "calculation group" : "table")} '{comparisonObject.TargetObjectName}'. {retainPartitionsMessage}", ValidationMessageType.Table, ValidationMessageStatus.Informational));
}
} }
else else
{ {
@ -1305,7 +1540,9 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
} }
} }
//Relationships #endregion
#region Relationships
private void DeleteRelationship(ComparisonObject comparisonObject) private void DeleteRelationship(ComparisonObject comparisonObject)
{ {
@ -1369,7 +1606,9 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
} }
} }
//Measures / KPIs #endregion
#region Measures / KPIs
private void DeleteMeasure(ComparisonObject comparisonObject) private void DeleteMeasure(ComparisonObject comparisonObject)
{ {
@ -1440,6 +1679,84 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
#endregion #endregion
#region CalculationItems
private void DeleteCalculationItem(ComparisonObject comparisonObject)
{
if ((comparisonObject.ComparisonObjectType == ComparisonObjectType.CalculationItem || comparisonObject.ComparisonObjectType == ComparisonObjectType.Kpi) &&
comparisonObject.MergeAction == MergeAction.Delete)
{
foreach (Table tableTarget in _targetTabularModel.Tables)
{
CalculationItem calculationItemTarget = tableTarget.CalculationItems.FindByName(comparisonObject.TargetObjectInternalName);
if (calculationItemTarget != null)
{
// CalculationItem may have already been deleted if parent table was deleted
tableTarget.DeleteCalculationItem(comparisonObject.TargetObjectInternalName);
break;
}
}
OnValidationMessage(new ValidationMessageEventArgs($"Delete calculation item {comparisonObject.TargetObjectInternalName}.", ValidationMessageType.CalculationItem, ValidationMessageStatus.Informational));
}
}
private void CreateCalculationItem(ComparisonObject comparisonObject, string tableName)
{
if ((comparisonObject.ComparisonObjectType == ComparisonObjectType.CalculationItem || comparisonObject.ComparisonObjectType == ComparisonObjectType.Kpi) &&
comparisonObject.MergeAction == MergeAction.Create)
{
foreach (Table tableInTarget in _targetTabularModel.Tables)
{
CalculationItem calculationItemInTarget = tableInTarget.CalculationItems.FindByName(comparisonObject.SourceObjectInternalName);
if (calculationItemInTarget != null)
{
OnValidationMessage(new ValidationMessageEventArgs($"Unable to create calculation item {comparisonObject.SourceObjectInternalName} because name already exists in target model.", ValidationMessageType.CalculationItem, ValidationMessageStatus.Warning));
return;
}
}
Table tableSource = _sourceTabularModel.Tables.FindByName(tableName);
Table tableTarget = _targetTabularModel.Tables.FindByName(tableName);
if (tableTarget == null)
{
OnValidationMessage(new ValidationMessageEventArgs($"Unable to create calculation item {comparisonObject.SourceObjectInternalName} because (considering changes) target table {tableName} does not exist.", ValidationMessageType.CalculationItem, ValidationMessageStatus.Warning));
return;
}
else if (!tableTarget.IsCalculationGroup)
{
OnValidationMessage(new ValidationMessageEventArgs($"Unable to create calculation item {comparisonObject.SourceObjectInternalName} because the target table {tableName} is not a calculation group table.", ValidationMessageType.CalculationItem, ValidationMessageStatus.Warning));
return;
}
//If we get here, can create calculationItem/kpi
CalculationItem calculationItemSource = tableSource.CalculationItems.FindByName(comparisonObject.SourceObjectInternalName);
tableTarget.CreateCalculationItem(calculationItemSource.TomCalculationItem);
OnValidationMessage(new ValidationMessageEventArgs($"Create calculation item {comparisonObject.SourceObjectInternalName}.", ValidationMessageType.CalculationItem, ValidationMessageStatus.Informational));
}
}
private void UpdateCalculationItem(ComparisonObject comparisonObject, string tableName)
{
if ((comparisonObject.ComparisonObjectType == ComparisonObjectType.CalculationItem || comparisonObject.ComparisonObjectType == ComparisonObjectType.Kpi) &&
comparisonObject.MergeAction == MergeAction.Update)
{
Table tableSource = _sourceTabularModel.Tables.FindByName(tableName);
Table tableTarget = _targetTabularModel.Tables.FindByName(tableName);
CalculationItem calculationItemSource = tableSource.CalculationItems.FindByName(comparisonObject.SourceObjectInternalName);
tableTarget.UpdateCalculationItem(calculationItemSource.TomCalculationItem);
OnValidationMessage(new ValidationMessageEventArgs($"Update calculation item {comparisonObject.SourceObjectInternalName}.", ValidationMessageType.CalculationItem, ValidationMessageStatus.Informational));
}
}
#endregion
#endregion
/// <summary> /// <summary>
/// Update target tabular model with changes defined by actions in ComparisonObject instances. /// Update target tabular model with changes defined by actions in ComparisonObject instances.
/// </summary> /// </summary>

View File

@ -44,7 +44,7 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
} }
else else
{ {
if (_comparisonObjectType == ComparisonObjectType.Relationship || _comparisonObjectType == ComparisonObjectType.Measure || _comparisonObjectType == ComparisonObjectType.Kpi) if (_comparisonObjectType == ComparisonObjectType.Relationship || _comparisonObjectType == ComparisonObjectType.Measure || _comparisonObjectType == ComparisonObjectType.Kpi || _comparisonObjectType == ComparisonObjectType.CalculationItem)
{ {
return " " + _sourceObject.Name; return " " + _sourceObject.Name;
} }
@ -114,7 +114,7 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
} }
else else
{ {
if (_comparisonObjectType == ComparisonObjectType.Relationship || _comparisonObjectType == ComparisonObjectType.Measure || _comparisonObjectType == ComparisonObjectType.Kpi) if (_comparisonObjectType == ComparisonObjectType.Relationship || _comparisonObjectType == ComparisonObjectType.Measure || _comparisonObjectType == ComparisonObjectType.Kpi || _comparisonObjectType == ComparisonObjectType.CalculationItem)
{ {
return " " + _targetObject.Name; return " " + _targetObject.Name;
} }
@ -172,36 +172,42 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
switch (this.ComparisonObjectType) switch (this.ComparisonObjectType)
{ {
//tabular objects //tabular objects
case ComparisonObjectType.DataSource: case ComparisonObjectType.Model:
sortKey = "A"; sortKey = "A";
break; break;
case ComparisonObjectType.Expression: case ComparisonObjectType.DataSource:
sortKey = "B"; sortKey = "B";
break; break;
case ComparisonObjectType.Table: case ComparisonObjectType.Expression:
sortKey = "C"; sortKey = "C";
break; break;
case ComparisonObjectType.Relationship: case ComparisonObjectType.Table:
sortKey = "D"; sortKey = "D";
break; break;
case ComparisonObjectType.Measure: case ComparisonObjectType.Relationship:
sortKey = "E"; sortKey = "E";
break; break;
case ComparisonObjectType.Kpi: case ComparisonObjectType.Measure:
sortKey = "F"; sortKey = "F";
break; break;
case ComparisonObjectType.Action: case ComparisonObjectType.Kpi:
sortKey = "G"; sortKey = "G";
break; break;
case ComparisonObjectType.Perspective: case ComparisonObjectType.CalculationItem:
sortKey = "H"; sortKey = "H";
break; break;
case ComparisonObjectType.Culture: case ComparisonObjectType.Action:
sortKey = "I"; sortKey = "I";
break; break;
case ComparisonObjectType.Role: case ComparisonObjectType.Perspective:
sortKey = "J"; sortKey = "J";
break; break;
case ComparisonObjectType.Culture:
sortKey = "K";
break;
case ComparisonObjectType.Role:
sortKey = "L";
break;
default: default:
sortKey = "Z"; sortKey = "Z";

View File

@ -0,0 +1,65 @@
using Microsoft.AnalysisServices.Tabular;
using Tom=Microsoft.AnalysisServices.Tabular;
namespace BismNormalizer.TabularCompare.TabularMetadata
{
/// <summary>
/// Abstraction of a tabular model [model] with properties and methods for comparison purposes.
/// </summary>
public class Model : TabularObject
{
#region Private Members
private TabularModel _parentTabularModel;
private Tom.Model _tomModel;
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the Model class using multiple parameters.
/// </summary>
/// <param name="parentTabularModel">TabularModel object that the Model object belongs to.</param>
/// <param name="tomModel">Tabular Object Model Model object abtstracted by the Model class.</param>
public Model(TabularModel parentTabularModel, Tom.Model tomModel) : base(tomModel)
{
_parentTabularModel = parentTabularModel;
_tomModel = tomModel;
PopulateProperties();
}
#endregion
#region Properties
/// <summary>
/// TabularModel object that the Model object belongs to.
/// </summary>
public TabularModel ParentTabularModel => _parentTabularModel;
/// <summary>
/// Tabular Object Model Model object abtstracted by the Model class.
/// </summary>
public Tom.Model TomModel => _tomModel;
public override string ToString() => this.GetType().FullName;
#endregion
private void PopulateProperties()
{
string customObjectDefinition = "{ ";
if (!string.IsNullOrEmpty(_tomModel.Description))
{
customObjectDefinition += $"\"description\": \"{_tomModel.Description}\", ";
}
customObjectDefinition += $"\"defaultMode\": \"{_tomModel.DefaultMode.ToString().ToLower()}\", ";
customObjectDefinition += $"\"discourageImplicitMeasures\": {_tomModel.DiscourageImplicitMeasures.ToString().ToLower()} }}";
base.SetCustomObjectDefinition(customObjectDefinition);
}
}
}

View File

@ -0,0 +1,48 @@
//using System;
//using System.Collections.Generic;
//using System.IO;
//using System.Linq;
//using System.Text;
//using System.Globalization;
//using Microsoft.AnalysisServices.Tabular;
//using Tom=Microsoft.AnalysisServices.Tabular;
//namespace BismNormalizer.TabularCompare.TabularMetadata
//{
// /// <summary>
// /// Abstraction of a tabular model refreshPolicy with properties and methods for comparison purposes.
// /// </summary>
// public class RefreshPolicy : TabularObject
// {
// private Table _parentTable;
// private Tom.RefreshPolicy _tomRefreshPolicy;
// /// <summary>
// /// Initializes a new instance of the RefreshPolicy class using multiple parameters.
// /// </summary>
// /// <param name="parentTable">Table object that the refreshPolicy belongs to.</param>
// /// <param name="tomRefreshPolicy">Tabular Object Model RefreshPolicy object abtstracted by the RefreshPolicy class.</param>
// public RefreshPolicy(Table parentTable, Tom.RefreshPolicy tomRefreshPolicy) : base(tomRefreshPolicy)
// {
// _parentTable = parentTable;
// _tomRefreshPolicy = tomRefreshPolicy;
// }
// /// <summary>
// /// Table object that the Relationship oject belongs to.
// /// </summary>
// public Table ParentTable => _parentTable;
// /// <summary>
// /// Tabular Object Model RefreshPolicy object abtstracted by the RefreshPolicy class.
// /// </summary>
// public Tom.RefreshPolicy TomRefreshPolicy => _tomRefreshPolicy;
// /// <summary>
// /// Name of the table that the RefreshPolicy oject belongs to.
// /// </summary>
// public string TableName => _tomRefreshPolicy.Table.Name;
// public override string ToString() => this.GetType().FullName;
// }
//}

View File

@ -0,0 +1,98 @@
//using System;
//using System.Collections.Generic;
//namespace BismNormalizer.TabularCompare.TabularMetadata
//{
// /// <summary>
// /// Represents a collection of RefreshPolicy objects.
// /// </summary>
// public class RefreshPolicyCollection : List<RefreshPolicy>
// {
// /// <summary>
// /// Find an object in the collection by name.
// /// </summary>
// /// <param name="name"></param>
// /// <returns>RefreshPolicy object if found. Null if not found.</returns>
// public RefreshPolicy FindByName(string name)
// {
// foreach (RefreshPolicy refreshPolicy in this)
// {
// if (refreshPolicy.Name == name)
// {
// return refreshPolicy;
// }
// }
// return null;
// }
// /// <summary>
// /// A Boolean specifying whether the collection contains object by name.
// /// </summary>
// /// <param name="name"></param>
// /// <returns>True if the object is found, or False if it's not found.</returns>
// public bool ContainsName(string name)
// {
// foreach (RefreshPolicy refreshPolicy in this)
// {
// if (refreshPolicy.Name == name)
// {
// return true;
// }
// }
// return false;
// }
// /// <summary>
// /// A Boolean specifying whether the collection contains object by name searching without case sensitivity.
// /// </summary>
// /// <param name="name"></param>
// /// <returns>True if the object is found, or False if it's not found.</returns>
// public bool ContainsNameCaseInsensitive(string name)
// {
// foreach (RefreshPolicy refreshPolicy in this)
// {
// if (refreshPolicy.Name.ToUpper() == name.ToUpper())
// {
// return true;
// }
// }
// return false;
// }
// /// <summary>
// /// Returns a collection of RefreshPolicy objects filtered by the parent table's name.
// /// </summary>
// /// <param name="tableName"></param>
// /// <returns>RefreshPolicyCollection</returns>
// public RefreshPolicyCollection FilterByTableName(string tableName)
// {
// RefreshPolicyCollection returnRefreshPolicys = new RefreshPolicyCollection();
// foreach (RefreshPolicy refreshPolicy in this)
// {
// if (refreshPolicy.TableName == tableName)
// {
// returnRefreshPolicys.Add(refreshPolicy);
// }
// }
// return returnRefreshPolicys;
// }
// /// <summary>
// /// Removes an object from the collection by its name.
// /// </summary>
// /// <param name="name"></param>
// /// <returns>True if the object was removed, or False if was not found.</returns>
// public bool RemoveByName(string name)
// {
// foreach (RefreshPolicy refreshPolicy in this)
// {
// if (refreshPolicy.Name == name)
// {
// this.Remove(refreshPolicy);
// return true;
// }
// }
// return false;
// }
// }
//}

View File

@ -20,6 +20,9 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
private string _dataSourceName; private string _dataSourceName;
private RelationshipCollection _relationships = new RelationshipCollection(); private RelationshipCollection _relationships = new RelationshipCollection();
private MeasureCollection _measures = new MeasureCollection(); private MeasureCollection _measures = new MeasureCollection();
private bool _isCalculationGroup;
private ModeType _tableModeType;
private CalculationItemCollection _calculationItems = new CalculationItemCollection();
/// <summary> /// <summary>
/// Initializes a new instance of the Table class using multiple parameters. /// Initializes a new instance of the Table class using multiple parameters.
@ -59,6 +62,18 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
/// </summary> /// </summary>
public MeasureCollection Measures => _measures; public MeasureCollection Measures => _measures;
/// <summary>
/// True if the table is a calculation group.
/// </summary>
public bool IsCalculationGroup => _isCalculationGroup;
public ModeType TableModeType => _tableModeType;
/// <summary>
/// Collection of calculation items for the Table object.
/// </summary>
public CalculationItemCollection CalculationItems => _calculationItems;
/// <summary> /// <summary>
/// Tabular Object Model Table object abtstracted by the Table class. /// Tabular Object Model Table object abtstracted by the Table class.
/// </summary> /// </summary>
@ -68,16 +83,18 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
{ {
base.RemovePropertyFromObjectDefinition("measures"); base.RemovePropertyFromObjectDefinition("measures");
_isCalculationGroup = (_tomTable.CalculationGroup != null);
_partitionsDefinition = ""; _partitionsDefinition = "";
_dataSourceName = ""; _dataSourceName = "";
bool hasMOrQueryPartition = false; bool hasMQueryOrPolicyPartition = false;
//Associate table with a DataSource if possible. It's not possible if calc table or if M expression refers to a shared expression, or multiple data sources //Associate table with a DataSource if possible. It's not possible if calc table or if M expression refers to a shared expression, or multiple data sources
foreach (Partition partition in _tomTable.Partitions) foreach (Partition partition in _tomTable.Partitions)
{ {
_tableModeType = partition.Mode;
if (partition.SourceType == PartitionSourceType.M) if (partition.SourceType == PartitionSourceType.M)
{ {
hasMOrQueryPartition = true; hasMQueryOrPolicyPartition = true;
//Check M dependency tree to see if all partitions refer only to a single DataSource //Check M dependency tree to see if all partitions refer only to a single DataSource
CalcDependencyCollection calcDependencies = _parentTabularModel.MDependencies.DependenciesReferenceFrom(CalcDependencyObjectType.Partition, _tomTable.Name, partition.Name); CalcDependencyCollection calcDependencies = _parentTabularModel.MDependencies.DependenciesReferenceFrom(CalcDependencyObjectType.Partition, _tomTable.Name, partition.Name);
@ -105,17 +122,24 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
//If old partition, find the primary partition (first one) to determine DataSource. Technically it is possible for different partitions in the same table to point to different DataSources, but the Tabular Designer in VS doesn't support it. If set manually in .bim file, the UI still associates with the first partition (e.g. when processing table by itself, or deletinig the DataSource gives a warning message listing associated tables). //If old partition, find the primary partition (first one) to determine DataSource. Technically it is possible for different partitions in the same table to point to different DataSources, but the Tabular Designer in VS doesn't support it. If set manually in .bim file, the UI still associates with the first partition (e.g. when processing table by itself, or deletinig the DataSource gives a warning message listing associated tables).
if (partition.SourceType == PartitionSourceType.Query) if (partition.SourceType == PartitionSourceType.Query)
{ {
hasMOrQueryPartition = true; hasMQueryOrPolicyPartition = true;
_dataSourceName = ((QueryPartitionSource)partition.Source).DataSource.Name; _dataSourceName = ((QueryPartitionSource)partition.Source).DataSource.Name;
break; break;
} }
//Might be a policy partition.
if (partition.SourceType == PartitionSourceType.PolicyRange)
{
hasMQueryOrPolicyPartition = true;
break;
}
} }
if (hasMOrQueryPartition) if (hasMQueryOrPolicyPartition || _isCalculationGroup)
{ {
_partitionsDefinition = base.RetrievePropertyFromObjectDefinition("partitions"); _partitionsDefinition = base.RetrievePropertyFromObjectDefinition("partitions");
//Option to hide partitions only applies to M and query partitions (calculated tables hold dax defintitions in their partitions) //Option to hide partitions only applies to M, query and policy partitions (calculated tables hold dax defintitions in their partitions)
if (!_parentTabularModel.ComparisonInfo.OptionsInfo.OptionPartitions) if (!_parentTabularModel.ComparisonInfo.OptionsInfo.OptionPartitions)
{ {
base.RemovePropertyFromObjectDefinition("partitions"); base.RemovePropertyFromObjectDefinition("partitions");
@ -136,6 +160,15 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
{ {
_measures.Add(new Measure(this, measure, measure.KPI != null)); _measures.Add(new Measure(this, measure, measure.KPI != null));
} }
//Find calc items
if (_isCalculationGroup)
{
foreach (Tom.CalculationItem calcItem in _tomTable.CalculationGroup.CalculationItems)
{
_calculationItems.Add(new CalculationItem(this, calcItem));
}
}
} }
#region Relationship collection methods #region Relationship collection methods
@ -174,8 +207,12 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
/// Find all direct relationships that filter this table. This is all ACTIVE relationships where 1) this is FROM table, or 2) this is TO table with CrossFilteringBehavior=BothDirections /// Find all direct relationships that filter this table. This is all ACTIVE relationships where 1) this is FROM table, or 2) this is TO table with CrossFilteringBehavior=BothDirections
/// </summary> /// </summary>
/// <returns>All the associated Relationships.</returns> /// <returns>All the associated Relationships.</returns>
public List<Relationship> FindFilteringRelationships() public List<Relationship> FindFilteredRelationships(bool checkSecurityBehavior = false)
{ {
//T1[C1]->T2[C2]
//FromTableName: T1 *** this.Name
//ToTableName: T2
//Considers DIRECT relationships for this table ONLY (1 level). //Considers DIRECT relationships for this table ONLY (1 level).
List<Relationship> filteringRelationships = new List<Relationship>(); List<Relationship> filteringRelationships = new List<Relationship>();
foreach (Table table in _parentTabularModel.Tables) foreach (Table table in _parentTabularModel.Tables)
@ -184,7 +221,36 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
{ {
if (relationship.TomRelationship.IsActive && if (relationship.TomRelationship.IsActive &&
(relationship.FromTableName == this.Name || (relationship.FromTableName == this.Name ||
(relationship.ToTableName == this.Name && relationship.TomRelationship.CrossFilteringBehavior == CrossFilteringBehavior.BothDirections) (relationship.ToTableName == this.Name && relationship.TomRelationship.CrossFilteringBehavior == CrossFilteringBehavior.BothDirections && (!checkSecurityBehavior || (checkSecurityBehavior && relationship.TomRelationship.SecurityFilteringBehavior == SecurityFilteringBehavior.BothDirections)))
)
)
{
filteringRelationships.Add(relationship);
}
}
}
return filteringRelationships;
}
/// <summary>
/// Find all direct relationships that filter this table. This is all ACTIVE relationships where 1) this is FROM table, or 2) this is TO table with CrossFilteringBehavior=BothDirections
/// </summary>
/// <returns>All the associated Relationships.</returns>
public List<Relationship> FindFilteringRelationships(bool checkSecurityBehavior = false)
{
//T1[C1]->T2[C2]
//FromTableName: T1
//ToTableName: T2 *** this.Name
//Considers DIRECT relationships for this table ONLY (1 level).
List<Relationship> filteringRelationships = new List<Relationship>();
foreach (Table table in _parentTabularModel.Tables)
{
foreach (Relationship relationship in table.Relationships)
{
if (relationship.TomRelationship.IsActive &&
(relationship.ToTableName == this.Name ||
(relationship.FromTableName == this.Name && relationship.TomRelationship.CrossFilteringBehavior == CrossFilteringBehavior.BothDirections && (!checkSecurityBehavior || (checkSecurityBehavior && relationship.TomRelationship.SecurityFilteringBehavior == SecurityFilteringBehavior.BothDirections)))
) )
) )
{ {
@ -311,6 +377,12 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
return false; return false;
} }
if (this.IsCalculationGroup || _parentTabularModel.Tables.FindByName(tabularRelationshipSource.ToTable.Name).IsCalculationGroup)
{
warningMessage = $"Unable to create Relationship {relationshipName} because one or more tables is a calculation group.";
return false;
}
// Delete the target relationship with same tables/columns if still there. Not using RemoveByInternalName in case internal name is actually different. // Delete the target relationship with same tables/columns if still there. Not using RemoveByInternalName in case internal name is actually different.
if (this.Relationships.ContainsName(relationshipSource.Name)) if (this.Relationships.ContainsName(relationshipSource.Name))
{ {
@ -403,10 +475,75 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
CreateMeasure(tomMeasureSource); CreateMeasure(tomMeasureSource);
} }
// CalculationItems
/// <summary>
/// Delete calculation item associated with the Table object.
/// </summary>
/// <param name="name">Name of the calculationItem to be deleted.</param>
public void DeleteCalculationItem(string name)
{
if (_tomTable.CalculationGroup.CalculationItems.ContainsName(name))
{
_tomTable.CalculationGroup.CalculationItems.Remove(name);
}
// shell model
if (_calculationItems.ContainsName(name))
{
_calculationItems.RemoveByName(name);
}
}
/// <summary>
/// Create calculationItem associated with the Table object.
/// </summary>
/// <param name="tomCalculationItemSource">Tabular Object Model CalculationItem object from the source tabular model to be abstracted in the target.</param>
public void CreateCalculationItem(Tom.CalculationItem tomCalculationItemSource)
{
if (_tomTable.CalculationGroup.CalculationItems.ContainsName(tomCalculationItemSource.Name))
{
_tomTable.CalculationGroup.CalculationItems.Remove(tomCalculationItemSource.Name);
}
Tom.CalculationItem tomCalculationItemTarget = new Tom.CalculationItem();
tomCalculationItemSource.CopyTo(tomCalculationItemTarget);
_tomTable.CalculationGroup.CalculationItems.Add(tomCalculationItemTarget);
// shell model
_calculationItems.Add(new CalculationItem(this, tomCalculationItemTarget));
}
/// <summary>
/// Update calculationItem associated with the Table object.
/// </summary>
/// <param name="tomCalculationItemSource">Tabular Object Model CalculationItem object from the source tabular model to be abstracted in the target.</param>
public void UpdateCalculationItem(Tom.CalculationItem tomCalculationItemSource)
{
if (_calculationItems.ContainsName(tomCalculationItemSource.Name))
{
DeleteCalculationItem(tomCalculationItemSource.Name);
}
CreateCalculationItem(tomCalculationItemSource);
}
#endregion #endregion
#region Other public methods #region Other public methods
/// <summary>
/// For option when retain storage mode in composite models.
/// </summary>
/// <param name="modeType"></param>
public void ResetStorageMode(ModeType modeType)
{
foreach (Partition partition in _tomTable.Partitions)
{
partition.Mode = modeType;
}
_tableModeType = modeType;
}
/// <summary> /// <summary>
/// A Boolean specifying whether the table contains a column with the same name searching without case sensitivity. /// A Boolean specifying whether the table contains a column with the same name searching without case sensitivity.
/// </summary> /// </summary>

View File

@ -66,7 +66,7 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
/// Returns a collection of Table objects that do not have a DataSource associated with them. These can be calculated tables or tables with M partitions that do not refer to a DataSource. /// Returns a collection of Table objects that do not have a DataSource associated with them. These can be calculated tables or tables with M partitions that do not refer to a DataSource.
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public TableCollection WithoutDataSource(Model model) public TableCollection WithoutDataSource(Microsoft.AnalysisServices.Tabular.Model model)
{ {
TableCollection tablesWithDataSource = new TableCollection(); TableCollection tablesWithDataSource = new TableCollection();
foreach (Microsoft.AnalysisServices.Tabular.DataSource dataSource in model.DataSources) foreach (Microsoft.AnalysisServices.Tabular.DataSource dataSource in model.DataSources)

View File

@ -22,6 +22,7 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
private ComparisonInfo _comparisonInfo; private ComparisonInfo _comparisonInfo;
private Server _server; private Server _server;
private Database _database; private Database _database;
private Model _model;
private DataSourceCollection _dataSources = new DataSourceCollection(); private DataSourceCollection _dataSources = new DataSourceCollection();
private TableCollection _tables = new TableCollection(); private TableCollection _tables = new TableCollection();
private ExpressionCollection _expressions = new ExpressionCollection(); private ExpressionCollection _expressions = new ExpressionCollection();
@ -68,6 +69,7 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
InitializeCalcDependencies(); InitializeCalcDependencies();
//Shell model //Shell model
_model = new Model(this, _database.Model);
foreach (Tom.DataSource dataSource in _database.Model.DataSources) foreach (Tom.DataSource dataSource in _database.Model.DataSources)
{ {
if (dataSource.Type == DataSourceType.Provider || dataSource.Type == DataSourceType.Structured) if (dataSource.Type == DataSourceType.Provider || dataSource.Type == DataSourceType.Structured)
@ -212,6 +214,15 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
set { _database = value; } set { _database = value; }
} }
/// <summary>
/// Model object.
/// </summary>
public Model Model
{
get { return _model; }
set { _model = value; }
}
/// <summary> /// <summary>
/// Collection of DataSources for the TabularModel object. /// Collection of DataSources for the TabularModel object.
/// </summary> /// </summary>
@ -291,6 +302,25 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
#endregion #endregion
#region Model
/// <summary>
/// Update Model associated with the TabularModel object.
/// </summary>
/// <param name="dataSourceSource">Model object from the source tabular model to be updated in the target.</param>
/// <param name="dataSourceTarget">Model object in the target tabular model to be updated.</param>
public void UpdateModel(Model modelSource, Model modelTarget)
{
modelTarget.TomModel.Description = modelSource.TomModel.Description;
if (!_comparisonInfo.OptionsInfo.OptionRetainStorageMode)
{
modelTarget.TomModel.DefaultMode = modelSource.TomModel.DefaultMode;
}
modelTarget.TomModel.DiscourageImplicitMeasures = modelSource.TomModel.DiscourageImplicitMeasures;
}
#endregion
#region DataSources #region DataSources
/// <summary> /// <summary>
@ -323,7 +353,7 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
dataSourceSource.TomDataSource.CopyTo(providerTarget); dataSourceSource.TomDataSource.CopyTo(providerTarget);
_database.Model.DataSources.Add(providerTarget); _database.Model.DataSources.Add(providerTarget);
// shell model // shell model
_dataSources.Add(new DataSource(this, providerTarget)); _dataSources.Add(new DataSource(this, providerTarget));
} }
@ -416,6 +446,7 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
} }
tomTableTarget.Measures.Clear(); //Measures will be added separately later tomTableTarget.Measures.Clear(); //Measures will be added separately later
tomTableTarget.CalculationGroup?.CalculationItems.Clear(); //Calculation items will be added separately later
_database.Model.Tables.Add(tomTableTarget); _database.Model.Tables.Add(tomTableTarget);
_tables.Add(new Table(this, tomTableTarget)); _tables.Add(new Table(this, tomTableTarget));
@ -430,6 +461,7 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
{ {
bool canRetainPartitions = CanRetainPartitions(tableSource, tableTarget, out retainPartitionsMessage); bool canRetainPartitions = CanRetainPartitions(tableSource, tableTarget, out retainPartitionsMessage);
Tom.Table tomTableTargetOrig = tableTarget.TomTable.Clone(); Tom.Table tomTableTargetOrig = tableTarget.TomTable.Clone();
ModeType tableTargetModeType = tableTarget.TableModeType;
List<SingleColumnRelationship> tomRelationshipsToAddBack = DeleteTable(tableTarget.Name); List<SingleColumnRelationship> tomRelationshipsToAddBack = DeleteTable(tableTarget.Name);
CreateTable(tableSource); CreateTable(tableSource);
@ -462,50 +494,70 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
{ {
tableTarget.CreateMeasure(tomMeasureToAddBack); tableTarget.CreateMeasure(tomMeasureToAddBack);
} }
//add back calculationItems
if (tomTableTargetOrig.CalculationGroup != null)
{
foreach (Tom.CalculationItem tomCalculationItemToAddBack in tomTableTargetOrig.CalculationGroup.CalculationItems)
{
tableTarget.CreateCalculationItem(tomCalculationItemToAddBack);
}
}
else
{
//add back storage mode if option selected
if (_comparisonInfo.OptionsInfo.OptionRetainStorageMode)
{
tableTarget.ResetStorageMode(tableTargetModeType);
}
}
} }
public bool CanRetainPartitions(Table tableSource, Table tableTarget, out string retainPartitionsMessage) public bool CanRetainPartitions(Table tableSource, Table tableTarget, out string retainPartitionsMessage)
{ {
//Initialize variables
retainPartitionsMessage = ""; retainPartitionsMessage = "";
PartitionSourceType sourceTypeSource = PartitionSourceType.None;
//only applies to db deployment, and need option checked
if (!_comparisonInfo.OptionsInfo.OptionRetainPartitions)
return false;
//both tables need to have M or query partitions. Also type needs to match (won't copy query partition to M table). If a table has no partitions, do nothing.
PartitionSourceType sourceTypeTarget = PartitionSourceType.None;
foreach (Partition partition in tableSource.TomTable.Partitions) foreach (Partition partition in tableSource.TomTable.Partitions)
{ {
sourceTypeTarget = partition.SourceType; sourceTypeSource = partition.SourceType;
break; break;
} }
if (!(sourceTypeTarget == PartitionSourceType.M || sourceTypeTarget == PartitionSourceType.Query)) PartitionSourceType sourceTypeTarget = PartitionSourceType.None;
foreach (Partition partitionTarget in tableTarget.TomTable.Partitions)
{
sourceTypeTarget = partitionTarget.SourceType;
break;
}
//Verify necessary options are checked
if (!_comparisonInfo.OptionsInfo.OptionRetainPartitions)
return false;
if (_comparisonInfo.OptionsInfo.OptionRetainPolicyPartitions && sourceTypeTarget != PartitionSourceType.PolicyRange)
return false;
//both tables need to have M or query partitions, or target can be policy partitions. Also type needs to match (won't copy query partition to M table). If a table has no partitions, do nothing.
if (!(sourceTypeSource == PartitionSourceType.M || sourceTypeSource == PartitionSourceType.Query || sourceTypeSource == PartitionSourceType.PolicyRange))
{ {
retainPartitionsMessage = $"Retain partitions not applicable to partition types."; retainPartitionsMessage = $"Retain partitions not applicable to partition types.";
return false; return false;
} }
PartitionSourceType sourceTypeOrig = PartitionSourceType.None; if (!(sourceTypeTarget == PartitionSourceType.M || sourceTypeTarget == PartitionSourceType.Query || sourceTypeTarget == PartitionSourceType.PolicyRange))
foreach (Partition partitionOrig in tableTarget.TomTable.Partitions)
{
sourceTypeOrig = partitionOrig.SourceType;
break;
}
if (!(sourceTypeOrig == PartitionSourceType.M || sourceTypeOrig == PartitionSourceType.Query))
{ {
retainPartitionsMessage = $"Retain partitions not applicable to partition types."; retainPartitionsMessage = $"Retain partitions not applicable to partition types.";
return false; return false;
} }
if (sourceTypeOrig != sourceTypeTarget) if ((sourceTypeTarget != sourceTypeSource) && sourceTypeTarget != PartitionSourceType.PolicyRange)
{ {
retainPartitionsMessage = $"Retain partitions not applied because source partition type is {sourceTypeTarget.ToString()} and target partition type is {sourceTypeOrig.ToString()}."; retainPartitionsMessage = $"Retain partitions not applied because source partition type is {sourceTypeSource.ToString()} and target partition type is {sourceTypeTarget.ToString()}.";
return false; return false;
} }
if (tableSource.PartitionsDefinition == tableTarget.PartitionsDefinition) if (tableSource.PartitionsDefinition == tableTarget.PartitionsDefinition)
{ {
retainPartitionsMessage = "Source & target partition definitions match, so retain partitions not necessary."; retainPartitionsMessage = "Source & target partition definitions already match, so retain partitions not necessary.";
return false; return false;
} }
@ -592,7 +644,7 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
//beginTable might be the From or the To table in TOM Relationship object; it depends on CrossFilterDirection. //beginTable might be the From or the To table in TOM Relationship object; it depends on CrossFilterDirection.
RelationshipChainsFromRoot referencedTableCollection = new RelationshipChainsFromRoot(); RelationshipChainsFromRoot referencedTableCollection = new RelationshipChainsFromRoot();
foreach (Relationship filteringRelationship in beginTable.FindFilteringRelationships()) foreach (Relationship filteringRelationship in beginTable.FindFilteredRelationships())
{ {
// EndTable can be either the From or the To table of a Relationship object depending on CrossFilteringBehavior // EndTable can be either the From or the To table of a Relationship object depending on CrossFilteringBehavior
string endTableName = GetEndTableName(beginTable, filteringRelationship, out bool biDi); string endTableName = GetEndTableName(beginTable, filteringRelationship, out bool biDi);
@ -661,7 +713,7 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
chainsFromRoot.Add(link); chainsFromRoot.Add(link);
Table beginTable = link.EndTable; //EndTable is now the begin table as iterating next level ... Table beginTable = link.EndTable; //EndTable is now the begin table as iterating next level ...
foreach (Relationship filteringRelationship in beginTable.FindFilteringRelationships()) foreach (Relationship filteringRelationship in beginTable.FindFilteredRelationships())
{ {
// EndTable can be either the From or the To table of a Relationship object depending on direction of CrossFilteringBehavior // EndTable can be either the From or the To table of a Relationship object depending on direction of CrossFilteringBehavior
string endTableName = GetEndTableName(beginTable, filteringRelationship, out bool biDi); string endTableName = GetEndTableName(beginTable, filteringRelationship, out bool biDi);
@ -694,7 +746,7 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
#endregion #endregion
#region Variation Cleanup #region Variation / Aggregations Cleanup
/// <summary> /// <summary>
/// Remove variations referring to objects that don't exist. /// Remove variations referring to objects that don't exist.
@ -769,7 +821,7 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
} }
} }
//Check if any tables that have ShowAsVariationsOnly = true really have variatinos pointing at them //Check if any tables that have ShowAsVariationsOnly = true really have variations pointing at them
foreach (Table table in _tables) foreach (Table table in _tables)
{ {
if (table.TomTable.ShowAsVariationsOnly == true && !targetVariationTablesRemaining.Contains(table.Name)) if (table.TomTable.ShowAsVariationsOnly == true && !targetVariationTablesRemaining.Contains(table.Name))
@ -779,6 +831,225 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
} }
} }
/// <summary>
/// Remove aggregations referring to objects that don't exist.
/// </summary>
public void CleanUpAggregations()
{
//modelTablesWithRls to be used for Rule 11 below:
List<string> modelTablesWithRls = new List<string>();
foreach (Role role in _roles)
{
foreach (TablePermission tablePermission in role.TomRole.TablePermissions)
{
if (!String.IsNullOrEmpty(tablePermission.FilterExpression))
{
modelTablesWithRls.Add(tablePermission.Name);
}
}
}
foreach (Table table in _tables)
{
bool foundViolation = false;
string warningMessage = "";
foreach (Column column in table.TomTable.Columns)
{
if (!foundViolation)
{
/* Check aggs refer to valid base tables/columns
*/
if (column.AlternateOf?.BaseTable != null)
{
if (!_database.Model.Tables.ContainsName(column.AlternateOf.BaseTable.Name))
{
//Base table doesn't exist
foundViolation = true;
warningMessage = $"Removed aggregations on table {table.Name} because summarization {column.AlternateOf.Summarization.ToString()} on column {column.Name} (considering changes) refers to detail table that does not exist [table:{column.AlternateOf.BaseTable.Name}].\n";
break;
}
}
else if (column.AlternateOf?.BaseColumn != null)
{
if (_database.Model.Tables.ContainsName(column.AlternateOf.BaseColumn.Table?.Name))
{
//the referenced table is there, how about the referenced column?
if (!_database.Model.Tables.Find(column.AlternateOf.BaseColumn.Table.Name).Columns.ContainsName(column.AlternateOf.BaseColumn.Name))
{
//Base column does not exist
foundViolation = true;
warningMessage = $"Removed aggregations on table {table.Name} because summarization {column.AlternateOf.Summarization.ToString()} on column {column.Name} (considering changes) refers to detail column that does not exist [table:{column.AlternateOf.BaseColumn.Table.Name}/column:{column.AlternateOf.BaseColumn.Name}].\n";
break;
}
}
else
{
//Base table does not exist
foundViolation = true;
warningMessage = $"Removed aggregations on table {table.Name} because summarization {column.AlternateOf.Summarization.ToString()} on column {column.Name} (considering changes) refers to detail table that does not exist [table:{column.AlternateOf.BaseColumn.Table.Name}].\n";
break;
}
}
string detailTableName = null;
if (!foundViolation && column.AlternateOf != null)
{
detailTableName = (column.AlternateOf.BaseTable != null ? column.AlternateOf.BaseTable.Name : column.AlternateOf.BaseColumn.Table.Name);
}
Table detailTable = _tables.FindByName(detailTableName);
if (!foundViolation && column.AlternateOf != null && column.AlternateOf.Summarization != SummarizationType.GroupBy && modelTablesWithRls.Count > 0 && detailTable != null)
{
/* Rule 11: RLS expressions that can filter the agg table, must also be able to filter the detail table(s) using an active relationship
*/
//Get list of filtering RLS tables that filter the agg table
List<string> rlsTablesFilteringAgg = new List<string>(); //RLS tables that filter the agg table
//beginTable might be the From or the To table in TOM Relationship object; it depends on CrossFilterDirection.
RelationshipChainsFromRoot referencedTableCollection = new RelationshipChainsFromRoot();
foreach (Relationship filteringRelationship in table.FindFilteredRelationships(checkSecurityBehavior: true))
{
// EndTable can be either the From or the To table of a Relationship object depending on CrossFilteringBehavior/SecurityBehavior
string endTableName = GetEndTableName(table, filteringRelationship, out bool biDi);
RelationshipLink rootLink = new RelationshipLink(table, _tables.FindByName(endTableName), true, "", false, filteringRelationship, biDi);
ValidateLinkForAggsRls(rootLink, referencedTableCollection, modelTablesWithRls, rlsTablesFilteringAgg);
}
//If the agg table itself has RLS on it, then consider it a table that is filtering the agg too
if (modelTablesWithRls.Contains(table.Name))
{
rlsTablesFilteringAgg.Add(table.Name);
}
if (rlsTablesFilteringAgg.Count > 0)
{
//Get list of filtering RLS tables on the detail table
List<string> rlsTablesFilteringDetail = new List<string>(); //RLS tables that filter the detail table
//beginTable might be the From or the To table in TOM Relationship object; it depends on CrossFilterDirection.
referencedTableCollection = new RelationshipChainsFromRoot();
foreach (Relationship filteringRelationship in detailTable.FindFilteredRelationships(checkSecurityBehavior: true))
{
// EndTable can be either the From or the To table of a Relationship object depending on CrossFilteringBehavior/SecurityBehavior
string endTableName = GetEndTableName(detailTable, filteringRelationship, out bool biDi);
RelationshipLink rootLink = new RelationshipLink(detailTable, _tables.FindByName(endTableName), true, "", false, filteringRelationship, biDi);
ValidateLinkForAggsRls(rootLink, referencedTableCollection, modelTablesWithRls, rlsTablesFilteringDetail);
}
//For each agg table, check any RLS filter tables also covers the detail table
foreach (string rlsTableFilteringAgg in rlsTablesFilteringAgg)
{
if (!rlsTablesFilteringDetail.Contains(rlsTableFilteringAgg))
{
foundViolation = true;
warningMessage = $"Removed aggregations on table {table.Name} because summarization {column.AlternateOf.Summarization.ToString()} on column {column.Name} (considering changes) RLS filter on table {rlsTableFilteringAgg} that filters the agg, but does not filter detail table {detailTableName}.\n";
break;
}
}
}
}
if (!foundViolation && column.AlternateOf != null)
{
/* Rule 10: Relationships between aggregation tables and other (non-aggregation) tables are not allowed if the aggregation table is on the filtering side of a relationship (active or inactive relationships).
This rule applies whether relationships are weak or strong, whether BiDi or not [including to-many BiDi, not just to-one]
*/
//beginTable might be the From or the To table in TOM Relationship object; it depends on CrossFilterDirection.
RelationshipChainsFromRoot referencedTableCollection = new RelationshipChainsFromRoot();
foreach (Relationship filteringRelationship in table.FindFilteringRelationships())
{
// EndTable can be either the From or the To table of a Relationship object depending on CrossFilteringBehavior/SecurityBehavior
string endTableName = GetEndTableName(table, filteringRelationship, out bool biDi);
Table endTable = _tables.FindByName(endTableName);
if (endTable != null)
{
bool endTableContainsAggs = false;
foreach (Column col in endTable.TomTable.Columns)
{
if (col.AlternateOf != null)
{
//End table has at least 1 agg so we are good
endTableContainsAggs = true;
break;
}
}
if (!endTableContainsAggs)
{
foundViolation = true;
warningMessage = $"Removed aggregations on table {table.Name} because summarization {column.AlternateOf.Summarization.ToString()} on column {column.Name} (considering changes) the agg table is on the filtering side of a relationship to a table ({endTable.Name}) that does not contain aggregations, which is not allowed.\n";
break;
}
}
}
}
if (!foundViolation && column.AlternateOf != null && detailTable != null)
{
/* Rule 3: Chained aggregations are disallowed
*/
foreach (Column detailColumn in detailTable.TomTable.Columns)
{
if (detailColumn.AlternateOf != null)
{
foundViolation = true;
warningMessage = $"Removed aggregations on table {table.Name} because summarization {column.AlternateOf.Summarization.ToString()} on column {column.Name} (considering changes) the detail table {detailTableName} also contains aggregations, which is not allowed.\n";
break;
}
}
}
}
}
//Clear all aggs on the agg table
if (foundViolation)
{
_parentComparison.OnValidationMessage(new ValidationMessageEventArgs(warningMessage, ValidationMessageType.AggregationDependency, ValidationMessageStatus.Warning));
foreach (Column column in table.TomTable.Columns)
{
if (column.AlternateOf != null)
{
column.AlternateOf = null;
}
}
}
}
}
private void ValidateLinkForAggsRls(RelationshipLink link, RelationshipChainsFromRoot chainsFromRoot, List<string> modelTablesWithRls, List<string> rlsTablesFiltering)
{
if (link.FilteringRelationship.TomRelationship.IsActive)
{
if (modelTablesWithRls.Contains(link.EndTable.Name) && !rlsTablesFiltering.Contains(link.EndTable.Name))
{
rlsTablesFiltering.Add(link.EndTable.Name);
}
//Add the link to the chain and re-iterate ...
chainsFromRoot.Add(link);
Table beginTable = link.EndTable; //EndTable is now the begin table as iterating next level ...
foreach (Relationship filteringRelationship in beginTable.FindFilteredRelationships(checkSecurityBehavior: true))
{
// EndTable can be either the From or the To table of a Relationship object depending on direction of CrossFilteringBehavior
string endTableName = GetEndTableName(beginTable, filteringRelationship, out bool biDi);
//Need to check if endTableName has already been covered by TablePath to avoid CrossFilteringBehavior leading both ways and never ending loop
if (!link.TablePath.Contains("'" + endTableName + "'"))
{
RelationshipLink newLink = new RelationshipLink(beginTable, _tables.FindByName(endTableName), false, link.TablePath, link.PrecedingPathBiDiInvoked, filteringRelationship, biDi);
ValidateLinkForAggsRls(newLink, chainsFromRoot, modelTablesWithRls, rlsTablesFiltering);
}
}
}
}
#endregion #endregion
#region Backup / Restore #region Backup / Restore
@ -1275,7 +1546,7 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
break; break;
} }
//If namedObjectTarget is null, the model object doesn't exist in target, so can ignore //If namedObjectTarget is null, the model object does not exist in target, so can ignore
if (namedObjectTarget != null) if (namedObjectTarget != null)
{ {
//Does the translation already exist in cultureTarget? //Does the translation already exist in cultureTarget?
@ -1683,7 +1954,7 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
traceEvent.Columns.Add(Amo.TraceColumn.IntegerData); traceEvent.Columns.Add(Amo.TraceColumn.IntegerData);
traceEvent.Columns.Add(Amo.TraceColumn.SessionID); traceEvent.Columns.Add(Amo.TraceColumn.SessionID);
traceEvent.Columns.Add(Amo.TraceColumn.Spid); traceEvent.Columns.Add(Amo.TraceColumn.Spid);
trace.Update(); trace.Update(Amo.UpdateOptions.Default, Amo.UpdateMode.CreateOrReplace);
trace.OnEvent += new TraceEventHandler(Trace_OnEvent); trace.OnEvent += new TraceEventHandler(Trace_OnEvent);
trace.Start(); trace.Start();
@ -1707,8 +1978,20 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
// Show row count for each table // Show row count for each table
foreach (ProcessingTable table in _tablesToProcess) foreach (ProcessingTable table in _tablesToProcess)
{ {
int rowCount = _connectionInfo.DirectQuery ? 0 : Core.Comparison.FindRowCount(_server, table.Name, _database.Name); string message = "";
_parentComparison.OnDeploymentMessage(new DeploymentMessageEventArgs(table.Name, $"Success. {String.Format("{0:#,###0}", rowCount)} rows transferred.", DeploymentStatus.Success)); if (
this._tables.FindByName(table.Name)?.TableModeType == ModeType.DirectQuery ||
(this._tables.FindByName(table.Name)?.TableModeType == ModeType.Default && _database.Model.DefaultMode == ModeType.DirectQuery)
)
{
message = "Success. 0 rows transferred (DirectQuery).";
}
else
{
int rowCount = Core.Comparison.FindRowCount(_server, table.Name, _database.Name);
message = $"Success. {String.Format("{0:#,###0}", rowCount)} rows transferred.";
}
_parentComparison.OnDeploymentMessage(new DeploymentMessageEventArgs(table.Name, message, DeploymentStatus.Success));
} }
_parentComparison.OnDeploymentComplete(new DeploymentCompleteEventArgs(DeploymentStatus.Success, null)); _parentComparison.OnDeploymentComplete(new DeploymentCompleteEventArgs(DeploymentStatus.Success, null));
} }
@ -1785,7 +2068,7 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
PartitionRowCounter partition = processingTable.FindPartition(partitionNodeList[0].InnerText); PartitionRowCounter partition = processingTable.FindPartition(partitionNodeList[0].InnerText);
partition.RowCount = e.IntegerData; partition.RowCount = e.IntegerData;
_parentComparison.OnDeploymentMessage(new DeploymentMessageEventArgs(processingTable.Name, $"Retreived {String.Format("{0:#,###0}", processingTable.GetRowCount())} rows ...", DeploymentStatus.Deploying)); _parentComparison.OnDeploymentMessage(new DeploymentMessageEventArgs(processingTable.Name, $"Retrieved {String.Format("{0:#,###0}", processingTable.GetRowCount())} rows ...", DeploymentStatus.Deploying));
} }
} }
@ -1860,10 +2143,10 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
private void FinalValidation() private void FinalValidation()
{ {
if (_connectionInfo.DirectQuery && _dataSources.Count > 1) //if (_connectionInfo.DirectQuery && _dataSources.Count > 1)
{ //{
throw new InvalidOperationException("Target model contains multiple data sources, which are not allowed for Direct Query models. Re-run comparison and (considering changes) ensure there is a single connection in the target model."); // throw new InvalidOperationException("Target model contains multiple data sources, which are not allowed for Direct Query models. Re-run comparison and (considering changes) ensure there is a single connection in the target model.");
} //}
} }
public override string ToString() => this.GetType().FullName; public override string ToString() => this.GetType().FullName;

View File

@ -24,6 +24,7 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
public TabularObject(NamedMetadataObject namedMetaDataObject) public TabularObject(NamedMetadataObject namedMetaDataObject)
{ {
_name = namedMetaDataObject.Name; _name = namedMetaDataObject.Name;
if (namedMetaDataObject is Tom.Model) return; //Model has custom JSON string
//Serialize json //Serialize json
SerializeOptions options = new SerializeOptions(); SerializeOptions options = new SerializeOptions();
@ -40,9 +41,23 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
_objectDefinition = token.ToString(Formatting.Indented); _objectDefinition = token.ToString(Formatting.Indented);
} }
//todo: remove with Giri's fix
//Remove return characters
if (namedMetaDataObject is Tom.NamedExpression || namedMetaDataObject is Tom.Table)
{
_objectDefinition = _objectDefinition.Replace("\\r", "");
}
//Order table columns //Order table columns
if (namedMetaDataObject is Tom.Table) if (namedMetaDataObject is Tom.Table)
{ {
if (((Tom.Table)namedMetaDataObject).CalculationGroup != null)
{
JToken token = JToken.Parse(_objectDefinition);
RemovePropertyFromObjectDefinition(token, "calculationItems");
_objectDefinition = token.ToString(Formatting.Indented);
}
_objectDefinition = SortArray(_objectDefinition, "columns"); _objectDefinition = SortArray(_objectDefinition, "columns");
_objectDefinition = SortArray(_objectDefinition, "partitions"); _objectDefinition = SortArray(_objectDefinition, "partitions");
} }
@ -111,6 +126,14 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
_objectDefinition = jObj.ToString(Formatting.Indented); _objectDefinition = jObj.ToString(Formatting.Indented);
} }
/// <summary>
/// Set a custom JSON string. An example is for the model class which contains properties that cannot be set.
/// </summary>
public void SetCustomObjectDefinition(string customObjectDefinition)
{
_objectDefinition = JToken.Parse(customObjectDefinition).ToString();
}
/// <summary> /// <summary>
/// Retrieve a JSON property definition from the full object definition. An example is partitions. /// Retrieve a JSON property definition from the full object definition. An example is partitions.
/// </summary> /// </summary>

View File

@ -58,16 +58,16 @@
this.btnOptions = new System.Windows.Forms.ToolStripButton(); this.btnOptions = new System.Windows.Forms.ToolStripButton();
this.btnReportDifferences = new System.Windows.Forms.ToolStripButton(); this.btnReportDifferences = new System.Windows.Forms.ToolStripButton();
this.scDifferenceResults = new System.Windows.Forms.SplitContainer(); this.scDifferenceResults = new System.Windows.Forms.SplitContainer();
this.pnlProgressBar = new System.Windows.Forms.Panel();
this.progressBar = new System.Windows.Forms.ProgressBar();
this.lblProgressBar = new System.Windows.Forms.Label();
this.treeGridComparisonResults = new BismNormalizer.TabularCompare.UI.TreeGridViewComparison();
this.TreeGridImageList = new System.Windows.Forms.ImageList(this.components); this.TreeGridImageList = new System.Windows.Forms.ImageList(this.components);
this.scObjectDefinitions = new System.Windows.Forms.SplitContainer(); this.scObjectDefinitions = new System.Windows.Forms.SplitContainer();
this.txtSourceObjectDefinition = new BismNormalizer.TabularCompare.UI.SynchronizedScrollRichTextBox();
this.label4 = new System.Windows.Forms.Label(); this.label4 = new System.Windows.Forms.Label();
this.txtTargetObjectDefinition = new BismNormalizer.TabularCompare.UI.SynchronizedScrollRichTextBox();
this.label5 = new System.Windows.Forms.Label(); this.label5 = new System.Windows.Forms.Label();
this.progressBar = new System.Windows.Forms.ToolStripProgressBar();
this.pnlProgressBar = new System.Windows.Forms.StatusStrip();
this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel();
this.treeGridComparisonResults = new BismNormalizer.TabularCompare.UI.TreeGridViewComparison();
this.txtSourceObjectDefinition = new BismNormalizer.TabularCompare.UI.SynchronizedScrollRichTextBox();
this.txtTargetObjectDefinition = new BismNormalizer.TabularCompare.UI.SynchronizedScrollRichTextBox();
this.pnlHeader.SuspendLayout(); this.pnlHeader.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.spltSourceTarget)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.spltSourceTarget)).BeginInit();
this.spltSourceTarget.Panel1.SuspendLayout(); this.spltSourceTarget.Panel1.SuspendLayout();
@ -78,12 +78,12 @@
this.scDifferenceResults.Panel1.SuspendLayout(); this.scDifferenceResults.Panel1.SuspendLayout();
this.scDifferenceResults.Panel2.SuspendLayout(); this.scDifferenceResults.Panel2.SuspendLayout();
this.scDifferenceResults.SuspendLayout(); this.scDifferenceResults.SuspendLayout();
this.pnlProgressBar.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.treeGridComparisonResults)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.scObjectDefinitions)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.scObjectDefinitions)).BeginInit();
this.scObjectDefinitions.Panel1.SuspendLayout(); this.scObjectDefinitions.Panel1.SuspendLayout();
this.scObjectDefinitions.Panel2.SuspendLayout(); this.scObjectDefinitions.Panel2.SuspendLayout();
this.scObjectDefinitions.SuspendLayout(); this.scObjectDefinitions.SuspendLayout();
this.pnlProgressBar.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.treeGridComparisonResults)).BeginInit();
this.SuspendLayout(); this.SuspendLayout();
// //
// pnlHeader // pnlHeader
@ -92,8 +92,9 @@
this.pnlHeader.Controls.Add(this.toolStrip1); this.pnlHeader.Controls.Add(this.toolStrip1);
this.pnlHeader.Dock = System.Windows.Forms.DockStyle.Top; this.pnlHeader.Dock = System.Windows.Forms.DockStyle.Top;
this.pnlHeader.Location = new System.Drawing.Point(0, 0); this.pnlHeader.Location = new System.Drawing.Point(0, 0);
this.pnlHeader.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.pnlHeader.Name = "pnlHeader"; this.pnlHeader.Name = "pnlHeader";
this.pnlHeader.Size = new System.Drawing.Size(653, 55); this.pnlHeader.Size = new System.Drawing.Size(980, 85);
this.pnlHeader.TabIndex = 46; this.pnlHeader.TabIndex = 46;
// //
// spltSourceTarget // spltSourceTarget
@ -101,6 +102,7 @@
this.spltSourceTarget.Dock = System.Windows.Forms.DockStyle.Fill; this.spltSourceTarget.Dock = System.Windows.Forms.DockStyle.Fill;
this.spltSourceTarget.IsSplitterFixed = true; this.spltSourceTarget.IsSplitterFixed = true;
this.spltSourceTarget.Location = new System.Drawing.Point(0, 25); this.spltSourceTarget.Location = new System.Drawing.Point(0, 25);
this.spltSourceTarget.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.spltSourceTarget.Name = "spltSourceTarget"; this.spltSourceTarget.Name = "spltSourceTarget";
// //
// spltSourceTarget.Panel1 // spltSourceTarget.Panel1
@ -112,16 +114,18 @@
// //
this.spltSourceTarget.Panel2.Controls.Add(this.txtTarget); this.spltSourceTarget.Panel2.Controls.Add(this.txtTarget);
this.spltSourceTarget.Panel2.Controls.Add(this.label2); this.spltSourceTarget.Panel2.Controls.Add(this.label2);
this.spltSourceTarget.Size = new System.Drawing.Size(653, 30); this.spltSourceTarget.Size = new System.Drawing.Size(980, 60);
this.spltSourceTarget.SplitterDistance = 321; this.spltSourceTarget.SplitterDistance = 481;
this.spltSourceTarget.SplitterWidth = 6;
this.spltSourceTarget.TabIndex = 45; this.spltSourceTarget.TabIndex = 45;
// //
// label1 // label1
// //
this.label1.AutoSize = true; this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(2, 8); this.label1.Location = new System.Drawing.Point(3, 12);
this.label1.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.label1.Name = "label1"; this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(41, 13); this.label1.Size = new System.Drawing.Size(60, 20);
this.label1.TabIndex = 39; this.label1.TabIndex = 39;
this.label1.Text = "Source"; this.label1.Text = "Source";
// //
@ -131,9 +135,10 @@
| System.Windows.Forms.AnchorStyles.Right))); | System.Windows.Forms.AnchorStyles.Right)));
this.txtSource.BackColor = System.Drawing.SystemColors.Control; this.txtSource.BackColor = System.Drawing.SystemColors.Control;
this.txtSource.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; this.txtSource.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.txtSource.Location = new System.Drawing.Point(49, 7); this.txtSource.Location = new System.Drawing.Point(74, 11);
this.txtSource.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.txtSource.Name = "txtSource"; this.txtSource.Name = "txtSource";
this.txtSource.Size = new System.Drawing.Size(269, 20); this.txtSource.Size = new System.Drawing.Size(401, 26);
this.txtSource.TabIndex = 41; this.txtSource.TabIndex = 41;
this.txtSource.KeyDown += new System.Windows.Forms.KeyEventHandler(this.txt_KeyDown); this.txtSource.KeyDown += new System.Windows.Forms.KeyEventHandler(this.txt_KeyDown);
// //
@ -143,9 +148,10 @@
| System.Windows.Forms.AnchorStyles.Right))); | System.Windows.Forms.AnchorStyles.Right)));
this.txtTarget.BackColor = System.Drawing.SystemColors.Control; this.txtTarget.BackColor = System.Drawing.SystemColors.Control;
this.txtTarget.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; this.txtTarget.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.txtTarget.Location = new System.Drawing.Point(45, 7); this.txtTarget.Location = new System.Drawing.Point(68, 11);
this.txtTarget.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.txtTarget.Name = "txtTarget"; this.txtTarget.Name = "txtTarget";
this.txtTarget.Size = new System.Drawing.Size(272, 20); this.txtTarget.Size = new System.Drawing.Size(408, 26);
this.txtTarget.TabIndex = 42; this.txtTarget.TabIndex = 42;
this.txtTarget.KeyDown += new System.Windows.Forms.KeyEventHandler(this.txt_KeyDown); this.txtTarget.KeyDown += new System.Windows.Forms.KeyEventHandler(this.txt_KeyDown);
// //
@ -154,9 +160,10 @@
this.label2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) this.label2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right))); | System.Windows.Forms.AnchorStyles.Right)));
this.label2.AutoSize = true; this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(3, 8); this.label2.Location = new System.Drawing.Point(4, 12);
this.label2.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.label2.Name = "label2"; this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(38, 13); this.label2.Size = new System.Drawing.Size(55, 20);
this.label2.TabIndex = 40; this.label2.TabIndex = 40;
this.label2.Text = "Target"; this.label2.Text = "Target";
// //
@ -173,7 +180,8 @@
this.btnReportDifferences}); this.btnReportDifferences});
this.toolStrip1.Location = new System.Drawing.Point(0, 0); this.toolStrip1.Location = new System.Drawing.Point(0, 0);
this.toolStrip1.Name = "toolStrip1"; this.toolStrip1.Name = "toolStrip1";
this.toolStrip1.Size = new System.Drawing.Size(653, 25); this.toolStrip1.Padding = new System.Windows.Forms.Padding(0, 0, 2, 0);
this.toolStrip1.Size = new System.Drawing.Size(980, 25);
this.toolStrip1.TabIndex = 46; this.toolStrip1.TabIndex = 46;
this.toolStrip1.Text = "toolStrip1"; this.toolStrip1.Text = "toolStrip1";
// //
@ -325,14 +333,15 @@
this.btnReportDifferences.Image = ((System.Drawing.Image)(resources.GetObject("btnReportDifferences.Image"))); this.btnReportDifferences.Image = ((System.Drawing.Image)(resources.GetObject("btnReportDifferences.Image")));
this.btnReportDifferences.ImageTransparentColor = System.Drawing.Color.Magenta; this.btnReportDifferences.ImageTransparentColor = System.Drawing.Color.Magenta;
this.btnReportDifferences.Name = "btnReportDifferences"; this.btnReportDifferences.Name = "btnReportDifferences";
this.btnReportDifferences.Size = new System.Drawing.Size(124, 20); this.btnReportDifferences.Size = new System.Drawing.Size(124, 22);
this.btnReportDifferences.Text = "Report Differences"; this.btnReportDifferences.Text = "Report Differences";
this.btnReportDifferences.Click += new System.EventHandler(this.btnReportDifferences_Click); this.btnReportDifferences.Click += new System.EventHandler(this.btnReportDifferences_Click);
// //
// scDifferenceResults // scDifferenceResults
// //
this.scDifferenceResults.Dock = System.Windows.Forms.DockStyle.Fill; this.scDifferenceResults.Dock = System.Windows.Forms.DockStyle.Fill;
this.scDifferenceResults.Location = new System.Drawing.Point(0, 55); this.scDifferenceResults.Location = new System.Drawing.Point(0, 85);
this.scDifferenceResults.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.scDifferenceResults.Name = "scDifferenceResults"; this.scDifferenceResults.Name = "scDifferenceResults";
this.scDifferenceResults.Orientation = System.Windows.Forms.Orientation.Horizontal; this.scDifferenceResults.Orientation = System.Windows.Forms.Orientation.Horizontal;
// //
@ -344,75 +353,11 @@
// scDifferenceResults.Panel2 // scDifferenceResults.Panel2
// //
this.scDifferenceResults.Panel2.Controls.Add(this.scObjectDefinitions); this.scDifferenceResults.Panel2.Controls.Add(this.scObjectDefinitions);
this.scDifferenceResults.Size = new System.Drawing.Size(653, 510); this.scDifferenceResults.Size = new System.Drawing.Size(980, 784);
this.scDifferenceResults.SplitterDistance = 371; this.scDifferenceResults.SplitterDistance = 570;
this.scDifferenceResults.SplitterWidth = 6;
this.scDifferenceResults.TabIndex = 2; this.scDifferenceResults.TabIndex = 2;
// //
// pnlProgressBar
//
this.pnlProgressBar.BackColor = System.Drawing.SystemColors.Control;
this.pnlProgressBar.Controls.Add(this.progressBar);
this.pnlProgressBar.Controls.Add(this.lblProgressBar);
this.pnlProgressBar.Location = new System.Drawing.Point(60, 21);
this.pnlProgressBar.Name = "pnlProgressBar";
this.pnlProgressBar.Size = new System.Drawing.Size(280, 54);
this.pnlProgressBar.TabIndex = 1;
this.pnlProgressBar.Visible = false;
//
// progressBar
//
this.progressBar.Location = new System.Drawing.Point(120, 16);
this.progressBar.Name = "progressBar";
this.progressBar.Size = new System.Drawing.Size(137, 18);
this.progressBar.Step = 1;
this.progressBar.TabIndex = 1;
//
// lblProgressBar
//
this.lblProgressBar.AutoSize = true;
this.lblProgressBar.Location = new System.Drawing.Point(12, 16);
this.lblProgressBar.Name = "lblProgressBar";
this.lblProgressBar.Size = new System.Drawing.Size(101, 13);
this.lblProgressBar.TabIndex = 0;
this.lblProgressBar.Text = "Generating report ...";
//
// treeGridComparisonResults
//
this.treeGridComparisonResults.AllowUserToAddRows = false;
this.treeGridComparisonResults.AllowUserToDeleteRows = false;
this.treeGridComparisonResults.AllowUserToResizeRows = false;
this.treeGridComparisonResults.AutoSizeRowsMode = System.Windows.Forms.DataGridViewAutoSizeRowsMode.AllCells;
dataGridViewCellStyle1.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
dataGridViewCellStyle1.BackColor = System.Drawing.SystemColors.Control;
dataGridViewCellStyle1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
dataGridViewCellStyle1.ForeColor = System.Drawing.SystemColors.WindowText;
dataGridViewCellStyle1.SelectionBackColor = System.Drawing.SystemColors.Highlight;
dataGridViewCellStyle1.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
dataGridViewCellStyle1.WrapMode = System.Windows.Forms.DataGridViewTriState.True;
this.treeGridComparisonResults.ColumnHeadersDefaultCellStyle = dataGridViewCellStyle1;
this.treeGridComparisonResults.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this.treeGridComparisonResults.Comparison = null;
dataGridViewCellStyle2.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
dataGridViewCellStyle2.BackColor = System.Drawing.SystemColors.Window;
dataGridViewCellStyle2.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
dataGridViewCellStyle2.ForeColor = System.Drawing.SystemColors.ControlText;
dataGridViewCellStyle2.SelectionBackColor = System.Drawing.SystemColors.Highlight;
dataGridViewCellStyle2.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
dataGridViewCellStyle2.WrapMode = System.Windows.Forms.DataGridViewTriState.False;
this.treeGridComparisonResults.DefaultCellStyle = dataGridViewCellStyle2;
this.treeGridComparisonResults.Dock = System.Windows.Forms.DockStyle.Fill;
this.treeGridComparisonResults.EditMode = System.Windows.Forms.DataGridViewEditMode.EditOnEnter;
this.treeGridComparisonResults.ImageList = this.TreeGridImageList;
this.treeGridComparisonResults.Location = new System.Drawing.Point(0, 0);
this.treeGridComparisonResults.Name = "treeGridComparisonResults";
this.treeGridComparisonResults.RowHeadersVisible = false;
this.treeGridComparisonResults.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.CellSelect;
this.treeGridComparisonResults.Size = new System.Drawing.Size(653, 371);
this.treeGridComparisonResults.TabIndex = 0;
this.treeGridComparisonResults.Unloading = false;
this.treeGridComparisonResults.DataError += new System.Windows.Forms.DataGridViewDataErrorEventHandler(this.treeGridComparisonResults_DataError);
this.treeGridComparisonResults.MouseUp += new System.Windows.Forms.MouseEventHandler(this.treeGridComparisonResults_MouseUp);
//
// TreeGridImageList // TreeGridImageList
// //
this.TreeGridImageList.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("TreeGridImageList.ImageStream"))); this.TreeGridImageList.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("TreeGridImageList.ImageStream")));
@ -445,6 +390,7 @@
// //
this.scObjectDefinitions.Dock = System.Windows.Forms.DockStyle.Fill; this.scObjectDefinitions.Dock = System.Windows.Forms.DockStyle.Fill;
this.scObjectDefinitions.Location = new System.Drawing.Point(0, 0); this.scObjectDefinitions.Location = new System.Drawing.Point(0, 0);
this.scObjectDefinitions.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.scObjectDefinitions.Name = "scObjectDefinitions"; this.scObjectDefinitions.Name = "scObjectDefinitions";
// //
// scObjectDefinitions.Panel1 // scObjectDefinitions.Panel1
@ -458,10 +404,93 @@
this.scObjectDefinitions.Panel2.BackColor = System.Drawing.SystemColors.Control; this.scObjectDefinitions.Panel2.BackColor = System.Drawing.SystemColors.Control;
this.scObjectDefinitions.Panel2.Controls.Add(this.txtTargetObjectDefinition); this.scObjectDefinitions.Panel2.Controls.Add(this.txtTargetObjectDefinition);
this.scObjectDefinitions.Panel2.Controls.Add(this.label5); this.scObjectDefinitions.Panel2.Controls.Add(this.label5);
this.scObjectDefinitions.Size = new System.Drawing.Size(653, 135); this.scObjectDefinitions.Size = new System.Drawing.Size(980, 208);
this.scObjectDefinitions.SplitterDistance = 331; this.scObjectDefinitions.SplitterDistance = 496;
this.scObjectDefinitions.SplitterWidth = 6;
this.scObjectDefinitions.TabIndex = 0; this.scObjectDefinitions.TabIndex = 0;
// //
// label4
//
this.label4.AutoSize = true;
this.label4.Location = new System.Drawing.Point(6, 2);
this.label4.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(181, 20);
this.label4.TabIndex = 0;
this.label4.Text = "Source Object Definition";
//
// label5
//
this.label5.AutoSize = true;
this.label5.Location = new System.Drawing.Point(4, 2);
this.label5.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.label5.Name = "label5";
this.label5.Size = new System.Drawing.Size(176, 20);
this.label5.TabIndex = 1;
this.label5.Text = "Target Object Definition";
//
// progressBar
//
this.progressBar.Name = "progressBar";
this.progressBar.Size = new System.Drawing.Size(150, 16);
//
// pnlProgressBar
//
this.pnlProgressBar.ImageScalingSize = new System.Drawing.Size(36, 36);
this.pnlProgressBar.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.toolStripStatusLabel1,
this.progressBar});
this.pnlProgressBar.Location = new System.Drawing.Point(0, 548);
this.pnlProgressBar.Name = "pnlProgressBar";
this.pnlProgressBar.Padding = new System.Windows.Forms.Padding(1, 0, 21, 0);
this.pnlProgressBar.Size = new System.Drawing.Size(980, 22);
this.pnlProgressBar.TabIndex = 49;
this.pnlProgressBar.Text = "Comparison Status";
this.pnlProgressBar.Visible = false;
//
// toolStripStatusLabel1
//
this.toolStripStatusLabel1.Name = "toolStripStatusLabel1";
this.toolStripStatusLabel1.Size = new System.Drawing.Size(0, 17);
//
// treeGridComparisonResults
//
this.treeGridComparisonResults.AllowUserToAddRows = false;
this.treeGridComparisonResults.AllowUserToDeleteRows = false;
this.treeGridComparisonResults.AllowUserToResizeRows = false;
this.treeGridComparisonResults.AutoSizeRowsMode = System.Windows.Forms.DataGridViewAutoSizeRowsMode.AllCells;
dataGridViewCellStyle1.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
dataGridViewCellStyle1.BackColor = System.Drawing.SystemColors.Control;
dataGridViewCellStyle1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
dataGridViewCellStyle1.ForeColor = System.Drawing.SystemColors.WindowText;
dataGridViewCellStyle1.SelectionBackColor = System.Drawing.SystemColors.Highlight;
dataGridViewCellStyle1.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
dataGridViewCellStyle1.WrapMode = System.Windows.Forms.DataGridViewTriState.True;
this.treeGridComparisonResults.ColumnHeadersDefaultCellStyle = dataGridViewCellStyle1;
this.treeGridComparisonResults.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this.treeGridComparisonResults.Comparison = null;
dataGridViewCellStyle2.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
dataGridViewCellStyle2.BackColor = System.Drawing.SystemColors.Window;
dataGridViewCellStyle2.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
dataGridViewCellStyle2.ForeColor = System.Drawing.SystemColors.ControlText;
dataGridViewCellStyle2.SelectionBackColor = System.Drawing.SystemColors.Highlight;
dataGridViewCellStyle2.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
dataGridViewCellStyle2.WrapMode = System.Windows.Forms.DataGridViewTriState.False;
this.treeGridComparisonResults.DefaultCellStyle = dataGridViewCellStyle2;
this.treeGridComparisonResults.Dock = System.Windows.Forms.DockStyle.Fill;
this.treeGridComparisonResults.EditMode = System.Windows.Forms.DataGridViewEditMode.EditOnEnter;
this.treeGridComparisonResults.ImageList = this.TreeGridImageList;
this.treeGridComparisonResults.Location = new System.Drawing.Point(0, 0);
this.treeGridComparisonResults.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.treeGridComparisonResults.Name = "treeGridComparisonResults";
this.treeGridComparisonResults.RowHeadersVisible = false;
this.treeGridComparisonResults.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.CellSelect;
this.treeGridComparisonResults.Size = new System.Drawing.Size(980, 570);
this.treeGridComparisonResults.TabIndex = 0;
this.treeGridComparisonResults.Unloading = false;
this.treeGridComparisonResults.DataError += new System.Windows.Forms.DataGridViewDataErrorEventHandler(this.treeGridComparisonResults_DataError);
this.treeGridComparisonResults.MouseUp += new System.Windows.Forms.MouseEventHandler(this.treeGridComparisonResults_MouseUp);
//
// txtSourceObjectDefinition // txtSourceObjectDefinition
// //
this.txtSourceObjectDefinition.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) this.txtSourceObjectDefinition.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
@ -469,25 +498,17 @@
| System.Windows.Forms.AnchorStyles.Right))); | System.Windows.Forms.AnchorStyles.Right)));
this.txtSourceObjectDefinition.BackColor = System.Drawing.Color.White; this.txtSourceObjectDefinition.BackColor = System.Drawing.Color.White;
this.txtSourceObjectDefinition.Font = new System.Drawing.Font("Consolas", 9.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.txtSourceObjectDefinition.Font = new System.Drawing.Font("Consolas", 9.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.txtSourceObjectDefinition.Location = new System.Drawing.Point(0, 16); this.txtSourceObjectDefinition.Location = new System.Drawing.Point(0, 25);
this.txtSourceObjectDefinition.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.txtSourceObjectDefinition.Name = "txtSourceObjectDefinition"; this.txtSourceObjectDefinition.Name = "txtSourceObjectDefinition";
this.txtSourceObjectDefinition.ReadOnly = true; this.txtSourceObjectDefinition.ReadOnly = true;
this.txtSourceObjectDefinition.Size = new System.Drawing.Size(331, 119); this.txtSourceObjectDefinition.Size = new System.Drawing.Size(494, 181);
this.txtSourceObjectDefinition.TabIndex = 1; this.txtSourceObjectDefinition.TabIndex = 1;
this.txtSourceObjectDefinition.Text = ""; this.txtSourceObjectDefinition.Text = "";
this.txtSourceObjectDefinition.WordWrap = false; this.txtSourceObjectDefinition.WordWrap = false;
this.txtSourceObjectDefinition.vScroll += new BismNormalizer.TabularCompare.UI.SynchronizedScrollRichTextBox.vScrollEventHandler(this.txtSourceObjectDefinition_vScroll); this.txtSourceObjectDefinition.vScroll += new BismNormalizer.TabularCompare.UI.SynchronizedScrollRichTextBox.vScrollEventHandler(this.txtSourceObjectDefinition_vScroll);
this.txtSourceObjectDefinition.KeyUp += new System.Windows.Forms.KeyEventHandler(this.txtSourceObjectDefinition_KeyUp); this.txtSourceObjectDefinition.KeyUp += new System.Windows.Forms.KeyEventHandler(this.txtSourceObjectDefinition_KeyUp);
// //
// label4
//
this.label4.AutoSize = true;
this.label4.Location = new System.Drawing.Point(4, 1);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(122, 13);
this.label4.TabIndex = 0;
this.label4.Text = "Source Object Definition";
//
// txtTargetObjectDefinition // txtTargetObjectDefinition
// //
this.txtTargetObjectDefinition.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) this.txtTargetObjectDefinition.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
@ -495,33 +516,26 @@
| System.Windows.Forms.AnchorStyles.Right))); | System.Windows.Forms.AnchorStyles.Right)));
this.txtTargetObjectDefinition.BackColor = System.Drawing.Color.White; this.txtTargetObjectDefinition.BackColor = System.Drawing.Color.White;
this.txtTargetObjectDefinition.Font = new System.Drawing.Font("Consolas", 9.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.txtTargetObjectDefinition.Font = new System.Drawing.Font("Consolas", 9.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.txtTargetObjectDefinition.Location = new System.Drawing.Point(0, 16); this.txtTargetObjectDefinition.Location = new System.Drawing.Point(0, 25);
this.txtTargetObjectDefinition.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.txtTargetObjectDefinition.Name = "txtTargetObjectDefinition"; this.txtTargetObjectDefinition.Name = "txtTargetObjectDefinition";
this.txtTargetObjectDefinition.ReadOnly = true; this.txtTargetObjectDefinition.ReadOnly = true;
this.txtTargetObjectDefinition.Size = new System.Drawing.Size(313, 119); this.txtTargetObjectDefinition.Size = new System.Drawing.Size(469, 181);
this.txtTargetObjectDefinition.TabIndex = 2; this.txtTargetObjectDefinition.TabIndex = 2;
this.txtTargetObjectDefinition.Text = ""; this.txtTargetObjectDefinition.Text = "";
this.txtTargetObjectDefinition.WordWrap = false; this.txtTargetObjectDefinition.WordWrap = false;
this.txtTargetObjectDefinition.vScroll += new BismNormalizer.TabularCompare.UI.SynchronizedScrollRichTextBox.vScrollEventHandler(this.txtTargetObjectDefinition_vScroll); this.txtTargetObjectDefinition.vScroll += new BismNormalizer.TabularCompare.UI.SynchronizedScrollRichTextBox.vScrollEventHandler(this.txtTargetObjectDefinition_vScroll);
this.txtTargetObjectDefinition.KeyUp += new System.Windows.Forms.KeyEventHandler(this.txtTargetObjectDefinition_KeyUp); this.txtTargetObjectDefinition.KeyUp += new System.Windows.Forms.KeyEventHandler(this.txtTargetObjectDefinition_KeyUp);
// //
// label5
//
this.label5.AutoSize = true;
this.label5.Location = new System.Drawing.Point(3, 1);
this.label5.Name = "label5";
this.label5.Size = new System.Drawing.Size(119, 13);
this.label5.TabIndex = 1;
this.label5.Text = "Target Object Definition";
//
// ComparisonControl // ComparisonControl
// //
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleDimensions = new System.Drawing.SizeF(9F, 20F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.scDifferenceResults); this.Controls.Add(this.scDifferenceResults);
this.Controls.Add(this.pnlHeader); this.Controls.Add(this.pnlHeader);
this.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.Name = "ComparisonControl"; this.Name = "ComparisonControl";
this.Size = new System.Drawing.Size(653, 565); this.Size = new System.Drawing.Size(980, 869);
this.Load += new System.EventHandler(this.BismNormalizer_Load); this.Load += new System.EventHandler(this.BismNormalizer_Load);
this.pnlHeader.ResumeLayout(false); this.pnlHeader.ResumeLayout(false);
this.pnlHeader.PerformLayout(); this.pnlHeader.PerformLayout();
@ -534,18 +548,19 @@
this.toolStrip1.ResumeLayout(false); this.toolStrip1.ResumeLayout(false);
this.toolStrip1.PerformLayout(); this.toolStrip1.PerformLayout();
this.scDifferenceResults.Panel1.ResumeLayout(false); this.scDifferenceResults.Panel1.ResumeLayout(false);
this.scDifferenceResults.Panel1.PerformLayout();
this.scDifferenceResults.Panel2.ResumeLayout(false); this.scDifferenceResults.Panel2.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.scDifferenceResults)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.scDifferenceResults)).EndInit();
this.scDifferenceResults.ResumeLayout(false); this.scDifferenceResults.ResumeLayout(false);
this.pnlProgressBar.ResumeLayout(false);
this.pnlProgressBar.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.treeGridComparisonResults)).EndInit();
this.scObjectDefinitions.Panel1.ResumeLayout(false); this.scObjectDefinitions.Panel1.ResumeLayout(false);
this.scObjectDefinitions.Panel1.PerformLayout(); this.scObjectDefinitions.Panel1.PerformLayout();
this.scObjectDefinitions.Panel2.ResumeLayout(false); this.scObjectDefinitions.Panel2.ResumeLayout(false);
this.scObjectDefinitions.Panel2.PerformLayout(); this.scObjectDefinitions.Panel2.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.scObjectDefinitions)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.scObjectDefinitions)).EndInit();
this.scObjectDefinitions.ResumeLayout(false); this.scObjectDefinitions.ResumeLayout(false);
this.pnlProgressBar.ResumeLayout(false);
this.pnlProgressBar.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.treeGridComparisonResults)).EndInit();
this.ResumeLayout(false); this.ResumeLayout(false);
} }
@ -559,9 +574,6 @@
private System.Windows.Forms.Label label4; private System.Windows.Forms.Label label4;
private SynchronizedScrollRichTextBox txtTargetObjectDefinition; private SynchronizedScrollRichTextBox txtTargetObjectDefinition;
private System.Windows.Forms.Label label5; private System.Windows.Forms.Label label5;
private System.Windows.Forms.Panel pnlProgressBar;
private System.Windows.Forms.ProgressBar progressBar;
private System.Windows.Forms.Label lblProgressBar;
private System.Windows.Forms.Panel pnlHeader; private System.Windows.Forms.Panel pnlHeader;
public System.Windows.Forms.ImageList TreeGridImageList; public System.Windows.Forms.ImageList TreeGridImageList;
private System.Windows.Forms.SplitContainer spltSourceTarget; private System.Windows.Forms.SplitContainer spltSourceTarget;
@ -588,5 +600,8 @@
private System.Windows.Forms.ToolStripButton btnOptions; private System.Windows.Forms.ToolStripButton btnOptions;
private System.Windows.Forms.ToolStripButton btnReportDifferences; private System.Windows.Forms.ToolStripButton btnReportDifferences;
private System.Windows.Forms.ToolStripMenuItem hideSkipObjectsWithSameDefinitionToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem hideSkipObjectsWithSameDefinitionToolStripMenuItem;
private System.Windows.Forms.StatusStrip pnlProgressBar;
private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel1;
private System.Windows.Forms.ToolStripProgressBar progressBar;
} }
} }

View File

@ -131,7 +131,7 @@ namespace BismNormalizer.TabularCompare.UI
//Blank file not saved to yet //Blank file not saved to yet
return; return;
} }
_comparisonInfo = ComparisonInfo.DeserializeBsmnFile(fileName); _comparisonInfo = ComparisonInfo.DeserializeBsmnFile(fileName, "BISM Normalizer");
PopulateSourceTargetTextBoxes(); PopulateSourceTargetTextBoxes();
} }

View File

@ -194,6 +194,9 @@
3gAAAABJRU5ErkJggg== 3gAAAABJRU5ErkJggg==
</value> </value>
</data> </data>
<metadata name="pnlProgressBar.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>405, 17</value>
</metadata>
<metadata name="TreeGridImageList.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> <metadata name="TreeGridImageList.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value> <value>17, 17</value>
</metadata> </metadata>
@ -201,354 +204,353 @@
<value> <value>
AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w
LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0
ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAAA4 ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAADy
UQAAAk1TRnQBSQFMAgEBFwEAAXwBAgF8AQIBEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA UAAAAk1TRnQBSQFMAgEBFwEAAZQBAgGUAQIBEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA
AwABYAMAAQEBAAEgBgABYP8AKwADnwH/A58B/wOfAf8DnwH/ZAADbgG7A4AB/4QAA58B/wOfAf8DnwH/ AwABYAMAAQEBAAEgBgABYP8AKwADnwH/A58B/wOfAf8DnwH/ZAADWwG7A4AB/4QAA58B/wOfAf8DnwH/
A58B/zAAAwcBCgNWAcEDLgFHEAADNAFUA1YBuwM6AWEQAAMHAQkDYAGZgAADoQH/A58B/wOfAf8DoQH/ A58B/zAAAwcBCgNWAcEDLgFHEAADNAFUA1YBuwM6AWEQAAMHAQkDTgGZgAADoQH/A58B/wOfAf8DoQH/
NwAB/wNTAa0QAANYAcADDAH8Az0BaRQAA4AB/wgAA4AB/wMUARoEAANVAYADUAF3ZAADoQH/A58B/wOf NwAB/wNTAa0QAANYAcADDwH8Az0BaRQAA4AB/wgAA4AB/wMTARoEAANHAYADQwF3ZAADoQH/A58B/wOf
Af8DnwH/GAADEgEZAyoBQRQAA0wBkQMAAf8MAAMEAQUDAAH/A0cBggMGAQgUAAN4Ad4DFAEaBAADUAF3 Af8DnwH/GAADEgEZAyoBQRQAA0wBkQMAAf8MAAMEAQUDAAH/A0cBggMGAQgUAANoAd4DEwEaBAADQwF3
A0wBbwQAA34B8wQAAzABQGAAA6EB/wOfAf8DnwH/A58B/xgAAzkBYAMAAf8DSwGOEAADIwE0AwAB/wNZ A0ABbwQAA3MB8wQAAyoBQGAAA6EB/wOfAf8DnwH/A58B/xgAAzkBYAMAAf8DSwGOEAADIwE0AwAB/wNZ
AcQDWQHSA1sB0ANaAcoDAAH/AxoBJRgAA2gBqgNnAaoMAANzAcwDewHmVAADoQH/A58B/wOfAf8DnwH/ AcQDWQHSA1sB0ANaAcoDAAH/AxoBJRgAA1UBqgNVAaoMAANiAcwDbwHmVAADoQH/A58B/wOfAf8DnwH/
A58B/wOhAf8DnwH/A58B/wOfAf8DnwH/A6EB/wOfAf8DnwH/A58B/wgAAzwBZwMAAf8DPwFvCAADWQHJ A58B/wOhAf8DnwH/A58B/wOfAf8DnwH/A6EB/wOfAf8DnwH/A58B/wgAAzwBZwMAAf8DPwFvCAADWQHJ
AyoBQANZAcQDAAH/A1cBxQNXAcUDAAH/A1kB1xwAA0UBYgOAAf8MAAM9AVUDYAGZVAADnwH/A6EB/wOf AyoBQANZAcQDAAH/A1cBxQNXAcUDAAH/A1kB1xwAAzoBYgOAAf8MAAM1AVUDTgGZVAADnwH/A6EB/wOf
Af8DnwH/A6EB/wOhAf8DoQH/A58B/wOhAf8DoQH/A6EB/wOfAf8DoQH/A58B/wwAA0kBiQMAAf8EAAM4 Af8DnwH/A6EB/wOhAf8DoQH/A58B/wOhAf8DoQH/A6EB/wOfAf8DoQH/A58B/wwAA0kBiQMAAf8EAAM4
AVwDAAH/AwoBDgNEAXkDAAH/CwAB/wNKAY0cAAMUARoDgAH/DAADgAH/A2QBolQAA58B/wOfAf8DoQH/ AVwDAAH/AwoBDgNEAXkDAAH/CwAB/wNKAY0cAAMTARoDgAH/DAADgAH/A1IBolQAA58B/wOfAf8DoQH/
A58B/wOhAf8DnwH/A6EB/wOfAf8DnwH/A58B/wOfAf8DnwH/A6EB/wOfAf8QAANJAe8DWQHJAx4B+gNI A58B/wOhAf8DnwH/A6EB/wOfAf8DnwH/A58B/wOfAf8DnwH/A6EB/wOfAf8QAANMAe8DWQHJAyEB+gNI
AYgEAAMfASwDAAH/Ax4BKwMdASoDAAH/Ax0BKSAAA4AB/wMqATgEAANdAZEDgAH/BAADYAGZA3sB6kwA AYgEAAMfASwDAAH/Ax4BKwMdASoDAAH/Ax0BKSAAA4AB/wMmATgEAANNAZEDgAH/BAADTgGZA28B6kwA
A58B/wOhAf8DnwH/A6EB/wOfAf8DoQH/A6EB/wOfAf8DoQH/A58B/wOfAf8DoQH/A58B/wOfAf8QAAMx A58B/wOhAf8DnwH/A6EB/wOfAf8DoQH/A6EB/wOfAf8DoQH/A58B/wOfAf8DoQH/A58B/wOfAf8QAAMx
AU4DAAH/A1oB1QwAAx4B+gNKAYsDSgGKAygB+CQAA3wB7gNQAXd4AAOfAf8DnwH/A58B/wOfAf8YAAMl AU4DAAH/A1oB1QwAAyEB+gNKAYsDSgGKAzEB+CQAA3IB7gNDAXd4AAOfAf8DnwH/A58B/wOfAf8YAAMl
ATcDQgF0AzgBXQM7AWUDAAH/A1MBsAMoAT0DQgF2Aw4BEwNCAXUDAAH/AwAB/wNIAYYgAANJAWsDewHm ATcDQgF0AzgBXQM7AWUDAAH/A1MBsAMoAT0DQgF2Aw4BEwNCAXUDAAH/AwAB/wNIAYYgAAM+AWsDbwHm
A3gB3QNVAYB0AAOfAf8DnwH/A6EB/wOhAf8YAANKAYwDAAH/AwAB/wMAAf4DAAH+AwwB/AMAAf8DAAH/ A2kB3QNHAYB0AAOfAf8DnwH/A6EB/wOhAf8YAANKAYwDAAH/AwAB/wMAAf4DAAH+Aw8B/AMAAf8DAAH/
A1YBuwMMARADAAH/AwAB/wMdASooAAN/Afd4AAOhAf8DnwH/A58B/wOhAf8YAAMEAQUDCQEMAwABAQMK A1YBuwMMARADAAH/AwAB/wMdASooAAN3Afd4AAOhAf8DnwH/A58B/wOhAf8YAAMEAQUDCQEMAwABAQMK
AQ0DAAH/AzsBZAQAAwUBBwMPARQDBAQGAQgDBwEJLAADfAHueAADoQH/A6EB/wOhAf8DnwH/JAADAgED AQ0DAAH/AzsBZAQAAwUBBwMPARQDBAQGAQgDBwEJLAADcgHueAADoQH/A6EB/wOhAf8DnwH/JAADAgED
AwAB/wM3AVtEAANHAWYDGgEiA3MBzHAAA58B/wOfAf8DnwH/A6EB/3gAAz0BVQNJAWt4AAMBAQL/AN0A AwAB/wM3AVtEAAM8AWYDGAEiA2IBzHAAA58B/wOfAf8DnwH/A6EB/3gAAzUBVQM+AWt4AAMBAQL/AN0A
Af4B8wHyAf8B/gHzAfIB/wH+AfMB8gH/Af4B8wHyAf8B/gHzAfIB/wH+AfMB8gH/Af4B8wHyAf8B/gHz Af4B8wHyAf8B/gHzAfIB/wH+AfMB8gH/Af4B8wHyAf8B/gHzAfIB/wH+AfMB8gH/Af4B8wHyAf8B/gHz
AfIB/wH+AfMB8gH/Af4B8wHyAf8B/gHzAfIB/wH+AfMB8gH/Af4B8wHyAf8B/gHzAfIB/wH+AfMB8gH/ AfIB/wH+AfMB8gH/Af4B8wHyAf8B/gHzAfIB/wH+AfMB8gH/Af4B8wHyAf8B/gHzAfIB/wH+AfMB8gH/
Af4B8wHyAf8EAAMqAf8DKgH/AyoB/wMqAf8DKgH/AyoB/wMqAf8DKgH/EAABwAGVAUkB/wHAAZUBSQH/ Af4B8wHyAf8EAAMnAf8DJwH/AycB/wMnAf8DJwH/AycB/wMnAf8DJwH/EAABwAGVAUYB/wHAAZUBRgH/
hAAB/gHzAfIB/wMdAf8DHQH/Ax0B/wMdAf8DHQH/Ax0B/wMdAf8DHQH/Ax0B/wMdAf8DHQH/Ax0B/wMd hAAB/gHzAfIB/wMaAf8DGgH/AxoB/wMaAf8DGgH/AxoB/wMaAf8DGgH/AxoB/wMaAf8DGgH/AxoB/wMa
Af8DHQH/Af4B8wHyAf8EAAMqAf8D+AH/A/gB/wP4Af8D+AH/A/gB/wP4Af8DKgH/DAABwAGVAUkB/wGh Af8DGgH/Af4B8wHyAf8EAAMnAf8D+AH/A/gB/wP4Af8D+AH/A/gB/wP4Af8DJwH/DAABwAGVAUYB/wGh
ATwBAAH/AcABlQFJAf8MAAPAAf8DkgH/A+oB/yAAA2MB6APAAf8UAAP+Af8D8QH/A8cB/wOPAf8DgAH/ ATkBAAH/AcABlQFGAf8MAAPAAf8DkgH/A+oB/yAAA18B6APAAf8UAAP+Af8D8QH/A8cB/wOPAf8DgAH/
A6IB/wPsAf8UAAH+AfMB8gH/Ax0B/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5 A6IB/wPsAf8UAAH+AfMB8gH/AxoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5
AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wMdAf8B/gHzAfIB/wQAAyoB/wP4Af8D+AH/ AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wMaAf8B/gHzAfIB/wQAAycB/wP4Af8D+AH/
A/gB/wP4Af8D+gH/A/wB/wPQAf8IAAHAAZUBSQH/AaEBPAEAAf8BwAGVAUkB/xAAA5IB/wOSAf8DkgH/ A/gB/wP4Af8D+gH/A/wB/wPQAf8IAAHAAZUBRgH/AaEBOQEAAf8BwAGVAUYB/xAAA5IB/wOSAf8DkgH/
A2MB6BgAA+sB/wOwAf8DDQEREAAD/QH/A9YB/wOVAf8DlQH/A50B/wOWAf8DiQH/A1MB/wPVAf8QAAH+ A18B6BgAA+sB/wOwAf8DDQEREAAD/QH/A9YB/wOVAf8DlQH/A50B/wOWAf8DiQH/A1AB/wPVAf8QAAH+
AfMB8gH/Ax0B/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5 AfMB8gH/AxoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5
AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wMdAf8B/gHzAfIB/wQAAyoB/wP4Af8D+AH/A/gB/wP8Af8BxgGf AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wMaAf8B/gHzAfIB/wQAAycB/wP4Af8D+AH/A/gB/wP8Af8BxgGf
AVkB/wGhATwBAAH/AaEBPAEAAf8BoQE8AQAB/wGzAVwBFQH/AaEBPAEAAf8BwAGVAUkB/xQAA+sB/wOQ AVYB/wGhATkBAAH/AaEBOQEAAf8BoQE5AQAB/wGzAVkBEgH/AaEBOQEAAf8BwAGVAUYB/xQAA+sB/wOQ
Af8DkgH/A5IB/wNSAakMAAMQARYD3wH/A50B/wMxAU0UAAPXAf8DogH/A6IB/wOiAf8DnQH/A5wB/wOc Af8DkgH/A5IB/wNSAakMAAMQARYD3wH/A50B/wMxAU0UAAPXAf8DogH/A6IB/wOiAf8DnQH/A5wB/wOc
Af8DnAH/A10B/wPSAf8MAAH+AfMB8gH/Ax0B/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5 Af8DnAH/A1oB/wPSAf8MAAH+AfMB8gH/AxoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5
AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wMdAf8B/gHzAfIB/wQAAyoB/wP4 AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wMaAf8B/gHzAfIB/wQAAycB/wP4
Af8D+AH/A/oB/wHGAZ8BWQH/AbcBZAEkAf8B8gHwAesB/wP4Af8B8gHwAesB/wG3AWQBJAH/AbMBXAEV Af8D+AH/A/oB/wHGAZ8BVgH/AbcBYQEhAf8B8gHwAesB/wP4Af8B8gHwAesB/wG3AWEBIQH/AbMBWQES
Af8cAANdAcoDkgH/A5AB/wOgAf8DMQFNBAADDQERA8AB/wOSAf8DUgGpFAAD9AH/A64B/wOuAf8DsAH/ Af8cAANdAcoDkgH/A5AB/wOgAf8DMQFNBAADDQERA8AB/wOSAf8DUgGpFAAD9AH/A64B/wOuAf8DsAH/
A7AB/wOuAf8DqAH/A6IB/wOcAf8DnAH/A1MB/wPsAf8IAAH+AfMB8gH/Ax0B/wH5AuoB/wH5AuoB/wH5 A7AB/wOuAf8DqAH/A6IB/wOcAf8DnAH/A1AB/wPsAf8IAAH+AfMB8gH/AxoB/wH5AuoB/wH5AuoB/wH5
AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wMd AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wMa
Af8B/gHzAfIB/wQAAyoB/wP4Af8D+AH/A/wB/wGhATwBAAH/AfIB8AHrAf8D+AH/A/gB/wP4Af8B8gHw Af8B/gHzAfIB/wQAAycB/wP4Af8D+AH/A/wB/wGhATkBAAH/AfIB8AHrAf8D+AH/A/gB/wP4Af8B8gHw
AesB/wGhATwBAAH/A8QB/wMqAf8DKgH/FAADVgGrA5AB/wOSAf8DnQH/Az4BawPAAf8DkAH/A2MB6AMD AesB/wGhATkBAAH/A8QB/wMnAf8DJwH/FAADVgGrA5AB/wOSAf8DnQH/Az4BawPAAf8DkAH/A18B6AMD
AQQUAAPdAf8DvAH/A8IB/wPGAf8DxwH/A8EB/wO8Af8DrgH/A6IB/wOcAf8DiQH/A6IB/wgAAf4B8wHy AQQUAAPdAf8DvAH/A8IB/wPGAf8DxwH/A8EB/wO8Af8DrgH/A6IB/wOcAf8DiQH/A6IB/wgAAf4B8wHy
Af8DHQH/AfkC6gH/AfkC6gH/AfkC6gH/AfkC6gH/AfkC6gH/AfkC6gH/AfkC6gH/AfkC6gH/AfkC6gH/ Af8DGgH/AfkC6gH/AfkC6gH/AfkC6gH/AfkC6gH/AfkC6gH/AfkC6gH/AfkC6gH/AfkC6gH/AfkC6gH/
AfkC6gH/AfkC6gH/AfkC6gH/Ax0B/wH+AfMB8gH/BAADKgH/A/gB/wP4Af8D/QH/AaEBPAEAAf8D+AH/ AfkC6gH/AfkC6gH/AfkC6gH/AxoB/wH+AfMB8gH/BAADJwH/A/gB/wP4Af8D/QH/AaEBOQEAAf8D+AH/
A/gB/wP4Af8D+AH/A/gB/wGhATwBAAH/A/0B/wP4Af8DKgH/GAADPgFrA50B/wOSAf8DkAH/A5IB/wPr A/gB/wP4Af8D+AH/A/gB/wGhATkBAAH/A/0B/wP4Af8DJwH/GAADPgFrA50B/wOSAf8DkAH/A5IB/wPr
Af8DAwQEAQUUAAPWAf8DwgH/A/4B/wP+Af8D/gH/A/0B/wP8Af8D/AH/A/wB/wP6Af8DjwH/A4AB/wgA Af8DAwQEAQUUAAPWAf8DwgH/A/4B/wP+Af8D/gH/A/0B/wP8Af8D/AH/A/wB/wP6Af8DjwH/A4AB/wgA
Af4B8wHyAf8DHQH/AfkC6gH/AfkC6gH/AfkC6gH/AfkC6gH/AfkC6gH/AfkC6gH/AfkC6gH/AfkC6gH/ Af4B8wHyAf8DGgH/AfkC6gH/AfkC6gH/AfkC6gH/AfkC6gH/AfkC6gH/AfkC6gH/AfkC6gH/AfkC6gH/
AfkC6gH/AfkC6gH/AfkC6gH/AfkC6gH/Ax0B/wH+AfMB8gH/BAADKgH/A/gB/wP4Af8D/AH/AaEBPAEA AfkC6gH/AfkC6gH/AfkC6gH/AfkC6gH/AxoB/wH+AfMB8gH/BAADJwH/A/gB/wP4Af8D/AH/AaEBOQEA
Af8B8gHwAesB/wP4Af8D+AH/A/gB/wHyAfAB6wH/AaEBPAEAAf8D/AH/A/gB/wMqAf8cAANcAckDkgH/ Af8B8gHwAesB/wP4Af8D+AH/A/gB/wHyAfAB6wH/AaEBOQEAAf8D/AH/A/gB/wMnAf8cAANcAckDkgH/
A5AB/wOdAf8DDQERHAAD1gH/A88N/wP+Af8D/gH/A/0B/wP8Af8D+wH/A48B/wOOAf8IAAH+AfMB8gH/ A5AB/wOdAf8DDQERHAAD1gH/A88N/wP+Af8D/gH/A/0B/wP8Af8D+wH/A48B/wOOAf8IAAH+AfMB8gH/
Ax0B/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5 AxoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5
AuoB/wH5AuoB/wH5AuoB/wMdAf8B/gHzAfIB/wQAAyoB/wMqAf8DKgH/A2QB/wHGAZ8BWQH/AbkBiAE3 AuoB/wH5AuoB/wH5AuoB/wMaAf8B/gHzAfIB/wQAAycB/wMnAf8DJwH/A2EB/wHGAZ8BVgH/AbkBiAE0
Af8B8gHwAesB/wP4Af8B8gHwAesB/wG5AYgBNwH/AcYBnwFZAf8D+gH/A/gB/wMqAf8YAANSAakDkgH/ Af8B8gHwAesB/wP4Af8B8gHwAesB/wG5AYgBNAH/AcYBnwFWAf8D+gH/A/gB/wMnAf8YAANSAakDkgH/
A5IB/wOQAf8DkgH/A1wByRAAAwsBDwgAA+kB/wPZAf8D7AH/A/AB/wPwAf8D7AH/A+EB/wPXAf8DwAH/ A5IB/wOQAf8DkgH/A1wByRAAAwsBDwgAA+kB/wPZAf8D7AH/A/AB/wPwAf8D7AH/A+EB/wPXAf8DwAH/
A6gB/wOPAf8DxgH/CAAB/gHzAfIB/wMdAf8B+QLqAf8B+QLqAf8B+QLqAf8B+QLqAf8B+QLqAf8B+QLq A6gB/wOPAf8DxgH/CAAB/gHzAfIB/wMaAf8B+QLqAf8B+QLqAf8B+QLqAf8B+QLqAf8B+QLqAf8B+QLq
Af8B+QLqAf8B+QLqAf8B+QLqAf8B+QLqAf8B+QLqAf8B+QLqAf8DHQH/Af4B8wHyAf8YAAHGAZ8BWQH/ Af8B+QLqAf8B+QLqAf8B+QLqAf8B+QLqAf8B+QLqAf8B+QLqAf8DGgH/Af4B8wHyAf8YAAHGAZ8BVgH/
AaEBPAEAAf8BoQE8AQAB/wGhATwBAAH/AcYBnwFZAf8D/AH/A/gB/wP4Af8DKgH/FAADXAHJA5IB/wOQ AaEBOQEAAf8BoQE5AQAB/wGhATkBAAH/AcYBnwFWAf8D/AH/A/gB/wP4Af8DJwH/FAADXAHJA5IB/wOQ
Af8DnQH/Az4BawPAAf8DkgH/A0oBjBgAA/cB/wPZAf8D7AH/A/EB/wPwAf8D7AH/A+AB/wPWAf8DwAH/ Af8DnQH/Az4BawPAAf8DkgH/A0oBjBgAA/cB/wPZAf8D7AH/A/EB/wPwAf8D7AH/A+AB/wPWAf8DwAH/
A6gB/wOcAf8D8AH/CAAB/gHzAfIB/wMdAf8B+QLqAf8B+QLqAf8B+QLqAf8B+QLqAf8B+QLqAf8B+QLq A6gB/wOcAf8D8AH/CAAB/gHzAfIB/wMaAf8B+QLqAf8B+QLqAf8B+QLqAf8B+QLqAf8B+QLqAf8B+QLq
Af8B+QLqAf8B+QLqAf8B+QLqAf8B+QLqAf8B+QLqAf8B+QLqAf8DHQH/Af4B8wHyAf8cAAPEAf8D/QH/ Af8B+QLqAf8B+QLqAf8B+QLqAf8B+QLqAf8B+QLqAf8B+QLqAf8DGgH/Af4B8wHyAf8cAAPEAf8D/QH/
A/wB/wP6Af8D+AH/A/gB/wP4Af8DKgH/EAAD6gH/A5IB/wOQAf8DkAH/A1IBqQQAAw0BEQPgAf8DoAH/ A/wB/wP6Af8D+AH/A/gB/wP4Af8DJwH/EAAD6gH/A5IB/wOQAf8DkAH/A1IBqQQAAw0BEQPgAf8DoAH/
AzEBTRQAA/4B/wPsAf8D4AH/A/EB/wPxAf8D6gH/A+IB/wPSAf8DwQH/A6gB/wPXAf8D/gH/CAAB/gHz AzEBTRQAA/4B/wPsAf8D4AH/A/EB/wPxAf8D6gH/A+IB/wPSAf8DwQH/A6gB/wPXAf8D/gH/CAAB/gHz
AfIB/wMdAf8DHQH/Ax0B/wMdAf8DHQH/Ax0B/wMdAf8DHQH/Ax0B/wMdAf8DHQH/Ax0B/wMdAf8DHQH/ AfIB/wMaAf8DGgH/AxoB/wMaAf8DGgH/AxoB/wMaAf8DGgH/AxoB/wMaAf8DGgH/AxoB/wMaAf8DGgH/
Af4B8wHyAf8cAAMqAf8D+AH/A/gB/wP4Af8D+AH/AyoB/wMqAf8DigH/EAADkgH/A5IB/wOQAf8DYwHo Af4B8wHyAf8cAAMnAf8D+AH/A/gB/wP4Af8D+AH/AycB/wMnAf8DigH/EAADkgH/A5IB/wOQAf8DXwHo
EAAD6gH/A7AB/wMNAREUAAP9Af8D7AH/A90B/wPjAf8D5gH/A9wB/wPLAf8DuwH/A9YB/wP9Af8MAAH+ EAAD6gH/A7AB/wMNAREUAAP9Af8D7AH/A90B/wPjAf8D5gH/A9wB/wPLAf8DuwH/A9YB/wP9Af8MAAH+
AfMB8gH/Ax0B/wMdAf8DHQH/Ax0B/wMdAf8DHQH/Ax0B/wMdAf8DHQH/Ax0B/wMdAf8DHQH/Ax0B/wMd AfMB8gH/AxoB/wMaAf8DGgH/AxoB/wMaAf8DGgH/AxoB/wMaAf8DGgH/AxoB/wMaAf8DGgH/AxoB/wMa
Af8B/gHzAfIB/xwAAyoB/wP4Af8D+AH/A/gB/wP4Af8DKgH/A4oB/xQAA8AB/wOSAf8D6gH/GAADYwHo Af8B/gHzAfIB/xwAAycB/wP4Af8D+AH/A/gB/wP4Af8DJwH/A4oB/xQAA8AB/wOSAf8D6gH/GAADXwHo
A8AB/xgAA/0B/wP3Af8D6QH/A9wB/wPVAf8D4gH/A+8B/wP+Af8QAAH+AfMB8gH/Ax0B/wMdAf8DHQH/ A8AB/xgAA/0B/wP3Af8D6QH/A9wB/wPVAf8D4gH/A+8B/wP+Af8QAAH+AfMB8gH/AxoB/wMaAf8DGgH/
Ax0B/wMdAf8DHQH/Ax0B/wMdAf8DHQH/Ax0B/wMdAf8DHQH/Ax0B/wMdAf8B/gHzAfIB/xwAAyoB/wMq AxoB/wMaAf8DGgH/AxoB/wMaAf8DGgH/AxoB/wMaAf8DGgH/AxoB/wMaAf8B/gHzAfIB/xwAAycB/wMn
Af8DKgH/AyoB/wMqAf8DigH/EwABAXgAAf4B8wHyAf8B/gHzAfIB/wH+AfMB8gH/Af4B8wHyAf8B/gHz Af8DJwH/AycB/wMnAf8DigH/EwABAXgAAf4B8wHyAf8B/gHzAfIB/wH+AfMB8gH/Af4B8wHyAf8B/gHz
AfIB/wH+AfMB8gH/Af4B8wHyAf8B/gHzAfIB/wH+AfMB8gH/Af4B8wHyAf8B/gHzAfIB/wH+AfMB8gH/ AfIB/wH+AfMB8gH/Af4B8wHyAf8B/gHzAfIB/wH+AfMB8gH/Af4B8wHyAf8B/gHzAfIB/wH+AfMB8gH/
Af4B8wHyAf8B/gHzAfIB/wH+AfMB8gH/Af4B8wHyAf//AAEAAf8BAAP/AQAD/wEAA/8BAAP/AQAD/wEA Af4B8wHyAf8B/gHzAfIB/wH+AfMB8gH/Af4B8wHyAf//AAEAAf8BAAP/AQAD/wEAA/8BAAP/AQAD/wEA
A/8BAAP/AQAD/wEAA/8BAAP/AQAD/wEAA/8BAAP/AQAD/wEAA/8BAAL/AysBQgMrAUIDMwFSAzcBWgM3 A/8BAAP/AQAD/wEAA/8BAAP/AQAD/wEAA/8BAAP/AQAD/wEAA/8BAAL/AysBQgMrAUIDMwFSAzcBWgM3
AVsDSgGJA0sBjgNKAY0DPQFnAzcBWwM3AVsDNAFUAycBOgMRARcIAAMrAUIDKwFCAysBQgMyAVADNwFa AVsDSgGJA0sBjgNKAY0DPQFnAzcBWwM3AVsDNAFUAycBOgMRARcIAAMrAUIDKwFCAysBQgMyAVADNwFa
A0gBgwNLAY4DSgGNA0QBegM3AVsDNwFbFAABJQG5AdMB/wEAAYwBqQH/AQABjAGpAf8BAAGMAakB/wEA A0gBgwNLAY4DSgGNA0QBegM3AVsDNwFbFAABIgG5AdMB/wEAAYwBqQH/AQABjAGpAf8BAAGMAakB/wEA
AYwBqQH/AQABjAGpAf8BAAGMAakB/wEAAYwBqQH/AQABjAGpAf8BAAGMAakB/wEAAYwBqQH/AQABjAGp AYwBqQH/AQABjAGpAf8BAAGMAakB/wEAAYwBqQH/AQABjAGpAf8BAAGMAakB/wEAAYwBqQH/AQABjAGp
Af8BAAGMAakB/wEAAYwBqQH/AQABjAGpAf8BJQG5AdMB/wEAAbkB0wH/AQABjAGpAf8BAAGMAakB/wEA Af8BAAGMAakB/wEAAYwBqQH/AQABjAGpAf8BIgG5AdMB/wEAAbkB0wH/AQABjAGpAf8BAAGMAakB/wEA
AYwBqQH/AQABjAGpAf8BAAGMAakB/wEAAYwBqQH/AQABjAGpAf8BAAGMAakB/wEAAYwBqQH/AQABjAGp AYwBqQH/AQABjAGpAf8BAAGMAakB/wEAAYwBqQH/AQABjAGpAf8BAAGMAakB/wEAAYwBqQH/AQABjAGp
Af8BAAGMAakB/wEAAYwBqQH/AQABjAGpAf8BAAGMAakB/wEAAbkB0wH/AysBQgMdAf8DHQH/Ax0B/wMd Af8BAAGMAakB/wEAAYwBqQH/AQABjAGpAf8BAAGMAakB/wEAAbkB0wH/AysBQgMaAf8DGgH/AxoB/wMa
Af8DHQH/Ax0B/wMdAf8DQAFxAx0B/wMdAf8DNAH/A1wB6gNWAbQDPgFrBAADLgFIAyUB/wMlAf8DJQH/ Af8DGgH/AxoB/wMaAf8DQAFxAxoB/wMaAf8DMQH/A1wB6gNWAbQDPgFrBAADLgFIAyIB/wMiAf8DIgH/
AyUB/wMlAf8DJQH/AyUB/wMlAf8DJQH/AzcBWxQAARQBtAHRAf8BAwHJAekB/wEAAcYB8QH/AQABwgHw AyIB/wMiAf8DIgH/AyIB/wMiAf8DIgH/AzcBWxQAAREBtAHRAf8BAAHJAekB/wEAAcYB8QH/AQABwgHw
Af8BAAHBAfAB/wEAAcAB8AH/AQABwQHwAf8BAAHBAfAB/wEAAcEB8AH/AQABwQHwAf8BAAHCAfAB/wEA Af8BAAHBAfAB/wEAAcAB8AH/AQABwQHwAf8BAAHBAfAB/wEAAcEB8AH/AQABwQHwAf8BAAHCAfAB/wEA
AcMB8AH/AQABwwHwAf8BAAHEAfEB/wEAAcMB5AH/ARQBtAHRAf8BAAG0AdEB/wEAAckB6QH/AQABxgHx AcMB8AH/AQABwwHwAf8BAAHEAfEB/wEAAcMB5AH/AREBtAHRAf8BAAG0AdEB/wEAAckB6QH/AQABxgHx
Af8BAAHCAfAB/wEAAcEB8AH/AQABwAHwAf8BAAHBAfAB/wEAAcEB8AH/AQABwQHwAf8BAAHBAfAB/wEA Af8BAAHCAfAB/wEAAcEB8AH/AQABwAHwAf8BAAHBAfAB/wEAAcEB8AH/AQABwQHwAf8BAAHBAfAB/wEA
AcIB8AH/AQABwwHwAf8BAAHDAfAB/wEAAcQB8QH/AQABwwHkAf8BAAG0AdEB/wMrAUIDHQH/Ax0B/wMd AcIB8AH/AQABwwHwAf8BAAHDAfAB/wEAAcQB8QH/AQABwwHkAf8BAAG0AdEB/wMrAUIDGgH/AxoB/wMa
Af8DHQH/Ax0B/wMdAf8DHQH/A0gBgwMdAf8DHQH/Ax0B/wMdAf8DHQH/A0oBjQM/AW0DNQFVAyUB/wH5 Af8DGgH/AxoB/wMaAf8DGgH/A0gBgwMaAf8DGgH/AxoB/wMaAf8DGgH/A0oBjQM/AW0DNQFVAyIB/wH5
AuoB/wH5AuoB/wH5AuoB/wMlAf8B+QLqAf8B+QLqAf8B+QLqAf8DJQH/AzcBWwM3AVsDNwFbDAABTgHI AuoB/wH5AuoB/wH5AuoB/wMiAf8B+QLqAf8B+QLqAf8B+QLqAf8DIgH/AzcBWwM3AVsDNwFbDAABSwHI
AdwB/wEAAa4BzwH/AQABzQHyAf8BAAHIAfEB/wEAAcUB8QH/AQABxAHxAf8BAAHDAfAB/wMAAf8DAAH/ AdwB/wEAAa4BzwH/AQABzQHyAf8BAAHIAfEB/wEAAcUB8QH/AQABxAHxAf8BAAHDAfAB/wMAAf8DAAH/
AQABxgHxAf8BAAHIAfEB/wEAAcoB8gH/AQABygHyAf8BAAHMAfEB/wEAAasBzQH/AU4ByAHcAv8BAAL/ AQABxgHxAf8BAAHIAfEB/wEAAcoB8gH/AQABygHyAf8BAAHMAfEB/wEAAasBzQH/AUsByAHcAv8BAAL/
AQABrgHPAf8BAAHNAfIB/wEAAcgB8QH/AQABxQHxAf8BAAHEAfEB/wEAAcMB8AH/AwAB/wMAAf8BAAHG AQABrgHPAf8BAAHNAfIB/wEAAcgB8QH/AQABxQHxAf8BAAHEAfEB/wEAAcMB8AH/AwAB/wMAAf8BAAHG
AfEB/wEAAcgB8QH/AQABygHyAf8BAAHKAfIB/wEAAcwB8QH/AQABqwHNAv8BAAL/AysBQgMdAf8DHQH/ AfEB/wEAAcgB8QH/AQABygHyAf8BAAHKAfIB/wEAAcwB8QH/AQABqwHNAv8BAAL/AysBQgMaAf8DGgH/
Ax0B/wMdAf8DHQH/Ax0B/wMdAf8DTAGTAx0B/wMdAf8DHQH/Ax0B/wMdAf8DHQH/AzcBWwM2AVgDJQH/ AxoB/wMaAf8DGgH/AxoB/wMaAf8DTAGTAxoB/wMaAf8DGgH/AxoB/wMaAf8DGgH/AzcBWwM2AVgDIgH/
AfkC6gH/AfkC6gH/AfkC6gH/AyUB/wH5AuoB/wH5AuoB/wH5AuoB/wMlAf8DNwFbAyUB/wNAAW4MAAHi AfkC6gH/AfkC6gH/AfkC6gH/AyIB/wH5AuoB/wH5AuoB/wH5AuoB/wMiAf8DNwFbAyIB/wNAAW4MAAHi
Ae4B8gH/ARQBtAHRAf8BBAHGAeQB/wEEAdEB8wH/AQABzQHyAf8BAAHLAfIB/wEAAcoB8gH/AwAB/wMA Ae4B8gH/AREBtAHRAf8BAQHGAeQB/wEBAdEB8wH/AQABzQHyAf8BAAHLAfIB/wEAAcoB8gH/AwAB/wMA
Af8BAAHNAfMB/wEEAdEB8wH/AQUB0gH0Af8BBgHTAfQB/wEDAcUB4wH/ARQBtAHRAf8B4gHuAfIC/wEA Af8BAAHNAfMB/wEBAdEB8wH/AQIB0gH0Af8BAwHTAfQB/wEAAcUB4wH/AREBtAHRAf8B4gHuAfIC/wEA
Av8BAAG0AdEB/wEAAcYB5AH/AQAB0QHzAf8BAAHNAfIB/wEAAcsB8gH/AQABygHyAf8DAAH/AwAB/wEA Av8BAAG0AdEB/wEAAcYB5AH/AQAB0QHzAf8BAAHNAfIB/wEAAcsB8gH/AQABygHyAf8DAAH/AwAB/wEA
Ac0B8wH/AQAB0QHzAf8BAAHSAfQB/wEAAdMB9AH/AQABxQHjAf8BAAG0AdEC/wEAAv8DNQFVAx0B/wMd Ac0B8wH/AQAB0QHzAf8BAAHSAfQB/wEAAdMB9AH/AQABxQHjAf8BAAG0AdEC/wEAAv8DNQFVAxoB/wMa
Af8DHQH/A2IB6QMdAf8DHQH/Ax0B/wNRAZwDHQH/Ax0B/wMdAf8DHQH/Ax0B/wMdAf8DNwFbAzIBUAMl Af8DGgH/A2IB6QMaAf8DGgH/AxoB/wNRAZwDGgH/AxoB/wMaAf8DGgH/AxoB/wMaAf8DNwFbAzIBUAMi
Af8DJQH/AyUB/wMlAf8DJQH/AyUB/wMlAf8DJQH/AyUB/wM3AVsDJQH/A0oBihAAAYABzQHfAf8BAAGs Af8DIgH/AyIB/wMiAf8DIgH/AyIB/wMiAf8DIgH/AyIB/wM3AVsDIgH/A0oBihAAAYABzQHfAf8BAAGs
Ac0B/wESAdsB9AH/AQ4B2QH1Af8BCwHXAfUB/wEKAdYB9AH/AQoB1gH0Af8BDAHXAfUB/wEOAdkB9QH/ Ac0B/wEPAdsB9AH/AQsB2QH1Af8BCAHXAfUB/wEHAdYB9AH/AQcB1gH0Af8BCQHXAfUB/wELAdkB9QH/
AQ4B2QH1Af8BEAHbAfUB/wERAdoB8wH/AQABqgHLAf8BgAHNAd8B/wQAAf8BAAP/AQAC/wEAAawBzQH/ AQsB2QH1Af8BDQHbAfUB/wEOAdoB8wH/AQABqgHLAf8BgAHNAd8B/wQAAf8BAAP/AQAC/wEAAawBzQH/
AQAB2wH0Af8BAAHZAfUB/wEAAdcB9QH/AQAB1gH0Af8BAAHWAfQB/wEAAdcB9QH/AQAB2QH1Af8BAAHZ AQAB2wH0Af8BAAHZAfUB/wEAAdcB9QH/AQAB1gH0Af8BAAHWAfQB/wEAAdcB9QH/AQAB2QH1Af8BAAHZ
AfUB/wEAAdsB9QH/AQAB2gHzAf8BAAGqAcsC/wEAA/8BAAL/AzYBWAMdAf8DHQH/A10B0wNUAaYDXQHT AfUB/wEAAdsB9QH/AQAB2gHzAf8BAAGqAcsC/wEAA/8BAAL/AzYBWAMaAf8DGgH/A10B0wNUAaYDXQHT
Ax0B/wMdAf8DWgG9Ax0B/wMdAf8DHQH/Ax0B/wMdAf8DHQH/AzcBWwMxAU4DNwFaA0ABbgNKAY0DUgGk AxoB/wMaAf8DWgG9AxoB/wMaAf8DGgH/AxoB/wMaAf8DGgH/AzcBWwMxAU4DNwFaA0ABbgNKAY0DUgGk
A1wB6gNiAe8DYgHvAV8CXgHtA1wBzANIAYUDJQH/A0gBhQM3AVsDNwFbAzcBWwQAAeoB8gH1Af8BFAG0 A1wB6gNiAe8DYgHvA10B7QNcAcwDSAGFAyIB/wNIAYUDNwFbAzcBWwM3AVsEAAHqAfIB9QH/AREBtAHR
AdEB/wEJAcYB3wH/AR0B5gH4Af8BHAHkAfcB/wEbAeMB9wH/AQABRgFPAf8BAAFGAU8B/wEZAeIB9wH/ Af8BBgHGAd8B/wEaAeYB+AH/ARkB5AH3Af8BGAHjAfcB/wEAAUMBTAH/AQABQwFMAf8BFgHiAfcB/wEW
ARkB4gH3Af8BGgHjAfcB/wEIAccB4AH/ARQBtAHRAf8B6gHyAfUB/wQAAf8BAAP/AQAC/wEAAbQB0QH/ AeIB9wH/ARcB4wH3Af8BBQHHAeAB/wERAbQB0QH/AeoB8gH1Af8EAAH/AQAD/wEAAv8BAAG0AdEB/wEA
AQABxgHfAf8BAAHmAfgB/wEAAeQB9wH/AQAB4wH3Af8BAAEXASAB/wEAARcBIAH/AQAB4gH3Af8BAAHi AcYB3wH/AQAB5gH4Af8BAAHkAfcB/wEAAeMB9wH/AQABFAEdAf8BAAEUAR0B/wEAAeIB9wH/AQAB4gH3
AfcB/wEAAeMB9wH/AQABxwHgAf8BAAG0AdEC/wEAA/8BAAL/Ay4BRwMzAVIDPQFnA0YBfwNOAZUDUgGj Af8BAAHjAfcB/wEAAccB4AH/AQABtAHRAv8BAAP/AQAC/wMuAUcDMwFSAz0BZwNGAX8DTgGVA1IBowFc
AWICYAH1AXsCeQH6AXsCeQH6Ax0B/wMdAf8DHQH/Ax0B/wMdAf8DHQH/AzcBWwMAAQEDOQFfAyUB/wNO AloB9QF4AnYB+gF4AnYB+gMaAf8DGgH/AxoB/wMaAf8DGgH/AxoB/wM3AVsDAAEBAzkBXwMiAf8DTgGU
AZQDUgGnAyUB/wGKAoMB+gGIAoYB+QMlAf8BggGBAYAB9wNbAcgDJQH/A0gBhQMlAf8DJQH/AzcBWwgA A1IBpwMiAf8BgQJ9AfoBhQKDAfkDIgH/AX8BfQF6AfcDWwHIAyIB/wNIAYUDIgH/AyIB/wM3AVsIAAGO
AY4B0wHjAf8BAAGqAcsB/wElAeoB9gH/ASkB8AH6Af8BJwHuAfkB/wMAAf8DAAH/ASMB6gH5Af8BIwHq AdMB4wH/AQABqgHLAf8BIgHqAfYB/wEmAfAB+gH/ASQB7gH5Af8DAAH/AwAB/wEgAeoB+QH/ASAB6gH5
AfkB/wEeAeUB9QH/AQABqgHLAf8BjgHTAeMB/wgAAf8BAAP/AQAD/wEAAv8BAAGqAcsB/wEAAeoB9gH/ Af8BGwHlAfUB/wEAAaoBywH/AY4B0wHjAf8IAAH/AQAD/wEAA/8BAAL/AQABqgHLAf8BAAHqAfYB/wEA
AQAB8AH6Af8BAAHuAfkB/wMAAf8DAAH/AQAB6gH5Af8BAAHqAfkB/wEAAeUB9QH/AQABqgHLAv8BAAP/ AfAB+gH/AQAB7gH5Af8DAAH/AwAB/wEAAeoB+QH/AQAB6gH5Af8BAAHlAfUB/wEAAaoBywL/AQAD/wEA
AQAD/wEAAv8EAAMgAS8DTAGSAygB/wMdAf8DKAH/AXEBbwFuAfoDPwH/Ax0B/wMdAf8DHQH/Ax0B/wMd A/8BAAL/BAADIAEvA0wBkgMlAf8DGgH/AyUB/wFuAWwBawH6AzwB/wMaAf8DGgH/AxoB/wMaAf8DGgH/
Af8DHQH/Ax0B/wM4AV4EAAM5AV8DJQH/AyUB/wMlAf8DJQH/AyUB/wMlAf8DJQH/AyUB/wMlAf8DJQH/ AxoB/wMaAf8DOAFeBAADOQFfAyIB/wMiAf8DIgH/AyIB/wMiAf8DIgH/AyIB/wMiAf8DIgH/AyIB/wNI
A0gBhQNOAZUDJQH/AzcBWwgAAe8B9AH2Af8BFAG0AdEB/wEHAcIB2wH/AS0B8wH7Af8BLAHxAfoB/wMA AYUDTgGVAyIB/wM3AVsIAAHvAfQB9gH/AREBtAHRAf8BBAHCAdsB/wEqAfMB+wH/ASkB8QH6Af8DAAH/
Af8DAAH/ASgB7wH6Af8BKAHvAfoB/wEJAcYB3wH/ARQBtAHRAf8B7wH0AfYB/wgAAf8BAAP/AQAD/wEA AwAB/wElAe8B+gH/ASUB7wH6Af8BBgHGAd8B/wERAbQB0QH/Ae8B9AH2Af8IAAH/AQAD/wEAA/8BAAL/
Av8BAAG0AdEB/wEAAcIB2wH/AQAB8wH7Af8BAAHxAfoB/wMAAf8DAAH/AQAB7wH6Af8BAAHvAfoB/wEA AQABtAHRAf8BAAHCAdsB/wEAAfMB+wH/AQAB8QH6Af8DAAH/AwAB/wEAAe8B+gH/AQAB7wH6Af8BAAHG
AcYB3wH/AQABtAHRAv8BAAP/AQAD/wEAAv8EAAM4AVwDKAH/Ax0B/wMdAf8DHQH/AygB/wNfAegDHQH/ Ad8B/wEAAbQB0QL/AQAD/wEAA/8BAAL/BAADOAFcAyUB/wMaAf8DGgH/AxoB/wMlAf8DXwHoAxoB/wMa
Ax0B/wMdAf8DHQH/Ax0B/wMdAf8DHQH/A0oBiwQAAzkBXwMlAf8B+QLqAf8B+QLqAf8DJQH/AfkC6gH/ Af8DGgH/AxoB/wMaAf8DGgH/AxoB/wNKAYsEAAM5AV8DIgH/AfkC6gH/AfkC6gH/AyIB/wH5AuoB/wH5
AfkC6gH/AyUB/wH5AuoB/wH5AuoB/wMlAf8DXgHZAyUB/wMlAf8DNwFbDAABnAHXAeUB/wEAAakBywH/ AuoB/wMiAf8B+QLqAf8B+QLqAf8DIgH/A14B2QMiAf8DIgH/AzcBWwwAAZwB1wHlAf8BAAGpAcsB/wEk
AScB6gH0Af8BLwH0AfsB/wMAAf8DAAH/AS0B8gH6Af8BJgHqAfYB/wEAAakBywH/AZwB1wHlAf8MAAH/ AeoB9AH/ASwB9AH7Af8DAAH/AwAB/wEqAfIB+gH/ASMB6gH2Af8BAAGpAcsB/wGcAdcB5QH/DAAB/wEA
AQAD/wEAA/8BAAP/AQAC/wEAAakBywH/AQAB6gH0Af8BAAH0AfsB/wMAAf8DAAH/AQAB8gH6Af8BAAHq A/8BAAP/AQAD/wEAAv8BAAGpAcsB/wEAAeoB9AH/AQAB9AH7Af8DAAH/AwAB/wEAAfIB+gH/AQAB6gH2
AfYB/wEAAakBywL/AQAD/wEAA/8BAAP/AQAC/wQAAzgBXAMdAf8DHQH/Ax0B/wMdAf8DHQH/A1QBrwMd Af8BAAGpAcsC/wEAA/8BAAP/AQAD/wEAAv8EAAM4AVwDGgH/AxoB/wMaAf8DGgH/AxoB/wNUAa8DGgH/
Af8DHQH/Ax0B/wMdAf8DHQH/Ax0B/wMdAf8DRAF7BAADOQFfAyUB/wMlAf8DJQH/AyUB/wMlAf8DJQH/ AxoB/wMaAf8DGgH/AxoB/wMaAf8DGgH/A0QBewQAAzkBXwMiAf8DIgH/AyIB/wMiAf8DIgH/AyIB/wMi
AyUB/wMlAf8DJQH/AyUB/wNiAekDYgHpAyUB/wNIAYYQAAEUAbQB0QH/AQQBvwHZAf8BOQH2AfsB/wMA Af8DIgH/AyIB/wMiAf8DYgHpA2IB6QMiAf8DSAGGEAABEQG0AdEB/wEBAb8B2QH/ATYB9gH7Af8DAAH/
Af8DAAH/ATAB9QH7Af8BCwHGAd0B/wEUAbQB0QH/AfUB9gH3Af8MAAH/AQAD/wEAA/8BAAP/AQAC/wEA AwAB/wEtAfUB+wH/AQgBxgHdAf8BEQG0AdEB/wH1AfYB9wH/DAAB/wEAA/8BAAP/AQAD/wEAAv8BAAG0
AbQB0QH/AQABvwHZAf8BCgH2AfsB/wMAAf8DAAH/AQEB9QH7Af8BAAHGAd0B/wEAAbQB0QL/AQAD/wEA AdEB/wEAAb8B2QH/AQcB9gH7Af8DAAH/AwAB/wEAAfUB+wH/AQABxgHdAf8BAAG0AdEC/wEAA/8BAAP/
A/8BAAP/AQAC/wQAAzgBXAMoAf8DHQH/Ax0B/wMdAf8DKAH/A1YBqwNeAdADXAHqA1wB6gNcAeoDXAHq AQAD/wEAAv8EAAM4AVwDJQH/AxoB/wMaAf8DGgH/AyUB/wNWAasDXgHQA1wB6gNcAeoDXAHqA1wB6gMl
AygB/wMdAf8DNwFbBAADOQFfAyUB/wMlAf8DJQH/AyUB/wMlAf8DJQH/AyUB/wMlAf8DJQH/AyUB/wNh Af8DGgH/AzcBWwQAAzkBXwMiAf8DIgH/AyIB/wMiAf8DIgH/AyIB/wMiAf8DIgH/AyIB/wMiAf8DYQHc
AdwDJQH/AyUB/wM9AWcQAAGrAd0B6QH/AQABqQHKAf8BJgHoAfMB/wEwAfUB+wH/ATAB9QH7Af8BKQHt AyIB/wMiAf8DPQFnEAABqwHdAekB/wEAAakBygH/ASMB6AHzAf8BLQH1AfsB/wEtAfUB+wH/ASYB7QH2
AfYB/wEAAakBywH/AasB3QHpAf8QAAH/AQAD/wEAA/8BAAP/AQAD/wEAAv8BAAGpAcoB/wEAAegB8wH/ Af8BAAGpAcsB/wGrAd0B6QH/EAAB/wEAA/8BAAP/AQAD/wEAA/8BAAL/AQABqQHKAf8BAAHoAfMB/wEA
AQEB9QH7Af8BAQH1AfsB/wEAAe0B9gH/AQABqQHLAv8BAAP/AQAD/wEAA/8BAAP/AQAC/wQAAyABLwNM AfUB+wH/AQAB9QH7Af8BAAHtAfYB/wEAAakBywL/AQAD/wEAA/8BAAP/AQAD/wEAAv8EAAMgAS8DTAGS
AZIDKAH/Ax0B/wMoAf8DVAGvA1YBqwNVAa0DXwHoA1wB6gNcAeoDXAHqA1wB6gMdAf8DNwFbBAADQwF4 AyUB/wMaAf8DJQH/A1QBrwNWAasDVQGtA18B6ANcAeoDXAHqA1wB6gNcAeoDGgH/AzcBWwQAA0MBeAMi
AyUB/wMlAf8DJQH/AyUB/wMlAf8DJQH/AyUB/wMlAf8DJQH/AyUB/wNOAZUDXQHTAyUB/wM3AVsUAAEV Af8DIgH/AyIB/wMiAf8DIgH/AyIB/wMiAf8DIgH/AyIB/wMiAf8DTgGVA10B0wMiAf8DNwFbFAABEgG0
AbQB0QH/AQIBuwHWAf8BMAH1AfsB/wEwAfUB+wH/AQoBxgHdAf8BFQG0AdEB/xQAAf8BAAP/AQAD/wEA AdEB/wEAAbsB1gH/AS0B9QH7Af8BLQH1AfsB/wEHAcYB3QH/ARIBtAHRAf8UAAH/AQAD/wEAA/8BAAP/
A/8BAAP/AQAC/wEAAbQB0QH/AQABuwHWAf8BAQH1AfsB/wEBAfUB+wH/AQABxgHdAf8BAAG0AdEC/wEA AQAD/wEAAv8BAAG0AdEB/wEAAbsB1gH/AQAB9QH7Af8BAAH1AfsB/wEAAcYB3QH/AQABtAHRAv8BAAP/
A/8BAAP/AQAD/wEAA/8BAAL/CAADSwGOA0wBkgNXAboDVgGrA1YBqwNWAasDVgGrA2EB5ANcAeoDXAHq AQAD/wEAA/8BAAP/AQAC/wgAA0sBjgNMAZIDVwG6A1YBqwNWAasDVgGrA1YBqwNhAeQDXAHqA1wB6gNc
A1wB6gNcAeoDHQH/AzcBWwQAA0kBhwM+AWsDNwFbAzcBWwM3AVsDOgFiA1ABngNSAaMDUgGjA1IBowNS AeoDXAHqAxoB/wM3AVsEAANJAYcDPgFrAzcBWwM3AVsDNwFbAzoBYgNQAZ4DUgGjA1IBowNSAaMDUgGj
AaMDTgGVAyUB/wMlAf8DNwFbFAABuwHiAe0B/wEAAagBygH/ASMB5QHxAf8BKQHsAfUB/wEAAakBywH/ A04BlQMiAf8DIgH/AzcBWxQAAbsB4gHtAf8BAAGoAcoB/wEgAeUB8QH/ASYB7AH1Af8BAAGpAcsB/wG7
AbsB4gHtAf8UAAH/AQAD/wEAA/8BAAP/AQAD/wEAA/8BAAL/AQABqAHKAf8BAAHlAfEB/wEAAewB9QH/ AeIB7QH/FAAB/wEAA/8BAAP/AQAD/wEAA/8BAAP/AQAC/wEAAagBygH/AQAB5QHxAf8BAAHsAfUB/wEA
AQABqQHLAv8BAAP/AQAD/wEAA/8BAAP/AQAD/wEAAv8IAAM+AWsDSgGMAygB/wNWAbEDWAG5A1YBqwNW AakBywL/AQAD/wEAA/8BAAP/AQAD/wEAA/8BAAL/CAADPgFrA0oBjAMlAf8DVgGxA1gBuQNWAasDVgGr
AasDYQHhA1wB6gNcAeoDXAHqAygB/wNKAYwDLgFIEAADNwFbAyUB/wMlAf8DJQH/AyUB/wMlAf8DJQH/ A2EB4QNcAeoDXAHqA1wB6gMlAf8DSgGMAy4BSBAAAzcBWwMiAf8DIgH/AyIB/wMiAf8DIgH/AyIB/wMi
AyUB/wMlAf8DJQH/AyUB/wM2AVkYAAEVAbQB0QH/AQABuQHVAf8BCgHGAd0B/wEVAbQB0QH/GAAB/wEA Af8DIgH/AyIB/wMiAf8DNgFZGAABEgG0AdEB/wEAAbkB1QH/AQcBxgHdAf8BEgG0AdEB/xgAAf8BAAP/
A/8BAAP/AQAD/wEAA/8BAAP/AQAC/wEAAbQB0QH/AQABuQHVAf8BAAHGAd0B/wEAAbQB0QL/AQAD/wEA AQAD/wEAA/8BAAP/AQAD/wEAAv8BAAG0AdEB/wEAAbkB1QH/AQABxgHdAf8BAAG0AdEC/wEAA/8BAAP/
A/8BAAP/AQAD/wEAA/8BAAL/DAADPQFoA1YBtANcAeoDNAH/Ax0B/wMdAf8DHQH/Ax0B/wM0Af8DXAHq AQAD/wEAA/8BAAP/AQAC/wwAAz0BaANWAbQDXAHqAzEB/wMaAf8DGgH/AxoB/wMaAf8DMQH/A1wB6gNX
A1cBugM+AWsUAAM3AVsDJQH/AyUB/wMlAf8DJQH/AyUB/wMlAf8DJQH/AyUB/wMlAf8DJQH/AzQBVBgA AboDPgFrFAADNwFbAyIB/wMiAf8DIgH/AyIB/wMiAf8DIgH/AyIB/wMiAf8DIgH/AyIB/wM0AVQYAAHJ
AckB6QHxAf8BBQGvAc4B/wEFAa8BzgH/AckB6QHxAf8YAAH/AQAD/wEAA/8BAAP/AQAD/wEAA/8BAAP/ AekB8QH/AQIBrwHOAf8BAgGvAc4B/wHJAekB8QH/GAAB/wEAA/8BAAP/AQAD/wEAA/8BAAP/AQAD/wEA
AQAC/wEAAa8BzgH/AQABrwHOAv8BAAP/AQAD/wEAA/8BAAP/AQAD/wEAA/8BAAL/EAADDQERAycBOgMz Av8BAAGvAc4B/wEAAa8BzgL/AQAD/wEAA/8BAAP/AQAD/wEAA/8BAAP/AQAC/xAAAw0BEQMnAToDMwFT
AVMDNwFbAzsBZQNKAY0DSwGOA0gBhAM4AV4DEgEZGAADNwFbAzcBWwNJAYcDSwGOA0sBjgNKAY0DRQF8 AzcBWwM7AWUDSgGNA0sBjgNIAYQDOAFeAxIBGRgAAzcBWwM3AVsDSQGHA0sBjgNLAY4DSgGNA0UBfAM3
AzcBWwM3AVsDNwFbAzUBVwM3AVr/AEEAAyoBQAMqAUADKgFAAyoBQAMqAUADKgFAAyoBQAMqAUADKgFA AVsDNwFbAzcBWwM1AVcDNwFa/wBBAAMqAUADKgFAAyoBQAMqAUADKgFAAyoBQAMqAUADKgFAAyoBQAMq
AyoBQAMqAUADKgFAAyoBQAMmATgDDAEQBAADKgFAAyoBQAMqAUADKgFAAyoBQAMqAUADKgFAAyoBQAMq AUADKgFAAyoBQAMqAUADJgE4AwwBEAQAAyoBQAMqAUADKgFAAyoBQAMqAUADKgFAAyoBQAMqAUADKgFA
AUADKgFAAyoBQAMqAUADKgFAAyYBOAMMARAUAAHWAb4BrQH/AbUBmgGEAf8BnAEfAQQB/wGUARMBAAH/ AyoBQAMqAUADKgFAAyoBQAMmATgDDAEQFAAB1gG+Aa0B/wG1AZoBhAH/AZwBHAEBAf8BlAEQAQAB/wGU
AZQBEwEAAf8BpQEnARUB/wG9AaYBlAH/AdYBvgG1Af8gAAH3AfMB7wH/AdYBvgG1Af8BrQGOAVsB/wGU ARABAAH/AaUBJAESAf8BvQGmAZQB/wHWAb4BtQH/IAAB9wHzAe8B/wHWAb4BtQH/Aa0BjgFYAf8BlAFG
AUkBMgH/AYwBQQEqAf8BlAFVAUMB/wHGAbYBrQH/FAADXAHfA1wB3wNcAd8DXAHfA1wB3wNcAd8DXAHf AS8B/wGMAT4BJwH/AZQBUgFAAf8BxgG2Aa0B/xQAA1wB3wNcAd8DXAHfA1wB3wNcAd8DXAHfA1wB3wNc
A1wB3wNcAd8DXAHfA1wB3wNcAd8DXAHfA1sBwwMmATgEAANcAd8DXAHfA1wB3wNcAd8DXAHfA1wB3wNc Ad8DXAHfA1wB3wNcAd8DXAHfA1wB3wNbAcMDJgE4BAADXAHfA1wB3wNcAd8DXAHfA1wB3wNcAd8DXAHf
Ad8DXAHfA1wB3wNcAd8DXAHfA1wB3wNcAd8DWwHDAyYBOBAAAcYBrgGcAf8BrQGGARUB/wGtAZIBJQH/ A1wB3wNcAd8DXAHfA1wB3wNcAd8DXAHfA1sBwwMmATgQAAHGAa4BnAH/Aa0BhgESAf8BrQGSASIB/wHW
AdYBzwHOAf8B5wHzAfcB/wHnAe8B9wH/AcYBwwG9Af8BpQGGAR0B/wGlASMBDQH/AcYBrgGcAf8YAAH3 Ac8BzgH/AecB8wH3Af8B5wHvAfcB/wHGAcMBvQH/AaUBhgEaAf8BpQEgAQoB/wHGAa4BnAH/GAAB9wHr
AesB5wH/Ab0BmgGMAf8BnAFNATIB/wGcAU0BMgH/AZwBUQE6Af8BnAFNAToB/wGUAUUBMgH/AVsBMQEZ AecB/wG9AZoBjAH/AZwBSgEvAf8BnAFKAS8B/wGcAU4BNwH/AZwBSgE3Af8BlAFCAS8B/wFYAS4BFgH/
Af8BrQGaAYwB/xAAAacCpgH/ArMBsgH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/ Aa0BmgGMAf8QAAGnAqYB/wKzAbIB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6
A7oB/wGxArAB/wNcAd8DKgFABAABpwKmAf8CswGyAf8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/ Af8BsQKwAf8DXAHfAyoBQAQAAacCpgH/ArMBsgH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6
A7oB/wO6Af8DugH/AbECsAH/A1wB3wMqAUAMAAHOAa4BnAH/AbUBmgGMAf8B7wHrAecF/wH3AfsC/wHv Af8DugH/A7oB/wGxArAB/wNcAd8DKgFADAABzgGuAZwB/wG1AZoBjAH/Ae8B6wHnBf8B9wH7Av8B7wH7
AfsB9wH/Ae8C9wH/Au8B9wH/AecB8wL/Ab0BtgG1Af8BlAETAQAB/wHGAa4BnAH/FAABvQGaAYwB/wGl AfcB/wHvAvcB/wLvAfcB/wHnAfMC/wG9AbYBtQH/AZQBEAEAAf8BxgGuAZwB/xQAAb0BmgGMAf8BpQFS
AVUBOgH/AaUBVQE6Af8BpQFVAToB/wGcAVEBOgH/AZwBUQE6Af8BnAFRAToB/wGcAVEBOgH/AYQBNQEi ATcB/wGlAVIBNwH/AaUBUgE3Af8BnAFOATcB/wGcAU4BNwH/AZwBTgE3Af8BnAFOATcB/wGEATIBHwH/
Af8BrQGWAYwB/wwAA5EB/wPEAf8D4wH/A+MB/wPjAf8C4QHgAf8B2AHUAdIB/wHaAdYB1QH/A+MB/wPj Aa0BlgGMAf8MAAORAf8DxAH/A+MB/wPjAf8D4wH/AuEB4AH/AdgB1AHSAf8B2gHWAdUB/wPjAf8D4wH/
Af8D4wH/A+MB/wO6Af8DXAHfAyoBQAQAA5EB/wPEAf8D4wH/A+MB/wPjAf8D4wH/A+MB/wPjAf8D4wH/ A+MB/wPjAf8DugH/A1wB3wMqAUAEAAORAf8DxAH/A+MB/wPjAf8D4wH/A+MB/wPjAf8D4wH/A+MB/wPj
A+MB/wPjAf8D4wH/A7oB/wNcAd8DKgFACAAB1gG6Aa0B/wG1AZIBJQH/A/cJ/wHeAbYBpQH/AaUCAAH/ Af8D4wH/A+MB/wO6Af8DXAHfAyoBQAgAAdYBugGtAf8BtQGSASIB/wP3Cf8B3gG2AaUB/wGlAgAB/wGl
AaUCAAH/AdYBvgGtAf8B9wP/Ae8B9wL/Ab0BrgGlAf8BnAEXAQAB/wHWAb4BtQH/DAAB5wHHAbUB/wGt AgAB/wHWAb4BrQH/AfcD/wHvAfcC/wG9Aa4BpQH/AZwBFAEAAf8B1gG+AbUB/wwAAecBxwG1Af8BrQFa
AV0BQwH/Aa0BXQFDAf8BrQFdAUsB/wGtAV0BSwH/Aa0BXQFDAf8BpQFZAUMB/wGlAVUBOgH/AZwBUQE6 AUAB/wGtAVoBQAH/Aa0BWgFIAf8BrQFaAUgB/wGtAVoBQAH/AaUBVgFAAf8BpQFSATcB/wGcAU4BNwH/
Af8BnAFRAToB/wFbATEBGQH/AcYBtgGtAf8IAAORAf8DxAH/A+MB/wPjAf8D4wH/AdkB1AHSAf8BowGI AZwBTgE3Af8BWAEuARYB/wHGAbYBrQH/CAADkQH/A8QB/wPjAf8D4wH/A+MB/wHZAdQB0gH/AaMBiAEh
ASQB/wGuAZcBjAH/A+MB/wPjAf8D4wH/A+MB/wO6Af8DXAHfAyoBQAQAA5EB/wPEAf8D4wH/A+MB/wPj Af8BrgGXAYwB/wPjAf8D4wH/A+MB/wPjAf8DugH/A1wB3wMqAUAEAAORAf8DxAH/A+MB/wPjAf8D4wH/
Af8D4wH/A+MB/wPjAf8D4wH/A+MB/wPjAf8D4wH/A7oB/wNcAd8DKgFACAABvQGeAYQB/wHeAccBvQ3/ A+MB/wPjAf8D4wH/A+MB/wPjAf8D4wH/A+MB/wO6Af8DXAHfAyoBQAgAAb0BngGEAf8B3gHHAb0N/wHv
Ae8B1wHGAf8BrQIAAf8BpQIAAf8B9wHvAecF/wHvAesB7wH/AecB8wH3Af8BnAEnARUB/wG1AZIBJQH/ AdcBxgH/Aa0CAAH/AaUCAAH/AfcB7wHnBf8B7wHrAe8B/wHnAfMB9wH/AZwBJAESAf8BtQGSASIB/wwA
DAABzgGiAYwB/wGtAYYBSwH/AbUBigFTAf8BvQGOAVMB/wG9AY4BUwH/AbUBigFTAf8BtQGGAUsB/wGt Ac4BogGMAf8BrQGGAUgB/wG1AYoBUAH/Ab0BjgFQAf8BvQGOAVAB/wG1AYoBUAH/AbUBhgFIAf8BrQFa
AV0BQwH/AaUBVQE6Af8BnAFRAToB/wGUAUUBMgH/AZQBVQFDAf8IAAORAf8BxgLHAf8B5gLnAf8B5gLn AUAB/wGlAVIBNwH/AZwBTgE3Af8BlAFCAS8B/wGUAVIBQAH/CAADkQH/AcYCxwH/AeYC5wH/AeYC5wH/
Af8B5gLnAf8B2AHSAc8B/wGPARQBAgH/AZ4BgAEaAf8B5gLnAf8B5gLnAf8B5gLnAf8B5gLnAf8DvAH/ AeYC5wH/AdgB0gHPAf8BjwERAQAB/wGeAYABFwH/AeYC5wH/AeYC5wH/AeYC5wH/AeYC5wH/A7wB/wNc
A1wB3wMqAUAEAAORAf8BxgLHAf8B5gLnAf8B5gLnAf8B5gLnAf8B5gLnAf8B5gLnAf8B5gLnAf8B5gLn Ad8DKgFABAADkQH/AcYCxwH/AeYC5wH/AeYC5wH/AeYC5wH/AeYC5wH/AeYC5wH/AeYC5wH/AeYC5wH/
Af8B5gLnAf8B5gLnAf8B5gLnAf8DvAH/A1wB3wMqAUAEAAHWAboBrQH/Ab0BmgGEAv8B+w7/Ae8B4wHW AeYC5wH/AeYC5wH/AeYC5wH/A7wB/wNcAd8DKgFABAAB1gG6Aa0B/wG9AZoBhAL/AfsO/wHvAeMB1gH/
Af8BvQIAAf8BtQEPAQAB/wH3AfsB9wX/AfcB8wH3Af8B7wHzAfcB/wHGAb4BvQH/AZwBHwEEAf8MAAHG Ab0CAAH/AbUBDAEAAf8B9wH7AfcF/wH3AfMB9wH/Ae8B8wH3Af8BxgG+Ab0B/wGcARwBAQH/DAABxgGa
AZoBhAH/Ab0BigFTAv8B+wP/AvcC/wHzAe8B/wH3AesB5wH/AfcB4wHeAf8B9wHjAdYB/wH3AeMB3gH/ AYQB/wG9AYoBUAL/AfsD/wL3Av8B8wHvAf8B9wHrAecB/wH3AeMB3gH/AfcB4wHWAf8B9wHjAd4B/wH3
AfcB2wHOAf8BnAFJATIB/wGMAUEBKgH/CAADkQH/AcoCywH/AewC7QH/AewC7QH/AewC7QH/Ad0B2AHV AdsBzgH/AZwBRgEvAf8BjAE+AScB/wgAA5EB/wHKAssB/wHsAu0B/wHsAu0B/wHsAu0B/wHdAdgB1QH/
Af8BkQEWAQMB/wGgAYIBHAH/AewC7QH/AewC7QH/AewC7QH/AewC7QH/A78B/wNcAd8DKgFABAADkQH/ AZEBEwEAAf8BoAGCARkB/wHsAu0B/wHsAu0B/wHsAu0B/wHsAu0B/wO/Af8DXAHfAyoBQAQAA5EB/wHK
AcoCywH/AewC7QH/AewC7QH/AewC7QH/AewC7QH/AewC7QH/AewC7QH/AewC7QH/AewC7QH/AewC7QH/ AssB/wHsAu0B/wHsAu0B/wHsAu0B/wHsAu0B/wHsAu0B/wHsAu0B/wHsAu0B/wHsAu0B/wHsAu0B/wHs
AewC7QH/A78B/wNcAd8DKgFABAABzgGuAZwB/wHOAaYBjBH/Ae8B3wHWAf8BvQEDAQAB/wG1AQ8BAAH/ Au0B/wO/Af8DXAHfAyoBQAQAAc4BrgGcAf8BzgGmAYwR/wHvAd8B1gH/Ab0CAAH/AbUBDAEAAf8B9wLv
AfcC7wn/Ae8B8wH3Af8B1gHbAd4B/wGcAR8BBAH/DAABxgGaAYQB/wHGAZYBWw7/AfsD/wHzAe8B/wH3 Cf8B7wHzAfcB/wHWAdsB3gH/AZwBHAEBAf8MAAHGAZoBhAH/AcYBlgFYDv8B+wP/AfMB7wH/AfcB6wHn
AesB5wH/AfcB4wHeAf8B9wHfAdYB/wGcAUkBMgH/AZQBSQEyAf8IAAORAf8D0AH/AegB3gHaAf8ByAGj Af8B9wHjAd4B/wH3Ad8B1gH/AZwBRgEvAf8BlAFGAS8B/wgAA5EB/wPQAf8B6AHeAdoB/wHIAaMBlgH/
AZYB/wHBAZcBiAH/AbsBjwEoAf8BnwEQAQAB/wGkARgBAwH/AcEBlwGIAf8BwQGXAYgB/wHOAa8BowH/ AcEBlwGIAf8BuwGPASUB/wGfAQ0BAAH/AaQBFQEAAf8BwQGXAYgB/wHBAZcBiAH/Ac4BrwGjAf8B7wHq
Ae8B6gHnAf8DwwH/A1wB3wMqAUAEAAORAf8BygLLAf8B4QHYAdQB/wHHAaEBlAH/AcEBlwGIAf8BwQGX AecB/wPDAf8DXAHfAyoBQAQAA5EB/wHKAssB/wHhAdgB1AH/AccBoQGUAf8BwQGXAYgB/wHBAZcBiAH/
AYgB/wHBAZcBiAH/AcEBlwGIAf8BwQGXAYgB/wHBAZcBiAH/AcwBrQGhAf8B5gHiAeEB/wO/Af8DXAHf AcEBlwGIAf8BwQGXAYgB/wHBAZcBiAH/AcEBlwGIAf8BzAGtAaEB/wHmAeIB4QH/A78B/wNcAd8DKgFA
AyoBQAQAAc4BpgGUAf8BzgGqAZQR/wHvAdsBzgH/AcYBAwEAAf8BtQELAQAB/wHvAesB5wn/A/cB/wHe BAABzgGmAZQB/wHOAaoBlBH/Ae8B2wHOAf8BxgIAAf8BtQEIAQAB/wHvAesB5wn/A/cB/wHeAeMB5wH/
AeMB5wH/AZwBIwENAf8MAAHeAbIBnAH/Ac4BngGEAf8B5wG2AZwB/wHnAb4BrQH/AecBvgGtAf8B5wG2 AZwBIAEKAf8MAAHeAbIBnAH/Ac4BngGEAf8B5wG2AZwB/wHnAb4BrQH/AecBvgGtAf8B5wG2AZwB/wHW
AZwB/wHWAaYBjAH/Ac4BmgGEAf8BtQGKAUsB/wGlAVkBQwH/AZwBSQEyAf8BrQGOAVsB/wgAA5EB/wPT AaYBjAH/Ac4BmgGEAf8BtQGKAUgB/wGlAVYBQAH/AZwBRgEvAf8BrQGOAVgB/wgAA5EB/wPTAf8B6wHf
Af8B6wHfAdkB/wHEAZcBhwH/AbwBiQEgAf8BuAGDARkB/wGiAQ8BAAH/AacBFQEAAf8BvAGJASAB/wG8 AdkB/wHEAZcBhwH/AbwBiQEdAf8BuAGDARYB/wGiAQwBAAH/AacBEgEAAf8BvAGJAR0B/wG8AYkBHQH/
AYkBIAH/AcwBpgGYAf8B9AHtAeoB/wPGAf8DXAHfAyoBQAQAA5EB/wHMAs0B/wHjAdcB0gH/AcMBlgGG AcwBpgGYAf8B9AHtAeoB/wPGAf8DXAHfAyoBQAQAA5EB/wHMAs0B/wHjAdcB0gH/AcMBlgGGAf8BvAGJ
Af8BvAGJASAB/wG8AYkBIAH/AbwBiQEgAf8BvAGJASAB/wG8AYkBIAH/AbwBiQEgAf8ByQGjAZYB/wHp AR0B/wG8AYkBHQH/AbwBiQEdAf8BvAGJAR0B/wG8AYkBHQH/AbwBiQEdAf8ByQGjAZYB/wHpAeQB4QH/
AeQB4QH/A8EB/wNcAd8DKgFABAABxgGiAYwB/wHOAaoBlBH/Ad4BwwGtAf8BvQEHAQAB/wG9AR8BAAH/ A8EB/wNcAd8DKgFABAABxgGiAYwB/wHOAaoBlBH/Ad4BwwGtAf8BvQEEAQAB/wG9ARwBAAH/AfcC7wb/
AfcC7wb/AfsC/wH3AfsC/wHeAdcB3gH/AZwBHwEEAf8MAAHvAc8BvQH/Ac4BngGEAf8B5wG2AZwB/wHn AfsC/wH3AfsC/wHeAdcB3gH/AZwBHAEBAf8MAAHvAc8BvQH/Ac4BngGEAf8B5wG2AZwB/wHnAb4BrQH/
Ab4BrQH/AecBvgGtAf8B5wG2AZwB/wHWAaYBjAH/Ac4BmgGEAf8BtQGKAUsB/wGlAVkBQwH/AZwBUQE6 AecBvgGtAf8B5wG2AZwB/wHWAaYBjAH/Ac4BmgGEAf8BtQGKAUgB/wGlAVYBQAH/AZwBTgE3Af8B1gG+
Af8B1gG+AbUB/wgAA5EB/wPTAf8B+AH2AfUB/wHyAeoB5wH/AfEB6AHkAf8B4gHUAc0B/wGWARcBBAH/ AbUB/wgAA5EB/wPTAf8B+AH2AfUB/wHyAeoB5wH/AfEB6AHkAf8B4gHUAc0B/wGWARQBAQH/AaUBgwEY
AaUBgwEbAf8B8QHoAeQB/wHxAegB5AH/AfMB7QHqAf8B+gH5AfcB/wPGAf8DXAHfAyoBQAQAA5EB/wPS Af8B8QHoAeQB/wHxAegB5AH/AfMB7QHqAf8B+gH5AfcB/wPGAf8DXAHfAyoBQAQAA5EB/wPSAf8B9wH1
Af8B9wH1AfMB/wHyAeoB5wH/AfEB6AHkAf8B8QHoAeQB/wHxAegB5AH/AfEB6AHkAf8B8QHoAeQB/wHx AfMB/wHyAeoB5wH/AfEB6AHkAf8B8QHoAeQB/wHxAegB5AH/AfEB6AHkAf8B8QHoAeQB/wHxAegB5AH/
AegB5AH/AfMB7AHpAf8B+AH3AfYB/wPFAf8DXAHfAyoBQAQAAdYBsgGcAf8BzgGiAYwR/wH3AesB5wH/ AfMB7AHpAf8B+AH3AfYB/wPFAf8DXAHfAyoBQAQAAdYBsgGcAf8BzgGiAYwR/wH3AesB5wH/Ae8B2wHW
Ae8B2wHWAf8B9wHrAecK/wH7Av8B9wP/Ac4BvgG9Af8BpQEnAQ0B/wwAAf8B8wHvAf8B3gG2AaUB/wHW Af8B9wHrAecK/wH7Av8B9wP/Ac4BvgG9Af8BpQEkAQoB/wwAAf8B8wHvAf8B3gG2AaUB/wHWAaYBjAH/
AaYBjAH/AecBvgGtAf8B7wG+Aa0B/wHnAbIBnAH/AdYBpgGUAf8BxgGWAYQB/wG1AYoBUwH/AaUBWQFD AecBvgGtAf8B7wG+Aa0B/wHnAbIBnAH/AdYBpgGUAf8BxgGWAYQB/wG1AYoBUAH/AaUBVgFAAf8BvQGa
Af8BvQGaAYwB/wH3Au8B/wgAA5EB/wPUAf8C/AH7Af8C/AH7Af8C/AH7Af8B6wHlAeEB/wGVARoBBwH/ AYwB/wH3Au8B/wgAA5EB/wPUAf8C/AH7Af8C/AH7Af8C/AH7Af8B6wHlAeEB/wGVARcBBAH/AaYBiAEe
AaYBiAEhAf8C/AH7Af8C/AH7Af8C/AH7Af8C/AH7Af8DxwH/A1wB3wMqAUAEAAORAf8D0wH/AvsB+gH/ Af8C/AH7Af8C/AH7Af8C/AH7Af8C/AH7Af8DxwH/A1wB3wMqAUAEAAORAf8D0wH/AvsB+gH/AvsB+gH/
AvsB+gH/AvsB+gH/AvsB+gH/AvsB+gH/AvsB+gH/AvsB+gH/AvsB+gH/AvsB+gH/AvsB+gH/A8YB/wNc AvsB+gH/AvsB+gH/AvsB+gH/AvsB+gH/AvsB+gH/AvsB+gH/AvsB+gH/AvsB+gH/A8YB/wNcAd8DKgFA
Ad8DKgFACAAB1gGmAYwB/wHvAecB3g7/AfsC/wHWAaIBhAH/AdYBogGEAv8B+w7/AaUBJwENAf8BxgGm CAAB1gGmAYwB/wHvAecB3g7/AfsC/wHWAaIBhAH/AdYBogGEAv8B+w7/AaUBJAEKAf8BxgGmAZQB/xAA
AZQB/xAAAfcB6wHnAf8B3gG2AaUB/wHWAaIBjAH/AdYBqgGUAf8B3gGuAZQB/wHOAaIBjAH/Ab0BkgFb AfcB6wHnAf8B3gG2AaUB/wHWAaIBjAH/AdYBqgGUAf8B3gGuAZQB/wHOAaIBjAH/Ab0BkgFYAf8BtQGG
Af8BtQGGAUsB/wG9AZoBjAH/AfcB6wHnAf8MAAORAf8D1AH/A/wB/wP8Af8D/AH/Ae0B6AHlAf8BogGC AUgB/wG9AZoBjAH/AfcB6wHnAf8MAAORAf8D1AH/A/wB/wP8Af8D/AH/Ae0B6AHlAf8BogGCARgB/wGx
ARsB/wGxAZcBiQH/A/wB/wP8Af8D/AH/A/wB/wPHAf8DXAHfAyoBQAQAA5EB/wPTAf8C+wH6Af8C+wH6 AZcBiQH/A/wB/wP8Af8D/AH/A/wB/wPHAf8DXAHfAyoBQAQAA5EB/wPTAf8C+wH6Af8C+wH6Af8C+wH6
Af8C+wH6Af8C+wH6Af8C+wH6Af8C+wH6Af8C+wH6Af8C+wH6Af8C+wH6Af8C+wH6Af8DxgH/A1wB3wMq Af8C+wH6Af8C+wH6Af8C+wH6Af8C+wH6Af8C+wH6Af8C+wH6Af8C+wH6Af8DxgH/A1wB3wMqAUAIAAHW
AUAIAAHWAbYBnAH/AecBsgGUDf8B9wHvAecB/wHGARcBAAH/Ab0BDwEAAf8B9wLvCf8BxgGuAZwB/wGt AbYBnAH/AecBsgGUDf8B9wHvAecB/wHGARQBAAH/Ab0BDAEAAf8B9wLvCf8BxgGuAZwB/wGtAYYBEgH/
AYYBFQH/AdYBwwG1Af8UAAH/Ae8B5wH/Ae8BzwG9Af8B3gGyAZwB/wHOAZ4BjAH/AcYBmgGEAf8B1gGm AdYBwwG1Af8UAAH/Ae8B5wH/Ae8BzwG9Af8B3gGyAZwB/wHOAZ4BjAH/AcYBmgGEAf8B1gGmAZQB/wHW
AZQB/wHWAboBrQL/AvcB/xAAA5EB/wPUAf8D/AH/A/wB/wP8Af8B+AL2Af8B4gHZAdUB/wHnAd8B2wH/ AboBrQL/AvcB/xAAA5EB/wPUAf8D/AH/A/wB/wP8Af8B+AL2Af8B4gHZAdUB/wHnAd8B2wH/A/wB/wP8
A/wB/wP8Af8D/AH/A/wB/wPHAf8DXAHfAyoBQAQAA5EB/wPTAf8C+wH6Af8C+wH6Af8C+wH6Af8C+wH6 Af8D/AH/A/wB/wPHAf8DXAHfAyoBQAQAA5EB/wPTAf8C+wH6Af8C+wH6Af8C+wH6Af8C+wH6Af8C+wH6
Af8C+wH6Af8C+wH6Af8C+wH6Af8C+wH6Af8C+wH6Af8C+wH6Af8DxgH/A1wB3wMqAUAMAAHeAbIBlAH/ Af8C+wH6Af8C+wH6Af8C+wH6Af8C+wH6Af8C+wH6Af8DxgH/A1wB3wMqAUAMAAHeAbIBlAH/Ae8BxwGt
Ae8BxwGtDv8C9wL/AfcB7wb/AvcB/wHOAbYBpQH/Aa0BhgEVAf8B1gHDAbUB/0gAAqEBoAH/A8EB/wPU Dv8C9wL/AfcB7wb/AvcB/wHOAbYBpQH/Aa0BhgESAf8B1gHDAbUB/0gAAqEBoAH/A8EB/wPUAf8D1AH/
Af8D1AH/A9QB/wPUAf8D1AH/A9QB/wPUAf8D1AH/A9QB/wPUAf8DuwH/A1wB3wMqAUAEAAKhAaAB/wPA A9QB/wPUAf8D1AH/A9QB/wPUAf8D1AH/A9QB/wPUAf8DuwH/A1wB3wMqAUAEAAKhAaAB/wPAAf8D0wH/
Af8D0wH/A9MB/wPTAf8D0wH/A9MB/wPTAf8D0wH/A9MB/wPTAf8D0wH/A7oB/wNcAd8DKgFAEAAB3gG2 A9MB/wPTAf8D0wH/A9MB/wPTAf8D0wH/A9MB/wPTAf8D0wH/A7oB/wNcAd8DKgFAEAAB3gG2AZwB/wHn
AZwB/wHnAbYBlAH/AfcB3wHGAv8B5wHeAv8B6wHnAf8B9wHnAd4B/wHnAc8BxgH/Ac4BqgGUAf8BvQGa AbYBlAH/AfcB3wHGAv8B5wHeAv8B6wHnAf8B9wHnAd4B/wHnAc8BxgH/Ac4BqgGUAf8BvQGaAYQB/wHW
AYQB/wHWAcMBtQH/TAABvAG7AboB/wKhAaAB/wORAf8DkQH/A5EB/wORAf8DkQH/A5EB/wORAf8DkQH/ AcMBtQH/TAABvAG7AboB/wKhAaAB/wORAf8DkQH/A5EB/wORAf8DkQH/A5EB/wORAf8DkQH/A5EB/wOR
A5EB/wORAf8BpwKmAf8DXAHfAyoBQAQAAbwBuwG6Af8CoQGgAf8DkQH/A5EB/wORAf8DkQH/A5EB/wOR Af8BpwKmAf8DXAHfAyoBQAQAAbwBuwG6Af8CoQGgAf8DkQH/A5EB/wORAf8DkQH/A5EB/wORAf8DkQH/
Af8DkQH/A5EB/wORAf8DkQH/AacCpgH/A1wB3wMqAUAUAAHeAb4BrQH/Ad4BtgGcAf8B5wG2AZwB/wHn A5EB/wORAf8DkQH/AacCpgH/A1wB3wMqAUAUAAHeAb4BrQH/Ad4BtgGcAf8B5wG2AZwB/wHnAbIBlAH/
AbIBlAH/Ad4BqgGMAf8B1gGuAZwB/wHWAb4BtQH//wDtAAEQAY8BFQH/ARABjwEVAf8BEAGPARUB/wEQ Ad4BqgGMAf8B1gGuAZwB/wHWAb4BtQH//wDtAAENAY8BEgH/AQ0BjwESAf8BDQGPARIB/wENAY8BEgH/
AY8BFQH/GAAD2gH/A9oB/wPaAf8D2gH/A9oB/wPaAf8D2gH/A9oB/wNbAcQkAAEWASoBtwH/AQABAgGm GAAD2gH/A9oB/wPaAf8D2gH/A9oB/wPaAf8D2gH/A9oB/wNbAcQkAAETAScBtwH/AgABpgH/AUMBUgHE
Af8BRgFVAcQB/yAAA18B6AEWASoBtwH/DAAB/wFGATQC/wFGATQB/0gAARABjwEVAf8BEAGPARUB/wEQ Af8gAANfAegBEwEnAbcB/wwAAf8BQwExAv8BQwExAf9IAAENAY8BEgH/AQ0BjwESAf8BDQGPARIB/wEN
AY8BFQH/ARABjwEVAf8YAAPaAf8DHQH/Ax0B/wMdAf8DHQH/Ax0B/wMdAf8D2gH/A2UB9AMBAQIDAAEB AY8BEgH/GAAD2gH/AxoB/wMaAf8DGgH/AxoB/wMaAf8DGgH/A9oB/wNlAfQDAQECAwABAQcAAQEWAAGm
BwABARUAAQIBpgH/AQABAgGmAf8BAAECAaYB/wNfAegYAAFGAVUBxAH/AQYBHAGyAf8DDQERDAAB/wFG Af8CAAGmAf8CAAGmAf8DXwHoGAABQwFSAcQB/wEDARkBsgH/Aw0BEQwAAf8BQwExAf8IAAH/AUMBMQH/
ATQB/wgAAf8BRgE0Af9AAAEQAY8BFQH/ARABjwEVAf8BEAGPARUB/wEQAY8BFQH/GAAD2gH/Ax0B/wMd QAABDQGPARIB/wENAY8BEgH/AQ0BjwESAf8BDQGPARIB/xgAA9oB/wMaAf8DGgH/AxoB/wMaAf8DGgH/
Af8DHQH/Ax0B/wMdAf8DHQH/A9oB/wNRAZwEAAMBAQIDBAEFAwABARQAAUYBVQHEAf8BAAECAaYB/wEA AxoB/wPaAf8DUQGcBAADAQECAwQBBQMAAQEUAAFDAVIBxAH/AgABpgH/AgABpgH/AgABpgH/A1IBqQwA
AQIBpgH/AQABAgGmAf8DUgGpDAADEAEWATgBSAG+Af8BAAEPAawB/wMxAU0YAAH/AUYBNAL/AUYBNAL/ AxABFgE1AUUBvgH/AQABDAGsAf8DMQFNGAAB/wFDATEC/wFDATEC/wFDATEB/zwAAQ0BjwESAf8BDQGP
AUYBNAH/PAABEAGPARUB/wEQAY8BFQH/ARABjwEVAf8BEAGPARUB/xgAA9oB/wMdAf8DHQH/Ax0B/wMd ARIB/wENAY8BEgH/AQ0BjwESAf8YAAPaAf8DGgH/AxoB/wMaAf8DGgH/AxoB/wMaAf8D2gH/A2AB6wNd
Af8DHQH/Ax0B/wPaAf8DYAHrA10B0gNZAcIDWwHGA1QBrAMbASYUAANdAcoBAAECAaYB/wEAAQIBpgH/ AdIDWQHCA1sBxgNUAawDGwEmFAADXQHKAgABpgH/AgABpgH/AQABDAGsAf8DMQFNBAADDQERARMBJwG3
AQABDwGsAf8DMQFNBAADDQERARYBKgG3Af8BAAECAaYB/wNSAakYAAH/AUYBNAL/AUYBNAL/AUYBNAL/ Af8CAAGmAf8DUgGpGAAB/wFDATEC/wFDATEC/wFDATEC/wFDATEC/wFDATEB/zgAAQ0BjwESAf8BDQGP
AUYBNAL/AUYBNAH/OAABEAGPARUB/wEQAY8BFQH/ARABjwEVAf8BEAGPARUB/xgAA9oB/wPaAf8D2gH/ ARIB/wENAY8BEgH/AQ0BjwESAf8YAAPaAf8D2gH/A9oB/wPaAf8D2gH/A9oB/wPaAf8D2gH/A9oB/wPa
A9oB/wPaAf8D2gH/A9oB/wPaAf8D2gH/A9oB/wPaAf8D2gH/A0MBdwMAAQEYAANWAasBAAECAaYB/wEA Af8D2gH/A9oB/wNDAXcDAAEBGAADVgGrAgABpgH/AgABpgH/AQABDAGsAf8DPgFrARMBJwG3Af8CAAGm
AQIBpgH/AQABDwGsAf8DPgFrARYBKgG3Af8BAAECAaYB/wNfAegDAwEEHAAB/wFGATQC/wFGATQC/wFG Af8DXwHoAwMBBBwAAf8BQwExAv8BQwExAv8BQwExAv8BQwExAv8BQwExAf8gAAENAY8BEgH/AQ0BjwES
ATQC/wFGATQC/wFGATQB/yAAARABjwEVAf8BEAGPARUB/wEQAY8BFQH/ARABjwEVAf8BEAGPARUB/wEQ Af8BDQGPARIB/wENAY8BEgH/AQ0BjwESAf8BDQGPARIB/wENAY8BEgH/AQ0BjwESAf8BDQGPARIB/wEN
AY8BFQH/ARABjwEVAf8BEAGPARUB/wEQAY8BFQH/ARABjwEVAf8BEAGPARUB/wEQAY8BFQH/ARABjwEV AY8BEgH/AQ0BjwESAf8BDQGPARIB/wENAY8BEgH/AQ0BjwESAf8EAAPaAf8DGgH/AxoB/wMaAf8DGgH/
Af8BEAGPARUB/wQAA9oB/wMdAf8DHQH/Ax0B/wMdAf8DHQH/Ax0B/wMdAf8DHQH/Ax0B/wMdAf8D2gH/ AxoB/wMaAf8DGgH/AxoB/wMaAf8DGgH/A9oB/wM1AVcDBAEFAw8BFAMAAQEUAAM+AWsBAAEMAawB/wIA
AzUBVwMEAQUDDwEUAwABARQAAz4BawEAAQ8BrAH/AQABAgGmAf8BAAECAaYB/wEAAQIBpgH/AUYBVQHE AaYB/wIAAaYB/wIAAaYB/wFDAVIBxAH/AwMEBAEFIAAB/wFDATEC/wFDATEC/wFDATEC/wFDATEC/wFD
Af8DAwQEAQUgAAH/AUYBNAL/AUYBNAL/AUYBNAL/AUYBNAL/AUYBNAH/HAABEAGPARUB/wEQAY8BFQH/ ATEB/xwAAQ0BjwESAf8BDQGPARIB/wENAY8BEgH/AQ0BjwESAf8BDQGPARIB/wENAY8BEgH/AQ0BjwES
ARABjwEVAf8BEAGPARUB/wEQAY8BFQH/ARABjwEVAf8BEAGPARUB/wEQAY8BFQH/ARABjwEVAf8BEAGP Af8BDQGPARIB/wENAY8BEgH/AQ0BjwESAf8BDQGPARIB/wENAY8BEgH/AQ0BjwESAf8BDQGPARIB/wQA
ARUB/wEQAY8BFQH/ARABjwEVAf8BEAGPARUB/wEQAY8BFQH/BAAD2gH/Ax0B/wMdAf8DHQH/Ax0B/wMd A9oB/wMaAf8DGgH/AxoB/wMaAf8DGgH/AxoB/wMaAf8DGgH/AxoB/wMaAf8D2gH/AwoBDiQAA1wByQIA
Af8DHQH/Ax0B/wMdAf8DHQH/Ax0B/wPaAf8DCgEOJAADXAHJAQABAgGmAf8BAAECAaYB/wEAAQ8BrAH/ AaYB/wIAAaYB/wEAAQwBrAH/Aw0BESwAAf8BQwExAv8BQwExAv8BQwExAv8BQwExAv8BQwExAf8YAAEN
Aw0BESwAAf8BRgE0Av8BRgE0Av8BRgE0Av8BRgE0Av8BRgE0Af8YAAEQAY8BFQH/ARABjwEVAf8BEAGP AY8BEgH/AQ0BjwESAf8BDQGPARIB/wENAY8BEgH/AQ0BjwESAf8BDQGPARIB/wENAY8BEgH/AQ0BjwES
ARUB/wEQAY8BFQH/ARABjwEVAf8BEAGPARUB/wEQAY8BFQH/ARABjwEVAf8BEAGPARUB/wEQAY8BFQH/ Af8BDQGPARIB/wENAY8BEgH/AQ0BjwESAf8BDQGPARIB/wENAY8BEgH/AQ0BjwESAf8EAAPaAf8DGgH/
ARABjwEVAf8BEAGPARUB/wEQAY8BFQH/ARABjwEVAf8EAAPaAf8DHQH/Ax0B/wMdAf8DHQH/Ax0B/wMd AxoB/wMaAf8DGgH/AxoB/wMaAf8DGgH/AxoB/wMaAf8DGgH/A9oB/wMvAUoDBQEHAyABLgMsAUMUAANS
Af8DHQH/Ax0B/wMdAf8DHQH/A9oB/wMvAUoDBQEHAyABLgMsAUMUAANSAakBAAECAaYB/wEAAQIBpgH/ AakCAAGmAf8CAAGmAf8CAAGmAf8CAAGmAf8DXAHJEAADCwEPHAAB/wFDATEC/wFDATEC/wFDATEC/wFD
AQABAgGmAf8BAAECAaYB/wNcAckQAAMLAQ8cAAH/AUYBNAL/AUYBNAL/AUYBNAL/AUYBNAL/AUYBNAH/ ATEC/wFDATEB/xQAAQ0BjwESAf8BDQGPARIB/wENAY8BEgH/AQ0BjwESAf8BDQGPARIB/wENAY8BEgH/
FAABEAGPARUB/wEQAY8BFQH/ARABjwEVAf8BEAGPARUB/wEQAY8BFQH/ARABjwEVAf8BEAGPARUB/wEQ AQ0BjwESAf8BDQGPARIB/wENAY8BEgH/AQ0BjwESAf8BDQGPARIB/wENAY8BEgH/AQ0BjwESAf8BDQGP
AY8BFQH/ARABjwEVAf8BEAGPARUB/wEQAY8BFQH/ARABjwEVAf8BEAGPARUB/wEQAY8BFQH/BAAD2gH/ ARIB/wQAA9oB/wPaAf8D2gH/A9oB/wPaAf8D2gH/A9oB/wPaAf8D2gH/A9oB/wPaAf8D2gH/A9oB/wPa
A9oB/wPaAf8D2gH/A9oB/wPaAf8D2gH/A9oB/wPaAf8D2gH/A9oB/wPaAf8D2gH/A9oB/wPaAf8D2gH/ Af8D2gH/A9oB/xAAA1wByQIAAaYB/wIAAaYB/wEAAQwBrAH/Az4BawETAScBtwH/AgABpgH/A0oBjDAA
EAADXAHJAQABAgGmAf8BAAECAaYB/wEAAQ8BrAH/Az4BawEWASoBtwH/AQABAgGmAf8DSgGMMAAB/wFG Af8BQwExAv8BQwExAv8BQwExAf8sAAENAY8BEgH/AQ0BjwESAf8BDQGPARIB/wENAY8BEgH/GAAD2gH/
ATQC/wFGATQC/wFGATQB/ywAARABjwEVAf8BEAGPARUB/wEQAY8BFQH/ARABjwEVAf8YAAPaAf8DHQH/ AxoB/wMaAf8DGgH/AxoB/wMaAf8DGgH/AxoB/wMaAf8DGgH/AxoB/wMaAf8DGgH/AxoB/wMaAf8D2gH/
Ax0B/wMdAf8DHQH/Ax0B/wMdAf8DHQH/Ax0B/wMdAf8DHQH/Ax0B/wMdAf8DHQH/Ax0B/wPaAf8MAAFG DAABQwFSAcQB/wIAAaYB/wIAAaYB/wIAAaYB/wNSAakEAAMNAREBNQFFAb4B/wEAAQwBrAH/AzEBTTAA
AVUBxAH/AQABAgGmAf8BAAECAaYB/wEAAQIBpgH/A1IBqQQAAw0BEQE4AUgBvgH/AQABDwGsAf8DMQFN Af8BQwExAf8IAAH/AUMBMQL/AUMBMQH/IAABDQGPARIB/wENAY8BEgH/AQ0BjwESAf8BDQGPARIB/xgA
MAAB/wFGATQB/wgAAf8BRgE0Av8BRgE0Af8gAAEQAY8BFQH/ARABjwEVAf8BEAGPARUB/wEQAY8BFQH/ A9oB/wMaAf8DGgH/AxoB/wMaAf8DGgH/AxoB/wMaAf8DGgH/AxoB/wMaAf8DGgH/AxoB/wMaAf8DGgH/
GAAD2gH/Ax0B/wMdAf8DHQH/Ax0B/wMdAf8DHQH/Ax0B/wMdAf8DHQH/Ax0B/wMdAf8DHQH/Ax0B/wMd A9oB/w4AAaYB/wIAAaYB/wIAAaYB/wNfAegQAAFDAVIBxAH/AQMBGQGyAf8DDQERNAAB/wFDATEC/wFD
Af8D2gH/DQABAgGmAf8BAAECAaYB/wEAAQIBpgH/A18B6BAAAUYBVQHEAf8BBgEcAbIB/wMNARE0AAH/ ATEC/wFDATEB/yAAAQ0BjwESAf8BDQGPARIB/wENAY8BEgH/AQ0BjwESAf8YAAPaAf8DGgH/AxoB/wMa
AUYBNAL/AUYBNAL/AUYBNAH/IAABEAGPARUB/wEQAY8BFQH/ARABjwEVAf8BEAGPARUB/xgAA9oB/wMd Af8DGgH/AxoB/wMaAf8DGgH/AxoB/wMaAf8DGgH/AxoB/wMaAf8DGgH/AxoB/wPaAf8MAAETAScBtwH/
Af8DHQH/Ax0B/wMdAf8DHQH/Ax0B/wMdAf8DHQH/Ax0B/wMdAf8DHQH/Ax0B/wMdAf8DHQH/A9oB/wwA AgABpgH/AUMBUgHEAf8YAANfAegBEwEnAbcB/zQAAf8BQwExAv8BQwExAf8kAAENAY8BEgH/AQ0BjwES
ARYBKgG3Af8BAAECAaYB/wFGAVUBxAH/GAADXwHoARYBKgG3Af80AAH/AUYBNAL/AUYBNAH/JAABEAGP Af8BDQGPARIB/wENAY8BEgH/GAAD2gH/A9oB/wPaAf8D2gH/A9oB/wPaAf8D2gH/A9oB/wPaAf8D2gH/
ARUB/wEQAY8BFQH/ARABjwEVAf8BEAGPARUB/xgAA9oB/wPaAf8D2gH/A9oB/wPaAf8D2gH/A9oB/wPa A9oB/wPaAf8D2gH/A9oB/wPaAf8D2gH/BwABAZAAAQ0BjwESAf8BDQGPARIB/wENAY8BEgH/AQ0BjwES
Af8D2gH/A9oB/wPaAf8D2gH/A9oB/wPaAf8D2gH/A9oB/wcAAQGQAAEQAY8BFQH/ARABjwEVAf8BEAGP Af/4AAMBAQKcAAM9AWkDPgFqA0EBcgM3AVoDNwFbAzcBWwM6AWIDSgGLA0sBjiQAA/0B/wP3Af8D9gH/
ARUB/wEQAY8BFQH/+AADAQECnAADPQFpAz4BagNBAXIDNwFaAzcBWwM3AVsDOgFiA0oBiwNLAY4kAAP9 A/YB/wP2Af8D9gH/A/YB/wP2Af8D9gH/A/cB/wP9Af8cAAOKAf8DOgH/AyIB/wMiAf8DIgH/AyIB/wM6
Af8D9wH/A/YB/wP2Af8D9gH/A/YB/wP2Af8D9gH/A/YB/wP3Af8D/QH/HAADigH/Az0B/wMlAf8DJQH/ Af8DigH/EAAD9QH/A/UB/wP1Af8D9QH/A/UB/wP1Af8D9QH/A/UB/wP1Af8D9QH/A/UB/wP1Af8D9QH/
AyUB/wMlAf8DPQH/A4oB/xAAA/UB/wP1Af8D9QH/A/UB/wP1Af8D9QH/A/UB/wP1Af8D9QH/A/UB/wP1 A/UB/wP1Af8EAAM9AWkDGgH/AxoB/wMaAf8DGgH/AxoB/wMaAf8DGgH/A0oBiSQAA/cB/wOGAf8DGgH/
Af8D9QH/A/UB/wP1Af8D9QH/BAADPQFpAx0B/wMdAf8DHQH/Ax0B/wMdAf8DHQH/Ax0B/wNKAYkkAAP3 AxoB/wMaAf8DGgH/AxoB/wMaAf8DGgH/A4YB/wP3Af8UAAO5Af8DIgH/AyIB/wMiAf8DIgH/AyIB/wMi
Af8DhgH/Ax0B/wMdAf8DHQH/Ax0B/wMdAf8DHQH/Ax0B/wOGAf8D9wH/FAADuQH/AyUB/wMlAf8DJQH/ Af8DIgH/AyIB/wMiAf8DIgH/A7kB/wgAA/UB/wMZAf8DGQH/AxkB/wMZAf8DGQH/AxkB/wMZAf8DGQH/
AyUB/wMlAf8DJQH/AyUB/wMlAf8DJQH/AyUB/wO5Af8IAAP1Af8DHAH/AxwB/wMcAf8DHAH/AxwB/wMc AxkB/wMZAf8DGQH/AxkB/wMZAf8D9QH/BAADOwFlAxoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5
Af8DHAH/AxwB/wMcAf8DHAH/AxwB/wMcAf8DHAH/A/UB/wQAAzsBZQMdAf8B+QLqAf8B+QLqAf8B+QLq AuoB/wMaAf8DPgFrAzcBWwM3AVsDNwFbAzcBWxQAA/YB/wMaAf8B8QHvAfAB/wHxAe8B8AH/AfEB7wHw
Af8B+QLqAf8B+QLqAf8DHQH/Az4BawM3AVsDNwFbAzcBWwM3AVsUAAP2Af8DHQH/AfEB7wHwAf8B8QHv Af8B8QHvAfAB/wHxAe8B8AH/AfEB7wHwAf8B8QHvAfAB/wMaAf8D9gH/EAAE/wMiAf8DIgH/AyIB/wMi
AfAB/wHxAe8B8AH/AfEB7wHwAf8B8QHvAfAB/wHxAe8B8AH/AfEB7wHwAf8DHQH/A/YB/xAABP8DJQH/ Af8DIgH/AyIB/wMiAf8DIgH/AyIB/wMiAf8DIgH/AyIB/wgAA/UB/wMZAf8B7gLvAf8B7gLvAf8B7gLv
AyUB/wMlAf8DJQH/AyUB/wMlAf8DJQH/AyUB/wMlAf8DJQH/AyUB/wMlAf8IAAP1Af8DHAH/Ae4C7wH/ Af8DGQH/Ae4C7wH/Ae4C7wH/Ae4C7wH/AxkB/wHuAu8B/wHuAu8B/wHuAu8B/wMZAf8D9QH/BAADLgFI
Ae4C7wH/Ae4C7wH/AxwB/wHuAu8B/wHuAu8B/wHuAu8B/wMcAf8B7gLvAf8B7gLvAf8B7gLvAf8DHAH/ AxoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wMaAf8DGgH/AxoB/wMaAf8DGgH/AzcBWxQA
A/UB/wQAAy4BSAMdAf8B+QLqAf8B+QLqAf8B+QLqAf8B+QLqAf8B+QLqAf8DHQH/Ax0B/wMdAf8DHQH/ A/YB/wMaAf8B8QHvAfAB/wMaAf8B8QHvAfAB/wMaAf8B8QHvAfAB/wMaAf8B8QHvAfAB/wMaAf8D9gH/
Ax0B/wM3AVsUAAP2Af8DHQH/AfEB7wHwAf8DHQH/AfEB7wHwAf8DHQH/AfEB7wHwAf8DHQH/AfEB7wHw EAAE/wMiAf8DIgH/AyIB/wMiAf8DIgH/AyIB/wMiAf8DIgH/AyIB/wMiAf8DIgH/AyIB/wgAA/UB/wMZ
Af8DHQH/A/YB/xAABP8DJQH/AyUB/wMlAf8DJQH/AyUB/wMlAf8DJQH/AyUB/wMlAf8DJQH/AyUB/wMl Af8B7gLvAf8B7gLvAf8B7gLvAf8DGQH/Ae4C7wH/Ae4C7wH/Ae4C7wH/AxkB/wHuAu8B/wHuAu8B/wHu
Af8IAAP1Af8DHAH/Ae4C7wH/Ae4C7wH/Ae4C7wH/AxwB/wHuAu8B/wHuAu8B/wHuAu8B/wMcAf8B7gLv Au8B/wMZAf8D9QH/BAADLAFDAxoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wMaAf8DNwFb
Af8B7gLvAf8B7gLvAf8DHAH/A/UB/wQAAywBQwMdAf8B+QLqAf8B+QLqAf8B+QLqAf8B+QLqAf8B+QLq AzcBWwM3AVsDGgH/AzcBWxQAA/YB/wMaAf8B8QHvAfAB/wHxAe8B8AH/AfEB7wHwAf8B8QHvAfAB/wHx
Af8DHQH/AzcBWwM3AVsDNwFbAx0B/wM3AVsUAAP2Af8DHQH/AfEB7wHwAf8B8QHvAfAB/wHxAe8B8AH/ Ae8B8AH/AxoB/wHxAe8B8AH/AxoB/wP2Af8QAAT/AyIB/wMiAf8DIgH/AyIB/wMiAf8DIgH/AyIB/wMi
AfEB7wHwAf8B8QHvAfAB/wMdAf8B8QHvAfAB/wMdAf8D9gH/EAAE/wMlAf8DJQH/AyUB/wMlAf8DJQH/ Af8DIgH/AyIB/wMiAf8DIgH/CAAD9QH/AxkB/wMZAf8DGQH/AxkB/wMZAf8DGQH/AxkB/wMZAf8DGQH/
AyUB/wMlAf8DJQH/AyUB/wMlAf8DJQH/AyUB/wgAA/UB/wMcAf8DHAH/AxwB/wMcAf8DHAH/AxwB/wMc AxkB/wMZAf8DGQH/AxkB/wP1Af8EAAMrAUIDGgH/AxoB/wMaAf8DGgH/AxoB/wMaAf8DGgH/AzcBWwQA
Af8DHAH/AxwB/wMcAf8DHAH/AxwB/wMcAf8D9QH/BAADKwFCAx0B/wMdAf8DHQH/Ax0B/wMdAf8DHQH/ AzcBWwMaAf8DNwFbFAAD9gH/AxoB/wHxAe8B8AH/AxoB/wHxAe8B8AH/AxoB/wHxAe8B8AH/AxoB/wHx
Ax0B/wM3AVsEAAM3AVsDHQH/AzcBWxQAA/YB/wMdAf8B8QHvAfAB/wMdAf8B8QHvAfAB/wMdAf8B8QHv Ae8B8AH/AxoB/wP2Af8QAAT/AyIB/wMiAf8DIgH/AyIB/wMiAf8DIgH/AyIB/wMiAf8DIgH/AyIB/wMi
AfAB/wMdAf8B8QHvAfAB/wMdAf8D9gH/EAAE/wMlAf8DJQH/AyUB/wMlAf8DJQH/AyUB/wMlAf8DJQH/ Af8DIgH/CAAD9QH/AxkB/wHuAu8B/wHuAu8B/wHuAu8B/wMZAf8B7gLvAf8B7gLvAf8B7gLvAf8DGQH/
AyUB/wMlAf8DJQH/AyUB/wgAA/UB/wMcAf8B7gLvAf8B7gLvAf8B7gLvAf8DHAH/Ae4C7wH/Ae4C7wH/ Ae4C7wH/Ae4C7wH/Ae4C7wH/AxkB/wP1Af8EAAMoATwDGgH/AxoB/wMaAf8DGgH/AxoB/wMaAf8DGgH/
Ae4C7wH/AxwB/wHuAu8B/wHuAu8B/wHuAu8B/wMcAf8D9QH/BAADKAE8Ax0B/wMdAf8DHQH/Ax0B/wMd AzcBWwQAAzcBWwMaAf8DQAFxFAAD9gH/AxoB/wHxAe8B8AH/AfEB7wHwAf8B8QHvAfAB/wHxAe8B8AH/
Af8DHQH/Ax0B/wM3AVsEAAM3AVsDHQH/A0ABcRQAA/YB/wMdAf8B8QHvAfAB/wHxAe8B8AH/AfEB7wHw AfEB7wHwAf8B8QHvAfAB/wHxAe8B8AH/AxoB/wP2Af8QAAT/AyIB/wMiAf8DIgH/AyIB/wMiAf8DIgH/
Af8B8QHvAfAB/wHxAe8B8AH/AfEB7wHwAf8B8QHvAfAB/wMdAf8D9gH/EAAE/wMlAf8DJQH/AyUB/wMl AyIB/wMiAf8DIgH/AyIB/wMiAf8DIgH/CAAD9QH/AxkB/wHuAu8B/wHuAu8B/wHuAu8B/wMZAf8B7gLv
Af8DJQH/AyUB/wMlAf8DJQH/AyUB/wMlAf8DJQH/AyUB/wgAA/UB/wMcAf8B7gLvAf8B7gLvAf8B7gLv Af8B7gLvAf8B7gLvAf8DGQH/Ae4C7wH/Ae4C7wH/Ae4C7wH/AxkB/wP1Af8EAAMqAUEDKgFBAygBPQMl
Af8DHAH/Ae4C7wH/Ae4C7wH/Ae4C7wH/AxwB/wHuAu8B/wHuAu8B/wHuAu8B/wMcAf8D9QH/BAADKgFB ATcDJwE7Ay4BSAM2AVkDNwFbAzcBWwQAAzcBWwMaAf8DSgGNFAAD9gH/AxoB/wHxAe8B8AH/AxoB/wHx
AyoBQQMoAT0DJQE3AycBOwMuAUgDNgFZAzcBWwM3AVsEAAM3AVsDHQH/A0oBjRQAA/YB/wMdAf8B8QHv Ae8B8AH/AxoB/wHxAe8B8AH/AxoB/wHxAe8B8AH/AxoB/wP2Af8QAAT/AyIB/wMiAf8DIgH/AyIB/wMi
AfAB/wMdAf8B8QHvAfAB/wMdAf8B8QHvAfAB/wMdAf8B8QHvAfAB/wMdAf8D9gH/EAAE/wMlAf8DJQH/ Af8DIgH/AyIB/wMiAf8DIgH/AyIB/wMiAf8DIgH/CAAD9QH/AxkB/wMZAf8DGQH/AxkB/wMZAf8DGQH/
AyUB/wMlAf8DJQH/AyUB/wMlAf8DJQH/AyUB/wMlAf8DJQH/AyUB/wgAA/UB/wMcAf8DHAH/AxwB/wMc AxkB/wMZAf8DGQH/AxkB/wMZAf8DGQH/AxkB/wP1Af8cAAM1AVYDNwFbAzcBWwM3AVsDNwFbAxoB/wNL
Af8DHAH/AxwB/wMcAf8DHAH/AxwB/wMcAf8DHAH/AxwB/wMcAf8D9QH/HAADNQFWAzcBWwM3AVsDNwFb AY4DSgGMA0cBgQwAA/YB/wMaAf8B8QHvAfAB/wHxAe8B8AH/AfEB7wHwAf8B8QHvAfAB/wHxAe8B8AH/
AzcBWwMdAf8DSwGOA0oBjANHAYEMAAP2Af8DHQH/AfEB7wHwAf8B8QHvAfAB/wHxAe8B8AH/AfEB7wHw AfEB7wHwAf8B8QHvAfAB/wMaAf8D9gH/EAAE/wMiAf8DIgH/AyIB/wMiAf8DIgH/AyIB/wMiAf8DIgH/
Af8B8QHvAfAB/wHxAe8B8AH/AfEB7wHwAf8DHQH/A/YB/xAABP8DJQH/AyUB/wMlAf8DJQH/AyUB/wMl AyIB/wMiAf8DIgH/AyIB/wgAA/UB/wMZAf8B7gLvAf8B7gLvAf8B7gLvAf8DGQH/Ae4C7wH/Ae4C7wH/
Af8DJQH/AyUB/wMlAf8DJQH/AyUB/wMlAf8IAAP1Af8DHAH/Ae4C7wH/Ae4C7wH/Ae4C7wH/AxwB/wHu Ae4C7wH/AxkB/wHuAu8B/wHuAu8B/wHuAu8B/wMZAf8D9QH/HAADKQE+AxoB/wMaAf8DGgH/AxoB/wMa
Au8B/wHuAu8B/wHuAu8B/wMcAf8B7gLvAf8B7gLvAf8B7gLvAf8DHAH/A/UB/xwAAykBPgMdAf8DHQH/ Af8DGgH/AxoB/wM9AWgMAAP2Af8DGgH/AfEB7wHwAf8DGgH/AfEB7wHwAf8DGgH/AfEB7wHwAf8DGgH/
Ax0B/wMdAf8DHQH/Ax0B/wMdAf8DPQFoDAAD9gH/Ax0B/wHxAe8B8AH/Ax0B/wHxAe8B8AH/Ax0B/wHx AfEB7wHwAf8DGgH/A/YB/xAABP8DIgH/Ay0B/wOpAf8C4QHiAf8D+AH/A/gB/wP4Af8D+AH/AuEB4gH/
Ae8B8AH/Ax0B/wHxAe8B8AH/Ax0B/wP2Af8QAAT/AyUB/wMwAf8DqQH/AuEB4gH/A/gB/wP4Af8D+AH/ A6kB/wMtAf8DIgH/CAAD9QH/AxkB/wHuAu8B/wHuAu8B/wHuAu8B/wMZAf8B7gLvAf8B7gLvAf8B7gLv
A/gB/wLhAeIB/wOpAf8DMAH/AyUB/wgAA/UB/wMcAf8B7gLvAf8B7gLvAf8B7gLvAf8DHAH/Ae4C7wH/ Af8DGQH/Ae4C7wH/Ae4C7wH/Ae4C7wH/AxkB/wP1Af8cAAMlATcDGgH/AfkC6gH/AfkC6gH/AfkC6gH/
Ae4C7wH/Ae4C7wH/AxwB/wHuAu8B/wHuAu8B/wHuAu8B/wMcAf8D9QH/HAADJQE3Ax0B/wH5AuoB/wH5 AfkC6gH/AfkC6gH/AxoB/wM7AWMMAAP2Af8DGgH/AfEB7wHwAf8B8QHvAfAB/wHxAe8B8AH/AfEB7wHw
AuoB/wH5AuoB/wH5AuoB/wH5AuoB/wMdAf8DOwFjDAAD9gH/Ax0B/wHxAe8B8AH/AfEB7wHwAf8B8QHv Af8B8QHvAfAB/wHxAe8B8AH/AfEB7wHwAf8DGgH/A/YB/xAAA/MB/wMtAf8D7QH/A/gB/wP4Af8D+AH/
AfAB/wHxAe8B8AH/AfEB7wHwAf8B8QHvAfAB/wHxAe8B8AH/Ax0B/wP2Af8QAAPzAf8DMAH/A+0B/wP4 A/gB/wP4Af8D+AH/A/gB/wP4Af8D7QH/AyIB/wgAA/UB/wMZAf8DGQH/AxkB/wMZAf8DGQH/AxkB/wMZ
Af8D+AH/A/gB/wP4Af8D+AH/A/gB/wP4Af8D+AH/A+0B/wMlAf8IAAP1Af8DHAH/AxwB/wMcAf8DHAH/ Af8DGQH/AxkB/wMZAf8DGQH/AxkB/wMZAf8D9QH/HAADJQE3AxoB/wH5AuoB/wH5AuoB/wH5AuoB/wH5
AxwB/wMcAf8DHAH/AxwB/wMcAf8DHAH/AxwB/wMcAf8DHAH/A/UB/xwAAyUBNwMdAf8B+QLqAf8B+QLq AuoB/wH5AuoB/wMaAf8DLwFKDAAD9gH/AxoB/wHxAe8B8AH/AxoB/wMaAf8DGgH/AxoB/wMaAf8B8QHv
Af8B+QLqAf8B+QLqAf8B+QLqAf8DHQH/Ay8BSgwAA/YB/wMdAf8B8QHvAfAB/wMdAf8DHQH/Ax0B/wMd AfAB/wMaAf8D9gH/FAADLQH/A+0B/wP4Af8D+AH/A/gB/wP4Af8D+AH/A/gB/wP4Af8D+AH/A+0B/wMi
Af8DHQH/AfEB7wHwAf8DHQH/A/YB/xQAAzAB/wPtAf8D+AH/A/gB/wP4Af8D+AH/A/gB/wP4Af8D+AH/ Af8IAAP1Af8DGQH/AxkB/wMZAf8DGQH/AxkB/wMZAf8DGQH/AxkB/wMZAf8DGQH/AxkB/wMZAf8DGQH/
A/gB/wPtAf8DJQH/CAAD9QH/AxwB/wMcAf8DHAH/AxwB/wMcAf8DHAH/AxwB/wMcAf8DHAH/AxwB/wMc A/UB/xwAAyUBNwMaAf8B+QLqAf8B+QLqAf8B+QLqAf8B+QLqAf8B+QLqAf8DGgH/AysBQgwAA/YB/wMa
Af8DHAH/AxwB/wP1Af8cAAMlATcDHQH/AfkC6gH/AfkC6gH/AfkC6gH/AfkC6gH/AfkC6gH/Ax0B/wMr Af8B8QHvAfAB/wMaAf8DGgH/AxoB/wMaAf8DGgH/AfEB7wHwAf8DGgH/A/YB/xQAA7kB/wMtAf8DqQH/
AUIMAAP2Af8DHQH/AfEB7wHwAf8DHQH/Ax0B/wMdAf8DHQH/Ax0B/wHxAe8B8AH/Ax0B/wP2Af8UAAO5 AuEB4gH/A/gB/wP4Af8D+AH/A/gB/wLhAeIB/wOpAf8DLQH/A7kB/wgAA/UB/wMZAf8DGQH/AxkB/wMZ
Af8DMAH/A6kB/wLhAeIB/wP4Af8D+AH/A/gB/wP4Af8C4QHiAf8DqQH/AzAB/wO5Af8IAAP1Af8DHAH/ Af8DGQH/AxkB/wMZAf8DGQH/AxkB/wMZAf8DGQH/AxkB/wMZAf8D9QH/HAADKgFAAxoB/wMaAf8DGgH/
AxwB/wMcAf8DHAH/AxwB/wMcAf8DHAH/AxwB/wMcAf8DHAH/AxwB/wMcAf8DHAH/A/UB/xwAAyoBQAMd AxoB/wMaAf8DGgH/AxoB/wMrAUIMAAP2Af8DGgH/AfEB7wHwAf8B8QHvAfAB/wHxAe8B8AH/AfEB7wHw
Af8DHQH/Ax0B/wMdAf8DHQH/Ax0B/wMdAf8DKwFCDAAD9gH/Ax0B/wHxAe8B8AH/AfEB7wHwAf8B8QHv Af8B8QHvAfAB/wHxAe8B8AH/AfEB7wHwAf8DGgH/A/YB/xgAA+gB/wOKAf8DOgH/AyIB/wMiAf8DIgH/
AfAB/wHxAe8B8AH/AfEB7wHwAf8B8QHvAfAB/wHxAe8B8AH/Ax0B/wP2Af8YAAPoAf8DigH/Az0B/wMl AyIB/wM6Af8DigH/A+gB/wwAA/UB/wP1Af8D9QH/A/UB/wP1Af8D9QH/A/UB/wP1Af8D9QH/A/UB/wP1
Af8DJQH/AyUB/wMlAf8DPQH/A4oB/wPoAf8MAAP1Af8D9QH/A/UB/wP1Af8D9QH/A/UB/wP1Af8D9QH/ Af8D9QH/A/UB/wP1Af8D9QH/HAADKwFCAxoB/wMaAf8DGgH/AxoB/wMaAf8DGgH/AxoB/wMzAVMMAAP3
A/UB/wP1Af8D9QH/A/UB/wP1Af8D9QH/A/UB/xwAAysBQgMdAf8DHQH/Ax0B/wMdAf8DHQH/Ax0B/wMd Af8DhgH/AxoB/wMaAf8DGgH/AxoB/wMaAf8DGgH/AxoB/wOGAf8D9wH/pAADKwFCAy4BRwM+AWoDRwGB
Af8DMwFTDAAD9wH/A4YB/wMdAf8DHQH/Ax0B/wMdAf8DHQH/Ax0B/wMdAf8DhgH/A/cB/6QAAysBQgMu A0oBiQM3AVsDNwFbAzcBWgM3AVoMAAP9Af8D9wH/A/YB/wP2Af8D9gH/A/YB/wP2Af8D9gH/A/YB/wP3
AUcDPgFqA0cBgQNKAYkDNwFbAzcBWwM3AVoDNwFaDAAD/QH/A/cB/wP2Af8D9gH/A/YB/wP2Af8D9gH/ Af8D/QH/DAABQgFNAT4HAAE+AwABKAMAAUADAAFgAwABAQEAAQEGAAEDFgAD/wEABv8CAAH8AT8C/wHn
A/YB/wP2Af8D9wH/A/0B/wwAAUIBTQE+BwABPgMAASgDAAFAAwABYAMAAQEBAAEBBgABAxYAA/8BAAb/ Af8CAAH8AT8B/AF4AfMB/wIAAfwBPwH+AXgB+wEnAgAB/AE/AT4BcAH5ASsCAAH8AT8BHgEBAfkBzwIA
AgAB/AE/Av8B5wH/AgAB/AE/AfwBeAHzAf8CAAH8AT8B/gF4AfsBJwIAAfwBPwE+AXAB+QErAgAB/AE/ AYABAQGMAQMB+QHPAgABgAEBAcgBMwH5Ac8CAAGAAQEB4QEDAfwBkwIAAYABAQHjAYcB/AH/AgAB/AE/
AR4BAQH5Ac8CAAGAAQEBjAEDAfkBzwIAAYABAQHIATMB+QHPAgABgAEBAeEBAwH8AZMCAAGAAQEB4wGH AQABBwH4AX8CAAH8AT8BAAEHAf4B/wIAAfwBPwECAQ8B/gH/AgAB/AE/AeMB/wH+AT8CAAH8AT8D/wE/
AfwB/wIAAfwBPwEAAQcB+AF/AgAB/AE/AQABBwH+Af8CAAH8AT8BAgEPAf4B/wIAAfwBPwHjAf8B/gE/ AgAB/wF/BP8CAAj/AgABgAF5BP8CAAGAAXEBxwH5AfABHwIAAYABYwHDAfEB4AEPAgABgAEHAcEBwwHg
AgAB/AE/A/8BPwIAAf8BfwT/AgAI/wIAAYABeQT/AgABgAFxAccB+QHwAR8CAAGAAWMBwwHxAeABDwIA AQcCAAGAAQ8B4AGHAcABAwIAAYABAQHwAQcBwAEDAgABgAEBAfgBBwHAAQMCAAGAAQEB/AEfAcABAwIA
AYABBwHBAcMB4AEHAgABgAEPAeABhwHAAQMCAAGAAQEB8AEHAcABAwIAAYABAQH4AQcBwAEDAgABgAEB AYABAQH4AR4BwAEDAgAB/AEBAfABDwHAAQMCAAH+AQEB4AGHAcABAwIAAf4BAQHhAeMB4AEHAgAB/gED
AfwBHwHAAQMCAAGAAQEB+AEeAcABAwIAAfwBAQHwAQ8BwAEDAgAB/gEBAeABhwHAAQMCAAH+AQEB4QHj AeMB8wHwAQ8CAAH+AQcBvwP/AgAI/wMAAQMBAAEfBQABAQEAAR8HAAEHBwABBwcAAQcBgAEBBgABgAEB
AeABBwIAAf4BAwHjAfMB8AEPAgAB/gEHAb8D/wIACP8DAAEDAQABHwUAAQEBAAEfBwABBwcAAQcHAAEH BgABwAEDAgABgAEAAYABAAHAAQMCAAGAAQABgAEAAeABBwIAAYABAAGAAQAB8AEHAgABgAEAAYABAAHw
AYABAQYAAYABAQYAAcABAwIAAYABAAGAAQABwAEDAgABgAEAAYABAAHgAQcCAAGAAQABgAEAAfABBwIA AQ8CAAGAAQABgAEAAfgBHwIAAcABAAGAAQAB+AEfAgABwAEAAfABAAH8AT8CAAHgAQEB8AEAAfwBPwIA
AYABAAGAAQAB8AEPAgABgAEAAYABAAH4AR8CAAHAAQABgAEAAfgBHwIAAcABAAHwAQAB/AE/AgAB4AEB AfABAwHwAQAK/wEAAQEBAAEBAfABDwHwAR8BAAEBAQABAQHgAQcB4AEPAQABAQEAAQEBwAEDAeABBwEA
AfABAAH8AT8CAAHwAQMB8AEACv8BAAEBAQABAQHwAQ8B8AEfAQABAQEAAQEB4AEHAeABDwEAAQEBAAEB AQEBAAEBAYABAQHAAQMBAAEBAQABAQGAAQEBwAEDAQABAQEAAQEBAAEBAcABAwEAAQEBAAEBAQABAQHA
AcABAwHgAQcBAAEBAQABAQGAAQEBwAEDAQABAQEAAQEBgAEBAcABAwEAAQEBAAEBAQABAQHAAQMBAAEB AQMBAAEBAQABAQEAAQEBwAEDAQABAQEAAQEBAAEBAcABAwEAAQEBAAEBAQABAQHAAQMBAAEBAQABAQGA
AQABAQEAAQEBwAEDAQABAQEAAQEBAAEBAcABAwEAAQEBAAEBAQABAQHAAQMBAAEBAQABAQEAAQEBwAED AQEB4AEHAQABAQEAAQEBgAEBAfABDwEAAQEBAAEBAcABAwL/AQABAQEAAQEB4AEHAv8BAAEBAQABAQHw
AQABAQEAAQEBgAEBAeABBwEAAQEBAAEBAYABAQHwAQ8BAAEBAQABAQHAAQMC/wEAAQEBAAEBAeABBwL/ AR8O/wH8AT8BAAF/AccB+QHPAf8B/AE/AQABFwHDAfEB2wH/AfwBPwEAAUcBwQHDAfEB/wH8AT8BAAED
AQABAQEAAQEB8AEfDv8B/AE/AQABfwHHAfkBzwH/AfwBPwEAARcBwwHxAdsB/wH8AT8BAAFHAcEBwwHx AeABhwHgAf8B/AE/AQABAwHwAQcB8AF/AYABAQIAAfgBBwH4AT8BgAEBAQABBwH8AR8B/AEfAYABAQIA
Af8B/AE/AQABAwHgAYcB4AH/AfwBPwEAAQMB8AEHAfABfwGAAQECAAH4AQcB+AE/AYABAQEAAQcB/AEf AfgBHgH+AQ8BgAEBAgAB8AEPAf8BHwH8AT8CAAHgAYcB/wGzAfwBPwIAAeEB4wH/AeMB/AE/AgAB4wHz
AfwBHwGAAQECAAH4AR4B/gEPAYABAQIAAfABDwH/AR8B/AE/AgAB4AGHAf8BswH8AT8CAAHhAeMB/wHj Af8B5wH8AT8CAAG/A/8B/AE/B/8BfwT/AQABfwHAAQcB8AEPAQABAQEAAX8BwAEHAcABAwEAAQEBAAEH
AfwBPwIAAeMB8wH/AecB/AE/AgABvwP/AfwBPwf/AX8E/wEAAX8BwAEHAfABDwEAAQEBAAF/AcABBwHA AcABBwGAAQMBAAEBAQABBwHAAQcBgAEDAQABAQEAAQcBwAEHAYABAwEAAQEBAAFHAcABBwGAAQMBAAEB
AQMBAAEBAQABBwHAAQcBgAEDAQABAQEAAQcBwAEHAYABAwEAAQEBAAEHAcABBwGAAQMBAAEBAQABRwHA AQABRwHAAQcBgAEDAQABAQEAAUcBwAEHAYABAwEAAQEB/AEBAcABBwGAAQMBAAEBAfwBAQHAAQcBgAED
AQcBgAEDAQABAQEAAUcBwAEHAYABAwEAAQEBAAFHAcABBwGAAQMBAAEBAfwBAQHAAQcBgAEDAQABAQH8 AQABAQH8AQEBwAEHAYABAwEAAQEB/AEBAcABBwHAAQMBAAEBAfwBAQHAAQcBwAEDAQABAQH8AQEBwAEH
AQEBwAEHAYABAwEAAQEB/AEBAcABBwGAAQMBAAEBAfwBAQHAAQcBwAEDAQABAQH8AQEBwAEHAcABAwEA AeABBwEAAQEB/AEBAcABBwT/AfwBAQHAAQcL
AQEB/AEBAcABBwHgAQcBAAEBAfwBAQHAAQcE/wH8AQEBwAEHCw==
</value> </value>
</data> </data>
</root> </root>

View File

@ -0,0 +1,314 @@
namespace BismNormalizer.TabularCompare.UI
{
partial class ConnectionsAlmt
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.cboSourceDatabase = new System.Windows.Forms.ComboBox();
this.cboSourceServer = new System.Windows.Forms.ComboBox();
this.label2 = new System.Windows.Forms.Label();
this.label1 = new System.Windows.Forms.Label();
this.pnlSourceDb = new System.Windows.Forms.Panel();
this.grpSource = new System.Windows.Forms.GroupBox();
this.btnOK = new System.Windows.Forms.Button();
this.btnCancel = new System.Windows.Forms.Button();
this.btnSwitch = new System.Windows.Forms.Button();
this.panel2 = new System.Windows.Forms.Panel();
this.panel1 = new System.Windows.Forms.Panel();
this.grpTarget = new System.Windows.Forms.GroupBox();
this.label3 = new System.Windows.Forms.Label();
this.label4 = new System.Windows.Forms.Label();
this.pnlTargetDb = new System.Windows.Forms.Panel();
this.cboTargetServer = new System.Windows.Forms.ComboBox();
this.cboTargetDatabase = new System.Windows.Forms.ComboBox();
this.pnlSourceDb.SuspendLayout();
this.grpSource.SuspendLayout();
this.panel2.SuspendLayout();
this.panel1.SuspendLayout();
this.grpTarget.SuspendLayout();
this.pnlTargetDb.SuspendLayout();
this.SuspendLayout();
//
// cboSourceDatabase
//
this.cboSourceDatabase.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.cboSourceDatabase.FormattingEnabled = true;
this.cboSourceDatabase.Location = new System.Drawing.Point(26, 87);
this.cboSourceDatabase.Margin = new System.Windows.Forms.Padding(7);
this.cboSourceDatabase.MaxDropDownItems = 11;
this.cboSourceDatabase.Name = "cboSourceDatabase";
this.cboSourceDatabase.Size = new System.Drawing.Size(858, 37);
this.cboSourceDatabase.TabIndex = 2;
this.cboSourceDatabase.Enter += new System.EventHandler(this.cboSourceDatabase_Enter);
//
// cboSourceServer
//
this.cboSourceServer.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.cboSourceServer.FormattingEnabled = true;
this.cboSourceServer.Location = new System.Drawing.Point(26, 16);
this.cboSourceServer.Margin = new System.Windows.Forms.Padding(7);
this.cboSourceServer.MaxDropDownItems = 11;
this.cboSourceServer.Name = "cboSourceServer";
this.cboSourceServer.Size = new System.Drawing.Size(858, 37);
this.cboSourceServer.TabIndex = 1;
this.cboSourceServer.TextChanged += new System.EventHandler(this.cboSourceServer_TextChanged);
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(18, 154);
this.label2.Margin = new System.Windows.Forms.Padding(7, 0, 7, 0);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(94, 29);
this.label2.TabIndex = 2;
this.label2.Text = "Dataset";
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(14, 83);
this.label1.Margin = new System.Windows.Forms.Padding(7, 0, 7, 0);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(134, 29);
this.label1.TabIndex = 1;
this.label1.Text = "Workspace";
//
// pnlSourceDb
//
this.pnlSourceDb.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.pnlSourceDb.Controls.Add(this.cboSourceServer);
this.pnlSourceDb.Controls.Add(this.cboSourceDatabase);
this.pnlSourceDb.Location = new System.Drawing.Point(147, 60);
this.pnlSourceDb.Margin = new System.Windows.Forms.Padding(7);
this.pnlSourceDb.Name = "pnlSourceDb";
this.pnlSourceDb.Size = new System.Drawing.Size(910, 147);
this.pnlSourceDb.TabIndex = 1;
//
// grpSource
//
this.grpSource.Controls.Add(this.label1);
this.grpSource.Controls.Add(this.label2);
this.grpSource.Controls.Add(this.pnlSourceDb);
this.grpSource.Dock = System.Windows.Forms.DockStyle.Top;
this.grpSource.Location = new System.Drawing.Point(0, 0);
this.grpSource.Margin = new System.Windows.Forms.Padding(7);
this.grpSource.Name = "grpSource";
this.grpSource.Padding = new System.Windows.Forms.Padding(7);
this.grpSource.Size = new System.Drawing.Size(1069, 263);
this.grpSource.TabIndex = 16;
this.grpSource.TabStop = false;
this.grpSource.Text = "Source";
//
// btnOK
//
this.btnOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnOK.DialogResult = System.Windows.Forms.DialogResult.OK;
this.btnOK.Location = new System.Drawing.Point(696, 23);
this.btnOK.Margin = new System.Windows.Forms.Padding(7);
this.btnOK.Name = "btnOK";
this.btnOK.Size = new System.Drawing.Size(161, 51);
this.btnOK.TabIndex = 6;
this.btnOK.Text = "OK";
this.btnOK.UseVisualStyleBackColor = true;
this.btnOK.Click += new System.EventHandler(this.btnOK_Click);
//
// btnCancel
//
this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.btnCancel.Location = new System.Drawing.Point(871, 23);
this.btnCancel.Margin = new System.Windows.Forms.Padding(7);
this.btnCancel.Name = "btnCancel";
this.btnCancel.Size = new System.Drawing.Size(166, 51);
this.btnCancel.TabIndex = 7;
this.btnCancel.Text = "Cancel";
this.btnCancel.UseVisualStyleBackColor = true;
//
// btnSwitch
//
this.btnSwitch.BackgroundImage = global::BismNormalizer.Resources.ButtonSwitch;
this.btnSwitch.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Center;
this.btnSwitch.Location = new System.Drawing.Point(467, 6);
this.btnSwitch.Margin = new System.Windows.Forms.Padding(7);
this.btnSwitch.Name = "btnSwitch";
this.btnSwitch.Size = new System.Drawing.Size(130, 71);
this.btnSwitch.TabIndex = 3;
this.btnSwitch.UseVisualStyleBackColor = true;
this.btnSwitch.Click += new System.EventHandler(this.btnSwitch_Click);
//
// panel2
//
this.panel2.Controls.Add(this.btnCancel);
this.panel2.Controls.Add(this.btnOK);
this.panel2.Dock = System.Windows.Forms.DockStyle.Bottom;
this.panel2.Location = new System.Drawing.Point(0, 627);
this.panel2.Name = "panel2";
this.panel2.Size = new System.Drawing.Size(1069, 100);
this.panel2.TabIndex = 22;
//
// panel1
//
this.panel1.Controls.Add(this.btnSwitch);
this.panel1.Dock = System.Windows.Forms.DockStyle.Top;
this.panel1.Location = new System.Drawing.Point(0, 263);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(1069, 84);
this.panel1.TabIndex = 25;
//
// grpTarget
//
this.grpTarget.Controls.Add(this.label3);
this.grpTarget.Controls.Add(this.label4);
this.grpTarget.Controls.Add(this.pnlTargetDb);
this.grpTarget.Dock = System.Windows.Forms.DockStyle.Top;
this.grpTarget.Location = new System.Drawing.Point(0, 347);
this.grpTarget.Margin = new System.Windows.Forms.Padding(7);
this.grpTarget.Name = "grpTarget";
this.grpTarget.Padding = new System.Windows.Forms.Padding(7);
this.grpTarget.Size = new System.Drawing.Size(1069, 268);
this.grpTarget.TabIndex = 26;
this.grpTarget.TabStop = false;
this.grpTarget.Text = "Target";
//
// label3
//
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(15, 83);
this.label3.Margin = new System.Windows.Forms.Padding(7, 0, 7, 0);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(134, 29);
this.label3.TabIndex = 4;
this.label3.Text = "Workspace";
//
// label4
//
this.label4.AutoSize = true;
this.label4.Location = new System.Drawing.Point(15, 154);
this.label4.Margin = new System.Windows.Forms.Padding(7, 0, 7, 0);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(94, 29);
this.label4.TabIndex = 5;
this.label4.Text = "Dataset";
//
// pnlTargetDb
//
this.pnlTargetDb.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.pnlTargetDb.Controls.Add(this.cboTargetServer);
this.pnlTargetDb.Controls.Add(this.cboTargetDatabase);
this.pnlTargetDb.Location = new System.Drawing.Point(144, 60);
this.pnlTargetDb.Margin = new System.Windows.Forms.Padding(7);
this.pnlTargetDb.Name = "pnlTargetDb";
this.pnlTargetDb.Size = new System.Drawing.Size(911, 147);
this.pnlTargetDb.TabIndex = 15;
//
// cboTargetServer
//
this.cboTargetServer.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.cboTargetServer.FormattingEnabled = true;
this.cboTargetServer.Location = new System.Drawing.Point(26, 16);
this.cboTargetServer.Margin = new System.Windows.Forms.Padding(7);
this.cboTargetServer.MaxDropDownItems = 11;
this.cboTargetServer.Name = "cboTargetServer";
this.cboTargetServer.Size = new System.Drawing.Size(862, 37);
this.cboTargetServer.TabIndex = 4;
this.cboTargetServer.TextChanged += new System.EventHandler(this.cboTargetServer_TextChanged);
//
// cboTargetDatabase
//
this.cboTargetDatabase.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.cboTargetDatabase.FormattingEnabled = true;
this.cboTargetDatabase.Location = new System.Drawing.Point(26, 87);
this.cboTargetDatabase.Margin = new System.Windows.Forms.Padding(7);
this.cboTargetDatabase.MaxDropDownItems = 11;
this.cboTargetDatabase.Name = "cboTargetDatabase";
this.cboTargetDatabase.Size = new System.Drawing.Size(862, 37);
this.cboTargetDatabase.TabIndex = 5;
this.cboTargetDatabase.Enter += new System.EventHandler(this.cboTargetDatabase_Enter);
//
// Connections
//
this.AcceptButton = this.btnOK;
this.AutoScaleDimensions = new System.Drawing.SizeF(14F, 29F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.btnCancel;
this.ClientSize = new System.Drawing.Size(1069, 727);
this.Controls.Add(this.grpTarget);
this.Controls.Add(this.panel1);
this.Controls.Add(this.panel2);
this.Controls.Add(this.grpSource);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.Margin = new System.Windows.Forms.Padding(7);
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "Connections";
this.ShowIcon = false;
this.ShowInTaskbar = false;
this.Text = "Connections";
this.Load += new System.EventHandler(this.Connections_Load);
this.pnlSourceDb.ResumeLayout(false);
this.grpSource.ResumeLayout(false);
this.grpSource.PerformLayout();
this.panel2.ResumeLayout(false);
this.panel1.ResumeLayout(false);
this.grpTarget.ResumeLayout(false);
this.grpTarget.PerformLayout();
this.pnlTargetDb.ResumeLayout(false);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.ComboBox cboSourceDatabase;
private System.Windows.Forms.ComboBox cboSourceServer;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Panel pnlSourceDb;
private System.Windows.Forms.GroupBox grpSource;
private System.Windows.Forms.Button btnOK;
private System.Windows.Forms.Button btnCancel;
private System.Windows.Forms.Button btnSwitch;
private System.Windows.Forms.Panel panel2;
private System.Windows.Forms.Panel panel1;
private System.Windows.Forms.GroupBox grpTarget;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.Label label4;
private System.Windows.Forms.Panel pnlTargetDb;
private System.Windows.Forms.ComboBox cboTargetServer;
private System.Windows.Forms.ComboBox cboTargetDatabase;
}
}

View File

@ -0,0 +1,243 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Windows.Forms;
using Microsoft.AnalysisServices;
using System.Drawing;
namespace BismNormalizer.TabularCompare.UI
{
public partial class ConnectionsAlmt : Form
{
private ComparisonInfo _comparisonInfo;
private float _dpiScaleFactor;
private bool _sourceDatabaseBound = false;
private bool _targetDatabaseBound = false;
public ConnectionsAlmt()
{
InitializeComponent();
}
private void Connections_Load(object sender, EventArgs e)
{
this.Width = Convert.ToInt32(this.Width * 1.3);
if (_dpiScaleFactor > 1)
{
//DPI
float dpiScaleFactorFudged = _dpiScaleFactor * HighDPIUtils.PrimaryFudgeFactor;
float fudgeFactorWidth = 0.95f;
this.Scale(new SizeF(dpiScaleFactorFudged * (_dpiScaleFactor > 1.7 ? 1 : HighDPIUtils.SecondaryFudgeFactor), dpiScaleFactorFudged * HighDPIUtils.SecondaryFudgeFactor));
this.Width = Convert.ToInt32(this.Width * dpiScaleFactorFudged * fudgeFactorWidth);
foreach (Control control in HighDPIUtils.GetChildInControl(this)) //.OfType<Button>())
{
if (control is GroupBox || control is Button)
{
control.Font = new Font(control.Font.FontFamily,
control.Font.Size * dpiScaleFactorFudged * HighDPIUtils.SecondaryFudgeFactor,
control.Font.Style);
}
if (control is GroupBox || control.Name == "btnSwitch")
{
control.Width = Convert.ToInt32(control.Width * dpiScaleFactorFudged * fudgeFactorWidth);
}
if (control is ComboBox)
{
control.Width = Convert.ToInt32(control.Width * fudgeFactorWidth);
}
if (control is Panel)
{
control.Left = Convert.ToInt32(control.Left * dpiScaleFactorFudged);
}
}
this.btnSwitch.Left = grpSource.Right + Convert.ToInt32(12 * dpiScaleFactorFudged);
this.grpTarget.Left = btnSwitch.Right + Convert.ToInt32(12 * dpiScaleFactorFudged);
}
cboSourceServer.DataSource = ComparisonControl.ReverseArray<string>(Settings.Default.SourceServerAutoCompleteEntries.Substring(0, Settings.Default.SourceServerAutoCompleteEntries.Length - 1).Split("|".ToCharArray()));
cboTargetServer.DataSource = ComparisonControl.ReverseArray<string>(Settings.Default.TargetServerAutoCompleteEntries.Substring(0, Settings.Default.TargetServerAutoCompleteEntries.Length - 1).Split("|".ToCharArray()));
cboSourceDatabase.Text = Settings.Default.SourceCatalog;
cboTargetDatabase.Text = Settings.Default.TargetCatalog;
bool boundTargetDatabase = false;
BindSourceConnectionInfo();
BindTargetConnectionInfo(out boundTargetDatabase);
}
private bool BindSourceConnectionInfo()
{
bool returnVal = false;
if (_comparisonInfo?.ConnectionInfoSource != null)
{
if (!String.IsNullOrEmpty(_comparisonInfo.ConnectionInfoSource.ServerName) && !String.IsNullOrEmpty(_comparisonInfo.ConnectionInfoSource.DatabaseName))
{
cboSourceServer.Text = _comparisonInfo.ConnectionInfoSource.ServerName;
cboSourceDatabase.Text = _comparisonInfo.ConnectionInfoSource.DatabaseName;
returnVal = true;
}
}
return returnVal;
}
private bool BindTargetConnectionInfo(out bool boundTargetDatabase)
{
bool returnVal = false;
boundTargetDatabase = false;
if (_comparisonInfo?.ConnectionInfoTarget != null)
{
if (!String.IsNullOrEmpty(_comparisonInfo.ConnectionInfoTarget.ServerName) && !String.IsNullOrEmpty(_comparisonInfo.ConnectionInfoTarget.DatabaseName))
{
cboTargetServer.Text = _comparisonInfo.ConnectionInfoTarget.ServerName;
cboTargetDatabase.Text = _comparisonInfo.ConnectionInfoTarget.DatabaseName;
boundTargetDatabase = true;
returnVal = true;
}
}
return returnVal;
}
private static void IterateProject(SortedList projects, EnvDTE.Project project, string derivedProjectName = "")
{
if (project.ProjectItems != null) //if project is unloaded, its ProjectItems==null
{
derivedProjectName = AppendProjectName(project, derivedProjectName);
if (project.FileName.EndsWith(".smproj"))
{
projects.Add(derivedProjectName, project);
}
else if (project.Kind == "{66A26720-8FB5-11D2-AA7E-00C04F688DDE}")
{
foreach (EnvDTE.ProjectItem projectItem in project.ProjectItems)
{
if (projectItem.SubProject != null)
{
IterateProject(projects, projectItem.SubProject, derivedProjectName);
}
}
}
}
}
private static string AppendProjectName(EnvDTE.Project project, string derivedProjectName)
{
if (derivedProjectName != "")
{
derivedProjectName += "\\";
}
derivedProjectName += project.Name;
return derivedProjectName;
}
EnvDTE80.DTE2 _dte; //EnvDTE._DTE _dte;
public EnvDTE80.DTE2 Dte // EnvDTE._DTE DTE
{
get { return _dte; }
set { _dte = value; }
}
public ComparisonInfo ComparisonInfo
{
get { return _comparisonInfo; }
set { _comparisonInfo = value; }
}
public float DpiScaleFactor
{
get { return _dpiScaleFactor; }
set { _dpiScaleFactor = value; }
}
private void btnOK_Click(object sender, EventArgs e)
{
_comparisonInfo.ConnectionInfoSource.UseProject = false;
_comparisonInfo.ConnectionInfoSource.ServerName = cboSourceServer.Text;
_comparisonInfo.ConnectionInfoSource.DatabaseName = cboSourceDatabase.Text;
_comparisonInfo.ConnectionInfoSource.ProjectName = null;
_comparisonInfo.ConnectionInfoSource.ProjectFile = null;
_comparisonInfo.ConnectionInfoTarget.UseProject = false;
_comparisonInfo.ConnectionInfoTarget.ServerName = cboTargetServer.Text;
_comparisonInfo.ConnectionInfoTarget.DatabaseName = cboTargetDatabase.Text;
_comparisonInfo.ConnectionInfoTarget.ProjectName = null;
_comparisonInfo.ConnectionInfoTarget.ProjectFile = null;
}
private void btnSwitch_Click(object sender, EventArgs e)
{
ConnectionInfo infoSourceTemp = new ConnectionInfo();
infoSourceTemp.ServerName = cboSourceServer.Text;
infoSourceTemp.DatabaseName = cboSourceDatabase.Text;
cboSourceServer.Text = cboTargetServer.Text;
cboSourceDatabase.Text = cboTargetDatabase.Text;
cboTargetServer.Text = infoSourceTemp.ServerName;
cboTargetDatabase.Text = infoSourceTemp.DatabaseName;
}
private void cboSourceServer_TextChanged(object sender, EventArgs e)
{
_sourceDatabaseBound = false;
}
private void cboTargetServer_TextChanged(object sender, EventArgs e)
{
_targetDatabaseBound = false;
}
private void cboSourceDatabase_Enter(object sender, EventArgs e)
{
if (!_sourceDatabaseBound && cboSourceServer.Text != "")
{
BindDatabaseList(cboSourceServer.Text, cboSourceDatabase);
_sourceDatabaseBound = true;
}
}
private void cboTargetDatabase_Enter(object sender, EventArgs e)
{
if (!_targetDatabaseBound && cboTargetServer.Text != "")
{
BindDatabaseList(cboTargetServer.Text, cboTargetDatabase);
_targetDatabaseBound = true;
}
}
private void BindDatabaseList(string serverName, ComboBox cboCatalog)
{
try
{
// bind to databases from server
string currentDb = cboCatalog.Text;
// discover databases
Server server = new Server();
server.Connect($"Provider=MSOLAP;Data Source={serverName};");
List<string> databases = new List<string>();
foreach (Database database in server.Databases)
{
databases.Add(database.Name);
}
databases.Sort();
cboCatalog.DataSource = databases;
cboCatalog.Text = currentDb;
}
catch (Exception)
{ // if user entered duff server name, just ignore
cboCatalog.DataSource = null;
}
}
}
}

View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -78,7 +78,7 @@ namespace BismNormalizer.TabularCompare.UI
} }
catch (Exception exc) catch (Exception exc)
{ {
MessageBox.Show(exc.Message, "BISM Normalizer", MessageBoxButtons.OK, MessageBoxIcon.Error); MessageBox.Show(exc.Message, _comparisonInfo.AppName, MessageBoxButtons.OK, MessageBoxIcon.Error);
} }
} }
@ -122,7 +122,7 @@ namespace BismNormalizer.TabularCompare.UI
btnStopProcessing.Enabled = false; btnStopProcessing.Enabled = false;
btnClose.Enabled = true; btnClose.Enabled = true;
btnClose.Select(); //btnClose.Select();
} }
private delegate void SetErrorStatusDelegate(string errorMessage); private delegate void SetErrorStatusDelegate(string errorMessage);
@ -169,7 +169,7 @@ namespace BismNormalizer.TabularCompare.UI
private void btnStopProcessing_Click(object sender, EventArgs e) private void btnStopProcessing_Click(object sender, EventArgs e)
{ {
if (MessageBox.Show("Are you sure you want to attempt to stop processing?", "BISM Normalizer", MessageBoxButtons.YesNo, MessageBoxIcon.Question) != DialogResult.Yes) if (MessageBox.Show("Are you sure you want to attempt to stop processing?", _comparisonInfo.AppName, MessageBoxButtons.YesNo, MessageBoxIcon.Question) != DialogResult.Yes)
{ {
return; return;
} }

View File

@ -35,14 +35,16 @@
this.chkMeasureDependencies = new System.Windows.Forms.CheckBox(); this.chkMeasureDependencies = new System.Windows.Forms.CheckBox();
this.chkPerspectives = new System.Windows.Forms.CheckBox(); this.chkPerspectives = new System.Windows.Forms.CheckBox();
this.groupBox1 = new System.Windows.Forms.GroupBox(); this.groupBox1 = new System.Windows.Forms.GroupBox();
this.chkRetainPolicyPartitions = new System.Windows.Forms.CheckBox();
this.chkRetainPartitions = new System.Windows.Forms.CheckBox();
this.chkMergeCultures = new System.Windows.Forms.CheckBox(); this.chkMergeCultures = new System.Windows.Forms.CheckBox();
this.chkCultures = new System.Windows.Forms.CheckBox(); this.chkCultures = new System.Windows.Forms.CheckBox();
this.chkMergePerspectives = new System.Windows.Forms.CheckBox(); this.chkMergePerspectives = new System.Windows.Forms.CheckBox();
this.chkRetainPartitions = new System.Windows.Forms.CheckBox();
this.groupBox2 = new System.Windows.Forms.GroupBox(); this.groupBox2 = new System.Windows.Forms.GroupBox();
this.chkAffectedTables = new System.Windows.Forms.CheckBox(); this.chkAffectedTables = new System.Windows.Forms.CheckBox();
this.cboProcessingOption = new System.Windows.Forms.ComboBox(); this.cboProcessingOption = new System.Windows.Forms.ComboBox();
this.label1 = new System.Windows.Forms.Label(); this.label1 = new System.Windows.Forms.Label();
this.chkRetainStorageMode = new System.Windows.Forms.CheckBox();
this.groupBox1.SuspendLayout(); this.groupBox1.SuspendLayout();
this.groupBox2.SuspendLayout(); this.groupBox2.SuspendLayout();
this.SuspendLayout(); this.SuspendLayout();
@ -51,9 +53,10 @@
// //
this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.btnCancel.Location = new System.Drawing.Point(274, 393); this.btnCancel.Location = new System.Drawing.Point(411, 673);
this.btnCancel.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.btnCancel.Name = "btnCancel"; this.btnCancel.Name = "btnCancel";
this.btnCancel.Size = new System.Drawing.Size(75, 23); this.btnCancel.Size = new System.Drawing.Size(112, 35);
this.btnCancel.TabIndex = 21; this.btnCancel.TabIndex = 21;
this.btnCancel.Text = "Cancel"; this.btnCancel.Text = "Cancel";
this.btnCancel.UseVisualStyleBackColor = true; this.btnCancel.UseVisualStyleBackColor = true;
@ -62,9 +65,10 @@
// //
this.btnOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.btnOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnOK.DialogResult = System.Windows.Forms.DialogResult.OK; this.btnOK.DialogResult = System.Windows.Forms.DialogResult.OK;
this.btnOK.Location = new System.Drawing.Point(193, 393); this.btnOK.Location = new System.Drawing.Point(290, 673);
this.btnOK.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.btnOK.Name = "btnOK"; this.btnOK.Name = "btnOK";
this.btnOK.Size = new System.Drawing.Size(75, 23); this.btnOK.Size = new System.Drawing.Size(112, 35);
this.btnOK.TabIndex = 20; this.btnOK.TabIndex = 20;
this.btnOK.Text = "OK"; this.btnOK.Text = "OK";
this.btnOK.UseVisualStyleBackColor = true; this.btnOK.UseVisualStyleBackColor = true;
@ -75,9 +79,10 @@
this.chkRoles.AutoSize = true; this.chkRoles.AutoSize = true;
this.chkRoles.Checked = true; this.chkRoles.Checked = true;
this.chkRoles.CheckState = System.Windows.Forms.CheckState.Checked; this.chkRoles.CheckState = System.Windows.Forms.CheckState.Checked;
this.chkRoles.Location = new System.Drawing.Point(13, 124); this.chkRoles.Location = new System.Drawing.Point(20, 186);
this.chkRoles.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.chkRoles.Name = "chkRoles"; this.chkRoles.Name = "chkRoles";
this.chkRoles.Size = new System.Drawing.Size(86, 17); this.chkRoles.Size = new System.Drawing.Size(118, 24);
this.chkRoles.TabIndex = 5; this.chkRoles.TabIndex = 5;
this.chkRoles.Text = "Include roles"; this.chkRoles.Text = "Include roles";
this.chkRoles.UseVisualStyleBackColor = true; this.chkRoles.UseVisualStyleBackColor = true;
@ -85,9 +90,10 @@
// chkPartitions // chkPartitions
// //
this.chkPartitions.AutoSize = true; this.chkPartitions.AutoSize = true;
this.chkPartitions.Location = new System.Drawing.Point(13, 152); this.chkPartitions.Location = new System.Drawing.Point(20, 232);
this.chkPartitions.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.chkPartitions.Name = "chkPartitions"; this.chkPartitions.Name = "chkPartitions";
this.chkPartitions.Size = new System.Drawing.Size(224, 17); this.chkPartitions.Size = new System.Drawing.Size(327, 24);
this.chkPartitions.TabIndex = 6; this.chkPartitions.TabIndex = 6;
this.chkPartitions.Text = "Consider partitions when comparing tables"; this.chkPartitions.Text = "Consider partitions when comparing tables";
this.chkPartitions.UseVisualStyleBackColor = true; this.chkPartitions.UseVisualStyleBackColor = true;
@ -99,9 +105,10 @@
this.chkMeasureDependencies.AutoSize = true; this.chkMeasureDependencies.AutoSize = true;
this.chkMeasureDependencies.Checked = true; this.chkMeasureDependencies.Checked = true;
this.chkMeasureDependencies.CheckState = System.Windows.Forms.CheckState.Checked; this.chkMeasureDependencies.CheckState = System.Windows.Forms.CheckState.Checked;
this.chkMeasureDependencies.Location = new System.Drawing.Point(13, 208); this.chkMeasureDependencies.Location = new System.Drawing.Point(20, 397);
this.chkMeasureDependencies.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.chkMeasureDependencies.Name = "chkMeasureDependencies"; this.chkMeasureDependencies.Name = "chkMeasureDependencies";
this.chkMeasureDependencies.Size = new System.Drawing.Size(47, 17); this.chkMeasureDependencies.Size = new System.Drawing.Size(61, 24);
this.chkMeasureDependencies.TabIndex = 7; this.chkMeasureDependencies.TabIndex = 7;
this.chkMeasureDependencies.Text = "XXX"; this.chkMeasureDependencies.Text = "XXX";
this.chkMeasureDependencies.UseVisualStyleBackColor = true; this.chkMeasureDependencies.UseVisualStyleBackColor = true;
@ -109,9 +116,10 @@
// chkPerspectives // chkPerspectives
// //
this.chkPerspectives.AutoSize = true; this.chkPerspectives.AutoSize = true;
this.chkPerspectives.Location = new System.Drawing.Point(13, 25); this.chkPerspectives.Location = new System.Drawing.Point(20, 38);
this.chkPerspectives.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.chkPerspectives.Name = "chkPerspectives"; this.chkPerspectives.Name = "chkPerspectives";
this.chkPerspectives.Size = new System.Drawing.Size(124, 17); this.chkPerspectives.Size = new System.Drawing.Size(173, 24);
this.chkPerspectives.TabIndex = 3; this.chkPerspectives.TabIndex = 3;
this.chkPerspectives.Text = "Include perspectives"; this.chkPerspectives.Text = "Include perspectives";
this.chkPerspectives.UseVisualStyleBackColor = true; this.chkPerspectives.UseVisualStyleBackColor = true;
@ -122,6 +130,8 @@
this.groupBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) this.groupBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right))); | System.Windows.Forms.AnchorStyles.Right)));
this.groupBox1.Controls.Add(this.chkRetainStorageMode);
this.groupBox1.Controls.Add(this.chkRetainPolicyPartitions);
this.groupBox1.Controls.Add(this.chkRetainPartitions); this.groupBox1.Controls.Add(this.chkRetainPartitions);
this.groupBox1.Controls.Add(this.chkMergeCultures); this.groupBox1.Controls.Add(this.chkMergeCultures);
this.groupBox1.Controls.Add(this.chkCultures); this.groupBox1.Controls.Add(this.chkCultures);
@ -130,20 +140,47 @@
this.groupBox1.Controls.Add(this.chkMeasureDependencies); this.groupBox1.Controls.Add(this.chkMeasureDependencies);
this.groupBox1.Controls.Add(this.chkPartitions); this.groupBox1.Controls.Add(this.chkPartitions);
this.groupBox1.Controls.Add(this.chkRoles); this.groupBox1.Controls.Add(this.chkRoles);
this.groupBox1.Location = new System.Drawing.Point(12, 12); this.groupBox1.Location = new System.Drawing.Point(18, 18);
this.groupBox1.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.groupBox1.Name = "groupBox1"; this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(337, 256); this.groupBox1.Padding = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.groupBox1.Size = new System.Drawing.Size(506, 471);
this.groupBox1.TabIndex = 22; this.groupBox1.TabIndex = 22;
this.groupBox1.TabStop = false; this.groupBox1.TabStop = false;
this.groupBox1.Text = "Comparison Options"; this.groupBox1.Text = "Comparison Options";
// //
// chkRetainPolicyPartitions
//
this.chkRetainPolicyPartitions.AutoSize = true;
this.chkRetainPolicyPartitions.Enabled = false;
this.chkRetainPolicyPartitions.Location = new System.Drawing.Point(52, 312);
this.chkRetainPolicyPartitions.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.chkRetainPolicyPartitions.Name = "chkRetainPolicyPartitions";
this.chkRetainPolicyPartitions.Size = new System.Drawing.Size(322, 24);
this.chkRetainPolicyPartitions.TabIndex = 11;
this.chkRetainPolicyPartitions.Text = "Retain only refresh-policy based partitions";
this.chkRetainPolicyPartitions.UseVisualStyleBackColor = true;
//
// chkRetainPartitions
//
this.chkRetainPartitions.AutoSize = true;
this.chkRetainPartitions.Location = new System.Drawing.Point(20, 280);
this.chkRetainPartitions.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.chkRetainPartitions.Name = "chkRetainPartitions";
this.chkRetainPartitions.Size = new System.Drawing.Size(270, 24);
this.chkRetainPartitions.TabIndex = 10;
this.chkRetainPartitions.Text = "For table updates, retain partitions";
this.chkRetainPartitions.UseVisualStyleBackColor = true;
this.chkRetainPartitions.CheckedChanged += new System.EventHandler(this.ChkRetainPartitions_CheckedChanged);
//
// chkMergeCultures // chkMergeCultures
// //
this.chkMergeCultures.AutoSize = true; this.chkMergeCultures.AutoSize = true;
this.chkMergeCultures.Enabled = false; this.chkMergeCultures.Enabled = false;
this.chkMergeCultures.Location = new System.Drawing.Point(37, 98); this.chkMergeCultures.Location = new System.Drawing.Point(52, 148);
this.chkMergeCultures.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.chkMergeCultures.Name = "chkMergeCultures"; this.chkMergeCultures.Name = "chkMergeCultures";
this.chkMergeCultures.Size = new System.Drawing.Size(270, 17); this.chkMergeCultures.Size = new System.Drawing.Size(398, 24);
this.chkMergeCultures.TabIndex = 9; this.chkMergeCultures.TabIndex = 9;
this.chkMergeCultures.Text = "For culture updates, merge translations (not replace)"; this.chkMergeCultures.Text = "For culture updates, merge translations (not replace)";
this.chkMergeCultures.UseVisualStyleBackColor = true; this.chkMergeCultures.UseVisualStyleBackColor = true;
@ -151,9 +188,10 @@
// chkCultures // chkCultures
// //
this.chkCultures.AutoSize = true; this.chkCultures.AutoSize = true;
this.chkCultures.Location = new System.Drawing.Point(15, 75); this.chkCultures.Location = new System.Drawing.Point(20, 115);
this.chkCultures.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.chkCultures.Name = "chkCultures"; this.chkCultures.Name = "chkCultures";
this.chkCultures.Size = new System.Drawing.Size(101, 17); this.chkCultures.Size = new System.Drawing.Size(140, 24);
this.chkCultures.TabIndex = 8; this.chkCultures.TabIndex = 8;
this.chkCultures.Text = "Include cultures"; this.chkCultures.Text = "Include cultures";
this.chkCultures.UseVisualStyleBackColor = true; this.chkCultures.UseVisualStyleBackColor = true;
@ -163,23 +201,14 @@
// //
this.chkMergePerspectives.AutoSize = true; this.chkMergePerspectives.AutoSize = true;
this.chkMergePerspectives.Enabled = false; this.chkMergePerspectives.Enabled = false;
this.chkMergePerspectives.Location = new System.Drawing.Point(35, 48); this.chkMergePerspectives.Location = new System.Drawing.Point(52, 71);
this.chkMergePerspectives.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.chkMergePerspectives.Name = "chkMergePerspectives"; this.chkMergePerspectives.Name = "chkMergePerspectives";
this.chkMergePerspectives.Size = new System.Drawing.Size(287, 17); this.chkMergePerspectives.Size = new System.Drawing.Size(420, 24);
this.chkMergePerspectives.TabIndex = 4; this.chkMergePerspectives.TabIndex = 4;
this.chkMergePerspectives.Text = "For perspective updates, merge selections (not replace)"; this.chkMergePerspectives.Text = "For perspective updates, merge selections (not replace)";
this.chkMergePerspectives.UseVisualStyleBackColor = true; this.chkMergePerspectives.UseVisualStyleBackColor = true;
// //
// chkRetainPartitions
//
this.chkRetainPartitions.AutoSize = true;
this.chkRetainPartitions.Location = new System.Drawing.Point(13, 181);
this.chkRetainPartitions.Name = "chkRetainPartitions";
this.chkRetainPartitions.Size = new System.Drawing.Size(247, 17);
this.chkRetainPartitions.TabIndex = 10;
this.chkRetainPartitions.Text = "For table updates, retain partitions (not replace)";
this.chkRetainPartitions.UseVisualStyleBackColor = true;
//
// groupBox2 // groupBox2
// //
this.groupBox2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) this.groupBox2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
@ -187,9 +216,11 @@
this.groupBox2.Controls.Add(this.chkAffectedTables); this.groupBox2.Controls.Add(this.chkAffectedTables);
this.groupBox2.Controls.Add(this.cboProcessingOption); this.groupBox2.Controls.Add(this.cboProcessingOption);
this.groupBox2.Controls.Add(this.label1); this.groupBox2.Controls.Add(this.label1);
this.groupBox2.Location = new System.Drawing.Point(12, 274); this.groupBox2.Location = new System.Drawing.Point(18, 499);
this.groupBox2.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.groupBox2.Name = "groupBox2"; this.groupBox2.Name = "groupBox2";
this.groupBox2.Size = new System.Drawing.Size(337, 101); this.groupBox2.Padding = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.groupBox2.Size = new System.Drawing.Size(506, 155);
this.groupBox2.TabIndex = 23; this.groupBox2.TabIndex = 23;
this.groupBox2.TabStop = false; this.groupBox2.TabStop = false;
this.groupBox2.Text = "Database Deployment"; this.groupBox2.Text = "Database Deployment";
@ -199,9 +230,10 @@
this.chkAffectedTables.AutoSize = true; this.chkAffectedTables.AutoSize = true;
this.chkAffectedTables.Checked = true; this.chkAffectedTables.Checked = true;
this.chkAffectedTables.CheckState = System.Windows.Forms.CheckState.Checked; this.chkAffectedTables.CheckState = System.Windows.Forms.CheckState.Checked;
this.chkAffectedTables.Location = new System.Drawing.Point(13, 64); this.chkAffectedTables.Location = new System.Drawing.Point(20, 98);
this.chkAffectedTables.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.chkAffectedTables.Name = "chkAffectedTables"; this.chkAffectedTables.Name = "chkAffectedTables";
this.chkAffectedTables.Size = new System.Drawing.Size(159, 17); this.chkAffectedTables.Size = new System.Drawing.Size(227, 24);
this.chkAffectedTables.TabIndex = 9; this.chkAffectedTables.TabIndex = 9;
this.chkAffectedTables.Text = "Process only affected tables"; this.chkAffectedTables.Text = "Process only affected tables";
this.chkAffectedTables.UseVisualStyleBackColor = true; this.chkAffectedTables.UseVisualStyleBackColor = true;
@ -215,38 +247,52 @@
"Default", "Default",
"Do Not Process", "Do Not Process",
"Full"}); "Full"});
this.cboProcessingOption.Location = new System.Drawing.Point(114, 25); this.cboProcessingOption.Location = new System.Drawing.Point(171, 38);
this.cboProcessingOption.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.cboProcessingOption.Name = "cboProcessingOption"; this.cboProcessingOption.Name = "cboProcessingOption";
this.cboProcessingOption.Size = new System.Drawing.Size(131, 21); this.cboProcessingOption.Size = new System.Drawing.Size(194, 28);
this.cboProcessingOption.TabIndex = 8; this.cboProcessingOption.TabIndex = 8;
// //
// label1 // label1
// //
this.label1.AutoSize = true; this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(12, 28); this.label1.Location = new System.Drawing.Point(18, 43);
this.label1.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.label1.Name = "label1"; this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(96, 13); this.label1.Size = new System.Drawing.Size(142, 20);
this.label1.TabIndex = 0; this.label1.TabIndex = 0;
this.label1.Text = "Processing Option:"; this.label1.Text = "Processing Option:";
// //
// chkRetainStorageMode
//
this.chkRetainStorageMode.AutoSize = true;
this.chkRetainStorageMode.Location = new System.Drawing.Point(20, 357);
this.chkRetainStorageMode.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.chkRetainStorageMode.Name = "chkRetainStorageMode";
this.chkRetainStorageMode.Size = new System.Drawing.Size(303, 24);
this.chkRetainStorageMode.TabIndex = 12;
this.chkRetainStorageMode.Text = "For table updates, retain storage mode";
this.chkRetainStorageMode.UseVisualStyleBackColor = true;
//
// Options // Options
// //
this.AcceptButton = this.btnOK; this.AcceptButton = this.btnOK;
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleDimensions = new System.Drawing.SizeF(9F, 20F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.btnCancel; this.CancelButton = this.btnCancel;
this.ClientSize = new System.Drawing.Size(361, 428); this.ClientSize = new System.Drawing.Size(542, 733);
this.Controls.Add(this.groupBox2); this.Controls.Add(this.groupBox2);
this.Controls.Add(this.groupBox1); this.Controls.Add(this.groupBox1);
this.Controls.Add(this.btnCancel); this.Controls.Add(this.btnCancel);
this.Controls.Add(this.btnOK); this.Controls.Add(this.btnOK);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.MaximizeBox = false; this.MaximizeBox = false;
this.MinimizeBox = false; this.MinimizeBox = false;
this.Name = "Options"; this.Name = "Options";
this.ShowIcon = false; this.ShowIcon = false;
this.ShowInTaskbar = false; this.ShowInTaskbar = false;
this.Text = "BISM Normalizer Options"; this.Text = "Options";
this.Load += new System.EventHandler(this.Options_Load); this.Load += new System.EventHandler(this.Options_Load);
this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.Options_KeyDown); this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.Options_KeyDown);
this.groupBox1.ResumeLayout(false); this.groupBox1.ResumeLayout(false);
@ -274,5 +320,7 @@
private System.Windows.Forms.CheckBox chkMergeCultures; private System.Windows.Forms.CheckBox chkMergeCultures;
private System.Windows.Forms.CheckBox chkCultures; private System.Windows.Forms.CheckBox chkCultures;
private System.Windows.Forms.CheckBox chkRetainPartitions; private System.Windows.Forms.CheckBox chkRetainPartitions;
private System.Windows.Forms.CheckBox chkRetainPolicyPartitions;
private System.Windows.Forms.CheckBox chkRetainStorageMode;
} }
} }

View File

@ -51,6 +51,8 @@ namespace BismNormalizer.TabularCompare.UI
//chkActions.Checked = _comparisonInfo.OptionsInfo.OptionActions; //chkActions.Checked = _comparisonInfo.OptionsInfo.OptionActions;
chkPartitions.Checked = _comparisonInfo.OptionsInfo.OptionPartitions; chkPartitions.Checked = _comparisonInfo.OptionsInfo.OptionPartitions;
chkRetainPartitions.Checked = _comparisonInfo.OptionsInfo.OptionRetainPartitions; chkRetainPartitions.Checked = _comparisonInfo.OptionsInfo.OptionRetainPartitions;
chkRetainPolicyPartitions.Checked = _comparisonInfo.OptionsInfo.OptionRetainPolicyPartitions;
chkRetainStorageMode.Checked = _comparisonInfo.OptionsInfo.OptionRetainStorageMode;
chkMeasureDependencies.Checked = _comparisonInfo.OptionsInfo.OptionMeasureDependencies; chkMeasureDependencies.Checked = _comparisonInfo.OptionsInfo.OptionMeasureDependencies;
string processingOption = _comparisonInfo.OptionsInfo.OptionProcessingOption.ToString(); string processingOption = _comparisonInfo.OptionsInfo.OptionProcessingOption.ToString();
cboProcessingOption.Text = processingOption == "DoNotProcess" ? "Do Not Process" : processingOption; cboProcessingOption.Text = processingOption == "DoNotProcess" ? "Do Not Process" : processingOption;
@ -69,6 +71,8 @@ namespace BismNormalizer.TabularCompare.UI
_comparisonInfo.OptionsInfo.OptionActions = false; _comparisonInfo.OptionsInfo.OptionActions = false;
_comparisonInfo.OptionsInfo.OptionPartitions = chkPartitions.Checked; _comparisonInfo.OptionsInfo.OptionPartitions = chkPartitions.Checked;
_comparisonInfo.OptionsInfo.OptionRetainPartitions = chkRetainPartitions.Checked; _comparisonInfo.OptionsInfo.OptionRetainPartitions = chkRetainPartitions.Checked;
_comparisonInfo.OptionsInfo.OptionRetainPolicyPartitions = chkRetainPolicyPartitions.Checked;
_comparisonInfo.OptionsInfo.OptionRetainStorageMode = chkRetainStorageMode.Checked;
_comparisonInfo.OptionsInfo.OptionMeasureDependencies = chkMeasureDependencies.Checked; _comparisonInfo.OptionsInfo.OptionMeasureDependencies = chkMeasureDependencies.Checked;
_comparisonInfo.OptionsInfo.OptionProcessingOption = (ProcessingOption)Enum.Parse(typeof(ProcessingOption), cboProcessingOption.Text.Replace(" ", "")); _comparisonInfo.OptionsInfo.OptionProcessingOption = (ProcessingOption)Enum.Parse(typeof(ProcessingOption), cboProcessingOption.Text.Replace(" ", ""));
//_comparisonInfo.OptionsInfo.OptionTransaction = chkTransaction.Checked; //_comparisonInfo.OptionsInfo.OptionTransaction = chkTransaction.Checked;
@ -88,15 +92,27 @@ namespace BismNormalizer.TabularCompare.UI
chkMergeCultures.Enabled = chkCultures.Checked; chkMergeCultures.Enabled = chkCultures.Checked;
} }
private void ChkRetainPartitions_CheckedChanged(object sender, EventArgs e)
{
chkRetainPolicyPartitions.Enabled = chkRetainPartitions.Checked;
}
private void Options_KeyDown(object sender, KeyEventArgs e) private void Options_KeyDown(object sender, KeyEventArgs e)
{ {
if (e.Control && e.Shift && e.KeyCode == Keys.D) if (e.Control && e.Shift && e.KeyCode == Keys.D)
{ {
if (MessageBox.Show($"Are you sure you want to toggle 192 Device DPI from optimized for {(Settings.Default.OptionHighDpiLocal ? "local" : "Remote Desktop")} to {(Settings.Default.OptionHighDpiLocal ? "Remote Desktop" : "local")}?", "BISM Normalizer", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) if (MessageBox.Show($"Are you sure you want to toggle 192 Device DPI from optimized for {(Settings.Default.OptionHighDpiLocal ? "local" : "Remote Desktop")} to {(Settings.Default.OptionHighDpiLocal ? "Remote Desktop" : "local")}?", "ALM Toolkit", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
{ {
Settings.Default.OptionHighDpiLocal = !Settings.Default.OptionHighDpiLocal; Settings.Default.OptionHighDpiLocal = !Settings.Default.OptionHighDpiLocal;
} }
} }
else if (e.Control && e.Shift && e.KeyCode == Keys.C)
{
if (MessageBox.Show($"Are you sure you want to {(Settings.Default.OptionCompositeModelsOverride ? "*disallow*" : "*allow*")} composite model comparisons on Analysis Services?", "ALM Toolkit", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
{
Settings.Default.OptionCompositeModelsOverride = !Settings.Default.OptionCompositeModelsOverride;
}
}
} }
public ComparisonInfo ComparisonInfo public ComparisonInfo ComparisonInfo
@ -110,5 +126,6 @@ namespace BismNormalizer.TabularCompare.UI
get { return _dpiScaleFactor; } get { return _dpiScaleFactor; }
set { _dpiScaleFactor = value; } set { _dpiScaleFactor = value; }
} }
} }
} }

View File

@ -221,6 +221,10 @@ namespace BismNormalizer.TabularCompare.UI
switch (comparisonObject.ComparisonObjectType) switch (comparisonObject.ComparisonObjectType)
{ {
// Tabular objecs // Tabular objecs
case ComparisonObjectType.Model:
node.ImageIndex = 25;
node.Cells[0].Value = treeIndentLevel1 + "Model";
break;
case ComparisonObjectType.DataSource: case ComparisonObjectType.DataSource:
node.ImageIndex = 0; node.ImageIndex = 0;
node.Cells[0].Value = treeIndentLevel1 + "Data Source"; node.Cells[0].Value = treeIndentLevel1 + "Data Source";
@ -241,6 +245,10 @@ namespace BismNormalizer.TabularCompare.UI
node.ImageIndex = 4; node.ImageIndex = 4;
node.Cells[0].Value = treeIndentLevel2 + "KPI"; node.Cells[0].Value = treeIndentLevel2 + "KPI";
break; break;
case ComparisonObjectType.CalculationItem:
node.ImageIndex = 24;
node.Cells[0].Value = treeIndentLevel2 + "Calculation Item";
break;
case ComparisonObjectType.Expression: case ComparisonObjectType.Expression:
node.ImageIndex = 22; node.ImageIndex = 22;
node.Cells[0].Value = treeIndentLevel1 + "Expression"; node.Cells[0].Value = treeIndentLevel1 + "Expression";
@ -261,6 +269,10 @@ namespace BismNormalizer.TabularCompare.UI
node.ImageIndex = 16; node.ImageIndex = 16;
node.Cells[0].Value = treeIndentLevel1 + "Action"; node.Cells[0].Value = treeIndentLevel1 + "Action";
break; break;
//case ComparisonObjectType.RefreshPolicy:
// node.ImageIndex = 26;
// node.Cells[0].Value = treeIndentLevel1 + "Refresh Policy";
// break;
default: default:
break; break;

View File

@ -120,6 +120,10 @@ namespace BismNormalizer.TabularCompare.UI
TreeGridNode particularTypeNode = null; TreeGridNode particularTypeNode = null;
switch (validationMessageType) switch (validationMessageType)
{ {
case ValidationMessageType.Model:
particularTypeNode = FindOrCreateTypeNode(topLevelNodeForHandle, "Model");
particularTypeNode.ImageIndex = 25;
break;
case ValidationMessageType.DataSource: case ValidationMessageType.DataSource:
particularTypeNode = FindOrCreateTypeNode(topLevelNodeForHandle, "Data Sources"); particularTypeNode = FindOrCreateTypeNode(topLevelNodeForHandle, "Data Sources");
particularTypeNode.ImageIndex = 0; particularTypeNode.ImageIndex = 0;
@ -140,6 +144,14 @@ namespace BismNormalizer.TabularCompare.UI
particularTypeNode = FindOrCreateTypeNode(topLevelNodeForHandle, "KPIs"); particularTypeNode = FindOrCreateTypeNode(topLevelNodeForHandle, "KPIs");
particularTypeNode.ImageIndex = 4; particularTypeNode.ImageIndex = 4;
break; break;
case ValidationMessageType.CalculationItem:
particularTypeNode = FindOrCreateTypeNode(topLevelNodeForHandle, "Calculation Items");
particularTypeNode.ImageIndex = 24;
break;
case ValidationMessageType.CalculationGroup:
particularTypeNode = FindOrCreateTypeNode(topLevelNodeForHandle, "Calculation Groups");
particularTypeNode.ImageIndex = 23;
break;
case ValidationMessageType.Expression: case ValidationMessageType.Expression:
particularTypeNode = FindOrCreateTypeNode(topLevelNodeForHandle, "Expression"); particularTypeNode = FindOrCreateTypeNode(topLevelNodeForHandle, "Expression");
particularTypeNode.ImageIndex = 22; particularTypeNode.ImageIndex = 22;
@ -160,10 +172,18 @@ namespace BismNormalizer.TabularCompare.UI
particularTypeNode = FindOrCreateTypeNode(topLevelNodeForHandle, "Actions"); particularTypeNode = FindOrCreateTypeNode(topLevelNodeForHandle, "Actions");
particularTypeNode.ImageIndex = 16; particularTypeNode.ImageIndex = 16;
break; break;
//case ValidationMessageType.RefreshPolicy:
// particularTypeNode = FindOrCreateTypeNode(topLevelNodeForHandle, "Refresh Policy");
// particularTypeNode.ImageIndex = 26;
// break;
case ValidationMessageType.MeasureCalculationDependency: case ValidationMessageType.MeasureCalculationDependency:
particularTypeNode = FindOrCreateTypeNode(topLevelNodeForHandle, "Measure Calculation Dependencies"); particularTypeNode = FindOrCreateTypeNode(topLevelNodeForHandle, "Measure Calculation Dependencies");
particularTypeNode.ImageIndex = 3; particularTypeNode.ImageIndex = 3;
break; break;
case ValidationMessageType.AggregationDependency:
particularTypeNode = FindOrCreateTypeNode(topLevelNodeForHandle, "Aggregation Dependencies");
particularTypeNode.ImageIndex = 2;
break;
default: default:
//Something is wrong, better get out of here. //Something is wrong, better get out of here.
return; return;

View File

@ -143,7 +143,8 @@ namespace BismNormalizer.TabularCompare.UI
_informationalMessageButton.Left = Convert.ToInt32(92 * _hpiScaleFactor) + pixelsPerDigit * warningCount.Length; _informationalMessageButton.Left = Convert.ToInt32(92 * _hpiScaleFactor) + pixelsPerDigit * warningCount.Length;
//where "informational messages" button ends //where "informational messages" button ends
_fillerPanel.Left = Convert.ToInt32(268 * _hpiScaleFactor) + (pixelsPerDigit * warningCount.Length) + (pixelsPerDigit * informationalMessageCount.Length); //5/15/2018: was ToInt32(268 * _hpiScaleFactor)
_fillerPanel.Left = Convert.ToInt32(250 * _hpiScaleFactor) + (pixelsPerDigit * warningCount.Length) + (pixelsPerDigit * informationalMessageCount.Length);
} }
} }
} }

View File

@ -73,6 +73,15 @@
<setting name="OptionHighDpiLocal" serializeAs="String"> <setting name="OptionHighDpiLocal" serializeAs="String">
<value>True</value> <value>True</value>
</setting> </setting>
<setting name="OptionCompositeModelsOverride" serializeAs="String">
<value>False</value>
</setting>
<setting name="OptionRetainPolicyPartitions" serializeAs="String">
<value>False</value>
</setting>
<setting name="OptionRetainStorageMode" serializeAs="String">
<value>False</value>
</setting>
</BismNormalizer.Settings> </BismNormalizer.Settings>
</userSettings> </userSettings>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" /></startup> <startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" /></startup>
@ -95,5 +104,9 @@
<bindingRedirect oldVersion="0.0.0.0-14.0.0.0" newVersion="14.0.0.0" /> <bindingRedirect oldVersion="0.0.0.0-14.0.0.0" newVersion="14.0.0.0" />
</dependentAssembly> </dependentAssembly>
</assemblyBinding> </assemblyBinding>
<System.Windows.Forms.ApplicationConfigurationSection>
<add key="DpiAwareness" value="PerMonitorV2" />
<add key="EnableWindowsFormsHighDpiAutoResizing" value="false" />
</System.Windows.Forms.ApplicationConfigurationSection>
</runtime> </runtime>
</configuration> </configuration>

View File

@ -2,7 +2,7 @@
<packages> <packages>
<package id="EnvDTE" version="8.0.2" targetFramework="net472" /> <package id="EnvDTE" version="8.0.2" targetFramework="net472" />
<package id="EnvDTE80" version="8.0.3" targetFramework="net472" /> <package id="EnvDTE80" version="8.0.3" targetFramework="net472" />
<package id="Microsoft.AnalysisServices.retail.amd64" version="16.3.0" targetFramework="net461" /> <package id="Microsoft.AnalysisServices.retail.amd64" version="18.0.5" targetFramework="net472" />
<package id="Microsoft.ApplicationInsights" version="2.8.1" targetFramework="net461" /> <package id="Microsoft.ApplicationInsights" version="2.8.1" targetFramework="net461" />
<package id="Microsoft.ApplicationInsights.Agent.Intercept" version="2.4.0" targetFramework="net461" /> <package id="Microsoft.ApplicationInsights.Agent.Intercept" version="2.4.0" targetFramework="net461" />
<package id="Microsoft.ApplicationInsights.DependencyCollector" version="2.8.1" targetFramework="net461" /> <package id="Microsoft.ApplicationInsights.DependencyCollector" version="2.8.1" targetFramework="net461" />

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011" xmlns:d="http://schemas.microsoft.com/developer/vsx-schema-design/2011"> <PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011" xmlns:d="http://schemas.microsoft.com/developer/vsx-schema-design/2011">
<Metadata> <Metadata>
<Identity Id="BismNormalizer.ea2aeb43-64a6-4dee-8816-099fb44513fa" Version="4.0.1.10" Language="en-US" Publisher="BISM Normalizer" /> <Identity Id="BismNormalizer.ea2aeb43-64a6-4dee-8816-099fb44513fa" Version="4.0.1.12" Language="en-US" Publisher="BISM Normalizer" />
<DisplayName>BISM Normalizer</DisplayName> <DisplayName>BISM Normalizer</DisplayName>
<Description xml:space="preserve">BISM Normalizer manages Analysis Services tabular models</Description> <Description xml:space="preserve">BISM Normalizer manages Analysis Services tabular models</Description>
<MoreInfo>http://bism-normalizer.com/</MoreInfo> <MoreInfo>http://bism-normalizer.com/</MoreInfo>