zoulei 1 年之前
父節點
當前提交
7a848bf5ef

二進制
XdCxRhDW.Api/AddIns/检测Cpu参估/XcorrCpu.exe


+ 4 - 11
XdCxRhDW.Api/AddIns/检测Cpu参估/XcorrCpu.txt

@@ -1,12 +1,5 @@
+XcorrCpu_EXPORT bool XcorrCpuFile(double* res, int& resCount, const char* f1, const char* f2, int smplCount, double samplingRate
+		, double dtCenter, double dtRange, double dfRange, double filterDt, double filterDf, double snrThreshold, int threadCount);
 
-时隙参估(滑动)--起始样点太小会溢出
-	0 "Z:/xcorr-d1.dat" "Z:/xcorr-d2.dat" 1562500 1778 20 16384 0 1048576 14
-
-时隙画图(滑动)--起始样点太小会溢出
-	1 "Z:/xcorr-d1.dat" "Z:/xcorr-d2.dat" 1562500 1778 20 16384 0 1048576 14 "Z:/res.txt"
-
-文件参估
-	2 "Z:/xcorr-d1.dat" "Z:/xcorr-d2.dat" 1562500 1778 20 16384 1048576 14
-
-文件画图
-	3 "Z:/xcorr-d1.dat" "Z:/xcorr-d2.dat" 1562500 1778 20 16384 1048576 14 "Z:/res.txt"
+	XcorrCpu_EXPORT bool XcorrCpuArray(double* res, int& resCount, short * buf1, short* buf2, int smplCount, double samplingRate
+		, double dtCenter, double dtRange, double dfRange, double filterDt, double filterDf, double snrThreshold, int threadCount);

+ 76 - 8
XdCxRhDW.App/Controllers/DetectCgController.cs

@@ -1,16 +1,11 @@
 using System;
 using System.Collections.Generic;
 using System.IO;
-using System.Linq;
-using System.Net.Http;
-using System.Net;
-using System.Text;
 using System.Threading.Tasks;
 using System.Web.Http;
+using XdCxRhDW.Api;
 using XdCxRhDW.Dto;
 using XdCxRhDW.WebApi;
-using System.ComponentModel.DataAnnotations;
-using XdCxRhDW.Api;
 
 namespace XdCxRhDW.App.Controllers
 {
@@ -104,6 +99,79 @@ namespace XdCxRhDW.App.Controllers
 
         }
 
+
+        /// <summary>
+        /// CPU参估多样点位置计算(需要先上传文件)
+        /// </summary>
+        /// <param name="dto">CPU参估多样点位置参数</param>
+        /// <returns></returns>
+        [HttpPost]
+        public async Task<AjaxResult<List<CpuCgResDto>>> CpuCgMultiCalc(CpuCgMultiDto dto)
+        {
+            dto.file1 = GetLocalFile(dto.file1);
+            dto.file2 = GetLocalFile(dto.file2);
+            XcorrStruct xItem = new XcorrStruct();
+            xItem.file1 = dto.file1;
+            xItem.file2 = dto.file2;
+            xItem.samplingRate = dto.samplingRate;
+            xItem.dtCenter = dto.dtCenter;
+            xItem.dtRange = dto.dtRange;
+            xItem.dfRange = dto.dfRange;
+            xItem.snrThreshold = dto.snrThreshold;
+
+            List<CpuCgResDto> resDtos = new List<CpuCgResDto>();
+            foreach (var smpItem in dto.smpPositions)
+            {
+                try
+                {
+                    XcorrUtils xcorr = new XcorrUtils();
+                    xItem.smpStart = smpItem.smpStart;
+                    xItem.smpCount = smpItem.smpCount;
+                    var result = await xcorr.Calc(xItem);
+                    //开始计算
+                    if (result.flag == -2)
+                    {
+                        Serilog.Log.Error("参估计算内部错误!");
+                        continue;
+                    }
+                    else if (result.flag == -1)
+                    {
+                        Serilog.Log.Error("参估计算所需数据超出文件范围!");
+                        continue;
+                    }
+                    CpuCgResDto resDto = new CpuCgResDto();
+                    resDto.TimeMs = result.tm;
+                    resDto.Smpstart = result.smpstart;
+                    resDto.Smplen = result.smplen;
+                    if (result.flag == 1)
+                    {
+                        resDto.Dt = result.dt.Value;
+                        resDto.Df = result.df.Value;
+                        resDto.Snr = result.snr.Value;
+                        resDtos.Add(resDto);
+                    }
+
+
+                }
+                catch (Exception ex)
+                {
+                    Serilog.Log.Error(ex, "执行CPU参估异常");
+                    continue;
+                }
+            }
+            try
+            {
+                //删除计算得文件
+                File.Delete(dto.file1);
+                File.Delete(dto.file2);
+            }
+            catch
+            {
+            }
+            return Success(resDtos);
+
+        }
+
         /// <summary>
         /// GPU参估计算(需要先上传文件)
         /// </summary>
@@ -184,7 +252,7 @@ namespace XdCxRhDW.App.Controllers
                     var dmcResult = await xcorr.DmcCheckAsync(dto.file1, dto.fsHz, DmcType.Ky5758, dto.band);
                     dmcResults.AddRange(dmcResult);
                 }
-              
+
                 foreach (var dmcItem in dmcResults)
                 {
                     DetectResDto detectRes = new DetectResDto(dmcItem.Start, dmcItem.Length, dmcItem.UserName);
@@ -228,7 +296,7 @@ namespace XdCxRhDW.App.Controllers
                  var val = Gcd(dto.FsHz, dto.OutFsHz);//最大公约数
                  var insertFactor = dto.OutFsHz / val;
                  var extFactor = dto.FsHz / val;
-                 var outFile = ReSampleHelper.Resample(fileIn, fileOut, insertFactor, extFactor,dto.TimeoutSeconds);
+                 var outFile = ReSampleHelper.Resample(fileIn, fileOut, insertFactor, extFactor, dto.TimeoutSeconds);
                  if (!string.IsNullOrWhiteSpace(outFile))
                  {
                      if (!File.Exists(outFile))

+ 5 - 34
XdCxRhDW.App/Localizer/ChsLocalizer.cs

@@ -1,5 +1,4 @@
-using DevExpress.Map.Localization;
-using DevExpress.Utils.Filtering.Internal;
+using DevExpress.Data.Localization;
 using DevExpress.Utils.Localization;
 using DevExpress.XtraBars.Docking2010;
 using DevExpress.XtraBars.Localization;
@@ -12,7 +11,6 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
-using System.Windows;
 
 namespace XdCxRhDW
 {
@@ -49,39 +47,8 @@ namespace XdCxRhDW
                 {
                     e.Value = "(全选)";
                 }
-
-            }
-            else if (e.StringIDType == typeof(GridStringId))
-            {
-
-            }
-            else if (e.StringIDType == typeof(BarString))
-            {
-            }
-            else if (e.StringIDType == typeof(DocumentManagerStringId))
-            {
-
-            }
-            else if (e.StringIDType == typeof(LayoutStringId))
-            {
-            }
-            else if (e.StringIDType == typeof(MapStringId))
-            {
-            }
-            else if (e.StringIDType == typeof(FilteringLocalizerStringId))
-            {
-
-            }
-            else if (e.StringIDType == typeof(FilterUIElementLocalizerStringId))
-            {
-            }
-            else
-            {
             }
         }
-
-
-
     }
     class ChsControlLocalizer : Localizer
     {
@@ -117,6 +84,10 @@ namespace XdCxRhDW
                     return "输入搜索文本...";
                 case StringId.TabHeaderButtonClose:
                     return "关闭选项卡";
+                case StringId.OK:
+                    return "确定";
+                case StringId.Cancel:
+                    return "取消";
             }
             var res = base.GetLocalizedString(id);
             return res;

+ 2 - 1
XdCxRhDW.App/UserControl/CtrlHome.cs

@@ -867,7 +867,7 @@ namespace XdCxRhDW.App.UserControl
                         dto.TaskName = tsk.TaskName;
                         dto.PosType = (EnumPosTypeDto)(int)tsk.PosType;
                         dto.SigType = (EnumSigTypeDto)(int)tsk.SigType;
-                        dto.TaskCheckType = (EnumTaskCheckTypeDto)(int)tsk.DetectionWay.Value;
+                        dto.TaskCheckType = tsk.DetectionWay.HasValue?(EnumTaskCheckTypeDto)(int)tsk.DetectionWay.Value: EnumTaskCheckTypeDto.DAMA;
                         dto.CapDir = tsk.CapDir;
                         dto.DateDirFormat = tsk.CapDirFormat;
                         var strs = tsk.HistoryFrequpMHz.Split(',');
@@ -877,6 +877,7 @@ namespace XdCxRhDW.App.UserControl
                         if (res.code != 200)
                         {
                             DxHelper.MsgBoxHelper.ShowWarning($"下发启动历史任务的服务失败{res.msg}");
+                            return;
                         }
                     }
                     using (RHDWContext db = new RHDWContext())

+ 1 - 0
XdCxRhDW.TaskServer/Controllers/HistoryTaskProcessingController.cs

@@ -42,6 +42,7 @@ namespace XdCxRhDW.TaskServer.Controllers
 
                 _service.allTask.RemoveAll(a => a.IsRuning == false);
                 LogHelper.Info($"接收到历史任务编号:{dto.ID}");
+                //dto.ID = 1;
                 //dto.StartTime = new DateTime(2024, 03, 24, 12, 00, 00);
                 //dto.DateDirFormat = "yyyyMMddHH";
                 //dto.CapDir = @"D:\\data";

+ 23 - 0
XdCxRhDW.TaskServer/Task/ExtractRes.cs

@@ -0,0 +1,23 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using XdCxRhDW.Dto;
+
+namespace XdCxRhDW.TaskServer.Task
+{
+    public class ExtractRes
+    {
+        /// <summary>
+        /// 提取检测文件
+        /// </summary>
+        public string file { get; set; }
+        
+
+        /// <summary>
+        /// 提取时隙位置
+        /// </summary>
+        public List<SmpPosition>  positions { get; set; }
+    }
+}

+ 98 - 3
XdCxRhDW.TaskServer/Task/HistoryTaskI.cs

@@ -1,12 +1,9 @@
 using DevExpress.Utils.Extensions;
-using DevExpress.XtraPrinting.Native.Properties;
 using System;
 using System.Collections.Generic;
-using System.ComponentModel.DataAnnotations;
 using System.Configuration;
 using System.IO;
 using System.Linq;
-using System.Text;
 using System.Threading.Tasks;
 using XdCxRhDW;
 using XdCxRhDW.Dto;
@@ -175,6 +172,33 @@ namespace XdCxRhDW.TaskServer.Task
             }
         }
 
+        //CPU多检测计算
+        public async Task<List<CpuCgResDto>> CPUCalcAsync(string file1, string file2, double fsHz, List<SmpPosition> smps, double dtCenter, double dtRange)
+        {
+            string step = "CPU计算";
+            CpuCgMultiDto dto = new CpuCgMultiDto();
+            dto.file1 = await UploadFileAsync(step, file1);
+            dto.file2 = await UploadFileAsync(step, file2);
+            dto.smpPositions = smps;
+            dto.samplingRate = fsHz;
+            dto.dtCenter = dtCenter;
+            dto.dtRange = dtRange;
+            dto.snrThreshold = 14;
+            try
+            {
+                var result = await HttpHelper.PostRequestAsync<List<CpuCgResDto>>(baseUrl + "DetectCg/CpuCgMultiCalc", dto);
+                if (result.code != 200)
+                {
+                    throw new Exception($"CPU文件参估出错,{result.msg}");
+
+                }
+                return result.data;
+            }
+            catch (Exception ex)
+            {
+                throw new Exception($"CPU文件参估出错,{ex.Message}");
+            }
+        }
         //GPU计算
         public async Task<GpuCgResponseDto> GPUCalcAsync(string file1, string file2, double fsHz, double dtCenter, double dtRange)
         {
@@ -205,8 +229,79 @@ namespace XdCxRhDW.TaskServer.Task
                 throw new Exception($"GPU文件参估出错{ex.Message}");
             }
         }
+        /// <summary>
+        /// 提取检测时隙数据
+        /// </summary>
+        /// <param name="file"></param>
+        /// <param name="fsHz"></param>
+        /// <param name="smps"></param>
+        /// <param name="dtCenter"></param>
+        /// <param name="dtRange"></param>
+        /// <param name="Ch"></param>
+        /// <returns></returns>
+        public async Task<ExtractRes> ExtractMergeAsync(string file, double fsHz, List<SmpPosition> smps, double dtCenter, double dtRange, int Ch)
+        {
+            long offset = 0;
+            long zero = 0;
+            if (Ch == 2)//主星
+            {
+                zero = 0;
+            }
+            else if (Ch != 2 && dtCenter == 0)//三星信号文件
+            {
+                zero = Convert.ToInt64(dtRange * 1e-6 * fsHz) / 2;
+            }
+            else//地信号文件
+            {
+                zero = Convert.ToInt64(dtRange * 1e-6 * fsHz) / 2;
+                offset = Convert.ToInt64(0.26 * fsHz);
+            }
+
+            string detectFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "MultiDetect");
+            Directory.CreateDirectory(detectFolder);
 
+            string outfile = Path.Combine(detectFolder, Path.GetFileNameWithoutExtension(file) + "_de" + Path.GetExtension(file));
 
 
+            ExtractRes res = new ExtractRes();
+            res.file = outfile;
+
+            List<SmpPosition> smpp = new List<SmpPosition>();
+            // 从指定位置开始读取数据
+            using (FileStream fileStream = new FileStream(file, FileMode.Open, FileAccess.Read))
+            {
+                byte[] bytes = new byte[fileStream.Length];
+
+                foreach (var smp in smps)
+                {
+                  
+                        long start = (smp.smpStart - zero - offset) * 4;
+                        int length = Convert.ToInt32(smp.smpCount + zero * 2 - offset) * 4;
+
+                        if (start < 0 || length < 0 || length > fileStream.Length)
+                        {
+                            continue;
+                        }
+                        // 移动到文件的指定位置
+                        fileStream.Seek(start, SeekOrigin.Begin);
+
+                        byte[] buffer = new byte[length];
+                        // 读取指定长度的数据
+                        int bytesRead = await fileStream.ReadAsync(buffer, 0, buffer.Length);
+
+                        Array.ConstrainedCopy(buffer, 0, bytes, (int)start, bytesRead);
+                        smpp.Add(smp);
+                   
+                }
+                using (FileStream wrStream = new FileStream(outfile, FileMode.Create, FileAccess.ReadWrite))
+                {
+                    await wrStream.WriteAsync(bytes, 0, bytes.Length);
+                }
+
+            }
+            res.positions = smpp;
+            return res;
+
+        }
     }
 }

+ 42 - 22
XdCxRhDW.TaskServer/Task/X2D1Task.cs

@@ -1,23 +1,16 @@
-using DevExpress.Utils.About;
-using MySql.Data.MySqlClient;
-using System;
+using System;
 using System.Collections.Generic;
 using System.Globalization;
 using System.IO;
 using System.Linq;
-using System.Security.Policy;
-using System.Text;
 using System.Threading;
 using System.Threading.Tasks;
-using XdCxRhDW;
 using XdCxRhDW.Dto;
-using ZstdSharp.Unsafe;
 
 namespace XdCxRhDW.TaskServer.Task
 {
     public class X2D1Task : HistoryTaskI
     {
-
         public override void Start(HistoryTaskProcessingDto dto)
         {
             IsRuning = true;
@@ -115,24 +108,51 @@ namespace XdCxRhDW.TaskServer.Task
                                 var mDetect = await DAMAAsync(dto.TaskCheckType, minfo.FsHz, minfo.FilePath);
                                 var dfile = await ToResampleAsync((int)dinfo.FsHz, dinfo.FilePath);
                                 var nfile = await ToResampleAsync((int)ninfo.FsHz, ninfo.FilePath);
-                                foreach (var deitem in mDetect)
+
+                                if (mDetect.Count() <= 0)
                                 {
+                                    LogHelper.Info($"历史任务:{dto.ID}文件{minfo.FilePath}未检测出结果");
+                                    continue;
+                                }
+                                //主星文件
+                                string mfile = mDetect.First().File1;
+
+                                //时隙数
+                                var smps = mDetect.Select(m => new SmpPosition() { smpStart = m.Start, smpCount = m.Length }).ToList();
+
+                                int dtRange = 40000;
+
+                                //提取时隙有效数据
+                                //var mdfile = await ExtractMergeAsync(mfile, nfile.OutFsHz, smps, 0, dtRange, minfo.Ch);
+                                //var ddfile = await ExtractMergeAsync(dfile.File, nfile.OutFsHz, smps, -260000, dtRange, dinfo.Ch);
+                                //var ndfile = await ExtractMergeAsync(nfile.File, nfile.OutFsHz, smps, 0, dtRange, ninfo.Ch);
+
+                                //var xds = await CPUCalcAsync(mdfile.file, ddfile.file, dfile.OutFsHz, ddfile.positions, -260000, dtRange);
+                                //var sxs = await CPUCalcAsync(mdfile.file, ndfile.file, nfile.OutFsHz, ndfile.positions, 0, dtRange);
+
+
+
+                                var xds = await CPUCalcAsync(mfile, dfile.File, dfile.OutFsHz, smps, -260000, dtRange);
+                                var sxs = await CPUCalcAsync(mfile, nfile.File, nfile.OutFsHz, smps, 0, dtRange);
+
+                                foreach (var sxitem in sxs)
+                                {
+                                    var xd = xds.FirstOrDefault(x => x.Smpstart == sxitem.Smpstart && x.Smplen == sxitem.Smplen);
+                                    var deitem = mDetect.FirstOrDefault(x => x.Start == sxitem.Smpstart && x.Length == sxitem.Smplen);
                                     if (!IsRuning)
                                     {
                                         break;
                                     }
                                     try
                                     {
-                                        var xd = await CPUCalcAsync(deitem.File1, dfile.File, dfile.OutFsHz, deitem, 260000, 40000);
-                                        Thread.Sleep(100);
-                                        var sx = await CPUCalcAsync(deitem.File1, nfile.File, nfile.OutFsHz, deitem, 0, 40000);
                                         X2D1NoXlPosDto x2D1 = new X2D1NoXlPosDto()
                                         {
-                                            SigTime = minfo.CapTime.AddSeconds(deitem.Start / nfile.OutFsHz),
+                                            TaskID = dto.ID,
+                                            SigTime = minfo.CapTime.AddSeconds(sxitem.Smpstart / nfile.OutFsHz),
                                             MainCode = minfo.SatId,
                                             AdjaCode = ninfo.SatId,
-                                            SxDto = sx.Dt,
-                                            XdDto = xd.Dt,
+                                            SxDto = sxitem.Dt,
+                                            XdDto = xd == null ? 0 : xd.Dt,
                                             SatTxLon = satTx.Lon,
                                             SatTxLat = satTx.Lat,
                                             CdbTxLon = cdbTx.Lon,
@@ -141,10 +161,10 @@ namespace XdCxRhDW.TaskServer.Task
                                             RefLat = refTx.Lat,
                                             FreqDown = minfo.FreqHz * 1e-6,
                                             FreqUp = dinfo.FreqHz * 1e-6,
-                                            XdDfo = xd.Df,
-                                            XdSnr = xd.Snr,
-                                            SxDfo = sx.Df,
-                                            SxSnr = sx.Snr,
+                                            XdDfo = xd == null ? 0 : xd.Df,
+                                            XdSnr = xd == null ? 0 : xd.Snr,
+                                            SxDfo = sxitem.Df,
+                                            SxSnr = sxitem.Snr,
                                             CheckRes = new CheckResDto()
                                             {
                                                 FileName = deitem.File1,
@@ -156,7 +176,6 @@ namespace XdCxRhDW.TaskServer.Task
                                                 PosCheckType = deitem.DmcType.GetEnumByDisplayName<EnumPosCheckTypeDto>(),
                                             }
                                         };
-
                                         await X2D1NoXlAsync(x2D1);
                                     }
                                     catch (Exception ex)
@@ -164,8 +183,8 @@ namespace XdCxRhDW.TaskServer.Task
                                         LogHelper.Info($"历史任务:{dto.ID}异常:{ex.Message}");
                                         continue;
                                     }
-
                                 }
+
                             }
                         }
                         catch (Exception ex)
@@ -187,6 +206,7 @@ namespace XdCxRhDW.TaskServer.Task
             var result = await HttpHelper.PostRequestAsync<PosResDto>(baseUrl + "Pos/PosX2D1NoXlAsync", x2D1);
             if (result.code != 200)
             {
+                LogHelper.Error($"推送历史任务定位结果:{x2D1.TaskID}异常:{result.msg}");
                 return false;
             }
             return true;
@@ -253,7 +273,7 @@ namespace XdCxRhDW.TaskServer.Task
             historyFile.FsHz = fsHz;
             if (ch > 1)
             {
-                historyFile.SatId = GetSatId(historyFile.FreqHz);
+                historyFile.SatId = 44637;// GetSatId(historyFile.FreqHz);
 
             }
             return historyFile;

+ 1 - 0
XdCxRhDW.TaskServer/XdCxRhDW.TaskServer.csproj

@@ -160,6 +160,7 @@
       <DependentUpon>MainForm.cs</DependentUpon>
     </Compile>
     <Compile Include="Service\HistoryTaskService.cs" />
+    <Compile Include="Task\ExtractRes.cs" />
     <Compile Include="Task\HistoryFile.cs" />
     <Compile Include="Task\HistoryTaskI.cs" />
     <Compile Include="Task\TxInfo.cs" />

+ 1 - 0
XdCxRhDw.Dto/02.XdCxRhDW.Dto.csproj

@@ -53,6 +53,7 @@
     <Compile Include="Attribute\FileMustExistAttribute.cs" />
     <Compile Include="Attribute\Pow2Attribute.cs" />
     <Compile Include="Attribute\RangeAttribute.cs" />
+    <Compile Include="CpuCgMultiDto.cs" />
     <Compile Include="GpuCgDto.cs" />
     <Compile Include="CpuCgDto.cs" />
     <Compile Include="FileDownloadDto.cs" />

+ 88 - 0
XdCxRhDw.Dto/CpuCgMultiDto.cs

@@ -0,0 +1,88 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using XdCxRhDW.Dto.Attribute;
+
+namespace XdCxRhDW.Dto
+{
+    public class CpuCgMultiDto
+    {
+        /// <summary>
+        /// 上传后返回的文件名
+        /// </summary>
+        [FileMustExist]
+        public string file1 { get; set; }
+
+        /// <summary>
+        /// 上传后返回的文件名
+        /// </summary>
+        [FileMustExist]
+        public string file2 { get; set; }
+
+        /// <summary>
+        /// 样点位置
+        /// </summary>
+
+        public List<SmpPosition> smpPositions { get; set; }  
+        /// <summary>
+        /// 采样率(Hz)
+        /// </summary>
+        [RangeDouble(0, 100e6)]
+        public double samplingRate { get; set; }
+
+        /// <summary>
+        /// 时差中心(us)
+        /// </summary>
+        public double dtCenter { get; set; }
+
+        /// <summary>
+        /// 时差范围(us)
+        /// </summary>
+        [RangeDouble(0, 100000)]
+        public double dtRange { get; set; }
+
+        /// <summary>
+        /// 频差范围(单位Hz,默认16384)
+        /// </summary>
+        [Pow2]
+        public double dfRange { get; set; } = 16384;
+
+        /// <summary>
+        /// 信噪比门限dB
+        /// </summary>
+        [RangeDouble(10, 50, IncludeMin = true)]
+        public double snrThreshold { get; set; }
+
+        /// <summary>
+        /// 模型参数自定义验证(复杂的验证逻辑在这里面写)
+        /// </summary>
+        /// <param name="validationContext"></param>
+        /// <returns></returns>
+        public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
+        {
+            //if (this.Age<18)
+            //    yield return new ValidationResult("你太年轻了", new[] { nameof(this.Age) });
+            yield return null;
+        }
+    }
+
+    public class SmpPosition
+    {
+        /// <summary>
+        /// 开始样点
+        /// </summary>
+        [RangeLong(0, IncludeMin = true)]
+        public long smpStart { get; set; }
+
+        /// <summary>
+        /// 样点数
+        /// </summary>
+        [RangeLong(0, IncludeMin = true)]
+        public long smpCount { get; set; }
+
+
+    }
+}