clear main branch
This commit is contained in:
Родитель
ca3630be0c
Коммит
6ad63030e8
|
@ -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
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();
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче