增加一个公共服务类

pull/3/head
刘鑫 4 months ago
parent fb355d955c
commit 2d6ebca32d
  1. 2
      WeiCloud.Fusion/Alarm.DomainService/Alarm.DomainService.csproj
  2. 3
      WeiCloud.Fusion/Alarm.DomainService/DahAlarm/IDahuaGeneralCtlService.cs
  3. 1
      WeiCloud.Fusion/AlarmService/AlarmService.API/AlarmService.API.csproj
  4. 0
      WeiCloud.Fusion/Common.SharedService/Common.Shared.Application/ApiResult.cs
  5. 0
      WeiCloud.Fusion/Common.SharedService/Common.Shared.Application/Common.Shared.Application.csproj
  6. 0
      WeiCloud.Fusion/Common.SharedService/Common.Shared.Application/DaHua/DaHApiResult.cs
  7. 0
      WeiCloud.Fusion/Common.SharedService/Common.Shared.Application/DaHua/RequestDto/DahuaVideoQueryDto.cs
  8. 0
      WeiCloud.Fusion/Common.SharedService/Common.Shared.Application/DaHua/ResponeDto/DahuaVideoResDto.cs
  9. 74
      WeiCloud.Fusion/Common.SharedService/Common.Shared.Application/MQTT/MQTTParamDto.cs
  10. 21
      WeiCloud.Fusion/Common.SharedService/Common.Shared.DomainService/Common.Shared.DomainService.csproj
  11. 28
      WeiCloud.Fusion/Common.SharedService/Common.Shared.DomainService/MqttClient/IMqttClientService.cs
  12. 93
      WeiCloud.Fusion/Common.SharedService/Common.Shared.DomainService/MqttClient/MQTTClient.cs
  13. 173
      WeiCloud.Fusion/Common.SharedService/Common.Shared.DomainService/MqttClient/MqttClientListService.cs
  14. 119
      WeiCloud.Fusion/Common.SharedService/Common.Shared.DomainService/MqttClient/MqttClientService.cs
  15. 2
      WeiCloud.Fusion/VideoService/Video.DomainService/Video.DomainService.csproj
  16. 35
      WeiCloud.Fusion/WeiCloud.Core/BaseModels/LoggerWarp.cs
  17. 23
      WeiCloud.Fusion/WeiCloud.Fusion.sln

@ -14,7 +14,7 @@
<ItemGroup>
<ProjectReference Include="..\Alarm.Application\Alarm.Application.csproj" />
<ProjectReference Include="..\Common.Shared.Application\Common.Shared.Application.csproj" />
<ProjectReference Include="..\Common.SharedService\Common.Shared.Application\Common.Shared.Application.csproj" />
</ItemGroup>
</Project>

@ -1,5 +1,4 @@
using Alarm.Application.RequestDto;
using Alarm.Application.ResponeDto;
using Alarm.Application.ResponeDto;
using Common.Shared.Application.DaHua;
namespace Alarm.DomainService.DahAlarm

@ -8,7 +8,6 @@
<ItemGroup>
<ProjectReference Include="..\..\Alarm.DomainService\Alarm.DomainService.csproj" />
<ProjectReference Include="..\..\Common.Shared.Application\Common.Shared.Application.csproj" />
<ProjectReference Include="..\..\WeiCloud.Utils\WeiCloud.Utils.csproj" />
</ItemGroup>

@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Common.Shared.Application.MQTT
{
/// <summary>
/// Mqtt参数
/// </summary>
public class MQTTParamDto
{
/// <summary>
/// mqtt的标识名称
/// </summary>
public string MqttClientMark { get; set; }
/// <summary>
/// 项目ID
/// </summary>
public long ProjectId { get; set; }
/// <summary>
/// 服务器Ip
/// </summary>
public string HostIp { get; set; }
/// <summary>
/// 服务器端口号
/// </summary>
public short HostPort { get; set; }
/// <summary>
/// 超时时间 ms
/// </summary>
public int Timeout { get; set; }
/// <summary>
/// 通讯质量等级 0至多一次 2一次 1 至少一次
/// </summary>
public short Level { get; set; }
/// <summary>
/// 用户名
/// </summary>
public string UserName { get; set; }
/// <summary>
/// 密码
/// </summary>
public string Password { get; set; }
/// <summary>
/// 客户端ID
/// </summary>
public string? ClientId { get; set; }
/// <summary>
/// 发布的topic
/// </summary>
public List<string>? PublishTopics { get; set; }
/// <summary>
/// 订阅的topic
/// </summary>
public List<string>? SubscribeTopics { get; set; }
/// <summary>
/// 物联网版本 1 是老版本 2是新版本
/// </summary>
public short IotType { get; set; }
}
}

@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MQTTnet" Version="4.1.4.563" />
<PackageReference Include="NLog" Version="6.0.3" />
<PackageReference Include="NLog.Extensions.Logging" Version="6.0.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\WeiCloud.Core\WeiCloud.Core.csproj" />
<ProjectReference Include="..\..\WeiCloud.Utils\WeiCloud.Utils.csproj" />
<ProjectReference Include="..\Common.Shared.Application\Common.Shared.Application.csproj" />
</ItemGroup>
</Project>

@ -0,0 +1,28 @@
using MQTTnet;
using MQTTnet.Client;
namespace Common.Shared.DomainService.MqttClient
{
public interface IMqttClientService
{
/// <returns></returns>
Task<int> SubscribeAsync(string topicName);
/// <summary>
/// 取消订阅主题
/// </summary>
/// <param name="topicName"></param>
/// <returns></returns>
Task<int> UnSubscribeAsync(string topicName);
/// <summary>
/// 发送消息
/// </summary>
/// <param name="topicName"></param>
/// <param name="message"></param>
/// <returns></returns>
Task<MqttClientPublishResult> PublishAsync(string topicName, string message);
Task ReceiveAsync(Action<MqttApplicationMessageReceivedEventArgs> action);
}
}

@ -0,0 +1,93 @@
using Microsoft.Extensions.Logging;
using MQTTnet;
using MQTTnet.Client;
using MQTTnet.Protocol;
using WeiCloud.Core.BaseModels;
namespace Common.Shared.DomainService.MqttClient
{
public class MQTTClient
{
private readonly ILogger<MQTTClient> _logger;
internal IMqttClient mqttClient;
public MQTTClient(ILogger<MQTTClient> logger)
{
_logger = logger;
}
private async Task Subscribe(string topicNameStrs)
{
if (!string.IsNullOrWhiteSpace(topicNameStrs))
{
var topicNames = topicNameStrs.Split(",");
foreach (var topicName in topicNames)
{
await mqttClient.SubscribeAsync(topicName, MqttQualityOfServiceLevel.AtMostOnce);
}
}
}
/// <summary>
/// 初始化
/// </summary>
/// <param name="serverIp"></param>
/// <param name="port"></param>
/// <param name="authUser"></param>
/// <param name="authPwd"></param>
/// <param name="clientId"></param>
/// <returns></returns>
public async Task Init(string serverIp, int port, string authUser, string authPwd, string topicNameStrs, string clientId = "")
{
try
{
if (string.IsNullOrWhiteSpace(clientId))
{
clientId = Guid.NewGuid().ToString();
}
var factory = new MqttFactory();
mqttClient = factory.CreateMqttClient();
var options = new MqttClientOptionsBuilder()
.WithTcpServer(serverIp, port)
.WithCredentials(authUser, authPwd)
.WithCleanSession(false)
.WithClientId(clientId)
.Build();
//mqttClient.UseApplicationMessageReceivedHandler(e =>
//{
// Console.WriteLine("###收到消息####");
// Console.WriteLine($"Topic {e.ApplicationMessage.Topic}");
// Console.WriteLine($"Payload {Encoding.UTF8.GetString(e.ApplicationMessage.Payload)}");
// Console.WriteLine($"Qos {e.ApplicationMessage.QualityOfServiceLevel}");
// Console.WriteLine($"Retain {e.ApplicationMessage.Retain}");
// Console.WriteLine();
//});
mqttClient.DisconnectedAsync += async e =>
{
Console.WriteLine($"{clientId}连接异常{serverIp} {port}");
try
{
_logger.LogWarning(new LoggerWarp("Init", message: $"{clientId}连接异常{serverIp} {port}").GetMessage());
await Task.Delay(TimeSpan.FromSeconds(5));
await mqttClient.ConnectAsync(options);
//订阅
await Subscribe(topicNameStrs);
Console.WriteLine($"{clientId}重新连接服务器成功{serverIp} {port}");
_logger.LogWarning(new LoggerWarp("Init", message: $"{clientId}重新连接服务器{mqttClient.IsConnected}{serverIp} {port}").GetMessage());
}
catch (Exception ex)
{
Console.WriteLine($"重新连接服务器异常 {ex.Message}");
_logger.LogError(new LoggerWarp("Init", message: "重新连接服务器异常", ex: ex).GetMessage());
}
};
await mqttClient.ConnectAsync(options);
await Subscribe(topicNameStrs);
}
catch (Exception ex)
{
_logger.LogError(new LoggerWarp("Init", ex: ex).GetMessage());
}
}
}
}

@ -0,0 +1,173 @@
using Common.Shared.Application.MQTT;
using Microsoft.Extensions.Logging;
using MQTTnet;
using MQTTnet.Client;
using MQTTnet.Protocol;
using System.Collections.Concurrent;
using System.Text;
using WeiCloud.Utils.Common;
namespace Common.Shared.DomainService.MqttClient
{
public class MqttClientListService
{
private readonly ILogger<MqttClientListService> _logger;
/// <summary>
/// mqttclient集合
/// </summary>
public static ConcurrentDictionary<MQTTParamDto, IMqttClient> _mqttClientList = new ConcurrentDictionary<MQTTParamDto, IMqttClient>();
private MqttFactory _factory = new MqttFactory();
/// <summary>
/// DI
/// </summary>
/// <param name="logger"></param>
/// <param name="weiCloudDBRobotContext"></param>
/// <param name="redisHashService"></param>
/// <param name="configuration"></param>
/// <exception cref="ArgumentNullException"></exception>
public MqttClientListService(ILogger<MqttClientListService> logger)
{
_logger = logger;
}
/// <summary>
/// 创建mqtt客户端
/// </summary>
/// <param name="mQTT"></param>
/// <returns></returns>
public async Task<IMqttClient> CreateMqttClient(MQTTParamDto mQTT)
{
try
{
var key = _mqttClientList.Keys.Where(x => x.MqttClientMark == mQTT.MqttClientMark).FirstOrDefault();
if (key != null)
{
return _mqttClientList[key];
}
if (string.IsNullOrWhiteSpace(mQTT.ClientId))
{
mQTT.ClientId = "robot_mqtt_" + UidGenerator.Uid().ToString();
}
var mqttClient = _factory.CreateMqttClient();
var options = new MqttClientOptionsBuilder()
.WithTcpServer(mQTT.HostIp, mQTT.HostPort)
.WithCredentials(mQTT.UserName, mQTT.Password)
.WithCleanSession(false)
.WithClientId(mQTT.ClientId)
.Build();
mqttClient.ApplicationMessageReceivedAsync += delegate (MqttApplicationMessageReceivedEventArgs args)
{
//var key = _mqttClientList.Keys.Where(x => x.ClientId == ).FirstOrDefault();
Console.WriteLine($"Topic {args.ApplicationMessage.Topic}");
Console.WriteLine($"Payload {Encoding.UTF8.GetString(args.ApplicationMessage.Payload)}");
Console.WriteLine($"Qos {args.ApplicationMessage.QualityOfServiceLevel}");
//进行业务处理
return Task.CompletedTask;
};
mqttClient.DisconnectedAsync += async e =>
{
await Task.Delay(TimeSpan.FromSeconds(5));
try
{
await mqttClient.ConnectAsync(options);
//订阅
await Subscribe(mqttClient, mQTT.SubscribeTopics, mQTT.Level);
}
catch (Exception ex)
{
Console.WriteLine($"重新连接服务器异常 {ex.Message}");
_logger.LogError($"Init 重新连接服务器异常{ex.Message}");
}
};
await mqttClient.ConnectAsync(options);
await Subscribe(mqttClient, mQTT.SubscribeTopics, mQTT.Level);
_mqttClientList.TryAdd(mQTT, mqttClient);
return mqttClient;
}
catch (Exception ex)
{
_logger.LogError($"create mqttclient error {ex.Message}");
return null;
}
}
/// <summary>
/// 订阅主题
/// </summary>
/// <param name="mqttClient"></param>
/// <param name="topics"></param>
/// <param name="level"></param>
/// <returns></returns>
private async Task Subscribe(IMqttClient mqttClient, List<string>? topics, short level)
{
var mqttSubscribeOptions = _factory.CreateSubscribeOptionsBuilder();
if (topics != null)
{
foreach (var topic in topics)
{
mqttSubscribeOptions.WithTopicFilter(
f =>
{
f.WithTopic(topic);
if (level == 1)
{
f.WithAtLeastOnceQoS();
}
else if (level == 0)
{
f.WithAtMostOnceQoS();
}
else if (level == 2)
{
f.WithExactlyOnceQoS();
}
});
}
var response = await mqttClient.SubscribeAsync(mqttSubscribeOptions.Build(), CancellationToken.None);
}
}
/// <summary>
/// 发布主题数据
/// </summary>
/// <param name="mqttClientMark"></param>
/// <param name="msgs"></param>
/// <returns></returns>
public async Task Publish(string mqttClientMark, List<string> msgs)
{
IMqttClient mqttClient = null;
var key = _mqttClientList.Keys.Where(x => x.MqttClientMark == mqttClientMark).FirstOrDefault();
if (key != null)
{
if (key.PublishTopics == null)
{
return;
}
mqttClient = _mqttClientList[key];
}
if (mqttClient == null)
{
return;
}
foreach (var msg in msgs)
{
foreach (var topic in key.PublishTopics)
{
var applicationMessage = new MqttApplicationMessageBuilder()
.WithTopic(topic)
.WithPayload(msg)
.WithQualityOfServiceLevel(MqttQualityOfServiceLevel.AtMostOnce)
.Build();
await mqttClient.PublishAsync(applicationMessage, CancellationToken.None);
}
}
}
}
}

@ -0,0 +1,119 @@
using Common.Shared.DomainService.MqttClient;
using Microsoft.Extensions.Configuration;
using MQTTnet;
using MQTTnet.Client;
namespace WeiCloud.SafetyFirePro.Services
{
public class MqttClientService : IMqttClientService
{
private readonly MQTTClient _mQTTClient;
private readonly IConfiguration _configuration;
private string topicName = string.Empty;
private string mqttClientId = string.Empty;
public MqttClientService(MQTTClient mQTTClient, IConfiguration configuration)
{
_mQTTClient = mQTTClient;
//_configuration = configuration;
//using var loggerFactory = LoggerFactory.Create(builder =>
//{
//});
//var logger = loggerFactory.CreateLogger<MQTTClient>();
//_mQTTClient = new MQTTClient(logger);
//string mqttHostIp = _configuration["MqttClientOption:HostIp"];//IP地址
//short mqttHostPort = short.Parse(_configuration["MqttClientOption:HostPort"]);//端口号
//int mqttTimeout = short.Parse(_configuration["MqttClientOption:Timeout"]);//超时时间
//string mqttUsername = _configuration["MqttClientOption:UserName"];//用户名
//string mqttPassword = _configuration["MqttClientOption:Password"];//密码
////string mqttClientId = _configuration["MqttClientOption:ClientId"];
//string proid = _configuration["MqttClientOption:ProjectId"];
//topicName = $"weilink/v1/control/commandcallback/{proid}/#";
//_mQTTClient.Init(mqttHostIp, mqttHostPort, mqttUsername, mqttPassword, topicName, mqttClientId);
}
/// <summary>
/// 订阅主题
/// </summary>
/// <param name="topicName"></param>
/// <returns></returns>
public async Task<int> SubscribeAsync(string topicName)
{
if (string.IsNullOrEmpty(topicName))
{
return -1;
}
if (!_mQTTClient.mqttClient.IsConnected)
{
return -2;
}
await _mQTTClient.mqttClient.SubscribeAsync(new MqttTopicFilterBuilder().WithTopic(topicName).Build());
return 1;
}
/// <summary>
/// 取消订阅主题
/// </summary>
/// <param name="topicName"></param>
/// <returns></returns>
public async Task<int> UnSubscribeAsync(string topicName)
{
if (string.IsNullOrEmpty(topicName))
{
return -1;
}
if (!_mQTTClient.mqttClient.IsConnected)
{
return -2;
}
MqttClientUnsubscribeOptions mqttClientUnsubscribeOptions = new MqttClientUnsubscribeOptions()
{
TopicFilters = new List<string>() { topicName }
};
await _mQTTClient.mqttClient.UnsubscribeAsync(mqttClientUnsubscribeOptions);
return 1;
}
/// <summary>
/// 发送消息
/// </summary>
/// <param name="topicName"></param>
/// <param name="message"></param>
/// <returns></returns>
public async Task<MqttClientPublishResult> PublishAsync(string topicName, string message)
{
if (string.IsNullOrEmpty(topicName))
{
return new MqttClientPublishResult();
}
if (!_mQTTClient.mqttClient.IsConnected)
{
return new MqttClientPublishResult();
}
var messagebuilder = new MqttApplicationMessageBuilder()
.WithTopic(topicName)
.WithPayload(message)
.WithQualityOfServiceLevel(MQTTnet.Protocol.MqttQualityOfServiceLevel.AtLeastOnce)
//.WithExactlyOnceQoS()
//.WithAtLeastOnceQoS()
.WithRetainFlag(false)
.Build();
MqttClientPublishResult mqttClientPublishResult = await _mQTTClient.mqttClient.PublishAsync(messagebuilder);
return mqttClientPublishResult;
}
/// <summary>
/// 接收消息
/// </summary>
/// <param name="action"></param>
/// <returns></returns>
public async Task ReceiveAsync(Action<MqttApplicationMessageReceivedEventArgs> action)
{
_mQTTClient.mqttClient.ApplicationMessageReceivedAsync += async e =>
{
action(e);
};
}
}
}

@ -7,7 +7,7 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Common.Shared.Application\Common.Shared.Application.csproj" />
<ProjectReference Include="..\..\Common.SharedService\Common.Shared.Application\Common.Shared.Application.csproj" />
<ProjectReference Include="..\..\WeiCloud.Utils\WeiCloud.Utils.csproj" />
<ProjectReference Include="..\Video.Application\Video.Application.csproj" />
</ItemGroup>

@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace WeiCloud.Core.BaseModels
{
public class LoggerWarp
{
private readonly string _actionName;
private readonly string _message;
private readonly Exception _ex;
public LoggerWarp(string actionName, string message = "", Exception ex = null)
{
_actionName = actionName;
_message = message;
_ex = ex;
}
public string GetMessage()
{
StringBuilder messageString = new StringBuilder();
messageString.Append(_actionName).Append("|");
if (!string.IsNullOrEmpty(_message))
{
messageString.Append(_message).Append("|");
}
if (_ex != null)
{
messageString.Append($"抛出了异常信息:{_ex.Message} {_ex.StackTrace} {_ex.Source}");
}
return messageString.ToString();
}
}
}

@ -49,12 +49,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AlarmService.API", "AlarmSe
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Alarm.DomainService", "Alarm.DomainService\Alarm.DomainService.csproj", "{3ED553C4-3A63-4613-B979-472FDA5EA346}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Common.Shared.Application", "Common.Shared.Application", "{80F3B34B-C334-44D2-A861-31FD403AD57D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Common.Shared.Application", "Common.Shared.Application\Common.Shared.Application.csproj", "{6CE57FEC-4982-48AF-A9CB-4BCE93A84228}"
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Common.SharedService", "Common.SharedService", "{80F3B34B-C334-44D2-A861-31FD403AD57D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Alarm.Application", "Alarm.Application\Alarm.Application.csproj", "{89367194-A636-41B9-81F0-283DCB84C296}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Common.Shared.Application", "Common.SharedService\Common.Shared.Application\Common.Shared.Application.csproj", "{9A5FBAFF-EBE8-3156-5547-FB3ED1DEB545}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Common.Shared.DomainService", "Common.SharedService\Common.Shared.DomainService\Common.Shared.DomainService.csproj", "{C2757FC0-54A9-BBD3-2E23-55F2F3912BA4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -125,14 +127,18 @@ Global
{3ED553C4-3A63-4613-B979-472FDA5EA346}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3ED553C4-3A63-4613-B979-472FDA5EA346}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3ED553C4-3A63-4613-B979-472FDA5EA346}.Release|Any CPU.Build.0 = Release|Any CPU
{6CE57FEC-4982-48AF-A9CB-4BCE93A84228}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6CE57FEC-4982-48AF-A9CB-4BCE93A84228}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6CE57FEC-4982-48AF-A9CB-4BCE93A84228}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6CE57FEC-4982-48AF-A9CB-4BCE93A84228}.Release|Any CPU.Build.0 = Release|Any CPU
{89367194-A636-41B9-81F0-283DCB84C296}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{89367194-A636-41B9-81F0-283DCB84C296}.Debug|Any CPU.Build.0 = Debug|Any CPU
{89367194-A636-41B9-81F0-283DCB84C296}.Release|Any CPU.ActiveCfg = Release|Any CPU
{89367194-A636-41B9-81F0-283DCB84C296}.Release|Any CPU.Build.0 = Release|Any CPU
{9A5FBAFF-EBE8-3156-5547-FB3ED1DEB545}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9A5FBAFF-EBE8-3156-5547-FB3ED1DEB545}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9A5FBAFF-EBE8-3156-5547-FB3ED1DEB545}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9A5FBAFF-EBE8-3156-5547-FB3ED1DEB545}.Release|Any CPU.Build.0 = Release|Any CPU
{C2757FC0-54A9-BBD3-2E23-55F2F3912BA4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C2757FC0-54A9-BBD3-2E23-55F2F3912BA4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C2757FC0-54A9-BBD3-2E23-55F2F3912BA4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C2757FC0-54A9-BBD3-2E23-55F2F3912BA4}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -154,8 +160,9 @@ Global
{9F2BD2C5-6496-419D-B87A-4F481E963C4D} = {19A25984-FFA8-49BE-A710-6F269A406C61}
{2677EAF0-9F7F-4969-B8B1-3006F35EB93E} = {18791734-CA81-482D-964A-CA6D0F308B8E}
{3ED553C4-3A63-4613-B979-472FDA5EA346} = {18791734-CA81-482D-964A-CA6D0F308B8E}
{6CE57FEC-4982-48AF-A9CB-4BCE93A84228} = {80F3B34B-C334-44D2-A861-31FD403AD57D}
{89367194-A636-41B9-81F0-283DCB84C296} = {18791734-CA81-482D-964A-CA6D0F308B8E}
{9A5FBAFF-EBE8-3156-5547-FB3ED1DEB545} = {80F3B34B-C334-44D2-A861-31FD403AD57D}
{C2757FC0-54A9-BBD3-2E23-55F2F3912BA4} = {80F3B34B-C334-44D2-A861-31FD403AD57D}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {379A56DA-D3F0-4E7E-8FF7-DA8E20015BF3}

Loading…
Cancel
Save