Compare commits

...

12 Commits

Author SHA1 Message Date
Diego
29365c4ef9 修改脚本测试方法 2025-06-14 11:56:31 +08:00
Diego
17a6189089 style: 更新SysResourcePage页面样式 2025-06-13 16:03:28 +08:00
Diego
003b8a3763 10.7.56 2025-06-13 13:35:38 +08:00
Diego
1c7f8b5cab 10.7.55 2025-06-13 09:14:22 +08:00
Diego
b7ff9ffca2 更新解决方案 2025-06-13 09:06:42 +08:00
Diego
9bba9bda76 10.7.54 2025-06-12 23:54:10 +08:00
Diego
ec2fcc75d3 合并代码 2025-06-12 20:21:50 +08:00
Diego
57a4038577 pwa安装提示优化 2025-06-12 10:20:52 +08:00
Diego
b78a76e60f 增加采集设备写入数据的控制台文本日志 2025-06-11 23:49:37 +08:00
Diego
28bd751d44 增加tab右键菜单 2025-06-11 22:57:00 +08:00
Diego
dcba7b9810 10.7.50 2025-06-11 21:50:46 +08:00
Diego
7f1a741ce6 优化sql实时表执行性能 2025-06-11 21:39:14 +08:00
352 changed files with 2082 additions and 1678 deletions

View File

@@ -20,6 +20,7 @@ using System.Collections.Concurrent;
using ThingsGateway.Extension;
using ThingsGateway.FriendlyException;
using ThingsGateway.NewLife.Json.Extension;
using ThingsGateway.SqlSugar;
namespace ThingsGateway.Admin.Application;
@@ -90,13 +91,12 @@ public sealed class OperDescAttribute : MoAttribute
OperDescAttribute.WriteToQueue(log);
}
}
private static SqlSugarClient _db = DbContext.Db.GetConnectionScopeWithAttr<SysOperateLog>().CopyNew();
/// <summary>
/// 将日志消息写入数据库中
/// </summary>
private static async Task ProcessQueue()
{
var db = DbContext.Db.GetConnectionScopeWithAttr<SysOperateLog>().CopyNew();
var appLifetime = App.RootServices!.GetService<IHostApplicationLifetime>()!;
while (!appLifetime.ApplicationStopping.IsCancellationRequested)
{
@@ -105,7 +105,7 @@ public sealed class OperDescAttribute : MoAttribute
var data = _logMessageQueue.ToListWithDequeue(); // 从日志队列中获取数据
if (data.Count > 0)
{
await db.InsertableWithAttr(data).ExecuteCommandAsync(appLifetime.ApplicationStopping).ConfigureAwait(false);//入库
await _db.InsertableWithAttr(data).ExecuteCommandAsync(appLifetime.ApplicationStopping).ConfigureAwait(false);//入库
}
}
catch (Exception ex)

View File

@@ -20,6 +20,7 @@ using ThingsGateway.NewLife;
using ThingsGateway.NewLife.Caching;
using ThingsGateway.NewLife.Threading;
using ThingsGateway.Schedule;
using ThingsGateway.SqlSugar;
namespace ThingsGateway.Admin.Application;
@@ -60,7 +61,7 @@ public class HardwareJob : IJob, IHardwareJob
var historyHardwareInfos = MemoryCache.Get<List<HistoryHardwareInfo>>(CacheKey);
if (historyHardwareInfos == null)
{
using var db = DbContext.Db.GetConnectionScopeWithAttr<HistoryHardwareInfo>().CopyNew();
using var db = _db.CopyNew();
historyHardwareInfos = await db.Queryable<HistoryHardwareInfo>().Where(a => a.Date > DateTime.Now.AddDays(-3)).ToListAsync().ConfigureAwait(false);
MemoryCache.Set(CacheKey, historyHardwareInfos);
@@ -70,6 +71,7 @@ public class HardwareJob : IJob, IHardwareJob
private bool error = false;
private DateTime hisInsertTime = default;
private SqlSugarClient _db = DbContext.Db.GetConnectionScopeWithAttr<HistoryHardwareInfo>().CopyNew();
public async Task ExecuteAsync(JobExecutingContext context, CancellationToken stoppingToken)
{
@@ -121,7 +123,6 @@ public class HardwareJob : IJob, IHardwareJob
if (DateTime.Now > hisInsertTime.Add(TimeSpan.FromMilliseconds(HardwareInfoOptions.HistoryInterval)))
{
hisInsertTime = DateTime.Now;
using var db = DbContext.Db.GetConnectionScopeWithAttr<HistoryHardwareInfo>().CopyNew();
{
var his = new HistoryHardwareInfo()
{
@@ -132,12 +133,12 @@ public class HardwareJob : IJob, IHardwareJob
CpuUsage = (HardwareInfo.MachineInfo.CpuRate * 100).ToInt(),
Temperature = (HardwareInfo.MachineInfo.Temperature).ToInt(),
};
await db.Insertable(his).ExecuteCommandAsync(stoppingToken).ConfigureAwait(false);
await _db.Insertable(his).ExecuteCommandAsync(stoppingToken).ConfigureAwait(false);
MemoryCache.Remove(CacheKey);
}
var sevenDaysAgo = TimerX.Now.AddDays(-HardwareInfoOptions.DaysAgo);
//删除特定信息
var result = await db.Deleteable<HistoryHardwareInfo>(a => a.Date <= sevenDaysAgo).ExecuteCommandAsync(stoppingToken).ConfigureAwait(false);
var result = await _db.Deleteable<HistoryHardwareInfo>(a => a.Date <= sevenDaysAgo).ExecuteCommandAsync(stoppingToken).ConfigureAwait(false);
if (result > 0)
{
MemoryCache.Remove(CacheKey);

View File

@@ -18,7 +18,7 @@ public class SysRelationSeedData : ISqlSugarEntitySeedData<SysRelation>
/// <inheritdoc/>
public IEnumerable<SysRelation> SeedData()
{
var db = DbContext.Db.GetConnectionScopeWithAttr<SysRelation>().CopyNew();
using var db = DbContext.Db.GetConnectionScopeWithAttr<SysRelation>().CopyNew();
if (db.Queryable<SysRelation>().Any(a => a.ObjectId == RoleConst.SuperAdminId))
return Enumerable.Empty<SysRelation>();
var data = SeedDataUtil.GetSeedData<SysRelation>(PathExtensions.CombinePathWithOs("SeedData", "Admin", "seed_sys_relation.json"));

View File

@@ -10,7 +10,6 @@
using BootstrapBlazor.Components;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using System.Reflection;
@@ -67,7 +66,7 @@ public class Startup : AppStartup
}
public void Use(IApplicationBuilder applicationBuilder)
public void Use(IServiceProvider serviceProvider)
{
//检查ConfigId
var configIdGroup = DbContext.DbConfigs.GroupBy(it => it.ConfigId);

View File

@@ -33,7 +33,7 @@
</PopConfirmButton>
<PopConfirmButton Color=Color.Warning IsDisabled="SelectedRows.Count!=1||!AuthorizeButton(AdminOperConst.Edit)" Text=@OperDescLocalizer["ChangeParentResource"] Icon="fa fa-copy" OnConfirm="OnChangeParent">
<BodyTemplate>
<div class="min-height-500 overflow-y-auto">
<div class="overflow-y-auto" style="height:500px">
<TreeView Items="MenuTreeItems" IsVirtualize="true" OnTreeItemClick="a=>{ChangeParentId=a.Value.Id;return Task.CompletedTask;}" />
</div>
</BodyTemplate>

View File

@@ -14,6 +14,7 @@
"ThingsGateway.SqlSugar",
"ThingsGateway.Admin.Application",
"ThingsGateway.Admin.Razor",
"ThingsGateway.DB",
"ThingsGateway.Razor"
]
},

View File

@@ -14,6 +14,7 @@
"ThingsGateway.SqlSugar",
"ThingsGateway.Admin.Application",
"ThingsGateway.Admin.Razor",
"ThingsGateway.DB",
"ThingsGateway.Razor"
]
},

View File

@@ -40,6 +40,7 @@ public class SingleFilePublish : ISingleFilePublish
"ThingsGateway.NewLife.X",
"ThingsGateway.Razor",
"ThingsGateway.Admin.Razor" ,
"ThingsGateway.DB",
"ThingsGateway.Admin.Application",
"ThingsGateway.SqlSugar",
];

View File

@@ -48,11 +48,11 @@ public class Startup : AppStartup
});
// 事件总线
services.AddEventBus(options =>
{
//// 事件总线
//services.AddEventBus(options =>
//{
});
//});
// 任务调度
services.AddSchedule(options =>
@@ -151,8 +151,6 @@ public class Startup : AppStartup
});
services.AddHealthChecks();
#region

View File

@@ -16,6 +16,7 @@
<!--动态适用GC-->
<GarbageCollectionAdaptationMode>1</GarbageCollectionAdaptationMode>
<CETCompat>false</CETCompat>
<!--使用自托管线程池-->
<!--<UseWindowsThreadPool>false</UseWindowsThreadPool> -->

View File

@@ -124,16 +124,8 @@ public class SugarAopService : ISugarAopService
//执行时间超过1秒
if (db.Ado.SqlExecutionTime.TotalSeconds > 1)
{
//代码CS文件名
var fileName = db.Ado.SqlStackTrace.FirstFileName;
//代码行数
var fileLine = db.Ado.SqlStackTrace.FirstLine;
//方法名
var FirstMethodName = db.Ado.SqlStackTrace.FirstMethodName;
DbContext.WriteLog($"{fileName}-{FirstMethodName}-{fileLine} 执行时间超过1秒");
DbContext.WriteLog($"SQL执行时间超过1秒");
DbContext.WriteLogWithSql(UtilMethods.GetNativeSql(sql, pars));
}
};
}

View File

@@ -66,7 +66,8 @@ public static class CodeFirstUtils
{
// 按主键进行批量增加和更新
var storage = db.StorageableByObject(seedData.ToList()).ToStorage();
if (ignoreAdd == null) storage.AsInsertable.ExecuteCommand();//执行插入
if (ignoreAdd == null)
storage.AsInsertable.ExecuteCommand();//执行插入
if (ignoreUpdate == null && config.IsUpdateSeedData) storage.AsUpdateable.ExecuteCommand();//只有没有忽略更新的特性才执行更新
}
else// 没有主键或者不是预定义的主键(有重复的可能)

View File

@@ -10,7 +10,6 @@
using BootstrapBlazor.Components;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using ThingsGateway.SqlSugar;
@@ -32,11 +31,10 @@ public class Startup : AppStartup
StaticConfig.EnableAllWhereIF = true;
services.AddSingleton<ISugarAopService, SugarAopService>();
}
public void Use(IApplicationBuilder applicationBuilder)
public void Use(IServiceProvider serviceProvider)
{

View File

@@ -67,13 +67,13 @@ internal static class Penetrates
["patch"] = "PATCH"
};
IsApiControllerCached = new ConcurrentDictionary<Type, bool>();
//IsApiControllerCached = new ConcurrentDictionary<Type, bool>();
}
/// <summary>
/// <see cref="IsApiController(Type)"/> 缓存集合
/// </summary>
private static readonly ConcurrentDictionary<Type, bool> IsApiControllerCached;
///// <summary>
///// <see cref="IsApiController(Type)"/> 缓存集合
///// </summary>
//private static readonly ConcurrentDictionary<Type, bool> IsApiControllerCached;
/// <summary>
/// 是否是Api控制器
@@ -82,8 +82,8 @@ internal static class Penetrates
/// <returns></returns>
internal static bool IsApiController(Type type)
{
return IsApiControllerCached.GetOrAdd(type, Function);
//return IsApiControllerCached.GetOrAdd(type, Function);
return Function(type);
// 本地静态方法
static bool Function(Type type)
{

View File

@@ -39,7 +39,7 @@
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />
<PackageReference Include="Mapster" Version="7.4.0" />
<PackageReference Include="MiniProfiler.AspNetCore.Mvc" Version="4.5.4" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="8.1.4" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="9.0.1" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net8.0' ">

View File

@@ -1160,7 +1160,7 @@ public class MachineInfo
public static String GetInfo(String path, String property, String? nameSpace = null)
{
// Linux Mono不支持WMI
if (Runtime.Mono) return "";
if (Runtime.Mono) return string.Empty;
var bbs = new List<String>();
try
@@ -1181,7 +1181,7 @@ public class MachineInfo
catch (Exception ex)
{
if (XTrace.Log.Level <= LogLevel.Debug) XTrace.WriteLine("WMI.GetInfo({0})失败!{1}", path, ex.Message);
return "";
return string.Empty;
}
bbs.Sort();

View File

@@ -854,13 +854,13 @@ public static class IOHelper
/// <returns></returns>
public static String ToHex(this Byte[]? data, Int32 offset = 0, Int32 count = -1)
{
if (data == null || data.Length <= 0) return "";
if (data == null || data.Length <= 0) return string.Empty;
if (count < 0)
count = data.Length - offset;
else if (offset + count > data.Length)
count = data.Length - offset;
if (count == 0) return "";
if (count == 0) return string.Empty;
//return BitConverter.ToString(data).Replace("-", null);
// 上面的方法要替换-,效率太低
@@ -883,7 +883,7 @@ public static class IOHelper
/// <returns></returns>
public static String ToHex(this Byte[]? data, String? separate, Int32 groupSize = 0, Int32 maxLength = -1)
{
if (data == null || data.Length <= 0) return "";
if (data == null || data.Length <= 0) return string.Empty;
if (groupSize < 0) groupSize = 0;

View File

@@ -8,7 +8,6 @@
// QQ群605534569
//------------------------------------------------------------------------------
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using ThingsGateway.NewLife;
@@ -59,7 +58,7 @@ public class Startup : AppStartup
}
/// <inheritdoc/>
public void Use(IApplicationBuilder applicationBuilder)
public void Use(IServiceProvider serviceProvider)
{
}
}

View File

@@ -7,7 +7,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="BootstrapBlazor.FontAwesome" Version="9.0.2" />
<PackageReference Include="BootstrapBlazor" Version="9.7.2" />
<PackageReference Include="BootstrapBlazor" Version="9.7.3" />
<PackageReference Include="Yitter.IdGenerator" Version="1.0.14" />
</ItemGroup>

View File

@@ -26,6 +26,10 @@
height: var(--line-chart-table-height);
}
.wb-control .wb-full {
display: none;
}
.dialog-table {
height: calc(100vh - 200px);
}

View File

@@ -201,9 +201,9 @@ namespace ThingsGateway.SqlSugar
try
{
if (this.Context.CurrentConnectionConfig?.MoreSettings?.IsNoReadXmlDescription == true)
if (this.Context.CurrentConnectionConfig?.MoreSettings?.IsNoReadXmlDescription ?? true == true)
{
return "";
return string.Empty;
}
if (entityType.Assembly.IsDynamic && entityType.Assembly.FullName.StartsWith("Dynamic"))
{

View File

@@ -17,7 +17,7 @@
public int DefaultCacheDurationInSeconds { get; set; }
public bool? TableEnumIsString { get; set; }
public DateTime? DbMinDate { get; set; } = DateTime.MinValue.Date.AddYears(1900 - 1);
public bool IsNoReadXmlDescription { get; set; }
public bool IsNoReadXmlDescription { get; set; } = true;
public bool SqlServerCodeFirstNvarchar { get; set; }
public bool OracleCodeFirstNvarchar2 { get; set; }
public bool SqliteCodeFirstEnableDefaultValue { get; set; }

View File

@@ -501,7 +501,7 @@ namespace ThingsGateway.SqlSugar
{
return GetFirstTypeNameFromExpression(methodCall.Arguments.FirstOrDefault());
}
return "";
return string.Empty;
}
public static string GetMethodName(Expression expression)

View File

@@ -245,7 +245,7 @@ namespace ThingsGateway.SqlSugar
public string GetMemberName(MemberExpression memberExpression)
{
return "";
return string.Empty;
}
private void ExtMapper(MapperExpressionInfo fillInfo, MapperExpressionInfo mappingFild1Info, MapperExpressionInfo mappingFild1Info2, MapperExpressionInfo selectInfo)

View File

@@ -47,7 +47,7 @@ namespace ThingsGateway.SqlSugar
var isWhere = Convert.ToBoolean(value);
if (!Convert.ToBoolean(isWhere))
{
return "";
return string.Empty;
}
var argExp = exp.Arguments[1];
var copyContext = this.Context;

View File

@@ -43,7 +43,7 @@ namespace ThingsGateway.SqlSugar
}
else
{
return "";
return string.Empty;
}
}
}

View File

@@ -117,7 +117,7 @@
}
}
}
internal static class ReflectionInoHelper
public static class ReflectionInoHelper
{
private static List<Action> removeActions = new List<Action>();
internal static void AddRemoveFunc(Action removeAction)

View File

@@ -576,7 +576,7 @@ WHERE table_name = '" + tableName + "'");
}
else
{
return "";
return string.Empty;
}
}

View File

@@ -144,7 +144,7 @@ namespace ThingsGateway.SqlSugar
public string DataTableToCsvString(DataTable table)
{
if (table.Rows.Count == 0)
return "";
return string.Empty;
StringBuilder sb = new StringBuilder();
DataColumn colum;
foreach (DataRow row in table.Rows)

View File

@@ -262,7 +262,7 @@ namespace ThingsGateway.SqlSugar
{
get
{
return "";
return string.Empty;
}
}
#endregion

View File

@@ -51,7 +51,7 @@ namespace ThingsGateway.SqlSugar
{
get
{
return "";
return string.Empty;
}
}
protected override string AddColumnToTableSql

View File

@@ -92,12 +92,12 @@ namespace ThingsGateway.SqlSugar
public static string ObjToString(this object thisValue)
{
if (thisValue != null) return thisValue.ToString().Trim();
return "";
return string.Empty;
}
public static string ObjToStringNoTrim(this object thisValue)
{
if (thisValue != null) return thisValue.ToString();
return "";
return string.Empty;
}
public static string ObjToStringNew(this object thisValue)
{
@@ -110,7 +110,7 @@ namespace ThingsGateway.SqlSugar
return Convert.ToDateTime(thisValue.ToString()).ToString("yyyy-MM-dd");
}
if (thisValue != null) return thisValue.ToString().Trim();
return "";
return string.Empty;
}
public static string ObjToString(this object thisValue, string errorValue)

View File

@@ -57,7 +57,7 @@
public static string ObjToString(this object thisValue)
{
if (thisValue != null) return thisValue.ToString().Trim();
return "";
return string.Empty;
}
public static string ObjToString(this object thisValue, string errorValue)

View File

@@ -893,42 +893,25 @@ namespace ThingsGateway.SqlSugar
return Guid.NewGuid() + "";
}
}
static Type IAsyncStateMachineType = typeof(IAsyncStateMachine);
public static bool IsAsyncMethod(MethodBase method)
{
if (method == null)
{
return false;
}
if (method.DeclaringType != null)
{
if (method.DeclaringType.GetInterfaces().Contains(typeof(IAsyncStateMachine)))
{
return true;
}
}
if (method == null) return false;
if (method.GetCustomAttribute<AsyncStateMachineAttribute>() != null)
return true;
if (method.DeclaringType?.GetInterfaces().Contains(IAsyncStateMachineType) == true)
return true;
// 补救方案:有些 async 方法是动态生成的,名字惯例判断
var name = method.Name;
if (name.Contains("OutputAsyncCausalityEvents"))
{
return true;
}
if (name.Contains("OutputWaitEtwEvents"))
{
return true;
}
if (name.Contains("ExecuteAsync"))
{
return true;
}
//if (method?.DeclaringType?.FullName?.Contains("Furion.InternalApp")==true)
//{
// return false;
//}
Type attType = typeof(AsyncStateMachineAttribute);
var attrib = (AsyncStateMachineAttribute)method.GetCustomAttribute(attType);
return (attrib != null);
return name.EndsWith("ExecuteAsync") || name.Contains("OutputAsyncCausalityEvents") || name.Contains("OutputWaitEtwEvents");
}
public static StackTraceInfo GetStackTrace()
{

View File

@@ -29,7 +29,7 @@ namespace ThingsGateway.SqlSugar.TDengine
{
get
{
return "";
return string.Empty;
}
}

View File

@@ -16,7 +16,7 @@
public static string ObjToStringNoTrim(this object thisValue)
{
if (thisValue != null) return thisValue.ToString();
return "";
return string.Empty;
}
public static string ToLower(this string value, bool isLower)
{
@@ -78,7 +78,7 @@
public static string ObjToString(this object thisValue)
{
if (thisValue != null) return thisValue.ToString().Trim();
return "";
return string.Empty;
}
public static string ObjToString(this object thisValue, string errorValue)

View File

@@ -30,7 +30,7 @@
<PackageReference Include="CsvHelper" Version="33.1.0" />
<PackageReference Include="TDengine.Connector" Version="3.1.6" />
<PackageReference Include="Oracle.ManagedDataAccess.Core" Version="23.8.0" />
<PackageReference Include="Oscar.Data.SqlClient" Version="4.2.18" />
<PackageReference Include="Oscar.Data.SqlClient" Version="4.2.20" />
<PackageReference Include="System.Data.Common" Version="4.3.0" />
<PackageReference Include="Microsoft.Data.SqlClient" Version="6.0.2" />
<PackageReference Include="System.Reflection.Emit.Lightweight" Version="4.7.0" />

View File

@@ -1,9 +1,9 @@
<Project>
<PropertyGroup>
<PluginVersion>10.7.47</PluginVersion>
<ProPluginVersion>10.7.47</ProPluginVersion>
<AuthenticationVersion>2.5.0</AuthenticationVersion>
<PluginVersion>10.7.57</PluginVersion>
<ProPluginVersion>10.7.57</ProPluginVersion>
<AuthenticationVersion>2.6.0</AuthenticationVersion>
<NET8Version>8.0.17</NET8Version>
<NET9Version>9.0.6</NET9Version>
</PropertyGroup>

View File

@@ -121,12 +121,12 @@ public static class TextFileReader
}
using var fs = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 4096, FileOptions.SequentialScan);
var result = ReadLogsInverse(fs, lineCount, fileInfo.Length);
var result = ReadLogsInverse(fs, lineCount, length);
_cache.Set(cacheKey, new LogDataCache
{
LogDatas = result,
Length = fileInfo.Length,
Length = length,
});
return new OperResult<List<LogData>>() { Content = result };
@@ -140,7 +140,6 @@ public static class TextFileReader
private static List<LogData> ReadLogsInverse(FileStream fs, int lineCount, long length)
{
length = fs.Length;
long ps = 0; // 保存起始位置
List<string> txt = new(); // 存储读取的文本内容
@@ -186,7 +185,8 @@ public static class TextFileReader
if (fs.Length == 0) return 0;
var newPos = position;
byte[] buffer = _bytePool.Rent(maxRead); // 从池中租借字节数组
var len = (int)Math.Min(fs.Length, maxRead);
byte[] buffer = _bytePool.Rent(len); // 从池中租借字节数组
int index = 0;
try
@@ -201,7 +201,7 @@ public static class TextFileReader
if (byteRead == -1) break;
if (index >= maxRead)
if (index >= len)
{
newPos = -1;
return newPos;

View File

@@ -1,6 +1,4 @@
using System.Runtime.CompilerServices;
using ThingsGateway.Blazor.Diagrams.Core.Behaviors;
using ThingsGateway.Blazor.Diagrams.Core.Behaviors;
using ThingsGateway.Blazor.Diagrams.Core.Controls;
using ThingsGateway.Blazor.Diagrams.Core.Events;
using ThingsGateway.Blazor.Diagrams.Core.Extensions;
@@ -9,10 +7,6 @@ using ThingsGateway.Blazor.Diagrams.Core.Layers;
using ThingsGateway.Blazor.Diagrams.Core.Models.Base;
using ThingsGateway.Blazor.Diagrams.Core.Options;
[assembly: InternalsVisibleTo("ThingsGateway.Blazor.Diagrams")]
[assembly: InternalsVisibleTo("ThingsGateway.Blazor.Diagrams.Tests")]
[assembly: InternalsVisibleTo("ThingsGateway.Blazor.Diagrams.Core.Tests")]
namespace ThingsGateway.Blazor.Diagrams.Core;
public abstract class Diagram

Some files were not shown because too many files have changed in this diff Show More