This commit is contained in:
Mark Brown 2023-11-07 17:12:25 +00:00
Родитель ca3630be0c
Коммит 6ad63030e8
129 изменённых файлов: 0 добавлений и 4666 удалений

33
.github/workflows/dotnet-build-test.yml поставляемый
Просмотреть файл

@ -1,33 +0,0 @@
name: .NET
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
schedule:
- cron: '0 0 * * *'
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup .NET
uses: actions/setup-dotnet@v2
with:
dotnet-version: 6.0.x
- name: Restore dependencies
run: dotnet restore
- name: Build
run: dotnet build --no-restore
- name: Test
run: dotnet test --no-build --verbosity normal
- name: Debug Build Artifact
uses: actions/upload-artifact@v3
with:
name: debug-build
path: /home/runner/work/azure-documentdb-datamigrationtool/azure-documentdb-datamigrationtool/Core/Microsoft.DataTransfer.Core/bin/Debug/net6.0 #path/to/artifact/ # or path/to/artifact

Просмотреть файл

@ -1 +0,0 @@
Please read the contributing guidelines from the [Azure Team](http://azure.github.io/guidelines.html "Azure Team")

Просмотреть файл

@ -1,20 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
<PackageReference Include="MSTest.TestAdapter" Version="2.2.10" />
<PackageReference Include="MSTest.TestFramework" Version="2.2.10" />
<PackageReference Include="coverlet.collector" Version="3.1.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>

Просмотреть файл

@ -1,13 +0,0 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Microsoft.DataTransfer.Core.UnitTests
{
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
}
}
}

Просмотреть файл

@ -1,9 +0,0 @@
namespace Microsoft.DataTransfer.Core;
public class DataTransferOptions
{
public string? Source { get; set; }
public string? Sink { get; set; }
public string? SourceSettingsPath { get; set; }
public string? SinkSettingsPath { get; set; }
}

Просмотреть файл

@ -1,30 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<UserSecretsId>c7432a3a-5dc1-4e86-a1f0-b2363bf5c77f</UserSecretsId>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.Core" Version="1.25.0" />
<PackageReference Include="Microsoft.Data.SqlClient" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.1" />
<PackageReference Include="System.ComponentModel.Composition" Version="6.0.0" />
<PackageReference Include="System.Configuration.ConfigurationManager" Version="6.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Interfaces\Microsoft.DataTransfer.Interfaces\Microsoft.DataTransfer.Interfaces.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="appsettings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

Просмотреть файл

@ -1,145 +0,0 @@
using System.ComponentModel.Composition.Hosting;
using Microsoft.DataTransfer.Interfaces;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace Microsoft.DataTransfer.Core;
class Program
{
public static async Task Main(string[] args)
{
using IHost host = Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration(cfg =>
{
cfg.AddUserSecrets<Program>();
})
.Build();
IConfiguration configuration = host.Services.GetRequiredService<IConfiguration>();
var options = configuration.Get<DataTransferOptions>();
var hostingProcess = host.RunAsync();
var catalog = new AggregateCatalog();
if (!Directory.Exists("Extensions"))
{
Directory.CreateDirectory("Extensions");
}
catalog.Catalogs.Add(new DirectoryCatalog("Extensions", "*Extension.dll"));
var container = new CompositionContainer(catalog);
var sources = LoadExtensions<IDataSourceExtension>(container);
var sinks = LoadExtensions<IDataSinkExtension>(container);
Console.WriteLine($"{sources.Count + sinks.Count} Extensions Loaded");
var source = GetExtensionSelection(options.Source, sources, "Source");
var sourceConfig = BuildSettingsConfiguration(configuration, options.SourceSettingsPath, $"{source.DisplayName}SourceSettings", options.Source == null);
var sink = GetExtensionSelection(options.Sink, sinks, "Sink");
var sinkConfig = BuildSettingsConfiguration(configuration, options.SinkSettingsPath, $"{sink.DisplayName}SinkSettings", options.Sink == null);
var data = source.ReadAsync(sourceConfig);
await sink.WriteAsync(data, sinkConfig);
Console.WriteLine("Done");
Console.WriteLine("Enter to Quit...");
Console.ReadLine();
await host.StopAsync();
await hostingProcess;
}
private static List<T> LoadExtensions<T>(CompositionContainer container)
where T : class, IDataTransferExtension
{
var sources = new List<T>();
foreach (var exportedExtension in container.GetExports<T>())
{
sources.Add(exportedExtension.Value);
}
return sources;
}
private static T GetExtensionSelection<T>(string? selectionName, List<T> extensions, string inputPrompt)
where T : class, IDataTransferExtension
{
if (!string.IsNullOrWhiteSpace(selectionName))
{
var extension = extensions.FirstOrDefault(s => selectionName.Equals(s.DisplayName, StringComparison.OrdinalIgnoreCase));
if (extension != null)
{
Console.WriteLine($"Using {extension.DisplayName} {inputPrompt}");
return extension;
}
}
Console.WriteLine($"Select {inputPrompt}");
for (var index = 0; index < extensions.Count; index++)
{
var extension = extensions[index];
Console.WriteLine($"{index + 1}:{extension.DisplayName}");
}
string? selection = "";
int input;
while (!int.TryParse(selection, out input) || input > extensions.Count)
{
selection = Console.ReadLine();
}
return extensions[input - 1];
}
private static IConfiguration BuildSettingsConfiguration(IConfiguration configuration, string? settingsPath, string configSection, bool promptForFile)
{
IConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
if (!string.IsNullOrEmpty(settingsPath))
{
configurationBuilder = configurationBuilder.AddJsonFile(settingsPath);
}
else if (promptForFile)
{
Console.Write($"Load settings from a file? (y/n):");
var response = Console.ReadLine();
if (IsYesResponse(response))
{
Console.Write("Path to file: ");
var path = Console.ReadLine();
if (!string.IsNullOrWhiteSpace(path))
{
configurationBuilder = configurationBuilder.AddJsonFile(path);
}
}
else
{
Console.Write($"Configuration section to read settings? (default={configSection}):");
response = Console.ReadLine();
if (!string.IsNullOrWhiteSpace(response))
{
configSection = response;
}
}
}
return configurationBuilder
.AddConfiguration(configuration.GetSection(configSection))
.Build();
}
private static bool IsYesResponse(string? response)
{
if (response?.Equals("y", StringComparison.CurrentCultureIgnoreCase) == true)
return true;
if (response?.Equals("yes", StringComparison.CurrentCultureIgnoreCase) == true)
return true;
return false;
}
}

Просмотреть файл

@ -1,24 +0,0 @@
{
"profiles": {
"Microsoft.DataTransfer.Core": {
"commandName": "Project",
"commandLineArgs": ""
},
"JSON->Cosmos": {
"commandName": "Project",
"commandLineArgs": "--source json --sink cosmos --SourceSettingsPath=c:\\temp\\JsonSourceSettings.json --SinkSettingsPath=c:\\temp\\CosmosSinkSettings.json"
},
"Cosmos->JSON": {
"commandName": "Project",
"commandLineArgs": "--source cosmos --sink json --SourceSettingsPath=c:\\temp\\CosmosSourceSettings.json --SinkSettingsPath=c:\\temp\\JsonSinkSettings.json"
},
"SqlServer->Cosmos": {
"commandName": "Project",
"commandLineArgs": "--source sqlServer --sink cosmos --SourceSettingsPath=c:\\temp\\SqlSourceSettings.json --SinkSettingsPath=c:\\temp\\CosmosSinkSettings.json"
},
"JSON->SqlServer": {
"commandName": "Project",
"commandLineArgs": "--source json --sink sqlServer --JsonSourceSettings:FilePath=c:\\temp\\test-json-sql-in.json --SinkSettingsPath=c:\\temp\\SqlSinkSettings.json"
}
}
}

Просмотреть файл

@ -1,7 +0,0 @@
{
"ConnectionString": "DefaultEndpointsProtocol=https;AccountName=cosmosmigrationtable;AccountKey=<key>;EndpointSuffix=core.windows.net",
"Table": "DestinationTable1",
"PartitionKeyFieldName": "State",
"RowKeyFieldName": "id"
}

Просмотреть файл

@ -1,7 +0,0 @@
{
"ConnectionString": "DefaultEndpointsProtocol=https;AccountName=cosmosmigrationtable;AccountKey=<key>;EndpointSuffix=core.windows.net",
"Table": "SourceTable1",
"PartitionKeyFieldName": "State",
"RowKeyFieldName": "id"
}

Просмотреть файл

@ -1,6 +0,0 @@
{
"Database":"myDb",
"Container":"myContainer",
"PartitionKeyPath":"/id",
"RecreateContainer": true
}

Просмотреть файл

@ -1,5 +0,0 @@
{
"Database":"myDb",
"Container":"myContainer",
"IncludeMetadataFields": false
}

Просмотреть файл

@ -1,5 +0,0 @@
{
"FilePath": "c:\\temp\\test-json-out.json",
"Indented": true
}

Просмотреть файл

@ -1,4 +0,0 @@
{
"FilePath": "c:\\temp\\test-json-in.json"
}

Просмотреть файл

@ -1,5 +0,0 @@
{
"ConnectionString": "mongodb://localhost",
"DatabaseName": "myDb"
}

Просмотреть файл

@ -1,51 +0,0 @@
[
{
"id": "1",
"name": "John",
"level2": {
"id": 4324,
"location": "here"
},
"itemsNested": [
{
"number": "one",
"count": 3
},
{
"number": "two",
"count": 7
},
{
"number": "three",
"count": 2
}
]
},
{
"id": 2,
"name": "Matt",
"otherNames": [
"One",
"Two",
"Three"
],
"mixed": [
1,
true,
3,
"four",
{
"letter": "E",
"number": 6
}
]
},
{
"noId": 9,
"message": "Needs generated id"
},
{
"id": 3,
"description": "Hello JSON"
}
]

Просмотреть файл

@ -1,26 +0,0 @@
{
"JsonSourceSettings": {
},
"JsonSinkSettings": {
},
"CosmosSourceSettings": {
"ConnectionString": "<Add in User Secrets>"
},
"CosmosSinkSettings": {
"ConnectionString": "<Add in User Secrets>"
},
"MongoSourceSettings": {
},
"MongoSinkSettings": {
},
"AzureTableAPISourceSettings": {
},
"AzureTableAPISinkSettings": {
},
"SqlServerSourceSettings": {
"ConnectionString": "<Add in User Secrets>"
},
"SqlServerSinkSettings": {
"ConnectionString": "<Add in User Secrets>"
}
}

Просмотреть файл

@ -1,5 +0,0 @@
{
"additionalProbingPaths": [
"Extensions"
]
}

Просмотреть файл

@ -1,119 +0,0 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31919.166
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.DataTransfer.Core", "Core\Microsoft.DataTransfer.Core\Microsoft.DataTransfer.Core.csproj", "{A164C7E5-E6FB-43B3-85B1-C67FFDFE330A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.DataTransfer.Interfaces", "Interfaces\Microsoft.DataTransfer.Interfaces\Microsoft.DataTransfer.Interfaces.csproj", "{2A3EE681-C7CD-4062-913B-737E6265CEF7}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.DataTransfer.Core.UnitTests", "Core\Microsoft.DataTransfer.Core.UnitTests\Microsoft.DataTransfer.Core.UnitTests.csproj", "{7339C831-B668-4CF9-951C-E2F4AE951996}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Extensions", "Extensions", "{A8A1CEAB-2D82-460C-9B86-74ABD17CD201}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.DataTransfer.JsonExtension", "Extensions\Json\Microsoft.DataTransfer.JsonExtension\Microsoft.DataTransfer.JsonExtension.csproj", "{55355690-D898-4C75-818A-72655DB4495A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.DataTransfer.CosmosExtension", "Extensions\Cosmos\Microsoft.DataTransfer.CosmosExtension\Microsoft.DataTransfer.CosmosExtension.csproj", "{688F9479-06FF-4B8F-9294-369D549C78FD}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.DataTransfer.AzureTableAPIExtension", "Extensions\AzureTableAPI\Microsoft.DataTransfer.AzureTableAPIExtension\Microsoft.DataTransfer.AzureTableAPIExtension.csproj", "{CA03961C-4330-4ED9-963A-3B63FBC08ABB}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Cosmos", "Cosmos", "{D0475879-F47F-4D12-9A43-812043CFFD22}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Json", "Json", "{84E51D21-FA45-4CCB-94BB-6B6066749A4A}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AzureTableAPI", "AzureTableAPI", "{CB41F880-D0A5-42C1-9571-479CF7E54D82}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.DataTransfer.AzureTableAPIExtension.UnitTests", "Extensions\AzureTableAPI\Microsoft.DataTransfer.AzureTableAPIExtension.UnitTests\Microsoft.DataTransfer.AzureTableAPIExtension.UnitTests.csproj", "{F31FADBA-BC78-4839-A9F5-8861695EC95E}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Mongo", "Mongo", "{F18E789A-D32D-48D3-B75F-1196D7215F74}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.DataTransfer.MongoExtension", "Extensions\Mongo\Microsoft.DataTransfer.MongoExtension\Microsoft.DataTransfer.MongoExtension.csproj", "{F6EAC33B-9F7D-433B-9328-622FB8938C24}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.DataTransfer.JsonExtension.UnitTests", "Extensions\Json\Microsoft.DataTransfer.JsonExtension.UnitTests\Microsoft.DataTransfer.JsonExtension.UnitTests.csproj", "{ED1E375E-A5A3-47EA-A7D5-07344C7E152F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.DataTransfer.CosmosExtension.UnitTests", "Extensions\Cosmos\Microsoft.DataTransfer.CosmosExtension.UnitTests\Microsoft.DataTransfer.CosmosExtension.UnitTests.csproj", "{C7A3910D-A7F6-4767-9A7A-19CFA4CCB7A8}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SqlServer", "SqlServer", "{2F075279-E8B0-4A6E-A8D9-2058B7DEC671}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.DataTransfer.SqlServerExtension", "Extensions\SqlServer\Microsoft.DataTransfer.SqlServerExtension\Microsoft.DataTransfer.SqlServerExtension.csproj", "{7A020621-77E6-4DD1-B230-50A46B4BB2B1}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.DataTransfer.SqlServerExtension.UnitTests", "Extensions\SqlServer\Microsoft.DataTransfer.SqlServerExtension.UnitTests\Microsoft.DataTransfer.SqlServerExtension.UnitTests.csproj", "{3E4C4ABF-D8C2-4997-A719-E756483C8D63}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{A164C7E5-E6FB-43B3-85B1-C67FFDFE330A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A164C7E5-E6FB-43B3-85B1-C67FFDFE330A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A164C7E5-E6FB-43B3-85B1-C67FFDFE330A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A164C7E5-E6FB-43B3-85B1-C67FFDFE330A}.Release|Any CPU.Build.0 = Release|Any CPU
{2A3EE681-C7CD-4062-913B-737E6265CEF7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2A3EE681-C7CD-4062-913B-737E6265CEF7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2A3EE681-C7CD-4062-913B-737E6265CEF7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2A3EE681-C7CD-4062-913B-737E6265CEF7}.Release|Any CPU.Build.0 = Release|Any CPU
{7339C831-B668-4CF9-951C-E2F4AE951996}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7339C831-B668-4CF9-951C-E2F4AE951996}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7339C831-B668-4CF9-951C-E2F4AE951996}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7339C831-B668-4CF9-951C-E2F4AE951996}.Release|Any CPU.Build.0 = Release|Any CPU
{55355690-D898-4C75-818A-72655DB4495A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{55355690-D898-4C75-818A-72655DB4495A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{55355690-D898-4C75-818A-72655DB4495A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{55355690-D898-4C75-818A-72655DB4495A}.Release|Any CPU.Build.0 = Release|Any CPU
{688F9479-06FF-4B8F-9294-369D549C78FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{688F9479-06FF-4B8F-9294-369D549C78FD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{688F9479-06FF-4B8F-9294-369D549C78FD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{688F9479-06FF-4B8F-9294-369D549C78FD}.Release|Any CPU.Build.0 = Release|Any CPU
{CA03961C-4330-4ED9-963A-3B63FBC08ABB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CA03961C-4330-4ED9-963A-3B63FBC08ABB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CA03961C-4330-4ED9-963A-3B63FBC08ABB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CA03961C-4330-4ED9-963A-3B63FBC08ABB}.Release|Any CPU.Build.0 = Release|Any CPU
{F31FADBA-BC78-4839-A9F5-8861695EC95E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F31FADBA-BC78-4839-A9F5-8861695EC95E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F31FADBA-BC78-4839-A9F5-8861695EC95E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F31FADBA-BC78-4839-A9F5-8861695EC95E}.Release|Any CPU.Build.0 = Release|Any CPU
{F6EAC33B-9F7D-433B-9328-622FB8938C24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F6EAC33B-9F7D-433B-9328-622FB8938C24}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F6EAC33B-9F7D-433B-9328-622FB8938C24}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F6EAC33B-9F7D-433B-9328-622FB8938C24}.Release|Any CPU.Build.0 = Release|Any CPU
{ED1E375E-A5A3-47EA-A7D5-07344C7E152F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{ED1E375E-A5A3-47EA-A7D5-07344C7E152F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ED1E375E-A5A3-47EA-A7D5-07344C7E152F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ED1E375E-A5A3-47EA-A7D5-07344C7E152F}.Release|Any CPU.Build.0 = Release|Any CPU
{C7A3910D-A7F6-4767-9A7A-19CFA4CCB7A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C7A3910D-A7F6-4767-9A7A-19CFA4CCB7A8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C7A3910D-A7F6-4767-9A7A-19CFA4CCB7A8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C7A3910D-A7F6-4767-9A7A-19CFA4CCB7A8}.Release|Any CPU.Build.0 = Release|Any CPU
{7A020621-77E6-4DD1-B230-50A46B4BB2B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7A020621-77E6-4DD1-B230-50A46B4BB2B1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7A020621-77E6-4DD1-B230-50A46B4BB2B1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7A020621-77E6-4DD1-B230-50A46B4BB2B1}.Release|Any CPU.Build.0 = Release|Any CPU
{3E4C4ABF-D8C2-4997-A719-E756483C8D63}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3E4C4ABF-D8C2-4997-A719-E756483C8D63}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3E4C4ABF-D8C2-4997-A719-E756483C8D63}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3E4C4ABF-D8C2-4997-A719-E756483C8D63}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{55355690-D898-4C75-818A-72655DB4495A} = {84E51D21-FA45-4CCB-94BB-6B6066749A4A}
{688F9479-06FF-4B8F-9294-369D549C78FD} = {D0475879-F47F-4D12-9A43-812043CFFD22}
{CA03961C-4330-4ED9-963A-3B63FBC08ABB} = {CB41F880-D0A5-42C1-9571-479CF7E54D82}
{D0475879-F47F-4D12-9A43-812043CFFD22} = {A8A1CEAB-2D82-460C-9B86-74ABD17CD201}
{84E51D21-FA45-4CCB-94BB-6B6066749A4A} = {A8A1CEAB-2D82-460C-9B86-74ABD17CD201}
{CB41F880-D0A5-42C1-9571-479CF7E54D82} = {A8A1CEAB-2D82-460C-9B86-74ABD17CD201}
{F31FADBA-BC78-4839-A9F5-8861695EC95E} = {CB41F880-D0A5-42C1-9571-479CF7E54D82}
{F18E789A-D32D-48D3-B75F-1196D7215F74} = {A8A1CEAB-2D82-460C-9B86-74ABD17CD201}
{F6EAC33B-9F7D-433B-9328-622FB8938C24} = {F18E789A-D32D-48D3-B75F-1196D7215F74}
{ED1E375E-A5A3-47EA-A7D5-07344C7E152F} = {84E51D21-FA45-4CCB-94BB-6B6066749A4A}
{C7A3910D-A7F6-4767-9A7A-19CFA4CCB7A8} = {D0475879-F47F-4D12-9A43-812043CFFD22}
{2F075279-E8B0-4A6E-A8D9-2058B7DEC671} = {A8A1CEAB-2D82-460C-9B86-74ABD17CD201}
{7A020621-77E6-4DD1-B230-50A46B4BB2B1} = {2F075279-E8B0-4A6E-A8D9-2058B7DEC671}
{3E4C4ABF-D8C2-4997-A719-E756483C8D63} = {2F075279-E8B0-4A6E-A8D9-2058B7DEC671}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {662B3F27-70D8-45E6-A1C0-1438A9C8A542}
EndGlobalSection
EndGlobal

359
EULA.RTF
Просмотреть файл

@ -1,359 +0,0 @@
{\rtf1\adeflang1025\ansi\ansicpg1252\uc1\adeff0\deff0\stshfdbch0\stshfloch31506\stshfhich31506\stshfbi31506\deflang1033\deflangfe1033\themelang1033\themelangfe0\themelangcs0{\fonttbl{\f0\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman{\*\falt Times New Roman};}
{\f2\fbidi \fmodern\fcharset0\fprq1{\*\panose 02070309020205020404}Courier New{\*\falt Arial};}{\f3\fbidi \froman\fcharset2\fprq2{\*\panose 05050102010706020507}Symbol{\*\falt Bookshelf Symbol 3};}
{\f10\fbidi \fnil\fcharset2\fprq2{\*\panose 05000000000000000000}Wingdings{\*\falt Symbol};}{\f34\fbidi \froman\fcharset0\fprq2{\*\panose 02040503050406030204}Cambria Math{\*\falt Calisto MT};}
{\f37\fbidi \fswiss\fcharset0\fprq2{\*\panose 020f0502020204030204}Calibri{\*\falt Times New Roman};}{\f38\fbidi \fswiss\fcharset0\fprq2{\*\panose 020b0502040204020203}Segoe UI;}
{\flomajor\f31500\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman{\*\falt Times New Roman};}{\fdbmajor\f31501\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman{\*\falt Times New Roman};}
{\fhimajor\f31502\fbidi \fswiss\fcharset0\fprq2{\*\panose 020f0302020204030204}Calibri Light;}{\fbimajor\f31503\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman{\*\falt Times New Roman};}
{\flominor\f31504\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman{\*\falt Times New Roman};}{\fdbminor\f31505\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman{\*\falt Times New Roman};}
{\fhiminor\f31506\fbidi \fswiss\fcharset0\fprq2{\*\panose 020f0502020204030204}Calibri{\*\falt Times New Roman};}{\fbiminor\f31507\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman{\*\falt Times New Roman};}
{\f39\fbidi \froman\fcharset238\fprq2 Times New Roman CE{\*\falt Times New Roman};}{\f40\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr{\*\falt Times New Roman};}{\f42\fbidi \froman\fcharset161\fprq2 Times New Roman Greek{\*\falt Times New Roman};}
{\f43\fbidi \froman\fcharset162\fprq2 Times New Roman Tur{\*\falt Times New Roman};}{\f44\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew){\*\falt Times New Roman};}
{\f45\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic){\*\falt Times New Roman};}{\f46\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic{\*\falt Times New Roman};}
{\f47\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese){\*\falt Times New Roman};}{\f59\fbidi \fmodern\fcharset238\fprq1 Courier New CE{\*\falt Arial};}{\f60\fbidi \fmodern\fcharset204\fprq1 Courier New Cyr{\*\falt Arial};}
{\f62\fbidi \fmodern\fcharset161\fprq1 Courier New Greek{\*\falt Arial};}{\f63\fbidi \fmodern\fcharset162\fprq1 Courier New Tur{\*\falt Arial};}{\f64\fbidi \fmodern\fcharset177\fprq1 Courier New (Hebrew){\*\falt Arial};}
{\f65\fbidi \fmodern\fcharset178\fprq1 Courier New (Arabic){\*\falt Arial};}{\f66\fbidi \fmodern\fcharset186\fprq1 Courier New Baltic{\*\falt Arial};}{\f67\fbidi \fmodern\fcharset163\fprq1 Courier New (Vietnamese){\*\falt Arial};}
{\f379\fbidi \froman\fcharset238\fprq2 Cambria Math CE{\*\falt Calisto MT};}{\f380\fbidi \froman\fcharset204\fprq2 Cambria Math Cyr{\*\falt Calisto MT};}{\f382\fbidi \froman\fcharset161\fprq2 Cambria Math Greek{\*\falt Calisto MT};}
{\f383\fbidi \froman\fcharset162\fprq2 Cambria Math Tur{\*\falt Calisto MT};}{\f386\fbidi \froman\fcharset186\fprq2 Cambria Math Baltic{\*\falt Calisto MT};}{\f387\fbidi \froman\fcharset163\fprq2 Cambria Math (Vietnamese){\*\falt Calisto MT};}
{\f409\fbidi \fswiss\fcharset238\fprq2 Calibri CE{\*\falt Times New Roman};}{\f410\fbidi \fswiss\fcharset204\fprq2 Calibri Cyr{\*\falt Times New Roman};}{\f412\fbidi \fswiss\fcharset161\fprq2 Calibri Greek{\*\falt Times New Roman};}
{\f413\fbidi \fswiss\fcharset162\fprq2 Calibri Tur{\*\falt Times New Roman};}{\f416\fbidi \fswiss\fcharset186\fprq2 Calibri Baltic{\*\falt Times New Roman};}{\f417\fbidi \fswiss\fcharset163\fprq2 Calibri (Vietnamese){\*\falt Times New Roman};}
{\f419\fbidi \fswiss\fcharset238\fprq2 Segoe UI CE;}{\f420\fbidi \fswiss\fcharset204\fprq2 Segoe UI Cyr;}{\f422\fbidi \fswiss\fcharset161\fprq2 Segoe UI Greek;}{\f423\fbidi \fswiss\fcharset162\fprq2 Segoe UI Tur;}
{\f424\fbidi \fswiss\fcharset177\fprq2 Segoe UI (Hebrew);}{\f425\fbidi \fswiss\fcharset178\fprq2 Segoe UI (Arabic);}{\f426\fbidi \fswiss\fcharset186\fprq2 Segoe UI Baltic;}{\f427\fbidi \fswiss\fcharset163\fprq2 Segoe UI (Vietnamese);}
{\flomajor\f31508\fbidi \froman\fcharset238\fprq2 Times New Roman CE{\*\falt Times New Roman};}{\flomajor\f31509\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr{\*\falt Times New Roman};}
{\flomajor\f31511\fbidi \froman\fcharset161\fprq2 Times New Roman Greek{\*\falt Times New Roman};}{\flomajor\f31512\fbidi \froman\fcharset162\fprq2 Times New Roman Tur{\*\falt Times New Roman};}
{\flomajor\f31513\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew){\*\falt Times New Roman};}{\flomajor\f31514\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic){\*\falt Times New Roman};}
{\flomajor\f31515\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic{\*\falt Times New Roman};}{\flomajor\f31516\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese){\*\falt Times New Roman};}
{\fdbmajor\f31518\fbidi \froman\fcharset238\fprq2 Times New Roman CE{\*\falt Times New Roman};}{\fdbmajor\f31519\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr{\*\falt Times New Roman};}
{\fdbmajor\f31521\fbidi \froman\fcharset161\fprq2 Times New Roman Greek{\*\falt Times New Roman};}{\fdbmajor\f31522\fbidi \froman\fcharset162\fprq2 Times New Roman Tur{\*\falt Times New Roman};}
{\fdbmajor\f31523\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew){\*\falt Times New Roman};}{\fdbmajor\f31524\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic){\*\falt Times New Roman};}
{\fdbmajor\f31525\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic{\*\falt Times New Roman};}{\fdbmajor\f31526\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese){\*\falt Times New Roman};}
{\fhimajor\f31528\fbidi \fswiss\fcharset238\fprq2 Calibri Light CE;}{\fhimajor\f31529\fbidi \fswiss\fcharset204\fprq2 Calibri Light Cyr;}{\fhimajor\f31531\fbidi \fswiss\fcharset161\fprq2 Calibri Light Greek;}
{\fhimajor\f31532\fbidi \fswiss\fcharset162\fprq2 Calibri Light Tur;}{\fhimajor\f31535\fbidi \fswiss\fcharset186\fprq2 Calibri Light Baltic;}{\fhimajor\f31536\fbidi \fswiss\fcharset163\fprq2 Calibri Light (Vietnamese);}
{\fbimajor\f31538\fbidi \froman\fcharset238\fprq2 Times New Roman CE{\*\falt Times New Roman};}{\fbimajor\f31539\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr{\*\falt Times New Roman};}
{\fbimajor\f31541\fbidi \froman\fcharset161\fprq2 Times New Roman Greek{\*\falt Times New Roman};}{\fbimajor\f31542\fbidi \froman\fcharset162\fprq2 Times New Roman Tur{\*\falt Times New Roman};}
{\fbimajor\f31543\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew){\*\falt Times New Roman};}{\fbimajor\f31544\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic){\*\falt Times New Roman};}
{\fbimajor\f31545\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic{\*\falt Times New Roman};}{\fbimajor\f31546\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese){\*\falt Times New Roman};}
{\flominor\f31548\fbidi \froman\fcharset238\fprq2 Times New Roman CE{\*\falt Times New Roman};}{\flominor\f31549\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr{\*\falt Times New Roman};}
{\flominor\f31551\fbidi \froman\fcharset161\fprq2 Times New Roman Greek{\*\falt Times New Roman};}{\flominor\f31552\fbidi \froman\fcharset162\fprq2 Times New Roman Tur{\*\falt Times New Roman};}
{\flominor\f31553\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew){\*\falt Times New Roman};}{\flominor\f31554\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic){\*\falt Times New Roman};}
{\flominor\f31555\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic{\*\falt Times New Roman};}{\flominor\f31556\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese){\*\falt Times New Roman};}
{\fdbminor\f31558\fbidi \froman\fcharset238\fprq2 Times New Roman CE{\*\falt Times New Roman};}{\fdbminor\f31559\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr{\*\falt Times New Roman};}
{\fdbminor\f31561\fbidi \froman\fcharset161\fprq2 Times New Roman Greek{\*\falt Times New Roman};}{\fdbminor\f31562\fbidi \froman\fcharset162\fprq2 Times New Roman Tur{\*\falt Times New Roman};}
{\fdbminor\f31563\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew){\*\falt Times New Roman};}{\fdbminor\f31564\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic){\*\falt Times New Roman};}
{\fdbminor\f31565\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic{\*\falt Times New Roman};}{\fdbminor\f31566\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese){\*\falt Times New Roman};}
{\fhiminor\f31568\fbidi \fswiss\fcharset238\fprq2 Calibri CE{\*\falt Times New Roman};}{\fhiminor\f31569\fbidi \fswiss\fcharset204\fprq2 Calibri Cyr{\*\falt Times New Roman};}
{\fhiminor\f31571\fbidi \fswiss\fcharset161\fprq2 Calibri Greek{\*\falt Times New Roman};}{\fhiminor\f31572\fbidi \fswiss\fcharset162\fprq2 Calibri Tur{\*\falt Times New Roman};}
{\fhiminor\f31575\fbidi \fswiss\fcharset186\fprq2 Calibri Baltic{\*\falt Times New Roman};}{\fhiminor\f31576\fbidi \fswiss\fcharset163\fprq2 Calibri (Vietnamese){\*\falt Times New Roman};}
{\fbiminor\f31578\fbidi \froman\fcharset238\fprq2 Times New Roman CE{\*\falt Times New Roman};}{\fbiminor\f31579\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr{\*\falt Times New Roman};}
{\fbiminor\f31581\fbidi \froman\fcharset161\fprq2 Times New Roman Greek{\*\falt Times New Roman};}{\fbiminor\f31582\fbidi \froman\fcharset162\fprq2 Times New Roman Tur{\*\falt Times New Roman};}
{\fbiminor\f31583\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew){\*\falt Times New Roman};}{\fbiminor\f31584\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic){\*\falt Times New Roman};}
{\fbiminor\f31585\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic{\*\falt Times New Roman};}{\fbiminor\f31586\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese){\*\falt Times New Roman};}}{\colortbl;\red0\green0\blue0;
\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;
\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;}{\*\defchp \f31506\fs22 }{\*\defpap \ql \li0\ri0\sa160\sl259\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 }
\noqfpromote {\stylesheet{\ql \li0\ri0\sa160\sl259\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs22\alang1025 \ltrch\fcs0 \f31506\fs22\lang1033\langfe1033\cgrid\langnp1033\langfenp1033
\snext0 \sqformat \spriority0 \styrsid6032001 Normal;}{\*\cs10 \additive \ssemihidden \sunhideused \spriority1 Default Paragraph Font;}{\*
\ts11\tsrowd\trftsWidthB3\trpaddl108\trpaddr108\trpaddfl3\trpaddft3\trpaddfb3\trpaddfr3\trcbpat1\trcfpat1\tblind0\tblindtype3\tsvertalt\tsbrdrt\tsbrdrl\tsbrdrb\tsbrdrr\tsbrdrdgl\tsbrdrdgr\tsbrdrh\tsbrdrv \ql \li0\ri0\sa160\sl259\slmult1
\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31506\afs22\alang1025 \ltrch\fcs0 \f31506\fs22\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \snext11 \ssemihidden \sunhideused Normal Table;}{\*\cs15 \additive
\rtlch\fcs1 \af0\afs16 \ltrch\fcs0 \fs16 \sbasedon10 \ssemihidden \sunhideused \styrsid6032001 annotation reference;}{\s16\ql \li0\ri0\sa160\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025
\ltrch\fcs0 \f31506\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext16 \slink17 \ssemihidden \sunhideused \styrsid6032001 annotation text;}{\*\cs17 \additive \rtlch\fcs1 \af0\afs20 \ltrch\fcs0 \fs20\dbch\af0
\sbasedon10 \slink16 \slocked \ssemihidden \styrsid6032001 Comment Text Char;}{\s18\ql \li0\ri0\sa160\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \ab\af0\afs20\alang1025 \ltrch\fcs0
\b\f31506\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon16 \snext16 \slink19 \ssemihidden \sunhideused \styrsid6032001 annotation subject;}{\*\cs19 \additive \rtlch\fcs1 \ab\af0\afs20 \ltrch\fcs0 \b\fs20\dbch\af0
\sbasedon17 \slink18 \slocked \ssemihidden \styrsid6032001 Comment Subject Char;}{\s20\ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af38\afs18\alang1025 \ltrch\fcs0
\f38\fs18\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext20 \slink21 \ssemihidden \sunhideused \styrsid6032001 Balloon Text;}{\*\cs21 \additive \rtlch\fcs1 \af38\afs18 \ltrch\fcs0 \f38\fs18
\sbasedon10 \slink20 \slocked \ssemihidden \styrsid6032001 Balloon Text Char;}{\s22\ql \li720\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin720\itap0 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0
\fs24\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext22 \sqformat \spriority34 \styrsid15406008 List Paragraph;}}{\*\listtable{\list\listtemplateid1868886164{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0
\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fs20\fbias0 \fi-360\li720\jclisttab\tx720\lin720 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0
{\leveltext\'01o;}{\levelnumbers;}\f2\fs20\fbias0 \fi-360\li1440\jclisttab\tx1440\lin1440 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\'01\u-3929 ?;}{\levelnumbers;}
\f10\fs20\fbias0 \fi-360\li2160\jclisttab\tx2160\lin2160 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f10\fs20\fbias0 \fi-360\li2880
\jclisttab\tx2880\lin2880 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f10\fs20\fbias0 \fi-360\li3600\jclisttab\tx3600\lin3600 }
{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f10\fs20\fbias0 \fi-360\li4320\jclisttab\tx4320\lin4320 }{\listlevel\levelnfc23\levelnfcn23
\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f10\fs20\fbias0 \fi-360\li5040\jclisttab\tx5040\lin5040 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0
\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f10\fs20\fbias0 \fi-360\li5760\jclisttab\tx5760\lin5760 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative
\levelspace0\levelindent0{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f10\fs20\fbias0 \fi-360\li6480\jclisttab\tx6480\lin6480 }{\listname ;}\listid964506261}{\list\listtemplateid-1239677934\listhybrid{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0
\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698703\'02\'00.;}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fi-360\li720\lin720 }{\listlevel\levelnfc4\levelnfcn4\leveljc0\leveljcn0\levelfollow0\levelstartat1
\levelspace0\levelindent0{\leveltext\leveltemplateid67698713\'02\'01.;}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fi-360\li1440\lin1440 }{\listlevel\levelnfc2\levelnfcn2\leveljc2\leveljcn2\levelfollow0\levelstartat1\levelspace0\levelindent0
{\leveltext\leveltemplateid67698715\'02\'02.;}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fi-180\li2160\lin2160 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext
\leveltemplateid67698703\'02\'03.;}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fi-360\li2880\lin2880 }{\listlevel\levelnfc4\levelnfcn4\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698713
\'02\'04.;}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fi-360\li3600\lin3600 }{\listlevel\levelnfc2\levelnfcn2\leveljc2\leveljcn2\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698715\'02\'05.;}{\levelnumbers\'01;}
\rtlch\fcs1 \af0 \ltrch\fcs0 \fi-180\li4320\lin4320 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698703\'02\'06.;}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0
\fi-360\li5040\lin5040 }{\listlevel\levelnfc4\levelnfcn4\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698713\'02\'07.;}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fi-360\li5760\lin5760 }
{\listlevel\levelnfc2\levelnfcn2\leveljc2\leveljcn2\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698715\'02\'08.;}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fi-180\li6480\lin6480 }{\listname ;}\listid1456872348}
{\list\listtemplateid1581805376\listhybrid{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698703\'02\'00.;}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0
\fi-360\li720\lin720 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li1440\lin1440 }{\listlevel\levelnfc2
\levelnfcn2\leveljc2\leveljcn2\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698715\'02\'02.;}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fi-180\li2160\lin2160 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0
\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698703\'02\'03.;}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fi-360\li2880\lin2880 }{\listlevel\levelnfc4\levelnfcn4\leveljc0\leveljcn0\levelfollow0\levelstartat1
\levelspace0\levelindent0{\leveltext\leveltemplateid67698713\'02\'04.;}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fi-360\li3600\lin3600 }{\listlevel\levelnfc2\levelnfcn2\leveljc2\leveljcn2\levelfollow0\levelstartat1\levelspace0\levelindent0
{\leveltext\leveltemplateid67698715\'02\'05.;}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fi-180\li4320\lin4320 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext
\leveltemplateid67698703\'02\'06.;}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fi-360\li5040\lin5040 }{\listlevel\levelnfc4\levelnfcn4\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698713
\'02\'07.;}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fi-360\li5760\lin5760 }{\listlevel\levelnfc2\levelnfcn2\leveljc2\leveljcn2\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698715\'02\'08.;}{\levelnumbers\'01;}
\rtlch\fcs1 \af0 \ltrch\fcs0 \fi-180\li6480\lin6480 }{\listname ;}\listid1914966234}}{\*\listoverridetable{\listoverride\listid964506261\listoverridecount0\ls1}{\listoverride\listid1456872348\listoverridecount9{\lfolevel\listoverridestartat\levelstartat1}
{\lfolevel\listoverridestartat\levelstartat1}{\lfolevel\listoverridestartat\levelstartat1}{\lfolevel\listoverridestartat\levelstartat1}{\lfolevel\listoverridestartat\levelstartat1}{\lfolevel\listoverridestartat\levelstartat1}{\lfolevel\listoverridestartat
\levelstartat1}{\lfolevel\listoverridestartat\levelstartat1}{\lfolevel\listoverridestartat\levelstartat1}\ls2}{\listoverride\listid1456872348\listoverridecount0\ls3}{\listoverride\listid1914966234\listoverridecount0\ls4}}{\*\pgptbl {\pgp\ipgp0\itap0\li0
\ri0\sb0\sa0}}{\*\rsidtbl \rsid1578962\rsid2838952\rsid3095117\rsid4149390\rsid4481066\rsid6032001\rsid7233155\rsid8026982\rsid10041081\rsid11088741\rsid12587259\rsid14049609\rsid15406008\rsid16546034}{\mmathPr\mmathFont34\mbrkBin0\mbrkBinSub0\msmallFrac0
\mdispDef1\mlMargin0\mrMargin0\mdefJc1\mwrapIndent1440\mintLim0\mnaryLim1}{\info{\author Preeti Singh (LCA)}{\operator Alexander Ivanov}{\creatim\yr2015\mo4\dy7\hr10\min9}{\revtim\yr2015\mo7\dy7\hr11\min29}{\version5}{\edmins4}{\nofpages4}{\nofwords1164}
{\nofchars6637}{\nofcharsws7786}{\vern57439}}{\*\xmlnstbl {\xmlns1 http://schemas.microsoft.com/office/word/2003/wordml}}\paperw12240\paperh15840\margl1440\margr1440\margt1440\margb1440\gutter0\ltrsect
\widowctrl\ftnbj\aenddoc\trackmoves0\trackformatting1\donotembedsysfont1\relyonvml0\donotembedlingdata0\grfdocevents0\validatexml1\showplaceholdtext0\ignoremixedcontent0\saveinvalidxml0\showxmlerrors1\noxlattoyen
\expshrtn\noultrlspc\dntblnsbdb\nospaceforul\formshade\horzdoc\dgmargin\dghspace180\dgvspace180\dghorigin1440\dgvorigin1440\dghshow1\dgvshow1
\jexpand\viewkind1\viewscale100\pgbrdrhead\pgbrdrfoot\splytwnine\ftnlytwnine\htmautsp\nolnhtadjtbl\useltbaln\alntblind\lytcalctblwd\lyttblrtgr\lnbrkrule\nobrkwrptbl\snaptogridincell\allowfieldendsel\wrppunct
\asianbrkrule\rsidroot6032001\newtblstyruls\nogrowautofit\usenormstyforlist\noindnmbrts\felnbrelev\nocxsptable\indrlsweleven\noafcnsttbl\afelev\utinl\hwelev\spltpgpar\notcvasp\notbrkcnstfrctbl\notvatxbx\krnprsnet\cachedcolbal \nouicompat \fet0
{\*\wgrffmtfilter 2450}\nofeaturethrottle1\ilfomacatclnup0\ltrpar \sectd \ltrsect\linex0\endnhere\sectlinegrid360\sectdefaultcl\sftnbj {\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl2\pnucltr\pnstart1\pnindent720\pnhang
{\pntxta .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang {\pntxta )}}{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl6\pnlcltr\pnstart1\pnindent720\pnhang
{\pntxtb (}{\pntxta )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl8\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}
\pard\plain \ltrpar\ql \li0\ri0\sa160\sl259\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid6032001 \rtlch\fcs1 \af0\afs22\alang1025 \ltrch\fcs0 \f31506\fs22\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {
\rtlch\fcs1 \af0 \ltrch\fcs0 \b\insrsid6032001\charrsid4149390 MICROSOFT SOFTWARE LICENSE TERMS
\par }{\rtlch\fcs1 \af0 \ltrch\fcs0 \b\insrsid8026982 Azure }{\rtlch\fcs1 \af0 \ltrch\fcs0 \b\insrsid6032001 DocumentDB Data Migration Tool}{\rtlch\fcs1 \af0 \ltrch\fcs0 \b\insrsid6032001\charrsid4149390
\par }{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid6032001
\par These license terms are an agreement
between Microsoft Corporation (or based on where you live, one of its affiliates) and you. Please read them. They apply to the software named above, which includes the media on which you received it, if any. The terms also apply to any Microsoft
\par
\par * updates,
\par * supplements,
\par * Internet-based services, and
\par * support services
\par
\par for this software, unless other terms accompany those items. If so, those terms apply.
\par
\par By using the software, you accept these terms}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid6032001\charrsid6032001 . You may choose not to accept these terms, in which ca
se you may not use the software (if you have not already installed it) or withdraw your acceptance any time by uninstalling the software.}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid6032001
\par If you comply with these license terms, you have the rights below.
\par
\par }{\rtlch\fcs1 \af0 \ltrch\fcs0 \b\insrsid6032001\charrsid4149390 1. INSTALLATION AND USE RIGHTS.
\par a. Installation and Use.}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid6032001 You may run this software on your devices }{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid15406008 to migrate data to Azure DocumentDB from }{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid7233155
different }{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid15406008 data sources}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid7233155 including}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid1578962 , but not limited to}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid15406008 :}{
\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid6032001
\par {\listtext\pard\plain\ltrpar \s22 \rtlch\fcs1 \af0\afs22 \ltrch\fcs0 \f3\fs22\insrsid15406008\charrsid15406008 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard\plain \ltrpar
\s22\ql \fi-180\li180\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\ls4\ilvl1\adjustright\rin0\lin180\itap0\pararsid15406008 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af0\afs22
\ltrch\fcs0 \f31506\fs22\insrsid15406008\charrsid15406008 CSV file/s
\par {\listtext\pard\plain\ltrpar \s22 \rtlch\fcs1 \af0\afs22 \ltrch\fcs0 \f3\fs22\insrsid15406008\charrsid15406008 \loch\af3\dbch\af0\hich\f3 \'b7\tab}JSON file/s
\par {\listtext\pard\plain\ltrpar \s22 \rtlch\fcs1 \af0\afs22 \ltrch\fcs0 \f3\fs22\insrsid15406008\charrsid15406008 \loch\af3\dbch\af0\hich\f3 \'b7\tab}SQL
\par {\listtext\pard\plain\ltrpar \s22 \rtlch\fcs1 \af0\afs22 \ltrch\fcs0 \f3\fs22\insrsid15406008\charrsid15406008 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ltrpar\s22\ql \fi-180\li180\ri0\widctlpar
\tx1350\wrapdefault\aspalpha\aspnum\faauto\ls4\ilvl1\adjustright\rin0\lin180\itap0\pararsid15406008 {\rtlch\fcs1 \af0\afs22 \ltrch\fcs0 \f31506\fs22\insrsid15406008\charrsid15406008 Azure DocumentDB
\par {\listtext\pard\plain\ltrpar \s22 \rtlch\fcs1 \af0\afs22 \ltrch\fcs0 \f3\fs22\insrsid15406008\charrsid15406008 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ltrpar
\s22\ql \fi-180\li180\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\ls4\ilvl1\adjustright\rin0\lin180\itap0\pararsid15406008 {\rtlch\fcs1 \af0\afs22 \ltrch\fcs0 \f31506\fs22\insrsid15406008\charrsid15406008 MongoDB}{\rtlch\fcs1 \af0\afs22 \ltrch\fcs0
\f31506\fs22\insrsid15406008
\par {\listtext\pard\plain\ltrpar \s22 \rtlch\fcs1 \af0\afs22 \ltrch\fcs0 \f3\fs22\insrsid7233155 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}{\rtlch\fcs1 \af0\afs22 \ltrch\fcs0 \f31506\fs22\insrsid7233155 Azure Table
\par {\listtext\pard\plain\ltrpar \s22 \rtlch\fcs1 \af0\afs22 \ltrch\fcs0 \f3\fs22\insrsid4481066 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}{\rtlch\fcs1 \af0\afs22 \ltrch\fcs0 \f31506\fs22\insrsid4481066 Amazon DynamoDB
\par {\listtext\pard\plain\ltrpar \s22 \rtlch\fcs1 \af0\afs22 \ltrch\fcs0 \f3\fs22\insrsid4481066 \loch\af3\dbch\af0\hich\f3 \'b7\tab}HBase
\par }\pard \ltrpar\s22\ql \li180\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin180\itap0\pararsid15406008 {\rtlch\fcs1 \af0\afs22 \ltrch\fcs0 \f31506\fs22\insrsid15406008\charrsid15406008
\par }\pard\plain \ltrpar\ql \li0\ri0\sa160\sl259\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid6032001 \rtlch\fcs1 \af0\afs22\alang1025 \ltrch\fcs0 \f31506\fs22\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {
\rtlch\fcs1 \af0 \ltrch\fcs0 \b\insrsid6032001 b}{\rtlch\fcs1 \af0 \ltrch\fcs0 \b\insrsid6032001\charrsid4149390 . Third Party Programs.}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid6032001\charrsid4149390 The software include}{\rtlch\fcs1 \af0 \ltrch\fcs0
\insrsid6032001 s}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid6032001\charrsid4149390
third party programs that Microsoft, not the third party, licenses to you under this agreement. Notices, if any, for the third party program are included for your information only.}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid6032001
\par }{\rtlch\fcs1 \af0 \ltrch\fcs0 \b\insrsid6032001\charrsid4149390 2. SCOPE OF LICENSE.}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid6032001 The software is licensed, not s
old. This agreement only gives you some rights to use the software. Microsoft reserves all other rights. Unless applicable law gives you more rights despite this limitation, you may use the software only as expressly permitted in this agreement. In doing
so, you must comply with any technical limitations in the software that only allow you to use it in certain ways. You may not
\par
\par * disclose the results of any benchmark tests of the software to any third party without Microsoft\rquote s prior written approval;
\par * work around any technical limitations in the software;
\par * reverse engineer, decompile or disassemble the software, except and only to the extent that applicable law expressly permits, despite this limitation;
\par * make more copies of the software than specified in this agreement or allowed by applicable law, despite this limitation;
\par * publish the software for others to copy;
\par * rent, lease or lend the software;
\par * transfer the software or this agreement to any third party; or
\par * use the software for commercial software hosting services.
\par }\pard \ltrpar\ql \fi-360\li360\ri0\sb100\sa100\sbauto1\saauto1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin360\itap0\pararsid6032001 {\rtlch\fcs1 \af0 \ltrch\fcs0 \b\insrsid6032001 3}{\rtlch\fcs1 \af0 \ltrch\fcs0
\b\insrsid6032001\charrsid12587259 .\tab EXPORT RESTRICTIONS.}{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0 \f0\fs24\lang9\langfe1033\langnp9\insrsid6032001\charrsid2838952 }{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid6032001\charrsid12587259
The software is subject to United States export laws and regulations. You must comply with all domestic and international export laws and regulations that apply to the software. These laws include restrictions on destinations, end users and end use. For a
dditional information, see}{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0 \f0\fs24\lang9\langfe1033\langnp9\insrsid6032001\charrsid2838952 }{\field\fldedit{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid16546034 HYPERLINK "http://www.microsoft.com/exporting" }{
\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid7233155 {\*\datafield
00d0c9ea79f9bace118c8200aa004ba90b0200000003000000e0c9ea79f9bace118c8200aa004ba90b5e00000068007400740070003a002f002f007700770077002e006d006900630072006f0073006f00660074002e0063006f006d002f006500780070006f007200740069006e0067000000795881f43b1d7f48af2c825d
c485276300000000a5ab000000}}}{\fldrslt {\rtlch\fcs1 \af0 \ltrch\fcs0 \ul\cf2\lang9\langfe1033\langnp9\insrsid6032001\charrsid12587259 www.microsoft.com/exporting}}}\sectd \ltrsect\linex0\endnhere\sectlinegrid360\sectdefaultcl\sftnbj {\rtlch\fcs1
\af0\afs24 \ltrch\fcs0 \f0\fs24\lang9\langfe1033\langnp9\insrsid6032001\charrsid2838952 .}{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0 \f0\fs24\lang9\langfe1033\langnp9\insrsid6032001
\par }\pard \ltrpar\ql \fi-360\li360\ri0\sa160\sl259\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin360\itap0\pararsid6032001 {\rtlch\fcs1 \af0 \ltrch\fcs0 \b\insrsid6032001\charrsid6032001 4}{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0
\f0\fs24\lang9\langfe1033\langnp9\insrsid6032001\charrsid6032001 . }{\rtlch\fcs1 \af0 \ltrch\fcs0 \b\insrsid6032001\charrsid6032001 UPDATES. }{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid6032001\charrsid6032001 The software may install automa
tic updates, which cannot be turned off. By using the software, you agree to receive automatic updates without any additional notice, and permit Microsoft to download and install them for you. You agree to obtain these updates only from Microsoft or Micro
soft authorized sources.\~\~ If you do not want software updates, disconnect your device from the internet or uninstall the software.}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid6032001\charrsid14049609
\par }\pard \ltrpar\ql \fi-360\li360\ri0\sb100\sa100\sbauto1\saauto1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin360\itap0\pararsid6032001 {\rtlch\fcs1 \af0 \ltrch\fcs0 \b\insrsid6032001 5}{\rtlch\fcs1 \af0 \ltrch\fcs0
\b\insrsid6032001\charrsid12587259 .\tab SUPPORT SERVICES.}{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0 \f0\fs24\lang9\langfe1033\langnp9\insrsid6032001\charrsid2838952 }{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid6032001\charrsid12587259 Because this software is \'93
as is,\'94 we may not provide support services for it.
\par }{\rtlch\fcs1 \af0 \ltrch\fcs0 \b\insrsid6032001 6}{\rtlch\fcs1 \af0 \ltrch\fcs0 \b\insrsid6032001\charrsid12587259 .\tab ENTIRE AGREEMENT.}{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0 \f0\fs24\lang9\langfe1033\langnp9\insrsid6032001\charrsid2838952 }{
\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid6032001\charrsid12587259 This agreement, and the terms for supplements, updates, Internet-based services and support services that you use, are the entire agreement for the software and support services.
\par }\pard \ltrpar\ql \li0\ri0\sb100\sa100\sbauto1\saauto1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid6032001 {\rtlch\fcs1 \af0 \ltrch\fcs0 \b\insrsid6032001 7}{\rtlch\fcs1 \af0 \ltrch\fcs0
\b\insrsid6032001\charrsid12587259 . APPLICABLE LAW.
\par }\pard \ltrpar\ql \fi-360\li720\ri0\sb100\sa100\sbauto1\saauto1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin720\itap0\pararsid6032001 {\rtlch\fcs1 \af0 \ltrch\fcs0 \b\insrsid6032001\charrsid12587259 a.\tab United States.}{\rtlch\fcs1
\af0\afs24 \ltrch\fcs0 \f0\fs24\lang9\langfe1033\langnp9\insrsid6032001\charrsid2838952 }{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid6032001\charrsid12587259 If you acquired the software in the United
States, Washington state law governs the interpretation of this agreement and applies to claims for breach of it, regardless of conflict of laws principles. The laws of the state where you live govern all other claims, including claims under state consume
r protection laws, unfair competition laws, and in tort.
\par }{\rtlch\fcs1 \af0 \ltrch\fcs0 \b\insrsid6032001\charrsid12587259 b.\tab Outside the United States.}{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0 \f0\fs24\lang9\langfe1033\langnp9\insrsid6032001\charrsid2838952 }{\rtlch\fcs1 \af0 \ltrch\fcs0
\insrsid6032001\charrsid12587259 If you acquired the software in any other country, the laws of that country apply.
\par }\pard \ltrpar\ql \fi-360\li360\ri0\sb100\sa100\sbauto1\saauto1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin360\itap0\pararsid6032001 {\rtlch\fcs1 \af0 \ltrch\fcs0 \b\insrsid6032001 8}{\rtlch\fcs1 \af0 \ltrch\fcs0
\b\insrsid6032001\charrsid12587259 .\tab LEGAL EFFECT.}{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0 \f0\fs24\lang9\langfe1033\langnp9\insrsid6032001\charrsid2838952 }{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid6032001\charrsid12587259
This agreement describes certain legal rights. You may have other righ
ts under the laws of your country. You may also have rights with respect to the party from whom you acquired the software. This agreement does not change your rights under the laws of your country if the laws of your country do not permit it to do so.
\par }{\rtlch\fcs1 \af0 \ltrch\fcs0 \b\insrsid6032001 9}{\rtlch\fcs1 \af0 \ltrch\fcs0 \b\insrsid6032001\charrsid12587259 .\tab DISCLAIMER OF WARRANTY. THE SOFTWARE IS LICENSED \'93AS-IS.\'94
YOU BEAR THE RISK OF USING IT. MICROSOFT GIVES NO EXPRESS WARRANTIES, GUARANTEES OR CONDITIONS. YOU MAY HAVE ADDITIONAL CONSUMER RIGHTS UNDER YOUR LOCAL LAWS WHICH THIS AGREEMENT CANNOT CHANGE. TO T
HE EXTENT PERMITTED UNDER YOUR LOCAL LAWS, MICROSOFT EXCLUDES THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
\par }{\rtlch\fcs1 \af0 \ltrch\fcs0 \b\insrsid6032001 10}{\rtlch\fcs1 \af0 \ltrch\fcs0 \b\insrsid6032001\charrsid12587259 .\tab LIMITATION ON AND EXCLUSION OF REMEDIES AND DAMAGES.}{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0
\f0\fs24\lang9\langfe1033\langnp9\insrsid6032001\charrsid2838952 }{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid6032001\charrsid12587259 YOU CAN RECOVER FROM MICROSOFT AND ITS
SUPPLIERS ONLY DIRECT DAMAGES UP TO U.S. $5.00. YOU CANNOT RECOVER ANY OTHER DAMAGES, INCLUDING CONSEQUENTIAL, LOST PROFITS, SPECIAL, INDIRECT OR INCIDENTAL DAMAGES.
\par }\pard \ltrpar\ql \fi360\li0\ri0\sb100\sa100\sbauto1\saauto1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid6032001 {\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid6032001\charrsid12587259 This limitation applies to
\par {\listtext\pard\plain\ltrpar \rtlch\fcs1 \af0\afs22 \ltrch\fcs0 \f3\fs20\insrsid6032001\charrsid12587259 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ltrpar\ql \fi-360\li720\ri0\sb100\sa100\sbauto1\saauto1\widctlpar
\jclisttab\tx720\wrapdefault\aspalpha\aspnum\faauto\ls1\adjustright\rin0\lin720\itap0\pararsid6032001 {\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid6032001\charrsid12587259 anything related to the software, services, content (includin
g code) on third party Internet sites, or third party programs, and
\par {\listtext\pard\plain\ltrpar \rtlch\fcs1 \af0\afs22 \ltrch\fcs0 \f3\fs20\insrsid6032001\charrsid12587259 \loch\af3\dbch\af0\hich\f3 \'b7\tab}
claims for breach of contract, breach of warranty, guarantee or condition, strict liability, negligence, or other tort to the extent permitted by applicable law.
\par }\pard \ltrpar\ql \li360\ri0\sb100\sa100\sbauto1\saauto1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin360\itap0\pararsid6032001 {\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid6032001\charrsid12587259 It also applies even if
Microsoft knew or should have known about the possibility of the damages. The above limitation or exclusion may not apply to you because your country may not allow the exclusion or limitation of incidental, consequential or other damages.
\par }{\rtlch\fcs1 \af0 \ltrch\fcs0 \b\insrsid6032001\charrsid12587259 Please note:}{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0 \f0\fs24\lang9\langfe1033\langnp9\insrsid6032001\charrsid2838952 }{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid6032001\charrsid12587259
As this software is distributed in Quebec, Canada, some of the clauses in this agreement are provided below in French.
\par }{\rtlch\fcs1 \af0 \ltrch\fcs0 \b\insrsid6032001\charrsid12587259 Remarque:}{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0 \f0\fs24\lang9\langfe1033\langnp9\insrsid6032001\charrsid2838952 }{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid6032001\charrsid12587259 Ce logiciel
\'e9tant distribu\'e9 au Qu\'e9bec, Canada, certaines des clauses dans ce contrat sont fournies ci-dessous en fran\'e7ais.
\par }{\rtlch\fcs1 \af0 \ltrch\fcs0 \b\insrsid6032001\charrsid12587259 EXON\'c9RATION DE GARANTIE.}{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0 \f0\fs24\lang9\langfe1033\langnp9\insrsid6032001\charrsid2838952 }{\rtlch\fcs1 \af0 \ltrch\fcs0
\insrsid6032001\charrsid12587259 Le logiciel vis\'e9 par une licence est offert \'ab tel quel \'bb. Toute utilisation de ce logiciel est \'e0 votre seule risque et p\'e9ril. Microsoft n\rquote accorde aucune autre garantie expresse. Vous pouvez b\'e9n\'e9
ficier de droits additionnels en vertu du droit local sur la protection des consommateurs, que ce contrat ne peut modifier. La ou elles sont permises par le droit locale, les garanties implicites de qualit\'e9 marchande, d\rquote ad\'e9quation \'e0
un usage particulier et d\rquote absence de contrefa\'e7on sont exclues.
\par }{\rtlch\fcs1 \af0 \ltrch\fcs0 \b\insrsid6032001\charrsid12587259 LIMITATION DES DOMMAGES-INT\'c9R\'caTS ET EXCLUSION DE RESPONSABILIT\'c9 POUR LES DOMMAGES.}{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0
\f0\fs24\lang9\langfe1033\langnp9\insrsid6032001\charrsid2838952 }{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid6032001\charrsid12587259 Vous pouvez obtenir de Microsoft et de ses fournisseurs une indemnisation en cas de dommages directs uniquement \'e0
hauteur de 5,00 $ US. Vous ne pouvez pr\'e9tendre \'e0 aucune indemnisation pour les autres dommages, y compris les dommages sp\'e9ciaux, indirects ou accessoires et pertes de b\'e9n\'e9fices.
\par Cette limitation concerne :
\par tout ce qui est reli\'e9 au logiciel, aux services ou au contenu (y compris le code) figurant sur des sites Internet tiers ou dans des programmes tiers ; et
\par les r\'e9clamations au titre de violation de contrat ou de garantie, ou au titre de responsabilit\'e9 stricte, de n\'e9gligence ou d\rquote une autre faute dans la limite autoris\'e9e par la loi en vigueur.
\par Elle s\rquote applique \'e9galement, m\'eame si Microsoft connaissait ou devrait conna\'eetre l\rquote \'e9ventualit\'e9 d\rquote un tel dommage. Si votre pays n\rquote autorise pas l\rquote exclusion ou la limitation de responsabilit\'e9
pour les dommages indirects, accessoires ou de quelque nature que ce soit, il se peut que la limitation ou l\rquote exclusion ci-dessus ne s\rquote appliquera pas \'e0 votre \'e9gard.
\par EFFET JURIDIQUE. Le pr\'e9sent contrat d\'e9crit certains droits juridiques. Vous pourriez avoir d\rquote autres droits pr\'e9vus par les lois de votre pays. Le pr\'e9sent contrat ne modifie pas les droits que vous conf\'e8
rent les lois de votre pays si celles-ci ne le permettent pas.
\par }\pard \ltrpar\ql \li0\ri0\sa160\sl259\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid11088741
\par }{\*\themedata 504b030414000600080000002100e9de0fbfff0000001c020000130000005b436f6e74656e745f54797065735d2e786d6cac91cb4ec3301045f748fc83e52d4a
9cb2400825e982c78ec7a27cc0c8992416c9d8b2a755fbf74cd25442a820166c2cd933f79e3be372bd1f07b5c3989ca74aaff2422b24eb1b475da5df374fd9ad
5689811a183c61a50f98f4babebc2837878049899a52a57be670674cb23d8e90721f90a4d2fa3802cb35762680fd800ecd7551dc18eb899138e3c943d7e503b6
b01d583deee5f99824e290b4ba3f364eac4a430883b3c092d4eca8f946c916422ecab927f52ea42b89a1cd59c254f919b0e85e6535d135a8de20f20b8c12c3b0
0c895fcf6720192de6bf3b9e89ecdbd6596cbcdd8eb28e7c365ecc4ec1ff1460f53fe813d3cc7f5b7f020000ffff0300504b030414000600080000002100a5d6
a7e7c0000000360100000b0000005f72656c732f2e72656c73848fcf6ac3300c87ef85bd83d17d51d2c31825762fa590432fa37d00e1287f68221bdb1bebdb4f
c7060abb0884a4eff7a93dfeae8bf9e194e720169aaa06c3e2433fcb68e1763dbf7f82c985a4a725085b787086a37bdbb55fbc50d1a33ccd311ba548b6309512
0f88d94fbc52ae4264d1c910d24a45db3462247fa791715fd71f989e19e0364cd3f51652d73760ae8fa8c9ffb3c330cc9e4fc17faf2ce545046e37944c69e462
a1a82fe353bd90a865aad41ed0b5b8f9d6fd010000ffff0300504b0304140006000800000021006b799616830000008a0000001c0000007468656d652f746865
6d652f7468656d654d616e616765722e786d6c0ccc4d0ac3201040e17da17790d93763bb284562b2cbaebbf600439c1a41c7a0d29fdbd7e5e38337cedf14d59b
4b0d592c9c070d8a65cd2e88b7f07c2ca71ba8da481cc52c6ce1c715e6e97818c9b48d13df49c873517d23d59085adb5dd20d6b52bd521ef2cdd5eb9246a3d8b
4757e8d3f729e245eb2b260a0238fd010000ffff0300504b030414000600080000002100aa5225dfc60600008b1a0000160000007468656d652f7468656d652f
7468656d65312e786d6cec595d8bdb46147d2ff43f08bd3bfe92fcb1c41b6cd9ceb6d94d42eca4e4716c8fadc98e344633de8d0981923c160aa569e943037deb
43691b48a02fe9afd936a54d217fa17746b63c638fbb9b2585a5640d8b343af7ce997bafce1d4997afdc8fa87384134e58dc708b970aae83e3211b9178d2706f
f7bbb99aeb7081e211a22cc60d778eb97b65f7c30f2ea31d11e2083b601ff31dd4704321a63bf93c1fc230e297d814c7706dcc920809384d26f951828ec16f44
f3a542a1928f10895d274611b8bd311e932176fad2a5bbbb74dea1701a0b2e078634e949d7d8b050d8d1615122f89c0734718e106db830cf881df7f17de13a14
7101171a6e41fdb9f9ddcb79b4b330a2628bad66d7557f0bbb85c1e8b0a4e64c26836c52cff3bd4a33f3af00546ce23ad54ea553c9fc29001a0e61a52917dda7
dfaab7dafe02ab81d2438bef76b55d2e1a78cd7f798373d3973f03af40a97f6f03dfed06104503af4029dedfc07b5eb51478065e81527c65035f2d34db5ed5c0
2b5048497cb8812ef89572b05c6d061933ba6785d77daf5b2d2d9caf50500d5975c929c62c16db6a2d42f758d2058004522448ec88f9148fd110aa3840940c12
e2ec93490885374531e3305c2815ba8532fc973f4f1da988a01d8c346bc90b98f08d21c9c7e1c3844c45c3fd18bcba1ae4cdcb1fdfbc7cee9c3c7a71f2e89793
c78f4f1efd9c3a32acf6503cd1ad5e7fffc5df4f3f75fe7afeddeb275fd9f15cc7fffed367bffdfaa51d082b5d85e0d5d7cffe78f1ecd5379ffff9c3130bbc99
a0810eef930873e73a3e766eb10816a6426032c783e4ed2cfa2122ba45339e701423398bc57f478406fafa1c5164c1b5b019c13b09488c0d787576cf20dc0b93
9920168fd7c2c8001e30465b2cb146e19a9c4b0b737f164fec9327331d770ba123dbdc018a8dfc766653d05662731984d8a07993a258a0098eb170e4357688b1
6575770931e27a408609e36c2c9cbbc46921620d499f0c8c6a5a19ed9108f232b711847c1bb139b8e3b418b5adba8d8f4c24dc15885ac8f73135c27815cd048a
6c2efb28a27ac0f791086d247bf364a8e33a5c40a6279832a733c29cdb6c6e24b05e2de9d7405eec693fa0f3c84426821cda7cee23c674649b1d06218aa6366c
8fc4a18efd881f428922e7261336f80133ef10790e7940f1d674df21d848f7e96a701b9455a7b42a107965965872791533a37e7b733a4658490d08bfa1e71189
4f15f73559f7ff5b5907217df5ed53cbaa2eaaa0371362bda3f6d6647c1b6e5dbc03968cc8c5d7ee369ac53731dc2e9b0decbd74bf976ef77f2fdddbeee7772f
d82b8d06f9965bc574abae36eed1d67dfb9850da13738af7b9daba73e84ca32e0c4a3bf5cc8ab3e7b8690887f24e86090cdc2441cac64998f88488b017a229ec
ef8bae7432e10bd713ee4c19876dbf1ab6fa96783a8b0ed8287d5c2d16e5a3692a1e1c89d578c1cfc6e15143a4e84a75f50896b9576c27ea51794940dabe0d09
6d329344d942a2ba1c9441520fe610340b09b5b277c2a26e615193ee97a9da6001d4b2acc0d6c9810d57c3f53d30012378a242148f649ed2542fb3ab92f92e33
bd2d984605c03e625901ab4cd725d7adcb93ab4b4bed0c99364868e566925091513d8c87688417d52947cf42e36d735d5fa5d4a02743a1e683d25ad1a8d6fe8d
c579730d76ebda40635d2968ec1c37dc4ad9879219a269c31dc3633f1c4653a81d2eb7bc884ee0ddd95024e90d7f1e6599265cb4110fd3802bd149d520220227
0e2551c395cbcfd24063a5218a5bb104827061c9d541562e1a3948ba99643c1ee3a1d0d3ae8dc848a7a7a0f0a95658af2af3f383a5259b41ba7be1e8d819d059
720b4189f9d5a20ce0887078fb534ca33922f03a3313b255fdad35a685eceaef13550da5e3884e43b4e828ba98a77025e5191d7596c5403b5bac1902aa8564d1
080713d960f5a01add34eb1a2987ad5df7742319394d34573dd35015d935ed2a66ccb06c036bb13c5f93d7582d430c9aa677f854bad725b7bed4bab57d42d625
20e059fc2c5df70c0d41a3b69acca026196fcab0d4ecc5a8d93b960b3c85da599a84a6fa95a5dbb5b8653dc23a1d0c9eabf383dd7ad5c2d078b9af549156df3d
f44f136c700fc4a30d2f81675470954af8f09020d810f5d49e24950db845ee8bc5ad0147ce2c210df741c16f7a41c90f72859adfc97965af90abf9cd72aee9fb
e562c72f16daadd243682c228c8a7efacda50bafa2e87cf1e5458d6f7c7d89966fdb2e0d599467eaeb4a5e11575f5f8aa5ed5f5f1c02a2f3a052ead6cbf55625
572f37bb39afddaae5ea41a5956b57826abbdb0efc5abdfbd0758e14d86b9603afd2a9e52ac520c8799582a45fabe7aa5ea9d4f4aacd5ac76b3e5c6c6360e5a9
7c2c6201e155bc76ff010000ffff0300504b0304140006000800000021000dd1909fb60000001b010000270000007468656d652f7468656d652f5f72656c732f
7468656d654d616e616765722e786d6c2e72656c73848f4d0ac2301484f78277086f6fd3ba109126dd88d0add40384e4350d363f2451eced0dae2c082e8761be
9969bb979dc9136332de3168aa1a083ae995719ac16db8ec8e4052164e89d93b64b060828e6f37ed1567914b284d262452282e3198720e274a939cd08a54f980
ae38a38f56e422a3a641c8bbd048f7757da0f19b017cc524bd62107bd5001996509affb3fd381a89672f1f165dfe514173d9850528a2c6cce0239baa4c04ca5b
babac4df000000ffff0300504b01022d0014000600080000002100e9de0fbfff0000001c0200001300000000000000000000000000000000005b436f6e74656e
745f54797065735d2e786d6c504b01022d0014000600080000002100a5d6a7e7c0000000360100000b00000000000000000000000000300100005f72656c732f
2e72656c73504b01022d00140006000800000021006b799616830000008a0000001c00000000000000000000000000190200007468656d652f7468656d652f74
68656d654d616e616765722e786d6c504b01022d0014000600080000002100aa5225dfc60600008b1a00001600000000000000000000000000d6020000746865
6d652f7468656d652f7468656d65312e786d6c504b01022d00140006000800000021000dd1909fb60000001b0100002700000000000000000000000000d00900007468656d652f7468656d652f5f72656c732f7468656d654d616e616765722e786d6c2e72656c73504b050600000000050005005d010000cb0a00000000}
{\*\colorschememapping 3c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d3822207374616e64616c6f6e653d22796573223f3e0d0a3c613a636c724d
617020786d6c6e733a613d22687474703a2f2f736368656d61732e6f70656e786d6c666f726d6174732e6f72672f64726177696e676d6c2f323030362f6d6169
6e22206267313d226c743122207478313d22646b3122206267323d226c743222207478323d22646b322220616363656e74313d22616363656e74312220616363
656e74323d22616363656e74322220616363656e74333d22616363656e74332220616363656e74343d22616363656e74342220616363656e74353d22616363656e74352220616363656e74363d22616363656e74362220686c696e6b3d22686c696e6b2220666f6c486c696e6b3d22666f6c486c696e6b222f3e}
{\*\latentstyles\lsdstimax371\lsdlockeddef0\lsdsemihiddendef0\lsdunhideuseddef0\lsdqformatdef0\lsdprioritydef99{\lsdlockedexcept \lsdqformat1 \lsdpriority0 \lsdlocked0 Normal;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 1;
\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 2;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 3;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 4;
\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 5;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 6;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 7;
\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 8;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 9;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 1;
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 5;
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 6;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 7;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 8;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 9;
\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 1;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 2;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 3;
\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 4;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 5;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 6;
\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 7;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 8;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 9;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Normal Indent;
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 footnote text;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 annotation text;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 header;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 footer;
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index heading;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority35 \lsdlocked0 caption;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 table of figures;
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 envelope address;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 envelope return;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 footnote reference;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 annotation reference;
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 line number;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 page number;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 endnote reference;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 endnote text;
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 table of authorities;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 macro;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 toa heading;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List;
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Bullet;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List 3;
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List 5;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Bullet 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Bullet 3;
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Bullet 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Bullet 5;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number 3;
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number 5;\lsdqformat1 \lsdpriority10 \lsdlocked0 Title;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Closing;
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Signature;\lsdsemihidden1 \lsdunhideused1 \lsdpriority1 \lsdlocked0 Default Paragraph Font;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text Indent;
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Continue;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Continue 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Continue 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Continue 4;
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Continue 5;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Message Header;\lsdqformat1 \lsdpriority11 \lsdlocked0 Subtitle;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Salutation;
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Date;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text First Indent;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text First Indent 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Note Heading;
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text Indent 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text Indent 3;
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Block Text;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Hyperlink;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 FollowedHyperlink;\lsdqformat1 \lsdpriority22 \lsdlocked0 Strong;
\lsdqformat1 \lsdpriority20 \lsdlocked0 Emphasis;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Document Map;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Plain Text;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 E-mail Signature;
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Top of Form;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Bottom of Form;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Normal (Web);\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Acronym;
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Address;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Cite;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Code;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Definition;
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Keyboard;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Preformatted;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Sample;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Typewriter;
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Variable;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 annotation subject;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 No List;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Outline List 1;
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Outline List 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Outline List 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Balloon Text;\lsdpriority39 \lsdlocked0 Table Grid;
\lsdsemihidden1 \lsdlocked0 Placeholder Text;\lsdqformat1 \lsdpriority1 \lsdlocked0 No Spacing;\lsdpriority60 \lsdlocked0 Light Shading;\lsdpriority61 \lsdlocked0 Light List;\lsdpriority62 \lsdlocked0 Light Grid;
\lsdpriority63 \lsdlocked0 Medium Shading 1;\lsdpriority64 \lsdlocked0 Medium Shading 2;\lsdpriority65 \lsdlocked0 Medium List 1;\lsdpriority66 \lsdlocked0 Medium List 2;\lsdpriority67 \lsdlocked0 Medium Grid 1;\lsdpriority68 \lsdlocked0 Medium Grid 2;
\lsdpriority69 \lsdlocked0 Medium Grid 3;\lsdpriority70 \lsdlocked0 Dark List;\lsdpriority71 \lsdlocked0 Colorful Shading;\lsdpriority72 \lsdlocked0 Colorful List;\lsdpriority73 \lsdlocked0 Colorful Grid;\lsdpriority60 \lsdlocked0 Light Shading Accent 1;
\lsdpriority61 \lsdlocked0 Light List Accent 1;\lsdpriority62 \lsdlocked0 Light Grid Accent 1;\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 1;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 1;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 1;
\lsdsemihidden1 \lsdlocked0 Revision;\lsdqformat1 \lsdpriority34 \lsdlocked0 List Paragraph;\lsdqformat1 \lsdpriority29 \lsdlocked0 Quote;\lsdqformat1 \lsdpriority30 \lsdlocked0 Intense Quote;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 1;
\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 1;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 1;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 1;\lsdpriority70 \lsdlocked0 Dark List Accent 1;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 1;
\lsdpriority72 \lsdlocked0 Colorful List Accent 1;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 1;\lsdpriority60 \lsdlocked0 Light Shading Accent 2;\lsdpriority61 \lsdlocked0 Light List Accent 2;\lsdpriority62 \lsdlocked0 Light Grid Accent 2;
\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 2;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 2;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 2;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 2;
\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 2;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 2;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 2;\lsdpriority70 \lsdlocked0 Dark List Accent 2;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 2;
\lsdpriority72 \lsdlocked0 Colorful List Accent 2;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 2;\lsdpriority60 \lsdlocked0 Light Shading Accent 3;\lsdpriority61 \lsdlocked0 Light List Accent 3;\lsdpriority62 \lsdlocked0 Light Grid Accent 3;
\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 3;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 3;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 3;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 3;
\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 3;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 3;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 3;\lsdpriority70 \lsdlocked0 Dark List Accent 3;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 3;
\lsdpriority72 \lsdlocked0 Colorful List Accent 3;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 3;\lsdpriority60 \lsdlocked0 Light Shading Accent 4;\lsdpriority61 \lsdlocked0 Light List Accent 4;\lsdpriority62 \lsdlocked0 Light Grid Accent 4;
\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 4;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 4;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 4;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 4;
\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 4;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 4;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 4;\lsdpriority70 \lsdlocked0 Dark List Accent 4;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 4;
\lsdpriority72 \lsdlocked0 Colorful List Accent 4;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 4;\lsdpriority60 \lsdlocked0 Light Shading Accent 5;\lsdpriority61 \lsdlocked0 Light List Accent 5;\lsdpriority62 \lsdlocked0 Light Grid Accent 5;
\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 5;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 5;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 5;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 5;
\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 5;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 5;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 5;\lsdpriority70 \lsdlocked0 Dark List Accent 5;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 5;
\lsdpriority72 \lsdlocked0 Colorful List Accent 5;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 5;\lsdpriority60 \lsdlocked0 Light Shading Accent 6;\lsdpriority61 \lsdlocked0 Light List Accent 6;\lsdpriority62 \lsdlocked0 Light Grid Accent 6;
\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 6;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 6;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 6;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 6;
\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 6;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 6;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 6;\lsdpriority70 \lsdlocked0 Dark List Accent 6;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 6;
\lsdpriority72 \lsdlocked0 Colorful List Accent 6;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 6;\lsdqformat1 \lsdpriority19 \lsdlocked0 Subtle Emphasis;\lsdqformat1 \lsdpriority21 \lsdlocked0 Intense Emphasis;
\lsdqformat1 \lsdpriority31 \lsdlocked0 Subtle Reference;\lsdqformat1 \lsdpriority32 \lsdlocked0 Intense Reference;\lsdqformat1 \lsdpriority33 \lsdlocked0 Book Title;\lsdsemihidden1 \lsdunhideused1 \lsdpriority37 \lsdlocked0 Bibliography;
\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority39 \lsdlocked0 TOC Heading;\lsdpriority41 \lsdlocked0 Plain Table 1;\lsdpriority42 \lsdlocked0 Plain Table 2;\lsdpriority43 \lsdlocked0 Plain Table 3;\lsdpriority44 \lsdlocked0 Plain Table 4;
\lsdpriority45 \lsdlocked0 Plain Table 5;\lsdpriority40 \lsdlocked0 Grid Table Light;\lsdpriority46 \lsdlocked0 Grid Table 1 Light;\lsdpriority47 \lsdlocked0 Grid Table 2;\lsdpriority48 \lsdlocked0 Grid Table 3;\lsdpriority49 \lsdlocked0 Grid Table 4;
\lsdpriority50 \lsdlocked0 Grid Table 5 Dark;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 1;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 1;
\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 1;\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 1;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 1;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 1;
\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 1;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 2;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 2;\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 2;
\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 2;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 2;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 2;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 2;
\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 3;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 3;\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 3;\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 3;
\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 3;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 3;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 3;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 4;
\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 4;\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 4;\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 4;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 4;
\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 4;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 4;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 5;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 5;
\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 5;\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 5;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 5;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 5;
\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 5;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 6;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 6;\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 6;
\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 6;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 6;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 6;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 6;
\lsdpriority46 \lsdlocked0 List Table 1 Light;\lsdpriority47 \lsdlocked0 List Table 2;\lsdpriority48 \lsdlocked0 List Table 3;\lsdpriority49 \lsdlocked0 List Table 4;\lsdpriority50 \lsdlocked0 List Table 5 Dark;
\lsdpriority51 \lsdlocked0 List Table 6 Colorful;\lsdpriority52 \lsdlocked0 List Table 7 Colorful;\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 1;\lsdpriority47 \lsdlocked0 List Table 2 Accent 1;\lsdpriority48 \lsdlocked0 List Table 3 Accent 1;
\lsdpriority49 \lsdlocked0 List Table 4 Accent 1;\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 1;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 1;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 1;
\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 2;\lsdpriority47 \lsdlocked0 List Table 2 Accent 2;\lsdpriority48 \lsdlocked0 List Table 3 Accent 2;\lsdpriority49 \lsdlocked0 List Table 4 Accent 2;
\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 2;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 2;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 2;\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 3;
\lsdpriority47 \lsdlocked0 List Table 2 Accent 3;\lsdpriority48 \lsdlocked0 List Table 3 Accent 3;\lsdpriority49 \lsdlocked0 List Table 4 Accent 3;\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 3;
\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 3;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 3;\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 4;\lsdpriority47 \lsdlocked0 List Table 2 Accent 4;
\lsdpriority48 \lsdlocked0 List Table 3 Accent 4;\lsdpriority49 \lsdlocked0 List Table 4 Accent 4;\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 4;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 4;
\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 4;\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 5;\lsdpriority47 \lsdlocked0 List Table 2 Accent 5;\lsdpriority48 \lsdlocked0 List Table 3 Accent 5;
\lsdpriority49 \lsdlocked0 List Table 4 Accent 5;\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 5;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 5;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 5;
\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 6;\lsdpriority47 \lsdlocked0 List Table 2 Accent 6;\lsdpriority48 \lsdlocked0 List Table 3 Accent 6;\lsdpriority49 \lsdlocked0 List Table 4 Accent 6;
\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 6;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 6;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 6;}}{\*\datastore 010500000200000018000000
4d73786d6c322e534158584d4c5265616465722e362e3000000000000000000000060000
d0cf11e0a1b11ae1000000000000000000000000000000003e000300feff090006000000000000000000000001000000010000000000000000100000feffffff00000000feffffff0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
fffffffffffffffffdfffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffff52006f006f007400200045006e00740072007900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000500ffffffffffffffffffffffff0c6ad98892f1d411a65f0040963251e5000000000000000000000000a0cf
9cdfe2b8d001feffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000105000000000000}}

Просмотреть файл

@ -1,168 +0,0 @@
using Microsoft.DataTransfer.AzureTableAPIExtension.Data;
namespace Microsoft.DataTransfer.AzureTableAPIExtension.UnitTests.Data
{
[TestClass]
public class AzureTableAPIDataItemExtensionsTests
{
[TestMethod]
public void AzureTableAPIDataItem_GetString_01()
{
var dataitem = new MockDataItem(new Dictionary<string, object>()
{
{ "Name", "Chris" }
});
var entity = dataitem.ToTableEntity(null, null);
Assert.IsTrue(entity.ContainsKey("Name"));
Assert.AreEqual("Chris", entity.GetString("Name"));
}
[TestMethod]
public void AzureTableAPIDataItem_GetInt32_01()
{
var dataitem = new MockDataItem(new Dictionary<string, object>()
{
{ "Number", 123 }
});
var entity = dataitem.ToTableEntity(null, null);
Assert.IsTrue(entity.ContainsKey("Number"));
Assert.AreEqual(123, entity.GetInt32("Number"));
}
[TestMethod]
public void AzureTableAPIDataItem_PartitionKey_Int_01()
{
var dataitem = new MockDataItem(new Dictionary<string, object>()
{
{ "PartitionKey", 123 }
});
var entity = dataitem.ToTableEntity(null, null);
Assert.AreEqual(1, entity.Keys.Count());
Assert.AreEqual("123", entity.PartitionKey);
}
[TestMethod]
public void AzureTableAPIDataItem_PartitionKey_Int_02()
{
var dataitem = new MockDataItem(new Dictionary<string, object>()
{
{ "MyID", 123 }
});
var entity = dataitem.ToTableEntity("MyID", null);
Assert.AreEqual(1, entity.Keys.Count());
Assert.AreEqual("123", entity.PartitionKey);
}
[TestMethod]
public void AzureTableAPIDataItem_PartitionKey_String_01()
{
var dataitem = new MockDataItem(new Dictionary<string, object>()
{
{ "PartitionKey", "WI" }
});
var entity = dataitem.ToTableEntity(null, null);
Assert.AreEqual(1, entity.Keys.Count());
Assert.AreEqual("WI", entity.PartitionKey);
}
[TestMethod]
public void AzureTableAPIDataItem_PartitionKey_String_02()
{
var dataitem = new MockDataItem(new Dictionary<string, object>()
{
{ "MyVal", "WI" }
});
var entity = dataitem.ToTableEntity("MyVal", null);
Assert.AreEqual(1, entity.Keys.Count());
Assert.AreEqual("WI", entity.PartitionKey);
}
[TestMethod]
public void AzureTableAPIDataItem_RowKey_Int_01()
{
var dataitem = new MockDataItem(new Dictionary<string, object>()
{
{ "RowKey", 123 }
});
var entity = dataitem.ToTableEntity(null, null);
Assert.AreEqual(1, entity.Keys.Count());
Assert.AreEqual("123", entity.RowKey);
}
[TestMethod]
public void AzureTableAPIDataItem_RowKey_Int_02()
{
var dataitem = new MockDataItem(new Dictionary<string, object>()
{
{ "MyKey", 123 }
});
var entity = dataitem.ToTableEntity(null, "MyKey");
Assert.AreEqual(1, entity.Keys.Count());
Assert.AreEqual("123", entity.RowKey);
}
[TestMethod]
public void AzureTableAPIDataItem_RowKey_String_01()
{
var dataitem = new MockDataItem(new Dictionary<string, object>()
{
{ "RowKey", "WI" }
});
var entity = dataitem.ToTableEntity(null, null);
Assert.AreEqual(1, entity.Keys.Count());
Assert.AreEqual("WI", entity.RowKey);
}
[TestMethod]
public void AzureTableAPIDataItem_RowKey_String_02()
{
var dataitem = new MockDataItem(new Dictionary<string, object>()
{
{ "MyVal", "WI" }
});
var entity = dataitem.ToTableEntity(null, "MyVal");
Assert.AreEqual(1, entity.Keys.Count());
Assert.AreEqual("WI", entity.RowKey);
}
[TestMethod]
public void AzureTableAPIDataItem_PartitionKey_RowKey_01()
{
var dataitem = new MockDataItem(new Dictionary<string, object>()
{
{ "PartitionKey", "WI" },
{ "RowKey", 123 }
});
var entity = dataitem.ToTableEntity(String.Empty, String.Empty);
Assert.AreEqual(2, entity.Keys.Count());
Assert.AreEqual("WI", entity.PartitionKey);
Assert.AreEqual("123", entity.RowKey);
}
[TestMethod]
public void AzureTableAPIDataItem_PartitionKey_RowKey_02()
{
var dataitem = new MockDataItem(new Dictionary<string, object>()
{
{ "MyVal", "Tailspin" },
{ "ID", 456 }
});
var entity = dataitem.ToTableEntity("MyVal", "ID");
Assert.AreEqual(2, entity.Keys.Count());
Assert.AreEqual("Tailspin", entity.PartitionKey);
Assert.AreEqual("456", entity.RowKey);
}
}
}

Просмотреть файл

@ -1,89 +0,0 @@
using Azure.Data.Tables;
using Microsoft.DataTransfer.AzureTableAPIExtension.Data;
namespace Microsoft.DataTransfer.AzureTableAPIExtension.UnitTests.Data
{
[TestClass]
public class AzureTableAPIDataItemTests
{
[TestMethod]
public void AzureTableAPIDataItem_GetFieldNames_01()
{
var entity = new TableEntity(new Dictionary<string, object>()
{
{ "ID", 1 },
{ "Name", "Chris" },
{ "State", "FL" }
});
var dataitem = new AzureTableAPIDataItem(entity, null, null);
var keys = dataitem.GetFieldNames();
Assert.AreEqual(3, keys.Count());
Assert.IsTrue(keys.Contains("ID"), "Field 'ID' not found");
Assert.IsTrue(keys.Contains("Name"), "Field 'Name' not found");
Assert.IsTrue(keys.Contains("State"), "Field 'State' not found");
}
[TestMethod]
public void AzureTableAPIDataItem_GetFieldNames_02()
{
var entity = new TableEntity(new Dictionary<string, object>()
{
{ "Name", "Chris" }
});
entity.RowKey = "1";
entity.PartitionKey = "FL";
var dataitem = new AzureTableAPIDataItem(entity, null, null);
var keys = dataitem.GetFieldNames();
Assert.AreEqual(3, keys.Count());
Assert.IsTrue(keys.Contains("RowKey"), "Field 'RowKey' not found");
Assert.IsTrue(keys.Contains("PartitionKey"), "Field 'PartitionKey' not found");
Assert.IsTrue(keys.Contains("Name"), "Field 'Name' not found");
}
[TestMethod]
public void AzureTableAPIDataItem_Values_String_01()
{
var entity = new TableEntity(new Dictionary<string, object>()
{
{ "Name", "Chris" }
});
var dataitem = new AzureTableAPIDataItem(entity, null, null);
var keys = dataitem.GetFieldNames();
Assert.AreEqual("Chris", dataitem.GetValue("Name"));
}
[TestMethod]
public void AzureTableAPIDataItem_Values_Int_01()
{
var entity = new TableEntity(new Dictionary<string, object>()
{
{ "ID", 110 }
});
var dataitem = new AzureTableAPIDataItem(entity, null, null);
var keys = dataitem.GetFieldNames();
Assert.AreEqual(110, dataitem.GetValue("ID"));
}
[TestMethod]
public void AzureTableAPIDataItem_Values_Bool_01()
{
var entity = new TableEntity(new Dictionary<string, object>()
{
{ "SomeValue", true }
});
var dataitem = new AzureTableAPIDataItem(entity, null, null);
var keys = dataitem.GetFieldNames();
Assert.IsTrue((bool?)dataitem.GetValue("SomeValue"));
}
}
}

Просмотреть файл

@ -1,24 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.Data.Tables" Version="12.6.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
<PackageReference Include="MSTest.TestAdapter" Version="2.2.8" />
<PackageReference Include="MSTest.TestFramework" Version="2.2.8" />
<PackageReference Include="coverlet.collector" Version="3.1.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\Extensions\AzureTableAPI\Microsoft.DataTransfer.AzureTableAPIExtension\Microsoft.DataTransfer.AzureTableAPIExtension.csproj" />
<ProjectReference Include="..\..\..\Interfaces\Microsoft.DataTransfer.Interfaces\Microsoft.DataTransfer.Interfaces.csproj" />
</ItemGroup>
</Project>

Просмотреть файл

@ -1,24 +0,0 @@
using Microsoft.DataTransfer.Interfaces;
namespace Microsoft.DataTransfer.AzureTableAPIExtension.UnitTests
{
public class MockDataItem : IDataItem
{
public MockDataItem() { this.Data = new Dictionary<string, object>(); }
public MockDataItem(Dictionary<string, object> data)
{
this.Data = data;
}
public Dictionary<string, object> Data;
public IEnumerable<string> GetFieldNames()
{
return this.Data.Keys;
}
public object? GetValue(string fieldName)
{
return this.Data.GetValueOrDefault(fieldName);
}
}
}

Просмотреть файл

@ -1 +0,0 @@
global using Microsoft.VisualStudio.TestTools.UnitTesting;

Просмотреть файл

@ -1,35 +0,0 @@
using Azure.Data.Tables;
using Microsoft.DataTransfer.AzureTableAPIExtension.Data;
using Microsoft.DataTransfer.AzureTableAPIExtension.Settings;
using Microsoft.DataTransfer.Interfaces;
using Microsoft.Extensions.Configuration;
using System.ComponentModel.Composition;
namespace Microsoft.DataTransfer.AzureTableAPIExtension
{
[Export(typeof(IDataSinkExtension))]
public class AzureTableAPIDataSinkExtension : IDataSinkExtension
{
public string DisplayName => "AzureTableAPI";
public async Task WriteAsync(IAsyncEnumerable<IDataItem> dataItems, IConfiguration config, CancellationToken cancellationToken = default)
{
var settings = config.Get<AzureTableAPIDataSinkSettings>();
settings.Validate();
var serviceClient = new TableServiceClient(settings.ConnectionString);
var tableClient = serviceClient.GetTableClient(settings.Table);
await tableClient.CreateIfNotExistsAsync();
var createTasks = new List<Task>();
await foreach(var item in dataItems.WithCancellation(cancellationToken))
{
var entity = item.ToTableEntity(settings.PartitionKeyFieldName, settings.RowKeyFieldName);
createTasks.Add(tableClient.AddEntityAsync(entity));
}
await Task.WhenAll(createTasks);
}
}
}

Просмотреть файл

@ -1,44 +0,0 @@
using Azure;
using Azure.Data.Tables;
using Microsoft.DataTransfer.AzureTableAPIExtension.Data;
using Microsoft.DataTransfer.AzureTableAPIExtension.Settings;
using Microsoft.DataTransfer.Interfaces;
using Microsoft.Extensions.Configuration;
using System.ComponentModel.Composition;
using System.Runtime.CompilerServices;
namespace Microsoft.DataTransfer.AzureTableAPIExtension
{
[Export(typeof(IDataSourceExtension))]
public class AzureTableAPIDataSourceExtension : IDataSourceExtension
{
public string DisplayName => "AzureTableAPI";
public async IAsyncEnumerable<IDataItem> ReadAsync(IConfiguration config, [EnumeratorCancellation] CancellationToken cancellationToken = default)
{
var settings = config.Get<AzureTableAPIDataSourceSettings>();
settings.Validate();
var serviceClient = new TableServiceClient(settings.ConnectionString);
var tableClient = serviceClient.GetTableClient(settings.Table);
//Pageable<TableEntity> queryResultsFilter = tableClient.Query<TableEntity>(filter: $"PartitionKey eq '{partitionKey}'");
AsyncPageable<TableEntity> queryResults;
if (!string.IsNullOrWhiteSpace(settings.QueryFilter)) {
queryResults = tableClient.QueryAsync<TableEntity>(filter: settings.QueryFilter);
} else {
queryResults = tableClient.QueryAsync<TableEntity>();
}
var enumerator = queryResults.GetAsyncEnumerator();
while (await enumerator.MoveNextAsync())
{
yield return new AzureTableAPIDataItem(enumerator.Current, settings.PartitionKeyFieldName, settings.RowKeyFieldName);
}
//do
//{
// yield return new AzureTableAPIDataItem(enumerator.Current, settings.PartitionKeyFieldName, settings.RowKeyFieldName);
//} while (await enumerator.MoveNextAsync());
}
}
}

Просмотреть файл

@ -1,11 +0,0 @@
namespace Microsoft.DataTransfer.AzureTableAPIExtension
{
internal class AzureTableAPIException : Exception
{
public AzureTableAPIException(string message) : base(message)
{ }
public AzureTableAPIException(string message, Exception innerException) : base(message, innerException)
{ }
}
}

Просмотреть файл

@ -1,66 +0,0 @@
using Azure.Data.Tables;
using Microsoft.DataTransfer.Interfaces;
namespace Microsoft.DataTransfer.AzureTableAPIExtension.Data
{
public class AzureTableAPIDataItem : IDataItem
{
public AzureTableAPIDataItem(TableEntity entity, string? partitionKeyFieldName, string? rowKeyFieldName)
{
if (entity == null)
{
throw new ArgumentNullException("entity");
}
this.Entity = entity;
this.PartitionKeyFieldName = partitionKeyFieldName;
this.RowKeyFieldName = rowKeyFieldName;
}
public TableEntity Entity { get; private set; }
public string? PartitionKeyFieldName { get; private set; }
public string? RowKeyFieldName { get; private set; }
public IEnumerable<string> GetFieldNames()
{
var keys = Entity.Keys.ToList();
if (!string.IsNullOrWhiteSpace(this.PartitionKeyFieldName))
{
keys.Remove("PartitionKey");
keys.Add(this.PartitionKeyFieldName);
}
if (!string.IsNullOrWhiteSpace(this.RowKeyFieldName))
{
keys.Remove("RowKey");
keys.Add(this.RowKeyFieldName);
}
return keys;
}
public object? GetValue(string fieldName)
{
try
{
if (!string.IsNullOrWhiteSpace(this.PartitionKeyFieldName) && fieldName.Equals(this.PartitionKeyFieldName, StringComparison.InvariantCultureIgnoreCase))
{
return Entity.PartitionKey;
}
else if (!string.IsNullOrWhiteSpace(this.RowKeyFieldName) && fieldName.Equals(this.RowKeyFieldName, StringComparison.InvariantCultureIgnoreCase))
{
return Entity.RowKey;
}
return Entity[fieldName];
}
catch (Exception ex)
{
throw new AzureTableAPIException($"Error parsing field '${fieldName}'", ex);
}
}
}
}

Просмотреть файл

@ -1,45 +0,0 @@
using Azure.Data.Tables;
using Microsoft.DataTransfer.Interfaces;
namespace Microsoft.DataTransfer.AzureTableAPIExtension.Data
{
public static class AzureTableAPIDataItemExtensions
{
public static TableEntity ToTableEntity(this IDataItem item, string? PartitionKeyFieldName, string? RowKeyFieldName)
{
var entity = new TableEntity();
var partitionKeyFieldNameToUse = "PartitionKey";
if (!string.IsNullOrWhiteSpace(PartitionKeyFieldName))
{
partitionKeyFieldNameToUse = PartitionKeyFieldName;
}
var rowKeyFieldNameToUse = "RowKey";
if (!string.IsNullOrWhiteSpace(RowKeyFieldName))
{
rowKeyFieldNameToUse = RowKeyFieldName;
}
foreach (var key in item.GetFieldNames())
{
if (key.Equals(partitionKeyFieldNameToUse, StringComparison.InvariantCultureIgnoreCase))
{
var partitionKey = item.GetValue(key)?.ToString();
entity.PartitionKey = partitionKey;
}
else if (key.Equals(rowKeyFieldNameToUse, StringComparison.InvariantCultureIgnoreCase))
{
var rowKey = item.GetValue(key)?.ToString();
entity.RowKey = rowKey;
}
else
{
entity.Add(key, item.GetValue(key));
}
}
return entity;
}
}
}

Просмотреть файл

@ -1,24 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<OutputType>Exe</OutputType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.Data.Tables" Version="12.6.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="6.0.0" />
<PackageReference Include="System.ComponentModel.Composition" Version="6.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\Interfaces\Microsoft.DataTransfer.Interfaces\Microsoft.DataTransfer.Interfaces.csproj" />
</ItemGroup>
<Target Name="PublishDebug" AfterTargets="Build" Condition=" '$(Configuration)' == 'Debug' ">
<Exec Command="dotnet publish --no-build -p:PublishProfile=LocalDebugFolder" />
</Target>
</Project>

Просмотреть файл

@ -1 +0,0 @@
Console.WriteLine();

Просмотреть файл

@ -1,15 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project>
<PropertyGroup>
<Configuration>Debug</Configuration>
<Platform>Any CPU</Platform>
<PublishDir>..\..\..\Core\Microsoft.DataTransfer.Core\bin\Debug\net6.0\Extensions</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<_TargetId>Folder</_TargetId>
<TargetFramework>net6.0</TargetFramework>
<SelfContained>false</SelfContained>
</PropertyGroup>
</Project>

Просмотреть файл

@ -1,6 +0,0 @@
namespace Microsoft.DataTransfer.AzureTableAPIExtension.Settings
{
public class AzureTableAPIDataSinkSettings : AzureTableAPISettingsBase
{
}
}

Просмотреть файл

@ -1,7 +0,0 @@
namespace Microsoft.DataTransfer.AzureTableAPIExtension.Settings
{
public class AzureTableAPIDataSourceSettings : AzureTableAPISettingsBase
{
public string? QueryFilter { get; set; }
}
}

Просмотреть файл

@ -1,30 +0,0 @@
using Microsoft.DataTransfer.Interfaces;
using System.ComponentModel.DataAnnotations;
namespace Microsoft.DataTransfer.AzureTableAPIExtension.Settings
{
public abstract class AzureTableAPISettingsBase : IDataExtensionSettings
{
/// <summary>
/// The Connection String.
/// </summary>
[Required]
public string? ConnectionString { get; set; }
/// <summary>
/// The Table name.
/// </summary>
[Required]
public string? Table { get; set; }
/// <summary>
/// The field name to translate the RowKey from Table Entities to. (Optional)
/// </summary>
public string? RowKeyFieldName { get; set; }
/// <summary>
/// The field name to translate the PartitionKey from Table Entities to. (Optional)
/// </summary>
public string? PartitionKeyFieldName { get; set; }
}
}

Просмотреть файл

@ -1,54 +0,0 @@
# AzureTableAPI Extension
This extension is built to facilitate both a data Source and Sink for the migration tool to be able to read and write to Azure Table API. This covers both the Azure Storage Table API and Azure Cosmos DB Table API, since they both adhere to the same API spec.
## Configuration Settings
The AzureTableAPI has a couple required and optional settings for configuring the connection to the Table API you are connecting to. This applies to both Azure Storage Table API and Azure Cosmos DB Table API.
The following are the required settings that must be defined for using either the data Source or Sink:
- `ConnectionString` - This defines the Table API Connection String used for connecting to and authenticating with the Table API service. For example, this will contain the name of the Azure Storage Account and the Account Key for connecting to the Table API on the service. This is required.
- `Table` - This defines the name of the Table to connect to on the Table API service. Such as the name of the Azure Storage Table. This is required.
There are also a couple optional settings that can be configured on the AzureTableAPI to help with mapping data between the Source and Sink:
- `RowKeyFieldName` - This is used to specify a different field name when mapping data to / from the `RowKey` field of Azure Table API. Optional.
- `PartitionKeyFieldName` - This is used to specify a different field name when mapping data to / from the `PartitionKey` field of Azure Table API. Optional.
In the Azure Table API, the `RowKey` and `PartitionKey` are required fields on the entities storage in a Table. When performing mapping of data between Azure Table API and Cosmos DB (or some other data store), you may be required to use a different field name in the other data store than these names as required by the Azure Table API. The `RowKeyFieldName` and `PartitionKeyFieldName` enables these fields to be mapped to / from a custom field name that matches your data requirements. If these settings are not specified, then these fields will not be renamed in the data mapping and will remain as they are in the Azure Table API.
### Additional Source Settings
The AzureTableAPI Source extension has an additional setting that can be configured for helping with querying data.
The following setting is supported for the Source:
- `QueryFilter` - This enables you to specify an OData filter to be applied to the data being retrieved by the AzureTableAPI Source. This is used in cases where only a subset of data from the source Table is needed in the migration. Example usage to query a subset of entities from the source table: `PartitionKey eq 'foo'`.
## Example Source and Sink Settings Usage
The following are a couple example `settings.json` files for configuring the AzureTableAPI Source and Sink extensions.
**AzureTableAPISourceSettings.json**
```json
{
"ConnectionString": "DefaultEndpointsProtocol=https;AccountName=<storage-account-name>;AccountKey=<key>;EndpointSuffix=core.windows.net",
"Table": "SourceTable1",
"PartitionKeyFieldName": "State",
"RowKeyFieldName": "id",
"QueryFilter": "PartitionKey eq 'WI'"
}
```
**AzureTableAPISinkSettings.json**
```json
{
"ConnectionString": "DefaultEndpointsProtocol=https;AccountName=<storage-account-name>;AccountKey=<key>;EndpointSuffix=core.windows.net",
"Table": "DestinationTable1",
"PartitionKeyFieldName": "State",
"RowKeyFieldName": "id"
}
```

Просмотреть файл

@ -1,91 +0,0 @@
using Microsoft.DataTransfer.Interfaces;
using Newtonsoft.Json.Linq;
namespace Microsoft.DataTransfer.CosmosExtension.UnitTests
{
[TestClass]
public class CosmosDictionaryDataItemTests
{
[TestMethod]
public async Task GetFieldNames_WithFlatObject_ReportsCorrectNames()
{
const string fileIn = "Data/IdName.json";
var json = JObject.Parse(await File.ReadAllTextAsync(fileIn));
var item = new CosmosDictionaryDataItem(json.ToObject<Dictionary<string, object?>>());
var fields = item.GetFieldNames().ToList();
Assert.AreEqual(2, fields.Count);
CollectionAssert.Contains(fields, "id");
CollectionAssert.Contains(fields, "name");
}
[TestMethod]
public async Task GetValue_WithFlatObject_ReturnsValidValues()
{
const string fileIn = "Data/IdName.json";
var json = JObject.Parse(await File.ReadAllTextAsync(fileIn));
var item = new CosmosDictionaryDataItem(json.ToObject<Dictionary<string, object?>>());
Assert.AreEqual(1L, item.GetValue("id"));
Assert.AreEqual("One", item.GetValue("name"));
}
[TestMethod]
public async Task GetFieldNames_WithNestedObject_ReportsParentAndChildNames()
{
const string fileIn = "Data/Nested.json";
var json = JObject.Parse(await File.ReadAllTextAsync(fileIn));
var item = new CosmosDictionaryDataItem(json.ToObject<Dictionary<string, object?>>());
var fields = item.GetFieldNames().ToList();
Assert.AreEqual(3, fields.Count);
CollectionAssert.Contains(fields, "id");
CollectionAssert.Contains(fields, "name");
CollectionAssert.Contains(fields, "child");
var child = item.GetValue("child") as IDataItem;
Assert.IsNotNull(child);
var childFields = child.GetFieldNames().ToList();
Assert.AreEqual(2, childFields.Count);
CollectionAssert.Contains(childFields, "type");
CollectionAssert.Contains(childFields, "data");
}
[TestMethod]
public async Task GetValue_WithMixedValueTypes_ReturnsValidTypedValues()
{
const string fileIn = "Data/MixedTypes.json";
var json = JObject.Parse(await File.ReadAllTextAsync(fileIn));
var item = new CosmosDictionaryDataItem(json.ToObject<Dictionary<string, object?>>());
Assert.AreEqual(2L, item.GetValue("id"));
Assert.AreEqual("Matt", item.GetValue("name"));
object? arrayValue = item.GetValue("otherNames");
var array = arrayValue as IEnumerable<object>;
Assert.IsNotNull(array);
Assert.AreEqual(3, array.Count());
CollectionAssert.DoesNotContain(array.Select(a => a is string).ToList(), false);
object? mixedArrayValue = item.GetValue("mixed");
var mixedArray = mixedArrayValue as IEnumerable<object>;
Assert.IsNotNull(mixedArray);
Assert.AreEqual(5, mixedArray.Count());
Assert.AreEqual(1L, mixedArray.ElementAt(0));
Assert.AreEqual(true, mixedArray.ElementAt(1));
Assert.AreEqual(3L, mixedArray.ElementAt(2));
Assert.AreEqual("four", mixedArray.ElementAt(3));
Assert.IsInstanceOfType(mixedArray.ElementAt(4), typeof(IDataItem));
}
}
}

Просмотреть файл

@ -1,4 +0,0 @@
{
"id": 1,
"name": "One"
}

Просмотреть файл

@ -1,19 +0,0 @@
{
"id": 2,
"name": "Matt",
"otherNames": [
"One",
"Two",
"Three"
],
"mixed": [
1,
true,
3,
"four",
{
"letter": "E",
"number": 6
}
]
}

Просмотреть файл

@ -1,8 +0,0 @@
{
"id": 1,
"name": "One",
"child": {
"type": "Key",
"data": "Value"
}
}

Просмотреть файл

@ -1,36 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration" Version="6.0.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
<PackageReference Include="MSTest.TestAdapter" Version="2.2.8" />
<PackageReference Include="MSTest.TestFramework" Version="2.2.8" />
<PackageReference Include="coverlet.collector" Version="3.1.2" />
<PackageReference Include="System.Linq.Async" Version="6.0.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Microsoft.DataTransfer.CosmosExtension\Microsoft.DataTransfer.CosmosExtension.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="Data\Nested.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Data\IdName.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Data\MixedTypes.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

Просмотреть файл

@ -1 +0,0 @@
global using Microsoft.VisualStudio.TestTools.UnitTesting;

Просмотреть файл

@ -1,145 +0,0 @@
using System.ComponentModel.Composition;
using System.Diagnostics;
using System.Dynamic;
using Microsoft.Azure.Cosmos;
using Microsoft.DataTransfer.Interfaces;
using Microsoft.Extensions.Configuration;
using Polly;
using Polly.Retry;
namespace Microsoft.DataTransfer.CosmosExtension
{
[Export(typeof(IDataSinkExtension))]
public class CosmosDataSinkExtension : IDataSinkExtension
{
public string DisplayName => "Cosmos";
public async Task WriteAsync(IAsyncEnumerable<IDataItem> dataItems, IConfiguration config, CancellationToken cancellationToken = default)
{
var settings = config.Get<CosmosSinkSettings>();
settings.Validate();
var client = new CosmosClient(settings.ConnectionString,
new CosmosClientOptions
{
ConnectionMode = ConnectionMode.Gateway,
AllowBulkExecution = true
});
Database database = await client.CreateDatabaseIfNotExistsAsync(settings.Database, cancellationToken: cancellationToken);
if (settings.RecreateContainer)
{
try
{
await database.GetContainer(settings.Container).DeleteContainerAsync(cancellationToken: cancellationToken);
}
catch { }
}
Container? container = await database.CreateContainerIfNotExistsAsync(settings.Container, settings.PartitionKeyPath, cancellationToken: cancellationToken);
int insertCount = 0;
var timer = Stopwatch.StartNew();
void ReportCount(int i)
{
insertCount += i;
if (insertCount % 500 == 0)
{
Console.WriteLine($"{insertCount} records added after {timer.ElapsedMilliseconds / 1000.0:F2}s");
}
}
var convertedObjects = dataItems.Select(di => BuildObject(di, true)).Where(o => o != null).OfType<ExpandoObject>();
var batches = convertedObjects.Buffer(settings.BatchSize);
var retry = GetRetryPolicy();
await foreach (var batch in batches.WithCancellation(cancellationToken))
{
var insertTasks = batch.Select(item => InsertItemAsync(container, item, retry, cancellationToken)).ToList();
var results = await Task.WhenAll(insertTasks);
ReportCount(results.Sum());
}
Console.WriteLine($"Added {insertCount} total records in {timer.ElapsedMilliseconds / 1000.0:F2}s");
}
private static AsyncRetryPolicy GetRetryPolicy()
{
const int retryCount = 5;
const int retryDelayBaseMs = 100;
var jitter = new Random();
var retryPolicy = Policy
.Handle<CosmosException>(c => c.StatusCode == System.Net.HttpStatusCode.TooManyRequests)
.WaitAndRetryAsync(retryCount,
retryAttempt => TimeSpan.FromMilliseconds(Math.Pow(2, retryAttempt) * retryDelayBaseMs + jitter.Next(0, retryDelayBaseMs))
);
return retryPolicy;
}
private static Task<int> InsertItemAsync(Container container, ExpandoObject item, AsyncRetryPolicy retryPolicy, CancellationToken cancellationToken)
{
var task = retryPolicy.ExecuteAsync(() => container.CreateItemAsync(item, cancellationToken: cancellationToken))
.ContinueWith(t =>
{
if (t.IsCompletedSuccessfully)
{
return 1;
}
if (t.IsFaulted)
{
Console.WriteLine($"Error adding record: {t.Exception?.Message}");
}
return 0;
}, cancellationToken);
return task;
}
private static ExpandoObject? BuildObject(IDataItem? source, bool requireStringId = false)
{
if (source == null)
return null;
var fields = source.GetFieldNames().ToList();
var item = new ExpandoObject();
if (requireStringId && !fields.Contains("id", StringComparer.CurrentCultureIgnoreCase))
{
item.TryAdd("id", Guid.NewGuid().ToString());
}
foreach (string field in fields)
{
object? value = source.GetValue(field);
var fieldName = field;
if (string.Equals(field, "id", StringComparison.CurrentCultureIgnoreCase) && requireStringId)
{
value = value?.ToString();
fieldName = "id";
}
else if (value is IDataItem child)
{
value = BuildObject(child);
}
else if (value is IEnumerable<object?> array)
{
value = array.Select(dataItem =>
{
if (dataItem is IDataItem childObject)
{
return BuildObject(childObject);
}
return dataItem;
}).ToArray();
}
item.TryAdd(fieldName, value);
}
return item;
}
}
}

Просмотреть файл

@ -1,63 +0,0 @@
using System.ComponentModel.Composition;
using System.Runtime.CompilerServices;
using Microsoft.Azure.Cosmos;
using Microsoft.DataTransfer.Interfaces;
using Microsoft.Extensions.Configuration;
using System;
namespace Microsoft.DataTransfer.CosmosExtension
{
[Export(typeof(IDataSourceExtension))]
public class CosmosDataSourceExtension : IDataSourceExtension
{
public string DisplayName => "Cosmos";
public async IAsyncEnumerable<IDataItem> ReadAsync(IConfiguration config, [EnumeratorCancellation] CancellationToken cancellationToken = default)
{
var settings = config.Get<CosmosSourceSettings>();
settings.Validate();
var client = new CosmosClient(settings.ConnectionString,
new CosmosClientOptions
{
ConnectionMode = ConnectionMode.Gateway,
AllowBulkExecution = true
});
var container = client.GetContainer(settings.Database, settings.Container);
var requestOptions = new QueryRequestOptions();
if (!string.IsNullOrEmpty(settings.PartitionKey))
{
requestOptions.PartitionKey = new PartitionKey(settings.PartitionKey);
}
Console.WriteLine($"Reading from {settings.Database}.{settings.Container}");
using FeedIterator<Dictionary<string, object?>> feedIterator = GetFeedIterator<Dictionary<string, object?>>(settings, container, requestOptions);
while (feedIterator.HasMoreResults)
{
foreach (var item in await feedIterator.ReadNextAsync(cancellationToken))
{
if (!settings.IncludeMetadataFields)
{
var corePropertiesOnly = new Dictionary<string, object?>(item.Where(kvp => !kvp.Key.StartsWith("_")));
yield return new CosmosDictionaryDataItem(corePropertiesOnly);
}
else
{
yield return new CosmosDictionaryDataItem(item);
}
}
}
}
private static FeedIterator<T> GetFeedIterator<T>(CosmosSourceSettings settings, Container container, QueryRequestOptions requestOptions)
{
if (string.IsNullOrWhiteSpace(settings.Query))
{
return container.GetItemQueryIterator<T>(requestOptions: requestOptions);
}
return container.GetItemQueryIterator<T>(settings.Query, requestOptions: requestOptions);
}
}
}

Просмотреть файл

@ -1,44 +0,0 @@
using Microsoft.DataTransfer.Interfaces;
using Newtonsoft.Json.Linq;
namespace Microsoft.DataTransfer.CosmosExtension
{
public class CosmosDictionaryDataItem : IDataItem
{
public IDictionary<string, object?> Items { get; }
public CosmosDictionaryDataItem(IDictionary<string, object?> items)
{
Items = items;
}
public IEnumerable<string> GetFieldNames()
{
return Items.Keys;
}
public object? GetValue(string fieldName)
{
if (!Items.TryGetValue(fieldName, out var value))
{
return null;
}
return GetChildObject(value);
}
private static object? GetChildObject(object? value)
{
if (value is JObject element)
{
return new CosmosDictionaryDataItem(element.ToObject<IDictionary<string, object?>>().ToDictionary(k => k.Key, v => v.Value));
}
if (value is JArray array)
{
return array.ToObject<List<object?>>().Select(GetChildObject).ToList();
}
return value;
}
}
}

Просмотреть файл

@ -1,19 +0,0 @@
using Microsoft.DataTransfer.Interfaces;
using System.ComponentModel.DataAnnotations;
namespace Microsoft.DataTransfer.CosmosExtension
{
public class CosmosSinkSettings : IDataExtensionSettings
{
[Required]
public string? ConnectionString { get; set; }
[Required]
public string? Database { get; set; }
[Required]
public string? Container { get; set; }
[Required]
public string? PartitionKeyPath { get; set; }
public bool RecreateContainer { get; set; }
public int BatchSize { get; set; } = 100;
}
}

Просмотреть файл

@ -1,21 +0,0 @@
using Microsoft.DataTransfer.Interfaces;
using System.ComponentModel.DataAnnotations;
namespace Microsoft.DataTransfer.CosmosExtension
{
public class CosmosSourceSettings : IDataExtensionSettings
{
[Required]
public string? ConnectionString { get; set; }
[Required]
public string? Database { get; set; }
[Required]
public string? Container { get; set; }
public string? PartitionKey { get; set; }
public string? Query { get; set; }
public bool IncludeMetadataFields { get; set; }
}
}

Просмотреть файл

@ -1,28 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<OutputType>Exe</OutputType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Azure.Cosmos" Version="3.29.0" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="6.0.0" />
<PackageReference Include="Polly" Version="7.2.3" />
<PackageReference Include="System.ComponentModel.Composition" Version="6.0.0" />
<PackageReference Include="System.Interactive.Async" Version="6.0.1" />
<PackageReference Include="System.Linq.Async" Version="6.0.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\Interfaces\Microsoft.DataTransfer.Interfaces\Microsoft.DataTransfer.Interfaces.csproj" />
</ItemGroup>
<Target Name="PublishDebug" AfterTargets="Build" Condition=" '$(Configuration)' == 'Debug' ">
<Exec Command="dotnet publish --no-build -p:PublishProfile=LocalDebugFolder" />
</Target>
</Project>

Просмотреть файл

@ -1 +0,0 @@
Console.WriteLine();

Просмотреть файл

@ -1,15 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project>
<PropertyGroup>
<Configuration>Debug</Configuration>
<Platform>Any CPU</Platform>
<PublishDir>..\..\..\Core\Microsoft.DataTransfer.Core\bin\Debug\net6.0\Extensions</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<_TargetId>Folder</_TargetId>
<TargetFramework>net6.0</TargetFramework>
<SelfContained>false</SelfContained>
</PropertyGroup>
</Project>

Просмотреть файл

@ -1,38 +0,0 @@
# Cosmos Extension
The Cosmos data transfer extension provides source and sink capabilities for reading from and writing to containers in Cosmos DB using the Core (SQL) API. Source and sink both support string, number, and boolean property values, arrays, and hierarchical nested object structures.
## Settings
Source and sink settings both require multiple parameters to specify and provide access to the data location within a Cosmos DB account:
- `ConnectionString`
- `Database`
- `Container`
Source supports an optional `IncludeMetadataFields` parameter (`false` by default) to enable inclusion of built-in Cosmos fields prefixed with `"_"`, for example `"_etag"` and `"_ts"`.
### Source
```json
"CosmosSourceSettings": {
"ConnectionString": "AccountEndpoint=https://...",
"Database":"myDb",
"Container":"myContainer",
"IncludeMetadataFields": false
}
```
Sink requires an additional `PartitionKeyPath` parameter which is used when creating the container if it does not exist. It also supports an optional `RecreateContainer` parameter (`false` by default) to delete and then recreate the container to ensure only newly imported data is present. The optional `BatchSize` parameter (100 by default) sets the number of items to accumulate before inserting.
### Sink
```json
"CosmosSinkSettings": {
"ConnectionString": "AccountEndpoint=https://...",
"Database":"myDb",
"Container":"myContainer",
"PartitionKeyPath":"/id",
"RecreateContainer": false,
"BatchSize": 100
}
```

Просмотреть файл

@ -1,10 +0,0 @@
[
{
"id": 1,
"name": "One"
},
{
"id": 2,
"name": "Two"
}
]

Просмотреть файл

@ -1,14 +0,0 @@
[
{
"id": 3,
"name": "Three"
},
{
"id": 4,
"name": "Four"
},
{
"id": 5,
"name": "Five"
}
]

Просмотреть файл

@ -1,51 +0,0 @@
[
{
"id": 1,
"name": "John",
"level2": {
"id": 4324,
"location": "here"
},
"itemsNested": [
{
"number": "one",
"count": 3
},
{
"number": "two",
"count": 7
},
{
"number": "three",
"count": 2
}
]
},
{
"id": 2,
"name": "Matt",
"otherNames": [
"One",
"Two",
"Three"
],
"mixed": [
1,
true,
3,
"four",
{
"letter": "E",
"number": 6
}
]
},
{
"noId": 9,
"message": "Needs generated id"
},
{
"id": 3,
"description": "Hello JSON"
}
]

Просмотреть файл

@ -1,4 +0,0 @@
{
"id": 1,
"name": "One"
}

Просмотреть файл

@ -1,14 +0,0 @@
[
{
"id": 3,
"name": "Three"
},
{
"id": 4,
"name": "Four"
},
{
"id": 5,
"name": "Five"
}
]

Просмотреть файл

@ -1,4 +0,0 @@
{
"id": 2,
"name": "Two"
}

Просмотреть файл

@ -1,34 +0,0 @@
[
{
"id": 1,
"name": "One",
"child": {
"type": "Key",
"data": "Value"
}
},
{
"id": 2,
"name": "Two",
"child": {
"type": "Key",
"data": "Text"
}
},
{
"id": 3,
"name": "Three",
"child": {
"type": "Key",
"data": "String"
}
},
{
"id": 4,
"name": "Four",
"child": {
"type": "Key",
"data": "Number"
}
}
]

Просмотреть файл

@ -1,18 +0,0 @@
[
{
"id": 1,
"name": "One"
},
{
"id": 2,
"name": "Two"
},
{
"id": 3,
"name": "Three"
},
{
"id": 4,
"name": "Four"
}
]

Просмотреть файл

@ -1,4 +0,0 @@
{
"id": 1,
"name": "One"
}

Просмотреть файл

@ -1,4 +0,0 @@
{
"id": 1,
"name": "One"
}

Просмотреть файл

@ -1,4 +0,0 @@
{
"id": 2,
"name": "Two"
}

Просмотреть файл

@ -1,4 +0,0 @@
{
"id": 3,
"name": "Three"
}

Просмотреть файл

@ -1,4 +0,0 @@
{
"id": 4,
"name": "Four"
}

Просмотреть файл

@ -1,59 +0,0 @@
using Newtonsoft.Json.Linq;
namespace Microsoft.DataTransfer.JsonExtension.UnitTests
{
[TestClass]
public class JsonRoundTripTests
{
[TestMethod]
public async Task WriteAsync_fromReadAsync_ProducesIdenticalFile()
{
var input = new JsonDataSourceExtension();
var output = new JsonDataSinkExtension();
const string fileIn = "Data/ArraysTypesNesting.json";
const string fileOut = $"{nameof(WriteAsync_fromReadAsync_ProducesIdenticalFile)}_out.json";
var sourceConfig = TestHelpers.CreateConfig(new Dictionary<string, string>
{
{ "FilePath", fileIn }
});
var sinkConfig = TestHelpers.CreateConfig(new Dictionary<string, string>
{
{ "FilePath", fileOut },
{ "Indented", "true" },
});
await output.WriteAsync(input.ReadAsync(sourceConfig), sinkConfig);
bool areEqual = JToken.DeepEquals(JToken.Parse(await File.ReadAllTextAsync(fileIn)), JToken.Parse(await File.ReadAllTextAsync(fileOut)));
Assert.IsTrue(areEqual);
}
[TestMethod]
public async Task WriteAsync_fromFolderReadAsync_ProducesExpectedCombinedFile()
{
var input = new JsonDataSourceExtension();
var output = new JsonDataSinkExtension();
const string fileIn = "Data/SingleObjects";
const string fileCompare = "Data/SimpleIdName.json";
const string fileOut = $"{nameof(WriteAsync_fromFolderReadAsync_ProducesExpectedCombinedFile)}_out.json";
var sourceConfig = TestHelpers.CreateConfig(new Dictionary<string, string>
{
{ "FilePath", fileIn }
});
var sinkConfig = TestHelpers.CreateConfig(new Dictionary<string, string>
{
{ "FilePath", fileOut },
{ "Indented", "true" },
});
await output.WriteAsync(input.ReadAsync(sourceConfig), sinkConfig);
bool areEqual = JToken.DeepEquals(JToken.Parse(await File.ReadAllTextAsync(fileCompare)), JToken.Parse(await File.ReadAllTextAsync(fileOut)));
Assert.IsTrue(areEqual);
}
}
}

Просмотреть файл

@ -1,53 +0,0 @@
using Microsoft.DataTransfer.Interfaces;
using Newtonsoft.Json;
namespace Microsoft.DataTransfer.JsonExtension.UnitTests
{
[TestClass]
public class JsonSinkTests
{
[TestMethod]
public async Task WriteAsync_WithFlatObjects_WritesToValidFile()
{
var sink = new JsonDataSinkExtension();
var data = new List<DictionaryDataItem>
{
new(new Dictionary<string, object?>
{
{ "Id", 1 },
{ "Name", "One" },
}),
new(new Dictionary<string, object?>
{
{ "Id", 2 },
{ "Name", "Two" },
}),
new(new Dictionary<string, object?>
{
{ "Id", 3 },
{ "Name", "Three" },
}),
};
string outputFile = $"{DateTime.Now:yy-MM-dd}_Output.json";
var config = TestHelpers.CreateConfig(new Dictionary<string, string>
{
{ "FilePath", outputFile }
});
await sink.WriteAsync(data.ToAsyncEnumerable(), config);
var outputData = JsonConvert.DeserializeObject<List<TestDataObject>>(await File.ReadAllTextAsync(outputFile));
Assert.IsTrue(outputData.Any(o => o.Id == 1 && o.Name == "One"));
Assert.IsTrue(outputData.Any(o => o.Id == 2 && o.Name == "Two"));
Assert.IsTrue(outputData.Any(o => o.Id == 3 && o.Name == "Three"));
}
}
public class TestDataObject
{
public int Id { get; set; }
public string? Name { get; set; }
}
}

Просмотреть файл

@ -1,140 +0,0 @@
using Microsoft.DataTransfer.Interfaces;
namespace Microsoft.DataTransfer.JsonExtension.UnitTests
{
[TestClass]
public class JsonSourceTests
{
[TestMethod]
public async Task ReadAsync_WithFlatObjects_ReadsValues()
{
var extension = new JsonDataSourceExtension();
var config = TestHelpers.CreateConfig(new Dictionary<string, string>
{
{ "FilePath", "Data/SimpleIdName.json" }
});
await foreach (var dataItem in extension.ReadAsync(config))
{
CollectionAssert.AreEquivalent(new[] { "id", "name" }, dataItem.GetFieldNames().ToArray());
Assert.IsNotNull(dataItem.GetValue("id"));
Assert.IsNotNull(dataItem.GetValue("name"));
}
}
[TestMethod]
public async Task ReadAsync_WithNestedObjects_ReadsValues()
{
var extension = new JsonDataSourceExtension();
var config = TestHelpers.CreateConfig(new Dictionary<string, string>
{
{ "FilePath", "Data/NestedObjects.json" }
});
await foreach (var dataItem in extension.ReadAsync(config))
{
if (dataItem.GetValue("child") is IDataItem child)
{
CollectionAssert.AreEquivalent(new[] { "type", "data" }, child.GetFieldNames().ToArray());
Assert.IsNotNull(child.GetValue("type"));
Assert.IsNotNull(child.GetValue("data"));
}
else
{
Assert.Fail();
}
}
}
[TestMethod]
public async Task ReadAsync_WithSingleObjectFile_ReadsValues()
{
var extension = new JsonDataSourceExtension();
var config = TestHelpers.CreateConfig(new Dictionary<string, string>
{
{ "FilePath", "Data/SingleObject.json" }
});
int counter = 0;
await foreach (var dataItem in extension.ReadAsync(config))
{
counter++;
CollectionAssert.AreEquivalent(new[] { "id", "name" }, dataItem.GetFieldNames().ToArray());
Assert.IsInstanceOfType(dataItem.GetValue("id"), typeof(double));
Assert.IsNotNull(dataItem.GetValue("name"));
}
Assert.AreEqual(1, counter);
}
[TestMethod]
public async Task ReadAsync_WithSingleObjectsFolder_ReadsValuesInOrder()
{
var extension = new JsonDataSourceExtension();
var config = TestHelpers.CreateConfig(new Dictionary<string, string>
{
{ "FilePath", "Data/SingleObjects" }
});
int counter = 0;
double lastId = -1;
await foreach (var dataItem in extension.ReadAsync(config))
{
counter++;
CollectionAssert.AreEquivalent(new[] { "id", "name" }, dataItem.GetFieldNames().ToArray());
object? value = dataItem.GetValue("id");
Assert.IsInstanceOfType(value, typeof(double));
Assert.IsNotNull(dataItem.GetValue("name"));
var current = (double?)value ?? int.MaxValue;
Assert.IsTrue(current > lastId);
lastId = current;
}
Assert.AreEqual(4, counter);
}
[TestMethod]
public async Task ReadAsync_WithArraysFolder_ReadsValues()
{
var extension = new JsonDataSourceExtension();
var config = TestHelpers.CreateConfig(new Dictionary<string, string>
{
{ "FilePath", "Data/Arrays" }
});
int counter = 0;
await foreach (var dataItem in extension.ReadAsync(config))
{
counter++;
CollectionAssert.AreEquivalent(new[] { "id", "name" }, dataItem.GetFieldNames().ToArray());
Assert.IsInstanceOfType(dataItem.GetValue("id"), typeof(double));
Assert.IsNotNull(dataItem.GetValue("name"));
}
Assert.AreEqual(5, counter);
}
[TestMethod]
public async Task ReadAsync_WithMixedObjectsFolder_ReadsValues()
{
var extension = new JsonDataSourceExtension();
var config = TestHelpers.CreateConfig(new Dictionary<string, string>
{
{ "FilePath", "Data/MixedObjects" }
});
int counter = 0;
await foreach (var dataItem in extension.ReadAsync(config))
{
counter++;
CollectionAssert.AreEquivalent(new[] { "id", "name" }, dataItem.GetFieldNames().ToArray());
Assert.IsInstanceOfType(dataItem.GetValue("id"), typeof(double));
Assert.IsNotNull(dataItem.GetValue("name"));
}
Assert.AreEqual(5, counter);
}
}
}

Просмотреть файл

@ -1,66 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration" Version="6.0.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
<PackageReference Include="MSTest.TestAdapter" Version="2.2.8" />
<PackageReference Include="MSTest.TestFramework" Version="2.2.8" />
<PackageReference Include="coverlet.collector" Version="3.1.2" />
<PackageReference Include="System.Linq.Async" Version="6.0.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Microsoft.DataTransfer.JsonExtension\Microsoft.DataTransfer.JsonExtension.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="Data\Arrays\OneToTwo.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Data\Arrays\ThreeToFive.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Data\MixedObjects\One.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Data\MixedObjects\ThreeToFive.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Data\MixedObjects\Two.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Data\NestedObjects.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Data\SingleObject.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Data\SimpleIdName.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Data\ArraysTypesNesting.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Data\SingleObjects\4Four.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Data\SingleObjects\2-3\3Three.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Data\SingleObjects\2-3\2Two.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Data\SingleObjects\1One.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

Просмотреть файл

@ -1,12 +0,0 @@
using Microsoft.Extensions.Configuration;
namespace Microsoft.DataTransfer.JsonExtension.UnitTests
{
public static class TestHelpers
{
public static IConfiguration CreateConfig(Dictionary<string, string> values)
{
return new ConfigurationBuilder().AddInMemoryCollection(values).Build();
}
}
}

Просмотреть файл

@ -1 +0,0 @@
global using Microsoft.VisualStudio.TestTools.UnitTesting;

Просмотреть файл

@ -1,40 +0,0 @@
using Microsoft.DataTransfer.Interfaces;
using System.ComponentModel.Composition;
using System.Text.Json;
using Microsoft.Extensions.Configuration;
using System;
using Microsoft.DataTransfer.JsonExtension.Settings;
namespace Microsoft.DataTransfer.JsonExtension
{
[Export(typeof(IDataSinkExtension))]
public class JsonDataSinkExtension : IDataSinkExtension
{
public string DisplayName => "JSON";
public async Task WriteAsync(IAsyncEnumerable<IDataItem> dataItems, IConfiguration config, CancellationToken cancellationToken = default)
{
var settings = config.Get<JsonSinkSettings>();
settings.Validate();
if (settings.FilePath != null)
{
Console.WriteLine($"Writing to file '{settings.FilePath}'");
await using var stream = File.Create(settings.FilePath);
await using var writer = new Utf8JsonWriter(stream, new JsonWriterOptions
{
Indented = settings.Indented
});
writer.WriteStartArray();
await foreach (var item in dataItems.WithCancellation(cancellationToken))
{
DataItemJsonConverter.WriteDataItem(writer, item, settings.IncludeNullFields);
}
writer.WriteEndArray();
Console.WriteLine($"Completed writing data to file '{settings.FilePath}'");
}
}
}
}

Просмотреть файл

@ -1,94 +0,0 @@
using System.ComponentModel.Composition;
using System.Runtime.CompilerServices;
using System.Text;
using System.Text.Json;
using Microsoft.DataTransfer.Interfaces;
using Microsoft.DataTransfer.JsonExtension.Settings;
using Microsoft.Extensions.Configuration;
using System;
namespace Microsoft.DataTransfer.JsonExtension
{
[Export(typeof(IDataSourceExtension))]
public class JsonDataSourceExtension : IDataSourceExtension
{
public string DisplayName => "JSON";
public async IAsyncEnumerable<IDataItem> ReadAsync(IConfiguration config, [EnumeratorCancellation] CancellationToken cancellationToken = default)
{
var settings = config.Get<JsonSourceSettings>();
settings.Validate();
if (settings.FilePath != null)
{
if (File.Exists(settings.FilePath))
{
Console.WriteLine($"Reading file '{settings.FilePath}'");
var list = await ReadFileAsync(cancellationToken, settings.FilePath);
if (list != null)
{
foreach (var listItem in list)
{
yield return new JsonDictionaryDataItem(listItem);
}
}
}
else if (Directory.Exists(settings.FilePath))
{
string[] files = Directory.GetFiles(settings.FilePath, "*.json", SearchOption.AllDirectories);
Console.WriteLine($"Reading {files.Length} files from '{settings.FilePath}'");
foreach (string filePath in files.OrderBy(f => f))
{
Console.WriteLine($"Reading file '{filePath}'");
var list = await ReadFileAsync(cancellationToken, filePath);
if (list != null)
{
foreach (var listItem in list)
{
yield return new JsonDictionaryDataItem(listItem);
}
}
}
}
Console.WriteLine($"Completed reading '{settings.FilePath}'");
}
}
private static async Task<List<Dictionary<string, object?>>?> ReadFileAsync(CancellationToken cancellationToken, string filePath)
{
var file = await File.ReadAllTextAsync(filePath, cancellationToken);
try
{
using MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(file));
return await JsonSerializer.DeserializeAsync<List<Dictionary<string, object?>>>(stream, cancellationToken: cancellationToken);
}
catch (Exception ex)
{
// list failed
}
var list = new List<Dictionary<string, object?>>();
try
{
using MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(file));
var item = await JsonSerializer.DeserializeAsync<Dictionary<string, object?>>(stream, cancellationToken: cancellationToken);
if (item != null)
{
list.Add(item);
}
}
catch (Exception ex)
{
// single item failed
}
if (!list.Any())
{
Console.WriteLine($"No records read from '{filePath}'");
}
return list;
}
}
}

Просмотреть файл

@ -1,60 +0,0 @@
using System.Text.Json;
using Microsoft.DataTransfer.Interfaces;
namespace Microsoft.DataTransfer.JsonExtension
{
public class JsonDictionaryDataItem : IDataItem
{
public IDictionary<string, object?> Items { get; }
public JsonDictionaryDataItem(IDictionary<string, object?> items)
{
Items = items;
}
public IEnumerable<string> GetFieldNames()
{
return Items.Keys;
}
public object? GetValue(string fieldName)
{
if (!Items.TryGetValue(fieldName, out var value))
{
return null;
}
if (value is JsonElement element)
{
return GetElementValue(element);
}
return value;
}
private static object? GetElementValue(JsonElement element)
{
JsonValueKind kind = element.ValueKind;
switch (kind)
{
case JsonValueKind.String:
return element.GetString();
case JsonValueKind.Number:
return element.GetDouble();
case JsonValueKind.True:
return true;
case JsonValueKind.False:
return false;
case JsonValueKind.Object:
return GetChildObject(element);
case JsonValueKind.Array:
return element.EnumerateArray().Select(GetElementValue).ToList();
}
return element.GetRawText();
}
private static JsonDictionaryDataItem GetChildObject(JsonElement element)
{
return new JsonDictionaryDataItem(element.EnumerateObject().ToDictionary(p => p.Name, p => (object?)p.Value));
}
}
}

Просмотреть файл

@ -1,23 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<OutputType>Exe</OutputType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="6.0.0" />
<PackageReference Include="System.ComponentModel.Composition" Version="6.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\Interfaces\Microsoft.DataTransfer.Interfaces\Microsoft.DataTransfer.Interfaces.csproj" />
</ItemGroup>
<Target Name="PublishDebug" AfterTargets="Build" Condition=" '$(Configuration)' == 'Debug' ">
<Exec Command="dotnet publish --no-build -p:PublishProfile=LocalDebugFolder" />
</Target>
</Project>

Просмотреть файл

@ -1 +0,0 @@
Console.WriteLine();

Просмотреть файл

@ -1,15 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project>
<PropertyGroup>
<Configuration>Debug</Configuration>
<Platform>Any CPU</Platform>
<PublishDir>..\..\..\Core\Microsoft.DataTransfer.Core\bin\Debug\net6.0\Extensions</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<_TargetId>Folder</_TargetId>
<TargetFramework>net6.0</TargetFramework>
<SelfContained>false</SelfContained>
</PropertyGroup>
</Project>

Просмотреть файл

@ -1,25 +0,0 @@
# JSON Extension
The JSON data transfer extension provides source and sink capabilities for reading from and writing to JSON files. Source and sink both support string, number, and boolean property values, arrays, and hierarchical nested object structures.
## Settings
Source and sink settings both require a `FilePath` parameter, which should specify a path to a JSON file or folder containing JSON files. The path can be either absolute or relative to the application. The JSON files can contain either an array of JSON objects or a single object. Sink also supports an optional `Indented` parameter (`false` by default) and an optional `IncludeNullFields` parameter (`false` by default) to control the formatting of the JSON output.
### Source
```json
"JsonSourceSettings": {
"FilePath": ""
}
```
### Sink
```json
"JsonSinkSettings": {
"FilePath": "",
"Indented": true
}
```

Просмотреть файл

@ -1,14 +0,0 @@
using Microsoft.DataTransfer.Interfaces;
using System.ComponentModel.DataAnnotations;
namespace Microsoft.DataTransfer.JsonExtension.Settings
{
public class JsonSinkSettings : IDataExtensionSettings
{
[Required]
public string? FilePath { get; set; }
public bool IncludeNullFields { get; set; }
public bool Indented { get; set; }
}
}

Просмотреть файл

@ -1,11 +0,0 @@
using Microsoft.DataTransfer.Interfaces;
using System.ComponentModel.DataAnnotations;
namespace Microsoft.DataTransfer.JsonExtension.Settings
{
public class JsonSourceSettings : IDataExtensionSettings
{
[Required]
public string? FilePath { get; set; }
}
}

Просмотреть файл

@ -1,48 +0,0 @@
using MongoDB.Bson;
using MongoDB.Driver;
using MongoDB.Driver.Core.Events;
namespace Microsoft.DataTransfer.MongoExtension;
public class Context
{
private readonly IMongoDatabase database = null!;
public Context(string connectionString, string databaseName)
{
var mongoConnectionUrl = new MongoUrl(connectionString);
var mongoClientSettings = MongoClientSettings.FromUrl(mongoConnectionUrl);
mongoClientSettings.ClusterConfigurator = cb => {
cb.Subscribe<CommandStartedEvent>(e => {
System.Diagnostics.Debug.WriteLine($"{e.CommandName} - {e.Command.ToJson()}");
});
};
var client = new MongoClient(mongoClientSettings);
database = client.GetDatabase(databaseName);
}
public virtual IRepository<T> GetRepository<T>(string name)
{
return new MongoRepository<T>(database.GetCollection<T>(name));
}
public virtual IMongoCollection<T> GetCollection<T>(string name)
{
return database.GetCollection<T>(name);
}
public virtual async Task RenameCollectionAsync(string originalName, string newName)
{
await database.RenameCollectionAsync(originalName, newName);
}
public virtual async Task DropCollectionAsync(string name)
{
await database.DropCollectionAsync(name);
}
public virtual async Task<IList<string>> GetCollectionNamesAsync()
{
var names = await database.ListCollectionNamesAsync();
return names.ToList();
}
}

Просмотреть файл

@ -1,14 +0,0 @@
using System.Linq.Expressions;
namespace Microsoft.DataTransfer.MongoExtension;
public interface IRepository<TDocument>
{
ValueTask Add(TDocument item);
ValueTask AddRange(IEnumerable<TDocument> items);
ValueTask AddRange(params TDocument[] items);
ValueTask Update(Expression<Func<TDocument, bool>> filter, TDocument value);
ValueTask Remove(Expression<Func<TDocument, bool>> filter);
ValueTask RemoveRange(Expression<Func<TDocument, bool>> filter);
IQueryable<TDocument> AsQueryable();
}

Просмотреть файл

@ -1,24 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<OutputType>Exe</OutputType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="6.0.0" />
<PackageReference Include="MongoDB.Driver" Version="2.17.1" />
<PackageReference Include="System.ComponentModel.Composition" Version="6.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\Interfaces\Microsoft.DataTransfer.Interfaces\Microsoft.DataTransfer.Interfaces.csproj" />
</ItemGroup>
<Target Name="PublishDebug" AfterTargets="Build" Condition=" '$(Configuration)' == 'Debug' ">
<Exec Command="dotnet publish --no-build -p:PublishProfile=LocalDebugFolder" />
</Target>
</Project>

Просмотреть файл

@ -1,24 +0,0 @@
using Microsoft.DataTransfer.Interfaces;
using MongoDB.Bson;
namespace Microsoft.DataTransfer.MongoExtension;
public class MongoDataItem : IDataItem
{
private readonly BsonDocument record;
public MongoDataItem(BsonDocument record)
{
this.record = record;
}
public IEnumerable<string> GetFieldNames()
{
return record.Names;
}
public object? GetValue(string fieldName)
{
var value = record.GetValue(fieldName);
return BsonTypeMapper.MapToDotNetValue(value);
}
}

Просмотреть файл

@ -1,44 +0,0 @@
using Microsoft.DataTransfer.Interfaces;
using Microsoft.DataTransfer.MongoExtension.Settings;
using Microsoft.Extensions.Configuration;
using MongoDB.Bson;
using System.ComponentModel.Composition;
namespace Microsoft.DataTransfer.MongoExtension;
[Export(typeof(IDataSinkExtension))]
public class MongoDataSinkExtension : IDataSinkExtension
{
public string DisplayName => "Mongo";
public async Task WriteAsync(IAsyncEnumerable<IDataItem> dataItems, IConfiguration config, CancellationToken cancellationToken = default)
{
var settings = config.Get<MongoSinkSettings>();
settings.Validate();
if (!string.IsNullOrEmpty(settings.ConnectionString) && !string.IsNullOrEmpty(settings.DatabaseName) && !string.IsNullOrEmpty(settings.Collection))
{
var context = new Context(settings.ConnectionString, settings.DatabaseName);
var repo = context.GetRepository<BsonDocument>(settings.Collection);
var batchSize = settings.BatchSize ?? 1000;
var objects = new List<BsonDocument>();
await foreach (var item in dataItems)
{
var dict = item.GetFieldNames().ToDictionary(key => key, key => item.GetValue(key));
objects.Add(new BsonDocument(dict));
if (objects.Count == batchSize)
{
await repo.AddRange(objects);
objects.Clear();
}
}
if (objects.Any())
{
await repo.AddRange(objects);
}
}
}
}

Просмотреть файл

@ -1,45 +0,0 @@
using System.ComponentModel.Composition;
using System.Runtime.CompilerServices;
using Microsoft.Extensions.Configuration;
using Microsoft.DataTransfer.Interfaces;
using MongoDB.Bson;
using Microsoft.DataTransfer.MongoExtension.Settings;
namespace Microsoft.DataTransfer.MongoExtension;
[Export(typeof(IDataSourceExtension))]
internal class MongoDataSourceExtension : IDataSourceExtension
{
public string DisplayName => "Mongo";
public async IAsyncEnumerable<IDataItem> ReadAsync(IConfiguration config, [EnumeratorCancellation] CancellationToken cancellationToken = default)
{
var settings = config.Get<MongoSourceSettings>();
settings.Validate();
if (!string.IsNullOrEmpty(settings.ConnectionString) && !string.IsNullOrEmpty(settings.DatabaseName))
{
var context = new Context(settings.ConnectionString, settings.DatabaseName);
var collectionNames = !string.IsNullOrEmpty(settings.Collection)
? new List<string> { settings.Collection }
: await context.GetCollectionNamesAsync();
foreach (var collection in collectionNames)
{
await foreach (var item in EnumerateCollectionAsync(context, collection))
{
yield return item;
}
}
}
}
public async IAsyncEnumerable<IDataItem> EnumerateCollectionAsync(Context context, string collectionName)
{
var collection = context.GetRepository<BsonDocument>(collectionName);
foreach (var record in collection.AsQueryable())
{
yield return new MongoDataItem(record);
}
}
}

Просмотреть файл

@ -1,49 +0,0 @@
using MongoDB.Driver;
using System.Linq.Expressions;
namespace Microsoft.DataTransfer.MongoExtension;
public class MongoRepository<TDocument> : IRepository<TDocument>
{
private readonly IMongoCollection<TDocument> collection;
public MongoRepository(IMongoCollection<TDocument> collection)
{
this.collection = collection;
}
public async ValueTask Add(TDocument item)
{
await collection.InsertOneAsync(item);
}
public async ValueTask AddRange(IEnumerable<TDocument> items)
{
await collection.InsertManyAsync(items);
}
public async ValueTask AddRange(params TDocument[] items)
{
await collection.InsertManyAsync(items);
}
public async ValueTask Update(Expression<Func<TDocument, bool>> filter, TDocument value)
{
await collection.FindOneAndReplaceAsync(filter, value);
}
public async ValueTask Remove(Expression<Func<TDocument, bool>> filter)
{
await collection.DeleteOneAsync(filter);
}
public async ValueTask RemoveRange(Expression<Func<TDocument, bool>> filter)
{
await collection.DeleteManyAsync(filter);
}
public IQueryable<TDocument> AsQueryable()
{
return collection.AsQueryable();
}
}

Просмотреть файл

@ -1 +0,0 @@
Console.WriteLine("Starting Mongo extension");

Просмотреть файл

@ -1,15 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project>
<PropertyGroup>
<Configuration>Debug</Configuration>
<Platform>Any CPU</Platform>
<PublishDir>..\..\..\Core\Microsoft.DataTransfer.Core\bin\Debug\net6.0\Extensions</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<_TargetId>Folder</_TargetId>
<TargetFramework>net6.0</TargetFramework>
<SelfContained>false</SelfContained>
</PropertyGroup>
</Project>

Просмотреть файл

@ -1,28 +0,0 @@
# Mongo Extension
The Mongo data transfer extension provides source and sink capabilities for reading from and writing to a Mongo database.
## Settings
Source and sink settings require both `ConnectionString` and `DatabaseName` parameters. The source takes an optional `Collection` parameter (if this parameter is not set, it will read from all collections). The sink requires the `Collection` parameter and will insert all records received from a source into that collection, as well as an optional `BatchSize` parameter (default value is 100) to batch the writes into the collection.
### Source
```json
"MongoSourceSettings": {
"ConnectionString": "",
"DatabaseName: "",
"Collection": ""
}
```
### Sink
```json
"MongoSinkSettings": {
"ConnectionString": "",
"DatabaseName: "",
"Collection": "",
"BatchSize: 100
}
```

Просмотреть файл

@ -1,12 +0,0 @@
using Microsoft.DataTransfer.Interfaces;
using System.ComponentModel.DataAnnotations;
namespace Microsoft.DataTransfer.MongoExtension.Settings;
public class MongoBaseSettings : IDataExtensionSettings
{
[Required]
public string? ConnectionString { get; set; }
[Required]
public string? DatabaseName { get; set; }
}

Просмотреть файл

@ -1,10 +0,0 @@
using System.ComponentModel.DataAnnotations;
namespace Microsoft.DataTransfer.MongoExtension.Settings;
public class MongoSinkSettings : MongoBaseSettings
{
[Required]
public string? Collection { get; set; }
public int? BatchSize { get; set; }
}

Просмотреть файл

@ -1,5 +0,0 @@
namespace Microsoft.DataTransfer.MongoExtension.Settings;
public class MongoSourceSettings : MongoBaseSettings
{
public string? Collection { get; set; }
}

Просмотреть файл

@ -1,18 +0,0 @@
[
{
"id": 1,
"name": "One"
},
{
"id": 2,
"name": "Two"
},
{
"id": 3,
"name": "Three"
},
{
"id": 4,
"name": "Four"
}
]

Просмотреть файл

@ -1,30 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration" Version="6.0.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
<PackageReference Include="MSTest.TestAdapter" Version="2.2.8" />
<PackageReference Include="MSTest.TestFramework" Version="2.2.8" />
<PackageReference Include="coverlet.collector" Version="3.1.2" />
<PackageReference Include="System.Linq.Async" Version="6.0.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Microsoft.DataTransfer.SqlServerExtension\Microsoft.DataTransfer.SqlServerExtension.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="Data\FlatFile.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

Просмотреть файл

@ -1,8 +0,0 @@
namespace Microsoft.DataTransfer.SqlServerExtension.UnitTests
{
[TestClass]
public class SqlServerExtensionTests
{
}
}

Просмотреть файл

@ -1 +0,0 @@
global using Microsoft.VisualStudio.TestTools.UnitTesting;

Просмотреть файл

@ -1,18 +0,0 @@
using System.ComponentModel.DataAnnotations;
namespace Microsoft.DataTransfer.SqlServerExtension
{
public class ColumnMapping
{
[Required]
public string? ColumnName { get; set; }
public string? SourceFieldName { get; set; }
public bool AllowNull { get; set; } = true;
public object? DefaultValue { get; set; }
public string? GetFieldName()
{
return SourceFieldName ?? ColumnName;
}
}
}

Просмотреть файл

@ -1,27 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<OutputType>Exe</OutputType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Data.SqlClient" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="6.0.0" />
<PackageReference Include="System.ComponentModel.Composition" Version="6.0.0" />
<PackageReference Include="System.Interactive.Async" Version="6.0.1" />
<PackageReference Include="System.Linq.Async" Version="6.0.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\Interfaces\Microsoft.DataTransfer.Interfaces\Microsoft.DataTransfer.Interfaces.csproj" />
</ItemGroup>
<Target Name="PublishDebug" AfterTargets="Build" Condition=" '$(Configuration)' == 'Debug' ">
<Exec Command="dotnet publish --no-build -p:PublishProfile=LocalDebugFolder" />
</Target>
</Project>

Просмотреть файл

@ -1 +0,0 @@
Console.WriteLine();

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше