commit
c527abf326
|
|
@ -0,0 +1,9 @@
|
|||
.stfolder
|
||||
bin
|
||||
obj
|
||||
Newtonsoft.Json*
|
||||
nuget.exe
|
||||
ILMerge*
|
||||
example
|
||||
*.sln
|
||||
*.suo
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("NWEPDI")]
|
||||
[assembly: AssemblyProduct("")]
|
||||
[assembly: AssemblyCopyright("Copyright © NWEPDI 2018")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("d70bd3b9-6432-4f15-8adf-c4a6fd9239d8")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:2.0.50727.8689
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace PutTowerPostion.Properties {
|
||||
|
||||
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "9.0.0.0")]
|
||||
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
|
||||
|
||||
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||
|
||||
public static Settings Default {
|
||||
get {
|
||||
return defaultInstance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
|
||||
<Profiles />
|
||||
<Settings />
|
||||
</SettingsFile>
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>9.0.21022</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{CA8FB7A3-CEB6-471C-BB97-76CBFA17293C}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>PutTowerPostion</RootNamespace>
|
||||
<AssemblyName>PutTowerPostion</AssemblyName>
|
||||
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<StartAction>Program</StartAction>
|
||||
<StartProgram>C:\Program Files\AutoCAD 2010\acad.exe</StartProgram>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="acdbmgd, Version=18.0.0.0, Culture=neutral, processorArchitecture=x86">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>C:\Program Files\AutoCAD 2010\acdbmgd.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="acmgd, Version=18.0.0.0, Culture=neutral, processorArchitecture=x86">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>C:\Program Files\AutoCAD 2010\acmgd.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Office.Interop.Excel, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>C:\Program Files (x86)\Microsoft Office\root\Office16\ADDINS\Microsoft Power Query for Excel Integrated\bin\Microsoft.Office.Interop.Excel.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=11.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>Newtonsoft.Json.11.0.2\lib\net35\Newtonsoft.Json.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core">
|
||||
<RequiredTargetFramework>3.5</RequiredTargetFramework>
|
||||
</Reference>
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xml.Linq">
|
||||
<RequiredTargetFramework>3.5</RequiredTargetFramework>
|
||||
</Reference>
|
||||
<Reference Include="System.Data.DataSetExtensions">
|
||||
<RequiredTargetFramework>3.5</RequiredTargetFramework>
|
||||
</Reference>
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="cmd.cs" />
|
||||
<Compile Include="Config.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Properties\Settings.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||
<DependentUpon>Settings.settings</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Utils.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Properties\Settings.settings">
|
||||
<Generator>SettingsSingleFileGenerator</Generator>
|
||||
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<EnableUnmanagedDebugging>false</EnableUnmanagedDebugging>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<ProjectView>ProjectFiles</ProjectView>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace PutTowerPosition
|
||||
{
|
||||
class Utils
|
||||
{
|
||||
static public String NormDirectoryPath(String path)//把文件路径标准化为c:/abc/c的格式
|
||||
{
|
||||
String newPath = path.Trim();
|
||||
newPath = newPath.Replace('\\', '/');
|
||||
if ('/' == newPath[newPath.Length - 1])
|
||||
{
|
||||
newPath = newPath.Remove(newPath.Length - 1);
|
||||
}
|
||||
return newPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,344 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Autodesk.AutoCAD.Runtime;
|
||||
using Autodesk.AutoCAD.ApplicationServices;
|
||||
using Autodesk.AutoCAD.DatabaseServices;
|
||||
using Autodesk.AutoCAD.EditorInput;
|
||||
using Autodesk.AutoCAD.Geometry;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Windows.Forms;
|
||||
using System.Security.Cryptography;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
|
||||
[assembly: CommandClass(typeof(PutTowerPosition.Cmd))]
|
||||
namespace PutTowerPosition
|
||||
{
|
||||
|
||||
|
||||
public class Cmd
|
||||
{
|
||||
struct spanStruct
|
||||
{
|
||||
|
||||
public string towerName;
|
||||
public double span;
|
||||
};
|
||||
|
||||
struct Point2D
|
||||
{
|
||||
public double X;
|
||||
public double Y;
|
||||
};
|
||||
|
||||
public void PutTowerPositionCmd()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
[CommandMethod("ptp", CommandFlags.Session)]
|
||||
public static void PutTowerPosition()
|
||||
{
|
||||
string excelFile = findCordinationExcel(@"d:\code\PutTowerPosition\example\S000.DAT");
|
||||
Dictionary<string, double[]> cordDic = readCordExcel(excelFile);
|
||||
List<spanStruct> spanList = readSSpan(@"d:\code\PutTowerPosition\example\S000.DAT");
|
||||
Document acDoc;
|
||||
Database acCurDb;
|
||||
//acDoc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.Open(filePath, true);
|
||||
acDoc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
|
||||
using (DocumentLock acLckDoc = acDoc.LockDocument())
|
||||
{
|
||||
acCurDb = acDoc.Database;
|
||||
GetOrCreateLayer("TW", acCurDb);
|
||||
using (Transaction acTrans = acCurDb.TransactionManager.StartTransaction())
|
||||
{
|
||||
|
||||
BlockTable acBlkTbl;
|
||||
acBlkTbl = acTrans.GetObject(acCurDb.BlockTableId,
|
||||
|
||||
OpenMode.ForWrite) as BlockTable;
|
||||
BlockTableRecord acBlkTblRec;
|
||||
|
||||
acBlkTblRec = acTrans.GetObject(acBlkTbl[BlockTableRecord.ModelSpace],
|
||||
|
||||
OpenMode.ForWrite) as BlockTableRecord;
|
||||
|
||||
Point2D[] cordinationList = calTowerXYPostion(cordDic, spanList);
|
||||
foreach (Point2D point in cordinationList)
|
||||
{
|
||||
DBPoint dbPoint = new DBPoint(new Point3d(point.Y, point.X, 0));
|
||||
dbPoint.Layer = "TW";
|
||||
acBlkTblRec.AppendEntity(dbPoint);
|
||||
acTrans.AddNewlyCreatedDBObject(dbPoint, true);
|
||||
acCurDb.Pdmode = 35;
|
||||
acCurDb.Pdsize = 15;
|
||||
|
||||
//break;
|
||||
}
|
||||
acTrans.Commit();
|
||||
}
|
||||
//acBlkTblRec.Database.SaveAs(outputFilePath, false, DwgVersion.Current, acDoc.Database.SecurityParameters);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
private bool UnlockAllLayer(Document doc)
|
||||
{
|
||||
var acCurDb = doc.Database;
|
||||
//var ed = doc.Editor;
|
||||
LayerTableRecord ltr = null;
|
||||
using (var acTrans = acCurDb.TransactionManager.StartTransaction())
|
||||
{
|
||||
LayerTable layerTable;
|
||||
|
||||
layerTable = acTrans.GetObject(acCurDb.LayerTableId, OpenMode.ForWrite) as LayerTable;
|
||||
|
||||
foreach (ObjectId ltrId in layerTable)
|
||||
{
|
||||
// Don't try to lock/unlock either the current layer or layer 0
|
||||
// (depending on whether lockZero == true for the latter)
|
||||
ltr = (LayerTableRecord)acTrans.GetObject(ltrId, OpenMode.ForWrite);
|
||||
ltr.IsLocked = false;
|
||||
//ltr.IsOff = ltr.IsOff; // This is needed to force a graphics update
|
||||
|
||||
}
|
||||
acTrans.Commit();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static private LayerTableRecord GetOrCreateLayer(string layerName, Database db)
|
||||
{
|
||||
LayerTableRecord ltr;
|
||||
using (Transaction tr = db.TransactionManager.StartTransaction())
|
||||
{
|
||||
|
||||
LayerTable lt =
|
||||
|
||||
(LayerTable)tr.GetObject(
|
||||
|
||||
db.LayerTableId,
|
||||
|
||||
OpenMode.ForRead
|
||||
|
||||
);
|
||||
if (lt.Has(layerName))
|
||||
{
|
||||
ObjectId ltId = lt[layerName];
|
||||
ltr = (LayerTableRecord)tr.GetObject(ltId, OpenMode.ForWrite);
|
||||
}
|
||||
else
|
||||
{
|
||||
ltr = new LayerTableRecord();
|
||||
ltr.Name = layerName;
|
||||
lt.UpgradeOpen();
|
||||
ObjectId ltId = lt.Add(ltr);
|
||||
tr.AddNewlyCreatedDBObject(ltr, true);
|
||||
|
||||
}
|
||||
tr.Commit();
|
||||
}
|
||||
|
||||
return ltr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static ObjectIdCollection GetEntitiesOnLayer(Document acDoc, string layerName)
|
||||
{
|
||||
|
||||
//Document doc =
|
||||
|
||||
//Application.DocumentManager.MdiActiveDocument;
|
||||
|
||||
Editor ed = acDoc.Editor;
|
||||
|
||||
// Build a filter list so that only entities
|
||||
|
||||
// on the specified layer are selected
|
||||
|
||||
TypedValue[] tvs =
|
||||
|
||||
new TypedValue[1] {
|
||||
|
||||
new TypedValue(
|
||||
|
||||
(int)DxfCode.LayerName,
|
||||
|
||||
layerName
|
||||
|
||||
)
|
||||
|
||||
};
|
||||
|
||||
SelectionFilter sf =
|
||||
|
||||
new SelectionFilter(tvs);
|
||||
|
||||
PromptSelectionResult psr =
|
||||
|
||||
ed.SelectAll(sf);
|
||||
|
||||
if (psr.Status == PromptStatus.OK)
|
||||
|
||||
return
|
||||
|
||||
new ObjectIdCollection(
|
||||
|
||||
psr.Value.GetObjectIds()
|
||||
|
||||
);
|
||||
|
||||
else
|
||||
|
||||
return new ObjectIdCollection();
|
||||
|
||||
}
|
||||
|
||||
static string findCordinationExcel(string findDirOrFile)
|
||||
{
|
||||
string dir = findDirOrFile;
|
||||
FileAttributes attr = File.GetAttributes(findDirOrFile);
|
||||
if ((attr & FileAttributes.Directory) > 0)
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
dir = Path.GetDirectoryName(findDirOrFile);
|
||||
}
|
||||
|
||||
string cordExcelFile = dir + "/cord.xlsx";
|
||||
return cordExcelFile;
|
||||
}
|
||||
static private object get_value(Microsoft.Office.Interop.Excel.Worksheet sheet, string str_rang)
|
||||
{
|
||||
return sheet.get_Range(str_rang, Missing.Value).Value2;
|
||||
}
|
||||
static Dictionary<string, double[]> readCordExcel(string excelFilePath)
|
||||
{
|
||||
//TowerName X Y
|
||||
Microsoft.Office.Interop.Excel.Application objApp;
|
||||
Microsoft.Office.Interop.Excel._Workbook objBook;
|
||||
Microsoft.Office.Interop.Excel.Worksheet w_sheet;
|
||||
objApp = new Microsoft.Office.Interop.Excel.Application();
|
||||
objBook = objApp.Application.Workbooks.Add(excelFilePath);
|
||||
w_sheet = objBook.Sheets[1] as Microsoft.Office.Interop.Excel.Worksheet;
|
||||
Dictionary<string, double[]> towerCordination = new Dictionary<string, double[]>();
|
||||
for (int i = 1; i < 10000; i++)
|
||||
{
|
||||
string towerName = (string)(get_value(w_sheet, "A" + i.ToString()));
|
||||
if (towerName == null || towerName.Trim() == "")
|
||||
{
|
||||
break;
|
||||
}
|
||||
double[] cordination = new double[2];
|
||||
cordination[0] = (double)(get_value(w_sheet, "B" + i.ToString()));
|
||||
cordination[1] = (double)(get_value(w_sheet, "C" + i.ToString()));
|
||||
towerCordination.Add(towerName, cordination);
|
||||
}
|
||||
return towerCordination;
|
||||
|
||||
}
|
||||
|
||||
static List<spanStruct> readSSpan(string SFilePath)
|
||||
{
|
||||
StreamReader reader = new StreamReader(SFilePath, Encoding.GetEncoding("gb2312"));
|
||||
string line;
|
||||
double basicMileage = -1;
|
||||
List<spanStruct> spanList = new List<spanStruct>();
|
||||
Dictionary<string, char> has_tower = new Dictionary<string, char>();
|
||||
while ((line = reader.ReadLine()) != null)
|
||||
{
|
||||
if (line.Trim().StartsWith("首端") | line.Trim().StartsWith("塔号"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (line.Trim() == "")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
string norm_line;
|
||||
norm_line = Regex.Replace(line, @"\s+", ",");
|
||||
norm_line = norm_line.Substring(1);
|
||||
string[] sep = norm_line.Split(',');
|
||||
string towerName = sep[0];
|
||||
if (has_tower.ContainsKey(towerName))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
has_tower.Add(towerName, ' ');
|
||||
double mileage = Double.Parse(sep[1]);
|
||||
double span;
|
||||
if (basicMileage == -1)
|
||||
{
|
||||
basicMileage = mileage;
|
||||
}
|
||||
span = mileage - basicMileage;
|
||||
spanStruct _span;
|
||||
_span.towerName = towerName;
|
||||
_span.span = span;
|
||||
spanList.Add(_span);
|
||||
basicMileage = mileage;
|
||||
|
||||
}
|
||||
reader.Close();
|
||||
return spanList;
|
||||
}
|
||||
|
||||
static Point2D[] calTowerXYPostion(Dictionary<string, double[]> cordDic, List<spanStruct> SSpan)
|
||||
{
|
||||
Point2D[] cordinationList = new Point2D[SSpan.Count];
|
||||
Point2D startPoint;
|
||||
int tensionStart;//耐张段第一基塔位置
|
||||
tensionStart = 0;
|
||||
//find next end point
|
||||
Point2D endPoint;
|
||||
while (true)
|
||||
{
|
||||
startPoint.X = cordDic[SSpan[tensionStart].towerName][0];
|
||||
startPoint.Y = cordDic[SSpan[tensionStart].towerName][1];
|
||||
for (int i = tensionStart+1; i < SSpan.Count; i++)
|
||||
{
|
||||
string towerName;
|
||||
towerName = SSpan[i].towerName;
|
||||
if (cordDic.ContainsKey(towerName))
|
||||
{
|
||||
endPoint.X = cordDic[towerName][0];
|
||||
endPoint.Y = cordDic[towerName][1];
|
||||
cordinationList[tensionStart] = startPoint;
|
||||
double mileageInTension=0;//耐张段中的里程
|
||||
for (int j = tensionStart + 1; j < i; j++)
|
||||
{
|
||||
Point2D suspensionTowerPostion;
|
||||
double tensionLength;//耐张段长度
|
||||
tensionLength = Math.Sqrt(Math.Pow(endPoint.X - startPoint.X, 2) + Math.Pow(endPoint.Y - startPoint.Y, 2));
|
||||
mileageInTension += SSpan[j].span;
|
||||
suspensionTowerPostion.X = startPoint.X + (endPoint.X - startPoint.X) / tensionLength * mileageInTension;
|
||||
suspensionTowerPostion.Y = startPoint.Y + (endPoint.Y - startPoint.Y) / tensionLength * mileageInTension;
|
||||
cordinationList[j]=suspensionTowerPostion;
|
||||
}
|
||||
cordinationList[i] = endPoint;
|
||||
tensionStart = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (tensionStart >= (SSpan.Count - 1))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return cordinationList;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue