commit f05d2d215f795baa05a37e49d45a700f50257a56 Author: owenchen Date: Wed Aug 19 14:11:17 2026 +0800 ow diff --git a/CloudBuilder/.dockerignore b/CloudBuilder/.dockerignore new file mode 100644 index 0000000..fe1152b --- /dev/null +++ b/CloudBuilder/.dockerignore @@ -0,0 +1,30 @@ +**/.classpath +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/azds.yaml +**/bin +**/charts +**/docker-compose* +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +LICENSE +README.md +!**/.gitignore +!.git/HEAD +!.git/config +!.git/packed-refs +!.git/refs/heads/** \ No newline at end of file diff --git a/CloudBuilder/.gitignore b/CloudBuilder/.gitignore new file mode 100644 index 0000000..5312959 --- /dev/null +++ b/CloudBuilder/.gitignore @@ -0,0 +1,24 @@ +/CloudBuilder.Core/bin +/CloudBuilder.Core/obj +/CloudBuilder.Gui/bin +/CloudBuilder.Gui/obj +/CloudBuilder.Request/bin +/CloudBuilder.Request/obj +/CloudBuilder.Security/bin +/CloudBuilder.Security/obj +/CloudBuilder.Security.Gui/bin +/CloudBuilder.Security.Gui/obj +/CloudBuilder.Security.Service/bin +/CloudBuilder.Security.Service/obj +/CloudBuilder.Web.Entry/bin +/CloudBuilder.Web.Entry/obj +/CloudBuilderLauncher/bin +/CloudBuilderLauncher/obj +/.vs +/CloudBuilder.AI/.vs +/CloudBuilder.AI/bin +/CloudBuilder.AI/obj +/CloudBuilder.AI.Service/bin +/CloudBuilder.AI.Service/obj +/CloudBuilder.AI.Gui/obj +/CloudBuilder.AI.Gui/bin diff --git a/CloudBuilder/CloudBuilder.Core/Application/Builders/CloudBuilderBuilder.cs b/CloudBuilder/CloudBuilder.Core/Application/Builders/CloudBuilderBuilder.cs new file mode 100644 index 0000000..9cfa4c7 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Application/Builders/CloudBuilderBuilder.cs @@ -0,0 +1,140 @@ +using CloudBuilder.Core.Application.Options; +using CloudBuilder.Core.Application.Packs; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyModel; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Security.AccessControl; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.Application.Builders +{ + /// + /// CloudBuilder构建器 + /// + public class CloudBuilderBuilder + { + public CloudBuilderBuilder(IServiceCollection services, IConfiguration configuration) + { + this.Services = services; + AddOptions(configuration); + } + + /// + /// 获取 服务集合 + /// + public IServiceCollection Services { get; } + + /// + /// 获取 CloudBuilder选项配置委托 + /// + public CloudBuilderOptions CloudBuilderOptions { get; private set; } + + /// + /// 添加所有模块 + /// + /// 要添加的模块类型 + public CloudBuilderBuilder AddPack() + { + var baseType = typeof(CloudBuilderPack); + + var allAssemblies = GetAssemblies(); + + var types = allAssemblies + .SelectMany(a => a.DefinedTypes) + .Select(type => type.AsType()) + .Where(type => type != baseType && baseType.IsAssignableFrom(type)) + .Where(x => x.IsClass) + .OrderBy(x => x.GetCustomAttribute()?.Level).ToList(); + + foreach (var implementType in types) + { + if (Services.Any(m => m.ServiceType == baseType && m.ImplementationType == implementType)) + { + continue; + } + + //注入CloudBuilderPack模块内的服务 + CloudBuilderPack pack = (CloudBuilderPack)Activator.CreateInstance( + implementType, + BindingFlags.Public | BindingFlags.Instance, + null, + null, + null); + + pack.AddServices(Services, this); + } + + return this; + } + + /// + /// 添加CloudBuilder选项配置 + /// + /// CloudBuilder操作选项 + /// CloudBuilder构建器 + public CloudBuilderBuilder AddOptions(IConfiguration configuration) + { + CloudBuilderOptions options = new CloudBuilderOptions(); + new CloudBuilderOptionsSetup(configuration).Configure(options); + + CloudBuilderOptions = options; + return this; + } + + public T GetTransientService() + { + object? t = Services.BuildServiceProvider().GetService(typeof(T)); + if (t == null) return default(T)!; + return (T)t; + } + + public T GetTransientRequiredService() + { + return (T)Services.BuildServiceProvider().GetRequiredService(typeof(T)); + } + + public static Assembly[] GetAssemblies() + { + // 获取入口程序集 + var entryAssembly = Assembly.GetEntryAssembly(); + List reference = new List(); + + if (!string.IsNullOrWhiteSpace(entryAssembly.Location)) + { + var dependencyContext = DependencyContext.Default; + + // 读取项目程序集或 Furion 官方发布的包,或手动添加引用的dll,或配置特定的包前缀 + reference = dependencyContext.RuntimeLibraries + .Where(u => u.Type == "project" || u.Type == "reference") + .Select(x => x.Name).ToList(); + } + + string[] filters = + { + "mscorlib", + "netstandard", + "dotnet", + "api-ms-win-core", + "runtime.", + "System", + "Microsoft", + "Window", + }; + + //遍历文件夹的方式,用于传统.netfx + string path = AppContext.BaseDirectory; + string[] files = Directory.GetFiles(path, "*.dll", SearchOption.TopDirectoryOnly) + .Where(x => reference.Contains(Path.GetFileNameWithoutExtension(x))).ToArray(); + + return files.Where(file => filters.All(token => Path.GetFileName(file)?.StartsWith(token) != true)).Select(Assembly.LoadFrom).ToArray(); + } + + + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Application/Options/CloudBuilderDbContextOptions.cs b/CloudBuilder/CloudBuilder.Core/Application/Options/CloudBuilderDbContextOptions.cs new file mode 100644 index 0000000..09669d6 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Application/Options/CloudBuilderDbContextOptions.cs @@ -0,0 +1,50 @@ +using CloudBuilder.Core.DatabaseAccessor.Entity; + +namespace CloudBuilder.Core.Application.Options +{ + /// + /// 数据上下文配置节点 + /// + public class CloudBuilderDbContextOptions + { + /// + /// 初始化一个类型的新实例 + /// + public CloudBuilderDbContextOptions() + { + LazyLoadingProxiesEnabled = false; + AuditEntityEnabled = false; + AutoMigrationEnabled = false; + } + + /// + /// 获取或设置 上下文类型全名 + /// + public string DbContextTypeName { get; set; } = null!; + + /// + /// 获取或设置 连接字符串 + /// + public string ConnectionString { get; set; } = null!; + + /// + /// 获取或设置 数据库类型 + /// + public DatabaseType DatabaseType { get; set; } + + /// + /// 获取或设置 是否启用延迟加载代理 + /// + public bool LazyLoadingProxiesEnabled { get; set; } + + /// + /// 获取或设置 是否允许审计实体 + /// + public bool AuditEntityEnabled { get; set; } + + /// + /// 获取或设置 是否自动迁移 + /// + public bool AutoMigrationEnabled { get; set; } + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Application/Options/CloudBuilderOptions.cs b/CloudBuilder/CloudBuilder.Core/Application/Options/CloudBuilderOptions.cs new file mode 100644 index 0000000..124970d --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Application/Options/CloudBuilderOptions.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.Application.Options +{ + /// + /// CloudBuilder框架配置选项信息 + /// + public class CloudBuilderOptions + { + /// + /// 初始化一个类型的新实例 + /// + public CloudBuilderOptions() + { + DbContexts = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + } + + /// + /// 获取 数据上下文配置信息 + /// + public IDictionary DbContexts { get; } + + ///// + ///// 获取 第三方OAuth2登录配置信息 + ///// + //public IDictionary OAuth2S { get; } + + /// + /// 获取或设置 邮件发送选项 + /// + public MailSenderOptions MailSender { get; set; } + + /// + /// 全局授权 + /// + public bool EnableGlobalAuthorize { get; set; } + /// + /// 获取或设置 JWT身份认证选项 + /// + public JwtOptions Jwt { get; set; } + + /// + /// 获取或设置 Redis选项 + /// + public RedisOptions Redis { get; set; } + + ///// + ///// 获取或设置 Swagger选项 + ///// + //public SwaggerOptions Swagger { get; set; } + + ///// + ///// 获取或设置 Http传输加密选项 + ///// + //public HttpEncryptOptions HttpEncrypt { get; set; } + + /// + /// 获取指定上下文类和指定数据库类型的上下文配置信息 + /// + public CloudBuilderDbContextOptions GetDbContextOptions(string dbContextType) + { + return DbContexts.Values.SingleOrDefault(m => m.DbContextTypeName == dbContextType); + } + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Application/Options/CloudBuilderOptionsSetup.cs b/CloudBuilder/CloudBuilder.Core/Application/Options/CloudBuilderOptionsSetup.cs new file mode 100644 index 0000000..ff3561f --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Application/Options/CloudBuilderOptionsSetup.cs @@ -0,0 +1,107 @@ +using CloudBuilder.Core.Extensions; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Options; + +namespace CloudBuilder.Core.Application.Options +{ + /// + /// CloudBuilder配置选项创建器 + /// + public class CloudBuilderOptionsSetup : IConfigureOptions + { + private readonly IConfiguration _configuration; + + /// + /// 初始化一个类型的新实例 + /// + public CloudBuilderOptionsSetup(IConfiguration configuration) + { + _configuration = configuration; + } + + /// Invoked to configure a TOptions instance. + /// The options instance to configure. + public void Configure(CloudBuilderOptions options) + { + SetDbContextOptions(options); + + IConfigurationSection section; + + //MailSender + section = _configuration.GetSection("CloudBuilder:MailSender"); + MailSenderOptions sender = section.Get(); + if (sender != null) + { + if (sender.Password == null) + { + sender.Password = _configuration["CloudBuilder:MailSender:Password"]; + } + options.MailSender = sender; + } + + //EnableGlobalAuthorize + section = _configuration.GetSection("CloudBuilder:Authorization:EnableGlobalAuthorize"); + options.EnableGlobalAuthorize = section.Get(); + + //JwtOptions + section = _configuration.GetSection("CloudBuilder:Jwt"); + JwtOptions jwt = section.Get(); + if (jwt != null) + { + if (jwt.Secret == null) + { + jwt.Secret = _configuration["CloudBuilder:Jwt:Secret"]; + } + options.Jwt = jwt; + } + + // RedisOptions + section = _configuration.GetSection("CloudBuilder:Redis"); + RedisOptions redis = section.Get(); + if (redis != null) + { + if (redis.Configuration.IsMissing()) + { + throw new Exception("配置文件中Redis节点的Configuration不能为空"); + } + options.Redis = redis; + } + + //// SwaggerOptions + //section = _configuration.GetSection("CloudBuilder:Swagger"); + //SwaggerOptions swagger = section.Get(); + //if (swagger != null) + //{ + // if (swagger.Url.IsMissing()) + // { + // throw new CloudBuilderException("配置文件中Swagger节点的Url不能为空"); + // } + // options.Swagger = swagger; + //} + + } + + /// + /// 初始化上下文配置信息,首先以CloudBuilder配置节点中的为准, + /// 不存在CloudBuilder节点,才使用ConnectionStrings的数据连接串来构造SqlServer的配置, + /// 保证同一上下文类型只有一个配置节点 + /// + /// + private void SetDbContextOptions(CloudBuilderOptions options) + { + IConfigurationSection section = _configuration.GetSection("CloudBuilder:DbContexts"); + IDictionary dict = section.Get>(); + + var repeated = dict.Values.GroupBy(m => m.DbContextTypeName).FirstOrDefault(m => m.Count() > 1); + if (repeated != null) + { + throw new Exception($"数据上下文配置中存在多个配置节点指向同一个上下文类型:{repeated.First().DbContextTypeName}"); + } + + foreach (KeyValuePair pair in dict) + { + options.DbContexts.Add(pair.Key, pair.Value); + } + } + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Application/Options/JwtOptions.cs b/CloudBuilder/CloudBuilder.Core/Application/Options/JwtOptions.cs new file mode 100644 index 0000000..4fc619c --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Application/Options/JwtOptions.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.Application.Options +{ + /// + /// JWT身份认证选项 + /// + public class JwtOptions + { + /// + /// 获取或设置 密钥 + /// + public string Secret { get; set; } + + /// + /// 获取或设置 发行方 + /// + public string Issuer { get; set; } + + /// + /// 获取或设置 订阅方 + /// + public string Audience { get; set; } + + /// + /// 获取或设置 AccessToken有效期分钟数 + /// + public double AccessExpireMins { get; set; } + + /// + /// 获取或设置 RefreshToken有效期分钟数 + /// + public double RefreshExpireMins { get; set; } + + /// + /// 获取或设置 RefreshToken是否绝对过期 + /// + public bool IsRefreshAbsoluteExpired { get; set; } = true; + } + +} diff --git a/CloudBuilder/CloudBuilder.Core/Application/Options/MailSenderOptions.cs b/CloudBuilder/CloudBuilder.Core/Application/Options/MailSenderOptions.cs new file mode 100644 index 0000000..e216f99 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Application/Options/MailSenderOptions.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.Application.Options +{ + /// + /// 邮件发送选项 + /// + public class MailSenderOptions + { + /// + /// 获取或设置 邮件发送服务器 + /// + public string Host { get; set; } + + /// + /// 获取或设置 端口 + /// + public int Port { get; set; } + + /// + /// 获取或设置 是否SSL + /// + public bool EnableSsl { get; set; } + + /// + /// 获取或设置 发送方显示名 + /// + public string DisplayName { get; set; } + + /// + /// 获取或设置 发送方用户名 + /// + public string UserName { get; set; } + + /// + /// 获取或设置 发送方密码 + /// + public string Password { get; set; } + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Application/Options/RedisOptions.cs b/CloudBuilder/CloudBuilder.Core/Application/Options/RedisOptions.cs new file mode 100644 index 0000000..5b6d9e2 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Application/Options/RedisOptions.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.Application.Options +{ + /// + /// Redis选项 + /// + public class RedisOptions + { + /// + /// 获取或设置 Redis连接配置 + /// + public string Configuration { get; set; } + + /// + /// 获取或设置 Redis实例名称 + /// + public string InstanceName { get; set; } + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Application/Packs/CloudBuilderCorePack.cs b/CloudBuilder/CloudBuilder.Core/Application/Packs/CloudBuilderCorePack.cs new file mode 100644 index 0000000..04fc787 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Application/Packs/CloudBuilderCorePack.cs @@ -0,0 +1,60 @@ +using CloudBuilder.Core.Application.Builders; +using CloudBuilder.Core.Application.Options; +using CloudBuilder.Core.DatabaseAccessor; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Options; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.Application.Packs +{ + /// + /// CloudBuilder核心模块 + /// + [Description("CloudBuilder核心模块")] + [PackLevel(0)] + public class CloudBuilderCorePack : CloudBuilderPack + { + /// + /// 获取 模块级别 + /// + public override PackLevel Level => PackLevel.Core; + + /// + /// 将全局应用添加到依赖注入服务容器中 + /// + /// 依赖注入服务容器 + /// + public override IServiceCollection AddServices(IServiceCollection services, CloudBuilderBuilder builder) + { + services.AddSingleton(); + services.AddSingleton(new WebService(services)); + + services.AddScoped(); + + //services.TryAddSingleton(); + //services.TryAddSingleton(); + //services.TryAddSingleton(); + //services.TryAddSingleton(); + + //services.TryAddSingleton(); + //services.TryAddScoped(); + + //services.TryAddTransient(); + //services.AddTransient(); + + //services.AddDistributedMemoryCache(); + + return services; + } + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Application/Packs/CloudBuilderPack.cs b/CloudBuilder/CloudBuilder.Core/Application/Packs/CloudBuilderPack.cs new file mode 100644 index 0000000..a96e928 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Application/Packs/CloudBuilderPack.cs @@ -0,0 +1,52 @@ +using CloudBuilder.Core.Application.Builders; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.Application.Packs +{ + /// + /// CloudBuilder模块基类 + /// + public abstract class CloudBuilderPack + { + /// + /// 获取 模块级别,级别越小越先启动 + /// + public virtual PackLevel Level => PackLevel.Business; + + /// + /// 获取 模块启动顺序,模块启动的顺序先按级别启动,同一级别内部再按此顺序启动, + /// 级别默认为0,表示无依赖,需要在同级别有依赖顺序的时候,再重写为>0的顺序值 + /// + public virtual int Order => 0; + + /// + /// 获取 是否已可用 + /// + public bool IsEnabled { get; protected set; } + + /// + /// 将模块服务添加到依赖注入服务容器中 + /// + /// 依赖注入服务容器 + /// + public virtual IServiceCollection AddServices(IServiceCollection services, CloudBuilderBuilder builder) + { + return services; + } + + /// + /// 应用模块服务 + /// + /// 服务提供者 + public virtual void UsePack(IServiceProvider provider) + { + IsEnabled = true; + } + + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Application/Packs/PackLevel.cs b/CloudBuilder/CloudBuilder.Core/Application/Packs/PackLevel.cs new file mode 100644 index 0000000..46e83c4 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Application/Packs/PackLevel.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.Application.Packs +{ + /// + /// 模块级别,级别越核心,优先启动 + /// + public enum PackLevel + { + /// + /// 核心级别,表示系统的核心模块, + /// 这些模块不涉及第三方组件,在系统运行中是不可替换的,核心模块将始终加载 + /// + Core = 1, + /// + /// 框架级别,表示涉及第三方组件的基础模块 + /// + Framework = 10, + /// + /// 应用级别,表示涉及应用数据的基础模块 + /// + Application = 20, + /// + /// 业务级别,表示涉及真实业务处理的模块 + /// + Business = 30 + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Application/Packs/PackLevelAttribute.cs b/CloudBuilder/CloudBuilder.Core/Application/Packs/PackLevelAttribute.cs new file mode 100644 index 0000000..51850e4 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Application/Packs/PackLevelAttribute.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.Application.Packs +{ + public class PackLevelAttribute : Attribute + { + public PackLevelAttribute() + { + } + + public PackLevelAttribute(int level) + { + this.Level = level; + } + + /// + /// 获取权限名称 + /// + public int Level { get; set; } + + } + +} diff --git a/CloudBuilder/CloudBuilder.Core/Authorization/AuthorizationHandler.cs b/CloudBuilder/CloudBuilder.Core/Authorization/AuthorizationHandler.cs new file mode 100644 index 0000000..dbca6b6 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Authorization/AuthorizationHandler.cs @@ -0,0 +1,32 @@ +using Microsoft.AspNetCore.Authorization; + +namespace CloudBuilder.Core.Authorization +{ + public class AuthorizationHandler : IAuthorizationHandler, IAuthorize + { + /// + /// 身份认证Authorize + /// + /// + /// + public virtual Task HandleAsync(AuthorizationHandlerContext context) + { + if (context.HasFailed) + { + return Task.CompletedTask; + } + + // 判断身份认证是否通过 + var isAuthenticated = context.User.Identity.IsAuthenticated; + if (isAuthenticated) + { + context.Succeed(context.PendingRequirements.FirstOrDefault()!); + return Task.CompletedTask; + } + + context.Fail(); + + return Task.CompletedTask; + } + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Authorization/IAuthorize.cs b/CloudBuilder/CloudBuilder.Core/Authorization/IAuthorize.cs new file mode 100644 index 0000000..c634704 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Authorization/IAuthorize.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.Authorization +{ + public interface IAuthorize + { + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Authorization/JwtGenerate.cs b/CloudBuilder/CloudBuilder.Core/Authorization/JwtGenerate.cs new file mode 100644 index 0000000..16851da --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Authorization/JwtGenerate.cs @@ -0,0 +1,64 @@ +using CloudBuilder.Core.Application.Options; +using CloudBuilder.Core.Policy; +using Microsoft.IdentityModel.Tokens; +using System; +using System.Collections.Generic; +using System.IdentityModel.Tokens.Jwt; +using System.Linq; +using System.Security.Claims; +using System.Security.Cryptography; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.Authorization +{ + public class JwtGenerate + { + private readonly JwtOptions jwtOptions; + + public JwtGenerate(JwtOptions jwtOptions) + { + this.jwtOptions = jwtOptions; + } + + public string GenerateRefreshToken() + { + var randomNumber = new byte[32]; + using (var rng = RandomNumberGenerator.Create()) + { + rng.GetBytes(randomNumber); + return Convert.ToBase64String(randomNumber); + } + } + + public string Generate(Dictionary claims) + { + JwtOptions jwt = jwtOptions; + + var token = string.Empty; + + List claimls = new List(); + foreach (var claim in claims) + { + claimls.Add(new Claim(claim.Key, claim.Value)); + } + + var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwt.Secret)); + var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); + + var tokenHandler = new JwtSecurityTokenHandler(); + var tokenDescriptor = new SecurityTokenDescriptor + { + NotBefore = DateTime.UtcNow, + Issuer = jwt.Issuer, + Audience = jwt.Audience, + Subject = new ClaimsIdentity(claimls, ClaimPolicy.BEARER, ClaimPolicy.CLAINM_USERID, ClaimPolicy.ROLE), + Expires = DateTime.UtcNow.AddMinutes(jwt.AccessExpireMins), + SigningCredentials = credentials + }; + + var securityToken = tokenHandler.CreateToken(tokenDescriptor); + return tokenHandler.WriteToken(securityToken); + } + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Authorization/JwtInfo.cs b/CloudBuilder/CloudBuilder.Core/Authorization/JwtInfo.cs new file mode 100644 index 0000000..594ae48 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Authorization/JwtInfo.cs @@ -0,0 +1,23 @@ +using CloudBuilder.Core.Application.Options; +using CloudBuilder.Core.Policy; +using Microsoft.IdentityModel.Tokens; +using System; +using System.Collections.Generic; +using System.IdentityModel.Tokens.Jwt; +using System.Linq; +using System.Security.Claims; +using System.Security.Cryptography; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.Authorization +{ + [TypeScript] + public class JwtInfo + { + public string AccessToken { get; set; } = null!; + public string RefreshToken { get; set; } = null!; + public DateTime CreatedTime { get; set; } + + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Authorization/PermissionOperateAttribute.cs b/CloudBuilder/CloudBuilder.Core/Authorization/PermissionOperateAttribute.cs new file mode 100644 index 0000000..041a764 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Authorization/PermissionOperateAttribute.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Microsoft.AspNetCore.Authorization +{ + public class PermissionOperateAttribute : Attribute + { + public PermissionOperateAttribute(string name) + { + Name = name; + } + + public PermissionOperateAttribute(string name, string operate) + { + Name = name; + Operate = operate; + } + + public PermissionOperateAttribute(string name, Operate operate) + { + Name = name; + Operate = operate.ToString(); + } + + /// + /// 获取权限名称 + /// + public string Name { get; private set; } = null!; + + public string Operate { get; private set; } = null!; + } + + public enum Operate + { + None, + Find, + Print, + Insert, + Update, + Delete, + Submit, + Approval + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Authorization/PermissionRequirement.cs b/CloudBuilder/CloudBuilder.Core/Authorization/PermissionRequirement.cs new file mode 100644 index 0000000..051ab2f --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Authorization/PermissionRequirement.cs @@ -0,0 +1,49 @@ +using Microsoft.AspNetCore.Authorization; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.Authorization +{ + public class PermissionRequirement : IAuthorizationRequirement + { + + //public List UserPermissionDisplayDatas { get; set; } + + ///// + ///// 认证授权类型 + ///// + //public string ClaimType { internal get; set; } + + ///// + ///// 发行人 + ///// + //public string Issuer { get; set; } + ///// + ///// 订阅人 + ///// + //public string Audience { get; set; } + ///// + ///// 过期时间 + ///// + //public TimeSpan Expiration { get; set; } + ///// + ///// 签名验证 + ///// + //public SigningCredentials SigningCredentials { get; set; } + public PermissionRequirement() + { + } + //public PermissionRequirement(List permissions) + //{ + // //ClaimType = claimType; + // UserPermissionDisplayDatas = permissions; + // //Issuer = issuer; + // //Audience = audience; + // //Expiration = expiration; + // //SigningCredentials = signingCredentials; + //} + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Authorization/TypeScriptAttribute.cs b/CloudBuilder/CloudBuilder.Core/Authorization/TypeScriptAttribute.cs new file mode 100644 index 0000000..d0c5f61 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Authorization/TypeScriptAttribute.cs @@ -0,0 +1,28 @@ +using Microsoft.AspNetCore.Authorization; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.Authorization +{ + public class TypeScriptAttribute : Attribute + { + public TypeScriptAttribute() + { + } + + public TypeScriptAttribute(string name) + { + Name = name; + } + + /// + /// 获取权限名称 + /// + public string Name { get; private set; } = null!; + + } + +} diff --git a/CloudBuilder/CloudBuilder.Core/CloudBuilder.Core.csproj b/CloudBuilder/CloudBuilder.Core/CloudBuilder.Core.csproj new file mode 100644 index 0000000..1bf7432 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/CloudBuilder.Core.csproj @@ -0,0 +1,38 @@ + + + + net8.0 + enable + enable + False + + + + False + + + + True + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/ApplicationService.cs b/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/ApplicationService.cs new file mode 100644 index 0000000..9a7aeed --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/ApplicationService.cs @@ -0,0 +1,58 @@ +using CloudBuilder.Core.Application.Builders; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using CloudBuilder.Core.Policy; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.DatabaseAccessor +{ + public class ApplicationService : IApplicationService + { + + public ApplicationService( + CloudBuilderBuilder cloudBuilder, + IConfiguration configuration, + IServiceProvider serviceProvider, + IUnitOfWork unitOfWork, + IHttpContextAccessor httpContext + ) + { + CloudBuilder = cloudBuilder; + this.Configuration = configuration; + this.ServiceProvider = serviceProvider; + this.UnitOfWork = unitOfWork; + this.HttpContext = httpContext; + if (httpContext.HttpContext != null) + { + UserId = ClaimPolicy.GetClaimValue(HttpContext, ClaimPolicy.CLAINM_USERID); + string key = ClaimPolicy.GetHeaderKeyValue(HttpContext, ClaimPolicy.HEADER_LOCALE); + if (!string.IsNullOrEmpty(key)) + { + Locale = key; + } + } + } + + public IServiceProvider ServiceProvider { get; private set; } + + public IHttpContextAccessor HttpContext { get; private set; } + + public string UserId { get; set; } + public string Locale { get; set; } = ClaimPolicy.CLAINM_LOCALE; + public IUnitOfWork UnitOfWork { get; set; } + public CloudBuilderBuilder CloudBuilder { get; set; } + public IConfiguration Configuration { get; private set; } + + public KRepository GetRepository() + { + return ServiceProvider.GetRequiredService(); + } + } +} diff --git a/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/Entity/DatabaseType.cs b/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/Entity/DatabaseType.cs new file mode 100644 index 0000000..7c5a055 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/Entity/DatabaseType.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.DatabaseAccessor.Entity +{ + /// + /// 表示数据库类型,如SqlServer,Sqlite等 + /// + public enum DatabaseType + { + /// + /// SqlServer数据库类型 + /// + SqlServer, + /// + /// Sqlite数据库类型 + /// + Sqlite, + /// + /// MySql数据库类型 + /// + MySql, + /// + /// PostgreSql数据库类型 + /// + PostgreSql, + /// + /// Oracle数据库类型 + /// + Oracle + } +} diff --git a/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/Entity/EntityBase.cs b/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/Entity/EntityBase.cs new file mode 100644 index 0000000..681b24a --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/Entity/EntityBase.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.DatabaseAccessor.Entity +{ + /// + /// 实体类基类 + /// + public abstract class EntityBase : IEntity + { + /// + /// 获取或设置 编号 + /// + [DisplayName("编号")] + [NotMapped] + public TKey? Id { get; set; } + + public virtual string GetSelectFrom() + { + return null; + } + + public virtual string GetSelectCountFrom(string sqlWhere) + { + return null; + } + + public virtual string GetSelectTopFrom(int limit, int start, string orderby, string orderbytag, string sqlWhere) + { + return null; + } + + /// + /// 判断两个实体是否是同一数据记录的实体 + /// + /// 要比较的实体信息 + /// + public override bool Equals(object obj) + { + if (obj == null) + { + return false; + } + if (!(obj is EntityBase entity)) + { + return false; + } + return IsKeyEqual(entity.Id, Id); + } + + /// + /// 实体ID是否相等 + /// + public static bool IsKeyEqual(TKey id1, TKey id2) + { + if (id1 == null && id2 == null) + { + return true; + } + if (id1 == null || id2 == null) + { + return false; + } + + return Equals(id1, id2); + } + + /// + /// 用作特定类型的哈希函数。 + /// + /// + /// 当前 的哈希代码。
+ /// 如果Id为null则返回0, + /// 如果不为null则返回Id对应的哈希值 + ///
+ public override int GetHashCode() + { + if (Id == null) + { + return 0; + } + return Id.ToString().GetHashCode(); + } + } +} diff --git a/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/Entity/IApplicationService.cs b/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/Entity/IApplicationService.cs new file mode 100644 index 0000000..e8bdf66 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/Entity/IApplicationService.cs @@ -0,0 +1,37 @@ +using CloudBuilder.Core.Application.Builders; +using CloudBuilder.Core.Policy; +using Microsoft.Extensions.Configuration; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.DatabaseAccessor.Entity +{ + public interface IApplicationService + { + CloudBuilderBuilder CloudBuilder { get; set; } + IConfiguration Configuration { get; } + /// + /// 服务提供器 + /// + IServiceProvider ServiceProvider { get; } + + /// + /// 登录ID + /// + string UserId { get; set; } + string Locale { get; set; } + /// + /// 事务 + /// + IUnitOfWork UnitOfWork { get; set; } + /// + /// 数据仓库 + /// + /// + /// + K GetRepository(); + } +} diff --git a/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/Entity/IEntity.cs b/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/Entity/IEntity.cs new file mode 100644 index 0000000..ea872aa --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/Entity/IEntity.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.DatabaseAccessor.Entity +{ + /// + /// 数据模型接口 + /// + public interface IEntity : IGet + { + /// + /// 获取或设置 实体唯一标识,主键 + /// + TKey Id { get; set; } + } +} diff --git a/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/Entity/IEntityAudited.cs b/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/Entity/IEntityAudited.cs new file mode 100644 index 0000000..229fd31 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/Entity/IEntityAudited.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.DatabaseAccessor.Entity +{ + public interface IEntityAudited + { + public const string CREATED_DATETIME = "CreatedDatetime"; + public const string CREATED_BY = "CreatedBy"; + public const string UPDATED_DATETIME = "UpdatedDatetime"; + public const string UPDATED_BY = "UpdatedBy"; + public const string ROW_VERSION = "RowVersion"; + } +} diff --git a/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/Entity/IGet.cs b/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/Entity/IGet.cs new file mode 100644 index 0000000..c398d81 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/Entity/IGet.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.DatabaseAccessor.Entity +{ + public interface IGet + { + string GetSelectFrom(); + } +} diff --git a/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/Entity/IMaster.cs b/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/Entity/IMaster.cs new file mode 100644 index 0000000..1af3ffe --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/Entity/IMaster.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.DatabaseAccessor.Entity +{ + /// + /// 注册主库实体类 + /// + public interface IMaster + { + } +} diff --git a/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/Entity/IRepository.cs b/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/Entity/IRepository.cs new file mode 100644 index 0000000..0fda1cc --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/Entity/IRepository.cs @@ -0,0 +1,169 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.ChangeTracking; +using System; +using System.Collections.Generic; +using System.Data; +using System.Data.Common; +using System.Linq; +using System.Linq.Expressions; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.DatabaseAccessor.Entity +{ + /// + /// 定义实体仓储模型的数据标准操作 + /// + /// 实体类型 + /// 主键类型 + public interface IRepository + where TEntity : class + { + /// + /// 实体集合 + /// + DbSet Entities { get; } + + /// + /// 不跟踪的(脱轨)实体 + /// + IQueryable DetachedEntities { get; } + + /// + /// 服务提供器 + /// + IServiceProvider ServiceProvider { get; } + /// + /// 事务 + /// + IUnitOfWork UnitOfWork { get; set; } + + DbContext GetDbContext(); + + K GetRepository(); + /// + /// 动态改变主数据库 + /// + void ChangeMasterDatabase(); + + /// + /// 动态改变主数据库 + /// + void ChangeSecondaryDatabase(); + + #region FromSqlRaw + IQueryable FromSql(string sql, params object[] parameters); + IQueryable FromSqlWhere(TEntity t, string where, params object[] parameters); + + TEntity[] FindBySql(string sql, params object[] parameters); + TEntity[] FindBySqlWhere(TEntity t, string where, params object[] parameters); + + void PackSqlParameter(List parameters, string parameterName, object value); + + void ExecuteNonQuery(string sql, params object[] parameters); + + object ExecuteScalar(string sql, params object[] parameters); + + DataTable SelectDataTableBySql(string sql, params object[] parameters); + + DataTable SelectDataTableByMySql(string sql, params object[] parameters); + + #endregion + + + #region Insert + + EntityEntry Insert(TEntity entity); + + void Insert(params TEntity[] entities); + + void Insert(IEnumerable entities); + + Task> InsertAsync(TEntity entity, CancellationToken cancellationToken = default); + + Task InsertAsync(params TEntity[] entities); + + Task InsertAsync(IEnumerable entities, CancellationToken cancellationToken = default); + + EntityEntry InsertNow(TEntity entity); + + void InsertNow(params TEntity[] entities); + + void InsertNow(IEnumerable entities); + + Task> InsertNowAsync(TEntity entity, CancellationToken cancellationToken = default); + + Task InsertNowAsync(params TEntity[] entities); + + Task InsertNowAsync(TEntity[] entities, CancellationToken cancellationToken = default); + + Task InsertNowAsync(IEnumerable entities, CancellationToken cancellationToken = default); + int SaveNow(); + + Task SaveNowAsync(CancellationToken cancellationToken = default); + + #endregion + + #region Update + EntityEntry Update(TEntity entity); + void Update(params TEntity[] entities); + void Update(IEnumerable entities); + Task> UpdateAsync(TEntity entity); + Task UpdateAsync(params TEntity[] entities); + Task UpdateAsync(IEnumerable entities); + EntityEntry UpdateNow(TEntity entity); + void UpdateNow(params TEntity[] entities); + void UpdateNow(IEnumerable entities); + Task> UpdateNowAsync(TEntity entity, CancellationToken cancellationToken = default); + Task UpdateNowAsync(params TEntity[] entities); + Task UpdateNowAsync(TEntity[] entities, CancellationToken cancellationToken = default); + Task UpdateNowAsync(IEnumerable entities, CancellationToken cancellationToken = default); + EntityEntry UpdateInclude(TEntity entity, IEnumerable propertyNames); + EntityEntry UpdateInclude(TEntity entity, IEnumerable>> propertyPredicates); + Task> UpdateIncludeAsync(TEntity entity, string[] propertyNames); + Task> UpdateIncludeAsync(TEntity entity, Expression>[] propertyPredicates); + Task> UpdateIncludeAsync(TEntity entity, IEnumerable propertyNames); + Task> UpdateIncludeAsync(TEntity entity, IEnumerable>> propertyPredicates); + EntityEntry UpdateIncludeNow(TEntity entity, string[] propertyNames); + EntityEntry UpdateIncludeNow(TEntity entity, Expression>[] propertyPredicates); + EntityEntry UpdateIncludeNow(TEntity entity, IEnumerable propertyNames); + EntityEntry UpdateIncludeNow(TEntity entity, IEnumerable>> propertyPredicates); + Task> UpdateIncludeNowAsync(TEntity entity, string[] propertyNames, CancellationToken cancellationToken = default); + Task> UpdateIncludeNowAsync(TEntity entity, Expression>[] propertyPredicates, CancellationToken cancellationToken = default); + Task> UpdateIncludeNowAsync(TEntity entity, IEnumerable propertyNames, CancellationToken cancellationToken = default); + Task> UpdateIncludeNowAsync(TEntity entity, IEnumerable>> propertyPredicates, CancellationToken cancellationToken = default); + EntityEntry UpdateExclude(TEntity entity, IEnumerable propertyNames); + EntityEntry UpdateExclude(TEntity entity, IEnumerable>> propertyPredicates); + Task> UpdateExcludeAsync(TEntity entity, string[] propertyNames); + Task> UpdateExcludeAsync(TEntity entity, Expression>[] propertyPredicates); + Task> UpdateExcludeAsync(TEntity entity, IEnumerable propertyNames); + Task> UpdateExcludeAsync(TEntity entity, IEnumerable>> propertyPredicates); + EntityEntry UpdateExcludeNow(TEntity entity, string[] propertyNames); + EntityEntry UpdateExcludeNow(TEntity entity, Expression>[] propertyPredicates); + EntityEntry UpdateExcludeNow(TEntity entity, IEnumerable propertyNames); + EntityEntry UpdateExcludeNow(TEntity entity, IEnumerable>> propertyPredicates); + Task> UpdateExcludeNowAsync(TEntity entity, string[] propertyNames, CancellationToken cancellationToken = default); + Task> UpdateExcludeNowAsync(TEntity entity, Expression>[] propertyPredicates, CancellationToken cancellationToken = default); + Task> UpdateExcludeNowAsync(TEntity entity, IEnumerable propertyNames, CancellationToken cancellationToken = default); + Task> UpdateExcludeNowAsync(TEntity entity, IEnumerable>> propertyPredicates, CancellationToken cancellationToken = default); + + #endregion + + #region Delete + EntityEntry Delete(TEntity entity); + void Delete(params TEntity[] entities); + void Delete(IEnumerable entities); + Task> DeleteAsync(TEntity entity); + Task DeleteAsync(params TEntity[] entities); + Task DeleteAsync(IEnumerable entities); + EntityEntry DeleteNow(TEntity entity); + void DeleteNow(params TEntity[] entities); + void DeleteNow(IEnumerable entities); + Task> DeleteNowAsync(TEntity entity, CancellationToken cancellationToken = default); + Task DeleteNowAsync(params TEntity[] entities); + Task DeleteNowAsync(TEntity[] entities, CancellationToken cancellationToken = default); + Task DeleteNowAsync(IEnumerable entities, CancellationToken cancellationToken = default); + + #endregion + } +} diff --git a/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/Entity/ISecondary.cs b/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/Entity/ISecondary.cs new file mode 100644 index 0000000..b1c9afb --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/Entity/ISecondary.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.DatabaseAccessor.Entity +{ + /// + /// 注入从库实体类 + /// + public interface ISecondary + { + } +} diff --git a/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/Entity/ITypeScriptData.cs b/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/Entity/ITypeScriptData.cs new file mode 100644 index 0000000..6d1c8e5 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/Entity/ITypeScriptData.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.DatabaseAccessor.Entity +{ + /// + /// 实现接口将生成TypeScript文件的条件 + /// + public interface IData + { + } +} diff --git a/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/Entity/IUnitOfWork.cs b/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/Entity/IUnitOfWork.cs new file mode 100644 index 0000000..fcf1d64 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/Entity/IUnitOfWork.cs @@ -0,0 +1,53 @@ +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.DatabaseAccessor.Entity +{ + /// + /// 业务单元操作接口 + /// + public interface IUnitOfWork : IDisposable + { + /// + /// 获取 工作单元的事务是否已提交 + /// + bool HasCommitted { get; } + + /// + /// 添加DbContext共享事务 + /// + void AddDbContext(DbContext dbContext); + /// + /// 获取指定数据实体的上下文类型 + /// + /// 实体类型 + /// 实体所属上下文实例 + DbContext GetDbContext(); + + /// + /// 对数据库连接开启事务 + /// + void BeginOrUseTransaction(); + + /// + /// 对数据库连接开启事务 + /// + /// 异步取消标记 + /// + Task BeginOrUseTransactionAsync(CancellationToken cancellationToken = default); + + /// + /// 提交当前上下文的事务更改 + /// + void Commit(); + + /// + /// 回滚所有事务 + /// + void Rollback(); + } +} diff --git a/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/Entity/ViewEntityBase.cs b/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/Entity/ViewEntityBase.cs new file mode 100644 index 0000000..ac8f83b --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/Entity/ViewEntityBase.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.DatabaseAccessor.Entity +{ + public abstract class ViewEntityBase : IEntity + { + /// + /// View没有主键 + /// + [NotMapped] + public string? Id { get; set; } + + public virtual string GetSelectFrom() + { + return null!; + } + + public virtual string GetSelectCountFrom(string sqlWhere) + { + return null!; + } + + public virtual string GetSelectTopFrom(int limit, int start, string orderby, string orderbytag, string sqlWhere) + { + return null!; + } + } +} diff --git a/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/MasterDbContext.cs b/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/MasterDbContext.cs new file mode 100644 index 0000000..397f9c9 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/MasterDbContext.cs @@ -0,0 +1,218 @@ +using CloudBuilder.Core.DatabaseAccessor.Entity; +using CloudBuilder.Core.DependencyInjection.EFCore; +using CloudBuilder.Core.Policy; +using CloudBuilder.Core.Service; +using DocumentFormat.OpenXml.Math; +using DocumentFormat.OpenXml.Vml.Office; +using Microsoft.AspNetCore.Http; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Diagnostics; +using Microsoft.Extensions.Configuration; +using Microsoft.IdentityModel.JsonWebTokens; +using System; +using System.Collections.Generic; +using System.IdentityModel.Tokens.Jwt; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.DatabaseAccessor +{ + public class MasterDbContext : DbContext + { + public const string MASTER_DB_CONTEXT = "MasterDbContext"; + + public IEnumerable> _entityManagers; + private readonly IServiceProvider _serviceProvider; + private readonly IConfiguration configuration; + private readonly IHttpContextAccessor httpContextAccessor; + private FileLog fileLog; + + public MasterDbContext(DbContextOptions options, + IEnumerable> entityManagers, + IServiceProvider serviceProvider, + IConfiguration configuration, + IHttpContextAccessor httpContextAccessor + ) : base(options) + { + _entityManagers = entityManagers; + _serviceProvider = serviceProvider; + this.configuration = configuration; + this.httpContextAccessor = httpContextAccessor; + fileLog = new FileLog(configuration); + } + + public override int SaveChanges(bool acceptAllChangesOnSuccess) + { + try + { + SavingChangesEvent(); + return base.SaveChanges(acceptAllChangesOnSuccess); + } + catch (Exception ex) + { + //自动检验数据是否过时 + //ALTER TABLE table ADD row_version rowversion; + //[Column("row_version")] + //[Timestamp] + //public byte[] RowVersion { get; set; } + if (ex.Message.Contains("data may have been modified or deleted since entities were loaded.")) + { + throw new ValidatedException(CoreMessagePolicy.GetInstance().ComposeMessage(CoreMessagePolicy.THE_DATA_HAS_BEEN_MODIFIED)); + } + throw new ValidatedException(ex.InnerException?.Message ?? ex.Message); + } + + } + + public void SavingChangesEvent() + { + var entities = this.ChangeTracker.Entries() + .Where(u => (u.State == EntityState.Modified || u.State == EntityState.Deleted || u.State == EntityState.Added)).ToList(); + if (entities == null || entities.Count < 1) return; + + string uid = this.httpContextAccessor.HttpContext?.User?.Identity?.Name; + + DateTime now = DateTime.Now; + if (string.IsNullOrEmpty(uid)) + { + uid = GetUserIdFromToken(httpContextAccessor.HttpContext!); + } + + foreach (var entity in entities) + { + if (!(entity.State == EntityState.Added || entity.State == EntityState.Modified)) continue; + + // 获取所有实体有效属性,排除 [NotMapper] 属性 + var props = entity.OriginalValues.Properties; + + // 获取实体当前(现在)的值 + var currentValues = entity.CurrentValues; + + // 遍历所有属性 + foreach (var prop in props) + { + // 获取属性名 + var propName = prop.Name; + if (propName == IEntityAudited.CREATED_BY && entity.State == EntityState.Added) + { + currentValues[propName] = uid; + continue; + } + + if (propName == IEntityAudited.CREATED_DATETIME && entity.State == EntityState.Added) + { + currentValues[propName] = DateTime.Now; + continue; + } + + if (propName == IEntityAudited.UPDATED_BY) + { + currentValues[propName] = uid; + continue; + } + + if (propName == IEntityAudited.UPDATED_DATETIME) + { + currentValues[propName] = DateTime.Now; + continue; + } + } + } + + foreach (var entity in entities) + { + var entityName = entity.Metadata.GetTableName() ?? entity.Entity.GetType().Name; + var state = entity.State; + + // ====================================== + // 1. 获取所有主键(支持复合主键) + // ====================================== + var pkProps = entity.Properties + .Where(p => p.Metadata.IsPrimaryKey()) + .ToList(); + + // 拼接 WHERE 条件:Id=1 AND TenantId=2 + var whereClauses = pkProps + .Select(p => $"{p.Metadata.GetColumnName() ?? p.Metadata.Name} = '{p.CurrentValue?.ToString()?.Replace("'", "''")}'"); + string whereSql = string.Join(" AND ", whereClauses); + + string sqlLog = ""; + + // ====================================== + // 修改 UPDATE + // ====================================== + if (state == EntityState.Modified) + { + var setClauses = entity.Properties + .Where(p => p.IsModified) // 只记录真正修改的字段 + .Select(p => $"{p.Metadata.GetColumnName() ?? p.Metadata.Name} = '{p.CurrentValue?.ToString()?.Replace("'", "''")}'"); + + string setSql = string.Join(", ", setClauses); + sqlLog = $"[{uid}][{now.ToString("yyyy-MM-dd HH:mm:ss")}]UPDATE {entityName} SET {setSql} WHERE {whereSql}"; + } + + // ====================================== + // 新增 INSERT + // ====================================== + else if (state == EntityState.Added) + { + var data = entity.Properties.ToDictionary(p => p.Metadata.GetColumnName() ?? p.Metadata.Name, p => p.CurrentValue); + var columns = string.Join(", ", data.Keys); + var values = string.Join(", ", data.Values.Select(v => $"'{v?.ToString()?.Replace("'", "''")}'")); + sqlLog = $"[{uid}][{now.ToString("yyyy-MM-dd HH:mm:ss")}]INSERT INTO {entityName} ({columns}) VALUES ({values})"; + } + + // ====================================== + // 删除 DELETE + // ====================================== + else if (state == EntityState.Deleted) + { + sqlLog = $"[{uid}][{now.ToString("yyyy-MM-dd HH:mm:ss")}]DELETE FROM {entityName} WHERE {whereSql}"; + } + + fileLog.WriteToFile(sqlLog); + } + } + + protected override void OnModelCreating(ModelBuilder builder) + { + foreach (IMasterRegistEntityType entityManager in _entityManagers) + { + entityManager.RegistEntity(builder); + } + + base.OnModelCreating(builder); + } + + public string GetJwtBearerToken(HttpContext httpContext, string headerKey = "Authorization", string tokenPrefix = "Bearer ") + { + if (httpContext == null) return null; + // 判断请求报文头中是否有 "Authorization" 报文头 + var bearerToken = httpContext.Request.Headers[headerKey].ToString(); + if (string.IsNullOrWhiteSpace(bearerToken)) return default; + + var prefixLenght = tokenPrefix.Length; + return bearerToken.StartsWith(tokenPrefix, true, null) && bearerToken.Length > prefixLenght ? bearerToken[prefixLenght..] : default; + } + + public string GetUserIdFromToken(HttpContext httpContext) + { + string token = GetJwtBearerToken(httpContextAccessor.HttpContext!); + if (!string.IsNullOrEmpty(token)) + { + try + { + JsonWebToken json = new JsonWebTokenHandler().ReadJsonWebToken(token); + return json.GetClaim(ClaimPolicy.CLAINM_USERID).Value; + } + catch (Exception) + { + return string.Empty; + } + } + + return string.Empty; + } + } +} diff --git a/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/Repository.cs b/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/Repository.cs new file mode 100644 index 0000000..4fb8c0e --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/Repository.cs @@ -0,0 +1,943 @@ +using CloudBuilder.Core.Application.Builders; +using Microsoft.AspNetCore.Http; +using Microsoft.Data.SqlClient; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.ChangeTracking; +using Microsoft.Extensions.DependencyInjection; +using MySqlConnector; +using System.Data; +using System.Data.Common; +using System.Linq.Expressions; + +namespace CloudBuilder.Core.DatabaseAccessor.Entity +{ + public class Repository : IRepository where TEntity : class + { + private readonly CloudBuilderBuilder builder; + private DbContext dbContext; + private readonly IHttpContextAccessor httpContext; + // 主库key + public const string MASTER_DB_CONTEXT = MasterDbContext.MASTER_DB_CONTEXT; + // 从库key + public const string SECONDARY_DB_CONTEXT = SecondaryDbContext.SECONDARY_DB_CONTEXT; + + public Repository(IServiceProvider serviceProvider, + [FromKeyedServices(MASTER_DB_CONTEXT)] DbContext dbContext, + IUnitOfWork unitOfWork, + IHttpContextAccessor httpContext) + { + this.httpContext = httpContext; + this.dbContext = dbContext; + this.UnitOfWork = unitOfWork; + ServiceProvider = serviceProvider; + Entities = this.dbContext.Set()!; + DetachedEntities = Entities.AsNoTracking()!; + } + + public IUnitOfWork UnitOfWork { get; set; } + + public DbContext GetDbContext() { return dbContext; } + + public DbSet Entities { get; set; } = null!; + + public IQueryable DetachedEntities { get; set; } = null!; + + + public DbConnection DbConnection + { + get + { + return dbContext.Database.GetDbConnection(); + } + } + + public IServiceProvider ServiceProvider { get; set; } = null!; + + public virtual TRepository GetRepository() + { + return ServiceProvider.GetRequiredService(); + } + + public void ChangeMasterDatabase() + { + this.dbContext = ServiceProvider.GetRequiredKeyedService(MasterDbContext.MASTER_DB_CONTEXT); + Entities = this.dbContext.Set()!; + DetachedEntities = Entities.AsNoTracking()!; + } + + public void ChangeSecondaryDatabase() + { + this.dbContext = ServiceProvider.GetRequiredKeyedService(SecondaryDbContext.SECONDARY_DB_CONTEXT); + Entities = this.dbContext.Set()!; + DetachedEntities = Entities.AsNoTracking()!; + } + + #region FromSqlRaw + + public virtual IQueryable FromSql(string sql, params object[] parameters) + { + if (parameters == null) + return Entities.FromSqlRaw(sql); + else + return Entities.FromSqlRaw(sql, parameters); + } + + public virtual IQueryable FromSqlWhere(TEntity t, string where, params object[] parameters) + { + string sql = $"{((IEntity)t).GetSelectFrom()} {where} "; + if (parameters == null) + return Entities.FromSqlRaw(sql); + else + return Entities.FromSqlRaw(sql, parameters); + } + + public virtual TEntity[] FindBySql(string sql, params object[] parameters) + { + if (parameters == null) + return Entities.FromSqlRaw(sql).ToArray(); + else + return Entities.FromSqlRaw(sql, parameters).ToArray(); + } + + public virtual TEntity[] FindBySqlWhere(TEntity t, string where, params object[] parameters) + { + string sql = $"{((IGet)t).GetSelectFrom()} {where} "; + if (parameters == null) + return Entities.FromSqlRaw(sql).ToArray(); + else + return Entities.FromSqlRaw(sql, parameters).ToArray(); + } + + public void PackSqlParameter(List parameters, string parameterName, object value) + { + if (parameters == null) parameters = new List(); + else + { + string formatedValue; + if (value == null) formatedValue = $"null"; + else + { + formatedValue = $"'{value.ToString()}'"; + if (value is DateTime && !string.IsNullOrEmpty(formatedValue)) + formatedValue = $"'{Convert.ToDateTime(formatedValue).ToString("yyyy-MM-dd HH:mm:ss")}'"; + } + + parameters.Add(new MySqlParameter(parameterName, value == null ? DBNull.Value : value)); + } + } + + public void PackMySqlParameter(List parameters, string parameterName, object value) + { + if (parameters == null) parameters = new List(); + else + { + string formatedValue; + if (value == null) formatedValue = $"null"; + else + { + formatedValue = $"'{value.ToString()}'"; + if (value is DateTime && !string.IsNullOrEmpty(formatedValue)) + formatedValue = $"'{Convert.ToDateTime(formatedValue).ToString("yyyy-MM-dd HH:mm:ss")}'"; + } + + parameters.Add(new MySqlParameter(parameterName, value == null ? DBNull.Value : value)); + } + } + + public virtual void ExecuteNonQuery(string sql, params object[] parameters) + { + var conn = dbContext.Database.GetDbConnection(); ; + + if (conn.State != ConnectionState.Open) + { + conn.Open(); + } + + var cmd = conn.CreateCommand(); + + cmd.CommandText = sql; + if (parameters != null && parameters.Length > 0) + cmd.Parameters.AddRange(parameters); + + + cmd.ExecuteNonQuery(); + } + + public virtual object ExecuteScalar(string sql, params object[] parameters) + { + var conn = dbContext.Database.GetDbConnection(); ; + + conn.Open(); + var cmd = conn.CreateCommand(); + + cmd.CommandText = sql; + if (parameters != null && parameters.Length > 0) + cmd.Parameters.AddRange(parameters); + + + return cmd.ExecuteScalar(); + } + + + public virtual DataTable SelectDataTableByMySql(string sql, params object[] parameters) + { + var conn = dbContext.Database.GetDbConnection(); ; + + conn.Open(); + var cmd = conn.CreateCommand(); + + cmd.CommandText = sql; + if (parameters != null && parameters.Length > 0) + cmd.Parameters.AddRange(parameters); + + MySqlDataAdapter da = new MySqlDataAdapter(); + da.SelectCommand = cmd as MySqlCommand; + DataTable dt = new DataTable(); + da.Fill(dt); + + dt.TableName = "TableName"; + + return dt; + } + + + public virtual DataTable SelectDataTableBySql(string sql, params object[] parameters) + { + var conn = dbContext.Database.GetDbConnection(); ; + + conn.Open(); + var cmd = conn.CreateCommand(); + + cmd.CommandText = sql; + if (parameters != null && parameters.Length > 0) + cmd.Parameters.AddRange(parameters); + + SqlDataAdapter da = new SqlDataAdapter(); + da.SelectCommand = cmd as SqlCommand; + DataTable dt = new DataTable(); + da.Fill(dt); + + dt.TableName = "TableName"; + + return dt; + } + + #endregion + + #region Insert + + public virtual EntityEntry Insert(TEntity entity) + { + var entryEntity = Entities.Add(entity); + + return entryEntity; + } + + public virtual void Insert(params TEntity[] entities) + { + Entities.AddRange(entities); + } + + public virtual void Insert(IEnumerable entities) + { + Entities.AddRange(entities); + } + + public virtual async Task> InsertAsync(TEntity entity, CancellationToken cancellationToken = default) + { + var entityEntry = await Entities.AddAsync(entity, cancellationToken); + + return entityEntry; + } + + public virtual Task InsertAsync(params TEntity[] entities) + { + return Entities.AddRangeAsync(entities); + } + + public virtual Task InsertAsync(IEnumerable entities, CancellationToken cancellationToken = default) + { + return Entities.AddRangeAsync(entities, cancellationToken); + } + + public virtual EntityEntry InsertNow(TEntity entity) + { + var entityEntry = Insert(entity); + SaveNow(); + return entityEntry; + } + + /// + /// 新增多条记录 + /// + /// 多个实体 + public virtual void InsertNow(params TEntity[] entities) + { + Insert(entities); + SaveNow(); + } + + /// + /// 新增多条记录 + /// + /// 多个实体 + public virtual void InsertNow(IEnumerable entities) + { + Insert(entities); + SaveNow(); + } + + /// + /// 新增一条记录并立即提交 + /// + /// 实体 + /// + /// 取消异步令牌 + /// 数据库中返回的实体 + public virtual async Task> InsertNowAsync(TEntity entity, CancellationToken cancellationToken = default) + { + var entityEntry = await InsertAsync(entity, cancellationToken); + await SaveNowAsync(cancellationToken); + return entityEntry; + } + + /// + /// 新增多条记录并立即提交 + /// + /// 多个实体 + /// Task + public virtual async Task InsertNowAsync(params TEntity[] entities) + { + await InsertAsync(entities); + await SaveNowAsync(); + } + + /// + /// 新增多条记录并立即提交 + /// + /// 多个实体 + /// 取消异步令牌 + /// Task + public virtual async Task InsertNowAsync(TEntity[] entities, CancellationToken cancellationToken = default) + { + await InsertAsync(entities); + await SaveNowAsync(cancellationToken); + } + + /// + /// 新增多条记录并立即提交 + /// + /// 多个实体 + /// 取消异步令牌 + /// Task + public virtual async Task InsertNowAsync(IEnumerable entities, CancellationToken cancellationToken = default) + { + await InsertAsync(entities, cancellationToken); + await SaveNowAsync(cancellationToken); + } + + + /// + /// 提交更改操作 + /// + /// + public virtual int SaveNow() + { + return dbContext.SaveChanges(); + } + + /// + /// 提交更改操作(异步) + /// + /// + /// + public virtual Task SaveNowAsync(CancellationToken cancellationToken = default) + { + return dbContext.SaveChangesAsync(cancellationToken); + } + + + #endregion + + #region Update + public virtual EntityEntry Update(TEntity entity) + { + var entityEntry = Entities.Update(entity); + + return entityEntry; + } + + public virtual void Update(params TEntity[] entities) + { + Entities.UpdateRange(entities); + } + + public virtual void Update(IEnumerable entities) + { + Entities.UpdateRange(entities); + } + + public virtual Task> UpdateAsync(TEntity entity) + { + return Task.FromResult(Update(entity)); + } + + public virtual Task UpdateAsync(params TEntity[] entities) + { + Update(entities); + return Task.CompletedTask; + } + + public virtual Task UpdateAsync(IEnumerable entities) + { + Update(entities); + return Task.CompletedTask; + } + + public virtual EntityEntry UpdateNow(TEntity entity) + { + var entityEntry = Update(entity); + SaveNow(); + return entityEntry; + } + + public virtual void UpdateNow(params TEntity[] entities) + { + Update(entities); + SaveNow(); + } + + public virtual void UpdateNow(IEnumerable entities) + { + Update(entities); + SaveNow(); + } + + public virtual async Task> UpdateNowAsync(TEntity entity, CancellationToken cancellationToken = default) + { + var entityEntry = await UpdateAsync(entity); + await SaveNowAsync(cancellationToken); + return entityEntry; + } + + public virtual async Task UpdateNowAsync(params TEntity[] entities) + { + await UpdateAsync(entities); + await SaveNowAsync(); + } + + public virtual async Task UpdateNowAsync(TEntity[] entities, CancellationToken cancellationToken = default) + { + await UpdateAsync(entities); + await SaveNowAsync(cancellationToken); + } + + public virtual async Task UpdateNowAsync(IEnumerable entities, CancellationToken cancellationToken = default) + { + await UpdateAsync(entities); + await SaveNowAsync(cancellationToken); + } + + public virtual EntityEntry UpdateInclude(TEntity entity, IEnumerable propertyNames) + { + var entityEntry = ChangeEntityState(entity, EntityState.Detached); + foreach (var propertyName in propertyNames) + { + EntityPropertyEntry(entity, propertyName).IsModified = true; + } + + return entityEntry; + } + + public virtual EntityEntry UpdateInclude(TEntity entity, IEnumerable>> propertyPredicates) + { + var entityEntry = ChangeEntityState(entity, EntityState.Detached); + foreach (var propertyPredicate in propertyPredicates) + { + EntityPropertyEntry(entity, propertyPredicate).IsModified = true; + } + + return entityEntry; + } + + public virtual Task> UpdateIncludeAsync(TEntity entity, string[] propertyNames) + { + return Task.FromResult(UpdateInclude(entity, propertyNames)); + } + + public virtual Task> UpdateIncludeAsync(TEntity entity, Expression>[] propertyPredicates) + { + return Task.FromResult(UpdateInclude(entity, propertyPredicates)); + } + + public virtual Task> UpdateIncludeAsync(TEntity entity, IEnumerable propertyNames) + { + return Task.FromResult(UpdateInclude(entity, propertyNames)); + } + + public virtual Task> UpdateIncludeAsync(TEntity entity, IEnumerable>> propertyPredicates) + { + return Task.FromResult(UpdateInclude(entity, propertyPredicates)); + } + + public virtual EntityEntry UpdateIncludeNow(TEntity entity, string[] propertyNames) + { + var entityEntry = UpdateInclude(entity, propertyNames); + SaveNow(); + return entityEntry; + } + + public virtual EntityEntry UpdateIncludeNow(TEntity entity, Expression>[] propertyPredicates) + { + var entityEntry = UpdateInclude(entity, propertyPredicates); + SaveNow(); + return entityEntry; + } + + public virtual EntityEntry UpdateIncludeNow(TEntity entity, IEnumerable propertyNames) + { + var entityEntry = UpdateInclude(entity, propertyNames); + SaveNow(); + return entityEntry; + } + + public virtual EntityEntry UpdateIncludeNow(TEntity entity, IEnumerable>> propertyPredicates) + { + var entityEntry = UpdateInclude(entity, propertyPredicates); + SaveNow(); + return entityEntry; + } + + public virtual async Task> UpdateIncludeNowAsync(TEntity entity, string[] propertyNames, CancellationToken cancellationToken = default) + { + var entityEntry = await UpdateIncludeAsync(entity, propertyNames); + await SaveNowAsync(cancellationToken); + return entityEntry; + } + + public virtual async Task> UpdateIncludeNowAsync(TEntity entity, Expression>[] propertyPredicates, CancellationToken cancellationToken = default) + { + var entityEntry = await UpdateIncludeAsync(entity, propertyPredicates); + await SaveNowAsync(cancellationToken); + return entityEntry; + } + + public virtual async Task> UpdateIncludeNowAsync(TEntity entity, IEnumerable propertyNames, CancellationToken cancellationToken = default) + { + var entityEntry = await UpdateIncludeAsync(entity, propertyNames); + await SaveNowAsync(cancellationToken); + return entityEntry; + } + + public virtual async Task> UpdateIncludeNowAsync(TEntity entity, IEnumerable>> propertyPredicates, CancellationToken cancellationToken = default) + { + var entityEntry = await UpdateIncludeAsync(entity, propertyPredicates); + await SaveNowAsync(cancellationToken); + return entityEntry; + } + + + public virtual EntityEntry UpdateExclude(TEntity entity, IEnumerable propertyNames) + { + var entityEntry = ChangeEntityState(entity, EntityState.Modified); + foreach (var propertyName in propertyNames) + { + EntityPropertyEntry(entity, propertyName).IsModified = false; + } + + return entityEntry; + } + + public virtual EntityEntry UpdateExclude(TEntity entity, IEnumerable>> propertyPredicates) + { + var entityEntry = ChangeEntityState(entity, EntityState.Modified); + foreach (var propertyPredicate in propertyPredicates) + { + EntityPropertyEntry(entity, propertyPredicate).IsModified = false; + } + + return entityEntry; + } + + public virtual Task> UpdateExcludeAsync(TEntity entity, string[] propertyNames) + { + return Task.FromResult(UpdateExclude(entity, propertyNames)); + } + + public virtual Task> UpdateExcludeAsync(TEntity entity, Expression>[] propertyPredicates) + { + return Task.FromResult(UpdateExclude(entity, propertyPredicates)); + } + + public virtual Task> UpdateExcludeAsync(TEntity entity, IEnumerable propertyNames) + { + return Task.FromResult(UpdateExclude(entity, propertyNames)); + } + + + public virtual Task> UpdateExcludeAsync(TEntity entity, IEnumerable>> propertyPredicates) + { + return Task.FromResult(UpdateExclude(entity, propertyPredicates)); + } + + public virtual EntityEntry UpdateExcludeNow(TEntity entity, string[] propertyNames) + { + var entityEntry = UpdateExclude(entity, propertyNames); + SaveNow(); + return entityEntry; + } + + public virtual EntityEntry UpdateExcludeNow(TEntity entity, Expression>[] propertyPredicates) + { + var entityEntry = UpdateExclude(entity, propertyPredicates); + SaveNow(); + return entityEntry; + } + + public virtual EntityEntry UpdateExcludeNow(TEntity entity, IEnumerable propertyNames) + { + var entityEntry = UpdateExclude(entity, propertyNames); + SaveNow(); + return entityEntry; + } + + public virtual EntityEntry UpdateExcludeNow(TEntity entity, IEnumerable>> propertyPredicates) + { + var entityEntry = UpdateExclude(entity, propertyPredicates); + SaveNow(); + return entityEntry; + } + + public virtual async Task> UpdateExcludeNowAsync(TEntity entity, string[] propertyNames, CancellationToken cancellationToken = default) + { + var entityEntry = await UpdateExcludeAsync(entity, propertyNames); + await SaveNowAsync(cancellationToken); + return entityEntry; + } + + public virtual async Task> UpdateExcludeNowAsync(TEntity entity, Expression>[] propertyPredicates, CancellationToken cancellationToken = default) + { + var entityEntry = await UpdateExcludeAsync(entity, propertyPredicates); + await SaveNowAsync(cancellationToken); + return entityEntry; + } + + public virtual async Task> UpdateExcludeNowAsync(TEntity entity, IEnumerable propertyNames, CancellationToken cancellationToken = default) + { + var entityEntry = await UpdateExcludeAsync(entity, propertyNames); + await SaveNowAsync(cancellationToken); + return entityEntry; + } + + public virtual async Task> UpdateExcludeNowAsync(TEntity entity, IEnumerable>> propertyPredicates, CancellationToken cancellationToken = default) + { + var entityEntry = await UpdateExcludeAsync(entity, propertyPredicates); + await SaveNowAsync(cancellationToken); + return entityEntry; + } + + #endregion + + #region Delete + public virtual EntityEntry Delete(TEntity entity) + { + return Entities.Remove(entity); + } + + public virtual void Delete(params TEntity[] entities) + { + Entities.RemoveRange(entities); + } + + public virtual void Delete(IEnumerable entities) + { + Entities.RemoveRange(entities); + } + + public virtual Task> DeleteAsync(TEntity entity) + { + return Task.FromResult(Delete(entity)); + } + + public virtual Task DeleteAsync(params TEntity[] entities) + { + Delete(entities); + return Task.CompletedTask; + } + + public virtual Task DeleteAsync(IEnumerable entities) + { + Delete(entities); + return Task.CompletedTask; + } + + public virtual EntityEntry DeleteNow(TEntity entity) + { + var entityEntry = Delete(entity); + SaveNow(); + return entityEntry; + } + + public virtual void DeleteNow(params TEntity[] entities) + { + Delete(entities); + SaveNow(); + } + + public virtual void DeleteNow(IEnumerable entities) + { + Delete(entities); + SaveNow(); + } + + public virtual async Task> DeleteNowAsync(TEntity entity, CancellationToken cancellationToken = default) + { + var entityEntry = await DeleteAsync(entity); + await SaveNowAsync(cancellationToken); + return entityEntry; + } + + public virtual async Task DeleteNowAsync(params TEntity[] entities) + { + await DeleteAsync(entities); + await SaveNowAsync(); + } + + public virtual async Task DeleteNowAsync(TEntity[] entities, CancellationToken cancellationToken = default) + { + await DeleteAsync(entities); + await SaveNowAsync(cancellationToken); + } + + public virtual async Task DeleteNowAsync(IEnumerable entities, CancellationToken cancellationToken = default) + { + await DeleteAsync(entities); + await SaveNowAsync(cancellationToken); + } + + #endregion + + #region EntityEntry + + /// + /// 将实体加入数据上下文托管 + /// + /// 实体 + /// EntityEntry + public virtual EntityEntry Entry(object entity) + { + return dbContext.Entry(entity); + } + + /// + /// 将实体加入数据上下文托管 + /// + /// 实体 + /// + public virtual EntityEntry Entry(TEntity entity) + { + return dbContext.Entry(entity); + } + + /// + /// 获取实体状态 + /// + /// 实体 + /// + public virtual EntityState EntityEntryState(object entity) + { + return Entry(entity).State; + } + + /// + /// 获取实体状态 + /// + /// 实体 + /// EntityState + public virtual EntityState EntityEntryState(TEntity entity) + { + return Entry(entity).State; + } + + /// + /// 将实体属性加入托管 + /// + /// 实体 + /// 属性名 + /// PropertyEntry + public virtual PropertyEntry EntityPropertyEntry(object entity, string propertyName) + { + return Entry(entity).Property(propertyName); + } + + /// + /// 将实体属性加入托管 + /// + /// 实体 + /// 属性名 + /// PropertyEntry + public virtual PropertyEntry EntityPropertyEntry(TEntity entity, string propertyName) + { + return Entry(entity).Property(propertyName); + } + + /// + /// 将实体属性加入托管 + /// + /// 属性类型 + /// 实体 + /// 属性表达式 + /// PropertyEntry + public virtual PropertyEntry EntityPropertyEntry(TEntity entity, Expression> propertyPredicate) + { + return Entry(entity).Property(propertyPredicate); + } + + /// + /// 改变实体状态 + /// + /// 实体 + /// 实体状态 + /// EntityEntry + public virtual EntityEntry ChangeEntityState(object entity, EntityState entityState) + { + var entityEntry = Entry(entity); + entityEntry.State = entityState; + return entityEntry; + } + + /// + /// 改变实体状态 + /// + /// 实体 + /// 实体状态 + /// EntityEntry{TEntity} + public virtual EntityEntry ChangeEntityState(TEntity entity, EntityState entityState) + { + var entityEntry = Entry(entity); + entityEntry.State = entityState; + return entityEntry; + } + + /// + /// 改变实体状态 + /// + /// 实体条目 + /// 实体状态 + /// EntityEntry + public virtual EntityEntry ChangeEntityState(EntityEntry entityEntry, EntityState entityState) + { + entityEntry.State = entityState; + return entityEntry; + } + + /// + /// 改变实体状态 + /// + /// 实体条目 + /// 实体状态 + /// EntityEntry{TEntity} + public virtual EntityEntry ChangeEntityState(EntityEntry entityEntry, EntityState entityState) + { + entityEntry.State = entityState; + return entityEntry; + } + + /// + /// 判断是否被附加 + /// + /// 实体 + /// bool + public virtual bool IsAttached(object entity) + { + return EntityEntryState(entity) != EntityState.Detached; + } + + /// + /// 判断是否被附加 + /// + /// 实体 + /// bool + public virtual bool IsAttached(TEntity entity) + { + return EntityEntryState(entity) != EntityState.Detached; + } + + /// + /// 附加实体 + /// + /// 实体 + /// EntityEntry + public virtual EntityEntry Attach(object entity) + { + return dbContext.Attach(entity); + } + + /// + /// 附加实体 + /// + /// 实体 + /// EntityEntry + public virtual EntityEntry Attach(TEntity entity) + { + return dbContext.Attach(entity); + } + + /// + /// 附加多个实体 + /// + /// 多个实体 + public virtual void AttachRange(params object[] entities) + { + dbContext.AttachRange(entities); + } + + /// + /// 附加多个实体 + /// + /// 多个实体 + public virtual void AttachRange(IEnumerable entities) + { + dbContext.AttachRange(entities); + } + + /// + /// 取消附加实体 + /// + /// 实体 + public virtual void Detach(object entity) + { + ChangeEntityState(entity, EntityState.Detached); + } + + /// + /// 取消附加实体 + /// + /// 实体 + public virtual void Detach(TEntity entity) + { + ChangeEntityState(entity, EntityState.Detached); + } + + /// + /// 取消附加实体 + /// + /// 实体条目 + public virtual void Detach(EntityEntry entityEntry) + { + ChangeEntityState(entityEntry, EntityState.Detached); + } + + /// + /// 取消附加实体 + /// + /// 实体条目 + public virtual void Detach(EntityEntry entityEntry) + { + ChangeEntityState(entityEntry, EntityState.Detached); + } + + + #endregion + } +} diff --git a/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/SecondaryDbContext.cs b/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/SecondaryDbContext.cs new file mode 100644 index 0000000..ff67671 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/SecondaryDbContext.cs @@ -0,0 +1,142 @@ +using CloudBuilder.Core.DatabaseAccessor.Entity; +using CloudBuilder.Core.DependencyInjection.EFCore; +using CloudBuilder.Core.Policy; +using CloudBuilder.Core.Service; +using Microsoft.AspNetCore.Http; +using Microsoft.EntityFrameworkCore; +using Microsoft.IdentityModel.JsonWebTokens; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.DatabaseAccessor +{ + public class SecondaryDbContext : DbContext + { + public const string SECONDARY_DB_CONTEXT = "SecondaryDbContext"; + + public IEnumerable> _entityManagers; + private readonly IServiceProvider _serviceProvider; + private readonly IHttpContextAccessor httpContextAccessor; + + public SecondaryDbContext(DbContextOptions options, + IEnumerable> entityManagers, + IServiceProvider serviceProvider, + IHttpContextAccessor httpContextAccessor) : base(options) + { + _entityManagers = entityManagers; + _serviceProvider = serviceProvider; + this.httpContextAccessor = httpContextAccessor; + } + + public override int SaveChanges(bool acceptAllChangesOnSuccess) + { + try + { + SavingChangesEvent(); + return base.SaveChanges(acceptAllChangesOnSuccess); + } + catch (Exception ex) + { + if (ex.Message.Contains("data may have been modified or deleted since entities were loaded.")) + { + throw new ValidatedException(CoreMessagePolicy.GetInstance().ComposeMessage(CoreMessagePolicy.THE_DATA_HAS_BEEN_MODIFIED)); + } + throw new ValidatedException(ex.InnerException?.Message ?? ex.Message); + } + } + + public void SavingChangesEvent() + { + var entities = this.ChangeTracker.Entries() + .Where(u => (u.State == EntityState.Modified || u.State == EntityState.Deleted || u.State == EntityState.Added)).ToList(); + if (entities == null || entities.Count < 1) return; + + string uid = this.httpContextAccessor.HttpContext?.User?.Identity?.Name; + + if (string.IsNullOrEmpty(uid)) + { + uid = string.Empty; + string token = GetJwtBearerToken(httpContextAccessor.HttpContext!); + if (!string.IsNullOrEmpty(token)) + { + try + { + JsonWebToken json = new JsonWebTokenHandler().ReadJsonWebToken(token); + uid = json.GetClaim(ClaimPolicy.CLAINM_USERID).Value; + } + catch (Exception) + { + + } + + } + } + + foreach (var entity in entities) + { + if (!(entity.State == EntityState.Added || entity.State == EntityState.Modified)) continue; + + // 获取所有实体有效属性,排除 [NotMapper] 属性 + var props = entity.OriginalValues.Properties; + + // 获取实体当前(现在)的值 + var currentValues = entity.CurrentValues; + + // 遍历所有属性 + foreach (var prop in props) + { + // 获取属性名 + var propName = prop.Name; + if (propName == IEntityAudited.CREATED_BY && entity.State == EntityState.Added) + { + currentValues[propName] = uid; + continue; + } + + if (propName == IEntityAudited.CREATED_DATETIME && entity.State == EntityState.Added) + { + currentValues[propName] = DateTime.Now; + continue; + } + + if (propName == IEntityAudited.UPDATED_BY) + { + currentValues[propName] = uid; + continue; + } + + if (propName == IEntityAudited.UPDATED_DATETIME) + { + currentValues[propName] = DateTime.Now; + continue; + } + } + } + } + + protected override void OnModelCreating(ModelBuilder builder) + { + foreach (IMasterRegistEntityType entityManager in _entityManagers) + { + entityManager.RegistEntity(builder); + } + + base.OnModelCreating(builder); + } + + public string GetJwtBearerToken(HttpContext httpContext, string headerKey = "Authorization", string tokenPrefix = "Bearer ") + { + if (httpContext == null) return null; + // 判断请求报文头中是否有 "Authorization" 报文头 + var bearerToken = httpContext.Request.Headers[headerKey].ToString(); + if (string.IsNullOrWhiteSpace(bearerToken)) return default; + + var prefixLenght = tokenPrefix.Length; + return bearerToken.StartsWith(tokenPrefix, true, null) && bearerToken.Length > prefixLenght ? bearerToken[prefixLenght..] : default; + } + + } +} diff --git a/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/UnitOfWork.cs b/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/UnitOfWork.cs new file mode 100644 index 0000000..0f62af4 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/UnitOfWork.cs @@ -0,0 +1,200 @@ +using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Data.Common; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using Microsoft.Extensions.DependencyInjection; + +namespace CloudBuilder.Core.DatabaseAccessor +{ + public class UnitOfWork : IUnitOfWork + { + private readonly List _dbContexts = new List(); + private DbTransaction _transaction; + private DbConnection _connection; + private DbContext _dbContext; + + /// + /// 初始化一个类型的新实例 + /// + public UnitOfWork([FromKeyedServices(MasterDbContext.MASTER_DB_CONTEXT)] DbContext context) + { + _dbContext = context; + _dbContexts.Add(_dbContext); + _connection = _dbContext.Database.GetDbConnection(); + } + + + /// + /// 获取 事务是否已提交 + /// + public bool HasCommitted { get; private set; } + + /// + /// 添加DbContext共享事务 + /// + public void AddDbContext(DbContext dbContext) + { + _dbContexts.Add(dbContext); + } + + public DbContext GetDbContext() + { + return _dbContext; + } + + /// + /// 对数据库连接开启事务 + /// + public virtual void BeginOrUseTransaction() + { + if (_dbContexts.Count == 0) + { + return; + } + if (_transaction?.Connection == null) + { + if (_connection.State != ConnectionState.Open) + { + _connection.Open(); + } + + _transaction = _connection.BeginTransaction(); + } + + foreach (DbContext context in _dbContexts) + { + if (context.Database.CurrentTransaction != null && context.Database.CurrentTransaction.GetDbTransaction() == _transaction) + { + continue; + } + //if (context.IsRelationalTransaction()) + //{ + //共享事务仅限关系数据库 + context.Database.UseTransaction(_transaction); + //} + //else + //{ + // context.Database.BeginTransaction(); + //} + } + + HasCommitted = false; + } + + /// + /// 对数据库连接开启事务 + /// + /// 异步取消标记 + /// + public virtual async Task BeginOrUseTransactionAsync(CancellationToken cancellationToken = default) + { + if (_dbContexts.Count == 0) + { + return; + } + if (_transaction?.Connection == null) + { + if (_connection.State != ConnectionState.Open) + { + await _connection.OpenAsync(cancellationToken); + } + + _transaction = _connection.BeginTransaction(); + } + + foreach (DbContext context in _dbContexts) + { + if (context.Database.CurrentTransaction != null && context.Database.CurrentTransaction.GetDbTransaction() == _transaction) + { + continue; + } + //if (context.IsRelationalTransaction()) + //{ + context.Database.UseTransaction(_transaction); + //} + //else + //{ + // await context.Database.BeginTransactionAsync(cancellationToken); + //} + } + + HasCommitted = false; + } + + /// + /// 提交当前上下文的事务更改 + /// + public virtual void Commit() + { + if (HasCommitted || _dbContexts.Count == 0 || _transaction == null) + { + return; + } + + _transaction.Commit(); + foreach (DbContext context in _dbContexts) + { + //if (context.IsRelationalTransaction()) + //{ + context.Database.CurrentTransaction.Dispose(); + //关系型数据库共享事务 + continue; + //} + + //context.Database.CommitTransaction(); + } + + HasCommitted = true; + } + + /// + /// 回滚所有事务 + /// + public virtual void Rollback() + { + if (_transaction?.Connection != null) + { + _transaction.Rollback(); + } + foreach (var context in _dbContexts) + { + //if (context.IsRelationalTransaction()) + //{ + CleanChanges(context); + if (context.Database.CurrentTransaction != null) + { + //context.Database.CurrentTransaction.Rollback(); + context.Database.CurrentTransaction.Dispose(); + } + continue; + //} + //context.Database.RollbackTransaction(); + } + HasCommitted = true; + } + + private static void CleanChanges(DbContext context) + { + var entries = context.ChangeTracker.Entries().ToArray(); + foreach (var entry in entries) + { + entry.State = EntityState.Detached; + } + } + + public void Dispose() + { + _transaction?.Dispose(); + foreach (DbContext context in _dbContexts) + { + context.Dispose(); + } + } + } +} diff --git a/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/UnitOfWorkAttribute.cs b/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/UnitOfWorkAttribute.cs new file mode 100644 index 0000000..dde1348 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/UnitOfWorkAttribute.cs @@ -0,0 +1,104 @@ +using CloudBuilder.Core.Service; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Transactions; + +namespace CloudBuilder.Core.DatabaseAccessor +{ + /* + 事务范围:TransactionScopeOption.RequiresNew 管理的是分布式事务, + TransactionScopeOption.Required但对于单个数据库连接,通常不需要分布式事务。 + OnActionExecutionAsync 是 ASP.NET Core 中异步的 Action 过滤器执行方法。 + // OnActionExecuting: Action 执行前 + [开始事务] + ↓ + [Action 方法执行] + ↓ + // OnActionExecuted: Action 执行后(无论是否异常) + [检查异常] + //Controller对象不抛出异常,返回的是异常对象ValidatedException、ServiceErrorException(方便前端信息统一处理) + [提交或回滚事务] + */ + [AttributeUsage(AttributeTargets.Method)] + public class UnitOfWorkAttribute : ActionFilterAttribute + { + private TransactionScope _transactionScope; + + public override void OnActionExecuting(ActionExecutingContext context) + { + _transactionScope = new TransactionScope(TransactionScopeOption.RequiresNew, + new TransactionOptions + { + IsolationLevel = IsolationLevel.ReadCommitted, + Timeout = TransactionManager.MaximumTimeout + }); + + base.OnActionExecuting(context); + } + + //public override void OnActionExecuting(ActionExecutingContext context) + //{ + // // 正确:单机数据库事务(不是分布式) + // _transactionScope = new TransactionScope( + // TransactionScopeOption.Required, + // new TransactionOptions + // { + // IsolationLevel = IsolationLevel.ReadCommitted + // }, + // TransactionScopeAsyncFlowOption.Enabled); // 必须加这个 + + // base.OnActionExecuting(context); + //} + + public override void OnActionExecuted(ActionExecutedContext context) + { + if (_transactionScope == null) + { + base.OnActionExecuted(context); + return; + } + + bool needRollback = false; + + try + { + // ============================================== + // 核心逻辑:判断返回值是不是异常对象 + // ============================================== + if (context.Result is ObjectResult objectResult) + { + var value = objectResult.Value; + + if (value != null) + { + // 只要是这两个异常 → 必须回滚 + if (value is ValidatedException || value is ServiceErrorException) + { + needRollback = true; + } + } + } + + // 如果没有异常,才提交 + if (!needRollback) + { + //必须要有 SaveChanges() 调用,否则数据只会停留在内存中,不会真正保存到数据库。 + _transactionScope.Complete(); + } + } + finally + { + // 不 Complete() 就是自动回滚 + _transactionScope.Dispose(); + } + + base.OnActionExecuted(context); + } + } +} diff --git a/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/WebService.cs b/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/WebService.cs new file mode 100644 index 0000000..6c7df5d --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/DatabaseAccessor/WebService.cs @@ -0,0 +1,19 @@ +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.DatabaseAccessor +{ + public class WebService + { + public WebService(IServiceCollection services) + { + Services = services; + } + + public IServiceCollection Services { get; } + } +} diff --git a/CloudBuilder/CloudBuilder.Core/DependencyInjection/Authorization/AuthorizationPack.cs b/CloudBuilder/CloudBuilder.Core/DependencyInjection/Authorization/AuthorizationPack.cs new file mode 100644 index 0000000..837cf82 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/DependencyInjection/Authorization/AuthorizationPack.cs @@ -0,0 +1,136 @@ +using CloudBuilder.Core.Application.Builders; +using CloudBuilder.Core.Application.Options; +using CloudBuilder.Core.Application.Packs; +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.Extensions; +using CloudBuilder.Core.Policy; +using CloudBuilder.Core.Service; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.IdentityModel.Tokens; +using System.Text; +/* +使用JWT: +1.认证(AddAuthentication) +1.1开启Bearer认证 +1.2注册JwtBearer服务 +3.开启中间件(app.UseAuthentication()) +4.实现IAuthenticationService接口认证服务 +5.实现IAuthorizationPermissionService接口授权服务 + +2.授权(AddAuthorization) +2.1无状态授权[Authorize] +1.2有状态授权[Authorize["Permission"]] AddAuthorization注册自定义授权 + +*/ + +namespace CloudBuilder.Core.DependencyInjection.Authorization +{ + [PackLevel(45)] + public class AuthorizationPack : CloudBuilderPack + { + /// + /// 获取 模块级别 + /// + public override PackLevel Level => PackLevel.Framework; + + /// + /// 获取 模块启动顺序,模块启动的顺序先按级别启动,级别内部再按此顺序启动 + /// + public override int Order => 2; + + /// + /// 将服务添加到依赖注入服务容器中 + /// + /// 依赖注入服务容器 + /// + public override IServiceCollection AddServices(IServiceCollection services, CloudBuilderBuilder builder) + { + /*策略授权 + 1.导入 + Microsoft.AspNetCore.Authorization + Microsoft.AspNetCore.Authentication.JwtBearer + 2.具体实现逻辑交由外部的PermissionServices:IAuthorizationPermissionService来处理 + */ + + CloudBuilderOptions section = builder.CloudBuilderOptions; + if (section.Jwt == null) return services; + + var signingCredentials = new SigningCredentials(new SymmetricSecurityKey(Encoding.ASCII.GetBytes(section.Jwt.Secret)), SecurityAlgorithms.HmacSha256); + + // 角色与接口的权限要求参数 + var permissionRequirement = new PermissionRequirement(); + + //初始化认证信息 + services.AddAuthentication(x => + { + x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; + x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; + }).AddJwtBearer(x => + { + x.RequireHttpsMetadata = false; + x.SaveToken = true; + + //Token Validation Parameters + x.TokenValidationParameters = new TokenValidationParameters + { + ClockSkew= TimeSpan.Zero, + //通常,验证库(至少是MS之一)可以补偿时钟偏斜。 ClockSkew的默认值为5分钟。 + ValidateIssuerSigningKey = true, + //获取或设置要使用的Microsoft.IdentityModel.Tokens.SecurityKey用于签名验证。 + IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(section.Jwt.Secret)), + //获取或设置一个System.String,它表示将使用的有效发行者检查代币的发行者。 + ValidIssuer = section.Jwt.Issuer, + //获取或设置一个字符串,该字符串表示将用于检查的有效受众反对令牌的观众。 + ValidAudience = section.Jwt.Audience, + ValidateIssuer = true, + ValidateAudience = true, + ValidateLifetime = true, + NameClaimType = ClaimPolicy.CLAINM_USERID, + RoleClaimType = ClaimPolicy.ROLE, + }; + }); + + //启用全局授权(所有的Controller就无需加入Authorize属性,如果加入就会重复执行授权) + if (section.EnableGlobalAuthorize) + { + services.Configure(options => + { + options.Filters.Add(new AuthorizeFilter()); + }); + } + + //初始化授权信息(使用自定义复杂的授权) + services.AddAuthorization(options => + { + options.AddPolicy(AuthorizePolicy.PERMISSION, policy => policy.Requirements.Add(permissionRequirement)); + }); + + var baseType = typeof(IAuthorize); + + var allAssemblies = CloudBuilderBuilder.GetAssemblies(); + + var types = allAssemblies + .SelectMany(a => a.DefinedTypes) + .Select(type => type.AsType()) + .Where(type => type != baseType && type.HasImplementedRawGeneric(baseType)) + .Where(x => x.IsClass).ToList(); + + foreach (var implementType in types) + { + services.AddScoped(implementType.GetInterfaces().FirstOrDefault(), implementType); + } + + services.AddSingleton(new JwtGenerate(section.Jwt)); + + return services; + } + + } +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Core/DependencyInjection/EFCore/EntityFrameworkPack.cs b/CloudBuilder/CloudBuilder.Core/DependencyInjection/EFCore/EntityFrameworkPack.cs new file mode 100644 index 0000000..44a113c --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/DependencyInjection/EFCore/EntityFrameworkPack.cs @@ -0,0 +1,89 @@ +using CloudBuilder.Core.Application.Builders; +using CloudBuilder.Core.Application.Options; +using CloudBuilder.Core.Application.Packs; +using CloudBuilder.Core.DatabaseAccessor; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; + +namespace CloudBuilder.Core.DependencyInjection.EFCore +{ + [PackLevel(15)] + public class EntityFrameworkPack : CloudBuilderPack + { + /// + /// 获取 模块级别 + /// + public override PackLevel Level => PackLevel.Framework; + + /// + /// 获取 模块启动顺序,模块启动的顺序先按级别启动,级别内部再按此顺序启动 + /// + public override int Order => 2; + + /// + /// 将注册实体类服务添加到依赖注入服务容器中 + /// 各模块然后自动注入实体类(含多关键字和无关键字) + /// + /// 依赖注入服务容器 + /// + public override IServiceCollection AddServices(IServiceCollection services, CloudBuilderBuilder builder) + { + var baseType = typeof(IMasterRegistEntityType); + + var allAssemblies = CloudBuilderBuilder.GetAssemblies(); + + var types = allAssemblies + .SelectMany(a => a.DefinedTypes) + .Select(type => type.AsType()) + .Where(type => type != baseType && baseType.IsAssignableFrom(type)) + .Where(x => x.IsClass).ToList(); + + foreach (var implementType in types) + { + services.AddSingleton(baseType, implementType); + } + + services.TryAddScoped(typeof(IRepository<>), typeof(Repository<>)); + services.TryAddScoped(typeof(IUnitOfWork), typeof(UnitOfWork)); + + //当你直接在控制器方法上使用[UnitOfWork] 特性时,ASP.NET Core 的过滤器管道会自动实例化这个特性,不需要手动注册。 + //如果你的 UnitOfWorkAttribute 没有构造函数依赖,那么不需要注册: + services.TryAddScoped(); + + services.TryAddKeyedScoped(SecondaryDbContext.SECONDARY_DB_CONTEXT); + services.TryAddKeyedScoped(MasterDbContext.MASTER_DB_CONTEXT); + + services.AddDbContext(opts => + { + var connStr = builder.CloudBuilderOptions + .GetDbContextOptions(MasterDbContext.MASTER_DB_CONTEXT) + .ConnectionString; + + opts.UseMySql(connStr, ServerVersion.AutoDetect(connStr)); + }); + + services.AddDbContext(opts => + opts.UseSqlServer(builder.CloudBuilderOptions.GetDbContextOptions(SecondaryDbContext.SECONDARY_DB_CONTEXT).ConnectionString)); + + // services.AddDbContext(opts => + //opts.UseSqlServer(builder.CloudBuilderOptions.GetDbContextOptions(MasterDbContext.MASTER_DB_CONTEXT).ConnectionString)); + + //services.AddDbContext(opts => + //{ + // var connStr = builder.CloudBuilderOptions + // .GetDbContextOptions(SecondaryDbContext.SECONDARY_DB_CONTEXT) + // .ConnectionString; + + // opts.UseMySql(connStr, ServerVersion.AutoDetect(connStr)); + //}); + + + + return services; + } + + + } +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Core/DependencyInjection/EFCore/IMasterRegistEntityType.cs b/CloudBuilder/CloudBuilder.Core/DependencyInjection/EFCore/IMasterRegistEntityType.cs new file mode 100644 index 0000000..1ecfa75 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/DependencyInjection/EFCore/IMasterRegistEntityType.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.DependencyInjection.EFCore +{ + /// + /// 每一个模块注册实体类 + /// + /// + public interface IMasterRegistEntityType + { + /// + /// 注入所有Entity实体类,调用AddEntityType和RegistKeys + /// + /// + void RegistEntity(T builder); + + /// + /// 如果Entity实体类不是单一主键,要单独重写注入(自动生成) + /// + /// + void RegistKeys(T builder); + + /// + /// 注入所有Entity实体类 + /// + /// + /// + void AddEntityType(T builder, string assemblyName); + } +} diff --git a/CloudBuilder/CloudBuilder.Core/DependencyInjection/EFCore/ISecondaryRegistEntityType.cs b/CloudBuilder/CloudBuilder.Core/DependencyInjection/EFCore/ISecondaryRegistEntityType.cs new file mode 100644 index 0000000..db8f123 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/DependencyInjection/EFCore/ISecondaryRegistEntityType.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.DependencyInjection.EFCore +{ + /// + /// 每一个模块注册从库实体类 + /// + /// + public interface ISecondaryRegistEntityType + { + /// + /// 注入所有Entity实体类,调用AddEntityType和RegistKeys + /// + /// + void RegistEntity(T builder); + + /// + /// 如果Entity实体类不是单一主键,要单独重写注入(自动生成) + /// + /// + void RegistKeys(T builder); + + /// + /// 注入所有Entity实体类 + /// + /// + /// + void AddEntityType(T builder, string assemblyName); + } +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Core/DependencyInjection/EFCore/RegistEntityHelper.cs b/CloudBuilder/CloudBuilder.Core/DependencyInjection/EFCore/RegistEntityHelper.cs new file mode 100644 index 0000000..f8d8000 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/DependencyInjection/EFCore/RegistEntityHelper.cs @@ -0,0 +1,56 @@ +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using CloudBuilder.Core.Extensions; +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.DependencyInjection.EFCore +{ + public class RegistEntityHelper + { + public static void AddMasterEntityType(ModelBuilder builder, string _assemblyName) + { + var eType = typeof(IEntity<>); + AddMasterEntityType(builder, _assemblyName, eType); + } + + public static void AddSecondaryEntityType(ModelBuilder builder, string _assemblyName) + { + var eType = typeof(ISecondary); + AddMasterEntityType(builder, _assemblyName, eType); + } + + public static void AddMasterEntityType(ModelBuilder builder, string _assemblyName, Type eType) + { + var mType = typeof(IEntity<>); + var sType = typeof(ISecondary); + + var entityTypes = Assembly.Load(new AssemblyName(_assemblyName)).GetTypes() + .Where(type => !string.IsNullOrWhiteSpace(type.Namespace)) + .Where(type => type.GetTypeInfo().IsClass) + .Where(type => type.GetTypeInfo().BaseType != null) + .Where(type => type.HasImplementedRawGeneric(eType)).ToList(); + + if (eType == mType) entityTypes = entityTypes.Where(type => !type.HasImplementedRawGeneric(sType)).ToList(); + + NotMappedAttribute notMapped = null; + foreach (var entityType in entityTypes) + { + //排除实体类标记[NotMapped] + notMapped = entityType.GetCustomAttribute(); + if (notMapped != null) continue; + + if (builder.Model.FindEntityType(entityType) != null) + continue; + builder.Model.AddEntityType(entityType); + } + } + + } +} diff --git a/CloudBuilder/CloudBuilder.Core/DependencyInjection/EventBuses/EventBusesPack.cs b/CloudBuilder/CloudBuilder.Core/DependencyInjection/EventBuses/EventBusesPack.cs new file mode 100644 index 0000000..eb810fb --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/DependencyInjection/EventBuses/EventBusesPack.cs @@ -0,0 +1,78 @@ +using CloudBuilder.Core.Application.Builders; +using CloudBuilder.Core.Application.Packs; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using CloudBuilder.Core.DatabaseAccessor; +using CloudBuilder.Core.DependencyInjection.EFCore; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection.Extensions; +using CloudBuilder.Core.Service; +using CloudBuilder.Core.Extensions; + +namespace CloudBuilder.Core.DependencyInjection.EventBuses +{ + [PackLevel(30)] + public class EventBusesPack : CloudBuilderPack + { + + /// + /// 获取 模块级别 + /// + public override PackLevel Level => PackLevel.Business; + + /// + /// 获取 模块启动顺序,模块启动的顺序先按级别启动,级别内部再按此顺序启动 + /// + public override int Order => 3; + + /// + /// 将事件总线的发布者和监听者都添加到依赖注入容器中 + /// + /// 依赖注入服务容器 + /// + public override IServiceCollection AddServices(IServiceCollection services, CloudBuilderBuilder builder) + { + var baseType = typeof(IEventPublisher); + + var allAssemblies = CloudBuilderBuilder.GetAssemblies(); + + var types = allAssemblies + .SelectMany(a => a.DefinedTypes) + .Select(type => type.AsType()) + .Where(type => type != baseType && type.HasImplementedRawGeneric(baseType)) + .Where(x => x.IsClass).ToList(); + + + foreach (var implementType in types) + { + services.AddScoped(implementType.GetInterfaces().FirstOrDefault(), implementType); + } + + baseType = typeof(IEventSubscriber); + + types = allAssemblies + .SelectMany(a => a.DefinedTypes) + .Select(type => type.AsType()) + .Where(type => type != baseType && type.HasImplementedRawGeneric(baseType)) + .Where(x => x.IsClass).ToList(); + + + foreach (var implementType in types) + { + services.AddScoped(implementType.GetInterfaces().FirstOrDefault(), implementType); + } + /* + * 取出所有监听服务 + IEnumerable subscribers = service.ServiceProvider.GetServices(); + */ + return services; + } + + + } +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Core/DependencyInjection/EventBuses/EventData.cs b/CloudBuilder/CloudBuilder.Core/DependencyInjection/EventBuses/EventData.cs new file mode 100644 index 0000000..f003f2d --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/DependencyInjection/EventBuses/EventData.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.DependencyInjection.EventBuses +{ + /// + /// 定义事件数据,所有事件都要实现该接口 + /// + public class EventData + { + /// + /// 获取 事件编号 + /// + public string? EventId { get; set; } + /// + /// 获取 事件发生的时间 + /// + public DateTime EventTime { get; } = DateTime.Now; + /// + /// 获取或设置 事件源,触发事件的对象 + /// + public object? EventSource { get; set; } + } +} diff --git a/CloudBuilder/CloudBuilder.Core/DependencyInjection/EventBuses/IEventPublisher.cs b/CloudBuilder/CloudBuilder.Core/DependencyInjection/EventBuses/IEventPublisher.cs new file mode 100644 index 0000000..50433c0 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/DependencyInjection/EventBuses/IEventPublisher.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.DependencyInjection.EventBuses +{ + /// + /// 定义事件发布者 + /// + public interface IEventPublisher + { + + } +} diff --git a/CloudBuilder/CloudBuilder.Core/DependencyInjection/EventBuses/IEventSubscriber.cs b/CloudBuilder/CloudBuilder.Core/DependencyInjection/EventBuses/IEventSubscriber.cs new file mode 100644 index 0000000..6528a63 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/DependencyInjection/EventBuses/IEventSubscriber.cs @@ -0,0 +1,17 @@ +using Microsoft.AspNetCore.Components.Web; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.DependencyInjection.EventBuses +{ + /// + /// 定义事件订阅者 + /// + public interface IEventSubscriber + { + + } +} diff --git a/CloudBuilder/CloudBuilder.Core/DependencyInjection/Form/ApplicationServiceContext.cs b/CloudBuilder/CloudBuilder.Core/DependencyInjection/Form/ApplicationServiceContext.cs new file mode 100644 index 0000000..e90943d --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/DependencyInjection/Form/ApplicationServiceContext.cs @@ -0,0 +1,34 @@ +using CloudBuilder.Core.DependencyInjection.Request; +using CloudBuilder.Core.Policy; +using DocumentFormat.OpenXml.InkML; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.DependencyInjection.Form +{ + public class ApplicationServiceContext + { + public static IServiceProvider ServiceProvider = null!; + public static IContext Context = null!; + public static IConfiguration Configuration; + public static ILocaleMessageManager localeMessageManager = null!; + public static ISecurityMasterManager securityMasterManager = null!; + public ApplicationServiceContext(IServiceProvider serviceProvider, IContext context, IConfiguration configuration) + { + ServiceProvider = serviceProvider; + Context = context; + Context.DefaultVersion = configuration.GetValue("CloudBuilder:DefaultVersion")!; + Context.DefaultCopyright = configuration.GetValue("CloudBuilder:DefaultCopyright")!; + Context.DefaultTitle = configuration.GetValue("CloudBuilder:DefaultTitle")!; + + Configuration = configuration; + localeMessageManager = ServiceProvider.GetService()!; + securityMasterManager = ServiceProvider.GetService()!; + } + } +} diff --git a/CloudBuilder/CloudBuilder.Core/DependencyInjection/Form/FormPack.cs b/CloudBuilder/CloudBuilder.Core/DependencyInjection/Form/FormPack.cs new file mode 100644 index 0000000..c15e1d1 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/DependencyInjection/Form/FormPack.cs @@ -0,0 +1,98 @@ +using CloudBuilder.Core.Application.Builders; +using CloudBuilder.Core.Application.Packs; +using CloudBuilder.Core.DatabaseAccessor; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using CloudBuilder.Core.DependencyInjection.EFCore; +using CloudBuilder.Core.DependencyInjection.Request; +using CloudBuilder.Core.Extensions; +using CloudBuilder.Core.Service; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.DependencyInjection.Form +{ + [PackLevel(40)] + public class FormPack : CloudBuilderPack + { + /// + /// 获取 模块级别 + /// + public override PackLevel Level => PackLevel.Business; + + /// + /// 获取 模块启动顺序,模块启动的顺序先按级别启动,级别内部再按此顺序启动 + /// + public override int Order => 2; + + /// + /// 将窗体和用户控件添加到依赖注入服务容器中 + /// + /// 依赖注入服务容器 + /// + public override IServiceCollection AddServices(IServiceCollection services, CloudBuilderBuilder builder) + { + //注入窗体 + var baseType = typeof(IForm); + + var allAssemblies = CloudBuilderBuilder.GetAssemblies(); + + var types = allAssemblies + .SelectMany(a => a.DefinedTypes) + .Select(type => type.AsType()) + .Where(type => type != baseType && type.BaseType?.Name != "AbstractPage" && type.HasImplementedRawGeneric(baseType)) + .Where(x => x.IsClass).ToList(); + + + foreach (var implementType in types) + { + services.TryAddKeyedScoped(implementType, implementType.Name); + } + + //注入Page + baseType = typeof(IForm); + + allAssemblies = CloudBuilderBuilder.GetAssemblies(); + + types = allAssemblies + .SelectMany(a => a.DefinedTypes) + .Select(type => type.AsType()) + .Where(type => type != baseType && type.BaseType?.Name == "AbstractPage" && type.HasImplementedRawGeneric(baseType)) + .Where(x => x.IsClass).ToList(); + + + foreach (var implementType in types) + { + //主界面窗口及弹出的窗口,要使用Transient注入,每次打开都要创建新的实例 + //注意要清空之前的自定义属性。BindingContextAttributeProvider + services.TryAddKeyedTransient(implementType.BaseType, implementType.Name, implementType); + //services.TryAddKeyedScoped(implementType.BaseType, implementType.Name, implementType); + } + + //注入用户控件 + baseType = typeof(IUserControl); + types = allAssemblies + .SelectMany(a => a.DefinedTypes) + .Select(type => type.AsType()) + .Where(type => type != baseType && type.HasImplementedRawGeneric(baseType)) + .Where(x => x.IsClass).ToList(); + + foreach (var implementType in types) + { + services.TryAddKeyedScoped(implementType, implementType.Name); + } + + //services.TryAddSingleton(); + services.TryAddScoped(); + + return services; + } + + + } +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Core/DependencyInjection/Form/IForm.cs b/CloudBuilder/CloudBuilder.Core/DependencyInjection/Form/IForm.cs new file mode 100644 index 0000000..2553970 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/DependencyInjection/Form/IForm.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.DependencyInjection.Form +{ + public interface IForm + { + } +} diff --git a/CloudBuilder/CloudBuilder.Core/DependencyInjection/Form/IUserControl.cs b/CloudBuilder/CloudBuilder.Core/DependencyInjection/Form/IUserControl.cs new file mode 100644 index 0000000..03b86ab --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/DependencyInjection/Form/IUserControl.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.DependencyInjection.Form +{ + public interface IUserControl + { + } +} diff --git a/CloudBuilder/CloudBuilder.Core/DependencyInjection/Policy/IPolicy.cs b/CloudBuilder/CloudBuilder.Core/DependencyInjection/Policy/IPolicy.cs new file mode 100644 index 0000000..095f78e --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/DependencyInjection/Policy/IPolicy.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.DependencyInjection.Policy +{ + public interface IPolicy + { + } +} diff --git a/CloudBuilder/CloudBuilder.Core/DependencyInjection/Policy/PolicyPack.cs b/CloudBuilder/CloudBuilder.Core/DependencyInjection/Policy/PolicyPack.cs new file mode 100644 index 0000000..d593dd3 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/DependencyInjection/Policy/PolicyPack.cs @@ -0,0 +1,61 @@ +using CloudBuilder.Core.Application.Builders; +using CloudBuilder.Core.Application.Packs; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using CloudBuilder.Core.DatabaseAccessor; +using CloudBuilder.Core.DependencyInjection.EFCore; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection.Extensions; +using CloudBuilder.Core.Service; +using CloudBuilder.Core.Extensions; + +namespace CloudBuilder.Core.DependencyInjection.Policy +{ + [PackLevel(10)] + public class PolicyPack : CloudBuilderPack + { + /// + /// 获取 模块级别 + /// + public override PackLevel Level => PackLevel.Business; + + /// + /// 获取 模块启动顺序,模块启动的顺序先按级别启动,级别内部再按此顺序启动 + /// + public override int Order => 2; + + /// + /// 将窗体和用户控件添加到依赖注入服务容器中 + /// + /// 依赖注入服务容器 + /// + public override IServiceCollection AddServices(IServiceCollection services, CloudBuilderBuilder builder) + { + //注入Policy + var baseType = typeof(IPolicy); + + var allAssemblies = CloudBuilderBuilder.GetAssemblies(); + + var types = allAssemblies + .SelectMany(a => a.DefinedTypes) + .Select(type => type.AsType()) + .Where(type => type != baseType && baseType.IsAssignableFrom(type)) + .Where(x => x.IsClass).ToList(); + + + foreach (var implementType in types) + { + services.TryAddKeyedScoped(implementType, implementType.Name); + } + + return services; + } + + + } +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Core/DependencyInjection/Request/IContext.cs b/CloudBuilder/CloudBuilder.Core/DependencyInjection/Request/IContext.cs new file mode 100644 index 0000000..af3a8a3 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/DependencyInjection/Request/IContext.cs @@ -0,0 +1,32 @@ +using DocumentFormat.OpenXml.Presentation; +using Microsoft.AspNetCore.Authorization; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.DependencyInjection.Request +{ + public interface IContext + { + string DefaultVersion { get; set; } + string Requestor { get; set; } + string UserType { get; set; } + DateTime LoginDate { get; set; } + string DefaultCopyright { get; set; } + string DefaultTitle { get; set; } + void SetPermissionInfo(dynamic permissionInfo); + dynamic GetPermissionInfo(); + void SetToken(string token); + string GetToken(); + string GetCulture(); + void SetCulture(string culture); + bool Assert(Func action, string permissionName); + bool Assert(Func action, string permissionName, string operate); + bool Assert(Func action, string permissionName, Operate operate); + bool AssertDependents(Func action, string permissionName, string dependents); + bool AssertDependents(Func action, string permissionName, string dependents, Operate operate); + } +} diff --git a/CloudBuilder/CloudBuilder.Core/DependencyInjection/Request/IRequest.cs b/CloudBuilder/CloudBuilder.Core/DependencyInjection/Request/IRequest.cs new file mode 100644 index 0000000..21d9656 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/DependencyInjection/Request/IRequest.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.DependencyInjection.Request +{ + public interface IRequest + { + } +} diff --git a/CloudBuilder/CloudBuilder.Core/DependencyInjection/Request/LoginContext.cs b/CloudBuilder/CloudBuilder.Core/DependencyInjection/Request/LoginContext.cs new file mode 100644 index 0000000..2e80630 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/DependencyInjection/Request/LoginContext.cs @@ -0,0 +1,104 @@ +using CloudBuilder.Core.DependencyInjection.Request; +using CloudBuilder.Core.Request; +using Microsoft.AspNetCore.Authorization; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +/* +{ + "CloudBuilder": { + "Culture": "zh-cn", + } +} +*/ + +namespace CloudBuilder.Core.DependencyInjection.Request +{ + public class LoginContext : IContext + { + public const string CULTURE_EN = "en"; + private string culture = null!; + private string token = null!; + private dynamic permissionInfo = null!; + private readonly IConfiguration configuration; + + public string DefaultVersion { get; set; } + public string Requestor { get; set; } + public string UserType { get; set; } + public DateTime LoginDate { get; set; } + public string DefaultCopyright { get; set; } + + public string DefaultTitle { get; set; } + + public LoginContext(IConfiguration configuration) + { + this.configuration = configuration; + + culture = this.configuration["CloudBuilder:Culture"]!; + DefaultVersion = this.configuration["CloudBuilder:DefaultVersion"] ?? "Ver.0.0.0.1"; + Requestor = string.Empty; + LoginDate = DateTime.Now; + DefaultCopyright = this.configuration["CloudBuilder:DefaultCopyright"] ?? "版权所有 © 2025 有家相册"; + } + + public bool Assert(Func action, string permissionName) + { + return action(permissionName); + } + + public bool Assert(Func action, string permissionName, string operate) + { + return action(permissionName, operate); + } + + public bool Assert(Func action, string permissionName, Operate operate) + { + return action(permissionName, operate); + } + + public bool AssertDependents(Func action, string permissionName, string dependents) + { + return action(permissionName, dependents); + } + + public bool AssertDependents(Func action, string permissionName, string dependents, Operate operate) + { + return action(permissionName, dependents, operate); + } + + public string GetCulture() + { + return this.culture; + } + + public void SetCulture(string culture) + { + this.culture = culture; + } + + public string GetToken() + { + return this.token; + } + + public void SetToken(string token) + { + this.token = token; + } + + public dynamic GetPermissionInfo() + { + return this.permissionInfo; + } + + public void SetPermissionInfo(dynamic permissionInfo) + { + this.permissionInfo = permissionInfo; + } + } +} diff --git a/CloudBuilder/CloudBuilder.Core/DependencyInjection/Request/RequestPack.cs b/CloudBuilder/CloudBuilder.Core/DependencyInjection/Request/RequestPack.cs new file mode 100644 index 0000000..35704c8 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/DependencyInjection/Request/RequestPack.cs @@ -0,0 +1,77 @@ +using CloudBuilder.Core.Application.Builders; +using CloudBuilder.Core.Application.Packs; +using CloudBuilder.Core.Extensions; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; + +namespace CloudBuilder.Core.DependencyInjection.Request +{ + [PackLevel(35)] + public class RequestPack : CloudBuilderPack + { + /// + /// 获取 模块级别 + /// + public override PackLevel Level => PackLevel.Business; + + /// + /// 获取 模块启动顺序,模块启动的顺序先按级别启动,级别内部再按此顺序启动 + /// + public override int Order => 2; + + /// + /// 将请求添加到依赖注入服务容器中 + /// + /// 依赖注入服务容器 + /// + public override IServiceCollection AddServices(IServiceCollection services, CloudBuilderBuilder builder) + { + //注入请求 + services.AddHttpClient(); + + var baseType = typeof(IRequest); + + var allAssemblies = CloudBuilderBuilder.GetAssemblies(); + + var types = allAssemblies + .SelectMany(a => a.DefinedTypes) + .Select(type => type.AsType()) + .Where(type => type != baseType && type.HasImplementedRawGeneric(baseType)) + .Where(x => x.IsClass).ToList(); + + /*TryAddKeyedScoped Scoped(作用域) 每个请求(或作用域)内是同一个实例,不同请求之间不同。 + * 在 WinForms 应用程序中,依赖注入(DI)的 作用域(Scoped)生命周期 不像 ASP.NET Core 那样自动按 HTTP 请求划分作用域, + * 而是需要手动管理作用域。 + * 在 WinForms 应用程序中,如果没有使用手动管理作用域,那么相关于全局作用域,类似于单例又不同于单例(手动管理作用域)。 + * 在 WinForms 中使用 Scoped 服务 + using (var scope1 = ServiceProvider.CreateScope()) + { + AuthRequest authRequest = scope1.ServiceProvider.GetRequiredKeyedService(typeof(AuthRequest).Name); + string pubKeyc = await authRequest.GetRsaPublicKey(); + } + //下面的对应的是上面的调用方式 + //services.TryAddKeyedScoped(implementType, implementType.Name); + 现在修改为下面这样调用方式 IServiceRequest serviceRequest + // IAuthRequest authRequest = ServiceProvider.GetService()!; + */ + foreach (var implementType in types) + { + //AuthRequest要对应AuthService的方法,所以注入名字 + services.TryAddKeyedScoped(implementType, implementType.Name); + + //ServiceRequest(注入接口) + + services.TryAddScoped(implementType.GetInterfaces().FirstOrDefault(), implementType); + } + + //因为每个用户都是独立的,因此不能注册为单一的 + //services.TryAddSingleton(); + //客户端的生命周期是静态的,唯一的 + + //注册为作用域生命周期 + services.TryAddScoped(); + + return services; + } + } +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Core/DependencyInjection/Service/ServicePack.cs b/CloudBuilder/CloudBuilder.Core/DependencyInjection/Service/ServicePack.cs new file mode 100644 index 0000000..59e7f96 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/DependencyInjection/Service/ServicePack.cs @@ -0,0 +1,54 @@ +using CloudBuilder.Core.Application.Builders; +using CloudBuilder.Core.Application.Packs; +using CloudBuilder.Core.Extensions; +using CloudBuilder.Core.Service; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; + +namespace CloudBuilder.Core.DependencyInjection.Service +{ + [PackLevel(20)] + public class ServicePack : CloudBuilderPack + { + + /// + /// 获取 模块级别 + /// + public override PackLevel Level => PackLevel.Business; + + /// + /// 获取 模块启动顺序,模块启动的顺序先按级别启动,级别内部再按此顺序启动 + /// + public override int Order => 2; + + /// + /// 将服务添加到依赖注入服务容器中 + /// + /// 依赖注入服务容器 + /// + public override IServiceCollection AddServices(IServiceCollection services, CloudBuilderBuilder builder) + { + var baseType = typeof(IService); + + var allAssemblies = CloudBuilderBuilder.GetAssemblies(); + + var types = allAssemblies + .SelectMany(a => a.DefinedTypes) + .Select(type => type.AsType()) + .Where(type => type != baseType && type.HasImplementedRawGeneric(baseType)) + .Where(x => x.IsClass).ToList(); + + + foreach (var implementType in types) + { + services.TryAddScoped(implementType.GetInterfaces().FirstOrDefault(), implementType); + } + + // IAuthService authRequest = ServiceProvider.GetService()!; + + return services; + } + + + } +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Core/DependencyInjection/Task/IScheduleTask.cs b/CloudBuilder/CloudBuilder.Core/DependencyInjection/Task/IScheduleTask.cs new file mode 100644 index 0000000..e46855f --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/DependencyInjection/Task/IScheduleTask.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.DependencyInjection.Task +{ + public interface IScheduleTask + { + void Run(Dictionary bodyDict); + } +} diff --git a/CloudBuilder/CloudBuilder.Core/DependencyInjection/Task/ScheduleTaskPack.cs b/CloudBuilder/CloudBuilder.Core/DependencyInjection/Task/ScheduleTaskPack.cs new file mode 100644 index 0000000..79fae43 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/DependencyInjection/Task/ScheduleTaskPack.cs @@ -0,0 +1,57 @@ +using CloudBuilder.Core.Application.Builders; +using CloudBuilder.Core.Application.Packs; +using CloudBuilder.Core.Extensions; +using CloudBuilder.Core.Service; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; + +namespace CloudBuilder.Core.DependencyInjection.Task +{ + [PackLevel(20)] + public class ScheduleTaskPack : CloudBuilderPack + { + /// + /// 获取 模块级别 + /// + public override PackLevel Level => PackLevel.Business; + + /// + /// 获取 模块启动顺序,模块启动的顺序先按级别启动,级别内部再按此顺序启动 + /// + public override int Order => 2; + + /// + /// 将服务添加到依赖注入服务容器中 + /// + /// 依赖注入服务容器 + /// + public override IServiceCollection AddServices(IServiceCollection services, CloudBuilderBuilder builder) + { + var baseType = typeof(IScheduleTask); + + var allAssemblies = CloudBuilderBuilder.GetAssemblies(); + + var types = allAssemblies + .SelectMany(a => a.DefinedTypes) + .Select(type => type.AsType()) + .Where(type => type != baseType && type.HasImplementedRawGeneric(baseType)) + .Where(x => x.IsClass).ToList(); + + + foreach (var implementType in types) + { + //使用TryAddScoped可以避免同一个接口注册多个实现 + + //使用AddScoped可以同一个接口注册多个实现 + //即使容器中原本就有IOrder服务,也会再添加一个IOrder服务进去,这样一来容器中就会存在多个IOrder服务 + //在需要获取服务的地方注入IOrder服务时,默认会得到最后一个注册的IOrder服务实例 + //IEnumerable orders获取所有的IOrder服务 + services.AddScoped(baseType, implementType); + } + + return services; + } + + + } +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Core/Extensions/ClaimsIdentityExtensions.cs b/CloudBuilder/CloudBuilder.Core/Extensions/ClaimsIdentityExtensions.cs new file mode 100644 index 0000000..3b2a8f4 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Extensions/ClaimsIdentityExtensions.cs @@ -0,0 +1,138 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Claims; +using System.Security.Principal; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.Extensions +{ + /// + /// 扩展操作类 + /// + public static class ClaimsIdentityExtensions + { + /// + /// 获取指定类型的Claim值 + /// + public static string GetClaimValueFirstOrDefault(this IIdentity identity, string type) + { + if (!(identity is ClaimsIdentity claimsIdentity)) + { + return null; + } + return claimsIdentity.FindFirst(type)?.Value; + } + + /// + /// 获取指定类型的所有Claim值 + /// + public static string[] GetClaimValues(this IIdentity identity, string type) + { + if (!(identity is ClaimsIdentity claimsIdentity)) + { + return null; + } + return claimsIdentity.Claims.Where(m => m.Type == type).Select(m => m.Value).ToArray(); + } + + /// + /// 获取用户ID + /// + public static T GetUserId(this IIdentity identity) + { + if (!(identity is ClaimsIdentity claimsIdentity)) + { + return default(T); + } + string value = claimsIdentity.FindFirst(ClaimTypes.NameIdentifier)?.Value; + if (value == null) + { + return default(T); + } + return value.CastTo(); + } + + /// + /// 获取用户ID + /// + public static string GetUserId(this IIdentity identity) + { + if (!(identity is ClaimsIdentity claimsIdentity)) + { + return null; + } + return claimsIdentity.FindFirst(ClaimTypes.NameIdentifier)?.Value; + } + + /// + /// 获取用户名 + /// + public static string GetUserName(this IIdentity identity) + { + if (!(identity is ClaimsIdentity claimsIdentity)) + { + return null; + } + return claimsIdentity.FindFirst(ClaimTypes.Name)?.Value; + } + + /// + /// 获取Email + /// + public static string GetEmail(this IIdentity identity) + { + if (!(identity is ClaimsIdentity claimsIdentity)) + { + return null; + } + return claimsIdentity.FindFirst(ClaimTypes.Email)?.Value; + } + + /// + /// 获取昵称 + /// + public static string GetNickName(this IIdentity identity) + { + if (!(identity is ClaimsIdentity claimsIdentity)) + { + return null; + } + return claimsIdentity.FindFirst(ClaimTypes.GivenName)?.Value; + } + + /// + /// 移除指定类型的声明 + /// + public static void RemoveClaim(this IIdentity identity, string claimType) + { + if (!(identity is ClaimsIdentity claimsIdentity)) + { + return; + } + Claim claim = claimsIdentity.FindFirst(claimType); + if (claim == null) + { + return; + } + claimsIdentity.RemoveClaim(claim); + } + + /// + /// 获取所有角色 + /// + public static string[] GetRoles(this IIdentity identity) + { + if (!(identity is ClaimsIdentity claimsIdentity)) + { + return new string[0]; + } + return claimsIdentity.FindAll(ClaimTypes.Role).SelectMany(m => + { + string[] roles = m.Value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + return roles; + }).ToArray(); + } + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Extensions/CollectionExtensions.cs b/CloudBuilder/CloudBuilder.Core/Extensions/CollectionExtensions.cs new file mode 100644 index 0000000..f1af04d --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Extensions/CollectionExtensions.cs @@ -0,0 +1,112 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.Extensions +{ + /// + /// 集合类型字符串排序操作类 + /// + /// 集合项类型 + public static class CollectionPropertySorter + { + // ReSharper disable StaticFieldInGenericType + private static readonly ConcurrentDictionary Cache = new ConcurrentDictionary(); + + /// + /// 按指定的属性名称对序列进行排序 + /// + /// 序列 + /// 属性名称 + /// 排序方向 + public static IOrderedEnumerable OrderBy(IEnumerable source, string propertyName, ListSortDirection sortDirection) + { + propertyName.CheckNotNullOrEmpty("propertyName"); + dynamic expression = GetKeySelector(propertyName); + dynamic keySelector = expression.Compile(); + return sortDirection == ListSortDirection.Ascending + ? Enumerable.OrderBy(source, keySelector) + : Enumerable.OrderByDescending(source, keySelector); + } + + /// + /// 按指定的属性名称对进行继续排序 + /// + /// 序列 + /// 属性名称 + /// 排序方向 + public static IOrderedEnumerable ThenBy(IOrderedEnumerable source, string propertyName, ListSortDirection sortDirection) + { + propertyName.CheckNotNullOrEmpty("propertyName"); + dynamic expression = GetKeySelector(propertyName); + dynamic keySelector = expression.Compile(); + return sortDirection == ListSortDirection.Ascending + ? Enumerable.ThenBy(source, keySelector) + : Enumerable.ThenByDescending(source, keySelector); + } + + /// + /// 按指定的属性名称对序列进行排序 + /// + /// IQueryable{T}序列 + /// 属性名称 + /// 排序方向 + /// + public static IOrderedQueryable OrderBy(IQueryable source, string propertyName, ListSortDirection sortDirection) + { + propertyName.CheckNotNullOrEmpty("propertyName"); + dynamic keySelector = GetKeySelector(propertyName); + return sortDirection == ListSortDirection.Ascending + ? Queryable.OrderBy(source, keySelector) + : Queryable.OrderByDescending(source, keySelector); + } + + /// + /// 按指定的属性名称对序列进行排序 + /// + /// IOrderedQueryable{T}序列 + /// 属性名称 + /// 排序方向 + /// + public static IOrderedQueryable ThenBy(IOrderedQueryable source, string propertyName, ListSortDirection sortDirection) + { + propertyName.CheckNotNullOrEmpty("propertyName"); + dynamic keySelector = GetKeySelector(propertyName); + return sortDirection == ListSortDirection.Ascending + ? Queryable.ThenBy(source, keySelector) + : Queryable.ThenByDescending(source, keySelector); + } + + private static LambdaExpression GetKeySelector(string keyName) + { + Type type = typeof(T); + string key = type.FullName + "." + keyName; + if (Cache.ContainsKey(key)) + { + return Cache[key]; + } + ParameterExpression param = Expression.Parameter(type); + string[] propertyNames = keyName.Split('.'); + Expression propertyAccess = param; + foreach (string propertyName in propertyNames) + { + PropertyInfo property = type.GetProperty(propertyName); + if (property == null) + { + throw new Exception(string.Format("指定对象中不存在名称为“{0}”的属性。", propertyName)); + } + type = property.PropertyType; + propertyAccess = Expression.MakeMemberAccess(propertyAccess, property); + } + LambdaExpression keySelector = Expression.Lambda(propertyAccess, param); + Cache[key] = keySelector; + return keySelector; + } + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Extensions/CustomAttributeExtensions.cs b/CloudBuilder/CloudBuilder.Core/Extensions/CustomAttributeExtensions.cs new file mode 100644 index 0000000..2948101 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Extensions/CustomAttributeExtensions.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.Extensions +{ + using System; + using System.Collections.Concurrent; + using System.Reflection; + + public static class CustomAttributeExtensions + { + /// + /// Cache Data + /// + private static readonly ConcurrentDictionary Cache = new ConcurrentDictionary(); + + /// + /// 获取CustomAttribute Value + /// + /// Attribute的子类型 + /// TReturn的子类型 + /// 头部标有CustomAttribute类的类型 + /// 取Attribute具体哪个属性值的匿名函数 + /// 返回Attribute的值,没有则返回null + public static TReturn GetCustomAttributeValue(this Type sourceType, Func attributeValueAction) + where TAttribute : Attribute + { + return _getAttributeValue(sourceType, attributeValueAction, null); + } + + /// + /// 获取CustomAttribute Value + /// + /// Attribute的子类型 + /// TReturn的子类型 + /// 头部标有CustomAttribute类的类型 + /// 取Attribute具体哪个属性值的匿名函数 + /// field name或property name + /// 返回Attribute的值,没有则返回null + public static TReturn GetCustomAttributeValue(this Type sourceType, Func attributeValueAction, string propertyName) + where TAttribute : Attribute + { + return _getAttributeValue(sourceType, attributeValueAction, propertyName); + } + + #region private methods + + private static TReturn _getAttributeValue(Type sourceType, Func attributeFunc, string propertyName) + where TAttribute : Attribute + { + var cacheKey = BuildKey(sourceType, propertyName); + var value = Cache.GetOrAdd(cacheKey, k => GetValue(sourceType, attributeFunc, propertyName)); + if (value is TReturn) return (TReturn)Cache[cacheKey]; + return default(TReturn); + } + + private static string BuildKey(Type type, string propertyName) where TAttribute : Attribute + { + var attributeName = typeof(TAttribute).FullName; + if (string.IsNullOrEmpty(propertyName)) + { + return type.FullName + "." + attributeName; + } + + return type.FullName + "." + propertyName + "." + attributeName; + } + + private static TReturn GetValue(this Type type, Func attributeValueAction, string name) + where TAttribute : Attribute + { + TAttribute attribute = default(TAttribute); + if (string.IsNullOrEmpty(name)) + { + attribute = type.GetCustomAttribute(false); + } + else + { + var propertyInfo = type.GetProperty(name); + if (propertyInfo != null) + { + attribute = propertyInfo.GetCustomAttribute(false); + } + else + { + var fieldInfo = type.GetField(name); + if (fieldInfo != null) + { + attribute = fieldInfo.GetCustomAttribute(false); + } + else + { + var methodInfo = type.GetMethod(name); + if (methodInfo != null) + { + attribute = methodInfo.GetCustomAttribute(false); + } + } + } + } + + return attribute == null ? default(TReturn) : attributeValueAction(attribute); + } + + #endregion + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Extensions/EnumerableExtensions.cs b/CloudBuilder/CloudBuilder.Core/Extensions/EnumerableExtensions.cs new file mode 100644 index 0000000..87af668 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Extensions/EnumerableExtensions.cs @@ -0,0 +1,199 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.Extensions +{ + /// + /// Enumerable集合扩展方法 + /// + public static class EnumerableExtensions + { + /// + /// 打乱一个集合的项顺序 + /// + public static IEnumerable Shuffle(this IEnumerable source) + { + if (source == null) + { + throw new ArgumentNullException(nameof(source)); + } + return source.OrderBy(m => Guid.NewGuid()); + } + + /// + /// 将集合展开并分别转换成字符串,再以指定的分隔符衔接,拼成一个字符串返回。默认分隔符为逗号 + /// + /// 要处理的集合 + /// 分隔符,默认为逗号 + /// 拼接后的字符串 + public static string ExpandAndToString(this IEnumerable collection, string separator = ",") + { + return collection.ExpandAndToString(t => t?.ToString(), separator); + } + + /// + /// 循环集合的每一项,调用委托生成字符串,返回合并后的字符串。默认分隔符为逗号 + /// + /// 待处理的集合 + /// 单个集合项的转换委托 + /// 分隔符,默认为逗号 + /// 泛型类型 + /// + public static string ExpandAndToString(this IEnumerable collection, Func itemFormatFunc, string separator = ",") + { + collection = collection as IList ?? collection.ToList(); + if (!collection.Any()) + { + return string.Empty; + } + StringBuilder sb = new StringBuilder(); + int i = 0; + int count = collection.Count(); + foreach (T t in collection) + { + if (i == count - 1) + { + sb.Append(itemFormatFunc(t)); + } + else + { + sb.Append(itemFormatFunc(t) + separator); + } + i++; + } + return sb.ToString(); + } + + /// + /// 集合是否为空 + /// + /// 要处理的集合 + /// 动态类型 + /// 为空返回True,不为空返回False + public static bool IsEmpty(this IEnumerable collection) + { + collection = collection as IList ?? collection.ToList(); + return !collection.Any(); + } + + /// + /// 根据第三方条件是否为真来决定是否执行指定条件的查询 + /// + /// 要查询的源 + /// 查询条件 + /// 第三方条件 + /// 动态类型 + /// 查询的结果 + public static IEnumerable WhereIf(this IEnumerable source, Func predicate, bool condition) + { + source = source as IList ?? source.ToList(); + + return condition ? source.Where(predicate) : source; + } + + /// + /// 将字符串集合按指定前缀排序 + /// + public static IEnumerable OrderByPrefixes(this IEnumerable source, Func keySelector, params string[] prefixes) + { + List all = source.OrderBy(keySelector).ToList(); + List result = new List(); + foreach (string prefix in prefixes) + { + List tmpList = all.Where(m => keySelector(m).StartsWith(prefix)).OrderBy(keySelector).ToList(); + all = all.Except(tmpList).ToList(); + result.AddRange(tmpList); + } + result.AddRange(all); + return result; + } + + /// + /// 根据指定条件返回集合中不重复的元素 + /// + /// 动态类型 + /// 动态筛选条件类型 + /// 要操作的源 + /// 重复数据筛选条件 + /// 不重复元素的集合 + public static IEnumerable DistinctBy(this IEnumerable source, Func keySelector) + { + source = source as IList ?? source.ToList(); + + return source.GroupBy(keySelector).Select(group => group.First()); + } + + /// + /// 把集合按指定字段与排序方式进行排序 + /// + /// 集合项类型 + /// 要排序的数据集 + /// 排序属性名 + /// 排序方向 + /// 排序后的数据集 + public static IOrderedEnumerable OrderBy(this IEnumerable source, + string propertyName, + ListSortDirection sortDirection = ListSortDirection.Ascending) + { + return CollectionPropertySorter.OrderBy(source, propertyName, sortDirection); + } + + /// + /// 把集合按指定字段排序条件进行排序 + /// + /// 动态类型 + /// 要排序的数据集 + /// 列表字段排序条件 + /// + public static IOrderedEnumerable OrderBy(this IEnumerable source, SortCondition sortCondition) + { + return source.OrderBy(sortCondition.SortField, sortCondition.ListSortDirection); + } + + /// + /// 把集合按指定字段排序条件进行排序 + /// + /// 动态类型 + /// 要排序的数据集 + /// 列表字段排序条件 + /// + public static IOrderedEnumerable OrderBy(this IEnumerable source, SortCondition sortCondition) + { + return source.OrderBy(sortCondition.SortField, sortCondition.ListSortDirection); + } + + /// + /// 把集合继续按指定字段排序方式进行排序 + /// + /// 动态类型 + /// 要排序的数据集 + /// 排序属性名 + /// 排序方向 + /// + public static IOrderedEnumerable ThenBy(this IOrderedEnumerable source, + string propertyName, + ListSortDirection sortDirection = ListSortDirection.Ascending) + { + propertyName.CheckNotNullOrEmpty("propertyName"); + + return CollectionPropertySorter.ThenBy(source, propertyName, sortDirection); + } + + /// + /// 把集合继续指定字段排序方式进行排序 + /// + /// 动态类型 + /// 要排序的数据集 + /// 列表字段排序条件 + /// + public static IOrderedEnumerable ThenBy(this IOrderedEnumerable source, SortCondition sortCondition) + { + return source.ThenBy(sortCondition.SortField, sortCondition.ListSortDirection); + } + + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Extensions/FileExtension.cs b/CloudBuilder/CloudBuilder.Core/Extensions/FileExtension.cs new file mode 100644 index 0000000..b722908 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Extensions/FileExtension.cs @@ -0,0 +1,37 @@ +using Microsoft.AspNetCore.StaticFiles; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.Extensions +{ + public class FileExtension + { + public static FileExtensionContentTypeProvider GetFileExtensionContentTypeProvider() + { + var fileExtensionProvider = new FileExtensionContentTypeProvider(); + fileExtensionProvider.Mappings[".iec"] = "application/octet-stream"; + fileExtensionProvider.Mappings[".patch"] = "application/octet-stream"; + fileExtensionProvider.Mappings[".apk"] = "application/vnd.android.package-archive"; + fileExtensionProvider.Mappings[".pem"] = "application/x-x509-user-cert"; + fileExtensionProvider.Mappings[".gzip"] = "application/x-gzip"; + fileExtensionProvider.Mappings[".7zip"] = "application/zip"; + fileExtensionProvider.Mappings[".jpg2"] = "image/jp2"; + fileExtensionProvider.Mappings[".et"] = "application/kset"; + fileExtensionProvider.Mappings[".dps"] = "application/ksdps"; + fileExtensionProvider.Mappings[".cdr"] = "application/x-coreldraw"; + fileExtensionProvider.Mappings[".shtml"] = "text/html"; + fileExtensionProvider.Mappings[".php"] = "application/x-httpd-php"; + fileExtensionProvider.Mappings[".php3"] = "application/x-httpd-php"; + fileExtensionProvider.Mappings[".php4"] = "application/x-httpd-php"; + fileExtensionProvider.Mappings[".phtml"] = "application/x-httpd-php"; + fileExtensionProvider.Mappings[".pcd"] = "image/x-photo-cd"; + fileExtensionProvider.Mappings[".bcmap"] = "application/octet-stream"; + fileExtensionProvider.Mappings[".properties"] = "application/octet-stream"; + fileExtensionProvider.Mappings[".m3u8"] = "application/x-mpegURL"; + return fileExtensionProvider; + } + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Extensions/ObjectExtensions.cs b/CloudBuilder/CloudBuilder.Core/Extensions/ObjectExtensions.cs new file mode 100644 index 0000000..8be0617 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Extensions/ObjectExtensions.cs @@ -0,0 +1,315 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Dynamic; +using System.IO; +using System.Linq; +using System.Runtime.Serialization; +using System.Runtime.Serialization.Formatters.Binary; +using System.Text; +using System.Text.Json; +using System.Threading.Tasks; +using System.Xml; + +namespace CloudBuilder.Core.Extensions +{ + /// + /// 基类型扩展辅助操作类 + /// + public static class ObjectExtensions + { + #region 公共方法 + + /// + /// 把对象类型转换为指定类型 + /// + /// + /// + /// + public static object CastTo(this object value, Type conversionType) + { + if (value == null) + { + return null; + } + if (conversionType.IsNullableType()) + { + conversionType = conversionType.GetUnNullableType(); + } + if (conversionType.IsEnum) + { + return Enum.Parse(conversionType, value.ToString()); + } + if (conversionType == typeof(Guid)) + { + return Guid.Parse(value.ToString()); + } + return Convert.ChangeType(value, conversionType); + } + + /// + /// 把对象类型转化为指定类型 + /// + /// 动态类型 + /// 要转化的源对象 + /// 转化后的指定类型的对象,转化失败引发异常。 + public static T CastTo(this object value) + { + if (value == null && default(T) == null) + { + return default(T); + } + if (value.GetType() == typeof(T)) + { + return (T)value; + } + object result = CastTo(value, typeof(T)); + return (T)result; + } + + /// + /// 把对象类型转化为指定类型,转化失败时返回指定的默认值 + /// + /// 动态类型 + /// 要转化的源对象 + /// 转化失败返回的指定默认值 + /// 转化后的指定类型对象,转化失败时返回指定的默认值 + public static T CastTo(this object value, T defaultValue) + { + try + { + return CastTo(value); + } + catch (Exception) + { + return defaultValue; + } + } + + /// + /// 判断当前值是否介于指定范围内 + /// + /// 动态类型 + /// 动态类型对象 + /// 范围起点 + /// 范围终点 + /// 是否可等于上限(默认等于) + /// 是否可等于下限(默认等于) + /// 是否介于 + public static bool IsBetween(this IComparable value, T start, T end, bool leftEqual = true, bool rightEqual = true) where T : IComparable + { + bool flag = leftEqual ? value.CompareTo(start) >= 0 : value.CompareTo(start) > 0; + return flag && (rightEqual ? value.CompareTo(end) <= 0 : value.CompareTo(end) < 0); + } + + /// + /// 判断当前值是否介于指定范围内 + /// + /// 动态类型 + /// 动态类型对象 + /// 范围小值 + /// 范围大值 + /// 是否可等于小值(默认等于) + /// 是否可等于大值(默认等于) + public static bool IsInRange(this IComparable value, T min, T max, bool minEqual = true, bool maxEqual = true) where T : IComparable + { + bool flag = minEqual ? value.CompareTo(min) >= 0 : value.CompareTo(min) > 0; + return flag && (maxEqual ? value.CompareTo(max) <= 0 : value.CompareTo(max) < 0); + } + + /// + /// 是否存在于 + /// + public static bool IsIn(this T value, params T[] source) + { + return source.Contains(value); + } + + /// + /// 将对象[主要是匿名对象]转换为dynamic + /// + public static dynamic ToDynamic(this object value) + { + IDictionary expando = new ExpandoObject(); + Type type = value.GetType(); + PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(type); + foreach (PropertyDescriptor property in properties) + { + var val = property.GetValue(value); + if (property.PropertyType.FullName != null && property.PropertyType.FullName.StartsWith("<>f__AnonymousType")) + { + dynamic dval = val.ToDynamic(); + expando.Add(property.Name, dval); + } + else + { + expando.Add(property.Name, val); + } + } + return (ExpandoObject)expando; + } + + /// + /// 将 DateTimeOffset 转换成本地 DateTime + /// + /// + /// + public static DateTime ConvertToDateTime(this DateTimeOffset dateTime) + { + if (dateTime.Offset.Equals(TimeSpan.Zero)) + return dateTime.UtcDateTime; + if (dateTime.Offset.Equals(TimeZoneInfo.Local.GetUtcOffset(dateTime.DateTime))) + return dateTime.ToLocalTime().DateTime; + else + return dateTime.DateTime; + } + + /// + /// 将 DateTimeOffset? 转换成本地 DateTime? + /// + /// + /// + public static DateTime? ConvertToDateTime(this DateTimeOffset? dateTime) + { + return dateTime.HasValue ? dateTime.Value.ConvertToDateTime() : null; + } + + /// + /// 将 DateTime 转换成 DateTimeOffset + /// + /// + /// + public static DateTimeOffset ConvertToDateTimeOffset(this DateTime dateTime) + { + return DateTime.SpecifyKind(dateTime, DateTimeKind.Local); + } + + /// + /// 将 DateTime? 转换成 DateTimeOffset? + /// + /// + /// + public static DateTimeOffset? ConvertToDateTimeOffset(this DateTime? dateTime) + { + return dateTime.HasValue ? dateTime.Value.ConvertToDateTimeOffset() : null; + } + + /// + /// 将时间戳转换为 DateTime + /// + /// + /// + internal static DateTime ConvertToDateTime(this long timestamp) + { + var timeStampDateTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + var digitCount = (int)Math.Floor(Math.Log10(timestamp) + 1); + + if (digitCount != 13 && digitCount != 10) + { + throw new ArgumentException("Data is not a valid timestamp format."); + } + + return (digitCount == 13 + ? timeStampDateTime.AddMilliseconds(timestamp) // 13 位时间戳 + : timeStampDateTime.AddSeconds(timestamp)).ToLocalTime(); // 10 位时间戳 + } + + /// + /// 将 IFormFile 转换成 byte[] + /// + /// + /// + //public static byte[] ToByteArray(this IFormFile formFile) + //{ + // var fileLength = formFile.Length; + // using var stream = formFile.OpenReadStream(); + // var bytes = new byte[fileLength]; + + // stream.Read(bytes, 0, (int)fileLength); + + // return bytes; + //} + + /// + /// 将流保存到本地磁盘 + /// + /// + /// + /// + public static void CopyToSave(this Stream stream, string path) + { + // 空检查 + if (string.IsNullOrWhiteSpace(path)) throw new ArgumentNullException(nameof(path)); + + using var fileStream = File.Create(path); + stream.CopyTo(fileStream); + } + + /// + /// 将字节数组保存到本地磁盘 + /// + /// + /// + /// + public static void CopyToSave(this byte[] bytes, string path) + { + using var stream = new MemoryStream(bytes); + stream.CopyToSave(path); + } + + /// + /// 将流保存到本地磁盘 + /// + /// + /// + /// + public static async Task CopyToSaveAsync(this Stream stream, string path) + { + // 空检查 + if (string.IsNullOrWhiteSpace(path)) throw new ArgumentNullException(nameof(path)); + + using var fileStream = File.Create(path); + await stream.CopyToAsync(fileStream); + } + + /// + /// 将字节数组保存到本地磁盘 + /// + /// + /// + /// + public static async Task CopyToSaveAsync(this byte[] bytes, string path) + { + using var stream = new MemoryStream(bytes); + await stream.CopyToSaveAsync(path); + } + + + /// + /// 判断类型是否实现某个泛型 + /// + /// 类型 + /// 泛型类型 + /// bool + public static bool HasImplementedRawGeneric(this Type type, Type generic) + { + // 检查接口类型 + var isTheRawGenericType = type.GetInterfaces().Any(IsTheRawGenericType); + if (isTheRawGenericType) return true; + + // 检查类型 + while (type != null && type != typeof(object)) + { + isTheRawGenericType = IsTheRawGenericType(type); + if (isTheRawGenericType) return true; + type = type.BaseType; + } + + return false; + + // 判断逻辑 + bool IsTheRawGenericType(Type type) => generic == (type.IsGenericType ? type.GetGenericTypeDefinition() : type); + } + #endregion + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Extensions/ParameterCheckExtensions.cs b/CloudBuilder/CloudBuilder.Core/Extensions/ParameterCheckExtensions.cs new file mode 100644 index 0000000..058b3a8 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Extensions/ParameterCheckExtensions.cs @@ -0,0 +1,200 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.Extensions +{ + /// + /// 用于参数检查的扩展方法 + /// + public static class ParameterCheckExtensions + { + /// + /// 验证指定值的断言是否为真,如果不为真,抛出指定消息的指定类型异常 + /// + /// 异常类型 + /// 要验证的断言。 + /// 异常消息。 + private static void Require(bool assertion, string message) where TException : Exception + { + if (assertion) + { + return; + } + if (string.IsNullOrEmpty(message)) + { + throw new ArgumentNullException("message"); + } + TException exception = (TException)Activator.CreateInstance(typeof(TException), message); + throw exception; + } + + /// + /// 验证指定值的断言表达式是否为真,不为值抛出异常 + /// + /// + /// 要验证的断言表达式 + /// 异常消息 + public static void Required(this T value, Func assertionFunc, string message) + { + if (assertionFunc == null) + { + throw new ArgumentNullException("assertionFunc"); + } + Require(assertionFunc(value), message); + } + + /// + /// 验证指定值的断言表达式是否为真,不为真抛出异常 + /// + /// 要判断的值的类型 + /// 抛出的异常类型 + /// 要判断的值 + /// 要验证的断言表达式 + /// 异常消息 + public static void Required(this T value, Func assertionFunc, string message) where TException : Exception + { + if (assertionFunc == null) + { + throw new ArgumentNullException("assertionFunc"); + } + Require(assertionFunc(value), message); + } + + /// + /// 检查参数不能为空引用,否则抛出异常。 + /// + /// + /// 参数名称 + /// + public static void CheckNotNull(this T value, string paramName) where T : class + { + Require(value != null, string.Format("参数“{0}”不能为空引用。", paramName)); + } + + /// + /// 检查字符串不能为空引用或空字符串,否则抛出异常或异常。 + /// + /// + /// 参数名称。 + /// + /// + public static void CheckNotNullOrEmpty(this string value, string paramName) + { + value.CheckNotNull(paramName); + Require(value.Length > 0, string.Format("参数“{0}”不能为空引用或空字符串。", paramName)); + } + + /// + /// 检查Guid值不能为Guid.Empty,否则抛出异常。 + /// + /// + /// 参数名称。 + /// + public static void CheckNotEmpty(this Guid value, string paramName) + { + Require(value != Guid.Empty, string.Format("参数“{0}”的值不能为Guid.Empty", paramName)); + } + + /// + /// 检查集合不能为空引用或空集合,否则抛出异常或异常。 + /// + /// 集合项的类型。 + /// + /// 参数名称。 + /// + /// + public static void CheckNotNullOrEmpty(this IEnumerable collection, string paramName) + { + collection.CheckNotNull(paramName); + Require(collection.Any(), string.Format("参数“{0}”不能为空引用或空集合。", paramName)); + } + + /// + /// 检查参数必须小于[或可等于,参数canEqual]指定值,否则抛出异常。 + /// + /// 参数类型。 + /// + /// 参数名称。 + /// 要比较的值。 + /// 是否可等于。 + /// + public static void CheckLessThan(this T value, string paramName, T target, bool canEqual = false) where T : IComparable + { + bool flag = canEqual ? value.CompareTo(target) <= 0 : value.CompareTo(target) < 0; + string format = canEqual ? "参数“{0}”的值必须小于或等于“{1}”。" : "参数“{0}”的值必须小于“{1}”。"; + Require(flag, string.Format(format, paramName, target)); + } + + /// + /// 检查参数必须大于[或可等于,参数canEqual]指定值,否则抛出异常。 + /// + /// 参数类型。 + /// + /// 参数名称。 + /// 要比较的值。 + /// 是否可等于。 + /// + public static void CheckGreaterThan(this T value, string paramName, T target, bool canEqual = false) where T : IComparable + { + bool flag = canEqual ? value.CompareTo(target) >= 0 : value.CompareTo(target) > 0; + string format = canEqual ? "参数“{0}”的值必须大于或等于“{1}”。" : "参数“{0}”的值必须大于“{1}”。"; + Require(flag, string.Format(format, paramName, target)); + } + + /// + /// 检查参数必须在指定范围之间,否则抛出异常。 + /// + /// 参数类型。 + /// + /// 参数名称。 + /// 比较范围的起始值。 + /// 比较范围的结束值。 + /// 是否可等于起始值 + /// 是否可等于结束值 + /// + public static void CheckBetween(this T value, string paramName, T start, T end, bool startEqual = false, bool endEqual = false) + where T : IComparable + { + bool flag = startEqual ? value.CompareTo(start) >= 0 : value.CompareTo(start) > 0; + string message = startEqual + ? string.Format("参数“{0}”的值必须在“{1}”与“{2}”之间。", paramName, start, end) + : string.Format("参数“{0}”的值必须在“{1}”与“{2}”之间,且不能等于“{3}”。", paramName, start, end, start); + Require(flag, message); + + flag = endEqual ? value.CompareTo(end) <= 0 : value.CompareTo(end) < 0; + message = endEqual + ? string.Format("参数“{0}”的值必须在“{1}”与“{2}”之间。", paramName, start, end) + : string.Format("参数“{0}”的值必须在“{1}”与“{2}”之间,且不能等于“{3}”。", paramName, start, end, end); + Require(flag, message); + } + + /// + /// 检查指定路径的文件夹必须存在,否则抛出异常。 + /// + /// + /// 参数名称。 + /// + /// + public static void CheckDirectoryExists(this string directory, string paramName = null) + { + CheckNotNull(directory, paramName); + Require(Directory.Exists(directory), string.Format("指定的目录路径“{0}”不存在。", directory)); + } + + /// + /// 检查指定路径的文件必须存在,否则抛出异常。 + /// + /// + /// 参数名称。 + /// 当文件路径为null时 + /// 当文件路径不存在时 + public static void CheckFileExists(this string filename, string paramName = null) + { + CheckNotNull(filename, paramName); + Require(File.Exists(filename), string.Format("指定的文件路径“{0}”不存在。", filename)); + } + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Extensions/ServiceExtensions.cs b/CloudBuilder/CloudBuilder.Core/Extensions/ServiceExtensions.cs new file mode 100644 index 0000000..d5585a5 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Extensions/ServiceExtensions.cs @@ -0,0 +1,86 @@ +using CloudBuilder.Core.Application.Builders; +using CloudBuilder.Core.DatabaseAccessor; +using CloudBuilder.Core.DependencyInjection.Form; +using CloudBuilder.Core.Extensions; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.FileSystemGlobbing; +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; +using System.Reflection; + +namespace Microsoft.Extensions.DependencyInjection +{ + public static partial class ServiceExtensions + { + /// + /// 添加依赖注入接口 + /// + /// 服务集合 + /// 服务集合 + public static IServiceCollection Initialize(this IServiceCollection services) + { + IConfiguration configuration = GetConfiguration(); + services.AddSingleton(configuration); + + CloudBuilderBuilder builder = new CloudBuilderBuilder(services, configuration); + builder.AddPack(); + + services.AddSingleton(builder); + + JsonConvert.DefaultSettings = () => new JsonSerializerSettings + { + NullValueHandling = NullValueHandling.Ignore, + ContractResolver = new DefaultContractResolver(), + ReferenceLoopHandling = ReferenceLoopHandling.Ignore, + DateFormatString = "yyyy-MM-dd HH:mm:ss" + }; + + return services; + } + public static IServiceProvider Build(this IServiceCollection services) + { + var serviceProvider = services.BuildServiceProvider(); + + //初始化WinForm系统环境变量 + ApplicationServiceContext applicationServiceContext = serviceProvider.GetService()!; + + return serviceProvider; + } + + public static IConfiguration GetConfiguration() + { + var entryAssembly = Assembly.GetEntryAssembly(); + string localentryAssembly = Path.GetFileNameWithoutExtension(entryAssembly.ManifestModule.Name); + var configuration = new ConfigurationBuilder(); + + // 获取程序执行目录 + var executeDirectory = AppContext.BaseDirectory; + + // 获取自定义配置扫描目录 + var configurationScanDirectories = (configuration.Build().GetSection("ConfigurationScanDirectories") + .Get() + ?? Array.Empty()).Select(u => Path.Combine(executeDirectory, u)); + + // 扫描执行目录及自定义配置目录下的 *.json 文件 + var jsonFiles = new[] { executeDirectory } + .Concat(configurationScanDirectories) + .SelectMany(u => + Directory.GetFiles(u, "*.json", SearchOption.TopDirectoryOnly)); + + // 如果没有配置文件,中止执行 + if (!jsonFiles.Any()) return configuration.Build(); + + // 循环加载 + foreach (var jsonFile in jsonFiles) + { + //存在应用名的不加入 + if (Path.GetFileName(jsonFile).Contains(localentryAssembly)) continue; + + configuration.AddJsonFile(jsonFile, optional: true, reloadOnChange: true); + } + + return configuration.Build(); + } + } +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Core/Extensions/SortCondition.cs b/CloudBuilder/CloudBuilder.Core/Extensions/SortCondition.cs new file mode 100644 index 0000000..3522729 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Extensions/SortCondition.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Linq.Expressions; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.Extensions +{ + /// + /// 列表字段排序条件 + /// + public class SortCondition + { + /// + /// 初始化一个类型的新实例 + /// + public SortCondition() : this(null) + { } + + /// + /// 构造一个指定字段名称的升序排序的排序条件 + /// + /// 字段名称 + public SortCondition(string sortField) + : this(sortField, ListSortDirection.Ascending) + { } + + /// + /// 构造一个排序字段名称和排序方式的排序条件 + /// + /// 字段名称 + /// 排序方式 + public SortCondition(string sortField, ListSortDirection listSortDirection) + { + SortField = sortField; + ListSortDirection = listSortDirection; + } + + /// + /// 获取或设置 排序字段名称 + /// + public string SortField { get; set; } + + /// + /// 获取或设置 排序方向 + /// + public ListSortDirection ListSortDirection { get; set; } + } + + + /// + /// 支持泛型的列表字段排序条件 + /// + /// 列表元素类型 + public class SortCondition : SortCondition + { + /// + /// 使用排序字段 初始化一个类型的新实例 + /// + public SortCondition(Expression> keySelector) + : this(keySelector, ListSortDirection.Ascending) + { } + + /// + /// 使用排序字段与排序方式 初始化一个类型的新实例 + /// + public SortCondition(Expression> keySelector, ListSortDirection listSortDirection) + : base(GetPropertyName(keySelector), listSortDirection) + { } + + /// + /// 从泛型委托获取属性名 + /// + private static string GetPropertyName(Expression> keySelector) + { + string param = keySelector.Parameters.First().Name; + string operand = ((dynamic)keySelector.Body).Operand.ToString(); + operand = operand.Substring(param.Length + 1, operand.Length - param.Length - 1); + return operand; + } + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Extensions/StringExtensions.cs b/CloudBuilder/CloudBuilder.Core/Extensions/StringExtensions.cs new file mode 100644 index 0000000..b23f4cf --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Extensions/StringExtensions.cs @@ -0,0 +1,1167 @@ +using CloudBuilder.Core.Extensions; +using System; +using System.Collections.Generic; +using System.Data.SqlTypes; +using System.Diagnostics; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using System.Web; + +namespace System +{ + /// + /// 字符串类型的扩展辅助操作类 + /// + public static class StringExtensions + { + public const char DELIMITER_CHAR = ','; + public const string DATA_FORMAT_SHORT= "yyyy-MM-dd"; + public const string DATA_FORMAT_LONG = "yyyy-MM-dd hh:mm:ss"; + /// + /// 字符串转为首字母大写,分隔符'_',如CreatedDatetime + /// + /// + /// + public static string StringToProerty(this string s) + { + string[] slist = s.Split('_'); + + string formats = string.Empty; + + foreach (string f in slist) + { + char[] clist = f.ToCharArray(); + formats += clist[0].ToString().ToUpper() + f.Substring(1, f.Length - 1); + } + + return formats; + } + + /// + /// 字符串转为第一个字母小写,接下来首字母大写,分隔符'_',如createdDatetime + /// + /// + /// + public static string StringToProtectedProerty(this string s) + { + string[] slist = s.Split('_'); + + string formats = string.Empty; + + foreach (string f in slist) + { + char[] clist = f.ToCharArray(); + formats += (formats.Length > 0 ? clist[0].ToString().ToUpper() : clist[0].ToString().ToLower()) + f.Substring(1, f.Length - 1); + } + + return formats; + } + + public static string StringToDbField(this string s) + { + var r = new Regex(@" + (?<=[A-Z])(?=[A-Z][a-z]) | + (?<=[^A-Z])(?=[A-Z]) | + (?<=[A-Za-z])(?=[^A-Za-z])", RegexOptions.IgnorePatternWhitespace); + + return r.Replace(s, "_").ToLower(); + } + + public static string GetFormattedShortDate(this DateTime date) + { + return date.ToString(DATA_FORMAT_SHORT); + } + + public static string GetFormattedLongDate(this DateTime date) + { + return date.ToString(DATA_FORMAT_LONG); + } + + public static string GetFormattedDateString(this SqlDateTime date, string dataFormat) + { + if (date.IsNull) return null; + + return date.Value.ToString(dataFormat); + } + + public static string GetFormattedDateString(this DateTime date, string dataFormat) + { + return date.ToString(dataFormat); + } + + public static string GetFormattedDateString(this DateTime? date, string dataFormat) + { + if (!date.HasValue) return null; + + return date.Value.ToString(dataFormat); + } + + public static bool TryParse(this string date, string format, out DateTime dateTime) + { + if (!DateTime.TryParseExact(date, format, new CultureInfo("en-US"), DateTimeStyles.None, out dateTime)) + { + return false; + } + + if (dateTime < new DateTime(1753, 1, 1)) return false; + + return true; + } + + /// + /// 字符串转日期格式 + /// + /// + /// + /// + public static SqlDateTime Parse(this string date, string format) + { + DateTime dateTime; + + if (!DateTime.TryParseExact(date, format, new CultureInfo("en-US"), DateTimeStyles.None, out dateTime)) + { + return SqlDateTime.Null; + } + + return dateTime; + } + + public static string[] DelimiteredListToArray(this string t) + { + return t.DelimiteredListToArray(DELIMITER_CHAR); + } + + public static string[] DelimiteredListToArray(this string t, char delim) + { + if (string.IsNullOrEmpty(t)) return null; + return t.Split(delim); + } + + /// + /// 字符串安全转数组,分隔符',' + /// + /// + /// + public static List DelimiteredListToList(this string t) + { + return t.DelimiteredListToList(DELIMITER_CHAR); + } + + public static List DelimiteredListToList(this string t, char delim) + { + if (string.IsNullOrEmpty(t)) return null; + + List l = new List(); + l.AddRange(t.DelimiteredListToArray(delim)); + return l; + } + + /// + /// 数组变成字符串 + /// + /// + /// + public static string ToDelimiteredList(this string[] s) + { + return s.ToDelimiteredList(DELIMITER_CHAR); + } + + public static string ToQuotedDelimitedList(this string[] s) + { + StringBuilder b = new StringBuilder(); + + foreach (string t in s) + { + if (b.Length > 0) b.Append(DELIMITER_CHAR); + b.Append('\'' + t + '\''); + } + + return b.ToString(); + } + + public static string ToDelimiteredList(this string[] s, char delim) + { + StringBuilder b = new StringBuilder(); + foreach (string t in s) + { + b.Append(delim + t); + } + + string r = b.ToString(); + if (r.StartsWith(delim.ToString())) r = r.Substring(1); + + return r; + } + + public static bool IsDelimiteredListContains(string dlist, string c) + { + return IsDelimiteredListContains(dlist, c, DELIMITER_CHAR); + } + + public static bool IsDelimiteredListContains(string dlist, string c, char delim) + { + List l = dlist.DelimiteredListToList(delim); + if (l == null || l.Count <= 0) return false; + + return l.Contains(c); + } + + public static string CreateRandomNum(int NumCount) + { + string allChar = "0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,G,H,I,J,K,O,P,Q,R,S,T,U,W,X,Y,Z,a,b,c,d,e,f,g,h,i,j,k,m,n,o,p,q,s,t,u,w,x,y,z"; + string[] allCharArray = allChar.Split(',');//拆分成数组 + string randomNum = ""; + int temp = -1; //记录上次随机数的数值,尽量避免产生几个相同的随机数 + Random rand = new Random(); + for (int i = 0; i < NumCount; i++) + { + if (temp != -1) + { + rand = new Random(i * temp * (int)DateTime.Now.Ticks); + } + int t = rand.Next(allCharArray.Length - 1); + if (temp == t) + { + return CreateRandomNum(NumCount); + } + temp = t; + randomNum += allCharArray[t]; + } + return randomNum; + } + + public static string CreateRandomNumber(int NumCount) + { + string allChar = "0,1,2,3,4,5,6,7,8,9"; + string[] allCharArray = allChar.Split(',');//拆分成数组 + string randomNum = ""; + int temp = -1; //记录上次随机数的数值,尽量避免产生几个相同的随机数 + Random rand = new Random(); + for (int i = 0; i < NumCount; i++) + { + if (temp != -1) + { + rand = new Random(i * temp * (int)DateTime.Now.Ticks); + } + int t = rand.Next(allCharArray.Length - 1); + if (temp == t) + { + return CreateRandomNumber(NumCount); + } + temp = t; + randomNum += allCharArray[t]; + } + return randomNum; + } + + #region 正则表达式 + + /// + /// 指示所指定的正则表达式在指定的输入字符串中是否找到了匹配项 + /// + /// 要搜索匹配项的字符串 + /// 要匹配的正则表达式模式 + /// 是否包含,否则全匹配 + /// 如果正则表达式找到匹配项,则为 true;否则,为 false + public static bool IsMatch(this string value, string pattern, bool isContains = true) + { + if (value == null) + { + return false; + } + return isContains + ? Regex.IsMatch(value, pattern) + : Regex.Match(value, pattern).Success; + } + + /// + /// 在指定的输入字符串中搜索指定的正则表达式的第一个匹配项 + /// + /// 要搜索匹配项的字符串 + /// 要匹配的正则表达式模式 + /// 一个对象,包含有关匹配项的信息 + public static string Match(this string value, string pattern) + { + if (value == null) + { + return null; + } + return Regex.Match(value, pattern).Value; + } + + /// + /// 在指定的输入字符串中搜索指定的正则表达式的所有匹配项的字符串集合 + /// + /// 要搜索匹配项的字符串 + /// 要匹配的正则表达式模式 + /// 一个集合,包含有关匹配项的字符串值 + public static IEnumerable Matches(this string value, string pattern) + { + if (value == null) + { + return new string[] { }; + } + MatchCollection matches = Regex.Matches(value, pattern); + return from Match match in matches select match.Value; + } + + /// + /// 在指定的输入字符串中匹配第一个数字字符串 + /// + public static string MatchFirstNumber(this string value) + { + MatchCollection matches = Regex.Matches(value, @"\d+"); + if (matches.Count == 0) + { + return string.Empty; + } + return matches[0].Value; + } + + /// + /// 在指定字符串中匹配最后一个数字字符串 + /// + public static string MatchLastNumber(this string value) + { + MatchCollection matches = Regex.Matches(value, @"\d+"); + if (matches.Count == 0) + { + return string.Empty; + } + return matches[matches.Count - 1].Value; + } + + /// + /// 在指定字符串中匹配所有数字字符串 + /// + public static IEnumerable MatchNumbers(this string value) + { + return Matches(value, @"\d+"); + } + + /// + /// 检测指定字符串中是否包含数字 + /// + public static bool IsMatchNumber(this string value) + { + return IsMatch(value, @"\d"); + } + + /// + /// 检测指定字符串是否全部为数字并且长度等于指定长度 + /// + public static bool IsMatchNumber(this string value, int length) + { + Regex regex = new Regex(@"^\d{" + length + "}$"); + return regex.IsMatch(value); + } + + /// + /// 截取指定字符串之间的字符串 + /// + /// + /// 起始字符串 + /// 结束字符串,可多个 + /// 返回的中间字符串 + public static string Substring(this string source, string startString, params string[] endStrings) + { + if (source.IsMissing()) + { + return string.Empty; + } + int startIndex = 0; + if (!string.IsNullOrEmpty(startString)) + { + startIndex = source.IndexOf(startString, StringComparison.OrdinalIgnoreCase); + if (startIndex < 0) + { + throw new InvalidOperationException(string.Format("在源字符串中无法找到“{0}”的子串位置", startString)); + } + startIndex = startIndex + startString.Length; + } + int endIndex = source.Length; + endStrings = endStrings.OrderByDescending(m => m.Length).ToArray(); + foreach (string endString in endStrings) + { + if (string.IsNullOrEmpty(endString)) + { + endIndex = source.Length; + break; + } + endIndex = source.IndexOf(endString, startIndex, StringComparison.OrdinalIgnoreCase); + if (endIndex < 0 || endIndex < startIndex) + { + continue; + } + break; + } + if (endIndex < 0 || endIndex < startIndex) + { + throw new InvalidOperationException(string.Format("在源字符串中无法找到“{0}”的子串位置", endStrings.ExpandAndToString())); + } + + int length = endIndex - startIndex; + return source.Substring(startIndex, length); + } + + /// + /// 用正则表达式截取字符串 + /// + public static string Substring2(this string source, string startString, string endString) + { + return source.Substring2(startString, endString, false); + } + + /// + /// 用正则表达式截取字符串 + /// + public static string Substring2(this string source, string startString, string endString, bool containsEmpty) + { + if (source.IsMissing()) + { + return string.Empty; + } + string inner = containsEmpty ? "\\s\\S" : "\\S"; + string result = source.Match(string.Format("(?<={0})([{1}]+?)(?={2})", startString, inner, endString)); + return result.IsMissing() ? null : result; + } + + /// + /// 是否电子邮件 + /// + public static bool IsEmail(this string value) + { + const string pattern = @"^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$"; + return value.IsMatch(pattern); + } + + /// + /// 是否是IP地址 + /// + public static bool IsIpAddress(this string value) + { + const string pattern = @"^((?:(?:25[0-5]|2[0-4]\d|((1\d{2})|([1-9]?\d)))\.){3}(?:25[0-5]|2[0-4]\d|((1\d{2})|([1-9]?\d))))$"; + return value.IsMatch(pattern); + } + + /// + /// 是否是整数 + /// + public static bool IsNumeric(this string value) + { + const string pattern = @"^\-?[0-9]+$"; + return value.IsMatch(pattern); + } + + /// + /// 是否是Unicode字符串 + /// + public static bool IsUnicode(this string value) + { + const string pattern = @"^[\u4E00-\u9FA5\uE815-\uFA29]+$"; + return value.IsMatch(pattern); + } + + /// + /// 是否Url字符串 + /// + public static bool IsUrl(this string value) + { + try + { + if (value.IsNullOrEmpty() || value.Contains(' ')) + { + return false; + } + Uri uri = new Uri(value); + return true; + } + catch (Exception) + { + return false; + } + } + + /// + /// 是否身份证号,验证如下3种情况: + /// 1.身份证号码为15位数字; + /// 2.身份证号码为18位数字; + /// 3.身份证号码为17位数字+1个字母 + /// + public static bool IsIdentityCardId(this string value) + { + if (value.Length != 15 && value.Length != 18) + { + return false; + } + Regex regex; + string[] array; + DateTime time; + if (value.Length == 15) + { + regex = new Regex(@"^(\d{6})(\d{2})(\d{2})(\d{2})(\d{3})_"); + if (!regex.Match(value).Success) + { + return false; + } + array = regex.Split(value); + return DateTime.TryParse(string.Format("{0}-{1}-{2}", "19" + array[2], array[3], array[4]), out time); + } + regex = new Regex(@"^(\d{6})(\d{4})(\d{2})(\d{2})(\d{3})([0-9Xx])$"); + if (!regex.Match(value).Success) + { + return false; + } + array = regex.Split(value); + if (!DateTime.TryParse(string.Format("{0}-{1}-{2}", array[2], array[3], array[4]), out time)) + { + return false; + } + //校验最后一位 + string[] chars = value.ToCharArray().Select(m => m.ToString()).ToArray(); + int[] weights = { 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2 }; + int sum = 0; + for (int i = 0; i < 17; i++) + { + int num = int.Parse(chars[i]); + sum = sum + num * weights[i]; + } + int mod = sum % 11; + string vCode = "10X98765432";//检验码字符串 + string last = vCode.ToCharArray().ElementAt(mod).ToString(); + return chars.Last().ToUpper() == last; + } + + /// + /// 是否手机号码 + /// + /// + /// 是否按严格格式验证 + public static bool IsMobileNumber(this string value, bool isRestrict = false) + { + string pattern = isRestrict ? @"^[1][3-8]\d{9}$" : @"^[1]\d{10}$"; + return value.IsMatch(pattern); + } + + #endregion + + #region 其他操作 + + /// + /// 指示指定的字符串是 null 或者 System.String.Empty 字符串 + /// + [DebuggerStepThrough] + public static bool IsNullOrEmpty(this string value) + { + return string.IsNullOrEmpty(value); + } + + /// + /// 指示指定的字符串是 null、空或者仅由空白字符组成。 + /// + [DebuggerStepThrough] + public static bool IsNullOrWhiteSpace(this string value) + { + return string.IsNullOrWhiteSpace(value); + } + + /// + /// 指示指定的字符串是 null、空或者仅由空白字符组成。 + /// + [DebuggerStepThrough] + public static bool IsMissing(this string value) + { + return string.IsNullOrWhiteSpace(value); + } + + /// + /// 为指定格式的字符串填充相应对象来生成字符串 + /// + /// 字符串格式,占位符以{n}表示 + /// 用于填充占位符的参数 + /// 格式化后的字符串 + [DebuggerStepThrough] + public static string FormatWith(this string format, params object[] args) + { + format.CheckNotNull("format"); + return string.Format(CultureInfo.CurrentCulture, format, args); + } + + /// + /// 将字符串反转 + /// + /// 要反转的字符串 + public static string ReverseString(this string value) + { + value.CheckNotNull("value"); + return new string(value.Reverse().ToArray()); + } + + /// + /// 单词变成单数形式 + /// + /// + /// + public static string ToSingular(this string word) + { + Regex plural1 = new Regex("(?[^aeiou])ies$"); + Regex plural2 = new Regex("(?[aeiou]y)s$"); + Regex plural3 = new Regex("(?[sxzh])es$"); + Regex plural4 = new Regex("(?[^sxzhyu])s$"); + + if (plural1.IsMatch(word)) + { + return plural1.Replace(word, "${keep}y"); + } + if (plural2.IsMatch(word)) + { + return plural2.Replace(word, "${keep}"); + } + if (plural3.IsMatch(word)) + { + return plural3.Replace(word, "${keep}"); + } + if (plural4.IsMatch(word)) + { + return plural4.Replace(word, "${keep}"); + } + + return word; + } + + /// + /// 单词变成复数形式 + /// + /// + /// + public static string ToPlural(this string word) + { + Regex plural1 = new Regex("(?[^aeiou])y$"); + Regex plural2 = new Regex("(?[aeiou]y)$"); + Regex plural3 = new Regex("(?[sxzh])$"); + Regex plural4 = new Regex("(?[^sxzhy])$"); + + if (plural1.IsMatch(word)) + { + return plural1.Replace(word, "${keep}ies"); + } + if (plural2.IsMatch(word)) + { + return plural2.Replace(word, "${keep}s"); + } + if (plural3.IsMatch(word)) + { + return plural3.Replace(word, "${keep}es"); + } + if (plural4.IsMatch(word)) + { + return plural4.Replace(word, "${keep}s"); + } + + return word; + } + + /// + /// 判断指定路径是否图片文件 + /// + public static bool IsImageFile(this string filename) + { + if (!File.Exists(filename)) + { + return false; + } + byte[] fileData = File.ReadAllBytes(filename); + if (fileData.Length == 0) + { + return false; + } + ushort code = BitConverter.ToUInt16(fileData, 0); + switch (code) + { + case 0x4D42: //bmp + case 0xD8FF: //jpg + case 0x4947: //gif + case 0x5089: //png + return true; + default: + return false; + } + } + + /// + /// 以指定字符串作为分隔符将指定字符串分隔成数组 + /// + /// 要分割的字符串 + /// 字符串类型的分隔符 + /// 是否移除数据中元素为空字符串的项 + /// 分割后的数据 + public static string[] Split(this string value, string strSplit, bool removeEmptyEntries = false) + { + return value.Split(new[] { strSplit }, removeEmptyEntries ? StringSplitOptions.RemoveEmptyEntries : StringSplitOptions.None); + } + + + /// + /// 支持汉字的字符串长度,汉字长度计为2 + /// + /// 参数字符串 + /// 当前字符串的长度,汉字长度为2 + public static int TextLength(this string value) + { + ASCIIEncoding ascii = new ASCIIEncoding(); + int tempLen = 0; + byte[] bytes = ascii.GetBytes(value); + foreach (byte b in bytes) + { + if (b == 63) + { + tempLen += 2; + } + else + { + tempLen += 1; + } + } + return tempLen; + } + + /// + /// 将JSON字符串还原为对象 + /// + /// 要转换的目标类型 + /// JSON字符串 + /// + //public static T FromJsonString(this string json) + //{ + // json.CheckNotNull("json"); + // return JsonConvert.DeserializeObject(json); + //} + + /// + /// 将JSON字符串还原为对象 + /// + /// JSON字符串 + /// 数据类型 + //public static object FromJsonString(this string json, Type type) + //{ + // return JsonConvert.DeserializeObject(json, type); + //} + + /// + /// 给URL添加查询参数 + /// + /// URL字符串 + /// 要添加的参数,形如:"id=1,cid=2" + /// + public static string AddUrlQuery(this string url, params string[] queries) + { + foreach (string query in queries) + { + if (!url.Contains("?")) + { + url += "?"; + } + else if (!url.EndsWith("&")) + { + url += "&"; + } + + url = url + query; + } + return url; + } + + /// + /// 获取URL中指定参数的值,不存在返回空字符串 + /// + public static string GetUrlQuery(this string url, string key) + { + Uri uri = new Uri(url); + string query = uri.Query; + if (query.IsNullOrEmpty()) + { + return string.Empty; + } + query = query.TrimStart('?'); + var dict = (from m in query.Split("&", true) + let strs = m.Split("=") + select new KeyValuePair(strs[0], strs[1])) + .ToDictionary(m => m.Key, m => m.Value); + if (dict.ContainsKey(key)) + { + return dict[key]; + } + return string.Empty; + } + + /// + /// 给URL添加 # 参数 + /// + /// URL字符串 + /// 要添加的参数 + /// + public static string AddHashFragment(this string url, string query) + { + if (!url.Contains("#")) + { + url += "#"; + } + + return url + query; + } + + /// + /// 将字符串转换为[]数组,默认编码为 + /// + public static byte[] ToBytes(this string value, Encoding encoding = null) + { + if (encoding == null) + { + encoding = Encoding.UTF8; + } + return encoding.GetBytes(value); + } + + /// + /// 将[]数组转换为字符串,默认编码为 + /// + public static string ToString2(this byte[] bytes, Encoding encoding = null) + { + if (encoding == null) + { + encoding = Encoding.UTF8; + } + return encoding.GetString(bytes); + } + + /// + /// 将[]数组转换为Base64字符串 + /// + public static string ToBase64String(this byte[] bytes) + { + return Convert.ToBase64String(bytes); + } + + /// + /// 将字符串转换为Base64字符串,默认编码为 + /// + /// 正常的字符串 + /// 编码 + /// Base64字符串 + public static string ToBase64String(this string source, Encoding encoding = null) + { + if (encoding == null) + { + encoding = Encoding.UTF8; + } + return Convert.ToBase64String(encoding.GetBytes(source)); + } + + /// + /// 将Base64字符串转换为正常字符串,默认编码为 + /// + /// Base64字符串 + /// 编码 + /// 正常字符串 + public static string FromBase64String(this string base64String, Encoding encoding = null) + { + if (encoding == null) + { + encoding = Encoding.UTF8; + } + byte[] bytes = Convert.FromBase64String(base64String); + return encoding.GetString(bytes); + } + + /// + /// 将字符串进行UrlDecode解码 + /// + /// 待UrlDecode解码的字符串 + /// UrlDecode解码后的字符串 + public static string ToUrlDecode(this string source) + { + return HttpUtility.UrlDecode(source); + } + + /// + /// 将字符串进行UrlEncode编码 + /// + /// 待UrlEncode编码的字符串 + /// UrlEncode编码后的字符串 + public static string ToUrlEncode(this string source) + { + return HttpUtility.UrlEncode(source); + } + + /// + /// 将字符串进行HtmlDecode解码 + /// + /// 待HtmlDecode解码的字符串 + /// HtmlDecode解码后的字符串 + public static string ToHtmlDecode(this string source) + { + return HttpUtility.HtmlDecode(source); + } + + /// + /// 将字符串进行HtmlEncode编码 + /// + /// 待HtmlEncode编码的字符串 + /// HtmlEncode编码后的字符串 + public static string ToHtmlEncode(this string source) + { + return HttpUtility.HtmlEncode(source); + } + + /// + /// 将字符串转换为十六进制字符串,默认编码为 + /// + public static string ToHexString(this string source, Encoding encoding = null) + { + if (encoding == null) + { + encoding = Encoding.UTF8; + } + byte[] bytes = encoding.GetBytes(source); + return bytes.ToHexString(); + } + + /// + /// 将十六进制字符串转换为常规字符串,默认编码为 + /// + public static string FromHexString(this string hexString, Encoding encoding = null) + { + if (encoding == null) + { + encoding = Encoding.UTF8; + } + byte[] bytes = hexString.ToHexBytes(); + return encoding.GetString(bytes); + } + + /// + /// 将byte[]编码为十六进制字符串 + /// + /// byte[]数组 + /// 十六进制字符串 + public static string ToHexString(this byte[] bytes) + { + return bytes.Aggregate(string.Empty, (current, t) => current + t.ToString("X2")); + } + + /// + /// 将十六进制字符串转换为byte[] + /// + /// 十六进制字符串 + /// byte[]数组 + public static byte[] ToHexBytes(this string hexString) + { + hexString = hexString ?? ""; + hexString = hexString.Replace(" ", ""); + byte[] bytes = new byte[hexString.Length / 2]; + for (int i = 0; i < bytes.Length; i++) + { + bytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16); + } + return bytes; + } + + /// + /// 将字符串进行Unicode编码,变成形如“\u7f16\u7801”的形式 + /// + /// 要进行编号的字符串 + public static string ToUnicodeString(this string source) + { + Regex regex = new Regex(@"[^\u0000-\u00ff]"); + return regex.Replace(source, m => string.Format(@"\u{0:x4}", (short)m.Value[0])); + } + + /// + /// 将形如“\u7f16\u7801”的Unicode字符串解码 + /// + public static string FromUnicodeString(this string source) + { + Regex regex = new Regex(@"\\u([0-9a-fA-F]{4})", RegexOptions.Compiled); + return regex.Replace(source, + m => + { + short s; + if (short.TryParse(m.Groups[1].Value, NumberStyles.HexNumber, CultureInfo.InstalledUICulture, out s)) + { + return "" + (char)s; + } + return m.Value; + }); + } + + /// + /// 将驼峰字符串按单词拆分并转换成小写,再以特定字符串分隔 + /// + /// 待转换的字符串 + /// 分隔符字符 + /// + public static string UpperToLowerAndSplit(this string str, string splitStr = "-") + { + if (string.IsNullOrEmpty(str)) + { + return str; + } + List words = new List(); + while (str.Length > 0) + { + char c = str.FirstOrDefault(char.IsUpper); + if (c == default(char)) + { + words.Add(str); + break; + } + int upperIndex = str.IndexOf(c); + if (upperIndex < 0) //admin + { + return str; + } + if (upperIndex > 0) //adminAdmin + { + string first = str.Substring(0, upperIndex); + words.Add(first); + str = str.Substring(upperIndex, str.Length - upperIndex); + continue; + } + str = char.ToLower(str[0]) + str.Substring(1, str.Length - 1); + } + return words.ExpandAndToString(splitStr); + } + + /// + /// 将驼峰字符串的第一个字符小写 + /// + public static string LowerFirstChar(this string str) + { + if (string.IsNullOrEmpty(str) || !char.IsUpper(str[0])) + { + return str; + } + if (str.Length == 1) + { + return char.ToLower(str[0]).ToString(); + } + return char.ToLower(str[0]) + str.Substring(1, str.Length - 1); + } + + /// + /// 将小驼峰字符串的第一个字符大写 + /// + public static string UpperFirstChar(this string str) + { + if (string.IsNullOrEmpty(str) || !char.IsLower(str[0])) + { + return str; + } + if (str.Length == 1) + { + return char.ToUpper(str[0]).ToString(); + } + return char.ToUpper(str[0]) + str.Substring(1, str.Length - 1); + } + + /// + /// 计算当前字符串与指定字符串的编辑距离(相似度) + /// + /// 源字符串 + /// 目标字符串 + /// 输出相似度 + /// 是否忽略大小写 + /// 编辑距离 + public static int LevenshteinDistance(this string source, string target, out double similarity, bool ignoreCase = false) + { + if (string.IsNullOrEmpty(source)) + { + if (string.IsNullOrEmpty(target)) + { + similarity = 1; + return 0; + } + similarity = 0; + return target.Length; + } + if (string.IsNullOrEmpty(target)) + { + similarity = 0; + return source.Length; + } + + string from, to; + if (ignoreCase) + { + from = source; + to = target; + } + else + { + from = source.ToLower(); + to = source.ToLower(); + } + + int m = from.Length, n = to.Length; + int[,] mn = new int[m + 1, n + 1]; + for (int i = 0; i <= m; i++) + { + mn[i, 0] = i; + } + for (int j = 1; j <= n; j++) + { + mn[0, j] = j; + } + for (int i = 1; i <= m; i++) + { + char c = from[i - 1]; + for (int j = 1; j <= n; j++) + { + if (c == to[j - 1]) + { + mn[i, j] = mn[i - 1, j - 1]; + } + else + { + mn[i, j] = Math.Min(mn[i - 1, j - 1], Math.Min(mn[i - 1, j], mn[i, j - 1])) + 1; + } + } + } + + int maxLength = Math.Max(m, n); + similarity = (double)(maxLength - mn[m, n]) / maxLength; + return mn[m, n]; + } + + /// + /// 计算两个字符串的相似度,应用公式:相似度=kq*q/(kq*q+kr*r+ks*s)(kq>0,kr>=0,ka>=0) + /// 其中,q是字符串1和字符串2中都存在的单词的总数,s是字符串1中存在,字符串2中不存在的单词总数,r是字符串2中存在,字符串1中不存在的单词总数. kq,kr和ka分别是q,r,s的权重,根据实际的计算情况,我们设kq=2,kr=ks=1. + /// + /// 源字符串 + /// 目标字符串 + /// 是否忽略大小写 + /// 字符串相似度 + public static double GetSimilarityWith(this string source, string target, bool ignoreCase = false) + { + if (string.IsNullOrEmpty(source) && string.IsNullOrEmpty(target)) + { + return 1; + } + if (string.IsNullOrEmpty(source) || string.IsNullOrEmpty(target)) + { + return 0; + } + const double kq = 2, kr = 1, ks = 1; + char[] sourceChars = source.ToCharArray(), targetChars = target.ToCharArray(); + + //获取交集数量 + int q = sourceChars.Intersect(targetChars).Count(), s = sourceChars.Length - q, r = targetChars.Length - q; + return kq * q / (kq * q + kr * r + ks * s); + } + + #endregion + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Extensions/TypeExtensions.cs b/CloudBuilder/CloudBuilder.Core/Extensions/TypeExtensions.cs new file mode 100644 index 0000000..258aaf3 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Extensions/TypeExtensions.cs @@ -0,0 +1,395 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.Extensions +{ + /// + /// 类型辅助扩展方法类 + /// + public static class TypeExtensions + { + /// + /// 判断当前类型是否可由指定类型派生 + /// + public static bool IsDeriveClassFrom(this Type type, bool canAbstract = false) + { + return IsDeriveClassFrom(type, typeof(TBaseType), canAbstract); + } + + /// + /// 判断当前类型是否可由指定类型派生 + /// + public static bool IsDeriveClassFrom(this Type type, Type baseType, bool canAbstract = false) + { + return type.IsClass && (canAbstract || !type.IsAbstract) && type.IsBaseOn(baseType); + } + + /// + /// 判断类型是否为Nullable类型 + /// + /// 要处理的类型 + /// 是返回True,不是返回False + public static bool IsNullableType(this Type type) + { + return type != null && type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>); + } + + /// + /// 由类型的Nullable类型返回实际类型 + /// + /// 要处理的类型对象 + /// + public static Type GetNonNullableType(this Type type) + { + return IsNullableType(type) ? type.GetGenericArguments()[0] : type; + } + + /// + /// 通过类型转换器获取Nullable类型的基础类型 + /// + /// 要处理的类型对象 + /// + public static Type GetUnNullableType(this Type type) + { + if (IsNullableType(type)) + { + NullableConverter nullableConverter = new NullableConverter(type); + return nullableConverter.UnderlyingType; + } + return type; + } + + /// + /// 获取类型的Description特性描述信息 + /// + /// 类型对象 + /// 是否搜索类型的继承链以查找描述特性 + /// 返回Description特性描述信息,如不存在则返回类型的全名 + public static string GetDescription(this Type type, bool inherit = true) + { + DescriptionAttribute desc = type.GetAttribute(inherit); + return desc == null ? type.FullName : desc.Description; + } + + /// + /// 获取成员元数据的Description特性描述信息 + /// + /// 成员元数据对象 + /// 是否搜索成员的继承链以查找描述特性 + /// 返回Description特性描述信息,如不存在则返回成员的名称 + public static string GetDescription(this MemberInfo member, bool inherit = true) + { + DescriptionAttribute desc = member.GetAttribute(inherit); + if (desc != null) + { + return desc.Description; + } + DisplayNameAttribute displayName = member.GetAttribute(inherit); + if (displayName != null) + { + return displayName.DisplayName; + } + DisplayAttribute display = member.GetAttribute(inherit); + if (display != null) + { + return display.Name; + } + return member.Name; + } + + /// + /// 检查指定指定类型成员中是否存在指定的Attribute特性 + /// + /// 要检查的Attribute特性类型 + /// 要检查的类型成员 + /// 是否从继承中查找 + /// 是否存在 + public static bool HasAttribute(this MemberInfo memberInfo, bool inherit = true) where T : Attribute + { + return memberInfo.IsDefined(typeof(T), inherit); + } + + /// + /// 从类型成员获取指定Attribute特性 + /// + /// Attribute特性类型 + /// 类型类型成员 + /// 是否从继承中查找 + /// 存在返回第一个,不存在返回null + public static T GetAttribute(this MemberInfo memberInfo, bool inherit = true) where T : Attribute + { + var attributes = memberInfo.GetCustomAttributes(typeof(T), inherit); + return attributes.FirstOrDefault() as T; + } + + /// + /// 从类型成员获取指定Attribute特性 + /// + /// Attribute特性类型 + /// 类型类型成员 + /// 是否从继承中查找 + /// 返回所有指定Attribute特性的数组 + public static T[] GetAttributes(this MemberInfo memberInfo, bool inherit = true) where T : Attribute + { + return memberInfo.GetCustomAttributes(typeof(T), inherit).Cast().ToArray(); + } + + /// + /// 判断类型是否为集合类型 + /// + /// 要处理的类型 + /// 是返回True,不是返回False + public static bool IsEnumerable(this Type type) + { + if (type == typeof(string)) + { + return false; + } + return typeof(IEnumerable).IsAssignableFrom(type); + } + + /// + /// 判断当前泛型类型是否可由指定类型的实例填充 + /// + /// 泛型类型 + /// 指定类型 + /// + public static bool IsGenericAssignableFrom(this Type genericType, Type type) + { + genericType.CheckNotNull("genericType"); + type.CheckNotNull("type"); + if (!genericType.IsGenericType) + { + throw new ArgumentException("该功能只支持泛型类型的调用,非泛型类型可使用 IsAssignableFrom 方法。"); + } + + List allOthers = new List { type }; + if (genericType.IsInterface) + { + allOthers.AddRange(type.GetInterfaces()); + } + + foreach (var other in allOthers) + { + Type cur = other; + while (cur != null) + { + if (cur.IsGenericType) + { + cur = cur.GetGenericTypeDefinition(); + } + if (cur.IsSubclassOf(genericType) || cur == genericType) + { + return true; + } + cur = cur.BaseType; + } + } + return false; + } + + /// + /// 方法是否是异步 + /// + public static bool IsAsync(this MethodInfo method) + { + return method.ReturnType == typeof(Task) + || method.ReturnType.IsGenericType && method.ReturnType.GetGenericTypeDefinition() == typeof(Task<>); + } + + /// + /// 返回当前类型是否是指定基类的派生类 + /// + /// 当前类型 + /// 要判断的基类型 + /// + public static bool IsBaseOn(this Type type, Type baseType) + { + if (baseType.IsGenericTypeDefinition) + { + return baseType.IsGenericAssignableFrom(type); + } + return baseType.IsAssignableFrom(type); + } + + /// + /// 返回当前类型是否是指定基类的派生类 + /// + /// 要判断的基类型 + /// 当前类型 + /// + public static bool IsBaseOn(this Type type) + { + Type baseType = typeof(TBaseType); + return type.IsBaseOn(baseType); + } + + /// + /// 返回当前方法信息是否是重写方法 + /// + /// 要判断的方法信息 + /// 是否是重写方法 + public static bool IsOverridden(this MethodInfo method) + { + return method.GetBaseDefinition().DeclaringType != method.DeclaringType; + } + + /// + /// 返回当前属性信息是否为virtual + /// + public static bool IsVirtual(this PropertyInfo property) + { + var accessor = property.GetAccessors().FirstOrDefault(); + if (accessor == null) + { + return false; + } + + return accessor.IsVirtual && !accessor.IsFinal; + } + + /// + /// 获取类型的全名,附带所在类库 + /// + public static string GetFullNameWithModule(this Type type) + { + return $"{type.FullName},{type.Module.Name.Replace(".dll", "").Replace(".exe", "")}"; + } + + /// + /// 获取类型的显示短名称 + /// + public static string ShortDisplayName(this Type type) + { + return type.DisplayName(false); + } + + /// + /// 获取类型的显示名称 + /// + public static string DisplayName([NotNull] this Type type, bool fullName = true) + { + StringBuilder sb = new StringBuilder(); + ProcessType(sb, type, fullName); + return sb.ToString(); + } + + #region 私有方法 + + private static readonly Dictionary _builtInTypeNames = new Dictionary + { + { typeof(bool), "bool" }, + { typeof(byte), "byte" }, + { typeof(char), "char" }, + { typeof(decimal), "decimal" }, + { typeof(double), "double" }, + { typeof(float), "float" }, + { typeof(int), "int" }, + { typeof(long), "long" }, + { typeof(object), "object" }, + { typeof(sbyte), "sbyte" }, + { typeof(short), "short" }, + { typeof(string), "string" }, + { typeof(uint), "uint" }, + { typeof(ulong), "ulong" }, + { typeof(ushort), "ushort" }, + { typeof(void), "void" } + }; + + private static void ProcessType(StringBuilder builder, Type type, bool fullName) + { + if (type.IsGenericType) + { + var genericArguments = type.GetGenericArguments(); + ProcessGenericType(builder, type, genericArguments, genericArguments.Length, fullName); + } + else if (type.IsArray) + { + ProcessArrayType(builder, type, fullName); + } + else if (_builtInTypeNames.TryGetValue(type, out var builtInName)) + { + builder.Append(builtInName); + } + else if (!type.IsGenericParameter) + { + builder.Append(fullName ? type.FullName : type.Name); + } + } + + private static void ProcessArrayType(StringBuilder builder, Type type, bool fullName) + { + var innerType = type; + while (innerType.IsArray) + { + innerType = innerType.GetElementType(); + } + + ProcessType(builder, innerType, fullName); + + while (type.IsArray) + { + builder.Append('['); + builder.Append(',', type.GetArrayRank() - 1); + builder.Append(']'); + type = type.GetElementType(); + } + } + + private static void ProcessGenericType(StringBuilder builder, Type type, Type[] genericArguments, int length, bool fullName) + { + var offset = type.IsNested ? type.DeclaringType.GetGenericArguments().Length : 0; + + if (fullName) + { + if (type.IsNested) + { + ProcessGenericType(builder, type.DeclaringType, genericArguments, offset, fullName); + builder.Append('+'); + } + else + { + builder.Append(type.Namespace); + builder.Append('.'); + } + } + + var genericPartIndex = type.Name.IndexOf('`'); + if (genericPartIndex <= 0) + { + builder.Append(type.Name); + return; + } + + builder.Append(type.Name, 0, genericPartIndex); + builder.Append('<'); + + for (var i = offset; i < length; i++) + { + ProcessType(builder, genericArguments[i], fullName); + if (i + 1 == length) + { + continue; + } + + builder.Append(','); + if (!genericArguments[i + 1].IsGenericParameter) + { + builder.Append(' '); + } + } + + builder.Append('>'); + } + + #endregion + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Policy/AbstractPolicy.cs b/CloudBuilder/CloudBuilder.Core/Policy/AbstractPolicy.cs new file mode 100644 index 0000000..7305271 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Policy/AbstractPolicy.cs @@ -0,0 +1,205 @@ +using CloudBuilder.Core.DependencyInjection.Policy; +using CloudBuilder.Core.DependencyInjection.Request; +using CloudBuilder.Core.Policy; +using CloudBuilder.Core.Service; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Resources; +using System.Text; +using System.Threading.Tasks; + +namespace System +{ + public class AbstractPolicy : IPolicy + { + public ResourceManager rm = null; + + public AbstractPolicy(IContext context) + { + this.context = context; + + string[] res = Assembly.GetAssembly(this.GetType()).GetManifestResourceNames(); + + if (res != null && res.Length > 0) + { + string baseName = this.GetType().Name + "_" + context.GetCulture(); + if (res.Where(x => x.Contains(baseName)).FirstOrDefault() != null) + rm = new ResourceManager(Path.GetFileNameWithoutExtension(res.Where(x => x.Contains(baseName)).FirstOrDefault()), Assembly.GetAssembly(this.GetType())); + else + rm = new ResourceManager(Path.GetFileNameWithoutExtension(res.Where(x => x.Contains(this.GetType().Name)).FirstOrDefault()), Assembly.GetAssembly(this.GetType())); + } + } + protected string[] values = null; + private readonly IContext context; + + public string[] GetValues() { return this.values; } + + public string[] GetMessages() + { + if (values == null || values.Length == 0) return null; + + List messages = new List(); + foreach (string v in values) + { + messages.Add(ComposeMessage(v)); + } + + return messages.ToArray(); + } + + public BindOption[] GetBindOptions() + { + if (values == null || values.Length == 0) return null; + + List messages = new List(); + foreach (string v in values) + { + messages.Add(new BindOption() { BindValue = v, DisplayName = ComposeMessage(v) }); + } + + return messages.ToArray(); + } + + public SelectOption[] GetSelectOptions() + { + if (values == null || values.Length == 0) return null; + + List messages = new List(); + foreach (string v in values) + { + messages.Add(new SelectOption() { BindValue = v, DisplayName = ComposeMessage(v) }); + } + + return messages.ToArray(); + } + + public string ComposeMessage(string msgId, params object[] p) + { + return ComposeMessage(msgId, context.GetCulture(), p); + } + + public string ComposeMessage(string msgId) + { + return ComposeMessage(msgId, context.GetCulture()); + } + + public string ComposeMessage(string msgId, string locale, params object[] p) + { + if (string.IsNullOrEmpty(msgId)) return null; + if (rm == null) return null; + + string[] res = Assembly.GetAssembly(this.GetType()).GetManifestResourceNames(); + string baseName = this.GetType().Name + "_" + locale; + if (res.Where(x => x.Contains(baseName)).FirstOrDefault() != null) + rm = new ResourceManager(Path.GetFileNameWithoutExtension(res.Where(x => x.Contains(baseName)).FirstOrDefault()), Assembly.GetAssembly(this.GetType())); + + if (rm == null) + rm = new ResourceManager(Path.GetFileNameWithoutExtension(res.Where(x => x.Contains(this.GetType().Name)).FirstOrDefault()), Assembly.GetAssembly(this.GetType())); + + return string.Format((string)rm.GetString(msgId), p); + } + + public string ComposeMessage(string msgId, string locale) + { + if (string.IsNullOrEmpty(msgId)) return null; + if (rm == null) return null; + + string[] res = Assembly.GetAssembly(this.GetType()).GetManifestResourceNames(); + + //foreach (var rn in res) + //{ + // Console.WriteLine($"[ManifestResource]={rn}"); + //} + + string baseName = this.GetType().Name + "_" + locale; + //Console.WriteLine($"[locale]={baseName}"); + if (res.Where(x => x.Contains(baseName)).FirstOrDefault() != null) + rm = new ResourceManager(Path.GetFileNameWithoutExtension(res.Where(x => x.Contains(baseName)).FirstOrDefault()), Assembly.GetAssembly(this.GetType())); + + if (rm == null) + rm = new ResourceManager(Path.GetFileNameWithoutExtension(res.Where(x => x.Contains(this.GetType().Name)).FirstOrDefault()), Assembly.GetAssembly(this.GetType())); + + if (rm == null) return null; + + return string.Format((string)rm.GetString(msgId)); + } + + public TableName[] GetTableName(T[] values) + { + if (values == null || values.Length == 0) return null; + TableName tb = null; + List> list = new List>(); + foreach (T v in values) + { + tb = new TableName(); + tb.DisplayName = ComposeMessage(v.ToString(), context.GetCulture()); + tb.Value = v; + list.Add(tb); + } + + return list.ToArray(); + } + + public Dictionary GetDictionary() + { + Dictionary keyValues = new Dictionary(); + foreach (string v in values) + { + keyValues.Add(v, ComposeMessage(v, context.GetCulture())); + } + + return keyValues; + } + + public TableName[] GetComposeMessages(string[] values) + { + if (values == null || values.Length == 0) return null; + TableName tb = null; + List> list = new List>(); + foreach (string v in values) + { + tb = new TableName(); + tb.DisplayName = ComposeMessage(v, context.GetCulture()); + tb.Value = v; + list.Add(tb); + } + + return list.ToArray(); + } + + public TableName[] GetComposeMessages(string[] values, string locale) + { + if (values == null || values.Length == 0) return null; + TableName tb = null; + List> list = new List>(); + foreach (string v in values) + { + tb = new TableName(); + tb.DisplayName = ComposeMessage(v, locale); + tb.Value = v; + list.Add(tb); + } + + return list.ToArray(); + } + + public TableName[] GetComposeMessages() + { + if (values == null || values.Length == 0) return null; + TableName tb = null; + List> list = new List>(); + foreach (string v in values) + { + tb = new TableName(); + tb.DisplayName = ComposeMessage(v, context.GetCulture()); + tb.Value = v; + list.Add(tb); + } + + return list.ToArray(); + } + + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Policy/AuthorizePolicy.cs b/CloudBuilder/CloudBuilder.Core/Policy/AuthorizePolicy.cs new file mode 100644 index 0000000..a9b9d47 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Policy/AuthorizePolicy.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.Policy +{ + public class AuthorizePolicy + { + public const string PERMISSION = "PERMISSION"; + + + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Policy/ClaimPolicy.cs b/CloudBuilder/CloudBuilder.Core/Policy/ClaimPolicy.cs new file mode 100644 index 0000000..7cc1d42 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Policy/ClaimPolicy.cs @@ -0,0 +1,94 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.IdentityModel.JsonWebTokens; +using System; +using System.Collections.Generic; +using System.IdentityModel.Tokens.Jwt; +using System.Linq; +using System.Net.Http; +using System.Security.Claims; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.Policy +{ + public class ClaimPolicy + { + /// + /// 用户Id + /// + public const string CLAINM_USERID = "UserId"; + + /// + /// 账号 + /// + public const string CLAINM_ACCOUNT = "Account"; + + /// + /// 名称 + /// + public const string CLAINM_NAME = "Name"; + + /// + /// 语言 + /// + public const string CLAINM_LOCALE = "zh-cn"; + + public const string ROLE = "Role"; + + public const string BEARER = "Bearer"; + + public const string HEADER_LOCALE = "locale"; + /// + /// 是否超级管理 + /// + public const string CLAINM_SUPERADMIN = "SuperAdmin"; + + /// + /// 租户Id + /// + public const string TENANT_ID = "TenantId"; + + public static string GetClaimValue(IHttpContextAccessor httpContextAccessor, string claimType) + { + string value = string.Empty; + string token = GetJwtBearerToken(httpContextAccessor.HttpContext); + return GetClaimValue(token, claimType); + } + + public static string GetHeaderKeyValue(IHttpContextAccessor httpContextAccessor, string headerKey) + { + if (httpContextAccessor.HttpContext.Request.Headers.Keys.Contains(headerKey)) + { + return httpContextAccessor.HttpContext.Request.Headers[headerKey].ToString(); + } + return string.Empty; + } + + public static string GetClaimValue(string token, string claimType) + { + string value = string.Empty; + if (!string.IsNullOrEmpty(token) && token.Length > 30) + { + JsonWebToken tk = new JsonWebTokenHandler().ReadJsonWebToken(token); + + if (tk == null) { return null; } + + Claim claim = tk.GetClaim(claimType); + if (claim != null) + value = claim.Value; + } + + return value; + } + + public static string GetJwtBearerToken(HttpContext httpContext, string headerKey = "Authorization", string tokenPrefix = "Bearer ") + { + // 判断请求报文头中是否有 "Authorization" 报文头 + var bearerToken = httpContext.Request.Headers[headerKey].ToString(); + if (string.IsNullOrWhiteSpace(bearerToken)) return default; + + var prefixLenght = tokenPrefix.Length; + return bearerToken.StartsWith(tokenPrefix, true, null) && bearerToken.Length > prefixLenght ? bearerToken[prefixLenght..] : default; + } + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Policy/CoreMessagePolicy.cs b/CloudBuilder/CloudBuilder.Core/Policy/CoreMessagePolicy.cs new file mode 100644 index 0000000..a614ff0 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Policy/CoreMessagePolicy.cs @@ -0,0 +1,32 @@ +using CloudBuilder.Core.DependencyInjection.Form; +using CloudBuilder.Core.DependencyInjection.Policy; +using CloudBuilder.Core.DependencyInjection.Request; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.Policy +{ + public class CoreMessagePolicy : AbstractPolicy, IPolicy + { + public const string THE_DATA_HAS_BEEN_MODIFIED = "the_data_has_been_modified"; + public const string NO_PERMISSION = "no_permission"; + + public static CoreMessagePolicy instance = null; + + public CoreMessagePolicy(IContext context) : base(context) + { + this.values = new string[] { THE_DATA_HAS_BEEN_MODIFIED, NO_PERMISSION }; + } + + public static CoreMessagePolicy GetInstance() + { + instance = ApplicationServiceContext.ServiceProvider.GetKeyedService(typeof(CoreMessagePolicy).Name); + return instance; + } + + } +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Core/Policy/CoreMessagePolicy_en.resx b/CloudBuilder/CloudBuilder.Core/Policy/CoreMessagePolicy_en.resx new file mode 100644 index 0000000..89ea833 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Policy/CoreMessagePolicy_en.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + No permission has been assigned. + + + The data has been modified by another user. Please refresh and try again. + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Core/Policy/CoreMessagePolicy_zh-cn.resx b/CloudBuilder/CloudBuilder.Core/Policy/CoreMessagePolicy_zh-cn.resx new file mode 100644 index 0000000..832c2ba --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Policy/CoreMessagePolicy_zh-cn.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 没有分配权限. + + + 数据已被其他用户修改,请刷新后重试. + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Core/Policy/ILocaleMessageManager.cs b/CloudBuilder/CloudBuilder.Core/Policy/ILocaleMessageManager.cs new file mode 100644 index 0000000..f351711 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Policy/ILocaleMessageManager.cs @@ -0,0 +1,18 @@ +using CloudBuilder.Core.DependencyInjection.Request; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.Policy +{ + public interface ILocaleMessageManager + { + void InitLocale(); + + string ComposeMessage(string groupName, string name); + TableName[] GetDataSource(string groupName); + TableName[] GetComposeMessages(string groupName, T[] values); + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Policy/ISecurityMasterManager.cs b/CloudBuilder/CloudBuilder.Core/Policy/ISecurityMasterManager.cs new file mode 100644 index 0000000..e521cb7 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Policy/ISecurityMasterManager.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.Policy +{ + public interface ISecurityMasterManager + { + void InitSecurityMaster(); + + string GetValue(string category, string subcategory, string codeItem); + + dynamic GetSecurityMaster(string category, string subcategory, string codeItem); + + void SetSecurityMaster(string category, string subcategory, string codeItem, string value); + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Policy/LocalePolicy.cs b/CloudBuilder/CloudBuilder.Core/Policy/LocalePolicy.cs new file mode 100644 index 0000000..97532c0 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Policy/LocalePolicy.cs @@ -0,0 +1,128 @@ +using CloudBuilder.Core.DependencyInjection.Policy; +using CloudBuilder.Core.DependencyInjection.Request; +using CloudBuilder.Core.Service; +using Microsoft.EntityFrameworkCore.Metadata.Internal; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Resources; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.Policy +{ + public class LocalePolicy : IPolicy + { + public const string ZH_CN = "zh-cn"; + public const string EN = "en"; + + public LocalePolicy(IContext context, ILocaleMessageManager localeMessageManager) + { + this.context = context; + this.localeMessageManager = localeMessageManager; + } + + protected object[] values = null; + private readonly IContext context; + private readonly ILocaleMessageManager localeMessageManager; + + public string Name { get; set; } = typeof(LocalePolicy).Name; + + public string[] GetValues() { return this.values?.Select(x => x.ToString()).ToArray(); } + + public string[] GetMessages() + { + if (values == null || values.Length == 0) return null; + + List messages = new List(); + foreach (string v in values) + { + messages.Add(ComposeMessage(Name, v)); + } + + return messages.ToArray(); + } + + public BindOption[] GetBindOptions() + { + if (values == null || values.Length == 0) return null; + + List messages = new List(); + foreach (string v in values) + { + messages.Add(new BindOption() { BindValue = v, DisplayName = ComposeMessage(v) }); + } + + return messages.ToArray(); + } + + public SelectOption[] GetSelectOptions() + { + if (values == null || values.Length == 0) return null; + + List messages = new List(); + foreach (string v in values) + { + messages.Add(new SelectOption() { BindValue = v, DisplayName = ComposeMessage(v) }); + } + + return messages.ToArray(); + } + + public string ComposeMessage(string msgId, params object[] p) + { + if (string.IsNullOrEmpty(msgId)) return null; + + string template = localeMessageManager.ComposeMessage(Name, msgId); + + if (string.IsNullOrEmpty(template)) throw new ValidatedException(string.Format("locale:{0}-{1}", Name, msgId)); + + return string.Format(template, p); + } + + public TableName[] GetDataSource() + { + return localeMessageManager.GetDataSource(this.Name); + } + + public Dictionary GetDictionary() + { + Dictionary keyValues = new Dictionary(); + TableName[] tables = localeMessageManager.GetDataSource(this.Name); + foreach (TableName v in tables) + { + keyValues.Add(v.Value, v.DisplayName); + } + + return keyValues; + } + + public TableName[] GetDataSource(Action[]> action) + { + TableName[] tables = localeMessageManager.GetDataSource(this.Name); + if (action != null) + { + action(tables); + } + return tables; + } + + public TableName[] GetComposeMessages() + { + if (values == null || values.Length == 0) return null; + TableName tb = null; + List> list = new List>(); + foreach (T v in values) + { + tb = new TableName(); + tb.DisplayName = ComposeMessage(v.ToString(), context.GetCulture()); + tb.Value = v; + list.Add(tb); + } + + return list.ToArray(); + } + + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Policy/SearchFilterOperatorPolicy.cs b/CloudBuilder/CloudBuilder.Core/Policy/SearchFilterOperatorPolicy.cs new file mode 100644 index 0000000..84f970c --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Policy/SearchFilterOperatorPolicy.cs @@ -0,0 +1,81 @@ +using CloudBuilder.Core.DependencyInjection.Form; +using CloudBuilder.Core.DependencyInjection.Request; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace System +{ + public class SearchFilterOperatorPolicy : AbstractPolicy + { + public const string EQUAL_TO = "equal_to";//='value' + public const string CONTAIN = "contain";//like '%value%' + public const string START_CONTAIN = "start_contain";//like 'value%' + public const string END_CONTAIN = "end_contain";//like '%value' + public const string CN_CONTAIN = "cn_contain";//like N'%value%' + public const string CN_START_CONTAIN = "cn_start_contain";//like 'value%' + public const string CN_END_CONTAIN = "cn_end_contain";//like '%value' + public const string IN_RANGE = "in_range";//in(values) + public const string NOT_IN_RANGE = "not_in_range";//not in(values) + public const string NUMBER_GREATER_THAN = "number_greater_than";//>value + public const string NUMBER_GREATER_THAN_OR_EQUAL_TO = "number_greater_than_or_equal_to";//>=value + public const string NUMBER_LESS_THAN = "number_less_than";//=value && <=value + public const string DATE_BETWEEN = "date_between";//between >=value && <=value + public const string DATETIME_BETWEEN = "datetime_between";//between >=value && <=value + public const string DATE_GREATER_THAN = "date_greater_than";//>value + public const string DATE_GREATER_THAN_OR_EQUAL_TO = "date_greater_than_or_equal_to";//>=value + public const string DATE_LESS_THAN = "date_less_than";//(typeof(SearchFilterOperatorPolicy).Name); + return instance; + } + + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Policy/SearchFilterOperatorPolicy_en.resx b/CloudBuilder/CloudBuilder.Core/Policy/SearchFilterOperatorPolicy_en.resx new file mode 100644 index 0000000..ec4ef7c --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Policy/SearchFilterOperatorPolicy_en.resx @@ -0,0 +1,195 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 数值范围 + + + 包含 + + + 结尾 + + + 包含 + + + 多选 + + + 开始 + + + 包含 + + + 日期范围 + + + 等于 + + + 大于 + + + 大于等于 + + + 小于 + + + 小于等于 + + + 结尾 + + + 等于 + + + 包含 + + + 多选 + + + 不包含 + + + 等于 + + + 大于 + + + 大于等于 + + + 小于 + + + 小于等于 + + + 单选 + + + 开始 + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Core/Policy/SearchFilterOperatorPolicy_zh-cn.resx b/CloudBuilder/CloudBuilder.Core/Policy/SearchFilterOperatorPolicy_zh-cn.resx new file mode 100644 index 0000000..ec4ef7c --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Policy/SearchFilterOperatorPolicy_zh-cn.resx @@ -0,0 +1,195 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 数值范围 + + + 包含 + + + 结尾 + + + 包含 + + + 多选 + + + 开始 + + + 包含 + + + 日期范围 + + + 等于 + + + 大于 + + + 大于等于 + + + 小于 + + + 小于等于 + + + 结尾 + + + 等于 + + + 包含 + + + 多选 + + + 不包含 + + + 等于 + + + 大于 + + + 大于等于 + + + 小于 + + + 小于等于 + + + 单选 + + + 开始 + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Core/Policy/SearchFilterTypePolicy.cs b/CloudBuilder/CloudBuilder.Core/Policy/SearchFilterTypePolicy.cs new file mode 100644 index 0000000..5e00ef3 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Policy/SearchFilterTypePolicy.cs @@ -0,0 +1,40 @@ +using CloudBuilder.Core.DependencyInjection.Form; +using CloudBuilder.Core.DependencyInjection.Request; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace System +{ + public class SearchFilterTypePolicy : AbstractPolicy + { + public const string TEXT = "Text"; + public const string TEXT_CONTAIN = "TextContain"; + public const string NUMBER = "Number"; + public const string DATE = "Date"; + public const string DATETIME = "DateTime"; + public const string MULTIPLE_SELECTION = "MultipleSelection"; + public const string SINGLE_SELECTION = "SingleSelection"; + public const string SEARCH_SINGLE_SELECTION = "SearchSingleSelection"; + public const string MENU_SINGLE_SELECTION = "MenuSingleSelection"; + public const string CHECKBOX = "Checkbox"; + public const string CHECKBOX_GROUP = "CheckboxGroup"; + public const string RADIO_GROUP = "RadioGroup"; + + public static SearchFilterTypePolicy instance = null; + + public SearchFilterTypePolicy(IContext context) : base(context) + { + this.values = new string[] { TEXT, TEXT_CONTAIN, NUMBER, DATE, DATETIME, MULTIPLE_SELECTION, SINGLE_SELECTION }; + } + + public static SearchFilterTypePolicy GetInstance() + { + instance = ApplicationServiceContext.ServiceProvider.GetKeyedService(typeof(SearchFilterTypePolicy).Name); + return instance; + } + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Policy/SearchFilterTypePolicy_en.resx b/CloudBuilder/CloudBuilder.Core/Policy/SearchFilterTypePolicy_en.resx new file mode 100644 index 0000000..21f164d --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Policy/SearchFilterTypePolicy_en.resx @@ -0,0 +1,156 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 单复选 + + + 多组复选 + + + 日期范围 + + + 时间范围 + + + 单选(可填) + + + 多选 + + + 数字 + + + 单选框 + + + 单选(过滤) + + + 单选 + + + 文本 + + + 文本(包含) + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Core/Policy/SearchFilterTypePolicy_zh-cn.resx b/CloudBuilder/CloudBuilder.Core/Policy/SearchFilterTypePolicy_zh-cn.resx new file mode 100644 index 0000000..21f164d --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Policy/SearchFilterTypePolicy_zh-cn.resx @@ -0,0 +1,156 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 单复选 + + + 多组复选 + + + 日期范围 + + + 时间范围 + + + 单选(可填) + + + 多选 + + + 数字 + + + 单选框 + + + 单选(过滤) + + + 单选 + + + 文本 + + + 文本(包含) + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Core/Policy/SecurityMasterPolicy.cs b/CloudBuilder/CloudBuilder.Core/Policy/SecurityMasterPolicy.cs new file mode 100644 index 0000000..9cb654a --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Policy/SecurityMasterPolicy.cs @@ -0,0 +1,58 @@ +using CloudBuilder.Core.DependencyInjection.Policy; +using CloudBuilder.Core.DependencyInjection.Request; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; + +namespace CloudBuilder.Core.Policy +{ + public class SecurityMasterPolicy : IPolicy + { + public string Namespace { get; set; } = typeof(SecurityMasterPolicy).Namespace; + + public string Name { get; set; } = typeof(SecurityMasterPolicy).Name; + + private readonly IContext context; + private readonly ISecurityMasterManager securityMasterManager; + public SecurityMasterPolicy(IContext context, ISecurityMasterManager securityMasterManager) + { + this.context = context; + this.securityMasterManager = securityMasterManager; + } + + public dynamic GetSecurityMaster(string codeItem) + { + return securityMasterManager.GetSecurityMaster(Namespace, Name, codeItem); + } + + public string GetValue(string codeItem) + { + return securityMasterManager.GetValue(Namespace, Name, codeItem); + } + + public dynamic GetDefaultValue(string codeItem, T t) + { + string value = securityMasterManager.GetValue(Namespace, Name, codeItem); + if (value == null) + { + securityMasterManager.SetSecurityMaster(Namespace, Name, codeItem, t.ToString()); + securityMasterManager.InitSecurityMaster(); + return t; + } + + if (t is string) return value; + + else if (t is int) return Convert.ToInt32(value); + + else if (t is decimal) return Convert.ToDecimal(value); + + else if (t is DateTime) return Convert.ToDateTime(value); + + return value; + } + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Policy/YesNoPolicy.cs b/CloudBuilder/CloudBuilder.Core/Policy/YesNoPolicy.cs new file mode 100644 index 0000000..ff6c6b7 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Policy/YesNoPolicy.cs @@ -0,0 +1,38 @@ + +using CloudBuilder.Core.DependencyInjection.Form; +using CloudBuilder.Core.DependencyInjection.Request; +using CloudBuilder.Core.Policy; +using Microsoft.Extensions.DependencyInjection; + +namespace System +{ + public class YesNoPolicy : AbstractPolicy + { + public const string YES = "Y"; + public const string NO = "N"; + + public static YesNoPolicy instance = null; + + public YesNoPolicy(IContext context) : base(context) + { + this.values = new string[] { YES, NO }; + } + + public static YesNoPolicy GetInstance() + { + instance = ApplicationServiceContext.ServiceProvider.GetKeyedService(typeof(YesNoPolicy).Name); + return instance; + } + + public static bool IsYes(string value) + { + return value == YES; + } + + public static string IsChecked(string value) + { + if (value == YES) return "checked"; + return null; + } + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Policy/YesNoPolicy_en.resx b/CloudBuilder/CloudBuilder.Core/Policy/YesNoPolicy_en.resx new file mode 100644 index 0000000..649094b --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Policy/YesNoPolicy_en.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + No + + + Yes + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Core/Policy/YesNoPolicy_zh-cn.resx b/CloudBuilder/CloudBuilder.Core/Policy/YesNoPolicy_zh-cn.resx new file mode 100644 index 0000000..ca4600e --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Policy/YesNoPolicy_zh-cn.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 否 + + + 是 + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Core/ReadMe.md b/CloudBuilder/CloudBuilder.Core/ReadMe.md new file mode 100644 index 0000000..34b388c --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/ReadMe.md @@ -0,0 +1,11 @@ +1.注入构建容器:CloudBuilderBuilder + services.AddCloudBuilder(); + 由CloudBuilderBuilder自动注入各模块:CloudBuilderPack + builder.AddCorePack(); + //注入配置选项... + builder.AddOptions(configuration); + 注入各模块CloudBuilder核心模块 + builder.AddPack(); + +2.public dynamic FindByKey(Int32 key) +JSON.stringify({"key":1}) \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Core/Report/DataToExcelHelper.cs b/CloudBuilder/CloudBuilder.Core/Report/DataToExcelHelper.cs new file mode 100644 index 0000000..acabc75 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Report/DataToExcelHelper.cs @@ -0,0 +1,398 @@ +using ClosedXML.Excel; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using CloudBuilder.Core.Extensions; +using CloudBuilder.Core.Service; +using DocumentFormat.OpenXml.Spreadsheet; +using DocumentFormat.OpenXml; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using System.Data.SqlTypes; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using System.Diagnostics; + +namespace CloudBuilder.Core.Report +{ + public class DataToExcelHelper + { + private readonly IApplicationService service; + public delegate object DataValueFormatOperation(string functionName, object value); + public delegate void CellTypeFormatOperation(IXLWorksheet xLWorksheet, string functionName, object cellValue, int rowIndex, int ColIndex, T[] datas); + public delegate void XLWorksheetOperation(IXLWorksheet xLWorksheet, T[] datas); + public DataToExcelHelper(IApplicationService service) + { + this.service = service; + } + + public IActionResult ToExcel(T[] datas) + { + using (var excel = new XLWorkbook()) + { + IXLWorksheet worksheet = GetExcelWorksheet(excel, datas); + + using (MemoryStream stream = new MemoryStream()) + { + excel.SaveAs(stream); + return new FileStreamResult(stream, + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" + ); + } + } + } + + public IXLWorksheet GetExcelWorksheet(XLWorkbook excel, T[] datas) + { + string tableName = typeof(T).GetCustomAttributeValue(x => x.Name); + + List headers = new List(); + PropertyInfo[] pArray = typeof(T).GetProperties(); + + string format = null; + foreach (PropertyInfo p in pArray) + { + object value = p.GetType(); + format = string.Empty; + if (value is DateTime || p.PropertyType.FullName.ToLower().Contains("datetime")) + { + format = TemplateHeader.DateTimeFormat1; + } + else if (value is int || p.PropertyType.FullName.ToLower().Contains("int")) + { + format = TemplateHeader.IntFormat1; + } + else if (value is decimal || p.PropertyType.FullName.ToLower().Contains("decimal")) + { + format = TemplateHeader.DecimalFormat1; + } + + //DatabaseGeneratedOption option = typeof(StockOrderEntity).GetCustomAttributeValue(x => x.DatabaseGeneratedOption, p.Name); + //if (option == DatabaseGeneratedOption.Identity) + //{ + // continue; + //} + + string displayName = typeof(T).GetCustomAttributeValue(x => x.Name, p.Name); + if (string.IsNullOrEmpty(displayName)) continue; + + headers.Add(new TemplateHeader + { + DisplayName = displayName, + BindingName = p.Name, + Format = format, + Width = TemplateHeader.WidthAutoFit + }); + } + + return PackWorksheet(excel, tableName, tableName, null, headers.ToArray(), datas, null); + } + + public IActionResult ToExcel(string worksheetName, string title, TemplateHeader[] headers, T[] datas) + { + return ToExcel(worksheetName, title, null, headers, datas, null); + } + + public IActionResult ToExcel(string worksheetName, string title, List subTitle, TemplateHeader[] headers, T[] datas) + { + return ToExcel(worksheetName, title, subTitle, headers, datas, null); + } + + public IActionResult ToExcel(string worksheetName, string title, TemplateHeader[] headers, T[] datas, Dictionary> mappings) + { + return ToExcel(worksheetName, title, null, headers, datas, mappings); + } + + public IActionResult ToExcel(string worksheetName, string title, List subTitle, TemplateHeader[] headers, T[] datas, Dictionary> mappings) + { + return ToExcel(worksheetName, title, subTitle, headers, datas, mappings, null!, null!, null!); + } + public IActionResult ToExcel(string worksheetName, string title, List subTitle, TemplateHeader[] headers, T[] datas, Dictionary> mappings, DataValueFormatOperation dataValueOperation) + { + return ToExcel(worksheetName, title, subTitle, headers, datas, mappings, dataValueOperation, null!, null!); + } + + public IActionResult ToExcel(string worksheetName, string title, List subTitle, TemplateHeader[] headers, T[] datas, Dictionary> mappings, DataValueFormatOperation dataValueOperation, + CellTypeFormatOperation cellOperation) + { + return ToExcel(worksheetName, title, subTitle, headers, datas, mappings, dataValueOperation, cellOperation, null!); + } + + public IActionResult ToExcel(string worksheetName, string title, List subTitle, TemplateHeader[] headers, T[] datas, Dictionary> mappings, DataValueFormatOperation dataValueOperation, + CellTypeFormatOperation cellOperation, XLWorksheetOperation xLWorksheetOperation) + { + string path = ToExcelFile(worksheetName, title, subTitle, headers, datas, mappings, dataValueOperation, cellOperation, xLWorksheetOperation); + + var stream = System.IO.File.OpenRead(path); + + return new FileStreamResult(stream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + } + + public void PrintExcel(string worksheetName, string title, TemplateHeader[] headers, T[] datas) + { + PrintExcel(worksheetName, title, null!, headers, datas, null!, null!, null!, null!); + } + + public void PrintExcel(string worksheetName, string title, List subTitle, TemplateHeader[] headers, T[] datas) + { + PrintExcel(worksheetName, title, subTitle, headers, datas, null!, null!, null!, null!); + } + + public void PrintExcel(string worksheetName, string title, List subTitle, TemplateHeader[] headers, T[] datas, Dictionary> mappings) + { + PrintExcel(worksheetName, title, subTitle, headers, datas, mappings, null!, null!, null!); + } + public void PrintExcel(string worksheetName, string title, List subTitle, TemplateHeader[] headers, T[] datas, Dictionary> mappings, DataValueFormatOperation dataValueOperation) + { + PrintExcel(worksheetName, title, subTitle, headers, datas, mappings, dataValueOperation, null!, null!); + } + + public void PrintExcel(string worksheetName, string title, List subTitle, TemplateHeader[] headers, T[] datas, Dictionary> mappings, DataValueFormatOperation dataValueOperation, +CellTypeFormatOperation cellOperation) + { + PrintExcel(worksheetName, title, subTitle, headers, datas, mappings, dataValueOperation, cellOperation, null!); + } + + public void PrintExcel(string worksheetName, string title, List subTitle, TemplateHeader[] headers, T[] datas, Dictionary> mappings, DataValueFormatOperation dataValueOperation, +CellTypeFormatOperation cellOperation, XLWorksheetOperation xLWorksheetOperation) + { + string fileFullname = ToExcelFile(worksheetName, title, subTitle, headers, datas, mappings, dataValueOperation, cellOperation, xLWorksheetOperation); + + Process.Start(new ProcessStartInfo + { + FileName = fileFullname, + UseShellExecute = true // 使用Windows Shell执行 + }); + } + + public string ToExcelFile(string worksheetName, string title, List subTitle, TemplateHeader[] headers, T[] datas, Dictionary> mappings, DataValueFormatOperation dataValueOperation, + CellTypeFormatOperation cellOperation, XLWorksheetOperation xLWorksheetOperation) + { + string tempPath = Path.GetTempPath() + $"{DateTime.Now.ToString("yyyyMMdd")}"; + + if (!Directory.Exists(tempPath)) Directory.CreateDirectory(tempPath); + + string fileFullname = Path.Combine(tempPath, worksheetName.Replace(" ", "") + $"{DateTime.Now.ToString("yyyyMMddHHmmssffff")}.xlsx"); + + if (service != null) + { + fileFullname = Path.Combine(service.Configuration["FileServiceSettings:ExcelOutputDirectory"], $"{DateTime.Now.ToString("yyyyMMdd")}", typeof(T).Name + $"{DateTime.Now.ToString("yyyyMMddHHmmssffff")}.xlsx"); + } + + using (var excel = new XLWorkbook()) + { + if (string.IsNullOrEmpty(worksheetName)) worksheetName = "Report"; + + PackWorksheet(excel, worksheetName, title, subTitle, headers, datas, mappings, dataValueOperation, cellOperation, xLWorksheetOperation); + excel.SaveAs(fileFullname); + } + + return fileFullname; + } + + public IXLWorksheet PackWorksheet(XLWorkbook excel, string worksheetName, string title, List subTitle, TemplateHeader[] headers, T[] datas, Dictionary> mappings) + { + return PackWorksheet(excel, worksheetName, title, subTitle, headers, datas, mappings, null!, null!, null!); + } + + public IXLWorksheet PackWorksheet(XLWorkbook excel, string worksheetName, string title, List subTitle, TemplateHeader[] headers, T[] datas, Dictionary> mappings, DataValueFormatOperation dataValueOperation) + { + return PackWorksheet(excel, worksheetName, title, subTitle, headers, datas, mappings, dataValueOperation, null!, null!); + } + + public IXLWorksheet PackWorksheet(XLWorkbook excel, string worksheetName, string title, List subTitle, TemplateHeader[] headers, T[] datas, Dictionary> mappings, DataValueFormatOperation dataValueOperation, + CellTypeFormatOperation cellOperation) + { + return PackWorksheet(excel, worksheetName, title, subTitle, headers, datas, mappings, dataValueOperation, cellOperation, null!); + } + + public IXLWorksheet PackWorksheet(XLWorkbook excel, string worksheetName, string title, List subTitle, TemplateHeader[] headers, T[] datas, Dictionary> mappings, DataValueFormatOperation dataValueOperation, + CellTypeFormatOperation cellOperation, XLWorksheetOperation xLWorksheetOperation) + { + List ExportDatas = new List(); + int rowIndex = 1; + var worksheet = excel.Worksheets.Add(worksheetName); + + List headerNames = new List(); + int i = 1; + foreach (TemplateHeader header in headers) + { + if (!string.IsNullOrEmpty(header.Format)) + worksheet.Column(i).Style.NumberFormat.Format = header.Format; + worksheet.Column(i).Width = header.DisplayName.Length * 1.5; + if (header.Width > 0) + worksheet.Column(i).Width = header.Width; + + headerNames.Add(header.DisplayName); + i++; + } + + worksheet.Row(rowIndex).Style.Font.FontSize = 20; + worksheet.Row(rowIndex).Height = 30; + worksheet.Range(rowIndex, 1, rowIndex, headers.Length).Merge(); + worksheet.Cell(rowIndex++, 1).Value = title; + + //空行 + rowIndex++; + worksheet.Row(rowIndex).Height = 20; + + if (subTitle != null && subTitle.Count > 0) + { + + foreach (string st in subTitle) + { + worksheet.Range(rowIndex, 1, rowIndex, headers.Length).Merge(); + worksheet.Cell(rowIndex++, 1).Value = st; + } + + //空行 + rowIndex++; + } + + //設置列名 + var listOfList = new List>(); + listOfList.Add(headerNames); + worksheet.Cell(rowIndex++, 1).InsertData(listOfList); + object[] rowData; + + int dataIndex = rowIndex; + + //Handle on empty dataset + var listOfArr = new List(); + if (datas != null && datas.Length > 0) + { + //綁定明細 + var t = datas[0].GetType(); + //里面是所有公共属性 + PropertyInfo[] pArray = t.GetProperties(); + + foreach (T d in datas) + { + rowData = new object[headers.Length]; + i = 0; + foreach (TemplateHeader header in headers) + { + rowData[i] = null; + Array.ForEach(pArray, p => + { + if (header.BindingName == p.Name) + { + object value = p.GetValue(d); + if (value == null || value == DBNull.Value) + { + rowData[i] = null; + } + else if (header.DataValueFormatName != null && dataValueOperation != null) + { + rowData[i] = dataValueOperation(header.DataValueFormatName, value); + } + else if (value is DateTime) + { + if (value == DBNull.Value) + { + rowData[i] = null; + } + else if (((DateTime)value).Year > 1900) + rowData[i] = (DateTime)value; + } + else if (value is SqlDateTime) + { + if (!((SqlDateTime)value).IsNull) + { + if (((SqlDateTime)value).Value.Year > 1900) + rowData[i] = ((SqlDateTime)value).Value; + } + else + { + rowData[i] = null; + } + } + else + { + if (mappings != null && mappings.ContainsKey(header.BindingName)) + { + if (mappings[header.BindingName].ContainsKey((string)value)) + rowData[i] = mappings[header.BindingName][(string)value]; + else + rowData[i] = value; + } + else + rowData[i] = value; + } + } + }); + + i++; + } + + listOfArr.Add(rowData); + + } + } + + worksheet.Cell(rowIndex++, 1).InsertData(listOfArr); + + if (datas != null && datas.Length > 0) + { + foreach (T d in datas) + { + i = 1; + foreach (TemplateHeader header in headers) + { + if (header.CellTypeFormatName != null) + cellOperation(worksheet, header.CellTypeFormatName, d, dataIndex, i, datas); + + i++; + } + + dataIndex++; + } + } + + rowIndex = rowIndex + listOfArr.Count(); + + // 3 is title line + space line + header line + int headerRow = 3 + (subTitle == null || subTitle.Count == 0 ? 0 : subTitle.Count + 1); + + worksheet.Range(headerRow, 1, headerRow, headers.Length).Style.Fill.PatternType = XLFillPatternValues.Solid; + worksheet.Range(headerRow, 1, headerRow, headers.Length).Style.Fill.SetBackgroundColor(XLColor.Silver); + var range = worksheet.Range(headerRow, 1, headerRow + datas.Length, headers.Length); + + range.Style.Border.TopBorder = XLBorderStyleValues.Thin; + range.Style.Border.BottomBorder = XLBorderStyleValues.Thin; + range.Style.Border.LeftBorder = XLBorderStyleValues.Thin; + range.Style.Border.RightBorder = XLBorderStyleValues.Thin; + range.Style.Alignment.WrapText = true; + range.Style.Alignment.Vertical = XLAlignmentVerticalValues.Top; + + + i = 1; + foreach (TemplateHeader header in headers) + { + if (header.Width == TemplateHeader.WidthAutoFit) + worksheet.Column(i).AdjustToContents(headerRow, headerRow + datas.Length, 10, 100); + i++; + } + + if (xLWorksheetOperation != null) + xLWorksheetOperation(worksheet, datas); + + return worksheet; + } + + private enum ExportDisplayStyle { Header, Subtotal, Detail, Total }; + private class ExportRow + { + public object[] values; + public ExportDisplayStyle displayStyle; + public ExportRow(object[] values, ExportDisplayStyle displayStyle) + { + this.values = values; + this.displayStyle = displayStyle; + } + } + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Request/HttpRequest.cs b/CloudBuilder/CloudBuilder.Core/Request/HttpRequest.cs new file mode 100644 index 0000000..eeca91a --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Request/HttpRequest.cs @@ -0,0 +1,22 @@ +using CloudBuilder.Core.DependencyInjection.Request; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.Request +{ + public class HttpRequest : IRequest + { + private HttpClient request; + + public HttpRequest(HttpClient request) + { + this.request = request; + } + + public HttpClient GetHttpClient() { return request; } + + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Request/IServiceRequest.cs b/CloudBuilder/CloudBuilder.Core/Request/IServiceRequest.cs new file mode 100644 index 0000000..aa47bac --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Request/IServiceRequest.cs @@ -0,0 +1,48 @@ + +using CloudBuilder.Core.DependencyInjection.Request; +using CloudBuilder.Core.Policy; +using CloudBuilder.Core.Service; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http.Headers; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.Request +{ + public interface IServiceRequest : IRequest + { + void SetToken(string token); + + void SetCulture(string culture); + + void SetToken(); + + Task GetAsync(string api); + + Task GetWithQueryAsync(string api, Dictionary queryParams); + + Task GetWithHeadersAsync(string api, Dictionary headers); + + Task GetWithHeadersAndQueryAsync(string api, Dictionary headers, Dictionary queryParams); + + Task PostAsJsonAsync(string api, T data); + Task PostAsJsonAsync(string api, Dictionary headers, T data); + Task PostAsJsonAsync(string api, Dictionary headers); + Task PostAsJsonAsync(string api); + + Task PostAsync(string api); + + void DownloadFile(string api, string filePath, Action progressCallback, Action completedCallback); + + Task PostAsync(string api, MultipartFormDataContent data); + + Task PostStreamAsync(string api, Dictionary headers, T data); + + void AddHeaders(string name, string? value); + void SetContext(IContext loginContext); + HttpClient GetHttpClient(); + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Request/ServiceRequest.cs b/CloudBuilder/CloudBuilder.Core/Request/ServiceRequest.cs new file mode 100644 index 0000000..9b6ec9b --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Request/ServiceRequest.cs @@ -0,0 +1,459 @@ +using CloudBuilder.Core.DependencyInjection.Request; +using CloudBuilder.Core.Policy; +using CloudBuilder.Core.Service; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; +using System.Net.Http.Headers; +using System.Net.Http.Json; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +/* +注意是否是全局作用域(winform如果没有加入局部作用域,则都是全局作用域) +全局作用域: +using (var scope1 = ServiceProvider.CreateScope()) +{ + YesNoPolicyRequest yesNoPolicyRequest = ServiceProvider.GetRequiredKeyedService(typeof(YesNoPolicyRequest).Name); + SelectOption[] selectOptions = yesNoPolicyRequest.FindSelectOption(true); +} + */ + +namespace CloudBuilder.Core.Request +{ + public class ServiceRequest : IServiceRequest + { + private readonly HttpClient request; + private readonly IConfiguration configuration; + private readonly IServiceProvider provider; + private readonly IContext loginContext; + private JsonSerializerSettings _jsonSettings; + + public ServiceRequest(HttpClient request, IConfiguration configuration, IServiceProvider provider) + { + this.request = request; + this.configuration = configuration; + this.provider = provider; + this.loginContext = provider.GetService()!; + this.request.BaseAddress = new Uri(this.configuration.GetValue("CloudBuilder:ServiceRequest:BaseAddress")!); + this.request.DefaultRequestHeaders.Add("Accept", this.configuration.GetValue("CloudBuilder:ServiceRequest:DefaultRequestHeaders:Accept")); + + this.request.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", loginContext.GetToken()); + + if (this.request.DefaultRequestHeaders.Contains(ClaimPolicy.HEADER_LOCALE)) + this.request.DefaultRequestHeaders.Remove(ClaimPolicy.HEADER_LOCALE); + this.request.DefaultRequestHeaders.Add(ClaimPolicy.HEADER_LOCALE, loginContext.GetCulture()); + + _jsonSettings = new JsonSerializerSettings + { + NullValueHandling = NullValueHandling.Ignore, + ContractResolver = new DefaultContractResolver(), + ReferenceLoopHandling = ReferenceLoopHandling.Ignore, + DateFormatString = "yyyy-MM-dd HH:mm:ss" + }; + } + + public void SetToken(string token) + { + loginContext.SetToken(token); + this.request.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); + } + + public void SetCulture(string culture) + { + loginContext.SetCulture(culture); + if (this.request.DefaultRequestHeaders.Contains(ClaimPolicy.HEADER_LOCALE)) + this.request.DefaultRequestHeaders.Remove(ClaimPolicy.HEADER_LOCALE); + this.request.DefaultRequestHeaders.Add(ClaimPolicy.HEADER_LOCALE, culture); + } + + public void SetToken() + { + //如果后面工程注入IContext服務对象,那么就会取出GetToken(),如果为空,防止后面工程沒有注入會出錯。 + IContext loginContext = provider.GetService()!; + + if (loginContext != null) + { + this.request.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", loginContext.GetToken()); + } + } + + public async Task GetAsync(string api) + { + return await GetWithHeadersAndQueryAsync(api, null!, null!); + } + + public async Task GetWithQueryAsync(string api, Dictionary queryParams) + { + return await GetWithHeadersAndQueryAsync(api, null!, queryParams); + } + + public async Task GetWithHeadersAsync(string api, Dictionary headers) + { + return await GetWithHeadersAndQueryAsync(api, headers, null!); + } + + public async Task GetWithHeadersAndQueryAsync(string api, Dictionary headers, Dictionary queryParams) + { + string url = api; + if (queryParams != null && queryParams.Count > 0) + { + List query = new List(); + + foreach (var param in queryParams) + { + query.Add(string.Format("{0}={1}", param.Key, param.Value)); + } + + url = api + "?" + QuotedString.ToDelimiteredList(query.ToArray(), '&'); + } + + if (headers != null && headers.Count > 0) + { + foreach (var header in headers) + { + if (request.DefaultRequestHeaders.Contains(header.Key)) request.DefaultRequestHeaders.Remove(header.Key); + request.DefaultRequestHeaders.Add(header.Key, header.Value); + } + } + + this.request.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", loginContext.GetToken()); + + if (request.DefaultRequestHeaders.Contains(ClaimPolicy.HEADER_LOCALE)) + request.DefaultRequestHeaders.Remove(ClaimPolicy.HEADER_LOCALE); + request.DefaultRequestHeaders.Add(ClaimPolicy.HEADER_LOCALE, loginContext.GetCulture()); + + var response = await request.GetAsync(url, HttpCompletionOption.ResponseHeadersRead); + /* + await request.GetAsync(url, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false) + 如果在此处加入ConfigureAwait(false),返回是数组就会出错。 + 要将ConfigureAwait(false)这个方法放入到下面语句 + var responseJson = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + */ + if (!response.IsSuccessStatusCode) + { + var responseContext = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + string errors = string.Empty; + if (responseContext != null && responseContext.StartsWith("{\"errors\"")) errors = responseContext.Substring(11, responseContext.IndexOf("}") - 11); + + if (response.ReasonPhrase == "Forbidden") + throw new Exception(string.Format("{0}", CoreMessagePolicy.GetInstance().ComposeMessage(CoreMessagePolicy.NO_PERMISSION))); + + throw new Exception(string.Format("{0}{1}", response.ReasonPhrase, string.IsNullOrEmpty(errors) ? "" : "\r\n" + errors)); + } + + response.EnsureSuccessStatusCode(); + + var responseJson = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + + CheckException(responseJson); + + return JsonConvert.DeserializeObject(responseJson, _jsonSettings)!; + } + + public async Task PostAsJsonAsync(string api, T data) + { + return await PostAsJsonAsync(api, null!, data); + } + public async Task PostAsJsonAsync(string api, Dictionary headers, T data) + { + if (headers != null && headers.Count > 0) + { + foreach (var header in headers) + { + if (request.DefaultRequestHeaders.Contains(header.Key)) request.DefaultRequestHeaders.Remove(header.Key); + request.DefaultRequestHeaders.Add(header.Key, header.Value); + } + } + + this.request.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", loginContext.GetToken()); + + if (request.DefaultRequestHeaders.Contains(ClaimPolicy.HEADER_LOCALE)) + request.DefaultRequestHeaders.Remove(ClaimPolicy.HEADER_LOCALE); + request.DefaultRequestHeaders.Add(ClaimPolicy.HEADER_LOCALE, loginContext.GetCulture()); + + var options = new JsonSerializerOptions + { + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull + }; + + var response = await this.request.PostAsJsonAsync(api, data, options); + + if (!response.IsSuccessStatusCode) + { + //{"errors":{},"type":"https://tools.ietf.org/html/rfc9110#section-15.5.1","title":"One or more validation errors occurred.","status":400,"traceId":"00-64ad066978f4471cb3c9ce219c213da9-bccca8afd14676b3-00"} + var responseContext = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + string errors = string.Empty; + if (responseContext != null && responseContext.StartsWith("{\"errors\"")) errors = responseContext.Substring(11, responseContext.IndexOf("}") - 11); + + if (response.ReasonPhrase == "Forbidden") + throw new Exception(string.Format("{0}", CoreMessagePolicy.GetInstance().ComposeMessage(CoreMessagePolicy.NO_PERMISSION))); + + throw new Exception(string.Format("{0}{1}", response.ReasonPhrase, string.IsNullOrEmpty(errors) ? "" : "\r\n" + errors)); + } + + response.EnsureSuccessStatusCode(); + + var responseJson = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + + CheckException(responseJson); + + return JsonConvert.DeserializeObject(responseJson, _jsonSettings)!; + } + + private void CheckException(string responseJson) + { + if (string.IsNullOrEmpty(responseJson) || !responseJson.StartsWith("{\"SourceCode\":\"CloudBuilder.Core.")) return; + + if (responseJson.StartsWith("{\"SourceCode\":\"CloudBuilder.Core.ValidatedException")) + { + ValidatedException vex = JsonConvert.DeserializeObject(responseJson, _jsonSettings)!; + throw vex; + } + else if (responseJson.StartsWith("{\"SourceCode\":\"CloudBuilder.Core.ServiceErrorException")) + { + ServiceErrorException sex = JsonConvert.DeserializeObject(responseJson, _jsonSettings)!; + throw sex; + } + } + + public async Task PostAsJsonAsync(string api, Dictionary headers) + { + if (headers != null && headers.Count > 0) + { + foreach (var header in headers) + { + if (request.DefaultRequestHeaders.Contains(header.Key)) request.DefaultRequestHeaders.Remove(header.Key); + request.DefaultRequestHeaders.Add(header.Key, header.Value); + } + } + + this.request.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", loginContext.GetToken()); + + if (request.DefaultRequestHeaders.Contains(ClaimPolicy.HEADER_LOCALE)) + request.DefaultRequestHeaders.Remove(ClaimPolicy.HEADER_LOCALE); + request.DefaultRequestHeaders.Add(ClaimPolicy.HEADER_LOCALE, loginContext.GetCulture()); + + var response = await this.request.PostAsync(api, null!); + + if (!response.IsSuccessStatusCode) + { + var responseContext = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + string errors = string.Empty; + if (responseContext != null && responseContext.StartsWith("{\"errors\"")) errors = responseContext.Substring(11, responseContext.IndexOf("}") - 11); + + if (response.ReasonPhrase == "Forbidden") + throw new Exception(string.Format("{0}", CoreMessagePolicy.GetInstance().ComposeMessage(CoreMessagePolicy.NO_PERMISSION))); + + throw new Exception(string.Format("{0}{1}", response.ReasonPhrase, string.IsNullOrEmpty(errors) ? "" : "\r\n" + errors)); + } + + response.EnsureSuccessStatusCode(); + + var responseJson = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + + CheckException(responseJson); + + return JsonConvert.DeserializeObject(responseJson, _jsonSettings)!; + } + + public async Task PostAsJsonAsync(string api) + { + this.request.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", loginContext.GetToken()); + + if (request.DefaultRequestHeaders.Contains(ClaimPolicy.HEADER_LOCALE)) + request.DefaultRequestHeaders.Remove(ClaimPolicy.HEADER_LOCALE); + request.DefaultRequestHeaders.Add(ClaimPolicy.HEADER_LOCALE, loginContext.GetCulture()); + + var response = await this.request.PostAsync(api, new StringContent(string.Empty)); + + if (!response.IsSuccessStatusCode) + { + var responseContext = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + string errors = string.Empty; + if (responseContext != null && responseContext.StartsWith("{\"errors\"")) errors = responseContext.Substring(11, responseContext.IndexOf("}") - 11); + + if (response.ReasonPhrase == "Forbidden") + throw new Exception(string.Format("{0}", CoreMessagePolicy.GetInstance().ComposeMessage(CoreMessagePolicy.NO_PERMISSION))); + + throw new Exception(string.Format("{0}{1}", response.ReasonPhrase, string.IsNullOrEmpty(errors) ? "" : "\r\n" + errors)); + } + + response.EnsureSuccessStatusCode(); + + var responseJson = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + + CheckException(responseJson); + + return JsonConvert.DeserializeObject(responseJson, _jsonSettings)!; + } + + public async Task PostAsync(string api) + { + this.request.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", loginContext.GetToken()); + + if (request.DefaultRequestHeaders.Contains(ClaimPolicy.HEADER_LOCALE)) + request.DefaultRequestHeaders.Remove(ClaimPolicy.HEADER_LOCALE); + request.DefaultRequestHeaders.Add(ClaimPolicy.HEADER_LOCALE, loginContext.GetCulture()); + + var response = await this.request.PostAsync(api, new StringContent(string.Empty)); + + if (!response.IsSuccessStatusCode) + { + var responseContext = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + string errors = string.Empty; + if (responseContext != null && responseContext.StartsWith("{\"errors\"")) errors = responseContext.Substring(11, responseContext.IndexOf("}") - 11); + + if (response.ReasonPhrase == "Forbidden") + throw new Exception(string.Format("{0}", CoreMessagePolicy.GetInstance().ComposeMessage(CoreMessagePolicy.NO_PERMISSION))); + + throw new Exception(string.Format("{0}{1}", response.ReasonPhrase, string.IsNullOrEmpty(errors) ? "" : "\r\n" + errors)); + } + + response.EnsureSuccessStatusCode(); + + var responseJson = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + + CheckException(responseJson); + } + + public async void DownloadFile(string api, string filePath, Action progressCallback = null!, Action completedCallback = null!) + { + this.request.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", loginContext.GetToken()); + + if (request.DefaultRequestHeaders.Contains(ClaimPolicy.HEADER_LOCALE)) + request.DefaultRequestHeaders.Remove(ClaimPolicy.HEADER_LOCALE); + request.DefaultRequestHeaders.Add(ClaimPolicy.HEADER_LOCALE, loginContext.GetCulture()); + + var response = await this.request.PostAsync(api, new StringContent(string.Empty)); + + if (!response.IsSuccessStatusCode) + { + var responseContext = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + string errors = string.Empty; + if (responseContext != null && responseContext.StartsWith("{\"errors\"")) errors = responseContext.Substring(11, responseContext.IndexOf("}") - 11); + + if (response.ReasonPhrase == "Forbidden") + throw new Exception(string.Format("{0}", CoreMessagePolicy.GetInstance().ComposeMessage(CoreMessagePolicy.NO_PERMISSION))); + + throw new Exception(string.Format("{0}{1}", response.ReasonPhrase, string.IsNullOrEmpty(errors) ? "" : "\r\n" + errors)); + } + + response.EnsureSuccessStatusCode(); + + long? totalBytes = response.Content.Headers.ContentLength; + + using (Stream contentStream = await response.Content.ReadAsStreamAsync(), + fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None)) + { + byte[] buffer = new byte[8192];// 8KB緩衝區 + long totalRead = 0; + int read; + + while ((read = await contentStream.ReadAsync(buffer, 0, buffer.Length)) > 0) + { + await fileStream.WriteAsync(buffer, 0, read); + totalRead += read; + if (progressCallback != null) progressCallback(totalRead); + } + } + + if (completedCallback != null) completedCallback(filePath); + } + public async Task PostStreamAsync(string api, Dictionary headers, T data) + { + if (headers != null && headers.Count > 0) + { + foreach (var header in headers) + { + if (request.DefaultRequestHeaders.Contains(header.Key)) request.DefaultRequestHeaders.Remove(header.Key); + request.DefaultRequestHeaders.Add(header.Key, header.Value); + } + } + + this.request.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", loginContext.GetToken()); + + if (request.DefaultRequestHeaders.Contains(ClaimPolicy.HEADER_LOCALE)) + request.DefaultRequestHeaders.Remove(ClaimPolicy.HEADER_LOCALE); + request.DefaultRequestHeaders.Add(ClaimPolicy.HEADER_LOCALE, loginContext.GetCulture()); + + var options = new JsonSerializerOptions + { + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull + }; + + try + { + var response = await this.request.PostAsJsonAsync(api, data, options).ConfigureAwait(false); + + if (!response.IsSuccessStatusCode) + { + //{"errors":{},"type":"https://tools.ietf.org/html/rfc9110#section-15.5.1","title":"One or more validation errors occurred.","status":400,"traceId":"00-64ad066978f4471cb3c9ce219c213da9-bccca8afd14676b3-00"} + var responseContext = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + string errors = string.Empty; + if (responseContext != null && responseContext.StartsWith("{\"errors\"")) errors = responseContext.Substring(11, responseContext.IndexOf("}") - 11); + + if (response.ReasonPhrase == "Forbidden") + throw new Exception(string.Format("{0}", CoreMessagePolicy.GetInstance().ComposeMessage(CoreMessagePolicy.NO_PERMISSION))); + + throw new Exception(string.Format("{0}{1}", response.ReasonPhrase, string.IsNullOrEmpty(errors) ? "" : "\r\n" + errors)); + } + + response.EnsureSuccessStatusCode(); + + + return await response.Content.ReadAsStreamAsync(); + } + catch (Exception ex ) + { + + throw ex; + } + } + + public async Task PostAsync(string api, MultipartFormDataContent data) + { + this.request.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", loginContext.GetToken()); + + if (request.DefaultRequestHeaders.Contains(ClaimPolicy.HEADER_LOCALE)) + request.DefaultRequestHeaders.Remove(ClaimPolicy.HEADER_LOCALE); + request.DefaultRequestHeaders.Add(ClaimPolicy.HEADER_LOCALE, loginContext.GetCulture()); + + var response = await this.request.PostAsync(api, data); + + if (!response.IsSuccessStatusCode) + { + var responseContext = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + string errors = string.Empty; + if (responseContext != null && responseContext.StartsWith("{\"errors\"")) errors = responseContext.Substring(11, responseContext.IndexOf("}") - 11); + + if (response.ReasonPhrase == "Forbidden") + throw new Exception(string.Format("{0}", CoreMessagePolicy.GetInstance().ComposeMessage(CoreMessagePolicy.NO_PERMISSION))); + + throw new Exception(string.Format("{0}{1}", response.ReasonPhrase, string.IsNullOrEmpty(errors) ? "" : "\r\n" + errors)); + } + + response.EnsureSuccessStatusCode(); + + var responseJson = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + + CheckException(responseJson); + + return JsonConvert.DeserializeObject(responseJson, _jsonSettings)!; + } + + public void AddHeaders(string name, string? value) + { + request.DefaultRequestHeaders.Add(name, value); + } + + public void SetContext(IContext loginContext) + { + this.loginContext.SetCulture(loginContext.GetCulture()); + this.loginContext.SetToken(loginContext.GetToken()); + } + + public HttpClient GetHttpClient() { return request; } + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Service/AbstractSearchCriteria.cs b/CloudBuilder/CloudBuilder.Core/Service/AbstractSearchCriteria.cs new file mode 100644 index 0000000..5e164a6 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Service/AbstractSearchCriteria.cs @@ -0,0 +1,125 @@ +using CloudBuilder.Core.Extensions; +using Microsoft.IdentityModel.Tokens; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.Service +{ + public class AbstractSearchCriteria + { + public int limit { get; set; } = 20; + public int page { get; set; } + public int clear { get; set; } + public string? orderby { get; set; } = string.Empty; + public string? orderbytag { get; set; } = string.Empty; + + public SearchFilter[]? Filter { get; set; } + + public bool IsModal { get; set; } = false; + + public string? ReportName { get; set; } + + public GridColumnInfo[]? GridColumns { get; set; } + + public SelectOption[]? SelectOptions { get; set; } + + public List PackSearchCriteriaDisplay(ref List headers, ref string sqlWhere) + { + return PackSearchCriteriaDisplay(ref headers, ref sqlWhere, null); + } + public List PackSearchCriteriaDisplay(ref List headers, ref string sqlWhere, Dictionary> mappings) + { + List l = new List(); + + if (this.GridColumns != null && this.GridColumns.Length > 0) + { + foreach (var column in this.GridColumns) + { + if (!string.IsNullOrEmpty(column.title)) + { + if (column.hidden != "N") continue; + if (string.IsNullOrEmpty(column.dataIndex) || string.IsNullOrEmpty(column.title) || column.dataIndex == "index") continue; + headers.Add(new TemplateHeader() + { + DisplayName = column.title, + BindingName = column.dataIndex!, + Format = column.format!, + Width = TemplateHeader.WidthAutoFit + }); + } + } + } + + if (this.Filter != null && this.Filter.Length > 0) + { + sqlWhere = SearchFilter.ComposeWhereClause(this.Filter); + + foreach (SearchFilter filter in this.Filter) + { + if (!string.IsNullOrEmpty(filter.Column) && headers.Where(x => filter.Column.StringToProerty() == x.BindingName).Count() > 0) + { + TemplateHeader h = headers.Where(x => filter.Column.StringToProerty() == x.BindingName).FirstOrDefault(); + string v = filter.Value; + + switch (filter.Operator) + { + case SearchFilterOperatorPolicy.BETWEEN: + case SearchFilterOperatorPolicy.DATE_BETWEEN: + case SearchFilterOperatorPolicy.DATETIME_BETWEEN: + if (!string.IsNullOrEmpty(filter.Value) && string.IsNullOrEmpty(filter.Value1)) + v = string.Format("[ {0} ~ ]", filter.Value); + break; + } + + + if (!string.IsNullOrEmpty(filter.Value) && !string.IsNullOrEmpty(filter.Value1)) v = string.Format("[ {0} ~ {1} ]", filter.Value, filter.Value1); + if (string.IsNullOrEmpty(filter.Value) && !string.IsNullOrEmpty(filter.Value1)) v = string.Format("[ ~ {0}]", filter.Value1); + if (filter.Values != null && filter.Values.Length > 0) + { + v = QuotedString.ToDelimiteredList(filter.Values); + if (mappings != null && mappings.Count() > 0) + { + List m = new List(); + foreach (string mv in filter.Values) + { + m.Add(mappings[h.BindingName][mv].ToString()); + } + v = QuotedString.ToDelimiteredList(m.ToArray()); + } + } + + l.Add(string.Format("{0}: {1}", h.DisplayName, v)); + } + } + } + + return l; + } + } + + public class TemplateHeader + { + public const string DateFormat1 = "yyyy-MM-dd"; + public const string DateTimeFormat1 = "yyyy-MM-dd HH:mm:ss"; + public const string IntFormat1 = "#,##0;(#,##0)"; + public const string DecimalFormat1 = "#,##0.00;(#,##0.00)"; + public const string PercentageFormat1 = "0.0%"; + public const double WidthAutoFit = -1; + + public TemplateHeader() + { + Width = WidthAutoFit; + } + public string Format { get; set; } + public string DisplayName { get; set; } + public string BindingName { get; set; } + public string CellTypeFormatName { get; set; } + public string DataValueFormatName { get; set; } + public double Width { get; set; } + public int? DisplayIndex { get; set; } + + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Service/ExceptionData.cs b/CloudBuilder/CloudBuilder.Core/Service/ExceptionData.cs new file mode 100644 index 0000000..494bee9 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Service/ExceptionData.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.Service +{ + public class ExceptionData + { + public string StatusCode { get; set; } + public string ErrMsg { get; set; } + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Service/IService.cs b/CloudBuilder/CloudBuilder.Core/Service/IService.cs new file mode 100644 index 0000000..67dc69b --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Service/IService.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.Service +{ + public interface IService + { + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Service/IServiceBase.cs b/CloudBuilder/CloudBuilder.Core/Service/IServiceBase.cs new file mode 100644 index 0000000..03adbbe --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Service/IServiceBase.cs @@ -0,0 +1,18 @@ +using CloudBuilder.Core.DatabaseAccessor; + +namespace CloudBuilder.Core.Service +{ + public interface IServiceBase : IService + { + Tdata FindByKey(Tkey tc); + + [UnitOfWork] + Tdata Insert(Tdata tdata); + + [UnitOfWork] + Tdata Update(Tdata tdata); + + [UnitOfWork] + void Delete(Tkey tkey); + } +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Core/Service/SearchCriteria.cs b/CloudBuilder/CloudBuilder.Core/Service/SearchCriteria.cs new file mode 100644 index 0000000..676357f --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Service/SearchCriteria.cs @@ -0,0 +1,307 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.Service +{ + public class SearchCriteria + { + public const string KEY_FILTER_COLUMN = "filter_column"; + public const string KEY_FILTER_OPERATOR = "filter_operator"; + public const string KEY_FILTER_TYPE = "filter_type"; + + public SearchCriteria() + { + Add(KEY_FILTER_OPERATOR, SearchFilterOperatorPolicy.GetInstance().GetBindOptions()); + Add(KEY_FILTER_TYPE, SearchFilterTypePolicy.GetInstance().GetBindOptions()); + } + public SearchCriteria(Selection[] selections) + { + Selections = selections; + Add(KEY_FILTER_OPERATOR, SearchFilterOperatorPolicy.GetInstance().GetBindOptions()); + Add(KEY_FILTER_TYPE, SearchFilterTypePolicy.GetInstance().GetBindOptions()); + } + public Selection[] Selections { get; set; } + + public void Add(string key, BindOption[] bindOptions) + { + if (bindOptions == null || bindOptions.Length == 0) return; + List selections = new List(); + + if (Selections != null) + { + selections.AddRange(Selections); + } + + selections.Add(new Selection() { Key = key, BindOptions = bindOptions }); + + Selections = selections.ToArray(); + } + + } + + public class Selection + { + public Selection() { } + public Selection(string key, BindOption[] bindOptions) + { + Key = key; + BindOptions = bindOptions; + } + + public string Key { get; set; } + public BindOption[] BindOptions { get; set; } + } + + public class BindOption + { + public BindOption() { } + public BindOption(string value, string name, SelectOption[] selectOptions) + { + BindValue = value; + DisplayName = name; + SelectOptions = selectOptions; + } + public BindOption(string value, string name, string type, string opt) + { + BindValue = value; + DisplayName = name; + Type = type; + Operator = opt; + } + public BindOption(string value, string name, string type, string opt, SelectOption[] selectOptions) + { + BindValue = value; + DisplayName = name; + Type = type; + Operator = opt; + Values = new string[] { }; + SelectOptions = selectOptions; + } + public BindOption(string value, string name, string type, string opt, string defaultValue, string defaultValue1, string[] defaultValues, SelectOption[] selectOptions) + { + BindValue = value; + DisplayName = name; + Type = type; + Operator = opt; + Values = new string[] { }; + Value1 = defaultValue1; + Value = defaultValue; + Values = defaultValues; + SelectOptions = selectOptions; + } + public BindOption(string value, string name, string type, string opt, string defaultValue, string defaultValue1, SelectOption[] selectOptions) + { + BindValue = value; + DisplayName = name; + Type = type; + Operator = opt; + Values = new string[] { }; + Value1 = defaultValue1; + Value = defaultValue; + SelectOptions = selectOptions; + } + public BindOption(string value, string name, string type, string opt, string[] defaultValues, SelectOption[] selectOptions) + { + BindValue = value; + DisplayName = name; + Type = type; + Operator = opt; + Values = new string[] { }; + Values = defaultValues; + SelectOptions = selectOptions; + } + public string DisplayName { get; set; } + public string BindValue { get; set; } + public string Type { get; set; } + public string Operator { get; set; } + public string[] Values { get; set; } + public string Value { get; set; } + public string Value1 { get; set; } + + public SelectOption[] SelectOptions { get; set; } + } + + public class SelectOption + { + public string DisplayName { get; set; } + public string BindValue { get; set; } + } + + public class SearchFilter + { + public SearchFilter() { } + public SearchFilter(string column, string opt, string value) + { + Column = column; + Operator = opt; + Value = value; + } + + public string? Column { get; set; } + public string? Type { get; set; } + public string? Operator { get; set; } + public string? Value { get; set; } + public string? Value1 { get; set; } + public string[]? Values { get; set; } + + public static string ComposeWhereClause(SearchFilter[] searchFilters) + { + StringBuilder sb = new StringBuilder(); + + if (searchFilters == null || searchFilters.Length == 0) return null; + + foreach (SearchFilter f in searchFilters) + { + if (string.IsNullOrEmpty(f.Value) && !(f.Operator == SearchFilterOperatorPolicy.DATE_BETWEEN || f.Operator == SearchFilterOperatorPolicy.BETWEEN || f.Operator == SearchFilterOperatorPolicy.DATETIME_BETWEEN)) continue; + switch (f.Operator) + { + case SearchFilterOperatorPolicy.EQUAL_TO: + case SearchFilterOperatorPolicy.SINGLE: + sb.Append(string.Format(" and {0} = '{1}' ", f.Column, QuoteString(f.Value))); + break; + case SearchFilterOperatorPolicy.CONTAIN: + sb.Append(string.Format(" and {0} like '%{1}%' ", f.Column, QuoteString(f.Value))); + break; + case SearchFilterOperatorPolicy.START_CONTAIN: + sb.Append(string.Format(" and {0} like '{1}%' ", f.Column, QuoteString(f.Value))); + break; + case SearchFilterOperatorPolicy.END_CONTAIN: + sb.Append(string.Format(" and {0} like '%{1}' ", f.Column, QuoteString(f.Value))); + break; + case SearchFilterOperatorPolicy.CN_CONTAIN: + sb.Append(string.Format(" and {0} like N'%{1}%' ", f.Column, QuoteString(f.Value))); + break; + case SearchFilterOperatorPolicy.CN_START_CONTAIN: + sb.Append(string.Format(" and {0} like N'{1}%' ", f.Column, QuoteString(f.Value))); + break; + case SearchFilterOperatorPolicy.CN_END_CONTAIN: + sb.Append(string.Format(" and {0} like N'%{1}' ", f.Column, QuoteString(f.Value))); + break; + case SearchFilterOperatorPolicy.CN_MULTIPLE: + case SearchFilterOperatorPolicy.CN_IN_RANGE: + sb.Append(string.Format(" and {0} in ({1}) ", f.Column, QuoteStringCNInRange(f.Values))); + break; + case SearchFilterOperatorPolicy.MULTIPLE: + case SearchFilterOperatorPolicy.IN_RANGE: + sb.Append(string.Format(" and {0} in ({1}) ", f.Column, QuoteStringInRange(f.Values))); + break; + case SearchFilterOperatorPolicy.NOT_IN_RANGE: + sb.Append(string.Format(" and {0} not in ({1}) ", f.Column, QuoteStringInRange(f.Values))); + break; + case SearchFilterOperatorPolicy.NUMBER_GREATER_THAN: + sb.Append(string.Format(" and {0} > {1} ", f.Column, QuoteNumber(f.Value))); + break; + case SearchFilterOperatorPolicy.NUMBER_GREATER_THAN_OR_EQUAL_TO: + sb.Append(string.Format(" and {0} >= {1} ", f.Column, QuoteNumber(f.Value))); + break; + case SearchFilterOperatorPolicy.NUMBER_LESS_THAN: + sb.Append(string.Format(" and {0} < {1} ", f.Column, QuoteNumber(f.Value))); + break; + case SearchFilterOperatorPolicy.NUMBER_LESS_THAN_OR_EQUAL_TO: + sb.Append(string.Format(" and {0} <= {1} ", f.Column, QuoteNumber(f.Value))); + break; + case SearchFilterOperatorPolicy.NUMBER_EQUAL_TO: + sb.Append(string.Format(" and {0} = {1} ", f.Column, QuoteNumber(f.Value))); + break; + case SearchFilterOperatorPolicy.BETWEEN: + if (!string.IsNullOrEmpty(f.Value) && !string.IsNullOrEmpty(f.Value1)) + sb.Append(string.Format(" and {0} between {1} and {2} ", f.Column, QuoteNumber(f.Value), QuoteNumber(f.Value1))); + if (!string.IsNullOrEmpty(f.Value) && string.IsNullOrEmpty(f.Value1)) + sb.Append(string.Format(" and {0} >= {1} ", f.Column, QuoteNumber(f.Value))); + if (string.IsNullOrEmpty(f.Value) && !string.IsNullOrEmpty(f.Value1)) + sb.Append(string.Format(" and {0} <= {1} ", f.Column, QuoteNumber(f.Value1))); + break; + case SearchFilterOperatorPolicy.DATE_BETWEEN: + if (!string.IsNullOrEmpty(f.Value) && !string.IsNullOrEmpty(f.Value1)) + sb.Append(string.Format(" and {0} between '{1}' and '{2}' ", f.Column, QuoteString(f.Value), Convert.ToDateTime(QuoteString(f.Value1)).AddDays(1).ToString("yyyy-MM-dd"))); + if (!string.IsNullOrEmpty(f.Value) && string.IsNullOrEmpty(f.Value1)) + sb.Append(string.Format(" and {0} >= '{1}' ", f.Column, QuoteString(f.Value))); + if (string.IsNullOrEmpty(f.Value) && !string.IsNullOrEmpty(f.Value1)) + sb.Append(string.Format(" and {0} <= '{1}' ", f.Column, Convert.ToDateTime(QuoteString(f.Value1)).AddDays(1).ToString("yyyy-MM-dd"))); + break; + case SearchFilterOperatorPolicy.DATETIME_BETWEEN: + if (!string.IsNullOrEmpty(f.Value) && !string.IsNullOrEmpty(f.Value1)) + sb.Append(string.Format(" and {0} between '{1}' and '{2}' ", f.Column, QuoteString(f.Value), Convert.ToDateTime(QuoteString(f.Value1)).AddSeconds(1).ToString("yyyy-MM-dd HH:mm:ss"))); + if (!string.IsNullOrEmpty(f.Value) && string.IsNullOrEmpty(f.Value1)) + sb.Append(string.Format(" and {0} >= '{1}' ", f.Column, QuoteString(f.Value))); + if (string.IsNullOrEmpty(f.Value) && !string.IsNullOrEmpty(f.Value1)) + sb.Append(string.Format(" and {0} <= '{1}' ", f.Column, Convert.ToDateTime(QuoteString(f.Value1)).AddSeconds(1).ToString("yyyy-MM-dd HH:mm:ss"))); + break; + case SearchFilterOperatorPolicy.DATE_GREATER_THAN: + sb.Append(string.Format(" and {0} > '{1}' ", f.Column, QuoteString(f.Value))); + break; + case SearchFilterOperatorPolicy.DATE_GREATER_THAN_OR_EQUAL_TO: + sb.Append(string.Format(" and {0} >= '{1}' ", f.Column, QuoteString(f.Value))); + break; + case SearchFilterOperatorPolicy.DATE_LESS_THAN: + sb.Append(string.Format(" and {0} < '{1}' ", f.Column, Convert.ToDateTime(QuoteString(f.Value)).AddDays(1).ToString("yyyy-MM-dd"))); + break; + case SearchFilterOperatorPolicy.DATE_LESS_THAN_OR_EQUAL_TO: + sb.Append(string.Format(" and {0} <= '{1}' ", f.Column, QuoteString(f.Value))); + break; + case SearchFilterOperatorPolicy.DATE_EQUAL_TO: + sb.Append(string.Format(" and {0} = '{1}' ", f.Column, QuoteString(f.Value))); + break; + } + } + + return sb.ToString(); + } + + public static string QuoteStringCNInRange(string[] values) + { + if (values == null || values.Length == 0) return string.Empty; + StringBuilder sb = new StringBuilder(); + + foreach (string v in values) + { + sb.Append(string.Format(" N'{0}', ", QuoteString(v))); + } + + return sb.ToString().Substring(0, sb.Length - 2); + } + + public static string QuoteStringInRange(string[] values) + { + if (values == null || values.Length == 0) return string.Empty; + StringBuilder sb = new StringBuilder(); + + foreach (string v in values) + { + sb.Append(string.Format(" '{0}', ", QuoteString(v))); + } + + return sb.ToString().Substring(0, sb.Length - 2); + } + + public static string QuoteNumber(string s) + { + int i = 0; + if (!int.TryParse(s, out i)) return "0"; + return s; + } + + public static string QuoteString(string s) + { + if (s == null) s = string.Empty; + + return s.Replace("'", "''");// "'" + s.Replace("'", "''") + "'"; + } + + } + + public class GridColumnInfo + { + public string? title { get; set; } + public string? dataIndex { get; set; } + + public int sequence { get; set; } + public string? align { get; set; } + public string? hidden { get; set; } + public string? format { get; set; } + + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Service/SearchCriteriaResultData.cs b/CloudBuilder/CloudBuilder.Core/Service/SearchCriteriaResultData.cs new file mode 100644 index 0000000..758a9fb --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Service/SearchCriteriaResultData.cs @@ -0,0 +1,19 @@ +using CloudBuilder.Core.Authorization; + +namespace CloudBuilder.Core.Service +{ + [TypeScript] + public class SearchCriteriaResultData + { + public int Limit { get; set; } + + public int Page { get; set; } + + public int Total { get; set; } + + public string? Sql { get; set; } + + public string? ErrorMessage { get; set; } + + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Service/ServiceErrorException.cs b/CloudBuilder/CloudBuilder.Core/Service/ServiceErrorException.cs new file mode 100644 index 0000000..9dd585d --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Service/ServiceErrorException.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Serialization; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.Service +{ + public class ServiceErrorException : Exception + { + public string SourceCode { get; set; } = "CloudBuilder.Core.ServiceErrorException"; + + public new string Message { get; set; } = string.Empty; + + /// + /// 初始化类的新实例 + /// + public ServiceErrorException() + { } + + public ServiceErrorException(Exception ex) + : base(ex.Message, ex) + { + Message = ex.Message; + } + + /// + /// 使用指定错误消息初始化类的新实例。 + /// + /// 描述错误的消息 + public ServiceErrorException(string message) + : base(message) + { + Message = message; + } + + /// + /// 使用异常消息与一个内部异常实例化一个类的新实例 + /// + /// 异常消息 + /// 用于封装在内部的异常实例 + public ServiceErrorException(string message, Exception inner) + : base(message, inner) + { Message = message; } + + /// + /// 使用可序列化数据实例化一个类的新实例 + /// + /// 保存序列化对象数据的对象。 + /// 有关源或目标的上下文信息。 + protected ServiceErrorException(SerializationInfo info, StreamingContext context) + : base(info, context) + { } + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Service/ServiceHelper.cs b/CloudBuilder/CloudBuilder.Core/Service/ServiceHelper.cs new file mode 100644 index 0000000..17c3565 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Service/ServiceHelper.cs @@ -0,0 +1,53 @@ +using CloudBuilder.Core.DependencyInjection.Form; +using Microsoft.Extensions.DependencyInjection; + +namespace CloudBuilder +{ + public class ServiceHelper + { + + //services.TryAddSingleton(); + /// + /// 通过单例获取指定类型的服务 + /// + public static R GetService() + { + return ApplicationServiceContext.ServiceProvider.GetService()!; + } + + //services.TryAddSingleton(); + /// + /// 通过接口获取指定类型的服务 + /// + public static R GetInterfaceService() + { + return ApplicationServiceContext.ServiceProvider.GetService()!; + } + + //services.TryAddKeyedScoped(implementType, implementType.Name); + /// + /// 通过名称获取指定类型的服务 + /// + public static R GetTypeService() + { + return ApplicationServiceContext.ServiceProvider.GetRequiredKeyedService(typeof(R).Name); + } + + //services.TryAddKeyedScoped(implementType.BaseType, implementType.Name, implementType); + /// + /// 通过名称获取指定类型(被继承的类)的服务 + /// + public static R GetBaseTypeService(string name) + { + return ApplicationServiceContext.ServiceProvider.GetRequiredKeyedService(name); + } + + public static R GetBaseTypeScopeService(string name) + { + using (var scope = ApplicationServiceContext.ServiceProvider.CreateScope()) + { + return scope.ServiceProvider.GetRequiredKeyedService(name); + } + } + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Service/ValidatedException.cs b/CloudBuilder/CloudBuilder.Core/Service/ValidatedException.cs new file mode 100644 index 0000000..7df44d2 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Service/ValidatedException.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Serialization; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.Service +{ + public class ValidatedException : Exception + { + public string SourceCode { get; set; } = "CloudBuilder.Core.ValidatedException"; + public new string Message { get; set; } = string.Empty; + + /// + /// 初始化类的新实例 + /// + public ValidatedException() + { } + + /// + /// 使用指定错误消息初始化类的新实例。 + /// + /// 描述错误的消息 + public ValidatedException(string message) + : base(message) + { + Message = message; + } + + /// + /// 使用异常消息与一个内部异常实例化一个类的新实例 + /// + /// 异常消息 + /// 用于封装在内部的异常实例 + public ValidatedException(string message, Exception inner) + : base(message, inner) + { + Message = message; + } + + /// + /// 使用可序列化数据实例化一个类的新实例 + /// + /// 保存序列化对象数据的对象。 + /// 有关源或目标的上下文信息。 + protected ValidatedException(SerializationInfo info, StreamingContext context) + : base(info, context) + { } + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Utility/DataTableConvertor.cs b/CloudBuilder/CloudBuilder.Core/Utility/DataTableConvertor.cs new file mode 100644 index 0000000..eb3942d --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Utility/DataTableConvertor.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Core.Utility +{ + public class DataTableConvertor + { + /// + /// DataTable转对象 + /// + /// + /// + public static List ConvertToList(DataTable dt) where T : new() + { + // 定义集合 + var list = new List(); + + if (dt == null || 0 == dt.Rows.Count) + { + return list; + } + + // 获得此模型的可写公共属性 + IEnumerable propertys = typeof(T).GetProperties().Where(u => u.CanWrite); + list = ConvertToEntity(dt, propertys); + + return list; + } + private static List ConvertToEntity(DataTable dt, IEnumerable propertys) where T : new() + { + var list = new List(); + + //遍历DataTable中所有的数据行 + foreach (DataRow dr in dt.Rows) + { + if (dr.RowState == DataRowState.Deleted) continue; + + var entity = new T(); + + //遍历该对象的所有属性 + foreach (PropertyInfo p in propertys) + { + //将属性名称赋值给临时变量 + string tmpName = p.Name; + + //检查DataTable是否包含此列(列名==对象的属性名) + if (!dt.Columns.Contains(tmpName)) continue; + //取值 + object value = dr[tmpName]; + + //如果非空,则赋给对象的属性 + if (value != DBNull.Value) + { + p.SetValue(entity, value, null); + } + } + //对象添加到泛型集合中 + list.Add(entity); + } + return list; + } + /// + /// 对象转DataTable + /// + /// + /// + public static DataTable ToDataTable(IList list) + { + return ToDataTable(list, false); + } + + public static DataTable ToDataTable(IList list, bool blankOption) + { + Type elementType = typeof(T); + + var t = new DataTable(); + + elementType.GetProperties().ToList().ForEach(propInfo => t.Columns.Add(propInfo.Name, Nullable.GetUnderlyingType(propInfo.PropertyType) ?? propInfo.PropertyType)); + + if (blankOption) + { + var row = t.NewRow(); + t.Rows.Add(row); + } + + foreach (T item in list) + { + var row = t.NewRow(); + elementType.GetProperties().ToList().ForEach(propInfo => row[propInfo.Name] = propInfo.GetValue(item, null) ?? DBNull.Value); + t.Rows.Add(row); + } + return t; + } + + public static DataTable ToDataTable(T[] list) + { + Type elementType = typeof(T); + + var t = new DataTable(); + + elementType.GetProperties().ToList().ForEach(propInfo => t.Columns.Add(propInfo.Name, Nullable.GetUnderlyingType(propInfo.PropertyType) ?? propInfo.PropertyType)); + foreach (T item in list) + { + var row = t.NewRow(); + elementType.GetProperties().ToList().ForEach(propInfo => row[propInfo.Name] = propInfo.GetValue(item, null) ?? DBNull.Value); + t.Rows.Add(row); + } + return t; + } + + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Utility/DeserializeHelper.cs b/CloudBuilder/CloudBuilder.Core/Utility/DeserializeHelper.cs new file mode 100644 index 0000000..552c06c --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Utility/DeserializeHelper.cs @@ -0,0 +1,20 @@ +using System.Xml.Serialization; + +namespace CloudBuilder.Util +{ + public class DeserializeHelper + { + public static T Deserialize(string xml) + { + StringReader textReader = new StringReader(xml); + XmlSerializer serializer = new XmlSerializer(typeof(T)); + return (T)serializer.Deserialize(textReader); + } + + public static string LoadXml(string filePath) + { + if (!File.Exists(filePath)) return null; + return File.ReadAllText(Path.Combine(filePath)); + } + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Utility/EncryptHelper.cs b/CloudBuilder/CloudBuilder.Core/Utility/EncryptHelper.cs new file mode 100644 index 0000000..06e0a22 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Utility/EncryptHelper.cs @@ -0,0 +1,122 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Security.Cryptography; +using System.Web; + +namespace System +{ + public static class EncryptHelper + { + /// + /// AES秘钥(强烈要求.json自定义取出) + /// + private const string AesKey = "OwenItc-*&$%RTj3"; + + /// + /// AES偏移向量(强烈要求.json自定义取出) + /// + private const string AesIV = "*&^KJ8a-Tj3*&$%R"; + + public static string AesEncrypt(string toEncryptString) + { + return AesEncrypt(toEncryptString, AesKey, AesIV); + } + + /// + /// AES加密 + /// + /// 待加密的明文 + /// + public static string AesEncrypt(this string toEncryptString, string aesKey, string aesIV) + { + var rijndaelCipher = new RijndaelManaged + { + Mode = CipherMode.CBC, + Padding = PaddingMode.PKCS7, + KeySize = 128, + BlockSize = 128 + }; + + var toEncryptBytes = Encoding.UTF8.GetBytes(toEncryptString); + var keyBytes = Encoding.UTF8.GetBytes(aesKey); + var ivBytes = Encoding.UTF8.GetBytes(aesIV); + + rijndaelCipher.Key = keyBytes; + rijndaelCipher.IV = ivBytes; + + ICryptoTransform transform = rijndaelCipher.CreateEncryptor(); + byte[] cipherBytes = transform.TransformFinalBlock(toEncryptBytes, 0, toEncryptBytes.Length); + return Convert.ToBase64String(cipherBytes); + } + + public static string AesDecrpt(string toDecrpt) + { + return AesDecrpt(toDecrpt, AesKey, AesIV); + } + /// + /// AES解密 + /// + /// + /// + public static string AesDecrpt(this string toDecrpt, string aesKey, string aesIV) + { + var key = Encoding.UTF8.GetBytes(aesKey); + var encryptedData = Convert.FromBase64String(toDecrpt); + var iv = Encoding.UTF8.GetBytes(aesIV); + + var rDel = new RijndaelManaged + { + Key = key, + IV = iv, + Mode = CipherMode.CBC, + Padding = PaddingMode.PKCS7 + }; + + var cTransform = rDel.CreateDecryptor(); + var resultArray = cTransform.TransformFinalBlock(encryptedData, 0, encryptedData.Length); + + return Encoding.UTF8.GetString(resultArray); + } + + public static string UrlEncode(string toEncryptString) + { + if (string.IsNullOrEmpty(toEncryptString)) return null; + return HttpUtility.UrlEncode(AesEncrypt(toEncryptString), Encoding.UTF8); + } + + public static string UrlDecode(string toEncryptString) + { + if (string.IsNullOrEmpty(toEncryptString)) return null; + return AesDecrpt(toEncryptString); + } + + public static string Decode(string toEncryptString) + { + if (string.IsNullOrEmpty(toEncryptString)) return null; + return AesDecrpt(HttpUtility.UrlDecode(toEncryptString, Encoding.UTF8)); + } + + public static string GetMd5(this string source) + { + if (string.IsNullOrEmpty(source)) return null; + + MD5 md = MD5.Create(); + + byte[] bytes = md.ComputeHash(System.Text.Encoding.UTF8.GetBytes(source)); + + string dec = null; + + foreach (byte b in bytes) + { + + dec += b.ToString("x2"); + + } + + return dec; + } + } +} + diff --git a/CloudBuilder/CloudBuilder.Core/Utility/FileLog.cs b/CloudBuilder/CloudBuilder.Core/Utility/FileLog.cs new file mode 100644 index 0000000..722d6e1 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Utility/FileLog.cs @@ -0,0 +1,58 @@ +using Microsoft.Extensions.Configuration; +using System; +using System.IO; +using System.Text; + +/// +/// 文件日志写入封装类,自动按日期分文件、超大小自动切割 +/// +public class FileLog +{ + private readonly IConfiguration _configuration; + private readonly object _lockObj = new object(); // 独立锁,不依赖外部this + + public FileLog(IConfiguration configuration) + { + _configuration = configuration ?? throw new ArgumentNullException(nameof(configuration)); + } + + /// + /// 写入日志内容到文件 + /// + /// 日志文本 + public void WriteToFile(string log) + { + try + { + // 读取配置,转换最大文件字节数 + int maxMb = _configuration.GetValue("Logging:MaxFileSizeMB"); + long maxFileSizeBytes = (long)maxMb * 1024 * 1024; + + string today = DateTime.Now.ToString("yyyyMMdd"); + string basePath = _configuration["Logging:LogFileDirectory"]; + Directory.CreateDirectory(basePath); + + string baseFileName = $"log-{today}"; + string ext = ".log"; + string finalPath = Path.Combine(basePath, $"{baseFileName}{ext}"); + int index = 1; + + // 文件超限则递增后缀切割 + while (File.Exists(finalPath) && new FileInfo(finalPath).Length >= maxFileSizeBytes) + { + finalPath = Path.Combine(basePath, $"{baseFileName}-{index}{ext}"); + index++; + } + + // 线程安全写入 + lock (_lockObj) + { + File.AppendAllText(finalPath, log + Environment.NewLine, Encoding.UTF8); + } + } + catch + { + // 原逻辑吞掉所有异常,如需日志可自行增加内部异常输出 + } + } +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Core/Utility/ObjectCopyHelper.cs b/CloudBuilder/CloudBuilder.Core/Utility/ObjectCopyHelper.cs new file mode 100644 index 0000000..9dba1c7 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Utility/ObjectCopyHelper.cs @@ -0,0 +1,147 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace System +{ + /// + /// 对象属性值复制 + /// + public class ObjectCopyHelper + { + /// + /// 属性映射(静态对象,无需重复建立属性映射关系,提高效率) + /// + public static Dictionary> MapDic = new Dictionary>(); + /// + /// S复制到D(创建对象D) + /// + /// 输出对象类型 + /// 输入对象类型 + /// 输入对象 + /// + public static D Copy(S s) + where D : class, new() + where S : class, new() + { + if (s == null) + { + return default(D); + } + //使用无参数构造函数,创建指定泛型类型参数所指定类型的实例 + D d = Activator.CreateInstance(); + return Copy(s, d); + } + /// + /// S复制到D(对象D已存在) + /// + /// 输出对象类型 + /// 输入对象类型 + /// 输入对象 + /// 输出对象 + /// + public static D Copy(S s, D d) + where D : class, new() + where S : class, new() + { + if (s == null || d == null) + { + return d; + } + try + { + var sType = s.GetType(); + var dType = typeof(D); + //属性映射Key + string mapkey = dType.FullName + "_" + sType.FullName; + if (MapDic.ContainsKey(mapkey)) + { + //已存在属性映射 + foreach (var item in MapDic[mapkey]) + { + //按照属性映射关系赋值 + //.net 4 + //dType.GetProperty(item).SetValue(d, sType.GetProperty(item).GetValue(s, null), null); + //.net 4.5 + dType.GetProperty(item).SetValue(d, sType.GetProperty(item).GetValue(s)); + } + } + else + { + //不存在属性映射,需要建立属性映射 + List namelist = new List(); + Dictionary dic = new Dictionary(); + //遍历获取输入类型的属性(属性名称,类型,值) + foreach (PropertyInfo sP in sType.GetProperties()) + { + //.net 4 + //dic.Add(sP.Name, new TypeAndValue() { type = sP.PropertyType, value = sP.GetValue(s, null) }); + //.net 4.5 + dic.Add(sP.Name, new TypeAndValue() { type = sP.PropertyType, value = sP.GetValue(s) }); + } + //遍历输出类型的属性,并与输入类型(相同名称和类型的属性)建立映射,并赋值 + foreach (PropertyInfo dP in dType.GetProperties()) + { + if (dic.Keys.Contains(dP.Name)) + { + if (dP.PropertyType == dic[dP.Name].type) + { + namelist.Add(dP.Name); + //.net 4 + //dP.SetValue(d, dic[dP.Name].value, null); + //.net 4.5 + dP.SetValue(d, dic[dP.Name].value); + } + } + } + //保存映射 + if (!MapDic.ContainsKey(mapkey)) + { + MapDic.Add(mapkey, namelist); + } + } + } + catch (Exception ex) + { + throw ex; + } + return d; + } + /// + /// SList复制到DList + /// + /// 输出对象类型 + /// 输入对象类型 + /// 输入对象集合 + /// + public static IQueryable Copy(IQueryable sList) + where D : class, new() + where S : class, new() + { + List dList = new List(); + foreach (var item in sList) + { + dList.Add(Copy(item)); + } + return dList.AsQueryable(); + } + } + /// + /// 类型和值 + /// + class TypeAndValue + { + /// + /// 类型 + /// + public Type type { get; set; } + /// + /// 值 + /// + public object value { get; set; } + } +} + diff --git a/CloudBuilder/CloudBuilder.Core/Utility/QuotedString.cs b/CloudBuilder/CloudBuilder.Core/Utility/QuotedString.cs new file mode 100644 index 0000000..f077ea5 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Utility/QuotedString.cs @@ -0,0 +1,126 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + + +namespace System +{ + public class QuotedString + { + public static string ToQuotedString(string[] vs) + { + if (vs == null || vs.Length == 0) return null; + + return ToQuotedDelimitedList(vs); + } + + public static string ToQuotedString(int[] vs) + { + if (vs == null || vs.Length == 0) return null; + + return ToQuotedDelimitedList(vs.Select(x => x.ToString()).ToArray()); ; + } + + public const char DELIMITER_CHAR = ','; + /// + /// 字符串安全转数组,分隔符',' + /// + /// + /// + public static string[] DelimiteredListToArray(string t) + { + return DelimiteredListToArray(t, DELIMITER_CHAR); + } + + public static string[] DelimiteredListToArray(string t, char delim) + { + if (string.IsNullOrEmpty(t)) return null; + return t.Split(delim); + } + /// + /// 字符串安全转数组,分隔符',' + /// + /// + /// + public static List DelimiteredListToList(string t) + { + return DelimiteredListToList(t, DELIMITER_CHAR); + } + + public static List DelimiteredListToList(string t, char delim) + { + if (string.IsNullOrEmpty(t)) return null; + + List l = new List(); + l.AddRange(DelimiteredListToArray(t, delim)); + return l; + } + + + /// + /// 数组变成字符串 + /// + /// + /// + public static string ToDelimiteredList(string[] s) + { + return ToDelimiteredList(s, DELIMITER_CHAR); + } + + public static string ToQuotedDelimitedList(string[] s) + { + StringBuilder b = new StringBuilder(); + + foreach (string t in s) + { + if (b.Length > 0) b.Append(DELIMITER_CHAR); + b.Append('\'' + t + '\''); + } + + return b.ToString(); + } + + public static string ToDelimiteredList(string[] s, char delim) + { + StringBuilder b = new StringBuilder(); + foreach (string t in s) + { + b.Append(delim + t); + } + + string r = b.ToString(); + if (r.StartsWith(delim.ToString())) r = r.Substring(1); + + return r; + } + + public static string CreateRandomNumber(int NumCount) + { + string text = "0,1,2,3,4,5,6,7,8,9"; + string[] array = text.Split(','); + string text2 = ""; + int num = -1; + Random random = new Random(); + for (int i = 0; i < NumCount; i++) + { + if (num != -1) + { + random = new Random(i * num * (int)DateTime.Now.Ticks); + } + + int num2 = random.Next(array.Length - 1); + if (num == num2) + { + return CreateRandomNumber(NumCount); + } + + num = num2; + text2 += array[num2]; + } + + return text2; + } + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Utility/RSA.cs b/CloudBuilder/CloudBuilder.Core/Utility/RSA.cs new file mode 100644 index 0000000..8044f2b --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Utility/RSA.cs @@ -0,0 +1,295 @@ +using System; +using System.IO; +using System.Security.Cryptography; +using System.Text; +using System.Text.RegularExpressions; +using CryptographyRSA = System.Security.Cryptography.RSA; // 别名避免与当前类名冲突 + +namespace System +{ + /// + /// RSA操作类(跨平台实现) + /// + public class RSA + { + // 记录当前实例是否仅包含公钥(替代原来的 rsa.PublicOnly) + private bool publicOnly; + + /// + /// 导出XML格式密钥对,如果convertToPublic含私钥的RSA将只返回公钥,仅含公钥的RSA不受影响 + /// + public string ToXML(bool convertToPublic = false) + { + bool includePrivate = !publicOnly && !convertToPublic; + return rsa.ToXmlString(includePrivate); + } + + /// + /// 导出PEM PKCS#1格式密钥对,如果convertToPublic含私钥的RSA将只返回公钥,仅含公钥的RSA不受影响 + /// + public string ToPEM_PKCS1(bool convertToPublic = false) + { + if (!publicOnly && !convertToPublic) + { + return rsa.ExportRSAPrivateKeyPem(); + } + return rsa.ExportRSAPublicKeyPem(); + } + + /// + /// 导出PEM PKCS#8格式密钥对,如果convertToPublic含私钥的RSA将只返回公钥,仅含公钥的RSA不受影响 + /// + public string ToPEM_PKCS8(bool convertToPublic = false) + { + if (!publicOnly && !convertToPublic) + { + return rsa.ExportPkcs8PrivateKeyPem(); + } + return rsa.ExportSubjectPublicKeyInfoPem(); + } + + /// + /// 加密字符串(utf-8),出错抛异常 + /// + public string Encode(string str) + { + return RSA_Unit.Base64EncodeBytes(Encode(Encoding.UTF8.GetBytes(str))); + } + + /// + /// 加密数据,出错抛异常 + /// + public byte[] Encode(byte[] data) + { + int blockLen = rsa.KeySize / 8 - 11; + if (data.Length <= blockLen) + { + return rsa.Encrypt(data, RSAEncryptionPadding.Pkcs1); + } + + using (var dataStream = new MemoryStream(data)) + using (var enStream = new MemoryStream()) + { + byte[] buffer = new byte[blockLen]; + int len = dataStream.Read(buffer, 0, blockLen); + + while (len > 0) + { + byte[] block = new byte[len]; + Array.Copy(buffer, 0, block, 0, len); + + byte[] enBlock = rsa.Encrypt(block, RSAEncryptionPadding.Pkcs1); + enStream.Write(enBlock, 0, enBlock.Length); + + len = dataStream.Read(buffer, 0, blockLen); + } + + return enStream.ToArray(); + } + } + + /// + /// 解密字符串(utf-8),解密异常返回null + /// + public string DecodeOrNull(string str) + { + if (string.IsNullOrEmpty(str)) + return null; + + var bytes = RSA_Unit.Base64DecodeBytes(str); + if (bytes == null) + return null; + + var decrypted = DecodeOrNull(bytes); + if (decrypted == null) + return null; + + return Encoding.UTF8.GetString(decrypted); + } + + /// + /// 解密数据,解密异常返回null + /// + public byte[] DecodeOrNull(byte[] data) + { + try + { + int blockLen = rsa.KeySize / 8; + if (data.Length <= blockLen) + { + return rsa.Decrypt(data, RSAEncryptionPadding.Pkcs1); + } + + using (var dataStream = new MemoryStream(data)) + using (var deStream = new MemoryStream()) + { + byte[] buffer = new byte[blockLen]; + int len = dataStream.Read(buffer, 0, blockLen); + + while (len > 0) + { + byte[] block = new byte[len]; + Array.Copy(buffer, 0, block, 0, len); + + byte[] deBlock = rsa.Decrypt(block, RSAEncryptionPadding.Pkcs1); + deStream.Write(deBlock, 0, deBlock.Length); + + len = dataStream.Read(buffer, 0, blockLen); + } + + return deStream.ToArray(); + } + } + catch + { + return null; + } + } + + /// + /// 对str进行签名,并指定hash算法(如:SHA256) + /// + public string Sign(string hash, string str) + { + return RSA_Unit.Base64EncodeBytes(Sign(hash, Encoding.UTF8.GetBytes(str))); + } + + /// + /// 对data进行签名,并指定hash算法(如:SHA256) + /// + public byte[] Sign(string hash, byte[] data) + { + return rsa.SignData(data, new HashAlgorithmName(hash), RSASignaturePadding.Pkcs1); + } + + /// + /// 验证字符串str的签名是否是sgin,并指定hash算法(如:SHA256) + /// + public bool Verify(string hash, string sgin, string str) + { + var bytes = RSA_Unit.Base64DecodeBytes(sgin); + if (bytes == null) + return false; + + return Verify(hash, bytes, Encoding.UTF8.GetBytes(str)); + } + + /// + /// 验证data的签名是否是sgin,并指定hash算法(如:SHA256) + /// + public bool Verify(string hash, byte[] sgin, byte[] data) + { + try + { + return rsa.VerifyData(data, sgin, new HashAlgorithmName(hash), RSASignaturePadding.Pkcs1); + } + catch + { + return false; + } + } + + private CryptographyRSA rsa; + + public RSA() : this(2048) + { + } + + /// + /// 用指定密钥大小创建一个新的RSA,出错抛异常 + /// + public RSA(int keySize) + { + rsa = CryptographyRSA.Create(); + rsa.KeySize = keySize; + publicOnly = false; // 新生成的密钥对包含私钥 + } + + /// + /// 通过指定的密钥,创建一个RSA,xml内可以只包含一个公钥或私钥,或都包含,出错抛异常 + /// + public RSA(string xml) + { + rsa = CryptographyRSA.Create(); + rsa.FromXmlString(xml); + + // 判断是否仅包含公钥 + publicOnly = false; + try + { + rsa.ExportParameters(true); // 能导出私钥参数说明含私钥 + } + catch (CryptographicException) + { + publicOnly = true; + } + } + + /// + /// 通过一个pem文件创建RSA,pem为公钥或私钥,出错抛异常 + /// + public RSA(string pem, bool noop) + { + rsa = CryptographyRSA.Create(); + + // 1. 兼容文件路径 + string pemContent = pem; + if (!pemContent.Contains("BEGIN")) + { + pemContent = File.ReadAllText(pem); + } + + // 2. 提取 Base64 部分(忽略标签) + var match = Regex.Match(pemContent, + @"-----BEGIN [^-]+-----([\s\S]*?)-----END [^-]+-----", + RegexOptions.Singleline); + if (!match.Success) + throw new CryptographicException("无效的 PEM 格式。"); + + string base64 = match.Groups[1].Value + .Replace("\r", "") + .Replace("\n", "") + .Replace(" ", "") + .Replace("\t", "") + .Trim(); + + byte[] der = Convert.FromBase64String(base64); + + // 3. 依次尝试常见 RSA 密钥格式(顺序可调整) + // 先尝试 PKCS#8 私钥,再尝试 PKCS#1 私钥,然后公钥 + try + { + rsa.ImportPkcs8PrivateKey(der, out _); + publicOnly = false; + return; + } + catch (CryptographicException) { } + + try + { + rsa.ImportRSAPrivateKey(der, out _); + publicOnly = false; + return; + } + catch (CryptographicException) { } + + try + { + rsa.ImportSubjectPublicKeyInfo(der, out _); + publicOnly = true; + return; + } + catch (CryptographicException) { } + + try + { + rsa.ImportRSAPublicKey(der, out _); + publicOnly = true; + return; + } + catch (CryptographicException) { } + + throw new CryptographicException("无法识别的 RSA 密钥格式。"); + } + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Utility/RSA_PEM.cs b/CloudBuilder/CloudBuilder.Core/Utility/RSA_PEM.cs new file mode 100644 index 0000000..01a125e --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Utility/RSA_PEM.cs @@ -0,0 +1,326 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace System +{ + public class RSA_PEM + { + /// + /// 用PEM格式密钥对创建RSA,支持PKCS#1、PKCS#8格式的PEM + /// + public static RSACryptoServiceProvider FromPEM(string pem) + { + var rsaParams = new CspParameters(); + rsaParams.Flags = CspProviderFlags.UseMachineKeyStore; + var rsa = new RSACryptoServiceProvider(rsaParams); + + var param = new RSAParameters(); + + var base64 = _PEMCode.Replace(pem, ""); + var data = RSA_Unit.Base64DecodeBytes(base64); + if (data == null) + { + throw new Exception("PEM内容无效"); + } + var idx = 0; + + //读取长度 + Func readLen = (first) => { + if (data[idx] == first) + { + idx++; + if (data[idx] == 0x81) + { + idx++; + return data[idx++]; + } + else if (data[idx] == 0x82) + { + idx++; + return (((int)data[idx++]) << 8) + data[idx++]; + } + else if (data[idx] < 0x80) + { + return data[idx++]; + } + } + throw new Exception("PEM未能提取到数据"); + }; + //读取块数据 + Func readBlock = () => { + var len = readLen(0x02); + if (data[idx] == 0x00) + { + idx++; + len--; + } + var val = data.sub(idx, len); + idx += len; + return val; + }; + //比较data从idx位置开始是否是byts内容 + Func eq = (byts) => { + for (var i = 0; i < byts.Length; i++, idx++) + { + if (idx >= data.Length) + { + return false; + } + if (byts[i] != data[idx]) + { + return false; + } + } + return true; + }; + + + + + if (pem.Contains("PUBLIC KEY")) + { + /****使用公钥****/ + //读取数据总长度 + readLen(0x30); + if (!eq(_SeqOID)) + { + throw new Exception("PEM未知格式"); + } + //读取1长度 + readLen(0x03); + idx++;//跳过0x00 + //读取2长度 + readLen(0x30); + + //Modulus + param.Modulus = readBlock(); + + //Exponent + param.Exponent = readBlock(); + } + else if (pem.Contains("PRIVATE KEY")) + { + /****使用私钥****/ + //读取数据总长度 + readLen(0x30); + + //读取版本号 + if (!eq(_Ver)) + { + throw new Exception("PEM未知版本"); + } + + //检测PKCS8 + var idx2 = idx; + if (eq(_SeqOID)) + { + //读取1长度 + readLen(0x04); + //读取2长度 + readLen(0x30); + + //读取版本号 + if (!eq(_Ver)) + { + throw new Exception("PEM版本无效"); + } + } + else + { + idx = idx2; + } + + //读取数据 + param.Modulus = readBlock(); + param.Exponent = readBlock(); + param.D = readBlock(); + param.P = readBlock(); + param.Q = readBlock(); + param.DP = readBlock(); + param.DQ = readBlock(); + param.InverseQ = readBlock(); + } + else + { + throw new Exception("pem需要BEGIN END标头"); + } + + rsa.ImportParameters(param); + return rsa; + } + static private Regex _PEMCode = new Regex(@"--+.+?--+|\s+"); + static private byte[] _SeqOID = new byte[] { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00 }; + static private byte[] _Ver = new byte[] { 0x02, 0x01, 0x00 }; + + + + + + + + + /// + /// 将RSA中的密钥对转换成PEM格式,usePKCS8=false时返回PKCS#1格式,否则返回PKCS#8格式,如果convertToPublic含私钥的RSA将只返回公钥,仅含公钥的RSA不受影响 + /// + public static string ToPEM(RSACryptoServiceProvider rsa, bool convertToPublic, bool usePKCS8) + { + //https://www.jianshu.com/p/25803dd9527d + //https://www.cnblogs.com/ylz8401/p/8443819.html + //https://blog.csdn.net/jiayanhui2877/article/details/47187077 + //https://blog.csdn.net/xuanshao_/article/details/51679824 + //https://blog.csdn.net/xuanshao_/article/details/51672547 + + var ms = new MemoryStream(); + //写入一个长度字节码 + Action writeLenByte = (len) => { + if (len < 0x80) + { + ms.WriteByte((byte)len); + } + else if (len <= 0xff) + { + ms.WriteByte(0x81); + ms.WriteByte((byte)len); + } + else + { + ms.WriteByte(0x82); + ms.WriteByte((byte)(len >> 8 & 0xff)); + ms.WriteByte((byte)(len & 0xff)); + } + }; + //写入一块数据 + Action writeBlock = (byts) => { + var addZero = (byts[0] >> 4) >= 0x8; + ms.WriteByte(0x02); + var len = byts.Length + (addZero ? 1 : 0); + writeLenByte(len); + + if (addZero) + { + ms.WriteByte(0x00); + } + ms.Write(byts, 0, byts.Length); + }; + //根据后续内容长度写入长度数据 + Func writeLen = (index, byts) => { + var len = byts.Length - index; + + ms.SetLength(0); + ms.Write(byts, 0, index); + writeLenByte(len); + ms.Write(byts, index, len); + + return ms.ToArray(); + }; + + + if (rsa.PublicOnly || convertToPublic) + { + /****生成公钥****/ + var param = rsa.ExportParameters(false); + + + //写入总字节数,不含本段长度,额外需要24字节的头,后续计算好填入 + ms.WriteByte(0x30); + var index1 = (int)ms.Length; + + //固定内容 + // encoded OID sequence for PKCS #1 rsaEncryption szOID_RSA_RSA = "1.2.840.113549.1.1.1" + ms.writeAll(_SeqOID); + + //从0x00开始的后续长度 + ms.WriteByte(0x03); + var index2 = (int)ms.Length; + ms.WriteByte(0x00); + + //后续内容长度 + ms.WriteByte(0x30); + var index3 = (int)ms.Length; + + //写入Modulus + writeBlock(param.Modulus); + + //写入Exponent + writeBlock(param.Exponent); + + + //计算空缺的长度 + var byts = ms.ToArray(); + + byts = writeLen(index3, byts); + byts = writeLen(index2, byts); + byts = writeLen(index1, byts); + + + return "-----BEGIN PUBLIC KEY-----\n" + RSA_Unit.TextBreak(RSA_Unit.Base64EncodeBytes(byts), 64) + "\n-----END PUBLIC KEY-----"; + } + else + { + /****生成私钥****/ + var param = rsa.ExportParameters(true); + + //写入总字节数,后续写入 + ms.WriteByte(0x30); + int index1 = (int)ms.Length; + + //写入版本号 + ms.writeAll(_Ver); + + //PKCS8 多一段数据 + int index2 = -1, index3 = -1; + if (usePKCS8) + { + //固定内容 + ms.writeAll(_SeqOID); + + //后续内容长度 + ms.WriteByte(0x04); + index2 = (int)ms.Length; + + //后续内容长度 + ms.WriteByte(0x30); + index3 = (int)ms.Length; + + //写入版本号 + ms.writeAll(_Ver); + } + + //写入数据 + writeBlock(param.Modulus); + writeBlock(param.Exponent); + writeBlock(param.D); + writeBlock(param.P); + writeBlock(param.Q); + writeBlock(param.DP); + writeBlock(param.DQ); + writeBlock(param.InverseQ); + + + //计算空缺的长度 + var byts = ms.ToArray(); + + if (index2 != -1) + { + byts = writeLen(index3, byts); + byts = writeLen(index2, byts); + } + byts = writeLen(index1, byts); + + + var flag = " PRIVATE KEY"; + if (!usePKCS8) + { + flag = " RSA" + flag; + } + return "-----BEGIN" + flag + "-----\n" + RSA_Unit.TextBreak(RSA_Unit.Base64EncodeBytes(byts), 64) + "\n-----END" + flag + "-----"; + } + } + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Utility/RSA_Unit.cs b/CloudBuilder/CloudBuilder.Core/Utility/RSA_Unit.cs new file mode 100644 index 0000000..7807093 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Utility/RSA_Unit.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace System +{ + /// + /// 封装的一些通用方法 + /// + public class RSA_Unit + { + static public string Base64EncodeBytes(byte[] byts) + { + return Convert.ToBase64String(byts); + } + static public byte[] Base64DecodeBytes(string str) + { + try + { + return Convert.FromBase64String(str); + } + catch + { + return null; + } + } + /// + /// 把字符串按每行多少个字断行 + /// + static public string TextBreak(string text, int line) + { + var idx = 0; + var len = text.Length; + var str = new StringBuilder(); + while (idx < len) + { + if (idx > 0) + { + str.Append('\n'); + } + if (idx + line >= len) + { + str.Append(text.Substring(idx)); + } + else + { + str.Append(text.Substring(idx, line)); + } + idx += line; + } + return str.ToString(); + } + } + + static public class Extensions + { + /// + /// 从数组start开始到指定长度复制一份 + /// + static public T[] sub(this T[] arr, int start, int count) + { + T[] val = new T[count]; + for (var i = 0; i < count; i++) + { + val[i] = arr[start + i]; + } + return val; + } + static public void writeAll(this Stream stream, byte[] byts) + { + stream.Write(byts, 0, byts.Length); + } + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Utility/SerializeHelper.cs b/CloudBuilder/CloudBuilder.Core/Utility/SerializeHelper.cs new file mode 100644 index 0000000..e64570d --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Utility/SerializeHelper.cs @@ -0,0 +1,29 @@ +using System.Text; +using System.Xml.Serialization; + +namespace CloudBuilder.Util +{ + public class SerializeHelper + { + public static string Serialize(object o) + { + if (o == null) return null; + + XmlSerializer serializer = new XmlSerializer(o.GetType()); + + using (MemoryStream stream = new MemoryStream()) + { + StreamWriter writer = new StreamWriter(stream, Encoding.UTF8); + serializer.Serialize((TextWriter)writer, o); + stream.Seek(0L, SeekOrigin.Begin); + StreamReader reader = new StreamReader(stream, Encoding.UTF8); + return reader.ReadToEnd(); + } + } + + public static void WriteAllText(string filePath, object o) + { + File.WriteAllText(filePath, Serialize(o)); + } + } +} diff --git a/CloudBuilder/CloudBuilder.Core/Utility/TableName.cs b/CloudBuilder/CloudBuilder.Core/Utility/TableName.cs new file mode 100644 index 0000000..184c789 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Core/Utility/TableName.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace System +{ + public class TableName + { + public TableName() + { + } + + public const string VALUE = "Value"; + public const string DISPLAY_NAME = "DisplayName"; + public virtual string Selected { get; set; } + public virtual T Value { get; set; } + public virtual string DisplayName { get; set; } + } +} diff --git a/CloudBuilder/CloudBuilder.Gui/AbstractForm.Designer.cs b/CloudBuilder/CloudBuilder.Gui/AbstractForm.Designer.cs new file mode 100644 index 0000000..aef40c7 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/AbstractForm.Designer.cs @@ -0,0 +1,48 @@ +namespace CloudBuilder.Gui +{ + partial class AbstractForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(AbstractForm)); + SuspendLayout(); + // + // AbstractForm + // + AutoScaleDimensions = new SizeF(7F, 15F); + AutoScaleMode = AutoScaleMode.Font; + ClientSize = new Size(984, 661); + Font = new Font("Arial", 9F); + Icon = (Icon)resources.GetObject("$this.Icon"); + Name = "AbstractForm"; + Text = "AbstractForm"; + ResumeLayout(false); + } + + #endregion + } +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Gui/AbstractForm.cs b/CloudBuilder/CloudBuilder.Gui/AbstractForm.cs new file mode 100644 index 0000000..3b0c0e0 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/AbstractForm.cs @@ -0,0 +1,524 @@ +using CloudBuilder.Core.DependencyInjection.Form; +using CloudBuilder.Core.DependencyInjection.Request; +using CloudBuilder.Core.Service; +using CloudBuilder.Gui.DependencyInjection; +using CloudBuilder.Request.Security; +using CloudBuilder.Security.Entity; +using CloudBuilder.Security.Policy; +using CloudBuilder.Security.Utility; +using Krypton.Navigator; +using Krypton.Toolkit; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Reflection; +using System.Resources; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace CloudBuilder.Gui +{ + public partial class AbstractForm : KryptonForm, IForm + { + private LoginContextPermission loginContextPermission; + private SecurityMessagePolicy securityMessagePolicy; + public string SecurityUserId = string.Empty; + public IContext Context; + //public WCFContract Wcf = null; + private object activatedParam; + public bool IsDialog = false; + public object OutputData = null; + public object InputData = null; + + public string ParentFunctionId { get; set; } + public string FunctionId { get; set; } + public object ActivatedParam { get; set; } + + protected GuiBindingContext guiBindingContext; + protected GuiOperateHelper guiOperateHelper = null; + + public KryptonNavigator KryptonNavigator { get; set; } + public Dictionary PageContext = new Dictionary(); + public GuiDisplayMode DisplayMode; + + public AbstractForm() + { + InitializeComponent(); + } + + + public AbstractForm(object param) + : this() + { + activatedParam = param; + } + + public virtual void FunctionActivated(object param) + { + + } + + public virtual void FunctionLoaded() + { + DisplayMode = GuiDisplayMode.View; + + InitResourceManager(); + } + + public string GetTitle(string functionName) + { + try + { + IContext loginContext = ServiceHelper.GetInterfaceService()!; + SecurityFunctionRequest securityFunctionRequest = ServiceHelper.GetTypeService(); + SecurityFunctionEntity function = securityFunctionRequest.FindByFunctionName(functionName); + if (function == null) return null; + return loginContext.GetCulture() == LoginContext.CULTURE_EN ? function.FunctionEngName : function.FunctionLocalName; + } + catch (Exception ex) + { + ShowMessageBox.ShowInfo(ex.Message); + return null; + } + } + + public void InitResourceManager() + { + IContext loginContext = ServiceHelper.GetInterfaceService()!; + string typeName = this.GetType().FullName + "_" + loginContext.GetCulture(); + if (Assembly.GetAssembly(this.GetType()).GetManifestResourceNames().Contains(typeName + ".resources")) + { + ResourceManager rm = new ResourceManager(typeName, Assembly.GetAssembly(this.GetType())); + + GuiOperateHelper.SetControlsText(this, rm); + } + } + + public AbstractForm GetAbstractDialog(string functionViewId) + { + return GetAbstractDialog(functionViewId, null); + } + + public AbstractForm GetAbstractDialog(string functionViewId, object param) + { + //if (ctx == null) ctx = ContextRegistry.GetContext(); + + //AbstractForm v = (AbstractForm)ctx.CreateObject(functionViewId, null, null); + AbstractForm v = new AbstractForm(); + //v.Wcf = new WCFContract(); + + v.IsDialog = true; + + v.FunctionId = functionViewId; + + v.ActivatedParam = param; + + v.FunctionLoaded(); + + v.FunctionActivated(param); + + v.StartPosition = FormStartPosition.CenterScreen; + + InitResourceManager(); + + return v; + } + + public AbstractPage GetAbstractPage() + { + foreach (Control c in this.Controls) + { + if (c is AbstractPage) + { + return (AbstractPage)c; + } + } + return null; + } + + public KryptonPage GetAbstractPage(ToolStripMenuItem sender) + { + KryptonPage af = GetAbstractPage(sender.Name); + af.Text = sender.Text; + + return af; + } + + public KryptonPage GetAbstractPage(string functionViewId) + { + return GetAbstractPage(functionViewId, null); + } + + private KryptonPage GetAbstractPage(string functionViewId, object param) + { + loginContextPermission = new LoginContextPermission(); + IContext loginContext = ServiceHelper.GetInterfaceService()!; + if (!loginContext.Assert(loginContextPermission.AssertByFunctionName, functionViewId)) + { + securityMessagePolicy = ServiceHelper.GetTypeService()!; + throw new ValidationException(securityMessagePolicy.ComposeMessage("no_permission")); + } + + KryptonPage v; + if (!PageContext.Keys.Contains(functionViewId)) + { + v = new KryptonPage(); + AbstractPage page = ServiceHelper.GetBaseTypeService(functionViewId); + page.Dock = DockStyle.Fill; + page.ActivatedParam = param; + page.InitResourceManager(); + page.ParentKryptonPage = v; + page.ParentAbstractForm = this; + v.Controls.Add(page); + + v.Text = GetTitle(functionViewId); + } + else + { + v = PageContext[functionViewId]; + } + + return v; + } + + public KryptonPage GetInitPage(string functionViewId, KryptonNavigator kryptonNavigator, string title, object param) + { + KryptonPage v; + AbstractPage abstractPage = null; ; + if (!PageContext.Keys.Contains(functionViewId)) + { + v = new KryptonPage(); + abstractPage = ServiceHelper.GetBaseTypeService(functionViewId); + abstractPage.Dock = DockStyle.Fill; + abstractPage.ActivatedParam = param; + abstractPage.InitResourceManager(); + abstractPage.ParentAbstractForm = this; + + v.Controls.Add(abstractPage); + + v.Text = title; + } + else + { + v = PageContext[functionViewId]; + + foreach (Control c in v.Controls) + { + if (c is AbstractPage) + { + abstractPage = (AbstractPage)c; + break; + } + } + + } + + v.Text = title; + + abstractPage.FunctionId = functionViewId; + + abstractPage.KryptonNavigator = kryptonNavigator; + + abstractPage.ActivatedParam = param; + + abstractPage.FunctionLoaded(); + + abstractPage.FunctionActivated(param); + + InitResourceManager(); + + return v; + } + + public void DisplayAbstractPage(ToolStripMenuItem sender, KryptonNavigator kryptonNavigator) + { + DisplayAbstractPage(sender.Name, sender.Text, null, kryptonNavigator); + } + + public void DisplayAbstractPage(string functionViewId) + { + DisplayAbstractPage(functionViewId, null); + } + + public void DisplayAbstractPage(string functionViewId, string title, object param, KryptonNavigator kryptonNavigator) + { + //deselecting page1,selecting page 2,deselected page1,selected page2,selectedpagechanged page2 + ////如果没有权限返回 + KryptonPage af = GetAbstractPage(functionViewId, param); + AbstractPage page = null; + foreach (Control c in af.Controls) + { + if (c is AbstractPage) + { + page = (AbstractPage)c; + break; + } + } + + if (!string.IsNullOrEmpty(title)) + { + af.Text = title; + } + else + { + af.Text = GetTitle(functionViewId); + } + + if (!PageContext.Keys.Contains(functionViewId)) + { + page.FunctionLoaded(); + + kryptonNavigator.Pages.Add(af); + + PageContext.Add(functionViewId, af); + } + + if (page == null) return; + + page.KryptonNavigator = kryptonNavigator; + + af.Visible = true; + kryptonNavigator.SelectedPage = af; + + kryptonNavigator.Focus(); + + kryptonNavigator.SelectedPage.Focus(); + + page.FunctionActivated(param); + } + + public void DisplayAbstractPage(string functionViewId, string title, object param) + { + DisplayAbstractPage(functionViewId, title, param, this.KryptonNavigator); + } + + public void DisplayAbstractPage(string functionViewId, string title) + { + DisplayAbstractPage(functionViewId, title, null, this.KryptonNavigator); + } + + public virtual KryptonNavigator GetKryptonNavigator() + { + return null; + } + + public virtual void Print() + { + + } + + public static void SetMid(Form form) + { + // Center the Form on the user's screen everytime it requires a Layout. + form.SetBounds((Screen.GetBounds(form).Width / 2) - (form.Width / 2), + (Screen.GetBounds(form).Height / 2) - (form.Height / 2), + form.Width, form.Height, BoundsSpecified.Location); + } + + public DialogResult ShowFormDialog() + { + return this.ShowFormDialog(null, false); + } + + public DialogResult ShowFormDialog(string title) + { + return this.ShowFormDialog(title, false); + } + + public DialogResult ShowFormDialog(string title, bool topMost) + { + IsDialog = true; + + if (!string.IsNullOrEmpty(title)) + this.Text = title; + + this.TopMost = topMost; + + this.ShowDialog(); + + return DialogResult; + } + public virtual DialogResult ShowDialog(object inputData) + { + return ShowDialog(null, inputData); + } + + public virtual DialogResult ShowDialog(string title, object inputData) + { + this.InputData = inputData; + + return this.ShowFormDialog(title); + } + + public virtual DialogResult ShowViewDialog(object inputData) + { + return ShowViewDialog(null, inputData); + } + + public virtual DialogResult ShowViewDialog(string title, object inputData) + { + this.InputData = inputData; + this.GetAbstractPage().InitInputData(inputData, GuiDisplayMode.View); + + DialogResult dr = this.ShowFormDialog(title); + if (DialogResult.OK != dr) return dr; + if (this.OutputData == null) + this.OutputData = this.GetAbstractPage().GetOutputData(); + + return dr; + } + + public virtual DialogResult ShowCreateDialog() + { + return ShowCreateDialog(null); + } + + public virtual DialogResult ShowCreateDialog(string title) + { + this.GetAbstractPage().InitInputData(null, GuiDisplayMode.Create); + + DialogResult dr = this.ShowFormDialog(title); + if (DialogResult.OK != dr) return dr; + + if (this.OutputData == null) + this.OutputData = this.GetAbstractPage().GetOutputData(); + + return dr; + } + + public virtual DialogResult ShowCreateDialog(string title, object inputData) + { + this.InputData = inputData; + + this.GetAbstractPage().InitInputData(inputData, GuiDisplayMode.Create); + + DialogResult dr = this.ShowFormDialog(title); + if (DialogResult.OK != dr) return dr; + + if (this.OutputData == null) + this.OutputData = this.GetAbstractPage().GetOutputData(); + + return dr; + } + + public virtual DialogResult ShowAmendDialog(object inputData) + { + return ShowAmendDialog(null, inputData); + } + + public virtual DialogResult ShowAmendDialog(string title, object inputData) + { + this.InputData = inputData; + this.GetAbstractPage().InitInputData(inputData, GuiDisplayMode.Amend); + DialogResult dr = this.ShowFormDialog(title); + if (DialogResult.OK != dr) return dr; + + if (this.OutputData == null) + this.OutputData = this.GetAbstractPage().GetOutputData(); + + return dr; + } + + public new void Show() + { + Show(null); + } + + public void Show(string title) + { + IsDialog = true; + + this.Text = title; + + this.ShowFormDialog(); + } + + /// + /// 元参数传入HandleException(() => Save()); + /// + /// + public void HandleException(Action action) + { + try + { + action(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + /// + /// 有参数传入 + /// + /// + /// + /// + public void HandleException(Action action, T param) + { + try + { + action(param); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + /// + /// 有参数传入,且有返回值 + /// + /// + /// + /// + /// + /// + public R HandleException(Func action, T param) + { + try + { + return action(param); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + + return default(R)!; + } + } +} + + diff --git a/CloudBuilder/CloudBuilder.Gui/AbstractForm.resx b/CloudBuilder/CloudBuilder.Gui/AbstractForm.resx new file mode 100644 index 0000000..3a1d295 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/AbstractForm.resx @@ -0,0 +1,216 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + AAABAAIAICAAAAEAIACoEAAAJgAAABAQAAABACAAaAQAAM4QAAAoAAAAIAAAAEAAAAABACAAAAAAAIAQ + AAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAAAsAAAALAAAACwAAAAsAAAALAAAACwAAAAsAAAALAAAACwAA + AAsAAAALAAAACwAAAAsoKCgpr66tu6+trbmuray5rq2sua6sqrmuq6m5raqoua2pp7mtqKe5r6mnt66p + p7euqKa3rqilt66opbeuqKW3rqimt4SAf4vb2tn/2dbV/9jW1f/Y1tT/2NbU/9jV1P/Y1dT/2NXT/9jV + 0//Y1NP/19TT/9fU0v/X1NL/19TS/726uf/l4+L/5ePi/+Ti4f/k4eD/4+De/+Pe3f/i3dv/4t3a/+Lb + 2f/i2tj/4drX/+HZ1v/h2dX/4dnV/+HZ1f/h2dX/qqWjv+bk4//9+Pb//Pj2//z49f/89/X//Pf0//v2 + 9P/79fP/+/Xy//v18v/69PH/+vTw//r08P/68+//2tTR//78+//9+/r//fr5//35+P/8+Pb//Pf0//v1 + 8//79PL/+vPw//ry7//68u7/+fHt//nx7f/58e3/+fHt//nx7f+7tbO/5uTj//z59//x4s3/5sqg/+bL + of/lyp7/5cme/97Qu//c2dj/2dbV/9jW1f/Y1tT/2NXU/9jV1P++vLr//vz7//77+v/9+/n//fr4//z4 + 9v/89/X/+/bz//v18v/79PH/+vPw//ry7//68u7/+fHu//nx7f/58e3/+vHu/7u2s7/m5OP//Pn3/+bL + ov/OmEP/z5tH/82ZQf/NmUL/z7SK//349v/9+Pb//Pj1//z49f/89/T/+/b0/9vX1f/+/Pv//vz7//37 + +v/9+vn/7uvp/+7q6P/u6ef/7ejm/+3n5P/t5uT/7OXj/+Xe3P/68u//+vLu//ry7//68u//u7a0v+bk + 5P/9+fn/58yl/9CbSv/Rn1D/06RY/9OkWP/RupT//Pn3//z59//8+fb//Pj2//z49f/89/T/3NjV//78 + /P/+/Pv//fv6//36+f/v6+r/9fHw/+7q6P/08O3/7ejl/+3n5P/t5uT/7Obj//rz8P/68/D/+vPw//rz + 8P+7t7W/5uXk//36+f/nzaX/z5tJ/9SmXP/Rnk7/0J1L/9C2jv/8+ff//Pn3//z59//8+fb//Pj1//z4 + 9f/c2NX//v38//78+//++/v//fv6/+/s6//18vD/7uro//Xw7v/t6eb/7ejl/+3n5f/t5+T/+/Tx//v0 + 8f/79PH/+/Tx/7y4tr/m5eT//fv5/+jOp//RnUz/1ade/9GeTv/QnEz/0LaO//35+f/9+fn//fn4//Tv + 7P/s5eH/6+Tg/87IxP/+/fz//vz8//78+//9+/r/9vPy/+/s6v/u6+n/7uro/+7q6P/u6ef/7ejm/+3o + 5v/79fP/+/Xz//v18//79fP/vLi3v+bm5f/9/Pr/6M+o/9GeTv/VqGD/0Z9Q/9CdTf/Qt4///fr5//36 + +f/9+vn/9O/t/+zl4v/r5eH/z8nF//79/f/+/fz//vz7//78+//9+/r//fr5//35+P/8+ff//Pj2//z3 + 9f/89/X//Pf0//z29P/89vT//Pb0//z39P+9ubi/5ubl//38+//oz6n/0Z1N/9aoYP/Rn1D/0J1N/9C2 + j//9+/n//fv5//36+f/08O3/7Obi/+zl4f/Oycb/9/b2//f29v/39vX/9/X0//f08//29PP/9vPy//bz + 8f/28vH/9fLw//Xx7//18e//9fHv//Xx7//18e//9fHv/7OxsL/m5uX//f37/+nRq//ToVX/16tm/9Oi + Vv/SoFP/0biS//38+v/9/Pr//fv6//Tx7f/s5+L/7Obi/8/Jxv/w8O//8O/v//Dv7v/w7+7/8O7t//Dt + 7f/v7ez/7+3s/+/s6//v7Ov/7+zq/+/r6v/u6+r/7uvq/+7r6v/v6+r/tLKxv+fm5v/+/f3/6dGs/9Kf + Uf/XqWP/06BT/9KfUP/RuJD//fz7//38+//9/Pr/9PHu/+zn4v/s5uL/z8nG/9nY2P/Z2Nf/2NfX/9jX + 1//Y19b/2NbV/9jW1f/Y1dX/19XV/9fV1f/X1dT/19XU/9fV1P/X1dT/19XU/9fV1P+lo6O/5+bm//79 + /f/q0q7/1aNZ/9mtav/VpVr/1KNY/9K6lP/9/fv//f37//38+//08e//7Ofj/+zn4v/Pysb/5eTk/87N + zf/Y2Nf/2NfX//79/P/+/Pz//vz7//78+//++/v//fv6//38+//9+/r//fv6//37+f/w7u3/4+Hh/62r + q7/n5+b///79/+vSrv/Volf/2axp/9WkWf/Uolf/0rmU//79/f/+/f3//v38//Ty8f/s5+T/7Ofk/87K + x//l5OT/5eTk/+Xk5P/k5OT/5OTk/+Tk4//k5OP/5OPj/+Tj4//k4+P/5OTk/+Tj4//k4+P/5OPj/+Tj + 4//k4+P/rq2tv+fn5//+/v7/69Ow/9akXP/arm3/16Ze/9WkW//Su5b//v39//79/f/+/f3/9fLx/+zo + 5f/s5+X/zsrI/+Xl5f/l5eX/5eXl/+Xl5f/l5eX/srKy/9HR0f/R0dH/0dHR/9HR0f+yrar/1M/M/9vX + 1f/b19T/29bU/5OTk5suLi4j5+fn//7+/v/r07H/1qNb/9qta//WpFz/1aNZ/9O6lf///v3///79//79 + /f/18vH/7Ojm/+zo5f/X09H/zs3M/87NzP/Lysj/y8nI/8vJyP+6uLf/y8nI/8vJyP/Lycf/y8jH/83H + w//z7en/+/b0//v28//79fL/tbW1hwAAAAXn5+f//////+3Vs//Zp2L/3LBy/9mnY//YpmD/1LuY//7+ + /v/+/v7//v39//Xy8f/s6Ob/7Ojm/+zo5f/08vD/9PLw/+zn5P/s5+P/7Ofi/+zm4v/s5eL/7OXi/+vl + 4f/r5OD/6+Tf//Pt6v/89/T/+/b0//v29P+3t7eHAAAABefn5///////7NSy/9ekXv/brm//2KVg/9ek + Xf/Tupb//v7+//7+/v/+/v7/9fPx/+zo5v/s6Ob/7Ojm//Xy8f/18vH/7Ofk/+zn5P/s5+P/7Ofi/+zm + 4v/s5uL/7OXi/+zl4f/r5eH/9O7r//z49f/89/T/+/b0/7m5uYcAAAAF5+fn///////t1bX/2qhl/96y + d//etHn/3rJ3/9jEqP///////////////v/29PL/7enm/+zo5v/s6Ob/9fLx//Xy8f/s6OX/7Ofk/+zn + 5P/s5+P/7Ofi/+zm4v/s5uL/7OXi/+zl4f/07+v//Pj1//z49f/89/T/u7y7hwAAAAXn5+f//////+3U + tP/ZpmH/3a9y/9mmYf/YpV//1LqY///////////////+//Xz8//s6eb/7Onm/+zo5v/18vH/9fLx/+zo + 5v/s6OX/7Ojk/+zn5P/s5+T/7Obj/+zm4v/s5eH/7OXh//Tv7P/8+ff//Pn2//z49v+9vb2HAAAABefn + 5///////7dW2/9upZ//esnf/26pp/9qpZ//VvZz/////////////////9vTz/+zq5v/t6eb/7Onm//Xz + 8f/18/H/7Ojm/+zo5f/s5+X/7Ofj/ezo5P3s5+P/7Obi/+zl4f/r5OH/9O/s+/z59/n8+ff7/Pj2+76+ + vocAAAAF5+fn///////t1bX/2qdk/96xdf/aqWb/2qdk/9W8m//////////////////29PP/7enm/+zp + 5v/s6eb/9fTx//Xz8f/t6uf/7ern/+3q5//t6uf/7ern/+zo5f/s5+P97Obh/+vk4f/z7+v//Pj1//z4 + 9f/89/T/wMC/hwAAAAXn5+f//////+7Vt//bqGf/3rJ3/9uqav/bqWf/1b2c//////////////////b0 + 8//t6uf/7Onn/+zp5//19PL/9fTy/+3q5//t6uf/7ern/+3q5//t6uf/7Orm/+zp5f/s6OP97Ojk//Tx + 7v/8+ff//Pn2//j29P/BwcGHAAAABefn5///////7ta3/9upaf/fsnn/3Ktr/9uqaf/VvZ3///////// + //////////////////////////////////////////////////////////////////////////////// + /////////fz8//v6+f/4+Pj/8vLy/8LCwocAAAAF5+fn///////u1bf/26hp/9+yef/drG7/3Ktt/9fC + pf/////////////////29PP/7ern/+3q5//t6uf/7ern/+3q5//t6uf/7ern/+3q5//t6uf/7ern/+zp + 5v/r6OX/6ebj/+rn5P/y8e//+fn5//Pz8//r6+v/w8PDhwAAAAPn5+f//////+7WuP/cqmz/3q5y/9+y + ef/gtX7/28u1//////////////////b08//t6uf/7ern/+3q5//t6uf/7ern/+3q5//t6uf/7ern/+3q + 5//s6eb/6ufk/+rn5P/j4N3/4N3a/+nn5v/t7e3/4+Pj/8/Pz//a2tp/////Aefn5///////7ta3/9yo + af/dq2z/3Klp/9ypav/VvZ3/////////////////9vTz/+3q5//t6uf/7ern/+3q5//t6uf/7ern/+3q + 5//t6uf/6+jl/+rn5P/q5+T/6ufk/8LAv/++vr7/v7+//7q6uv++vr7/29vbv////wH///8B5+fn//// + ///269z/7tW3/+7WuP/u1rf/7ta4/9/TxP/////////////////29PP/7ern/+3q5//t6uf/7ern/+3q + 5//t6uf/7ern/+3q5//r5+X/6ufk/+vn5f/r5+X/wL69//7+/v/39/f/4eLi/+Li4r////8B////Af// + /wHn5+f/////////////////////////////////5+fn//////////////////////////////////// + //////////////////////////////z8/P/8/Pz//Pz8//r6+v/FxcX/9vb2/+Dg4P/i4uK/////Af// + /wH///8B////AeLi4v/u7u7/7u7u/+7u7v/u7u7/7u7u/+7u7v/f39////////////////////////// + /////////////////////////////////////////f39//39/f/6+vr/9fX1/8PDw//i4uL/5eXlv/// + /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////AdDQ0H////////////// + ///////////////////////////////////////////////////+/v7/+/v7//X19f/t7e3/ysrK/+Tk + 5L////8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B1NTUf+/v + 7//u7u7/7u7u/+7u7v/u7u7/7u7u/+7u7v/u7u7/7u7u/+7u7v/u7u7/7u7u/+3t7f/q6ur/5ubm/+Hh + 4f/c3Ny/////Af///wH///8B////Af///wH///8B////AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAABAAAAAgAAAAAQAgAAAA + AABABAAAAAAAAAAAAAAAAAAAAAAAANTS0YPPzcyFz8zLhc/My4XPzMqFzsvKhc7LyYW/vby5zszL3c3K + yd3MyMbdy8bE3czFw9vLxcHby8TB27awrsHx7uz/9OfW//Hhyv/u4dD/6ubk/+nl4//p5OL/5eLg//37 + +v/8+ff/+/b0//r08f/68u//+fHt//nx7f/f19Tf8e7u/9uzdf/QnUz/0Ktu//z49v/8+PX//Pf0/+zq + 6P/9+/r/9fPx/+/r6f/u6ef/7Obk//Hq5//68u//39nW3/Hw7v/ctXj/0qJW/9Cpbf/8+fj/+vb0//Tu + 6//p5uT//vz7//j19P/w7ev/7+vp/+3o5v/07uv/+/Xy/+Db2d/x8e//3LZ7/9OjWP/Qqm7//fr5//j1 + 8//r5eH/5OHf//r5+P/6+Pf/+fb1//n19P/49PL/+PTy//jz8f/d2dff8vHx/964f//VpVz/0axx//38 + +v/49vT/7Obi/9rW1f/k4+P/5OLi/+Th4f/j4eD/4+Df/+Pg3//j4N//y8nI3/Ly8f/guoP/16hh/9Ou + df/9/fz/+ff2/+zn4//Z19X/3Nvb/+fn5//x8O//8e/v//Hv7//w7+7/7evr/8zLy9/y8vL/4buG/9ip + ZP/Ur3j//v39//n39//s5+X/1tTS/9nY1//Y19b/wsHA/87NzP/Hw8H/5+Lf/+vm4/+UlZRT8/Pz/+K9 + if/aq2n/1bB7//7+/v/5+Pf/7Ojm//Dt6//w7Or/7Ofj/+zm4v/r5eH/6+Tg//jy7//79vT/s7OzRfPz + 8//jvoz/3K9x/9i1hf//////+vn4/+zp5v/w7ev/8O3r/+zn5P/s5+P/7Obi/+zl4f/49PH//Pj1/7a3 + tkXz8/P/5L6O/9ytb//XsoD///////r5+f/s6eb/8e7r//Hu7P/s6Ob/7Ojl/ezn4//r5eH/+PTx/fz4 + 9v26urlF8/Pz/+S/j//drnH/2LOC///////8/Pz/9fTz//j29f/49/X/9vTz//b08//19PL/9fPx//r4 + 9v/49vX/vLy8RfPz8//lv5H/3q91/9y7kf//////+vn5/+3q5//t6uf/7ern/+3q5//s6eb/6ufk/+Xi + 3//w7+//5OTk/8zMzEPz8/P/68+t/+XAkf/fxKH///////r5+f/t6uf/7ern/+3q5//t6uf/6ufk/+rn + 5P/Pz87/1NTU/9LS0p////8B7e3t//b29v/29vb/7e3t//////////////////////////////////z8 + /P/5+fn/2NjY/+Li4p////8B////Af///wH///8B////AdLS0kH29vb/9vb2//b29v/29vb/9vb2//b2 + 9v/09PT/6urq/9fX15////8B////Af///wEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Gui/AbstractPage.Designer.cs b/CloudBuilder/CloudBuilder.Gui/AbstractPage.Designer.cs new file mode 100644 index 0000000..8eae6b8 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/AbstractPage.Designer.cs @@ -0,0 +1,47 @@ +namespace CloudBuilder.Gui +{ + partial class AbstractPage + { + /// + /// 設計工具所需的變數。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清除任何使用中的資源。 + /// + /// 如果應該處置 Managed 資源則為 true,否則為 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 元件設計工具產生的程式碼 + + /// + /// 此為設計工具支援所需的方法 - 請勿使用程式碼編輯器修改 + /// 這個方法的內容。 + /// + private void InitializeComponent() + { + this.SuspendLayout(); + // + // AbstractPage + // + this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Font = new System.Drawing.Font("Arial", 9F); + this.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); + this.Name = "AbstractPage"; + this.Size = new System.Drawing.Size(1024, 800); + this.ResumeLayout(false); + + } + + #endregion + } +} diff --git a/CloudBuilder/CloudBuilder.Gui/AbstractPage.cs b/CloudBuilder/CloudBuilder.Gui/AbstractPage.cs new file mode 100644 index 0000000..189de30 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/AbstractPage.cs @@ -0,0 +1,429 @@ +using CloudBuilder.Core.DependencyInjection.Form; +using CloudBuilder.Core.DependencyInjection.Request; +using CloudBuilder.Core.Service; +using CloudBuilder.Gui.DependencyInjection; +using CloudBuilder.Request.Security; +using CloudBuilder.Security.Entity; +using CloudBuilder.Security.Policy; +using CloudBuilder.Security.Utility; +using Krypton.Navigator; +using Krypton.Toolkit; +using Microsoft.Extensions.DependencyInjection; +using System.ComponentModel.DataAnnotations; +using System.Reflection; +using System.Resources; + +namespace CloudBuilder.Gui +{ + public partial class AbstractPage : UserControl, IForm + { + public AbstractPage() + { + InitializeComponent(); + } + + private LoginContextPermission loginContextPermission; + private SecurityMessagePolicy securityMessagePolicy; + public string SecurityUserId = string.Empty; + public IContext Context; + //public WCFContract Wcf = null; + private object activatedParam; + public bool IsDialog = false; + public object OutputData = null; + public object InputData = null; + + public AbstractForm ParentAbstractForm { get; set; } + public KryptonPage ParentKryptonPage { get; set; } + + public string FunctionId { get; set; } + public object ActivatedParam { get; set; } + + protected GuiBindingContext guiBindingContext; + protected GuiOperateHelper guiOperateHelper = null; + public KryptonNavigator KryptonNavigator { get; set; } + + public GuiDisplayMode DisplayMode; + + + public AbstractPage(object param) + : this() + { + activatedParam = param; + } + + public virtual void FunctionActivated(object param) + { + + } + + public virtual void FunctionSelected() + { + + } + + public virtual void FunctionLoaded() + { + DisplayMode = GuiDisplayMode.View; + + InitResourceManager(); + } + public virtual void Shown() + { + + } + + public virtual bool FunctionDeactivating() + { + return true; + } + + public string GetTitle(string functionName) + { + try + { + IContext loginContext = ServiceHelper.GetInterfaceService()!; + SecurityFunctionRequest securityFunctionRequest = ServiceHelper.GetTypeService(); + SecurityFunctionEntity function = securityFunctionRequest.FindByFunctionName(functionName); + if (function == null) return null; + return loginContext.GetCulture() == LoginContext.CULTURE_EN ? function.FunctionEngName : function.FunctionLocalName; + } + catch (Exception ex) + { + ShowMessageBox.ShowInfo(ex.Message); + return null; + } + } + + public void InitResourceManager() + { + IContext loginContext = ServiceHelper.GetInterfaceService()!; + string typeName = this.GetType().FullName + "_" + loginContext.GetCulture(); + if (Assembly.GetAssembly(this.GetType()).GetManifestResourceNames().Contains(typeName + ".resources")) + { + ResourceManager rm = new ResourceManager(typeName, Assembly.GetAssembly(this.GetType())); + + GuiOperateHelper.SetControlsText(this, rm); + } + } + + public AbstractForm GetAbstractDialog(string functionViewId) + { + return GetAbstractDialog(functionViewId, null); + } + + public AbstractForm GetAbstractDialog(string functionViewId, object param) + { + AbstractForm v = new AbstractForm(); + + AbstractPage page = ServiceHelper.GetBaseTypeService(functionViewId); + v.Size = new Size(page.Size.Width + 28, page.Size.Height + 38); + + page.Dock = DockStyle.Fill; + page.ActivatedParam = param; + page.InitResourceManager(); + page.ParentAbstractForm = v; + + page.IsDialog = true; + + page.FunctionId = functionViewId; + + page.ActivatedParam = param; + + page.FunctionLoaded(); + + page.FunctionActivated(param); + page.AutoSize = true; + page.AutoSizeMode = AutoSizeMode.GrowAndShrink; + page.BackColor = Color.White; + + page.FunctionSelected(); + + v.Controls.Add(page); + + v.Text = GetTitle(functionViewId); + v.AutoSize = true; + v.StartPosition = FormStartPosition.CenterScreen; + v.MaximizeBox = false; + v.MinimizeBox = false; + v.PaletteMode = PaletteMode.Office2010Silver; + v.FormClosing += page.FormClosing; + v.Shown += page.Shown; + return v; + } + + private void Shown(object sender,EventArgs e) + { + this.Showned(); + } + + public virtual void Showned() + { + + } + + private void FormClosing(object sender, FormClosingEventArgs e) + { + this.FormClosing(); + } + //窗口关闭时,自动释放内存 + public virtual void FormClosing() + { + var provider = ServiceHelper.GetService(); + provider.RemoveControlBinding(this.Controls); + } + + public virtual void InitInputData(object param, GuiDisplayMode mode) + { + + } + + public virtual object GetOutputData() + { + return null; + } + + public KryptonPage GetAbstractPage(ToolStripMenuItem sender) + { + KryptonPage af = GetAbstractPage(sender.Name); + af.Text = sender.Text; + + return af; + } + + public KryptonPage GetAbstractPage(string functionViewId) + { + return GetAbstractPage(functionViewId, null); + } + + private KryptonPage GetAbstractPage(string functionViewId, object param) + { + loginContextPermission = new LoginContextPermission(); + IContext loginContext = ServiceHelper.GetInterfaceService()!; + if (!loginContext.Assert(loginContextPermission.AssertByFunctionName, functionViewId)) + { + securityMessagePolicy = ServiceHelper.GetTypeService()!; + throw new ValidationException(securityMessagePolicy.ComposeMessage("no_permission")); + } + + KryptonPage v; + if (!ParentAbstractForm.PageContext.Keys.Contains(functionViewId)) + { + v = new KryptonPage(); + AbstractPage page = ServiceHelper.GetBaseTypeService(functionViewId); + page.Dock = DockStyle.Fill; + page.ActivatedParam = param; + page.InitResourceManager(); + page.ParentKryptonPage = v; + page.ParentAbstractForm = ParentAbstractForm; + v.Controls.Add(page); + + v.Text = GetTitle(functionViewId); + } + else + { + v = ParentAbstractForm.PageContext[functionViewId]; + } + + return v; + } + + public KryptonPage GetInitPage(string functionViewId, KryptonNavigator kryptonNavigator, string title, object param) + { + KryptonPage v; + AbstractPage page = null; ; + if (!ParentAbstractForm.PageContext.Keys.Contains(functionViewId)) + { + v = new KryptonPage(); + page = ServiceHelper.GetBaseTypeService(functionViewId); + page.Dock = DockStyle.Fill; + page.ActivatedParam = param; + page.InitResourceManager(); + + v.Controls.Add(page); + + v.Text = title; + } + else + { + v = ParentAbstractForm.PageContext[functionViewId]; + + foreach (Control c in v.Controls) + { + if (c is AbstractPage) + { + page = (AbstractPage)c; + break; + } + } + + } + + v.Text = title; + + page.FunctionId = functionViewId; + + page.KryptonNavigator = kryptonNavigator; + + page.ActivatedParam = param; + + page.FunctionLoaded(); + + page.FunctionActivated(param); + + InitResourceManager(); + + return v; + } + + public void DisplayAbstractPage(ToolStripMenuItem sender, KryptonNavigator kryptonNavigator) + { + DisplayAbstractPage(sender.Name, sender.Text, null, kryptonNavigator); + } + + public void DisplayAbstractPage(string functionViewId) + { + DisplayAbstractPage(functionViewId, null); + } + + public void DisplayAbstractPage(string functionViewId, string title, object param, KryptonNavigator kryptonNavigator) + { + //deselecting page1,selecting page 2,deselected page1,selected page2,selectedpagechanged page2 + ////如果没有权限返回 + KryptonPage af = GetAbstractPage(functionViewId, param); + af.Visible = true; + + AbstractPage page = GetAbstractPage(af); + + + if (!string.IsNullOrEmpty(title)) af.Text = title; + + if (!ParentAbstractForm.PageContext.Keys.Contains(functionViewId)) + { + page.FunctionLoaded(); + page.ParentKryptonPage = af; + + kryptonNavigator.Pages.Add(af); + + ParentAbstractForm.PageContext.Add(functionViewId, af); + } + + page.FunctionActivated(param); + + page.KryptonNavigator = kryptonNavigator; + + kryptonNavigator.SelectedPage = af; + } + + public AbstractPage GetAbstractPage(KryptonPage af) + { + foreach (Control c in af.Controls) + { + if (c is AbstractPage) + { + return (AbstractPage)c; + } + } + return null; + } + + public void DisplayAbstractPage(string functionViewId, string title, object param) + { + DisplayAbstractPage(functionViewId, title, param, this.KryptonNavigator); + } + + public void DisplayAbstractPage(string functionViewId, object param) + { + DisplayAbstractPage(functionViewId, null, param, this.KryptonNavigator); + } + + public void DisplayAbstractPage(string functionViewId, string title) + { + DisplayAbstractPage(functionViewId, title, null, this.KryptonNavigator); + } + + public virtual KryptonNavigator GetKryptonNavigator() + { + return null; + } + + public AbstractForm GetMainForm() + { + return ParentAbstractForm; + } + + public virtual void Print() + { + + } + + public static void SetMid(Form form) + { + // Center the Form on the user's screen everytime it requires a Layout. + form.SetBounds((Screen.GetBounds(form).Width / 2) - (form.Width / 2), + (Screen.GetBounds(form).Height / 2) - (form.Height / 2), + form.Width, form.Height, BoundsSpecified.Location); + } + + public void HandleException(Action action) + { + try + { + action(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + public void HandleException(Action action,T param) + { + try + { + action(param); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + public R HandleException(Func action, T param) + { + try + { + return action(param); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + + return default(R)!; + } + } +} diff --git a/CloudBuilder/CloudBuilder.Gui/AbstractPage.resx b/CloudBuilder/CloudBuilder.Gui/AbstractPage.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/AbstractPage.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Gui/BindingContextAttributeProvider.cs b/CloudBuilder/CloudBuilder.Gui/BindingContextAttributeProvider.cs new file mode 100644 index 0000000..1c9fc99 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/BindingContextAttributeProvider.cs @@ -0,0 +1,589 @@ +using Krypton.Toolkit; +using Microsoft.AspNetCore.Authorization; +using System; +using System.Collections; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using static System.Windows.Forms.Control; + +namespace CloudBuilder.Gui +{ + public class BindingContextAttributeProvider + { + private readonly ConcurrentDictionary m_props = + new ConcurrentDictionary(); + + private readonly ConcurrentDictionary m_prop_column_s = + new ConcurrentDictionary(); + + public BindingContextCustomAttribute GetCustomAttribute(DataGridViewColumn ctrl) + { + m_prop_column_s.TryGetValue(ctrl, out var attribute); + + if (attribute == null) SetCustomAttribute(ctrl); + + m_prop_column_s.TryGetValue(ctrl, out attribute); + + return attribute; + } + + public BindingContextCustomAttribute GetCustomAttribute(Control ctrl) + { + m_props.TryGetValue(ctrl, out var attribute); + + if (attribute == null) SetCustomAttribute(ctrl); + + m_props.TryGetValue(ctrl, out attribute); + + return attribute; + } + + public bool HasCustomAttribute(Control ctrl) + { + m_props.TryGetValue(ctrl, out var attribute); + + if (attribute == null) return false; + + return true; + } + + public bool HasCustomAttribute(DataGridViewColumn ctrl) + { + m_prop_column_s.TryGetValue(ctrl, out var attribute); + + if (attribute == null) return false; + + return true; + } + + public void RemoveControlBinding(DataGridViewColumn ctrl) + { + m_prop_column_s.TryRemove(ctrl, out _); + } + + public void RemoveControlBinding(ControlCollection ctrl) + { + if (ctrl.Count > 0) + { + foreach (Control childCtrl in ctrl) + { + RemoveControlBinding(childCtrl); + if (childCtrl.Controls.Count > 0) + { + RemoveControlBinding(childCtrl.Controls); + } + } + } + } + public void RemoveControlBinding(Control ctrl) + { + m_props.TryRemove(ctrl, out _); + } + + public void RemoveControlBinding(params Control[] ctrls) + { + foreach (var ctrl in ctrls) + { + RemoveControlBinding(ctrl); + } + } + + + #region SetCustomAttribute + + #region DataGridViewColumn + public void SetCustomAttribute(DataGridViewColumn ctrl) + { + BindingContextCustomAttribute bindingContext = new BindingContextCustomAttribute(); + m_prop_column_s.AddOrUpdate(ctrl, bindingContext, (key, oldValue) => bindingContext); + } + + public void SetCustomAttribute(DataGridViewColumn ctrl, BindingContextCustomAttribute bindingContext) + { + m_prop_column_s.AddOrUpdate(ctrl, bindingContext, (key, oldValue) => bindingContext); + } + + public void SetCustomAttribute(DataGridViewColumn ctrl, EnumEditModeColor editModeColor) + { + var attribute = m_prop_column_s.AddOrUpdate(ctrl, + // 如果键不存在,创建新属性 + key => new BindingContextCustomAttribute + { + EditModeColor = editModeColor + }, + // 如果键存在,更新属性 + (key, existing) => + { + existing.EditModeColor = editModeColor; + return existing; + }); + } + + + public void SetCustomAttribute(DataGridViewColumn ctrl, string bindDataName, EnumEditModeColor editModeColor) + { + var attribute = m_prop_column_s.AddOrUpdate(ctrl, + // 如果键不存在,创建新属性 + key => new BindingContextCustomAttribute + { + BindDataName = bindDataName, + BindDirection = EnumBindDirection.Both, + EditModeColor = editModeColor + }, + // 如果键存在,更新属性 + (key, existing) => + { + existing.BindDataName = bindDataName; + existing.BindDirection = EnumBindDirection.Both; + existing.EditModeColor = editModeColor; + return existing; + }); + } + + public void SetCustomAttribute(DataGridViewColumn ctrl, string bindDataName, string bindFormat, EnumEditModeColor editModeColor) + { + var attribute = m_prop_column_s.AddOrUpdate(ctrl, + // 如果键不存在,创建新属性 + key => new BindingContextCustomAttribute + { + BindDataName = bindDataName, + BindFormat = bindFormat, + EditModeColor = editModeColor + }, + // 如果键存在,更新属性 + (key, existing) => + { + existing.BindDataName = bindDataName; + existing.BindFormat = bindFormat; + existing.EditModeColor = editModeColor; + return existing; + }); + } + + public void SetCustomAttribute(DataGridViewColumn ctrl, string bindDataName, EnumBindDirection bindDirection, EnumEditModeColor editModeColor) + { + var attribute = m_prop_column_s.AddOrUpdate(ctrl, + // 如果键不存在,创建新属性 + key => new BindingContextCustomAttribute + { + BindDataName = bindDataName, + BindDirection = bindDirection, + EditModeColor = editModeColor + }, + // 如果键存在,更新属性 + (key, existing) => + { + existing.BindDirection = bindDirection; + existing.BindDataName = bindDataName; + existing.EditModeColor = editModeColor; + return existing; + }); + } + + public void SetCustomAttribute(DataGridViewColumn ctrl, string bindDataName, EnumBindDirection bindDirection) + { + var attribute = m_prop_column_s.AddOrUpdate(ctrl, + // 如果键不存在,创建新属性 + key => new BindingContextCustomAttribute + { + BindDataName = bindDataName, + BindDirection = bindDirection + }, + // 如果键存在,更新属性 + (key, existing) => + { + existing.BindDirection = bindDirection; + existing.BindDataName = bindDataName; + return existing; + }); + } + + public void SetCustomAttribute(DataGridViewColumn ctrl, string bindDataName, string bindFormat, EnumBindDirection bindDirection) + { + var attribute = m_prop_column_s.AddOrUpdate(ctrl, + // 如果键不存在,创建新属性 + key => new BindingContextCustomAttribute + { + BindDataName = bindDataName, + BindFormat = bindFormat, + BindDirection = bindDirection, + }, + // 如果键存在,更新属性 + (key, existing) => + { + existing.BindDirection = bindDirection; + existing.BindDataName = bindDataName; + existing.BindFormat = bindFormat; + return existing; + }); + } + + public void SetCustomAttribute(DataGridViewColumn ctrl, string permissionName, Operate permissionMode) + { + var attribute = m_prop_column_s.AddOrUpdate(ctrl, + // 如果键不存在,创建新属性 + key => new BindingContextCustomAttribute + { + PermissionName = permissionName, + PermissionMode = permissionMode, + }, + // 如果键存在,更新属性 + (key, existing) => + { + existing.PermissionName = permissionName; + existing.PermissionMode = permissionMode; + return existing; + }); + } + + public void SetCustomAttribute(DataGridViewColumn ctrl, string permissionName, string dependentDetailName, Operate permissionMode) + { + var attribute = m_prop_column_s.AddOrUpdate(ctrl, + // 如果键不存在,创建新属性 + key => new BindingContextCustomAttribute + { + PermissionName = permissionName, + DependentDetailName = dependentDetailName, + PermissionMode = permissionMode, + }, + // 如果键存在,更新属性 + (key, existing) => + { + existing.PermissionName = permissionName; + existing.DependentDetailName = dependentDetailName; + existing.PermissionMode = permissionMode; + return existing; + }); + } + + public void SetCustomAttribute(DataGridViewColumn ctrl, string permissionName, string dependentDetailName) + { + var attribute = m_prop_column_s.AddOrUpdate(ctrl, + // 如果键不存在,创建新属性 + key => new BindingContextCustomAttribute + { + PermissionName = permissionName, + DependentDetailName = dependentDetailName, + }, + // 如果键存在,更新属性 + (key, existing) => + { + existing.PermissionName = permissionName; + existing.DependentDetailName = dependentDetailName; + return existing; + }); + } + + + public void SetCustomAttribute(DataGridViewColumn ctrl, DataTable dataTableSource, DataTable deleteDataTableSource) + { + var attribute = m_prop_column_s.AddOrUpdate(ctrl, + // 如果键不存在,创建新属性 + key => new BindingContextCustomAttribute + { + DataTableSource = dataTableSource, + DeleteDataTableSource = deleteDataTableSource, + }, + // 如果键存在,更新属性 + (key, existing) => + { + existing.DataTableSource = dataTableSource; + existing.DeleteDataTableSource = deleteDataTableSource; + return existing; + }); + } + + #endregion + + #region Control + public void SetCustomAttribute(Control ctrl) + { + BindingContextCustomAttribute bindingContext = new BindingContextCustomAttribute(); + m_props.AddOrUpdate(ctrl, bindingContext, (key, oldValue) => bindingContext); + } + public void SetCustomAttribute(Control ctrl, BindingContextCustomAttribute bindingContext) + { + m_props.AddOrUpdate(ctrl, bindingContext, (key, oldValue) => bindingContext); + } + + public void SetCustomAttribute(Control ctrl, EnumEditModeColor editModeColor) + { + var attribute = m_props.AddOrUpdate(ctrl, + // 如果键不存在,创建新属性 + key => new BindingContextCustomAttribute + { + EditModeColor = editModeColor + }, + // 如果键存在,更新属性 + (key, existing) => + { + existing.EditModeColor = editModeColor; + return existing; + }); + } + + public void SetCustomAttribute(Control ctrl, EnumEditModeColor editModeColor, string bindDisplayName) + { + var attribute = m_props.AddOrUpdate(ctrl, + // 如果键不存在,创建新属性 + key => new BindingContextCustomAttribute + { + BindDisplayName = bindDisplayName, + EditModeColor = editModeColor + }, + // 如果键存在,更新属性 + (key, existing) => + { + existing.EditModeColor = editModeColor; + existing.BindDisplayName = bindDisplayName; + return existing; + }); + } + + + public void SetCustomAttribute(Control ctrl, string bindDataName, EnumEditModeColor editModeColor) + { + var attribute = m_props.AddOrUpdate(ctrl, + // 如果键不存在,创建新属性 + key => new BindingContextCustomAttribute + { + BindDataName = bindDataName, + EditModeColor = editModeColor + }, + // 如果键存在,更新属性 + (key, existing) => + { + existing.BindDataName = bindDataName; + existing.EditModeColor = editModeColor; + return existing; + }); + } + + public void SetCustomAttribute(Control ctrl, string bindDataName, string bindFormat, string bindDisplayName, EnumEditModeColor editModeColor) + { + var attribute = m_props.AddOrUpdate(ctrl, + // 如果键不存在,创建新属性 + key => new BindingContextCustomAttribute + { + BindDataName = bindDataName, + BindFormat = bindFormat, + BindDisplayName = bindDisplayName, + EditModeColor = editModeColor + }, + // 如果键存在,更新属性 + (key, existing) => + { + existing.BindDataName = bindDataName; + existing.BindFormat = bindFormat; + existing.BindDisplayName = bindDisplayName; + existing.EditModeColor = editModeColor; + return existing; + }); + } + + public void SetCustomAttribute(Control ctrl, string bindDataName, string bindDisplayName, EnumEditModeColor editModeColor) + { + var attribute = m_props.AddOrUpdate(ctrl, + // 如果键不存在,创建新属性 + key => new BindingContextCustomAttribute + { + BindDataName = bindDataName, + BindDisplayName = bindDisplayName, + EditModeColor = editModeColor + }, + // 如果键存在,更新属性 + (key, existing) => + { + existing.BindDataName = bindDataName; + existing.BindDisplayName = bindDisplayName; + existing.EditModeColor = editModeColor; + return existing; + }); + } + + public void SetCustomAttribute(Control ctrl, string bindDataName, EnumBindDirection bindDirection, EnumEditModeColor editModeColor) + { + var attribute = m_props.AddOrUpdate(ctrl, + // 如果键不存在,创建新属性 + key => new BindingContextCustomAttribute + { + BindDataName = bindDataName, + BindDirection = bindDirection, + EditModeColor = editModeColor + }, + // 如果键存在,更新属性 + (key, existing) => + { + existing.BindDirection = bindDirection; + existing.BindDataName = bindDataName; + existing.EditModeColor = editModeColor; + return existing; + }); + } + + public void SetCustomAttribute(Control ctrl, string bindDataName, EnumBindDirection bindDirection) + { + var attribute = m_props.AddOrUpdate(ctrl, + // 如果键不存在,创建新属性 + key => new BindingContextCustomAttribute + { + BindDataName = bindDataName, + BindDirection = bindDirection + }, + // 如果键存在,更新属性 + (key, existing) => + { + existing.BindDirection = bindDirection; + existing.BindDataName = bindDataName; + return existing; + }); + } + + public void SetCustomAttribute(Control ctrl, string bindDataName, string bindDisplayName, EnumBindDirection bindDirection) + { + var attribute = m_props.AddOrUpdate(ctrl, + // 如果键不存在,创建新属性 + key => new BindingContextCustomAttribute + { + BindDataName = bindDataName, + BindDisplayName = bindDisplayName, + BindDirection = bindDirection + }, + // 如果键存在,更新属性 + (key, existing) => + { + existing.BindDirection = bindDirection; + existing.BindDisplayName = bindDisplayName; + existing.BindDataName = bindDataName; + return existing; + }); + } + + + public void SetCustomAttribute(Control ctrl, string bindDataName, string bindFormat, string bindDisplayName, EnumBindDirection bindDirection) + { + var attribute = m_props.AddOrUpdate(ctrl, + // 如果键不存在,创建新属性 + key => new BindingContextCustomAttribute + { + BindDataName = bindDataName, + BindFormat = bindFormat, + BindDisplayName = bindDisplayName, + BindDirection = bindDirection, + }, + // 如果键存在,更新属性 + (key, existing) => + { + existing.BindDirection = bindDirection; + existing.BindDataName = bindDataName; + existing.BindDisplayName = bindDisplayName; + existing.BindFormat = bindFormat; + return existing; + }); + } + + public void SetCustomAttribute(Control ctrl, string permissionName, Operate permissionMode) + { + var attribute = m_props.AddOrUpdate(ctrl, + // 如果键不存在,创建新属性 + key => new BindingContextCustomAttribute + { + PermissionName = permissionName, + PermissionMode = permissionMode, + }, + // 如果键存在,更新属性 + (key, existing) => + { + existing.PermissionName = permissionName; + existing.PermissionMode = permissionMode; + return existing; + }); + } + + public void SetCustomAttribute(Control ctrl, string permissionName, string dependentDetailName, Operate permissionMode) + { + var attribute = m_props.AddOrUpdate(ctrl, + // 如果键不存在,创建新属性 + key => new BindingContextCustomAttribute + { + PermissionName = permissionName, + DependentDetailName = dependentDetailName, + PermissionMode = permissionMode, + }, + // 如果键存在,更新属性 + (key, existing) => + { + existing.PermissionName = permissionName; + existing.DependentDetailName = dependentDetailName; + existing.PermissionMode = permissionMode; + return existing; + }); + } + + public void SetCustomAttribute(Control ctrl, string permissionName, string dependentDetailName) + { + var attribute = m_props.AddOrUpdate(ctrl, + // 如果键不存在,创建新属性 + key => new BindingContextCustomAttribute + { + PermissionName = permissionName, + DependentDetailName = dependentDetailName, + }, + // 如果键存在,更新属性 + (key, existing) => + { + existing.PermissionName = permissionName; + existing.DependentDetailName = dependentDetailName; + return existing; + }); + } + + + public void SetCustomAttribute(Control ctrl, List dataSource, DataTable dataTableSource, DataTable deleteDataTableSource) + { + var attribute = m_props.AddOrUpdate(ctrl, + // 如果键不存在,创建新属性 + key => new BindingContextCustomAttribute + { + DataSource = dataSource, + DataTableSource = dataTableSource, + DeleteDataTableSource = deleteDataTableSource, + }, + // 如果键存在,更新属性 + (key, existing) => + { + existing.DataSource = dataSource; + existing.DataTableSource = dataTableSource; + existing.DeleteDataTableSource = deleteDataTableSource; + return existing; + }); + } + #endregion + + #endregion + + // IExtenderProvider interface + public bool CanExtend(object extendee) + { + // Exclude myself and not Control class + return (extendee is KryptonTextBox || + extendee is KryptonComboBox || + extendee is KryptonDataGridView || + extendee is KryptonDataGridView || + extendee is KryptonCheckBox || + extendee is KryptonDateTimePicker || + extendee is KryptonMaskedTextBox || + extendee is KryptonCheckedListBox || + extendee is KryptonListBox || + extendee is KryptonRadioButton || + extendee is KryptonButton + ); + } + } +} diff --git a/CloudBuilder/CloudBuilder.Gui/CloudBuilder.Gui.csproj b/CloudBuilder/CloudBuilder.Gui/CloudBuilder.Gui.csproj new file mode 100644 index 0000000..e1e7883 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/CloudBuilder.Gui.csproj @@ -0,0 +1,60 @@ + + + + Library + net8.0-windows + enable + true + enable + + + + ..\CloudBuilder.Core\bin\Debug\net8.0\CloudBuilder.Core.dll + + + ..\CloudBuilder.Request\bin\Debug\net8.0\CloudBuilder.Request.dll + + + ..\CloudBuilder.Security\bin\Debug\net8.0\CloudBuilder.Security.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + True + True + Resources.resx + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + + + diff --git a/CloudBuilder/CloudBuilder.Gui/CloudBuilder.Gui.csproj.user b/CloudBuilder/CloudBuilder.Gui/CloudBuilder.Gui.csproj.user new file mode 100644 index 0000000..17198df --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/CloudBuilder.Gui.csproj.user @@ -0,0 +1,24 @@ + + + + + + Form + + + UserControl + + + UserControl + + + Form + + + Form + + + Form + + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Gui/DataGridViewColumn.cs b/CloudBuilder/CloudBuilder.Gui/DataGridViewColumn.cs new file mode 100644 index 0000000..508625c --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/DataGridViewColumn.cs @@ -0,0 +1,98 @@ +using CloudBuilder.Core.Utility; +using Krypton.Toolkit; +using Microsoft.AspNetCore.Authorization; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace CloudBuilder.Gui +{ + public static partial class DataGridViewColumnExtensions + { + public static void Set(this DataGridViewColumn dataGridViewColumn, + BindingContextCustomAttribute bindingContext) + { + if (bindingContext != null && !string.IsNullOrEmpty(bindingContext.BindDataName)) dataGridViewColumn.DataPropertyName = bindingContext.BindDataName; + GetProvider().SetCustomAttribute(dataGridViewColumn, bindingContext); + } + + public static void Set(this DataGridViewColumn dataGridViewColumn, + EnumEditModeColor editModeColor) + { + GetProvider().SetCustomAttribute(dataGridViewColumn, editModeColor); + } + + public static void Set(this DataGridViewColumn dataGridViewColumn, + string bindDataName, + EnumEditModeColor editModeColor) + { + if (!string.IsNullOrEmpty(bindDataName)) dataGridViewColumn.DataPropertyName = bindDataName; + GetProvider().SetCustomAttribute(dataGridViewColumn, bindDataName, editModeColor); + } + + public static void Set(this DataGridViewColumn dataGridViewColumn, + string bindDataName) + { + if (!string.IsNullOrEmpty(bindDataName)) dataGridViewColumn.DataPropertyName = bindDataName; + //GetProvider().SetCustomAttribute(dataGridViewColumn, bindDataName, EnumBindDirection.Both); + } + + public static void Set(this DataGridViewColumn dataGridViewColumn, + string bindDataName, + EnumBindDirection bindDirection) + { + if (!string.IsNullOrEmpty(bindDataName)) dataGridViewColumn.DataPropertyName = bindDataName; + GetProvider().SetCustomAttribute(dataGridViewColumn, bindDataName, bindDirection); + } + + + public static void Set(this DataGridViewColumn dataGridViewColumn, + string bindDataName, + EnumBindDirection bindDirection, + EnumEditModeColor editModeColor) + { + if (!string.IsNullOrEmpty(bindDataName)) dataGridViewColumn.DataPropertyName = bindDataName; + GetProvider().SetCustomAttribute(dataGridViewColumn, bindDataName, bindDirection, editModeColor); + } + + public static void Set(this DataGridViewColumn dataGridViewColumn, + string bindDataName, + string bindFormat, + EnumBindDirection bindDirection) + { + if (!string.IsNullOrEmpty(bindDataName)) dataGridViewColumn.DataPropertyName = bindDataName; + GetProvider().SetCustomAttribute(dataGridViewColumn, bindDataName, bindFormat, bindDirection); + } + + public static void Set(this DataGridViewColumn dataGridViewColumn, + string permissionName, + Operate permissionMode) + { + GetProvider().SetCustomAttribute(dataGridViewColumn, permissionName, permissionMode); + } + + public static void Set(this DataGridViewColumn dataGridViewColumn, string permissionName, string dependentDetailName, Operate permissionMode) + { + GetProvider().SetCustomAttribute(dataGridViewColumn, permissionName, dependentDetailName, permissionMode); + } + + public static void Set(this DataGridViewColumn dataGridViewColumn, string permissionName, string dependentDetailName) + { + GetProvider().SetCustomAttribute(dataGridViewColumn, permissionName, dependentDetailName); + } + + public static BindingContextCustomAttribute GetCustomAttribute(this DataGridViewColumn dataGridViewColumn) + { + return GetProvider().GetCustomAttribute(dataGridViewColumn); + } + + private static BindingContextAttributeProvider GetProvider() + { + return ServiceHelper.GetService() ?? + throw new InvalidOperationException("BindingContextAttributeProvider is not registered in the service GetProvider()."); + } + } +} diff --git a/CloudBuilder/CloudBuilder.Gui/DataGridViewComboBoxColumnExtensions.cs b/CloudBuilder/CloudBuilder.Gui/DataGridViewComboBoxColumnExtensions.cs new file mode 100644 index 0000000..ce46a1e --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/DataGridViewComboBoxColumnExtensions.cs @@ -0,0 +1,143 @@ +using CloudBuilder.Core.Utility; +using Krypton.Toolkit; +using Microsoft.AspNetCore.Authorization; +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace CloudBuilder.Gui +{ + public static class DataGridViewComboBoxColumnExtensions + { + public static void SetDataSource(this DataGridViewComboBoxColumn dataGridViewComboBoxColumn, T[] ds, string displayMember, string valueMember, bool blankOption) + { + dataGridViewComboBoxColumn.DisplayStyle = DataGridViewComboBoxDisplayStyle.Nothing; + dataGridViewComboBoxColumn.DataSource = null; + DataTable dataTableSource = new DataTable(); + + if (ds == null) + { + return; + } + //首先將entity轉為datatable + dataTableSource = DataTableConvertor.ToDataTable(ds, blankOption); + + dataGridViewComboBoxColumn.DataSource = dataTableSource; + dataGridViewComboBoxColumn.DisplayMember = displayMember; + dataGridViewComboBoxColumn.ValueMember = valueMember; + + dataTableSource.AcceptChanges(); + + } + + public static void SetDataSource(this DataGridViewComboBoxColumn dataGridViewComboBoxColumn, TableName[] values, bool blankOption) + { + dataGridViewComboBoxColumn.SetDataSource>(values, TableName.DISPLAY_NAME, TableName.VALUE, blankOption); + } + public static void SetDataSource(this DataGridViewComboBoxColumn dataGridViewComboBoxColumn, List ds, string displayMember, string valueMember, bool blankOption) + { + dataGridViewComboBoxColumn.DataSource = null; + DataTable dataTableSource = new DataTable(); + //DataTable deleteDataTableSource = new DataTable(); + + if (ds == null) + { + return; + } + + dataTableSource = DataTableConvertor.ToDataTable(ds, blankOption); + + dataGridViewComboBoxColumn.DataSource = dataTableSource; + + dataGridViewComboBoxColumn.DisplayMember = displayMember; + dataGridViewComboBoxColumn.ValueMember = valueMember; + + dataTableSource.AcceptChanges(); + + //deleteDataTableSource = dataTableSource.Clone(); + } + + + public static void Set(this DataGridViewComboBoxColumn dataGridViewComboBoxColumn, + BindingContextCustomAttribute bindingContext) + { + GetProvider().SetCustomAttribute(dataGridViewComboBoxColumn, bindingContext); + } + + public static void Set(this DataGridViewComboBoxColumn dataGridViewComboBoxColumn, + EnumEditModeColor editModeColor) + { + GetProvider().SetCustomAttribute(dataGridViewComboBoxColumn, editModeColor); + } + + public static void Set(this DataGridViewComboBoxColumn dataGridViewComboBoxColumn, + string bindDataName, + EnumEditModeColor editModeColor) + { + GetProvider().SetCustomAttribute(dataGridViewComboBoxColumn, bindDataName, editModeColor); + } + + public static void Set(this DataGridViewComboBoxColumn dataGridViewComboBoxColumn, + string bindDataName) + { + GetProvider().SetCustomAttribute(dataGridViewComboBoxColumn, bindDataName, EnumBindDirection.Both); + } + + public static void Set(this DataGridViewComboBoxColumn dataGridViewComboBoxColumn, + string bindDataName, + EnumBindDirection bindDirection) + { + GetProvider().SetCustomAttribute(dataGridViewComboBoxColumn, bindDataName, bindDirection); + } + + + public static void Set(this DataGridViewComboBoxColumn dataGridViewComboBoxColumn, + string bindDataName, + EnumBindDirection bindDirection, + EnumEditModeColor editModeColor) + { + GetProvider().SetCustomAttribute(dataGridViewComboBoxColumn, bindDataName, bindDirection, editModeColor); + } + + public static void Set(this DataGridViewComboBoxColumn dataGridViewComboBoxColumn, + string bindDataName, + string bindFormat, + EnumBindDirection bindDirection) + { + GetProvider().SetCustomAttribute(dataGridViewComboBoxColumn, bindDataName, bindFormat, bindDirection); + } + + public static void Set(this DataGridViewComboBoxColumn dataGridViewComboBoxColumn, + string permissionName, + Operate permissionMode) + { + GetProvider().SetCustomAttribute(dataGridViewComboBoxColumn, permissionName, permissionMode); + } + + public static void Set(this DataGridViewComboBoxColumn dataGridViewComboBoxColumn, string permissionName, string dependentDetailName, Operate permissionMode) + { + GetProvider().SetCustomAttribute(dataGridViewComboBoxColumn, permissionName, dependentDetailName, permissionMode); + } + + public static void Set(this DataGridViewComboBoxColumn dataGridViewComboBoxColumn, string permissionName, string dependentDetailName) + { + GetProvider().SetCustomAttribute(dataGridViewComboBoxColumn, permissionName, dependentDetailName); + } + + + public static BindingContextCustomAttribute GetCustomAttribute(this DataGridViewComboBoxColumn dataGridViewComboBoxColumn) + { + return GetProvider().GetCustomAttribute(dataGridViewComboBoxColumn); + } + + private static BindingContextAttributeProvider GetProvider() + { + return ServiceHelper.GetService() ?? + throw new InvalidOperationException("BindingContextAttributeProvider is not registered in the service GetProvider()."); + } + } +} diff --git a/CloudBuilder/CloudBuilder.Gui/DependencyInjection/GuiPack.cs b/CloudBuilder/CloudBuilder.Gui/DependencyInjection/GuiPack.cs new file mode 100644 index 0000000..841e5e3 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/DependencyInjection/GuiPack.cs @@ -0,0 +1,50 @@ +using CloudBuilder.Core.Application.Builders; +using CloudBuilder.Core.Application.Packs; +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.DependencyInjection.Form; +using CloudBuilder.Core.DependencyInjection.Request; +using CloudBuilder.Core.Policy; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Gui.DependencyInjection +{ + [PackLevel(100)] + public class GuiPack : CloudBuilderPack + { + /// + /// 获取 模块级别 + /// + public override PackLevel Level => PackLevel.Business; + + /// + /// 获取 模块启动顺序,模块启动的顺序先按级别启动,级别内部再按此顺序启动 + /// + public override int Order => 2; + + /// + /// 将窗体和用户控件添加到依赖注入服务容器中 + /// + /// 依赖注入服务容器 + /// + public override IServiceCollection AddServices(IServiceCollection services, CloudBuilderBuilder builder) + { + services.TryAddSingleton(); + + services.TryAddSingleton(); + + services.TryAddSingleton(); + + services.TryAddSingleton(); + + return services; + } + + + } +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Gui/DependencyInjection/LocaleMessageManager.cs b/CloudBuilder/CloudBuilder.Gui/DependencyInjection/LocaleMessageManager.cs new file mode 100644 index 0000000..1b27703 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/DependencyInjection/LocaleMessageManager.cs @@ -0,0 +1,97 @@ +using CloudBuilder.Core.DependencyInjection.Request; +using CloudBuilder.Core.Policy; +using CloudBuilder.Request.Security; +using CloudBuilder.Security.Entity; +using DocumentFormat.OpenXml.Wordprocessing; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Resources; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Gui.DependencyInjection +{ + public class LocaleMessageManager : ILocaleMessageManager + { + public LocaleEntity[] LocaleEntities { get; set; } = null!; + + public static string SYSTEM = "system"; + + public static string GUI_OK = "ok"; + public static string GUI_CANCEL = "cancel"; + public static string GUI_INFORMATION = "gui_information"; + public static string GUI_ERROR = "gui_error"; + private readonly IServiceProvider serviceProvider; + private readonly IContext context; + + public LocaleMessageManager(IServiceProvider serviceProvider, IContext context) + { + this.serviceProvider = serviceProvider; + this.context = context; + } + + public void InitLocale() + { + LocaleRequest localeRequest = serviceProvider.GetRequiredKeyedService(typeof(LocaleRequest).Name); + + LocaleEntities = localeRequest.FindAll().OrderBy(x => x.OrderBy).ToArray(); + } + + public string ComposeMessage(string groupName, string name) + { + if (LocaleEntities == null || LocaleEntities.Length == 0) + { + InitLocale(); + } + + if (LocaleEntities == null || LocaleEntities.Length == 0) return null!; + + return LocaleEntities.Where(x => x.GroupName == groupName && x.Name == name && x.Lang == context.GetCulture()).Select(x => x.Value).FirstOrDefault()!; + } + public TableName[] GetDataSource(string groupName) + { + if (LocaleEntities == null || LocaleEntities.Length == 0) + { + InitLocale(); + } + + if (LocaleEntities == null || LocaleEntities.Length == 0) return null!; + + string[] values = LocaleEntities.Where(x => x.GroupName == groupName && x.Lang == context.GetCulture()).OrderBy(x => x.OrderBy).Select(x => x.Name).ToArray(); + + if (values == null || values.Length == 0) return null!; + + return GetComposeMessages(groupName, values); + } + + public TableName[] GetComposeMessages(string groupName, T[] values) + { + if (values == null || values.Length == 0) return null; + TableName tb = null; + List> list = new List>(); + foreach (T v in values) + { + tb = new TableName(); + tb.DisplayName = ComposeMessage(groupName, v.ToString()); + tb.Value = v; + list.Add(tb); + } + + return list.ToArray(); + } + } +} + +/* +INSERT INTO [dbo].[locale]([created_datetime],[created_by],[updated_datetime],[updated_by],[group_name],[lang],[name],[value],[order]) VALUES +(GETDATE(),'patch',GETDATE(),'patch','system','zh-cn','gui_error',N'出错信息',0), +(GETDATE(),'patch',GETDATE(),'patch','system','en','gui_error',N'Error Message',0), +(GETDATE(),'patch',GETDATE(),'patch','system','zh-cn','gui_information',N'验证信息',0), +(GETDATE(),'patch',GETDATE(),'patch','system','en','gui_information',N'Verification Message',0) + +="(GETDATE(),'patch',GETDATE(),'patch','"&$A$1&"','zh-cn','"&A2&"',N'"&B2&"',0)," +="(GETDATE(),'patch',GETDATE(),'patch','"&$A$1&"','en','"&A2&"',N'"&B2&"',0)," + */ diff --git a/CloudBuilder/CloudBuilder.Gui/DependencyInjection/SecurityMasterManager.cs b/CloudBuilder/CloudBuilder.Gui/DependencyInjection/SecurityMasterManager.cs new file mode 100644 index 0000000..9a62dd2 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/DependencyInjection/SecurityMasterManager.cs @@ -0,0 +1,76 @@ +using CloudBuilder.Core.Policy; +using CloudBuilder.Request.Security; +using CloudBuilder.Security.Entity; +using DocumentFormat.OpenXml.InkML; +using DocumentFormat.OpenXml.Wordprocessing; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Gui.DependencyInjection +{ + public class SecurityMasterManager : ISecurityMasterManager + { + public SecurityMasterEntity[]? SecurityMasterEntities { get; set; } + private readonly IServiceProvider serviceProvider; + + public SecurityMasterManager(IServiceProvider serviceProvider) + { + this.serviceProvider = serviceProvider; + } + + public dynamic GetSecurityMaster(string category, string subcategory, string codeItem) + { + if (SecurityMasterEntities == null || SecurityMasterEntities.Length == 0) + { + InitSecurityMaster(); + } + + if (SecurityMasterEntities == null || SecurityMasterEntities.Length == 0) return null!; + + return SecurityMasterEntities.Where(x => x.MasterCategory == category && x.MasterSubcategory == subcategory && x.MasterCodeItem == codeItem).FirstOrDefault()!; + } + + public string GetValue(string category, string subcategory, string codeItem) + { + if (SecurityMasterEntities == null || SecurityMasterEntities.Length == 0) + { + InitSecurityMaster(); + } + + if (SecurityMasterEntities == null || SecurityMasterEntities.Length == 0) return null!; + + return SecurityMasterEntities.Where(x => x.MasterCategory == category && x.MasterSubcategory == subcategory && x.MasterCodeItem == codeItem).Select(x => x.Value).FirstOrDefault()!; + } + + public void InitSecurityMaster() + { + SecurityMasterRequest securityMasterRequest = serviceProvider.GetRequiredKeyedService(typeof(SecurityMasterRequest).Name); + + SecurityMasterEntities = securityMasterRequest.FindAll().ToArray(); + } + + public void SetSecurityMaster(string category, string subcategory, string codeItem, string value) + { + SecurityMasterRequest securityMasterRequest = serviceProvider.GetRequiredKeyedService(typeof(SecurityMasterRequest).Name); + SecurityMasterEntity securityMasterEntity = new SecurityMasterEntity() + { + CreatedBy = string.Empty, + UpdatedBy = string.Empty, + CreatedDatetime = DateTime.Now, + UpdatedDatetime = DateTime.Now + }; + + securityMasterEntity.MasterCategory = category; + securityMasterEntity.MasterSubcategory = subcategory; + securityMasterEntity.MasterCodeItem = codeItem; + securityMasterEntity.Value = value; + securityMasterEntity.ValidIndc = YesNoPolicy.YES; + + securityMasterRequest.Insert(securityMasterEntity); + } + } +} diff --git a/CloudBuilder/CloudBuilder.Gui/Enum.cs b/CloudBuilder/CloudBuilder.Gui/Enum.cs new file mode 100644 index 0000000..f19dd01 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/Enum.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Gui +{ + #region EnumControlState + + /// + /// 控件的绑定流向DataPack写 ,DataBind读 + /// + public enum EnumBindDirection + { + Both,//可读可写 + None,//不读不写 + ReadOnly,//只读 + WriteOnly,//只写 + } + /// + /// 修改控件的的颜色和状态 + /// + public enum EnumEditModeColor + { + None,//非必填 + ReadOnly,//只读 + Required,//必填 + } + #endregion +} +namespace System +{ + public enum GuiDisplayMode + { + View = 0, + Create = 1, + Amend = 2 + } +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Gui/ExDataGridViewInfo.cs b/CloudBuilder/CloudBuilder.Gui/ExDataGridViewInfo.cs new file mode 100644 index 0000000..c543f6b --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/ExDataGridViewInfo.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Gui +{ + [Serializable] + public class ExDataGridViewInfo + { + public DataGridViewColumnsInfo[] ColumnsInfo; + + public string FrozenName { get; set; } + + public ExDataGridViewInfo() + { + } + } + + [Serializable] + public class DataGridViewColumnsInfo + { + public DataGridViewColumnsInfo() + { + } + + public string Name { get; set; } + + public string DisplayIndex { get; set; } + + public string Width { get; set; } + + public string Visiable { get; set; } + } +} diff --git a/CloudBuilder/CloudBuilder.Gui/ExDataGridViewSnapshot.cs b/CloudBuilder/CloudBuilder.Gui/ExDataGridViewSnapshot.cs new file mode 100644 index 0000000..1355e76 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/ExDataGridViewSnapshot.cs @@ -0,0 +1,71 @@ +using CloudBuilder.Core.Utility; +using Krypton.Toolkit; +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Gui +{ + public class ExDataGridViewSnapshot + { + public DataTable DataTableSource; + + public DataTable DeleteDataTableSource; + + public List DataSource; + + public ExDataGridViewSnapshot() + { + + } + + public T[] GetAddRows() where T : new() + { + return GetRows(DataRowState.Added); + } + + + public T[] GetDeleteRows() where T : new() + { + if (DeleteDataTableSource.Rows.Count == 0) return null; + + List l = DataTableConvertor.ConvertToList(DeleteDataTableSource); + + return l.ToArray(); + } + + public T[] GetUpdateRows() where T : new() + { + return GetRows(DataRowState.Modified); + } + + + private T[] GetRows(DataRowState drs) where T : new() + { + if (DataTableSource == null || DataTableSource.Rows.Count == 0) return null; + + DataTable dt = DataTableSource.Clone(); + foreach (DataRowView drv in DataTableSource.DefaultView) + { + if (drv.Row.RowState != drs || drv.Row.RowState == DataRowState.Deleted) continue; + + //drv.Row.AcceptChanges(); + dt.ImportRow(drv.Row); + } + + if (dt.Rows.Count == 0) return null; + + List l = DataTableConvertor.ConvertToList(dt); + + return l.ToArray(); + } + + public List GetAllRows() where T : new() + { + return DataTableConvertor.ConvertToList(DataTableSource); + } + } +} diff --git a/CloudBuilder/CloudBuilder.Gui/ExFormBindingEntry.cs b/CloudBuilder/CloudBuilder.Gui/ExFormBindingEntry.cs new file mode 100644 index 0000000..8bbfd9b --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/ExFormBindingEntry.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Gui +{ + public class ExFormBindingEntry + { + public string BindDataName { get; set; } + public EnumBindDirection BindDirection { get; set; } + public string BindFormat { get; set; } + + public EnumEditModeColor EditModeColor { get; set; } + + public string PermissionMode { get; set; } + public string PermissionName { get; set; } + + public ExFormBindingEntry() + { + + } + + public ExFormBindingEntry(EnumEditModeColor editModeColor, string bindDataName, EnumBindDirection bindDirection, string bindFormat, string permissionMode, string permissionName) + { + EditModeColor = editModeColor; + BindDataName = bindDataName; + BindDirection = bindDirection; + BindFormat = bindFormat; + PermissionMode = permissionMode; + PermissionName = permissionName; + } + } +} diff --git a/CloudBuilder/CloudBuilder.Gui/ExFormSnapshotDifference.cs b/CloudBuilder/CloudBuilder.Gui/ExFormSnapshotDifference.cs new file mode 100644 index 0000000..ed2377f --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/ExFormSnapshotDifference.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Gui +{ + public class ExFormSnapshotDifference + { + public ExFormSnapshotDifferenceEntry[] DiffEntries; + + + public ExFormSnapshotDifference() + { + } + } +} diff --git a/CloudBuilder/CloudBuilder.Gui/ExFormSnapshotDifferenceEntry.cs b/CloudBuilder/CloudBuilder.Gui/ExFormSnapshotDifferenceEntry.cs new file mode 100644 index 0000000..695a102 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/ExFormSnapshotDifferenceEntry.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Gui +{ + public class ExFormSnapshotDifferenceEntry + { + public string ControlName { get; set; } + public string DataPropertyName { get; set; } + public string DisplayName { get; set; } + public string NewDisplayValue { get; set; } + public object NewValue { get; set; } + public string OldDisplayValue { get; set; } + public object OldValue { get; set; } + + // Methods + public ExFormSnapshotDifferenceEntry(string controlName, string displayName, object oldValue, string oldDisplayValue, object newValue, string newDisplayValue) + : this(controlName, displayName, oldValue, oldDisplayValue, newValue, newDisplayValue, null) + { + + } + + public ExFormSnapshotDifferenceEntry(string controlName, string displayName, object oldValue, string oldDisplayValue, object newValue, string newDisplayValue, string dataPropertyName) + { + this.ControlName = controlName; + this.DisplayName = displayName; + this.OldValue = oldValue; + this.OldDisplayValue = oldDisplayValue; + this.NewValue = newValue; + this.NewDisplayValue = newDisplayValue; + this.DataPropertyName = dataPropertyName; + } + } +} diff --git a/CloudBuilder/CloudBuilder.Gui/ExFormSnapshotEntry.cs b/CloudBuilder/CloudBuilder.Gui/ExFormSnapshotEntry.cs new file mode 100644 index 0000000..2e2c315 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/ExFormSnapshotEntry.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Gui +{ + public class ExFormSnapshotEntry + { + public string ControlName { get; set; } + public string DataPropertyName { get; set; } + public string DisplayName { get; set; } + public string DisplayValue { get; set; } + public object Value { get; set; } + + // Methods + public ExFormSnapshotEntry() + { + + } + + public ExFormSnapshotEntry(string controlName, string displayName, object value, string displayValue) + : this(controlName, displayName, value, displayValue, null) + { + } + + public ExFormSnapshotEntry(string controlName, string displayName, object value, string displayValue, string dataPropertyName) + { + ControlName = controlName; + DisplayName = displayName; + DisplayValue = displayValue; + Value = value; + DataPropertyName = dataPropertyName; + } + + private static bool IsNull(object value) + { + if (value == null) return true; + + if (value is string) return string.IsNullOrEmpty((string)value); + + if (value is DBNull) return true; + + return false; + } + + public static bool Compare(object v1, object v2) + { + bool b1 = IsNull(v1); + bool b2 = IsNull(v2); + + if (b1 == b2 && b1 == true) return true; + + return v1.Equals(v2); + } + + public ExFormSnapshotDifferenceEntry Compare(ExFormSnapshotEntry o) + { + if (!Compare(this.Value, o.Value)) + { + return new ExFormSnapshotDifferenceEntry(this.ControlName, this.DisplayName, this.Value, this.DisplayValue, o.Value, o.DisplayValue, this.DataPropertyName); + } + + return null; + } + } +} diff --git a/CloudBuilder/CloudBuilder.Gui/GridViewPagination.Designer.cs b/CloudBuilder/CloudBuilder.Gui/GridViewPagination.Designer.cs new file mode 100644 index 0000000..69590f0 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/GridViewPagination.Designer.cs @@ -0,0 +1,247 @@ +namespace CloudBuilder.Gui +{ + partial class GridViewPagination + { + /// + /// 設計工具所需的變數。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清除任何使用中的資源。 + /// + /// 如果應該處置受控資源則為 true,否則為 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 元件設計工具產生的程式碼 + + /// + /// 此為設計工具支援所需的方法 - 請勿使用程式碼編輯器修改 + /// 這個方法的內容。 + /// + private void InitializeComponent() + { + tableLayoutPanel = new TableLayoutPanel(); + movePreviousBut = new Krypton.Toolkit.KryptonButton(); + printBut = new Krypton.Toolkit.KryptonButton(); + totalLabel = new Krypton.Toolkit.KryptonLabel(); + firstPageBut = new Krypton.Toolkit.KryptonButton(); + moveNextBut = new Krypton.Toolkit.KryptonButton(); + moveLastBut = new Krypton.Toolkit.KryptonButton(); + eachPageLabel = new Krypton.Toolkit.KryptonLabel(); + limitTxt = new Krypton.Toolkit.KryptonTextBox(); + startPageLabel = new Krypton.Toolkit.KryptonLabel(); + recordPageLabel = new Krypton.Toolkit.KryptonLabel(); + totalRecordLabel = new Krypton.Toolkit.KryptonLabel(); + recordLabel = new Krypton.Toolkit.KryptonLabel(); + pageLabel = new Krypton.Toolkit.KryptonLabel(); + tableLayoutPanel.SuspendLayout(); + SuspendLayout(); + // + // tableLayoutPanel + // + tableLayoutPanel.ColumnCount = 19; + tableLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F)); + tableLayoutPanel.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 20F)); + tableLayoutPanel.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel.Controls.Add(movePreviousBut, 12, 0); + tableLayoutPanel.Controls.Add(printBut, 17, 0); + tableLayoutPanel.Controls.Add(totalLabel, 1, 0); + tableLayoutPanel.Controls.Add(firstPageBut, 10, 0); + tableLayoutPanel.Controls.Add(moveNextBut, 13, 0); + tableLayoutPanel.Controls.Add(moveLastBut, 14, 0); + tableLayoutPanel.Controls.Add(eachPageLabel, 4, 0); + tableLayoutPanel.Controls.Add(limitTxt, 5, 0); + tableLayoutPanel.Controls.Add(startPageLabel, 7, 0); + tableLayoutPanel.Controls.Add(recordPageLabel, 6, 0); + tableLayoutPanel.Controls.Add(totalRecordLabel, 2, 0); + tableLayoutPanel.Controls.Add(recordLabel, 3, 0); + tableLayoutPanel.Controls.Add(pageLabel, 9, 0); + tableLayoutPanel.Dock = DockStyle.Fill; + tableLayoutPanel.Location = new Point(0, 0); + tableLayoutPanel.Margin = new Padding(0); + tableLayoutPanel.Name = "tableLayoutPanel"; + tableLayoutPanel.RowCount = 1; + tableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 100F)); + tableLayoutPanel.Size = new Size(700, 30); + tableLayoutPanel.TabIndex = 0; + // + // movePreviousBut + // + movePreviousBut.Location = new Point(535, 3); + movePreviousBut.Name = "movePreviousBut"; + movePreviousBut.Size = new Size(36, 24); + movePreviousBut.TabIndex = 2; + movePreviousBut.Values.Image = Properties.Resources.MovePrevious; + movePreviousBut.Values.Text = ""; + movePreviousBut.Click += movePreviousBut_Click; + // + // printBut + // + printBut.Location = new Point(661, 3); + printBut.Name = "printBut"; + printBut.Size = new Size(36, 24); + printBut.TabIndex = 2; + printBut.Values.Image = Properties.Resources.print; + printBut.Values.Text = ""; + printBut.Click += printBut_Click; + // + // totalLabel + // + totalLabel.Location = new Point(113, 3); + totalLabel.Name = "totalLabel"; + totalLabel.Size = new Size(36, 20); + totalLabel.TabIndex = 0; + totalLabel.Values.Text = "总计"; + // + // firstPageBut + // + firstPageBut.Location = new Point(493, 3); + firstPageBut.Margin = new Padding(20, 3, 3, 3); + firstPageBut.Name = "firstPageBut"; + firstPageBut.Size = new Size(36, 24); + firstPageBut.TabIndex = 2; + firstPageBut.Values.Image = Properties.Resources.MoveFirst; + firstPageBut.Values.Text = ""; + firstPageBut.Click += firstPageBut_Click; + // + // moveNextBut + // + moveNextBut.Location = new Point(577, 3); + moveNextBut.Name = "moveNextBut"; + moveNextBut.Size = new Size(36, 24); + moveNextBut.TabIndex = 2; + moveNextBut.Values.Image = Properties.Resources.MoveNext; + moveNextBut.Values.Text = ""; + moveNextBut.Click += moveNextBut_Click; + // + // moveLastBut + // + moveLastBut.Location = new Point(619, 3); + moveLastBut.Name = "moveLastBut"; + moveLastBut.Size = new Size(36, 24); + moveLastBut.TabIndex = 2; + moveLastBut.Values.Image = Properties.Resources.MoveLast; + moveLastBut.Values.Text = ""; + moveLastBut.Click += moveLastBut_Click; + // + // eachPageLabel + // + eachPageLabel.Location = new Point(241, 3); + eachPageLabel.Margin = new Padding(20, 3, 3, 0); + eachPageLabel.Name = "eachPageLabel"; + eachPageLabel.Size = new Size(36, 20); + eachPageLabel.TabIndex = 0; + eachPageLabel.Values.Text = "每页"; + // + // limitTxt + // + limitTxt.Location = new Point(283, 3); + limitTxt.Margin = new Padding(3, 3, 3, 0); + limitTxt.Name = "limitTxt"; + limitTxt.Size = new Size(60, 23); + limitTxt.TabIndex = 0; + limitTxt.KeyPress += limitTxt_KeyPress; + limitTxt.Validated += limitTxt_Validated; + // + // startPageLabel + // + startPageLabel.Location = new Point(405, 3); + startPageLabel.Margin = new Padding(20, 3, 3, 3); + startPageLabel.Name = "startPageLabel"; + startPageLabel.Size = new Size(45, 23); + startPageLabel.StateNormal.ShortText.Font = new Font("Arial", 12.25F, FontStyle.Bold); + startPageLabel.TabIndex = 0; + startPageLabel.Values.Text = "0 / 0"; + // + // recordPageLabel + // + recordPageLabel.Location = new Point(346, 3); + recordPageLabel.Margin = new Padding(0, 3, 3, 3); + recordPageLabel.Name = "recordPageLabel"; + recordPageLabel.Size = new Size(36, 20); + recordPageLabel.TabIndex = 0; + recordPageLabel.Values.Text = "记录"; + // + // totalRecordLabel + // + totalRecordLabel.Location = new Point(155, 3); + totalRecordLabel.Name = "totalRecordLabel"; + totalRecordLabel.Size = new Size(21, 23); + totalRecordLabel.StateNormal.ShortText.Font = new Font("Arial", 12.25F, FontStyle.Bold); + totalRecordLabel.TabIndex = 0; + totalRecordLabel.Values.Text = "0"; + // + // recordLabel + // + recordLabel.Location = new Point(182, 3); + recordLabel.Name = "recordLabel"; + recordLabel.Size = new Size(36, 20); + recordLabel.TabIndex = 0; + recordLabel.Values.Text = "记录"; + // + // pageLabel + // + pageLabel.Location = new Point(453, 3); + pageLabel.Margin = new Padding(0, 3, 3, 3); + pageLabel.Name = "pageLabel"; + pageLabel.Size = new Size(17, 20); + pageLabel.TabIndex = 0; + pageLabel.Values.Text = "页"; + // + // GridViewPagination + // + AutoScaleDimensions = new SizeF(7F, 17F); + AutoScaleMode = AutoScaleMode.Font; + AutoSizeMode = AutoSizeMode.GrowAndShrink; + Controls.Add(tableLayoutPanel); + Margin = new Padding(0); + Name = "GridViewPagination"; + Size = new Size(700, 30); + tableLayoutPanel.ResumeLayout(false); + tableLayoutPanel.PerformLayout(); + ResumeLayout(false); + } + + #endregion + + private TableLayoutPanel tableLayoutPanel; + private Krypton.Toolkit.KryptonLabel totalLabel; + private Krypton.Toolkit.KryptonLabel startPageLabel; + private Krypton.Toolkit.KryptonLabel eachPageLabel; + private Krypton.Toolkit.KryptonTextBox limitTxt; + private Krypton.Toolkit.KryptonLabel recordPageLabel; + private Krypton.Toolkit.KryptonButton firstPageBut; + private Krypton.Toolkit.KryptonButton movePreviousBut; + private Krypton.Toolkit.KryptonButton moveNextBut; + private Krypton.Toolkit.KryptonButton moveLastBut; + private Krypton.Toolkit.KryptonButton kryptonButton5; + private Krypton.Toolkit.KryptonButton printBut; + private Krypton.Toolkit.KryptonLabel totalRecordLabel; + private Krypton.Toolkit.KryptonLabel recordLabel; + private Krypton.Toolkit.KryptonLabel pageLabel; + } +} diff --git a/CloudBuilder/CloudBuilder.Gui/GridViewPagination.cs b/CloudBuilder/CloudBuilder.Gui/GridViewPagination.cs new file mode 100644 index 0000000..e9a8fba --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/GridViewPagination.cs @@ -0,0 +1,220 @@ +using CloudBuilder.Core.Service; +using Krypton.Toolkit; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace CloudBuilder.Gui +{ + public partial class GridViewPagination : UserControl + { + public event Action OnPaginationChanged; + public event Action OnPrint; + public int Limit { get; set; } = new AbstractSearchCriteria().limit; + private int OrgLimit; + public int CurrentPage { get; set; } = 0; + public int Page { get; set; } = 0; + public int Total { get; set; } = 0; + + public GridViewPagination() + { + InitializeComponent(); + firstPageBut.Enabled = false; + movePreviousBut.Enabled = false; + moveNextBut.Enabled = false; + moveLastBut.Enabled = false; + printBut.Enabled = false; + } + + public void SetLimit(int limit) + { + if (OrgLimit == 0) OrgLimit = limit; + + limitTxt.Text = limit.ToString(); + Limit = limit; + } + + public void SetTotal(int total) + { + this.Total = total; + if (Limit > 0) + this.Page = Convert.ToInt32(Math.Ceiling(total * 1.0 / Limit)); + else + this.Page = 1; + + if (total > 0 && CurrentPage == 0) CurrentPage = 1; + else if (total == 0) CurrentPage = 0; + + totalRecordLabel.Text = Total.ToString(); + startPageLabel.Text = string.Format("{0} / {1}", CurrentPage, Page); + + if (total < 0) return; + else if (total == 0) + { + firstPageBut.Enabled = false; + movePreviousBut.Enabled = false; + moveNextBut.Enabled = false; + moveLastBut.Enabled = false; + printBut.Enabled = false; + } + else if (CurrentPage == 1) + { + firstPageBut.Enabled = false; + movePreviousBut.Enabled = false; + printBut.Enabled = true; + if (Page > CurrentPage) + { + moveNextBut.Enabled = true; + moveLastBut.Enabled = true; + } + else + { + moveNextBut.Enabled = false; + moveLastBut.Enabled = false; + } + } + else if (CurrentPage == Page) + { + moveNextBut.Enabled = false; + moveLastBut.Enabled = false; + printBut.Enabled = true; + if (Page > 1) + { + firstPageBut.Enabled = true; + movePreviousBut.Enabled = true; + } + else + { + firstPageBut.Enabled = false; + movePreviousBut.Enabled = false; + } + } + else + { + firstPageBut.Enabled = true; + movePreviousBut.Enabled = true; + moveNextBut.Enabled = true; + moveLastBut.Enabled = true; + printBut.Enabled = true; + } + + } + + public void Reset() + { + this.Limit = OrgLimit > 0 ? OrgLimit : new AbstractSearchCriteria().limit; + this.CurrentPage = 1; + this.limitTxt.Text = this.Limit.ToString(); + SetTotal(0); + } + + private void limitTxt_Validated(object sender, EventArgs e) + { + if (string.IsNullOrEmpty(this.limitTxt.Text)) + { + this.Limit = 0; + this.CurrentPage = 1; + + LimitChanged(this.Limit); + return; + } + + if (!int.TryParse(limitTxt.Text, out int limit)) return; + + if (this.Limit == limit) return; + + this.Limit = limit; + + this.CurrentPage = 1; + + LimitChanged(this.Limit); + } + + public void LimitChanged(int limit) + { + OnPaginationChanged?.Invoke(); + } + + public void FirstPageChanged() + { + this.CurrentPage = 1; + OnPaginationChanged?.Invoke(); + } + + public void MovePreviousChanged() + { + if (this.CurrentPage - 1 < 0) + { + return; + } + this.CurrentPage -= 1; + OnPaginationChanged?.Invoke(); + } + + public void MoveNextChanged() + { + if (this.CurrentPage + 1 > this.Page) + { + return; + } + this.CurrentPage += 1; + OnPaginationChanged?.Invoke(); + } + public void MoveLastChanged() + { + this.CurrentPage = this.Page; + OnPaginationChanged?.Invoke(); + } + + public void Print() + { + OnPrint?.Invoke(); + // 可以使用limit做其他处理 + } + private void firstPageBut_Click(object sender, EventArgs e) + { + FirstPageChanged(); + } + + private void movePreviousBut_Click(object sender, EventArgs e) + { + MovePreviousChanged(); + } + + private void moveNextBut_Click(object sender, EventArgs e) + { + MoveNextChanged(); + } + + private void moveLastBut_Click(object sender, EventArgs e) + { + MoveLastChanged(); + } + + private void printBut_Click(object sender, EventArgs e) + { + Print(); + } + + private void limitTxt_KeyPress(object sender, KeyPressEventArgs e) + { + // 允许数字、控制字符(退格、删除等) 》》》》负号(如果需要负数) && e.KeyChar != '-' + if (!char.IsControl(e.KeyChar) && !char.IsDigit(e.KeyChar)) + { + e.Handled = true; + } + + // 只允许一个负号,且必须在开头 + //if (e.KeyChar == '-' && ((KryptonTextBox)sender).Text.IndexOf('-') >= 0) + //{ + // e.Handled = true; + //} + } + } +} diff --git a/CloudBuilder/CloudBuilder.Gui/GridViewPagination.resx b/CloudBuilder/CloudBuilder.Gui/GridViewPagination.resx new file mode 100644 index 0000000..8b2ff64 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/GridViewPagination.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Gui/GuiBindingContext.cs b/CloudBuilder/CloudBuilder.Gui/GuiBindingContext.cs new file mode 100644 index 0000000..647e815 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/GuiBindingContext.cs @@ -0,0 +1,421 @@ +using CloudBuilder.Gui.DependencyInjection; +using Krypton.Toolkit; +using Microsoft.AspNetCore.Authorization; +using Microsoft.Extensions.DependencyInjection; +using System.Collections; +using System.Collections.Concurrent; +using System.ComponentModel; +using System.Data; +using System.Data.SqlTypes; +using System.Globalization; +using System.Reflection; + +namespace CloudBuilder.Gui +{ + public class GuiBindingContext + { + private List bindingControls = new List(); + private BindingContextAttributeProvider provider = null!; + public object BindingObject; + + public GuiBindingContext() + { + } + + private static BindingContextAttributeProvider GetProvider() + { + return ServiceHelper.GetService() ?? + throw new InvalidOperationException("BindingContextAttributeProvider is not registered in the service GetProvider()."); + } + + public void BindingControls(params IComponent[] cc) + { + foreach (IComponent c in cc) + { + BindingControls(c); + } + } + + public void BindingControls(List cc) + { + BindingControls(cc.ToArray()); + } + + public void BindingControls(IComponent c) + { + if (!(c is Control)) return; + if (provider == null) provider = GetProvider(); + if (provider.HasCustomAttribute((Control)c) && !bindingControls.Contains((Control)c)) + { + bindingControls.Add((Control)c); + return; + } + + BindingControls(((Control)c).Controls); + } + + public void BindingControls(Control.ControlCollection cc) + { + IEnumerator enumerator = cc.GetEnumerator(); + while (enumerator.MoveNext()) + { + Control current = (Control)enumerator.Current; + BindingControls(current); + } + } + + + public void DataBind(object o, AbstractForm page) + { + BindingControls(page.Controls); + DataBind(o); + } + + public void DataBind(object o, AbstractPage page) + { + BindingControls(page.Controls); + DataBind(o); + } + + public void DataBind(object o) + { + if (o == null) return; + + BindingObject = o; + provider = GetProvider(); + BindingContextCustomAttribute customAttribute = null; + foreach (Control c in bindingControls) + { + customAttribute = provider.GetCustomAttribute(c); + if (customAttribute == null) continue; + //權限綁定時,是沒有BindDataName值的 + if (string.IsNullOrEmpty(customAttribute.BindDataName)) continue; + //只寫和None,不綁定值 + if (customAttribute.BindDirection == EnumBindDirection.None || customAttribute.BindDirection == EnumBindDirection.WriteOnly) continue; + + PropertyInfo pi = BindingObject.GetType().GetProperty(customAttribute.BindDataName); + + if (pi == null) continue; + + var value = pi.GetValue(BindingObject, null); + + SetValue(c, value, customAttribute.BindFormat); + } + } + + public void ResetColor() + { + foreach (Control c in bindingControls) + { + if (!(c is TextBox)) continue; + + //if (System.Drawing.SystemColors.Desktop == customAttribute.BackColor) continue; + + if (!(c is Control)) continue; + + ((Control)c).BackColor = System.Drawing.SystemColors.Control; + } + } + + public void DataPack() + { + if (BindingObject == null) return; + if (bindingControls == null || bindingControls.Count == 0) return; + + object value = null; + BindingContextCustomAttribute customAttribute = null; + + foreach (Control c in bindingControls) + { + customAttribute = provider.GetCustomAttribute(c); + + if (customAttribute == null) continue; + + //權限綁定時,是沒有BindDataName值的 + if (string.IsNullOrEmpty(customAttribute.BindDataName)) continue; + //只读和None,不綁定值 + if (customAttribute.BindDirection == EnumBindDirection.ReadOnly || customAttribute.BindDirection == EnumBindDirection.None) continue; + + PropertyInfo pi = BindingObject.GetType().GetProperty(customAttribute.BindDataName); + + if (pi == null) continue; + + value = GetValue(c, pi.PropertyType.Name, customAttribute.BindFormat); + + //if (value is string && "[continue][N/A]" == (Convert.ToString(value))) continue;//ExRadioButton + + pi.SetValue(BindingObject, value, null); + } + } + + + public void SetValue(Control c, object value, string bindFormat) + { + BindingContextCustomAttribute customAttribute = provider.GetCustomAttribute(c); + if (c is KryptonTextBox) + { + ((KryptonTextBox)c).SetValue(value, customAttribute.BindFormat); + } + else if (c is KryptonComboBox) + { + ((KryptonComboBox)c).SetValue(value); + } + else if (c is KryptonCheckBox) + { + ((KryptonCheckBox)c).SetValue(value); + } + else if (c is KryptonDateTimePicker) + { + ((KryptonDateTimePicker)c).SetValue(value, customAttribute.BindFormat); + } + if (c is KryptonMaskedTextBox) + { + ((KryptonMaskedTextBox)c).SetValue(value, customAttribute.BindFormat); + } + if (c is KryptonCheckedListBox) + { + ((KryptonCheckedListBox)c).SetValue(QuotedString.DelimiteredListToArray((string)value)); + } + if (c is KryptonListBox) + { + ((KryptonListBox)c).SetValue(QuotedString.DelimiteredListToArray((string)value)); + } + else if (c is KryptonRadioButton) + { + ((KryptonRadioButton)c).SetValue(value); + } + } + public object GetValue(Control c, string type, string bindFormat) + { + if (c is KryptonTextBox) + { + if (type.ToLower() == "string") + { + return ((KryptonTextBox)c).Text.Trim(); + } + else if (type.ToLower() == "nullable`1" || type.ToLower() == "datetime" || type.ToLower() == "sqldatetime") + { + if (type.ToLower() == "datetime" && string.IsNullOrEmpty(((KryptonTextBox)c).Text)) + return DBNull.Value; + else if (type.ToLower() == "sqldatetime" && string.IsNullOrEmpty(((KryptonTextBox)c).Text)) + return SqlDateTime.Null; + else + if (!string.IsNullOrEmpty(bindFormat)) + return DateTime.ParseExact(((KryptonTextBox)c).Text.Trim(), bindFormat, CultureInfo.InvariantCulture, DateTimeStyles.None); + else + return DateTime.Parse(((KryptonTextBox)c).Text.Trim(), CultureInfo.InvariantCulture, DateTimeStyles.None); + } + else if (type.ToLower() == "decimal") + { + if (string.IsNullOrEmpty(((KryptonTextBox)c).Text)) + return 0m; + if (!string.IsNullOrEmpty(bindFormat)) + return Decimal.Parse(Convert.ToDecimal(((KryptonTextBox)c).Text).ToString(bindFormat)); + else + return Convert.ToDecimal(((KryptonTextBox)c).Text); + } + else if (type.ToLower() == "int" || type.ToLower() == "int32" || type.ToLower() == "int16") + { + if (string.IsNullOrEmpty(((KryptonTextBox)c).Text)) + return 0; + return Convert.ToInt32(Convert.ToDecimal(((KryptonTextBox)c).Text)); + } + else if (type.ToLower() == "int64") + { + if (string.IsNullOrEmpty(((KryptonTextBox)c).Text)) + return 0; + return Convert.ToInt64(Convert.ToDecimal(((KryptonTextBox)c).Text)); + } + else if (type.ToLower() == "double" || type.ToLower() == "float") + { + if (string.IsNullOrEmpty(((KryptonTextBox)c).Text)) + return 0; + return Convert.ToDouble(((KryptonTextBox)c).Text); + } + } + else if (c is KryptonComboBox) + { + if (((KryptonComboBox)c).SelectedValue == null) return null; + + if (type.ToLower() == "string") + { + return ((KryptonComboBox)c).SelectedValue.ToString(); + } + else if (type.ToLower() == "decimal") + { + if (string.IsNullOrEmpty((string)((KryptonComboBox)c).SelectedValue)) return 0m; + + if (!string.IsNullOrEmpty(bindFormat)) + return Decimal.Parse(Convert.ToDecimal(((KryptonComboBox)c).SelectedValue).ToString(bindFormat)); + else + return Convert.ToDecimal(((KryptonComboBox)c).SelectedValue); + } + else if (type.ToLower() == "int" || type.ToLower() == "int32" || type.ToLower() == "int16") + { + if (string.IsNullOrEmpty((string)((KryptonComboBox)c).SelectedValue)) return 0; + + return Convert.ToInt32(Convert.ToDecimal(((KryptonComboBox)c).SelectedValue)); + } + else if (type.ToLower() == "int64") + { + if (string.IsNullOrEmpty((string)((KryptonComboBox)c).SelectedValue)) return 0; + + return Convert.ToInt64(Convert.ToDecimal(((KryptonComboBox)c).SelectedValue)); + } + else if (type.ToLower() == "double" || type.ToLower() == "float") + { + if (string.IsNullOrEmpty((string)((KryptonComboBox)c).SelectedValue)) return 0; + + return Convert.ToDouble(((KryptonComboBox)c).SelectedValue); + } + } + else if (c is KryptonCheckBox) + { + if (type.ToLower() == "string") + { + return ((KryptonCheckBox)c).Checked ? YesNoPolicy.YES : YesNoPolicy.NO; + } + else if (type.ToLower() == "decimal") + { + return ((KryptonCheckBox)c).Checked ? 1m : 0m; + } + else if (type.ToLower() == "bool") + { + return ((KryptonCheckBox)c).Checked ? true : false; + } + else if (type.ToLower() == "int" || type.ToLower() == "int32" || type.ToLower() == "int16" || type.ToLower() == "int64") + { + return ((KryptonCheckBox)c).Checked ? 1 : 0; + } + else if (type.ToLower() == "double" || type.ToLower() == "float") + { + return ((KryptonCheckBox)c).Checked ? 1d : 0d; + } + } + else if (c is KryptonDateTimePicker) + { + if (!((KryptonDateTimePicker)c).Checked) return null; + + if (string.IsNullOrEmpty(((KryptonDateTimePicker)c).Text)) return null; + else if (type.ToLower() == "string") + { + return ((KryptonDateTimePicker)c).Text.Trim(); + } + else if (type.ToLower() == "nullable`1" || type.ToLower() == "datetime" || type.ToLower() == "sqldatetime") + { + if (type.ToLower() == "datetime" && string.IsNullOrEmpty(((KryptonDateTimePicker)c).Text)) + return DBNull.Value; + else if (type.ToLower() == "sqldatetime" && string.IsNullOrEmpty(((KryptonDateTimePicker)c).Text)) + return SqlDateTime.Null; + else + return ((KryptonDateTimePicker)c).Value; + } + } + else if (c is KryptonMaskedTextBox) + { + if (string.IsNullOrEmpty(((KryptonMaskedTextBox)c).Text)) return null; + else if (type.ToLower() == "string") + { + return ((KryptonMaskedTextBox)c).Text.Trim(); + } + else if (type.ToLower() == "nullable`1" || type.ToLower() == "datetime" || type.ToLower() == "sqldatetime") + { + if (type.ToLower() == "datetime" && string.IsNullOrEmpty(((KryptonMaskedTextBox)c).Text)) + return DBNull.Value; + else if (type.ToLower() == "sqldatetime" && string.IsNullOrEmpty(((KryptonMaskedTextBox)c).Text)) + return SqlDateTime.Null; + else + { + if (!string.IsNullOrEmpty(bindFormat)) + return DateTime.ParseExact(((KryptonMaskedTextBox)c).Text.Trim(), bindFormat, CultureInfo.InvariantCulture, DateTimeStyles.None); + else + return DateTime.Parse(((KryptonMaskedTextBox)c).Text.Trim(), CultureInfo.InvariantCulture, DateTimeStyles.None); + } + } + else if (type.ToLower() == "decimal") + { + if (!string.IsNullOrEmpty(bindFormat)) + return Decimal.Parse(Convert.ToDecimal(((KryptonMaskedTextBox)c).Text).ToString(bindFormat)); + else + return Convert.ToDecimal(((KryptonMaskedTextBox)c).Text); + } + else if (type.ToLower() == "int" || type.ToLower() == "int32" || type.ToLower() == "int16") + { + return Convert.ToInt32(Convert.ToDecimal(((KryptonMaskedTextBox)c).Text)); + } + else if (type.ToLower() == "int64") + { + return Convert.ToInt64(Convert.ToDecimal(((KryptonMaskedTextBox)c).Text)); + } + else if (type.ToLower() == "double" || type.ToLower() == "float") + { + return Convert.ToDouble(((KryptonMaskedTextBox)c).Text); + } + } + else if (c is KryptonCheckedListBox) + { + if (((KryptonCheckedListBox)c).GetCheckedItemValue().Count() == 0) return null; + + return QuotedString.ToDelimiteredList(((KryptonCheckedListBox)c).GetCheckedItemValue()); + } + else if (c is KryptonListBox) + { + if (((KryptonListBox)c).GetAllItemValue().Count() == 0) return null; + + return QuotedString.ToDelimiteredList(((KryptonListBox)c).GetAllItemValue()); + } + else if (c is KryptonRadioButton) + { + if (type.ToLower() == "string") + { + return ((KryptonRadioButton)c).Checked ? "Y" : "N"; + } + else if (type.ToLower() == "decimal") + { + return ((KryptonRadioButton)c).Checked ? 1m : 0m; + } + else if (type.ToLower() == "bool") + { + return ((KryptonRadioButton)c).Checked ? true : false; + } + else if (type.ToLower() == "int" || type.ToLower() == "int32" || type.ToLower() == "int16" || type.ToLower() == "int64") + { + return ((KryptonRadioButton)c).Checked ? 1 : 0; + } + else if (type.ToLower() == "double" || type.ToLower() == "float") + { + return ((KryptonRadioButton)c).Checked ? 1d : 0d; + } + } + + return ((Control)c).Text; + } + } + + public class BindingContextCustomAttribute + { + public BindingContextCustomAttribute() + { + + } + + public string BindDataName { get; set; } + public string BindDisplayName { get; set; } + + public EnumBindDirection BindDirection { get; set; } + public string BindFormat { get; set; } + + public EnumEditModeColor EditModeColor { get; set; } + + public Operate PermissionMode { get; set; } + public string PermissionName { get; set; } + + public string DependentDetailName { get; set; } + + public List DataSource { get; set; } + + public DataTable DataTableSource { get; set; } + public DataTable DeleteDataTableSource { get; set; } + } +} + diff --git a/CloudBuilder/CloudBuilder.Gui/GuiOperateHelper.cs b/CloudBuilder/CloudBuilder.Gui/GuiOperateHelper.cs new file mode 100644 index 0000000..ec0ce55 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/GuiOperateHelper.cs @@ -0,0 +1,900 @@ +using CloudBuilder.Core.DependencyInjection.Form; +using CloudBuilder.Core.DependencyInjection.Request; +using CloudBuilder.Gui.DependencyInjection; +using CloudBuilder.Security.Policy; +using CloudBuilder.Security.Utility; +using Krypton.Toolkit; +using Microsoft.AspNetCore.Authorization; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.IdentityModel.Tokens; +using System; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Linq; +using System.Resources; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace CloudBuilder.Gui +{ + public class GuiOperateHelper + { + private LoginContextPermission loginContextPermission; + public GuiOperateHelper() + { + this.loginContextPermission = new LoginContextPermission(); + } + + public void EnableControls(bool enable, IComponent c) + { + if ((c is Control)) + ((Control)c).SuspendLayout(); + Enable(enable, c); + if ((c is Control)) + ((Control)c).ResumeLayout(); + + } + + public void EnableControls(bool enable, Control.ControlCollection cc) + { + IEnumerator enumerator = cc.GetEnumerator(); + while (enumerator.MoveNext()) + { + Control current = (Control)enumerator.Current; + EnableControls(enable, current); + } + } + + public void EnableControls(bool enable, params IComponent[] cc) + { + foreach (IComponent c in cc) + { + EnableControls(enable, c); + } + } + + public void EnableControls(bool enable, List cc) + { + foreach (IComponent c in cc) + { + EnableControls(enable, c); + } + } + + public bool CheckValidate(Control.ControlCollection cc) + { + IEnumerator enumerator = cc.GetEnumerator(); + while (enumerator.MoveNext()) + { + Control current = (Control)enumerator.Current; + if (!CheckValidate(current)) return false; + } + return true; + } + + public bool CheckValidate(params IComponent[] cc) + { + foreach (IComponent c in cc) + { + if (!CheckValidate(c)) return false; + } + return true; + } + + public bool CheckValidate(List cc) + { + foreach (IComponent c in cc) + { + if (!CheckValidate(c)) return false; + } + return true; + } + + public void ResetControls(params IComponent[] cc) + { + foreach (IComponent c in cc) + { + ResetControls(c); + } + } + + public void ResetControls(List cc) + { + ResetControls(cc.ToArray()); + } + + public void ResetControls(IComponent c) + { + if (!(c is Control)) return; + ((Control)c).SuspendLayout(); + Reset(((Control)c)); + ((Control)c).ResumeLayout(); + } + + public void ResetControls(Control.ControlCollection cc) + { + IEnumerator enumerator = cc.GetEnumerator(); + while (enumerator.MoveNext()) + { + Control current = (Control)enumerator.Current; + ResetControls(current); + } + } + + public void SetControlsText(params IComponent[] cc) + { + foreach (IComponent c in cc) + { + SetControlsText(c); + } + } + + + public static void SetControlsText(IComponent c, ResourceManager rs) + { + if ((c is Control)) + ((Control)c).SuspendLayout(); + SetText(c, rs); + if ((c is Control)) + ((Control)c).ResumeLayout(); + } + + public static void SetControlsText(Control.ControlCollection cc, ResourceManager rs) + { + IEnumerator enumerator = cc.GetEnumerator(); + while (enumerator.MoveNext()) + { + Control current = (Control)enumerator.Current; + SetControlsText(current, rs); + } + } + + public static void SetControlsText(ResourceManager rs, params IComponent[] cc) + { + foreach (IComponent c in cc) + { + SetControlsText(c, rs); + } + } + + public static void SetControlsText(List cc, ResourceManager rs) + { + foreach (Control c in cc) + { + SetControlsText(c, rs); + } + } + + private void Reset(IComponent c) + { + if (!(c is Control)) return; + + if (c is GridViewPagination) + { + ((GridViewPagination)c).Reset(); + } + else if (c is KryptonTextBox) + { + ((KryptonTextBox)c).Text = string.Empty; + } + else if (c is KryptonDateTimePicker) + { + ((KryptonDateTimePicker)c).Checked = false; + } + else if (c is KryptonMaskedTextBox) + { + ((KryptonMaskedTextBox)c).Text = string.Empty; + } + else if (c is KryptonNumericUpDown) + { + ((KryptonNumericUpDown)c).Text = "0"; + } + else if (c is KryptonComboBox) + { + ((KryptonComboBox)c).SelectedIndex = -1; + } + else if (c is KryptonCheckBox) + { + ((KryptonCheckBox)c).Checked = false; + } + else if (c is KryptonDataGridView) + { + ((KryptonDataGridView)c).Clear(); + } + else if (c is KryptonCheckedListBox) + { + ((KryptonCheckedListBox)c).Reset(); + } + else if (c is KryptonListBox) + { + ((KryptonListBox)c).Items.Clear(); + } + else if (c is KryptonRadioButton) + { + ((KryptonRadioButton)c).Checked = false; + } + else + { + if (((Control)c).HasChildren) ResetControls(((Control)c).Controls); + } + } + + + private static void SetText(IComponent c, ResourceManager rs) + { + if (c is Label) + { + var text = rs.GetString(((Label)c).Name); + + if (text != null) ((Label)c).Text = (string)text; + } + if (c is KryptonLabel) + { + var text = rs.GetString(((KryptonLabel)c).Name); + + if (text != null) ((KryptonLabel)c).Text = (string)text; + } + else if (c is Button) + { + var text = rs.GetString(((Button)c).Name); + + if (text != null) ((Button)c).Text = (string)text; + } + else if (c is KryptonButton) + { + var text = rs.GetString(((KryptonButton)c).Name); + + if (text != null) ((KryptonButton)c).Text = (string)text; + } + else if (c is DataGridView) + { + SetText(((DataGridView)c).Columns, rs); + } + else if (c is KryptonDataGridView) + { + SetText(((KryptonDataGridView)c).Columns, rs); + } + else if (c is SplitContainer) + { + if (((Control)c).HasChildren) SetControlsText(((SplitContainer)c).Panel1, rs); + if (((Control)c).HasChildren) SetControlsText(((SplitContainer)c).Panel2, rs); + } + else if (c is SplitterPanel) + { + if (((Control)c).HasChildren) SetControlsText(((SplitterPanel)c).Controls, rs); + } + else if (c is Panel) + { + if (((Control)c).HasChildren) SetControlsText(((Panel)c).Controls, rs); + } + else if (c is TableLayoutPanel) + { + if (((Control)c).HasChildren) SetControlsText(((TableLayoutPanel)c).Controls, rs); + } + else if (c is AbstractForm) + { + if (((Control)c).HasChildren) SetControlsText(((AbstractForm)c).Controls, rs); + } + + } + + private static void SetText(DataGridViewColumnCollection c, ResourceManager rs) + { + foreach (DataGridViewColumn dgvc in c) + { + var text = rs.GetString(((DataGridViewColumn)dgvc).Name); + if (text != null) dgvc.HeaderText = (string)text; + + } + } + + private void Enable(bool enable, IComponent c) + { + IContext loginContext = null!; + loginContext = ServiceHelper.GetInterfaceService()!; + + if (c is KryptonTextBox) + { + ((KryptonTextBox)c).ReadOnly = !enable; + + foreach (ButtonSpecAny but in ((KryptonTextBox)c).ButtonSpecs) + { + but.Enabled = enable ? ButtonEnabled.True : ButtonEnabled.False; + } + + BindingContextCustomAttribute guiBindingContext = ServiceHelper.GetService()!.GetCustomAttribute((KryptonTextBox)c); + + if (enable) + { + if (guiBindingContext == null) + { + //沒有設置時,默认白色 + ((KryptonTextBox)c).StateCommon.Back.Color1 = Color.White; + } + else if (guiBindingContext.EditModeColor == EnumEditModeColor.Required) + { + ((KryptonTextBox)c).StateCommon.Border.Color1 = Color.Peru; + ((KryptonTextBox)c).StateActive.Border.DrawBorders = ((Krypton.Toolkit.PaletteDrawBorders)((( + (Krypton.Toolkit.PaletteDrawBorders.Top | Krypton.Toolkit.PaletteDrawBorders.Bottom) | + Krypton.Toolkit.PaletteDrawBorders.Left) | Krypton.Toolkit.PaletteDrawBorders.Right))); + ((KryptonTextBox)c).StateCommon.Back.Color1 = Color.White; + } + else if (guiBindingContext.EditModeColor == EnumEditModeColor.ReadOnly) + { + ((KryptonTextBox)c).StateCommon.Border.Color1 = Color.Gainsboro; + ((KryptonTextBox)c).StateCommon.Back.Color1 = Color.FromArgb(234, 242, 251); + ((KryptonTextBox)c).ReadOnly = true; + } + else + { + ((KryptonTextBox)c).StateCommon.Back.Color1 = Color.White; + } + } + else + { + ((KryptonTextBox)c).StateCommon.Border.Color1 = Color.LightGray; + ((KryptonTextBox)c).StateCommon.Back.Color1 = Color.FromArgb(234, 242, 251); + } + + if (guiBindingContext != null && !string.IsNullOrEmpty(guiBindingContext.PermissionName) && string.IsNullOrEmpty(guiBindingContext.DependentDetailName)) + { + if (guiBindingContext.PermissionMode == Operate.Find && !loginContext.Assert(loginContextPermission.Assert, guiBindingContext.PermissionName, Operate.Find)) + { + guiBindingContext.BindDataName = null!; + ((KryptonTextBox)c).Text = null!; + ((KryptonTextBox)c).ReadOnly = true; + ((KryptonTextBox)c).StateCommon.Border.Color1 = Color.Gainsboro; + ((KryptonTextBox)c).StateCommon.Back.Color1 = Color.FromArgb(234, 242, 251); + } + if (guiBindingContext.PermissionMode == Operate.Update && !loginContext.Assert(loginContextPermission.Assert, guiBindingContext.PermissionName, Operate.Update)) + { + ((KryptonTextBox)c).ReadOnly = true; + ((KryptonTextBox)c).StateCommon.Border.Color1 = Color.Gainsboro; + ((KryptonTextBox)c).StateCommon.Back.Color1 = Color.FromArgb(234, 242, 251); + } + } + else if (guiBindingContext != null && !string.IsNullOrEmpty(guiBindingContext.PermissionName) && !string.IsNullOrEmpty(guiBindingContext.DependentDetailName)) + { + if (guiBindingContext.PermissionMode == Operate.Find && !loginContext.AssertDependents(loginContextPermission.AssertDependents, guiBindingContext.PermissionName, guiBindingContext.DependentDetailName, Operate.Find)) + { + guiBindingContext.BindDataName = null!; + ((KryptonTextBox)c).Text = null!; + ((KryptonTextBox)c).ReadOnly = true; + ((KryptonTextBox)c).StateCommon.Border.Color1 = Color.Gainsboro; + ((KryptonTextBox)c).StateCommon.Back.Color1 = Color.FromArgb(234, 242, 251); + } + if (guiBindingContext.PermissionMode == Operate.Update && !loginContext.AssertDependents(loginContextPermission.AssertDependents, guiBindingContext.PermissionName, guiBindingContext.DependentDetailName, Operate.Update)) + { + ((KryptonTextBox)c).ReadOnly = true; + ((KryptonTextBox)c).StateCommon.Border.Color1 = Color.Gainsboro; + ((KryptonTextBox)c).StateCommon.Back.Color1 = Color.FromArgb(234, 242, 251); + } + } + + } + else if (c is KryptonComboBox) + { + ((KryptonComboBox)c).Enabled = enable; + + BindingContextCustomAttribute guiBindingContext = ServiceHelper.GetService()!.GetCustomAttribute((KryptonComboBox)c); + + if (enable) + { + ((KryptonComboBox)c).StateCommon.ComboBox.Border.Width = 1; + + if (guiBindingContext == null) + { + //沒有設置時,默认白色 + ((KryptonComboBox)c).StateCommon.ComboBox.Back.Color1 = Color.White; + ((KryptonComboBox)c).StateCommon.ComboBox.Border.Color1 = Color.FromArgb(215, 229, 243); + } + else if (guiBindingContext.EditModeColor == EnumEditModeColor.Required) + { + ((KryptonComboBox)c).StateCommon.ComboBox.Back.Color1 = Color.White; + ((KryptonComboBox)c).StateCommon.ComboBox.Border.Color1 = Color.Peru; + ((KryptonComboBox)c).StateActive.ComboBox.Border.DrawBorders = ((Krypton.Toolkit.PaletteDrawBorders)((( + (Krypton.Toolkit.PaletteDrawBorders.Top | Krypton.Toolkit.PaletteDrawBorders.Bottom) | + Krypton.Toolkit.PaletteDrawBorders.Left) | Krypton.Toolkit.PaletteDrawBorders.Right))); + } + else if (guiBindingContext.EditModeColor == EnumEditModeColor.ReadOnly) + { + ((KryptonComboBox)c).StateCommon.ComboBox.Back.Color1 = Color.FromArgb(234, 242, 251); + ((KryptonComboBox)c).StateCommon.ComboBox.Border.Color1 = Color.LightGray; + ((KryptonComboBox)c).Enabled = false; + } + else + { + ((KryptonComboBox)c).StateCommon.ComboBox.Back.Color1 = Color.White; + ((KryptonComboBox)c).StateCommon.ComboBox.Border.Color1 = Color.FromArgb(215, 229, 243); + } + } + else + { + ((KryptonComboBox)c).StateDisabled.ComboBox.Back.Color1 = Color.FromArgb(234, 242, 251); + ((KryptonComboBox)c).StateDisabled.ComboBox.Border.Color1 = Color.LightGray; + ((KryptonComboBox)c).StateDisabled.ComboBox.Content.Color1 = Color.Black; + } + + if (guiBindingContext != null && !string.IsNullOrEmpty(guiBindingContext.PermissionName) && string.IsNullOrEmpty(guiBindingContext.DependentDetailName)) + { + if (guiBindingContext.PermissionMode == Operate.Find && !loginContext.Assert(loginContextPermission.Assert, guiBindingContext.PermissionName, Operate.Find)) + { + guiBindingContext.BindDataName = null!; + ((KryptonComboBox)c).SelectedIndex = -1; + ((KryptonComboBox)c).Enabled = false; + ((KryptonComboBox)c).StateCommon.ComboBox.Back.Color1 = Color.FromArgb(234, 242, 251); + ((KryptonComboBox)c).StateCommon.ComboBox.Border.Color1 = Color.LightGray; + } + if (guiBindingContext.PermissionMode == Operate.Update && !loginContext.Assert(loginContextPermission.Assert, guiBindingContext.PermissionName, Operate.Update)) + { + ((KryptonComboBox)c).Enabled = false; + ((KryptonComboBox)c).StateCommon.ComboBox.Back.Color1 = Color.FromArgb(234, 242, 251); + ((KryptonComboBox)c).StateCommon.ComboBox.Border.Color1 = Color.LightGray; + } + } + else if (guiBindingContext != null && !string.IsNullOrEmpty(guiBindingContext.PermissionName) && !string.IsNullOrEmpty(guiBindingContext.DependentDetailName)) + { + if (guiBindingContext.PermissionMode == Operate.Find && !loginContext.AssertDependents(loginContextPermission.AssertDependents, guiBindingContext.PermissionName, guiBindingContext.DependentDetailName, Operate.Find)) + { + guiBindingContext.BindDataName = null!; + ((KryptonComboBox)c).SelectedIndex = -1; + ((KryptonComboBox)c).Enabled = false; + ((KryptonComboBox)c).StateCommon.ComboBox.Back.Color1 = Color.FromArgb(234, 242, 251); + ((KryptonComboBox)c).StateCommon.ComboBox.Border.Color1 = Color.LightGray; + } + if (guiBindingContext.PermissionMode == Operate.Update && !loginContext.AssertDependents(loginContextPermission.AssertDependents, guiBindingContext.PermissionName, guiBindingContext.DependentDetailName, Operate.Update)) + { + ((KryptonComboBox)c).Enabled = false; + ((KryptonComboBox)c).StateCommon.ComboBox.Back.Color1 = Color.FromArgb(234, 242, 251); + ((KryptonComboBox)c).StateCommon.ComboBox.Border.Color1 = Color.LightGray; + } + } + } + else if (c is KryptonCheckBox) + { + ((KryptonCheckBox)c).Enabled = enable; + + BindingContextCustomAttribute guiBindingContext = ServiceHelper.GetService()!.GetCustomAttribute((KryptonCheckBox)c); + + if (enable) + { + ((KryptonCheckBox)c).StateCommon.ShortText.Color1 = Color.Black; + ((KryptonCheckBox)c).StateCommon.LongText.Color1 = Color.Black; + + if (guiBindingContext != null && guiBindingContext.EditModeColor == EnumEditModeColor.ReadOnly) + { + ((KryptonCheckBox)c).Enabled = false; + } + } + else + { + ((KryptonCheckBox)c).StateCommon.ShortText.Color1 = Color.DimGray; + ((KryptonCheckBox)c).StateCommon.LongText.Color1 = Color.DimGray; + } + + if (guiBindingContext != null && !string.IsNullOrEmpty(guiBindingContext.PermissionName) && string.IsNullOrEmpty(guiBindingContext.DependentDetailName)) + { + if (guiBindingContext.PermissionMode == Operate.Find && !loginContext.Assert(loginContextPermission.Assert, guiBindingContext.PermissionName, Operate.Find)) + { + guiBindingContext.BindDataName = null!; + ((KryptonCheckBox)c).Visible = false; + } + if (guiBindingContext.PermissionMode == Operate.Update && !loginContext.Assert(loginContextPermission.Assert, guiBindingContext.PermissionName, Operate.Update)) + { + ((KryptonCheckBox)c).Enabled = false; + } + } + else if (guiBindingContext != null && !string.IsNullOrEmpty(guiBindingContext.PermissionName) && !string.IsNullOrEmpty(guiBindingContext.DependentDetailName)) + { + if (guiBindingContext.PermissionMode == Operate.Find && !loginContext.AssertDependents(loginContextPermission.AssertDependents, guiBindingContext.PermissionName, guiBindingContext.DependentDetailName, Operate.Find)) + { + guiBindingContext.BindDataName = null!; + ((KryptonCheckBox)c).Visible = false; + } + if (guiBindingContext.PermissionMode == Operate.Update && !loginContext.AssertDependents(loginContextPermission.AssertDependents, guiBindingContext.PermissionName, guiBindingContext.DependentDetailName, Operate.Update)) + { + ((KryptonCheckBox)c).Enabled = false; + } + } + } + else if (c is KryptonDateTimePicker) + { + ((KryptonDateTimePicker)c).Enabled = enable; + + BindingContextCustomAttribute guiBindingContext = ServiceHelper.GetService()!.GetCustomAttribute((KryptonDateTimePicker)c); + + if (enable) + { + ((KryptonDateTimePicker)c).StateCommon.Border.Width = 1; + + if (guiBindingContext == null) + { + //沒有設置時,默认白色 + ((KryptonDateTimePicker)c).StateCommon.Border.Color1 = Color.FromArgb(215, 229, 243); + ((KryptonDateTimePicker)c).StateCommon.Back.Color1 = Color.White; + } + else if (guiBindingContext.EditModeColor == EnumEditModeColor.Required) + { + ((KryptonDateTimePicker)c).StateCommon.Back.Color1 = Color.White; + ((KryptonDateTimePicker)c).StateCommon.Border.Color1 = Color.Peru; + ((KryptonDateTimePicker)c).StateActive.Border.DrawBorders = ((Krypton.Toolkit.PaletteDrawBorders)((( + (Krypton.Toolkit.PaletteDrawBorders.Top | Krypton.Toolkit.PaletteDrawBorders.Bottom) | + Krypton.Toolkit.PaletteDrawBorders.Left) | Krypton.Toolkit.PaletteDrawBorders.Right))); + } + else if (guiBindingContext.EditModeColor == EnumEditModeColor.ReadOnly) + { + ((KryptonDateTimePicker)c).StateCommon.Border.Color1 = Color.LightGray; + ((KryptonDateTimePicker)c).StateCommon.Back.Color1 = Color.FromArgb(234, 242, 251); + ((KryptonDateTimePicker)c).Enabled = false; + } + else + { + ((KryptonDateTimePicker)c).StateCommon.Back.Color1 = Color.White; + ((KryptonDateTimePicker)c).StateCommon.Border.Color1 = Color.FromArgb(215, 229, 243); + } + + } + else + { + ((KryptonDateTimePicker)c).StateDisabled.Border.Color1 = Color.LightGray; + ((KryptonDateTimePicker)c).StateDisabled.Back.Color1 = Color.FromArgb(234, 242, 251); + ((KryptonDateTimePicker)c).StateDisabled.Content.Color1 = Color.Black; + } + + if (guiBindingContext != null && !string.IsNullOrEmpty(guiBindingContext.PermissionName) && string.IsNullOrEmpty(guiBindingContext.DependentDetailName)) + { + if (guiBindingContext.PermissionMode == Operate.Find && !loginContext.Assert(loginContextPermission.Assert, guiBindingContext.PermissionName, Operate.Find)) + { + guiBindingContext.BindDataName = null!; + ((KryptonDateTimePicker)c).Checked = false; + ((KryptonDateTimePicker)c).Enabled = false; + ((KryptonDateTimePicker)c).StateCommon.Border.Color1 = Color.LightGray; + ((KryptonDateTimePicker)c).StateCommon.Back.Color1 = Color.FromArgb(234, 242, 251); + } + if (guiBindingContext.PermissionMode == Operate.Update && !loginContext.Assert(loginContextPermission.Assert, guiBindingContext.PermissionName, Operate.Update)) + { + ((KryptonDateTimePicker)c).Enabled = false; + ((KryptonDateTimePicker)c).StateCommon.Border.Color1 = Color.LightGray; + ((KryptonDateTimePicker)c).StateCommon.Back.Color1 = Color.FromArgb(234, 242, 251); + } + } + else if (guiBindingContext != null && !string.IsNullOrEmpty(guiBindingContext.PermissionName) && !string.IsNullOrEmpty(guiBindingContext.DependentDetailName)) + { + if (guiBindingContext.PermissionMode == Operate.Find && !loginContext.AssertDependents(loginContextPermission.AssertDependents, guiBindingContext.PermissionName, guiBindingContext.DependentDetailName, Operate.Find)) + { + guiBindingContext.BindDataName = null!; + ((KryptonDateTimePicker)c).Checked = false; + ((KryptonDateTimePicker)c).Enabled = false; + ((KryptonDateTimePicker)c).StateCommon.Border.Color1 = Color.LightGray; + ((KryptonDateTimePicker)c).StateCommon.Back.Color1 = Color.FromArgb(234, 242, 251); + } + if (guiBindingContext.PermissionMode == Operate.Update && !loginContext.AssertDependents(loginContextPermission.AssertDependents, guiBindingContext.PermissionName, guiBindingContext.DependentDetailName, Operate.Update)) + { + ((KryptonDateTimePicker)c).Enabled = false; + ((KryptonDateTimePicker)c).StateCommon.Border.Color1 = Color.LightGray; + ((KryptonDateTimePicker)c).StateCommon.Back.Color1 = Color.FromArgb(234, 242, 251); + } + } + } + else if (c is KryptonMaskedTextBox) + { + ((KryptonMaskedTextBox)c).ReadOnly = !enable; + + foreach (ButtonSpecAny but in ((KryptonMaskedTextBox)c).ButtonSpecs) + { + but.Enabled = enable ? ButtonEnabled.True : ButtonEnabled.False; + } + + BindingContextCustomAttribute guiBindingContext = ServiceHelper.GetService()!.GetCustomAttribute((KryptonMaskedTextBox)c); + + if (enable) + { + if (guiBindingContext == null) + { + //沒有設置時,默认白色 + ((KryptonMaskedTextBox)c).StateCommon.Back.Color1 = Color.White; + } + else if (guiBindingContext.EditModeColor == EnumEditModeColor.Required) + { + ((KryptonMaskedTextBox)c).StateCommon.Border.Color1 = Color.Peru; + ((KryptonMaskedTextBox)c).StateActive.Border.DrawBorders = ((Krypton.Toolkit.PaletteDrawBorders)((( + (Krypton.Toolkit.PaletteDrawBorders.Top | Krypton.Toolkit.PaletteDrawBorders.Bottom) | + Krypton.Toolkit.PaletteDrawBorders.Left) | Krypton.Toolkit.PaletteDrawBorders.Right))); + ((KryptonMaskedTextBox)c).StateCommon.Back.Color1 = Color.White; + } + else if (guiBindingContext.EditModeColor == EnumEditModeColor.ReadOnly) + { + ((KryptonMaskedTextBox)c).StateCommon.Border.Color1 = Color.Gainsboro; + ((KryptonMaskedTextBox)c).StateCommon.Back.Color1 = Color.FromArgb(234, 242, 251); + ((KryptonMaskedTextBox)c).ReadOnly = true; + } + else + { + ((KryptonMaskedTextBox)c).StateCommon.Back.Color1 = Color.White; + } + + } + else + { + ((KryptonMaskedTextBox)c).StateCommon.Border.Color1 = Color.Gainsboro; + ((KryptonMaskedTextBox)c).StateCommon.Back.Color1 = Color.FromArgb(234, 242, 251); + ((KryptonMaskedTextBox)c).StateCommon.Content.Color1 = Color.Black; + } + + + if (guiBindingContext != null && !string.IsNullOrEmpty(guiBindingContext.PermissionName) && string.IsNullOrEmpty(guiBindingContext.DependentDetailName)) + { + if (guiBindingContext.PermissionMode == Operate.Find && !loginContext.Assert(loginContextPermission.Assert, guiBindingContext.PermissionName, Operate.Find)) + { + guiBindingContext.BindDataName = null!; + ((KryptonMaskedTextBox)c).Text = null!; + ((KryptonMaskedTextBox)c).ReadOnly = true; + ((KryptonMaskedTextBox)c).StateCommon.Border.Color1 = Color.Gainsboro; + ((KryptonMaskedTextBox)c).StateCommon.Back.Color1 = Color.FromArgb(234, 242, 251); + } + if (guiBindingContext.PermissionMode == Operate.Update && !loginContext.Assert(loginContextPermission.Assert, guiBindingContext.PermissionName, Operate.Update)) + { + ((KryptonMaskedTextBox)c).ReadOnly = true; + ((KryptonMaskedTextBox)c).StateCommon.Border.Color1 = Color.Gainsboro; + ((KryptonMaskedTextBox)c).StateCommon.Back.Color1 = Color.FromArgb(234, 242, 251); + } + } + else if (guiBindingContext != null && !string.IsNullOrEmpty(guiBindingContext.PermissionName) && !string.IsNullOrEmpty(guiBindingContext.DependentDetailName)) + { + if (guiBindingContext.PermissionMode == Operate.Find && !loginContext.AssertDependents(loginContextPermission.AssertDependents, guiBindingContext.PermissionName, guiBindingContext.DependentDetailName, Operate.Find)) + { + guiBindingContext.BindDataName = null!; + ((KryptonMaskedTextBox)c).Text = null!; + ((KryptonMaskedTextBox)c).ReadOnly = true; + ((KryptonMaskedTextBox)c).StateCommon.Border.Color1 = Color.Gainsboro; + ((KryptonMaskedTextBox)c).StateCommon.Back.Color1 = Color.FromArgb(234, 242, 251); + } + if (guiBindingContext.PermissionMode == Operate.Update && !loginContext.AssertDependents(loginContextPermission.AssertDependents, guiBindingContext.PermissionName, guiBindingContext.DependentDetailName, Operate.Update)) + { + ((KryptonMaskedTextBox)c).ReadOnly = true; + ((KryptonMaskedTextBox)c).StateCommon.Border.Color1 = Color.Gainsboro; + ((KryptonMaskedTextBox)c).StateCommon.Back.Color1 = Color.FromArgb(234, 242, 251); + } + } + } + else if (c is KryptonDataGridView) + { + foreach (DataGridViewColumn column in ((KryptonDataGridView)c).Columns) + { + column.ReadOnly = !enable; + + BindingContextCustomAttribute guiBindingContext = column.GetCustomAttribute(); + if (enable) + { + if (guiBindingContext == null) + { + //沒有設置時,默认白色 + column.DefaultCellStyle.BackColor = Color.White; + } + else if (guiBindingContext.EditModeColor == EnumEditModeColor.Required) + { + column.DefaultCellStyle.BackColor = Color.LightYellow; + } + else if (guiBindingContext.EditModeColor == EnumEditModeColor.ReadOnly) + { + column.DefaultCellStyle.BackColor = Color.Gainsboro; + column.ReadOnly = true; + } + else + { + column.DefaultCellStyle.BackColor = Color.White; + } + + + } + else + { + column.DefaultCellStyle.BackColor = Color.FromArgb(234, 242, 251); + } + + if (guiBindingContext != null && !string.IsNullOrEmpty(guiBindingContext.PermissionName) && string.IsNullOrEmpty(guiBindingContext.DependentDetailName)) + { + if (guiBindingContext.PermissionMode == Operate.Find && !loginContext.Assert(loginContextPermission.Assert, guiBindingContext.PermissionName, Operate.Find)) + { + column.DataPropertyName = null; + column.ReadOnly = true; + column.DefaultCellStyle.BackColor = Color.FromArgb(234, 242, 251); + } + if (guiBindingContext.PermissionMode == Operate.Update && !loginContext.Assert(loginContextPermission.Assert, guiBindingContext.PermissionName, Operate.Update)) + { + column.ReadOnly = true; + column.DefaultCellStyle.BackColor = Color.FromArgb(234, 242, 251); + } + } + else if (guiBindingContext != null && !string.IsNullOrEmpty(guiBindingContext.PermissionName) && !string.IsNullOrEmpty(guiBindingContext.DependentDetailName)) + { + if (guiBindingContext.PermissionMode == Operate.Find && !loginContext.AssertDependents(loginContextPermission.AssertDependents, guiBindingContext.PermissionName, guiBindingContext.DependentDetailName, Operate.Find)) + { + column.DataPropertyName = null; + column.ReadOnly = true; + column.DefaultCellStyle.BackColor = Color.FromArgb(234, 242, 251); + } + if (guiBindingContext.PermissionMode == Operate.Update && !loginContext.AssertDependents(loginContextPermission.AssertDependents, guiBindingContext.PermissionName, guiBindingContext.DependentDetailName, Operate.Update)) + { + column.ReadOnly = true; + column.DefaultCellStyle.BackColor = Color.FromArgb(234, 242, 251); + } + } + } + } + if (c is KryptonCheckedListBox) + { + ((KryptonCheckedListBox)c).Enabled = enable; + } + else if (c is KryptonListBox) + { + ((KryptonListBox)c).Enabled = enable; + } + else if (c is KryptonRadioButton) + { + ((KryptonRadioButton)c).Enabled = enable; + } + else if (c is KryptonButton) + { + BindingContextCustomAttribute guiBindingContext = ServiceHelper.GetService()!.GetCustomAttribute((KryptonButton)c); + + ((KryptonButton)c).Enabled = enable; + + if (enable && guiBindingContext != null + && !string.IsNullOrEmpty(guiBindingContext.PermissionName) + && loginContext != null) + { + if (string.IsNullOrEmpty(guiBindingContext.DependentDetailName) && !loginContext.Assert(loginContextPermission.Assert, guiBindingContext.PermissionName, guiBindingContext.PermissionMode)) + { + ((KryptonButton)c).Enabled = false; + } + else if (!string.IsNullOrEmpty(guiBindingContext.DependentDetailName) && !loginContext.AssertDependents(loginContextPermission.AssertDependents, guiBindingContext.PermissionName, guiBindingContext.DependentDetailName, guiBindingContext.PermissionMode)) + { + ((KryptonButton)c).Enabled = false; + } + } + } + else + { + if (((Control)c).HasChildren) EnableControls(enable, ((Control)c).Controls); + } + + } + + private bool CheckValidate(IComponent c) + { + IContext loginContext = null!; + loginContext = ServiceHelper.GetInterfaceService()!; + SecurityMessagePolicy securityMessagePolicy = ServiceHelper.GetTypeService()!; + bool isCheck = true; + + if (c is KryptonTextBox) + { + BindingContextCustomAttribute guiBindingContext = ServiceHelper.GetService()!.GetCustomAttribute((KryptonTextBox)c); + + if (!((KryptonTextBox)c).ReadOnly && guiBindingContext != null && guiBindingContext.EditModeColor == EnumEditModeColor.Required) + { + //沒有設置時,默认白色 + if (string.IsNullOrEmpty(((KryptonTextBox)c).GetValue())) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_VALID_INPUT, GuiOperateHelper.GetLabelText(guiBindingContext.BindDisplayName))); + ((KryptonTextBox)c).Focus(); + return false; + } + } + } + else if (c is KryptonComboBox) + { + BindingContextCustomAttribute guiBindingContext = ServiceHelper.GetService()!.GetCustomAttribute((KryptonComboBox)c); + + if (((KryptonComboBox)c).Enabled && guiBindingContext != null && guiBindingContext.EditModeColor == EnumEditModeColor.Required) + { + //沒有設置時,默认白色 + if (((KryptonComboBox)c).SelectedIndex <= 0) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_VALID_SELECT, GuiOperateHelper.GetLabelText(guiBindingContext.BindDisplayName))); + ((KryptonComboBox)c).Focus(); + return false; + } + } + } + else if (c is KryptonDateTimePicker) + { + BindingContextCustomAttribute guiBindingContext = ServiceHelper.GetService()!.GetCustomAttribute((KryptonDateTimePicker)c); + + if (((KryptonDateTimePicker)c).Enabled && guiBindingContext != null && guiBindingContext.EditModeColor == EnumEditModeColor.Required) + { + //沒有設置時,默认白色 + if (!((KryptonDateTimePicker)c).Checked) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_VALID_INPUT, GuiOperateHelper.GetLabelText(guiBindingContext.BindDisplayName))); + ((KryptonDateTimePicker)c).Focus(); + return false; + } + } + } + else if (c is KryptonMaskedTextBox) + { + BindingContextCustomAttribute guiBindingContext = ServiceHelper.GetService()!.GetCustomAttribute((KryptonMaskedTextBox)c); + + if (!((KryptonMaskedTextBox)c).ReadOnly && guiBindingContext != null && guiBindingContext.EditModeColor == EnumEditModeColor.Required) + { + //沒有設置時,默认白色 + if (string.IsNullOrEmpty(((KryptonMaskedTextBox)c).GetValue())) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_VALID_INPUT, GuiOperateHelper.GetLabelText(guiBindingContext.BindDisplayName))); + ((KryptonMaskedTextBox)c).Focus(); + return false; + } + } + } + else if (c is KryptonDataGridView) + { + if (!((KryptonDataGridView)c).Enabled) return isCheck; + foreach (DataGridViewRow row in ((KryptonDataGridView)c).Rows) + { + foreach (DataGridViewColumn column in ((KryptonDataGridView)c).Columns) + { + if (column.ReadOnly) continue; + + BindingContextCustomAttribute guiBindingContext = column.GetCustomAttribute(); + if (guiBindingContext != null && guiBindingContext.EditModeColor == EnumEditModeColor.Required) + { + if (column is DataGridViewComboBoxColumn || column is KryptonDataGridViewTextBoxColumn) + { + if (string.IsNullOrEmpty(row.Cells[column.Name].Value.ToString())) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_VALID_INPUT, column.HeaderText)); + ((KryptonDataGridView)c).CurrentCell = ((KryptonDataGridView)c).Rows[row.Index].Cells[column.Index]; + ((KryptonDataGridView)c).FirstDisplayedScrollingRowIndex = row.Index; + return false; + } + } + else if (column is KryptonDataGridViewDateTimePickerColumn) + { + if (!((KryptonDataGridViewDateTimePickerCell)row.Cells[column.Name]).Checked) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_VALID_INPUT, column.HeaderText)); + ((KryptonDataGridView)c).CurrentCell = ((KryptonDataGridView)c).Rows[row.Index].Cells[column.Index]; + ((KryptonDataGridView)c).FirstDisplayedScrollingRowIndex = row.Index; + return false; + } + } + } + } + } + } + else + { + if (((Control)c).HasChildren) isCheck = CheckValidate(((Control)c).Controls); + } + return isCheck; + } + + public static string GetLabelText(string text) + { + if (string.IsNullOrEmpty(text)) return null; + + return text.Substring(0, text.Length - 1); + } + + public void ComposeMessage(string groupName, params Control[] cc) + { + foreach (Control c in cc) + { + c.Text = ApplicationServiceContext.localeMessageManager.ComposeMessage(groupName, c.Name); + } + } + + public void ComposeMessage(string groupName, Control.ControlCollection cc) + { + foreach (Control c in cc) + { + c.Text = ApplicationServiceContext.localeMessageManager.ComposeMessage(groupName, c.Name); + } + } + } +} diff --git a/CloudBuilder/CloudBuilder.Gui/KryptonButtonExtensions.cs b/CloudBuilder/CloudBuilder.Gui/KryptonButtonExtensions.cs new file mode 100644 index 0000000..5373a98 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/KryptonButtonExtensions.cs @@ -0,0 +1,37 @@ +using CloudBuilder; +using CloudBuilder.Gui; +using Microsoft.AspNetCore.Authorization; + +namespace Krypton.Toolkit +{ + public static class KryptonButtonExtensions + { + public static void Set(this KryptonButton kryptonButton, + string permissionName, + Operate permissionMode) + { + GetProvider().SetCustomAttribute(kryptonButton, permissionName, permissionMode); + } + + public static void Set(this KryptonButton kryptonButton, string permissionName, string dependentDetailName, Operate permissionMode) + { + GetProvider().SetCustomAttribute(kryptonButton, permissionName, dependentDetailName, permissionMode); + } + + public static void Set(this KryptonButton kryptonButton, string permissionName, string dependentDetailName) + { + GetProvider().SetCustomAttribute(kryptonButton, permissionName, dependentDetailName); + } + + public static BindingContextCustomAttribute GetCustomAttribute(this KryptonButton kryptonButton) + { + return GetProvider().GetCustomAttribute(kryptonButton); + } + + private static BindingContextAttributeProvider GetProvider() + { + return ServiceHelper.GetService() ?? + throw new InvalidOperationException("BindingContextAttributeProvider is not registered in the service GetProvider()."); + } + } +} diff --git a/CloudBuilder/CloudBuilder.Gui/KryptonCheckBoxExtensions.cs b/CloudBuilder/CloudBuilder.Gui/KryptonCheckBoxExtensions.cs new file mode 100644 index 0000000..01f1e07 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/KryptonCheckBoxExtensions.cs @@ -0,0 +1,132 @@ +using CloudBuilder; +using CloudBuilder.Gui; +using CloudBuilder.Gui.DependencyInjection; +using Krypton.Toolkit; +using Microsoft.AspNetCore.Authorization; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Krypton.Toolkit +{ + public static class KryptonCheckBoxExtensions + { + + public static ExFormSnapshotEntry GetExFormSnapshotEntry(this KryptonCheckBox kryptonCheckBox) + { + string bindDataName = null; + + if (GetProvider().GetCustomAttribute(kryptonCheckBox) != null) + bindDataName = GetProvider().GetCustomAttribute(kryptonCheckBox).BindDataName; + + return new ExFormSnapshotEntry( + kryptonCheckBox.Name, + bindDataName, + kryptonCheckBox.Checked, + kryptonCheckBox.Text); + } + + public static void Set(this KryptonCheckBox kryptonCheckBox, + BindingContextCustomAttribute bindingContext) + { + GetProvider().SetCustomAttribute(kryptonCheckBox, bindingContext); + } + + public static void Set(this KryptonCheckBox kryptonCheckBox, + EnumEditModeColor editModeColor) + { + GetProvider().SetCustomAttribute(kryptonCheckBox, editModeColor); + } + + public static void Set(this KryptonCheckBox kryptonCheckBox, + string bindDataName, + EnumEditModeColor editModeColor) + { + GetProvider().SetCustomAttribute(kryptonCheckBox, bindDataName, editModeColor); + } + + public static void Set(this KryptonCheckBox kryptonCheckBox, + string bindDataName) + { + GetProvider().SetCustomAttribute(kryptonCheckBox, bindDataName, EnumBindDirection.Both); + } + + public static void Set(this KryptonCheckBox kryptonCheckBox, + string bindDataName, + EnumBindDirection bindDirection) + { + GetProvider().SetCustomAttribute(kryptonCheckBox, bindDataName, bindDirection); + } + + + public static void Set(this KryptonCheckBox kryptonCheckBox, + string bindDataName, + EnumBindDirection bindDirection, + EnumEditModeColor editModeColor) + { + GetProvider().SetCustomAttribute(kryptonCheckBox, bindDataName, bindDirection, editModeColor); + } + + public static void Set(this KryptonCheckBox kryptonCheckBox, + string bindDataName, + string bindFormat, + EnumBindDirection bindDirection) + { + GetProvider().SetCustomAttribute(kryptonCheckBox, bindDataName, bindFormat, bindDirection); + } + + public static void Set(this KryptonCheckBox kryptonCheckBox, + string permissionName, + Operate permissionMode) + { + GetProvider().SetCustomAttribute(kryptonCheckBox, permissionName, permissionMode); + } + + public static void Set(this KryptonCheckBox kryptonCheckBox, string permissionName, string dependentDetailName, Operate permissionMode) + { + GetProvider().SetCustomAttribute(kryptonCheckBox, permissionName, dependentDetailName, permissionMode); + } + + public static void Set(this KryptonCheckBox kryptonCheckBox, string permissionName, string dependentDetailName) + { + GetProvider().SetCustomAttribute(kryptonCheckBox, permissionName, dependentDetailName); + } + + public static bool GetValue(this KryptonCheckBox kryptonCheckBox) + { + return kryptonCheckBox.Checked; + } + + + public static void SetValue(this KryptonCheckBox kryptonCheckBox, object value) + { + if (value is bool) + { + kryptonCheckBox.Checked = (bool)value; + } + else if (value is string) + { + kryptonCheckBox.Checked = value.ToString().ToUpper() == "Y" ? true : false; + } + else if (value is decimal || value is int || value is Int32 || value is Int64 || value is Int16 || value is double || value is float) + { + kryptonCheckBox.Checked = Convert.ToDecimal(value) > 0; + } + } + public static BindingContextCustomAttribute GetCustomAttribute(this KryptonCheckBox kryptonCheckBox) + { + return GetProvider().GetCustomAttribute(kryptonCheckBox); + } + + private static BindingContextAttributeProvider GetProvider() + { + return ServiceHelper.GetService() ?? + throw new InvalidOperationException("BindingContextAttributeProvider is not registered in the service GetProvider()."); + } + } +} + + diff --git a/CloudBuilder/CloudBuilder.Gui/KryptonComboBoxExtensions.cs b/CloudBuilder/CloudBuilder.Gui/KryptonComboBoxExtensions.cs new file mode 100644 index 0000000..efcfd94 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/KryptonComboBoxExtensions.cs @@ -0,0 +1,199 @@ +using CloudBuilder; +using CloudBuilder.Core.Utility; +using CloudBuilder.Gui; +using CloudBuilder.Gui.DependencyInjection; +using Krypton.Toolkit; +using Microsoft.AspNetCore.Authorization; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Krypton.Toolkit +{ + public static class KryptonComboBoxExtensions + { + public static ExFormSnapshotEntry GetExFormSnapshotEntry(this KryptonComboBox kryptonComboBox) + { + string bindDataName = null; + + if (GetProvider().GetCustomAttribute(kryptonComboBox) != null) + bindDataName = GetProvider().GetCustomAttribute(kryptonComboBox).BindDataName; + + return new ExFormSnapshotEntry( + kryptonComboBox.Name, + bindDataName, + kryptonComboBox.SelectedValue, + kryptonComboBox.Text); + } + + public static void Set(this KryptonComboBox kryptonComboBox, + BindingContextCustomAttribute bindingContext) + { + GetProvider().SetCustomAttribute(kryptonComboBox, bindingContext); + } + + public static void Set(this KryptonComboBox kryptonComboBox, + EnumEditModeColor editModeColor) + { + GetProvider().SetCustomAttribute(kryptonComboBox, editModeColor); + } + + public static void Set(this KryptonComboBox kryptonComboBox, + EnumEditModeColor editModeColor, string bindDisplayName) + { + GetProvider().SetCustomAttribute(kryptonComboBox, editModeColor, bindDisplayName); + } + + public static void Set(this KryptonComboBox kryptonComboBox, + string bindDataName, + EnumEditModeColor editModeColor) + { + GetProvider().SetCustomAttribute(kryptonComboBox, bindDataName, editModeColor); + } + + public static void Set(this KryptonComboBox kryptonComboBox, string bindDataName, string bindDisplayName, EnumEditModeColor editModeColor) + { + GetProvider().SetCustomAttribute(kryptonComboBox, bindDataName, bindDisplayName, editModeColor); + } + + public static void Set(this KryptonComboBox kryptonComboBox, string bindDataName, string bindFormat, string bindDisplayName, EnumEditModeColor editModeColor) + { + GetProvider().SetCustomAttribute(kryptonComboBox, bindDataName, bindFormat, bindDisplayName, editModeColor); + } + + public static void Set(this KryptonComboBox kryptonComboBox, + string bindDataName) + { + GetProvider().SetCustomAttribute(kryptonComboBox, bindDataName, EnumBindDirection.Both); + } + + public static void Set(this KryptonComboBox kryptonComboBox, + string bindDataName, + EnumBindDirection bindDirection) + { + GetProvider().SetCustomAttribute(kryptonComboBox, bindDataName, bindDirection); + } + + + public static void Set(this KryptonComboBox kryptonComboBox, + string bindDataName, + EnumBindDirection bindDirection, + EnumEditModeColor editModeColor) + { + GetProvider().SetCustomAttribute(kryptonComboBox, bindDataName, bindDirection, editModeColor); + } + + public static void Set(this KryptonComboBox kryptonComboBox, + string bindDataName, + string bindFormat, + EnumBindDirection bindDirection) + { + GetProvider().SetCustomAttribute(kryptonComboBox, bindDataName, bindFormat, bindDirection); + } + + public static void Set(this KryptonComboBox kryptonComboBox, + string permissionName, + Operate permissionMode) + { + GetProvider().SetCustomAttribute(kryptonComboBox, permissionName, permissionMode); + } + + public static void Set(this KryptonComboBox kryptonComboBox, string permissionName, string dependentDetailName, Operate permissionMode) + { + GetProvider().SetCustomAttribute(kryptonComboBox, permissionName, dependentDetailName, permissionMode); + } + + public static void Set(this KryptonComboBox kryptonComboBox, string permissionName, string dependentDetailName) + { + GetProvider().SetCustomAttribute(kryptonComboBox, permissionName, dependentDetailName); + } + public static object GetValue(this KryptonComboBox kryptonComboBox) + { + if (kryptonComboBox.SelectedIndex < 0) return null; + if (kryptonComboBox.SelectedValue == DBNull.Value) return null; + if (kryptonComboBox.SelectedValue is DataRowView) return null; + return kryptonComboBox.SelectedValue; + } + + public static void SetValue(this KryptonComboBox kryptonComboBox, object value) + { + if (value == null) kryptonComboBox.SelectedIndex = -1; + else + kryptonComboBox.SelectedValue = value; + + } + + + //private const string DATA_TABLE_ROW_GUID_ID = "DATA_TABLE_ROW_GUID_ID"; + + public static void SetDataSource(this KryptonComboBox kryptonComboBox, List ds, string displayMember, string valueMember, bool blankOption) + { + kryptonComboBox.DataSource = null; + DataTable dataTableSource = new DataTable(); + //DataTable deleteDataTableSource = new DataTable(); + + if (ds == null) + { + return; + } + + dataTableSource = DataTableConvertor.ToDataTable(ds, blankOption); + + kryptonComboBox.DataSource = dataTableSource; + + kryptonComboBox.DisplayMember = displayMember; + kryptonComboBox.ValueMember = valueMember; + + dataTableSource.AcceptChanges(); + + //deleteDataTableSource = dataTableSource.Clone(); + } + + public static void Clear(this KryptonComboBox kryptonComboBox) + { + kryptonComboBox.DataSource = null; + } + + public static void SetDataSource(this KryptonComboBox kryptonComboBox, T[] ds, string displayMember, string valueMember, bool blankOption) + { + kryptonComboBox.DataSource = null; + DataTable dataTableSource = new DataTable(); + //DataTable deleteDataTableSource = new DataTable(); + + if (ds == null) + { + return; + } + //首先將entity轉為datatable + dataTableSource = DataTableConvertor.ToDataTable(ds, blankOption); + + kryptonComboBox.DataSource = dataTableSource; + kryptonComboBox.DisplayMember = displayMember; + kryptonComboBox.ValueMember = valueMember; + + dataTableSource.AcceptChanges(); + + //deleteDataTableSource = dataTableSource.Clone(); + } + + public static void SetDataSource(this KryptonComboBox kryptonComboBox, TableName[] values, bool blankOption) + { + kryptonComboBox.SetDataSource>(values, TableName.DISPLAY_NAME, TableName.VALUE, blankOption); + } + + public static BindingContextCustomAttribute GetCustomAttribute(this KryptonComboBox kryptonComboBox) + { + return GetProvider().GetCustomAttribute(kryptonComboBox); + } + + private static BindingContextAttributeProvider GetProvider() + { + return ServiceHelper.GetService() ?? + throw new InvalidOperationException("BindingContextAttributeProvider is not registered in the service GetProvider()."); + } + } +} diff --git a/CloudBuilder/CloudBuilder.Gui/KryptonDataGridViewColumnSetDialog.cs b/CloudBuilder/CloudBuilder.Gui/KryptonDataGridViewColumnSetDialog.cs new file mode 100644 index 0000000..f9f3073 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/KryptonDataGridViewColumnSetDialog.cs @@ -0,0 +1,553 @@ +using CloudBuilder; +using CloudBuilder.Core.DependencyInjection.Form; +using CloudBuilder.Core.DependencyInjection.Request; +using CloudBuilder.Gui; +using CloudBuilder.Gui.DependencyInjection; +using CloudBuilder.Request.Security; +using CloudBuilder.Security; +using CloudBuilder.Security.Entity; +using CloudBuilder.Security.Policy; +using CloudBuilder.Util; +using Microsoft.AspNetCore.Http.Extensions; +using Microsoft.Extensions.DependencyInjection; +using Newtonsoft.Json; +using System.ComponentModel.DataAnnotations; +using System.Runtime.Serialization; + +namespace Krypton.Toolkit +{ + public partial class KryptonDataGridViewColumnSetDialog : KryptonForm + { + private SecurityMessagePolicy securityMessagePolicy; + private string frozenColumnName; + private TableLayoutPanel tableLayoutPanel1; + private TableLayoutPanel tableLayoutPanel2; + private KryptonButton allBut; + private KryptonButton clearBut; + private KryptonButton reverseBut; + private KryptonButton upBut; + private KryptonButton downBut; + private KryptonButton unfreezeBut; + private KryptonButton frozenBut; + private KryptonLabel kryptonLabel1; + private KryptonLabel kryptonLabel2; + private TableLayoutPanel tableLayoutPanel3; + private KryptonButton okBut; + private KryptonButton cancelBut; + private KryptonTextBox controlNameTxt; + private KryptonTextBox frozenColumnTxt; + private TreeView tv; + private string parentName; + private GuiBindingContext guiBindingContext; + private KryptonButton resetBut; + private GuiOperateHelper guiHelper = null; + + public KryptonDataGridViewColumnSetDialog(KryptonDataGridView _dgv) + { + InitializeComponent(); + + securityMessagePolicy = ServiceHelper.GetTypeService()!; + + this.Text = "调整列属性"; + guiBindingContext = new GuiBindingContext(); + guiHelper = new GuiOperateHelper(); + + + dgv = _dgv; + controlNameTxt.Text = parentName = _dgv.GetFormName(_dgv) + "." + _dgv.Name; + + + this.AcceptButton = okBut; + this.CancelButton = cancelBut; + + + guiHelper.EnableControls(false, controlNameTxt, frozenColumnTxt); + + OnLoad(); + } + private KryptonDataGridView dgv; + + private Dictionary dic; + + private void OnLoad() + { + if (dgv == null) return; + TreeNode node; + DataGridViewColumn column; + DataGridViewColumn tmpcol; + + dic = dgv.SaveGridView(); + + for (int i = 0; i < dgv.Columns.Count; i++) + { + for (int j = 0; j < dgv.Columns.Count; j++) + { + tmpcol = dgv.Columns[j]; + if (tmpcol.DisplayIndex == i) + { + column = dgv.Columns[j]; + if (column.Tag == null || (int)(column.Tag) != 0) //不显示的隐藏列初始化为tag=0 + { + node = new TreeNode(column.HeaderText); + node.Tag = column; + + node.Checked = column.Visible; + + node.ImageIndex = i; + + node.ToolTipText = (i * 2).ToString(); + + tv.Nodes.Add(node); + + if (column.Frozen) + { + frozenColumnName = column.Name; + frozenColumnTxt.Text = column.HeaderText; + } + } + } + } + } + } + + private void okBut_Click(object sender, EventArgs e) + { + RefreshDataGridView(); + + this.DialogResult = DialogResult.OK; + this.Close(); + } + + private void RefreshDataGridView() + { + dic = new Dictionary(); + + int i = 0; + + List df = new List(); + DataGridViewColumnsInfo cf; + + foreach (TreeNode node in tv.Nodes) + { + dgv.Columns[i].Frozen = false; + + cf = new DataGridViewColumnsInfo(); + cf.DisplayIndex = tv.Nodes[i].ImageIndex.ToString(); + cf.Width = ((DataGridViewColumn)node.Tag).Width.ToString(); + cf.Visiable = tv.Nodes[i].Checked ? "true" : "false"; + cf.Name = ((DataGridViewColumn)node.Tag).Name; + + df.Add(cf); + + dic.Add(cf.Name, new string[] { cf.DisplayIndex, cf.Width, cf.Visiable }); + + i++; + } + + dgv.LoadGridView(dic); + + if (!string.IsNullOrEmpty(frozenColumnName)) dgv.Columns[frozenColumnName].Frozen = true; + + + ExDataGridViewInfo info = new ExDataGridViewInfo(); + info.FrozenName = frozenColumnName; + + info.ColumnsInfo = df.ToArray(); + + string serializable = SerializeHelper.Serialize(info); + + SecurityUserPreferenceEntity upf = new SecurityUserPreferenceEntity(); + upf.PreferenceKey = parentName; + upf.Preference = serializable; + upf.CreatedDatetime = upf.UpdatedDatetime = DateTime.Now; + upf.CreatedBy = upf.UpdatedBy = upf.Username = ApplicationServiceContext.Context.Requestor; + try + { + SecurityUserPreferenceRequest request = ServiceHelper.GetTypeService(); + + request.Update(upf); + + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_SUCCEED_UPDATED_NULL)); + } + catch (ValidationException validation) + { + ShowMessageBox.ShowInfo(validation); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex); + } + } + + private void upBut_Click(object sender, EventArgs e) + { + TreeNode selected = tv.SelectedNode; + tv.SelectedNode.ToolTipText = (Convert.ToInt32(tv.SelectedNode.ToolTipText) - 3).ToString(); + ResetTreeNode(selected); + } + + private void downBut_Click(object sender, EventArgs e) + { + TreeNode selected = tv.SelectedNode; + + tv.SelectedNode.ToolTipText = (Convert.ToInt32(tv.SelectedNode.ToolTipText) + 3).ToString(); + + ResetTreeNode(selected); + } + + private void ResetTreeNode(TreeNode selected) + { + List ls = new List(); + TreeNode temp = selected; + + foreach (TreeNode node in tv.Nodes) + { + ls.Add(node); + } + + tv.Nodes.Clear(); + + ls = ls.OrderBy(x => Convert.ToInt32(x.ToolTipText)).ToList(); + + int i = 0; + foreach (TreeNode node in ls) + { + node.ToolTipText = (i * 2).ToString(); + node.ImageIndex = i; + tv.Nodes.Add(node); + i++; + + if (node.Text != selected.Text) continue; + + temp = node; + } + + tv.SelectedNode = temp; + tv.Select(); + } + + private void btnCancel_Click(object sender, EventArgs e) + { + this.DialogResult = DialogResult.Cancel; + this.Close(); + } + + private void frozenBut_Click(object sender, EventArgs e) + { + if (!tv.SelectedNode.Checked) return; + + frozenColumnName = ((DataGridViewColumn)tv.SelectedNode.Tag).Name; + frozenColumnTxt.Text = ((DataGridViewColumn)tv.SelectedNode.Tag).HeaderText; + + tv.Select(); + } + + private void unfreezeBut_Click(object sender, EventArgs e) + { + frozenColumnTxt.Text = null; + frozenColumnName = null; + tv.Select(); + } + + private void tv_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e) + { + tv.SelectedNode.Checked = !tv.SelectedNode.Checked; + } + + private void InitializeComponent() + { + tableLayoutPanel1 = new TableLayoutPanel(); + tableLayoutPanel2 = new TableLayoutPanel(); + allBut = new KryptonButton(); + clearBut = new KryptonButton(); + reverseBut = new KryptonButton(); + upBut = new KryptonButton(); + downBut = new KryptonButton(); + unfreezeBut = new KryptonButton(); + frozenBut = new KryptonButton(); + kryptonLabel1 = new KryptonLabel(); + kryptonLabel2 = new KryptonLabel(); + tableLayoutPanel3 = new TableLayoutPanel(); + okBut = new KryptonButton(); + cancelBut = new KryptonButton(); + resetBut = new KryptonButton(); + controlNameTxt = new KryptonTextBox(); + frozenColumnTxt = new KryptonTextBox(); + tv = new TreeView(); + tableLayoutPanel1.SuspendLayout(); + tableLayoutPanel2.SuspendLayout(); + tableLayoutPanel3.SuspendLayout(); + SuspendLayout(); + // + // tableLayoutPanel1 + // + tableLayoutPanel1.ColumnCount = 3; + tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F)); + tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel1.Controls.Add(tableLayoutPanel2, 2, 2); + tableLayoutPanel1.Controls.Add(kryptonLabel1, 0, 1); + tableLayoutPanel1.Controls.Add(kryptonLabel2, 0, 0); + tableLayoutPanel1.Controls.Add(tableLayoutPanel3, 1, 3); + tableLayoutPanel1.Controls.Add(controlNameTxt, 1, 0); + tableLayoutPanel1.Controls.Add(frozenColumnTxt, 1, 1); + tableLayoutPanel1.Controls.Add(tv, 1, 2); + tableLayoutPanel1.Dock = DockStyle.Fill; + tableLayoutPanel1.Location = new Point(0, 0); + tableLayoutPanel1.Name = "tableLayoutPanel1"; + tableLayoutPanel1.RowCount = 4; + tableLayoutPanel1.RowStyles.Add(new RowStyle()); + tableLayoutPanel1.RowStyles.Add(new RowStyle()); + tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent, 100F)); + tableLayoutPanel1.RowStyles.Add(new RowStyle()); + tableLayoutPanel1.Size = new Size(467, 596); + tableLayoutPanel1.TabIndex = 0; + // + // tableLayoutPanel2 + // + tableLayoutPanel2.AutoSize = true; + tableLayoutPanel2.AutoSizeMode = AutoSizeMode.GrowAndShrink; + tableLayoutPanel2.ColumnCount = 1; + tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel2.Controls.Add(allBut, 0, 2); + tableLayoutPanel2.Controls.Add(clearBut, 0, 3); + tableLayoutPanel2.Controls.Add(reverseBut, 0, 4); + tableLayoutPanel2.Controls.Add(upBut, 0, 5); + tableLayoutPanel2.Controls.Add(downBut, 0, 6); + tableLayoutPanel2.Controls.Add(unfreezeBut, 0, 0); + tableLayoutPanel2.Controls.Add(frozenBut, 0, 1); + tableLayoutPanel2.Location = new Point(371, 58); + tableLayoutPanel2.Margin = new Padding(0); + tableLayoutPanel2.Name = "tableLayoutPanel2"; + tableLayoutPanel2.RowCount = 7; + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.Size = new Size(96, 217); + tableLayoutPanel2.TabIndex = 0; + // + // allBut + // + allBut.Location = new Point(3, 65); + allBut.Name = "allBut"; + allBut.Size = new Size(90, 25); + allBut.TabIndex = 1; + allBut.Values.Text = "全选"; + allBut.Click += allBut_Click; + // + // clearBut + // + clearBut.Location = new Point(3, 96); + clearBut.Name = "clearBut"; + clearBut.Size = new Size(90, 25); + clearBut.TabIndex = 1; + clearBut.Values.Text = "清空"; + clearBut.Click += clearBut_Click; + // + // reverseBut + // + reverseBut.Location = new Point(3, 127); + reverseBut.Name = "reverseBut"; + reverseBut.Size = new Size(90, 25); + reverseBut.TabIndex = 1; + reverseBut.Values.Text = "反选"; + reverseBut.Click += reverseBut_Click; + // + // upBut + // + upBut.Location = new Point(3, 158); + upBut.Name = "upBut"; + upBut.Size = new Size(90, 25); + upBut.TabIndex = 1; + upBut.Values.Text = "向上"; + upBut.Click += upBut_Click; + // + // downBut + // + downBut.Location = new Point(3, 189); + downBut.Name = "downBut"; + downBut.Size = new Size(90, 25); + downBut.TabIndex = 1; + downBut.Values.Text = "向下"; + downBut.Click += downBut_Click; + // + // unfreezeBut + // + unfreezeBut.Location = new Point(3, 3); + unfreezeBut.Name = "unfreezeBut"; + unfreezeBut.Size = new Size(90, 25); + unfreezeBut.TabIndex = 1; + unfreezeBut.Values.Text = "解冻"; + unfreezeBut.Click += unfreezeBut_Click; + // + // frozenBut + // + frozenBut.Location = new Point(3, 34); + frozenBut.Name = "frozenBut"; + frozenBut.Size = new Size(90, 25); + frozenBut.TabIndex = 1; + frozenBut.Values.Text = "冻结"; + frozenBut.Click += frozenBut_Click; + // + // kryptonLabel1 + // + kryptonLabel1.Location = new Point(3, 32); + kryptonLabel1.Name = "kryptonLabel1"; + kryptonLabel1.Size = new Size(65, 20); + kryptonLabel1.TabIndex = 1; + kryptonLabel1.Values.Text = "冻结列名:"; + // + // kryptonLabel2 + // + kryptonLabel2.Location = new Point(3, 3); + kryptonLabel2.Name = "kryptonLabel2"; + kryptonLabel2.Size = new Size(65, 20); + kryptonLabel2.TabIndex = 2; + kryptonLabel2.Values.Text = "组件名称:"; + kryptonLabel2.Visible = false; + // + // tableLayoutPanel3 + // + tableLayoutPanel3.AutoSize = true; + tableLayoutPanel3.AutoSizeMode = AutoSizeMode.GrowAndShrink; + tableLayoutPanel3.ColumnCount = 4; + tableLayoutPanel1.SetColumnSpan(tableLayoutPanel3, 2); + tableLayoutPanel3.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F)); + tableLayoutPanel3.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel3.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel3.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel3.Controls.Add(okBut, 2, 0); + tableLayoutPanel3.Controls.Add(cancelBut, 3, 0); + tableLayoutPanel3.Controls.Add(resetBut, 1, 0); + tableLayoutPanel3.Dock = DockStyle.Fill; + tableLayoutPanel3.Location = new Point(71, 565); + tableLayoutPanel3.Margin = new Padding(0); + tableLayoutPanel3.Name = "tableLayoutPanel3"; + tableLayoutPanel3.RowCount = 1; + tableLayoutPanel3.RowStyles.Add(new RowStyle()); + tableLayoutPanel3.Size = new Size(396, 31); + tableLayoutPanel3.TabIndex = 3; + // + // okBut + // + okBut.Location = new Point(207, 3); + okBut.Name = "okBut"; + okBut.Size = new Size(90, 25); + okBut.TabIndex = 0; + okBut.Values.Text = "确定"; + okBut.Click += okBut_Click; + // + // cancelBut + // + cancelBut.Location = new Point(303, 3); + cancelBut.Name = "cancelBut"; + cancelBut.Size = new Size(90, 25); + cancelBut.TabIndex = 1; + cancelBut.Values.Text = "取消"; + // + // resetBut + // + resetBut.Location = new Point(111, 3); + resetBut.Name = "resetBut"; + resetBut.Size = new Size(90, 25); + resetBut.TabIndex = 0; + resetBut.Values.Text = "重置"; + resetBut.Click += resetBut_Click; + // + // controlNameTxt + // + controlNameTxt.Dock = DockStyle.Fill; + controlNameTxt.Location = new Point(74, 3); + controlNameTxt.Name = "controlNameTxt"; + controlNameTxt.Size = new Size(294, 23); + controlNameTxt.TabIndex = 4; + controlNameTxt.Visible = false; + // + // frozenColumnTxt + // + frozenColumnTxt.Dock = DockStyle.Fill; + frozenColumnTxt.Location = new Point(74, 32); + frozenColumnTxt.Name = "frozenColumnTxt"; + frozenColumnTxt.Size = new Size(294, 23); + frozenColumnTxt.TabIndex = 4; + // + // tv + // + tv.CheckBoxes = true; + tv.Dock = DockStyle.Fill; + tv.Location = new Point(74, 58); + tv.Margin = new Padding(3, 0, 3, 3); + tv.Name = "tv"; + tv.Size = new Size(294, 504); + tv.TabIndex = 7; + tv.NodeMouseDoubleClick += tv_NodeMouseDoubleClick; + // + // KryptonDataGridViewColumnSetDialog + // + ClientSize = new Size(467, 596); + Controls.Add(tableLayoutPanel1); + Name = "KryptonDataGridViewColumnSetDialog"; + tableLayoutPanel1.ResumeLayout(false); + tableLayoutPanel1.PerformLayout(); + tableLayoutPanel2.ResumeLayout(false); + tableLayoutPanel3.ResumeLayout(false); + ResumeLayout(false); + + } + + private void allBut_Click(object sender, EventArgs e) + { + foreach (TreeNode node in tv.Nodes) + { + node.Checked = true; + } + } + + private void clearBut_Click(object sender, EventArgs e) + { + foreach (TreeNode node in tv.Nodes) + { + node.Checked = false; + } + } + + private void reverseBut_Click(object sender, EventArgs e) + { + foreach (TreeNode node in tv.Nodes) + { + node.Checked = !node.Checked; + } + } + + private void resetBut_Click(object sender, EventArgs e) + { + SecurityUserPreferenceEntityKey upf = new SecurityUserPreferenceEntityKey(); + upf.PreferenceKey = parentName; + upf.Username = ApplicationServiceContext.Context.Requestor; + try + { + + SecurityUserPreferenceRequest request = ServiceHelper.GetTypeService(); + + request.Delete(upf); + + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_SUCCEED_UPDATED_NULL)); + + this.DialogResult = DialogResult.OK; + this.Close(); + } + catch (ValidationException validation) + { + ShowMessageBox.ShowInfo(validation); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex); + } + } + } +} diff --git a/CloudBuilder/CloudBuilder.Gui/KryptonDataGridViewColumnSetDialog.resx b/CloudBuilder/CloudBuilder.Gui/KryptonDataGridViewColumnSetDialog.resx new file mode 100644 index 0000000..8b2ff64 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/KryptonDataGridViewColumnSetDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Gui/KryptonDataGridViewExtensions.cs b/CloudBuilder/CloudBuilder.Gui/KryptonDataGridViewExtensions.cs new file mode 100644 index 0000000..a3e57a1 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/KryptonDataGridViewExtensions.cs @@ -0,0 +1,847 @@ +using CloudBuilder; +using CloudBuilder.Core.DependencyInjection.Form; +using CloudBuilder.Core.Service; +using CloudBuilder.Core.Utility; +using CloudBuilder.Gui; +using CloudBuilder.Gui.DependencyInjection; +using CloudBuilder.Request.Security; +using CloudBuilder.Security; +using CloudBuilder.Security.Entity; +using CloudBuilder.Security.SearchCriteria; +using CloudBuilder.Util; +using Microsoft.Extensions.DependencyInjection; +using Newtonsoft.Json; +using System.ComponentModel; +using System.Data; +using System.Linq; +using System.Reflection; +using System.Windows.Forms; + +namespace Krypton.Toolkit +{ + public static class KryptonDataGridViewExtensions + { + public static void Set(this KryptonDataGridView kryptonDataGridView, + BindingContextCustomAttribute bindingContext) + { + GetProvider().SetCustomAttribute(kryptonDataGridView, bindingContext); + } + + public static void Set(this KryptonDataGridView kryptonDataGridView, List dataSource, + DataTable dataTableSource, + DataTable deleteDataTableSource + ) + { + GetProvider().SetCustomAttribute(kryptonDataGridView, dataSource, dataTableSource, deleteDataTableSource); + } + + #region 数据操作 + + + public static void DataSourceSorted(this KryptonDataGridView kryptonDataGridView, + DataGridViewColumn cloumn, string columnName, ListSortDirection sortDirection) + { + DataTable dataTableSource = GetProvider().GetCustomAttribute(kryptonDataGridView).DataTableSource; + + if (dataTableSource == null || dataTableSource.Columns.Count == 0) return; + dataTableSource.DefaultView.Sort = columnName; + kryptonDataGridView.Sort(cloumn, sortDirection); + } + + public static void SetDataSource(this KryptonDataGridView kryptonDataGridView, + List ds) + { + DataTable dataTableSource = GetProvider().GetCustomAttribute(kryptonDataGridView).DataTableSource; + DataTable deleteDataTableSource = GetProvider().GetCustomAttribute(kryptonDataGridView).DeleteDataTableSource; + if (ds == null) + { + kryptonDataGridView.DataSource = null; + kryptonDataGridView.Refresh(); + dataTableSource = new DataTable(); + deleteDataTableSource = new DataTable(); + Set(kryptonDataGridView, null!, dataTableSource, deleteDataTableSource); + return; + } + else + { + + } + + dataTableSource = DataTableConvertor.ToDataTable(ds); + + kryptonDataGridView.DataSource = dataTableSource; + kryptonDataGridView.Refresh(); + dataTableSource.AcceptChanges(); + + deleteDataTableSource = dataTableSource.Clone(); + + IEnumerable dynamicEnumerable = ds.Cast(); + + Set(kryptonDataGridView, dynamicEnumerable.ToList(), dataTableSource, deleteDataTableSource); + } + + public static void Clear(this KryptonDataGridView kryptonDataGridView) + { + DataTable dataTableSource = GetProvider().GetCustomAttribute(kryptonDataGridView).DataTableSource; + DataTable deleteDataTableSource = GetProvider().GetCustomAttribute(kryptonDataGridView).DeleteDataTableSource; + + kryptonDataGridView.DataSource = null; + kryptonDataGridView.Refresh(); + dataTableSource = new DataTable(); + deleteDataTableSource = new DataTable(); + Set(kryptonDataGridView, null!, dataTableSource, deleteDataTableSource); + } + + public static void SetDataSource(this KryptonDataGridView kryptonDataGridView, + T[] ds) + { + DataTable dataTableSource = GetProvider().GetCustomAttribute(kryptonDataGridView).DataTableSource; + DataTable deleteDataTableSource = GetProvider().GetCustomAttribute(kryptonDataGridView).DeleteDataTableSource; + + + + if (ds == null) + { + kryptonDataGridView.DataSource = null; + dataTableSource = new DataTable(); + deleteDataTableSource = new DataTable(); + Set(kryptonDataGridView, null!, dataTableSource, deleteDataTableSource); + return; + } + + //首先將entity轉為datatable + dataTableSource = DataTableConvertor.ToDataTable(ds); + dataTableSource.AcceptChanges(); + deleteDataTableSource = dataTableSource.Clone(); + + IEnumerable dynamicEnumerable = ds.Cast(); + + Set(kryptonDataGridView, dynamicEnumerable.ToList(), dataTableSource, deleteDataTableSource); + + kryptonDataGridView.DataSource = dataTableSource; + kryptonDataGridView.Refresh(); + } + + public static void SetDataSourceCustomAttributee(this KryptonDataGridView kryptonDataGridView, + T[] ds) + { + if (ds == null) + { + kryptonDataGridView.DataSource = null; + GetProvider().GetCustomAttribute(kryptonDataGridView).DataSource = default!; + } + else + { + IEnumerable dynamicEnumerable = ds.Cast(); + + GetProvider().GetCustomAttribute(kryptonDataGridView).DataSource = dynamicEnumerable.ToList(); + } + } + + public static void SetDataSourceCustomAttributee(this KryptonDataGridView kryptonDataGridView, + List ds) + { + if (ds == null) + { + kryptonDataGridView.DataSource = null; + GetProvider().GetCustomAttribute(kryptonDataGridView).DataSource = default!; + } + else + { + IEnumerable dynamicEnumerable = ds.Cast(); + + GetProvider().GetCustomAttribute(kryptonDataGridView).DataSource = dynamicEnumerable.ToList(); + } + } + + public static T[] GetAddRows(this KryptonDataGridView kryptonDataGridView) where T : new() + { + return GetRows(kryptonDataGridView, DataRowState.Added); + } + + private static T[] GetRows(this KryptonDataGridView kryptonDataGridView, DataRowState drs) where T : new() + { + DataTable dataTableSource = GetProvider().GetCustomAttribute(kryptonDataGridView).DataTableSource; + + if (dataTableSource == null || dataTableSource.Rows.Count == 0) return null!; + + DataTable dt = dataTableSource.Clone(); + foreach (DataRowView drv in dataTableSource.DefaultView) + { + if (drv.Row.RowState != drs || drv.Row.RowState == DataRowState.Deleted) continue; + + //drv.Row.AcceptChanges(); + dt.ImportRow(drv.Row); + } + + if (dt.Rows.Count == 0) return null; + + List l = DataTableConvertor.ConvertToList(dt); + + return l.ToArray(); + } + + public static void AddRow(this KryptonDataGridView kryptonDataGridView, T rows) where T : new() + { + AddRow(kryptonDataGridView, new T[] { rows }); + } + + public static void AddRow(this KryptonDataGridView kryptonDataGridView, List rows) where T : new() + { + AddRow(kryptonDataGridView, rows.ToArray()); + } + + public static void UpdateRow(this KryptonDataGridView kryptonDataGridView, T d, int rowIndex) + { + DataTable dataTableSource = GetProvider().GetCustomAttribute(kryptonDataGridView).DataTableSource; + DataTable deleteDataTableSource = GetProvider().GetCustomAttribute(kryptonDataGridView).DeleteDataTableSource; + + if (d == null) return; + if (dataTableSource == null || dataTableSource.Rows.Count == 0) return; + + GetProvider().GetCustomAttribute(kryptonDataGridView).DataSource[rowIndex] = d; + + int i = 0; + foreach (DataRowView drv in dataTableSource.DefaultView) + { + if (drv.Row.RowState == DataRowState.Deleted) + { + rowIndex = rowIndex + 1; + i++; + continue; + } + + if (i != rowIndex) + { + i++; + continue; + } + + DataRow dr = drv.Row; + + PropertyInfo[] pi = typeof(T).GetProperties(); + + foreach (PropertyInfo p in pi) + { + foreach (DataColumn dc in dataTableSource.Columns) + { + if (p.Name != dc.ColumnName) continue; + + dr[dc] = p.GetValue(d, null) ?? DBNull.Value; + + break; + } + } + + kryptonDataGridView.DataSource = dataTableSource; + kryptonDataGridView.Refresh(); + Set(kryptonDataGridView, GetProvider().GetCustomAttribute(kryptonDataGridView).DataSource, dataTableSource, deleteDataTableSource); + return; + } + } + + public static void DeleteRow(this KryptonDataGridView kryptonDataGridView, int rowIndex) + { + DataTable dataTableSource = GetProvider().GetCustomAttribute(kryptonDataGridView).DataTableSource; + DataTable deleteDataTableSource = GetProvider().GetCustomAttribute(kryptonDataGridView).DeleteDataTableSource; + + GetProvider().GetCustomAttribute(kryptonDataGridView).DataSource.RemoveAt(rowIndex); + + int i = 0; + foreach (DataRowView drv in dataTableSource.DefaultView) + { + if (drv.Row.RowState == DataRowState.Deleted) + { + rowIndex = rowIndex + 1; + + i++; + continue; + } + + if (i != rowIndex) + { + i++; + continue; + } + + if (drv.Row.RowState != DataRowState.Added) + deleteDataTableSource.ImportRow(drv.Row); + + dataTableSource.DefaultView.Delete(rowIndex); + + i++; + break; + } + + Set(kryptonDataGridView, GetProvider().GetCustomAttribute(kryptonDataGridView).DataSource, dataTableSource, deleteDataTableSource); + } + + public static void DeleteRows(this KryptonDataGridView kryptonDataGridView, DataGridViewSelectedRowCollection drc) + { + foreach (DataGridViewRow dr in drc) + { + DeleteRow(kryptonDataGridView, dr.Index); + } + } + + public static void DeleteRows(this KryptonDataGridView kryptonDataGridView, DataGridViewSelectedCellCollection drc) + { + List rows = new List(); + + foreach (DataGridViewCell dr in drc) + { + if (rows.Contains(dr.RowIndex)) continue; + + rows.Add(dr.RowIndex); + } + //删除要从最大的行先删除,不然数据会发生变化,大的行数,接下来就没有对应的了 + foreach (int i in rows.OrderByDescending(x => x).ToArray()) + { + DeleteRow(kryptonDataGridView, i); + } + } + + public static void AddRow(this KryptonDataGridView kryptonDataGridView, T[] rows) where T : new() + { + DataTable dataTableSource = GetProvider().GetCustomAttribute(kryptonDataGridView).DataTableSource; + DataTable deleteDataTableSource = GetProvider().GetCustomAttribute(kryptonDataGridView).DeleteDataTableSource; + + if (rows != null && rows.Length > 0) + { + foreach (var row in rows) + { + if (GetProvider().GetCustomAttribute(kryptonDataGridView).DataSource == null) + GetProvider().GetCustomAttribute(kryptonDataGridView).DataSource = new List(); + + GetProvider().GetCustomAttribute(kryptonDataGridView).DataSource.Add(row); + } + } + + DataTable dt = DataTableConvertor.ToDataTable(rows); + + if (dataTableSource == null || dataTableSource.Columns.Count == 0) + { + dataTableSource = dt.Clone(); + + kryptonDataGridView.DataSource = dataTableSource; + + dataTableSource.AcceptChanges(); + + deleteDataTableSource = dataTableSource.Clone(); + } + + foreach (DataRow dc in dt.Rows) + { + dataTableSource.ImportRow(dc); + kryptonDataGridView.DataSource = dataTableSource; + kryptonDataGridView.Refresh(); + } + + Set(kryptonDataGridView, GetProvider().GetCustomAttribute(kryptonDataGridView).DataSource, dataTableSource, deleteDataTableSource); + } + + public static T[] GetDeleteRows(this KryptonDataGridView kryptonDataGridView) where T : new() + { + DataTable dataTableSource = GetProvider().GetCustomAttribute(kryptonDataGridView).DataTableSource; + DataTable deleteDataTableSource = GetProvider().GetCustomAttribute(kryptonDataGridView).DeleteDataTableSource; + + if (deleteDataTableSource.Rows.Count == 0) return null; + + List l = DataTableConvertor.ConvertToList(deleteDataTableSource); + + return l.ToArray(); + } + + public static T[] GetUpdateRows(this KryptonDataGridView kryptonDataGridView) where T : new() + { + return GetRows(kryptonDataGridView, DataRowState.Modified); + } + + public static T[] GetUnchangedRows(this KryptonDataGridView kryptonDataGridView) where T : new() + { + return GetRows(kryptonDataGridView, DataRowState.Unchanged); + } + + public static T[] GetAllRows(this KryptonDataGridView kryptonDataGridView) where T : new() + { + DataTable dataTableSource = GetProvider().GetCustomAttribute(kryptonDataGridView).DataTableSource; + DataTable deleteDataTableSource = GetProvider().GetCustomAttribute(kryptonDataGridView).DeleteDataTableSource; + + if (dataTableSource.Rows.Count == 0) return null; + + + DataTable dt = dataTableSource.Clone(); + + foreach (DataRowView drv in dataTableSource.DefaultView) + { + if (drv.Row.RowState == DataRowState.Deleted) continue; + + //drv.Row.AcceptChanges(); + dt.ImportRow(drv.Row); + } + + if (dt.Rows.Count == 0) return null; + + List l = DataTableConvertor.ConvertToList(dt); + + return l.ToArray(); + } + + public static T[] GetDataSourceCustomAttribute(this KryptonDataGridView kryptonDataGridView) where T : new() + { + if (GetProvider().GetCustomAttribute(kryptonDataGridView).DataSource == null) return null!; + + IEnumerable dynamicEnumerable = GetProvider().GetCustomAttribute(kryptonDataGridView).DataSource.Cast(); + return dynamicEnumerable.ToArray(); + } + + public static T GetRowData(this KryptonDataGridView kryptonDataGridView, int rowIndex) where T : new() + { + DataTable dataTableSource = GetProvider().GetCustomAttribute(kryptonDataGridView).DataTableSource; + + if (dataTableSource == null || dataTableSource.Rows.Count == 0) return default!; + + int i = 0; + foreach (DataRowView drv in dataTableSource.DefaultView) + { + if (drv.Row.RowState == DataRowState.Deleted) + { + rowIndex = rowIndex + 1; + i++; + continue; + } + + if (i != rowIndex) + { + i++; + continue; + } + DataTable dt = dataTableSource.Clone(); + //drv.Row.AcceptChanges(); + dt.ImportRow(drv.Row); + + List l = DataTableConvertor.ConvertToList(dt); + + i++; + return l[0]; + } + + return default(T); + } + + public static T[] GetSelectedCellsData(this KryptonDataGridView kryptonDataGridView) where T : new() + { + DataTable dataTableSource = GetProvider().GetCustomAttribute(kryptonDataGridView).DataTableSource; + + if (dataTableSource == null || dataTableSource.Rows.Count == 0) return null!; + + List rows = new List(); + + foreach (DataGridViewCell dr in kryptonDataGridView.SelectedCells) + { + if (rows.Contains(dr.RowIndex)) continue; + + rows.Add(dr.RowIndex); + } + + if (rows.Count == 0) return null; + + return GetRowsData(kryptonDataGridView, rows.ToArray()); + } + + public static T[] GetSelectedRowsData(this KryptonDataGridView kryptonDataGridView) where T : new() + { + DataTable dataTableSource = GetProvider().GetCustomAttribute(kryptonDataGridView).DataTableSource; + if (dataTableSource == null || dataTableSource.Rows.Count == 0) return null!; + + List rows = new List(); + + foreach (DataGridViewRow dr in kryptonDataGridView.SelectedRows) + { + if (rows.Contains(dr.Index)) continue; + + rows.Add(dr.Index); + } + + if (rows.Count == 0) return null; + + return GetRowsData(kryptonDataGridView, rows.ToArray()); + } + + public static T[] GetRowsData(this KryptonDataGridView kryptonDataGridView, int[] rows) where T : new() + { + DataTable dataTableSource = GetProvider().GetCustomAttribute(kryptonDataGridView).DataTableSource; + if (dataTableSource == null) return null; + + DataTable dt = dataTableSource.Clone(); + + foreach (int j in rows) + { + int rowIndex = j; + + int i = 0; + foreach (DataRowView drv in dataTableSource.DefaultView) + { + if (drv.Row.RowState == DataRowState.Deleted) + { + rowIndex = rowIndex + 1; + i++; + continue; + } + + if (i != rowIndex) + { + i++; + continue; + } + //drv.Row.AcceptChanges(); + dt.ImportRow(drv.Row); + break; + } + } + + List l = DataTableConvertor.ConvertToList(dt); + + return l.ToArray(); + } + + public static int[] GetRowIndexs(this KryptonDataGridView kryptonDataGridView, DataGridViewSelectedCellCollection selectedCells) + { + List rowIndexs = new List(); + + foreach (DataGridViewCell cell in selectedCells) + { + if (!rowIndexs.Contains(cell.RowIndex)) rowIndexs.Add(cell.RowIndex); + } + + return rowIndexs.ToArray(); + } + + public static ExDataGridViewSnapshot TakeSnapshot(this KryptonDataGridView kryptonDataGridView) + { + DataTable dataTableSource = GetProvider().GetCustomAttribute(kryptonDataGridView).DataTableSource; + DataTable deleteDataTableSource = GetProvider().GetCustomAttribute(kryptonDataGridView).DeleteDataTableSource; + + if (dataTableSource == null || GetProvider().GetCustomAttribute(kryptonDataGridView).DataSource == null) return null; + + return new ExDataGridViewSnapshot() + { + DataSource = GetProvider().GetCustomAttribute(kryptonDataGridView).DataSource, + DataTableSource = dataTableSource.Copy(), + DeleteDataTableSource = deleteDataTableSource.Copy() + }; + } + + public static void SetSnapshot(this KryptonDataGridView kryptonDataGridView, ExDataGridViewSnapshot snapshot) + { + DataTable dataTableSource = GetProvider().GetCustomAttribute(kryptonDataGridView).DataTableSource; + DataTable deleteDataTableSource = GetProvider().GetCustomAttribute(kryptonDataGridView).DeleteDataTableSource; + + if (snapshot == null) return; + + kryptonDataGridView.DataSource = dataTableSource = snapshot.DataTableSource; + kryptonDataGridView.Refresh(); + deleteDataTableSource = snapshot.DeleteDataTableSource; + + Set(kryptonDataGridView, snapshot.DataSource, dataTableSource, deleteDataTableSource); + } + + public static void SetColumnDataSource(this KryptonDataGridView kryptonDataGridView, KryptonDataGridViewComboBoxColumn comboxCol, List ds, string displayMember, string valueMember, bool blankOption) + { + if (ds == null) + { + comboxCol.DataSource = null; + + return; + } + DataTable colDtbll = null; + + colDtbll = DataTableConvertor.ToDataTable(ds, blankOption); + + comboxCol.DataSource = colDtbll; + comboxCol.DisplayMember = displayMember; + comboxCol.ValueMember = valueMember; + } + + public static void SetColumnDataSource(this KryptonDataGridView kryptonDataGridView, KryptonDataGridViewComboBoxColumn comboxCol, T[] ds, string displayMember, string valueMember, bool blankOption) + { + if (ds == null) + { + comboxCol.DataSource = null; + return; + } + + SetColumnDataSource(kryptonDataGridView, comboxCol, ds.ToList(), displayMember, valueMember, blankOption); + } + + public static void SetColumnDataSource(this KryptonDataGridView kryptonDataGridView, KryptonDataGridViewComboBoxColumn comboxCol, TableName[] values, bool blankOption) + { + SetColumnDataSource>(kryptonDataGridView, comboxCol, values, TableName.DISPLAY_NAME, TableName.VALUE, blankOption); + } + + + public static void SetColumnDataSource(this KryptonDataGridView kryptonDataGridView, DataGridViewComboBoxColumn comboxCol, List ds, string displayMember, string valueMember, bool blankOption) + { + if (ds == null) + { + comboxCol.DataSource = null; + + return; + } + DataTable colDtbll = null; + + colDtbll = DataTableConvertor.ToDataTable(ds, blankOption); + + comboxCol.DataSource = colDtbll; + comboxCol.DisplayMember = displayMember; + comboxCol.ValueMember = valueMember; + } + + public static void SetColumnDataSource(this KryptonDataGridView kryptonDataGridView, DataGridViewComboBoxColumn comboxCol, T[] ds, string displayMember, string valueMember, bool blankOption) + { + if (ds == null) + { + comboxCol.DataSource = null; + return; + } + + SetColumnDataSource(kryptonDataGridView, comboxCol, ds.ToList(), displayMember, valueMember, blankOption); + } + + public static void SetColumnDataSource(this KryptonDataGridView kryptonDataGridView, DataGridViewComboBoxColumn comboxCol, TableName[] values, bool blankOption) + { + SetColumnDataSource>(kryptonDataGridView, comboxCol, values, TableName.DISPLAY_NAME, TableName.VALUE, blankOption); + } + + #endregion + + public static BindingContextCustomAttribute GetCustomAttribute(this KryptonDataGridView kryptonDataGridView) + { + return GetProvider().GetCustomAttribute(kryptonDataGridView); + } + + + public static void InitColumn(this KryptonDataGridView kryptonDataGridView, bool isSort, bool showRowNumber) + { + kryptonDataGridView.AutoGenerateColumns = false; + + foreach (DataGridViewColumn column in kryptonDataGridView.Columns) + { + column.SortMode = isSort ? DataGridViewColumnSortMode.Automatic : DataGridViewColumnSortMode.NotSortable; + } + + kryptonDataGridView.LoadUserPreference(); + kryptonDataGridView.EditMode = DataGridViewEditMode.EditOnEnter; + + if (showRowNumber) + kryptonDataGridView.RowPostPaint += (sender, e) => + { + // 绘制行号 + if (e.RowIndex >= 0) + { + Rectangle bounds = new Rectangle( + e.RowBounds.Left, + e.RowBounds.Top, + kryptonDataGridView.RowHeadersWidth, + e.RowBounds.Height); + + TextRenderer.DrawText(e.Graphics, + (e.RowIndex + 1).ToString(), + kryptonDataGridView.RowHeadersDefaultCellStyle.Font, + bounds, + kryptonDataGridView.RowHeadersDefaultCellStyle.ForeColor, + TextFormatFlags.Right | TextFormatFlags.VerticalCenter); + } + + // 绘制总数(只在第一行绘制一次) + if (e.RowIndex == 0) + { + var headerBounds = kryptonDataGridView.GetCellDisplayRectangle(-1, -1, true); + if (headerBounds.Width > 0) + { + TextRenderer.DrawText(e.Graphics, + $"{kryptonDataGridView.RowCount}", + kryptonDataGridView.RowHeadersDefaultCellStyle.Font, + headerBounds, + Color.DarkBlue, + TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter); + } + } + }; + + ContextMenuStrip contextMenuStrip; + ToolStripMenuItem adjustColumnsToolStripMenuItem; + contextMenuStrip = new ContextMenuStrip(); + adjustColumnsToolStripMenuItem = new ToolStripMenuItem(); + + contextMenuStrip.SuspendLayout(); + + contextMenuStrip.Items.AddRange(new ToolStripItem[] { adjustColumnsToolStripMenuItem }); + + contextMenuStrip.Name = "contextMenuStrip"; + + + Set(kryptonDataGridView, null!, null, null); + + // + // adjustColumnsToolStripMenuItem + // + + adjustColumnsToolStripMenuItem.Name = kryptonDataGridView.Name + DateTime.Now.ToString("yyyyHHddhhmmss");// "adjustColumnsToolStripMenuItem"; + adjustColumnsToolStripMenuItem.Text = "调整列属性"; + adjustColumnsToolStripMenuItem.Tag = kryptonDataGridView; + adjustColumnsToolStripMenuItem.Click += new System.EventHandler(adjustColumnsToolStripMenuItem_Click); + + kryptonDataGridView.TopLeftHeaderCell.ContextMenuStrip = contextMenuStrip; + foreach (DataGridViewColumn column in kryptonDataGridView.Columns) + { + column.HeaderCell.ContextMenuStrip = contextMenuStrip; + } + + //kryptonDataGridView.ContextMenuStrip = contextMenuStrip; + + contextMenuStrip.ResumeLayout(false); + } + + public static void adjustColumnsToolStripMenuItem_Click(object sender, EventArgs e) + { + KryptonDataGridViewColumnSetDialog f = new KryptonDataGridViewColumnSetDialog((KryptonDataGridView)((ToolStripMenuItem)sender).Tag); + + f.ShowDialog(); + } + + public static string GetFormName(this KryptonDataGridView kryptonDataGridView, Control control) + { + //弹出的对话框时会为空 + if (control == null) return string.Empty; + if (control.Parent is AbstractPage || control.Parent is KryptonForm) return control.Parent.ToString(); + else return kryptonDataGridView.GetFormName(control.Parent); + } + + //加載用戶配置文件 + public static void LoadUserPreference(this KryptonDataGridView kryptonDataGridView) + { + try + { + SecurityUserPreferenceEntity load = null!; + + + SecurityUserPreferenceRequest request = ServiceHelper.GetTypeService(); + SecurityUserPreferenceEntityKey key = new SecurityUserPreferenceEntityKey(); + key.Username = ApplicationServiceContext.Context.Requestor; + + key.PreferenceKey = kryptonDataGridView.GetFormName(kryptonDataGridView) + "." + kryptonDataGridView.Name; + + load = request.FindByKey(key); + + if (load == null) return; + + ExDataGridViewInfo info = DeserializeHelper.Deserialize(load.Preference); + + Dictionary dic = new Dictionary(); + + int i = 0; + + DataGridViewColumnsInfo cf; + + foreach (DataGridViewColumnsInfo column in info.ColumnsInfo) + { + kryptonDataGridView.Columns[i].Frozen = false; + + dic.Add(column.Name, new string[] { column.DisplayIndex, column.Width, column.Visiable }); + + i++; + } + + kryptonDataGridView.LoadGridView(dic); + + if (!string.IsNullOrEmpty(info.FrozenName)) kryptonDataGridView.Columns[info.FrozenName].Frozen = true; + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + /// + /// 保存列的设置,按顺序为:列名,显示顺序,列宽,是否可见(True,false字符串) + /// 自己需要将返回的内容持久化,通畅持久化需要再封装一次,增加用户及使用位置的标识,这样不同用户就可以有独立的配置 + /// + /// 返回的列名为dictionary[0],显示顺序(dictionary[0])[0],列宽(dictionary[0])[1],是否可见(dictionary[0])[2] + public static Dictionary SaveGridView(this KryptonDataGridView kryptonDataGridView) + { + Dictionary dict = new Dictionary(); + + for (int i = 0; i < kryptonDataGridView.Columns.Count; i++) + { + foreach (DataGridViewColumn col in kryptonDataGridView.Columns) + { + if (col.DisplayIndex == i) + { + string[] value = { col.DisplayIndex.ToString(), col.Width.ToString(), col.Visible.ToString() }; + dict.Add(col.Name, value); + } + } + } + return dict; + } + + /// + /// 列宽的加载,从传入的字典内加载用户传入的列信息 + /// 传入的内容应该按照显示顺序由小到大进行排序了 + /// 将持久化的列信息加载,一般应包含当前用户及控件使用位置信息 + /// + /// Dictionary<列名,{显示顺序,列宽,是否可见(True,false字符串)}> + public static void LoadGridView(this KryptonDataGridView kryptonDataGridView, Dictionary dict) + { + if (dict.Count <= 0) return; + + try + { + foreach (string dic in dict.Keys) + { + if (kryptonDataGridView.Columns.Contains(dic)) + { + DataGridViewColumn column = kryptonDataGridView.Columns[dic]; + column.DisplayIndex = Convert.ToInt32(dict[dic][0]); + column.Visible = Convert.ToBoolean(dict[dic][2]); + if (column.Visible) + { + column.Width = Convert.ToInt32(dict[dic][1]) > 20 ? Convert.ToInt32(dict[dic][1]) : 120; //小于20则自动调整为120. + } + } + } + } + catch (Exception e) + { + + throw e; + } + + } + + private static BindingContextAttributeProvider GetProvider() + { + return ServiceHelper.GetService() ?? + throw new InvalidOperationException("BindingContextAttributeProvider is not registered in the service GetProvider()."); + } + + public static TemplateHeader[] GetTemplateHeaders(this KryptonDataGridView kryptonDataGridView) + { + List headers = new List(); + foreach (DataGridViewColumn column in kryptonDataGridView.Columns) + { + TemplateHeader header = new TemplateHeader(); + header.BindingName = column.DataPropertyName; + header.DisplayName = column.HeaderText; + header.Format = column.DefaultCellStyle.Format; + if (!column.Visible) continue; + header.Width = column.Width / 8; + header.DisplayIndex = column.DisplayIndex; + headers.Add(header); + } + return headers.OrderBy(x => x.DisplayIndex).ToArray(); + } + + } +} diff --git a/CloudBuilder/CloudBuilder.Gui/KryptonDateTimePickerExtensions.cs b/CloudBuilder/CloudBuilder.Gui/KryptonDateTimePickerExtensions.cs new file mode 100644 index 0000000..0753a0a --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/KryptonDateTimePickerExtensions.cs @@ -0,0 +1,203 @@ +using CloudBuilder; +using CloudBuilder.Gui; +using CloudBuilder.Gui.DependencyInjection; +using Krypton.Toolkit; +using Microsoft.AspNetCore.Authorization; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.IdentityModel.Tokens; +using System; +using System.Collections.Generic; +using System.Data.SqlTypes; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace Krypton.Toolkit +{ + public static class KryptonDateTimePickerExtensions + { + public const string DATA_FROMAT = "yyyy-MM-dd"; + + public static ExFormSnapshotEntry GetExFormSnapshotEntry(this KryptonDateTimePicker kryptonDateTimePicker) + { + string bindDataName = null; + + if (GetProvider().GetCustomAttribute(kryptonDateTimePicker) != null) + bindDataName = GetProvider().GetCustomAttribute(kryptonDateTimePicker).BindDataName; + + return new ExFormSnapshotEntry( + kryptonDateTimePicker.Name, + bindDataName, + kryptonDateTimePicker.Text, + kryptonDateTimePicker.Text); + } + + public static void Set(this KryptonDateTimePicker kryptonDateTimePicker, + BindingContextCustomAttribute bindingContext) + { + GetProvider().SetCustomAttribute(kryptonDateTimePicker, bindingContext); + } + + public static void Set(this KryptonDateTimePicker kryptonDateTimePicker, + EnumEditModeColor editModeColor) + { + GetProvider().SetCustomAttribute(kryptonDateTimePicker, editModeColor); + } + public static void Set(this KryptonDateTimePicker kryptonDateTimePicker, EnumEditModeColor editModeColor, string bindDisplayName) + { + GetProvider().SetCustomAttribute(kryptonDateTimePicker, editModeColor, bindDisplayName); + } + + public static void Set(this KryptonDateTimePicker kryptonDateTimePicker, + string bindDataName, + EnumEditModeColor editModeColor) + { + GetProvider().SetCustomAttribute(kryptonDateTimePicker, bindDataName, editModeColor); + } + + public static void Set(this KryptonDateTimePicker kryptonDateTimePicker, + string bindDataName, + string bindFormat, + EnumEditModeColor editModeColor) + { + GetProvider().SetCustomAttribute(kryptonDateTimePicker, bindDataName, bindFormat, editModeColor); + } + + + public static void Set(this KryptonDateTimePicker kryptonDateTimePicker, + string bindDataName) + { + GetProvider().SetCustomAttribute(kryptonDateTimePicker, bindDataName, EnumBindDirection.Both); + } + + public static void Set(this KryptonDateTimePicker kryptonDateTimePicker, + string bindDataName, + EnumBindDirection bindDirection) + { + GetProvider().SetCustomAttribute(kryptonDateTimePicker, bindDataName, bindDirection); + } + + + public static void Set(this KryptonDateTimePicker kryptonDateTimePicker, + string bindDataName, + EnumBindDirection bindDirection, + EnumEditModeColor editModeColor) + { + GetProvider().SetCustomAttribute(kryptonDateTimePicker, bindDataName, bindDirection, editModeColor); + } + + public static void Set(this KryptonDateTimePicker kryptonDateTimePicker, + string bindDataName, + string bindFormat, + EnumBindDirection bindDirection) + { + GetProvider().SetCustomAttribute(kryptonDateTimePicker, bindDataName, bindFormat, bindDirection); + } + + public static void Set(this KryptonDateTimePicker kryptonDateTimePicker, + string permissionName, + Operate permissionMode) + { + GetProvider().SetCustomAttribute(kryptonDateTimePicker, permissionName, permissionMode); + } + + public static void Set(this KryptonDateTimePicker kryptonDateTimePicker, string permissionName, string dependentDetailName, Operate permissionMode) + { + GetProvider().SetCustomAttribute(kryptonDateTimePicker, permissionName, dependentDetailName, permissionMode); + } + + public static void Set(this KryptonDateTimePicker kryptonDateTimePicker, string permissionName, string dependentDetailName) + { + GetProvider().SetCustomAttribute(kryptonDateTimePicker, permissionName, dependentDetailName); + } + + public static string GetValue(this KryptonDateTimePicker kryptonDateTimePicker) + { + if (!kryptonDateTimePicker.Checked) return null!; + return kryptonDateTimePicker.Text; + } + + public static Nullable GetDateTimeValue(this KryptonDateTimePicker kryptonDateTimePicker) + { + string bindFormat = DATA_FROMAT; + + if (!string.IsNullOrEmpty(kryptonDateTimePicker.CustomFormat)) + bindFormat = kryptonDateTimePicker.CustomFormat; + + if (GetProvider().GetCustomAttribute(kryptonDateTimePicker) != null && + !string.IsNullOrEmpty(GetProvider().GetCustomAttribute(kryptonDateTimePicker).BindFormat)) + { + bindFormat = GetProvider().GetCustomAttribute(kryptonDateTimePicker).BindFormat; + } + + if (kryptonDateTimePicker.Checked) + return DateTime.ParseExact(kryptonDateTimePicker.Text.Trim(), bindFormat, CultureInfo.InvariantCulture, DateTimeStyles.None); + return null; + } + + public static void SetValue(this KryptonDateTimePicker kryptonDateTimePicker, string value) + { + if (string.IsNullOrEmpty(value)) + { + kryptonDateTimePicker.Checked = false; + return; + } + kryptonDateTimePicker.Checked = true; + kryptonDateTimePicker.Text = value; + } + + public static void SetValue(this KryptonDateTimePicker kryptonDateTimePicker, object value, string bindFormat) + { + if (value == null) + { + kryptonDateTimePicker.Checked = false; + } + else if (value is string) + { + if (string.IsNullOrEmpty((string)value)) + { + kryptonDateTimePicker.Checked = false; + return; + } + kryptonDateTimePicker.Checked = true; + kryptonDateTimePicker.Value = DateTime.ParseExact(value.ToString(), bindFormat, CultureInfo.InvariantCulture, DateTimeStyles.None); + } + else if (value is DateTime) + { + kryptonDateTimePicker.Checked = true; + if (value == null || ((DateTime)value).Year == 1) + kryptonDateTimePicker.Checked = false; + else if (!string.IsNullOrEmpty(bindFormat)) + { + kryptonDateTimePicker.Checked = false; + } + else + kryptonDateTimePicker.Value = (DateTime)value; + } + else if (value is SqlDateTime) + { + kryptonDateTimePicker.Checked = true; + if (((SqlDateTime)value).IsNull || ((SqlDateTime)value).Value.Year == 1) + kryptonDateTimePicker.Checked = false; + else if (!string.IsNullOrEmpty(bindFormat)) + kryptonDateTimePicker.Value = (DateTime)value; + else + kryptonDateTimePicker.Value = (DateTime)value; + } + } + + public static BindingContextCustomAttribute GetCustomAttribute(this KryptonDateTimePicker kryptonDateTimePicker) + { + return GetProvider().GetCustomAttribute(kryptonDateTimePicker); + } + + private static BindingContextAttributeProvider GetProvider() + { + return ServiceHelper.GetService() ?? + throw new InvalidOperationException("BindingContextAttributeProvider is not registered in the service GetProvider()."); + } + } +} + diff --git a/CloudBuilder/CloudBuilder.Gui/KryptonListBoxExtensions.cs b/CloudBuilder/CloudBuilder.Gui/KryptonListBoxExtensions.cs new file mode 100644 index 0000000..8bd0173 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/KryptonListBoxExtensions.cs @@ -0,0 +1,164 @@ +using CloudBuilder; +using CloudBuilder.Gui; +using CloudBuilder.Gui.DependencyInjection; +using Microsoft.AspNetCore.Authorization; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Krypton.Toolkit +{ + public static class KryptonListBoxExtensions + { + + public static ExFormSnapshotEntry GetExFormSnapshotEntry(this KryptonListBox kryptonListBox) + { + string bindDataName = null; + + if (GetProvider().GetCustomAttribute(kryptonListBox) != null) + bindDataName = GetProvider().GetCustomAttribute(kryptonListBox).BindDataName; + + return new ExFormSnapshotEntry( + kryptonListBox.Name, + bindDataName, + kryptonListBox.GetAllItemValue(), + kryptonListBox.Text); + } + + public static void Set(this KryptonListBox kryptonListBox, + BindingContextCustomAttribute bindingContext) + { + GetProvider().SetCustomAttribute(kryptonListBox, bindingContext); + } + + public static void Set(this KryptonListBox kryptonListBox, + EnumEditModeColor editModeColor) + { + GetProvider().SetCustomAttribute(kryptonListBox, editModeColor); + } + + public static void Set(this KryptonListBox kryptonListBox, + string bindDataName, + EnumEditModeColor editModeColor) + { + GetProvider().SetCustomAttribute(kryptonListBox, bindDataName, editModeColor); + } + + public static void Set(this KryptonListBox kryptonListBox, + string bindDataName) + { + GetProvider().SetCustomAttribute(kryptonListBox, bindDataName, EnumBindDirection.Both); + } + + public static void Set(this KryptonListBox kryptonListBox, + string bindDataName, + EnumBindDirection bindDirection) + { + GetProvider().SetCustomAttribute(kryptonListBox, bindDataName, bindDirection); + } + + + public static void Set(this KryptonListBox kryptonListBox, + string bindDataName, + EnumBindDirection bindDirection, + EnumEditModeColor editModeColor) + { + GetProvider().SetCustomAttribute(kryptonListBox, bindDataName, bindDirection, editModeColor); + } + + public static void Set(this KryptonListBox kryptonListBox, + string bindDataName, + string bindFormat, + EnumBindDirection bindDirection) + { + GetProvider().SetCustomAttribute(kryptonListBox, bindDataName, bindFormat, bindDirection); + } + + public static void Set(this KryptonListBox kryptonListBox, + string permissionName, + Operate permissionMode) + { + GetProvider().SetCustomAttribute(kryptonListBox, permissionName, permissionMode); + } + + public static void Set(this KryptonListBox kryptonListBox, string permissionName, string dependentDetailName, Operate permissionMode) + { + GetProvider().SetCustomAttribute(kryptonListBox, permissionName, dependentDetailName, permissionMode); + } + + public static void Set(this KryptonListBox kryptonListBox, string permissionName, string dependentDetailName) + { + GetProvider().SetCustomAttribute(kryptonListBox, permissionName, dependentDetailName); + } + + public static string[] GetAllItemText(this KryptonListBox kryptonListBox) + { + List l = new List(); + for (int i = 0; i < kryptonListBox.Items.Count; i++) + { + l.Add(((KryptonListItem)kryptonListBox.Items[i]).ShortText); + } + return l.ToArray(); + } + + + public static T[] GetAllItemValue(this KryptonListBox kryptonListBox) + { + List l = new List(); + for (int i = 0; i < kryptonListBox.Items.Count; i++) + { + l.Add((T)((Dictionary)((KryptonListItem)kryptonListBox.Items[i]).Tag)[i]); + } + return l.ToArray(); + } + + public static void SetValue(this KryptonListBox kryptonListBox, string[] ts) + { + kryptonListBox.Items.Clear(); + + if (ts == null || ts.Length == 0) return; + + List l = new List(); + KryptonListItem kryptonListItem; + + int i = 0; + Dictionary keyValues = new Dictionary(); + foreach (string item in ts) + { + kryptonListItem = new KryptonListItem(); + + kryptonListItem.ShortText = item; + l.Add(kryptonListItem); + + keyValues.Add(i, item); + kryptonListItem.Tag = keyValues; + i++; + } + + kryptonListBox.Items.AddRange(l.ToArray()); + } + + + public static void SetDataSource(this KryptonListBox kryptonListBox, T[] dataSource, string displayName, string valueName) + { + if (dataSource == null || dataSource.Length == 0) return; + KryptonListItem[] items = KryptonListItemConvertor.ToKryptonListItem(dataSource, displayName, valueName); + kryptonListBox.Items.AddRange(items); + } + + public static BindingContextCustomAttribute GetCustomAttribute(this KryptonListBox kryptonListBox) + { + return GetProvider().GetCustomAttribute(kryptonListBox); + } + private static BindingContextAttributeProvider GetProvider() + { + return ServiceHelper.GetService() ?? + throw new InvalidOperationException("BindingContextAttributeProvider is not registered in the service GetProvider()."); + } + } +} + + diff --git a/CloudBuilder/CloudBuilder.Gui/KryptonListItemConvertor.cs b/CloudBuilder/CloudBuilder.Gui/KryptonListItemConvertor.cs new file mode 100644 index 0000000..f89530a --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/KryptonListItemConvertor.cs @@ -0,0 +1,50 @@ +using Krypton.Toolkit; +using System.Reflection; + +namespace System +{ + public static class KryptonListItemConvertor + { + public static KryptonListItem[] ToKryptonListItem(IList list, string display, string value) + { + if (list == null || list.Count == 0) return null; + + List l = new List(); + KryptonListItem kryptonListItem; + Type elementType = typeof(T); + + int i = 0; + Dictionary keyValues = new Dictionary(); + foreach (T item in list) + { + kryptonListItem = new KryptonListItem(); + + foreach (PropertyInfo property in elementType.GetProperties()) + { + if (property.Name == display) + { + kryptonListItem.ShortText = property.GetValue(item, null).ToString(); + l.Add(kryptonListItem); + } + if (property.Name == value) + { + keyValues.Add(i, property.GetValue(item, null)); + } + } + + kryptonListItem.Tag = keyValues; + + i++; + } + + return l.ToArray(); + } + + public static KryptonListItem[] ToKryptonListItem(T[] list, string display, string value) + { + if (list == null || list.Length == 0) return null; + + return ToKryptonListItem(list.ToList(), display, value); + } + } +} diff --git a/CloudBuilder/CloudBuilder.Gui/KryptonMaskedTextBoxExtensions.cs b/CloudBuilder/CloudBuilder.Gui/KryptonMaskedTextBoxExtensions.cs new file mode 100644 index 0000000..5372940 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/KryptonMaskedTextBoxExtensions.cs @@ -0,0 +1,181 @@ +using CloudBuilder; +using CloudBuilder.Gui; +using CloudBuilder.Gui.DependencyInjection; +using Krypton.Toolkit; +using Microsoft.AspNetCore.Authorization; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Data.SqlTypes; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Krypton.Toolkit +{ + public static class KryptonMaskedTextBoxExtensions + { + public const string DATA_FROMAT = "yyyy-MM-dd"; + + public static ExFormSnapshotEntry GetExFormSnapshotEntry(this KryptonMaskedTextBox kryptonMaskedTextBox) + { + string bindDataName = null; + + if (GetProvider().GetCustomAttribute(kryptonMaskedTextBox) != null) + bindDataName = GetProvider().GetCustomAttribute(kryptonMaskedTextBox).BindDataName; + + return new ExFormSnapshotEntry( + kryptonMaskedTextBox.Name, + bindDataName, + kryptonMaskedTextBox.Text, + kryptonMaskedTextBox.Text); + } + + public static void Set(this KryptonMaskedTextBox kryptonMaskedTextBox, + BindingContextCustomAttribute bindingContext) + { + GetProvider().SetCustomAttribute(kryptonMaskedTextBox, bindingContext); + } + + public static void Set(this KryptonMaskedTextBox kryptonMaskedTextBox, + EnumEditModeColor editModeColor) + { + GetProvider().SetCustomAttribute(kryptonMaskedTextBox, editModeColor); + } + + public static void Set(this KryptonMaskedTextBox kryptonMaskedTextBox, EnumEditModeColor editModeColor, string bindDisplayName) + { + GetProvider().SetCustomAttribute(kryptonMaskedTextBox, editModeColor, bindDisplayName); + } + + public static void Set(this KryptonMaskedTextBox kryptonMaskedTextBox, + string bindDataName, + EnumEditModeColor editModeColor) + { + GetProvider().SetCustomAttribute(kryptonMaskedTextBox, bindDataName, editModeColor); + } + + public static void Set(this KryptonMaskedTextBox kryptonMaskedTextBox, + string bindDataName) + { + GetProvider().SetCustomAttribute(kryptonMaskedTextBox, bindDataName, EnumBindDirection.Both); + } + + public static void Set(this KryptonMaskedTextBox kryptonMaskedTextBox, + string bindDataName, + EnumBindDirection bindDirection) + { + GetProvider().SetCustomAttribute(kryptonMaskedTextBox, bindDataName, bindDirection); + } + + + public static void Set(this KryptonMaskedTextBox kryptonMaskedTextBox, + string bindDataName, + EnumBindDirection bindDirection, + EnumEditModeColor editModeColor) + { + GetProvider().SetCustomAttribute(kryptonMaskedTextBox, bindDataName, bindDirection, editModeColor); + } + + public static void Set(this KryptonMaskedTextBox kryptonMaskedTextBox, + string bindDataName, + string bindFormat, + EnumEditModeColor editModeColor) + { + GetProvider().SetCustomAttribute(kryptonMaskedTextBox, bindDataName, bindFormat, editModeColor); + } + + public static void Set(this KryptonMaskedTextBox kryptonMaskedTextBox, + string bindDataName, + string bindFormat, + EnumBindDirection bindDirection) + { + GetProvider().SetCustomAttribute(kryptonMaskedTextBox, bindDataName, bindFormat, bindDirection); + } + + public static void Set(this KryptonMaskedTextBox kryptonMaskedTextBox, + string permissionName, + Operate permissionMode) + { + GetProvider().SetCustomAttribute(kryptonMaskedTextBox, permissionName, permissionMode); + } + + public static void Set(this KryptonMaskedTextBox kryptonMaskedTextBox, string permissionName, string dependentDetailName, Operate permissionMode) + { + GetProvider().SetCustomAttribute(kryptonMaskedTextBox, permissionName, dependentDetailName, permissionMode); + } + + public static void Set(this KryptonMaskedTextBox kryptonMaskedTextBox, string permissionName, string dependentDetailName) + { + GetProvider().SetCustomAttribute(kryptonMaskedTextBox, permissionName, dependentDetailName); + } + + public static string GetValue(this KryptonMaskedTextBox kryptonMaskedTextBox) + { + if (IsEmpty(kryptonMaskedTextBox)) return string.Empty; + return kryptonMaskedTextBox.Text.Trim(); + } + + public static void SetValue(this KryptonMaskedTextBox kryptonMaskedTextBox, string value) + { + kryptonMaskedTextBox.Text = value; + } + + public static void SetValue(this KryptonMaskedTextBox kryptonMaskedTextBox, object value, string bindFormat) + { + if (value == null) + { + kryptonMaskedTextBox.Text = null; + } + else if (value is string) + { + kryptonMaskedTextBox.Text = value.ToString(); + } + else if (value is DateTime) + { + if (value == null) + kryptonMaskedTextBox.Text = string.Empty; + else if (!string.IsNullOrEmpty(bindFormat)) + kryptonMaskedTextBox.Text = ((DateTime)value).ToString(bindFormat); + else + kryptonMaskedTextBox.Text = ((DateTime)value).ToString(DATA_FROMAT); + } + else if (value is SqlDateTime) + { + if (((SqlDateTime)value).IsNull) + kryptonMaskedTextBox.Text = string.Empty; + else if (!string.IsNullOrEmpty(bindFormat)) + kryptonMaskedTextBox.Text = ((DateTime)value).ToString(bindFormat); + else + kryptonMaskedTextBox.Text = ((DateTime)value).ToString(DATA_FROMAT); + } + else if (value is decimal || value is int || value is Int32 || value is Int64 || value is Int16 || value is double || value is float) + { + if (!string.IsNullOrEmpty(bindFormat)) + kryptonMaskedTextBox.Text = (Convert.ToDecimal(value)).ToString(bindFormat); + else + kryptonMaskedTextBox.Text = (Convert.ToDecimal(value)).ToString(); + } + } + + public static bool IsEmpty(this KryptonMaskedTextBox kryptonMaskedTextBox) + { + string mark = System.Text.RegularExpressions.Regex.Replace(kryptonMaskedTextBox.Mask, @"\d", string.Empty); + if (mark.Length > 0) + mark = mark.Substring(0, 1); + if (string.IsNullOrEmpty(kryptonMaskedTextBox.Text.Replace(kryptonMaskedTextBox.PromptChar.ToString(), string.Empty).Replace(mark, string.Empty))) return true; + return false; + } + + public static BindingContextCustomAttribute GetCustomAttribute(this KryptonMaskedTextBox kryptonMaskedTextBox) + { + return GetProvider().GetCustomAttribute(kryptonMaskedTextBox); + } + + private static BindingContextAttributeProvider GetProvider() + { + return ServiceHelper.GetService() ?? + throw new InvalidOperationException("BindingContextAttributeProvider is not registered in the service GetProvider()."); + } + } +} diff --git a/CloudBuilder/CloudBuilder.Gui/KryptonMessageBoxForm.Designer.cs b/CloudBuilder/CloudBuilder.Gui/KryptonMessageBoxForm.Designer.cs new file mode 100644 index 0000000..48e47c9 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/KryptonMessageBoxForm.Designer.cs @@ -0,0 +1,295 @@ +#region BSD License +/* + * + * Original BSD 3-Clause License (https://github.com/ComponentFactory/Krypton/blob/master/LICENSE) + * © Component Factory Pty Ltd, 2006 - 2016, (Version 4.5.0.0) All rights reserved. + * + * New BSD 3-Clause License (https://github.com/Krypton-Suite/Standard-Toolkit/blob/master/LICENSE) + * Modifications by Peter Wagner(aka Wagnerp) & Simon Coghlan(aka Smurf-IV), et al. 2017 - 2023. All rights reserved. + * + */ +#endregion + + +namespace Krypton.Toolkit +{ + partial class KryptonMessageBoxForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + _messageIcon = new PictureBox(); + _panelButtons = new KryptonPanel(); + _borderEdge = new KryptonBorderEdge(); + _button4 = new MessageButton(); + _button3 = new MessageButton(); + _button1 = new MessageButton(); + _button2 = new MessageButton(); + _button5 = new MessageButton(); + kryptonPanel1 = new KryptonPanel(); + tableLayoutPanel1 = new TableLayoutPanel(); + _panelContentArea = new KryptonPanel(); + krtbMessageText = new KryptonRichTextBox(); + _linkLabelMessageText = new KryptonLinkWrapLabel(); + ((System.ComponentModel.ISupportInitialize)_messageIcon).BeginInit(); + ((System.ComponentModel.ISupportInitialize)_panelButtons).BeginInit(); + _panelButtons.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)kryptonPanel1).BeginInit(); + kryptonPanel1.SuspendLayout(); + tableLayoutPanel1.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)_panelContentArea).BeginInit(); + _panelContentArea.SuspendLayout(); + SuspendLayout(); + // + // _messageIcon + // + _messageIcon.BackColor = Color.Transparent; + _messageIcon.Dock = DockStyle.Fill; + _messageIcon.Location = new Point(10, 5); + _messageIcon.Margin = new Padding(10, 5, 4, 5); + _messageIcon.Name = "_messageIcon"; + _messageIcon.Size = new Size(38, 55); + _messageIcon.SizeMode = PictureBoxSizeMode.CenterImage; + _messageIcon.TabIndex = 0; + _messageIcon.TabStop = false; + // + // _panelButtons + // + tableLayoutPanel1.SetColumnSpan(_panelButtons, 2); + _panelButtons.Controls.Add(_borderEdge); + _panelButtons.Controls.Add(_button4); + _panelButtons.Controls.Add(_button3); + _panelButtons.Controls.Add(_button1); + _panelButtons.Controls.Add(_button2); + _panelButtons.Controls.Add(_button5); + _panelButtons.Dock = DockStyle.Fill; + _panelButtons.Location = new Point(0, 65); + _panelButtons.Margin = new Padding(0); + _panelButtons.Name = "_panelButtons"; + _panelButtons.PanelBackStyle = PaletteBackStyle.PanelAlternate; + _panelButtons.Size = new Size(214, 28); + _panelButtons.TabIndex = 0; + // + // _borderEdge + // + _borderEdge.BorderStyle = PaletteBorderStyle.HeaderPrimary; + _borderEdge.Dock = DockStyle.Top; + _borderEdge.Location = new Point(0, 0); + _borderEdge.Margin = new Padding(3, 2, 3, 2); + _borderEdge.Name = "_borderEdge"; + _borderEdge.Size = new Size(214, 1); + _borderEdge.Text = "kryptonBorderEdge1"; + // + // _button4 + // + _button4.Anchor = AnchorStyles.Top | AnchorStyles.Right; + _button4.AutoSize = true; + _button4.Enabled = false; + _button4.IgnoreAltF4 = false; + _button4.Location = new Point(214, 0); + _button4.Margin = new Padding(0); + _button4.MinimumSize = new Size(45, 28); + _button4.Name = "_button4"; + _button4.Size = new Size(45, 34); + _button4.TabIndex = 2; + _button4.Values.Text = "B4"; + _button4.Visible = false; + // + // _button3 + // + _button3.Anchor = AnchorStyles.Top | AnchorStyles.Right; + _button3.AutoSize = true; + _button3.Enabled = false; + _button3.IgnoreAltF4 = false; + _button3.Location = new Point(171, 0); + _button3.Margin = new Padding(0); + _button3.MinimumSize = new Size(45, 28); + _button3.Name = "_button3"; + _button3.Size = new Size(45, 34); + _button3.TabIndex = 2; + _button3.Values.Text = "B3"; + _button3.Visible = false; + // + // _button1 + // + _button1.Anchor = AnchorStyles.Top | AnchorStyles.Right; + _button1.AutoSize = true; + _button1.Enabled = false; + _button1.IgnoreAltF4 = false; + _button1.Location = new Point(81, 0); + _button1.Margin = new Padding(0); + _button1.MinimumSize = new Size(45, 28); + _button1.Name = "_button1"; + _button1.Size = new Size(45, 34); + _button1.TabIndex = 0; + _button1.Values.Text = "B1"; + _button1.Visible = false; + // + // _button2 + // + _button2.Anchor = AnchorStyles.Top | AnchorStyles.Right; + _button2.AutoSize = true; + _button2.Enabled = false; + _button2.IgnoreAltF4 = false; + _button2.Location = new Point(126, 0); + _button2.Margin = new Padding(0); + _button2.MinimumSize = new Size(45, 28); + _button2.Name = "_button2"; + _button2.Size = new Size(45, 34); + _button2.TabIndex = 1; + _button2.Values.Text = "B2"; + _button2.Visible = false; + // + // _button5 + // + _button5.AutoSize = true; + _button5.Enabled = false; + _button5.IgnoreAltF4 = false; + _button5.Location = new Point(0, 0); + _button5.Margin = new Padding(0); + _button5.MinimumSize = new Size(45, 28); + _button5.Name = "_button5"; + _button5.Size = new Size(45, 34); + _button5.TabIndex = 3; + _button5.Values.Text = "B5"; + _button5.Visible = false; + // + // kryptonPanel1 + // + kryptonPanel1.Controls.Add(tableLayoutPanel1); + kryptonPanel1.Dock = DockStyle.Fill; + kryptonPanel1.Location = new Point(0, 0); + kryptonPanel1.Margin = new Padding(3, 2, 3, 2); + kryptonPanel1.Name = "kryptonPanel1"; + kryptonPanel1.Size = new Size(214, 93); + kryptonPanel1.TabIndex = 1; + // + // tableLayoutPanel1 + // + tableLayoutPanel1.BackColor = Color.Transparent; + tableLayoutPanel1.ColumnCount = 2; + tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F)); + tableLayoutPanel1.Controls.Add(_panelButtons, 0, 1); + tableLayoutPanel1.Controls.Add(_messageIcon, 0, 0); + tableLayoutPanel1.Controls.Add(_panelContentArea, 1, 0); + tableLayoutPanel1.Dock = DockStyle.Fill; + tableLayoutPanel1.Location = new Point(0, 0); + tableLayoutPanel1.Margin = new Padding(3, 2, 3, 2); + tableLayoutPanel1.Name = "tableLayoutPanel1"; + tableLayoutPanel1.RowCount = 2; + tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent, 100F)); + tableLayoutPanel1.RowStyles.Add(new RowStyle()); + tableLayoutPanel1.Size = new Size(214, 93); + tableLayoutPanel1.TabIndex = 0; + // + // _panelContentArea + // + _panelContentArea.Controls.Add(krtbMessageText); + _panelContentArea.Controls.Add(_linkLabelMessageText); + _panelContentArea.Dock = DockStyle.Fill; + _panelContentArea.Location = new Point(56, 10); + _panelContentArea.Margin = new Padding(4, 10, 4, 10); + _panelContentArea.Name = "_panelContentArea"; + _panelContentArea.Size = new Size(154, 45); + _panelContentArea.TabIndex = 1; + // + // krtbMessageText + // + krtbMessageText.DetectUrls = false; + krtbMessageText.Dock = DockStyle.Fill; + krtbMessageText.InputControlStyle = InputControlStyle.PanelClient; + krtbMessageText.Location = new Point(0, 0); + krtbMessageText.Margin = new Padding(0); + krtbMessageText.Name = "krtbMessageText"; + krtbMessageText.ReadOnly = true; + krtbMessageText.ScrollBars = RichTextBoxScrollBars.None; + krtbMessageText.Size = new Size(154, 45); + krtbMessageText.StateCommon.Border.DrawBorders = PaletteDrawBorders.None; + krtbMessageText.TabIndex = 0; + krtbMessageText.TabStop = false; + krtbMessageText.Text = "Message Text\n.\ttabbed"; + krtbMessageText.WordWrap = false; + // + // _linkLabelMessageText + // + _linkLabelMessageText.AutoSize = false; + _linkLabelMessageText.Dock = DockStyle.Fill; + _linkLabelMessageText.LabelStyle = LabelStyle.NormalControl; + _linkLabelMessageText.Location = new Point(0, 0); + _linkLabelMessageText.Margin = new Padding(4, 0, 4, 0); + _linkLabelMessageText.Name = "_linkLabelMessageText"; + _linkLabelMessageText.Size = new Size(154, 45); + _linkLabelMessageText.Text = "Message Text"; + _linkLabelMessageText.TextAlign = ContentAlignment.MiddleLeft; + _linkLabelMessageText.LinkClicked += LinkClicked; + // + // KryptonMessageBoxForm + // + AutoScaleDimensions = new SizeF(7F, 17F); + AutoScaleMode = AutoScaleMode.Font; + ClientSize = new Size(214, 93); + Controls.Add(kryptonPanel1); + FormBorderStyle = FormBorderStyle.FixedDialog; + KeyPreview = true; + Margin = new Padding(3, 2, 3, 2); + MaximizeBox = false; + MinimizeBox = false; + Name = "KryptonMessageBoxForm"; + ShowIcon = false; + ShowInTaskbar = false; + SizeGripStyle = SizeGripStyle.Hide; + StartPosition = FormStartPosition.CenterParent; + FormClosed += OnFormClosed; + KeyDown += AnyKeyDown; + ((System.ComponentModel.ISupportInitialize)_messageIcon).EndInit(); + ((System.ComponentModel.ISupportInitialize)_panelButtons).EndInit(); + _panelButtons.ResumeLayout(false); + _panelButtons.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)kryptonPanel1).EndInit(); + kryptonPanel1.ResumeLayout(false); + tableLayoutPanel1.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)_panelContentArea).EndInit(); + _panelContentArea.ResumeLayout(false); + ResumeLayout(false); + } + + #endregion + private PictureBox _messageIcon; + private KryptonPanel _panelButtons; + private MessageButton _button1; + private MessageButton _button2; + private MessageButton _button3; + private MessageButton _button4; + private KryptonBorderEdge _borderEdge; + private KryptonPanel kryptonPanel1; + private TableLayoutPanel tableLayoutPanel1; + private MessageButton _button5; + private KryptonPanel _panelContentArea; + private KryptonLinkWrapLabel _linkLabelMessageText; + private KryptonRichTextBox krtbMessageText; + } +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Gui/KryptonMessageBoxForm.cs b/CloudBuilder/CloudBuilder.Gui/KryptonMessageBoxForm.cs new file mode 100644 index 0000000..c611259 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/KryptonMessageBoxForm.cs @@ -0,0 +1,1107 @@ +#region BSD License +/* + * + * Original BSD 3-Clause License (https://github.com/ComponentFactory/Krypton/blob/master/LICENSE) + * © Component Factory Pty Ltd, 2006 - 2016, (Version 4.5.0.0) All rights reserved. + * + * New BSD 3-Clause License (https://github.com/Krypton-Suite/Standard-Toolkit/blob/master/LICENSE) + * Modifications by Peter Wagner(aka Wagnerp) & Simon Coghlan(aka Smurf-IV), et al. 2017 - 2023. All rights reserved. + * + */ +#endregion + +// ReSharper disable InconsistentNaming +// ReSharper disable UnusedParameter.Local +using CloudBuilder.Gui.DependencyInjection; +using CloudBuilder.Gui.Policy; +using CloudBuilder.Gui.Properties; +using System.ComponentModel; +using System.Diagnostics; +using System.Media; +using System.Reflection; +using System.Text; +using ContentAlignment = System.Drawing.ContentAlignment; + +namespace Krypton.Toolkit +{ + + public partial class KryptonMessageBoxForm : KryptonForm + { + #region Static Fields + private const int GAP = 10; + private static readonly int OS_MAJOR_VERSION; + #endregion + + #region Instance Fields + + private readonly bool _showHelpButton; + private readonly string _text; + private readonly string _caption; + private readonly string _applicationPath; + private readonly KryptonMessageBoxButtons _buttons; + private readonly KryptonMessageBoxIcon _kryptonMessageBoxIcon; + private readonly Image? _applicationImage; + + private readonly KryptonMessageBoxDefaultButton _defaultButton; + private readonly MessageBoxOptions _options; // https://github.com/Krypton-Suite/Standard-Toolkit/issues/313 + + // If help information provided or we are not a service/default desktop application then grab an owner for showing the message box + private readonly IWin32Window? _showOwner; + private readonly HelpInfo? _helpInfo; + private readonly KryptonMessageBoxNativeWindow _krtbNativeWindow; + + // Action button features (aka _button5) + private readonly bool _showActionButton; + private readonly string _actionButtonText; + private readonly KryptonCommand? _actionButtonCommand; + + // For the LinkLabel option + private readonly MessageBoxContentAreaType? _contentAreaType; + private readonly KryptonCommand? _linkLabelCommand; + private readonly ProcessStartInfo? _linkLaunchArgument; + private readonly ContentAlignment? _messageTextAlignment; + private readonly LinkArea _contentLinkArea; + + #endregion + + #region Identity + static KryptonMessageBoxForm() => OS_MAJOR_VERSION = Environment.OSVersion.Version.Major; + + public KryptonMessageBoxForm() + { + InitializeComponent(); + } + + internal KryptonMessageBoxForm(IWin32Window? showOwner, string text, string caption, + KryptonMessageBoxButtons buttons, + KryptonMessageBoxIcon icon, + KryptonMessageBoxDefaultButton defaultButton, + MessageBoxOptions options, + HelpInfo? helpInfo, bool? showCtrlCopy, + bool? showHelpButton, + bool? showActionButton, string? actionButtonText, + KryptonCommand? actionButtonCommand, + Image? applicationImage, + string? applicationPath, + MessageBoxContentAreaType? contentAreaType, + KryptonCommand? linkLabelCommand, + ProcessStartInfo? linkLaunchArgument, + LinkArea? contentLinkArea) + { + // Store incoming values + _text = CommonHelper.NormalizeLineBreaks(text ?? string.Empty); + _caption = caption; + _buttons = buttons; + _kryptonMessageBoxIcon = icon; + _defaultButton = defaultButton; + _options = options; + _helpInfo = helpInfo; + _showOwner = showOwner; + _showHelpButton = showHelpButton ?? (helpInfo != null); + _showActionButton = showActionButton ?? false; + _actionButtonText = actionButtonText ?? string.Empty; + _actionButtonCommand = actionButtonCommand; + _applicationImage = applicationImage; + _applicationPath = applicationPath ?? string.Empty; + _contentAreaType = contentAreaType ?? MessageBoxContentAreaType.Normal; + _linkLabelCommand = linkLabelCommand ?? new KryptonCommand(); + _contentLinkArea = contentLinkArea ?? new LinkArea(0, text.Length); + _linkLaunchArgument = linkLaunchArgument ?? new ProcessStartInfo(); + _krtbNativeWindow = new(); + + + + // Create the form contents + InitializeComponent(); + + // Hookup the native window on the KRTB, only after IntializeComponent(). + _krtbNativeWindow.AssignHandle(krtbMessageText.RichTextBox.Handle); + + // Default Cursor for the KRTB when the cursors hovers over it + krtbMessageText.RichTextBox.Cursor = Cursors.Arrow; + + RightToLeftLayout = _options.HasFlag(MessageBoxOptions.RtlReading); + + // Update contents to match requirements + UpdateText(); + UpdateIcon(); + UpdateButtons(); + UpdateDefault(); + UpdateHelp(); + UpdateTextExtra(showCtrlCopy); + UpdateContentAreaType(contentAreaType); + UpdateContentLinkArea(contentLinkArea); + + if (!_text.Contains("\r\n")) + _panelContentArea.Padding = new Padding(0, 10, 0, 0); + else + _panelContentArea.Padding = new Padding(0, 0, 0, 0); + + SetupActionButtonUI(_showActionButton); + + // Finally calculate and set form sizing + UpdateSizing(showOwner); + } + + #endregion Identity + + #region Implementation + + private void UpdateText() + { + Text = string.IsNullOrEmpty(_caption) ? string.Empty : _caption.Split(Environment.NewLine.ToCharArray())[0]; + + if (_contentAreaType == MessageBoxContentAreaType.Normal) + { + krtbMessageText.Text = _text; + + krtbMessageText.RightToLeft = _options.HasFlag(MessageBoxOptions.RightAlign) + ? RightToLeft.Yes + : _options.HasFlag(MessageBoxOptions.RtlReading) + ? RightToLeft.Inherit + : RightToLeft.No; + } + else + { + _linkLabelMessageText.Text = _text; + + _linkLabelMessageText.RightToLeft = _options.HasFlag(MessageBoxOptions.RightAlign) ? RightToLeft.Yes : + _options.HasFlag(MessageBoxOptions.RtlReading) ? RightToLeft.Inherit : RightToLeft.No; + } + } + + private void UpdateTextExtra(bool? showCtrlCopy) + { + if (!showCtrlCopy.HasValue) + { + switch (_kryptonMessageBoxIcon) + { + case KryptonMessageBoxIcon.Error: + case KryptonMessageBoxIcon.Exclamation: + showCtrlCopy = true; + break; + } + } + + if (showCtrlCopy == true) + { + TextExtra = @"Ctrl+c to copy"; + } + } + + private void UpdateIcon() + { + if (OSUtilities.IsWindowsEleven) + { + switch (_kryptonMessageBoxIcon) + { + case KryptonMessageBoxIcon.None: + // Windows XP and before will Beep, Vista and above do not! + if (OS_MAJOR_VERSION < 6) + { + SystemSounds.Beep.Play(); + } + break; + case KryptonMessageBoxIcon.Hand: + _messageIcon.Image = Resources.GenericHand; + SystemSounds.Hand.Play(); + break; + case KryptonMessageBoxIcon.Question: + _messageIcon.Image = Resources.Question_Windows_11; + SystemSounds.Question.Play(); + break; + case KryptonMessageBoxIcon.Exclamation: + _messageIcon.Image = Resources.Warning_Windows_11; + SystemSounds.Exclamation.Play(); + break; + case KryptonMessageBoxIcon.Asterisk: + _messageIcon.Image = Resources.Asterisk_Windows_11; + SystemSounds.Asterisk.Play(); + break; + case KryptonMessageBoxIcon.Stop: + _messageIcon.Image = Resources.GenericStop; + SystemSounds.Asterisk.Play(); + break; + case KryptonMessageBoxIcon.Error: + _messageIcon.Image = Resources.Critical_Windows_11; + SystemSounds.Asterisk.Play(); + break; + case KryptonMessageBoxIcon.Warning: + _messageIcon.Image = Resources.Warning_Windows_11; + SystemSounds.Exclamation.Play(); + break; + case KryptonMessageBoxIcon.Information: + _messageIcon.Image = Resources.Information_Windows_11; + SystemSounds.Asterisk.Play(); + break; + case KryptonMessageBoxIcon.Shield: + _messageIcon.Image = Resources.UAC_Shield_Windows_11; + break; + case KryptonMessageBoxIcon.WindowsLogo: + _messageIcon.Image = Resources.Windows11; + break; + case KryptonMessageBoxIcon.Application: + if (_applicationImage != null) + { + _messageIcon.Image = _applicationImage; + } + else if (!string.IsNullOrEmpty(_applicationPath)) + { + Image? sourceImage = GraphicsExtensions.ExtractIconFromFilePath(_applicationPath)?.ToBitmap(); + Image? scaledImage = GraphicsExtensions.ScaleImage(sourceImage, new Size(32, 32)); + + _messageIcon.Image = scaledImage; + } + else + { + // Fall back to defaults + _messageIcon.Image = SystemIcons.Application.ToBitmap(); + } + break; + case KryptonMessageBoxIcon.SystemApplication: + _messageIcon.Image = SystemIcons.Application.ToBitmap(); + break; + } + } + else + { + switch (_kryptonMessageBoxIcon) + { + case KryptonMessageBoxIcon.None: + // Windows XP and before will Beep, Vista and above do not! + if (OS_MAJOR_VERSION < 6) + { + SystemSounds.Beep.Play(); + } + break; + case KryptonMessageBoxIcon.Hand: + _messageIcon.Image = Resources.GenericHand; + SystemSounds.Hand.Play(); + break; + case KryptonMessageBoxIcon.SystemHand: + _messageIcon.Image = SystemIcons.Hand.ToBitmap(); + SystemSounds.Hand.Play(); + break; + case KryptonMessageBoxIcon.Question: + _messageIcon.Image = Resources.GenericQuestion; + SystemSounds.Question.Play(); + break; + case KryptonMessageBoxIcon.SystemQuestion: + _messageIcon.Image = SystemIcons.Question.ToBitmap(); + SystemSounds.Question.Play(); + break; + case KryptonMessageBoxIcon.Exclamation: + _messageIcon.Image = Resources.GenericWarning; + SystemSounds.Exclamation.Play(); + break; + case KryptonMessageBoxIcon.SystemExclamation: + _messageIcon.Image = SystemIcons.Warning.ToBitmap(); + SystemSounds.Exclamation.Play(); + break; + case KryptonMessageBoxIcon.Asterisk: + _messageIcon.Image = OSUtilities.IsWindowsEleven + ? Resources.Asterisk_Windows_11 + : Resources.GenericAsterisk; + SystemSounds.Asterisk.Play(); + break; + case KryptonMessageBoxIcon.SystemAsterisk: + _messageIcon.Image = SystemIcons.Asterisk.ToBitmap(); + SystemSounds.Asterisk.Play(); + break; + case KryptonMessageBoxIcon.Stop: + _messageIcon.Image = Resources.GenericStop; + SystemSounds.Asterisk.Play(); + break; + case KryptonMessageBoxIcon.Error: + _messageIcon.Image = Resources.GenericCritical; + SystemSounds.Asterisk.Play(); + break; + case KryptonMessageBoxIcon.Warning: + _messageIcon.Image = Resources.GenericWarning; + SystemSounds.Exclamation.Play(); + break; + case KryptonMessageBoxIcon.Information: + _messageIcon.Image = Resources.GenericInformation; + SystemSounds.Asterisk.Play(); + break; + case KryptonMessageBoxIcon.Shield: + if (OSUtilities.IsWindowsEleven) + { + _messageIcon.Image = Resources.UAC_Shield_Windows_11; + } + else if (OSUtilities.IsWindowsTen) + { + _messageIcon.Image = Resources.UAC_Shield_Windows_11; + } + else + { + _messageIcon.Image = Resources.UAC_Shield_Windows_11; + } + break; + case KryptonMessageBoxIcon.WindowsLogo: + // Because Windows 11 displays a generic application icon, + // we need to rely on a image instead + if (OSUtilities.IsWindowsEleven) + { + _messageIcon.Image = Resources.Windows11; + } + // Windows 10 + else if (OSUtilities.IsWindowsTen) + { + _messageIcon.Image = Resources.Windows11; + } + else + { + _messageIcon.Image = SystemIcons.WinLogo.ToBitmap(); + } + break; + case KryptonMessageBoxIcon.Application: + if (_applicationImage != null) + { + _messageIcon.Image = _applicationImage; + } + else if (!string.IsNullOrEmpty(_applicationPath)) + { + Image? sourceImage = GraphicsExtensions.ExtractIconFromFilePath(_applicationPath)?.ToBitmap(); + Image? scaledImage = GraphicsExtensions.ScaleImage(sourceImage, new Size(32, 32)); + + _messageIcon.Image = scaledImage; + } + else + { + // Fall back to defaults + _messageIcon.Image = SystemIcons.Application.ToBitmap(); + } + break; + case KryptonMessageBoxIcon.SystemApplication: + _messageIcon.Image = SystemIcons.Application.ToBitmap(); + break; + } + } + _messageIcon.Visible = (_kryptonMessageBoxIcon != KryptonMessageBoxIcon.None); + } + + private void UpdateButtons() + { + switch (_buttons) + { + case KryptonMessageBoxButtons.OK: + _button1.Text = GeneralToolkitStringsPolicy.GetInstance().ComposeMessage(GeneralToolkitStringsPolicy.OK); + _button1.DialogResult = DialogResult.OK; + _button1.Visible = true; + _button1.Enabled = true; + break; + case KryptonMessageBoxButtons.OKCancel: + _button1.Text = GeneralToolkitStringsPolicy.GetInstance().ComposeMessage(GeneralToolkitStringsPolicy.OK); + _button2.Text = GeneralToolkitStringsPolicy.GetInstance().ComposeMessage(GeneralToolkitStringsPolicy.CANCEL); + _button1.DialogResult = DialogResult.OK; + _button2.DialogResult = DialogResult.Cancel; + _button1.Visible = true; + _button1.Enabled = true; + _button2.Visible = true; + _button2.Enabled = true; + break; + case KryptonMessageBoxButtons.YesNo: + _button1.Text = GeneralToolkitStringsPolicy.GetInstance().ComposeMessage(GeneralToolkitStringsPolicy.YES); + _button2.Text = GeneralToolkitStringsPolicy.GetInstance().ComposeMessage(GeneralToolkitStringsPolicy.NO); + _button1.DialogResult = DialogResult.Yes; + _button2.DialogResult = DialogResult.No; + _button1.Visible = true; + _button1.Enabled = true; + _button2.Visible = true; + _button2.Enabled = true; + ControlBox = false; + break; + case KryptonMessageBoxButtons.YesNoCancel: + _button1.Text = GeneralToolkitStringsPolicy.GetInstance().ComposeMessage(GeneralToolkitStringsPolicy.YES); + _button2.Text = GeneralToolkitStringsPolicy.GetInstance().ComposeMessage(GeneralToolkitStringsPolicy.NO); + _button3.Text = GeneralToolkitStringsPolicy.GetInstance().ComposeMessage(GeneralToolkitStringsPolicy.CANCEL); + _button1.DialogResult = DialogResult.Yes; + _button2.DialogResult = DialogResult.No; + _button3.DialogResult = DialogResult.Cancel; + _button1.Visible = true; + _button1.Enabled = true; + _button2.Visible = true; + _button2.Enabled = true; + _button3.Visible = true; + _button3.Enabled = true; + break; + case KryptonMessageBoxButtons.RetryCancel: + _button1.Text = GeneralToolkitStringsPolicy.GetInstance().ComposeMessage(GeneralToolkitStringsPolicy.RETRY); + _button2.Text = GeneralToolkitStringsPolicy.GetInstance().ComposeMessage(GeneralToolkitStringsPolicy.CANCEL); + _button1.DialogResult = DialogResult.Retry; + _button2.DialogResult = DialogResult.Cancel; + _button1.Visible = true; + _button1.Enabled = true; + _button2.Visible = true; + _button2.Enabled = true; + break; + case KryptonMessageBoxButtons.AbortRetryIgnore: + _button1.Text = GeneralToolkitStringsPolicy.GetInstance().ComposeMessage(GeneralToolkitStringsPolicy.ABORT); + _button2.Text = GeneralToolkitStringsPolicy.GetInstance().ComposeMessage(GeneralToolkitStringsPolicy.RETRY); + _button3.Text = GeneralToolkitStringsPolicy.GetInstance().ComposeMessage(GeneralToolkitStringsPolicy.IGNORE); + _button1.DialogResult = DialogResult.Abort; + _button2.DialogResult = DialogResult.Retry; + _button3.DialogResult = DialogResult.Ignore; + _button1.Visible = true; + _button1.Enabled = true; + _button2.Visible = true; + _button2.Enabled = true; + _button3.Visible = true; + _button3.Enabled = true; + ControlBox = false; + break; + case KryptonMessageBoxButtons.CancelTryContinue: + _button1.Text = GeneralToolkitStringsPolicy.GetInstance().ComposeMessage(GeneralToolkitStringsPolicy.CANCEL); + _button2.Text = GeneralToolkitStringsPolicy.GetInstance().ComposeMessage(GeneralToolkitStringsPolicy.TRYAGAIN); + _button3.Text = GeneralToolkitStringsPolicy.GetInstance().ComposeMessage(GeneralToolkitStringsPolicy.CONTINUE); + _button1.DialogResult = DialogResult.Cancel; +#if NET6_0_OR_GREATER + _button2.DialogResult = DialogResult.TryAgain; + _button3.DialogResult = DialogResult.Continue; +#else + _button2.DialogResult = (DialogResult)10; + _button3.DialogResult = (DialogResult)11; +#endif + _button1.Visible = true; + _button1.Enabled = true; + _button2.Visible = true; + _button2.Enabled = true; + _button3.Visible = true; + _button3.Enabled = true; + break; + } + + if (_showActionButton) + { + _button5.Text = _actionButtonText; + _button5.Visible = true; + _button5.Enabled = true; + _button5.KryptonCommand = _actionButtonCommand; + } + + // Do we ignore the Alt+F4 on the buttons? + if (!ControlBox) + { + _button1.IgnoreAltF4 = true; + _button2.IgnoreAltF4 = true; + _button3.IgnoreAltF4 = true; + _button4.IgnoreAltF4 = true; + _button5.IgnoreAltF4 = true; + } + } + + private void UpdateDefault() + { + switch (_defaultButton) + { + case KryptonMessageBoxDefaultButton.Button1: + _button1.Select(); + AcceptButton = _button1; + break; + case KryptonMessageBoxDefaultButton.Button2: + _button2.Select(); + AcceptButton = _button2; + break; + case KryptonMessageBoxDefaultButton.Button3: + _button3.Select(); + AcceptButton = _button3; + break; + case KryptonMessageBoxDefaultButton.Button4: + _button4.Select(); + AcceptButton = _showHelpButton ? _button4 : _button1; + break; + default: + _button1.Select(); + AcceptButton = _showHelpButton ? _button4 : _button1; + break; + } + } + + private void UpdateHelp() + { + if (!_showHelpButton) + { + return; + } + + MessageButton helpButton = _buttons switch + { + KryptonMessageBoxButtons.OK => _button2, + KryptonMessageBoxButtons.OKCancel or KryptonMessageBoxButtons.YesNo or KryptonMessageBoxButtons.RetryCancel => _button3, + KryptonMessageBoxButtons.AbortRetryIgnore or KryptonMessageBoxButtons.YesNoCancel => _button4, + _ => throw new ArgumentOutOfRangeException() + }; + if (helpButton != null) + { + helpButton.Visible = true; + helpButton.Enabled = true; + helpButton.Text = KryptonLanguageManager.GeneralToolkitStrings.Help; + helpButton.KeyPress += (_, _) => LaunchHelp(); + helpButton.Click += (_, _) => LaunchHelp(); + } + } + + /// + /// When the user clicks the Help button, the Help file specified in the helpFilePath parameter + /// is opened and the Help keyword topic identified by the keyword parameter is Displayed. + /// The form that owns the message box (or the active form) also receives the HelpRequested event. + /// + private void LaunchHelp() + { + try + { + if (_showOwner != null) + { + Control control = FromHandle(_showOwner.Handle); + + MethodInfo? mInfoMethod = control.GetType().GetMethod(nameof(OnHelpRequested), BindingFlags.Instance | BindingFlags.NonPublic, + Type.DefaultBinder, new[] { typeof(HelpEventArgs) }, null)!; + mInfoMethod?.Invoke(control, new object[] { new HelpEventArgs(MousePosition) }); + if (_helpInfo != null) + { + if (string.IsNullOrWhiteSpace(_helpInfo.HelpFilePath)) + { + return; + } + + if (!string.IsNullOrWhiteSpace(_helpInfo.Keyword)) + { + Help.ShowHelp(control, _helpInfo.HelpFilePath, _helpInfo.Keyword); + } + else + { + Help.ShowHelp(control, _helpInfo.HelpFilePath, _helpInfo.Navigator, _helpInfo.Param); + } + } + } + } + catch + { + // Do nothing if failure to send to Parent + } + } + + private void UpdateSizing(IWin32Window? showOwner) + { + Size messageSizing = UpdateMessageSizing(showOwner); + Size buttonsSizing = UpdateButtonsSizing(); + + // Size of window is calculated from the client area + ClientSize = new Size(Math.Max(messageSizing.Width, buttonsSizing.Width), + messageSizing.Height + buttonsSizing.Height); + } + + private Size UpdateMessageSizing(IWin32Window? showOwner) + { + // Update size of the message label but with a maximum width + Size textSize; + using (Graphics g = CreateGraphics()) + { + // Find size of the label, with a max of 2/3 screen width + Screen screen = showOwner is IWin32Window window + ? Screen.FromHandle(window.Handle) + : Screen.PrimaryScreen ?? throw new NullReferenceException("Screen.PrimaryScreen returned null"); + + Size scaledMonitorSize = screen.WorkingArea.Size; + scaledMonitorSize.Width = (int)(scaledMonitorSize.Width * 2 / 3.0f); + scaledMonitorSize.Height = (int)(scaledMonitorSize.Height * 0.95f); + + Font textFont = krtbMessageText.StateCommon.Content.GetContentShortTextFont(PaletteState.Normal); + Font captionFont = KryptonManager.CurrentGlobalPalette!.BaseFont; + + // Measure the string + SizeF messageSize = g.MeasureString(_text, textFont, new SizeF(scaledMonitorSize.Width, scaledMonitorSize.Height)); + // SKC: Don't forget to add the TextExtra into the calculation + SizeF captionSize = TextRenderer.MeasureText($"{_caption} {TextExtra}", captionFont, scaledMonitorSize); + + var messageXSize = Math.Max(messageSize.Width, captionSize.Width); + // Work out DPI adjustment factor + var factorX = g.DpiX > 96 ? (1.0f * g.DpiX / 96) : 1.0f; + var factorY = g.DpiY > 96 ? (1.0f * g.DpiY / 96) : 1.0f; + messageSize.Width = messageXSize * factorX; + messageSize.Height *= factorY; + + textSize = Size.Ceiling(messageSize); + } + + // Calculate the size of the icon area and text area including margins + Padding textPadding = krtbMessageText.StateCommon.Content.GetContentPadding(PaletteState.Normal); + Padding textAreaAllMargin = Padding.Add(textPadding, _panelContentArea.Margin); + + Size iconArea = new Size(_messageIcon.Width + _messageIcon.Margin.Left + _messageIcon.Margin.Right, + _messageIcon.Height + _messageIcon.Margin.Top + _messageIcon.Margin.Bottom); + + Size textArea = new Size(textSize.Width + textAreaAllMargin.Left + textAreaAllMargin.Right, + textSize.Height + textAreaAllMargin.Top + textAreaAllMargin.Bottom); + + return new Size(textArea.Width + iconArea.Width, + Math.Max(iconArea.Height, textArea.Height)); + } + + private Size UpdateButtonsSizing() + { + var numButtons = 1; + + // Button1 is always visible + Size button1Size = _button1.GetPreferredSize(Size.Empty); + var maxButtonSize = button1Size with { Width = button1Size.Width + GAP }; + + // If Button2 is visible + if (_button2.Enabled) + { + numButtons++; + Size button2Size = _button2.GetPreferredSize(Size.Empty); + maxButtonSize.Width = Math.Max(maxButtonSize.Width, button2Size.Width + GAP); + maxButtonSize.Height = Math.Max(maxButtonSize.Height, button2Size.Height); + } + + // If Button3 is visible + if (_button3.Enabled) + { + numButtons++; + Size button3Size = _button3.GetPreferredSize(Size.Empty); + maxButtonSize.Width = Math.Max(maxButtonSize.Width, button3Size.Width + GAP); + maxButtonSize.Height = Math.Max(maxButtonSize.Height, button3Size.Height); + } + // If Button4 is visible + if (_button4.Enabled) + { + numButtons++; + Size button4Size = _button4.GetPreferredSize(Size.Empty); + maxButtonSize.Width = Math.Max(maxButtonSize.Width, button4Size.Width + GAP); + maxButtonSize.Height = Math.Max(maxButtonSize.Height, button4Size.Height); + } + + // If Action button is visible + if (_button5.Enabled) + { + numButtons++; + Size actionButtonSize = _button5.GetPreferredSize(Size.Empty); + maxButtonSize.Width = Math.Max(maxButtonSize.Width, actionButtonSize.Width + GAP); + maxButtonSize.Height = Math.Max(maxButtonSize.Height, actionButtonSize.Height); + } + + // Start positioning buttons 10 pixels from right edge + var right = _panelButtons.Right - GAP; + var left = _panelButtons.Left - GAP; + + // If Action button is visible + if (_button5.Enabled) + { + _button5.Location = new Point(left - maxButtonSize.Width, GAP); + _button5.Size = maxButtonSize; + left -= maxButtonSize.Width + GAP; + } + + // If Button4 is visible + if (_button4.Enabled) + { + _button4.Location = new Point(right - maxButtonSize.Width, GAP); + _button4.Size = maxButtonSize; + right -= maxButtonSize.Width + GAP; + } + + // If Button3 is visible + if (_button3.Enabled) + { + _button3.Location = new Point(right - maxButtonSize.Width, GAP); + _button3.Size = maxButtonSize; + right -= maxButtonSize.Width + GAP; + } + + // If Button2 is visible + if (_button2.Enabled) + { + _button2.Location = new Point(right - maxButtonSize.Width, GAP); + _button2.Size = maxButtonSize; + right -= maxButtonSize.Width + GAP; + } + + // Button1 is always visible + _button1.Location = new Point(right - maxButtonSize.Width, GAP); + _button1.Size = maxButtonSize; + + // Size the panel for the buttons + _panelButtons.Size = new Size((maxButtonSize.Width * numButtons) + (GAP * (numButtons + 1)), maxButtonSize.Height + (GAP * 2)); + + // Button area is the number of buttons with gaps between them and 10 pixels around all edges + return new Size((maxButtonSize.Width * numButtons) + (GAP * (numButtons + 1)), maxButtonSize.Height + (GAP * 2)); + } + + private void OnFormClosed(object sender, FormClosedEventArgs e) + { + _krtbNativeWindow.ReleaseHandle(); + } + + private void AnyKeyDown(object sender, KeyEventArgs e) + { + // Escape key kills the dialog if we allow it to be closed + if (ControlBox + && (e.KeyCode == Keys.Escape) + ) + { + Close(); + } + else if (e.KeyData == (Keys.Control | Keys.C)) + { + const string DIVIDER = @"---------------------------"; + const string BUTTON_TEXT_SPACER = @" "; + // Pressing Ctrl+C should copy message text into the clipboard + var sb = new StringBuilder(); + + sb.AppendLine(DIVIDER); + sb.AppendLine(Text); + sb.AppendLine(DIVIDER); + sb.AppendLine(krtbMessageText.Text); + sb.AppendLine(DIVIDER); + sb.Append(_button1.Text).Append(BUTTON_TEXT_SPACER); + if (_button2.Enabled) + { + sb.Append(_button2.Text).Append(BUTTON_TEXT_SPACER); + if (_button3.Enabled) + { + sb.Append(_button3.Text).Append(BUTTON_TEXT_SPACER); + } + + if (_button4.Enabled) + { + sb.Append(_button4.Text).Append(BUTTON_TEXT_SPACER); + } + } + + sb.AppendLine(string.Empty); + sb.AppendLine(DIVIDER); + + Clipboard.SetText(sb.ToString(), TextDataFormat.Text); + Clipboard.SetText(sb.ToString(), TextDataFormat.UnicodeText); + } + } + + /// Setups the action button UI. + /// if set to true [visible]. + private void SetupActionButtonUI(bool visible) + { + _button5.Visible = visible; + _button5.Enabled = visible; + _button5.Click += (sender, args) => + { + try + { + _actionButtonCommand?.PerformExecute(); + } + catch (Exception e) + { + Debug.Assert(true, e.StackTrace); + + DialogResult = DialogResult.None; + } + }; + } + + private void LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + try + { + if (_linkLabelCommand != null) + { + _linkLabelCommand.PerformExecute(); + } + else if (_linkLaunchArgument != null) + { + Process.Start(_linkLaunchArgument); + } + } + catch (Exception exception) + { + ExceptionHandler.CaptureException(exception); + } + } + + /// Updates the type of the content area. + /// Type of the content area. + private void UpdateContentAreaType(MessageBoxContentAreaType? contentAreaType) + { + switch (contentAreaType) + { + case MessageBoxContentAreaType.Normal: + _linkLabelMessageText.Visible = false; + + krtbMessageText.Visible = true; + break; + case MessageBoxContentAreaType.LinkLabel: + _linkLabelMessageText.Visible = true; + + krtbMessageText.Visible = false; + break; + } + } + + private void UpdateContentLinkArea(LinkArea? contentLinkArea) + { + if (contentLinkArea != null) + { + _linkLabelMessageText.LinkArea = (LinkArea)contentLinkArea; + } + } + + #endregion + } + + #region Types + internal class HelpInfo + { + #region Identity + + /// + /// Initialize a new instance of the HelpInfo class. + /// + /// Value for HelpFilePath. + /// Value for Keyword + public HelpInfo(string? helpFilePath = null, string? keyword = null) + : this(helpFilePath, keyword, !string.IsNullOrWhiteSpace(keyword) ? HelpNavigator.Topic : HelpNavigator.TableOfContents, null) + { + } + + /// + /// Initialize a new instance of the HelpInfo class. + /// + /// Value for HelpFilePath. + /// Value for Navigator + /// + public HelpInfo(string? helpFilePath, HelpNavigator navigator, object? param = null) + : this(helpFilePath, null, navigator, param) + { + } + + /// + /// Initialize a new instance of the HelpInfo class. + /// + /// Value for HelpFilePath. + /// Value for Navigator + /// Value for Keyword + /// + private HelpInfo(string? helpFilePath, string? keyword, HelpNavigator navigator, object? param) + { + HelpFilePath = helpFilePath ?? string.Empty; + Keyword = keyword ?? string.Empty; + Navigator = navigator; + Param = param; + } + #endregion + + #region Properties + /// + /// Gets the HelpFilePath property. + /// + public string HelpFilePath { get; } + + /// + /// Gets the Keyword property. + /// + public string Keyword { get; } + + /// + /// Gets the Navigator property. + /// + public HelpNavigator Navigator { get; } + + /// + /// Gets the Param property. + /// + public object? Param { get; } + + #endregion + } + + #endregion + + [ToolboxItem(false)] + [DesignTimeVisible(false)] + internal class MessageButton : KryptonButton + { + #region Identity + public MessageButton() + { + IgnoreAltF4 = false; + Visible = false; + Enabled = false; + } + + /// + /// Gets and sets the ignoring of Alt+F4 + /// + public bool IgnoreAltF4 { get; set; } + + #endregion + + #region Protected + /// + /// Processes Windows messages. + /// + /// The Windows Message to process. + protected override void WndProc(ref Message m) + { + switch (m.Msg) + { + case KEYDOWN: + case SYSKEYDOWN: + if (IgnoreAltF4) + { + // Extract the keys being pressed + var keys = (Keys)(int)m.WParam.ToInt64(); + + // If the user standard combination ALT + F4 + if ((keys == Keys.F4) && ((ModifierKeys & Keys.Alt) == Keys.Alt)) + { + // Eat the message, so standard window proc does not close the window + return; + } + } + break; + } + + base.WndProc(ref m); + } + + public const int KEYDOWN = 256; + + public const int SYSKEYDOWN = 260; + #endregion + } + + internal class KryptonMessageBoxNativeWindow : NativeWindow + { + private const int WM_SETFOCUS = 7; + + private const int WM_KILLFOCUS = 8; + + private const int WM_MOUSEWHEEL = 522; + + protected override void WndProc(ref Message m) + { + if (m.Msg == 7) + { + m.Msg = 8; + } + + if (m.Msg != 522) + { + base.WndProc(ref m); + } + } + } + + internal class ExceptionHandler + { + // + // 摘要: + // Initializes a new instance of the Krypton.Toolkit.ExceptionHandler class. + public ExceptionHandler() + { + } + + // + // 摘要: + // Captures the exception. + // + // 參數: + // exception: + // The exception. + // + // title: + // The title. + // + // buttons: + // The buttons. + // + // icon: + // The icon. + // + // className: + // Name of the class. + // + // methodSignature: + // The method signature. + public static void CaptureException(Exception exception, string title = "Exception Caught", KryptonMessageBoxButtons buttons = KryptonMessageBoxButtons.OK, KryptonMessageBoxIcon icon = KryptonMessageBoxIcon.Warning, string className = "", string methodSignature = "") + { + if (className != "") + { + KryptonMessageBox.Show($"An unexpected error has occurred: {exception.Message}.\n\nError in class: '{className}.cs'.", title, buttons, icon); + } + else if (methodSignature != "") + { + KryptonMessageBox.Show($"An unexpected error has occurred: {exception.Message}.\n\nError in method: '{methodSignature}'.", title, buttons, icon); + } + else if (className != "" && methodSignature != "") + { + KryptonMessageBox.Show($"An unexpected error has occurred: {exception.Message}.\n\nError in class: '{className}.cs'.\n\nError in method: '{methodSignature}'.", title, buttons, icon); + } + else + { + KryptonMessageBox.Show("An unexpected error has occurred: " + exception.Message + ".", title, buttons, icon); + } + } + + // + // 摘要: + // Captures a stack trace of the exception. + // + // 參數: + // exception: + // The incoming exception. + // + // fileName: + // The file to write the exception stack trace to. + public static void PrintStackTrace(Exception exception, string fileName) + { + try + { + if (!File.Exists(fileName)) + { + File.Create(fileName); + } + + StreamWriter streamWriter = new StreamWriter(fileName); + streamWriter.Write(exception.ToString()); + streamWriter.Close(); + streamWriter.Dispose(); + } + catch (Exception exception2) + { + CaptureException(exception2); + } + } + + // + // 摘要: + // Captures a stack trace of the exception. + // + // 參數: + // exception: + // The incoming exception. + // + // fileName: + // The file to write the exception stack trace to. + public static void PrintExceptionStackTrace(Exception exception, string fileName) + { + try + { + if (!File.Exists(fileName)) + { + File.Create(fileName); + } + + StreamWriter streamWriter = new StreamWriter(fileName); + streamWriter.Write(exception.StackTrace); + streamWriter.Close(); + streamWriter.Dispose(); + } + catch (Exception exception2) + { + CaptureException(exception2); + } + } + } + +} diff --git a/CloudBuilder/CloudBuilder.Gui/KryptonMessageBoxForm.resx b/CloudBuilder/CloudBuilder.Gui/KryptonMessageBoxForm.resx new file mode 100644 index 0000000..8b2ff64 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/KryptonMessageBoxForm.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Gui/KryptonRadioButtonExtensions.cs b/CloudBuilder/CloudBuilder.Gui/KryptonRadioButtonExtensions.cs new file mode 100644 index 0000000..213542a --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/KryptonRadioButtonExtensions.cs @@ -0,0 +1,125 @@ +using CloudBuilder; +using CloudBuilder.Gui; +using CloudBuilder.Gui.DependencyInjection; +using Microsoft.AspNetCore.Authorization; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Krypton.Toolkit +{ + public static class KryptonRadioButtonExtensions + { + public static ExFormSnapshotEntry GetExFormSnapshotEntry(this KryptonRadioButton kryptonRadioButton) + { + string bindDataName = null; + + if (GetProvider().GetCustomAttribute(kryptonRadioButton) != null) + bindDataName = GetProvider().GetCustomAttribute(kryptonRadioButton).BindDataName; + + return new ExFormSnapshotEntry( + kryptonRadioButton.Name, + bindDataName, + kryptonRadioButton.Checked, + kryptonRadioButton.Text); + } + + public static void Set(this KryptonRadioButton kryptonRadioButton, + BindingContextCustomAttribute bindingContext) + { + GetProvider().SetCustomAttribute(kryptonRadioButton, bindingContext); + } + + public static void Set(this KryptonRadioButton kryptonRadioButton, + EnumEditModeColor editModeColor) + { + GetProvider().SetCustomAttribute(kryptonRadioButton, editModeColor); + } + + public static void Set(this KryptonRadioButton kryptonRadioButton, + string bindDataName, + EnumEditModeColor editModeColor) + { + GetProvider().SetCustomAttribute(kryptonRadioButton, bindDataName, editModeColor); + } + + public static void Set(this KryptonRadioButton kryptonRadioButton, + string bindDataName) + { + GetProvider().SetCustomAttribute(kryptonRadioButton, bindDataName, EnumBindDirection.Both); + } + + public static void Set(this KryptonRadioButton kryptonRadioButton, + string bindDataName, + EnumBindDirection bindDirection) + { + GetProvider().SetCustomAttribute(kryptonRadioButton, bindDataName, bindDirection); + } + + + public static void Set(this KryptonRadioButton kryptonRadioButton, + string bindDataName, + EnumBindDirection bindDirection, + EnumEditModeColor editModeColor) + { + GetProvider().SetCustomAttribute(kryptonRadioButton, bindDataName, bindDirection, editModeColor); + } + + public static void Set(this KryptonRadioButton kryptonRadioButton, + string bindDataName, + string bindFormat, + EnumBindDirection bindDirection) + { + GetProvider().SetCustomAttribute(kryptonRadioButton, bindDataName, bindFormat, bindDirection); + } + + public static void Set(this KryptonRadioButton kryptonRadioButton, + string permissionName, + Operate permissionMode) + { + GetProvider().SetCustomAttribute(kryptonRadioButton, permissionName, permissionMode); + } + + public static bool GetValue(this KryptonRadioButton kryptonRadioButton) + { + return kryptonRadioButton.Checked; + } + + + public static void SetValue(this KryptonRadioButton kryptonRadioButton, object value) + { + if (value == null) + { + kryptonRadioButton.Checked = false; + } + else if (value is bool) + { + kryptonRadioButton.Checked = (bool)value; + } + else if (value is string) + { + kryptonRadioButton.Checked = value.ToString().ToUpper() == "Y" ? true : false; + } + else if (value is decimal || value is int || value is Int32 || value is Int64 || value is Int16 || value is double || value is float) + { + kryptonRadioButton.Checked = Convert.ToDecimal(value) > 0; + } + } + + public static BindingContextCustomAttribute GetCustomAttribute(this KryptonRadioButton kryptonRadioButton) + { + return GetProvider().GetCustomAttribute(kryptonRadioButton); + } + + private static BindingContextAttributeProvider GetProvider() + { + return ServiceHelper.GetService() ?? + throw new InvalidOperationException("BindingContextAttributeProvider is not registered in the service GetProvider()."); + } + } +} + + diff --git a/CloudBuilder/CloudBuilder.Gui/KryptonTextBoxExtensions.cs b/CloudBuilder/CloudBuilder.Gui/KryptonTextBoxExtensions.cs new file mode 100644 index 0000000..ef8ca89 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/KryptonTextBoxExtensions.cs @@ -0,0 +1,167 @@ +using CloudBuilder; +using CloudBuilder.Gui; +using CloudBuilder.Gui.DependencyInjection; +using Microsoft.AspNetCore.Authorization; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Data.SqlTypes; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Krypton.Toolkit +{ + public static class KryptonTextBoxExtensions + { + public const string DATA_FROMAT = "yyyy-MM-dd"; + + public static ExFormSnapshotEntry GetExFormSnapshotEntry(this KryptonTextBox kryptonTextBox) + { + string bindDataName = null; + + if (GetProvider().GetCustomAttribute(kryptonTextBox) != null) + bindDataName = GetProvider().GetCustomAttribute(kryptonTextBox).BindDataName; + + return new ExFormSnapshotEntry(kryptonTextBox.Name, bindDataName, kryptonTextBox.Text, kryptonTextBox.Text); + } + + public static void Set(this KryptonTextBox kryptonTextBox, + BindingContextCustomAttribute bindingContext) + { + GetProvider().SetCustomAttribute(kryptonTextBox, bindingContext); + } + + public static void Set(this KryptonTextBox kryptonTextBox, + EnumEditModeColor editModeColor) + { + GetProvider().SetCustomAttribute(kryptonTextBox, editModeColor); + } + + public static void Set(this KryptonTextBox kryptonTextBox, EnumEditModeColor editModeColor, string bindDisplayName) + { + GetProvider().SetCustomAttribute(kryptonTextBox, editModeColor, bindDisplayName); + } + + public static void Set(this KryptonTextBox kryptonTextBox, + string bindDataName, + EnumEditModeColor editModeColor) + { + GetProvider().SetCustomAttribute(kryptonTextBox, bindDataName, editModeColor); + } + + public static void Set(this KryptonTextBox kryptonTextBox, + string bindDataName, string bindDisplayName, EnumEditModeColor editModeColor) + { + GetProvider().SetCustomAttribute(kryptonTextBox, bindDataName, bindDisplayName, editModeColor); + } + + public static void Set(this KryptonTextBox kryptonTextBox, + string bindDataName, string bindFormat, string bindDisplayName, EnumEditModeColor editModeColor) + { + GetProvider().SetCustomAttribute(kryptonTextBox, bindDataName, bindFormat, bindDisplayName, editModeColor); + } + + public static void Set(this KryptonTextBox kryptonTextBox, string bindDataName) + { + GetProvider().SetCustomAttribute(kryptonTextBox, bindDataName, EnumBindDirection.Both); + } + + public static void Set(this KryptonTextBox kryptonTextBox, + string bindDataName, EnumBindDirection bindDirection) + { + GetProvider().SetCustomAttribute(kryptonTextBox, bindDataName, bindDirection); + } + + + public static void Set(this KryptonTextBox kryptonTextBox, + string bindDataName, + EnumBindDirection bindDirection, + EnumEditModeColor editModeColor) + { + GetProvider().SetCustomAttribute(kryptonTextBox, bindDataName, bindDirection, editModeColor); + } + + public static void Set(this KryptonTextBox kryptonTextBox, string bindDataName, string bindFormat, string bindDisplayName, EnumBindDirection bindDirection) + { + GetProvider().SetCustomAttribute(kryptonTextBox, bindDataName, bindFormat, bindDisplayName, bindDirection); + } + + public static void Set(this KryptonTextBox kryptonTextBox, + string permissionName, + Operate permissionMode) + { + GetProvider().SetCustomAttribute(kryptonTextBox, permissionName, permissionMode); + } + + public static void Set(this KryptonTextBox kryptonTextBox, string permissionName, string dependentDetailName, Operate permissionMode) + { + GetProvider().SetCustomAttribute(kryptonTextBox, permissionName, dependentDetailName, permissionMode); + } + + public static void Set(this KryptonTextBox kryptonTextBox, string permissionName, string dependentDetailName) + { + GetProvider().SetCustomAttribute(kryptonTextBox, permissionName, dependentDetailName); + } + + public static string GetValue(this KryptonTextBox kryptonTextBox) + { + if (string.IsNullOrEmpty(kryptonTextBox.Text)) return string.Empty; + return kryptonTextBox.Text.Trim(); + } + + public static void SetValue(this KryptonTextBox kryptonTextBox, string value) + { + kryptonTextBox.Text = value; + } + + public static void SetValue(this KryptonTextBox kryptonTextBox, object value, string bindFormat) + { + if (value == null) + { + kryptonTextBox.Text = null; + } + else if (value is string) + { + kryptonTextBox.Text = value.ToString(); + } + else if (value is DateTime) + { + if (value == null) + kryptonTextBox.Text = string.Empty; + else if (!string.IsNullOrEmpty(bindFormat)) + kryptonTextBox.Text = ((DateTime)value).ToString(bindFormat); + else + kryptonTextBox.Text = ((DateTime)value).ToString(DATA_FROMAT); + } + else if (value is SqlDateTime) + { + if (((SqlDateTime)value).IsNull) + kryptonTextBox.Text = string.Empty; + else if (!string.IsNullOrEmpty(bindFormat)) + kryptonTextBox.Text = ((DateTime)value).ToString(bindFormat); + else + kryptonTextBox.Text = ((DateTime)value).ToString(DATA_FROMAT); + } + else if (value is decimal || value is int || value is Int32 || value is Int64 || value is Int16 || value is double || value is float) + { + if (!string.IsNullOrEmpty(bindFormat)) + kryptonTextBox.Text = (Convert.ToDecimal(value)).ToString(bindFormat); + else + kryptonTextBox.Text = (Convert.ToDecimal(value)).ToString(); + } + } + + public static BindingContextCustomAttribute GetCustomAttribute(this KryptonTextBox kryptonTextBox) + { + return GetProvider().GetCustomAttribute(kryptonTextBox); + } + + private static BindingContextAttributeProvider GetProvider() + { + return ServiceHelper.GetService() ?? + throw new InvalidOperationException("BindingContextAttributeProvider is not registered in the service GetProvider()."); + } + } +} + diff --git a/CloudBuilder/CloudBuilder.Gui/Policy/GeneralToolkitStringsPolicy.cs b/CloudBuilder/CloudBuilder.Gui/Policy/GeneralToolkitStringsPolicy.cs new file mode 100644 index 0000000..3c47375 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/Policy/GeneralToolkitStringsPolicy.cs @@ -0,0 +1,43 @@ +using CloudBuilder.Core.DependencyInjection.Request; +using CloudBuilder.Core.Policy; +using CloudBuilder.Gui.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Gui.Policy +{ + public class GeneralToolkitStringsPolicy : AbstractPolicy + { + public const string GUI_CAPTION_ERROR = "gui_caption_error"; + public const string GUI_CAPTION_INFORMATION = "gui_caption_information"; + + public const string OK = "OK"; + public const string CANCEL = "Cancel"; + public const string YES = "Yes"; + public const string NO = "No"; + public const string RETRY = "Retry"; + public const string ABORT = "Abort"; + public const string IGNORE = "Ignore"; + public const string TRYAGAIN = "TryAgain"; + public const string CONTINUE = "Continue"; + + public static GeneralToolkitStringsPolicy instance = null; + private readonly IContext context; + + public GeneralToolkitStringsPolicy(IContext context):base(context) + { + this.context = context; + } + + public static GeneralToolkitStringsPolicy GetInstance() + { + instance = ServiceHelper.GetTypeService(); + instance.values = new string[] { OK, CANCEL, YES, NO, RETRY, ABORT, IGNORE, TRYAGAIN, CONTINUE }; + return instance; + } + } +} diff --git a/CloudBuilder/CloudBuilder.Gui/Policy/GeneralToolkitStringsPolicy_en.resx b/CloudBuilder/CloudBuilder.Gui/Policy/GeneralToolkitStringsPolicy_en.resx new file mode 100644 index 0000000..8ca79ae --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/Policy/GeneralToolkitStringsPolicy_en.resx @@ -0,0 +1,153 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + O&K + + + Cance&l + + + &Yes + + + Ret&ry + + + A&bort + + + I&gnore + + + Try Aga&in + + + Co&ntinue + + + N&o + + + Error Message + + + Verification Message + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Gui/Policy/GeneralToolkitStringsPolicy_zh-cn.resx b/CloudBuilder/CloudBuilder.Gui/Policy/GeneralToolkitStringsPolicy_zh-cn.resx new file mode 100644 index 0000000..2e5cebd --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/Policy/GeneralToolkitStringsPolicy_zh-cn.resx @@ -0,0 +1,153 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 中止(&b) + + + 取消(&l) + + + 继续(&n) + + + 出错信息 + + + 验证信息 + + + 忽视(&) + + + 否(&o) + + + 确定(&K) + + + 重试(&r) + + + 再试(&i) + + + 是(&Y) + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Gui/ProgressForm.Designer.cs b/CloudBuilder/CloudBuilder.Gui/ProgressForm.Designer.cs new file mode 100644 index 0000000..8105d7e --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/ProgressForm.Designer.cs @@ -0,0 +1,99 @@ +namespace CloudBuilder.Gui +{ + partial class ProgressForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + tableLayoutPanel1 = new TableLayoutPanel(); + messageLabel = new Krypton.Toolkit.KryptonLabel(); + progressBar = new Krypton.Toolkit.KryptonProgressBar(); + tableLayoutPanel1.SuspendLayout(); + SuspendLayout(); + // + // tableLayoutPanel1 + // + tableLayoutPanel1.AutoSize = true; + tableLayoutPanel1.AutoSizeMode = AutoSizeMode.GrowAndShrink; + tableLayoutPanel1.ColumnCount = 1; + tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel1.Controls.Add(messageLabel, 0, 0); + tableLayoutPanel1.Controls.Add(progressBar, 0, 1); + tableLayoutPanel1.Dock = DockStyle.Fill; + tableLayoutPanel1.Location = new Point(0, 0); + tableLayoutPanel1.Name = "tableLayoutPanel1"; + tableLayoutPanel1.RowCount = 2; + tableLayoutPanel1.RowStyles.Add(new RowStyle()); + tableLayoutPanel1.RowStyles.Add(new RowStyle()); + tableLayoutPanel1.Size = new Size(400, 59); + tableLayoutPanel1.TabIndex = 0; + // + // messageLabel + // + messageLabel.Dock = DockStyle.Fill; + messageLabel.Location = new Point(3, 3); + messageLabel.Name = "messageLabel"; + messageLabel.Size = new Size(394, 20); + messageLabel.TabIndex = 0; + messageLabel.Values.Text = "正在处理中,请稍等..."; + // + // progressBar + // + progressBar.Dock = DockStyle.Fill; + progressBar.Location = new Point(3, 29); + progressBar.Name = "progressBar"; + progressBar.Size = new Size(394, 27); + progressBar.StateCommon.Back.Color1 = Color.Green; + progressBar.StateDisabled.Back.ColorStyle = Krypton.Toolkit.PaletteColorStyle.OneNote; + progressBar.StateNormal.Back.ColorStyle = Krypton.Toolkit.PaletteColorStyle.OneNote; + progressBar.TabIndex = 1; + progressBar.Values.Text = ""; + // + // ProgressForm + // + AutoScaleDimensions = new SizeF(7F, 15F); + AutoScaleMode = AutoScaleMode.Font; + AutoSize = true; + AutoSizeMode = AutoSizeMode.GrowAndShrink; + ClientSize = new Size(400, 59); + CloseBox = false; + Controls.Add(tableLayoutPanel1); + FormBorderStyle = FormBorderStyle.None; + Name = "ProgressForm"; + Text = "ProgressForm"; + tableLayoutPanel1.ResumeLayout(false); + tableLayoutPanel1.PerformLayout(); + ResumeLayout(false); + PerformLayout(); + } + + #endregion + + private TableLayoutPanel tableLayoutPanel1; + private Krypton.Toolkit.KryptonLabel messageLabel; + private Krypton.Toolkit.KryptonProgressBar progressBar; + } +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Gui/ProgressForm.cs b/CloudBuilder/CloudBuilder.Gui/ProgressForm.cs new file mode 100644 index 0000000..745ac82 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/ProgressForm.cs @@ -0,0 +1,51 @@ +using CloudBuilder.Core.DependencyInjection.Form; +using CloudBuilder.Core.DependencyInjection.Request; +using Krypton.Toolkit; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using static System.Windows.Forms.VisualStyles.VisualStyleElement; + +namespace CloudBuilder.Gui +{ + public partial class ProgressForm : AbstractForm, IForm + { + private BackgroundWorker _worker; + + public ProgressForm(BackgroundWorker worker) + { + InitializeComponent(); + + InitResourceManager(); + + this.SetBounds((Screen.GetBounds(this).Width / 2) - (this.Width / 2), +(Screen.GetBounds(this).Height / 2) - (this.Height / 2), +this.Width, this.Height, BoundsSpecified.Location); + + _worker = worker; + _worker.ProgressChanged += Worker_ProgressChanged; + _worker.RunWorkerCompleted += Worker_RunWorkerCompleted; + } + + + private void Worker_ProgressChanged(object sender, ProgressChangedEventArgs e) + { + progressBar.Value = e.ProgressPercentage; + } + + private void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) + { + if (e.Error != null) + { + ShowMessageBox.ShowError(e.Error.Message); + } + this.Close(); + } + } +} diff --git a/CloudBuilder/CloudBuilder.Gui/ProgressForm.resx b/CloudBuilder/CloudBuilder.Gui/ProgressForm.resx new file mode 100644 index 0000000..8b2ff64 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/ProgressForm.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Gui/ProgressForm_en.resx b/CloudBuilder/CloudBuilder.Gui/ProgressForm_en.resx new file mode 100644 index 0000000..2a0ccd1 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/ProgressForm_en.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Processing, please wait a moment... + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Gui/ProgressForm_zh-cn.resx b/CloudBuilder/CloudBuilder.Gui/ProgressForm_zh-cn.resx new file mode 100644 index 0000000..2a11e4f --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/ProgressForm_zh-cn.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 正在处理中,请稍等...... + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Gui/Properties/Resources.Designer.cs b/CloudBuilder/CloudBuilder.Gui/Properties/Resources.Designer.cs new file mode 100644 index 0000000..977952e --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/Properties/Resources.Designer.cs @@ -0,0 +1,373 @@ +//------------------------------------------------------------------------------ +// +// 這段程式碼是由工具產生的。 +// 執行階段版本:4.0.30319.42000 +// +// 對這個檔案所做的變更可能會造成錯誤的行為,而且如果重新產生程式碼, +// 變更將會遺失。 +// +//------------------------------------------------------------------------------ + +namespace CloudBuilder.Gui.Properties { + using System; + + + /// + /// 用於查詢當地語系化字串等的強類型資源類別。 + /// + // 這個類別是自動產生的,是利用 StronglyTypedResourceBuilder + // 類別透過 ResGen 或 Visual Studio 這類工具。 + // 若要加入或移除成員,請編輯您的 .ResX 檔,然後重新執行 ResGen + // (利用 /str 選項),或重建您的 VS 專案。 + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// 傳回這個類別使用的快取的 ResourceManager 執行個體。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("CloudBuilder.Gui.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// 覆寫目前執行緒的 CurrentUICulture 屬性,對象是所有 + /// 使用這個強類型資源類別的資源查閱。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// 查詢類型 System.Drawing.Bitmap 的當地語系化資源。 + /// + internal static System.Drawing.Bitmap amend_16 { + get { + object obj = ResourceManager.GetObject("amend_16", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查詢類型 System.Drawing.Bitmap 的當地語系化資源。 + /// + internal static System.Drawing.Bitmap Asterisk_Windows_11 { + get { + object obj = ResourceManager.GetObject("Asterisk_Windows_11", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查詢類型 System.Drawing.Bitmap 的當地語系化資源。 + /// + internal static System.Drawing.Bitmap cancel_16 { + get { + object obj = ResourceManager.GetObject("cancel_16", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查詢類型 System.Drawing.Bitmap 的當地語系化資源。 + /// + internal static System.Drawing.Bitmap close_16 { + get { + object obj = ResourceManager.GetObject("close_16", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查詢類型 System.Drawing.Bitmap 的當地語系化資源。 + /// + internal static System.Drawing.Bitmap create_16 { + get { + object obj = ResourceManager.GetObject("create_16", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查詢類型 System.Drawing.Bitmap 的當地語系化資源。 + /// + internal static System.Drawing.Bitmap Critical_Windows_11 { + get { + object obj = ResourceManager.GetObject("Critical_Windows_11", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查詢類型 System.Drawing.Bitmap 的當地語系化資源。 + /// + internal static System.Drawing.Bitmap delete_16 { + get { + object obj = ResourceManager.GetObject("delete_16", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查詢類型 System.Drawing.Bitmap 的當地語系化資源。 + /// + internal static System.Drawing.Bitmap GenericAsterisk { + get { + object obj = ResourceManager.GetObject("GenericAsterisk", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查詢類型 System.Drawing.Bitmap 的當地語系化資源。 + /// + internal static System.Drawing.Bitmap GenericCritical { + get { + object obj = ResourceManager.GetObject("GenericCritical", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查詢類型 System.Drawing.Bitmap 的當地語系化資源。 + /// + internal static System.Drawing.Bitmap GenericHand { + get { + object obj = ResourceManager.GetObject("GenericHand", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查詢類型 System.Drawing.Bitmap 的當地語系化資源。 + /// + internal static System.Drawing.Bitmap GenericInformation { + get { + object obj = ResourceManager.GetObject("GenericInformation", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查詢類型 System.Drawing.Bitmap 的當地語系化資源。 + /// + internal static System.Drawing.Bitmap GenericQuestion { + get { + object obj = ResourceManager.GetObject("GenericQuestion", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查詢類型 System.Drawing.Bitmap 的當地語系化資源。 + /// + internal static System.Drawing.Bitmap GenericStop { + get { + object obj = ResourceManager.GetObject("GenericStop", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查詢類型 System.Drawing.Bitmap 的當地語系化資源。 + /// + internal static System.Drawing.Bitmap GenericWarning { + get { + object obj = ResourceManager.GetObject("GenericWarning", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查詢類型 System.Drawing.Bitmap 的當地語系化資源。 + /// + internal static System.Drawing.Bitmap Information_Windows_11 { + get { + object obj = ResourceManager.GetObject("Information_Windows_11", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查詢類型 System.Drawing.Bitmap 的當地語系化資源。 + /// + internal static System.Drawing.Bitmap MoveFirst { + get { + object obj = ResourceManager.GetObject("MoveFirst", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查詢類型 System.Drawing.Bitmap 的當地語系化資源。 + /// + internal static System.Drawing.Bitmap MoveFirst1 { + get { + object obj = ResourceManager.GetObject("MoveFirst1", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查詢類型 System.Drawing.Bitmap 的當地語系化資源。 + /// + internal static System.Drawing.Bitmap MoveLast { + get { + object obj = ResourceManager.GetObject("MoveLast", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查詢類型 System.Drawing.Bitmap 的當地語系化資源。 + /// + internal static System.Drawing.Bitmap MoveLast1 { + get { + object obj = ResourceManager.GetObject("MoveLast1", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查詢類型 System.Drawing.Bitmap 的當地語系化資源。 + /// + internal static System.Drawing.Bitmap MoveNext { + get { + object obj = ResourceManager.GetObject("MoveNext", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查詢類型 System.Drawing.Bitmap 的當地語系化資源。 + /// + internal static System.Drawing.Bitmap MovePrevious { + get { + object obj = ResourceManager.GetObject("MovePrevious", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查詢類型 System.Drawing.Bitmap 的當地語系化資源。 + /// + internal static System.Drawing.Bitmap ok_16 { + get { + object obj = ResourceManager.GetObject("ok_16", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查詢類型 System.Drawing.Bitmap 的當地語系化資源。 + /// + internal static System.Drawing.Bitmap print { + get { + object obj = ResourceManager.GetObject("print", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查詢類型 System.Drawing.Bitmap 的當地語系化資源。 + /// + internal static System.Drawing.Bitmap Question_Windows_11 { + get { + object obj = ResourceManager.GetObject("Question_Windows_11", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查詢類型 System.Drawing.Bitmap 的當地語系化資源。 + /// + internal static System.Drawing.Bitmap reset_16 { + get { + object obj = ResourceManager.GetObject("reset_16", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查詢類型 System.Drawing.Bitmap 的當地語系化資源。 + /// + internal static System.Drawing.Bitmap save_16 { + get { + object obj = ResourceManager.GetObject("save_16", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查詢類型 System.Drawing.Bitmap 的當地語系化資源。 + /// + internal static System.Drawing.Bitmap search_16 { + get { + object obj = ResourceManager.GetObject("search_16", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查詢類型 System.Drawing.Bitmap 的當地語系化資源。 + /// + internal static System.Drawing.Bitmap UAC_Shield_Windows_11 { + get { + object obj = ResourceManager.GetObject("UAC_Shield_Windows_11", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查詢類型 System.Drawing.Bitmap 的當地語系化資源。 + /// + internal static System.Drawing.Bitmap view_16 { + get { + object obj = ResourceManager.GetObject("view_16", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查詢類型 System.Drawing.Bitmap 的當地語系化資源。 + /// + internal static System.Drawing.Bitmap Warning_Windows_11 { + get { + object obj = ResourceManager.GetObject("Warning_Windows_11", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查詢類型 System.Drawing.Bitmap 的當地語系化資源。 + /// + internal static System.Drawing.Bitmap Windows11 { + get { + object obj = ResourceManager.GetObject("Windows11", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/CloudBuilder/CloudBuilder.Gui/Properties/Resources.resx b/CloudBuilder/CloudBuilder.Gui/Properties/Resources.resx new file mode 100644 index 0000000..be4b2aa --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/Properties/Resources.resx @@ -0,0 +1,214 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\cancel_16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Warning_Windows_11.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\GenericStop.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\search_16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\amend_16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\GenericQuestion.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\delete_16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Asterisk_Windows_11.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\view_16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\GenericInformation.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\MoveFirst.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Question_Windows_11.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\ok_16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\create_16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Information_Windows_11.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\close_16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Windows11.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\GenericAsterisk.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\GenericCritical.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\save_16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\MoveLast1.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\GenericHand.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\MoveLast.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\GenericWarning.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\MoveFirst1.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\MovePrevious.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Critical_Windows_11.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\UAC_Shield_Windows_11.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\MoveNext.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\reset_16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\print.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Gui/Resources/Asterisk_Windows_11.png b/CloudBuilder/CloudBuilder.Gui/Resources/Asterisk_Windows_11.png new file mode 100644 index 0000000..3b3eef8 Binary files /dev/null and b/CloudBuilder/CloudBuilder.Gui/Resources/Asterisk_Windows_11.png differ diff --git a/CloudBuilder/CloudBuilder.Gui/Resources/Critical_Windows_11.png b/CloudBuilder/CloudBuilder.Gui/Resources/Critical_Windows_11.png new file mode 100644 index 0000000..8594c98 Binary files /dev/null and b/CloudBuilder/CloudBuilder.Gui/Resources/Critical_Windows_11.png differ diff --git a/CloudBuilder/CloudBuilder.Gui/Resources/GenericAsterisk.png b/CloudBuilder/CloudBuilder.Gui/Resources/GenericAsterisk.png new file mode 100644 index 0000000..3f9111d Binary files /dev/null and b/CloudBuilder/CloudBuilder.Gui/Resources/GenericAsterisk.png differ diff --git a/CloudBuilder/CloudBuilder.Gui/Resources/GenericCritical.png b/CloudBuilder/CloudBuilder.Gui/Resources/GenericCritical.png new file mode 100644 index 0000000..bb86de3 Binary files /dev/null and b/CloudBuilder/CloudBuilder.Gui/Resources/GenericCritical.png differ diff --git a/CloudBuilder/CloudBuilder.Gui/Resources/GenericHand.png b/CloudBuilder/CloudBuilder.Gui/Resources/GenericHand.png new file mode 100644 index 0000000..6217dc8 Binary files /dev/null and b/CloudBuilder/CloudBuilder.Gui/Resources/GenericHand.png differ diff --git a/CloudBuilder/CloudBuilder.Gui/Resources/GenericInformation.png b/CloudBuilder/CloudBuilder.Gui/Resources/GenericInformation.png new file mode 100644 index 0000000..0403c3e Binary files /dev/null and b/CloudBuilder/CloudBuilder.Gui/Resources/GenericInformation.png differ diff --git a/CloudBuilder/CloudBuilder.Gui/Resources/GenericQuestion.png b/CloudBuilder/CloudBuilder.Gui/Resources/GenericQuestion.png new file mode 100644 index 0000000..9c5013a Binary files /dev/null and b/CloudBuilder/CloudBuilder.Gui/Resources/GenericQuestion.png differ diff --git a/CloudBuilder/CloudBuilder.Gui/Resources/GenericStop.png b/CloudBuilder/CloudBuilder.Gui/Resources/GenericStop.png new file mode 100644 index 0000000..8646c31 Binary files /dev/null and b/CloudBuilder/CloudBuilder.Gui/Resources/GenericStop.png differ diff --git a/CloudBuilder/CloudBuilder.Gui/Resources/GenericWarning.png b/CloudBuilder/CloudBuilder.Gui/Resources/GenericWarning.png new file mode 100644 index 0000000..d350bfe Binary files /dev/null and b/CloudBuilder/CloudBuilder.Gui/Resources/GenericWarning.png differ diff --git a/CloudBuilder/CloudBuilder.Gui/Resources/Information_Windows_11.png b/CloudBuilder/CloudBuilder.Gui/Resources/Information_Windows_11.png new file mode 100644 index 0000000..81074e4 Binary files /dev/null and b/CloudBuilder/CloudBuilder.Gui/Resources/Information_Windows_11.png differ diff --git a/CloudBuilder/CloudBuilder.Gui/Resources/MoveFirst.png b/CloudBuilder/CloudBuilder.Gui/Resources/MoveFirst.png new file mode 100644 index 0000000..46e0754 Binary files /dev/null and b/CloudBuilder/CloudBuilder.Gui/Resources/MoveFirst.png differ diff --git a/CloudBuilder/CloudBuilder.Gui/Resources/MoveFirst1.png b/CloudBuilder/CloudBuilder.Gui/Resources/MoveFirst1.png new file mode 100644 index 0000000..46e0754 Binary files /dev/null and b/CloudBuilder/CloudBuilder.Gui/Resources/MoveFirst1.png differ diff --git a/CloudBuilder/CloudBuilder.Gui/Resources/MoveLast.png b/CloudBuilder/CloudBuilder.Gui/Resources/MoveLast.png new file mode 100644 index 0000000..80b2a45 Binary files /dev/null and b/CloudBuilder/CloudBuilder.Gui/Resources/MoveLast.png differ diff --git a/CloudBuilder/CloudBuilder.Gui/Resources/MoveLast1.png b/CloudBuilder/CloudBuilder.Gui/Resources/MoveLast1.png new file mode 100644 index 0000000..80b2a45 Binary files /dev/null and b/CloudBuilder/CloudBuilder.Gui/Resources/MoveLast1.png differ diff --git a/CloudBuilder/CloudBuilder.Gui/Resources/MoveNext.png b/CloudBuilder/CloudBuilder.Gui/Resources/MoveNext.png new file mode 100644 index 0000000..5afeea1 Binary files /dev/null and b/CloudBuilder/CloudBuilder.Gui/Resources/MoveNext.png differ diff --git a/CloudBuilder/CloudBuilder.Gui/Resources/MovePrevious.png b/CloudBuilder/CloudBuilder.Gui/Resources/MovePrevious.png new file mode 100644 index 0000000..62ed1f3 Binary files /dev/null and b/CloudBuilder/CloudBuilder.Gui/Resources/MovePrevious.png differ diff --git a/CloudBuilder/CloudBuilder.Gui/Resources/Office2007ToolbarPrintPreviewNormal.png b/CloudBuilder/CloudBuilder.Gui/Resources/Office2007ToolbarPrintPreviewNormal.png new file mode 100644 index 0000000..5ad0882 Binary files /dev/null and b/CloudBuilder/CloudBuilder.Gui/Resources/Office2007ToolbarPrintPreviewNormal.png differ diff --git a/CloudBuilder/CloudBuilder.Gui/Resources/Office2007ToolbarRedoNormal.png b/CloudBuilder/CloudBuilder.Gui/Resources/Office2007ToolbarRedoNormal.png new file mode 100644 index 0000000..59bb57f Binary files /dev/null and b/CloudBuilder/CloudBuilder.Gui/Resources/Office2007ToolbarRedoNormal.png differ diff --git a/CloudBuilder/CloudBuilder.Gui/Resources/Question_Windows_11.png b/CloudBuilder/CloudBuilder.Gui/Resources/Question_Windows_11.png new file mode 100644 index 0000000..b843e3c Binary files /dev/null and b/CloudBuilder/CloudBuilder.Gui/Resources/Question_Windows_11.png differ diff --git a/CloudBuilder/CloudBuilder.Gui/Resources/UAC_Shield_Windows_11.png b/CloudBuilder/CloudBuilder.Gui/Resources/UAC_Shield_Windows_11.png new file mode 100644 index 0000000..c404596 Binary files /dev/null and b/CloudBuilder/CloudBuilder.Gui/Resources/UAC_Shield_Windows_11.png differ diff --git a/CloudBuilder/CloudBuilder.Gui/Resources/Warning_Windows_11.png b/CloudBuilder/CloudBuilder.Gui/Resources/Warning_Windows_11.png new file mode 100644 index 0000000..290b45b Binary files /dev/null and b/CloudBuilder/CloudBuilder.Gui/Resources/Warning_Windows_11.png differ diff --git a/CloudBuilder/CloudBuilder.Gui/Resources/Windows11.png b/CloudBuilder/CloudBuilder.Gui/Resources/Windows11.png new file mode 100644 index 0000000..a13b4cb Binary files /dev/null and b/CloudBuilder/CloudBuilder.Gui/Resources/Windows11.png differ diff --git a/CloudBuilder/CloudBuilder.Gui/Resources/amend_16.png b/CloudBuilder/CloudBuilder.Gui/Resources/amend_16.png new file mode 100644 index 0000000..95dabb1 Binary files /dev/null and b/CloudBuilder/CloudBuilder.Gui/Resources/amend_16.png differ diff --git a/CloudBuilder/CloudBuilder.Gui/Resources/cancel_16.png b/CloudBuilder/CloudBuilder.Gui/Resources/cancel_16.png new file mode 100644 index 0000000..0da8729 Binary files /dev/null and b/CloudBuilder/CloudBuilder.Gui/Resources/cancel_16.png differ diff --git a/CloudBuilder/CloudBuilder.Gui/Resources/close_16.png b/CloudBuilder/CloudBuilder.Gui/Resources/close_16.png new file mode 100644 index 0000000..349423f Binary files /dev/null and b/CloudBuilder/CloudBuilder.Gui/Resources/close_16.png differ diff --git a/CloudBuilder/CloudBuilder.Gui/Resources/create_16.png b/CloudBuilder/CloudBuilder.Gui/Resources/create_16.png new file mode 100644 index 0000000..18365cf Binary files /dev/null and b/CloudBuilder/CloudBuilder.Gui/Resources/create_16.png differ diff --git a/CloudBuilder/CloudBuilder.Gui/Resources/delete_16.png b/CloudBuilder/CloudBuilder.Gui/Resources/delete_16.png new file mode 100644 index 0000000..0b4a3bc Binary files /dev/null and b/CloudBuilder/CloudBuilder.Gui/Resources/delete_16.png differ diff --git a/CloudBuilder/CloudBuilder.Gui/Resources/ok_16.png b/CloudBuilder/CloudBuilder.Gui/Resources/ok_16.png new file mode 100644 index 0000000..47dc49d Binary files /dev/null and b/CloudBuilder/CloudBuilder.Gui/Resources/ok_16.png differ diff --git a/CloudBuilder/CloudBuilder.Gui/Resources/print.png b/CloudBuilder/CloudBuilder.Gui/Resources/print.png new file mode 100644 index 0000000..902217c Binary files /dev/null and b/CloudBuilder/CloudBuilder.Gui/Resources/print.png differ diff --git a/CloudBuilder/CloudBuilder.Gui/Resources/reset_16.png b/CloudBuilder/CloudBuilder.Gui/Resources/reset_16.png new file mode 100644 index 0000000..ceb83b0 Binary files /dev/null and b/CloudBuilder/CloudBuilder.Gui/Resources/reset_16.png differ diff --git a/CloudBuilder/CloudBuilder.Gui/Resources/save_16.png b/CloudBuilder/CloudBuilder.Gui/Resources/save_16.png new file mode 100644 index 0000000..f9d9eab Binary files /dev/null and b/CloudBuilder/CloudBuilder.Gui/Resources/save_16.png differ diff --git a/CloudBuilder/CloudBuilder.Gui/Resources/search_16.png b/CloudBuilder/CloudBuilder.Gui/Resources/search_16.png new file mode 100644 index 0000000..1a77c32 Binary files /dev/null and b/CloudBuilder/CloudBuilder.Gui/Resources/search_16.png differ diff --git a/CloudBuilder/CloudBuilder.Gui/Resources/view_16.png b/CloudBuilder/CloudBuilder.Gui/Resources/view_16.png new file mode 100644 index 0000000..49f50e2 Binary files /dev/null and b/CloudBuilder/CloudBuilder.Gui/Resources/view_16.png differ diff --git a/CloudBuilder/CloudBuilder.Gui/ShowMessageBox.cs b/CloudBuilder/CloudBuilder.Gui/ShowMessageBox.cs new file mode 100644 index 0000000..f0cd99a --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/ShowMessageBox.cs @@ -0,0 +1,125 @@ +using CloudBuilder.Gui.DependencyInjection; +using CloudBuilder.Gui.Policy; +using DocumentFormat.OpenXml.Vml.Spreadsheet; +using Krypton.Toolkit; +using Microsoft.AspNetCore.Mvc.ApplicationParts; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Diagnostics; +using System.Drawing; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Gui +{ + public class ShowMessageBox + { + public static void ShowError(string msg, string caption) + { + ShowCore(msg, caption, KryptonMessageBoxButtons.OK, KryptonMessageBoxIcon.Error, KryptonMessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly); + } + + public static void ShowError(string msg) + { + ShowCore(msg, GeneralToolkitStringsPolicy.GetInstance().ComposeMessage(GeneralToolkitStringsPolicy.GUI_CAPTION_ERROR), KryptonMessageBoxButtons.OK, KryptonMessageBoxIcon.Error, KryptonMessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly); + } + + public static void ShowError(Exception ex) + { + string msg = ex.Message; + if (ex.InnerException != null) msg += "\r\n" + ex.InnerException.Message; + + ShowCore(msg, GeneralToolkitStringsPolicy.GetInstance().ComposeMessage(GeneralToolkitStringsPolicy.GUI_CAPTION_ERROR), KryptonMessageBoxButtons.OK, KryptonMessageBoxIcon.Error, KryptonMessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly); + } + + public static void ShowError(Exception ex, string caption) + { + string msg = ex.Message; + if (ex.InnerException != null) msg += "\r\n" + ex.InnerException.Message; + + ShowCore(msg, caption, KryptonMessageBoxButtons.OK, KryptonMessageBoxIcon.Error, KryptonMessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly); + } + + public static void ShowInfo(ValidationException validation) + { + string msg = validation.Message; + + ShowCore(msg, GeneralToolkitStringsPolicy.GetInstance().ComposeMessage(GeneralToolkitStringsPolicy.GUI_CAPTION_INFORMATION), KryptonMessageBoxButtons.OK, KryptonMessageBoxIcon.Information, KryptonMessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly); + } + + public static void ShowInfo(string msg, Control ct) + { + ShowCore(msg, GeneralToolkitStringsPolicy.GetInstance().ComposeMessage(GeneralToolkitStringsPolicy.GUI_CAPTION_INFORMATION), KryptonMessageBoxButtons.OK, KryptonMessageBoxIcon.Information, KryptonMessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly); + + if (ct != null) ct.Focus(); + } + + public static void ShowInfo(string msg) + { + ShowCore(msg, GeneralToolkitStringsPolicy.GetInstance().ComposeMessage(GeneralToolkitStringsPolicy.GUI_CAPTION_INFORMATION), KryptonMessageBoxButtons.OK, KryptonMessageBoxIcon.Information, KryptonMessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly); + } + + public static void ShowInfo(string msg, string caption) + { + ShowCore(msg, GeneralToolkitStringsPolicy.GetInstance().ComposeMessage(GeneralToolkitStringsPolicy.GUI_CAPTION_INFORMATION), KryptonMessageBoxButtons.OK, KryptonMessageBoxIcon.Information, KryptonMessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly); + } + + public static DialogResult ShowOption(string msg, string caption, KryptonMessageBoxButtons buttons, KryptonMessageBoxIcon icon, KryptonMessageBoxDefaultButton defaultButton) + { + if (string.IsNullOrEmpty(caption)) caption = GeneralToolkitStringsPolicy.GetInstance().ComposeMessage(GeneralToolkitStringsPolicy.GUI_CAPTION_INFORMATION); + + return ShowCore(msg, caption, buttons, icon, defaultButton, MessageBoxOptions.DefaultDesktopOnly); + } + + public static DialogResult ShowOption(string msg, string caption) + { + if (string.IsNullOrEmpty(caption)) caption = GeneralToolkitStringsPolicy.GetInstance().ComposeMessage(GeneralToolkitStringsPolicy.GUI_CAPTION_INFORMATION); + + return ShowCore(msg, caption, KryptonMessageBoxButtons.YesNo, KryptonMessageBoxIcon.Question, KryptonMessageBoxDefaultButton.Button2, MessageBoxOptions.DefaultDesktopOnly); + } + + + private static DialogResult ShowCore(string text, string caption, KryptonMessageBoxButtons buttons, KryptonMessageBoxIcon icon, KryptonMessageBoxDefaultButton defaultButton, MessageBoxOptions options, HelpInfo? helpInfo = null!, bool? showCtrlCopy = false, bool? showHelpButton = false, bool? showActionButton = false, string? actionButtonText = null!, KryptonCommand? actionButtonCommand = null!, Image? applicationImage = null!, string? applicationPath = null!, MessageBoxContentAreaType? contentAreaType = null!, KryptonCommand? linkLabelCommand = null!, ProcessStartInfo? linkLaunchArgument = null!, LinkArea? contentLinkArea = null!) + { + IWin32Window? owner = null!; + caption = (string.IsNullOrEmpty(caption) ? " " : caption); + IWin32Window win32Window = ValidateOptions(owner, options, helpInfo); + using KryptonMessageBoxForm kryptonMessageBoxForm = new KryptonMessageBoxForm(win32Window, text, caption, buttons, icon, defaultButton, options, helpInfo, showCtrlCopy, showHelpButton, showActionButton, actionButtonText, actionButtonCommand, applicationImage, applicationPath, contentAreaType, linkLabelCommand, linkLaunchArgument, contentLinkArea); + kryptonMessageBoxForm.StartPosition = ((win32Window == null) ? FormStartPosition.CenterScreen : FormStartPosition.CenterParent); + return kryptonMessageBoxForm.ShowDialog(win32Window); + } + + private static IWin32Window? ValidateOptions(IWin32Window? owner, MessageBoxOptions options, HelpInfo? helpInfo) + { + if (!SystemInformation.UserInteractive && (options & (MessageBoxOptions.ServiceNotification | MessageBoxOptions.DefaultDesktopOnly)) == 0) + { + throw new InvalidOperationException("Cannot show modal dialog when non-interactive"); + } + + if (owner != null && (options & (MessageBoxOptions.ServiceNotification | MessageBoxOptions.DefaultDesktopOnly)) != 0) + { + throw new ArgumentException("Cannot show message box from a service with an owner specified", "options"); + } + + if (helpInfo != null && (options & (MessageBoxOptions.ServiceNotification | MessageBoxOptions.DefaultDesktopOnly)) != 0) + { + throw new ArgumentException("Cannot show message box from a service with help specified", "options"); + } + + IWin32Window result = null; + if (helpInfo != null || (options & (MessageBoxOptions.ServiceNotification | MessageBoxOptions.DefaultDesktopOnly)) == 0) + { + result = owner ?? Control.FromHandle(GetActiveWindow()); + } + + return result; + } + + [DllImport("user32.dll", CharSet = CharSet.Auto)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + internal static extern nint GetActiveWindow(); + } +} diff --git a/CloudBuilder/CloudBuilder.Gui/UserPreferenceData.cs b/CloudBuilder/CloudBuilder.Gui/UserPreferenceData.cs new file mode 100644 index 0000000..ca5cfab --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/UserPreferenceData.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Gui +{ + public class UserPreferenceData + { + public string Username { get; set; } + public string PreferenceKey { get; set; } + public string Preference { get; set; } + } +} diff --git a/CloudBuilder/CloudBuilder.Gui/kryptonCheckedListBoxExtensions.cs b/CloudBuilder/CloudBuilder.Gui/kryptonCheckedListBoxExtensions.cs new file mode 100644 index 0000000..210c19a --- /dev/null +++ b/CloudBuilder/CloudBuilder.Gui/kryptonCheckedListBoxExtensions.cs @@ -0,0 +1,202 @@ +using CloudBuilder; +using CloudBuilder.Gui; +using CloudBuilder.Gui.DependencyInjection; +using Krypton.Toolkit; +using Microsoft.AspNetCore.Authorization; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace Krypton.Toolkit +{ + public static class kryptonCheckedListBoxExtensions + { + + public static ExFormSnapshotEntry GetExFormSnapshotEntry(this KryptonCheckedListBox kryptonCheckedListBox) + { + string bindDataName = null; + + if (GetProvider().GetCustomAttribute(kryptonCheckedListBox) != null) + bindDataName = GetProvider().GetCustomAttribute(kryptonCheckedListBox).BindDataName; + + return new ExFormSnapshotEntry( + kryptonCheckedListBox.Name, + bindDataName, + kryptonCheckedListBox.GetCheckedItemValue(), + kryptonCheckedListBox.Text); + } + + public static void Set(this KryptonCheckedListBox kryptonCheckedListBox, + BindingContextCustomAttribute bindingContext) + { + GetProvider().SetCustomAttribute(kryptonCheckedListBox, bindingContext); + } + + public static void Set(this KryptonCheckedListBox kryptonCheckedListBox, + EnumEditModeColor editModeColor) + { + GetProvider().SetCustomAttribute(kryptonCheckedListBox, editModeColor); + } + + public static void Set(this KryptonCheckedListBox kryptonCheckedListBox, + string bindDataName, + EnumEditModeColor editModeColor) + { + GetProvider().SetCustomAttribute(kryptonCheckedListBox, bindDataName, editModeColor); + } + + public static void Set(this KryptonCheckedListBox kryptonCheckedListBox, + string bindDataName) + { + GetProvider().SetCustomAttribute(kryptonCheckedListBox, bindDataName, EnumBindDirection.Both); + } + + public static void Set(this KryptonCheckedListBox kryptonCheckedListBox, + string bindDataName, + EnumBindDirection bindDirection) + { + GetProvider().SetCustomAttribute(kryptonCheckedListBox, bindDataName, bindDirection); + } + + + public static void Set(this KryptonCheckedListBox kryptonCheckedListBox, + string bindDataName, + EnumBindDirection bindDirection, + EnumEditModeColor editModeColor) + { + GetProvider().SetCustomAttribute(kryptonCheckedListBox, bindDataName, bindDirection, editModeColor); + } + + public static void Set(this KryptonCheckedListBox kryptonCheckedListBox, + string bindDataName, + string bindFormat, + EnumBindDirection bindDirection) + { + GetProvider().SetCustomAttribute(kryptonCheckedListBox, bindDataName, bindFormat, bindDirection); + } + + public static void Set(this KryptonCheckedListBox kryptonCheckedListBox, + string permissionName, + Operate permissionMode) + { + GetProvider().SetCustomAttribute(kryptonCheckedListBox, permissionName, permissionMode); + } + + public static void Set(this KryptonCheckedListBox kryptonCheckedListBox, string permissionName, string dependentDetailName, Operate permissionMode) + { + GetProvider().SetCustomAttribute(kryptonCheckedListBox, permissionName, dependentDetailName, permissionMode); + } + + public static void Set(this KryptonCheckedListBox kryptonCheckedListBox, string permissionName, string dependentDetailName) + { + GetProvider().SetCustomAttribute(kryptonCheckedListBox, permissionName, dependentDetailName); + } + + public static string[] GetCheckedItemText(this KryptonCheckedListBox kryptonCheckedListBox) + { + List l = new List(); + for (int i = 0; i < kryptonCheckedListBox.Items.Count; i++) + { + if (kryptonCheckedListBox.GetItemCheckState(i) == CheckState.Checked) + { + l.Add(((KryptonListItem)kryptonCheckedListBox.Items[i]).ShortText); + } + } + return l.ToArray(); + } + + public static string[] GetUnCheckedItemText(this KryptonCheckedListBox kryptonCheckedListBox) + { + List l = new List(); + for (int i = 0; i < kryptonCheckedListBox.Items.Count; i++) + { + if (kryptonCheckedListBox.GetItemCheckState(i) == CheckState.Unchecked) + { + l.Add(((KryptonListItem)kryptonCheckedListBox.Items[i]).ShortText); + } + } + return l.ToArray(); + } + + public static T[] GetCheckedItemValue(this KryptonCheckedListBox kryptonCheckedListBox) + { + List l = new List(); + for (int i = 0; i < kryptonCheckedListBox.Items.Count; i++) + { + if (kryptonCheckedListBox.GetItemCheckState(i) == CheckState.Checked) + { + l.Add((T)((Dictionary)((KryptonListItem)kryptonCheckedListBox.Items[i]).Tag)[i]); + } + } + return l.ToArray(); + } + + public static T[] GetUnCheckedItemValue(this KryptonCheckedListBox kryptonCheckedListBox) + { + List l = new List(); + for (int i = 0; i < kryptonCheckedListBox.Items.Count; i++) + { + if (kryptonCheckedListBox.GetItemCheckState(i) == CheckState.Unchecked) + { + l.Add((T)((Dictionary)((KryptonListItem)kryptonCheckedListBox.Items[i]).Tag)[i]); + } + } + return l.ToArray(); + } + + public static void SetValue(this KryptonCheckedListBox kryptonCheckedListBox, string[] ts) + { + SetCheckedValue(kryptonCheckedListBox, ts); + } + + public static void Reset(this KryptonCheckedListBox kryptonCheckedListBox) + { + for (int i = 0; i < kryptonCheckedListBox.Items.Count; i++) + { + kryptonCheckedListBox.SetItemCheckState(i, CheckState.Unchecked); + } + } + + public static void SetCheckedValue(this KryptonCheckedListBox kryptonCheckedListBox, object[] ts) + { + + for (int i = 0; i < kryptonCheckedListBox.Items.Count; i++) + { + kryptonCheckedListBox.SetItemCheckState(i, CheckState.Unchecked); + if (ts == null || ts.Length == 0) continue; + + foreach (object t in ts) + { + if (((Dictionary)((KryptonListItem)kryptonCheckedListBox.Items[i]).Tag)[i].ToString() == t.ToString()) + { + kryptonCheckedListBox.SetItemCheckState(i, CheckState.Checked); + } + } + } + } + + public static void SetDataSource(this KryptonCheckedListBox kryptonCheckedListBox, T[] dataSource, string displayName, string valueName) + { + if (dataSource == null || dataSource.Length == 0) return; + KryptonListItem[] items = KryptonListItemConvertor.ToKryptonListItem(dataSource, displayName, valueName); + kryptonCheckedListBox.Items.AddRange(items); + } + + public static BindingContextCustomAttribute GetCustomAttribute(this KryptonCheckedListBox kryptonCheckedListBox) + { + return GetProvider().GetCustomAttribute(kryptonCheckedListBox); + } + + private static BindingContextAttributeProvider GetProvider() + { + return ServiceHelper.GetService() ?? + throw new InvalidOperationException("BindingContextAttributeProvider is not registered in the service GetProvider()."); + } + } +} + + diff --git a/CloudBuilder/CloudBuilder.Request/AI/AiBookRequest.auto.cs b/CloudBuilder/CloudBuilder.Request/AI/AiBookRequest.auto.cs new file mode 100644 index 0000000..32d6a43 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Request/AI/AiBookRequest.auto.cs @@ -0,0 +1,87 @@ + +using CloudBuilder.Core.DependencyInjection.Request; +using CloudBuilder.Core.Request; +using CloudBuilder.Core.Service; +using Microsoft.Extensions.DependencyInjection; +using CloudBuilder.AI.Service; + using CloudBuilder.Core.DatabaseAccessor.Entity; + using CloudBuilder.AI.Data; + using System; + using CloudBuilder.AI.Entity; + using CloudBuilder.AI.SearchCriteria; + using Microsoft.AspNetCore.Mvc; + +namespace CloudBuilder.Request.AI +{ + +public class AiBookRequest : IRequest +{ + +private readonly IServiceRequest serviceRequest; +public AiBookRequest(IServiceRequest serviceRequest) +{ +this.serviceRequest = serviceRequest; +} + + public AiBookData FindByKey(string key) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/AiBook/FindByKey?key=" + key.ToString())).GetAwaiter().GetResult(); } + + public AiBookEntity FindByTitle(string title) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/AiBook/FindByTitle?title=" + title.ToString())).GetAwaiter().GetResult(); } + + public AiBookResultData FindBySearchCriteria(AiBookSearchCriteria criteria) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/AiBook/FindBySearchCriteria" , criteria)).GetAwaiter().GetResult(); } + + public AiBookData Insert(AiBookData data) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/AiBook/Insert" , data)).GetAwaiter().GetResult(); } + + public AiBookData Update(AiBookData data) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/AiBook/Update" , data)).GetAwaiter().GetResult(); } + + public void Delete(string key) + { + Task.Run(() => serviceRequest.PostAsync("/AiBook/Delete?key=" + key.ToString())).GetAwaiter().GetResult(); } + + public void Deletes(string[] keys) + { + Task.Run(() => serviceRequest.PostAsJsonAsync("/AiBook/Deletes" , keys)).GetAwaiter().GetResult(); } + + + public class ProcessBookCompositionData3 { + public string key { get; set; } + public string encoding { get; set; } + public string pattern { get; set; } + + } + public AiBookData ProcessBook(string key, string encoding, string pattern) + { +var compositionData = new ProcessBookCompositionData3{ key = key, encoding = encoding, pattern = pattern }; return Task.Run(() => serviceRequest.PostAsJsonAsync("/AiBook/ProcessBook", compositionData)).GetAwaiter().GetResult(); } + + public IActionResult GetMp3Stream(AiSentenceViewEntity aiSentence) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/AiBook/GetMp3Stream" , aiSentence)).GetAwaiter().GetResult(); } + + public void GenerateMp3(AiChapterEntity[] chapters) + { + Task.Run(() => serviceRequest.PostAsJsonAsync("/AiBook/GenerateMp3" , chapters)).GetAwaiter().GetResult(); } + + public void GenerateMp3ByBookId(string bookId) + { + Task.Run(() => serviceRequest.PostAsync("/AiBook/GenerateMp3ByBookId?bookId=" + bookId.ToString())).GetAwaiter().GetResult(); } + + public void PackPersonNameByBookId(string bookId) + { + Task.Run(() => serviceRequest.PostAsync("/AiBook/PackPersonNameByBookId?bookId=" + bookId.ToString())).GetAwaiter().GetResult(); } + + public void PackPersonName(AiChapterEntity[] chapters) + { + Task.Run(() => serviceRequest.PostAsJsonAsync("/AiBook/PackPersonName" , chapters)).GetAwaiter().GetResult(); } + + +} +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Request/AI/AiChapterRequest.auto.cs b/CloudBuilder/CloudBuilder.Request/AI/AiChapterRequest.auto.cs new file mode 100644 index 0000000..93b6109 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Request/AI/AiChapterRequest.auto.cs @@ -0,0 +1,49 @@ + +using CloudBuilder.Core.DependencyInjection.Request; +using CloudBuilder.Core.Request; +using CloudBuilder.Core.Service; +using Microsoft.Extensions.DependencyInjection; +using CloudBuilder.AI.Service; + using CloudBuilder.Core.DatabaseAccessor.Entity; + using CloudBuilder.AI.Data; + using System; + using CloudBuilder.AI.Entity; + using CloudBuilder.AI.SearchCriteria; + using Microsoft.AspNetCore.Mvc; + using CloudBuilder.AI; + +namespace CloudBuilder.Request.AI +{ + +public class AiChapterRequest : IRequest +{ + +private readonly IServiceRequest serviceRequest; +public AiChapterRequest(IServiceRequest serviceRequest) +{ +this.serviceRequest = serviceRequest; +} + + public AiChapterEntity FindByKey(AiChapterEntityKey key) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/AiChapter/FindByKey" , key)).GetAwaiter().GetResult(); } + + public AiChapterResultData FindBySearchCriteria(AiChapterSearchCriteria criteria) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/AiChapter/FindBySearchCriteria" , criteria)).GetAwaiter().GetResult(); } + + public AiChapterEntity Insert(AiChapterEntity data) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/AiChapter/Insert" , data)).GetAwaiter().GetResult(); } + + public AiChapterEntity Update(AiChapterEntity data) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/AiChapter/Update" , data)).GetAwaiter().GetResult(); } + + public void Delete(AiChapterEntityKey key) + { + Task.Run(() => serviceRequest.PostAsJsonAsync("/AiChapter/Delete" , key)).GetAwaiter().GetResult(); } + + +} +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Request/AI/AiSentenceRequest.auto.cs b/CloudBuilder/CloudBuilder.Request/AI/AiSentenceRequest.auto.cs new file mode 100644 index 0000000..4ef66a3 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Request/AI/AiSentenceRequest.auto.cs @@ -0,0 +1,63 @@ + +using CloudBuilder.Core.DependencyInjection.Request; +using CloudBuilder.Core.Request; +using CloudBuilder.Core.Service; +using Microsoft.Extensions.DependencyInjection; +using CloudBuilder.AI.Service; + using CloudBuilder.Core.DatabaseAccessor.Entity; + using CloudBuilder.AI.Data; + using System; + using CloudBuilder.AI.Entity; + using CloudBuilder.AI.SearchCriteria; + using Microsoft.AspNetCore.Mvc; + using CloudBuilder.AI; + +namespace CloudBuilder.Request.AI +{ + +public class AiSentenceRequest : IRequest +{ + +private readonly IServiceRequest serviceRequest; +public AiSentenceRequest(IServiceRequest serviceRequest) +{ +this.serviceRequest = serviceRequest; +} + + public AiSentenceEntity FindByKey(Int64 key) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/AiSentence/FindByKey?key=" + key.ToString())).GetAwaiter().GetResult(); } + + + public class FindByChapterIdCompositionData2 { + public string bookId { get; set; } + public Int64 chapterId { get; set; } + + } + public AiSentenceViewEntity[] FindByChapterId(string bookId, Int64 chapterId) + { +var compositionData = new FindByChapterIdCompositionData2{ bookId = bookId, chapterId = chapterId }; return Task.Run(() => serviceRequest.PostAsJsonAsync("/AiSentence/FindByChapterId", compositionData)).GetAwaiter().GetResult(); } + + public AiSentenceViewResultData FindBySearchCriteria(AiSentenceSearchCriteria criteria) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/AiSentence/FindBySearchCriteria" , criteria)).GetAwaiter().GetResult(); } + + public AiSentenceEntity Insert(AiSentenceEntity data) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/AiSentence/Insert" , data)).GetAwaiter().GetResult(); } + + public void Inserts(AiSentenceEntity[] datas) + { + Task.Run(() => serviceRequest.PostAsJsonAsync("/AiSentence/Inserts" , datas)).GetAwaiter().GetResult(); } + + public AiSentenceEntity Update(AiSentenceEntity data) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/AiSentence/Update" , data)).GetAwaiter().GetResult(); } + + public void Delete(Int64 key) + { + Task.Run(() => serviceRequest.PostAsync("/AiSentence/Delete?key=" + key.ToString())).GetAwaiter().GetResult(); } + + +} +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Request/AI/DmsFileRequest.auto.cs b/CloudBuilder/CloudBuilder.Request/AI/DmsFileRequest.auto.cs new file mode 100644 index 0000000..6c970a9 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Request/AI/DmsFileRequest.auto.cs @@ -0,0 +1,106 @@ + +using CloudBuilder.Core.DependencyInjection.Request; +using CloudBuilder.Core.Request; +using CloudBuilder.Core.Service; +using Microsoft.Extensions.DependencyInjection; +using CloudBuilder.AI.Service; + using CloudBuilder.Core.DatabaseAccessor.Entity; + using CloudBuilder.AI.Data; + using System; + using CloudBuilder.AI.Entity; + using CloudBuilder.AI.SearchCriteria; + using Microsoft.AspNetCore.Mvc; + using CloudBuilder.AI; + using Microsoft.AspNetCore.Http; + +namespace CloudBuilder.Request.AI +{ + +public class DmsFileRequest : IRequest +{ + +private readonly IServiceRequest serviceRequest; +public DmsFileRequest(IServiceRequest serviceRequest) +{ +this.serviceRequest = serviceRequest; +} + + public DmsFileEntity FindByKey(Int32 key) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/DmsFile/FindByKey?key=" + key.ToString())).GetAwaiter().GetResult(); } + + public DmsFileResultData FindBySearchCriteria(DmsFileSearchCriteria criteria) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/DmsFile/FindBySearchCriteria" , criteria)).GetAwaiter().GetResult(); } + + public DmsFileResultData FindDatasBySearchCriteria(DmsFileSearchCriteria criteria) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/DmsFile/FindDatasBySearchCriteria" , criteria)).GetAwaiter().GetResult(); } + + public dynamic PrintBySearchCriteria(DmsFileSearchCriteria criteria) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/DmsFile/PrintBySearchCriteria" , criteria)).GetAwaiter().GetResult(); } + + public DmsFileEntity Insert(DmsFileEntity data) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/DmsFile/Insert" , data)).GetAwaiter().GetResult(); } + + public DmsFileEntity Update(DmsFileEntity data) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/DmsFile/Update" , data)).GetAwaiter().GetResult(); } + + public void Delete(Int32 key) + { + Task.Run(() => serviceRequest.PostAsync("/DmsFile/Delete?key=" + key.ToString())).GetAwaiter().GetResult(); } + + public string GetFolderName(string folderLocalName) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/DmsFile/GetFolderName?folderLocalName=" + folderLocalName.ToString())).GetAwaiter().GetResult(); } + + public string CreateDmsFolder(DmsFileEntity dmsFile) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/DmsFile/CreateDmsFolder" , dmsFile)).GetAwaiter().GetResult(); } + + public DmsFileEntity UpdateDmsFolder(DmsFileEntity dmsFile) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/DmsFile/UpdateDmsFolder" , dmsFile)).GetAwaiter().GetResult(); } + + public SelectOption[] FindDmsFolders() + { +return Task.Run(() => serviceRequest.PostAsJsonAsync ("/DmsFile/FindDmsFolders")).GetAwaiter().GetResult(); } + + public DmsFolderTreeData FindDmsFolderTreeData() + { +return Task.Run(() => serviceRequest.PostAsJsonAsync ("/DmsFile/FindDmsFolderTreeData")).GetAwaiter().GetResult(); } + + public void MoveDmsFolder(DmsFileEntity dmsFile) + { + Task.Run(() => serviceRequest.PostAsJsonAsync("/DmsFile/MoveDmsFolder" , dmsFile)).GetAwaiter().GetResult(); } + + public BookDmsFileViewEntity UploadFile() + { +return Task.Run(() => serviceRequest.PostAsJsonAsync ("/DmsFile/UploadFile")).GetAwaiter().GetResult(); } + + public dynamic DownloadFile(Int32 fileId) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/DmsFile/DownloadFile?fileId=" + fileId.ToString())).GetAwaiter().GetResult(); } + + public dynamic DownloadFilePreview(DmsFileEntity dmsFile) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/DmsFile/DownloadFilePreview" , dmsFile)).GetAwaiter().GetResult(); } + + public dynamic DownloadFileCombine(string fileName) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/DmsFile/DownloadFileCombine?fileName=" + fileName.ToString())).GetAwaiter().GetResult(); } + + public Int32 FindDmsFolderMapByFolderName(string folderName) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/DmsFile/FindDmsFolderMapByFolderName?folderName=" + folderName.ToString())).GetAwaiter().GetResult(); } + + public string FindFolderNameParentByFolderName(string folderName) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/DmsFile/FindFolderNameParentByFolderName?folderName=" + folderName.ToString())).GetAwaiter().GetResult(); } + + +} +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Request/CloudBuilder.Request.csproj b/CloudBuilder/CloudBuilder.Request/CloudBuilder.Request.csproj new file mode 100644 index 0000000..b4335ae --- /dev/null +++ b/CloudBuilder/CloudBuilder.Request/CloudBuilder.Request.csproj @@ -0,0 +1,42 @@ + + + + net8.0 + enable + enable + + + + + ..\CloudBuilder.AI\bin\Debug\net8.0\CloudBuilder.AI.dll + + + ..\CloudBuilder.Core\bin\Debug\net8.0\CloudBuilder.Core.dll + + + ..\CloudBuilder.Security\bin\Debug\net8.0\CloudBuilder.Security.dll + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CloudBuilder/CloudBuilder.Request/Security/AuthRequest.auto.cs b/CloudBuilder/CloudBuilder.Request/Security/AuthRequest.auto.cs new file mode 100644 index 0000000..09235c5 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Request/Security/AuthRequest.auto.cs @@ -0,0 +1,81 @@ + +using CloudBuilder.Core.DependencyInjection.Request; +using CloudBuilder.Core.Request; +using CloudBuilder.Core.Service; +using Microsoft.Extensions.DependencyInjection; +using CloudBuilder.Security.Service; + using CloudBuilder.Core.DatabaseAccessor.Entity; + using Microsoft.AspNetCore.Http; + using CloudBuilder.Core.Policy; + using CloudBuilder.Core.DependencyInjection.Request; + using CloudBuilder.Security.Data; + using CloudBuilder.Core.Authorization; + using System; + +namespace CloudBuilder.Request.Security +{ + +public class AuthRequest : IRequest +{ + +private readonly IServiceRequest serviceRequest; +public AuthRequest(IServiceRequest serviceRequest) +{ +this.serviceRequest = serviceRequest; +} + + public LoginProfile Login(LoginData data) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/Auth/Login" , data)).GetAwaiter().GetResult(); } + + public LoginProfile LoginAgent(LoginData data) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/Auth/LoginAgent" , data)).GetAwaiter().GetResult(); } + + public string Register(RegisterData data) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/Auth/Register" , data)).GetAwaiter().GetResult(); } + + public LoginProfile AmendPassword(LoginData data) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/Auth/AmendPassword" , data)).GetAwaiter().GetResult(); } + + public string GetRsaPublicKey() + { +return Task.Run(() => serviceRequest.GetAsync("/Auth/GetRsaPublicKey")).GetAwaiter().GetResult(); } + + public JwtInfo RefreshToken(JwtInfo jwtInfo) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/Auth/RefreshToken" , jwtInfo)).GetAwaiter().GetResult(); } + + public void Logout() + { + Task.Run(() => serviceRequest.PostAsync("/Auth/Logout")).GetAwaiter().GetResult(); } + + public bool ConfirmPassword(string password) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/Auth/ConfirmPassword?password=" + password.ToString())).GetAwaiter().GetResult(); } + + public string BeginBiometricRegistration(string deviceName) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/Auth/BeginBiometricRegistration?deviceName=" + deviceName.ToString())).GetAwaiter().GetResult(); } + + public BiometricRegistrationResultDto FinishBiometricRegistration(FinishBiometricRegistrationData dto) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/Auth/FinishBiometricRegistration" , dto)).GetAwaiter().GetResult(); } + + public BiometricLoginChallengeDto BeginBiometricLogin(string username) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/Auth/BeginBiometricLogin?username=" + username.ToString())).GetAwaiter().GetResult(); } + + public LoginProfile FinishBiometricLogin(FinishBiometricLoginData dto) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/Auth/FinishBiometricLogin" , dto)).GetAwaiter().GetResult(); } + + public void RemoveBiometric() + { + Task.Run(() => serviceRequest.PostAsync("/Auth/RemoveBiometric")).GetAwaiter().GetResult(); } + + +} +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Request/Security/LocaleRequest.auto.cs b/CloudBuilder/CloudBuilder.Request/Security/LocaleRequest.auto.cs new file mode 100644 index 0000000..fac21cf --- /dev/null +++ b/CloudBuilder/CloudBuilder.Request/Security/LocaleRequest.auto.cs @@ -0,0 +1,60 @@ + +using CloudBuilder.Core.DependencyInjection.Request; +using CloudBuilder.Core.Request; +using CloudBuilder.Core.Service; +using Microsoft.Extensions.DependencyInjection; +using CloudBuilder.Security.Service; + using CloudBuilder.Core.DatabaseAccessor.Entity; + using Microsoft.AspNetCore.Http; + using CloudBuilder.Core.Policy; + using CloudBuilder.Core.DependencyInjection.Request; + using CloudBuilder.Security.Data; + using CloudBuilder.Core.Authorization; + using System; + using CloudBuilder.Security.Entity; + using CloudBuilder.Security.SearchCriteria; + using CloudBuilder.Security; + +namespace CloudBuilder.Request.Security +{ + +public class LocaleRequest : IRequest +{ + +private readonly IServiceRequest serviceRequest; +public LocaleRequest(IServiceRequest serviceRequest) +{ +this.serviceRequest = serviceRequest; +} + + public LocaleEntity[] FindAll() + { +return Task.Run(() => serviceRequest.GetAsync("/Locale/FindAll")).GetAwaiter().GetResult(); } + + public LocaleResultData FindBySearchCriteria(LocaleSearchCriteria criteria) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/Locale/FindBySearchCriteria" , criteria)).GetAwaiter().GetResult(); } + + public LocaleEntity FindByKey(LocaleEntityKey key) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/Locale/FindByKey" , key)).GetAwaiter().GetResult(); } + + public LocaleEntity Insert(LocaleEntity data) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/Locale/Insert" , data)).GetAwaiter().GetResult(); } + + public LocaleEntity Update(LocaleEntity data) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/Locale/Update" , data)).GetAwaiter().GetResult(); } + + public void UpdateLocaleData(LocaleData data) + { + Task.Run(() => serviceRequest.PostAsJsonAsync("/Locale/UpdateLocaleData" , data)).GetAwaiter().GetResult(); } + + public void Delete(LocaleEntityKey key) + { + Task.Run(() => serviceRequest.PostAsJsonAsync("/Locale/Delete" , key)).GetAwaiter().GetResult(); } + + +} +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Request/Security/SecurityActorRequest.auto.cs b/CloudBuilder/CloudBuilder.Request/Security/SecurityActorRequest.auto.cs new file mode 100644 index 0000000..1454380 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Request/Security/SecurityActorRequest.auto.cs @@ -0,0 +1,68 @@ + +using CloudBuilder.Core.DependencyInjection.Request; +using CloudBuilder.Core.Request; +using CloudBuilder.Core.Service; +using Microsoft.Extensions.DependencyInjection; +using CloudBuilder.Security.Service; + using CloudBuilder.Core.DatabaseAccessor.Entity; + using Microsoft.AspNetCore.Http; + using CloudBuilder.Core.Policy; + using CloudBuilder.Core.DependencyInjection.Request; + using CloudBuilder.Security.Data; + using CloudBuilder.Core.Authorization; + using System; + using CloudBuilder.Security.Entity; + using CloudBuilder.Security.SearchCriteria; + using CloudBuilder.Security; + +namespace CloudBuilder.Request.Security +{ + +public class SecurityActorRequest : IRequest +{ + +private readonly IServiceRequest serviceRequest; +public SecurityActorRequest(IServiceRequest serviceRequest) +{ +this.serviceRequest = serviceRequest; +} + + public SecurityActorData FindByKey(string key) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityActor/FindByKey?key=" + key.ToString())).GetAwaiter().GetResult(); } + + public SecurityActorEntity[] FindAll() + { +return Task.Run(() => serviceRequest.PostAsJsonAsync ("/SecurityActor/FindAll")).GetAwaiter().GetResult(); } + + public SecurityActorEntity[] FindAllByNoPermission() + { +return Task.Run(() => serviceRequest.PostAsJsonAsync ("/SecurityActor/FindAllByNoPermission")).GetAwaiter().GetResult(); } + + public SecurityActorResultData FindBySearchCriteria(SecurityActorSearchCriteria criteria) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityActor/FindBySearchCriteria" , criteria)).GetAwaiter().GetResult(); } + + public dynamic PrintBySearchCriteria(SecurityActorSearchCriteria criteria) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityActor/PrintBySearchCriteria" , criteria)).GetAwaiter().GetResult(); } + + public SecurityActorData Insert(SecurityActorData data) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityActor/Insert" , data)).GetAwaiter().GetResult(); } + + public SecurityActorData Update(SecurityActorData data) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityActor/Update" , data)).GetAwaiter().GetResult(); } + + public void Delete(string key) + { + Task.Run(() => serviceRequest.PostAsync("/SecurityActor/Delete?key=" + key.ToString())).GetAwaiter().GetResult(); } + + public void Deletes(string[] keys) + { + Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityActor/Deletes" , keys)).GetAwaiter().GetResult(); } + + +} +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Request/Security/SecurityFunctionRequest.auto.cs b/CloudBuilder/CloudBuilder.Request/Security/SecurityFunctionRequest.auto.cs new file mode 100644 index 0000000..f13bdc9 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Request/Security/SecurityFunctionRequest.auto.cs @@ -0,0 +1,68 @@ + +using CloudBuilder.Core.DependencyInjection.Request; +using CloudBuilder.Core.Request; +using CloudBuilder.Core.Service; +using Microsoft.Extensions.DependencyInjection; +using CloudBuilder.Security.Service; + using CloudBuilder.Core.DatabaseAccessor.Entity; + using Microsoft.AspNetCore.Http; + using CloudBuilder.Core.Policy; + using CloudBuilder.Core.DependencyInjection.Request; + using CloudBuilder.Security.Data; + using CloudBuilder.Core.Authorization; + using System; + using CloudBuilder.Security.Entity; + using CloudBuilder.Security.SearchCriteria; + using CloudBuilder.Security; + +namespace CloudBuilder.Request.Security +{ + +public class SecurityFunctionRequest : IRequest +{ + +private readonly IServiceRequest serviceRequest; +public SecurityFunctionRequest(IServiceRequest serviceRequest) +{ +this.serviceRequest = serviceRequest; +} + + public SecurityFunctionData FindByKey(string key) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityFunction/FindByKey?key=" + key.ToString())).GetAwaiter().GetResult(); } + + public SecurityFunctionResultData FindBySearchCriteria(SecurityFunctionSearchCriteria criteria) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityFunction/FindBySearchCriteria" , criteria)).GetAwaiter().GetResult(); } + + public dynamic PrintBySearchCriteria(SecurityFunctionSearchCriteria criteria) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityFunction/PrintBySearchCriteria" , criteria)).GetAwaiter().GetResult(); } + + public SecurityFunctionData Insert(SecurityFunctionData data) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityFunction/Insert" , data)).GetAwaiter().GetResult(); } + + public SecurityFunctionData Update(SecurityFunctionData data) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityFunction/Update" , data)).GetAwaiter().GetResult(); } + + public void Delete(string key) + { + Task.Run(() => serviceRequest.PostAsync("/SecurityFunction/Delete?key=" + key.ToString())).GetAwaiter().GetResult(); } + + public void Deletes(string[] keys) + { + Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityFunction/Deletes" , keys)).GetAwaiter().GetResult(); } + + public SecurityFunctionEntity FindByFunctionName(string functionName) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityFunction/FindByFunctionName?functionName=" + functionName.ToString())).GetAwaiter().GetResult(); } + + public SecurityFunctionDisplayData[] FindMenus() + { +return Task.Run(() => serviceRequest.PostAsJsonAsync ("/SecurityFunction/FindMenus")).GetAwaiter().GetResult(); } + + +} +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Request/Security/SecurityGeneratorNumberRequest.auto.cs b/CloudBuilder/CloudBuilder.Request/Security/SecurityGeneratorNumberRequest.auto.cs new file mode 100644 index 0000000..b28e239 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Request/Security/SecurityGeneratorNumberRequest.auto.cs @@ -0,0 +1,56 @@ + +using CloudBuilder.Core.DependencyInjection.Request; +using CloudBuilder.Core.Request; +using CloudBuilder.Core.Service; +using Microsoft.Extensions.DependencyInjection; +using CloudBuilder.Security.Service; + using CloudBuilder.Core.DatabaseAccessor.Entity; + using Microsoft.AspNetCore.Http; + using CloudBuilder.Core.Policy; + using CloudBuilder.Core.DependencyInjection.Request; + using CloudBuilder.Security.Data; + using CloudBuilder.Core.Authorization; + using System; + using CloudBuilder.Security.Entity; + using CloudBuilder.Security.SearchCriteria; + using CloudBuilder.Security; + +namespace CloudBuilder.Request.Security +{ + +public class SecurityGeneratorNumberRequest : IRequest +{ + +private readonly IServiceRequest serviceRequest; +public SecurityGeneratorNumberRequest(IServiceRequest serviceRequest) +{ +this.serviceRequest = serviceRequest; +} + + public SecurityGeneratorNumberEntity FindByKey(Int32 key) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityGeneratorNumber/FindByKey?key=" + key.ToString())).GetAwaiter().GetResult(); } + + public SecurityGeneratorNumberResultData FindBySearchCriteria(SecurityGeneratorNumberSearchCriteria criteria) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityGeneratorNumber/FindBySearchCriteria" , criteria)).GetAwaiter().GetResult(); } + + public dynamic PrintBySearchCriteria(SecurityGeneratorNumberSearchCriteria criteria) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityGeneratorNumber/PrintBySearchCriteria" , criteria)).GetAwaiter().GetResult(); } + + public SecurityGeneratorNumberEntity Insert(SecurityGeneratorNumberEntity data) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityGeneratorNumber/Insert" , data)).GetAwaiter().GetResult(); } + + public SecurityGeneratorNumberEntity Update(SecurityGeneratorNumberEntity data) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityGeneratorNumber/Update" , data)).GetAwaiter().GetResult(); } + + public void Delete(Int32 key) + { + Task.Run(() => serviceRequest.PostAsync("/SecurityGeneratorNumber/Delete?key=" + key.ToString())).GetAwaiter().GetResult(); } + + +} +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Request/Security/SecurityGroupRequest.auto.cs b/CloudBuilder/CloudBuilder.Request/Security/SecurityGroupRequest.auto.cs new file mode 100644 index 0000000..217e1ec --- /dev/null +++ b/CloudBuilder/CloudBuilder.Request/Security/SecurityGroupRequest.auto.cs @@ -0,0 +1,64 @@ + +using CloudBuilder.Core.DependencyInjection.Request; +using CloudBuilder.Core.Request; +using CloudBuilder.Core.Service; +using Microsoft.Extensions.DependencyInjection; +using CloudBuilder.Security.Service; + using CloudBuilder.Core.DatabaseAccessor.Entity; + using Microsoft.AspNetCore.Http; + using CloudBuilder.Core.Policy; + using CloudBuilder.Core.DependencyInjection.Request; + using CloudBuilder.Security.Data; + using CloudBuilder.Core.Authorization; + using System; + using CloudBuilder.Security.Entity; + using CloudBuilder.Security.SearchCriteria; + using CloudBuilder.Security; + +namespace CloudBuilder.Request.Security +{ + +public class SecurityGroupRequest : IRequest +{ + +private readonly IServiceRequest serviceRequest; +public SecurityGroupRequest(IServiceRequest serviceRequest) +{ +this.serviceRequest = serviceRequest; +} + + public SecurityGroupData FindByKey(string key) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityGroup/FindByKey?key=" + key.ToString())).GetAwaiter().GetResult(); } + + public SecurityGroupEntity[] FindAll() + { +return Task.Run(() => serviceRequest.PostAsJsonAsync ("/SecurityGroup/FindAll")).GetAwaiter().GetResult(); } + + public SecurityGroupResultData FindBySearchCriteria(SecurityGroupSearchCriteria criteria) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityGroup/FindBySearchCriteria" , criteria)).GetAwaiter().GetResult(); } + + public dynamic PrintBySearchCriteria(SecurityGroupSearchCriteria criteria) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityGroup/PrintBySearchCriteria" , criteria)).GetAwaiter().GetResult(); } + + public SecurityGroupData Insert(SecurityGroupData data) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityGroup/Insert" , data)).GetAwaiter().GetResult(); } + + public SecurityGroupData Update(SecurityGroupData data) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityGroup/Update" , data)).GetAwaiter().GetResult(); } + + public void Delete(string key) + { + Task.Run(() => serviceRequest.PostAsync("/SecurityGroup/Delete?key=" + key.ToString())).GetAwaiter().GetResult(); } + + public void Deletes(string[] keys) + { + Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityGroup/Deletes" , keys)).GetAwaiter().GetResult(); } + + +} +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Request/Security/SecurityLockRequest.auto.cs b/CloudBuilder/CloudBuilder.Request/Security/SecurityLockRequest.auto.cs new file mode 100644 index 0000000..3f46fbc --- /dev/null +++ b/CloudBuilder/CloudBuilder.Request/Security/SecurityLockRequest.auto.cs @@ -0,0 +1,101 @@ + +using CloudBuilder.Core.DependencyInjection.Request; +using CloudBuilder.Core.Request; +using CloudBuilder.Core.Service; +using Microsoft.Extensions.DependencyInjection; +using CloudBuilder.Security.Service; + using CloudBuilder.Core.DatabaseAccessor.Entity; + using Microsoft.AspNetCore.Http; + using CloudBuilder.Core.Policy; + using CloudBuilder.Core.DependencyInjection.Request; + using CloudBuilder.Security.Data; + using CloudBuilder.Core.Authorization; + using System; + using CloudBuilder.Security.Entity; + using CloudBuilder.Security.SearchCriteria; + using CloudBuilder.Security; + +namespace CloudBuilder.Request.Security +{ + +public class SecurityLockRequest : IRequest +{ + +private readonly IServiceRequest serviceRequest; +public SecurityLockRequest(IServiceRequest serviceRequest) +{ +this.serviceRequest = serviceRequest; +} + + public SecurityLockEntity FindByKey(SecurityLockEntityKey key) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityLock/FindByKey" , key)).GetAwaiter().GetResult(); } + + public SecurityLockEntity Insert(SecurityLockEntity data) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityLock/Insert" , data)).GetAwaiter().GetResult(); } + + public SecurityLockEntity Update(SecurityLockEntity data) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityLock/Update" , data)).GetAwaiter().GetResult(); } + + public void Delete(SecurityLockEntityKey key) + { + Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityLock/Delete" , key)).GetAwaiter().GetResult(); } + + + public class IsLockedCompositionData2 { + public string entityName { get; set; } + public string key { get; set; } + + } + public bool IsLocked(string entityName, string key) + { +var compositionData = new IsLockedCompositionData2{ entityName = entityName, key = key }; return Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityLock/IsLocked", compositionData)).GetAwaiter().GetResult(); } + + + public class LockCompositionData3 { + public string entityName { get; set; } + public string key { get; set; } + public string username { get; set; } + + } + public void Lock(string entityName, string key, string username) + { +var compositionData = new LockCompositionData3{ entityName = entityName, key = key, username = username }; Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityLock/Lock", compositionData)).GetAwaiter().GetResult(); } + + + public class ForceLockCompositionData3 { + public string entityName { get; set; } + public string key { get; set; } + public string username { get; set; } + + } + public void ForceLock(string entityName, string key, string username) + { +var compositionData = new ForceLockCompositionData3{ entityName = entityName, key = key, username = username }; Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityLock/ForceLock", compositionData)).GetAwaiter().GetResult(); } + + + public class ConsumeLockCompositionData3 { + public string entityName { get; set; } + public string key { get; set; } + public string username { get; set; } + + } + public void ConsumeLock(string entityName, string key, string username) + { +var compositionData = new ConsumeLockCompositionData3{ entityName = entityName, key = key, username = username }; Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityLock/ConsumeLock", compositionData)).GetAwaiter().GetResult(); } + + + public class ClearLockCompositionData2 { + public string entityName { get; set; } + public string key { get; set; } + + } + public void ClearLock(string entityName, string key) + { +var compositionData = new ClearLockCompositionData2{ entityName = entityName, key = key }; Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityLock/ClearLock", compositionData)).GetAwaiter().GetResult(); } + + +} +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Request/Security/SecurityMasterRequest.auto.cs b/CloudBuilder/CloudBuilder.Request/Security/SecurityMasterRequest.auto.cs new file mode 100644 index 0000000..8bf757b --- /dev/null +++ b/CloudBuilder/CloudBuilder.Request/Security/SecurityMasterRequest.auto.cs @@ -0,0 +1,64 @@ + +using CloudBuilder.Core.DependencyInjection.Request; +using CloudBuilder.Core.Request; +using CloudBuilder.Core.Service; +using Microsoft.Extensions.DependencyInjection; +using CloudBuilder.Security.Service; + using CloudBuilder.Core.DatabaseAccessor.Entity; + using Microsoft.AspNetCore.Http; + using CloudBuilder.Core.Policy; + using CloudBuilder.Core.DependencyInjection.Request; + using CloudBuilder.Security.Data; + using CloudBuilder.Core.Authorization; + using System; + using CloudBuilder.Security.Entity; + using CloudBuilder.Security.SearchCriteria; + using CloudBuilder.Security; + +namespace CloudBuilder.Request.Security +{ + +public class SecurityMasterRequest : IRequest +{ + +private readonly IServiceRequest serviceRequest; +public SecurityMasterRequest(IServiceRequest serviceRequest) +{ +this.serviceRequest = serviceRequest; +} + + public SecurityMasterEntity FindByKey(SecurityMasterEntityKey key) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityMaster/FindByKey" , key)).GetAwaiter().GetResult(); } + + public SecurityMasterEntity[] FindAll() + { +return Task.Run(() => serviceRequest.GetAsync("/SecurityMaster/FindAll")).GetAwaiter().GetResult(); } + + public SecurityMasterResultData FindBySearchCriteria(SecurityMasterSearchCriteria criteria) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityMaster/FindBySearchCriteria" , criteria)).GetAwaiter().GetResult(); } + + public dynamic PrintBySearchCriteria(SecurityMasterSearchCriteria criteria) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityMaster/PrintBySearchCriteria" , criteria)).GetAwaiter().GetResult(); } + + public SecurityMasterEntity Insert(SecurityMasterEntity data) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityMaster/Insert" , data)).GetAwaiter().GetResult(); } + + public SecurityMasterEntity Update(SecurityMasterEntity data) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityMaster/Update" , data)).GetAwaiter().GetResult(); } + + public void Delete(SecurityMasterEntityKey key) + { + Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityMaster/Delete" , key)).GetAwaiter().GetResult(); } + + public void Deletes(SecurityMasterEntity[] datas) + { + Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityMaster/Deletes" , datas)).GetAwaiter().GetResult(); } + + +} +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Request/Security/SecurityPermissionRequest.auto.cs b/CloudBuilder/CloudBuilder.Request/Security/SecurityPermissionRequest.auto.cs new file mode 100644 index 0000000..8ca088e --- /dev/null +++ b/CloudBuilder/CloudBuilder.Request/Security/SecurityPermissionRequest.auto.cs @@ -0,0 +1,68 @@ + +using CloudBuilder.Core.DependencyInjection.Request; +using CloudBuilder.Core.Request; +using CloudBuilder.Core.Service; +using Microsoft.Extensions.DependencyInjection; +using CloudBuilder.Security.Service; + using CloudBuilder.Core.DatabaseAccessor.Entity; + using Microsoft.AspNetCore.Http; + using CloudBuilder.Core.Policy; + using CloudBuilder.Core.DependencyInjection.Request; + using CloudBuilder.Security.Data; + using CloudBuilder.Core.Authorization; + using System; + using CloudBuilder.Security.Entity; + using CloudBuilder.Security.SearchCriteria; + using CloudBuilder.Security; + +namespace CloudBuilder.Request.Security +{ + +public class SecurityPermissionRequest : IRequest +{ + +private readonly IServiceRequest serviceRequest; +public SecurityPermissionRequest(IServiceRequest serviceRequest) +{ +this.serviceRequest = serviceRequest; +} + + public SecurityPermissionData FindByKey(string key) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityPermission/FindByKey?key=" + key.ToString())).GetAwaiter().GetResult(); } + + public SecurityPermissionResultData FindBySearchCriteria(SecurityPermissionSearchCriteria criteria) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityPermission/FindBySearchCriteria" , criteria)).GetAwaiter().GetResult(); } + + public SecurityPermissionResultData FindDependentBySearchCriteria(SecurityPermissionSearchCriteria criteria) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityPermission/FindDependentBySearchCriteria" , criteria)).GetAwaiter().GetResult(); } + + public SecurityPermissionResultData FindDependentsBySearchCriteria(SecurityPermissionSearchCriteria criteria) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityPermission/FindDependentsBySearchCriteria" , criteria)).GetAwaiter().GetResult(); } + + public dynamic PrintBySearchCriteria(SecurityPermissionSearchCriteria criteria) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityPermission/PrintBySearchCriteria" , criteria)).GetAwaiter().GetResult(); } + + public SecurityPermissionData Insert(SecurityPermissionData data) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityPermission/Insert" , data)).GetAwaiter().GetResult(); } + + public SecurityPermissionData Update(SecurityPermissionData data) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityPermission/Update" , data)).GetAwaiter().GetResult(); } + + public void Delete(string key) + { + Task.Run(() => serviceRequest.PostAsync("/SecurityPermission/Delete?key=" + key.ToString())).GetAwaiter().GetResult(); } + + public void Deletes(string[] keys) + { + Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityPermission/Deletes" , keys)).GetAwaiter().GetResult(); } + + +} +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Request/Security/SecurityUserPreferenceRequest.auto.cs b/CloudBuilder/CloudBuilder.Request/Security/SecurityUserPreferenceRequest.auto.cs new file mode 100644 index 0000000..95f02a8 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Request/Security/SecurityUserPreferenceRequest.auto.cs @@ -0,0 +1,56 @@ + +using CloudBuilder.Core.DependencyInjection.Request; +using CloudBuilder.Core.Request; +using CloudBuilder.Core.Service; +using Microsoft.Extensions.DependencyInjection; +using CloudBuilder.Security.Service; + using CloudBuilder.Core.DatabaseAccessor.Entity; + using Microsoft.AspNetCore.Http; + using CloudBuilder.Core.Policy; + using CloudBuilder.Core.DependencyInjection.Request; + using CloudBuilder.Security.Data; + using CloudBuilder.Core.Authorization; + using System; + using CloudBuilder.Security.Entity; + using CloudBuilder.Security.SearchCriteria; + using CloudBuilder.Security; + +namespace CloudBuilder.Request.Security +{ + +public class SecurityUserPreferenceRequest : IRequest +{ + +private readonly IServiceRequest serviceRequest; +public SecurityUserPreferenceRequest(IServiceRequest serviceRequest) +{ +this.serviceRequest = serviceRequest; +} + + public SecurityUserPreferenceEntity FindByKey(SecurityUserPreferenceEntityKey key) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityUserPreference/FindByKey" , key)).GetAwaiter().GetResult(); } + + public SecurityUserPreferenceEntity[] FindBySearchCriteria(SecurityUserPreferenceSearchCriteria criteria) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityUserPreference/FindBySearchCriteria" , criteria)).GetAwaiter().GetResult(); } + + public dynamic PrintBySearchCriteria(SecurityUserPreferenceSearchCriteria criteria) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityUserPreference/PrintBySearchCriteria" , criteria)).GetAwaiter().GetResult(); } + + public SecurityUserPreferenceEntity Insert(SecurityUserPreferenceEntity data) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityUserPreference/Insert" , data)).GetAwaiter().GetResult(); } + + public SecurityUserPreferenceEntity Update(SecurityUserPreferenceEntity data) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityUserPreference/Update" , data)).GetAwaiter().GetResult(); } + + public void Delete(SecurityUserPreferenceEntityKey key) + { + Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityUserPreference/Delete" , key)).GetAwaiter().GetResult(); } + + +} +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Request/Security/SecurityUserRequest.auto.cs b/CloudBuilder/CloudBuilder.Request/Security/SecurityUserRequest.auto.cs new file mode 100644 index 0000000..b223254 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Request/Security/SecurityUserRequest.auto.cs @@ -0,0 +1,76 @@ + +using CloudBuilder.Core.DependencyInjection.Request; +using CloudBuilder.Core.Request; +using CloudBuilder.Core.Service; +using Microsoft.Extensions.DependencyInjection; +using CloudBuilder.Security.Service; + using CloudBuilder.Core.DatabaseAccessor.Entity; + using Microsoft.AspNetCore.Http; + using CloudBuilder.Core.Policy; + using CloudBuilder.Core.DependencyInjection.Request; + using CloudBuilder.Security.Data; + using CloudBuilder.Core.Authorization; + using System; + using CloudBuilder.Security.Entity; + using CloudBuilder.Security.SearchCriteria; + using CloudBuilder.Security; + +namespace CloudBuilder.Request.Security +{ + +public class SecurityUserRequest : IRequest +{ + +private readonly IServiceRequest serviceRequest; +public SecurityUserRequest(IServiceRequest serviceRequest) +{ +this.serviceRequest = serviceRequest; +} + + public SecurityUserEntity FindByStaffId(string staffid) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityUser/FindByStaffId?staffid=" + staffid.ToString())).GetAwaiter().GetResult(); } + + public SecurityUserData FindByKey(string key) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityUser/FindByKey?key=" + key.ToString())).GetAwaiter().GetResult(); } + + public SecurityUserEntity[] FindAll() + { +return Task.Run(() => serviceRequest.PostAsJsonAsync ("/SecurityUser/FindAll")).GetAwaiter().GetResult(); } + + public SecurityUserResultData FindBySearchCriteria(SecurityUserSearchCriteria criteria) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityUser/FindBySearchCriteria" , criteria)).GetAwaiter().GetResult(); } + + public dynamic PrintBySearchCriteria(SecurityUserSearchCriteria criteria) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityUser/PrintBySearchCriteria" , criteria)).GetAwaiter().GetResult(); } + + public SecurityUserData Insert(SecurityUserData data) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityUser/Insert" , data)).GetAwaiter().GetResult(); } + + public SecurityUserData Update(SecurityUserData data) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityUser/Update" , data)).GetAwaiter().GetResult(); } + + public void Delete(string key) + { + Task.Run(() => serviceRequest.PostAsync("/SecurityUser/Delete?key=" + key.ToString())).GetAwaiter().GetResult(); } + + public void Deletes(string[] keys) + { + Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityUser/Deletes" , keys)).GetAwaiter().GetResult(); } + + public SecurityFunctionResultData FindMenuByUsername() + { +return Task.Run(() => serviceRequest.PostAsJsonAsync ("/SecurityUser/FindMenuByUsername")).GetAwaiter().GetResult(); } + + public void UpdateLocalName(string localName) + { + Task.Run(() => serviceRequest.PostAsync("/SecurityUser/UpdateLocalName?localName=" + localName.ToString())).GetAwaiter().GetResult(); } + + +} +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Request/Security/YesNoPolicyRequest.auto.cs b/CloudBuilder/CloudBuilder.Request/Security/YesNoPolicyRequest.auto.cs new file mode 100644 index 0000000..3e0ad35 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Request/Security/YesNoPolicyRequest.auto.cs @@ -0,0 +1,41 @@ + +using CloudBuilder.Core.DependencyInjection.Request; +using CloudBuilder.Core.Request; +using CloudBuilder.Core.Service; +using Microsoft.Extensions.DependencyInjection; +using CloudBuilder.Security.Service; + using CloudBuilder.Core.DatabaseAccessor.Entity; + using Microsoft.AspNetCore.Http; + using CloudBuilder.Core.Policy; + using CloudBuilder.Core.DependencyInjection.Request; + using CloudBuilder.Security.Data; + using CloudBuilder.Core.Authorization; + using System; + using CloudBuilder.Security.Entity; + using CloudBuilder.Security.SearchCriteria; + using CloudBuilder.Security; + using Microsoft.Extensions.Options; + +namespace CloudBuilder.Request.Security +{ + +public class YesNoPolicyRequest : IRequest +{ + +private readonly IServiceRequest serviceRequest; +public YesNoPolicyRequest(IServiceRequest serviceRequest) +{ +this.serviceRequest = serviceRequest; +} + + public SelectOption[] FindSelectOption(bool blank) + { +return Task.Run(() => serviceRequest.PostAsJsonAsync("/YesNoPolicy/FindSelectOption?blank=" + blank.ToString())).GetAwaiter().GetResult(); } + + public void Copy() + { +return Task.Run(() => serviceRequest.GetAsync("/YesNoPolicy/Copy")).GetAwaiter().GetResult(); } + + +} +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Security.Gui/CloudBuilder.Security.Gui.csproj b/CloudBuilder/CloudBuilder.Security.Gui/CloudBuilder.Security.Gui.csproj new file mode 100644 index 0000000..30c9674 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/CloudBuilder.Security.Gui.csproj @@ -0,0 +1,69 @@ + + + + Library + net8.0-windows + enable + true + enable + + + + + + + + ..\CloudBuilder.Core\bin\Debug\net8.0\CloudBuilder.Core.dll + + + ..\CloudBuilder.Gui\bin\Debug\net8.0-windows\CloudBuilder.Gui.dll + + + ..\CloudBuilder.Request\bin\Debug\net8.0\CloudBuilder.Request.dll + + + ..\CloudBuilder.Security\bin\Debug\net8.0\CloudBuilder.Security.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + True + True + Resources.resx + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + + + + diff --git a/CloudBuilder/CloudBuilder.Security.Gui/CloudBuilder.Security.Gui.csproj.user b/CloudBuilder/CloudBuilder.Security.Gui/CloudBuilder.Security.Gui.csproj.user new file mode 100644 index 0000000..679a4fc --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/CloudBuilder.Security.Gui.csproj.user @@ -0,0 +1,60 @@ + + + + + + UserControl + + + Form + + + Form + + + Form + + + UserControl + + + UserControl + + + UserControl + + + UserControl + + + UserControl + + + UserControl + + + UserControl + + + UserControl + + + UserControl + + + UserControl + + + UserControl + + + UserControl + + + UserControl + + + UserControl + + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Security.Gui/LocaleEnquiryPage.Designer.cs b/CloudBuilder/CloudBuilder.Security.Gui/LocaleEnquiryPage.Designer.cs new file mode 100644 index 0000000..00b8a49 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/LocaleEnquiryPage.Designer.cs @@ -0,0 +1,486 @@ +namespace CloudBuilder.Security.Gui +{ + partial class LocaleEnquiryPage + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + DataGridViewCellStyle dataGridViewCellStyle1 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle2 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle3 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle4 = new DataGridViewCellStyle(); + mainPanel = new TableLayoutPanel(); + topPanel = new TableLayoutPanel(); + groupNameLabel = new Krypton.Toolkit.KryptonLabel(); + groupNameTxt = new Krypton.Toolkit.KryptonTextBox(); + searchPanel = new TableLayoutPanel(); + searchBut = new Krypton.Toolkit.KryptonButton(); + resetBut = new Krypton.Toolkit.KryptonButton(); + kryptonLabel1 = new Krypton.Toolkit.KryptonLabel(); + valueTxt = new Krypton.Toolkit.KryptonTextBox(); + nameLabel = new Krypton.Toolkit.KryptonLabel(); + nameTxt = new Krypton.Toolkit.KryptonTextBox(); + langLabel = new Krypton.Toolkit.KryptonLabel(); + langCombo = new Krypton.Toolkit.KryptonComboBox(); + contextPanel = new TableLayoutPanel(); + dataGv = new Krypton.Toolkit.KryptonDataGridView(); + gridViewPagination = new CloudBuilder.Gui.GridViewPagination(); + bottomPanel = new TableLayoutPanel(); + operationPanel = new TableLayoutPanel(); + amendBut = new Krypton.Toolkit.KryptonButton(); + savePanel = new TableLayoutPanel(); + tableLayoutPanel1 = new TableLayoutPanel(); + delBut = new Krypton.Toolkit.KryptonButton(); + addBut = new Krypton.Toolkit.KryptonButton(); + cancelBut = new Krypton.Toolkit.KryptonButton(); + saveBut = new Krypton.Toolkit.KryptonButton(); + groupNameCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + langCol = new DataGridViewComboBoxColumn(); + nameCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + valueCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + orderByCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + mainPanel.SuspendLayout(); + topPanel.SuspendLayout(); + searchPanel.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)langCombo).BeginInit(); + contextPanel.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)dataGv).BeginInit(); + bottomPanel.SuspendLayout(); + operationPanel.SuspendLayout(); + savePanel.SuspendLayout(); + tableLayoutPanel1.SuspendLayout(); + SuspendLayout(); + // + // mainPanel + // + mainPanel.ColumnCount = 1; + mainPanel.ColumnStyles.Add(new ColumnStyle()); + mainPanel.Controls.Add(topPanel, 0, 0); + mainPanel.Controls.Add(contextPanel, 0, 1); + mainPanel.Controls.Add(bottomPanel, 0, 2); + mainPanel.Dock = DockStyle.Fill; + mainPanel.Location = new Point(0, 0); + mainPanel.Name = "mainPanel"; + mainPanel.RowCount = 3; + mainPanel.RowStyles.Add(new RowStyle()); + mainPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 100F)); + mainPanel.RowStyles.Add(new RowStyle()); + mainPanel.Size = new Size(1024, 800); + mainPanel.TabIndex = 0; + // + // topPanel + // + topPanel.AutoSize = true; + topPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + topPanel.ColumnCount = 5; + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.Controls.Add(groupNameLabel, 0, 0); + topPanel.Controls.Add(groupNameTxt, 1, 0); + topPanel.Controls.Add(searchPanel, 4, 0); + topPanel.Controls.Add(kryptonLabel1, 2, 0); + topPanel.Controls.Add(valueTxt, 3, 0); + topPanel.Controls.Add(nameLabel, 0, 1); + topPanel.Controls.Add(nameTxt, 1, 1); + topPanel.Controls.Add(langLabel, 2, 1); + topPanel.Controls.Add(langCombo, 3, 1); + topPanel.Dock = DockStyle.Fill; + topPanel.Location = new Point(3, 3); + topPanel.Name = "topPanel"; + topPanel.RowCount = 2; + topPanel.RowStyles.Add(new RowStyle()); + topPanel.RowStyles.Add(new RowStyle()); + topPanel.Size = new Size(1018, 60); + topPanel.TabIndex = 0; + // + // groupNameLabel + // + groupNameLabel.Location = new Point(3, 3); + groupNameLabel.Name = "groupNameLabel"; + groupNameLabel.Size = new Size(52, 20); + groupNameLabel.TabIndex = 999; + groupNameLabel.Values.Text = "分类名:"; + // + // groupNameTxt + // + groupNameTxt.Location = new Point(61, 3); + groupNameTxt.Name = "groupNameTxt"; + groupNameTxt.Size = new Size(200, 23); + groupNameTxt.TabIndex = 0; + // + // searchPanel + // + searchPanel.AutoSize = true; + searchPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + searchPanel.ColumnCount = 3; + searchPanel.ColumnStyles.Add(new ColumnStyle()); + searchPanel.ColumnStyles.Add(new ColumnStyle()); + searchPanel.ColumnStyles.Add(new ColumnStyle()); + searchPanel.Controls.Add(searchBut, 0, 0); + searchPanel.Controls.Add(resetBut, 1, 0); + searchPanel.Location = new Point(602, 0); + searchPanel.Margin = new Padding(60, 0, 0, 0); + searchPanel.Name = "searchPanel"; + searchPanel.RowCount = 1; + searchPanel.RowStyles.Add(new RowStyle()); + searchPanel.Size = new Size(192, 31); + searchPanel.TabIndex = 999; + // + // searchBut + // + searchBut.Location = new Point(3, 3); + searchBut.Name = "searchBut"; + searchBut.Size = new Size(90, 25); + searchBut.TabIndex = 0; + searchBut.Values.Image = Properties.Resources.search_16; + searchBut.Values.Text = "查询(&S)"; + searchBut.Click += searchBut_Click; + // + // resetBut + // + resetBut.Location = new Point(99, 3); + resetBut.Name = "resetBut"; + resetBut.Size = new Size(90, 25); + resetBut.TabIndex = 0; + resetBut.Values.Image = Properties.Resources.reset_16; + resetBut.Values.Text = "重置(&R)"; + resetBut.Click += resetBut_Click; + // + // kryptonLabel1 + // + kryptonLabel1.Location = new Point(294, 3); + kryptonLabel1.Margin = new Padding(30, 3, 3, 3); + kryptonLabel1.Name = "kryptonLabel1"; + kryptonLabel1.Size = new Size(26, 20); + kryptonLabel1.TabIndex = 999; + kryptonLabel1.Values.Text = "值:"; + // + // valueTxt + // + valueTxt.Location = new Point(339, 3); + valueTxt.Name = "valueTxt"; + valueTxt.Size = new Size(200, 23); + valueTxt.TabIndex = 1; + // + // nameLabel + // + nameLabel.Location = new Point(3, 34); + nameLabel.Name = "nameLabel"; + nameLabel.Size = new Size(52, 20); + nameLabel.TabIndex = 999; + nameLabel.Values.Text = "子类名:"; + // + // nameTxt + // + nameTxt.Location = new Point(61, 34); + nameTxt.Name = "nameTxt"; + nameTxt.Size = new Size(200, 23); + nameTxt.TabIndex = 3; + // + // langLabel + // + langLabel.Location = new Point(294, 34); + langLabel.Margin = new Padding(30, 3, 3, 3); + langLabel.Name = "langLabel"; + langLabel.Size = new Size(39, 20); + langLabel.TabIndex = 999; + langLabel.Values.Text = "语言:"; + // + // langCombo + // + langCombo.DropDownStyle = ComboBoxStyle.DropDownList; + langCombo.DropDownWidth = 200; + langCombo.IntegralHeight = false; + langCombo.Location = new Point(339, 34); + langCombo.Name = "langCombo"; + langCombo.Size = new Size(200, 22); + langCombo.StateCommon.ComboBox.Content.TextH = Krypton.Toolkit.PaletteRelativeAlign.Near; + langCombo.TabIndex = 4; + // + // contextPanel + // + contextPanel.ColumnCount = 1; + contextPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F)); + contextPanel.Controls.Add(dataGv, 0, 0); + contextPanel.Controls.Add(gridViewPagination, 0, 1); + contextPanel.Dock = DockStyle.Fill; + contextPanel.Location = new Point(3, 69); + contextPanel.Name = "contextPanel"; + contextPanel.RowCount = 2; + contextPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 50F)); + contextPanel.RowStyles.Add(new RowStyle()); + contextPanel.Size = new Size(1018, 617); + contextPanel.TabIndex = 999; + // + // dataGv + // + dataGv.AllowUserToAddRows = false; + dataGv.AllowUserToDeleteRows = false; + dataGv.BorderStyle = BorderStyle.None; + dataGv.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize; + dataGv.Columns.AddRange(new DataGridViewColumn[] { groupNameCol, langCol, nameCol, valueCol, orderByCol }); + dataGv.Dock = DockStyle.Fill; + dataGv.Location = new Point(3, 3); + dataGv.Name = "dataGv"; + dataGv.Size = new Size(1012, 581); + dataGv.TabIndex = 0; + // + // gridViewPagination + // + gridViewPagination.AutoSizeMode = AutoSizeMode.GrowAndShrink; + gridViewPagination.CurrentPage = 0; + gridViewPagination.Dock = DockStyle.Fill; + gridViewPagination.Limit = 20; + gridViewPagination.Location = new Point(0, 587); + gridViewPagination.Margin = new Padding(0); + gridViewPagination.Name = "gridViewPagination"; + gridViewPagination.Page = 0; + gridViewPagination.Size = new Size(1018, 30); + gridViewPagination.TabIndex = 999; + gridViewPagination.Total = 0; + // + // bottomPanel + // + bottomPanel.AutoSize = true; + bottomPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + bottomPanel.ColumnCount = 2; + bottomPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F)); + bottomPanel.ColumnStyles.Add(new ColumnStyle()); + bottomPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 20F)); + bottomPanel.Controls.Add(operationPanel, 0, 1); + bottomPanel.Controls.Add(savePanel, 0, 0); + bottomPanel.Dock = DockStyle.Fill; + bottomPanel.Location = new Point(3, 692); + bottomPanel.Name = "bottomPanel"; + bottomPanel.RowCount = 2; + bottomPanel.RowStyles.Add(new RowStyle()); + bottomPanel.RowStyles.Add(new RowStyle()); + bottomPanel.Size = new Size(1018, 105); + bottomPanel.TabIndex = 999; + // + // operationPanel + // + operationPanel.AutoSize = true; + operationPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + operationPanel.ColumnCount = 3; + operationPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F)); + operationPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 101F)); + operationPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F)); + operationPanel.Controls.Add(amendBut, 0, 0); + operationPanel.Location = new Point(0, 74); + operationPanel.Margin = new Padding(0); + operationPanel.Name = "operationPanel"; + operationPanel.RowCount = 1; + operationPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 50F)); + operationPanel.Size = new Size(293, 31); + operationPanel.TabIndex = 0; + // + // amendBut + // + amendBut.Location = new Point(3, 3); + amendBut.Name = "amendBut"; + amendBut.Size = new Size(90, 25); + amendBut.TabIndex = 0; + amendBut.Values.Image = Properties.Resources.amend_16; + amendBut.Values.Text = "修改(&A)"; + amendBut.Click += amendBut_Click; + // + // savePanel + // + savePanel.AutoSize = true; + savePanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + savePanel.ColumnCount = 2; + savePanel.ColumnStyles.Add(new ColumnStyle()); + savePanel.ColumnStyles.Add(new ColumnStyle()); + savePanel.Controls.Add(tableLayoutPanel1, 0, 0); + savePanel.Controls.Add(cancelBut, 1, 1); + savePanel.Controls.Add(saveBut, 0, 1); + savePanel.Location = new Point(3, 3); + savePanel.Name = "savePanel"; + savePanel.RowCount = 2; + savePanel.RowStyles.Add(new RowStyle()); + savePanel.RowStyles.Add(new RowStyle()); + savePanel.Size = new Size(192, 68); + savePanel.TabIndex = 2; + // + // tableLayoutPanel1 + // + tableLayoutPanel1.AutoSize = true; + tableLayoutPanel1.AutoSizeMode = AutoSizeMode.GrowAndShrink; + tableLayoutPanel1.ColumnCount = 2; + savePanel.SetColumnSpan(tableLayoutPanel1, 2); + tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel1.Controls.Add(delBut, 1, 0); + tableLayoutPanel1.Controls.Add(addBut, 0, 0); + tableLayoutPanel1.Location = new Point(3, 3); + tableLayoutPanel1.Name = "tableLayoutPanel1"; + tableLayoutPanel1.RowCount = 1; + tableLayoutPanel1.RowStyles.Add(new RowStyle()); + tableLayoutPanel1.Size = new Size(92, 31); + tableLayoutPanel1.TabIndex = 3; + // + // delBut + // + delBut.Location = new Point(49, 3); + delBut.Name = "delBut"; + delBut.Size = new Size(40, 25); + delBut.TabIndex = 2; + delBut.Values.Image = Properties.Resources.navigate_minus; + delBut.Values.Text = ""; + delBut.Click += delBut_Click; + // + // addBut + // + addBut.Location = new Point(3, 3); + addBut.Name = "addBut"; + addBut.Size = new Size(40, 25); + addBut.TabIndex = 1; + addBut.Values.Image = Properties.Resources.navigate_plus; + addBut.Values.Text = ""; + addBut.Click += addBut_Click; + // + // cancelBut + // + cancelBut.Location = new Point(99, 40); + cancelBut.Name = "cancelBut"; + cancelBut.Size = new Size(90, 25); + cancelBut.TabIndex = 2; + cancelBut.Values.Image = Properties.Resources.cancel_16; + cancelBut.Values.Text = "取消(&L)"; + cancelBut.Click += cancelBut_Click; + // + // saveBut + // + saveBut.Location = new Point(3, 40); + saveBut.Name = "saveBut"; + saveBut.Size = new Size(90, 25); + saveBut.TabIndex = 1; + saveBut.Values.Image = Properties.Resources.save_16; + saveBut.Values.Text = "保存(&S)"; + saveBut.Click += saveBut_Click; + // + // groupNameCol + // + groupNameCol.DataPropertyName = "GroupName"; + groupNameCol.DefaultCellStyle = dataGridViewCellStyle1; + groupNameCol.HeaderText = "分类名"; + groupNameCol.Name = "groupNameCol"; + groupNameCol.Width = 260; + // + // langCol + // + langCol.DataPropertyName = "Lang"; + langCol.DisplayStyle = DataGridViewComboBoxDisplayStyle.Nothing; + langCol.HeaderText = "语言"; + langCol.Name = "langCol"; + langCol.Resizable = DataGridViewTriState.True; + // + // nameCol + // + nameCol.DataPropertyName = "Name"; + nameCol.DefaultCellStyle = dataGridViewCellStyle2; + nameCol.HeaderText = "子类名"; + nameCol.Name = "nameCol"; + nameCol.Width = 260; + // + // valueCol + // + valueCol.DataPropertyName = "Value"; + valueCol.DefaultCellStyle = dataGridViewCellStyle3; + valueCol.HeaderText = "值"; + valueCol.Name = "valueCol"; + valueCol.Resizable = DataGridViewTriState.True; + valueCol.Width = 260; + // + // orderByCol + // + orderByCol.DataPropertyName = "OrderBy"; + orderByCol.DefaultCellStyle = dataGridViewCellStyle4; + orderByCol.HeaderText = "排序"; + orderByCol.Name = "orderByCol"; + orderByCol.Width = 100; + // + // LocaleEnquiryPage + // + AutoScaleDimensions = new SizeF(7F, 15F); + AutoScaleMode = AutoScaleMode.Font; + Controls.Add(mainPanel); + Name = "LocaleEnquiryPage"; + mainPanel.ResumeLayout(false); + mainPanel.PerformLayout(); + topPanel.ResumeLayout(false); + topPanel.PerformLayout(); + searchPanel.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)langCombo).EndInit(); + contextPanel.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)dataGv).EndInit(); + bottomPanel.ResumeLayout(false); + bottomPanel.PerformLayout(); + operationPanel.ResumeLayout(false); + savePanel.ResumeLayout(false); + savePanel.PerformLayout(); + tableLayoutPanel1.ResumeLayout(false); + ResumeLayout(false); + } + + #endregion + + private TableLayoutPanel mainPanel; + private TableLayoutPanel topPanel; + private TableLayoutPanel searchPanel; + private Krypton.Toolkit.KryptonButton searchBut; + private Krypton.Toolkit.KryptonButton resetBut; + private TableLayoutPanel contextPanel; + private TableLayoutPanel bottomPanel; + private TableLayoutPanel operationPanel; + private Krypton.Toolkit.KryptonButton amendBut; + private Krypton.Toolkit.KryptonLabel groupNameLabel; + private Krypton.Toolkit.KryptonTextBox groupNameTxt; + private Krypton.Toolkit.KryptonDataGridView dataGv; + private CloudBuilder.Gui.GridViewPagination gridViewPagination; + private Krypton.Toolkit.KryptonLabel kryptonLabel1; + private Krypton.Toolkit.KryptonTextBox valueTxt; + private TableLayoutPanel savePanel; + private Krypton.Toolkit.KryptonButton cancelBut; + private Krypton.Toolkit.KryptonButton saveBut; + private TableLayoutPanel tableLayoutPanel1; + private Krypton.Toolkit.KryptonButton delBut; + private Krypton.Toolkit.KryptonButton addBut; + private Krypton.Toolkit.KryptonLabel nameLabel; + private Krypton.Toolkit.KryptonTextBox nameTxt; + private Krypton.Toolkit.KryptonLabel langLabel; + private Krypton.Toolkit.KryptonComboBox langCombo; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn groupNameCol; + private DataGridViewComboBoxColumn langCol; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn nameCol; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn valueCol; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn orderByCol; + } +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Security.Gui/LocaleEnquiryPage.cs b/CloudBuilder/CloudBuilder.Security.Gui/LocaleEnquiryPage.cs new file mode 100644 index 0000000..d8089f6 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/LocaleEnquiryPage.cs @@ -0,0 +1,325 @@ +using ClosedXML.Excel; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using CloudBuilder.Core.DependencyInjection.Form; +using CloudBuilder.Core.Report; +using CloudBuilder.Core.Service; +using CloudBuilder.Gui; +using CloudBuilder.Gui.DependencyInjection; +using CloudBuilder.Request.Security; +using CloudBuilder.Security.Data; +using CloudBuilder.Security.Entity; +using CloudBuilder.Security.Linkup; +using CloudBuilder.Security.Policy; +using CloudBuilder.Security.SearchCriteria; +using DocumentFormat.OpenXml.Office2010.ExcelAc; +using DocumentFormat.OpenXml.Spreadsheet; +using DocumentFormat.OpenXml.Wordprocessing; +using Krypton.Toolkit; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http.Extensions; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.IdentityModel.Tokens; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + + +namespace CloudBuilder.Security.Gui +{ + public partial class LocaleEnquiryPage : AbstractPage + { + private LocaleDisplayData[] locales = null!; + private LocaleSearchCriteria searchCriteria = null!; + private BindingContextAttributeProvider provider; + private LocaleRequest localeRequest; + private SecurityMessagePolicy securityMessagePolicy; + + //初始化Page,注入容器内,不要在此做任何事情 + public LocaleEnquiryPage() + { + InitializeComponent(); + } + + /// + /// 第一次加载时执行,只执行一次 + /// + public override void FunctionLoaded() + { + HandleException(() => OnFunctionLoaded()); + } + + private void OnFunctionLoaded() + { + base.FunctionLoaded(); + //初始化容器------------------------------------- + localeRequest = ServiceHelper.GetTypeService(); + securityMessagePolicy = ServiceHelper.GetTypeService()!; + + //界面初始化 + InitGui(); + } + + /// + /// 每次从别的界面进入时执行,不包括下面的界面切换,发生在FunctionLoaded之后 + /// 这个是有参数传入,常用于查询界面进入到操作界面发生 + /// + /// + public override void FunctionActivated(object param) + { + base.FunctionActivated(param); + groupNameTxt.Focus(); + } + /// + /// 当Page被选中时执行,用于Tab导航的切换,没有参数变化,跟FunctionActivated有区别 + /// + public override void FunctionSelected() + { + this.ParentAbstractForm.AcceptButton = this.searchBut; + this.ParentAbstractForm.CancelButton = this.resetBut; + + + groupNameTxt.Focus(); + } + /// + /// 控件的初始化 + /// + private void InitGui() + { + //DataGridView初始化不要自动生成列,且允许重排列名操作 + dataGv.InitColumn(false, true); + + dataGv.SetColumnDataSource(langCol, CulturePolicy.GetInstance().GetComposeMessages(), true); + + langCombo.SetDataSource(CulturePolicy.GetInstance().GetComposeMessages(), true); + + //初始化绑定设置 + InitBindingContext(); + //设置显示模式 + SetDisplayMode(true); + + InitGridViewPagination(); + } + /// + /// DataGridView分页控件初始化 + /// + private void InitGridViewPagination() + { + searchCriteria = new LocaleSearchCriteria(); + gridViewPagination.SetLimit(searchCriteria.limit); + gridViewPagination.OnPaginationChanged += Search; + gridViewPagination.OnPrint += Print; + } + + /// + /// 打印当前查询结果 + /// + private void Print() + { + //設置查詢條件 + List searCriteria = new List(); + if (!string.IsNullOrEmpty(groupNameTxt.Text)) + searCriteria.Add(groupNameLabel.Text + groupNameTxt.Text); + + //設置每列的格式 + TemplateHeader[] headers = dataGv.GetTemplateHeaders(); + + //打印Excel + new DataToExcelHelper(null).PrintExcel(this.Parent.Text, this.Parent.Text, searCriteria, headers, locales); + } + + /// + /// 有特殊要求的UI控件初始化设置,使用guiOperateHelper管理 + /// + private void InitBindingContext() + { + InitPermission(); + + nameCol.Set(EnumEditModeColor.Required); + orderByCol.Set(EnumEditModeColor.Required); + valueCol.Set(EnumEditModeColor.Required); + groupNameCol.Set(EnumEditModeColor.Required); + langCol.Set(EnumEditModeColor.Required); + + guiOperateHelper = new GuiOperateHelper(); + } + + private void InitPermission() + { + amendBut.Set(SecurityPermissionPolicy.Locale, Operate.Update); + } + + private void SetDisplayMode(bool enable) + { + guiOperateHelper.EnableControls(true, this.searchPanel); + guiOperateHelper.EnableControls(!enable, dataGv); + savePanel.Visible = !enable; + amendBut.Visible = gridViewPagination.Visible = enable; + guiOperateHelper.EnableControls(enable, amendBut); + + this.groupNameTxt.Focus(); + } + + private void searchBut_Click(object sender, EventArgs e) + { + HandleException(() => Search()); + } + + /// + /// 与Web同步写法 + /// + /// + private LocaleSearchCriteria PackSearchCriteria() + { + searchCriteria = new LocaleSearchCriteria(); + searchCriteria.limit = gridViewPagination.Limit; + searchCriteria.page = gridViewPagination.CurrentPage; + + List filters = new List(); + + SearchFilter filter = new SearchFilter(); + filter.Column = LocaleEntity.DB_GROUP_NAME; + filter.Type = SearchFilterTypePolicy.TEXT; + filter.Operator = SearchFilterOperatorPolicy.CONTAIN; + filter.Value = groupNameTxt.GetValue(); + filters.Add(filter); + + filter = new SearchFilter(); + filter.Column = LocaleEntity.DB_VALUE; + filter.Type = SearchFilterTypePolicy.TEXT; + filter.Operator = SearchFilterOperatorPolicy.CN_CONTAIN; + filter.Value = valueTxt.GetValue(); + filters.Add(filter); + + filter = new SearchFilter(); + filter.Column = LocaleEntity.DB_LANG; + filter.Type = SearchFilterTypePolicy.TEXT; + filter.Operator = SearchFilterOperatorPolicy.SINGLE; + filter.Value = (string)langCombo.GetValue(); + filters.Add(filter); + + filter = new SearchFilter(); + filter.Column = LocaleEntity.DB_NAME; + filter.Type = SearchFilterTypePolicy.TEXT; + filter.Operator = SearchFilterOperatorPolicy.CONTAIN; + filter.Value = nameTxt.GetValue(); + filters.Add(filter); + + + searchCriteria.Filter = filters.ToArray(); + + return searchCriteria; + } + + private void Search() + { + var data = localeRequest.FindBySearchCriteria(PackSearchCriteria()); + + if (data != null) locales = data.Datas; + + gridViewPagination.SetTotal(data.Total); + + if (locales == null || locales.Length == 0) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + guiOperateHelper.ResetControls(this.dataGv); + return; + } + + dataGv.SetDataSource(locales); + + SetDisplayMode(true); + } + + private void resetBut_Click(object sender, EventArgs e) + { + guiOperateHelper.ResetControls(this.mainPanel); + + SetDisplayMode(true); + } + + private void DisplayPage(GuiDisplayMode mode) + { + this.DisplayMode = mode; + + SetDisplayMode(false); + } + + + private void amendBut_Click(object sender, EventArgs e) + { + DisplayPage(GuiDisplayMode.Amend); + } + + private bool SaveValidate() + { + if (!guiOperateHelper.CheckValidate(this.dataGv)) return false; + + return true; + } + + private void saveBut_Click(object sender, EventArgs e) + { + HandleException(() => Save()); + } + + private void Save() + { + if (!SaveValidate()) return; + + LocaleData data = new LocaleData(); + data.Inserts = dataGv.GetAddRows(); + data.Updates = dataGv.GetUpdateRows(); + data.Deletes = dataGv.GetDeleteRows(); + + localeRequest.UpdateLocaleData(data); + + ShowMessageBox.ShowInfo((this.DisplayMode == GuiDisplayMode.Create) ? + securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_SUCCEED_CREATED_NULL) : + securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_SUCCEED_UPDATED_NULL)); + + Search(); + } + + private void addBut_Click(object sender, EventArgs e) + { + dataGv.AddRow(new LocaleEntity() { CreatedBy = string.Empty, UpdatedBy = string.Empty, CreatedDatetime = DateTime.Now, UpdatedDatetime = DateTime.Now }); + } + + private void delBut_Click(object sender, EventArgs e) + { + if (dataGv.RowCount <= 0 || dataGv.SelectedCells.Count <= 0) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + return; + } + + dataGv.DeleteRows(dataGv.SelectedCells); + } + + + private void cancelBut_Click(object sender, EventArgs e) + { + HandleException(() => Cancel()); + } + + private void Cancel() + { + this.DisplayMode = GuiDisplayMode.View; + + guiOperateHelper.ResetControls(this.dataGv); + + SetDisplayMode(true); + + Search(); + } + } +} diff --git a/CloudBuilder/CloudBuilder.Security.Gui/LocaleEnquiryPage.resx b/CloudBuilder/CloudBuilder.Security.Gui/LocaleEnquiryPage.resx new file mode 100644 index 0000000..40d0e41 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/LocaleEnquiryPage.resx @@ -0,0 +1,144 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Security.Gui/LoginForm.Designer.cs b/CloudBuilder/CloudBuilder.Security.Gui/LoginForm.Designer.cs new file mode 100644 index 0000000..ea06081 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/LoginForm.Designer.cs @@ -0,0 +1,200 @@ +namespace CloudBuilder.Security.Gui +{ + partial class LoginForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(LoginForm)); + mainPanel = new TableLayoutPanel(); + userLabel = new Krypton.Toolkit.KryptonLabel(); + passwordLabel = new Krypton.Toolkit.KryptonLabel(); + tableLayoutPanel2 = new TableLayoutPanel(); + loginBut = new Krypton.Toolkit.KryptonButton(); + cancelBut = new Krypton.Toolkit.KryptonButton(); + userNameTxt = new Krypton.Toolkit.KryptonTextBox(); + passwordTxt = new Krypton.Toolkit.KryptonTextBox(); + cultureLabel = new Krypton.Toolkit.KryptonLabel(); + cultureComboBox = new Krypton.Toolkit.KryptonComboBox(); + mainPanel.SuspendLayout(); + tableLayoutPanel2.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)cultureComboBox).BeginInit(); + SuspendLayout(); + // + // mainPanel + // + mainPanel.BackColor = Color.Transparent; + mainPanel.ColumnCount = 4; + mainPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 45F)); + mainPanel.ColumnStyles.Add(new ColumnStyle()); + mainPanel.ColumnStyles.Add(new ColumnStyle()); + mainPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 55F)); + mainPanel.Controls.Add(userLabel, 1, 2); + mainPanel.Controls.Add(passwordLabel, 1, 3); + mainPanel.Controls.Add(tableLayoutPanel2, 2, 4); + mainPanel.Controls.Add(userNameTxt, 2, 2); + mainPanel.Controls.Add(passwordTxt, 2, 3); + mainPanel.Controls.Add(cultureLabel, 1, 1); + mainPanel.Controls.Add(cultureComboBox, 2, 1); + mainPanel.Dock = DockStyle.Fill; + mainPanel.Location = new Point(0, 0); + mainPanel.Name = "mainPanel"; + mainPanel.RowCount = 5; + mainPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 50F)); + mainPanel.RowStyles.Add(new RowStyle()); + mainPanel.RowStyles.Add(new RowStyle()); + mainPanel.RowStyles.Add(new RowStyle()); + mainPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 50F)); + mainPanel.Size = new Size(452, 223); + mainPanel.TabIndex = 0; + // + // userLabel + // + userLabel.Location = new Point(93, 99); + userLabel.Name = "userLabel"; + userLabel.Size = new Size(38, 20); + userLabel.TabIndex = 111; + userLabel.Values.Text = "User:"; + // + // passwordLabel + // + passwordLabel.Location = new Point(93, 128); + passwordLabel.Name = "passwordLabel"; + passwordLabel.Size = new Size(65, 20); + passwordLabel.TabIndex = 111; + passwordLabel.Values.Text = "Password:"; + // + // tableLayoutPanel2 + // + tableLayoutPanel2.AutoSize = true; + tableLayoutPanel2.AutoSizeMode = AutoSizeMode.GrowAndShrink; + tableLayoutPanel2.BackColor = Color.Transparent; + tableLayoutPanel2.ColumnCount = 2; + tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel2.Controls.Add(loginBut, 0, 0); + tableLayoutPanel2.Controls.Add(cancelBut, 1, 0); + tableLayoutPanel2.Dock = DockStyle.Fill; + tableLayoutPanel2.Location = new Point(166, 157); + tableLayoutPanel2.Name = "tableLayoutPanel2"; + tableLayoutPanel2.RowCount = 1; + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.Size = new Size(172, 63); + tableLayoutPanel2.TabIndex = 3; + // + // loginBut + // + loginBut.Location = new Point(3, 3); + loginBut.Name = "loginBut"; + loginBut.Size = new Size(80, 25); + loginBut.TabIndex = 2; + loginBut.Values.Text = "Login"; + loginBut.Click += loginBut_Click; + // + // cancelBut + // + cancelBut.Location = new Point(89, 3); + cancelBut.Name = "cancelBut"; + cancelBut.Size = new Size(80, 25); + cancelBut.TabIndex = 3; + cancelBut.Values.Text = "Cancel"; + cancelBut.Click += cancelBut_Click; + // + // userNameTxt + // + userNameTxt.CharacterCasing = CharacterCasing.Upper; + userNameTxt.Dock = DockStyle.Fill; + userNameTxt.Location = new Point(166, 99); + userNameTxt.Name = "userNameTxt"; + userNameTxt.Size = new Size(172, 23); + userNameTxt.TabIndex = 0; + // + // passwordTxt + // + passwordTxt.Dock = DockStyle.Fill; + passwordTxt.Location = new Point(166, 128); + passwordTxt.Name = "passwordTxt"; + passwordTxt.PasswordChar = '*'; + passwordTxt.Size = new Size(172, 23); + passwordTxt.TabIndex = 1; + // + // cultureLabel + // + cultureLabel.Location = new Point(93, 71); + cultureLabel.Name = "cultureLabel"; + cultureLabel.Size = new Size(67, 20); + cultureLabel.TabIndex = 111; + cultureLabel.Values.Text = "Language:"; + // + // cultureComboBox + // + cultureComboBox.DropDownStyle = ComboBoxStyle.DropDownList; + cultureComboBox.DropDownWidth = 172; + cultureComboBox.IntegralHeight = false; + cultureComboBox.Location = new Point(166, 71); + cultureComboBox.Name = "cultureComboBox"; + cultureComboBox.Size = new Size(172, 22); + cultureComboBox.StateCommon.ComboBox.Content.TextH = Krypton.Toolkit.PaletteRelativeAlign.Near; + cultureComboBox.TabIndex = 112; + cultureComboBox.SelectionChangeCommitted += cultureComboBox_SelectionChangeCommitted; + // + // LoginForm + // + AutoScaleDimensions = new SizeF(7F, 15F); + AutoScaleMode = AutoScaleMode.Font; + BackgroundImage = Properties.Resources.Yo7OjL6wMwgA845AU; + BackgroundImageLayout = ImageLayout.Stretch; + ClientSize = new Size(452, 223); + Controls.Add(mainPanel); + DoubleBuffered = true; + FormBorderStyle = FormBorderStyle.None; + Icon = (Icon)resources.GetObject("$this.Icon"); + Name = "LoginForm"; + PaletteMode = Krypton.Toolkit.PaletteMode.Office2010Blue; + Text = "LoginForm"; + FormClosing += LoginForm_FormClosing; + mainPanel.ResumeLayout(false); + mainPanel.PerformLayout(); + tableLayoutPanel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)cultureComboBox).EndInit(); + ResumeLayout(false); + } + + #endregion + + private System.Windows.Forms.TableLayoutPanel mainPanel; + private Krypton.Toolkit.KryptonLabel userLabel; + private Krypton.Toolkit.KryptonLabel passwordLabel; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2; + private Krypton.Toolkit.KryptonButton loginBut; + private Krypton.Toolkit.KryptonButton cancelBut; + private Krypton.Toolkit.KryptonTextBox userNameTxt; + private Krypton.Toolkit.KryptonTextBox passwordTxt; + + private Krypton.Toolkit.KryptonLabel cultureLabel; + private Krypton.Toolkit.KryptonComboBox cultureComboBox; + } +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Security.Gui/LoginForm.cs b/CloudBuilder/CloudBuilder.Security.Gui/LoginForm.cs new file mode 100644 index 0000000..a0d38e3 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/LoginForm.cs @@ -0,0 +1,297 @@ +using CloudBuilder.Core.DependencyInjection.Request; +using CloudBuilder.Core.Service; +using CloudBuilder.Gui; +using CloudBuilder.Gui.DependencyInjection; +using CloudBuilder.Request.Security; +using CloudBuilder.Security.Data; +using CloudBuilder.Security.Entity; +using CloudBuilder.Security.Policy; +using DocumentFormat.OpenXml.Bibliography; +using Krypton.Toolkit; +using Microsoft.AspNetCore.Http.Extensions; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.IdentityModel.Tokens; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Net; +using System.Runtime.InteropServices; // 請加在 using 區 +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace CloudBuilder.Security.Gui +{ + public partial class LoginForm : AbstractForm + { + // Win32 API 设置可能拖动界面功能 + [DllImport("user32.dll")] + public static extern bool ReleaseCapture(); + [DllImport("user32.dll")] + public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam); + + private const int WM_NCLBUTTONDOWN = 0xA1; + private const int HTCAPTION = 0x2; + + private IContext loginContext; + private GuiOperateHelper guiOperateHelper; + protected GuiBindingContext guiBindingContext; + + private SecurityMessagePolicy securityMessagePolicy; + private LoginData loginData; + private bool complete = false; + private bool completeValidatedException = false; + + private BackgroundWorker _worker; + public LoginForm() + { + InitializeComponent(); + + // 允許整個表單拖動 + this.MouseDown += LoginForm_MouseDown; + this.mainPanel.MouseDown += LoginForm_MouseDown; + //设置居中对齐 + this.SetBounds((Screen.GetBounds(this).Width / 2) - (this.Width / 2), + (Screen.GetBounds(this).Height / 2) - (this.Height / 2), + this.Width, this.Height, BoundsSpecified.Location); + + InitializeBackgroundWorker(); + } + + private void InitializeBackgroundWorker() + { + _worker = new BackgroundWorker + { + WorkerReportsProgress = true, + WorkerSupportsCancellation = true + }; + + _worker.DoWork += Worker_DoWork; + } + + public void InitForm() + { + try + { + //语言本地化------------------------------------- + InitGuiComposeMessage(); + + //初始化容器------------------------------------- + loginContext = ServiceHelper.GetInterfaceService()!; + + securityMessagePolicy = ServiceHelper.GetTypeService()!; + + //创建“数据双向绑定”实例 + guiBindingContext = new GuiBindingContext(); + //创建“控件统一管理”实例 + guiOperateHelper = new GuiOperateHelper(); + + //初始化自定义属性,由数据双向绑定、控件统一管理------ + userNameTxt.Set(SecurityUserEntity.USER_MOBILE, userLabel.Text,EnumEditModeColor.Required); + passwordTxt.Set(SecurityUserEntity.USER_PASSWORD, passwordLabel.Text, EnumEditModeColor.Required); + + loginData = new LoginData(); + //控件绑定数据对象------------------------------------- + guiBindingContext.DataBind(loginData, this); + + //设置控件状态------------------------------------- + guiOperateHelper.EnableControls(true, this.mainPanel); + + //设置回车和Esc按钮 + this.AcceptButton = this.loginBut; + + this.CancelButton = this.cancelBut; + //设置初始化焦点 + userNameTxt.Focus(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void InitGuiComposeMessage() + { + //cultureComboBox绑定数据源 + cultureComboBox.SetDataSource(CulturePolicy.GetInstance().GetComposeMessages(), false); + //设置当前文化显示名称 + InitResourceManager(); + //userLabel.Text变了,绑定的也要变 + userNameTxt.Set(SecurityUserEntity.USER_MOBILE, userLabel.Text, EnumEditModeColor.Required); + passwordTxt.Set(SecurityUserEntity.USER_PASSWORD, passwordLabel.Text, EnumEditModeColor.Required); + } + + private void Login() + { + complete = false; + completeValidatedException = false; + + Task.Run(() => + { + for (int i = 1; i <= 90; i++) + { + if (completeValidatedException) + { + _worker.ReportProgress(100); + break; + } + if (complete) + { + _worker.ReportProgress(90); + break; + } + Thread.Sleep(50); + _worker.ReportProgress(i); + } + }); + + //从容器获取请求对象 + AuthRequest authRequest = ServiceHelper.GetTypeService(); + //获取RSA公钥 + string pubKey = authRequest.GetRsaPublicKey(); + //加密用户密码 + string guid = Guid.NewGuid().ToString(); + string psw = guid + EncryptHelper.GetMd5(loginData.UserPassword); + loginData.UserPassword = null; + var rsa = new RSA(pubKey, true); + loginData.Guid = guid; + loginData.RsaUserPassword = rsa.Encode(psw); + //设置当前文化 + loginData.Culture = loginContext.GetCulture(); + + LoginProfile loginProfile; + + loginProfile = authRequest.Login(loginData); + complete = true; + + //登录成功后设置登录上下文 + loginContext.Requestor = loginProfile.Username; + loginContext.SetPermissionInfo(loginProfile.PermissionInfo); + loginContext.SetToken(loginProfile.Token.AccessToken); + loginContext.LoginDate = DateTime.Now; + + //成功后关闭登录窗口 + for (int i = 91; i <= 100; i++) + { + Thread.Sleep(10); + _worker.ReportProgress(i); + } + + this.DialogResult = DialogResult.OK; + } + + private bool SaveValidate() + { + if (!guiOperateHelper.CheckValidate(this.mainPanel)) return false; + + return true; + } + + public void loginBut_Click(object sender, EventArgs e) + { + try + { + //将控件绑定到数据对象 + guiBindingContext.DataPack(); + //登录前验证 + if (!SaveValidate()) return; + //调用登录方法 + if (!_worker.IsBusy) + { + // 顯示進度條表單 + ProgressForm progressForm = new ProgressForm(_worker); + progressForm.Show(this); // this 表示主表單是擁有者 + + // 開始後台工作 + _worker.RunWorkerAsync(); + } + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void Worker_DoWork(object sender, DoWorkEventArgs e) + { + try + { + Login(); + } + catch (ValidatedException ex) + { + completeValidatedException = true; + _worker.ReportProgress(100); + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + completeValidatedException = true; + _worker.ReportProgress(100); + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + completeValidatedException = true; + _worker.ReportProgress(100); + ShowMessageBox.ShowError(ex.Message); + } + } + + private void cancelBut_Click(object sender, EventArgs e) + { + //关闭登录窗口 + this.DialogResult = DialogResult.Cancel; + } + + private void cultureComboBox_SelectionChangeCommitted(object sender, EventArgs e) + { + if (cultureComboBox.GetValue() == null || string.IsNullOrEmpty((string)cultureComboBox.GetValue())) return; + //设置全局文化变量 + loginContext.SetCulture((string)cultureComboBox.GetValue()); + //重新初始化,值会发生变化 + InitGuiComposeMessage(); + //重新设置当前文化 + cultureComboBox.SetValue(loginContext.GetCulture()); + } + + /// + /// 拖动窗口事件处理 + /// + private void LoginForm_MouseDown(object sender, MouseEventArgs e) + { + if (e.Button == MouseButtons.Left) + { + ReleaseCapture(); + SendMessage(this.Handle, WM_NCLBUTTONDOWN, HTCAPTION, 0); + } + } + + private void LoginForm_FormClosing(object sender, FormClosingEventArgs e) + { + var provider = ServiceHelper.GetService(); + provider.RemoveControlBinding(this.Controls); + } + } +} diff --git a/CloudBuilder/CloudBuilder.Security.Gui/LoginForm.resx b/CloudBuilder/CloudBuilder.Security.Gui/LoginForm.resx new file mode 100644 index 0000000..98e233d --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/LoginForm.resx @@ -0,0 +1,2823 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + AAABAAgAgIAAAAEAIAAoCAEAhgAAAGBgAAABACAAqJQAAK4IAQBISAAAAQAgAIhUAABWnQEAQEAAAAEA + IAAoQgAA3vEBADAwAAABACAAqCUAAAY0AgAgIAAAAQAgAKgQAACuWQIAGBgAAAEAIACICQAAVmoCABAQ + AAABACAAaAQAAN5zAgAoAAAAgAAAAAABAAABACAAAAAAAAAIAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPDEPATwyDwEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCNhABQjYQAUI3EAFCNxABQjcQAUM3EAFCNhACQjYQAkI3 + EAJCNxABQjcQAUI2EAFBNhABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABFOREBRTkRAUU5EQFGOhEBRjoRAUY6 + EQJFOREDRTkRBEU5EQVFOREFRTkRBkU5EQZFOREGRTkRBkU5EQVFOREFRTkRA0Y6EQJGOhEBAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABHOxIBRzsSAUc7 + EgFIOxIBSDsSAUg7EgJIOxIDRzsSBEc7EgVHOxIGRzsSB0c7EghHOxIJRzsSC0c7Eg1HOxIORzsSDkc7 + Eg5HOxINRzsSDEc7EgpHOxIIRzsSBUc7EgRIOxICRzsSAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABJPBIBSTwSAUk8EgFJPBIBSTwSAUk8EgJJPBIDSTwSBEk8EgVJPBIFSTwSB0k8EghJPBIJSTwSC0k8 + Eg1JPBIPSTwSEUk8EhNJPBIWSTwSGEk8EhpJPBIbSTwSGkk8EhlJPBIWSTwSE0k8Eg9JPBILSTwSCEk8 + EgVJPBIDSTwSAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABJPBIBSTwSAUk8EgFJPBIBSTwSAUk8EgJJPBIDSTwSBEk8EgVJPBIFSTwSB0k8 + EghJPBIJSTwSC0k8Eg1JPBIOSTwSEUk8EhNJPBIWSTwSGEk8EhtJPBIeSTwSIkk8EiVJPBIoSTwSK0k8 + EixJPBIrSTwSKUk8EiVJPBIgSTwSGkk8EhVJPBIPSTwSCkk8EgZJPBIDSTwSAQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASTwSAUk8EgFJPBIBSTwSAUk8EgJJPBIDSTwSBEk8 + EgVJPBIFSTwSB0k8EghJPBIJSTwSC0k8Eg1JPBIOSTwSEUk8EhNJPBIWSTwSGEk8EhtJPBIeSTwSIUk8 + EiVJPBIoSTwSLEk8EjBJPBI1STwSOUk8Ej1JPBJASTwSQUk8EkBJPBI9STwSOEk8EjFJPBIqSTwSIUk8 + EhhJPBIRSTwSC0k8EgZJPBIDSTwSAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASTwSAUk8EgFJPBIBSTwSAUk8 + EgFJPBICSTwSBEk8EgVJPBIFSTwSB0k8EghJPBIJSTwSC0k8Eg1JPBIOSTwSEUk8EhNJPBIWSTwSGEk8 + EhtJPBIeSTwSIUk8EiVJPBIoSTwSLEk8EjBJPBI0STwSOUk8Ej1JPBJBSTwSRkk8EktJPBJRSTwSVUk8 + EldJPBJZSTwSWEk8ElRJPBJOSTwSRkk8EjxJPBIxSTwSJUk8EhtJPBITSTwSDEk8EgdJPBIDSTwSAQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASTwSAUk8 + EgFJPBIBSTwSAUk8EgFJPBICSTwSA0k8EgRJPBIFSTwSBkk8EghJPBIJSTwSC0k8Eg1JPBIOSTwSEUk8 + EhNJPBIWSTwSGEk8EhtJPBIeSTwSIUk8EiVJPBIoSTwSLEk8EjBJPBI0STwSOUk8Ej1JPBJBSTwSRkk8 + EktJPBJQSTwSVUk8ElpJPBJfSTwSZEk8EmlJPBJtSTwScEk8EnFJPBJwSTwSbEk8EmVJPBJcSTwSUEk8 + EkNJPBI1STwSKEk8EhxJPBITSTwSDEk8EgdJPBIDSTwSAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAASTwSAUk8EgFJPBIBSTwSAUk8EgFJPBICSTwSA0k8EgRJPBIFSTwSBkk8EgdJPBIISTwSCkk8 + EgxJPBIOSTwSEEk8EhJJPBIVSTwSGEk8EhtJPBIeSTwSIUk8EiVJPBIoSTwSLEk8EjBJPBI0STwSOUk8 + Ej1JPBJBSTwSRkk8EktJPBJQSTwSVUk8ElpJPBJfSTwSZEk8EmlJPBJtSTwSckk8EndJPBJ8STwSgEk8 + EoRJPBKHSTwSh0k8EoZJPBKCSTwSe0k8EnFJPBJlSTwSVkk8EkdJPBI3STwSKUk8Eh1JPBITSTwSDEk8 + EgdJPBIDSTwSAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAASTwSAUk8EgFJPBIBSTwSAUk8EgFJPBICSTwSA0k8EgRJPBIFSTwSBUk8 + EgdJPBIISTwSCUk8EgtJPBINSTwSD0k8EhFJPBIUSTwSF0k8EhpJPBIdSTwSIEk8EiRJPBIoSTwSLEk8 + EjBJPBI0STwSOUk8Ej1JPBJBSTwSRkk8EktJPBJQSTwSVUk8ElpJPBJfSTwSZEk8EmlJPBJtSTwSckk8 + EndJPBJ8STwSgEk8EoRJPBKISTwSjFdJIp1pWDaydmVGyYVyV+SLd17xhXJX5HJhQcFQQhqUSTwShUk8 + EnlJPBJqSTwSWkk8EkhJPBI4STwSKkk8Eh1JPBITSTwSDEk8EgZJPBIDSTwSAQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASTwSAUk8EgFJPBIBSTwSAUk8EgFJPBICSTwSA0k8 + EgRJPBIFSTwSBUk8EgdJPBIISTwSCUk8EgtJPBINSTwSDkk8EhFJPBITSTwSFkk8EhhJPBIbSTwSH0k8 + EiJJPBImSTwSK0k8Ei9JPBIzSTwSOEk8Ej1JPBJBSTwSRkk8EktJPBJQSTwSVUk8ElpJPBJfSTwSZEk8 + EmlJPBJtSTwSckk8EndJPBJ8STwSgEk8EoRJPBKISTwSjFBCGpZjVDCrdmVGyYFvU96OemH4kX1l/5F9 + Zf+RfWX/kX1l/5WAaP+RfWX/kX1l/456YfhoWDa0STwSikk8EnxJPBJtSTwSW0k8EklJPBI5STwSKkk8 + EhxJPBITSTwSC0k8EgZJPBIDSTwSAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEk8EgFJPBIBSTwSAUk8 + EgFJPBICSTwSA0k8EgRJPBIFSTwSBUk8EgdJPBIISTwSCUk8EgtJPBINSTwSDkk8EhFJPBITSTwSFkk8 + EhhJPBIbSTwSHkk8EiFJPBIlSTwSKEk8Ei1JPBIxSTwSNkk8EjtJPBJASTwSRUk8EkpJPBJPSTwSVUk8 + ElpJPBJfSTwSZEk8EmlJPBJtSTwSckk8EndJPBJ8STwSgEk8EoRJPBKISTwSjEk8EpBjVDCrdmVGyYFv + U96Ld17ykX1l/5F9Zf+RfWX/kX1l/5F9Zf+jjXP/sJh9/76kiP/QtJb/2Luc/9i7nP+9o4f/mYRr/5F9 + Zf9tXDu9STwSjUk8En5JPBJtSTwSXEk8EklJPBI4STwSKUk8EhxJPBISSTwSCkk8EgVJPBICSTwSAQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEk8 + EgFJPBIBSTwSAUk8EgFJPBIBSTwSAkk8EgRJPBIFSTwSBUk8EgdJPBIISTwSCUk8EgtJPBINSTwSDkk8 + EhFJPBITSTwSFkk8EhhJPBIbSTwSHkk8EiFJPBIlSTwSKEk8EixJPBIwSTwSNEk8EjlJPBI9STwSQkk8 + EkdJPBJMSTwSUkk8EldJPBJdSTwSY0k8EmhJPBJtSTwSckk8EndJPBJ8STwSgEk8EoRJPBKISTwSjEk8 + EpBjVDCrcmFBwn5rT9iIdVrskX1l/5F9Zf+RfWX/kX1l/5F9Zf+eiXD/sJl//76lif/LsZT/2b2f/9m9 + nv/ZvJ7/2byd/9m8nf/Yu5z/2Luc/9i7nP/Yupv/q5N5/5F9Zf9tXDu+STwSjkk8En9JPBJtSTwSW0k8 + EkhJPBI2STwSJ0k8EhpJPBIQSTwSCUk8EgVJPBICAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAEk8EgFJPBIBSTwSAUk8EgFJPBIBSTwSAkk8EgNJPBIESTwSBUk8EgZJPBIISTwSCUk8 + EgtJPBINSTwSDkk8EhFJPBITSTwSFkk8EhhJPBIbSTwSHkk8EiFJPBIlSTwSKEk8EixJPBIwSTwSNEk8 + EjlJPBI9STwSQUk8EkZJPBJLSTwSUEk8ElVJPBJaSTwSX0k8EmRJPBJqSTwScEk8EnZJPBJ7STwSf0k8 + EoRJPBKISTwSjEk8EpBdTimlbV08vHpoStGIdVrskX1l/5F9Zf+RfWX/kX1l/5F9Zf+eiXD/rJZ8/7mi + h//HrpL/2b+i/9m+of/ZvqH/2b6g/9m9oP/ZvZ//2b2f/9m8nv/ZvJ7/2byd/9i7nf/Yu5z/2Luc/9i6 + m//Yupv/nIZt/5F9Zf9tXDu+STwSjkk8En1JPBJrSTwSWUk8EkVJPBIzSTwSJUk8EhhJPBIOSTwSCEk8 + EgRJPBIBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEk8EgFJPBIBSTwSAUk8EgFJPBIBSTwSAkk8EgNJPBIESTwSBUk8 + EgZJPBIHSTwSCEk8EgpJPBIMSTwSDkk8EhBJPBISSTwSFUk8EhhJPBIbSTwSHkk8EiFJPBIlSTwSKEk8 + EixJPBIwSTwSNEk8EjlJPBI9STwSQUk8EkZJPBJLSTwSUEk8ElVJPBJaSTwSX0k8EmRJPBJpSTwSbUk8 + EnJJPBJ3STwSfEk8EoFJPBKGSTwSi0k8EpBXSSKfbV08u3poStGEclflkX1l/5F9Zf+RfWX/kX1l/5F9 + Zf+ahW3/p5J5/7Wfhf/HsJX/2sCk/9nApP/ZwKP/2b+j/9m/ov/Zv6L/2b6h/9m+of/ZvqD/2b2g/9m9 + n//ZvZ//2bye/9m8nv/ZvJ3/2byd/9i7nP/Yu5z/2Lqb/9i6m/+4m4D/lH9n/5F9Zf9tXDu+STwSjEk8 + EntJPBJpSTwSVUk8EkJJPBIwSTwSIEk8EhRJPBILSTwSBkk8EgJJPBIBAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEk8EgFJPBIBSTwSAUk8EgFJPBIBSTwSAkk8 + EgNJPBIESTwSBUk8EgVJPBIHSTwSCEk8EglJPBILSTwSDUk8Eg9JPBIRSTwSFEk8EhdJPBIaSTwSHUk8 + EiBJPBIkSTwSKEk8EixJPBIwSTwSNEk8EjlJPBI9STwSQUk8EkZJPBJLSTwSUEk8ElVJPBJaSTwSX0k8 + EmRJPBJpSTwSbUk8EnJJPBJ3STwSfEk8EoBJPBKESTwSiEk8Eo1XSSKdaFg2s3ZlRsqEclfljnph+JF9 + Zf+RfWX/kX1l/5F9Zf+VgWn/p5J6/7Wghv/HsZb/1b2i/9rCpv/awab/2sGl/9rBpf/awKT/2cCk/9nA + o//Zv6P/2b+i/9m/ov/ZvqH/2b6h/9m+oP/ZvqD/2b2f/9m9n//ZvZ7/2bye/9m8nf/ZvJ3/2Luc/9i7 + nP/Yu5v/2Lqb/7mcgP+kim//lH9n/456YfldTimqSTwSikk8EnhJPBJkSTwST0k8EjtJPBIpSTwSGkk8 + Eg9JPBIISTwSBEk8EgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEk8EgFJPBIBSTwSAUk8 + EgFJPBIBSTwSAkk8EgNJPBIESTwSBUk8EgVJPBIHSTwSCEk8EglJPBILSTwSDUk8Eg5JPBIRSTwSE0k8 + EhZJPBIYSTwSG0k8Eh9JPBIiSTwSJkk8EitJPBIvSTwSM0k8EjhJPBI9STwSQUk8EkZJPBJLSTwSUEk8 + ElVJPBJaSTwSX0k8EmRJPBJpSTwSbUk8EnJJPBJ3STwSfEk8EoBJPBKESTwSiEk8EoxQQhqWY1Qwq3Zl + RsmBb1Pejnph+JF9Zf+RfWX/kX1l/5F9Zf+VgWn/o492/7Wgh//DrZT/0Lug/9rDqf/aw6j/2sOo/9rC + p//awqf/2sKm/9rBpv/awaX/2sGl/9rApP/ZwKT/2cCj/9nAo//Zv6L/2b+i/9m/ov/ZvqH/2b6h/9m+ + oP/ZvZ//2b2f/9m9nv/ZvJ7/2byd/9m8nf/Yu53/2Luc/9i7nP/Yupv/vJ+D/6aLcP+kiW//lH9m/456 + YfhdTimnSTwShUk8EnJJPBJdSTwSR0k8EjNJPBIhSTwSFEk8EgtJPBIFSTwSAgAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABJPBIBSTwSAUk8EgFJPBIBSTwSAkk8EgNJPBIESTwSBUk8EgVJPBIHSTwSCEk8EglJPBILSTwSDUk8 + Eg5JPBIRSTwSE0k8EhZJPBIYSTwSG0k8Eh5JPBIhSTwSJUk8EihJPBItSTwSMUk8EjZJPBI7STwSQEk8 + EkVJPBJKSTwST0k8ElVJPBJaSTwSX0k8EmRJPBJpSTwSbUk8EnJJPBJ3STwSfEk8EoBJPBKESTwSiEk8 + EoxJPBKQY1Qwq3JhQcKBb1Pei3de8pF9Zf+RfWX/kX1l/5F9Zf+RfWX/o493/7GchP+/qpH/zbee/9rF + q//axav/2sSq/9rEqv/axKn/2sOp/9rDqP/aw6j/2sKn/9rCp//awqb/2sGm/9rBpv/awaX/2sGl/9nA + pP/ZwKT/2cCj/9m/o//Zv6L/2b+i/9m+of/ZvqH/2b6g/9m9oP/ZvZ//2b2f/9m8nv/ZvJ7/2byd/9i7 + nf/Yu5z/2Luc/9i6m/+/oob/potw/6WKcP+jiW7/lH9m/456YfheTyqjSTwSfkk8EmlJPBJSSTwSPEk8 + EilJPBIZSTwSDkk8EgdJPBICRzsSAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAASTwSAUk8EgFJPBIBSTwSAUk8EgJJPBIESTwSBUk8EgVJPBIHSTwSCEk8 + EglJPBILSTwSDUk8Eg5JPBIRSTwSE0k8EhZJPBIYSTwSG0k8Eh5JPBIhSTwSJUk8EihJPBIsSTwSMEk8 + EjRJPBI5STwSPUk8EkJJPBJHSTwSTEk8ElJJPBJXSTwSXUk8EmNJPBJoSTwSbUk8EnJJPBJ3STwSfEk8 + EoBJPBKESTwSiEk8EoxJPBKQY1Qwq3JhQcJ+a0/YiHVa7JF9Zf+RfWX/kX1l/5F9Zf+RfWX/notz/6yZ + gf+/q5P/zbmh/9vHrv/bxq7/28at/9vGrP/bxaz/2sWr/9rFq//axKr/2sSq/9rEqf/aw6n/2sOp/9rD + qP/aw6j/2sKn/9rCp//awqb/2sGm/9rBpf/awaX/2sCk/9nApP/ZwKP/2b+j/9m/ov/Zv6L/2b6h/9m+ + of/ZvqD/2b2g/9m9n//ZvZ//2bye/9m8nv/ZvJ3/2byd/9i7nP/Yu5z/2Lub/7+ihv+mi3D/pYpw/6WK + b/+ih23/kn1l/456YfhRQxuNSTwSckk8EltJPBJESTwSL0k8Eh5JPBIRSTwSCUk8EgNHOxIBAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASTwSAUk8EgFJPBICSTwSA0k8 + EgRJPBIGSTwSCEk8EglJPBILSTwSDUk8Eg5JPBIRSTwSE0k8EhZJPBIYSTwSG0k8Eh5JPBIhSTwSJUk8 + EihJPBIsSTwSMEk8EjRJPBI5STwSPUk8EkFJPBJGSTwSS0k8ElBJPBJVSTwSWkk8El9JPBJkSTwSakk8 + EnBJPBJ2STwSe0k8En9JPBKESTwSiEk8EoxJPBKQXU4ppW1dPLx6aErRhHJX5ZF9Zf+RfWX/kX1l/5F9 + Zf+RfWX/notz/6yZgf+6p5D/yLae/9vIsf/byLD/28iw/9vHr//bx6//28eu/9vGrv/bxq3/28at/9vF + rP/bxaz/2sWr/9rFq//axKr/2sSq/9rEqf/aw6n/2sOo/9rDqP/awqf/2sKn/9rCpv/awab/2sGl/9rB + pf/awKT/2cCk/9nAo//Zv6P/2b+i/9m/ov/ZvqH/2b6h/9m+oP/ZvqD/2b2f/9m9n//ZvZ7/2bye/9m8 + nf/ZvJ3/2Luc/9i7nP/Yu5v/v6OG/6aLcP+minD/pYpv/6WJbv+ghmz/kn1l/4ZzWOFJPBJ6STwSY0k8 + EktJPBI1STwSIkk8EhNJPBIKSTwSBEg7EgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAEk8EgFJPBICSTwSBEk8EgZJPBIISTwSCkk8Eg1JPBIQSTwSEkk8EhVJPBIYSTwSG0k8 + Eh5JPBIhSTwSJUk8EihJPBIsSTwSMEk8EjRJPBI5STwSPUk8EkFJPBJGSTwSS0k8ElBJPBJVSTwSWkk8 + El9JPBJkSTwSaUk8Em1JPBJySTwSd0k8EnxJPBKBSTwShkk8EotJPBKQV0kin2hYNrV6aErRhHJX5ZF9 + Zf+RfWX/kX1l/5F9Zf+RfWX/moZv/6iVfv+2pIz/ybeg/9fFrv/byrP/28my/9vJsv/bybH/28ix/9vI + sP/byLD/28ev/9vHr//bx67/28eu/9vGrf/bxq3/28as/9vFrP/axav/2sWr/9rEqv/axKr/2sSp/9rD + qf/aw6j/2sOo/9rCp//awqf/2sKm/9rBpv/awaX/2sGl/9rApP/ZwKT/2cCj/9nAo//Zv6P/2b+i/9m/ + ov/ZvqH/2b6h/9m+oP/ZvZ//2b2f/9m9nv/ZvJ7/2byd/9m8nf/Yu53/2Luc/9i7nP+/o4b/potw/6aK + cP+lim//pYlu/6SIbf+ehGr/kX1l/2tbOaVJPBJpSTwSUEk8EjlJPBIlSTwSFkk8EgtJPBIFSDsSAQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEY6EQFIOxIBSTwSBEk8EgZJPBIJSTwSDEk8 + EhBJPBIUSTwSGEk8EhxJPBIgSTwSJEk8EihJPBIsSTwSMEk8EjRJPBI5STwSPUk8EkFJPBJGSTwSS0k8 + ElBJPBJVSTwSWkk8El9JPBJkSTwSaUk8Em1JPBJySTwSd0k8EnxJPBKASTwShEk8EohJPBKNV0kinWhY + NrN2ZUbKhHJX5Y56YfiRfWX/kX1l/5F9Zf+RfWX/lYJq/6ORef+2pI7/ybih/9fHsP/cy7X/3Mu1/9zL + tP/cy7T/3Mqz/9vKs//bybL/28my/9vJsf/bybH/28iw/9vIsP/byK//28ev/9vHrv/bx67/28at/9vG + rf/bxqz/28Ws/9rFq//axav/2sSq/9rEqv/axKn/2sOp/9rDqP/aw6j/2sKn/9rCp//awqb/2sGm/9rB + pv/awaX/2sGl/9nApP/ZwKT/2cCj/9m/o//Zv6L/2b+i/9m+of/ZvqH/2b6g/9m9oP/ZvZ//2b2f/9m8 + nv/ZvJ7/2byd/9i7nf/Yu5z/2Luc/7+jhv+mi3H/popw/6WKb/+liW7/pIlu/6SIbf+Vf2f/hnNZ3kk8 + Em1JPBJUSTwSPEk8EidJPBIXSTwSDEk8EgVIOxIBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAARjoRAkg7EgRJPBIHSTwSC0k8EhBJPBIWSTwSHEk8EiJJPBIoSTwSLUk8EjNJPBI4STwSPUk8 + EkFJPBJGSTwSS0k8ElBJPBJVSTwSWkk8El9JPBJkSTwSaUk8Em1JPBJySTwSd0k8EnxJPBKASTwShEk8 + EohJPBKMUEIalmNUMKt2ZUbJgW9T3ot3XvKRfWX/kX1l/5F9Zf+RfWX/lYJq/6ORev+2pY//xLSe/9LD + rf/czbj/3M23/9zNt//czLb/3My2/9zLtf/cy7X/3Mu0/9zLtP/cyrP/28qz/9vKsv/bybL/28mx/9vJ + sf/byLD/28iw/9vIr//bx6//28ev/9vHrv/bxq7/28at/9vGrP/bxaz/2sWr/9rFq//axKr/2sSq/9rE + qf/aw6n/2sOp/9rDqP/aw6j/2sKn/9rCp//awqb/2sGm/9rBpf/awaX/2sCk/9nApP/ZwKP/2b+j/9m/ + ov/Zv6L/2b6h/9m+of/ZvqD/2b2g/9m9n//ZvZ//2bye/9m8nv/ZvJ3/2byd/9i7nP/Yu5z/y6+R/6aL + cf+minD/pYpv/6WJbv+kiW7/pIht/5yDav+RfWX/WkwmgEk8ElhJPBI/STwSKkk8EhlJPBINSTwSBkg7 + EgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEQ4EAFGOhEDSDsSB0k8EgxJPBISSTwSGkk8 + EiNJPBIsSTwSNEk8EjxJPBJDSTwSSUk8Ek9JPBJUSTwSWkk8El9JPBJkSTwSaUk8Em1JPBJySTwSd0k8 + EnxJPBKASTwShEk8EohJPBKMSTwSkGNUMKtyYUHCgW9T3ot3XvKRfWX/kX1l/5F9Zf+RfWX/kX1l/6SR + ev+yoYv/wLCb/86/qv/cz7r/3M+6/9zOuf/czrn/3M24/9zNuP/czbf/3M23/9zMtv/czLb/3My1/9zL + tf/cy7T/3Mu0/9zKs//byrP/28qz/9vJsv/bybL/28mx/9vIsf/byLD/28iw/9vHr//bx6//28eu/9vG + rv/bxq3/28at/9vFrP/bxaz/2sWr/9rFq//axKr/2sSq/9rEqf/aw6n/2sOo/9rDqP/awqf/2sKn/9rC + pv/awab/2sGl/9rBpf/awKT/2cCk/9nAo//Zv6P/2b+i/9m/ov/ZvqH/2b6h/9m+oP/ZvqD/2b2f/9m9 + n//ZvZ7/2bye/9m8nf/ZvJ3/2Luc/9i7nP/Lr5H/potx/6aLcP+lim//pYlv/6SJbv+kiG3/oods/5F9 + Zf9oWDaSSTwSW0k8EkJJPBItSTwSG0k8Eg9JPBIHSDsSAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAARDgQAkY6EQVIOxILSTwSEkk8EhxJPBInSTwSMkk8Ej5JPBJJSTwSU0k8EltJPBJhSTwSZ0k8 + Em1JPBJySTwSd0k8EnxJPBKASTwShEk8EohJPBKMSTwSkGNUMKtyYUHCfmtP2Ih1WuyRfWX/kX1l/5F9 + Zf+RfWX/kX1l/5+Mdf+tnIb/wLGc/87Brf/d0b3/3dC8/93QvP/d0Lz/3c+7/93Pu//cz7r/3M65/9zO + uf/czrj/3M24/9zNt//czbf/3My2/9zMtv/czLb/3Mu1/9zLtf/cy7T/3Mq0/9zKs//byrP/28my/9vJ + sv/bybH/28ix/9vIsP/byLD/28ev/9vHr//bx67/28eu/9vGrf/bxq3/28as/9vFrP/axav/2sWr/9rE + qv/axKr/2sSp/9rDqf/aw6j/2sOo/9rCp//awqf/2sKm/9rBpv/awaX/2sGl/9rApP/ZwKT/2cCj/9nA + o//Zv6P/2b+i/9m/ov/ZvqH/2b6h/9m+oP/ZvZ//2b2f/9m9nv/ZvJ7/2byd/9m8nf/Yu53/2Luc/8uv + kf+mi3H/potw/6WKb/+liW//pIlu/6SIbf+jh2z/kX1l/3ppS7dJPBJeSTwSRUk8Ei9JPBIdSTwSEEk8 + EghIOxIDRTkRAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD40DwFEOBADRjoRCEg7EhBJPBIaSTwSJ0k8 + EjVJPBJDSTwSUUk8El9JPBJpSTwSckk8EnlJPBJ+STwSg0k8EohJPBKMSTwSkF1OKaVtXTy8emhK0YRy + V+WRfWX/kX1l/5F9Zf+RfWX/kX1l/5+Ndv+tnYf/u62Y/8q9qf/d0r//3dK//93Sv//d0b7/3dG+/93R + vf/d0L3/3dC8/93QvP/dz7v/3c+7/9zPuv/czrr/3M65/9zOuf/czbj/3M24/9zNt//czLf/3My2/9zM + tv/cy7X/3Mu1/9zLtP/cy7T/3Mqz/9vKs//bybL/28my/9vJsf/bybH/28iw/9vIsP/byK//28ev/9vH + rv/Vwaj/vKeN/6iSd/+eh23/inNY/4pzWP+Kc1j/mYJn/6OMcf+8pYv/1b6j/9rDqP/aw6j/2sKn/9rC + p//awqb/2sGm/9rBpv/awaX/2sGl/9nApP/ZwKT/2cCj/9m/o//Zv6L/2b+i/9m+of/ZvqH/2b6g/9m9 + oP/ZvZ//2b2f/9m8nv/ZvJ7/2byd/9i7nf/Yu5z/y6+R/6aLcf+mi3D/pYpv/6WJb/+kiW7/pIht/6OH + bP+RfWX/emhLuUk8EmFJPBJISTwSMkk8Eh9JPBISSTwSCUg7EgNFOREBAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAPzQPAkQ4EAZGOhEMSDsSFUk8EiJJPBIySTwSREk8ElVJPBJlSTwSc0k8En9JPBKHSTwSjldJ + Ip5oWDa0emhK0YRyV+WRfWX/kX1l/5F9Zf+RfWX/kX1l/5qIcP+pmIL/t6iU/8q+q//Zzrz/3dTC/93T + wf/d08H/3dLA/93SwP/d0r//3dK//93Rvv/d0b7/3dG9/93Qvf/d0Lz/3dC8/93Pu//dz7v/3M+6/9zO + uv/czrn/3M65/9zNuP/czbj/3M23/9zNt//czLb/3My2/9zLtf/cy7X/3Mu0/9zLtP/cyrP/28qz/9vK + sv/bybL/28mx/9vJsf/byLD/28iw/9vIr//Vwqn/sp2D/494Xf+Kc1j/inNY/4pzWP+Kc1j/inNY/4pz + WP+Kc1j/inNY/4pzWP+Kc1j/qJF2/9C5nv/aw6j/2sKn/9rCp//awqb/2sGm/9rBpf/awaX/2sCk/9nA + pP/ZwKP/2b+j/9m/ov/Zv6L/2b6h/9m+of/ZvqD/2b2g/9m9n//ZvZ//2bye/9m8nv/ZvJ3/2byd/9i7 + nP/Lr5H/p4tx/6aLcP+linD/pYlv/6SJbv+kiG3/o4ht/5F9Zf95aEq7STwSZUk8EkxJPBI1STwSIkk8 + EhNJPBIJRzsSBEY6EQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/NA8DRDgQCEY6ERBIOxIbSTwSK0k8 + Ej1JPBJRSTwSZVJEHH5rWjmod2VHxoVyV+SOemH4kX1l/5F9Zf+RfWX/kX1l/5WCa/+kk33/t6mV/8W6 + p//Z0L//3tXE/97VxP/e1cP/3tTD/97Uwv/d1ML/3dPB/93Twf/d08D/3dLA/93Sv//d0r//3dG+/93R + vv/d0b3/3dC9/93QvP/d0Lz/3c+7/93Pu//cz7r/3M+6/9zOuf/czrn/3M24/9zNuP/czbf/3M23/9zM + tv/czLb/3My1/9zLtf/cy7T/3Mu0/9zKs//byrP/28qz/9vJsv/bybL/28mx/9vIsf/byLD/wa2U/494 + Xf+Kc1j/inNY/4pzWP+Kc1j/n414/7Cikv+2qpz/saOU/6CPev+PemD/inNY/4pzWP+Kc1j/j3hd/7eg + hf/awqf/2sKn/9rCpv/awab/2sGl/9rBpf/awKT/2cCk/9nAo//Zv6P/2b+i/9m/ov/ZvqH/2b6h/9m+ + oP/ZvqD/2b2f/9m9n//ZvZ7/2bye/9m8nf/ZvJ3/2Luc/8uvkf+ni3H/potw/6WKcP+liW//pIlu/6SI + bf+jiG3/kX1l/3lnSrxJPBJoSTwST0k8EjhJPBIkSTwSFUk8EgpHOxIFRjoRAQAAAAAAAAAAAAAAAAAA + AAAAAAAAOS8OAT80DwREOBAKRjoRE0g7EiFJPBIzSTwSR0k8Elx7aUy2jnti9pF9Zf+RfWX/kX1l/5F9 + Zf+kk37/t6qW/8W7qf/Uy7v/3tfH/97Xxv/e1sb/3tbF/97Wxf/e1cT/3tXE/97Vw//e1MP/3tTC/93U + wv/d08H/3dPB/93TwP/d0sD/3dK//93Sv//d0b7/3dG+/93Rvf/d0b3/3dC8/93QvP/d0Lz/3c+7/93P + u//cz7r/3M65/9zOuf/czrj/3M24/9zNt//czbf/3My2/9zMtv/czLb/3Mu1/9zLtf/cy7T/3Mq0/9zK + s//byrP/28my/9vJsv/bybH/28mx/62Yfv+Kc1j/inNY/4pzWP+Uf2f/vbKl/9fTzv/e29j/393a/+De + 3P/i4N//4+Lh/+Tj4v/Iwbj/oI97/4pzWP+Kc1j/inNY/6OLcP/VvaL/2sKm/9rBpv/awaX/2sGl/9rA + pP/ZwKT/2cCj/9nAo//Zv6P/2b+i/9m/ov/ZvqH/2b6h/9m+oP/ZvZ//2b2f/9m9nv/ZvJ7/2byd/9m8 + nf/Yu53/2Luc/6eLcf+mi3D/pYpw/6WKb/+kiW7/pIht/6OIbf+Uf2b/eWdJvkk8EmtJPBJSSTwSOkk8 + EiZJPBIWSTwSC0c7EgVGOhEBAAAAAAAAAAAAAAAAAAAAAAgdMQE5Lw4BPzQPBUQ4EAtGOhEWSDsSJUk8 + EjhJPBJOiXZc1ZF9Zf+aiHH/s6WR/8G2pP/Qx7f/39nJ/97Yyf/e2Mj/3tjI/97Xx//e18f/3tfG/97W + xv/e1sX/3tbF/97VxP/e1cT/3tXD/97Uw//e1ML/3tTC/93Twf/d08H/3dPA/93SwP/d0r//3dK//93S + v//d0b7/3dG+/93Rvf/d0L3/3dC8/93QvP/dz7v/3c+7/9zPuv/czrr/3M65/9zOuf/czbj/3M24/9zN + t//czLf/3My2/9zMtv/cy7X/3Mu1/9zLtP/cy7T/3Mqz/9vKs//bybL/28my/9vJsf+ok3n/inNY/4pz + WP+OeF//taiZ/9jTzv/a1dD/29fT/9zY1P/d2tb/3tvY/9/d2v/g3tz/4uDf/+Pi4f/k4+L/yMG4/496 + YP+Kc1j/inNY/5mBZv/VvaL/2sGm/9rBpv/awaX/2sGl/9nApP/ZwKT/2cCj/9m/o//Zv6L/2b+i/9m+ + of/ZvqH/2b6g/9m9oP/ZvZ//2b2f/9m8nv/ZvJ7/2byd/9i7nf/Yu5z/p4tx/6aLcP+linD/pYpv/6SJ + bv+kiG3/o4ht/5V/Z/95Z0m/STwSbUk8ElNJPBI8STwSJ0k8EhdJPBILRzsSBUY6EQEAAAAAAAAAAAAA + AAAAAAAACB0xATkvDgI/NA8GRDgQDUY6ERhIOxIoSTwSPHhmSJGRfWX/uKuY/9/ay//f2sv/39nK/9/Z + yv/f2cn/3tjJ/97Yyf/e2Mj/3tfI/97Xx//e18b/3tbG/97Wxf/e1sX/3tXE/97VxP/e1cP/3tTD/97U + w//e1ML/3dTC/93Twf/d08H/3dPA/93SwP/d0r//3dK//93Rvv/d0b7/3dG9/93Qvf/d0Lz/3dC8/93P + u//dz7v/3M+6/9zOuv/czrn/3M65/9zNuP/czbj/3M23/9zNt//czLb/3My2/9zLtf/cy7X/3Mu0/9zL + tP/cyrP/28qz/9vKsv/bybL/sp6F/4pzWP+Kc1j/jnhe/8a8sf/Vzsj/1tDK/9fSzP/Y087/yL2y/7mo + l/+rlX//oohv/5p9Yf+rlX//sJuI/8K1qP/a1dH/2NXR/5qIcv+Kc1j/inNY/6OLcP/awqb/2sGm/9rB + pf/awaX/2sCk/9nApP/ZwKP/2b+j/9m/ov/Zv6L/2b6h/9m+of/ZvqD/2b2g/9m9n//ZvZ//2bye/9m8 + nv/ZvJ3/2byd/9i7nP+njHH/potw/6aKcP+lim//pYlu/6SIbf+kiG3/lX9n/4ZzWd9JPBJuSTwSVUk8 + Ej1JPBIoSTwSF0k8EgtHOxIFRjoRAQAAAAAAAAAAAAAAAAAAAAAIHTEBOS8OAj80DwZEOBANRjoRGEg7 + EihJPBI8i3dez6mahf/f2sz/39rM/9/ay//f2cv/39nK/9/Zyv/e2Mn/3tjJ/97YyP/e18j/3tfH/97X + xv/e1sb/3tbG/97Wxf/e1sX/3tXE/97VxP/e1cP/3tTD/97Uwv/d1ML/3dPB/93Twf/d08D/3dLA/93S + v//d0r//3dG+/93Rvv/d0b3/3dC9/93QvP/d0Lz/3c+7/93Pu//cz7r/3M+6/9zOuf/czrn/3M64/9zN + uP/czbf/3M23/9zMtv/czLb/3My1/9zLtf/cy7T/3Mu0/9zKs//byrP/28qz/8azm/+Kc1j/inNY/454 + Xv/DuKz/0srC/9PMxP/Uzcb/wLKj/6uUff+li3L/oYds/52CZv+afWH/mn1h/5p9Yf+afWH/mn1h/5p9 + Yf+1opD/1M7I/5qHcf+Kc1j/inNY/7Kaf//awab/2sGl/9rBpf/awKT/2cCk/9nAo//Zv6P/2b+i/9m/ + ov/ZvqH/2b6h/9m+oP/ZvqD/2b2f/9m9n//ZvZ7/2bye/9m8nf/ZvJ3/2Luc/6eMcf+mi3D/popw/6WK + b/+liW7/pIht/6SIbf+Vf2f/hnNZ30k8Em9JPBJWSTwSPUk8EihJPBIYSTwSDEc7EgVGOhEBAAAAAAAA + AAAAAAAAAAAAAAgdMQE5Lw4CPzQPBUQ4EAxGOhEXSDsSJ0k8EjyLd17PuKyZ/9/azP/f2sz/39rL/9/Z + y//f2cr/39nK/97Yyf/e2Mn/3tjI/97YyP/e18f/3tfH/97Xxv/e1sb/3tbF/97Wxf/e1cT/3tXE/97V + w//e1MP/3tTC/93Uwv/d08H/3dPB/93TwP/d0sD/3dK//93Sv//d0b7/3dG+/93Rvf/d0b3/3dC8/93Q + vP/d0Lz/3c+7/93Pu//cz7r/3M65/9zOuf/czrj/3M24/9zNt//czbf/3My3/9zMtv/czLb/3Mu1/9zL + tf/cy7T/3Mq0/9zKs//byrP/lH1j/4pzWP+Kc1j/vK+h/87FvP/Px77/y8G2/7ilk/+umYL/q5R8/6eP + d/+kinH/oIVq/5yAZP+afWH/mn1h/5p9Yf+afWH/mn1h/5p9Yf+eg2j/va6f/495YP+Kc1j/inNY/8uy + l//awaX/2sGl/9rApP/ZwKT/2cCj/9nAo//Zv6P/2b+i/9m/ov/ZvqH/2b6h/9m+oP/ZvZ//2b2f/9m9 + nv/ZvJ7/2bye/9m8nf/Yu53/p4xx/6aLcP+minD/pYpv/6WJbv+kiG3/pIht/5V/Z/+Gc1nfSTwSb0k8 + ElZJPBI+STwSKUk8EhhJPBIMRzsSBUY6EQEAAAAAAAAAAAAAAAAAAAAACB0xATkvDgE/NA8FRDgQDEY6 + ERZIOxImSTwSO4t3Xs+uoIz/39rM/9/azP/f2sv/39rL/9/Zyv/f2cr/39nJ/97Yyf/e2Mj/3tjI/97X + x//e18f/3tfG/97Wxv/e1sX/3tbF/97VxP/e1cT/3tXD/97Uw//e1ML/3tTC/93Twf/d08H/3dPA/93S + wP/d0sD/3dK//93Sv//d0b7/3dG+/93Rvf/d0L3/3dC8/93QvP/dz7v/3c+7/9zPuv/czrr/3M65/9zO + uf/czbj/3M24/9zNt//czLf/3My2/9zMtv/cy7X/3Mu1/9zLtP/cy7T/3Mqz/7Kehf+Kc1j/inNY/6mZ + hv/LwLb/zMK4/8m+s/+5p5X/taGN/7Gdh/+umIH/qpN7/6aOdf+jiW7/noNo/5t+Yv+afWH/mn1h/5p9 + Yf+afWH/mn1h/5p9Yf+afWH/mYBm/4pzWP+Kc1j/noZr/9rBpv/awaX/2sGl/9nApP/ZwKT/2cCj/9m/ + o//Zv6L/2b+i/9m+of/ZvqH/2b6g/9m9oP/ZvZ//2b2f/9m8nv/ZvJ7/2byd/9i7nf+njHH/potx/6aK + cP+lim//pYlu/6SJbv+kiG3/lX9n/4ZzWd9JPBJvSTwSVkk8Ej5JPBIpSTwSGEk8EgxHOxIFRjoRAQAA + AAAAAAAAAAAAAAAAAAAAAAAAOS8OAT80DwREOBALRjoRFUg7EiRJPBI4i3hezqSUf//f28z/39rM/9/a + y//f2sv/39nK/9/Zyv/f2cn/3tjJ/9nSwv/Nwa7/zcCu/97Xx//e18b/3tbG/97Wxf/e1sX/3tXE/97V + xP/e1cP/3tTD/97Uw//e1ML/3dTC/93Twf/d08H/3dPA/93SwP/d0r//3dK//93Rvv/d0b7/3dG9/93Q + vf/d0Lz/3dC8/93Pu//dz7v/3M+6/9zOuv/czrn/3M65/9zNuP/czbj/3M23/9zNt//czLb/3My2/9zM + tf/cy7X/3Mu0/9zLtP/cyrP/lH1j/4pzWP+Nd13/w7eq/8i9sv/IvLH/v6+e/7uqmP+4pZL/tKCM/7Gb + hv+tloD/qZF5/6WMcv+hhmz/nYBk/5p9Yf+afWH/mn1h/5p9Yf+afWH/mn1h/5p9Yf+afWH/k3hd/4pz + WP+Kc1j/xq2S/9rBpf/awaX/2sCk/9nApP/ZwKP/2b+j/9m/ov/Zv6L/2b6h/9m+of/ZvqD/2b2g/9m9 + n//ZvZ//2bye/9m8nv/ZvJ3/2byd/7OXfP+mi3H/popw/6WKb/+liW7/pIlu/6SIbf+agmn/hnNY30k8 + EnBJPBJWSTwSPkk8EilJPBIYSTwSDEc7EgVGOhEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPzQPA0Q4 + EApGOhETSDsSIkk8EjaBblKjmohy/9/bzP/f2sz/39rM/9/ay//f2cv/39nK/9/Zyv/EtqH/mn1g/5p9 + YP+afWD/po1z/9nRwP/e1sb/3tbG/97Wxf/e1sX/3tXE/97VxP/e1cP/3tTD/97Uwv/d1ML/3dPB/93T + wf/d08D/3dLA/93Sv//d0r//3dG+/93Rvv/d0b3/3dC9/93QvP/d0Lz/3c+7/93Pu//cz7r/3M+6/9zO + uf/czrn/3M64/9zNuP/czbf/3M23/9zMtv/czLb/3My1/9zLtf/cy7T/3Mu0/72pkf+Kc1j/inNY/6eV + gf/FuKz/xrqu/8W3qf/CsqL/vq6d/7upl/+3pJH/s5+L/6+ahP+rlH3/oYhw/5Z8Y/+Sd17/kHVb/5V5 + Xv+afWH/mn1h/5p9Yf+afWH/mn1h/5p9Yf+afWH/j3Za/4pzWP+okHX/2sGl/9rBpf/awKT/2cCk/9nA + o//Zv6P/2b+i/9m/ov/ZvqH/2b6h/9m+oP/ZvqD/2b2f/9m9n//ZvZ7/2bye/9m8nf/ZvJ3/s5h8/6aL + cf+mi3D/pYpv/6WJb/+kiW7/pIht/5qCaf+Gc1jfSTwScEk8ElZJPBI+STwSKUk8EhhJPBIMRzsSBUY6 + EQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/NA8DRDgQCUY6ERJIOxIgSTwSNIFvU6KRfWX/39vN/9/a + zP/f2sz/39rL/9/Zy//f2cr/1s28/5p9YP++rp3/2tLL/8a4qf+dgWX/wK+Z/97Xxv/e1sb/3tbF/97W + xf/e1cT/3tXE/97Vw//e1MP/3tTC/93Uwv/d08H/3dPB/93TwP/d0sD/3dK//93Sv//d0b7/3dG+/93R + vf/d0b3/3dC8/93QvP/d0Lz/3c+7/93Pu//cz7r/3M65/9zOuf/czrj/3M24/9zNt//czbf/3My3/9zM + tv/czLb/3Mu1/9zLtf/cy7T/o450/4pzWP+Kc1j/vrCh/8O1qP/Huq3/yLqs/8W2p//BsqL/vq2c/7qo + lf+2oo//qpR+/5B3YP+HbVX/h21V/4dtVf+HbVX/h21V/4lvVv+VeV7/mn1h/5p9Yf+afWH/mn1h/5p9 + Yf+ZfGD/i3NY/4pzWP/VvKD/2sGl/9rApP/ZwKT/2cCk/9nAo//Zv6P/2b+i/9m/ov/ZvqH/2b6h/9m+ + oP/ZvZ//2b2f/9m9nv/ZvJ7/2bye/9m8nf+zmHz/potx/6aLcP+lim//pYlv/6SJbv+kiG3/moJp/5F9 + Zf9JPBJwSTwSVkk8Ej5JPBIpSTwSGEk8EgxHOxIFRjoRAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD80 + DwNEOBAIRjoREUg7Eh9JPBIxcF8/dJF9Zf/Vz8D/39rM/9/azP/f2sv/39rL/9/Zyv/Nwq//mn1g/+Xh + 3f/a0sv/0MS5/6aMc/+3pI3/3tfG/97Wxv/e1sX/3tbF/97VxP/e1cT/3tXD/97Uw//e1ML/3tTC/93T + wf/d08H/3dPA/93SwP/d0sD/3dK//93Sv//d0b7/3dG+/93Rvf/d0L3/3dC8/93QvP/dz7v/3c+7/9zP + uv/czrr/3M65/9zOuf/czbj/3M24/9zNt//czLf/3My2/9zMtv/cy7X/3Mu1/9zLtP+PeF3/inNY/5qF + bv+/sKL/wrWn/87Ct//Lv7L/yLqs/8S1pv/AsKD/vKuZ/6+bh/+JcFj/h21V/4dtVf+HbVX/h21V/4dt + Vf+HbVX/h21V/4dtVf+Sd1z/mn1h/5p9Yf+afWH/mn1h/5p9Yf+SeFz/inNY/8Gojf/awaX/2sGl/9rA + pP/ZwKT/2cCj/9m/o//Zv6L/2b+i/9m+of/ZvqH/2b6g/9m9oP/ZvZ//2b2f/9m8nv/ZvJ7/2byd/7OY + fP+ni3H/potw/6WKcP+liW//pIlu/6SIbf+agmn/kX1l/0k8EnBJPBJWSTwSPkk8EilJPBIYSTwSDEc7 + EgVGOhEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPzQPA0Q4EAdGOhEQSDsSHUk8Ei9qWjhnkX1l/8vD + s//f28z/39rM/9/ay//f2sv/39nK/83Cr/+afWD/5eHd/9rSyv/PxLn/sZuG/6uTef/e18b/3tbG/97W + xf/e1sX/3tXE/97VxP/e1cP/3tTD/97Uw//e1ML/3dTC/93Twf/d08H/3dPA/93SwP/d0r//3dK//93R + vv/d0b7/3dG9/93Qvf/d0Lz/3dC8/93Pu//dz7v/3M+6/9zOuv/czrn/3M65/9zNuP/czbj/3M23/9zN + t//czLb/3My2/9zMtf/cy7X/zLqj/4pzWP+Kc1j/ppN+/72tnv/JvbD/0se9/87Dt//LvrH/x7mr/8Oz + pP+4ppT/inBZ/4dtVf+HbVX/h21V/4dtVf+HbVX/mYZz/6+ilf+xpZj/nYp3/4dtVf+UeF3/mn1h/5p9 + Yf+afWH/mn1h/5h7X/+Kc1j/rZV6/9rBpf/awaX/2sCk/9nApP/ZwKP/2b+j/9m/ov/Zv6L/2b6h/9m+ + of/ZvqD/2b2g/9m9n//ZvZ//2bye/9m8nv/ZvJ3/s5h8/6eLcf+mi3D/pYpw/6WJb/+kiW7/pIht/5qC + af+RfWX/STwScEk8ElZJPBI+STwSKUk8EhhJPBIMRzsSBUY6EQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAA/NA8DRDgQB0Y6EQ9IOxIbSTwSLEk8EkKRfWX/wbem/9/bzP/f2sz/39rM/9/ay//f2cv/2tPD/5p9 + YP/Rxrz/2tLK/8/EuP+zn4r/oohs/97Xx//e1sb/3tbG/97Wxf/e1sX/3tXE/97VxP/e1cP/3tTD/97U + wv/d1ML/3dPB/93Twf/d08D/3dLA/93Sv//d0r//3dG+/93Rvv/d0b3/3dC9/93QvP/d0Lz/3c+7/93P + u//cz7r/3M+6/9zOuf/czrn/3M64/9zNuP/czbf/3M23/9zMtv/czLb/3My1/9zLtf+9qpL/inNY/4pz + WP+um4j/u6qa/9TLwv/Vy8L/0ce8/83Btf/JvK//xbao/5mCbf+HbVX/h21V/4dtVf+HbVX/h21V/6OT + g/+/t67/xr62/8nDu//Kw7z/sKKU/4huVf+YfGD/mn1h/5p9Yf+afWH/mn1h/492Wv+ehmv/2sGl/9rB + pf/awKT/2cCk/9nAo//ZwKP/2b+i/9m/ov/ZvqH/2b6h/9m+oP/ZvqD/2b2f/9m9n//ZvZ7/2bye/9m8 + nf+zmHz/p4tx/6aLcP+linD/pYpv/6SJbv+kiG3/moJp/5F9Zf9JPBJwSTwSVkk8Ej5JPBIpSTwSGEk8 + EgxHOxIFRjoRAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD80DwJEOBAFRjoRDUg7EhlJPBIpSTwSPo97 + Y/O4rJn/39vN/9/azP/f2sz/39rL/9/Zy//f2cr/mn1g/8zAs//a0sr/z8S4/7upl/+afWD/3tfH/97X + xv/e1sb/3tbF/97Wxf/e1cT/3tXE/97Vw//e1MP/3tTC/93Uwv/d08H/3dPB/93TwP/d0sD/3dK//93S + v//d0b7/3dG+/93Rvf/d0b3/3dC9/93QvP/d0Lz/3c+7/93Pu//cz7r/3M65/9zOuf/czrj/3M24/9zN + t//czbf/3My3/9zMtv/czLb/3Mu1/7Ofhv+Kc1j/inNY/7ellP+9rZ3/29TN/9jPx//UysD/0MS5/8u/ + sv+/r6D/h21V/4dtVf+HbVX/h21V/4dtVf+NdV//vrat/8jBuf/QysP/1M/J/9XQyv/SzMb/nYl3/5F2 + W/+afWH/mn1h/5p9Yf+afWH/k3hd/4pzWP/awaX/2sGl/9rApP/ZwKT/2cCk/9nAo//Zv6P/2b+i/9m/ + ov/ZvqH/2b6h/9m+oP/ZvZ//2b2f/9m9nv/ZvJ7/2bye/8Ckh/+ni3H/potw/6WKcP+lim//pIlu/6SI + bf+fhWv/kX1l/0k8EnBJPBJWSTwSPkk8EilJPBIYSTwSDEc7EgVGOhEBAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAPzQPAUQ4EAVGOhEMSDsSF0k8EidJPBI7i3dez66gjP/f283/39rM/9/azP/f2sv/39rL/9/Z + yv+rlHr/vq2b/9nRyf/Pw7j/wLCf/5p9YP/RxrP/3tfG/97Wxv/e1sX/3tbF/97VxP/e1cT/3tXD/97U + w//e1ML/3tTC/93Twf/d08H/3dPA/93SwP/d0sD/3dK//93Sv//d0b7/3dG+/93Rvf/d0L3/3dC8/93Q + vP/dz7v/3c+7/9zPuv/czrr/3M65/9zOuf/czbj/3M24/9zNt//czLf/3My2/9zMtv/cy7X/s5+G/4pz + WP+Kc1j/taKQ/8a5q//e2NH/2tPL/9bNxP/Sx73/zcG1/6iUgv+HbVX/h21V/4dtVf+HbVX/h21V/6SU + hP/FvbX/0MrD/9nUz//f29f/4NzY/9zY0//GvbT/inBX/5p9Yf+afWH/mn1h/5p9Yf+Wel7/inNY/9rB + pv/awaX/2sGl/9rApP/ZwKT/2cCj/9m/o//Zv6L/2b+i/9m+of/ZvqH/2b6g/9m9oP/ZvZ//2b2f/9m8 + nv/ZvJ7/wKSH/6eLcf+mi3D/pYpw/6WKb/+kiW7/pIht/5+Fa/+RfWX/STwScEk8ElZJPBI+STwSKUk8 + EhhJPBIMRzsSBUY6EQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/NA8BRDgQBEY6EQtIOxIVSTwSJUk8 + EjmJdlzEpJR//9/bzf/f28z/39rM/9/ay//f2sv/39nK/6+Zgf+0oIz/2dHJ/8/DuP/Ftqj/mn1g/83A + rf/e18b/3tbG/97Wxf/e1sX/3tXE/97VxP/e1cT/3tTD/97Uw//e1ML/3dTC/93Twf/d08H/3dPA/93S + wP/d0r//3dK//93Rvv/d0b7/3dG9/93Qvf/d0Lz/3dC8/93Pu//dz7v/3M+6/9zOuv/czrn/3M65/9zN + uP/czbj/3M23/9zNt//czLb/3My2/9zMtf+zn4b/inNY/4pzWP+zn4v/zMC0/+Hb1f/c1c7/2M/H/9PJ + v//Ow7f/mIFs/4dtVf+HbVX/h21V/4dtVf+HbVX/tKic/8nDu//V0Mv/4d3Z/+nn5P/r6eb/5eLe/9vW + 0f+QeWP/mn1h/5p9Yf+afWH/mn1h/5l8YP+Kc1j/2sGm/9rBpf/awaX/2sCk/9nApP/ZwKP/2b+j/9m/ + ov/Zv6L/2b6h/9m+of/ZvqD/2b2g/9m9n//ZvZ//2bye/9m8nv/ApIj/p4xx/6aLcP+minD/pYpv/6WJ + bv+kiG3/n4Vr/5F9Zf9pWDaPSTwSVkk8Ej5JPBIpSTwSGEk8EgxHOxIFRjoRAQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABEOBADRjoRCkg7EhNJPBIiSTwSNoFuUqOaiHL/39vN/9/bzf/f2sz/39rM/9/a + y//f2cv/vKuV/6uUff/Z0cn/zsO4/8W2qP+eg2f/vKqT/97Xx//e1sb/3tbG/97Wxf/e1sX/3tXE/97V + xP/e1cP/3tTD/97Uwv/d1ML/3dPB/93Twf/d08D/3dLA/93Sv//d0r//3dG+/93Rvv/d0b3/3dC9/93Q + vP/d0Lz/3c+7/93Pu//cz7r/3M+6/9zOuf/czrn/3M64/9zNuP/czbf/3M23/9zMtv/czLb/3My1/7Of + hv+Kc1j/inNY/7CciP/LwLT/4t3Y/97X0P/Z0cn/1MrA/8/EuP+YgWz/h21V/4dtVf+HbVX/h21V/4dt + Vf+/t67/zMa//9nVz//m49//8vDu//b08//s6ef/39vX/5uGcv+VeV7/mn1h/5p9Yf+afWH/mn1h/4pz + WP/awab/2sGl/9rBpf/awKT/2cCk/9nAo//ZwKP/2b+i/9m/ov/ZvqH/2b6h/9m+of/ZvqD/2b2f/9m9 + n//ZvZ7/2bye/8CkiP+njHH/potw/6aKcP+lim//pYlu/6SIbf+fhWv/kX1l/2lYNo9JPBJWSTwSPkk8 + EilJPBIYSTwSDEc7EgVGOhEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEQ4EANGOhEJSDsSEkk8 + EiBJPBI0fmtPl5F9Zf/f283/4NzO/9/bzf/f2sz/39rL/9/ay//AsJz/noJn/9nRyf/Ow7f/xLan/6OJ + b/+3pI3/3tfH/97Xxv/e1sb/3tbF/97Wxf/e1cT/3tXE/97Vw//e1MP/3tTC/93Uwv/d08H/3dPB/93T + wP/d0sD/3dK//93Sv//d0b7/3dG+/93Rvf/d0b3/3dC9/93QvP/d0Lz/3c+7/93Pu//cz7r/3M65/9zO + uf/czrj/3M24/9zNt//czbf/3My3/9zMtv/czLb/s5+G/4pzWP+Kc1j/rpmD/8u/sv/j39r/3tjS/9nR + yf/Uy8H/z8S5/5iCbP+HbVX/h21V/4dtVf+HbVX/h21V/7+3rv/Mxr//2tXQ/+fk4P/z8vD/+Pf2/+3r + 6P/g3Nj/pJKB/5V5Xv+afWH/mn1h/5p9Yf+afWH/inNY/9rBpv/awaX/2sGl/9rApP/ZwKT/2cCk/9nA + o//Zv6P/2b+i/9m/ov/ZvqH/2b6h/9m+oP/ZvZ//2b2f/9m9nv/ZvJ7/wKSI/6eMcf+mi3H/popw/6WK + b/+liW7/pIlu/5+Fa/+RfWX/aVg2j0k8EldJPBI/STwSKUk8EhhJPBIMRzsSBUY6EQEAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAARDgQA0Y6EQhIOxIRSTwSH0k8EjFwXz90kX1l/9XPwP/f3M7/4NvO/9/a + zP/f2sv/39rL/83CsP+afWD/2dDI/87Dt//Etaf/qZF5/6uTef/e18f/3tfG/97Wxv/e1sX/3tbF/97V + xP/e1cT/3tXD/97Uw//e1ML/3tTC/93Twf/d08H/3dPA/93SwP/d0sD/3dK//93Sv//d0b7/3dG+/93R + vf/d0L3/3dC8/93QvP/dz7v/3c+7/9zPuv/czrr/3M65/9zOuf/czbj/3M24/9zNt//czLf/3My2/9zM + tv+zn4b/inNY/4pzWP+pk33/ybyw/+Pe2f/e19H/2dHJ/9TKwf/PxLn/mIFs/4dtVf+HbVX/h21V/4dt + Vf+HbVX/urGm/8rDvP/W0sz/4t/b/+zq5//v7er/6OXi/93Z1P+kkoD/lXle/5p9Yf+afWH/mn1h/5p9 + Yf+Kc1j/2sGm/9rBpv/awaX/2sGl/9rApP/ZwKT/2cCj/9m/o//Zv6L/2b+i/9m+of/ZvqH/2b6g/9m9 + oP/ZvZ//2b2f/9m8nv/ApIj/p4xx/6aLcf+minD/pYpv/6WJbv+kiW7/oIVr/5F9Zf9oWDaPSTwSWEk8 + EkBJPBIqSTwSGUk8Eg1HOxIGRjoRAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABEOBADRjoRB0g7 + EhBJPBIdSTwSL2paOGeRfWX/y8Oz/+Dcz//g3M7/4NvN/9/azP/f2sv/1s69/5p9YP/Iuqz/zsK2/8S1 + pv+slH3/ooht/97Xx//e18b/3tbG/97Wxf/e1sX/3tXE/97VxP/e1cT/3tTD/97Uw//e1ML/3dTC/93T + wf/d08H/3dPA/93SwP/d0r//3dK//93Rvv/d0b7/3dG9/93Qvf/d0Lz/3dC8/93Pu//dz7v/3M+6/9zO + uv/czrn/3M65/9zNuP/czbj/3M23/9zNt//czLb/3My2/8e1nv+Kc1j/inNY/6KLc//Huqz/4dzW/93W + z//Y0Mf/08rA/8/DuP+chnL/h21V/4dtVf+HbVX/h21V/4dtVf+uoZT/xb62/9HLxf/b1tH/4t7a/+Tg + 3P/f29f/19LM/5mEcP+Xe1//mn1h/5p9Yf+afWH/l3tf/5mBZv/awqb/2sGm/9rBpf/awaX/2sCk/9nA + pP/ZwKP/2b+j/9m/ov/Zv6L/2b6h/9m+of/ZvqD/2b6g/9m9n//ZvZ//2bye/8ywk/+njHL/potx/6aL + cP+lim//pYlv/6SJbv+kiG3/kX1l/2hYNpFJPBJZSTwSQUk8EitJPBIaSTwSDkc7EgZGOhECAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEQ4EANGOhEHSDsSD0k8EhtJPBIsSTwSQpF9Zf/Bt6b/4NzO/+Hd + 0P/g3M7/4NvN/9/azP/f2sv/mn5h/8i6rP/Owrb/xLWm/7Ofiv+afWD/3tfH/97Xx//e1sb/3tbG/97W + xf/e1sX/3tXE/97VxP/e1cP/3tTD/97Uwv/d1ML/3dPB/93Twf/d08D/3dLA/93Sv//d0r//3dG+/93R + vv/d0b3/3dC9/93QvP/d0Lz/3c+7/93Pu//cz7r/3M+6/9zOuf/czrn/3M64/9zNuP/czbf/3M23/9zM + tv/czLb/0cCq/4pzWP+Kc1j/mIFo/7ajkf/f2dL/29PM/9fOxf/SyL3/zsK2/6yaiP+HbVX/h21V/4dt + Vf+HbVX/h21V/5yKd/+/t67/ycO7/9LMxv/X0s3/2NTO/9XQyv/PycH/jXRd/5p9Yf+afWH/mn1h/5p9 + Yf+VeV7/o4tw/9rCpv/awab/2sGl/9rBpf/awKT/2cCk/9nAo//ZwKP/2b+i/9m/ov/ZvqH/2b6h/9m+ + of/ZvqD/2b2f/9m9n//ZvZ7/zLCT/6eMcv+mi3H/potw/6WKb/+liW//pIlu/6SIbf+RfWX/aFg2kkk8 + EltJPBJDSTwSLUk8EhtJPBIPRzsSB0Y6EQIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARDgQAkY6 + EQVIOxINSTwSGUk8EilJPBI+j3tj87ismf/g3M7/4d3Q/+Hcz//g287/4NvN/+DbzP+okHX/uKWS/87C + tv/Etab/taKN/5p9YP/RxrT/3tfH/97Xxv/e1sb/3tbF/97Wxf/e1cT/3tXE/97Vw//e1MP/3tTC/93U + wv/d08H/3dPB/93TwP/d0sD/3dK//93Sv//d0b7/3dG+/93Rvf/d0b3/3dC9/93QvP/d0Lz/3c+7/93P + u//cz7r/3M65/9zOuf/czrj/3M24/9zNuP/czbf/3My3/9zMtv/czLb/lH5j/4pzWP+Pd13/po51/9zV + zv/Y0Mj/1cvB/9HFu//MwLP/wLCh/4dtVf+HbVX/h21V/4dtVf+HbVX/iXBZ/7WroP/BubD/yMG5/8zG + v//Nx8D/y8S9/7Ommf+PdFr/mn1h/5p9Yf+afWH/mn1h/5F3W/+3n4T/2sKm/9rBpv/awaX/2sGl/9rA + pP/ZwKT/2cCk/9nAo//Zv6P/2b+i/9m/ov/ZvqH/2b6h/9m+oP/ZvZ//2b2f/9m9n//MsJP/p4xy/6aL + cf+mi3D/pYpv/6WJb/+kiW7/pIht/5F9Zf96aUu4STwSXkk8EkVJPBIvSTwSHUk8EhBHOxIIRjoRA0I2 + EAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABEOBABRjoRBUg7EgxJPBIXSTwSJ0k8EjuLd17PrqCM/9/b + zv/i3tH/4d3Q/+Hcz//g3M7/4NvN/62Xfv+1oY3/zsK2/8S0pv+7qZb/mn1g/83Arf/e18f/3tfG/97W + xv/e1sX/3tbF/97VxP/e1cT/3tXD/97Uw//e1ML/3tTC/93Twf/d08H/3dPB/93SwP/d0sD/3dK//93S + v//d0b7/3dG+/93Rvf/d0L3/3dC8/93QvP/dz7v/3c+7/9zPuv/czrr/3M65/9zOuf/czbj/3M24/9zN + t//czLf/3My2/9zMtv+tmYH/inNY/4pzWP+fhm3/yLut/9bNw//Sx73/zsO3/8q9sP/Gt6n/nYdy/4dt + Vf+HbVX/h21V/4dtVf+HbVX/l4Rw/7eupP++taz/wbmx/8K7sv+9tKr/jnZg/5d7X/+afWH/mn1h/5p9 + Yf+afWH/jHRZ/9C4nf/awqf/2sGm/9rBpv/awaX/2sGl/9rApP/ZwKT/2cCj/9m/o//Zv6L/2b+i/9m+ + of/ZvqH/2b6g/9m9oP/ZvZ//2b2f/8ywk/+njHL/p4tx/6aLcP+linD/pYlv/6SJbv+kiG3/kX1l/3po + SrlJPBJhSTwSSEk8EjJJPBIfSTwSEkc7EglGOhEDQjYQAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEQ4 + EAFGOhEESDsSC0k8EhVJPBIlSTwSOYl2XMSklH//39vO/+Le0v/i3tH/4d3Q/+Hcz//h3M3/v6+a/6uU + fP/Pw7f/xLWm/7uolv+dgWX/vKqU/97Xx//e18b/3tbG/97Wxf/e1sX/3tXE/97VxP/e1cT/3tTD/97U + w//e1ML/3dTC/93Twf/d08H/3dPA/93SwP/d0r//3dK//93Rvv/d0b7/3dG9/93Qvf/d0Lz/3dC8/93P + u//dz7v/3M+6/9zOuv/czrn/3M65/9zNuP/czbj/3M23/9zNt//czLb/3My2/8y7pP+Kc1j/inNY/5N6 + YP+1oY7/0si+/8/Euf/Mv7P/yLqs/8S1pv+8q5r/inBZ/4dtVf+HbVX/h21V/4dtVf+HbVX/lH9r/66i + lv+2raP/r6OW/5B5ZP+QdVv/mn1h/5p9Yf+afWH/mn1h/5Z6Xv+Zgmf/2sKn/9rCp//awqb/2sGm/9rB + pf/awaX/2sCk/9nApP/ZwKP/2b+j/9m/ov/Zv6L/2b6h/9m+of/ZvqD/2b6g/9m9n//ZvZ//zLGT/6eM + cv+ni3H/potw/6WKcP+liW//pIlu/6SIbf+RfWX/eWhKu0k8EmVJPBJMSTwSNUk8EiJJPBITRzsSCUU5 + EQRCNxABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEY6EQNIOxIKSTwSE0k8EiJJPBI2gW5So5qI + cv/f283/49/T/+Lf0v/i3tD/4d3Q/+Hczv/EtaL/poxz/8/DuP/Ftqf/u6mX/6CGa/+3pI3/3tfH/97X + x//e1sb/3tbG/97Wxf/e1sX/3tXE/97VxP/e1cP/3tTD/97Uwv/d1ML/3dPB/93Twf/d08D/3dLA/93S + v//d0r//3dG+/93Rvv/d0b3/3dC9/93QvP/d0Lz/3c+7/93Pu//cz7r/3M+6/9zOuf/czrn/3M64/9zN + uP/czbf/3M23/9zMtv/czLb/3My1/56Jb/+Kc1j/inNY/56Eaf/JvK//zMC0/8m8rv/Ft6j/wbKi/72s + m/+wnIj/inBY/4dtVf+HbVX/h21V/4dtVf+HbVX/h21V/4dtVf+HbVX/jnNZ/5p9Yf+afWH/mn1h/5p9 + Yf+afWH/jnVa/7yliv/awqf/2sKn/9rCpv/awab/2sGl/9rBpf/awKT/2cCk/9nAo//ZwKP/2b+i/9m/ + ov/ZvqH/2b6h/9m+of/ZvqD/2b2f/9m9n//MsZT/p4xy/6eLcf+mi3D/pYpw/6WKb/+kiW7/pIht/5N+ + Zv95Z0q8STwSaEk8Ek9JPBI4STwSJEk8EhVHOxIKRTkRBUI3EAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAARjoRA0g7EglJPBISSTwSIEk8EjR+a0+XkX1l/9/bzf/i39L/49/T/+Le0v/i3dH/4t3P/9HH + tv+ghWr/0MS5/8W3qP+8q5j/po10/6uTev/e18f/3tfH/97Xxv/e1sb/3tbF/97Wxf/e1cT/3tXE/97V + w//e1MP/3tTC/93Uwv/d08H/3dPB/93TwP/d0sD/3dK//93Sv//d0b7/3dG+/93Rvf/d0b3/3dC9/93Q + vP/d0Lz/3c+7/93Pu//cz7r/3M65/9zOuf/czrj/3M24/9zNuP/czbf/3My3/9zMtv/czLb/x7Wd/4pz + WP+Kc1j/j3dc/6qTe//JvK7/xrip/8OzpP+/rp7/u6mX/7ekkf+rlYD/kXhg/4dtVf+HbVX/h21V/4dt + Vf+HbVX/h21V/5B1W/+afWH/mn1h/5p9Yf+afWH/mn1h/5V5Xv+UfWL/2sOo/9rCp//awqf/2sKm/9rB + pv/awaX/2sGl/9rBpf/ZwKT/2cCk/9nAo//Zv6P/2b+i/9m/ov/ZvqH/2b6h/9m+oP/ZvZ//2b2f/9m9 + n/+njHL/p4tx/6aLcP+linD/pYpv/6SJbv+kiG3/lX9n/3lnSb5JPBJrSTwSUkk8EjpJPBImSTwSFkc7 + EgtFOREFQjcQAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABGOhEDSDsSCEk8EhFJPBIfSTwSMXBf + P3SRfWX/1c/A/+Lf0v/j4NP/49/T/+Le0f/i3dD/1s29/6KHbP/HuKr/xriq/72smv+pkXr/qI91/97X + x//e18f/3tfG/97Wxv/e1sX/3tbF/97VxP/e1cT/3tXD/97Uw//e1ML/3tTC/93Twf/d08H/3dPB/93S + wP/d0sD/3dK//93Sv//d0b7/3dG+/93Rvf/d0L3/3dC8/93QvP/dz7v/3c+7/9zPuv/czrr/3M65/9zO + uf/czbj/3M24/9zNt//czLf/3My2/9zMtv/cy7X/o451/4pzWP+Kc1j/k3pf/7Sgi//Ds6T/wK+f/7yr + mf+5ppP/taGN/7Gbhv+tloD/oopy/5V7Y/+TeF//kXZb/5F2W/+YfGD/mn1h/5p9Yf+afWH/mn1h/5p9 + Yf+Ye1//i3NY/8Gqj//aw6j/2sOo/9rCp//awqf/2sGm/9rBpv/awaX/2sGl/9rApP/ZwKT/2cCj/9m/ + o//Zv6L/2b+i/9m+of/ZvqH/2b6g/9m9oP/ZvZ//2b2f/6eMcv+njHH/potw/6aKcP+lim//pYlu/6SI + bf+Vf2f/eWdJv0k8Em1JPBJTSTwSPEk8EidJPBIXRzsSC0U5EQVCNxABAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAEY6EQNIOxIHSTwSEEk8Eh1JPBIvalo4Z5F9Zf/Lw7P/4t7S/+Tg1P/j4NP/49/S/+Pe + 0f/i3tD/o4lv/8S1pf/Huar/vq2b/7Cbhf+dgWX/3tjI/97Xx//e18b/3tbG/97Wxf/e1sX/3tXE/97V + xP/e1cT/3tTD/97Uw//e1ML/3dTC/93Twf/d08H/3dPA/93SwP/d0r//3dK//93Rvv/d0b7/3dG9/93Q + vf/d0Lz/3dC8/93Pu//dz7v/3M+6/9zOuv/czrn/3M65/9zNuP/czbj/3M23/9zNt//czLb/3My2/9zM + tf/Wxa//j3hd/4pzWP+Kc1j/lXtf/7KdiP+8q5n/uaeU/7aijv+ynYj/rpiC/6qTfP+mjnX/oohu/56C + Z/+afWH/mn1h/5p9Yf+afWH/mn1h/5p9Yf+afWH/mXxg/410Wf+jjHH/2sOp/9rDqP/aw6j/2sKn/9rC + p//awqb/2sGm/9rBpf/awaX/2sCk/9nApP/ZwKP/2b+j/9m/ov/Zv6L/2b6h/9m+of/ZvqD/2b6g/9m9 + n//ZvZ//p4xy/6eMcf+mi3D/popw/6WKb/+liW7/pIht/5V/Z/+Gc1nfSTwSbkk8ElVJPBI9STwSKEk8 + EhdHOxILRTkRBUI3EAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARjoRA0g7EgdJPBIPSTwSG0k8 + EixJPBJCkX1l/8G3pv/i3tH/5OHV/+Tg1P/j39P/49/S/+Pe0f+slX3/vKuY/8i6q/+/rp3/s56I/5+D + aP/Xzr3/3tfI/97Xx//e1sb/3tbG/97Wxf/e1sX/3tXE/97VxP/e1cP/3tTD/97Uwv/d1ML/3dPB/93T + wf/d08D/3dLA/93Sv//d0r//3dG+/93Rvv/d0b3/3dG9/93QvP/d0Lz/3c+7/93Pu//cz7r/3M+6/9zO + uf/czrn/3M64/9zNuP/czbf/3M23/9zMtv/czLb/3My1/9zLtf/HtZ3/inNY/4pzWP+Kc1j/lHpe/66Y + gf+2o4//s56K/7CahP+slX7/qJB4/6SLcf+ghWr/nIBk/5p9Yf+afWH/mn1h/5p9Yf+afWH/mn1h/5h7 + X/+NdFn/lH1i/9W+pP/aw6n/2sOo/9rDqP/awqf/2sKn/9rCpv/awab/2sGl/9rBpf/awKT/2cCk/9nA + o//ZwKP/2b+i/9m/ov/ZvqH/2b6h/9m+of/ZvqD/2b2f/9m9n/+njHL/p4xx/6aLcf+minD/pYpv/6WJ + bv+kiW7/lX9n/4ZzWd9JPBJvSTwSVkk8Ej1JPBIoSTwSGEc7EgxFOREFQjcQAQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABGOhECSDsSBUk8Eg1JPBIZSTwSKUk8Ej6Pe2PzuKyZ/+Dd0P/l4db/5OHV/+Tg + 1P/k39P/49/S/7Whi/+6qJX/yLut/8Cvnv+4pJD/oIVq/9DEsv/f2cn/3tfH/97Xxv/e1sb/3tbF/97W + xf/e1cT/3tXE/97Vw//e1MP/3tTC/93Uwv/d08H/3dPB/93TwP/d0sD/3dK//93Sv//d0b7/3dG+/93R + vv/d0b3/3dC9/93QvP/d0Lz/3c+7/93Pu//cz7r/3M65/9zOuf/czrj/3M24/9zNuP/czbf/3My3/9zM + tv/czLb/3Mu1/9zLtf+9qpH/inNY/4pzWP+Kc1j/j3Za/6GHbf+vmYP/rZZ//6mRef+ljHP/oodt/56C + Z/+afWH/mn1h/5p9Yf+afWH/mn1h/5p9Yf+UeV3/i3NY/494Xf/LtJr/2sSp/9rDqf/aw6j/2sOo/9rC + p//awqf/2sKm/9rBpv/awaX/2sGl/9rBpf/ZwKT/2cCk/9nAo//Zv6P/2b+i/9m/ov/ZvqH/2b6h/9m+ + oP/ZvZ//2b2f/6eMcv+njHH/potx/6aKcP+lim//pYlu/6SJbv+Vf2f/hnNZ30k8Em9JPBJWSTwSPkk8 + EilJPBIYRzsSDEU5EQVCNxABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEY6EQFIOxIFSTwSDEk8 + EhdJPBInSTwSO4t3Xs+uoIz/4NzP/+Xi1//l4db/5OHV/+Tg1P/k39P/wrKe/7Gbhf/JvK7/wbCf/7il + kv+kinD/xLah/+DZy//f2Mn/3tfG/97Wxv/e1sX/3tbF/97VxP/e1cT/3tXD/97Uw//e1ML/3tTC/93T + wf/d08H/3dPB/93SwP/d0sD/3dK//93Sv//d0b7/3dG+/93Rvf/d0L3/3dC8/93QvP/dz7v/3c+7/9zP + uv/czrr/3M65/9zOuf/czbj/3M24/9zNt//czLf/3My2/9zMtv/cy7X/3Mu1/9zLtP/Cr5f/j3hd/4pz + WP+Kc1j/i3NY/5N5Xv+ghm3/pYxy/6OJb/+fhGn/m39j/5p9Yf+afWH/mn1h/5l8YP+UeV3/jnVa/4pz + WP+UfWL/y7Wb/9rEqv/axKn/2sOp/9rDqP/aw6j/2sOo/9rCp//awqf/2sGm/9rBpv/awaX/2sGl/9rA + pP/ZwKT/2cCj/9m/o//Zv6L/2b+i/9m+of/ZvqH/2b6g/9m9oP/ZvZ//qo91/6eMcf+mi3H/popw/6WK + b/+liW7/pIlu/5iBaP+Gc1nfSTwSb0k8ElZJPBI+STwSKUk8EhhHOxIMRTkRBUI3EAEAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAARjoRAUg7EgRJPBILSTwSFUk8EiVJPBI5iXZcxKSUf//f283/5uLX/+Xi + 1//l4tb/5eHV/+Tg1P/GuKX/sJmD/8q9r//CsqH/uaaU/6iPdv/BsZ3/4NrM/+DZyv/f2Mn/3tbG/97W + xf/e1sX/3tbF/97VxP/e1cT/3tTD/9rPvv+6po//vauV/9bLuP/d08H/3dPA/93SwP/d0r//3dK//93R + vv/d0b7/3dG9/93Qvf/d0Lz/3dC8/93Pu//dz7v/3M+6/9zOuv/czrn/3M65/9zNuP/czbj/3M23/9zN + t//czLb/3My2/9zMtf/cy7X/3Mu0/9zLtP/MuqL/mYNp/4pzWP+Kc1j/inNY/4pzWP+NdVn/kXhc/5N6 + Xv+SeFz/knhc/492Wv+OdVr/inNY/4pzWP+Kc1j/o4xy/9W/pf/axav/2sSq/9rEqv/aw6n/2sOp/9rD + qP/aw6j/2sKn/9rCp//awqb/2sGm/9rBpf/awaX/2sCk/9nApP/ZwKP/2b+j/9m/ov/Zv6L/2b6h/9m+ + of/ZvqD/2b6g/9m9n/+0mH3/p4xy/6aLcf+mi3D/pYpv/6WJb/+kiW7/moJp/4ZzWN9JPBJwSTwSVkk8 + Ej5JPBIpSTwSGEc7EgxFOREFQjcQAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASDsSA0k8 + EgpJPBITSTwSIkk8EjaBblKjmohy/9/bzf/m49j/5uPY/+Xi1//l4db/5eDV/9bNvf+qkXn/y72w/8Ky + ov+6qJX/rJR9/7Oeh//h28z/4NrL/+DZyv/f2Mj/3tbG/97Wxf/e1sX/3tXE/97VxP/e1cP/x7ei/6qS + ef+qknr/qpN6/7ejjP/Qw6//3dLA/93Sv//d0r//3dG+/93Rvv/d0b3/3dG9/93QvP/d0Lz/3c+7/93P + u//dz7v/3M+6/9zOuf/czrn/3M64/9zNuP/czbf/3M23/9zMtv/czLb/3My1/9zLtf/cy7X/3Mu0/9zK + tP/byrP/vKmQ/5R9Y/+Kc1j/inNY/4pzWP+Kc1j/inNY/4pzWP+Kc1j/inNY/4pzWP+Kc1j/nodt/8ax + l//bxaz/2sWr/9rFq//axKr/2sSq/9rEqf/aw6n/2sOo/9rDqP/awqf/2sKn/9rCpv/awab/2sGl/9rB + pf/awKT/2cCk/9nAo//ZwKP/2b+i/9m/ov/Zv6L/2b6h/9m+of/ZvqD/2b2f/7SYff+njHL/potx/6aL + cP+lim//pYlv/6SJbv+agmn/hnNY30k8EnBJPBJWSTwSPkk8EilJPBIYRzsSDEU5EQVCNxABAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABIOxIDSTwSCEk8EhJJPBIfSTwSM35sT5aRfWX/39vN/+Xh + 1v/m49j/5uPY/+Xi1//l4db/1s2//6uTe//Huar/w7Ok/7upl/+ul4D/sZuD/+Hczf/h28z/4NrL/+DZ + yv/f18j/3tbF/97Wxf/e1cT/3tXE/97Vw//Ht6L/qpJ5/6qSef+qk3r/q5N6/6uTe/+xm4P/yrqm/93S + v//d0b7/3dG+/93Rvv/d0b3/3dC9/93QvP/d0Lz/3c+7/93Pu//cz7r/3M65/9zOuf/czrj/3M24/9zN + uP/czbf/3My3/9zMtv/czLb/3Mu1/9zLtf/cy7T/3Mq0/9zKs//byrP/28my/8u4of+tmH//nohu/494 + Xf+Kc1j/inNY/5R9Yv+eiG3/sp2D/8u2nf/bxq3/28as/9vFrP/axav/2sWr/9rEqv/axKr/2sSp/9rD + qf/aw6j/2sOo/9rCp//awqf/2sKm/9rBpv/awaX/2sGl/9rBpf/ZwKT/2cCk/9nAo//Zv6P/2b+i/9m/ + ov/ZvqH/2b6h/9m+oP/ZvZ//tJl+/6eMcv+ni3H/potw/6WKcP+liW//pIlu/5qCaf+RfWX/STwScEk8 + ElZJPBI+STwSKUk8EhhHOxIMRTkRBUI3EAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEg7 + EgNJPBIHSTwSEEk8Eh1JPBIwcF8/c5F9Zf/Vz8D/5OHV/+fk2f/m49n/5uPY/+bi1v/l4db/rZV+/8S0 + pP/EtaX/vauZ/7KdiP+njnT/4tzO/+Hbzf/h2sz/4NrL/+DZyv/f18f/3tbF/97VxP/e1cT/3tXD/9HE + sP+qknn/qpJ5/6qTev+rk3r/q5N7/6uTe/+rlHv/rpeA/8Sznf/Zzbr/3dG+/93Rvf/d0L3/3dC8/93Q + vP/dz7v/3c+7/9zPuv/czrr/3M65/9zOuf/czbj/3M24/9zNt//czLf/3My2/9zMtv/cy7X/3Mu1/9zL + tP/cy7T/3Mqz/9vKs//byrL/28my/9vJsf/bybH/28iw/9vIsP/byK//28ev/9vHrv/bx67/28au/9vG + rf/bxqz/28Ws/9rFq//axav/2sSq/9rEqv/axKn/2sOp/9rDqf/aw6j/2sOo/9rCp//awqf/2sGm/9rB + pv/awaX/2sGl/9rApP/ZwKT/2cCj/9m/o//Zv6L/2b+i/9m+of/ZvqH/2b6g/9m9oP+0mX7/p4xy/6eL + cf+mi3D/pYpw/6WJb/+kiW7/moNp/5F9Zf9JPBJwSTwSVkk8Ej5JPBIpSTwSGEc7EgxFOREFQjcQAQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASDsSA0k8EgdJPBIPSTwSG0k8EixrWjllkX1l/8vD + s//j4NP/5+Ta/+fk2f/m49j/5uLX/+bi1/+ynIb/wbCf/8W2p/++rJr/tKCL/6iQd//b08T/4tzO/+Hb + zf/h28z/4drK/+DZyv/e18b/3tbF/97VxP/e1cT/1Mi1/6qSef+qknn/qpN6/6uTev+rk3v/q5N7/6uU + e/+rlHz/rJR8/6yUff++q5X/08Wx/93Qvf/d0Lz/3dC8/93Pu//dz7v/3M+6/9zPuv/czrn/3M65/9zN + uP/czbj/3M23/9zNt//czLb/3My2/9zMtf/cy7X/3Mu0/9zLtP/cyrP/28qz/9vKsv/bybL/28my/9vJ + sf/byLH/28iw/9vIsP/bx6//28ev/9vHrv/bxq7/28at/9vGrP/bxaz/28Ws/9rFq//axav/2sSq/9rE + qv/axKn/2sOp/9rDqP/aw6j/2sKn/9rCp//awqb/2sGm/9rBpf/awaX/2sCk/9nApP/ZwKP/2b+j/9m/ + ov/Zv6L/2b6h/9m+of/ZvqD/2b6g/7SZfv+njHL/p4tx/6aLcP+linD/pYpv/6SJbv+ag2n/kX1l/0k8 + EnBJPBJWSTwSPkk8EilJPBIYRzsSDEU5EQVCNxABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABIOxICSTwSBUk8Eg1JPBIZSTwSKUk8Ej+RfWX/wbem/+Lf0//o5dv/5+Ta/+fk2f/n49j/5uLX/72s + mP++rJr/xrio/7+tnP+4pJD/qpF5/9TKuv/i3c//4tzO/+Hbzf/h28z/4dnL/+DZyf/e1sb/3tXE/97V + xP/e1cP/qpJ5/6qSef+qk3r/q5N6/6uTe/+rk3v/q5R7/6uUfP+slHz/rJR9/6yVff+slX3/uKSN/8u6 + pf/d0Lz/3c+7/93Pu//dz7v/3M+6/9zOuf/czrn/3M64/9zNuP/czbf/3M23/9zMtv/czLb/3My1/9zL + tf/cy7X/3Mu0/9zKtP/byrP/28qz/9vJsv/bybL/28mx/9vIsf/byLD/28iw/9vHr//bx6//28eu/9vH + rv/bxq3/28at/9vGrP/bxaz/2sWr/9rFq//axKr/2sSq/9rEqf/aw6n/2sOo/9rDqP/awqf/2sKn/9rC + pv/awab/2sGl/9rBpf/awKT/2cCk/9nAo//ZwKP/0Lie/9C4nv/QuJ7/0Led/862nP/Ispr/tZqA/6eM + cv+ni3H/potw/6WKcP+lim//pIlu/56Fa/+RfWX/STwScEk8ElZJPBI+STwSKUk8EhhHOxIMRTkRBUI3 + EAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEg7EgFJPBIFSTwSDEk8EhdJPBInSTwSO497 + Y/O4rJn/4d3Q/+jl2//o5dv/5+Ta/+fk2f/n49j/xbak/7mmkv/HuKn/wK+d/7mlkv+tlX7/yr2r/+Pe + 0P/i3c//4tzO/+Hbzf/h2sz/4dnK/+DZyf/e1sX/3tXE/97Vw/+znob/qpJ5/6qTev+rk3r/q5N7/6uT + e/+rlHv/q5R8/6yUfP+slHz/rJV9/6yVff+slX7/rJZ+/7CZgv+/q5X/zr2o/9rLt//cz7r/3M65/9zO + uf/czrn/3M24/9zNuP/czbf/3My3/9zMtv/czLb/3Mu1/9zLtf/cy7T/3Mq0/9zKs//byrP/28my/9vJ + sv/bybH/28mx/9vIsP/byLD/28iv/9vHr//bx67/28eu/9vGrf/bxq3/28as/9vFrP/axav/2sWr/9rE + qv/axKr/2sSp/9rDqf/aw6j/07yj/9C6of/JtJz/x7Kb/8exm/+/qpX/v6qW/7yolP+2o5H/tqSS/7ek + kv+3pJL/t6ST/7elk/+3pZT/uKWU/7imlP+0nIX/p4xy/6eLcf+mi3D/pYpw/6WKb/+kiW7/n4Zr/5F9 + Zf9JPBJwSTwSVkk8Ej5JPBIpSTwSGEc7EgxFOREFQjcQAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAASDsSAUk8EgRJPBILSTwSFUk8EiVJPBI5i3hezq6gjP/g3M//6ebc/+jl3P/o5dv/6OXa/+fj + 2f/NwLD/uaWR/8i5q//BsJ//uqeU/6+Ygv/Iuaf/497R/+Pd0P/i3M//4tzO/+LbzP/h2sv/4drK/+DZ + yf/e1cT/3tXD/7qmkP+qknn/qpJ6/6uTev+rk3r/q5N7/6uUe/+rlHz/rJR8/6yUfP+slX3/rJV9/6yV + fv+sln7/rZZ+/62Wf/+tln//rZd//7ahiv+/q5X/x7ag/9DAq//ZyrT/3M24/9zNt//czLf/3My2/9zM + tv/cy7X/3Mu1/9zLtP/cy7T/3Mqz/9vKs//byrL/28my/9vJsf/bybH/28iw/9vIsP/byK//28ev/9vH + rv/bx67/28au/9vGrf/bxqz/28Ws/9C7o//Qu6P/x7Kb/8Svmf+9qZT/uKWR/7Shjv+1oY7/taGP/7Wi + j/+1oo//taKQ/7aikP+2o5H/tqOR/7ajkf+2pJL/t6SS/7ekkv+3pJP/t6WT/7ellP+4pZT/uKaU/7CZ + hP+njHL/p4xx/6aLcP+minD/pYpv/6WJbv+fhmv/kX1l/0k8EnBJPBJWSTwSPkk8EilJPBIYRzsSDEU5 + EQVCNxABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASTwSA0k8EgpJPBITSTwSIkk8 + EjaJdlzDpJR//9/bzf/p5t3/6ebc/+jm3P/o5dv/6OTa/9fOwP+znoj/ybus/8Kyof+7qZb/spyG/7uo + lP/k39L/497R/+Pd0P/j3M//4tzN/+Lbzf/h2sv/4drK/+DYyP/e1cT/xLOe/6qSef+qknr/q5N6/6uT + ev+rk3v/q5R7/6uUfP+rlHz/rJR8/6yVff+slX3/rJV9/6yWfv+tln7/rZZ//62Wf/+tl3//rZeA/66X + gP+ul4H/rpiB/66Ygf+umIL/t6KM/7qmkP+6pY//xbKc/8WznP/Gspz/xrKc/8aynP/Gspz/xbKc/8ay + nP/Gspz/xrKc/8aynP/Gspz/xrKc/8aynP+8p5L/vKiS/7yok/+8qJP/uKOO/7Ofi/+zn4v/s5+L/7Of + jP+0oIz/tKCN/7Sgjf+0oY3/tKGO/7Whjv+1oY//taKP/7Wij/+1opD/tqKQ/7ajkP+2o5H/tqOR/7ak + kv+7q5v/t6SS/7ekk/+3pZP/t6WU/7ellP+4ppT/sJmE/6eMcv+njHH/potw/6aKcP+lim//pYlu/5+G + a/+RfWX/aVg2j0k8ElZJPBI+STwSKUk8EhhHOxIMRTkRBUI3EAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABJPBIDSTwSCUk8EhJJPBIgSTwSNIFvU6KaiHL/39vN/+fk2v/p593/6ebc/+nm + 3P/o5dv/29PH/7Wgi//Juqz/w7Oi/72qmP+0n4r/uaaR/+Tf0//k39L/497R/+Pd0P/j3M7/4tvN/+Lb + zP/h2sv/4dnK/+DYyP/RxLH/qpJ5/6qSev+qk3r/q5N6/6uTe/+rlHv/q5R8/6uUfP+slHz/rJV9/6yV + ff+slX3/rJZ+/62Wfv+tln//rZZ//62Xf/+tl4D/rpeA/66Xgf+umIH/rpiB/66Ygv+vmIL/r5mD/6+Z + g/+vmYP/r5qE/7CahP+wmoT/sJqF/7Cbhf+wm4b/sZuG/7Gchv+xnIf/sZyH/7GciP+xnYj/sp2I/7Kd + if+ynYn/sp6K/7Keiv+znor/s5+L/7Ofi/+zn4v/s5+M/7SgjP+0oI3/tKCN/7Shjf+0oY7/taGO/7Wh + jv+1oo//taKP/7Ohj/+0o5H/tqaX/7qtof/Atq3/x8G7/83Jxf/OycT/uaeX/7elk/+3pZP/t6WU/7il + lP+wmYT/p4xy/6eMcf+mi3H/popw/6WKb/+liW7/n4Zr/5F9Zf9pWDaPSTwSVkk8Ej5JPBIpSTwSGEc7 + EgxFOREFQjcQAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEk8EgNJPBIISTwSEUk8 + Eh9JPBIxfmxPlZF9Zf/f283/5+Ta/+rn3v/p593/6ebd/+nl3P/l4Nb/t6KN/8W1pf/EtKT/vqya/7ej + jv+xmoT/5eDU/+Tf0//k39L/5N7R/+Pdz//j3M7/4tvN/+LbzP/i2sv/4dnK/+DYyP+qknr/qpJ6/6qT + ev+rk3r/q5N7/6uUe/+rlHz/q5R8/6yUfP+slX3/rJV9/6yVff+slX7/rZZ+/62Wf/+tln//rZd//62X + gP+ul4D/rpeB/66Ygf+umIH/rpiC/6+Ygv+vmYP/r5mD/6+Zg/+vmoT/sJqE/7CahP+wmoX/sJuF/7Cb + hv+wm4b/sZyG/7Gch/+xnIf/sZyI/7GdiP+ynYj/sp2J/7Kdif+ynon/sp6K/7Oeiv+zn4v/s5+L/7Of + i/+zn4z/tKCM/7SgjP+0oI3/rpqF/6uXgv+ok37/ppF+/6aTgP+nlYT/rJyM/7GilP+2qZ3/u7Cm/8G4 + sP/HwLr/zcnE/9PRz//Fu7H/t6WT/7elk/+3pZT/uKWU/7CZhP+njHL/p4xx/6aLcf+minD/pYpv/6WJ + bv+fhmv/kX1l/2lYNo9JPBJXSTwSP0k8EilJPBIYRzsSDEU5EQVCNxABAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAASTwSA0k8EgdJPBIQSTwSHUk8Ei9xYEBykX1l/9XPwP/l4tf/6ujf/+rn + 3v/q593/6ebc/+nl3P+4pJD/xbWl/8a2pv+/rZz/uaWR/7Kchv/f2Mv/5eDU/+Tf0//k3tH/5N7R/+Pd + z//j3M7/49zN/+LbzP/i2sv/4dnK/7mmkP+qknr/qpN6/6uTev+rk3v/q5N7/6uUfP+rlHz/rJR8/6yV + ff+slX3/rJV9/6yVfv+tln7/rZZ//62Wf/+tl3//rZeA/66XgP+ul4H/rpiB/66Ygf+umIL/r5iC/6+Z + gv+vmYP/r5mD/6+ahP+vmoT/sJqE/7Cahf+wm4X/sJuG/7Cbhv+xnIb/sZyH/7Gch/+xnIf/sZ2I/7Kd + iP+ynYn/sp2J/7Keif+ynor/s56K/7Oeiv+tmIP/qJJ8/5+Hb/+cg2v/mH9n/5J4X/+VfGT/mIBp/5uF + b/+finX/o498/6eVg/+rm4v/sKGT/7WonP+7sKX/wLev/8a/uf/MyMP/09DO/8e+tf+3pZP/t6WT/7el + lP+4pZT/sJmE/6eMcv+njHL/potx/6aLcP+lim//pYlv/6OIbf+RfWX/aFg2j0k8ElhJPBJASTwSKkk8 + EhlHOxINRTkRBUI3EAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJPBIDSTwSB0k8 + Eg9JPBIbSTwSLGtaOWSRfWX/y8Oz/+Xi1v/r6N//6ujf/+rn3v/q593/6ebc/8W2pP/CsaD/x7eo/8Cv + nv+7qJT/tJ6J/9nQwv/l4dX/5eDU/+Xf0//k39H/5N7Q/+Pd0P/j3M7/49zN/+LazP/i2sv/x7il/6+Z + gv+qk3r/q5N6/6uTe/+rk3v/q5R7/6uUfP+slHz/rJV9/6yVff+slX3/rJV+/62Wfv+tln//rZZ//62X + f/+tl4D/rpeA/66XgP+umIH/rpiB/66Ygv+umIL/r5mC/6+Zg/+vmYP/r5qE/6+ahP+wmoT/sJqF/7Cb + hf+wm4X/sJuG/7Gbhv+xnIf/sZyH/7Gch/+xnYj/sp2I/7Kdif+ynYn/sp6J/7Keiv+dg2v/im1R/4hr + Tv+JbVH/i29T/41xVv+PdFr/knde/5R7Y/+Xf2j/m4Ru/56JdP+ijnv/ppSC/6uaiv+woZL/rJ2O/62f + kP+xpZf/xb64/8vHwv/Sz83/x720/7elk/+3pZP/t6WU/7illP+wmYT/p4xy/6eMcv+mi3H/potw/6WK + b/+liW//pIlu/5F9Zf9oWDaRSTwSWUk8EkFJPBIrSTwSGkc7Eg5FOREGQzcQAgAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEk8EgJJPBIFSTwSDUk8EhlJPBIpSTwSPpF9Zf/Bt6b/4t7S/+vp + 4P/r6OD/6ujf/+rn3v/q593/ybur/8Gwnv/Iuan/wrGg/7ypl/+2oYz/0MS1/+bh1v/m4dX/5eDU/+Xf + 0//k39H/5N3Q/+Tdz//j3M7/49vN/+LbzP/UyLb/tJ+J/7Cag/+rk3r/q5N7/6uTe/+rlHv/q5R8/6yU + fP+slX3/rJV9/6yVff+slX7/rp+O/7nHzv/F1N7/x9HW/7esn/+ul4D/rpeA/66Ygf+umIH/rpiC/66Y + gv+vmYL/r5mD/6+Zg/+vmYP/r5qE/7CahP+wmoX/sJuF/7Cbhf+wm4b/sZuG/7Gch/+xnIf/sZyH/7Gd + iP+ynYj/sp2J/7Kdif+ynon/p5B6/4dpTP+Hak3/iGtO/4lsUP+LblP/jXFW/490Wv+Rd17/lHtj/5d/ + aP+Zgmz/mIJs/5WAav+RfGX/jnli/4VvVf+Fb1X/hW9V/4VvVf+Rfmj/x8G6/9HOzP/Nx8H/t6WT/7el + k/+3pZT/uKWU/7CZhP+ojXP/p4xy/6eLcf+mi3D/pYpw/6WJb/+kiW7/kX1l/2hYNpJJPBJbSTwSQ0k8 + Ei1JPBIbRzsSD0U5EQdCNxACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASTwSAUk8 + EgVJPBIMSTwSF0k8EidJPBI7j3tj87ismf/i3tL/7Onh/+vp4P/r6OD/6+jf/+rn3v/TyLr/wK6c/8m6 + q//DsqL/vauZ/7ijj//OwrL/5uLX/+bh1f/m4NX/5eDT/+Xf0v/k3tH/5N7Q/+Tdz//j3M7/49vN/+DX + yP+1oIv/tKCK/7Gag/+rk3v/q5N7/6uUe/+rlHz/rJR8/6yUff+slX3/rJV9/6yZhv+32/b/yuj+/9zw + /v/m9P//3/H//7y3r/+ul4D/rpiB/66Ygf+umIL/rpiC/6+Zgv+vmYP/r5mD/6+Zg/+vmoT/o6uq/562 + wf+etsH/pKyr/7Cbhv+xm4b/sZyH/7Gch/+xnIf/sZ2I/7KdiP+ynYn/sp2J/7Keif+cg2v/h2lM/4dp + Tf+Iak7/iWxQ/4tuU/+NcVb/jHJY/4tzWf+Iclj/h3BX/4VvVf+Fb1X/hW9V/4VvVf+Fb1X/hW9V/4Vv + Vf+Fb1X/hW9V/4VvVf+om4v/0M7L/87JxP+3pZP/t6WT/7ellP+4pZT/sJmD/6iNc/+njHL/p4tx/6aL + cP+linD/pYlv/6SJbv+RfWX/emlLt0k8El5JPBJFSTwSL0k8Eh1HOxIQRTkRCEI3EAM8Mg8BAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJPBIBSTwSBEk8EgtJPBIVSTwSJUk8EjmLeF7OrqCM/9/b + zf/s6uL/7Onh/+vp4P/r6eD/6+jf/9rRxP++rJn/yryt/8S0pP+/rZv/uaaS/8Ozof/n49j/5+LW/+bh + 1v/m4NT/5eDT/+Xf0v/l3tH/5N7Q/+Tdz//j3M7/49vN/8Gwnf+1oYz/taCL/7GahP+rk3v/q5R7/6uU + fP+slHz/rJR9/6yVff+slX3/qsDO/7ri/v/Q6/7/5fT///b7///r9v//1Oj2/6+ciP+umIH/rpiB/66Y + gv+umIL/r5mC/6+Zg/+vmYP/oKmp/4vN9v+S1P7/mNf+/5jX/v+U1f7/js72/6Orq/+xnIf/sZyH/7Gc + h/+xnYj/sp2I/7Kdif+ynYn/sp6J/6SNdv+HaUz/h2lN/4hqTv+JbFD/im5S/4lvVf+Fb1X/hW9V/4Vv + Vf+Fb1X/hW9V/4VvVf+Qe2P/nIp1/7iqmv/IvbH/4drT//r49/+xo5P/hW9V/5aFcP/Qzcn/zsjD/7el + k/+3pZP/t6WU/7illP+wmYP/qI1z/6eMcv+ni3H/potw/6WKcP+liW//pIlu/5F9Zf96aEu5STwSYEk8 + EkdJPBIxSTwSHkc7EhFFOREIQjcQAzwyDwEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABJPBIDSTwSCkk8EhNJPBIiSTwSNol2XMOklH//39vN/+zp4f/s6uL/7Orh/+zp4f/r6eD/4NnO/7+s + mv/Lva//xral/8Cvnf+7qJX/wbCe/+fj2f/n49f/5+LW/+bh1f/m4dT/5uDT/+Xf0v/l3tH/5N7Q/+Td + z//j3M7/zb+u/7ejjv+2ooz/taCM/7Kchv+rlHz/q5R8/6yUfP+slH3/rJV9/6yVff+pyN7/uOD+/8zp + /v/f8f//6vb//+Pz///S6/7/trSv/66Ygf+umIH/rpiC/66Ygv+vmYL/r5mD/5ursf+Fz/7/k9X+/5/a + /v+o3f7/qd7+/6Lb/v+W1v7/idH+/5e0wv+xnIf/sZyH/7GciP+ynYj/sp2I/7Kdif+ynon/qZR+/4dp + TP+HaUz/iGpO/4lsUP+KblL/hW9U/4VvVf+KdFr/mINr/6eUfv+6qZf/z8K1/9zSyP/j3NT/6uTe//Ds + 6P/18vD/+fj2/8C1p/+Fb1X/jXpi/8/MyP/NyML/t6WT/7elk/+3pZT/uKWU/7CZg/+ojXP/p4xy/6eL + cf+mi3D/pYpw/6WKb/+kiW7/kX1l/3poS7lJPBJiSTwSSUk8EjJJPBIfRzsSEkU5EQlCNhAEPTIPAQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEk8EgNJPBIJSTwSEkk8EiBJPBI0gW9TopqI + cv/f283/6efe/+3r4//s6uL/7Orh/+zp4f/m4df/wK6c/8i5qv/Gt6f/wrCf/72qmP+6ppP/6OTZ/+jj + 2P/n49f/5+LW/+bh1f/m4dT/5t/T/+Xf0v/l3tH/5N3Q/+Tdz//b0sL/uKWQ/7ijjv+3oo7/tqGM/7Oe + iP+rlHz/rJR8/6yUfP+slX3/rJV9/6fI3v+v3f7/weT+/8/q/v/V7f7/0ev+/8Xm/v+zvL//rpeB/66Y + gf+umIH/rpiC/6+Zgv+nnpL/esv+/4rR/v+b2P7/qt7+/7bj/v+45P7/rd/+/5/Z/v+P0/7/f8z+/52p + rP+xnIf/sZyI/7GdiP+ynYj/sp2J/7Keif+ynor/h2lM/4dpTP+Iak7/iWxP/4puUv+Fb1X/hW9V/6OM + dP+2oY3/wK6d/8q7rP/Txrn/29HG/+La0v/p493/7+vm//Tx7v/59/X/3tjQ/4VvVf+Fb1X/zsvH/9XU + 0v+3pJP/t6WT/7ellP+4pZT/sJmD/6iNc/+njHL/p4tx/6aLcP+linD/pYpv/6SJbv+VgGf/emhKukk8 + EmNJPBJKSTwSM0k8EiBHOxISRTkRCUI2EAQ9Mg8BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAASTwSA0k8EghJPBIRSTwSH0k8EjF6aEuKkX1l/9/bzf/p5t3/7evj/+3r4//t6uL/7Ori/+zp + 4f/CsJ//ybqr/8i5qf/DsqH/vqyZ/76smv/o5Nr/6OTZ/+jj2P/n4tf/5+LW/+bh1f/m4NT/5t/T/+Xf + 0v/l3tH/5N3Q/+Tdz/+8qpb/uaWQ/7ikkP+3o47/tqKN/7Oeif+slH3/rJR8/6yVff+slX3/p8PW/6fZ + /v+x3f7/u+L+/8Dk/v+94/7/tN/+/620t/+ul4H/rpiB/66Ygf+umIL/r5mC/4a1z/98y/7/jNL+/53Y + /v+t3/7/veb+/8Dn/v+y4f7/odr+/5HU/v+Azf7/ecHv/7Gch/+xnIj/sZ2I/7KdiP+ynYn/sp6J/7Ke + iv+Pclf/h2lM/4hqTf+Ja0//im1R/4VvVf+Fb1X/oYpy/7Wfiv+/rJr/yLmp/9HEt//az8T/4dnQ/+jh + 2//u6eX/8/Dt//j29P/d19D/hW9V/4VvVf/JxL//1NPR/7ekk/+3pZP/t6WU/7illP+vmIH/qI1z/6eM + cv+njHH/potw/6aKcP+lim//pYlu/5WAZ/96aEq5STwSYkk8EklJPBIzSTwSIEc7EhJFOREJQjYQAzwy + DwEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJPBIDSTwSB0k8EhBJPBIdSTwSL3Fg + QHKRfWX/2tXG/+bj2f/u7OT/7evk/+3r4//t6uL/7Ori/8u9rf/EtKP/x7eo/8Kwn/++rJr/0cS2/+nl + 2//o5Nr/6OTZ/+jj2P/n4tf/5+LW/+fh1f/m4NT/5uDT/+Xf0v/l3tH/5d3Q/8q8qv+6p5L/uaWR/7ik + kP+3pI//tqKN/7Wgi/+tln//rJV9/6yVff+prq3/ptn+/6bZ/v+p2v7/q9v+/6ra/v+m2f7/rZ+Q/66X + gf+umIH/rpiB/66Ygv+vmYL/bsH2/3nK/v+J0f7/mdf+/6fd/v+y4f7/tOL+/6ve/v+d2f7/jtL+/37M + /v9txf7/oqOd/7GciP+xnYj/sp2I/7Kdif+ynYn/sp6K/5F2W/+HaUz/iGpN/4hrT/+KbVH/hW9V/4Vv + Vf+chGz/s52H/72ql//Ht6f/0MK1/9jNwv/g187/5+DZ/+3o4//z7+z/9/Xz//v6+f+Fb1X/hW9V/7yz + qv/U0tD/t6ST/7elk/+3pZT/t6WU/6yTe/+ojXP/p4xy/6eMcf+mi3D/popw/6WKb/+liW7/lYBn/3po + S7lJPBJgSTwSR0k8EjFJPBIeRzsSEUU5EQhCNxADPDIPAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAEk8EgNJPBIHSTwSD0k8EhtJPBIsYlMvWZF9Zf/Lw7P/5eHW/+7s5f/u7OT/7uvk/+3r + 4//t6+L/5eDW/8m6qv/CsaD/x7em/9XKvf/q593/6ubc/+nl2//p5dr/6OTZ/+jj2P/n4tf/5+LW/+fh + 1f/m4NT/5uDT/+bf0v/l3tH/2M29/7uolf+6p5P/uaaS/7ilkf+4pJD/t6OO/7ahjP+vmYP/rJV9/6yV + ff+ov87/ptn+/6bZ/v+m2f7/ptn+/6m8xv+ul4D/rpeB/66Ygf+umIH/rpiC/6Sdkf9kwv7/dMj+/4LO + /v+Q1P7/nNj+/6Pb/v+k3P7/ntn+/5PV/v+G0P7/eMr+/2nD/v+HrcP/sZyI/7GdiP+ynYj/sp2J/7Kd + if+ynor/nINr/4dpTP+Iak3/iGtP/4ptUf+GblT/hW9V/5d/Zv+xm4X/vKiV/8W1pP/PwbP/18zA/9/W + zf/m39j/7Ofi//Lu6//39PL/8/Du/4VvVf+Fb1X/u7Kp/9PRz/+7qpv/t6WT/7elk/+3pZT/rJR8/6iN + c/+njHL/p4xx/6aLcf+minD/pYpv/6WJbv+VgGf/h3Ra20k8El1JPBJFSTwSLkk8Eh1HOxIQRTkRCEI3 + EAM8Mg8BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASTwSAkk8EgVJPBINSTwSGUk8 + EilJPBI+kX1l/8a9rP/j39P/7+3m/+7s5f/u7OX/7uzk/+3r4//t6uL/7eri/+zp4f/s6OD/6+jf/+vn + 3v/q5t3/6ubc/+nl2//p5dr/6OTZ/+jj2P/o49f/5+HW/+fh1f/m4NT/5t/T/+bf0v/j283/vKqW/7yp + lf+7p5T/uqeS/7mmkv+4pJD/uKOP/7ejjv+xnIb/rJV9/6yVfv+qr67/qMTW/6jE1v+qq6f/rZeA/66X + gP+ul4H/rpiB/66Ygf+umIL/mKGh/16//v9sxf7/ecr+/4TP/v+O0/7/k9X+/5TV/v+Q0/7/h9D+/3zL + /v9vxv7/YsH+/4Ssw/+xnIj/sZ2I/7KdiP+ynYn/sp2J/7Keif+iinL/h2lM/4hqTf+Ia0//im1R/4Zu + VP+Fb1X/knth/6+Zgv+6ppL/xLOi/82/sf/Wyr7/3tTL/+Xd1v/e187/1s7E/72xo/+ikX3/hW9V/4Vv + Vf/DvLX/0tDO/7+xo/+3pZP/t6WT/7ellP+qkHj/qI1z/6eMcv+njHH/potx/6aKcP+lim//pYlu/5aA + Z/+IdFraSTwSWEk8EkBJPBIrSTwSGkc7Eg5FOREHQjcQAjwyDwEAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABJPBIBSTwSBUk8EgxJPBIXSTwSJ0k8EjuOemLnuKyZ/+Dczv/v7eb/7+3m/+/t + 5f/u7OX/7uzk/+3r4//t6uL/7erh/+zp4f/s6OD/6+jf/+vn3v/q5t3/6ubc/+nl2//p5Nr/6OTZ/+jj + 2P/o4tf/5+LW/+fh1f/n4NT/5t/T/+bf0v/Ku6r/vaqX/7yplv+7qJT/uqeU/7mmkv+5pZH/uKSQ/7ej + jv+zn4r/rZZ//62Wfv+tln//rZZ//62Xf/+tl4D/rpeA/66Xgf+umIH/rpiB/66Ygv+pmon/Vbv//2LB + /v9txf7/d8n+/3/M/v+Dzv7/g87+/4DN/v95yv7/cMb+/2XC/v9Yvf//f6rD/7Gch/+xnYj/sp2I/7Kd + if+ynYn/sp6J/6eQev+HaUz/h2pN/4hrTv+JbVD/iG5T/4VvVf+LdFv/rpd//7ikkP+zoY3/rZuH/6eW + gv+biHL/hW9V/4VvVf+Fb1X/hW9V/4VvVf+Fb1X/oZKB/8vGwv/Sz8z/vrCj/7elk/+3pZP/tqOS/6iO + dP+ojXP/p4xy/6eMcf+mi3H/popw/6WKb/+liW7/loBn/3xqTbJJPBJTSTwSO0k8EidJPBIXRzsSDEU5 + EQVCNxABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEk8EgFJPBIESTwSC0k8 + EhVJPBIlSTwSOYt4Xs6zppL/39vN//Du5//v7eb/7+3m/+/t5v/u7OX/7uzk/+3r4//t6uL/7erh/+zp + 4P/s6N//7Ojf/+vn3v/q5t3/6ubc/+nl2//p5Nr/6eTZ/+jj2P/o4tf/5+LW/+fh1f/n4NT/5uDT/9fM + vf++rJn/vauY/7yqlv+7qZb/u6iU/7qmk/+5ppL/uKWQ/7ejj/+2oo3/sJqD/62Wf/+tln//rZd//62X + gP+ul4D/rpeA/66Ygf+umIH/rpiC/6+Ygv9Rtff/Vrz//2DA/v9pw/7/b8b+/3PI/v9zyP7/cMf+/2vE + /v9jwf7/Wb3//024//96qMP/sZyH/7GdiP+ynYj/sp2J/7Kdif+ynon/sp6K/4dpTP+Hak3/iGtO/4ls + UP+IblP/hW9V/4VvVf+Fb1X/hW9V/4VvVf+Fb1X/hW9V/4VvVf+Fb1X/hW9V/4VvVf+NeWL/lYJt/6mb + i//Evbb/y8XA/8/Lx/+4p5f/t6WT/7elk/+xnIj/qI50/6iNc/+njHL/p4xy/6aLcf+mi3D/pYpv/6WJ + b/+SfWX/eWhKpEk8EkxJPBI1STwSIkk8EhRHOxIKRTkRBEI3EAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEk8EgNJPBIKSTwSE0k8EiJJPBI2h3RZuKSUf//f283/7erj//Du + 5//v7ef/7+3m/+/t5v/u7OX/7uzk/+7r4//t6uL/7erh/+zp4P/s6OD/6+jf/+vn3v/q593/6ubc/+rl + 2//p5Nr/6eTZ/+jj2P/o4tf/6OLW/+fh1P/n4NT/5N3P/8Cum/+/rJr/vqyZ/72rmP+8qZb/u6iV/7qo + lP+5ppL/uKWR/7ikkP+3o4//s56J/62Wf/+tl3//rZeA/66XgP+ul4D/rpiB/66Ygf+umIL/rpiC/2qp + 0P9Jt///Urr//1q9//9fwP7/YsH+/2LB/v9gwP7/XL7//1W7//9MuP//QbP//5Ohpf+xnIf/sZ2I/7Kd + iP+ynYn/sp2J/7Keif+ynor/jG9T/4dpTf+Iak7/iWxQ/4tuUv+Hb1X/hW9V/4VvVf+Fb1X/hW9V/4Zw + Vv+LdVz/kXxl/5mFcP+gjnv/rp+Q/7Ommf+5raL/vrSr/8S8tf/HwLn/u6uc/7ekk/+3pZP/tqOR/6qR + eP+ojnT/qI1z/6eMcv+njHL/potx/6aLcP+lim//ooht/5F9Zf9mVjN2STwSREk8Ei9JPBIeSTwSEUc7 + EghFOREDQjYQAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASTwSA0k8 + EglJPBISSTwSIEk8EjSBb1Oin454/9/bzf/s6uH/8O7o//Du5//v7ef/7+3m/+/t5v/u7OX/7uvk/+7r + 4//t6uL/7erh/+3p4P/s6N//6+jf/+vn3v/q593/6ubc/+rl2//p5dr/6eTZ/+jj2P/o49f/6OLW/+fh + 1f/n4NP/z8Gx/8CunP+/rZv/vqya/72rmP+9qpf/vKmW/7uolP+6p5P/uaaS/7mlkf+4pJD/tqKO/7Cb + hP+tl4D/rZeA/66XgP+umIH/rpiB/66Ygv+umIL/oJuS/zux//9EtP//S7f//0+5//9Suv//Urr//1C5 + //9MuP//RrX//z6y//9FrPD/sZyH/7Gch/+xnYj/sp2I/7Kdif+ynYn/sp6J/7Keiv+Sdlv/h2lM/4hq + Tv+JbFD/im5S/4xwVf+Mclj/i3NZ/5B3Xv+VfWX/mYJs/52Hcv+hjHn/pZKA/6mYh/+wn4//tKSV/7en + l/+4p5f/tqST/7akkv+3pJL/t6ST/7elk/+ul4D/qY51/6mOdP+ojXP/qI1z/6eMcv+ni3H/potw/6WK + cP+chGr/j3tj9Ek8ElBJPBI7STwSKEk8EhlJPBINRzsSBkY6EQJCNhABAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJPBIDSTwSCEk8EhFJPBIfSTwSMXpoS4qRfWX/39vN/+jl + 2//x7+n/8O7o//Du5//w7uf/7+3m/+/s5v/v7OX/7uzk/+7r4//t6uL/7erh/+3p4P/s6OD/6+jf/+vn + 3v/r5t3/6ubc/+rl2//p5Nr/6eTZ/+jj2P/o4tf/6OHW/+fh1f/b0cP/wbCe/8Cvnf+/rpz/vq2a/76r + mf+9q5j/vKqW/7uolf+6qJT/uqeT/7mlkv+4pJD/t6OP/7Sgi/+wmYP/rpeA/66Ygf+umIH/rpiC/66Y + gv+vmYL/b6LB/zWu//87sf//P7P//0Gz//9Bs///QLP//zyx//83r///MKz//5Cfpf+xnIf/sZyH/7Gd + iP+ynYj/sp2J/7Kdif+ynon/sp6K/52Da/+HaUz/iGpO/4lsUP+KblL/jHBV/45zWP+Qdlz/k3lh/5uE + bf+jjXj/qZSA/6+cif+yn4z/taKP/7WikP+2o5D/tqOR/7ajkf+2o5H/tqSS/7ekkv+1oY//rJN7/6qP + dv+pjnX/qY50/6iNc/+ojXP/p4xy/6eLcf+mi3D/pYpw/5N+Zv+Fcle+STwSREk8EjFJPBIhSTwSFEk8 + EgpHOxIERjoRAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEk8 + EgNJPBIHSTwSEEk8Eh1JPBIvcWBAcpF9Zf/a1cb/6OXb//Hv6f/x7+n/8O/o//Du6P/w7uf/7+3m/+/t + 5v/v7OX/7uzk/+7r4//u6uL/7erh/+zp4P/s6OD/6+je/+vn3v/r5t3/6ubc/+rl2//p5Nr/6eTZ/+nj + 2P/o4tf/6OLW/+fh1P/Ht6f/wbCf/8Cwnf/Arpz/v62b/76smv+9q5n/vKqX/7uplv+7qJT/uqeU/7mm + kv+4pZH/t6SQ/7ejjv+0n4r/sJqE/66Ygf+umIL/rpiC/6+Zgv+vmYP/bKHB/yuq//8vrP//Ma3//zGt + //8vrP//LKv//yep//98oLP/sZyH/7Gch/+xnIf/sZyI/7KdiP+ynYj/sp2J/7Keif+ynor/sJqG/5d9 + Y/+Iak3/jnJX/5d9ZP+giHD/qJF8/62Yg/+0oI3/tKGN/7Shjv+1oY7/taGP/7Wij/+1oo//taKQ/7aj + kP+2o5H/tqOR/7ajkf+znor/r5iB/6uQd/+qkHb/qo92/6mPdf+pjnT/qI1z/6iNc/+njHL/p4tx/6aL + cP+fhmz/kX1l/2BRLV9JPBI4STwSJ0k8EhlJPBIPSTwSB0c7EgNFOREBAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASTwSA0k8EgdJPBIPSTwSG0k8EixiUy9ZkX1l/8vD + s//j4NT/8vDq//Hw6v/x7+n/8e/o//Du6P/w7uf/7+3m/+/t5v/v7OX/7uvk/+7r4//u6uL/7erh/+zp + 4f/s6eD/7Ojf/+vn3v/r5t3/6ubb/+rl2//q5Nn/6eTZ/+nj1//o4tf/6OLW/9jMvv/DsqH/wrGf/8Gw + nv/Br53/wK6c/7+tm/++q5n/vaqY/7yqlv+7qZX/uqeU/7qmk/+5ppL/uKSQ/7ejj/+3o47/tJ+K/7Cb + hv+umIL/r5mC/6+Zg/+vmYP/i5yi/1ah0P8qpff/IKb//zKk7/9VodH/npyV/7Gbhv+xnIb/sZyH/7Gc + h/+xnIj/sp2I/7KdiP+ynYn/sp6J/7Keiv+ynor/s56K/7Ofi/+zn4v/s5+L/7OgjP+0oIz/tKCN/7Sg + jf+0oY3/tKGO/7Whjv+1oY//taKP/7Wij/+0oY7/tJ+L/7Gbhv+vl4D/rZN7/6ySeP+rkXj/q5B3/6qQ + dv+qj3b/qY91/6mOdP+ojXP/qI1z/6eMcv+ni3H/pIpv/5N+Zv+Gc1i7STwSPUk8EixJPBIdSTwSEkk8 + EgpJPBIESDsSAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABJPBICSTwSBUk8Eg1JPBIZSTwSKUk8Ej6RfWX/xr2s/+Lf0v/y8ev/8vDq//Hw6v/x7+n/8e/p//Du + 6P/w7uf/8O3m/+/t5v/v7OX/7+vk/+7r4//t6uL/7erh/+zp4P/s6eD/7Ojf/+vn3v/r593/6ubc/+rl + 2//q5Nr/6eTZ/+nj2P/o4tb/5d7S/8a2pv/Ds6H/wrKg/8Kwn//Br57/wK6c/7+tm/++rJr/vquY/72q + l/+8qZb/u6iV/7qnlP+5ppL/uaWR/7ikkP+3o4//tqKO/7WgjP+ynYf/sJqE/6+Zg/+vmYP/r5qE/7Ca + hP+wmoT/sJuF/7Cbhf+wm4b/sZuG/7Gchv+xnIf/sZyH/7GciP+xnYj/sp2I/7Kdif+ynon/sp6K/7Ke + iv+znor/s5+L/7Ofi/+zn4v/s6CM/7SgjP+0oI3/tKCN/7Shjf+0oI3/s56K/7Kch/+xmYP/r5d//66V + fP+ulHv/rZR7/62Tev+sknn/rJJ4/6uReP+rkHf/qpB2/6qPdv+pj3X/qY50/6iNc/+ojXP/p4xy/6eM + cf+XgWj/j3tj81hJI0pJPBIvSTwSIUk8EhVJPBIMSTwSB0k8EgNHOxIBAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEk8EgFJPBIFSTwSC0k8EhZJPBImSTwSO456 + Yue4rJn/39vN//Px7P/y8ev/8vDr//Lw6v/x7+n/8e/p//Du6P/w7uf/8O3m/+/t5v/v7OX/7+zk/+7r + 4//t6uL/7erh/+zp4P/s6OD/7Oje/+vn3f/r5tz/6uXb/+rl2v/p5Nn/6ePY/+ji1//o4db/1su9/8S0 + o//Ds6L/w7Gg/8Kxn//BsJ7/wK+d/7+unP+/rZr/vqyZ/72rmP+8qpf/u6mW/7qolP+6ppP/uaaS/7il + kf+3pJD/tqKP/7aijf+1oY3/s5+K/7Gch/+wm4X/sJqE/7CahP+wm4X/sJuF/7Cbhv+xm4b/sZyG/7Gc + h/+xnIf/sZyI/7GdiP+ynYj/sp2J/7Keif+ynor/sp6K/7Oeiv+zn4v/s5+L/7Ofi/+zn4r/s56J/7Od + h/+ym4T/sZmB/7GYgP+wmH//sJd//6+Wfv+vln3/rpV8/66UfP+tlHv/rZN6/6ySef+sknn/q5F4/6uR + d/+qkHb/qo92/6mPdf+pjnT/qI1z/6iNc/+njHL/mYJp/5F9Zf9sXDpgSTwSL0k8EiJJPBIXSTwSDkk8 + EgdJPBIESTwSAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAASTwSAUk8EgRJPBIKSTwSFEk8EiRJPBI3i3hezrOmkv/f283/8O/p//Px7P/y8ev/8vDr//Lw + 6v/x8Or/8e/p//Hu6P/w7uf/8O3m/+/t5v/v7OX/7+zk/+7r4//t6uL/7erh/+3p4P/s6N//6+fe/+vm + 3f/q5tz/6uXb/+nk2v/p49j/6OLX/+ji1v/l3tL/x7in/8S0o//DsqL/wrKh/8KxoP/BsJ7/wK+d/8Cv + nP+/rZv/vqya/72rmf+8q5j/u6mW/7uolf+6p5T/uaaT/7ilkv+4pJH/t6SP/7aij/+1oY3/tKCM/7Sg + i/+znon/sp2I/7Gch/+wm4b/sJuG/7Gbhv+xnIb/sZyH/7Gch/+xnIj/sZ2I/7KdiP+ynYn/sp2J/7Ke + iv+znon/tJ6I/7SeiP+0nYf/tJyF/7SbhP+zm4P/s5qC/7Kagv+xmYH/sZiA/7CYf/+wl3//r5Z+/6+W + ff+ulXz/rpR8/62Ue/+tk3r/rJJ5/6ySef+rkXj/q5F3/6qQdv+qj3b/qY91/6mOdP+ojXP/pYtx/5WA + Z/+RfWX/fWtOgkk8Ei5JPBIiSTwSF0k8Eg9JPBIJSTwSBEk8EgJJPBIBAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASTwSA0k8EglJPBISSTwSIUk8 + EjOHdFq3pJR//9/bzf/u7OX/8/Lt//Px7P/z8ez/8vHr//Lw6v/x8Or/8e/p//Hu6P/w7uf/8O3n/+/t + 5f/v7OX/7uvk/+7r4//t6uL/7enh/+zo4P/s6N7/6+fd/+rm3P/q5dv/6eTa/+jj2P/n4tf/5+HV/+bg + 1P/Xzb//xLSk/8Ozo//Ds6L/wrKh/8KxoP/BsJ//wbCe/8Cvnf/Arpz/vq2b/72smv+9q5j/vKqX/7up + lv+6qJX/uaeU/7mmk/+4pZH/t6SR/7ejj/+2oo7/taGN/7Wgi/+ynYn/sZ2H/7Cchv+wm4b/sZuG/7Gc + hv+xnIf/sZyH/7KdiP+znon/tZ+J/7agif+2n4n/t5+I/7afiP+2nof/tZ2G/7Wdhv+0nIX/tJyE/7Ob + g/+zmoP/spqC/7KZgf+xmID/sZiA/7CXf/+wln7/r5Z9/6+Vff+ulHz/rpR7/62Tev+tk3r/rJJ5/6uR + eP+rkXf/qpB3/6qPdv+pj3X/poxy/5yFbP+RfWX/kHxj8m9ePllJPBIqSTwSH0k8EhZJPBIPSTwSCUk8 + EgRJPBICSTwSAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABJPBIDSTwSCEk8EhFJPBIdSTwSL4JwVJ+fjnj/39vN/+zq4v/08u7/8/Lt//Py + 7P/z8ez/8vHr//Lw6//x7+r/8e/p//Hu6P/w7uf/8O3m//Dt5f/v7OX/7uvj/+3q4v/t6eH/7Ojg/+vn + 3//r593/6uXc/+jk2v/o49j/5+HX/+bg1f/l39T/5N7S/+Td0f/NwbL/w7Oj/8Ozov/CsqL/wrKh/8Kx + oP/BsaD/wbCe/8Gvnv/Arp3/v66b/76smv++q5n/vaqY/7yql/+7qJb/t6SR/7ejjv+zn4r/sp6J/7Gb + hv+vm4X/sJqE/7CahP+wmoX/sp2H/7Oeif+2oIr/t6GM/7iijP+6o43/uaKM/7mii/+4oYv/uKGK/7eg + if+3n4j/tp+I/7aeh/+1nYb/tZ2G/7Schf+0nIT/s5uD/7Oag/+ymoL/spmB/7GYgP+xmID/sJd//7CW + fv+vln3/r5V9/66UfP+ulHv/rZN6/62Tev+sknn/q5F4/6uRd/+njXT/oIhv/5iCav+RfWX/kX1l/4l2 + XLFcTSg7STwSJUk8EhxJPBIUSTwSDUk8EghJPBIESTwSAkk8EgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEk8EgNJPBIHSTwSD0k8 + EhpJPBIrfGpNhJF9Zf/f283/5+TZ//Tz7v/08+7/9PLt//Py7f/z8ez/8vHr//Lw6//y7+r/8e/p//Hv + 6P/w7uf/8O3m/+/s5f/u6+T/7erj/+zp4f/r6OD/6ufe/+nl3P/o49r/5+LY/+bg1v/l39T/5N3T/+Pc + 0f/i28//4drO/9/Xy//JvK3/wrKi/8Kyov/CsqL/wrKh/8Kyof/CsaD/wbCg/7yplv+6p5T/tqKO/7Wg + i/+ynIf/r5qD/66Ygf+umIL/r5iC/7Gbhf+znYf/tqCK/7ehjP+6pY//vKaQ/72nkf+9ppH/vKaQ/7yl + j/+7pI7/u6SO/7qjjf+6o4z/uaKL/7mhi/+4oYr/t6CJ/7efiP+2n4j/tp6H/7Wehv+1nYb/tJyF/7Sc + hP+zm4P/s5qD/7Kagv+ymYH/sZmA/7GYgP+wl3//sJZ+/6+Wfv+vlX3/rpV8/66Ue/+tk3v/po10/6CI + cP+bhGz/lH9n/5F9Zf+RfWX/j3tj5Ih1WqNpWTdGSTwSJUk8Eh5JPBIYSTwSEUk8EgxJPBIHSTwSBEk8 + EgJJPBIBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAASTwSAkk8EgVJPBIMSTwSFkk8EiV0Y0RokX1l/9rVxv/g3M//8/Lt//Tz + 7//08+7/9PLt//Py7f/z8ez/8vHr//Lw6v/y8Or/8e/p//Hu6P/w7ef/8O3m/+7s5P/t6uP/7Onh/+vn + 3//p5dz/5+Pa/+bh1//k39X/493T/+Hc0f/g2s//39jN/97Xy//d1sr/3dXJ/9jQwf/OwrP/uaiV/7Kf + i/+tmIL/r5qE/6uUfP+rlH7/rJV+/62Xf/+vmoP/s52G/7ehi/+4oo3/u6aR/7ynkv/BrJf/wKuW/8Cq + lf+/qpT/v6mU/76ok/++qJL/vaeR/72mkf+8ppD/vKWP/7ukjv+7pI7/uqON/7qjjP+5oov/uaGL/7ih + iv+3oIn/t5+I/7afiP+2nof/tZ6G/7Wdhv+0nIX/tJyE/7Obg/+zmoP/spqC/7KZgf+xmYD/sZiA/7CX + f/+ulXz/p493/6CJcf+chm3/loFp/5F9Zf+RfWX/kX1l/5F9Zf+NeWDJhnNYlnJhQVNJPBInSTwSIUk8 + EhxJPBIXSTwSEkk8Eg1JPBIJSTwSBkk8EgNJPBICSTwSAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJPBIBSTwSBEk8 + EglJPBISSTwSHltNJzyRfWX/y8Oz/9/bzf/o5dz/9fTv//Tz7//08+7/9PLu//Py7f/z8ez/8/Hr//Lw + 6//y8Or/8e/p//Hu6P/w7ef/7+zl/+3q4//r6OD/6ebd/+fj2v/l4Nj/4dzR/9nTx//Y0cT/z8a3/83E + tP/Gu6n/xbqo/7+zn//BtKD/wbSg/8G0oP/EtqL/wrGd/7uok/+6ppD/vKeS/72olP+/q5b/xK+b/8Sv + m//Dr5r/w66a/8Ktmf/CrZj/wayX/8Gsl//Aq5b/wKqV/7+qlP+/qZT/vqiT/76okv+9p5H/vaaR/7ym + kP+8pY//u6SO/7ukjv+6o43/uqOM/7mii/+5oYv/uKGK/7egif+3n4j/tp+I/7aeh/+1nob/tZ2G/7Sc + hf+0nIT/s5uD/7CZgf+qknr/o411/5+Jcf+Zg2v/k35m/5F9Zf+RfWX/kX1l/5F9Zf+NeWDJinddr4Rx + VodyYUJSSTwSJ0k8EiNJPBIfSTwSG0k8EhdJPBIUSTwSEEk8Eg1JPBIJSTwSBkk8EgRJPBICSTwSAQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJPBIDSTwSB0k8Eg5JPBIYSTwSJo56YdezppL/39vN/9/b + zf/q597/9fTv//Xz7//08+7/9PLu//Py7f/z8ez/8/Hr//Lw6//w7uj/7Ong/+vo3//k4NT/4dzR/9vV + yP/Uzb7/zcS0/8W8qf/Bt6T/u66b/7iql/+zpJD/saCM/62ciP+rmIP/qJWA/6iTf/+qloH/rpmF/7Ke + if+3oo7/u6eT/7+rl//BrZn/w6+b/8Ovm//Er5v/xK+b/8Svm//Drpr/wq6Z/8KtmP/BrJj/wayX/8Cr + lv/AqpX/v6qV/7+plP++qZP/vqiS/72nkv+9ppH/vKaQ/7ylj/+7pY//u6SO/7qjjf+6o4z/uaKM/7mh + i/+4oYr/t6CJ/7egif+2n4j/s5yF/6yVfv+lj3f/oIpz/5mEbP+Tfmb/kX1l/5F9Zf+RfWX/kX1l/497 + Y+SNemHIhnNYlYFvU3l0YkNQSTwSJkk8EiNJPBIgSTwSHUk8EhpJPBIXSTwSFEk8EhJJPBIPSTwSDEk8 + EgpJPBIISTwSBkk8EgRJPBIDSTwSAkk8EgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEk8 + EgJJPBIFSTwSCkk8EhJJPBIegW9TeZF9Zf/Qybn/39vN/9/bzf/h3tH/5eLX/+rn3v/k4dX/5OHV/+Tg + 1P/g287/39rL/97Zyv/a0cL/2M/A/9TKuf/OwbH/yLqp/8Cwnf+6qZb/sZ6K/6yZhP+olID/pZF9/6OP + ev+ijXj/oIx3/5+Ldf+gi3b/oox4/6WQe/+plH//rpmF/7Sfi/+4pJD/vamV/8CsmP/Drpv/w6+b/8Sv + m//Er5v/xK+b/8Oumv/Crpn/wq2Y/8GsmP/BrJf/wKuW/8Cqlf+/qpX/v6mU/76pk/++qJL/vaeS/72m + kf+8ppD/vKWP/7ulj/+7pI7/uqON/7qjjP+xm4T/rJZ//6SPd/+finL/moVu/5F9Zf+RfWX/kX1l/5F9 + Zf+RfWX/j3tj5I16YciGc1iVgW5SenlnSV9JPBIoSTwSJEk8EiFJPBIeSTwSG0k8EhhJPBIWSTwSFEk8 + EhJJPBIQSTwSDkk8EgxJPBIKSTwSCEk8EgdJPBIGSTwSBEk8EgNJPBICSTwSAUk8EgEAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEk8EgNJPBIHSTwSDUk8EhVJPBIhinddrpWC + a/+8sJ7/3dbH/93Vx//c1MX/2tDB/9rPwP/Yy7v/1sm5/9bHtv/SwbD/0sCv/9C/rv/OvKv/y7mn/8a0 + ov/ArZv/uaeT/7OfjP+smYT/p5N+/6KOef+mkn//qZWB/6SPe/+mkHr/oIlx/5yEa/+dhW7/n4hx/6WQ + e/+qloH/sZyI/7ajjv+8qJP/v6uY/8Kumv/Dr5v/xK+b/8Swm//Er5v/w66a/8Kumf/CrZn/wayY/8Gs + l//Aq5b/wKuW/7+qlf+/qZT/vqmT/76ok/+9p5L/t6GL/7Gbhf+pk33/o453/5uGb/+WgWr/kX1l/5F9 + Zf+RfWX/kX1l/5F9Zf+OemLWjHhfu4ZzWZSBb1N5emhKXUk8EiZJPBIjSTwSIEk8Eh5JPBIcSTwSGkk8 + EhdJPBIVSTwSE0k8EhFJPBIPSTwSDUk8EgtJPBIKSTwSCEk8EgdJPBIGSTwSBUk8EgRJPBIDSTwSA0k8 + EgJJPBIBSTwSAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAASTwSAkk8EgRJPBIISTwSDkk8EhZJPBIhiXZcn5F9Zf+mlH7/0sGx/9bGtf/WxbX/1cS0/9XE + s//Uw7L/1MOy/9LBsP/SwK//0L+u/868q//KuKb/xbOh/7+smf+4pJH/v6+g/9nQxv/d1c3/4trR/9TI + vP/Ht6f/u6eU/6+Ygv+li3H/nIBk/5p9YP+afWD/mn5h/6qVgP+wnIj/tqKO/7ynk/+/q5f/wq2a/8Ov + m//EsJz/xLCb/8Svm//Drpr/wq6Z/8Ktmf/BrJj/wayX/72ok/+0n4n/rpmD/6iTfP+ciHD/mYVt/5F9 + Zf+RfWX/kX1l/5F9Zf+RfWX/kHxk8Y16YciIdVuihnNZlHlnSV90YkNPSTwSJUk8EiJJPBIgSTwSHUk8 + EhtJPBIYSTwSFkk8EhRJPBISSTwSEUk8Eg9JPBIOSTwSDEk8EgpJPBIJSTwSCEk8EgdJPBIGSTwSBUk8 + EgRJPBIDSTwSA0k8EgJJPBIBSTwSAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASTwSAkk8EgVJPBIJSTwSDkk8 + EhVJPBIeemhKXY97Y+OVgWr/xbOh/9bFtf/VxLT/1cSz/9TDsv/Uw7L/0sGw/9LAr//Qv63/zryr/8q4 + pv/Fs6H/vqyZ/+DY0P///////f38//Ht6f/i2tL/1cm9/8i4qP+7qJX/sJmC/6WMcv+dgGT/mn1g/5p9 + YP+afWD/q5aC/7Gdif+3o4//vaiU/8CrmP/Crpr/w6+b/8SwnP/BrJj/t6KN/7Cchv+qlX//oIx1/52J + cf+RfWX/kX1l/5F9Zf+RfWX/kX1l/5F9Zf+NemHIjHhfu4ZzWZR+bE9remhKXUk8EiZJPBIjSTwSIEk8 + Eh5JPBIcSTwSGkk8EhhJPBIWSTwSFEk8EhJJPBIQSTwSDkk8Eg1JPBILSTwSCkk8EglJPBIISTwSB0k8 + EgZJPBIFSTwSBUk8EgNJPBIDSTwSAkk8EgJJPBIBSTwSAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAASTwSAkk8EgVJPBIISTwSDEk8EhNJPBIbX1AsMox4X7uRfWX/r5yI/9HA + r//VxLP/1MOz/9TDsv/SwbD/0sCv/9C/rv/OvKv/yrmn/8a0of/ArZr/7unk///////9/f3/8e7q/+Pb + 1P/Wyr7/yLmp/7yplv+wmoP/poxz/52BZf+afWD/mn1g/5p9YP+umob/rJiE/6qWgf+lkHv/pZF7/56K + c/+ciHH/kHxk/5F9Zf+RfWX/kX1l/5F9Zf+RfWX/jXphyIx4X7uGc1mUgW9TeHpoSl1fUCszSTwSI0k8 + EiBJPBIeSTwSHEk8EhpJPBIYSTwSFkk8EhRJPBISSTwSEUk8Eg9JPBIOSTwSDUk8EgtJPBIKSTwSCEk8 + EgdJPBIHSTwSBkk8EgVJPBIESTwSA0k8EgNJPBICSTwSAkk8EgFJPBIBSTwSAQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASTwSAkk8 + EgRJPBIHSTwSC0k8EhBJPBIXSTwSH39sUGqQfGTxnYpz/8i2pf/Uw7P/1MOy/9PCsf/SwbD/0L+u/8+9 + q//Luqj/x7Wj/8Kvnf/v6uX///////7+/f/y7+v/5NzV/9bLv//Juqr/vaqX/7GbhP+mjXT/nYFl/5p9 + YP+afWD/mn1g/4FtVv97Z1H/gW1W/4ZyW/+Kdl//jXli/4x4X8mMeF+7hnNZlIFvU3h6aEpdX1ArM0k8 + EiNJPBIgSTwSHkk8EhxJPBIaSTwSGEk8EhZJPBIUSTwSEkk8EhFJPBIPSTwSDkk8Eg1JPBILSTwSCkk8 + EglJPBIISTwSB0k8EgZJPBIFSTwSBUk8EgRJPBIDSTwSA0k8EgJJPBIBSTwSAUk8EgEAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASTwSAUk8EgNJPBIFSTwSCUk8Eg1JPBITSTwSG25d + PD2NemHHkX1l/6qXgv/HtaP/08Kx/9LBsP/Rv67/z76s/8y7qf/Jt6X/xbOg//Dr5v///////v7+//Pw + 7P/l3db/08e7/8Szov+5pZH/rJR8/6KIbv+cf2P/mn1g/5p9YP+afWD/hXFa/3NgR6ZzYEaJcV9Ca11N + Kz5LPhYqSjwUJEk8Eh9JPBIcSTwSGkk8EhhJPBIWSTwSFEk8EhJJPBIRSTwSD0k8Eg5JPBINSTwSC0k8 + EgpJPBIJSTwSCEk8EgdJPBIGSTwSBUk8EgVJPBIESTwSA0k8EgNJPBIDSTwSAkk8EgFJPBIBSTwSAQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAASTwSAUk8EgJJPBIESTwSB0k8EgtJPBIQSTwSFUk8EhyJdVuPkHxk8JF9Zf+VgWn/oY53/6CN + dv+vnIf/nIlz/5mGcP+MeWL/4dzX//f28//m39j/18vA/8W1pf++q5n/tqKN/6+Ygf+njnX/oIVq/5t+ + Yv+afWD/mn1g/5p9YP+HdFzyVkQjPFVEIjFTQx8nUEEcH00/GBlLPRQVSTwSEUk8Eg9JPBIOSTwSDUk8 + EgtJPBIKSTwSCUk8EghJPBIHSTwSBkk8EgVJPBIFSTwSBEk8EgNJPBIDSTwSA0k8EgJJPBIBSTwSAUk8 + EgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEk8EgJJPBIDSTwSBUk8 + EghJPBIMSTwSEEk8EhVJPBIbgW9TZYp3XZ2OemHGj3ti4497Y/+NeWH/iHRbyol2XuXSyL7/4NfO/9vQ + xv/Ux7v/zL2u/8Oyof+7p5T/spyG/6qSev+jiG7/nIBk/5p9YP+XfF//kHlg/4ZyWqBZRyYlWEYkHVVE + IRdSQx4ST0AaDks9FQpJPBIISTwSB0k8EgZJPBIFSTwSBUk8EgRJPBIDSTwSA0k8EgNJPBICSTwSAUk8 + EgFJPBIBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEg7EgFIOxICSDsSBEg7EgZIOxIJSDsSDEg7Eg9IOxITSDsSF0g7 + EhpJPBMdSjwUIEw+FiNOPxknfmtQa5+Oef/AtKb/zcG1/8a5q/+/sKD/uKeV/7Geiv+rloD/nohx/5iB + aP+QemH/jHhg8Il1XaiDb1ZiXUoqGVtJKBVaSCcPV0YkC1REIQhRQR0GTD4WA0g7EgNIOxIDSDsSAkg7 + EgFIOxIBSDsSAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABGOhEBRjoRAkY6EQRGOhEFRjoRB0Y6EQpGOhEMRjoRDkc7EhBJPBQSSz0WFE0/GRZQQR0ZfGlORYl1 + XIuLd1+njHhgxIx4YMSMeGDEjHhgw4l1XImJdV2JhXJYXYBtUz9eSisTX0ssEV9LLA5eSysMXEopCltJ + KAdaSCgEVkYkA1FCHQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARDgQAUQ4EAJEOBADRDgQBEQ4 + EAVEOBAGRDgQB0Y6EwhJPBcJTD4aCk9AHQxRQiAOVEMiDldFJQ9YRicPWUcoD1pIKQ5cSSoNXEgqDFtI + KgxbSSoKXEosCF1KLAhgTC8HYU0vBWBMLgReSy0DW0kqAldGJgFRQh8BAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/NA8BPzQPAT80DwI/NA8DPzQPA0Q3FANHOhgESTwaBE0+ + HQVPQCAGUkIjBlZEJgVWRScFWUcrBVtILARaSCwEWkgrBFlHKwNYRioDWEcqA19LMAFjTjMBY04zAWNO + MwEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABDNxcBSTscAUs8HwFMPSEBTD0hAUw9IQFVRCoBW0gwAVtI + MAFbSDABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAP////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////z///////////////////8AB//////////////////gAAP//////////////// + 8AAAA////////////////gAAAAH//////////////8AAAAAA//////////////wAAAAAAH////////// + //+AAAAAAAA////////////wAAAAAAAAH//////////+AAAAAAAAAA//////////wAAAAAAAAAAH//// + ////+AAAAAAAAAAAA////////4AAAAAAAAAAAAH///////AAAAAAAAAAAAAB//////4AAAAAAAAAAAAA + AP/////AAAAAAAAAAAAAAAB////4AAAAAAAAAAAAAAAAf///AAAAAAAAAAAAAAAAAH//8AAAAAAAAAAA + AAAAAAA//wAAAAAAAAAAAAAAAAAAP/wAAAAAAAAAAAAAAAAAAD/4AAAAAAAAAAAAAAAAAAA/4AAAAAAA + AAAAAAAAAAAAP+AAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAH4AA + AAAAAAAAAAAAAAAAAB+AAAAAAAAAAAAAAAAAAAAfgAAAAAAAAAAAAAAAAAAAHwAAAAAAAAAAAAAAAAAA + AB4AAAAAAAAAAAAAAAAAAAAeAAAAAAAAAAAAAAAAAAAAHgAAAAAAAAAAAAAAAAAAAB4AAAAAAAAAAAAA + AAAAAAAeAAAAAAAAAAAAAAAAAAAAHwAAAAAAAAAAAAAAAAAAAB+AAAAAAAAAAAAAAAAAAAAfgAAAAAAA + AAAAAAAAAAAAH4AAAAAAAAAAAAAAAAAAAB+AAAAAAAAAAAAAAAAAAAAfgAAAAAAAAAAAAAAAAAAAH4AA + AAAAAAAAAAAAAAAAAB+AAAAAAAAAAAAAAAAAAAAfgAAAAAAAAAAAAAAAAAAAH8AAAAAAAAAAAAAAAAAA + AB/AAAAAAAAAAAAAAAAAAAAfwAAAAAAAAAAAAAAAAAAAH8AAAAAAAAAAAAAAAAAAAB/AAAAAAAAAAAAA + AAAAAAAfwAAAAAAAAAAAAAAAAAAAD8AAAAAAAAAAAAAAAAAAAA/AAAAAAAAAAAAAAAAAAAAP4AAAAAAA + AAAAAAAAAAAAD+AAAAAAAAAAAAAAAAAAAA/gAAAAAAAAAAAAAAAAAAAP4AAAAAAAAAAAAAAAAAAAD+AA + AAAAAAAAAAAAAAAAAA/gAAAAAAAAAAAAAAAAAAAP4AAAAAAAAAAAAAAAAAAAD+AAAAAAAAAAAAAAAAAA + AA/wAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAA + AAAAAAAP8AAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAP+AAAAAAA + AAAAAAAAAAAAD/gAAAAAAAAAAAAAAAAAAA/4AAAAAAAAAAAAAAAAAAAP+AAAAAAAAAAAAAAAAAAAD/gA + AAAAAAAAAAAAAAAAAA/4AAAAAAAAAAAAAAAAAAAP+AAAAAAAAAAAAAAAAAAAB/gAAAAAAAAAAAAAAAAA + AAf8AAAAAAAAAAAAAAAAAAAH/AAAAAAAAAAAAAAAAAAAB/wAAAAAAAAAAAAAAAAAAAf8AAAAAAAAAAAA + AAAAAAAH/AAAAAAAAAAAAAAAAAAAB/wAAAAAAAAAAAAAAAAAAAf8AAAAAAAAAAAAAAAAAAAP/AAAAAAA + AAAAAAAAAAAAD/4AAAAAAAAAAAAAAAAAAA/+AAAAAAAAAAAAAAAAAAAP/gAAAAAAAAAAAAAAAAAAH/4A + AAAAAAAAAAAAAAAAAB/+AAAAAAAAAAAAAAAAAAA//gAAAAAAAAAAAAAAAAAAP/4AAAAAAAAAAAAAAAAA + AH/+AAAAAAAAAAAAAAAAAAB//wAAAAAAAAAAAAAAAAAA//8AAAAAAAAAAAAAAAAAAf//AAAAAAAAAAAA + AAAAAAP//wAAAAAAAAAAAAAAAAAH//8AAAAAAAAAAAAAAAAAH///gAAAAAAAAAAAAAAAAD///4AAAAAA + AAAAAAAAAAD////AAAAAAAAAAAAAAAAH////wAAAAAAAAAAAAAAA/////+AAAAAAAAAAAAAAH//////w + AAAAAAAAAAAAA///////+AAAAAAAAAAAAf////////wAAAAAAAAAAH/////////+AAAAAAAAAD////// + /////4AAAAAAAB/////////////AAAAAAA//////////////8AAAAAf///////////////wAAAAP//// + ////////////gAAAf/////////////////8AP/////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ////////////////////////KAAAAGAAAADAAAAAAQAgAAAAAACAlAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADww + DwE/NQ8BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAQzcQAUM3EAFDNxABQzcQAUI2EAJCNxACQzcQAUM3EAFCNxABAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABGOhIBRjoSAkY6EgNHOxIDRjoSBUY6EgZGOhIIRjoSCUY6EglGOhIJRjoSCEY6 + EgdGOhIERjsSAkg7EgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAASTwSAUk8EgFJPBIBSTwSAUk8EgJJPBIDSTwSBEk8EgRJPBIGSTwSCEk8EgpJPBIMSTwSD0k8 + EhFJPBIVSTwSF0k8EhhJPBIXSTwSFUk8EhBJPBILSTwSB0k8EgRJPBIBAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABJPBIBSTwSAUk8EgFJPBIBSTwSA0k8EgNJPBIFSTwSBkk8EghJPBIJSTwSDEk8 + Eg5JPBIRSTwSFUk8EhhJPBIbSTwSIEk8EiVJPBIqSTwSLkk8Ei9JPBItSTwSKUk8EiFJPBIaSTwSEUk8 + EgpJPBIESTwSAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJPBIBSTwSAkk8EgNJPBIDSTwSBUk8EgZJPBIISTwSCkk8 + EgxJPBIPSTwSEkk8EhRJPBIYSTwSHEk8EiBJPBIkSTwSKUk8Ei9JPBI0STwSOUk8EkFJPBJHSTwSS0k8 + Ek1JPBJKSTwSREk8EjpJPBIuSTwSH0k8EhRJPBILSTwSBUk8EgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEk8EgFJPBIBSTwSAUk8EgFJPBICSTwSA0k8EgRJPBIFSTwSCEk8 + EglJPBILSTwSDkk8EhFJPBIVSTwSF0k8EhtJPBIgSTwSJUk8EilJPBIuSTwSNEk8EjpJPBI/STwSRkk8 + Ek1JPBJUSTwSWkg7EWBHOhBlRTgOZ0U4DWhFOQ5nSDsRYkk8EldJPBJHSTwSNEk8EiNJPBIVSTwSDEk8 + EgVJPBIBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASTwSAUk8EgFJPBIBSTwSAUk8EgNJPBIESTwSBUk8 + EgdJPBIISTwSC0k8Eg1JPBIQSTwSE0k8EhdJPBIcSTwSHkk8EiVJPBIpSTwSLkk8EjRJPBI6STwSQEk8 + EkZJPBJNSTwSU0k8ElpJPBJhSTwSZ0Y5DmxENwtsQTUKcUY5D3xNQBeJVUYemVdJIZ5TRRyTRTkOe0Y5 + Dm9JPBJiSTwSTEk8EjdJPBIlSTwSFkk8EgxJPBIFSTwSAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJPBIBSTwSAkk8EgJJPBIDSTwSBEk8 + EgVJPBIHSTwSCEk8EgpJPBIMSTwSD0k8EhJJPBIWSTwSGkk8Eh5JPBIjSTwSKEk8Ei5JPBI0STwSOUk8 + EkBJPBJHSTwSTEk8ElNJPBJaSTwSYEk8EmdJPBJuRjoPcUQ3DHRDNwp4RDcNf1NGHpNgUC2raVg3wXZk + RdSAblLkinZf+pB7Zf+GdFvzcmFBzlBDGpJGOQ53STwSZ0k8Ek5JPBI5STwSJUk8EhZJPBIMSTwSBUk8 + EgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJPBIBSTwSAUk8EgFJPBICSTwSA0k8 + EgRJPBIESTwSB0k8EghJPBIKSTwSDEk8Eg9JPBISSTwSFkk8EhhJPBIcSTwSIUk8EiVJPBIrSTwSMUk8 + EjhJPBI/STwSRUk8EkxJPBJUSTwSWkk8EmFIOxBmRjkOa0U4DW9FOQ12RzoQfUg7EIVHORCKV0gjn2xc + O8B0Y0bXfmxR6ol2XfORfWX+l4Js/6aQef+ymn//waeM/86xlP/DqYz/o412/4JwVupTRByaQzcMeUk8 + EmdJPBJPSTwSOEk8EiRJPBIVSTwSCkk8EgRJPBIBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEk8EgFJPBIBSTwSAUk8 + EgFJPBIDSTwSBkk8EgZJPBIISTwSCkk8EgxJPBIOSTwSEkk8EhZJPBIZSTwSHEk8EiFJPBImSTwSK0k8 + EjBJPBI1STwSO0k8EkJJPBJISTwST0k8EldJPBJeSTwSZkg7EGxEOA1vQjUKckI2CXdKPRSFUEIaklRG + H6BhUS2ydGNEzn1qUOSHdFv6lH9n/5qFbf+gjHT/rZZ9/72liv/LsJT/2Lue/9u+oP/cvZ//3b+g/92/ + oP/cvp//272d/7Oagf+CcFbrU0Qcm0M3DHlJPBJnSTwSTkk8EjVJPBIiSTwSEkk8EglJPBIEAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASTwSAUk8 + EgJJPBIDSTwSA0k8EgRJPBIGSTwSCEk8EglJPBIMSTwSD0k8EhJJPBIVSTwSGUk8Eh1JPBIhSTwSJUk8 + EitJPBIwSTwSNUk8EjxJPBJCSTwSSEk8Ek5JPBJVSTwSW0k8EmJJPBFpRzoQbUY5DXNENwx4QTYKfE0/ + FopbTSijY1Qxtm1cPcx7aUzdhHFX7o56Y/+ZhW//oY11/6+Zf/+7pIr/xK2R/8+1mf/cwaT/38Wn/97B + pP/cwaL/2r6g/9m9n//ZvJ7/2byd/9m8nf/Yu5z/3L6f/9S1mP+eh2//hHJY7FRFHpxGOQ55STwSZEk8 + EkpJPBIySTwSHkk8Eg9JPBIHSTwSAkk8EgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJPBIBSTwSAUk8 + EgFJPBIBSTwSAkk8EgNJPBIESTwSBkk8EgdJPBIJSTwSC0k8Eg1JPBIQSTwSFEk8EhdJPBIbSTwSIEk8 + EiVJPBIqSTwSMEk8EjZJPBI7STwSQUk8EkhJPBJPSTwSVUk8ElxIOxFiRzoQZkU4DmtFOA1xRToOd0g7 + EYBHOxGHUUMalWFSLq1vXz/JemdK4oRxV++OemH6k39o/5+Jc/+sl3//vKaM/8qymP/PuJz/1byg/97F + qf/ix6v/3sWn/9zCpv/awKP/2b6h/9m+of/ZvqD/2b2f/9m9n//ZvZ7/2byd/9m8nf/Yu5z/2ryd/9W2 + mP+tkHX/mYRs/4FuU+RLPhSPRTkOdUk8El9JPBJDSTwSKkk8EhdJPBIKSTwSBEk8EgEAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEk8 + EgFJPBIBSTwSAUk8EgFJPBIDSTwSBEk8EgVJPBIGSTwSCUk8EgpJPBINSTwSD0k8EhJJPBIXSTwSGkk8 + Eh5JPBIjSTwSKEk8Ei9JPBI0STwSOkk8EkJJPBJHSTwSTkk8ElVJPBJcSTwSYkk8EmlFOA5rRDcLb0E1 + CXJFOA56TkAYilNHHplYSiSoZ1c2u3hnSdiCb1byj3pi/5aCav+eiXL/p5F7/7Sgh//Er5b/0byi/9vD + qf/cxar/3sWp/97Gq//exqn/3MOn/9vCpv/awKT/2cCj/9nAo//Zv6L/2b+i/9m+of/ZvqH/2b2f/9m9 + n//ZvZ7/2byd/9m8nf/Yu53/2byd/9S2mP+wk3j/o4hu/5qGbv98a03dTD8VikY5D25JPBJUSTwSN0k8 + Eh9JPBIQSTwSBkk8EgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAEk8EgFJPBIDSTwSAkk8EgRJPBIFSTwSCEk8EghJPBILSTwSDUk8EhBJPBISSTwSFkk8 + EhpJPBIeSTwSIkk8EidJPBIsSTwSMUk8EjdJPBI+STwSRUk8EkxJPBJUSTwSWkk8EmJJPBJpSDwRb0Y5 + D3NEOA12QzYKeUQ5DYFWSCKYYFAtrGZWNL9zYkHSgW5T5ol2XfqTfWf/nopz/6mVfv+zn4f/wKuT/8u2 + nf/Wwaf/4Muw/+DKsP/dx63/3Maq/9vDqf/aw6n/2sOo/9rCp//awqf/2sGm/9rBpf/awaX/2cCk/9nA + o//Zv6P/2b+i/9m+of/ZvqH/2b2g/9m9n//ZvZ//2bye/9m8nf/ZvJ3/2byd/9W4mf+wlHn/pIlv/6WK + bv+bg23/fGpO3EY7EHxJPBJiSTwSREk8EilJPBIVSTwSCUk8EgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAASTwSAUk8EgJJPBICSTwSBUk8EgZJPBIJSTwSC0k8Eg1JPBIQSTwSE0k8 + EhZJPBIZSTwSHkk8EiJJPBInSTwSK0k8EjFJPBI3STwSPEk8EkNJPBJKSTwSUEk8EldJPBJdSDsQZEY5 + DmlFOA1wRTkNdUY5D35IOxGGSDsSjVpLJKJoVzW8cmFD039sUOyKdl31j3xk/5iEbv+olH3/sp+I/8Gu + l//Ou6T/1MGp/9vHr//hzbX/4s21/9/Ksf/dyK7/28Ws/9rFq//axav/2sSq/9rEqf/aw6n/2sOo/9rC + p//awqf/2sGm/9rBpf/awaX/2cCk/9nAo//Zv6P/2b+i/9m+of/ZvqH/2b6g/9m9n//ZvZ//2bye/9m8 + nf/ZvJ3/2byd/9W4mf+wlXn/o4dt/6aKb/+jh23/moRt/29fP8BENwxmSTwSTkk8EjBJPBIaSTwSC0k8 + EgMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJPBICSTwSBEk8EgdJPBIKSTwSDUk8 + EhJJPBIVSTwSGkk8Eh1JPBIiSTwSJ0k8EixJPBIxSTwSNkk8Ej1JPBJDSTwSSUk8ElBJPBJXSTwSXUk8 + EmRIOxFqRTgNa0I1Cm9DNgx2Sj0Tg1BEG5JVRyCiX1Arsm5dP8p8ak7kiXRc/pF+Zf+bh3D/o494/66b + hf+6qJH/zLqj/9rIsf/cy7T/3sy1/97Ntf/fzbb/3suz/9zJsP/bx6//28eu/9vGrf/bxq3/28Ws/9rF + q//axav/2sSq/9rEqf/aw6n/2sOo/9rCp//awqf/2sGm/9rBpf/awaX/2cCk/9nAo//ZwKP/2b+i/9m/ + ov/ZvqH/2b6g/9m9n//ZvZ//2bye/9m8nf/ZvJ3/2byd/9W4mf+vlXj/o4dt/6WKb/+liW7/o4hv/5B9 + ZfpYSSOGRDcNUEk8EjZJPBIdSTwSDEk8EgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARjoRAUg7 + EgNJPBIHSTwSC0k8EhFJPBIYSTwSHkk8EiVJPBIrSTwSMUk8EjdJPBI9STwSQ0k8EkpJPBJQSTwSVkk8 + El1JPBJjSTwSakg7EHBGOQ5zRDcMdkI2CntLPhSHW0wnoGNUMbVuXDzKemhL3IVyV++OeWH/mYVu/6WS + fP+unYb/uKeQ/8S0nf/Tw63/4NC6/+LTvf/h0Lr/3863/93LtP/byrP/28my/9vJsf/bybH/28iw/9vI + r//bx6//28eu/9vGrv/bxqz/28Ws/9rFq//axav/2sSq/9rEqf/aw6n/2sOo/9rDqP/awqf/2sKm/9rB + pv/awaX/2sCk/9nApP/ZwKP/2b+i/9m/ov/ZvqH/2b6g/9m9oP/ZvZ//2bye/9m8nv/ZvJ3/2byd/9e6 + m/+0mHz/o4Zu/6WKb/+liW7/pIhu/52Gb/9vXj63RDcMUEk8EjlJPBIfSTwSDUk8EgQAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAARjoRAkg7EgdJPBIOSTwSF0k8EiJJPBItSTwSN0k8EkBJPBJISTwST0k8 + EldJPBJeSDsRY0c6EGhFOQ5tRTgNckY6D3lIOhGBSDsQh0w/FpJiUi6tcF8/ynpnSuKDcFbujXph+ZJ+ + Z/+einP/rpyI/7qolP/JuaT/0sSu/9nKtf/f0bz/5NXA/+HUvv/f0bv/3c23/9zMtf/cy7X/3Mu0/9zK + s//byrP/28my/9vJsv/bybH/28iw/9vIsP/bx6//28eu/9vHr//dyK//38mw/+DKsf/fyrD/3siv/97I + rf/bxar/2sOo/9rDqP/awqf/2sKm/9rBpv/awaX/2sCk/9nApP/ZwKP/2b+i/9m/ov/ZvqH/2b6g/9m+ + oP/ZvZ//2b2e/9m8nv/ZvJ3/2byd/9m8nf+5nID/oodt/6WKb/+liW//pYlt/6OJb/9+bVDQSj4VW0c7 + EDxJPBIjSTwSEEk8EgZGOhIBAAAAAAAAAAAAAAAAAAAAAAAAAABBNg8BRjoRBEg7Eg1JPBIYSTwSJ0k8 + EjdJPBJHSTwSVkk8EmBJPBFoRjkObkQ3C3FBNQl0RjkPfU1BF4xSRR2ZV0gip2xbO8F4ZUnZgWxS7416 + Yf+Wg2v/nIpz/6iUfv+1pI//xbai/9XJtf/f0r7/39K+/+DTwP/h08H/4NO+/97Qu//dz7r/3M24/9zN + t//czbf/3My2/9zMtv/cy7X/3Mu0/9zKtP/cyrP/28my/9vJsv/bybH/28iw/9vIsP/bx6//38uy/+DM + tf/Wwqj/0Luh/8q0mv/Js5n/zbac/9K8ov/ex6z/4cqv/9vEqf/awqf/2sKm/9rBpv/awaX/2sCk/9nA + pP/ZwKP/2b+j/9m/ov/Zv6L/2b6h/9m+oP/ZvZ//2b2e/9m8nv/ZvJ3/2bye/9m8nf+4nID/oodt/6WK + b/+liW//pYlt/6KHbf+Jd13lUkQbakY5Dj1JPBIlSTwSEkk8EgdGOhICAAAAAAAAAAAAAAAAAAAAAAAA + AABBNg8DRjoRCUg7EhRJPBIlSTwSOkk8Ek5GOQ9fRDgNbUM2CnZFOQ6BUkQdlF9QLKxnVzXCdWNE1IBt + UeWHclj1lH5o/56Kdf+pmIP/taWQ/8K0oP/Mwa3/2My6/+Xayf/j2MX/4NXD/9/TwP/d0r7/3dC8/93Q + vP/dz7v/3M+6/9zOuv/czrn/3M24/9zNuP/czbf/3My2/9zMtv/cy7X/3Mu0/9zLtP/cyrP/28qy/9vJ + sv/bybH/28iw/9zKsv/gz7b/0Lui/62Zf/+Ygmf/jHRY/31lSf99ZUj/hW5R/5J6X/+nkHT/waqP/93G + q//dxar/2sKm/9rCpv/awab/2sGl/9rApP/ZwKT/2b+j/9m/ov/Zv6L/2b6h/9m+oP/ZvaD/2b2f/9m8 + nv/ZvJ7/2r2d/9m8nf+4nID/oodt/6WKcP+liW//pYlu/6KHbf+Idl3mUUMbb0Y5DkJJPBIqSTwSFEk8 + EgdGOhICAAAAAAAAAAAAAAAAAAAAAAAAAABCNg8FRjoRDkg7EhxJPBIzRjkORUg7EGNZSiOOalk4t3Vj + RNZ+a0/qiHRb85F8ZP6XhG7/pZF8/7SkkP/Et6X/0Maz/9bLuf/d08L/5NzK/+Tcyv/h2Mb/39bD/93S + wP/d0r//3dG+/93Rvv/d0b3/3dC8/93QvP/dz7v/3M+6/9zPuv/czrn/3M24/9zNuP/czbf/3My2/9zM + tv/czLX/3Mu0/9zLtP/cyrP/28qz/9vJsv/bybL/3821/9zJsf+ynYP/i3NY/39mSv+Da1D/lIFq/6qa + if+tn43/nYt2/4pzWf9+Zkr/gmpO/6CJbv/PuJ3/4Mit/9rDpv/awab/2sGl/9rApP/ZwKT/2b+j/9m/ + ov/Zv6L/2b6h/9m+oP/ZvqD/2b2f/9m9nv/ZvJ7/2r2d/9m8nf+3m3//oodt/6WKcP+liW//pYlu/6KI + bv+IdVzmUEIbc0Y5DkdJPBItSTwSF0k8EglGOhIDAAAAAAAAAAAAAAAAAAAAADowDgFCNg8HRjoREkg7 + EiVFOAw3UkQbaX5qT9KQfGT/m4dx/6CPef+tm4j/wLOg/87FtP/c08P/39nI/+HZyf/i28r/4trJ/+LZ + yP/f18X/3tTC/93Uwv/d08H/3dPA/93SwP/d0r//3dG+/93Rvv/d0b3/3dC8/93QvP/d0Lz/3c+7/9zP + uv/czrn/3M64/9zNuP/czbf/3My2/9zMtv/czLb/3Mu1/9zLtP/cyrT/28qz/9vJsv/ezbb/2MWt/5+K + cP9/aEv/iHFX/6iYhv/QycL/4ODc/+Xm5v/q6u3/7O7x/+jp6v/EvLL/l4Nt/3xkRv+Od1z/wqqP/9/H + q//awab/2sGl/9rApP/ZwKT/2cCj/9m/o//Zv6L/2b6h/9m+of/Zvp//2b2f/9m9nv/ZvJ7/2byd/93A + of/Ao4f/oYZs/6WKcP+lim//pYlt/6OJb/+JdVvmUEIadkY5DkpJPBIvSTwSGEk8EgpGOhIDAAAAAAAA + AAAAAAAACB0xATowDgJCNg8IRjoRFUU6DydPQRlHh3JY3ayah//Ivqz/1cy8/+Hby//n4tL/493O/+Hb + y//f2Mr/3tjH/97Wxv/e1sX/3tXE/97VxP/e1cP/3tTD/97Uwv/d1ML/3dPB/93TwP/d0sD/3dK//93R + vv/d0b7/3dC9/93QvP/d0Lz/3c+7/9zPuv/czrr/3M65/9zNuP/czbj/3M23/9zMtv/czLb/3Mu1/9zL + tP/cy7T/28qz/97Mtf/Zx6//nohu/35mSf+VgWj/xr2y/+Dc2f/h3dv/2dPO/8zCuP/Dtqn/vq+g/8m9 + s//X0cv/4d/e/7CjlP+EbVD/iHBV/8atkv/gx6z/2sGl/9rBpf/awKT/2cCj/9m/o//Zv6L/2b6h/9m+ + of/ZvqD/2b2f/9m9n//ZvJ7/2byd/97Bof/ApIf/oYZs/6aKcP+lim//pYlt/6OJb/+Pe2LxUkQdf0Y5 + DktJPBIySTwSGUk8EgpGOhIDAAAAAAAAAAAAAAAACB0xATowDgJCNg8JRjoRFkE0Ch9oVjR/ppWB/97Z + zP/n5Nb/493P/+Day//f2cr/3tjJ/97YyP/e18j/3tfG/97Wxv/e1sb/3tbF/97VxP/e1cT/3tTD/97U + wv/d1ML/3dPB/93TwP/d0sD/3dK//93Rvv/d0b7/3dC9/93QvP/d0Lz/3c+7/9zPuv/cz7r/3M65/9zO + uP/czbj/3M23/9zMtv/czLb/3Mu1/9zLtP/cy7T/3Mu0/+DPuP+rl33/fmZJ/5J+Zf/Lwbj/29bR/9LL + w/+8rJz/q5R+/6CHbP+XeVv/k3NU/5d5XP+bf2P/qJB4/8q/tf+zp5j/hG1R/5B4Xf/Qt5z/3sWp/9rB + pf/awKT/2cCj/9m/o//Zv6L/2b6h/9m+of/ZvqD/2b2f/9m9n//ZvZ7/2byd/97Bof/ApIf/oYZs/6aK + cP+lim//pYlt/6OHbf+Tf2j8VEYghkU4DUxJPBIySTwSGkk8EgpGOhIDAAAAAAAAAAAAAAAACB0xATow + DgJCNg8IRjoRFUE0ChxnVTOFtqiV/+Pg0v/f2sz/39nL/9/Zyv/f2cr/3tjJ/9/Zyf/g28v/3tfH/97X + xv/e1sb/3tbF/97VxP/e1cT/3tTD/97Uwv/d1ML/3dPB/93TwP/d0sD/3dK//93Rvv/d0b7/3dG9/93Q + vP/d0Lz/3c+7/93Pu//cz7n/3M65/9zOuP/czbj/3M23/9zMt//czLb/3Mu1/9zLtf/cy7T/38+4/8e1 + nf+EbVL/inRb/8O4q//TzMX/yb2z/7Whjv+qk3r/pY10/6KIbv+egmf/mn1h/5l8YP+Ye13/lndZ/5d5 + Xf+wmoX/m4dw/4BoTf+kjHH/3sWp/9zCpv/awKT/2cCj/9nAo//Zv6P/2b+i/9m+of/ZvqH/2b2f/9m9 + n//ZvZ7/2bye/97Bov+/o4b/oYZs/6aKcP+lim//pYlt/6OHbf+Sfmb6VEYghUU4DUxJPBIzSTwSGkk8 + EgpGOhIDAAAAAAAAAAAAAAAACB0xATowDgFCNg8IRjoRFEE0ChlnVzODq5mF/+Dcz//f28z/39rL/9/Z + yv/f2cr/4d3O/9/by//Y0b//4dzM/+DZyP/e1sb/3tbF/97VxP/e1cT/3tTD/97Uw//e1ML/3dPB/93T + wf/d08D/3dK//93Sv//d0b7/3dG9/93Qvf/d0Lz/3c+7/93Pu//cz7r/3M65/9zOuf/czbj/3M23/9zN + t//czLb/3My1/9zLtf/cy7T/3863/5yFbP+BaU3/r5+N/8/FvP/IvLD/uqiX/7WgjP+ynIb/rZZ//6eP + dv+iiG7/nYFl/5t+Yf+afWH/mn1h/5p9Yf+Yel3/mX5i/4x1Wv+Gb1T/xayR/97Fqf/awaX/2cCk/9nA + o//Zv6P/2b+i/9m+of/ZvqH/2b2g/9m9n//ZvZ//2bye/97Bov/Ep4r/o4hu/6aKcP+lim7/pYlu/6SI + bf+Tf2b6VEYfhUU4Dk1JPBIzSTwSGkk8EgpGOhIDAAAAAAAAAAAAAAAAAAAAAAAAAABCNg8GRjoREUI2 + CxpkVDBtnYp0++Hcz//g283/39rL/9/Zy//i3c7/zsKv/6SJb/+hh2v/rph//9zTw//f2Mj/3tbF/97W + xf/e1cT/3tXD/97Uw//e1ML/3dPB/93Twf/d08D/3dK//93Sv//d0b7/3dG9/93Qvf/d0Lz/3c+7/93P + u//cz7r/3M65/9zOuf/czrj/3M23/9zNt//czLb/3My1/9zLtf/fz7j/yref/4VtUv+Re2L/wrWp/8i9 + sf/DtKT/vq6c/7mnlf+1oY3/sp2I/6mSe/+chGv/lHlf/5N3XP+ZfGH/m31h/5p9Yf+afWH/m31h/5d7 + YP+Gb1P/pIxx/97EqP/awaX/2cCk/9nAo//Zv6P/2b+i/9m+of/ZvqH/2b6g/9m9n//ZvZ//2bye/93A + of/JrI3/pYpw/6WKb/+liW//pYlu/6SIbf+VgGf6VEYfhUU4Dk1JPBIzSTwSGkk8EgpGOhIDAAAAAAAA + AAAAAAAAAAAAAAAAAABBNg8GRjoREEM2CxthUS1dk35m9N/bzf/g283/39rL/+DazP/f2sn/oolu/8W2 + qv/TycD/oIVq/8K0nf/h28v/3tbF/97Wxf/e1cT/3tXD/97Uw//e1ML/3dPB/93Twf/d08D/3dK//93S + v//d0b7/3dG9/93Rvf/d0Lz/3dC8/93Pu//dz7v/3M65/9zOuf/czrj/3M23/9zNt//czLf/3My2/9zL + tf/j073/q5Z9/4FoTP+lk3//x7uv/8m7rv/Huav/w7Ok/72tnP+8qpf/qJJ8/4xzW/+GbFT/hmxV/4Rp + Uf+CZ07/jXFW/5p+Yf+afWH/mn1h/5x9Yf+Sd1v/iHJX/9S6oP/cwaX/2cCk/9nApP/ZwKP/2b+i/9m/ + ov/ZvqH/2b6g/9m9n//ZvZ//2bye/93Aof/IrI3/pYpw/6WKb/+liW//pYlu/6KHbP+chW//V0ojkUQ4 + DUpJPBIzSTwSGkk8EgpGOhIDAAAAAAAAAAAAAAAAAAAAAAAAAABBNg8FRjoRD0Q3DR1YSSNCjnlg59TP + v//i3c//39rL/+Ddzv/Z0sH/pIpu/+Xg3f/Z0Mr/r5mE/7ikjf/j3c7/3tbF/97Wxf/e1cT/3tXD/97U + w//e1MP/3dTC/93Twf/d08H/3dLA/93Sv//d0r//3dG+/93Rvf/d0L3/3dC8/93Pu//dz7v/3M66/9zO + uf/czrn/3M24/9zNt//czbf/3My2/9zMtv/gz7n/mYNn/4dwVf+xoI7/yLmt/9HFuv/Mv7L/xrip/8S0 + pv+umof/h21V/4RqUv+HbVX/hGlQ/493Yv+ciHb/jnhi/4pvU/+bfGD/mn1h/5t9Yf+Ye1//iXJX/76m + iv/fxqr/2sCk/9nApP/ZwKP/2b+i/9m/ov/ZvqH/2b6g/9m9oP/ZvZ//2bye/93Aof/HrI3/popw/6WK + cP+liXD/pYlu/6KHbP+bhW//V0kjkEQ4DUpJPBIzSTwSGkk8EgpGOhIDAAAAAAAAAAAAAAAAAAAAAAAA + AABBNg8FRjoRDUg7ER1FOg4rgnBU3M3Etf/i3tD/39rM/9/azP/h3Mz/pY1x/9TKwP/Z0Mn/tKCM/66Y + ff/k38//3tbG/97Wxf/e1sX/3tXE/97Vw//e1MP/3dTC/93Twf/d08H/3dLA/93Sv//d0r//3dG+/93R + vf/d0L3/3dC8/93Pu//dz7v/3M+6/9zOuf/czrn/3M24/9zNt//czbf/3My2/+DPuf/Twar/j3ld/412 + Xf+2o5P/z8S5/9bMw//PxLj/zL+y/8Gwof+NdF3/g2hQ/4dtVf+EaFD/l4Nw/7yzqf/Jwrv/xb61/56K + eP+NcVT/nH9i/5p9Yf+cfWH/jHNX/6uTeP/gx6v/2sCk/9nApP/ZwKP/2b+i/9m/ov/ZvqH/2b6g/9m+ + oP/ZvZ//2b2e/93Aof/Hq43/polw/6WKcP+linD/pYlu/6KHbP+bhW//V0kjkEQ4DUpJPBIzSTwSGkk8 + EgpGOhIDAAAAAAAAAAAAAAAAAAAAAAAAAABBNg8DRjoRC0g7EhtANAkifGpNycS5p//k4NL/39rM/9/a + y//m4dT/q5J5/8q8rv/Z0sn/u6iW/6aOcv/k3c7/3tbH/97Wxf/e1sX/3tXE/97Vw//e1MP/3dTC/93T + wf/d08H/3dLA/93Sv//d0r//3dG+/93Rvf/d0b3/3dC8/93QvP/dz7v/3M+6/9zOuf/czrn/3M24/9zN + t//czbf/3My2/+DQu//LuqL/i3RZ/5B6Yf+9rJv/187G/9nSy//SyL7/z8S4/7CdjP+BZU3/h21V/4Zs + U/+HblX/t6yh/9DLxP/V0Mr/3NnU/83Gv/+UfGb/lnhb/5p9Yf+cfWH/j3RZ/5qCaP/iya3/2sCk/9nA + pP/ZwKT/2b+j/9m/ov/Zv6L/2b6h/9m+oP/ZvZ//2b2e/9y/of/Ps5X/qo5z/6WKb/+linD/pIlu/6SI + bf+fh3D/VEcgjkQ4DUpJPBIzSTwSGkk8EgpGOhIDAAAAAAAAAAAAAAAAAAAAAAAAAABBNg8DRjoRCUg7 + EhhDNgojeWZJrbmsmv/l4dX/39rM/9/ay//k4dL/tqKL/72snP/Z0cn/wbCi/6OJbf/c1MP/39jI/97W + xf/e1sX/3tXE/97VxP/e1MP/3tTC/93Uwv/d08H/3dPA/93SwP/d0r//3dG+/93Rvv/d0b3/3dC8/93Q + vP/dz7v/3M+6/9zOuv/czrn/3M24/9zNuP/czbf/3My2/+DRu//MuqL/i3RZ/493XP/CsqL/3dfQ/9zV + z//Vy8P/0MS5/5iCbv+FaVL/h21V/4NoTv+Xg2//xr+2/9bQzP/i3tr/5uXi/+fk4v+tnY//j3JU/5t+ + Yf+afWH/k3db/5uDaf/iya3/2sGl/9rApP/ZwKT/2b+j/9m/ov/Zv6L/2b6h/9m+oP/ZvaD/2b2f/9y/ + of/Ps5X/qo90/6WKb/+minD/pYlu/6SIbf+dhm7/ZFQxnEY5DkxJPBIzSTwSGkk8EgpGOhIDAAAAAAAA + AAAAAAAAAAAAAAAAAABBNg8BRjoRCEg7EhVDNwwicmBBlK2ei//l49b/39rM/9/azP/j39D/vq6X/7Sh + jf/Z0sr/w7Wn/6GGa//SyLX/4drL/97Wxv/e1sX/3tXE/97VxP/e1cP/3tTC/93Uwv/d08H/3dPA/93S + wP/d0r//3dG+/93Rvv/d0b3/3dC8/93QvP/dz7v/3M+6/9zPuv/czrn/3M64/9zNuP/czbf/3My2/+DR + u//MuqL/i3Va/411Wv/AsaH/4NvV/+DY0f/XzsX/0cW6/5N8Zf+FalL/h21V/4BlTP+hkH//z8nE/9vX + 0v/t6+f/9vTz//Hw7/+8sKT/j3JY/5p8YP+afWH/lHhc/5uEaf/iya3/2sGl/9rApP/ZwKT/2cCj/9m/ + ov/Zv6L/2b6h/9m+of/Zvp//2b2f/9zAof/PspX/qo90/6WKb/+minD/pYlu/6SIbf+bhG3/cmJCq0Y6 + D0xJPBIzSTwSGkk8EgpGOhIDAAAAAAAAAAAAAAAAAAAAAAAAAABEOBABRjoRB0g7EhRENwwha1k4fqST + fv/n5Nf/39vN/9/azP/i39D/xbei/6qRev/c1c3/w7an/6KIb//Kvqn/4t7O/97Wxv/e1sX/3tXE/97V + xP/e1cP/3tTC/93Uwv/d08H/3dPA/93SwP/d0r//3dG+/93Rvv/d0b3/3dC9/93QvP/d0Lz/3c+7/9zP + uv/czrn/3M64/9zNuP/czbf/3My3/+DRu//KuKL/i3RZ/4x1Wf+8q5r/4t3Y/9/Z1P/XzsX/0ce7/5R9 + Z/+FalL/h21V/4BlTP+ikYD/zsrF/9zY0//v7Or/+Pf3//Lv7//DurD/knZc/5l8X/+afWH/lHhc/5mD + aP/iya3/2sGl/9rApP/ZwKT/2cCj/9m/o//Zv6L/2b6h/9m+of/Zvp//2b2f/9zAof/OsZT/qo90/6WK + cP+minD/pYlu/6SJbv+bhG3/cF8/qEY5D01JPBIzSTwSGkk8EgpGOhIDAAAAAAAAAAAAAAAAAAAAAAAA + AABEOBABRjoRB0g7EhJFOQ4hY1IvYp+OeP/d283/4t3Q/+DazP/i3M7/0ce2/6SLcv/VzMP/xriq/6KJ + b//Bspz/5d/Q/97Wxv/e1sX/3tXE/97VxP/e1cT/3tTD/97Uwv/d1ML/3dPB/93TwP/d0sD/3dK//93R + vv/d0b7/3dC9/93QvP/d0Lz/3c+7/9zPuv/czrr/3M65/9zNuP/czbj/3M23/+DQuv/RwKn/kHhe/4px + Vf+3pZT/4dzW/9/Y0v/XzsX/0cW7/5V9Z/+FalL/h21V/4NmTf+diXf/yMK7/9bRzP/k4Nz/6ufl/+nm + 5f+9sqf/kXZa/5l8X/+afWH/lHhc/6CIbf/iya7/2sGl/9rBpf/awKT/2cCj/9m/o//Zv6L/2b6h/9m+ + of/ZvqD/2b2f/9vAov/TtZj/rJF2/6WKcP+mi3D/pYlv/6WKbv+ehW7/b18/qUY5D05JPBI0STwSG0k8 + EgtGOhIDAAAAAAAAAAAAAAAAAAAAAAAAAABEOBABRjoRBkg7EhBJPBEhSz4URZiGb//X0cP/5OHU/+Dc + zv/g283/29XF/6KJb//Pw7f/yLyu/6WLdP+6qJH/5uHS/97Wxv/e1sb/3tbF/97VxP/e1cT/3tTD/97U + wv/d1ML/3dPB/93TwP/d0sD/3dK//93Rvv/d0b7/3dC9/93QvP/d0Lz/3c+7/9zPuv/cz7r/3M65/9zO + uP/czbj/3M23/93Nt//ezrj/ln9m/4VuUf+nkn3/3NXM/97X0P/VzML/0ca6/6GNeP+CZ0//h21V/4Rq + Uf+PemP/vLSq/8/Jwv/X0sz/2tbR/93b1v+voZH/j3JV/5t9Yf+afWH/k3Zc/62Vev/gx6z/2sGl/9rB + pf/awKT/2cCj/9nAo//Zv6L/2b6h/9m+of/ZvqH/2b2f/9q+oP/Yu5z/rpJ4/6OIb/+mi2//pYlv/6aK + bv+fhm7/bl9ArEY5D1FJPBI3STwSHUk8Eg1HOxIEAAAAAAAAAAAAAAAAAAAAAAAAAABEOBABRjoRBEg7 + Eg5JPBEeRjgNOZN/Z/LQyLj/5eLV/+Hcz//g3M7/39rK/6mRd//Ft6j/y76w/6mSe/+xnIT/4dzM/9/Y + x//e1sb/3tbF/97VxP/e1cT/3tTD/97Uwv/d1ML/3dPB/93TwP/d0sD/3dK//93Rvv/d0b7/3dG9/93Q + vf/d0Lz/3c+7/93Pu//cz7n/3M65/9zOuP/czbj/3M23/9zMt//k1L7/pJB3/4RsUP+UemD/0ca6/9vT + zP/Sx73/0MS5/7akk/+BZ0//h21V/4dtVf+DaVD/p5mK/8W/t//Jwrv/zsnC/8fBuv+ZhG7/lHda/5t9 + Yf+afWH/kHRY/8Gqjv/dxan/2sGl/9rBpf/awKT/2cCk/9nAo//Zv6P/2b+i/9m+of/ZvqH/2b2f/9q+ + oP/Wupz/rpJ4/6OIb/+mi2//pYlv/6aKbv+dhWz/fWtPyUg7EVdJPBI5STwSHkk8Eg5HOxIFQzcQAQAA + AAAAAAAAAAAAAAAAAAAAAAAARjoRBEg7EgxJPBEbRzsQNIt4XtfHvq//5uTZ/+Le0f/h3dD/4tzO/7Kd + hf+/r57/zb+z/6+ZhP+qknf/3tbG/+DZyP/e1sb/3tbF/97VxP/e1cT/3tTD/97Uw//e1ML/3dPB/93T + wf/d08D/3dK//93Sv//d0b7/3dG9/93Qvf/d0Lz/3c+7/93Pu//cz7r/3M65/9zOuf/czbj/3M23/9zN + t//g0Lr/w7Gb/4VuU/+NdFn/uaeV/9fOxf/PxLn/y76x/8W2pv+XgGv/gmdP/4dtVf+Ha1P/iXJb/6qc + jv++uK//vrev/56Me/+Pc1f/m35h/5p9Yf+ZfGD/kXhd/9i/pf/bw6n/2sGm/9rBpf/awaX/2cCk/9nA + o//Zv6P/2b+i/9m+of/ZvqH/2b6g/9q+oP/Wupz/rpJ4/6WIb/+li3D/pYlv/6aKbv+dhWz/fWtPykg7 + EVxJPBI+STwSJEk8EhFHOxIFQzcQAQAAAAAAAAAAAAAAAAAAAAAAAAAARjoRAkg7EgtJPBIYSDsQLoFs + Ub/AtaT/6ufc/+Lf0v/i3tD/49/R/7mnkv+4pZL/zsK1/7KciP+kjHH/2c++/+Day//e1sb/3tbF/97W + xf/e1cT/3tXD/97Uw//e1ML/3dPB/93Twf/d08D/3dK//93Sv//d0b7/3dG9/93Qvf/d0Lz/3c+7/93P + u//cz7r/3M65/9zOuf/czrj/3M23/9zNt//czLf/3cy2/5V/Zf+FbVL/nYRq/83Btv/NwbX/xriq/8S1 + pf+4pJL/jXRd/4NpUf+GbFT/hGpR/4dtVv+PeWP/jXZg/4xwV/+bfWH/mn1h/5t+Yv+PdFj/q5R5/93F + qv/awqf/2sGm/9rBpf/awaX/2cCk/9nAo//ZwKP/2b+i/9m+of/ZvqH/2b6g/9q+oP/Wup3/rpN4/6WI + b/+li3D/pYpv/6WKbv+ehm3/fWtPzEg6EWFJPBJDSTwSJ0k8EhJGOhIHQzcQAQAAAAAAAAAAAAAAAAAA + AAAAAAAARjoRAkg7EgpJPBIYSDsRKndjRqi5rZv/6unb/+Pg0//i3tL/5uHU/8GynP+znor/zsK2/7aj + j/+hhmz/08m3/+LbzP/e18b/3tbF/97Wxf/e1cT/3tXD/97Uw//e1ML/3dPB/93Twf/d08D/3dK//93S + v//d0b7/3dG9/93Rvf/d0L3/3dC8/93Pu//dz7v/3M65/9zOuf/czrj/3M24/9zNt//czLf/4dG7/76r + k/+DbFD/iXFW/62Xgf/Lv7D/w7Sl/76snP+8qZf/r5qG/5R8ZP+Jb1j/iG1X/4ZsU/+Ga1L/jnFX/5t+ + YP+afWH/mn1h/5d6Xv+Pdlz/zrid/97HrP/awqf/2sGm/9rBpf/awaX/2cCk/9nApP/ZwKP/2b+i/9m/ + ov/ZvqH/2b6g/9m9n//ewqT/spZ8/6OIbv+li3D/pYpv/6WKbv+ghm3/fWpNykc6EWRJPBJFSTwSKUk8 + EhRGOhIHQzcQAQAAAAAAAAAAAAAAAAAAAAAAAAAARjoRAkg7EghJPBIXSDsQJG9cPY+zpZH/5ePW/+Xh + 1P/j4NL/5uLX/8zArf+ul4D/zL+y/7uql/+ghGn/0Maz/+Lczf/e18b/3tbF/97Wxf/e1cT/3tXE/97U + w//e1MP/3dTC/93Twf/d08H/3dLA/93Sv//d0r//3dG+/93Rvf/d0L3/3dC8/93Pu//dz7v/3M66/9zO + uf/czrn/3M24/9zNt//czbf/3s+5/93Ntv+finH/gWlO/452Wv+znYj/wbKh/7uplv+1oo3/sZuG/62W + gP+iiXH/mX5k/5Z6Xv+ZfWD/nH9h/5p9Yf+afWH/m3xg/4pwVP+ymoD/38it/9rDqP/awqf/2sKm/9rB + pv/awaX/2sCk/9nApP/ZwKP/2b+i/9m/ov/ZvqH/2b6g/9m+oP/ewqT/spd8/6OIbv+minD/pYpv/6aK + bv+ghmz/g3BV20g7EWhJPBJISTwSK0k8EhRGOhIHQzcQAQAAAAAAAAAAAAAAAAAAAAAAAAAARjoRAkg7 + EghJPBIURTgOHlhIInKtnor/4NzP/+bi2P/k39T/5+TX/9XMvP+tmID/yLys/8Cvnf+hhmz/yryp/+Lb + zv/e18f/3tbG/97Wxf/e1sX/3tXE/97Vw//e1MP/3dTC/93Twf/d08H/3dLA/93Sv//d0r//3dG+/93R + vf/d0b3/3dC8/93Pu//dz7v/3M+6/9zOuf/czrn/3M24/9zNt//czbf/3My2/+HSuv/Twar/kHle/4Jq + Tv+Pdlr/rZeA/7mmk/+znor/rZeA/6ePeP+jiW//noJm/5t+Yf+afWH/mn1h/5t9Yf+bfGD/inBU/5yF + av/bxKn/3car/9rDqP/awqf/2sKm/9rBpv/awaX/2sCk/9nApP/ZwKP/2b+i/9m/ov/ZvqH/2b6h/9m+ + oP/ewqT/spd8/6OIbv+minH/pYpv/6aKb/+fhm3/iXZc6kk7EWtJPBFJSTwSK0k8EhVGOhIIQzcQAQAA + AAAAAAAAAAAAAAAAAAAAAAAARjoRAUg7EgZJPBISRTgNG1JDG2Clk3//3NfJ/+jl2f/k4dX/5+PY/9rS + xP+ynYb/xben/8Kxof+mjnX/wbGb/+Pdzf/e18f/3tbG/97Wxf/e1sX/3tXE/97Vw//e1MP/4djG/+DX + xf/d08H/3dLA/93Sv//d0r//3dG+/93Rvv/d0b3/3dC8/93QvP/dz7v/3M+6/9zOuf/czrn/3M24/9zN + uP/czbf/3My2/9zMtv/h0Lv/yrig/454Xf+DalD/jHJW/5+Gbf+slX7/rJN7/6aMcv+ghGr/m35i/5t+ + Yv+bfmL/m31h/5Z7Xv+Ib1P/lH1j/9G7ov/dx6z/2sOo/9rDqP/awqf/2sKm/9rBpv/awaX/2sGl/9nA + pP/ZwKT/2b+j/9m/ov/Zv6L/2b6h/9m+oP/ewqT/spd8/6OIbv+minH/pYpv/6aKb/+fhm3/h3Vb6Ek7 + EWtJPBFJSTwSLEk8EhVGOhIIQzcQAQAAAAAAAAAAAAAAAAAAAAAAAAAARjoRAUg7EgZJPBIQRTgNG1RF + HlOaiHLz2NHC/+jm3P/l4df/5uTY/9/Zzf+1oIn/wrOj/8S0pP+qk33/u6mT/+Lcz//g2cn/3tbG/97W + xf/e1sX/3tXE/97Vw//g1sb/0MKu/9LFsf/h2cf/4NbD/93SwP/d0r//3dG+/93Rvv/d0b3/3dC8/93Q + vP/dz7v/3M+6/9zOuv/czrn/3M24/9zNuP/czbf/3My2/9zMtv/cy7X/4tG6/869pv+Zgmj/gmtP/4Zu + U/+Pd1z/mIBl/5yBZv+YfWL/lntf/5V6Xf+TeF3/jHNY/4NtUv+giW//1L+l/93Hrf/axKn/2sOp/9rD + qP/aw6j/2sKn/9rCpv/awab/2sGl/9rApP/ZwKT/2b+j/9m/ov/Zv6L/2b6h/9m+oP/ewqP/uJyB/6SJ + b/+mi3H/pYpv/6aKbv+iiG7/inZb6Ec7EWtJPBFJSTwSLEk8EhVGOhIIQzcQAQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAEg7EgRJPBIORTkOGVNEHUePemHh1My+/+rp3v/m49j/5uLX/+Xg1v+6ppH/wK+f/8S1 + pv+wmoX/sp2G/+Hbzv/g2sv/39jI/97Wxv/e1sX/3tXE/+HYx//Xy7n/rZd+/6mReP+4pY7/0MKv/9/T + wf/g1cL/39PA/93Rvv/d0b3/3dC8/93QvP/dz7v/3c+7/9zPuv/czrn/3M64/9zNuP/czbf/3My2/9zM + tv/czLX/3Mu1/+DRuf/ayLH/tqKJ/495Xv+Fb1T/g2xR/4VtUv+FbVL/hm5T/4ZvVP+Fb1T/lH5k/72o + jf/cx63/3smv/9rEqv/axKr/2sOp/9rDqP/aw6j/2sKn/9rCpv/awab/2sGl/9rApP/ZwKT/2cCj/9m/ + ov/Zv6L/2b6h/9m+of/cwaP/vaGF/6SJcP+mi3D/pYpv/6aKb/+iiG7/iXVb6Ec7EWpJPBFJSTwSLEk8 + EhVGOhIIQzcQAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEg7EgNJPBIMRTkOGFFEGzuDblPQz8e5/+ro + 3f/m49n/5uPY/+jl2/++rpn/u6qY/8W1p/+0n4r/rZV8/+Hdzf/h28z/4NnK/9/Xx//e1sX/3tXE/+HY + x//Wyrf/rpZ+/6aNdP+nj3b/qZF4/7Kdhv/Mvan/2867/+LXxP/g1MH/3dC9/93QvP/d0Lz/3c+7/9zP + uv/czrn/3M64/9zNuP/czbj/3My3/9zMtv/czLb/3Mu1/9zLtP/fzrj/4M+4/9vJsv/Cr5f/q5Z9/56I + bf+ahGr/oIpv/62Xff/EsJb/28at/+DLsf/dx6//2sWr/9rEqv/axKr/2sOp/9rDqP/aw6j/2sKn/9rC + pv/awab/2sGl/9rBpf/ZwKT/2cCj/9m/o//Zv6L/2b6h/9m+of/cwaP/vKGF/6WJcP+mi3D/pYpw/6aK + b/+ghmz/kn1l/0g7Em1IPBFJSTwSLEk8EhVGOhIIQzcQAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEg7 + EgNJPBILRzoQFk5AFyx9ak29xryr/+jm2//o5dr/5uPY/+zr4f/Ju6r/uaSR/8a2qP+4pZH/qI93/9/Y + yv/h3M7/4dvM/+Hayv/e18f/3tXE/9/Wxf/d08H/sZuD/6ePdf+rk3r/q5N7/6mRef+mj3b/s5yE/8Wz + nv/WyrX/4dXC/9/Tv//d0Lz/3c+7/9zPuv/cz7r/3M65/9zNuP/czbj/3M23/9zMtv/czLb/3Mu1/9zL + tP/cy7T/28qz/9zLs//ezLb/4c+3/+PQuf/j0Lj/48+3/+HNtf/eyrH/3Meu/9vGrP/bxaz/2sWr/9rF + q//axKr/2sSp/9rDqf/aw6j/2sKn/9rCp//awqb/2sGl/9rBpf/awKT/2cCj/9m/o//awKL/2r+h/9q/ + of/ew6P/vKGG/6WJcP+mi3D/pYpw/6aJb/+gh2z/kn1l/0g7Em1IPBFJSTwSLEk8EhVGOhIIQzcQAQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEg7EgJJPBIISTwSFkM3DBtsWzmnv7Oi/+fk2P/o5dv/5+TZ/+vp + 3//QxbX/uqaS/8a3qP+7qJX/rJN7/9fOvv/k39H/4dvN/+HazP/h2cr/3tfG/97VxP/i2cn/tJ+H/6aO + df+rk3r/q5N7/6uTe/+rlHz/qZF4/6eOd/+umYH/vaqU/9LDrv/f0b3/39G9/+DSvv/e0rv/3c+6/9zO + uf/czbj/3M23/9zMtv/czLb/3Mu1/9zLtf/cy7T/28qz/9vKs//bybL/28mx/9vIsf/byLD/28ev/9vH + r//bx67/28at/9vGrf/bxqz/2sWr/9vGrP/bxav/28Wq/93Fqv/dxan/3MSp/9vDqP/bw6f/28Km/9rB + pv/awKT/2cCj/9e+o//QuZ//0rqe/9K5nv/QuZ//uaCF/6aKcP+mi3D/pYpw/6WKb/+jiG3/k35m/0g7 + Em1IPBFJSTwSLEk8EhVGOhIIQzcQAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEg7EgFJPBIISTwSFUE1 + CRdmVTSTtaaT/+Xh1f/p5tz/5+Ta/+vo3v/Xz8H/uaaR/8a2p/+9qpj/rZWA/8/Es//l4dT/4tzO/+Hb + zf/h2cv/4NnJ/97Wxf/j2sn/vKmU/6ePdv+qk3r/q5N7/6uTe/+rlHz/rJR8/6yUfP+qk3r/qZJ7/6uU + fP+1nof/xbOd/9LBrP/WybL/2su2/97RvP/h077/4NK8/+DQu//f0Lr/3864/9/OuP/fzrf/3822/97N + tv/ezLX/3sy0/97MtP/ey7P/3suy/9/Lsv/fy7H/38mw/9/Ksf/gyrD/3Met/9rFq//Xwqj/1cCm/9S+ + pP/QuqD/yrSd/8Wwmf/Dr5n/vqmW/7yolf+5pZH/tqOS/7ekkf+2o5P/tqST/7aklP+3ppX/s52I/6eL + cf+mi3D/pYpw/6WKb/+kim3/k35m/0Y5D2pIPBFJSTwSLEk8EhVGOhIIQzcQAQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABJPBIGSTwSEkI1ChhmVjN9qZmE/+Pf1P/q59//6Obc/+no3v/g2c3/uaaS/8a3 + qP+/rZv/sJmE/8m6qP/n49f/49zQ/+Pcz//i28z/4drL/+HZyf/h2cr/xbWf/6mOdv+qknr/q5N6/6uT + e/+rlHz/rJR8/6yUfP+slX3/rJV9/6yWfv+rlH3/qpN8/6mSe/+xmoP/uKON/7+slv/EsZz/ybej/8u5 + pP/Qvqj/08Ks/9PBq//Twar/08Cq/9LAqv/TwKn/08Cp/9PAqf/Tv6j/07+o/8y4of/MuKH/zLmi/8m0 + nf/Is5z/w66Y/8Cqlv+6ppL/tqKP/7GgjP+xnoz/sp+N/7Ogjf+zoI//taCP/7Whj/+1oY7/tKGO/7aj + kf+1opD/t6WT/7ellP+4ppb/spyH/6eLcf+mi3D/popw/6aKb/+kiW3/lYBo/1VGIHpHOg9HSTwSLEk8 + EhVGOhIIQzcQAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJPBIGSTwSEEI3CxljUzBqnYp0+eHe + 0v/p6N7/6efd/+rn3f/l4db/u6iV/8a3p//Ar57/s5yG/8Gxnv/p5dr/497R/+Pd0P/j283/4tvM/+Ha + y//j28z/08az/6iQdv+qknr/q5N6/6uTe/+rlHz/q5R8/6yUfP+slX3/rJV9/6yWfv+tln//rZZ//62X + f/+tln//q5R+/6qUfP+pkXv/rJV+/62Ygv+wmoT/sp2H/7Kdh/+ynYf/sp2I/7KdiP+znoj/s56J/7Oe + if+zn4r/tJ+K/7GciP+xnYn/sZ2J/7Cbh/+vm4f/sJyI/7GejP+0oI7/taGQ/7ajj/+2oo//tqKP/7aj + kP+0oY//tKKQ/7amlv+7rqL/wrqx/8vGwf/BtKj/taOQ/7elk/+4p5b/spuH/6eLcf+mi3H/popw/6aK + b/+kiG3/loFo/2RUMYhGOQ5FSTwSLEk8EhVGOhIIQzcQAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABJPBIFSTwSD0Q3CxlgUCtVkX1l8OHcz//r6N//6efe/+nm3f/s6OH/wK+c/8Kyof/DsqH/tKCL/7uo + lf/q5tr/5N/S/+Te0f/j3c7/4tvN/+LbzP/i2sv/4NnJ/6yUfP+qknf/q5N6/6uTe/+rlHz/q5R8/6yU + fP+slX3/rJV9/6yVfv+tln//rZZ//62Xf/+ul4D/rpeB/66Ygf+umIL/r5iC/66Ygv+umIL/rpmD/6+Z + g/+vmYT/r5qE/6+ahf+wm4X/sJuG/7Cbhv+wnIf/sZyH/7Gcif+xnYn/sZ2K/7ahjv+3pJH/tKGN/7Gc + iP+wm4b/rZiE/6iTfv+mkXz/pY97/6WSf/+ol4j/sKGT/7irn//At6//x8G6/9LPzf/Py8f/uKeX/7ak + kv+4p5b/spuH/6eLcf+mi3H/popw/6aKb/+kiG3/loFo/2FRLoZGOQ1GSTwSLEk8EhVGOhIIQzcQAQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJPBIFSTwSDkU4DRpZSiRAjXlg5tXPwv/r6N7/6+jg/+rn + 3f/u7OL/x7io/8Oxof/DtKT/t6SP/7qmk//l4NX/5eHV/+Xe0v/k39D/493P/+Pczv/j283/4tvM/7yq + lf+pkXj/qpJ5/6uTe/+rlHz/q5R8/6yUfP+slX3/rJV9/6yVfv+tk3r/qpB2/6qRd/+ulX7/rpeB/66Y + gf+umIL/r5iC/6+Zgv+vmYP/r5qE/6+ahP+wmoX/sJuF/7Cbhf+xnIb/sZyH/7Gch/+xnYj/sp2I/7Kd + if+ynon/tKCM/6eRe/+cgmn/mH9m/5N4Xv+Rd13/j3Na/5J5Yf+Xf2n/nohz/6WRf/+smor/s6WY/7So + m/+7sKT/xsG8/9DNy//PycT/uaiX/7akkv+4p5b/spuH/6eLcf+mi3H/potw/6WKb/+nim//l4Jp/2BR + LodGOQ1HSTwSLUk8EhZGOhIIQzcQAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJPBIESTwSC0g8 + ERtFOA4ngm9U3c3Etf/q597/7Onh/+ro3//t7OP/z8O1/8Gwnv/Ht6f/u6eU/7mlkv/f2cz/5+TZ/+Xg + 1P/l39H/5N7Q/+Tdz//j3M7/5N3Q/8y9q/+ul4H/q5R6/6uTe/+rlHv/q5R8/6yUfP+slX3/rJR8/6yR + eP+xraX/v8nP/7/Avv+wm4b/rJR7/66Ygf+umIL/rpiC/6+Zgv+vmYP/sJiA/7KXff+xmID/sJmB/7KY + fv+ymIH/sZyH/7Gch/+xnYj/sp2I/7Kdif+zoIv/q5V//4hqTf+DZEb/hWhL/4hrUP+NcVf/kXZd/5V9 + Zf+ZgWr/moRu/5aBbP+Uf2j/i3Zf/4VvVf+Fb1X/mIZz/8vIwv/Rz8z/u6qb/7ajkP+4p5b/spuH/6iM + cv+ni3H/potw/6WKcP+nim//loFp/19SL4lGOQ1KSTwSMEk8EhhGOhIKQjcQAgAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABJPBIDSTwSCkk8EhlANAkgfGpNyMK3pv/s6d//7Ori/+vo4P/t6+L/2M/C/8Gv + nv/IuKn/vauZ/7ilkf/b08X/6uXa/+bg1P/l4NL/5N7R/+Te0P/k3c//5t/R/9jNvf+xnYf/spyF/6yU + e/+rk3r/q5R8/6yUfP+slH3/q5J2/6ysqf/B6P//3/T//+/+///T3uT/rpqG/62Uff+umIL/rpiC/6+Z + gv+wmID/sJZ//6Wnov+cucj/mr7R/6GyuP+tnpD/tJl//7Gchv+xnYj/sp2I/7Kdif+1oIz/oYly/4Vm + Sf+HaU3/iWxQ/4xvVP+McVf/iXJY/4VvVf+BalD/fWZK/35mS/+FblT/i3de/5eFbv+UgWr/fmdL/66j + lf/W1dT/u6yd/7aikP+4p5b/spuG/6iMcv+ni3H/potw/6WKcP+nim//mIJr/25ePadENwxLSTwSMkk8 + EhpGOhILQjcQAzwyDwEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJPBIBSTwSCEk8EhZDNgoheWZJrLap + l//r6d//7evj/+zq4P/t6+P/4NjN/8Kvnv/Ku6z/wK6c/7ajj//Vy7z/6+je/+fi1v/m4dT/5uDT/+Xf + 0v/l3tH/5d/R/9/WyP+8qZb/taCK/7Och/+slXz/qpN7/6yUfP+slHz/q5R8/6vN5P/F6f//5PL///b7 + ///j+P//uLay/6uTe/+umIH/rpiC/7CYf/+umoP/k7fN/4vX//+a3P//oN7//5bd//+OzfH/o6mn/7SZ + gP+xnYj/sp2I/7Kdif+0oIz/qZN9/4ZnS/+HaU3/iWxQ/4luUv+Eb1T/hG9V/4x3Xv+YhG3/qJaC/7io + mP/NwrX/4dvT///////m4tz/hW5U/5qMeP/W1dP/u6yc/7aikP+4p5b/spuG/6iMcv+ni3H/potw/6WK + cP+nim//mIJr/25ePqlENwxNSTwSNUk8EhxGOhINQjcQBD0yDwEAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABJPBIBSTwSB0k8EhRDNwwfc2BBkqyciP/r6d//7evj/+zq4v/t6uP/5uDX/8Gwnv/Ku6v/w7Gg/7ai + j//Rxbf/7erg/+fj1//n4db/5uHU/+bf0//l39L/5d7R/+Xf0f/IuaX/tJ+J/7eij/+0n4n/rJR8/6yT + e/+slHz/q5R7/6fM6P+65P//0ur+/9vv/v/Q7///t8bO/62Vff+umID/rpiB/7OVef+UsL//gNX//5zZ + //+x4f7/uuP+/6ze/v+U2f//gcz9/6WknP+zmoP/sZ2I/7KdiP+ynon/sZ2I/4dpTP+HaUz/iWxP/4lu + U/+CbFL/mIFp/7WhjP/GtaX/2MzA/+Xd1P/t5+H/8+/r//r4+P/x7er/jnlg/499Z//b3dz/va6h/7Si + j/+4p5b/spuG/6iMcv+ni3H/potw/6WKcP+nim//moRs/29ePqpENwxQSTwSNkk8Eh1GOhINQjYQBD0y + DwEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJPBIBSTwSB0k8EhNENwwgaVg3dqSTff/r6t//7evj/+3r + 4//t6uP/6+ng/8KxoP/Iuqv/w7Kh/7ejkP/Uybz/7Ovh/+jj2P/n4tf/5uHV/+bg1P/m39P/5d7R/+ji + 1v/SxrX/tqGM/7ikj/+3o4//tJ+K/62Vfv+rlHv/rJR6/6XH3P+p3v//tt/+/7vi/v+15v//rLvD/66U + e/+umIH/sZd9/6edjv93xPX/h9P//6HZ/v+25P7/wuf+/7Hg/v+a1/7/ftH//4K63f+2mX7/sZ2I/7Kd + iP+ynon/sp+L/41vU/+HaUr/iWtO/4ltUv+CbFL/m4Rs/7mkj//FtKP/0MK1/9vRxv/l3db/7ejj//Xz + 8f/5+Pf/k4Fp/4t3X//X19f/v6+i/7Sij/+4p5b/sJqE/6iMcf+njHH/potw/6aKcP+nim//m4Rs/25d + PadENwxOSTwSNkk8Eh1GOhINQjYQBDwyDwEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJPBIBSTwSBkk8 + EhFFOQ8fYFArXJ+NeP/h39L/7u3k/+7s5f/u6+P/7uzk/9PIu/+/rZz/v6yb/8u+rf/m49j/6ebc/+nl + 2v/o49n/5+LX/+fi1v/n4NX/5uDT/+fh1f/e1MX/vquY/7ikkP+4pZH/uKSP/7Whjf+vmYL/rJF2/6qp + o/+l2///pd3//6bd//+l2v7/rKKY/66Uev+umIH/spV6/5ujov9nyf//hM///5nX/v+o3f7/r9/+/6Xc + /v+T1f7/e83//27A9P+mn5X/tJuD/7KdiP+ynYn/sp+M/5N4Xv+GZ0r/iGtP/4ltUv+DbVP/lHxj/7We + iv/CsJ7/zsCy/9nPw//k3NT/7unk//n18v//////nYx2/4VwV//PzMn/wbOm/7WikP+5p5f/rpeB/6eM + cf+njHH/potx/6aKcP+nim//m4Vt/3RjRbZENgpKSTwSM0k8EhtGOhIMQjcQAzwyDwEAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABJPBIBSTwSBUk8Eg5IPBEeSTsSP5iHcP/a1MX/8O3m/+/t5v/u7OX/7uzl/+zp + 4v/k3tT/5N3T/+rm3v/t6eH/6ubc/+nl2//p5dr/6OPY/+ji1//n4db/5uDU/+bf0//n4dT/w7Og/7il + kf+6p5P/uaaS/7ikkP+3oo//sZuE/6yRdv+qqaX/qMje/6fH2/+rp6D/rpV7/66XgP+umIH/sZZ8/4yn + tP9exv//esr+/4jR/v+U1f7/l9b+/5HU/v+Ez/7/ccn//2S/+f+coqL/tpuB/7KdiP+ynYn/tKCL/5uC + af+FZkj/iGtP/4ltUv+DblT/j3le/7SeiP/DsZ7/z8Cy/9nPw//j29T/5N3W/9rSyv/Ataf/h3BW/4x4 + YP/S0M7/xLmv/7WjkP+5p5b/rZZ//6eMcf+njHH/potx/6aKcP+mim//nYVu/3ppTMVDNgpCSTwSL0k8 + EhhGOhIKQjcQAzwyDwEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASTwSBEk8Eg1IPBEcRjgNNpN/ + aOvPyLf/8O/n//Du5//v7eX/7uzk/+7s5P/v7ub/7u3l/+3p4f/r6N//6ubd/+rm3P/p5Nv/6OTZ/+jj + 2P/o4tf/5+HV/+fg1P/p4tb/0cW1/7uolf+7qJX/uqeU/7mmkv+5pZL/t6SQ/7OdiP+uk3n/rJR7/62U + ff+tlHr/rpd//66Xgf+umIH/tJV6/5Sgo/9PwP//acT+/3fJ/v9/zP7/gc3+/33M/v9zx/7/YsL//1i6 + +/+ZoaD/t5yB/7KdiP+ynYn/tKCM/6OKc/+EZEf/iGtO/4ltUf+GblT/iHJY/6iQef+smYP/pZN+/56M + d/+Kdlz/f2lO/39oTP9+Z0v/hnBW/6+jl//W1dT/w7es/7Wjkf+4ppX/q5N6/6eMcf+njHH/potx/6aK + cP+mim//nIRt/3FhQaJENww+STwSKUk8EhRGOhIIQjcQAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAASTwSAkk8EgxJPBEZRzsQMot4XtHIv67/8u/n//Du6P/v7ef/7+3m/+7s5f/u6+T/7erh/+3q + 4P/s6N//6+jf/+vm3v/q593/6uTb/+nk2v/p49n/6OLX/+ji1v/n4db/4NnJ/76rmP+9q5j/vKqX/7yp + lf+6p5T/uKaR/7ikkP+2oYz/sJqD/62Uff+tl3//rpeA/66XgP+umIH/s5d8/56clv9Lt/3/Vr3//2PB + //9pxP7/asX+/2jE/v9gwP//ULz//02y9/+gnpf/tpyD/7KdiP+ynYn/taGN/6qTf/+DZUn/iGpO/4ps + Uf+Hb1T/g21V/4BqUP9/aU//gGhO/4NtUf+KdFv/kHtk/5mIc/+jlIT/taqe/8rGwf/Jw7z/uaiZ/7el + k/+znov/qY50/6iNc/+njHL/potx/6aLcP+ninD/mYFq/2hZNoJEOA04STwSI0k8EhFGOhIFQzcQAQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASTwSAkk8EgpJPBIYSDoQLIJuUrvBt6X/8O/n//Hv + 6P/w7uf/7+3m/+/t5v/u6+X/7uvj/+3q4v/t6uH/7Ojf/+vo3//r597/6ubc/+rl2//p5dr/6OPY/+jj + 1//o4tb/6OLV/8i5qP++q5n/vqya/72rmP+9qpf/u6iU/7qnk/+5ppL/uKOR/7Oeif+umYD/rZeA/66X + gP+umIH/r5iA/7OXfP9lqNL/Nrf//0+4//9Uu///Vbv//1O6//9NuP//NrT//1ip3v+5mn7/sZ2H/7Kd + iP+ynYn/tKGM/6yWgP+HaU3/h2lM/4lsUP+KblL/iXBV/4lwVv+Odlv/k3xl/5qEbv+hjXv/qJmI/7Wl + l/+6rJ7/vK2f/7qpnP+4ppX/uKST/7ekkf+sk3r/qY1y/6iNc/+ojXP/p4tx/6eLcP+kiG7/k35m/Ew+ + FlJHPBAwSTwSHEk8EgxHOxIEQzcQAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASTwSAkk8 + EglJPBIXSDsRJnVhQ6G6rpv/7+3l//Hv6f/w7uj/8O7n/+/t5v/v7Ob/7uzk/+7r4//t6uL/7eng/+zo + 4P/r6N//6+bd/+rm3P/q5dv/6eTZ/+jj2P/o4tf/6eTY/9fNvv++q5n/v66c/76tmv++q5n/vKqX/7uo + lf+6qJT/uaaT/7ilkf+2oo3/spyG/6+Ygv+umID/rpiC/7WXe/+em5P/Qarv/yqx//87sv//QLL//zuy + //8psP//M6r6/52dmP+2nIL/sZ2I/7KdiP+ynYn/s5+K/7Gcif+Td1z/gWNE/4ZoTP+McFX/kndd/5Z9 + ZP+eh3H/p5F8/62ahv+zoI3/tKGP/7WikP+2o5H/tqOS/7ajkf+2opD/s5+L/6yRef+pjnT/qY50/6iN + c/+ojXP/p4tx/6eMcf+fh27/gXBUwUc6DzlJPBEmSTwSFUk8EghHOxICAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAASTwSAkk8EghJPBIVSDsPIWxZOIi1pZP/6efb//Hw7P/x8Or/8e/o//Du + 6P/w7ub/7+3m/+/s5f/u6+T/7uri/+3q4P/s6OD/7Ojf/+vm3v/r5tz/6uTb/+rk2f/p49j/6eXY/+Xd + 0P/GtqT/wK+d/8Gvnf/Arpz/vqya/72rmP+8qZb/uqiV/7mnk/+5ppL/uKSQ/7WhjP+ynYf/r5mE/62Y + gv+3mXr/m5qU/1Cj2P8oqP7/Fqr//yKo//9HpN7/lZ6e/7icgP+xnIf/sZyI/7KdiP+ynYn/sp6J/7Sg + jP+umIP/nYZs/6GJcv+qlH3/sJuG/7Sgjv+3pJL/tqSR/7ejkP+2pJH/tqOR/7Wikf+1oY//s56J/7Kb + hf+ulX7/q452/6qPdv+qj3b/qY50/6iNc/+ojXP/qIxy/6WLb/+Zg23+Xk8raEU5DSZJPBIbSTwSDUk8 + EgRGOhIBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASTwSAUk8EgZJPBISRTgNG1ZG + IGuvoIv/4d/R//Tz7f/y8Or/8e/p//Hv6f/w7uj/8O3m/+/t5v/v6+X/7uvj/+3q4v/t6uD/7Ong/+zo + 3//r593/6ubc/+rl2v/q5Nn/6ePY/+vk2f/VyLr/wK+d/8KxoP/Cr5//wK6c/7+tm/++rJn/vaqX/7yp + lv+7qJX/uaaS/7mlkf+4pJD/taGM/7Oeif+wm4X/tpl9/7CYgP+Zmpf/jpyf/5Wcmv+vm4f/upp//7Gc + hv+xnIf/sZyI/7GdiP+ynYn/sp6J/7Keiv+0n43/t6SS/7ekkP+2pJD/taGP/7Shjv+0oYz/tKCO/7Oe + i/+znIf/sJqD/6+YgP+vln3/rZN5/6uRdv+rkXf/q5B3/6qQdv+qj3b/qY50/6iNc/+pjXP/qYxx/52G + b/96aEuvRzoQKkc6EB9JPBIRSTwSCEk8EgMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAASTwSAUk8EgVJPBIQRTgNGVJCG1ymlYD/29fH//X07//y8ev/8vDq//Hv6f/x7+n/8O7n//Dt + 5v/v7eb/7+zk/+7r4//t6uL/7Ong/+zo4P/s6N7/6+bc/+rl2//q5dr/6ePY/+vl2v/j28//xrin/8Kx + oP/DsaD/wbCe/8Cvnf+/rpv/vqyZ/72rmP+8qpf/uqiU/7qmk/+5ppL/t6SR/7ejkP+2oo3/s5+L/7Sc + hv+4m37/upp9/7ibf/+0m4T/sZuG/7Gchv+xnIf/sZyI/7GdiP+ynYn/sp6J/7Keiv+znor/s5+K/7Of + iv+znon/s52I/7Ochv+xmoL/sZh//7CYfv+wln//r5V8/66Ue/+ulHv/rZN6/6ySef+sknn/q5F3/6qQ + dv+qj3b/qY50/6mOdP+njXL/n4dv/4p4XtNRQxoyRTgOHEk8EhRJPBIJSTwSBEk8EgEAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASTwSAUk8EgVJPBINRTgNF1NFHU6biXPw19LD//Px + 7f/z8e3/8/Ds//Lx6//y8Or/8e/p//Hu6P/w7ub/7+3m/+/s5f/t6uT/7eri/+3p4f/s6N//6+fd/+rm + 3P/q5dv/6ePY/+fi1//q5Nr/1Mi6/8Gxof/Ds6L/wrKh/8Kxn//BsJ7/wK6c/7+tm/+9rJr/vKqX/7yp + lv+7qJX/uaaT/7mlkv+3pJH/tqOP/7aij/+1oY3/s56K/7Gdh/+wm4b/sZuG/7Gchv+xnIf/sZyI/7Kd + iP+0non/tJ6J/7Wfif+1n4j/tZ2H/7Wdhv+0m4T/s5uD/7Oagv+xmoL/sZiA/7CYf/+wln//r5Z9/6+V + ff+ulHz/rZN6/62Tev+sknn/q5F3/6qQd/+skHf/qo90/6OJcP+ahW3/h3Vbx1pLJ0BENwwaSTwSFEk8 + EgtJPBIESTwSAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEk8 + EgNJPBIMRTgOFFJEHT+QfGTd1M2+//Lw6//08+7/8/Ls//Px7P/y8ev/8e/q//Hv6f/x7uj/8O3m//Dt + 5f/v7OT/7eri/+3p4f/r5+D/6+fd/+rl3P/p5Nr/5+LX/+bg1v/m4NT/5NzR/8q8rf/BsJ//wrKi/8Oz + ov/DsqH/wrGi/8KxoP/BsJ7/v62b/72smf+8qpj/uqiV/7ajkP+0oYz/s5+K/7CbiP+vm4X/sJqF/7Gc + hv+ynoj/tJ+J/7agi/+3oYz/t6GL/7ihi/+4oYv/t6CJ/7efiP+2n4j/tZ2G/7Wdhv+0nIX/s5uD/7Oa + g/+ymoL/sZiA/7GYgP+wln//r5Z9/7CWfv+vlX3/rpR7/6+Ve/+rkXn/q5J3/6iOdP+jinL/m4Vt/5SA + avx5Z0qSUEIaJUM2CxJJPBISSTwSCkk8EgRJPBIBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEk8EgNJPBIKRTkOElFEHC+Eb1XJ0Mi4/+7s4//29vH/9PLt//Py + 7f/z8ev/8vDr//Lv6v/x7+n/8O7n//Dt5v/v7OX/7erj/+zp4f/r6N//6eXc/+jj2v/n4df/5eDV/+bf + 1f/l3tP/5d7U/9/Xy//JvK3/wK6f/7yrmv+8q5n/vKqX/7qmlP+2oo7/s56J/7Kdh/+xm4X/sJqE/7Cb + hf+znYf/tqCJ/7iijP+5o4//vaeQ/7ymkP+9ppL/vKWP/7ukjv+7pI7/uqOM/7mii/+5oYv/t6CJ/7ef + iP+2n4j/tZ6G/7Wdhv+0nIX/s5uD/7Oag/+zm4P/spqB/7Sbg/+zmYH/sJd//62Te/+rk3j/qJB4/6KK + cv+hiXL/m4Zw/5aAavKHdFrSemlKkV1OKThFOQ0URjkPEkk8Eg5JPBIISTwSBEk8EgIAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEk8EgJJPBIHSDoREEs/ + FRh5ZkiwycGw/+bj1//08u7/9fTw//Tz7v/08u7/8/Hs//Px6//y8Ov/8e/p//Hu6P/w7+b/7uzl/+7r + 4//s6OD/6eXe/+Xh2P/h29L/3NbJ/9jRw//Uy73/0ci4/9LJuP/PxLP/wbSh/7ikkP+ynYf/sZuD/7Gb + hP+1n4n/uaOO/7umkP++qJP/v6qW/8Gsl//Drpn/wqyX/8Cslf/AqJT/vqiS/72nkf+9ppH/vKWP/7uk + jv+7pI7/uqOM/7mii/+5oYv/t6CJ/7efiP+2n4j/tp+H/7efiP+3nof/tp6G/7SchP+ul3//qpR7/6eO + dv+hinT/nodx/5uGbv+ZhG3/k35n6I57Ysp3ZUigaVg2eWZWNElNQBYXQDQIDEY5DxBJPBIPSTwSCUk8 + EgZJPBICSTwSAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABJPBIFSTwSDUI1CQhrWTeEt6mW/+Pg0v/n5Nr/9PPu//b18f/19PD/9PPu//Ty + 7f/08u3/8fDr/+7r5P/r597/5eDW/97Zzf/W0MD/zcW1/8a8q/+/s6L/uauX/7OjkP+unYn/qpmD/6uW + gv+um4f/tqSP/72nk/+9qpb/wq6a/8SwnP/GsZ7/x7Ke/8Wwnf/Dr5v/w66Z/8GsmP/BrJf/wKqV/7+q + lf+/qZT/vqiS/72nkv+9ppH/vaaQ/7ymkP++pZD/vaaP/7ukjv+6ooz/uKGK/7egif+1nof/r5mB/6qT + ff+nkHr/nohy/5qHb/+Yg2z/kn5n/456YuqIdVzBhHJXmXFfQG9TRx9JVkkhN1VGHiRHOhAJQDQHA0I3 + CghGOw8MSTwSC0k8EglJPBIGSTwSA0k8EgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJPBIDSTwSCEQ4DQtbTCc0kn5l5cvB + sf/i39H/4t/S/+Xi1v/l4db/4t3R/+Hbzv/c1sb/3NTF/9fMvf/Uybj/zL+v/8S0o/+6qZb/rJeC/6GN + df+diHL/n4p0/56JdP+eiXT/nYdy/6CKdf+mkXz/q5eC/7Sfi/+7p5P/wKyY/8Oum//Er5v/xK+b/8Sv + m//Crpr/wq2Y/8GsmP/BrJf/wauW/8CrmP/CrJf/wqyW/8Grlv+/qJP/u6SO/7ehi/+0noj/spyF/6yW + f/+lkXr/o453/56IdP+WgWr7lIBq7415YeB+a1DJfWtOqnhlSHl0YkJeUEMaLkc6EB5JPBEYSDsSEUY5 + DwtEOA0HRTgNB0U4DglIOxELSTwSCUk8EgdJPBIGSTwSA0k8EgJJPBIBSTwSAQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABJPBIBSTwSBUk8EgxDNgoKXk8rT5R/Z+m2p5T/28+//9zPv//WyLj/1ca1/9PEs//TwK//0b2s/8+9 + rP/MuKf/xrSi/7yolP+wnYn/u6yb/8CypP/AsaL/uaeW/6+ah/+nj3f/m4Fn/5uAZP+cg2n/p5J8/7Gd + if+5ppH/v6uX/8Kumv/EsJz/xbGc/8axnf/FsZz/xbCc/8Wvnf/GsJv/vqmU/7mkj/+znYf/rZeC/6eS + fP+jjnj/oIt0/56Icv+Xgmz/kH1l4o15YM+HdFqxcWFAmmlYN3doWDZcZlYzQVhKJCRAMwcHQzYKCUM3 + CwxENwwMRzoQDUk8Eg1JPBELSTwRCkk8EglJPBIGSTwSBUk8EgVJPBIDSTwSAkk8EgFJPBIBAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASTwSAkk8EgZJPBIMQjYJBltMJjeFcVe3oo14/826 + qf/ayLj/1sW0/9TCsf/TwrH/0sCv/9C/rf/Muqn/xLKf/8Gvnf/n4Nv/+/r5//Lv6//i2dD/zb+v/7ym + k/+rknr/noBl/5p8Xf+XeVr/qZJ8/7aijv+8qJT/wayY/8Ovmv/FsZ3/w66a/7qlkP+0n4r/rZmD/6eT + fP+einP/m4dw/5iEbf+SfmX/i3lg34d0WsWBb1Sae2pMgFdJI1ZXSCJHVUchM1VFHiZRQxoTRDgMBEE0 + CQNCNQoFQjcKB0U4DQpJPBIMSTwSCkk8EglJPBIHSTwSBkk8EgRJPBIDSTwSAkk8EgJJPBIBAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEk8 + EgJJPBIFSTwSCkM3DAhOQRgUcmBChJeCa/S7qZX/18e2/9nIuf/Uw7L/0sCv/9C/rv/Mu6n/w7Gd/8e3 + p/////7///////Ds6P/d0sn/y72t/7unlP+rlHz/noNm/5p9X/+afF7/oYt1/6OQe/+ijXn/o496/6OO + eP+bhnH/lYBq+JR/aOyMeWDegG5R0ntqTad5ZkmNdGJFaWpaOUhOQRklRzkQG0k8EhhIOxERSDsRDEU4 + DAZFOA0FRTgNB0U4DghHOg4KSDwRCUk8EglJPBIGSTwSBkk8EgVJPBIDSTwSAkk8EgJJPBIBSTwSAUk8 + EgFJPBIBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJPBIBSTwSBEk8EglHOhANQjUJB2VVMkKMeF/NqZaD/8e1 + o//YyLb/2Me3/9XEs//SwbD/yrim/9C/r//9/Pz///////Ty7v/f1s7/ybys/7mlkv+pkXj/noJm/5p9 + YP+dfmH/hG5W/3RgStp7aE/GdWNGp2pZOI9oWTdsaFc2VGRUMDpYSSMdQzcKB0E2CQhDNgoJQzcMCkQ4 + DQxHOhAMSTwRC0k8EQtJPBEJSTwSCEk8EgdJPBIFSTwSBUk8EgVJPBICSTwSA0k8EgJJPBIBSTwSAQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASTwSAUk8 + EgJJPBIGSDsRC0Q4DQZOQBgZemdKlZaAavyjj3n/rpqG/7ShjP+1oo3/oY54/6iYhf/5+fj/8u7p/9rP + xf/Ht6f/uqeU/7CYgf+kiW//nX5i/5t9YP+df2H/jXhf/1tJK0hZSCYtT0EbFEU3DQVCNQsFQjUKA0I3 + CwdFOA4KSTwSC0k8EgpJPBIJSTwSB0k8EgZJPBIFSTwSBEk8EgNJPBIDSTwSAUk8EgFJPBIBAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJPBIBSTwSBEk8EghFOA4FRTgOB1BCGyN4ZklufWlMn31r + T8F9a07TdWFFr5SCbN/b0sr/4NbO/9THu//JuKn/vaqX/7Kbhf+mjXT/m4Fl/5uBZf+Xf2X0gG1Ul1ZE + IxZVRCESUkIeD09AGgtKPBMISTwSBkk8EgVJPBIESTwSA0k8EgJJPBICSTwSAUk8EgFJPBIBAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASDsSAUc6 + EgJHOxIFRzoRB0U4DwdBNQsFQTUKBEI2CwJENw0FRjgPB2tYOkydi3bAsaCO462divWolYL0o5B785yH + ctSVf2jGi3ddp3NfRHtyXkQ/XUorCllIJgtaSCcIVkUkBVBBHAJKPBQBSDsSAUg7EgEAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARDgQAkQ4EANEOBAFRDgQB0Q4EAhHOxUJSz0ZC00+ + GgNYSCcRW0gnJl1KKzBeTC4vYk8wLWJOMBtiTzISAAAAAAAAAAAAAAAAXkosA15LLARaSCgBU0QiAQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAA/NA8BPzQPAT80DwJBNRECRzoXA0k7GgMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFdH + KgJhTTIBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEU4GAFKPB4BSz0hAUs8 + IAFQQCUBWkgvAVtIMQFaSC4BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////// + /////////////////////////////////////////+f//////////////gD/////////////4AA///// + ///////gAAAf//////////4AAAAP//////////AAAAAH////////+AAAAAAD////////gAAAAAAB//// + ///4AAAAAAAA//////4AAAAAAAAAf////+AAAAAAAAAAf////gAAAAAAAAAAH///AAAAAAAAAAAAH//w + AAAAAAAAAAAAH/+AAAAAAAAAAAAAH/gAAAAAAAAAAAAAH/AAAAAAAAAAAAAAH8AAAAAAAAAAAAAAH8AA + AAAAAAAAAAAAD4AAAAAAAAAAAAAAD4AAAAAAAAAAAAAAD4AAAAAAAAAAAAAADwAAAAAAAAAAAAAADgAA + AAAAAAAAAAAADgAAAAAAAAAAAAAADgAAAAAAAAAAAAAADgAAAAAAAAAAAAAAD4AAAAAAAAAAAAAAD4AA + AAAAAAAAAAAAD4AAAAAAAAAAAAAAD4AAAAAAAAAAAAAAD4AAAAAAAAAAAAAAD4AAAAAAAAAAAAAAD4AA + AAAAAAAAAAAAD4AAAAAAAAAAAAAAD4AAAAAAAAAAAAAAD4AAAAAAAAAAAAAAD4AAAAAAAAAAAAAAB8AA + AAAAAAAAAAAAB8AAAAAAAAAAAAAAB8AAAAAAAAAAAAAAB8AAAAAAAAAAAAAAB8AAAAAAAAAAAAAAB8AA + AAAAAAAAAAAAB8AAAAAAAAAAAAAAB+AAAAAAAAAAAAAAB+AAAAAAAAAAAAAAB+AAAAAAAAAAAAAAB+AA + AAAAAAAAAAAAB+AAAAAAAAAAAAAAB/AAAAAAAAAAAAAAB/AAAAAAAAAAAAAAB/AAAAAAAAAAAAAAB/AA + AAAAAAAAAAAAB/AAAAAAAAAAAAAAB/AAAAAAAAAAAAAAA/AAAAAAAAAAAAAAA/AAAAAAAAAAAAAAA/AA + AAAAAAAAAAAAA/AAAAAAAAAAAAAAA/AAAAAAAAAAAAAAA/gAAAAAAAAAAAAAB/gAAAAAAAAAAAAAB/gA + AAAAAAAAAAAAB/gAAAAAAAAAAAAAD/gAAAAAAAAAAAAAD/gAAAAAAAAAAAAAH/gAAAAAAAAAAAAAH/gA + AAAAAAAAAAAAP/wAAAAAAAAAAAAAf/wAAAAAAAAAAAAA//wAAAAAAAAAAAAB//4AAAAAAAAAAAAH//4A + AAAAAAAAAAAP//4AAAAAAAAAAAD///8AAAAAAAAAAD////+AAAAAAAAAAf/////AAAAAAAAB///////g + AAAAAAD////////4AAAAAD/////////8AAAAH///////////gADh////////////4H+f//////////// + /wD///////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////ygAAABIAAAAkAAAAAEAIAAAAAAAYFQAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAADouCgE7MQoBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAADwwCgE8MgoBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCNg0BQzcNAkI2DQNBNQ0EQTUNB0E1 + DQdBNg0HQTUNBkE1DQRCNw0BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEU4 + DQFFOA0BRTgNAUU4DQJFOA0DRTgNBUU4DQdFOA0JRTgNDEU4DRBFOA0URTgNGUU4DRtFOA0aRTgNFUU4 + DQ5FOA0HRTgNAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARTgNAUU4DQFFOA0CRTgNA0U4DQVFOA0GRTgNCkU4 + DQxFOA0QRTgNFEU4DRhFOA0eRTgNJEU4DSpFOA0zRTgNOkU4DT1FOA07RTgNMUU4DSVFOA0WRTgNCkU4 + DQMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARTgNAQAA + AAAAAAAARTgNAUU4DQNFOA0ERTgNB0U4DQlFOA0MRTgNEEU4DRRFOA0YRTgNH0U4DSRFOA0rRTgNMkU4 + DTlFOA1CRDcLSkM2C1BCNQlZQTQIX0AzBmFANAhfQzcLVkU4DUZFOA0tRTgNGUU4DQtFOA0DAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARTgNAUU4DQFFOA0BRTgNBEU4DQZFOA0IRTgNC0U4 + DQ5FOA0SRTgNGEU4DR5FOA0iRTgNK0U4DTFFOA06RTgNQkU4DUpFOA1TQjUJWD8zBl4/MwZmQjUIcUM2 + C35LPRWQVUchp1xMKLVURSClQzYLfEI1CWVFOA1NRTgNMUU4DRpFOA0LRTgNAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEU4 + DQFFOA0BRTgNA0U4DQRFOA0GRTgNB0U4DQtFOA0ORTgNEUU4DRZFOA0bRTgNIkU4DSlFOA0xRTgNOUU4 + DUNFOA1KRTgMVEM2CllCNQlgQTUIaEA0B3FANAh5TT0WjlRFH6VdTiq4bl0+z3toTeONeF7wn4lv/rCW + f/+hjHH+dWRH2Eo7EY9ANAhqRTgNT0U4DTFFOA0aRTgNC0U4DQIAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEU4DQJFOA0ERTgNBUU4DQhFOA0KRTgNDUU4 + DRJFOA0VRTgNGkU4DSFFOA0oRTgNLUU4DTVFOA09RTgNRUQ3C09CNgpXQjUJX0AzB2g+MgVvQjUJe0k6 + EYxOPhicXk8rtGxbO894ZUnjjHdd8ZmEbP2pk3r/u6KI/8qvlP/Stpn/2Lqb/92/n//bvp3/waaL/35r + T+NIORCQQTQIa0U4DU5FOA0vRTgNF0U4DQlFOA0DAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEU4 + DQFFOA0CRTgNA0U4DQVFOA0HRTgNCUU4DQxFOA0RRTgNFUU4DRtFOA0hRTgNJkU4DS5FOA02RzgOPkU4 + DUdENwxNQzYKVEI1CVtANAhiQDMHakM2C3hHOQ6JTT4XmVxNKLNmVTXJdmRI3Yl1Wu+ZhGv+p5F6/7ig + hv/GrpP/zrWZ/9m+of/dwqT/3cGi/9zAoP/bvp//2r2c/9m8nP/bvZz/3b2d/62Tev97aU3kSjoQjkA0 + CGdFOA1KRTgNKUU4DRJFOA0FRTgNAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABFOA0BRTgNAkU4DQNFOA0FRTgNBkU4DQpFOA0MRTgNEEU4 + DRRFOA0ZRTgNH0U4DSVFOA0tRTgNNUU4DT1FOA1GRTgNTkU4DVdCNQldPzMGYj8yBmlDNgt2RTgNg00/ + F5VaSyauZFMxxnVjRNeFcVfslIBn+6aSev+2n4j/w62T/8+3m//YwKT/2sKk/9/FqP/hxaj/3MOk/9m/ + of/YvZ//2L2f/9i8nf/YvJ3/2Lyb/9i7m//Yu5v/2bqb/7eYff+dhGz/dmZI2UQ4DIVDNgpgRTgNPkU4 + DR1FOA0KRTgNAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARTgNAUU4 + DQFFOA0DRTgNBUU4DQZFOA0JRTgNC0U4DQ9FOA0URTgNGEU4DR1FOA0jRTgNKkU4DTFFOA06RTgMQkQ3 + DExDNwtUQzYKXkE1CWRBNAhtQDMHdEE1CH9PQBmVVkchqmJSLr50YkPYgW1S7JF9ZPSikHb/tJ6H/8Gs + lP/OuZ//18Gn/9rFqv/fx6z/38es/93Fqf/bw6f/28Om/9nAo//Yv6L/2L+h/9i+of/YvqD/2L2f/9i8 + nv/YvJ3/2Lyd/9i7m//Yu5v/2Lub/7eafv+ih2z/noZt/3VjRdVCNgp2RTgMUEU4DStFOA0RRTgNBQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARTgNAkU4DQJFOA0GRTgNCEU4DQxFOA0PRTgNE0U4 + DRhFOA0dRTgNI0U4DSpFOA0wRTgNOUU4DUFFOA5KRDcLUUE0CFZANAhdQDQHaEA0B3JDNwuASzwUk1BA + G6ZhUCy7b10+039rUOuRfWP4n4x1/7Kdhv+/qpT/zbqj/9bDrP/cx7D/4cy0/+HKsf/fya//3Met/9vF + qv/Zw6j/2cOn/9nCpv/ZwaX/2cGl/9nAo//ZwKP/2L+h/9i+of/YvqD/2L2f/9i9nv/YvJ3/2Lyd/9i7 + m//Yu5v/2Lub/7aaff+hhWn/pIhs/52Fbv9oWDa5QTMIWEQ3DTZFOA0XRTgNBgAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAEQ3DQFFOA0ERTgNCUU4DQ9FOA0VRTgNHUU4DSNFOA0qRTgNMUU4DTlFOA1BRTgNSUU4 + DVFFOA1aQzYKYkAzB2U+MgVsRTgMe0s8FY1TQx6hYFEsuWtZONF6Z0rfjXth8J6Lcv+tm4T/v6yW/8q4 + ov/SwKn/3cu0/+DNt//fzLb/38y0/93Ksv/bx6//2sat/9rFrP/axar/2sSp/9nEqf/Zw6j/2cOn/9nC + pv/Zwqb/2cGl/9nApP/ZwKP/2b+i/9i/of/YvqD/2L6g/9i9nv/YvJ7/2Lyd/9i7nP/Yu5v/2Lub/7ib + f/+ghGn/o4hr/6WJb/+NeF/wTT0Wc0E0CDdFOA0aRTgNBwAAAAAAAAAAAAAAAAAAAAAAAAAAQDQLAUQ3 + DQVFOA0NRTgNGUU4DSdFOA00RTgNP0U4DEhDNgtQQzYKWEE0CV9ANAdnQDQIcEM2C3xDNguHT0AYml9P + K7dqWDbOe2hL4Yh1XPKahm76rZmE/72slv/LuqT/1MWw/9vMt//f0Lr/4tK8/+LRu//gzrj/3Muz/9rJ + sv/ayLH/2siw/9rHr//ax67/2sat/9zIsP/fyrD/4suy/+HLsf/gybD/38it/9vEqP/Zwqb/2cGk/9nA + pP/ZwKP/2b+i/9i/of/YvqD/2L6g/9i9nv/YvZ7/2Lyc/9i7nP/Yu5v/2r2d/76ghP+ghWr/o4hs/6WI + bP+chGn+XlArkz80BzlFOA0eRTgNCUM2DQEAAAAAAAAAAAAAAAAAAAAAPzQLAkQ3DQxFOA0cRTgNM0M2 + C0dBNAhXPzMGYUA0CG1CNQl6RTgNiFBBGpxXRSCvZVMyxHpmSt6Hc1nzmYdu/qeWgP+5pZH/xrei/9XI + tf/f0b3/4NK+/+LTwf/h07//39C8/93Puv/dzrj/28y2/9vLtf/byrT/28qz/9vJsv/ayLH/2six/9rG + rv/byLD/4s20/9nFrf/Hspj/uaGG/7Kafv+6oof/y7WZ/93Gqv/gyK3/2sKk/9nApP/ZwKP/2b+i/9i/ + of/YvqH/2L6g/9i9n//YvZ7/2Lyc/9i7nP/Yu5v/2r2d/76hhP+ghWr/o4hs/6SIa/+fhWz/alo4qkA0 + Bz9ENwwhRTgNC0M2DQIAAAAAAAAAAAAAAAAAAAAAQDQLB0Q3DRVFOA0vQTQIR0c5DmxRQRuUWEgirmRT + MsNzYULbgm5T6paDa/eoloH/uKeU/8S2ov/RxbL/2M67/9/Uwv/l2sj/4tbD/9/SwP/c0Lz/3M+7/9zO + uv/bzrn/2825/9vMt//bzLf/28y1/9vLtf/by7T/28qz/9vJsv/aybL/2six/93Ls//dy7P/vKaM/5J6 + Xf+CaU3/h3BX/4p2Xv+FblL/hGpN/5iAYv/FrpL/38aq/9vDpv/ZwKP/2cCi/9i/ov/YvqH/2L6g/9i9 + n//YvZ7/2L2e/9i8nP/Yu5z/276d/72gg/+ghWr/o4ht/6SIbP+fhmz/aFg4rUAzB0ZENwwnRTgNDkM2 + DQMAAAAAAAAAAAAAAAA4LQkBQDQLDEM2DB9BNAg5XUwmkIFtUeSUgGj2oY94/7Wkkv/Guqj/0si3/9nQ + v//g2Mf/49rJ/+PayP/j2cf/4dfF/93Uwf/b0L7/3NC9/9zQvf/c0Lz/3M+7/9zPu//czrr/2865/9vN + t//bzLf/28y1/9vLtf/by7X/28qz/9vJs//ayLH/3cy1/9rIsP+ijHD/f2VJ/5aCbf/BuK3/1tXQ/+Dd + 3f/b2tf/xL20/5SCbP+AZ0r/r5d8/9zEp//bwqX/2b+i/9i/ov/Yv6H/2L6h/9i9n//YvZ7/2L2d/9i8 + nP/Yu5v/3L+f/8OliP+ghWr/o4ht/6SIa/+ghmz/aFg2r0AzB0tENwwqRTgNEEU4CwMAAAAAAAAAAAIZ + LgE4LQkCQDQLDj8zCB5aSiRxopB7+c3Es//a0sP/493N/+Tdzv/i283/4drL/+DZyP/g18b/39XE/93U + wv/d08L/3dPB/9zSwP/c0r//3NG//9zQvf/c0L3/3M+7/9zPu//czrr/2865/9vNuP/bzLf/28y3/9vL + tf/by7X/28qz/9vKs//cy7T/3Muz/5+Jbf99ZUj/s6aW/93Z1v/b1tL/y8G2/7ysm/+5p5b/xrqv/9LL + xP+uoJH/gWpO/6+Vev/gxqn/2cCj/9m/ov/Yv6H/2L6h/9i9n//YvZ//2L2d/9i8nf/Yu5v/3cCf/8Wo + iv+ghWr/pIht/6SIa/+hiG7/bl09vUAzB09ENwwsRTgNEEc4CwMAAAAAAAAAAAMZLQE4LQkDQTQLDzwv + BBpxXz+gz8a2/+nn2f/i283/39jJ/93XyP/f2cn/39jI/93Vxf/d1cX/3dXD/93Uw//d08L/3dPB/9zS + wP/c0r//3NG//9zQvf/c0L3/3NC7/9zPu//czrr/3M65/9vNuP/bzbf/28y3/9vLtv/by7X/28q0/9vK + tP/h0br/taGI/3xkSP+xopH/19DL/8a6rv+tl4H/n4Vq/5Z4Wv+RcVP/k3RV/5l8X/+1oY//oY97/4Fo + Tf/Ap4v/4Mao/9m/ov/Yv6H/2L+h/9i+oP/YvZ//2L2d/9i8nf/Yu5z/3cCg/8Sniv+ghWr/pIht/6SI + a/+iiG//cGBBxUAzB1BENwwtRTgNEUc4CwMAAAAAAAAAAAMZLQE4LQkCQTQLDT0wBBdvXTydzMKz/+Tg + 0f/f2Mn/39jJ/+Hbzf/Z0sD/2dLA/+HZyf/d1cX/3dXD/93Uw//d08L/3dPC/9zSwP/c0sD/3NK+/9zR + vv/c0L3/3NC8/9zPu//czrr/3M66/9vNuP/bzbj/28y2/9vMtv/by7X/28q0/9/Nt//Twqr/iHBV/5qI + cv/Qx77/w7Wn/7Ocif+slX3/p5B3/6KHbP+bfmL/mXxe/5Z3Wv+Vdln/nIFl/4dvVP+UfWD/2L6i/9vC + pf/Yv6L/2L+h/9i+oP/YvZ//2L2f/9i8nf/Yu5z/3L+g/8epjP+ihmv/o4hs/6SIa/+jiW7/cF8/wj8z + B1FENwwtRTgNEUQ2DQMAAAAAAAAAAAAAAAA5LgkBQDQLCz4yBhVnVTKKwbWj/+bi1P/f2Mr/4t3O/8q9 + qP+qknv/qJF3/8y/rP/h2cn/3dXE/93Uw//d1ML/3dPC/9zSwP/c0sD/3NK+/9zRvv/c0L3/3NC8/9zP + u//czrr/3M66/9vNuP/bzbj/2822/9vMtv/by7X/28q0/+HQuv+0n4b/gmlP/7qqnf/IvbH/wLCe/7mm + lP+3o4//qZN9/5Z+ZP+Ocln/jnBV/5V2Wv+ZfF7/mHpc/5Z4XP+GbVH/vqSJ/+DFqP/Yv6L/2L+h/9i+ + oP/YvZ//2L2f/9i8nf/Yu5z/3L6f/8yvj/+jiG3/o4ds/6SHa/+kiW7/cmFBxT8zB1FENwwtRTgNEUM2 + DQMAAAAAAAAAAAAAAAAAAAAAPzQLCj8yBhRfTSlyt6mW/uXi0//g2sz/4dzN/6+ZgP/Wzcb/vayc/7Oe + hv/h2sn/3dXE/93Uw//d1ML/3dPC/9zTwf/c0sD/3NK//9zRvv/c0b7/3NC8/9zPvP/cz7v/3M66/9vN + uf/bzbj/2823/9vMtv/bzLb/28q0/+DOuP+XgWT/kn1k/8S2qP/Mv7P/xrip/8Kyof+wnIj/i3BZ/4Fm + T/+BZU3/hmxW/4htVf+RdFb/mXtf/5p7Xv+Lb1P/pI1x/93Dpv/ZwKP/2L+i/9i+oP/YvqD/2L2f/9i8 + nv/Yu53/3L6f/8qvj/+jiG3/o4dt/6OHa/+kinD/d2VHzT80B1JENwwsRTgNEUM2DQMAAAAAAAAAAAAA + AAA9MgoBPzQLCEEzCRJNPhZVqpyH+ePf0P/g2sz/4t3P/7Sfhv/Yz8f/xriq/6+Yf//g2cn/3dXF/93V + xP/d1MP/3dTC/9zTwf/c0sD/3NLA/9zRvv/c0b7/3NC8/9zPvP/cz7v/3M66/9vOuf/bzbj/2824/9vM + tv/bzLX/3c23/9XDrP+MdVj/nYhy/8u+sv/UysD/zMC0/8Oyo/+OdF3/gGRM/4JlTf+Xg27/u7Gm/7mw + pP+Ufmb/knRW/5t9YP+SdVn/ln5i/9a9oP/cwqX/2L+i/9i+oP/YvqD/2L2e/9i9nv/YvJ3/3L+f/8qu + j/+kh23/o4ht/6OHa/+kiXD/d2VHyz8zB1JENwwsRTgNEUM2DQMAAAAAAAAAAAAAAAAAAAAAPzQLBkE0 + CRBFNw1Dn4947OLczv/g28z/5uLU/7qmkP/JvK7/zMC0/6mSd//d1cX/3dXF/93VxP/d1MP/3dTC/9zT + wf/c0sD/3NLA/9zRvv/c0b7/3NC8/9zQvP/cz7v/3M+7/9vOuf/bzbj/2824/9vMtv/by7X/4M+6/828 + o/+Ib1T/pI96/9XMwv/Y0cr/0si9/7Gdjf+AY0v/g2hP/4duVf+8s6j/1tLN/+Dd2v/Eu7L/kHRa/5d6 + W/+Wd1v/jXNZ/9G4nP/dw6b/2L+i/9i+of/YvqD/2L6g/9i9nv/YvJ3/276e/9C0lf+ojHD/oohs/6KH + a/+ni3H/eGZHzD8zB1JENwwsRTgNEUM2DQMAAAAAAAAAAAAAAAAAAAAAPzQLBEE1CQ5HOA44k4Fp2N3Y + y//i287/4+HS/8KznP+/r5//0Ma8/6ePdf/Vy7n/4NjI/93VxP/d1MP/3dTD/93Twf/c08H/3NK//9zR + v//c0b7/3NC9/9zQvP/cz7v/3M+7/9vOuf/bzrn/2823/9vMt//by7X/4M+6/828o/+HblL/pI94/9vV + zf/d1tD/1szC/5+Ldv+BZU7/gGRL/5WCbP/MxsD/4t3Y//Hx7v/k4d//nIVw/5NzVf+XeFz/kXZb/9G4 + nP/dxKb/2L+i/9i/of/YvqD/2L6g/9i9n//YvZ7/27+f/9C0lf+njXD/o4hs/6SHbP+kiW7/hHBU2Eg6 + EFpDNworRTgNEUM2DQMAAAAAAAAAAAAAAAAAAAAAQTULA0I1Cg1FNw0thnJYxtvUxv/i3dD/4t/Q/8e6 + pf+3o5D/08vB/6aPdf/Nwq3/4tvM/93UxP/d1MP/3dTD/93Twf/c08H/3NK//9zRv//c0b7/3NC9/9zQ + vP/cz7z/3M+7/9zOuv/bzrn/2823/9vMt//by7b/4NC6/8y7o/+HblL/oIx0/9zWz//g2dT/1s7D/56K + dP+CZU3/f2NK/5mGc//QzMb/5+Tf//v5+v/t6un/pZF//5JyVf+WeFz/kHZb/9C4m//dxKb/2L+i/9i/ + of/YvqH/2L6f/9i9n//YvZ3/27+f/8+zlP+njHH/o4ht/6SHbP+jiW7/h3JX2ko8FFxDNgorRTgNEUM2 + DQMAAAAAAAAAAAAAAAAAAAAAQTULA0M2Cw1CNQoheGZJstPMvf/k4dP/4tzO/9HItv+wmoX/0ce9/6eQ + eP/Ft6H/5N3O/9zUw//d1MP/3dTD/93Twv/d08H/3NPB/9zSv//c0b//3NG9/9zQvf/cz7z/3M+7/9zO + uv/bzrn/2825/9vMt//bzLb/38+5/9PDrP+LcVb/mYNq/9nSyv/g2NL/1szE/6GMd/+BZU3/gWRL/5N/ + af/Iwrv/3NfT/+rn5f/i39v/oY14/5JzVf+WeFz/lHpe/9K6nv/dxKf/2b+j/9i/of/YvqH/2L6f/9i9 + n//YvZ7/2r6f/9S3mP+pjnL/o4hs/6SIbP+lim//hnFW2Ug6EV1DNgotRTgNEkM2DQMAAAAAAAAAAAAA + AAAAAAAAQTULA0Q3DQw+MgQXZ1YzncvBsv/m49b/4dvN/9nTwv+umIL/zcG1/6yVgP+9rZb/5N/O/9zU + xf/d1cT/3dTD/93Twv/d08H/3NPB/9zSv//c0b//3NG9/9zQvf/c0Lz/3M+8/9zOuv/czrn/2865/9vN + t//bzLf/28y2/9/Ouf+Vf2T/iW9U/8zAs//d1c//1Mm//7Gejf9/ZEv/hGlQ/4ZtVf+2rJ//zsnD/9XR + y//JxLz/lHxj/5V2WP+UdVr/noVp/9e/ov/bw6b/2b+i/9i/ov/Yv6H/2L2g/9i9n//YvZ7/2b2e/9a6 + mv+sj3T/oodr/6SIbP+lim7/i3Vb40s+FmdDNgovRTgNFEM3DQYAAAAAAAAAAAAAAAAAAAAAQTULAUQ3 + DQo/MgUTYlIuiMG1pP/n5dj/4t3P/9/YyP+0n4j/x7qs/7Kdif+0n4f/4tvL/9/Wxv/d1cT/3dTD/93T + wv/d08L/3dPA/9zSwP/c0r//3NG+/9zQvf/c0Lz/3M+8/9zOuv/czrr/2864/9vNuP/bzLf/28y2/+HQ + vP+wm4T/f2RI/7Sfjf/Xzsb/zcK2/8O1pP+OdF//gWVN/4JmTf+Sfmn/t66j/7+5sf+ejHv/kXRX/5p8 + X/+Pclb/sJZ8/9/GrP/ZwKT/2cCj/9i/ov/Yv6H/2L6h/9i9n//YvZ//2b6e/9W5mv+sj3T/oods/6OI + bP+kiW3/jnhf7VBAGXJCNgo0RTgNGEM3DQYAAAAAAAAAAAAAAAAAAAAAAAAAAEQ3DQhANAcRXEsmcran + lPvq6Nv/4t/R/+Lczv+4pZD/w7Sj/7eikP+tl37/4NfH/9/Xx//d1cT/3dXE/93Uwv/d08L/3dPA/9zS + wP/c0r//3NG+/9zQvf/c0Lz/3M+8/9zOuv/czrr/2864/9vNuP/bzbf/28y2/+DPuv/Pvqf/h29U/5F3 + Xf/Ju67/yr2w/8S1pP+xnIn/iG5W/4FmTv+AZU3/h25Y/4tzXf+PcVf/mHte/5d4Xf+QdVr/ybKX/9/G + qv/ZwKT/2cCj/9i/ov/Yv6H/2L+h/9i9n//YvZ//2b6e/9a6nP+tkHX/oods/6OJbP+kiW3/jnhe608/ + GXZCNQo6RTgNHEM2DQgAAAAAAAAAAAAAAAAAAAAAQjYMAUQ3DQhCNAkSV0UgXaqch/Hp5tj/4+DS/+Xh + 0/+/r5n/vaya/7yqmP+okXf/3NXF/+DZyP/d1cT/3dXE/93Uw//d08L/3dPB/9zSwP/c0sD/3NG+/9zR + vv/c0L3/3NC8/9zPu//czrr/3M66/9vNuP/bzbj/28y2/9zMt//i0bv/rpl//31jR/+ii3L/xLWk/76t + m/+4pJD/qJJ9/5V8ZP+NcVn/i29U/5J0V/+ZfF7/mXxf/41wVP+pkHX/38es/9rCpv/ZwaT/2cCk/9m/ + ov/Yv6L/2L+g/9i+oP/YvZ//2L2d/9u/oP+vk3f/oYZr/6SJbP+liWz/kXpg709AGnxCNgo+RTgNHkM2 + DQgAAAAAAAAAAAAAAAAAAAAAQjYMAUQ3DQdDNgoPSTkPQ5yNdefl4dP/5uHV/+fk1//Iu6f/uKaR/8Cw + nf+nj3X/2c+//+HZy//d1cT/3dXE/93Uw//d1ML/3dTD/93Twf/c0sD/3NG+/9zRvv/c0L3/3NC8/9zP + u//czrr/3M66/9vNuP/bzbj/28y2/9vMtv/g0Ln/2smy/5V/ZP9+Y0f/oYpx/7mlkv+znYn/rJR+/6SL + cP+bf2L/mXxf/5p9X/+afF//j3BU/5R7X//VvaL/3MWp/9nBpf/ZwaT/2cCk/9m/ov/Yv6L/2L+g/9i+ + oP/YvZ//2L2f/9u/oP+vk3f/oYZr/6SIbf+kiG3/lX5l/FNEHYZCNQk/RTgNH0M2DQkAAAAAAAAAAAAA + AAAAAAAAAAAAAEQ3DQVDNgsOQjQIM5CAZt3g2s3/5+TZ/+fk2P/QxLT/uKWQ/8GxoP+oknr/08e1/+Lb + zP/d1cT/3dXE/93Uw//d1MP/4NXE/+DWxP/h18X/3dK//9zRvv/c0L3/3NC9/9zPu//cz7v/3M66/9vN + uP/bzbj/28y3/9vMtv/by7X/4c+6/9LAqP+TfWL/fmNI/5N7X/+mjnb/poxy/5+DZ/+ZfV//mXxf/5V3 + XP+JbVH/kHdc/8mzmP/fyK3/2cKm/9nBpf/ZwaT/2cCk/9nAo//Yv6L/2L+i/9i+oP/YvqD/2L2f/9u/ + oP+wlHj/oYZr/6SIbf+kiG3/lYBl+1NDHYdCNQk/RTgNH0M2DQkAAAAAAAAAAAAAAAAAAAAAAAAAAEQ3 + DQRDNgoORDYLKoZzWMrb1Mf/6efc/+jl2f/Wzr//uaSR/8Kyov+slH7/zL+t/+Tf0P/d1sb/3dXE/9/V + xP/h18b/zLyo/7qljv/Pwa7/39PB/+HVwv/d0r//3NC8/9zPu//cz7v/3M65/9vOuf/bzbj/2823/9vM + tv/by7X/28q0/+HQuf/Vxa3/p5F3/4RsUf+Cak7/inBV/4twVf+Kb1P/hm1R/4duVP+gim//z7ug/9/I + rv/Zw6j/2cKm/9nCpv/ZwaX/2cGk/9nAo//Zv6L/2L+i/9i+oP/YvqD/2L2f/9vAoP+2mX7/oods/6SI + bP+liW3/mIBm+1JDHYZCNQk/RTgNH0M2DQkAAAAAAAAAAAAAAAAAAAAAAAAAAEQ3DQJDNgsMQzcLInpm + SLXVzsH/6und/+jl2v/d1sr/uKaS/8Gxof+uloD/xbej/+Xh0v/g2Mj/3dXF/9/VxP/i2Mf/v62W/6CF + a/+mj3X/tZ+J/8u8pv/cz7z/4tXC/+DSv//d0Lz/3M+7/9vOuf/bzbj/2823/9vMt//by7b/28u1/9rK + s//gz7j/4M64/8y6of+vm4L/m4Rp/5R+Y/+ahGj/qpV7/8eyl//dyK//38mw/9nDqP/Zw6j/2cKm/9nC + pv/ZwaX/2cGk/9nAo//ZwKP/2L+h/9i+of/YvqD/2L2f/9u/oP+3m3//ooZs/6SJbf+kiGz/moJp/lRF + II1BNQg+RTgNH0M2DQkAAAAAAAAAAAAAAAAAAAAAAAAAAEQ3DQJENwwMQjUJFm1cOpvMw7T/6+nd/+jm + 2v/l4dX/vqyY/8Gvn/+xmoX/wbCc/+Xh0//h2sv/4NjI/93UxP/i2cj/x7eh/6SKcP+ojnX/po50/6WO + dP+ym4T/xbSe/9fKt//g07//4dK+/93QvP/cz7r/28y4/9vLt//bzLb/28u1/9vKtP/bybP/28qz/9/N + tv/fzbb/38y0/9/Ls//gy7P/4Muy/9/JsP/bxq3/2cOp/9nEqf/aw6j/2sSo/9vDp//bw6f/28Om/9zC + pP/cwqX/3MGi/9rAo//Zv6D/2b+f/9vAof+3m4D/ooZr/6SIbf+kh2z/nIRr/1VHIZBBNQg+RTgNH0M2 + DQkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABHOQ4LPjIFDlxMJ4LCt6X/6+jc/+nm2//n5Nj/xLSh/8Gv + nf+1n4z/vamW/+Tf0P/i3M7/4dnL/9/Xxv/j2sn/zr+s/6WNc/+okHb/qZF4/6mSev+nj3X/po51/66Y + gP+/qpT/z72o/9rLtv/cz7n/3dC7/+HRvP/g0Lr/38+5/9/Nt//fzbf/3820/9zMtf/cy7T/3Muz/93K + sf/dybH/3cmx/93Ir//fya//3cit/9vGrP/axKn/2sOn/9jBpP/TvKL/0Lqf/822nf/Ks5v/yLGY/8Ww + mP/CrJf/wq6X/8KumP+xmYD/pIhs/6OIbf+kiWz/noZs/1REH41ANQg+RTgNH0M2DQkAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABHOQ4JPzIGD1lKJG22p5X/6+jd/+ro3//q6N3/ybyq/7+unf+4pJH/uaSR/+Lb + zv/k3dH/4trM/+HZyv/j28v/08e1/6qReP+njnX/qZF3/6mSev+qknr/qpN7/6iRd/+nj3b/qpN8/7Ca + g/+5o4z/wq+Y/8i3of/Mu6b/0L6o/9TCrP/Uwqz/1MKq/9PBqv/Uwan/1MGp/9TBqf/Sv6b/z7ui/8+7 + o//Nt5//yrWc/8Swmf+/qpX/uqaR/7ijj/+2oY//taGO/7Sfjv+znoz/sZ6M/7Kfjv+zn47/s6GR/7Wj + k/+vloH/pIhs/6SIbf+liGz/noZs/11NKZZBNAg+RTgNH0M2DQkAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABHOA4HPzMHD1ZHIFqomIT46+nf/+ro3//s6uL/z8O1/7+tm/+8qZb/tZ+K/+DZzP/m4dP/49zN/+La + y//j28z/39XF/7Gagf+mjXP/qZF3/6mSev+pknr/qpN7/6qTe/+qlHz/qpN8/6mTe/+qknv/qJJ7/6iR + ev+slH7/rZeB/7GahP+xm4X/sZuG/7Gbhv+ynIb/spyH/7KdiP+ynIf/sJqG/7Cbh/+ynIn/sp2K/7Ke + i/+zno3/sp6M/7Gcif+wm4j/r5yJ/7Gejf+2ppj/vrSp/8rEv//AtKf/tKGO/7ellP+vloH/pIht/6SI + bf+liGz/noVr/2paOKNBNAk+RTgNH0M2DQkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABFOA4GQDQIEVJC + G0WdjHXs6OXZ/+vp4P/u7OT/2M7B/7+tm/++rpv/s52J/9zVx//n4tb/5d3P/+Lczf/i2sz/5d/P/72q + lf+mjXH/qJB4/6mSev+pknr/qpN7/6qTe/+qk3v/qo50/6iPc/+tk3z/rZZ//62WgP+uloD/rZaA/62X + gf+ul4H/rpiC/66Ygv+vmYP/r5mE/6+ahf+wmob/sJuH/7Kdiv+vmYX/qJF8/6KKcv+ehW3/moJr/5uE + bf+giXX/ppOD/7GilP+5rqL/xL63/9HPzf/Kw7z/taGQ/7ekk/+vloH/pIht/6SJbf+liWz/oIds/2dY + NqFBNAc+RTgNH0M2DQkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABFOA0FQzcLEUM1Ci6PfmXg4dvQ/+7r + 4//t7OT/3dfM/8Kwn//BsZ//tqCM/9bNv//o5Nn/5d/R/+Tdz//k3M7/5d/R/87Ar/+qknv/qZF3/6mS + eP+pknr/qpN7/6qRd/+qk33/tbSu/7u4sv+ul4L/rJN7/62WgP+tloD/rpeB/7CVfP+xlHv/rpeB/7CW + fv+yln3/sJqE/7Cbhv+xm4b/sp6J/62XgP+LbVH/hGZI/4ZpTf+KbVL/jnNa/5N7Yv+Vf2j/lH5p/5B7 + ZP+Ic1r/k4Br/8S/uf/Nx8L/tqKQ/7akkv+vloH/pYlt/6SJbf+liW3/oYdt/2dYN6RBNAhBRTgNIkM3 + DQo9MgsBAAAAAAAAAAAAAAAAAAAAAAAAAABFOA0CRTgNED0wAyKDcVbM2tPG/+/u5v/t6+P/5eDU/8W0 + pP/Es6L/t6KP/9HHt//q5tr/5eDS/+Xf0P/k3c//5t/R/9rQwf+znYj/r5d//6mRdv+pknr/qpJ7/6iP + dP+uvML/0vL///H////P1NP/qpJ9/6yUff+tl4D/sJZ8/6qYhv+bs7r/mMPY/5q9yv+mo5z/s5d9/7Cb + hf+xm4b/tJ6K/6SMdf+CYkT/hWVJ/4lrT/+IblT/g2xS/4FqUP+CalD/i3Rc/5qIcf+snYr/i3Vc/56R + f//Py8f/tqOR/7ajkv+vloD/pYlt/6SJbf+liW3/oYdt/3FhQblBNAhHRTgNJUM3DQw9MgsCAAAAAAAA + AAAAAAAAAAAAAAAAAABFOA0BRTgNDT8zBh57Z0uy0ci7//Lx6f/t7OP/6ubd/8m4qP/GtqT/uKSR/8u+ + rv/s6d3/5+LV/+bh0//m39L/5d/R/+LazP+/rZj/s52H/7CZgv+okXj/qpF4/6iTff+s0ev/z+3//+z4 + ///W7vj/r6WZ/6qRd/+wlHv/rJiF/4rA3P+S3P//qeP//6Hi//+L0fb/nqiq/7OXfv+xm4X/sp2J/6yW + gf+FZkr/hmdL/4ZrT/+Ca1H/lX9m/62Zhf/Ftqf/2dDF/+/r5v//////uayc/4t4Yf/QzMf/tqOS/7aj + kv+vloD/pYlt/6SJbf+liW3/oohu/3NiQrxBNAhKRTgNKEM3DQ89MQsDAAAAAAAAAAAAAAAAAAAAAAAA + AABFOA0BRTgNDEAyBxpuXDuXysGy//Ly6v/t6+P/7uzk/8q9rf/DsqH/uKSR/8u+sP/s6uD/6OLW/+bh + 1P/m4NP/5t3R/+ji1P/KvKn/tJ6J/7eijv+xmYP/qpF4/6iSeP+ky+T/suP//7/n//+24/z/rKWb/66S + dv+xk3X/kKy6/3zT//+j2///v+f+/7fi/v+Q2P//fMXx/6qbjP+zmYH/sZyH/7Cbh/+Ka0//hWZI/4Zo + Tf+EbFL/rJR+/8e2pP/Xy7//5t3U//Dr5v//////x72x/4dyWv/Oy8f/t6WU/7Wjkf+ulX//pYlt/6SJ + bf+liG3/oohu/3NhQrpBNAhKRTgNKEM3DQ89MQsDAAAAAAAAAAAAAAAAAAAAAAAAAABFOA0BRTgNCkA0 + CBZhUCx9wbel//Dv5//v7OX/8O7m/9zUyf/FtaT/yrus/+Pd0v/q6N3/6eTZ/+fi1v/n4dX/5+DT/+ji + 1f/XzL3/uKOP/7eijv+3o4//spyH/6yRdf+nqqf/o9j4/6Ld//+lxNf/rJV//66Tev+ulHz/eLbX/3bQ + //+Z1v7/qd3+/6Tb/v+M0v//asf//5Wkqv+1mH7/sZuH/7Gdif+Qc1n/hGVI/4ZpTv+Da1H/o4xz/8Ov + nP/Sxbj/5dvT//Pu6v/9/f3/xryw/4JtU//Jw77/uqmY/7aikf+sk3z/pYlt/6SJbv+liG3/oohu/3pn + S8hBMwdGRTgNJkM3DQ09MgsCAAAAAAAAAAAAAAAAAAAAAAAAAABFOA0BRTgNCUA0CBJQQBlluKmW/+/s + 5P/x7+j/7uzk/+7s5f/s6eD/7enh/+3p4f/q5tv/6eXa/+jk1//o49b/5+LU/+ji1f/i2c3/vq2Z/7ij + j/+4pZH/uKOP/7Seif+uk3j/qaKY/6isqv+qmIP/rZR7/6+Vff+ulX7/a7PZ/2TI//+Azf7/itD+/4fQ + /v92yv//XMH//4mmtf+3mX3/sZuH/7Oeiv+YfWL/gmJE/4ZqTv+Bak//nIVr/7qlkf+8rZv/uaqb/7Ch + kP+llIH/iHJY/5WEcP/Rzcv/u6yc/7aikP+qkXj/pYpt/6SJbv+liG3/oohu/3poS8RBNAg+RTgNIEM3 + DQo9MgsBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARTgNBkE1CBBPPxhVrJuH9e3q4P/y8Ov/7+3m/+7s + 5f/v7eX/7uvi/+zp3//r59//6+fd/+nl2v/p5Nn/6eLX/+ji1v/o4tX/zL+t/7mlkf+7p5T/uqaS/7ik + kf+2oYz/sZZ8/62Ocv+sk3j/rZV+/66Vff+0k3f/bajM/0q///9lwv//a8X+/2rE/v9ewP//RLj//4qh + rf+3mX7/sZuH/7WgjP+ehG7/gWFD/4hqTv+Ea1H/g2xU/4ZvVv+DbFL/gWpQ/4FqUP+Ldl//nY17/8G6 + s//Iwbr/t6WV/7Oei/+njXL/pYpv/6SJbv+liW3/oodu/29ePaJANAgyRTgNGkM2DQcAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAARTgNBUI1Cg9NPBVGno525Oro3f/z8uv/7+3n/+/t5v/u6+X/7uvi/+3q + 4f/s6N//6+jf/+rm2//q5dr/6OTY/+jj1v/r5dj/2tDB/72pl/+8qZf/vKmW/7qmk/+5pZL/uKSR/7Se + if+umID/rJV+/62Vfv+0lHb/lJub/zay+v8+t///T7n//024//81tv//P6zw/6eajP+1moH/sZuH/7Sg + i/+ji3T/gWFC/4NkR/+Gak7/hmtQ/4lwVv+TfGT/nYl0/6iXhv+1pJb/u6yd/7uqnf+3pJT/taCO/6yT + ev+mim//potw/6WKb/+mim3/nYVs/ldJI3RANQgkRTgNEkM3DQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAARTgNBUM2Cg9JOQ82kYBm0ebi1v/z8u7/8e/p/+/t5//w7eb/7u3l/+3q4//u6uH/6+jg/+zo + 3f/q5tz/6+Xa/+nj2P/p5Nj/5uDS/8a2pP+9qpj/v62Z/7yplv+7p5T/uaWT/7ikkf+2oo7/s52H/6+Z + gv+uln//s5V4/3ies/8tqfX/IK3//x6t//8xp+7/iZ2m/7iZff+xm4b/sZuH/7Kdif+wmYX/lHhe/41x + Vv+agGb/ooty/6mUgP+wm4j/tKGN/7WhkP+1oY//tKCN/7Oeiv+wmIT/qpB3/6eMcf+njHH/potw/6aL + b/+njHH/h3NY1Eg7ED1DNgoZRTgNC0M2DQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARTgNA0Q3 + DAxAMgUkgW9Svd3Yy//19e//8vDq//Hv6f/w7uj/8O3m/+/s5f/u6+P/7erh/+zp4P/s59//6ubc/+rl + 2f/q5Nj/6+ba/9bLvP+/rZr/wa+d/7+tm/++rJn/vKiW/7qnk/+6ppL/uKOP/7ahjf+ynYn/sZmC/7aW + ev+WmJX/cZyx/3Ocsf+fmpL/uJl9/7CahP+wmob/sZuH/7Gch/+ynYr/s56L/7Kfiv+1oY3/taGP/7ai + j/+0oI3/s52J/7Gahf+vmIL/rpV9/6qRdv+pjnT/qI1y/6iNc/+njHH/p4tw/6iMcf+bhGz8X1AsdD8y + BhhFOA0QRTgNBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARTgNAkQ3DAs9MAMbdWRFr9XO + vv/29vD/8vHr//Hw6f/x7+n/8O3n/+/t5v/v7OT/7uvj/+zp4f/s6OD/7Ofc/+rl2v/q5Nj/6+TZ/+bf + 0v/Gt6b/wa+d/8Gwnv+/rpv/vqyY/7yplv+7qJT/uaWR/7mkkf+3o5D/tqKO/7Sfif+5m4H/vJl7/7uZ + e/+2mH7/sJqD/6+ahf+vmob/sZuH/7Gch/+xnIj/s56J/7Seif+znIf/spuE/7GYgf+wln7/r5V9/66T + e/+tknj/rJF3/6qQdf+qkHb/qI9z/6mOdP+ojXH/p4xx/6CIb/9zY0ObQjUIGkM2CxJFOA0HRTgNAQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARTgNAUQ3DAg/MgYUblw8mczDtP/19O//8/Lu//Px + 7P/y8Ov/8e/q//Hu5//w7eb/7+zl/+3q4v/t6eH/7Ojf/+rm2//q5dn/5+HW/+nj1//Xzb//wbCf/8Gx + n//Csp//wrCe/8Cvnf+/rpr/vaqX/7uplv+5pZP/tqKP/7Ofi/+ynIn/sJuG/6+ZhP+vmoX/spyG/7Oc + h/+znIf/tZ6I/7Wdh/+1nYb/tJyF/7SbhP+zmYL/spiA/7GYgP+wln7/r5V9/66UfP+vlHz/rZJ6/66S + eP+skXf/qY90/6iNc/+jinH/loBo8W1dPINFOA4cQzYKEEU4DQlFOA0CAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAARTgNAUQ3DAdANAgNZFIxf8S4pv/08uv/9vXw//Py7f/z8ev/8u/r//Hv + 6f/w7uf/8O7m/+3r4//t6uL/6+jg/+rl3P/o49n/5uLW/+fg1f/m4NT/0ca4/8Cwn/+8qpn/vKmX/7qm + lP+2oo7/tJ6K/7OdiP+ynIb/sZyG/7WdiP+1non/t6CL/7mijP+6oo3/uaGL/7mijP+5oYr/uKCJ/7ee + h/+2nYb/tJ2F/7Wchf+0m4T/s5mC/7Oagv+ymID/s5iA/7CVff+vk3v/rZN6/6aNdf+hinL/m4Vt+413 + Xdx4ZkiZV0kjRUAzBwxCNQoKRTgNB0U4DQIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAARTgNAUU4DQZBNAgEWEchW7ismPrs6uD/9fPw//b18v/29PD/9fPu//Tz7v/z8ez/8vDp/+7t + 5f/s6eD/5+TZ/+Lc0v/a08j/08u8/8zCs//Jvq3/yb6s/8Cynv+3oo7/s52H/7Seh/+4oYz/u6WQ/7ym + kf++qJP/wKqV/8Cqlf+/qZP/vqaR/7ylj/+8pI//u6ON/7ujjf+7o4z/uqKL/7mgif+4n4j/tp+G/7Wc + hv+1m4X/sZiB/6yUff+okXr/oot0/5yGbvSRfWLjhnJX0IFtUqxoVzV8XE0oUU0+FiA+MgUKQjUJB0Q3 + DAdFOA0ERTgNAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEU4 + DQNBNAgDSzsSKJmIb93d2Mr/6unf/+7t5f/u7OT/7Ong/+nm2//n4tf/4trO/9nQxP/PxLX/v7Ke/6+f + if+nloH/pZJ8/6GOeP+fi3T/pI56/66Zhf+4oo7/vqqW/8Svm//FsJz/xbCb/8Kumf/BrZf/wKqW/8Cp + lP+/qZb/waqU/8CplP++ppH/vKSO/7qijf+5oYr/s5uF/7CYg/+slYD/pI93/52Hcf2SfWTui3Zd0IVx + V7RsXDuWZFUyd2JTL1NRQxwvQzgLGEU4DQ0AAAAAAAAAAEI2CgdFOA0GRTgNBEU4DQIAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEU4DQFENw0HQTUJB1xM + J1qhkHru0MS0/+DUxf/ZzL3/1ce3/9LDsf/Rv63/zbup/8a0of+3oo//sp+N/7emlv+1o5L/rZiF/6OL + c/+YfmT/moBl/6OOdv+znor/vaiU/8Ovmv/FsZz/xrGc/8Wwm//Fr5r/xK+b/8Cplf+6pI//tp6J/6+Z + hP+ok33/o411/pqFbvuTf2bkjXhfynpoSq5tXDyPa1s6c2BRLVBJOxEwSzsSIUo6EBI/MwcDAAAAAAAA + AABBNQkBQzYKAUM2CwNFOA0FRzkOA0U4DQIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABFOA0CRDcMBz4yBQFWRR9AiHNaxL6o + lv/XxbX/18a1/9LAr//Qvaz/zLup/8Kvmv/Iuan/9PHv//Xy7//d08n/w7Kf/6yTfP+bfWD/lXVW/6OL + cv+1oY3/u6WR/7+plf++qJX/uKKN/7Cahf+lkXv/nYlx85aCauaMeF7WfGlNwXVkR6JyYEF8X08qWU4/ + GD5OQBktTj4WG0M2Cgg+MQUCPzMGAT8zBgEAAAAAQjUJAkI2CgJFOAwERTgNAkU4DQFFOA0CAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARTgNAUU4DQVANAcBSToRHHJgQI6qloL1zLup/9nI + t//XxrX/0sKx/8i1of/ZzL////////f28//b0cf/wrGe/6qTfP+bf2H/mXtc/5F6YP+KdmH1jXhh5YZy + WNF/a1C6fGdLoHBePoFbTCZlWEkiS1dIIjRNPxgbQDMHCEA0BwdBNAgEQjQIAgAAAABCNQkCQjUKBEQ4 + DAZFOA0FRTgNA0U4DQJFOA0BRTgNAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEU4DQFFOA0FQTQIAwAAAABbTCdQjnhg1K6ahf26ppP/vaqW/6yX + gv/Ctqj////+/+ff1//KvK3/uKKO/6aLcf+bfWD/nX9g/4tzWf9bSSxoVkcjPEg5EB9DNQsPQzYLBwAA + AAAAAAAAAAAAAAAAAABBNQkDRTgNBEU4DQRFOA0DRTgNA0U4DQJFOA0BAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAARTgNAkM2CwMAAAAARDYNE2FQLlBtWzqDbV07oGZTMpGYh3LN3NHJ/9PF + uv/DsqD/tp+L/6WNdP+Ue172j3Zb4HtmS4hSQB8OUD4bB0o7FANDNgsBQzYLAUQ3DAJFOA0DRTgNAkU4 + DQFFOA0BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAEM2DQFDNw0CQDQKAwAAAAAAAAAAAAAAAAAAAABcSiksfWlPeYJuVZR/bFOXfmlPhntl + TGuEb1VLbls/JAAAAABYRSMEVEMiAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAD0yCwI8MQsDPTEMBEM1EgUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABDNRYBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////////8A + AAD///////////8AAAD///////////8AAAD/////////P/8AAAD/////////P/8AAAD////////gB/8A + AAD///////AAA/8AAAD//////wAAAf8AAAD/////2AAAAP8AAAD////+AAAAAH8AAAD////AAAAAAD8A + AAD///4AAAAAAB8AAAD//4AAAAAAAA8AAAD/8AAAAAAAAA8AAAD+AAAAAAAAAA8AAADwAAAAAAAAAA8A + AADAAAAAAAAAAA8AAACAAAAAAAAAAAcAAACAAAAAAAAAAAcAAACAAAAAAAAAAAcAAAAAAAAAAAAAAAYA + AAAAAAAAAAAAAAYAAAAAAAAAAAAAAAYAAAAAAAAAAAAAAAcAAAAAAAAAAAAAAAcAAACAAAAAAAAAAAcA + AAAAAAAAAAAAAAcAAACAAAAAAAAAAAcAAACAAAAAAAAAAAcAAACAAAAAAAAAAAcAAACAAAAAAAAAAAcA + AACAAAAAAAAAAAcAAACAAAAAAAAAAAcAAADAAAAAAAAAAAcAAACAAAAAAAAAAAcAAACAAAAAAAAAAAcA + AADAAAAAAAAAAAcAAADAAAAAAAAAAAcAAADAAAAAAAAAAAcAAADAAAAAAAAAAAcAAADgAAAAAAAAAAcA + AADgAAAAAAAAAAcAAADgAAAAAAAAAAcAAADgAAAAAAAAAAcAAADgAAAAAAAAAAMAAADgAAAAAAAAAAMA + AADgAAAAAAAAAAMAAADgAAAAAAAAAAMAAADgAAAAAAAAAAMAAADgAAAAAAAAAAMAAADwAAAAAAAAAAcA + AADwAAAAAAAAAAcAAADwAAAAAAAAAAcAAADwAAAAAAAAAA8AAADwAAAAAAAAAA8AAADwAAAAAAAAAB8A + AADwAAAAAAAAAD8AAADwAAAAAAAAAH8AAAD4AAAAAAAAYf8AAAD4AAAAAAAMD/8AAAD8AAAAAACB//8A + AAD+AAAAAEA///8AAAD/EAAA8B////8AAAD/yAAAB/////8AAAD/48An//////8AAAD//D////////8A + AAD//9////////8AAAD///////////8AAAD///////////8AAAD///////////8AAAD///////////8A + AAD///////////8AAAAoAAAAQAAAAIAAAAABACAAAAAAAABCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADcsCAE4LggBAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAA3LAgBOS8IAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAD4yCwE+MgsBOzAKAT0yCgM+MgsCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABCNQsBQjULAkI1CwJBNQsDQTULBUE0CwlBNAsMQTQLEUE0CxJBNQsQQTQLC0E0CwYAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQjULAUI1 + CwFCNQsCQjULBEI1CwNCNQsGQjULCUI1Cw1CNQsRQjULFkI1CxxCNQsjQjULLEI1CzRCNQs2QjULMUI1 + CyVCNQsXQjULCUI1CwEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEI1CwEAAAAAAAAAAEI1 + CwFCNQsDQjULA0I1CwZCNQsJQjULDUI1CxJCNQsWQjULHUI1CyNCNQssQjULM0E1CjxAMwhFPzIITD4x + B1U9MARdPC8DXj0xB1hBNQpMQjULM0I1CxpCNQsKQjULAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQjULAQAA + AABCNQsCQjULBUI1CwhCNQsLQjULD0I1CxVCNQsdQjULIkI1CypCNQozQTQKO0A0CUNAMwhMPjEHVDov + A1w6LgRmPjEGdEAzCoRKPBaaV0kltFxNK7xKPRidOy8Eb0AzCFZCNQs4QjULG0I1CwpCNQsBAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCNQsBAAAAAEI1 + CwNCNQsFQjULB0I1CwpCNQsPQjULE0I1CxlCNQsfQjULKUI1CzFBNAo6QDMJRD4yB0s9MAVUPC8FXDsu + BGY+MQd1PjEIg0c4EpRWRiOwYVEvxXZjRdyJdFnvnIZr+7KZgP/ApIv/ooxx/2BQLsA6LAN4PTIHVUI1 + CzhCNQsbQjULCUI1CwIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEI1CwEAAAAAQjULAUI1 + CwRCNQsGQjULC0I1Cw5CNQsSQjULGUM1DB9DNgwoQjULMEE0CjdAMwk9PjIHRDwvBk07LwRYOS0DYzwv + BHM9MAeERDYPllFAHa1cSyvBcmBC14ZyVu+ag2n9rpV8/72ljP/MsJb/17ue/9y+of/fwJ7/4sSi/+LD + pP+yln//X04uxjsuA3g/MghWQjULNUI1CxdCNQsIQjULAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEI1CwFCNQsCQjULA0I1 + CwZCNQsJQjULDUI1CxFCNQsXQjULH0I1CydCNQswRDUNOEE0CkA/MgdGPC8FTTsuBFQ5LgFfOi4DbD8y + CH5DNA2STj8aqFlIKMBsWz3WgW1T6ZWBZ/islXv/vaaN/8iwl//XvaL/3cSn/9/Epv/hxqf/3sOk/9zA + nv/avZ3/2LyZ/9a5mf/hwJ//za2Q/5uDbP9fTy3AOC4BcEE0CVFCNQssQjULDkI1CwIAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCNQsBQjULAUI1CwFCNQsDQjULBUI1 + CwlCNQsMQjULEUI1CxVCNQscQjULI0I1Cy1CNQs2QTUKP0AzCUk+MgdPPC8FVzgsAF05LQFoPjEHe0Az + CoxNPximWUcnwGdWNtF8a03nkXxi9aeSef26pIz/yLOa/9S9pf/cxKr/38er/+HJrP/gx6n/38Wp/9zC + pP/Yv6H/17yd/9e8nf/Xu5v/17ub/9e7mv/Xupn/276d/8ipiv+ninD/lX9m/lxNKbg5LgJlQjYLQkI1 + CxtCNQsHQjULAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCNQsBQjULAkI1CwNCNQsGQjULCEI1 + CwxCNQsQQjULFUI1CxxCNQsiQjULKkI1CzRCNQw9QDMJRT0yBko8MAVROy4CXDguAWg9MAV5PzEJi0s7 + FaBVRSK6ZlQ003poS+eOel/xpI51+7ejjf/Hs5z/0r+o/93Hsf/gyrD/4syy/9/Kr//fyK3/3Maq/9vD + p//ZwaX/2cCk/9e+of/Xvp//172f/9e9nv/XvJ3/17yc/9e7m//Xu5v/17qZ/9u+nf/Hqov/o4Zp/6SH + a/+Wf2f+U0QfnTwuBUxCNQspQjULC0I1CwEAAAAAAAAAAAAAAAAAAAAAAAAAAEI1CwFCNQsFQjULCEI1 + Cw5CNQsWQjULHUI1CyNCNQsqQjULNEI1CzxCNQtFQjULT0E0CFc8LwRbOi0BYj4xB3FCMwyESj0Wm1ZH + IbZjUC/LdmVI4Ip1W/SejHL5tKGK/8Kwmf/Qvqf/3Mmz/97Kt//hzrb/4M61/9/Ls//dybD/3Mas/9rF + qP/Xwqf/18Km/9fCpv/YwaX/2MGl/9jApP/Yv6P/2L+i/9e+n//XvZ7/172e/9e8nP/Xu5z/17ub/9e6 + mv/bvp3/yKuM/6OEaf+fhGX/p4pw/4JtUeRBMghcPzMHK0M2Cw4AAAAAAAAAAAAAAAAAAAAAAAAAAD4y + CQFCNQsHQjULEEI1CyBCNQsuQTUKOkE0CUU/MwhMPjIHVT0wBl47MARnPTAGdD0wBn9GNw+TV0chsGNR + Lsl1YkXfhnJY8ZuHcPuynYj/w7Ga/9DAq//ZyrX/38+6/+LSvP/j0bv/4M64/9zLtP/bybL/2siw/9nG + rv/Zxq3/2sau/93JsP/hy7H/4cuy/+DKsP/gya//3MWo/9nCpv/YwKP/2L+j/9i/ov/Xvp//172e/9e9 + nv/XvJz/17yc/9e7mv/Xupr/3L+d/8yvkf+liGz/n4Rn/6aIa/+YgGT7T0McfDovBClDNgwTQTQLAgAA + AAAAAAAAAAAAAAAAAAA9MgkCQjULEUI1CiY/Mgg8PTAGUzouA2I8LwVwPjAHgUQ2DZJRQByqXEonvnNf + Q9iGcVfymodt/6uZg/+/qpb/zb+q/9vOvP/h07//4tPB/+PUwf/f0b3/3dC7/93OuP/bzLb/2sq0/9rJ + s//aybH/2cew/9nHsP/Zxq7/3suz/+HMs//MuJ3/t52C/6qRcv+tknX/vaaI/9e+o//hya7/3MKl/9i/ + o//Yv6L/176f/9e9n//XvZ7/17yd/9e8nP/Xu5r/17qa/9y/nf/NsJH/pYhs/5+EZ/+lh2n/m4Jo/ltO + KJM5LQIsQjULFEE0CwMAAAAAAAAAAAAAAAAAAAAAPjIJCkE0Cxw+MAU3QjMKa1JAHKFdSyi+bVs904Jv + U+qUg2n4q5mE/76um//Kvav/1su4/97Uwf/i2Mb/59zK/+LVwv/d0L7/2866/9vNuf/azbj/2sy4/9rL + tv/ay7b/2su0/9rKtP/ayrP/2six/9nIsf/ax7D/4c+3/9PAp/+fh2r/gGhK/4dyWv+WhXH/k4Nu/4hx + WP+KcFP/tZt+/93FqP/dxaj/2L+h/9e/of/XvZ//172e/9e8nf/XvJz/17yc/9e6mv/cv57/zrGR/6WI + a/+fhGj/pYdq/5uDZ/5aSyeXOSwCNEI1CxtBNAsFAAAAAAAAAAAAAAAANisHAT0yCQ88MAUhUUAZdIp1 + WuasmYX/u6yX/8y9rf/YzsD/4NjJ/+TdzP/o38//5NzM/+PZx//g1sT/3NLA/9nOvf/bz7z/28+8/9vP + uv/bzrr/2825/9rNuP/azLb/2su2/9rLtf/ayrT/2sqz/9rIsv/Zx7D/4dC5/827n/+GbE7/hnBX/7yy + qP/d3dr/4+Pi/+Lf3f/V0s7/raOU/4JrUf+iiWz/3cSo/97Ep//WvZ//176f/9e9n//XvJ3/17yc/9e8 + m//Xupn/3L+e/9O1lf+ni23/nYJo/6WHaf+chGj/W0wnnjksAjlCNQsdQjUKBQAAAAAAAAAAABYsATYr + BwQ6LgYJPC4HMox5X9Le1sn/6uTX/+nk1f/m4dL/5N7Q/+Hayv/e1sX/3dTD/9zTwf/b0cH/3NLA/9vR + v//b0b7/29C+/9vPvP/bz7v/2866/9vNuf/azbj/2sy3/9rLtv/ay7b/2sq0/9rKs//ZyLL/4M+4/9fG + sP+GblD/i3de/9TOyf/c19P/v7Gi/6mTef+eg2j/qpN+/8GypP+2qJr/gmxT/6mNcf/iyKv/2sCj/9e9 + n//XvZ//17yd/9e8nf/XvJv/17qa/93Anf/Utpb/popu/56CaP+kh2n/noVs/2BQL645LAE7QjULH0M1 + CgUAAAAAAAAAAAAWKwE2KwcEOi0FBj8vBzqhkXng7uve/+bg0f/c1Mb/4dvN/+Dcy//h3Mv/3tjJ/9vT + wv/c1ML/3NLB/9zSwf/b0b//29G//9vRvf/b0L3/28+8/9vPuv/bzbn/2825/9rMt//azLf/2su1/9rL + tf/aybP/28q0/+TUvv+kjnP/gGpQ/8vBtv/Owbn/r5eD/56EZ/+Ze17/k3FT/49uTP+ObEz/o4lv/5aB + Z/97ZUn/w6qM/+PJrP/XvqH/176f/9e9nv/XvJ3/17yc/9e6mv/dwJ//07aW/6eLb/+egmf/pIdp/5+G + a/9gUDCuOCwBPEI1Cx9DNAsGAAAAAAAAAAAAAAAANywHAjovBgQ+LwUvkYFm0+Ld0P/i3c7/4dvM/9XK + uP+wm4L/uKaO/9vSw//g2Mj/3NPC/9zTwf/c0sH/29G//9vRv//b0b3/29C9/9vPvP/bz7r/2825/9vN + uf/azLf/2sy3/9rMtf/ay7X/2cmz/+LRu//Qvaf/gWdL/6qYif/Nw7j/uqmV/7SciP+znYf/o4xy/5N4 + X/+QcVb/k3NW/5R1Vf+Xd1r/hGlN/5yDZv/ewqb/28Kl/9e+n//XvZ7/17yd/9e8nf/Xupr/2r2d/9e5 + mP+sj3L/nYJm/6SGaf+hhmr/YVEurTgsATxCNQsfQTQLBgAAAAAAAAAAAAAAADcsBwE6LwcGPC8EJINw + VL/d18j/5uHT/+Le0P+1oYf/x7mt/6+Zhf/Ds5z/5t/O/9zTwv/c08H/3NLB/9vSwP/b0b//29G+/9vQ + vf/b0Lz/2867/9vOuv/bzbn/2sy4/9rMt//azLb/2su1/9rKtP/o1sD/sZuB/4VtUf+/sKH/y72x/8O1 + pf/Ar5z/pY13/4NoUP9+YUn/gGJL/4RmTf+RclT/mXpd/5BxU/+LcVX/yrOV/9/GqP/XvqH/172e/9e9 + nv/XvJ3/17qb/9u9nf/Wu5n/rJBy/56CZ/+jhmn/oohs/2ZWNLY3LAA7QjULHkE0CwYAAAAAAAAAAAAA + AAA6LwgBPDAIBTcoABZtXjym1s+//+fh0//k39P/tZ+H/9jQyf+8q5n/uqeN/+Tg0f/c1MP/3NPC/9zT + wf/b0sD/29G//9vRv//b0L3/29C8/9vOu//bzrr/2825/9rNuP/azLf/2sy3/9rLtP/czLb/4tG7/52G + af+PeF//yLqt/9PJv//NwLP/tJ+N/4BjTP94WkP/iG9Y/7Cllv+1q5//kHhe/5FyVf+YeFz/iW1R/7mi + hP/hx6r/2L+i/9e9nv/XvZ7/17yc/9e7nP/bvp3/1rqZ/62Pcv+egmf/o4Zp/6KHbf9nVjW1NysAO0I1 + Cx5BNAsGAAAAAAAAAAAAAAAAAAAAADwxCAU2KQAOYFAukM/Etv/n4dP/6ObX/7yqk//Kva//wbKk/7Sd + hf/j3s//3NTE/9zTwv/c08H/29LA/9vRv//b0b//29C9/9vQvP/bz7v/2866/9vOuv/azbj/2sy3/9rM + t//ayrT/3s64/9/Ot/+VfmH/k3xl/9LKv//Z0s3/z8S4/5uDb/93WkD/e2FG/6ubjf/W083/4+Lf/8G3 + r/+LblH/l3dY/4dpT/+vlXv/4Meq/9nAov/XvZ//172e/9e9nv/Xu5v/2b2c/9q8nf+ylXf/noNn/6KG + af+liW7/aFg2tzcrADtCNQseQTQLBgAAAAAAAAAAAAAAAAAAAAA8MQgEOCwAClxIJXrFuan/6eLW/+Tj + 1P/Et57/wK+h/8e6rf+slXv/39fI/97Xx//c08L/3NPC/9zSwP/b0sD/29G+/9vQvv/b0L3/28+7/9vO + uv/bzrr/2s24/9rNuP/azLb/2sq1/97OuP/fzrf/lHxh/5N7Yf/Z0sr/4NrV/87Ctv+MdF3/eFlB/4Rq + UP+9tav/4uDb//b49f/j4N7/lXpi/5FvUf+KbFH/sph8/+DHqv/ZwKL/176f/9e9nv/XvZ7/17yd/9m+ + nf/avZz/sZZ3/56EZ/+jhWn/pIht/3ZjRcQ+MQdBQTQJG0E0CwYAAAAAAAAAAAAAAAAAAAAAPjIJAzot + AwZRPhtmuayZ9+nj2P/j4NL/yr+q/7ijkP/Kv7L/qJF1/9rSwP/h28v/3NLC/9zTwv/c0sD/29LA/9vR + v//b0L7/29C9/9vPu//bzrv/2866/9vNuf/azbj/2sy3/9rKtf/ezrn/38+4/5V8Yv+PeFz/2dLK/+Tc + 1//Mw7f/jXNb/3ZYP/+Ea1P/vrit/+bi3v/6+fn/6efj/5qEbf+QblD/iWxR/7CYe//gx6r/2cCj/9e+ + n//XvZ//172d/9e8nP/Zvp3/2byc/7KWeP+eg2j/o4Vp/6OIbf93ZEbEPTAGQUAzCBxBNAsGAAAAAAAA + AAAAAAAAAAAAAD4yCQQ6MAMDRjQMUKmahuzp5tn/5N/R/9TNu/+xm4X/yLyw/6ePdP/Uyrj/4t3N/9vS + wv/c08L/3NLB/9zSwP/b0sD/29G+/9vQvf/b0Lz/2867/9vOuv/bzbn/2s24/9rMuP/azLX/3My2/+TV + v/+iim//hWpN/9HHvP/i2tb/0MO5/5J5ZP92WUD/gWVL/7GmmP/W0s7/4uDc/9bTzP+TeWH/kW9R/4xv + U/+4noH/4Mir/9rAo//Xvp//172f/9e8nf/XvJ3/2Lyc/93Anv+2mnz/n4Rm/6OGaf+mim7/eWVIxzsw + BkVBNAkdQTQLB0AzCwEAAAAAAAAAAAAAAAA/MwoDPTAFAT0vBD2ZinHg5+TX/+Tf0//c1cX/spyG/8W3 + qv+pkHj/y76q/+Tf0P/b1MP/3NPC/9zSwf/c0sH/3NK//9vRv//b0b7/28+8/9vPu//bzrv/2825/9vN + uf/azbf/2sy3/9nLtP/m18P/uaSO/3peQf+6qJX/29TP/9DFuf+plIH/d1tC/3teQ/+Sfmn/wLux/87M + x/+snpL/jW9T/5NzVv+Rc1j/x66T/9/Hq//Yv6L/176h/9e+n//XvJ//17yd/9i8nP/dwZ7/uZl+/56D + Zv+ihmn/pols/4BqT9dBMwtQPzMIIEE1CwsAAAAAAAAAAAAAAAAAAAAAPzMKAT4xBwE9LwUtjXth0uTg + 0//o5Nf/4NrL/7ejjf/Cs6T/q5N8/8Oym//n3s//3dXE/9zUw//c08H/3NLB/9zSv//b0b//29G+/9vP + vP/bz7v/2867/9vNuf/bzbn/2s23/9rMt//ay7X/4NC8/9bFsP+GbFH/lHhg/9HGu//Mv7L/wK+c/5J3 + Yv94XEP/emBG/413ZP+WhHP/jG5X/5d2Wf+Ob1T/nIJm/9nBpv/exan/2L+i/9e+of/Xvp//176f/9e8 + nf/YvZ3/27+f/7eaf/+fg2f/oodp/6WIbP+Aa1DbQjIKWD8zCCZBNAsOAAAAAAAAAAAAAAAAAAAAAEAz + CgI/MggEPS0FIoFuUr7h287/6efY/+Pf0f+8rJb/v66c/6+Xgv+7q5P/5t/R/93Wxf/c1MP/3NPC/9zS + wf/c0sD/29G//9vRvv/b0L3/28+8/9vPu//bzrr/2825/9vNuf/azLf/2sy2/9vLtv/n1sD/sZyC/3le + Qf+sln//x7qq/7+tmv+wmYX/lXtk/4drU/+EZUv/iWtO/5R2WP+Udln/im1R/72miv/jy6//2cCk/9i/ + o//YvqH/176h/9e+nv/XvZ7/17yc/97DpP+8n4P/noNn/6KGaf+miWv/gmxR3EEzCl4/MwgrQTQLDgAA + AAAAAAAAAAAAAAAAAAA/MwoCQDQKBTgpABJtWzul2NLC/+vn2v/n5Nf/xbah/7qok/+0noj/t6SM/+Tc + 0P/e1sb/3NTD/9zTwv/c08H/3NPC/93Twf/b0L7/29C9/9vPvP/bz7v/2866/9vNuf/bzbn/2sy3/9rM + tv/ay7X/4NC6/97Otv+UfmL/e2BE/6iSev+7ppT/sZqG/6iOdP+bgGL/l3lb/5h6XP+XeFn/iGhM/6OK + bf/fx6z/28So/9jAo//Yv6P/2L6h/9e+of/Xvp7/172e/9e8nf/fw6X/vaGD/56DZ/+ihWn/pYht/4hy + VexDNgxlPzIHK0E0Cw8AAAAAAAAAAAAAAAAAAAAAAAAAAEE0DAU2KQAJYFAsk8/Etv/s6t7/6OTY/83B + sP+4ppH/taOO/7Shif/h2cv/39jH/9zUw//c08L/3NPC/97Swf/e1cL/4NbF/93Sv//c0L3/28+8/9vO + uv/bzrr/2825/9rMt//azLf/2su1/9rKtP/gz7v/1cOs/5F7YP96YET/k3pf/6SKcf+fhGf/lnlc/5R2 + Wf+QcFX/hGhM/5uEZ//Xwab/38is/9fApP/YwKP/2L+j/9i/ov/XvqH/176h/9e9nv/XvJ3/38Oj/76i + hP+eg2f/ooVp/6WIbf+Ic1bsQzUMZz8yBytBNAsPAAAAAAAAAAAAAAAAAAAAAAAAAABBNAoFOCsABlpH + JH/FuKn/7evh/+rn2v/Tyrv/uaSR/7ilkv+ym4b/3NfG/+Hdzf/c1MP/3tTD/9/Vxf/ArZb/s52E/8/B + rv/e0b//4NbD/97TwP/cz7v/2866/9vNuP/azbj/2sy3/9rMtf/ayrT/2smz/+HQuf/aybH/qpR6/4Vt + Uv+AZ0z/g2hN/4RnTP+Eak7/jHNZ/6+YfP/axqv/3ces/9fBpv/YwaX/2MCk/9jAo//Yv6L/2L6h/9e+ + of/XvZ7/17yd/93Co//Cpoj/ooVq/6KFaP+miW3/i3NY7UE1DGc/MgcrQTQLDwAAAAAAAAAAAAAAAAAA + AAAAAAAAQTQKAzouAwNRPhhnua2b9u3t4P/p6Nz/3NTI/7mmkv+5ppT/sJiB/9nTwv/k39D/3dXF/97V + xP/f1sX/tqGI/5h7YP+jinD/s56G/8q6pf/bzbr/4tXC/+HUwf/d0b3/2s65/9rMtv/ay7b/2cq1/9rK + tP/XyLL/4M64/+TTvP/Swqn/uKSK/6uUef+slnr/uqWK/9O+pP/hzrX/3cat/9fCp//Ywqb/2cKl/9nB + pf/awaT/2sGj/9rBpP/awKH/2b+h/9m+nv/gxaT/xaiK/6KFav+ihmn/pols/452XfJCNw5tPjIGKUE0 + Cw8AAAAAAAAAAAAAAAAAAAAAAAAAAEI0CwQAAAAARDQKSqmchuzt6t7/6und/+Le0f++q5f/u6eU/7CZ + g//WzLv/5uHT/+DYyf/e1cX/4dnI/8Gvl/+hhWr/p41y/6GJbv+jiW7/sJiA/8OynP/VxbH/39C8/+DV + wP/e077/39C8/+DQuv/dzbf/3cu1/9zKtP/dzLT/4dC6/+bUvv/p1r3/6tS9/+jSu//izLP/3ciu/9vG + q//cx6z/3caq/93GqP/cxKf/2cKl/9i/o//XvqL/1ryd/9K6nv/Rt5r/1b2f/7+mif+jhmr/ooVp/6aJ + bf+PeV7zQjYMbD4yBilBNAsPAAAAAAAAAAAAAAAAAAAAAAAAAABENg0CAAAAADwtBDaZinHi6uba/+3r + 4P/m49b/w7Of/7uplv+xmYb/0ca0/+jh1v/h2cz/4NjI/+Pby//Gt6L/oYdq/6iOc/+okHj/qI91/6SL + cP+ji3D/rJN6/7qkjP/EsZr/zbyl/9TFr//YybT/2su1/97Mtv/dzLb/3Muy/9rJsv/bybH/28mw/9rH + rv/Yxaz/2MSr/9jCqP/Uv6b/z7mh/8q0m//HsZf/w62W/7+rlP+8ppL/uaON/7aeif+ynIn/tZ+O/7em + lP+ym4b/pYdr/6OGaf+nimz/kXpe8kU2D248MAYpQTQLDwAAAAAAAAAAAAAAAAAAAAAAAAAARTYNAj4x + BwI9MAYpjXpg1ufi1//u7eP/6ejd/8e5qv+8qpb/spuG/8y+rv/p5Nj/49zN/+HZyv/k3M3/0sW0/6WL + b/+mjHH/qJB2/6iQd/+pkXn/qJB2/6aOdf+ljXX/p492/6qRef+rlX7/sZqE/7Seif+5pI3/uaWO/7ml + jv+5pI7/uqWN/7qmj/+6pY3/t6KL/7aijP+3oYz/tqON/7Wijv+0n4//sp2L/7CaiP+tmoj/rpmJ/7Gf + kP+5raL/v7Wr/7Ojkf+zoZD/sZmI/6WHbP+jhmn/pods/5V+Y/dTQx98Oy4DJkE0CxAAAAAAAAAAAAAA + AAAAAAAAAAAAAEM1DQE+MggFPDAGG4BsUMLg3M//7+3k/+3s4//QwrT/vaqW/7OdiP/Iuaj/6OTY/+be + 0P/h28z/49vN/97Vxf+tln7/o4hs/6iPd/+okHf/qZF4/6mReP+pkHf/qIls/6aMb/+qkXn/qZF6/6qQ + ef+pkXr/qpJ7/6qSe/+rk3z/qpN+/6uUf/+rlYH/rJWB/6yWgv+vmYb/r5mF/6mSfP+jinP/n4dv/5uF + bv+hiXP/ppKB/7Gjk/+8sab/ycfC/9PRz/++saT/tJ6M/7Kbh/+lh2z/o4Zp/6eKbP+XgGP2UkYhfTsu + AiZCNQwQAAAAAAAAAAAAAAAAAAAAAAAAAABCNQsBQTUKCDYpAAxtWzus2M/D//Hu5//u7OP/1s3A/7+t + mv+3o4//w7Oi/+bi1//n4NP/49zO/+Tcz//j3c7/v6yX/6SJb/+oj3T/qJB2/6mReP+pjnP/qZJ8/7S0 + rv+2q57/qo91/6uSev+slH7/rZV//7CTd/+wkHf/rZR+/7CTeP+xlnv/r5mD/7CZhP+xnYj/rZaA/4ps + UP+DZUj/hmhM/4psUv+OdFv/knpj/5F7Zf+OeWP/hnFY/52Oe//Pzcv/xLat/7Kei/+xm4f/pohs/6OH + af+niG3/mIBk91FEIH47LgMpQzUMEjwwCgEAAAAAAAAAAAAAAAAAAAAAAAAAAEQ3DQc0KAAFYE4rlM3D + tP/y8en/7+3k/93Xyv/BsJ7/uqaT/8Cum//m4dT/6OLV/+Tez//k3c//59/S/82/sP+tk3v/qpJ3/6eP + df+pkHf/p4xx/67Byv/e/f//8f39/7u0q/+liW//rJR7/7GSd/+ol4f/l7bB/5fG3v+ZuML/q5qL/7KV + ef+vmYP/tJ2J/6aNdf9/XT//g2NH/4ZpTf+DalH/gGlP/4JpUP+Lc1v/not2/66ejP+HcFb/r6eZ/8rA + uP+ynYv/sZmG/6aIbP+jh2n/pohs/5qCZ/xaTCeTOSwCLEM2DBU8MAoCAAAAAAAAAAAAAAAAAAAAAAAA + AABDNQwFNysABFtHJHvCtqb99PPr/+7v5v/k3tP/xLKf/7yplP+5p5T/5N/S/+rn2v/m4NL/5t7R/+jh + 0//a0L//tp+J/7GZg/+rk3r/qI1y/6eQd/+q1PP/0vD//+j9//+/0tj/p493/6+Nbv+slYL/hMLh/5Xh + //+y6P//m+T//4fE5/+omYz/tJR5/7Gch/+ul4L/g2NG/4RlSP+AZkr/iG9W/6mTfP/Gtqj/3tTK//bz + 7///////qZqG/5mLef/Nxb7/sp2L/7GZhv+miGz/o4dp/6aIbP+cg2j8W0wolTksAjBDNgwYPDAKBAAA + AAAAAAAAAAAAAAAAAAAAAAAAQjYMBTouBAVQPRhgt6yX9fLy6//w7ub/6ufe/8W3pf+3oo//wbKh/+fi + 2P/r5tr/5uDU/+be0//o39P/49zN/76tmP+ym4f/tp+K/6ySe/+ojnD/osTa/6vo//+v6///q8LP/6yO + c/+0jGf/jam1/3XT//+m3P//web+/67f//941f//iK/D/7SUeP+ymYL/r5uH/4hpTP+DY0T/f2JH/5B2 + Xf/AqpX/1Mi7/+ne1//59fH//////7epmf+QgGz/zMW//7Ohjf+vl4P/pYhs/6OHaf+mh2z/nIRp/V1M + Kpc5LAEvQzYNGDwwCgQAAAAAAAAAAAAAAAAAAAAAAAAAAEI1CwQ8MQYFQTMJRqmahO/x7uf/8e/o/+/t + 4//f2M3/08i7/+Td0//s6d7/6eTZ/+fi1f/n4dT/6OLU/+jh1f/Lva3/s5uH/7ajj/+1ooz/rpR5/6ib + jP+fxtz/nsXa/6ecj/+ujnD/s49w/3euyP9qzP//j9L//5zW/v+V1P7/bc3//3Cz3P+ul4L/tZiA/7Gc + iP+Pclf/gGBD/4BkSv+JcVb/uKKK/82+sP/Xy8H/3NTN/9jQyP+XhW3/lodz/8/Iwv+3o5D/rpWA/6WH + av+jh2r/pYdr/52GbP9jUzGhOCsAJ0M2DRQ8MAoCAAAAAAAAAAAAAAAAAAAAAAAAAABCNQsDPjIHBDos + AzOaiXHl7+vh//Ly7P/v7eT/8fDp//Py6//w7eT/6+fd/+rm2//p5Nj/6ePX/+nh1f/r5tn/2c+//7il + j/+3o47/uKSQ/7ahjv+ylXn/rJF3/6mPdv+rjnH/rZN8/7mPbv9yp8P/UML//2/H//93yf7/c8f+/1PD + //9frt3/rpeD/7SYf/+znov/l3xj/39dP/+DZ0z/gmpR/5R+Zv+Yg2z/jnlj/4ZwVv+BalH/indh/7+6 + tP/Kwrr/taKP/6ySef+kiGr/o4dq/6WHa/+eg2r9Xk8sijgsAR1DNg0QAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAQjULAT8zCAM9LQUnjnph0urn2//08+3/7+3n/+/s5v/u6+P/7uvf/+zo3//r6N7/6uba/+rk + 2f/o4tb/6uTX/+be0P/Csp//uaOQ/7qnk/+5pZH/uKOQ/7Wbg/+vknf/qZN5/6qTfP+3kG7/kZma/zO1 + //9Fuv//Wrz//066//8ot///aaPE/7mVeP+zmYL/tJ+M/5yCav96WTr/gmRG/4BkSf97YUb/f2dN/4hx + Wf+TgGr/pZKD/7iqnP/Cta3/uaiY/7Gahf+njG//pYhs/6SIbP+oi27/lnxj9Es+Flw7LwUWQTULCwAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEI1CwFANAkGPCwDHH9rT7rj4NP/9fTw//Hv6f/v7ef/7+3m/+3r + 4v/u6uH/7Ojf/+zo3P/q5tv/6uTY/+ni1//s59r/0sW1/7qmk/+9q5b/u6eT/7qmkv+4pJP/tqKO/7Kc + hv+vmIH/rpR6/7WScv9qnr3/Iav//x2v//8Vrf//QKTf/6aYiv+6mHn/sJmF/7GdiP+rknv/iGlN/4hq + T/+XfGD/nYZu/6iSfv+ynYn/taOR/7illf+3pJH/spyJ/66Uf/+ojHH/popt/6WJbf+liWz/qIxw/35q + Tcc8MQUpQDMIEEE0CwUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQjUMBjYpAAxsWjmg2dPG//b3 + 8f/y8Or/8e/p//Du5//w7OT/7uvj/+3q4P/s6d//7Ofe/+rm2v/q49f/7ejc/+HZzP/BsJ3/vqyY/76s + mf+9q5f/u6eT/7mmkf+4pI//tp+L/7GbiP+xmH7/tJN3/4iWnP9gm7r/cpmw/6qWhv+4l3n/r5iD/7CZ + hf+wmoX/spyJ/7Cah/+wnIb/s5+L/7Whjv+1oY3/s56K/7GZhP+vl4H/rJN5/6mOcv+nim//p4tv/6aK + b/+miW3/qItw/5iBaPpTRiBhOS0CDEM2DAtBNAsBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEI1 + DAY2KQAGYE8sj8/Ht//4+PP/8vHr//Hw6f/x7uj/7+3m/+/s5P/u6+L/7Ong/+zo3//s59v/6uTY/+vj + 2P/s59r/0MSz/76smP/Ar5z/v66a/76rl/+8qZT/uqeR/7mkkP+3o4//taGO/7Sdhv+6mXv/vZd2/7qW + dv+0l3v/rpiD/66YhP+wmYX/sJqF/7Cahv+znIf/s5uH/7KahP+wl4D/r5N7/66Tef+tkXf/rJB0/6uP + dP+qjnL/qY5y/6iNcf+pjHD/qYxx/56GbP9oWTeIOi0CDkE0Cg1CNQsDAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABCNQsEAAAAAFpJJXjFuqv+9/fy//Tz7v/z8ez/8fDr//Hu6P/w7eb/7+zk/+3q + 4f/t6eD/7Oje/+rm2v/p49f/7Oba/+Pc0P/HuKn/v6+b/8Cwnf/AsJ3/vq6a/7uqlf+5pZH/t6KP/7Se + i/+wnIj/sJqH/6+ahP+vmYT/sZqE/7Obhv+zm4b/tZyG/7Sbhf+0m4T/s5qD/7OYgf+ylX//sZd//7CW + fv+wlHv/r5N6/7GTfP+vknr/r5J4/62ReP+qjnT/oolw/495YORhUS5uPTEHDkAzCQtCNQsFAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQjULBAAAAABQPhpau6+a/ff07//49/P/9fTv//Xy + 7f/z8e3/8vHr//Lw6//v7+f/8O7m/+7r4//t6N//6OPY/+Le0f/j3tH/19DB/8Kzof+5ppP/t6OO/7Se + if+znIj/s5uH/7Obhf+znof/t5+K/7ehiv+4oYv/uqKM/7qhi/+5oov/uaGK/7ifiP+4nYb/t5yF/7Wd + hf+2nIf/t5yF/7Wbg/+0moP/tZmC/7CVfv+skXj/qI11/5iCafOIdVnffmhNvGRUMnlJPRQqAAAAAEAz + CQVCNQsEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEI1CwMAAAAARTULLKmZ + g/Lv7uP/9PTw//X18f/29PD/8/Lt//Ly6//v7OT/6OTc/+Hd0f/Uzb3/xrur/72xnv+3qpb/sqSP/7eo + lP+4qJT/tqGK/7Wfif+7pY7/vqiS/7+qlP++qpT/wKqU/8CqlP+/qpT/wamS/76nkf+/pY//vqaP/76m + jv+7o4z/u6GM/7qhi/+0nIX/sZeD/6uSfP+kjXf6lYJn6oVwVdh/a066bl4+ll5QK3lgUC5QX04rJkQ3 + DgUAAAAAAAAAAEI1CwRCNQsCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABCNQsBQDMJAzwvBQNvXD2Rxrmp/+fh1f/o4dT/3dXJ/9rRwv/Zzr3/1ca2/8y8rP+5ppP/p5J6/6KP + eP+hjHX/nIZu/5R7Yv+XfGP/o411/7Wfi//ArJf/xrKd/8iznf/Hs53/xrGb/8axnP/ErZj/wqyX/8Gp + k/+8pZD/t5+K/7Oahv+tloD/pY54/JaBaemKdlzShHFVu3BeP5xdTCh5X00rXEo7FDtXSiUlXU4qDwAA + AAAAAAAAAAAAAAAAAAAAAAAAQDMJA0E0DAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEI1CwM+MwgCOi4ECmlVNYGsl4P318Sz/9nJuP/Qv63/zLmm/8m3 + pP+/q5X/v66d/+HZ1f/g2dH/ybqr/7CZg/+bfmL/knBS/6GIbv+5pI//wayX/8axnv/Fr5v/wKqU/7ij + jv+xm4f/qZN+/56JcfiPemHmiHRbyHxqTKRlUzKHW0sobVtLJ1FLPRUyQTMKHkI2CxE+MQYBAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAD4yBwE/MggCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQjULAgAAAAAAAAAAUUAbS496 + YNHItaX/2sm6/9rIt//UxLP/x7We/9zQxP//////9/Ty/9PGuP+0non/nYBj/5Z1Vf+Tel//k39q/5eB + a/SRe2Lhi3RcyoFqUK1nVzaPXU4ocltMKFZQQR04QDQKIUE1Cxc/MggJAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAQDMIAUAzCAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABCNQsBPjEHAQAAAABmVDMVbVs8l6iSfv69qJT/wK6Z/62Zgv/LwLT//////+HXzP/CsZ7/rZR6/5t8 + YP+cfFz/i3FX/1lHKnBSQiBAQzUMIjsuBRNbSicHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAEA0CQFCNQsBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+MQcBAAAAAAAAAABMPBgsalg2bGxbOpJhTi2GlYVvx9nM + xf/Huan/t6SQ/6mQePuUfF70jHNX3nplSoNOPBwHSzoXAQAAAAAAAAAAAAAAAEE0CgFBNAsBAAAAAEE0 + CgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD8yCgE5LwUCAAAAAAAA + AAAAAAAAAAAAAFhFJBx6ZUtjeWVKdnhkSXJ0XkVYgGlQO21ZPhYAAAAAVUIiAU8/HgEAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAADkuBwEzKQQCMikFAzouCwQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP// + ///////////////////////////P/////////8//////////B////////8AD///////wAAD//////YAA + AH/////0AAAAP////oAAAAAf///QAAAAAA///AAAAAAAD/8AAAAAAAAH8AAAAAAAAAfAAAAAAAAAD4AA + AAAAAAAHgAAAAAAAAAeAAAAAAAAABwAAAAAAAAAGAAAAAAAAAAYAAAAAAAAABwAAAAAAAAAHAAAAAAAA + AAcAAAAAAAAAB4AAAAAAAAAHgAAAAAAAAAeAAAAAAAAAB4AAAAAAAAADgAAAAAAAAAeAAAAAAAAAB4AA + AAAAAAAHgAAAAAAAAAfAAAAAAAAAB8AAAAAAAAAHwAAAAAAAAAfQAAAAAAAAB9AAAAAAAAAHwAAAAAAA + AAfAAAAAAAAAB8AAAAAAAAAD4AAAAAAAAAPgAAAAAAAAA+AAAAAAAAAD4AAAAAAAAAPgAAAAAAAAB+AA + AAAAAAAH4AAAAAAAAAfwAAAAAAAAB/AAAAAAAAAP9AAAAAAAAB/0AAAAAAABP/QAAAAAAAZ/8AAAAAAA + +f/4AAAAAB/P//2AAAAP+f///kAAB/5/////sAA5f//////PAT////////D///////////////////// + ////////////////////////////////////////KAAAADAAAABgAAAAAQAgAAAAAACAJQAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA2KwgBOC4IAQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAA9MgoBPTIKAkAzCwEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABCNQsBQjULBEI1CwdCNQsLQjULEkI1CxpDNQshQjULH0I1CxNCNAsHAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEI1 + CwNCNQsHQjULDEI1CxFCNQsZQTUKIUAzCSo/Mgc1Oy8EPjkuAkw4KwBWOCwBUUA0CD5CNQshQjULCAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCNQsBQjULBUI1 + CwpDNQsQQjULGEI1CyJBNAkpPzIHMjwvBDw4LgFJNioAVjcqAGk8MAaARjcRmFdIJbVtXD3OXEwsvDkt + AnY9MAZIQjULIkI1CwgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQjULA0I1CwVCNQsJQzUMD0M2 + DBdCNQsgQTQKJz8zCC48MQU6OS0CRzcrAFc2KQBoOy0FfUQ1EJVVRSGzZ1Q2zYJtUeOahWnytZqB/8es + kP/bvaD/1Lab/3xnS942KwF8PTIFSEI1CyFCNQsHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCNQsEQjULCEI1Cw1CNQsVQjULHkI0 + CydBMwkwPDAEODksAkM2KgBQNSkAYTkrAndAMguRTT4arWJRMst7aEvjmINn9q+ZgP3FrZT/2L6j/+DF + qf/lyKv/5Mam/+LDov/cv5z/6cin/8mqkf9xXkLeNy0AdD0yBkJCNQsYQjULAQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQjULAkI1CwdCNQsMQjUME0Q2DBtBNQojQDMILD4x + BjY6LgNENyoAUTUoAF81KAB0PjEJjUo7FaZgTy3HdWNH3JB+YvKrln3/w62V/9O+pf/gx6//5cyw/+bN + r//kyq3/4Mao/9rAov/Zvp//17yc/9e7m//Vupn/3L+e/8WmiP+kiXD/b14/1zktAWRBNQouQjULCAAA + AAAAAAAAAAAAAAAAAAAAAAAAQjULAUI1CwJCNQsHQjULDUI1CxNCNQsbQjULJEI1Cy9CNQo5PTAEQTks + AUo3LABaOC0Cbj4xBYhJOhSkW0omwnJhQdeMel7uppN7/r+qlP/RvKf/3sqz/+TQuf/m0Lf/486x/97J + rv/bxar/2MOl/9fBpf/Yv6P/176g/9e9n//XvZ7/17yc/9e7nP/Xupr/3L+e/8CihP+ggmX/p4xz/2FP + L7A6LAI3QjYLDwAAAAAAAAAAAAAAAAAAAABANAoBQjULC0I1CxpANAkpPzIHNzsvBEE5LQJONisAXTcr + AG48LQOBSjoTnlpII7twXj/Xh3Vb7aSRePq8qpT/z7+p/9zMuP/l1L7/5tS//+TTvf/gz7j/3cqx/93J + sf/gzLT/4cyx/9/Ir//fybD/4cqu/9vEp//Yv6P/2L+i/9e+n//XvZ7/17yd/9e8m//Xupr/3cCf/8Sm + if+cgGT/qoxw/4t0V+k7MgZFQDMIDgAAAAAAAAAAAAAAAAAAAABANAoJQDMIHzgrAEA3KgBnOiwCgUM1 + DJtURB+1aVc4zIRyWOefjXT+t6aR/867qf/bzrz/5dbF/+fYxv/l18P/4dS//+DSvP/czbf/28q0/9rI + sf/Xxa7/3Mm0/+PQuf/GsJP/pYpu/52DZP+jiWv/vqSG/+DHq//fxan/17+h/9e+n//XvZ//17yd/9e8 + nP/Xupr/3cCf/8apiv+dgWX/p4ls/5N8X/RCNw9ZPC8FEEM1CwEAAAAAAAAAADgsBwE+MggRPzAFRGRP + LreDcVXinIpy8rWmk//Lvav/3NDB/+PZyf/n3sz/5d3M/+Tayf/e0r//28+7/9vNuf/azbj/2su2/9rL + tf/ay7T/2sqz/9nHsf/dy7X/4c+2/6GIa/+HcFf/rKKW/8K9t/+4sKb/lINw/5h+Yv/Xv6L/38ir/9e+ + n//Xvp7/17yd/9e8nP/Xu5v/3cCf/8mrjP+dgmb/p4pt/5F7XfRCNA1hPC8FGEs6BwIAAAAAABMwATcs + BwE0KAAPc2BCqd3SxP/r49T/7OXY/+3p3f/o49P/5NzL/+DXxv/e08P/29G//9jPvf/bz7z/28+7/9vO + uv/bzbn/2sy3/9rLtv/ay7X/2smz/9vJtP/m1b//nYZn/4l2Xv/Vz8z/08zE/7uplP+3pJL/wbWo/5qK + ef+Tel//38Om/9vDpf/XvZ//17ye/9e8nf/Xu5r/38Gf/8uujv+dgWb/pols/5R+Y/lEOBBtPC8EGEw6 + BwIAAAAAABMvAQAAAAAzIwAPj39jxvbz6P/k3s//4dvM/9XNuf/d1sX/3NXG/9vTv//c0sH/29HA/9vR + vv/b0b3/28+8/9vOuv/bzbn/2sy4/9rMtv/ay7X/2siy/+XVwP/Crpb/gWpS/83Duv/Cr6L/pIlt/5d5 + W/+Oa0r/knFQ/6OJbv9+Z03/rJN2/+bLrv/XvqD/172e/9e8nf/Xu5v/3sGg/8yvj/+dgmb/pols/5d/ + ZPpEOBFwOy8EGUg3CQMAAAAAAAAAAAAAAAAzJwAHe2lKrOXf0v/m49X/yr2n/7CahP+8qpX/49vK/93V + w//c08H/29LA/9vRv//b0b7/29C8/9vOu//bzrr/2sy4/9rMt//azLX/2823/+XTvv+Xf2P/pZKA/83A + tP+8qpX/tJ2J/5J5YP+DZUz/hWNI/5RzU/+RcVT/jXNX/9i/ov/bxKb/172e/9e9nv/Xu5z/3L+f/8+y + kv+ghGj/pYZq/5qCZPxGOhFyOi8EGEI0DAMAAAAAAAAAADovCQEAAAAAY1Qxjt7YyP/s6dz/v62X/83A + uP+ynob/3NXD/97XyP/c08H/29LA/9vRv//b0b7/29C8/9vOu//bzrr/2s24/9rMt//ay7X/4NG7/9fE + rP+JcFP/uqqa/9bLwf/Gt6j/jnNd/3JTO/+Uf2z/q5yP/490Wv+Vdlj/iWxQ/8Osjv/hyKv/1r2e/9e9 + nf/Xu5z/3cCg/8+ykv+hhGj/o4Zr/5uCZ/1HOxNzOi4DF0I1DAMAAAAAAAAAAAAAAAAAAAAAVEQfctXL + vv/v7uD/x7mk/8i6rv+1oI3/1827/+DYyf/c08H/29LA/9vRv//b0b7/29C8/9vPu//bzrr/2s24/9rM + t//ay7X/4tK8/9C9pP+HbVD/yLyx/+Le2f+2o5T/c1Q7/4FnT//Jwrr/7/Lx/7qupP+Ma0v/iWlP/7qf + hf/iyav/172f/9e9nv/XvJ3/3L+e/9S1lv+jh2v/o4Zq/5+Eaf5LPhd3Oi4DF0I1DAMAAAAAAAAAAAAA + AAAAAAAATTsVWsu+r//u7OH/y8Gr/8CwoP+2o4//zsKu/+Lczf/c08L/3NLB/9vSwP/b0L//29C9/9vP + u//bzrv/2825/9rNuP/ay7b/4tK9/8+9pf+EaU3/zcO3/+rm4v+qmof/cVA1/414Yf/Z1dD//////9zX + 0v+MblD/iGdL/7ujhv/iyaz/176f/9e9nv/XvJ3/3MCg/9S2lv+jiGv/ooVq/6GHbP9WSCOAOy0AFUE0 + CwIAAAAAAAAAAD4yCQEAAAAAPy8GQrqtnPfv7eH/1Mu5/7mmlf+1o4//ybuk/+Pfz//b0sL/3NLB/9zS + wP/b0r//29C9/9vPvP/bzrv/2825/9rNuP/azLb/4NG8/9jHsP+DZ0n/wran/+vl4v+wno7/cFE3/4Zv + Vf/OyMH/8fHy/87Iv/+MbE//iWpN/76mif/iyaz/176f/9e9nv/XvJ3/2r6e/9e6mP+lim7/o4Zp/6OJ + bf9VRiODOi4BFkE0CwQAAAAAAAAAAD8zCgEAAAAANykAK6ebhOnw7eL/3dXG/7mlkv+1oY7/wK+Y/+bg + 0P/b08L/3NLB/9zSwP/c0r//29G+/9vPvP/bz7v/2826/9vNuP/azLf/3M63/+TVwv+SeF7/oYl0/+Hc + 1v/DtKX/gGVM/3RWO/+hlIP/xcK9/6CMe/+ObE7/kHFW/8+3nP/exqr/176g/9e9n//XvJ7/2r6e/9i7 + mf+niW//oYVo/6WIbv9dTCqWOC4BF0E0CwYAAAAAAAAAAAAAAAAAAAAAOCgAHZuKctjx7+L/4t/Q/72r + l/+0oI3/uaaO/+bf0P/c1cT/3NPC/9zSwf/c0r//29G+/9vQvf/bz7z/2866/9vNuf/bzbj/2su1/+bW + w/+/rJP/fWFF/8Ozo//NwLD/qpJ+/4FkTP99YUn/iG5X/5BxVf+ObVH/oolu/+LKrv/awaT/2L6i/9e+ + oP/Xvp7/2r+e/9i8nv+ojHH/oYZn/6WIbv9eTCqdOSwBH0E0CwgAAAAAAAAAAAAAAAAAAAAANCQAC4R1 + WL3u693/6ubZ/8Kznf+1oIr/tqOL/+Pcz//d1cT/3NPC/9zTwf/g1sX/3dPB/9vQvf/bz7z/2866/9vN + uf/bzbj/2sy2/93Nt//m1r//mIFl/4FmTP+4pZH/u6SS/6aMcv+VeFn/lHVV/45vUP+LblL/0Lmd/+DK + rP/Yv6P/2L6i/9e+oP/Xvp7/2b6f/9u/of+pj3L/n4Jn/6eLcP9iUS2qOCwAIUE0CwkAAAAAAAAAAAAA + AABANQsBAAAAAHJhQqjo49j/7uzh/8m8qv+0oYz/tKCK/+DZy//e1sb/3dPD/9zSwf/Xyrb/39XE/+LY + xv/d0r//2866/9rNuf/bzLj/2sy3/9nKtP/fz7r/3sy2/5V+Y/9+Y0f/lHth/5Z5XP+Nb1L/h2dM/4pw + U//DrpH/5Myy/9jBpP/Yv6P/2L+i/9e+of/XvqD/2b6f/9y/oP+skHP/n4Jm/6iKcf9jUi+uOCwAIkE0 + CwkAAAAAAAAAAAAAAABBNAoCAAAAAGZUM5Dh3NH/8fLm/9HGt/+2oI7/spuG/9zXxv/g2sz/39bG/9nN + vP+mjHL/r5mB/82+q//e1MH/49fE/+DTv//bzrr/2sy1/9rLtf/YyLL/3s64/+LRuv+6po3/lH9j/4xz + WP+Te1//qJN5/9K9pP/hzLH/18Km/9jBpf/ZwaX/2cCj/9rAov/Zv6H/28Cg/93Cov+wlHf/n4Nm/6mN + cf9kUzOyNywAIkE0CgcAAAAAAAAAAAAAAABCNAsCAAAAAFNDHG7X0MH/8/Xq/9nRxP+5o5D/sZqF/9nS + wf/k3tD/4NfI/93TwP+pj3T/nIBj/6GJbf+wmH//yLah/9vMuP/h1MD/4NXA/+DSvv/g0bv/3cy2/+LQ + uf/p2cL/5dW+/+LOtP/l0Lj/6NO6/+TPtv/bx6v/3car/93GqP/cxKf/2cGl/9i/of/Vu5z/1Lqc/9a9 + n/+vlHf/oINn/6qOc/9mVzS1NysAIUE0CwYAAAAAAAAAAAAAAABENg0BAAAAAEU1DlXJvq7/9/ju/+Db + zf+8q5f/sZmG/9bLuv/n4db/4dnK/+LZyv+ynIP/oohs/6ePd/+kinD/oYlt/6uTe/+7po//xbOb/829 + p//Swq7/18aw/9bFrv/VxKz/2MWt/9nIr//Xw6v/07+n/9G8ov/OuaL/yLSd/8Sul/++qpT/uKOP/7Wf + iv+0nov/sp6N/7akk/+qj3f/pIVn/6uNcv9sWTm5NioAIkA0CggAAAAAAAAAAAAAAAAAAAAAAAAAAEEy + CUG8r533+Pnx/+fj2f/BsJ//sZqF/9DEtP/q5tn/4tnL/+ff0f/ArZj/oIRn/6iPdv+pkXj/qZF6/6WL + cf+hhGb/pIty/6aPeP+qkXv/rJeA/62Ygf+vmIL/rpiD/66ahf+ul4L/sJuG/7Ofi/+umYX/qZSB/6eQ + fP+ok4H/sJ6O/72xqP/LycX/vLCj/7Oejf+rkHr/ooRn/6qNcf92ZETCOC0BHD8yCQgAAAAAAAAAAAAA + AAAAAAAAAAAAADgpACinmoTn+fbw/+3q4f/Huqn/s56J/8u+r//r5tr/493O/+fi1f/SxbP/pIhv/6aN + cf+pkXf/qY1y/6uXg/+1rJ//rJJ5/6qPd/+rk33/sI9z/6uNdP+qkHf/sJB0/62WgP+vmYX/rZeC/45y + WP+Ka1D/i25T/4xzW/+Qd2H/j3pk/459Zv/AvLT/zMO9/7Oei/+rkXn/o4Vn/6uNcv91ZUTCOC0CHUAy + CgcAAAAAAAAAAAAAAAAAAAAAAAAAADIkABWWhWzW9/Xu//Dw5//PxLL/uKKN/8W2pP/s59r/5uDR/+fh + 0//g1sj/s5uF/6iPdf+ojnT/pIpw/7bS3//1////zMvF/6OIb/+xkHP/pZuO/5bF1/+azOD/oaek/7OS + dv+0nYj/qpJ7/3xbPP+CY0f/gmhO/4dvVv+Te2b/r56M/66fi/+Tg23/x8C4/7Wfjv+rkHn/pIVn/6qN + cv98akrTOS0DJT8zCQoAAAAAAAAAAAAAAAAAAAAAAAAAADQmAAyHdVq98/Lq//T17f/Vy7v/spyG/8Gx + of/t6d7/5+LV/+ff0//o4dL/wa+a/6+Yg/+tk3r/pIxx/6nX9f/L/v//u9vn/62Ka/+sj3f/fsbq/6fp + //+67f//gtf//52fnP+2lXn/r5qH/4VlSP9/YUT/iG9V/76qlv/j18///////////f+XhXH/vLOq/7ek + kv+rkHj/ooVn/6uNcv9+akzTOS0DJj8zCgsAAAAAAAAAAAAAAAAAAAAAAAAAADImAAJwYUCk7+ri//b2 + 8P/l4NX/zcCx/9/Yzf/s6d7/5+LV/+fg1P/r5tn/z8Ky/7Kah/+1o47/rpF2/6Sqp/+b0+7/oqur/7aI + Yv+XnJb/aM3//5zY//+q2v7/dtT//3uuyv+4lXf/spyI/4ttUf99XkP/iG9V/8GtmP/YzML/5t7Y/9HI + vv+Ne2T/wrqz/7qnlP+pjHT/o4Vn/6qMcv+EcFPdOy4EJT8yCQkAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABgTi2L5+DU//b38f/w7uj/8/Ps//Hu5P/q593/6eTZ/+ni1v/r5tr/39bJ/7ekj/+4pJD/t6SO/7KU + ef+qjnX/p4tv/7ePbv+bl4//Rr3//2nI//94x/7/SsP//2qoyv+7lXb/tZ+M/5B0Wv98XD//gGdM/4t0 + XP+Ldl7/g2xT/4NsVP+qn5L/zMW//7SgjP+nim7/o4do/6uNc/9/a07NOC4DGD8yCgUAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABYQyFx29TH//r69v/u7Oj/7uzk/+3q4P/s6eD/6+fc/+nl2f/p49f/6+XY/8a2 + pP+4pJD/u6eT/7mkkv+1nIb/rpeA/66Uef+2kW//V6TR/yO1//8pt///Ia79/5Kamv+8lnj/tKGO/5t/ + Zv97Wjv/h2lN/4hvVv+Wfmj/o5J9/7Wklf++rqL/taCP/6uQdv+kiGv/popt/6yPdP9lVTOWNywACUE0 + CgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABGNQ9RysKy/vv9+f/x7+n/8O7n/+/s5P/t6+L/7Onf/+vn + 3P/q5Nj/7une/9jOwP+7qJP/vquX/7yplv+6ppP/uKOO/7Odif+1mHz/r5N8/2aat/9Knsn/ipid/7yV + d/+wmYP/sJuG/7CZhf+okXr/rZmD/7Wgjf+4o4//tqCL/7Kbhf+rkXf/popu/6eJbf+nim7/rpF2/5N9 + Ye9BNQ0zPDAFAUI1DAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7LAM8u7Cd9v7/+v/y8en/8e7p/+/t + 5v/v7OP/7Ong/+zo3v/r5dj/7OXa/+vl2P/HuKb/vauY/8Cwm/++rJr/u6qU/7umkv+2o5H/t52F/76Y + dv+9lHP/upZ1/7CYgv+umYX/sZqF/7Kch/+2n4n/s5uF/7GYgf+uk3r/rJB2/62Pdf+sj3P/rpF1/62R + dv+vk3n/mYFm91RGIVkAAAAAQjULBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCMAkmrKCK7P/+ + +v/29PD/8/Hs//Lw6v/x7+n/7+3n//Du5v/x7eT/7une/+7q3v/f2c7/xLSj/7yrl/+6qJT/t6OP/7We + iv+znIj/spyI/7KdiP+ynYj/tJ2I/7afif+3nof/tpyF/7WchP+1m4T/t5qD/7abg/+3m4T/tZmC/7WX + gf+vk3z/oolw/5d+ZOx2Y0SvXU4rOAAAAABCNQsEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAA8KwIHmIlv1v399v/4+vb/9vTx//T07v/y8ur/7Ori/+Hf0v/Qx7j/xLmo/7yynv+9s5//vK2a/7Sf + iv+2oIn/u6OO/7ymkf+9qJH/v6mT/8Grlf/Dq5X/waiS/8OrlP/CqZL/wKSR/72kjv+4n4n/sJeB/6eQ + eP+VgGbrinRZz3hmR6lrWzqFZVQzUVJCHh8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAEI1CwEAAAAAVkciW76wnv3u5tr/4trL/9fKuv/UxrP/ybin/7Whjf+smof/ppN+/5uC + av+Qc1j/oIhu/7ynkf/KtaH/zrmm/866o//Mt6T/yLKf/8OsmP+8pZH/s5uG/6GLdPOZhGzoiXVbzHpn + S6xtWzuKXU0pZFlIJUNNQBkjXlAtCgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEI1CwEAAAAAAAAAAF9KKUWWgWfX18S0/9vJuf/Uwa//xLGa/9jL + wP/7+vv/29DG/6+WgP+Vc1T/mH1g/66ahf+0non/sZqF+aCKcuWJdlrMgW5Rtm5dPpleTyx5WEglU1pJ + JzRVRiEgRzsSCQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOy4EAQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABVQh4Sfm1Qm7ii + kP/ItqP/tKGK/+Lb0///////0cKy/6ySd/+dfF3/j3NY/2FOM4lTRB9TRTYPNlxKKR1YSiQNUEIbAQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAFFAHCtyXz9oYk4ubJSFb7PFtqnwqpeB75mCaOKLclbLfGZLdQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFdDIwN0X0QrcF1ALXNdRRkAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB3YUYDcl5DBAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///////wAA//////n/ + AAD///////8AAP/////4/wAA/////gB/AAD////gAD8AAP///AAAHwAA//+AAAAPAAD/+AAAAAcAAP8A + AAAABwAAwAAAAAAHAACAAAAAAAcAAIAAAAAAAwAAAAAAAAACAAAAAAAAAAIAAIAAAAAAAwAAgAAAAAAD + AABAAAAAAAMAAMAAAAAAAwAAwAAAAAADAABAAAAAAAMAAEAAAAAAAwAAwAAAAAADAADAAAAAAAMAAKAA + AAAAAwAAoAAAAAADAACgAAAAAAMAAKAAAAAAAwAA4AAAAAADAADgAAAAAAMAAOAAAAAAAwAA4AAAAAAD + AADgAAAAAAMAAPAAAAAAAwAA8AAAAAADAADwAAAAAAMAAPAAAAAAFwAA8AAAAAAvAADwAAAAAP8AAOgA + AAAP/wAA7AAAA/3/AAD+AAD///8AAP+AP////wAA//D/////AAD/+f////8AAP///////wAA//////// + AAD///////8AACgAAAAgAAAAQAAAAAEAIAAAAAAAgBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALyUAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOywBAzgrAAU7LAECAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPC0BAjosAAY3KgANMiYAGSwiACgqIAA/Kh8ARDYp + ACY8LQEHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPTACAjwuAQY5LAANNSkAGC8jACgsHwA5Kh8AUzAjAHNAMQqVV0UhtX1o + RteBbE7cOCsAhTElAC47LQIGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAADwtAQQ5KwAMNigAFS8jACIqHgA1KBwASywgAGo5KwKNUkAes3FePdSUfV/rtJt/+tCy + l//fwaP/6cam//TTsv+eg2j4MiYAgzQnACY7LQECAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPC4BATwu + AQQ8LgEMOCoAFDImAB8sIQAvKR0ASisfAGk3JwCJSzsWrWpXNsyMeVvorph+/8qzmf/exq3/6c+z/+vR + s//oza7/4cWl/9y/nf/Xupf/3r+c/8OihP+CbE/zNykAZjksAA0AAAAAAAAAAAAAAAA6LgECNyoADTEl + AB4sHgAxKRwASCweAGM3JgCBTDkRpWVVMsiIdVbkqJZ89sW0nf/byLL/59O+/+nVv//x3MT/6tO1/9zE + pv/hyKr/3MWo/9a8nf/XvJz/17ua/9e6mP/ev5z/tZZ3/6mIbv9oVTGzLyQADQAAAAAAAAAAAAAAADQm + ABg1IwBtRjYNomFPK8KBcFLbpJV8+cKznf/ayrj/6NnH/+3dyv/q3Mf/59fB/+LRuf/byq//5NG6/8Ss + jv+hinD/p5R//6qTeP/Stpf/4cep/9e8nP/Xu5v/17qY/9/Anv+4mXr/pIVn/3hkQs4vIgAYAAAAAAAA + AAAAAAAATz0Ya8W1of7e08T/7ufZ/+/o2P/t5NP/5t3N/+DWw//c0Lv/2c65/9nMtf/Zy7L/2Mew/+XS + vv+8pon/kn5n/8S8tP+/sqL/rZ+R/5F9Zf/PtJb/4cSm/9e7mv/Xupn/4cKd/7ucff+jg2j/eGNC1TUk + ACQAAAAAAAAAAAAAAABsWjyQ//zz/+bezf/Nv6v/3dbE/9vUwP/Z0L3/2tC9/9vQu//bzrn/2sy3/9rM + tf/gz7j/3Mix/454X//Ftq3/uaGL/45sTP+KZUP/jW5S/5N6Xf/kx6r/172c/9e6mf/hwp7/vaB//6OD + aP99ZkTZLiMAJgAAAAAAAAAAAAAAAFBAG2nr59n/0MOw/7Odi//Qw67/4trI/9vSv//b0b7/29C8/9vO + uv/azbj/2su1/+XWv/+8por/n4p1/9jLwP+gh3L/eFlB/5Z/bP+ObVD/hmdJ/8+1l//cw6P/1bmY/9/A + n//AooH/o4Jn/39pRt0sIwAlAAAAAAAAAAAAAAAATDkSS9/Zy//Z0r//u6eX/8e7pv/i28z/29K//9vR + vv/b0Lz/28+6/9rNuP/ay7X/59fA/6+Wef+woZD/4t3X/3VVO/+QemX/+f7//7anlv98Vzj/xauO/+HG + p//Vupn/3sCf/8SlhP+ig2f/hG1O4DIlACYAAAAAAAAAAAAAAAA4JQAy0Ma2/+Pcyv+znor/w7Sd/+Pd + zP/b0sD/3NK//9vRvf/bz7v/2825/9rMtf/m2ML/sZl+/6yaiP/n4Nz/cVE1/5SBbP//////wrWn/3pV + Nf/IrpH/4MWl/9W6mf/dwJ7/xqmG/6KDZ/+JclTkNScAKQAAAAAAAAAAAAAAACkWABq+s57w7uvd/7Of + iv+7p5D/5N3N/9vTwf/c0r//29G9/9vPu//bzrn/2sy3/+LTvf/Ou6T/jXNZ/9zUyf+YgGn/c1U6/6md + lP+UeWL/i2lL/9i/o//bwKL/1ryb/93Bnv/Jq4v/ooNm/49zV+w1KAA2AAAAAAAAAAAAAAAAJhQABqib + gtf59+v/uqeR/7Sfh//j2sv/3NTB/+DWw//i2MX/3NK+/9vNuf/bzbj/2822/+jYwv+giGv/kntj/76p + lf+Tdlr/gV8+/35cOv+xmHz/5c2u/9i9oP/XvZz/3cGh/8uuj/+hgmb/kXVY8jYpAEIAAAAAAAAAAAAA + AAAAAAAAkYJovv799P/DtKH/r5iC/93Yyf/h2Mf/1MWx/8y8p//j18b/4tfD/9zPuv/ay7T/3My1/+DR + uv+dhGj/h2xP/4hqTP+DZUj/qZBy/+DJrP/awaT/2b6h/9i+oP/ewqL/z7GR/6KDZv+TeVv1NyoARwAA + AAAAAAAAAAAAAAAAAAB9bU+h/f/1/9DDsv+tk33/3NbF/+ji0v/KuKH/lXdZ/62Xff/MuqT/39K//+LW + wP/i07z/5NO8/+3bxP/Uwqj/yLOX/9fDqf/o07r/4cmr/93Ep//awaT/1rya/9m8mv/NsZP/pIVo/5V7 + Xfg2KgBHAAAAAAAAAAAAAAAAAAAAAGBQLIX6+fD/29TF/6yUf//a0MH/6+XY/9bIuP+egmX/n4Rp/5+D + af+ojXL/t6CE/8Kvmf/Itp//zLie/9C9pf/Tv6j/0Lqi/8u3nv/DrZf/u6aP/7ijj/+8qpr/t6WW/6+Y + hv+nhWj/mn5g+zstAkoAAAAAAAAAAAAAAAAAAAAATj0YZ/Lt5f/o5Nn/r5mF/9bJuv/s59r/5dvO/6uQ + d/+hhmr/p4tv/6qUf/+pj3X/ooRs/6mHav+jh23/qIdq/6qPeP+oknz/knZc/4xwVv+Jblf/inNc/6OZ + i//KxcD/sJeD/6eGaP+dgmT/PjMISwAAAAAAAAAAAAAAAAAAAAA9KwdI5d7T//Py5/+znob/zL6s/+7r + 3P/s5df/w7Ca/6WIbP+ehWr/yO37/9nq6v+pgWL/np2T/53Y6/+cwMv/r5N6/62Tev93VTb/el4//5d/ + af/Fuaz/tqiW/6+ll/+2n43/poVo/5+EZv9BNQtXAAAAAAAAAAAAAAAAAAAAADAiAC7Ty773/v72/8q7 + qf/b08b/7Ojb/+zn2f/Wybn/rpWA/6uPc/+ixtX/qMnR/6+CXv9yv+X/q+z//4jg//+Koqn/uZV2/39h + Q/9+YkX/y7up//n08v/Fu67/qJ2P/7ikkP+jg2T/pIZr/0Y4EFwAAAAAAAAAAAAAAAAAAAAAMyEAG76x + n+f/////8/Hr//Hu5f/q5tr/6+bZ/+fe0f+4pJD/t6GL/66ReP+mh2v/tIlj/1er2f9Exf//NMD//4Kd + qP/Cmnz/g2dL/3NUNf+Ea1P/hm9V/5WCb//Ct6//rpV+/6WEZf+ihmr/QDQKRgAAAAAAAAAAAAAAAAAA + AAA4IwALpZiC1f/////v7eb/7+zj/+3q4P/r5tr/8Ord/8y8q/+4o4z/vKeT/7Weif+4l3j/nZGE/zmg + 0/9Pm8T/s5J4/7Oag/+iiHD/moFn/6aOeP+umoP/tJ6J/6qPdv+lhmj/s5N5/39qSMsvJAAJAAAAAAAA + AAAAAAAAAAAAAAAAAACRgmfB//////Lw6//x7+j/8O3l//Ht5P/18eb/6+bY/8OxoP+9rJb/uqaT/7Wg + jf+5mH3/u5Jw/7uSbf+xln3/rpiB/7adhv+4n4j/uZuD/7WXfv+zknj/rpBz/6mNb/+KclXSRDcPKQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAHxsTaL//////fz5//T07f/x7+j/39rO/83Csv/LwrD/wbKi/7ah + iv+5ooz/vKWP/7+okv/ErJf/xKuW/8Srk//DppD/uZ6G/7KXf/+njnP/ln5k44dwU712YUGRaFQ0UVxN + KQsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQzMJK7CijN/r39H/4NHA/8y6pf/AsJ//uaqZ/5N3 + W/+UeFn/w6yY/9K4p//Er5j/tqGL/qaQd+yWgGbXh3JWu3VhQpl0X0FyXEwmTUs6EyhSQx4JAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATTYSEoNvU57Isp//vKaP//Xy + 8P/07OT/poZp/45tT/9wXUCkYE4rdmNPLVJVRB81WkolIkk6EwwAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFlG + IixhTClMjHtjj6CMd76Kb1OlfGNGYQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA////v/////////8f///gD//8AAf/wAAD8AAAA4AAAAOAAAADgAAAA4AAAAOAAAADgAAAA4AA + AAOAAAADgAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAAD4AAAB+AAAA/gAAD/8AA///wP + //////////////////8oAAAAGAAAADAAAAABACAAAAAAAGAJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAACgdAAYhGAAYJBkANCgcACo2KQACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAArIAABJRkAEiIXADApGwBRNCgJdk07Gp9tWDbEnoNj7XJe + O84kGQBFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKB4AASQYAA8kFgAqJRcASTEi + AnJGNx2aZVQ2wYt2Vt2wmXn3zrSW/+LEqP/qy6v/9NGu/+K/of9iTjDUKh4AMzMnAAQAAAAAAAAAAAAA + AAAlGAANIxUAJiUXAEQwHwBoRDMOkWJSMr2GdFrgq5p99cq0nP/hzbT/9dvD/+zStf/v0rX/6tGy/9zA + oP/WuZf/2buX/86ti/+qh2z/Tz8biCwiABYAAAAAMiMBDjcoB1hbSyu4gXJV1qWXfvXHuaT/39C+/+zd + yv/v38z/6tzF/+fVvf/k0Lf/sp1//6ubh/+smYT/ya+R/+DDpf/Ut5f/3L6b/82tjP+oh2n/ZVIyrTEj + AygAAAAAalk7JJmLc6b/+e3/7+fX//Dq2P/l3Mv/3dS+/9rOuP/XyrP/18iv/+TSvP+rlXn/qJiJ/7mm + lP+WemD/iG5U/8+ylf/ewaH/3Lya/9Gxjf+nhWr/ZFExtDIlAzIAAAAAYlM0IJaMc5vo3Mz/tqGN/9nR + vf/b0r7/2c+7/9rOuf/Zy7b/39G6/9fCqf+eh3H/z76z/4RjSP+FZUv/gF5C/6eKa//gyKf/2ryb/9Kz + kf+ph2r/ZlMxty4lAzIAAAAARjUYFnFkSIbj3Mn/taGN/9XNuf/f18T/2s+7/9rPuf/ZzLb/4tW+/8my + lv+woIz/yLuy/2lKMP/59PL/rZqH/5NvTv/hyKj/2r2c/9S1k/+qiWz/bVg4ujQoBDMAAAAAKh0JD0g7 + KnPt5dH/sJuE/9LHsv/g2Mj/2tC7/9rPuv/ZzLf/4NK7/9PAqP+ji3b/z8O4/21PMv/59PL/n4dy/599 + Xf/iyar/2b2c/9a4lP+sim7/clw9xDgrBjwAAAAAFgsDByMaEVjy79X/tJ6F/8u7qP/h28r/39bC/+HZ + xP/bz7r/2cq0/+bXwP+mjnL/oIt1/5yCaP9xUTT/elk6/8uxlP/fxKb/2L2c/9i7mv+ri27/dl0+0Tot + BksAAAAAGhEHBhELBkPg28D/tqOO/8Cxnf/m4dH/yrih/8i2of/i1sP/4dbA/+HSu//j1Lz/p5F0/5R4 + Wv+NcFL/v6iI/+bOr//cv6H/3cCe/96/nf+vjnH/d2BA1zsuB1EAAAAAQzUdBxUPBTK3s5v5xLGe/7qo + lP/w697/vqqU/5BwUv+uln3/w7CX/9HBqf/ay7P/5tO6/9fEq//dyrD/48+1/9O7of/LtJv/yrKY/8Kp + kf+ujHH/fmVE2TwwB1MAAAAAMiQGARsRAR+xqZPs1s6+/7ehjP/w6t//2cu6/5t9YP+bfWH/pY1z/6aI + b/+qhmn/p4tu/7STdv+wmYD/l3th/41wW/+OdmH/raWb/7mqof+qh2r/hWtJ3kI2DlYAAAAAAAAAAB0Q + AA6vppTe7eXW/7SfiP/r5tr/6eLT/7GXff+dgWf/zvb//7+woP+VkIX/reL1/6OtrP+qiGz/b0wt/5B3 + Xv/p497/xr6y/7Chk/+tjXD/h25N5Ec6E2IAAAAAAAAAAAAAAACfkn/J///9/+DYzP/r6Nv/7+nb/8e1 + pP+rkHX/oail/66Ma/9xrMr/fOr//3LD4v+1k3n/d1Qz/4huVP/59PL/tKug/7Smmf+ph2n/jHBR5Ew9 + F2EAAAAAAAAAAAAAAACGd1+v//////Lx6P/s6d//8evf/97Txv+2oIr/tZh//7eQbf+Qkov/LaPh/2+W + p/+8lXb/lnph/49zWv+Ue2H/o4t3/6OGav+ohGb/bVk4rzMoBCMAAAAAAAAAAAAAAAB4Z0ua//////X0 + 8f/y8en/7eja/+zl1f/Cs6H/sZ6I/7Gdif+4lHf/uo9s/7qTcf+zmID/tJmD/7WXfv+rinH/mHda/45w + UfN6YUa0NiwHFgAAAAAAAAAAAAAAAAAAAABVRSNS5+DX//327f/WzLn/tKWR/52Ldf+Re2D/tZyH/7+h + jP+tknz/p412/56GbfmPc1jeg2hPwmxWOKRiTzF7dGBDVGNPMCsAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAXUcmTauUfOSojHX/5N3X/7Wch/9qSCz/ZlE5sldFLIRJOiBjRjkbR15LLSdvWj4WY1AwBQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGZSNCBKNxtVi31ol41z + W7FsUDZyVkUqBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA////AP///wD//wcA/+AHAPwAAQDAAAEAAAABAAAAAQAAAAEAAAABAAAA + AQAAAAEAAAABAAAAAQAAAAEAgAABAMAAAQDAAAEAwAADAMAADwDgAP8A8D//AP///wD///8AKAAAABAA + AAAgAAAAAQAgAAAAAABABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAABUMAAohFQATIxkAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAABUKABgcEQBEMiYOe1lGKIeKcU+tvJt4zD4wFl0AAAAAAAAAAAAAAAAAAAAACwAAFxsL + ADwtIAJrTT8mpn5rT9aym4H02Lye//PUssz/5MTM9NSxzPzXscyyj3D/LCADQiIZAAgyJAYeaVxCwqqb + gfjQwaz/797I//jp0f//7dX/79i9/72qkv+tm4b/xamM/+LEo//dv5j/vpp6/0w6GnEqHQEbUEMoM7aw + m//o0b//7ejR/9/Vv//bzrf/5tS8/7Seh/+xm4z/gF1A/4NhRf/cwaD/6Mek/7yZev9KOBhzJx8BHhsR + AxqmmnzrtaCJ/9/axv/f0r7/39O9/+LSuP++qpT/noh4//n08v+oknv/x6iF/+zOq//Bnn7/VEEglTAk + AyUAAAALq6SM3sqylv/h2Mf/5+DM/+bax//r3MX/vqaN/5aAaP+Ha1P/kHFU/+LFp//pzKj/xKKC/1pF + JKk3KAUyAAAAAIiEb87Ks5v/5NvL/8KtlP/MuKL/5tjC/+/hyP++qYr/ooZn/9/IqP/t0rP/4sSh/8ai + hv9fSye2OSwFOAAAAABqZVK60Lym/+fazv/BrJT/jWlJ/7WgiP++mXz/0a2P/9O6n/+vlHv/nIRr/7qt + of+6mYP/a1UsukA1CjsAAAAAX1dInPTo1v/g2cj/6NzL/6KIb//L1tH/r7Ow/7fv//+/saX/bkcj//n0 + 8v/MycX/tpiC/3heOM9PPxpGAAAAAG1cSX//////9vXr//z26//Er5z/soxs/4yWkv9Cwfj/rZ+Q/5Jq + Rv+vmob/rJWD/6mCZf9SPyCcMiUJKAAAAABbSy9h////////9//a0b3/wLKd/8Gnkv/NpIj/vI9w/62G + aP+afGX/fF1B8G9PMthgRCyRAAAAAAAAAAAAAAAAOiwNBH9qT6iqkXX/sZyK/11AKv9tVD7FaVQ8mV1L + L3phTDJSUj4jLUk5HxcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABHMRUBPSsWVnlmVKFaPSeIPzEZCAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//wAA/+MAAP4DAADAAAAAAAAAAAAA + AAAAAAAAAAAAAIAAAACAAAAAgAAAAIAAAACAAwAAgA8AAMH/AAD//wAA + + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Security.Gui/LoginForm_en.resx b/CloudBuilder/CloudBuilder.Security.Gui/LoginForm_en.resx new file mode 100644 index 0000000..2357074 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/LoginForm_en.resx @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Cancel + + + Language: + + + Login + + + Password: + + + Username: + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Security.Gui/LoginForm_zh-cn.resx b/CloudBuilder/CloudBuilder.Security.Gui/LoginForm_zh-cn.resx new file mode 100644 index 0000000..40319f4 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/LoginForm_zh-cn.resx @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 语言: + + + 用户名: + + + 密码: + + + 登录 + + + 取消 + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Security.Gui/MainForm.Designer.cs b/CloudBuilder/CloudBuilder.Security.Gui/MainForm.Designer.cs new file mode 100644 index 0000000..a0fa3d5 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/MainForm.Designer.cs @@ -0,0 +1,309 @@ +namespace CloudBuilder.Security.Gui +{ + partial class MainForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm)); + this.mainStatusStrip = new System.Windows.Forms.StatusStrip(); + this.securityUserNameLabel = new System.Windows.Forms.ToolStripStatusLabel(); + this.copyLabel = new System.Windows.Forms.ToolStripStatusLabel(); + this.mainMenu = new System.Windows.Forms.MenuStrip(); + this.systemToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.permissionToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.userEnquiryToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStrip1 = new System.Windows.Forms.ToolStrip(); + this.kryptonManager1 = new Krypton.Toolkit.KryptonManager(this.components); + this.toolStripContainer1 = new System.Windows.Forms.ToolStripContainer(); + this.mainPanel = new Krypton.Toolkit.KryptonPanel(); + this.mainKryptonNavigator = new Krypton.Navigator.KryptonNavigator(); + this.kryptonPanel2 = new Krypton.Toolkit.KryptonPanel(); + this.navigatorLeft = new Krypton.Navigator.KryptonNavigator(); + this.buttonLeft = new Krypton.Navigator.ButtonSpecNavigator(); + this.kryptonPage2 = new Krypton.Navigator.KryptonPage(); + this.favoritePanel = new System.Windows.Forms.TableLayoutPanel(); + this.mainStatusStrip.SuspendLayout(); + this.mainMenu.SuspendLayout(); + this.toolStripContainer1.ContentPanel.SuspendLayout(); + this.toolStripContainer1.TopToolStripPanel.SuspendLayout(); + this.toolStripContainer1.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.mainPanel)).BeginInit(); + this.mainPanel.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.mainKryptonNavigator)).BeginInit(); + this.mainKryptonNavigator.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.kryptonPanel2)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.navigatorLeft)).BeginInit(); + this.navigatorLeft.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.kryptonPage2)).BeginInit(); + this.kryptonPage2.SuspendLayout(); + this.SuspendLayout(); + // + // mainStatusStrip + // + this.mainStatusStrip.Font = new System.Drawing.Font("Arial", 9F); + this.mainStatusStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.securityUserNameLabel, + this.copyLabel}); + this.mainStatusStrip.Location = new System.Drawing.Point(0, 640); + this.mainStatusStrip.Name = "mainStatusStrip"; + this.mainStatusStrip.Padding = new System.Windows.Forms.Padding(1, 0, 19, 0); + this.mainStatusStrip.Size = new System.Drawing.Size(984, 22); + this.mainStatusStrip.TabIndex = 9; + this.mainStatusStrip.Text = "status"; + // + // securityUserNameLabel + // + this.securityUserNameLabel.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text; + this.securityUserNameLabel.Name = "securityUserNameLabel"; + this.securityUserNameLabel.Size = new System.Drawing.Size(61, 17); + this.securityUserNameLabel.Text = "Login Info"; + // + // copyLabel + // + this.copyLabel.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text; + this.copyLabel.Margin = new System.Windows.Forms.Padding(60, 3, 0, 2); + this.copyLabel.Name = "copyLabel"; + this.copyLabel.RightToLeft = System.Windows.Forms.RightToLeft.No; + this.copyLabel.Size = new System.Drawing.Size(170, 17); + this.copyLabel.Text = "Copyright © 2013 Owen Chen"; + this.copyLabel.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // mainMenu + // + this.mainMenu.Dock = System.Windows.Forms.DockStyle.None; + this.mainMenu.Font = new System.Drawing.Font("Segoe UI", 9F); + this.mainMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.systemToolStripMenuItem}); + this.mainMenu.Location = new System.Drawing.Point(0, 0); + this.mainMenu.Name = "mainMenu"; + this.mainMenu.Size = new System.Drawing.Size(984, 24); + this.mainMenu.TabIndex = 10; + this.mainMenu.Text = "menuStrip1"; + // + // systemToolStripMenuItem + // + this.systemToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.permissionToolStripMenuItem}); + this.systemToolStripMenuItem.Name = "systemToolStripMenuItem"; + this.systemToolStripMenuItem.Size = new System.Drawing.Size(67, 20); + this.systemToolStripMenuItem.Text = "系统设置"; + // + // permissionToolStripMenuItem + // + this.permissionToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.userEnquiryToolStripMenuItem}); + this.permissionToolStripMenuItem.Name = "permissionToolStripMenuItem"; + this.permissionToolStripMenuItem.Size = new System.Drawing.Size(180, 22); + this.permissionToolStripMenuItem.Text = "权限管理"; + // + // userEnquiryToolStripMenuItem + // + this.userEnquiryToolStripMenuItem.Name = "userEnquiryToolStripMenuItem"; + this.userEnquiryToolStripMenuItem.Size = new System.Drawing.Size(180, 22); + this.userEnquiryToolStripMenuItem.Text = "用户查询"; + // + // toolStrip1 + // + this.toolStrip1.Dock = System.Windows.Forms.DockStyle.None; + this.toolStrip1.Font = new System.Drawing.Font("Segoe UI", 9F); + this.toolStrip1.Location = new System.Drawing.Point(3, 24); + this.toolStrip1.Name = "toolStrip1"; + this.toolStrip1.Size = new System.Drawing.Size(111, 25); + this.toolStrip1.TabIndex = 11; + this.toolStrip1.Text = "toolStrip1"; + // + // toolStripContainer1 + // + // + // toolStripContainer1.ContentPanel + // + this.toolStripContainer1.ContentPanel.Controls.Add(this.mainPanel); + this.toolStripContainer1.ContentPanel.Size = new System.Drawing.Size(984, 591); + this.toolStripContainer1.Dock = System.Windows.Forms.DockStyle.Fill; + this.toolStripContainer1.Location = new System.Drawing.Point(0, 0); + this.toolStripContainer1.Name = "toolStripContainer1"; + this.toolStripContainer1.Size = new System.Drawing.Size(984, 640); + this.toolStripContainer1.TabIndex = 12; + this.toolStripContainer1.Text = "toolStripContainer1"; + // + // toolStripContainer1.TopToolStripPanel + // + this.toolStripContainer1.TopToolStripPanel.Controls.Add(this.mainMenu); + this.toolStripContainer1.TopToolStripPanel.Controls.Add(this.toolStrip1); + // + // mainPanel + // + this.mainPanel.Controls.Add(this.mainKryptonNavigator); + this.mainPanel.Controls.Add(this.kryptonPanel2); + this.mainPanel.Controls.Add(this.navigatorLeft); + this.mainPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.mainPanel.Location = new System.Drawing.Point(0, 0); + this.mainPanel.Name = "mainPanel"; + this.mainPanel.Size = new System.Drawing.Size(984, 591); + this.mainPanel.TabIndex = 1; + // + // mainKryptonNavigator + // + this.mainKryptonNavigator.Button.CloseButtonAction = Krypton.Navigator.CloseButtonAction.HidePage; + this.mainKryptonNavigator.Dock = System.Windows.Forms.DockStyle.Fill; + this.mainKryptonNavigator.Location = new System.Drawing.Point(89, 0); + this.mainKryptonNavigator.Name = "mainKryptonNavigator"; + this.mainKryptonNavigator.Size = new System.Drawing.Size(895, 591); + this.mainKryptonNavigator.StateCommon.CheckButton.Content.Image.ImageH = Krypton.Toolkit.PaletteRelativeAlign.Center; + this.mainKryptonNavigator.StateCommon.CheckButton.Content.Image.ImageV = Krypton.Toolkit.PaletteRelativeAlign.Near; + this.mainKryptonNavigator.TabIndex = 0; + this.mainKryptonNavigator.Text = "kryptonNavigator1"; + this.mainKryptonNavigator.Selecting += new System.EventHandler(this.mainKryptonNavigator_Selecting); + this.mainKryptonNavigator.Selected += new System.EventHandler(this.mainKryptonNavigator_Selected); + this.mainKryptonNavigator.Deselecting += new System.EventHandler(this.mainKryptonNavigator_Deselecting); + this.mainKryptonNavigator.Deselected += new System.EventHandler(this.mainKryptonNavigator_Deselected); + // + // kryptonPanel2 + // + this.kryptonPanel2.Dock = System.Windows.Forms.DockStyle.Left; + this.kryptonPanel2.Location = new System.Drawing.Point(84, 0); + this.kryptonPanel2.Name = "kryptonPanel2"; + this.kryptonPanel2.Size = new System.Drawing.Size(5, 591); + this.kryptonPanel2.TabIndex = 2; + // + // navigatorLeft + // + this.navigatorLeft.AutoSize = true; + this.navigatorLeft.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.navigatorLeft.Button.ButtonDisplayLogic = Krypton.Navigator.ButtonDisplayLogic.None; + this.navigatorLeft.Button.ButtonSpecs.AddRange(new Krypton.Navigator.ButtonSpecNavigator[] { + this.buttonLeft}); + this.navigatorLeft.Button.CloseButtonDisplay = Krypton.Navigator.ButtonDisplay.Hide; + this.navigatorLeft.Dock = System.Windows.Forms.DockStyle.Left; + this.navigatorLeft.Header.HeaderPositionBar = Krypton.Toolkit.VisualOrientation.Left; + this.navigatorLeft.Location = new System.Drawing.Point(0, 0); + this.navigatorLeft.Name = "navigatorLeft"; + this.navigatorLeft.NavigatorMode = Krypton.Navigator.NavigatorMode.HeaderBarCheckButtonGroup; + this.navigatorLeft.Pages.AddRange(new Krypton.Navigator.KryptonPage[] { + this.kryptonPage2}); + this.navigatorLeft.PopupPages.AllowPopupPages = Krypton.Navigator.PopupPageAllow.OnlyCompatibleModes; + this.navigatorLeft.PopupPages.Position = Krypton.Navigator.PopupPagePosition.FarMatch; + this.navigatorLeft.SelectedIndex = 0; + this.navigatorLeft.Size = new System.Drawing.Size(84, 591); + this.navigatorLeft.TabIndex = 1; + this.navigatorLeft.Text = "kryptonNavigator1"; + // + // buttonLeft + // + this.buttonLeft.Edge = Krypton.Toolkit.PaletteRelativeEdgeAlign.Near; + this.buttonLeft.Type = Krypton.Toolkit.PaletteButtonSpecStyle.ArrowLeft; + this.buttonLeft.TypeRestricted = Krypton.Navigator.PaletteNavButtonSpecStyle.ArrowLeft; + this.buttonLeft.UniqueName = "46BC0F8FA7B4463D899D3D35A7A9592F"; + this.buttonLeft.Click += new System.EventHandler(this.buttonLeft_Click); + // + // kryptonPage2 + // + this.kryptonPage2.AutoHiddenSlideSize = new System.Drawing.Size(200, 200); + this.kryptonPage2.Controls.Add(this.favoritePanel); + this.kryptonPage2.Flags = 65534; + this.kryptonPage2.LastVisibleSet = true; + this.kryptonPage2.MinimumSize = new System.Drawing.Size(50, 50); + this.kryptonPage2.Name = "kryptonPage2"; + this.kryptonPage2.Size = new System.Drawing.Size(51, 589); + this.kryptonPage2.Text = "收藏夹"; + this.kryptonPage2.ToolTipTitle = "Page ToolTip"; + this.kryptonPage2.UniqueName = "337B28D6BA2D4CA2D7A874B45ADA95A0"; + // + // favoritePanel + // + this.favoritePanel.AutoSize = true; + this.favoritePanel.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.favoritePanel.BackColor = System.Drawing.Color.Transparent; + this.favoritePanel.ColumnCount = 1; + this.favoritePanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.favoritePanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.favoritePanel.Location = new System.Drawing.Point(0, 0); + this.favoritePanel.Name = "favoritePanel"; + this.favoritePanel.RowCount = 2; + this.favoritePanel.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.favoritePanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.favoritePanel.Size = new System.Drawing.Size(51, 589); + this.favoritePanel.TabIndex = 0; + // + // MainForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(984, 662); + this.Controls.Add(this.toolStripContainer1); + this.Controls.Add(this.mainStatusStrip); + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.MainMenuStrip = this.mainMenu; + this.Name = "MainForm"; + this.Text = "MainForm"; + this.mainStatusStrip.ResumeLayout(false); + this.mainStatusStrip.PerformLayout(); + this.mainMenu.ResumeLayout(false); + this.mainMenu.PerformLayout(); + this.toolStripContainer1.ContentPanel.ResumeLayout(false); + this.toolStripContainer1.TopToolStripPanel.ResumeLayout(false); + this.toolStripContainer1.TopToolStripPanel.PerformLayout(); + this.toolStripContainer1.ResumeLayout(false); + this.toolStripContainer1.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.mainPanel)).EndInit(); + this.mainPanel.ResumeLayout(false); + this.mainPanel.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.mainKryptonNavigator)).EndInit(); + this.mainKryptonNavigator.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.kryptonPanel2)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.navigatorLeft)).EndInit(); + this.navigatorLeft.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.kryptonPage2)).EndInit(); + this.kryptonPage2.ResumeLayout(false); + this.kryptonPage2.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.StatusStrip mainStatusStrip; + private System.Windows.Forms.ToolStripStatusLabel securityUserNameLabel; + private System.Windows.Forms.ToolStripStatusLabel copyLabel; + private System.Windows.Forms.MenuStrip mainMenu; + private System.Windows.Forms.ToolStripMenuItem systemToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem permissionToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem userEnquiryToolStripMenuItem; + private System.Windows.Forms.ToolStrip toolStrip1; + private Krypton.Toolkit.KryptonManager kryptonManager1; + private System.Windows.Forms.ToolStripContainer toolStripContainer1; + private Krypton.Navigator.KryptonNavigator navigatorLeft; + private Krypton.Navigator.KryptonPage kryptonPage2; + private Krypton.Toolkit.KryptonPanel mainPanel; + private Krypton.Toolkit.KryptonPanel kryptonPanel2; + private Krypton.Navigator.ButtonSpecNavigator buttonLeft; + private Krypton.Navigator.KryptonNavigator mainKryptonNavigator; + private System.Windows.Forms.TableLayoutPanel favoritePanel; + } +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Security.Gui/MainForm.cs b/CloudBuilder/CloudBuilder.Security.Gui/MainForm.cs new file mode 100644 index 0000000..e7932d4 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/MainForm.cs @@ -0,0 +1,151 @@ +using CloudBuilder.Core.DependencyInjection.Request; +using CloudBuilder.Core.Service; +using CloudBuilder.Gui; +using CloudBuilder.Gui.DependencyInjection; +using CloudBuilder.Request.Security; +using CloudBuilder.Security.Data; +using CloudBuilder.Security.Policy; +using Krypton.Navigator; +using Microsoft.Extensions.DependencyInjection; +using CloudBuilder.Core.Extensions; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace CloudBuilder.Security.Gui +{ + public partial class MainForm : AbstractForm + { + private IContext loginContext = null; + private SecurityFunctionResultData securityMenuData = null; + + public MainForm() + { + InitializeComponent(); + } + + public void InitForm() + { + try + { + //初始化容器------------------------------------- + loginContext = ServiceHelper.GetInterfaceService()!; + //设置登录信息 + securityUserNameLabel.Text = string.Format("[{0}] [{1}] {2}", loginContext.DefaultVersion, loginContext.Requestor, loginContext.LoginDate.GetFormattedDateString("yyyy-MM-dd HH:mm:ss")); + copyLabel.Text = loginContext.DefaultCopyright; + this.Text = loginContext.DefaultTitle; + //不启用这两个功能 + navigatorLeft.Visible = false; + toolStrip1.Visible = false; + + navigatorLeft.NavigatorMode = NavigatorMode.HeaderBarCheckButtonOnly; + buttonLeft.TypeRestricted = PaletteNavButtonSpecStyle.ArrowRight; + this.KryptonNavigator = mainKryptonNavigator; + //设置居中对齐 + this.SetBounds((Screen.GetBounds(this).Width / 2) - (this.Width / 2), + (Screen.GetBounds(this).Height / 2) - (this.Height / 2), + this.Width, this.Height, BoundsSpecified.Location); + //设置最大化 + this.WindowState = FormWindowState.Maximized; + //清空菜单项 + this.mainMenu.Items.Clear(); + //初始化菜单数据------------------------------------- + InitData(); + //设置菜单 + InitMenu(); + //设置欢迎页 + + DisplayAbstractPage(typeof(WelcomePage).Name); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void InitData() + { + SecurityUserRequest securityUserRequest = ServiceHelper.GetTypeService(); + + securityMenuData = securityUserRequest.FindMenuByUsername(); + } + + private void buttonLeft_Click(object sender, EventArgs e) + { + + if (navigatorLeft.NavigatorMode == NavigatorMode.HeaderBarCheckButtonGroup) + { + navigatorLeft.NavigatorMode = NavigatorMode.HeaderBarCheckButtonOnly; + buttonLeft.TypeRestricted = PaletteNavButtonSpecStyle.ArrowRight; + } + else + { + navigatorLeft.NavigatorMode = NavigatorMode.HeaderBarCheckButtonGroup; + buttonLeft.TypeRestricted = PaletteNavButtonSpecStyle.ArrowLeft; + } + } + + + private void mainKryptonNavigator_Deselecting(object sender, KryptonPageCancelEventArgs e) + { + if (mainKryptonNavigator.Pages.Count == 0) return; + + if (mainKryptonNavigator.SelectedPage == null) return; + + AbstractPage page = GetAbstractPage(mainKryptonNavigator.SelectedPage); + + if (page == null) return; + + if (!page.FunctionDeactivating()) e.Cancel = true; + } + + public AbstractPage GetAbstractPage(KryptonPage page) + { + foreach (Control c in page.Controls) + { + if (c is AbstractPage) + { + return (AbstractPage)c; + } + } + return null; + } + + private void mainKryptonNavigator_Selecting(object sender, KryptonPageCancelEventArgs e) + { + + } + + private void mainKryptonNavigator_Deselected(object sender, KryptonPageEventArgs e) + { + + } + + private void mainKryptonNavigator_Selected(object sender, KryptonPageEventArgs e) + { + if (mainKryptonNavigator.Pages.Count == 0) return; + + if (mainKryptonNavigator.SelectedPage == null) return; + + AbstractPage page = GetAbstractPage(mainKryptonNavigator.SelectedPage); + + if (page == null) return; + + page.FunctionSelected(); + } + } +} diff --git a/CloudBuilder/CloudBuilder.Security.Gui/MainForm.partial.cs b/CloudBuilder/CloudBuilder.Security.Gui/MainForm.partial.cs new file mode 100644 index 0000000..2f5e501 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/MainForm.partial.cs @@ -0,0 +1,171 @@ +using CloudBuilder.Core.DependencyInjection.Request; +using CloudBuilder.Core.Extensions; +using CloudBuilder.Core.Policy; +using CloudBuilder.Core.Service; +using CloudBuilder.Gui; +using CloudBuilder.Security.Data; +using CloudBuilder.Security.Entity; +using CloudBuilder.Security.Policy; +using DocumentFormat.OpenXml.Math; +using DocumentFormat.OpenXml.Spreadsheet; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +namespace CloudBuilder.Security.Gui +{ + public partial class MainForm + { + private Dictionary menuItems = new Dictionary(); + + private void InitMenu() + { + this.mainMenu.Items.Clear(); + + if (securityMenuData == null || securityMenuData.SecurityFunctionDisplayDatas == null || securityMenuData.SecurityFunctionDisplayDatas.Count() == 0 || securityMenuData.SecurityFunctionMaps == null || securityMenuData.SecurityFunctionMaps.Count() == 0) + { + return; + } + + Dictionary menuItems = new Dictionary(); + + SetMenuItem(); + } + + + + public void SetMenuItem() + { + SecurityUserPermissionInfo permissionInfo = loginContext.GetPermissionInfo(); + + string menuDisplayName = null; + + foreach (SecurityFunctionDisplayData functionDisplayData in securityMenuData.SecurityFunctionDisplayDatas.OrderBy(x => x.Orderby)) + { + SecurityFunctionMapEntity[] maps = securityMenuData.SecurityFunctionMaps.Where(x => x.FunctionNameSon == functionDisplayData.FunctionName).OrderBy(x => x.Orderby).ToArray(); + + if (maps == null || maps.Count() == 0) return; + + if (functionDisplayData.FunctionIndc != YesNoPolicy.YES) continue; + + menuDisplayName = CulturePolicy.IsZhcn(loginContext.GetCulture()) ? functionDisplayData.FunctionLocalName : functionDisplayData.FunctionEngName; + + foreach (SecurityFunctionMapEntity map in maps) + { + if (functionDisplayData.FunctionNameParent != map.FunctionNameParent) continue; + + if (menuDisplayName == "-" || menuDisplayName == "divider") + { + AddToolStripSeparator(map); + continue; + } + + AddMenuItem(functionDisplayData, map.FunctionNameParent); + } + } + } + + private void AddToolStripSeparator(SecurityFunctionMapEntity map) + { + ToolStripSeparator sp = new ToolStripSeparator(); + sp.Name = map.FunctionNameParent + map.Orderby + "_" + menuItems[map.FunctionNameParent].DropDownItems.Count; + menuItems[map.FunctionNameParent].DropDownItems.Add(sp); + + } + + private void AddMenuItem(SecurityFunctionDisplayData function, string functionNameParent) + { + //Only Permission whithout function + if (string.IsNullOrEmpty(function.FunctionName)) return; + if (string.IsNullOrEmpty(function.PageName) && function.FunctionIndc == YesNoPolicy.YES) return; + + string functionName = function.FunctionName; + + if (menuItems.ContainsKey(functionName)) + { + functionName = functionName + "_" + functionNameParent; + } + + ToolStripMenuItem menuItem = new ToolStripMenuItem(); + menuItem.Name = !string.IsNullOrEmpty(function.PageName) ? function.PageName : function.FunctionName; + menuItem.Size = new System.Drawing.Size(124, 22); + menuItem.Text = CulturePolicy.IsZhcn(loginContext.GetCulture()) ? function.FunctionLocalName : function.FunctionEngName; + + if (function.FunctionIndc == YesNoPolicy.YES) + menuItem.Click += new System.EventHandler(MenuItem_Click); + + if (!menuItems.ContainsKey(menuItem.Name)) + { + menuItems.Add(menuItem.Name, menuItem); + } + else + { + menuItems.Add(functionName, menuItem); + } + + CreateParentMenuItem(function.FunctionName, menuItem, functionNameParent); + } + + private void CreateParentMenuItem(string functionName, ToolStripMenuItem menuItem, string functionNameParent) + { + SecurityFunctionMapEntity[] maps = securityMenuData.SecurityFunctionMaps.Where(x => x.FunctionNameSon == functionName).OrderBy(x => x.Orderby).ToArray(); + + //如果不存在上級節點返回 + if (maps == null || maps.Count() == 0) return; + + SecurityFunctionMapEntity[] tmaps; + SecurityFunctionDisplayData functionDisplayData; + foreach (SecurityFunctionMapEntity map in maps) + { + if (!menuItems.ContainsKey(map.FunctionNameParent)) + { + functionDisplayData = securityMenuData.SecurityFunctionDisplayDatas.Where(x => x.FunctionName == map.FunctionNameParent).FirstOrDefault()!; + + if (functionDisplayData == null) + { + mainMenu.Items.Add(menuItem); + return; + } + + tmaps = securityMenuData.SecurityFunctionMaps.OrderBy(x => x.Orderby).Where(x => x.FunctionNameSon == functionDisplayData.FunctionName).ToArray(); + + if (tmaps == null || tmaps.Length == 0) + { + mainMenu.Items.Add(menuItem); + return; + } + + + AddMenuItem(functionDisplayData, tmaps[0].FunctionNameParent); + } + + if (map.FunctionNameParent != functionNameParent) continue; + + menuItems[map.FunctionNameParent].DropDownItems.Add(menuItem); + } + } + + private void MenuItem_Click(object sender, EventArgs e) + { + try + { + DisplayAbstractPage(menuItems[((ToolStripMenuItem)sender).Name].Name, menuItems[((ToolStripMenuItem)sender).Name].Text, null, this.KryptonNavigator); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + } +} diff --git a/CloudBuilder/CloudBuilder.Security.Gui/MainForm.resx b/CloudBuilder/CloudBuilder.Security.Gui/MainForm.resx new file mode 100644 index 0000000..f502986 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/MainForm.resx @@ -0,0 +1,2826 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + + + AAABAAgAgIAAAAEAIAAoCAEAhgAAAGBgAAABACAAqJQAAK4IAQBISAAAAQAgAIhUAABWnQEAQEAAAAEA + IAAoQgAA3vEBADAwAAABACAAqCUAAAY0AgAgIAAAAQAgAKgQAACuWQIAGBgAAAEAIACICQAAVmoCABAQ + AAABACAAaAQAAN5zAgAoAAAAgAAAAAABAAABACAAAAAAAAAIAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPDEPATwyDwEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCNhABQjYQAUI3EAFCNxABQjcQAUM3EAFCNhACQjYQAkI3 + EAJCNxABQjcQAUI2EAFBNhABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABFOREBRTkRAUU5EQFGOhEBRjoRAUY6 + EQJFOREDRTkRBEU5EQVFOREFRTkRBkU5EQZFOREGRTkRBkU5EQVFOREFRTkRA0Y6EQJGOhEBAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABHOxIBRzsSAUc7 + EgFIOxIBSDsSAUg7EgJIOxIDRzsSBEc7EgVHOxIGRzsSB0c7EghHOxIJRzsSC0c7Eg1HOxIORzsSDkc7 + Eg5HOxINRzsSDEc7EgpHOxIIRzsSBUc7EgRIOxICRzsSAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABJPBIBSTwSAUk8EgFJPBIBSTwSAUk8EgJJPBIDSTwSBEk8EgVJPBIFSTwSB0k8EghJPBIJSTwSC0k8 + Eg1JPBIPSTwSEUk8EhNJPBIWSTwSGEk8EhpJPBIbSTwSGkk8EhlJPBIWSTwSE0k8Eg9JPBILSTwSCEk8 + EgVJPBIDSTwSAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABJPBIBSTwSAUk8EgFJPBIBSTwSAUk8EgJJPBIDSTwSBEk8EgVJPBIFSTwSB0k8 + EghJPBIJSTwSC0k8Eg1JPBIOSTwSEUk8EhNJPBIWSTwSGEk8EhtJPBIeSTwSIkk8EiVJPBIoSTwSK0k8 + EixJPBIrSTwSKUk8EiVJPBIgSTwSGkk8EhVJPBIPSTwSCkk8EgZJPBIDSTwSAQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASTwSAUk8EgFJPBIBSTwSAUk8EgJJPBIDSTwSBEk8 + EgVJPBIFSTwSB0k8EghJPBIJSTwSC0k8Eg1JPBIOSTwSEUk8EhNJPBIWSTwSGEk8EhtJPBIeSTwSIUk8 + EiVJPBIoSTwSLEk8EjBJPBI1STwSOUk8Ej1JPBJASTwSQUk8EkBJPBI9STwSOEk8EjFJPBIqSTwSIUk8 + EhhJPBIRSTwSC0k8EgZJPBIDSTwSAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASTwSAUk8EgFJPBIBSTwSAUk8 + EgFJPBICSTwSBEk8EgVJPBIFSTwSB0k8EghJPBIJSTwSC0k8Eg1JPBIOSTwSEUk8EhNJPBIWSTwSGEk8 + EhtJPBIeSTwSIUk8EiVJPBIoSTwSLEk8EjBJPBI0STwSOUk8Ej1JPBJBSTwSRkk8EktJPBJRSTwSVUk8 + EldJPBJZSTwSWEk8ElRJPBJOSTwSRkk8EjxJPBIxSTwSJUk8EhtJPBITSTwSDEk8EgdJPBIDSTwSAQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASTwSAUk8 + EgFJPBIBSTwSAUk8EgFJPBICSTwSA0k8EgRJPBIFSTwSBkk8EghJPBIJSTwSC0k8Eg1JPBIOSTwSEUk8 + EhNJPBIWSTwSGEk8EhtJPBIeSTwSIUk8EiVJPBIoSTwSLEk8EjBJPBI0STwSOUk8Ej1JPBJBSTwSRkk8 + EktJPBJQSTwSVUk8ElpJPBJfSTwSZEk8EmlJPBJtSTwScEk8EnFJPBJwSTwSbEk8EmVJPBJcSTwSUEk8 + EkNJPBI1STwSKEk8EhxJPBITSTwSDEk8EgdJPBIDSTwSAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAASTwSAUk8EgFJPBIBSTwSAUk8EgFJPBICSTwSA0k8EgRJPBIFSTwSBkk8EgdJPBIISTwSCkk8 + EgxJPBIOSTwSEEk8EhJJPBIVSTwSGEk8EhtJPBIeSTwSIUk8EiVJPBIoSTwSLEk8EjBJPBI0STwSOUk8 + Ej1JPBJBSTwSRkk8EktJPBJQSTwSVUk8ElpJPBJfSTwSZEk8EmlJPBJtSTwSckk8EndJPBJ8STwSgEk8 + EoRJPBKHSTwSh0k8EoZJPBKCSTwSe0k8EnFJPBJlSTwSVkk8EkdJPBI3STwSKUk8Eh1JPBITSTwSDEk8 + EgdJPBIDSTwSAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAASTwSAUk8EgFJPBIBSTwSAUk8EgFJPBICSTwSA0k8EgRJPBIFSTwSBUk8 + EgdJPBIISTwSCUk8EgtJPBINSTwSD0k8EhFJPBIUSTwSF0k8EhpJPBIdSTwSIEk8EiRJPBIoSTwSLEk8 + EjBJPBI0STwSOUk8Ej1JPBJBSTwSRkk8EktJPBJQSTwSVUk8ElpJPBJfSTwSZEk8EmlJPBJtSTwSckk8 + EndJPBJ8STwSgEk8EoRJPBKISTwSjFdJIp1pWDaydmVGyYVyV+SLd17xhXJX5HJhQcFQQhqUSTwShUk8 + EnlJPBJqSTwSWkk8EkhJPBI4STwSKkk8Eh1JPBITSTwSDEk8EgZJPBIDSTwSAQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASTwSAUk8EgFJPBIBSTwSAUk8EgFJPBICSTwSA0k8 + EgRJPBIFSTwSBUk8EgdJPBIISTwSCUk8EgtJPBINSTwSDkk8EhFJPBITSTwSFkk8EhhJPBIbSTwSH0k8 + EiJJPBImSTwSK0k8Ei9JPBIzSTwSOEk8Ej1JPBJBSTwSRkk8EktJPBJQSTwSVUk8ElpJPBJfSTwSZEk8 + EmlJPBJtSTwSckk8EndJPBJ8STwSgEk8EoRJPBKISTwSjFBCGpZjVDCrdmVGyYFvU96OemH4kX1l/5F9 + Zf+RfWX/kX1l/5WAaP+RfWX/kX1l/456YfhoWDa0STwSikk8EnxJPBJtSTwSW0k8EklJPBI5STwSKkk8 + EhxJPBITSTwSC0k8EgZJPBIDSTwSAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEk8EgFJPBIBSTwSAUk8 + EgFJPBICSTwSA0k8EgRJPBIFSTwSBUk8EgdJPBIISTwSCUk8EgtJPBINSTwSDkk8EhFJPBITSTwSFkk8 + EhhJPBIbSTwSHkk8EiFJPBIlSTwSKEk8Ei1JPBIxSTwSNkk8EjtJPBJASTwSRUk8EkpJPBJPSTwSVUk8 + ElpJPBJfSTwSZEk8EmlJPBJtSTwSckk8EndJPBJ8STwSgEk8EoRJPBKISTwSjEk8EpBjVDCrdmVGyYFv + U96Ld17ykX1l/5F9Zf+RfWX/kX1l/5F9Zf+jjXP/sJh9/76kiP/QtJb/2Luc/9i7nP+9o4f/mYRr/5F9 + Zf9tXDu9STwSjUk8En5JPBJtSTwSXEk8EklJPBI4STwSKUk8EhxJPBISSTwSCkk8EgVJPBICSTwSAQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEk8 + EgFJPBIBSTwSAUk8EgFJPBIBSTwSAkk8EgRJPBIFSTwSBUk8EgdJPBIISTwSCUk8EgtJPBINSTwSDkk8 + EhFJPBITSTwSFkk8EhhJPBIbSTwSHkk8EiFJPBIlSTwSKEk8EixJPBIwSTwSNEk8EjlJPBI9STwSQkk8 + EkdJPBJMSTwSUkk8EldJPBJdSTwSY0k8EmhJPBJtSTwSckk8EndJPBJ8STwSgEk8EoRJPBKISTwSjEk8 + EpBjVDCrcmFBwn5rT9iIdVrskX1l/5F9Zf+RfWX/kX1l/5F9Zf+eiXD/sJl//76lif/LsZT/2b2f/9m9 + nv/ZvJ7/2byd/9m8nf/Yu5z/2Luc/9i7nP/Yupv/q5N5/5F9Zf9tXDu+STwSjkk8En9JPBJtSTwSW0k8 + EkhJPBI2STwSJ0k8EhpJPBIQSTwSCUk8EgVJPBICAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAEk8EgFJPBIBSTwSAUk8EgFJPBIBSTwSAkk8EgNJPBIESTwSBUk8EgZJPBIISTwSCUk8 + EgtJPBINSTwSDkk8EhFJPBITSTwSFkk8EhhJPBIbSTwSHkk8EiFJPBIlSTwSKEk8EixJPBIwSTwSNEk8 + EjlJPBI9STwSQUk8EkZJPBJLSTwSUEk8ElVJPBJaSTwSX0k8EmRJPBJqSTwScEk8EnZJPBJ7STwSf0k8 + EoRJPBKISTwSjEk8EpBdTimlbV08vHpoStGIdVrskX1l/5F9Zf+RfWX/kX1l/5F9Zf+eiXD/rJZ8/7mi + h//HrpL/2b+i/9m+of/ZvqH/2b6g/9m9oP/ZvZ//2b2f/9m8nv/ZvJ7/2byd/9i7nf/Yu5z/2Luc/9i6 + m//Yupv/nIZt/5F9Zf9tXDu+STwSjkk8En1JPBJrSTwSWUk8EkVJPBIzSTwSJUk8EhhJPBIOSTwSCEk8 + EgRJPBIBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEk8EgFJPBIBSTwSAUk8EgFJPBIBSTwSAkk8EgNJPBIESTwSBUk8 + EgZJPBIHSTwSCEk8EgpJPBIMSTwSDkk8EhBJPBISSTwSFUk8EhhJPBIbSTwSHkk8EiFJPBIlSTwSKEk8 + EixJPBIwSTwSNEk8EjlJPBI9STwSQUk8EkZJPBJLSTwSUEk8ElVJPBJaSTwSX0k8EmRJPBJpSTwSbUk8 + EnJJPBJ3STwSfEk8EoFJPBKGSTwSi0k8EpBXSSKfbV08u3poStGEclflkX1l/5F9Zf+RfWX/kX1l/5F9 + Zf+ahW3/p5J5/7Wfhf/HsJX/2sCk/9nApP/ZwKP/2b+j/9m/ov/Zv6L/2b6h/9m+of/ZvqD/2b2g/9m9 + n//ZvZ//2bye/9m8nv/ZvJ3/2byd/9i7nP/Yu5z/2Lqb/9i6m/+4m4D/lH9n/5F9Zf9tXDu+STwSjEk8 + EntJPBJpSTwSVUk8EkJJPBIwSTwSIEk8EhRJPBILSTwSBkk8EgJJPBIBAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEk8EgFJPBIBSTwSAUk8EgFJPBIBSTwSAkk8 + EgNJPBIESTwSBUk8EgVJPBIHSTwSCEk8EglJPBILSTwSDUk8Eg9JPBIRSTwSFEk8EhdJPBIaSTwSHUk8 + EiBJPBIkSTwSKEk8EixJPBIwSTwSNEk8EjlJPBI9STwSQUk8EkZJPBJLSTwSUEk8ElVJPBJaSTwSX0k8 + EmRJPBJpSTwSbUk8EnJJPBJ3STwSfEk8EoBJPBKESTwSiEk8Eo1XSSKdaFg2s3ZlRsqEclfljnph+JF9 + Zf+RfWX/kX1l/5F9Zf+VgWn/p5J6/7Wghv/HsZb/1b2i/9rCpv/awab/2sGl/9rBpf/awKT/2cCk/9nA + o//Zv6P/2b+i/9m/ov/ZvqH/2b6h/9m+oP/ZvqD/2b2f/9m9n//ZvZ7/2bye/9m8nf/ZvJ3/2Luc/9i7 + nP/Yu5v/2Lqb/7mcgP+kim//lH9n/456YfldTimqSTwSikk8EnhJPBJkSTwST0k8EjtJPBIpSTwSGkk8 + Eg9JPBIISTwSBEk8EgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEk8EgFJPBIBSTwSAUk8 + EgFJPBIBSTwSAkk8EgNJPBIESTwSBUk8EgVJPBIHSTwSCEk8EglJPBILSTwSDUk8Eg5JPBIRSTwSE0k8 + EhZJPBIYSTwSG0k8Eh9JPBIiSTwSJkk8EitJPBIvSTwSM0k8EjhJPBI9STwSQUk8EkZJPBJLSTwSUEk8 + ElVJPBJaSTwSX0k8EmRJPBJpSTwSbUk8EnJJPBJ3STwSfEk8EoBJPBKESTwSiEk8EoxQQhqWY1Qwq3Zl + RsmBb1Pejnph+JF9Zf+RfWX/kX1l/5F9Zf+VgWn/o492/7Wgh//DrZT/0Lug/9rDqf/aw6j/2sOo/9rC + p//awqf/2sKm/9rBpv/awaX/2sGl/9rApP/ZwKT/2cCj/9nAo//Zv6L/2b+i/9m/ov/ZvqH/2b6h/9m+ + oP/ZvZ//2b2f/9m9nv/ZvJ7/2byd/9m8nf/Yu53/2Luc/9i7nP/Yupv/vJ+D/6aLcP+kiW//lH9m/456 + YfhdTimnSTwShUk8EnJJPBJdSTwSR0k8EjNJPBIhSTwSFEk8EgtJPBIFSTwSAgAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABJPBIBSTwSAUk8EgFJPBIBSTwSAkk8EgNJPBIESTwSBUk8EgVJPBIHSTwSCEk8EglJPBILSTwSDUk8 + Eg5JPBIRSTwSE0k8EhZJPBIYSTwSG0k8Eh5JPBIhSTwSJUk8EihJPBItSTwSMUk8EjZJPBI7STwSQEk8 + EkVJPBJKSTwST0k8ElVJPBJaSTwSX0k8EmRJPBJpSTwSbUk8EnJJPBJ3STwSfEk8EoBJPBKESTwSiEk8 + EoxJPBKQY1Qwq3JhQcKBb1Pei3de8pF9Zf+RfWX/kX1l/5F9Zf+RfWX/o493/7GchP+/qpH/zbee/9rF + q//axav/2sSq/9rEqv/axKn/2sOp/9rDqP/aw6j/2sKn/9rCp//awqb/2sGm/9rBpv/awaX/2sGl/9nA + pP/ZwKT/2cCj/9m/o//Zv6L/2b+i/9m+of/ZvqH/2b6g/9m9oP/ZvZ//2b2f/9m8nv/ZvJ7/2byd/9i7 + nf/Yu5z/2Luc/9i6m/+/oob/potw/6WKcP+jiW7/lH9m/456YfheTyqjSTwSfkk8EmlJPBJSSTwSPEk8 + EilJPBIZSTwSDkk8EgdJPBICRzsSAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAASTwSAUk8EgFJPBIBSTwSAUk8EgJJPBIESTwSBUk8EgVJPBIHSTwSCEk8 + EglJPBILSTwSDUk8Eg5JPBIRSTwSE0k8EhZJPBIYSTwSG0k8Eh5JPBIhSTwSJUk8EihJPBIsSTwSMEk8 + EjRJPBI5STwSPUk8EkJJPBJHSTwSTEk8ElJJPBJXSTwSXUk8EmNJPBJoSTwSbUk8EnJJPBJ3STwSfEk8 + EoBJPBKESTwSiEk8EoxJPBKQY1Qwq3JhQcJ+a0/YiHVa7JF9Zf+RfWX/kX1l/5F9Zf+RfWX/notz/6yZ + gf+/q5P/zbmh/9vHrv/bxq7/28at/9vGrP/bxaz/2sWr/9rFq//axKr/2sSq/9rEqf/aw6n/2sOp/9rD + qP/aw6j/2sKn/9rCp//awqb/2sGm/9rBpf/awaX/2sCk/9nApP/ZwKP/2b+j/9m/ov/Zv6L/2b6h/9m+ + of/ZvqD/2b2g/9m9n//ZvZ//2bye/9m8nv/ZvJ3/2byd/9i7nP/Yu5z/2Lub/7+ihv+mi3D/pYpw/6WK + b/+ih23/kn1l/456YfhRQxuNSTwSckk8EltJPBJESTwSL0k8Eh5JPBIRSTwSCUk8EgNHOxIBAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASTwSAUk8EgFJPBICSTwSA0k8 + EgRJPBIGSTwSCEk8EglJPBILSTwSDUk8Eg5JPBIRSTwSE0k8EhZJPBIYSTwSG0k8Eh5JPBIhSTwSJUk8 + EihJPBIsSTwSMEk8EjRJPBI5STwSPUk8EkFJPBJGSTwSS0k8ElBJPBJVSTwSWkk8El9JPBJkSTwSakk8 + EnBJPBJ2STwSe0k8En9JPBKESTwSiEk8EoxJPBKQXU4ppW1dPLx6aErRhHJX5ZF9Zf+RfWX/kX1l/5F9 + Zf+RfWX/notz/6yZgf+6p5D/yLae/9vIsf/byLD/28iw/9vHr//bx6//28eu/9vGrv/bxq3/28at/9vF + rP/bxaz/2sWr/9rFq//axKr/2sSq/9rEqf/aw6n/2sOo/9rDqP/awqf/2sKn/9rCpv/awab/2sGl/9rB + pf/awKT/2cCk/9nAo//Zv6P/2b+i/9m/ov/ZvqH/2b6h/9m+oP/ZvqD/2b2f/9m9n//ZvZ7/2bye/9m8 + nf/ZvJ3/2Luc/9i7nP/Yu5v/v6OG/6aLcP+minD/pYpv/6WJbv+ghmz/kn1l/4ZzWOFJPBJ6STwSY0k8 + EktJPBI1STwSIkk8EhNJPBIKSTwSBEg7EgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAEk8EgFJPBICSTwSBEk8EgZJPBIISTwSCkk8Eg1JPBIQSTwSEkk8EhVJPBIYSTwSG0k8 + Eh5JPBIhSTwSJUk8EihJPBIsSTwSMEk8EjRJPBI5STwSPUk8EkFJPBJGSTwSS0k8ElBJPBJVSTwSWkk8 + El9JPBJkSTwSaUk8Em1JPBJySTwSd0k8EnxJPBKBSTwShkk8EotJPBKQV0kin2hYNrV6aErRhHJX5ZF9 + Zf+RfWX/kX1l/5F9Zf+RfWX/moZv/6iVfv+2pIz/ybeg/9fFrv/byrP/28my/9vJsv/bybH/28ix/9vI + sP/byLD/28ev/9vHr//bx67/28eu/9vGrf/bxq3/28as/9vFrP/axav/2sWr/9rEqv/axKr/2sSp/9rD + qf/aw6j/2sOo/9rCp//awqf/2sKm/9rBpv/awaX/2sGl/9rApP/ZwKT/2cCj/9nAo//Zv6P/2b+i/9m/ + ov/ZvqH/2b6h/9m+oP/ZvZ//2b2f/9m9nv/ZvJ7/2byd/9m8nf/Yu53/2Luc/9i7nP+/o4b/potw/6aK + cP+lim//pYlu/6SIbf+ehGr/kX1l/2tbOaVJPBJpSTwSUEk8EjlJPBIlSTwSFkk8EgtJPBIFSDsSAQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEY6EQFIOxIBSTwSBEk8EgZJPBIJSTwSDEk8 + EhBJPBIUSTwSGEk8EhxJPBIgSTwSJEk8EihJPBIsSTwSMEk8EjRJPBI5STwSPUk8EkFJPBJGSTwSS0k8 + ElBJPBJVSTwSWkk8El9JPBJkSTwSaUk8Em1JPBJySTwSd0k8EnxJPBKASTwShEk8EohJPBKNV0kinWhY + NrN2ZUbKhHJX5Y56YfiRfWX/kX1l/5F9Zf+RfWX/lYJq/6ORef+2pI7/ybih/9fHsP/cy7X/3Mu1/9zL + tP/cy7T/3Mqz/9vKs//bybL/28my/9vJsf/bybH/28iw/9vIsP/byK//28ev/9vHrv/bx67/28at/9vG + rf/bxqz/28Ws/9rFq//axav/2sSq/9rEqv/axKn/2sOp/9rDqP/aw6j/2sKn/9rCp//awqb/2sGm/9rB + pv/awaX/2sGl/9nApP/ZwKT/2cCj/9m/o//Zv6L/2b+i/9m+of/ZvqH/2b6g/9m9oP/ZvZ//2b2f/9m8 + nv/ZvJ7/2byd/9i7nf/Yu5z/2Luc/7+jhv+mi3H/popw/6WKb/+liW7/pIlu/6SIbf+Vf2f/hnNZ3kk8 + Em1JPBJUSTwSPEk8EidJPBIXSTwSDEk8EgVIOxIBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAARjoRAkg7EgRJPBIHSTwSC0k8EhBJPBIWSTwSHEk8EiJJPBIoSTwSLUk8EjNJPBI4STwSPUk8 + EkFJPBJGSTwSS0k8ElBJPBJVSTwSWkk8El9JPBJkSTwSaUk8Em1JPBJySTwSd0k8EnxJPBKASTwShEk8 + EohJPBKMUEIalmNUMKt2ZUbJgW9T3ot3XvKRfWX/kX1l/5F9Zf+RfWX/lYJq/6ORev+2pY//xLSe/9LD + rf/czbj/3M23/9zNt//czLb/3My2/9zLtf/cy7X/3Mu0/9zLtP/cyrP/28qz/9vKsv/bybL/28mx/9vJ + sf/byLD/28iw/9vIr//bx6//28ev/9vHrv/bxq7/28at/9vGrP/bxaz/2sWr/9rFq//axKr/2sSq/9rE + qf/aw6n/2sOp/9rDqP/aw6j/2sKn/9rCp//awqb/2sGm/9rBpf/awaX/2sCk/9nApP/ZwKP/2b+j/9m/ + ov/Zv6L/2b6h/9m+of/ZvqD/2b2g/9m9n//ZvZ//2bye/9m8nv/ZvJ3/2byd/9i7nP/Yu5z/y6+R/6aL + cf+minD/pYpv/6WJbv+kiW7/pIht/5yDav+RfWX/WkwmgEk8ElhJPBI/STwSKkk8EhlJPBINSTwSBkg7 + EgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEQ4EAFGOhEDSDsSB0k8EgxJPBISSTwSGkk8 + EiNJPBIsSTwSNEk8EjxJPBJDSTwSSUk8Ek9JPBJUSTwSWkk8El9JPBJkSTwSaUk8Em1JPBJySTwSd0k8 + EnxJPBKASTwShEk8EohJPBKMSTwSkGNUMKtyYUHCgW9T3ot3XvKRfWX/kX1l/5F9Zf+RfWX/kX1l/6SR + ev+yoYv/wLCb/86/qv/cz7r/3M+6/9zOuf/czrn/3M24/9zNuP/czbf/3M23/9zMtv/czLb/3My1/9zL + tf/cy7T/3Mu0/9zKs//byrP/28qz/9vJsv/bybL/28mx/9vIsf/byLD/28iw/9vHr//bx6//28eu/9vG + rv/bxq3/28at/9vFrP/bxaz/2sWr/9rFq//axKr/2sSq/9rEqf/aw6n/2sOo/9rDqP/awqf/2sKn/9rC + pv/awab/2sGl/9rBpf/awKT/2cCk/9nAo//Zv6P/2b+i/9m/ov/ZvqH/2b6h/9m+oP/ZvqD/2b2f/9m9 + n//ZvZ7/2bye/9m8nf/ZvJ3/2Luc/9i7nP/Lr5H/potx/6aLcP+lim//pYlv/6SJbv+kiG3/oods/5F9 + Zf9oWDaSSTwSW0k8EkJJPBItSTwSG0k8Eg9JPBIHSDsSAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAARDgQAkY6EQVIOxILSTwSEkk8EhxJPBInSTwSMkk8Ej5JPBJJSTwSU0k8EltJPBJhSTwSZ0k8 + Em1JPBJySTwSd0k8EnxJPBKASTwShEk8EohJPBKMSTwSkGNUMKtyYUHCfmtP2Ih1WuyRfWX/kX1l/5F9 + Zf+RfWX/kX1l/5+Mdf+tnIb/wLGc/87Brf/d0b3/3dC8/93QvP/d0Lz/3c+7/93Pu//cz7r/3M65/9zO + uf/czrj/3M24/9zNt//czbf/3My2/9zMtv/czLb/3Mu1/9zLtf/cy7T/3Mq0/9zKs//byrP/28my/9vJ + sv/bybH/28ix/9vIsP/byLD/28ev/9vHr//bx67/28eu/9vGrf/bxq3/28as/9vFrP/axav/2sWr/9rE + qv/axKr/2sSp/9rDqf/aw6j/2sOo/9rCp//awqf/2sKm/9rBpv/awaX/2sGl/9rApP/ZwKT/2cCj/9nA + o//Zv6P/2b+i/9m/ov/ZvqH/2b6h/9m+oP/ZvZ//2b2f/9m9nv/ZvJ7/2byd/9m8nf/Yu53/2Luc/8uv + kf+mi3H/potw/6WKb/+liW//pIlu/6SIbf+jh2z/kX1l/3ppS7dJPBJeSTwSRUk8Ei9JPBIdSTwSEEk8 + EghIOxIDRTkRAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD40DwFEOBADRjoRCEg7EhBJPBIaSTwSJ0k8 + EjVJPBJDSTwSUUk8El9JPBJpSTwSckk8EnlJPBJ+STwSg0k8EohJPBKMSTwSkF1OKaVtXTy8emhK0YRy + V+WRfWX/kX1l/5F9Zf+RfWX/kX1l/5+Ndv+tnYf/u62Y/8q9qf/d0r//3dK//93Sv//d0b7/3dG+/93R + vf/d0L3/3dC8/93QvP/dz7v/3c+7/9zPuv/czrr/3M65/9zOuf/czbj/3M24/9zNt//czLf/3My2/9zM + tv/cy7X/3Mu1/9zLtP/cy7T/3Mqz/9vKs//bybL/28my/9vJsf/bybH/28iw/9vIsP/byK//28ev/9vH + rv/Vwaj/vKeN/6iSd/+eh23/inNY/4pzWP+Kc1j/mYJn/6OMcf+8pYv/1b6j/9rDqP/aw6j/2sKn/9rC + p//awqb/2sGm/9rBpv/awaX/2sGl/9nApP/ZwKT/2cCj/9m/o//Zv6L/2b+i/9m+of/ZvqH/2b6g/9m9 + oP/ZvZ//2b2f/9m8nv/ZvJ7/2byd/9i7nf/Yu5z/y6+R/6aLcf+mi3D/pYpv/6WJb/+kiW7/pIht/6OH + bP+RfWX/emhLuUk8EmFJPBJISTwSMkk8Eh9JPBISSTwSCUg7EgNFOREBAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAPzQPAkQ4EAZGOhEMSDsSFUk8EiJJPBIySTwSREk8ElVJPBJlSTwSc0k8En9JPBKHSTwSjldJ + Ip5oWDa0emhK0YRyV+WRfWX/kX1l/5F9Zf+RfWX/kX1l/5qIcP+pmIL/t6iU/8q+q//Zzrz/3dTC/93T + wf/d08H/3dLA/93SwP/d0r//3dK//93Rvv/d0b7/3dG9/93Qvf/d0Lz/3dC8/93Pu//dz7v/3M+6/9zO + uv/czrn/3M65/9zNuP/czbj/3M23/9zNt//czLb/3My2/9zLtf/cy7X/3Mu0/9zLtP/cyrP/28qz/9vK + sv/bybL/28mx/9vJsf/byLD/28iw/9vIr//Vwqn/sp2D/494Xf+Kc1j/inNY/4pzWP+Kc1j/inNY/4pz + WP+Kc1j/inNY/4pzWP+Kc1j/qJF2/9C5nv/aw6j/2sKn/9rCp//awqb/2sGm/9rBpf/awaX/2sCk/9nA + pP/ZwKP/2b+j/9m/ov/Zv6L/2b6h/9m+of/ZvqD/2b2g/9m9n//ZvZ//2bye/9m8nv/ZvJ3/2byd/9i7 + nP/Lr5H/p4tx/6aLcP+linD/pYlv/6SJbv+kiG3/o4ht/5F9Zf95aEq7STwSZUk8EkxJPBI1STwSIkk8 + EhNJPBIJRzsSBEY6EQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/NA8DRDgQCEY6ERBIOxIbSTwSK0k8 + Ej1JPBJRSTwSZVJEHH5rWjmod2VHxoVyV+SOemH4kX1l/5F9Zf+RfWX/kX1l/5WCa/+kk33/t6mV/8W6 + p//Z0L//3tXE/97VxP/e1cP/3tTD/97Uwv/d1ML/3dPB/93Twf/d08D/3dLA/93Sv//d0r//3dG+/93R + vv/d0b3/3dC9/93QvP/d0Lz/3c+7/93Pu//cz7r/3M+6/9zOuf/czrn/3M24/9zNuP/czbf/3M23/9zM + tv/czLb/3My1/9zLtf/cy7T/3Mu0/9zKs//byrP/28qz/9vJsv/bybL/28mx/9vIsf/byLD/wa2U/494 + Xf+Kc1j/inNY/4pzWP+Kc1j/n414/7Cikv+2qpz/saOU/6CPev+PemD/inNY/4pzWP+Kc1j/j3hd/7eg + hf/awqf/2sKn/9rCpv/awab/2sGl/9rBpf/awKT/2cCk/9nAo//Zv6P/2b+i/9m/ov/ZvqH/2b6h/9m+ + oP/ZvqD/2b2f/9m9n//ZvZ7/2bye/9m8nf/ZvJ3/2Luc/8uvkf+ni3H/potw/6WKcP+liW//pIlu/6SI + bf+jiG3/kX1l/3lnSrxJPBJoSTwST0k8EjhJPBIkSTwSFUk8EgpHOxIFRjoRAQAAAAAAAAAAAAAAAAAA + AAAAAAAAOS8OAT80DwREOBAKRjoRE0g7EiFJPBIzSTwSR0k8Elx7aUy2jnti9pF9Zf+RfWX/kX1l/5F9 + Zf+kk37/t6qW/8W7qf/Uy7v/3tfH/97Xxv/e1sb/3tbF/97Wxf/e1cT/3tXE/97Vw//e1MP/3tTC/93U + wv/d08H/3dPB/93TwP/d0sD/3dK//93Sv//d0b7/3dG+/93Rvf/d0b3/3dC8/93QvP/d0Lz/3c+7/93P + u//cz7r/3M65/9zOuf/czrj/3M24/9zNt//czbf/3My2/9zMtv/czLb/3Mu1/9zLtf/cy7T/3Mq0/9zK + s//byrP/28my/9vJsv/bybH/28mx/62Yfv+Kc1j/inNY/4pzWP+Uf2f/vbKl/9fTzv/e29j/393a/+De + 3P/i4N//4+Lh/+Tj4v/Iwbj/oI97/4pzWP+Kc1j/inNY/6OLcP/VvaL/2sKm/9rBpv/awaX/2sGl/9rA + pP/ZwKT/2cCj/9nAo//Zv6P/2b+i/9m/ov/ZvqH/2b6h/9m+oP/ZvZ//2b2f/9m9nv/ZvJ7/2byd/9m8 + nf/Yu53/2Luc/6eLcf+mi3D/pYpw/6WKb/+kiW7/pIht/6OIbf+Uf2b/eWdJvkk8EmtJPBJSSTwSOkk8 + EiZJPBIWSTwSC0c7EgVGOhEBAAAAAAAAAAAAAAAAAAAAAAgdMQE5Lw4BPzQPBUQ4EAtGOhEWSDsSJUk8 + EjhJPBJOiXZc1ZF9Zf+aiHH/s6WR/8G2pP/Qx7f/39nJ/97Yyf/e2Mj/3tjI/97Xx//e18f/3tfG/97W + xv/e1sX/3tbF/97VxP/e1cT/3tXD/97Uw//e1ML/3tTC/93Twf/d08H/3dPA/93SwP/d0r//3dK//93S + v//d0b7/3dG+/93Rvf/d0L3/3dC8/93QvP/dz7v/3c+7/9zPuv/czrr/3M65/9zOuf/czbj/3M24/9zN + t//czLf/3My2/9zMtv/cy7X/3Mu1/9zLtP/cy7T/3Mqz/9vKs//bybL/28my/9vJsf+ok3n/inNY/4pz + WP+OeF//taiZ/9jTzv/a1dD/29fT/9zY1P/d2tb/3tvY/9/d2v/g3tz/4uDf/+Pi4f/k4+L/yMG4/496 + YP+Kc1j/inNY/5mBZv/VvaL/2sGm/9rBpv/awaX/2sGl/9nApP/ZwKT/2cCj/9m/o//Zv6L/2b+i/9m+ + of/ZvqH/2b6g/9m9oP/ZvZ//2b2f/9m8nv/ZvJ7/2byd/9i7nf/Yu5z/p4tx/6aLcP+linD/pYpv/6SJ + bv+kiG3/o4ht/5V/Z/95Z0m/STwSbUk8ElNJPBI8STwSJ0k8EhdJPBILRzsSBUY6EQEAAAAAAAAAAAAA + AAAAAAAACB0xATkvDgI/NA8GRDgQDUY6ERhIOxIoSTwSPHhmSJGRfWX/uKuY/9/ay//f2sv/39nK/9/Z + yv/f2cn/3tjJ/97Yyf/e2Mj/3tfI/97Xx//e18b/3tbG/97Wxf/e1sX/3tXE/97VxP/e1cP/3tTD/97U + w//e1ML/3dTC/93Twf/d08H/3dPA/93SwP/d0r//3dK//93Rvv/d0b7/3dG9/93Qvf/d0Lz/3dC8/93P + u//dz7v/3M+6/9zOuv/czrn/3M65/9zNuP/czbj/3M23/9zNt//czLb/3My2/9zLtf/cy7X/3Mu0/9zL + tP/cyrP/28qz/9vKsv/bybL/sp6F/4pzWP+Kc1j/jnhe/8a8sf/Vzsj/1tDK/9fSzP/Y087/yL2y/7mo + l/+rlX//oohv/5p9Yf+rlX//sJuI/8K1qP/a1dH/2NXR/5qIcv+Kc1j/inNY/6OLcP/awqb/2sGm/9rB + pf/awaX/2sCk/9nApP/ZwKP/2b+j/9m/ov/Zv6L/2b6h/9m+of/ZvqD/2b2g/9m9n//ZvZ//2bye/9m8 + nv/ZvJ3/2byd/9i7nP+njHH/potw/6aKcP+lim//pYlu/6SIbf+kiG3/lX9n/4ZzWd9JPBJuSTwSVUk8 + Ej1JPBIoSTwSF0k8EgtHOxIFRjoRAQAAAAAAAAAAAAAAAAAAAAAIHTEBOS8OAj80DwZEOBANRjoRGEg7 + EihJPBI8i3dez6mahf/f2sz/39rM/9/ay//f2cv/39nK/9/Zyv/e2Mn/3tjJ/97YyP/e18j/3tfH/97X + xv/e1sb/3tbG/97Wxf/e1sX/3tXE/97VxP/e1cP/3tTD/97Uwv/d1ML/3dPB/93Twf/d08D/3dLA/93S + v//d0r//3dG+/93Rvv/d0b3/3dC9/93QvP/d0Lz/3c+7/93Pu//cz7r/3M+6/9zOuf/czrn/3M64/9zN + uP/czbf/3M23/9zMtv/czLb/3My1/9zLtf/cy7T/3Mu0/9zKs//byrP/28qz/8azm/+Kc1j/inNY/454 + Xv/DuKz/0srC/9PMxP/Uzcb/wLKj/6uUff+li3L/oYds/52CZv+afWH/mn1h/5p9Yf+afWH/mn1h/5p9 + Yf+1opD/1M7I/5qHcf+Kc1j/inNY/7Kaf//awab/2sGl/9rBpf/awKT/2cCk/9nAo//Zv6P/2b+i/9m/ + ov/ZvqH/2b6h/9m+oP/ZvqD/2b2f/9m9n//ZvZ7/2bye/9m8nf/ZvJ3/2Luc/6eMcf+mi3D/popw/6WK + b/+liW7/pIht/6SIbf+Vf2f/hnNZ30k8Em9JPBJWSTwSPUk8EihJPBIYSTwSDEc7EgVGOhEBAAAAAAAA + AAAAAAAAAAAAAAgdMQE5Lw4CPzQPBUQ4EAxGOhEXSDsSJ0k8EjyLd17PuKyZ/9/azP/f2sz/39rL/9/Z + y//f2cr/39nK/97Yyf/e2Mn/3tjI/97YyP/e18f/3tfH/97Xxv/e1sb/3tbF/97Wxf/e1cT/3tXE/97V + w//e1MP/3tTC/93Uwv/d08H/3dPB/93TwP/d0sD/3dK//93Sv//d0b7/3dG+/93Rvf/d0b3/3dC8/93Q + vP/d0Lz/3c+7/93Pu//cz7r/3M65/9zOuf/czrj/3M24/9zNt//czbf/3My3/9zMtv/czLb/3Mu1/9zL + tf/cy7T/3Mq0/9zKs//byrP/lH1j/4pzWP+Kc1j/vK+h/87FvP/Px77/y8G2/7ilk/+umYL/q5R8/6eP + d/+kinH/oIVq/5yAZP+afWH/mn1h/5p9Yf+afWH/mn1h/5p9Yf+eg2j/va6f/495YP+Kc1j/inNY/8uy + l//awaX/2sGl/9rApP/ZwKT/2cCj/9nAo//Zv6P/2b+i/9m/ov/ZvqH/2b6h/9m+oP/ZvZ//2b2f/9m9 + nv/ZvJ7/2bye/9m8nf/Yu53/p4xx/6aLcP+minD/pYpv/6WJbv+kiG3/pIht/5V/Z/+Gc1nfSTwSb0k8 + ElZJPBI+STwSKUk8EhhJPBIMRzsSBUY6EQEAAAAAAAAAAAAAAAAAAAAACB0xATkvDgE/NA8FRDgQDEY6 + ERZIOxImSTwSO4t3Xs+uoIz/39rM/9/azP/f2sv/39rL/9/Zyv/f2cr/39nJ/97Yyf/e2Mj/3tjI/97X + x//e18f/3tfG/97Wxv/e1sX/3tbF/97VxP/e1cT/3tXD/97Uw//e1ML/3tTC/93Twf/d08H/3dPA/93S + wP/d0sD/3dK//93Sv//d0b7/3dG+/93Rvf/d0L3/3dC8/93QvP/dz7v/3c+7/9zPuv/czrr/3M65/9zO + uf/czbj/3M24/9zNt//czLf/3My2/9zMtv/cy7X/3Mu1/9zLtP/cy7T/3Mqz/7Kehf+Kc1j/inNY/6mZ + hv/LwLb/zMK4/8m+s/+5p5X/taGN/7Gdh/+umIH/qpN7/6aOdf+jiW7/noNo/5t+Yv+afWH/mn1h/5p9 + Yf+afWH/mn1h/5p9Yf+afWH/mYBm/4pzWP+Kc1j/noZr/9rBpv/awaX/2sGl/9nApP/ZwKT/2cCj/9m/ + o//Zv6L/2b+i/9m+of/ZvqH/2b6g/9m9oP/ZvZ//2b2f/9m8nv/ZvJ7/2byd/9i7nf+njHH/potx/6aK + cP+lim//pYlu/6SJbv+kiG3/lX9n/4ZzWd9JPBJvSTwSVkk8Ej5JPBIpSTwSGEk8EgxHOxIFRjoRAQAA + AAAAAAAAAAAAAAAAAAAAAAAAOS8OAT80DwREOBALRjoRFUg7EiRJPBI4i3hezqSUf//f28z/39rM/9/a + y//f2sv/39nK/9/Zyv/f2cn/3tjJ/9nSwv/Nwa7/zcCu/97Xx//e18b/3tbG/97Wxf/e1sX/3tXE/97V + xP/e1cP/3tTD/97Uw//e1ML/3dTC/93Twf/d08H/3dPA/93SwP/d0r//3dK//93Rvv/d0b7/3dG9/93Q + vf/d0Lz/3dC8/93Pu//dz7v/3M+6/9zOuv/czrn/3M65/9zNuP/czbj/3M23/9zNt//czLb/3My2/9zM + tf/cy7X/3Mu0/9zLtP/cyrP/lH1j/4pzWP+Nd13/w7eq/8i9sv/IvLH/v6+e/7uqmP+4pZL/tKCM/7Gb + hv+tloD/qZF5/6WMcv+hhmz/nYBk/5p9Yf+afWH/mn1h/5p9Yf+afWH/mn1h/5p9Yf+afWH/k3hd/4pz + WP+Kc1j/xq2S/9rBpf/awaX/2sCk/9nApP/ZwKP/2b+j/9m/ov/Zv6L/2b6h/9m+of/ZvqD/2b2g/9m9 + n//ZvZ//2bye/9m8nv/ZvJ3/2byd/7OXfP+mi3H/popw/6WKb/+liW7/pIlu/6SIbf+agmn/hnNY30k8 + EnBJPBJWSTwSPkk8EilJPBIYSTwSDEc7EgVGOhEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPzQPA0Q4 + EApGOhETSDsSIkk8EjaBblKjmohy/9/bzP/f2sz/39rM/9/ay//f2cv/39nK/9/Zyv/EtqH/mn1g/5p9 + YP+afWD/po1z/9nRwP/e1sb/3tbG/97Wxf/e1sX/3tXE/97VxP/e1cP/3tTD/97Uwv/d1ML/3dPB/93T + wf/d08D/3dLA/93Sv//d0r//3dG+/93Rvv/d0b3/3dC9/93QvP/d0Lz/3c+7/93Pu//cz7r/3M+6/9zO + uf/czrn/3M64/9zNuP/czbf/3M23/9zMtv/czLb/3My1/9zLtf/cy7T/3Mu0/72pkf+Kc1j/inNY/6eV + gf/FuKz/xrqu/8W3qf/CsqL/vq6d/7upl/+3pJH/s5+L/6+ahP+rlH3/oYhw/5Z8Y/+Sd17/kHVb/5V5 + Xv+afWH/mn1h/5p9Yf+afWH/mn1h/5p9Yf+afWH/j3Za/4pzWP+okHX/2sGl/9rBpf/awKT/2cCk/9nA + o//Zv6P/2b+i/9m/ov/ZvqH/2b6h/9m+oP/ZvqD/2b2f/9m9n//ZvZ7/2bye/9m8nf/ZvJ3/s5h8/6aL + cf+mi3D/pYpv/6WJb/+kiW7/pIht/5qCaf+Gc1jfSTwScEk8ElZJPBI+STwSKUk8EhhJPBIMRzsSBUY6 + EQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/NA8DRDgQCUY6ERJIOxIgSTwSNIFvU6KRfWX/39vN/9/a + zP/f2sz/39rL/9/Zy//f2cr/1s28/5p9YP++rp3/2tLL/8a4qf+dgWX/wK+Z/97Xxv/e1sb/3tbF/97W + xf/e1cT/3tXE/97Vw//e1MP/3tTC/93Uwv/d08H/3dPB/93TwP/d0sD/3dK//93Sv//d0b7/3dG+/93R + vf/d0b3/3dC8/93QvP/d0Lz/3c+7/93Pu//cz7r/3M65/9zOuf/czrj/3M24/9zNt//czbf/3My3/9zM + tv/czLb/3Mu1/9zLtf/cy7T/o450/4pzWP+Kc1j/vrCh/8O1qP/Huq3/yLqs/8W2p//BsqL/vq2c/7qo + lf+2oo//qpR+/5B3YP+HbVX/h21V/4dtVf+HbVX/h21V/4lvVv+VeV7/mn1h/5p9Yf+afWH/mn1h/5p9 + Yf+ZfGD/i3NY/4pzWP/VvKD/2sGl/9rApP/ZwKT/2cCk/9nAo//Zv6P/2b+i/9m/ov/ZvqH/2b6h/9m+ + oP/ZvZ//2b2f/9m9nv/ZvJ7/2bye/9m8nf+zmHz/potx/6aLcP+lim//pYlv/6SJbv+kiG3/moJp/5F9 + Zf9JPBJwSTwSVkk8Ej5JPBIpSTwSGEk8EgxHOxIFRjoRAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD80 + DwNEOBAIRjoREUg7Eh9JPBIxcF8/dJF9Zf/Vz8D/39rM/9/azP/f2sv/39rL/9/Zyv/Nwq//mn1g/+Xh + 3f/a0sv/0MS5/6aMc/+3pI3/3tfG/97Wxv/e1sX/3tbF/97VxP/e1cT/3tXD/97Uw//e1ML/3tTC/93T + wf/d08H/3dPA/93SwP/d0sD/3dK//93Sv//d0b7/3dG+/93Rvf/d0L3/3dC8/93QvP/dz7v/3c+7/9zP + uv/czrr/3M65/9zOuf/czbj/3M24/9zNt//czLf/3My2/9zMtv/cy7X/3Mu1/9zLtP+PeF3/inNY/5qF + bv+/sKL/wrWn/87Ct//Lv7L/yLqs/8S1pv/AsKD/vKuZ/6+bh/+JcFj/h21V/4dtVf+HbVX/h21V/4dt + Vf+HbVX/h21V/4dtVf+Sd1z/mn1h/5p9Yf+afWH/mn1h/5p9Yf+SeFz/inNY/8Gojf/awaX/2sGl/9rA + pP/ZwKT/2cCj/9m/o//Zv6L/2b+i/9m+of/ZvqH/2b6g/9m9oP/ZvZ//2b2f/9m8nv/ZvJ7/2byd/7OY + fP+ni3H/potw/6WKcP+liW//pIlu/6SIbf+agmn/kX1l/0k8EnBJPBJWSTwSPkk8EilJPBIYSTwSDEc7 + EgVGOhEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPzQPA0Q4EAdGOhEQSDsSHUk8Ei9qWjhnkX1l/8vD + s//f28z/39rM/9/ay//f2sv/39nK/83Cr/+afWD/5eHd/9rSyv/PxLn/sZuG/6uTef/e18b/3tbG/97W + xf/e1sX/3tXE/97VxP/e1cP/3tTD/97Uw//e1ML/3dTC/93Twf/d08H/3dPA/93SwP/d0r//3dK//93R + vv/d0b7/3dG9/93Qvf/d0Lz/3dC8/93Pu//dz7v/3M+6/9zOuv/czrn/3M65/9zNuP/czbj/3M23/9zN + t//czLb/3My2/9zMtf/cy7X/zLqj/4pzWP+Kc1j/ppN+/72tnv/JvbD/0se9/87Dt//LvrH/x7mr/8Oz + pP+4ppT/inBZ/4dtVf+HbVX/h21V/4dtVf+HbVX/mYZz/6+ilf+xpZj/nYp3/4dtVf+UeF3/mn1h/5p9 + Yf+afWH/mn1h/5h7X/+Kc1j/rZV6/9rBpf/awaX/2sCk/9nApP/ZwKP/2b+j/9m/ov/Zv6L/2b6h/9m+ + of/ZvqD/2b2g/9m9n//ZvZ//2bye/9m8nv/ZvJ3/s5h8/6eLcf+mi3D/pYpw/6WJb/+kiW7/pIht/5qC + af+RfWX/STwScEk8ElZJPBI+STwSKUk8EhhJPBIMRzsSBUY6EQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAA/NA8DRDgQB0Y6EQ9IOxIbSTwSLEk8EkKRfWX/wbem/9/bzP/f2sz/39rM/9/ay//f2cv/2tPD/5p9 + YP/Rxrz/2tLK/8/EuP+zn4r/oohs/97Xx//e1sb/3tbG/97Wxf/e1sX/3tXE/97VxP/e1cP/3tTD/97U + wv/d1ML/3dPB/93Twf/d08D/3dLA/93Sv//d0r//3dG+/93Rvv/d0b3/3dC9/93QvP/d0Lz/3c+7/93P + u//cz7r/3M+6/9zOuf/czrn/3M64/9zNuP/czbf/3M23/9zMtv/czLb/3My1/9zLtf+9qpL/inNY/4pz + WP+um4j/u6qa/9TLwv/Vy8L/0ce8/83Btf/JvK//xbao/5mCbf+HbVX/h21V/4dtVf+HbVX/h21V/6OT + g/+/t67/xr62/8nDu//Kw7z/sKKU/4huVf+YfGD/mn1h/5p9Yf+afWH/mn1h/492Wv+ehmv/2sGl/9rB + pf/awKT/2cCk/9nAo//ZwKP/2b+i/9m/ov/ZvqH/2b6h/9m+oP/ZvqD/2b2f/9m9n//ZvZ7/2bye/9m8 + nf+zmHz/p4tx/6aLcP+linD/pYpv/6SJbv+kiG3/moJp/5F9Zf9JPBJwSTwSVkk8Ej5JPBIpSTwSGEk8 + EgxHOxIFRjoRAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD80DwJEOBAFRjoRDUg7EhlJPBIpSTwSPo97 + Y/O4rJn/39vN/9/azP/f2sz/39rL/9/Zy//f2cr/mn1g/8zAs//a0sr/z8S4/7upl/+afWD/3tfH/97X + xv/e1sb/3tbF/97Wxf/e1cT/3tXE/97Vw//e1MP/3tTC/93Uwv/d08H/3dPB/93TwP/d0sD/3dK//93S + v//d0b7/3dG+/93Rvf/d0b3/3dC9/93QvP/d0Lz/3c+7/93Pu//cz7r/3M65/9zOuf/czrj/3M24/9zN + t//czbf/3My3/9zMtv/czLb/3Mu1/7Ofhv+Kc1j/inNY/7ellP+9rZ3/29TN/9jPx//UysD/0MS5/8u/ + sv+/r6D/h21V/4dtVf+HbVX/h21V/4dtVf+NdV//vrat/8jBuf/QysP/1M/J/9XQyv/SzMb/nYl3/5F2 + W/+afWH/mn1h/5p9Yf+afWH/k3hd/4pzWP/awaX/2sGl/9rApP/ZwKT/2cCk/9nAo//Zv6P/2b+i/9m/ + ov/ZvqH/2b6h/9m+oP/ZvZ//2b2f/9m9nv/ZvJ7/2bye/8Ckh/+ni3H/potw/6WKcP+lim//pIlu/6SI + bf+fhWv/kX1l/0k8EnBJPBJWSTwSPkk8EilJPBIYSTwSDEc7EgVGOhEBAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAPzQPAUQ4EAVGOhEMSDsSF0k8EidJPBI7i3dez66gjP/f283/39rM/9/azP/f2sv/39rL/9/Z + yv+rlHr/vq2b/9nRyf/Pw7j/wLCf/5p9YP/RxrP/3tfG/97Wxv/e1sX/3tbF/97VxP/e1cT/3tXD/97U + w//e1ML/3tTC/93Twf/d08H/3dPA/93SwP/d0sD/3dK//93Sv//d0b7/3dG+/93Rvf/d0L3/3dC8/93Q + vP/dz7v/3c+7/9zPuv/czrr/3M65/9zOuf/czbj/3M24/9zNt//czLf/3My2/9zMtv/cy7X/s5+G/4pz + WP+Kc1j/taKQ/8a5q//e2NH/2tPL/9bNxP/Sx73/zcG1/6iUgv+HbVX/h21V/4dtVf+HbVX/h21V/6SU + hP/FvbX/0MrD/9nUz//f29f/4NzY/9zY0//GvbT/inBX/5p9Yf+afWH/mn1h/5p9Yf+Wel7/inNY/9rB + pv/awaX/2sGl/9rApP/ZwKT/2cCj/9m/o//Zv6L/2b+i/9m+of/ZvqH/2b6g/9m9oP/ZvZ//2b2f/9m8 + nv/ZvJ7/wKSH/6eLcf+mi3D/pYpw/6WKb/+kiW7/pIht/5+Fa/+RfWX/STwScEk8ElZJPBI+STwSKUk8 + EhhJPBIMRzsSBUY6EQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/NA8BRDgQBEY6EQtIOxIVSTwSJUk8 + EjmJdlzEpJR//9/bzf/f28z/39rM/9/ay//f2sv/39nK/6+Zgf+0oIz/2dHJ/8/DuP/Ftqj/mn1g/83A + rf/e18b/3tbG/97Wxf/e1sX/3tXE/97VxP/e1cT/3tTD/97Uw//e1ML/3dTC/93Twf/d08H/3dPA/93S + wP/d0r//3dK//93Rvv/d0b7/3dG9/93Qvf/d0Lz/3dC8/93Pu//dz7v/3M+6/9zOuv/czrn/3M65/9zN + uP/czbj/3M23/9zNt//czLb/3My2/9zMtf+zn4b/inNY/4pzWP+zn4v/zMC0/+Hb1f/c1c7/2M/H/9PJ + v//Ow7f/mIFs/4dtVf+HbVX/h21V/4dtVf+HbVX/tKic/8nDu//V0Mv/4d3Z/+nn5P/r6eb/5eLe/9vW + 0f+QeWP/mn1h/5p9Yf+afWH/mn1h/5l8YP+Kc1j/2sGm/9rBpf/awaX/2sCk/9nApP/ZwKP/2b+j/9m/ + ov/Zv6L/2b6h/9m+of/ZvqD/2b2g/9m9n//ZvZ//2bye/9m8nv/ApIj/p4xx/6aLcP+minD/pYpv/6WJ + bv+kiG3/n4Vr/5F9Zf9pWDaPSTwSVkk8Ej5JPBIpSTwSGEk8EgxHOxIFRjoRAQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABEOBADRjoRCkg7EhNJPBIiSTwSNoFuUqOaiHL/39vN/9/bzf/f2sz/39rM/9/a + y//f2cv/vKuV/6uUff/Z0cn/zsO4/8W2qP+eg2f/vKqT/97Xx//e1sb/3tbG/97Wxf/e1sX/3tXE/97V + xP/e1cP/3tTD/97Uwv/d1ML/3dPB/93Twf/d08D/3dLA/93Sv//d0r//3dG+/93Rvv/d0b3/3dC9/93Q + vP/d0Lz/3c+7/93Pu//cz7r/3M+6/9zOuf/czrn/3M64/9zNuP/czbf/3M23/9zMtv/czLb/3My1/7Of + hv+Kc1j/inNY/7CciP/LwLT/4t3Y/97X0P/Z0cn/1MrA/8/EuP+YgWz/h21V/4dtVf+HbVX/h21V/4dt + Vf+/t67/zMa//9nVz//m49//8vDu//b08//s6ef/39vX/5uGcv+VeV7/mn1h/5p9Yf+afWH/mn1h/4pz + WP/awab/2sGl/9rBpf/awKT/2cCk/9nAo//ZwKP/2b+i/9m/ov/ZvqH/2b6h/9m+of/ZvqD/2b2f/9m9 + n//ZvZ7/2bye/8CkiP+njHH/potw/6aKcP+lim//pYlu/6SIbf+fhWv/kX1l/2lYNo9JPBJWSTwSPkk8 + EilJPBIYSTwSDEc7EgVGOhEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEQ4EANGOhEJSDsSEkk8 + EiBJPBI0fmtPl5F9Zf/f283/4NzO/9/bzf/f2sz/39rL/9/ay//AsJz/noJn/9nRyf/Ow7f/xLan/6OJ + b/+3pI3/3tfH/97Xxv/e1sb/3tbF/97Wxf/e1cT/3tXE/97Vw//e1MP/3tTC/93Uwv/d08H/3dPB/93T + wP/d0sD/3dK//93Sv//d0b7/3dG+/93Rvf/d0b3/3dC9/93QvP/d0Lz/3c+7/93Pu//cz7r/3M65/9zO + uf/czrj/3M24/9zNt//czbf/3My3/9zMtv/czLb/s5+G/4pzWP+Kc1j/rpmD/8u/sv/j39r/3tjS/9nR + yf/Uy8H/z8S5/5iCbP+HbVX/h21V/4dtVf+HbVX/h21V/7+3rv/Mxr//2tXQ/+fk4P/z8vD/+Pf2/+3r + 6P/g3Nj/pJKB/5V5Xv+afWH/mn1h/5p9Yf+afWH/inNY/9rBpv/awaX/2sGl/9rApP/ZwKT/2cCk/9nA + o//Zv6P/2b+i/9m/ov/ZvqH/2b6h/9m+oP/ZvZ//2b2f/9m9nv/ZvJ7/wKSI/6eMcf+mi3H/popw/6WK + b/+liW7/pIlu/5+Fa/+RfWX/aVg2j0k8EldJPBI/STwSKUk8EhhJPBIMRzsSBUY6EQEAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAARDgQA0Y6EQhIOxIRSTwSH0k8EjFwXz90kX1l/9XPwP/f3M7/4NvO/9/a + zP/f2sv/39rL/83CsP+afWD/2dDI/87Dt//Etaf/qZF5/6uTef/e18f/3tfG/97Wxv/e1sX/3tbF/97V + xP/e1cT/3tXD/97Uw//e1ML/3tTC/93Twf/d08H/3dPA/93SwP/d0sD/3dK//93Sv//d0b7/3dG+/93R + vf/d0L3/3dC8/93QvP/dz7v/3c+7/9zPuv/czrr/3M65/9zOuf/czbj/3M24/9zNt//czLf/3My2/9zM + tv+zn4b/inNY/4pzWP+pk33/ybyw/+Pe2f/e19H/2dHJ/9TKwf/PxLn/mIFs/4dtVf+HbVX/h21V/4dt + Vf+HbVX/urGm/8rDvP/W0sz/4t/b/+zq5//v7er/6OXi/93Z1P+kkoD/lXle/5p9Yf+afWH/mn1h/5p9 + Yf+Kc1j/2sGm/9rBpv/awaX/2sGl/9rApP/ZwKT/2cCj/9m/o//Zv6L/2b+i/9m+of/ZvqH/2b6g/9m9 + oP/ZvZ//2b2f/9m8nv/ApIj/p4xx/6aLcf+minD/pYpv/6WJbv+kiW7/oIVr/5F9Zf9oWDaPSTwSWEk8 + EkBJPBIqSTwSGUk8Eg1HOxIGRjoRAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABEOBADRjoRB0g7 + EhBJPBIdSTwSL2paOGeRfWX/y8Oz/+Dcz//g3M7/4NvN/9/azP/f2sv/1s69/5p9YP/Iuqz/zsK2/8S1 + pv+slH3/ooht/97Xx//e18b/3tbG/97Wxf/e1sX/3tXE/97VxP/e1cT/3tTD/97Uw//e1ML/3dTC/93T + wf/d08H/3dPA/93SwP/d0r//3dK//93Rvv/d0b7/3dG9/93Qvf/d0Lz/3dC8/93Pu//dz7v/3M+6/9zO + uv/czrn/3M65/9zNuP/czbj/3M23/9zNt//czLb/3My2/8e1nv+Kc1j/inNY/6KLc//Huqz/4dzW/93W + z//Y0Mf/08rA/8/DuP+chnL/h21V/4dtVf+HbVX/h21V/4dtVf+uoZT/xb62/9HLxf/b1tH/4t7a/+Tg + 3P/f29f/19LM/5mEcP+Xe1//mn1h/5p9Yf+afWH/l3tf/5mBZv/awqb/2sGm/9rBpf/awaX/2sCk/9nA + pP/ZwKP/2b+j/9m/ov/Zv6L/2b6h/9m+of/ZvqD/2b6g/9m9n//ZvZ//2bye/8ywk/+njHL/potx/6aL + cP+lim//pYlv/6SJbv+kiG3/kX1l/2hYNpFJPBJZSTwSQUk8EitJPBIaSTwSDkc7EgZGOhECAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEQ4EANGOhEHSDsSD0k8EhtJPBIsSTwSQpF9Zf/Bt6b/4NzO/+Hd + 0P/g3M7/4NvN/9/azP/f2sv/mn5h/8i6rP/Owrb/xLWm/7Ofiv+afWD/3tfH/97Xx//e1sb/3tbG/97W + xf/e1sX/3tXE/97VxP/e1cP/3tTD/97Uwv/d1ML/3dPB/93Twf/d08D/3dLA/93Sv//d0r//3dG+/93R + vv/d0b3/3dC9/93QvP/d0Lz/3c+7/93Pu//cz7r/3M+6/9zOuf/czrn/3M64/9zNuP/czbf/3M23/9zM + tv/czLb/0cCq/4pzWP+Kc1j/mIFo/7ajkf/f2dL/29PM/9fOxf/SyL3/zsK2/6yaiP+HbVX/h21V/4dt + Vf+HbVX/h21V/5yKd/+/t67/ycO7/9LMxv/X0s3/2NTO/9XQyv/PycH/jXRd/5p9Yf+afWH/mn1h/5p9 + Yf+VeV7/o4tw/9rCpv/awab/2sGl/9rBpf/awKT/2cCk/9nAo//ZwKP/2b+i/9m/ov/ZvqH/2b6h/9m+ + of/ZvqD/2b2f/9m9n//ZvZ7/zLCT/6eMcv+mi3H/potw/6WKb/+liW//pIlu/6SIbf+RfWX/aFg2kkk8 + EltJPBJDSTwSLUk8EhtJPBIPRzsSB0Y6EQIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARDgQAkY6 + EQVIOxINSTwSGUk8EilJPBI+j3tj87ismf/g3M7/4d3Q/+Hcz//g287/4NvN/+DbzP+okHX/uKWS/87C + tv/Etab/taKN/5p9YP/RxrT/3tfH/97Xxv/e1sb/3tbF/97Wxf/e1cT/3tXE/97Vw//e1MP/3tTC/93U + wv/d08H/3dPB/93TwP/d0sD/3dK//93Sv//d0b7/3dG+/93Rvf/d0b3/3dC9/93QvP/d0Lz/3c+7/93P + u//cz7r/3M65/9zOuf/czrj/3M24/9zNuP/czbf/3My3/9zMtv/czLb/lH5j/4pzWP+Pd13/po51/9zV + zv/Y0Mj/1cvB/9HFu//MwLP/wLCh/4dtVf+HbVX/h21V/4dtVf+HbVX/iXBZ/7WroP/BubD/yMG5/8zG + v//Nx8D/y8S9/7Ommf+PdFr/mn1h/5p9Yf+afWH/mn1h/5F3W/+3n4T/2sKm/9rBpv/awaX/2sGl/9rA + pP/ZwKT/2cCk/9nAo//Zv6P/2b+i/9m/ov/ZvqH/2b6h/9m+oP/ZvZ//2b2f/9m9n//MsJP/p4xy/6aL + cf+mi3D/pYpv/6WJb/+kiW7/pIht/5F9Zf96aUu4STwSXkk8EkVJPBIvSTwSHUk8EhBHOxIIRjoRA0I2 + EAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABEOBABRjoRBUg7EgxJPBIXSTwSJ0k8EjuLd17PrqCM/9/b + zv/i3tH/4d3Q/+Hcz//g3M7/4NvN/62Xfv+1oY3/zsK2/8S0pv+7qZb/mn1g/83Arf/e18f/3tfG/97W + xv/e1sX/3tbF/97VxP/e1cT/3tXD/97Uw//e1ML/3tTC/93Twf/d08H/3dPB/93SwP/d0sD/3dK//93S + v//d0b7/3dG+/93Rvf/d0L3/3dC8/93QvP/dz7v/3c+7/9zPuv/czrr/3M65/9zOuf/czbj/3M24/9zN + t//czLf/3My2/9zMtv+tmYH/inNY/4pzWP+fhm3/yLut/9bNw//Sx73/zsO3/8q9sP/Gt6n/nYdy/4dt + Vf+HbVX/h21V/4dtVf+HbVX/l4Rw/7eupP++taz/wbmx/8K7sv+9tKr/jnZg/5d7X/+afWH/mn1h/5p9 + Yf+afWH/jHRZ/9C4nf/awqf/2sGm/9rBpv/awaX/2sGl/9rApP/ZwKT/2cCj/9m/o//Zv6L/2b+i/9m+ + of/ZvqH/2b6g/9m9oP/ZvZ//2b2f/8ywk/+njHL/p4tx/6aLcP+linD/pYlv/6SJbv+kiG3/kX1l/3po + SrlJPBJhSTwSSEk8EjJJPBIfSTwSEkc7EglGOhEDQjYQAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEQ4 + EAFGOhEESDsSC0k8EhVJPBIlSTwSOYl2XMSklH//39vO/+Le0v/i3tH/4d3Q/+Hcz//h3M3/v6+a/6uU + fP/Pw7f/xLWm/7uolv+dgWX/vKqU/97Xx//e18b/3tbG/97Wxf/e1sX/3tXE/97VxP/e1cT/3tTD/97U + w//e1ML/3dTC/93Twf/d08H/3dPA/93SwP/d0r//3dK//93Rvv/d0b7/3dG9/93Qvf/d0Lz/3dC8/93P + u//dz7v/3M+6/9zOuv/czrn/3M65/9zNuP/czbj/3M23/9zNt//czLb/3My2/8y7pP+Kc1j/inNY/5N6 + YP+1oY7/0si+/8/Euf/Mv7P/yLqs/8S1pv+8q5r/inBZ/4dtVf+HbVX/h21V/4dtVf+HbVX/lH9r/66i + lv+2raP/r6OW/5B5ZP+QdVv/mn1h/5p9Yf+afWH/mn1h/5Z6Xv+Zgmf/2sKn/9rCp//awqb/2sGm/9rB + pf/awaX/2sCk/9nApP/ZwKP/2b+j/9m/ov/Zv6L/2b6h/9m+of/ZvqD/2b6g/9m9n//ZvZ//zLGT/6eM + cv+ni3H/potw/6WKcP+liW//pIlu/6SIbf+RfWX/eWhKu0k8EmVJPBJMSTwSNUk8EiJJPBITRzsSCUU5 + EQRCNxABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEY6EQNIOxIKSTwSE0k8EiJJPBI2gW5So5qI + cv/f283/49/T/+Lf0v/i3tD/4d3Q/+Hczv/EtaL/poxz/8/DuP/Ftqf/u6mX/6CGa/+3pI3/3tfH/97X + x//e1sb/3tbG/97Wxf/e1sX/3tXE/97VxP/e1cP/3tTD/97Uwv/d1ML/3dPB/93Twf/d08D/3dLA/93S + v//d0r//3dG+/93Rvv/d0b3/3dC9/93QvP/d0Lz/3c+7/93Pu//cz7r/3M+6/9zOuf/czrn/3M64/9zN + uP/czbf/3M23/9zMtv/czLb/3My1/56Jb/+Kc1j/inNY/56Eaf/JvK//zMC0/8m8rv/Ft6j/wbKi/72s + m/+wnIj/inBY/4dtVf+HbVX/h21V/4dtVf+HbVX/h21V/4dtVf+HbVX/jnNZ/5p9Yf+afWH/mn1h/5p9 + Yf+afWH/jnVa/7yliv/awqf/2sKn/9rCpv/awab/2sGl/9rBpf/awKT/2cCk/9nAo//ZwKP/2b+i/9m/ + ov/ZvqH/2b6h/9m+of/ZvqD/2b2f/9m9n//MsZT/p4xy/6eLcf+mi3D/pYpw/6WKb/+kiW7/pIht/5N+ + Zv95Z0q8STwSaEk8Ek9JPBI4STwSJEk8EhVHOxIKRTkRBUI3EAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAARjoRA0g7EglJPBISSTwSIEk8EjR+a0+XkX1l/9/bzf/i39L/49/T/+Le0v/i3dH/4t3P/9HH + tv+ghWr/0MS5/8W3qP+8q5j/po10/6uTev/e18f/3tfH/97Xxv/e1sb/3tbF/97Wxf/e1cT/3tXE/97V + w//e1MP/3tTC/93Uwv/d08H/3dPB/93TwP/d0sD/3dK//93Sv//d0b7/3dG+/93Rvf/d0b3/3dC9/93Q + vP/d0Lz/3c+7/93Pu//cz7r/3M65/9zOuf/czrj/3M24/9zNuP/czbf/3My3/9zMtv/czLb/x7Wd/4pz + WP+Kc1j/j3dc/6qTe//JvK7/xrip/8OzpP+/rp7/u6mX/7ekkf+rlYD/kXhg/4dtVf+HbVX/h21V/4dt + Vf+HbVX/h21V/5B1W/+afWH/mn1h/5p9Yf+afWH/mn1h/5V5Xv+UfWL/2sOo/9rCp//awqf/2sKm/9rB + pv/awaX/2sGl/9rBpf/ZwKT/2cCk/9nAo//Zv6P/2b+i/9m/ov/ZvqH/2b6h/9m+oP/ZvZ//2b2f/9m9 + n/+njHL/p4tx/6aLcP+linD/pYpv/6SJbv+kiG3/lX9n/3lnSb5JPBJrSTwSUkk8EjpJPBImSTwSFkc7 + EgtFOREFQjcQAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABGOhEDSDsSCEk8EhFJPBIfSTwSMXBf + P3SRfWX/1c/A/+Lf0v/j4NP/49/T/+Le0f/i3dD/1s29/6KHbP/HuKr/xriq/72smv+pkXr/qI91/97X + x//e18f/3tfG/97Wxv/e1sX/3tbF/97VxP/e1cT/3tXD/97Uw//e1ML/3tTC/93Twf/d08H/3dPB/93S + wP/d0sD/3dK//93Sv//d0b7/3dG+/93Rvf/d0L3/3dC8/93QvP/dz7v/3c+7/9zPuv/czrr/3M65/9zO + uf/czbj/3M24/9zNt//czLf/3My2/9zMtv/cy7X/o451/4pzWP+Kc1j/k3pf/7Sgi//Ds6T/wK+f/7yr + mf+5ppP/taGN/7Gbhv+tloD/oopy/5V7Y/+TeF//kXZb/5F2W/+YfGD/mn1h/5p9Yf+afWH/mn1h/5p9 + Yf+Ye1//i3NY/8Gqj//aw6j/2sOo/9rCp//awqf/2sGm/9rBpv/awaX/2sGl/9rApP/ZwKT/2cCj/9m/ + o//Zv6L/2b+i/9m+of/ZvqH/2b6g/9m9oP/ZvZ//2b2f/6eMcv+njHH/potw/6aKcP+lim//pYlu/6SI + bf+Vf2f/eWdJv0k8Em1JPBJTSTwSPEk8EidJPBIXRzsSC0U5EQVCNxABAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAEY6EQNIOxIHSTwSEEk8Eh1JPBIvalo4Z5F9Zf/Lw7P/4t7S/+Tg1P/j4NP/49/S/+Pe + 0f/i3tD/o4lv/8S1pf/Huar/vq2b/7Cbhf+dgWX/3tjI/97Xx//e18b/3tbG/97Wxf/e1sX/3tXE/97V + xP/e1cT/3tTD/97Uw//e1ML/3dTC/93Twf/d08H/3dPA/93SwP/d0r//3dK//93Rvv/d0b7/3dG9/93Q + vf/d0Lz/3dC8/93Pu//dz7v/3M+6/9zOuv/czrn/3M65/9zNuP/czbj/3M23/9zNt//czLb/3My2/9zM + tf/Wxa//j3hd/4pzWP+Kc1j/lXtf/7KdiP+8q5n/uaeU/7aijv+ynYj/rpiC/6qTfP+mjnX/oohu/56C + Z/+afWH/mn1h/5p9Yf+afWH/mn1h/5p9Yf+afWH/mXxg/410Wf+jjHH/2sOp/9rDqP/aw6j/2sKn/9rC + p//awqb/2sGm/9rBpf/awaX/2sCk/9nApP/ZwKP/2b+j/9m/ov/Zv6L/2b6h/9m+of/ZvqD/2b6g/9m9 + n//ZvZ//p4xy/6eMcf+mi3D/popw/6WKb/+liW7/pIht/5V/Z/+Gc1nfSTwSbkk8ElVJPBI9STwSKEk8 + EhdHOxILRTkRBUI3EAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARjoRA0g7EgdJPBIPSTwSG0k8 + EixJPBJCkX1l/8G3pv/i3tH/5OHV/+Tg1P/j39P/49/S/+Pe0f+slX3/vKuY/8i6q/+/rp3/s56I/5+D + aP/Xzr3/3tfI/97Xx//e1sb/3tbG/97Wxf/e1sX/3tXE/97VxP/e1cP/3tTD/97Uwv/d1ML/3dPB/93T + wf/d08D/3dLA/93Sv//d0r//3dG+/93Rvv/d0b3/3dG9/93QvP/d0Lz/3c+7/93Pu//cz7r/3M+6/9zO + uf/czrn/3M64/9zNuP/czbf/3M23/9zMtv/czLb/3My1/9zLtf/HtZ3/inNY/4pzWP+Kc1j/lHpe/66Y + gf+2o4//s56K/7CahP+slX7/qJB4/6SLcf+ghWr/nIBk/5p9Yf+afWH/mn1h/5p9Yf+afWH/mn1h/5h7 + X/+NdFn/lH1i/9W+pP/aw6n/2sOo/9rDqP/awqf/2sKn/9rCpv/awab/2sGl/9rBpf/awKT/2cCk/9nA + o//ZwKP/2b+i/9m/ov/ZvqH/2b6h/9m+of/ZvqD/2b2f/9m9n/+njHL/p4xx/6aLcf+minD/pYpv/6WJ + bv+kiW7/lX9n/4ZzWd9JPBJvSTwSVkk8Ej1JPBIoSTwSGEc7EgxFOREFQjcQAQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABGOhECSDsSBUk8Eg1JPBIZSTwSKUk8Ej6Pe2PzuKyZ/+Dd0P/l4db/5OHV/+Tg + 1P/k39P/49/S/7Whi/+6qJX/yLut/8Cvnv+4pJD/oIVq/9DEsv/f2cn/3tfH/97Xxv/e1sb/3tbF/97W + xf/e1cT/3tXE/97Vw//e1MP/3tTC/93Uwv/d08H/3dPB/93TwP/d0sD/3dK//93Sv//d0b7/3dG+/93R + vv/d0b3/3dC9/93QvP/d0Lz/3c+7/93Pu//cz7r/3M65/9zOuf/czrj/3M24/9zNuP/czbf/3My3/9zM + tv/czLb/3Mu1/9zLtf+9qpH/inNY/4pzWP+Kc1j/j3Za/6GHbf+vmYP/rZZ//6mRef+ljHP/oodt/56C + Z/+afWH/mn1h/5p9Yf+afWH/mn1h/5p9Yf+UeV3/i3NY/494Xf/LtJr/2sSp/9rDqf/aw6j/2sOo/9rC + p//awqf/2sKm/9rBpv/awaX/2sGl/9rBpf/ZwKT/2cCk/9nAo//Zv6P/2b+i/9m/ov/ZvqH/2b6h/9m+ + oP/ZvZ//2b2f/6eMcv+njHH/potx/6aKcP+lim//pYlu/6SJbv+Vf2f/hnNZ30k8Em9JPBJWSTwSPkk8 + EilJPBIYRzsSDEU5EQVCNxABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEY6EQFIOxIFSTwSDEk8 + EhdJPBInSTwSO4t3Xs+uoIz/4NzP/+Xi1//l4db/5OHV/+Tg1P/k39P/wrKe/7Gbhf/JvK7/wbCf/7il + kv+kinD/xLah/+DZy//f2Mn/3tfG/97Wxv/e1sX/3tbF/97VxP/e1cT/3tXD/97Uw//e1ML/3tTC/93T + wf/d08H/3dPB/93SwP/d0sD/3dK//93Sv//d0b7/3dG+/93Rvf/d0L3/3dC8/93QvP/dz7v/3c+7/9zP + uv/czrr/3M65/9zOuf/czbj/3M24/9zNt//czLf/3My2/9zMtv/cy7X/3Mu1/9zLtP/Cr5f/j3hd/4pz + WP+Kc1j/i3NY/5N5Xv+ghm3/pYxy/6OJb/+fhGn/m39j/5p9Yf+afWH/mn1h/5l8YP+UeV3/jnVa/4pz + WP+UfWL/y7Wb/9rEqv/axKn/2sOp/9rDqP/aw6j/2sOo/9rCp//awqf/2sGm/9rBpv/awaX/2sGl/9rA + pP/ZwKT/2cCj/9m/o//Zv6L/2b+i/9m+of/ZvqH/2b6g/9m9oP/ZvZ//qo91/6eMcf+mi3H/popw/6WK + b/+liW7/pIlu/5iBaP+Gc1nfSTwSb0k8ElZJPBI+STwSKUk8EhhHOxIMRTkRBUI3EAEAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAARjoRAUg7EgRJPBILSTwSFUk8EiVJPBI5iXZcxKSUf//f283/5uLX/+Xi + 1//l4tb/5eHV/+Tg1P/GuKX/sJmD/8q9r//CsqH/uaaU/6iPdv/BsZ3/4NrM/+DZyv/f2Mn/3tbG/97W + xf/e1sX/3tbF/97VxP/e1cT/3tTD/9rPvv+6po//vauV/9bLuP/d08H/3dPA/93SwP/d0r//3dK//93R + vv/d0b7/3dG9/93Qvf/d0Lz/3dC8/93Pu//dz7v/3M+6/9zOuv/czrn/3M65/9zNuP/czbj/3M23/9zN + t//czLb/3My2/9zMtf/cy7X/3Mu0/9zLtP/MuqL/mYNp/4pzWP+Kc1j/inNY/4pzWP+NdVn/kXhc/5N6 + Xv+SeFz/knhc/492Wv+OdVr/inNY/4pzWP+Kc1j/o4xy/9W/pf/axav/2sSq/9rEqv/aw6n/2sOp/9rD + qP/aw6j/2sKn/9rCp//awqb/2sGm/9rBpf/awaX/2sCk/9nApP/ZwKP/2b+j/9m/ov/Zv6L/2b6h/9m+ + of/ZvqD/2b6g/9m9n/+0mH3/p4xy/6aLcf+mi3D/pYpv/6WJb/+kiW7/moJp/4ZzWN9JPBJwSTwSVkk8 + Ej5JPBIpSTwSGEc7EgxFOREFQjcQAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASDsSA0k8 + EgpJPBITSTwSIkk8EjaBblKjmohy/9/bzf/m49j/5uPY/+Xi1//l4db/5eDV/9bNvf+qkXn/y72w/8Ky + ov+6qJX/rJR9/7Oeh//h28z/4NrL/+DZyv/f2Mj/3tbG/97Wxf/e1sX/3tXE/97VxP/e1cP/x7ei/6qS + ef+qknr/qpN6/7ejjP/Qw6//3dLA/93Sv//d0r//3dG+/93Rvv/d0b3/3dG9/93QvP/d0Lz/3c+7/93P + u//dz7v/3M+6/9zOuf/czrn/3M64/9zNuP/czbf/3M23/9zMtv/czLb/3My1/9zLtf/cy7X/3Mu0/9zK + tP/byrP/vKmQ/5R9Y/+Kc1j/inNY/4pzWP+Kc1j/inNY/4pzWP+Kc1j/inNY/4pzWP+Kc1j/nodt/8ax + l//bxaz/2sWr/9rFq//axKr/2sSq/9rEqf/aw6n/2sOo/9rDqP/awqf/2sKn/9rCpv/awab/2sGl/9rB + pf/awKT/2cCk/9nAo//ZwKP/2b+i/9m/ov/Zv6L/2b6h/9m+of/ZvqD/2b2f/7SYff+njHL/potx/6aL + cP+lim//pYlv/6SJbv+agmn/hnNY30k8EnBJPBJWSTwSPkk8EilJPBIYRzsSDEU5EQVCNxABAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABIOxIDSTwSCEk8EhJJPBIfSTwSM35sT5aRfWX/39vN/+Xh + 1v/m49j/5uPY/+Xi1//l4db/1s2//6uTe//Huar/w7Ok/7upl/+ul4D/sZuD/+Hczf/h28z/4NrL/+DZ + yv/f18j/3tbF/97Wxf/e1cT/3tXE/97Vw//Ht6L/qpJ5/6qSef+qk3r/q5N6/6uTe/+xm4P/yrqm/93S + v//d0b7/3dG+/93Rvv/d0b3/3dC9/93QvP/d0Lz/3c+7/93Pu//cz7r/3M65/9zOuf/czrj/3M24/9zN + uP/czbf/3My3/9zMtv/czLb/3Mu1/9zLtf/cy7T/3Mq0/9zKs//byrP/28my/8u4of+tmH//nohu/494 + Xf+Kc1j/inNY/5R9Yv+eiG3/sp2D/8u2nf/bxq3/28as/9vFrP/axav/2sWr/9rEqv/axKr/2sSp/9rD + qf/aw6j/2sOo/9rCp//awqf/2sKm/9rBpv/awaX/2sGl/9rBpf/ZwKT/2cCk/9nAo//Zv6P/2b+i/9m/ + ov/ZvqH/2b6h/9m+oP/ZvZ//tJl+/6eMcv+ni3H/potw/6WKcP+liW//pIlu/5qCaf+RfWX/STwScEk8 + ElZJPBI+STwSKUk8EhhHOxIMRTkRBUI3EAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEg7 + EgNJPBIHSTwSEEk8Eh1JPBIwcF8/c5F9Zf/Vz8D/5OHV/+fk2f/m49n/5uPY/+bi1v/l4db/rZV+/8S0 + pP/EtaX/vauZ/7KdiP+njnT/4tzO/+Hbzf/h2sz/4NrL/+DZyv/f18f/3tbF/97VxP/e1cT/3tXD/9HE + sP+qknn/qpJ5/6qTev+rk3r/q5N7/6uTe/+rlHv/rpeA/8Sznf/Zzbr/3dG+/93Rvf/d0L3/3dC8/93Q + vP/dz7v/3c+7/9zPuv/czrr/3M65/9zOuf/czbj/3M24/9zNt//czLf/3My2/9zMtv/cy7X/3Mu1/9zL + tP/cy7T/3Mqz/9vKs//byrL/28my/9vJsf/bybH/28iw/9vIsP/byK//28ev/9vHrv/bx67/28au/9vG + rf/bxqz/28Ws/9rFq//axav/2sSq/9rEqv/axKn/2sOp/9rDqf/aw6j/2sOo/9rCp//awqf/2sGm/9rB + pv/awaX/2sGl/9rApP/ZwKT/2cCj/9m/o//Zv6L/2b+i/9m+of/ZvqH/2b6g/9m9oP+0mX7/p4xy/6eL + cf+mi3D/pYpw/6WJb/+kiW7/moNp/5F9Zf9JPBJwSTwSVkk8Ej5JPBIpSTwSGEc7EgxFOREFQjcQAQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASDsSA0k8EgdJPBIPSTwSG0k8EixrWjllkX1l/8vD + s//j4NP/5+Ta/+fk2f/m49j/5uLX/+bi1/+ynIb/wbCf/8W2p/++rJr/tKCL/6iQd//b08T/4tzO/+Hb + zf/h28z/4drK/+DZyv/e18b/3tbF/97VxP/e1cT/1Mi1/6qSef+qknn/qpN6/6uTev+rk3v/q5N7/6uU + e/+rlHz/rJR8/6yUff++q5X/08Wx/93Qvf/d0Lz/3dC8/93Pu//dz7v/3M+6/9zPuv/czrn/3M65/9zN + uP/czbj/3M23/9zNt//czLb/3My2/9zMtf/cy7X/3Mu0/9zLtP/cyrP/28qz/9vKsv/bybL/28my/9vJ + sf/byLH/28iw/9vIsP/bx6//28ev/9vHrv/bxq7/28at/9vGrP/bxaz/28Ws/9rFq//axav/2sSq/9rE + qv/axKn/2sOp/9rDqP/aw6j/2sKn/9rCp//awqb/2sGm/9rBpf/awaX/2sCk/9nApP/ZwKP/2b+j/9m/ + ov/Zv6L/2b6h/9m+of/ZvqD/2b6g/7SZfv+njHL/p4tx/6aLcP+linD/pYpv/6SJbv+ag2n/kX1l/0k8 + EnBJPBJWSTwSPkk8EilJPBIYRzsSDEU5EQVCNxABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABIOxICSTwSBUk8Eg1JPBIZSTwSKUk8Ej+RfWX/wbem/+Lf0//o5dv/5+Ta/+fk2f/n49j/5uLX/72s + mP++rJr/xrio/7+tnP+4pJD/qpF5/9TKuv/i3c//4tzO/+Hbzf/h28z/4dnL/+DZyf/e1sb/3tXE/97V + xP/e1cP/qpJ5/6qSef+qk3r/q5N6/6uTe/+rk3v/q5R7/6uUfP+slHz/rJR9/6yVff+slX3/uKSN/8u6 + pf/d0Lz/3c+7/93Pu//dz7v/3M+6/9zOuf/czrn/3M64/9zNuP/czbf/3M23/9zMtv/czLb/3My1/9zL + tf/cy7X/3Mu0/9zKtP/byrP/28qz/9vJsv/bybL/28mx/9vIsf/byLD/28iw/9vHr//bx6//28eu/9vH + rv/bxq3/28at/9vGrP/bxaz/2sWr/9rFq//axKr/2sSq/9rEqf/aw6n/2sOo/9rDqP/awqf/2sKn/9rC + pv/awab/2sGl/9rBpf/awKT/2cCk/9nAo//ZwKP/0Lie/9C4nv/QuJ7/0Led/862nP/Ispr/tZqA/6eM + cv+ni3H/potw/6WKcP+lim//pIlu/56Fa/+RfWX/STwScEk8ElZJPBI+STwSKUk8EhhHOxIMRTkRBUI3 + EAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEg7EgFJPBIFSTwSDEk8EhdJPBInSTwSO497 + Y/O4rJn/4d3Q/+jl2//o5dv/5+Ta/+fk2f/n49j/xbak/7mmkv/HuKn/wK+d/7mlkv+tlX7/yr2r/+Pe + 0P/i3c//4tzO/+Hbzf/h2sz/4dnK/+DZyf/e1sX/3tXE/97Vw/+znob/qpJ5/6qTev+rk3r/q5N7/6uT + e/+rlHv/q5R8/6yUfP+slHz/rJV9/6yVff+slX7/rJZ+/7CZgv+/q5X/zr2o/9rLt//cz7r/3M65/9zO + uf/czrn/3M24/9zNuP/czbf/3My3/9zMtv/czLb/3Mu1/9zLtf/cy7T/3Mq0/9zKs//byrP/28my/9vJ + sv/bybH/28mx/9vIsP/byLD/28iv/9vHr//bx67/28eu/9vGrf/bxq3/28as/9vFrP/axav/2sWr/9rE + qv/axKr/2sSp/9rDqf/aw6j/07yj/9C6of/JtJz/x7Kb/8exm/+/qpX/v6qW/7yolP+2o5H/tqSS/7ek + kv+3pJL/t6ST/7elk/+3pZT/uKWU/7imlP+0nIX/p4xy/6eLcf+mi3D/pYpw/6WKb/+kiW7/n4Zr/5F9 + Zf9JPBJwSTwSVkk8Ej5JPBIpSTwSGEc7EgxFOREFQjcQAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAASDsSAUk8EgRJPBILSTwSFUk8EiVJPBI5i3hezq6gjP/g3M//6ebc/+jl3P/o5dv/6OXa/+fj + 2f/NwLD/uaWR/8i5q//BsJ//uqeU/6+Ygv/Iuaf/497R/+Pd0P/i3M//4tzO/+LbzP/h2sv/4drK/+DZ + yf/e1cT/3tXD/7qmkP+qknn/qpJ6/6uTev+rk3r/q5N7/6uUe/+rlHz/rJR8/6yUfP+slX3/rJV9/6yV + fv+sln7/rZZ+/62Wf/+tln//rZd//7ahiv+/q5X/x7ag/9DAq//ZyrT/3M24/9zNt//czLf/3My2/9zM + tv/cy7X/3Mu1/9zLtP/cy7T/3Mqz/9vKs//byrL/28my/9vJsf/bybH/28iw/9vIsP/byK//28ev/9vH + rv/bx67/28au/9vGrf/bxqz/28Ws/9C7o//Qu6P/x7Kb/8Svmf+9qZT/uKWR/7Shjv+1oY7/taGP/7Wi + j/+1oo//taKQ/7aikP+2o5H/tqOR/7ajkf+2pJL/t6SS/7ekkv+3pJP/t6WT/7ellP+4pZT/uKaU/7CZ + hP+njHL/p4xx/6aLcP+minD/pYpv/6WJbv+fhmv/kX1l/0k8EnBJPBJWSTwSPkk8EilJPBIYRzsSDEU5 + EQVCNxABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASTwSA0k8EgpJPBITSTwSIkk8 + EjaJdlzDpJR//9/bzf/p5t3/6ebc/+jm3P/o5dv/6OTa/9fOwP+znoj/ybus/8Kyof+7qZb/spyG/7uo + lP/k39L/497R/+Pd0P/j3M//4tzN/+Lbzf/h2sv/4drK/+DYyP/e1cT/xLOe/6qSef+qknr/q5N6/6uT + ev+rk3v/q5R7/6uUfP+rlHz/rJR8/6yVff+slX3/rJV9/6yWfv+tln7/rZZ//62Wf/+tl3//rZeA/66X + gP+ul4H/rpiB/66Ygf+umIL/t6KM/7qmkP+6pY//xbKc/8WznP/Gspz/xrKc/8aynP/Gspz/xbKc/8ay + nP/Gspz/xrKc/8aynP/Gspz/xrKc/8aynP+8p5L/vKiS/7yok/+8qJP/uKOO/7Ofi/+zn4v/s5+L/7Of + jP+0oIz/tKCN/7Sgjf+0oY3/tKGO/7Whjv+1oY//taKP/7Wij/+1opD/tqKQ/7ajkP+2o5H/tqOR/7ak + kv+7q5v/t6SS/7ekk/+3pZP/t6WU/7ellP+4ppT/sJmE/6eMcv+njHH/potw/6aKcP+lim//pYlu/5+G + a/+RfWX/aVg2j0k8ElZJPBI+STwSKUk8EhhHOxIMRTkRBUI3EAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABJPBIDSTwSCUk8EhJJPBIgSTwSNIFvU6KaiHL/39vN/+fk2v/p593/6ebc/+nm + 3P/o5dv/29PH/7Wgi//Juqz/w7Oi/72qmP+0n4r/uaaR/+Tf0//k39L/497R/+Pd0P/j3M7/4tvN/+Lb + zP/h2sv/4dnK/+DYyP/RxLH/qpJ5/6qSev+qk3r/q5N6/6uTe/+rlHv/q5R8/6uUfP+slHz/rJV9/6yV + ff+slX3/rJZ+/62Wfv+tln//rZZ//62Xf/+tl4D/rpeA/66Xgf+umIH/rpiB/66Ygv+vmIL/r5mD/6+Z + g/+vmYP/r5qE/7CahP+wmoT/sJqF/7Cbhf+wm4b/sZuG/7Gchv+xnIf/sZyH/7GciP+xnYj/sp2I/7Kd + if+ynYn/sp6K/7Keiv+znor/s5+L/7Ofi/+zn4v/s5+M/7SgjP+0oI3/tKCN/7Shjf+0oY7/taGO/7Wh + jv+1oo//taKP/7Ohj/+0o5H/tqaX/7qtof/Atq3/x8G7/83Jxf/OycT/uaeX/7elk/+3pZP/t6WU/7il + lP+wmYT/p4xy/6eMcf+mi3H/popw/6WKb/+liW7/n4Zr/5F9Zf9pWDaPSTwSVkk8Ej5JPBIpSTwSGEc7 + EgxFOREFQjcQAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEk8EgNJPBIISTwSEUk8 + Eh9JPBIxfmxPlZF9Zf/f283/5+Ta/+rn3v/p593/6ebd/+nl3P/l4Nb/t6KN/8W1pf/EtKT/vqya/7ej + jv+xmoT/5eDU/+Tf0//k39L/5N7R/+Pdz//j3M7/4tvN/+LbzP/i2sv/4dnK/+DYyP+qknr/qpJ6/6qT + ev+rk3r/q5N7/6uUe/+rlHz/q5R8/6yUfP+slX3/rJV9/6yVff+slX7/rZZ+/62Wf/+tln//rZd//62X + gP+ul4D/rpeB/66Ygf+umIH/rpiC/6+Ygv+vmYP/r5mD/6+Zg/+vmoT/sJqE/7CahP+wmoX/sJuF/7Cb + hv+wm4b/sZyG/7Gch/+xnIf/sZyI/7GdiP+ynYj/sp2J/7Kdif+ynon/sp6K/7Oeiv+zn4v/s5+L/7Of + i/+zn4z/tKCM/7SgjP+0oI3/rpqF/6uXgv+ok37/ppF+/6aTgP+nlYT/rJyM/7GilP+2qZ3/u7Cm/8G4 + sP/HwLr/zcnE/9PRz//Fu7H/t6WT/7elk/+3pZT/uKWU/7CZhP+njHL/p4xx/6aLcf+minD/pYpv/6WJ + bv+fhmv/kX1l/2lYNo9JPBJXSTwSP0k8EilJPBIYRzsSDEU5EQVCNxABAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAASTwSA0k8EgdJPBIQSTwSHUk8Ei9xYEBykX1l/9XPwP/l4tf/6ujf/+rn + 3v/q593/6ebc/+nl3P+4pJD/xbWl/8a2pv+/rZz/uaWR/7Kchv/f2Mv/5eDU/+Tf0//k3tH/5N7R/+Pd + z//j3M7/49zN/+LbzP/i2sv/4dnK/7mmkP+qknr/qpN6/6uTev+rk3v/q5N7/6uUfP+rlHz/rJR8/6yV + ff+slX3/rJV9/6yVfv+tln7/rZZ//62Wf/+tl3//rZeA/66XgP+ul4H/rpiB/66Ygf+umIL/r5iC/6+Z + gv+vmYP/r5mD/6+ahP+vmoT/sJqE/7Cahf+wm4X/sJuG/7Cbhv+xnIb/sZyH/7Gch/+xnIf/sZ2I/7Kd + iP+ynYn/sp2J/7Keif+ynor/s56K/7Oeiv+tmIP/qJJ8/5+Hb/+cg2v/mH9n/5J4X/+VfGT/mIBp/5uF + b/+finX/o498/6eVg/+rm4v/sKGT/7WonP+7sKX/wLev/8a/uf/MyMP/09DO/8e+tf+3pZP/t6WT/7el + lP+4pZT/sJmE/6eMcv+njHL/potx/6aLcP+lim//pYlv/6OIbf+RfWX/aFg2j0k8ElhJPBJASTwSKkk8 + EhlHOxINRTkRBUI3EAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJPBIDSTwSB0k8 + Eg9JPBIbSTwSLGtaOWSRfWX/y8Oz/+Xi1v/r6N//6ujf/+rn3v/q593/6ebc/8W2pP/CsaD/x7eo/8Cv + nv+7qJT/tJ6J/9nQwv/l4dX/5eDU/+Xf0//k39H/5N7Q/+Pd0P/j3M7/49zN/+LazP/i2sv/x7il/6+Z + gv+qk3r/q5N6/6uTe/+rk3v/q5R7/6uUfP+slHz/rJV9/6yVff+slX3/rJV+/62Wfv+tln//rZZ//62X + f/+tl4D/rpeA/66XgP+umIH/rpiB/66Ygv+umIL/r5mC/6+Zg/+vmYP/r5qE/6+ahP+wmoT/sJqF/7Cb + hf+wm4X/sJuG/7Gbhv+xnIf/sZyH/7Gch/+xnYj/sp2I/7Kdif+ynYn/sp6J/7Keiv+dg2v/im1R/4hr + Tv+JbVH/i29T/41xVv+PdFr/knde/5R7Y/+Xf2j/m4Ru/56JdP+ijnv/ppSC/6uaiv+woZL/rJ2O/62f + kP+xpZf/xb64/8vHwv/Sz83/x720/7elk/+3pZP/t6WU/7illP+wmYT/p4xy/6eMcv+mi3H/potw/6WK + b/+liW//pIlu/5F9Zf9oWDaRSTwSWUk8EkFJPBIrSTwSGkc7Eg5FOREGQzcQAgAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEk8EgJJPBIFSTwSDUk8EhlJPBIpSTwSPpF9Zf/Bt6b/4t7S/+vp + 4P/r6OD/6ujf/+rn3v/q593/ybur/8Gwnv/Iuan/wrGg/7ypl/+2oYz/0MS1/+bh1v/m4dX/5eDU/+Xf + 0//k39H/5N3Q/+Tdz//j3M7/49vN/+LbzP/UyLb/tJ+J/7Cag/+rk3r/q5N7/6uTe/+rlHv/q5R8/6yU + fP+slX3/rJV9/6yVff+slX7/rp+O/7nHzv/F1N7/x9HW/7esn/+ul4D/rpeA/66Ygf+umIH/rpiC/66Y + gv+vmYL/r5mD/6+Zg/+vmYP/r5qE/7CahP+wmoX/sJuF/7Cbhf+wm4b/sZuG/7Gch/+xnIf/sZyH/7Gd + iP+ynYj/sp2J/7Kdif+ynon/p5B6/4dpTP+Hak3/iGtO/4lsUP+LblP/jXFW/490Wv+Rd17/lHtj/5d/ + aP+Zgmz/mIJs/5WAav+RfGX/jnli/4VvVf+Fb1X/hW9V/4VvVf+Rfmj/x8G6/9HOzP/Nx8H/t6WT/7el + k/+3pZT/uKWU/7CZhP+ojXP/p4xy/6eLcf+mi3D/pYpw/6WJb/+kiW7/kX1l/2hYNpJJPBJbSTwSQ0k8 + Ei1JPBIbRzsSD0U5EQdCNxACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASTwSAUk8 + EgVJPBIMSTwSF0k8EidJPBI7j3tj87ismf/i3tL/7Onh/+vp4P/r6OD/6+jf/+rn3v/TyLr/wK6c/8m6 + q//DsqL/vauZ/7ijj//OwrL/5uLX/+bh1f/m4NX/5eDT/+Xf0v/k3tH/5N7Q/+Tdz//j3M7/49vN/+DX + yP+1oIv/tKCK/7Gag/+rk3v/q5N7/6uUe/+rlHz/rJR8/6yUff+slX3/rJV9/6yZhv+32/b/yuj+/9zw + /v/m9P//3/H//7y3r/+ul4D/rpiB/66Ygf+umIL/rpiC/6+Zgv+vmYP/r5mD/6+Zg/+vmoT/o6uq/562 + wf+etsH/pKyr/7Cbhv+xm4b/sZyH/7Gch/+xnIf/sZ2I/7KdiP+ynYn/sp2J/7Keif+cg2v/h2lM/4dp + Tf+Iak7/iWxQ/4tuU/+NcVb/jHJY/4tzWf+Iclj/h3BX/4VvVf+Fb1X/hW9V/4VvVf+Fb1X/hW9V/4Vv + Vf+Fb1X/hW9V/4VvVf+om4v/0M7L/87JxP+3pZP/t6WT/7ellP+4pZT/sJmD/6iNc/+njHL/p4tx/6aL + cP+linD/pYlv/6SJbv+RfWX/emlLt0k8El5JPBJFSTwSL0k8Eh1HOxIQRTkRCEI3EAM8Mg8BAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJPBIBSTwSBEk8EgtJPBIVSTwSJUk8EjmLeF7OrqCM/9/b + zf/s6uL/7Onh/+vp4P/r6eD/6+jf/9rRxP++rJn/yryt/8S0pP+/rZv/uaaS/8Ozof/n49j/5+LW/+bh + 1v/m4NT/5eDT/+Xf0v/l3tH/5N7Q/+Tdz//j3M7/49vN/8Gwnf+1oYz/taCL/7GahP+rk3v/q5R7/6uU + fP+slHz/rJR9/6yVff+slX3/qsDO/7ri/v/Q6/7/5fT///b7///r9v//1Oj2/6+ciP+umIH/rpiB/66Y + gv+umIL/r5mC/6+Zg/+vmYP/oKmp/4vN9v+S1P7/mNf+/5jX/v+U1f7/js72/6Orq/+xnIf/sZyH/7Gc + h/+xnYj/sp2I/7Kdif+ynYn/sp6J/6SNdv+HaUz/h2lN/4hqTv+JbFD/im5S/4lvVf+Fb1X/hW9V/4Vv + Vf+Fb1X/hW9V/4VvVf+Qe2P/nIp1/7iqmv/IvbH/4drT//r49/+xo5P/hW9V/5aFcP/Qzcn/zsjD/7el + k/+3pZP/t6WU/7illP+wmYP/qI1z/6eMcv+ni3H/potw/6WKcP+liW//pIlu/5F9Zf96aEu5STwSYEk8 + EkdJPBIxSTwSHkc7EhFFOREIQjcQAzwyDwEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABJPBIDSTwSCkk8EhNJPBIiSTwSNol2XMOklH//39vN/+zp4f/s6uL/7Orh/+zp4f/r6eD/4NnO/7+s + mv/Lva//xral/8Cvnf+7qJX/wbCe/+fj2f/n49f/5+LW/+bh1f/m4dT/5uDT/+Xf0v/l3tH/5N7Q/+Td + z//j3M7/zb+u/7ejjv+2ooz/taCM/7Kchv+rlHz/q5R8/6yUfP+slH3/rJV9/6yVff+pyN7/uOD+/8zp + /v/f8f//6vb//+Pz///S6/7/trSv/66Ygf+umIH/rpiC/66Ygv+vmYL/r5mD/5ursf+Fz/7/k9X+/5/a + /v+o3f7/qd7+/6Lb/v+W1v7/idH+/5e0wv+xnIf/sZyH/7GciP+ynYj/sp2I/7Kdif+ynon/qZR+/4dp + TP+HaUz/iGpO/4lsUP+KblL/hW9U/4VvVf+KdFr/mINr/6eUfv+6qZf/z8K1/9zSyP/j3NT/6uTe//Ds + 6P/18vD/+fj2/8C1p/+Fb1X/jXpi/8/MyP/NyML/t6WT/7elk/+3pZT/uKWU/7CZg/+ojXP/p4xy/6eL + cf+mi3D/pYpw/6WKb/+kiW7/kX1l/3poS7lJPBJiSTwSSUk8EjJJPBIfRzsSEkU5EQlCNhAEPTIPAQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEk8EgNJPBIJSTwSEkk8EiBJPBI0gW9TopqI + cv/f283/6efe/+3r4//s6uL/7Orh/+zp4f/m4df/wK6c/8i5qv/Gt6f/wrCf/72qmP+6ppP/6OTZ/+jj + 2P/n49f/5+LW/+bh1f/m4dT/5t/T/+Xf0v/l3tH/5N3Q/+Tdz//b0sL/uKWQ/7ijjv+3oo7/tqGM/7Oe + iP+rlHz/rJR8/6yUfP+slX3/rJV9/6fI3v+v3f7/weT+/8/q/v/V7f7/0ev+/8Xm/v+zvL//rpeB/66Y + gf+umIH/rpiC/6+Zgv+nnpL/esv+/4rR/v+b2P7/qt7+/7bj/v+45P7/rd/+/5/Z/v+P0/7/f8z+/52p + rP+xnIf/sZyI/7GdiP+ynYj/sp2J/7Keif+ynor/h2lM/4dpTP+Iak7/iWxP/4puUv+Fb1X/hW9V/6OM + dP+2oY3/wK6d/8q7rP/Txrn/29HG/+La0v/p493/7+vm//Tx7v/59/X/3tjQ/4VvVf+Fb1X/zsvH/9XU + 0v+3pJP/t6WT/7ellP+4pZT/sJmD/6iNc/+njHL/p4tx/6aLcP+linD/pYpv/6SJbv+VgGf/emhKukk8 + EmNJPBJKSTwSM0k8EiBHOxISRTkRCUI2EAQ9Mg8BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAASTwSA0k8EghJPBIRSTwSH0k8EjF6aEuKkX1l/9/bzf/p5t3/7evj/+3r4//t6uL/7Ori/+zp + 4f/CsJ//ybqr/8i5qf/DsqH/vqyZ/76smv/o5Nr/6OTZ/+jj2P/n4tf/5+LW/+bh1f/m4NT/5t/T/+Xf + 0v/l3tH/5N3Q/+Tdz/+8qpb/uaWQ/7ikkP+3o47/tqKN/7Oeif+slH3/rJR8/6yVff+slX3/p8PW/6fZ + /v+x3f7/u+L+/8Dk/v+94/7/tN/+/620t/+ul4H/rpiB/66Ygf+umIL/r5mC/4a1z/98y/7/jNL+/53Y + /v+t3/7/veb+/8Dn/v+y4f7/odr+/5HU/v+Azf7/ecHv/7Gch/+xnIj/sZ2I/7KdiP+ynYn/sp6J/7Ke + iv+Pclf/h2lM/4hqTf+Ja0//im1R/4VvVf+Fb1X/oYpy/7Wfiv+/rJr/yLmp/9HEt//az8T/4dnQ/+jh + 2//u6eX/8/Dt//j29P/d19D/hW9V/4VvVf/JxL//1NPR/7ekk/+3pZP/t6WU/7illP+vmIH/qI1z/6eM + cv+njHH/potw/6aKcP+lim//pYlu/5WAZ/96aEq5STwSYkk8EklJPBIzSTwSIEc7EhJFOREJQjYQAzwy + DwEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJPBIDSTwSB0k8EhBJPBIdSTwSL3Fg + QHKRfWX/2tXG/+bj2f/u7OT/7evk/+3r4//t6uL/7Ori/8u9rf/EtKP/x7eo/8Kwn/++rJr/0cS2/+nl + 2//o5Nr/6OTZ/+jj2P/n4tf/5+LW/+fh1f/m4NT/5uDT/+Xf0v/l3tH/5d3Q/8q8qv+6p5L/uaWR/7ik + kP+3pI//tqKN/7Wgi/+tln//rJV9/6yVff+prq3/ptn+/6bZ/v+p2v7/q9v+/6ra/v+m2f7/rZ+Q/66X + gf+umIH/rpiB/66Ygv+vmYL/bsH2/3nK/v+J0f7/mdf+/6fd/v+y4f7/tOL+/6ve/v+d2f7/jtL+/37M + /v9txf7/oqOd/7GciP+xnYj/sp2I/7Kdif+ynYn/sp6K/5F2W/+HaUz/iGpN/4hrT/+KbVH/hW9V/4Vv + Vf+chGz/s52H/72ql//Ht6f/0MK1/9jNwv/g187/5+DZ/+3o4//z7+z/9/Xz//v6+f+Fb1X/hW9V/7yz + qv/U0tD/t6ST/7elk/+3pZT/t6WU/6yTe/+ojXP/p4xy/6eMcf+mi3D/popw/6WKb/+liW7/lYBn/3po + S7lJPBJgSTwSR0k8EjFJPBIeRzsSEUU5EQhCNxADPDIPAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAEk8EgNJPBIHSTwSD0k8EhtJPBIsYlMvWZF9Zf/Lw7P/5eHW/+7s5f/u7OT/7uvk/+3r + 4//t6+L/5eDW/8m6qv/CsaD/x7em/9XKvf/q593/6ubc/+nl2//p5dr/6OTZ/+jj2P/n4tf/5+LW/+fh + 1f/m4NT/5uDT/+bf0v/l3tH/2M29/7uolf+6p5P/uaaS/7ilkf+4pJD/t6OO/7ahjP+vmYP/rJV9/6yV + ff+ov87/ptn+/6bZ/v+m2f7/ptn+/6m8xv+ul4D/rpeB/66Ygf+umIH/rpiC/6Sdkf9kwv7/dMj+/4LO + /v+Q1P7/nNj+/6Pb/v+k3P7/ntn+/5PV/v+G0P7/eMr+/2nD/v+HrcP/sZyI/7GdiP+ynYj/sp2J/7Kd + if+ynor/nINr/4dpTP+Iak3/iGtP/4ptUf+GblT/hW9V/5d/Zv+xm4X/vKiV/8W1pP/PwbP/18zA/9/W + zf/m39j/7Ofi//Lu6//39PL/8/Du/4VvVf+Fb1X/u7Kp/9PRz/+7qpv/t6WT/7elk/+3pZT/rJR8/6iN + c/+njHL/p4xx/6aLcf+minD/pYpv/6WJbv+VgGf/h3Ra20k8El1JPBJFSTwSLkk8Eh1HOxIQRTkRCEI3 + EAM8Mg8BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASTwSAkk8EgVJPBINSTwSGUk8 + EilJPBI+kX1l/8a9rP/j39P/7+3m/+7s5f/u7OX/7uzk/+3r4//t6uL/7eri/+zp4f/s6OD/6+jf/+vn + 3v/q5t3/6ubc/+nl2//p5dr/6OTZ/+jj2P/o49f/5+HW/+fh1f/m4NT/5t/T/+bf0v/j283/vKqW/7yp + lf+7p5T/uqeS/7mmkv+4pJD/uKOP/7ejjv+xnIb/rJV9/6yVfv+qr67/qMTW/6jE1v+qq6f/rZeA/66X + gP+ul4H/rpiB/66Ygf+umIL/mKGh/16//v9sxf7/ecr+/4TP/v+O0/7/k9X+/5TV/v+Q0/7/h9D+/3zL + /v9vxv7/YsH+/4Ssw/+xnIj/sZ2I/7KdiP+ynYn/sp2J/7Keif+iinL/h2lM/4hqTf+Ia0//im1R/4Zu + VP+Fb1X/knth/6+Zgv+6ppL/xLOi/82/sf/Wyr7/3tTL/+Xd1v/e187/1s7E/72xo/+ikX3/hW9V/4Vv + Vf/DvLX/0tDO/7+xo/+3pZP/t6WT/7ellP+qkHj/qI1z/6eMcv+njHH/potx/6aKcP+lim//pYlu/5aA + Z/+IdFraSTwSWEk8EkBJPBIrSTwSGkc7Eg5FOREHQjcQAjwyDwEAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABJPBIBSTwSBUk8EgxJPBIXSTwSJ0k8EjuOemLnuKyZ/+Dczv/v7eb/7+3m/+/t + 5f/u7OX/7uzk/+3r4//t6uL/7erh/+zp4f/s6OD/6+jf/+vn3v/q5t3/6ubc/+nl2//p5Nr/6OTZ/+jj + 2P/o4tf/5+LW/+fh1f/n4NT/5t/T/+bf0v/Ku6r/vaqX/7yplv+7qJT/uqeU/7mmkv+5pZH/uKSQ/7ej + jv+zn4r/rZZ//62Wfv+tln//rZZ//62Xf/+tl4D/rpeA/66Xgf+umIH/rpiB/66Ygv+pmon/Vbv//2LB + /v9txf7/d8n+/3/M/v+Dzv7/g87+/4DN/v95yv7/cMb+/2XC/v9Yvf//f6rD/7Gch/+xnYj/sp2I/7Kd + if+ynYn/sp6J/6eQev+HaUz/h2pN/4hrTv+JbVD/iG5T/4VvVf+LdFv/rpd//7ikkP+zoY3/rZuH/6eW + gv+biHL/hW9V/4VvVf+Fb1X/hW9V/4VvVf+Fb1X/oZKB/8vGwv/Sz8z/vrCj/7elk/+3pZP/tqOS/6iO + dP+ojXP/p4xy/6eMcf+mi3H/popw/6WKb/+liW7/loBn/3xqTbJJPBJTSTwSO0k8EidJPBIXRzsSDEU5 + EQVCNxABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEk8EgFJPBIESTwSC0k8 + EhVJPBIlSTwSOYt4Xs6zppL/39vN//Du5//v7eb/7+3m/+/t5v/u7OX/7uzk/+3r4//t6uL/7erh/+zp + 4P/s6N//7Ojf/+vn3v/q5t3/6ubc/+nl2//p5Nr/6eTZ/+jj2P/o4tf/5+LW/+fh1f/n4NT/5uDT/9fM + vf++rJn/vauY/7yqlv+7qZb/u6iU/7qmk/+5ppL/uKWQ/7ejj/+2oo3/sJqD/62Wf/+tln//rZd//62X + gP+ul4D/rpeA/66Ygf+umIH/rpiC/6+Ygv9Rtff/Vrz//2DA/v9pw/7/b8b+/3PI/v9zyP7/cMf+/2vE + /v9jwf7/Wb3//024//96qMP/sZyH/7GdiP+ynYj/sp2J/7Kdif+ynon/sp6K/4dpTP+Hak3/iGtO/4ls + UP+IblP/hW9V/4VvVf+Fb1X/hW9V/4VvVf+Fb1X/hW9V/4VvVf+Fb1X/hW9V/4VvVf+NeWL/lYJt/6mb + i//Evbb/y8XA/8/Lx/+4p5f/t6WT/7elk/+xnIj/qI50/6iNc/+njHL/p4xy/6aLcf+mi3D/pYpv/6WJ + b/+SfWX/eWhKpEk8EkxJPBI1STwSIkk8EhRHOxIKRTkRBEI3EAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEk8EgNJPBIKSTwSE0k8EiJJPBI2h3RZuKSUf//f283/7erj//Du + 5//v7ef/7+3m/+/t5v/u7OX/7uzk/+7r4//t6uL/7erh/+zp4P/s6OD/6+jf/+vn3v/q593/6ubc/+rl + 2//p5Nr/6eTZ/+jj2P/o4tf/6OLW/+fh1P/n4NT/5N3P/8Cum/+/rJr/vqyZ/72rmP+8qZb/u6iV/7qo + lP+5ppL/uKWR/7ikkP+3o4//s56J/62Wf/+tl3//rZeA/66XgP+ul4D/rpiB/66Ygf+umIL/rpiC/2qp + 0P9Jt///Urr//1q9//9fwP7/YsH+/2LB/v9gwP7/XL7//1W7//9MuP//QbP//5Ohpf+xnIf/sZ2I/7Kd + iP+ynYn/sp2J/7Keif+ynor/jG9T/4dpTf+Iak7/iWxQ/4tuUv+Hb1X/hW9V/4VvVf+Fb1X/hW9V/4Zw + Vv+LdVz/kXxl/5mFcP+gjnv/rp+Q/7Ommf+5raL/vrSr/8S8tf/HwLn/u6uc/7ekk/+3pZP/tqOR/6qR + eP+ojnT/qI1z/6eMcv+njHL/potx/6aLcP+lim//ooht/5F9Zf9mVjN2STwSREk8Ei9JPBIeSTwSEUc7 + EghFOREDQjYQAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASTwSA0k8 + EglJPBISSTwSIEk8EjSBb1Oin454/9/bzf/s6uH/8O7o//Du5//v7ef/7+3m/+/t5v/u7OX/7uvk/+7r + 4//t6uL/7erh/+3p4P/s6N//6+jf/+vn3v/q593/6ubc/+rl2//p5dr/6eTZ/+jj2P/o49f/6OLW/+fh + 1f/n4NP/z8Gx/8CunP+/rZv/vqya/72rmP+9qpf/vKmW/7uolP+6p5P/uaaS/7mlkf+4pJD/tqKO/7Cb + hP+tl4D/rZeA/66XgP+umIH/rpiB/66Ygv+umIL/oJuS/zux//9EtP//S7f//0+5//9Suv//Urr//1C5 + //9MuP//RrX//z6y//9FrPD/sZyH/7Gch/+xnYj/sp2I/7Kdif+ynYn/sp6J/7Keiv+Sdlv/h2lM/4hq + Tv+JbFD/im5S/4xwVf+Mclj/i3NZ/5B3Xv+VfWX/mYJs/52Hcv+hjHn/pZKA/6mYh/+wn4//tKSV/7en + l/+4p5f/tqST/7akkv+3pJL/t6ST/7elk/+ul4D/qY51/6mOdP+ojXP/qI1z/6eMcv+ni3H/potw/6WK + cP+chGr/j3tj9Ek8ElBJPBI7STwSKEk8EhlJPBINRzsSBkY6EQJCNhABAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJPBIDSTwSCEk8EhFJPBIfSTwSMXpoS4qRfWX/39vN/+jl + 2//x7+n/8O7o//Du5//w7uf/7+3m/+/s5v/v7OX/7uzk/+7r4//t6uL/7erh/+3p4P/s6OD/6+jf/+vn + 3v/r5t3/6ubc/+rl2//p5Nr/6eTZ/+jj2P/o4tf/6OHW/+fh1f/b0cP/wbCe/8Cvnf+/rpz/vq2a/76r + mf+9q5j/vKqW/7uolf+6qJT/uqeT/7mlkv+4pJD/t6OP/7Sgi/+wmYP/rpeA/66Ygf+umIH/rpiC/66Y + gv+vmYL/b6LB/zWu//87sf//P7P//0Gz//9Bs///QLP//zyx//83r///MKz//5Cfpf+xnIf/sZyH/7Gd + iP+ynYj/sp2J/7Kdif+ynon/sp6K/52Da/+HaUz/iGpO/4lsUP+KblL/jHBV/45zWP+Qdlz/k3lh/5uE + bf+jjXj/qZSA/6+cif+yn4z/taKP/7WikP+2o5D/tqOR/7ajkf+2o5H/tqSS/7ekkv+1oY//rJN7/6qP + dv+pjnX/qY50/6iNc/+ojXP/p4xy/6eLcf+mi3D/pYpw/5N+Zv+Fcle+STwSREk8EjFJPBIhSTwSFEk8 + EgpHOxIERjoRAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEk8 + EgNJPBIHSTwSEEk8Eh1JPBIvcWBAcpF9Zf/a1cb/6OXb//Hv6f/x7+n/8O/o//Du6P/w7uf/7+3m/+/t + 5v/v7OX/7uzk/+7r4//u6uL/7erh/+zp4P/s6OD/6+je/+vn3v/r5t3/6ubc/+rl2//p5Nr/6eTZ/+nj + 2P/o4tf/6OLW/+fh1P/Ht6f/wbCf/8Cwnf/Arpz/v62b/76smv+9q5n/vKqX/7uplv+7qJT/uqeU/7mm + kv+4pZH/t6SQ/7ejjv+0n4r/sJqE/66Ygf+umIL/rpiC/6+Zgv+vmYP/bKHB/yuq//8vrP//Ma3//zGt + //8vrP//LKv//yep//98oLP/sZyH/7Gch/+xnIf/sZyI/7KdiP+ynYj/sp2J/7Keif+ynor/sJqG/5d9 + Y/+Iak3/jnJX/5d9ZP+giHD/qJF8/62Yg/+0oI3/tKGN/7Shjv+1oY7/taGP/7Wij/+1oo//taKQ/7aj + kP+2o5H/tqOR/7ajkf+znor/r5iB/6uQd/+qkHb/qo92/6mPdf+pjnT/qI1z/6iNc/+njHL/p4tx/6aL + cP+fhmz/kX1l/2BRLV9JPBI4STwSJ0k8EhlJPBIPSTwSB0c7EgNFOREBAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASTwSA0k8EgdJPBIPSTwSG0k8EixiUy9ZkX1l/8vD + s//j4NT/8vDq//Hw6v/x7+n/8e/o//Du6P/w7uf/7+3m/+/t5v/v7OX/7uvk/+7r4//u6uL/7erh/+zp + 4f/s6eD/7Ojf/+vn3v/r5t3/6ubb/+rl2//q5Nn/6eTZ/+nj1//o4tf/6OLW/9jMvv/DsqH/wrGf/8Gw + nv/Br53/wK6c/7+tm/++q5n/vaqY/7yqlv+7qZX/uqeU/7qmk/+5ppL/uKSQ/7ejj/+3o47/tJ+K/7Cb + hv+umIL/r5mC/6+Zg/+vmYP/i5yi/1ah0P8qpff/IKb//zKk7/9VodH/npyV/7Gbhv+xnIb/sZyH/7Gc + h/+xnIj/sp2I/7KdiP+ynYn/sp6J/7Keiv+ynor/s56K/7Ofi/+zn4v/s5+L/7OgjP+0oIz/tKCN/7Sg + jf+0oY3/tKGO/7Whjv+1oY//taKP/7Wij/+0oY7/tJ+L/7Gbhv+vl4D/rZN7/6ySeP+rkXj/q5B3/6qQ + dv+qj3b/qY91/6mOdP+ojXP/qI1z/6eMcv+ni3H/pIpv/5N+Zv+Gc1i7STwSPUk8EixJPBIdSTwSEkk8 + EgpJPBIESDsSAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABJPBICSTwSBUk8Eg1JPBIZSTwSKUk8Ej6RfWX/xr2s/+Lf0v/y8ev/8vDq//Hw6v/x7+n/8e/p//Du + 6P/w7uf/8O3m/+/t5v/v7OX/7+vk/+7r4//t6uL/7erh/+zp4P/s6eD/7Ojf/+vn3v/r593/6ubc/+rl + 2//q5Nr/6eTZ/+nj2P/o4tb/5d7S/8a2pv/Ds6H/wrKg/8Kwn//Br57/wK6c/7+tm/++rJr/vquY/72q + l/+8qZb/u6iV/7qnlP+5ppL/uaWR/7ikkP+3o4//tqKO/7WgjP+ynYf/sJqE/6+Zg/+vmYP/r5qE/7Ca + hP+wmoT/sJuF/7Cbhf+wm4b/sZuG/7Gchv+xnIf/sZyH/7GciP+xnYj/sp2I/7Kdif+ynon/sp6K/7Ke + iv+znor/s5+L/7Ofi/+zn4v/s6CM/7SgjP+0oI3/tKCN/7Shjf+0oI3/s56K/7Kch/+xmYP/r5d//66V + fP+ulHv/rZR7/62Tev+sknn/rJJ4/6uReP+rkHf/qpB2/6qPdv+pj3X/qY50/6iNc/+ojXP/p4xy/6eM + cf+XgWj/j3tj81hJI0pJPBIvSTwSIUk8EhVJPBIMSTwSB0k8EgNHOxIBAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEk8EgFJPBIFSTwSC0k8EhZJPBImSTwSO456 + Yue4rJn/39vN//Px7P/y8ev/8vDr//Lw6v/x7+n/8e/p//Du6P/w7uf/8O3m/+/t5v/v7OX/7+zk/+7r + 4//t6uL/7erh/+zp4P/s6OD/7Oje/+vn3f/r5tz/6uXb/+rl2v/p5Nn/6ePY/+ji1//o4db/1su9/8S0 + o//Ds6L/w7Gg/8Kxn//BsJ7/wK+d/7+unP+/rZr/vqyZ/72rmP+8qpf/u6mW/7qolP+6ppP/uaaS/7il + kf+3pJD/tqKP/7aijf+1oY3/s5+K/7Gch/+wm4X/sJqE/7CahP+wm4X/sJuF/7Cbhv+xm4b/sZyG/7Gc + h/+xnIf/sZyI/7GdiP+ynYj/sp2J/7Keif+ynor/sp6K/7Oeiv+zn4v/s5+L/7Ofi/+zn4r/s56J/7Od + h/+ym4T/sZmB/7GYgP+wmH//sJd//6+Wfv+vln3/rpV8/66UfP+tlHv/rZN6/6ySef+sknn/q5F4/6uR + d/+qkHb/qo92/6mPdf+pjnT/qI1z/6iNc/+njHL/mYJp/5F9Zf9sXDpgSTwSL0k8EiJJPBIXSTwSDkk8 + EgdJPBIESTwSAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAASTwSAUk8EgRJPBIKSTwSFEk8EiRJPBI3i3hezrOmkv/f283/8O/p//Px7P/y8ev/8vDr//Lw + 6v/x8Or/8e/p//Hu6P/w7uf/8O3m/+/t5v/v7OX/7+zk/+7r4//t6uL/7erh/+3p4P/s6N//6+fe/+vm + 3f/q5tz/6uXb/+nk2v/p49j/6OLX/+ji1v/l3tL/x7in/8S0o//DsqL/wrKh/8KxoP/BsJ7/wK+d/8Cv + nP+/rZv/vqya/72rmf+8q5j/u6mW/7uolf+6p5T/uaaT/7ilkv+4pJH/t6SP/7aij/+1oY3/tKCM/7Sg + i/+znon/sp2I/7Gch/+wm4b/sJuG/7Gbhv+xnIb/sZyH/7Gch/+xnIj/sZ2I/7KdiP+ynYn/sp2J/7Ke + iv+znon/tJ6I/7SeiP+0nYf/tJyF/7SbhP+zm4P/s5qC/7Kagv+xmYH/sZiA/7CYf/+wl3//r5Z+/6+W + ff+ulXz/rpR8/62Ue/+tk3r/rJJ5/6ySef+rkXj/q5F3/6qQdv+qj3b/qY91/6mOdP+ojXP/pYtx/5WA + Z/+RfWX/fWtOgkk8Ei5JPBIiSTwSF0k8Eg9JPBIJSTwSBEk8EgJJPBIBAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASTwSA0k8EglJPBISSTwSIUk8 + EjOHdFq3pJR//9/bzf/u7OX/8/Lt//Px7P/z8ez/8vHr//Lw6v/x8Or/8e/p//Hu6P/w7uf/8O3n/+/t + 5f/v7OX/7uvk/+7r4//t6uL/7enh/+zo4P/s6N7/6+fd/+rm3P/q5dv/6eTa/+jj2P/n4tf/5+HV/+bg + 1P/Xzb//xLSk/8Ozo//Ds6L/wrKh/8KxoP/BsJ//wbCe/8Cvnf/Arpz/vq2b/72smv+9q5j/vKqX/7up + lv+6qJX/uaeU/7mmk/+4pZH/t6SR/7ejj/+2oo7/taGN/7Wgi/+ynYn/sZ2H/7Cchv+wm4b/sZuG/7Gc + hv+xnIf/sZyH/7KdiP+znon/tZ+J/7agif+2n4n/t5+I/7afiP+2nof/tZ2G/7Wdhv+0nIX/tJyE/7Ob + g/+zmoP/spqC/7KZgf+xmID/sZiA/7CXf/+wln7/r5Z9/6+Vff+ulHz/rpR7/62Tev+tk3r/rJJ5/6uR + eP+rkXf/qpB3/6qPdv+pj3X/poxy/5yFbP+RfWX/kHxj8m9ePllJPBIqSTwSH0k8EhZJPBIPSTwSCUk8 + EgRJPBICSTwSAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABJPBIDSTwSCEk8EhFJPBIdSTwSL4JwVJ+fjnj/39vN/+zq4v/08u7/8/Lt//Py + 7P/z8ez/8vHr//Lw6//x7+r/8e/p//Hu6P/w7uf/8O3m//Dt5f/v7OX/7uvj/+3q4v/t6eH/7Ojg/+vn + 3//r593/6uXc/+jk2v/o49j/5+HX/+bg1f/l39T/5N7S/+Td0f/NwbL/w7Oj/8Ozov/CsqL/wrKh/8Kx + oP/BsaD/wbCe/8Gvnv/Arp3/v66b/76smv++q5n/vaqY/7yql/+7qJb/t6SR/7ejjv+zn4r/sp6J/7Gb + hv+vm4X/sJqE/7CahP+wmoX/sp2H/7Oeif+2oIr/t6GM/7iijP+6o43/uaKM/7mii/+4oYv/uKGK/7eg + if+3n4j/tp+I/7aeh/+1nYb/tZ2G/7Schf+0nIT/s5uD/7Oag/+ymoL/spmB/7GYgP+xmID/sJd//7CW + fv+vln3/r5V9/66UfP+ulHv/rZN6/62Tev+sknn/q5F4/6uRd/+njXT/oIhv/5iCav+RfWX/kX1l/4l2 + XLFcTSg7STwSJUk8EhxJPBIUSTwSDUk8EghJPBIESTwSAkk8EgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEk8EgNJPBIHSTwSD0k8 + EhpJPBIrfGpNhJF9Zf/f283/5+TZ//Tz7v/08+7/9PLt//Py7f/z8ez/8vHr//Lw6//y7+r/8e/p//Hv + 6P/w7uf/8O3m/+/s5f/u6+T/7erj/+zp4f/r6OD/6ufe/+nl3P/o49r/5+LY/+bg1v/l39T/5N3T/+Pc + 0f/i28//4drO/9/Xy//JvK3/wrKi/8Kyov/CsqL/wrKh/8Kyof/CsaD/wbCg/7yplv+6p5T/tqKO/7Wg + i/+ynIf/r5qD/66Ygf+umIL/r5iC/7Gbhf+znYf/tqCK/7ehjP+6pY//vKaQ/72nkf+9ppH/vKaQ/7yl + j/+7pI7/u6SO/7qjjf+6o4z/uaKL/7mhi/+4oYr/t6CJ/7efiP+2n4j/tp6H/7Wehv+1nYb/tJyF/7Sc + hP+zm4P/s5qD/7Kagv+ymYH/sZmA/7GYgP+wl3//sJZ+/6+Wfv+vlX3/rpV8/66Ue/+tk3v/po10/6CI + cP+bhGz/lH9n/5F9Zf+RfWX/j3tj5Ih1WqNpWTdGSTwSJUk8Eh5JPBIYSTwSEUk8EgxJPBIHSTwSBEk8 + EgJJPBIBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAASTwSAkk8EgVJPBIMSTwSFkk8EiV0Y0RokX1l/9rVxv/g3M//8/Lt//Tz + 7//08+7/9PLt//Py7f/z8ez/8vHr//Lw6v/y8Or/8e/p//Hu6P/w7ef/8O3m/+7s5P/t6uP/7Onh/+vn + 3//p5dz/5+Pa/+bh1//k39X/493T/+Hc0f/g2s//39jN/97Xy//d1sr/3dXJ/9jQwf/OwrP/uaiV/7Kf + i/+tmIL/r5qE/6uUfP+rlH7/rJV+/62Xf/+vmoP/s52G/7ehi/+4oo3/u6aR/7ynkv/BrJf/wKuW/8Cq + lf+/qpT/v6mU/76ok/++qJL/vaeR/72mkf+8ppD/vKWP/7ukjv+7pI7/uqON/7qjjP+5oov/uaGL/7ih + iv+3oIn/t5+I/7afiP+2nof/tZ6G/7Wdhv+0nIX/tJyE/7Obg/+zmoP/spqC/7KZgf+xmYD/sZiA/7CX + f/+ulXz/p493/6CJcf+chm3/loFp/5F9Zf+RfWX/kX1l/5F9Zf+NeWDJhnNYlnJhQVNJPBInSTwSIUk8 + EhxJPBIXSTwSEkk8Eg1JPBIJSTwSBkk8EgNJPBICSTwSAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJPBIBSTwSBEk8 + EglJPBISSTwSHltNJzyRfWX/y8Oz/9/bzf/o5dz/9fTv//Tz7//08+7/9PLu//Py7f/z8ez/8/Hr//Lw + 6//y8Or/8e/p//Hu6P/w7ef/7+zl/+3q4//r6OD/6ebd/+fj2v/l4Nj/4dzR/9nTx//Y0cT/z8a3/83E + tP/Gu6n/xbqo/7+zn//BtKD/wbSg/8G0oP/EtqL/wrGd/7uok/+6ppD/vKeS/72olP+/q5b/xK+b/8Sv + m//Dr5r/w66a/8Ktmf/CrZj/wayX/8Gsl//Aq5b/wKqV/7+qlP+/qZT/vqiT/76okv+9p5H/vaaR/7ym + kP+8pY//u6SO/7ukjv+6o43/uqOM/7mii/+5oYv/uKGK/7egif+3n4j/tp+I/7aeh/+1nob/tZ2G/7Sc + hf+0nIT/s5uD/7CZgf+qknr/o411/5+Jcf+Zg2v/k35m/5F9Zf+RfWX/kX1l/5F9Zf+NeWDJinddr4Rx + VodyYUJSSTwSJ0k8EiNJPBIfSTwSG0k8EhdJPBIUSTwSEEk8Eg1JPBIJSTwSBkk8EgRJPBICSTwSAQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJPBIDSTwSB0k8Eg5JPBIYSTwSJo56YdezppL/39vN/9/b + zf/q597/9fTv//Xz7//08+7/9PLu//Py7f/z8ez/8/Hr//Lw6//w7uj/7Ong/+vo3//k4NT/4dzR/9vV + yP/Uzb7/zcS0/8W8qf/Bt6T/u66b/7iql/+zpJD/saCM/62ciP+rmIP/qJWA/6iTf/+qloH/rpmF/7Ke + if+3oo7/u6eT/7+rl//BrZn/w6+b/8Ovm//Er5v/xK+b/8Svm//Drpr/wq6Z/8KtmP/BrJj/wayX/8Cr + lv/AqpX/v6qV/7+plP++qZP/vqiS/72nkv+9ppH/vKaQ/7ylj/+7pY//u6SO/7qjjf+6o4z/uaKM/7mh + i/+4oYr/t6CJ/7egif+2n4j/s5yF/6yVfv+lj3f/oIpz/5mEbP+Tfmb/kX1l/5F9Zf+RfWX/kX1l/497 + Y+SNemHIhnNYlYFvU3l0YkNQSTwSJkk8EiNJPBIgSTwSHUk8EhpJPBIXSTwSFEk8EhJJPBIPSTwSDEk8 + EgpJPBIISTwSBkk8EgRJPBIDSTwSAkk8EgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEk8 + EgJJPBIFSTwSCkk8EhJJPBIegW9TeZF9Zf/Qybn/39vN/9/bzf/h3tH/5eLX/+rn3v/k4dX/5OHV/+Tg + 1P/g287/39rL/97Zyv/a0cL/2M/A/9TKuf/OwbH/yLqp/8Cwnf+6qZb/sZ6K/6yZhP+olID/pZF9/6OP + ev+ijXj/oIx3/5+Ldf+gi3b/oox4/6WQe/+plH//rpmF/7Sfi/+4pJD/vamV/8CsmP/Drpv/w6+b/8Sv + m//Er5v/xK+b/8Oumv/Crpn/wq2Y/8GsmP/BrJf/wKuW/8Cqlf+/qpX/v6mU/76pk/++qJL/vaeS/72m + kf+8ppD/vKWP/7ulj/+7pI7/uqON/7qjjP+xm4T/rJZ//6SPd/+finL/moVu/5F9Zf+RfWX/kX1l/5F9 + Zf+RfWX/j3tj5I16YciGc1iVgW5SenlnSV9JPBIoSTwSJEk8EiFJPBIeSTwSG0k8EhhJPBIWSTwSFEk8 + EhJJPBIQSTwSDkk8EgxJPBIKSTwSCEk8EgdJPBIGSTwSBEk8EgNJPBICSTwSAUk8EgEAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEk8EgNJPBIHSTwSDUk8EhVJPBIhinddrpWC + a/+8sJ7/3dbH/93Vx//c1MX/2tDB/9rPwP/Yy7v/1sm5/9bHtv/SwbD/0sCv/9C/rv/OvKv/y7mn/8a0 + ov/ArZv/uaeT/7OfjP+smYT/p5N+/6KOef+mkn//qZWB/6SPe/+mkHr/oIlx/5yEa/+dhW7/n4hx/6WQ + e/+qloH/sZyI/7ajjv+8qJP/v6uY/8Kumv/Dr5v/xK+b/8Swm//Er5v/w66a/8Kumf/CrZn/wayY/8Gs + l//Aq5b/wKuW/7+qlf+/qZT/vqmT/76ok/+9p5L/t6GL/7Gbhf+pk33/o453/5uGb/+WgWr/kX1l/5F9 + Zf+RfWX/kX1l/5F9Zf+OemLWjHhfu4ZzWZSBb1N5emhKXUk8EiZJPBIjSTwSIEk8Eh5JPBIcSTwSGkk8 + EhdJPBIVSTwSE0k8EhFJPBIPSTwSDUk8EgtJPBIKSTwSCEk8EgdJPBIGSTwSBUk8EgRJPBIDSTwSA0k8 + EgJJPBIBSTwSAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAASTwSAkk8EgRJPBIISTwSDkk8EhZJPBIhiXZcn5F9Zf+mlH7/0sGx/9bGtf/WxbX/1cS0/9XE + s//Uw7L/1MOy/9LBsP/SwK//0L+u/868q//KuKb/xbOh/7+smf+4pJH/v6+g/9nQxv/d1c3/4trR/9TI + vP/Ht6f/u6eU/6+Ygv+li3H/nIBk/5p9YP+afWD/mn5h/6qVgP+wnIj/tqKO/7ynk/+/q5f/wq2a/8Ov + m//EsJz/xLCb/8Svm//Drpr/wq6Z/8Ktmf/BrJj/wayX/72ok/+0n4n/rpmD/6iTfP+ciHD/mYVt/5F9 + Zf+RfWX/kX1l/5F9Zf+RfWX/kHxk8Y16YciIdVuihnNZlHlnSV90YkNPSTwSJUk8EiJJPBIgSTwSHUk8 + EhtJPBIYSTwSFkk8EhRJPBISSTwSEUk8Eg9JPBIOSTwSDEk8EgpJPBIJSTwSCEk8EgdJPBIGSTwSBUk8 + EgRJPBIDSTwSA0k8EgJJPBIBSTwSAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASTwSAkk8EgVJPBIJSTwSDkk8 + EhVJPBIeemhKXY97Y+OVgWr/xbOh/9bFtf/VxLT/1cSz/9TDsv/Uw7L/0sGw/9LAr//Qv63/zryr/8q4 + pv/Fs6H/vqyZ/+DY0P///////f38//Ht6f/i2tL/1cm9/8i4qP+7qJX/sJmC/6WMcv+dgGT/mn1g/5p9 + YP+afWD/q5aC/7Gdif+3o4//vaiU/8CrmP/Crpr/w6+b/8SwnP/BrJj/t6KN/7Cchv+qlX//oIx1/52J + cf+RfWX/kX1l/5F9Zf+RfWX/kX1l/5F9Zf+NemHIjHhfu4ZzWZR+bE9remhKXUk8EiZJPBIjSTwSIEk8 + Eh5JPBIcSTwSGkk8EhhJPBIWSTwSFEk8EhJJPBIQSTwSDkk8Eg1JPBILSTwSCkk8EglJPBIISTwSB0k8 + EgZJPBIFSTwSBUk8EgNJPBIDSTwSAkk8EgJJPBIBSTwSAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAASTwSAkk8EgVJPBIISTwSDEk8EhNJPBIbX1AsMox4X7uRfWX/r5yI/9HA + r//VxLP/1MOz/9TDsv/SwbD/0sCv/9C/rv/OvKv/yrmn/8a0of/ArZr/7unk///////9/f3/8e7q/+Pb + 1P/Wyr7/yLmp/7yplv+wmoP/poxz/52BZf+afWD/mn1g/5p9YP+umob/rJiE/6qWgf+lkHv/pZF7/56K + c/+ciHH/kHxk/5F9Zf+RfWX/kX1l/5F9Zf+RfWX/jXphyIx4X7uGc1mUgW9TeHpoSl1fUCszSTwSI0k8 + EiBJPBIeSTwSHEk8EhpJPBIYSTwSFkk8EhRJPBISSTwSEUk8Eg9JPBIOSTwSDUk8EgtJPBIKSTwSCEk8 + EgdJPBIHSTwSBkk8EgVJPBIESTwSA0k8EgNJPBICSTwSAkk8EgFJPBIBSTwSAQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASTwSAkk8 + EgRJPBIHSTwSC0k8EhBJPBIXSTwSH39sUGqQfGTxnYpz/8i2pf/Uw7P/1MOy/9PCsf/SwbD/0L+u/8+9 + q//Luqj/x7Wj/8Kvnf/v6uX///////7+/f/y7+v/5NzV/9bLv//Juqr/vaqX/7GbhP+mjXT/nYFl/5p9 + YP+afWD/mn1g/4FtVv97Z1H/gW1W/4ZyW/+Kdl//jXli/4x4X8mMeF+7hnNZlIFvU3h6aEpdX1ArM0k8 + EiNJPBIgSTwSHkk8EhxJPBIaSTwSGEk8EhZJPBIUSTwSEkk8EhFJPBIPSTwSDkk8Eg1JPBILSTwSCkk8 + EglJPBIISTwSB0k8EgZJPBIFSTwSBUk8EgRJPBIDSTwSA0k8EgJJPBIBSTwSAUk8EgEAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASTwSAUk8EgNJPBIFSTwSCUk8Eg1JPBITSTwSG25d + PD2NemHHkX1l/6qXgv/HtaP/08Kx/9LBsP/Rv67/z76s/8y7qf/Jt6X/xbOg//Dr5v///////v7+//Pw + 7P/l3db/08e7/8Szov+5pZH/rJR8/6KIbv+cf2P/mn1g/5p9YP+afWD/hXFa/3NgR6ZzYEaJcV9Ca11N + Kz5LPhYqSjwUJEk8Eh9JPBIcSTwSGkk8EhhJPBIWSTwSFEk8EhJJPBIRSTwSD0k8Eg5JPBINSTwSC0k8 + EgpJPBIJSTwSCEk8EgdJPBIGSTwSBUk8EgVJPBIESTwSA0k8EgNJPBIDSTwSAkk8EgFJPBIBSTwSAQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAASTwSAUk8EgJJPBIESTwSB0k8EgtJPBIQSTwSFUk8EhyJdVuPkHxk8JF9Zf+VgWn/oY53/6CN + dv+vnIf/nIlz/5mGcP+MeWL/4dzX//f28//m39j/18vA/8W1pf++q5n/tqKN/6+Ygf+njnX/oIVq/5t+ + Yv+afWD/mn1g/5p9YP+HdFzyVkQjPFVEIjFTQx8nUEEcH00/GBlLPRQVSTwSEUk8Eg9JPBIOSTwSDUk8 + EgtJPBIKSTwSCUk8EghJPBIHSTwSBkk8EgVJPBIFSTwSBEk8EgNJPBIDSTwSA0k8EgJJPBIBSTwSAUk8 + EgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEk8EgJJPBIDSTwSBUk8 + EghJPBIMSTwSEEk8EhVJPBIbgW9TZYp3XZ2OemHGj3ti4497Y/+NeWH/iHRbyol2XuXSyL7/4NfO/9vQ + xv/Ux7v/zL2u/8Oyof+7p5T/spyG/6qSev+jiG7/nIBk/5p9YP+XfF//kHlg/4ZyWqBZRyYlWEYkHVVE + IRdSQx4ST0AaDks9FQpJPBIISTwSB0k8EgZJPBIFSTwSBUk8EgRJPBIDSTwSA0k8EgNJPBICSTwSAUk8 + EgFJPBIBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEg7EgFIOxICSDsSBEg7EgZIOxIJSDsSDEg7Eg9IOxITSDsSF0g7 + EhpJPBMdSjwUIEw+FiNOPxknfmtQa5+Oef/AtKb/zcG1/8a5q/+/sKD/uKeV/7Geiv+rloD/nohx/5iB + aP+QemH/jHhg8Il1XaiDb1ZiXUoqGVtJKBVaSCcPV0YkC1REIQhRQR0GTD4WA0g7EgNIOxIDSDsSAkg7 + EgFIOxIBSDsSAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABGOhEBRjoRAkY6EQRGOhEFRjoRB0Y6EQpGOhEMRjoRDkc7EhBJPBQSSz0WFE0/GRZQQR0ZfGlORYl1 + XIuLd1+njHhgxIx4YMSMeGDEjHhgw4l1XImJdV2JhXJYXYBtUz9eSisTX0ssEV9LLA5eSysMXEopCltJ + KAdaSCgEVkYkA1FCHQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARDgQAUQ4EAJEOBADRDgQBEQ4 + EAVEOBAGRDgQB0Y6EwhJPBcJTD4aCk9AHQxRQiAOVEMiDldFJQ9YRicPWUcoD1pIKQ5cSSoNXEgqDFtI + KgxbSSoKXEosCF1KLAhgTC8HYU0vBWBMLgReSy0DW0kqAldGJgFRQh8BAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/NA8BPzQPAT80DwI/NA8DPzQPA0Q3FANHOhgESTwaBE0+ + HQVPQCAGUkIjBlZEJgVWRScFWUcrBVtILARaSCwEWkgrBFlHKwNYRioDWEcqA19LMAFjTjMBY04zAWNO + MwEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABDNxcBSTscAUs8HwFMPSEBTD0hAUw9IQFVRCoBW0gwAVtI + MAFbSDABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAP////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////z///////////////////8AB//////////////////gAAP//////////////// + 8AAAA////////////////gAAAAH//////////////8AAAAAA//////////////wAAAAAAH////////// + //+AAAAAAAA////////////wAAAAAAAAH//////////+AAAAAAAAAA//////////wAAAAAAAAAAH//// + ////+AAAAAAAAAAAA////////4AAAAAAAAAAAAH///////AAAAAAAAAAAAAB//////4AAAAAAAAAAAAA + AP/////AAAAAAAAAAAAAAAB////4AAAAAAAAAAAAAAAAf///AAAAAAAAAAAAAAAAAH//8AAAAAAAAAAA + AAAAAAA//wAAAAAAAAAAAAAAAAAAP/wAAAAAAAAAAAAAAAAAAD/4AAAAAAAAAAAAAAAAAAA/4AAAAAAA + AAAAAAAAAAAAP+AAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAH4AA + AAAAAAAAAAAAAAAAAB+AAAAAAAAAAAAAAAAAAAAfgAAAAAAAAAAAAAAAAAAAHwAAAAAAAAAAAAAAAAAA + AB4AAAAAAAAAAAAAAAAAAAAeAAAAAAAAAAAAAAAAAAAAHgAAAAAAAAAAAAAAAAAAAB4AAAAAAAAAAAAA + AAAAAAAeAAAAAAAAAAAAAAAAAAAAHwAAAAAAAAAAAAAAAAAAAB+AAAAAAAAAAAAAAAAAAAAfgAAAAAAA + AAAAAAAAAAAAH4AAAAAAAAAAAAAAAAAAAB+AAAAAAAAAAAAAAAAAAAAfgAAAAAAAAAAAAAAAAAAAH4AA + AAAAAAAAAAAAAAAAAB+AAAAAAAAAAAAAAAAAAAAfgAAAAAAAAAAAAAAAAAAAH8AAAAAAAAAAAAAAAAAA + AB/AAAAAAAAAAAAAAAAAAAAfwAAAAAAAAAAAAAAAAAAAH8AAAAAAAAAAAAAAAAAAAB/AAAAAAAAAAAAA + AAAAAAAfwAAAAAAAAAAAAAAAAAAAD8AAAAAAAAAAAAAAAAAAAA/AAAAAAAAAAAAAAAAAAAAP4AAAAAAA + AAAAAAAAAAAAD+AAAAAAAAAAAAAAAAAAAA/gAAAAAAAAAAAAAAAAAAAP4AAAAAAAAAAAAAAAAAAAD+AA + AAAAAAAAAAAAAAAAAA/gAAAAAAAAAAAAAAAAAAAP4AAAAAAAAAAAAAAAAAAAD+AAAAAAAAAAAAAAAAAA + AA/wAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAA + AAAAAAAP8AAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAP+AAAAAAA + AAAAAAAAAAAAD/gAAAAAAAAAAAAAAAAAAA/4AAAAAAAAAAAAAAAAAAAP+AAAAAAAAAAAAAAAAAAAD/gA + AAAAAAAAAAAAAAAAAA/4AAAAAAAAAAAAAAAAAAAP+AAAAAAAAAAAAAAAAAAAB/gAAAAAAAAAAAAAAAAA + AAf8AAAAAAAAAAAAAAAAAAAH/AAAAAAAAAAAAAAAAAAAB/wAAAAAAAAAAAAAAAAAAAf8AAAAAAAAAAAA + AAAAAAAH/AAAAAAAAAAAAAAAAAAAB/wAAAAAAAAAAAAAAAAAAAf8AAAAAAAAAAAAAAAAAAAP/AAAAAAA + AAAAAAAAAAAAD/4AAAAAAAAAAAAAAAAAAA/+AAAAAAAAAAAAAAAAAAAP/gAAAAAAAAAAAAAAAAAAH/4A + AAAAAAAAAAAAAAAAAB/+AAAAAAAAAAAAAAAAAAA//gAAAAAAAAAAAAAAAAAAP/4AAAAAAAAAAAAAAAAA + AH/+AAAAAAAAAAAAAAAAAAB//wAAAAAAAAAAAAAAAAAA//8AAAAAAAAAAAAAAAAAAf//AAAAAAAAAAAA + AAAAAAP//wAAAAAAAAAAAAAAAAAH//8AAAAAAAAAAAAAAAAAH///gAAAAAAAAAAAAAAAAD///4AAAAAA + AAAAAAAAAAD////AAAAAAAAAAAAAAAAH////wAAAAAAAAAAAAAAA/////+AAAAAAAAAAAAAAH//////w + AAAAAAAAAAAAA///////+AAAAAAAAAAAAf////////wAAAAAAAAAAH/////////+AAAAAAAAAD////// + /////4AAAAAAAB/////////////AAAAAAA//////////////8AAAAAf///////////////wAAAAP//// + ////////////gAAAf/////////////////8AP/////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ////////////////////////KAAAAGAAAADAAAAAAQAgAAAAAACAlAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADww + DwE/NQ8BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAQzcQAUM3EAFDNxABQzcQAUI2EAJCNxACQzcQAUM3EAFCNxABAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABGOhIBRjoSAkY6EgNHOxIDRjoSBUY6EgZGOhIIRjoSCUY6EglGOhIJRjoSCEY6 + EgdGOhIERjsSAkg7EgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAASTwSAUk8EgFJPBIBSTwSAUk8EgJJPBIDSTwSBEk8EgRJPBIGSTwSCEk8EgpJPBIMSTwSD0k8 + EhFJPBIVSTwSF0k8EhhJPBIXSTwSFUk8EhBJPBILSTwSB0k8EgRJPBIBAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABJPBIBSTwSAUk8EgFJPBIBSTwSA0k8EgNJPBIFSTwSBkk8EghJPBIJSTwSDEk8 + Eg5JPBIRSTwSFUk8EhhJPBIbSTwSIEk8EiVJPBIqSTwSLkk8Ei9JPBItSTwSKUk8EiFJPBIaSTwSEUk8 + EgpJPBIESTwSAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJPBIBSTwSAkk8EgNJPBIDSTwSBUk8EgZJPBIISTwSCkk8 + EgxJPBIPSTwSEkk8EhRJPBIYSTwSHEk8EiBJPBIkSTwSKUk8Ei9JPBI0STwSOUk8EkFJPBJHSTwSS0k8 + Ek1JPBJKSTwSREk8EjpJPBIuSTwSH0k8EhRJPBILSTwSBUk8EgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEk8EgFJPBIBSTwSAUk8EgFJPBICSTwSA0k8EgRJPBIFSTwSCEk8 + EglJPBILSTwSDkk8EhFJPBIVSTwSF0k8EhtJPBIgSTwSJUk8EilJPBIuSTwSNEk8EjpJPBI/STwSRkk8 + Ek1JPBJUSTwSWkg7EWBHOhBlRTgOZ0U4DWhFOQ5nSDsRYkk8EldJPBJHSTwSNEk8EiNJPBIVSTwSDEk8 + EgVJPBIBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASTwSAUk8EgFJPBIBSTwSAUk8EgNJPBIESTwSBUk8 + EgdJPBIISTwSC0k8Eg1JPBIQSTwSE0k8EhdJPBIcSTwSHkk8EiVJPBIpSTwSLkk8EjRJPBI6STwSQEk8 + EkZJPBJNSTwSU0k8ElpJPBJhSTwSZ0Y5DmxENwtsQTUKcUY5D3xNQBeJVUYemVdJIZ5TRRyTRTkOe0Y5 + Dm9JPBJiSTwSTEk8EjdJPBIlSTwSFkk8EgxJPBIFSTwSAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJPBIBSTwSAkk8EgJJPBIDSTwSBEk8 + EgVJPBIHSTwSCEk8EgpJPBIMSTwSD0k8EhJJPBIWSTwSGkk8Eh5JPBIjSTwSKEk8Ei5JPBI0STwSOUk8 + EkBJPBJHSTwSTEk8ElNJPBJaSTwSYEk8EmdJPBJuRjoPcUQ3DHRDNwp4RDcNf1NGHpNgUC2raVg3wXZk + RdSAblLkinZf+pB7Zf+GdFvzcmFBzlBDGpJGOQ53STwSZ0k8Ek5JPBI5STwSJUk8EhZJPBIMSTwSBUk8 + EgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJPBIBSTwSAUk8EgFJPBICSTwSA0k8 + EgRJPBIESTwSB0k8EghJPBIKSTwSDEk8Eg9JPBISSTwSFkk8EhhJPBIcSTwSIUk8EiVJPBIrSTwSMUk8 + EjhJPBI/STwSRUk8EkxJPBJUSTwSWkk8EmFIOxBmRjkOa0U4DW9FOQ12RzoQfUg7EIVHORCKV0gjn2xc + O8B0Y0bXfmxR6ol2XfORfWX+l4Js/6aQef+ymn//waeM/86xlP/DqYz/o412/4JwVupTRByaQzcMeUk8 + EmdJPBJPSTwSOEk8EiRJPBIVSTwSCkk8EgRJPBIBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEk8EgFJPBIBSTwSAUk8 + EgFJPBIDSTwSBkk8EgZJPBIISTwSCkk8EgxJPBIOSTwSEkk8EhZJPBIZSTwSHEk8EiFJPBImSTwSK0k8 + EjBJPBI1STwSO0k8EkJJPBJISTwST0k8EldJPBJeSTwSZkg7EGxEOA1vQjUKckI2CXdKPRSFUEIaklRG + H6BhUS2ydGNEzn1qUOSHdFv6lH9n/5qFbf+gjHT/rZZ9/72liv/LsJT/2Lue/9u+oP/cvZ//3b+g/92/ + oP/cvp//272d/7Oagf+CcFbrU0Qcm0M3DHlJPBJnSTwSTkk8EjVJPBIiSTwSEkk8EglJPBIEAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASTwSAUk8 + EgJJPBIDSTwSA0k8EgRJPBIGSTwSCEk8EglJPBIMSTwSD0k8EhJJPBIVSTwSGUk8Eh1JPBIhSTwSJUk8 + EitJPBIwSTwSNUk8EjxJPBJCSTwSSEk8Ek5JPBJVSTwSW0k8EmJJPBFpRzoQbUY5DXNENwx4QTYKfE0/ + FopbTSijY1Qxtm1cPcx7aUzdhHFX7o56Y/+ZhW//oY11/6+Zf/+7pIr/xK2R/8+1mf/cwaT/38Wn/97B + pP/cwaL/2r6g/9m9n//ZvJ7/2byd/9m8nf/Yu5z/3L6f/9S1mP+eh2//hHJY7FRFHpxGOQ55STwSZEk8 + EkpJPBIySTwSHkk8Eg9JPBIHSTwSAkk8EgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJPBIBSTwSAUk8 + EgFJPBIBSTwSAkk8EgNJPBIESTwSBkk8EgdJPBIJSTwSC0k8Eg1JPBIQSTwSFEk8EhdJPBIbSTwSIEk8 + EiVJPBIqSTwSMEk8EjZJPBI7STwSQUk8EkhJPBJPSTwSVUk8ElxIOxFiRzoQZkU4DmtFOA1xRToOd0g7 + EYBHOxGHUUMalWFSLq1vXz/JemdK4oRxV++OemH6k39o/5+Jc/+sl3//vKaM/8qymP/PuJz/1byg/97F + qf/ix6v/3sWn/9zCpv/awKP/2b6h/9m+of/ZvqD/2b2f/9m9n//ZvZ7/2byd/9m8nf/Yu5z/2ryd/9W2 + mP+tkHX/mYRs/4FuU+RLPhSPRTkOdUk8El9JPBJDSTwSKkk8EhdJPBIKSTwSBEk8EgEAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEk8 + EgFJPBIBSTwSAUk8EgFJPBIDSTwSBEk8EgVJPBIGSTwSCUk8EgpJPBINSTwSD0k8EhJJPBIXSTwSGkk8 + Eh5JPBIjSTwSKEk8Ei9JPBI0STwSOkk8EkJJPBJHSTwSTkk8ElVJPBJcSTwSYkk8EmlFOA5rRDcLb0E1 + CXJFOA56TkAYilNHHplYSiSoZ1c2u3hnSdiCb1byj3pi/5aCav+eiXL/p5F7/7Sgh//Er5b/0byi/9vD + qf/cxar/3sWp/97Gq//exqn/3MOn/9vCpv/awKT/2cCj/9nAo//Zv6L/2b+i/9m+of/ZvqH/2b2f/9m9 + n//ZvZ7/2byd/9m8nf/Yu53/2byd/9S2mP+wk3j/o4hu/5qGbv98a03dTD8VikY5D25JPBJUSTwSN0k8 + Eh9JPBIQSTwSBkk8EgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAEk8EgFJPBIDSTwSAkk8EgRJPBIFSTwSCEk8EghJPBILSTwSDUk8EhBJPBISSTwSFkk8 + EhpJPBIeSTwSIkk8EidJPBIsSTwSMUk8EjdJPBI+STwSRUk8EkxJPBJUSTwSWkk8EmJJPBJpSDwRb0Y5 + D3NEOA12QzYKeUQ5DYFWSCKYYFAtrGZWNL9zYkHSgW5T5ol2XfqTfWf/nopz/6mVfv+zn4f/wKuT/8u2 + nf/Wwaf/4Muw/+DKsP/dx63/3Maq/9vDqf/aw6n/2sOo/9rCp//awqf/2sGm/9rBpf/awaX/2cCk/9nA + o//Zv6P/2b+i/9m+of/ZvqH/2b2g/9m9n//ZvZ//2bye/9m8nf/ZvJ3/2byd/9W4mf+wlHn/pIlv/6WK + bv+bg23/fGpO3EY7EHxJPBJiSTwSREk8EilJPBIVSTwSCUk8EgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAASTwSAUk8EgJJPBICSTwSBUk8EgZJPBIJSTwSC0k8Eg1JPBIQSTwSE0k8 + EhZJPBIZSTwSHkk8EiJJPBInSTwSK0k8EjFJPBI3STwSPEk8EkNJPBJKSTwSUEk8EldJPBJdSDsQZEY5 + DmlFOA1wRTkNdUY5D35IOxGGSDsSjVpLJKJoVzW8cmFD039sUOyKdl31j3xk/5iEbv+olH3/sp+I/8Gu + l//Ou6T/1MGp/9vHr//hzbX/4s21/9/Ksf/dyK7/28Ws/9rFq//axav/2sSq/9rEqf/aw6n/2sOo/9rC + p//awqf/2sGm/9rBpf/awaX/2cCk/9nAo//Zv6P/2b+i/9m+of/ZvqH/2b6g/9m9n//ZvZ//2bye/9m8 + nf/ZvJ3/2byd/9W4mf+wlXn/o4dt/6aKb/+jh23/moRt/29fP8BENwxmSTwSTkk8EjBJPBIaSTwSC0k8 + EgMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJPBICSTwSBEk8EgdJPBIKSTwSDUk8 + EhJJPBIVSTwSGkk8Eh1JPBIiSTwSJ0k8EixJPBIxSTwSNkk8Ej1JPBJDSTwSSUk8ElBJPBJXSTwSXUk8 + EmRIOxFqRTgNa0I1Cm9DNgx2Sj0Tg1BEG5JVRyCiX1Arsm5dP8p8ak7kiXRc/pF+Zf+bh3D/o494/66b + hf+6qJH/zLqj/9rIsf/cy7T/3sy1/97Ntf/fzbb/3suz/9zJsP/bx6//28eu/9vGrf/bxq3/28Ws/9rF + q//axav/2sSq/9rEqf/aw6n/2sOo/9rCp//awqf/2sGm/9rBpf/awaX/2cCk/9nAo//ZwKP/2b+i/9m/ + ov/ZvqH/2b6g/9m9n//ZvZ//2bye/9m8nf/ZvJ3/2byd/9W4mf+vlXj/o4dt/6WKb/+liW7/o4hv/5B9 + ZfpYSSOGRDcNUEk8EjZJPBIdSTwSDEk8EgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARjoRAUg7 + EgNJPBIHSTwSC0k8EhFJPBIYSTwSHkk8EiVJPBIrSTwSMUk8EjdJPBI9STwSQ0k8EkpJPBJQSTwSVkk8 + El1JPBJjSTwSakg7EHBGOQ5zRDcMdkI2CntLPhSHW0wnoGNUMbVuXDzKemhL3IVyV++OeWH/mYVu/6WS + fP+unYb/uKeQ/8S0nf/Tw63/4NC6/+LTvf/h0Lr/3863/93LtP/byrP/28my/9vJsf/bybH/28iw/9vI + r//bx6//28eu/9vGrv/bxqz/28Ws/9rFq//axav/2sSq/9rEqf/aw6n/2sOo/9rDqP/awqf/2sKm/9rB + pv/awaX/2sCk/9nApP/ZwKP/2b+i/9m/ov/ZvqH/2b6g/9m9oP/ZvZ//2bye/9m8nv/ZvJ3/2byd/9e6 + m/+0mHz/o4Zu/6WKb/+liW7/pIhu/52Gb/9vXj63RDcMUEk8EjlJPBIfSTwSDUk8EgQAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAARjoRAkg7EgdJPBIOSTwSF0k8EiJJPBItSTwSN0k8EkBJPBJISTwST0k8 + EldJPBJeSDsRY0c6EGhFOQ5tRTgNckY6D3lIOhGBSDsQh0w/FpJiUi6tcF8/ynpnSuKDcFbujXph+ZJ+ + Z/+einP/rpyI/7qolP/JuaT/0sSu/9nKtf/f0bz/5NXA/+HUvv/f0bv/3c23/9zMtf/cy7X/3Mu0/9zK + s//byrP/28my/9vJsv/bybH/28iw/9vIsP/bx6//28eu/9vHr//dyK//38mw/+DKsf/fyrD/3siv/97I + rf/bxar/2sOo/9rDqP/awqf/2sKm/9rBpv/awaX/2sCk/9nApP/ZwKP/2b+i/9m/ov/ZvqH/2b6g/9m+ + oP/ZvZ//2b2e/9m8nv/ZvJ3/2byd/9m8nf+5nID/oodt/6WKb/+liW//pYlt/6OJb/9+bVDQSj4VW0c7 + EDxJPBIjSTwSEEk8EgZGOhIBAAAAAAAAAAAAAAAAAAAAAAAAAABBNg8BRjoRBEg7Eg1JPBIYSTwSJ0k8 + EjdJPBJHSTwSVkk8EmBJPBFoRjkObkQ3C3FBNQl0RjkPfU1BF4xSRR2ZV0gip2xbO8F4ZUnZgWxS7416 + Yf+Wg2v/nIpz/6iUfv+1pI//xbai/9XJtf/f0r7/39K+/+DTwP/h08H/4NO+/97Qu//dz7r/3M24/9zN + t//czbf/3My2/9zMtv/cy7X/3Mu0/9zKtP/cyrP/28my/9vJsv/bybH/28iw/9vIsP/bx6//38uy/+DM + tf/Wwqj/0Luh/8q0mv/Js5n/zbac/9K8ov/ex6z/4cqv/9vEqf/awqf/2sKm/9rBpv/awaX/2sCk/9nA + pP/ZwKP/2b+j/9m/ov/Zv6L/2b6h/9m+oP/ZvZ//2b2e/9m8nv/ZvJ3/2bye/9m8nf+4nID/oodt/6WK + b/+liW//pYlt/6KHbf+Jd13lUkQbakY5Dj1JPBIlSTwSEkk8EgdGOhICAAAAAAAAAAAAAAAAAAAAAAAA + AABBNg8DRjoRCUg7EhRJPBIlSTwSOkk8Ek5GOQ9fRDgNbUM2CnZFOQ6BUkQdlF9QLKxnVzXCdWNE1IBt + UeWHclj1lH5o/56Kdf+pmIP/taWQ/8K0oP/Mwa3/2My6/+Xayf/j2MX/4NXD/9/TwP/d0r7/3dC8/93Q + vP/dz7v/3M+6/9zOuv/czrn/3M24/9zNuP/czbf/3My2/9zMtv/cy7X/3Mu0/9zLtP/cyrP/28qy/9vJ + sv/bybH/28iw/9zKsv/gz7b/0Lui/62Zf/+Ygmf/jHRY/31lSf99ZUj/hW5R/5J6X/+nkHT/waqP/93G + q//dxar/2sKm/9rCpv/awab/2sGl/9rApP/ZwKT/2b+j/9m/ov/Zv6L/2b6h/9m+oP/ZvaD/2b2f/9m8 + nv/ZvJ7/2r2d/9m8nf+4nID/oodt/6WKcP+liW//pYlu/6KHbf+Idl3mUUMbb0Y5DkJJPBIqSTwSFEk8 + EgdGOhICAAAAAAAAAAAAAAAAAAAAAAAAAABCNg8FRjoRDkg7EhxJPBIzRjkORUg7EGNZSiOOalk4t3Vj + RNZ+a0/qiHRb85F8ZP6XhG7/pZF8/7SkkP/Et6X/0Maz/9bLuf/d08L/5NzK/+Tcyv/h2Mb/39bD/93S + wP/d0r//3dG+/93Rvv/d0b3/3dC8/93QvP/dz7v/3M+6/9zPuv/czrn/3M24/9zNuP/czbf/3My2/9zM + tv/czLX/3Mu0/9zLtP/cyrP/28qz/9vJsv/bybL/3821/9zJsf+ynYP/i3NY/39mSv+Da1D/lIFq/6qa + if+tn43/nYt2/4pzWf9+Zkr/gmpO/6CJbv/PuJ3/4Mit/9rDpv/awab/2sGl/9rApP/ZwKT/2b+j/9m/ + ov/Zv6L/2b6h/9m+oP/ZvqD/2b2f/9m9nv/ZvJ7/2r2d/9m8nf+3m3//oodt/6WKcP+liW//pYlu/6KI + bv+IdVzmUEIbc0Y5DkdJPBItSTwSF0k8EglGOhIDAAAAAAAAAAAAAAAAAAAAADowDgFCNg8HRjoREkg7 + EiVFOAw3UkQbaX5qT9KQfGT/m4dx/6CPef+tm4j/wLOg/87FtP/c08P/39nI/+HZyf/i28r/4trJ/+LZ + yP/f18X/3tTC/93Uwv/d08H/3dPA/93SwP/d0r//3dG+/93Rvv/d0b3/3dC8/93QvP/d0Lz/3c+7/9zP + uv/czrn/3M64/9zNuP/czbf/3My2/9zMtv/czLb/3Mu1/9zLtP/cyrT/28qz/9vJsv/ezbb/2MWt/5+K + cP9/aEv/iHFX/6iYhv/QycL/4ODc/+Xm5v/q6u3/7O7x/+jp6v/EvLL/l4Nt/3xkRv+Od1z/wqqP/9/H + q//awab/2sGl/9rApP/ZwKT/2cCj/9m/o//Zv6L/2b6h/9m+of/Zvp//2b2f/9m9nv/ZvJ7/2byd/93A + of/Ao4f/oYZs/6WKcP+lim//pYlt/6OJb/+JdVvmUEIadkY5DkpJPBIvSTwSGEk8EgpGOhIDAAAAAAAA + AAAAAAAACB0xATowDgJCNg8IRjoRFUU6DydPQRlHh3JY3ayah//Ivqz/1cy8/+Hby//n4tL/493O/+Hb + y//f2Mr/3tjH/97Wxv/e1sX/3tXE/97VxP/e1cP/3tTD/97Uwv/d1ML/3dPB/93TwP/d0sD/3dK//93R + vv/d0b7/3dC9/93QvP/d0Lz/3c+7/9zPuv/czrr/3M65/9zNuP/czbj/3M23/9zMtv/czLb/3Mu1/9zL + tP/cy7T/28qz/97Mtf/Zx6//nohu/35mSf+VgWj/xr2y/+Dc2f/h3dv/2dPO/8zCuP/Dtqn/vq+g/8m9 + s//X0cv/4d/e/7CjlP+EbVD/iHBV/8atkv/gx6z/2sGl/9rBpf/awKT/2cCj/9m/o//Zv6L/2b6h/9m+ + of/ZvqD/2b2f/9m9n//ZvJ7/2byd/97Bof/ApIf/oYZs/6aKcP+lim//pYlt/6OJb/+Pe2LxUkQdf0Y5 + DktJPBIySTwSGUk8EgpGOhIDAAAAAAAAAAAAAAAACB0xATowDgJCNg8JRjoRFkE0Ch9oVjR/ppWB/97Z + zP/n5Nb/493P/+Day//f2cr/3tjJ/97YyP/e18j/3tfG/97Wxv/e1sb/3tbF/97VxP/e1cT/3tTD/97U + wv/d1ML/3dPB/93TwP/d0sD/3dK//93Rvv/d0b7/3dC9/93QvP/d0Lz/3c+7/9zPuv/cz7r/3M65/9zO + uP/czbj/3M23/9zMtv/czLb/3Mu1/9zLtP/cy7T/3Mu0/+DPuP+rl33/fmZJ/5J+Zf/Lwbj/29bR/9LL + w/+8rJz/q5R+/6CHbP+XeVv/k3NU/5d5XP+bf2P/qJB4/8q/tf+zp5j/hG1R/5B4Xf/Qt5z/3sWp/9rB + pf/awKT/2cCj/9m/o//Zv6L/2b6h/9m+of/ZvqD/2b2f/9m9n//ZvZ7/2byd/97Bof/ApIf/oYZs/6aK + cP+lim//pYlt/6OHbf+Tf2j8VEYghkU4DUxJPBIySTwSGkk8EgpGOhIDAAAAAAAAAAAAAAAACB0xATow + DgJCNg8IRjoRFUE0ChxnVTOFtqiV/+Pg0v/f2sz/39nL/9/Zyv/f2cr/3tjJ/9/Zyf/g28v/3tfH/97X + xv/e1sb/3tbF/97VxP/e1cT/3tTD/97Uwv/d1ML/3dPB/93TwP/d0sD/3dK//93Rvv/d0b7/3dG9/93Q + vP/d0Lz/3c+7/93Pu//cz7n/3M65/9zOuP/czbj/3M23/9zMt//czLb/3Mu1/9zLtf/cy7T/38+4/8e1 + nf+EbVL/inRb/8O4q//TzMX/yb2z/7Whjv+qk3r/pY10/6KIbv+egmf/mn1h/5l8YP+Ye13/lndZ/5d5 + Xf+wmoX/m4dw/4BoTf+kjHH/3sWp/9zCpv/awKT/2cCj/9nAo//Zv6P/2b+i/9m+of/ZvqH/2b2f/9m9 + n//ZvZ7/2bye/97Bov+/o4b/oYZs/6aKcP+lim//pYlt/6OHbf+Sfmb6VEYghUU4DUxJPBIzSTwSGkk8 + EgpGOhIDAAAAAAAAAAAAAAAACB0xATowDgFCNg8IRjoRFEE0ChlnVzODq5mF/+Dcz//f28z/39rL/9/Z + yv/f2cr/4d3O/9/by//Y0b//4dzM/+DZyP/e1sb/3tbF/97VxP/e1cT/3tTD/97Uw//e1ML/3dPB/93T + wf/d08D/3dK//93Sv//d0b7/3dG9/93Qvf/d0Lz/3c+7/93Pu//cz7r/3M65/9zOuf/czbj/3M23/9zN + t//czLb/3My1/9zLtf/cy7T/3863/5yFbP+BaU3/r5+N/8/FvP/IvLD/uqiX/7WgjP+ynIb/rZZ//6eP + dv+iiG7/nYFl/5t+Yf+afWH/mn1h/5p9Yf+Yel3/mX5i/4x1Wv+Gb1T/xayR/97Fqf/awaX/2cCk/9nA + o//Zv6P/2b+i/9m+of/ZvqH/2b2g/9m9n//ZvZ//2bye/97Bov/Ep4r/o4hu/6aKcP+lim7/pYlu/6SI + bf+Tf2b6VEYfhUU4Dk1JPBIzSTwSGkk8EgpGOhIDAAAAAAAAAAAAAAAAAAAAAAAAAABCNg8GRjoREUI2 + CxpkVDBtnYp0++Hcz//g283/39rL/9/Zy//i3c7/zsKv/6SJb/+hh2v/rph//9zTw//f2Mj/3tbF/97W + xf/e1cT/3tXD/97Uw//e1ML/3dPB/93Twf/d08D/3dK//93Sv//d0b7/3dG9/93Qvf/d0Lz/3c+7/93P + u//cz7r/3M65/9zOuf/czrj/3M23/9zNt//czLb/3My1/9zLtf/fz7j/yref/4VtUv+Re2L/wrWp/8i9 + sf/DtKT/vq6c/7mnlf+1oY3/sp2I/6mSe/+chGv/lHlf/5N3XP+ZfGH/m31h/5p9Yf+afWH/m31h/5d7 + YP+Gb1P/pIxx/97EqP/awaX/2cCk/9nAo//Zv6P/2b+i/9m+of/ZvqH/2b6g/9m9n//ZvZ//2bye/93A + of/JrI3/pYpw/6WKb/+liW//pYlu/6SIbf+VgGf6VEYfhUU4Dk1JPBIzSTwSGkk8EgpGOhIDAAAAAAAA + AAAAAAAAAAAAAAAAAABBNg8GRjoREEM2CxthUS1dk35m9N/bzf/g283/39rL/+DazP/f2sn/oolu/8W2 + qv/TycD/oIVq/8K0nf/h28v/3tbF/97Wxf/e1cT/3tXD/97Uw//e1ML/3dPB/93Twf/d08D/3dK//93S + v//d0b7/3dG9/93Rvf/d0Lz/3dC8/93Pu//dz7v/3M65/9zOuf/czrj/3M23/9zNt//czLf/3My2/9zL + tf/j073/q5Z9/4FoTP+lk3//x7uv/8m7rv/Huav/w7Ok/72tnP+8qpf/qJJ8/4xzW/+GbFT/hmxV/4Rp + Uf+CZ07/jXFW/5p+Yf+afWH/mn1h/5x9Yf+Sd1v/iHJX/9S6oP/cwaX/2cCk/9nApP/ZwKP/2b+i/9m/ + ov/ZvqH/2b6g/9m9n//ZvZ//2bye/93Aof/IrI3/pYpw/6WKb/+liW//pYlu/6KHbP+chW//V0ojkUQ4 + DUpJPBIzSTwSGkk8EgpGOhIDAAAAAAAAAAAAAAAAAAAAAAAAAABBNg8FRjoRD0Q3DR1YSSNCjnlg59TP + v//i3c//39rL/+Ddzv/Z0sH/pIpu/+Xg3f/Z0Mr/r5mE/7ikjf/j3c7/3tbF/97Wxf/e1cT/3tXD/97U + w//e1MP/3dTC/93Twf/d08H/3dLA/93Sv//d0r//3dG+/93Rvf/d0L3/3dC8/93Pu//dz7v/3M66/9zO + uf/czrn/3M24/9zNt//czbf/3My2/9zMtv/gz7n/mYNn/4dwVf+xoI7/yLmt/9HFuv/Mv7L/xrip/8S0 + pv+umof/h21V/4RqUv+HbVX/hGlQ/493Yv+ciHb/jnhi/4pvU/+bfGD/mn1h/5t9Yf+Ye1//iXJX/76m + iv/fxqr/2sCk/9nApP/ZwKP/2b+i/9m/ov/ZvqH/2b6g/9m9oP/ZvZ//2bye/93Aof/HrI3/popw/6WK + cP+liXD/pYlu/6KHbP+bhW//V0kjkEQ4DUpJPBIzSTwSGkk8EgpGOhIDAAAAAAAAAAAAAAAAAAAAAAAA + AABBNg8FRjoRDUg7ER1FOg4rgnBU3M3Etf/i3tD/39rM/9/azP/h3Mz/pY1x/9TKwP/Z0Mn/tKCM/66Y + ff/k38//3tbG/97Wxf/e1sX/3tXE/97Vw//e1MP/3dTC/93Twf/d08H/3dLA/93Sv//d0r//3dG+/93R + vf/d0L3/3dC8/93Pu//dz7v/3M+6/9zOuf/czrn/3M24/9zNt//czbf/3My2/+DPuf/Twar/j3ld/412 + Xf+2o5P/z8S5/9bMw//PxLj/zL+y/8Gwof+NdF3/g2hQ/4dtVf+EaFD/l4Nw/7yzqf/Jwrv/xb61/56K + eP+NcVT/nH9i/5p9Yf+cfWH/jHNX/6uTeP/gx6v/2sCk/9nApP/ZwKP/2b+i/9m/ov/ZvqH/2b6g/9m+ + oP/ZvZ//2b2e/93Aof/Hq43/polw/6WKcP+linD/pYlu/6KHbP+bhW//V0kjkEQ4DUpJPBIzSTwSGkk8 + EgpGOhIDAAAAAAAAAAAAAAAAAAAAAAAAAABBNg8DRjoRC0g7EhtANAkifGpNycS5p//k4NL/39rM/9/a + y//m4dT/q5J5/8q8rv/Z0sn/u6iW/6aOcv/k3c7/3tbH/97Wxf/e1sX/3tXE/97Vw//e1MP/3dTC/93T + wf/d08H/3dLA/93Sv//d0r//3dG+/93Rvf/d0b3/3dC8/93QvP/dz7v/3M+6/9zOuf/czrn/3M24/9zN + t//czbf/3My2/+DQu//LuqL/i3RZ/5B6Yf+9rJv/187G/9nSy//SyL7/z8S4/7CdjP+BZU3/h21V/4Zs + U/+HblX/t6yh/9DLxP/V0Mr/3NnU/83Gv/+UfGb/lnhb/5p9Yf+cfWH/j3RZ/5qCaP/iya3/2sCk/9nA + pP/ZwKT/2b+j/9m/ov/Zv6L/2b6h/9m+oP/ZvZ//2b2e/9y/of/Ps5X/qo5z/6WKb/+linD/pIlu/6SI + bf+fh3D/VEcgjkQ4DUpJPBIzSTwSGkk8EgpGOhIDAAAAAAAAAAAAAAAAAAAAAAAAAABBNg8DRjoRCUg7 + EhhDNgojeWZJrbmsmv/l4dX/39rM/9/ay//k4dL/tqKL/72snP/Z0cn/wbCi/6OJbf/c1MP/39jI/97W + xf/e1sX/3tXE/97VxP/e1MP/3tTC/93Uwv/d08H/3dPA/93SwP/d0r//3dG+/93Rvv/d0b3/3dC8/93Q + vP/dz7v/3M+6/9zOuv/czrn/3M24/9zNuP/czbf/3My2/+DRu//MuqL/i3RZ/493XP/CsqL/3dfQ/9zV + z//Vy8P/0MS5/5iCbv+FaVL/h21V/4NoTv+Xg2//xr+2/9bQzP/i3tr/5uXi/+fk4v+tnY//j3JU/5t+ + Yf+afWH/k3db/5uDaf/iya3/2sGl/9rApP/ZwKT/2b+j/9m/ov/Zv6L/2b6h/9m+oP/ZvaD/2b2f/9y/ + of/Ps5X/qo90/6WKb/+minD/pYlu/6SIbf+dhm7/ZFQxnEY5DkxJPBIzSTwSGkk8EgpGOhIDAAAAAAAA + AAAAAAAAAAAAAAAAAABBNg8BRjoRCEg7EhVDNwwicmBBlK2ei//l49b/39rM/9/azP/j39D/vq6X/7Sh + jf/Z0sr/w7Wn/6GGa//SyLX/4drL/97Wxv/e1sX/3tXE/97VxP/e1cP/3tTC/93Uwv/d08H/3dPA/93S + wP/d0r//3dG+/93Rvv/d0b3/3dC8/93QvP/dz7v/3M+6/9zPuv/czrn/3M64/9zNuP/czbf/3My2/+DR + u//MuqL/i3Va/411Wv/AsaH/4NvV/+DY0f/XzsX/0cW6/5N8Zf+FalL/h21V/4BlTP+hkH//z8nE/9vX + 0v/t6+f/9vTz//Hw7/+8sKT/j3JY/5p8YP+afWH/lHhc/5uEaf/iya3/2sGl/9rApP/ZwKT/2cCj/9m/ + ov/Zv6L/2b6h/9m+of/Zvp//2b2f/9zAof/PspX/qo90/6WKb/+minD/pYlu/6SIbf+bhG3/cmJCq0Y6 + D0xJPBIzSTwSGkk8EgpGOhIDAAAAAAAAAAAAAAAAAAAAAAAAAABEOBABRjoRB0g7EhRENwwha1k4fqST + fv/n5Nf/39vN/9/azP/i39D/xbei/6qRev/c1c3/w7an/6KIb//Kvqn/4t7O/97Wxv/e1sX/3tXE/97V + xP/e1cP/3tTC/93Uwv/d08H/3dPA/93SwP/d0r//3dG+/93Rvv/d0b3/3dC9/93QvP/d0Lz/3c+7/9zP + uv/czrn/3M64/9zNuP/czbf/3My3/+DRu//KuKL/i3RZ/4x1Wf+8q5r/4t3Y/9/Z1P/XzsX/0ce7/5R9 + Z/+FalL/h21V/4BlTP+ikYD/zsrF/9zY0//v7Or/+Pf3//Lv7//DurD/knZc/5l8X/+afWH/lHhc/5mD + aP/iya3/2sGl/9rApP/ZwKT/2cCj/9m/o//Zv6L/2b6h/9m+of/Zvp//2b2f/9zAof/OsZT/qo90/6WK + cP+minD/pYlu/6SJbv+bhG3/cF8/qEY5D01JPBIzSTwSGkk8EgpGOhIDAAAAAAAAAAAAAAAAAAAAAAAA + AABEOBABRjoRB0g7EhJFOQ4hY1IvYp+OeP/d283/4t3Q/+DazP/i3M7/0ce2/6SLcv/VzMP/xriq/6KJ + b//Bspz/5d/Q/97Wxv/e1sX/3tXE/97VxP/e1cT/3tTD/97Uwv/d1ML/3dPB/93TwP/d0sD/3dK//93R + vv/d0b7/3dC9/93QvP/d0Lz/3c+7/9zPuv/czrr/3M65/9zNuP/czbj/3M23/+DQuv/RwKn/kHhe/4px + Vf+3pZT/4dzW/9/Y0v/XzsX/0cW7/5V9Z/+FalL/h21V/4NmTf+diXf/yMK7/9bRzP/k4Nz/6ufl/+nm + 5f+9sqf/kXZa/5l8X/+afWH/lHhc/6CIbf/iya7/2sGl/9rBpf/awKT/2cCj/9m/o//Zv6L/2b6h/9m+ + of/ZvqD/2b2f/9vAov/TtZj/rJF2/6WKcP+mi3D/pYlv/6WKbv+ehW7/b18/qUY5D05JPBI0STwSG0k8 + EgtGOhIDAAAAAAAAAAAAAAAAAAAAAAAAAABEOBABRjoRBkg7EhBJPBEhSz4URZiGb//X0cP/5OHU/+Dc + zv/g283/29XF/6KJb//Pw7f/yLyu/6WLdP+6qJH/5uHS/97Wxv/e1sb/3tbF/97VxP/e1cT/3tTD/97U + wv/d1ML/3dPB/93TwP/d0sD/3dK//93Rvv/d0b7/3dC9/93QvP/d0Lz/3c+7/9zPuv/cz7r/3M65/9zO + uP/czbj/3M23/93Nt//ezrj/ln9m/4VuUf+nkn3/3NXM/97X0P/VzML/0ca6/6GNeP+CZ0//h21V/4Rq + Uf+PemP/vLSq/8/Jwv/X0sz/2tbR/93b1v+voZH/j3JV/5t9Yf+afWH/k3Zc/62Vev/gx6z/2sGl/9rB + pf/awKT/2cCj/9nAo//Zv6L/2b6h/9m+of/ZvqH/2b2f/9q+oP/Yu5z/rpJ4/6OIb/+mi2//pYlv/6aK + bv+fhm7/bl9ArEY5D1FJPBI3STwSHUk8Eg1HOxIEAAAAAAAAAAAAAAAAAAAAAAAAAABEOBABRjoRBEg7 + Eg5JPBEeRjgNOZN/Z/LQyLj/5eLV/+Hcz//g3M7/39rK/6mRd//Ft6j/y76w/6mSe/+xnIT/4dzM/9/Y + x//e1sb/3tbF/97VxP/e1cT/3tTD/97Uwv/d1ML/3dPB/93TwP/d0sD/3dK//93Rvv/d0b7/3dG9/93Q + vf/d0Lz/3c+7/93Pu//cz7n/3M65/9zOuP/czbj/3M23/9zMt//k1L7/pJB3/4RsUP+UemD/0ca6/9vT + zP/Sx73/0MS5/7akk/+BZ0//h21V/4dtVf+DaVD/p5mK/8W/t//Jwrv/zsnC/8fBuv+ZhG7/lHda/5t9 + Yf+afWH/kHRY/8Gqjv/dxan/2sGl/9rBpf/awKT/2cCk/9nAo//Zv6P/2b+i/9m+of/ZvqH/2b2f/9q+ + oP/Wupz/rpJ4/6OIb/+mi2//pYlv/6aKbv+dhWz/fWtPyUg7EVdJPBI5STwSHkk8Eg5HOxIFQzcQAQAA + AAAAAAAAAAAAAAAAAAAAAAAARjoRBEg7EgxJPBEbRzsQNIt4XtfHvq//5uTZ/+Le0f/h3dD/4tzO/7Kd + hf+/r57/zb+z/6+ZhP+qknf/3tbG/+DZyP/e1sb/3tbF/97VxP/e1cT/3tTD/97Uw//e1ML/3dPB/93T + wf/d08D/3dK//93Sv//d0b7/3dG9/93Qvf/d0Lz/3c+7/93Pu//cz7r/3M65/9zOuf/czbj/3M23/9zN + t//g0Lr/w7Gb/4VuU/+NdFn/uaeV/9fOxf/PxLn/y76x/8W2pv+XgGv/gmdP/4dtVf+Ha1P/iXJb/6qc + jv++uK//vrev/56Me/+Pc1f/m35h/5p9Yf+ZfGD/kXhd/9i/pf/bw6n/2sGm/9rBpf/awaX/2cCk/9nA + o//Zv6P/2b+i/9m+of/ZvqH/2b6g/9q+oP/Wupz/rpJ4/6WIb/+li3D/pYlv/6aKbv+dhWz/fWtPykg7 + EVxJPBI+STwSJEk8EhFHOxIFQzcQAQAAAAAAAAAAAAAAAAAAAAAAAAAARjoRAkg7EgtJPBIYSDsQLoFs + Ub/AtaT/6ufc/+Lf0v/i3tD/49/R/7mnkv+4pZL/zsK1/7KciP+kjHH/2c++/+Day//e1sb/3tbF/97W + xf/e1cT/3tXD/97Uw//e1ML/3dPB/93Twf/d08D/3dK//93Sv//d0b7/3dG9/93Qvf/d0Lz/3c+7/93P + u//cz7r/3M65/9zOuf/czrj/3M23/9zNt//czLf/3cy2/5V/Zf+FbVL/nYRq/83Btv/NwbX/xriq/8S1 + pf+4pJL/jXRd/4NpUf+GbFT/hGpR/4dtVv+PeWP/jXZg/4xwV/+bfWH/mn1h/5t+Yv+PdFj/q5R5/93F + qv/awqf/2sGm/9rBpf/awaX/2cCk/9nAo//ZwKP/2b+i/9m+of/ZvqH/2b6g/9q+oP/Wup3/rpN4/6WI + b/+li3D/pYpv/6WKbv+ehm3/fWtPzEg6EWFJPBJDSTwSJ0k8EhJGOhIHQzcQAQAAAAAAAAAAAAAAAAAA + AAAAAAAARjoRAkg7EgpJPBIYSDsRKndjRqi5rZv/6unb/+Pg0//i3tL/5uHU/8GynP+znor/zsK2/7aj + j/+hhmz/08m3/+LbzP/e18b/3tbF/97Wxf/e1cT/3tXD/97Uw//e1ML/3dPB/93Twf/d08D/3dK//93S + v//d0b7/3dG9/93Rvf/d0L3/3dC8/93Pu//dz7v/3M65/9zOuf/czrj/3M24/9zNt//czLf/4dG7/76r + k/+DbFD/iXFW/62Xgf/Lv7D/w7Sl/76snP+8qZf/r5qG/5R8ZP+Jb1j/iG1X/4ZsU/+Ga1L/jnFX/5t+ + YP+afWH/mn1h/5d6Xv+Pdlz/zrid/97HrP/awqf/2sGm/9rBpf/awaX/2cCk/9nApP/ZwKP/2b+i/9m/ + ov/ZvqH/2b6g/9m9n//ewqT/spZ8/6OIbv+li3D/pYpv/6WKbv+ghm3/fWpNykc6EWRJPBJFSTwSKUk8 + EhRGOhIHQzcQAQAAAAAAAAAAAAAAAAAAAAAAAAAARjoRAkg7EghJPBIXSDsQJG9cPY+zpZH/5ePW/+Xh + 1P/j4NL/5uLX/8zArf+ul4D/zL+y/7uql/+ghGn/0Maz/+Lczf/e18b/3tbF/97Wxf/e1cT/3tXE/97U + w//e1MP/3dTC/93Twf/d08H/3dLA/93Sv//d0r//3dG+/93Rvf/d0L3/3dC8/93Pu//dz7v/3M66/9zO + uf/czrn/3M24/9zNt//czbf/3s+5/93Ntv+finH/gWlO/452Wv+znYj/wbKh/7uplv+1oo3/sZuG/62W + gP+iiXH/mX5k/5Z6Xv+ZfWD/nH9h/5p9Yf+afWH/m3xg/4pwVP+ymoD/38it/9rDqP/awqf/2sKm/9rB + pv/awaX/2sCk/9nApP/ZwKP/2b+i/9m/ov/ZvqH/2b6g/9m+oP/ewqT/spd8/6OIbv+minD/pYpv/6aK + bv+ghmz/g3BV20g7EWhJPBJISTwSK0k8EhRGOhIHQzcQAQAAAAAAAAAAAAAAAAAAAAAAAAAARjoRAkg7 + EghJPBIURTgOHlhIInKtnor/4NzP/+bi2P/k39T/5+TX/9XMvP+tmID/yLys/8Cvnf+hhmz/yryp/+Lb + zv/e18f/3tbG/97Wxf/e1sX/3tXE/97Vw//e1MP/3dTC/93Twf/d08H/3dLA/93Sv//d0r//3dG+/93R + vf/d0b3/3dC8/93Pu//dz7v/3M+6/9zOuf/czrn/3M24/9zNt//czbf/3My2/+HSuv/Twar/kHle/4Jq + Tv+Pdlr/rZeA/7mmk/+znor/rZeA/6ePeP+jiW//noJm/5t+Yf+afWH/mn1h/5t9Yf+bfGD/inBU/5yF + av/bxKn/3car/9rDqP/awqf/2sKm/9rBpv/awaX/2sCk/9nApP/ZwKP/2b+i/9m/ov/ZvqH/2b6h/9m+ + oP/ewqT/spd8/6OIbv+minH/pYpv/6aKb/+fhm3/iXZc6kk7EWtJPBFJSTwSK0k8EhVGOhIIQzcQAQAA + AAAAAAAAAAAAAAAAAAAAAAAARjoRAUg7EgZJPBISRTgNG1JDG2Clk3//3NfJ/+jl2f/k4dX/5+PY/9rS + xP+ynYb/xben/8Kxof+mjnX/wbGb/+Pdzf/e18f/3tbG/97Wxf/e1sX/3tXE/97Vw//e1MP/4djG/+DX + xf/d08H/3dLA/93Sv//d0r//3dG+/93Rvv/d0b3/3dC8/93QvP/dz7v/3M+6/9zOuf/czrn/3M24/9zN + uP/czbf/3My2/9zMtv/h0Lv/yrig/454Xf+DalD/jHJW/5+Gbf+slX7/rJN7/6aMcv+ghGr/m35i/5t+ + Yv+bfmL/m31h/5Z7Xv+Ib1P/lH1j/9G7ov/dx6z/2sOo/9rDqP/awqf/2sKm/9rBpv/awaX/2sGl/9nA + pP/ZwKT/2b+j/9m/ov/Zv6L/2b6h/9m+oP/ewqT/spd8/6OIbv+minH/pYpv/6aKb/+fhm3/h3Vb6Ek7 + EWtJPBFJSTwSLEk8EhVGOhIIQzcQAQAAAAAAAAAAAAAAAAAAAAAAAAAARjoRAUg7EgZJPBIQRTgNG1RF + HlOaiHLz2NHC/+jm3P/l4df/5uTY/9/Zzf+1oIn/wrOj/8S0pP+qk33/u6mT/+Lcz//g2cn/3tbG/97W + xf/e1sX/3tXE/97Vw//g1sb/0MKu/9LFsf/h2cf/4NbD/93SwP/d0r//3dG+/93Rvv/d0b3/3dC8/93Q + vP/dz7v/3M+6/9zOuv/czrn/3M24/9zNuP/czbf/3My2/9zMtv/cy7X/4tG6/869pv+Zgmj/gmtP/4Zu + U/+Pd1z/mIBl/5yBZv+YfWL/lntf/5V6Xf+TeF3/jHNY/4NtUv+giW//1L+l/93Hrf/axKn/2sOp/9rD + qP/aw6j/2sKn/9rCpv/awab/2sGl/9rApP/ZwKT/2b+j/9m/ov/Zv6L/2b6h/9m+oP/ewqP/uJyB/6SJ + b/+mi3H/pYpv/6aKbv+iiG7/inZb6Ec7EWtJPBFJSTwSLEk8EhVGOhIIQzcQAQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAEg7EgRJPBIORTkOGVNEHUePemHh1My+/+rp3v/m49j/5uLX/+Xg1v+6ppH/wK+f/8S1 + pv+wmoX/sp2G/+Hbzv/g2sv/39jI/97Wxv/e1sX/3tXE/+HYx//Xy7n/rZd+/6mReP+4pY7/0MKv/9/T + wf/g1cL/39PA/93Rvv/d0b3/3dC8/93QvP/dz7v/3c+7/9zPuv/czrn/3M64/9zNuP/czbf/3My2/9zM + tv/czLX/3Mu1/+DRuf/ayLH/tqKJ/495Xv+Fb1T/g2xR/4VtUv+FbVL/hm5T/4ZvVP+Fb1T/lH5k/72o + jf/cx63/3smv/9rEqv/axKr/2sOp/9rDqP/aw6j/2sKn/9rCpv/awab/2sGl/9rApP/ZwKT/2cCj/9m/ + ov/Zv6L/2b6h/9m+of/cwaP/vaGF/6SJcP+mi3D/pYpv/6aKb/+iiG7/iXVb6Ec7EWpJPBFJSTwSLEk8 + EhVGOhIIQzcQAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEg7EgNJPBIMRTkOGFFEGzuDblPQz8e5/+ro + 3f/m49n/5uPY/+jl2/++rpn/u6qY/8W1p/+0n4r/rZV8/+Hdzf/h28z/4NnK/9/Xx//e1sX/3tXE/+HY + x//Wyrf/rpZ+/6aNdP+nj3b/qZF4/7Kdhv/Mvan/2867/+LXxP/g1MH/3dC9/93QvP/d0Lz/3c+7/9zP + uv/czrn/3M64/9zNuP/czbj/3My3/9zMtv/czLb/3Mu1/9zLtP/fzrj/4M+4/9vJsv/Cr5f/q5Z9/56I + bf+ahGr/oIpv/62Xff/EsJb/28at/+DLsf/dx6//2sWr/9rEqv/axKr/2sOp/9rDqP/aw6j/2sKn/9rC + pv/awab/2sGl/9rBpf/ZwKT/2cCj/9m/o//Zv6L/2b6h/9m+of/cwaP/vKGF/6WJcP+mi3D/pYpw/6aK + b/+ghmz/kn1l/0g7Em1IPBFJSTwSLEk8EhVGOhIIQzcQAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEg7 + EgNJPBILRzoQFk5AFyx9ak29xryr/+jm2//o5dr/5uPY/+zr4f/Ju6r/uaSR/8a2qP+4pZH/qI93/9/Y + yv/h3M7/4dvM/+Hayv/e18f/3tXE/9/Wxf/d08H/sZuD/6ePdf+rk3r/q5N7/6mRef+mj3b/s5yE/8Wz + nv/WyrX/4dXC/9/Tv//d0Lz/3c+7/9zPuv/cz7r/3M65/9zNuP/czbj/3M23/9zMtv/czLb/3Mu1/9zL + tP/cy7T/28qz/9zLs//ezLb/4c+3/+PQuf/j0Lj/48+3/+HNtf/eyrH/3Meu/9vGrP/bxaz/2sWr/9rF + q//axKr/2sSp/9rDqf/aw6j/2sKn/9rCp//awqb/2sGl/9rBpf/awKT/2cCj/9m/o//awKL/2r+h/9q/ + of/ew6P/vKGG/6WJcP+mi3D/pYpw/6aJb/+gh2z/kn1l/0g7Em1IPBFJSTwSLEk8EhVGOhIIQzcQAQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEg7EgJJPBIISTwSFkM3DBtsWzmnv7Oi/+fk2P/o5dv/5+TZ/+vp + 3//QxbX/uqaS/8a3qP+7qJX/rJN7/9fOvv/k39H/4dvN/+HazP/h2cr/3tfG/97VxP/i2cn/tJ+H/6aO + df+rk3r/q5N7/6uTe/+rlHz/qZF4/6eOd/+umYH/vaqU/9LDrv/f0b3/39G9/+DSvv/e0rv/3c+6/9zO + uf/czbj/3M23/9zMtv/czLb/3Mu1/9zLtf/cy7T/28qz/9vKs//bybL/28mx/9vIsf/byLD/28ev/9vH + r//bx67/28at/9vGrf/bxqz/2sWr/9vGrP/bxav/28Wq/93Fqv/dxan/3MSp/9vDqP/bw6f/28Km/9rB + pv/awKT/2cCj/9e+o//QuZ//0rqe/9K5nv/QuZ//uaCF/6aKcP+mi3D/pYpw/6WKb/+jiG3/k35m/0g7 + Em1IPBFJSTwSLEk8EhVGOhIIQzcQAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEg7EgFJPBIISTwSFUE1 + CRdmVTSTtaaT/+Xh1f/p5tz/5+Ta/+vo3v/Xz8H/uaaR/8a2p/+9qpj/rZWA/8/Es//l4dT/4tzO/+Hb + zf/h2cv/4NnJ/97Wxf/j2sn/vKmU/6ePdv+qk3r/q5N7/6uTe/+rlHz/rJR8/6yUfP+qk3r/qZJ7/6uU + fP+1nof/xbOd/9LBrP/WybL/2su2/97RvP/h077/4NK8/+DQu//f0Lr/3864/9/OuP/fzrf/3822/97N + tv/ezLX/3sy0/97MtP/ey7P/3suy/9/Lsv/fy7H/38mw/9/Ksf/gyrD/3Met/9rFq//Xwqj/1cCm/9S+ + pP/QuqD/yrSd/8Wwmf/Dr5n/vqmW/7yolf+5pZH/tqOS/7ekkf+2o5P/tqST/7aklP+3ppX/s52I/6eL + cf+mi3D/pYpw/6WKb/+kim3/k35m/0Y5D2pIPBFJSTwSLEk8EhVGOhIIQzcQAQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABJPBIGSTwSEkI1ChhmVjN9qZmE/+Pf1P/q59//6Obc/+no3v/g2c3/uaaS/8a3 + qP+/rZv/sJmE/8m6qP/n49f/49zQ/+Pcz//i28z/4drL/+HZyf/h2cr/xbWf/6mOdv+qknr/q5N6/6uT + e/+rlHz/rJR8/6yUfP+slX3/rJV9/6yWfv+rlH3/qpN8/6mSe/+xmoP/uKON/7+slv/EsZz/ybej/8u5 + pP/Qvqj/08Ks/9PBq//Twar/08Cq/9LAqv/TwKn/08Cp/9PAqf/Tv6j/07+o/8y4of/MuKH/zLmi/8m0 + nf/Is5z/w66Y/8Cqlv+6ppL/tqKP/7GgjP+xnoz/sp+N/7Ogjf+zoI//taCP/7Whj/+1oY7/tKGO/7aj + kf+1opD/t6WT/7ellP+4ppb/spyH/6eLcf+mi3D/popw/6aKb/+kiW3/lYBo/1VGIHpHOg9HSTwSLEk8 + EhVGOhIIQzcQAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJPBIGSTwSEEI3CxljUzBqnYp0+eHe + 0v/p6N7/6efd/+rn3f/l4db/u6iV/8a3p//Ar57/s5yG/8Gxnv/p5dr/497R/+Pd0P/j283/4tvM/+Ha + y//j28z/08az/6iQdv+qknr/q5N6/6uTe/+rlHz/q5R8/6yUfP+slX3/rJV9/6yWfv+tln//rZZ//62X + f/+tln//q5R+/6qUfP+pkXv/rJV+/62Ygv+wmoT/sp2H/7Kdh/+ynYf/sp2I/7KdiP+znoj/s56J/7Oe + if+zn4r/tJ+K/7GciP+xnYn/sZ2J/7Cbh/+vm4f/sJyI/7GejP+0oI7/taGQ/7ajj/+2oo//tqKP/7aj + kP+0oY//tKKQ/7amlv+7rqL/wrqx/8vGwf/BtKj/taOQ/7elk/+4p5b/spuH/6eLcf+mi3H/popw/6aK + b/+kiG3/loFo/2RUMYhGOQ5FSTwSLEk8EhVGOhIIQzcQAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABJPBIFSTwSD0Q3CxlgUCtVkX1l8OHcz//r6N//6efe/+nm3f/s6OH/wK+c/8Kyof/DsqH/tKCL/7uo + lf/q5tr/5N/S/+Te0f/j3c7/4tvN/+LbzP/i2sv/4NnJ/6yUfP+qknf/q5N6/6uTe/+rlHz/q5R8/6yU + fP+slX3/rJV9/6yVfv+tln//rZZ//62Xf/+ul4D/rpeB/66Ygf+umIL/r5iC/66Ygv+umIL/rpmD/6+Z + g/+vmYT/r5qE/6+ahf+wm4X/sJuG/7Cbhv+wnIf/sZyH/7Gcif+xnYn/sZ2K/7ahjv+3pJH/tKGN/7Gc + iP+wm4b/rZiE/6iTfv+mkXz/pY97/6WSf/+ol4j/sKGT/7irn//At6//x8G6/9LPzf/Py8f/uKeX/7ak + kv+4p5b/spuH/6eLcf+mi3H/popw/6aKb/+kiG3/loFo/2FRLoZGOQ1GSTwSLEk8EhVGOhIIQzcQAQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJPBIFSTwSDkU4DRpZSiRAjXlg5tXPwv/r6N7/6+jg/+rn + 3f/u7OL/x7io/8Oxof/DtKT/t6SP/7qmk//l4NX/5eHV/+Xe0v/k39D/493P/+Pczv/j283/4tvM/7yq + lf+pkXj/qpJ5/6uTe/+rlHz/q5R8/6yUfP+slX3/rJV9/6yVfv+tk3r/qpB2/6qRd/+ulX7/rpeB/66Y + gf+umIL/r5iC/6+Zgv+vmYP/r5qE/6+ahP+wmoX/sJuF/7Cbhf+xnIb/sZyH/7Gch/+xnYj/sp2I/7Kd + if+ynon/tKCM/6eRe/+cgmn/mH9m/5N4Xv+Rd13/j3Na/5J5Yf+Xf2n/nohz/6WRf/+smor/s6WY/7So + m/+7sKT/xsG8/9DNy//PycT/uaiX/7akkv+4p5b/spuH/6eLcf+mi3H/potw/6WKb/+nim//l4Jp/2BR + LodGOQ1HSTwSLUk8EhZGOhIIQzcQAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJPBIESTwSC0g8 + ERtFOA4ngm9U3c3Etf/q597/7Onh/+ro3//t7OP/z8O1/8Gwnv/Ht6f/u6eU/7mlkv/f2cz/5+TZ/+Xg + 1P/l39H/5N7Q/+Tdz//j3M7/5N3Q/8y9q/+ul4H/q5R6/6uTe/+rlHv/q5R8/6yUfP+slX3/rJR8/6yR + eP+xraX/v8nP/7/Avv+wm4b/rJR7/66Ygf+umIL/rpiC/6+Zgv+vmYP/sJiA/7KXff+xmID/sJmB/7KY + fv+ymIH/sZyH/7Gch/+xnYj/sp2I/7Kdif+zoIv/q5V//4hqTf+DZEb/hWhL/4hrUP+NcVf/kXZd/5V9 + Zf+ZgWr/moRu/5aBbP+Uf2j/i3Zf/4VvVf+Fb1X/mIZz/8vIwv/Rz8z/u6qb/7ajkP+4p5b/spuH/6iM + cv+ni3H/potw/6WKcP+nim//loFp/19SL4lGOQ1KSTwSMEk8EhhGOhIKQjcQAgAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABJPBIDSTwSCkk8EhlANAkgfGpNyMK3pv/s6d//7Ori/+vo4P/t6+L/2M/C/8Gv + nv/IuKn/vauZ/7ilkf/b08X/6uXa/+bg1P/l4NL/5N7R/+Te0P/k3c//5t/R/9jNvf+xnYf/spyF/6yU + e/+rk3r/q5R8/6yUfP+slH3/q5J2/6ysqf/B6P//3/T//+/+///T3uT/rpqG/62Uff+umIL/rpiC/6+Z + gv+wmID/sJZ//6Wnov+cucj/mr7R/6GyuP+tnpD/tJl//7Gchv+xnYj/sp2I/7Kdif+1oIz/oYly/4Vm + Sf+HaU3/iWxQ/4xvVP+McVf/iXJY/4VvVf+BalD/fWZK/35mS/+FblT/i3de/5eFbv+UgWr/fmdL/66j + lf/W1dT/u6yd/7aikP+4p5b/spuG/6iMcv+ni3H/potw/6WKcP+nim//mIJr/25ePadENwxLSTwSMkk8 + EhpGOhILQjcQAzwyDwEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJPBIBSTwSCEk8EhZDNgoheWZJrLap + l//r6d//7evj/+zq4P/t6+P/4NjN/8Kvnv/Ku6z/wK6c/7ajj//Vy7z/6+je/+fi1v/m4dT/5uDT/+Xf + 0v/l3tH/5d/R/9/WyP+8qZb/taCK/7Och/+slXz/qpN7/6yUfP+slHz/q5R8/6vN5P/F6f//5PL///b7 + ///j+P//uLay/6uTe/+umIH/rpiC/7CYf/+umoP/k7fN/4vX//+a3P//oN7//5bd//+OzfH/o6mn/7SZ + gP+xnYj/sp2I/7Kdif+0oIz/qZN9/4ZnS/+HaU3/iWxQ/4luUv+Eb1T/hG9V/4x3Xv+YhG3/qJaC/7io + mP/NwrX/4dvT///////m4tz/hW5U/5qMeP/W1dP/u6yc/7aikP+4p5b/spuG/6iMcv+ni3H/potw/6WK + cP+nim//mIJr/25ePqlENwxNSTwSNUk8EhxGOhINQjcQBD0yDwEAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABJPBIBSTwSB0k8EhRDNwwfc2BBkqyciP/r6d//7evj/+zq4v/t6uP/5uDX/8Gwnv/Ku6v/w7Gg/7ai + j//Rxbf/7erg/+fj1//n4db/5uHU/+bf0//l39L/5d7R/+Xf0f/IuaX/tJ+J/7eij/+0n4n/rJR8/6yT + e/+slHz/q5R7/6fM6P+65P//0ur+/9vv/v/Q7///t8bO/62Vff+umID/rpiB/7OVef+UsL//gNX//5zZ + //+x4f7/uuP+/6ze/v+U2f//gcz9/6WknP+zmoP/sZ2I/7KdiP+ynon/sZ2I/4dpTP+HaUz/iWxP/4lu + U/+CbFL/mIFp/7WhjP/GtaX/2MzA/+Xd1P/t5+H/8+/r//r4+P/x7er/jnlg/499Z//b3dz/va6h/7Si + j/+4p5b/spuG/6iMcv+ni3H/potw/6WKcP+nim//moRs/29ePqpENwxQSTwSNkk8Eh1GOhINQjYQBD0y + DwEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJPBIBSTwSB0k8EhNENwwgaVg3dqSTff/r6t//7evj/+3r + 4//t6uP/6+ng/8KxoP/Iuqv/w7Kh/7ejkP/Uybz/7Ovh/+jj2P/n4tf/5uHV/+bg1P/m39P/5d7R/+ji + 1v/SxrX/tqGM/7ikj/+3o4//tJ+K/62Vfv+rlHv/rJR6/6XH3P+p3v//tt/+/7vi/v+15v//rLvD/66U + e/+umIH/sZd9/6edjv93xPX/h9P//6HZ/v+25P7/wuf+/7Hg/v+a1/7/ftH//4K63f+2mX7/sZ2I/7Kd + iP+ynon/sp+L/41vU/+HaUr/iWtO/4ltUv+CbFL/m4Rs/7mkj//FtKP/0MK1/9vRxv/l3db/7ejj//Xz + 8f/5+Pf/k4Fp/4t3X//X19f/v6+i/7Sij/+4p5b/sJqE/6iMcf+njHH/potw/6aKcP+nim//m4Rs/25d + PadENwxOSTwSNkk8Eh1GOhINQjYQBDwyDwEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJPBIBSTwSBkk8 + EhFFOQ8fYFArXJ+NeP/h39L/7u3k/+7s5f/u6+P/7uzk/9PIu/+/rZz/v6yb/8u+rf/m49j/6ebc/+nl + 2v/o49n/5+LX/+fi1v/n4NX/5uDT/+fh1f/e1MX/vquY/7ikkP+4pZH/uKSP/7Whjf+vmYL/rJF2/6qp + o/+l2///pd3//6bd//+l2v7/rKKY/66Uev+umIH/spV6/5ujov9nyf//hM///5nX/v+o3f7/r9/+/6Xc + /v+T1f7/e83//27A9P+mn5X/tJuD/7KdiP+ynYn/sp+M/5N4Xv+GZ0r/iGtP/4ltUv+DbVP/lHxj/7We + iv/CsJ7/zsCy/9nPw//k3NT/7unk//n18v//////nYx2/4VwV//PzMn/wbOm/7WikP+5p5f/rpeB/6eM + cf+njHH/potx/6aKcP+nim//m4Vt/3RjRbZENgpKSTwSM0k8EhtGOhIMQjcQAzwyDwEAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABJPBIBSTwSBUk8Eg5IPBEeSTsSP5iHcP/a1MX/8O3m/+/t5v/u7OX/7uzl/+zp + 4v/k3tT/5N3T/+rm3v/t6eH/6ubc/+nl2//p5dr/6OPY/+ji1//n4db/5uDU/+bf0//n4dT/w7Og/7il + kf+6p5P/uaaS/7ikkP+3oo//sZuE/6yRdv+qqaX/qMje/6fH2/+rp6D/rpV7/66XgP+umIH/sZZ8/4yn + tP9exv//esr+/4jR/v+U1f7/l9b+/5HU/v+Ez/7/ccn//2S/+f+coqL/tpuB/7KdiP+ynYn/tKCL/5uC + af+FZkj/iGtP/4ltUv+DblT/j3le/7SeiP/DsZ7/z8Cy/9nPw//j29T/5N3W/9rSyv/Ataf/h3BW/4x4 + YP/S0M7/xLmv/7WjkP+5p5b/rZZ//6eMcf+njHH/potx/6aKcP+mim//nYVu/3ppTMVDNgpCSTwSL0k8 + EhhGOhIKQjcQAzwyDwEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASTwSBEk8Eg1IPBEcRjgNNpN/ + aOvPyLf/8O/n//Du5//v7eX/7uzk/+7s5P/v7ub/7u3l/+3p4f/r6N//6ubd/+rm3P/p5Nv/6OTZ/+jj + 2P/o4tf/5+HV/+fg1P/p4tb/0cW1/7uolf+7qJX/uqeU/7mmkv+5pZL/t6SQ/7OdiP+uk3n/rJR7/62U + ff+tlHr/rpd//66Xgf+umIH/tJV6/5Sgo/9PwP//acT+/3fJ/v9/zP7/gc3+/33M/v9zx/7/YsL//1i6 + +/+ZoaD/t5yB/7KdiP+ynYn/tKCM/6OKc/+EZEf/iGtO/4ltUf+GblT/iHJY/6iQef+smYP/pZN+/56M + d/+Kdlz/f2lO/39oTP9+Z0v/hnBW/6+jl//W1dT/w7es/7Wjkf+4ppX/q5N6/6eMcf+njHH/potx/6aK + cP+mim//nIRt/3FhQaJENww+STwSKUk8EhRGOhIIQjcQAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAASTwSAkk8EgxJPBEZRzsQMot4XtHIv67/8u/n//Du6P/v7ef/7+3m/+7s5f/u6+T/7erh/+3q + 4P/s6N//6+jf/+vm3v/q593/6uTb/+nk2v/p49n/6OLX/+ji1v/n4db/4NnJ/76rmP+9q5j/vKqX/7yp + lf+6p5T/uKaR/7ikkP+2oYz/sJqD/62Uff+tl3//rpeA/66XgP+umIH/s5d8/56clv9Lt/3/Vr3//2PB + //9pxP7/asX+/2jE/v9gwP//ULz//02y9/+gnpf/tpyD/7KdiP+ynYn/taGN/6qTf/+DZUn/iGpO/4ps + Uf+Hb1T/g21V/4BqUP9/aU//gGhO/4NtUf+KdFv/kHtk/5mIc/+jlIT/taqe/8rGwf/Jw7z/uaiZ/7el + k/+znov/qY50/6iNc/+njHL/potx/6aLcP+ninD/mYFq/2hZNoJEOA04STwSI0k8EhFGOhIFQzcQAQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASTwSAkk8EgpJPBIYSDoQLIJuUrvBt6X/8O/n//Hv + 6P/w7uf/7+3m/+/t5v/u6+X/7uvj/+3q4v/t6uH/7Ojf/+vo3//r597/6ubc/+rl2//p5dr/6OPY/+jj + 1//o4tb/6OLV/8i5qP++q5n/vqya/72rmP+9qpf/u6iU/7qnk/+5ppL/uKOR/7Oeif+umYD/rZeA/66X + gP+umIH/r5iA/7OXfP9lqNL/Nrf//0+4//9Uu///Vbv//1O6//9NuP//NrT//1ip3v+5mn7/sZ2H/7Kd + iP+ynYn/tKGM/6yWgP+HaU3/h2lM/4lsUP+KblL/iXBV/4lwVv+Odlv/k3xl/5qEbv+hjXv/qJmI/7Wl + l/+6rJ7/vK2f/7qpnP+4ppX/uKST/7ekkf+sk3r/qY1y/6iNc/+ojXP/p4tx/6eLcP+kiG7/k35m/Ew+ + FlJHPBAwSTwSHEk8EgxHOxIEQzcQAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASTwSAkk8 + EglJPBIXSDsRJnVhQ6G6rpv/7+3l//Hv6f/w7uj/8O7n/+/t5v/v7Ob/7uzk/+7r4//t6uL/7eng/+zo + 4P/r6N//6+bd/+rm3P/q5dv/6eTZ/+jj2P/o4tf/6eTY/9fNvv++q5n/v66c/76tmv++q5n/vKqX/7uo + lf+6qJT/uaaT/7ilkf+2oo3/spyG/6+Ygv+umID/rpiC/7WXe/+em5P/Qarv/yqx//87sv//QLL//zuy + //8psP//M6r6/52dmP+2nIL/sZ2I/7KdiP+ynYn/s5+K/7Gcif+Td1z/gWNE/4ZoTP+McFX/kndd/5Z9 + ZP+eh3H/p5F8/62ahv+zoI3/tKGP/7WikP+2o5H/tqOS/7ajkf+2opD/s5+L/6yRef+pjnT/qY50/6iN + c/+ojXP/p4tx/6eMcf+fh27/gXBUwUc6DzlJPBEmSTwSFUk8EghHOxICAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAASTwSAkk8EghJPBIVSDsPIWxZOIi1pZP/6efb//Hw7P/x8Or/8e/o//Du + 6P/w7ub/7+3m/+/s5f/u6+T/7uri/+3q4P/s6OD/7Ojf/+vm3v/r5tz/6uTb/+rk2f/p49j/6eXY/+Xd + 0P/GtqT/wK+d/8Gvnf/Arpz/vqya/72rmP+8qZb/uqiV/7mnk/+5ppL/uKSQ/7WhjP+ynYf/r5mE/62Y + gv+3mXr/m5qU/1Cj2P8oqP7/Fqr//yKo//9HpN7/lZ6e/7icgP+xnIf/sZyI/7KdiP+ynYn/sp6J/7Sg + jP+umIP/nYZs/6GJcv+qlH3/sJuG/7Sgjv+3pJL/tqSR/7ejkP+2pJH/tqOR/7Wikf+1oY//s56J/7Kb + hf+ulX7/q452/6qPdv+qj3b/qY50/6iNc/+ojXP/qIxy/6WLb/+Zg23+Xk8raEU5DSZJPBIbSTwSDUk8 + EgRGOhIBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASTwSAUk8EgZJPBISRTgNG1ZG + IGuvoIv/4d/R//Tz7f/y8Or/8e/p//Hv6f/w7uj/8O3m/+/t5v/v6+X/7uvj/+3q4v/t6uD/7Ong/+zo + 3//r593/6ubc/+rl2v/q5Nn/6ePY/+vk2f/VyLr/wK+d/8KxoP/Cr5//wK6c/7+tm/++rJn/vaqX/7yp + lv+7qJX/uaaS/7mlkf+4pJD/taGM/7Oeif+wm4X/tpl9/7CYgP+Zmpf/jpyf/5Wcmv+vm4f/upp//7Gc + hv+xnIf/sZyI/7GdiP+ynYn/sp6J/7Keiv+0n43/t6SS/7ekkP+2pJD/taGP/7Shjv+0oYz/tKCO/7Oe + i/+znIf/sJqD/6+YgP+vln3/rZN5/6uRdv+rkXf/q5B3/6qQdv+qj3b/qY50/6iNc/+pjXP/qYxx/52G + b/96aEuvRzoQKkc6EB9JPBIRSTwSCEk8EgMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAASTwSAUk8EgVJPBIQRTgNGVJCG1ymlYD/29fH//X07//y8ev/8vDq//Hv6f/x7+n/8O7n//Dt + 5v/v7eb/7+zk/+7r4//t6uL/7Ong/+zo4P/s6N7/6+bc/+rl2//q5dr/6ePY/+vl2v/j28//xrin/8Kx + oP/DsaD/wbCe/8Cvnf+/rpv/vqyZ/72rmP+8qpf/uqiU/7qmk/+5ppL/t6SR/7ejkP+2oo3/s5+L/7Sc + hv+4m37/upp9/7ibf/+0m4T/sZuG/7Gchv+xnIf/sZyI/7GdiP+ynYn/sp6J/7Keiv+znor/s5+K/7Of + iv+znon/s52I/7Ochv+xmoL/sZh//7CYfv+wln//r5V8/66Ue/+ulHv/rZN6/6ySef+sknn/q5F3/6qQ + dv+qj3b/qY50/6mOdP+njXL/n4dv/4p4XtNRQxoyRTgOHEk8EhRJPBIJSTwSBEk8EgEAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASTwSAUk8EgVJPBINRTgNF1NFHU6biXPw19LD//Px + 7f/z8e3/8/Ds//Lx6//y8Or/8e/p//Hu6P/w7ub/7+3m/+/s5f/t6uT/7eri/+3p4f/s6N//6+fd/+rm + 3P/q5dv/6ePY/+fi1//q5Nr/1Mi6/8Gxof/Ds6L/wrKh/8Kxn//BsJ7/wK6c/7+tm/+9rJr/vKqX/7yp + lv+7qJX/uaaT/7mlkv+3pJH/tqOP/7aij/+1oY3/s56K/7Gdh/+wm4b/sZuG/7Gchv+xnIf/sZyI/7Kd + iP+0non/tJ6J/7Wfif+1n4j/tZ2H/7Wdhv+0m4T/s5uD/7Oagv+xmoL/sZiA/7CYf/+wln//r5Z9/6+V + ff+ulHz/rZN6/62Tev+sknn/q5F3/6qQd/+skHf/qo90/6OJcP+ahW3/h3Vbx1pLJ0BENwwaSTwSFEk8 + EgtJPBIESTwSAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEk8 + EgNJPBIMRTgOFFJEHT+QfGTd1M2+//Lw6//08+7/8/Ls//Px7P/y8ev/8e/q//Hv6f/x7uj/8O3m//Dt + 5f/v7OT/7eri/+3p4f/r5+D/6+fd/+rl3P/p5Nr/5+LX/+bg1v/m4NT/5NzR/8q8rf/BsJ//wrKi/8Oz + ov/DsqH/wrGi/8KxoP/BsJ7/v62b/72smf+8qpj/uqiV/7ajkP+0oYz/s5+K/7CbiP+vm4X/sJqF/7Gc + hv+ynoj/tJ+J/7agi/+3oYz/t6GL/7ihi/+4oYv/t6CJ/7efiP+2n4j/tZ2G/7Wdhv+0nIX/s5uD/7Oa + g/+ymoL/sZiA/7GYgP+wln//r5Z9/7CWfv+vlX3/rpR7/6+Ve/+rkXn/q5J3/6iOdP+jinL/m4Vt/5SA + avx5Z0qSUEIaJUM2CxJJPBISSTwSCkk8EgRJPBIBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEk8EgNJPBIKRTkOElFEHC+Eb1XJ0Mi4/+7s4//29vH/9PLt//Py + 7f/z8ev/8vDr//Lv6v/x7+n/8O7n//Dt5v/v7OX/7erj/+zp4f/r6N//6eXc/+jj2v/n4df/5eDV/+bf + 1f/l3tP/5d7U/9/Xy//JvK3/wK6f/7yrmv+8q5n/vKqX/7qmlP+2oo7/s56J/7Kdh/+xm4X/sJqE/7Cb + hf+znYf/tqCJ/7iijP+5o4//vaeQ/7ymkP+9ppL/vKWP/7ukjv+7pI7/uqOM/7mii/+5oYv/t6CJ/7ef + iP+2n4j/tZ6G/7Wdhv+0nIX/s5uD/7Oag/+zm4P/spqB/7Sbg/+zmYH/sJd//62Te/+rk3j/qJB4/6KK + cv+hiXL/m4Zw/5aAavKHdFrSemlKkV1OKThFOQ0URjkPEkk8Eg5JPBIISTwSBEk8EgIAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEk8EgJJPBIHSDoREEs/ + FRh5ZkiwycGw/+bj1//08u7/9fTw//Tz7v/08u7/8/Hs//Px6//y8Ov/8e/p//Hu6P/w7+b/7uzl/+7r + 4//s6OD/6eXe/+Xh2P/h29L/3NbJ/9jRw//Uy73/0ci4/9LJuP/PxLP/wbSh/7ikkP+ynYf/sZuD/7Gb + hP+1n4n/uaOO/7umkP++qJP/v6qW/8Gsl//Drpn/wqyX/8Cslf/AqJT/vqiS/72nkf+9ppH/vKWP/7uk + jv+7pI7/uqOM/7mii/+5oYv/t6CJ/7efiP+2n4j/tp+H/7efiP+3nof/tp6G/7SchP+ul3//qpR7/6eO + dv+hinT/nodx/5uGbv+ZhG3/k35n6I57Ysp3ZUigaVg2eWZWNElNQBYXQDQIDEY5DxBJPBIPSTwSCUk8 + EgZJPBICSTwSAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABJPBIFSTwSDUI1CQhrWTeEt6mW/+Pg0v/n5Nr/9PPu//b18f/19PD/9PPu//Ty + 7f/08u3/8fDr/+7r5P/r597/5eDW/97Zzf/W0MD/zcW1/8a8q/+/s6L/uauX/7OjkP+unYn/qpmD/6uW + gv+um4f/tqSP/72nk/+9qpb/wq6a/8SwnP/GsZ7/x7Ke/8Wwnf/Dr5v/w66Z/8GsmP/BrJf/wKqV/7+q + lf+/qZT/vqiS/72nkv+9ppH/vaaQ/7ymkP++pZD/vaaP/7ukjv+6ooz/uKGK/7egif+1nof/r5mB/6qT + ff+nkHr/nohy/5qHb/+Yg2z/kn5n/456YuqIdVzBhHJXmXFfQG9TRx9JVkkhN1VGHiRHOhAJQDQHA0I3 + CghGOw8MSTwSC0k8EglJPBIGSTwSA0k8EgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJPBIDSTwSCEQ4DQtbTCc0kn5l5cvB + sf/i39H/4t/S/+Xi1v/l4db/4t3R/+Hbzv/c1sb/3NTF/9fMvf/Uybj/zL+v/8S0o/+6qZb/rJeC/6GN + df+diHL/n4p0/56JdP+eiXT/nYdy/6CKdf+mkXz/q5eC/7Sfi/+7p5P/wKyY/8Oum//Er5v/xK+b/8Sv + m//Crpr/wq2Y/8GsmP/BrJf/wauW/8CrmP/CrJf/wqyW/8Grlv+/qJP/u6SO/7ehi/+0noj/spyF/6yW + f/+lkXr/o453/56IdP+WgWr7lIBq7415YeB+a1DJfWtOqnhlSHl0YkJeUEMaLkc6EB5JPBEYSDsSEUY5 + DwtEOA0HRTgNB0U4DglIOxELSTwSCUk8EgdJPBIGSTwSA0k8EgJJPBIBSTwSAQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABJPBIBSTwSBUk8EgxDNgoKXk8rT5R/Z+m2p5T/28+//9zPv//WyLj/1ca1/9PEs//TwK//0b2s/8+9 + rP/MuKf/xrSi/7yolP+wnYn/u6yb/8CypP/AsaL/uaeW/6+ah/+nj3f/m4Fn/5uAZP+cg2n/p5J8/7Gd + if+5ppH/v6uX/8Kumv/EsJz/xbGc/8axnf/FsZz/xbCc/8Wvnf/GsJv/vqmU/7mkj/+znYf/rZeC/6eS + fP+jjnj/oIt0/56Icv+Xgmz/kH1l4o15YM+HdFqxcWFAmmlYN3doWDZcZlYzQVhKJCRAMwcHQzYKCUM3 + CwxENwwMRzoQDUk8Eg1JPBELSTwRCkk8EglJPBIGSTwSBUk8EgVJPBIDSTwSAkk8EgFJPBIBAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASTwSAkk8EgZJPBIMQjYJBltMJjeFcVe3oo14/826 + qf/ayLj/1sW0/9TCsf/TwrH/0sCv/9C/rf/Muqn/xLKf/8Gvnf/n4Nv/+/r5//Lv6//i2dD/zb+v/7ym + k/+rknr/noBl/5p8Xf+XeVr/qZJ8/7aijv+8qJT/wayY/8Ovmv/FsZ3/w66a/7qlkP+0n4r/rZmD/6eT + fP+einP/m4dw/5iEbf+SfmX/i3lg34d0WsWBb1Sae2pMgFdJI1ZXSCJHVUchM1VFHiZRQxoTRDgMBEE0 + CQNCNQoFQjcKB0U4DQpJPBIMSTwSCkk8EglJPBIHSTwSBkk8EgRJPBIDSTwSAkk8EgJJPBIBAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEk8 + EgJJPBIFSTwSCkM3DAhOQRgUcmBChJeCa/S7qZX/18e2/9nIuf/Uw7L/0sCv/9C/rv/Mu6n/w7Gd/8e3 + p/////7///////Ds6P/d0sn/y72t/7unlP+rlHz/noNm/5p9X/+afF7/oYt1/6OQe/+ijXn/o496/6OO + eP+bhnH/lYBq+JR/aOyMeWDegG5R0ntqTad5ZkmNdGJFaWpaOUhOQRklRzkQG0k8EhhIOxERSDsRDEU4 + DAZFOA0FRTgNB0U4DghHOg4KSDwRCUk8EglJPBIGSTwSBkk8EgVJPBIDSTwSAkk8EgJJPBIBSTwSAUk8 + EgFJPBIBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJPBIBSTwSBEk8EglHOhANQjUJB2VVMkKMeF/NqZaD/8e1 + o//YyLb/2Me3/9XEs//SwbD/yrim/9C/r//9/Pz///////Ty7v/f1s7/ybys/7mlkv+pkXj/noJm/5p9 + YP+dfmH/hG5W/3RgStp7aE/GdWNGp2pZOI9oWTdsaFc2VGRUMDpYSSMdQzcKB0E2CQhDNgoJQzcMCkQ4 + DQxHOhAMSTwRC0k8EQtJPBEJSTwSCEk8EgdJPBIFSTwSBUk8EgVJPBICSTwSA0k8EgJJPBIBSTwSAQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASTwSAUk8 + EgJJPBIGSDsRC0Q4DQZOQBgZemdKlZaAavyjj3n/rpqG/7ShjP+1oo3/oY54/6iYhf/5+fj/8u7p/9rP + xf/Ht6f/uqeU/7CYgf+kiW//nX5i/5t9YP+df2H/jXhf/1tJK0hZSCYtT0EbFEU3DQVCNQsFQjUKA0I3 + CwdFOA4KSTwSC0k8EgpJPBIJSTwSB0k8EgZJPBIFSTwSBEk8EgNJPBIDSTwSAUk8EgFJPBIBAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJPBIBSTwSBEk8EghFOA4FRTgOB1BCGyN4ZklufWlMn31r + T8F9a07TdWFFr5SCbN/b0sr/4NbO/9THu//JuKn/vaqX/7Kbhf+mjXT/m4Fl/5uBZf+Xf2X0gG1Ul1ZE + IxZVRCESUkIeD09AGgtKPBMISTwSBkk8EgVJPBIESTwSA0k8EgJJPBICSTwSAUk8EgFJPBIBAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASDsSAUc6 + EgJHOxIFRzoRB0U4DwdBNQsFQTUKBEI2CwJENw0FRjgPB2tYOkydi3bAsaCO462divWolYL0o5B785yH + ctSVf2jGi3ddp3NfRHtyXkQ/XUorCllIJgtaSCcIVkUkBVBBHAJKPBQBSDsSAUg7EgEAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARDgQAkQ4EANEOBAFRDgQB0Q4EAhHOxUJSz0ZC00+ + GgNYSCcRW0gnJl1KKzBeTC4vYk8wLWJOMBtiTzISAAAAAAAAAAAAAAAAXkosA15LLARaSCgBU0QiAQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAA/NA8BPzQPAT80DwJBNRECRzoXA0k7GgMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFdH + KgJhTTIBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEU4GAFKPB4BSz0hAUs8 + IAFQQCUBWkgvAVtIMQFaSC4BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////// + /////////////////////////////////////////+f//////////////gD/////////////4AA///// + ///////gAAAf//////////4AAAAP//////////AAAAAH////////+AAAAAAD////////gAAAAAAB//// + ///4AAAAAAAA//////4AAAAAAAAAf////+AAAAAAAAAAf////gAAAAAAAAAAH///AAAAAAAAAAAAH//w + AAAAAAAAAAAAH/+AAAAAAAAAAAAAH/gAAAAAAAAAAAAAH/AAAAAAAAAAAAAAH8AAAAAAAAAAAAAAH8AA + AAAAAAAAAAAAD4AAAAAAAAAAAAAAD4AAAAAAAAAAAAAAD4AAAAAAAAAAAAAADwAAAAAAAAAAAAAADgAA + AAAAAAAAAAAADgAAAAAAAAAAAAAADgAAAAAAAAAAAAAADgAAAAAAAAAAAAAAD4AAAAAAAAAAAAAAD4AA + AAAAAAAAAAAAD4AAAAAAAAAAAAAAD4AAAAAAAAAAAAAAD4AAAAAAAAAAAAAAD4AAAAAAAAAAAAAAD4AA + AAAAAAAAAAAAD4AAAAAAAAAAAAAAD4AAAAAAAAAAAAAAD4AAAAAAAAAAAAAAD4AAAAAAAAAAAAAAB8AA + AAAAAAAAAAAAB8AAAAAAAAAAAAAAB8AAAAAAAAAAAAAAB8AAAAAAAAAAAAAAB8AAAAAAAAAAAAAAB8AA + AAAAAAAAAAAAB8AAAAAAAAAAAAAAB+AAAAAAAAAAAAAAB+AAAAAAAAAAAAAAB+AAAAAAAAAAAAAAB+AA + AAAAAAAAAAAAB+AAAAAAAAAAAAAAB/AAAAAAAAAAAAAAB/AAAAAAAAAAAAAAB/AAAAAAAAAAAAAAB/AA + AAAAAAAAAAAAB/AAAAAAAAAAAAAAB/AAAAAAAAAAAAAAA/AAAAAAAAAAAAAAA/AAAAAAAAAAAAAAA/AA + AAAAAAAAAAAAA/AAAAAAAAAAAAAAA/AAAAAAAAAAAAAAA/gAAAAAAAAAAAAAB/gAAAAAAAAAAAAAB/gA + AAAAAAAAAAAAB/gAAAAAAAAAAAAAD/gAAAAAAAAAAAAAD/gAAAAAAAAAAAAAH/gAAAAAAAAAAAAAH/gA + AAAAAAAAAAAAP/wAAAAAAAAAAAAAf/wAAAAAAAAAAAAA//wAAAAAAAAAAAAB//4AAAAAAAAAAAAH//4A + AAAAAAAAAAAP//4AAAAAAAAAAAD///8AAAAAAAAAAD////+AAAAAAAAAAf/////AAAAAAAAB///////g + AAAAAAD////////4AAAAAD/////////8AAAAH///////////gADh////////////4H+f//////////// + /wD///////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////ygAAABIAAAAkAAAAAEAIAAAAAAAYFQAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAADouCgE7MQoBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAADwwCgE8MgoBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCNg0BQzcNAkI2DQNBNQ0EQTUNB0E1 + DQdBNg0HQTUNBkE1DQRCNw0BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEU4 + DQFFOA0BRTgNAUU4DQJFOA0DRTgNBUU4DQdFOA0JRTgNDEU4DRBFOA0URTgNGUU4DRtFOA0aRTgNFUU4 + DQ5FOA0HRTgNAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARTgNAUU4DQFFOA0CRTgNA0U4DQVFOA0GRTgNCkU4 + DQxFOA0QRTgNFEU4DRhFOA0eRTgNJEU4DSpFOA0zRTgNOkU4DT1FOA07RTgNMUU4DSVFOA0WRTgNCkU4 + DQMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARTgNAQAA + AAAAAAAARTgNAUU4DQNFOA0ERTgNB0U4DQlFOA0MRTgNEEU4DRRFOA0YRTgNH0U4DSRFOA0rRTgNMkU4 + DTlFOA1CRDcLSkM2C1BCNQlZQTQIX0AzBmFANAhfQzcLVkU4DUZFOA0tRTgNGUU4DQtFOA0DAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARTgNAUU4DQFFOA0BRTgNBEU4DQZFOA0IRTgNC0U4 + DQ5FOA0SRTgNGEU4DR5FOA0iRTgNK0U4DTFFOA06RTgNQkU4DUpFOA1TQjUJWD8zBl4/MwZmQjUIcUM2 + C35LPRWQVUchp1xMKLVURSClQzYLfEI1CWVFOA1NRTgNMUU4DRpFOA0LRTgNAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEU4 + DQFFOA0BRTgNA0U4DQRFOA0GRTgNB0U4DQtFOA0ORTgNEUU4DRZFOA0bRTgNIkU4DSlFOA0xRTgNOUU4 + DUNFOA1KRTgMVEM2CllCNQlgQTUIaEA0B3FANAh5TT0WjlRFH6VdTiq4bl0+z3toTeONeF7wn4lv/rCW + f/+hjHH+dWRH2Eo7EY9ANAhqRTgNT0U4DTFFOA0aRTgNC0U4DQIAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEU4DQJFOA0ERTgNBUU4DQhFOA0KRTgNDUU4 + DRJFOA0VRTgNGkU4DSFFOA0oRTgNLUU4DTVFOA09RTgNRUQ3C09CNgpXQjUJX0AzB2g+MgVvQjUJe0k6 + EYxOPhicXk8rtGxbO894ZUnjjHdd8ZmEbP2pk3r/u6KI/8qvlP/Stpn/2Lqb/92/n//bvp3/waaL/35r + T+NIORCQQTQIa0U4DU5FOA0vRTgNF0U4DQlFOA0DAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEU4 + DQFFOA0CRTgNA0U4DQVFOA0HRTgNCUU4DQxFOA0RRTgNFUU4DRtFOA0hRTgNJkU4DS5FOA02RzgOPkU4 + DUdENwxNQzYKVEI1CVtANAhiQDMHakM2C3hHOQ6JTT4XmVxNKLNmVTXJdmRI3Yl1Wu+ZhGv+p5F6/7ig + hv/GrpP/zrWZ/9m+of/dwqT/3cGi/9zAoP/bvp//2r2c/9m8nP/bvZz/3b2d/62Tev97aU3kSjoQjkA0 + CGdFOA1KRTgNKUU4DRJFOA0FRTgNAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABFOA0BRTgNAkU4DQNFOA0FRTgNBkU4DQpFOA0MRTgNEEU4 + DRRFOA0ZRTgNH0U4DSVFOA0tRTgNNUU4DT1FOA1GRTgNTkU4DVdCNQldPzMGYj8yBmlDNgt2RTgNg00/ + F5VaSyauZFMxxnVjRNeFcVfslIBn+6aSev+2n4j/w62T/8+3m//YwKT/2sKk/9/FqP/hxaj/3MOk/9m/ + of/YvZ//2L2f/9i8nf/YvJ3/2Lyb/9i7m//Yu5v/2bqb/7eYff+dhGz/dmZI2UQ4DIVDNgpgRTgNPkU4 + DR1FOA0KRTgNAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARTgNAUU4 + DQFFOA0DRTgNBUU4DQZFOA0JRTgNC0U4DQ9FOA0URTgNGEU4DR1FOA0jRTgNKkU4DTFFOA06RTgMQkQ3 + DExDNwtUQzYKXkE1CWRBNAhtQDMHdEE1CH9PQBmVVkchqmJSLr50YkPYgW1S7JF9ZPSikHb/tJ6H/8Gs + lP/OuZ//18Gn/9rFqv/fx6z/38es/93Fqf/bw6f/28Om/9nAo//Yv6L/2L+h/9i+of/YvqD/2L2f/9i8 + nv/YvJ3/2Lyd/9i7m//Yu5v/2Lub/7eafv+ih2z/noZt/3VjRdVCNgp2RTgMUEU4DStFOA0RRTgNBQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARTgNAkU4DQJFOA0GRTgNCEU4DQxFOA0PRTgNE0U4 + DRhFOA0dRTgNI0U4DSpFOA0wRTgNOUU4DUFFOA5KRDcLUUE0CFZANAhdQDQHaEA0B3JDNwuASzwUk1BA + G6ZhUCy7b10+039rUOuRfWP4n4x1/7Kdhv+/qpT/zbqj/9bDrP/cx7D/4cy0/+HKsf/fya//3Met/9vF + qv/Zw6j/2cOn/9nCpv/ZwaX/2cGl/9nAo//ZwKP/2L+h/9i+of/YvqD/2L2f/9i9nv/YvJ3/2Lyd/9i7 + m//Yu5v/2Lub/7aaff+hhWn/pIhs/52Fbv9oWDa5QTMIWEQ3DTZFOA0XRTgNBgAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAEQ3DQFFOA0ERTgNCUU4DQ9FOA0VRTgNHUU4DSNFOA0qRTgNMUU4DTlFOA1BRTgNSUU4 + DVFFOA1aQzYKYkAzB2U+MgVsRTgMe0s8FY1TQx6hYFEsuWtZONF6Z0rfjXth8J6Lcv+tm4T/v6yW/8q4 + ov/SwKn/3cu0/+DNt//fzLb/38y0/93Ksv/bx6//2sat/9rFrP/axar/2sSp/9nEqf/Zw6j/2cOn/9nC + pv/Zwqb/2cGl/9nApP/ZwKP/2b+i/9i/of/YvqD/2L6g/9i9nv/YvJ7/2Lyd/9i7nP/Yu5v/2Lub/7ib + f/+ghGn/o4hr/6WJb/+NeF/wTT0Wc0E0CDdFOA0aRTgNBwAAAAAAAAAAAAAAAAAAAAAAAAAAQDQLAUQ3 + DQVFOA0NRTgNGUU4DSdFOA00RTgNP0U4DEhDNgtQQzYKWEE0CV9ANAdnQDQIcEM2C3xDNguHT0AYml9P + K7dqWDbOe2hL4Yh1XPKahm76rZmE/72slv/LuqT/1MWw/9vMt//f0Lr/4tK8/+LRu//gzrj/3Muz/9rJ + sv/ayLH/2siw/9rHr//ax67/2sat/9zIsP/fyrD/4suy/+HLsf/gybD/38it/9vEqP/Zwqb/2cGk/9nA + pP/ZwKP/2b+i/9i/of/YvqD/2L6g/9i9nv/YvZ7/2Lyc/9i7nP/Yu5v/2r2d/76ghP+ghWr/o4hs/6WI + bP+chGn+XlArkz80BzlFOA0eRTgNCUM2DQEAAAAAAAAAAAAAAAAAAAAAPzQLAkQ3DQxFOA0cRTgNM0M2 + C0dBNAhXPzMGYUA0CG1CNQl6RTgNiFBBGpxXRSCvZVMyxHpmSt6Hc1nzmYdu/qeWgP+5pZH/xrei/9XI + tf/f0b3/4NK+/+LTwf/h07//39C8/93Puv/dzrj/28y2/9vLtf/byrT/28qz/9vJsv/ayLH/2six/9rG + rv/byLD/4s20/9nFrf/Hspj/uaGG/7Kafv+6oof/y7WZ/93Gqv/gyK3/2sKk/9nApP/ZwKP/2b+i/9i/ + of/YvqH/2L6g/9i9n//YvZ7/2Lyc/9i7nP/Yu5v/2r2d/76hhP+ghWr/o4hs/6SIa/+fhWz/alo4qkA0 + Bz9ENwwhRTgNC0M2DQIAAAAAAAAAAAAAAAAAAAAAQDQLB0Q3DRVFOA0vQTQIR0c5DmxRQRuUWEgirmRT + MsNzYULbgm5T6paDa/eoloH/uKeU/8S2ov/RxbL/2M67/9/Uwv/l2sj/4tbD/9/SwP/c0Lz/3M+7/9zO + uv/bzrn/2825/9vMt//bzLf/28y1/9vLtf/by7T/28qz/9vJsv/aybL/2six/93Ls//dy7P/vKaM/5J6 + Xf+CaU3/h3BX/4p2Xv+FblL/hGpN/5iAYv/FrpL/38aq/9vDpv/ZwKP/2cCi/9i/ov/YvqH/2L6g/9i9 + n//YvZ7/2L2e/9i8nP/Yu5z/276d/72gg/+ghWr/o4ht/6SIbP+fhmz/aFg4rUAzB0ZENwwnRTgNDkM2 + DQMAAAAAAAAAAAAAAAA4LQkBQDQLDEM2DB9BNAg5XUwmkIFtUeSUgGj2oY94/7Wkkv/Guqj/0si3/9nQ + v//g2Mf/49rJ/+PayP/j2cf/4dfF/93Uwf/b0L7/3NC9/9zQvf/c0Lz/3M+7/9zPu//czrr/2865/9vN + t//bzLf/28y1/9vLtf/by7X/28qz/9vJs//ayLH/3cy1/9rIsP+ijHD/f2VJ/5aCbf/BuK3/1tXQ/+Dd + 3f/b2tf/xL20/5SCbP+AZ0r/r5d8/9zEp//bwqX/2b+i/9i/ov/Yv6H/2L6h/9i9n//YvZ7/2L2d/9i8 + nP/Yu5v/3L+f/8OliP+ghWr/o4ht/6SIa/+ghmz/aFg2r0AzB0tENwwqRTgNEEU4CwMAAAAAAAAAAAIZ + LgE4LQkCQDQLDj8zCB5aSiRxopB7+c3Es//a0sP/493N/+Tdzv/i283/4drL/+DZyP/g18b/39XE/93U + wv/d08L/3dPB/9zSwP/c0r//3NG//9zQvf/c0L3/3M+7/9zPu//czrr/2865/9vNuP/bzLf/28y3/9vL + tf/by7X/28qz/9vKs//cy7T/3Muz/5+Jbf99ZUj/s6aW/93Z1v/b1tL/y8G2/7ysm/+5p5b/xrqv/9LL + xP+uoJH/gWpO/6+Vev/gxqn/2cCj/9m/ov/Yv6H/2L6h/9i9n//YvZ//2L2d/9i8nf/Yu5v/3cCf/8Wo + iv+ghWr/pIht/6SIa/+hiG7/bl09vUAzB09ENwwsRTgNEEc4CwMAAAAAAAAAAAMZLQE4LQkDQTQLDzwv + BBpxXz+gz8a2/+nn2f/i283/39jJ/93XyP/f2cn/39jI/93Vxf/d1cX/3dXD/93Uw//d08L/3dPB/9zS + wP/c0r//3NG//9zQvf/c0L3/3NC7/9zPu//czrr/3M65/9vNuP/bzbf/28y3/9vLtv/by7X/28q0/9vK + tP/h0br/taGI/3xkSP+xopH/19DL/8a6rv+tl4H/n4Vq/5Z4Wv+RcVP/k3RV/5l8X/+1oY//oY97/4Fo + Tf/Ap4v/4Mao/9m/ov/Yv6H/2L+h/9i+oP/YvZ//2L2d/9i8nf/Yu5z/3cCg/8Sniv+ghWr/pIht/6SI + a/+iiG//cGBBxUAzB1BENwwtRTgNEUc4CwMAAAAAAAAAAAMZLQE4LQkCQTQLDT0wBBdvXTydzMKz/+Tg + 0f/f2Mn/39jJ/+Hbzf/Z0sD/2dLA/+HZyf/d1cX/3dXD/93Uw//d08L/3dPC/9zSwP/c0sD/3NK+/9zR + vv/c0L3/3NC8/9zPu//czrr/3M66/9vNuP/bzbj/28y2/9vMtv/by7X/28q0/9/Nt//Twqr/iHBV/5qI + cv/Qx77/w7Wn/7Ocif+slX3/p5B3/6KHbP+bfmL/mXxe/5Z3Wv+Vdln/nIFl/4dvVP+UfWD/2L6i/9vC + pf/Yv6L/2L+h/9i+oP/YvZ//2L2f/9i8nf/Yu5z/3L+g/8epjP+ihmv/o4hs/6SIa/+jiW7/cF8/wj8z + B1FENwwtRTgNEUQ2DQMAAAAAAAAAAAAAAAA5LgkBQDQLCz4yBhVnVTKKwbWj/+bi1P/f2Mr/4t3O/8q9 + qP+qknv/qJF3/8y/rP/h2cn/3dXE/93Uw//d1ML/3dPC/9zSwP/c0sD/3NK+/9zRvv/c0L3/3NC8/9zP + u//czrr/3M66/9vNuP/bzbj/2822/9vMtv/by7X/28q0/+HQuv+0n4b/gmlP/7qqnf/IvbH/wLCe/7mm + lP+3o4//qZN9/5Z+ZP+Ocln/jnBV/5V2Wv+ZfF7/mHpc/5Z4XP+GbVH/vqSJ/+DFqP/Yv6L/2L+h/9i+ + oP/YvZ//2L2f/9i8nf/Yu5z/3L6f/8yvj/+jiG3/o4ds/6SHa/+kiW7/cmFBxT8zB1FENwwtRTgNEUM2 + DQMAAAAAAAAAAAAAAAAAAAAAPzQLCj8yBhRfTSlyt6mW/uXi0//g2sz/4dzN/6+ZgP/Wzcb/vayc/7Oe + hv/h2sn/3dXE/93Uw//d1ML/3dPC/9zTwf/c0sD/3NK//9zRvv/c0b7/3NC8/9zPvP/cz7v/3M66/9vN + uf/bzbj/2823/9vMtv/bzLb/28q0/+DOuP+XgWT/kn1k/8S2qP/Mv7P/xrip/8Kyof+wnIj/i3BZ/4Fm + T/+BZU3/hmxW/4htVf+RdFb/mXtf/5p7Xv+Lb1P/pI1x/93Dpv/ZwKP/2L+i/9i+oP/YvqD/2L2f/9i8 + nv/Yu53/3L6f/8qvj/+jiG3/o4dt/6OHa/+kinD/d2VHzT80B1JENwwsRTgNEUM2DQMAAAAAAAAAAAAA + AAA9MgoBPzQLCEEzCRJNPhZVqpyH+ePf0P/g2sz/4t3P/7Sfhv/Yz8f/xriq/6+Yf//g2cn/3dXF/93V + xP/d1MP/3dTC/9zTwf/c0sD/3NLA/9zRvv/c0b7/3NC8/9zPvP/cz7v/3M66/9vOuf/bzbj/2824/9vM + tv/bzLX/3c23/9XDrP+MdVj/nYhy/8u+sv/UysD/zMC0/8Oyo/+OdF3/gGRM/4JlTf+Xg27/u7Gm/7mw + pP+Ufmb/knRW/5t9YP+SdVn/ln5i/9a9oP/cwqX/2L+i/9i+oP/YvqD/2L2e/9i9nv/YvJ3/3L+f/8qu + j/+kh23/o4ht/6OHa/+kiXD/d2VHyz8zB1JENwwsRTgNEUM2DQMAAAAAAAAAAAAAAAAAAAAAPzQLBkE0 + CRBFNw1Dn4947OLczv/g28z/5uLU/7qmkP/JvK7/zMC0/6mSd//d1cX/3dXF/93VxP/d1MP/3dTC/9zT + wf/c0sD/3NLA/9zRvv/c0b7/3NC8/9zQvP/cz7v/3M+7/9vOuf/bzbj/2824/9vMtv/by7X/4M+6/828 + o/+Ib1T/pI96/9XMwv/Y0cr/0si9/7Gdjf+AY0v/g2hP/4duVf+8s6j/1tLN/+Dd2v/Eu7L/kHRa/5d6 + W/+Wd1v/jXNZ/9G4nP/dw6b/2L+i/9i+of/YvqD/2L6g/9i9nv/YvJ3/276e/9C0lf+ojHD/oohs/6KH + a/+ni3H/eGZHzD8zB1JENwwsRTgNEUM2DQMAAAAAAAAAAAAAAAAAAAAAPzQLBEE1CQ5HOA44k4Fp2N3Y + y//i287/4+HS/8KznP+/r5//0Ma8/6ePdf/Vy7n/4NjI/93VxP/d1MP/3dTD/93Twf/c08H/3NK//9zR + v//c0b7/3NC9/9zQvP/cz7v/3M+7/9vOuf/bzrn/2823/9vMt//by7X/4M+6/828o/+HblL/pI94/9vV + zf/d1tD/1szC/5+Ldv+BZU7/gGRL/5WCbP/MxsD/4t3Y//Hx7v/k4d//nIVw/5NzVf+XeFz/kXZb/9G4 + nP/dxKb/2L+i/9i/of/YvqD/2L6g/9i9n//YvZ7/27+f/9C0lf+njXD/o4hs/6SHbP+kiW7/hHBU2Eg6 + EFpDNworRTgNEUM2DQMAAAAAAAAAAAAAAAAAAAAAQTULA0I1Cg1FNw0thnJYxtvUxv/i3dD/4t/Q/8e6 + pf+3o5D/08vB/6aPdf/Nwq3/4tvM/93UxP/d1MP/3dTD/93Twf/c08H/3NK//9zRv//c0b7/3NC9/9zQ + vP/cz7z/3M+7/9zOuv/bzrn/2823/9vMt//by7b/4NC6/8y7o/+HblL/oIx0/9zWz//g2dT/1s7D/56K + dP+CZU3/f2NK/5mGc//QzMb/5+Tf//v5+v/t6un/pZF//5JyVf+WeFz/kHZb/9C4m//dxKb/2L+i/9i/ + of/YvqH/2L6f/9i9n//YvZ3/27+f/8+zlP+njHH/o4ht/6SHbP+jiW7/h3JX2ko8FFxDNgorRTgNEUM2 + DQMAAAAAAAAAAAAAAAAAAAAAQTULA0M2Cw1CNQoheGZJstPMvf/k4dP/4tzO/9HItv+wmoX/0ce9/6eQ + eP/Ft6H/5N3O/9zUw//d1MP/3dTD/93Twv/d08H/3NPB/9zSv//c0b//3NG9/9zQvf/cz7z/3M+7/9zO + uv/bzrn/2825/9vMt//bzLb/38+5/9PDrP+LcVb/mYNq/9nSyv/g2NL/1szE/6GMd/+BZU3/gWRL/5N/ + af/Iwrv/3NfT/+rn5f/i39v/oY14/5JzVf+WeFz/lHpe/9K6nv/dxKf/2b+j/9i/of/YvqH/2L6f/9i9 + n//YvZ7/2r6f/9S3mP+pjnL/o4hs/6SIbP+lim//hnFW2Ug6EV1DNgotRTgNEkM2DQMAAAAAAAAAAAAA + AAAAAAAAQTULA0Q3DQw+MgQXZ1YzncvBsv/m49b/4dvN/9nTwv+umIL/zcG1/6yVgP+9rZb/5N/O/9zU + xf/d1cT/3dTD/93Twv/d08H/3NPB/9zSv//c0b//3NG9/9zQvf/c0Lz/3M+8/9zOuv/czrn/2865/9vN + t//bzLf/28y2/9/Ouf+Vf2T/iW9U/8zAs//d1c//1Mm//7Gejf9/ZEv/hGlQ/4ZtVf+2rJ//zsnD/9XR + y//JxLz/lHxj/5V2WP+UdVr/noVp/9e/ov/bw6b/2b+i/9i/ov/Yv6H/2L2g/9i9n//YvZ7/2b2e/9a6 + mv+sj3T/oodr/6SIbP+lim7/i3Vb40s+FmdDNgovRTgNFEM3DQYAAAAAAAAAAAAAAAAAAAAAQTULAUQ3 + DQo/MgUTYlIuiMG1pP/n5dj/4t3P/9/YyP+0n4j/x7qs/7Kdif+0n4f/4tvL/9/Wxv/d1cT/3dTD/93T + wv/d08L/3dPA/9zSwP/c0r//3NG+/9zQvf/c0Lz/3M+8/9zOuv/czrr/2864/9vNuP/bzLf/28y2/+HQ + vP+wm4T/f2RI/7Sfjf/Xzsb/zcK2/8O1pP+OdF//gWVN/4JmTf+Sfmn/t66j/7+5sf+ejHv/kXRX/5p8 + X/+Pclb/sJZ8/9/GrP/ZwKT/2cCj/9i/ov/Yv6H/2L6h/9i9n//YvZ//2b6e/9W5mv+sj3T/oods/6OI + bP+kiW3/jnhf7VBAGXJCNgo0RTgNGEM3DQYAAAAAAAAAAAAAAAAAAAAAAAAAAEQ3DQhANAcRXEsmcran + lPvq6Nv/4t/R/+Lczv+4pZD/w7Sj/7eikP+tl37/4NfH/9/Xx//d1cT/3dXE/93Uwv/d08L/3dPA/9zS + wP/c0r//3NG+/9zQvf/c0Lz/3M+8/9zOuv/czrr/2864/9vNuP/bzbf/28y2/+DPuv/Pvqf/h29U/5F3 + Xf/Ju67/yr2w/8S1pP+xnIn/iG5W/4FmTv+AZU3/h25Y/4tzXf+PcVf/mHte/5d4Xf+QdVr/ybKX/9/G + qv/ZwKT/2cCj/9i/ov/Yv6H/2L+h/9i9n//YvZ//2b6e/9a6nP+tkHX/oods/6OJbP+kiW3/jnhe608/ + GXZCNQo6RTgNHEM2DQgAAAAAAAAAAAAAAAAAAAAAQjYMAUQ3DQhCNAkSV0UgXaqch/Hp5tj/4+DS/+Xh + 0/+/r5n/vaya/7yqmP+okXf/3NXF/+DZyP/d1cT/3dXE/93Uw//d08L/3dPB/9zSwP/c0sD/3NG+/9zR + vv/c0L3/3NC8/9zPu//czrr/3M66/9vNuP/bzbj/28y2/9zMt//i0bv/rpl//31jR/+ii3L/xLWk/76t + m/+4pJD/qJJ9/5V8ZP+NcVn/i29U/5J0V/+ZfF7/mXxf/41wVP+pkHX/38es/9rCpv/ZwaT/2cCk/9m/ + ov/Yv6L/2L+g/9i+oP/YvZ//2L2d/9u/oP+vk3f/oYZr/6SJbP+liWz/kXpg709AGnxCNgo+RTgNHkM2 + DQgAAAAAAAAAAAAAAAAAAAAAQjYMAUQ3DQdDNgoPSTkPQ5yNdefl4dP/5uHV/+fk1//Iu6f/uKaR/8Cw + nf+nj3X/2c+//+HZy//d1cT/3dXE/93Uw//d1ML/3dTD/93Twf/c0sD/3NG+/9zRvv/c0L3/3NC8/9zP + u//czrr/3M66/9vNuP/bzbj/28y2/9vMtv/g0Ln/2smy/5V/ZP9+Y0f/oYpx/7mlkv+znYn/rJR+/6SL + cP+bf2L/mXxf/5p9X/+afF//j3BU/5R7X//VvaL/3MWp/9nBpf/ZwaT/2cCk/9m/ov/Yv6L/2L+g/9i+ + oP/YvZ//2L2f/9u/oP+vk3f/oYZr/6SIbf+kiG3/lX5l/FNEHYZCNQk/RTgNH0M2DQkAAAAAAAAAAAAA + AAAAAAAAAAAAAEQ3DQVDNgsOQjQIM5CAZt3g2s3/5+TZ/+fk2P/QxLT/uKWQ/8GxoP+oknr/08e1/+Lb + zP/d1cT/3dXE/93Uw//d1MP/4NXE/+DWxP/h18X/3dK//9zRvv/c0L3/3NC9/9zPu//cz7v/3M66/9vN + uP/bzbj/28y3/9vMtv/by7X/4c+6/9LAqP+TfWL/fmNI/5N7X/+mjnb/poxy/5+DZ/+ZfV//mXxf/5V3 + XP+JbVH/kHdc/8mzmP/fyK3/2cKm/9nBpf/ZwaT/2cCk/9nAo//Yv6L/2L+i/9i+oP/YvqD/2L2f/9u/ + oP+wlHj/oYZr/6SIbf+kiG3/lYBl+1NDHYdCNQk/RTgNH0M2DQkAAAAAAAAAAAAAAAAAAAAAAAAAAEQ3 + DQRDNgoORDYLKoZzWMrb1Mf/6efc/+jl2f/Wzr//uaSR/8Kyov+slH7/zL+t/+Tf0P/d1sb/3dXE/9/V + xP/h18b/zLyo/7qljv/Pwa7/39PB/+HVwv/d0r//3NC8/9zPu//cz7v/3M65/9vOuf/bzbj/2823/9vM + tv/by7X/28q0/+HQuf/Vxa3/p5F3/4RsUf+Cak7/inBV/4twVf+Kb1P/hm1R/4duVP+gim//z7ug/9/I + rv/Zw6j/2cKm/9nCpv/ZwaX/2cGk/9nAo//Zv6L/2L+i/9i+oP/YvqD/2L2f/9vAoP+2mX7/oods/6SI + bP+liW3/mIBm+1JDHYZCNQk/RTgNH0M2DQkAAAAAAAAAAAAAAAAAAAAAAAAAAEQ3DQJDNgsMQzcLInpm + SLXVzsH/6und/+jl2v/d1sr/uKaS/8Gxof+uloD/xbej/+Xh0v/g2Mj/3dXF/9/VxP/i2Mf/v62W/6CF + a/+mj3X/tZ+J/8u8pv/cz7z/4tXC/+DSv//d0Lz/3M+7/9vOuf/bzbj/2823/9vMt//by7b/28u1/9rK + s//gz7j/4M64/8y6of+vm4L/m4Rp/5R+Y/+ahGj/qpV7/8eyl//dyK//38mw/9nDqP/Zw6j/2cKm/9nC + pv/ZwaX/2cGk/9nAo//ZwKP/2L+h/9i+of/YvqD/2L2f/9u/oP+3m3//ooZs/6SJbf+kiGz/moJp/lRF + II1BNQg+RTgNH0M2DQkAAAAAAAAAAAAAAAAAAAAAAAAAAEQ3DQJENwwMQjUJFm1cOpvMw7T/6+nd/+jm + 2v/l4dX/vqyY/8Gvn/+xmoX/wbCc/+Xh0//h2sv/4NjI/93UxP/i2cj/x7eh/6SKcP+ojnX/po50/6WO + dP+ym4T/xbSe/9fKt//g07//4dK+/93QvP/cz7r/28y4/9vLt//bzLb/28u1/9vKtP/bybP/28qz/9/N + tv/fzbb/38y0/9/Ls//gy7P/4Muy/9/JsP/bxq3/2cOp/9nEqf/aw6j/2sSo/9vDp//bw6f/28Om/9zC + pP/cwqX/3MGi/9rAo//Zv6D/2b+f/9vAof+3m4D/ooZr/6SIbf+kh2z/nIRr/1VHIZBBNQg+RTgNH0M2 + DQkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABHOQ4LPjIFDlxMJ4LCt6X/6+jc/+nm2//n5Nj/xLSh/8Gv + nf+1n4z/vamW/+Tf0P/i3M7/4dnL/9/Xxv/j2sn/zr+s/6WNc/+okHb/qZF4/6mSev+nj3X/po51/66Y + gP+/qpT/z72o/9rLtv/cz7n/3dC7/+HRvP/g0Lr/38+5/9/Nt//fzbf/3820/9zMtf/cy7T/3Muz/93K + sf/dybH/3cmx/93Ir//fya//3cit/9vGrP/axKn/2sOn/9jBpP/TvKL/0Lqf/822nf/Ks5v/yLGY/8Ww + mP/CrJf/wq6X/8KumP+xmYD/pIhs/6OIbf+kiWz/noZs/1REH41ANQg+RTgNH0M2DQkAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABHOQ4JPzIGD1lKJG22p5X/6+jd/+ro3//q6N3/ybyq/7+unf+4pJH/uaSR/+Lb + zv/k3dH/4trM/+HZyv/j28v/08e1/6qReP+njnX/qZF3/6mSev+qknr/qpN7/6iRd/+nj3b/qpN8/7Ca + g/+5o4z/wq+Y/8i3of/Mu6b/0L6o/9TCrP/Uwqz/1MKq/9PBqv/Uwan/1MGp/9TBqf/Sv6b/z7ui/8+7 + o//Nt5//yrWc/8Swmf+/qpX/uqaR/7ijj/+2oY//taGO/7Sfjv+znoz/sZ6M/7Kfjv+zn47/s6GR/7Wj + k/+vloH/pIhs/6SIbf+liGz/noZs/11NKZZBNAg+RTgNH0M2DQkAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABHOA4HPzMHD1ZHIFqomIT46+nf/+ro3//s6uL/z8O1/7+tm/+8qZb/tZ+K/+DZzP/m4dP/49zN/+La + y//j28z/39XF/7Gagf+mjXP/qZF3/6mSev+pknr/qpN7/6qTe/+qlHz/qpN8/6mTe/+qknv/qJJ7/6iR + ev+slH7/rZeB/7GahP+xm4X/sZuG/7Gbhv+ynIb/spyH/7KdiP+ynIf/sJqG/7Cbh/+ynIn/sp2K/7Ke + i/+zno3/sp6M/7Gcif+wm4j/r5yJ/7Gejf+2ppj/vrSp/8rEv//AtKf/tKGO/7ellP+vloH/pIht/6SI + bf+liGz/noVr/2paOKNBNAk+RTgNH0M2DQkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABFOA4GQDQIEVJC + G0WdjHXs6OXZ/+vp4P/u7OT/2M7B/7+tm/++rpv/s52J/9zVx//n4tb/5d3P/+Lczf/i2sz/5d/P/72q + lf+mjXH/qJB4/6mSev+pknr/qpN7/6qTe/+qk3v/qo50/6iPc/+tk3z/rZZ//62WgP+uloD/rZaA/62X + gf+ul4H/rpiC/66Ygv+vmYP/r5mE/6+ahf+wmob/sJuH/7Kdiv+vmYX/qJF8/6KKcv+ehW3/moJr/5uE + bf+giXX/ppOD/7GilP+5rqL/xL63/9HPzf/Kw7z/taGQ/7ekk/+vloH/pIht/6SJbf+liWz/oIds/2dY + NqFBNAc+RTgNH0M2DQkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABFOA0FQzcLEUM1Ci6PfmXg4dvQ/+7r + 4//t7OT/3dfM/8Kwn//BsZ//tqCM/9bNv//o5Nn/5d/R/+Tdz//k3M7/5d/R/87Ar/+qknv/qZF3/6mS + eP+pknr/qpN7/6qRd/+qk33/tbSu/7u4sv+ul4L/rJN7/62WgP+tloD/rpeB/7CVfP+xlHv/rpeB/7CW + fv+yln3/sJqE/7Cbhv+xm4b/sp6J/62XgP+LbVH/hGZI/4ZpTf+KbVL/jnNa/5N7Yv+Vf2j/lH5p/5B7 + ZP+Ic1r/k4Br/8S/uf/Nx8L/tqKQ/7akkv+vloH/pYlt/6SJbf+liW3/oYdt/2dYN6RBNAhBRTgNIkM3 + DQo9MgsBAAAAAAAAAAAAAAAAAAAAAAAAAABFOA0CRTgNED0wAyKDcVbM2tPG/+/u5v/t6+P/5eDU/8W0 + pP/Es6L/t6KP/9HHt//q5tr/5eDS/+Xf0P/k3c//5t/R/9rQwf+znYj/r5d//6mRdv+pknr/qpJ7/6iP + dP+uvML/0vL///H////P1NP/qpJ9/6yUff+tl4D/sJZ8/6qYhv+bs7r/mMPY/5q9yv+mo5z/s5d9/7Cb + hf+xm4b/tJ6K/6SMdf+CYkT/hWVJ/4lrT/+IblT/g2xS/4FqUP+CalD/i3Rc/5qIcf+snYr/i3Vc/56R + f//Py8f/tqOR/7ajkv+vloD/pYlt/6SJbf+liW3/oYdt/3FhQblBNAhHRTgNJUM3DQw9MgsCAAAAAAAA + AAAAAAAAAAAAAAAAAABFOA0BRTgNDT8zBh57Z0uy0ci7//Lx6f/t7OP/6ubd/8m4qP/GtqT/uKSR/8u+ + rv/s6d3/5+LV/+bh0//m39L/5d/R/+LazP+/rZj/s52H/7CZgv+okXj/qpF4/6iTff+s0ev/z+3//+z4 + ///W7vj/r6WZ/6qRd/+wlHv/rJiF/4rA3P+S3P//qeP//6Hi//+L0fb/nqiq/7OXfv+xm4X/sp2J/6yW + gf+FZkr/hmdL/4ZrT/+Ca1H/lX9m/62Zhf/Ftqf/2dDF/+/r5v//////uayc/4t4Yf/QzMf/tqOS/7aj + kv+vloD/pYlt/6SJbf+liW3/oohu/3NiQrxBNAhKRTgNKEM3DQ89MQsDAAAAAAAAAAAAAAAAAAAAAAAA + AABFOA0BRTgNDEAyBxpuXDuXysGy//Ly6v/t6+P/7uzk/8q9rf/DsqH/uKSR/8u+sP/s6uD/6OLW/+bh + 1P/m4NP/5t3R/+ji1P/KvKn/tJ6J/7eijv+xmYP/qpF4/6iSeP+ky+T/suP//7/n//+24/z/rKWb/66S + dv+xk3X/kKy6/3zT//+j2///v+f+/7fi/v+Q2P//fMXx/6qbjP+zmYH/sZyH/7Cbh/+Ka0//hWZI/4Zo + Tf+EbFL/rJR+/8e2pP/Xy7//5t3U//Dr5v//////x72x/4dyWv/Oy8f/t6WU/7Wjkf+ulX//pYlt/6SJ + bf+liG3/oohu/3NhQrpBNAhKRTgNKEM3DQ89MQsDAAAAAAAAAAAAAAAAAAAAAAAAAABFOA0BRTgNCkA0 + CBZhUCx9wbel//Dv5//v7OX/8O7m/9zUyf/FtaT/yrus/+Pd0v/q6N3/6eTZ/+fi1v/n4dX/5+DT/+ji + 1f/XzL3/uKOP/7eijv+3o4//spyH/6yRdf+nqqf/o9j4/6Ld//+lxNf/rJV//66Tev+ulHz/eLbX/3bQ + //+Z1v7/qd3+/6Tb/v+M0v//asf//5Wkqv+1mH7/sZuH/7Gdif+Qc1n/hGVI/4ZpTv+Da1H/o4xz/8Ov + nP/Sxbj/5dvT//Pu6v/9/f3/xryw/4JtU//Jw77/uqmY/7aikf+sk3z/pYlt/6SJbv+liG3/oohu/3pn + S8hBMwdGRTgNJkM3DQ09MgsCAAAAAAAAAAAAAAAAAAAAAAAAAABFOA0BRTgNCUA0CBJQQBlluKmW/+/s + 5P/x7+j/7uzk/+7s5f/s6eD/7enh/+3p4f/q5tv/6eXa/+jk1//o49b/5+LU/+ji1f/i2c3/vq2Z/7ij + j/+4pZH/uKOP/7Seif+uk3j/qaKY/6isqv+qmIP/rZR7/6+Vff+ulX7/a7PZ/2TI//+Azf7/itD+/4fQ + /v92yv//XMH//4mmtf+3mX3/sZuH/7Oeiv+YfWL/gmJE/4ZqTv+Bak//nIVr/7qlkf+8rZv/uaqb/7Ch + kP+llIH/iHJY/5WEcP/Rzcv/u6yc/7aikP+qkXj/pYpt/6SJbv+liG3/oohu/3poS8RBNAg+RTgNIEM3 + DQo9MgsBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARTgNBkE1CBBPPxhVrJuH9e3q4P/y8Ov/7+3m/+7s + 5f/v7eX/7uvi/+zp3//r59//6+fd/+nl2v/p5Nn/6eLX/+ji1v/o4tX/zL+t/7mlkf+7p5T/uqaS/7ik + kf+2oYz/sZZ8/62Ocv+sk3j/rZV+/66Vff+0k3f/bajM/0q///9lwv//a8X+/2rE/v9ewP//RLj//4qh + rf+3mX7/sZuH/7WgjP+ehG7/gWFD/4hqTv+Ea1H/g2xU/4ZvVv+DbFL/gWpQ/4FqUP+Ldl//nY17/8G6 + s//Iwbr/t6WV/7Oei/+njXL/pYpv/6SJbv+liW3/oodu/29ePaJANAgyRTgNGkM2DQcAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAARTgNBUI1Cg9NPBVGno525Oro3f/z8uv/7+3n/+/t5v/u6+X/7uvi/+3q + 4f/s6N//6+jf/+rm2//q5dr/6OTY/+jj1v/r5dj/2tDB/72pl/+8qZf/vKmW/7qmk/+5pZL/uKSR/7Se + if+umID/rJV+/62Vfv+0lHb/lJub/zay+v8+t///T7n//024//81tv//P6zw/6eajP+1moH/sZuH/7Sg + i/+ji3T/gWFC/4NkR/+Gak7/hmtQ/4lwVv+TfGT/nYl0/6iXhv+1pJb/u6yd/7uqnf+3pJT/taCO/6yT + ev+mim//potw/6WKb/+mim3/nYVs/ldJI3RANQgkRTgNEkM3DQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAARTgNBUM2Cg9JOQ82kYBm0ebi1v/z8u7/8e/p/+/t5//w7eb/7u3l/+3q4//u6uH/6+jg/+zo + 3f/q5tz/6+Xa/+nj2P/p5Nj/5uDS/8a2pP+9qpj/v62Z/7yplv+7p5T/uaWT/7ikkf+2oo7/s52H/6+Z + gv+uln//s5V4/3ies/8tqfX/IK3//x6t//8xp+7/iZ2m/7iZff+xm4b/sZuH/7Kdif+wmYX/lHhe/41x + Vv+agGb/ooty/6mUgP+wm4j/tKGN/7WhkP+1oY//tKCN/7Oeiv+wmIT/qpB3/6eMcf+njHH/potw/6aL + b/+njHH/h3NY1Eg7ED1DNgoZRTgNC0M2DQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARTgNA0Q3 + DAxAMgUkgW9Svd3Yy//19e//8vDq//Hv6f/w7uj/8O3m/+/s5f/u6+P/7erh/+zp4P/s59//6ubc/+rl + 2f/q5Nj/6+ba/9bLvP+/rZr/wa+d/7+tm/++rJn/vKiW/7qnk/+6ppL/uKOP/7ahjf+ynYn/sZmC/7aW + ev+WmJX/cZyx/3Ocsf+fmpL/uJl9/7CahP+wmob/sZuH/7Gch/+ynYr/s56L/7Kfiv+1oY3/taGP/7ai + j/+0oI3/s52J/7Gahf+vmIL/rpV9/6qRdv+pjnT/qI1y/6iNc/+njHH/p4tw/6iMcf+bhGz8X1AsdD8y + BhhFOA0QRTgNBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARTgNAkQ3DAs9MAMbdWRFr9XO + vv/29vD/8vHr//Hw6f/x7+n/8O3n/+/t5v/v7OT/7uvj/+zp4f/s6OD/7Ofc/+rl2v/q5Nj/6+TZ/+bf + 0v/Gt6b/wa+d/8Gwnv+/rpv/vqyY/7yplv+7qJT/uaWR/7mkkf+3o5D/tqKO/7Sfif+5m4H/vJl7/7uZ + e/+2mH7/sJqD/6+ahf+vmob/sZuH/7Gch/+xnIj/s56J/7Seif+znIf/spuE/7GYgf+wln7/r5V9/66T + e/+tknj/rJF3/6qQdf+qkHb/qI9z/6mOdP+ojXH/p4xx/6CIb/9zY0ObQjUIGkM2CxJFOA0HRTgNAQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARTgNAUQ3DAg/MgYUblw8mczDtP/19O//8/Lu//Px + 7P/y8Ov/8e/q//Hu5//w7eb/7+zl/+3q4v/t6eH/7Ojf/+rm2//q5dn/5+HW/+nj1//Xzb//wbCf/8Gx + n//Csp//wrCe/8Cvnf+/rpr/vaqX/7uplv+5pZP/tqKP/7Ofi/+ynIn/sJuG/6+ZhP+vmoX/spyG/7Oc + h/+znIf/tZ6I/7Wdh/+1nYb/tJyF/7SbhP+zmYL/spiA/7GYgP+wln7/r5V9/66UfP+vlHz/rZJ6/66S + eP+skXf/qY90/6iNc/+jinH/loBo8W1dPINFOA4cQzYKEEU4DQlFOA0CAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAARTgNAUQ3DAdANAgNZFIxf8S4pv/08uv/9vXw//Py7f/z8ev/8u/r//Hv + 6f/w7uf/8O7m/+3r4//t6uL/6+jg/+rl3P/o49n/5uLW/+fg1f/m4NT/0ca4/8Cwn/+8qpn/vKmX/7qm + lP+2oo7/tJ6K/7OdiP+ynIb/sZyG/7WdiP+1non/t6CL/7mijP+6oo3/uaGL/7mijP+5oYr/uKCJ/7ee + h/+2nYb/tJ2F/7Wchf+0m4T/s5mC/7Oagv+ymID/s5iA/7CVff+vk3v/rZN6/6aNdf+hinL/m4Vt+413 + Xdx4ZkiZV0kjRUAzBwxCNQoKRTgNB0U4DQIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAARTgNAUU4DQZBNAgEWEchW7ismPrs6uD/9fPw//b18v/29PD/9fPu//Tz7v/z8ez/8vDp/+7t + 5f/s6eD/5+TZ/+Lc0v/a08j/08u8/8zCs//Jvq3/yb6s/8Cynv+3oo7/s52H/7Seh/+4oYz/u6WQ/7ym + kf++qJP/wKqV/8Cqlf+/qZP/vqaR/7ylj/+8pI//u6ON/7ujjf+7o4z/uqKL/7mgif+4n4j/tp+G/7Wc + hv+1m4X/sZiB/6yUff+okXr/oot0/5yGbvSRfWLjhnJX0IFtUqxoVzV8XE0oUU0+FiA+MgUKQjUJB0Q3 + DAdFOA0ERTgNAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEU4 + DQNBNAgDSzsSKJmIb93d2Mr/6unf/+7t5f/u7OT/7Ong/+nm2//n4tf/4trO/9nQxP/PxLX/v7Ke/6+f + if+nloH/pZJ8/6GOeP+fi3T/pI56/66Zhf+4oo7/vqqW/8Svm//FsJz/xbCb/8Kumf/BrZf/wKqW/8Cp + lP+/qZb/waqU/8CplP++ppH/vKSO/7qijf+5oYr/s5uF/7CYg/+slYD/pI93/52Hcf2SfWTui3Zd0IVx + V7RsXDuWZFUyd2JTL1NRQxwvQzgLGEU4DQ0AAAAAAAAAAEI2CgdFOA0GRTgNBEU4DQIAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEU4DQFENw0HQTUJB1xM + J1qhkHru0MS0/+DUxf/ZzL3/1ce3/9LDsf/Rv63/zbup/8a0of+3oo//sp+N/7emlv+1o5L/rZiF/6OL + c/+YfmT/moBl/6OOdv+znor/vaiU/8Ovmv/FsZz/xrGc/8Wwm//Fr5r/xK+b/8Cplf+6pI//tp6J/6+Z + hP+ok33/o411/pqFbvuTf2bkjXhfynpoSq5tXDyPa1s6c2BRLVBJOxEwSzsSIUo6EBI/MwcDAAAAAAAA + AABBNQkBQzYKAUM2CwNFOA0FRzkOA0U4DQIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABFOA0CRDcMBz4yBQFWRR9AiHNaxL6o + lv/XxbX/18a1/9LAr//Qvaz/zLup/8Kvmv/Iuan/9PHv//Xy7//d08n/w7Kf/6yTfP+bfWD/lXVW/6OL + cv+1oY3/u6WR/7+plf++qJX/uKKN/7Cahf+lkXv/nYlx85aCauaMeF7WfGlNwXVkR6JyYEF8X08qWU4/ + GD5OQBktTj4WG0M2Cgg+MQUCPzMGAT8zBgEAAAAAQjUJAkI2CgJFOAwERTgNAkU4DQFFOA0CAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARTgNAUU4DQVANAcBSToRHHJgQI6qloL1zLup/9nI + t//XxrX/0sKx/8i1of/ZzL////////f28//b0cf/wrGe/6qTfP+bf2H/mXtc/5F6YP+KdmH1jXhh5YZy + WNF/a1C6fGdLoHBePoFbTCZlWEkiS1dIIjRNPxgbQDMHCEA0BwdBNAgEQjQIAgAAAABCNQkCQjUKBEQ4 + DAZFOA0FRTgNA0U4DQJFOA0BRTgNAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEU4DQFFOA0FQTQIAwAAAABbTCdQjnhg1K6ahf26ppP/vaqW/6yX + gv/Ctqj////+/+ff1//KvK3/uKKO/6aLcf+bfWD/nX9g/4tzWf9bSSxoVkcjPEg5EB9DNQsPQzYLBwAA + AAAAAAAAAAAAAAAAAABBNQkDRTgNBEU4DQRFOA0DRTgNA0U4DQJFOA0BAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAARTgNAkM2CwMAAAAARDYNE2FQLlBtWzqDbV07oGZTMpGYh3LN3NHJ/9PF + uv/DsqD/tp+L/6WNdP+Ue172j3Zb4HtmS4hSQB8OUD4bB0o7FANDNgsBQzYLAUQ3DAJFOA0DRTgNAkU4 + DQFFOA0BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAEM2DQFDNw0CQDQKAwAAAAAAAAAAAAAAAAAAAABcSiksfWlPeYJuVZR/bFOXfmlPhntl + TGuEb1VLbls/JAAAAABYRSMEVEMiAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAD0yCwI8MQsDPTEMBEM1EgUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABDNRYBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////////8A + AAD///////////8AAAD///////////8AAAD/////////P/8AAAD/////////P/8AAAD////////gB/8A + AAD///////AAA/8AAAD//////wAAAf8AAAD/////2AAAAP8AAAD////+AAAAAH8AAAD////AAAAAAD8A + AAD///4AAAAAAB8AAAD//4AAAAAAAA8AAAD/8AAAAAAAAA8AAAD+AAAAAAAAAA8AAADwAAAAAAAAAA8A + AADAAAAAAAAAAA8AAACAAAAAAAAAAAcAAACAAAAAAAAAAAcAAACAAAAAAAAAAAcAAAAAAAAAAAAAAAYA + AAAAAAAAAAAAAAYAAAAAAAAAAAAAAAYAAAAAAAAAAAAAAAcAAAAAAAAAAAAAAAcAAACAAAAAAAAAAAcA + AAAAAAAAAAAAAAcAAACAAAAAAAAAAAcAAACAAAAAAAAAAAcAAACAAAAAAAAAAAcAAACAAAAAAAAAAAcA + AACAAAAAAAAAAAcAAACAAAAAAAAAAAcAAADAAAAAAAAAAAcAAACAAAAAAAAAAAcAAACAAAAAAAAAAAcA + AADAAAAAAAAAAAcAAADAAAAAAAAAAAcAAADAAAAAAAAAAAcAAADAAAAAAAAAAAcAAADgAAAAAAAAAAcA + AADgAAAAAAAAAAcAAADgAAAAAAAAAAcAAADgAAAAAAAAAAcAAADgAAAAAAAAAAMAAADgAAAAAAAAAAMA + AADgAAAAAAAAAAMAAADgAAAAAAAAAAMAAADgAAAAAAAAAAMAAADgAAAAAAAAAAMAAADwAAAAAAAAAAcA + AADwAAAAAAAAAAcAAADwAAAAAAAAAAcAAADwAAAAAAAAAA8AAADwAAAAAAAAAA8AAADwAAAAAAAAAB8A + AADwAAAAAAAAAD8AAADwAAAAAAAAAH8AAAD4AAAAAAAAYf8AAAD4AAAAAAAMD/8AAAD8AAAAAACB//8A + AAD+AAAAAEA///8AAAD/EAAA8B////8AAAD/yAAAB/////8AAAD/48An//////8AAAD//D////////8A + AAD//9////////8AAAD///////////8AAAD///////////8AAAD///////////8AAAD///////////8A + AAD///////////8AAAAoAAAAQAAAAIAAAAABACAAAAAAAABCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADcsCAE4LggBAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAA3LAgBOS8IAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAD4yCwE+MgsBOzAKAT0yCgM+MgsCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABCNQsBQjULAkI1CwJBNQsDQTULBUE0CwlBNAsMQTQLEUE0CxJBNQsQQTQLC0E0CwYAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQjULAUI1 + CwFCNQsCQjULBEI1CwNCNQsGQjULCUI1Cw1CNQsRQjULFkI1CxxCNQsjQjULLEI1CzRCNQs2QjULMUI1 + CyVCNQsXQjULCUI1CwEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEI1CwEAAAAAAAAAAEI1 + CwFCNQsDQjULA0I1CwZCNQsJQjULDUI1CxJCNQsWQjULHUI1CyNCNQssQjULM0E1CjxAMwhFPzIITD4x + B1U9MARdPC8DXj0xB1hBNQpMQjULM0I1CxpCNQsKQjULAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQjULAQAA + AABCNQsCQjULBUI1CwhCNQsLQjULD0I1CxVCNQsdQjULIkI1CypCNQozQTQKO0A0CUNAMwhMPjEHVDov + A1w6LgRmPjEGdEAzCoRKPBaaV0kltFxNK7xKPRidOy8Eb0AzCFZCNQs4QjULG0I1CwpCNQsBAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCNQsBAAAAAEI1 + CwNCNQsFQjULB0I1CwpCNQsPQjULE0I1CxlCNQsfQjULKUI1CzFBNAo6QDMJRD4yB0s9MAVUPC8FXDsu + BGY+MQd1PjEIg0c4EpRWRiOwYVEvxXZjRdyJdFnvnIZr+7KZgP/ApIv/ooxx/2BQLsA6LAN4PTIHVUI1 + CzhCNQsbQjULCUI1CwIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEI1CwEAAAAAQjULAUI1 + CwRCNQsGQjULC0I1Cw5CNQsSQjULGUM1DB9DNgwoQjULMEE0CjdAMwk9PjIHRDwvBk07LwRYOS0DYzwv + BHM9MAeERDYPllFAHa1cSyvBcmBC14ZyVu+ag2n9rpV8/72ljP/MsJb/17ue/9y+of/fwJ7/4sSi/+LD + pP+yln//X04uxjsuA3g/MghWQjULNUI1CxdCNQsIQjULAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEI1CwFCNQsCQjULA0I1 + CwZCNQsJQjULDUI1CxFCNQsXQjULH0I1CydCNQswRDUNOEE0CkA/MgdGPC8FTTsuBFQ5LgFfOi4DbD8y + CH5DNA2STj8aqFlIKMBsWz3WgW1T6ZWBZ/islXv/vaaN/8iwl//XvaL/3cSn/9/Epv/hxqf/3sOk/9zA + nv/avZ3/2LyZ/9a5mf/hwJ//za2Q/5uDbP9fTy3AOC4BcEE0CVFCNQssQjULDkI1CwIAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCNQsBQjULAUI1CwFCNQsDQjULBUI1 + CwlCNQsMQjULEUI1CxVCNQscQjULI0I1Cy1CNQs2QTUKP0AzCUk+MgdPPC8FVzgsAF05LQFoPjEHe0Az + CoxNPximWUcnwGdWNtF8a03nkXxi9aeSef26pIz/yLOa/9S9pf/cxKr/38er/+HJrP/gx6n/38Wp/9zC + pP/Yv6H/17yd/9e8nf/Xu5v/17ub/9e7mv/Xupn/276d/8ipiv+ninD/lX9m/lxNKbg5LgJlQjYLQkI1 + CxtCNQsHQjULAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCNQsBQjULAkI1CwNCNQsGQjULCEI1 + CwxCNQsQQjULFUI1CxxCNQsiQjULKkI1CzRCNQw9QDMJRT0yBko8MAVROy4CXDguAWg9MAV5PzEJi0s7 + FaBVRSK6ZlQ003poS+eOel/xpI51+7ejjf/Hs5z/0r+o/93Hsf/gyrD/4syy/9/Kr//fyK3/3Maq/9vD + p//ZwaX/2cCk/9e+of/Xvp//172f/9e9nv/XvJ3/17yc/9e7m//Xu5v/17qZ/9u+nf/Hqov/o4Zp/6SH + a/+Wf2f+U0QfnTwuBUxCNQspQjULC0I1CwEAAAAAAAAAAAAAAAAAAAAAAAAAAEI1CwFCNQsFQjULCEI1 + Cw5CNQsWQjULHUI1CyNCNQsqQjULNEI1CzxCNQtFQjULT0E0CFc8LwRbOi0BYj4xB3FCMwyESj0Wm1ZH + IbZjUC/LdmVI4Ip1W/SejHL5tKGK/8Kwmf/Qvqf/3Mmz/97Kt//hzrb/4M61/9/Ls//dybD/3Mas/9rF + qP/Xwqf/18Km/9fCpv/YwaX/2MGl/9jApP/Yv6P/2L+i/9e+n//XvZ7/172e/9e8nP/Xu5z/17ub/9e6 + mv/bvp3/yKuM/6OEaf+fhGX/p4pw/4JtUeRBMghcPzMHK0M2Cw4AAAAAAAAAAAAAAAAAAAAAAAAAAD4y + CQFCNQsHQjULEEI1CyBCNQsuQTUKOkE0CUU/MwhMPjIHVT0wBl47MARnPTAGdD0wBn9GNw+TV0chsGNR + Lsl1YkXfhnJY8ZuHcPuynYj/w7Ga/9DAq//ZyrX/38+6/+LSvP/j0bv/4M64/9zLtP/bybL/2siw/9nG + rv/Zxq3/2sau/93JsP/hy7H/4cuy/+DKsP/gya//3MWo/9nCpv/YwKP/2L+j/9i/ov/Xvp//172e/9e9 + nv/XvJz/17yc/9e7mv/Xupr/3L+d/8yvkf+liGz/n4Rn/6aIa/+YgGT7T0McfDovBClDNgwTQTQLAgAA + AAAAAAAAAAAAAAAAAAA9MgkCQjULEUI1CiY/Mgg8PTAGUzouA2I8LwVwPjAHgUQ2DZJRQByqXEonvnNf + Q9iGcVfymodt/6uZg/+/qpb/zb+q/9vOvP/h07//4tPB/+PUwf/f0b3/3dC7/93OuP/bzLb/2sq0/9rJ + s//aybH/2cew/9nHsP/Zxq7/3suz/+HMs//MuJ3/t52C/6qRcv+tknX/vaaI/9e+o//hya7/3MKl/9i/ + o//Yv6L/176f/9e9n//XvZ7/17yd/9e8nP/Xu5r/17qa/9y/nf/NsJH/pYhs/5+EZ/+lh2n/m4Jo/ltO + KJM5LQIsQjULFEE0CwMAAAAAAAAAAAAAAAAAAAAAPjIJCkE0Cxw+MAU3QjMKa1JAHKFdSyi+bVs904Jv + U+qUg2n4q5mE/76um//Kvav/1su4/97Uwf/i2Mb/59zK/+LVwv/d0L7/2866/9vNuf/azbj/2sy4/9rL + tv/ay7b/2su0/9rKtP/ayrP/2six/9nIsf/ax7D/4c+3/9PAp/+fh2r/gGhK/4dyWv+WhXH/k4Nu/4hx + WP+KcFP/tZt+/93FqP/dxaj/2L+h/9e/of/XvZ//172e/9e8nf/XvJz/17yc/9e6mv/cv57/zrGR/6WI + a/+fhGj/pYdq/5uDZ/5aSyeXOSwCNEI1CxtBNAsFAAAAAAAAAAAAAAAANisHAT0yCQ88MAUhUUAZdIp1 + WuasmYX/u6yX/8y9rf/YzsD/4NjJ/+TdzP/o38//5NzM/+PZx//g1sT/3NLA/9nOvf/bz7z/28+8/9vP + uv/bzrr/2825/9rNuP/azLb/2su2/9rLtf/ayrT/2sqz/9rIsv/Zx7D/4dC5/827n/+GbE7/hnBX/7yy + qP/d3dr/4+Pi/+Lf3f/V0s7/raOU/4JrUf+iiWz/3cSo/97Ep//WvZ//176f/9e9n//XvJ3/17yc/9e8 + m//Xupn/3L+e/9O1lf+ni23/nYJo/6WHaf+chGj/W0wnnjksAjlCNQsdQjUKBQAAAAAAAAAAABYsATYr + BwQ6LgYJPC4HMox5X9Le1sn/6uTX/+nk1f/m4dL/5N7Q/+Hayv/e1sX/3dTD/9zTwf/b0cH/3NLA/9vR + v//b0b7/29C+/9vPvP/bz7v/2866/9vNuf/azbj/2sy3/9rLtv/ay7b/2sq0/9rKs//ZyLL/4M+4/9fG + sP+GblD/i3de/9TOyf/c19P/v7Gi/6mTef+eg2j/qpN+/8GypP+2qJr/gmxT/6mNcf/iyKv/2sCj/9e9 + n//XvZ//17yd/9e8nf/XvJv/17qa/93Anf/Utpb/popu/56CaP+kh2n/noVs/2BQL645LAE7QjULH0M1 + CgUAAAAAAAAAAAAWKwE2KwcEOi0FBj8vBzqhkXng7uve/+bg0f/c1Mb/4dvN/+Dcy//h3Mv/3tjJ/9vT + wv/c1ML/3NLB/9zSwf/b0b//29G//9vRvf/b0L3/28+8/9vPuv/bzbn/2825/9rMt//azLf/2su1/9rL + tf/aybP/28q0/+TUvv+kjnP/gGpQ/8vBtv/Owbn/r5eD/56EZ/+Ze17/k3FT/49uTP+ObEz/o4lv/5aB + Z/97ZUn/w6qM/+PJrP/XvqH/176f/9e9nv/XvJ3/17yc/9e6mv/dwJ//07aW/6eLb/+egmf/pIdp/5+G + a/9gUDCuOCwBPEI1Cx9DNAsGAAAAAAAAAAAAAAAANywHAjovBgQ+LwUvkYFm0+Ld0P/i3c7/4dvM/9XK + uP+wm4L/uKaO/9vSw//g2Mj/3NPC/9zTwf/c0sH/29G//9vRv//b0b3/29C9/9vPvP/bz7r/2825/9vN + uf/azLf/2sy3/9rMtf/ay7X/2cmz/+LRu//Qvaf/gWdL/6qYif/Nw7j/uqmV/7SciP+znYf/o4xy/5N4 + X/+QcVb/k3NW/5R1Vf+Xd1r/hGlN/5yDZv/ewqb/28Kl/9e+n//XvZ7/17yd/9e8nf/Xupr/2r2d/9e5 + mP+sj3L/nYJm/6SGaf+hhmr/YVEurTgsATxCNQsfQTQLBgAAAAAAAAAAAAAAADcsBwE6LwcGPC8EJINw + VL/d18j/5uHT/+Le0P+1oYf/x7mt/6+Zhf/Ds5z/5t/O/9zTwv/c08H/3NLB/9vSwP/b0b//29G+/9vQ + vf/b0Lz/2867/9vOuv/bzbn/2sy4/9rMt//azLb/2su1/9rKtP/o1sD/sZuB/4VtUf+/sKH/y72x/8O1 + pf/Ar5z/pY13/4NoUP9+YUn/gGJL/4RmTf+RclT/mXpd/5BxU/+LcVX/yrOV/9/GqP/XvqH/172e/9e9 + nv/XvJ3/17qb/9u9nf/Wu5n/rJBy/56CZ/+jhmn/oohs/2ZWNLY3LAA7QjULHkE0CwYAAAAAAAAAAAAA + AAA6LwgBPDAIBTcoABZtXjym1s+//+fh0//k39P/tZ+H/9jQyf+8q5n/uqeN/+Tg0f/c1MP/3NPC/9zT + wf/b0sD/29G//9vRv//b0L3/29C8/9vOu//bzrr/2825/9rNuP/azLf/2sy3/9rLtP/czLb/4tG7/52G + af+PeF//yLqt/9PJv//NwLP/tJ+N/4BjTP94WkP/iG9Y/7Cllv+1q5//kHhe/5FyVf+YeFz/iW1R/7mi + hP/hx6r/2L+i/9e9nv/XvZ7/17yc/9e7nP/bvp3/1rqZ/62Pcv+egmf/o4Zp/6KHbf9nVjW1NysAO0I1 + Cx5BNAsGAAAAAAAAAAAAAAAAAAAAADwxCAU2KQAOYFAukM/Etv/n4dP/6ObX/7yqk//Kva//wbKk/7Sd + hf/j3s//3NTE/9zTwv/c08H/29LA/9vRv//b0b//29C9/9vQvP/bz7v/2866/9vOuv/azbj/2sy3/9rM + t//ayrT/3s64/9/Ot/+VfmH/k3xl/9LKv//Z0s3/z8S4/5uDb/93WkD/e2FG/6ubjf/W083/4+Lf/8G3 + r/+LblH/l3dY/4dpT/+vlXv/4Meq/9nAov/XvZ//172e/9e9nv/Xu5v/2b2c/9q8nf+ylXf/noNn/6KG + af+liW7/aFg2tzcrADtCNQseQTQLBgAAAAAAAAAAAAAAAAAAAAA8MQgEOCwAClxIJXrFuan/6eLW/+Tj + 1P/Et57/wK+h/8e6rf+slXv/39fI/97Xx//c08L/3NPC/9zSwP/b0sD/29G+/9vQvv/b0L3/28+7/9vO + uv/bzrr/2s24/9rNuP/azLb/2sq1/97OuP/fzrf/lHxh/5N7Yf/Z0sr/4NrV/87Ctv+MdF3/eFlB/4Rq + UP+9tav/4uDb//b49f/j4N7/lXpi/5FvUf+KbFH/sph8/+DHqv/ZwKL/176f/9e9nv/XvZ7/17yd/9m+ + nf/avZz/sZZ3/56EZ/+jhWn/pIht/3ZjRcQ+MQdBQTQJG0E0CwYAAAAAAAAAAAAAAAAAAAAAPjIJAzot + AwZRPhtmuayZ9+nj2P/j4NL/yr+q/7ijkP/Kv7L/qJF1/9rSwP/h28v/3NLC/9zTwv/c0sD/29LA/9vR + v//b0L7/29C9/9vPu//bzrv/2866/9vNuf/azbj/2sy3/9rKtf/ezrn/38+4/5V8Yv+PeFz/2dLK/+Tc + 1//Mw7f/jXNb/3ZYP/+Ea1P/vrit/+bi3v/6+fn/6efj/5qEbf+QblD/iWxR/7CYe//gx6r/2cCj/9e+ + n//XvZ//172d/9e8nP/Zvp3/2byc/7KWeP+eg2j/o4Vp/6OIbf93ZEbEPTAGQUAzCBxBNAsGAAAAAAAA + AAAAAAAAAAAAAD4yCQQ6MAMDRjQMUKmahuzp5tn/5N/R/9TNu/+xm4X/yLyw/6ePdP/Uyrj/4t3N/9vS + wv/c08L/3NLB/9zSwP/b0sD/29G+/9vQvf/b0Lz/2867/9vOuv/bzbn/2s24/9rMuP/azLX/3My2/+TV + v/+iim//hWpN/9HHvP/i2tb/0MO5/5J5ZP92WUD/gWVL/7GmmP/W0s7/4uDc/9bTzP+TeWH/kW9R/4xv + U/+4noH/4Mir/9rAo//Xvp//172f/9e8nf/XvJ3/2Lyc/93Anv+2mnz/n4Rm/6OGaf+mim7/eWVIxzsw + BkVBNAkdQTQLB0AzCwEAAAAAAAAAAAAAAAA/MwoDPTAFAT0vBD2ZinHg5+TX/+Tf0//c1cX/spyG/8W3 + qv+pkHj/y76q/+Tf0P/b1MP/3NPC/9zSwf/c0sH/3NK//9vRv//b0b7/28+8/9vPu//bzrv/2825/9vN + uf/azbf/2sy3/9nLtP/m18P/uaSO/3peQf+6qJX/29TP/9DFuf+plIH/d1tC/3teQ/+Sfmn/wLux/87M + x/+snpL/jW9T/5NzVv+Rc1j/x66T/9/Hq//Yv6L/176h/9e+n//XvJ//17yd/9i8nP/dwZ7/uZl+/56D + Zv+ihmn/pols/4BqT9dBMwtQPzMIIEE1CwsAAAAAAAAAAAAAAAAAAAAAPzMKAT4xBwE9LwUtjXth0uTg + 0//o5Nf/4NrL/7ejjf/Cs6T/q5N8/8Oym//n3s//3dXE/9zUw//c08H/3NLB/9zSv//b0b//29G+/9vP + vP/bz7v/2867/9vNuf/bzbn/2s23/9rMt//ay7X/4NC8/9bFsP+GbFH/lHhg/9HGu//Mv7L/wK+c/5J3 + Yv94XEP/emBG/413ZP+WhHP/jG5X/5d2Wf+Ob1T/nIJm/9nBpv/exan/2L+i/9e+of/Xvp//176f/9e8 + nf/YvZ3/27+f/7eaf/+fg2f/oodp/6WIbP+Aa1DbQjIKWD8zCCZBNAsOAAAAAAAAAAAAAAAAAAAAAEAz + CgI/MggEPS0FIoFuUr7h287/6efY/+Pf0f+8rJb/v66c/6+Xgv+7q5P/5t/R/93Wxf/c1MP/3NPC/9zS + wf/c0sD/29G//9vRvv/b0L3/28+8/9vPu//bzrr/2825/9vNuf/azLf/2sy2/9vLtv/n1sD/sZyC/3le + Qf+sln//x7qq/7+tmv+wmYX/lXtk/4drU/+EZUv/iWtO/5R2WP+Udln/im1R/72miv/jy6//2cCk/9i/ + o//YvqH/176h/9e+nv/XvZ7/17yc/97DpP+8n4P/noNn/6KGaf+miWv/gmxR3EEzCl4/MwgrQTQLDgAA + AAAAAAAAAAAAAAAAAAA/MwoCQDQKBTgpABJtWzul2NLC/+vn2v/n5Nf/xbah/7qok/+0noj/t6SM/+Tc + 0P/e1sb/3NTD/9zTwv/c08H/3NPC/93Twf/b0L7/29C9/9vPvP/bz7v/2866/9vNuf/bzbn/2sy3/9rM + tv/ay7X/4NC6/97Otv+UfmL/e2BE/6iSev+7ppT/sZqG/6iOdP+bgGL/l3lb/5h6XP+XeFn/iGhM/6OK + bf/fx6z/28So/9jAo//Yv6P/2L6h/9e+of/Xvp7/172e/9e8nf/fw6X/vaGD/56DZ/+ihWn/pYht/4hy + VexDNgxlPzIHK0E0Cw8AAAAAAAAAAAAAAAAAAAAAAAAAAEE0DAU2KQAJYFAsk8/Etv/s6t7/6OTY/83B + sP+4ppH/taOO/7Shif/h2cv/39jH/9zUw//c08L/3NPC/97Swf/e1cL/4NbF/93Sv//c0L3/28+8/9vO + uv/bzrr/2825/9rMt//azLf/2su1/9rKtP/gz7v/1cOs/5F7YP96YET/k3pf/6SKcf+fhGf/lnlc/5R2 + Wf+QcFX/hGhM/5uEZ//Xwab/38is/9fApP/YwKP/2L+j/9i/ov/XvqH/176h/9e9nv/XvJ3/38Oj/76i + hP+eg2f/ooVp/6WIbf+Ic1bsQzUMZz8yBytBNAsPAAAAAAAAAAAAAAAAAAAAAAAAAABBNAoFOCsABlpH + JH/FuKn/7evh/+rn2v/Tyrv/uaSR/7ilkv+ym4b/3NfG/+Hdzf/c1MP/3tTD/9/Vxf/ArZb/s52E/8/B + rv/e0b//4NbD/97TwP/cz7v/2866/9vNuP/azbj/2sy3/9rMtf/ayrT/2smz/+HQuf/aybH/qpR6/4Vt + Uv+AZ0z/g2hN/4RnTP+Eak7/jHNZ/6+YfP/axqv/3ces/9fBpv/YwaX/2MCk/9jAo//Yv6L/2L6h/9e+ + of/XvZ7/17yd/93Co//Cpoj/ooVq/6KFaP+miW3/i3NY7UE1DGc/MgcrQTQLDwAAAAAAAAAAAAAAAAAA + AAAAAAAAQTQKAzouAwNRPhhnua2b9u3t4P/p6Nz/3NTI/7mmkv+5ppT/sJiB/9nTwv/k39D/3dXF/97V + xP/f1sX/tqGI/5h7YP+jinD/s56G/8q6pf/bzbr/4tXC/+HUwf/d0b3/2s65/9rMtv/ay7b/2cq1/9rK + tP/XyLL/4M64/+TTvP/Swqn/uKSK/6uUef+slnr/uqWK/9O+pP/hzrX/3cat/9fCp//Ywqb/2cKl/9nB + pf/awaT/2sGj/9rBpP/awKH/2b+h/9m+nv/gxaT/xaiK/6KFav+ihmn/pols/452XfJCNw5tPjIGKUE0 + Cw8AAAAAAAAAAAAAAAAAAAAAAAAAAEI0CwQAAAAARDQKSqmchuzt6t7/6und/+Le0f++q5f/u6eU/7CZ + g//WzLv/5uHT/+DYyf/e1cX/4dnI/8Gvl/+hhWr/p41y/6GJbv+jiW7/sJiA/8OynP/VxbH/39C8/+DV + wP/e077/39C8/+DQuv/dzbf/3cu1/9zKtP/dzLT/4dC6/+bUvv/p1r3/6tS9/+jSu//izLP/3ciu/9vG + q//cx6z/3caq/93GqP/cxKf/2cKl/9i/o//XvqL/1ryd/9K6nv/Rt5r/1b2f/7+mif+jhmr/ooVp/6aJ + bf+PeV7zQjYMbD4yBilBNAsPAAAAAAAAAAAAAAAAAAAAAAAAAABENg0CAAAAADwtBDaZinHi6uba/+3r + 4P/m49b/w7Of/7uplv+xmYb/0ca0/+jh1v/h2cz/4NjI/+Pby//Gt6L/oYdq/6iOc/+okHj/qI91/6SL + cP+ji3D/rJN6/7qkjP/EsZr/zbyl/9TFr//YybT/2su1/97Mtv/dzLb/3Muy/9rJsv/bybH/28mw/9rH + rv/Yxaz/2MSr/9jCqP/Uv6b/z7mh/8q0m//HsZf/w62W/7+rlP+8ppL/uaON/7aeif+ynIn/tZ+O/7em + lP+ym4b/pYdr/6OGaf+nimz/kXpe8kU2D248MAYpQTQLDwAAAAAAAAAAAAAAAAAAAAAAAAAARTYNAj4x + BwI9MAYpjXpg1ufi1//u7eP/6ejd/8e5qv+8qpb/spuG/8y+rv/p5Nj/49zN/+HZyv/k3M3/0sW0/6WL + b/+mjHH/qJB2/6iQd/+pkXn/qJB2/6aOdf+ljXX/p492/6qRef+rlX7/sZqE/7Seif+5pI3/uaWO/7ml + jv+5pI7/uqWN/7qmj/+6pY3/t6KL/7aijP+3oYz/tqON/7Wijv+0n4//sp2L/7CaiP+tmoj/rpmJ/7Gf + kP+5raL/v7Wr/7Ojkf+zoZD/sZmI/6WHbP+jhmn/pods/5V+Y/dTQx98Oy4DJkE0CxAAAAAAAAAAAAAA + AAAAAAAAAAAAAEM1DQE+MggFPDAGG4BsUMLg3M//7+3k/+3s4//QwrT/vaqW/7OdiP/Iuaj/6OTY/+be + 0P/h28z/49vN/97Vxf+tln7/o4hs/6iPd/+okHf/qZF4/6mReP+pkHf/qIls/6aMb/+qkXn/qZF6/6qQ + ef+pkXr/qpJ7/6qSe/+rk3z/qpN+/6uUf/+rlYH/rJWB/6yWgv+vmYb/r5mF/6mSfP+jinP/n4dv/5uF + bv+hiXP/ppKB/7Gjk/+8sab/ycfC/9PRz/++saT/tJ6M/7Kbh/+lh2z/o4Zp/6eKbP+XgGP2UkYhfTsu + AiZCNQwQAAAAAAAAAAAAAAAAAAAAAAAAAABCNQsBQTUKCDYpAAxtWzus2M/D//Hu5//u7OP/1s3A/7+t + mv+3o4//w7Oi/+bi1//n4NP/49zO/+Tcz//j3c7/v6yX/6SJb/+oj3T/qJB2/6mReP+pjnP/qZJ8/7S0 + rv+2q57/qo91/6uSev+slH7/rZV//7CTd/+wkHf/rZR+/7CTeP+xlnv/r5mD/7CZhP+xnYj/rZaA/4ps + UP+DZUj/hmhM/4psUv+OdFv/knpj/5F7Zf+OeWP/hnFY/52Oe//Pzcv/xLat/7Kei/+xm4f/pohs/6OH + af+niG3/mIBk91FEIH47LgMpQzUMEjwwCgEAAAAAAAAAAAAAAAAAAAAAAAAAAEQ3DQc0KAAFYE4rlM3D + tP/y8en/7+3k/93Xyv/BsJ7/uqaT/8Cum//m4dT/6OLV/+Tez//k3c//59/S/82/sP+tk3v/qpJ3/6eP + df+pkHf/p4xx/67Byv/e/f//8f39/7u0q/+liW//rJR7/7GSd/+ol4f/l7bB/5fG3v+ZuML/q5qL/7KV + ef+vmYP/tJ2J/6aNdf9/XT//g2NH/4ZpTf+DalH/gGlP/4JpUP+Lc1v/not2/66ejP+HcFb/r6eZ/8rA + uP+ynYv/sZmG/6aIbP+jh2n/pohs/5qCZ/xaTCeTOSwCLEM2DBU8MAoCAAAAAAAAAAAAAAAAAAAAAAAA + AABDNQwFNysABFtHJHvCtqb99PPr/+7v5v/k3tP/xLKf/7yplP+5p5T/5N/S/+rn2v/m4NL/5t7R/+jh + 0//a0L//tp+J/7GZg/+rk3r/qI1y/6eQd/+q1PP/0vD//+j9//+/0tj/p493/6+Nbv+slYL/hMLh/5Xh + //+y6P//m+T//4fE5/+omYz/tJR5/7Gch/+ul4L/g2NG/4RlSP+AZkr/iG9W/6mTfP/Gtqj/3tTK//bz + 7///////qZqG/5mLef/Nxb7/sp2L/7GZhv+miGz/o4dp/6aIbP+cg2j8W0wolTksAjBDNgwYPDAKBAAA + AAAAAAAAAAAAAAAAAAAAAAAAQjYMBTouBAVQPRhgt6yX9fLy6//w7ub/6ufe/8W3pf+3oo//wbKh/+fi + 2P/r5tr/5uDU/+be0//o39P/49zN/76tmP+ym4f/tp+K/6ySe/+ojnD/osTa/6vo//+v6///q8LP/6yO + c/+0jGf/jam1/3XT//+m3P//web+/67f//941f//iK/D/7SUeP+ymYL/r5uH/4hpTP+DY0T/f2JH/5B2 + Xf/AqpX/1Mi7/+ne1//59fH//////7epmf+QgGz/zMW//7Ohjf+vl4P/pYhs/6OHaf+mh2z/nIRp/V1M + Kpc5LAEvQzYNGDwwCgQAAAAAAAAAAAAAAAAAAAAAAAAAAEI1CwQ8MQYFQTMJRqmahO/x7uf/8e/o/+/t + 4//f2M3/08i7/+Td0//s6d7/6eTZ/+fi1f/n4dT/6OLU/+jh1f/Lva3/s5uH/7ajj/+1ooz/rpR5/6ib + jP+fxtz/nsXa/6ecj/+ujnD/s49w/3euyP9qzP//j9L//5zW/v+V1P7/bc3//3Cz3P+ul4L/tZiA/7Gc + iP+Pclf/gGBD/4BkSv+JcVb/uKKK/82+sP/Xy8H/3NTN/9jQyP+XhW3/lodz/8/Iwv+3o5D/rpWA/6WH + av+jh2r/pYdr/52GbP9jUzGhOCsAJ0M2DRQ8MAoCAAAAAAAAAAAAAAAAAAAAAAAAAABCNQsDPjIHBDos + AzOaiXHl7+vh//Ly7P/v7eT/8fDp//Py6//w7eT/6+fd/+rm2//p5Nj/6ePX/+nh1f/r5tn/2c+//7il + j/+3o47/uKSQ/7ahjv+ylXn/rJF3/6mPdv+rjnH/rZN8/7mPbv9yp8P/UML//2/H//93yf7/c8f+/1PD + //9frt3/rpeD/7SYf/+znov/l3xj/39dP/+DZ0z/gmpR/5R+Zv+Yg2z/jnlj/4ZwVv+BalH/indh/7+6 + tP/Kwrr/taKP/6ySef+kiGr/o4dq/6WHa/+eg2r9Xk8sijgsAR1DNg0QAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAQjULAT8zCAM9LQUnjnph0urn2//08+3/7+3n/+/s5v/u6+P/7uvf/+zo3//r6N7/6uba/+rk + 2f/o4tb/6uTX/+be0P/Csp//uaOQ/7qnk/+5pZH/uKOQ/7Wbg/+vknf/qZN5/6qTfP+3kG7/kZma/zO1 + //9Fuv//Wrz//066//8ot///aaPE/7mVeP+zmYL/tJ+M/5yCav96WTr/gmRG/4BkSf97YUb/f2dN/4hx + Wf+TgGr/pZKD/7iqnP/Cta3/uaiY/7Gahf+njG//pYhs/6SIbP+oi27/lnxj9Es+Flw7LwUWQTULCwAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEI1CwFANAkGPCwDHH9rT7rj4NP/9fTw//Hv6f/v7ef/7+3m/+3r + 4v/u6uH/7Ojf/+zo3P/q5tv/6uTY/+ni1//s59r/0sW1/7qmk/+9q5b/u6eT/7qmkv+4pJP/tqKO/7Kc + hv+vmIH/rpR6/7WScv9qnr3/Iav//x2v//8Vrf//QKTf/6aYiv+6mHn/sJmF/7GdiP+rknv/iGlN/4hq + T/+XfGD/nYZu/6iSfv+ynYn/taOR/7illf+3pJH/spyJ/66Uf/+ojHH/popt/6WJbf+liWz/qIxw/35q + Tcc8MQUpQDMIEEE0CwUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQjUMBjYpAAxsWjmg2dPG//b3 + 8f/y8Or/8e/p//Du5//w7OT/7uvj/+3q4P/s6d//7Ofe/+rm2v/q49f/7ejc/+HZzP/BsJ3/vqyY/76s + mf+9q5f/u6eT/7mmkf+4pI//tp+L/7GbiP+xmH7/tJN3/4iWnP9gm7r/cpmw/6qWhv+4l3n/r5iD/7CZ + hf+wmoX/spyJ/7Cah/+wnIb/s5+L/7Whjv+1oY3/s56K/7GZhP+vl4H/rJN5/6mOcv+nim//p4tv/6aK + b/+miW3/qItw/5iBaPpTRiBhOS0CDEM2DAtBNAsBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEI1 + DAY2KQAGYE8sj8/Ht//4+PP/8vHr//Hw6f/x7uj/7+3m/+/s5P/u6+L/7Ong/+zo3//s59v/6uTY/+vj + 2P/s59r/0MSz/76smP/Ar5z/v66a/76rl/+8qZT/uqeR/7mkkP+3o4//taGO/7Sdhv+6mXv/vZd2/7qW + dv+0l3v/rpiD/66YhP+wmYX/sJqF/7Cahv+znIf/s5uH/7KahP+wl4D/r5N7/66Tef+tkXf/rJB0/6uP + dP+qjnL/qY5y/6iNcf+pjHD/qYxx/56GbP9oWTeIOi0CDkE0Cg1CNQsDAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABCNQsEAAAAAFpJJXjFuqv+9/fy//Tz7v/z8ez/8fDr//Hu6P/w7eb/7+zk/+3q + 4f/t6eD/7Oje/+rm2v/p49f/7Oba/+Pc0P/HuKn/v6+b/8Cwnf/AsJ3/vq6a/7uqlf+5pZH/t6KP/7Se + i/+wnIj/sJqH/6+ahP+vmYT/sZqE/7Obhv+zm4b/tZyG/7Sbhf+0m4T/s5qD/7OYgf+ylX//sZd//7CW + fv+wlHv/r5N6/7GTfP+vknr/r5J4/62ReP+qjnT/oolw/495YORhUS5uPTEHDkAzCQtCNQsFAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQjULBAAAAABQPhpau6+a/ff07//49/P/9fTv//Xy + 7f/z8e3/8vHr//Lw6//v7+f/8O7m/+7r4//t6N//6OPY/+Le0f/j3tH/19DB/8Kzof+5ppP/t6OO/7Se + if+znIj/s5uH/7Obhf+znof/t5+K/7ehiv+4oYv/uqKM/7qhi/+5oov/uaGK/7ifiP+4nYb/t5yF/7Wd + hf+2nIf/t5yF/7Wbg/+0moP/tZmC/7CVfv+skXj/qI11/5iCafOIdVnffmhNvGRUMnlJPRQqAAAAAEAz + CQVCNQsEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEI1CwMAAAAARTULLKmZ + g/Lv7uP/9PTw//X18f/29PD/8/Lt//Ly6//v7OT/6OTc/+Hd0f/Uzb3/xrur/72xnv+3qpb/sqSP/7eo + lP+4qJT/tqGK/7Wfif+7pY7/vqiS/7+qlP++qpT/wKqU/8CqlP+/qpT/wamS/76nkf+/pY//vqaP/76m + jv+7o4z/u6GM/7qhi/+0nIX/sZeD/6uSfP+kjXf6lYJn6oVwVdh/a066bl4+ll5QK3lgUC5QX04rJkQ3 + DgUAAAAAAAAAAEI1CwRCNQsCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABCNQsBQDMJAzwvBQNvXD2Rxrmp/+fh1f/o4dT/3dXJ/9rRwv/Zzr3/1ca2/8y8rP+5ppP/p5J6/6KP + eP+hjHX/nIZu/5R7Yv+XfGP/o411/7Wfi//ArJf/xrKd/8iznf/Hs53/xrGb/8axnP/ErZj/wqyX/8Gp + k/+8pZD/t5+K/7Oahv+tloD/pY54/JaBaemKdlzShHFVu3BeP5xdTCh5X00rXEo7FDtXSiUlXU4qDwAA + AAAAAAAAAAAAAAAAAAAAAAAAQDMJA0E0DAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEI1CwM+MwgCOi4ECmlVNYGsl4P318Sz/9nJuP/Qv63/zLmm/8m3 + pP+/q5X/v66d/+HZ1f/g2dH/ybqr/7CZg/+bfmL/knBS/6GIbv+5pI//wayX/8axnv/Fr5v/wKqU/7ij + jv+xm4f/qZN+/56JcfiPemHmiHRbyHxqTKRlUzKHW0sobVtLJ1FLPRUyQTMKHkI2CxE+MQYBAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAD4yBwE/MggCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQjULAgAAAAAAAAAAUUAbS496 + YNHItaX/2sm6/9rIt//UxLP/x7We/9zQxP//////9/Ty/9PGuP+0non/nYBj/5Z1Vf+Tel//k39q/5eB + a/SRe2Lhi3RcyoFqUK1nVzaPXU4ocltMKFZQQR04QDQKIUE1Cxc/MggJAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAQDMIAUAzCAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABCNQsBPjEHAQAAAABmVDMVbVs8l6iSfv69qJT/wK6Z/62Zgv/LwLT//////+HXzP/CsZ7/rZR6/5t8 + YP+cfFz/i3FX/1lHKnBSQiBAQzUMIjsuBRNbSicHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAEA0CQFCNQsBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+MQcBAAAAAAAAAABMPBgsalg2bGxbOpJhTi2GlYVvx9nM + xf/Huan/t6SQ/6mQePuUfF70jHNX3nplSoNOPBwHSzoXAQAAAAAAAAAAAAAAAEE0CgFBNAsBAAAAAEE0 + CgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD8yCgE5LwUCAAAAAAAA + AAAAAAAAAAAAAFhFJBx6ZUtjeWVKdnhkSXJ0XkVYgGlQO21ZPhYAAAAAVUIiAU8/HgEAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAADkuBwEzKQQCMikFAzouCwQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP// + ///////////////////////////P/////////8//////////B////////8AD///////wAAD//////YAA + AH/////0AAAAP////oAAAAAf///QAAAAAA///AAAAAAAD/8AAAAAAAAH8AAAAAAAAAfAAAAAAAAAD4AA + AAAAAAAHgAAAAAAAAAeAAAAAAAAABwAAAAAAAAAGAAAAAAAAAAYAAAAAAAAABwAAAAAAAAAHAAAAAAAA + AAcAAAAAAAAAB4AAAAAAAAAHgAAAAAAAAAeAAAAAAAAAB4AAAAAAAAADgAAAAAAAAAeAAAAAAAAAB4AA + AAAAAAAHgAAAAAAAAAfAAAAAAAAAB8AAAAAAAAAHwAAAAAAAAAfQAAAAAAAAB9AAAAAAAAAHwAAAAAAA + AAfAAAAAAAAAB8AAAAAAAAAD4AAAAAAAAAPgAAAAAAAAA+AAAAAAAAAD4AAAAAAAAAPgAAAAAAAAB+AA + AAAAAAAH4AAAAAAAAAfwAAAAAAAAB/AAAAAAAAAP9AAAAAAAAB/0AAAAAAABP/QAAAAAAAZ/8AAAAAAA + +f/4AAAAAB/P//2AAAAP+f///kAAB/5/////sAA5f//////PAT////////D///////////////////// + ////////////////////////////////////////KAAAADAAAABgAAAAAQAgAAAAAACAJQAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA2KwgBOC4IAQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAA9MgoBPTIKAkAzCwEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABCNQsBQjULBEI1CwdCNQsLQjULEkI1CxpDNQshQjULH0I1CxNCNAsHAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEI1 + CwNCNQsHQjULDEI1CxFCNQsZQTUKIUAzCSo/Mgc1Oy8EPjkuAkw4KwBWOCwBUUA0CD5CNQshQjULCAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCNQsBQjULBUI1 + CwpDNQsQQjULGEI1CyJBNAkpPzIHMjwvBDw4LgFJNioAVjcqAGk8MAaARjcRmFdIJbVtXD3OXEwsvDkt + AnY9MAZIQjULIkI1CwgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQjULA0I1CwVCNQsJQzUMD0M2 + DBdCNQsgQTQKJz8zCC48MQU6OS0CRzcrAFc2KQBoOy0FfUQ1EJVVRSGzZ1Q2zYJtUeOahWnytZqB/8es + kP/bvaD/1Lab/3xnS942KwF8PTIFSEI1CyFCNQsHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCNQsEQjULCEI1Cw1CNQsVQjULHkI0 + CydBMwkwPDAEODksAkM2KgBQNSkAYTkrAndAMguRTT4arWJRMst7aEvjmINn9q+ZgP3FrZT/2L6j/+DF + qf/lyKv/5Mam/+LDov/cv5z/6cin/8mqkf9xXkLeNy0AdD0yBkJCNQsYQjULAQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQjULAkI1CwdCNQsMQjUME0Q2DBtBNQojQDMILD4x + BjY6LgNENyoAUTUoAF81KAB0PjEJjUo7FaZgTy3HdWNH3JB+YvKrln3/w62V/9O+pf/gx6//5cyw/+bN + r//kyq3/4Mao/9rAov/Zvp//17yc/9e7m//Vupn/3L+e/8WmiP+kiXD/b14/1zktAWRBNQouQjULCAAA + AAAAAAAAAAAAAAAAAAAAAAAAQjULAUI1CwJCNQsHQjULDUI1CxNCNQsbQjULJEI1Cy9CNQo5PTAEQTks + AUo3LABaOC0Cbj4xBYhJOhSkW0omwnJhQdeMel7uppN7/r+qlP/RvKf/3sqz/+TQuf/m0Lf/486x/97J + rv/bxar/2MOl/9fBpf/Yv6P/176g/9e9n//XvZ7/17yc/9e7nP/Xupr/3L+e/8CihP+ggmX/p4xz/2FP + L7A6LAI3QjYLDwAAAAAAAAAAAAAAAAAAAABANAoBQjULC0I1CxpANAkpPzIHNzsvBEE5LQJONisAXTcr + AG48LQOBSjoTnlpII7twXj/Xh3Vb7aSRePq8qpT/z7+p/9zMuP/l1L7/5tS//+TTvf/gz7j/3cqx/93J + sf/gzLT/4cyx/9/Ir//fybD/4cqu/9vEp//Yv6P/2L+i/9e+n//XvZ7/17yd/9e8m//Xupr/3cCf/8Sm + if+cgGT/qoxw/4t0V+k7MgZFQDMIDgAAAAAAAAAAAAAAAAAAAABANAoJQDMIHzgrAEA3KgBnOiwCgUM1 + DJtURB+1aVc4zIRyWOefjXT+t6aR/867qf/bzrz/5dbF/+fYxv/l18P/4dS//+DSvP/czbf/28q0/9rI + sf/Xxa7/3Mm0/+PQuf/GsJP/pYpu/52DZP+jiWv/vqSG/+DHq//fxan/17+h/9e+n//XvZ//17yd/9e8 + nP/Xupr/3cCf/8apiv+dgWX/p4ls/5N8X/RCNw9ZPC8FEEM1CwEAAAAAAAAAADgsBwE+MggRPzAFRGRP + LreDcVXinIpy8rWmk//Lvav/3NDB/+PZyf/n3sz/5d3M/+Tayf/e0r//28+7/9vNuf/azbj/2su2/9rL + tf/ay7T/2sqz/9nHsf/dy7X/4c+2/6GIa/+HcFf/rKKW/8K9t/+4sKb/lINw/5h+Yv/Xv6L/38ir/9e+ + n//Xvp7/17yd/9e8nP/Xu5v/3cCf/8mrjP+dgmb/p4pt/5F7XfRCNA1hPC8FGEs6BwIAAAAAABMwATcs + BwE0KAAPc2BCqd3SxP/r49T/7OXY/+3p3f/o49P/5NzL/+DXxv/e08P/29G//9jPvf/bz7z/28+7/9vO + uv/bzbn/2sy3/9rLtv/ay7X/2smz/9vJtP/m1b//nYZn/4l2Xv/Vz8z/08zE/7uplP+3pJL/wbWo/5qK + ef+Tel//38Om/9vDpf/XvZ//17ye/9e8nf/Xu5r/38Gf/8uujv+dgWb/pols/5R+Y/lEOBBtPC8EGEw6 + BwIAAAAAABMvAQAAAAAzIwAPj39jxvbz6P/k3s//4dvM/9XNuf/d1sX/3NXG/9vTv//c0sH/29HA/9vR + vv/b0b3/28+8/9vOuv/bzbn/2sy4/9rMtv/ay7X/2siy/+XVwP/Crpb/gWpS/83Duv/Cr6L/pIlt/5d5 + W/+Oa0r/knFQ/6OJbv9+Z03/rJN2/+bLrv/XvqD/172e/9e8nf/Xu5v/3sGg/8yvj/+dgmb/pols/5d/ + ZPpEOBFwOy8EGUg3CQMAAAAAAAAAAAAAAAAzJwAHe2lKrOXf0v/m49X/yr2n/7CahP+8qpX/49vK/93V + w//c08H/29LA/9vRv//b0b7/29C8/9vOu//bzrr/2sy4/9rMt//azLX/2823/+XTvv+Xf2P/pZKA/83A + tP+8qpX/tJ2J/5J5YP+DZUz/hWNI/5RzU/+RcVT/jXNX/9i/ov/bxKb/172e/9e9nv/Xu5z/3L+f/8+y + kv+ghGj/pYZq/5qCZPxGOhFyOi8EGEI0DAMAAAAAAAAAADovCQEAAAAAY1Qxjt7YyP/s6dz/v62X/83A + uP+ynob/3NXD/97XyP/c08H/29LA/9vRv//b0b7/29C8/9vOu//bzrr/2s24/9rMt//ay7X/4NG7/9fE + rP+JcFP/uqqa/9bLwf/Gt6j/jnNd/3JTO/+Uf2z/q5yP/490Wv+Vdlj/iWxQ/8Osjv/hyKv/1r2e/9e9 + nf/Xu5z/3cCg/8+ykv+hhGj/o4Zr/5uCZ/1HOxNzOi4DF0I1DAMAAAAAAAAAAAAAAAAAAAAAVEQfctXL + vv/v7uD/x7mk/8i6rv+1oI3/1827/+DYyf/c08H/29LA/9vRv//b0b7/29C8/9vPu//bzrr/2s24/9rM + t//ay7X/4tK8/9C9pP+HbVD/yLyx/+Le2f+2o5T/c1Q7/4FnT//Jwrr/7/Lx/7qupP+Ma0v/iWlP/7qf + hf/iyav/172f/9e9nv/XvJ3/3L+e/9S1lv+jh2v/o4Zq/5+Eaf5LPhd3Oi4DF0I1DAMAAAAAAAAAAAAA + AAAAAAAATTsVWsu+r//u7OH/y8Gr/8CwoP+2o4//zsKu/+Lczf/c08L/3NLB/9vSwP/b0L//29C9/9vP + u//bzrv/2825/9rNuP/ay7b/4tK9/8+9pf+EaU3/zcO3/+rm4v+qmof/cVA1/414Yf/Z1dD//////9zX + 0v+MblD/iGdL/7ujhv/iyaz/176f/9e9nv/XvJ3/3MCg/9S2lv+jiGv/ooVq/6GHbP9WSCOAOy0AFUE0 + CwIAAAAAAAAAAD4yCQEAAAAAPy8GQrqtnPfv7eH/1Mu5/7mmlf+1o4//ybuk/+Pfz//b0sL/3NLB/9zS + wP/b0r//29C9/9vPvP/bzrv/2825/9rNuP/azLb/4NG8/9jHsP+DZ0n/wran/+vl4v+wno7/cFE3/4Zv + Vf/OyMH/8fHy/87Iv/+MbE//iWpN/76mif/iyaz/176f/9e9nv/XvJ3/2r6e/9e6mP+lim7/o4Zp/6OJ + bf9VRiODOi4BFkE0CwQAAAAAAAAAAD8zCgEAAAAANykAK6ebhOnw7eL/3dXG/7mlkv+1oY7/wK+Y/+bg + 0P/b08L/3NLB/9zSwP/c0r//29G+/9vPvP/bz7v/2826/9vNuP/azLf/3M63/+TVwv+SeF7/oYl0/+Hc + 1v/DtKX/gGVM/3RWO/+hlIP/xcK9/6CMe/+ObE7/kHFW/8+3nP/exqr/176g/9e9n//XvJ7/2r6e/9i7 + mf+niW//oYVo/6WIbv9dTCqWOC4BF0E0CwYAAAAAAAAAAAAAAAAAAAAAOCgAHZuKctjx7+L/4t/Q/72r + l/+0oI3/uaaO/+bf0P/c1cT/3NPC/9zSwf/c0r//29G+/9vQvf/bz7z/2866/9vNuf/bzbj/2su1/+bW + w/+/rJP/fWFF/8Ozo//NwLD/qpJ+/4FkTP99YUn/iG5X/5BxVf+ObVH/oolu/+LKrv/awaT/2L6i/9e+ + oP/Xvp7/2r+e/9i8nv+ojHH/oYZn/6WIbv9eTCqdOSwBH0E0CwgAAAAAAAAAAAAAAAAAAAAANCQAC4R1 + WL3u693/6ubZ/8Kznf+1oIr/tqOL/+Pcz//d1cT/3NPC/9zTwf/g1sX/3dPB/9vQvf/bz7z/2866/9vN + uf/bzbj/2sy2/93Nt//m1r//mIFl/4FmTP+4pZH/u6SS/6aMcv+VeFn/lHVV/45vUP+LblL/0Lmd/+DK + rP/Yv6P/2L6i/9e+oP/Xvp7/2b6f/9u/of+pj3L/n4Jn/6eLcP9iUS2qOCwAIUE0CwkAAAAAAAAAAAAA + AABANQsBAAAAAHJhQqjo49j/7uzh/8m8qv+0oYz/tKCK/+DZy//e1sb/3dPD/9zSwf/Xyrb/39XE/+LY + xv/d0r//2866/9rNuf/bzLj/2sy3/9nKtP/fz7r/3sy2/5V+Y/9+Y0f/lHth/5Z5XP+Nb1L/h2dM/4pw + U//DrpH/5Myy/9jBpP/Yv6P/2L+i/9e+of/XvqD/2b6f/9y/oP+skHP/n4Jm/6iKcf9jUi+uOCwAIkE0 + CwkAAAAAAAAAAAAAAABBNAoCAAAAAGZUM5Dh3NH/8fLm/9HGt/+2oI7/spuG/9zXxv/g2sz/39bG/9nN + vP+mjHL/r5mB/82+q//e1MH/49fE/+DTv//bzrr/2sy1/9rLtf/YyLL/3s64/+LRuv+6po3/lH9j/4xz + WP+Te1//qJN5/9K9pP/hzLH/18Km/9jBpf/ZwaX/2cCj/9rAov/Zv6H/28Cg/93Cov+wlHf/n4Nm/6mN + cf9kUzOyNywAIkE0CgcAAAAAAAAAAAAAAABCNAsCAAAAAFNDHG7X0MH/8/Xq/9nRxP+5o5D/sZqF/9nS + wf/k3tD/4NfI/93TwP+pj3T/nIBj/6GJbf+wmH//yLah/9vMuP/h1MD/4NXA/+DSvv/g0bv/3cy2/+LQ + uf/p2cL/5dW+/+LOtP/l0Lj/6NO6/+TPtv/bx6v/3car/93GqP/cxKf/2cGl/9i/of/Vu5z/1Lqc/9a9 + n/+vlHf/oINn/6qOc/9mVzS1NysAIUE0CwYAAAAAAAAAAAAAAABENg0BAAAAAEU1DlXJvq7/9/ju/+Db + zf+8q5f/sZmG/9bLuv/n4db/4dnK/+LZyv+ynIP/oohs/6ePd/+kinD/oYlt/6uTe/+7po//xbOb/829 + p//Swq7/18aw/9bFrv/VxKz/2MWt/9nIr//Xw6v/07+n/9G8ov/OuaL/yLSd/8Sul/++qpT/uKOP/7Wf + iv+0nov/sp6N/7akk/+qj3f/pIVn/6uNcv9sWTm5NioAIkA0CggAAAAAAAAAAAAAAAAAAAAAAAAAAEEy + CUG8r533+Pnx/+fj2f/BsJ//sZqF/9DEtP/q5tn/4tnL/+ff0f/ArZj/oIRn/6iPdv+pkXj/qZF6/6WL + cf+hhGb/pIty/6aPeP+qkXv/rJeA/62Ygf+vmIL/rpiD/66ahf+ul4L/sJuG/7Ofi/+umYX/qZSB/6eQ + fP+ok4H/sJ6O/72xqP/LycX/vLCj/7Oejf+rkHr/ooRn/6qNcf92ZETCOC0BHD8yCQgAAAAAAAAAAAAA + AAAAAAAAAAAAADgpACinmoTn+fbw/+3q4f/Huqn/s56J/8u+r//r5tr/493O/+fi1f/SxbP/pIhv/6aN + cf+pkXf/qY1y/6uXg/+1rJ//rJJ5/6qPd/+rk33/sI9z/6uNdP+qkHf/sJB0/62WgP+vmYX/rZeC/45y + WP+Ka1D/i25T/4xzW/+Qd2H/j3pk/459Zv/AvLT/zMO9/7Oei/+rkXn/o4Vn/6uNcv91ZUTCOC0CHUAy + CgcAAAAAAAAAAAAAAAAAAAAAAAAAADIkABWWhWzW9/Xu//Dw5//PxLL/uKKN/8W2pP/s59r/5uDR/+fh + 0//g1sj/s5uF/6iPdf+ojnT/pIpw/7bS3//1////zMvF/6OIb/+xkHP/pZuO/5bF1/+azOD/oaek/7OS + dv+0nYj/qpJ7/3xbPP+CY0f/gmhO/4dvVv+Te2b/r56M/66fi/+Tg23/x8C4/7Wfjv+rkHn/pIVn/6qN + cv98akrTOS0DJT8zCQoAAAAAAAAAAAAAAAAAAAAAAAAAADQmAAyHdVq98/Lq//T17f/Vy7v/spyG/8Gx + of/t6d7/5+LV/+ff0//o4dL/wa+a/6+Yg/+tk3r/pIxx/6nX9f/L/v//u9vn/62Ka/+sj3f/fsbq/6fp + //+67f//gtf//52fnP+2lXn/r5qH/4VlSP9/YUT/iG9V/76qlv/j18///////////f+XhXH/vLOq/7ek + kv+rkHj/ooVn/6uNcv9+akzTOS0DJj8zCgsAAAAAAAAAAAAAAAAAAAAAAAAAADImAAJwYUCk7+ri//b2 + 8P/l4NX/zcCx/9/Yzf/s6d7/5+LV/+fg1P/r5tn/z8Ky/7Kah/+1o47/rpF2/6Sqp/+b0+7/oqur/7aI + Yv+XnJb/aM3//5zY//+q2v7/dtT//3uuyv+4lXf/spyI/4ttUf99XkP/iG9V/8GtmP/YzML/5t7Y/9HI + vv+Ne2T/wrqz/7qnlP+pjHT/o4Vn/6qMcv+EcFPdOy4EJT8yCQkAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABgTi2L5+DU//b38f/w7uj/8/Ps//Hu5P/q593/6eTZ/+ni1v/r5tr/39bJ/7ekj/+4pJD/t6SO/7KU + ef+qjnX/p4tv/7ePbv+bl4//Rr3//2nI//94x/7/SsP//2qoyv+7lXb/tZ+M/5B0Wv98XD//gGdM/4t0 + XP+Ldl7/g2xT/4NsVP+qn5L/zMW//7SgjP+nim7/o4do/6uNc/9/a07NOC4DGD8yCgUAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABYQyFx29TH//r69v/u7Oj/7uzk/+3q4P/s6eD/6+fc/+nl2f/p49f/6+XY/8a2 + pP+4pJD/u6eT/7mkkv+1nIb/rpeA/66Uef+2kW//V6TR/yO1//8pt///Ia79/5Kamv+8lnj/tKGO/5t/ + Zv97Wjv/h2lN/4hvVv+Wfmj/o5J9/7Wklf++rqL/taCP/6uQdv+kiGv/popt/6yPdP9lVTOWNywACUE0 + CgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABGNQ9RysKy/vv9+f/x7+n/8O7n/+/s5P/t6+L/7Onf/+vn + 3P/q5Nj/7une/9jOwP+7qJP/vquX/7yplv+6ppP/uKOO/7Odif+1mHz/r5N8/2aat/9Knsn/ipid/7yV + d/+wmYP/sJuG/7CZhf+okXr/rZmD/7Wgjf+4o4//tqCL/7Kbhf+rkXf/popu/6eJbf+nim7/rpF2/5N9 + Ye9BNQ0zPDAFAUI1DAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7LAM8u7Cd9v7/+v/y8en/8e7p/+/t + 5v/v7OP/7Ong/+zo3v/r5dj/7OXa/+vl2P/HuKb/vauY/8Cwm/++rJr/u6qU/7umkv+2o5H/t52F/76Y + dv+9lHP/upZ1/7CYgv+umYX/sZqF/7Kch/+2n4n/s5uF/7GYgf+uk3r/rJB2/62Pdf+sj3P/rpF1/62R + dv+vk3n/mYFm91RGIVkAAAAAQjULBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCMAkmrKCK7P/+ + +v/29PD/8/Hs//Lw6v/x7+n/7+3n//Du5v/x7eT/7une/+7q3v/f2c7/xLSj/7yrl/+6qJT/t6OP/7We + iv+znIj/spyI/7KdiP+ynYj/tJ2I/7afif+3nof/tpyF/7WchP+1m4T/t5qD/7abg/+3m4T/tZmC/7WX + gf+vk3z/oolw/5d+ZOx2Y0SvXU4rOAAAAABCNQsEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAA8KwIHmIlv1v399v/4+vb/9vTx//T07v/y8ur/7Ori/+Hf0v/Qx7j/xLmo/7yynv+9s5//vK2a/7Sf + iv+2oIn/u6OO/7ymkf+9qJH/v6mT/8Grlf/Dq5X/waiS/8OrlP/CqZL/wKSR/72kjv+4n4n/sJeB/6eQ + eP+VgGbrinRZz3hmR6lrWzqFZVQzUVJCHh8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAEI1CwEAAAAAVkciW76wnv3u5tr/4trL/9fKuv/UxrP/ybin/7Whjf+smof/ppN+/5uC + av+Qc1j/oIhu/7ynkf/KtaH/zrmm/866o//Mt6T/yLKf/8OsmP+8pZH/s5uG/6GLdPOZhGzoiXVbzHpn + S6xtWzuKXU0pZFlIJUNNQBkjXlAtCgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEI1CwEAAAAAAAAAAF9KKUWWgWfX18S0/9vJuf/Uwa//xLGa/9jL + wP/7+vv/29DG/6+WgP+Vc1T/mH1g/66ahf+0non/sZqF+aCKcuWJdlrMgW5Rtm5dPpleTyx5WEglU1pJ + JzRVRiEgRzsSCQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOy4EAQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABVQh4Sfm1Qm7ii + kP/ItqP/tKGK/+Lb0///////0cKy/6ySd/+dfF3/j3NY/2FOM4lTRB9TRTYPNlxKKR1YSiQNUEIbAQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAFFAHCtyXz9oYk4ubJSFb7PFtqnwqpeB75mCaOKLclbLfGZLdQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFdDIwN0X0QrcF1ALXNdRRkAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB3YUYDcl5DBAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///////wAA//////n/ + AAD///////8AAP/////4/wAA/////gB/AAD////gAD8AAP///AAAHwAA//+AAAAPAAD/+AAAAAcAAP8A + AAAABwAAwAAAAAAHAACAAAAAAAcAAIAAAAAAAwAAAAAAAAACAAAAAAAAAAIAAIAAAAAAAwAAgAAAAAAD + AABAAAAAAAMAAMAAAAAAAwAAwAAAAAADAABAAAAAAAMAAEAAAAAAAwAAwAAAAAADAADAAAAAAAMAAKAA + AAAAAwAAoAAAAAADAACgAAAAAAMAAKAAAAAAAwAA4AAAAAADAADgAAAAAAMAAOAAAAAAAwAA4AAAAAAD + AADgAAAAAAMAAPAAAAAAAwAA8AAAAAADAADwAAAAAAMAAPAAAAAAFwAA8AAAAAAvAADwAAAAAP8AAOgA + AAAP/wAA7AAAA/3/AAD+AAD///8AAP+AP////wAA//D/////AAD/+f////8AAP///////wAA//////// + AAD///////8AACgAAAAgAAAAQAAAAAEAIAAAAAAAgBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALyUAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOywBAzgrAAU7LAECAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPC0BAjosAAY3KgANMiYAGSwiACgqIAA/Kh8ARDYp + ACY8LQEHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPTACAjwuAQY5LAANNSkAGC8jACgsHwA5Kh8AUzAjAHNAMQqVV0UhtX1o + RteBbE7cOCsAhTElAC47LQIGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAADwtAQQ5KwAMNigAFS8jACIqHgA1KBwASywgAGo5KwKNUkAes3FePdSUfV/rtJt/+tCy + l//fwaP/6cam//TTsv+eg2j4MiYAgzQnACY7LQECAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPC4BATwu + AQQ8LgEMOCoAFDImAB8sIQAvKR0ASisfAGk3JwCJSzsWrWpXNsyMeVvorph+/8qzmf/exq3/6c+z/+vR + s//oza7/4cWl/9y/nf/Xupf/3r+c/8OihP+CbE/zNykAZjksAA0AAAAAAAAAAAAAAAA6LgECNyoADTEl + AB4sHgAxKRwASCweAGM3JgCBTDkRpWVVMsiIdVbkqJZ89sW0nf/byLL/59O+/+nVv//x3MT/6tO1/9zE + pv/hyKr/3MWo/9a8nf/XvJz/17ua/9e6mP/ev5z/tZZ3/6mIbv9oVTGzLyQADQAAAAAAAAAAAAAAADQm + ABg1IwBtRjYNomFPK8KBcFLbpJV8+cKznf/ayrj/6NnH/+3dyv/q3Mf/59fB/+LRuf/byq//5NG6/8Ss + jv+hinD/p5R//6qTeP/Stpf/4cep/9e8nP/Xu5v/17qY/9/Anv+4mXr/pIVn/3hkQs4vIgAYAAAAAAAA + AAAAAAAATz0Ya8W1of7e08T/7ufZ/+/o2P/t5NP/5t3N/+DWw//c0Lv/2c65/9nMtf/Zy7L/2Mew/+XS + vv+8pon/kn5n/8S8tP+/sqL/rZ+R/5F9Zf/PtJb/4cSm/9e7mv/Xupn/4cKd/7ucff+jg2j/eGNC1TUk + ACQAAAAAAAAAAAAAAABsWjyQ//zz/+bezf/Nv6v/3dbE/9vUwP/Z0L3/2tC9/9vQu//bzrn/2sy3/9rM + tf/gz7j/3Mix/454X//Ftq3/uaGL/45sTP+KZUP/jW5S/5N6Xf/kx6r/172c/9e6mf/hwp7/vaB//6OD + aP99ZkTZLiMAJgAAAAAAAAAAAAAAAFBAG2nr59n/0MOw/7Odi//Qw67/4trI/9vSv//b0b7/29C8/9vO + uv/azbj/2su1/+XWv/+8por/n4p1/9jLwP+gh3L/eFlB/5Z/bP+ObVD/hmdJ/8+1l//cw6P/1bmY/9/A + n//AooH/o4Jn/39pRt0sIwAlAAAAAAAAAAAAAAAATDkSS9/Zy//Z0r//u6eX/8e7pv/i28z/29K//9vR + vv/b0Lz/28+6/9rNuP/ay7X/59fA/6+Wef+woZD/4t3X/3VVO/+QemX/+f7//7anlv98Vzj/xauO/+HG + p//Vupn/3sCf/8SlhP+ig2f/hG1O4DIlACYAAAAAAAAAAAAAAAA4JQAy0Ma2/+Pcyv+znor/w7Sd/+Pd + zP/b0sD/3NK//9vRvf/bz7v/2825/9rMtf/m2ML/sZl+/6yaiP/n4Nz/cVE1/5SBbP//////wrWn/3pV + Nf/IrpH/4MWl/9W6mf/dwJ7/xqmG/6KDZ/+JclTkNScAKQAAAAAAAAAAAAAAACkWABq+s57w7uvd/7Of + iv+7p5D/5N3N/9vTwf/c0r//29G9/9vPu//bzrn/2sy3/+LTvf/Ou6T/jXNZ/9zUyf+YgGn/c1U6/6md + lP+UeWL/i2lL/9i/o//bwKL/1ryb/93Bnv/Jq4v/ooNm/49zV+w1KAA2AAAAAAAAAAAAAAAAJhQABqib + gtf59+v/uqeR/7Sfh//j2sv/3NTB/+DWw//i2MX/3NK+/9vNuf/bzbj/2822/+jYwv+giGv/kntj/76p + lf+Tdlr/gV8+/35cOv+xmHz/5c2u/9i9oP/XvZz/3cGh/8uuj/+hgmb/kXVY8jYpAEIAAAAAAAAAAAAA + AAAAAAAAkYJovv799P/DtKH/r5iC/93Yyf/h2Mf/1MWx/8y8p//j18b/4tfD/9zPuv/ay7T/3My1/+DR + uv+dhGj/h2xP/4hqTP+DZUj/qZBy/+DJrP/awaT/2b6h/9i+oP/ewqL/z7GR/6KDZv+TeVv1NyoARwAA + AAAAAAAAAAAAAAAAAAB9bU+h/f/1/9DDsv+tk33/3NbF/+ji0v/KuKH/lXdZ/62Xff/MuqT/39K//+LW + wP/i07z/5NO8/+3bxP/Uwqj/yLOX/9fDqf/o07r/4cmr/93Ep//awaT/1rya/9m8mv/NsZP/pIVo/5V7 + Xfg2KgBHAAAAAAAAAAAAAAAAAAAAAGBQLIX6+fD/29TF/6yUf//a0MH/6+XY/9bIuP+egmX/n4Rp/5+D + af+ojXL/t6CE/8Kvmf/Itp//zLie/9C9pf/Tv6j/0Lqi/8u3nv/DrZf/u6aP/7ijj/+8qpr/t6WW/6+Y + hv+nhWj/mn5g+zstAkoAAAAAAAAAAAAAAAAAAAAATj0YZ/Lt5f/o5Nn/r5mF/9bJuv/s59r/5dvO/6uQ + d/+hhmr/p4tv/6qUf/+pj3X/ooRs/6mHav+jh23/qIdq/6qPeP+oknz/knZc/4xwVv+Jblf/inNc/6OZ + i//KxcD/sJeD/6eGaP+dgmT/PjMISwAAAAAAAAAAAAAAAAAAAAA9KwdI5d7T//Py5/+znob/zL6s/+7r + 3P/s5df/w7Ca/6WIbP+ehWr/yO37/9nq6v+pgWL/np2T/53Y6/+cwMv/r5N6/62Tev93VTb/el4//5d/ + af/Fuaz/tqiW/6+ll/+2n43/poVo/5+EZv9BNQtXAAAAAAAAAAAAAAAAAAAAADAiAC7Ty773/v72/8q7 + qf/b08b/7Ojb/+zn2f/Wybn/rpWA/6uPc/+ixtX/qMnR/6+CXv9yv+X/q+z//4jg//+Koqn/uZV2/39h + Q/9+YkX/y7up//n08v/Fu67/qJ2P/7ikkP+jg2T/pIZr/0Y4EFwAAAAAAAAAAAAAAAAAAAAAMyEAG76x + n+f/////8/Hr//Hu5f/q5tr/6+bZ/+fe0f+4pJD/t6GL/66ReP+mh2v/tIlj/1er2f9Exf//NMD//4Kd + qP/Cmnz/g2dL/3NUNf+Ea1P/hm9V/5WCb//Ct6//rpV+/6WEZf+ihmr/QDQKRgAAAAAAAAAAAAAAAAAA + AAA4IwALpZiC1f/////v7eb/7+zj/+3q4P/r5tr/8Ord/8y8q/+4o4z/vKeT/7Weif+4l3j/nZGE/zmg + 0/9Pm8T/s5J4/7Oag/+iiHD/moFn/6aOeP+umoP/tJ6J/6qPdv+lhmj/s5N5/39qSMsvJAAJAAAAAAAA + AAAAAAAAAAAAAAAAAACRgmfB//////Lw6//x7+j/8O3l//Ht5P/18eb/6+bY/8OxoP+9rJb/uqaT/7Wg + jf+5mH3/u5Jw/7uSbf+xln3/rpiB/7adhv+4n4j/uZuD/7WXfv+zknj/rpBz/6mNb/+KclXSRDcPKQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAHxsTaL//////fz5//T07f/x7+j/39rO/83Csv/LwrD/wbKi/7ah + iv+5ooz/vKWP/7+okv/ErJf/xKuW/8Srk//DppD/uZ6G/7KXf/+njnP/ln5k44dwU712YUGRaFQ0UVxN + KQsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQzMJK7CijN/r39H/4NHA/8y6pf/AsJ//uaqZ/5N3 + W/+UeFn/w6yY/9K4p//Er5j/tqGL/qaQd+yWgGbXh3JWu3VhQpl0X0FyXEwmTUs6EyhSQx4JAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATTYSEoNvU57Isp//vKaP//Xy + 8P/07OT/poZp/45tT/9wXUCkYE4rdmNPLVJVRB81WkolIkk6EwwAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFlG + IixhTClMjHtjj6CMd76Kb1OlfGNGYQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA////v/////////8f///gD//8AAf/wAAD8AAAA4AAAAOAAAADgAAAA4AAAAOAAAADgAAAA4AA + AAOAAAADgAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAAD4AAAB+AAAA/gAAD/8AA///wP + //////////////////8oAAAAGAAAADAAAAABACAAAAAAAGAJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAACgdAAYhGAAYJBkANCgcACo2KQACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAArIAABJRkAEiIXADApGwBRNCgJdk07Gp9tWDbEnoNj7XJe + O84kGQBFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKB4AASQYAA8kFgAqJRcASTEi + AnJGNx2aZVQ2wYt2Vt2wmXn3zrSW/+LEqP/qy6v/9NGu/+K/of9iTjDUKh4AMzMnAAQAAAAAAAAAAAAA + AAAlGAANIxUAJiUXAEQwHwBoRDMOkWJSMr2GdFrgq5p99cq0nP/hzbT/9dvD/+zStf/v0rX/6tGy/9zA + oP/WuZf/2buX/86ti/+qh2z/Tz8biCwiABYAAAAAMiMBDjcoB1hbSyu4gXJV1qWXfvXHuaT/39C+/+zd + yv/v38z/6tzF/+fVvf/k0Lf/sp1//6ubh/+smYT/ya+R/+DDpf/Ut5f/3L6b/82tjP+oh2n/ZVIyrTEj + AygAAAAAalk7JJmLc6b/+e3/7+fX//Dq2P/l3Mv/3dS+/9rOuP/XyrP/18iv/+TSvP+rlXn/qJiJ/7mm + lP+WemD/iG5U/8+ylf/ewaH/3Lya/9Gxjf+nhWr/ZFExtDIlAzIAAAAAYlM0IJaMc5vo3Mz/tqGN/9nR + vf/b0r7/2c+7/9rOuf/Zy7b/39G6/9fCqf+eh3H/z76z/4RjSP+FZUv/gF5C/6eKa//gyKf/2ryb/9Kz + kf+ph2r/ZlMxty4lAzIAAAAARjUYFnFkSIbj3Mn/taGN/9XNuf/f18T/2s+7/9rPuf/ZzLb/4tW+/8my + lv+woIz/yLuy/2lKMP/59PL/rZqH/5NvTv/hyKj/2r2c/9S1k/+qiWz/bVg4ujQoBDMAAAAAKh0JD0g7 + KnPt5dH/sJuE/9LHsv/g2Mj/2tC7/9rPuv/ZzLf/4NK7/9PAqP+ji3b/z8O4/21PMv/59PL/n4dy/599 + Xf/iyar/2b2c/9a4lP+sim7/clw9xDgrBjwAAAAAFgsDByMaEVjy79X/tJ6F/8u7qP/h28r/39bC/+HZ + xP/bz7r/2cq0/+bXwP+mjnL/oIt1/5yCaP9xUTT/elk6/8uxlP/fxKb/2L2c/9i7mv+ri27/dl0+0Tot + BksAAAAAGhEHBhELBkPg28D/tqOO/8Cxnf/m4dH/yrih/8i2of/i1sP/4dbA/+HSu//j1Lz/p5F0/5R4 + Wv+NcFL/v6iI/+bOr//cv6H/3cCe/96/nf+vjnH/d2BA1zsuB1EAAAAAQzUdBxUPBTK3s5v5xLGe/7qo + lP/w697/vqqU/5BwUv+uln3/w7CX/9HBqf/ay7P/5tO6/9fEq//dyrD/48+1/9O7of/LtJv/yrKY/8Kp + kf+ujHH/fmVE2TwwB1MAAAAAMiQGARsRAR+xqZPs1s6+/7ehjP/w6t//2cu6/5t9YP+bfWH/pY1z/6aI + b/+qhmn/p4tu/7STdv+wmYD/l3th/41wW/+OdmH/raWb/7mqof+qh2r/hWtJ3kI2DlYAAAAAAAAAAB0Q + AA6vppTe7eXW/7SfiP/r5tr/6eLT/7GXff+dgWf/zvb//7+woP+VkIX/reL1/6OtrP+qiGz/b0wt/5B3 + Xv/p497/xr6y/7Chk/+tjXD/h25N5Ec6E2IAAAAAAAAAAAAAAACfkn/J///9/+DYzP/r6Nv/7+nb/8e1 + pP+rkHX/oail/66Ma/9xrMr/fOr//3LD4v+1k3n/d1Qz/4huVP/59PL/tKug/7Smmf+ph2n/jHBR5Ew9 + F2EAAAAAAAAAAAAAAACGd1+v//////Lx6P/s6d//8evf/97Txv+2oIr/tZh//7eQbf+Qkov/LaPh/2+W + p/+8lXb/lnph/49zWv+Ue2H/o4t3/6OGav+ohGb/bVk4rzMoBCMAAAAAAAAAAAAAAAB4Z0ua//////X0 + 8f/y8en/7eja/+zl1f/Cs6H/sZ6I/7Gdif+4lHf/uo9s/7qTcf+zmID/tJmD/7WXfv+rinH/mHda/45w + UfN6YUa0NiwHFgAAAAAAAAAAAAAAAAAAAABVRSNS5+DX//327f/WzLn/tKWR/52Ldf+Re2D/tZyH/7+h + jP+tknz/p412/56GbfmPc1jeg2hPwmxWOKRiTzF7dGBDVGNPMCsAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAXUcmTauUfOSojHX/5N3X/7Wch/9qSCz/ZlE5sldFLIRJOiBjRjkbR15LLSdvWj4WY1AwBQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGZSNCBKNxtVi31ol41z + W7FsUDZyVkUqBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA////AP///wD//wcA/+AHAPwAAQDAAAEAAAABAAAAAQAAAAEAAAABAAAA + AQAAAAEAAAABAAAAAQAAAAEAgAABAMAAAQDAAAEAwAADAMAADwDgAP8A8D//AP///wD///8AKAAAABAA + AAAgAAAAAQAgAAAAAABABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAABUMAAohFQATIxkAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAABUKABgcEQBEMiYOe1lGKIeKcU+tvJt4zD4wFl0AAAAAAAAAAAAAAAAAAAAACwAAFxsL + ADwtIAJrTT8mpn5rT9aym4H02Lye//PUssz/5MTM9NSxzPzXscyyj3D/LCADQiIZAAgyJAYeaVxCwqqb + gfjQwaz/797I//jp0f//7dX/79i9/72qkv+tm4b/xamM/+LEo//dv5j/vpp6/0w6GnEqHQEbUEMoM7aw + m//o0b//7ejR/9/Vv//bzrf/5tS8/7Seh/+xm4z/gF1A/4NhRf/cwaD/6Mek/7yZev9KOBhzJx8BHhsR + AxqmmnzrtaCJ/9/axv/f0r7/39O9/+LSuP++qpT/noh4//n08v+oknv/x6iF/+zOq//Bnn7/VEEglTAk + AyUAAAALq6SM3sqylv/h2Mf/5+DM/+bax//r3MX/vqaN/5aAaP+Ha1P/kHFU/+LFp//pzKj/xKKC/1pF + JKk3KAUyAAAAAIiEb87Ks5v/5NvL/8KtlP/MuKL/5tjC/+/hyP++qYr/ooZn/9/IqP/t0rP/4sSh/8ai + hv9fSye2OSwFOAAAAABqZVK60Lym/+fazv/BrJT/jWlJ/7WgiP++mXz/0a2P/9O6n/+vlHv/nIRr/7qt + of+6mYP/a1UsukA1CjsAAAAAX1dInPTo1v/g2cj/6NzL/6KIb//L1tH/r7Ow/7fv//+/saX/bkcj//n0 + 8v/MycX/tpiC/3heOM9PPxpGAAAAAG1cSX//////9vXr//z26//Er5z/soxs/4yWkv9Cwfj/rZ+Q/5Jq + Rv+vmob/rJWD/6mCZf9SPyCcMiUJKAAAAABbSy9h////////9//a0b3/wLKd/8Gnkv/NpIj/vI9w/62G + aP+afGX/fF1B8G9PMthgRCyRAAAAAAAAAAAAAAAAOiwNBH9qT6iqkXX/sZyK/11AKv9tVD7FaVQ8mV1L + L3phTDJSUj4jLUk5HxcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABHMRUBPSsWVnlmVKFaPSeIPzEZCAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//wAA/+MAAP4DAADAAAAAAAAAAAAA + AAAAAAAAAAAAAIAAAACAAAAAgAAAAIAAAACAAwAAgA8AAMH/AAD//wAA + + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Security.Gui/Properties/Resources.Designer.cs b/CloudBuilder/CloudBuilder.Security.Gui/Properties/Resources.Designer.cs new file mode 100644 index 0000000..4ec0539 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/Properties/Resources.Designer.cs @@ -0,0 +1,213 @@ +//------------------------------------------------------------------------------ +// +// 這段程式碼是由工具產生的。 +// 執行階段版本:4.0.30319.42000 +// +// 對這個檔案所做的變更可能會造成錯誤的行為,而且如果重新產生程式碼, +// 變更將會遺失。 +// +//------------------------------------------------------------------------------ + +namespace CloudBuilder.Security.Gui.Properties { + using System; + + + /// + /// 用於查詢當地語系化字串等的強類型資源類別。 + /// + // 這個類別是自動產生的,是利用 StronglyTypedResourceBuilder + // 類別透過 ResGen 或 Visual Studio 這類工具。 + // 若要加入或移除成員,請編輯您的 .ResX 檔,然後重新執行 ResGen + // (利用 /str 選項),或重建您的 VS 專案。 + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// 傳回這個類別使用的快取的 ResourceManager 執行個體。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("CloudBuilder.Security.Gui.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// 覆寫目前執行緒的 CurrentUICulture 屬性,對象是所有 + /// 使用這個強類型資源類別的資源查閱。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// 查詢類型 System.Drawing.Bitmap 的當地語系化資源。 + /// + internal static System.Drawing.Bitmap amend_16 { + get { + object obj = ResourceManager.GetObject("amend_16", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查詢類型 System.Drawing.Bitmap 的當地語系化資源。 + /// + internal static System.Drawing.Bitmap cancel_16 { + get { + object obj = ResourceManager.GetObject("cancel_16", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查詢類型 System.Drawing.Bitmap 的當地語系化資源。 + /// + internal static System.Drawing.Bitmap close_16 { + get { + object obj = ResourceManager.GetObject("close_16", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查詢類型 System.Drawing.Bitmap 的當地語系化資源。 + /// + internal static System.Drawing.Bitmap create_16 { + get { + object obj = ResourceManager.GetObject("create_16", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查詢類型 System.Drawing.Bitmap 的當地語系化資源。 + /// + internal static System.Drawing.Bitmap delete_16 { + get { + object obj = ResourceManager.GetObject("delete_16", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查詢類型 System.Drawing.Bitmap 的當地語系化資源。 + /// + internal static System.Drawing.Bitmap MoveNext { + get { + object obj = ResourceManager.GetObject("MoveNext", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查詢類型 System.Drawing.Bitmap 的當地語系化資源。 + /// + internal static System.Drawing.Bitmap MovePrevious { + get { + object obj = ResourceManager.GetObject("MovePrevious", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查詢類型 System.Drawing.Bitmap 的當地語系化資源。 + /// + internal static System.Drawing.Bitmap navigate_minus { + get { + object obj = ResourceManager.GetObject("navigate_minus", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查詢類型 System.Drawing.Bitmap 的當地語系化資源。 + /// + internal static System.Drawing.Bitmap navigate_plus { + get { + object obj = ResourceManager.GetObject("navigate_plus", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查詢類型 System.Drawing.Bitmap 的當地語系化資源。 + /// + internal static System.Drawing.Bitmap ok_16 { + get { + object obj = ResourceManager.GetObject("ok_16", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查詢類型 System.Drawing.Bitmap 的當地語系化資源。 + /// + internal static System.Drawing.Bitmap reset_16 { + get { + object obj = ResourceManager.GetObject("reset_16", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查詢類型 System.Drawing.Bitmap 的當地語系化資源。 + /// + internal static System.Drawing.Bitmap save_16 { + get { + object obj = ResourceManager.GetObject("save_16", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查詢類型 System.Drawing.Bitmap 的當地語系化資源。 + /// + internal static System.Drawing.Bitmap search_16 { + get { + object obj = ResourceManager.GetObject("search_16", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查詢類型 System.Drawing.Bitmap 的當地語系化資源。 + /// + internal static System.Drawing.Bitmap view_16 { + get { + object obj = ResourceManager.GetObject("view_16", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查詢類型 System.Drawing.Bitmap 的當地語系化資源。 + /// + internal static System.Drawing.Bitmap Yo7OjL6wMwgA845AU { + get { + object obj = ResourceManager.GetObject("Yo7OjL6wMwgA845AU", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/CloudBuilder/CloudBuilder.Security.Gui/Properties/Resources.resx b/CloudBuilder/CloudBuilder.Security.Gui/Properties/Resources.resx new file mode 100644 index 0000000..bf3acfc --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/Properties/Resources.resx @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\save_16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\create_16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Yo7OjL6wMwgA845AU.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\cancel_16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\amend_16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\delete_16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\view_16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\MovePrevious.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\search_16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\close_16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\MoveNext.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\ok_16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\reset_16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\navigate_minus.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\navigate_plus.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Security.Gui/Resources/MoveFirst.png b/CloudBuilder/CloudBuilder.Security.Gui/Resources/MoveFirst.png new file mode 100644 index 0000000..46e0754 Binary files /dev/null and b/CloudBuilder/CloudBuilder.Security.Gui/Resources/MoveFirst.png differ diff --git a/CloudBuilder/CloudBuilder.Security.Gui/Resources/MoveLast.png b/CloudBuilder/CloudBuilder.Security.Gui/Resources/MoveLast.png new file mode 100644 index 0000000..80b2a45 Binary files /dev/null and b/CloudBuilder/CloudBuilder.Security.Gui/Resources/MoveLast.png differ diff --git a/CloudBuilder/CloudBuilder.Security.Gui/Resources/MoveNext.png b/CloudBuilder/CloudBuilder.Security.Gui/Resources/MoveNext.png new file mode 100644 index 0000000..5afeea1 Binary files /dev/null and b/CloudBuilder/CloudBuilder.Security.Gui/Resources/MoveNext.png differ diff --git a/CloudBuilder/CloudBuilder.Security.Gui/Resources/MovePrevious.png b/CloudBuilder/CloudBuilder.Security.Gui/Resources/MovePrevious.png new file mode 100644 index 0000000..62ed1f3 Binary files /dev/null and b/CloudBuilder/CloudBuilder.Security.Gui/Resources/MovePrevious.png differ diff --git a/CloudBuilder/CloudBuilder.Security.Gui/Resources/Yo7OjL6wMwgA845AU.png b/CloudBuilder/CloudBuilder.Security.Gui/Resources/Yo7OjL6wMwgA845AU.png new file mode 100644 index 0000000..d4c7b14 Binary files /dev/null and b/CloudBuilder/CloudBuilder.Security.Gui/Resources/Yo7OjL6wMwgA845AU.png differ diff --git a/CloudBuilder/CloudBuilder.Security.Gui/Resources/amend_16.png b/CloudBuilder/CloudBuilder.Security.Gui/Resources/amend_16.png new file mode 100644 index 0000000..95dabb1 Binary files /dev/null and b/CloudBuilder/CloudBuilder.Security.Gui/Resources/amend_16.png differ diff --git a/CloudBuilder/CloudBuilder.Security.Gui/Resources/cancel_16.png b/CloudBuilder/CloudBuilder.Security.Gui/Resources/cancel_16.png new file mode 100644 index 0000000..0da8729 Binary files /dev/null and b/CloudBuilder/CloudBuilder.Security.Gui/Resources/cancel_16.png differ diff --git a/CloudBuilder/CloudBuilder.Security.Gui/Resources/close_16.png b/CloudBuilder/CloudBuilder.Security.Gui/Resources/close_16.png new file mode 100644 index 0000000..349423f Binary files /dev/null and b/CloudBuilder/CloudBuilder.Security.Gui/Resources/close_16.png differ diff --git a/CloudBuilder/CloudBuilder.Security.Gui/Resources/create_16.png b/CloudBuilder/CloudBuilder.Security.Gui/Resources/create_16.png new file mode 100644 index 0000000..18365cf Binary files /dev/null and b/CloudBuilder/CloudBuilder.Security.Gui/Resources/create_16.png differ diff --git a/CloudBuilder/CloudBuilder.Security.Gui/Resources/delete_16.png b/CloudBuilder/CloudBuilder.Security.Gui/Resources/delete_16.png new file mode 100644 index 0000000..0b4a3bc Binary files /dev/null and b/CloudBuilder/CloudBuilder.Security.Gui/Resources/delete_16.png differ diff --git a/CloudBuilder/CloudBuilder.Security.Gui/Resources/favicon.ico b/CloudBuilder/CloudBuilder.Security.Gui/Resources/favicon.ico new file mode 100644 index 0000000..63e859b Binary files /dev/null and b/CloudBuilder/CloudBuilder.Security.Gui/Resources/favicon.ico differ diff --git a/CloudBuilder/CloudBuilder.Security.Gui/Resources/navigate_minus.png b/CloudBuilder/CloudBuilder.Security.Gui/Resources/navigate_minus.png new file mode 100644 index 0000000..bb65279 Binary files /dev/null and b/CloudBuilder/CloudBuilder.Security.Gui/Resources/navigate_minus.png differ diff --git a/CloudBuilder/CloudBuilder.Security.Gui/Resources/navigate_plus.png b/CloudBuilder/CloudBuilder.Security.Gui/Resources/navigate_plus.png new file mode 100644 index 0000000..22a7dc8 Binary files /dev/null and b/CloudBuilder/CloudBuilder.Security.Gui/Resources/navigate_plus.png differ diff --git a/CloudBuilder/CloudBuilder.Security.Gui/Resources/ok_16.png b/CloudBuilder/CloudBuilder.Security.Gui/Resources/ok_16.png new file mode 100644 index 0000000..47dc49d Binary files /dev/null and b/CloudBuilder/CloudBuilder.Security.Gui/Resources/ok_16.png differ diff --git a/CloudBuilder/CloudBuilder.Security.Gui/Resources/print.png b/CloudBuilder/CloudBuilder.Security.Gui/Resources/print.png new file mode 100644 index 0000000..902217c Binary files /dev/null and b/CloudBuilder/CloudBuilder.Security.Gui/Resources/print.png differ diff --git a/CloudBuilder/CloudBuilder.Security.Gui/Resources/reset_16.png b/CloudBuilder/CloudBuilder.Security.Gui/Resources/reset_16.png new file mode 100644 index 0000000..ceb83b0 Binary files /dev/null and b/CloudBuilder/CloudBuilder.Security.Gui/Resources/reset_16.png differ diff --git a/CloudBuilder/CloudBuilder.Security.Gui/Resources/save_16.png b/CloudBuilder/CloudBuilder.Security.Gui/Resources/save_16.png new file mode 100644 index 0000000..f9d9eab Binary files /dev/null and b/CloudBuilder/CloudBuilder.Security.Gui/Resources/save_16.png differ diff --git a/CloudBuilder/CloudBuilder.Security.Gui/Resources/search_16.png b/CloudBuilder/CloudBuilder.Security.Gui/Resources/search_16.png new file mode 100644 index 0000000..1a77c32 Binary files /dev/null and b/CloudBuilder/CloudBuilder.Security.Gui/Resources/search_16.png differ diff --git a/CloudBuilder/CloudBuilder.Security.Gui/Resources/view_16.png b/CloudBuilder/CloudBuilder.Security.Gui/Resources/view_16.png new file mode 100644 index 0000000..49f50e2 Binary files /dev/null and b/CloudBuilder/CloudBuilder.Security.Gui/Resources/view_16.png differ diff --git a/CloudBuilder/CloudBuilder.Security.Gui/SecurityActorEnquiryPage.Designer.cs b/CloudBuilder/CloudBuilder.Security.Gui/SecurityActorEnquiryPage.Designer.cs new file mode 100644 index 0000000..0182c06 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/SecurityActorEnquiryPage.Designer.cs @@ -0,0 +1,387 @@ +namespace CloudBuilder.Security.Gui +{ + partial class SecurityActorEnquiryPage + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + DataGridViewCellStyle dataGridViewCellStyle7 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle8 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle9 = new DataGridViewCellStyle(); + mainPanel = new TableLayoutPanel(); + topPanel = new TableLayoutPanel(); + searchActorNameLabel = new Krypton.Toolkit.KryptonLabel(); + actorNameTxt = new Krypton.Toolkit.KryptonTextBox(); + searchPanel = new TableLayoutPanel(); + searchBut = new Krypton.Toolkit.KryptonButton(); + resetBut = new Krypton.Toolkit.KryptonButton(); + createBut = new Krypton.Toolkit.KryptonButton(); + contextPanel = new TableLayoutPanel(); + dataGv = new Krypton.Toolkit.KryptonDataGridView(); + actorNameCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + actorLocalNameCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + actorEngNameCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + gridViewPagination = new CloudBuilder.Gui.GridViewPagination(); + bottomPanel = new TableLayoutPanel(); + operationPanel = new TableLayoutPanel(); + viewBut = new Krypton.Toolkit.KryptonButton(); + amendBut = new Krypton.Toolkit.KryptonButton(); + deleteBut = new Krypton.Toolkit.KryptonButton(); + dialogPanel = new TableLayoutPanel(); + okBut = new Krypton.Toolkit.KryptonButton(); + cancelBut = new Krypton.Toolkit.KryptonButton(); + mainPanel.SuspendLayout(); + topPanel.SuspendLayout(); + searchPanel.SuspendLayout(); + contextPanel.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)dataGv).BeginInit(); + bottomPanel.SuspendLayout(); + operationPanel.SuspendLayout(); + dialogPanel.SuspendLayout(); + SuspendLayout(); + // + // mainPanel + // + mainPanel.ColumnCount = 1; + mainPanel.ColumnStyles.Add(new ColumnStyle()); + mainPanel.Controls.Add(topPanel, 0, 0); + mainPanel.Controls.Add(contextPanel, 0, 1); + mainPanel.Controls.Add(bottomPanel, 0, 2); + mainPanel.Dock = DockStyle.Fill; + mainPanel.Location = new Point(0, 0); + mainPanel.Name = "mainPanel"; + mainPanel.RowCount = 3; + mainPanel.RowStyles.Add(new RowStyle()); + mainPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 100F)); + mainPanel.RowStyles.Add(new RowStyle()); + mainPanel.Size = new Size(1024, 800); + mainPanel.TabIndex = 0; + // + // topPanel + // + topPanel.AutoSize = true; + topPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + topPanel.ColumnCount = 5; + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.Controls.Add(searchActorNameLabel, 0, 0); + topPanel.Controls.Add(actorNameTxt, 1, 0); + topPanel.Controls.Add(searchPanel, 4, 0); + topPanel.Dock = DockStyle.Fill; + topPanel.Location = new Point(3, 3); + topPanel.Name = "topPanel"; + topPanel.RowCount = 1; + topPanel.RowStyles.Add(new RowStyle()); + topPanel.Size = new Size(1018, 31); + topPanel.TabIndex = 0; + // + // searchActorNameLabel + // + searchActorNameLabel.Location = new Point(3, 3); + searchActorNameLabel.Name = "searchActorNameLabel"; + searchActorNameLabel.Size = new Size(52, 20); + searchActorNameLabel.TabIndex = 999; + searchActorNameLabel.Values.Text = "角色名:"; + // + // actorNameTxt + // + actorNameTxt.Location = new Point(61, 3); + actorNameTxt.Name = "actorNameTxt"; + actorNameTxt.Size = new Size(200, 23); + actorNameTxt.TabIndex = 0; + // + // searchPanel + // + searchPanel.AutoSize = true; + searchPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + searchPanel.ColumnCount = 3; + searchPanel.ColumnStyles.Add(new ColumnStyle()); + searchPanel.ColumnStyles.Add(new ColumnStyle()); + searchPanel.ColumnStyles.Add(new ColumnStyle()); + searchPanel.Controls.Add(searchBut, 0, 0); + searchPanel.Controls.Add(resetBut, 1, 0); + searchPanel.Controls.Add(createBut, 2, 0); + searchPanel.Location = new Point(324, 0); + searchPanel.Margin = new Padding(60, 0, 0, 0); + searchPanel.Name = "searchPanel"; + searchPanel.RowCount = 1; + searchPanel.RowStyles.Add(new RowStyle()); + searchPanel.Size = new Size(288, 31); + searchPanel.TabIndex = 999; + // + // searchBut + // + searchBut.Location = new Point(3, 3); + searchBut.Name = "searchBut"; + searchBut.Size = new Size(90, 25); + searchBut.TabIndex = 0; + searchBut.Values.Image = Properties.Resources.search_16; + searchBut.Values.Text = "查询(&S)"; + searchBut.Click += searchBut_Click; + // + // resetBut + // + resetBut.Location = new Point(99, 3); + resetBut.Name = "resetBut"; + resetBut.Size = new Size(90, 25); + resetBut.TabIndex = 0; + resetBut.Values.Image = Properties.Resources.reset_16; + resetBut.Values.Text = "重置(&R)"; + resetBut.Click += resetBut_Click; + // + // createBut + // + createBut.Location = new Point(195, 3); + createBut.Name = "createBut"; + createBut.Size = new Size(90, 25); + createBut.TabIndex = 0; + createBut.Values.Image = Properties.Resources.create_16; + createBut.Values.Text = "新增(&C)"; + createBut.Click += createBut_Click; + // + // contextPanel + // + contextPanel.ColumnCount = 1; + contextPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F)); + contextPanel.Controls.Add(dataGv, 0, 0); + contextPanel.Controls.Add(gridViewPagination, 0, 1); + contextPanel.Dock = DockStyle.Fill; + contextPanel.Location = new Point(3, 40); + contextPanel.Name = "contextPanel"; + contextPanel.RowCount = 2; + contextPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 50F)); + contextPanel.RowStyles.Add(new RowStyle()); + contextPanel.Size = new Size(1018, 683); + contextPanel.TabIndex = 999; + // + // dataGv + // + dataGv.AllowUserToAddRows = false; + dataGv.AllowUserToDeleteRows = false; + dataGv.BorderStyle = BorderStyle.None; + dataGv.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize; + dataGv.Columns.AddRange(new DataGridViewColumn[] { actorNameCol, actorLocalNameCol, actorEngNameCol }); + dataGv.Dock = DockStyle.Fill; + dataGv.Location = new Point(3, 3); + dataGv.Name = "dataGv"; + dataGv.Size = new Size(1012, 647); + dataGv.TabIndex = 0; + dataGv.CellDoubleClick += dataGv_CellDoubleClick; + // + // actorNameCol + // + actorNameCol.DataPropertyName = "ActorName"; + actorNameCol.DefaultCellStyle = dataGridViewCellStyle7; + actorNameCol.HeaderText = "角色名"; + actorNameCol.Name = "actorNameCol"; + actorNameCol.Width = 260; + // + // actorLocalNameCol + // + actorLocalNameCol.DataPropertyName = "ActorLocalName"; + actorLocalNameCol.DefaultCellStyle = dataGridViewCellStyle8; + actorLocalNameCol.HeaderText = "中文名"; + actorLocalNameCol.Name = "actorLocalNameCol"; + actorLocalNameCol.Width = 260; + // + // actorEngNameCol + // + actorEngNameCol.DataPropertyName = "ActorEngName"; + actorEngNameCol.DefaultCellStyle = dataGridViewCellStyle9; + actorEngNameCol.HeaderText = "英文名"; + actorEngNameCol.Name = "actorEngNameCol"; + actorEngNameCol.Resizable = DataGridViewTriState.True; + actorEngNameCol.Width = 260; + // + // gridViewPagination + // + gridViewPagination.AutoSizeMode = AutoSizeMode.GrowAndShrink; + gridViewPagination.CurrentPage = 0; + gridViewPagination.Dock = DockStyle.Fill; + gridViewPagination.Limit = 20; + gridViewPagination.Location = new Point(0, 653); + gridViewPagination.Margin = new Padding(0); + gridViewPagination.Name = "gridViewPagination"; + gridViewPagination.Page = 0; + gridViewPagination.Size = new Size(1018, 30); + gridViewPagination.TabIndex = 999; + gridViewPagination.Total = 0; + // + // bottomPanel + // + bottomPanel.AutoSize = true; + bottomPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + bottomPanel.ColumnCount = 2; + bottomPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F)); + bottomPanel.ColumnStyles.Add(new ColumnStyle()); + bottomPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 20F)); + bottomPanel.Controls.Add(operationPanel, 0, 0); + bottomPanel.Controls.Add(dialogPanel, 2, 1); + bottomPanel.Dock = DockStyle.Fill; + bottomPanel.Location = new Point(3, 729); + bottomPanel.Name = "bottomPanel"; + bottomPanel.RowCount = 2; + bottomPanel.RowStyles.Add(new RowStyle()); + bottomPanel.RowStyles.Add(new RowStyle()); + bottomPanel.Size = new Size(1018, 68); + bottomPanel.TabIndex = 999; + // + // operationPanel + // + operationPanel.AutoSize = true; + operationPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + operationPanel.ColumnCount = 3; + operationPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F)); + operationPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 101F)); + operationPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F)); + operationPanel.Controls.Add(viewBut, 0, 0); + operationPanel.Controls.Add(amendBut, 1, 0); + operationPanel.Controls.Add(deleteBut, 2, 0); + operationPanel.Location = new Point(0, 0); + operationPanel.Margin = new Padding(0); + operationPanel.Name = "operationPanel"; + operationPanel.RowCount = 1; + operationPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 50F)); + operationPanel.Size = new Size(293, 31); + operationPanel.TabIndex = 0; + // + // viewBut + // + viewBut.Location = new Point(3, 3); + viewBut.Name = "viewBut"; + viewBut.Size = new Size(90, 25); + viewBut.TabIndex = 0; + viewBut.Values.Image = Properties.Resources.view_16; + viewBut.Values.Text = "查看(&V)"; + viewBut.Click += viewBut_Click; + // + // amendBut + // + amendBut.Location = new Point(99, 3); + amendBut.Name = "amendBut"; + amendBut.Size = new Size(90, 25); + amendBut.TabIndex = 0; + amendBut.Values.Image = Properties.Resources.amend_16; + amendBut.Values.Text = "修改(&A)"; + amendBut.Click += amendBut_Click; + // + // deleteBut + // + deleteBut.Location = new Point(200, 3); + deleteBut.Name = "deleteBut"; + deleteBut.Size = new Size(90, 25); + deleteBut.TabIndex = 0; + deleteBut.Values.Image = Properties.Resources.delete_16; + deleteBut.Values.Text = "删除(&D)"; + deleteBut.Click += deleteBut_Click; + // + // dialogPanel + // + dialogPanel.AutoSize = true; + dialogPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + dialogPanel.ColumnCount = 2; + dialogPanel.ColumnStyles.Add(new ColumnStyle()); + dialogPanel.ColumnStyles.Add(new ColumnStyle()); + dialogPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 20F)); + dialogPanel.Controls.Add(okBut, 0, 0); + dialogPanel.Controls.Add(cancelBut, 1, 0); + dialogPanel.Dock = DockStyle.Fill; + dialogPanel.Location = new Point(823, 34); + dialogPanel.Name = "dialogPanel"; + dialogPanel.RowCount = 1; + dialogPanel.RowStyles.Add(new RowStyle()); + dialogPanel.Size = new Size(192, 31); + dialogPanel.TabIndex = 1; + // + // okBut + // + okBut.Location = new Point(3, 3); + okBut.Name = "okBut"; + okBut.Size = new Size(90, 25); + okBut.TabIndex = 0; + okBut.Values.Image = Properties.Resources.ok_16; + okBut.Values.Text = "确定(&O)"; + okBut.Click += okBut_Click; + // + // cancelBut + // + cancelBut.Location = new Point(99, 3); + cancelBut.Name = "cancelBut"; + cancelBut.Size = new Size(90, 25); + cancelBut.TabIndex = 0; + cancelBut.Values.Image = Properties.Resources.close_16; + cancelBut.Values.Text = "取消(&C)"; + cancelBut.Click += cancelBut_Click; + // + // SecurityActorEnquiryPage + // + AutoScaleDimensions = new SizeF(7F, 15F); + AutoScaleMode = AutoScaleMode.Font; + Controls.Add(mainPanel); + Name = "SecurityActorEnquiryPage"; + mainPanel.ResumeLayout(false); + mainPanel.PerformLayout(); + topPanel.ResumeLayout(false); + topPanel.PerformLayout(); + searchPanel.ResumeLayout(false); + contextPanel.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)dataGv).EndInit(); + bottomPanel.ResumeLayout(false); + bottomPanel.PerformLayout(); + operationPanel.ResumeLayout(false); + dialogPanel.ResumeLayout(false); + ResumeLayout(false); + } + + #endregion + + private TableLayoutPanel mainPanel; + private TableLayoutPanel topPanel; + private TableLayoutPanel searchPanel; + private Krypton.Toolkit.KryptonButton searchBut; + private Krypton.Toolkit.KryptonButton resetBut; + private Krypton.Toolkit.KryptonButton createBut; + private TableLayoutPanel contextPanel; + private TableLayoutPanel bottomPanel; + private TableLayoutPanel operationPanel; + private Krypton.Toolkit.KryptonButton viewBut; + private Krypton.Toolkit.KryptonButton amendBut; + private Krypton.Toolkit.KryptonButton deleteBut; + private Krypton.Toolkit.KryptonLabel searchActorNameLabel; + private Krypton.Toolkit.KryptonTextBox actorNameTxt; + private Krypton.Toolkit.KryptonDataGridView dataGv; + private TableLayoutPanel dialogPanel; + private Krypton.Toolkit.KryptonButton okBut; + private Krypton.Toolkit.KryptonButton cancelBut; + private CloudBuilder.Gui.GridViewPagination gridViewPagination; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn actorNameCol; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn actorLocalNameCol; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn actorEngNameCol; + } +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Security.Gui/SecurityActorEnquiryPage.cs b/CloudBuilder/CloudBuilder.Security.Gui/SecurityActorEnquiryPage.cs new file mode 100644 index 0000000..46c4034 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/SecurityActorEnquiryPage.cs @@ -0,0 +1,385 @@ +using ClosedXML.Excel; +using CloudBuilder.Core.DependencyInjection.Form; +using CloudBuilder.Core.Report; +using CloudBuilder.Core.Service; +using CloudBuilder.Gui; +using CloudBuilder.Gui.DependencyInjection; +using CloudBuilder.Request.Security; +using CloudBuilder.Security.Data; +using CloudBuilder.Security.Entity; +using CloudBuilder.Security.Linkup; +using CloudBuilder.Security.Policy; +using CloudBuilder.Security.SearchCriteria; +using DocumentFormat.OpenXml.Spreadsheet; +using Krypton.Toolkit; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http.Extensions; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.IdentityModel.Tokens; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + + +namespace CloudBuilder.Security.Gui +{ + public partial class SecurityActorEnquiryPage : AbstractPage + { + private SecurityActorEntity[] securityActors = null!; + private SecurityActorSearchCriteria searchCriteria = null!; + private BindingContextAttributeProvider provider; + private SecurityActorRequest securityActorRequest; + private SecurityMessagePolicy securityMessagePolicy; + + //初始化Page,注入容器内,不要在此做任何事情 + public SecurityActorEnquiryPage() + { + InitializeComponent(); + } + + /// + /// 第一次加载时执行,只执行一次 + /// + public override void FunctionLoaded() + { + try + { + base.FunctionLoaded(); + //初始化容器------------------------------------- + securityActorRequest = ServiceHelper.GetTypeService(); + securityMessagePolicy = ServiceHelper.GetTypeService()!; + + //界面初始化 + InitGui(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + /// + /// 每次从别的界面进入时执行,不包括下面的界面切换,发生在FunctionLoaded之后 + /// 这个是有参数传入,常用于查询界面进入到操作界面发生 + /// + /// + public override void FunctionActivated(object param) + { + base.FunctionActivated(param); + actorNameTxt.Focus(); + } + /// + /// 当Page被选中时执行,用于Tab导航的切换,没有参数变化,跟FunctionActivated有区别 + /// + public override void FunctionSelected() + { + this.ParentAbstractForm.AcceptButton = this.searchBut; + if (!IsDialog) + this.ParentAbstractForm.CancelButton = this.resetBut; + else + this.ParentAbstractForm.CancelButton = this.cancelBut; + + actorNameTxt.Focus(); + } + /// + /// 控件的初始化 + /// + private void InitGui() + { + //DataGridView初始化不要自动生成列,且允许重排列名操作 + dataGv.InitColumn(true, true); + //初始化绑定设置 + InitBindingContext(); + //设置显示模式 + SetDisplayMode(true); + + InitGridViewPagination(); + } + /// + /// DataGridView分页控件初始化 + /// + private void InitGridViewPagination() + { + searchCriteria = new SecurityActorSearchCriteria(); + gridViewPagination.SetLimit(searchCriteria.limit); + gridViewPagination.OnPaginationChanged += Search; + gridViewPagination.OnPrint += Print; + } + + /// + /// 打印当前查询结果 + /// + private void Print() + { + //設置查詢條件 + List searCriteria = new List(); + if (!string.IsNullOrEmpty(actorNameTxt.Text)) + searCriteria.Add(searchActorNameLabel.Text + actorNameTxt.Text); + + //設置每列的格式 + TemplateHeader[] headers = dataGv.GetTemplateHeaders(); + + //打印Excel + new DataToExcelHelper(null).PrintExcel(this.Parent.Text, this.Parent.Text, searCriteria, headers, securityActors); + } + + /// + /// 有特殊要求的UI控件初始化设置,使用guiOperateHelper管理 + /// + private void InitBindingContext() + { + InitPermission(); + + guiOperateHelper = new GuiOperateHelper(); + } + + private void InitPermission() + { + viewBut.Set(SecurityPermissionPolicy.SecurityActor, Operate.Find); + createBut.Set(SecurityPermissionPolicy.SecurityActor, Operate.Insert); + amendBut.Set(SecurityPermissionPolicy.SecurityActor, Operate.Update); + deleteBut.Set(SecurityPermissionPolicy.SecurityActor, Operate.Delete); + } + + private void SetDisplayMode(bool enable) + { + guiOperateHelper.EnableControls(true, this.searchPanel, this.bottomPanel); + guiOperateHelper.EnableControls(false, dataGv); + + if (securityActors != null) + guiOperateHelper.EnableControls(enable, viewBut, amendBut, deleteBut); + else + guiOperateHelper.EnableControls(false, viewBut, amendBut, deleteBut); + + //如果是弹出的窗口,不显示 + createBut.Visible = !IsDialog; + dialogPanel.Visible = IsDialog; + operationPanel.Visible = !IsDialog; + + this.actorNameTxt.Focus(); + } + + private void searchBut_Click(object sender, EventArgs e) + { + HandleException(() => Search()); + } + + /// + /// 与Web同步写法 + /// + /// + private SecurityActorSearchCriteria PackSearchCriteria() + { + searchCriteria = new SecurityActorSearchCriteria(); + searchCriteria.limit = gridViewPagination.Limit; + searchCriteria.page = gridViewPagination.CurrentPage; + + List filters = new List(); + + SearchFilter filter = new SearchFilter(); + filter.Column = SecurityActorEntity.DB_ACTOR_NAME; + filter.Type = SearchFilterTypePolicy.TEXT; + filter.Operator = SearchFilterOperatorPolicy.CONTAIN; + filter.Value = actorNameTxt.GetValue(); + filters.Add(filter); + + searchCriteria.Filter = filters.ToArray(); + + return searchCriteria; + } + + private void Search() + { + try + { + var data = securityActorRequest.FindBySearchCriteria(PackSearchCriteria()); + + if (data != null) securityActors = data.Datas; + + gridViewPagination.SetTotal(data.Total); + + if (securityActors == null || securityActors.Length == 0) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + guiOperateHelper.ResetControls(this.dataGv); + return; + } + + dataGv.SetDataSource(securityActors); + + SetDisplayMode(true); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void resetBut_Click(object sender, EventArgs e) + { + guiOperateHelper.ResetControls(this.mainPanel); + + SetDisplayMode(false); + } + + private void createBut_Click(object sender, EventArgs e) + { + DisplayPage(GuiDisplayMode.Create, null); + } + + private void DisplayPage(GuiDisplayMode mode, string actorName) + { + SecurityActorOperationLinkup linkupData = new SecurityActorOperationLinkup(); + linkupData.DisplayMode = Convert.ToInt32(mode); + linkupData.ActorName = actorName; + + this.DisplayAbstractPage(typeof(SecurityActorOperationPage).Name, linkupData); + } + + + private void viewBut_Click(object sender, EventArgs e) + { + if (dataGv.RowCount <= 0 || dataGv.SelectedCells.Count <= 0) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + return; + } + + SecurityActorEntity data = dataGv.GetRowData(dataGv.SelectedCells[0].RowIndex); + + DisplayPage(GuiDisplayMode.View, data.ActorName); + } + + private void amendBut_Click(object sender, EventArgs e) + { + if (dataGv.RowCount <= 0 || dataGv.SelectedCells.Count <= 0) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + return; + } + + SecurityActorEntity data = dataGv.GetRowData(dataGv.SelectedCells[0].RowIndex); + + DisplayPage(GuiDisplayMode.Amend, data.ActorName); + } + + private void deleteBut_Click(object sender, EventArgs e) + { + HandleException(() => Delete()); + } + + private void Delete() + { + if (dataGv.RowCount <= 0 || dataGv.SelectedCells.Count <= 0) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + return; + } + + if (DialogResult.Yes != ShowMessageBox.ShowOption(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_CONFIRM_DEL_NULL), securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_DELETE))) return; + + SecurityActorEntity[] datas = dataGv.GetSelectedCellsData(); + + securityActorRequest.Deletes(datas.Select(x => x.ActorName).ToArray()); + + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_SUCCEED_DELETED_NULL)); + + Search(); + } + + private void okBut_Click(object sender, EventArgs e) + { + try + { + if (dataGv.RowCount <= 0 || dataGv.SelectedCells.Count <= 0) return; + //SecurityActorEntity data = dataGv.GetRowData(dataGv.SelectedCells[0].RowIndex); + SecurityActorEntity[] datas = dataGv.GetSelectedCellsData(); + + this.ParentAbstractForm.OutputData = datas; + this.ParentAbstractForm.DialogResult = DialogResult.OK; + this.ParentAbstractForm.Close(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void cancelBut_Click(object sender, EventArgs e) + { + try + { + this.ParentAbstractForm.DialogResult = DialogResult.Cancel; + this.ParentAbstractForm.Close(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void dataGv_CellDoubleClick(object sender, DataGridViewCellEventArgs e) + { + try + { + if (IsDialog) + okBut_Click(null, null); + else + viewBut_Click(null, null); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + } +} diff --git a/CloudBuilder/CloudBuilder.Security.Gui/SecurityActorEnquiryPage.resx b/CloudBuilder/CloudBuilder.Security.Gui/SecurityActorEnquiryPage.resx new file mode 100644 index 0000000..6f0defd --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/SecurityActorEnquiryPage.resx @@ -0,0 +1,159 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Security.Gui/SecurityActorOperationPage.Designer.cs b/CloudBuilder/CloudBuilder.Security.Gui/SecurityActorOperationPage.Designer.cs new file mode 100644 index 0000000..9b7fe78 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/SecurityActorOperationPage.Designer.cs @@ -0,0 +1,944 @@ +namespace CloudBuilder.Security.Gui +{ + partial class SecurityActorOperationPage + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + DataGridViewCellStyle dataGridViewCellStyle6 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle5 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle7 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle8 = new DataGridViewCellStyle(); + tableLayoutPanel2 = new TableLayoutPanel(); + actorNameLabel = new Krypton.Toolkit.KryptonLabel(); + actorLocalNameLabel = new Krypton.Toolkit.KryptonLabel(); + actorEngNameLabel = new Krypton.Toolkit.KryptonLabel(); + actorNameTxt = new Krypton.Toolkit.KryptonTextBox(); + actorLocalNameTxt = new Krypton.Toolkit.KryptonTextBox(); + actorEngNameTxt = new Krypton.Toolkit.KryptonTextBox(); + kryptonPanel2 = new Krypton.Toolkit.KryptonPanel(); + splitContainer1 = new SplitContainer(); + tableLayoutPanel3 = new TableLayoutPanel(); + tableLayoutPanel4 = new TableLayoutPanel(); + selectedGv = new Krypton.Toolkit.KryptonDataGridView(); + groupNameSelectedCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + groupLocalNameSelectedCol = new DataGridViewComboBoxColumn(); + kryptonHeader1 = new Krypton.Toolkit.KryptonHeader(); + tableLayoutPanel5 = new TableLayoutPanel(); + deselectedBut = new Krypton.Toolkit.KryptonButton(); + selectedBut = new Krypton.Toolkit.KryptonButton(); + tableLayoutPanel6 = new TableLayoutPanel(); + kryptonHeader2 = new Krypton.Toolkit.KryptonHeader(); + deselectedGv = new Krypton.Toolkit.KryptonDataGridView(); + groupNameCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + groupLocalNameCol = new DataGridViewComboBoxColumn(); + mainPanel = new TableLayoutPanel(); + topPanel = new TableLayoutPanel(); + searchPanel = new TableLayoutPanel(); + createBut = new Krypton.Toolkit.KryptonButton(); + resetBut = new Krypton.Toolkit.KryptonButton(); + searchBut = new Krypton.Toolkit.KryptonButton(); + actorNameSearchLabel = new Krypton.Toolkit.KryptonLabel(); + actorNameSearchTxt = new Krypton.Toolkit.KryptonTextBox(); + actorNameSearchBut = new Krypton.Toolkit.ButtonSpecAny(); + kryptonPanel1 = new Krypton.Toolkit.KryptonPanel(); + bottomPanel = new TableLayoutPanel(); + savePanel = new TableLayoutPanel(); + cancelBut = new Krypton.Toolkit.KryptonButton(); + saveBut = new Krypton.Toolkit.KryptonButton(); + operationPanel = new TableLayoutPanel(); + deleteBut = new Krypton.Toolkit.KryptonButton(); + amendBut = new Krypton.Toolkit.KryptonButton(); + contentPanel = new TableLayoutPanel(); + splitContainer2 = new SplitContainer(); + tableLayoutPanel1 = new TableLayoutPanel(); + tableLayoutPanel7 = new TableLayoutPanel(); + selectedUserGv = new Krypton.Toolkit.KryptonDataGridView(); + userNameSelectedCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + userLocalNameSelectedCol = new DataGridViewComboBoxColumn(); + kryptonHeader3 = new Krypton.Toolkit.KryptonHeader(); + tableLayoutPanel8 = new TableLayoutPanel(); + userDeselectedBut = new Krypton.Toolkit.KryptonButton(); + userSelectedBut = new Krypton.Toolkit.KryptonButton(); + tableLayoutPanel9 = new TableLayoutPanel(); + kryptonHeader4 = new Krypton.Toolkit.KryptonHeader(); + deselectedUserGv = new Krypton.Toolkit.KryptonDataGridView(); + userNameCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + userLocalNameCol = new DataGridViewComboBoxColumn(); + kryptonPanel3 = new Krypton.Toolkit.KryptonPanel(); + tableLayoutPanel2.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)kryptonPanel2).BeginInit(); + ((System.ComponentModel.ISupportInitialize)splitContainer1).BeginInit(); + splitContainer1.Panel1.SuspendLayout(); + splitContainer1.Panel2.SuspendLayout(); + splitContainer1.SuspendLayout(); + tableLayoutPanel3.SuspendLayout(); + tableLayoutPanel4.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)selectedGv).BeginInit(); + tableLayoutPanel5.SuspendLayout(); + tableLayoutPanel6.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)deselectedGv).BeginInit(); + mainPanel.SuspendLayout(); + topPanel.SuspendLayout(); + searchPanel.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)kryptonPanel1).BeginInit(); + bottomPanel.SuspendLayout(); + savePanel.SuspendLayout(); + operationPanel.SuspendLayout(); + contentPanel.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)splitContainer2).BeginInit(); + splitContainer2.Panel1.SuspendLayout(); + splitContainer2.Panel2.SuspendLayout(); + splitContainer2.SuspendLayout(); + tableLayoutPanel1.SuspendLayout(); + tableLayoutPanel7.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)selectedUserGv).BeginInit(); + tableLayoutPanel8.SuspendLayout(); + tableLayoutPanel9.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)deselectedUserGv).BeginInit(); + ((System.ComponentModel.ISupportInitialize)kryptonPanel3).BeginInit(); + SuspendLayout(); + // + // tableLayoutPanel2 + // + tableLayoutPanel2.AutoSize = true; + tableLayoutPanel2.AutoSizeMode = AutoSizeMode.GrowAndShrink; + tableLayoutPanel2.ColumnCount = 2; + tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel2.Controls.Add(actorNameLabel, 0, 0); + tableLayoutPanel2.Controls.Add(actorLocalNameLabel, 0, 1); + tableLayoutPanel2.Controls.Add(actorEngNameLabel, 0, 2); + tableLayoutPanel2.Controls.Add(actorNameTxt, 1, 0); + tableLayoutPanel2.Controls.Add(actorLocalNameTxt, 1, 1); + tableLayoutPanel2.Controls.Add(actorEngNameTxt, 1, 2); + tableLayoutPanel2.Location = new Point(3, 3); + tableLayoutPanel2.Name = "tableLayoutPanel2"; + tableLayoutPanel2.RowCount = 3; + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.Size = new Size(364, 87); + tableLayoutPanel2.TabIndex = 0; + // + // actorNameLabel + // + actorNameLabel.Location = new Point(3, 3); + actorNameLabel.Name = "actorNameLabel"; + actorNameLabel.Size = new Size(52, 20); + actorNameLabel.TabIndex = 1; + actorNameLabel.Values.Text = "角色名:"; + // + // actorLocalNameLabel + // + actorLocalNameLabel.Location = new Point(3, 32); + actorLocalNameLabel.Name = "actorLocalNameLabel"; + actorLocalNameLabel.Size = new Size(52, 20); + actorLocalNameLabel.TabIndex = 1; + actorLocalNameLabel.Values.Text = "中文名:"; + // + // actorEngNameLabel + // + actorEngNameLabel.Location = new Point(3, 61); + actorEngNameLabel.Name = "actorEngNameLabel"; + actorEngNameLabel.Size = new Size(52, 20); + actorEngNameLabel.TabIndex = 1; + actorEngNameLabel.Values.Text = "英文名:"; + // + // actorNameTxt + // + actorNameTxt.Dock = DockStyle.Fill; + actorNameTxt.Location = new Point(61, 3); + actorNameTxt.MaxLength = 50; + actorNameTxt.Name = "actorNameTxt"; + actorNameTxt.Size = new Size(300, 23); + actorNameTxt.TabIndex = 3; + // + // actorLocalNameTxt + // + actorLocalNameTxt.Dock = DockStyle.Fill; + actorLocalNameTxt.Location = new Point(61, 32); + actorLocalNameTxt.MaxLength = 50; + actorLocalNameTxt.Name = "actorLocalNameTxt"; + actorLocalNameTxt.Size = new Size(300, 23); + actorLocalNameTxt.TabIndex = 3; + // + // actorEngNameTxt + // + actorEngNameTxt.Dock = DockStyle.Fill; + actorEngNameTxt.Location = new Point(61, 61); + actorEngNameTxt.MaxLength = 50; + actorEngNameTxt.Name = "actorEngNameTxt"; + actorEngNameTxt.Size = new Size(300, 23); + actorEngNameTxt.TabIndex = 3; + // + // kryptonPanel2 + // + kryptonPanel2.Dock = DockStyle.Fill; + kryptonPanel2.Location = new Point(3, 96); + kryptonPanel2.Name = "kryptonPanel2"; + kryptonPanel2.Size = new Size(1018, 5); + kryptonPanel2.TabIndex = 1; + // + // splitContainer1 + // + splitContainer1.BackColor = SystemColors.GradientActiveCaption; + splitContainer1.Dock = DockStyle.Fill; + splitContainer1.Location = new Point(3, 107); + splitContainer1.Name = "splitContainer1"; + // + // splitContainer1.Panel1 + // + splitContainer1.Panel1.Controls.Add(tableLayoutPanel3); + // + // splitContainer1.Panel2 + // + splitContainer1.Panel2.Controls.Add(tableLayoutPanel6); + splitContainer1.Size = new Size(1018, 500); + splitContainer1.SplitterDistance = 500; + splitContainer1.SplitterWidth = 8; + splitContainer1.TabIndex = 2; + // + // tableLayoutPanel3 + // + tableLayoutPanel3.BackColor = SystemColors.Control; + tableLayoutPanel3.ColumnCount = 2; + tableLayoutPanel3.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F)); + tableLayoutPanel3.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel3.Controls.Add(tableLayoutPanel4, 0, 0); + tableLayoutPanel3.Controls.Add(tableLayoutPanel5, 1, 0); + tableLayoutPanel3.Dock = DockStyle.Fill; + tableLayoutPanel3.Location = new Point(0, 0); + tableLayoutPanel3.Name = "tableLayoutPanel3"; + tableLayoutPanel3.RowCount = 1; + tableLayoutPanel3.RowStyles.Add(new RowStyle()); + tableLayoutPanel3.Size = new Size(500, 500); + tableLayoutPanel3.TabIndex = 0; + // + // tableLayoutPanel4 + // + tableLayoutPanel4.ColumnCount = 1; + tableLayoutPanel4.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F)); + tableLayoutPanel4.Controls.Add(selectedGv, 0, 1); + tableLayoutPanel4.Controls.Add(kryptonHeader1, 0, 0); + tableLayoutPanel4.Dock = DockStyle.Fill; + tableLayoutPanel4.Location = new Point(0, 0); + tableLayoutPanel4.Margin = new Padding(0); + tableLayoutPanel4.Name = "tableLayoutPanel4"; + tableLayoutPanel4.RowCount = 2; + tableLayoutPanel4.RowStyles.Add(new RowStyle()); + tableLayoutPanel4.RowStyles.Add(new RowStyle(SizeType.Percent, 50F)); + tableLayoutPanel4.Size = new Size(458, 500); + tableLayoutPanel4.TabIndex = 1; + // + // selectedGv + // + selectedGv.AllowUserToAddRows = false; + selectedGv.AllowUserToDeleteRows = false; + selectedGv.BorderStyle = BorderStyle.None; + selectedGv.Columns.AddRange(new DataGridViewColumn[] { groupNameSelectedCol, groupLocalNameSelectedCol }); + selectedGv.Dock = DockStyle.Fill; + selectedGv.Location = new Point(0, 31); + selectedGv.Margin = new Padding(0); + selectedGv.Name = "selectedGv"; + selectedGv.Size = new Size(458, 469); + selectedGv.TabIndex = 2; + selectedGv.CellDoubleClick += selectedGv_CellDoubleClick; + // + // groupNameSelectedCol + // + groupNameSelectedCol.DataPropertyName = "GroupName"; + groupNameSelectedCol.DefaultCellStyle = dataGridViewCellStyle6; + groupNameSelectedCol.HeaderText = "组别名"; + groupNameSelectedCol.Name = "groupNameSelectedCol"; + groupNameSelectedCol.Width = 200; + // + // groupLocalNameSelectedCol + // + groupLocalNameSelectedCol.DataPropertyName = "GroupName"; + groupLocalNameSelectedCol.DisplayStyle = DataGridViewComboBoxDisplayStyle.Nothing; + groupLocalNameSelectedCol.HeaderText = "组别中文名"; + groupLocalNameSelectedCol.Name = "groupLocalNameSelectedCol"; + groupLocalNameSelectedCol.Resizable = DataGridViewTriState.True; + groupLocalNameSelectedCol.Width = 200; + // + // kryptonHeader1 + // + kryptonHeader1.Dock = DockStyle.Top; + kryptonHeader1.Location = new Point(0, 0); + kryptonHeader1.Margin = new Padding(0); + kryptonHeader1.Name = "kryptonHeader1"; + kryptonHeader1.Size = new Size(458, 31); + kryptonHeader1.TabIndex = 0; + kryptonHeader1.Values.Description = ""; + kryptonHeader1.Values.Heading = "授权组别"; + kryptonHeader1.Values.Image = null; + // + // tableLayoutPanel5 + // + tableLayoutPanel5.AutoSize = true; + tableLayoutPanel5.ColumnCount = 1; + tableLayoutPanel5.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel5.Controls.Add(deselectedBut, 0, 2); + tableLayoutPanel5.Controls.Add(selectedBut, 0, 1); + tableLayoutPanel5.Dock = DockStyle.Fill; + tableLayoutPanel5.Location = new Point(461, 3); + tableLayoutPanel5.Name = "tableLayoutPanel5"; + tableLayoutPanel5.RowCount = 4; + tableLayoutPanel5.RowStyles.Add(new RowStyle(SizeType.Percent, 50F)); + tableLayoutPanel5.RowStyles.Add(new RowStyle()); + tableLayoutPanel5.RowStyles.Add(new RowStyle()); + tableLayoutPanel5.RowStyles.Add(new RowStyle(SizeType.Percent, 50F)); + tableLayoutPanel5.Size = new Size(36, 494); + tableLayoutPanel5.TabIndex = 1; + // + // deselectedBut + // + deselectedBut.Location = new Point(3, 277); + deselectedBut.Margin = new Padding(3, 30, 3, 3); + deselectedBut.Name = "deselectedBut"; + deselectedBut.Size = new Size(30, 25); + deselectedBut.TabIndex = 0; + deselectedBut.Values.Image = Properties.Resources.MovePrevious; + deselectedBut.Values.Text = ""; + deselectedBut.Click += deselectedBut_Click; + // + // selectedBut + // + selectedBut.Location = new Point(3, 192); + selectedBut.Margin = new Padding(3, 3, 3, 30); + selectedBut.Name = "selectedBut"; + selectedBut.Size = new Size(30, 25); + selectedBut.TabIndex = 0; + selectedBut.Values.Image = Properties.Resources.MoveNext; + selectedBut.Values.Text = ""; + selectedBut.Click += selectedBut_Click; + // + // tableLayoutPanel6 + // + tableLayoutPanel6.BackColor = SystemColors.Control; + tableLayoutPanel6.ColumnCount = 1; + tableLayoutPanel6.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F)); + tableLayoutPanel6.Controls.Add(kryptonHeader2, 0, 0); + tableLayoutPanel6.Controls.Add(deselectedGv, 0, 1); + tableLayoutPanel6.Dock = DockStyle.Fill; + tableLayoutPanel6.Location = new Point(0, 0); + tableLayoutPanel6.Name = "tableLayoutPanel6"; + tableLayoutPanel6.Padding = new Padding(4, 0, 0, 0); + tableLayoutPanel6.RowCount = 2; + tableLayoutPanel6.RowStyles.Add(new RowStyle()); + tableLayoutPanel6.RowStyles.Add(new RowStyle(SizeType.Percent, 83.39552F)); + tableLayoutPanel6.Size = new Size(510, 500); + tableLayoutPanel6.TabIndex = 0; + // + // kryptonHeader2 + // + kryptonHeader2.Dock = DockStyle.Top; + kryptonHeader2.Location = new Point(4, 0); + kryptonHeader2.Margin = new Padding(0); + kryptonHeader2.Name = "kryptonHeader2"; + kryptonHeader2.Size = new Size(506, 31); + kryptonHeader2.TabIndex = 1; + kryptonHeader2.Values.Description = ""; + kryptonHeader2.Values.Heading = "未授权组别"; + kryptonHeader2.Values.Image = null; + // + // deselectedGv + // + deselectedGv.AllowUserToAddRows = false; + deselectedGv.AllowUserToDeleteRows = false; + deselectedGv.BorderStyle = BorderStyle.None; + deselectedGv.Columns.AddRange(new DataGridViewColumn[] { groupNameCol, groupLocalNameCol }); + deselectedGv.Dock = DockStyle.Fill; + deselectedGv.Location = new Point(4, 31); + deselectedGv.Margin = new Padding(0); + deselectedGv.Name = "deselectedGv"; + deselectedGv.Size = new Size(506, 469); + deselectedGv.TabIndex = 1; + deselectedGv.CellDoubleClick += deselectedGv_CellDoubleClick; + // + // groupNameCol + // + groupNameCol.DataPropertyName = "GroupName"; + groupNameCol.DefaultCellStyle = dataGridViewCellStyle5; + groupNameCol.HeaderText = "组别名"; + groupNameCol.Name = "groupNameCol"; + groupNameCol.Width = 200; + // + // groupLocalNameCol + // + groupLocalNameCol.DataPropertyName = "GroupName"; + groupLocalNameCol.DisplayStyle = DataGridViewComboBoxDisplayStyle.Nothing; + groupLocalNameCol.HeaderText = "组别中文名"; + groupLocalNameCol.Name = "groupLocalNameCol"; + groupLocalNameCol.Resizable = DataGridViewTriState.True; + groupLocalNameCol.Width = 200; + // + // mainPanel + // + mainPanel.ColumnCount = 1; + mainPanel.ColumnStyles.Add(new ColumnStyle()); + mainPanel.Controls.Add(topPanel, 0, 0); + mainPanel.Controls.Add(kryptonPanel1, 0, 1); + mainPanel.Controls.Add(bottomPanel, 0, 3); + mainPanel.Controls.Add(contentPanel, 0, 2); + mainPanel.Dock = DockStyle.Fill; + mainPanel.Location = new Point(0, 0); + mainPanel.Name = "mainPanel"; + mainPanel.RowCount = 4; + mainPanel.RowStyles.Add(new RowStyle()); + mainPanel.RowStyles.Add(new RowStyle()); + mainPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 100F)); + mainPanel.RowStyles.Add(new RowStyle()); + mainPanel.Size = new Size(1024, 800); + mainPanel.TabIndex = 1; + // + // topPanel + // + topPanel.AutoSize = true; + topPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + topPanel.ColumnCount = 3; + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 20F)); + topPanel.Controls.Add(searchPanel, 3, 0); + topPanel.Controls.Add(actorNameSearchLabel, 0, 0); + topPanel.Controls.Add(actorNameSearchTxt, 1, 0); + topPanel.Dock = DockStyle.Fill; + topPanel.Location = new Point(3, 3); + topPanel.Name = "topPanel"; + topPanel.RowCount = 1; + topPanel.RowStyles.Add(new RowStyle()); + topPanel.Size = new Size(1018, 31); + topPanel.TabIndex = 0; + // + // searchPanel + // + searchPanel.AutoSize = true; + searchPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + searchPanel.ColumnCount = 3; + searchPanel.ColumnStyles.Add(new ColumnStyle()); + searchPanel.ColumnStyles.Add(new ColumnStyle()); + searchPanel.ColumnStyles.Add(new ColumnStyle()); + searchPanel.Controls.Add(createBut, 2, 0); + searchPanel.Controls.Add(resetBut, 1, 0); + searchPanel.Controls.Add(searchBut, 0, 0); + searchPanel.Location = new Point(424, 0); + searchPanel.Margin = new Padding(60, 0, 0, 0); + searchPanel.Name = "searchPanel"; + searchPanel.RowCount = 1; + searchPanel.RowStyles.Add(new RowStyle()); + searchPanel.Size = new Size(288, 31); + searchPanel.TabIndex = 0; + // + // createBut + // + createBut.Location = new Point(195, 3); + createBut.Name = "createBut"; + createBut.Size = new Size(90, 25); + createBut.TabIndex = 3; + createBut.Values.Image = Properties.Resources.create_16; + createBut.Values.Text = "新增(&C)"; + createBut.Click += createBut_Click; + // + // resetBut + // + resetBut.Location = new Point(99, 3); + resetBut.Name = "resetBut"; + resetBut.Size = new Size(90, 25); + resetBut.TabIndex = 2; + resetBut.Values.Image = Properties.Resources.reset_16; + resetBut.Values.Text = "重置(&R)"; + resetBut.Click += resetBut_Click; + // + // searchBut + // + searchBut.Location = new Point(3, 3); + searchBut.Name = "searchBut"; + searchBut.Size = new Size(90, 25); + searchBut.TabIndex = 1; + searchBut.Values.Image = Properties.Resources.search_16; + searchBut.Values.Text = "查询(&S)"; + searchBut.Click += searchBut_Click; + // + // actorNameSearchLabel + // + actorNameSearchLabel.Location = new Point(3, 3); + actorNameSearchLabel.Name = "actorNameSearchLabel"; + actorNameSearchLabel.Size = new Size(52, 20); + actorNameSearchLabel.TabIndex = 1; + actorNameSearchLabel.Values.Text = "角色名:"; + // + // actorNameSearchTxt + // + actorNameSearchTxt.ButtonSpecs.Add(actorNameSearchBut); + actorNameSearchTxt.Location = new Point(61, 3); + actorNameSearchTxt.Name = "actorNameSearchTxt"; + actorNameSearchTxt.Size = new Size(300, 23); + actorNameSearchTxt.TabIndex = 2; + // + // actorNameSearchBut + // + actorNameSearchBut.Type = Krypton.Toolkit.PaletteButtonSpecStyle.WorkspaceMaximize; + actorNameSearchBut.UniqueName = "3a322a66645f4aff808be4720c638ad8"; + actorNameSearchBut.Click += actorNameSearchBut_Click; + // + // kryptonPanel1 + // + kryptonPanel1.Dock = DockStyle.Fill; + kryptonPanel1.Location = new Point(3, 40); + kryptonPanel1.Name = "kryptonPanel1"; + kryptonPanel1.Size = new Size(1018, 5); + kryptonPanel1.TabIndex = 1; + // + // bottomPanel + // + bottomPanel.AutoSize = true; + bottomPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + bottomPanel.ColumnCount = 1; + bottomPanel.ColumnStyles.Add(new ColumnStyle()); + bottomPanel.Controls.Add(savePanel, 0, 0); + bottomPanel.Controls.Add(operationPanel, 0, 1); + bottomPanel.Location = new Point(0, 726); + bottomPanel.Margin = new Padding(0); + bottomPanel.Name = "bottomPanel"; + bottomPanel.RowCount = 2; + bottomPanel.RowStyles.Add(new RowStyle()); + bottomPanel.RowStyles.Add(new RowStyle()); + bottomPanel.Size = new Size(198, 74); + bottomPanel.TabIndex = 2; + // + // savePanel + // + savePanel.AutoSize = true; + savePanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + savePanel.ColumnCount = 2; + savePanel.ColumnStyles.Add(new ColumnStyle()); + savePanel.ColumnStyles.Add(new ColumnStyle()); + savePanel.Controls.Add(cancelBut, 1, 0); + savePanel.Controls.Add(saveBut, 0, 0); + savePanel.Location = new Point(3, 3); + savePanel.Name = "savePanel"; + savePanel.RowCount = 1; + savePanel.RowStyles.Add(new RowStyle()); + savePanel.Size = new Size(192, 31); + savePanel.TabIndex = 0; + // + // cancelBut + // + cancelBut.Location = new Point(99, 3); + cancelBut.Name = "cancelBut"; + cancelBut.Size = new Size(90, 25); + cancelBut.TabIndex = 2; + cancelBut.Values.Image = Properties.Resources.cancel_16; + cancelBut.Values.Text = "取消(&L)"; + cancelBut.Click += cancelBut_Click; + // + // saveBut + // + saveBut.Location = new Point(3, 3); + saveBut.Name = "saveBut"; + saveBut.Size = new Size(90, 25); + saveBut.TabIndex = 1; + saveBut.Values.Image = Properties.Resources.save_16; + saveBut.Values.Text = "保存(&S)"; + saveBut.Click += saveBut_Click; + // + // operationPanel + // + operationPanel.AutoSize = true; + operationPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + operationPanel.ColumnCount = 2; + operationPanel.ColumnStyles.Add(new ColumnStyle()); + operationPanel.ColumnStyles.Add(new ColumnStyle()); + operationPanel.Controls.Add(deleteBut, 1, 0); + operationPanel.Controls.Add(amendBut, 0, 0); + operationPanel.Location = new Point(3, 40); + operationPanel.Name = "operationPanel"; + operationPanel.RowCount = 1; + operationPanel.RowStyles.Add(new RowStyle()); + operationPanel.Size = new Size(192, 31); + operationPanel.TabIndex = 0; + // + // deleteBut + // + deleteBut.Location = new Point(99, 3); + deleteBut.Name = "deleteBut"; + deleteBut.Size = new Size(90, 25); + deleteBut.TabIndex = 2; + deleteBut.Values.Image = Properties.Resources.delete_16; + deleteBut.Values.Text = "删除(&D)"; + deleteBut.Click += deleteBut_Click; + // + // amendBut + // + amendBut.Location = new Point(3, 3); + amendBut.Name = "amendBut"; + amendBut.Size = new Size(90, 25); + amendBut.TabIndex = 1; + amendBut.Values.Image = Properties.Resources.amend_16; + amendBut.Values.Text = "修改(&M)"; + amendBut.Click += amendBut_Click; + // + // contentPanel + // + contentPanel.AutoScroll = true; + contentPanel.ColumnCount = 1; + contentPanel.ColumnStyles.Add(new ColumnStyle()); + contentPanel.Controls.Add(splitContainer2, 0, 4); + contentPanel.Controls.Add(kryptonPanel3, 0, 3); + contentPanel.Controls.Add(tableLayoutPanel2, 0, 0); + contentPanel.Controls.Add(kryptonPanel2, 0, 1); + contentPanel.Controls.Add(splitContainer1, 0, 2); + contentPanel.Dock = DockStyle.Fill; + contentPanel.Location = new Point(3, 51); + contentPanel.Name = "contentPanel"; + contentPanel.RowCount = 5; + contentPanel.RowStyles.Add(new RowStyle()); + contentPanel.RowStyles.Add(new RowStyle()); + contentPanel.RowStyles.Add(new RowStyle()); + contentPanel.RowStyles.Add(new RowStyle()); + contentPanel.RowStyles.Add(new RowStyle()); + contentPanel.Size = new Size(1018, 672); + contentPanel.TabIndex = 3; + // + // splitContainer2 + // + splitContainer2.BackColor = SystemColors.GradientActiveCaption; + splitContainer2.Dock = DockStyle.Fill; + splitContainer2.Location = new Point(3, 624); + splitContainer2.Name = "splitContainer2"; + // + // splitContainer2.Panel1 + // + splitContainer2.Panel1.Controls.Add(tableLayoutPanel1); + // + // splitContainer2.Panel2 + // + splitContainer2.Panel2.Controls.Add(tableLayoutPanel9); + splitContainer2.Size = new Size(1018, 500); + splitContainer2.SplitterDistance = 500; + splitContainer2.SplitterWidth = 8; + splitContainer2.TabIndex = 4; + // + // tableLayoutPanel1 + // + tableLayoutPanel1.BackColor = SystemColors.Control; + tableLayoutPanel1.ColumnCount = 2; + tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F)); + tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel1.Controls.Add(tableLayoutPanel7, 0, 0); + tableLayoutPanel1.Controls.Add(tableLayoutPanel8, 1, 0); + tableLayoutPanel1.Dock = DockStyle.Fill; + tableLayoutPanel1.Location = new Point(0, 0); + tableLayoutPanel1.Name = "tableLayoutPanel1"; + tableLayoutPanel1.RowCount = 1; + tableLayoutPanel1.RowStyles.Add(new RowStyle()); + tableLayoutPanel1.Size = new Size(500, 500); + tableLayoutPanel1.TabIndex = 0; + // + // tableLayoutPanel7 + // + tableLayoutPanel7.ColumnCount = 1; + tableLayoutPanel7.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F)); + tableLayoutPanel7.Controls.Add(selectedUserGv, 0, 1); + tableLayoutPanel7.Controls.Add(kryptonHeader3, 0, 0); + tableLayoutPanel7.Dock = DockStyle.Fill; + tableLayoutPanel7.Location = new Point(0, 0); + tableLayoutPanel7.Margin = new Padding(0); + tableLayoutPanel7.Name = "tableLayoutPanel7"; + tableLayoutPanel7.RowCount = 2; + tableLayoutPanel7.RowStyles.Add(new RowStyle()); + tableLayoutPanel7.RowStyles.Add(new RowStyle(SizeType.Percent, 50F)); + tableLayoutPanel7.Size = new Size(458, 500); + tableLayoutPanel7.TabIndex = 1; + // + // selectedUserGv + // + selectedUserGv.AllowUserToAddRows = false; + selectedUserGv.AllowUserToDeleteRows = false; + selectedUserGv.BorderStyle = BorderStyle.None; + selectedUserGv.Columns.AddRange(new DataGridViewColumn[] { userNameSelectedCol, userLocalNameSelectedCol }); + selectedUserGv.Dock = DockStyle.Fill; + selectedUserGv.Location = new Point(0, 31); + selectedUserGv.Margin = new Padding(0); + selectedUserGv.Name = "selectedUserGv"; + selectedUserGv.Size = new Size(458, 469); + selectedUserGv.TabIndex = 2; + // + // userNameSelectedCol + // + userNameSelectedCol.DataPropertyName = "UserName"; + userNameSelectedCol.DefaultCellStyle = dataGridViewCellStyle7; + userNameSelectedCol.HeaderText = "用户名"; + userNameSelectedCol.Name = "userNameSelectedCol"; + userNameSelectedCol.Resizable = DataGridViewTriState.True; + userNameSelectedCol.Width = 200; + // + // userLocalNameSelectedCol + // + userLocalNameSelectedCol.DataPropertyName = "UserName"; + userLocalNameSelectedCol.DisplayStyle = DataGridViewComboBoxDisplayStyle.Nothing; + userLocalNameSelectedCol.HeaderText = "用户中文名"; + userLocalNameSelectedCol.Name = "userLocalNameSelectedCol"; + userLocalNameSelectedCol.Resizable = DataGridViewTriState.True; + userLocalNameSelectedCol.SortMode = DataGridViewColumnSortMode.Automatic; + userLocalNameSelectedCol.Width = 200; + // + // kryptonHeader3 + // + kryptonHeader3.Dock = DockStyle.Top; + kryptonHeader3.Location = new Point(0, 0); + kryptonHeader3.Margin = new Padding(0); + kryptonHeader3.Name = "kryptonHeader3"; + kryptonHeader3.Size = new Size(458, 31); + kryptonHeader3.TabIndex = 0; + kryptonHeader3.Values.Description = ""; + kryptonHeader3.Values.Heading = "授权用户"; + kryptonHeader3.Values.Image = null; + // + // tableLayoutPanel8 + // + tableLayoutPanel8.AutoSize = true; + tableLayoutPanel8.ColumnCount = 1; + tableLayoutPanel8.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel8.Controls.Add(userDeselectedBut, 0, 2); + tableLayoutPanel8.Controls.Add(userSelectedBut, 0, 1); + tableLayoutPanel8.Dock = DockStyle.Fill; + tableLayoutPanel8.Location = new Point(461, 3); + tableLayoutPanel8.Name = "tableLayoutPanel8"; + tableLayoutPanel8.RowCount = 4; + tableLayoutPanel8.RowStyles.Add(new RowStyle(SizeType.Percent, 50F)); + tableLayoutPanel8.RowStyles.Add(new RowStyle()); + tableLayoutPanel8.RowStyles.Add(new RowStyle()); + tableLayoutPanel8.RowStyles.Add(new RowStyle(SizeType.Percent, 50F)); + tableLayoutPanel8.Size = new Size(36, 494); + tableLayoutPanel8.TabIndex = 1; + // + // userDeselectedBut + // + userDeselectedBut.Location = new Point(3, 277); + userDeselectedBut.Margin = new Padding(3, 30, 3, 3); + userDeselectedBut.Name = "userDeselectedBut"; + userDeselectedBut.Size = new Size(30, 25); + userDeselectedBut.TabIndex = 0; + userDeselectedBut.Values.Image = Properties.Resources.MovePrevious; + userDeselectedBut.Values.Text = ""; + userDeselectedBut.Click += userDeselectedBut_Click; + // + // userSelectedBut + // + userSelectedBut.Location = new Point(3, 192); + userSelectedBut.Margin = new Padding(3, 3, 3, 30); + userSelectedBut.Name = "userSelectedBut"; + userSelectedBut.Size = new Size(30, 25); + userSelectedBut.TabIndex = 0; + userSelectedBut.Values.Image = Properties.Resources.MoveNext; + userSelectedBut.Values.Text = ""; + userSelectedBut.Click += userSelectedBut_Click; + // + // tableLayoutPanel9 + // + tableLayoutPanel9.BackColor = SystemColors.Control; + tableLayoutPanel9.ColumnCount = 1; + tableLayoutPanel9.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F)); + tableLayoutPanel9.Controls.Add(kryptonHeader4, 0, 0); + tableLayoutPanel9.Controls.Add(deselectedUserGv, 0, 1); + tableLayoutPanel9.Dock = DockStyle.Fill; + tableLayoutPanel9.Location = new Point(0, 0); + tableLayoutPanel9.Name = "tableLayoutPanel9"; + tableLayoutPanel9.Padding = new Padding(4, 0, 0, 0); + tableLayoutPanel9.RowCount = 2; + tableLayoutPanel9.RowStyles.Add(new RowStyle()); + tableLayoutPanel9.RowStyles.Add(new RowStyle(SizeType.Percent, 83.39552F)); + tableLayoutPanel9.Size = new Size(510, 500); + tableLayoutPanel9.TabIndex = 0; + // + // kryptonHeader4 + // + kryptonHeader4.Dock = DockStyle.Top; + kryptonHeader4.Location = new Point(4, 0); + kryptonHeader4.Margin = new Padding(0); + kryptonHeader4.Name = "kryptonHeader4"; + kryptonHeader4.Size = new Size(506, 31); + kryptonHeader4.TabIndex = 1; + kryptonHeader4.Values.Description = ""; + kryptonHeader4.Values.Heading = "未授权用户"; + kryptonHeader4.Values.Image = null; + // + // deselectedUserGv + // + deselectedUserGv.AllowUserToAddRows = false; + deselectedUserGv.AllowUserToDeleteRows = false; + deselectedUserGv.BorderStyle = BorderStyle.None; + deselectedUserGv.Columns.AddRange(new DataGridViewColumn[] { userNameCol, userLocalNameCol }); + deselectedUserGv.Dock = DockStyle.Fill; + deselectedUserGv.Location = new Point(4, 31); + deselectedUserGv.Margin = new Padding(0); + deselectedUserGv.Name = "deselectedUserGv"; + deselectedUserGv.Size = new Size(506, 469); + deselectedUserGv.TabIndex = 1; + // + // userNameCol + // + userNameCol.DataPropertyName = "UserName"; + userNameCol.DefaultCellStyle = dataGridViewCellStyle8; + userNameCol.HeaderText = "用户名"; + userNameCol.Name = "userNameCol"; + userNameCol.Resizable = DataGridViewTriState.True; + userNameCol.Width = 200; + // + // userLocalNameCol + // + userLocalNameCol.DataPropertyName = "UserName"; + userLocalNameCol.DisplayStyle = DataGridViewComboBoxDisplayStyle.Nothing; + userLocalNameCol.HeaderText = "中文名"; + userLocalNameCol.Name = "userLocalNameCol"; + userLocalNameCol.Resizable = DataGridViewTriState.True; + userLocalNameCol.SortMode = DataGridViewColumnSortMode.Automatic; + userLocalNameCol.Width = 200; + // + // kryptonPanel3 + // + kryptonPanel3.Dock = DockStyle.Fill; + kryptonPanel3.Location = new Point(3, 613); + kryptonPanel3.Name = "kryptonPanel3"; + kryptonPanel3.Size = new Size(1018, 5); + kryptonPanel3.TabIndex = 3; + // + // SecurityActorOperationPage + // + AutoScaleDimensions = new SizeF(7F, 15F); + AutoScaleMode = AutoScaleMode.Font; + Controls.Add(mainPanel); + Name = "SecurityActorOperationPage"; + tableLayoutPanel2.ResumeLayout(false); + tableLayoutPanel2.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)kryptonPanel2).EndInit(); + splitContainer1.Panel1.ResumeLayout(false); + splitContainer1.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)splitContainer1).EndInit(); + splitContainer1.ResumeLayout(false); + tableLayoutPanel3.ResumeLayout(false); + tableLayoutPanel3.PerformLayout(); + tableLayoutPanel4.ResumeLayout(false); + tableLayoutPanel4.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)selectedGv).EndInit(); + tableLayoutPanel5.ResumeLayout(false); + tableLayoutPanel6.ResumeLayout(false); + tableLayoutPanel6.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)deselectedGv).EndInit(); + mainPanel.ResumeLayout(false); + mainPanel.PerformLayout(); + topPanel.ResumeLayout(false); + topPanel.PerformLayout(); + searchPanel.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)kryptonPanel1).EndInit(); + bottomPanel.ResumeLayout(false); + bottomPanel.PerformLayout(); + savePanel.ResumeLayout(false); + operationPanel.ResumeLayout(false); + contentPanel.ResumeLayout(false); + contentPanel.PerformLayout(); + splitContainer2.Panel1.ResumeLayout(false); + splitContainer2.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)splitContainer2).EndInit(); + splitContainer2.ResumeLayout(false); + tableLayoutPanel1.ResumeLayout(false); + tableLayoutPanel1.PerformLayout(); + tableLayoutPanel7.ResumeLayout(false); + tableLayoutPanel7.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)selectedUserGv).EndInit(); + tableLayoutPanel8.ResumeLayout(false); + tableLayoutPanel9.ResumeLayout(false); + tableLayoutPanel9.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)deselectedUserGv).EndInit(); + ((System.ComponentModel.ISupportInitialize)kryptonPanel3).EndInit(); + ResumeLayout(false); + } + + #endregion + + private TableLayoutPanel tableLayoutPanel2; + private Krypton.Toolkit.KryptonLabel actorNameLabel; + private Krypton.Toolkit.KryptonLabel actorLocalNameLabel; + private Krypton.Toolkit.KryptonLabel actorEngNameLabel; + private Krypton.Toolkit.KryptonTextBox actorNameTxt; + private Krypton.Toolkit.KryptonTextBox actorLocalNameTxt; + private Krypton.Toolkit.KryptonTextBox actorEngNameTxt; + private Krypton.Toolkit.KryptonPanel kryptonPanel2; + private SplitContainer splitContainer1; + private TableLayoutPanel tableLayoutPanel3; + private TableLayoutPanel tableLayoutPanel4; + private Krypton.Toolkit.KryptonHeader kryptonHeader1; + private Krypton.Toolkit.KryptonDataGridView deselectedGv; + private TableLayoutPanel tableLayoutPanel5; + private Krypton.Toolkit.KryptonButton deselectedBut; + private Krypton.Toolkit.KryptonButton selectedBut; + private TableLayoutPanel tableLayoutPanel6; + private Krypton.Toolkit.KryptonDataGridView selectedGv; + private Krypton.Toolkit.KryptonHeader kryptonHeader2; + private TableLayoutPanel mainPanel; + private TableLayoutPanel topPanel; + private TableLayoutPanel searchPanel; + private Krypton.Toolkit.KryptonButton createBut; + private Krypton.Toolkit.KryptonButton resetBut; + private Krypton.Toolkit.KryptonButton searchBut; + private Krypton.Toolkit.KryptonLabel actorNameSearchLabel; + private Krypton.Toolkit.KryptonTextBox actorNameSearchTxt; + private Krypton.Toolkit.ButtonSpecAny actorNameSearchBut; + private Krypton.Toolkit.KryptonPanel kryptonPanel1; + private TableLayoutPanel bottomPanel; + private TableLayoutPanel savePanel; + private Krypton.Toolkit.KryptonButton cancelBut; + private Krypton.Toolkit.KryptonButton saveBut; + private TableLayoutPanel operationPanel; + private Krypton.Toolkit.KryptonButton deleteBut; + private Krypton.Toolkit.KryptonButton amendBut; + private TableLayoutPanel contentPanel; + private SplitContainer splitContainer2; + private TableLayoutPanel tableLayoutPanel1; + private TableLayoutPanel tableLayoutPanel7; + private Krypton.Toolkit.KryptonHeader kryptonHeader3; + private Krypton.Toolkit.KryptonDataGridView deselectedUserGv; + private TableLayoutPanel tableLayoutPanel8; + private Krypton.Toolkit.KryptonButton userDeselectedBut; + private Krypton.Toolkit.KryptonButton userSelectedBut; + private TableLayoutPanel tableLayoutPanel9; + private Krypton.Toolkit.KryptonDataGridView selectedUserGv; + private Krypton.Toolkit.KryptonHeader kryptonHeader4; + private Krypton.Toolkit.KryptonPanel kryptonPanel3; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn groupNameSelectedCol; + private DataGridViewComboBoxColumn groupLocalNameSelectedCol; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn groupNameCol; + private DataGridViewComboBoxColumn groupLocalNameCol; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn userNameSelectedCol; + private DataGridViewComboBoxColumn userLocalNameSelectedCol; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn userNameCol; + private DataGridViewComboBoxColumn userLocalNameCol; + } +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Security.Gui/SecurityActorOperationPage.cs b/CloudBuilder/CloudBuilder.Security.Gui/SecurityActorOperationPage.cs new file mode 100644 index 0000000..213a568 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/SecurityActorOperationPage.cs @@ -0,0 +1,677 @@ +using CloudBuilder.Core.Service; +using CloudBuilder.Gui; +using CloudBuilder.Request.Security; +using CloudBuilder.Security.Data; +using CloudBuilder.Security.Entity; +using CloudBuilder.Security.Linkup; +using CloudBuilder.Security.Policy; +using Krypton.Toolkit; +using Microsoft.AspNetCore.Authorization; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace CloudBuilder.Security.Gui +{ + public partial class SecurityActorOperationPage : AbstractPage + { + private SecurityActorData data; + private SecurityActorEntity securityActorEntity; + private SecurityMessagePolicy securityMessagePolicy; + private SecurityActorRequest securityActorRequest; + private SecurityGroupEntity[] securityGroups; + private SecurityUserEntity[] securityUsers; + public SecurityActorOperationPage() + { + InitializeComponent(); + } + + public override void FunctionLoaded() + { + try + { + base.FunctionLoaded(); + //初始化容器------------------------------------- + securityMessagePolicy = ServiceHelper.GetTypeService()!; + securityActorRequest = ServiceHelper.GetTypeService(); + + //界面初始化 + InitGui(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + + private void InitGui() + { + InitBindingContext(); + + InitComBox(); + + InitDisplayMode(); + + this.ParentAbstractForm.AcceptButton = this.searchBut; + this.ParentAbstractForm.CancelButton = this.resetBut; + } + + private void InitComBox() + { + try + { + SecurityGroupRequest securityGroupRequest = ServiceHelper.GetTypeService(); + securityGroups = securityGroupRequest.FindAll(); + + deselectedGv.SetColumnDataSource(groupLocalNameCol, securityGroups, SecurityGroupEntity.GROUP_LOCAL_NAME, SecurityGroupEntity.GROUP_NAME, true); + selectedGv.SetColumnDataSource(groupLocalNameSelectedCol, securityGroups, SecurityGroupEntity.GROUP_LOCAL_NAME, SecurityGroupEntity.GROUP_NAME, true); + + SecurityUserRequest securityUserRequest = ServiceHelper.GetTypeService(); + securityUsers = securityUserRequest.FindAll(); + + deselectedUserGv.SetColumnDataSource(userLocalNameCol, securityUsers, SecurityUserEntity.USER_LOCAL_NAME, SecurityUserEntity.USER_NAME, true); + selectedUserGv.SetColumnDataSource(userLocalNameSelectedCol, securityUsers, SecurityUserEntity.USER_LOCAL_NAME, SecurityUserEntity.USER_NAME, true); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + /// + /// 有特殊要求的UI控件初始化设置,Init与Add配对后,使用guiOperateHelper管理 + /// + private void InitBindingContext() + { + //需要绑定数据 + guiBindingContext = new GuiBindingContext(); + + InitPermission(); + + actorNameTxt.Set(SecurityActorEntity.ACTOR_NAME, actorNameLabel.Text, EnumEditModeColor.Required); + actorLocalNameTxt.Set(SecurityActorEntity.ACTOR_LOCAL_NAME); + actorEngNameTxt.Set(SecurityActorEntity.ACTOR_ENG_NAME); + + selectedGv.InitColumn(false, true); + deselectedGv.InitColumn(false, true); + + selectedUserGv.InitColumn(false, true); + deselectedUserGv.InitColumn(false, true); + + guiOperateHelper = new GuiOperateHelper(); + } + + private void InitPermission() + { + createBut.Set(SecurityPermissionPolicy.SecurityActor, Operate.Insert); + amendBut.Set(SecurityPermissionPolicy.SecurityActor, Operate.Update); + deleteBut.Set(SecurityPermissionPolicy.SecurityActor, Operate.Delete); + } + + /// + /// 每次从别的界面进入时执行,发生在FunctionLoaded之后 + /// + /// + public override void FunctionActivated(object param) + { + try + { + if (param == null) + { + actorNameSearchTxt.Focus(); + return; + } + + InitDisplayMode(); + + SecurityActorOperationLinkup linkup = null; + + if (param is SecurityActorOperationLinkup) + { + linkup = (SecurityActorOperationLinkup)param; + } + + this.DisplayMode = (GuiDisplayMode)linkup.DisplayMode; + + actorNameSearchTxt.Text = linkup.ActorName; + + if (this.DisplayMode == GuiDisplayMode.View) + { + Search(); + } + else if (this.DisplayMode == GuiDisplayMode.Create) + { + Create(); + } + else if (this.DisplayMode == GuiDisplayMode.Amend) + { + Search(); + Amend(); + } + + actorNameSearchTxt.Focus(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + public override void FunctionSelected() + { + this.ParentAbstractForm.AcceptButton = this.searchBut; + if (!IsDialog) + this.ParentAbstractForm.CancelButton = this.resetBut; + else + this.ParentAbstractForm.CancelButton = this.cancelBut; + + actorNameSearchTxt.Focus(); + } + + public override bool FunctionDeactivating() + { + if (this.DisplayMode == GuiDisplayMode.View) + { + return true; + } + else + { + return CancelEditing(); + } + } + + private bool CancelEditing() + { + DialogResult result = ShowMessageBox.ShowOption(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_CONFIRM_CANCEL), securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_CONFIRM)); + + //从外部跳转(非mainKryptonNavigator),result第一次不生效?,所以再执行一次生效 + if (result == DialogResult.Cancel) + { + result = ShowMessageBox.ShowOption(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_CONFIRM_CANCEL), securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_CONFIRM)); + } + + if (result == DialogResult.No) + { + return false; + } + + Cancel(); + + return true; + } + + private void InitDisplayMode() + { + this.DisplayMode = GuiDisplayMode.View; + + SetDisplayMode(); + } + + private void SetDisplayMode() + { + if (this.DisplayMode == GuiDisplayMode.View) + { + savePanel.Visible = false; + operationPanel.Visible = true; + + guiOperateHelper.EnableControls(true, topPanel); + guiOperateHelper.EnableControls(false, contentPanel); + //查詢有記錄時,修改等控件有效 + if (securityActorEntity != null) + guiOperateHelper.EnableControls(true, bottomPanel); + else + guiOperateHelper.EnableControls(false, bottomPanel); + } + else if (this.DisplayMode == GuiDisplayMode.Amend || this.DisplayMode == GuiDisplayMode.Create) + { + savePanel.Visible = true; + operationPanel.Visible = false; + + guiOperateHelper.EnableControls(false, topPanel); + guiOperateHelper.EnableControls(true, bottomPanel, contentPanel); + + if (this.DisplayMode == GuiDisplayMode.Amend) guiOperateHelper.EnableControls(false, actorNameTxt); + } + + guiOperateHelper.EnableControls(false, deselectedGv, selectedGv); + } + + private void PackUIToEntity() + { + guiBindingContext.DataPack(); + + SecurityGroupEntity[] groups = selectedGv.GetAllRows(); + if (groups != null && groups.Length > 0) + { + data.SecurityActorGroups = groups.Select(x => new SecurityActorGroupViewEntity() { ActorName = actorNameTxt.Text, GroupName = x.GroupName }).ToArray(); + } + else + data.SecurityActorGroups = null; + + SecurityUserEntity[] users = selectedUserGv.GetAllRows(); + if (users != null && users.Length > 0) + { + data.SecurityUserActors = users.Select(x => new SecurityUserActorViewEntity() { ActorName = actorNameTxt.Text, UserName = x.UserName, UserLocalName = string.Empty }).ToArray(); + } + else + data.SecurityUserActors = null; + } + + private bool SaveValidate() + { + if (!guiOperateHelper.CheckValidate(this.mainPanel)) return false; + + return true; + } + + private void Search() + { + try + { + if (string.IsNullOrEmpty(actorNameSearchTxt.Text)) return; + + Reset(); + + data = securityActorRequest.FindByKey(actorNameSearchTxt.Text); + + if (data == null || data.SecurityActor == null) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + } + else + { + securityActorEntity = data.SecurityActor; + + PackEntityToUI(); + + SetDisplayMode(); + } + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void Create() + { + this.DisplayMode = GuiDisplayMode.Create; + + guiOperateHelper.ResetControls(this.mainPanel); + + SetDisplayMode(); + + data = new SecurityActorData(); + securityActorEntity = new SecurityActorEntity() + { + CreatedBy = string.Empty, + UpdatedBy = string.Empty, + CreatedDatetime = DateTime.Now, + UpdatedDatetime = DateTime.Now, + }; + data.SecurityActor = securityActorEntity; + + PackEntityToUI(); + + actorNameTxt.Focus(); + } + + private void Amend() + { + this.DisplayMode = GuiDisplayMode.Amend; + + SetDisplayMode(); + } + + private void PackEntityToUI() + { + guiBindingContext.DataBind(data.SecurityActor, this); + + SecurityGroupEntity[] allGroups = securityGroups; + SecurityGroupEntity[] deselecteds = null; + SecurityGroupEntity[] selecteds = null; + if (data.SecurityActorGroups != null) + { + deselecteds = allGroups.Where(x => !data.SecurityActorGroups.Select(y => y.GroupName).Contains(x.GroupName)).ToArray(); + selecteds = allGroups.Where(x => data.SecurityActorGroups.Select(y => y.GroupName).Contains(x.GroupName)).ToArray(); + } + else + { + deselecteds = allGroups; + } + + deselectedGv.SetDataSource(deselecteds); + selectedGv.SetDataSource(selecteds); + + SecurityUserEntity[] allUsers = securityUsers; + SecurityUserEntity[] deselectedUsers = null; + SecurityUserEntity[] selectedUsers = null; + if (data.SecurityUserActors != null) + { + deselectedUsers = allUsers.Where(x => !data.SecurityUserActors.Select(y => y.UserName).Contains(x.UserName)).ToArray(); + selectedUsers = allUsers.Where(x => data.SecurityUserActors.Select(y => y.UserName).Contains(x.UserName)).ToArray(); + } + else + { + deselectedUsers = allUsers; + } + + deselectedUserGv.SetDataSource(deselectedUsers); + selectedUserGv.SetDataSource(selectedUsers); + } + + private void Reset() + { + this.DisplayMode = GuiDisplayMode.View; + + securityActorEntity = null; + + guiOperateHelper.ResetControls(this.contentPanel); + + SetDisplayMode(); + + actorNameSearchTxt.Focus(); + } + + public void Cancel() + { + if (!string.IsNullOrEmpty(actorNameSearchTxt.Text)) + Search(); + else + Reset(); + + } + + + private void actorNameSearchBut_Click(object sender, EventArgs e) + { + try + { + AbstractForm dialog = GetAbstractDialog(typeof(SecurityActorEnquiryPage).Name); + + if (DialogResult.OK != dialog.ShowDialog()) return; + + actorNameSearchTxt.Text = ((SecurityActorEntity[])dialog.OutputData)[0].ActorName; + + Search(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void searchBut_Click(object sender, EventArgs e) + { + try + { + if (string.IsNullOrEmpty(actorNameSearchTxt.Text)) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_VALID_INPUT, GuiOperateHelper.GetLabelText(actorNameSearchLabel.Text))); + this.actorNameSearchTxt.Focus(); + return; + } + this.DisplayMode = GuiDisplayMode.View; + + Search(); + + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void resetBut_Click(object sender, EventArgs e) + { + try + { + guiOperateHelper.ResetControls(this.topPanel); + Reset(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void createBut_Click(object sender, EventArgs e) + { + HandleException(() => Create()); + } + + private void amendBut_Click(object sender, EventArgs e) + { + HandleException(() => Amend()); + } + + private void deleteBut_Click(object sender, EventArgs e) + { + try + { + if (securityActorEntity == null) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + return; + } + + if (DialogResult.Yes != ShowMessageBox.ShowOption(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_CONFIRM_DEL_NULL), securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_DELETE))) return; + + securityActorRequest.Delete(securityActorEntity.ActorName); + + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_SUCCEED_DELETED_NULL)); + + Reset(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void saveBut_Click(object sender, EventArgs e) + { + try + { + if (!SaveValidate()) return; + + PackUIToEntity(); + + + if (this.DisplayMode == GuiDisplayMode.Create) + securityActorRequest.Insert(data); + else + securityActorRequest.Update(data); + + + ShowMessageBox.ShowInfo((this.DisplayMode == GuiDisplayMode.Create) ? + securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_SUCCEED_CREATED_NULL) : + securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_SUCCEED_UPDATED_NULL)); + + actorNameSearchTxt.Text = securityActorEntity.ActorName; + Search(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void cancelBut_Click(object sender, EventArgs e) + { + HandleException(() => CancelEditing()); + + } + + private void selectedBut_Click(object sender, EventArgs e) + { + if (selectedGv.RowCount <= 0 || selectedGv.SelectedCells.Count <= 0) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + return; + } + + SecurityGroupEntity[] securityGroups = selectedGv.GetSelectedCellsData(); + selectedGv.DeleteRows(selectedGv.SelectedCells); + + deselectedGv.AddRow(securityGroups); + } + + private void deselectedBut_Click(object sender, EventArgs e) + { + if (deselectedGv.RowCount <= 0 || deselectedGv.SelectedCells.Count <= 0) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + return; + } + + SecurityGroupEntity[] securityGroups = deselectedGv.GetSelectedCellsData(); + deselectedGv.DeleteRows(deselectedGv.SelectedCells); + + selectedGv.AddRow(securityGroups); + } + + private void userSelectedBut_Click(object sender, EventArgs e) + { + if (selectedUserGv.RowCount <= 0 || selectedUserGv.SelectedCells.Count <= 0) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + return; + } + + SecurityUserEntity[] securityUsers = selectedUserGv.GetSelectedCellsData(); + selectedUserGv.DeleteRows(selectedUserGv.SelectedCells); + + deselectedUserGv.AddRow(securityUsers); + } + + private void userDeselectedBut_Click(object sender, EventArgs e) + { + if (deselectedUserGv.RowCount <= 0 || deselectedUserGv.SelectedCells.Count <= 0) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + return; + } + + SecurityUserEntity[] securityUsers = deselectedUserGv.GetSelectedCellsData(); + deselectedUserGv.DeleteRows(deselectedGv.SelectedCells); + + selectedUserGv.AddRow(securityUsers); + } + + + private void selectedGv_CellDoubleClick(object sender, DataGridViewCellEventArgs e) + { + if (selectedGv.RowCount <= 0 || selectedGv.SelectedCells.Count <= 0) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + return; + } + + SecurityGroupEntity data = selectedGv.GetRowData(selectedGv.SelectedCells[0].RowIndex); + + DisplayPage(GuiDisplayMode.View, data.GroupName); + } + + private void DisplayPage(GuiDisplayMode mode, string groupName) + { + SecurityGroupOperationLinkup linkupData = new SecurityGroupOperationLinkup(); + linkupData.DisplayMode = Convert.ToInt32(mode); + linkupData.GroupName = groupName; + + this.DisplayAbstractPage(typeof(SecurityGroupOperationPage).Name, linkupData); + } + + private void deselectedGv_CellDoubleClick(object sender, DataGridViewCellEventArgs e) + { + if (deselectedGv.RowCount <= 0 || deselectedGv.SelectedCells.Count <= 0) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + return; + } + + SecurityGroupEntity data = deselectedGv.GetRowData(deselectedGv.SelectedCells[0].RowIndex); + + DisplayPage(GuiDisplayMode.View, data.GroupName); + } + } +} diff --git a/CloudBuilder/CloudBuilder.Security.Gui/SecurityActorOperationPage.resx b/CloudBuilder/CloudBuilder.Security.Gui/SecurityActorOperationPage.resx new file mode 100644 index 0000000..d573b74 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/SecurityActorOperationPage.resx @@ -0,0 +1,138 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + True + + + True + + + True + + + True + + + True + + + True + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Security.Gui/SecurityFunctionEnquiryPage.Designer.cs b/CloudBuilder/CloudBuilder.Security.Gui/SecurityFunctionEnquiryPage.Designer.cs new file mode 100644 index 0000000..ec68c96 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/SecurityFunctionEnquiryPage.Designer.cs @@ -0,0 +1,466 @@ +namespace CloudBuilder.Security.Gui +{ + partial class SecurityFunctionEnquiryPage + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + DataGridViewCellStyle dataGridViewCellStyle1 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle2 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle3 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle4 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle5 = new DataGridViewCellStyle(); + mainPanel = new TableLayoutPanel(); + topPanel = new TableLayoutPanel(); + functionIndcCombo = new Krypton.Toolkit.KryptonComboBox(); + searchFunctionNameLabel = new Krypton.Toolkit.KryptonLabel(); + functionNameTxt = new Krypton.Toolkit.KryptonTextBox(); + searchPanel = new TableLayoutPanel(); + searchBut = new Krypton.Toolkit.KryptonButton(); + resetBut = new Krypton.Toolkit.KryptonButton(); + createBut = new Krypton.Toolkit.KryptonButton(); + functionLocalNameLabel = new Krypton.Toolkit.KryptonLabel(); + functionLocalNameTxt = new Krypton.Toolkit.KryptonTextBox(); + functionIndcLabel = new Krypton.Toolkit.KryptonLabel(); + contextPanel = new TableLayoutPanel(); + dataGv = new Krypton.Toolkit.KryptonDataGridView(); + functionNameCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + functionLocalNameCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + functionEngNameCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + pageNameCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + functionIndcCol = new Krypton.Toolkit.KryptonDataGridViewCheckBoxColumn(); + gridViewPagination = new CloudBuilder.Gui.GridViewPagination(); + bottomPanel = new TableLayoutPanel(); + operationPanel = new TableLayoutPanel(); + viewBut = new Krypton.Toolkit.KryptonButton(); + amendBut = new Krypton.Toolkit.KryptonButton(); + deleteBut = new Krypton.Toolkit.KryptonButton(); + dialogPanel = new TableLayoutPanel(); + okBut = new Krypton.Toolkit.KryptonButton(); + cancelBut = new Krypton.Toolkit.KryptonButton(); + mainPanel.SuspendLayout(); + topPanel.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)functionIndcCombo).BeginInit(); + searchPanel.SuspendLayout(); + contextPanel.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)dataGv).BeginInit(); + bottomPanel.SuspendLayout(); + operationPanel.SuspendLayout(); + dialogPanel.SuspendLayout(); + SuspendLayout(); + // + // mainPanel + // + mainPanel.ColumnCount = 1; + mainPanel.ColumnStyles.Add(new ColumnStyle()); + mainPanel.Controls.Add(topPanel, 0, 0); + mainPanel.Controls.Add(contextPanel, 0, 1); + mainPanel.Controls.Add(bottomPanel, 0, 2); + mainPanel.Dock = DockStyle.Fill; + mainPanel.Location = new Point(0, 0); + mainPanel.Name = "mainPanel"; + mainPanel.RowCount = 3; + mainPanel.RowStyles.Add(new RowStyle()); + mainPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 100F)); + mainPanel.RowStyles.Add(new RowStyle()); + mainPanel.Size = new Size(1024, 800); + mainPanel.TabIndex = 0; + // + // topPanel + // + topPanel.AutoSize = true; + topPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + topPanel.ColumnCount = 5; + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.Controls.Add(functionIndcCombo, 1, 1); + topPanel.Controls.Add(searchFunctionNameLabel, 0, 0); + topPanel.Controls.Add(functionNameTxt, 1, 0); + topPanel.Controls.Add(searchPanel, 4, 0); + topPanel.Controls.Add(functionLocalNameLabel, 2, 0); + topPanel.Controls.Add(functionLocalNameTxt, 3, 0); + topPanel.Controls.Add(functionIndcLabel, 0, 1); + topPanel.Dock = DockStyle.Fill; + topPanel.Location = new Point(3, 3); + topPanel.Name = "topPanel"; + topPanel.RowCount = 2; + topPanel.RowStyles.Add(new RowStyle()); + topPanel.RowStyles.Add(new RowStyle()); + topPanel.Size = new Size(1018, 59); + topPanel.TabIndex = 0; + // + // functionIndcCombo + // + functionIndcCombo.DropDownStyle = ComboBoxStyle.DropDownList; + functionIndcCombo.DropDownWidth = 200; + functionIndcCombo.IntegralHeight = false; + functionIndcCombo.Location = new Point(77, 34); + functionIndcCombo.Name = "functionIndcCombo"; + functionIndcCombo.Size = new Size(200, 22); + functionIndcCombo.StateCommon.ComboBox.Content.TextH = Krypton.Toolkit.PaletteRelativeAlign.Near; + functionIndcCombo.TabIndex = 1000; + // + // searchFunctionNameLabel + // + searchFunctionNameLabel.Location = new Point(3, 3); + searchFunctionNameLabel.Name = "searchFunctionNameLabel"; + searchFunctionNameLabel.Size = new Size(52, 20); + searchFunctionNameLabel.TabIndex = 999; + searchFunctionNameLabel.Values.Text = "应用名:"; + // + // functionNameTxt + // + functionNameTxt.Location = new Point(77, 3); + functionNameTxt.Name = "functionNameTxt"; + functionNameTxt.Size = new Size(200, 23); + functionNameTxt.TabIndex = 0; + // + // searchPanel + // + searchPanel.AutoSize = true; + searchPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + searchPanel.ColumnCount = 3; + searchPanel.ColumnStyles.Add(new ColumnStyle()); + searchPanel.ColumnStyles.Add(new ColumnStyle()); + searchPanel.ColumnStyles.Add(new ColumnStyle()); + searchPanel.Controls.Add(searchBut, 0, 0); + searchPanel.Controls.Add(resetBut, 1, 0); + searchPanel.Controls.Add(createBut, 2, 0); + searchPanel.Location = new Point(631, 0); + searchPanel.Margin = new Padding(60, 0, 0, 0); + searchPanel.Name = "searchPanel"; + searchPanel.RowCount = 1; + searchPanel.RowStyles.Add(new RowStyle()); + searchPanel.Size = new Size(288, 31); + searchPanel.TabIndex = 999; + // + // searchBut + // + searchBut.Location = new Point(3, 3); + searchBut.Name = "searchBut"; + searchBut.Size = new Size(90, 25); + searchBut.TabIndex = 0; + searchBut.Values.Image = Properties.Resources.search_16; + searchBut.Values.Text = "查询(&S)"; + searchBut.Click += searchBut_Click; + // + // resetBut + // + resetBut.Location = new Point(99, 3); + resetBut.Name = "resetBut"; + resetBut.Size = new Size(90, 25); + resetBut.TabIndex = 0; + resetBut.Values.Image = Properties.Resources.reset_16; + resetBut.Values.Text = "重置(&R)"; + resetBut.Click += resetBut_Click; + // + // createBut + // + createBut.Location = new Point(195, 3); + createBut.Name = "createBut"; + createBut.Size = new Size(90, 25); + createBut.TabIndex = 0; + createBut.Values.Image = Properties.Resources.create_16; + createBut.Values.Text = "新增(&C)"; + createBut.Click += createBut_Click; + // + // functionLocalNameLabel + // + functionLocalNameLabel.Location = new Point(310, 3); + functionLocalNameLabel.Margin = new Padding(30, 3, 3, 3); + functionLocalNameLabel.Name = "functionLocalNameLabel"; + functionLocalNameLabel.Size = new Size(52, 20); + functionLocalNameLabel.TabIndex = 999; + functionLocalNameLabel.Values.Text = "中文名:"; + // + // functionLocalNameTxt + // + functionLocalNameTxt.Location = new Point(368, 3); + functionLocalNameTxt.Name = "functionLocalNameTxt"; + functionLocalNameTxt.Size = new Size(200, 23); + functionLocalNameTxt.TabIndex = 0; + // + // functionIndcLabel + // + functionIndcLabel.Location = new Point(3, 34); + functionIndcLabel.Name = "functionIndcLabel"; + functionIndcLabel.Size = new Size(68, 20); + functionIndcLabel.TabIndex = 999; + functionIndcLabel.Values.Text = "是否菜单?"; + // + // contextPanel + // + contextPanel.ColumnCount = 1; + contextPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F)); + contextPanel.Controls.Add(dataGv, 0, 0); + contextPanel.Controls.Add(gridViewPagination, 0, 1); + contextPanel.Dock = DockStyle.Fill; + contextPanel.Location = new Point(3, 68); + contextPanel.Name = "contextPanel"; + contextPanel.RowCount = 2; + contextPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 50F)); + contextPanel.RowStyles.Add(new RowStyle()); + contextPanel.Size = new Size(1018, 655); + contextPanel.TabIndex = 999; + // + // dataGv + // + dataGv.AllowUserToAddRows = false; + dataGv.AllowUserToDeleteRows = false; + dataGv.BorderStyle = BorderStyle.None; + dataGv.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize; + dataGv.Columns.AddRange(new DataGridViewColumn[] { functionNameCol, functionLocalNameCol, functionEngNameCol, pageNameCol, functionIndcCol }); + dataGv.Dock = DockStyle.Fill; + dataGv.Location = new Point(3, 3); + dataGv.Name = "dataGv"; + dataGv.Size = new Size(1012, 619); + dataGv.TabIndex = 0; + dataGv.CellDoubleClick += dataGv_CellDoubleClick; + // + // functionNameCol + // + functionNameCol.DataPropertyName = "FunctionName"; + functionNameCol.DefaultCellStyle = dataGridViewCellStyle1; + functionNameCol.HeaderText = "应用名"; + functionNameCol.Name = "functionNameCol"; + functionNameCol.Width = 260; + // + // functionLocalNameCol + // + functionLocalNameCol.DataPropertyName = "FunctionLocalName"; + functionLocalNameCol.DefaultCellStyle = dataGridViewCellStyle2; + functionLocalNameCol.HeaderText = "中文名"; + functionLocalNameCol.Name = "functionLocalNameCol"; + functionLocalNameCol.Width = 260; + // + // functionEngNameCol + // + functionEngNameCol.DataPropertyName = "FunctionEngName"; + functionEngNameCol.DefaultCellStyle = dataGridViewCellStyle3; + functionEngNameCol.HeaderText = "英文名"; + functionEngNameCol.Name = "functionEngNameCol"; + functionEngNameCol.Resizable = DataGridViewTriState.True; + functionEngNameCol.Width = 260; + // + // pageNameCol + // + pageNameCol.DataPropertyName = "PageName"; + pageNameCol.DefaultCellStyle = dataGridViewCellStyle4; + pageNameCol.HeaderText = "页面名称"; + pageNameCol.Name = "pageNameCol"; + pageNameCol.Resizable = DataGridViewTriState.True; + pageNameCol.Width = 300; + // + // functionIndcCol + // + functionIndcCol.DataPropertyName = "FunctionIndc"; + dataGridViewCellStyle5.Alignment = DataGridViewContentAlignment.MiddleCenter; + dataGridViewCellStyle5.NullValue = false; + functionIndcCol.DefaultCellStyle = dataGridViewCellStyle5; + functionIndcCol.FalseValue = "N"; + functionIndcCol.HeaderText = "是否菜单?"; + functionIndcCol.IndeterminateValue = null; + functionIndcCol.Name = "functionIndcCol"; + functionIndcCol.Resizable = DataGridViewTriState.True; + functionIndcCol.SortMode = DataGridViewColumnSortMode.Automatic; + functionIndcCol.TrueValue = "Y"; + // + // gridViewPagination + // + gridViewPagination.AutoSizeMode = AutoSizeMode.GrowAndShrink; + gridViewPagination.CurrentPage = 0; + gridViewPagination.Dock = DockStyle.Fill; + gridViewPagination.Limit = 20; + gridViewPagination.Location = new Point(0, 625); + gridViewPagination.Margin = new Padding(0); + gridViewPagination.Name = "gridViewPagination"; + gridViewPagination.Page = 0; + gridViewPagination.Size = new Size(1018, 30); + gridViewPagination.TabIndex = 999; + gridViewPagination.Total = 0; + // + // bottomPanel + // + bottomPanel.AutoSize = true; + bottomPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + bottomPanel.ColumnCount = 2; + bottomPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F)); + bottomPanel.ColumnStyles.Add(new ColumnStyle()); + bottomPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 20F)); + bottomPanel.Controls.Add(operationPanel, 0, 0); + bottomPanel.Controls.Add(dialogPanel, 2, 1); + bottomPanel.Dock = DockStyle.Fill; + bottomPanel.Location = new Point(3, 729); + bottomPanel.Name = "bottomPanel"; + bottomPanel.RowCount = 2; + bottomPanel.RowStyles.Add(new RowStyle()); + bottomPanel.RowStyles.Add(new RowStyle()); + bottomPanel.Size = new Size(1018, 68); + bottomPanel.TabIndex = 999; + // + // operationPanel + // + operationPanel.AutoSize = true; + operationPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + operationPanel.ColumnCount = 3; + operationPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F)); + operationPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 101F)); + operationPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F)); + operationPanel.Controls.Add(viewBut, 0, 0); + operationPanel.Controls.Add(amendBut, 1, 0); + operationPanel.Controls.Add(deleteBut, 2, 0); + operationPanel.Location = new Point(0, 0); + operationPanel.Margin = new Padding(0); + operationPanel.Name = "operationPanel"; + operationPanel.RowCount = 1; + operationPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 50F)); + operationPanel.Size = new Size(293, 31); + operationPanel.TabIndex = 0; + // + // viewBut + // + viewBut.Location = new Point(3, 3); + viewBut.Name = "viewBut"; + viewBut.Size = new Size(90, 25); + viewBut.TabIndex = 0; + viewBut.Values.Image = Properties.Resources.view_16; + viewBut.Values.Text = "查看(&V)"; + viewBut.Click += viewBut_Click; + // + // amendBut + // + amendBut.Location = new Point(99, 3); + amendBut.Name = "amendBut"; + amendBut.Size = new Size(90, 25); + amendBut.TabIndex = 0; + amendBut.Values.Image = Properties.Resources.amend_16; + amendBut.Values.Text = "修改(&A)"; + amendBut.Click += amendBut_Click; + // + // deleteBut + // + deleteBut.Location = new Point(200, 3); + deleteBut.Name = "deleteBut"; + deleteBut.Size = new Size(90, 25); + deleteBut.TabIndex = 0; + deleteBut.Values.Image = Properties.Resources.delete_16; + deleteBut.Values.Text = "删除(&D)"; + deleteBut.Click += deleteBut_Click; + // + // dialogPanel + // + dialogPanel.AutoSize = true; + dialogPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + dialogPanel.ColumnCount = 2; + dialogPanel.ColumnStyles.Add(new ColumnStyle()); + dialogPanel.ColumnStyles.Add(new ColumnStyle()); + dialogPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 20F)); + dialogPanel.Controls.Add(okBut, 0, 0); + dialogPanel.Controls.Add(cancelBut, 1, 0); + dialogPanel.Dock = DockStyle.Fill; + dialogPanel.Location = new Point(823, 34); + dialogPanel.Name = "dialogPanel"; + dialogPanel.RowCount = 1; + dialogPanel.RowStyles.Add(new RowStyle()); + dialogPanel.Size = new Size(192, 31); + dialogPanel.TabIndex = 1; + // + // okBut + // + okBut.Location = new Point(3, 3); + okBut.Name = "okBut"; + okBut.Size = new Size(90, 25); + okBut.TabIndex = 0; + okBut.Values.Image = Properties.Resources.ok_16; + okBut.Values.Text = "确定(&O)"; + okBut.Click += okBut_Click; + // + // cancelBut + // + cancelBut.Location = new Point(99, 3); + cancelBut.Name = "cancelBut"; + cancelBut.Size = new Size(90, 25); + cancelBut.TabIndex = 0; + cancelBut.Values.Image = Properties.Resources.close_16; + cancelBut.Values.Text = "取消(&C)"; + cancelBut.Click += cancelBut_Click; + // + // SecurityFunctionEnquiryPage + // + AutoScaleDimensions = new SizeF(7F, 15F); + AutoScaleMode = AutoScaleMode.Font; + Controls.Add(mainPanel); + Name = "SecurityFunctionEnquiryPage"; + mainPanel.ResumeLayout(false); + mainPanel.PerformLayout(); + topPanel.ResumeLayout(false); + topPanel.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)functionIndcCombo).EndInit(); + searchPanel.ResumeLayout(false); + contextPanel.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)dataGv).EndInit(); + bottomPanel.ResumeLayout(false); + bottomPanel.PerformLayout(); + operationPanel.ResumeLayout(false); + dialogPanel.ResumeLayout(false); + ResumeLayout(false); + } + + #endregion + + private TableLayoutPanel mainPanel; + private TableLayoutPanel topPanel; + private TableLayoutPanel searchPanel; + private Krypton.Toolkit.KryptonButton searchBut; + private Krypton.Toolkit.KryptonButton resetBut; + private Krypton.Toolkit.KryptonButton createBut; + private TableLayoutPanel contextPanel; + private TableLayoutPanel bottomPanel; + private TableLayoutPanel operationPanel; + private Krypton.Toolkit.KryptonButton viewBut; + private Krypton.Toolkit.KryptonButton amendBut; + private Krypton.Toolkit.KryptonButton deleteBut; + private Krypton.Toolkit.KryptonLabel searchFunctionNameLabel; + private Krypton.Toolkit.KryptonTextBox functionNameTxt; + private Krypton.Toolkit.KryptonDataGridView dataGv; + private TableLayoutPanel dialogPanel; + private Krypton.Toolkit.KryptonButton okBut; + private Krypton.Toolkit.KryptonButton cancelBut; + private CloudBuilder.Gui.GridViewPagination gridViewPagination; + private Krypton.Toolkit.KryptonLabel functionLocalNameLabel; + private Krypton.Toolkit.KryptonTextBox functionLocalNameTxt; + private Krypton.Toolkit.KryptonLabel functionIndcLabel; + private Krypton.Toolkit.KryptonComboBox functionIndcCombo; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn functionNameCol; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn functionLocalNameCol; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn functionEngNameCol; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn pageNameCol; + private Krypton.Toolkit.KryptonDataGridViewCheckBoxColumn functionIndcCol; + } +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Security.Gui/SecurityFunctionEnquiryPage.cs b/CloudBuilder/CloudBuilder.Security.Gui/SecurityFunctionEnquiryPage.cs new file mode 100644 index 0000000..3a15ef1 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/SecurityFunctionEnquiryPage.cs @@ -0,0 +1,455 @@ +using ClosedXML.Excel; +using CloudBuilder.Core.DependencyInjection.Form; +using CloudBuilder.Core.Report; +using CloudBuilder.Core.Service; +using CloudBuilder.Gui; +using CloudBuilder.Gui.DependencyInjection; +using CloudBuilder.Request.Security; +using CloudBuilder.Security.Data; +using CloudBuilder.Security.Entity; +using CloudBuilder.Security.Linkup; +using CloudBuilder.Security.Policy; +using CloudBuilder.Security.SearchCriteria; +using DocumentFormat.OpenXml.Spreadsheet; +using Krypton.Toolkit; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http.Extensions; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.IdentityModel.Tokens; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + + +namespace CloudBuilder.Security.Gui +{ + public partial class SecurityFunctionEnquiryPage : AbstractPage + { + private SecurityFunctionEntity[] securityFunctions = null!; + private SecurityFunctionSearchCriteria searchCriteria = null!; + private BindingContextAttributeProvider provider; + private SecurityFunctionRequest securityFunctionRequest; + private SecurityMessagePolicy securityMessagePolicy; + + //初始化Page,注入容器内,不要在此做任何事情 + public SecurityFunctionEnquiryPage() + { + InitializeComponent(); + } + + /// + /// 第一次加载时执行,只执行一次 + /// + public override void FunctionLoaded() + { + try + { + base.FunctionLoaded(); + //初始化容器------------------------------------- + securityFunctionRequest = ServiceHelper.GetTypeService(); + securityMessagePolicy = ServiceHelper.GetTypeService()!; + + //界面初始化 + InitGui(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + /// + /// 每次从别的界面进入时执行,不包括下面的界面切换,发生在FunctionLoaded之后 + /// 这个是有参数传入,常用于查询界面进入到操作界面发生 + /// + /// + public override void FunctionActivated(object param) + { + base.FunctionActivated(param); + functionNameTxt.Focus(); + } + /// + /// 弹出界面调用,发生在FunctionLoaded()之后 + /// + public override void InitInputData(object param, GuiDisplayMode mode) + { + base.InitInputData(param, mode); + if (param == null) return; + SecurityFunctionSearchCriteria criteria = param as SecurityFunctionSearchCriteria; + functionNameTxt.Text = criteria.FunctionName; + functionLocalNameTxt.Text = criteria.FunctionLocalName; + + if (!string.IsNullOrEmpty(criteria.FunctionIndc)) + functionIndcCombo.SelectedValue = criteria.FunctionIndc; + + if (criteria.FunctionIndcEnable != null && criteria.FunctionIndcEnable == false) guiOperateHelper.EnableControls(false, functionIndcCombo); + + Search(); + } + + /// + /// 当Page被选中时执行,用于Tab导航的切换,没有参数变化,跟FunctionActivated有区别 + /// + public override void FunctionSelected() + { + this.ParentAbstractForm.AcceptButton = this.searchBut; + if (!IsDialog) + this.ParentAbstractForm.CancelButton = this.resetBut; + else + this.ParentAbstractForm.CancelButton = this.cancelBut; + + functionNameTxt.Focus(); + } + /// + /// 控件的初始化 + /// + private void InitGui() + { + //DataGridView初始化不要自动生成列,且允许重排列名操作 + dataGv.InitColumn(true, true); + InitCombo(); + //初始化绑定设置 + InitBindingContext(); + //设置显示模式 + SetDisplayMode(true); + + InitGridViewPagination(); + } + /// + /// DataGridView分页控件初始化 + /// + private void InitGridViewPagination() + { + searchCriteria = new SecurityFunctionSearchCriteria(); + gridViewPagination.SetLimit(searchCriteria.limit); + gridViewPagination.OnPaginationChanged += Search; + gridViewPagination.OnPrint += Print; + } + + private void InitCombo() + { + functionIndcCombo.SetDataSource(YesNoPolicy.GetInstance().GetComposeMessages(), true); + } + + /// + /// 打印当前查询结果 + /// + private void Print() + { + //設置查詢條件 + List searCriteria = new List(); + if (!string.IsNullOrEmpty(functionNameTxt.Text)) + searCriteria.Add(searchFunctionNameLabel.Text + functionNameTxt.Text); + + //設置每列的格式 + TemplateHeader[] headers = dataGv.GetTemplateHeaders(); + + //打印Excel + new DataToExcelHelper(null).PrintExcel(this.Parent.Text, this.Parent.Text, searCriteria, headers, securityFunctions); + } + + /// + /// 有特殊要求的UI控件初始化设置,使用guiOperateHelper管理 + /// + private void InitBindingContext() + { + InitPermission(); + + guiOperateHelper = new GuiOperateHelper(); + } + + private void InitPermission() + { + viewBut.Set(SecurityPermissionPolicy.SecurityGroup, Operate.Find); + createBut.Set(SecurityPermissionPolicy.SecurityGroup, Operate.Insert); + amendBut.Set(SecurityPermissionPolicy.SecurityGroup, Operate.Update); + deleteBut.Set(SecurityPermissionPolicy.SecurityGroup, Operate.Delete); + } + + private void SetDisplayMode(bool enable) + { + guiOperateHelper.EnableControls(true, this.searchPanel, this.bottomPanel); + guiOperateHelper.EnableControls(false, dataGv); + + if (securityFunctions != null) + guiOperateHelper.EnableControls(enable, viewBut, amendBut, deleteBut); + else + guiOperateHelper.EnableControls(false, viewBut, amendBut, deleteBut); + + //如果是弹出的窗口,不显示 + createBut.Visible = !IsDialog; + dialogPanel.Visible = IsDialog; + operationPanel.Visible = !IsDialog; + + this.functionNameTxt.Focus(); + } + + private void searchBut_Click(object sender, EventArgs e) + { + try + { + Search(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + /// + /// 与Web同步写法 + /// + /// + private SecurityFunctionSearchCriteria PackSearchCriteria() + { + searchCriteria = new SecurityFunctionSearchCriteria(); + searchCriteria.limit = gridViewPagination.Limit; + searchCriteria.page = gridViewPagination.CurrentPage; + + List filters = new List(); + + SearchFilter filter = new SearchFilter(); + filter.Column = SecurityFunctionEntity.DB_FUNCTION_NAME; + filter.Type = SearchFilterTypePolicy.TEXT; + filter.Operator = SearchFilterOperatorPolicy.CONTAIN; + filter.Value = functionNameTxt.GetValue(); + filters.Add(filter); + + filter = new SearchFilter(); + filter.Column = SecurityFunctionEntity.DB_FUNCTION_LOCAL_NAME; + filter.Type = SearchFilterTypePolicy.TEXT; + filter.Operator = SearchFilterOperatorPolicy.CN_CONTAIN; + filter.Value = functionLocalNameTxt.GetValue(); + filters.Add(filter); + + filter = new SearchFilter(); + filter.Column = SecurityFunctionEntity.DB_FUNCTION_INDC; + filter.Type = SearchFilterTypePolicy.TEXT; + filter.Operator = SearchFilterOperatorPolicy.SINGLE; + filter.Value = (string)functionIndcCombo.GetValue(); + filters.Add(filter); + + + searchCriteria.Filter = filters.ToArray(); + + return searchCriteria; + } + + private void Search() + { + try + { + var data = securityFunctionRequest.FindBySearchCriteria(PackSearchCriteria()); + + if (data != null) securityFunctions = data.SecurityFunctionDisplayDatas; + + gridViewPagination.SetTotal(data.Total); + + if (securityFunctions == null || securityFunctions.Length == 0) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + guiOperateHelper.ResetControls(this.dataGv); + return; + } + + dataGv.SetDataSource(securityFunctions); + + SetDisplayMode(true); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void resetBut_Click(object sender, EventArgs e) + { + guiOperateHelper.ResetControls(this.mainPanel); + //Reset时默认会设置limit为AbstractSearchCriteria.limit,如果不同时,需要重新设置 + gridViewPagination.SetLimit(searchCriteria.limit); + SetDisplayMode(false); + } + + private void createBut_Click(object sender, EventArgs e) + { + DisplayPage(GuiDisplayMode.Create, null); + } + + private void DisplayPage(GuiDisplayMode mode, string functionName) + { + SecurityFunctionOperationLinkup linkupData = new SecurityFunctionOperationLinkup(); + linkupData.DisplayMode = Convert.ToInt32(mode); + linkupData.FunctionName = functionName; + + this.DisplayAbstractPage(typeof(SecurityFunctionOperationPage).Name, linkupData); + } + + + private void viewBut_Click(object sender, EventArgs e) + { + if (dataGv.RowCount <= 0 || dataGv.SelectedCells.Count <= 0) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + return; + } + + SecurityFunctionEntity data = dataGv.GetRowData(dataGv.SelectedCells[0].RowIndex); + + DisplayPage(GuiDisplayMode.View, data.FunctionName); + } + + private void amendBut_Click(object sender, EventArgs e) + { + if (dataGv.RowCount <= 0 || dataGv.SelectedCells.Count <= 0) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + return; + } + + SecurityFunctionEntity data = dataGv.GetRowData(dataGv.SelectedCells[0].RowIndex); + + DisplayPage(GuiDisplayMode.Amend, data.FunctionName); + } + + private void deleteBut_Click(object sender, EventArgs e) + { + try + { + Delete(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void Delete() + { + if (dataGv.RowCount <= 0 || dataGv.SelectedCells.Count <= 0) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + return; + } + + if (DialogResult.Yes != ShowMessageBox.ShowOption(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_CONFIRM_DEL_NULL), securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_DELETE))) return; + + SecurityFunctionEntity[] datas = dataGv.GetSelectedCellsData(); + + securityFunctionRequest.Deletes(datas.Select(x => x.FunctionName).ToArray()); + + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_SUCCEED_DELETED_NULL)); + + Search(); + } + + private void okBut_Click(object sender, EventArgs e) + { + try + { + if (dataGv.RowCount <= 0 || dataGv.SelectedCells.Count <= 0) return; + SecurityFunctionEntity[] datas = dataGv.GetSelectedCellsData(); + + this.ParentAbstractForm.OutputData = datas; + this.ParentAbstractForm.DialogResult = DialogResult.OK; + this.ParentAbstractForm.Close(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void cancelBut_Click(object sender, EventArgs e) + { + try + { + this.ParentAbstractForm.DialogResult = DialogResult.Cancel; + this.ParentAbstractForm.Close(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void dataGv_CellDoubleClick(object sender, DataGridViewCellEventArgs e) + { + try + { + if (IsDialog) + okBut_Click(null, null); + else + viewBut_Click(null, null); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + } +} diff --git a/CloudBuilder/CloudBuilder.Security.Gui/SecurityFunctionEnquiryPage.resx b/CloudBuilder/CloudBuilder.Security.Gui/SecurityFunctionEnquiryPage.resx new file mode 100644 index 0000000..5180a26 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/SecurityFunctionEnquiryPage.resx @@ -0,0 +1,150 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Security.Gui/SecurityFunctionOperationPage.Designer.cs b/CloudBuilder/CloudBuilder.Security.Gui/SecurityFunctionOperationPage.Designer.cs new file mode 100644 index 0000000..2323091 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/SecurityFunctionOperationPage.Designer.cs @@ -0,0 +1,847 @@ +namespace CloudBuilder.Security.Gui +{ + partial class SecurityFunctionOperationPage + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + DataGridViewCellStyle dataGridViewCellStyle6 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle7 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle8 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle9 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle10 = new DataGridViewCellStyle(); + delSonBut = new Krypton.Toolkit.KryptonButton(); + kryptonHeader2 = new Krypton.Toolkit.KryptonHeader(); + tableLayoutPanel3 = new TableLayoutPanel(); + tableLayoutPanel4 = new TableLayoutPanel(); + tableLayoutPanel1 = new TableLayoutPanel(); + delBut = new Krypton.Toolkit.KryptonButton(); + addBut = new Krypton.Toolkit.KryptonButton(); + kryptonHeader1 = new Krypton.Toolkit.KryptonHeader(); + dataGv = new Krypton.Toolkit.KryptonDataGridView(); + dependentDetailNameCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + dependentDetailDescriptionCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + dataSonGv = new Krypton.Toolkit.KryptonDataGridView(); + functionNameSonCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + functionLocalNameSonCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + orderbyCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + tableLayoutPanel2 = new TableLayoutPanel(); + functionIndcCombo = new Krypton.Toolkit.KryptonComboBox(); + functionNameLabel = new Krypton.Toolkit.KryptonLabel(); + permissionNameTxt = new Krypton.Toolkit.KryptonTextBox(); + permissionSearchBut = new Krypton.Toolkit.ButtonSpecAny(); + functionLocalNameLabel = new Krypton.Toolkit.KryptonLabel(); + functionEngNameLabel = new Krypton.Toolkit.KryptonLabel(); + functionNameTxt = new Krypton.Toolkit.KryptonTextBox(); + functionLocalNameTxt = new Krypton.Toolkit.KryptonTextBox(); + functionEngNameTxt = new Krypton.Toolkit.KryptonTextBox(); + pageNameLabel = new Krypton.Toolkit.KryptonLabel(); + pageNameTxt = new Krypton.Toolkit.KryptonTextBox(); + apiRouteLabel = new Krypton.Toolkit.KryptonLabel(); + functionIndcLabel = new Krypton.Toolkit.KryptonLabel(); + pageUrlLabel = new Krypton.Toolkit.KryptonLabel(); + iconLabel = new Krypton.Toolkit.KryptonLabel(); + permissionNameLabel = new Krypton.Toolkit.KryptonLabel(); + apiRouteTxt = new Krypton.Toolkit.KryptonTextBox(); + pageUrlTxt = new Krypton.Toolkit.KryptonTextBox(); + iconTxt = new Krypton.Toolkit.KryptonTextBox(); + kryptonPanel2 = new Krypton.Toolkit.KryptonPanel(); + addSonBut = new Krypton.Toolkit.KryptonButton(); + contentPanel = new TableLayoutPanel(); + tableLayoutPanel5 = new TableLayoutPanel(); + searchPanel = new TableLayoutPanel(); + createBut = new Krypton.Toolkit.KryptonButton(); + resetBut = new Krypton.Toolkit.KryptonButton(); + searchBut = new Krypton.Toolkit.KryptonButton(); + functionNameSearchLabel = new Krypton.Toolkit.KryptonLabel(); + functionNameSearchTxt = new Krypton.Toolkit.KryptonTextBox(); + functionNameSearchBut = new Krypton.Toolkit.ButtonSpecAny(); + kryptonPanel1 = new Krypton.Toolkit.KryptonPanel(); + bottomPanel = new TableLayoutPanel(); + savePanel = new TableLayoutPanel(); + cancelBut = new Krypton.Toolkit.KryptonButton(); + saveBut = new Krypton.Toolkit.KryptonButton(); + operationPanel = new TableLayoutPanel(); + deleteBut = new Krypton.Toolkit.KryptonButton(); + amendBut = new Krypton.Toolkit.KryptonButton(); + mainPanel = new TableLayoutPanel(); + topPanel = new TableLayoutPanel(); + tableLayoutPanel3.SuspendLayout(); + tableLayoutPanel4.SuspendLayout(); + tableLayoutPanel1.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)dataGv).BeginInit(); + ((System.ComponentModel.ISupportInitialize)dataSonGv).BeginInit(); + tableLayoutPanel2.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)functionIndcCombo).BeginInit(); + ((System.ComponentModel.ISupportInitialize)kryptonPanel2).BeginInit(); + contentPanel.SuspendLayout(); + tableLayoutPanel5.SuspendLayout(); + searchPanel.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)kryptonPanel1).BeginInit(); + bottomPanel.SuspendLayout(); + savePanel.SuspendLayout(); + operationPanel.SuspendLayout(); + mainPanel.SuspendLayout(); + topPanel.SuspendLayout(); + SuspendLayout(); + // + // delSonBut + // + delSonBut.Location = new Point(49, 3); + delSonBut.Name = "delSonBut"; + delSonBut.Size = new Size(40, 25); + delSonBut.TabIndex = 2; + delSonBut.Values.Image = Properties.Resources.navigate_minus; + delSonBut.Values.Text = ""; + delSonBut.Click += delSonBut_Click; + // + // kryptonHeader2 + // + kryptonHeader2.Dock = DockStyle.Top; + kryptonHeader2.Location = new Point(0, 324); + kryptonHeader2.Margin = new Padding(0); + kryptonHeader2.Name = "kryptonHeader2"; + kryptonHeader2.Size = new Size(1024, 31); + kryptonHeader2.TabIndex = 3; + kryptonHeader2.Values.Description = ""; + kryptonHeader2.Values.Heading = "下级菜单"; + kryptonHeader2.Values.Image = null; + // + // tableLayoutPanel3 + // + tableLayoutPanel3.AutoSize = true; + tableLayoutPanel3.AutoSizeMode = AutoSizeMode.GrowAndShrink; + tableLayoutPanel3.BackColor = SystemColors.Control; + tableLayoutPanel3.ColumnCount = 1; + tableLayoutPanel3.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel3.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 20F)); + tableLayoutPanel3.Controls.Add(tableLayoutPanel4, 0, 0); + tableLayoutPanel3.Dock = DockStyle.Fill; + tableLayoutPanel3.Location = new Point(0, 156); + tableLayoutPanel3.Margin = new Padding(0); + tableLayoutPanel3.Name = "tableLayoutPanel3"; + tableLayoutPanel3.RowCount = 1; + tableLayoutPanel3.RowStyles.Add(new RowStyle()); + tableLayoutPanel3.Size = new Size(1024, 168); + tableLayoutPanel3.TabIndex = 2; + // + // tableLayoutPanel4 + // + tableLayoutPanel4.AutoSize = true; + tableLayoutPanel4.AutoSizeMode = AutoSizeMode.GrowAndShrink; + tableLayoutPanel4.ColumnCount = 1; + tableLayoutPanel4.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F)); + tableLayoutPanel4.Controls.Add(tableLayoutPanel1, 0, 2); + tableLayoutPanel4.Controls.Add(kryptonHeader1, 0, 0); + tableLayoutPanel4.Controls.Add(dataGv, 0, 1); + tableLayoutPanel4.Dock = DockStyle.Fill; + tableLayoutPanel4.Location = new Point(0, 0); + tableLayoutPanel4.Margin = new Padding(0); + tableLayoutPanel4.Name = "tableLayoutPanel4"; + tableLayoutPanel4.RowCount = 3; + tableLayoutPanel4.RowStyles.Add(new RowStyle()); + tableLayoutPanel4.RowStyles.Add(new RowStyle()); + tableLayoutPanel4.RowStyles.Add(new RowStyle()); + tableLayoutPanel4.Size = new Size(1024, 168); + tableLayoutPanel4.TabIndex = 1; + // + // tableLayoutPanel1 + // + tableLayoutPanel1.AutoSize = true; + tableLayoutPanel1.AutoSizeMode = AutoSizeMode.GrowAndShrink; + tableLayoutPanel1.ColumnCount = 2; + tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel1.Controls.Add(delBut, 1, 0); + tableLayoutPanel1.Controls.Add(addBut, 0, 0); + tableLayoutPanel1.Location = new Point(3, 134); + tableLayoutPanel1.Name = "tableLayoutPanel1"; + tableLayoutPanel1.RowCount = 1; + tableLayoutPanel1.RowStyles.Add(new RowStyle()); + tableLayoutPanel1.Size = new Size(92, 31); + tableLayoutPanel1.TabIndex = 0; + // + // delBut + // + delBut.Location = new Point(49, 3); + delBut.Name = "delBut"; + delBut.Size = new Size(40, 25); + delBut.TabIndex = 2; + delBut.Values.Image = Properties.Resources.navigate_minus; + delBut.Values.Text = ""; + delBut.Click += delBut_Click; + // + // addBut + // + addBut.Location = new Point(3, 3); + addBut.Name = "addBut"; + addBut.Size = new Size(40, 25); + addBut.TabIndex = 1; + addBut.Values.Image = Properties.Resources.navigate_plus; + addBut.Values.Text = ""; + addBut.Click += addBut_Click; + // + // kryptonHeader1 + // + kryptonHeader1.Dock = DockStyle.Top; + kryptonHeader1.Location = new Point(0, 0); + kryptonHeader1.Margin = new Padding(0); + kryptonHeader1.Name = "kryptonHeader1"; + kryptonHeader1.Size = new Size(1024, 31); + kryptonHeader1.TabIndex = 0; + kryptonHeader1.Values.Description = ""; + kryptonHeader1.Values.Heading = "上级目录"; + kryptonHeader1.Values.Image = null; + // + // dataGv + // + dataGv.AllowUserToAddRows = false; + dataGv.AllowUserToDeleteRows = false; + dataGv.BorderStyle = BorderStyle.None; + dataGv.Columns.AddRange(new DataGridViewColumn[] { dependentDetailNameCol, dependentDetailDescriptionCol }); + dataGv.Dock = DockStyle.Fill; + dataGv.Location = new Point(0, 31); + dataGv.Margin = new Padding(0); + dataGv.Name = "dataGv"; + dataGv.Size = new Size(1024, 100); + dataGv.TabIndex = 2; + // + // dependentDetailNameCol + // + dependentDetailNameCol.DataPropertyName = "ParentFunctionName"; + dependentDetailNameCol.DefaultCellStyle = dataGridViewCellStyle6; + dependentDetailNameCol.HeaderText = "应用名"; + dependentDetailNameCol.MaxInputLength = 50; + dependentDetailNameCol.Name = "dependentDetailNameCol"; + dependentDetailNameCol.Resizable = DataGridViewTriState.True; + dependentDetailNameCol.Width = 300; + // + // dependentDetailDescriptionCol + // + dependentDetailDescriptionCol.DataPropertyName = "ParentFunctionLocalName"; + dependentDetailDescriptionCol.DefaultCellStyle = dataGridViewCellStyle7; + dependentDetailDescriptionCol.HeaderText = "中文名"; + dependentDetailDescriptionCol.MaxInputLength = 500; + dependentDetailDescriptionCol.Name = "dependentDetailDescriptionCol"; + dependentDetailDescriptionCol.Width = 300; + // + // dataSonGv + // + dataSonGv.AllowUserToAddRows = false; + dataSonGv.AllowUserToDeleteRows = false; + dataSonGv.BorderStyle = BorderStyle.None; + dataSonGv.Columns.AddRange(new DataGridViewColumn[] { functionNameSonCol, functionLocalNameSonCol, orderbyCol }); + dataSonGv.Dock = DockStyle.Fill; + dataSonGv.Location = new Point(0, 355); + dataSonGv.Margin = new Padding(0); + dataSonGv.Name = "dataSonGv"; + dataSonGv.Size = new Size(1024, 280); + dataSonGv.TabIndex = 4; + // + // functionNameSonCol + // + functionNameSonCol.DataPropertyName = "SonFunctionName"; + functionNameSonCol.DefaultCellStyle = dataGridViewCellStyle8; + functionNameSonCol.HeaderText = "应用名"; + functionNameSonCol.Name = "functionNameSonCol"; + functionNameSonCol.Width = 300; + // + // functionLocalNameSonCol + // + functionLocalNameSonCol.DataPropertyName = "SonFunctionLocalName"; + functionLocalNameSonCol.DefaultCellStyle = dataGridViewCellStyle9; + functionLocalNameSonCol.HeaderText = "中文名"; + functionLocalNameSonCol.Name = "functionLocalNameSonCol"; + functionLocalNameSonCol.Width = 300; + // + // orderbyCol + // + orderbyCol.DataPropertyName = "Orderby"; + orderbyCol.DefaultCellStyle = dataGridViewCellStyle10; + orderbyCol.HeaderText = "顺序"; + orderbyCol.MaxInputLength = 5; + orderbyCol.Name = "orderbyCol"; + orderbyCol.Width = 60; + // + // tableLayoutPanel2 + // + tableLayoutPanel2.AutoSize = true; + tableLayoutPanel2.AutoSizeMode = AutoSizeMode.GrowAndShrink; + tableLayoutPanel2.ColumnCount = 4; + tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel2.Controls.Add(functionIndcCombo, 3, 0); + tableLayoutPanel2.Controls.Add(functionNameLabel, 0, 0); + tableLayoutPanel2.Controls.Add(permissionNameTxt, 1, 4); + tableLayoutPanel2.Controls.Add(functionLocalNameLabel, 0, 1); + tableLayoutPanel2.Controls.Add(functionEngNameLabel, 0, 2); + tableLayoutPanel2.Controls.Add(functionNameTxt, 1, 0); + tableLayoutPanel2.Controls.Add(functionLocalNameTxt, 1, 1); + tableLayoutPanel2.Controls.Add(functionEngNameTxt, 1, 2); + tableLayoutPanel2.Controls.Add(pageNameLabel, 0, 3); + tableLayoutPanel2.Controls.Add(pageNameTxt, 1, 3); + tableLayoutPanel2.Controls.Add(apiRouteLabel, 2, 3); + tableLayoutPanel2.Controls.Add(functionIndcLabel, 2, 0); + tableLayoutPanel2.Controls.Add(pageUrlLabel, 2, 2); + tableLayoutPanel2.Controls.Add(iconLabel, 2, 1); + tableLayoutPanel2.Controls.Add(permissionNameLabel, 0, 4); + tableLayoutPanel2.Controls.Add(apiRouteTxt, 3, 3); + tableLayoutPanel2.Controls.Add(pageUrlTxt, 3, 2); + tableLayoutPanel2.Controls.Add(iconTxt, 3, 1); + tableLayoutPanel2.Location = new Point(3, 3); + tableLayoutPanel2.Name = "tableLayoutPanel2"; + tableLayoutPanel2.RowCount = 5; + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.Size = new Size(768, 145); + tableLayoutPanel2.TabIndex = 0; + // + // functionIndcCombo + // + functionIndcCombo.DropDownStyle = ComboBoxStyle.DropDownList; + functionIndcCombo.DropDownWidth = 200; + functionIndcCombo.IntegralHeight = false; + functionIndcCombo.Location = new Point(465, 3); + functionIndcCombo.Name = "functionIndcCombo"; + functionIndcCombo.Size = new Size(300, 22); + functionIndcCombo.StateCommon.ComboBox.Content.TextH = Krypton.Toolkit.PaletteRelativeAlign.Near; + functionIndcCombo.TabIndex = 10; + // + // functionNameLabel + // + functionNameLabel.Location = new Point(3, 3); + functionNameLabel.Name = "functionNameLabel"; + functionNameLabel.Size = new Size(52, 20); + functionNameLabel.TabIndex = 1; + functionNameLabel.Values.Text = "应用名:"; + // + // permissionNameTxt + // + permissionNameTxt.ButtonSpecs.Add(permissionSearchBut); + permissionNameTxt.Location = new Point(61, 119); + permissionNameTxt.MaxLength = 50; + permissionNameTxt.Name = "permissionNameTxt"; + permissionNameTxt.Size = new Size(300, 23); + permissionNameTxt.TabIndex = 5; + // + // permissionSearchBut + // + permissionSearchBut.Type = Krypton.Toolkit.PaletteButtonSpecStyle.WorkspaceMaximize; + permissionSearchBut.UniqueName = "29ee19b90170485ca37adcc57c43685d"; + permissionSearchBut.Click += permissionSearchBut_Click; + // + // functionLocalNameLabel + // + functionLocalNameLabel.Location = new Point(3, 32); + functionLocalNameLabel.Name = "functionLocalNameLabel"; + functionLocalNameLabel.Size = new Size(52, 20); + functionLocalNameLabel.TabIndex = 1; + functionLocalNameLabel.Values.Text = "中文名:"; + // + // functionEngNameLabel + // + functionEngNameLabel.Location = new Point(3, 61); + functionEngNameLabel.Name = "functionEngNameLabel"; + functionEngNameLabel.Size = new Size(52, 20); + functionEngNameLabel.TabIndex = 1; + functionEngNameLabel.Values.Text = "英文名:"; + // + // functionNameTxt + // + functionNameTxt.Dock = DockStyle.Fill; + functionNameTxt.Location = new Point(61, 3); + functionNameTxt.MaxLength = 50; + functionNameTxt.Name = "functionNameTxt"; + functionNameTxt.Size = new Size(300, 23); + functionNameTxt.TabIndex = 1; + // + // functionLocalNameTxt + // + functionLocalNameTxt.Location = new Point(61, 32); + functionLocalNameTxt.MaxLength = 50; + functionLocalNameTxt.Name = "functionLocalNameTxt"; + functionLocalNameTxt.Size = new Size(300, 23); + functionLocalNameTxt.TabIndex = 2; + // + // functionEngNameTxt + // + functionEngNameTxt.Dock = DockStyle.Fill; + functionEngNameTxt.Location = new Point(61, 61); + functionEngNameTxt.MaxLength = 50; + functionEngNameTxt.Name = "functionEngNameTxt"; + functionEngNameTxt.Size = new Size(300, 23); + functionEngNameTxt.TabIndex = 3; + // + // pageNameLabel + // + pageNameLabel.Location = new Point(3, 90); + pageNameLabel.Name = "pageNameLabel"; + pageNameLabel.Size = new Size(52, 20); + pageNameLabel.TabIndex = 1; + pageNameLabel.Values.Text = "页面名:"; + // + // pageNameTxt + // + pageNameTxt.Dock = DockStyle.Fill; + pageNameTxt.Location = new Point(61, 90); + pageNameTxt.MaxLength = 50; + pageNameTxt.Name = "pageNameTxt"; + pageNameTxt.Size = new Size(300, 23); + pageNameTxt.TabIndex = 4; + // + // apiRouteLabel + // + apiRouteLabel.Location = new Point(394, 90); + apiRouteLabel.Margin = new Padding(30, 3, 3, 3); + apiRouteLabel.Name = "apiRouteLabel"; + apiRouteLabel.Size = new Size(57, 20); + apiRouteLabel.TabIndex = 1; + apiRouteLabel.Values.Text = "Api路由:"; + // + // functionIndcLabel + // + functionIndcLabel.Location = new Point(394, 3); + functionIndcLabel.Margin = new Padding(30, 3, 3, 3); + functionIndcLabel.Name = "functionIndcLabel"; + functionIndcLabel.Size = new Size(62, 20); + functionIndcLabel.TabIndex = 1; + functionIndcLabel.Values.Text = "菜单项?"; + // + // pageUrlLabel + // + pageUrlLabel.Location = new Point(394, 61); + pageUrlLabel.Margin = new Padding(30, 3, 3, 3); + pageUrlLabel.Name = "pageUrlLabel"; + pageUrlLabel.Size = new Size(65, 20); + pageUrlLabel.TabIndex = 1; + pageUrlLabel.Values.Text = "页面路径:"; + // + // iconLabel + // + iconLabel.Location = new Point(394, 32); + iconLabel.Margin = new Padding(30, 3, 3, 3); + iconLabel.Name = "iconLabel"; + iconLabel.Size = new Size(39, 20); + iconLabel.TabIndex = 1; + iconLabel.Values.Text = "图标:"; + // + // permissionNameLabel + // + permissionNameLabel.Location = new Point(3, 119); + permissionNameLabel.Name = "permissionNameLabel"; + permissionNameLabel.Size = new Size(52, 20); + permissionNameLabel.TabIndex = 1; + permissionNameLabel.Values.Text = "权限名:"; + // + // apiRouteTxt + // + apiRouteTxt.Location = new Point(465, 90); + apiRouteTxt.MaxLength = 512; + apiRouteTxt.Name = "apiRouteTxt"; + apiRouteTxt.Size = new Size(300, 23); + apiRouteTxt.TabIndex = 13; + // + // pageUrlTxt + // + pageUrlTxt.Dock = DockStyle.Fill; + pageUrlTxt.Location = new Point(465, 61); + pageUrlTxt.MaxLength = 512; + pageUrlTxt.Name = "pageUrlTxt"; + pageUrlTxt.Size = new Size(300, 23); + pageUrlTxt.TabIndex = 12; + // + // iconTxt + // + iconTxt.Dock = DockStyle.Fill; + iconTxt.Location = new Point(465, 32); + iconTxt.MaxLength = 256; + iconTxt.Name = "iconTxt"; + iconTxt.Size = new Size(300, 23); + iconTxt.TabIndex = 11; + // + // kryptonPanel2 + // + kryptonPanel2.Dock = DockStyle.Fill; + kryptonPanel2.Location = new Point(0, 151); + kryptonPanel2.Margin = new Padding(0); + kryptonPanel2.Name = "kryptonPanel2"; + kryptonPanel2.Size = new Size(1024, 5); + kryptonPanel2.TabIndex = 1; + // + // addSonBut + // + addSonBut.Location = new Point(3, 3); + addSonBut.Name = "addSonBut"; + addSonBut.Size = new Size(40, 25); + addSonBut.TabIndex = 1; + addSonBut.Values.Image = Properties.Resources.navigate_plus; + addSonBut.Values.Text = ""; + addSonBut.Click += addSonBut_Click; + // + // contentPanel + // + contentPanel.ColumnCount = 1; + contentPanel.ColumnStyles.Add(new ColumnStyle()); + contentPanel.Controls.Add(tableLayoutPanel5, 0, 5); + contentPanel.Controls.Add(dataSonGv, 0, 4); + contentPanel.Controls.Add(kryptonHeader2, 0, 3); + contentPanel.Controls.Add(tableLayoutPanel3, 0, 2); + contentPanel.Controls.Add(tableLayoutPanel2, 0, 0); + contentPanel.Controls.Add(kryptonPanel2, 0, 1); + contentPanel.Dock = DockStyle.Fill; + contentPanel.Location = new Point(3, 51); + contentPanel.Name = "contentPanel"; + contentPanel.RowCount = 6; + contentPanel.RowStyles.Add(new RowStyle()); + contentPanel.RowStyles.Add(new RowStyle()); + contentPanel.RowStyles.Add(new RowStyle()); + contentPanel.RowStyles.Add(new RowStyle()); + contentPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 100F)); + contentPanel.RowStyles.Add(new RowStyle()); + contentPanel.Size = new Size(1018, 672); + contentPanel.TabIndex = 3; + // + // tableLayoutPanel5 + // + tableLayoutPanel5.AutoSize = true; + tableLayoutPanel5.AutoSizeMode = AutoSizeMode.GrowAndShrink; + tableLayoutPanel5.ColumnCount = 2; + tableLayoutPanel5.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel5.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel5.Controls.Add(delSonBut, 1, 0); + tableLayoutPanel5.Controls.Add(addSonBut, 0, 0); + tableLayoutPanel5.Location = new Point(3, 638); + tableLayoutPanel5.Name = "tableLayoutPanel5"; + tableLayoutPanel5.RowCount = 1; + tableLayoutPanel5.RowStyles.Add(new RowStyle()); + tableLayoutPanel5.Size = new Size(92, 31); + tableLayoutPanel5.TabIndex = 5; + // + // searchPanel + // + searchPanel.AutoSize = true; + searchPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + searchPanel.ColumnCount = 3; + searchPanel.ColumnStyles.Add(new ColumnStyle()); + searchPanel.ColumnStyles.Add(new ColumnStyle()); + searchPanel.ColumnStyles.Add(new ColumnStyle()); + searchPanel.Controls.Add(createBut, 2, 0); + searchPanel.Controls.Add(resetBut, 1, 0); + searchPanel.Controls.Add(searchBut, 0, 0); + searchPanel.Location = new Point(424, 0); + searchPanel.Margin = new Padding(60, 0, 0, 0); + searchPanel.Name = "searchPanel"; + searchPanel.RowCount = 1; + searchPanel.RowStyles.Add(new RowStyle()); + searchPanel.Size = new Size(288, 31); + searchPanel.TabIndex = 0; + // + // createBut + // + createBut.Location = new Point(195, 3); + createBut.Name = "createBut"; + createBut.Size = new Size(90, 25); + createBut.TabIndex = 3; + createBut.Values.Image = Properties.Resources.create_16; + createBut.Values.Text = "新增(&C)"; + createBut.Click += createBut_Click; + // + // resetBut + // + resetBut.Location = new Point(99, 3); + resetBut.Name = "resetBut"; + resetBut.Size = new Size(90, 25); + resetBut.TabIndex = 2; + resetBut.Values.Image = Properties.Resources.reset_16; + resetBut.Values.Text = "重置(&R)"; + resetBut.Click += resetBut_Click; + // + // searchBut + // + searchBut.Location = new Point(3, 3); + searchBut.Name = "searchBut"; + searchBut.Size = new Size(90, 25); + searchBut.TabIndex = 1; + searchBut.Values.Image = Properties.Resources.search_16; + searchBut.Values.Text = "查询(&S)"; + searchBut.Click += searchBut_Click; + // + // functionNameSearchLabel + // + functionNameSearchLabel.Location = new Point(3, 3); + functionNameSearchLabel.Name = "functionNameSearchLabel"; + functionNameSearchLabel.Size = new Size(52, 20); + functionNameSearchLabel.TabIndex = 1; + functionNameSearchLabel.Values.Text = "应用名:"; + // + // functionNameSearchTxt + // + functionNameSearchTxt.ButtonSpecs.Add(functionNameSearchBut); + functionNameSearchTxt.Location = new Point(61, 3); + functionNameSearchTxt.Name = "functionNameSearchTxt"; + functionNameSearchTxt.Size = new Size(300, 23); + functionNameSearchTxt.TabIndex = 0; + // + // functionNameSearchBut + // + functionNameSearchBut.Type = Krypton.Toolkit.PaletteButtonSpecStyle.WorkspaceMaximize; + functionNameSearchBut.UniqueName = "3a322a66645f4aff808be4720c638ad8"; + functionNameSearchBut.Click += functionNameSearchBut_Click; + // + // kryptonPanel1 + // + kryptonPanel1.Dock = DockStyle.Fill; + kryptonPanel1.Location = new Point(3, 40); + kryptonPanel1.Name = "kryptonPanel1"; + kryptonPanel1.Size = new Size(1018, 5); + kryptonPanel1.TabIndex = 1; + // + // bottomPanel + // + bottomPanel.AutoSize = true; + bottomPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + bottomPanel.ColumnCount = 1; + bottomPanel.ColumnStyles.Add(new ColumnStyle()); + bottomPanel.Controls.Add(savePanel, 0, 0); + bottomPanel.Controls.Add(operationPanel, 0, 1); + bottomPanel.Location = new Point(0, 726); + bottomPanel.Margin = new Padding(0); + bottomPanel.Name = "bottomPanel"; + bottomPanel.RowCount = 2; + bottomPanel.RowStyles.Add(new RowStyle()); + bottomPanel.RowStyles.Add(new RowStyle()); + bottomPanel.Size = new Size(198, 74); + bottomPanel.TabIndex = 2; + // + // savePanel + // + savePanel.AutoSize = true; + savePanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + savePanel.ColumnCount = 2; + savePanel.ColumnStyles.Add(new ColumnStyle()); + savePanel.ColumnStyles.Add(new ColumnStyle()); + savePanel.Controls.Add(cancelBut, 1, 0); + savePanel.Controls.Add(saveBut, 0, 0); + savePanel.Location = new Point(3, 3); + savePanel.Name = "savePanel"; + savePanel.RowCount = 1; + savePanel.RowStyles.Add(new RowStyle()); + savePanel.Size = new Size(192, 31); + savePanel.TabIndex = 0; + // + // cancelBut + // + cancelBut.Location = new Point(99, 3); + cancelBut.Name = "cancelBut"; + cancelBut.Size = new Size(90, 25); + cancelBut.TabIndex = 2; + cancelBut.Values.Image = Properties.Resources.cancel_16; + cancelBut.Values.Text = "取消(&L)"; + cancelBut.Click += cancelBut_Click; + // + // saveBut + // + saveBut.Location = new Point(3, 3); + saveBut.Name = "saveBut"; + saveBut.Size = new Size(90, 25); + saveBut.TabIndex = 1; + saveBut.Values.Image = Properties.Resources.save_16; + saveBut.Values.Text = "保存(&S)"; + saveBut.Click += saveBut_Click; + // + // operationPanel + // + operationPanel.AutoSize = true; + operationPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + operationPanel.ColumnCount = 2; + operationPanel.ColumnStyles.Add(new ColumnStyle()); + operationPanel.ColumnStyles.Add(new ColumnStyle()); + operationPanel.Controls.Add(deleteBut, 1, 0); + operationPanel.Controls.Add(amendBut, 0, 0); + operationPanel.Location = new Point(3, 40); + operationPanel.Name = "operationPanel"; + operationPanel.RowCount = 1; + operationPanel.RowStyles.Add(new RowStyle()); + operationPanel.Size = new Size(192, 31); + operationPanel.TabIndex = 0; + // + // deleteBut + // + deleteBut.Location = new Point(99, 3); + deleteBut.Name = "deleteBut"; + deleteBut.Size = new Size(90, 25); + deleteBut.TabIndex = 2; + deleteBut.Values.Image = Properties.Resources.delete_16; + deleteBut.Values.Text = "删除(&D)"; + deleteBut.Click += deleteBut_Click; + // + // amendBut + // + amendBut.Location = new Point(3, 3); + amendBut.Name = "amendBut"; + amendBut.Size = new Size(90, 25); + amendBut.TabIndex = 1; + amendBut.Values.Image = Properties.Resources.amend_16; + amendBut.Values.Text = "修改(&M)"; + amendBut.Click += amendBut_Click; + // + // mainPanel + // + mainPanel.ColumnCount = 1; + mainPanel.ColumnStyles.Add(new ColumnStyle()); + mainPanel.Controls.Add(topPanel, 0, 0); + mainPanel.Controls.Add(kryptonPanel1, 0, 1); + mainPanel.Controls.Add(bottomPanel, 0, 3); + mainPanel.Controls.Add(contentPanel, 0, 2); + mainPanel.Dock = DockStyle.Fill; + mainPanel.Location = new Point(0, 0); + mainPanel.Name = "mainPanel"; + mainPanel.RowCount = 4; + mainPanel.RowStyles.Add(new RowStyle()); + mainPanel.RowStyles.Add(new RowStyle()); + mainPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 100F)); + mainPanel.RowStyles.Add(new RowStyle()); + mainPanel.Size = new Size(1024, 800); + mainPanel.TabIndex = 3; + // + // topPanel + // + topPanel.AutoSize = true; + topPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + topPanel.ColumnCount = 3; + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 20F)); + topPanel.Controls.Add(searchPanel, 3, 0); + topPanel.Controls.Add(functionNameSearchLabel, 0, 0); + topPanel.Controls.Add(functionNameSearchTxt, 1, 0); + topPanel.Dock = DockStyle.Fill; + topPanel.Location = new Point(3, 3); + topPanel.Name = "topPanel"; + topPanel.RowCount = 1; + topPanel.RowStyles.Add(new RowStyle()); + topPanel.Size = new Size(1018, 31); + topPanel.TabIndex = 0; + // + // SecurityFunctionOperationPage + // + AutoScaleDimensions = new SizeF(7F, 15F); + AutoScaleMode = AutoScaleMode.Font; + Controls.Add(mainPanel); + Name = "SecurityFunctionOperationPage"; + tableLayoutPanel3.ResumeLayout(false); + tableLayoutPanel3.PerformLayout(); + tableLayoutPanel4.ResumeLayout(false); + tableLayoutPanel4.PerformLayout(); + tableLayoutPanel1.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)dataGv).EndInit(); + ((System.ComponentModel.ISupportInitialize)dataSonGv).EndInit(); + tableLayoutPanel2.ResumeLayout(false); + tableLayoutPanel2.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)functionIndcCombo).EndInit(); + ((System.ComponentModel.ISupportInitialize)kryptonPanel2).EndInit(); + contentPanel.ResumeLayout(false); + contentPanel.PerformLayout(); + tableLayoutPanel5.ResumeLayout(false); + searchPanel.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)kryptonPanel1).EndInit(); + bottomPanel.ResumeLayout(false); + bottomPanel.PerformLayout(); + savePanel.ResumeLayout(false); + operationPanel.ResumeLayout(false); + mainPanel.ResumeLayout(false); + mainPanel.PerformLayout(); + topPanel.ResumeLayout(false); + topPanel.PerformLayout(); + ResumeLayout(false); + } + + #endregion + + private Krypton.Toolkit.KryptonButton delSonBut; + private Krypton.Toolkit.KryptonHeader kryptonHeader2; + private TableLayoutPanel tableLayoutPanel3; + private TableLayoutPanel tableLayoutPanel4; + private TableLayoutPanel tableLayoutPanel1; + private Krypton.Toolkit.KryptonButton delBut; + private Krypton.Toolkit.KryptonButton addBut; + private Krypton.Toolkit.KryptonHeader kryptonHeader1; + private Krypton.Toolkit.KryptonDataGridView dataGv; + private Krypton.Toolkit.KryptonDataGridView dataSonGv; + private TableLayoutPanel tableLayoutPanel2; + private Krypton.Toolkit.KryptonComboBox functionIndcCombo; + private Krypton.Toolkit.KryptonLabel functionNameLabel; + private Krypton.Toolkit.KryptonTextBox permissionNameTxt; + private Krypton.Toolkit.ButtonSpecAny permissionSearchBut; + private Krypton.Toolkit.KryptonLabel functionLocalNameLabel; + private Krypton.Toolkit.KryptonLabel functionEngNameLabel; + private Krypton.Toolkit.KryptonTextBox functionNameTxt; + private Krypton.Toolkit.KryptonTextBox functionLocalNameTxt; + private Krypton.Toolkit.KryptonTextBox functionEngNameTxt; + private Krypton.Toolkit.KryptonLabel pageNameLabel; + private Krypton.Toolkit.KryptonTextBox pageNameTxt; + private Krypton.Toolkit.KryptonLabel apiRouteLabel; + private Krypton.Toolkit.KryptonLabel functionIndcLabel; + private Krypton.Toolkit.KryptonLabel pageUrlLabel; + private Krypton.Toolkit.KryptonLabel iconLabel; + private Krypton.Toolkit.KryptonLabel permissionNameLabel; + private Krypton.Toolkit.KryptonTextBox apiRouteTxt; + private Krypton.Toolkit.KryptonTextBox pageUrlTxt; + private Krypton.Toolkit.KryptonTextBox iconTxt; + private Krypton.Toolkit.KryptonPanel kryptonPanel2; + private Krypton.Toolkit.KryptonButton addSonBut; + private TableLayoutPanel contentPanel; + private TableLayoutPanel tableLayoutPanel5; + private TableLayoutPanel searchPanel; + private Krypton.Toolkit.KryptonButton createBut; + private Krypton.Toolkit.KryptonButton resetBut; + private Krypton.Toolkit.KryptonButton searchBut; + private Krypton.Toolkit.KryptonLabel functionNameSearchLabel; + private Krypton.Toolkit.KryptonTextBox functionNameSearchTxt; + private Krypton.Toolkit.ButtonSpecAny functionNameSearchBut; + private Krypton.Toolkit.KryptonPanel kryptonPanel1; + private TableLayoutPanel bottomPanel; + private TableLayoutPanel savePanel; + private Krypton.Toolkit.KryptonButton cancelBut; + private Krypton.Toolkit.KryptonButton saveBut; + private TableLayoutPanel operationPanel; + private Krypton.Toolkit.KryptonButton deleteBut; + private Krypton.Toolkit.KryptonButton amendBut; + private TableLayoutPanel mainPanel; + private TableLayoutPanel topPanel; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn dependentDetailNameCol; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn dependentDetailDescriptionCol; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn functionNameSonCol; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn functionLocalNameSonCol; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn orderbyCol; + } +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Security.Gui/SecurityFunctionOperationPage.cs b/CloudBuilder/CloudBuilder.Security.Gui/SecurityFunctionOperationPage.cs new file mode 100644 index 0000000..1c44a97 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/SecurityFunctionOperationPage.cs @@ -0,0 +1,707 @@ +using CloudBuilder.Core.Service; +using CloudBuilder.Gui; +using CloudBuilder.Request.Security; +using CloudBuilder.Security.Data; +using CloudBuilder.Security.Entity; +using CloudBuilder.Security.Linkup; +using CloudBuilder.Security.Policy; +using CloudBuilder.Security.SearchCriteria; +using DocumentFormat.OpenXml.Wordprocessing; +using Krypton.Toolkit; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http.Extensions; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace CloudBuilder.Security.Gui +{ + public partial class SecurityFunctionOperationPage : AbstractPage + { + private SecurityMessagePolicy securityMessagePolicy; + private SecurityFunctionRequest securityFunctionRequest; + private SecurityFunctionDisplayData securityFunctionEntity; + private SecurityFunctionData data; + public SecurityFunctionOperationPage() + { + InitializeComponent(); + } + + /// + /// 第一次加载时执行,只执行一次 + /// + public override void FunctionLoaded() + { + try + { + base.FunctionLoaded(); + //初始化容器------------------------------------- + securityMessagePolicy = ServiceHelper.GetTypeService()!; + securityFunctionRequest = ServiceHelper.GetTypeService(); + + //界面初始化 + InitGui(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void InitGui() + { + InitBindingContext(); + + InitComBox(); + + InitDisplayMode(); + + this.ParentAbstractForm.AcceptButton = this.searchBut; + this.ParentAbstractForm.CancelButton = this.resetBut; + } + + /// + /// 有特殊要求的UI控件初始化设置,Init与Add配对后,使用guiOperateHelper管理 + /// + private void InitBindingContext() + { + //需要绑定数据 + guiBindingContext = new GuiBindingContext(); + + InitPermission(); + + functionNameTxt.Set(SecurityFunctionEntity.FUNCTION_NAME, functionNameLabel.Text, EnumEditModeColor.Required); + functionEngNameTxt.Set(SecurityFunctionEntity.FUNCTION_ENG_NAME, functionEngNameLabel.Text, EnumEditModeColor.Required); + functionLocalNameTxt.Set(SecurityFunctionEntity.FUNCTION_LOCAL_NAME, functionLocalNameLabel.Text, EnumEditModeColor.Required); + pageNameTxt.Set(SecurityFunctionEntity.PAGE_NAME); + apiRouteTxt.Set(SecurityFunctionEntity.API_ROUTE); + pageUrlTxt.Set(SecurityFunctionEntity.PAGE_URL); + iconTxt.Set(SecurityFunctionEntity.ICON); + functionIndcCombo.Set(SecurityFunctionEntity.FUNCTION_INDC, functionIndcLabel.Text, EnumEditModeColor.Required); + permissionNameTxt.Set(SecurityFunctionDisplayData.PERMISSION_NAME); + + dataGv.InitColumn(false, true); + dataSonGv.InitColumn(false, true); + + guiOperateHelper = new GuiOperateHelper(); + } + + private void InitComBox() + { + functionIndcCombo.SetDataSource(YesNoPolicy.GetInstance().GetComposeMessages(), true); + } + + private void InitPermission() + { + createBut.Set(SecurityPermissionPolicy.SecurityFunction, Operate.Insert); + amendBut.Set(SecurityPermissionPolicy.SecurityFunction, Operate.Update); + deleteBut.Set(SecurityPermissionPolicy.SecurityFunction, Operate.Delete); + } + + /// + /// 每次从别的界面进入时执行,发生在FunctionLoaded之后 + /// + /// + public override void FunctionActivated(object param) + { + try + { + if (param == null) + { + functionNameSearchTxt.Focus(); + return; + } + + InitDisplayMode(); + + SecurityFunctionOperationLinkup linkup = null; + + if (param is SecurityFunctionOperationLinkup) + { + linkup = (SecurityFunctionOperationLinkup)param; + } + + this.DisplayMode = (GuiDisplayMode)linkup.DisplayMode; + + functionNameSearchTxt.Text = linkup.FunctionName; + + if (this.DisplayMode == GuiDisplayMode.View) + { + Search(); + } + else if (this.DisplayMode == GuiDisplayMode.Create) + { + Create(); + } + else if (this.DisplayMode == GuiDisplayMode.Amend) + { + Search(); + Amend(); + } + + functionNameSearchTxt.Focus(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + public override void FunctionSelected() + { + this.ParentAbstractForm.AcceptButton = this.searchBut; + if (!IsDialog) + this.ParentAbstractForm.CancelButton = this.resetBut; + else + this.ParentAbstractForm.CancelButton = this.cancelBut; + + functionNameSearchTxt.Focus(); + } + + public override bool FunctionDeactivating() + { + if (this.DisplayMode == GuiDisplayMode.View) + { + return true; + } + else + { + return CancelEditing(); + } + } + + private bool CancelEditing() + { + DialogResult result = ShowMessageBox.ShowOption(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_CONFIRM_CANCEL), securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_CONFIRM)); + + //从外部跳转(非mainKryptonNavigator),result第一次不生效?,所以再执行一次生效 + if (result == DialogResult.Cancel) + { + result = ShowMessageBox.ShowOption(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_CONFIRM_CANCEL), securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_CONFIRM)); + } + + if (result == DialogResult.No) + { + return false; + } + + Cancel(); + + return true; + } + + private void InitDisplayMode() + { + this.DisplayMode = GuiDisplayMode.View; + + SetDisplayMode(); + } + + private void SetDisplayMode() + { + if (this.DisplayMode == GuiDisplayMode.View) + { + savePanel.Visible = false; + operationPanel.Visible = true; + + guiOperateHelper.EnableControls(true, topPanel); + guiOperateHelper.EnableControls(false, contentPanel); + //查詢有記錄時,修改等控件有效 + if (securityFunctionEntity != null) + guiOperateHelper.EnableControls(true, bottomPanel); + else + guiOperateHelper.EnableControls(false, bottomPanel); + } + else if (this.DisplayMode == GuiDisplayMode.Amend || this.DisplayMode == GuiDisplayMode.Create) + { + savePanel.Visible = true; + operationPanel.Visible = false; + + guiOperateHelper.EnableControls(false, topPanel); + guiOperateHelper.EnableControls(true, bottomPanel, contentPanel); + + if (this.DisplayMode == GuiDisplayMode.Amend) guiOperateHelper.EnableControls(false, functionNameTxt); + + guiOperateHelper.EnableControls(false, dataGv); + functionLocalNameSonCol.ReadOnly = true; + functionLocalNameSonCol.DefaultCellStyle.BackColor = System.Drawing.Color.Silver; + functionNameSonCol.ReadOnly = true; + functionNameSonCol.DefaultCellStyle.BackColor = System.Drawing.Color.Silver; + dataGv.DefaultCellStyle.BackColor = System.Drawing.Color.Silver; + } + } + + private void PackUIToEntity() + { + guiBindingContext.DataPack(); + + SecurityFunctionMapViewEntity[] securityFunctionMapParents = dataGv.GetAllRows(); + + if (securityFunctionMapParents == null || securityFunctionMapParents.Length == 0) + data.SecurityFunctionMapParents = null; + else + data.SecurityFunctionMapParents = securityFunctionMapParents.Select(x => new SecurityFunctionMapViewEntity() + { + ParentFunctionName = x.ParentFunctionName, + SonFunctionName = functionNameTxt.Text + }).ToArray(); + + SecurityFunctionMapViewEntity[] securityFunctionMapSons = dataSonGv.GetAllRows(); + + if (securityFunctionMapSons == null || securityFunctionMapSons.Length == 0) + data.SecurityFunctionMapSons = null; + else + data.SecurityFunctionMapSons = securityFunctionMapSons.Select(x => new SecurityFunctionMapViewEntity() + { + ParentFunctionName = functionNameTxt.Text, + SonFunctionName = x.SonFunctionName, + Orderby = x.Orderby + }).ToArray(); + } + + private bool SaveValidate() + { + if (!guiOperateHelper.CheckValidate(this.mainPanel)) return false; + + return true; + } + + private void Search() + { + try + { + if (string.IsNullOrEmpty(functionNameSearchTxt.Text)) return; + + Reset(); + + data = securityFunctionRequest.FindByKey(functionNameSearchTxt.Text); + + if (data == null || data.SecurityFunction == null) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + } + else + { + securityFunctionEntity = data.SecurityFunction; + + PackEntityToUI(); + + SetDisplayMode(); + } + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void Create() + { + this.DisplayMode = GuiDisplayMode.Create; + + guiOperateHelper.ResetControls(this.mainPanel); + + SetDisplayMode(); + + data = new SecurityFunctionData(); + securityFunctionEntity = new SecurityFunctionDisplayData() + { + CreatedBy = string.Empty, + UpdatedBy = string.Empty, + CreatedDatetime = DateTime.Now, + UpdatedDatetime = DateTime.Now, + }; + data.SecurityFunction = securityFunctionEntity; + + PackEntityToUI(); + + functionNameTxt.Focus(); + } + + private void Amend() + { + this.DisplayMode = GuiDisplayMode.Amend; + + SetDisplayMode(); + } + + private void PackEntityToUI() + { + guiBindingContext.DataBind(data.SecurityFunction, this); + + dataGv.SetDataSource(data.SecurityFunctionMapParents); + dataSonGv.SetDataSource(data.SecurityFunctionMapSons); + } + + private void Reset() + { + this.DisplayMode = GuiDisplayMode.View; + + securityFunctionEntity = null; + + guiOperateHelper.ResetControls(this.contentPanel); + + SetDisplayMode(); + + functionNameSearchTxt.Focus(); + } + + public void Cancel() + { + if (!string.IsNullOrEmpty(functionNameSearchTxt.Text)) + Search(); + else + Reset(); + + } + + + private void functionNameSearchBut_Click(object sender, EventArgs e) + { + try + { + AbstractForm dialog = GetAbstractDialog(typeof(SecurityFunctionEnquiryPage).Name); + + if (DialogResult.OK != dialog.ShowDialog()) return; + + functionNameSearchTxt.Text = ((SecurityFunctionEntity[])dialog.OutputData)[0].FunctionName; + + Search(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void permissionSearchBut_Click(object sender, EventArgs e) + { + try + { + AbstractForm dialog = GetAbstractDialog(typeof(SecurityPermissionEnquiryPage).Name); + + if (DialogResult.OK != dialog.ShowDialog()) return; + + permissionNameTxt.Text = ((SecurityPermissionEntity[])dialog.OutputData)[0].PermissionName; + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void searchBut_Click(object sender, EventArgs e) + { + try + { + if (string.IsNullOrEmpty(functionNameSearchTxt.Text)) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_VALID_INPUT, GuiOperateHelper.GetLabelText(functionNameSearchLabel.Text))); + this.functionNameSearchTxt.Focus(); + return; + } + + this.DisplayMode = GuiDisplayMode.View; + + Search(); + + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void resetBut_Click(object sender, EventArgs e) + { + try + { + guiOperateHelper.ResetControls(this.topPanel); + Reset(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void createBut_Click(object sender, EventArgs e) + { + HandleException(() => Create()); + } + + private void amendBut_Click(object sender, EventArgs e) + { + HandleException(() => Amend()); + } + + private void deleteBut_Click(object sender, EventArgs e) + { + try + { + if (securityFunctionEntity == null) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + return; + } + + if (DialogResult.Yes != ShowMessageBox.ShowOption(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_CONFIRM_DEL_NULL), securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_DELETE))) return; + + securityFunctionRequest.Delete(securityFunctionEntity.FunctionName); + + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_SUCCEED_DELETED_NULL)); + + Reset(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void saveBut_Click(object sender, EventArgs e) + { + try + { + if (!SaveValidate()) return; + + PackUIToEntity(); + + + if (this.DisplayMode == GuiDisplayMode.Create) + securityFunctionRequest.Insert(data); + else + securityFunctionRequest.Update(data); + + + ShowMessageBox.ShowInfo((this.DisplayMode == GuiDisplayMode.Create) ? + securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_SUCCEED_CREATED_NULL) : + securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_SUCCEED_UPDATED_NULL)); + + functionNameSearchTxt.Text = securityFunctionEntity.FunctionName; + Search(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void cancelBut_Click(object sender, EventArgs e) + { + HandleException(() => CancelEditing()); + } + + private void addBut_Click(object sender, EventArgs e) + { + try + { + AbstractForm dialog = GetAbstractDialog(typeof(SecurityFunctionEnquiryPage).Name); + + SecurityFunctionSearchCriteria criteria = new SecurityFunctionSearchCriteria(); + criteria.FunctionIndc = YesNoPolicy.NO; + criteria.FunctionIndcEnable = false; + if (DialogResult.OK != dialog.ShowViewDialog(null, criteria)) return; + + SecurityFunctionEntity[] securityFunctions = (SecurityFunctionEntity[])dialog.OutputData; + SecurityFunctionMapViewEntity map; + List l = new List(); + + List parentFunctionNames = new List(); + + int maxOrder = 1; + if (dataSonGv.Rows.Count > 1) + { + maxOrder = dataSonGv.GetAllRows().Max(x => x.Orderby) + 1; + parentFunctionNames = dataSonGv.GetAllRows().Select(x => x.ParentFunctionName).ToList(); + } + + foreach (SecurityFunctionEntity securityFunction in securityFunctions) + { + if (parentFunctionNames.Contains(securityFunction.FunctionName)) continue; + parentFunctionNames.Add(securityFunction.FunctionName); + + map = new SecurityFunctionMapViewEntity(); + map.ParentFunctionName = securityFunction.FunctionName; + map.ParentFunctionLocalName = securityFunction.FunctionLocalName; + map.Orderby = maxOrder++; + + l.Add(map); + } + + dataGv.AddRow(l); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void delBut_Click(object sender, EventArgs e) + { + if (dataGv.RowCount <= 0 || dataGv.SelectedCells.Count <= 0) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + return; + } + + dataGv.DeleteRows(dataGv.SelectedCells); + } + + private void addSonBut_Click(object sender, EventArgs e) + { + try + { + if (functionIndcCombo.GetValue() != YesNoPolicy.NO) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_VALID_SELECT, GuiOperateHelper.GetLabelText(functionIndcLabel.Text))); + functionIndcCombo.Focus(); + return; + } + + AbstractForm dialog = GetAbstractDialog(typeof(SecurityFunctionEnquiryPage).Name); + + SecurityFunctionSearchCriteria criteria = new SecurityFunctionSearchCriteria(); + criteria.FunctionIndc = YesNoPolicy.YES; + criteria.FunctionIndcEnable = false; + if (DialogResult.OK != dialog.ShowViewDialog(null, criteria)) return; + + SecurityFunctionEntity[] securityFunctions = (SecurityFunctionEntity[])dialog.OutputData; + SecurityFunctionMapViewEntity map; + List l = new List(); + + List sonFunctionNames = new List(); + + int maxOrder = 1; + if (dataSonGv.Rows.Count > 1) + { + maxOrder = dataSonGv.GetAllRows().Max(x => x.Orderby) + 1; + sonFunctionNames = dataSonGv.GetAllRows().Select(x => x.SonFunctionName).ToList(); + } + foreach (SecurityFunctionEntity securityFunction in securityFunctions) + { + if (sonFunctionNames.Contains(securityFunction.FunctionName)) continue; + sonFunctionNames.Add(securityFunction.FunctionName); + + map = new SecurityFunctionMapViewEntity(); + map.SonFunctionName = securityFunction.FunctionName; + map.SonFunctionLocalName = securityFunction.FunctionLocalName; + map.Orderby = maxOrder++; + + l.Add(map); + } + + dataSonGv.AddRow(l); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void delSonBut_Click(object sender, EventArgs e) + { + if (dataSonGv.RowCount <= 0 || dataSonGv.SelectedCells.Count <= 0) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + return; + } + + dataSonGv.DeleteRows(dataSonGv.SelectedCells); + } + } +} diff --git a/CloudBuilder/CloudBuilder.Security.Gui/SecurityFunctionOperationPage.resx b/CloudBuilder/CloudBuilder.Security.Gui/SecurityFunctionOperationPage.resx new file mode 100644 index 0000000..d573b74 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/SecurityFunctionOperationPage.resx @@ -0,0 +1,138 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + True + + + True + + + True + + + True + + + True + + + True + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Security.Gui/SecurityGroupEnquiryPage.Designer.cs b/CloudBuilder/CloudBuilder.Security.Gui/SecurityGroupEnquiryPage.Designer.cs new file mode 100644 index 0000000..4088d29 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/SecurityGroupEnquiryPage.Designer.cs @@ -0,0 +1,387 @@ +namespace CloudBuilder.Security.Gui +{ + partial class SecurityGroupEnquiryPage + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + DataGridViewCellStyle dataGridViewCellStyle7 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle8 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle9 = new DataGridViewCellStyle(); + mainPanel = new TableLayoutPanel(); + topPanel = new TableLayoutPanel(); + searchGroupNameLabel = new Krypton.Toolkit.KryptonLabel(); + groupNameTxt = new Krypton.Toolkit.KryptonTextBox(); + searchPanel = new TableLayoutPanel(); + searchBut = new Krypton.Toolkit.KryptonButton(); + resetBut = new Krypton.Toolkit.KryptonButton(); + createBut = new Krypton.Toolkit.KryptonButton(); + contextPanel = new TableLayoutPanel(); + dataGv = new Krypton.Toolkit.KryptonDataGridView(); + groupNameCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + groupLocalNameCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + groupEngNameCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + gridViewPagination = new CloudBuilder.Gui.GridViewPagination(); + bottomPanel = new TableLayoutPanel(); + operationPanel = new TableLayoutPanel(); + viewBut = new Krypton.Toolkit.KryptonButton(); + amendBut = new Krypton.Toolkit.KryptonButton(); + deleteBut = new Krypton.Toolkit.KryptonButton(); + dialogPanel = new TableLayoutPanel(); + okBut = new Krypton.Toolkit.KryptonButton(); + cancelBut = new Krypton.Toolkit.KryptonButton(); + mainPanel.SuspendLayout(); + topPanel.SuspendLayout(); + searchPanel.SuspendLayout(); + contextPanel.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)dataGv).BeginInit(); + bottomPanel.SuspendLayout(); + operationPanel.SuspendLayout(); + dialogPanel.SuspendLayout(); + SuspendLayout(); + // + // mainPanel + // + mainPanel.ColumnCount = 1; + mainPanel.ColumnStyles.Add(new ColumnStyle()); + mainPanel.Controls.Add(topPanel, 0, 0); + mainPanel.Controls.Add(contextPanel, 0, 1); + mainPanel.Controls.Add(bottomPanel, 0, 2); + mainPanel.Dock = DockStyle.Fill; + mainPanel.Location = new Point(0, 0); + mainPanel.Name = "mainPanel"; + mainPanel.RowCount = 3; + mainPanel.RowStyles.Add(new RowStyle()); + mainPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 100F)); + mainPanel.RowStyles.Add(new RowStyle()); + mainPanel.Size = new Size(1024, 800); + mainPanel.TabIndex = 0; + // + // topPanel + // + topPanel.AutoSize = true; + topPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + topPanel.ColumnCount = 5; + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.Controls.Add(searchGroupNameLabel, 0, 0); + topPanel.Controls.Add(groupNameTxt, 1, 0); + topPanel.Controls.Add(searchPanel, 4, 0); + topPanel.Dock = DockStyle.Fill; + topPanel.Location = new Point(3, 3); + topPanel.Name = "topPanel"; + topPanel.RowCount = 1; + topPanel.RowStyles.Add(new RowStyle()); + topPanel.Size = new Size(1018, 31); + topPanel.TabIndex = 0; + // + // searchGroupNameLabel + // + searchGroupNameLabel.Location = new Point(3, 3); + searchGroupNameLabel.Name = "searchGroupNameLabel"; + searchGroupNameLabel.Size = new Size(52, 20); + searchGroupNameLabel.TabIndex = 999; + searchGroupNameLabel.Values.Text = "组别名:"; + // + // groupNameTxt + // + groupNameTxt.Location = new Point(61, 3); + groupNameTxt.Name = "groupNameTxt"; + groupNameTxt.Size = new Size(200, 23); + groupNameTxt.TabIndex = 0; + // + // searchPanel + // + searchPanel.AutoSize = true; + searchPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + searchPanel.ColumnCount = 3; + searchPanel.ColumnStyles.Add(new ColumnStyle()); + searchPanel.ColumnStyles.Add(new ColumnStyle()); + searchPanel.ColumnStyles.Add(new ColumnStyle()); + searchPanel.Controls.Add(searchBut, 0, 0); + searchPanel.Controls.Add(resetBut, 1, 0); + searchPanel.Controls.Add(createBut, 2, 0); + searchPanel.Location = new Point(324, 0); + searchPanel.Margin = new Padding(60, 0, 0, 0); + searchPanel.Name = "searchPanel"; + searchPanel.RowCount = 1; + searchPanel.RowStyles.Add(new RowStyle()); + searchPanel.Size = new Size(288, 31); + searchPanel.TabIndex = 999; + // + // searchBut + // + searchBut.Location = new Point(3, 3); + searchBut.Name = "searchBut"; + searchBut.Size = new Size(90, 25); + searchBut.TabIndex = 0; + searchBut.Values.Image = Properties.Resources.search_16; + searchBut.Values.Text = "查询(&S)"; + searchBut.Click += searchBut_Click; + // + // resetBut + // + resetBut.Location = new Point(99, 3); + resetBut.Name = "resetBut"; + resetBut.Size = new Size(90, 25); + resetBut.TabIndex = 0; + resetBut.Values.Image = Properties.Resources.reset_16; + resetBut.Values.Text = "重置(&R)"; + resetBut.Click += resetBut_Click; + // + // createBut + // + createBut.Location = new Point(195, 3); + createBut.Name = "createBut"; + createBut.Size = new Size(90, 25); + createBut.TabIndex = 0; + createBut.Values.Image = Properties.Resources.create_16; + createBut.Values.Text = "新增(&C)"; + createBut.Click += createBut_Click; + // + // contextPanel + // + contextPanel.ColumnCount = 1; + contextPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F)); + contextPanel.Controls.Add(dataGv, 0, 0); + contextPanel.Controls.Add(gridViewPagination, 0, 1); + contextPanel.Dock = DockStyle.Fill; + contextPanel.Location = new Point(3, 40); + contextPanel.Name = "contextPanel"; + contextPanel.RowCount = 2; + contextPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 50F)); + contextPanel.RowStyles.Add(new RowStyle()); + contextPanel.Size = new Size(1018, 683); + contextPanel.TabIndex = 999; + // + // dataGv + // + dataGv.AllowUserToAddRows = false; + dataGv.AllowUserToDeleteRows = false; + dataGv.BorderStyle = BorderStyle.None; + dataGv.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize; + dataGv.Columns.AddRange(new DataGridViewColumn[] { groupNameCol, groupLocalNameCol, groupEngNameCol }); + dataGv.Dock = DockStyle.Fill; + dataGv.Location = new Point(3, 3); + dataGv.Name = "dataGv"; + dataGv.Size = new Size(1012, 647); + dataGv.TabIndex = 0; + dataGv.CellDoubleClick += dataGv_CellDoubleClick; + // + // groupNameCol + // + groupNameCol.DataPropertyName = "GroupName"; + groupNameCol.DefaultCellStyle = dataGridViewCellStyle7; + groupNameCol.HeaderText = "组别名"; + groupNameCol.Name = "groupNameCol"; + groupNameCol.Width = 260; + // + // groupLocalNameCol + // + groupLocalNameCol.DataPropertyName = "GroupLocalName"; + groupLocalNameCol.DefaultCellStyle = dataGridViewCellStyle8; + groupLocalNameCol.HeaderText = "中文名"; + groupLocalNameCol.Name = "groupLocalNameCol"; + groupLocalNameCol.Width = 260; + // + // groupEngNameCol + // + groupEngNameCol.DataPropertyName = "GroupEngName"; + groupEngNameCol.DefaultCellStyle = dataGridViewCellStyle9; + groupEngNameCol.HeaderText = "英文名"; + groupEngNameCol.Name = "groupEngNameCol"; + groupEngNameCol.Resizable = DataGridViewTriState.True; + groupEngNameCol.Width = 260; + // + // gridViewPagination + // + gridViewPagination.AutoSizeMode = AutoSizeMode.GrowAndShrink; + gridViewPagination.CurrentPage = 0; + gridViewPagination.Dock = DockStyle.Fill; + gridViewPagination.Limit = 20; + gridViewPagination.Location = new Point(0, 653); + gridViewPagination.Margin = new Padding(0); + gridViewPagination.Name = "gridViewPagination"; + gridViewPagination.Page = 0; + gridViewPagination.Size = new Size(1018, 30); + gridViewPagination.TabIndex = 999; + gridViewPagination.Total = 0; + // + // bottomPanel + // + bottomPanel.AutoSize = true; + bottomPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + bottomPanel.ColumnCount = 2; + bottomPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F)); + bottomPanel.ColumnStyles.Add(new ColumnStyle()); + bottomPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 20F)); + bottomPanel.Controls.Add(operationPanel, 0, 0); + bottomPanel.Controls.Add(dialogPanel, 2, 1); + bottomPanel.Dock = DockStyle.Fill; + bottomPanel.Location = new Point(3, 729); + bottomPanel.Name = "bottomPanel"; + bottomPanel.RowCount = 2; + bottomPanel.RowStyles.Add(new RowStyle()); + bottomPanel.RowStyles.Add(new RowStyle()); + bottomPanel.Size = new Size(1018, 68); + bottomPanel.TabIndex = 999; + // + // operationPanel + // + operationPanel.AutoSize = true; + operationPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + operationPanel.ColumnCount = 3; + operationPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F)); + operationPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 101F)); + operationPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F)); + operationPanel.Controls.Add(viewBut, 0, 0); + operationPanel.Controls.Add(amendBut, 1, 0); + operationPanel.Controls.Add(deleteBut, 2, 0); + operationPanel.Location = new Point(0, 0); + operationPanel.Margin = new Padding(0); + operationPanel.Name = "operationPanel"; + operationPanel.RowCount = 1; + operationPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 50F)); + operationPanel.Size = new Size(293, 31); + operationPanel.TabIndex = 0; + // + // viewBut + // + viewBut.Location = new Point(3, 3); + viewBut.Name = "viewBut"; + viewBut.Size = new Size(90, 25); + viewBut.TabIndex = 0; + viewBut.Values.Image = Properties.Resources.view_16; + viewBut.Values.Text = "查看(&V)"; + viewBut.Click += viewBut_Click; + // + // amendBut + // + amendBut.Location = new Point(99, 3); + amendBut.Name = "amendBut"; + amendBut.Size = new Size(90, 25); + amendBut.TabIndex = 0; + amendBut.Values.Image = Properties.Resources.amend_16; + amendBut.Values.Text = "修改(&A)"; + amendBut.Click += amendBut_Click; + // + // deleteBut + // + deleteBut.Location = new Point(200, 3); + deleteBut.Name = "deleteBut"; + deleteBut.Size = new Size(90, 25); + deleteBut.TabIndex = 0; + deleteBut.Values.Image = Properties.Resources.delete_16; + deleteBut.Values.Text = "删除(&D)"; + deleteBut.Click += deleteBut_Click; + // + // dialogPanel + // + dialogPanel.AutoSize = true; + dialogPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + dialogPanel.ColumnCount = 2; + dialogPanel.ColumnStyles.Add(new ColumnStyle()); + dialogPanel.ColumnStyles.Add(new ColumnStyle()); + dialogPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 20F)); + dialogPanel.Controls.Add(okBut, 0, 0); + dialogPanel.Controls.Add(cancelBut, 1, 0); + dialogPanel.Dock = DockStyle.Fill; + dialogPanel.Location = new Point(823, 34); + dialogPanel.Name = "dialogPanel"; + dialogPanel.RowCount = 1; + dialogPanel.RowStyles.Add(new RowStyle()); + dialogPanel.Size = new Size(192, 31); + dialogPanel.TabIndex = 1; + // + // okBut + // + okBut.Location = new Point(3, 3); + okBut.Name = "okBut"; + okBut.Size = new Size(90, 25); + okBut.TabIndex = 0; + okBut.Values.Image = Properties.Resources.ok_16; + okBut.Values.Text = "确定(&O)"; + okBut.Click += okBut_Click; + // + // cancelBut + // + cancelBut.Location = new Point(99, 3); + cancelBut.Name = "cancelBut"; + cancelBut.Size = new Size(90, 25); + cancelBut.TabIndex = 0; + cancelBut.Values.Image = Properties.Resources.close_16; + cancelBut.Values.Text = "取消(&C)"; + cancelBut.Click += cancelBut_Click; + // + // SecurityGroupEnquiryPage + // + AutoScaleDimensions = new SizeF(7F, 15F); + AutoScaleMode = AutoScaleMode.Font; + Controls.Add(mainPanel); + Name = "SecurityGroupEnquiryPage"; + mainPanel.ResumeLayout(false); + mainPanel.PerformLayout(); + topPanel.ResumeLayout(false); + topPanel.PerformLayout(); + searchPanel.ResumeLayout(false); + contextPanel.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)dataGv).EndInit(); + bottomPanel.ResumeLayout(false); + bottomPanel.PerformLayout(); + operationPanel.ResumeLayout(false); + dialogPanel.ResumeLayout(false); + ResumeLayout(false); + } + + #endregion + + private TableLayoutPanel mainPanel; + private TableLayoutPanel topPanel; + private TableLayoutPanel searchPanel; + private Krypton.Toolkit.KryptonButton searchBut; + private Krypton.Toolkit.KryptonButton resetBut; + private Krypton.Toolkit.KryptonButton createBut; + private TableLayoutPanel contextPanel; + private TableLayoutPanel bottomPanel; + private TableLayoutPanel operationPanel; + private Krypton.Toolkit.KryptonButton viewBut; + private Krypton.Toolkit.KryptonButton amendBut; + private Krypton.Toolkit.KryptonButton deleteBut; + private Krypton.Toolkit.KryptonLabel searchGroupNameLabel; + private Krypton.Toolkit.KryptonTextBox groupNameTxt; + private Krypton.Toolkit.KryptonDataGridView dataGv; + private TableLayoutPanel dialogPanel; + private Krypton.Toolkit.KryptonButton okBut; + private Krypton.Toolkit.KryptonButton cancelBut; + private CloudBuilder.Gui.GridViewPagination gridViewPagination; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn groupNameCol; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn groupLocalNameCol; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn groupEngNameCol; + } +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Security.Gui/SecurityGroupEnquiryPage.cs b/CloudBuilder/CloudBuilder.Security.Gui/SecurityGroupEnquiryPage.cs new file mode 100644 index 0000000..3cae0fb --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/SecurityGroupEnquiryPage.cs @@ -0,0 +1,415 @@ +using ClosedXML.Excel; +using CloudBuilder.Core.DependencyInjection.Form; +using CloudBuilder.Core.Report; +using CloudBuilder.Core.Service; +using CloudBuilder.Gui; +using CloudBuilder.Gui.DependencyInjection; +using CloudBuilder.Request.Security; +using CloudBuilder.Security.Data; +using CloudBuilder.Security.Entity; +using CloudBuilder.Security.Linkup; +using CloudBuilder.Security.Policy; +using CloudBuilder.Security.SearchCriteria; +using DocumentFormat.OpenXml.Spreadsheet; +using Krypton.Toolkit; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http.Extensions; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.IdentityModel.Tokens; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + + +namespace CloudBuilder.Security.Gui +{ + public partial class SecurityGroupEnquiryPage : AbstractPage + { + private SecurityGroupEntity[] securityGroups = null!; + private SecurityGroupSearchCriteria searchCriteria = null!; + private BindingContextAttributeProvider provider; + private SecurityGroupRequest securityGroupRequest; + private SecurityMessagePolicy securityMessagePolicy; + + //初始化Page,注入容器内,不要在此做任何事情 + public SecurityGroupEnquiryPage() + { + InitializeComponent(); + } + + /// + /// 第一次加载时执行,只执行一次 + /// + public override void FunctionLoaded() + { + try + { + base.FunctionLoaded(); + //初始化容器------------------------------------- + securityGroupRequest = ServiceHelper.GetTypeService(); + securityMessagePolicy = ServiceHelper.GetTypeService()!; + + //界面初始化 + InitGui(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + /// + /// 每次从别的界面进入时执行,不包括下面的界面切换,发生在FunctionLoaded之后 + /// 这个是有参数传入,常用于查询界面进入到操作界面发生 + /// + /// + public override void FunctionActivated(object param) + { + base.FunctionActivated(param); + groupNameTxt.Focus(); + } + /// + /// 当Page被选中时执行,用于Tab导航的切换,没有参数变化,跟FunctionActivated有区别 + /// + public override void FunctionSelected() + { + this.ParentAbstractForm.AcceptButton = this.searchBut; + if (!IsDialog) + this.ParentAbstractForm.CancelButton = this.resetBut; + else + this.ParentAbstractForm.CancelButton = this.cancelBut; + + groupNameTxt.Focus(); + } + /// + /// 控件的初始化 + /// + private void InitGui() + { + //DataGridView初始化不要自动生成列,且允许重排列名操作 + dataGv.InitColumn(true, true); + //初始化绑定设置 + InitBindingContext(); + //设置显示模式 + SetDisplayMode(true); + + InitGridViewPagination(); + } + /// + /// DataGridView分页控件初始化 + /// + private void InitGridViewPagination() + { + searchCriteria = new SecurityGroupSearchCriteria(); + gridViewPagination.SetLimit(searchCriteria.limit); + gridViewPagination.OnPaginationChanged += Search; + gridViewPagination.OnPrint += Print; + } + + /// + /// 打印当前查询结果 + /// + private void Print() + { + //設置查詢條件 + List searCriteria = new List(); + if (!string.IsNullOrEmpty(groupNameTxt.Text)) + searCriteria.Add(searchGroupNameLabel.Text + groupNameTxt.Text); + + //設置每列的格式 + TemplateHeader[] headers = dataGv.GetTemplateHeaders(); + + //打印Excel + new DataToExcelHelper(null).PrintExcel(this.Parent.Text, this.Parent.Text, searCriteria, headers, securityGroups); + } + + /// + /// 有特殊要求的UI控件初始化设置,使用guiOperateHelper管理 + /// + private void InitBindingContext() + { + InitPermission(); + + guiOperateHelper = new GuiOperateHelper(); + } + + private void InitPermission() + { + viewBut.Set(SecurityPermissionPolicy.SecurityGroup, Operate.Find); + createBut.Set(SecurityPermissionPolicy.SecurityGroup, Operate.Insert); + amendBut.Set(SecurityPermissionPolicy.SecurityGroup, Operate.Update); + deleteBut.Set(SecurityPermissionPolicy.SecurityGroup, Operate.Delete); + } + + private void SetDisplayMode(bool enable) + { + guiOperateHelper.EnableControls(true, this.searchPanel, this.bottomPanel); + guiOperateHelper.EnableControls(false, dataGv); + + if (securityGroups != null) + guiOperateHelper.EnableControls(enable, viewBut, amendBut, deleteBut); + else + guiOperateHelper.EnableControls(false, viewBut, amendBut, deleteBut); + + //如果是弹出的窗口,不显示 + createBut.Visible = !IsDialog; + dialogPanel.Visible = IsDialog; + operationPanel.Visible = !IsDialog; + + this.groupNameTxt.Focus(); + } + + private void searchBut_Click(object sender, EventArgs e) + { + try + { + Search(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + /// + /// 与Web同步写法 + /// + /// + private SecurityGroupSearchCriteria PackSearchCriteria() + { + searchCriteria = new SecurityGroupSearchCriteria(); + searchCriteria.limit = gridViewPagination.Limit; + searchCriteria.page = gridViewPagination.CurrentPage; + + List filters = new List(); + + SearchFilter filter = new SearchFilter(); + filter.Column = SecurityGroupEntity.DB_GROUP_NAME; + filter.Type = SearchFilterTypePolicy.TEXT; + filter.Operator = SearchFilterOperatorPolicy.CONTAIN; + filter.Value = groupNameTxt.GetValue(); + filters.Add(filter); + + searchCriteria.Filter = filters.ToArray(); + + return searchCriteria; + } + + private void Search() + { + try + { + var data = securityGroupRequest.FindBySearchCriteria(PackSearchCriteria()); + + if (data != null) securityGroups = data.Datas; + + gridViewPagination.SetTotal(data.Total); + + if (securityGroups == null || securityGroups.Length == 0) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + guiOperateHelper.ResetControls(this.dataGv); + return; + } + + dataGv.SetDataSource(securityGroups); + + SetDisplayMode(true); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void resetBut_Click(object sender, EventArgs e) + { + guiOperateHelper.ResetControls(this.mainPanel); + //Reset时默认会设置limit为AbstractSearchCriteria.limit,如果不同时,需要重新设置 + gridViewPagination.SetLimit(searchCriteria.limit); + SetDisplayMode(false); + } + + private void createBut_Click(object sender, EventArgs e) + { + DisplayPage(GuiDisplayMode.Create, null); + } + + private void DisplayPage(GuiDisplayMode mode, string groupName) + { + SecurityGroupOperationLinkup linkupData = new SecurityGroupOperationLinkup(); + linkupData.DisplayMode = Convert.ToInt32(mode); + linkupData.GroupName = groupName; + + this.DisplayAbstractPage(typeof(SecurityGroupOperationPage).Name, linkupData); + } + + + private void viewBut_Click(object sender, EventArgs e) + { + if (dataGv.RowCount <= 0 || dataGv.SelectedCells.Count <= 0) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + return; + } + + SecurityGroupEntity data = dataGv.GetRowData(dataGv.SelectedCells[0].RowIndex); + + DisplayPage(GuiDisplayMode.View, data.GroupName); + } + + private void amendBut_Click(object sender, EventArgs e) + { + if (dataGv.RowCount <= 0 || dataGv.SelectedCells.Count <= 0) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + return; + } + + SecurityGroupEntity data = dataGv.GetRowData(dataGv.SelectedCells[0].RowIndex); + + DisplayPage(GuiDisplayMode.Amend, data.GroupName); + } + + private void deleteBut_Click(object sender, EventArgs e) + { + try + { + Delete(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void Delete() + { + if (dataGv.RowCount <= 0 || dataGv.SelectedCells.Count <= 0) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + return; + } + + if (DialogResult.Yes != ShowMessageBox.ShowOption(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_CONFIRM_DEL_NULL), securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_DELETE))) return; + + SecurityGroupEntity[] datas = dataGv.GetSelectedCellsData(); + + securityGroupRequest.Deletes(datas.Select(x => x.GroupName).ToArray()); + + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_SUCCEED_DELETED_NULL)); + + Search(); + } + + private void okBut_Click(object sender, EventArgs e) + { + try + { + if (dataGv.RowCount <= 0 || dataGv.SelectedCells.Count <= 0) return; + //SecurityGroupEntity data = dataGv.GetRowData(dataGv.SelectedCells[0].RowIndex); + SecurityGroupEntity[] datas = dataGv.GetSelectedCellsData(); + this.ParentAbstractForm.OutputData = datas; + this.ParentAbstractForm.DialogResult = DialogResult.OK; + this.ParentAbstractForm.Close(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void cancelBut_Click(object sender, EventArgs e) + { + try + { + this.ParentAbstractForm.DialogResult = DialogResult.Cancel; + this.ParentAbstractForm.Close(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void dataGv_CellDoubleClick(object sender, DataGridViewCellEventArgs e) + { + try + { + if (IsDialog) + okBut_Click(null, null); + else + viewBut_Click(null, null); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + } +} diff --git a/CloudBuilder/CloudBuilder.Security.Gui/SecurityGroupEnquiryPage.resx b/CloudBuilder/CloudBuilder.Security.Gui/SecurityGroupEnquiryPage.resx new file mode 100644 index 0000000..6f0defd --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/SecurityGroupEnquiryPage.resx @@ -0,0 +1,159 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Security.Gui/SecurityGroupOperationPage.Designer.cs b/CloudBuilder/CloudBuilder.Security.Gui/SecurityGroupOperationPage.Designer.cs new file mode 100644 index 0000000..ded2781 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/SecurityGroupOperationPage.Designer.cs @@ -0,0 +1,941 @@ +namespace CloudBuilder.Security.Gui +{ + partial class SecurityGroupOperationPage + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + DataGridViewCellStyle dataGridViewCellStyle1 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle2 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle3 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle4 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle5 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle6 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle7 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle8 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle9 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle10 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle11 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle12 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle13 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle14 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle15 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle16 = new DataGridViewCellStyle(); + kryptonPanel2 = new Krypton.Toolkit.KryptonPanel(); + contentPanel = new TableLayoutPanel(); + actorGv = new Krypton.Toolkit.KryptonDataGridView(); + actorNameCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + actorLocalNameCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + kryptonHeader3 = new Krypton.Toolkit.KryptonHeader(); + tableLayoutPanel5 = new TableLayoutPanel(); + delDsBut = new Krypton.Toolkit.KryptonButton(); + dataDsGv = new Krypton.Toolkit.KryptonDataGridView(); + dsDependentCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + dsDependentDetailNameCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + dsDependentDetailDescriptionCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + dsViewIndcCol = new Krypton.Toolkit.KryptonDataGridViewCheckBoxColumn(); + dsCreateIndcCol = new Krypton.Toolkit.KryptonDataGridViewCheckBoxColumn(); + dsAmendIndcCol = new Krypton.Toolkit.KryptonDataGridViewCheckBoxColumn(); + dsDeleteIndcCol = new Krypton.Toolkit.KryptonDataGridViewCheckBoxColumn(); + kryptonHeader2 = new Krypton.Toolkit.KryptonHeader(); + tableLayoutPanel3 = new TableLayoutPanel(); + tableLayoutPanel4 = new TableLayoutPanel(); + tableLayoutPanel1 = new TableLayoutPanel(); + delBut = new Krypton.Toolkit.KryptonButton(); + addBut = new Krypton.Toolkit.KryptonButton(); + kryptonHeader1 = new Krypton.Toolkit.KryptonHeader(); + dataGv = new Krypton.Toolkit.KryptonDataGridView(); + permissionNameCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + permissionDescriptionCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + dependentCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + viewIndcCol = new Krypton.Toolkit.KryptonDataGridViewCheckBoxColumn(); + createIndcCol = new Krypton.Toolkit.KryptonDataGridViewCheckBoxColumn(); + amendIndcCol = new Krypton.Toolkit.KryptonDataGridViewCheckBoxColumn(); + deleteIndcCol = new Krypton.Toolkit.KryptonDataGridViewCheckBoxColumn(); + tableLayoutPanel2 = new TableLayoutPanel(); + groupNameLabel = new Krypton.Toolkit.KryptonLabel(); + groupLocalNameLabel = new Krypton.Toolkit.KryptonLabel(); + groupEngNameLabel = new Krypton.Toolkit.KryptonLabel(); + groupNameTxt = new Krypton.Toolkit.KryptonTextBox(); + groupLocalNameTxt = new Krypton.Toolkit.KryptonTextBox(); + groupEngNameTxt = new Krypton.Toolkit.KryptonTextBox(); + tableLayoutPanel6 = new TableLayoutPanel(); + delActorBut = new Krypton.Toolkit.KryptonButton(); + addActorBut = new Krypton.Toolkit.KryptonButton(); + permissionSearchBut = new Krypton.Toolkit.ButtonSpecAny(); + searchPanel = new TableLayoutPanel(); + createBut = new Krypton.Toolkit.KryptonButton(); + resetBut = new Krypton.Toolkit.KryptonButton(); + searchBut = new Krypton.Toolkit.KryptonButton(); + groupNameSearchLabel = new Krypton.Toolkit.KryptonLabel(); + groupNameSearchTxt = new Krypton.Toolkit.KryptonTextBox(); + groupNameSearchBut = new Krypton.Toolkit.ButtonSpecAny(); + kryptonPanel1 = new Krypton.Toolkit.KryptonPanel(); + bottomPanel = new TableLayoutPanel(); + savePanel = new TableLayoutPanel(); + cancelBut = new Krypton.Toolkit.KryptonButton(); + saveBut = new Krypton.Toolkit.KryptonButton(); + operationPanel = new TableLayoutPanel(); + deleteBut = new Krypton.Toolkit.KryptonButton(); + amendBut = new Krypton.Toolkit.KryptonButton(); + topPanel = new TableLayoutPanel(); + mainPanel = new TableLayoutPanel(); + ((System.ComponentModel.ISupportInitialize)kryptonPanel2).BeginInit(); + contentPanel.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)actorGv).BeginInit(); + tableLayoutPanel5.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)dataDsGv).BeginInit(); + tableLayoutPanel3.SuspendLayout(); + tableLayoutPanel4.SuspendLayout(); + tableLayoutPanel1.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)dataGv).BeginInit(); + tableLayoutPanel2.SuspendLayout(); + tableLayoutPanel6.SuspendLayout(); + searchPanel.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)kryptonPanel1).BeginInit(); + bottomPanel.SuspendLayout(); + savePanel.SuspendLayout(); + operationPanel.SuspendLayout(); + topPanel.SuspendLayout(); + mainPanel.SuspendLayout(); + SuspendLayout(); + // + // kryptonPanel2 + // + kryptonPanel2.Dock = DockStyle.Fill; + kryptonPanel2.Location = new Point(0, 93); + kryptonPanel2.Margin = new Padding(0); + kryptonPanel2.Name = "kryptonPanel2"; + kryptonPanel2.Size = new Size(1024, 5); + kryptonPanel2.TabIndex = 1; + // + // contentPanel + // + contentPanel.AutoScroll = true; + contentPanel.ColumnCount = 1; + contentPanel.ColumnStyles.Add(new ColumnStyle()); + contentPanel.Controls.Add(actorGv, 0, 7); + contentPanel.Controls.Add(kryptonHeader3, 0, 6); + contentPanel.Controls.Add(tableLayoutPanel5, 0, 5); + contentPanel.Controls.Add(dataDsGv, 0, 4); + contentPanel.Controls.Add(kryptonHeader2, 0, 3); + contentPanel.Controls.Add(tableLayoutPanel3, 0, 2); + contentPanel.Controls.Add(tableLayoutPanel2, 0, 0); + contentPanel.Controls.Add(kryptonPanel2, 0, 1); + contentPanel.Controls.Add(tableLayoutPanel6, 0, 8); + contentPanel.Dock = DockStyle.Fill; + contentPanel.Location = new Point(3, 51); + contentPanel.Name = "contentPanel"; + contentPanel.RowCount = 9; + contentPanel.RowStyles.Add(new RowStyle()); + contentPanel.RowStyles.Add(new RowStyle()); + contentPanel.RowStyles.Add(new RowStyle()); + contentPanel.RowStyles.Add(new RowStyle()); + contentPanel.RowStyles.Add(new RowStyle()); + contentPanel.RowStyles.Add(new RowStyle()); + contentPanel.RowStyles.Add(new RowStyle()); + contentPanel.RowStyles.Add(new RowStyle()); + contentPanel.RowStyles.Add(new RowStyle()); + contentPanel.Size = new Size(1018, 672); + contentPanel.TabIndex = 3; + // + // actorGv + // + actorGv.AllowUserToAddRows = false; + actorGv.AllowUserToDeleteRows = false; + actorGv.BorderStyle = BorderStyle.None; + actorGv.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize; + actorGv.Columns.AddRange(new DataGridViewColumn[] { actorNameCol, actorLocalNameCol }); + actorGv.Dock = DockStyle.Fill; + actorGv.Location = new Point(0, 945); + actorGv.Margin = new Padding(0); + actorGv.Name = "actorGv"; + actorGv.Size = new Size(1024, 300); + actorGv.TabIndex = 7; + // + // actorNameCol + // + actorNameCol.DataPropertyName = "ActorName"; + actorNameCol.DefaultCellStyle = dataGridViewCellStyle1; + actorNameCol.HeaderText = "角色名"; + actorNameCol.Name = "actorNameCol"; + actorNameCol.Resizable = DataGridViewTriState.True; + actorNameCol.Width = 300; + // + // actorLocalNameCol + // + actorLocalNameCol.DataPropertyName = "ActorLocalName"; + actorLocalNameCol.DefaultCellStyle = dataGridViewCellStyle2; + actorLocalNameCol.HeaderText = "角色中文名"; + actorLocalNameCol.Name = "actorLocalNameCol"; + actorLocalNameCol.Resizable = DataGridViewTriState.True; + actorLocalNameCol.Width = 300; + // + // kryptonHeader3 + // + kryptonHeader3.Dock = DockStyle.Top; + kryptonHeader3.Location = new Point(0, 914); + kryptonHeader3.Margin = new Padding(0); + kryptonHeader3.Name = "kryptonHeader3"; + kryptonHeader3.Size = new Size(1024, 31); + kryptonHeader3.TabIndex = 6; + kryptonHeader3.Values.Description = ""; + kryptonHeader3.Values.Heading = "授权角色"; + kryptonHeader3.Values.Image = null; + // + // tableLayoutPanel5 + // + tableLayoutPanel5.AutoSize = true; + tableLayoutPanel5.AutoSizeMode = AutoSizeMode.GrowAndShrink; + tableLayoutPanel5.ColumnCount = 2; + tableLayoutPanel5.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel5.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel5.Controls.Add(delDsBut, 1, 0); + tableLayoutPanel5.Location = new Point(3, 880); + tableLayoutPanel5.Name = "tableLayoutPanel5"; + tableLayoutPanel5.RowCount = 1; + tableLayoutPanel5.RowStyles.Add(new RowStyle()); + tableLayoutPanel5.Size = new Size(46, 31); + tableLayoutPanel5.TabIndex = 5; + // + // delDsBut + // + delDsBut.Location = new Point(3, 3); + delDsBut.Name = "delDsBut"; + delDsBut.Size = new Size(40, 25); + delDsBut.TabIndex = 2; + delDsBut.Values.Image = Properties.Resources.navigate_minus; + delDsBut.Values.Text = ""; + delDsBut.Click += delDsBut_Click; + // + // dataDsGv + // + dataDsGv.AllowUserToAddRows = false; + dataDsGv.AllowUserToDeleteRows = false; + dataDsGv.BorderStyle = BorderStyle.None; + dataDsGv.Columns.AddRange(new DataGridViewColumn[] { dsDependentCol, dsDependentDetailNameCol, dsDependentDetailDescriptionCol, dsViewIndcCol, dsCreateIndcCol, dsAmendIndcCol, dsDeleteIndcCol }); + dataDsGv.Dock = DockStyle.Fill; + dataDsGv.Location = new Point(0, 597); + dataDsGv.Margin = new Padding(0); + dataDsGv.Name = "dataDsGv"; + dataDsGv.Size = new Size(1024, 280); + dataDsGv.TabIndex = 4; + // + // dsDependentCol + // + dsDependentCol.DataPropertyName = "Dependent"; + dsDependentCol.DefaultCellStyle = dataGridViewCellStyle3; + dsDependentCol.HeaderText = "扩展名"; + dsDependentCol.Name = "dsDependentCol"; + dsDependentCol.Resizable = DataGridViewTriState.True; + dsDependentCol.Width = 100; + // + // dsDependentDetailNameCol + // + dsDependentDetailNameCol.DataPropertyName = "DependentDetailName"; + dsDependentDetailNameCol.DefaultCellStyle = dataGridViewCellStyle4; + dsDependentDetailNameCol.HeaderText = "扩展子项目名"; + dsDependentDetailNameCol.Name = "dsDependentDetailNameCol"; + dsDependentDetailNameCol.Resizable = DataGridViewTriState.True; + dsDependentDetailNameCol.Width = 200; + // + // dsDependentDetailDescriptionCol + // + dsDependentDetailDescriptionCol.DataPropertyName = "DependentDetailDescription"; + dsDependentDetailDescriptionCol.DefaultCellStyle = dataGridViewCellStyle5; + dsDependentDetailDescriptionCol.HeaderText = "扩展子项目中文名"; + dsDependentDetailDescriptionCol.Name = "dsDependentDetailDescriptionCol"; + dsDependentDetailDescriptionCol.Resizable = DataGridViewTriState.True; + dsDependentDetailDescriptionCol.Width = 200; + // + // dsViewIndcCol + // + dsViewIndcCol.DataPropertyName = "ViewIndc"; + dataGridViewCellStyle6.Alignment = DataGridViewContentAlignment.MiddleCenter; + dataGridViewCellStyle6.NullValue = false; + dsViewIndcCol.DefaultCellStyle = dataGridViewCellStyle6; + dsViewIndcCol.FalseValue = "N"; + dsViewIndcCol.HeaderText = "查看"; + dsViewIndcCol.IndeterminateValue = null; + dsViewIndcCol.Name = "dsViewIndcCol"; + dsViewIndcCol.TrueValue = "Y"; + // + // dsCreateIndcCol + // + dsCreateIndcCol.DataPropertyName = "CreateIndc"; + dataGridViewCellStyle7.Alignment = DataGridViewContentAlignment.MiddleCenter; + dataGridViewCellStyle7.NullValue = false; + dsCreateIndcCol.DefaultCellStyle = dataGridViewCellStyle7; + dsCreateIndcCol.FalseValue = "N"; + dsCreateIndcCol.HeaderText = "新增"; + dsCreateIndcCol.IndeterminateValue = null; + dsCreateIndcCol.Name = "dsCreateIndcCol"; + dsCreateIndcCol.TrueValue = "Y"; + // + // dsAmendIndcCol + // + dsAmendIndcCol.DataPropertyName = "AmendIndc"; + dataGridViewCellStyle8.Alignment = DataGridViewContentAlignment.MiddleCenter; + dataGridViewCellStyle8.NullValue = false; + dsAmendIndcCol.DefaultCellStyle = dataGridViewCellStyle8; + dsAmendIndcCol.FalseValue = "N"; + dsAmendIndcCol.HeaderText = "修改"; + dsAmendIndcCol.IndeterminateValue = null; + dsAmendIndcCol.Name = "dsAmendIndcCol"; + dsAmendIndcCol.TrueValue = "Y"; + // + // dsDeleteIndcCol + // + dsDeleteIndcCol.DataPropertyName = "DeleteIndc"; + dataGridViewCellStyle9.Alignment = DataGridViewContentAlignment.MiddleCenter; + dataGridViewCellStyle9.NullValue = false; + dsDeleteIndcCol.DefaultCellStyle = dataGridViewCellStyle9; + dsDeleteIndcCol.FalseValue = "N"; + dsDeleteIndcCol.HeaderText = "删除"; + dsDeleteIndcCol.IndeterminateValue = null; + dsDeleteIndcCol.Name = "dsDeleteIndcCol"; + dsDeleteIndcCol.TrueValue = "Y"; + // + // kryptonHeader2 + // + kryptonHeader2.Dock = DockStyle.Top; + kryptonHeader2.Location = new Point(0, 566); + kryptonHeader2.Margin = new Padding(0); + kryptonHeader2.Name = "kryptonHeader2"; + kryptonHeader2.Size = new Size(1024, 31); + kryptonHeader2.TabIndex = 3; + kryptonHeader2.Values.Description = ""; + kryptonHeader2.Values.Heading = "扩展权限明细"; + kryptonHeader2.Values.Image = null; + // + // tableLayoutPanel3 + // + tableLayoutPanel3.AutoSize = true; + tableLayoutPanel3.AutoSizeMode = AutoSizeMode.GrowAndShrink; + tableLayoutPanel3.BackColor = SystemColors.Control; + tableLayoutPanel3.ColumnCount = 1; + tableLayoutPanel3.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel3.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 20F)); + tableLayoutPanel3.Controls.Add(tableLayoutPanel4, 0, 0); + tableLayoutPanel3.Dock = DockStyle.Fill; + tableLayoutPanel3.Location = new Point(0, 98); + tableLayoutPanel3.Margin = new Padding(0); + tableLayoutPanel3.Name = "tableLayoutPanel3"; + tableLayoutPanel3.RowCount = 1; + tableLayoutPanel3.RowStyles.Add(new RowStyle()); + tableLayoutPanel3.Size = new Size(1024, 468); + tableLayoutPanel3.TabIndex = 2; + // + // tableLayoutPanel4 + // + tableLayoutPanel4.AutoSize = true; + tableLayoutPanel4.AutoSizeMode = AutoSizeMode.GrowAndShrink; + tableLayoutPanel4.ColumnCount = 1; + tableLayoutPanel4.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F)); + tableLayoutPanel4.Controls.Add(tableLayoutPanel1, 0, 2); + tableLayoutPanel4.Controls.Add(kryptonHeader1, 0, 0); + tableLayoutPanel4.Controls.Add(dataGv, 0, 1); + tableLayoutPanel4.Dock = DockStyle.Fill; + tableLayoutPanel4.Location = new Point(0, 0); + tableLayoutPanel4.Margin = new Padding(0); + tableLayoutPanel4.Name = "tableLayoutPanel4"; + tableLayoutPanel4.RowCount = 3; + tableLayoutPanel4.RowStyles.Add(new RowStyle()); + tableLayoutPanel4.RowStyles.Add(new RowStyle()); + tableLayoutPanel4.RowStyles.Add(new RowStyle()); + tableLayoutPanel4.Size = new Size(1024, 468); + tableLayoutPanel4.TabIndex = 1; + // + // tableLayoutPanel1 + // + tableLayoutPanel1.AutoSize = true; + tableLayoutPanel1.AutoSizeMode = AutoSizeMode.GrowAndShrink; + tableLayoutPanel1.ColumnCount = 2; + tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel1.Controls.Add(delBut, 1, 0); + tableLayoutPanel1.Controls.Add(addBut, 0, 0); + tableLayoutPanel1.Location = new Point(3, 434); + tableLayoutPanel1.Name = "tableLayoutPanel1"; + tableLayoutPanel1.RowCount = 1; + tableLayoutPanel1.RowStyles.Add(new RowStyle()); + tableLayoutPanel1.Size = new Size(92, 31); + tableLayoutPanel1.TabIndex = 0; + // + // delBut + // + delBut.Location = new Point(49, 3); + delBut.Name = "delBut"; + delBut.Size = new Size(40, 25); + delBut.TabIndex = 2; + delBut.Values.Image = Properties.Resources.navigate_minus; + delBut.Values.Text = ""; + delBut.Click += delBut_Click; + // + // addBut + // + addBut.Location = new Point(3, 3); + addBut.Name = "addBut"; + addBut.Size = new Size(40, 25); + addBut.TabIndex = 1; + addBut.Values.Image = Properties.Resources.navigate_plus; + addBut.Values.Text = ""; + addBut.Click += addBut_Click; + // + // kryptonHeader1 + // + kryptonHeader1.Dock = DockStyle.Top; + kryptonHeader1.Location = new Point(0, 0); + kryptonHeader1.Margin = new Padding(0); + kryptonHeader1.Name = "kryptonHeader1"; + kryptonHeader1.Size = new Size(1024, 31); + kryptonHeader1.TabIndex = 0; + kryptonHeader1.Values.Description = ""; + kryptonHeader1.Values.Heading = "权限明细"; + kryptonHeader1.Values.Image = null; + // + // dataGv + // + dataGv.AllowUserToAddRows = false; + dataGv.AllowUserToDeleteRows = false; + dataGv.BorderStyle = BorderStyle.None; + dataGv.Columns.AddRange(new DataGridViewColumn[] { permissionNameCol, permissionDescriptionCol, dependentCol, viewIndcCol, createIndcCol, amendIndcCol, deleteIndcCol }); + dataGv.Dock = DockStyle.Fill; + dataGv.Location = new Point(0, 31); + dataGv.Margin = new Padding(0); + dataGv.Name = "dataGv"; + dataGv.Size = new Size(1024, 400); + dataGv.TabIndex = 2; + dataGv.CellClick += dataGv_CellClick; + dataGv.CellDoubleClick += dataGv_CellDoubleClick; + // + // permissionNameCol + // + permissionNameCol.DataPropertyName = "PermissionName"; + permissionNameCol.DefaultCellStyle = dataGridViewCellStyle10; + permissionNameCol.HeaderText = "权限名"; + permissionNameCol.Name = "permissionNameCol"; + permissionNameCol.Resizable = DataGridViewTriState.True; + permissionNameCol.Width = 300; + // + // permissionDescriptionCol + // + permissionDescriptionCol.DataPropertyName = "PermissionDescription"; + permissionDescriptionCol.DefaultCellStyle = dataGridViewCellStyle11; + permissionDescriptionCol.HeaderText = "中文名"; + permissionDescriptionCol.Name = "permissionDescriptionCol"; + permissionDescriptionCol.Resizable = DataGridViewTriState.True; + permissionDescriptionCol.Width = 300; + // + // dependentCol + // + dependentCol.DataPropertyName = "Dependent"; + dataGridViewCellStyle12.Font = new Font("Arial", 9F, FontStyle.Bold | FontStyle.Underline); + dataGridViewCellStyle12.ForeColor = Color.Blue; + dependentCol.DefaultCellStyle = dataGridViewCellStyle12; + dependentCol.HeaderText = "扩展名"; + dependentCol.Name = "dependentCol"; + dependentCol.Resizable = DataGridViewTriState.True; + dependentCol.Width = 100; + // + // viewIndcCol + // + viewIndcCol.DataPropertyName = "ViewIndc"; + dataGridViewCellStyle13.Alignment = DataGridViewContentAlignment.MiddleCenter; + dataGridViewCellStyle13.NullValue = false; + viewIndcCol.DefaultCellStyle = dataGridViewCellStyle13; + viewIndcCol.FalseValue = "N"; + viewIndcCol.HeaderText = "查看"; + viewIndcCol.IndeterminateValue = null; + viewIndcCol.Name = "viewIndcCol"; + viewIndcCol.Resizable = DataGridViewTriState.True; + viewIndcCol.SortMode = DataGridViewColumnSortMode.Automatic; + viewIndcCol.TrueValue = "Y"; + viewIndcCol.Width = 60; + // + // createIndcCol + // + createIndcCol.DataPropertyName = "CreateIndc"; + dataGridViewCellStyle14.Alignment = DataGridViewContentAlignment.MiddleCenter; + dataGridViewCellStyle14.NullValue = false; + createIndcCol.DefaultCellStyle = dataGridViewCellStyle14; + createIndcCol.FalseValue = "N"; + createIndcCol.HeaderText = "新增"; + createIndcCol.IndeterminateValue = null; + createIndcCol.Name = "createIndcCol"; + createIndcCol.Resizable = DataGridViewTriState.True; + createIndcCol.SortMode = DataGridViewColumnSortMode.Automatic; + createIndcCol.TrueValue = "Y"; + createIndcCol.Width = 60; + // + // amendIndcCol + // + amendIndcCol.DataPropertyName = "AmendIndc"; + dataGridViewCellStyle15.Alignment = DataGridViewContentAlignment.MiddleCenter; + dataGridViewCellStyle15.NullValue = false; + amendIndcCol.DefaultCellStyle = dataGridViewCellStyle15; + amendIndcCol.FalseValue = "N"; + amendIndcCol.HeaderText = "修改"; + amendIndcCol.IndeterminateValue = null; + amendIndcCol.Name = "amendIndcCol"; + amendIndcCol.Resizable = DataGridViewTriState.True; + amendIndcCol.SortMode = DataGridViewColumnSortMode.Automatic; + amendIndcCol.TrueValue = "Y"; + amendIndcCol.Width = 60; + // + // deleteIndcCol + // + deleteIndcCol.DataPropertyName = "DeleteIndc"; + dataGridViewCellStyle16.Alignment = DataGridViewContentAlignment.MiddleCenter; + dataGridViewCellStyle16.NullValue = false; + deleteIndcCol.DefaultCellStyle = dataGridViewCellStyle16; + deleteIndcCol.FalseValue = "N"; + deleteIndcCol.HeaderText = "删除"; + deleteIndcCol.IndeterminateValue = null; + deleteIndcCol.Name = "deleteIndcCol"; + deleteIndcCol.Resizable = DataGridViewTriState.True; + deleteIndcCol.SortMode = DataGridViewColumnSortMode.Automatic; + deleteIndcCol.TrueValue = "Y"; + deleteIndcCol.Width = 60; + // + // tableLayoutPanel2 + // + tableLayoutPanel2.AutoSize = true; + tableLayoutPanel2.AutoSizeMode = AutoSizeMode.GrowAndShrink; + tableLayoutPanel2.ColumnCount = 2; + tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel2.Controls.Add(groupNameLabel, 0, 0); + tableLayoutPanel2.Controls.Add(groupLocalNameLabel, 0, 1); + tableLayoutPanel2.Controls.Add(groupEngNameLabel, 0, 2); + tableLayoutPanel2.Controls.Add(groupNameTxt, 1, 0); + tableLayoutPanel2.Controls.Add(groupLocalNameTxt, 1, 1); + tableLayoutPanel2.Controls.Add(groupEngNameTxt, 1, 2); + tableLayoutPanel2.Location = new Point(3, 3); + tableLayoutPanel2.Name = "tableLayoutPanel2"; + tableLayoutPanel2.RowCount = 3; + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.Size = new Size(364, 87); + tableLayoutPanel2.TabIndex = 0; + // + // groupNameLabel + // + groupNameLabel.Location = new Point(3, 3); + groupNameLabel.Name = "groupNameLabel"; + groupNameLabel.Size = new Size(52, 20); + groupNameLabel.TabIndex = 1; + groupNameLabel.Values.Text = "组别名:"; + // + // groupLocalNameLabel + // + groupLocalNameLabel.Location = new Point(3, 32); + groupLocalNameLabel.Name = "groupLocalNameLabel"; + groupLocalNameLabel.Size = new Size(52, 20); + groupLocalNameLabel.TabIndex = 1; + groupLocalNameLabel.Values.Text = "中文名:"; + // + // groupEngNameLabel + // + groupEngNameLabel.Location = new Point(3, 61); + groupEngNameLabel.Name = "groupEngNameLabel"; + groupEngNameLabel.Size = new Size(52, 20); + groupEngNameLabel.TabIndex = 1; + groupEngNameLabel.Values.Text = "英文名:"; + // + // groupNameTxt + // + groupNameTxt.Dock = DockStyle.Fill; + groupNameTxt.Location = new Point(61, 3); + groupNameTxt.MaxLength = 50; + groupNameTxt.Name = "groupNameTxt"; + groupNameTxt.Size = new Size(300, 23); + groupNameTxt.TabIndex = 1; + // + // groupLocalNameTxt + // + groupLocalNameTxt.Location = new Point(61, 32); + groupLocalNameTxt.MaxLength = 50; + groupLocalNameTxt.Name = "groupLocalNameTxt"; + groupLocalNameTxt.Size = new Size(300, 23); + groupLocalNameTxt.TabIndex = 2; + // + // groupEngNameTxt + // + groupEngNameTxt.Dock = DockStyle.Fill; + groupEngNameTxt.Location = new Point(61, 61); + groupEngNameTxt.MaxLength = 50; + groupEngNameTxt.Name = "groupEngNameTxt"; + groupEngNameTxt.Size = new Size(300, 23); + groupEngNameTxt.TabIndex = 3; + // + // tableLayoutPanel6 + // + tableLayoutPanel6.AutoSize = true; + tableLayoutPanel6.AutoSizeMode = AutoSizeMode.GrowAndShrink; + tableLayoutPanel6.ColumnCount = 2; + tableLayoutPanel6.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel6.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel6.Controls.Add(delActorBut, 1, 0); + tableLayoutPanel6.Controls.Add(addActorBut, 0, 0); + tableLayoutPanel6.Location = new Point(3, 1248); + tableLayoutPanel6.Name = "tableLayoutPanel6"; + tableLayoutPanel6.RowCount = 1; + tableLayoutPanel6.RowStyles.Add(new RowStyle()); + tableLayoutPanel6.Size = new Size(92, 31); + tableLayoutPanel6.TabIndex = 5; + // + // delActorBut + // + delActorBut.Location = new Point(49, 3); + delActorBut.Name = "delActorBut"; + delActorBut.Size = new Size(40, 25); + delActorBut.TabIndex = 2; + delActorBut.Values.Image = Properties.Resources.navigate_minus; + delActorBut.Values.Text = ""; + delActorBut.Click += delActorBut_Click; + // + // addActorBut + // + addActorBut.Location = new Point(3, 3); + addActorBut.Name = "addActorBut"; + addActorBut.Size = new Size(40, 25); + addActorBut.TabIndex = 1; + addActorBut.Values.Image = Properties.Resources.navigate_plus; + addActorBut.Values.Text = ""; + addActorBut.Click += addActorBut_Click; + // + // permissionSearchBut + // + permissionSearchBut.Type = Krypton.Toolkit.PaletteButtonSpecStyle.WorkspaceMaximize; + permissionSearchBut.UniqueName = "29ee19b90170485ca37adcc57c43685d"; + // + // searchPanel + // + searchPanel.AutoSize = true; + searchPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + searchPanel.ColumnCount = 3; + searchPanel.ColumnStyles.Add(new ColumnStyle()); + searchPanel.ColumnStyles.Add(new ColumnStyle()); + searchPanel.ColumnStyles.Add(new ColumnStyle()); + searchPanel.Controls.Add(createBut, 2, 0); + searchPanel.Controls.Add(resetBut, 1, 0); + searchPanel.Controls.Add(searchBut, 0, 0); + searchPanel.Location = new Point(424, 0); + searchPanel.Margin = new Padding(60, 0, 0, 0); + searchPanel.Name = "searchPanel"; + searchPanel.RowCount = 1; + searchPanel.RowStyles.Add(new RowStyle()); + searchPanel.Size = new Size(288, 31); + searchPanel.TabIndex = 0; + // + // createBut + // + createBut.Location = new Point(195, 3); + createBut.Name = "createBut"; + createBut.Size = new Size(90, 25); + createBut.TabIndex = 3; + createBut.Values.Image = Properties.Resources.create_16; + createBut.Values.Text = "新增(&C)"; + createBut.Click += createBut_Click; + // + // resetBut + // + resetBut.Location = new Point(99, 3); + resetBut.Name = "resetBut"; + resetBut.Size = new Size(90, 25); + resetBut.TabIndex = 2; + resetBut.Values.Image = Properties.Resources.reset_16; + resetBut.Values.Text = "重置(&R)"; + resetBut.Click += resetBut_Click; + // + // searchBut + // + searchBut.Location = new Point(3, 3); + searchBut.Name = "searchBut"; + searchBut.Size = new Size(90, 25); + searchBut.TabIndex = 1; + searchBut.Values.Image = Properties.Resources.search_16; + searchBut.Values.Text = "查询(&S)"; + searchBut.Click += searchBut_Click; + // + // groupNameSearchLabel + // + groupNameSearchLabel.Location = new Point(3, 3); + groupNameSearchLabel.Name = "groupNameSearchLabel"; + groupNameSearchLabel.Size = new Size(52, 20); + groupNameSearchLabel.TabIndex = 1; + groupNameSearchLabel.Values.Text = "组别名:"; + // + // groupNameSearchTxt + // + groupNameSearchTxt.ButtonSpecs.Add(groupNameSearchBut); + groupNameSearchTxt.Location = new Point(61, 3); + groupNameSearchTxt.Name = "groupNameSearchTxt"; + groupNameSearchTxt.Size = new Size(300, 23); + groupNameSearchTxt.TabIndex = 0; + // + // groupNameSearchBut + // + groupNameSearchBut.Type = Krypton.Toolkit.PaletteButtonSpecStyle.WorkspaceMaximize; + groupNameSearchBut.UniqueName = "3a322a66645f4aff808be4720c638ad8"; + groupNameSearchBut.Click += groupNameSearchBut_Click; + // + // kryptonPanel1 + // + kryptonPanel1.Dock = DockStyle.Fill; + kryptonPanel1.Location = new Point(3, 40); + kryptonPanel1.Name = "kryptonPanel1"; + kryptonPanel1.Size = new Size(1018, 5); + kryptonPanel1.TabIndex = 1; + // + // bottomPanel + // + bottomPanel.AutoSize = true; + bottomPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + bottomPanel.ColumnCount = 1; + bottomPanel.ColumnStyles.Add(new ColumnStyle()); + bottomPanel.Controls.Add(savePanel, 0, 0); + bottomPanel.Controls.Add(operationPanel, 0, 1); + bottomPanel.Location = new Point(0, 726); + bottomPanel.Margin = new Padding(0); + bottomPanel.Name = "bottomPanel"; + bottomPanel.RowCount = 2; + bottomPanel.RowStyles.Add(new RowStyle()); + bottomPanel.RowStyles.Add(new RowStyle()); + bottomPanel.Size = new Size(198, 74); + bottomPanel.TabIndex = 2; + // + // savePanel + // + savePanel.AutoSize = true; + savePanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + savePanel.ColumnCount = 2; + savePanel.ColumnStyles.Add(new ColumnStyle()); + savePanel.ColumnStyles.Add(new ColumnStyle()); + savePanel.Controls.Add(cancelBut, 1, 0); + savePanel.Controls.Add(saveBut, 0, 0); + savePanel.Location = new Point(3, 3); + savePanel.Name = "savePanel"; + savePanel.RowCount = 1; + savePanel.RowStyles.Add(new RowStyle()); + savePanel.Size = new Size(192, 31); + savePanel.TabIndex = 0; + // + // cancelBut + // + cancelBut.Location = new Point(99, 3); + cancelBut.Name = "cancelBut"; + cancelBut.Size = new Size(90, 25); + cancelBut.TabIndex = 2; + cancelBut.Values.Image = Properties.Resources.cancel_16; + cancelBut.Values.Text = "取消(&L)"; + cancelBut.Click += cancelBut_Click; + // + // saveBut + // + saveBut.Location = new Point(3, 3); + saveBut.Name = "saveBut"; + saveBut.Size = new Size(90, 25); + saveBut.TabIndex = 1; + saveBut.Values.Image = Properties.Resources.save_16; + saveBut.Values.Text = "保存(&S)"; + saveBut.Click += saveBut_Click; + // + // operationPanel + // + operationPanel.AutoSize = true; + operationPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + operationPanel.ColumnCount = 2; + operationPanel.ColumnStyles.Add(new ColumnStyle()); + operationPanel.ColumnStyles.Add(new ColumnStyle()); + operationPanel.Controls.Add(deleteBut, 1, 0); + operationPanel.Controls.Add(amendBut, 0, 0); + operationPanel.Location = new Point(3, 40); + operationPanel.Name = "operationPanel"; + operationPanel.RowCount = 1; + operationPanel.RowStyles.Add(new RowStyle()); + operationPanel.Size = new Size(192, 31); + operationPanel.TabIndex = 0; + // + // deleteBut + // + deleteBut.Location = new Point(99, 3); + deleteBut.Name = "deleteBut"; + deleteBut.Size = new Size(90, 25); + deleteBut.TabIndex = 2; + deleteBut.Values.Image = Properties.Resources.delete_16; + deleteBut.Values.Text = "删除(&D)"; + deleteBut.Click += deleteBut_Click; + // + // amendBut + // + amendBut.Location = new Point(3, 3); + amendBut.Name = "amendBut"; + amendBut.Size = new Size(90, 25); + amendBut.TabIndex = 1; + amendBut.Values.Image = Properties.Resources.amend_16; + amendBut.Values.Text = "修改(&M)"; + amendBut.Click += amendBut_Click; + // + // topPanel + // + topPanel.AutoSize = true; + topPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + topPanel.ColumnCount = 3; + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 20F)); + topPanel.Controls.Add(searchPanel, 3, 0); + topPanel.Controls.Add(groupNameSearchLabel, 0, 0); + topPanel.Controls.Add(groupNameSearchTxt, 1, 0); + topPanel.Dock = DockStyle.Fill; + topPanel.Location = new Point(3, 3); + topPanel.Name = "topPanel"; + topPanel.RowCount = 1; + topPanel.RowStyles.Add(new RowStyle()); + topPanel.Size = new Size(1018, 31); + topPanel.TabIndex = 0; + // + // mainPanel + // + mainPanel.ColumnCount = 1; + mainPanel.ColumnStyles.Add(new ColumnStyle()); + mainPanel.Controls.Add(topPanel, 0, 0); + mainPanel.Controls.Add(kryptonPanel1, 0, 1); + mainPanel.Controls.Add(bottomPanel, 0, 3); + mainPanel.Controls.Add(contentPanel, 0, 2); + mainPanel.Dock = DockStyle.Fill; + mainPanel.Location = new Point(0, 0); + mainPanel.Name = "mainPanel"; + mainPanel.RowCount = 4; + mainPanel.RowStyles.Add(new RowStyle()); + mainPanel.RowStyles.Add(new RowStyle()); + mainPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 100F)); + mainPanel.RowStyles.Add(new RowStyle()); + mainPanel.Size = new Size(1024, 800); + mainPanel.TabIndex = 4; + // + // SecurityGroupOperationPage + // + AutoScaleDimensions = new SizeF(7F, 15F); + AutoScaleMode = AutoScaleMode.Font; + Controls.Add(mainPanel); + Name = "SecurityGroupOperationPage"; + ((System.ComponentModel.ISupportInitialize)kryptonPanel2).EndInit(); + contentPanel.ResumeLayout(false); + contentPanel.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)actorGv).EndInit(); + tableLayoutPanel5.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)dataDsGv).EndInit(); + tableLayoutPanel3.ResumeLayout(false); + tableLayoutPanel3.PerformLayout(); + tableLayoutPanel4.ResumeLayout(false); + tableLayoutPanel4.PerformLayout(); + tableLayoutPanel1.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)dataGv).EndInit(); + tableLayoutPanel2.ResumeLayout(false); + tableLayoutPanel2.PerformLayout(); + tableLayoutPanel6.ResumeLayout(false); + searchPanel.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)kryptonPanel1).EndInit(); + bottomPanel.ResumeLayout(false); + bottomPanel.PerformLayout(); + savePanel.ResumeLayout(false); + operationPanel.ResumeLayout(false); + topPanel.ResumeLayout(false); + topPanel.PerformLayout(); + mainPanel.ResumeLayout(false); + mainPanel.PerformLayout(); + ResumeLayout(false); + } + + #endregion + private Krypton.Toolkit.KryptonCheckBox delegateIndcChk; + private Krypton.Toolkit.KryptonTextBox permissionNameSearchTxt; + private Krypton.Toolkit.KryptonPanel kryptonPanel2; + private TableLayoutPanel contentPanel; + private TableLayoutPanel tableLayoutPanel5; + private Krypton.Toolkit.KryptonButton delDsBut; + private Krypton.Toolkit.KryptonDataGridView dataDsGv; + private Krypton.Toolkit.KryptonHeader kryptonHeader2; + private TableLayoutPanel tableLayoutPanel3; + private TableLayoutPanel tableLayoutPanel4; + private TableLayoutPanel tableLayoutPanel1; + private Krypton.Toolkit.KryptonButton delBut; + private Krypton.Toolkit.KryptonButton addBut; + private Krypton.Toolkit.KryptonHeader kryptonHeader1; + private Krypton.Toolkit.KryptonDataGridView dataGv; + private TableLayoutPanel tableLayoutPanel2; + private Krypton.Toolkit.KryptonLabel groupNameLabel; + private Krypton.Toolkit.KryptonLabel groupLocalNameLabel; + private Krypton.Toolkit.KryptonLabel groupEngNameLabel; + private Krypton.Toolkit.KryptonTextBox groupNameTxt; + private Krypton.Toolkit.KryptonTextBox groupLocalNameTxt; + private Krypton.Toolkit.KryptonTextBox groupEngNameTxt; + private Krypton.Toolkit.ButtonSpecAny permissionSearchBut; + private TableLayoutPanel searchPanel; + private Krypton.Toolkit.KryptonButton createBut; + private Krypton.Toolkit.KryptonButton resetBut; + private Krypton.Toolkit.KryptonButton searchBut; + private Krypton.Toolkit.KryptonLabel groupNameSearchLabel; + private Krypton.Toolkit.KryptonTextBox groupNameSearchTxt; + private Krypton.Toolkit.ButtonSpecAny groupNameSearchBut; + private Krypton.Toolkit.KryptonPanel kryptonPanel1; + private TableLayoutPanel bottomPanel; + private TableLayoutPanel savePanel; + private Krypton.Toolkit.KryptonButton cancelBut; + private Krypton.Toolkit.KryptonButton saveBut; + private TableLayoutPanel operationPanel; + private Krypton.Toolkit.KryptonButton deleteBut; + private Krypton.Toolkit.KryptonButton amendBut; + private TableLayoutPanel topPanel; + private TableLayoutPanel mainPanel; + private Krypton.Toolkit.KryptonHeader kryptonHeader3; + private TableLayoutPanel tableLayoutPanel6; + private Krypton.Toolkit.KryptonButton delActorBut; + private Krypton.Toolkit.KryptonButton addActorBut; + private Krypton.Toolkit.KryptonDataGridView actorGv; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn actorNameCol; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn actorLocalNameCol; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn dsDependentCol; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn dsDependentDetailNameCol; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn dsDependentDetailDescriptionCol; + private Krypton.Toolkit.KryptonDataGridViewCheckBoxColumn dsViewIndcCol; + private Krypton.Toolkit.KryptonDataGridViewCheckBoxColumn dsCreateIndcCol; + private Krypton.Toolkit.KryptonDataGridViewCheckBoxColumn dsAmendIndcCol; + private Krypton.Toolkit.KryptonDataGridViewCheckBoxColumn dsDeleteIndcCol; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn permissionNameCol; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn permissionDescriptionCol; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn dependentCol; + private Krypton.Toolkit.KryptonDataGridViewCheckBoxColumn viewIndcCol; + private Krypton.Toolkit.KryptonDataGridViewCheckBoxColumn createIndcCol; + private Krypton.Toolkit.KryptonDataGridViewCheckBoxColumn amendIndcCol; + private Krypton.Toolkit.KryptonDataGridViewCheckBoxColumn deleteIndcCol; + } +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Security.Gui/SecurityGroupOperationPage.cs b/CloudBuilder/CloudBuilder.Security.Gui/SecurityGroupOperationPage.cs new file mode 100644 index 0000000..2c52002 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/SecurityGroupOperationPage.cs @@ -0,0 +1,863 @@ +using CloudBuilder.Core.Service; +using CloudBuilder.Gui; +using CloudBuilder.Request.Security; +using CloudBuilder.Security.Data; +using CloudBuilder.Security.Entity; +using CloudBuilder.Security.Linkup; +using CloudBuilder.Security.Policy; +using CloudBuilder.Security.SearchCriteria; +using Krypton.Toolkit; +using Microsoft.AspNetCore.Authorization; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace CloudBuilder.Security.Gui +{ + public partial class SecurityGroupOperationPage : AbstractPage + { + private SecurityMessagePolicy securityMessagePolicy; + private SecurityGroupRequest securityGroupRequest; + private SecurityGroupEntity securityGroupEntity; + private SecurityGroupData data; + public SecurityGroupOperationPage() + { + InitializeComponent(); + } + + /// + /// 第一次加载时执行,只执行一次 + /// + public override void FunctionLoaded() + { + try + { + base.FunctionLoaded(); + //初始化容器------------------------------------- + securityMessagePolicy = ServiceHelper.GetTypeService()!; + securityGroupRequest = ServiceHelper.GetTypeService(); + + //界面初始化 + InitGui(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void InitGui() + { + InitBindingContext(); + + InitDisplayMode(); + + this.ParentAbstractForm.AcceptButton = this.searchBut; + this.ParentAbstractForm.CancelButton = this.resetBut; + } + + /// + /// 有特殊要求的UI控件初始化设置,Init与Add配对后,使用guiOperateHelper管理 + /// + private void InitBindingContext() + { + //需要绑定数据 + guiBindingContext = new GuiBindingContext(); + + InitPermission(); + + groupNameTxt.Set(SecurityGroupEntity.GROUP_NAME, groupNameLabel.Text, EnumEditModeColor.Required); + groupEngNameTxt.Set(SecurityGroupEntity.GROUP_ENG_NAME, groupLocalNameLabel.Text, EnumEditModeColor.Required); + groupLocalNameTxt.Set(SecurityGroupEntity.GROUP_LOCAL_NAME, groupEngNameLabel.Text, EnumEditModeColor.Required); + + dataGv.InitColumn(false, true); + dataDsGv.InitColumn(false, true); + actorGv.InitColumn(false, true); + + guiOperateHelper = new GuiOperateHelper(); + } + + private void InitPermission() + { + createBut.Set(SecurityPermissionPolicy.SecurityGroup, Operate.Insert); + amendBut.Set(SecurityPermissionPolicy.SecurityGroup, Operate.Update); + deleteBut.Set(SecurityPermissionPolicy.SecurityGroup, Operate.Delete); + } + + /// + /// 每次从别的界面进入时执行,发生在FunctionLoaded之后 + /// + /// + public override void FunctionActivated(object param) + { + try + { + if (param == null) + { + groupNameSearchTxt.Focus(); + return; + } + + InitDisplayMode(); + + SecurityGroupOperationLinkup linkup = null; + + if (param is SecurityGroupOperationLinkup) + { + linkup = (SecurityGroupOperationLinkup)param; + } + + this.DisplayMode = (GuiDisplayMode)linkup.DisplayMode; + + groupNameSearchTxt.Text = linkup.GroupName; + + if (this.DisplayMode == GuiDisplayMode.View) + { + Search(); + } + else if (this.DisplayMode == GuiDisplayMode.Create) + { + Create(); + } + else if (this.DisplayMode == GuiDisplayMode.Amend) + { + Search(); + Amend(); + } + + groupNameSearchTxt.Focus(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + public override void FunctionSelected() + { + this.ParentAbstractForm.AcceptButton = this.searchBut; + if (!IsDialog) + this.ParentAbstractForm.CancelButton = this.resetBut; + else + this.ParentAbstractForm.CancelButton = this.cancelBut; + + groupNameSearchTxt.Focus(); + } + + public override bool FunctionDeactivating() + { + if (this.DisplayMode == GuiDisplayMode.View) + { + return true; + } + else + { + return CancelEditing(); + } + } + + private bool CancelEditing() + { + DialogResult result = ShowMessageBox.ShowOption(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_CONFIRM_CANCEL), securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_CONFIRM)); + + //从外部跳转(非mainKryptonNavigator),result第一次不生效?,所以再执行一次生效 + if (result == DialogResult.Cancel) + { + result = ShowMessageBox.ShowOption(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_CONFIRM_CANCEL), securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_CONFIRM)); + } + + if (result == DialogResult.No) + { + return false; + } + + Cancel(); + + return true; + } + + private void InitDisplayMode() + { + this.DisplayMode = GuiDisplayMode.View; + + SetDisplayMode(); + } + + private void SetDisplayMode() + { + if (this.DisplayMode == GuiDisplayMode.View) + { + savePanel.Visible = false; + operationPanel.Visible = true; + + guiOperateHelper.EnableControls(true, topPanel); + guiOperateHelper.EnableControls(false, contentPanel); + //查詢有記錄時,修改等控件有效 + if (securityGroupEntity != null) + guiOperateHelper.EnableControls(true, bottomPanel); + else + guiOperateHelper.EnableControls(false, bottomPanel); + } + else if (this.DisplayMode == GuiDisplayMode.Amend || this.DisplayMode == GuiDisplayMode.Create) + { + savePanel.Visible = true; + operationPanel.Visible = false; + + guiOperateHelper.EnableControls(false, topPanel); + guiOperateHelper.EnableControls(true, bottomPanel, contentPanel); + + if (this.DisplayMode == GuiDisplayMode.Amend) guiOperateHelper.EnableControls(false, groupNameTxt); + + + permissionNameCol.ReadOnly = true; + permissionNameCol.DefaultCellStyle.BackColor = System.Drawing.Color.Silver; + permissionDescriptionCol.ReadOnly = true; + permissionDescriptionCol.DefaultCellStyle.BackColor = System.Drawing.Color.Silver; + dependentCol.ReadOnly = true; + dependentCol.DefaultCellStyle.BackColor = System.Drawing.Color.Silver; + + dsDependentCol.ReadOnly = true; + dsDependentCol.DefaultCellStyle.BackColor = System.Drawing.Color.Silver; + dsDependentDetailNameCol.ReadOnly = true; + dsDependentDetailNameCol.DefaultCellStyle.BackColor = System.Drawing.Color.Silver; + dsDependentDetailDescriptionCol.ReadOnly = true; + dsDependentDetailDescriptionCol.DefaultCellStyle.BackColor = System.Drawing.Color.Silver; + + actorGv.DefaultCellStyle.BackColor = System.Drawing.Color.Silver; + } + } + + private void PackUIToEntity() + { + guiBindingContext.DataPack(); + + SecurityGroupPermissionViewDisplayData[] securityGroupPermissions = dataGv.GetAllRows(); + + if (securityGroupPermissions == null || securityGroupPermissions.Length == 0) + data.SecurityGroupPermissionViews = null; + else + data.SecurityGroupPermissionViews = securityGroupPermissions.Select(x => new SecurityGroupPermissionViewDisplayData() + { + PermissionName = x.PermissionName, + GroupName = groupNameTxt.Text, + ViewIndc = x.ViewIndc, + AmendIndc = x.AmendIndc, + CreateIndc = x.CreateIndc, + DeleteIndc = x.DeleteIndc, + Dependent = x.Dependent, + IsView = x.ViewIndc == YesNoPolicy.YES, + IsAmend = x.AmendIndc == YesNoPolicy.YES, + IsCreate = x.CreateIndc == YesNoPolicy.YES, + IsDelete = x.DeleteIndc == YesNoPolicy.YES, + PermissionDescription = x.PermissionDescription + }).ToArray(); + + SecurityGroupPermissionDependentViewDisplayData[] dependents = dataDsGv.GetAllRows(); + + if (dependents == null || dependents.Length == 0) + data.SecurityGroupPermissionDependentViews = null; + else + data.SecurityGroupPermissionDependentViews = dependents.Select(x => new SecurityGroupPermissionDependentViewDisplayData() + { + PermissionName = x.PermissionName, + GroupName = groupNameTxt.Text, + ViewIndc = x.ViewIndc, + AmendIndc = x.AmendIndc, + CreateIndc = x.CreateIndc, + DeleteIndc = x.DeleteIndc, + Dependent = x.Dependent, + IsView = x.ViewIndc == YesNoPolicy.YES, + IsAmend = x.AmendIndc == YesNoPolicy.YES, + IsCreate = x.CreateIndc == YesNoPolicy.YES, + IsDelete = x.DeleteIndc == YesNoPolicy.YES, + PermissionDescription = x.PermissionDescription, + DependentDetailDescription = x.DependentDetailDescription, + DependentDetailName = x.DependentDetailName, + }).ToArray(); + + SecurityActorGroupViewEntity[] actors = actorGv.GetAllRows(); + + if (actors == null || actors.Length == 0) + data.SecurityActorGroups = null; + else + data.SecurityActorGroups = actors.Select(x => new SecurityActorGroupViewEntity() + { + ActorName = x.ActorName, + GroupName = groupNameTxt.Text, + ActorLocalName = x.ActorLocalName, + }).ToArray(); + } + + private bool SaveValidate() + { + if (!guiOperateHelper.CheckValidate(this.mainPanel)) return false; + + return true; + } + + private void Search() + { + try + { + if (string.IsNullOrEmpty(groupNameSearchTxt.Text)) return; + + Reset(); + + data = securityGroupRequest.FindByKey(groupNameSearchTxt.Text); + + if (data == null || data.SecurityGroup == null) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + } + else + { + securityGroupEntity = data.SecurityGroup; + + PackEntityToUI(); + + SetDisplayMode(); + } + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void Create() + { + this.DisplayMode = GuiDisplayMode.Create; + + guiOperateHelper.ResetControls(this.mainPanel); + + SetDisplayMode(); + + data = new SecurityGroupData(); + securityGroupEntity = new SecurityGroupEntity() + { + CreatedBy = string.Empty, + UpdatedBy = string.Empty, + CreatedDatetime = DateTime.Now, + UpdatedDatetime = DateTime.Now, + }; + data.SecurityGroup = securityGroupEntity; + + PackEntityToUI(); + + groupNameTxt.Focus(); + } + + private void Amend() + { + this.DisplayMode = GuiDisplayMode.Amend; + + SetDisplayMode(); + } + + private void PackEntityToUI() + { + guiBindingContext.DataBind(data.SecurityGroup, this); + + dataGv.SetDataSource(data.SecurityGroupPermissionViews); + dataDsGv.SetDataSource(data.SecurityGroupPermissionDependentViews); + actorGv.SetDataSource(data.SecurityActorGroups); + } + + private void Reset() + { + this.DisplayMode = GuiDisplayMode.View; + + securityGroupEntity = null; + + guiOperateHelper.ResetControls(this.contentPanel); + + SetDisplayMode(); + + groupNameSearchTxt.Focus(); + } + + public void Cancel() + { + if (!string.IsNullOrEmpty(groupNameSearchTxt.Text)) + Search(); + else + Reset(); + + } + + + private void groupNameSearchBut_Click(object sender, EventArgs e) + { + try + { + AbstractForm dialog = GetAbstractDialog(typeof(SecurityGroupEnquiryPage).Name); + + if (DialogResult.OK != dialog.ShowDialog()) return; + + groupNameSearchTxt.Text = ((SecurityGroupEntity[])dialog.OutputData)[0].GroupName; + + Search(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void searchBut_Click(object sender, EventArgs e) + { + try + { + if (string.IsNullOrEmpty(groupNameSearchTxt.Text)) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_VALID_INPUT, GuiOperateHelper.GetLabelText(groupNameSearchLabel.Text))); + this.groupNameSearchTxt.Focus(); + return; + } + + this.DisplayMode = GuiDisplayMode.View; + + Search(); + + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void resetBut_Click(object sender, EventArgs e) + { + try + { + guiOperateHelper.ResetControls(this.topPanel); + Reset(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void createBut_Click(object sender, EventArgs e) + { + try + { + Create(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void amendBut_Click(object sender, EventArgs e) + { + try + { + Amend(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void deleteBut_Click(object sender, EventArgs e) + { + try + { + if (securityGroupEntity == null) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + return; + } + + if (DialogResult.Yes != ShowMessageBox.ShowOption(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_CONFIRM_DEL_NULL), securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_DELETE))) return; + + securityGroupRequest.Delete(securityGroupEntity.GroupName); + + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_SUCCEED_DELETED_NULL)); + + Reset(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void saveBut_Click(object sender, EventArgs e) + { + try + { + if (!SaveValidate()) return; + + PackUIToEntity(); + + + if (this.DisplayMode == GuiDisplayMode.Create) + securityGroupRequest.Insert(data); + else + securityGroupRequest.Update(data); + + + ShowMessageBox.ShowInfo((this.DisplayMode == GuiDisplayMode.Create) ? + securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_SUCCEED_CREATED_NULL) : + securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_SUCCEED_UPDATED_NULL)); + + groupNameSearchTxt.Text = securityGroupEntity.GroupName; + Search(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void cancelBut_Click(object sender, EventArgs e) + { + try + { + CancelEditing(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void addBut_Click(object sender, EventArgs e) + { + try + { + AbstractForm dialog = GetAbstractDialog(typeof(SecurityPermissionEnquiryPage).Name); + + if (DialogResult.OK != dialog.ShowDialog()) return; + + SecurityPermissionEntity[] securityPermissions = (SecurityPermissionEntity[])dialog.OutputData; + List permissionNames = new List(); + if (dataGv.Rows.Count > 0) + { + permissionNames.AddRange(dataGv.GetAllRows().Select(x => x.PermissionName)); + } + + SecurityGroupPermissionViewDisplayData d; + + foreach (SecurityPermissionEntity securityPermission in securityPermissions) + { + if (permissionNames.Contains(securityPermission.PermissionName)) continue; + permissionNames.Add(securityPermission.PermissionName); + + d = new SecurityGroupPermissionViewDisplayData() + { + PermissionName = securityPermission.PermissionName, + PermissionDescription = securityPermission.Description, + Dependent = securityPermission.Dependent, + ViewIndc = YesNoPolicy.YES, + AmendIndc = YesNoPolicy.YES, + CreateIndc = YesNoPolicy.YES, + DeleteIndc = YesNoPolicy.YES, + IsView = true, + IsAmend = true, + IsCreate = true, + IsDelete = true, + }; + + dataGv.AddRow(d); + } + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void delBut_Click(object sender, EventArgs e) + { + if (dataGv.RowCount <= 0 || dataGv.SelectedCells.Count <= 0) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + return; + } + + List dependents = dataGv.GetAllRows().Select(x => x.Dependent).ToList(); + + dataGv.DeleteRows(dataGv.SelectedCells); + + SecurityGroupPermissionDependentViewDisplayData[] ds = dataDsGv.GetAllRows(); + + if (ds != null && ds.Length > 0) + { + dataDsGv.SetDataSource(ds.Where(x => !dependents.Contains(x.Dependent)).ToList()); + } + } + + private void addDsBut_Click(object sender, EventArgs e) + { + //AddDs(null); + } + + private void AddDs(SecurityGroupPermissionViewDisplayData displayData) + { + try + { + AbstractForm dialog = GetAbstractDialog(typeof(SecurityPermissionDependentEnquiryPage).Name); + + SecurityPermissionSearchCriteria criteria = new SecurityPermissionSearchCriteria(); + criteria.PermissionName = displayData.PermissionName; + criteria.Dependent = displayData.Dependent; + criteria.DependentEnable = false; + if (DialogResult.OK != dialog.ShowViewDialog(null, criteria)) return; + + SecurityPermissionDependentEntity[] securityPermissions = (SecurityPermissionDependentEntity[])dialog.OutputData; + List dependentDetailNames = new List(); + if (dataDsGv.Rows.Count > 0) + { + dependentDetailNames.AddRange(dataDsGv.GetAllRows().Select(x => x.PermissionName + "_" + x.DependentDetailName)); + } + + SecurityGroupPermissionDependentViewDisplayData d; + + foreach (SecurityPermissionDependentEntity securityPermission in securityPermissions) + { + if (dependentDetailNames.Contains(securityPermission.PermissionName + "_" + securityPermission.DependentDetailName)) continue; + dependentDetailNames.Add(securityPermission.PermissionName + "_" + securityPermission.DependentDetailName); + + d = new SecurityGroupPermissionDependentViewDisplayData() + { + DependentDetailDescription = securityPermission.DependentDetailDescription, + DependentDetailName = securityPermission.DependentDetailName, + PermissionName = securityPermission.PermissionName, + Dependent = securityPermission.Dependent, + ViewIndc = YesNoPolicy.YES, + AmendIndc = YesNoPolicy.YES, + CreateIndc = YesNoPolicy.YES, + DeleteIndc = YesNoPolicy.YES, + IsView = true, + IsAmend = true, + IsCreate = true, + IsDelete = true, + }; + + dataDsGv.AddRow(d); + } + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void delDsBut_Click(object sender, EventArgs e) + { + if (dataDsGv.RowCount <= 0 || dataDsGv.SelectedCells.Count <= 0) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + return; + } + + dataDsGv.DeleteRows(dataDsGv.SelectedCells); + } + + private void addActorBut_Click(object sender, EventArgs e) + { + try + { + AbstractForm dialog = GetAbstractDialog(typeof(SecurityActorEnquiryPage).Name); + + if (DialogResult.OK != dialog.ShowDialog()) return; + + SecurityActorEntity[] securityActors = (SecurityActorEntity[])dialog.OutputData; + List actorNames = new List(); + if (actorGv.Rows.Count > 0) + { + actorNames.AddRange(actorGv.GetAllRows().Select(x => x.ActorName)); + } + + SecurityActorGroupViewEntity d; + + foreach (SecurityActorEntity securityActor in securityActors) + { + if (actorNames.Contains(securityActor.ActorName)) continue; + actorNames.Add(securityActor.ActorName); + + d = new SecurityActorGroupViewEntity() + { + ActorName = securityActor.ActorName, + ActorLocalName = securityActor.ActorLocalName + }; + + actorGv.AddRow(d); + } + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void delActorBut_Click(object sender, EventArgs e) + { + if (actorGv.RowCount <= 0 || actorGv.SelectedCells.Count <= 0) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + return; + } + + actorGv.DeleteRows(actorGv.SelectedCells); + } + + private void dataGv_CellClick(object sender, DataGridViewCellEventArgs e) + { + if (this.DisplayMode == GuiDisplayMode.View) return; + + if (e.RowIndex < 0 || e.ColumnIndex != dependentCol.Index) return; + SecurityGroupPermissionViewDisplayData d = dataGv.GetRowData(e.RowIndex); + + if (string.IsNullOrEmpty(d.Dependent)) return; + + AddDs(d); + } + + private void dataGv_CellDoubleClick(object sender, DataGridViewCellEventArgs e) + { + if (dataGv.RowCount <= 0 || dataGv.SelectedCells.Count <= 0) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + return; + } + + SecurityGroupPermissionViewDisplayData data = dataGv.GetRowData(dataGv.SelectedCells[0].RowIndex); + + DisplayPage(GuiDisplayMode.View, data.PermissionName); + } + + private void DisplayPage(GuiDisplayMode mode, string permissionName) + { + SecurityPermissionOperationLinkup linkupData = new SecurityPermissionOperationLinkup(); + linkupData.DisplayMode = Convert.ToInt32(mode); + linkupData.PermissionName = permissionName; + + this.DisplayAbstractPage(typeof(SecurityPermissionOperationPage).Name, linkupData); + } + } +} diff --git a/CloudBuilder/CloudBuilder.Security.Gui/SecurityGroupOperationPage.resx b/CloudBuilder/CloudBuilder.Security.Gui/SecurityGroupOperationPage.resx new file mode 100644 index 0000000..bece4d3 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/SecurityGroupOperationPage.resx @@ -0,0 +1,153 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Security.Gui/SecurityMasterDialogPage.Designer.cs b/CloudBuilder/CloudBuilder.Security.Gui/SecurityMasterDialogPage.Designer.cs new file mode 100644 index 0000000..d7af140 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/SecurityMasterDialogPage.Designer.cs @@ -0,0 +1,349 @@ +namespace CloudBuilder.Security.Gui +{ + partial class SecurityMasterDialogPage + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + mainPanel = new TableLayoutPanel(); + dialogPanel = new TableLayoutPanel(); + okBut = new Krypton.Toolkit.KryptonButton(); + cancelBut = new Krypton.Toolkit.KryptonButton(); + contentPanel = new TableLayoutPanel(); + masterCategoryLabel = new Krypton.Toolkit.KryptonLabel(); + masterCategoryTxt = new Krypton.Toolkit.KryptonTextBox(); + masterSubcategoryLabel = new Krypton.Toolkit.KryptonLabel(); + masterSubcategoryTxt = new Krypton.Toolkit.KryptonTextBox(); + masterCodeItemLabel = new Krypton.Toolkit.KryptonLabel(); + masterCodeItemTxt = new Krypton.Toolkit.KryptonTextBox(); + localDescriptionLabel = new Krypton.Toolkit.KryptonLabel(); + localDescriptionTxt = new Krypton.Toolkit.KryptonTextBox(); + engDescriptionLabel = new Krypton.Toolkit.KryptonLabel(); + engDescriptionTxt = new Krypton.Toolkit.KryptonTextBox(); + valueLabel = new Krypton.Toolkit.KryptonLabel(); + valueTxt = new Krypton.Toolkit.KryptonTextBox(); + orderByLabel = new Krypton.Toolkit.KryptonLabel(); + validIndcCombo = new Krypton.Toolkit.KryptonComboBox(); + remarkLabel = new Krypton.Toolkit.KryptonLabel(); + remarkTxt = new Krypton.Toolkit.KryptonTextBox(); + validIndcLabel = new Krypton.Toolkit.KryptonLabel(); + orderByTxt = new Krypton.Toolkit.KryptonTextBox(); + mainPanel.SuspendLayout(); + dialogPanel.SuspendLayout(); + contentPanel.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)validIndcCombo).BeginInit(); + SuspendLayout(); + // + // mainPanel + // + mainPanel.ColumnCount = 1; + mainPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F)); + mainPanel.Controls.Add(dialogPanel, 0, 1); + mainPanel.Controls.Add(contentPanel, 0, 0); + mainPanel.Dock = DockStyle.Fill; + mainPanel.Location = new Point(0, 0); + mainPanel.Name = "mainPanel"; + mainPanel.RowCount = 2; + mainPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 65.0666656F)); + mainPanel.RowStyles.Add(new RowStyle()); + mainPanel.Size = new Size(800, 505); + mainPanel.TabIndex = 0; + // + // dialogPanel + // + dialogPanel.AutoSize = true; + dialogPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + dialogPanel.ColumnCount = 3; + dialogPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F)); + dialogPanel.ColumnStyles.Add(new ColumnStyle()); + dialogPanel.ColumnStyles.Add(new ColumnStyle()); + dialogPanel.Controls.Add(cancelBut, 2, 0); + dialogPanel.Controls.Add(okBut, 1, 0); + dialogPanel.Dock = DockStyle.Fill; + dialogPanel.Location = new Point(3, 471); + dialogPanel.Name = "dialogPanel"; + dialogPanel.RowCount = 1; + dialogPanel.RowStyles.Add(new RowStyle()); + dialogPanel.Size = new Size(794, 31); + dialogPanel.TabIndex = 999; + // + // okBut + // + okBut.Location = new Point(605, 3); + okBut.Name = "okBut"; + okBut.Size = new Size(90, 25); + okBut.TabIndex = 0; + okBut.Values.Image = Properties.Resources.ok_16; + okBut.Values.Text = "确定(&O)"; + okBut.Click += okBut_Click; + // + // cancelBut + // + cancelBut.Location = new Point(701, 3); + cancelBut.Name = "cancelBut"; + cancelBut.Size = new Size(90, 25); + cancelBut.TabIndex = 0; + cancelBut.Values.Image = Properties.Resources.close_16; + cancelBut.Values.Text = "取消(&C)"; + cancelBut.Click += cancelBut_Click; + // + // contentPanel + // + contentPanel.ColumnCount = 2; + contentPanel.ColumnStyles.Add(new ColumnStyle()); + contentPanel.ColumnStyles.Add(new ColumnStyle()); + contentPanel.Controls.Add(masterCategoryLabel, 0, 0); + contentPanel.Controls.Add(masterCategoryTxt, 1, 0); + contentPanel.Controls.Add(masterSubcategoryLabel, 0, 1); + contentPanel.Controls.Add(masterSubcategoryTxt, 1, 1); + contentPanel.Controls.Add(masterCodeItemLabel, 0, 2); + contentPanel.Controls.Add(masterCodeItemTxt, 1, 2); + contentPanel.Controls.Add(localDescriptionLabel, 0, 3); + contentPanel.Controls.Add(localDescriptionTxt, 1, 3); + contentPanel.Controls.Add(engDescriptionLabel, 0, 4); + contentPanel.Controls.Add(engDescriptionTxt, 1, 4); + contentPanel.Controls.Add(valueLabel, 0, 5); + contentPanel.Controls.Add(valueTxt, 1, 5); + contentPanel.Controls.Add(validIndcCombo, 1, 7); + contentPanel.Controls.Add(orderByTxt, 1, 6); + contentPanel.Controls.Add(orderByLabel, 0, 6); + contentPanel.Controls.Add(validIndcLabel, 0, 7); + contentPanel.Controls.Add(remarkTxt, 1, 9); + contentPanel.Controls.Add(remarkLabel, 0, 9); + contentPanel.Dock = DockStyle.Fill; + contentPanel.Location = new Point(3, 3); + contentPanel.Name = "contentPanel"; + contentPanel.RowCount = 10; + contentPanel.RowStyles.Add(new RowStyle()); + contentPanel.RowStyles.Add(new RowStyle()); + contentPanel.RowStyles.Add(new RowStyle()); + contentPanel.RowStyles.Add(new RowStyle()); + contentPanel.RowStyles.Add(new RowStyle()); + contentPanel.RowStyles.Add(new RowStyle()); + contentPanel.RowStyles.Add(new RowStyle()); + contentPanel.RowStyles.Add(new RowStyle()); + contentPanel.RowStyles.Add(new RowStyle()); + contentPanel.RowStyles.Add(new RowStyle()); + contentPanel.RowStyles.Add(new RowStyle(SizeType.Absolute, 20F)); + contentPanel.Size = new Size(794, 462); + contentPanel.TabIndex = 3; + // + // masterCategoryLabel + // + masterCategoryLabel.Location = new Point(3, 3); + masterCategoryLabel.Name = "masterCategoryLabel"; + masterCategoryLabel.Size = new Size(52, 20); + masterCategoryLabel.TabIndex = 0; + masterCategoryLabel.Values.Text = "主类别:"; + // + // masterCategoryTxt + // + masterCategoryTxt.Location = new Point(74, 3); + masterCategoryTxt.MaxLength = 50; + masterCategoryTxt.Name = "masterCategoryTxt"; + masterCategoryTxt.Size = new Size(300, 23); + masterCategoryTxt.TabIndex = 0; + // + // masterSubcategoryLabel + // + masterSubcategoryLabel.Location = new Point(3, 32); + masterSubcategoryLabel.Name = "masterSubcategoryLabel"; + masterSubcategoryLabel.Size = new Size(52, 20); + masterSubcategoryLabel.TabIndex = 0; + masterSubcategoryLabel.Values.Text = "子类别:"; + // + // masterSubcategoryTxt + // + masterSubcategoryTxt.Location = new Point(74, 32); + masterSubcategoryTxt.MaxLength = 50; + masterSubcategoryTxt.Name = "masterSubcategoryTxt"; + masterSubcategoryTxt.Size = new Size(300, 23); + masterSubcategoryTxt.TabIndex = 1; + // + // masterCodeItemLabel + // + masterCodeItemLabel.Location = new Point(3, 61); + masterCodeItemLabel.Name = "masterCodeItemLabel"; + masterCodeItemLabel.Size = new Size(39, 20); + masterCodeItemLabel.TabIndex = 0; + masterCodeItemLabel.Values.Text = "选项:"; + // + // masterCodeItemTxt + // + masterCodeItemTxt.Location = new Point(74, 61); + masterCodeItemTxt.MaxLength = 50; + masterCodeItemTxt.Name = "masterCodeItemTxt"; + masterCodeItemTxt.Size = new Size(300, 23); + masterCodeItemTxt.TabIndex = 2; + // + // localDescriptionLabel + // + localDescriptionLabel.Location = new Point(3, 90); + localDescriptionLabel.Name = "localDescriptionLabel"; + localDescriptionLabel.Size = new Size(65, 20); + localDescriptionLabel.TabIndex = 0; + localDescriptionLabel.Values.Text = "中文描述:"; + // + // localDescriptionTxt + // + localDescriptionTxt.Dock = DockStyle.Fill; + localDescriptionTxt.Location = new Point(74, 90); + localDescriptionTxt.MaxLength = 1000; + localDescriptionTxt.Multiline = true; + localDescriptionTxt.Name = "localDescriptionTxt"; + localDescriptionTxt.Size = new Size(717, 60); + localDescriptionTxt.TabIndex = 3; + // + // engDescriptionLabel + // + engDescriptionLabel.Location = new Point(3, 156); + engDescriptionLabel.Name = "engDescriptionLabel"; + engDescriptionLabel.Size = new Size(65, 20); + engDescriptionLabel.TabIndex = 0; + engDescriptionLabel.Values.Text = "英文描述:"; + // + // engDescriptionTxt + // + engDescriptionTxt.Dock = DockStyle.Fill; + engDescriptionTxt.Location = new Point(74, 156); + engDescriptionTxt.MaxLength = 1000; + engDescriptionTxt.Multiline = true; + engDescriptionTxt.Name = "engDescriptionTxt"; + engDescriptionTxt.Size = new Size(717, 60); + engDescriptionTxt.TabIndex = 4; + // + // valueLabel + // + valueLabel.Location = new Point(3, 222); + valueLabel.Name = "valueLabel"; + valueLabel.Size = new Size(26, 20); + valueLabel.TabIndex = 0; + valueLabel.Values.Text = "值:"; + // + // valueTxt + // + valueTxt.Location = new Point(74, 222); + valueTxt.MaxLength = 50; + valueTxt.Name = "valueTxt"; + valueTxt.Size = new Size(300, 23); + valueTxt.TabIndex = 5; + // + // orderByLabel + // + orderByLabel.Location = new Point(3, 251); + orderByLabel.Name = "orderByLabel"; + orderByLabel.Size = new Size(39, 20); + orderByLabel.TabIndex = 0; + orderByLabel.Values.Text = "排序:"; + // + // validIndcCombo + // + validIndcCombo.DropDownStyle = ComboBoxStyle.DropDownList; + validIndcCombo.DropDownWidth = 200; + validIndcCombo.IntegralHeight = false; + validIndcCombo.Location = new Point(74, 280); + validIndcCombo.Name = "validIndcCombo"; + validIndcCombo.Size = new Size(300, 22); + validIndcCombo.StateCommon.ComboBox.Content.TextH = Krypton.Toolkit.PaletteRelativeAlign.Near; + validIndcCombo.TabIndex = 7; + // + // remarkLabel + // + remarkLabel.Location = new Point(3, 308); + remarkLabel.Name = "remarkLabel"; + remarkLabel.Size = new Size(39, 20); + remarkLabel.TabIndex = 0; + remarkLabel.Values.Text = "备注:"; + // + // remarkTxt + // + remarkTxt.Dock = DockStyle.Fill; + remarkTxt.Location = new Point(74, 308); + remarkTxt.MaxLength = 3000; + remarkTxt.Multiline = true; + remarkTxt.Name = "remarkTxt"; + remarkTxt.Size = new Size(717, 151); + remarkTxt.TabIndex = 8; + // + // validIndcLabel + // + validIndcLabel.Location = new Point(3, 280); + validIndcLabel.Name = "validIndcLabel"; + validIndcLabel.Size = new Size(42, 20); + validIndcLabel.TabIndex = 0; + validIndcLabel.Values.Text = "有效?"; + // + // orderByTxt + // + orderByTxt.Location = new Point(74, 251); + orderByTxt.MaxLength = 9; + orderByTxt.Name = "orderByTxt"; + orderByTxt.Size = new Size(300, 23); + orderByTxt.TabIndex = 6; + // + // SecurityMasterDialogPage + // + AutoScaleDimensions = new SizeF(7F, 15F); + AutoScaleMode = AutoScaleMode.Font; + Controls.Add(mainPanel); + Name = "SecurityMasterDialogPage"; + Size = new Size(800, 505); + mainPanel.ResumeLayout(false); + mainPanel.PerformLayout(); + dialogPanel.ResumeLayout(false); + contentPanel.ResumeLayout(false); + contentPanel.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)validIndcCombo).EndInit(); + ResumeLayout(false); + } + + #endregion + + private TableLayoutPanel mainPanel; + private TableLayoutPanel dialogPanel; + private Krypton.Toolkit.KryptonButton cancelBut; + private Krypton.Toolkit.KryptonButton okBut; + private TableLayoutPanel contentPanel; + private Krypton.Toolkit.KryptonLabel masterCategoryLabel; + private Krypton.Toolkit.KryptonTextBox masterCategoryTxt; + private Krypton.Toolkit.KryptonLabel masterSubcategoryLabel; + private Krypton.Toolkit.KryptonTextBox masterSubcategoryTxt; + private Krypton.Toolkit.KryptonLabel masterCodeItemLabel; + private Krypton.Toolkit.KryptonTextBox masterCodeItemTxt; + private Krypton.Toolkit.KryptonLabel localDescriptionLabel; + private Krypton.Toolkit.KryptonTextBox localDescriptionTxt; + private Krypton.Toolkit.KryptonLabel engDescriptionLabel; + private Krypton.Toolkit.KryptonTextBox engDescriptionTxt; + private Krypton.Toolkit.KryptonLabel valueLabel; + private Krypton.Toolkit.KryptonTextBox valueTxt; + private Krypton.Toolkit.KryptonLabel orderByLabel; + private Krypton.Toolkit.KryptonComboBox validIndcCombo; + private Krypton.Toolkit.KryptonLabel remarkLabel; + private Krypton.Toolkit.KryptonTextBox remarkTxt; + private Krypton.Toolkit.KryptonTextBox orderByTxt; + private Krypton.Toolkit.KryptonLabel validIndcLabel; + } +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Security.Gui/SecurityMasterDialogPage.cs b/CloudBuilder/CloudBuilder.Security.Gui/SecurityMasterDialogPage.cs new file mode 100644 index 0000000..dfbf576 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/SecurityMasterDialogPage.cs @@ -0,0 +1,290 @@ +using CloudBuilder.Core.Service; +using CloudBuilder.Gui; +using CloudBuilder.Request.Security; +using CloudBuilder.Security.Entity; +using CloudBuilder.Security.Policy; +using CloudBuilder.Security.SearchCriteria; +using Krypton.Toolkit; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace CloudBuilder.Security.Gui +{ + public partial class SecurityMasterDialogPage : AbstractPage + { + private SecurityMessagePolicy securityMessagePolicy; + private SecurityMasterRequest securityMasterRequest; + private SecurityMasterEntity securityMasterEntity; + private bool allowCancel = false; + public SecurityMasterDialogPage() + { + InitializeComponent(); + } + + /// + /// 第一次加载时执行,只执行一次 + /// + public override void FunctionLoaded() + { + try + { + base.FunctionLoaded(); + //初始化容器------------------------------------- + securityMessagePolicy = ServiceHelper.GetTypeService()!; + securityMasterRequest = ServiceHelper.GetTypeService(); + + //界面初始化 + InitGui(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + /// + /// 弹出界面调用,发生在FunctionLoaded()之后 + /// + public override void InitInputData(object param, GuiDisplayMode mode) + { + base.InitInputData(param, mode); + if (mode == GuiDisplayMode.Create) + { + Create(); + return; + } + + SecurityMasterEntity securityMasterEntity = param as SecurityMasterEntity; + if (securityMasterEntity == null) return; + + Search(new SecurityMasterEntityKey() + { + MasterCategory = securityMasterEntity.MasterCategory, + MasterSubcategory = securityMasterEntity.MasterSubcategory, + MasterCodeItem = securityMasterEntity.MasterCodeItem + }); + + if (mode == GuiDisplayMode.Amend) + { + Amend(); + } + } + + private void InitGui() + { + InitBindingContext(); + InitCombo(); + InitDisplayMode(); + + this.ParentAbstractForm.AcceptButton = this.okBut; + + // 手动处理 ESC 键 + this.ParentAbstractForm.KeyPreview = true; // 允许表单接收按键事件 + this.ParentAbstractForm.KeyDown += (sender, e) => + { + if (e.KeyCode == Keys.Escape) + { + this.ParentAbstractForm.DialogResult = DialogResult.Cancel; + this.ParentAbstractForm.Close(); + } + }; + } + + private void InitCombo() + { + validIndcCombo.SetDataSource(YesNoPolicy.GetInstance().GetComposeMessages(), true); + } + + /// + /// 有特殊要求的UI控件初始化设置,Init与Add配对后,使用guiOperateHelper管理 + /// + private void InitBindingContext() + { + //需要绑定数据 + guiBindingContext = new GuiBindingContext(); + + masterCategoryTxt.Set(SecurityMasterEntity.MASTER_CATEGORY, masterCategoryLabel.Text, EnumEditModeColor.Required); + masterSubcategoryTxt.Set(SecurityMasterEntity.MASTER_SUBCATEGORY, masterSubcategoryLabel.Text,EnumEditModeColor.Required); + masterCodeItemTxt.Set(SecurityMasterEntity.MASTER_CODE_ITEM, masterCodeItemLabel.Text, EnumEditModeColor.Required); + localDescriptionTxt.Set(SecurityMasterEntity.LOCAL_DESCRIPTION); + engDescriptionTxt.Set(SecurityMasterEntity.ENG_DESCRIPTION); + valueTxt.Set(SecurityMasterEntity.VALUE, valueLabel.Text, EnumEditModeColor.Required); + validIndcCombo.Set(SecurityMasterEntity.VALID_INDC, validIndcLabel.Text, EnumEditModeColor.Required); + orderByTxt.Set(SecurityMasterEntity.ORDER_BY, orderByLabel.Text, EnumEditModeColor.Required); + remarkTxt.Set(SecurityMasterEntity.REMARK); + + guiOperateHelper = new GuiOperateHelper(); + } + + private void InitDisplayMode() + { + this.DisplayMode = GuiDisplayMode.View; + + SetDisplayMode(); + } + + private void SetDisplayMode() + { + if (this.DisplayMode == GuiDisplayMode.View) + { + okBut.Visible = false; + guiOperateHelper.EnableControls(false, contentPanel); + } + else if (this.DisplayMode == GuiDisplayMode.Amend || this.DisplayMode == GuiDisplayMode.Create) + { + okBut.Visible = true; + guiOperateHelper.EnableControls(true, contentPanel); + + if (this.DisplayMode == GuiDisplayMode.Amend) guiOperateHelper.EnableControls(false, masterCategoryTxt, masterCodeItemTxt, masterSubcategoryTxt); + } + } + + private void PackUIToEntity() + { + guiBindingContext.DataPack(); + securityMasterEntity.MasterCategory = masterCategoryTxt.Text; + securityMasterEntity.MasterSubcategory = masterSubcategoryTxt.Text; + securityMasterEntity.MasterCodeItem = masterCodeItemTxt.Text; + securityMasterEntity.Value = valueTxt.Text; + //..... + } + + private bool SaveValidate() + { + if (!guiOperateHelper.CheckValidate(this.mainPanel)) return false; + + return true; + } + + private void Search(SecurityMasterEntityKey masterEntityKey) + { + try + { + securityMasterEntity = securityMasterRequest.FindByKey(masterEntityKey); + + if (securityMasterEntity == null) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + } + else + { + PackEntityToUI(); + + SetDisplayMode(); + } + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void Create() + { + this.DisplayMode = GuiDisplayMode.Create; + + guiOperateHelper.ResetControls(this.mainPanel); + + SetDisplayMode(); + + securityMasterEntity = new SecurityMasterEntity() + { + CreatedBy = string.Empty, + UpdatedBy = string.Empty, + CreatedDatetime = DateTime.Now, + UpdatedDatetime = DateTime.Now, + }; + + PackEntityToUI(); + } + + private void Amend() + { + this.DisplayMode = GuiDisplayMode.Amend; + + SetDisplayMode(); + } + + private void PackEntityToUI() + { + guiBindingContext.DataBind(securityMasterEntity, this); + + } + + private void okBut_Click(object sender, EventArgs e) + { + try + { + if (!SaveValidate()) return; + + PackUIToEntity(); + + + if (this.DisplayMode == GuiDisplayMode.Create) + securityMasterRequest.Insert(securityMasterEntity); + else + securityMasterRequest.Update(securityMasterEntity); + + + ShowMessageBox.ShowInfo((this.DisplayMode == GuiDisplayMode.Create) ? + securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_SUCCEED_CREATED_NULL) : + securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_SUCCEED_UPDATED_NULL)); + + this.ParentAbstractForm.OutputData = securityMasterEntity; + + this.ParentAbstractForm.DialogResult = DialogResult.OK; + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + + } + + private void cancelBut_Click(object sender, EventArgs e) + { + if (GuiDisplayMode.View != this.DisplayMode) + { + DialogResult result = ShowMessageBox.ShowOption(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_CONFIRM_CANCEL), securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_CONFIRM)); + + if (result == DialogResult.No) + { + return; + } + } + + this.ParentAbstractForm.DialogResult = DialogResult.Cancel; + } + } +} diff --git a/CloudBuilder/CloudBuilder.Security.Gui/SecurityMasterDialogPage.resx b/CloudBuilder/CloudBuilder.Security.Gui/SecurityMasterDialogPage.resx new file mode 100644 index 0000000..8b2ff64 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/SecurityMasterDialogPage.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Security.Gui/SecurityMasterEnquiryPage.Designer.cs b/CloudBuilder/CloudBuilder.Security.Gui/SecurityMasterEnquiryPage.Designer.cs new file mode 100644 index 0000000..b8e9efc --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/SecurityMasterEnquiryPage.Designer.cs @@ -0,0 +1,530 @@ +namespace CloudBuilder.Security.Gui +{ + partial class SecurityMasterEnquiryPage + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + DataGridViewCellStyle dataGridViewCellStyle1 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle2 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle3 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle4 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle5 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle6 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle7 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle8 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle9 = new DataGridViewCellStyle(); + mainPanel = new TableLayoutPanel(); + topPanel = new TableLayoutPanel(); + masterCategoryLabel = new Krypton.Toolkit.KryptonLabel(); + masterCategoryTxt = new Krypton.Toolkit.KryptonTextBox(); + searchPanel = new TableLayoutPanel(); + searchBut = new Krypton.Toolkit.KryptonButton(); + resetBut = new Krypton.Toolkit.KryptonButton(); + createBut = new Krypton.Toolkit.KryptonButton(); + contextPanel = new TableLayoutPanel(); + dataGv = new Krypton.Toolkit.KryptonDataGridView(); + gridViewPagination = new CloudBuilder.Gui.GridViewPagination(); + bottomPanel = new TableLayoutPanel(); + operationPanel = new TableLayoutPanel(); + viewBut = new Krypton.Toolkit.KryptonButton(); + amendBut = new Krypton.Toolkit.KryptonButton(); + deleteBut = new Krypton.Toolkit.KryptonButton(); + dialogPanel = new TableLayoutPanel(); + okBut = new Krypton.Toolkit.KryptonButton(); + cancelBut = new Krypton.Toolkit.KryptonButton(); + masterSubcategoryLabel = new Krypton.Toolkit.KryptonLabel(); + masterSubcategoryTxt = new Krypton.Toolkit.KryptonTextBox(); + masterCodeItemLabel = new Krypton.Toolkit.KryptonLabel(); + masterCodeItemTxt = new Krypton.Toolkit.KryptonTextBox(); + localDescriptionLabel = new Krypton.Toolkit.KryptonLabel(); + localDescriptionTxt = new Krypton.Toolkit.KryptonTextBox(); + masterCategoryCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + masterSubcategoryCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + masterCodeItemCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + localDescriptionCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + engDescriptionCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + valueCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + remarkCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + orderByCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + validIndcCol = new Krypton.Toolkit.KryptonDataGridViewCheckBoxColumn(); + mainPanel.SuspendLayout(); + topPanel.SuspendLayout(); + searchPanel.SuspendLayout(); + contextPanel.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)dataGv).BeginInit(); + bottomPanel.SuspendLayout(); + operationPanel.SuspendLayout(); + dialogPanel.SuspendLayout(); + SuspendLayout(); + // + // mainPanel + // + mainPanel.ColumnCount = 1; + mainPanel.ColumnStyles.Add(new ColumnStyle()); + mainPanel.Controls.Add(topPanel, 0, 0); + mainPanel.Controls.Add(contextPanel, 0, 1); + mainPanel.Controls.Add(bottomPanel, 0, 2); + mainPanel.Dock = DockStyle.Fill; + mainPanel.Location = new Point(0, 0); + mainPanel.Name = "mainPanel"; + mainPanel.RowCount = 3; + mainPanel.RowStyles.Add(new RowStyle()); + mainPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 100F)); + mainPanel.RowStyles.Add(new RowStyle()); + mainPanel.Size = new Size(1024, 800); + mainPanel.TabIndex = 0; + // + // topPanel + // + topPanel.AutoSize = true; + topPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + topPanel.ColumnCount = 5; + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.Controls.Add(masterCategoryLabel, 0, 0); + topPanel.Controls.Add(masterCategoryTxt, 1, 0); + topPanel.Controls.Add(searchPanel, 4, 0); + topPanel.Controls.Add(masterSubcategoryLabel, 2, 0); + topPanel.Controls.Add(masterSubcategoryTxt, 3, 0); + topPanel.Controls.Add(masterCodeItemLabel, 0, 1); + topPanel.Controls.Add(masterCodeItemTxt, 1, 1); + topPanel.Controls.Add(localDescriptionLabel, 2, 1); + topPanel.Controls.Add(localDescriptionTxt, 3, 1); + topPanel.Dock = DockStyle.Fill; + topPanel.Location = new Point(3, 3); + topPanel.Name = "topPanel"; + topPanel.RowCount = 2; + topPanel.RowStyles.Add(new RowStyle()); + topPanel.RowStyles.Add(new RowStyle()); + topPanel.Size = new Size(1018, 60); + topPanel.TabIndex = 0; + // + // masterCategoryLabel + // + masterCategoryLabel.Location = new Point(3, 3); + masterCategoryLabel.Name = "masterCategoryLabel"; + masterCategoryLabel.Size = new Size(52, 20); + masterCategoryLabel.TabIndex = 999; + masterCategoryLabel.Values.Text = "主类别:"; + // + // masterCategoryTxt + // + masterCategoryTxt.Location = new Point(61, 3); + masterCategoryTxt.Name = "masterCategoryTxt"; + masterCategoryTxt.Size = new Size(200, 23); + masterCategoryTxt.TabIndex = 0; + // + // searchPanel + // + searchPanel.AutoSize = true; + searchPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + searchPanel.ColumnCount = 3; + searchPanel.ColumnStyles.Add(new ColumnStyle()); + searchPanel.ColumnStyles.Add(new ColumnStyle()); + searchPanel.ColumnStyles.Add(new ColumnStyle()); + searchPanel.Controls.Add(searchBut, 0, 0); + searchPanel.Controls.Add(resetBut, 1, 0); + searchPanel.Controls.Add(createBut, 2, 0); + searchPanel.Location = new Point(615, 0); + searchPanel.Margin = new Padding(60, 0, 0, 0); + searchPanel.Name = "searchPanel"; + searchPanel.RowCount = 1; + searchPanel.RowStyles.Add(new RowStyle()); + searchPanel.Size = new Size(288, 31); + searchPanel.TabIndex = 999; + // + // searchBut + // + searchBut.Location = new Point(3, 3); + searchBut.Name = "searchBut"; + searchBut.Size = new Size(90, 25); + searchBut.TabIndex = 0; + searchBut.Values.Image = Properties.Resources.search_16; + searchBut.Values.Text = "查询(&S)"; + searchBut.Click += searchBut_Click; + // + // resetBut + // + resetBut.Location = new Point(99, 3); + resetBut.Name = "resetBut"; + resetBut.Size = new Size(90, 25); + resetBut.TabIndex = 0; + resetBut.Values.Image = Properties.Resources.reset_16; + resetBut.Values.Text = "重置(&R)"; + resetBut.Click += resetBut_Click; + // + // createBut + // + createBut.Location = new Point(195, 3); + createBut.Name = "createBut"; + createBut.Size = new Size(90, 25); + createBut.TabIndex = 0; + createBut.Values.Image = Properties.Resources.create_16; + createBut.Values.Text = "新增(&C)"; + createBut.Click += createBut_Click; + // + // contextPanel + // + contextPanel.ColumnCount = 1; + contextPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F)); + contextPanel.Controls.Add(dataGv, 0, 0); + contextPanel.Controls.Add(gridViewPagination, 0, 1); + contextPanel.Dock = DockStyle.Fill; + contextPanel.Location = new Point(3, 69); + contextPanel.Name = "contextPanel"; + contextPanel.RowCount = 2; + contextPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 50F)); + contextPanel.RowStyles.Add(new RowStyle()); + contextPanel.Size = new Size(1018, 654); + contextPanel.TabIndex = 999; + // + // dataGv + // + dataGv.AllowUserToAddRows = false; + dataGv.AllowUserToDeleteRows = false; + dataGv.BorderStyle = BorderStyle.None; + dataGv.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize; + dataGv.Columns.AddRange(new DataGridViewColumn[] { masterCategoryCol, masterSubcategoryCol, masterCodeItemCol, localDescriptionCol, engDescriptionCol, valueCol, remarkCol, orderByCol, validIndcCol }); + dataGv.Dock = DockStyle.Fill; + dataGv.Location = new Point(3, 3); + dataGv.Name = "dataGv"; + dataGv.Size = new Size(1012, 618); + dataGv.TabIndex = 0; + dataGv.CellDoubleClick += dataGv_CellDoubleClick; + // + // gridViewPagination + // + gridViewPagination.AutoSizeMode = AutoSizeMode.GrowAndShrink; + gridViewPagination.CurrentPage = 0; + gridViewPagination.Dock = DockStyle.Fill; + gridViewPagination.Limit = 20; + gridViewPagination.Location = new Point(0, 624); + gridViewPagination.Margin = new Padding(0); + gridViewPagination.Name = "gridViewPagination"; + gridViewPagination.Page = 0; + gridViewPagination.Size = new Size(1018, 30); + gridViewPagination.TabIndex = 999; + gridViewPagination.Total = 0; + // + // bottomPanel + // + bottomPanel.AutoSize = true; + bottomPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + bottomPanel.ColumnCount = 2; + bottomPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F)); + bottomPanel.ColumnStyles.Add(new ColumnStyle()); + bottomPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 20F)); + bottomPanel.Controls.Add(operationPanel, 0, 0); + bottomPanel.Controls.Add(dialogPanel, 2, 1); + bottomPanel.Dock = DockStyle.Fill; + bottomPanel.Location = new Point(3, 729); + bottomPanel.Name = "bottomPanel"; + bottomPanel.RowCount = 2; + bottomPanel.RowStyles.Add(new RowStyle()); + bottomPanel.RowStyles.Add(new RowStyle()); + bottomPanel.Size = new Size(1018, 68); + bottomPanel.TabIndex = 999; + // + // operationPanel + // + operationPanel.AutoSize = true; + operationPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + operationPanel.ColumnCount = 3; + operationPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F)); + operationPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 101F)); + operationPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F)); + operationPanel.Controls.Add(viewBut, 0, 0); + operationPanel.Controls.Add(amendBut, 1, 0); + operationPanel.Controls.Add(deleteBut, 2, 0); + operationPanel.Location = new Point(0, 0); + operationPanel.Margin = new Padding(0); + operationPanel.Name = "operationPanel"; + operationPanel.RowCount = 1; + operationPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 50F)); + operationPanel.Size = new Size(293, 31); + operationPanel.TabIndex = 0; + // + // viewBut + // + viewBut.Location = new Point(3, 3); + viewBut.Name = "viewBut"; + viewBut.Size = new Size(90, 25); + viewBut.TabIndex = 0; + viewBut.Values.Image = Properties.Resources.view_16; + viewBut.Values.Text = "查看(&V)"; + viewBut.Click += viewBut_Click; + // + // amendBut + // + amendBut.Location = new Point(99, 3); + amendBut.Name = "amendBut"; + amendBut.Size = new Size(90, 25); + amendBut.TabIndex = 0; + amendBut.Values.Image = Properties.Resources.amend_16; + amendBut.Values.Text = "修改(&A)"; + amendBut.Click += amendBut_Click; + // + // deleteBut + // + deleteBut.Location = new Point(200, 3); + deleteBut.Name = "deleteBut"; + deleteBut.Size = new Size(90, 25); + deleteBut.TabIndex = 0; + deleteBut.Values.Image = Properties.Resources.delete_16; + deleteBut.Values.Text = "删除(&D)"; + deleteBut.Click += deleteBut_Click; + // + // dialogPanel + // + dialogPanel.AutoSize = true; + dialogPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + dialogPanel.ColumnCount = 2; + dialogPanel.ColumnStyles.Add(new ColumnStyle()); + dialogPanel.ColumnStyles.Add(new ColumnStyle()); + dialogPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 20F)); + dialogPanel.Controls.Add(okBut, 0, 0); + dialogPanel.Controls.Add(cancelBut, 1, 0); + dialogPanel.Dock = DockStyle.Fill; + dialogPanel.Location = new Point(823, 34); + dialogPanel.Name = "dialogPanel"; + dialogPanel.RowCount = 1; + dialogPanel.RowStyles.Add(new RowStyle()); + dialogPanel.Size = new Size(192, 31); + dialogPanel.TabIndex = 1; + // + // okBut + // + okBut.Location = new Point(3, 3); + okBut.Name = "okBut"; + okBut.Size = new Size(90, 25); + okBut.TabIndex = 0; + okBut.Values.Image = Properties.Resources.ok_16; + okBut.Values.Text = "确定(&O)"; + okBut.Click += okBut_Click; + // + // cancelBut + // + cancelBut.Location = new Point(99, 3); + cancelBut.Name = "cancelBut"; + cancelBut.Size = new Size(90, 25); + cancelBut.TabIndex = 0; + cancelBut.Values.Image = Properties.Resources.close_16; + cancelBut.Values.Text = "取消(&C)"; + cancelBut.Click += cancelBut_Click; + // + // masterSubcategoryLabel + // + masterSubcategoryLabel.Location = new Point(294, 3); + masterSubcategoryLabel.Margin = new Padding(30, 3, 3, 3); + masterSubcategoryLabel.Name = "masterSubcategoryLabel"; + masterSubcategoryLabel.Size = new Size(52, 20); + masterSubcategoryLabel.TabIndex = 999; + masterSubcategoryLabel.Values.Text = "子类别:"; + // + // masterSubcategoryTxt + // + masterSubcategoryTxt.Location = new Point(352, 3); + masterSubcategoryTxt.Name = "masterSubcategoryTxt"; + masterSubcategoryTxt.Size = new Size(200, 23); + masterSubcategoryTxt.TabIndex = 0; + // + // masterCodeItemLabel + // + masterCodeItemLabel.Location = new Point(3, 34); + masterCodeItemLabel.Name = "masterCodeItemLabel"; + masterCodeItemLabel.Size = new Size(39, 20); + masterCodeItemLabel.TabIndex = 999; + masterCodeItemLabel.Values.Text = "选项:"; + // + // masterCodeItemTxt + // + masterCodeItemTxt.Location = new Point(61, 34); + masterCodeItemTxt.Name = "masterCodeItemTxt"; + masterCodeItemTxt.Size = new Size(200, 23); + masterCodeItemTxt.TabIndex = 0; + // + // localDescriptionLabel + // + localDescriptionLabel.Location = new Point(294, 34); + localDescriptionLabel.Margin = new Padding(30, 3, 3, 3); + localDescriptionLabel.Name = "localDescriptionLabel"; + localDescriptionLabel.Size = new Size(39, 20); + localDescriptionLabel.TabIndex = 999; + localDescriptionLabel.Values.Text = "描述:"; + // + // localDescriptionTxt + // + localDescriptionTxt.Location = new Point(352, 34); + localDescriptionTxt.Name = "localDescriptionTxt"; + localDescriptionTxt.Size = new Size(200, 23); + localDescriptionTxt.TabIndex = 0; + // + // masterCategoryCol + // + masterCategoryCol.DataPropertyName = "MasterCategory"; + masterCategoryCol.DefaultCellStyle = dataGridViewCellStyle1; + masterCategoryCol.HeaderText = "主类别"; + masterCategoryCol.Name = "masterCategoryCol"; + masterCategoryCol.Width = 260; + // + // masterSubcategoryCol + // + masterSubcategoryCol.DataPropertyName = "MasterSubcategory"; + masterSubcategoryCol.DefaultCellStyle = dataGridViewCellStyle2; + masterSubcategoryCol.HeaderText = "子类别"; + masterSubcategoryCol.Name = "masterSubcategoryCol"; + masterSubcategoryCol.Width = 260; + // + // masterCodeItemCol + // + masterCodeItemCol.DataPropertyName = "MasterCodeItem"; + masterCodeItemCol.DefaultCellStyle = dataGridViewCellStyle3; + masterCodeItemCol.HeaderText = "选项"; + masterCodeItemCol.Name = "masterCodeItemCol"; + masterCodeItemCol.Resizable = DataGridViewTriState.True; + masterCodeItemCol.Width = 260; + // + // localDescriptionCol + // + localDescriptionCol.DataPropertyName = "LocalDescription"; + localDescriptionCol.DefaultCellStyle = dataGridViewCellStyle4; + localDescriptionCol.HeaderText = "中文描述"; + localDescriptionCol.Name = "localDescriptionCol"; + localDescriptionCol.Resizable = DataGridViewTriState.True; + localDescriptionCol.Width = 300; + // + // engDescriptionCol + // + engDescriptionCol.DataPropertyName = "EngDescription"; + engDescriptionCol.DefaultCellStyle = dataGridViewCellStyle5; + engDescriptionCol.HeaderText = "英文描述"; + engDescriptionCol.Name = "engDescriptionCol"; + engDescriptionCol.Resizable = DataGridViewTriState.True; + engDescriptionCol.Width = 300; + // + // valueCol + // + valueCol.DataPropertyName = "Value"; + valueCol.DefaultCellStyle = dataGridViewCellStyle6; + valueCol.HeaderText = "值"; + valueCol.Name = "valueCol"; + valueCol.Resizable = DataGridViewTriState.True; + valueCol.Width = 100; + // + // remarkCol + // + remarkCol.DataPropertyName = "Remark"; + remarkCol.DefaultCellStyle = dataGridViewCellStyle7; + remarkCol.HeaderText = "备注"; + remarkCol.Name = "remarkCol"; + remarkCol.Resizable = DataGridViewTriState.True; + remarkCol.Width = 300; + // + // orderByCol + // + orderByCol.DataPropertyName = "OrderBy"; + orderByCol.DefaultCellStyle = dataGridViewCellStyle8; + orderByCol.HeaderText = "排序"; + orderByCol.Name = "orderByCol"; + orderByCol.Resizable = DataGridViewTriState.True; + orderByCol.Width = 100; + // + // validIndcCol + // + validIndcCol.DataPropertyName = "ValidIndc"; + dataGridViewCellStyle9.Alignment = DataGridViewContentAlignment.MiddleCenter; + dataGridViewCellStyle9.NullValue = false; + validIndcCol.DefaultCellStyle = dataGridViewCellStyle9; + validIndcCol.FalseValue = "N"; + validIndcCol.HeaderText = "有效?"; + validIndcCol.IndeterminateValue = null; + validIndcCol.Name = "validIndcCol"; + validIndcCol.Resizable = DataGridViewTriState.True; + validIndcCol.SortMode = DataGridViewColumnSortMode.Automatic; + validIndcCol.TrueValue = "Y"; + // + // SecurityMasterEnquiryPage + // + AutoScaleDimensions = new SizeF(7F, 15F); + AutoScaleMode = AutoScaleMode.Font; + Controls.Add(mainPanel); + Name = "SecurityMasterEnquiryPage"; + mainPanel.ResumeLayout(false); + mainPanel.PerformLayout(); + topPanel.ResumeLayout(false); + topPanel.PerformLayout(); + searchPanel.ResumeLayout(false); + contextPanel.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)dataGv).EndInit(); + bottomPanel.ResumeLayout(false); + bottomPanel.PerformLayout(); + operationPanel.ResumeLayout(false); + dialogPanel.ResumeLayout(false); + ResumeLayout(false); + } + + #endregion + + private TableLayoutPanel mainPanel; + private TableLayoutPanel topPanel; + private TableLayoutPanel searchPanel; + private Krypton.Toolkit.KryptonButton searchBut; + private Krypton.Toolkit.KryptonButton resetBut; + private Krypton.Toolkit.KryptonButton createBut; + private TableLayoutPanel contextPanel; + private TableLayoutPanel bottomPanel; + private TableLayoutPanel operationPanel; + private Krypton.Toolkit.KryptonButton viewBut; + private Krypton.Toolkit.KryptonButton amendBut; + private Krypton.Toolkit.KryptonButton deleteBut; + private Krypton.Toolkit.KryptonLabel masterCategoryLabel; + private Krypton.Toolkit.KryptonTextBox masterCategoryTxt; + private Krypton.Toolkit.KryptonDataGridView dataGv; + private TableLayoutPanel dialogPanel; + private Krypton.Toolkit.KryptonButton okBut; + private Krypton.Toolkit.KryptonButton cancelBut; + private CloudBuilder.Gui.GridViewPagination gridViewPagination; + private Krypton.Toolkit.KryptonLabel masterSubcategoryLabel; + private Krypton.Toolkit.KryptonTextBox masterSubcategoryTxt; + private Krypton.Toolkit.KryptonLabel masterCodeItemLabel; + private Krypton.Toolkit.KryptonTextBox masterCodeItemTxt; + private Krypton.Toolkit.KryptonLabel localDescriptionLabel; + private Krypton.Toolkit.KryptonTextBox localDescriptionTxt; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn masterCategoryCol; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn masterSubcategoryCol; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn masterCodeItemCol; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn localDescriptionCol; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn engDescriptionCol; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn valueCol; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn remarkCol; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn orderByCol; + private Krypton.Toolkit.KryptonDataGridViewCheckBoxColumn validIndcCol; + } +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Security.Gui/SecurityMasterEnquiryPage.cs b/CloudBuilder/CloudBuilder.Security.Gui/SecurityMasterEnquiryPage.cs new file mode 100644 index 0000000..7abcc9e --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/SecurityMasterEnquiryPage.cs @@ -0,0 +1,468 @@ +using ClosedXML.Excel; +using CloudBuilder.Core.DependencyInjection.Form; +using CloudBuilder.Core.Report; +using CloudBuilder.Core.Service; +using CloudBuilder.Gui; +using CloudBuilder.Gui.DependencyInjection; +using CloudBuilder.Request.Security; +using CloudBuilder.Security.Data; +using CloudBuilder.Security.Entity; +using CloudBuilder.Security.Linkup; +using CloudBuilder.Security.Policy; +using CloudBuilder.Security.SearchCriteria; +using DocumentFormat.OpenXml.Spreadsheet; +using Krypton.Toolkit; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http.Extensions; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.IdentityModel.Tokens; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + + +namespace CloudBuilder.Security.Gui +{ + public partial class SecurityMasterEnquiryPage : AbstractPage + { + private SecurityMasterEntity[] securityMasters = null!; + private SecurityMasterSearchCriteria searchCriteria = null!; + private BindingContextAttributeProvider provider; + private SecurityMasterRequest securityMasterRequest; + private SecurityMessagePolicy securityMessagePolicy; + + //初始化Page,注入容器内,不要在此做任何事情 + public SecurityMasterEnquiryPage() + { + InitializeComponent(); + } + + /// + /// 第一次加载时执行,只执行一次 + /// + public override void FunctionLoaded() + { + try + { + base.FunctionLoaded(); + //初始化容器------------------------------------- + securityMasterRequest = ServiceHelper.GetTypeService(); + securityMessagePolicy = ServiceHelper.GetTypeService()!; + + //界面初始化 + InitGui(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + /// + /// 每次从别的界面进入时执行,不包括下面的界面切换,发生在FunctionLoaded之后 + /// 这个是有参数传入,常用于查询界面进入到操作界面发生 + /// + /// + public override void FunctionActivated(object param) + { + base.FunctionActivated(param); + masterCategoryTxt.Focus(); + } + /// + /// 当Page被选中时执行,用于Tab导航的切换,没有参数变化,跟FunctionActivated有区别 + /// + public override void FunctionSelected() + { + this.ParentAbstractForm.AcceptButton = this.searchBut; + if (!IsDialog) + this.ParentAbstractForm.CancelButton = this.resetBut; + else + this.ParentAbstractForm.CancelButton = this.cancelBut; + + masterCategoryTxt.Focus(); + } + /// + /// 控件的初始化 + /// + private void InitGui() + { + //DataGridView初始化不要自动生成列,且允许重排列名操作 + dataGv.InitColumn(true, true); + //初始化绑定设置 + InitBindingContext(); + //设置显示模式 + SetDisplayMode(true); + + InitGridViewPagination(); + } + /// + /// DataGridView分页控件初始化 + /// + private void InitGridViewPagination() + { + searchCriteria = new SecurityMasterSearchCriteria(); + gridViewPagination.SetLimit(searchCriteria.limit); + gridViewPagination.OnPaginationChanged += Search; + gridViewPagination.OnPrint += Print; + } + + /// + /// 打印当前查询结果 + /// + private void Print() + { + //設置查詢條件 + List searCriteria = new List(); + if (!string.IsNullOrEmpty(masterCategoryTxt.Text)) + searCriteria.Add(masterCategoryLabel.Text + masterCategoryTxt.Text); + + //設置每列的格式 + TemplateHeader[] headers = dataGv.GetTemplateHeaders(); + + //打印Excel + new DataToExcelHelper(null).PrintExcel(this.Parent.Text, this.Parent.Text, searCriteria, headers, securityMasters); + } + + /// + /// 有特殊要求的UI控件初始化设置,使用guiOperateHelper管理 + /// + private void InitBindingContext() + { + InitPermission(); + + guiOperateHelper = new GuiOperateHelper(); + } + + private void InitPermission() + { + viewBut.Set(SecurityPermissionPolicy.SecurityMaster, Operate.Find); + createBut.Set(SecurityPermissionPolicy.SecurityMaster, Operate.Insert); + amendBut.Set(SecurityPermissionPolicy.SecurityMaster, Operate.Update); + deleteBut.Set(SecurityPermissionPolicy.SecurityMaster, Operate.Delete); + } + + private void SetDisplayMode(bool enable) + { + guiOperateHelper.EnableControls(true, this.searchPanel, this.bottomPanel); + guiOperateHelper.EnableControls(false, dataGv); + + if (securityMasters != null) + guiOperateHelper.EnableControls(enable, viewBut, amendBut, deleteBut); + else + guiOperateHelper.EnableControls(false, viewBut, amendBut, deleteBut); + + //如果是弹出的窗口,不显示 + createBut.Visible = !IsDialog; + dialogPanel.Visible = IsDialog; + operationPanel.Visible = !IsDialog; + + this.masterCategoryTxt.Focus(); + } + + private void searchBut_Click(object sender, EventArgs e) + { + try + { + Search(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + /// + /// 与Web同步写法 + /// + /// + private SecurityMasterSearchCriteria PackSearchCriteria() + { + searchCriteria = new SecurityMasterSearchCriteria(); + searchCriteria.limit = gridViewPagination.Limit; + searchCriteria.page = gridViewPagination.CurrentPage; + + List filters = new List(); + + SearchFilter filter = new SearchFilter(); + filter.Column = SecurityMasterEntity.DB_MASTER_CATEGORY; + filter.Type = SearchFilterTypePolicy.TEXT; + filter.Operator = SearchFilterOperatorPolicy.CONTAIN; + filter.Value = masterCategoryTxt.GetValue(); + filters.Add(filter); + + filter = new SearchFilter(); + filter.Column = SecurityMasterEntity.DB_MASTER_SUBCATEGORY; + filter.Type = SearchFilterTypePolicy.TEXT; + filter.Operator = SearchFilterOperatorPolicy.CONTAIN; + filter.Value = masterSubcategoryTxt.GetValue(); + filters.Add(filter); + + filter = new SearchFilter(); + filter.Column = SecurityMasterEntity.DB_MASTER_CODE_ITEM; + filter.Type = SearchFilterTypePolicy.TEXT; + filter.Operator = SearchFilterOperatorPolicy.CONTAIN; + filter.Value = masterCodeItemTxt.GetValue(); + filters.Add(filter); + + filter = new SearchFilter(); + filter.Column = SecurityMasterEntity.DB_LOCAL_DESCRIPTION; + filter.Type = SearchFilterTypePolicy.TEXT; + filter.Operator = SearchFilterOperatorPolicy.CN_CONTAIN; + filter.Value = localDescriptionTxt.GetValue(); + filters.Add(filter); + + + searchCriteria.Filter = filters.ToArray(); + + return searchCriteria; + } + + private void Search() + { + try + { + var data = securityMasterRequest.FindBySearchCriteria(PackSearchCriteria()); + + if (data != null) securityMasters = data.Datas; + + gridViewPagination.SetTotal(data.Total); + + if (securityMasters == null || securityMasters.Length == 0) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + guiOperateHelper.ResetControls(this.dataGv); + return; + } + + dataGv.SetDataSource(securityMasters); + + SetDisplayMode(true); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void resetBut_Click(object sender, EventArgs e) + { + guiOperateHelper.ResetControls(this.mainPanel); + //Reset时默认会设置limit为AbstractSearchCriteria.limit,如果不同时,需要重新设置 + gridViewPagination.SetLimit(searchCriteria.limit); + SetDisplayMode(false); + } + + private void createBut_Click(object sender, EventArgs e) + { + DisplayPage(GuiDisplayMode.Create, null); + } + + private void DisplayPage(GuiDisplayMode mode, SecurityMasterEntity data) + { + try + { + AbstractForm dialog = GetAbstractDialog(typeof(SecurityMasterDialogPage).Name); + if (mode == GuiDisplayMode.Create) + { + if (DialogResult.OK != dialog.ShowCreateDialog()) return; + } + else if (mode == GuiDisplayMode.Amend) + { + if (DialogResult.OK != dialog.ShowAmendDialog(data)) return; + } + else + { + dialog.ShowViewDialog(data); + return; + } + + //masterCategoryTxt.Text = ((SecurityMasterEntity)dialog.OutputData).MasterCategory; + //masterSubcategoryTxt.Text = ((SecurityMasterEntity)dialog.OutputData).MasterSubcategory; + //masterCodeItemTxt.Text = ((SecurityMasterEntity)dialog.OutputData).MasterCodeItem; + + Search(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + + private void viewBut_Click(object sender, EventArgs e) + { + if (dataGv.RowCount <= 0 || dataGv.SelectedCells.Count <= 0) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + return; + } + + SecurityMasterEntity data = dataGv.GetRowData(dataGv.SelectedCells[0].RowIndex); + + DisplayPage(GuiDisplayMode.View, data); + } + + private void amendBut_Click(object sender, EventArgs e) + { + if (dataGv.RowCount <= 0 || dataGv.SelectedCells.Count <= 0) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + return; + } + + SecurityMasterEntity data = dataGv.GetRowData(dataGv.SelectedCells[0].RowIndex); + + DisplayPage(GuiDisplayMode.Amend, data); + } + + private void deleteBut_Click(object sender, EventArgs e) + { + try + { + Delete(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void Delete() + { + if (dataGv.RowCount <= 0 || dataGv.SelectedCells.Count <= 0) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + return; + } + + if (DialogResult.Yes != ShowMessageBox.ShowOption(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_CONFIRM_DEL_NULL), securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_DELETE))) return; + + SecurityMasterEntity[] datas = dataGv.GetSelectedCellsData(); + + securityMasterRequest.Deletes(datas); + + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_SUCCEED_DELETED_NULL)); + + Search(); + } + + private void okBut_Click(object sender, EventArgs e) + { + try + { + if (dataGv.RowCount <= 0 || dataGv.SelectedCells.Count <= 0) return; + //SecurityMasterEntity data = dataGv.GetRowData(dataGv.SelectedCells[0].RowIndex); + SecurityMasterEntity[] datas = dataGv.GetSelectedCellsData(); + + this.ParentAbstractForm.OutputData = datas; + this.ParentAbstractForm.DialogResult = DialogResult.OK; + this.ParentAbstractForm.Close(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void cancelBut_Click(object sender, EventArgs e) + { + try + { + this.ParentAbstractForm.DialogResult = DialogResult.Cancel; + this.ParentAbstractForm.Close(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void dataGv_CellDoubleClick(object sender, DataGridViewCellEventArgs e) + { + try + { + if (IsDialog) + okBut_Click(null, null); + else + viewBut_Click(null, null); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + } +} diff --git a/CloudBuilder/CloudBuilder.Security.Gui/SecurityMasterEnquiryPage.resx b/CloudBuilder/CloudBuilder.Security.Gui/SecurityMasterEnquiryPage.resx new file mode 100644 index 0000000..4dfba1e --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/SecurityMasterEnquiryPage.resx @@ -0,0 +1,147 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Security.Gui/SecurityPermissionDependentEnquiryPage.Designer.cs b/CloudBuilder/CloudBuilder.Security.Gui/SecurityPermissionDependentEnquiryPage.Designer.cs new file mode 100644 index 0000000..aa8ba34 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/SecurityPermissionDependentEnquiryPage.Designer.cs @@ -0,0 +1,420 @@ +namespace CloudBuilder.Security.Gui +{ + partial class SecurityPermissionDependentEnquiryPage + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + DataGridViewCellStyle dataGridViewCellStyle9 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle10 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle11 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle12 = new DataGridViewCellStyle(); + mainPanel = new TableLayoutPanel(); + topPanel = new TableLayoutPanel(); + searchPermissionNameLabel = new Krypton.Toolkit.KryptonLabel(); + permissionNameTxt = new Krypton.Toolkit.KryptonTextBox(); + searchPanel = new TableLayoutPanel(); + searchBut = new Krypton.Toolkit.KryptonButton(); + resetBut = new Krypton.Toolkit.KryptonButton(); + createBut = new Krypton.Toolkit.KryptonButton(); + contextPanel = new TableLayoutPanel(); + dataGv = new Krypton.Toolkit.KryptonDataGridView(); + gridViewPagination = new CloudBuilder.Gui.GridViewPagination(); + bottomPanel = new TableLayoutPanel(); + operationPanel = new TableLayoutPanel(); + viewBut = new Krypton.Toolkit.KryptonButton(); + amendBut = new Krypton.Toolkit.KryptonButton(); + deleteBut = new Krypton.Toolkit.KryptonButton(); + dialogPanel = new TableLayoutPanel(); + okBut = new Krypton.Toolkit.KryptonButton(); + cancelBut = new Krypton.Toolkit.KryptonButton(); + permissionNameCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + dependentCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + dependentDetailNameCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + descriptionCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + dependentLabel = new Krypton.Toolkit.KryptonLabel(); + dependentTxt = new Krypton.Toolkit.KryptonTextBox(); + mainPanel.SuspendLayout(); + topPanel.SuspendLayout(); + searchPanel.SuspendLayout(); + contextPanel.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)dataGv).BeginInit(); + bottomPanel.SuspendLayout(); + operationPanel.SuspendLayout(); + dialogPanel.SuspendLayout(); + SuspendLayout(); + // + // mainPanel + // + mainPanel.ColumnCount = 1; + mainPanel.ColumnStyles.Add(new ColumnStyle()); + mainPanel.Controls.Add(topPanel, 0, 0); + mainPanel.Controls.Add(contextPanel, 0, 1); + mainPanel.Controls.Add(bottomPanel, 0, 2); + mainPanel.Dock = DockStyle.Fill; + mainPanel.Location = new Point(0, 0); + mainPanel.Name = "mainPanel"; + mainPanel.RowCount = 3; + mainPanel.RowStyles.Add(new RowStyle()); + mainPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 100F)); + mainPanel.RowStyles.Add(new RowStyle()); + mainPanel.Size = new Size(1024, 800); + mainPanel.TabIndex = 0; + // + // topPanel + // + topPanel.AutoSize = true; + topPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + topPanel.ColumnCount = 5; + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.Controls.Add(searchPermissionNameLabel, 0, 0); + topPanel.Controls.Add(permissionNameTxt, 1, 0); + topPanel.Controls.Add(searchPanel, 4, 0); + topPanel.Controls.Add(dependentLabel, 2, 0); + topPanel.Controls.Add(dependentTxt, 3, 0); + topPanel.Dock = DockStyle.Fill; + topPanel.Location = new Point(3, 3); + topPanel.Name = "topPanel"; + topPanel.RowCount = 1; + topPanel.RowStyles.Add(new RowStyle()); + topPanel.Size = new Size(1018, 31); + topPanel.TabIndex = 0; + // + // searchPermissionNameLabel + // + searchPermissionNameLabel.Location = new Point(3, 3); + searchPermissionNameLabel.Name = "searchPermissionNameLabel"; + searchPermissionNameLabel.Size = new Size(52, 20); + searchPermissionNameLabel.TabIndex = 999; + searchPermissionNameLabel.Values.Text = "权限名:"; + // + // permissionNameTxt + // + permissionNameTxt.Location = new Point(61, 3); + permissionNameTxt.Name = "permissionNameTxt"; + permissionNameTxt.Size = new Size(200, 23); + permissionNameTxt.TabIndex = 0; + // + // searchPanel + // + searchPanel.AutoSize = true; + searchPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + searchPanel.ColumnCount = 3; + searchPanel.ColumnStyles.Add(new ColumnStyle()); + searchPanel.ColumnStyles.Add(new ColumnStyle()); + searchPanel.ColumnStyles.Add(new ColumnStyle()); + searchPanel.Controls.Add(searchBut, 0, 0); + searchPanel.Controls.Add(resetBut, 1, 0); + searchPanel.Controls.Add(createBut, 2, 0); + searchPanel.Location = new Point(609, 0); + searchPanel.Margin = new Padding(60, 0, 0, 0); + searchPanel.Name = "searchPanel"; + searchPanel.RowCount = 1; + searchPanel.RowStyles.Add(new RowStyle()); + searchPanel.Size = new Size(288, 31); + searchPanel.TabIndex = 999; + // + // searchBut + // + searchBut.Location = new Point(3, 3); + searchBut.Name = "searchBut"; + searchBut.Size = new Size(90, 25); + searchBut.TabIndex = 0; + searchBut.Values.Image = Properties.Resources.search_16; + searchBut.Values.Text = "查询(&S)"; + searchBut.Click += searchBut_Click; + // + // resetBut + // + resetBut.Location = new Point(99, 3); + resetBut.Name = "resetBut"; + resetBut.Size = new Size(90, 25); + resetBut.TabIndex = 0; + resetBut.Values.Image = Properties.Resources.reset_16; + resetBut.Values.Text = "重置(&R)"; + resetBut.Click += resetBut_Click; + // + // createBut + // + createBut.Location = new Point(195, 3); + createBut.Name = "createBut"; + createBut.Size = new Size(90, 25); + createBut.TabIndex = 0; + createBut.Values.Image = Properties.Resources.create_16; + createBut.Values.Text = "新增(&C)"; + createBut.Click += createBut_Click; + // + // contextPanel + // + contextPanel.ColumnCount = 1; + contextPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F)); + contextPanel.Controls.Add(dataGv, 0, 0); + contextPanel.Controls.Add(gridViewPagination, 0, 1); + contextPanel.Dock = DockStyle.Fill; + contextPanel.Location = new Point(3, 40); + contextPanel.Name = "contextPanel"; + contextPanel.RowCount = 2; + contextPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 50F)); + contextPanel.RowStyles.Add(new RowStyle()); + contextPanel.Size = new Size(1018, 683); + contextPanel.TabIndex = 999; + // + // dataGv + // + dataGv.AllowUserToAddRows = false; + dataGv.AllowUserToDeleteRows = false; + dataGv.BorderStyle = BorderStyle.None; + dataGv.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize; + dataGv.Columns.AddRange(new DataGridViewColumn[] { permissionNameCol, dependentCol, dependentDetailNameCol, descriptionCol }); + dataGv.Dock = DockStyle.Fill; + dataGv.Location = new Point(3, 3); + dataGv.Name = "dataGv"; + dataGv.Size = new Size(1012, 647); + dataGv.TabIndex = 0; + dataGv.CellDoubleClick += dataGv_CellDoubleClick; + // + // gridViewPagination + // + gridViewPagination.AutoSizeMode = AutoSizeMode.GrowAndShrink; + gridViewPagination.CurrentPage = 0; + gridViewPagination.Dock = DockStyle.Fill; + gridViewPagination.Limit = 20; + gridViewPagination.Location = new Point(0, 653); + gridViewPagination.Margin = new Padding(0); + gridViewPagination.Name = "gridViewPagination"; + gridViewPagination.Page = 0; + gridViewPagination.Size = new Size(1018, 30); + gridViewPagination.TabIndex = 999; + gridViewPagination.Total = 0; + // + // bottomPanel + // + bottomPanel.AutoSize = true; + bottomPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + bottomPanel.ColumnCount = 2; + bottomPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F)); + bottomPanel.ColumnStyles.Add(new ColumnStyle()); + bottomPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 20F)); + bottomPanel.Controls.Add(operationPanel, 0, 0); + bottomPanel.Controls.Add(dialogPanel, 2, 1); + bottomPanel.Dock = DockStyle.Fill; + bottomPanel.Location = new Point(3, 729); + bottomPanel.Name = "bottomPanel"; + bottomPanel.RowCount = 2; + bottomPanel.RowStyles.Add(new RowStyle()); + bottomPanel.RowStyles.Add(new RowStyle()); + bottomPanel.Size = new Size(1018, 68); + bottomPanel.TabIndex = 999; + // + // operationPanel + // + operationPanel.AutoSize = true; + operationPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + operationPanel.ColumnCount = 3; + operationPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F)); + operationPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 101F)); + operationPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F)); + operationPanel.Controls.Add(viewBut, 0, 0); + operationPanel.Controls.Add(amendBut, 1, 0); + operationPanel.Controls.Add(deleteBut, 2, 0); + operationPanel.Location = new Point(0, 0); + operationPanel.Margin = new Padding(0); + operationPanel.Name = "operationPanel"; + operationPanel.RowCount = 1; + operationPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 50F)); + operationPanel.Size = new Size(293, 31); + operationPanel.TabIndex = 0; + // + // viewBut + // + viewBut.Location = new Point(3, 3); + viewBut.Name = "viewBut"; + viewBut.Size = new Size(90, 25); + viewBut.TabIndex = 0; + viewBut.Values.Image = Properties.Resources.view_16; + viewBut.Values.Text = "查看(&V)"; + viewBut.Click += viewBut_Click; + // + // amendBut + // + amendBut.Location = new Point(99, 3); + amendBut.Name = "amendBut"; + amendBut.Size = new Size(90, 25); + amendBut.TabIndex = 0; + amendBut.Values.Image = Properties.Resources.amend_16; + amendBut.Values.Text = "修改(&A)"; + amendBut.Click += amendBut_Click; + // + // deleteBut + // + deleteBut.Location = new Point(200, 3); + deleteBut.Name = "deleteBut"; + deleteBut.Size = new Size(90, 25); + deleteBut.TabIndex = 0; + deleteBut.Values.Image = Properties.Resources.delete_16; + deleteBut.Values.Text = "删除(&D)"; + deleteBut.Click += deleteBut_Click; + // + // dialogPanel + // + dialogPanel.AutoSize = true; + dialogPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + dialogPanel.ColumnCount = 2; + dialogPanel.ColumnStyles.Add(new ColumnStyle()); + dialogPanel.ColumnStyles.Add(new ColumnStyle()); + dialogPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 20F)); + dialogPanel.Controls.Add(okBut, 0, 0); + dialogPanel.Controls.Add(cancelBut, 1, 0); + dialogPanel.Dock = DockStyle.Fill; + dialogPanel.Location = new Point(823, 34); + dialogPanel.Name = "dialogPanel"; + dialogPanel.RowCount = 1; + dialogPanel.RowStyles.Add(new RowStyle()); + dialogPanel.Size = new Size(192, 31); + dialogPanel.TabIndex = 1; + // + // okBut + // + okBut.Location = new Point(3, 3); + okBut.Name = "okBut"; + okBut.Size = new Size(90, 25); + okBut.TabIndex = 0; + okBut.Values.Image = Properties.Resources.ok_16; + okBut.Values.Text = "确定(&O)"; + okBut.Click += okBut_Click; + // + // cancelBut + // + cancelBut.Location = new Point(99, 3); + cancelBut.Name = "cancelBut"; + cancelBut.Size = new Size(90, 25); + cancelBut.TabIndex = 0; + cancelBut.Values.Image = Properties.Resources.close_16; + cancelBut.Values.Text = "取消(&C)"; + cancelBut.Click += cancelBut_Click; + // + // permissionNameCol + // + permissionNameCol.DataPropertyName = "PermissionName"; + permissionNameCol.DefaultCellStyle = dataGridViewCellStyle9; + permissionNameCol.HeaderText = "权限名"; + permissionNameCol.Name = "permissionNameCol"; + permissionNameCol.Width = 200; + // + // dependentCol + // + dependentCol.DataPropertyName = "Dependent"; + dependentCol.DefaultCellStyle = dataGridViewCellStyle10; + dependentCol.HeaderText = "扩展名"; + dependentCol.Name = "dependentCol"; + dependentCol.Width = 200; + // + // dependentDetailNameCol + // + dependentDetailNameCol.DataPropertyName = "DependentDetailName"; + dependentDetailNameCol.DefaultCellStyle = dataGridViewCellStyle11; + dependentDetailNameCol.HeaderText = "扩展子项目名"; + dependentDetailNameCol.Name = "dependentDetailNameCol"; + dependentDetailNameCol.Width = 300; + // + // descriptionCol + // + descriptionCol.DataPropertyName = "DependentDetailDescription"; + descriptionCol.DefaultCellStyle = dataGridViewCellStyle12; + descriptionCol.HeaderText = "扩展子项目中文"; + descriptionCol.Name = "descriptionCol"; + descriptionCol.Resizable = DataGridViewTriState.True; + descriptionCol.Width = 260; + // + // dependentLabel + // + dependentLabel.Location = new Point(294, 3); + dependentLabel.Margin = new Padding(30, 3, 3, 3); + dependentLabel.Name = "dependentLabel"; + dependentLabel.Size = new Size(52, 20); + dependentLabel.TabIndex = 999; + dependentLabel.Values.Text = "扩展名:"; + // + // dependentTxt + // + dependentTxt.Location = new Point(352, 3); + dependentTxt.Name = "dependentTxt"; + dependentTxt.Size = new Size(194, 23); + dependentTxt.TabIndex = 1; + // + // SecurityPermissionDependentEnquiryPage + // + AutoScaleDimensions = new SizeF(7F, 15F); + AutoScaleMode = AutoScaleMode.Font; + Controls.Add(mainPanel); + Name = "SecurityPermissionDependentEnquiryPage"; + mainPanel.ResumeLayout(false); + mainPanel.PerformLayout(); + topPanel.ResumeLayout(false); + topPanel.PerformLayout(); + searchPanel.ResumeLayout(false); + contextPanel.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)dataGv).EndInit(); + bottomPanel.ResumeLayout(false); + bottomPanel.PerformLayout(); + operationPanel.ResumeLayout(false); + dialogPanel.ResumeLayout(false); + ResumeLayout(false); + } + + #endregion + + private TableLayoutPanel mainPanel; + private TableLayoutPanel topPanel; + private TableLayoutPanel searchPanel; + private Krypton.Toolkit.KryptonButton searchBut; + private Krypton.Toolkit.KryptonButton resetBut; + private Krypton.Toolkit.KryptonButton createBut; + private TableLayoutPanel contextPanel; + private TableLayoutPanel bottomPanel; + private TableLayoutPanel operationPanel; + private Krypton.Toolkit.KryptonButton viewBut; + private Krypton.Toolkit.KryptonButton amendBut; + private Krypton.Toolkit.KryptonButton deleteBut; + private Krypton.Toolkit.KryptonLabel searchPermissionNameLabel; + private Krypton.Toolkit.KryptonTextBox permissionNameTxt; + private Krypton.Toolkit.KryptonDataGridView dataGv; + private TableLayoutPanel dialogPanel; + private Krypton.Toolkit.KryptonButton okBut; + private Krypton.Toolkit.KryptonButton cancelBut; + private CloudBuilder.Gui.GridViewPagination gridViewPagination; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn permissionNameCol; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn dependentCol; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn dependentDetailNameCol; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn descriptionCol; + private Krypton.Toolkit.KryptonLabel dependentLabel; + private Krypton.Toolkit.KryptonTextBox dependentTxt; + } +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Security.Gui/SecurityPermissionDependentEnquiryPage.cs b/CloudBuilder/CloudBuilder.Security.Gui/SecurityPermissionDependentEnquiryPage.cs new file mode 100644 index 0000000..639ea0b --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/SecurityPermissionDependentEnquiryPage.cs @@ -0,0 +1,438 @@ +using ClosedXML.Excel; +using CloudBuilder.Core.DependencyInjection.Form; +using CloudBuilder.Core.Report; +using CloudBuilder.Core.Service; +using CloudBuilder.Gui; +using CloudBuilder.Gui.DependencyInjection; +using CloudBuilder.Request.Security; +using CloudBuilder.Security.Data; +using CloudBuilder.Security.Entity; +using CloudBuilder.Security.Linkup; +using CloudBuilder.Security.Policy; +using CloudBuilder.Security.SearchCriteria; +using DocumentFormat.OpenXml.Spreadsheet; +using Krypton.Toolkit; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http.Extensions; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.IdentityModel.Tokens; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + + +namespace CloudBuilder.Security.Gui +{ + public partial class SecurityPermissionDependentEnquiryPage : AbstractPage + { + private SecurityPermissionDependentEntity[] securityPermissions = null!; + private SecurityPermissionSearchCriteria searchCriteria = null!; + private BindingContextAttributeProvider provider; + private SecurityPermissionRequest securityPermissionRequest; + private SecurityMessagePolicy securityMessagePolicy; + + //初始化Page,注入容器内,不要在此做任何事情 + public SecurityPermissionDependentEnquiryPage() + { + InitializeComponent(); + } + + /// + /// 第一次加载时执行,只执行一次 + /// + public override void FunctionLoaded() + { + try + { + base.FunctionLoaded(); + //初始化容器------------------------------------- + securityPermissionRequest = ServiceHelper.GetTypeService(); + securityMessagePolicy = ServiceHelper.GetTypeService()!; + + //界面初始化 + InitGui(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + /// + /// 弹出界面调用,发生在FunctionLoaded()之后 + /// + public override void InitInputData(object param, GuiDisplayMode mode) + { + base.InitInputData(param, mode); + if (param == null) return; + + SecurityPermissionSearchCriteria criteria = param as SecurityPermissionSearchCriteria; + permissionNameTxt.Text = criteria.PermissionName; + dependentTxt.Text = criteria.Dependent; + + if (criteria.DependentEnable != null && criteria.DependentEnable == false) guiOperateHelper.EnableControls(false, permissionNameTxt, dependentTxt); + + Search(); + } + /// + /// 每次从别的界面进入时执行,不包括下面的界面切换,发生在FunctionLoaded之后 + /// 这个是有参数传入,常用于查询界面进入到操作界面发生 + /// + /// + public override void FunctionActivated(object param) + { + base.FunctionActivated(param); + permissionNameTxt.Focus(); + } + /// + /// 当Page被选中时执行,用于Tab导航的切换,没有参数变化,跟FunctionActivated有区别 + /// + public override void FunctionSelected() + { + this.ParentAbstractForm.AcceptButton = this.searchBut; + if (!IsDialog) + this.ParentAbstractForm.CancelButton = this.resetBut; + else + this.ParentAbstractForm.CancelButton = this.cancelBut; + + permissionNameTxt.Focus(); + } + /// + /// 控件的初始化 + /// + private void InitGui() + { + //DataGridView初始化不要自动生成列,且允许重排列名操作 + dataGv.InitColumn(true, true); + //初始化绑定设置 + InitBindingContext(); + //设置显示模式 + SetDisplayMode(true); + + InitGridViewPagination(); + } + /// + /// DataGridView分页控件初始化 + /// + private void InitGridViewPagination() + { + searchCriteria = new SecurityPermissionSearchCriteria(); + gridViewPagination.SetLimit(searchCriteria.limit); + gridViewPagination.OnPaginationChanged += Search; + gridViewPagination.OnPrint += Print; + } + + /// + /// 打印当前查询结果 + /// + private void Print() + { + //設置查詢條件 + List searCriteria = new List(); + if (!string.IsNullOrEmpty(permissionNameTxt.Text)) + searCriteria.Add(searchPermissionNameLabel.Text + permissionNameTxt.Text); + + //設置每列的格式 + TemplateHeader[] headers = dataGv.GetTemplateHeaders(); + + //打印Excel + new DataToExcelHelper(null).PrintExcel(this.Parent.Text, this.Parent.Text, searCriteria, headers, securityPermissions); + } + + /// + /// 有特殊要求的UI控件初始化设置,使用guiOperateHelper管理 + /// + private void InitBindingContext() + { + InitPermission(); + + guiOperateHelper = new GuiOperateHelper(); + } + + private void InitPermission() + { + viewBut.Set(SecurityPermissionPolicy.SecurityPermission, Operate.Find); + createBut.Set(SecurityPermissionPolicy.SecurityPermission, Operate.Insert); + amendBut.Set(SecurityPermissionPolicy.SecurityPermission, Operate.Update); + deleteBut.Set(SecurityPermissionPolicy.SecurityPermission, Operate.Delete); + } + + private void SetDisplayMode(bool enable) + { + guiOperateHelper.EnableControls(true, this.searchPanel, this.bottomPanel); + guiOperateHelper.EnableControls(false, dataGv); + + if (securityPermissions != null) + guiOperateHelper.EnableControls(enable, viewBut, amendBut, deleteBut); + else + guiOperateHelper.EnableControls(false, viewBut, amendBut, deleteBut); + + //如果是弹出的窗口,不显示 + createBut.Visible = !IsDialog; + dialogPanel.Visible = IsDialog; + operationPanel.Visible = !IsDialog; + + this.permissionNameTxt.Focus(); + } + + private void searchBut_Click(object sender, EventArgs e) + { + try + { + Search(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + /// + /// 与Web同步写法 + /// + /// + private SecurityPermissionSearchCriteria PackSearchCriteria() + { + searchCriteria = new SecurityPermissionSearchCriteria(); + searchCriteria.limit = gridViewPagination.Limit; + searchCriteria.page = gridViewPagination.CurrentPage; + + List filters = new List(); + + SearchFilter filter = new SearchFilter(); + filter.Column = SecurityPermissionDependentEntity.DB_PERMISSION_NAME; + filter.Type = SearchFilterTypePolicy.TEXT; + filter.Operator = SearchFilterOperatorPolicy.SINGLE; + filter.Value = permissionNameTxt.GetValue(); + filters.Add(filter); + + filter = new SearchFilter(); + filter.Column = SecurityPermissionDependentEntity.DB_DEPENDENT; + filter.Type = SearchFilterTypePolicy.TEXT; + filter.Operator = SearchFilterOperatorPolicy.SINGLE; + filter.Value = dependentTxt.GetValue(); + filters.Add(filter); + + searchCriteria.Filter = filters.ToArray(); + + return searchCriteria; + } + + private void Search() + { + try + { + var data = securityPermissionRequest.FindDependentBySearchCriteria(PackSearchCriteria()); + + if (data != null) securityPermissions = data.Dependents; + + gridViewPagination.SetTotal(data.Total); + + if (securityPermissions == null || securityPermissions.Length == 0) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + guiOperateHelper.ResetControls(this.dataGv); + return; + } + + dataGv.SetDataSource(securityPermissions); + + SetDisplayMode(true); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void resetBut_Click(object sender, EventArgs e) + { + guiOperateHelper.ResetControls(this.mainPanel); + //Reset时默认会设置limit为AbstractSearchCriteria.limit,如果不同时,需要重新设置 + gridViewPagination.SetLimit(searchCriteria.limit); + SetDisplayMode(false); + } + + private void createBut_Click(object sender, EventArgs e) + { + DisplayPage(GuiDisplayMode.Create, null); + } + + private void DisplayPage(GuiDisplayMode mode, string permissionName) + { + SecurityPermissionOperationLinkup linkupData = new SecurityPermissionOperationLinkup(); + linkupData.DisplayMode = Convert.ToInt32(mode); + linkupData.PermissionName = permissionName; + + this.DisplayAbstractPage(typeof(SecurityPermissionOperationPage).Name, linkupData); + } + + + private void viewBut_Click(object sender, EventArgs e) + { + if (dataGv.RowCount <= 0 || dataGv.SelectedCells.Count <= 0) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + return; + } + + SecurityPermissionDependentEntity data = dataGv.GetRowData(dataGv.SelectedCells[0].RowIndex); + + DisplayPage(GuiDisplayMode.View, data.PermissionName); + } + + private void amendBut_Click(object sender, EventArgs e) + { + if (dataGv.RowCount <= 0 || dataGv.SelectedCells.Count <= 0) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + return; + } + + SecurityPermissionDependentEntity data = dataGv.GetRowData(dataGv.SelectedCells[0].RowIndex); + + DisplayPage(GuiDisplayMode.Amend, data.PermissionName); + } + + private void deleteBut_Click(object sender, EventArgs e) + { + try + { + Delete(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void Delete() + { + if (dataGv.RowCount <= 0 || dataGv.SelectedCells.Count <= 0) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + return; + } + + if (DialogResult.Yes != ShowMessageBox.ShowOption(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_CONFIRM_DEL_NULL), securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_DELETE))) return; + + SecurityPermissionDependentEntity[] datas = dataGv.GetSelectedCellsData(); + + securityPermissionRequest.Deletes(datas.Select(x => x.PermissionName).ToArray()); + + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_SUCCEED_DELETED_NULL)); + + Search(); + } + + private void okBut_Click(object sender, EventArgs e) + { + try + { + if (dataGv.RowCount <= 0 || dataGv.SelectedCells.Count <= 0) return; + SecurityPermissionDependentEntity[] datas = dataGv.GetSelectedCellsData(); + + this.ParentAbstractForm.OutputData = datas; + this.ParentAbstractForm.DialogResult = DialogResult.OK; + this.ParentAbstractForm.Close(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void cancelBut_Click(object sender, EventArgs e) + { + try + { + this.ParentAbstractForm.DialogResult = DialogResult.Cancel; + this.ParentAbstractForm.Close(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void dataGv_CellDoubleClick(object sender, DataGridViewCellEventArgs e) + { + try + { + if (IsDialog) + okBut_Click(null, null); + else + viewBut_Click(null, null); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + } +} diff --git a/CloudBuilder/CloudBuilder.Security.Gui/SecurityPermissionDependentEnquiryPage.resx b/CloudBuilder/CloudBuilder.Security.Gui/SecurityPermissionDependentEnquiryPage.resx new file mode 100644 index 0000000..01338d6 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/SecurityPermissionDependentEnquiryPage.resx @@ -0,0 +1,156 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Security.Gui/SecurityPermissionEnquiryPage.Designer.cs b/CloudBuilder/CloudBuilder.Security.Gui/SecurityPermissionEnquiryPage.Designer.cs new file mode 100644 index 0000000..4b39c30 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/SecurityPermissionEnquiryPage.Designer.cs @@ -0,0 +1,401 @@ +namespace CloudBuilder.Security.Gui +{ + partial class SecurityPermissionEnquiryPage + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + DataGridViewCellStyle dataGridViewCellStyle9 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle10 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle11 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle12 = new DataGridViewCellStyle(); + mainPanel = new TableLayoutPanel(); + topPanel = new TableLayoutPanel(); + searchPermissionNameLabel = new Krypton.Toolkit.KryptonLabel(); + permissionNameTxt = new Krypton.Toolkit.KryptonTextBox(); + searchPanel = new TableLayoutPanel(); + searchBut = new Krypton.Toolkit.KryptonButton(); + resetBut = new Krypton.Toolkit.KryptonButton(); + createBut = new Krypton.Toolkit.KryptonButton(); + contextPanel = new TableLayoutPanel(); + dataGv = new Krypton.Toolkit.KryptonDataGridView(); + permissionNameCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + dependentCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + descriptionCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + delegateIndcCol = new Krypton.Toolkit.KryptonDataGridViewCheckBoxColumn(); + gridViewPagination = new CloudBuilder.Gui.GridViewPagination(); + bottomPanel = new TableLayoutPanel(); + operationPanel = new TableLayoutPanel(); + viewBut = new Krypton.Toolkit.KryptonButton(); + amendBut = new Krypton.Toolkit.KryptonButton(); + deleteBut = new Krypton.Toolkit.KryptonButton(); + dialogPanel = new TableLayoutPanel(); + okBut = new Krypton.Toolkit.KryptonButton(); + cancelBut = new Krypton.Toolkit.KryptonButton(); + mainPanel.SuspendLayout(); + topPanel.SuspendLayout(); + searchPanel.SuspendLayout(); + contextPanel.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)dataGv).BeginInit(); + bottomPanel.SuspendLayout(); + operationPanel.SuspendLayout(); + dialogPanel.SuspendLayout(); + SuspendLayout(); + // + // mainPanel + // + mainPanel.ColumnCount = 1; + mainPanel.ColumnStyles.Add(new ColumnStyle()); + mainPanel.Controls.Add(topPanel, 0, 0); + mainPanel.Controls.Add(contextPanel, 0, 1); + mainPanel.Controls.Add(bottomPanel, 0, 2); + mainPanel.Dock = DockStyle.Fill; + mainPanel.Location = new Point(0, 0); + mainPanel.Name = "mainPanel"; + mainPanel.RowCount = 3; + mainPanel.RowStyles.Add(new RowStyle()); + mainPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 100F)); + mainPanel.RowStyles.Add(new RowStyle()); + mainPanel.Size = new Size(1024, 800); + mainPanel.TabIndex = 0; + // + // topPanel + // + topPanel.AutoSize = true; + topPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + topPanel.ColumnCount = 5; + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.Controls.Add(searchPermissionNameLabel, 0, 0); + topPanel.Controls.Add(permissionNameTxt, 1, 0); + topPanel.Controls.Add(searchPanel, 4, 0); + topPanel.Dock = DockStyle.Fill; + topPanel.Location = new Point(3, 3); + topPanel.Name = "topPanel"; + topPanel.RowCount = 1; + topPanel.RowStyles.Add(new RowStyle()); + topPanel.Size = new Size(1018, 31); + topPanel.TabIndex = 0; + // + // searchPermissionNameLabel + // + searchPermissionNameLabel.Location = new Point(3, 3); + searchPermissionNameLabel.Name = "searchPermissionNameLabel"; + searchPermissionNameLabel.Size = new Size(52, 20); + searchPermissionNameLabel.TabIndex = 999; + searchPermissionNameLabel.Values.Text = "权限名:"; + // + // permissionNameTxt + // + permissionNameTxt.Location = new Point(61, 3); + permissionNameTxt.Name = "permissionNameTxt"; + permissionNameTxt.Size = new Size(200, 23); + permissionNameTxt.TabIndex = 0; + // + // searchPanel + // + searchPanel.AutoSize = true; + searchPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + searchPanel.ColumnCount = 3; + searchPanel.ColumnStyles.Add(new ColumnStyle()); + searchPanel.ColumnStyles.Add(new ColumnStyle()); + searchPanel.ColumnStyles.Add(new ColumnStyle()); + searchPanel.Controls.Add(searchBut, 0, 0); + searchPanel.Controls.Add(resetBut, 1, 0); + searchPanel.Controls.Add(createBut, 2, 0); + searchPanel.Location = new Point(324, 0); + searchPanel.Margin = new Padding(60, 0, 0, 0); + searchPanel.Name = "searchPanel"; + searchPanel.RowCount = 1; + searchPanel.RowStyles.Add(new RowStyle()); + searchPanel.Size = new Size(288, 31); + searchPanel.TabIndex = 999; + // + // searchBut + // + searchBut.Location = new Point(3, 3); + searchBut.Name = "searchBut"; + searchBut.Size = new Size(90, 25); + searchBut.TabIndex = 0; + searchBut.Values.Image = Properties.Resources.search_16; + searchBut.Values.Text = "查询(&S)"; + searchBut.Click += searchBut_Click; + // + // resetBut + // + resetBut.Location = new Point(99, 3); + resetBut.Name = "resetBut"; + resetBut.Size = new Size(90, 25); + resetBut.TabIndex = 0; + resetBut.Values.Image = Properties.Resources.reset_16; + resetBut.Values.Text = "重置(&R)"; + resetBut.Click += resetBut_Click; + // + // createBut + // + createBut.Location = new Point(195, 3); + createBut.Name = "createBut"; + createBut.Size = new Size(90, 25); + createBut.TabIndex = 0; + createBut.Values.Image = Properties.Resources.create_16; + createBut.Values.Text = "新增(&C)"; + createBut.Click += createBut_Click; + // + // contextPanel + // + contextPanel.ColumnCount = 1; + contextPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F)); + contextPanel.Controls.Add(dataGv, 0, 0); + contextPanel.Controls.Add(gridViewPagination, 0, 1); + contextPanel.Dock = DockStyle.Fill; + contextPanel.Location = new Point(3, 40); + contextPanel.Name = "contextPanel"; + contextPanel.RowCount = 2; + contextPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 50F)); + contextPanel.RowStyles.Add(new RowStyle()); + contextPanel.Size = new Size(1018, 683); + contextPanel.TabIndex = 999; + // + // dataGv + // + dataGv.AllowUserToAddRows = false; + dataGv.AllowUserToDeleteRows = false; + dataGv.BorderStyle = BorderStyle.None; + dataGv.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize; + dataGv.Columns.AddRange(new DataGridViewColumn[] { permissionNameCol, dependentCol, descriptionCol, delegateIndcCol }); + dataGv.Dock = DockStyle.Fill; + dataGv.Location = new Point(3, 3); + dataGv.Name = "dataGv"; + dataGv.Size = new Size(1012, 647); + dataGv.TabIndex = 0; + dataGv.CellDoubleClick += dataGv_CellDoubleClick; + // + // permissionNameCol + // + permissionNameCol.DataPropertyName = "PermissionName"; + permissionNameCol.DefaultCellStyle = dataGridViewCellStyle9; + permissionNameCol.HeaderText = "权限名"; + permissionNameCol.Name = "permissionNameCol"; + permissionNameCol.Width = 260; + // + // dependentCol + // + dependentCol.DataPropertyName = "Dependent"; + dependentCol.DefaultCellStyle = dataGridViewCellStyle10; + dependentCol.HeaderText = "扩展名"; + dependentCol.Name = "dependentCol"; + dependentCol.Width = 260; + // + // descriptionCol + // + descriptionCol.DataPropertyName = "Description"; + descriptionCol.DefaultCellStyle = dataGridViewCellStyle11; + descriptionCol.HeaderText = "描述"; + descriptionCol.Name = "descriptionCol"; + descriptionCol.Resizable = DataGridViewTriState.True; + descriptionCol.Width = 260; + // + // delegateIndcCol + // + dataGridViewCellStyle12.Alignment = DataGridViewContentAlignment.MiddleCenter; + dataGridViewCellStyle12.NullValue = false; + delegateIndcCol.DefaultCellStyle = dataGridViewCellStyle12; + delegateIndcCol.FalseValue = "N"; + delegateIndcCol.HeaderText = "能否代理?"; + delegateIndcCol.IndeterminateValue = null; + delegateIndcCol.Name = "delegateIndcCol"; + delegateIndcCol.TrueValue = "Y"; + // + // gridViewPagination + // + gridViewPagination.AutoSizeMode = AutoSizeMode.GrowAndShrink; + gridViewPagination.CurrentPage = 0; + gridViewPagination.Dock = DockStyle.Fill; + gridViewPagination.Limit = 20; + gridViewPagination.Location = new Point(0, 653); + gridViewPagination.Margin = new Padding(0); + gridViewPagination.Name = "gridViewPagination"; + gridViewPagination.Page = 0; + gridViewPagination.Size = new Size(1018, 30); + gridViewPagination.TabIndex = 999; + gridViewPagination.Total = 0; + // + // bottomPanel + // + bottomPanel.AutoSize = true; + bottomPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + bottomPanel.ColumnCount = 2; + bottomPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F)); + bottomPanel.ColumnStyles.Add(new ColumnStyle()); + bottomPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 20F)); + bottomPanel.Controls.Add(operationPanel, 0, 0); + bottomPanel.Controls.Add(dialogPanel, 2, 1); + bottomPanel.Dock = DockStyle.Fill; + bottomPanel.Location = new Point(3, 729); + bottomPanel.Name = "bottomPanel"; + bottomPanel.RowCount = 2; + bottomPanel.RowStyles.Add(new RowStyle()); + bottomPanel.RowStyles.Add(new RowStyle()); + bottomPanel.Size = new Size(1018, 68); + bottomPanel.TabIndex = 999; + // + // operationPanel + // + operationPanel.AutoSize = true; + operationPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + operationPanel.ColumnCount = 3; + operationPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F)); + operationPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 101F)); + operationPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F)); + operationPanel.Controls.Add(viewBut, 0, 0); + operationPanel.Controls.Add(amendBut, 1, 0); + operationPanel.Controls.Add(deleteBut, 2, 0); + operationPanel.Location = new Point(0, 0); + operationPanel.Margin = new Padding(0); + operationPanel.Name = "operationPanel"; + operationPanel.RowCount = 1; + operationPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 50F)); + operationPanel.Size = new Size(293, 31); + operationPanel.TabIndex = 0; + // + // viewBut + // + viewBut.Location = new Point(3, 3); + viewBut.Name = "viewBut"; + viewBut.Size = new Size(90, 25); + viewBut.TabIndex = 0; + viewBut.Values.Image = Properties.Resources.view_16; + viewBut.Values.Text = "查看(&V)"; + viewBut.Click += viewBut_Click; + // + // amendBut + // + amendBut.Location = new Point(99, 3); + amendBut.Name = "amendBut"; + amendBut.Size = new Size(90, 25); + amendBut.TabIndex = 0; + amendBut.Values.Image = Properties.Resources.amend_16; + amendBut.Values.Text = "修改(&A)"; + amendBut.Click += amendBut_Click; + // + // deleteBut + // + deleteBut.Location = new Point(200, 3); + deleteBut.Name = "deleteBut"; + deleteBut.Size = new Size(90, 25); + deleteBut.TabIndex = 0; + deleteBut.Values.Image = Properties.Resources.delete_16; + deleteBut.Values.Text = "删除(&D)"; + deleteBut.Click += deleteBut_Click; + // + // dialogPanel + // + dialogPanel.AutoSize = true; + dialogPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + dialogPanel.ColumnCount = 2; + dialogPanel.ColumnStyles.Add(new ColumnStyle()); + dialogPanel.ColumnStyles.Add(new ColumnStyle()); + dialogPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 20F)); + dialogPanel.Controls.Add(okBut, 0, 0); + dialogPanel.Controls.Add(cancelBut, 1, 0); + dialogPanel.Dock = DockStyle.Fill; + dialogPanel.Location = new Point(823, 34); + dialogPanel.Name = "dialogPanel"; + dialogPanel.RowCount = 1; + dialogPanel.RowStyles.Add(new RowStyle()); + dialogPanel.Size = new Size(192, 31); + dialogPanel.TabIndex = 1; + // + // okBut + // + okBut.Location = new Point(3, 3); + okBut.Name = "okBut"; + okBut.Size = new Size(90, 25); + okBut.TabIndex = 0; + okBut.Values.Image = Properties.Resources.ok_16; + okBut.Values.Text = "确定(&O)"; + okBut.Click += okBut_Click; + // + // cancelBut + // + cancelBut.Location = new Point(99, 3); + cancelBut.Name = "cancelBut"; + cancelBut.Size = new Size(90, 25); + cancelBut.TabIndex = 0; + cancelBut.Values.Image = Properties.Resources.close_16; + cancelBut.Values.Text = "取消(&C)"; + cancelBut.Click += cancelBut_Click; + // + // SecurityPermissionEnquiryPage + // + AutoScaleDimensions = new SizeF(7F, 15F); + AutoScaleMode = AutoScaleMode.Font; + Controls.Add(mainPanel); + Name = "SecurityPermissionEnquiryPage"; + mainPanel.ResumeLayout(false); + mainPanel.PerformLayout(); + topPanel.ResumeLayout(false); + topPanel.PerformLayout(); + searchPanel.ResumeLayout(false); + contextPanel.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)dataGv).EndInit(); + bottomPanel.ResumeLayout(false); + bottomPanel.PerformLayout(); + operationPanel.ResumeLayout(false); + dialogPanel.ResumeLayout(false); + ResumeLayout(false); + } + + #endregion + + private TableLayoutPanel mainPanel; + private TableLayoutPanel topPanel; + private TableLayoutPanel searchPanel; + private Krypton.Toolkit.KryptonButton searchBut; + private Krypton.Toolkit.KryptonButton resetBut; + private Krypton.Toolkit.KryptonButton createBut; + private TableLayoutPanel contextPanel; + private TableLayoutPanel bottomPanel; + private TableLayoutPanel operationPanel; + private Krypton.Toolkit.KryptonButton viewBut; + private Krypton.Toolkit.KryptonButton amendBut; + private Krypton.Toolkit.KryptonButton deleteBut; + private Krypton.Toolkit.KryptonLabel searchPermissionNameLabel; + private Krypton.Toolkit.KryptonTextBox permissionNameTxt; + private Krypton.Toolkit.KryptonDataGridView dataGv; + private TableLayoutPanel dialogPanel; + private Krypton.Toolkit.KryptonButton okBut; + private Krypton.Toolkit.KryptonButton cancelBut; + private CloudBuilder.Gui.GridViewPagination gridViewPagination; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn permissionNameCol; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn dependentCol; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn descriptionCol; + private Krypton.Toolkit.KryptonDataGridViewCheckBoxColumn delegateIndcCol; + } +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Security.Gui/SecurityPermissionEnquiryPage.cs b/CloudBuilder/CloudBuilder.Security.Gui/SecurityPermissionEnquiryPage.cs new file mode 100644 index 0000000..285d283 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/SecurityPermissionEnquiryPage.cs @@ -0,0 +1,416 @@ +using ClosedXML.Excel; +using CloudBuilder.Core.DependencyInjection.Form; +using CloudBuilder.Core.Report; +using CloudBuilder.Core.Service; +using CloudBuilder.Gui; +using CloudBuilder.Gui.DependencyInjection; +using CloudBuilder.Request.Security; +using CloudBuilder.Security.Data; +using CloudBuilder.Security.Entity; +using CloudBuilder.Security.Linkup; +using CloudBuilder.Security.Policy; +using CloudBuilder.Security.SearchCriteria; +using DocumentFormat.OpenXml.Spreadsheet; +using Krypton.Toolkit; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http.Extensions; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.IdentityModel.Tokens; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + + +namespace CloudBuilder.Security.Gui +{ + public partial class SecurityPermissionEnquiryPage : AbstractPage + { + private SecurityPermissionEntity[] securityPermissions = null!; + private SecurityPermissionSearchCriteria searchCriteria = null!; + private BindingContextAttributeProvider provider; + private SecurityPermissionRequest securityPermissionRequest; + private SecurityMessagePolicy securityMessagePolicy; + + //初始化Page,注入容器内,不要在此做任何事情 + public SecurityPermissionEnquiryPage() + { + InitializeComponent(); + } + + /// + /// 第一次加载时执行,只执行一次 + /// + public override void FunctionLoaded() + { + try + { + base.FunctionLoaded(); + //初始化容器------------------------------------- + securityPermissionRequest = ServiceHelper.GetTypeService(); + securityMessagePolicy = ServiceHelper.GetTypeService()!; + + //界面初始化 + InitGui(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + /// + /// 每次从别的界面进入时执行,不包括下面的界面切换,发生在FunctionLoaded之后 + /// 这个是有参数传入,常用于查询界面进入到操作界面发生 + /// + /// + public override void FunctionActivated(object param) + { + base.FunctionActivated(param); + permissionNameTxt.Focus(); + } + /// + /// 当Page被选中时执行,用于Tab导航的切换,没有参数变化,跟FunctionActivated有区别 + /// + public override void FunctionSelected() + { + this.ParentAbstractForm.AcceptButton = this.searchBut; + if (!IsDialog) + this.ParentAbstractForm.CancelButton = this.resetBut; + else + this.ParentAbstractForm.CancelButton = this.cancelBut; + + permissionNameTxt.Focus(); + } + /// + /// 控件的初始化 + /// + private void InitGui() + { + //DataGridView初始化不要自动生成列,且允许重排列名操作 + dataGv.InitColumn(true, true); + //初始化绑定设置 + InitBindingContext(); + //设置显示模式 + SetDisplayMode(true); + + InitGridViewPagination(); + } + /// + /// DataGridView分页控件初始化 + /// + private void InitGridViewPagination() + { + searchCriteria = new SecurityPermissionSearchCriteria(); + gridViewPagination.SetLimit(searchCriteria.limit); + gridViewPagination.OnPaginationChanged += Search; + gridViewPagination.OnPrint += Print; + } + + /// + /// 打印当前查询结果 + /// + private void Print() + { + //設置查詢條件 + List searCriteria = new List(); + if (!string.IsNullOrEmpty(permissionNameTxt.Text)) + searCriteria.Add(searchPermissionNameLabel.Text + permissionNameTxt.Text); + + //設置每列的格式 + TemplateHeader[] headers = dataGv.GetTemplateHeaders(); + + //打印Excel + new DataToExcelHelper(null).PrintExcel(this.Parent.Text, this.Parent.Text, searCriteria, headers, securityPermissions); + } + + /// + /// 有特殊要求的UI控件初始化设置,使用guiOperateHelper管理 + /// + private void InitBindingContext() + { + InitPermission(); + + guiOperateHelper = new GuiOperateHelper(); + } + + private void InitPermission() + { + viewBut.Set(SecurityPermissionPolicy.SecurityPermission, Operate.Find); + createBut.Set(SecurityPermissionPolicy.SecurityPermission, Operate.Insert); + amendBut.Set(SecurityPermissionPolicy.SecurityPermission, Operate.Update); + deleteBut.Set(SecurityPermissionPolicy.SecurityPermission, Operate.Delete); + } + + private void SetDisplayMode(bool enable) + { + guiOperateHelper.EnableControls(true, this.searchPanel, this.bottomPanel); + guiOperateHelper.EnableControls(false, dataGv); + + if (securityPermissions != null) + guiOperateHelper.EnableControls(enable, viewBut, amendBut, deleteBut); + else + guiOperateHelper.EnableControls(false, viewBut, amendBut, deleteBut); + + //如果是弹出的窗口,不显示 + createBut.Visible = !IsDialog; + dialogPanel.Visible = IsDialog; + operationPanel.Visible = !IsDialog; + + this.permissionNameTxt.Focus(); + } + + private void searchBut_Click(object sender, EventArgs e) + { + try + { + Search(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + /// + /// 与Web同步写法 + /// + /// + private SecurityPermissionSearchCriteria PackSearchCriteria() + { + searchCriteria = new SecurityPermissionSearchCriteria(); + searchCriteria.limit = gridViewPagination.Limit; + searchCriteria.page = gridViewPagination.CurrentPage; + + List filters = new List(); + + SearchFilter filter = new SearchFilter(); + filter.Column = SecurityPermissionEntity.DB_PERMISSION_NAME; + filter.Type = SearchFilterTypePolicy.TEXT; + filter.Operator = SearchFilterOperatorPolicy.CONTAIN; + filter.Value = permissionNameTxt.GetValue(); + filters.Add(filter); + + searchCriteria.Filter = filters.ToArray(); + + return searchCriteria; + } + + private void Search() + { + try + { + var data = securityPermissionRequest.FindBySearchCriteria(PackSearchCriteria()); + + if (data != null) securityPermissions = data.Permissions; + + gridViewPagination.SetTotal(data.Total); + + if (securityPermissions == null || securityPermissions.Length == 0) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + guiOperateHelper.ResetControls(this.dataGv); + return; + } + + dataGv.SetDataSource(securityPermissions); + + SetDisplayMode(true); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void resetBut_Click(object sender, EventArgs e) + { + guiOperateHelper.ResetControls(this.mainPanel); + //Reset时默认会设置limit为AbstractSearchCriteria.limit,如果不同时,需要重新设置 + gridViewPagination.SetLimit(searchCriteria.limit); + SetDisplayMode(false); + } + + private void createBut_Click(object sender, EventArgs e) + { + DisplayPage(GuiDisplayMode.Create, null); + } + + private void DisplayPage(GuiDisplayMode mode, string permissionName) + { + SecurityPermissionOperationLinkup linkupData = new SecurityPermissionOperationLinkup(); + linkupData.DisplayMode = Convert.ToInt32(mode); + linkupData.PermissionName = permissionName; + + this.DisplayAbstractPage(typeof(SecurityPermissionOperationPage).Name, linkupData); + } + + + private void viewBut_Click(object sender, EventArgs e) + { + if (dataGv.RowCount <= 0 || dataGv.SelectedCells.Count <= 0) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + return; + } + + SecurityPermissionEntity data = dataGv.GetRowData(dataGv.SelectedCells[0].RowIndex); + + DisplayPage(GuiDisplayMode.View, data.PermissionName); + } + + private void amendBut_Click(object sender, EventArgs e) + { + if (dataGv.RowCount <= 0 || dataGv.SelectedCells.Count <= 0) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + return; + } + + SecurityPermissionEntity data = dataGv.GetRowData(dataGv.SelectedCells[0].RowIndex); + + DisplayPage(GuiDisplayMode.Amend, data.PermissionName); + } + + private void deleteBut_Click(object sender, EventArgs e) + { + try + { + Delete(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void Delete() + { + if (dataGv.RowCount <= 0 || dataGv.SelectedCells.Count <= 0) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + return; + } + + if (DialogResult.Yes != ShowMessageBox.ShowOption(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_CONFIRM_DEL_NULL), securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_DELETE))) return; + + SecurityPermissionEntity[] datas = dataGv.GetSelectedCellsData(); + + securityPermissionRequest.Deletes(datas.Select(x => x.PermissionName).ToArray()); + + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_SUCCEED_DELETED_NULL)); + + Search(); + } + + private void okBut_Click(object sender, EventArgs e) + { + try + { + if (dataGv.RowCount <= 0 || dataGv.SelectedCells.Count <= 0) return; + //SecurityPermissionEntity data = dataGv.GetRowData(dataGv.SelectedCells[0].RowIndex); + SecurityPermissionEntity[] datas = dataGv.GetSelectedCellsData(); + + this.ParentAbstractForm.OutputData = datas; + this.ParentAbstractForm.DialogResult = DialogResult.OK; + this.ParentAbstractForm.Close(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void cancelBut_Click(object sender, EventArgs e) + { + try + { + this.ParentAbstractForm.DialogResult = DialogResult.Cancel; + this.ParentAbstractForm.Close(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void dataGv_CellDoubleClick(object sender, DataGridViewCellEventArgs e) + { + try + { + if (IsDialog) + okBut_Click(null, null); + else + viewBut_Click(null, null); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + } +} diff --git a/CloudBuilder/CloudBuilder.Security.Gui/SecurityPermissionEnquiryPage.resx b/CloudBuilder/CloudBuilder.Security.Gui/SecurityPermissionEnquiryPage.resx new file mode 100644 index 0000000..501bafc --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/SecurityPermissionEnquiryPage.resx @@ -0,0 +1,165 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Security.Gui/SecurityPermissionOperationPage.Designer.cs b/CloudBuilder/CloudBuilder.Security.Gui/SecurityPermissionOperationPage.Designer.cs new file mode 100644 index 0000000..b21ca36 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/SecurityPermissionOperationPage.Designer.cs @@ -0,0 +1,580 @@ +namespace CloudBuilder.Security.Gui +{ + partial class SecurityPermissionOperationPage + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + DataGridViewCellStyle dataGridViewCellStyle1 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle2 = new DataGridViewCellStyle(); + contentPanel = new TableLayoutPanel(); + tableLayoutPanel3 = new TableLayoutPanel(); + tableLayoutPanel4 = new TableLayoutPanel(); + tableLayoutPanel1 = new TableLayoutPanel(); + delBut = new Krypton.Toolkit.KryptonButton(); + addBut = new Krypton.Toolkit.KryptonButton(); + kryptonHeader1 = new Krypton.Toolkit.KryptonHeader(); + dataGv = new Krypton.Toolkit.KryptonDataGridView(); + dependentDetailNameCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + dependentDetailDescriptionCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + tableLayoutPanel2 = new TableLayoutPanel(); + permissionNameLabel = new Krypton.Toolkit.KryptonLabel(); + descriptionLabel = new Krypton.Toolkit.KryptonLabel(); + dependentLabel = new Krypton.Toolkit.KryptonLabel(); + delegateIndcChk = new Krypton.Toolkit.KryptonCheckBox(); + permissionNameTxt = new Krypton.Toolkit.KryptonTextBox(); + descriptionTxt = new Krypton.Toolkit.KryptonTextBox(); + dependentTxt = new Krypton.Toolkit.KryptonTextBox(); + kryptonPanel2 = new Krypton.Toolkit.KryptonPanel(); + mainPanel = new TableLayoutPanel(); + topPanel = new TableLayoutPanel(); + searchPanel = new TableLayoutPanel(); + createBut = new Krypton.Toolkit.KryptonButton(); + resetBut = new Krypton.Toolkit.KryptonButton(); + searchBut = new Krypton.Toolkit.KryptonButton(); + permissionNameSearchLabel = new Krypton.Toolkit.KryptonLabel(); + permissionNameSearchTxt = new Krypton.Toolkit.KryptonTextBox(); + permissionNameSearchBut = new Krypton.Toolkit.ButtonSpecAny(); + kryptonPanel1 = new Krypton.Toolkit.KryptonPanel(); + bottomPanel = new TableLayoutPanel(); + savePanel = new TableLayoutPanel(); + cancelBut = new Krypton.Toolkit.KryptonButton(); + saveBut = new Krypton.Toolkit.KryptonButton(); + operationPanel = new TableLayoutPanel(); + deleteBut = new Krypton.Toolkit.KryptonButton(); + amendBut = new Krypton.Toolkit.KryptonButton(); + contentPanel.SuspendLayout(); + tableLayoutPanel3.SuspendLayout(); + tableLayoutPanel4.SuspendLayout(); + tableLayoutPanel1.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)dataGv).BeginInit(); + tableLayoutPanel2.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)kryptonPanel2).BeginInit(); + mainPanel.SuspendLayout(); + topPanel.SuspendLayout(); + searchPanel.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)kryptonPanel1).BeginInit(); + bottomPanel.SuspendLayout(); + savePanel.SuspendLayout(); + operationPanel.SuspendLayout(); + SuspendLayout(); + // + // contentPanel + // + contentPanel.ColumnCount = 1; + contentPanel.ColumnStyles.Add(new ColumnStyle()); + contentPanel.Controls.Add(tableLayoutPanel3, 0, 2); + contentPanel.Controls.Add(tableLayoutPanel2, 0, 0); + contentPanel.Controls.Add(kryptonPanel2, 0, 1); + contentPanel.Dock = DockStyle.Fill; + contentPanel.Location = new Point(3, 51); + contentPanel.Name = "contentPanel"; + contentPanel.RowCount = 3; + contentPanel.RowStyles.Add(new RowStyle()); + contentPanel.RowStyles.Add(new RowStyle()); + contentPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 100F)); + contentPanel.Size = new Size(1018, 672); + contentPanel.TabIndex = 3; + // + // tableLayoutPanel3 + // + tableLayoutPanel3.BackColor = SystemColors.Control; + tableLayoutPanel3.ColumnCount = 1; + tableLayoutPanel3.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel3.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 20F)); + tableLayoutPanel3.Controls.Add(tableLayoutPanel4, 0, 0); + tableLayoutPanel3.Dock = DockStyle.Fill; + tableLayoutPanel3.Location = new Point(3, 133); + tableLayoutPanel3.Name = "tableLayoutPanel3"; + tableLayoutPanel3.RowCount = 1; + tableLayoutPanel3.RowStyles.Add(new RowStyle()); + tableLayoutPanel3.Size = new Size(1018, 536); + tableLayoutPanel3.TabIndex = 2; + // + // tableLayoutPanel4 + // + tableLayoutPanel4.ColumnCount = 1; + tableLayoutPanel4.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F)); + tableLayoutPanel4.Controls.Add(tableLayoutPanel1, 0, 2); + tableLayoutPanel4.Controls.Add(kryptonHeader1, 0, 0); + tableLayoutPanel4.Controls.Add(dataGv, 0, 1); + tableLayoutPanel4.Dock = DockStyle.Fill; + tableLayoutPanel4.Location = new Point(0, 0); + tableLayoutPanel4.Margin = new Padding(0); + tableLayoutPanel4.Name = "tableLayoutPanel4"; + tableLayoutPanel4.RowCount = 3; + tableLayoutPanel4.RowStyles.Add(new RowStyle()); + tableLayoutPanel4.RowStyles.Add(new RowStyle(SizeType.Percent, 50F)); + tableLayoutPanel4.RowStyles.Add(new RowStyle()); + tableLayoutPanel4.Size = new Size(1018, 536); + tableLayoutPanel4.TabIndex = 1; + // + // tableLayoutPanel1 + // + tableLayoutPanel1.AutoSize = true; + tableLayoutPanel1.AutoSizeMode = AutoSizeMode.GrowAndShrink; + tableLayoutPanel1.ColumnCount = 2; + tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel1.Controls.Add(delBut, 1, 0); + tableLayoutPanel1.Controls.Add(addBut, 0, 0); + tableLayoutPanel1.Location = new Point(3, 502); + tableLayoutPanel1.Name = "tableLayoutPanel1"; + tableLayoutPanel1.RowCount = 1; + tableLayoutPanel1.RowStyles.Add(new RowStyle()); + tableLayoutPanel1.Size = new Size(92, 31); + tableLayoutPanel1.TabIndex = 0; + // + // delBut + // + delBut.Location = new Point(49, 3); + delBut.Name = "delBut"; + delBut.Size = new Size(40, 25); + delBut.TabIndex = 2; + delBut.Values.Image = Properties.Resources.navigate_minus; + delBut.Values.Text = ""; + delBut.Click += delBut_Click; + // + // addBut + // + addBut.Location = new Point(3, 3); + addBut.Name = "addBut"; + addBut.Size = new Size(40, 25); + addBut.TabIndex = 1; + addBut.Values.Image = Properties.Resources.navigate_plus; + addBut.Values.Text = ""; + addBut.Click += addBut_Click; + // + // kryptonHeader1 + // + kryptonHeader1.Dock = DockStyle.Top; + kryptonHeader1.Location = new Point(0, 0); + kryptonHeader1.Margin = new Padding(0); + kryptonHeader1.Name = "kryptonHeader1"; + kryptonHeader1.Size = new Size(1018, 31); + kryptonHeader1.TabIndex = 0; + kryptonHeader1.Values.Description = ""; + kryptonHeader1.Values.Heading = "扩展权限明细"; + kryptonHeader1.Values.Image = null; + // + // dataGv + // + dataGv.AllowUserToAddRows = false; + dataGv.AllowUserToDeleteRows = false; + dataGv.BorderStyle = BorderStyle.None; + dataGv.Columns.AddRange(new DataGridViewColumn[] { dependentDetailNameCol, dependentDetailDescriptionCol }); + dataGv.Dock = DockStyle.Fill; + dataGv.Location = new Point(0, 31); + dataGv.Margin = new Padding(0); + dataGv.Name = "dataGv"; + dataGv.Size = new Size(1018, 468); + dataGv.TabIndex = 2; + // + // dependentDetailNameCol + // + dependentDetailNameCol.DataPropertyName = "DependentDetailName"; + dependentDetailNameCol.DefaultCellStyle = dataGridViewCellStyle1; + dependentDetailNameCol.HeaderText = "扩展名称"; + dependentDetailNameCol.MaxInputLength = 50; + dependentDetailNameCol.Name = "dependentDetailNameCol"; + dependentDetailNameCol.Resizable = DataGridViewTriState.True; + dependentDetailNameCol.Width = 200; + // + // dependentDetailDescriptionCol + // + dependentDetailDescriptionCol.DataPropertyName = "DependentDetailDescription"; + dependentDetailDescriptionCol.DefaultCellStyle = dataGridViewCellStyle2; + dependentDetailDescriptionCol.HeaderText = "扩展描述"; + dependentDetailDescriptionCol.MaxInputLength = 500; + dependentDetailDescriptionCol.Name = "dependentDetailDescriptionCol"; + dependentDetailDescriptionCol.Width = 300; + // + // tableLayoutPanel2 + // + tableLayoutPanel2.AutoSize = true; + tableLayoutPanel2.AutoSizeMode = AutoSizeMode.GrowAndShrink; + tableLayoutPanel2.ColumnCount = 2; + tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel2.Controls.Add(permissionNameLabel, 0, 0); + tableLayoutPanel2.Controls.Add(descriptionLabel, 0, 1); + tableLayoutPanel2.Controls.Add(dependentLabel, 0, 2); + tableLayoutPanel2.Controls.Add(delegateIndcChk, 1, 3); + tableLayoutPanel2.Controls.Add(permissionNameTxt, 1, 0); + tableLayoutPanel2.Controls.Add(descriptionTxt, 1, 1); + tableLayoutPanel2.Controls.Add(dependentTxt, 1, 2); + tableLayoutPanel2.Location = new Point(3, 3); + tableLayoutPanel2.Name = "tableLayoutPanel2"; + tableLayoutPanel2.RowCount = 4; + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.Size = new Size(364, 113); + tableLayoutPanel2.TabIndex = 0; + // + // permissionNameLabel + // + permissionNameLabel.Location = new Point(3, 3); + permissionNameLabel.Name = "permissionNameLabel"; + permissionNameLabel.Size = new Size(52, 20); + permissionNameLabel.TabIndex = 1; + permissionNameLabel.Values.Text = "权限名:"; + // + // descriptionLabel + // + descriptionLabel.Location = new Point(3, 32); + descriptionLabel.Name = "descriptionLabel"; + descriptionLabel.Size = new Size(39, 20); + descriptionLabel.TabIndex = 1; + descriptionLabel.Values.Text = "描述:"; + // + // dependentLabel + // + dependentLabel.Location = new Point(3, 61); + dependentLabel.Name = "dependentLabel"; + dependentLabel.Size = new Size(52, 20); + dependentLabel.TabIndex = 1; + dependentLabel.Values.Text = "扩展名:"; + // + // delegateIndcChk + // + delegateIndcChk.Location = new Point(61, 90); + delegateIndcChk.Name = "delegateIndcChk"; + delegateIndcChk.Size = new Size(81, 20); + delegateIndcChk.TabIndex = 2; + delegateIndcChk.Values.Text = "允许代理?"; + // + // permissionNameTxt + // + permissionNameTxt.Dock = DockStyle.Fill; + permissionNameTxt.Location = new Point(61, 3); + permissionNameTxt.MaxLength = 50; + permissionNameTxt.Name = "permissionNameTxt"; + permissionNameTxt.Size = new Size(300, 23); + permissionNameTxt.TabIndex = 3; + // + // descriptionTxt + // + descriptionTxt.Location = new Point(61, 32); + descriptionTxt.MaxLength = 500; + descriptionTxt.Name = "descriptionTxt"; + descriptionTxt.Size = new Size(300, 23); + descriptionTxt.TabIndex = 3; + // + // dependentTxt + // + dependentTxt.Dock = DockStyle.Fill; + dependentTxt.Location = new Point(61, 61); + dependentTxt.MaxLength = 50; + dependentTxt.Name = "dependentTxt"; + dependentTxt.Size = new Size(300, 23); + dependentTxt.TabIndex = 3; + // + // kryptonPanel2 + // + kryptonPanel2.Dock = DockStyle.Fill; + kryptonPanel2.Location = new Point(3, 122); + kryptonPanel2.Name = "kryptonPanel2"; + kryptonPanel2.Size = new Size(1018, 5); + kryptonPanel2.TabIndex = 1; + // + // mainPanel + // + mainPanel.ColumnCount = 1; + mainPanel.ColumnStyles.Add(new ColumnStyle()); + mainPanel.Controls.Add(topPanel, 0, 0); + mainPanel.Controls.Add(kryptonPanel1, 0, 1); + mainPanel.Controls.Add(bottomPanel, 0, 3); + mainPanel.Controls.Add(contentPanel, 0, 2); + mainPanel.Dock = DockStyle.Fill; + mainPanel.Location = new Point(0, 0); + mainPanel.Name = "mainPanel"; + mainPanel.RowCount = 4; + mainPanel.RowStyles.Add(new RowStyle()); + mainPanel.RowStyles.Add(new RowStyle()); + mainPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 100F)); + mainPanel.RowStyles.Add(new RowStyle()); + mainPanel.Size = new Size(1024, 800); + mainPanel.TabIndex = 1; + // + // topPanel + // + topPanel.AutoSize = true; + topPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + topPanel.ColumnCount = 3; + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 20F)); + topPanel.Controls.Add(searchPanel, 3, 0); + topPanel.Controls.Add(permissionNameSearchLabel, 0, 0); + topPanel.Controls.Add(permissionNameSearchTxt, 1, 0); + topPanel.Dock = DockStyle.Fill; + topPanel.Location = new Point(3, 3); + topPanel.Name = "topPanel"; + topPanel.RowCount = 1; + topPanel.RowStyles.Add(new RowStyle()); + topPanel.Size = new Size(1018, 31); + topPanel.TabIndex = 0; + // + // searchPanel + // + searchPanel.AutoSize = true; + searchPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + searchPanel.ColumnCount = 3; + searchPanel.ColumnStyles.Add(new ColumnStyle()); + searchPanel.ColumnStyles.Add(new ColumnStyle()); + searchPanel.ColumnStyles.Add(new ColumnStyle()); + searchPanel.Controls.Add(createBut, 2, 0); + searchPanel.Controls.Add(resetBut, 1, 0); + searchPanel.Controls.Add(searchBut, 0, 0); + searchPanel.Location = new Point(424, 0); + searchPanel.Margin = new Padding(60, 0, 0, 0); + searchPanel.Name = "searchPanel"; + searchPanel.RowCount = 1; + searchPanel.RowStyles.Add(new RowStyle()); + searchPanel.Size = new Size(288, 31); + searchPanel.TabIndex = 0; + // + // createBut + // + createBut.Location = new Point(195, 3); + createBut.Name = "createBut"; + createBut.Size = new Size(90, 25); + createBut.TabIndex = 3; + createBut.Values.Image = Properties.Resources.create_16; + createBut.Values.Text = "新增(&C)"; + createBut.Click += createBut_Click; + // + // resetBut + // + resetBut.Location = new Point(99, 3); + resetBut.Name = "resetBut"; + resetBut.Size = new Size(90, 25); + resetBut.TabIndex = 2; + resetBut.Values.Image = Properties.Resources.reset_16; + resetBut.Values.Text = "重置(&R)"; + resetBut.Click += resetBut_Click; + // + // searchBut + // + searchBut.Location = new Point(3, 3); + searchBut.Name = "searchBut"; + searchBut.Size = new Size(90, 25); + searchBut.TabIndex = 1; + searchBut.Values.Image = Properties.Resources.search_16; + searchBut.Values.Text = "查询(&S)"; + searchBut.Click += searchBut_Click; + // + // permissionNameSearchLabel + // + permissionNameSearchLabel.Location = new Point(3, 3); + permissionNameSearchLabel.Name = "permissionNameSearchLabel"; + permissionNameSearchLabel.Size = new Size(52, 20); + permissionNameSearchLabel.TabIndex = 1; + permissionNameSearchLabel.Values.Text = "权限名:"; + // + // permissionNameSearchTxt + // + permissionNameSearchTxt.ButtonSpecs.Add(permissionNameSearchBut); + permissionNameSearchTxt.Location = new Point(61, 3); + permissionNameSearchTxt.Name = "permissionNameSearchTxt"; + permissionNameSearchTxt.Size = new Size(300, 23); + permissionNameSearchTxt.TabIndex = 2; + // + // permissionNameSearchBut + // + permissionNameSearchBut.Type = Krypton.Toolkit.PaletteButtonSpecStyle.WorkspaceMaximize; + permissionNameSearchBut.UniqueName = "3a322a66645f4aff808be4720c638ad8"; + permissionNameSearchBut.Click += permissionNameSearchBut_Click; + // + // kryptonPanel1 + // + kryptonPanel1.Dock = DockStyle.Fill; + kryptonPanel1.Location = new Point(3, 40); + kryptonPanel1.Name = "kryptonPanel1"; + kryptonPanel1.Size = new Size(1018, 5); + kryptonPanel1.TabIndex = 1; + // + // bottomPanel + // + bottomPanel.AutoSize = true; + bottomPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + bottomPanel.ColumnCount = 1; + bottomPanel.ColumnStyles.Add(new ColumnStyle()); + bottomPanel.Controls.Add(savePanel, 0, 0); + bottomPanel.Controls.Add(operationPanel, 0, 1); + bottomPanel.Location = new Point(0, 726); + bottomPanel.Margin = new Padding(0); + bottomPanel.Name = "bottomPanel"; + bottomPanel.RowCount = 2; + bottomPanel.RowStyles.Add(new RowStyle()); + bottomPanel.RowStyles.Add(new RowStyle()); + bottomPanel.Size = new Size(198, 74); + bottomPanel.TabIndex = 2; + // + // savePanel + // + savePanel.AutoSize = true; + savePanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + savePanel.ColumnCount = 2; + savePanel.ColumnStyles.Add(new ColumnStyle()); + savePanel.ColumnStyles.Add(new ColumnStyle()); + savePanel.Controls.Add(cancelBut, 1, 0); + savePanel.Controls.Add(saveBut, 0, 0); + savePanel.Location = new Point(3, 3); + savePanel.Name = "savePanel"; + savePanel.RowCount = 1; + savePanel.RowStyles.Add(new RowStyle()); + savePanel.Size = new Size(192, 31); + savePanel.TabIndex = 0; + // + // cancelBut + // + cancelBut.Location = new Point(99, 3); + cancelBut.Name = "cancelBut"; + cancelBut.Size = new Size(90, 25); + cancelBut.TabIndex = 2; + cancelBut.Values.Image = Properties.Resources.cancel_16; + cancelBut.Values.Text = "取消(&L)"; + cancelBut.Click += cancelBut_Click; + // + // saveBut + // + saveBut.Location = new Point(3, 3); + saveBut.Name = "saveBut"; + saveBut.Size = new Size(90, 25); + saveBut.TabIndex = 1; + saveBut.Values.Image = Properties.Resources.save_16; + saveBut.Values.Text = "保存(&S)"; + saveBut.Click += saveBut_Click; + // + // operationPanel + // + operationPanel.AutoSize = true; + operationPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + operationPanel.ColumnCount = 2; + operationPanel.ColumnStyles.Add(new ColumnStyle()); + operationPanel.ColumnStyles.Add(new ColumnStyle()); + operationPanel.Controls.Add(deleteBut, 1, 0); + operationPanel.Controls.Add(amendBut, 0, 0); + operationPanel.Location = new Point(3, 40); + operationPanel.Name = "operationPanel"; + operationPanel.RowCount = 1; + operationPanel.RowStyles.Add(new RowStyle()); + operationPanel.Size = new Size(192, 31); + operationPanel.TabIndex = 0; + // + // deleteBut + // + deleteBut.Location = new Point(99, 3); + deleteBut.Name = "deleteBut"; + deleteBut.Size = new Size(90, 25); + deleteBut.TabIndex = 2; + deleteBut.Values.Image = Properties.Resources.delete_16; + deleteBut.Values.Text = "删除(&D)"; + deleteBut.Click += deleteBut_Click; + // + // amendBut + // + amendBut.Location = new Point(3, 3); + amendBut.Name = "amendBut"; + amendBut.Size = new Size(90, 25); + amendBut.TabIndex = 1; + amendBut.Values.Image = Properties.Resources.amend_16; + amendBut.Values.Text = "修改(&M)"; + amendBut.Click += amendBut_Click; + // + // SecurityPermissionOperationPage + // + AutoScaleDimensions = new SizeF(7F, 15F); + AutoScaleMode = AutoScaleMode.Font; + Controls.Add(mainPanel); + Name = "SecurityPermissionOperationPage"; + contentPanel.ResumeLayout(false); + contentPanel.PerformLayout(); + tableLayoutPanel3.ResumeLayout(false); + tableLayoutPanel4.ResumeLayout(false); + tableLayoutPanel4.PerformLayout(); + tableLayoutPanel1.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)dataGv).EndInit(); + tableLayoutPanel2.ResumeLayout(false); + tableLayoutPanel2.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)kryptonPanel2).EndInit(); + mainPanel.ResumeLayout(false); + mainPanel.PerformLayout(); + topPanel.ResumeLayout(false); + topPanel.PerformLayout(); + searchPanel.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)kryptonPanel1).EndInit(); + bottomPanel.ResumeLayout(false); + bottomPanel.PerformLayout(); + savePanel.ResumeLayout(false); + operationPanel.ResumeLayout(false); + ResumeLayout(false); + } + + #endregion + + private TableLayoutPanel contentPanel; + private TableLayoutPanel tableLayoutPanel3; + private TableLayoutPanel tableLayoutPanel4; + private Krypton.Toolkit.KryptonHeader kryptonHeader1; + private Krypton.Toolkit.KryptonDataGridView dataGv; + private TableLayoutPanel tableLayoutPanel2; + private Krypton.Toolkit.KryptonLabel permissionNameLabel; + private Krypton.Toolkit.KryptonLabel descriptionLabel; + private Krypton.Toolkit.KryptonLabel dependentLabel; + private Krypton.Toolkit.KryptonCheckBox delegateIndcChk; + private Krypton.Toolkit.KryptonTextBox permissionNameTxt; + private Krypton.Toolkit.KryptonTextBox descriptionTxt; + private Krypton.Toolkit.KryptonTextBox dependentTxt; + private Krypton.Toolkit.KryptonPanel kryptonPanel2; + private TableLayoutPanel mainPanel; + private TableLayoutPanel topPanel; + private TableLayoutPanel searchPanel; + private Krypton.Toolkit.KryptonButton createBut; + private Krypton.Toolkit.KryptonButton resetBut; + private Krypton.Toolkit.KryptonButton searchBut; + private Krypton.Toolkit.KryptonLabel permissionNameSearchLabel; + private Krypton.Toolkit.KryptonTextBox permissionNameSearchTxt; + private Krypton.Toolkit.ButtonSpecAny permissionNameSearchBut; + private Krypton.Toolkit.KryptonPanel kryptonPanel1; + private TableLayoutPanel bottomPanel; + private TableLayoutPanel savePanel; + private Krypton.Toolkit.KryptonButton cancelBut; + private Krypton.Toolkit.KryptonButton saveBut; + private TableLayoutPanel operationPanel; + private Krypton.Toolkit.KryptonButton deleteBut; + private Krypton.Toolkit.KryptonButton amendBut; + private TableLayoutPanel tableLayoutPanel1; + private Krypton.Toolkit.KryptonButton delBut; + private Krypton.Toolkit.KryptonButton addBut; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn dependentDetailNameCol; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn dependentDetailDescriptionCol; + } +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Security.Gui/SecurityPermissionOperationPage.cs b/CloudBuilder/CloudBuilder.Security.Gui/SecurityPermissionOperationPage.cs new file mode 100644 index 0000000..f3e641d --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/SecurityPermissionOperationPage.cs @@ -0,0 +1,594 @@ +using CloudBuilder.Core.Service; +using CloudBuilder.Gui; +using CloudBuilder.Request.Security; +using CloudBuilder.Security.Data; +using CloudBuilder.Security.Entity; +using CloudBuilder.Security.Linkup; +using CloudBuilder.Security.Policy; +using DocumentFormat.OpenXml.Wordprocessing; +using Krypton.Toolkit; +using Microsoft.AspNetCore.Authorization; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Security.Permissions; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace CloudBuilder.Security.Gui +{ + public partial class SecurityPermissionOperationPage : AbstractPage + { + private SecurityMessagePolicy securityMessagePolicy; + private SecurityPermissionRequest securityPermissionRequest; + private SecurityPermissionEntity securityPermissionEntity; + private SecurityPermissionData data; + + public object deselectedGv { get; private set; } + + public SecurityPermissionOperationPage() + { + InitializeComponent(); + } + + + /// + /// 第一次加载时执行,只执行一次 + /// + public override void FunctionLoaded() + { + try + { + base.FunctionLoaded(); + //初始化容器------------------------------------- + securityMessagePolicy = ServiceHelper.GetTypeService()!; + securityPermissionRequest = ServiceHelper.GetTypeService(); + + //界面初始化 + InitGui(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + + private void InitGui() + { + InitBindingContext(); + + InitDisplayMode(); + + this.ParentAbstractForm.AcceptButton = this.searchBut; + this.ParentAbstractForm.CancelButton = this.resetBut; + } + + /// + /// 有特殊要求的UI控件初始化设置,Init与Add配对后,使用guiOperateHelper管理 + /// + private void InitBindingContext() + { + //需要绑定数据 + guiBindingContext = new GuiBindingContext(); + + InitPermission(); + + permissionNameTxt.Set(SecurityPermissionEntity.PERMISSION_NAME,permissionNameLabel.Text, EnumEditModeColor.Required); + dependentTxt.Set(SecurityPermissionEntity.DEPENDENT); + descriptionTxt.Set(SecurityPermissionEntity.DESCRIPTION); + delegateIndcChk.Set(SecurityPermissionEntity.DELEGATE_INDC); + + dependentDetailNameCol.Set(EnumEditModeColor.Required); + dependentDetailDescriptionCol.Set(EnumEditModeColor.Required); + + dataGv.InitColumn(false, true); + + guiOperateHelper = new GuiOperateHelper(); + } + + private void InitPermission() + { + createBut.Set(SecurityPermissionPolicy.SecurityPermission, Operate.Insert); + amendBut.Set(SecurityPermissionPolicy.SecurityPermission, Operate.Update); + deleteBut.Set(SecurityPermissionPolicy.SecurityPermission, Operate.Delete); + } + + /// + /// 每次从别的界面进入时执行,发生在FunctionLoaded之后 + /// + /// + public override void FunctionActivated(object param) + { + try + { + if (param == null) + { + permissionNameSearchTxt.Focus(); + return; + } + + InitDisplayMode(); + + SecurityPermissionOperationLinkup linkup = null; + + if (param is SecurityPermissionOperationLinkup) + { + linkup = (SecurityPermissionOperationLinkup)param; + } + + this.DisplayMode = (GuiDisplayMode)linkup.DisplayMode; + + permissionNameSearchTxt.Text = linkup.PermissionName; + + if (this.DisplayMode == GuiDisplayMode.View) + { + Search(); + } + else if (this.DisplayMode == GuiDisplayMode.Create) + { + Create(); + } + else if (this.DisplayMode == GuiDisplayMode.Amend) + { + Search(); + Amend(); + } + + permissionNameSearchTxt.Focus(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + public override void FunctionSelected() + { + this.ParentAbstractForm.AcceptButton = this.searchBut; + if (!IsDialog) + this.ParentAbstractForm.CancelButton = this.resetBut; + else + this.ParentAbstractForm.CancelButton = this.cancelBut; + + permissionNameSearchTxt.Focus(); + } + + public override bool FunctionDeactivating() + { + if (this.DisplayMode == GuiDisplayMode.View) + { + return true; + } + else + { + return CancelEditing(); + } + } + + private bool CancelEditing() + { + DialogResult result = ShowMessageBox.ShowOption(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_CONFIRM_CANCEL), securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_CONFIRM)); + + //从外部跳转(非mainKryptonNavigator),result第一次不生效?,所以再执行一次生效 + if (result == DialogResult.Cancel) + { + result = ShowMessageBox.ShowOption(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_CONFIRM_CANCEL), securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_CONFIRM)); + } + + if (result == DialogResult.No) + { + return false; + } + + Cancel(); + + return true; + } + + private void InitDisplayMode() + { + this.DisplayMode = GuiDisplayMode.View; + + SetDisplayMode(); + } + + private void SetDisplayMode() + { + if (this.DisplayMode == GuiDisplayMode.View) + { + savePanel.Visible = false; + operationPanel.Visible = true; + + guiOperateHelper.EnableControls(true, topPanel); + guiOperateHelper.EnableControls(false, contentPanel); + //查詢有記錄時,修改等控件有效 + if (securityPermissionEntity != null) + guiOperateHelper.EnableControls(true, bottomPanel); + else + guiOperateHelper.EnableControls(false, bottomPanel); + } + else if (this.DisplayMode == GuiDisplayMode.Amend || this.DisplayMode == GuiDisplayMode.Create) + { + savePanel.Visible = true; + operationPanel.Visible = false; + + guiOperateHelper.EnableControls(false, topPanel); + guiOperateHelper.EnableControls(true, bottomPanel, contentPanel); + + if (this.DisplayMode == GuiDisplayMode.Amend) guiOperateHelper.EnableControls(false, permissionNameTxt); + } + } + + private void PackUIToEntity() + { + guiBindingContext.DataPack(); + + SecurityPermissionDependentEntity[] dependentEntities = dataGv.GetAllRows(); + + if (dependentEntities == null || dependentEntities.Length == 0) + data.SecurityPermissionDependents = null; + else + data.SecurityPermissionDependents = dependentEntities.Select(x => new SecurityPermissionDependentEntity() + { + CreatedBy = x.CreatedBy, + UpdatedBy = x.UpdatedBy, + PermissionName = permissionNameTxt.Text, + Dependent = dependentTxt.Text, + DependentDetailName = x.DependentDetailName, + DependentDetailDescription = x.DependentDetailDescription + }).ToArray(); ; + } + + private bool SaveValidate() + { + if (!guiOperateHelper.CheckValidate(this.contentPanel)) return false; + + if (dataGv.Rows.Count > 0 && string.IsNullOrEmpty(dependentTxt.Text)) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_VALID_INPUT, GuiOperateHelper.GetLabelText(dependentLabel.Text))); + dependentTxt.Focus(); + return false; + } + + return true; + } + + private void Search() + { + try + { + if (string.IsNullOrEmpty(permissionNameSearchTxt.Text)) return; + + Reset(); + + data = securityPermissionRequest.FindByKey(permissionNameSearchTxt.Text); + + if (data == null || data.SecurityPermission == null) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + } + else + { + securityPermissionEntity = data.SecurityPermission; + + PackEntityToUI(); + + SetDisplayMode(); + } + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void Create() + { + this.DisplayMode = GuiDisplayMode.Create; + + guiOperateHelper.ResetControls(this.mainPanel); + + SetDisplayMode(); + + data = new SecurityPermissionData(); + securityPermissionEntity = new SecurityPermissionEntity() + { + CreatedBy = string.Empty, + UpdatedBy = string.Empty, + CreatedDatetime = DateTime.Now, + UpdatedDatetime = DateTime.Now, + }; + data.SecurityPermission = securityPermissionEntity; + + PackEntityToUI(); + + permissionNameTxt.Focus(); + } + + private void Amend() + { + this.DisplayMode = GuiDisplayMode.Amend; + + SetDisplayMode(); + } + + private void PackEntityToUI() + { + guiBindingContext.DataBind(data.SecurityPermission, this); + + dataGv.SetDataSource(data.SecurityPermissionDependents); + } + + private void Reset() + { + this.DisplayMode = GuiDisplayMode.View; + + securityPermissionEntity = null; + + guiOperateHelper.ResetControls(this.contentPanel); + + SetDisplayMode(); + + permissionNameSearchTxt.Focus(); + } + + public void Cancel() + { + if (!string.IsNullOrEmpty(permissionNameSearchTxt.Text)) + Search(); + else + Reset(); + + } + + + private void permissionNameSearchBut_Click(object sender, EventArgs e) + { + try + { + AbstractForm dialog = GetAbstractDialog(typeof(SecurityPermissionEnquiryPage).Name); + + if (DialogResult.OK != dialog.ShowDialog()) return; + + permissionNameSearchTxt.Text = ((SecurityPermissionEntity[])dialog.OutputData)[0].PermissionName; + + Search(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void searchBut_Click(object sender, EventArgs e) + { + try + { + if (string.IsNullOrEmpty(permissionNameSearchTxt.Text)) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_VALID_INPUT, GuiOperateHelper.GetLabelText(permissionNameSearchLabel.Text))); + this.permissionNameSearchTxt.Focus(); + return; + } + this.DisplayMode = GuiDisplayMode.View; + + Search(); + + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void resetBut_Click(object sender, EventArgs e) + { + try + { + guiOperateHelper.ResetControls(this.topPanel); + Reset(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void createBut_Click(object sender, EventArgs e) + { + try + { + Create(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void amendBut_Click(object sender, EventArgs e) + { + try + { + Amend(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void deleteBut_Click(object sender, EventArgs e) + { + try + { + if (securityPermissionEntity == null) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + return; + } + + if (DialogResult.Yes != ShowMessageBox.ShowOption(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_CONFIRM_DEL_NULL), securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_DELETE))) return; + + securityPermissionRequest.Delete(securityPermissionEntity.PermissionName); + + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_SUCCEED_DELETED_NULL)); + + Reset(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void saveBut_Click(object sender, EventArgs e) + { + try + { + if (!SaveValidate()) return; + + PackUIToEntity(); + + + if (this.DisplayMode == GuiDisplayMode.Create) + securityPermissionRequest.Insert(data); + else + securityPermissionRequest.Update(data); + + + ShowMessageBox.ShowInfo((this.DisplayMode == GuiDisplayMode.Create) ? + securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_SUCCEED_CREATED_NULL) : + securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_SUCCEED_UPDATED_NULL)); + + permissionNameSearchTxt.Text = securityPermissionEntity.PermissionName; + Search(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void cancelBut_Click(object sender, EventArgs e) + { + try + { + CancelEditing(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void addBut_Click(object sender, EventArgs e) + { + dataGv.AddRow(new SecurityPermissionDependentEntity() { CreatedBy = string.Empty, UpdatedBy = string.Empty }); + } + + private void delBut_Click(object sender, EventArgs e) + { + if (dataGv.RowCount <= 0 || dataGv.SelectedCells.Count <= 0) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + return; + } + + dataGv.DeleteRows(dataGv.SelectedCells); + } + } +} diff --git a/CloudBuilder/CloudBuilder.Security.Gui/SecurityPermissionOperationPage.resx b/CloudBuilder/CloudBuilder.Security.Gui/SecurityPermissionOperationPage.resx new file mode 100644 index 0000000..a0a8ae6 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/SecurityPermissionOperationPage.resx @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + True + + + True + + + True + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Security.Gui/SecurityUserEnquiryPage.Designer.cs b/CloudBuilder/CloudBuilder.Security.Gui/SecurityUserEnquiryPage.Designer.cs new file mode 100644 index 0000000..29274e9 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/SecurityUserEnquiryPage.Designer.cs @@ -0,0 +1,421 @@ +namespace CloudBuilder.Security.Gui +{ + partial class SecurityUserEnquiryPage + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + DataGridViewCellStyle dataGridViewCellStyle1 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle2 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle3 = new DataGridViewCellStyle(); + mainPanel = new TableLayoutPanel(); + topPanel = new TableLayoutPanel(); + deleteLabel = new Krypton.Toolkit.KryptonLabel(); + userNameLabel = new Krypton.Toolkit.KryptonLabel(); + userNameTxt = new Krypton.Toolkit.KryptonTextBox(); + searchPanel = new TableLayoutPanel(); + searchBut = new Krypton.Toolkit.KryptonButton(); + resetBut = new Krypton.Toolkit.KryptonButton(); + createBut = new Krypton.Toolkit.KryptonButton(); + userIsValidIndcCombo = new Krypton.Toolkit.KryptonComboBox(); + contextPanel = new TableLayoutPanel(); + dataGv = new Krypton.Toolkit.KryptonDataGridView(); + gridViewPagination = new CloudBuilder.Gui.GridViewPagination(); + bottomPanel = new TableLayoutPanel(); + operationPanel = new TableLayoutPanel(); + viewBut = new Krypton.Toolkit.KryptonButton(); + amendBut = new Krypton.Toolkit.KryptonButton(); + deleteBut = new Krypton.Toolkit.KryptonButton(); + dialogPanel = new TableLayoutPanel(); + okBut = new Krypton.Toolkit.KryptonButton(); + cancelBut = new Krypton.Toolkit.KryptonButton(); + userNameCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + userMobileCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + userIsValidIndcCol = new Krypton.Toolkit.KryptonDataGridViewCheckBoxColumn(); + mainPanel.SuspendLayout(); + topPanel.SuspendLayout(); + searchPanel.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)userIsValidIndcCombo).BeginInit(); + contextPanel.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)dataGv).BeginInit(); + bottomPanel.SuspendLayout(); + operationPanel.SuspendLayout(); + dialogPanel.SuspendLayout(); + SuspendLayout(); + // + // mainPanel + // + mainPanel.ColumnCount = 1; + mainPanel.ColumnStyles.Add(new ColumnStyle()); + mainPanel.Controls.Add(topPanel, 0, 0); + mainPanel.Controls.Add(contextPanel, 0, 1); + mainPanel.Controls.Add(bottomPanel, 0, 2); + mainPanel.Dock = DockStyle.Fill; + mainPanel.Location = new Point(0, 0); + mainPanel.Name = "mainPanel"; + mainPanel.RowCount = 3; + mainPanel.RowStyles.Add(new RowStyle()); + mainPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 100F)); + mainPanel.RowStyles.Add(new RowStyle()); + mainPanel.Size = new Size(1024, 800); + mainPanel.TabIndex = 0; + // + // topPanel + // + topPanel.AutoSize = true; + topPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + topPanel.ColumnCount = 5; + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.Controls.Add(deleteLabel, 2, 0); + topPanel.Controls.Add(userNameLabel, 0, 0); + topPanel.Controls.Add(userNameTxt, 1, 0); + topPanel.Controls.Add(searchPanel, 4, 0); + topPanel.Controls.Add(userIsValidIndcCombo, 3, 0); + topPanel.Dock = DockStyle.Fill; + topPanel.Location = new Point(3, 3); + topPanel.Name = "topPanel"; + topPanel.RowCount = 1; + topPanel.RowStyles.Add(new RowStyle()); + topPanel.Size = new Size(1018, 31); + topPanel.TabIndex = 0; + // + // deleteLabel + // + deleteLabel.Location = new Point(294, 3); + deleteLabel.Margin = new Padding(30, 3, 3, 3); + deleteLabel.Name = "deleteLabel"; + deleteLabel.Size = new Size(39, 20); + deleteLabel.TabIndex = 999; + deleteLabel.Values.Text = "有效:"; + // + // userNameLabel + // + userNameLabel.Location = new Point(3, 3); + userNameLabel.Name = "userNameLabel"; + userNameLabel.Size = new Size(52, 20); + userNameLabel.TabIndex = 999; + userNameLabel.Values.Text = "用户名:"; + // + // userNameTxt + // + userNameTxt.Location = new Point(61, 3); + userNameTxt.Name = "userNameTxt"; + userNameTxt.Size = new Size(200, 23); + userNameTxt.TabIndex = 0; + // + // searchPanel + // + searchPanel.AutoSize = true; + searchPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + searchPanel.ColumnCount = 3; + searchPanel.ColumnStyles.Add(new ColumnStyle()); + searchPanel.ColumnStyles.Add(new ColumnStyle()); + searchPanel.ColumnStyles.Add(new ColumnStyle()); + searchPanel.Controls.Add(searchBut, 0, 0); + searchPanel.Controls.Add(resetBut, 1, 0); + searchPanel.Controls.Add(createBut, 2, 0); + searchPanel.Location = new Point(602, 0); + searchPanel.Margin = new Padding(60, 0, 0, 0); + searchPanel.Name = "searchPanel"; + searchPanel.RowCount = 1; + searchPanel.RowStyles.Add(new RowStyle()); + searchPanel.Size = new Size(288, 31); + searchPanel.TabIndex = 999; + // + // searchBut + // + searchBut.Location = new Point(3, 3); + searchBut.Name = "searchBut"; + searchBut.Size = new Size(90, 25); + searchBut.TabIndex = 0; + searchBut.Values.Image = Properties.Resources.search_16; + searchBut.Values.Text = "查询(&S)"; + searchBut.Click += searchBut_Click; + // + // resetBut + // + resetBut.Location = new Point(99, 3); + resetBut.Name = "resetBut"; + resetBut.Size = new Size(90, 25); + resetBut.TabIndex = 0; + resetBut.Values.Image = Properties.Resources.reset_16; + resetBut.Values.Text = "重置(&R)"; + resetBut.Click += resetBut_Click; + // + // createBut + // + createBut.Location = new Point(195, 3); + createBut.Name = "createBut"; + createBut.Size = new Size(90, 25); + createBut.TabIndex = 0; + createBut.Values.Image = Properties.Resources.create_16; + createBut.Values.Text = "新增(&C)"; + createBut.Click += createBut_Click; + // + // userIsValidIndcCombo + // + userIsValidIndcCombo.DropDownStyle = ComboBoxStyle.DropDownList; + userIsValidIndcCombo.DropDownWidth = 200; + userIsValidIndcCombo.IntegralHeight = false; + userIsValidIndcCombo.Location = new Point(339, 3); + userIsValidIndcCombo.Name = "userIsValidIndcCombo"; + userIsValidIndcCombo.Size = new Size(200, 22); + userIsValidIndcCombo.StateCommon.ComboBox.Content.TextH = Krypton.Toolkit.PaletteRelativeAlign.Near; + userIsValidIndcCombo.TabIndex = 1; + // + // contextPanel + // + contextPanel.ColumnCount = 1; + contextPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F)); + contextPanel.Controls.Add(dataGv, 0, 0); + contextPanel.Controls.Add(gridViewPagination, 0, 1); + contextPanel.Dock = DockStyle.Fill; + contextPanel.Location = new Point(3, 40); + contextPanel.Name = "contextPanel"; + contextPanel.RowCount = 2; + contextPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 50F)); + contextPanel.RowStyles.Add(new RowStyle()); + contextPanel.Size = new Size(1018, 683); + contextPanel.TabIndex = 999; + // + // dataGv + // + dataGv.AllowUserToAddRows = false; + dataGv.AllowUserToDeleteRows = false; + dataGv.BorderStyle = BorderStyle.None; + dataGv.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize; + dataGv.Columns.AddRange(new DataGridViewColumn[] { userNameCol, userMobileCol, userIsValidIndcCol }); + dataGv.Dock = DockStyle.Fill; + dataGv.Location = new Point(3, 3); + dataGv.Name = "dataGv"; + dataGv.Size = new Size(1012, 647); + dataGv.TabIndex = 0; + dataGv.CellDoubleClick += dataGv_CellDoubleClick; + // + // gridViewPagination + // + gridViewPagination.AutoSizeMode = AutoSizeMode.GrowAndShrink; + gridViewPagination.CurrentPage = 0; + gridViewPagination.Dock = DockStyle.Fill; + gridViewPagination.Limit = 20; + gridViewPagination.Location = new Point(0, 653); + gridViewPagination.Margin = new Padding(0); + gridViewPagination.Name = "gridViewPagination"; + gridViewPagination.Page = 0; + gridViewPagination.Size = new Size(1018, 30); + gridViewPagination.TabIndex = 999; + gridViewPagination.Total = 0; + // + // bottomPanel + // + bottomPanel.AutoSize = true; + bottomPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + bottomPanel.ColumnCount = 2; + bottomPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F)); + bottomPanel.ColumnStyles.Add(new ColumnStyle()); + bottomPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 20F)); + bottomPanel.Controls.Add(operationPanel, 0, 0); + bottomPanel.Controls.Add(dialogPanel, 2, 1); + bottomPanel.Dock = DockStyle.Fill; + bottomPanel.Location = new Point(3, 729); + bottomPanel.Name = "bottomPanel"; + bottomPanel.RowCount = 2; + bottomPanel.RowStyles.Add(new RowStyle()); + bottomPanel.RowStyles.Add(new RowStyle()); + bottomPanel.Size = new Size(1018, 68); + bottomPanel.TabIndex = 999; + // + // operationPanel + // + operationPanel.AutoSize = true; + operationPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + operationPanel.ColumnCount = 3; + operationPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F)); + operationPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 101F)); + operationPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F)); + operationPanel.Controls.Add(viewBut, 0, 0); + operationPanel.Controls.Add(amendBut, 1, 0); + operationPanel.Controls.Add(deleteBut, 2, 0); + operationPanel.Location = new Point(0, 0); + operationPanel.Margin = new Padding(0); + operationPanel.Name = "operationPanel"; + operationPanel.RowCount = 1; + operationPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 50F)); + operationPanel.Size = new Size(293, 31); + operationPanel.TabIndex = 0; + // + // viewBut + // + viewBut.Location = new Point(3, 3); + viewBut.Name = "viewBut"; + viewBut.Size = new Size(90, 25); + viewBut.TabIndex = 0; + viewBut.Values.Image = Properties.Resources.view_16; + viewBut.Values.Text = "查看(&V)"; + viewBut.Click += viewBut_Click; + // + // amendBut + // + amendBut.Location = new Point(99, 3); + amendBut.Name = "amendBut"; + amendBut.Size = new Size(90, 25); + amendBut.TabIndex = 0; + amendBut.Values.Image = Properties.Resources.amend_16; + amendBut.Values.Text = "修改(&A)"; + amendBut.Click += amendBut_Click; + // + // deleteBut + // + deleteBut.Location = new Point(200, 3); + deleteBut.Name = "deleteBut"; + deleteBut.Size = new Size(90, 25); + deleteBut.TabIndex = 0; + deleteBut.Values.Image = Properties.Resources.delete_16; + deleteBut.Values.Text = "无效(&D)"; + deleteBut.Click += deleteBut_Click; + // + // dialogPanel + // + dialogPanel.AutoSize = true; + dialogPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + dialogPanel.ColumnCount = 2; + dialogPanel.ColumnStyles.Add(new ColumnStyle()); + dialogPanel.ColumnStyles.Add(new ColumnStyle()); + dialogPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 20F)); + dialogPanel.Controls.Add(okBut, 0, 0); + dialogPanel.Controls.Add(cancelBut, 1, 0); + dialogPanel.Dock = DockStyle.Fill; + dialogPanel.Location = new Point(823, 34); + dialogPanel.Name = "dialogPanel"; + dialogPanel.RowCount = 1; + dialogPanel.RowStyles.Add(new RowStyle()); + dialogPanel.Size = new Size(192, 31); + dialogPanel.TabIndex = 1; + // + // okBut + // + okBut.Location = new Point(3, 3); + okBut.Name = "okBut"; + okBut.Size = new Size(90, 25); + okBut.TabIndex = 0; + okBut.Values.Image = Properties.Resources.ok_16; + okBut.Values.Text = "确定(&O)"; + okBut.Click += okBut_Click; + // + // cancelBut + // + cancelBut.Location = new Point(99, 3); + cancelBut.Name = "cancelBut"; + cancelBut.Size = new Size(90, 25); + cancelBut.TabIndex = 0; + cancelBut.Values.Image = Properties.Resources.close_16; + cancelBut.Values.Text = "取消(&C)"; + cancelBut.Click += cancelBut_Click; + // + // userNameCol + // + userNameCol.DataPropertyName = "UserName"; + userNameCol.DefaultCellStyle = dataGridViewCellStyle1; + userNameCol.HeaderText = "用户名"; + userNameCol.Name = "userNameCol"; + userNameCol.Width = 260; + // + // userMobileCol + // + userMobileCol.DataPropertyName = "UserMobile"; + userMobileCol.DefaultCellStyle = dataGridViewCellStyle2; + userMobileCol.HeaderText = "手机号码"; + userMobileCol.Name = "userMobileCol"; + userMobileCol.Width = 260; + // + // userIsValidIndcCol + // + userIsValidIndcCol.DataPropertyName = "UserIsValidIndc"; + dataGridViewCellStyle3.Alignment = DataGridViewContentAlignment.MiddleCenter; + dataGridViewCellStyle3.NullValue = false; + userIsValidIndcCol.DefaultCellStyle = dataGridViewCellStyle3; + userIsValidIndcCol.FalseValue = "N"; + userIsValidIndcCol.HeaderText = "有效?"; + userIsValidIndcCol.IndeterminateValue = null; + userIsValidIndcCol.Name = "userIsValidIndcCol"; + userIsValidIndcCol.Resizable = DataGridViewTriState.True; + userIsValidIndcCol.SortMode = DataGridViewColumnSortMode.Automatic; + userIsValidIndcCol.TrueValue = "Y"; + userIsValidIndcCol.Width = 80; + // + // SecurityUserEnquiryPage + // + AutoScaleDimensions = new SizeF(7F, 15F); + AutoScaleMode = AutoScaleMode.Font; + Controls.Add(mainPanel); + Name = "SecurityUserEnquiryPage"; + mainPanel.ResumeLayout(false); + mainPanel.PerformLayout(); + topPanel.ResumeLayout(false); + topPanel.PerformLayout(); + searchPanel.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)userIsValidIndcCombo).EndInit(); + contextPanel.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)dataGv).EndInit(); + bottomPanel.ResumeLayout(false); + bottomPanel.PerformLayout(); + operationPanel.ResumeLayout(false); + dialogPanel.ResumeLayout(false); + ResumeLayout(false); + } + + #endregion + + private TableLayoutPanel mainPanel; + private TableLayoutPanel topPanel; + private TableLayoutPanel searchPanel; + private Krypton.Toolkit.KryptonButton searchBut; + private Krypton.Toolkit.KryptonButton resetBut; + private Krypton.Toolkit.KryptonButton createBut; + private TableLayoutPanel contextPanel; + private TableLayoutPanel bottomPanel; + private TableLayoutPanel operationPanel; + private Krypton.Toolkit.KryptonButton viewBut; + private Krypton.Toolkit.KryptonButton amendBut; + private Krypton.Toolkit.KryptonButton deleteBut; + private Krypton.Toolkit.KryptonLabel userNameLabel; + private Krypton.Toolkit.KryptonLabel deleteLabel; + private Krypton.Toolkit.KryptonTextBox userNameTxt; + private Krypton.Toolkit.KryptonComboBox userIsValidIndcCombo; + private Krypton.Toolkit.KryptonDataGridView dataGv; + private TableLayoutPanel dialogPanel; + private Krypton.Toolkit.KryptonButton okBut; + private Krypton.Toolkit.KryptonButton cancelBut; + private CloudBuilder.Gui.GridViewPagination gridViewPagination; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn userNameCol; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn userMobileCol; + private Krypton.Toolkit.KryptonDataGridViewCheckBoxColumn userIsValidIndcCol; + } +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Security.Gui/SecurityUserEnquiryPage.cs b/CloudBuilder/CloudBuilder.Security.Gui/SecurityUserEnquiryPage.cs new file mode 100644 index 0000000..eb595c5 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/SecurityUserEnquiryPage.cs @@ -0,0 +1,348 @@ +using ClosedXML.Excel; +using CloudBuilder.Core.DependencyInjection.Form; +using CloudBuilder.Core.Report; +using CloudBuilder.Core.Service; +using CloudBuilder.Gui; +using CloudBuilder.Gui.DependencyInjection; +using CloudBuilder.Request.Security; +using CloudBuilder.Security.Data; +using CloudBuilder.Security.Entity; +using CloudBuilder.Security.Linkup; +using CloudBuilder.Security.Policy; +using CloudBuilder.Security.SearchCriteria; +using DocumentFormat.OpenXml.Spreadsheet; +using Krypton.Toolkit; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http.Extensions; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.IdentityModel.Tokens; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + + +namespace CloudBuilder.Security.Gui +{ + public partial class SecurityUserEnquiryPage : AbstractPage + { + private SecurityUserEntity[] securityUsers = null!; + private SecurityUserSearchCriteria searchCriteria = null!; + private BindingContextAttributeProvider provider; + private SecurityUserRequest securityUserRequest; + private SecurityMessagePolicy securityMessagePolicy; + + //初始化Page,注入容器内,不要在此做任何事情 + public SecurityUserEnquiryPage() + { + InitializeComponent(); + } + + /// + /// 第一次加载时执行,只执行一次 + /// + public override void FunctionLoaded() + { + HandleException(() => onFunctionLoaded()); + } + + private void onFunctionLoaded() + { + base.FunctionLoaded(); + //初始化容器------------------------------------- + securityUserRequest = ServiceHelper.GetTypeService(); + securityMessagePolicy = ServiceHelper.GetTypeService()!; + + //界面初始化 + InitGui(); + } + + /// + /// 每次从别的界面进入时执行,不包括下面的界面切换,发生在FunctionLoaded之后 + /// 这个是有参数传入,常用于查询界面进入到操作界面发生 + /// + /// + public override void FunctionActivated(object param) + { + base.FunctionActivated(param); + userNameTxt.Focus(); + } + /// + /// 当Page被选中时执行,用于Tab导航的切换,没有参数变化,跟FunctionActivated有区别 + /// + public override void FunctionSelected() + { + this.ParentAbstractForm.AcceptButton = this.searchBut; + if (!IsDialog) + this.ParentAbstractForm.CancelButton = this.resetBut; + else + this.ParentAbstractForm.CancelButton = this.cancelBut; + + userNameTxt.Focus(); + } + /// + /// 控件的初始化 + /// + private void InitGui() + { + //DataGridView初始化不要自动生成列,且允许重排列名操作 + dataGv.InitColumn(true, true); + //绑定ComboBox数据源 + InitCombo(); + //设置userIsValidIndcCombo默认值 + userIsValidIndcCombo.SelectedValue = YesNoPolicy.YES; + //初始化绑定设置 + InitBindingContext(); + //设置显示模式 + SetDisplayMode(true); + + InitGridViewPagination(); + } + /// + /// DataGridView分页控件初始化 + /// + private void InitGridViewPagination() + { + searchCriteria = new SecurityUserSearchCriteria(); + gridViewPagination.SetLimit(searchCriteria.limit); + gridViewPagination.OnPaginationChanged += Search; + gridViewPagination.OnPrint += Print; + } + + /// + /// 打印当前查询结果 + /// + private void Print() + { + //設置Value與description的映射,另一方式是dataValeOperation传入函数 + Dictionary> mappings = new Dictionary>(); + Dictionary validDic = YesNoPolicy.GetInstance().GetDictionary(); + mappings.Add(SecurityUserEntity.USER_IS_VALID_INDC, validDic); + //設置查詢條件 + List searCriteria = new List(); + if (!string.IsNullOrEmpty(userNameTxt.Text)) + searCriteria.Add(userNameLabel.Text + userNameTxt.Text); + if (!string.IsNullOrEmpty(userIsValidIndcCombo.Text)) + searCriteria.Add(deleteLabel.Text + userIsValidIndcCombo.Text); + //設置每列的格式 + TemplateHeader[] headers = dataGv.GetTemplateHeaders(); + headers.Where(x => x.BindingName == SecurityUserEntity.USER_IS_VALID_INDC).FirstOrDefault().CellTypeFormatName = SecurityUserEntity.USER_IS_VALID_INDC; + //打印Excel + new DataToExcelHelper(null).PrintExcel(this.Parent.Text, this.Parent.Text, searCriteria, headers, securityUsers, mappings, null, CellTypeFormatOperation, null); + } + + public void CellTypeFormatOperation(IXLWorksheet xLWorksheet, string functionName, object cellValue, int rowIndex, int ColIndex, SecurityUserEntity[] datas) + { + SecurityUserEntity entity = (SecurityUserEntity)cellValue; + if (entity.UserIsValidIndc == YesNoPolicy.NO) + { + xLWorksheet.Range(rowIndex, ColIndex, rowIndex, ColIndex).Style.Fill.PatternType = XLFillPatternValues.Solid; + xLWorksheet.Range(rowIndex, ColIndex, rowIndex, ColIndex).Style.Fill.SetBackgroundColor(XLColor.Red); + } + } + + private void InitCombo() + { + userIsValidIndcCombo.SetDataSource(YesNoPolicy.GetInstance().GetComposeMessages(), true); + } + + /// + /// 有特殊要求的UI控件初始化设置,使用guiOperateHelper管理 + /// + private void InitBindingContext() + { + InitPermission(); + + guiOperateHelper = new GuiOperateHelper(); + } + + private void InitPermission() + { + viewBut.Set(SecurityPermissionPolicy.SecurityUser, Operate.Find); + createBut.Set(SecurityPermissionPolicy.SecurityUser, Operate.Insert); + amendBut.Set(SecurityPermissionPolicy.SecurityUser, Operate.Update); + deleteBut.Set(SecurityPermissionPolicy.SecurityUser, Operate.Delete); + } + + private void SetDisplayMode(bool enable) + { + guiOperateHelper.EnableControls(true, this.searchPanel, this.bottomPanel); + guiOperateHelper.EnableControls(false, dataGv); + + if (securityUsers != null) + guiOperateHelper.EnableControls(enable, viewBut, amendBut, deleteBut); + else + guiOperateHelper.EnableControls(false, viewBut, amendBut, deleteBut); + + //如果是弹出的窗口,不显示 + createBut.Visible = !IsDialog; + dialogPanel.Visible = IsDialog; + operationPanel.Visible = !IsDialog; + + this.userNameTxt.Focus(); + } + + private void searchBut_Click(object sender, EventArgs e) + { + HandleException(() => Search()); + } + + /// + /// 与Web同步写法 + /// + /// + private SecurityUserSearchCriteria PackSearchCriteria() + { + searchCriteria = new SecurityUserSearchCriteria(); + searchCriteria.limit = gridViewPagination.Limit; + searchCriteria.page = gridViewPagination.CurrentPage; + + List filters = new List(); + + SearchFilter filter = new SearchFilter(); + filter.Column = SecurityUserEntity.DB_USER_NAME; + filter.Type = SearchFilterTypePolicy.TEXT; + filter.Operator = SearchFilterOperatorPolicy.CONTAIN; + filter.Value = userNameTxt.GetValue(); + filters.Add(filter); + + filter = new SearchFilter(); + filter.Column = SecurityUserEntity.DB_USER_IS_VALID_INDC; + filter.Type = SearchFilterTypePolicy.TEXT; + filter.Operator = SearchFilterOperatorPolicy.SINGLE; + filter.Value = (string)userIsValidIndcCombo.GetValue(); + filters.Add(filter); + + searchCriteria.Filter = filters.ToArray(); + + return searchCriteria; + } + + private void Search() + { + var data = securityUserRequest.FindBySearchCriteria(PackSearchCriteria()); + + if (data != null) securityUsers = data.Datas; + + gridViewPagination.SetTotal(data.Total); + + if (securityUsers == null || securityUsers.Length == 0) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + guiOperateHelper.ResetControls(this.dataGv); + return; + } + + dataGv.SetDataSource(securityUsers); + + SetDisplayMode(true); + } + + private void resetBut_Click(object sender, EventArgs e) + { + guiOperateHelper.ResetControls(this.mainPanel); + + SetDisplayMode(false); + + userIsValidIndcCombo.SelectedValue = YesNoPolicy.YES; + } + + private void createBut_Click(object sender, EventArgs e) + { + DisplayPage(GuiDisplayMode.Create, null); + } + + private void DisplayPage(GuiDisplayMode mode, string userName) + { + SecurityUserOperationLinkup linkupData = new SecurityUserOperationLinkup(); + linkupData.DisplayMode = Convert.ToInt32(mode); + linkupData.UserName = userName; + + this.DisplayAbstractPage(typeof(SecurityUserOperationPage).Name, linkupData); + } + + + private void viewBut_Click(object sender, EventArgs e) + { + if (dataGv.RowCount <= 0 || dataGv.SelectedCells.Count <= 0) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + return; + } + + SecurityUserEntity data = dataGv.GetRowData(dataGv.SelectedCells[0].RowIndex); + + DisplayPage(GuiDisplayMode.View, data.UserName); + } + + private void amendBut_Click(object sender, EventArgs e) + { + if (dataGv.RowCount <= 0 || dataGv.SelectedCells.Count <= 0) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + return; + } + + SecurityUserEntity data = dataGv.GetRowData(dataGv.SelectedCells[0].RowIndex); + + DisplayPage(GuiDisplayMode.Amend, data.UserName); + } + + private void deleteBut_Click(object sender, EventArgs e) + { + HandleException(() => Delete()); + } + + private void Delete() + { + if (dataGv.RowCount <= 0 || dataGv.SelectedCells.Count <= 0) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + return; + } + + if (DialogResult.Yes != ShowMessageBox.ShowOption(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_CONFIRM_DEL_NULL), securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_DELETE))) return; + + SecurityUserEntity[] datas = dataGv.GetSelectedCellsData(); + + securityUserRequest.Deletes(datas.Select(x => x.UserName).ToArray()); + + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_SUCCEED_DELETED_NULL)); + + Search(); + } + + private void okBut_Click(object sender, EventArgs e) + { + if (dataGv.RowCount <= 0 || dataGv.SelectedCells.Count <= 0) return; + //SecurityUserEntity data = dataGv.GetRowData(dataGv.SelectedCells[0].RowIndex); + SecurityUserEntity[] datas = dataGv.GetSelectedCellsData(); + + this.ParentAbstractForm.OutputData = datas; + this.ParentAbstractForm.DialogResult = DialogResult.OK; + this.ParentAbstractForm.Close(); + } + + private void cancelBut_Click(object sender, EventArgs e) + { + this.ParentAbstractForm.DialogResult = DialogResult.Cancel; + this.ParentAbstractForm.Close(); + } + + private void dataGv_CellDoubleClick(object sender, DataGridViewCellEventArgs e) + { + if (IsDialog) + okBut_Click(null, null); + else + viewBut_Click(null, null); + } + } +} diff --git a/CloudBuilder/CloudBuilder.Security.Gui/SecurityUserEnquiryPage.resx b/CloudBuilder/CloudBuilder.Security.Gui/SecurityUserEnquiryPage.resx new file mode 100644 index 0000000..15fc8aa --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/SecurityUserEnquiryPage.resx @@ -0,0 +1,150 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Security.Gui/SecurityUserOperationPage.Designer.cs b/CloudBuilder/CloudBuilder.Security.Gui/SecurityUserOperationPage.Designer.cs new file mode 100644 index 0000000..372908e --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/SecurityUserOperationPage.Designer.cs @@ -0,0 +1,717 @@ +namespace CloudBuilder.Security.Gui +{ + partial class SecurityUserOperationPage + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + DataGridViewCellStyle dataGridViewCellStyle1 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle2 = new DataGridViewCellStyle(); + mainPanel = new TableLayoutPanel(); + topPanel = new TableLayoutPanel(); + searchPanel = new TableLayoutPanel(); + createBut = new Krypton.Toolkit.KryptonButton(); + resetBut = new Krypton.Toolkit.KryptonButton(); + searchBut = new Krypton.Toolkit.KryptonButton(); + userNameSearchLabel = new Krypton.Toolkit.KryptonLabel(); + userNameSearchTxt = new Krypton.Toolkit.KryptonTextBox(); + userNameSearchBut = new Krypton.Toolkit.ButtonSpecAny(); + kryptonPanel1 = new Krypton.Toolkit.KryptonPanel(); + bottomPanel = new TableLayoutPanel(); + savePanel = new TableLayoutPanel(); + cancelBut = new Krypton.Toolkit.KryptonButton(); + saveBut = new Krypton.Toolkit.KryptonButton(); + operationPanel = new TableLayoutPanel(); + deleteBut = new Krypton.Toolkit.KryptonButton(); + amendBut = new Krypton.Toolkit.KryptonButton(); + contentPanel = new TableLayoutPanel(); + tableLayoutPanel2 = new TableLayoutPanel(); + userNameLabel = new Krypton.Toolkit.KryptonLabel(); + userLocalNameLabel = new Krypton.Toolkit.KryptonLabel(); + userMobileLabel = new Krypton.Toolkit.KryptonLabel(); + userIsValidIndcChk = new Krypton.Toolkit.KryptonCheckBox(); + userNameTxt = new Krypton.Toolkit.KryptonTextBox(); + userLocalNameTxt = new Krypton.Toolkit.KryptonTextBox(); + userMobileTxt = new Krypton.Toolkit.KryptonTextBox(); + userTypeLabel = new Krypton.Toolkit.KryptonLabel(); + userTypeCombo = new Krypton.Toolkit.KryptonComboBox(); + kryptonPanel2 = new Krypton.Toolkit.KryptonPanel(); + splitContainer1 = new SplitContainer(); + tableLayoutPanel3 = new TableLayoutPanel(); + tableLayoutPanel4 = new TableLayoutPanel(); + kryptonHeader1 = new Krypton.Toolkit.KryptonHeader(); + selectedGv = new Krypton.Toolkit.KryptonDataGridView(); + actorNameSelectedCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + actorLocalNameSelectedCol = new DataGridViewComboBoxColumn(); + tableLayoutPanel5 = new TableLayoutPanel(); + deselectedBut = new Krypton.Toolkit.KryptonButton(); + selectedBut = new Krypton.Toolkit.KryptonButton(); + tableLayoutPanel6 = new TableLayoutPanel(); + kryptonHeader2 = new Krypton.Toolkit.KryptonHeader(); + deselectedGv = new Krypton.Toolkit.KryptonDataGridView(); + actorNameCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + actorLocalNameCol = new DataGridViewComboBoxColumn(); + mainPanel.SuspendLayout(); + topPanel.SuspendLayout(); + searchPanel.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)kryptonPanel1).BeginInit(); + bottomPanel.SuspendLayout(); + savePanel.SuspendLayout(); + operationPanel.SuspendLayout(); + contentPanel.SuspendLayout(); + tableLayoutPanel2.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)userTypeCombo).BeginInit(); + ((System.ComponentModel.ISupportInitialize)kryptonPanel2).BeginInit(); + ((System.ComponentModel.ISupportInitialize)splitContainer1).BeginInit(); + splitContainer1.Panel1.SuspendLayout(); + splitContainer1.Panel2.SuspendLayout(); + splitContainer1.SuspendLayout(); + tableLayoutPanel3.SuspendLayout(); + tableLayoutPanel4.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)selectedGv).BeginInit(); + tableLayoutPanel5.SuspendLayout(); + tableLayoutPanel6.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)deselectedGv).BeginInit(); + SuspendLayout(); + // + // mainPanel + // + mainPanel.ColumnCount = 1; + mainPanel.ColumnStyles.Add(new ColumnStyle()); + mainPanel.Controls.Add(topPanel, 0, 0); + mainPanel.Controls.Add(kryptonPanel1, 0, 1); + mainPanel.Controls.Add(bottomPanel, 0, 3); + mainPanel.Controls.Add(contentPanel, 0, 2); + mainPanel.Dock = DockStyle.Fill; + mainPanel.Location = new Point(0, 0); + mainPanel.Name = "mainPanel"; + mainPanel.RowCount = 4; + mainPanel.RowStyles.Add(new RowStyle()); + mainPanel.RowStyles.Add(new RowStyle()); + mainPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 100F)); + mainPanel.RowStyles.Add(new RowStyle()); + mainPanel.Size = new Size(1024, 800); + mainPanel.TabIndex = 0; + // + // topPanel + // + topPanel.AutoSize = true; + topPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + topPanel.ColumnCount = 3; + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.ColumnStyles.Add(new ColumnStyle()); + topPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 20F)); + topPanel.Controls.Add(searchPanel, 3, 0); + topPanel.Controls.Add(userNameSearchLabel, 0, 0); + topPanel.Controls.Add(userNameSearchTxt, 1, 0); + topPanel.Dock = DockStyle.Fill; + topPanel.Location = new Point(3, 3); + topPanel.Name = "topPanel"; + topPanel.RowCount = 1; + topPanel.RowStyles.Add(new RowStyle()); + topPanel.Size = new Size(1018, 31); + topPanel.TabIndex = 0; + // + // searchPanel + // + searchPanel.AutoSize = true; + searchPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + searchPanel.ColumnCount = 3; + searchPanel.ColumnStyles.Add(new ColumnStyle()); + searchPanel.ColumnStyles.Add(new ColumnStyle()); + searchPanel.ColumnStyles.Add(new ColumnStyle()); + searchPanel.Controls.Add(createBut, 2, 0); + searchPanel.Controls.Add(resetBut, 1, 0); + searchPanel.Controls.Add(searchBut, 0, 0); + searchPanel.Location = new Point(424, 0); + searchPanel.Margin = new Padding(60, 0, 0, 0); + searchPanel.Name = "searchPanel"; + searchPanel.RowCount = 1; + searchPanel.RowStyles.Add(new RowStyle()); + searchPanel.Size = new Size(288, 31); + searchPanel.TabIndex = 0; + // + // createBut + // + createBut.Location = new Point(195, 3); + createBut.Name = "createBut"; + createBut.Size = new Size(90, 25); + createBut.TabIndex = 3; + createBut.Values.Image = Properties.Resources.create_16; + createBut.Values.Text = "新增(&C)"; + createBut.Click += createBut_Click; + // + // resetBut + // + resetBut.Location = new Point(99, 3); + resetBut.Name = "resetBut"; + resetBut.Size = new Size(90, 25); + resetBut.TabIndex = 2; + resetBut.Values.Image = Properties.Resources.reset_16; + resetBut.Values.Text = "重置(&R)"; + resetBut.Click += resetBut_Click; + // + // searchBut + // + searchBut.Location = new Point(3, 3); + searchBut.Name = "searchBut"; + searchBut.Size = new Size(90, 25); + searchBut.TabIndex = 1; + searchBut.Values.Image = Properties.Resources.search_16; + searchBut.Values.Text = "查询(&S)"; + searchBut.Click += searchBut_Click; + // + // userNameSearchLabel + // + userNameSearchLabel.Location = new Point(3, 3); + userNameSearchLabel.Name = "userNameSearchLabel"; + userNameSearchLabel.Size = new Size(52, 20); + userNameSearchLabel.TabIndex = 1; + userNameSearchLabel.Values.Text = "用户名:"; + // + // userNameSearchTxt + // + userNameSearchTxt.ButtonSpecs.Add(userNameSearchBut); + userNameSearchTxt.Location = new Point(61, 3); + userNameSearchTxt.Name = "userNameSearchTxt"; + userNameSearchTxt.Size = new Size(300, 23); + userNameSearchTxt.TabIndex = 2; + // + // userNameSearchBut + // + userNameSearchBut.Type = Krypton.Toolkit.PaletteButtonSpecStyle.WorkspaceMaximize; + userNameSearchBut.UniqueName = "3a322a66645f4aff808be4720c638ad8"; + userNameSearchBut.Click += userNameSearchBut_Click; + // + // kryptonPanel1 + // + kryptonPanel1.Dock = DockStyle.Fill; + kryptonPanel1.Location = new Point(3, 40); + kryptonPanel1.Name = "kryptonPanel1"; + kryptonPanel1.Size = new Size(1018, 5); + kryptonPanel1.TabIndex = 1; + // + // bottomPanel + // + bottomPanel.AutoSize = true; + bottomPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + bottomPanel.ColumnCount = 1; + bottomPanel.ColumnStyles.Add(new ColumnStyle()); + bottomPanel.Controls.Add(savePanel, 0, 0); + bottomPanel.Controls.Add(operationPanel, 0, 1); + bottomPanel.Location = new Point(0, 726); + bottomPanel.Margin = new Padding(0); + bottomPanel.Name = "bottomPanel"; + bottomPanel.RowCount = 2; + bottomPanel.RowStyles.Add(new RowStyle()); + bottomPanel.RowStyles.Add(new RowStyle()); + bottomPanel.Size = new Size(198, 74); + bottomPanel.TabIndex = 2; + // + // savePanel + // + savePanel.AutoSize = true; + savePanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + savePanel.ColumnCount = 2; + savePanel.ColumnStyles.Add(new ColumnStyle()); + savePanel.ColumnStyles.Add(new ColumnStyle()); + savePanel.Controls.Add(cancelBut, 1, 0); + savePanel.Controls.Add(saveBut, 0, 0); + savePanel.Location = new Point(3, 3); + savePanel.Name = "savePanel"; + savePanel.RowCount = 1; + savePanel.RowStyles.Add(new RowStyle()); + savePanel.Size = new Size(192, 31); + savePanel.TabIndex = 0; + // + // cancelBut + // + cancelBut.Location = new Point(99, 3); + cancelBut.Name = "cancelBut"; + cancelBut.Size = new Size(90, 25); + cancelBut.TabIndex = 2; + cancelBut.Values.Image = Properties.Resources.cancel_16; + cancelBut.Values.Text = "取消(&L)"; + cancelBut.Click += cancelBut_Click; + // + // saveBut + // + saveBut.Location = new Point(3, 3); + saveBut.Name = "saveBut"; + saveBut.Size = new Size(90, 25); + saveBut.TabIndex = 1; + saveBut.Values.Image = Properties.Resources.save_16; + saveBut.Values.Text = "保存(&S)"; + saveBut.Click += saveBut_Click; + // + // operationPanel + // + operationPanel.AutoSize = true; + operationPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + operationPanel.ColumnCount = 2; + operationPanel.ColumnStyles.Add(new ColumnStyle()); + operationPanel.ColumnStyles.Add(new ColumnStyle()); + operationPanel.Controls.Add(deleteBut, 1, 0); + operationPanel.Controls.Add(amendBut, 0, 0); + operationPanel.Location = new Point(3, 40); + operationPanel.Name = "operationPanel"; + operationPanel.RowCount = 1; + operationPanel.RowStyles.Add(new RowStyle()); + operationPanel.Size = new Size(192, 31); + operationPanel.TabIndex = 0; + // + // deleteBut + // + deleteBut.Location = new Point(99, 3); + deleteBut.Name = "deleteBut"; + deleteBut.Size = new Size(90, 25); + deleteBut.TabIndex = 2; + deleteBut.Values.Image = Properties.Resources.delete_16; + deleteBut.Values.Text = "删除(&D)"; + deleteBut.Click += deleteBut_Click; + // + // amendBut + // + amendBut.Location = new Point(3, 3); + amendBut.Name = "amendBut"; + amendBut.Size = new Size(90, 25); + amendBut.TabIndex = 1; + amendBut.Values.Image = Properties.Resources.amend_16; + amendBut.Values.Text = "修改(&M)"; + amendBut.Click += amendBut_Click; + // + // contentPanel + // + contentPanel.ColumnCount = 1; + contentPanel.ColumnStyles.Add(new ColumnStyle()); + contentPanel.Controls.Add(tableLayoutPanel2, 0, 0); + contentPanel.Controls.Add(kryptonPanel2, 0, 1); + contentPanel.Controls.Add(splitContainer1, 0, 2); + contentPanel.Dock = DockStyle.Fill; + contentPanel.Location = new Point(3, 51); + contentPanel.Name = "contentPanel"; + contentPanel.RowCount = 3; + contentPanel.RowStyles.Add(new RowStyle()); + contentPanel.RowStyles.Add(new RowStyle()); + contentPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 100F)); + contentPanel.Size = new Size(1018, 672); + contentPanel.TabIndex = 3; + // + // tableLayoutPanel2 + // + tableLayoutPanel2.AutoSize = true; + tableLayoutPanel2.AutoSizeMode = AutoSizeMode.GrowAndShrink; + tableLayoutPanel2.ColumnCount = 2; + tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel2.Controls.Add(userNameLabel, 0, 0); + tableLayoutPanel2.Controls.Add(userLocalNameLabel, 0, 1); + tableLayoutPanel2.Controls.Add(userMobileLabel, 0, 2); + tableLayoutPanel2.Controls.Add(userIsValidIndcChk, 1, 4); + tableLayoutPanel2.Controls.Add(userNameTxt, 1, 0); + tableLayoutPanel2.Controls.Add(userLocalNameTxt, 1, 1); + tableLayoutPanel2.Controls.Add(userMobileTxt, 1, 2); + tableLayoutPanel2.Controls.Add(userTypeLabel, 0, 3); + tableLayoutPanel2.Controls.Add(userTypeCombo, 1, 3); + tableLayoutPanel2.Location = new Point(3, 3); + tableLayoutPanel2.Name = "tableLayoutPanel2"; + tableLayoutPanel2.RowCount = 5; + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.Size = new Size(377, 141); + tableLayoutPanel2.TabIndex = 0; + // + // userNameLabel + // + userNameLabel.Location = new Point(3, 3); + userNameLabel.Name = "userNameLabel"; + userNameLabel.Size = new Size(52, 20); + userNameLabel.TabIndex = 1; + userNameLabel.Values.Text = "用户名:"; + // + // userLocalNameLabel + // + userLocalNameLabel.Location = new Point(3, 32); + userLocalNameLabel.Name = "userLocalNameLabel"; + userLocalNameLabel.Size = new Size(39, 20); + userLocalNameLabel.TabIndex = 1; + userLocalNameLabel.Values.Text = "昵称:"; + // + // userMobileLabel + // + userMobileLabel.Location = new Point(3, 61); + userMobileLabel.Name = "userMobileLabel"; + userMobileLabel.Size = new Size(65, 20); + userMobileLabel.TabIndex = 1; + userMobileLabel.Values.Text = "手机号码:"; + // + // userIsValidIndcChk + // + userIsValidIndcChk.Location = new Point(74, 118); + userIsValidIndcChk.Name = "userIsValidIndcChk"; + userIsValidIndcChk.Size = new Size(55, 20); + userIsValidIndcChk.TabIndex = 2; + userIsValidIndcChk.Values.Text = "有效?"; + // + // userNameTxt + // + userNameTxt.Dock = DockStyle.Fill; + userNameTxt.Location = new Point(74, 3); + userNameTxt.MaxLength = 50; + userNameTxt.Name = "userNameTxt"; + userNameTxt.Size = new Size(300, 23); + userNameTxt.TabIndex = 3; + // + // userLocalNameTxt + // + userLocalNameTxt.Dock = DockStyle.Fill; + userLocalNameTxt.Location = new Point(74, 32); + userLocalNameTxt.MaxLength = 50; + userLocalNameTxt.Name = "userLocalNameTxt"; + userLocalNameTxt.Size = new Size(300, 23); + userLocalNameTxt.TabIndex = 3; + // + // userMobileTxt + // + userMobileTxt.Dock = DockStyle.Fill; + userMobileTxt.Location = new Point(74, 61); + userMobileTxt.MaxLength = 50; + userMobileTxt.Name = "userMobileTxt"; + userMobileTxt.Size = new Size(300, 23); + userMobileTxt.TabIndex = 3; + // + // userTypeLabel + // + userTypeLabel.Location = new Point(3, 90); + userTypeLabel.Name = "userTypeLabel"; + userTypeLabel.Size = new Size(65, 20); + userTypeLabel.TabIndex = 1; + userTypeLabel.Values.Text = "用户类型:"; + // + // userTypeCombo + // + userTypeCombo.Dock = DockStyle.Fill; + userTypeCombo.DropDownStyle = ComboBoxStyle.DropDownList; + userTypeCombo.DropDownWidth = 300; + userTypeCombo.IntegralHeight = false; + userTypeCombo.Location = new Point(74, 90); + userTypeCombo.Name = "userTypeCombo"; + userTypeCombo.Size = new Size(300, 22); + userTypeCombo.StateCommon.ComboBox.Content.TextH = Krypton.Toolkit.PaletteRelativeAlign.Near; + userTypeCombo.TabIndex = 4; + // + // kryptonPanel2 + // + kryptonPanel2.Dock = DockStyle.Fill; + kryptonPanel2.Location = new Point(3, 150); + kryptonPanel2.Name = "kryptonPanel2"; + kryptonPanel2.Size = new Size(1018, 5); + kryptonPanel2.TabIndex = 1; + // + // splitContainer1 + // + splitContainer1.BackColor = SystemColors.GradientActiveCaption; + splitContainer1.Dock = DockStyle.Fill; + splitContainer1.Location = new Point(3, 161); + splitContainer1.Name = "splitContainer1"; + // + // splitContainer1.Panel1 + // + splitContainer1.Panel1.Controls.Add(tableLayoutPanel3); + // + // splitContainer1.Panel2 + // + splitContainer1.Panel2.Controls.Add(tableLayoutPanel6); + splitContainer1.Size = new Size(1018, 508); + splitContainer1.SplitterDistance = 500; + splitContainer1.SplitterWidth = 8; + splitContainer1.TabIndex = 2; + // + // tableLayoutPanel3 + // + tableLayoutPanel3.BackColor = SystemColors.Control; + tableLayoutPanel3.ColumnCount = 2; + tableLayoutPanel3.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F)); + tableLayoutPanel3.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel3.Controls.Add(tableLayoutPanel4, 0, 0); + tableLayoutPanel3.Controls.Add(tableLayoutPanel5, 1, 0); + tableLayoutPanel3.Dock = DockStyle.Fill; + tableLayoutPanel3.Location = new Point(0, 0); + tableLayoutPanel3.Name = "tableLayoutPanel3"; + tableLayoutPanel3.RowCount = 1; + tableLayoutPanel3.RowStyles.Add(new RowStyle()); + tableLayoutPanel3.Size = new Size(500, 508); + tableLayoutPanel3.TabIndex = 0; + // + // tableLayoutPanel4 + // + tableLayoutPanel4.ColumnCount = 1; + tableLayoutPanel4.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F)); + tableLayoutPanel4.Controls.Add(kryptonHeader1, 0, 0); + tableLayoutPanel4.Controls.Add(selectedGv, 0, 1); + tableLayoutPanel4.Dock = DockStyle.Fill; + tableLayoutPanel4.Location = new Point(0, 0); + tableLayoutPanel4.Margin = new Padding(0); + tableLayoutPanel4.Name = "tableLayoutPanel4"; + tableLayoutPanel4.RowCount = 2; + tableLayoutPanel4.RowStyles.Add(new RowStyle()); + tableLayoutPanel4.RowStyles.Add(new RowStyle(SizeType.Percent, 50F)); + tableLayoutPanel4.Size = new Size(458, 536); + tableLayoutPanel4.TabIndex = 1; + // + // kryptonHeader1 + // + kryptonHeader1.Dock = DockStyle.Top; + kryptonHeader1.Location = new Point(0, 0); + kryptonHeader1.Margin = new Padding(0); + kryptonHeader1.Name = "kryptonHeader1"; + kryptonHeader1.Size = new Size(458, 31); + kryptonHeader1.TabIndex = 0; + kryptonHeader1.Values.Description = ""; + kryptonHeader1.Values.Heading = "授权角色"; + kryptonHeader1.Values.Image = null; + // + // selectedGv + // + selectedGv.AllowUserToAddRows = false; + selectedGv.AllowUserToDeleteRows = false; + selectedGv.BorderStyle = BorderStyle.None; + selectedGv.Columns.AddRange(new DataGridViewColumn[] { actorNameSelectedCol, actorLocalNameSelectedCol }); + selectedGv.Dock = DockStyle.Fill; + selectedGv.Location = new Point(0, 31); + selectedGv.Margin = new Padding(0); + selectedGv.Name = "selectedGv"; + selectedGv.Size = new Size(458, 505); + selectedGv.TabIndex = 2; + selectedGv.CellDoubleClick += selectedGv_CellDoubleClick; + // + // actorNameSelectedCol + // + actorNameSelectedCol.DataPropertyName = "ActorName"; + actorNameSelectedCol.DefaultCellStyle = dataGridViewCellStyle1; + actorNameSelectedCol.HeaderText = "角色名"; + actorNameSelectedCol.Name = "actorNameSelectedCol"; + actorNameSelectedCol.Width = 200; + // + // actorLocalNameSelectedCol + // + actorLocalNameSelectedCol.DataPropertyName = "ActorName"; + actorLocalNameSelectedCol.DisplayStyle = DataGridViewComboBoxDisplayStyle.Nothing; + actorLocalNameSelectedCol.HeaderText = "角色名称"; + actorLocalNameSelectedCol.Name = "actorLocalNameSelectedCol"; + actorLocalNameSelectedCol.Resizable = DataGridViewTriState.True; + actorLocalNameSelectedCol.Width = 200; + // + // tableLayoutPanel5 + // + tableLayoutPanel5.AutoSize = true; + tableLayoutPanel5.ColumnCount = 1; + tableLayoutPanel5.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel5.Controls.Add(deselectedBut, 0, 2); + tableLayoutPanel5.Controls.Add(selectedBut, 0, 1); + tableLayoutPanel5.Dock = DockStyle.Fill; + tableLayoutPanel5.Location = new Point(461, 3); + tableLayoutPanel5.Name = "tableLayoutPanel5"; + tableLayoutPanel5.RowCount = 4; + tableLayoutPanel5.RowStyles.Add(new RowStyle(SizeType.Percent, 50F)); + tableLayoutPanel5.RowStyles.Add(new RowStyle()); + tableLayoutPanel5.RowStyles.Add(new RowStyle()); + tableLayoutPanel5.RowStyles.Add(new RowStyle(SizeType.Percent, 50F)); + tableLayoutPanel5.Size = new Size(36, 530); + tableLayoutPanel5.TabIndex = 1; + // + // deselectedBut + // + deselectedBut.Location = new Point(3, 295); + deselectedBut.Margin = new Padding(3, 30, 3, 3); + deselectedBut.Name = "deselectedBut"; + deselectedBut.Size = new Size(30, 25); + deselectedBut.TabIndex = 0; + deselectedBut.Values.Image = Properties.Resources.MovePrevious; + deselectedBut.Values.Text = ""; + deselectedBut.Click += deselectedBut_Click; + // + // selectedBut + // + selectedBut.Location = new Point(3, 210); + selectedBut.Margin = new Padding(3, 3, 3, 30); + selectedBut.Name = "selectedBut"; + selectedBut.Size = new Size(30, 25); + selectedBut.TabIndex = 0; + selectedBut.Values.Image = Properties.Resources.MoveNext; + selectedBut.Values.Text = ""; + selectedBut.Click += selectedBut_Click; + // + // tableLayoutPanel6 + // + tableLayoutPanel6.BackColor = SystemColors.Control; + tableLayoutPanel6.ColumnCount = 1; + tableLayoutPanel6.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F)); + tableLayoutPanel6.Controls.Add(kryptonHeader2, 0, 0); + tableLayoutPanel6.Controls.Add(deselectedGv, 0, 1); + tableLayoutPanel6.Dock = DockStyle.Fill; + tableLayoutPanel6.Location = new Point(0, 0); + tableLayoutPanel6.Name = "tableLayoutPanel6"; + tableLayoutPanel6.Padding = new Padding(4, 0, 0, 0); + tableLayoutPanel6.RowCount = 2; + tableLayoutPanel6.RowStyles.Add(new RowStyle()); + tableLayoutPanel6.RowStyles.Add(new RowStyle(SizeType.Percent, 83.39552F)); + tableLayoutPanel6.Size = new Size(510, 508); + tableLayoutPanel6.TabIndex = 0; + // + // kryptonHeader2 + // + kryptonHeader2.Dock = DockStyle.Top; + kryptonHeader2.Location = new Point(4, 0); + kryptonHeader2.Margin = new Padding(0); + kryptonHeader2.Name = "kryptonHeader2"; + kryptonHeader2.Size = new Size(506, 31); + kryptonHeader2.TabIndex = 1; + kryptonHeader2.Values.Description = ""; + kryptonHeader2.Values.Heading = "未授权角色"; + kryptonHeader2.Values.Image = null; + // + // deselectedGv + // + deselectedGv.AllowUserToAddRows = false; + deselectedGv.AllowUserToDeleteRows = false; + deselectedGv.BorderStyle = BorderStyle.None; + deselectedGv.Columns.AddRange(new DataGridViewColumn[] { actorNameCol, actorLocalNameCol }); + deselectedGv.Dock = DockStyle.Fill; + deselectedGv.Location = new Point(4, 31); + deselectedGv.Margin = new Padding(0); + deselectedGv.Name = "deselectedGv"; + deselectedGv.Size = new Size(506, 477); + deselectedGv.TabIndex = 1; + deselectedGv.CellDoubleClick += deselectedGv_CellDoubleClick; + // + // actorNameCol + // + actorNameCol.DataPropertyName = "ActorName"; + actorNameCol.DefaultCellStyle = dataGridViewCellStyle2; + actorNameCol.HeaderText = "角色名"; + actorNameCol.Name = "actorNameCol"; + actorNameCol.Width = 200; + // + // actorLocalNameCol + // + actorLocalNameCol.DataPropertyName = "ActorName"; + actorLocalNameCol.DisplayStyle = DataGridViewComboBoxDisplayStyle.Nothing; + actorLocalNameCol.HeaderText = "角色名称"; + actorLocalNameCol.Name = "actorLocalNameCol"; + actorLocalNameCol.Resizable = DataGridViewTriState.True; + actorLocalNameCol.Width = 200; + // + // SecurityUserOperationPage + // + AutoScaleDimensions = new SizeF(7F, 15F); + AutoScaleMode = AutoScaleMode.Font; + Controls.Add(mainPanel); + Name = "SecurityUserOperationPage"; + mainPanel.ResumeLayout(false); + mainPanel.PerformLayout(); + topPanel.ResumeLayout(false); + topPanel.PerformLayout(); + searchPanel.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)kryptonPanel1).EndInit(); + bottomPanel.ResumeLayout(false); + bottomPanel.PerformLayout(); + savePanel.ResumeLayout(false); + operationPanel.ResumeLayout(false); + contentPanel.ResumeLayout(false); + contentPanel.PerformLayout(); + tableLayoutPanel2.ResumeLayout(false); + tableLayoutPanel2.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)userTypeCombo).EndInit(); + ((System.ComponentModel.ISupportInitialize)kryptonPanel2).EndInit(); + splitContainer1.Panel1.ResumeLayout(false); + splitContainer1.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)splitContainer1).EndInit(); + splitContainer1.ResumeLayout(false); + tableLayoutPanel3.ResumeLayout(false); + tableLayoutPanel3.PerformLayout(); + tableLayoutPanel4.ResumeLayout(false); + tableLayoutPanel4.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)selectedGv).EndInit(); + tableLayoutPanel5.ResumeLayout(false); + tableLayoutPanel6.ResumeLayout(false); + tableLayoutPanel6.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)deselectedGv).EndInit(); + ResumeLayout(false); + } + + #endregion + + private TableLayoutPanel mainPanel; + private TableLayoutPanel topPanel; + private TableLayoutPanel searchPanel; + private Krypton.Toolkit.KryptonButton createBut; + private Krypton.Toolkit.KryptonButton resetBut; + private Krypton.Toolkit.KryptonButton searchBut; + private Krypton.Toolkit.KryptonLabel userNameSearchLabel; + private Krypton.Toolkit.KryptonTextBox userNameSearchTxt; + private Krypton.Toolkit.ButtonSpecAny userNameSearchBut; + private Krypton.Toolkit.KryptonPanel kryptonPanel1; + private TableLayoutPanel bottomPanel; + private TableLayoutPanel savePanel; + private TableLayoutPanel operationPanel; + private Krypton.Toolkit.KryptonButton saveBut; + private Krypton.Toolkit.KryptonButton cancelBut; + private Krypton.Toolkit.KryptonButton amendBut; + private Krypton.Toolkit.KryptonButton deleteBut; + private TableLayoutPanel contentPanel; + private TableLayoutPanel tableLayoutPanel2; + private Krypton.Toolkit.KryptonLabel userNameLabel; + private Krypton.Toolkit.KryptonLabel userLocalNameLabel; + private Krypton.Toolkit.KryptonLabel userMobileLabel; + private Krypton.Toolkit.KryptonCheckBox userIsValidIndcChk; + private Krypton.Toolkit.KryptonTextBox userNameTxt; + private Krypton.Toolkit.KryptonTextBox userLocalNameTxt; + private Krypton.Toolkit.KryptonTextBox userMobileTxt; + private Krypton.Toolkit.KryptonPanel kryptonPanel2; + private SplitContainer splitContainer1; + private TableLayoutPanel tableLayoutPanel3; + private TableLayoutPanel tableLayoutPanel4; + private TableLayoutPanel tableLayoutPanel5; + private Krypton.Toolkit.KryptonHeader kryptonHeader1; + private Krypton.Toolkit.KryptonDataGridView deselectedGv; + private Krypton.Toolkit.KryptonButton deselectedBut; + private Krypton.Toolkit.KryptonButton selectedBut; + private TableLayoutPanel tableLayoutPanel6; + private Krypton.Toolkit.KryptonDataGridView selectedGv; + private Krypton.Toolkit.KryptonHeader kryptonHeader2; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn actorNameSelectedCol; + private DataGridViewComboBoxColumn actorLocalNameSelectedCol; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn actorNameCol; + private DataGridViewComboBoxColumn actorLocalNameCol; + private Krypton.Toolkit.KryptonLabel userTypeLabel; + private Krypton.Toolkit.KryptonComboBox userTypeCombo; + } +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Security.Gui/SecurityUserOperationPage.cs b/CloudBuilder/CloudBuilder.Security.Gui/SecurityUserOperationPage.cs new file mode 100644 index 0000000..67ea99f --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/SecurityUserOperationPage.cs @@ -0,0 +1,586 @@ +using CloudBuilder.Core.Service; +using CloudBuilder.Gui; +using CloudBuilder.Request.Security; +using CloudBuilder.Security.Data; +using CloudBuilder.Security.Entity; +using CloudBuilder.Security.Linkup; +using CloudBuilder.Security.Policy; +using Krypton.Toolkit; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http.Extensions; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Net; +using System.Security.Permissions; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace CloudBuilder.Security.Gui +{ + public partial class SecurityUserOperationPage : AbstractPage + { + private SecurityMessagePolicy securityMessagePolicy; + private SecurityUserTypePolicy securityUserTypePolicy; + private SecurityUserData data; + private SecurityUserDisplayData securityUserEntity; + private SecurityActorEntity[] securityActors = null; + private SecurityUserRequest securityUserRequest; + + //初始化Page,注入容器内,不要在此做任何事情 + public SecurityUserOperationPage() + { + InitializeComponent(); + } + + /// + /// 第一次加载时执行,只执行一次 + /// + public override void FunctionLoaded() + { + HandleException(() => OnFunctionLoaded()); + } + + private void OnFunctionLoaded() + { + base.FunctionLoaded(); + //初始化容器------------------------------------- + securityMessagePolicy = ServiceHelper.GetTypeService()!; + securityUserRequest = ServiceHelper.GetTypeService(); + securityUserTypePolicy = ServiceHelper.GetTypeService()!; + //界面初始化 + InitGui(); + } + + + private void InitGui() + { + InitBindingContext(); + + InitComBox(); + + InitDisplayMode(); + + this.ParentAbstractForm.AcceptButton = this.searchBut; + this.ParentAbstractForm.CancelButton = this.resetBut; + } + + private void InitComBox() + { + userTypeCombo.SetDataSource(securityUserTypePolicy.GetDataSource(), true); + + SecurityActorRequest securityActorRequest = ServiceHelper.GetTypeService(); + securityActors = securityActorRequest.FindAllByNoPermission(); + + deselectedGv.SetColumnDataSource(actorLocalNameCol, securityActors, SecurityActorEntity.ACTOR_LOCAL_NAME, SecurityActorEntity.ACTOR_NAME, true); + selectedGv.SetColumnDataSource(actorLocalNameSelectedCol, securityActors, SecurityActorEntity.ACTOR_LOCAL_NAME, SecurityActorEntity.ACTOR_NAME, true); + } + + /// + /// 有特殊要求的UI控件初始化设置,Init与Add配对后,使用guiOperateHelper管理 + /// + private void InitBindingContext() + { + //需要绑定数据 + guiBindingContext = new GuiBindingContext(); + + InitPermission(); + + userNameTxt.Set(SecurityUserEntity.USER_NAME, userNameLabel.Text, EnumEditModeColor.Required); + userLocalNameTxt.Set(SecurityUserEntity.USER_LOCAL_NAME); + userMobileTxt.Set(SecurityUserEntity.USER_MOBILE, userMobileLabel.Text, EnumEditModeColor.Required); + userIsValidIndcChk.Set(SecurityUserEntity.USER_IS_VALID_INDC, EnumBindDirection.Both); + userTypeCombo.Set(SecurityUserEntity.USER_TYPE, userTypeLabel.Text, EnumEditModeColor.Required); + selectedGv.InitColumn(false, true); + deselectedGv.InitColumn(false, true); + + guiOperateHelper = new GuiOperateHelper(); + } + + private void InitPermission() + { + createBut.Set(SecurityPermissionPolicy.SecurityUser, Operate.Insert); + amendBut.Set(SecurityPermissionPolicy.SecurityUser, Operate.Update); + deleteBut.Set(SecurityPermissionPolicy.SecurityUser, Operate.Delete); + } + + /// + /// 每次从别的界面进入时执行,发生在FunctionLoaded之后 + /// + /// + public override void FunctionActivated(object param) + { + try + { + if (param == null) + { + userNameSearchTxt.Focus(); + return; + } + + InitDisplayMode(); + + SecurityUserOperationLinkup linkup = null; + + if (param is SecurityUserOperationLinkup) + { + linkup = (SecurityUserOperationLinkup)param; + } + + this.DisplayMode = (GuiDisplayMode)linkup.DisplayMode; + + userNameSearchTxt.Text = linkup.UserName; + + if (this.DisplayMode == GuiDisplayMode.View) + { + Search(); + } + else if (this.DisplayMode == GuiDisplayMode.Create) + { + Create(); + } + else if (this.DisplayMode == GuiDisplayMode.Amend) + { + Search(); + Amend(); + } + + userNameSearchTxt.Focus(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + public override void FunctionSelected() + { + this.ParentAbstractForm.AcceptButton = this.searchBut; + if (!IsDialog) + this.ParentAbstractForm.CancelButton = this.resetBut; + else + this.ParentAbstractForm.CancelButton = this.cancelBut; + + userNameSearchTxt.Focus(); + } + + public override bool FunctionDeactivating() + { + if (this.DisplayMode == GuiDisplayMode.View) + { + return true; + } + else + { + return CancelEditing(); + } + } + + private bool CancelEditing() + { + DialogResult result = ShowMessageBox.ShowOption(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_CONFIRM_CANCEL), securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_CONFIRM)); + + //从外部跳转(非mainKryptonNavigator),result第一次不生效?,所以再执行一次生效 + if (result == DialogResult.Cancel) + { + result = ShowMessageBox.ShowOption(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_CONFIRM_CANCEL), securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_CONFIRM)); + } + + if (result == DialogResult.No) + { + return false; + } + + Cancel(); + + return true; + } + + private void InitDisplayMode() + { + this.DisplayMode = GuiDisplayMode.View; + + SetDisplayMode(); + } + + private void SetDisplayMode() + { + if (this.DisplayMode == GuiDisplayMode.View) + { + savePanel.Visible = false; + operationPanel.Visible = true; + + guiOperateHelper.EnableControls(true, topPanel); + guiOperateHelper.EnableControls(false, contentPanel); + //查詢有記錄時,修改等控件有效 + if (securityUserEntity != null) + guiOperateHelper.EnableControls(true, bottomPanel); + else + guiOperateHelper.EnableControls(false, bottomPanel); + } + else if (this.DisplayMode == GuiDisplayMode.Amend || this.DisplayMode == GuiDisplayMode.Create) + { + savePanel.Visible = true; + operationPanel.Visible = false; + + guiOperateHelper.EnableControls(false, topPanel); + guiOperateHelper.EnableControls(true, bottomPanel, contentPanel); + + if (this.DisplayMode == GuiDisplayMode.Amend) guiOperateHelper.EnableControls(false, userNameTxt); + } + + guiOperateHelper.EnableControls(false, deselectedGv, selectedGv); + } + + private void PackUIToEntity() + { + guiBindingContext.DataPack(); + + SecurityActorEntity[] actors = selectedGv.GetAllRows(); + if (actors != null && actors.Length > 0) + data.SecurityUserActors = actors.Select(x => new SecurityUserActorViewEntity() { UserName = userNameTxt.Text, ActorName = x.ActorName, UserLocalName = string.Empty }).ToArray(); + else data.SecurityUserActors = null; + } + private bool SaveValidate() + { + if (!guiOperateHelper.CheckValidate(this.mainPanel)) return false; + + return true; + } + + private void Search() + { + try + { + if (string.IsNullOrEmpty(userNameSearchTxt.Text)) return; + + Reset(); + + data = securityUserRequest.FindByKey(userNameSearchTxt.Text); + + if (data == null || data.SecurityUser == null) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + } + else + { + securityUserEntity = data.SecurityUser; + + PackEntityToUI(); + + SetDisplayMode(); + } + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void Create() + { + this.DisplayMode = GuiDisplayMode.Create; + + guiOperateHelper.ResetControls(this.mainPanel); + + SetDisplayMode(); + + data = new SecurityUserData(); + securityUserEntity = new SecurityUserDisplayData() + { + CreatedBy = string.Empty, + UpdatedBy = string.Empty, + CreatedDatetime = DateTime.Now, + UpdatedDatetime = DateTime.Now, + UserType = SecurityUserTypePolicy.NORMAL_USERS + }; + data.SecurityUser = securityUserEntity; + + PackEntityToUI(); + + userNameTxt.Focus(); + } + + private void Amend() + { + this.DisplayMode = GuiDisplayMode.Amend; + + SetDisplayMode(); + } + + private void PackEntityToUI() + { + guiBindingContext.DataBind(data.SecurityUser, this); ; + + SecurityActorEntity[] allActors = securityActors; + SecurityActorEntity[] deselecteds = null; + SecurityActorEntity[] selecteds = null; + if (data.SecurityUserActors != null && securityActors != null) + { + deselecteds = allActors.Where(x => !data.SecurityUserActors.Select(y => y.ActorName).Contains(x.ActorName)).ToArray(); + selecteds = allActors.Where(x => data.SecurityUserActors.Select(y => y.ActorName).Contains(x.ActorName)).ToArray(); + } + else + { + deselecteds = allActors; + } + + deselectedGv.SetDataSource(deselecteds); + selectedGv.SetDataSource(selecteds); + } + + private void Reset() + { + this.DisplayMode = GuiDisplayMode.View; + + securityUserEntity = null; + + guiOperateHelper.ResetControls(this.contentPanel); + + SetDisplayMode(); + + userNameSearchTxt.Focus(); + } + + public void Cancel() + { + if (!string.IsNullOrEmpty(userNameSearchTxt.Text)) + Search(); + else + Reset(); + + } + + private void searchBut_Click(object sender, EventArgs e) + { + try + { + if (string.IsNullOrEmpty(userNameSearchTxt.Text)) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_VALID_INPUT, GuiOperateHelper.GetLabelText(userNameSearchLabel.Text))); + this.userNameSearchTxt.Focus(); + return; + } + this.DisplayMode = GuiDisplayMode.View; + + Search(); + + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void resetBut_Click(object sender, EventArgs e) + { + guiOperateHelper.ResetControls(this.topPanel); + HandleException(() => Reset()); + } + + private void createBut_Click(object sender, EventArgs e) + { + HandleException(() => Create()); + } + + private void saveBut_Click(object sender, EventArgs e) + { + try + { + if (!SaveValidate()) return; + + PackUIToEntity(); + + + if (this.DisplayMode == GuiDisplayMode.Create) + securityUserRequest.Insert(data); + else + securityUserRequest.Update(data); + + + ShowMessageBox.ShowInfo((this.DisplayMode == GuiDisplayMode.Create) ? + securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_SUCCEED_CREATED_NULL) : + securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_SUCCEED_UPDATED_NULL)); + + userNameSearchTxt.Text = securityUserEntity.UserName; + Search(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void cancelBut_Click(object sender, EventArgs e) + { + + HandleException(() => CancelEditing()); + + } + + private void amendBut_Click(object sender, EventArgs e) + { + HandleException(() => Amend()); + } + + private void deleteBut_Click(object sender, EventArgs e) + { + try + { + if (securityUserEntity == null) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + return; + } + + if (DialogResult.Yes != ShowMessageBox.ShowOption(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_CONFIRM_DEL_NULL), securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_DELETE))) return; + + securityUserRequest.Delete(securityUserEntity.UserName); + + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_SUCCEED_DELETED_NULL)); + + Reset(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void selectedBut_Click(object sender, EventArgs e) + { + if (selectedGv.RowCount <= 0 || selectedGv.SelectedCells.Count <= 0) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + return; + } + + SecurityActorEntity[] securityActors = selectedGv.GetSelectedCellsData(); + selectedGv.DeleteRows(selectedGv.SelectedCells); + + deselectedGv.AddRow(securityActors); + } + + private void deselectedBut_Click(object sender, EventArgs e) + { + if (deselectedGv.RowCount <= 0 || deselectedGv.SelectedCells.Count <= 0) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + return; + } + + SecurityActorEntity[] securityActors = deselectedGv.GetSelectedCellsData(); + deselectedGv.DeleteRows(deselectedGv.SelectedCells); + + selectedGv.AddRow(securityActors); + } + + private void userNameSearchBut_Click(object sender, EventArgs e) + { + try + { + AbstractForm dialog = GetAbstractDialog(typeof(SecurityUserEnquiryPage).Name); + + if (DialogResult.OK != dialog.ShowDialog()) return; + + userNameSearchTxt.Text = ((SecurityUserEntity[])dialog.OutputData)[0].UserName; + + Search(); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + private void selectedGv_CellDoubleClick(object sender, DataGridViewCellEventArgs e) + { + if (selectedGv.RowCount <= 0 || selectedGv.SelectedCells.Count <= 0) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + return; + } + + SecurityActorEntity data = selectedGv.GetRowData(selectedGv.SelectedCells[0].RowIndex); + + DisplayPage(GuiDisplayMode.View, data.ActorName); + } + + + private void DisplayPage(GuiDisplayMode mode, string actorName) + { + SecurityActorOperationLinkup linkupData = new SecurityActorOperationLinkup(); + linkupData.DisplayMode = Convert.ToInt32(mode); + linkupData.ActorName = actorName; + + this.DisplayAbstractPage(typeof(SecurityActorOperationPage).Name, linkupData); + } + + private void deselectedGv_CellDoubleClick(object sender, DataGridViewCellEventArgs e) + { + if (deselectedGv.RowCount <= 0 || deselectedGv.SelectedCells.Count <= 0) + { + ShowMessageBox.ShowInfo(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.GUI_WS_RECORD_NOT_FOUND)); + return; + } + + SecurityActorEntity data = deselectedGv.GetRowData(deselectedGv.SelectedCells[0].RowIndex); + + DisplayPage(GuiDisplayMode.View, data.ActorName); + } + } +} diff --git a/CloudBuilder/CloudBuilder.Security.Gui/SecurityUserOperationPage.resx b/CloudBuilder/CloudBuilder.Security.Gui/SecurityUserOperationPage.resx new file mode 100644 index 0000000..a0a8ae6 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/SecurityUserOperationPage.resx @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + True + + + True + + + True + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Security.Gui/WelcomePage.Designer.cs b/CloudBuilder/CloudBuilder.Security.Gui/WelcomePage.Designer.cs new file mode 100644 index 0000000..b5fe833 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/WelcomePage.Designer.cs @@ -0,0 +1,62 @@ +namespace CloudBuilder.Security.Gui +{ + partial class WelcomePage + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + webView = new Microsoft.Web.WebView2.WinForms.WebView2(); + ((System.ComponentModel.ISupportInitialize)webView).BeginInit(); + SuspendLayout(); + // + // webView + // + webView.AllowExternalDrop = true; + webView.CreationProperties = null; + webView.DefaultBackgroundColor = Color.White; + webView.Dock = DockStyle.Fill; + webView.Location = new Point(0, 0); + webView.Name = "webView"; + webView.Size = new Size(800, 450); + webView.TabIndex = 0; + webView.ZoomFactor = 1D; + // + // WelcomePage + // + AutoScaleDimensions = new SizeF(7F, 15F); + AutoScaleMode = AutoScaleMode.Font; + Controls.Add(webView); + Name = "WelcomePage"; + Size = new Size(800, 450); + ((System.ComponentModel.ISupportInitialize)webView).EndInit(); + ResumeLayout(false); + } + + #endregion + + private Microsoft.Web.WebView2.WinForms.WebView2 webView; + } +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Security.Gui/WelcomePage.cs b/CloudBuilder/CloudBuilder.Security.Gui/WelcomePage.cs new file mode 100644 index 0000000..2ead44c --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/WelcomePage.cs @@ -0,0 +1,78 @@ +using CloudBuilder.Core.Service; +using CloudBuilder.Gui; +using Microsoft.Web.WebView2.Core; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace CloudBuilder.Security.Gui +{ + public partial class WelcomePage : AbstractPage + { + private double currentZoomFactor = 1; + public WelcomePage() + { + InitializeComponent(); + + InitializeWebView(); + } + + private async void InitializeWebView() + { + try + { + // 初始化 CoreWebView2 + await webView.EnsureCoreWebView2Async(null); + webView.CoreWebView2.FrameNavigationCompleted += OnNavigationCompleted; + webView.CoreWebView2.NavigationCompleted += OnNavigationCompleted; + + webView.CoreWebView2.DOMContentLoaded += (sender, e) => + { + webView.ZoomFactor = currentZoomFactor; + }; + + webView.ZoomFactorChanged += (sender, e) => currentZoomFactor = webView.ZoomFactor; + + // 加载网页 + webView.CoreWebView2.Navigate("https://chat.deepseek.com/"); + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + } + + + private void OnNavigationCompleted(object sender, CoreWebView2NavigationCompletedEventArgs e) + { + if (e.IsSuccess) + { + // 小延迟确保DOM完全加载 + Task.Delay(100).ContinueWith(_ => + { + this.Invoke((MethodInvoker)delegate + { + if (Math.Abs(webView.ZoomFactor - currentZoomFactor) > 0.01f) + { + webView.ZoomFactor = currentZoomFactor; + } + }); + }); + } + } + } +} diff --git a/CloudBuilder/CloudBuilder.Security.Gui/WelcomePage.resx b/CloudBuilder/CloudBuilder.Security.Gui/WelcomePage.resx new file mode 100644 index 0000000..8b2ff64 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Gui/WelcomePage.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Security.Service/AuthService.cs b/CloudBuilder/CloudBuilder.Security.Service/AuthService.cs new file mode 100644 index 0000000..b2068f8 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Service/AuthService.cs @@ -0,0 +1,990 @@ +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.DatabaseAccessor; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using CloudBuilder.Core.DependencyInjection.EventBuses; +using CloudBuilder.Core.DependencyInjection.Request; +using CloudBuilder.Core.Policy; +using CloudBuilder.Core.Service; +using CloudBuilder.Security.Data; +using CloudBuilder.Security.Entity; +using CloudBuilder.Security.Policy; +using CloudBuilder.Security.Publisher; +using CloudBuilder.Security.Service.Authorization; +using CloudBuilder.Security.Service.Publisher; +using DocumentFormat.OpenXml.Spreadsheet; +using Fido2NetLib; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.IdentityModel.JsonWebTokens; +using Microsoft.IdentityModel.Tokens; +using Newtonsoft.Json; +using System.ComponentModel.DataAnnotations; +using System.IdentityModel.Tokens.Jwt; +using System.Runtime; +using System.Security.Cryptography; +using System.Text; +using System.Text.RegularExpressions; +using RSA = System.RSA; + +namespace CloudBuilder.Security.Service +{ + public class AuthService : IAuthService + { + private readonly IApplicationService service; + private readonly IHttpContextAccessor httpContextAccessor; + private readonly ILocaleMessageManager localeMessageManager; + private readonly IContext context; + private readonly IWebAuthnService webAuthnService; + private IRepository repository; + public AuthService(IApplicationService service, IHttpContextAccessor httpContextAccessor, ILocaleMessageManager localeMessageManager, IContext context, IWebAuthnService webAuthnService) + { + this.service = service; + this.httpContextAccessor = httpContextAccessor; + this.localeMessageManager = localeMessageManager; + this.context = context; + this.webAuthnService = webAuthnService; + repository = service.GetRepository>(); + } + + [AllowAnonymous] + [UnitOfWork] + public LoginProfile Login(LoginData data) + { + context.SetCulture(data.Culture); + string certification = localeMessageManager.ComposeMessage(typeof(AuthService).Name, "certification"); + SecurityUserEntity securityUserEntity = repository.DetachedEntities.Where(x => + (x.UserName == data.UserMobile || x.UserMobile == data.UserMobile) + && x.UserIsValidIndc == YesNoPolicy.YES).FirstOrDefault()!; + + if (securityUserEntity == null) + { + throw new ValidatedException(certification); + } + + var descKey = service.Configuration[SecuritySettingsPolicy.SecuritySettings_DescKey]; + + var privateKey = service.Configuration[SecuritySettingsPolicy.SecuritySettings_RsaPrivateKey]; + var rsa = new System.RSA(privateKey, true); + + var psd = rsa.DecodeOrNull(data.RsaUserPassword); + if (string.IsNullOrEmpty(psd)) throw new ValidatedException(certification); + //052636a8-b146-9efd-f5dc-0034a3c5bb34+password + var guid = psd.Substring(0, 36); + + + if (guid != data.Guid) + { + throw new ValidatedException(certification); + } + + if (securityUserEntity.IsAccountsLockedIndc == YesNoPolicy.YES && securityUserEntity.AccountsLockedDatetime.HasValue + && securityUserEntity.AccountsLockedDatetime.Value.Subtract(DateTime.Now).TotalMinutes > 0) + { + throw new ValidatedException(localeMessageManager.ComposeMessage("AuthService", "locked")); + } + + data.UserPassword = psd.Substring(36, psd.Length - 36); + + if (securityUserEntity.UserPassword != data.UserPassword) + { + securityUserEntity.ErrorLoginCount += 1; + //输错多少次后,账号锁定 + if (securityUserEntity.ErrorLoginCount > SecurityUserPolicy.ERROR_LOGIN_COUNT) + { + securityUserEntity.IsAccountsLockedIndc = YesNoPolicy.YES; + securityUserEntity.AccountsLockedDatetime = DateTime.Now.AddDays(1); + } + + repository.UpdateNow(securityUserEntity); + + throw new ValidatedException(certification); + } + + securityUserEntity.ErrorLoginCount = 0; + securityUserEntity.IsAccountsLockedIndc = YesNoPolicy.NO; + securityUserEntity.AccountsLockedDatetime = null; + //更新最后登录日期 + securityUserEntity.LastLoginDatetime = DateTime.Now; + + repository.UpdateNow(securityUserEntity); + + return PackLoginProfile(securityUserEntity, data.Culture); + } + + private LoginProfile PackLoginProfile(SecurityUserEntity securityUserEntity, string culture) + { + JwtGenerate jwtGenerate = service.ServiceProvider.GetService()!; + + string clainmName = Guid.NewGuid().ToString(); + Dictionary claims = new Dictionary(); + claims.Add(ClaimPolicy.CLAINM_NAME, clainmName); + claims.Add(ClaimPolicy.CLAINM_ACCOUNT, securityUserEntity.UserMobile!); + claims.Add(ClaimPolicy.CLAINM_USERID, securityUserEntity.UserName); + claims.Add(ClaimPolicy.CLAINM_LOCALE, culture); + + var accessToken = jwtGenerate.Generate(claims); + if (httpContextAccessor.HttpContext.Request.Headers.ContainsKey("Authorization")) + httpContextAccessor.HttpContext.Request.Headers.Remove("Authorization"); + httpContextAccessor.HttpContext.Request.Headers.Add("Authorization", "Bearer " + accessToken); + + if (httpContextAccessor.HttpContext.Request.Headers.ContainsKey(ClaimPolicy.HEADER_LOCALE)) + httpContextAccessor.HttpContext.Request.Headers.Remove(ClaimPolicy.HEADER_LOCALE); + httpContextAccessor.HttpContext.Request.Headers.Add(ClaimPolicy.HEADER_LOCALE, culture); + + service.UserId = securityUserEntity.UserName; + + IRepository repositoryLog = service.GetRepository>(); + + SecurityUserWebLoginEntity webLogin = new SecurityUserWebLoginEntity + { + Username = securityUserEntity.UserName, + SessionId = clainmName, + LoginTime = DateTime.Now, + HostIp = httpContextAccessor.HttpContext.Connection.RemoteIpAddress?.MapToIPv4()?.ToString(), + HostUserAgent = this.httpContextAccessor?.HttpContext?.Request.Headers.UserAgent.ToString(), + RefreshToken = jwtGenerate.GenerateRefreshToken(), + RefreshTokenRefreshedTime = DateTime.Now, + }; + + repositoryLog.InsertNow(webLogin); + PermissionContext permissionContext = new PermissionContext(service); + return new LoginProfile + { + Token = new JwtInfo() { AccessToken = accessToken, RefreshToken = webLogin.RefreshToken, CreatedTime = webLogin.RefreshTokenRefreshedTime }, + Username = securityUserEntity.UserName, + UserType = securityUserEntity.UserType, + UserLocalName = securityUserEntity.UserLocalName, + UserEngName = securityUserEntity.UserEngName, + UserMobile = securityUserEntity.UserMobile!, + PermissionInfo = permissionContext.GetUserPermissionInfo() + }; + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityUser, operate: "LoginAgent")] + [UnitOfWork] + public LoginProfile LoginAgent(LoginData data) + { + LoginProfile loginProfile = Login(data); + + SecurityUserEntity agent = repository.DetachedEntities.Where(x => + (x.UserMobile == data.AgentUserName && x.UserIsValidIndc == YesNoPolicy.YES)).FirstOrDefault()!; + + if (agent == null) + { + throw new ValidatedException("代理用户不存在."); + } + + JwtGenerate jwtGenerate = service.ServiceProvider.GetService()!; + + Dictionary claims = new Dictionary(); + claims.Add(ClaimPolicy.CLAINM_NAME, agent.UserName); + claims.Add(ClaimPolicy.CLAINM_ACCOUNT, agent.UserMobile!); + claims.Add(ClaimPolicy.CLAINM_USERID, agent.UserName); + claims.Add(ClaimPolicy.CLAINM_LOCALE, data.Culture); + + var accessToken = jwtGenerate.Generate(claims); + if (httpContextAccessor.HttpContext.Request.Headers.ContainsKey("Authorization")) + httpContextAccessor.HttpContext.Request.Headers.Remove("Authorization"); + httpContextAccessor.HttpContext.Request.Headers.Add("Authorization", "Bearer " + accessToken); + + if (httpContextAccessor.HttpContext.Request.Headers.ContainsKey(ClaimPolicy.HEADER_LOCALE)) + httpContextAccessor.HttpContext.Request.Headers.Remove(ClaimPolicy.HEADER_LOCALE); + httpContextAccessor.HttpContext.Request.Headers.Add(ClaimPolicy.HEADER_LOCALE, data.Culture); + + SecurityUserWebLoginEntity webLogin = new SecurityUserWebLoginEntity + { + Username = agent.UserName, + SessionId = Guid.NewGuid().ToString(), + LoginTime = DateTime.Now, + HostIp = loginProfile.Username, + HostUserAgent = loginProfile.UserMobile!, + RefreshToken = jwtGenerate.GenerateRefreshToken(), + RefreshTokenRefreshedTime = DateTime.Now, + }; + + IRepository repositoryLog = service.GetRepository>(); + + repositoryLog.InsertNow(webLogin); + + service.UserId = agent.UserName; + PermissionContext permissionContext = new PermissionContext(service); + return new LoginProfile + { + Token = new JwtInfo() { AccessToken = accessToken, RefreshToken = webLogin.RefreshToken, CreatedTime = webLogin.RefreshTokenRefreshedTime }, + Username = agent.UserName, + UserType = agent.UserType, + UserLocalName = agent.UserLocalName, + UserEngName = agent.UserEngName, + UserMobile = agent.UserMobile!, + PermissionInfo = permissionContext.GetUserPermissionInfo() + }; + } + + [AllowAnonymous] + [UnitOfWork] + public string Register(RegisterData data) + { + SecurityUserEntity securityUser = repository.DetachedEntities.Where(x => x.UserMobile == data.UserMobile).FirstOrDefault()!; + if (securityUser != null) + { + throw new ValidatedException("手机号已注册."); + } + + securityUser = new SecurityUserEntity(); + + if (string.IsNullOrEmpty(data.UserMobile) || string.IsNullOrEmpty(data.RsaUserPassword)) return null; + + ISecurityGeneratorNumberService securityGeneratorNumberService = service.ServiceProvider.GetService()!; + string userName = securityGeneratorNumberService.GetNo(SecurityPrefixPolicy.SECURITY_USER, SecurityPrefixPolicy.SECURITY_USER_USER_NAME, null, YesNoPolicy.NO, SecurityPrefixPolicy.SECURITY_USER_FORMAT); + + var privateKey = service.Configuration[SecuritySettingsPolicy.SecuritySettings_RsaPrivateKey]; + var rsa = new System.RSA(privateKey, true); + + securityUser.UserPassword = rsa.DecodeOrNull(data.RsaUserPassword); + //052636a8-b146-9efd-f5dc-0034a3c5bb34+password(MD5) + string guid = securityUser.UserPassword.Substring(0, 36); + + securityUser.UserPassword = securityUser.UserPassword.Substring(36, securityUser.UserPassword.Length - 36); + securityUser.UserName = userName; + securityUser.UserMobile = data.UserMobile; + securityUser.UserLocalName = "用户" + securityUser.UserName; + securityUser.UserIsValidIndc = YesNoPolicy.YES; + + JwtGenerate jwtGenerate = service.ServiceProvider.GetService()!; + + Dictionary claims = new Dictionary(); + claims.Add(ClaimPolicy.CLAINM_NAME, securityUser.UserName); + claims.Add(ClaimPolicy.CLAINM_ACCOUNT, securityUser.UserName); + claims.Add(ClaimPolicy.CLAINM_USERID, securityUser.UserName); + claims.Add(ClaimPolicy.CLAINM_LOCALE, CulturePolicy.ZH_CN); + + service.UserId = securityUser.UserName; + + var accessToken = jwtGenerate.Generate(claims); + if (httpContextAccessor.HttpContext.Request.Headers.ContainsKey("Authorization")) + httpContextAccessor.HttpContext.Request.Headers.Remove("Authorization"); + httpContextAccessor.HttpContext.Request.Headers.Add("Authorization", "Bearer " + accessToken); + + repository.InsertNow(securityUser); + + //发布注册的事务 + EventData eventData = new EventData(); + ISecurityUserRegisterPublisher publisher = service.ServiceProvider.GetService()!; + eventData.EventSource = securityUser; + eventData.EventId = typeof(SecurityUserRegisterPublisher).Name; + publisher.Publish(eventData); + + return securityUser.UserMobile; + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityUser, operate: Operate.Update)] + [UnitOfWork] + public LoginProfile AmendPassword(LoginData data) + { + SecurityUserEntity securityUserEntity = repository.DetachedEntities.Where(x => + x.UserName == service.UserId + && x.UserIsValidIndc == YesNoPolicy.YES).FirstOrDefault()!; + + if (securityUserEntity == null) + { + throw new ValidatedException("认证不通过."); + } + + var descKey = service.Configuration[SecuritySettingsPolicy.SecuritySettings_DescKey]; + + var privateKey = service.Configuration[SecuritySettingsPolicy.SecuritySettings_RsaPrivateKey]; + var rsa = new RSA(privateKey, true); + + var psd = rsa.DecodeOrNull(data.RsaUserPassword); + if (string.IsNullOrEmpty(psd)) throw new ValidatedException("认证不通过."); + //052636a8-b146-9efd-f5dc-0034a3c5bb34+password + var guid = psd.Substring(0, 36); + + + if (guid != data.UserName) + { + throw new ValidatedException("认证不通过."); + } + + if (securityUserEntity.IsAccountsLockedIndc == YesNoPolicy.YES && securityUserEntity.AccountsLockedDatetime.HasValue + && securityUserEntity.AccountsLockedDatetime.Value.Subtract(DateTime.Now).TotalMinutes > 0) + { + throw new ValidatedException("用户账号已锁定."); + } + + if (securityUserEntity.UserPassword != psd.Substring(36, psd.Length - 36)) + { + securityUserEntity.ErrorLoginCount += 1; + //输错多少次后,账号锁定 + if (securityUserEntity.ErrorLoginCount > SecurityUserPolicy.ERROR_LOGIN_COUNT) + { + securityUserEntity.IsAccountsLockedIndc = YesNoPolicy.YES; + securityUserEntity.AccountsLockedDatetime = DateTime.Now.AddDays(1); + } + + repository.UpdateNow(securityUserEntity); + + throw new ValidatedException("认证不通过."); + } + + JwtGenerate jwtGenerate = service.ServiceProvider.GetService()!; + + string clainmName = Guid.NewGuid().ToString(); + Dictionary claims = new Dictionary(); + claims.Add(ClaimPolicy.CLAINM_NAME, clainmName); + claims.Add(ClaimPolicy.CLAINM_ACCOUNT, securityUserEntity.UserMobile!); + claims.Add(ClaimPolicy.CLAINM_USERID, securityUserEntity.UserName); + claims.Add(ClaimPolicy.CLAINM_LOCALE, data.Culture ?? CulturePolicy.ZH_CN); + + var accessToken = jwtGenerate.Generate(claims); + if (httpContextAccessor.HttpContext.Request.Headers.ContainsKey("Authorization")) + httpContextAccessor.HttpContext.Request.Headers.Remove("Authorization"); + httpContextAccessor.HttpContext.Request.Headers.Add("Authorization", "Bearer " + accessToken); + + securityUserEntity.ErrorLoginCount = 0; + securityUserEntity.IsAccountsLockedIndc = YesNoPolicy.NO; + securityUserEntity.AccountsLockedDatetime = null; + //更新最后登录日期 + securityUserEntity.LastLoginDatetime = DateTime.Now; + psd = rsa.DecodeOrNull(data.UserPassword); + if (string.IsNullOrEmpty(psd)) throw new ValidatedException("认证不通过."); + securityUserEntity.UserPassword = psd.Substring(36, psd.Length - 36); + repository.UpdateNow(securityUserEntity); + + IRepository repositoryLog = service.GetRepository>(); + + SecurityUserWebLoginEntity webLogin = new SecurityUserWebLoginEntity + { + Username = securityUserEntity.UserName, + SessionId = clainmName, + LoginTime = DateTime.Now, + HostIp = httpContextAccessor.HttpContext.Connection.RemoteIpAddress?.MapToIPv4()?.ToString(), + HostUserAgent = this.httpContextAccessor?.HttpContext?.Request.Headers.UserAgent.ToString(), + RefreshToken = jwtGenerate.GenerateRefreshToken(), + RefreshTokenRefreshedTime = DateTime.Now, + }; + + repositoryLog.InsertNow(webLogin); + PermissionContext permissionContext = new PermissionContext(service); + return new LoginProfile + { + Token = new JwtInfo() { AccessToken = accessToken, RefreshToken = webLogin.RefreshToken, CreatedTime = webLogin.RefreshTokenRefreshedTime }, + Username = securityUserEntity.UserName, + UserType = securityUserEntity.UserType, + UserLocalName = securityUserEntity.UserLocalName, + UserEngName = securityUserEntity.UserEngName, + UserMobile = securityUserEntity.UserMobile!, + PermissionInfo = permissionContext.GetUserPermissionInfo() + }; + } + + + [AllowAnonymous] + [HttpGet] + public string GetRsaPublicKey() + { + if (string.IsNullOrEmpty(service.Configuration["SecuritySettings:RsaPublicKey"])) + throw new ValidatedException("[SecuritySettings:RsaPublicKey]"); + return service.Configuration["SecuritySettings:RsaPublicKey"]!; + } + + [AllowAnonymous] + public JwtInfo RefreshToken(JwtInfo jwtInfo) + { + if (jwtInfo == null || string.IsNullOrEmpty(jwtInfo.AccessToken) || string.IsNullOrEmpty(jwtInfo.RefreshToken)) + throw new ServiceErrorException("无效的令牌,请重新登录."); + + TokenValidationParameters parameters = new TokenValidationParameters + { + ValidateIssuerSigningKey = true, + //获取或设置要使用的Microsoft.IdentityModel.Tokens.SecurityKey用于签名验证。 + IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(service.CloudBuilder.CloudBuilderOptions.Jwt.Secret)), + //获取或设置一个System.String,它表示将使用的有效发行者检查代币的发行者。 + ValidIssuer = service.CloudBuilder.CloudBuilderOptions.Jwt.Issuer, + //获取或设置一个字符串,该字符串表示将用于检查的有效受众反对令牌的观众。 + ValidAudience = service.CloudBuilder.CloudBuilderOptions.Jwt.Audience, + ValidateIssuer = true, + ValidateAudience = true, + ValidateLifetime = false,//不验证过期时间 + }; + + // 验证 Token + var tokenHandler = new JwtSecurityTokenHandler(); + SecurityToken vTocken; + string token = jwtInfo.AccessToken.Replace("Bearer ", ""); + try + { + var tokenValidationResult = tokenHandler.ValidateToken(token, parameters, out vTocken); + + if (tokenValidationResult == null || !tokenValidationResult.Identities.Any() || !tokenValidationResult.Identities.First().IsAuthenticated) + throw new ServiceErrorException("无效的令牌,请重新登录."); + } + catch (Exception) + { + throw new ServiceErrorException("无效的令牌,请重新登录."); + } + + string clainmName = ClaimPolicy.GetClaimValue(token, ClaimPolicy.CLAINM_NAME); + string username = ClaimPolicy.GetClaimValue(token, ClaimPolicy.CLAINM_USERID); + string userMobile = ClaimPolicy.GetClaimValue(token, ClaimPolicy.CLAINM_ACCOUNT); + string locale = ClaimPolicy.GetClaimValue(token, ClaimPolicy.CLAINM_LOCALE); + if (string.IsNullOrEmpty(clainmName) || string.IsNullOrEmpty(username)) + throw new ServiceErrorException("无效的令牌,请重新登录."); + + IRepository repositorySecurityUser = service.GetRepository>(); + + SecurityUserEntity user = repositorySecurityUser.DetachedEntities.Where(x => x.UserName == username && x.UserIsValidIndc == YesNoPolicy.YES).FirstOrDefault(); + if (user == null) throw new ServiceErrorException("无效的令牌,请重新登录."); + + IRepository repositoryLog = service.GetRepository>(); + + SecurityUserWebLoginEntity log = repositoryLog.DetachedEntities.Where(x => x.Username == username && x.SessionId == clainmName).FirstOrDefault()!; + + //不是最后登录的令牌失效 + DateTime? LoginTime = repositoryLog.DetachedEntities.Where(x => x.Username == username).Max(x => x.LoginTime); + if (LoginTime.HasValue && log.LoginTime < LoginTime.Value) throw new ServiceErrorException("无效的令牌,请重新登录."); + + if (log == null || log.RefreshToken != jwtInfo.RefreshToken || log.LogoutTime.HasValue || + log.RefreshToken != jwtInfo.RefreshToken || log.RefreshTokenRefreshedTime.AddMinutes(Convert.ToInt32(service.CloudBuilder.CloudBuilderOptions.Jwt.RefreshExpireMins)) < DateTime.Now) + throw new ServiceErrorException("无效的令牌,请重新登录."); + + JwtGenerate jwtGenerate = service.ServiceProvider.GetService()!; + + Dictionary claims = new Dictionary(); + claims.Add(ClaimPolicy.CLAINM_NAME, clainmName); + claims.Add(ClaimPolicy.CLAINM_ACCOUNT, userMobile); + claims.Add(ClaimPolicy.CLAINM_USERID, username); + claims.Add(ClaimPolicy.CLAINM_LOCALE, locale ?? CulturePolicy.ZH_CN); + + var accessToken = jwtGenerate.Generate(claims); + + log.RefreshToken = jwtGenerate.GenerateRefreshToken(); + log.RefreshTokenRefreshedTime = DateTime.Now; + + if (httpContextAccessor.HttpContext.Request.Headers.ContainsKey("Authorization")) + httpContextAccessor.HttpContext.Request.Headers.Remove("Authorization"); + httpContextAccessor.HttpContext.Request.Headers.Add("Authorization", "Bearer " + accessToken); + + repositoryLog.UpdateNow(log); + + jwtInfo.AccessToken = accessToken; + jwtInfo.RefreshToken = log.RefreshToken; + jwtInfo.CreatedTime = log.RefreshTokenRefreshedTime; + + return jwtInfo; + } + + [AllowAnonymous] + public void Logout() + { + string username = ClaimPolicy.GetClaimValue(httpContextAccessor, ClaimPolicy.CLAINM_USERID); + string clainmName = ClaimPolicy.GetClaimValue(httpContextAccessor, ClaimPolicy.CLAINM_NAME); + + if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(clainmName)) { return; } + + + IRepository repositoryLog = service.GetRepository>(); + + SecurityUserWebLoginEntity log = repositoryLog.DetachedEntities.Where(x => x.Username == username && x.SessionId == clainmName).FirstOrDefault()!; + if (log == null || log.LogoutTime.HasValue) { return; } + + log.LogoutTime = DateTime.Now; + + repositoryLog.UpdateNow(log); + } + + + // ===== Biometric / WebAuthn login (fingerprint, face, device PIN) ===== + // Two-phase registration + two-phase assertion. The browser drives + // navigator.credentials.create() / navigator.credentials.get(); we + // generate challenges server-side, verify the response, and persist + // the credential on the user. Login re-uses LoginProfileFactory so + // the JWT + SecurityUserWebLogin flow is identical to the password + // login in AuthProcess. + + // Verifies the password of the currently-authenticated user. + // Used as a step-up authentication gate before sensitive + // operations like enabling biometric login on a new device. + // + // The username is taken from `loginCredential` (the JWT/cookie + // identity), not from the request body — the request only carries + // the password. This means: + // 1. A valid JWT is required to even hit this method. + // 2. The user can only verify their OWN password, not someone + // else's (even if they craft a request with a different + // username, that field is ignored). + // 3. No new session is minted — the existing one is preserved. + // + // Returns true if the password matches, throws ValidationException + // otherwise. The frontend treats the exception as "wrong password". + [PermissionOperate(name: SecurityPermissionPolicy.SecurityUser, operate: Operate.Find)] + public bool ConfirmPassword(string password) + { + if (string.IsNullOrWhiteSpace(password)) + throw new ValidationException("password is required"); + + var username = service.UserId; + if (string.IsNullOrWhiteSpace(username)) + throw new ValidationException("User not found."); + + var user = repository.DetachedEntities.FirstOrDefault(x => x.UserName == username); + if (user == null) + throw new ValidationException("User not found."); + + var descKey = service.Configuration[SecuritySettingsPolicy.SecuritySettings_DescKey]; + + var privateKey = service.Configuration[SecuritySettingsPolicy.SecuritySettings_RsaPrivateKey]; + var rsa = new System.RSA(privateKey, true); + + var psd = rsa.DecodeOrNull(password); + if (string.IsNullOrEmpty(psd)) return false; + + return user.UserPassword == psd.Substring(36, psd.Length - 36); + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityUser, operate: Operate.Find)] + public string BeginBiometricRegistration(string deviceName) + { + try + { + if (string.IsNullOrWhiteSpace(deviceName)) + deviceName = "Unnamed device"; + + var username = service.UserId;// loginCredential.GetUsername(); + if (string.IsNullOrWhiteSpace(username)) + throw new ValidationException("User not found."); + + var userIdBytes = Encoding.UTF8.GetBytes(username); + // v1: one credential per user — exclude list is empty. + var options = webAuthnService.BuildCreationOptions(username, userIdBytes, Array.Empty()); + + return options.ToJson(); + } + catch (Exception ex) + { + //logger.LogError("BeginBiometricRegistration ERROR: " + ex.ToString()); + throw; + } + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityUser, operate: Operate.Find)] + public BiometricRegistrationResultDto FinishBiometricRegistration(FinishBiometricRegistrationData dto) + { + if (dto == null || string.IsNullOrWhiteSpace(dto.AttestationJson) || string.IsNullOrWhiteSpace(dto.CreationOptionsJson)) + throw new ValidationException("attestationJson and creationOptionsJson are required"); + + var username = service.UserId;// loginCredential.GetUsername(); + if (string.IsNullOrWhiteSpace(username)) + throw new ValidationException("User not found."); + + var user = repository.DetachedEntities.FirstOrDefault(x => x.UserName == username); + if (user == null) + throw new ValidationException("User not found."); + + // Diagnostic: log the raw JSON we received so we can diagnose + // Fido2NetLib "Expected rawResponse, got null" failures. The + // Fido2NetLib 1.0.0-alpha VerifyAsync checks `Raw == null` at + // the top, before any field-level checks — if it fires, the + // wrapper was constructed with a null raw, which means either + // (a) CredentialCreateOptions.FromJson returned null and the + // constructor blew up, or (b) the C# deserializer produced a + // shell object whose required properties are all null. + //logger.LogInformation( + // "FinishBiometricRegistration_DIAG attestationJson[0..400]={att} creationOptionsJson[0..200]={opts}", + // dto.AttestationJson.Substring(0, Math.Min(400, dto.AttestationJson.Length)), + // dto.CreationOptionsJson.Substring(0, Math.Min(200, dto.CreationOptionsJson.Length))); + + CredentialCreateOptions originalOptions; + try + { + originalOptions = CredentialCreateOptions.FromJson(dto.CreationOptionsJson); + } + catch (Exception ex) + { + throw new ValidationException("Invalid creationOptionsJson: " + ex.Message); + } + if (originalOptions == null) + throw new ValidationException("CredentialCreateOptions.FromJson returned null (creationOptionsJson parsed as the JSON literal 'null' or empty)"); + + AuthenticatorAttestationRawResponse raw; + try + { + //logger.LogInformation("DTO: " + dto.AttestationJson); + // MUST use Newtonsoft.Json here, not System.Text.Json. Fido2NetLib's + // AuthenticatorAttestationRawResponse relies on Newtonsoft.Json-specific + // attributes that System.Text.Json does not honor: + // * [JsonConverter(typeof(Base64UrlConverter))] on Id/RawId/AttestationObject/ClientDataJson + // (converts base64url strings to byte[]; System.Text.Json would leave them as strings) + // * [JsonConverter(typeof(StringEnumConverter))] on PublicKeyCredentialType.Type + // with [EnumMember(Value = "public-key")] on the PublicKey member + // + // And Fido2NetLib's AuthenticatorAttestationResponse.Parse throws + // "Expected rawResponse, got null" when rawResponse.Response is null — + // which is exactly what System.Text.Json produces, because it is + // case-sensitive by default and looks for `Response` (PascalCase) in + // the JSON, while the browser sends `response` (lowercase). + // Newtonsoft.Json's default ContractResolver is case-insensitive. + raw = JsonConvert.DeserializeObject(dto.AttestationJson); + } + catch (Exception ex) + { + throw new ValidationException("Invalid attestationJson: " + ex.Message); + } + if (raw == null) throw new ValidationException("Invalid attestationJson"); + if (raw.Response == null) throw new ValidationException("raw.Response is null after deserialization — the browser's JSON didn't bind to Fido2NetLib's Response property"); + + // Diagnostic: log what Fido2NetLib will see. If any of these + // are null, Fido2NetLib's VerifyAsync will throw the cryptic + // "Expected rawResponse, got null" or "Id is missing" / "RawId + // is missing" / "clientDataJson cannot be null" etc. + //logger.LogInformation( + // "FinishBiometricRegistration_DIAG raw.Id={id} raw.RawId={rawId} raw.Type={type} raw.Response.AttestationObject={ao} raw.Response.ClientDataJson={cdj}", + // raw.Id, + // raw.RawId, + // raw.Type, + // raw.Response?.AttestationObject == null ? "" : $"<{raw.Response.AttestationObject.Length} chars>", + // raw.Response?.ClientDataJson == null ? "" : $"<{raw.Response.ClientDataJson.Length} chars>"); + + // Fido2NetLib verifies signature, certificate chain, challenge, + // origin, and rpId. We only need to await it. + var stored = webAuthnService + .FinishRegistrationAsync(raw, originalOptions, _ => Task.FromResult(true)) + .GetAwaiter().GetResult(); + + // Persist on the user. v1 = one credential per user: just + // overwrite. (The excludeCredentials list passed to + // BuildCreationOptions is empty, so the authenticator will + // refuse to re-enroll the same key on the same device — but + // re-enrolling on a new device overwrites. That's intentional.) + // + // SecurityUser.BiometricCredentialId / BiometricPublicKey are + // `string` columns (per the request to keep the schema as-is). + // Fido2NetLib gives us `byte[]`; we encode with base64url so + // the stored value is directly usable as the credential id + // (matches the format returned to the browser in + // BiometricRegistrationResultDto.CredentialIdBase64Url) and + // the public key can be decoded back to byte[] for the + // assertion verification path. + user.BiometricCredentialId = Fido2NetLib.Base64Url.Encode(stored.CredentialId); + user.BiometricPublicKey = Fido2NetLib.Base64Url.Encode(stored.PublicKey); + user.BiometricCounter = 0; + user.BiometricDeviceName = dto.AttestationJson.Length > 0 ? "(set on the device)" : null; + user.BiometricEnrolledAt = DateTime.Now; + user.BiometricLastUsedAt = null; + + repository.UpdateNow(user); + + return new BiometricRegistrationResultDto + { + CredentialIdBase64Url = Fido2NetLib.Base64Url.Encode(stored.CredentialId) + }; + } + + [AllowAnonymous] + public BiometricLoginChallengeDto BeginBiometricLogin(string username) + { + if (string.IsNullOrWhiteSpace(username)) + throw new ValidationException("username is required"); + + var user = repository.DetachedEntities.FirstOrDefault(x => x.UserName == username); + if (user == null) + throw new ValidationException("User not found."); + if (user.BiometricCredentialId == null || user.BiometricCredentialId.Length == 0) + throw new ValidationException("Biometric not enrolled for this user"); + + + // user.BiometricCredentialId is stored as base64url (see + // FinishBiometricRegistration). Decode back to byte[] for + // Fido2NetLib's PublicKeyCredentialDescriptor.Id. + // BuildRequestOptionsJson bypasses Fido2NetLib 1.0.0-alpha's + // PascalCase serializer. See WebAuthnService.BuildRequestOptionsJson + // for why the wire shape has to be hand-built. + var optionsJson = webAuthnService.BuildRequestOptionsJson( + Fido2NetLib.Base64Url.Decode(user.BiometricCredentialId)); + return new BiometricLoginChallengeDto + { + RequestOptionsJson = optionsJson, + ChallengeId = Guid.NewGuid().ToString() + }; + } + + [AllowAnonymous] + public LoginProfile FinishBiometricLogin(FinishBiometricLoginData dto) + { + if (dto == null || string.IsNullOrWhiteSpace(dto.Username) || string.IsNullOrWhiteSpace(dto.AssertionJson) || string.IsNullOrWhiteSpace(dto.RequestOptionsJson)) + throw new ValidationException("username, assertionJson, and requestOptionsJson are required"); + + var user = repository.DetachedEntities.FirstOrDefault(x => x.UserMobile == dto.Username || x.UserName == dto.Username); + if (user == null) + throw new ValidationException("User not found."); + + if (user.BiometricCredentialId == null || user.BiometricPublicKey == null) + throw new ValidationException("Biometric not enrolled for this user"); + + AssertionOptions originalOptions; + try + { + // dto.RequestOptionsJson arrives double-JSON-encoded: the + // backend returns the options as a JSON string (e.g. + // '{"challenge":"...","rpId":"..."}' + // ), and the frontend then does JSON.stringify() on that + // string, wrapping it in another layer of quotes: + // '"{\"challenge\":\"...\",\"rpId\":\"..."}"' + // Fido2NetLib's AssertionOptions.FromJson then tries to + // deserialize that as an AssertionOptions object and throws + // "Could not cast or convert from System.String to + // Fido2NetLib.AssertionOptions" because it sees a string + // token at the top level. + // + // Unwrap one layer with JToken.Parse: if the result is a + // JValue (the JSON-encoded string case), parse its string + // value to get the inner JSON. If it's already a JObject + // (no double-encoding), just use ToString(). + var token = Newtonsoft.Json.Linq.JToken.Parse(dto.RequestOptionsJson); + if (token is Newtonsoft.Json.Linq.JValue v && v.Type == Newtonsoft.Json.Linq.JTokenType.String) + { + token = Newtonsoft.Json.Linq.JToken.Parse((string)v.Value!); + } + originalOptions = AssertionOptions.FromJson(token.ToString()); + } + catch (Exception ex) + { + //logger.LogError("FinishBiometricLogin_ERROR_1: " + ex.ToString()); + throw new ValidationException("Invalid requestOptionsJson: " + ex.Message); + } + + AuthenticatorAssertionRawResponse raw; + try + { + // Fido2NetLib 1.0.0-alpha declares Id/RawId/Response.* as `string` + // (no [JsonConverter] — that was added in v1.1.0+), and internally + // does (byte[])raw.Id to look up the credential. The (byte[]) cast + // throws "Unable to cast object of type 'System.String' to type + // 'System.Byte[]'" on the assertion flow (the registration flow + // doesn't hit it because its Parse() path only touches + // Response.AttestationObject, never Id/RawId). + // + // Fix: deserialize normally with Newtonsoft.Json, then patch the + // base64url string fields to byte[] via reflection. If the C# + // property is byte[] (1.1.0+ shape) this is a no-op. If it's + // string (1.0.0-alpha shape) the reflection write will fail at + // runtime with a clear ArgumentException — see the catch below + // for the workaround. + raw = JsonConvert.DeserializeObject(dto.AssertionJson); + WebAuthnAssertionPatcher.PatchResponseToByteArrays(raw); + + // DIAG: log the actual runtime property type so we can confirm + // the shape of the Fido2NetLib 1.0.0-alpha class and choose the + // right patching strategy. + //logger.LogInformation( + // "FinishBiometricLogin_DIAG Id={idType} RawId={rawIdType} Response.Id={respIdType} Response.AuthenticatorData={adType} Response.Signature={sigType} Response.ClientDataJson={cdjType}", + // typeof(AuthenticatorAssertionRawResponse).GetProperty("Id")?.PropertyType.Name, + // typeof(AuthenticatorAssertionRawResponse).GetProperty("RawId")?.PropertyType.Name, + // typeof(AuthenticatorAssertionRawResponse.AssertionResponse).GetProperty("Id")?.PropertyType.Name, + // typeof(AuthenticatorAssertionRawResponse.AssertionResponse).GetProperty("AuthenticatorData")?.PropertyType.Name, + // typeof(AuthenticatorAssertionRawResponse.AssertionResponse).GetProperty("Signature")?.PropertyType.Name, + // typeof(AuthenticatorAssertionRawResponse.AssertionResponse).GetProperty("ClientDataJson")?.PropertyType.Name); + } + catch (Exception ex) + { + //logger.LogError("FinishBiometricLogin_ERROR_2: " + ex.ToString()); + throw new ValidationException("Invalid assertionJson: " + ex.Message); + } + if (raw == null) + { + //logger.LogError("FinishBiometricLogin_ERROR_3:"); + throw new ValidationException("Invalid assertionJson"); + } + + try + { + // user.BiometricPublicKey is stored as base64url; decode to + // byte[] for Fido2NetLib's MakeAssertionAsync signature. + var newCounter = webAuthnService + .FinishAssertionAsync(raw, originalOptions, Fido2NetLib.Base64Url.Decode(user.BiometricPublicKey), (uint)user.BiometricCounter) + .GetAwaiter().GetResult(); + + // Persist counter + last-used timestamp. + user.BiometricCounter = (int)newCounter; + user.BiometricLastUsedAt = DateTime.Now; + repository.UpdateNow(user); + + // Mint the session the same way AuthProcess.Login does. + + return PackLoginProfile(user, CulturePolicy.ZH_CN); + } + catch (Exception ex) + { + //logger.LogError("FinishBiometricLogin_ERROR_4: " + ex.ToString()); + throw; + } + } + + // ===== Epayslip biometric verification (step-up auth, not a new login) ===== + // + // BeginBiometricLogin / FinishBiometricLogin mint a new JWT session + // (they are the password-less login flow). The two webmethods below + // reuse the same WebAuthn ceremony against the CURRENTLY-authenticated + // user's stored credential, but instead of issuing a fresh profile + // they just stamp a 5-minute unlock in EpayslipBiometricUnlockStore + // so SalaryTaxWebProcess.SalaryTax can accept biometricVerified=true + // as a substitute for the epayslip password. + // + // Both webmethods require the user to be logged in (the auto-generated + // UserProfileController has [Authorize] at the class level) AND + // require biometric_for_epayslip=1 -- we re-check the server flag + // here even though the frontend gates on it, so a user cannot + // accidentally hit Begin from a stale tab after disabling the flag. + + // Returns the WebAuthn request options JSON for the current user's + // stored credential. The frontend parses the string and passes it to + // @simplewebauthn/browser's startAuthentication. + // + // Wrapped in EpayslipBiometricAssertionChallengeDto (not returned + // as a raw string) so the auto-generated TS service stub's + // resp.requestOptionsJson mirrors the BiometricLoginChallengeDto + // contract used by LoginView. A raw-string return would serialize + // as a JSON-encoded quoted string and confuse the frontend's + // JSON.parse step. + + public BiometricLoginChallengeDto BeginEpayslipBiometricAssertion() + { + var username = service.UserId; + if (string.IsNullOrWhiteSpace(username)) + throw new ValidationException("User not found."); + + var user = repository.DetachedEntities.FirstOrDefault(x => x.UserName == username); + if (user == null) + throw new ValidationException("User not found."); + + // Defense in depth: refuse to issue a challenge if the user + // has not enrolled biometric login or has not opted in to + // biometric-for-epayslip. + if (string.IsNullOrEmpty(user.BiometricCredentialId)) + throw new ValidationException("Biometric login must be enabled first"); + + // user.BiometricCredentialId is stored as base64url (see + // FinishBiometricRegistration). Decode back to byte[] for + // Fido2NetLib's PublicKeyCredentialDescriptor.Id. + return new BiometricLoginChallengeDto + { + RequestOptionsJson = webAuthnService.BuildRequestOptionsJson( + Fido2NetLib.Base64Url.Decode(user.BiometricCredentialId)) + }; + } + + // Verifies the assertion produced by the browser from + // BeginEpayslipBiometricAssertion's challenge. On success stamps + // the unlock store for 5 minutes -- SalaryTax can then accept + // biometricVerified=true instead of the epayslip password hash. + // + // Same Newtonsoft + double-JSON-decode dance as FinishBiometricLogin + // (see that method's comments for why Newtonsoft specifically and + // why the options string needs unwrapping); only the persistence + // step is different -- we do not mint a new session. + + public bool FinishEpayslipBiometricAssertion(string assertionJson, string requestOptionsJson) + { + if (string.IsNullOrWhiteSpace(assertionJson) || string.IsNullOrWhiteSpace(requestOptionsJson)) + throw new ValidationException("assertionJson and requestOptionsJson are required"); + + var username = service.UserId; + if (string.IsNullOrWhiteSpace(username)) + throw new ValidationException("User not found."); + + var user = repository.DetachedEntities.FirstOrDefault(x => x.UserName == username); + if (user == null) + throw new ValidationException("User not found."); + + if (string.IsNullOrEmpty(user.BiometricCredentialId) || string.IsNullOrEmpty(user.BiometricPublicKey)) + throw new ValidationException("Biometric not enrolled for this user"); + + AssertionOptions originalOptions; + try + { + // Same unwrap as FinishBiometricLogin: the frontend + // double-JSON-encodes the options string, so the top-level + // JToken is a JSON string of a JSON object. Unwrap one layer + // before handing to Fido2NetLib's FromJson. + var token = Newtonsoft.Json.Linq.JToken.Parse(requestOptionsJson); + if (token is Newtonsoft.Json.Linq.JValue v && v.Type == Newtonsoft.Json.Linq.JTokenType.String) + { + token = Newtonsoft.Json.Linq.JToken.Parse((string)v.Value!); + } + originalOptions = AssertionOptions.FromJson(token.ToString()); + } + catch (Exception ex) + { + //logger.LogError("FinishEpayslipBiometricAssertion_ERROR_1: " + ex.ToString()); + throw new ValidationException("Invalid requestOptionsJson: " + ex.Message); + } + + AuthenticatorAssertionRawResponse raw; + try + { + // See WebAuthnAssertionPatcher for why this is needed. + raw = JsonConvert.DeserializeObject(assertionJson); + WebAuthnAssertionPatcher.PatchResponseToByteArrays(raw); + } + catch (Exception ex) + { + //logger.LogError("FinishEpayslipBiometricAssertion_ERROR_2: " + ex.ToString()); + throw new ValidationException("Invalid assertionJson: " + ex.Message); + } + if (raw == null) + throw new ValidationException("Invalid assertionJson"); + if (raw.Response == null) + throw new ValidationException("assertionJson is missing the response field"); + + try + { + // user.BiometricPublicKey is stored as base64url; decode to + // byte[] for Fido2NetLib's MakeAssertionAsync signature. + var newCounter = webAuthnService + .FinishAssertionAsync(raw, originalOptions, Fido2NetLib.Base64Url.Decode(user.BiometricPublicKey), (uint)user.BiometricCounter) + .GetAwaiter().GetResult(); + + user.BiometricCounter = (int)newCounter; + user.BiometricLastUsedAt = DateTime.Now; + + repository.UpdateNow(user); + + + // Stamp the unlock. Default duration is 5 minutes -- see + // EpayslipBiometricUnlockStore.DefaultDuration. + //epayslipUnlockStore.Unlock(username); + //logger.LogInformation("FinishEpayslipBiometricAssertion: unlocked for username={username}", username); + return true; + } + catch (Exception ex) + { + //logger.LogError("FinishEpayslipBiometricAssertion_ERROR_3: " + ex.ToString()); + throw; + } + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityUser, operate: Operate.Find)] + public void RemoveBiometric() + { + var username = service.UserId;// loginCredential.GetUsername(); + if (string.IsNullOrWhiteSpace(username)) + throw new ValidationException("User not found."); + + var user = repository.DetachedEntities.FirstOrDefault(x => x.UserName == username); + if (user == null) + throw new ValidationException("User not found."); + + user.BiometricCredentialId = null; + user.BiometricPublicKey = null; + user.BiometricCounter = 0; + user.BiometricDeviceName = null; + user.BiometricEnrolledAt = null; + user.BiometricLastUsedAt = null; + + repository.UpdateNow(user); + } + } +} diff --git a/CloudBuilder/CloudBuilder.Security.Service/Authorization/PermissionContext.cs b/CloudBuilder/CloudBuilder.Security.Service/Authorization/PermissionContext.cs new file mode 100644 index 0000000..97d0e67 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Service/Authorization/PermissionContext.cs @@ -0,0 +1,158 @@ +using CloudBuilder.Core.DatabaseAccessor.Entity; +using CloudBuilder.Core.Service; +using CloudBuilder.Security.Data; +using CloudBuilder.Security.Entity; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Security.Service.Authorization +{ + public class PermissionContext + { + private readonly IApplicationService service; + + public PermissionContext(IApplicationService service) + { + this.service = service; + } + + public string[] GetAllGroups() + { + if (string.IsNullOrEmpty(service.UserId)) return null!; + + var userActors = service.GetRepository>().DetachedEntities.Where(x => x.UserName == service.UserId); + + var actorGroups = service.GetRepository>().DetachedEntities.Where(x => userActors.Select(x => x.ActorName).Contains(x.ActorName)); + + if (!actorGroups.Any()) + { + return null!; + } + + return actorGroups.Select(x => x.GroupName).ToArray(); + } + + public SecurityUserPermissionInfo GetUserPermissionInfo() + { + SecurityUserPermissionInfo info = new SecurityUserPermissionInfo(); + + var userActors = service.GetRepository>() + .DetachedEntities + .Where(x => x.UserName == service.UserId); + + // 关键修复:加上 .ToArray(),把 actorGroups 加载到本地内存,变成内存集合,不再是IQueryable延迟查询 + var actorGroups = service.GetRepository>() + .DetachedEntities + .Where(x => userActors.Select(u => u.ActorName).Contains(x.ActorName)) + .ToArray(); // ← 这里ToArray强制立刻查询数据库,后续全部内存操作 + + info.UserGroups = actorGroups.Select(x => x.GroupName).ToArray(); + + info.Permissions = ( + from p in service.GetRepository>().DetachedEntities.AsEnumerable() + join g in actorGroups on p.GroupName equals g.GroupName + select p + ).ToArray(); + + info.PermissionDependents = + ( + from p in service.GetRepository>().DetachedEntities.AsEnumerable() + join g in actorGroups on p.GroupName equals g.GroupName + select p + ).ToArray(); + + info.PermissionFunctionMaps = + ( + from m in service.GetRepository>().DetachedEntities.AsEnumerable() + join p in info.Permissions on m.PermissionName equals p.PermissionName + select m + ).ToArray(); + return info; + } + + public bool CanNone(string permission) + { + if (string.IsNullOrEmpty(service.UserId)) return false; + + SecurityUserPermissionInfo permissionInfo = GetUserPermissionInfo(); + return permissionInfo.Permissions?.Any(x => x.PermissionName == permission) == true; + } + + public bool CanView(string permission) + { + if (string.IsNullOrEmpty(service.UserId)) return false; + + SecurityUserPermissionInfo permissionInfo = GetUserPermissionInfo(); + return permissionInfo.Permissions?.Any(x => x.PermissionName == permission && x.ViewIndc == YesNoPolicy.YES) == true; + } + + public bool CanCreate(string permission) + { + if (string.IsNullOrEmpty(service.UserId)) return false; + + SecurityUserPermissionInfo permissionInfo = GetUserPermissionInfo(); + return permissionInfo.Permissions?.Any(x => x.PermissionName == permission && x.CreateIndc == YesNoPolicy.YES) == true; + } + + public bool CanAmend(string permission) + { + if (string.IsNullOrEmpty(service.UserId)) return false; + + SecurityUserPermissionInfo permissionInfo = GetUserPermissionInfo(); + return permissionInfo.Permissions?.Any(x => x.PermissionName == permission && x.AmendIndc == YesNoPolicy.YES) == true; + } + + public bool CanDelete(string permission) + { + if (string.IsNullOrEmpty(service.UserId)) return false; + + SecurityUserPermissionInfo permissionInfo = GetUserPermissionInfo(); + return permissionInfo.Permissions?.Any(x => x.PermissionName == permission && x.DeleteIndc == YesNoPolicy.YES) == true; + } + + public bool CanNone(string permission, string dependent) + { + if (string.IsNullOrEmpty(service.UserId)) return false; + + SecurityUserPermissionInfo permissionInfo = GetUserPermissionInfo(); + return permissionInfo.PermissionDependents?.Any(x => x.PermissionName == permission && x.DependentDetailName == dependent) == true; + } + + public bool CanView(string permission, string dependent) + { + if (string.IsNullOrEmpty(service.UserId)) return false; + + SecurityUserPermissionInfo permissionInfo = GetUserPermissionInfo(); + return permissionInfo.PermissionDependents?.Any(x => x.PermissionName == permission && x.DependentDetailName == dependent && x.ViewIndc == YesNoPolicy.YES) == true; + } + + public bool CanCreate(string permission, string dependent) + { + if (string.IsNullOrEmpty(service.UserId)) return false; + + SecurityUserPermissionInfo permissionInfo = GetUserPermissionInfo(); + return permissionInfo.PermissionDependents?.Any(x => x.PermissionName == permission && x.DependentDetailName == dependent && x.CreateIndc == YesNoPolicy.YES) == true; + } + + public bool CanAmend(string permission, string dependent) + { + if (string.IsNullOrEmpty(service.UserId)) return false; + + SecurityUserPermissionInfo permissionInfo = GetUserPermissionInfo(); + return permissionInfo.PermissionDependents?.Any(x => x.PermissionName == permission && x.DependentDetailName == dependent && x.AmendIndc == YesNoPolicy.YES) == true; + } + + public bool CanDelete(string permission, string dependent) + { + if (string.IsNullOrEmpty(service.UserId)) return false; + + SecurityUserPermissionInfo permissionInfo = GetUserPermissionInfo(); + return permissionInfo.PermissionDependents?.Any(x => x.PermissionName == permission && x.DependentDetailName == dependent && x.DeleteIndc == YesNoPolicy.YES) == true; + } + + } +} diff --git a/CloudBuilder/CloudBuilder.Security.Service/Authorization/PermissionHandler.cs b/CloudBuilder/CloudBuilder.Security.Service/Authorization/PermissionHandler.cs new file mode 100644 index 0000000..c6d91b9 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Service/Authorization/PermissionHandler.cs @@ -0,0 +1,107 @@ +using CloudBuilder.Core.Application.Packs; +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.DatabaseAccessor; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using CloudBuilder.Core.DependencyInjection.Request; +using CloudBuilder.Core.Policy; +using CloudBuilder.Core.Service; +using CloudBuilder.Security.Policy; +using DocumentFormat.OpenXml.Drawing.Charts; +using DocumentFormat.OpenXml.EMMA; +using DocumentFormat.OpenXml.Office2016.Drawing.ChartDrawing; +using DocumentFormat.OpenXml.Wordprocessing; +using EnvDTE; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.IdentityModel.Tokens; +using System; +using System.Collections.Generic; +using System.IdentityModel.Tokens.Jwt; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using static Microsoft.EntityFrameworkCore.DbLoggerCategory; + +namespace CloudBuilder.Security.Service.Authorization +{ + public class PermissionHandler : AuthorizationHandler, IAuthorize + { + private readonly WebService service; + private readonly IContext loginContext; + private readonly IHttpContextAccessor httpContextAccessor; + + public PermissionHandler(WebService service, IContext loginContext, IHttpContextAccessor httpContextAccessor) + { + this.service = service; + this.loginContext = loginContext; + this.httpContextAccessor = httpContextAccessor; + } + + protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement) + { + if (context.HasFailed) return Task.CompletedTask; + + var httpContext = httpContextAccessor.HttpContext; + + EndpointMetadataCollection collection = httpContext.GetEndpoint().Metadata; + + PermissionOperateAttribute permission = null; + foreach (var item in collection) + { + if (!(item is PermissionOperateAttribute)) continue; + permission = (PermissionOperateAttribute)item; + break; + } + + //没有设置权限名出错 + if (permission == null) + { + context.Fail(); + return Task.CompletedTask; + } + + string userName = ClaimPolicy.GetClaimValue(httpContextAccessor, ClaimPolicy.CLAINM_USERID); + loginContext.Requestor = userName; + loginContext.SetToken(ClaimPolicy.GetJwtBearerToken(httpContextAccessor.HttpContext)); + loginContext.SetCulture(ClaimPolicy.GetClaimValue(httpContextAccessor, ClaimPolicy.CLAINM_LOCALE) ?? CulturePolicy.ZH_CN); + + IApplicationService applicationService = service.Services.BuildServiceProvider().GetRequiredService(); + PermissionContext permissionContext = new PermissionContext(applicationService); + + bool result = false; + switch (permission.Operate) + { + case "None": + result = permissionContext.CanNone(permission.Name); + break; + case "Find": + case "Print": + result = permissionContext.CanView(permission.Name); + break; + case "Insert": + result = permissionContext.CanCreate(permission.Name); + break; + case "Update": + result = permissionContext.CanAmend(permission.Name); + break; + case "Delete": + result = permissionContext.CanDelete(permission.Name); + break; + default: + result = permissionContext.CanNone(permission.Name, permission.Operate); + break; + } + + if (result && httpContext != null) + { + context.Succeed(requirement); + return Task.CompletedTask; + } + + context.Fail(); + + return Task.CompletedTask; + } + } +} diff --git a/CloudBuilder/CloudBuilder.Security.Service/CloudBuilder.Security.Service.csproj b/CloudBuilder/CloudBuilder.Security.Service/CloudBuilder.Security.Service.csproj new file mode 100644 index 0000000..b8ea72c --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Service/CloudBuilder.Security.Service.csproj @@ -0,0 +1,46 @@ + + + + net8.0 + enable + enable + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ..\CloudBuilder.Core\bin\Debug\net8.0\CloudBuilder.Core.dll + + + ..\CloudBuilder.Security\bin\Debug\net8.0\CloudBuilder.Security.dll + + + + + + + diff --git a/CloudBuilder/CloudBuilder.Security.Service/DependencyInjection/CloudBuilderSecurityServicePack.cs b/CloudBuilder/CloudBuilder.Security.Service/DependencyInjection/CloudBuilderSecurityServicePack.cs new file mode 100644 index 0000000..5a29f69 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Service/DependencyInjection/CloudBuilderSecurityServicePack.cs @@ -0,0 +1,47 @@ +using CloudBuilder.Core.Application.Builders; +using CloudBuilder.Core.Application.Packs; +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.DependencyInjection.Form; +using CloudBuilder.Core.DependencyInjection.Request; +using CloudBuilder.Core.Policy; +using CloudBuilder.Security.Service; +using CloudBuilder.Security.Service.DependencyInjection; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Gui.DependencyInjection +{ + [PackLevel(100)] + public class CloudBuilderSecurityServicePack : CloudBuilderPack + { + /// + /// 获取 模块级别 + /// + public override PackLevel Level => PackLevel.Business; + + /// + /// 获取 模块启动顺序,模块启动的顺序先按级别启动,级别内部再按此顺序启动 + /// + public override int Order => 2; + + /// + /// 将ServiceMessageManager到依赖注入服务容器中 + /// + /// 依赖注入服务容器 + /// + public override IServiceCollection AddServices(IServiceCollection services,CloudBuilderBuilder builder) + { + services.TryAddScoped(); + services.TryAddScoped(); + + return services; + } + + + } +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Security.Service/DependencyInjection/SecurityMasterManager.cs b/CloudBuilder/CloudBuilder.Security.Service/DependencyInjection/SecurityMasterManager.cs new file mode 100644 index 0000000..ae9d620 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Service/DependencyInjection/SecurityMasterManager.cs @@ -0,0 +1,66 @@ +using CloudBuilder.Core.DatabaseAccessor.Entity; +using CloudBuilder.Core.DependencyInjection.Request; +using CloudBuilder.Core.Policy; +using CloudBuilder.Security.Entity; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Security.Service.DependencyInjection +{ + public class SecurityMasterManager : ISecurityMasterManager + { + private readonly IApplicationService service; + private readonly IContext context; + + public SecurityMasterManager(IApplicationService service, IContext context) + { + + this.service = service; + this.context = context; + } + + + public void InitSecurityMaster() + { + //暂时不处理缓存 + throw new NotImplementedException(); + } + + public string GetValue(string category, string subcategory, string codeItem) + { + SecurityMasterEntity securityMaster = GetSecurityMaster(category, subcategory, codeItem); + if (securityMaster == null) return null; + return securityMaster.Value; + } + + public dynamic GetSecurityMaster(string category, string subcategory, string codeItem) + { + SecurityMasterEntityKey key = new SecurityMasterEntityKey() + { + MasterSubcategory = subcategory, + MasterCategory = category, + MasterCodeItem = codeItem + }; + ISecurityMasterService securityMasterService = service.ServiceProvider.GetService()!; + return securityMasterService.FindByKey(key); + + } + + public void SetSecurityMaster(string category, string subcategory, string codeItem, string value) + { + SecurityMasterEntity securityMaster = new SecurityMasterEntity(); + securityMaster.MasterSubcategory = subcategory; + securityMaster.MasterCodeItem = codeItem; + securityMaster.MasterCategory = category; + securityMaster.Value = value; + securityMaster.ValidIndc = YesNoPolicy.YES; + + ISecurityMasterService securityMasterService = service.ServiceProvider.GetService()!; + securityMasterService.Insert(securityMaster); + } + } +} diff --git a/CloudBuilder/CloudBuilder.Security.Service/DependencyInjection/ServiceMessageManager.cs b/CloudBuilder/CloudBuilder.Security.Service/DependencyInjection/ServiceMessageManager.cs new file mode 100644 index 0000000..2f1dec1 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Service/DependencyInjection/ServiceMessageManager.cs @@ -0,0 +1,73 @@ +using CloudBuilder.Core.DatabaseAccessor.Entity; +using CloudBuilder.Core.DependencyInjection.Request; +using CloudBuilder.Core.Policy; +using CloudBuilder.Core.Service; +using CloudBuilder.Security.Entity; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Security.Service.DependencyInjection +{ + public class ServiceMessageManager : ILocaleMessageManager + { + public LocaleEntity[] LocaleEntities { get; set; } = null!; + + public static string SYSTEM = "system"; + public static string GUI_INFORMATION = "gui_information"; + public static string GUI_ERROR = "gui_error"; + private readonly IContext context; + + public IApplicationService Service { get; set; } + + private readonly IApplicationService service; + + private IRepository repository; + public ServiceMessageManager(IApplicationService service, IContext context) + { + this.service = service; + this.context = context; + repository = service.GetRepository>(); + } + + public void InitLocale() + { + + } + + public string ComposeMessage(string groupName, string name) + { + LocaleEntity localeEntity = repository.DetachedEntities.Where(x => x.GroupName == groupName && x.Name == name && x.Lang == context.GetCulture()).FirstOrDefault()!; + + if (localeEntity == null) throw new ValidatedException(); + + return localeEntity.Value; + } + + public TableName[] GetDataSource(string groupName) + { + string[] values = repository.DetachedEntities.Where(x => x.GroupName == groupName && x.Lang == context.GetCulture()).Select(x => x.Name).ToArray(); + + return GetComposeMessages(groupName, values); + } + + public TableName[] GetComposeMessages(string groupName, T[] values) + { + if (values == null || values.Length == 0) return null; + TableName tb = null; + List> list = new List>(); + foreach (T v in values) + { + tb = new TableName(); + tb.DisplayName = ComposeMessage(groupName, v.ToString()); + tb.Value = v; + list.Add(tb); + } + + return list.ToArray(); + } + } +} diff --git a/CloudBuilder/CloudBuilder.Security.Service/LocaleService.cs b/CloudBuilder/CloudBuilder.Security.Service/LocaleService.cs new file mode 100644 index 0000000..2d4ce78 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Service/LocaleService.cs @@ -0,0 +1,158 @@ +using CloudBuilder.Core.DatabaseAccessor; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using CloudBuilder.Core.Service; +using CloudBuilder.Security.Data; +using CloudBuilder.Security.Entity; +using CloudBuilder.Security.Policy; +using CloudBuilder.Security.SearchCriteria; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +namespace CloudBuilder.Security.Service +{ + public class LocaleService : ILocaleService + { + private readonly IApplicationService service; + + private IRepository repository; + public LocaleService(IApplicationService service) + { + this.service = service; + repository = service.GetRepository>(); + } + + [AllowAnonymous] + [HttpGet] + public LocaleEntity[] FindAll() + { + return repository.DetachedEntities.ToArray(); + } + + [AllowAnonymous] + public LocaleResultData FindBySearchCriteria(LocaleSearchCriteria criteria) + { + LocaleResultData data = new LocaleResultData(); + LocaleEntity[] list = null; + + int count = 0; + + string sqlWhere = null; + + if (criteria.Filter != null && criteria.Filter.Length > 0) + { + sqlWhere = SearchFilter.ComposeWhereClause(criteria.Filter); + } + + LocaleEntity entity = LocaleEntity.GetInstance(); + string sql = entity.GetSelectTopFrom(criteria.limit, criteria.page, criteria.orderby.StringToDbField(), criteria.orderbytag, sqlWhere); + + string err = null; + try + { + list = repository.FromSql(sql).ToArray(); + } + catch (System.Exception ex) + { + err = ex.Message; + } + + + if (list != null && list.Length > 0) + { + sql = entity.GetSelectCountFrom(sqlWhere); + count = Convert.ToInt32(repository.ExecuteScalar(sql)); + + data.Datas = list.Select(x => new LocaleDisplayData(x)).ToArray(); + } + else + { + data.Datas = null; + } + + data.Limit = criteria.limit; + data.Page = criteria.page; + + data.Total = count; + //data.Sql = sql; + data.ErrorMessage = err; + return data; + } + + [AllowAnonymous] + public LocaleEntity FindByKey(LocaleEntityKey key) + { + return repository.DetachedEntities.Where(x => 1 == 1 + && x.GroupName == key.GroupName + && x.Lang == key.Lang + && x.Name == key.Name + ).FirstOrDefault()!; + } + + [PermissionOperate(name: SecurityPermissionPolicy.Locale, operate: Operate.Insert)] + [UnitOfWork] + public LocaleEntity Insert(LocaleEntity data) + { + throw new NotImplementedException(); + } + + [PermissionOperate(name: SecurityPermissionPolicy.Locale, operate: Operate.Update)] + [UnitOfWork] + public LocaleEntity Update(LocaleEntity data) + { + throw new NotImplementedException(); + } + + [PermissionOperate(name: SecurityPermissionPolicy.Locale, operate: Operate.Update)] + [UnitOfWork] + public void UpdateLocaleData(LocaleData data) + { + List list = new List(); + LocaleEntity locale; + if (data.Deletes != null) + { + foreach (var item in data.Deletes) + { + locale = new LocaleEntity() { GroupName = item.OrgGroupName, Name = item.OrgName, Lang = item.OrgLang }; + list.Add(locale); + } + repository.DeleteNow(list); + } + if (data.Inserts != null) + { + repository.InsertNow(data.Inserts); + } + if (data.Updates != null) + { + list = new List(); + foreach (var item in data.Updates) + { + locale = new LocaleEntity() { GroupName = item.OrgGroupName, Name = item.OrgName, Lang = item.OrgLang }; + list.Add(locale); + } + repository.DeleteNow(list); + + list = new List(); + foreach (var item in data.Updates) + { + locale = new LocaleEntity(); + ObjectCopyHelper.Copy(item, locale); + list.Add(locale); + } + repository.InsertNow(list); + } + } + + + [PermissionOperate(name: SecurityPermissionPolicy.Locale, operate: Operate.Delete)] + public void Delete(LocaleEntityKey key) + { + LocaleEntity ent = repository.DetachedEntities.Where(x => 1 == 1 + && x.GroupName == key.GroupName + && x.Lang == key.Lang + && x.Name == key.Name + ).FirstOrDefault()!; + if (ent != null) { repository.DeleteNow(ent); } + } + + + } +} diff --git a/CloudBuilder/CloudBuilder.Security.Service/Publisher/SecurityUserRegisterPublisher.cs b/CloudBuilder/CloudBuilder.Security.Service/Publisher/SecurityUserRegisterPublisher.cs new file mode 100644 index 0000000..ccc062d --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Service/Publisher/SecurityUserRegisterPublisher.cs @@ -0,0 +1,34 @@ +using CloudBuilder.Core.DatabaseAccessor.Entity; +using CloudBuilder.Core.DependencyInjection.EventBuses; +using CloudBuilder.Security.Publisher; +using CloudBuilder.Security.Subscriber; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Security.Service.Publisher +{ + public class SecurityUserRegisterPublisher : ISecurityUserRegisterPublisher + { + private readonly IApplicationService service; + + public SecurityUserRegisterPublisher(IApplicationService service) + { + this.service = service; + } + + public void Publish(EventData eventData) + { + IEnumerable subscribers = service.ServiceProvider.GetServices(); + + foreach (var subscriber in subscribers) + { + subscriber.Handle(eventData); + } + } + } +} diff --git a/CloudBuilder/CloudBuilder.Security.Service/SecurityActorService.cs b/CloudBuilder/CloudBuilder.Security.Service/SecurityActorService.cs new file mode 100644 index 0000000..d804a67 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Service/SecurityActorService.cs @@ -0,0 +1,245 @@ +using CloudBuilder.Core.DatabaseAccessor; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using CloudBuilder.Core.Extensions; +using CloudBuilder.Core.Service; +using CloudBuilder.Security.Data; +using CloudBuilder.Security.Entity; +using CloudBuilder.Security.Policy; +using CloudBuilder.Security.SearchCriteria; +using CloudBuilder.Security.Utility; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System.Security.Permissions; +namespace CloudBuilder.Security.Service +{ + public class SecurityActorService : ISecurityActorService + { + private readonly IApplicationService service; + + private IRepository repository; + public SecurityActorService(IApplicationService service) + { + this.service = service; + repository = service.GetRepository>(); + } + + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityActor, operate: Operate.Find)] + public SecurityActorData FindByKey(string key) + { + SecurityActorData data = new SecurityActorData(); + if (string.IsNullOrEmpty(key)) return data; + + SecurityActorEntity actor = repository.DetachedEntities.Where(x => x.ActorName == key).FirstOrDefault(); + + if (actor == null) return data; + + data.SecurityActor = actor; + + IRepository repositoryAgv = repository.GetRepository>(); + IRepository repositoryUav = repository.GetRepository>(); + + data.SecurityActorGroups = repositoryAgv.DetachedEntities.Where(x => x.ActorName == key).ToArray(); + + data.SecurityUserActors = repositoryUav.DetachedEntities.Where(x => x.ActorName == key).ToArray(); + + return data; + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityActor, operate: Operate.Find)] + public SecurityActorEntity[] FindAll() + { + return repository.DetachedEntities.ToArray(); + } + + [AllowAnonymous] + [HttpPost] + public SecurityActorEntity[] FindAllByNoPermission() + { + return repository.DetachedEntities.ToArray(); + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityActor, operate: Operate.Find)] + public SecurityActorResultData FindBySearchCriteria(SecurityActorSearchCriteria criteria) + { + SecurityActorResultData data = new SecurityActorResultData(); + SecurityActorEntity[] list = null; + + int count = 0; + + string sqlWhere = null; + + if (criteria.Filter != null && criteria.Filter.Length > 0) + { + sqlWhere = SearchFilter.ComposeWhereClause(criteria.Filter); + } + + SecurityActorEntity entity = SecurityActorEntity.GetInstance(); + string sql = entity.GetSelectTopFrom(criteria.limit, criteria.page, criteria.orderby.StringToDbField(), criteria.orderbytag, sqlWhere); + + string err = null; + try + { + list = repository.FromSql(sql).ToArray(); + } + catch (System.Exception ex) + { + err = ex.Message; + } + + + if (list != null && list.Length > 0) + { + sql = entity.GetSelectCountFrom(sqlWhere); + count = Convert.ToInt32(repository.ExecuteScalar(sql)); + } + + data.Limit = criteria.limit; + data.Page = criteria.page; + data.Datas = list; + data.Total = count; + //data.Sql = sql; + data.ErrorMessage = err; + return data; + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityActor, operate: Operate.Print)] + public dynamic PrintBySearchCriteria(SecurityActorSearchCriteria criteria) + { + throw new NotImplementedException(); + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityActor, operate: Operate.Insert)] + [UnitOfWork] + public SecurityActorData Insert(SecurityActorData data) + { + SecurityActorEntity securityActor = repository.DetachedEntities.Where(x => x.ActorName == data.SecurityActor.ActorName).FirstOrDefault(); + if (securityActor != null) + { + throw new ValidatedException("记录已存在."); + } + + ValidateHelper.Validate(service, data.SecurityActor, SecurityActorEntity.DB_NAME_SECURITY_ACTOR); + + securityActor = new SecurityActorEntity(); + + ObjectCopyHelper.Copy(data.SecurityActor, securityActor); + + repository.InsertNow(securityActor); + + SaveSecurityActorGroup(data); + + SaveSecurityUserActor(data); + + return FindByKey(data.SecurityActor.ActorName); + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityActor, operate: Operate.Update)] + [UnitOfWork] + public SecurityActorData Update(SecurityActorData data) + { + SecurityActorEntity securityActor = repository.DetachedEntities.Where(x => x.ActorName == data.SecurityActor.ActorName).FirstOrDefault(); + if (securityActor == null) + { + throw new ValidatedException("记录不存在."); + } + + ValidateHelper.Validate(service, data.SecurityActor, SecurityActorEntity.DB_NAME_SECURITY_ACTOR); + + ObjectCopyHelper.Copy(data.SecurityActor, securityActor); + + repository.UpdateNow(securityActor); + + SaveSecurityActorGroup(data); + + SaveSecurityUserActor(data); + + return FindByKey(data.SecurityActor.ActorName); + } + + private void SaveSecurityUserActor(SecurityActorData data) + { + IRepository repositoryUa = repository.GetRepository>(); + + SecurityUserActorEntity[] olds = repositoryUa.Entities.Where(x => x.ActorName == data.SecurityActor.ActorName).ToArray(); + if (olds != null && olds.Length > 0) + { + foreach (SecurityUserActorEntity old in olds) + { + repositoryUa.DeleteNow(old); + } + } + + if (data.SecurityUserActors != null && data.SecurityUserActors.Length > 0) + foreach (SecurityUserActorViewEntity dto in data.SecurityUserActors) + { + repositoryUa.InsertNow(new SecurityUserActorEntity() + { + UserName = dto.UserName, + ActorName = data.SecurityActor.ActorName, + }); + } + + } + + private void SaveSecurityActorGroup(SecurityActorData data) + { + IRepository repositoryAg = repository.GetRepository>(); + + SecurityActorGroupEntity[] olds = repositoryAg.Entities.Where(x => x.ActorName == data.SecurityActor.ActorName).ToArray(); + if (olds != null && olds.Length > 0) + { + foreach (SecurityActorGroupEntity old in olds) + { + repositoryAg.DeleteNow(old); + } + } + + if (data.SecurityActorGroups != null && data.SecurityActorGroups.Length > 0) + foreach (SecurityActorGroupViewEntity dto in data.SecurityActorGroups) + { + repositoryAg.InsertNow(new SecurityActorGroupEntity() + { + ActorName = data.SecurityActor.ActorName, + GroupName = dto.GroupName, + }); + } + + } + + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityActor, operate: Operate.Delete)] + [UnitOfWork] + public void Delete(string key) + { + SecurityActorEntity securityActor = repository.DetachedEntities.Where(x => x.ActorName == key).FirstOrDefault(); + if (securityActor == null) + { + throw new ValidatedException("记录不存在."); + } + + repository.DeleteNow(securityActor); + + IRepository repositoryAg = repository.GetRepository>(); + + SecurityActorGroupEntity[] olds = repositoryAg.Entities.Where(x => x.ActorName == key).ToArray(); + if (olds != null && olds.Length > 0) + { + foreach (SecurityActorGroupEntity old in olds) + { + repositoryAg.DeleteNow(old); + } + } + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityActor, operate: Operate.Delete)] + [UnitOfWork] + public void Deletes(string[] keys) + { + foreach (string key in keys) + { + Delete(key); + } + } + } +} diff --git a/CloudBuilder/CloudBuilder.Security.Service/SecurityFunctionService.cs b/CloudBuilder/CloudBuilder.Security.Service/SecurityFunctionService.cs new file mode 100644 index 0000000..416200c --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Service/SecurityFunctionService.cs @@ -0,0 +1,301 @@ + +using CloudBuilder.Core.DatabaseAccessor; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using CloudBuilder.Core.Extensions; +using CloudBuilder.Core.Service; +using CloudBuilder.Security.Data; +using CloudBuilder.Security.Entity; +using CloudBuilder.Security.Policy; +using CloudBuilder.Security.SearchCriteria; +using CloudBuilder.Security.Utility; +using DocumentFormat.OpenXml.Math; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; +using System.Diagnostics; +namespace CloudBuilder.Security.Service +{ + public class SecurityFunctionService : ISecurityFunctionService + { + private readonly IApplicationService service; + + private IRepository repository; + public SecurityFunctionService(IApplicationService service) + { + this.service = service; + repository = service.GetRepository>(); + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityFunction, operate: Operate.Find)] + public SecurityFunctionData FindByKey(string key) + { + SecurityFunctionData data = new SecurityFunctionData(); + if (string.IsNullOrEmpty(key)) return data; + + SecurityFunctionEntity function = repository.DetachedEntities.Where(x => x.FunctionName == key).FirstOrDefault(); + + if (function == null) return data; + + data.SecurityFunction = new SecurityFunctionDisplayData(function); + + IRepository repositoryMap = repository.GetRepository>(); + + SecurityPermissionFunctionMapEntity map = repositoryMap.Entities.Where(x => x.FunctionName == key).FirstOrDefault(); + if (map != null) data.SecurityFunction.PermissionName = map.PermissionName; + + data.SecurityFunctionMapParents = repository.GetRepository>().DetachedEntities.Where(x => x.SonFunctionName == key).OrderBy(x => x.Orderby).ToArray(); + data.SecurityFunctionMapSons = repository.GetRepository>().DetachedEntities.Where(x => x.ParentFunctionName == key).OrderBy(x => x.Orderby).ToArray(); + + return data; + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityFunction, operate: Operate.Find)] + public SecurityFunctionResultData FindBySearchCriteria(SecurityFunctionSearchCriteria criteria) + { + SecurityFunctionResultData data = new SecurityFunctionResultData(); + SecurityFunctionEntity[] list = null; + + int count = 0; + + string sqlWhere = null; + + if (criteria.Filter != null && criteria.Filter.Length > 0) + { + sqlWhere = SearchFilter.ComposeWhereClause(criteria.Filter); + } + + SecurityFunctionEntity entity = SecurityFunctionEntity.GetInstance(); + string sql = entity.GetSelectTopFrom(criteria.limit, criteria.page, criteria.orderby.StringToDbField(), criteria.orderbytag, sqlWhere); + + string err = null; + try + { + list = repository.FromSql(sql).ToArray(); + } + catch (System.Exception ex) + { + err = ex.Message; + } + + + if (list != null && list.Length > 0) + { + sql = entity.GetSelectCountFrom(sqlWhere); + count = Convert.ToInt32(repository.ExecuteScalar(sql)); + + data.SecurityFunctionDisplayDatas = list.Select(x => new SecurityFunctionDisplayData(x)).ToArray(); + } + else + { + data.SecurityFunctionDisplayDatas = null; + } + + data.Limit = criteria.limit; + data.Page = criteria.page; + + data.Total = count; + //data.Sql = sql; + data.ErrorMessage = err; + return data; + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityFunction, operate: Operate.Print)] + public dynamic PrintBySearchCriteria(SecurityFunctionSearchCriteria criteria) + { + throw new NotImplementedException(); + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityFunction, operate: Operate.Insert)] + [UnitOfWork] + public SecurityFunctionData Insert(SecurityFunctionData data) + { + SecurityFunctionEntity securityFunction = repository.DetachedEntities.Where(x => x.FunctionName == data.SecurityFunction.FunctionName).FirstOrDefault(); + if (securityFunction != null) + { + throw new ValidatedException("记录已存在."); + } + + Validate(data.SecurityFunction); + + securityFunction = new SecurityFunctionEntity(); + ObjectCopyHelper.Copy(data.SecurityFunction, securityFunction); + + repository.InsertNow(securityFunction); + + SaveFunctionPermissionMap(data.SecurityFunction.FunctionName, data.SecurityFunction.PermissionName); + SaveParentMaps(securityFunction.FunctionName, data.SecurityFunctionMapParents); + SaveSonMaps(securityFunction.FunctionName, data.SecurityFunctionMapSons); + + return FindByKey(data.SecurityFunction.FunctionName); + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityFunction, operate: Operate.Update)] + [UnitOfWork] + public SecurityFunctionData Update(SecurityFunctionData data) + { + SecurityFunctionEntity securityFunction = repository.DetachedEntities.Where(x => x.FunctionName == data.SecurityFunction.FunctionName).FirstOrDefault(); + if (securityFunction == null) + { + throw new ValidatedException("记录不存在."); + } + + Validate(data.SecurityFunction); + + ObjectCopyHelper.Copy(data.SecurityFunction, securityFunction); + + repository.UpdateNow(securityFunction); + + SaveFunctionPermissionMap(data.SecurityFunction.FunctionName, data.SecurityFunction.PermissionName); + + SaveParentMaps(securityFunction.FunctionName, data.SecurityFunctionMapParents); + + SaveSonMaps(securityFunction.FunctionName, data.SecurityFunctionMapSons); + + return FindByKey(data.SecurityFunction.FunctionName); + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityFunction, operate: Operate.Delete)] + [UnitOfWork] + public void Delete(string key) + { + SecurityFunctionEntity securityFunction = repository.DetachedEntities.Where(x => x.FunctionName == key).FirstOrDefault(); + if (securityFunction == null) + { + throw new ValidatedException("记录不存在."); + } + + repository.DeleteNow(securityFunction); + + IRepository repositoryMapView = repository.GetRepository>(); + IRepository repositoryMap = repository.GetRepository>(); + + + SecurityFunctionMapViewEntity[] olds = repositoryMapView.Entities.Where(x => x.ParentFunctionName == key || x.SonFunctionName == key).ToArray(); + if (olds != null && olds.Length > 0) + { + foreach (SecurityFunctionMapViewEntity old in olds) + { + repositoryMap.DeleteNow(new SecurityFunctionMapEntity() { FunctionNameSon = old.SonFunctionName, FunctionNameParent = old.ParentFunctionName }); + } + } + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityFunction, operate: Operate.Delete)] + [UnitOfWork] + public void Deletes(string[] keys) + { + foreach (string key in keys) + { + Delete(key); + } + } + + [AllowAnonymous] + public SecurityFunctionEntity FindByFunctionName(string functionName) + { + return repository.DetachedEntities.Where(x => x.FunctionName == functionName || x.PageName == functionName).FirstOrDefault()!; + } + + [AllowAnonymous] + public SecurityFunctionDisplayData[] FindMenus() + { + SecurityFunctionEntity[] entities = repository.DetachedEntities.Where(x => x.FunctionIndc == YesNoPolicy.YES && x.PageUrl != null && x.PageUrl.Length > 0).ToArray(); + + SecurityPermissionFunctionMapEntity[] permissions = service.GetRepository>().DetachedEntities.ToArray(); + + var q = from e in entities + join p in permissions on e.FunctionName equals p.FunctionName + select new SecurityFunctionDisplayData(e) { PermissionName = p.PermissionName }; + + return q.ToArray(); + } + + private void Validate(SecurityFunctionDisplayData securityFunctionDto) + { + List sysTableSchemas = service.ServiceProvider.GetRequiredService().FindByTableName(SecurityFunctionEntity.DB_NAME_SECURITY_FUNCTION); + ValidateHelper.ValidateString(securityFunctionDto, sysTableSchemas.ToArray()); + } + + private void SaveFunctionPermissionMap(string functionName, string permissionName) + { + IRepository repositoryMap = repository.GetRepository>(); + + SecurityPermissionFunctionMapEntity[] olds = repositoryMap.Entities.Where(x => x.FunctionName == functionName).ToArray(); + + if (olds != null && olds.Length > 0) + { + foreach (SecurityPermissionFunctionMapEntity old in olds) + { + repositoryMap.DeleteNow(old); + } + } + + if (string.IsNullOrEmpty(permissionName)) return; + + SecurityPermissionFunctionMapEntity map = new SecurityPermissionFunctionMapEntity(); + map.FunctionName = functionName; + map.PermissionName = permissionName; + repositoryMap.InsertNow(map); + } + + private void SaveParentMaps(string functionName, SecurityFunctionMapViewEntity[] maps) + { + IRepository repositoryMapView = repository.GetRepository>(); + IRepository repositoryMap = repository.GetRepository>(); + SecurityFunctionMapViewEntity[] olds = repositoryMapView.Entities.Where(x => x.SonFunctionName == functionName).ToArray(); + if (olds != null && olds.Length > 0) + { + foreach (SecurityFunctionMapViewEntity old in olds) + { + repositoryMap.DeleteNow(new SecurityFunctionMapEntity() { FunctionNameSon = old.SonFunctionName, FunctionNameParent = old.ParentFunctionName }); + } + } + + if (maps == null || maps.Length == 0) return; + + int maxOrderBy = 0; + foreach (SecurityFunctionMapViewEntity map in maps) + { + SecurityFunctionMapViewEntity[] oldMaps = repositoryMapView.Entities.Where(x => x.ParentFunctionName == map.ParentFunctionName).ToArray(); + + if (oldMaps != null && oldMaps.Count() > 0) maxOrderBy = oldMaps.Max(x => x.Orderby); + + repositoryMap.InsertNow(new SecurityFunctionMapEntity() + { + FunctionNameSon = functionName, + FunctionNameParent = map.ParentFunctionName, + Orderby = oldMaps == null ? 1 : maxOrderBy + 1 + }); + } + + } + + private void SaveSonMaps(string functionName, SecurityFunctionMapViewEntity[] maps) + { + IRepository repositoryMapView = repository.GetRepository>(); + IRepository repositoryMap = repository.GetRepository>(); + + SecurityFunctionMapViewEntity[] olds = repositoryMapView.Entities.Where(x => x.ParentFunctionName == functionName).ToArray(); + if (olds != null && olds.Length > 0) + { + foreach (SecurityFunctionMapViewEntity old in olds) + { + repositoryMap.DeleteNow(new SecurityFunctionMapEntity() { FunctionNameSon = old.SonFunctionName, FunctionNameParent = old.ParentFunctionName }); + } + } + + if (maps == null || maps.Length == 0) return; + int i = 1; + foreach (SecurityFunctionMapViewEntity map in maps.OrderBy(x => x.Orderby).ToArray()) + { + repositoryMap.InsertNow(new SecurityFunctionMapEntity() + { + FunctionNameSon = map.SonFunctionName, + FunctionNameParent = functionName, + Orderby = i++ + }); + } + } + + } +} diff --git a/CloudBuilder/CloudBuilder.Security.Service/SecurityGeneratorNumberService.cs b/CloudBuilder/CloudBuilder.Security.Service/SecurityGeneratorNumberService.cs new file mode 100644 index 0000000..d51cc5c --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Service/SecurityGeneratorNumberService.cs @@ -0,0 +1,284 @@ +using CloudBuilder.Core.DatabaseAccessor; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using CloudBuilder.Core.Extensions; +using CloudBuilder.Core.Report; +using CloudBuilder.Core.Service; +using CloudBuilder.Security.Data; +using CloudBuilder.Security.Entity; +using CloudBuilder.Security.Policy; +using CloudBuilder.Security.SearchCriteria; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +namespace CloudBuilder.Security.Service +{ + public class SecurityGeneratorNumberService : ISecurityGeneratorNumberService + { + private readonly IApplicationService service; + + private IRepository repository; + public SecurityGeneratorNumberService(IApplicationService service) + { + this.service = service; + repository = service.GetRepository>(); + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityGeneratorNumber, operate: Operate.Find)] + public SecurityGeneratorNumberEntity FindByKey(int key) + { + return repository.DetachedEntities.Where(x => x.GeneratorId == key).FirstOrDefault()!; + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityGeneratorNumber, operate: Operate.Find)] + public SecurityGeneratorNumberResultData FindBySearchCriteria(SecurityGeneratorNumberSearchCriteria criteria) + { + SecurityGeneratorNumberResultData data = new SecurityGeneratorNumberResultData(); + SecurityGeneratorNumberEntity[] list = null; + + int count = 0; + + string sqlWhere = null; + + if (criteria.Filter != null && criteria.Filter.Length > 0) + { + sqlWhere = SearchFilter.ComposeWhereClause(criteria.Filter); + } + + SecurityGeneratorNumberEntity entity = SecurityGeneratorNumberEntity.GetInstance(); + string sql = entity.GetSelectTopFrom(criteria.limit, criteria.page, criteria.orderby.StringToDbField(), criteria.orderbytag, sqlWhere); + + string err = null; + try + { + list = repository.FromSql(sql).ToArray(); + } + catch (System.Exception ex) + { + err = ex.Message; + } + + + if (list != null && list.Length > 0) + { + sql = entity.GetSelectCountFrom(sqlWhere); + count = Convert.ToInt32(repository.ExecuteScalar(sql)); + } + + data.Limit = criteria.limit; + data.Page = criteria.page; + data.Datas = list; + data.Total = count; + //data.Sql = sql; + data.ErrorMessage = err; + return data; + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityGeneratorNumber, operate: Operate.Print)] + public dynamic PrintBySearchCriteria(SecurityGeneratorNumberSearchCriteria criteria) + { + string sqlWhere = string.Empty; + List headers = new List(); + + Dictionary> mappings = new Dictionary>(); + Dictionary validDic = new Dictionary(); + foreach (string v in YesNoPolicy.GetInstance().GetValues()) + { + validDic.Add(v, YesNoPolicy.GetInstance().ComposeMessage(v, service.Locale)); + } + mappings.Add(SecurityGeneratorNumberEntity.REFRESH_PERIOD, validDic); + + List searCriteria = criteria.PackSearchCriteriaDisplay(ref headers, ref sqlWhere, mappings); + + SecurityGeneratorNumberEntity entity = SecurityGeneratorNumberEntity.GetInstance(); + string sql = entity.GetSelectFrom() + " where 1=1 " + sqlWhere; + + SecurityGeneratorNumberEntity[] list = repository.FromSql(sql).ToArray(); + + return new DataToExcelHelper(service).ToExcel(criteria.ReportName, criteria.ReportName, searCriteria, headers.ToArray(), list, mappings); + + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityGeneratorNumber, operate: Operate.Insert)] + [UnitOfWork] + public SecurityGeneratorNumberEntity Insert(SecurityGeneratorNumberEntity data) + { + throw new NotImplementedException(); + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityGeneratorNumber, operate: Operate.Update)] + [UnitOfWork] + public SecurityGeneratorNumberEntity Update(SecurityGeneratorNumberEntity data) + { + SecurityGeneratorNumberEntity entity = repository.Entities.Where(x => x.GeneratorId == data.GeneratorId).FirstOrDefault()!; + if (entity == null) + { + throw new ValidatedException("记录不存在."); + } + + entity.RefreshPeriod = data.RefreshPeriod; + entity.NextId = data.NextId; + entity.Format = data.Format; + + repository.UpdateNow(entity); + + return entity; + } + + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityGeneratorNumber, operate: Operate.Delete)] + [UnitOfWork] + public void Delete(int key) + { + SecurityGeneratorNumberEntity entity = repository.Entities.Where(x => x.GeneratorId == key).FirstOrDefault()!; + if (entity == null) + { + throw new ValidatedException("记录不存在."); + } + + repository.DeleteNow(entity); + } + + + public string GetNo(string systemId, string subsystemId) + { + return GetNo(systemId, subsystemId, null); + } + + public string GetNo(string systemId, string subsystemId, string prefix) + { + return GetNo(systemId, subsystemId, prefix, null, null); + } + + public string GetNo(string systemId, string subsystemId, string prefix, string refreshPeriod, string format) + { + SecurityGeneratorNumberEntity number = null; + + if (!string.IsNullOrEmpty(systemId) && !string.IsNullOrEmpty(subsystemId)) + { + SecurityGeneratorNumberEntity[] tps = repository.Entities.Where(x => x.SystemId == systemId && x.SubsystemId == subsystemId).ToArray(); + + if (tps != null && tps.Length > 0 && !string.IsNullOrEmpty(prefix)) + { + tps = tps.Where(x => x.Prefix == prefix).ToArray(); + } + + if (tps != null && tps.Length > 0) number = tps[0]; + } + + if (number == null) + { + number = new SecurityGeneratorNumberEntity(); + + number.SystemId = string.IsNullOrEmpty(systemId) ? string.Empty : systemId; + number.SubsystemId = string.IsNullOrEmpty(subsystemId) ? string.Empty : subsystemId; + + number.Prefix = string.IsNullOrEmpty(prefix) ? string.Empty : prefix; + number.RefreshPeriod = string.IsNullOrEmpty(refreshPeriod) ? YesNoPolicy.YES : refreshPeriod; + number.Format = string.IsNullOrEmpty(format) ? "yyMMdd000000" : format; + number.LastGeneratorDate = DateTime.Now; + number.NextId = 2; + + repository.InsertNow(number); + } + else + { + number.NextId += 1; + + number.LastGeneratorDate = DateTime.Now; + repository.UpdateNow(number); + } + + format = number.Format; + + if (number.LastGeneratorDate.Date.Subtract(DateTime.Now.Date).TotalDays != 0 && number.RefreshPeriod == YesNoPolicy.YES) + { + number.NextId = 1; + } + + string temp = format.Replace("0", "").Replace("yyyy", DateTime.Now.ToString("yyyy"), StringComparison.OrdinalIgnoreCase).Replace("yy", DateTime.Now.ToString("yy"), StringComparison.OrdinalIgnoreCase) + .Replace("MM", DateTime.Now.ToString("MM"), StringComparison.OrdinalIgnoreCase).Replace("dd", DateTime.Now.ToString("dd")); + + string zero = format.Replace("y", "").Replace("Y", "").Replace("M", "").Replace("m", "").Replace("d", "").Replace("D", ""); + string code = number.Prefix + temp + string.Format("{0:" + zero + "}", number.NextId - 1); + + Int64 max = Convert.ToInt64(zero.Replace("0", "9")); + if (max == number.NextId) + { + throw new Exception("系统编号已达到最大值."); + } + + return code; + } + + public int GetNextId(string systemId, string subsystemId) + { + return GetNextId(systemId, subsystemId, null); + } + + public int GetNextId(string systemId, string subsystemId, string prefix) + { + return GetNextId(systemId, subsystemId, prefix, null); + } + + public int GetNextId(string systemId, string subsystemId, string prefix, string format) + { + return GetNextId(systemId, subsystemId, prefix, format, 1); + } + + public int GetNextId(string systemId, string subsystemId, string prefix, string format, int length) + { + SecurityGeneratorNumberEntity number = null; + + if (!string.IsNullOrEmpty(systemId) && !string.IsNullOrEmpty(subsystemId)) + { + SecurityGeneratorNumberEntity[] tps = repository.DetachedEntities.Where(x => x.SystemId == systemId && x.SubsystemId == subsystemId).ToArray(); + + if (tps != null && tps.Length > 0 && !string.IsNullOrEmpty(prefix)) + { + tps = tps.Where(x => x.Prefix == prefix).ToArray(); + } + + if (tps != null && tps.Length > 0) number = tps[0]; + } + + if (number == null) + { + number = new SecurityGeneratorNumberEntity(); + + number.SystemId = string.IsNullOrEmpty(systemId) ? string.Empty : systemId; + number.SubsystemId = string.IsNullOrEmpty(subsystemId) ? string.Empty : subsystemId; + + number.Prefix = string.IsNullOrEmpty(prefix) ? string.Empty : prefix; + number.Format = string.IsNullOrEmpty(format) ? "yyMMdd000000" : format; + number.LastGeneratorDate = DateTime.Now; + number.NextId = 1 + length; + number.RefreshPeriod = YesNoPolicy.NO; + + repository.Insert(number); + } + else + { + + number.NextId = number.NextId + length; + + if (number.LastGeneratorDate.Date.Subtract(DateTime.Now.Date).TotalDays != 0 && number.RefreshPeriod == YesNoPolicy.YES) + { + number.NextId = 1 + length; + } + + number.LastGeneratorDate = DateTime.Now; + repository.Update(number); + } + + string zero = number.Format.Replace("y", "").Replace("Y", "").Replace("M", "").Replace("m", "").Replace("d", "").Replace("D", ""); + + Int64 max = Convert.ToInt64(zero.Replace("0", "9")); + if (max == number.NextId - length) + { + throw new Exception("系统编号已达到最大值."); + } + + return number.NextId - length - 1; + } + + } +} diff --git a/CloudBuilder/CloudBuilder.Security.Service/SecurityGroupService.cs b/CloudBuilder/CloudBuilder.Security.Service/SecurityGroupService.cs new file mode 100644 index 0000000..a6a8542 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Service/SecurityGroupService.cs @@ -0,0 +1,295 @@ +using CloudBuilder.Core.DatabaseAccessor; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using CloudBuilder.Core.Extensions; +using CloudBuilder.Core.Service; +using CloudBuilder.Security.Data; +using CloudBuilder.Security.Entity; +using CloudBuilder.Security.Policy; +using CloudBuilder.Security.SearchCriteria; +using CloudBuilder.Security.Utility; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +namespace CloudBuilder.Security.Service +{ + public class SecurityGroupService : ISecurityGroupService + { + private readonly IApplicationService service; + + private IRepository repository; + public SecurityGroupService(IApplicationService service) + { + this.service = service; + repository = service.GetRepository>(); + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityGroup, operate: Operate.Find)] + public SecurityGroupData FindByKey(string key) + { + SecurityGroupData data = new SecurityGroupData(); + if (string.IsNullOrEmpty(key)) return data; + + SecurityGroupEntity group = repository.DetachedEntities.Where(x => x.GroupName == key).FirstOrDefault(); + if (group == null) return data; + + data.SecurityGroup = group; + + + IRepository repositoryGpv = repository.GetRepository>(); + IRepository repositoryGpdv = repository.GetRepository>(); + IRepository repositoryAgv = repository.GetRepository>(); + + SecurityGroupPermissionViewEntity[] sgps = repositoryGpv.DetachedEntities.Where(x => x.GroupName == key).ToArray(); + if (sgps != null && sgps.Length > 0) + data.SecurityGroupPermissionViews = sgps.Select(x => new SecurityGroupPermissionViewDisplayData(x)).ToArray(); + + SecurityGroupPermissionDependentViewEntity[] sgpds = repositoryGpdv.DetachedEntities.Where(x => x.GroupName == key).ToArray(); + if (sgpds != null && sgpds.Length > 0) + data.SecurityGroupPermissionDependentViews = sgpds.Select(x => new SecurityGroupPermissionDependentViewDisplayData(x)).ToArray(); + + + data.SecurityActorGroups = repositoryAgv.DetachedEntities.Where(x => x.GroupName == key).ToArray(); + + return data; + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityGroup, operate: Operate.Find)] + public SecurityGroupEntity[] FindAll() + { + return repository.DetachedEntities.ToArray(); + } + + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityGroup, operate: Operate.Find)] + public SecurityGroupResultData FindBySearchCriteria(SecurityGroupSearchCriteria criteria) + { + SecurityGroupResultData data = new SecurityGroupResultData(); + SecurityGroupEntity[] list = null; + + int count = 0; + + string sqlWhere = null; + + if (criteria.Filter != null && criteria.Filter.Length > 0) + { + sqlWhere = SearchFilter.ComposeWhereClause(criteria.Filter); + } + + SecurityGroupEntity entity = SecurityGroupEntity.GetInstance(); + string sql = entity.GetSelectTopFrom(criteria.limit, criteria.page, criteria.orderby.StringToDbField(), criteria.orderbytag, sqlWhere); + + string err = null; + try + { + list = repository.FromSql(sql).ToArray(); + } + catch (System.Exception ex) + { + err = ex.Message; + } + + + if (list != null && list.Length > 0) + { + sql = entity.GetSelectCountFrom(sqlWhere); + count = Convert.ToInt32(repository.ExecuteScalar(sql)); + } + + data.Limit = criteria.limit; + data.Page = criteria.page; + data.Datas = list; + data.Total = count; + //data.Sql = sql; + data.ErrorMessage = err; + return data; + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityGroup, operate: Operate.Print)] + public dynamic PrintBySearchCriteria(SecurityGroupSearchCriteria criteria) + { + throw new NotImplementedException(); + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityGroup, operate: Operate.Insert)] + [UnitOfWork] + public SecurityGroupData Insert(SecurityGroupData data) + { + SecurityGroupEntity securityGroup = repository.DetachedEntities.Where(x => x.GroupName == data.SecurityGroup.GroupName).FirstOrDefault(); + if (securityGroup != null) + { + throw new ValidatedException("记录已存在."); + } + + ValidateHelper.Validate(service, data.SecurityGroup, SecurityGroupEntity.DB_NAME_SECURITY_GROUP); + + securityGroup = new SecurityGroupEntity(); + + ObjectCopyHelper.Copy(data.SecurityGroup, securityGroup); + + repository.InsertNow(securityGroup); + + SaveSecurityGroupPermission(data); + + SaveSecurityActorGroup(data); + + return FindByKey(data.SecurityGroup.GroupName); + } + + private void SaveSecurityGroupPermission(SecurityGroupData data) + { + IRepository repositoryGp = repository.GetRepository>(); + + SecurityGroupPermissionEntity[] olds = repositoryGp.Entities.Where(x => x.GroupName == data.SecurityGroup.GroupName).ToArray(); + if (olds != null && olds.Length > 0) + { + foreach (SecurityGroupPermissionEntity old in olds) + { + repositoryGp.DeleteNow(old); + } + } + + if (data.SecurityGroupPermissionViews != null && data.SecurityGroupPermissionViews.Length > 0) + foreach (SecurityGroupPermissionViewDisplayData dto in data.SecurityGroupPermissionViews) + { + repositoryGp.InsertNow(new SecurityGroupPermissionEntity() + { + GroupName = data.SecurityGroup.GroupName, + PermissionName = dto.PermissionName, + Dependent = dto.Dependent, + ViewIndc = dto.IsView ? YesNoPolicy.YES : YesNoPolicy.NO, + AmendIndc = dto.IsAmend ? YesNoPolicy.YES : YesNoPolicy.NO, + DeleteIndc = dto.IsDelete ? YesNoPolicy.YES : YesNoPolicy.NO, + CreateIndc = dto.IsCreate ? YesNoPolicy.YES : YesNoPolicy.NO, + }); + } + IRepository repositoryGpd = repository.GetRepository>(); + + SecurityGroupPermissionDependentEntity[] oldds = repositoryGpd.Entities.Where(x => x.GroupName == data.SecurityGroup.GroupName).ToArray(); + if (oldds != null && oldds.Length > 0) + { + foreach (SecurityGroupPermissionDependentEntity old in oldds) + { + repositoryGpd.DeleteNow(old); + } + } + + if (data.SecurityGroupPermissionDependentViews != null && data.SecurityGroupPermissionDependentViews.Length > 0) + foreach (SecurityGroupPermissionDependentViewDisplayData dto in data.SecurityGroupPermissionDependentViews) + { + repositoryGpd.InsertNow(new SecurityGroupPermissionDependentEntity() + { + GroupName = data.SecurityGroup.GroupName, + PermissionName = dto.PermissionName, + DependentDetailName = dto.DependentDetailName, + ViewIndc = dto.IsView ? YesNoPolicy.YES : YesNoPolicy.NO, + AmendIndc = dto.IsAmend ? YesNoPolicy.YES : YesNoPolicy.NO, + DeleteIndc = dto.IsDelete ? YesNoPolicy.YES : YesNoPolicy.NO, + CreateIndc = dto.IsCreate ? YesNoPolicy.YES : YesNoPolicy.NO, + }); + } + } + + private void SaveSecurityActorGroup(SecurityGroupData data) + { + IRepository repositoryAg = repository.GetRepository>(); + + SecurityActorGroupEntity[] olds = repositoryAg.Entities.Where(x => x.GroupName == data.SecurityGroup.GroupName).ToArray(); + if (olds != null && olds.Length > 0) + { + foreach (SecurityActorGroupEntity old in olds) + { + repositoryAg.DeleteNow(old); + } + } + + if (data.SecurityActorGroups != null && data.SecurityActorGroups.Length > 0) + foreach (SecurityActorGroupViewEntity dto in data.SecurityActorGroups) + { + repositoryAg.InsertNow(new SecurityActorGroupEntity() + { + GroupName = data.SecurityGroup.GroupName, + ActorName = dto.ActorName, + }); + } + + } + + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityGroup, operate: Operate.Update)] + [UnitOfWork] + public SecurityGroupData Update(SecurityGroupData data) + { + SecurityGroupEntity securityGroup = repository.DetachedEntities.Where(x => x.GroupName == data.SecurityGroup.GroupName).FirstOrDefault(); + if (securityGroup == null) + { + throw new ValidatedException("记录不存在."); + } + + ValidateHelper.Validate(service, data.SecurityGroup, SecurityGroupEntity.DB_NAME_SECURITY_GROUP); + + ObjectCopyHelper.Copy(data.SecurityGroup, securityGroup); + + repository.UpdateNow(securityGroup); + + SaveSecurityGroupPermission(data); + + SaveSecurityActorGroup(data); + + return FindByKey(data.SecurityGroup.GroupName); + } + + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityGroup, operate: Operate.Delete)] + [UnitOfWork] + public void Delete(string key) + { + SecurityGroupEntity securityGroup = repository.DetachedEntities.Where(x => x.GroupName == key).FirstOrDefault(); + if (securityGroup == null) + { + throw new ValidatedException("记录不存在."); + } + + repository.DeleteNow(securityGroup); + + IRepository repositoryGp = repository.GetRepository>(); + IRepository repositoryGpd = repository.GetRepository>(); + + SecurityGroupPermissionEntity[] olds = repositoryGp.Entities.Where(x => x.PermissionName == key).ToArray(); + if (olds != null && olds.Length > 0) + { + foreach (SecurityGroupPermissionEntity old in olds) + { + repositoryGp.DeleteNow(old); + } + } + + SecurityGroupPermissionDependentEntity[] oldds = repositoryGpd.Entities.Where(x => x.PermissionName == key).ToArray(); + if (oldds != null && oldds.Length > 0) + { + foreach (SecurityGroupPermissionDependentEntity old in oldds) + { + repositoryGpd.DeleteNow(old); + } + } + + IRepository repositoryAg = repository.GetRepository>(); + SecurityActorGroupEntity[] oldAgs = repositoryAg.Entities.Where(x => x.GroupName == key).ToArray(); + if (oldAgs != null && oldAgs.Length > 0) + { + foreach (SecurityActorGroupEntity old in oldAgs) + { + repositoryAg.DeleteNow(old); + } + } + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityGroup, operate: Operate.Delete)] + [UnitOfWork] + public void Deletes(string[] keys) + { + foreach (string key in keys) + { + Delete(key); + } + } + } +} diff --git a/CloudBuilder/CloudBuilder.Security.Service/SecurityLockService.auto.cs b/CloudBuilder/CloudBuilder.Security.Service/SecurityLockService.auto.cs new file mode 100644 index 0000000..19c0de0 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Service/SecurityLockService.auto.cs @@ -0,0 +1,220 @@ +using CloudBuilder.Core.DatabaseAccessor; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using CloudBuilder.Core.DependencyInjection.Request; +using CloudBuilder.Core.Policy; +using CloudBuilder.Core.Service; +using CloudBuilder.Gui; +using CloudBuilder.Security.Entity; +using CloudBuilder.Security.Policy; +using CloudBuilder.Security.SearchCriteria; +using DocumentFormat.OpenXml.Spreadsheet; +using Microsoft.AspNetCore.Authorization; +using Microsoft.Extensions.DependencyInjection; +namespace CloudBuilder.Security.Service +{ + public class SecurityLockService : ISecurityLockService + { + + + //if key is non string type, it is expected to convert to string before using this process + + //usage: + //1. UI call Lock to hold entity, exception would be thrown if entity held by others + //2. upon finish edition, UI call ConsumeLock to free the reserved lock, + // exception would be thrown if the lock is overrided either by super user or after expiery + + public const double ACTIVE_WINDOW_MINUTES = -30D;//allow lock 30 minutes + + private SecurityMessagePolicy securityMessagePolicy; + private readonly IApplicationService service; + private readonly ILocaleMessageManager localeMessageManager; + private readonly IContext context; + private IRepository repository; + public SecurityLockService(IApplicationService service, ILocaleMessageManager localeMessageManager, IContext context) + { + this.service = service; + this.localeMessageManager = localeMessageManager; + this.context = context; + repository = service.GetRepository>(); + securityMessagePolicy = service.ServiceProvider.GetRequiredKeyedService(typeof(SecurityMessagePolicy).Name); + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityLock, operate: Operate.Find)] + public SecurityLockEntity FindByKey(SecurityLockEntityKey key) + { + return repository.DetachedEntities.Where(x => 1 == 1 + && x.EntityName == key.EntityName + && x.PkeyId == key.PkeyId + && x.LockedByActor == key.LockedByActor + ).FirstOrDefault()!; + } + + //[PermissionOperate(name: SecurityPermissionPolicy.SecurityLock, operate: Operate.Find)] + public dynamic FindBySearchCriteria(SecurityLockSearchCriteria criteria) + { + throw new NotImplementedException(); + } + + //[PermissionOperate(name: SecurityPermissionPolicy.SecurityLock, operate: Operate.Print)] + public dynamic PrintBySearchCriteria(SecurityLockSearchCriteria criteria) + { + throw new NotImplementedException(); + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityLock, operate: Operate.Insert)] + [UnitOfWork] + public SecurityLockEntity Insert(SecurityLockEntity data) + { + repository.InsertNow(data); + + return data; + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityLock, operate: Operate.Update)] + [UnitOfWork] + public SecurityLockEntity Update(SecurityLockEntity data) + { + throw new NotImplementedException(); + } + + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityLock, operate: Operate.Delete)] + public void Delete(SecurityLockEntityKey key) + { + SecurityLockEntity ent = repository.DetachedEntities.Where(x => 1 == 1 + && x.EntityName == key.EntityName + && x.PkeyId == key.PkeyId + && x.LockedByActor == key.LockedByActor + ).FirstOrDefault()!; + if (ent != null) { repository.DeleteNow(ent); } + } + + [AllowAnonymous] + public bool IsLocked(string entityName, string key) + { + SecurityLockEntity ent = null; + return IsLocked(entityName, key, out ent); + } + + public bool IsLocked(string entityName, string key, out SecurityLockEntity ent) + { + //find active lock + ent = FindActiveLock(entityName, key); + if (ent != null) return true; + + return false; + } + + + private SecurityLockEntity FindActiveLock(string entityName, string key) + { + SecurityLockEntity entLock = FindSingleByEntityNameAndPkeyId(entityName, key); + + if (entLock == null) return null; + + DateTime effectiveDt = DateTime.Now.AddMinutes(ACTIVE_WINDOW_MINUTES); + if (entLock.CreatedDatetime.CompareTo(effectiveDt) < 0) + { + //it's an expired lock, remove it + repository.DeleteNow(entLock); + return null; + } + + //it's an effective one + return entLock; + } + + private SecurityLockEntity FindSingleByEntityNameAndPkeyId(string entityName, string key) + { + SecurityLockEntity[] entLocks = FindByEntityNameAndPkeyId(entityName, key); + if (entLocks == null || entLocks.Length <= 0) return null; + return entLocks[0]; + } + + private SecurityLockEntity[] FindByEntityNameAndPkeyId(string entityName, string key) + { + SecurityLockEntity[] entLocks = repository.DetachedEntities.Where(x => 1 == 1 + && x.EntityName == entityName + && x.PkeyId == key + ).OrderByDescending(x => x.CreatedDatetime).ToArray(); + + if (entLocks == null && entLocks.Length <= 0) return null; + + return entLocks; + } + + [AllowAnonymous] + public void Lock(string entityName, string key, string username) + { + Lock(entityName, key, username, false); + } + + private void Lock(string entityName, string key, string username, bool forceLock) + { + if (!forceLock) + { + SecurityLockEntity actLock = FindActiveLock(entityName, key); + if (actLock != null && !actLock.LockedByActor.Equals(username)) + { + //"{0} [{1}] is locked by [{2}] on [{3}]"; + //throw new ValidatedException(entityName + " [" + key + "] is locked by [" + actLock.LockedByActor + "] on [" + actLock.CreatedDatetime + "]"); + ISecurityUserService securityLockService = service.ServiceProvider.GetService()!; + var user = securityLockService.FindByStaffId(actLock.LockedByActor); + string lockedByActor = actLock.LockedByActor; + + if (user != null) lockedByActor = user.UserLocalName; + + throw new ValidatedException(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.LOCKED, localeMessageManager.ComposeMessage(typeof(SecurityLockService).Name, entityName), key, + lockedByActor, + actLock.CreatedDatetime.GetFormattedDateString("yyyy-MM-dd HH:mm:ss"))); + } + + } + + ClearLock(entityName, key); + + + SecurityLockEntity newLock = new SecurityLockEntity(); + newLock.EntityName = entityName; + newLock.PkeyId = key; + newLock.LockedByActor = username; + Insert(newLock); + } + + [AllowAnonymous] + public void ForceLock(string entityName, string key, string username) + { + Lock(entityName, key, username, true); + } + + [AllowAnonymous] + public void ConsumeLock(string entityName, string key, string username) + { + SecurityLockEntity actLock = FindActiveLock(entityName, key); + if (actLock == null) return; + if (!actLock.LockedByActor.Equals(username)) + { + ISecurityUserService securityLockService = service.ServiceProvider.GetService()!; + var user = securityLockService.FindByStaffId(actLock.LockedByActor); + string lockedByActor = actLock.LockedByActor; + + if (user != null) lockedByActor = user.UserLocalName; + + throw new ValidatedException(securityMessagePolicy.ComposeMessage(SecurityMessagePolicy.EXPIRED, entityName, key, lockedByActor, actLock.CreatedDatetime)); + //throw new ValidatedException("Your lock is expired or force removed. " + entityName + " [" + key + "] is locked by [" + actLock.LockedByActor + "] on [" + actLock.CreatedDatetime + "]"); + } + + ClearLock(entityName, key); + } + + [AllowAnonymous] + public void ClearLock(string entityName, string key) + { + //find all the locks, then purge + SecurityLockEntity[] entities = FindByEntityNameAndPkeyId(entityName, key); + if (entities == null || entities.Length <= 0) return; + + repository.DeleteNow(entities); + } + } +} diff --git a/CloudBuilder/CloudBuilder.Security.Service/SecurityMasterService.cs b/CloudBuilder/CloudBuilder.Security.Service/SecurityMasterService.cs new file mode 100644 index 0000000..6f05a24 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Service/SecurityMasterService.cs @@ -0,0 +1,177 @@ +using CloudBuilder.Core.DatabaseAccessor; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using CloudBuilder.Core.Extensions; +using CloudBuilder.Core.Policy; +using CloudBuilder.Core.Report; +using CloudBuilder.Core.Service; +using CloudBuilder.Security.Data; +using CloudBuilder.Security.Entity; +using CloudBuilder.Security.Policy; +using CloudBuilder.Security.SearchCriteria; +using CloudBuilder.Security.Utility; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System.Security.Permissions; +namespace CloudBuilder.Security.Service +{ + public class SecurityMasterService : ISecurityMasterService + { + private readonly IApplicationService service; + + private IRepository repository; + public SecurityMasterService(IApplicationService service) + { + this.service = service; + repository = service.GetRepository>(); + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityMaster, operate: Operate.Find)] + public SecurityMasterEntity FindByKey(SecurityMasterEntityKey key) + { + return repository.DetachedEntities.Where(x => x.MasterCategory == key.MasterCategory + && x.MasterSubcategory == key.MasterSubcategory + && x.MasterCodeItem == key.MasterCodeItem + ).FirstOrDefault()!; + } + + [AllowAnonymous] + [HttpGet] + public SecurityMasterEntity[] FindAll() + { + return repository.DetachedEntities.ToArray(); + } + + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityMaster, operate: Operate.Find)] + public SecurityMasterResultData FindBySearchCriteria(SecurityMasterSearchCriteria criteria) + { + SecurityMasterResultData data = new SecurityMasterResultData(); + SecurityMasterEntity[] list = null; + + int count = 0; + + string sqlWhere = null; + + if (criteria.Filter != null && criteria.Filter.Length > 0) + { + sqlWhere = SearchFilter.ComposeWhereClause(criteria.Filter); + } + + SecurityMasterEntity entity = SecurityMasterEntity.GetInstance(); + string sql = entity.GetSelectTopFrom(criteria.limit, criteria.page, criteria.orderby.StringToDbField(), criteria.orderbytag, sqlWhere); + + string err = null; + try + { + list = repository.FromSql(sql).ToArray(); + } + catch (System.Exception ex) + { + err = ex.Message; + } + + + if (list != null && list.Length > 0) + { + sql = entity.GetSelectCountFrom(sqlWhere); + count = Convert.ToInt32(repository.ExecuteScalar(sql)); + } + + data.Limit = criteria.limit; + data.Page = criteria.page; + data.Datas = list; + data.Total = count; + //data.Sql = sql; + data.ErrorMessage = err; + return data; + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityMaster, operate: Operate.Print)] + public dynamic PrintBySearchCriteria(SecurityMasterSearchCriteria criteria) + { + string sqlWhere = string.Empty; + List headers = new List(); + + Dictionary> mappings = new Dictionary>(); + Dictionary validDic = new Dictionary(); + foreach (string v in YesNoPolicy.GetInstance().GetValues()) + { + validDic.Add(v, YesNoPolicy.GetInstance().ComposeMessage(v, service.Locale)); + } + mappings.Add(SecurityMasterEntity.VALID_INDC, validDic); + + List searCriteria = criteria.PackSearchCriteriaDisplay(ref headers, ref sqlWhere, mappings); + + SecurityMasterEntity entity = SecurityMasterEntity.GetInstance(); + string sql = entity.GetSelectFrom() + " where 1=1 " + sqlWhere; + + SecurityMasterEntity[] list = repository.FromSql(sql).ToArray(); + + return new DataToExcelHelper(service).ToExcel(criteria.ReportName, criteria.ReportName, searCriteria, headers.ToArray(), list, mappings); + + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityMaster, operate: Operate.Insert)] + [UnitOfWork] + public SecurityMasterEntity Insert(SecurityMasterEntity data) + { + SecurityMasterEntity securityMaster = repository.DetachedEntities.Where(x => x.MasterCategory == data.MasterCategory && + x.MasterSubcategory == data.MasterSubcategory && x.MasterCodeItem == data.MasterCodeItem).FirstOrDefault()!; + if (securityMaster != null) + { + throw new ValidatedException("记录已存在."); + } + + ValidateHelper.Validate(service, data, SecurityMasterEntity.DB_NAME_SECURITY_MASTER); + + securityMaster = new SecurityMasterEntity(); + + ObjectCopyHelper.Copy(data, securityMaster); + + securityMaster.ValidIndc = YesNoPolicy.YES; + repository.InsertNow(securityMaster); + + return FindByKey(new SecurityMasterEntityKey { MasterCategory = data.MasterCategory, MasterCodeItem = data.MasterCodeItem, MasterSubcategory = data.MasterSubcategory }); + + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityMaster, operate: Operate.Update)] + [UnitOfWork] + public SecurityMasterEntity Update(SecurityMasterEntity data) + { + SecurityMasterEntity securityMaster = repository.DetachedEntities.Where(x => x.MasterCategory == data.MasterCategory && + x.MasterSubcategory == data.MasterSubcategory && x.MasterCodeItem == data.MasterCodeItem).FirstOrDefault()!; + if (securityMaster == null) + { + throw new ValidatedException("记录不存在."); + } + + ValidateHelper.Validate(service, data, SecurityMasterEntity.DB_NAME_SECURITY_MASTER); + ObjectCopyHelper.Copy(data, securityMaster); + + repository.UpdateNow(securityMaster); + + return FindByKey(new SecurityMasterEntityKey { MasterCategory = data.MasterCategory, MasterCodeItem = data.MasterCodeItem, MasterSubcategory = data.MasterSubcategory }); + } + + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityMaster, operate: Operate.Delete)] + public void Delete(SecurityMasterEntityKey key) + { + SecurityMasterEntity ent = repository.DetachedEntities.Where(x => x.MasterCategory == key.MasterCategory + && x.MasterSubcategory == key.MasterSubcategory + && x.MasterCodeItem == key.MasterCodeItem + ).FirstOrDefault()!; + if (ent != null) { repository.DeleteNow(ent); } + } + + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityMaster, operate: Operate.Delete)] + public void Deletes(SecurityMasterEntity[] datas) + { + if (datas == null || datas.Length == 0) return; + repository.DeleteNow(datas); + } + + } +} diff --git a/CloudBuilder/CloudBuilder.Security.Service/SecurityPermissionService.cs b/CloudBuilder/CloudBuilder.Security.Service/SecurityPermissionService.cs new file mode 100644 index 0000000..b8a389b --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Service/SecurityPermissionService.cs @@ -0,0 +1,300 @@ +using CloudBuilder.Core.DatabaseAccessor; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using CloudBuilder.Core.Extensions; +using CloudBuilder.Core.Service; +using CloudBuilder.Security.Data; +using CloudBuilder.Security.Entity; +using CloudBuilder.Security.Policy; +using CloudBuilder.Security.SearchCriteria; +using CloudBuilder.Security.Utility; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; +namespace CloudBuilder.Security.Service +{ + public class SecurityPermissionService : ISecurityPermissionService + { + private readonly IApplicationService service; + + private IRepository repository; + public SecurityPermissionService(IApplicationService service) + { + this.service = service; + repository = service.GetRepository>(); + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityPermission, operate: Operate.Find)] + public SecurityPermissionData FindByKey(string key) + { + SecurityPermissionData data = new SecurityPermissionData(); + if (string.IsNullOrEmpty(key)) return data; + + SecurityPermissionEntity permission = repository.DetachedEntities.Where(x => x.PermissionName == key).FirstOrDefault(); + + if (permission == null) return data; + + data.SecurityPermission = permission; + + IRepository repositoryDependent = repository.GetRepository>(); + + SecurityPermissionDependentEntity[] dpts = repositoryDependent.DetachedEntities.Where(x => x.PermissionName == key).ToArray(); + if (dpts != null && dpts.Length > 0) + { + data.SecurityPermissionDependents = dpts; + } + + return data; + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityPermission, operate: Operate.Find)] + public SecurityPermissionResultData FindBySearchCriteria(SecurityPermissionSearchCriteria criteria) + { + SecurityPermissionResultData data = new SecurityPermissionResultData(); + SecurityPermissionEntity[] list = null; + + int count = 0; + + string sqlWhere = null; + + if (criteria.Filter != null && criteria.Filter.Length > 0) + { + sqlWhere = SearchFilter.ComposeWhereClause(criteria.Filter); + } + + SecurityPermissionEntity entity = SecurityPermissionEntity.GetInstance(); + string sql = entity.GetSelectTopFrom(criteria.limit, criteria.page, criteria.orderby.StringToDbField(), criteria.orderbytag, sqlWhere); + + string err = null; + try + { + list = repository.FromSql(sql).ToArray(); + } + catch (System.Exception ex) + { + err = ex.Message; + } + + + if (list != null && list.Length > 0) + { + sql = entity.GetSelectCountFrom(sqlWhere); + count = Convert.ToInt32(repository.ExecuteScalar(sql)); + } + + data.Limit = criteria.limit; + data.Page = criteria.page; + data.Permissions = list; + data.Total = count; + //data.Sql = sql; + data.ErrorMessage = err; + return data; + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityPermission, operate: Operate.Find)] + public SecurityPermissionResultData FindDependentBySearchCriteria(SecurityPermissionSearchCriteria criteria) + { + SecurityPermissionResultData data = new SecurityPermissionResultData(); + SecurityPermissionDependentEntity[] list = null; + IRepository repositoryDependent = service.GetRepository>(); + int count = 0; + + string sqlWhere = null; + + if (criteria.Filter != null && criteria.Filter.Length > 0) + { + sqlWhere = SearchFilter.ComposeWhereClause(criteria.Filter); + } + + SecurityPermissionDependentEntity entity = SecurityPermissionDependentEntity.GetInstance(); + string sql = entity.GetSelectTopFrom(criteria.limit, criteria.page, criteria.orderby.StringToDbField(), criteria.orderbytag, sqlWhere); + + string err = null; + try + { + list = repositoryDependent.FromSql(sql).ToArray(); + } + catch (System.Exception ex) + { + err = ex.Message; + } + + + if (list != null && list.Length > 0) + { + sql = entity.GetSelectCountFrom(sqlWhere); + count = (int)repositoryDependent.ExecuteScalar(sql); + } + + data.Limit = criteria.limit; + data.Page = criteria.page; + data.Dependents = list; + data.Total = count; + //data.Sql = sql; + data.ErrorMessage = err; + return data; + } + + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityPermission, operate: Operate.Find)] + public SecurityPermissionResultData FindDependentsBySearchCriteria(SecurityPermissionSearchCriteria criteria) + { + SecurityPermissionResultData data = new SecurityPermissionResultData(); + SecurityPermissionDependentEntity[] list = null; + + int count = 0; + + string sqlWhere = null; + + if (criteria.Filter != null && criteria.Filter.Length > 0) + { + sqlWhere = SearchFilter.ComposeWhereClause(criteria.Filter); + } + + SecurityPermissionDependentEntity entity = SecurityPermissionDependentEntity.GetInstance(); + string sql = entity.GetSelectTopFrom(criteria.limit, criteria.page, criteria.orderby.StringToDbField(), criteria.orderbytag, sqlWhere); + + IRepository repositoryDependent = repository.GetRepository>(); + + + string err = null; + try + { + list = repositoryDependent.FromSql(sql).ToArray(); + } + catch (System.Exception ex) + { + err = ex.Message; + } + + + if (list != null && list.Length > 0) + { + sql = entity.GetSelectCountFrom(sqlWhere); + count = Convert.ToInt32(repository.ExecuteScalar(sql)); + } + + data.Limit = criteria.limit; + data.Page = criteria.page; + data.Dependents = list; + data.Total = count; + //data.Sql = sql; + data.ErrorMessage = err; + return data; + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityPermission, operate: Operate.Print)] + public dynamic PrintBySearchCriteria(SecurityPermissionSearchCriteria criteria) + { + throw new NotImplementedException(); + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityPermission, operate: Operate.Insert)] + [UnitOfWork] + public SecurityPermissionData Insert(SecurityPermissionData data) + { + SecurityPermissionEntity securityPermission = repository.DetachedEntities.Where(x => x.PermissionName == data.SecurityPermission.PermissionName).FirstOrDefault(); + if (securityPermission != null) + { + throw new ValidatedException("记录已存在."); + } + + ValidateHelper.Validate(service, data.SecurityPermission, SecurityPermissionEntity.DB_NAME_SECURITY_PERMISSION); + + securityPermission = new SecurityPermissionEntity(); + ObjectCopyHelper.Copy(data.SecurityPermission, securityPermission); + + repository.InsertNow(securityPermission); + + SaveSecurityPermissionDependents(securityPermission.PermissionName, securityPermission.Dependent, data.SecurityPermissionDependents); + + return FindByKey(data.SecurityPermission.PermissionName); + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityPermission, operate: Operate.Update)] + [UnitOfWork] + public SecurityPermissionData Update(SecurityPermissionData data) + { + SecurityPermissionEntity securityPermission = repository.DetachedEntities.Where(x => x.PermissionName == data.SecurityPermission.PermissionName).FirstOrDefault(); + if (securityPermission == null) + { + throw new ValidatedException("记录不存在."); + } + + ValidateHelper.Validate(service, data.SecurityPermission, SecurityPermissionEntity.DB_NAME_SECURITY_PERMISSION); + + ObjectCopyHelper.Copy(data.SecurityPermission, securityPermission); + + repository.UpdateNow(securityPermission); + + SaveSecurityPermissionDependents(securityPermission.PermissionName, securityPermission.Dependent, data.SecurityPermissionDependents); + + return FindByKey(data.SecurityPermission.PermissionName); + } + + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityPermission, operate: Operate.Delete)] + [UnitOfWork] + public void Delete(string key) + { + SecurityPermissionEntity SecurityPermission = repository.DetachedEntities.Where(x => x.PermissionName == key).FirstOrDefault(); + if (SecurityPermission == null) + { + throw new ValidatedException("记录不存在."); + } + + repository.DeleteNow(SecurityPermission); + + + IRepository repositoryDependent = repository.GetRepository>(); + + SecurityPermissionDependentEntity[] olds = repositoryDependent.Entities.Where(x => x.PermissionName == key).ToArray(); + if (olds != null && olds.Length > 0) + { + foreach (SecurityPermissionDependentEntity old in olds) + { + repositoryDependent.DeleteNow(old); + } + } + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityPermission, operate: Operate.Delete)] + [UnitOfWork] + public void Deletes(string[] keys) + { + foreach (string key in keys) + { + Delete(key); + } + } + + private void SaveSecurityPermissionDependents(string permissionName, string dependent, SecurityPermissionDependentEntity[] dependents) + { + IRepository repositoryDependent = repository.GetRepository>(); + + SecurityPermissionDependentEntity[] olds = repositoryDependent.Entities.Where(x => x.PermissionName == permissionName).ToArray(); + if (olds != null && olds.Length > 0) + { + foreach (SecurityPermissionDependentEntity old in olds) + { + repositoryDependent.DeleteNow(old); + } + } + + if (dependents == null || dependents.Length == 0) return; + + foreach (SecurityPermissionDependentEntity dto in dependents) + { + ValidateHelper.Validate(service, dto, SecurityPermissionDependentEntity.DB_NAME_SECURITY_PERMISSION_DEPENDENT); + + repositoryDependent.InsertNow(new SecurityPermissionDependentEntity() + { + PermissionName = permissionName, + Dependent = dependent, + DependentDetailName = dto.DependentDetailName, + DependentDetailDescription = dto.DependentDetailDescription + }); + } + + } + } +} diff --git a/CloudBuilder/CloudBuilder.Security.Service/SecurityUserPreferenceService.cs b/CloudBuilder/CloudBuilder.Security.Service/SecurityUserPreferenceService.cs new file mode 100644 index 0000000..6845339 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Service/SecurityUserPreferenceService.cs @@ -0,0 +1,84 @@ +using CloudBuilder.Core.DatabaseAccessor; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using CloudBuilder.Security.Entity; +using CloudBuilder.Security.Policy; +using CloudBuilder.Security.SearchCriteria; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +namespace CloudBuilder.Security.Service +{ + public class SecurityUserPreferenceService : ISecurityUserPreferenceService + { + private readonly IApplicationService service; + + private IRepository repository; + public SecurityUserPreferenceService(IApplicationService service) + { + this.service = service; + repository = service.GetRepository>(); + } + + [AllowAnonymous] + public SecurityUserPreferenceEntity FindByKey(SecurityUserPreferenceEntityKey key) + { + return repository.DetachedEntities.Where(x => 1 == 1 + && x.Username == service.UserId + && x.PreferenceKey == key.PreferenceKey + ).FirstOrDefault()!; + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityUserPreference, operate: Operate.Find)] + public SecurityUserPreferenceEntity[] FindBySearchCriteria(SecurityUserPreferenceSearchCriteria criteria) + { + throw new NotImplementedException(); + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityUserPreference, operate: Operate.Print)] + public dynamic PrintBySearchCriteria(SecurityUserPreferenceSearchCriteria criteria) + { + throw new NotImplementedException(); + } + + [AllowAnonymous] + [UnitOfWork] + public SecurityUserPreferenceEntity Insert(SecurityUserPreferenceEntity data) + { + SecurityUserPreferenceEntity preferenceEntity = repository.DetachedEntities.Where(x => x.Username == data.Username && +x.PreferenceKey == data.PreferenceKey).FirstOrDefault()!; + if (preferenceEntity != null) { repository.DeleteNow(preferenceEntity); } + + repository.InsertNow(data); + return data!; + } + + [AllowAnonymous] + [UnitOfWork] + public SecurityUserPreferenceEntity Update(SecurityUserPreferenceEntity data) + { + SecurityUserPreferenceEntity preferenceEntity = repository.DetachedEntities.Where(x => x.Username == data.Username && +x.PreferenceKey == data.PreferenceKey).FirstOrDefault()!; + if (preferenceEntity == null) + { + repository.InsertNow(data); + } + else + { + preferenceEntity.Preference = data.Preference; + repository.UpdateNow(preferenceEntity); + } + + return data!; + } + + + [AllowAnonymous] + public void Delete(SecurityUserPreferenceEntityKey key) + { + SecurityUserPreferenceEntity ent = repository.DetachedEntities.Where(x => 1 == 1 + && x.Username == key.Username + && x.PreferenceKey == key.PreferenceKey + ).FirstOrDefault()!; + if (ent != null) { repository.DeleteNow(ent); } + } + } +} diff --git a/CloudBuilder/CloudBuilder.Security.Service/SecurityUserService.cs b/CloudBuilder/CloudBuilder.Security.Service/SecurityUserService.cs new file mode 100644 index 0000000..290304b --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Service/SecurityUserService.cs @@ -0,0 +1,353 @@ +using CloudBuilder.Core.DatabaseAccessor; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using CloudBuilder.Core.Extensions; +using CloudBuilder.Core.Policy; +using CloudBuilder.Core.Service; +using CloudBuilder.Security.Data; +using CloudBuilder.Security.Entity; +using CloudBuilder.Security.Policy; +using CloudBuilder.Security.SearchCriteria; +using CloudBuilder.Security.Service.Authorization; +using CloudBuilder.Security.Utility; +using DocumentFormat.OpenXml.Spreadsheet; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Security.Permissions; +namespace CloudBuilder.Security.Service +{ + public class SecurityUserService : ISecurityUserService + { + private readonly IApplicationService service; + private readonly IHttpContextAccessor httpContextAccessor; + private IRepository repository; + public SecurityUserService(IApplicationService service, IHttpContextAccessor httpContextAccessor) + { + this.service = service; + this.httpContextAccessor = httpContextAccessor; + repository = service.GetRepository>(); + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityUser, operate: Operate.Find)] + public SecurityUserEntity FindByStaffId(string staffid) + { + return repository.DetachedEntities.Where(x => x.UserName == staffid).FirstOrDefault(); + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityUser, operate: Operate.Find)] + public SecurityUserData FindByKey(string key) + { + SecurityUserData data = new SecurityUserData(); + if (string.IsNullOrEmpty(key)) return data; + + SecurityUserEntity user = repository.DetachedEntities.Where(x => x.UserName == key).FirstOrDefault(); + + if (user == null) return data; + + string uid = service.UserId; + + PermissionContext permissionContext = new PermissionContext(service); + + if (user.UserName != uid && permissionContext.CanView(SecurityPermissionPolicy.CanSeeAllUser)) + { + return data; + } + + data.SecurityUser = new SecurityUserDisplayData(user); + + IRepository repositoryUav = repository.GetRepository>(); + + data.SecurityUserActors = repositoryUav.DetachedEntities.Where(x => x.UserName == key).ToArray(); + + return data; + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityUser, operate: Operate.Find)] + public SecurityUserEntity[] FindAll() + { + return repository.DetachedEntities.ToArray(); + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityUser, operate: Operate.Find)] + public SecurityUserResultData FindBySearchCriteria(SecurityUserSearchCriteria criteria) + { + SecurityUserResultData data = new SecurityUserResultData(); + SecurityUserEntity[] list = null; + + int count = 0; + + string sqlWhere = null; + + if (criteria.Filter != null && criteria.Filter.Length > 0) + { + sqlWhere = SearchFilter.ComposeWhereClause(criteria.Filter); + } + + //sqlWhere = sqlWhere + string.Format(" and {0} ='{1}' ", SecurityUserEntity.DB_USER_IS_VALID_INDC, YesNoPolicy.YES); + + SecurityUserEntity entity = SecurityUserEntity.GetInstance(); + string sql = entity.GetSelectTopFrom(criteria.limit, criteria.page, criteria.orderby.StringToDbField(), criteria.orderbytag, sqlWhere); + + + + string err = null; + try + { + list = repository.FromSql(sql).ToArray(); + } + catch (System.Exception ex) + { + err = ex.Message; + } + + + if (list != null && list.Length > 0) + { + sql = entity.GetSelectCountFrom(sqlWhere); + count = Convert.ToInt32(repository.ExecuteScalar(sql)); + } + + data.Limit = criteria.limit; + data.Page = criteria.page; + data.Datas = list; + data.Total = count; + //data.Sql = sql; + data.ErrorMessage = err; + return data; + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityUser, operate: Operate.Print)] + public dynamic PrintBySearchCriteria(SecurityUserSearchCriteria criteria) + { + throw new NotImplementedException(); + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityUser, operate: Operate.Insert)] + [UnitOfWork] + public SecurityUserData Insert(SecurityUserData data) + { + SecurityUserEntity securityUser = repository.DetachedEntities.Where(x => x.UserName == data.SecurityUser.UserName).FirstOrDefault(); + if (securityUser != null) + { + throw new ValidatedException("记录已存在."); + } + + ValidateHelper.Validate(service, data.SecurityUser, SecurityUserEntity.DB_NAME_SECURITY_USER); + + securityUser = new SecurityUserEntity(); + + ObjectCopyHelper.Copy(data.SecurityUser, securityUser); + if (!string.IsNullOrEmpty(data.SecurityUser.OrgUserPassword)) + securityUser.UserPassword = data.SecurityUser.OrgUserPassword.GetMd5(); + + securityUser.UserIsValidIndc = YesNoPolicy.YES; + repository.InsertNow(securityUser); + + SaveSecurityUserActor(data); + + return FindByKey(data.SecurityUser.UserName); + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityUser, operate: Operate.Update)] + [UnitOfWork] + public SecurityUserData Update(SecurityUserData data) + { + SecurityUserEntity SecurityUser = repository.DetachedEntities.Where(x => x.UserName == data.SecurityUser.UserName).FirstOrDefault(); + if (SecurityUser == null) + { + throw new ValidatedException("记录不存在."); + } + + ValidateHelper.Validate(service, data.SecurityUser, SecurityUserEntity.DB_NAME_SECURITY_USER); + + ObjectCopyHelper.Copy(data.SecurityUser, SecurityUser); + + if (!string.IsNullOrEmpty(data.SecurityUser.OrgUserPassword)) + { + SecurityUser.UserPassword = data.SecurityUser.OrgUserPassword.GetMd5(); + } + + repository.UpdateNow(SecurityUser); + + SaveSecurityUserActor(data); + + return FindByKey(data.SecurityUser.UserName); + } + + private void SaveSecurityUserActor(SecurityUserData data) + { + IRepository repositoryUa = repository.GetRepository>(); + + SecurityUserActorEntity[] olds = repositoryUa.Entities.Where(x => x.UserName == data.SecurityUser.UserName).ToArray(); + if (olds != null && olds.Length > 0) + { + foreach (SecurityUserActorEntity old in olds) + { + repositoryUa.DeleteNow(old); + } + } + + if (data.SecurityUserActors != null && data.SecurityUserActors.Length > 0) + foreach (SecurityUserActorViewEntity dto in data.SecurityUserActors) + { + repositoryUa.InsertNow(new SecurityUserActorEntity() + { + UserName = data.SecurityUser.UserName, + ActorName = dto.ActorName, + }); + } + + } + + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityUser, operate: Operate.Delete)] + [UnitOfWork] + public void Delete(string key) + { + SecurityUserEntity securityUser = repository.DetachedEntities.Where(x => x.UserName == key).FirstOrDefault(); + if (securityUser == null) + { + throw new ValidatedException("记录不存在."); + } + + securityUser.UserIsValidIndc = "N"; + repository.UpdateNow(securityUser); + + } + + [PermissionOperate(name: SecurityPermissionPolicy.SecurityUser, operate: Operate.Delete)] + [UnitOfWork] + public void Deletes(string[] keys) + { + foreach (string key in keys) + { + Delete(key); + } + } + + [AllowAnonymous] + public SecurityFunctionResultData FindMenuByUsername() + { + string username = service.UserId; + + if (string.IsNullOrEmpty(username)) return null; + + SecurityFunctionResultData data = new SecurityFunctionResultData(); + + var userActors = service.GetRepository>().DetachedEntities.Where(x => x.UserName == username); + + var actorGroups = service.GetRepository>().DetachedEntities.Where(x => userActors.Select(x => x.ActorName).Contains(x.ActorName)); + + var groupPermissions = service.GetRepository>().DetachedEntities.Where(x => actorGroups.Select(x => x.GroupName).Contains(x.GroupName)); + + var pfMaps = service.GetRepository>().DetachedEntities.Where(x => groupPermissions.Select(x => x.PermissionName).Contains(x.PermissionName)); + + SecurityFunctionEntity[] securityFunctions = service.GetRepository>().DetachedEntities.Where(x => pfMaps.Select(x => x.FunctionName).Contains(x.FunctionName)).ToArray(); + if (securityFunctions == null || securityFunctions.Length == 0) return null; + + SecurityFunctionMapEntity[] securityFunctionMaps = service.GetRepository>().DetachedEntities.ToArray(); + + SecurityFunctionEntity[] functions = service.GetRepository>().DetachedEntities.ToArray(); + + if (securityFunctionMaps == null || securityFunctionMaps.Length == 0) return null; + + List displayDatas = new List(); + List maps = new List(); + + foreach (var securityFunction in securityFunctions) + { + PackSecurityFunction(displayDatas, maps, securityFunction, functions, securityFunctionMaps); + } + + data.SecurityFunctionMaps = maps.ToArray(); + data.SecurityFunctionDisplayDatas = displayDatas.OrderBy(x => x.Orderby).ToArray(); + + return data; + } + + private int GetOrderBy(string functionName, ref int level, SecurityFunctionEntity[] securityFunctions, SecurityFunctionMapEntity[] securityFunctionMaps, int baseOrderBy) + { + SecurityFunctionMapEntity[] parents = securityFunctionMaps.Where(x => x.FunctionNameSon == functionName).ToArray(); + int orderBy = 0; + if (parents != null && parents.Length > 0) + { + if (level > 0) + return parents.FirstOrDefault().Orderby * 10000 + baseOrderBy; + else + orderBy = baseOrderBy * 100; + } + else + { + return baseOrderBy * 1000000; + } + + foreach (var parent in parents) + { + level = 0; + SecurityFunctionEntity f = securityFunctions.Where(x => x.FunctionName == parent.FunctionNameParent).FirstOrDefault()!; + if (f == null || f.FunctionName == SecurityFunctionResultData.BOOTUP) continue; + level += 1; + SecurityFunctionMapEntity[] ps = securityFunctionMaps.Where(x => x.FunctionNameSon == functionName).ToArray(); + + orderBy = GetOrderBy(f.FunctionName, ref level, securityFunctions, securityFunctionMaps, parents.FirstOrDefault().Orderby * 100 + baseOrderBy); + } + + if (level == 0) orderBy = parents.FirstOrDefault().Orderby * 10000 + orderBy; + + return orderBy; + } + + private void PackSecurityFunction(List displayDatas, List maps, SecurityFunctionEntity securityFunction, SecurityFunctionEntity[] securityFunctions, SecurityFunctionMapEntity[] securityFunctionMaps) + { + if (!displayDatas.Select(x => x.FunctionName).Contains(securityFunction.FunctionName)) + { + SecurityFunctionMapEntity[] parents = securityFunctionMaps.Where(x => x.FunctionNameSon == securityFunction.FunctionName).ToArray(); + + int orderby = 0; + if (parents != null && parents.Length > 0) + { + foreach (var parent in parents) + { + int level = 0; + orderby = GetOrderBy(parent.FunctionNameParent, ref level, securityFunctions, securityFunctionMaps, parent.Orderby); + + displayDatas.Add(new SecurityFunctionDisplayData(securityFunction) { Orderby = orderby, FunctionNameParent = parent.FunctionNameParent }); + } + } + else + { + //顶级菜单 + orderby = 1000000; + displayDatas.Add(new SecurityFunctionDisplayData(securityFunction) { Orderby = orderby }); + } + + + + foreach (var parent in parents) + { + SecurityFunctionEntity f = securityFunctions.Where(x => x.FunctionName == parent.FunctionNameParent).FirstOrDefault()!; + if (f == null) continue; + maps.Add(parent); + PackSecurityFunction(displayDatas, maps, f, securityFunctions, securityFunctionMaps); + } + } + } + + + [AllowAnonymous] + public void UpdateLocalName(string localName) + { + SecurityUserEntity securityUser = repository.DetachedEntities.Where(x => x.UserName == service.UserId && x.UserIsValidIndc == YesNoPolicy.YES).FirstOrDefault(); + if (securityUser == null) + { + throw new ValidatedException("用户不存在."); + } + securityUser.UserLocalName = localName; + repository.UpdateNow(securityUser); + + } + } +} diff --git a/CloudBuilder/CloudBuilder.Security.Service/Subscriber/InsertSecurityUserActorSubscriber.cs b/CloudBuilder/CloudBuilder.Security.Service/Subscriber/InsertSecurityUserActorSubscriber.cs new file mode 100644 index 0000000..6251a58 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Service/Subscriber/InsertSecurityUserActorSubscriber.cs @@ -0,0 +1,29 @@ +using CloudBuilder.Core.DatabaseAccessor.Entity; +using CloudBuilder.Core.DependencyInjection.EventBuses; +using CloudBuilder.Security.Entity; +using CloudBuilder.Security.Policy; +using CloudBuilder.Security.Subscriber; + +namespace CloudBuilder.Security.Service.Subscriber +{ + public class InsertSecurityUserActorSubscriber : ISecurityUserRegisterSubscriber + { + private readonly IApplicationService service; + + public InsertSecurityUserActorSubscriber(IApplicationService service) + { + this.service = service; + } + + public void Handle(EventData eventData) + { + IRepository repository = service.GetRepository>(); + + SecurityUserActorEntity ent = new SecurityUserActorEntity(); + ent.UserName = ((SecurityUserEntity)eventData.EventSource).UserName; + ent.ActorName = SecurityUserPolicy.SECURITY_USER_BASE_ACTOR; + + repository.InsertNow(ent); + } + } +} diff --git a/CloudBuilder/CloudBuilder.Security.Service/SysTableSchemaViewService.cs b/CloudBuilder/CloudBuilder.Security.Service/SysTableSchemaViewService.cs new file mode 100644 index 0000000..fd82a8b --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Service/SysTableSchemaViewService.cs @@ -0,0 +1,28 @@ +using CloudBuilder.Core.DatabaseAccessor.Entity; +using CloudBuilder.Security.Entity; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Security.Service +{ + public class SysTableSchemaViewService : ISysTableSchemaViewService + { + private readonly IApplicationService service; + private readonly IRepository repository; + public SysTableSchemaViewService(IApplicationService service) + { + repository = service.GetRepository>(); + this.service = service; + } + + + public List FindByTableName(string tableName) + { + List list = repository.DetachedEntities.Where(x => x.TableName == tableName).ToList(); + return list; + } + } +} diff --git a/CloudBuilder/CloudBuilder.Security.Service/WebAuthnAssertionPatcher.cs b/CloudBuilder/CloudBuilder.Security.Service/WebAuthnAssertionPatcher.cs new file mode 100644 index 0000000..34644cf --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Service/WebAuthnAssertionPatcher.cs @@ -0,0 +1,92 @@ +using Fido2NetLib; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Security.Service +{ + + /// + /// Re-encodes the base64url string fields on a freshly-deserialized + /// as byte[]. + /// + /// Fido2NetLib 1.0.0-alpha has these properties typed as string + /// (no [JsonConverter] — that was added in v1.1.0+), but its + /// MakeAssertionAsync internally does + /// (byte[])raw.Id and + /// (byte[])raw.Response.ClientDataJson to look up the credential + /// and verify the signature. The hard cast throws + /// "Unable to cast object of type 'System.String' to type 'System.Byte[]'". + /// + /// This helper was originally a private static method on + /// UserProfileProcess; it was extracted so + /// FinishEpayslipBiometricAssertion (the new epayslip-unlock + /// flow) can share the same Fido2NetLib 1.0.0-alpha workaround without + /// duplicating the reflection-patching logic. + /// + /// Behaviour: + /// 1. Checks the runtime property type. + /// 2. If it's already byte[] (v1.1.0+), base64url-decodes the + /// incoming string and stores the bytes. + /// 3. If it's string (v1.0.0-alpha), we can't store byte[] + /// in a string field — CLR enforces type safety. Fido2NetLib's + /// internal (byte[]) cast will then throw on the next call with a + /// clear InvalidCastException we can diagnose from the stack trace. + /// + public static class WebAuthnAssertionPatcher + { + public static void PatchResponseToByteArrays(AuthenticatorAssertionRawResponse raw) + { + if (raw == null) return; + + PatchStringPropertyToByteArray(raw, "Id"); + PatchStringPropertyToByteArray(raw, "RawId"); + + if (raw.Response != null) + { + PatchStringPropertyToByteArray(raw.Response, "Id"); + PatchStringPropertyToByteArray(raw.Response, "AuthenticatorData"); + PatchStringPropertyToByteArray(raw.Response, "Signature"); + PatchStringPropertyToByteArray(raw.Response, "ClientDataJson"); + PatchStringPropertyToByteArray(raw.Response, "UserHandle"); + } + } + + private static void PatchStringPropertyToByteArray(object target, string propertyName) + { + if (target == null) return; + var prop = target.GetType().GetProperty(propertyName); + if (prop == null) return; + if (!prop.CanWrite) return; + var current = prop.GetValue(target); + // If Fido2NetLib 1.1.0+ shape — property is already byte[]. + if (prop.PropertyType == typeof(byte[])) + { + if (current is byte[]) return; // already decoded by the converter + if (current is string s && !string.IsNullOrEmpty(s)) + { + try { prop.SetValue(target, Fido2NetLib.Base64Url.Decode(s)); } + catch { /* leave original value; Fido2NetLib will surface a clearer error */ } + } + return; + } + // If the property is `object` (1.0.0-alpha may store the raw + // deserialized value as object), we can safely put a byte[] in it. + if (prop.PropertyType == typeof(object)) + { + if (current is string s && !string.IsNullOrEmpty(s)) + { + try { prop.SetValue(target, Fido2NetLib.Base64Url.Decode(s)); } catch { } + } + return; + } + // If the property is `string` (1.0.0-alpha default), we cannot + // store byte[] in a string-typed field — CLR enforces type safety + // even via reflection. Fido2NetLib's internal (byte[]) cast will + // throw on the next call. The caller will see a clear + // InvalidCastException that we can diagnose from the stack trace. + } + } +} diff --git a/CloudBuilder/CloudBuilder.Security.Service/WebAuthnService.cs b/CloudBuilder/CloudBuilder.Security.Service/WebAuthnService.cs new file mode 100644 index 0000000..0b0e163 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Service/WebAuthnService.cs @@ -0,0 +1,221 @@ +using CloudBuilder.Security.Data; +using Fido2NetLib; +using Fido2NetLib.Objects; +using Microsoft.Extensions.Options; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Security.Service +{ + + /// + /// Wraps the Fido2NetLib ceremony primitives (challenge generation, + /// attestation verification, assertion verification) so the process + /// layer can stay focused on the workflow. The frontend drives both + /// registration and login through this service via webmethods on + /// UserProfileProcess. + /// + public class WebAuthnService: IWebAuthnService + { + private readonly Fido2 _fido2; + private readonly WebAuthnOptions _options; + + public WebAuthnService(IOptions options) + { + _options = options.Value; + + var config = new Fido2.Configuration + { + ServerDomain = _options.RpId, + ServerName = _options.RpName, + Origin = _options.Origin, + // Fido2NetLib expresses the challenge length in BYTES here. + // 32 bytes = 256 bits, the WebAuthn-recommended minimum. + ChallengeSize = 32, + Timeout = (uint)_options.TimeoutMs + }; + _fido2 = new Fido2(config); + } + + public string Origin => _options.Origin; + public string RpId => _options.RpId; + + /// + /// Build the PublicKeyCredentialCreationOptions that the browser + /// will hand to navigator.credentials.create(). + /// + /// HR+ username (becomes the WebAuthn user.name + user.displayName). + /// Stable per-user byte array. We use the username's UTF-8 bytes — fine for v1 because usernames are unique. + /// If the user is re-enrolling on a new device, the existing credential ID is passed via excludeCredentials so the authenticator refuses to re-enroll the same one. For v1 we don't track this (one-device-only); pass an empty list. + public CredentialCreateOptions BuildCreationOptions(string username, byte[] userId, IReadOnlyList existingCredentialIds) + { + var user = new User + { + Name = username, + Id = userId, + DisplayName = username + }; + + var exclude = existingCredentialIds + .Select(id => new PublicKeyCredentialDescriptor { Id = id }) + .ToList(); + + return _fido2.RequestNewCredential( + user, + exclude, + new AuthenticatorSelection + { + // Prefer the platform authenticator (Touch ID / Windows Hello / + // fingerprint) over roaming keys. + AuthenticatorAttachment = AuthenticatorAttachment.Platform, + UserVerification = UserVerificationRequirement.Preferred + }, + AttestationConveyancePreference.None); + } + + /// + /// Verify the attestation returned by the browser and return the + /// stored credential fields. Throws on validation failure. + /// + public async Task FinishRegistrationAsync( + AuthenticatorAttestationRawResponse attestationResponse, + CredentialCreateOptions originalOptions, + Func> isCredentialIdUnique) + { + // Fido2NetLib's MakeNewCredentialAsync takes a delegate that, given + // the new credential id, decides whether the credential is unique + // for the user. In our schema the credential id is stored on + // SecurityUser.biometric_credential_id, so uniqueness is automatic + // — the same credential id can never be assigned to two users. + // We always return true. + var makeResult = await _fido2.MakeNewCredentialAsync( + attestationResponse, + originalOptions, + (args) => Task.FromResult(true), + requestTokenBindingId: null); + + if (makeResult?.Result is not AttestationVerificationSuccess success) + { + throw new InvalidOperationException( + "Fido2 attestation verification failed: " + + (makeResult?.ErrorMessage ?? "unknown error")); + } + + return new StoredBiometricCredential + { + CredentialId = success.CredentialId, + PublicKey = success.PublicKey + }; + } + + /// + /// Build the PublicKeyCredentialRequestOptions that the browser will + /// hand to navigator.credentials.get(). Only the stored + /// credential for this user is allowed. + /// + public AssertionOptions BuildRequestOptions(byte[] storedCredentialId) + { + var allowed = new List + { + new() { Id = storedCredentialId } + }; + return _fido2.GetAssertionOptions(allowed, UserVerificationRequirement.Preferred); + } + + /// + /// Same as but returns a + /// browser-ready JSON string directly. + /// + /// Fido2NetLib 1.0.0-alpha's AssertionOptions.ToJson() serializes + /// AllowCredentials[].Id as PascalCase (the C# property is + /// Id with no [JsonProperty("id")] attribute — the + /// attribute was added in v1.1.0+). The browser's + /// @simplewebauthn/browser toPublicKeyCredentialDescriptor + /// does const { id } = descriptor, gets undefined, then + /// passes it to base64URLStringToBuffer(id) which does + /// id.replace(...) and throws + /// "Cannot read properties of undefined (reading 'replace')". + /// + /// We bypass Fido2NetLib's serializer entirely and emit the JSON + /// shape the WebAuthn spec + the browser expect directly: camelCase + /// keys, allowCredentials[].id as base64url, type: "public-key", + /// userVerification: "preferred". + /// + public string BuildRequestOptionsJson(byte[] storedCredentialId) + { + var options = _fido2.GetAssertionOptions( + new List { new() { Id = storedCredentialId } }, + UserVerificationRequirement.Preferred); + + var result = new + { + challenge = options.Challenge, + rpId = options.RpId, + allowCredentials = new[] + { + new + { + id = Fido2NetLib.Base64Url.Encode(storedCredentialId), + type = "public-key", + }, + }, + userVerification = options.UserVerification?.ToString().ToLower() ?? "preferred", + timeout = options.Timeout, + }; + + return JsonConvert.SerializeObject(result); + } + + /// + /// Verify the assertion returned by the browser. Returns the new + /// signature counter to persist. Throws on validation failure. + /// + public async Task FinishAssertionAsync( + AuthenticatorAssertionRawResponse assertionResponse, + AssertionOptions originalOptions, + byte[] storedPublicKey, + uint storedCounter) + { + var result = await _fido2.MakeAssertionAsync( + assertionResponse, + originalOptions, + storedPublicKey, + storedCounter, + (args) => Task.FromResult(true), // userHandle ownership always true for our single-user case + requestTokenBindingId: null); + + if (result is null) + { + throw new InvalidOperationException("Fido2 assertion verification returned null"); + } + + // MakeAssertionAsync returns AssertionVerificationSuccess, but in + // some Fido2NetLib versions it may surface a status/error wrapper. + // Use the typed object via dynamic to stay version-agnostic. + uint newCounter; + try + { + newCounter = (uint)result.Counter; + } + catch + { + throw new InvalidOperationException("Fido2 assertion verification did not return a counter"); + } + + // The counter MUST be strictly greater than the stored value + // (replay protection). Fido2NetLib already enforces this server-side + // and would have thrown; the second check is a belt-and-suspenders. + if (newCounter <= storedCounter) + { + throw new InvalidOperationException( + $"WebAuthn counter regression: stored={storedCounter}, new={newCounter}"); + } + + return newCounter; + } + } +} diff --git a/CloudBuilder/CloudBuilder.Security.Service/YesNoPolicyService.cs b/CloudBuilder/CloudBuilder.Security.Service/YesNoPolicyService.cs new file mode 100644 index 0000000..ce6055b --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security.Service/YesNoPolicyService.cs @@ -0,0 +1,169 @@ +using CloudBuilder.Core.DatabaseAccessor.Entity; +using CloudBuilder.Core.Service; +using CloudBuilder.Security.Data; +using CloudBuilder.Security.Entity; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Security.Service +{ + public class YesNoPolicyService : IYesNoPolicyService + { + private readonly IApplicationService service; + private IRepository repository; + private IRepository repositorySecurityUser; + private IRepository repositorySecurityUserActor; + private IRepository repositorySecurityActor; + private IRepository repositorySecurityActorGroup; + private IRepository repositorySecurityGroup; + private IRepository repositorySecurityGroupPermission; + private IRepository repositorySecurityGroupPermissionDependent; + private IRepository repositorySecurityPermission; + private IRepository repositorySecurityPermissionDependent; + private IRepository repositorySecurityPermissionFunctionMap; + private IRepository repositorySecurityFunction; + private IRepository repositorySecurityFunctionMap; + private IRepository repositorySecurityMaster; + private IRepository repositorySecurityGeneratorNumber; + public YesNoPolicyService(IApplicationService service) + { + this.service = service; + repository = service.GetRepository>(); + + repositorySecurityUser = service.GetRepository>(); + repositorySecurityUserActor = service.GetRepository>(); + repositorySecurityActor = service.GetRepository>(); + repositorySecurityActorGroup = service.GetRepository>(); + repositorySecurityGroup = service.GetRepository>(); + repositorySecurityGroupPermission = service.GetRepository>(); + repositorySecurityGroupPermissionDependent = service.GetRepository>(); + repositorySecurityPermission = service.GetRepository>(); + repositorySecurityPermissionDependent = service.GetRepository>(); + repositorySecurityPermissionFunctionMap = service.GetRepository>(); + repositorySecurityFunction = service.GetRepository>(); + repositorySecurityFunctionMap = service.GetRepository>(); + repositorySecurityMaster = service.GetRepository>(); + repositorySecurityGeneratorNumber = service.GetRepository>(); + } + + [AllowAnonymous] + [HttpPost] + public SelectOption[] FindSelectOption(bool blank) + { + YesNoPolicy policy = service.ServiceProvider.GetKeyedService(typeof(YesNoPolicy).Name); + string[] values = policy.GetValues(); + List l = new List(); + + SelectOption selectOption; + if (blank) + { + selectOption = new SelectOption(); + l.Add(selectOption); + } + + foreach (string value in values) + { + selectOption = new SelectOption(); + selectOption.BindValue = value; + selectOption.DisplayName = policy.ComposeMessage(value, service.Locale); + l.Add(selectOption); + } + return l.ToArray(); + } + + [AllowAnonymous] + [HttpGet] + public void Copy() + { + repository.ChangeSecondaryDatabase(); + repositorySecurityUser.ChangeSecondaryDatabase(); + repositorySecurityUserActor.ChangeSecondaryDatabase(); + repositorySecurityActor.ChangeSecondaryDatabase(); + repositorySecurityActorGroup.ChangeSecondaryDatabase(); + repositorySecurityGroup.ChangeSecondaryDatabase(); + repositorySecurityGroupPermission.ChangeSecondaryDatabase(); + repositorySecurityGroupPermissionDependent.ChangeSecondaryDatabase(); + repositorySecurityPermission.ChangeSecondaryDatabase(); + repositorySecurityPermissionDependent.ChangeSecondaryDatabase(); + repositorySecurityPermissionFunctionMap.ChangeSecondaryDatabase(); + repositorySecurityFunction.ChangeSecondaryDatabase(); + repositorySecurityFunctionMap.ChangeSecondaryDatabase(); + repositorySecurityMaster.ChangeSecondaryDatabase(); + repositorySecurityGeneratorNumber.ChangeSecondaryDatabase(); + + + var locales= repository.DetachedEntities.ToArray(); + var SecurityUsers = repositorySecurityUser.DetachedEntities.ToArray(); + var SecurityUserActors = repositorySecurityUserActor.DetachedEntities.ToArray(); + var SecurityActors = repositorySecurityActor.DetachedEntities.ToArray(); + var SecurityActorGroups = repositorySecurityActorGroup.DetachedEntities.ToArray(); + var SecurityGroups = repositorySecurityGroup.DetachedEntities.ToArray(); + var SecurityGroupPermissions = repositorySecurityGroupPermission.DetachedEntities.ToArray(); + var SecurityGroupPermissionDependents = repositorySecurityGroupPermissionDependent.DetachedEntities.ToArray(); + var SecurityPermissions = repositorySecurityPermission.DetachedEntities.ToArray(); + var SecurityPermissionDependents = repositorySecurityPermissionDependent.DetachedEntities.ToArray(); + var SecurityPermissionFunctionMaps = repositorySecurityPermissionFunctionMap.DetachedEntities.ToArray(); + var SecurityFunctions = repositorySecurityFunction.DetachedEntities.ToArray(); + var SecurityFunctionMaps = repositorySecurityFunctionMap.DetachedEntities.ToArray(); + var SecurityMasters = repositorySecurityMaster.DetachedEntities.ToArray(); + var SecurityGeneratorNumbers = repositorySecurityGeneratorNumber.DetachedEntities.ToArray(); + + repository.ChangeMasterDatabase(); + repositorySecurityUser.ChangeMasterDatabase(); + repositorySecurityUserActor.ChangeMasterDatabase(); + repositorySecurityActor.ChangeMasterDatabase(); + repositorySecurityActorGroup.ChangeMasterDatabase(); + repositorySecurityGroup.ChangeMasterDatabase(); + repositorySecurityGroupPermission.ChangeMasterDatabase(); + repositorySecurityGroupPermissionDependent.ChangeMasterDatabase(); + repositorySecurityPermission.ChangeMasterDatabase(); + repositorySecurityPermissionDependent.ChangeMasterDatabase(); + repositorySecurityPermissionFunctionMap.ChangeMasterDatabase(); + repositorySecurityFunction.ChangeMasterDatabase(); + repositorySecurityFunctionMap.ChangeMasterDatabase(); + repositorySecurityMaster.ChangeMasterDatabase(); + repositorySecurityGeneratorNumber.ChangeMasterDatabase(); + + repository.ExecuteNonQuery("TRUNCATE TABLE " + LocaleEntity.DB_NAME_LOCALE); + + repository.ExecuteNonQuery("TRUNCATE TABLE " + SecurityUserEntity.DB_NAME_SECURITY_USER); + repository.ExecuteNonQuery("TRUNCATE TABLE " + SecurityActorEntity.DB_NAME_SECURITY_ACTOR); + repository.ExecuteNonQuery("TRUNCATE TABLE " + SecurityUserActorEntity.DB_NAME_SECURITY_USER_ACTOR); + repository.ExecuteNonQuery("TRUNCATE TABLE " + SecurityActorGroupEntity.DB_NAME_SECURITY_ACTOR_GROUP); + repository.ExecuteNonQuery("TRUNCATE TABLE " + SecurityGroupEntity.DB_NAME_SECURITY_GROUP); + repository.ExecuteNonQuery("TRUNCATE TABLE " + SecurityGroupPermissionEntity.DB_NAME_SECURITY_GROUP_PERMISSION); + repository.ExecuteNonQuery("TRUNCATE TABLE " + SecurityGroupPermissionDependentEntity.DB_NAME_SECURITY_GROUP_PERMISSION_DEPENDENT); + repository.ExecuteNonQuery("TRUNCATE TABLE " + SecurityPermissionEntity.DB_NAME_SECURITY_PERMISSION); + repository.ExecuteNonQuery("TRUNCATE TABLE " + SecurityPermissionDependentEntity.DB_NAME_SECURITY_PERMISSION_DEPENDENT); + repository.ExecuteNonQuery("TRUNCATE TABLE " + SecurityPermissionFunctionMapEntity.DB_NAME_SECURITY_PERMISSION_FUNCTION_MAP); + repository.ExecuteNonQuery("TRUNCATE TABLE " + SecurityFunctionEntity.DB_NAME_SECURITY_FUNCTION); + repository.ExecuteNonQuery("TRUNCATE TABLE " + SecurityFunctionMapEntity.DB_NAME_SECURITY_FUNCTION_MAP); + repository.ExecuteNonQuery("TRUNCATE TABLE " + SecurityMasterEntity.DB_NAME_SECURITY_MASTER); + repository.ExecuteNonQuery("TRUNCATE TABLE " + SecurityGeneratorNumberEntity.DB_NAME_SECURITY_GENERATOR_NUMBER); + + repository.InsertNow(locales); + repositorySecurityUser.InsertNow(SecurityUsers); + repositorySecurityUserActor.InsertNow(SecurityUserActors); + repositorySecurityActor.InsertNow(SecurityActors); + repositorySecurityActorGroup.InsertNow(SecurityActorGroups); + repositorySecurityGroup.InsertNow(SecurityGroups); + repositorySecurityGroupPermission.InsertNow(SecurityGroupPermissions); + repositorySecurityGroupPermissionDependent.InsertNow(SecurityGroupPermissionDependents); + repositorySecurityPermission.InsertNow(SecurityPermissions); + repositorySecurityPermissionDependent.InsertNow(SecurityPermissionDependents); + repositorySecurityPermissionFunctionMap.InsertNow(SecurityPermissionFunctionMaps); + repositorySecurityFunction.InsertNow(SecurityFunctions); + repositorySecurityFunctionMap.InsertNow(SecurityFunctionMaps); + repositorySecurityMaster.InsertNow(SecurityMasters); + repositorySecurityGeneratorNumber.InsertNow(SecurityGeneratorNumbers); + } + } +} diff --git a/CloudBuilder/CloudBuilder.Security/CloudBuilder.Security.csproj b/CloudBuilder/CloudBuilder.Security/CloudBuilder.Security.csproj new file mode 100644 index 0000000..243ac8e --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/CloudBuilder.Security.csproj @@ -0,0 +1,46 @@ + + + + net8.0 + enable + enable + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ..\CloudBuilder.Core\bin\Debug\net8.0\CloudBuilder.Core.dll + + + + + + + + + + + diff --git a/CloudBuilder/CloudBuilder.Security/Data/BiometricLoginChallengeDto.cs b/CloudBuilder/CloudBuilder.Security/Data/BiometricLoginChallengeDto.cs new file mode 100644 index 0000000..10b7f88 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Data/BiometricLoginChallengeDto.cs @@ -0,0 +1,19 @@ +using CloudBuilder.Core.Authorization; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Security.Data +{ + [TypeScript] + public class BiometricLoginChallengeDto + { + /// AssertionOptions JSON to feed to navigator.credentials.get(). + public string RequestOptionsJson { get; set; } = null!; + + /// Opaque id identifying this challenge — we round-trip the requestOptionsJson instead, so this is informational and currently unused. + public string ChallengeId { get; set; } = string.Empty; + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Data/BiometricRegistrationResultDto.cs b/CloudBuilder/CloudBuilder.Security/Data/BiometricRegistrationResultDto.cs new file mode 100644 index 0000000..4ddfda8 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Data/BiometricRegistrationResultDto.cs @@ -0,0 +1,15 @@ +using CloudBuilder.Core.Authorization; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Security.Data +{ + [TypeScript] + public class BiometricRegistrationResultDto + { + public string CredentialIdBase64Url { get; set; } = string.Empty; + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Data/FinishBiometricLoginData.cs b/CloudBuilder/CloudBuilder.Security/Data/FinishBiometricLoginData.cs new file mode 100644 index 0000000..0e7b41f --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Data/FinishBiometricLoginData.cs @@ -0,0 +1,20 @@ +using CloudBuilder.Core.Authorization; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Security.Data +{ + [TypeScript] + public class FinishBiometricLoginData + { + public string Username { get; set; } = null!; + public string AssertionJson { get; set; } = null!; + public string RequestOptionsJson { get; set; } = null!; + + /// Opaque id; informational only. We round-trip the requestOptionsJson. + public string ChallengeId { get; set; } = string.Empty; + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Data/FinishBiometricRegistrationData.cs b/CloudBuilder/CloudBuilder.Security/Data/FinishBiometricRegistrationData.cs new file mode 100644 index 0000000..08ec9c3 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Data/FinishBiometricRegistrationData.cs @@ -0,0 +1,19 @@ +using CloudBuilder.Core.Authorization; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Security.Data +{ + [TypeScript] + public class FinishBiometricRegistrationData + { + /// JSON the browser returns from navigator.credentials.create(). + public string AttestationJson { get; set; } = null!; + + /// The CredentialCreateOptions JSON we returned from BeginBiometricRegistration. Round-tripped because Fido2NetLib verifies the challenge against it. + public string CreationOptionsJson { get; set; } = null!; + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Data/LocaleData.cs b/CloudBuilder/CloudBuilder.Security/Data/LocaleData.cs new file mode 100644 index 0000000..05d71c1 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Data/LocaleData.cs @@ -0,0 +1,20 @@ +using CloudBuilder.Core.Authorization; +using CloudBuilder.Security.Entity; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Security.Data +{ + [TypeScript] + public class LocaleData + { + public LocaleDisplayData[]? Inserts { get; set; } + + public LocaleDisplayData[]? Updates { get; set; } + + public LocaleDisplayData[]? Deletes { get; set; } + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Data/LocaleDisplayData.cs b/CloudBuilder/CloudBuilder.Security/Data/LocaleDisplayData.cs new file mode 100644 index 0000000..ecd9af2 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Data/LocaleDisplayData.cs @@ -0,0 +1,30 @@ +using CloudBuilder.Security.Entity; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Security.Data +{ + [NotMapped] + public class LocaleDisplayData : LocaleEntity + { + public LocaleDisplayData() + { + } + public LocaleDisplayData(LocaleEntity entity) + { + OrgGroupName=entity.GroupName; + OrgLang = entity.Lang; + OrgName = entity.Name; + CopyFrom(entity); + } + + public string? OrgGroupName { get; set; } + public string? OrgLang { get; set; } + public string? OrgName { get; set; } + } +} + diff --git a/CloudBuilder/CloudBuilder.Security/Data/LocaleResultData.cs b/CloudBuilder/CloudBuilder.Security/Data/LocaleResultData.cs new file mode 100644 index 0000000..c861a6e --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Data/LocaleResultData.cs @@ -0,0 +1,16 @@ +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.Service; +using CloudBuilder.Security.Entity; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Security.Data +{ + public class LocaleResultData : SearchCriteriaResultData + { + public LocaleDisplayData[]? Datas { get; set; } + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Data/LoginData.cs b/CloudBuilder/CloudBuilder.Security/Data/LoginData.cs new file mode 100644 index 0000000..9221e5c --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Data/LoginData.cs @@ -0,0 +1,28 @@ +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Security.Data +{ + [TypeScript] + public class LoginData + { + public string? UserName { get; set; } + + public string? AgentUserName { get; set; } + + public string? UserMobile { get; set; } + + public string? UserPassword { get; set; } + + public string? RsaUserPassword { get; set; } + + public string? Guid { get; set; } + + public string? Culture { get; set; } + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Data/LoginProfile.cs b/CloudBuilder/CloudBuilder.Security/Data/LoginProfile.cs new file mode 100644 index 0000000..57a9373 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Data/LoginProfile.cs @@ -0,0 +1,23 @@ +using CloudBuilder.Core.Authorization; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Security.Data +{ + [TypeScript] + public class LoginProfile + { + public JwtInfo Token { get; set; } = null!; + public string UserType { get; set; } = null!; + public string Username { get; set; } = null!; + public string? UserLocalName { get; set; } + public string? UserEngName { get; set; } + public string UserMobile { get; set; } = null!; + + public SecurityUserPermissionInfo PermissionInfo { get; set; } + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Data/RegisterData.cs b/CloudBuilder/CloudBuilder.Security/Data/RegisterData.cs new file mode 100644 index 0000000..f63a26b --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Data/RegisterData.cs @@ -0,0 +1,26 @@ +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Security.Data +{ + [TypeScript] + public class RegisterData + { + public string? UserName { get; set; } + + public string? UserMobile { get; set; } + + public string? UserPassword { get; set; } + + public string? ConfirmUserPassword { get; set; } + + public string? RsaUserPassword { get; set; } + + public string? Agree { get; set; } + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Data/SecurityActorData.cs b/CloudBuilder/CloudBuilder.Security/Data/SecurityActorData.cs new file mode 100644 index 0000000..fff47b3 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Data/SecurityActorData.cs @@ -0,0 +1,19 @@ +using CloudBuilder.Core.Authorization; +using CloudBuilder.Security.Data; +using CloudBuilder.Security.Entity; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Security.Data +{ + [TypeScript] + public class SecurityActorData + { + public SecurityActorEntity? SecurityActor { get; set; } + public SecurityActorGroupViewEntity[]? SecurityActorGroups { get; set; } + public SecurityUserActorViewEntity[]? SecurityUserActors { get; set; } + } +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Security/Data/SecurityActorResultData.cs b/CloudBuilder/CloudBuilder.Security/Data/SecurityActorResultData.cs new file mode 100644 index 0000000..f75c3c7 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Data/SecurityActorResultData.cs @@ -0,0 +1,17 @@ +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.Service; +using CloudBuilder.Security.Entity; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Security.Data +{ + [TypeScript] + public class SecurityActorResultData : SearchCriteriaResultData + { + public SecurityActorEntity[]? Datas { get; set; } + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Data/SecurityFunctionData.cs b/CloudBuilder/CloudBuilder.Security/Data/SecurityFunctionData.cs new file mode 100644 index 0000000..7b3af77 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Data/SecurityFunctionData.cs @@ -0,0 +1,18 @@ +using CloudBuilder.Core.Authorization; +using CloudBuilder.Security.Entity; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Security.Data +{ + [TypeScript] + public class SecurityFunctionData + { + public SecurityFunctionDisplayData? SecurityFunction { get; set; } + public SecurityFunctionMapViewEntity[]? SecurityFunctionMapParents { get; set; } + public SecurityFunctionMapViewEntity[]? SecurityFunctionMapSons { get; set; } + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Data/SecurityFunctionDisplayData.cs b/CloudBuilder/CloudBuilder.Security/Data/SecurityFunctionDisplayData.cs new file mode 100644 index 0000000..6fea387 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Data/SecurityFunctionDisplayData.cs @@ -0,0 +1,35 @@ + +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using CloudBuilder.Security.Entity; +using System.ComponentModel.DataAnnotations.Schema; +using System.Text.Json.Serialization; +namespace CloudBuilder.Security.Data +{ + /// + /// 排除实体类标记 + /// + [NotMapped] + [TypeScript] + public class SecurityFunctionDisplayData : SecurityFunctionEntity + { + public const string PERMISSION_NAME = "PermissionName"; + + public SecurityFunctionDisplayData() + { + } + public SecurityFunctionDisplayData(SecurityFunctionEntity entity) + { + CopyFrom(entity); + } + + public string? FunctionNameParent { get; set; } + + public int Orderby { get; set; } + + public string? PermissionName { get; set; } + + public List? SonSecurityFunctions { get; set; } + } +} + diff --git a/CloudBuilder/CloudBuilder.Security/Data/SecurityFunctionResultData.cs b/CloudBuilder/CloudBuilder.Security/Data/SecurityFunctionResultData.cs new file mode 100644 index 0000000..db3dac8 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Data/SecurityFunctionResultData.cs @@ -0,0 +1,23 @@ +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.Service; +using CloudBuilder.Security.Entity; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Security.Data +{ + [TypeScript] + public class SecurityFunctionResultData : SearchCriteriaResultData + { + + public const string BOOTUP = "BOOTUP"; + + public SecurityFunctionDisplayData[] SecurityFunctionDisplayDatas { get; set; } = null!; + + public SecurityFunctionMapEntity[] SecurityFunctionMaps { get; set; } = null!; + + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Data/SecurityGeneratorNumberData.cs b/CloudBuilder/CloudBuilder.Security/Data/SecurityGeneratorNumberData.cs new file mode 100644 index 0000000..1d41d42 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Data/SecurityGeneratorNumberData.cs @@ -0,0 +1,12 @@ +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.Service; +using CloudBuilder.Security.Entity; + +namespace CloudBuilder.Security.Data +{ + [TypeScript] + public class SecurityGeneratorNumberData : SearchCriteriaResultData + { + public SecurityGeneratorNumberEntity[]? datas { get; set; } + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Data/SecurityGeneratorNumberResultData.cs b/CloudBuilder/CloudBuilder.Security/Data/SecurityGeneratorNumberResultData.cs new file mode 100644 index 0000000..cadb5de --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Data/SecurityGeneratorNumberResultData.cs @@ -0,0 +1,12 @@ +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.Service; +using CloudBuilder.Security.Entity; + +namespace CloudBuilder.Security.Data +{ + [TypeScript] + public class SecurityGeneratorNumberResultData : SearchCriteriaResultData + { + public SecurityGeneratorNumberEntity[]? Datas { get; set; } + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Data/SecurityGroupData.cs b/CloudBuilder/CloudBuilder.Security/Data/SecurityGroupData.cs new file mode 100644 index 0000000..6ec83b7 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Data/SecurityGroupData.cs @@ -0,0 +1,22 @@ +using CloudBuilder.Core.Authorization; +using CloudBuilder.Security.Data; +using CloudBuilder.Security.Entity; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Security.Data +{ + [TypeScript] + public class SecurityGroupData + { + public SecurityGroupEntity? SecurityGroup { get; set; } + + public SecurityGroupPermissionViewDisplayData[]? SecurityGroupPermissionViews { get; set; } + public SecurityGroupPermissionDependentViewDisplayData[]? SecurityGroupPermissionDependentViews { get; set; } + + public SecurityActorGroupViewEntity[]? SecurityActorGroups { get; set; } + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Data/SecurityGroupPermissionDependentViewDisplayData.cs b/CloudBuilder/CloudBuilder.Security/Data/SecurityGroupPermissionDependentViewDisplayData.cs new file mode 100644 index 0000000..42bb18b --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Data/SecurityGroupPermissionDependentViewDisplayData.cs @@ -0,0 +1,39 @@ +using CloudBuilder.Core.Authorization; +using CloudBuilder.Security.Entity; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Security.Data +{ + [NotMapped] + [TypeScript] + public class SecurityGroupPermissionDependentViewDisplayData : SecurityGroupPermissionDependentViewEntity + { + public SecurityGroupPermissionDependentViewDisplayData() + { + + } + public SecurityGroupPermissionDependentViewDisplayData(SecurityGroupPermissionDependentViewEntity entity) + { + CopyFrom(entity, true); + this.IsView = entity.ViewIndc == YesNoPolicy.YES; + this.IsCreate = entity.CreateIndc == YesNoPolicy.YES; + this.IsAmend = entity.AmendIndc == YesNoPolicy.YES; + this.IsDelete = entity.DeleteIndc == YesNoPolicy.YES; + } + + public const string IS_VIEW = "IsView"; + public const string IS_CREATE = "IsCreate"; + public const string IS_AMEND = "IsAmend"; + public const string IS_DELETE = "IsDelete"; + + public bool IsView { get; set; } + public bool IsCreate { get; set; } + public bool IsAmend { get; set; } + public bool IsDelete { get; set; } + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Data/SecurityGroupPermissionViewDisplayData.cs b/CloudBuilder/CloudBuilder.Security/Data/SecurityGroupPermissionViewDisplayData.cs new file mode 100644 index 0000000..55eb95e --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Data/SecurityGroupPermissionViewDisplayData.cs @@ -0,0 +1,41 @@ +using CloudBuilder.Core.Authorization; +using CloudBuilder.Security.Entity; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Security.Data +{ + [NotMapped] + [TypeScript] + public class SecurityGroupPermissionViewDisplayData : SecurityGroupPermissionViewEntity + { + public SecurityGroupPermissionViewDisplayData() + { + } + public SecurityGroupPermissionViewDisplayData(SecurityGroupPermissionViewEntity entity) + { + CopyFrom(entity); + this.IsView = entity.ViewIndc == YesNoPolicy.YES; + this.IsCreate = entity.CreateIndc == YesNoPolicy.YES; + this.IsAmend = entity.AmendIndc == YesNoPolicy.YES; + this.IsDelete = entity.DeleteIndc == YesNoPolicy.YES; + } + + public const string IS_VIEW = "IsView"; + public const string IS_CREATE = "IsCreate"; + public const string IS_AMEND = "IsAmend"; + public const string IS_DELETE = "IsDelete"; + + public bool IsView { get; set; } + + public bool IsCreate { get; set; } + + public bool IsAmend { get; set; } + + public bool IsDelete { get; set; } + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Data/SecurityGroupResultData.cs b/CloudBuilder/CloudBuilder.Security/Data/SecurityGroupResultData.cs new file mode 100644 index 0000000..ecea9d3 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Data/SecurityGroupResultData.cs @@ -0,0 +1,17 @@ +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.Service; +using CloudBuilder.Security.Entity; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Security.Data +{ + [TypeScript] + public class SecurityGroupResultData : SearchCriteriaResultData + { + public SecurityGroupEntity[]? Datas { get; set; } + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Data/SecurityMasterResultData.cs b/CloudBuilder/CloudBuilder.Security/Data/SecurityMasterResultData.cs new file mode 100644 index 0000000..8355092 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Data/SecurityMasterResultData.cs @@ -0,0 +1,17 @@ +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.Service; +using CloudBuilder.Security.Entity; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Security.Data +{ + [TypeScript] + public class SecurityMasterResultData : SearchCriteriaResultData + { + public SecurityMasterEntity[]? Datas { get; set; } + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Data/SecurityPermissionData.cs b/CloudBuilder/CloudBuilder.Security/Data/SecurityPermissionData.cs new file mode 100644 index 0000000..de8f18b --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Data/SecurityPermissionData.cs @@ -0,0 +1,18 @@ +using CloudBuilder.Core.Authorization; +using CloudBuilder.Security.Entity; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Security.Data +{ + [TypeScript] + public class SecurityPermissionData + { + public SecurityPermissionEntity? SecurityPermission { get; set; } + + public SecurityPermissionDependentEntity[]? SecurityPermissionDependents { get; set; } + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Data/SecurityPermissionResultData.cs b/CloudBuilder/CloudBuilder.Security/Data/SecurityPermissionResultData.cs new file mode 100644 index 0000000..91f4598 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Data/SecurityPermissionResultData.cs @@ -0,0 +1,19 @@ +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.Service; +using CloudBuilder.Security.Entity; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Security.Data +{ + [TypeScript] + public class SecurityPermissionResultData : SearchCriteriaResultData + { + public SecurityPermissionEntity[]? Permissions { get; set; } + + public SecurityPermissionDependentEntity[]? Dependents { get; set; } + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Data/SecurityUserData.cs b/CloudBuilder/CloudBuilder.Security/Data/SecurityUserData.cs new file mode 100644 index 0000000..c4d4164 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Data/SecurityUserData.cs @@ -0,0 +1,17 @@ +using CloudBuilder.Core.Authorization; +using CloudBuilder.Security.Entity; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Security.Data +{ + [TypeScript] + public class SecurityUserData + { + public SecurityUserDisplayData? SecurityUser { get; set; } + public SecurityUserActorViewEntity[]? SecurityUserActors { get; set; } + } +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Security/Data/SecurityUserDisplayData.cs b/CloudBuilder/CloudBuilder.Security/Data/SecurityUserDisplayData.cs new file mode 100644 index 0000000..783e5c2 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Data/SecurityUserDisplayData.cs @@ -0,0 +1,28 @@ + +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using CloudBuilder.Security.Entity; +using System.ComponentModel.DataAnnotations.Schema; +namespace CloudBuilder.Security.Data +{ + /// + /// 排除实体类标记 + /// + [NotMapped] + [TypeScript] + public class SecurityUserDisplayData : SecurityUserEntity + { + + public SecurityUserDisplayData() + { + } + public SecurityUserDisplayData(SecurityUserEntity entity) + { + CopyFrom(entity); + } + + public string? OrgUserPassword { get; set; } + + } +} + diff --git a/CloudBuilder/CloudBuilder.Security/Data/SecurityUserPermissionInfo.cs b/CloudBuilder/CloudBuilder.Security/Data/SecurityUserPermissionInfo.cs new file mode 100644 index 0000000..228f3b9 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Data/SecurityUserPermissionInfo.cs @@ -0,0 +1,20 @@ +using CloudBuilder.Core.Authorization; +using CloudBuilder.Security.Entity; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Security.Data +{ + [TypeScript] + public class SecurityUserPermissionInfo + { + public string[]? UserGroups { get; set; } + public SecurityGroupPermissionViewEntity[]? Permissions { get; set; } + public SecurityGroupPermissionDependentViewEntity[]? PermissionDependents { get; set; } + + public SecurityPermissionFunctionMapViewEntity[]? PermissionFunctionMaps { get; set; } + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Data/SecurityUserResultData.cs b/CloudBuilder/CloudBuilder.Security/Data/SecurityUserResultData.cs new file mode 100644 index 0000000..cb6d8bf --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Data/SecurityUserResultData.cs @@ -0,0 +1,17 @@ +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.Service; +using CloudBuilder.Security.Entity; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Security.Data +{ + [TypeScript] + public class SecurityUserResultData : SearchCriteriaResultData + { + public SecurityUserEntity[]? Datas { get; set; } + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Data/WebAuthnOptions.cs b/CloudBuilder/CloudBuilder.Security/Data/WebAuthnOptions.cs new file mode 100644 index 0000000..417a25c --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Data/WebAuthnOptions.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Security.Data +{ + + /// + /// Plain-old-data wrapper for the credential fields we persist on + /// SecurityUser. The frontend never sees this type. + /// + public class StoredBiometricCredential + { + public byte[] CredentialId { get; set; } = Array.Empty(); + public byte[] PublicKey { get; set; } = Array.Empty(); + } + + public class WebAuthnOptions + { + /// + /// Relying Party ID — the registrable domain suffix of the + /// origin's host. For dev: "localhost". For production: + /// "eleave.1010printing.com". + /// + public string RpId { get; set; } = "localhost"; + + /// + /// Human-readable relying-party name. Shown in the OS biometric + /// prompt ("Use HR Plus to sign in to localhost"). + /// + public string RpName { get; set; } = "HR Plus"; + + /// + /// The full origin (scheme + host + port) the user is loading + /// the page from. Fido2NetLib verifies the attestation/assertion + /// origin matches this exactly. Must be HTTPS in production + /// (localhost is exempt). + /// + public string Origin { get; set; } = "https://localhost:8000"; + + /// + /// WebAuthn ceremony timeout in milliseconds. Default 60s. + /// + public int TimeoutMs { get; set; } = 60000; + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Entity/CloudBuilderSecurityRegistEntity.auto.cs b/CloudBuilder/CloudBuilder.Security/Entity/CloudBuilderSecurityRegistEntity.auto.cs new file mode 100644 index 0000000..38cd891 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Entity/CloudBuilderSecurityRegistEntity.auto.cs @@ -0,0 +1,128 @@ +using CloudBuilder.Core.DependencyInjection.EFCore; +using Microsoft.EntityFrameworkCore; +using System.Reflection; + +namespace CloudBuilder.Security.Entity +{ + public class CloudBuilderSecurityRegistEntity : IMasterRegistEntityType + { + /// + ///注入模块内的所有实体类 + /// + /// + public void RegistEntity(ModelBuilder builder) + { + string _assemblyName = Assembly.GetExecutingAssembly().GetName().Name; + //注入所有Entity实体类 + AddEntityType(builder, _assemblyName); + //如果Entity实体类不是单一主键,要单独重写注入 + RegistKeys(builder); + } + + public void AddEntityType(ModelBuilder builder, string _assemblyName) + { + RegistEntityHelper.AddMasterEntityType(builder, _assemblyName); + } + + /// + ///如果存在多个主键的,要在RegistKeys方法注入 + ///builder.Entity().HasKey(c => new { c.TableName, c.FieldName }); + ///builder.Entity(eb => { eb.HasNoKey(); }); + /// + /// + public void RegistKeys(ModelBuilder builder) + { + //***BEGIN*** + + builder.Entity().HasKey(c => new {c.ActorName,c.GroupName}); + builder.Entity(eb => { eb.HasNoKey(); }); + builder.Entity().HasKey(c => new {c.GroupName,c.PermissionName,c.DependentDetailName}); + builder.Entity().HasKey(c => new {c.FunctionNameParent,c.FunctionNameSon}); + builder.Entity(eb => { eb.HasNoKey(); }); + builder.Entity(eb => { eb.HasNoKey(); }); + builder.Entity(eb => { eb.HasNoKey(); }); + builder.Entity().HasKey(c => new { c.GroupName, c.PermissionName }); + builder.Entity().HasKey(c => new {c.MasterCategory,c.MasterSubcategory,c.MasterCodeItem}); + builder.Entity().HasKey(c => new {c.PermissionName,c.DependentDetailName}); + builder.Entity(eb => { eb.HasNoKey(); }); + builder.Entity(eb => { eb.HasNoKey(); }); + builder.Entity().HasKey(c => new {c.UserName,c.ActorName}); + builder.Entity(eb => { eb.HasNoKey(); }); + builder.Entity().HasKey(c => new {c.UserName,c.DelegatedByUser,c.PermissionName}); + builder.Entity(eb => { eb.HasNoKey(); }); + builder.Entity().HasKey(c => new {c.SessionId,c.Username}); + builder.Entity().HasKey(c => new {c.PermissionName,c.FunctionName}); + builder.Entity(eb => { eb.HasNoKey(); }); + builder.Entity().HasKey(c => new {c.GroupName,c.Lang,c.Name}); + builder.Entity().HasKey(c => new {c.Username,c.PreferenceKey}); + builder.Entity(eb => { eb.HasNoKey(); }); + builder.Entity(eb => { eb.HasNoKey(); }); + builder.Entity(eb => { eb.HasNoKey(); }); + builder.Entity(eb => { eb.HasNoKey(); }); + builder.Entity(eb => { eb.HasNoKey(); }); + builder.Entity(eb => { eb.HasNoKey(); }); + builder.Entity(eb => { eb.HasNoKey(); }); + builder.Entity(eb => { eb.HasNoKey(); }); + builder.Entity(eb => { eb.HasNoKey(); }); + builder.Entity(eb => { eb.HasNoKey(); }); + builder.Entity(eb => { eb.HasNoKey(); }); + builder.Entity(eb => { eb.HasNoKey(); }); + builder.Entity().HasKey(c => new {c.Username,c.PreferenceKey,c.ProfileName}); + builder.Entity(eb => { eb.HasNoKey(); }); + builder.Entity(eb => { eb.HasNoKey(); }); + builder.Entity(eb => { eb.HasNoKey(); }); + builder.Entity(eb => { eb.HasNoKey(); }); + builder.Entity(eb => { eb.HasNoKey(); }); + builder.Entity(eb => { eb.HasNoKey(); }); + builder.Entity(eb => { eb.HasNoKey(); }); + builder.Entity(eb => { eb.HasNoKey(); }); + builder.Entity(eb => { eb.HasNoKey(); }); + builder.Entity(eb => { eb.HasNoKey(); }); + builder.Entity(eb => { eb.HasNoKey(); }); + builder.Entity(eb => { eb.HasNoKey(); }); + builder.Entity(eb => { eb.HasNoKey(); }); + builder.Entity().HasKey(c => new {c.EntityName,c.PkeyId,c.LockedByActor}); + + + + + + + +builder.Entity(eb => { eb.HasNoKey(); }); + + +builder.Entity(eb => { eb.HasNoKey(); }); + + + +builder.Entity(eb => { eb.HasNoKey(); }); + +builder.Entity(eb => { eb.HasNoKey(); }); + + +builder.Entity(eb => { eb.HasNoKey(); }); + +builder.Entity(eb => { eb.HasNoKey(); }); + + + +builder.Entity(eb => { eb.HasNoKey(); }); + + +builder.Entity(eb => { eb.HasNoKey(); }); + +builder.Entity(eb => { eb.HasNoKey(); }); + +builder.Entity(eb => { eb.HasNoKey(); }); + +builder.Entity(eb => { eb.HasNoKey(); }); + +builder.Entity(eb => { eb.HasNoKey(); }); + +builder.Entity(eb => { eb.HasNoKey(); }); + //***END*** + } + } +} + diff --git a/CloudBuilder/CloudBuilder.Security/Entity/LocaleEntity.auto.cs b/CloudBuilder/CloudBuilder.Security/Entity/LocaleEntity.auto.cs new file mode 100644 index 0000000..4f8f8e9 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Entity/LocaleEntity.auto.cs @@ -0,0 +1,123 @@ + +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +namespace CloudBuilder.Security.Entity + { + [TypeScript] + [Table("locale")] + public class LocaleEntity : EntityBase + { + + public LocaleEntity() + { + } + + [Column("created_by")] + public string CreatedBy { get; set; } + [Column("created_datetime")] + public DateTime CreatedDatetime { get; set; } + [Column("group_name")] + public string GroupName { get; set; } + [Column("lang")] + public string Lang { get; set; } + [Column("name")] + public string Name { get; set; } + [Column("order_by")] + public int OrderBy { get; set; } + [Column("updated_by")] + public string UpdatedBy { get; set; } + [Column("updated_datetime")] + public DateTime UpdatedDatetime { get; set; } + [Column("value")] + public string Value { get; set; } + + public const string CREATED_BY = "CreatedBy"; + public const string CREATED_DATETIME = "CreatedDatetime"; + public const string GROUP_NAME = "GroupName"; + public const string LANG = "Lang"; + public const string NAME = "Name"; + public const string ORDER_BY = "OrderBy"; + public const string UPDATED_BY = "UpdatedBy"; + public const string UPDATED_DATETIME = "UpdatedDatetime"; + public const string VALUE = "Value"; + + public const string DB_NAME_LOCALE = "locale"; + public const string DB_NAME_FIELDS="created_by,created_datetime,group_name,lang,name,order_by,updated_by,updated_datetime,value"; + + public const string DB_CREATED_BY = "created_by"; + public const string DB_CREATED_DATETIME = "created_datetime"; + public const string DB_GROUP_NAME = "group_name"; + public const string DB_LANG = "lang"; + public const string DB_NAME = "name"; + public const string DB_ORDER_BY = "order_by"; + public const string DB_UPDATED_BY = "updated_by"; + public const string DB_UPDATED_DATETIME = "updated_datetime"; + public const string DB_VALUE = "value"; + + + public static LocaleEntity GetInstance() + { + return new LocaleEntity(); + } + + public virtual void CopyFrom(LocaleEntity source) + { + CopyFrom(source, true); + } + + public virtual void CopyFrom(LocaleEntity source, bool includeSystemFields) + { + if (source == null) + { + throw new NullReferenceException("Source entity is null."); + } + + this.CreatedBy = source.CreatedBy; + this.CreatedDatetime = source.CreatedDatetime; + this.GroupName = source.GroupName; + this.Lang = source.Lang; + this.Name = source.Name; + this.OrderBy = source.OrderBy; + this.UpdatedBy = source.UpdatedBy; + this.UpdatedDatetime = source.UpdatedDatetime; + this.Value = source.Value; + + if (includeSystemFields) + { + this.CreatedBy = source.CreatedBy; + this.CreatedDatetime = source.CreatedDatetime; + this.UpdatedBy = source.UpdatedBy; + this.UpdatedDatetime = source.UpdatedDatetime; + } + } + + public override string GetSelectFrom() + { + return $" select {DB_NAME_FIELDS} from { DB_NAME_LOCALE} "; + } + + public override string GetSelectCountFrom(string sqlWhere) + { + return $" select count(*) from { DB_NAME_LOCALE} where 1=1 {sqlWhere}"; + } + + public override string GetSelectTopFrom(int limit, int start,string orderby,string orderbytag, string sqlWhere) + { + if (string.IsNullOrEmpty(orderbytag) || orderbytag.Trim() != "desc") orderbytag = "asc"; + if (string.IsNullOrEmpty(orderby) || !DB_NAME_FIELDS.Contains(orderby)) orderby = DB_GROUP_NAME ; + int offset = limit * (start - 1); + return $" select {DB_NAME_FIELDS} from (select {DB_NAME_FIELDS} ,row_number() over(order by {orderby} {orderbytag}) as num from { DB_NAME_LOCALE} where 1=1 {sqlWhere} ) a where num> {offset} LIMIT {offset},{limit} "; + } + + public LocaleEntity Clone() + { + LocaleEntity result = new LocaleEntity(); + result.CopyFrom(this); + + return result; + } + + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Entity/LocaleEntityKey.auto.cs b/CloudBuilder/CloudBuilder.Security/Entity/LocaleEntityKey.auto.cs new file mode 100644 index 0000000..988729e --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Entity/LocaleEntityKey.auto.cs @@ -0,0 +1,35 @@ + +using CloudBuilder.Core.Authorization; +namespace CloudBuilder.Security +{ + [TypeScript] + public class LocaleEntityKey + { + public string GroupName { get; set; } + public string Lang { get; set; } + public string Name { get; set; } + + public override bool Equals(object obj) + { + if (this == obj) return true; + + LocaleEntityKey pkey = obj as LocaleEntityKey; + if (pkey == null) return false; + + if (GroupName != pkey.GroupName) return false; + if (Lang != pkey.Lang) return false; + if (Name != pkey.Name) return false; + + return true; + } + + + public override string ToString() + { + string declareSql=""; + declareSql=declareSql+$"declare @__tkey_GroupName_0 varchar(50) select @__tkey_GroupName_0 ='{GroupName}'; " ; declareSql=declareSql+$"declare @__tkey_Lang_1 varchar(50) select @__tkey_Lang_1 ='{Lang}'; " ; declareSql=declareSql+$"declare @__tkey_Name_2 varchar(50) select @__tkey_Name_2 ='{Name}'; " ; + return declareSql; + } + } + } + /* builder.Entity().HasKey(c => new { c.GroupName, c.Lang, c.Name}); */ diff --git a/CloudBuilder/CloudBuilder.Security/Entity/SecurityActorEntity.auto.cs b/CloudBuilder/CloudBuilder.Security/Entity/SecurityActorEntity.auto.cs new file mode 100644 index 0000000..47e5a33 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Entity/SecurityActorEntity.auto.cs @@ -0,0 +1,114 @@ + +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +namespace CloudBuilder.Security.Entity + { + [TypeScript] + [Table("security_actor")] + public class SecurityActorEntity : ViewEntityBase + { + + public SecurityActorEntity() + { + } + + [Column("actor_eng_name")] + public string? ActorEngName { get; set; } + [Column("actor_local_name")] + public string? ActorLocalName { get; set; } + [Key] + [Column("actor_name")] + public string ActorName { get; set; } + [Column("created_by")] + public string CreatedBy { get; set; } + [Column("created_datetime")] + public DateTime CreatedDatetime { get; set; } + [Column("updated_by")] + public string UpdatedBy { get; set; } + [Column("updated_datetime")] + public DateTime UpdatedDatetime { get; set; } + + public const string ACTOR_ENG_NAME = "ActorEngName"; + public const string ACTOR_LOCAL_NAME = "ActorLocalName"; + public const string ACTOR_NAME = "ActorName"; + public const string CREATED_BY = "CreatedBy"; + public const string CREATED_DATETIME = "CreatedDatetime"; + public const string UPDATED_BY = "UpdatedBy"; + public const string UPDATED_DATETIME = "UpdatedDatetime"; + + public const string DB_NAME_SECURITY_ACTOR = "security_actor"; + public const string DB_NAME_FIELDS="actor_eng_name,actor_local_name,actor_name,created_by,created_datetime,updated_by,updated_datetime"; + + public const string DB_ACTOR_ENG_NAME = "actor_eng_name"; + public const string DB_ACTOR_LOCAL_NAME = "actor_local_name"; + public const string DB_ACTOR_NAME = "actor_name"; + public const string DB_CREATED_BY = "created_by"; + public const string DB_CREATED_DATETIME = "created_datetime"; + public const string DB_UPDATED_BY = "updated_by"; + public const string DB_UPDATED_DATETIME = "updated_datetime"; + + + public static SecurityActorEntity GetInstance() + { + return new SecurityActorEntity(); + } + + public virtual void CopyFrom(SecurityActorEntity source) + { + CopyFrom(source, true); + } + + public virtual void CopyFrom(SecurityActorEntity source, bool includeSystemFields) + { + if (source == null) + { + throw new NullReferenceException("Source entity is null."); + } + + this.ActorEngName = source.ActorEngName; + this.ActorLocalName = source.ActorLocalName; + this.ActorName = source.ActorName; + this.CreatedBy = source.CreatedBy; + this.CreatedDatetime = source.CreatedDatetime; + this.UpdatedBy = source.UpdatedBy; + this.UpdatedDatetime = source.UpdatedDatetime; + + if (includeSystemFields) + { + this.CreatedBy = source.CreatedBy; + this.CreatedDatetime = source.CreatedDatetime; + this.UpdatedBy = source.UpdatedBy; + this.UpdatedDatetime = source.UpdatedDatetime; + } + } + + public override string GetSelectFrom() + { + return $" select {DB_NAME_FIELDS} from { DB_NAME_SECURITY_ACTOR} "; + } + + public override string GetSelectCountFrom(string sqlWhere) + { + return $" select count(*) from { DB_NAME_SECURITY_ACTOR} where 1=1 {sqlWhere}"; + } + + public override string GetSelectTopFrom(int limit, int start,string orderby,string orderbytag, string sqlWhere) + { + if (string.IsNullOrEmpty(orderbytag) || orderbytag.Trim() != "desc") orderbytag = "asc"; + if (string.IsNullOrEmpty(orderby) || !DB_NAME_FIELDS.Contains(orderby)) orderby = DB_ACTOR_NAME ; + int offset = limit * (start - 1); + return $" select {DB_NAME_FIELDS} from (select {DB_NAME_FIELDS} ,row_number() over(order by {orderby} {orderbytag}) as num from { DB_NAME_SECURITY_ACTOR} where 1=1 {sqlWhere} ) a where num> {offset} LIMIT {offset},{limit} "; + } + + public SecurityActorEntity Clone() + { + SecurityActorEntity result = new SecurityActorEntity(); + result.CopyFrom(this); + + return result; + } + + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Entity/SecurityActorGroupEntity.auto.cs b/CloudBuilder/CloudBuilder.Security/Entity/SecurityActorGroupEntity.auto.cs new file mode 100644 index 0000000..669bcd3 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Entity/SecurityActorGroupEntity.auto.cs @@ -0,0 +1,108 @@ + +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +namespace CloudBuilder.Security.Entity + { + [TypeScript] + [Table("security_actor_group")] + public class SecurityActorGroupEntity : EntityBase + { + + public SecurityActorGroupEntity() + { + } + + [Column("actor_name")] + public string ActorName { get; set; } + [Column("created_by")] + public string CreatedBy { get; set; } + [Column("created_datetime")] + public DateTime CreatedDatetime { get; set; } + [Column("group_name")] + public string GroupName { get; set; } + [Column("updated_by")] + public string UpdatedBy { get; set; } + [Column("updated_datetime")] + public DateTime UpdatedDatetime { get; set; } + + public const string ACTOR_NAME = "ActorName"; + public const string CREATED_BY = "CreatedBy"; + public const string CREATED_DATETIME = "CreatedDatetime"; + public const string GROUP_NAME = "GroupName"; + public const string UPDATED_BY = "UpdatedBy"; + public const string UPDATED_DATETIME = "UpdatedDatetime"; + + public const string DB_NAME_SECURITY_ACTOR_GROUP = "security_actor_group"; + public const string DB_NAME_FIELDS="actor_name,created_by,created_datetime,group_name,updated_by,updated_datetime"; + + public const string DB_ACTOR_NAME = "actor_name"; + public const string DB_CREATED_BY = "created_by"; + public const string DB_CREATED_DATETIME = "created_datetime"; + public const string DB_GROUP_NAME = "group_name"; + public const string DB_UPDATED_BY = "updated_by"; + public const string DB_UPDATED_DATETIME = "updated_datetime"; + + + public static SecurityActorGroupEntity GetInstance() + { + return new SecurityActorGroupEntity(); + } + + public virtual void CopyFrom(SecurityActorGroupEntity source) + { + CopyFrom(source, true); + } + + public virtual void CopyFrom(SecurityActorGroupEntity source, bool includeSystemFields) + { + if (source == null) + { + throw new NullReferenceException("Source entity is null."); + } + + this.ActorName = source.ActorName; + this.CreatedBy = source.CreatedBy; + this.CreatedDatetime = source.CreatedDatetime; + this.GroupName = source.GroupName; + this.UpdatedBy = source.UpdatedBy; + this.UpdatedDatetime = source.UpdatedDatetime; + + if (includeSystemFields) + { + this.CreatedBy = source.CreatedBy; + this.CreatedDatetime = source.CreatedDatetime; + this.UpdatedBy = source.UpdatedBy; + this.UpdatedDatetime = source.UpdatedDatetime; + } + } + + public override string GetSelectFrom() + { + return $" select {DB_NAME_FIELDS} from { DB_NAME_SECURITY_ACTOR_GROUP} "; + } + + public override string GetSelectCountFrom(string sqlWhere) + { + return $" select count(*) from { DB_NAME_SECURITY_ACTOR_GROUP} where 1=1 {sqlWhere}"; + } + + public override string GetSelectTopFrom(int limit, int start,string orderby,string orderbytag, string sqlWhere) + { + if (string.IsNullOrEmpty(orderbytag) || orderbytag.Trim() != "desc") orderbytag = "asc"; + if (string.IsNullOrEmpty(orderby) || !DB_NAME_FIELDS.Contains(orderby)) orderby = DB_ACTOR_NAME ; + int offset = limit * (start - 1); + return $" select {DB_NAME_FIELDS} from (select {DB_NAME_FIELDS} ,row_number() over(order by {orderby} {orderbytag}) as num from { DB_NAME_SECURITY_ACTOR_GROUP} where 1=1 {sqlWhere} ) a where num> {offset} LIMIT {offset},{limit} "; + } + + public SecurityActorGroupEntity Clone() + { + SecurityActorGroupEntity result = new SecurityActorGroupEntity(); + result.CopyFrom(this); + + return result; + } + + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Entity/SecurityActorGroupEntityKey.auto.cs b/CloudBuilder/CloudBuilder.Security/Entity/SecurityActorGroupEntityKey.auto.cs new file mode 100644 index 0000000..94770c9 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Entity/SecurityActorGroupEntityKey.auto.cs @@ -0,0 +1,33 @@ + +using CloudBuilder.Core.Authorization; +namespace CloudBuilder.Security +{ + [TypeScript] + public class SecurityActorGroupEntityKey + { + public string ActorName { get; set; } + public string GroupName { get; set; } + + public override bool Equals(object obj) + { + if (this == obj) return true; + + SecurityActorGroupEntityKey pkey = obj as SecurityActorGroupEntityKey; + if (pkey == null) return false; + + if (ActorName != pkey.ActorName) return false; + if (GroupName != pkey.GroupName) return false; + + return true; + } + + + public override string ToString() + { + string declareSql=""; + declareSql=declareSql+$"declare @__tkey_ActorName_0 varchar(50) select @__tkey_ActorName_0 ='{ActorName}'; " ; declareSql=declareSql+$"declare @__tkey_GroupName_1 varchar(50) select @__tkey_GroupName_1 ='{GroupName}'; " ; + return declareSql; + } + } + } + /* builder.Entity().HasKey(c => new { c.ActorName, c.GroupName}); */ diff --git a/CloudBuilder/CloudBuilder.Security/Entity/SecurityActorGroupViewEntity.auto.cs b/CloudBuilder/CloudBuilder.Security/Entity/SecurityActorGroupViewEntity.auto.cs new file mode 100644 index 0000000..c9593cf --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Entity/SecurityActorGroupViewEntity.auto.cs @@ -0,0 +1,94 @@ + +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +namespace CloudBuilder.Security.Entity + { + [TypeScript] + [Table("security_actor_group_view")] + public class SecurityActorGroupViewEntity : ViewEntityBase + { + + public SecurityActorGroupViewEntity() + { + } + + [Column("actor_local_name")] + public string? ActorLocalName { get; set; } + [Column("actor_name")] + public string ActorName { get; set; } + [Column("group_local_name")] + public string? GroupLocalName { get; set; } + [Column("group_name")] + public string GroupName { get; set; } + + public const string ACTOR_LOCAL_NAME = "ActorLocalName"; + public const string ACTOR_NAME = "ActorName"; + public const string GROUP_LOCAL_NAME = "GroupLocalName"; + public const string GROUP_NAME = "GroupName"; + + public const string DB_NAME_SECURITY_ACTOR_GROUP_VIEW = "security_actor_group_view"; + public const string DB_NAME_FIELDS="actor_local_name,actor_name,group_local_name,group_name"; + + public const string DB_ACTOR_LOCAL_NAME = "actor_local_name"; + public const string DB_ACTOR_NAME = "actor_name"; + public const string DB_GROUP_LOCAL_NAME = "group_local_name"; + public const string DB_GROUP_NAME = "group_name"; + + + public static SecurityActorGroupViewEntity GetInstance() + { + return new SecurityActorGroupViewEntity(); + } + + public virtual void CopyFrom(SecurityActorGroupViewEntity source) + { + CopyFrom(source, true); + } + + public virtual void CopyFrom(SecurityActorGroupViewEntity source, bool includeSystemFields) + { + if (source == null) + { + throw new NullReferenceException("Source entity is null."); + } + + this.ActorLocalName = source.ActorLocalName; + this.ActorName = source.ActorName; + this.GroupLocalName = source.GroupLocalName; + this.GroupName = source.GroupName; + + if (includeSystemFields) + { + } + } + + public override string GetSelectFrom() + { + return $" select {DB_NAME_FIELDS} from { DB_NAME_SECURITY_ACTOR_GROUP_VIEW} "; + } + + public override string GetSelectCountFrom(string sqlWhere) + { + return $" select count(*) from { DB_NAME_SECURITY_ACTOR_GROUP_VIEW} where 1=1 {sqlWhere}"; + } + + public override string GetSelectTopFrom(int limit, int start,string orderby,string orderbytag, string sqlWhere) + { + if (string.IsNullOrEmpty(orderbytag) || orderbytag.Trim() != "desc") orderbytag = "asc"; + + if (string.IsNullOrEmpty(orderby) || !DB_NAME_FIELDS.Contains(orderby)) orderby = DB_ACTOR_LOCAL_NAME ; int offset = limit * (start - 1); + return $" select {DB_NAME_FIELDS} from (select {DB_NAME_FIELDS} ,row_number() over(order by {orderby} {orderbytag}) as num from { DB_NAME_SECURITY_ACTOR_GROUP_VIEW} where 1=1 {sqlWhere} ) a where num> {offset} LIMIT {offset},{limit} "; + } + + public SecurityActorGroupViewEntity Clone() + { + SecurityActorGroupViewEntity result = new SecurityActorGroupViewEntity(); + result.CopyFrom(this); + + return result; + } + + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Entity/SecurityFunctionEntity.auto.cs b/CloudBuilder/CloudBuilder.Security/Entity/SecurityFunctionEntity.auto.cs new file mode 100644 index 0000000..605efdf --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Entity/SecurityFunctionEntity.auto.cs @@ -0,0 +1,139 @@ + +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +namespace CloudBuilder.Security.Entity + { + [TypeScript] + [Table("security_function")] + public class SecurityFunctionEntity : ViewEntityBase + { + + public SecurityFunctionEntity() + { + } + + [Column("api_route")] + public string? ApiRoute { get; set; } + [Column("created_by")] + public string CreatedBy { get; set; } + [Column("created_datetime")] + public DateTime CreatedDatetime { get; set; } + [Column("function_eng_name")] + public string? FunctionEngName { get; set; } + [Column("function_indc")] + public string FunctionIndc { get; set; } + [Column("function_local_name")] + public string? FunctionLocalName { get; set; } + [Key] + [Column("function_name")] + public string FunctionName { get; set; } + [Column("icon")] + public string? Icon { get; set; } + [Column("page_name")] + public string? PageName { get; set; } + [Column("page_url")] + public string? PageUrl { get; set; } + [Column("updated_by")] + public string UpdatedBy { get; set; } + [Column("updated_datetime")] + public DateTime UpdatedDatetime { get; set; } + + public const string API_ROUTE = "ApiRoute"; + public const string CREATED_BY = "CreatedBy"; + public const string CREATED_DATETIME = "CreatedDatetime"; + public const string FUNCTION_ENG_NAME = "FunctionEngName"; + public const string FUNCTION_INDC = "FunctionIndc"; + public const string FUNCTION_LOCAL_NAME = "FunctionLocalName"; + public const string FUNCTION_NAME = "FunctionName"; + public const string ICON = "Icon"; + public const string PAGE_NAME = "PageName"; + public const string PAGE_URL = "PageUrl"; + public const string UPDATED_BY = "UpdatedBy"; + public const string UPDATED_DATETIME = "UpdatedDatetime"; + + public const string DB_NAME_SECURITY_FUNCTION = "security_function"; + public const string DB_NAME_FIELDS="api_route,created_by,created_datetime,function_eng_name,function_indc,function_local_name,function_name,icon,page_name,page_url,updated_by,updated_datetime"; + + public const string DB_API_ROUTE = "api_route"; + public const string DB_CREATED_BY = "created_by"; + public const string DB_CREATED_DATETIME = "created_datetime"; + public const string DB_FUNCTION_ENG_NAME = "function_eng_name"; + public const string DB_FUNCTION_INDC = "function_indc"; + public const string DB_FUNCTION_LOCAL_NAME = "function_local_name"; + public const string DB_FUNCTION_NAME = "function_name"; + public const string DB_ICON = "icon"; + public const string DB_PAGE_NAME = "page_name"; + public const string DB_PAGE_URL = "page_url"; + public const string DB_UPDATED_BY = "updated_by"; + public const string DB_UPDATED_DATETIME = "updated_datetime"; + + + public static SecurityFunctionEntity GetInstance() + { + return new SecurityFunctionEntity(); + } + + public virtual void CopyFrom(SecurityFunctionEntity source) + { + CopyFrom(source, true); + } + + public virtual void CopyFrom(SecurityFunctionEntity source, bool includeSystemFields) + { + if (source == null) + { + throw new NullReferenceException("Source entity is null."); + } + + this.ApiRoute = source.ApiRoute; + this.CreatedBy = source.CreatedBy; + this.CreatedDatetime = source.CreatedDatetime; + this.FunctionEngName = source.FunctionEngName; + this.FunctionIndc = source.FunctionIndc; + this.FunctionLocalName = source.FunctionLocalName; + this.FunctionName = source.FunctionName; + this.Icon = source.Icon; + this.PageName = source.PageName; + this.PageUrl = source.PageUrl; + this.UpdatedBy = source.UpdatedBy; + this.UpdatedDatetime = source.UpdatedDatetime; + + if (includeSystemFields) + { + this.CreatedBy = source.CreatedBy; + this.CreatedDatetime = source.CreatedDatetime; + this.UpdatedBy = source.UpdatedBy; + this.UpdatedDatetime = source.UpdatedDatetime; + } + } + + public override string GetSelectFrom() + { + return $" select {DB_NAME_FIELDS} from { DB_NAME_SECURITY_FUNCTION} "; + } + + public override string GetSelectCountFrom(string sqlWhere) + { + return $" select count(*) from { DB_NAME_SECURITY_FUNCTION} where 1=1 {sqlWhere}"; + } + + public override string GetSelectTopFrom(int limit, int start,string orderby,string orderbytag, string sqlWhere) + { + if (string.IsNullOrEmpty(orderbytag) || orderbytag.Trim() != "desc") orderbytag = "asc"; + if (string.IsNullOrEmpty(orderby) || !DB_NAME_FIELDS.Contains(orderby)) orderby = DB_FUNCTION_NAME ; + int offset = limit * (start - 1); + return $" select {DB_NAME_FIELDS} from (select {DB_NAME_FIELDS} ,row_number() over(order by {orderby} {orderbytag}) as num from { DB_NAME_SECURITY_FUNCTION} where 1=1 {sqlWhere} ) a where num> {offset} LIMIT {offset},{limit} "; + } + + public SecurityFunctionEntity Clone() + { + SecurityFunctionEntity result = new SecurityFunctionEntity(); + result.CopyFrom(this); + + return result; + } + + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Entity/SecurityFunctionMapEntity.auto.cs b/CloudBuilder/CloudBuilder.Security/Entity/SecurityFunctionMapEntity.auto.cs new file mode 100644 index 0000000..8aa32de --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Entity/SecurityFunctionMapEntity.auto.cs @@ -0,0 +1,113 @@ + +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +namespace CloudBuilder.Security.Entity + { + [TypeScript] + [Table("security_function_map")] + public class SecurityFunctionMapEntity : EntityBase + { + + public SecurityFunctionMapEntity() + { + } + + [Column("created_by")] + public string CreatedBy { get; set; } + [Column("created_datetime")] + public DateTime CreatedDatetime { get; set; } + [Column("function_name_parent")] + public string FunctionNameParent { get; set; } + [Column("function_name_son")] + public string FunctionNameSon { get; set; } + [Column("orderby")] + public int Orderby { get; set; } + [Column("updated_by")] + public string UpdatedBy { get; set; } + [Column("updated_datetime")] + public DateTime UpdatedDatetime { get; set; } + + public const string CREATED_BY = "CreatedBy"; + public const string CREATED_DATETIME = "CreatedDatetime"; + public const string FUNCTION_NAME_PARENT = "FunctionNameParent"; + public const string FUNCTION_NAME_SON = "FunctionNameSon"; + public const string ORDERBY = "Orderby"; + public const string UPDATED_BY = "UpdatedBy"; + public const string UPDATED_DATETIME = "UpdatedDatetime"; + + public const string DB_NAME_SECURITY_FUNCTION_MAP = "security_function_map"; + public const string DB_NAME_FIELDS="created_by,created_datetime,function_name_parent,function_name_son,orderby,updated_by,updated_datetime"; + + public const string DB_CREATED_BY = "created_by"; + public const string DB_CREATED_DATETIME = "created_datetime"; + public const string DB_FUNCTION_NAME_PARENT = "function_name_parent"; + public const string DB_FUNCTION_NAME_SON = "function_name_son"; + public const string DB_ORDERBY = "orderby"; + public const string DB_UPDATED_BY = "updated_by"; + public const string DB_UPDATED_DATETIME = "updated_datetime"; + + + public static SecurityFunctionMapEntity GetInstance() + { + return new SecurityFunctionMapEntity(); + } + + public virtual void CopyFrom(SecurityFunctionMapEntity source) + { + CopyFrom(source, true); + } + + public virtual void CopyFrom(SecurityFunctionMapEntity source, bool includeSystemFields) + { + if (source == null) + { + throw new NullReferenceException("Source entity is null."); + } + + this.CreatedBy = source.CreatedBy; + this.CreatedDatetime = source.CreatedDatetime; + this.FunctionNameParent = source.FunctionNameParent; + this.FunctionNameSon = source.FunctionNameSon; + this.Orderby = source.Orderby; + this.UpdatedBy = source.UpdatedBy; + this.UpdatedDatetime = source.UpdatedDatetime; + + if (includeSystemFields) + { + this.CreatedBy = source.CreatedBy; + this.CreatedDatetime = source.CreatedDatetime; + this.UpdatedBy = source.UpdatedBy; + this.UpdatedDatetime = source.UpdatedDatetime; + } + } + + public override string GetSelectFrom() + { + return $" select {DB_NAME_FIELDS} from { DB_NAME_SECURITY_FUNCTION_MAP} "; + } + + public override string GetSelectCountFrom(string sqlWhere) + { + return $" select count(*) from { DB_NAME_SECURITY_FUNCTION_MAP} where 1=1 {sqlWhere}"; + } + + public override string GetSelectTopFrom(int limit, int start,string orderby,string orderbytag, string sqlWhere) + { + if (string.IsNullOrEmpty(orderbytag) || orderbytag.Trim() != "desc") orderbytag = "asc"; + if (string.IsNullOrEmpty(orderby) || !DB_NAME_FIELDS.Contains(orderby)) orderby = DB_FUNCTION_NAME_PARENT ; + int offset = limit * (start - 1); + return $" select {DB_NAME_FIELDS} from (select {DB_NAME_FIELDS} ,row_number() over(order by {orderby} {orderbytag}) as num from { DB_NAME_SECURITY_FUNCTION_MAP} where 1=1 {sqlWhere} ) a where num> {offset} LIMIT {offset},{limit} "; + } + + public SecurityFunctionMapEntity Clone() + { + SecurityFunctionMapEntity result = new SecurityFunctionMapEntity(); + result.CopyFrom(this); + + return result; + } + + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Entity/SecurityFunctionMapEntityKey.auto.cs b/CloudBuilder/CloudBuilder.Security/Entity/SecurityFunctionMapEntityKey.auto.cs new file mode 100644 index 0000000..fb0ae82 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Entity/SecurityFunctionMapEntityKey.auto.cs @@ -0,0 +1,33 @@ + +using CloudBuilder.Core.Authorization; +namespace CloudBuilder.Security +{ + [TypeScript] + public class SecurityFunctionMapEntityKey + { + public string FunctionNameParent { get; set; } + public string FunctionNameSon { get; set; } + + public override bool Equals(object obj) + { + if (this == obj) return true; + + SecurityFunctionMapEntityKey pkey = obj as SecurityFunctionMapEntityKey; + if (pkey == null) return false; + + if (FunctionNameParent != pkey.FunctionNameParent) return false; + if (FunctionNameSon != pkey.FunctionNameSon) return false; + + return true; + } + + + public override string ToString() + { + string declareSql=""; + declareSql=declareSql+$"declare @__tkey_FunctionNameParent_0 varchar(50) select @__tkey_FunctionNameParent_0 ='{FunctionNameParent}'; " ; declareSql=declareSql+$"declare @__tkey_FunctionNameSon_1 varchar(50) select @__tkey_FunctionNameSon_1 ='{FunctionNameSon}'; " ; + return declareSql; + } + } + } + /* builder.Entity().HasKey(c => new { c.FunctionNameParent, c.FunctionNameSon}); */ diff --git a/CloudBuilder/CloudBuilder.Security/Entity/SecurityFunctionMapViewEntity.auto.cs b/CloudBuilder/CloudBuilder.Security/Entity/SecurityFunctionMapViewEntity.auto.cs new file mode 100644 index 0000000..cfea446 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Entity/SecurityFunctionMapViewEntity.auto.cs @@ -0,0 +1,104 @@ + +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +namespace CloudBuilder.Security.Entity + { + [TypeScript] + [Table("security_function_map_view")] + public class SecurityFunctionMapViewEntity : ViewEntityBase + { + + public SecurityFunctionMapViewEntity() + { + } + + [Column("orderby")] + public int Orderby { get; set; } + [Column("parent_function_local_name")] + public string? ParentFunctionLocalName { get; set; } + [Column("parent_function_name")] + public string ParentFunctionName { get; set; } + [Column("son_function_local_name")] + public string? SonFunctionLocalName { get; set; } + [Column("son_function_name")] + public string SonFunctionName { get; set; } + [Column("son_page_name")] + public string? SonPageName { get; set; } + + public const string ORDERBY = "Orderby"; + public const string PARENT_FUNCTION_LOCAL_NAME = "ParentFunctionLocalName"; + public const string PARENT_FUNCTION_NAME = "ParentFunctionName"; + public const string SON_FUNCTION_LOCAL_NAME = "SonFunctionLocalName"; + public const string SON_FUNCTION_NAME = "SonFunctionName"; + public const string SON_PAGE_NAME = "SonPageName"; + + public const string DB_NAME_SECURITY_FUNCTION_MAP_VIEW = "security_function_map_view"; + public const string DB_NAME_FIELDS="orderby,parent_function_local_name,parent_function_name,son_function_local_name,son_function_name,son_page_name"; + + public const string DB_ORDERBY = "orderby"; + public const string DB_PARENT_FUNCTION_LOCAL_NAME = "parent_function_local_name"; + public const string DB_PARENT_FUNCTION_NAME = "parent_function_name"; + public const string DB_SON_FUNCTION_LOCAL_NAME = "son_function_local_name"; + public const string DB_SON_FUNCTION_NAME = "son_function_name"; + public const string DB_SON_PAGE_NAME = "son_page_name"; + + + public static SecurityFunctionMapViewEntity GetInstance() + { + return new SecurityFunctionMapViewEntity(); + } + + public virtual void CopyFrom(SecurityFunctionMapViewEntity source) + { + CopyFrom(source, true); + } + + public virtual void CopyFrom(SecurityFunctionMapViewEntity source, bool includeSystemFields) + { + if (source == null) + { + throw new NullReferenceException("Source entity is null."); + } + + this.Orderby = source.Orderby; + this.ParentFunctionLocalName = source.ParentFunctionLocalName; + this.ParentFunctionName = source.ParentFunctionName; + this.SonFunctionLocalName = source.SonFunctionLocalName; + this.SonFunctionName = source.SonFunctionName; + this.SonPageName = source.SonPageName; + + if (includeSystemFields) + { + } + } + + public override string GetSelectFrom() + { + return $" select {DB_NAME_FIELDS} from { DB_NAME_SECURITY_FUNCTION_MAP_VIEW} "; + } + + public override string GetSelectCountFrom(string sqlWhere) + { + return $" select count(*) from { DB_NAME_SECURITY_FUNCTION_MAP_VIEW} where 1=1 {sqlWhere}"; + } + + public override string GetSelectTopFrom(int limit, int start,string orderby,string orderbytag, string sqlWhere) + { + if (string.IsNullOrEmpty(orderbytag) || orderbytag.Trim() != "desc") orderbytag = "asc"; + + if (string.IsNullOrEmpty(orderby) || !DB_NAME_FIELDS.Contains(orderby)) orderby = DB_ORDERBY ; int offset = limit * (start - 1); + return $" select {DB_NAME_FIELDS} from (select {DB_NAME_FIELDS} ,row_number() over(order by {orderby} {orderbytag}) as num from { DB_NAME_SECURITY_FUNCTION_MAP_VIEW} where 1=1 {sqlWhere} ) a where num> {offset} LIMIT {offset},{limit} "; + } + + public SecurityFunctionMapViewEntity Clone() + { + SecurityFunctionMapViewEntity result = new SecurityFunctionMapViewEntity(); + result.CopyFrom(this); + + return result; + } + + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Entity/SecurityGeneratorNumberEntity.auto.cs b/CloudBuilder/CloudBuilder.Security/Entity/SecurityGeneratorNumberEntity.auto.cs new file mode 100644 index 0000000..7dbd182 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Entity/SecurityGeneratorNumberEntity.auto.cs @@ -0,0 +1,140 @@ + +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +namespace CloudBuilder.Security.Entity + { + [TypeScript] + [Table("security_generator_number")] + public class SecurityGeneratorNumberEntity : ViewEntityBase + { + + public SecurityGeneratorNumberEntity() + { + } + + [Column("created_by")] + public string CreatedBy { get; set; } + [Column("created_datetime")] + public DateTime CreatedDatetime { get; set; } + [Column("format")] + public string Format { get; set; } + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + [Column("generator_id")] + public int GeneratorId { get; set; } + [Column("last_generator_date")] + public DateTime LastGeneratorDate { get; set; } + [Column("next_id")] + public int NextId { get; set; } + [Column("prefix")] + public string? Prefix { get; set; } + [Column("refresh_period")] + public string RefreshPeriod { get; set; } + [Column("subsystem_id")] + public string SubsystemId { get; set; } + [Column("system_id")] + public string SystemId { get; set; } + [Column("updated_by")] + public string UpdatedBy { get; set; } + [Column("updated_datetime")] + public DateTime UpdatedDatetime { get; set; } + + public const string CREATED_BY = "CreatedBy"; + public const string CREATED_DATETIME = "CreatedDatetime"; + public const string FORMAT = "Format"; + public const string GENERATOR_ID = "GeneratorId"; + public const string LAST_GENERATOR_DATE = "LastGeneratorDate"; + public const string NEXT_ID = "NextId"; + public const string PREFIX = "Prefix"; + public const string REFRESH_PERIOD = "RefreshPeriod"; + public const string SUBSYSTEM_ID = "SubsystemId"; + public const string SYSTEM_ID = "SystemId"; + public const string UPDATED_BY = "UpdatedBy"; + public const string UPDATED_DATETIME = "UpdatedDatetime"; + + public const string DB_NAME_SECURITY_GENERATOR_NUMBER = "security_generator_number"; + public const string DB_NAME_FIELDS="created_by,created_datetime,format,generator_id,last_generator_date,next_id,prefix,refresh_period,subsystem_id,system_id,updated_by,updated_datetime"; + + public const string DB_CREATED_BY = "created_by"; + public const string DB_CREATED_DATETIME = "created_datetime"; + public const string DB_FORMAT = "format"; + public const string DB_GENERATOR_ID = "generator_id"; + public const string DB_LAST_GENERATOR_DATE = "last_generator_date"; + public const string DB_NEXT_ID = "next_id"; + public const string DB_PREFIX = "prefix"; + public const string DB_REFRESH_PERIOD = "refresh_period"; + public const string DB_SUBSYSTEM_ID = "subsystem_id"; + public const string DB_SYSTEM_ID = "system_id"; + public const string DB_UPDATED_BY = "updated_by"; + public const string DB_UPDATED_DATETIME = "updated_datetime"; + + + public static SecurityGeneratorNumberEntity GetInstance() + { + return new SecurityGeneratorNumberEntity(); + } + + public virtual void CopyFrom(SecurityGeneratorNumberEntity source) + { + CopyFrom(source, true); + } + + public virtual void CopyFrom(SecurityGeneratorNumberEntity source, bool includeSystemFields) + { + if (source == null) + { + throw new NullReferenceException("Source entity is null."); + } + + this.CreatedBy = source.CreatedBy; + this.CreatedDatetime = source.CreatedDatetime; + this.Format = source.Format; + this.GeneratorId = source.GeneratorId; + this.LastGeneratorDate = source.LastGeneratorDate; + this.NextId = source.NextId; + this.Prefix = source.Prefix; + this.RefreshPeriod = source.RefreshPeriod; + this.SubsystemId = source.SubsystemId; + this.SystemId = source.SystemId; + this.UpdatedBy = source.UpdatedBy; + this.UpdatedDatetime = source.UpdatedDatetime; + + if (includeSystemFields) + { + this.CreatedBy = source.CreatedBy; + this.CreatedDatetime = source.CreatedDatetime; + this.UpdatedBy = source.UpdatedBy; + this.UpdatedDatetime = source.UpdatedDatetime; + } + } + + public override string GetSelectFrom() + { + return $" select {DB_NAME_FIELDS} from { DB_NAME_SECURITY_GENERATOR_NUMBER} "; + } + + public override string GetSelectCountFrom(string sqlWhere) + { + return $" select count(*) from { DB_NAME_SECURITY_GENERATOR_NUMBER} where 1=1 {sqlWhere}"; + } + + public override string GetSelectTopFrom(int limit, int start,string orderby,string orderbytag, string sqlWhere) + { + if (string.IsNullOrEmpty(orderbytag) || orderbytag.Trim() != "desc") orderbytag = "asc"; + if (string.IsNullOrEmpty(orderby) || !DB_NAME_FIELDS.Contains(orderby)) orderby = DB_GENERATOR_ID ; + int offset = limit * (start - 1); + return $" select {DB_NAME_FIELDS} from (select {DB_NAME_FIELDS} ,row_number() over(order by {orderby} {orderbytag}) as num from { DB_NAME_SECURITY_GENERATOR_NUMBER} where 1=1 {sqlWhere} ) a where num> {offset} LIMIT {offset},{limit} "; + } + + public SecurityGeneratorNumberEntity Clone() + { + SecurityGeneratorNumberEntity result = new SecurityGeneratorNumberEntity(); + result.CopyFrom(this); + + return result; + } + + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Entity/SecurityGroupEntity.auto.cs b/CloudBuilder/CloudBuilder.Security/Entity/SecurityGroupEntity.auto.cs new file mode 100644 index 0000000..5219f09 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Entity/SecurityGroupEntity.auto.cs @@ -0,0 +1,114 @@ + +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +namespace CloudBuilder.Security.Entity + { + [TypeScript] + [Table("security_group")] + public class SecurityGroupEntity : ViewEntityBase + { + + public SecurityGroupEntity() + { + } + + [Column("created_by")] + public string CreatedBy { get; set; } + [Column("created_datetime")] + public DateTime CreatedDatetime { get; set; } + [Column("group_eng_name")] + public string? GroupEngName { get; set; } + [Column("group_local_name")] + public string? GroupLocalName { get; set; } + [Key] + [Column("group_name")] + public string GroupName { get; set; } + [Column("updated_by")] + public string UpdatedBy { get; set; } + [Column("updated_datetime")] + public DateTime UpdatedDatetime { get; set; } + + public const string CREATED_BY = "CreatedBy"; + public const string CREATED_DATETIME = "CreatedDatetime"; + public const string GROUP_ENG_NAME = "GroupEngName"; + public const string GROUP_LOCAL_NAME = "GroupLocalName"; + public const string GROUP_NAME = "GroupName"; + public const string UPDATED_BY = "UpdatedBy"; + public const string UPDATED_DATETIME = "UpdatedDatetime"; + + public const string DB_NAME_SECURITY_GROUP = "security_group"; + public const string DB_NAME_FIELDS="created_by,created_datetime,group_eng_name,group_local_name,group_name,updated_by,updated_datetime"; + + public const string DB_CREATED_BY = "created_by"; + public const string DB_CREATED_DATETIME = "created_datetime"; + public const string DB_GROUP_ENG_NAME = "group_eng_name"; + public const string DB_GROUP_LOCAL_NAME = "group_local_name"; + public const string DB_GROUP_NAME = "group_name"; + public const string DB_UPDATED_BY = "updated_by"; + public const string DB_UPDATED_DATETIME = "updated_datetime"; + + + public static SecurityGroupEntity GetInstance() + { + return new SecurityGroupEntity(); + } + + public virtual void CopyFrom(SecurityGroupEntity source) + { + CopyFrom(source, true); + } + + public virtual void CopyFrom(SecurityGroupEntity source, bool includeSystemFields) + { + if (source == null) + { + throw new NullReferenceException("Source entity is null."); + } + + this.CreatedBy = source.CreatedBy; + this.CreatedDatetime = source.CreatedDatetime; + this.GroupEngName = source.GroupEngName; + this.GroupLocalName = source.GroupLocalName; + this.GroupName = source.GroupName; + this.UpdatedBy = source.UpdatedBy; + this.UpdatedDatetime = source.UpdatedDatetime; + + if (includeSystemFields) + { + this.CreatedBy = source.CreatedBy; + this.CreatedDatetime = source.CreatedDatetime; + this.UpdatedBy = source.UpdatedBy; + this.UpdatedDatetime = source.UpdatedDatetime; + } + } + + public override string GetSelectFrom() + { + return $" select {DB_NAME_FIELDS} from { DB_NAME_SECURITY_GROUP} "; + } + + public override string GetSelectCountFrom(string sqlWhere) + { + return $" select count(*) from { DB_NAME_SECURITY_GROUP} where 1=1 {sqlWhere}"; + } + + public override string GetSelectTopFrom(int limit, int start,string orderby,string orderbytag, string sqlWhere) + { + if (string.IsNullOrEmpty(orderbytag) || orderbytag.Trim() != "desc") orderbytag = "asc"; + if (string.IsNullOrEmpty(orderby) || !DB_NAME_FIELDS.Contains(orderby)) orderby = DB_GROUP_NAME ; + int offset = limit * (start - 1); + return $" select {DB_NAME_FIELDS} from (select {DB_NAME_FIELDS} ,row_number() over(order by {orderby} {orderbytag}) as num from { DB_NAME_SECURITY_GROUP} where 1=1 {sqlWhere} ) a where num> {offset} LIMIT {offset},{limit} "; + } + + public SecurityGroupEntity Clone() + { + SecurityGroupEntity result = new SecurityGroupEntity(); + result.CopyFrom(this); + + return result; + } + + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Entity/SecurityGroupPermissionDependentEntity.auto.cs b/CloudBuilder/CloudBuilder.Security/Entity/SecurityGroupPermissionDependentEntity.auto.cs new file mode 100644 index 0000000..847e142 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Entity/SecurityGroupPermissionDependentEntity.auto.cs @@ -0,0 +1,133 @@ + +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +namespace CloudBuilder.Security.Entity + { + [TypeScript] + [Table("security_group_permission_dependent")] + public class SecurityGroupPermissionDependentEntity : EntityBase + { + + public SecurityGroupPermissionDependentEntity() + { + } + + [Column("amend_indc")] + public string AmendIndc { get; set; } + [Column("create_indc")] + public string CreateIndc { get; set; } + [Column("created_by")] + public string CreatedBy { get; set; } + [Column("created_datetime")] + public DateTime CreatedDatetime { get; set; } + [Column("delete_indc")] + public string DeleteIndc { get; set; } + [Column("dependent_detail_name")] + public string DependentDetailName { get; set; } + [Column("group_name")] + public string GroupName { get; set; } + [Column("permission_name")] + public string PermissionName { get; set; } + [Column("updated_by")] + public string UpdatedBy { get; set; } + [Column("updated_datetime")] + public DateTime UpdatedDatetime { get; set; } + [Column("view_indc")] + public string ViewIndc { get; set; } + + public const string AMEND_INDC = "AmendIndc"; + public const string CREATE_INDC = "CreateIndc"; + public const string CREATED_BY = "CreatedBy"; + public const string CREATED_DATETIME = "CreatedDatetime"; + public const string DELETE_INDC = "DeleteIndc"; + public const string DEPENDENT_DETAIL_NAME = "DependentDetailName"; + public const string GROUP_NAME = "GroupName"; + public const string PERMISSION_NAME = "PermissionName"; + public const string UPDATED_BY = "UpdatedBy"; + public const string UPDATED_DATETIME = "UpdatedDatetime"; + public const string VIEW_INDC = "ViewIndc"; + + public const string DB_NAME_SECURITY_GROUP_PERMISSION_DEPENDENT = "security_group_permission_dependent"; + public const string DB_NAME_FIELDS="amend_indc,create_indc,created_by,created_datetime,delete_indc,dependent_detail_name,group_name,permission_name,updated_by,updated_datetime,view_indc"; + + public const string DB_AMEND_INDC = "amend_indc"; + public const string DB_CREATE_INDC = "create_indc"; + public const string DB_CREATED_BY = "created_by"; + public const string DB_CREATED_DATETIME = "created_datetime"; + public const string DB_DELETE_INDC = "delete_indc"; + public const string DB_DEPENDENT_DETAIL_NAME = "dependent_detail_name"; + public const string DB_GROUP_NAME = "group_name"; + public const string DB_PERMISSION_NAME = "permission_name"; + public const string DB_UPDATED_BY = "updated_by"; + public const string DB_UPDATED_DATETIME = "updated_datetime"; + public const string DB_VIEW_INDC = "view_indc"; + + + public static SecurityGroupPermissionDependentEntity GetInstance() + { + return new SecurityGroupPermissionDependentEntity(); + } + + public virtual void CopyFrom(SecurityGroupPermissionDependentEntity source) + { + CopyFrom(source, true); + } + + public virtual void CopyFrom(SecurityGroupPermissionDependentEntity source, bool includeSystemFields) + { + if (source == null) + { + throw new NullReferenceException("Source entity is null."); + } + + this.AmendIndc = source.AmendIndc; + this.CreateIndc = source.CreateIndc; + this.CreatedBy = source.CreatedBy; + this.CreatedDatetime = source.CreatedDatetime; + this.DeleteIndc = source.DeleteIndc; + this.DependentDetailName = source.DependentDetailName; + this.GroupName = source.GroupName; + this.PermissionName = source.PermissionName; + this.UpdatedBy = source.UpdatedBy; + this.UpdatedDatetime = source.UpdatedDatetime; + this.ViewIndc = source.ViewIndc; + + if (includeSystemFields) + { + this.CreatedBy = source.CreatedBy; + this.CreatedDatetime = source.CreatedDatetime; + this.UpdatedBy = source.UpdatedBy; + this.UpdatedDatetime = source.UpdatedDatetime; + } + } + + public override string GetSelectFrom() + { + return $" select {DB_NAME_FIELDS} from { DB_NAME_SECURITY_GROUP_PERMISSION_DEPENDENT} "; + } + + public override string GetSelectCountFrom(string sqlWhere) + { + return $" select count(*) from { DB_NAME_SECURITY_GROUP_PERMISSION_DEPENDENT} where 1=1 {sqlWhere}"; + } + + public override string GetSelectTopFrom(int limit, int start,string orderby,string orderbytag, string sqlWhere) + { + if (string.IsNullOrEmpty(orderbytag) || orderbytag.Trim() != "desc") orderbytag = "asc"; + if (string.IsNullOrEmpty(orderby) || !DB_NAME_FIELDS.Contains(orderby)) orderby = DB_DEPENDENT_DETAIL_NAME ; + int offset = limit * (start - 1); + return $" select {DB_NAME_FIELDS} from (select {DB_NAME_FIELDS} ,row_number() over(order by {orderby} {orderbytag}) as num from { DB_NAME_SECURITY_GROUP_PERMISSION_DEPENDENT} where 1=1 {sqlWhere} ) a where num> {offset} LIMIT {offset},{limit} "; + } + + public SecurityGroupPermissionDependentEntity Clone() + { + SecurityGroupPermissionDependentEntity result = new SecurityGroupPermissionDependentEntity(); + result.CopyFrom(this); + + return result; + } + + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Entity/SecurityGroupPermissionDependentEntityKey.auto.cs b/CloudBuilder/CloudBuilder.Security/Entity/SecurityGroupPermissionDependentEntityKey.auto.cs new file mode 100644 index 0000000..015546e --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Entity/SecurityGroupPermissionDependentEntityKey.auto.cs @@ -0,0 +1,35 @@ + +using CloudBuilder.Core.Authorization; +namespace CloudBuilder.Security +{ + [TypeScript] + public class SecurityGroupPermissionDependentEntityKey + { + public string DependentDetailName { get; set; } + public string GroupName { get; set; } + public string PermissionName { get; set; } + + public override bool Equals(object obj) + { + if (this == obj) return true; + + SecurityGroupPermissionDependentEntityKey pkey = obj as SecurityGroupPermissionDependentEntityKey; + if (pkey == null) return false; + + if (DependentDetailName != pkey.DependentDetailName) return false; + if (GroupName != pkey.GroupName) return false; + if (PermissionName != pkey.PermissionName) return false; + + return true; + } + + + public override string ToString() + { + string declareSql=""; + declareSql=declareSql+$"declare @__tkey_DependentDetailName_0 varchar(50) select @__tkey_DependentDetailName_0 ='{DependentDetailName}'; " ; declareSql=declareSql+$"declare @__tkey_GroupName_1 varchar(50) select @__tkey_GroupName_1 ='{GroupName}'; " ; declareSql=declareSql+$"declare @__tkey_PermissionName_2 varchar(50) select @__tkey_PermissionName_2 ='{PermissionName}'; " ; + return declareSql; + } + } + } + /* builder.Entity().HasKey(c => new { c.DependentDetailName, c.GroupName, c.PermissionName}); */ diff --git a/CloudBuilder/CloudBuilder.Security/Entity/SecurityGroupPermissionDependentViewEntity.auto.cs b/CloudBuilder/CloudBuilder.Security/Entity/SecurityGroupPermissionDependentViewEntity.auto.cs new file mode 100644 index 0000000..170363f --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Entity/SecurityGroupPermissionDependentViewEntity.auto.cs @@ -0,0 +1,124 @@ + +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +namespace CloudBuilder.Security.Entity + { + [TypeScript] + [Table("security_group_permission_dependent_view")] + public class SecurityGroupPermissionDependentViewEntity : ViewEntityBase + { + + public SecurityGroupPermissionDependentViewEntity() + { + } + + [Column("amend_indc")] + public string AmendIndc { get; set; } + [Column("create_indc")] + public string CreateIndc { get; set; } + [Column("delete_indc")] + public string DeleteIndc { get; set; } + [Column("dependent")] + public string Dependent { get; set; } + [Column("dependent_detail_description")] + public string? DependentDetailDescription { get; set; } + [Column("dependent_detail_name")] + public string DependentDetailName { get; set; } + [Column("group_name")] + public string GroupName { get; set; } + [Column("permission_description")] + public string? PermissionDescription { get; set; } + [Column("permission_name")] + public string PermissionName { get; set; } + [Column("view_indc")] + public string ViewIndc { get; set; } + + public const string AMEND_INDC = "AmendIndc"; + public const string CREATE_INDC = "CreateIndc"; + public const string DELETE_INDC = "DeleteIndc"; + public const string DEPENDENT = "Dependent"; + public const string DEPENDENT_DETAIL_DESCRIPTION = "DependentDetailDescription"; + public const string DEPENDENT_DETAIL_NAME = "DependentDetailName"; + public const string GROUP_NAME = "GroupName"; + public const string PERMISSION_DESCRIPTION = "PermissionDescription"; + public const string PERMISSION_NAME = "PermissionName"; + public const string VIEW_INDC = "ViewIndc"; + + public const string DB_NAME_SECURITY_GROUP_PERMISSION_DEPENDENT_VIEW = "security_group_permission_dependent_view"; + public const string DB_NAME_FIELDS="amend_indc,create_indc,delete_indc,dependent,dependent_detail_description,dependent_detail_name,group_name,permission_description,permission_name,view_indc"; + + public const string DB_AMEND_INDC = "amend_indc"; + public const string DB_CREATE_INDC = "create_indc"; + public const string DB_DELETE_INDC = "delete_indc"; + public const string DB_DEPENDENT = "dependent"; + public const string DB_DEPENDENT_DETAIL_DESCRIPTION = "dependent_detail_description"; + public const string DB_DEPENDENT_DETAIL_NAME = "dependent_detail_name"; + public const string DB_GROUP_NAME = "group_name"; + public const string DB_PERMISSION_DESCRIPTION = "permission_description"; + public const string DB_PERMISSION_NAME = "permission_name"; + public const string DB_VIEW_INDC = "view_indc"; + + + public static SecurityGroupPermissionDependentViewEntity GetInstance() + { + return new SecurityGroupPermissionDependentViewEntity(); + } + + public virtual void CopyFrom(SecurityGroupPermissionDependentViewEntity source) + { + CopyFrom(source, true); + } + + public virtual void CopyFrom(SecurityGroupPermissionDependentViewEntity source, bool includeSystemFields) + { + if (source == null) + { + throw new NullReferenceException("Source entity is null."); + } + + this.AmendIndc = source.AmendIndc; + this.CreateIndc = source.CreateIndc; + this.DeleteIndc = source.DeleteIndc; + this.Dependent = source.Dependent; + this.DependentDetailDescription = source.DependentDetailDescription; + this.DependentDetailName = source.DependentDetailName; + this.GroupName = source.GroupName; + this.PermissionDescription = source.PermissionDescription; + this.PermissionName = source.PermissionName; + this.ViewIndc = source.ViewIndc; + + if (includeSystemFields) + { + } + } + + public override string GetSelectFrom() + { + return $" select {DB_NAME_FIELDS} from { DB_NAME_SECURITY_GROUP_PERMISSION_DEPENDENT_VIEW} "; + } + + public override string GetSelectCountFrom(string sqlWhere) + { + return $" select count(*) from { DB_NAME_SECURITY_GROUP_PERMISSION_DEPENDENT_VIEW} where 1=1 {sqlWhere}"; + } + + public override string GetSelectTopFrom(int limit, int start,string orderby,string orderbytag, string sqlWhere) + { + if (string.IsNullOrEmpty(orderbytag) || orderbytag.Trim() != "desc") orderbytag = "asc"; + + if (string.IsNullOrEmpty(orderby) || !DB_NAME_FIELDS.Contains(orderby)) orderby = DB_AMEND_INDC ; int offset = limit * (start - 1); + return $" select {DB_NAME_FIELDS} from (select {DB_NAME_FIELDS} ,row_number() over(order by {orderby} {orderbytag}) as num from { DB_NAME_SECURITY_GROUP_PERMISSION_DEPENDENT_VIEW} where 1=1 {sqlWhere} ) a where num> {offset} LIMIT {offset},{limit} "; + } + + public SecurityGroupPermissionDependentViewEntity Clone() + { + SecurityGroupPermissionDependentViewEntity result = new SecurityGroupPermissionDependentViewEntity(); + result.CopyFrom(this); + + return result; + } + + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Entity/SecurityGroupPermissionEntity.auto.cs b/CloudBuilder/CloudBuilder.Security/Entity/SecurityGroupPermissionEntity.auto.cs new file mode 100644 index 0000000..1492a96 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Entity/SecurityGroupPermissionEntity.auto.cs @@ -0,0 +1,133 @@ + +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +namespace CloudBuilder.Security.Entity + { + [TypeScript] + [Table("security_group_permission")] + public class SecurityGroupPermissionEntity : EntityBase + { + + public SecurityGroupPermissionEntity() + { + } + + [Column("amend_indc")] + public string AmendIndc { get; set; } + [Column("create_indc")] + public string CreateIndc { get; set; } + [Column("created_by")] + public string CreatedBy { get; set; } + [Column("created_datetime")] + public DateTime CreatedDatetime { get; set; } + [Column("delete_indc")] + public string DeleteIndc { get; set; } + [Column("dependent")] + public string? Dependent { get; set; } + [Column("group_name")] + public string GroupName { get; set; } + [Column("permission_name")] + public string PermissionName { get; set; } + [Column("updated_by")] + public string UpdatedBy { get; set; } + [Column("updated_datetime")] + public DateTime UpdatedDatetime { get; set; } + [Column("view_indc")] + public string ViewIndc { get; set; } + + public const string AMEND_INDC = "AmendIndc"; + public const string CREATE_INDC = "CreateIndc"; + public const string CREATED_BY = "CreatedBy"; + public const string CREATED_DATETIME = "CreatedDatetime"; + public const string DELETE_INDC = "DeleteIndc"; + public const string DEPENDENT = "Dependent"; + public const string GROUP_NAME = "GroupName"; + public const string PERMISSION_NAME = "PermissionName"; + public const string UPDATED_BY = "UpdatedBy"; + public const string UPDATED_DATETIME = "UpdatedDatetime"; + public const string VIEW_INDC = "ViewIndc"; + + public const string DB_NAME_SECURITY_GROUP_PERMISSION = "security_group_permission"; + public const string DB_NAME_FIELDS="amend_indc,create_indc,created_by,created_datetime,delete_indc,dependent,group_name,permission_name,updated_by,updated_datetime,view_indc"; + + public const string DB_AMEND_INDC = "amend_indc"; + public const string DB_CREATE_INDC = "create_indc"; + public const string DB_CREATED_BY = "created_by"; + public const string DB_CREATED_DATETIME = "created_datetime"; + public const string DB_DELETE_INDC = "delete_indc"; + public const string DB_DEPENDENT = "dependent"; + public const string DB_GROUP_NAME = "group_name"; + public const string DB_PERMISSION_NAME = "permission_name"; + public const string DB_UPDATED_BY = "updated_by"; + public const string DB_UPDATED_DATETIME = "updated_datetime"; + public const string DB_VIEW_INDC = "view_indc"; + + + public static SecurityGroupPermissionEntity GetInstance() + { + return new SecurityGroupPermissionEntity(); + } + + public virtual void CopyFrom(SecurityGroupPermissionEntity source) + { + CopyFrom(source, true); + } + + public virtual void CopyFrom(SecurityGroupPermissionEntity source, bool includeSystemFields) + { + if (source == null) + { + throw new NullReferenceException("Source entity is null."); + } + + this.AmendIndc = source.AmendIndc; + this.CreateIndc = source.CreateIndc; + this.CreatedBy = source.CreatedBy; + this.CreatedDatetime = source.CreatedDatetime; + this.DeleteIndc = source.DeleteIndc; + this.Dependent = source.Dependent; + this.GroupName = source.GroupName; + this.PermissionName = source.PermissionName; + this.UpdatedBy = source.UpdatedBy; + this.UpdatedDatetime = source.UpdatedDatetime; + this.ViewIndc = source.ViewIndc; + + if (includeSystemFields) + { + this.CreatedBy = source.CreatedBy; + this.CreatedDatetime = source.CreatedDatetime; + this.UpdatedBy = source.UpdatedBy; + this.UpdatedDatetime = source.UpdatedDatetime; + } + } + + public override string GetSelectFrom() + { + return $" select {DB_NAME_FIELDS} from { DB_NAME_SECURITY_GROUP_PERMISSION} "; + } + + public override string GetSelectCountFrom(string sqlWhere) + { + return $" select count(*) from { DB_NAME_SECURITY_GROUP_PERMISSION} where 1=1 {sqlWhere}"; + } + + public override string GetSelectTopFrom(int limit, int start,string orderby,string orderbytag, string sqlWhere) + { + if (string.IsNullOrEmpty(orderbytag) || orderbytag.Trim() != "desc") orderbytag = "asc"; + if (string.IsNullOrEmpty(orderby) || !DB_NAME_FIELDS.Contains(orderby)) orderby = DB_GROUP_NAME ; + int offset = limit * (start - 1); + return $" select {DB_NAME_FIELDS} from (select {DB_NAME_FIELDS} ,row_number() over(order by {orderby} {orderbytag}) as num from { DB_NAME_SECURITY_GROUP_PERMISSION} where 1=1 {sqlWhere} ) a where num> {offset} LIMIT {offset},{limit} "; + } + + public SecurityGroupPermissionEntity Clone() + { + SecurityGroupPermissionEntity result = new SecurityGroupPermissionEntity(); + result.CopyFrom(this); + + return result; + } + + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Entity/SecurityGroupPermissionEntityKey.auto.cs b/CloudBuilder/CloudBuilder.Security/Entity/SecurityGroupPermissionEntityKey.auto.cs new file mode 100644 index 0000000..77d7353 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Entity/SecurityGroupPermissionEntityKey.auto.cs @@ -0,0 +1,33 @@ + +using CloudBuilder.Core.Authorization; +namespace CloudBuilder.Security +{ + [TypeScript] + public class SecurityGroupPermissionEntityKey + { + public string GroupName { get; set; } + public string PermissionName { get; set; } + + public override bool Equals(object obj) + { + if (this == obj) return true; + + SecurityGroupPermissionEntityKey pkey = obj as SecurityGroupPermissionEntityKey; + if (pkey == null) return false; + + if (GroupName != pkey.GroupName) return false; + if (PermissionName != pkey.PermissionName) return false; + + return true; + } + + + public override string ToString() + { + string declareSql=""; + declareSql=declareSql+$"declare @__tkey_GroupName_0 varchar(50) select @__tkey_GroupName_0 ='{GroupName}'; " ; declareSql=declareSql+$"declare @__tkey_PermissionName_1 varchar(50) select @__tkey_PermissionName_1 ='{PermissionName}'; " ; + return declareSql; + } + } + } + /* builder.Entity().HasKey(c => new { c.GroupName, c.PermissionName}); */ diff --git a/CloudBuilder/CloudBuilder.Security/Entity/SecurityGroupPermissionViewEntity.auto.cs b/CloudBuilder/CloudBuilder.Security/Entity/SecurityGroupPermissionViewEntity.auto.cs new file mode 100644 index 0000000..23c885e --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Entity/SecurityGroupPermissionViewEntity.auto.cs @@ -0,0 +1,114 @@ + +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +namespace CloudBuilder.Security.Entity + { + [TypeScript] + [Table("security_group_permission_view")] + public class SecurityGroupPermissionViewEntity : ViewEntityBase + { + + public SecurityGroupPermissionViewEntity() + { + } + + [Column("amend_indc")] + public string AmendIndc { get; set; } + [Column("create_indc")] + public string CreateIndc { get; set; } + [Column("delete_indc")] + public string DeleteIndc { get; set; } + [Column("dependent")] + public string? Dependent { get; set; } + [Column("group_name")] + public string GroupName { get; set; } + [Column("permission_description")] + public string? PermissionDescription { get; set; } + [Column("permission_name")] + public string PermissionName { get; set; } + [Column("view_indc")] + public string ViewIndc { get; set; } + + public const string AMEND_INDC = "AmendIndc"; + public const string CREATE_INDC = "CreateIndc"; + public const string DELETE_INDC = "DeleteIndc"; + public const string DEPENDENT = "Dependent"; + public const string GROUP_NAME = "GroupName"; + public const string PERMISSION_DESCRIPTION = "PermissionDescription"; + public const string PERMISSION_NAME = "PermissionName"; + public const string VIEW_INDC = "ViewIndc"; + + public const string DB_NAME_SECURITY_GROUP_PERMISSION_VIEW = "security_group_permission_view"; + public const string DB_NAME_FIELDS="amend_indc,create_indc,delete_indc,dependent,group_name,permission_description,permission_name,view_indc"; + + public const string DB_AMEND_INDC = "amend_indc"; + public const string DB_CREATE_INDC = "create_indc"; + public const string DB_DELETE_INDC = "delete_indc"; + public const string DB_DEPENDENT = "dependent"; + public const string DB_GROUP_NAME = "group_name"; + public const string DB_PERMISSION_DESCRIPTION = "permission_description"; + public const string DB_PERMISSION_NAME = "permission_name"; + public const string DB_VIEW_INDC = "view_indc"; + + + public static SecurityGroupPermissionViewEntity GetInstance() + { + return new SecurityGroupPermissionViewEntity(); + } + + public virtual void CopyFrom(SecurityGroupPermissionViewEntity source) + { + CopyFrom(source, true); + } + + public virtual void CopyFrom(SecurityGroupPermissionViewEntity source, bool includeSystemFields) + { + if (source == null) + { + throw new NullReferenceException("Source entity is null."); + } + + this.AmendIndc = source.AmendIndc; + this.CreateIndc = source.CreateIndc; + this.DeleteIndc = source.DeleteIndc; + this.Dependent = source.Dependent; + this.GroupName = source.GroupName; + this.PermissionDescription = source.PermissionDescription; + this.PermissionName = source.PermissionName; + this.ViewIndc = source.ViewIndc; + + if (includeSystemFields) + { + } + } + + public override string GetSelectFrom() + { + return $" select {DB_NAME_FIELDS} from { DB_NAME_SECURITY_GROUP_PERMISSION_VIEW} "; + } + + public override string GetSelectCountFrom(string sqlWhere) + { + return $" select count(*) from { DB_NAME_SECURITY_GROUP_PERMISSION_VIEW} where 1=1 {sqlWhere}"; + } + + public override string GetSelectTopFrom(int limit, int start,string orderby,string orderbytag, string sqlWhere) + { + if (string.IsNullOrEmpty(orderbytag) || orderbytag.Trim() != "desc") orderbytag = "asc"; + + if (string.IsNullOrEmpty(orderby) || !DB_NAME_FIELDS.Contains(orderby)) orderby = DB_AMEND_INDC ; int offset = limit * (start - 1); + return $" select {DB_NAME_FIELDS} from (select {DB_NAME_FIELDS} ,row_number() over(order by {orderby} {orderbytag}) as num from { DB_NAME_SECURITY_GROUP_PERMISSION_VIEW} where 1=1 {sqlWhere} ) a where num> {offset} LIMIT {offset},{limit} "; + } + + public SecurityGroupPermissionViewEntity Clone() + { + SecurityGroupPermissionViewEntity result = new SecurityGroupPermissionViewEntity(); + result.CopyFrom(this); + + return result; + } + + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Entity/SecurityInitializerTickViewEntity.auto.cs b/CloudBuilder/CloudBuilder.Security/Entity/SecurityInitializerTickViewEntity.auto.cs new file mode 100644 index 0000000..3c55e33 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Entity/SecurityInitializerTickViewEntity.auto.cs @@ -0,0 +1,133 @@ +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +namespace CloudBuilder.Security.Entity + { + [TypeScript] + [Table("security_initializer_tick_view")] + public class SecurityInitializerTickViewEntity : ViewEntityBase + { + + public SecurityInitializerTickViewEntity() + { + } + + [Column("security_actor_upd")] + public Nullable SecurityActorUpd { get; set; } + [Column("security_actor_group_upd")] + public Nullable SecurityActorGroupUpd { get; set; } + [Column("security_function_upd")] + public Nullable SecurityFunctionUpd { get; set; } + [Column("security_function_map_upd")] + public Nullable SecurityFunctionMapUpd { get; set; } + [Column("product_upd")] + public Nullable ProductUpd { get; set; } + [Column("security_group_permission_upd")] + public Nullable SecurityGroupPermissionUpd { get; set; } + [Column("security_group_permission_dependent_upd")] + public Nullable SecurityGroupPermissionDependentUpd { get; set; } + [Column("security_master_upd")] + public Nullable SecurityMasterUpd { get; set; } + [Column("security_permission_upd")] + public Nullable SecurityPermissionUpd { get; set; } + [Column("security_permission_dependent_upd")] + public Nullable SecurityPermissionDependentUpd { get; set; } + [Column("security_user_upd")] + public Nullable SecurityUserUpd { get; set; } + [Column("security_user_actor_upd")] + public Nullable SecurityUserActorUpd { get; set; } + + public const string SECURITY_ACTOR_UPD = "SecurityActorUpd"; + public const string SECURITY_ACTOR_GROUP_UPD = "SecurityActorGroupUpd"; + public const string SECURITY_FUNCTION_UPD = "SecurityFunctionUpd"; + public const string SECURITY_FUNCTION_MAP_UPD = "SecurityFunctionMapUpd"; + public const string PRODUCT_UPD = "ProductUpd"; + public const string SECURITY_GROUP_PERMISSION_UPD = "SecurityGroupPermissionUpd"; + public const string SECURITY_GROUP_PERMISSION_DEPENDENT_UPD = "SecurityGroupPermissionDependentUpd"; + public const string SECURITY_MASTER_UPD = "SecurityMasterUpd"; + public const string SECURITY_PERMISSION_UPD = "SecurityPermissionUpd"; + public const string SECURITY_PERMISSION_DEPENDENT_UPD = "SecurityPermissionDependentUpd"; + public const string SECURITY_USER_UPD = "SecurityUserUpd"; + public const string SECURITY_USER_ACTOR_UPD = "SecurityUserActorUpd"; + + public const string DB_NAME_SECURITY_INITIALIZER_TICK_VIEW = "security_initializer_tick_view"; + public const string DB_NAME_FIELDS="security_actor_upd,security_actor_group_upd,security_function_upd,security_function_map_upd,product_upd,security_group_permission_upd,security_group_permission_dependent_upd,security_master_upd,security_permission_upd,security_permission_dependent_upd,security_user_upd,security_user_actor_upd"; + + public const string DB_SECURITY_ACTOR_UPD = "security_actor_upd"; + public const string DB_SECURITY_ACTOR_GROUP_UPD = "security_actor_group_upd"; + public const string DB_SECURITY_FUNCTION_UPD = "security_function_upd"; + public const string DB_SECURITY_FUNCTION_MAP_UPD = "security_function_map_upd"; + public const string DB_PRODUCT_UPD = "product_upd"; + public const string DB_SECURITY_GROUP_PERMISSION_UPD = "security_group_permission_upd"; + public const string DB_SECURITY_GROUP_PERMISSION_DEPENDENT_UPD = "security_group_permission_dependent_upd"; + public const string DB_SECURITY_MASTER_UPD = "security_master_upd"; + public const string DB_SECURITY_PERMISSION_UPD = "security_permission_upd"; + public const string DB_SECURITY_PERMISSION_DEPENDENT_UPD = "security_permission_dependent_upd"; + public const string DB_SECURITY_USER_UPD = "security_user_upd"; + public const string DB_SECURITY_USER_ACTOR_UPD = "security_user_actor_upd"; + + + public static SecurityInitializerTickViewEntity GetInstance() + { + return new SecurityInitializerTickViewEntity(); + } + + public virtual void CopyFrom(SecurityInitializerTickViewEntity source) + { + CopyFrom(source, true); + } + + public virtual void CopyFrom(SecurityInitializerTickViewEntity source, bool includeSystemFields) + { + if (source == null) + { + throw new NullReferenceException("Source entity is null."); + } + + this.SecurityActorUpd = source.SecurityActorUpd; + this.SecurityActorGroupUpd = source.SecurityActorGroupUpd; + this.SecurityFunctionUpd = source.SecurityFunctionUpd; + this.SecurityFunctionMapUpd = source.SecurityFunctionMapUpd; + this.ProductUpd = source.ProductUpd; + this.SecurityGroupPermissionUpd = source.SecurityGroupPermissionUpd; + this.SecurityGroupPermissionDependentUpd = source.SecurityGroupPermissionDependentUpd; + this.SecurityMasterUpd = source.SecurityMasterUpd; + this.SecurityPermissionUpd = source.SecurityPermissionUpd; + this.SecurityPermissionDependentUpd = source.SecurityPermissionDependentUpd; + this.SecurityUserUpd = source.SecurityUserUpd; + this.SecurityUserActorUpd = source.SecurityUserActorUpd; + + if (includeSystemFields) + { + } + } + + public override string GetSelectFrom() + { + return $" select {DB_NAME_FIELDS} from { DB_NAME_SECURITY_INITIALIZER_TICK_VIEW} "; + } + + public override string GetSelectCountFrom(string sqlWhere) + { + return $" select count(*) from { DB_NAME_SECURITY_INITIALIZER_TICK_VIEW} where 1=1 {sqlWhere}"; + } + + public override string GetSelectTopFrom(int limit, int start,string orderby,string orderbytag, string sqlWhere) + { + if (string.IsNullOrEmpty(orderbytag) || orderbytag.Trim() != "desc") orderbytag = "asc"; + + if (string.IsNullOrEmpty(orderby) || !DB_NAME_FIELDS.Contains(orderby)) orderby = DB_SECURITY_ACTOR_UPD ; string top = limit > 0 ? $"top {limit}" : ""; + return $" select {top} {DB_NAME_FIELDS} from (select {DB_NAME_FIELDS} ,row_number() over(order by {orderby} {orderbytag}) as num from { DB_NAME_SECURITY_INITIALIZER_TICK_VIEW} where 1=1 {sqlWhere} ) a where num> {limit * (start - 1)}"; + } + + public SecurityInitializerTickViewEntity Clone() + { + SecurityInitializerTickViewEntity result = new SecurityInitializerTickViewEntity(); + result.CopyFrom(this); + + return result; + } + + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Entity/SecurityLockEntity.auto.cs b/CloudBuilder/CloudBuilder.Security/Entity/SecurityLockEntity.auto.cs new file mode 100644 index 0000000..e0a0622 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Entity/SecurityLockEntity.auto.cs @@ -0,0 +1,113 @@ + +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +namespace CloudBuilder.Security.Entity + { + [TypeScript] + [Table("security_lock")] + public class SecurityLockEntity : EntityBase + { + + public SecurityLockEntity() + { + } + + [Column("created_by")] + public string CreatedBy { get; set; } + [Column("created_datetime")] + public DateTime CreatedDatetime { get; set; } + [Column("entity_name")] + public string EntityName { get; set; } + [Column("locked_by_actor")] + public string LockedByActor { get; set; } + [Column("pkey_id")] + public string PkeyId { get; set; } + [Column("updated_by")] + public string UpdatedBy { get; set; } + [Column("updated_datetime")] + public DateTime UpdatedDatetime { get; set; } + + public const string CREATED_BY = "CreatedBy"; + public const string CREATED_DATETIME = "CreatedDatetime"; + public const string ENTITY_NAME = "EntityName"; + public const string LOCKED_BY_ACTOR = "LockedByActor"; + public const string PKEY_ID = "PkeyId"; + public const string UPDATED_BY = "UpdatedBy"; + public const string UPDATED_DATETIME = "UpdatedDatetime"; + + public const string DB_NAME_SECURITY_LOCK = "security_lock"; + public const string DB_NAME_FIELDS="created_by,created_datetime,entity_name,locked_by_actor,pkey_id,updated_by,updated_datetime"; + + public const string DB_CREATED_BY = "created_by"; + public const string DB_CREATED_DATETIME = "created_datetime"; + public const string DB_ENTITY_NAME = "entity_name"; + public const string DB_LOCKED_BY_ACTOR = "locked_by_actor"; + public const string DB_PKEY_ID = "pkey_id"; + public const string DB_UPDATED_BY = "updated_by"; + public const string DB_UPDATED_DATETIME = "updated_datetime"; + + + public static SecurityLockEntity GetInstance() + { + return new SecurityLockEntity(); + } + + public virtual void CopyFrom(SecurityLockEntity source) + { + CopyFrom(source, true); + } + + public virtual void CopyFrom(SecurityLockEntity source, bool includeSystemFields) + { + if (source == null) + { + throw new NullReferenceException("Source entity is null."); + } + + this.CreatedBy = source.CreatedBy; + this.CreatedDatetime = source.CreatedDatetime; + this.EntityName = source.EntityName; + this.LockedByActor = source.LockedByActor; + this.PkeyId = source.PkeyId; + this.UpdatedBy = source.UpdatedBy; + this.UpdatedDatetime = source.UpdatedDatetime; + + if (includeSystemFields) + { + this.CreatedBy = source.CreatedBy; + this.CreatedDatetime = source.CreatedDatetime; + this.UpdatedBy = source.UpdatedBy; + this.UpdatedDatetime = source.UpdatedDatetime; + } + } + + public override string GetSelectFrom() + { + return $" select {DB_NAME_FIELDS} from { DB_NAME_SECURITY_LOCK} "; + } + + public override string GetSelectCountFrom(string sqlWhere) + { + return $" select count(*) from { DB_NAME_SECURITY_LOCK} where 1=1 {sqlWhere}"; + } + + public override string GetSelectTopFrom(int limit, int start,string orderby,string orderbytag, string sqlWhere) + { + if (string.IsNullOrEmpty(orderbytag) || orderbytag.Trim() != "desc") orderbytag = "asc"; + if (string.IsNullOrEmpty(orderby) || !DB_NAME_FIELDS.Contains(orderby)) orderby = DB_ENTITY_NAME ; + int offset = limit * (start - 1); + return $" select {DB_NAME_FIELDS} from (select {DB_NAME_FIELDS} ,row_number() over(order by {orderby} {orderbytag}) as num from { DB_NAME_SECURITY_LOCK} where 1=1 {sqlWhere} ) a where num> {offset} LIMIT {offset},{limit} "; + } + + public SecurityLockEntity Clone() + { + SecurityLockEntity result = new SecurityLockEntity(); + result.CopyFrom(this); + + return result; + } + + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Entity/SecurityLockEntityKey.auto.cs b/CloudBuilder/CloudBuilder.Security/Entity/SecurityLockEntityKey.auto.cs new file mode 100644 index 0000000..324f3dc --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Entity/SecurityLockEntityKey.auto.cs @@ -0,0 +1,35 @@ + +using CloudBuilder.Core.Authorization; +namespace CloudBuilder.Security +{ + [TypeScript] + public class SecurityLockEntityKey + { + public string EntityName { get; set; } + public string LockedByActor { get; set; } + public string PkeyId { get; set; } + + public override bool Equals(object obj) + { + if (this == obj) return true; + + SecurityLockEntityKey pkey = obj as SecurityLockEntityKey; + if (pkey == null) return false; + + if (EntityName != pkey.EntityName) return false; + if (LockedByActor != pkey.LockedByActor) return false; + if (PkeyId != pkey.PkeyId) return false; + + return true; + } + + + public override string ToString() + { + string declareSql=""; + declareSql=declareSql+$"declare @__tkey_EntityName_0 varchar(50) select @__tkey_EntityName_0 ='{EntityName}'; " ; declareSql=declareSql+$"declare @__tkey_LockedByActor_1 varchar(50) select @__tkey_LockedByActor_1 ='{LockedByActor}'; " ; declareSql=declareSql+$"declare @__tkey_PkeyId_2 varchar(50) select @__tkey_PkeyId_2 ='{PkeyId}'; " ; + return declareSql; + } + } + } + /* builder.Entity().HasKey(c => new { c.EntityName, c.LockedByActor, c.PkeyId}); */ diff --git a/CloudBuilder/CloudBuilder.Security/Entity/SecurityMasterEntity.auto.cs b/CloudBuilder/CloudBuilder.Security/Entity/SecurityMasterEntity.auto.cs new file mode 100644 index 0000000..c2e5e70 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Entity/SecurityMasterEntity.auto.cs @@ -0,0 +1,143 @@ + +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +namespace CloudBuilder.Security.Entity + { + [TypeScript] + [Table("security_master")] + public class SecurityMasterEntity : EntityBase + { + + public SecurityMasterEntity() + { + } + + [Column("created_by")] + public string CreatedBy { get; set; } + [Column("created_datetime")] + public DateTime CreatedDatetime { get; set; } + [Column("eng_description")] + public string? EngDescription { get; set; } + [Column("local_description")] + public string? LocalDescription { get; set; } + [Column("master_category")] + public string MasterCategory { get; set; } + [Column("master_code_item")] + public string MasterCodeItem { get; set; } + [Column("master_subcategory")] + public string MasterSubcategory { get; set; } + [Column("order_by")] + public int OrderBy { get; set; } + [Column("remark")] + public string? Remark { get; set; } + [Column("updated_by")] + public string UpdatedBy { get; set; } + [Column("updated_datetime")] + public DateTime UpdatedDatetime { get; set; } + [Column("valid_indc")] + public string ValidIndc { get; set; } + [Column("value")] + public string Value { get; set; } + + public const string CREATED_BY = "CreatedBy"; + public const string CREATED_DATETIME = "CreatedDatetime"; + public const string ENG_DESCRIPTION = "EngDescription"; + public const string LOCAL_DESCRIPTION = "LocalDescription"; + public const string MASTER_CATEGORY = "MasterCategory"; + public const string MASTER_CODE_ITEM = "MasterCodeItem"; + public const string MASTER_SUBCATEGORY = "MasterSubcategory"; + public const string ORDER_BY = "OrderBy"; + public const string REMARK = "Remark"; + public const string UPDATED_BY = "UpdatedBy"; + public const string UPDATED_DATETIME = "UpdatedDatetime"; + public const string VALID_INDC = "ValidIndc"; + public const string VALUE = "Value"; + + public const string DB_NAME_SECURITY_MASTER = "security_master"; + public const string DB_NAME_FIELDS="created_by,created_datetime,eng_description,local_description,master_category,master_code_item,master_subcategory,order_by,remark,updated_by,updated_datetime,valid_indc,value"; + + public const string DB_CREATED_BY = "created_by"; + public const string DB_CREATED_DATETIME = "created_datetime"; + public const string DB_ENG_DESCRIPTION = "eng_description"; + public const string DB_LOCAL_DESCRIPTION = "local_description"; + public const string DB_MASTER_CATEGORY = "master_category"; + public const string DB_MASTER_CODE_ITEM = "master_code_item"; + public const string DB_MASTER_SUBCATEGORY = "master_subcategory"; + public const string DB_ORDER_BY = "order_by"; + public const string DB_REMARK = "remark"; + public const string DB_UPDATED_BY = "updated_by"; + public const string DB_UPDATED_DATETIME = "updated_datetime"; + public const string DB_VALID_INDC = "valid_indc"; + public const string DB_VALUE = "value"; + + + public static SecurityMasterEntity GetInstance() + { + return new SecurityMasterEntity(); + } + + public virtual void CopyFrom(SecurityMasterEntity source) + { + CopyFrom(source, true); + } + + public virtual void CopyFrom(SecurityMasterEntity source, bool includeSystemFields) + { + if (source == null) + { + throw new NullReferenceException("Source entity is null."); + } + + this.CreatedBy = source.CreatedBy; + this.CreatedDatetime = source.CreatedDatetime; + this.EngDescription = source.EngDescription; + this.LocalDescription = source.LocalDescription; + this.MasterCategory = source.MasterCategory; + this.MasterCodeItem = source.MasterCodeItem; + this.MasterSubcategory = source.MasterSubcategory; + this.OrderBy = source.OrderBy; + this.Remark = source.Remark; + this.UpdatedBy = source.UpdatedBy; + this.UpdatedDatetime = source.UpdatedDatetime; + this.ValidIndc = source.ValidIndc; + this.Value = source.Value; + + if (includeSystemFields) + { + this.CreatedBy = source.CreatedBy; + this.CreatedDatetime = source.CreatedDatetime; + this.UpdatedBy = source.UpdatedBy; + this.UpdatedDatetime = source.UpdatedDatetime; + } + } + + public override string GetSelectFrom() + { + return $" select {DB_NAME_FIELDS} from { DB_NAME_SECURITY_MASTER} "; + } + + public override string GetSelectCountFrom(string sqlWhere) + { + return $" select count(*) from { DB_NAME_SECURITY_MASTER} where 1=1 {sqlWhere}"; + } + + public override string GetSelectTopFrom(int limit, int start,string orderby,string orderbytag, string sqlWhere) + { + if (string.IsNullOrEmpty(orderbytag) || orderbytag.Trim() != "desc") orderbytag = "asc"; + if (string.IsNullOrEmpty(orderby) || !DB_NAME_FIELDS.Contains(orderby)) orderby = DB_MASTER_CATEGORY ; + int offset = limit * (start - 1); + return $" select {DB_NAME_FIELDS} from (select {DB_NAME_FIELDS} ,row_number() over(order by {orderby} {orderbytag}) as num from { DB_NAME_SECURITY_MASTER} where 1=1 {sqlWhere} ) a where num> {offset} LIMIT {offset},{limit} "; + } + + public SecurityMasterEntity Clone() + { + SecurityMasterEntity result = new SecurityMasterEntity(); + result.CopyFrom(this); + + return result; + } + + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Entity/SecurityMasterEntityKey.auto.cs b/CloudBuilder/CloudBuilder.Security/Entity/SecurityMasterEntityKey.auto.cs new file mode 100644 index 0000000..4c23beb --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Entity/SecurityMasterEntityKey.auto.cs @@ -0,0 +1,35 @@ + +using CloudBuilder.Core.Authorization; +namespace CloudBuilder.Security +{ + [TypeScript] + public class SecurityMasterEntityKey + { + public string MasterCategory { get; set; } + public string MasterCodeItem { get; set; } + public string MasterSubcategory { get; set; } + + public override bool Equals(object obj) + { + if (this == obj) return true; + + SecurityMasterEntityKey pkey = obj as SecurityMasterEntityKey; + if (pkey == null) return false; + + if (MasterCategory != pkey.MasterCategory) return false; + if (MasterCodeItem != pkey.MasterCodeItem) return false; + if (MasterSubcategory != pkey.MasterSubcategory) return false; + + return true; + } + + + public override string ToString() + { + string declareSql=""; + declareSql=declareSql+$"declare @__tkey_MasterCategory_0 varchar(50) select @__tkey_MasterCategory_0 ='{MasterCategory}'; " ; declareSql=declareSql+$"declare @__tkey_MasterCodeItem_1 varchar(50) select @__tkey_MasterCodeItem_1 ='{MasterCodeItem}'; " ; declareSql=declareSql+$"declare @__tkey_MasterSubcategory_2 varchar(50) select @__tkey_MasterSubcategory_2 ='{MasterSubcategory}'; " ; + return declareSql; + } + } + } + /* builder.Entity().HasKey(c => new { c.MasterCategory, c.MasterCodeItem, c.MasterSubcategory}); */ diff --git a/CloudBuilder/CloudBuilder.Security/Entity/SecurityPermissionDependentEntity.auto.cs b/CloudBuilder/CloudBuilder.Security/Entity/SecurityPermissionDependentEntity.auto.cs new file mode 100644 index 0000000..c39249b --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Entity/SecurityPermissionDependentEntity.auto.cs @@ -0,0 +1,118 @@ + +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +namespace CloudBuilder.Security.Entity + { + [TypeScript] + [Table("security_permission_dependent")] + public class SecurityPermissionDependentEntity : EntityBase + { + + public SecurityPermissionDependentEntity() + { + } + + [Column("created_by")] + public string CreatedBy { get; set; } + [Column("created_datetime")] + public DateTime CreatedDatetime { get; set; } + [Column("dependent")] + public string Dependent { get; set; } + [Column("dependent_detail_description")] + public string? DependentDetailDescription { get; set; } + [Column("dependent_detail_name")] + public string DependentDetailName { get; set; } + [Column("permission_name")] + public string PermissionName { get; set; } + [Column("updated_by")] + public string UpdatedBy { get; set; } + [Column("updated_datetime")] + public DateTime UpdatedDatetime { get; set; } + + public const string CREATED_BY = "CreatedBy"; + public const string CREATED_DATETIME = "CreatedDatetime"; + public const string DEPENDENT = "Dependent"; + public const string DEPENDENT_DETAIL_DESCRIPTION = "DependentDetailDescription"; + public const string DEPENDENT_DETAIL_NAME = "DependentDetailName"; + public const string PERMISSION_NAME = "PermissionName"; + public const string UPDATED_BY = "UpdatedBy"; + public const string UPDATED_DATETIME = "UpdatedDatetime"; + + public const string DB_NAME_SECURITY_PERMISSION_DEPENDENT = "security_permission_dependent"; + public const string DB_NAME_FIELDS="created_by,created_datetime,dependent,dependent_detail_description,dependent_detail_name,permission_name,updated_by,updated_datetime"; + + public const string DB_CREATED_BY = "created_by"; + public const string DB_CREATED_DATETIME = "created_datetime"; + public const string DB_DEPENDENT = "dependent"; + public const string DB_DEPENDENT_DETAIL_DESCRIPTION = "dependent_detail_description"; + public const string DB_DEPENDENT_DETAIL_NAME = "dependent_detail_name"; + public const string DB_PERMISSION_NAME = "permission_name"; + public const string DB_UPDATED_BY = "updated_by"; + public const string DB_UPDATED_DATETIME = "updated_datetime"; + + + public static SecurityPermissionDependentEntity GetInstance() + { + return new SecurityPermissionDependentEntity(); + } + + public virtual void CopyFrom(SecurityPermissionDependentEntity source) + { + CopyFrom(source, true); + } + + public virtual void CopyFrom(SecurityPermissionDependentEntity source, bool includeSystemFields) + { + if (source == null) + { + throw new NullReferenceException("Source entity is null."); + } + + this.CreatedBy = source.CreatedBy; + this.CreatedDatetime = source.CreatedDatetime; + this.Dependent = source.Dependent; + this.DependentDetailDescription = source.DependentDetailDescription; + this.DependentDetailName = source.DependentDetailName; + this.PermissionName = source.PermissionName; + this.UpdatedBy = source.UpdatedBy; + this.UpdatedDatetime = source.UpdatedDatetime; + + if (includeSystemFields) + { + this.CreatedBy = source.CreatedBy; + this.CreatedDatetime = source.CreatedDatetime; + this.UpdatedBy = source.UpdatedBy; + this.UpdatedDatetime = source.UpdatedDatetime; + } + } + + public override string GetSelectFrom() + { + return $" select {DB_NAME_FIELDS} from { DB_NAME_SECURITY_PERMISSION_DEPENDENT} "; + } + + public override string GetSelectCountFrom(string sqlWhere) + { + return $" select count(*) from { DB_NAME_SECURITY_PERMISSION_DEPENDENT} where 1=1 {sqlWhere}"; + } + + public override string GetSelectTopFrom(int limit, int start,string orderby,string orderbytag, string sqlWhere) + { + if (string.IsNullOrEmpty(orderbytag) || orderbytag.Trim() != "desc") orderbytag = "asc"; + if (string.IsNullOrEmpty(orderby) || !DB_NAME_FIELDS.Contains(orderby)) orderby = DB_DEPENDENT_DETAIL_NAME ; + int offset = limit * (start - 1); + return $" select {DB_NAME_FIELDS} from (select {DB_NAME_FIELDS} ,row_number() over(order by {orderby} {orderbytag}) as num from { DB_NAME_SECURITY_PERMISSION_DEPENDENT} where 1=1 {sqlWhere} ) a where num> {offset} LIMIT {offset},{limit} "; + } + + public SecurityPermissionDependentEntity Clone() + { + SecurityPermissionDependentEntity result = new SecurityPermissionDependentEntity(); + result.CopyFrom(this); + + return result; + } + + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Entity/SecurityPermissionDependentEntityKey.auto.cs b/CloudBuilder/CloudBuilder.Security/Entity/SecurityPermissionDependentEntityKey.auto.cs new file mode 100644 index 0000000..20260b0 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Entity/SecurityPermissionDependentEntityKey.auto.cs @@ -0,0 +1,33 @@ + +using CloudBuilder.Core.Authorization; +namespace CloudBuilder.Security +{ + [TypeScript] + public class SecurityPermissionDependentEntityKey + { + public string DependentDetailName { get; set; } + public string PermissionName { get; set; } + + public override bool Equals(object obj) + { + if (this == obj) return true; + + SecurityPermissionDependentEntityKey pkey = obj as SecurityPermissionDependentEntityKey; + if (pkey == null) return false; + + if (DependentDetailName != pkey.DependentDetailName) return false; + if (PermissionName != pkey.PermissionName) return false; + + return true; + } + + + public override string ToString() + { + string declareSql=""; + declareSql=declareSql+$"declare @__tkey_DependentDetailName_0 varchar(50) select @__tkey_DependentDetailName_0 ='{DependentDetailName}'; " ; declareSql=declareSql+$"declare @__tkey_PermissionName_1 varchar(50) select @__tkey_PermissionName_1 ='{PermissionName}'; " ; + return declareSql; + } + } + } + /* builder.Entity().HasKey(c => new { c.DependentDetailName, c.PermissionName}); */ diff --git a/CloudBuilder/CloudBuilder.Security/Entity/SecurityPermissionEntity.auto.cs b/CloudBuilder/CloudBuilder.Security/Entity/SecurityPermissionEntity.auto.cs new file mode 100644 index 0000000..6cdb7b6 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Entity/SecurityPermissionEntity.auto.cs @@ -0,0 +1,119 @@ + +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +namespace CloudBuilder.Security.Entity + { + [TypeScript] + [Table("security_permission")] + public class SecurityPermissionEntity : ViewEntityBase + { + + public SecurityPermissionEntity() + { + } + + [Column("created_by")] + public string CreatedBy { get; set; } + [Column("created_datetime")] + public DateTime CreatedDatetime { get; set; } + [Column("delegate_indc")] + public string DelegateIndc { get; set; } + [Column("dependent")] + public string? Dependent { get; set; } + [Column("description")] + public string? Description { get; set; } + [Key] + [Column("permission_name")] + public string PermissionName { get; set; } + [Column("updated_by")] + public string UpdatedBy { get; set; } + [Column("updated_datetime")] + public DateTime UpdatedDatetime { get; set; } + + public const string CREATED_BY = "CreatedBy"; + public const string CREATED_DATETIME = "CreatedDatetime"; + public const string DELEGATE_INDC = "DelegateIndc"; + public const string DEPENDENT = "Dependent"; + public const string DESCRIPTION = "Description"; + public const string PERMISSION_NAME = "PermissionName"; + public const string UPDATED_BY = "UpdatedBy"; + public const string UPDATED_DATETIME = "UpdatedDatetime"; + + public const string DB_NAME_SECURITY_PERMISSION = "security_permission"; + public const string DB_NAME_FIELDS="created_by,created_datetime,delegate_indc,dependent,description,permission_name,updated_by,updated_datetime"; + + public const string DB_CREATED_BY = "created_by"; + public const string DB_CREATED_DATETIME = "created_datetime"; + public const string DB_DELEGATE_INDC = "delegate_indc"; + public const string DB_DEPENDENT = "dependent"; + public const string DB_DESCRIPTION = "description"; + public const string DB_PERMISSION_NAME = "permission_name"; + public const string DB_UPDATED_BY = "updated_by"; + public const string DB_UPDATED_DATETIME = "updated_datetime"; + + + public static SecurityPermissionEntity GetInstance() + { + return new SecurityPermissionEntity(); + } + + public virtual void CopyFrom(SecurityPermissionEntity source) + { + CopyFrom(source, true); + } + + public virtual void CopyFrom(SecurityPermissionEntity source, bool includeSystemFields) + { + if (source == null) + { + throw new NullReferenceException("Source entity is null."); + } + + this.CreatedBy = source.CreatedBy; + this.CreatedDatetime = source.CreatedDatetime; + this.DelegateIndc = source.DelegateIndc; + this.Dependent = source.Dependent; + this.Description = source.Description; + this.PermissionName = source.PermissionName; + this.UpdatedBy = source.UpdatedBy; + this.UpdatedDatetime = source.UpdatedDatetime; + + if (includeSystemFields) + { + this.CreatedBy = source.CreatedBy; + this.CreatedDatetime = source.CreatedDatetime; + this.UpdatedBy = source.UpdatedBy; + this.UpdatedDatetime = source.UpdatedDatetime; + } + } + + public override string GetSelectFrom() + { + return $" select {DB_NAME_FIELDS} from { DB_NAME_SECURITY_PERMISSION} "; + } + + public override string GetSelectCountFrom(string sqlWhere) + { + return $" select count(*) from { DB_NAME_SECURITY_PERMISSION} where 1=1 {sqlWhere}"; + } + + public override string GetSelectTopFrom(int limit, int start,string orderby,string orderbytag, string sqlWhere) + { + if (string.IsNullOrEmpty(orderbytag) || orderbytag.Trim() != "desc") orderbytag = "asc"; + if (string.IsNullOrEmpty(orderby) || !DB_NAME_FIELDS.Contains(orderby)) orderby = DB_PERMISSION_NAME ; + int offset = limit * (start - 1); + return $" select {DB_NAME_FIELDS} from (select {DB_NAME_FIELDS} ,row_number() over(order by {orderby} {orderbytag}) as num from { DB_NAME_SECURITY_PERMISSION} where 1=1 {sqlWhere} ) a where num> {offset} LIMIT {offset},{limit} "; + } + + public SecurityPermissionEntity Clone() + { + SecurityPermissionEntity result = new SecurityPermissionEntity(); + result.CopyFrom(this); + + return result; + } + + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Entity/SecurityPermissionFunctionMapEntity.auto.cs b/CloudBuilder/CloudBuilder.Security/Entity/SecurityPermissionFunctionMapEntity.auto.cs new file mode 100644 index 0000000..6e17207 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Entity/SecurityPermissionFunctionMapEntity.auto.cs @@ -0,0 +1,108 @@ + +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +namespace CloudBuilder.Security.Entity + { + [TypeScript] + [Table("security_permission_function_map")] + public class SecurityPermissionFunctionMapEntity : EntityBase + { + + public SecurityPermissionFunctionMapEntity() + { + } + + [Column("created_by")] + public string CreatedBy { get; set; } + [Column("created_datetime")] + public DateTime CreatedDatetime { get; set; } + [Column("function_name")] + public string FunctionName { get; set; } + [Column("permission_name")] + public string PermissionName { get; set; } + [Column("updated_by")] + public string UpdatedBy { get; set; } + [Column("updated_datetime")] + public DateTime UpdatedDatetime { get; set; } + + public const string CREATED_BY = "CreatedBy"; + public const string CREATED_DATETIME = "CreatedDatetime"; + public const string FUNCTION_NAME = "FunctionName"; + public const string PERMISSION_NAME = "PermissionName"; + public const string UPDATED_BY = "UpdatedBy"; + public const string UPDATED_DATETIME = "UpdatedDatetime"; + + public const string DB_NAME_SECURITY_PERMISSION_FUNCTION_MAP = "security_permission_function_map"; + public const string DB_NAME_FIELDS="created_by,created_datetime,function_name,permission_name,updated_by,updated_datetime"; + + public const string DB_CREATED_BY = "created_by"; + public const string DB_CREATED_DATETIME = "created_datetime"; + public const string DB_FUNCTION_NAME = "function_name"; + public const string DB_PERMISSION_NAME = "permission_name"; + public const string DB_UPDATED_BY = "updated_by"; + public const string DB_UPDATED_DATETIME = "updated_datetime"; + + + public static SecurityPermissionFunctionMapEntity GetInstance() + { + return new SecurityPermissionFunctionMapEntity(); + } + + public virtual void CopyFrom(SecurityPermissionFunctionMapEntity source) + { + CopyFrom(source, true); + } + + public virtual void CopyFrom(SecurityPermissionFunctionMapEntity source, bool includeSystemFields) + { + if (source == null) + { + throw new NullReferenceException("Source entity is null."); + } + + this.CreatedBy = source.CreatedBy; + this.CreatedDatetime = source.CreatedDatetime; + this.FunctionName = source.FunctionName; + this.PermissionName = source.PermissionName; + this.UpdatedBy = source.UpdatedBy; + this.UpdatedDatetime = source.UpdatedDatetime; + + if (includeSystemFields) + { + this.CreatedBy = source.CreatedBy; + this.CreatedDatetime = source.CreatedDatetime; + this.UpdatedBy = source.UpdatedBy; + this.UpdatedDatetime = source.UpdatedDatetime; + } + } + + public override string GetSelectFrom() + { + return $" select {DB_NAME_FIELDS} from { DB_NAME_SECURITY_PERMISSION_FUNCTION_MAP} "; + } + + public override string GetSelectCountFrom(string sqlWhere) + { + return $" select count(*) from { DB_NAME_SECURITY_PERMISSION_FUNCTION_MAP} where 1=1 {sqlWhere}"; + } + + public override string GetSelectTopFrom(int limit, int start,string orderby,string orderbytag, string sqlWhere) + { + if (string.IsNullOrEmpty(orderbytag) || orderbytag.Trim() != "desc") orderbytag = "asc"; + if (string.IsNullOrEmpty(orderby) || !DB_NAME_FIELDS.Contains(orderby)) orderby = DB_FUNCTION_NAME ; + int offset = limit * (start - 1); + return $" select {DB_NAME_FIELDS} from (select {DB_NAME_FIELDS} ,row_number() over(order by {orderby} {orderbytag}) as num from { DB_NAME_SECURITY_PERMISSION_FUNCTION_MAP} where 1=1 {sqlWhere} ) a where num> {offset} LIMIT {offset},{limit} "; + } + + public SecurityPermissionFunctionMapEntity Clone() + { + SecurityPermissionFunctionMapEntity result = new SecurityPermissionFunctionMapEntity(); + result.CopyFrom(this); + + return result; + } + + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Entity/SecurityPermissionFunctionMapEntityKey.auto.cs b/CloudBuilder/CloudBuilder.Security/Entity/SecurityPermissionFunctionMapEntityKey.auto.cs new file mode 100644 index 0000000..23b3e86 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Entity/SecurityPermissionFunctionMapEntityKey.auto.cs @@ -0,0 +1,33 @@ + +using CloudBuilder.Core.Authorization; +namespace CloudBuilder.Security +{ + [TypeScript] + public class SecurityPermissionFunctionMapEntityKey + { + public string FunctionName { get; set; } + public string PermissionName { get; set; } + + public override bool Equals(object obj) + { + if (this == obj) return true; + + SecurityPermissionFunctionMapEntityKey pkey = obj as SecurityPermissionFunctionMapEntityKey; + if (pkey == null) return false; + + if (FunctionName != pkey.FunctionName) return false; + if (PermissionName != pkey.PermissionName) return false; + + return true; + } + + + public override string ToString() + { + string declareSql=""; + declareSql=declareSql+$"declare @__tkey_FunctionName_0 varchar(50) select @__tkey_FunctionName_0 ='{FunctionName}'; " ; declareSql=declareSql+$"declare @__tkey_PermissionName_1 varchar(50) select @__tkey_PermissionName_1 ='{PermissionName}'; " ; + return declareSql; + } + } + } + /* builder.Entity().HasKey(c => new { c.FunctionName, c.PermissionName}); */ diff --git a/CloudBuilder/CloudBuilder.Security/Entity/SecurityPermissionFunctionMapViewEntity.auto.cs b/CloudBuilder/CloudBuilder.Security/Entity/SecurityPermissionFunctionMapViewEntity.auto.cs new file mode 100644 index 0000000..94d6475 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Entity/SecurityPermissionFunctionMapViewEntity.auto.cs @@ -0,0 +1,89 @@ + +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +namespace CloudBuilder.Security.Entity + { + [TypeScript] + [Table("security_permission_function_map_view")] + public class SecurityPermissionFunctionMapViewEntity : ViewEntityBase + { + + public SecurityPermissionFunctionMapViewEntity() + { + } + + [Column("function_name")] + public string FunctionName { get; set; } + [Column("page_name")] + public string? PageName { get; set; } + [Column("permission_name")] + public string PermissionName { get; set; } + + public const string FUNCTION_NAME = "FunctionName"; + public const string PAGE_NAME = "PageName"; + public const string PERMISSION_NAME = "PermissionName"; + + public const string DB_NAME_SECURITY_PERMISSION_FUNCTION_MAP_VIEW = "security_permission_function_map_view"; + public const string DB_NAME_FIELDS="function_name,page_name,permission_name"; + + public const string DB_FUNCTION_NAME = "function_name"; + public const string DB_PAGE_NAME = "page_name"; + public const string DB_PERMISSION_NAME = "permission_name"; + + + public static SecurityPermissionFunctionMapViewEntity GetInstance() + { + return new SecurityPermissionFunctionMapViewEntity(); + } + + public virtual void CopyFrom(SecurityPermissionFunctionMapViewEntity source) + { + CopyFrom(source, true); + } + + public virtual void CopyFrom(SecurityPermissionFunctionMapViewEntity source, bool includeSystemFields) + { + if (source == null) + { + throw new NullReferenceException("Source entity is null."); + } + + this.FunctionName = source.FunctionName; + this.PageName = source.PageName; + this.PermissionName = source.PermissionName; + + if (includeSystemFields) + { + } + } + + public override string GetSelectFrom() + { + return $" select {DB_NAME_FIELDS} from { DB_NAME_SECURITY_PERMISSION_FUNCTION_MAP_VIEW} "; + } + + public override string GetSelectCountFrom(string sqlWhere) + { + return $" select count(*) from { DB_NAME_SECURITY_PERMISSION_FUNCTION_MAP_VIEW} where 1=1 {sqlWhere}"; + } + + public override string GetSelectTopFrom(int limit, int start,string orderby,string orderbytag, string sqlWhere) + { + if (string.IsNullOrEmpty(orderbytag) || orderbytag.Trim() != "desc") orderbytag = "asc"; + + if (string.IsNullOrEmpty(orderby) || !DB_NAME_FIELDS.Contains(orderby)) orderby = DB_FUNCTION_NAME ; int offset = limit * (start - 1); + return $" select {DB_NAME_FIELDS} from (select {DB_NAME_FIELDS} ,row_number() over(order by {orderby} {orderbytag}) as num from { DB_NAME_SECURITY_PERMISSION_FUNCTION_MAP_VIEW} where 1=1 {sqlWhere} ) a where num> {offset} LIMIT {offset},{limit} "; + } + + public SecurityPermissionFunctionMapViewEntity Clone() + { + SecurityPermissionFunctionMapViewEntity result = new SecurityPermissionFunctionMapViewEntity(); + result.CopyFrom(this); + + return result; + } + + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Entity/SecurityPermissionViewEntity.auto.cs b/CloudBuilder/CloudBuilder.Security/Entity/SecurityPermissionViewEntity.auto.cs new file mode 100644 index 0000000..0d5f057 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Entity/SecurityPermissionViewEntity.auto.cs @@ -0,0 +1,100 @@ + +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +namespace CloudBuilder.Security.Entity + { + [TypeScript] + [Table("security_permission_view")] + public class SecurityPermissionViewEntity : ViewEntityBase + { + + public SecurityPermissionViewEntity() + { + } + + [Column("created_datetime")] + public DateTime CreatedDatetime { get; set; } + [Column("dependent")] + public string? Dependent { get; set; } + [Column("description")] + public string? Description { get; set; } + [Column("function_name")] + public string? FunctionName { get; set; } + [Column("permission_name")] + public string PermissionName { get; set; } + + public const string CREATED_DATETIME = "CreatedDatetime"; + public const string DEPENDENT = "Dependent"; + public const string DESCRIPTION = "Description"; + public const string FUNCTION_NAME = "FunctionName"; + public const string PERMISSION_NAME = "PermissionName"; + + public const string DB_NAME_SECURITY_PERMISSION_VIEW = "security_permission_view"; + public const string DB_NAME_FIELDS="created_datetime,dependent,description,function_name,permission_name"; + + public const string DB_CREATED_DATETIME = "created_datetime"; + public const string DB_DEPENDENT = "dependent"; + public const string DB_DESCRIPTION = "description"; + public const string DB_FUNCTION_NAME = "function_name"; + public const string DB_PERMISSION_NAME = "permission_name"; + + + public static SecurityPermissionViewEntity GetInstance() + { + return new SecurityPermissionViewEntity(); + } + + public virtual void CopyFrom(SecurityPermissionViewEntity source) + { + CopyFrom(source, true); + } + + public virtual void CopyFrom(SecurityPermissionViewEntity source, bool includeSystemFields) + { + if (source == null) + { + throw new NullReferenceException("Source entity is null."); + } + + this.CreatedDatetime = source.CreatedDatetime; + this.Dependent = source.Dependent; + this.Description = source.Description; + this.FunctionName = source.FunctionName; + this.PermissionName = source.PermissionName; + + if (includeSystemFields) + { + this.CreatedDatetime = source.CreatedDatetime; + } + } + + public override string GetSelectFrom() + { + return $" select {DB_NAME_FIELDS} from { DB_NAME_SECURITY_PERMISSION_VIEW} "; + } + + public override string GetSelectCountFrom(string sqlWhere) + { + return $" select count(*) from { DB_NAME_SECURITY_PERMISSION_VIEW} where 1=1 {sqlWhere}"; + } + + public override string GetSelectTopFrom(int limit, int start,string orderby,string orderbytag, string sqlWhere) + { + if (string.IsNullOrEmpty(orderbytag) || orderbytag.Trim() != "desc") orderbytag = "asc"; + + if (string.IsNullOrEmpty(orderby) || !DB_NAME_FIELDS.Contains(orderby)) orderby = DB_CREATED_DATETIME ; int offset = limit * (start - 1); + return $" select {DB_NAME_FIELDS} from (select {DB_NAME_FIELDS} ,row_number() over(order by {orderby} {orderbytag}) as num from { DB_NAME_SECURITY_PERMISSION_VIEW} where 1=1 {sqlWhere} ) a where num> {offset} LIMIT {offset},{limit} "; + } + + public SecurityPermissionViewEntity Clone() + { + SecurityPermissionViewEntity result = new SecurityPermissionViewEntity(); + result.CopyFrom(this); + + return result; + } + + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Entity/SecurityTableDescriptionEntity.auto.cs b/CloudBuilder/CloudBuilder.Security/Entity/SecurityTableDescriptionEntity.auto.cs new file mode 100644 index 0000000..e2585bd --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Entity/SecurityTableDescriptionEntity.auto.cs @@ -0,0 +1,120 @@ + +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +namespace CloudBuilder.Security.Entity + { + [TypeScript] + [Table("security_table_description")] + public class SecurityTableDescriptionEntity : ViewEntityBase + { + + public SecurityTableDescriptionEntity() + { + } + + [Column("created_by")] + public string CreatedBy { get; set; } + [Column("created_datetime")] + public DateTime CreatedDatetime { get; set; } + [Column("description")] + public string? Description { get; set; } + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + [Column("description_id")] + public int DescriptionId { get; set; } + [Column("field_name")] + public string FieldName { get; set; } + [Column("table_name")] + public string TableName { get; set; } + [Column("updated_by")] + public string UpdatedBy { get; set; } + [Column("updated_datetime")] + public DateTime UpdatedDatetime { get; set; } + + public const string CREATED_BY = "CreatedBy"; + public const string CREATED_DATETIME = "CreatedDatetime"; + public const string DESCRIPTION = "Description"; + public const string DESCRIPTION_ID = "DescriptionId"; + public const string FIELD_NAME = "FieldName"; + public const string TABLE_NAME = "TableName"; + public const string UPDATED_BY = "UpdatedBy"; + public const string UPDATED_DATETIME = "UpdatedDatetime"; + + public const string DB_NAME_SECURITY_TABLE_DESCRIPTION = "security_table_description"; + public const string DB_NAME_FIELDS="created_by,created_datetime,description,description_id,field_name,table_name,updated_by,updated_datetime"; + + public const string DB_CREATED_BY = "created_by"; + public const string DB_CREATED_DATETIME = "created_datetime"; + public const string DB_DESCRIPTION = "description"; + public const string DB_DESCRIPTION_ID = "description_id"; + public const string DB_FIELD_NAME = "field_name"; + public const string DB_TABLE_NAME = "table_name"; + public const string DB_UPDATED_BY = "updated_by"; + public const string DB_UPDATED_DATETIME = "updated_datetime"; + + + public static SecurityTableDescriptionEntity GetInstance() + { + return new SecurityTableDescriptionEntity(); + } + + public virtual void CopyFrom(SecurityTableDescriptionEntity source) + { + CopyFrom(source, true); + } + + public virtual void CopyFrom(SecurityTableDescriptionEntity source, bool includeSystemFields) + { + if (source == null) + { + throw new NullReferenceException("Source entity is null."); + } + + this.CreatedBy = source.CreatedBy; + this.CreatedDatetime = source.CreatedDatetime; + this.Description = source.Description; + this.DescriptionId = source.DescriptionId; + this.FieldName = source.FieldName; + this.TableName = source.TableName; + this.UpdatedBy = source.UpdatedBy; + this.UpdatedDatetime = source.UpdatedDatetime; + + if (includeSystemFields) + { + this.CreatedBy = source.CreatedBy; + this.CreatedDatetime = source.CreatedDatetime; + this.UpdatedBy = source.UpdatedBy; + this.UpdatedDatetime = source.UpdatedDatetime; + } + } + + public override string GetSelectFrom() + { + return $" select {DB_NAME_FIELDS} from { DB_NAME_SECURITY_TABLE_DESCRIPTION} "; + } + + public override string GetSelectCountFrom(string sqlWhere) + { + return $" select count(*) from { DB_NAME_SECURITY_TABLE_DESCRIPTION} where 1=1 {sqlWhere}"; + } + + public override string GetSelectTopFrom(int limit, int start,string orderby,string orderbytag, string sqlWhere) + { + if (string.IsNullOrEmpty(orderbytag) || orderbytag.Trim() != "desc") orderbytag = "asc"; + if (string.IsNullOrEmpty(orderby) || !DB_NAME_FIELDS.Contains(orderby)) orderby = DB_DESCRIPTION_ID ; + int offset = limit * (start - 1); + return $" select {DB_NAME_FIELDS} from (select {DB_NAME_FIELDS} ,row_number() over(order by {orderby} {orderbytag}) as num from { DB_NAME_SECURITY_TABLE_DESCRIPTION} where 1=1 {sqlWhere} ) a where num> {offset} LIMIT {offset},{limit} "; + } + + public SecurityTableDescriptionEntity Clone() + { + SecurityTableDescriptionEntity result = new SecurityTableDescriptionEntity(); + result.CopyFrom(this); + + return result; + } + + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Entity/SecurityTableDescriptionViewEntity.auto.cs b/CloudBuilder/CloudBuilder.Security/Entity/SecurityTableDescriptionViewEntity.auto.cs new file mode 100644 index 0000000..70cfabe --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Entity/SecurityTableDescriptionViewEntity.auto.cs @@ -0,0 +1,158 @@ +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +namespace CloudBuilder.Security.Entity + { + [TypeScript] + [Table("security_table_description_view")] + public class SecurityTableDescriptionViewEntity : ViewEntityBase + { + + public SecurityTableDescriptionViewEntity() + { + } + + [Column("table_name")] + public string? TableName { get; set; } + [Column("field_name")] + public string? FieldName { get; set; } + [Column("type_name")] + public string? TypeName { get; set; } + [Column("type_of_name")] + public string? TypeOfName { get; set; } + [Column("max_length")] + public int MaxLength { get; set; } + [Column("scale")] + public int Scale { get; set; } + [Column("is_null_able")] + public string IsNullAble { get; set; } + [Column("field_default_value")] + public string FieldDefaultValue { get; set; } + [Column("xtype")] + public string? Xtype { get; set; } + [Column("find_by")] + public int FindBy { get; set; } + [Column("operation")] + public int Operation { get; set; } + [Column("pk")] + public int Pk { get; set; } + [Column("pk_name")] + public string PkName { get; set; } + [Column("is_identity")] + public int IsIdentity { get; set; } + [Column("colid")] + public int Colid { get; set; } + [Column("description")] + public string? Description { get; set; } + [Column("description_id")] + public int DescriptionId { get; set; } + + public const string TABLE_NAME = "TableName"; + public const string FIELD_NAME = "FieldName"; + public const string TYPE_NAME = "TypeName"; + public const string TYPE_OF_NAME = "TypeOfName"; + public const string MAX_LENGTH = "MaxLength"; + public const string SCALE = "Scale"; + public const string IS_NULL_ABLE = "IsNullAble"; + public const string FIELD_DEFAULT_VALUE = "FieldDefaultValue"; + public const string XTYPE = "Xtype"; + public const string FIND_BY = "FindBy"; + public const string OPERATION = "Operation"; + public const string PK = "Pk"; + public const string PK_NAME = "PkName"; + public const string IS_IDENTITY = "IsIdentity"; + public const string COLID = "Colid"; + public const string DESCRIPTION = "Description"; + public const string DESCRIPTION_ID = "DescriptionId"; + + public const string DB_NAME_SECURITY_TABLE_DESCRIPTION_VIEW = "security_table_description_view"; + public const string DB_NAME_FIELDS="table_name,field_name,type_name,type_of_name,max_length,scale,is_null_able,field_default_value,xtype,find_by,operation,pk,pk_name,is_identity,colid,description,description_id"; + + public const string DB_TABLE_NAME = "table_name"; + public const string DB_FIELD_NAME = "field_name"; + public const string DB_TYPE_NAME = "type_name"; + public const string DB_TYPE_OF_NAME = "type_of_name"; + public const string DB_MAX_LENGTH = "max_length"; + public const string DB_SCALE = "scale"; + public const string DB_IS_NULL_ABLE = "is_null_able"; + public const string DB_FIELD_DEFAULT_VALUE = "field_default_value"; + public const string DB_XTYPE = "xtype"; + public const string DB_FIND_BY = "find_by"; + public const string DB_OPERATION = "operation"; + public const string DB_PK = "pk"; + public const string DB_PK_NAME = "pk_name"; + public const string DB_IS_IDENTITY = "is_identity"; + public const string DB_COLID = "colid"; + public const string DB_DESCRIPTION = "description"; + public const string DB_DESCRIPTION_ID = "description_id"; + + + public static SecurityTableDescriptionViewEntity GetInstance() + { + return new SecurityTableDescriptionViewEntity(); + } + + public virtual void CopyFrom(SecurityTableDescriptionViewEntity source) + { + CopyFrom(source, true); + } + + public virtual void CopyFrom(SecurityTableDescriptionViewEntity source, bool includeSystemFields) + { + if (source == null) + { + throw new NullReferenceException("Source entity is null."); + } + + this.TableName = source.TableName; + this.FieldName = source.FieldName; + this.TypeName = source.TypeName; + this.TypeOfName = source.TypeOfName; + this.MaxLength = source.MaxLength; + this.Scale = source.Scale; + this.IsNullAble = source.IsNullAble; + this.FieldDefaultValue = source.FieldDefaultValue; + this.Xtype = source.Xtype; + this.FindBy = source.FindBy; + this.Operation = source.Operation; + this.Pk = source.Pk; + this.PkName = source.PkName; + this.IsIdentity = source.IsIdentity; + this.Colid = source.Colid; + this.Description = source.Description; + this.DescriptionId = source.DescriptionId; + + if (includeSystemFields) + { + } + } + + public override string GetSelectFrom() + { + return $" select {DB_NAME_FIELDS} from { DB_NAME_SECURITY_TABLE_DESCRIPTION_VIEW} "; + } + + public override string GetSelectCountFrom(string sqlWhere) + { + return $" select count(*) from { DB_NAME_SECURITY_TABLE_DESCRIPTION_VIEW} where 1=1 {sqlWhere}"; + } + + public override string GetSelectTopFrom(int limit, int start,string orderby,string orderbytag, string sqlWhere) + { + if (string.IsNullOrEmpty(orderbytag) || orderbytag.Trim() != "desc") orderbytag = "asc"; + + if (string.IsNullOrEmpty(orderby) || !DB_NAME_FIELDS.Contains(orderby)) orderby = DB_TABLE_NAME ; string top = limit > 0 ? $"top {limit}" : ""; + return $" select {top} {DB_NAME_FIELDS} from (select {DB_NAME_FIELDS} ,row_number() over(order by {orderby} {orderbytag}) as num from { DB_NAME_SECURITY_TABLE_DESCRIPTION_VIEW} where 1=1 {sqlWhere} ) a where num> {limit * (start - 1)}"; + } + + public SecurityTableDescriptionViewEntity Clone() + { + SecurityTableDescriptionViewEntity result = new SecurityTableDescriptionViewEntity(); + result.CopyFrom(this); + + return result; + } + + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Entity/SecurityUserActorEntity.auto.cs b/CloudBuilder/CloudBuilder.Security/Entity/SecurityUserActorEntity.auto.cs new file mode 100644 index 0000000..e30a7a6 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Entity/SecurityUserActorEntity.auto.cs @@ -0,0 +1,108 @@ + +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +namespace CloudBuilder.Security.Entity + { + [TypeScript] + [Table("security_user_actor")] + public class SecurityUserActorEntity : EntityBase + { + + public SecurityUserActorEntity() + { + } + + [Column("actor_name")] + public string ActorName { get; set; } + [Column("created_by")] + public string CreatedBy { get; set; } + [Column("created_datetime")] + public DateTime CreatedDatetime { get; set; } + [Column("updated_by")] + public string UpdatedBy { get; set; } + [Column("updated_datetime")] + public DateTime UpdatedDatetime { get; set; } + [Column("user_name")] + public string UserName { get; set; } + + public const string ACTOR_NAME = "ActorName"; + public const string CREATED_BY = "CreatedBy"; + public const string CREATED_DATETIME = "CreatedDatetime"; + public const string UPDATED_BY = "UpdatedBy"; + public const string UPDATED_DATETIME = "UpdatedDatetime"; + public const string USER_NAME = "UserName"; + + public const string DB_NAME_SECURITY_USER_ACTOR = "security_user_actor"; + public const string DB_NAME_FIELDS="actor_name,created_by,created_datetime,updated_by,updated_datetime,user_name"; + + public const string DB_ACTOR_NAME = "actor_name"; + public const string DB_CREATED_BY = "created_by"; + public const string DB_CREATED_DATETIME = "created_datetime"; + public const string DB_UPDATED_BY = "updated_by"; + public const string DB_UPDATED_DATETIME = "updated_datetime"; + public const string DB_USER_NAME = "user_name"; + + + public static SecurityUserActorEntity GetInstance() + { + return new SecurityUserActorEntity(); + } + + public virtual void CopyFrom(SecurityUserActorEntity source) + { + CopyFrom(source, true); + } + + public virtual void CopyFrom(SecurityUserActorEntity source, bool includeSystemFields) + { + if (source == null) + { + throw new NullReferenceException("Source entity is null."); + } + + this.ActorName = source.ActorName; + this.CreatedBy = source.CreatedBy; + this.CreatedDatetime = source.CreatedDatetime; + this.UpdatedBy = source.UpdatedBy; + this.UpdatedDatetime = source.UpdatedDatetime; + this.UserName = source.UserName; + + if (includeSystemFields) + { + this.CreatedBy = source.CreatedBy; + this.CreatedDatetime = source.CreatedDatetime; + this.UpdatedBy = source.UpdatedBy; + this.UpdatedDatetime = source.UpdatedDatetime; + } + } + + public override string GetSelectFrom() + { + return $" select {DB_NAME_FIELDS} from { DB_NAME_SECURITY_USER_ACTOR} "; + } + + public override string GetSelectCountFrom(string sqlWhere) + { + return $" select count(*) from { DB_NAME_SECURITY_USER_ACTOR} where 1=1 {sqlWhere}"; + } + + public override string GetSelectTopFrom(int limit, int start,string orderby,string orderbytag, string sqlWhere) + { + if (string.IsNullOrEmpty(orderbytag) || orderbytag.Trim() != "desc") orderbytag = "asc"; + if (string.IsNullOrEmpty(orderby) || !DB_NAME_FIELDS.Contains(orderby)) orderby = DB_ACTOR_NAME ; + int offset = limit * (start - 1); + return $" select {DB_NAME_FIELDS} from (select {DB_NAME_FIELDS} ,row_number() over(order by {orderby} {orderbytag}) as num from { DB_NAME_SECURITY_USER_ACTOR} where 1=1 {sqlWhere} ) a where num> {offset} LIMIT {offset},{limit} "; + } + + public SecurityUserActorEntity Clone() + { + SecurityUserActorEntity result = new SecurityUserActorEntity(); + result.CopyFrom(this); + + return result; + } + + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Entity/SecurityUserActorEntityKey.auto.cs b/CloudBuilder/CloudBuilder.Security/Entity/SecurityUserActorEntityKey.auto.cs new file mode 100644 index 0000000..d9152cc --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Entity/SecurityUserActorEntityKey.auto.cs @@ -0,0 +1,33 @@ + +using CloudBuilder.Core.Authorization; +namespace CloudBuilder.Security +{ + [TypeScript] + public class SecurityUserActorEntityKey + { + public string ActorName { get; set; } + public string UserName { get; set; } + + public override bool Equals(object obj) + { + if (this == obj) return true; + + SecurityUserActorEntityKey pkey = obj as SecurityUserActorEntityKey; + if (pkey == null) return false; + + if (ActorName != pkey.ActorName) return false; + if (UserName != pkey.UserName) return false; + + return true; + } + + + public override string ToString() + { + string declareSql=""; + declareSql=declareSql+$"declare @__tkey_ActorName_0 varchar(50) select @__tkey_ActorName_0 ='{ActorName}'; " ; declareSql=declareSql+$"declare @__tkey_UserName_1 varchar(50) select @__tkey_UserName_1 ='{UserName}'; " ; + return declareSql; + } + } + } + /* builder.Entity().HasKey(c => new { c.ActorName, c.UserName}); */ diff --git a/CloudBuilder/CloudBuilder.Security/Entity/SecurityUserActorViewEntity.auto.cs b/CloudBuilder/CloudBuilder.Security/Entity/SecurityUserActorViewEntity.auto.cs new file mode 100644 index 0000000..1d76497 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Entity/SecurityUserActorViewEntity.auto.cs @@ -0,0 +1,99 @@ + +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +namespace CloudBuilder.Security.Entity + { + [TypeScript] + [Table("security_user_actor_view")] + public class SecurityUserActorViewEntity : ViewEntityBase + { + + public SecurityUserActorViewEntity() + { + } + + [Column("actor_local_name")] + public string? ActorLocalName { get; set; } + [Column("actor_name")] + public string ActorName { get; set; } + [Column("user_local_name")] + public string UserLocalName { get; set; } + [Column("user_mobile")] + public string? UserMobile { get; set; } + [Column("user_name")] + public string UserName { get; set; } + + public const string ACTOR_LOCAL_NAME = "ActorLocalName"; + public const string ACTOR_NAME = "ActorName"; + public const string USER_LOCAL_NAME = "UserLocalName"; + public const string USER_MOBILE = "UserMobile"; + public const string USER_NAME = "UserName"; + + public const string DB_NAME_SECURITY_USER_ACTOR_VIEW = "security_user_actor_view"; + public const string DB_NAME_FIELDS="actor_local_name,actor_name,user_local_name,user_mobile,user_name"; + + public const string DB_ACTOR_LOCAL_NAME = "actor_local_name"; + public const string DB_ACTOR_NAME = "actor_name"; + public const string DB_USER_LOCAL_NAME = "user_local_name"; + public const string DB_USER_MOBILE = "user_mobile"; + public const string DB_USER_NAME = "user_name"; + + + public static SecurityUserActorViewEntity GetInstance() + { + return new SecurityUserActorViewEntity(); + } + + public virtual void CopyFrom(SecurityUserActorViewEntity source) + { + CopyFrom(source, true); + } + + public virtual void CopyFrom(SecurityUserActorViewEntity source, bool includeSystemFields) + { + if (source == null) + { + throw new NullReferenceException("Source entity is null."); + } + + this.ActorLocalName = source.ActorLocalName; + this.ActorName = source.ActorName; + this.UserLocalName = source.UserLocalName; + this.UserMobile = source.UserMobile; + this.UserName = source.UserName; + + if (includeSystemFields) + { + } + } + + public override string GetSelectFrom() + { + return $" select {DB_NAME_FIELDS} from { DB_NAME_SECURITY_USER_ACTOR_VIEW} "; + } + + public override string GetSelectCountFrom(string sqlWhere) + { + return $" select count(*) from { DB_NAME_SECURITY_USER_ACTOR_VIEW} where 1=1 {sqlWhere}"; + } + + public override string GetSelectTopFrom(int limit, int start,string orderby,string orderbytag, string sqlWhere) + { + if (string.IsNullOrEmpty(orderbytag) || orderbytag.Trim() != "desc") orderbytag = "asc"; + + if (string.IsNullOrEmpty(orderby) || !DB_NAME_FIELDS.Contains(orderby)) orderby = DB_ACTOR_LOCAL_NAME ; int offset = limit * (start - 1); + return $" select {DB_NAME_FIELDS} from (select {DB_NAME_FIELDS} ,row_number() over(order by {orderby} {orderbytag}) as num from { DB_NAME_SECURITY_USER_ACTOR_VIEW} where 1=1 {sqlWhere} ) a where num> {offset} LIMIT {offset},{limit} "; + } + + public SecurityUserActorViewEntity Clone() + { + SecurityUserActorViewEntity result = new SecurityUserActorViewEntity(); + result.CopyFrom(this); + + return result; + } + + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Entity/SecurityUserDelegatedPermissionEntity.auto.cs b/CloudBuilder/CloudBuilder.Security/Entity/SecurityUserDelegatedPermissionEntity.auto.cs new file mode 100644 index 0000000..ee1f0fb --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Entity/SecurityUserDelegatedPermissionEntity.auto.cs @@ -0,0 +1,123 @@ + +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +namespace CloudBuilder.Security.Entity + { + [TypeScript] + [Table("security_user_delegated_permission")] + public class SecurityUserDelegatedPermissionEntity : EntityBase + { + + public SecurityUserDelegatedPermissionEntity() + { + } + + [Column("created_by")] + public string CreatedBy { get; set; } + [Column("created_datetime")] + public DateTime CreatedDatetime { get; set; } + [Column("delegated_by_user")] + public string DelegatedByUser { get; set; } + [Column("end_datetime")] + public DateTime EndDatetime { get; set; } + [Column("permission_name")] + public string PermissionName { get; set; } + [Column("start_datetime")] + public DateTime StartDatetime { get; set; } + [Column("updated_by")] + public string UpdatedBy { get; set; } + [Column("updated_datetime")] + public DateTime UpdatedDatetime { get; set; } + [Column("user_name")] + public string UserName { get; set; } + + public const string CREATED_BY = "CreatedBy"; + public const string CREATED_DATETIME = "CreatedDatetime"; + public const string DELEGATED_BY_USER = "DelegatedByUser"; + public const string END_DATETIME = "EndDatetime"; + public const string PERMISSION_NAME = "PermissionName"; + public const string START_DATETIME = "StartDatetime"; + public const string UPDATED_BY = "UpdatedBy"; + public const string UPDATED_DATETIME = "UpdatedDatetime"; + public const string USER_NAME = "UserName"; + + public const string DB_NAME_SECURITY_USER_DELEGATED_PERMISSION = "security_user_delegated_permission"; + public const string DB_NAME_FIELDS="created_by,created_datetime,delegated_by_user,end_datetime,permission_name,start_datetime,updated_by,updated_datetime,user_name"; + + public const string DB_CREATED_BY = "created_by"; + public const string DB_CREATED_DATETIME = "created_datetime"; + public const string DB_DELEGATED_BY_USER = "delegated_by_user"; + public const string DB_END_DATETIME = "end_datetime"; + public const string DB_PERMISSION_NAME = "permission_name"; + public const string DB_START_DATETIME = "start_datetime"; + public const string DB_UPDATED_BY = "updated_by"; + public const string DB_UPDATED_DATETIME = "updated_datetime"; + public const string DB_USER_NAME = "user_name"; + + + public static SecurityUserDelegatedPermissionEntity GetInstance() + { + return new SecurityUserDelegatedPermissionEntity(); + } + + public virtual void CopyFrom(SecurityUserDelegatedPermissionEntity source) + { + CopyFrom(source, true); + } + + public virtual void CopyFrom(SecurityUserDelegatedPermissionEntity source, bool includeSystemFields) + { + if (source == null) + { + throw new NullReferenceException("Source entity is null."); + } + + this.CreatedBy = source.CreatedBy; + this.CreatedDatetime = source.CreatedDatetime; + this.DelegatedByUser = source.DelegatedByUser; + this.EndDatetime = source.EndDatetime; + this.PermissionName = source.PermissionName; + this.StartDatetime = source.StartDatetime; + this.UpdatedBy = source.UpdatedBy; + this.UpdatedDatetime = source.UpdatedDatetime; + this.UserName = source.UserName; + + if (includeSystemFields) + { + this.CreatedBy = source.CreatedBy; + this.CreatedDatetime = source.CreatedDatetime; + this.UpdatedBy = source.UpdatedBy; + this.UpdatedDatetime = source.UpdatedDatetime; + } + } + + public override string GetSelectFrom() + { + return $" select {DB_NAME_FIELDS} from { DB_NAME_SECURITY_USER_DELEGATED_PERMISSION} "; + } + + public override string GetSelectCountFrom(string sqlWhere) + { + return $" select count(*) from { DB_NAME_SECURITY_USER_DELEGATED_PERMISSION} where 1=1 {sqlWhere}"; + } + + public override string GetSelectTopFrom(int limit, int start,string orderby,string orderbytag, string sqlWhere) + { + if (string.IsNullOrEmpty(orderbytag) || orderbytag.Trim() != "desc") orderbytag = "asc"; + if (string.IsNullOrEmpty(orderby) || !DB_NAME_FIELDS.Contains(orderby)) orderby = DB_DELEGATED_BY_USER ; + int offset = limit * (start - 1); + return $" select {DB_NAME_FIELDS} from (select {DB_NAME_FIELDS} ,row_number() over(order by {orderby} {orderbytag}) as num from { DB_NAME_SECURITY_USER_DELEGATED_PERMISSION} where 1=1 {sqlWhere} ) a where num> {offset} LIMIT {offset},{limit} "; + } + + public SecurityUserDelegatedPermissionEntity Clone() + { + SecurityUserDelegatedPermissionEntity result = new SecurityUserDelegatedPermissionEntity(); + result.CopyFrom(this); + + return result; + } + + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Entity/SecurityUserDelegatedPermissionEntityKey.auto.cs b/CloudBuilder/CloudBuilder.Security/Entity/SecurityUserDelegatedPermissionEntityKey.auto.cs new file mode 100644 index 0000000..ad3d6e5 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Entity/SecurityUserDelegatedPermissionEntityKey.auto.cs @@ -0,0 +1,35 @@ + +using CloudBuilder.Core.Authorization; +namespace CloudBuilder.Security +{ + [TypeScript] + public class SecurityUserDelegatedPermissionEntityKey + { + public string DelegatedByUser { get; set; } + public string PermissionName { get; set; } + public string UserName { get; set; } + + public override bool Equals(object obj) + { + if (this == obj) return true; + + SecurityUserDelegatedPermissionEntityKey pkey = obj as SecurityUserDelegatedPermissionEntityKey; + if (pkey == null) return false; + + if (DelegatedByUser != pkey.DelegatedByUser) return false; + if (PermissionName != pkey.PermissionName) return false; + if (UserName != pkey.UserName) return false; + + return true; + } + + + public override string ToString() + { + string declareSql=""; + declareSql=declareSql+$"declare @__tkey_DelegatedByUser_0 varchar(50) select @__tkey_DelegatedByUser_0 ='{DelegatedByUser}'; " ; declareSql=declareSql+$"declare @__tkey_PermissionName_1 varchar(50) select @__tkey_PermissionName_1 ='{PermissionName}'; " ; declareSql=declareSql+$"declare @__tkey_UserName_2 varchar(50) select @__tkey_UserName_2 ='{UserName}'; " ; + return declareSql; + } + } + } + /* builder.Entity().HasKey(c => new { c.DelegatedByUser, c.PermissionName, c.UserName}); */ diff --git a/CloudBuilder/CloudBuilder.Security/Entity/SecurityUserEntity.auto.cs b/CloudBuilder/CloudBuilder.Security/Entity/SecurityUserEntity.auto.cs new file mode 100644 index 0000000..2bcd98c --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Entity/SecurityUserEntity.auto.cs @@ -0,0 +1,269 @@ + +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +namespace CloudBuilder.Security.Entity + { + [TypeScript] + [Table("security_user")] + public class SecurityUserEntity : ViewEntityBase + { + + public SecurityUserEntity() + { + } + + [Column("accounts_locked_datetime")] + public Nullable AccountsLockedDatetime { get; set; } + [Column("biometric_counter")] + public int BiometricCounter { get; set; } + [Column("biometric_credential_id")] + public string? BiometricCredentialId { get; set; } + [Column("biometric_device_name")] + public string? BiometricDeviceName { get; set; } + [Column("biometric_enrolled_at")] + public Nullable BiometricEnrolledAt { get; set; } + [Column("biometric_last_used_at")] + public Nullable BiometricLastUsedAt { get; set; } + [Column("biometric_public_key")] + public string? BiometricPublicKey { get; set; } + [Column("community")] + public int Community { get; set; } + [Column("company_name")] + public string? CompanyName { get; set; } + [Column("created_by")] + public string CreatedBy { get; set; } + [Column("created_datetime")] + public DateTime CreatedDatetime { get; set; } + [Column("error_login_count")] + public int ErrorLoginCount { get; set; } + [Column("industry")] + public string? Industry { get; set; } + [Column("is_accounts_locked_indc")] + public string? IsAccountsLockedIndc { get; set; } + [Column("is_forece_change_password_indc")] + public string? IsForeceChangePasswordIndc { get; set; } + [Column("last_login_datetime")] + public Nullable LastLoginDatetime { get; set; } + [Column("postcode")] + public string? Postcode { get; set; } + [Column("room_name")] + public string? RoomName { get; set; } + [Column("updated_by")] + public string UpdatedBy { get; set; } + [Column("updated_datetime")] + public DateTime UpdatedDatetime { get; set; } + [Column("user_accounts_expire_datetime")] + public Nullable UserAccountsExpireDatetime { get; set; } + [Column("user_address")] + public string? UserAddress { get; set; } + [Column("user_alipay_account")] + public string? UserAlipayAccount { get; set; } + [Column("user_alipay_account_img_path")] + public string? UserAlipayAccountImgPath { get; set; } + [Column("user_eng_name")] + public string? UserEngName { get; set; } + [Column("user_grade")] + public int UserGrade { get; set; } + [Column("user_icon_img_path")] + public string? UserIconImgPath { get; set; } + [Column("user_is_valid_indc")] + public string? UserIsValidIndc { get; set; } + [Column("user_local_name")] + public string UserLocalName { get; set; } + [Column("user_mobile")] + public string? UserMobile { get; set; } + [Key] + [Column("user_name")] + public string UserName { get; set; } + [Column("user_password")] + public string? UserPassword { get; set; } + [Column("user_remark")] + public string? UserRemark { get; set; } + [Column("user_type")] + public string? UserType { get; set; } + [Column("user_type_end_datetime")] + public Nullable UserTypeEndDatetime { get; set; } + [Column("user_wechat_account")] + public string? UserWechatAccount { get; set; } + [Column("user_wechat_account_img_path")] + public string? UserWechatAccountImgPath { get; set; } + [Column("welcome_page")] + public string? WelcomePage { get; set; } + + public const string ACCOUNTS_LOCKED_DATETIME = "AccountsLockedDatetime"; + public const string BIOMETRIC_COUNTER = "BiometricCounter"; + public const string BIOMETRIC_CREDENTIAL_ID = "BiometricCredentialId"; + public const string BIOMETRIC_DEVICE_NAME = "BiometricDeviceName"; + public const string BIOMETRIC_ENROLLED_AT = "BiometricEnrolledAt"; + public const string BIOMETRIC_LAST_USED_AT = "BiometricLastUsedAt"; + public const string BIOMETRIC_PUBLIC_KEY = "BiometricPublicKey"; + public const string COMMUNITY = "Community"; + public const string COMPANY_NAME = "CompanyName"; + public const string CREATED_BY = "CreatedBy"; + public const string CREATED_DATETIME = "CreatedDatetime"; + public const string ERROR_LOGIN_COUNT = "ErrorLoginCount"; + public const string INDUSTRY = "Industry"; + public const string IS_ACCOUNTS_LOCKED_INDC = "IsAccountsLockedIndc"; + public const string IS_FORECE_CHANGE_PASSWORD_INDC = "IsForeceChangePasswordIndc"; + public const string LAST_LOGIN_DATETIME = "LastLoginDatetime"; + public const string POSTCODE = "Postcode"; + public const string ROOM_NAME = "RoomName"; + public const string UPDATED_BY = "UpdatedBy"; + public const string UPDATED_DATETIME = "UpdatedDatetime"; + public const string USER_ACCOUNTS_EXPIRE_DATETIME = "UserAccountsExpireDatetime"; + public const string USER_ADDRESS = "UserAddress"; + public const string USER_ALIPAY_ACCOUNT = "UserAlipayAccount"; + public const string USER_ALIPAY_ACCOUNT_IMG_PATH = "UserAlipayAccountImgPath"; + public const string USER_ENG_NAME = "UserEngName"; + public const string USER_GRADE = "UserGrade"; + public const string USER_ICON_IMG_PATH = "UserIconImgPath"; + public const string USER_IS_VALID_INDC = "UserIsValidIndc"; + public const string USER_LOCAL_NAME = "UserLocalName"; + public const string USER_MOBILE = "UserMobile"; + public const string USER_NAME = "UserName"; + public const string USER_PASSWORD = "UserPassword"; + public const string USER_REMARK = "UserRemark"; + public const string USER_TYPE = "UserType"; + public const string USER_TYPE_END_DATETIME = "UserTypeEndDatetime"; + public const string USER_WECHAT_ACCOUNT = "UserWechatAccount"; + public const string USER_WECHAT_ACCOUNT_IMG_PATH = "UserWechatAccountImgPath"; + public const string WELCOME_PAGE = "WelcomePage"; + + public const string DB_NAME_SECURITY_USER = "security_user"; + public const string DB_NAME_FIELDS="accounts_locked_datetime,biometric_counter,biometric_credential_id,biometric_device_name,biometric_enrolled_at,biometric_last_used_at,biometric_public_key,community,company_name,created_by,created_datetime,error_login_count,industry,is_accounts_locked_indc,is_forece_change_password_indc,last_login_datetime,postcode,room_name,updated_by,updated_datetime,user_accounts_expire_datetime,user_address,user_alipay_account,user_alipay_account_img_path,user_eng_name,user_grade,user_icon_img_path,user_is_valid_indc,user_local_name,user_mobile,user_name,user_password,user_remark,user_type,user_type_end_datetime,user_wechat_account,user_wechat_account_img_path,welcome_page"; + + public const string DB_ACCOUNTS_LOCKED_DATETIME = "accounts_locked_datetime"; + public const string DB_BIOMETRIC_COUNTER = "biometric_counter"; + public const string DB_BIOMETRIC_CREDENTIAL_ID = "biometric_credential_id"; + public const string DB_BIOMETRIC_DEVICE_NAME = "biometric_device_name"; + public const string DB_BIOMETRIC_ENROLLED_AT = "biometric_enrolled_at"; + public const string DB_BIOMETRIC_LAST_USED_AT = "biometric_last_used_at"; + public const string DB_BIOMETRIC_PUBLIC_KEY = "biometric_public_key"; + public const string DB_COMMUNITY = "community"; + public const string DB_COMPANY_NAME = "company_name"; + public const string DB_CREATED_BY = "created_by"; + public const string DB_CREATED_DATETIME = "created_datetime"; + public const string DB_ERROR_LOGIN_COUNT = "error_login_count"; + public const string DB_INDUSTRY = "industry"; + public const string DB_IS_ACCOUNTS_LOCKED_INDC = "is_accounts_locked_indc"; + public const string DB_IS_FORECE_CHANGE_PASSWORD_INDC = "is_forece_change_password_indc"; + public const string DB_LAST_LOGIN_DATETIME = "last_login_datetime"; + public const string DB_POSTCODE = "postcode"; + public const string DB_ROOM_NAME = "room_name"; + public const string DB_UPDATED_BY = "updated_by"; + public const string DB_UPDATED_DATETIME = "updated_datetime"; + public const string DB_USER_ACCOUNTS_EXPIRE_DATETIME = "user_accounts_expire_datetime"; + public const string DB_USER_ADDRESS = "user_address"; + public const string DB_USER_ALIPAY_ACCOUNT = "user_alipay_account"; + public const string DB_USER_ALIPAY_ACCOUNT_IMG_PATH = "user_alipay_account_img_path"; + public const string DB_USER_ENG_NAME = "user_eng_name"; + public const string DB_USER_GRADE = "user_grade"; + public const string DB_USER_ICON_IMG_PATH = "user_icon_img_path"; + public const string DB_USER_IS_VALID_INDC = "user_is_valid_indc"; + public const string DB_USER_LOCAL_NAME = "user_local_name"; + public const string DB_USER_MOBILE = "user_mobile"; + public const string DB_USER_NAME = "user_name"; + public const string DB_USER_PASSWORD = "user_password"; + public const string DB_USER_REMARK = "user_remark"; + public const string DB_USER_TYPE = "user_type"; + public const string DB_USER_TYPE_END_DATETIME = "user_type_end_datetime"; + public const string DB_USER_WECHAT_ACCOUNT = "user_wechat_account"; + public const string DB_USER_WECHAT_ACCOUNT_IMG_PATH = "user_wechat_account_img_path"; + public const string DB_WELCOME_PAGE = "welcome_page"; + + + public static SecurityUserEntity GetInstance() + { + return new SecurityUserEntity(); + } + + public virtual void CopyFrom(SecurityUserEntity source) + { + CopyFrom(source, true); + } + + public virtual void CopyFrom(SecurityUserEntity source, bool includeSystemFields) + { + if (source == null) + { + throw new NullReferenceException("Source entity is null."); + } + + this.AccountsLockedDatetime = source.AccountsLockedDatetime; + this.BiometricCounter = source.BiometricCounter; + this.BiometricCredentialId = source.BiometricCredentialId; + this.BiometricDeviceName = source.BiometricDeviceName; + this.BiometricEnrolledAt = source.BiometricEnrolledAt; + this.BiometricLastUsedAt = source.BiometricLastUsedAt; + this.BiometricPublicKey = source.BiometricPublicKey; + this.Community = source.Community; + this.CompanyName = source.CompanyName; + this.CreatedBy = source.CreatedBy; + this.CreatedDatetime = source.CreatedDatetime; + this.ErrorLoginCount = source.ErrorLoginCount; + this.Industry = source.Industry; + this.IsAccountsLockedIndc = source.IsAccountsLockedIndc; + this.IsForeceChangePasswordIndc = source.IsForeceChangePasswordIndc; + this.LastLoginDatetime = source.LastLoginDatetime; + this.Postcode = source.Postcode; + this.RoomName = source.RoomName; + this.UpdatedBy = source.UpdatedBy; + this.UpdatedDatetime = source.UpdatedDatetime; + this.UserAccountsExpireDatetime = source.UserAccountsExpireDatetime; + this.UserAddress = source.UserAddress; + this.UserAlipayAccount = source.UserAlipayAccount; + this.UserAlipayAccountImgPath = source.UserAlipayAccountImgPath; + this.UserEngName = source.UserEngName; + this.UserGrade = source.UserGrade; + this.UserIconImgPath = source.UserIconImgPath; + this.UserIsValidIndc = source.UserIsValidIndc; + this.UserLocalName = source.UserLocalName; + this.UserMobile = source.UserMobile; + this.UserName = source.UserName; + this.UserPassword = source.UserPassword; + this.UserRemark = source.UserRemark; + this.UserType = source.UserType; + this.UserTypeEndDatetime = source.UserTypeEndDatetime; + this.UserWechatAccount = source.UserWechatAccount; + this.UserWechatAccountImgPath = source.UserWechatAccountImgPath; + this.WelcomePage = source.WelcomePage; + + if (includeSystemFields) + { + this.CreatedBy = source.CreatedBy; + this.CreatedDatetime = source.CreatedDatetime; + this.UpdatedBy = source.UpdatedBy; + this.UpdatedDatetime = source.UpdatedDatetime; + } + } + + public override string GetSelectFrom() + { + return $" select {DB_NAME_FIELDS} from { DB_NAME_SECURITY_USER} "; + } + + public override string GetSelectCountFrom(string sqlWhere) + { + return $" select count(*) from { DB_NAME_SECURITY_USER} where 1=1 {sqlWhere}"; + } + + public override string GetSelectTopFrom(int limit, int start,string orderby,string orderbytag, string sqlWhere) + { + if (string.IsNullOrEmpty(orderbytag) || orderbytag.Trim() != "desc") orderbytag = "asc"; + if (string.IsNullOrEmpty(orderby) || !DB_NAME_FIELDS.Contains(orderby)) orderby = DB_USER_NAME ; + int offset = limit * (start - 1); + return $" select {DB_NAME_FIELDS} from (select {DB_NAME_FIELDS} ,row_number() over(order by {orderby} {orderbytag}) as num from { DB_NAME_SECURITY_USER} where 1=1 {sqlWhere} ) a where num> {offset} LIMIT {offset},{limit} "; + } + + public SecurityUserEntity Clone() + { + SecurityUserEntity result = new SecurityUserEntity(); + result.CopyFrom(this); + + return result; + } + + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Entity/SecurityUserLoginLogEntity.auto.cs b/CloudBuilder/CloudBuilder.Security/Entity/SecurityUserLoginLogEntity.auto.cs new file mode 100644 index 0000000..97f1f5a --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Entity/SecurityUserLoginLogEntity.auto.cs @@ -0,0 +1,120 @@ + +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +namespace CloudBuilder.Security.Entity + { + [TypeScript] + [Table("security_user_login_log")] + public class SecurityUserLoginLogEntity : ViewEntityBase + { + + public SecurityUserLoginLogEntity() + { + } + + [Column("agent_user_name")] + public string? AgentUserName { get; set; } + [Column("created_by")] + public string CreatedBy { get; set; } + [Column("created_datetime")] + public DateTime CreatedDatetime { get; set; } + [Column("ip_address")] + public string? IpAddress { get; set; } + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + [Column("login_log_id")] + public long LoginLogId { get; set; } + [Column("updated_by")] + public string UpdatedBy { get; set; } + [Column("updated_datetime")] + public DateTime UpdatedDatetime { get; set; } + [Column("user_name")] + public string UserName { get; set; } + + public const string AGENT_USER_NAME = "AgentUserName"; + public const string CREATED_BY = "CreatedBy"; + public const string CREATED_DATETIME = "CreatedDatetime"; + public const string IP_ADDRESS = "IpAddress"; + public const string LOGIN_LOG_ID = "LoginLogId"; + public const string UPDATED_BY = "UpdatedBy"; + public const string UPDATED_DATETIME = "UpdatedDatetime"; + public const string USER_NAME = "UserName"; + + public const string DB_NAME_SECURITY_USER_LOGIN_LOG = "security_user_login_log"; + public const string DB_NAME_FIELDS="agent_user_name,created_by,created_datetime,ip_address,login_log_id,updated_by,updated_datetime,user_name"; + + public const string DB_AGENT_USER_NAME = "agent_user_name"; + public const string DB_CREATED_BY = "created_by"; + public const string DB_CREATED_DATETIME = "created_datetime"; + public const string DB_IP_ADDRESS = "ip_address"; + public const string DB_LOGIN_LOG_ID = "login_log_id"; + public const string DB_UPDATED_BY = "updated_by"; + public const string DB_UPDATED_DATETIME = "updated_datetime"; + public const string DB_USER_NAME = "user_name"; + + + public static SecurityUserLoginLogEntity GetInstance() + { + return new SecurityUserLoginLogEntity(); + } + + public virtual void CopyFrom(SecurityUserLoginLogEntity source) + { + CopyFrom(source, true); + } + + public virtual void CopyFrom(SecurityUserLoginLogEntity source, bool includeSystemFields) + { + if (source == null) + { + throw new NullReferenceException("Source entity is null."); + } + + this.AgentUserName = source.AgentUserName; + this.CreatedBy = source.CreatedBy; + this.CreatedDatetime = source.CreatedDatetime; + this.IpAddress = source.IpAddress; + this.LoginLogId = source.LoginLogId; + this.UpdatedBy = source.UpdatedBy; + this.UpdatedDatetime = source.UpdatedDatetime; + this.UserName = source.UserName; + + if (includeSystemFields) + { + this.CreatedBy = source.CreatedBy; + this.CreatedDatetime = source.CreatedDatetime; + this.UpdatedBy = source.UpdatedBy; + this.UpdatedDatetime = source.UpdatedDatetime; + } + } + + public override string GetSelectFrom() + { + return $" select {DB_NAME_FIELDS} from { DB_NAME_SECURITY_USER_LOGIN_LOG} "; + } + + public override string GetSelectCountFrom(string sqlWhere) + { + return $" select count(*) from { DB_NAME_SECURITY_USER_LOGIN_LOG} where 1=1 {sqlWhere}"; + } + + public override string GetSelectTopFrom(int limit, int start,string orderby,string orderbytag, string sqlWhere) + { + if (string.IsNullOrEmpty(orderbytag) || orderbytag.Trim() != "desc") orderbytag = "asc"; + if (string.IsNullOrEmpty(orderby) || !DB_NAME_FIELDS.Contains(orderby)) orderby = DB_LOGIN_LOG_ID ; + int offset = limit * (start - 1); + return $" select {DB_NAME_FIELDS} from (select {DB_NAME_FIELDS} ,row_number() over(order by {orderby} {orderbytag}) as num from { DB_NAME_SECURITY_USER_LOGIN_LOG} where 1=1 {sqlWhere} ) a where num> {offset} LIMIT {offset},{limit} "; + } + + public SecurityUserLoginLogEntity Clone() + { + SecurityUserLoginLogEntity result = new SecurityUserLoginLogEntity(); + result.CopyFrom(this); + + return result; + } + + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Entity/SecurityUserPreferenceEntity.auto.cs b/CloudBuilder/CloudBuilder.Security/Entity/SecurityUserPreferenceEntity.auto.cs new file mode 100644 index 0000000..6e296ef --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Entity/SecurityUserPreferenceEntity.auto.cs @@ -0,0 +1,113 @@ + +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +namespace CloudBuilder.Security.Entity + { + [TypeScript] + [Table("security_user_preference")] + public class SecurityUserPreferenceEntity : EntityBase + { + + public SecurityUserPreferenceEntity() + { + } + + [Column("created_by")] + public string CreatedBy { get; set; } + [Column("created_datetime")] + public DateTime CreatedDatetime { get; set; } + [Column("preference")] + public string? Preference { get; set; } + [Column("preference_key")] + public string PreferenceKey { get; set; } + [Column("updated_by")] + public string UpdatedBy { get; set; } + [Column("updated_datetime")] + public DateTime UpdatedDatetime { get; set; } + [Column("username")] + public string Username { get; set; } + + public const string CREATED_BY = "CreatedBy"; + public const string CREATED_DATETIME = "CreatedDatetime"; + public const string PREFERENCE = "Preference"; + public const string PREFERENCE_KEY = "PreferenceKey"; + public const string UPDATED_BY = "UpdatedBy"; + public const string UPDATED_DATETIME = "UpdatedDatetime"; + public const string USERNAME = "Username"; + + public const string DB_NAME_SECURITY_USER_PREFERENCE = "security_user_preference"; + public const string DB_NAME_FIELDS="created_by,created_datetime,preference,preference_key,updated_by,updated_datetime,username"; + + public const string DB_CREATED_BY = "created_by"; + public const string DB_CREATED_DATETIME = "created_datetime"; + public const string DB_PREFERENCE = "preference"; + public const string DB_PREFERENCE_KEY = "preference_key"; + public const string DB_UPDATED_BY = "updated_by"; + public const string DB_UPDATED_DATETIME = "updated_datetime"; + public const string DB_USERNAME = "username"; + + + public static SecurityUserPreferenceEntity GetInstance() + { + return new SecurityUserPreferenceEntity(); + } + + public virtual void CopyFrom(SecurityUserPreferenceEntity source) + { + CopyFrom(source, true); + } + + public virtual void CopyFrom(SecurityUserPreferenceEntity source, bool includeSystemFields) + { + if (source == null) + { + throw new NullReferenceException("Source entity is null."); + } + + this.CreatedBy = source.CreatedBy; + this.CreatedDatetime = source.CreatedDatetime; + this.Preference = source.Preference; + this.PreferenceKey = source.PreferenceKey; + this.UpdatedBy = source.UpdatedBy; + this.UpdatedDatetime = source.UpdatedDatetime; + this.Username = source.Username; + + if (includeSystemFields) + { + this.CreatedBy = source.CreatedBy; + this.CreatedDatetime = source.CreatedDatetime; + this.UpdatedBy = source.UpdatedBy; + this.UpdatedDatetime = source.UpdatedDatetime; + } + } + + public override string GetSelectFrom() + { + return $" select {DB_NAME_FIELDS} from { DB_NAME_SECURITY_USER_PREFERENCE} "; + } + + public override string GetSelectCountFrom(string sqlWhere) + { + return $" select count(*) from { DB_NAME_SECURITY_USER_PREFERENCE} where 1=1 {sqlWhere}"; + } + + public override string GetSelectTopFrom(int limit, int start,string orderby,string orderbytag, string sqlWhere) + { + if (string.IsNullOrEmpty(orderbytag) || orderbytag.Trim() != "desc") orderbytag = "asc"; + if (string.IsNullOrEmpty(orderby) || !DB_NAME_FIELDS.Contains(orderby)) orderby = DB_PREFERENCE_KEY ; + int offset = limit * (start - 1); + return $" select {DB_NAME_FIELDS} from (select {DB_NAME_FIELDS} ,row_number() over(order by {orderby} {orderbytag}) as num from { DB_NAME_SECURITY_USER_PREFERENCE} where 1=1 {sqlWhere} ) a where num> {offset} LIMIT {offset},{limit} "; + } + + public SecurityUserPreferenceEntity Clone() + { + SecurityUserPreferenceEntity result = new SecurityUserPreferenceEntity(); + result.CopyFrom(this); + + return result; + } + + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Entity/SecurityUserPreferenceEntityKey.auto.cs b/CloudBuilder/CloudBuilder.Security/Entity/SecurityUserPreferenceEntityKey.auto.cs new file mode 100644 index 0000000..daa59be --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Entity/SecurityUserPreferenceEntityKey.auto.cs @@ -0,0 +1,33 @@ + +using CloudBuilder.Core.Authorization; +namespace CloudBuilder.Security +{ + [TypeScript] + public class SecurityUserPreferenceEntityKey + { + public string PreferenceKey { get; set; } + public string Username { get; set; } + + public override bool Equals(object obj) + { + if (this == obj) return true; + + SecurityUserPreferenceEntityKey pkey = obj as SecurityUserPreferenceEntityKey; + if (pkey == null) return false; + + if (PreferenceKey != pkey.PreferenceKey) return false; + if (Username != pkey.Username) return false; + + return true; + } + + + public override string ToString() + { + string declareSql=""; + declareSql=declareSql+$"declare @__tkey_PreferenceKey_0 varchar(50) select @__tkey_PreferenceKey_0 ='{PreferenceKey}'; " ; declareSql=declareSql+$"declare @__tkey_Username_1 varchar(50) select @__tkey_Username_1 ='{Username}'; " ; + return declareSql; + } + } + } + /* builder.Entity().HasKey(c => new { c.PreferenceKey, c.Username}); */ diff --git a/CloudBuilder/CloudBuilder.Security/Entity/SecurityUserViewEntity.auto.cs b/CloudBuilder/CloudBuilder.Security/Entity/SecurityUserViewEntity.auto.cs new file mode 100644 index 0000000..3fc9fa1 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Entity/SecurityUserViewEntity.auto.cs @@ -0,0 +1,104 @@ + +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +namespace CloudBuilder.Security.Entity + { + [TypeScript] + [Table("security_user_view")] + public class SecurityUserViewEntity : ViewEntityBase + { + + public SecurityUserViewEntity() + { + } + + [Column("actor_local_name")] + public string? ActorLocalName { get; set; } + [Column("actor_name")] + public string? ActorName { get; set; } + [Column("user_local_name")] + public string UserLocalName { get; set; } + [Column("user_mobile")] + public string? UserMobile { get; set; } + [Column("user_name")] + public string UserName { get; set; } + [Column("welcome_page")] + public string? WelcomePage { get; set; } + + public const string ACTOR_LOCAL_NAME = "ActorLocalName"; + public const string ACTOR_NAME = "ActorName"; + public const string USER_LOCAL_NAME = "UserLocalName"; + public const string USER_MOBILE = "UserMobile"; + public const string USER_NAME = "UserName"; + public const string WELCOME_PAGE = "WelcomePage"; + + public const string DB_NAME_SECURITY_USER_VIEW = "security_user_view"; + public const string DB_NAME_FIELDS="actor_local_name,actor_name,user_local_name,user_mobile,user_name,welcome_page"; + + public const string DB_ACTOR_LOCAL_NAME = "actor_local_name"; + public const string DB_ACTOR_NAME = "actor_name"; + public const string DB_USER_LOCAL_NAME = "user_local_name"; + public const string DB_USER_MOBILE = "user_mobile"; + public const string DB_USER_NAME = "user_name"; + public const string DB_WELCOME_PAGE = "welcome_page"; + + + public static SecurityUserViewEntity GetInstance() + { + return new SecurityUserViewEntity(); + } + + public virtual void CopyFrom(SecurityUserViewEntity source) + { + CopyFrom(source, true); + } + + public virtual void CopyFrom(SecurityUserViewEntity source, bool includeSystemFields) + { + if (source == null) + { + throw new NullReferenceException("Source entity is null."); + } + + this.ActorLocalName = source.ActorLocalName; + this.ActorName = source.ActorName; + this.UserLocalName = source.UserLocalName; + this.UserMobile = source.UserMobile; + this.UserName = source.UserName; + this.WelcomePage = source.WelcomePage; + + if (includeSystemFields) + { + } + } + + public override string GetSelectFrom() + { + return $" select {DB_NAME_FIELDS} from { DB_NAME_SECURITY_USER_VIEW} "; + } + + public override string GetSelectCountFrom(string sqlWhere) + { + return $" select count(*) from { DB_NAME_SECURITY_USER_VIEW} where 1=1 {sqlWhere}"; + } + + public override string GetSelectTopFrom(int limit, int start,string orderby,string orderbytag, string sqlWhere) + { + if (string.IsNullOrEmpty(orderbytag) || orderbytag.Trim() != "desc") orderbytag = "asc"; + + if (string.IsNullOrEmpty(orderby) || !DB_NAME_FIELDS.Contains(orderby)) orderby = DB_ACTOR_LOCAL_NAME ; int offset = limit * (start - 1); + return $" select {DB_NAME_FIELDS} from (select {DB_NAME_FIELDS} ,row_number() over(order by {orderby} {orderbytag}) as num from { DB_NAME_SECURITY_USER_VIEW} where 1=1 {sqlWhere} ) a where num> {offset} LIMIT {offset},{limit} "; + } + + public SecurityUserViewEntity Clone() + { + SecurityUserViewEntity result = new SecurityUserViewEntity(); + result.CopyFrom(this); + + return result; + } + + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Entity/SecurityUserWebLoginEntity.auto.cs b/CloudBuilder/CloudBuilder.Security/Entity/SecurityUserWebLoginEntity.auto.cs new file mode 100644 index 0000000..5636737 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Entity/SecurityUserWebLoginEntity.auto.cs @@ -0,0 +1,114 @@ + +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +namespace CloudBuilder.Security.Entity + { + [TypeScript] + [Table("security_user_web_login")] + public class SecurityUserWebLoginEntity : EntityBase + { + + public SecurityUserWebLoginEntity() + { + } + + [Column("host_ip")] + public string? HostIp { get; set; } + [Column("host_user_agent")] + public string? HostUserAgent { get; set; } + [Column("login_time")] + public DateTime LoginTime { get; set; } + [Column("logout_time")] + public Nullable LogoutTime { get; set; } + [Column("refresh_token")] + public string RefreshToken { get; set; } + [Column("refresh_token_refreshed_time")] + public DateTime RefreshTokenRefreshedTime { get; set; } + [Column("session_id")] + public string SessionId { get; set; } + [Column("username")] + public string Username { get; set; } + + public const string HOST_IP = "HostIp"; + public const string HOST_USER_AGENT = "HostUserAgent"; + public const string LOGIN_TIME = "LoginTime"; + public const string LOGOUT_TIME = "LogoutTime"; + public const string REFRESH_TOKEN = "RefreshToken"; + public const string REFRESH_TOKEN_REFRESHED_TIME = "RefreshTokenRefreshedTime"; + public const string SESSION_ID = "SessionId"; + public const string USERNAME = "Username"; + + public const string DB_NAME_SECURITY_USER_WEB_LOGIN = "security_user_web_login"; + public const string DB_NAME_FIELDS="host_ip,host_user_agent,login_time,logout_time,refresh_token,refresh_token_refreshed_time,session_id,username"; + + public const string DB_HOST_IP = "host_ip"; + public const string DB_HOST_USER_AGENT = "host_user_agent"; + public const string DB_LOGIN_TIME = "login_time"; + public const string DB_LOGOUT_TIME = "logout_time"; + public const string DB_REFRESH_TOKEN = "refresh_token"; + public const string DB_REFRESH_TOKEN_REFRESHED_TIME = "refresh_token_refreshed_time"; + public const string DB_SESSION_ID = "session_id"; + public const string DB_USERNAME = "username"; + + + public static SecurityUserWebLoginEntity GetInstance() + { + return new SecurityUserWebLoginEntity(); + } + + public virtual void CopyFrom(SecurityUserWebLoginEntity source) + { + CopyFrom(source, true); + } + + public virtual void CopyFrom(SecurityUserWebLoginEntity source, bool includeSystemFields) + { + if (source == null) + { + throw new NullReferenceException("Source entity is null."); + } + + this.HostIp = source.HostIp; + this.HostUserAgent = source.HostUserAgent; + this.LoginTime = source.LoginTime; + this.LogoutTime = source.LogoutTime; + this.RefreshToken = source.RefreshToken; + this.RefreshTokenRefreshedTime = source.RefreshTokenRefreshedTime; + this.SessionId = source.SessionId; + this.Username = source.Username; + + if (includeSystemFields) + { + } + } + + public override string GetSelectFrom() + { + return $" select {DB_NAME_FIELDS} from { DB_NAME_SECURITY_USER_WEB_LOGIN} "; + } + + public override string GetSelectCountFrom(string sqlWhere) + { + return $" select count(*) from { DB_NAME_SECURITY_USER_WEB_LOGIN} where 1=1 {sqlWhere}"; + } + + public override string GetSelectTopFrom(int limit, int start,string orderby,string orderbytag, string sqlWhere) + { + if (string.IsNullOrEmpty(orderbytag) || orderbytag.Trim() != "desc") orderbytag = "asc"; + if (string.IsNullOrEmpty(orderby) || !DB_NAME_FIELDS.Contains(orderby)) orderby = DB_SESSION_ID ; + int offset = limit * (start - 1); + return $" select {DB_NAME_FIELDS} from (select {DB_NAME_FIELDS} ,row_number() over(order by {orderby} {orderbytag}) as num from { DB_NAME_SECURITY_USER_WEB_LOGIN} where 1=1 {sqlWhere} ) a where num> {offset} LIMIT {offset},{limit} "; + } + + public SecurityUserWebLoginEntity Clone() + { + SecurityUserWebLoginEntity result = new SecurityUserWebLoginEntity(); + result.CopyFrom(this); + + return result; + } + + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Entity/SecurityUserWebLoginEntityKey.auto.cs b/CloudBuilder/CloudBuilder.Security/Entity/SecurityUserWebLoginEntityKey.auto.cs new file mode 100644 index 0000000..4eb8369 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Entity/SecurityUserWebLoginEntityKey.auto.cs @@ -0,0 +1,33 @@ + +using CloudBuilder.Core.Authorization; +namespace CloudBuilder.Security +{ + [TypeScript] + public class SecurityUserWebLoginEntityKey + { + public string SessionId { get; set; } + public string Username { get; set; } + + public override bool Equals(object obj) + { + if (this == obj) return true; + + SecurityUserWebLoginEntityKey pkey = obj as SecurityUserWebLoginEntityKey; + if (pkey == null) return false; + + if (SessionId != pkey.SessionId) return false; + if (Username != pkey.Username) return false; + + return true; + } + + + public override string ToString() + { + string declareSql=""; + declareSql=declareSql+$"declare @__tkey_SessionId_0 varchar(50) select @__tkey_SessionId_0 ='{SessionId}'; " ; declareSql=declareSql+$"declare @__tkey_Username_1 varchar(50) select @__tkey_Username_1 ='{Username}'; " ; + return declareSql; + } + } + } + /* builder.Entity().HasKey(c => new { c.SessionId, c.Username}); */ diff --git a/CloudBuilder/CloudBuilder.Security/Entity/SecurityUserWebPagePreferenceEntity.auto.cs b/CloudBuilder/CloudBuilder.Security/Entity/SecurityUserWebPagePreferenceEntity.auto.cs new file mode 100644 index 0000000..a06445d --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Entity/SecurityUserWebPagePreferenceEntity.auto.cs @@ -0,0 +1,123 @@ + +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +namespace CloudBuilder.Security.Entity + { + [TypeScript] + [Table("security_user_web_page_preference")] + public class SecurityUserWebPagePreferenceEntity : EntityBase + { + + public SecurityUserWebPagePreferenceEntity() + { + } + + [Column("created_by")] + public string CreatedBy { get; set; } + [Column("created_datetime")] + public DateTime CreatedDatetime { get; set; } + [Column("default_indc")] + public string? DefaultIndc { get; set; } + [Column("preference")] + public string? Preference { get; set; } + [Column("preference_key")] + public string PreferenceKey { get; set; } + [Column("profile_name")] + public string ProfileName { get; set; } + [Column("updated_by")] + public string UpdatedBy { get; set; } + [Column("updated_datetime")] + public DateTime UpdatedDatetime { get; set; } + [Column("username")] + public string Username { get; set; } + + public const string CREATED_BY = "CreatedBy"; + public const string CREATED_DATETIME = "CreatedDatetime"; + public const string DEFAULT_INDC = "DefaultIndc"; + public const string PREFERENCE = "Preference"; + public const string PREFERENCE_KEY = "PreferenceKey"; + public const string PROFILE_NAME = "ProfileName"; + public const string UPDATED_BY = "UpdatedBy"; + public const string UPDATED_DATETIME = "UpdatedDatetime"; + public const string USERNAME = "Username"; + + public const string DB_NAME_SECURITY_USER_WEB_PAGE_PREFERENCE = "security_user_web_page_preference"; + public const string DB_NAME_FIELDS="created_by,created_datetime,default_indc,preference,preference_key,profile_name,updated_by,updated_datetime,username"; + + public const string DB_CREATED_BY = "created_by"; + public const string DB_CREATED_DATETIME = "created_datetime"; + public const string DB_DEFAULT_INDC = "default_indc"; + public const string DB_PREFERENCE = "preference"; + public const string DB_PREFERENCE_KEY = "preference_key"; + public const string DB_PROFILE_NAME = "profile_name"; + public const string DB_UPDATED_BY = "updated_by"; + public const string DB_UPDATED_DATETIME = "updated_datetime"; + public const string DB_USERNAME = "username"; + + + public static SecurityUserWebPagePreferenceEntity GetInstance() + { + return new SecurityUserWebPagePreferenceEntity(); + } + + public virtual void CopyFrom(SecurityUserWebPagePreferenceEntity source) + { + CopyFrom(source, true); + } + + public virtual void CopyFrom(SecurityUserWebPagePreferenceEntity source, bool includeSystemFields) + { + if (source == null) + { + throw new NullReferenceException("Source entity is null."); + } + + this.CreatedBy = source.CreatedBy; + this.CreatedDatetime = source.CreatedDatetime; + this.DefaultIndc = source.DefaultIndc; + this.Preference = source.Preference; + this.PreferenceKey = source.PreferenceKey; + this.ProfileName = source.ProfileName; + this.UpdatedBy = source.UpdatedBy; + this.UpdatedDatetime = source.UpdatedDatetime; + this.Username = source.Username; + + if (includeSystemFields) + { + this.CreatedBy = source.CreatedBy; + this.CreatedDatetime = source.CreatedDatetime; + this.UpdatedBy = source.UpdatedBy; + this.UpdatedDatetime = source.UpdatedDatetime; + } + } + + public override string GetSelectFrom() + { + return $" select {DB_NAME_FIELDS} from { DB_NAME_SECURITY_USER_WEB_PAGE_PREFERENCE} "; + } + + public override string GetSelectCountFrom(string sqlWhere) + { + return $" select count(*) from { DB_NAME_SECURITY_USER_WEB_PAGE_PREFERENCE} where 1=1 {sqlWhere}"; + } + + public override string GetSelectTopFrom(int limit, int start,string orderby,string orderbytag, string sqlWhere) + { + if (string.IsNullOrEmpty(orderbytag) || orderbytag.Trim() != "desc") orderbytag = "asc"; + if (string.IsNullOrEmpty(orderby) || !DB_NAME_FIELDS.Contains(orderby)) orderby = DB_PREFERENCE_KEY ; + int offset = limit * (start - 1); + return $" select {DB_NAME_FIELDS} from (select {DB_NAME_FIELDS} ,row_number() over(order by {orderby} {orderbytag}) as num from { DB_NAME_SECURITY_USER_WEB_PAGE_PREFERENCE} where 1=1 {sqlWhere} ) a where num> {offset} LIMIT {offset},{limit} "; + } + + public SecurityUserWebPagePreferenceEntity Clone() + { + SecurityUserWebPagePreferenceEntity result = new SecurityUserWebPagePreferenceEntity(); + result.CopyFrom(this); + + return result; + } + + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Entity/SecurityUserWebPagePreferenceEntityKey.auto.cs b/CloudBuilder/CloudBuilder.Security/Entity/SecurityUserWebPagePreferenceEntityKey.auto.cs new file mode 100644 index 0000000..0e22370 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Entity/SecurityUserWebPagePreferenceEntityKey.auto.cs @@ -0,0 +1,35 @@ + +using CloudBuilder.Core.Authorization; +namespace CloudBuilder.Security +{ + [TypeScript] + public class SecurityUserWebPagePreferenceEntityKey + { + public string PreferenceKey { get; set; } + public string ProfileName { get; set; } + public string Username { get; set; } + + public override bool Equals(object obj) + { + if (this == obj) return true; + + SecurityUserWebPagePreferenceEntityKey pkey = obj as SecurityUserWebPagePreferenceEntityKey; + if (pkey == null) return false; + + if (PreferenceKey != pkey.PreferenceKey) return false; + if (ProfileName != pkey.ProfileName) return false; + if (Username != pkey.Username) return false; + + return true; + } + + + public override string ToString() + { + string declareSql=""; + declareSql=declareSql+$"declare @__tkey_PreferenceKey_0 varchar(50) select @__tkey_PreferenceKey_0 ='{PreferenceKey}'; " ; declareSql=declareSql+$"declare @__tkey_ProfileName_1 varchar(50) select @__tkey_ProfileName_1 ='{ProfileName}'; " ; declareSql=declareSql+$"declare @__tkey_Username_2 varchar(50) select @__tkey_Username_2 ='{Username}'; " ; + return declareSql; + } + } + } + /* builder.Entity().HasKey(c => new { c.PreferenceKey, c.ProfileName, c.Username}); */ diff --git a/CloudBuilder/CloudBuilder.Security/Entity/SysTablePkeyViewEntity.auto.cs b/CloudBuilder/CloudBuilder.Security/Entity/SysTablePkeyViewEntity.auto.cs new file mode 100644 index 0000000..647e083 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Entity/SysTablePkeyViewEntity.auto.cs @@ -0,0 +1,104 @@ + +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +namespace CloudBuilder.Security.Entity + { + [TypeScript] + [Table("sys_table_pkey_view")] + public class SysTablePkeyViewEntity : ViewEntityBase + { + + public SysTablePkeyViewEntity() + { + } + + [Column("column_name")] + public string? ColumnName { get; set; } + [Column("pk")] + public int Pk { get; set; } + [Column("pk_name")] + public string? PkName { get; set; } + [Column("table_name")] + public string TableName { get; set; } + [Column("table_owner")] + public string TableOwner { get; set; } + [Column("table_qualifier")] + public string? TableQualifier { get; set; } + + public const string COLUMN_NAME = "ColumnName"; + public const string PK = "Pk"; + public const string PK_NAME = "PkName"; + public const string TABLE_NAME = "TableName"; + public const string TABLE_OWNER = "TableOwner"; + public const string TABLE_QUALIFIER = "TableQualifier"; + + public const string DB_NAME_SYS_TABLE_PKEY_VIEW = "sys_table_pkey_view"; + public const string DB_NAME_FIELDS="column_name,pk,pk_name,table_name,table_owner,table_qualifier"; + + public const string DB_COLUMN_NAME = "column_name"; + public const string DB_PK = "pk"; + public const string DB_PK_NAME = "pk_name"; + public const string DB_TABLE_NAME = "table_name"; + public const string DB_TABLE_OWNER = "table_owner"; + public const string DB_TABLE_QUALIFIER = "table_qualifier"; + + + public static SysTablePkeyViewEntity GetInstance() + { + return new SysTablePkeyViewEntity(); + } + + public virtual void CopyFrom(SysTablePkeyViewEntity source) + { + CopyFrom(source, true); + } + + public virtual void CopyFrom(SysTablePkeyViewEntity source, bool includeSystemFields) + { + if (source == null) + { + throw new NullReferenceException("Source entity is null."); + } + + this.ColumnName = source.ColumnName; + this.Pk = source.Pk; + this.PkName = source.PkName; + this.TableName = source.TableName; + this.TableOwner = source.TableOwner; + this.TableQualifier = source.TableQualifier; + + if (includeSystemFields) + { + } + } + + public override string GetSelectFrom() + { + return $" select {DB_NAME_FIELDS} from { DB_NAME_SYS_TABLE_PKEY_VIEW} "; + } + + public override string GetSelectCountFrom(string sqlWhere) + { + return $" select count(*) from { DB_NAME_SYS_TABLE_PKEY_VIEW} where 1=1 {sqlWhere}"; + } + + public override string GetSelectTopFrom(int limit, int start,string orderby,string orderbytag, string sqlWhere) + { + if (string.IsNullOrEmpty(orderbytag) || orderbytag.Trim() != "desc") orderbytag = "asc"; + + if (string.IsNullOrEmpty(orderby) || !DB_NAME_FIELDS.Contains(orderby)) orderby = DB_COLUMN_NAME ; int offset = limit * (start - 1); + return $" select {DB_NAME_FIELDS} from (select {DB_NAME_FIELDS} ,row_number() over(order by {orderby} {orderbytag}) as num from { DB_NAME_SYS_TABLE_PKEY_VIEW} where 1=1 {sqlWhere} ) a where num> {offset} LIMIT {offset},{limit} "; + } + + public SysTablePkeyViewEntity Clone() + { + SysTablePkeyViewEntity result = new SysTablePkeyViewEntity(); + result.CopyFrom(this); + + return result; + } + + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Entity/SysTableSchemaViewEntity.auto.cs b/CloudBuilder/CloudBuilder.Security/Entity/SysTableSchemaViewEntity.auto.cs new file mode 100644 index 0000000..2a15450 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Entity/SysTableSchemaViewEntity.auto.cs @@ -0,0 +1,149 @@ + +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +namespace CloudBuilder.Security.Entity + { + [TypeScript] + [Table("sys_table_schema_view")] + public class SysTableSchemaViewEntity : ViewEntityBase + { + + public SysTableSchemaViewEntity() + { + } + + [Column("colid")] + public long Colid { get; set; } + [Column("field_default_value")] + public string FieldDefaultValue { get; set; } + [Column("field_name")] + public string? FieldName { get; set; } + [Column("find_by")] + public int FindBy { get; set; } + [Column("is_identity")] + public long IsIdentity { get; set; } + [Column("is_null_able")] + public string IsNullAble { get; set; } + [Column("max_length")] + public long MaxLength { get; set; } + [Column("operation")] + public int Operation { get; set; } + [Column("pk")] + public long Pk { get; set; } + [Column("pk_name")] + public string PkName { get; set; } + [Column("scale",TypeName = "decimal(20,0)")] + public decimal Scale { get; set; } + [Column("table_name")] + public string TableName { get; set; } + [Column("type_name")] + public string? TypeName { get; set; } + [Column("type_of_name")] + public string? TypeOfName { get; set; } + [Column("xtype")] + public string? Xtype { get; set; } + + public const string COLID = "Colid"; + public const string FIELD_DEFAULT_VALUE = "FieldDefaultValue"; + public const string FIELD_NAME = "FieldName"; + public const string FIND_BY = "FindBy"; + public const string IS_IDENTITY = "IsIdentity"; + public const string IS_NULL_ABLE = "IsNullAble"; + public const string MAX_LENGTH = "MaxLength"; + public const string OPERATION = "Operation"; + public const string PK = "Pk"; + public const string PK_NAME = "PkName"; + public const string SCALE = "Scale"; + public const string TABLE_NAME = "TableName"; + public const string TYPE_NAME = "TypeName"; + public const string TYPE_OF_NAME = "TypeOfName"; + public const string XTYPE = "Xtype"; + + public const string DB_NAME_SYS_TABLE_SCHEMA_VIEW = "sys_table_schema_view"; + public const string DB_NAME_FIELDS="colid,field_default_value,field_name,find_by,is_identity,is_null_able,max_length,operation,pk,pk_name,scale,table_name,type_name,type_of_name,xtype"; + + public const string DB_COLID = "colid"; + public const string DB_FIELD_DEFAULT_VALUE = "field_default_value"; + public const string DB_FIELD_NAME = "field_name"; + public const string DB_FIND_BY = "find_by"; + public const string DB_IS_IDENTITY = "is_identity"; + public const string DB_IS_NULL_ABLE = "is_null_able"; + public const string DB_MAX_LENGTH = "max_length"; + public const string DB_OPERATION = "operation"; + public const string DB_PK = "pk"; + public const string DB_PK_NAME = "pk_name"; + public const string DB_SCALE = "scale"; + public const string DB_TABLE_NAME = "table_name"; + public const string DB_TYPE_NAME = "type_name"; + public const string DB_TYPE_OF_NAME = "type_of_name"; + public const string DB_XTYPE = "xtype"; + + + public static SysTableSchemaViewEntity GetInstance() + { + return new SysTableSchemaViewEntity(); + } + + public virtual void CopyFrom(SysTableSchemaViewEntity source) + { + CopyFrom(source, true); + } + + public virtual void CopyFrom(SysTableSchemaViewEntity source, bool includeSystemFields) + { + if (source == null) + { + throw new NullReferenceException("Source entity is null."); + } + + this.Colid = source.Colid; + this.FieldDefaultValue = source.FieldDefaultValue; + this.FieldName = source.FieldName; + this.FindBy = source.FindBy; + this.IsIdentity = source.IsIdentity; + this.IsNullAble = source.IsNullAble; + this.MaxLength = source.MaxLength; + this.Operation = source.Operation; + this.Pk = source.Pk; + this.PkName = source.PkName; + this.Scale = source.Scale; + this.TableName = source.TableName; + this.TypeName = source.TypeName; + this.TypeOfName = source.TypeOfName; + this.Xtype = source.Xtype; + + if (includeSystemFields) + { + } + } + + public override string GetSelectFrom() + { + return $" select {DB_NAME_FIELDS} from { DB_NAME_SYS_TABLE_SCHEMA_VIEW} "; + } + + public override string GetSelectCountFrom(string sqlWhere) + { + return $" select count(*) from { DB_NAME_SYS_TABLE_SCHEMA_VIEW} where 1=1 {sqlWhere}"; + } + + public override string GetSelectTopFrom(int limit, int start,string orderby,string orderbytag, string sqlWhere) + { + if (string.IsNullOrEmpty(orderbytag) || orderbytag.Trim() != "desc") orderbytag = "asc"; + + if (string.IsNullOrEmpty(orderby) || !DB_NAME_FIELDS.Contains(orderby)) orderby = DB_COLID ; int offset = limit * (start - 1); + return $" select {DB_NAME_FIELDS} from (select {DB_NAME_FIELDS} ,row_number() over(order by {orderby} {orderbytag}) as num from { DB_NAME_SYS_TABLE_SCHEMA_VIEW} where 1=1 {sqlWhere} ) a where num> {offset} LIMIT {offset},{limit} "; + } + + public SysTableSchemaViewEntity Clone() + { + SysTableSchemaViewEntity result = new SysTableSchemaViewEntity(); + result.CopyFrom(this); + + return result; + } + + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Linkup/SecurityActorOperationLinkup.cs b/CloudBuilder/CloudBuilder.Security/Linkup/SecurityActorOperationLinkup.cs new file mode 100644 index 0000000..48b8e90 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Linkup/SecurityActorOperationLinkup.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Security.Linkup +{ + public class SecurityActorOperationLinkup + { + public int DisplayMode; + + public string ActorName; + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Linkup/SecurityFunctionOperationLinkup.cs b/CloudBuilder/CloudBuilder.Security/Linkup/SecurityFunctionOperationLinkup.cs new file mode 100644 index 0000000..5943f1e --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Linkup/SecurityFunctionOperationLinkup.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Security.Linkup +{ + public class SecurityFunctionOperationLinkup + { + public int DisplayMode; + + public string FunctionName; + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Linkup/SecurityGroupOperationLinkup.cs b/CloudBuilder/CloudBuilder.Security/Linkup/SecurityGroupOperationLinkup.cs new file mode 100644 index 0000000..fb5a1d1 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Linkup/SecurityGroupOperationLinkup.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Security.Linkup +{ + public class SecurityGroupOperationLinkup + { + public int DisplayMode; + + public string GroupName; + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Linkup/SecurityMasterOperationLinkup.cs b/CloudBuilder/CloudBuilder.Security/Linkup/SecurityMasterOperationLinkup.cs new file mode 100644 index 0000000..2c14052 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Linkup/SecurityMasterOperationLinkup.cs @@ -0,0 +1,16 @@ +using CloudBuilder.Security.Entity; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Security.Linkup +{ + public class SecurityMasterOperationLinkup + { + public int DisplayMode; + + public SecurityMasterEntity SecurityMaster; + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Linkup/SecurityPermissionOperationLinkup.cs b/CloudBuilder/CloudBuilder.Security/Linkup/SecurityPermissionOperationLinkup.cs new file mode 100644 index 0000000..dd65db1 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Linkup/SecurityPermissionOperationLinkup.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Security.Linkup +{ + public class SecurityPermissionOperationLinkup + { + public int DisplayMode; + + public string PermissionName; + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Linkup/SecurityUserOperationLinkup.cs b/CloudBuilder/CloudBuilder.Security/Linkup/SecurityUserOperationLinkup.cs new file mode 100644 index 0000000..d293d8e --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Linkup/SecurityUserOperationLinkup.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Security.Linkup +{ + public class SecurityUserOperationLinkup + { + public int DisplayMode; + + public string UserName; + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Policy/CulturePolicy.cs b/CloudBuilder/CloudBuilder.Security/Policy/CulturePolicy.cs new file mode 100644 index 0000000..7e9d5b3 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Policy/CulturePolicy.cs @@ -0,0 +1,52 @@ +using CloudBuilder.Core.DependencyInjection.Form; +using CloudBuilder.Core.DependencyInjection.Policy; +using CloudBuilder.Core.DependencyInjection.Request; +using CloudBuilder.Core.Policy; +using Microsoft.AspNetCore.Http.HttpResults; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.VisualStudio.OLE.Interop; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Channels; +using System.Threading.Tasks; + +namespace CloudBuilder.Security.Policy +{ + + public class CulturePolicy : AbstractPolicy, IPolicy + { + public const string ZH_CN = "zh-cn"; + public const string EN = "en"; + + public static CulturePolicy instance = null; + + public CulturePolicy(IContext context) : base(context) + { + this.values = new string[] { ZH_CN, EN }; + } + + public static CulturePolicy GetInstance() + { + instance = ApplicationServiceContext.ServiceProvider.GetKeyedService(typeof(CulturePolicy).Name); + return instance; + } + + //public class CulturePolicy : LocalePolicy, IPolicy + //public CulturePolicy(IContext context, ILocaleMessageManager localeMessageManager) : base(context, localeMessageManager) + //{ + // this.context = context; + // this.localeMessageManager = localeMessageManager; + + // this.values = new string[] { ZH_CN, EN }; + // this.Name = typeof(CulturePolicy).Name; + //} + + + public static bool IsZhcn(string value) + { + return value == ZH_CN; + } + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Policy/CulturePolicy_en.resx b/CloudBuilder/CloudBuilder.Security/Policy/CulturePolicy_en.resx new file mode 100644 index 0000000..61284c8 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Policy/CulturePolicy_en.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + English + + + Chinaese + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Security/Policy/CulturePolicy_zh-cn.resx b/CloudBuilder/CloudBuilder.Security/Policy/CulturePolicy_zh-cn.resx new file mode 100644 index 0000000..7c33192 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Policy/CulturePolicy_zh-cn.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 英文 + + + 中文 + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Security/Policy/FileTypePolicy.cs b/CloudBuilder/CloudBuilder.Security/Policy/FileTypePolicy.cs new file mode 100644 index 0000000..a671cb0 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Policy/FileTypePolicy.cs @@ -0,0 +1,126 @@ +using CloudBuilder.Core.DatabaseAccessor.Entity; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Security.Policy +{ + public class FileTypePolicy + { + public const string VIDEO = "V"; + public const string AUDIO = "A"; + public const string PHOTO = "P"; + public const string DOCUMENT = "D"; + public const string LYRIC = "L"; + + public static string GetType(string value) + { + if (string.IsNullOrEmpty(value)) return DOCUMENT; + else if (value.ToLower().Contains(".lrc")) return LYRIC; + + else if (value.ToLower().Contains(".jpg") || value.ToLower().Contains(".png") || + value.ToLower().Contains(".webp") || value.ToLower().Contains(".bmp") || + value.ToLower().Contains(".gif") || value.ToLower().Contains(".jpeg")) return PHOTO; + + else if (value.ToLower().Contains(".avi") || value.ToLower().Contains(".mpeg") || + value.ToLower().Contains(".mov") || value.ToLower().Contains(".wmv") || + value.ToLower().Contains(".mp4") || value.ToLower().Contains(".mkv") || + value.ToLower().Contains(".flv") || value.ToLower().Contains(".rm")) return VIDEO; + + else if (value.ToLower().Contains(".mp3") || value.ToLower().Contains(".wav") || + value.ToLower().Contains(".flac") || value.ToLower().Contains(".ape") || + value.ToLower().Contains(".wma") || value.ToLower().Contains(".mid")) return AUDIO; + + return DOCUMENT; + } + + + public static bool IsAudio(string value) + { + return GetType(value) == AUDIO; + } + + public static bool IsPhoto(string value) + { + return GetType(value) == PHOTO; + } + + public static bool IsVideo(string value) + { + return GetType(value) == VIDEO; + } + + public static bool IsLyric(string value) + { + return GetType(value) == LYRIC; + } + + + public static string PackUrl(IApplicationService service, string createdBy, string orderKey, string transcodeIndc) + { + string url = string.Empty; + var webRootPath = service.Configuration["FileServiceSettings:RequestPath"]; + var phy = service.Configuration["FileServiceSettings:PhysicalFileDirectory"]; + + var fileExtension = Path.GetExtension(orderKey);//获取文件格式,拓展名 + if (GetType(orderKey!) == FileTypePolicy.PHOTO) + { + if (transcodeIndc == YesNoPolicy.YES) + { + var backup = service.Configuration["FileServiceSettings:BackupDmsFileDirectory"].Replace(phy, ""); + var filePath = $"{backup.Replace("\\", "/")}/{createdBy}/{fileExtension.Replace(".", "")}/"; + url = service.Configuration["applicationUrl"] + webRootPath + filePath + orderKey; + } + else + { + var scale = service.Configuration["FileServiceSettings:ScaleDmsFileDirectory"].Replace(phy, ""); + var filePath = $"{scale.Replace("\\", "/")}/{createdBy}/{fileExtension.Replace(".", "")}/"; + url = service.Configuration["applicationUrl"] + webRootPath + filePath + orderKey; + } + } + else if (GetType(orderKey!) == FileTypePolicy.AUDIO) + { + var backup = service.Configuration["FileServiceSettings:BackupDmsFileDirectory"].Replace(phy, ""); + var filePath = $"{backup.Replace("\\", "/")}/{createdBy}/{fileExtension.Replace(".", "")}/"; + url = service.Configuration["applicationUrl"] + webRootPath + filePath + orderKey; + } + else if (GetType(orderKey!) == FileTypePolicy.VIDEO) + { + if (transcodeIndc == YesNoPolicy.YES) + { + var upload = service.Configuration["FileServiceSettings:UploadDmsFileDirectory"].Replace(phy, ""); + var filePath = $"{upload.Replace("\\", "/")}/{createdBy}/m3u8/"; + url = service.Configuration["applicationUrl"] + webRootPath + filePath + Path.GetFileNameWithoutExtension(orderKey) + "/main.m3u8"; + } + else + { + var backup = service.Configuration["FileServiceSettings:BackupDmsFileDirectory"].Replace(phy, ""); + var filePath = $"{backup.Replace("\\", "/")}/{createdBy}/{fileExtension.Replace(".", "")}/"; + url = service.Configuration["applicationUrl"] + webRootPath + filePath + orderKey; + } + } + + return url; + } + + public static string PackSourceVideoUrl(IApplicationService service, string createdBy, string orderKey) + { + var webRootPath = service.Configuration["FileServiceSettings:RequestPath"]; + var phy = service.Configuration["FileServiceSettings:PhysicalFileDirectory"]; + var upload = service.Configuration["FileServiceSettings:BackupDmsFileDirectory"].Replace(phy, ""); + var fileExtension = Path.GetExtension(orderKey);//获取文件格式,拓展名 + var filePath = $"{upload.Replace("\\", "/")}/{createdBy}/{fileExtension.Replace(".", "")}/"; + return service.Configuration["applicationUrl"] + webRootPath + filePath + orderKey; + + } + public static string PackFilePath(IApplicationService service, string createdBy, string orderKey) + { + var backup = service.Configuration["FileServiceSettings:BackupDmsFileDirectory"]!; + var fileExtension = Path.GetExtension(orderKey).Replace(".", "");//获取文件格式,拓展名 + + return Path.Combine(backup, createdBy, fileExtension, orderKey); + } + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Policy/OperationContractPolicy.cs b/CloudBuilder/CloudBuilder.Security/Policy/OperationContractPolicy.cs new file mode 100644 index 0000000..ec42ca0 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Policy/OperationContractPolicy.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Security.Policy +{ + public class OperationContractPolicy + { + public const string FIND_BY_KEY = "FindByKey"; + public const string FIND_BY_PREDICATE = "FindByPredicate"; + public const string FIND_BY_SEARCH_CRITERIA = "FindBySearchCriteria"; + public const string SEARCH = "SEARCH"; + public const string CREATE = "Create"; + public const string AMEND = "Amend"; + public const string DELETE = "Delete"; + public const string UPDATE = "Amend"; + + public OperationContractPolicy() { } + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Policy/SecurityMessagePolicy.cs b/CloudBuilder/CloudBuilder.Security/Policy/SecurityMessagePolicy.cs new file mode 100644 index 0000000..babd304 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Policy/SecurityMessagePolicy.cs @@ -0,0 +1,75 @@ +using CloudBuilder.Core.DependencyInjection.Policy; +using CloudBuilder.Core.DependencyInjection.Request; +using CloudBuilder.Core.Policy; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Security.Policy +{ + public class SecurityMessagePolicy : LocalePolicy, IPolicy + { + public static string REFRESH = "refresh"; + public static string LOCKED = "locked"; + public static string EXPIRED = "expired"; + public static string GUI_REPORT_PRINT = "gui_report_print"; + public static string GUI_WS_RECORD_EXISTED = "gui_ws_record_existed"; + public static string GUI_WS_RECORD_NOT_FOUND = "gui_ws_record_not_found"; + public static string GUI_WS_RECORD_NOT_FOUND_ID = "gui_ws_record_not_found_id"; + public static string GUI_CONFIRM = "gui_confirm"; + public static string GUI_CONFIRM_APPROVAL_NULL = "gui_confirm_approval_null"; + public static string GUI_CONFIRM_CANCEL = "gui_confirm_cancel"; + public static string GUI_CONFIRM_CANCEL_APPROVAL_NULL = "gui_confirm_cancel_approval_null"; + public static string GUI_CONFIRM_DEL = "gui_confirm_del"; + public static string GUI_CONFIRM_DEL_NULL = "gui_confirm_del_null"; + public static string GUI_CONFIRM_DEL_NUM = "gui_confirm_del_num"; + public static string GUI_CONFIRM_DEL_SHORT = "gui_confirm_del_short"; + public static string GUI_CONFIRM_OPEN = "gui_confirm_open"; + public static string GUI_CONFIRM_REVERT_NULL = "gui_confirm_revert_null"; + public static string GUI_DELETE = "gui_delete"; + public static string GUI_OPEN = "gui_open"; + public static string GUI_SUCCEED_APPROVE_NULL = "gui_succeed_approve_null"; + public static string GUI_SUCCEED_CANCEL_REVERT_NULL = "gui_succeed_cancel_revert_null"; + public static string GUI_SUCCEED_CANCEL_SUBMIT_NULL = "gui_succeed_cancel_submit_null"; + public static string GUI_SUCCEED_CREATED = "gui_succeed_created"; + public static string GUI_SUCCEED_CREATED_NULL = "gui_succeed_created_null"; + public static string GUI_SUCCEED_CREATED_SHORT = "gui_succeed_created_short"; + public static string GUI_SUCCEED_DELETED = "gui_succeed_deleted"; + public static string GUI_SUCCEED_DELETED_NULL = "gui_succeed_deleted_null"; + public static string GUI_SUCCEED_DELETED_SHORT = "gui_succeed_deleted_short"; + public static string GUI_SUCCEED_RECEIVE_NULL = "gui_succeed_receive_null"; + public static string GUI_SUCCEED_REVERT_NULL = "gui_succeed_revert_null"; + public static string GUI_SUCCEED_SAVED_NULL = "gui_succeed_saved_null"; + public static string GUI_SUCCEED_SEND_MAIL_NULL = "gui_succeed_send_mail_null"; + public static string GUI_SUCCEED_SUBMIT_NULL = "gui_succeed_submit_null"; + public static string GUI_SUCCEED_UPDATED = "gui_succeed_updated"; + public static string GUI_SUCCEED_UPDATED_NULL = "gui_succeed_updated_null"; + public static string GUI_SUCCEED_UPDATED_RECORD = "gui_succeed_updated_record"; + public static string GUI_SUCCEED_UPDATED_SHORT = "gui_succeed_updated_short"; + public static string GUI_TITLE_CONFIRMATION = "gui_title_confirmation"; + public static string GUI_VALID_INPUT = "gui_valid_input"; + public static string GUI_VALID_SELECT = "gui_valid_select"; + public static string GUI_VALID_SELECT_RECORD = "gui_valid_select_record"; + public static string WEB_EXCEPTION_MESSAGE = "web_exception_message"; + + private readonly IContext context; + private readonly ILocaleMessageManager localeMessageManager; + + public SecurityMessagePolicy(IContext context, ILocaleMessageManager localeMessageManager) : base(context, localeMessageManager) + { + this.context = context; + this.localeMessageManager = localeMessageManager; + + this.Name = typeof(SecurityMessagePolicy).Name; + } + + } +} + +/* +INSERT INTO [dbo].[locale]([created_datetime],[created_by],[updated_datetime],[updated_by],[group_name],[lang],[name],[value],[order_by]) VALUES +(GETDATE(),'patch',GETDATE(),'patch','SecurityMessagePolicy','zh-cn','gui_valid_select',N'请选择一个有效的{0}。',0), +(GETDATE(),'patch',GETDATE(),'patch','SecurityMessagePolicy','en','gui_valid_select',N'Please select a valid {0}',0) +*/ diff --git a/CloudBuilder/CloudBuilder.Security/Policy/SecurityPermissionPolicy.auto.cs b/CloudBuilder/CloudBuilder.Security/Policy/SecurityPermissionPolicy.auto.cs new file mode 100644 index 0000000..3348591 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Policy/SecurityPermissionPolicy.auto.cs @@ -0,0 +1,18 @@ +namespace CloudBuilder.Security.Policy +{ + public partial class SecurityPermissionPolicy + { + //***BEGIN*** + public const string SecurityUser = "SecurityUser"; + public const string SecurityMaster = "SecurityMaster"; + public const string SecurityGeneratorNumber = "SecurityGeneratorNumber"; + public const string SecurityPermission = "SecurityPermission"; + public const string SecurityFunction = "SecurityFunction"; + public const string SecurityGroup = "SecurityGroup"; + public const string SecurityActor = "SecurityActor"; + public const string Locale = "Locale"; + public const string SecurityUserPreference = "SecurityUserPreference"; + public const string SecurityLock = "SecurityLock"; + //***END*** + } +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Security/Policy/SecurityPermissionPolicy.cs b/CloudBuilder/CloudBuilder.Security/Policy/SecurityPermissionPolicy.cs new file mode 100644 index 0000000..480e39d --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Policy/SecurityPermissionPolicy.cs @@ -0,0 +1,13 @@ +using CloudBuilder.Core.Authorization; + +namespace CloudBuilder.Security.Policy +{ + /// + /// 用戶自定义文件-功能名称 + /// + [TypeScript] + public partial class SecurityPermissionPolicy + { + public const string CanSeeAllUser = "CanSeeAllUser"; + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Policy/SecurityPrefixPolicy.cs b/CloudBuilder/CloudBuilder.Security/Policy/SecurityPrefixPolicy.cs new file mode 100644 index 0000000..14249c8 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Policy/SecurityPrefixPolicy.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Security.Policy +{ + public class SecurityPrefixPolicy + { + public const string SECURITY_USER = "SECURITY_USER"; + public const string SECURITY_USER_USER_NAME = "USER_NAME"; + public const string SECURITY_USER_FORMAT = "000000"; + + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Policy/SecuritySettingsPolicy.cs b/CloudBuilder/CloudBuilder.Security/Policy/SecuritySettingsPolicy.cs new file mode 100644 index 0000000..086f23e --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Policy/SecuritySettingsPolicy.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Security.Policy +{ + public class SecuritySettingsPolicy + { + public const string SecuritySettings_RsaPublicKey = "SecuritySettings:RsaPublicKey"; + + public const string SecuritySettings_RsaPrivateKey = "SecuritySettings:RsaPrivateKey"; + + public const string SecuritySettings_DescKey = "SecuritySettings:DescKey"; + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Policy/SecurityUserPolicy.cs b/CloudBuilder/CloudBuilder.Security/Policy/SecurityUserPolicy.cs new file mode 100644 index 0000000..7c050f4 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Policy/SecurityUserPolicy.cs @@ -0,0 +1,23 @@ +using CloudBuilder.Core.Authorization; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Security.Policy +{ + [TypeScript] + public class SecurityUserPolicy + { + /// + /// 普通用户首次注册给予的角色 + /// + public const string SECURITY_USER_BASE_ACTOR = "SecurityUserBaseActor"; + + /// + /// 用户登录可以出错的次数 + /// + public const int ERROR_LOGIN_COUNT = 5; + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Policy/SecurityUserTypePolicy.cs b/CloudBuilder/CloudBuilder.Security/Policy/SecurityUserTypePolicy.cs new file mode 100644 index 0000000..537b75c --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Policy/SecurityUserTypePolicy.cs @@ -0,0 +1,57 @@ +using CloudBuilder.Core.DependencyInjection.Policy; +using CloudBuilder.Core.DependencyInjection.Request; +using CloudBuilder.Core.Policy; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Security.Policy +{ + public class SecurityUserTypePolicy : LocalePolicy, IPolicy + { + public const string NORMAL_USERS = "N"; + public const string ICTI_USERS = "I"; + public const string SEDEX_USERS = "S"; + public const string KOHLS_USERS = "K"; + + private readonly IContext context; + private readonly ILocaleMessageManager localeMessageManager; + + public SecurityUserTypePolicy(IContext context, ILocaleMessageManager localeMessageManager) : base(context, localeMessageManager) + { + this.context = context; + this.localeMessageManager = localeMessageManager; + + this.Name = typeof(SecurityUserTypePolicy).Name; + } + + + public static bool IsNormalUser(string code) + { + return code == NORMAL_USERS; + } + + public static bool IsIctiUser(string code) + { + return code == ICTI_USERS; + } + + public static bool IsSedexUser(string code) + { + return code == SEDEX_USERS; + } + + public static bool IsKohlsUser(string code) + { + return code == KOHLS_USERS; + } + + + public static bool IsAuditor(string code) + { + return IsIctiUser(code) || IsSedexUser(code) || IsKohlsUser(code); + } + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Publisher/ISecurityUserRegisterPublisher.cs b/CloudBuilder/CloudBuilder.Security/Publisher/ISecurityUserRegisterPublisher.cs new file mode 100644 index 0000000..587d50d --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Publisher/ISecurityUserRegisterPublisher.cs @@ -0,0 +1,18 @@ +using CloudBuilder.Core.DependencyInjection.EventBuses; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Security.Publisher +{ + public interface ISecurityUserRegisterPublisher : IEventPublisher + { + /// + /// 同步发布指定事件,并指定事件源 + /// + /// 事件数据 + void Publish(EventData eventData); + } +} diff --git a/CloudBuilder/CloudBuilder.Security/SearchCriteria/LocaleSearchCriteria.auto.cs b/CloudBuilder/CloudBuilder.Security/SearchCriteria/LocaleSearchCriteria.auto.cs new file mode 100644 index 0000000..2508317 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/SearchCriteria/LocaleSearchCriteria.auto.cs @@ -0,0 +1,10 @@ +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.Service; +namespace CloudBuilder.Security.SearchCriteria +{ + [TypeScript] + public class LocaleSearchCriteria: AbstractSearchCriteria + { + + } +} diff --git a/CloudBuilder/CloudBuilder.Security/SearchCriteria/SecurityActorSearchCriteria.auto.cs b/CloudBuilder/CloudBuilder.Security/SearchCriteria/SecurityActorSearchCriteria.auto.cs new file mode 100644 index 0000000..9e2d388 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/SearchCriteria/SecurityActorSearchCriteria.auto.cs @@ -0,0 +1,13 @@ +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.Service; +namespace CloudBuilder.Security.SearchCriteria +{ + [TypeScript] + public class SecurityActorSearchCriteria: AbstractSearchCriteria + { + public SecurityActorSearchCriteria() + { + limit = 30; + } + } +} diff --git a/CloudBuilder/CloudBuilder.Security/SearchCriteria/SecurityFunctionSearchCriteria.auto.cs b/CloudBuilder/CloudBuilder.Security/SearchCriteria/SecurityFunctionSearchCriteria.auto.cs new file mode 100644 index 0000000..681ae18 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/SearchCriteria/SecurityFunctionSearchCriteria.auto.cs @@ -0,0 +1,20 @@ + +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.Service; +namespace CloudBuilder.Security.SearchCriteria +{ + [TypeScript] + public class SecurityFunctionSearchCriteria : AbstractSearchCriteria + { + public SecurityFunctionSearchCriteria() + { + limit = 30; + } + public string? FunctionLocalName { get; set; } + public string? FunctionName { get; set; } + + public string? FunctionIndc { get; set; } + + public bool? FunctionIndcEnable { get; set; } + } +} diff --git a/CloudBuilder/CloudBuilder.Security/SearchCriteria/SecurityGeneratorNumberSearchCriteria.auto.cs b/CloudBuilder/CloudBuilder.Security/SearchCriteria/SecurityGeneratorNumberSearchCriteria.auto.cs new file mode 100644 index 0000000..77b7503 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/SearchCriteria/SecurityGeneratorNumberSearchCriteria.auto.cs @@ -0,0 +1,10 @@ +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.Service; +namespace CloudBuilder.Security.SearchCriteria +{ + [TypeScript] + public class SecurityGeneratorNumberSearchCriteria: AbstractSearchCriteria + { + + } +} diff --git a/CloudBuilder/CloudBuilder.Security/SearchCriteria/SecurityGroupSearchCriteria.auto.cs b/CloudBuilder/CloudBuilder.Security/SearchCriteria/SecurityGroupSearchCriteria.auto.cs new file mode 100644 index 0000000..b9edebe --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/SearchCriteria/SecurityGroupSearchCriteria.auto.cs @@ -0,0 +1,10 @@ +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.Service; +namespace CloudBuilder.Security.SearchCriteria +{ + [TypeScript] + public class SecurityGroupSearchCriteria: AbstractSearchCriteria + { + + } +} diff --git a/CloudBuilder/CloudBuilder.Security/SearchCriteria/SecurityLockSearchCriteria.auto.cs b/CloudBuilder/CloudBuilder.Security/SearchCriteria/SecurityLockSearchCriteria.auto.cs new file mode 100644 index 0000000..d5882c4 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/SearchCriteria/SecurityLockSearchCriteria.auto.cs @@ -0,0 +1,10 @@ +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.Service; +namespace CloudBuilder.Security.SearchCriteria +{ + [TypeScript] + public class SecurityLockSearchCriteria: AbstractSearchCriteria + { + + } +} diff --git a/CloudBuilder/CloudBuilder.Security/SearchCriteria/SecurityMasterSearchCriteria.auto.cs b/CloudBuilder/CloudBuilder.Security/SearchCriteria/SecurityMasterSearchCriteria.auto.cs new file mode 100644 index 0000000..23b623a --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/SearchCriteria/SecurityMasterSearchCriteria.auto.cs @@ -0,0 +1,13 @@ +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.Service; +namespace CloudBuilder.Security.SearchCriteria +{ + [TypeScript] + public class SecurityMasterSearchCriteria: AbstractSearchCriteria + { + public SecurityMasterSearchCriteria() + { + limit = 30; + } + } +} diff --git a/CloudBuilder/CloudBuilder.Security/SearchCriteria/SecurityPermissionSearchCriteria.auto.cs b/CloudBuilder/CloudBuilder.Security/SearchCriteria/SecurityPermissionSearchCriteria.auto.cs new file mode 100644 index 0000000..3deefe7 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/SearchCriteria/SecurityPermissionSearchCriteria.auto.cs @@ -0,0 +1,18 @@ +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.Service; +namespace CloudBuilder.Security.SearchCriteria +{ + [TypeScript] + public class SecurityPermissionSearchCriteria: AbstractSearchCriteria + { + public string? PermissionName { get; set; } + + public string? Dependent { get; set; } + + public bool? DependentEnable { get; set; } + public SecurityPermissionSearchCriteria() + { + limit = 30; + } + } +} diff --git a/CloudBuilder/CloudBuilder.Security/SearchCriteria/SecurityUserPreferenceSearchCriteria.auto.cs b/CloudBuilder/CloudBuilder.Security/SearchCriteria/SecurityUserPreferenceSearchCriteria.auto.cs new file mode 100644 index 0000000..1c3f985 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/SearchCriteria/SecurityUserPreferenceSearchCriteria.auto.cs @@ -0,0 +1,10 @@ +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.Service; +namespace CloudBuilder.Security.SearchCriteria +{ + [TypeScript] + public class SecurityUserPreferenceSearchCriteria: AbstractSearchCriteria + { + + } +} diff --git a/CloudBuilder/CloudBuilder.Security/SearchCriteria/SecurityUserSearchCriteria.auto.cs b/CloudBuilder/CloudBuilder.Security/SearchCriteria/SecurityUserSearchCriteria.auto.cs new file mode 100644 index 0000000..b1afdb5 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/SearchCriteria/SecurityUserSearchCriteria.auto.cs @@ -0,0 +1,14 @@ +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.Service; +namespace CloudBuilder.Security.SearchCriteria +{ + [TypeScript] + public class SecurityUserSearchCriteria: AbstractSearchCriteria + { + public SecurityUserSearchCriteria() + { + limit = 30; + } + public string? UserName { get; set; } + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Service/IAuthService.cs b/CloudBuilder/CloudBuilder.Security/Service/IAuthService.cs new file mode 100644 index 0000000..44c7a62 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Service/IAuthService.cs @@ -0,0 +1,39 @@ +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.Service; +using CloudBuilder.Security.Data; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Security.Service +{ + public interface IAuthService : IService + { + LoginProfile Login(LoginData data); + + string Register(RegisterData data); + + JwtInfo RefreshToken(JwtInfo jwtInfo); + + LoginProfile LoginAgent(LoginData data); + + LoginProfile AmendPassword(LoginData data); + + void Logout(); + + string GetRsaPublicKey(); + + BiometricLoginChallengeDto BeginBiometricLogin(string username); + + LoginProfile FinishBiometricLogin(FinishBiometricLoginData dto); + + bool ConfirmPassword(string password); + + string BeginBiometricRegistration(string deviceName); + BiometricRegistrationResultDto FinishBiometricRegistration(FinishBiometricRegistrationData dto); + + void RemoveBiometric(); + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Service/ILocaleService.auto.cs b/CloudBuilder/CloudBuilder.Security/Service/ILocaleService.auto.cs new file mode 100644 index 0000000..29fe052 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Service/ILocaleService.auto.cs @@ -0,0 +1,17 @@ + +using CloudBuilder.Core.DatabaseAccessor.Entity; +using CloudBuilder.Core.Service; +using CloudBuilder.Security.Data; +using CloudBuilder.Security.Entity; +using CloudBuilder.Security.SearchCriteria; + +namespace CloudBuilder.Security.Service +{ + public interface ILocaleService : IServiceBase + { + LocaleEntity[] FindAll(); + LocaleResultData FindBySearchCriteria(LocaleSearchCriteria tc); + + void UpdateLocaleData(LocaleData data); + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Service/ISecurityActorService.auto.cs b/CloudBuilder/CloudBuilder.Security/Service/ISecurityActorService.auto.cs new file mode 100644 index 0000000..b78c059 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Service/ISecurityActorService.auto.cs @@ -0,0 +1,21 @@ + +using CloudBuilder.Core.Service; +using CloudBuilder.Security.Data; +using CloudBuilder.Security.Entity; +using CloudBuilder.Security.SearchCriteria; +using Microsoft.AspNetCore.Mvc; + +namespace CloudBuilder.Security.Service +{ + public interface ISecurityActorService :IServiceBase + { + SecurityActorEntity[] FindAll(); + + SecurityActorEntity[] FindAllByNoPermission(); + + SecurityActorResultData FindBySearchCriteria(SecurityActorSearchCriteria tc); + dynamic PrintBySearchCriteria(SecurityActorSearchCriteria tc); + + void Deletes(string[] keys); + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Service/ISecurityFunctionService.cs b/CloudBuilder/CloudBuilder.Security/Service/ISecurityFunctionService.cs new file mode 100644 index 0000000..fab21bf --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Service/ISecurityFunctionService.cs @@ -0,0 +1,20 @@ + + +using CloudBuilder.Core.Service; +using CloudBuilder.Security.Data; +using CloudBuilder.Security.Entity; +using CloudBuilder.Security.SearchCriteria; +using Microsoft.AspNetCore.Mvc; + +namespace CloudBuilder.Security.Service +{ + public interface ISecurityFunctionService : IServiceBase + { + SecurityFunctionResultData FindBySearchCriteria(SecurityFunctionSearchCriteria tc); + dynamic PrintBySearchCriteria(SecurityFunctionSearchCriteria tc); + SecurityFunctionEntity FindByFunctionName(string functionName); + SecurityFunctionDisplayData[] FindMenus(); + + void Deletes(string[] keys); + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Service/ISecurityGeneratorNumberService.auto.cs b/CloudBuilder/CloudBuilder.Security/Service/ISecurityGeneratorNumberService.auto.cs new file mode 100644 index 0000000..c5644f5 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Service/ISecurityGeneratorNumberService.auto.cs @@ -0,0 +1,23 @@ + +using CloudBuilder.Core.Service; +using CloudBuilder.Security.Data; +using CloudBuilder.Security.Entity; +using CloudBuilder.Security.SearchCriteria; +using Microsoft.AspNetCore.Mvc; + +namespace CloudBuilder.Security.Service +{ + public interface ISecurityGeneratorNumberService :IServiceBase + { + SecurityGeneratorNumberResultData FindBySearchCriteria(SecurityGeneratorNumberSearchCriteria tc); + dynamic PrintBySearchCriteria(SecurityGeneratorNumberSearchCriteria tc); + string GetNo(string systemId, string subsystemId); + string GetNo(string systemId, string subsystemId, string prefix); + string GetNo(string systemId, string subsystemId, string prefix, string refreshPeriod, string format); + + int GetNextId(string systemId, string subsystemId); + int GetNextId(string systemId, string subsystemId, string prefix); + int GetNextId(string systemId, string subsystemId, string prefix, string format); + int GetNextId(string systemId, string subsystemId, string prefix, string format, int length); + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Service/ISecurityGroupService.cs b/CloudBuilder/CloudBuilder.Security/Service/ISecurityGroupService.cs new file mode 100644 index 0000000..27d11a5 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Service/ISecurityGroupService.cs @@ -0,0 +1,19 @@ + +using CloudBuilder.Core.Service; +using CloudBuilder.Security.Data; +using CloudBuilder.Security.Entity; +using CloudBuilder.Security.SearchCriteria; +using Microsoft.AspNetCore.Mvc; + +namespace CloudBuilder.Security.Service +{ + public interface ISecurityGroupService :IServiceBase + { + SecurityGroupEntity[] FindAll(); + + SecurityGroupResultData FindBySearchCriteria(SecurityGroupSearchCriteria tc); + dynamic PrintBySearchCriteria(SecurityGroupSearchCriteria tc); + + void Deletes(string[] keys); + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Service/ISecurityLockService.auto.cs b/CloudBuilder/CloudBuilder.Security/Service/ISecurityLockService.auto.cs new file mode 100644 index 0000000..ee60ead --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Service/ISecurityLockService.auto.cs @@ -0,0 +1,22 @@ + +using CloudBuilder.Security.Entity; +using CloudBuilder.Security.SearchCriteria; +using CloudBuilder.Core.Service; + +namespace CloudBuilder.Security.Service +{ + public interface ISecurityLockService :IServiceBase + { + bool IsLocked(string entityName, string key); + + void Lock(string entityName, string key, string username); + + void ForceLock(string entityName, string key, string username); + + void ConsumeLock(string entityName, string key, string username); + + void ClearLock(string entityName, string key); + + + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Service/ISecurityMasterService.auto.cs b/CloudBuilder/CloudBuilder.Security/Service/ISecurityMasterService.auto.cs new file mode 100644 index 0000000..b668cb2 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Service/ISecurityMasterService.auto.cs @@ -0,0 +1,20 @@ + +using CloudBuilder.Core.Service; +using CloudBuilder.Security.Data; +using CloudBuilder.Security.Entity; +using CloudBuilder.Security.SearchCriteria; +using Microsoft.AspNetCore.Mvc; + +namespace CloudBuilder.Security.Service +{ + public interface ISecurityMasterService :IServiceBase + { + SecurityMasterEntity[] FindAll(); + + SecurityMasterResultData FindBySearchCriteria(SecurityMasterSearchCriteria tc); + dynamic PrintBySearchCriteria(SecurityMasterSearchCriteria tc); + + void Deletes(SecurityMasterEntity[] datas); + + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Service/ISecurityPermissionService.cs b/CloudBuilder/CloudBuilder.Security/Service/ISecurityPermissionService.cs new file mode 100644 index 0000000..f7ab87b --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Service/ISecurityPermissionService.cs @@ -0,0 +1,19 @@ + +using CloudBuilder.Core.Service; +using CloudBuilder.Security.Data; +using CloudBuilder.Security.Entity; +using CloudBuilder.Security.SearchCriteria; +using Microsoft.AspNetCore.Mvc; + +namespace CloudBuilder.Security.Service +{ + public interface ISecurityPermissionService : IServiceBase + { + SecurityPermissionResultData FindDependentBySearchCriteria(SecurityPermissionSearchCriteria tc); + SecurityPermissionResultData FindBySearchCriteria(SecurityPermissionSearchCriteria tc); + dynamic PrintBySearchCriteria(SecurityPermissionSearchCriteria tc); + SecurityPermissionResultData FindDependentsBySearchCriteria(SecurityPermissionSearchCriteria criteria); + + void Deletes(string[] keys); + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Service/ISecurityUserPreferenceService.auto.cs b/CloudBuilder/CloudBuilder.Security/Service/ISecurityUserPreferenceService.auto.cs new file mode 100644 index 0000000..a59bde8 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Service/ISecurityUserPreferenceService.auto.cs @@ -0,0 +1,15 @@ + +using CloudBuilder.Core.Service; +using CloudBuilder.Security.Data; +using CloudBuilder.Security.Entity; +using CloudBuilder.Security.SearchCriteria; +using Microsoft.AspNetCore.Mvc; + +namespace CloudBuilder.Security.Service +{ + public interface ISecurityUserPreferenceService :IServiceBase + { + SecurityUserPreferenceEntity[] FindBySearchCriteria(SecurityUserPreferenceSearchCriteria tc); + dynamic PrintBySearchCriteria(SecurityUserPreferenceSearchCriteria tc); + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Service/ISecurityUserService.auto.cs b/CloudBuilder/CloudBuilder.Security/Service/ISecurityUserService.auto.cs new file mode 100644 index 0000000..3576815 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Service/ISecurityUserService.auto.cs @@ -0,0 +1,23 @@ + +using CloudBuilder.Security.Entity; +using CloudBuilder.Security.SearchCriteria; +using CloudBuilder.Core.Service; +using CloudBuilder.Security.Data; +using Microsoft.AspNetCore.Mvc; + +namespace CloudBuilder.Security.Service +{ + public interface ISecurityUserService : IServiceBase + { + SecurityUserEntity FindByStaffId(string staffid); + SecurityUserEntity[] FindAll(); + SecurityUserResultData FindBySearchCriteria(SecurityUserSearchCriteria tc); + dynamic PrintBySearchCriteria(SecurityUserSearchCriteria tc); + + SecurityFunctionResultData FindMenuByUsername(); + + void Deletes(string[] keys); + + void UpdateLocalName(string localName); + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Service/ISysTableSchemaViewService.auto.cs b/CloudBuilder/CloudBuilder.Security/Service/ISysTableSchemaViewService.auto.cs new file mode 100644 index 0000000..41ffcd0 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Service/ISysTableSchemaViewService.auto.cs @@ -0,0 +1,12 @@ + +using CloudBuilder.Security.Entity; +using CloudBuilder.Security.SearchCriteria; +using CloudBuilder.Core.Service; + +namespace CloudBuilder.Security.Service +{ + public interface ISysTableSchemaViewService : IService + { + List FindByTableName(string tableName); + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Service/IWebAuthnService.cs b/CloudBuilder/CloudBuilder.Security/Service/IWebAuthnService.cs new file mode 100644 index 0000000..fe8d513 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Service/IWebAuthnService.cs @@ -0,0 +1,32 @@ +using Fido2NetLib; +using Fido2NetLib.Objects; +using CloudBuilder.Core.Service; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using CloudBuilder.Security.Data; + +namespace CloudBuilder.Security.Service +{ + public interface IWebAuthnService : IService + { + CredentialCreateOptions BuildCreationOptions(string username, byte[] userId, IReadOnlyList existingCredentialIds); + + Task FinishRegistrationAsync( + AuthenticatorAttestationRawResponse attestationResponse, + CredentialCreateOptions originalOptions, + Func> isCredentialIdUnique); + + AssertionOptions BuildRequestOptions(byte[] storedCredentialId); + + string BuildRequestOptionsJson(byte[] storedCredentialId); + + Task FinishAssertionAsync( + AuthenticatorAssertionRawResponse assertionResponse, + AssertionOptions originalOptions, + byte[] storedPublicKey, + uint storedCounter); + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Service/IYesNoPolicyService.cs b/CloudBuilder/CloudBuilder.Security/Service/IYesNoPolicyService.cs new file mode 100644 index 0000000..f0dab6f --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Service/IYesNoPolicyService.cs @@ -0,0 +1,16 @@ +using CloudBuilder.Core.Service; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Security.Service +{ + public interface IYesNoPolicyService : IService + { + SelectOption[] FindSelectOption(bool blank); + + void Copy(); + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Subscriber/ISecurityUserRegisterSubscriber.cs b/CloudBuilder/CloudBuilder.Security/Subscriber/ISecurityUserRegisterSubscriber.cs new file mode 100644 index 0000000..1b73b44 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Subscriber/ISecurityUserRegisterSubscriber.cs @@ -0,0 +1,18 @@ +using CloudBuilder.Core.DependencyInjection.EventBuses; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Security.Subscriber +{ + public interface ISecurityUserRegisterSubscriber : IEventSubscriber + { + /// + /// 事件处理 + /// + /// 事件源数据 + void Handle(EventData eventData); + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Utility/LoginContextExtensions.cs b/CloudBuilder/CloudBuilder.Security/Utility/LoginContextExtensions.cs new file mode 100644 index 0000000..886016b --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Utility/LoginContextExtensions.cs @@ -0,0 +1,140 @@ +using CloudBuilder.Core.DependencyInjection.Form; +using CloudBuilder.Core.DependencyInjection.Request; +using CloudBuilder.Security.Data; +using Microsoft.AspNetCore.Authorization; +using Microsoft.Extensions.DependencyInjection; + +namespace CloudBuilder.Security.Utility +{ + public static class LoginContextExtensions + { + public static bool Assert(this LoginContext loginContext, string permissionName) + { + return Assert(loginContext, permissionName, Operate.None); + } + public static bool Assert(this LoginContext loginContext, string permissionName, string operate) + { + Operate op = Enum.Parse(operate); + return Assert(loginContext, permissionName, op); + } + + public static bool Assert(this LoginContext loginContext, string permissionName, Operate operate) + { + SecurityUserPermissionInfo permissionInfo = loginContext.GetPermissionInfo(); + switch (operate) + { + case Operate.None: + return permissionInfo.Permissions?.Any(x => x.PermissionName == permissionName) == true; + case Operate.Find: + return permissionInfo.Permissions?.Any(x => x.PermissionName == permissionName && x.ViewIndc == Operate.Find.ToString()) == true; + case Operate.Insert: + return permissionInfo.Permissions?.Any(x => x.PermissionName == permissionName && x.CreateIndc == Operate.Insert.ToString()) == true; + case Operate.Update: + return permissionInfo.Permissions?.Any(x => x.PermissionName == permissionName && x.AmendIndc == Operate.Insert.ToString()) == true; + case Operate.Delete: + return permissionInfo.Permissions?.Any(x => x.PermissionName == permissionName && x.DeleteIndc == Operate.Insert.ToString()) == true; + default: + return permissionInfo.Permissions?.Any(x => x.PermissionName == permissionName) == true; + } + } + + public static bool AssertDependents(this LoginContext loginContext, string permissionName, string dependent) + { + SecurityUserPermissionInfo permissionInfo = loginContext.GetPermissionInfo(); + return permissionInfo.PermissionDependents?.Any(x => x.PermissionName == permissionName && x.DependentDetailName == dependent) == true; + } + } + + public class LoginContextPermission + { + private readonly IContext loginContext; + private IServiceProvider ServiceProvider { get; } + public LoginContextPermission() + { + ServiceProvider = ApplicationServiceContext.ServiceProvider; + loginContext = ServiceProvider.GetService()!; + } + + public bool Assert(string permissionName) + { + return Assert(permissionName, Operate.None); + } + public bool Assert(string permissionName, string operate) + { + Operate op = Enum.Parse(operate); + return Assert(permissionName, op); + } + + public bool Assert(string permissionName, Operate operate) + { + SecurityUserPermissionInfo permissionInfo = loginContext.GetPermissionInfo(); + switch (operate) + { + case Operate.None: + return permissionInfo.Permissions?.Any(x => x.PermissionName == permissionName) == true; + case Operate.Find: + return permissionInfo.Permissions?.Any(x => x.PermissionName == permissionName && YesNoPolicy.IsYes(x.ViewIndc)) == true; + case Operate.Insert: + return permissionInfo.Permissions?.Any(x => x.PermissionName == permissionName && YesNoPolicy.IsYes(x.CreateIndc)) == true; + case Operate.Update: + return permissionInfo.Permissions?.Any(x => x.PermissionName == permissionName && YesNoPolicy.IsYes(x.AmendIndc)) == true; + case Operate.Delete: + return permissionInfo.Permissions?.Any(x => x.PermissionName == permissionName && YesNoPolicy.IsYes(x.DeleteIndc)) == true; + default: + return permissionInfo.Permissions?.Any(x => x.PermissionName == permissionName) == true; + } + } + + public bool AssertDependents(string permissionName, string dependent) + { + SecurityUserPermissionInfo permissionInfo = loginContext.GetPermissionInfo(); + return permissionInfo.PermissionDependents?.Any(x => x.PermissionName == permissionName && x.DependentDetailName == dependent) == true; + } + + public bool AssertDependents(string permissionName, string dependent, Operate operate) + { + SecurityUserPermissionInfo permissionInfo = loginContext.GetPermissionInfo(); + switch (operate) + { + case Operate.None: + return permissionInfo.PermissionDependents?.Any(x => x.PermissionName == permissionName && x.DependentDetailName == dependent) == true; + case Operate.Find: + return permissionInfo.PermissionDependents?.Any(x => x.PermissionName == permissionName && x.DependentDetailName == dependent && YesNoPolicy.IsYes(x.ViewIndc)) == true; + case Operate.Insert: + return permissionInfo.PermissionDependents?.Any(x => x.PermissionName == permissionName && x.DependentDetailName == dependent && YesNoPolicy.IsYes(x.CreateIndc)) == true; + case Operate.Update: + return permissionInfo.PermissionDependents?.Any(x => x.PermissionName == permissionName && x.DependentDetailName == dependent && YesNoPolicy.IsYes(x.AmendIndc)) == true; + case Operate.Delete: + return permissionInfo.PermissionDependents?.Any(x => x.PermissionName == permissionName && x.DependentDetailName == dependent && YesNoPolicy.IsYes(x.DeleteIndc)) == true; + default: + return permissionInfo.PermissionDependents?.Any(x => x.PermissionName == permissionName && x.DependentDetailName == dependent) == true; + } + } + + public bool AssertByFunctionName(string pageName) + { + SecurityUserPermissionInfo permissionInfo = loginContext.GetPermissionInfo(); + + return Assert(permissionInfo.PermissionFunctionMaps.Where(x => x.PageName == pageName).FirstOrDefault()?.PermissionName!, Operate.None); + } + public bool AssertByFunctionName(string pageName, string operate) + { + SecurityUserPermissionInfo permissionInfo = loginContext.GetPermissionInfo(); + Operate op = Enum.Parse(operate); + return Assert(permissionInfo.PermissionFunctionMaps.Where(x => x.PageName == pageName).FirstOrDefault()?.PermissionName!, op); + } + + public bool AssertByFunctionName(string pageName, Operate operate) + { + SecurityUserPermissionInfo permissionInfo = loginContext.GetPermissionInfo(); + return Assert(permissionInfo.PermissionFunctionMaps.Where(x => x.PageName == pageName).FirstOrDefault()?.PermissionName!, operate); + } + + public bool AssertDependentsByFunctionName(string pageName, string dependent) + { + SecurityUserPermissionInfo permissionInfo = loginContext.GetPermissionInfo(); + string permissionName = permissionInfo.PermissionFunctionMaps.Where(x => x.PageName == pageName).FirstOrDefault()?.PermissionName!; + return permissionInfo.PermissionDependents?.Any(x => x.PermissionName == permissionName && x.DependentDetailName == dependent) == true; + } + } +} diff --git a/CloudBuilder/CloudBuilder.Security/Utility/ValidateHelper.cs b/CloudBuilder/CloudBuilder.Security/Utility/ValidateHelper.cs new file mode 100644 index 0000000..63d097e --- /dev/null +++ b/CloudBuilder/CloudBuilder.Security/Utility/ValidateHelper.cs @@ -0,0 +1,50 @@ +using CloudBuilder.Core.DatabaseAccessor.Entity; +using CloudBuilder.Core.Service; +using CloudBuilder.Security.Entity; + +namespace CloudBuilder.Security.Utility +{ + public class ValidateHelper + { + public static void Validate(IApplicationService service, dynamic data, string tableName) + { + List sysTableSchemas = service.GetRepository>().DetachedEntities.Where(x => x.TableName == tableName).ToList(); + ValidateHelper.ValidateString(data, sysTableSchemas.ToArray()); + } + + public static void ValidateString(dynamic dynamic, SysTableSchemaViewEntity[] sysTableSchemas) + { + // 获取所有实体有效属性 + var props = dynamic.GetType().GetProperties(); + // 获取实体当前(现在)的值 + + SysTableSchemaViewEntity sysTableSchema; + long maxLength = 0; + string desName = null; + // 遍历所有属性 + foreach (var prop in props) + { + // 获取属性名 + var propName = prop.Name; + sysTableSchema = sysTableSchemas.Where(x => x.FieldName.Replace("_", "").ToLower() == propName.ToLower()).FirstOrDefault(); + + if (sysTableSchema == null) continue; + + if (sysTableSchema.TypeOfName != "string") continue; + + if (string.IsNullOrEmpty(prop.GetValue(dynamic, null))) continue; + + maxLength = sysTableSchema.MaxLength; + + object[] objs = prop.GetCustomAttributes(typeof(System.ComponentModel.DescriptionAttribute), true); + desName = propName; + if (objs != null && objs.Length > 0) desName = ((System.ComponentModel.DescriptionAttribute)objs[0]).Description; + + if (((string)prop.GetValue(dynamic, null)).Length > maxLength) + { + throw new ValidatedException(string.Format("{0}长度不能超过【{1}】字符.", desName, maxLength)); + } + } + } + } +} diff --git a/CloudBuilder/CloudBuilder.Web.Entry.sln b/CloudBuilder/CloudBuilder.Web.Entry.sln new file mode 100644 index 0000000..b1939a8 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Web.Entry.sln @@ -0,0 +1,43 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.14.37111.16 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CloudBuilder.Web.Entry", "CloudBuilder.Web.Entry\CloudBuilder.Web.Entry.csproj", "{9823D7CF-5DF8-BCAE-391B-C2CFC51C99C2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CloudBuilder.Security.Service", "CloudBuilder.Security.Service\CloudBuilder.Security.Service.csproj", "{D4371FF5-55AA-F6FB-9D02-FA0486C7F492}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CloudBuilder.Core", "CloudBuilder.Core\CloudBuilder.Core.csproj", "{AFA9D41C-E8A5-32D3-E81B-2ABA7C37D46C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CloudBuilder.Security", "CloudBuilder.Security\CloudBuilder.Security.csproj", "{269A5036-BAE9-FD61-1DD5-0EA93B79F0D7}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9823D7CF-5DF8-BCAE-391B-C2CFC51C99C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9823D7CF-5DF8-BCAE-391B-C2CFC51C99C2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9823D7CF-5DF8-BCAE-391B-C2CFC51C99C2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9823D7CF-5DF8-BCAE-391B-C2CFC51C99C2}.Release|Any CPU.Build.0 = Release|Any CPU + {D4371FF5-55AA-F6FB-9D02-FA0486C7F492}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D4371FF5-55AA-F6FB-9D02-FA0486C7F492}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D4371FF5-55AA-F6FB-9D02-FA0486C7F492}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D4371FF5-55AA-F6FB-9D02-FA0486C7F492}.Release|Any CPU.Build.0 = Release|Any CPU + {AFA9D41C-E8A5-32D3-E81B-2ABA7C37D46C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AFA9D41C-E8A5-32D3-E81B-2ABA7C37D46C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AFA9D41C-E8A5-32D3-E81B-2ABA7C37D46C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AFA9D41C-E8A5-32D3-E81B-2ABA7C37D46C}.Release|Any CPU.Build.0 = Release|Any CPU + {269A5036-BAE9-FD61-1DD5-0EA93B79F0D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {269A5036-BAE9-FD61-1DD5-0EA93B79F0D7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {269A5036-BAE9-FD61-1DD5-0EA93B79F0D7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {269A5036-BAE9-FD61-1DD5-0EA93B79F0D7}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {9AC4E316-55D0-4E83-BA52-46264DE9F1A9} + EndGlobalSection +EndGlobal diff --git a/CloudBuilder/CloudBuilder.Web.Entry/.config/dotnet-tools.json b/CloudBuilder/CloudBuilder.Web.Entry/.config/dotnet-tools.json new file mode 100644 index 0000000..fd9a39d --- /dev/null +++ b/CloudBuilder/CloudBuilder.Web.Entry/.config/dotnet-tools.json @@ -0,0 +1,12 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "dotnet-ef": { + "version": "8.0.1", + "commands": [ + "dotnet-ef" + ] + } + } +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Web.Entry/CloudBuilder.Web.Entry.csproj b/CloudBuilder/CloudBuilder.Web.Entry/CloudBuilder.Web.Entry.csproj new file mode 100644 index 0000000..5b1a530 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Web.Entry/CloudBuilder.Web.Entry.csproj @@ -0,0 +1,50 @@ + + + + net8.0 + enable + enable + false + Linux + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ..\CloudBuilder.Core\bin\Debug\net8.0\CloudBuilder.Core.dll + + + ..\CloudBuilder.Security\bin\Debug\net8.0\CloudBuilder.Security.dll + + + ..\CloudBuilder.Security.Service\bin\Debug\net8.0\CloudBuilder.Security.Service.dll + + + + + + + diff --git a/CloudBuilder/CloudBuilder.Web.Entry/CloudBuilder.Web.Entry.csproj.user b/CloudBuilder/CloudBuilder.Web.Entry/CloudBuilder.Web.Entry.csproj.user new file mode 100644 index 0000000..7b23cd1 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Web.Entry/CloudBuilder.Web.Entry.csproj.user @@ -0,0 +1,10 @@ + + + + D:\Docker\CloudBuilder\CloudBuilder.Web.Entry\Properties\PublishProfiles\FolderProfile3.pubxml + http + + + ProjectDebugger + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Web.Entry/Controllers/Security/AuthController.auto.cs b/CloudBuilder/CloudBuilder.Web.Entry/Controllers/Security/AuthController.auto.cs new file mode 100644 index 0000000..da097ff --- /dev/null +++ b/CloudBuilder/CloudBuilder.Web.Entry/Controllers/Security/AuthController.auto.cs @@ -0,0 +1,301 @@ + +using CloudBuilder.Core.DatabaseAccessor; +using CloudBuilder.Core.Policy; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System.Transactions; +using CloudBuilder.Core.Service; +using CloudBuilder.Security.Service; + using CloudBuilder.Core.DatabaseAccessor.Entity; + using Microsoft.AspNetCore.Http; + using CloudBuilder.Core.Policy; + using CloudBuilder.Core.DependencyInjection.Request; + using CloudBuilder.Security.Data; + using CloudBuilder.Core.Authorization; + using System; + +namespace CloudBuilder.Web.Entry.Controllers.Security +{ +[Authorize(AuthorizePolicy.PERMISSION)] +[ApiController] +[Route("[controller]/[action]")] +public class AuthController : ControllerBase +{ +private readonly IApplicationService service; +private readonly IAuthService authService; + +public AuthController(IApplicationService service, IAuthService authService) +{ +this.service = service; +this.authService= authService; +} + + [AllowAnonymous] + [HttpPost] + [UnitOfWork] + public dynamic Login(LoginData data) + { + try + { + + var result = authService.Login(data); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityUser", operate: "LoginAgent")] + [HttpPost] + [UnitOfWork] + public dynamic LoginAgent(LoginData data) + { + try + { + + var result = authService.LoginAgent(data); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [AllowAnonymous] + [HttpPost] + [UnitOfWork] + public dynamic Register(RegisterData data) + { + try + { + + var result = authService.Register(data); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityUser", operate: "Update")] + [HttpPost] + [UnitOfWork] + public dynamic AmendPassword(LoginData data) + { + try + { + + var result = authService.AmendPassword(data); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [AllowAnonymous] + [HttpGet] + public dynamic GetRsaPublicKey() + { + try + { + + var result = authService.GetRsaPublicKey(); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [AllowAnonymous] + [HttpPost] + public dynamic RefreshToken(JwtInfo jwtInfo) + { + try + { + + var result = authService.RefreshToken(jwtInfo); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [AllowAnonymous] + [HttpPost] + public dynamic Logout() + { + try + { + + authService.Logout(); + + return string.Empty; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityUser", operate: "Find")] + [HttpPost] + public dynamic ConfirmPassword(string password) + { + try + { + + var result = authService.ConfirmPassword(password); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityUser", operate: "Find")] + [HttpPost] + public dynamic BeginBiometricRegistration(string deviceName) + { + try + { + + var result = authService.BeginBiometricRegistration(deviceName); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityUser", operate: "Find")] + [HttpPost] + public dynamic FinishBiometricRegistration(FinishBiometricRegistrationData dto) + { + try + { + + var result = authService.FinishBiometricRegistration(dto); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [AllowAnonymous] + [HttpPost] + public dynamic BeginBiometricLogin(string username) + { + try + { + + var result = authService.BeginBiometricLogin(username); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [AllowAnonymous] + [HttpPost] + public dynamic FinishBiometricLogin(FinishBiometricLoginData dto) + { + try + { + + var result = authService.FinishBiometricLogin(dto); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityUser", operate: "Find")] + [HttpPost] + public dynamic RemoveBiometric() + { + try + { + + authService.RemoveBiometric(); + + return string.Empty; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + +} +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Web.Entry/Controllers/Security/LocaleController.auto.cs b/CloudBuilder/CloudBuilder.Web.Entry/Controllers/Security/LocaleController.auto.cs new file mode 100644 index 0000000..1dca1d1 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Web.Entry/Controllers/Security/LocaleController.auto.cs @@ -0,0 +1,179 @@ + +using CloudBuilder.Core.DatabaseAccessor; +using CloudBuilder.Core.Policy; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System.Transactions; +using CloudBuilder.Core.Service; +using CloudBuilder.Security.Service; + using CloudBuilder.Core.DatabaseAccessor.Entity; + using Microsoft.AspNetCore.Http; + using CloudBuilder.Core.Policy; + using CloudBuilder.Core.DependencyInjection.Request; + using CloudBuilder.Security.Data; + using CloudBuilder.Core.Authorization; + using System; + using CloudBuilder.Security.Entity; + using CloudBuilder.Security.SearchCriteria; + using CloudBuilder.Security; + +namespace CloudBuilder.Web.Entry.Controllers.Security +{ +[Authorize(AuthorizePolicy.PERMISSION)] +[ApiController] +[Route("[controller]/[action]")] +public class LocaleController : ControllerBase +{ +private readonly IApplicationService service; +private readonly ILocaleService localeService; + +public LocaleController(IApplicationService service, ILocaleService localeService) +{ +this.service = service; +this.localeService= localeService; +} + + [AllowAnonymous] + [HttpGet] + public dynamic FindAll() + { + try + { + + var result = localeService.FindAll(); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [AllowAnonymous] + [HttpPost] + public dynamic FindBySearchCriteria(LocaleSearchCriteria criteria) + { + try + { + + var result = localeService.FindBySearchCriteria(criteria); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [AllowAnonymous] + [HttpPost] + public dynamic FindByKey(LocaleEntityKey key) + { + try + { + + var result = localeService.FindByKey(key); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "Locale", operate: "Insert")] + [HttpPost] + [UnitOfWork] + public dynamic Insert(LocaleEntity data) + { + try + { + + var result = localeService.Insert(data); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "Locale", operate: "Update")] + [HttpPost] + [UnitOfWork] + public dynamic Update(LocaleEntity data) + { + try + { + + var result = localeService.Update(data); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "Locale", operate: "Update")] + [HttpPost] + [UnitOfWork] + public dynamic UpdateLocaleData(LocaleData data){ + try + { + localeService.UpdateLocaleData(data); + + return string.Empty; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "Locale", operate: "Delete")] + [HttpPost] + public dynamic Delete(LocaleEntityKey key){ + try + { + localeService.Delete(key); + + return string.Empty; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + +} +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Web.Entry/Controllers/Security/SecurityActorController.auto.cs b/CloudBuilder/CloudBuilder.Web.Entry/Controllers/Security/SecurityActorController.auto.cs new file mode 100644 index 0000000..6a97d8a --- /dev/null +++ b/CloudBuilder/CloudBuilder.Web.Entry/Controllers/Security/SecurityActorController.auto.cs @@ -0,0 +1,220 @@ + +using CloudBuilder.Core.DatabaseAccessor; +using CloudBuilder.Core.Policy; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System.Transactions; +using CloudBuilder.Core.Service; +using CloudBuilder.Security.Service; + using CloudBuilder.Core.DatabaseAccessor.Entity; + using Microsoft.AspNetCore.Http; + using CloudBuilder.Core.Policy; + using CloudBuilder.Core.DependencyInjection.Request; + using CloudBuilder.Security.Data; + using CloudBuilder.Core.Authorization; + using System; + using CloudBuilder.Security.Entity; + using CloudBuilder.Security.SearchCriteria; + using CloudBuilder.Security; + +namespace CloudBuilder.Web.Entry.Controllers.Security +{ +[Authorize(AuthorizePolicy.PERMISSION)] +[ApiController] +[Route("[controller]/[action]")] +public class SecurityActorController : ControllerBase +{ +private readonly IApplicationService service; +private readonly ISecurityActorService securityActorService; + +public SecurityActorController(IApplicationService service, ISecurityActorService securityActorService) +{ +this.service = service; +this.securityActorService= securityActorService; +} + + [PermissionOperate(name: "SecurityActor", operate: "Find")] + [HttpPost] + public dynamic FindByKey(string key) + { + try + { + + var result = securityActorService.FindByKey(key); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityActor", operate: "Find")] + [HttpPost] + public dynamic FindAll() + { + try + { + + var result = securityActorService.FindAll(); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [AllowAnonymous] + [HttpPost] + public dynamic FindAllByNoPermission() + { + try + { + + var result = securityActorService.FindAllByNoPermission(); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityActor", operate: "Find")] + [HttpPost] + public dynamic FindBySearchCriteria(SecurityActorSearchCriteria criteria) + { + try + { + + var result = securityActorService.FindBySearchCriteria(criteria); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityActor", operate: "Print")] + [HttpPost] + public dynamic PrintBySearchCriteria(SecurityActorSearchCriteria criteria) + { + try + { + + var result = securityActorService.PrintBySearchCriteria(criteria); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityActor", operate: "Insert")] + [HttpPost] + [UnitOfWork] + public dynamic Insert(SecurityActorData data) + { + try + { + + var result = securityActorService.Insert(data); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityActor", operate: "Update")] + [HttpPost] + [UnitOfWork] + public dynamic Update(SecurityActorData data) + { + try + { + + var result = securityActorService.Update(data); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityActor", operate: "Delete")] + [HttpPost] + [UnitOfWork] + public dynamic Delete(string key){ + try + { + securityActorService.Delete(key); + + return string.Empty; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityActor", operate: "Delete")] + [HttpPost] + [UnitOfWork] + public dynamic Deletes(string[] keys){ + try + { + securityActorService.Deletes(keys); + + return string.Empty; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + +} +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Web.Entry/Controllers/Security/SecurityFunctionController.auto.cs b/CloudBuilder/CloudBuilder.Web.Entry/Controllers/Security/SecurityFunctionController.auto.cs new file mode 100644 index 0000000..136fdb0 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Web.Entry/Controllers/Security/SecurityFunctionController.auto.cs @@ -0,0 +1,220 @@ + +using CloudBuilder.Core.DatabaseAccessor; +using CloudBuilder.Core.Policy; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System.Transactions; +using CloudBuilder.Core.Service; +using CloudBuilder.Security.Service; + using CloudBuilder.Core.DatabaseAccessor.Entity; + using Microsoft.AspNetCore.Http; + using CloudBuilder.Core.Policy; + using CloudBuilder.Core.DependencyInjection.Request; + using CloudBuilder.Security.Data; + using CloudBuilder.Core.Authorization; + using System; + using CloudBuilder.Security.Entity; + using CloudBuilder.Security.SearchCriteria; + using CloudBuilder.Security; + +namespace CloudBuilder.Web.Entry.Controllers.Security +{ +[Authorize(AuthorizePolicy.PERMISSION)] +[ApiController] +[Route("[controller]/[action]")] +public class SecurityFunctionController : ControllerBase +{ +private readonly IApplicationService service; +private readonly ISecurityFunctionService securityFunctionService; + +public SecurityFunctionController(IApplicationService service, ISecurityFunctionService securityFunctionService) +{ +this.service = service; +this.securityFunctionService= securityFunctionService; +} + + [PermissionOperate(name: "SecurityFunction", operate: "Find")] + [HttpPost] + public dynamic FindByKey(string key) + { + try + { + + var result = securityFunctionService.FindByKey(key); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityFunction", operate: "Find")] + [HttpPost] + public dynamic FindBySearchCriteria(SecurityFunctionSearchCriteria criteria) + { + try + { + + var result = securityFunctionService.FindBySearchCriteria(criteria); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityFunction", operate: "Print")] + [HttpPost] + public dynamic PrintBySearchCriteria(SecurityFunctionSearchCriteria criteria) + { + try + { + + var result = securityFunctionService.PrintBySearchCriteria(criteria); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityFunction", operate: "Insert")] + [HttpPost] + [UnitOfWork] + public dynamic Insert(SecurityFunctionData data) + { + try + { + + var result = securityFunctionService.Insert(data); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityFunction", operate: "Update")] + [HttpPost] + [UnitOfWork] + public dynamic Update(SecurityFunctionData data) + { + try + { + + var result = securityFunctionService.Update(data); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityFunction", operate: "Delete")] + [HttpPost] + [UnitOfWork] + public dynamic Delete(string key){ + try + { + securityFunctionService.Delete(key); + + return string.Empty; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityFunction", operate: "Delete")] + [HttpPost] + [UnitOfWork] + public dynamic Deletes(string[] keys){ + try + { + securityFunctionService.Deletes(keys); + + return string.Empty; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [AllowAnonymous] + [HttpPost] + public dynamic FindByFunctionName(string functionName) + { + try + { + + var result = securityFunctionService.FindByFunctionName(functionName); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [AllowAnonymous] + [HttpPost] + public dynamic FindMenus() + { + try + { + + var result = securityFunctionService.FindMenus(); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + +} +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Web.Entry/Controllers/Security/SecurityGeneratorNumberController.auto.cs b/CloudBuilder/CloudBuilder.Web.Entry/Controllers/Security/SecurityGeneratorNumberController.auto.cs new file mode 100644 index 0000000..c5b26e6 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Web.Entry/Controllers/Security/SecurityGeneratorNumberController.auto.cs @@ -0,0 +1,160 @@ + +using CloudBuilder.Core.DatabaseAccessor; +using CloudBuilder.Core.Policy; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System.Transactions; +using CloudBuilder.Core.Service; +using CloudBuilder.Security.Service; + using CloudBuilder.Core.DatabaseAccessor.Entity; + using Microsoft.AspNetCore.Http; + using CloudBuilder.Core.Policy; + using CloudBuilder.Core.DependencyInjection.Request; + using CloudBuilder.Security.Data; + using CloudBuilder.Core.Authorization; + using System; + using CloudBuilder.Security.Entity; + using CloudBuilder.Security.SearchCriteria; + using CloudBuilder.Security; + +namespace CloudBuilder.Web.Entry.Controllers.Security +{ +[Authorize(AuthorizePolicy.PERMISSION)] +[ApiController] +[Route("[controller]/[action]")] +public class SecurityGeneratorNumberController : ControllerBase +{ +private readonly IApplicationService service; +private readonly ISecurityGeneratorNumberService securityGeneratorNumberService; + +public SecurityGeneratorNumberController(IApplicationService service, ISecurityGeneratorNumberService securityGeneratorNumberService) +{ +this.service = service; +this.securityGeneratorNumberService= securityGeneratorNumberService; +} + + [PermissionOperate(name: "SecurityGeneratorNumber", operate: "Find")] + [HttpPost] + public dynamic FindByKey(Int32 key) + { + try + { + + var result = securityGeneratorNumberService.FindByKey(key); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityGeneratorNumber", operate: "Find")] + [HttpPost] + public dynamic FindBySearchCriteria(SecurityGeneratorNumberSearchCriteria criteria) + { + try + { + + var result = securityGeneratorNumberService.FindBySearchCriteria(criteria); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityGeneratorNumber", operate: "Print")] + [HttpPost] + public dynamic PrintBySearchCriteria(SecurityGeneratorNumberSearchCriteria criteria) + { + try + { + + var result = securityGeneratorNumberService.PrintBySearchCriteria(criteria); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityGeneratorNumber", operate: "Insert")] + [HttpPost] + [UnitOfWork] + public dynamic Insert(SecurityGeneratorNumberEntity data) + { + try + { + + var result = securityGeneratorNumberService.Insert(data); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityGeneratorNumber", operate: "Update")] + [HttpPost] + [UnitOfWork] + public dynamic Update(SecurityGeneratorNumberEntity data) + { + try + { + + var result = securityGeneratorNumberService.Update(data); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityGeneratorNumber", operate: "Delete")] + [HttpPost] + [UnitOfWork] + public dynamic Delete(Int32 key){ + try + { + securityGeneratorNumberService.Delete(key); + + return string.Empty; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + +} +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Web.Entry/Controllers/Security/SecurityGroupController.auto.cs b/CloudBuilder/CloudBuilder.Web.Entry/Controllers/Security/SecurityGroupController.auto.cs new file mode 100644 index 0000000..b9906bc --- /dev/null +++ b/CloudBuilder/CloudBuilder.Web.Entry/Controllers/Security/SecurityGroupController.auto.cs @@ -0,0 +1,200 @@ + +using CloudBuilder.Core.DatabaseAccessor; +using CloudBuilder.Core.Policy; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System.Transactions; +using CloudBuilder.Core.Service; +using CloudBuilder.Security.Service; + using CloudBuilder.Core.DatabaseAccessor.Entity; + using Microsoft.AspNetCore.Http; + using CloudBuilder.Core.Policy; + using CloudBuilder.Core.DependencyInjection.Request; + using CloudBuilder.Security.Data; + using CloudBuilder.Core.Authorization; + using System; + using CloudBuilder.Security.Entity; + using CloudBuilder.Security.SearchCriteria; + using CloudBuilder.Security; + +namespace CloudBuilder.Web.Entry.Controllers.Security +{ +[Authorize(AuthorizePolicy.PERMISSION)] +[ApiController] +[Route("[controller]/[action]")] +public class SecurityGroupController : ControllerBase +{ +private readonly IApplicationService service; +private readonly ISecurityGroupService securityGroupService; + +public SecurityGroupController(IApplicationService service, ISecurityGroupService securityGroupService) +{ +this.service = service; +this.securityGroupService= securityGroupService; +} + + [PermissionOperate(name: "SecurityGroup", operate: "Find")] + [HttpPost] + public dynamic FindByKey(string key) + { + try + { + + var result = securityGroupService.FindByKey(key); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityGroup", operate: "Find")] + [HttpPost] + public dynamic FindAll() + { + try + { + + var result = securityGroupService.FindAll(); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityGroup", operate: "Find")] + [HttpPost] + public dynamic FindBySearchCriteria(SecurityGroupSearchCriteria criteria) + { + try + { + + var result = securityGroupService.FindBySearchCriteria(criteria); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityGroup", operate: "Print")] + [HttpPost] + public dynamic PrintBySearchCriteria(SecurityGroupSearchCriteria criteria) + { + try + { + + var result = securityGroupService.PrintBySearchCriteria(criteria); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityGroup", operate: "Insert")] + [HttpPost] + [UnitOfWork] + public dynamic Insert(SecurityGroupData data) + { + try + { + + var result = securityGroupService.Insert(data); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityGroup", operate: "Update")] + [HttpPost] + [UnitOfWork] + public dynamic Update(SecurityGroupData data) + { + try + { + + var result = securityGroupService.Update(data); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityGroup", operate: "Delete")] + [HttpPost] + [UnitOfWork] + public dynamic Delete(string key){ + try + { + securityGroupService.Delete(key); + + return string.Empty; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityGroup", operate: "Delete")] + [HttpPost] + [UnitOfWork] + public dynamic Deletes(string[] keys){ + try + { + securityGroupService.Deletes(keys); + + return string.Empty; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + +} +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Web.Entry/Controllers/Security/SecurityLockController.auto.cs b/CloudBuilder/CloudBuilder.Web.Entry/Controllers/Security/SecurityLockController.auto.cs new file mode 100644 index 0000000..4d40f9c --- /dev/null +++ b/CloudBuilder/CloudBuilder.Web.Entry/Controllers/Security/SecurityLockController.auto.cs @@ -0,0 +1,253 @@ + +using CloudBuilder.Core.DatabaseAccessor; +using CloudBuilder.Core.Policy; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System.Transactions; +using CloudBuilder.Core.Service; +using CloudBuilder.Security.Service; + using CloudBuilder.Core.DatabaseAccessor.Entity; + using Microsoft.AspNetCore.Http; + using CloudBuilder.Core.Policy; + using CloudBuilder.Core.DependencyInjection.Request; + using CloudBuilder.Security.Data; + using CloudBuilder.Core.Authorization; + using System; + using CloudBuilder.Security.Entity; + using CloudBuilder.Security.SearchCriteria; + using CloudBuilder.Security; + +namespace CloudBuilder.Web.Entry.Controllers.Security +{ +[Authorize(AuthorizePolicy.PERMISSION)] +[ApiController] +[Route("[controller]/[action]")] +public class SecurityLockController : ControllerBase +{ +private readonly IApplicationService service; +private readonly ISecurityLockService securityLockService; + +public SecurityLockController(IApplicationService service, ISecurityLockService securityLockService) +{ +this.service = service; +this.securityLockService= securityLockService; +} + + [PermissionOperate(name: "SecurityLock", operate: "Find")] + [HttpPost] + public dynamic FindByKey(SecurityLockEntityKey key) + { + try + { + + var result = securityLockService.FindByKey(key); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityLock", operate: "Insert")] + [HttpPost] + [UnitOfWork] + public dynamic Insert(SecurityLockEntity data) + { + try + { + + var result = securityLockService.Insert(data); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityLock", operate: "Update")] + [HttpPost] + [UnitOfWork] + public dynamic Update(SecurityLockEntity data) + { + try + { + + var result = securityLockService.Update(data); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityLock", operate: "Delete")] + [HttpPost] + public dynamic Delete(SecurityLockEntityKey key){ + try + { + securityLockService.Delete(key); + + return string.Empty; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + + public class IsLockedCompositionData + { + public string entityName { get; set; } + public string key { get; set; } + + } + [AllowAnonymous] + [HttpPost] + public dynamic IsLocked(IsLockedCompositionData compositionData) + { + try + { + + var result = securityLockService.IsLocked(compositionData.entityName,compositionData.key); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + + public class LockCompositionData + { + public string entityName { get; set; } + public string key { get; set; } + public string username { get; set; } + + } + [AllowAnonymous] + [HttpPost] + public dynamic Lock(LockCompositionData compositionData){ + try + { + securityLockService.Lock(compositionData.entityName,compositionData.key,compositionData.username); + + return string.Empty; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + + public class ForceLockCompositionData + { + public string entityName { get; set; } + public string key { get; set; } + public string username { get; set; } + + } + [AllowAnonymous] + [HttpPost] + public dynamic ForceLock(ForceLockCompositionData compositionData){ + try + { + securityLockService.ForceLock(compositionData.entityName,compositionData.key,compositionData.username); + + return string.Empty; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + + public class ConsumeLockCompositionData + { + public string entityName { get; set; } + public string key { get; set; } + public string username { get; set; } + + } + [AllowAnonymous] + [HttpPost] + public dynamic ConsumeLock(ConsumeLockCompositionData compositionData){ + try + { + securityLockService.ConsumeLock(compositionData.entityName,compositionData.key,compositionData.username); + + return string.Empty; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + + public class ClearLockCompositionData + { + public string entityName { get; set; } + public string key { get; set; } + + } + [AllowAnonymous] + [HttpPost] + public dynamic ClearLock(ClearLockCompositionData compositionData){ + try + { + securityLockService.ClearLock(compositionData.entityName,compositionData.key); + + return string.Empty; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + +} +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Web.Entry/Controllers/Security/SecurityMasterController.auto.cs b/CloudBuilder/CloudBuilder.Web.Entry/Controllers/Security/SecurityMasterController.auto.cs new file mode 100644 index 0000000..8c2bb9a --- /dev/null +++ b/CloudBuilder/CloudBuilder.Web.Entry/Controllers/Security/SecurityMasterController.auto.cs @@ -0,0 +1,198 @@ + +using CloudBuilder.Core.DatabaseAccessor; +using CloudBuilder.Core.Policy; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System.Transactions; +using CloudBuilder.Core.Service; +using CloudBuilder.Security.Service; + using CloudBuilder.Core.DatabaseAccessor.Entity; + using Microsoft.AspNetCore.Http; + using CloudBuilder.Core.Policy; + using CloudBuilder.Core.DependencyInjection.Request; + using CloudBuilder.Security.Data; + using CloudBuilder.Core.Authorization; + using System; + using CloudBuilder.Security.Entity; + using CloudBuilder.Security.SearchCriteria; + using CloudBuilder.Security; + +namespace CloudBuilder.Web.Entry.Controllers.Security +{ +[Authorize(AuthorizePolicy.PERMISSION)] +[ApiController] +[Route("[controller]/[action]")] +public class SecurityMasterController : ControllerBase +{ +private readonly IApplicationService service; +private readonly ISecurityMasterService securityMasterService; + +public SecurityMasterController(IApplicationService service, ISecurityMasterService securityMasterService) +{ +this.service = service; +this.securityMasterService= securityMasterService; +} + + [PermissionOperate(name: "SecurityMaster", operate: "Find")] + [HttpPost] + public dynamic FindByKey(SecurityMasterEntityKey key) + { + try + { + + var result = securityMasterService.FindByKey(key); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [AllowAnonymous] + [HttpGet] + public dynamic FindAll() + { + try + { + + var result = securityMasterService.FindAll(); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityMaster", operate: "Find")] + [HttpPost] + public dynamic FindBySearchCriteria(SecurityMasterSearchCriteria criteria) + { + try + { + + var result = securityMasterService.FindBySearchCriteria(criteria); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityMaster", operate: "Print")] + [HttpPost] + public dynamic PrintBySearchCriteria(SecurityMasterSearchCriteria criteria) + { + try + { + + var result = securityMasterService.PrintBySearchCriteria(criteria); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityMaster", operate: "Insert")] + [HttpPost] + [UnitOfWork] + public dynamic Insert(SecurityMasterEntity data) + { + try + { + + var result = securityMasterService.Insert(data); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityMaster", operate: "Update")] + [HttpPost] + [UnitOfWork] + public dynamic Update(SecurityMasterEntity data) + { + try + { + + var result = securityMasterService.Update(data); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityMaster", operate: "Delete")] + [HttpPost] + public dynamic Delete(SecurityMasterEntityKey key){ + try + { + securityMasterService.Delete(key); + + return string.Empty; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityMaster", operate: "Delete")] + [HttpPost] + public dynamic Deletes(SecurityMasterEntity[] datas){ + try + { + securityMasterService.Deletes(datas); + + return string.Empty; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + +} +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Web.Entry/Controllers/Security/SecurityPermissionController.auto.cs b/CloudBuilder/CloudBuilder.Web.Entry/Controllers/Security/SecurityPermissionController.auto.cs new file mode 100644 index 0000000..9b7ce12 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Web.Entry/Controllers/Security/SecurityPermissionController.auto.cs @@ -0,0 +1,220 @@ + +using CloudBuilder.Core.DatabaseAccessor; +using CloudBuilder.Core.Policy; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System.Transactions; +using CloudBuilder.Core.Service; +using CloudBuilder.Security.Service; + using CloudBuilder.Core.DatabaseAccessor.Entity; + using Microsoft.AspNetCore.Http; + using CloudBuilder.Core.Policy; + using CloudBuilder.Core.DependencyInjection.Request; + using CloudBuilder.Security.Data; + using CloudBuilder.Core.Authorization; + using System; + using CloudBuilder.Security.Entity; + using CloudBuilder.Security.SearchCriteria; + using CloudBuilder.Security; + +namespace CloudBuilder.Web.Entry.Controllers.Security +{ +[Authorize(AuthorizePolicy.PERMISSION)] +[ApiController] +[Route("[controller]/[action]")] +public class SecurityPermissionController : ControllerBase +{ +private readonly IApplicationService service; +private readonly ISecurityPermissionService securityPermissionService; + +public SecurityPermissionController(IApplicationService service, ISecurityPermissionService securityPermissionService) +{ +this.service = service; +this.securityPermissionService= securityPermissionService; +} + + [PermissionOperate(name: "SecurityPermission", operate: "Find")] + [HttpPost] + public dynamic FindByKey(string key) + { + try + { + + var result = securityPermissionService.FindByKey(key); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityPermission", operate: "Find")] + [HttpPost] + public dynamic FindBySearchCriteria(SecurityPermissionSearchCriteria criteria) + { + try + { + + var result = securityPermissionService.FindBySearchCriteria(criteria); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityPermission", operate: "Find")] + [HttpPost] + public dynamic FindDependentBySearchCriteria(SecurityPermissionSearchCriteria criteria) + { + try + { + + var result = securityPermissionService.FindDependentBySearchCriteria(criteria); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityPermission", operate: "Find")] + [HttpPost] + public dynamic FindDependentsBySearchCriteria(SecurityPermissionSearchCriteria criteria) + { + try + { + + var result = securityPermissionService.FindDependentsBySearchCriteria(criteria); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityPermission", operate: "Print")] + [HttpPost] + public dynamic PrintBySearchCriteria(SecurityPermissionSearchCriteria criteria) + { + try + { + + var result = securityPermissionService.PrintBySearchCriteria(criteria); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityPermission", operate: "Insert")] + [HttpPost] + [UnitOfWork] + public dynamic Insert(SecurityPermissionData data) + { + try + { + + var result = securityPermissionService.Insert(data); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityPermission", operate: "Update")] + [HttpPost] + [UnitOfWork] + public dynamic Update(SecurityPermissionData data) + { + try + { + + var result = securityPermissionService.Update(data); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityPermission", operate: "Delete")] + [HttpPost] + [UnitOfWork] + public dynamic Delete(string key){ + try + { + securityPermissionService.Delete(key); + + return string.Empty; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityPermission", operate: "Delete")] + [HttpPost] + [UnitOfWork] + public dynamic Deletes(string[] keys){ + try + { + securityPermissionService.Deletes(keys); + + return string.Empty; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + +} +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Web.Entry/Controllers/Security/SecurityUserController.auto.cs b/CloudBuilder/CloudBuilder.Web.Entry/Controllers/Security/SecurityUserController.auto.cs new file mode 100644 index 0000000..9c58c8b --- /dev/null +++ b/CloudBuilder/CloudBuilder.Web.Entry/Controllers/Security/SecurityUserController.auto.cs @@ -0,0 +1,259 @@ + +using CloudBuilder.Core.DatabaseAccessor; +using CloudBuilder.Core.Policy; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System.Transactions; +using CloudBuilder.Core.Service; +using CloudBuilder.Security.Service; + using CloudBuilder.Core.DatabaseAccessor.Entity; + using Microsoft.AspNetCore.Http; + using CloudBuilder.Core.Policy; + using CloudBuilder.Core.DependencyInjection.Request; + using CloudBuilder.Security.Data; + using CloudBuilder.Core.Authorization; + using System; + using CloudBuilder.Security.Entity; + using CloudBuilder.Security.SearchCriteria; + using CloudBuilder.Security; + +namespace CloudBuilder.Web.Entry.Controllers.Security +{ +[Authorize(AuthorizePolicy.PERMISSION)] +[ApiController] +[Route("[controller]/[action]")] +public class SecurityUserController : ControllerBase +{ +private readonly IApplicationService service; +private readonly ISecurityUserService securityUserService; + +public SecurityUserController(IApplicationService service, ISecurityUserService securityUserService) +{ +this.service = service; +this.securityUserService= securityUserService; +} + + [PermissionOperate(name: "SecurityUser", operate: "Find")] + [HttpPost] + public dynamic FindByStaffId(string staffid) + { + try + { + + var result = securityUserService.FindByStaffId(staffid); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityUser", operate: "Find")] + [HttpPost] + public dynamic FindByKey(string key) + { + try + { + + var result = securityUserService.FindByKey(key); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityUser", operate: "Find")] + [HttpPost] + public dynamic FindAll() + { + try + { + + var result = securityUserService.FindAll(); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityUser", operate: "Find")] + [HttpPost] + public dynamic FindBySearchCriteria(SecurityUserSearchCriteria criteria) + { + try + { + + var result = securityUserService.FindBySearchCriteria(criteria); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityUser", operate: "Print")] + [HttpPost] + public dynamic PrintBySearchCriteria(SecurityUserSearchCriteria criteria) + { + try + { + + var result = securityUserService.PrintBySearchCriteria(criteria); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityUser", operate: "Insert")] + [HttpPost] + [UnitOfWork] + public dynamic Insert(SecurityUserData data) + { + try + { + + var result = securityUserService.Insert(data); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityUser", operate: "Update")] + [HttpPost] + [UnitOfWork] + public dynamic Update(SecurityUserData data) + { + try + { + + var result = securityUserService.Update(data); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityUser", operate: "Delete")] + [HttpPost] + [UnitOfWork] + public dynamic Delete(string key){ + try + { + securityUserService.Delete(key); + + return string.Empty; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityUser", operate: "Delete")] + [HttpPost] + [UnitOfWork] + public dynamic Deletes(string[] keys){ + try + { + securityUserService.Deletes(keys); + + return string.Empty; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [AllowAnonymous] + [HttpPost] + public dynamic FindMenuByUsername() + { + try + { + + var result = securityUserService.FindMenuByUsername(); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [AllowAnonymous] + [HttpPost] + public dynamic UpdateLocalName(string localName){ + try + { + securityUserService.UpdateLocalName(localName); + + return string.Empty; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + +} +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Web.Entry/Controllers/Security/SecurityUserPreferenceController.auto.cs b/CloudBuilder/CloudBuilder.Web.Entry/Controllers/Security/SecurityUserPreferenceController.auto.cs new file mode 100644 index 0000000..f81b284 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Web.Entry/Controllers/Security/SecurityUserPreferenceController.auto.cs @@ -0,0 +1,159 @@ + +using CloudBuilder.Core.DatabaseAccessor; +using CloudBuilder.Core.Policy; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System.Transactions; +using CloudBuilder.Core.Service; +using CloudBuilder.Security.Service; + using CloudBuilder.Core.DatabaseAccessor.Entity; + using Microsoft.AspNetCore.Http; + using CloudBuilder.Core.Policy; + using CloudBuilder.Core.DependencyInjection.Request; + using CloudBuilder.Security.Data; + using CloudBuilder.Core.Authorization; + using System; + using CloudBuilder.Security.Entity; + using CloudBuilder.Security.SearchCriteria; + using CloudBuilder.Security; + +namespace CloudBuilder.Web.Entry.Controllers.Security +{ +[Authorize(AuthorizePolicy.PERMISSION)] +[ApiController] +[Route("[controller]/[action]")] +public class SecurityUserPreferenceController : ControllerBase +{ +private readonly IApplicationService service; +private readonly ISecurityUserPreferenceService securityUserPreferenceService; + +public SecurityUserPreferenceController(IApplicationService service, ISecurityUserPreferenceService securityUserPreferenceService) +{ +this.service = service; +this.securityUserPreferenceService= securityUserPreferenceService; +} + + [AllowAnonymous] + [HttpPost] + public dynamic FindByKey(SecurityUserPreferenceEntityKey key) + { + try + { + + var result = securityUserPreferenceService.FindByKey(key); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityUserPreference", operate: "Find")] + [HttpPost] + public dynamic FindBySearchCriteria(SecurityUserPreferenceSearchCriteria criteria) + { + try + { + + var result = securityUserPreferenceService.FindBySearchCriteria(criteria); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "SecurityUserPreference", operate: "Print")] + [HttpPost] + public dynamic PrintBySearchCriteria(SecurityUserPreferenceSearchCriteria criteria) + { + try + { + + var result = securityUserPreferenceService.PrintBySearchCriteria(criteria); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [AllowAnonymous] + [HttpPost] + [UnitOfWork] + public dynamic Insert(SecurityUserPreferenceEntity data) + { + try + { + + var result = securityUserPreferenceService.Insert(data); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [AllowAnonymous] + [HttpPost] + [UnitOfWork] + public dynamic Update(SecurityUserPreferenceEntity data) + { + try + { + + var result = securityUserPreferenceService.Update(data); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [AllowAnonymous] + [HttpPost] + public dynamic Delete(SecurityUserPreferenceEntityKey key){ + try + { + securityUserPreferenceService.Delete(key); + + return string.Empty; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + +} +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Web.Entry/Controllers/Security/YesNoPolicyController.auto.cs b/CloudBuilder/CloudBuilder.Web.Entry/Controllers/Security/YesNoPolicyController.auto.cs new file mode 100644 index 0000000..5c94f6b --- /dev/null +++ b/CloudBuilder/CloudBuilder.Web.Entry/Controllers/Security/YesNoPolicyController.auto.cs @@ -0,0 +1,80 @@ + +using CloudBuilder.Core.DatabaseAccessor; +using CloudBuilder.Core.Policy; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System.Transactions; +using CloudBuilder.Core.Service; +using CloudBuilder.Security.Service; + using CloudBuilder.Core.DatabaseAccessor.Entity; + using Microsoft.AspNetCore.Http; + using CloudBuilder.Core.Policy; + using CloudBuilder.Core.DependencyInjection.Request; + using CloudBuilder.Security.Data; + using CloudBuilder.Core.Authorization; + using System; + using CloudBuilder.Security.Entity; + using CloudBuilder.Security.SearchCriteria; + using CloudBuilder.Security; + using Microsoft.Extensions.Options; + +namespace CloudBuilder.Web.Entry.Controllers.Security +{ +[Authorize(AuthorizePolicy.PERMISSION)] +[ApiController] +[Route("[controller]/[action]")] +public class YesNoPolicyController : ControllerBase +{ +private readonly IApplicationService service; +private readonly IYesNoPolicyService yesNoPolicyService; + +public YesNoPolicyController(IApplicationService service, IYesNoPolicyService yesNoPolicyService) +{ +this.service = service; +this.yesNoPolicyService= yesNoPolicyService; +} + + [AllowAnonymous] + [HttpPost] + public dynamic FindSelectOption(bool blank) + { + try + { + + var result = yesNoPolicyService.FindSelectOption(blank); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [AllowAnonymous] + [HttpGet] + public dynamic Copy() + { + try + { + + yesNoPolicyService.Copy(); + + return string.Empty; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + +} +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Web.Entry/Dockerfile b/CloudBuilder/CloudBuilder.Web.Entry/Dockerfile new file mode 100644 index 0000000..9ea4821 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Web.Entry/Dockerfile @@ -0,0 +1,29 @@ +# 請參閱 https://aka.ms/customizecontainer 了解如何自訂您的偵錯容器,以及 Visual Studio 如何使用此 Dockerfile 來組建您的映像,以加快偵錯速度。 + +# 此階段用於以快速模式從 VS 執行時 (偵錯設定的預設值) +FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base +WORKDIR /app +EXPOSE 8080 + + +# 此階段是用來組建服務專案 +FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build +ARG BUILD_CONFIGURATION=Release +WORKDIR /src +COPY ["CloudBuilder.Web.Entry/CloudBuilder.Web.Entry.csproj", "CloudBuilder.Web.Entry/"] +RUN dotnet restore "./CloudBuilder.Web.Entry/CloudBuilder.Web.Entry.csproj" +COPY . . +WORKDIR "/src/CloudBuilder.Web.Entry" +RUN dotnet build "./CloudBuilder.Web.Entry.csproj" -c $BUILD_CONFIGURATION -o /app/build + +# 此階段可用來發佈要複製到最終階段的服務專案 +FROM build AS publish +ARG BUILD_CONFIGURATION=Release +RUN dotnet publish "./CloudBuilder.Web.Entry.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false + +# 此階段用於生產環境,或以一般模式從 VS 執行時 (未使用偵錯設定時的預設值) +FROM base AS final +WORKDIR /app +COPY --from=publish /app/publish . +COPY ./dist ./dist +ENTRYPOINT ["dotnet", "CloudBuilder.Web.Entry.dll"] \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Web.Entry/Program.cs b/CloudBuilder/CloudBuilder.Web.Entry/Program.cs new file mode 100644 index 0000000..71159e8 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Web.Entry/Program.cs @@ -0,0 +1,126 @@ +using CloudBuilder.Core.DependencyInjection.Form; +using CloudBuilder.Core.Extensions; +using CloudBuilder.Core.Service; +using CloudBuilder.Security.Data; +using CloudBuilder.Security.Service; +using DocumentFormat.OpenXml.Office2016.Drawing.ChartDrawing; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.Http.Json; +using Microsoft.AspNetCore.Server.Kestrel.Core; +using Microsoft.Extensions.FileProviders; +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; +using System.Text.Json.Serialization; + +var builder = WebApplication.CreateBuilder(args); + + +builder.Services.Initialize(); +builder.Services.Configure(builder.Configuration.GetSection("WebAuthn")); + +// Add services to the container. +builder.Services.AddHttpClient().AddControllers() + .AddNewtonsoftJson(options => + { + options.SerializerSettings.ContractResolver = new DefaultContractResolver(); + options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Serialize; + options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore; + options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss"; + }); + + +builder.Services.AddSpaStaticFiles(options => { options.RootPath = "dist"; }); + +//================================上传文件============================== +//上传文件大小限制Kestrel设置 +builder.Services.Configure(options => +{ + // Set the limit to 256 MB + options.Limits.MaxRequestBodySize = null; +}); +//上传文件大小限制IIS设置 +builder.Services.Configure(options => +{ + options.MaxRequestBodySize = null; +}); + +builder.Services.Configure(options => +{ + options.ValueLengthLimit = int.MaxValue; + options.MultipartBodyLengthLimit = int.MaxValue; + options.MultipartHeadersLengthLimit = int.MaxValue; +}); +/* +如果是在VS中调试的项目 +需要修改项目根目录.vs\CloudBuilder\config\applicationhost.config 中找到节点添加 + + +如果是发布到IIS上的项目 +找到web.config在节点下添加。注意以后每次发布不要覆盖掉该web.config + + + + + + + + + + + + + + + + +IIS內修改ASP中修改最大请求实体主体限制 +*/ + +//================================上传文件============================== + +var app = builder.Build(); + +string urlOrigins = app.Configuration["UrlOrigins"]; +//跨域是否使用SSL +if (urlOrigins.Contains("https")) +{ + app.UseHttpsRedirection(); +} + +app.UseCors(b => +{ + b.WithOrigins(urlOrigins.Split(',')).AllowAnyMethod().AllowAnyHeader().AllowCredentials(); +}); + +//================================添加静态文件映射,在IIS及vs启动文件applicationhost.config的地方加入无效 +//开发环境使用以下设置,如果上线还需在IIS设置MIME +var provider = FileExtension.GetFileExtensionContentTypeProvider(); +provider.Mappings[".mp4"] = "application/x-mpegURL"; +provider.Mappings[".flac"] = "audio/x-flac"; +provider.Mappings[".m3u8"] = "application/vnd.apple.mpegurl"; +provider.Mappings[".lrc"] = "application/octet-stream"; +//虚拟文件,App.Configuration[VirtualPathPolicy.VirtualPath_RealPath]这个路径一定要存在,不然直接出错 +string physicalDir = app.Configuration["FileServiceSettings:PhysicalFileDirectory"]; +if (!string.IsNullOrEmpty(physicalDir)) +{ + app.UseStaticFiles(new StaticFileOptions() + { + FileProvider = new PhysicalFileProvider(app.Configuration["FileServiceSettings:PhysicalFileDirectory"]), + RequestPath = app.Configuration["FileServiceSettings:RequestPath"], + ContentTypeProvider = provider + }); +} + +//================================添加静态文件映射 + +// Configure the HTTP request pipeline. +app.UseAuthentication(); +app.UseRouting(); +app.UseAuthorization(); + +app.MapControllers(); + +app.UseSpaStaticFiles(); +app.UseSpa(configuration => { }); + +app.Run(); diff --git a/CloudBuilder/CloudBuilder.Web.Entry/Properties/PublishProfiles/FolderProfile.pubxml b/CloudBuilder/CloudBuilder.Web.Entry/Properties/PublishProfiles/FolderProfile.pubxml new file mode 100644 index 0000000..a1b38c7 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Web.Entry/Properties/PublishProfiles/FolderProfile.pubxml @@ -0,0 +1,21 @@ + + + + + false + false + true + Release + Any CPU + FileSystem + C:\inetpub\wwwroot\vue + FileSystem + <_TargetId>Folder + + net8.0 + 369132cb-47f8-44fd-ba90-1d6a605ac801 + false + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Web.Entry/Properties/PublishProfiles/FolderProfile.pubxml.user b/CloudBuilder/CloudBuilder.Web.Entry/Properties/PublishProfiles/FolderProfile.pubxml.user new file mode 100644 index 0000000..d95ec5e --- /dev/null +++ b/CloudBuilder/CloudBuilder.Web.Entry/Properties/PublishProfiles/FolderProfile.pubxml.user @@ -0,0 +1,11 @@ + + + + + <_PublishTargetUrl>C:\inetpub\wwwroot\vue + True|2025-02-21T01:17:42.0332319Z||;True|2025-02-20T17:54:48.5227502+08:00||;True|2025-02-20T14:43:44.4755548+08:00||;True|2025-02-18T14:48:38.1279736+08:00||;True|2025-02-18T14:30:06.8713276+08:00||;True|2025-02-18T12:23:21.7029574+08:00||;False|2025-02-18T12:00:12.8451503+08:00||;False|2025-02-18T11:59:48.3718169+08:00||;False|2025-02-18T11:59:27.1705555+08:00||;True|2025-02-18T11:58:00.6819258+08:00||;True|2025-02-18T11:55:11.3497343+08:00||;True|2025-02-18T11:17:38.2416175+08:00||;True|2025-02-18T11:15:42.5176910+08:00||;True|2025-02-18T10:18:58.1976451+08:00||;True|2025-02-18T10:12:10.1899652+08:00||;True|2025-02-18T10:11:17.8366085+08:00||;True|2025-02-18T10:05:26.8898914+08:00||;False|2025-02-18T10:04:33.0136788+08:00||;True|2025-01-13T15:33:36.8856684+08:00||;True|2025-01-13T15:09:43.9813208+08:00||;True|2025-01-13T14:48:28.7425876+08:00||;True|2024-12-09T08:41:48.9637493+08:00||;True|2024-06-11T17:33:49.2040712+08:00||;False|2024-06-11T17:32:59.6407939+08:00||;True|2024-06-11T16:30:00.2893189+08:00||;True|2024-06-11T16:17:09.6736622+08:00||;True|2024-06-06T16:29:09.6865383+08:00||;True|2024-06-06T08:52:48.6214582+08:00||;True|2024-06-06T08:27:23.8935107+08:00||;True|2024-06-05T16:54:39.9877626+08:00||;True|2024-06-05T16:43:47.3099658+08:00||;True|2024-06-05T15:16:50.1847108+08:00||;True|2024-05-31T08:05:26.5317322+08:00||;True|2024-05-31T08:04:03.7974732+08:00||;True|2024-05-30T21:42:27.5196708+08:00||;True|2024-05-30T21:37:33.9751309+08:00||;True|2024-05-30T17:28:17.6733343+08:00||;False|2024-05-30T17:28:01.8112502+08:00||;True|2024-05-29T10:59:16.8699002+08:00||;False|2024-05-29T10:58:38.9766757+08:00||;True|2024-05-28T09:35:21.2744589+08:00||;True|2024-05-27T10:28:23.0585167+08:00||;True|2024-05-26T12:51:58.7093675+08:00||;True|2024-05-26T12:51:52.1552336+08:00||;True|2024-05-26T11:33:30.5529917+08:00||;True|2024-05-26T11:22:22.0291577+08:00||;False|2024-05-26T11:22:10.9637009+08:00||;False|2024-05-26T11:21:27.5808366+08:00||;True|2024-05-25T19:32:42.7850312+08:00||;True|2024-05-25T18:16:06.8982836+08:00||;True|2024-05-25T17:56:31.4643806+08:00||;True|2024-05-25T17:54:24.5011091+08:00||;True|2024-05-25T16:53:10.2158278+08:00||;False|2024-05-25T16:52:30.0122904+08:00||;True|2024-05-22T15:20:02.5175934+08:00||;True|2024-05-21T16:57:20.6206412+08:00||;True|2024-05-21T16:29:19.8761381+08:00||;True|2024-05-21T15:42:29.4258892+08:00||;True|2024-05-21T11:13:06.6678431+08:00||;True|2024-05-21T11:10:55.1931883+08:00||;True|2024-05-21T11:07:54.1533538+08:00||;True|2024-05-21T11:07:26.0319621+08:00||;True|2024-05-21T11:06:23.7546831+08:00||;True|2024-05-21T11:01:41.0827477+08:00||;True|2024-05-20T15:04:24.6641402+08:00||;True|2024-05-20T14:46:24.0260148+08:00||;False|2024-05-20T14:45:45.0345419+08:00||;True|2024-04-26T16:32:10.3514161+08:00||;True|2024-04-26T16:03:18.3351196+08:00||;True|2024-04-26T15:53:32.9469568+08:00||;True|2024-04-26T15:49:16.1813318+08:00||;True|2024-04-26T11:41:08.9174989+08:00||;True|2024-04-26T11:39:27.5019165+08:00||;True|2024-04-26T11:33:54.2122690+08:00||;True|2024-04-26T11:11:36.8532751+08:00||;True|2024-04-26T11:11:19.8849783+08:00||;True|2024-04-26T10:07:07.7216761+08:00||;True|2024-04-26T08:54:11.5626013+08:00||;True|2024-04-03T15:31:52.2410946+08:00||;False|2024-04-03T15:10:36.5624576+08:00||;True|2024-04-03T14:18:55.5362847+08:00||;True|2024-04-02T10:31:27.4134967+08:00||;True|2024-04-02T10:17:21.1633276+08:00||;True|2024-04-02T09:18:46.3515162+08:00||;True|2024-04-02T09:17:25.1201533+08:00||;True|2024-04-02T09:13:42.1533840+08:00||;True|2024-03-25T09:05:24.0358289+08:00||;True|2024-03-22T11:10:12.4214308+08:00||;True|2024-03-22T08:56:07.5983805+08:00||;True|2024-03-21T16:38:13.6531866+08:00||;True|2024-03-20T16:51:09.0721907+08:00||;True|2024-03-20T15:39:34.0644852+08:00||;True|2024-03-19T14:24:58.8903495+08:00||;True|2024-03-19T10:22:21.2273556+08:00||;True|2024-03-18T15:29:38.8873414+08:00||;True|2024-03-14T16:06:51.9651367+08:00||;True|2024-03-07T09:21:31.6615954+08:00||;True|2024-03-05T13:45:57.1941176+08:00||;True|2024-03-05T11:48:44.3806050+08:00||;True|2024-03-05T11:02:38.1040818+08:00||; + + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Web.Entry/Properties/PublishProfiles/FolderProfile1.pubxml b/CloudBuilder/CloudBuilder.Web.Entry/Properties/PublishProfiles/FolderProfile1.pubxml new file mode 100644 index 0000000..3b6594f --- /dev/null +++ b/CloudBuilder/CloudBuilder.Web.Entry/Properties/PublishProfiles/FolderProfile1.pubxml @@ -0,0 +1,15 @@ + + + + + false + false + true + Release + Any CPU + FileSystem + C:\inetpub\wwwroot\webapi + FileSystem + <_TargetId>Folder + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Web.Entry/Properties/PublishProfiles/FolderProfile1.pubxml.user b/CloudBuilder/CloudBuilder.Web.Entry/Properties/PublishProfiles/FolderProfile1.pubxml.user new file mode 100644 index 0000000..3845089 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Web.Entry/Properties/PublishProfiles/FolderProfile1.pubxml.user @@ -0,0 +1,9 @@ + + + + + <_PublishTargetUrl>C:\inetpub\wwwroot\webapi + True|2026-08-06T05:11:18.2517555Z||;True|2026-08-06T13:09:44.6703394+08:00||;True|2026-08-06T10:39:04.1814630+08:00||;True|2026-08-06T10:03:51.6290574+08:00||;True|2026-08-06T10:03:46.6433716+08:00||;True|2026-08-06T09:57:39.5500548+08:00||;True|2026-08-06T09:43:56.5264669+08:00||;False|2026-08-06T09:42:30.9515003+08:00||;True|2026-08-06T09:39:51.6165569+08:00||;True|2026-08-06T09:38:12.2610385+08:00||;True|2026-08-06T08:18:49.5758328+08:00||;True|2026-06-24T08:26:55.0324041+08:00||;True|2026-06-24T08:21:40.3334931+08:00||;True|2026-06-24T08:20:33.0781131+08:00||;True|2026-06-24T08:09:48.1948679+08:00||;True|2026-06-23T10:11:00.8522806+08:00||; + + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Web.Entry/Properties/PublishProfiles/FolderProfile2.pubxml b/CloudBuilder/CloudBuilder.Web.Entry/Properties/PublishProfiles/FolderProfile2.pubxml new file mode 100644 index 0000000..71ef4cc --- /dev/null +++ b/CloudBuilder/CloudBuilder.Web.Entry/Properties/PublishProfiles/FolderProfile2.pubxml @@ -0,0 +1,20 @@ + + + + + false + false + true + Release + Any CPU + FileSystem + bin\Release\net8.0\publish\ + FileSystem + <_TargetId>Folder + + net8.0 + linux-x64 + 9823d7cf-5df8-bcae-391b-c2cfc51c99c2 + true + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Web.Entry/Properties/PublishProfiles/FolderProfile2.pubxml.user b/CloudBuilder/CloudBuilder.Web.Entry/Properties/PublishProfiles/FolderProfile2.pubxml.user new file mode 100644 index 0000000..7b9c078 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Web.Entry/Properties/PublishProfiles/FolderProfile2.pubxml.user @@ -0,0 +1,9 @@ + + + + + <_PublishTargetUrl>D:\Docker\CloudBuilder\CloudBuilder.Web.Entry\bin\Release\net8.0\publish\ + True|2026-08-18T08:02:14.7177454Z||;True|2026-08-18T15:58:16.6727283+08:00||;True|2026-08-18T15:44:12.0747654+08:00||; + + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Web.Entry/Properties/PublishProfiles/FolderProfile3.pubxml b/CloudBuilder/CloudBuilder.Web.Entry/Properties/PublishProfiles/FolderProfile3.pubxml new file mode 100644 index 0000000..fedead7 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Web.Entry/Properties/PublishProfiles/FolderProfile3.pubxml @@ -0,0 +1,20 @@ + + + + + false + false + true + Release + Any CPU + FileSystem + C:\inetpub\wwwroot\dockwebapi2 + FileSystem + <_TargetId>Folder + + net8.0 + linux-x64 + 9823d7cf-5df8-bcae-391b-c2cfc51c99c2 + true + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Web.Entry/Properties/PublishProfiles/FolderProfile3.pubxml.user b/CloudBuilder/CloudBuilder.Web.Entry/Properties/PublishProfiles/FolderProfile3.pubxml.user new file mode 100644 index 0000000..c9d2656 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Web.Entry/Properties/PublishProfiles/FolderProfile3.pubxml.user @@ -0,0 +1,9 @@ + + + + + <_PublishTargetUrl>C:\inetpub\wwwroot\dockwebapi2 + True|2026-08-19T05:39:59.9363522Z||;True|2026-08-19T13:36:53.0379313+08:00||;True|2026-08-19T13:31:36.0841398+08:00||;True|2026-08-19T11:44:37.5319626+08:00||;True|2026-08-19T09:36:45.6000047+08:00||;True|2026-08-19T09:34:36.8468631+08:00||;True|2026-08-19T08:35:41.2202300+08:00||;True|2026-08-18T16:20:59.0170916+08:00||; + + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Web.Entry/Properties/launchSettings.json b/CloudBuilder/CloudBuilder.Web.Entry/Properties/launchSettings.json new file mode 100644 index 0000000..57fef96 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Web.Entry/Properties/launchSettings.json @@ -0,0 +1,41 @@ +{ + "profiles": { + "http": { + "commandName": "Project", + "commandLineArgs": "D:\\NET8\\CloudBuilder\\CloudBuilder.Security.Service\\bin\\Debug\\net8.0\\CloudBuilder.Security.Service.dll", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "dotnetRunMessages": true, + "applicationUrl": "http://localhost:5235" + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "SecurityMaster/FindByAllowAnonymous", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "Container (Dockerfile)": { + "commandName": "Docker", + "launchBrowser": true, + "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/SecurityMaster/FindByAllowAnonymous", + "environmentVariables": { + "ASPNETCORE_HTTP_PORTS": "8080" + }, + "publishAllPorts": true, + "useSSL": false + } + }, + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:16958", + "sslPort": 0 + } + } +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Web.Entry/appsettings.json b/CloudBuilder/CloudBuilder.Web.Entry/appsettings.json new file mode 100644 index 0000000..396c7ef --- /dev/null +++ b/CloudBuilder/CloudBuilder.Web.Entry/appsettings.json @@ -0,0 +1,113 @@ +{ + "Logging": { + "LogFileDirectory": "D:\\Net8\\FileServer\\Log", + "MaxFileSizeMB": 20 + }, + "UrlOrigins": "http://192.168.195.68,http://localhost,http://localhost:8088,http://localhost:5235", //这个参数是反向指向的地址,也是跨域访问的地址,包含Vue内WebSitePolicy设置WebSite + "applicationUrl": "https://uat.youjiala.com", //這個地址是最外层用户访问的,不是反向指向的地址https://uat.youjiala.com + "CloudBuilder": { + "Culture": "zh-cn", + "DbContexts": { + "MasterDbContext": { + "DbContextTypeName": "MasterDbContext", + "ConnectionString": "server=nas.youjiala.com;port=3307;database=Furion;uid=root;pwd=Root@1237890;CharSet=utf8mb4;", + "DatabaseType": "MySql", + "LazyLoadingProxiesEnabled": true, + "AuditEntityEnabled": true, + "AutoMigrationEnabled": true + }, + "SecondaryDbContext": { + "DbContextTypeName": "SecondaryDbContext", + "ConnectionString": "Server=localhost\\SQLEXPRESS;Database=Furion;User=sa;Password=owen123456;MultipleActiveResultSets=True;TrustServerCertificate=true", + "DatabaseType": "SqlServer", + "LazyLoadingProxiesEnabled": true, + "AuditEntityEnabled": true, + "AutoMigrationEnabled": true + } + }, + "MailSender": { + "Host": "smtp.mxhichina.com", + "Port": 587, + "EnableSsl": true, + "DisplayName": "OSharp邮件发送", + "UserName": "osharpsender@66soft.net", + "Password": "OSharp147963" + }, + "Authorization": { "EnableGlobalAuthorize": false }, //全局授权 + "Jwt": { + "Issuer": "Owen Chen", + "Audience": "Cloud Builder", + "Secret": "{8619F7C3-B53C-4B85-99F0-983D351ECD82}", + "AccessExpireMins": 120, //4小时过期 + "RefreshExpireMins": 1440, // 1天 + "IsRefreshAbsoluteExpired": false + }, + "Redis": { + "Configuration": "localhost", + "InstanceName": "CloudBuilder:" + } + }, + "FileServiceSettings": { + "PhysicalFileDirectory": "", //D:\\Net8\\FileServer + "RequestPath": "/FileServer", //如果是IIS反向代理来的,那么要在本地给这个文件添加IUSR,IIS_IUSRS权限 + "UploadDmsFileDirectory": "D:\\Net8\\FileServer\\Upload\\DmsFile", //上传文件目录,有可能是分片文件,仅当临时文件使用 + "BackupDmsFileDirectory": "D:\\Net8\\FileServer\\Backup\\DmsFile", //这个是备份目录,也是完整文件目录,原文件目录 + "ScaleDmsFileDirectory": "D:\\Net8\\FileServer\\Scale\\DmsFile", //这个是压缩图片或者视频目录 + "ExcelOutputDirectory": "D:\\Net8\\FileServer\\Output" + }, + "Ffmpeg": { + "Path": "D:\\NET8\\Exe\\ffmpeg\\bin\\ffmpeg.exe", //视频转码 + "Pictrue": " -i {0} -ss 00:00:10.000 -frames:v 1 {1}", + "Arguments": " -i {0} -c:v libx264 -vf scale=1280:-1 -start_number 0 -hls_time {1} -hls_list_size 0 -f hls {2}" //0-源路径,1-目标路径,2-存放多少秒 1280×720,852*480 + }, + "CloudBuilder.Topshelf": { + "Path": "D:\\MAFAI\\CloudBuilder.Topshelf\\bin\\Debug\\net8.0\\CloudBuilder.Topshelf.exe" //图片压缩 + }, + "SecuritySettings": { + "RsaPublicKey": "-----BEGIN PUBLIC KEY-----MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8HMr2CBpoZPm3t9tCVlrKtTmI4jNJc7/HhxjIEiDjC8czP4PV+44LjXvLYcSV0fwi6nE4LH2c5PBPEnPfqp0g8TZeX+bYGvd70cXee9d8wHgBqi4k0J0X33c0ZnW7JruftPyvJo9OelYSofBXQTcwI+3uIl/YvrgQRv6A5mW01QIDAQAB-----END PUBLIC KEY-----", + "RsaPrivateKey": "-----BEGIN RSA PRIVATE KEY-----MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALwcyvYIGmhk+be320JWWsq1OYjiM0lzv8eHGMgSIOMLxzM/g9X7jguNe8thxJXR/CLqcTgsfZzk8E8Sc9+qnSDxNl5f5tga93vRxd5713zAeAGqLiTQnRffdzRmdbsmu5+0/K8mj056VhKh8FdBNzAj7e4iX9i+uBBG/oDmZbTVAgMBAAECgYEAmgNU5NTDkj9B+Pnt6UU8doSjw3+3j+bV2K2yS3QUOvAUus/Ax7x6ktjWxzCXvDY9IfUil2RNv9vtKEAqYLCWjc+lf8PV/yH1b7NEgyeAPBXtAJRoOnmYL2bdPW92kP9KgxJruF6Dz/C5AmMOncsvq8ABD+9Darn4p8dwj2ZC4O0CQQDf/AHmZsQokEItfCy4mHS9UbxbfIhEUv1ApPh/+Sr7NkJkHWYCtBQo+8jKO6zurAZQgWBPD1XX2UE4R+VIiZazAkEA1wAqtMvGhccyRZr+6kpkpDIa8+9jOE+nGUzqTDvgCID6as8AzOONFVVK6m/UUqkhcJ8Qu1pF36BGojy5BX2KVwJBAJSFpbji0hXXupowqfLp3RcgmNbNWAp+QUJZYhJx5cdYbmO2fssyH+AhPT6knYJR/YnqkDM8hv6vKCkqu2YDHjMCQAOA8TE5EOclM+CGghj3VWSHnIDVKdzFD4gOBNNxNlltIKeU8AJmwunSFgJ0CBXAw9a+ANvMwM7AIeaK7sj0HskCQAvxfDCq7gaNx+pfu0FHG8Gix08A/A6foggBl1fVu+L9sr9ZuOQ3HbXnl28F9ewuB9xdjnLUDjp7W7U0pB+vKoQ=-----END RSA PRIVATE KEY-----", + "DescKey": "052636a8b1469efdf5dc0034a3c5bb34", + "DefaultActor": "VIEW_SYSTEM" + }, + "IpRateLimiting": { + "EnableEndpointRateLimiting": true, //False: globally executed, true: executed for each + "StackBlockedRequests": false, //False: Number of rejections should be recorded on another counter + "RealIpHeader": "X-Real-IP", + "ClientIdHeader": "X-ClientId", + "IpWhitelist": [], //白名单 + "EndpointWhitelist": [], + "ClientWhitelist": [], + "HttpStatusCode": 200, + "QuotaExceededResponse": { + "Content": "{{\"code\":429,\"msg\":\"访问过于频繁,请稍后重试\",\"data\":null}}", + "ContentType": "application/json", + "StatusCode": 200 + }, + "GeneralRules": [ + { + "Endpoint": "*", + "Period": "1s", + "Limit": 5 + }, + { + "Endpoint": "*", + "Period": "1m", + "Limit": 50 + }, + { + "Endpoint": "*", + "Period": "12h", + "Limit": 500 + } + ] + + }, + "WebAuthn": { + "//": "RpId is the registrable domain suffix of Origin's host. It is a domain (or IP), NOT a full URL — never include the port. Origin is the full URL (scheme + host + port + path) the browser is loading the page from. For IP-based origins the rpId is just the IP (e.g. '172.16.253.243'); the port goes in Origin only. Examples: dev → RpId 'localhost' / Origin 'https://localhost:8000'; UAT → RpId '172.16.253.243' / Origin 'https://172.16.253.243:8002'; prod → RpId 'www.youjiala.com' / Origin 'https://www.youjiala.com'.", + "RpId": "uat.youjiala.com", + "RpName": "Cloud Builder", + "Origin": "https://uat.youjiala.com", + "TimeoutMs": 60000 + }, + "AllowedHosts": "*" +} diff --git a/CloudBuilder/CloudBuilder.Web.Entry/masterDmsFolder.json b/CloudBuilder/CloudBuilder.Web.Entry/masterDmsFolder.json new file mode 100644 index 0000000..d84788f --- /dev/null +++ b/CloudBuilder/CloudBuilder.Web.Entry/masterDmsFolder.json @@ -0,0 +1,10 @@ +{ + "CreateDmsFolder": { + "FileNameList": "居家类,旅游类,作品类,音乐,视频", + "0": "YYYY-主题", + "1": "YYYY-主题", + "2": "YYYY-主题", + "3": "人物分类,榜单分类,专辑分类", + "4": "YYYY-自拍,电影,电视剧" + } +} diff --git a/CloudBuilder/CloudBuilderLauncher.exe.lnk b/CloudBuilder/CloudBuilderLauncher.exe.lnk new file mode 100644 index 0000000..f0d7394 Binary files /dev/null and b/CloudBuilder/CloudBuilderLauncher.exe.lnk differ diff --git a/CloudBuilder/CloudBuilderLauncher.sln b/CloudBuilder/CloudBuilderLauncher.sln new file mode 100644 index 0000000..29cea74 --- /dev/null +++ b/CloudBuilder/CloudBuilderLauncher.sln @@ -0,0 +1,73 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.14.37111.16 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CloudBuilderLauncher", "CloudBuilderLauncher\CloudBuilderLauncher.csproj", "{6DA327D6-87FD-9F92-C842-B463A6E95A7F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CloudBuilder.Security.Gui", "CloudBuilder.Security.Gui\CloudBuilder.Security.Gui.csproj", "{063D44BC-42F9-0A59-CE39-064C43029990}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CloudBuilder.Request", "CloudBuilder.Request\CloudBuilder.Request.csproj", "{6CB84CF4-7E06-780D-C061-2A8284878458}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CloudBuilder.AI.Gui", "CloudBuilder.AI.Gui\CloudBuilder.AI.Gui.csproj", "{DCB1153B-908A-F08B-0191-DE1DF5A7309D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CloudBuilder.Gui", "CloudBuilder.Gui\CloudBuilder.Gui.csproj", "{8EFE6D03-160F-4F1F-8E23-1CDDF98AD064}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CloudBuilder.AI", "CloudBuilder.AI\CloudBuilder.AI.csproj", "{8C849E66-BEC0-F09D-791F-FB353DA7DBE7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CloudBuilder.AI.Service", "CloudBuilder.AI.Service\CloudBuilder.AI.Service.csproj", "{5767BF2F-70B3-4FF6-CB85-9C0F8F0C8612}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CloudBuilder.Security", "CloudBuilder.Security\CloudBuilder.Security.csproj", "{269A5036-BAE9-FD61-1DD5-0EA93B79F0D7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CloudBuilder.Core", "CloudBuilder.Core\CloudBuilder.Core.csproj", "{AFA9D41C-E8A5-32D3-E81B-2ABA7C37D46C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {6DA327D6-87FD-9F92-C842-B463A6E95A7F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6DA327D6-87FD-9F92-C842-B463A6E95A7F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6DA327D6-87FD-9F92-C842-B463A6E95A7F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6DA327D6-87FD-9F92-C842-B463A6E95A7F}.Release|Any CPU.Build.0 = Release|Any CPU + {063D44BC-42F9-0A59-CE39-064C43029990}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {063D44BC-42F9-0A59-CE39-064C43029990}.Debug|Any CPU.Build.0 = Debug|Any CPU + {063D44BC-42F9-0A59-CE39-064C43029990}.Release|Any CPU.ActiveCfg = Release|Any CPU + {063D44BC-42F9-0A59-CE39-064C43029990}.Release|Any CPU.Build.0 = Release|Any CPU + {6CB84CF4-7E06-780D-C061-2A8284878458}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6CB84CF4-7E06-780D-C061-2A8284878458}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6CB84CF4-7E06-780D-C061-2A8284878458}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6CB84CF4-7E06-780D-C061-2A8284878458}.Release|Any CPU.Build.0 = Release|Any CPU + {DCB1153B-908A-F08B-0191-DE1DF5A7309D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DCB1153B-908A-F08B-0191-DE1DF5A7309D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DCB1153B-908A-F08B-0191-DE1DF5A7309D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DCB1153B-908A-F08B-0191-DE1DF5A7309D}.Release|Any CPU.Build.0 = Release|Any CPU + {8EFE6D03-160F-4F1F-8E23-1CDDF98AD064}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8EFE6D03-160F-4F1F-8E23-1CDDF98AD064}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8EFE6D03-160F-4F1F-8E23-1CDDF98AD064}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8EFE6D03-160F-4F1F-8E23-1CDDF98AD064}.Release|Any CPU.Build.0 = Release|Any CPU + {8C849E66-BEC0-F09D-791F-FB353DA7DBE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8C849E66-BEC0-F09D-791F-FB353DA7DBE7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8C849E66-BEC0-F09D-791F-FB353DA7DBE7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8C849E66-BEC0-F09D-791F-FB353DA7DBE7}.Release|Any CPU.Build.0 = Release|Any CPU + {5767BF2F-70B3-4FF6-CB85-9C0F8F0C8612}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5767BF2F-70B3-4FF6-CB85-9C0F8F0C8612}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5767BF2F-70B3-4FF6-CB85-9C0F8F0C8612}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5767BF2F-70B3-4FF6-CB85-9C0F8F0C8612}.Release|Any CPU.Build.0 = Release|Any CPU + {269A5036-BAE9-FD61-1DD5-0EA93B79F0D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {269A5036-BAE9-FD61-1DD5-0EA93B79F0D7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {269A5036-BAE9-FD61-1DD5-0EA93B79F0D7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {269A5036-BAE9-FD61-1DD5-0EA93B79F0D7}.Release|Any CPU.Build.0 = Release|Any CPU + {AFA9D41C-E8A5-32D3-E81B-2ABA7C37D46C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AFA9D41C-E8A5-32D3-E81B-2ABA7C37D46C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AFA9D41C-E8A5-32D3-E81B-2ABA7C37D46C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AFA9D41C-E8A5-32D3-E81B-2ABA7C37D46C}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {1A72E767-FDC3-44C7-83DB-1EC72492724E} + EndGlobalSection +EndGlobal diff --git a/CloudBuilder/CloudBuilderLauncher/CloudBuilderLauncher.csproj b/CloudBuilder/CloudBuilderLauncher/CloudBuilderLauncher.csproj new file mode 100644 index 0000000..bfc34b6 --- /dev/null +++ b/CloudBuilder/CloudBuilderLauncher/CloudBuilderLauncher.csproj @@ -0,0 +1,68 @@ + + + + WinExe + net8.0-windows + enable + true + enable + + + + + + + + + PreserveNewest + + + + + ..\CloudBuilder.AI\bin\Debug\net8.0\CloudBuilder.AI.dll + + + ..\CloudBuilder.AI.Gui\bin\Debug\net8.0-windows\CloudBuilder.AI.Gui.dll + + + ..\CloudBuilder.Core\bin\Debug\net8.0\CloudBuilder.Core.dll + + + ..\CloudBuilder.Gui\bin\Debug\net8.0-windows\CloudBuilder.Gui.dll + + + ..\CloudBuilder.Request\bin\Debug\net8.0\CloudBuilder.Request.dll + + + ..\CloudBuilder.Security\bin\Debug\net8.0\CloudBuilder.Security.dll + + + ..\CloudBuilder.Security.Gui\bin\Debug\net8.0-windows\CloudBuilder.Security.Gui.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilderLauncher/CloudBuilderLauncher.csproj.user b/CloudBuilder/CloudBuilderLauncher/CloudBuilderLauncher.csproj.user new file mode 100644 index 0000000..0295687 --- /dev/null +++ b/CloudBuilder/CloudBuilderLauncher/CloudBuilderLauncher.csproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/CloudBuilder/CloudBuilderLauncher/Program.cs b/CloudBuilder/CloudBuilderLauncher/Program.cs new file mode 100644 index 0000000..4e7c985 --- /dev/null +++ b/CloudBuilder/CloudBuilderLauncher/Program.cs @@ -0,0 +1,73 @@ +using Azure; +using CloudBuilder.Core.DependencyInjection.Form; +using CloudBuilder.Core.DependencyInjection.Request; +using CloudBuilder.Core.Service; +using CloudBuilder.Gui; +using CloudBuilder.Gui.DependencyInjection; +using CloudBuilder.Security.Data; +using CloudBuilder.Security.Gui; +using Microsoft.Extensions.DependencyInjection; +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; +using System; +using System.Net.Http; +using System.Net.Http.Json; +using System.Net.NetworkInformation; + + +namespace CloudBuilderLauncher +{ + internal static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + // To customize application configuration such as set high DPI settings or default font, + // see https://aka.ms/applicationconfiguration. + ApplicationConfiguration.Initialize(); + + //Application.Run(new Form1()); + try + { + var services = new ServiceCollection(); + //容器初始化 + services.Initialize(); + //构造容器 + services.Build(); + + LoginForm login = ApplicationServiceContext.ServiceProvider.GetRequiredKeyedService(typeof(LoginForm).Name); + + login.InitForm(); + + if (DialogResult.OK.Equals(login.ShowDialog())) + { + login.Close(); + + MainForm mf = ApplicationServiceContext.ServiceProvider.GetRequiredKeyedService(typeof(MainForm).Name); + mf.InitForm(); + + Application.Run(mf); + } + } + catch (ValidatedException ex) + { + ShowMessageBox.ShowInfo(ex.Message); + } + catch (ServiceErrorException ex) + { + ShowMessageBox.ShowError(ex.Message); + } + catch (Exception ex) + { + ShowMessageBox.ShowError(ex.Message); + } + //容器初始化开始 + + + } + + } +} diff --git a/CloudBuilder/CloudBuilderLauncher/appsettings.json b/CloudBuilder/CloudBuilderLauncher/appsettings.json new file mode 100644 index 0000000..0421cfa --- /dev/null +++ b/CloudBuilder/CloudBuilderLauncher/appsettings.json @@ -0,0 +1,26 @@ +{ + "CloudBuilder": { + "Culture": "zh-cn", + "DefaultVersion": "Dev Ver.0.0.0.1", + "DefaultTitle": "有家相册", + "DefaultCopyright": "版权所有 © 2025 有家相册", + "DbContexts": { + "MasterDbContext": { + "DbContextTypeName": "MasterDbContext", + "ConnectionString": "Server=localhost\\SQLEXPRESS;Database=Furion_dev;User=sa;Password=owen123456;MultipleActiveResultSets=True;TrustServerCertificate=true", + "DatabaseType": "SqlServer", + "LazyLoadingProxiesEnabled": true, + "AuditEntityEnabled": true, + "AutoMigrationEnabled": true + } + }, + "ServiceRequest": { + "BaseAddress": "http://localhost:5235", + "DefaultRequestHeaders": { + "Accept": "application/json" + } + } + }, + "LogFileDirectory": "D:\\NET8\\CloudBuilder\\CloudBuilder.Web.Entry\\bin\\Debug\\net8.0\\logs", + "AllowedHosts": "*" +} diff --git a/CloudBuilder/Data/20260819.zip b/CloudBuilder/Data/20260819.zip new file mode 100644 index 0000000..2bdc4aa Binary files /dev/null and b/CloudBuilder/Data/20260819.zip differ diff --git a/CodeGenerator/.gitignore b/CodeGenerator/.gitignore new file mode 100644 index 0000000..80cd511 --- /dev/null +++ b/CodeGenerator/.gitignore @@ -0,0 +1,6 @@ +/CodeGenerator/bin +/CodeGenerator/obj +/CloudBuilder.CodeGenerator/bin +/CloudBuilder.CodeGenerator/obj + +/.vs diff --git a/CodeGenerator/CloudBuilder.CodeGenerator.exe.lnk b/CodeGenerator/CloudBuilder.CodeGenerator.exe.lnk new file mode 100644 index 0000000..83aea00 Binary files /dev/null and b/CodeGenerator/CloudBuilder.CodeGenerator.exe.lnk differ diff --git a/CodeGenerator/CloudBuilder.CodeGenerator.sln b/CodeGenerator/CloudBuilder.CodeGenerator.sln new file mode 100644 index 0000000..6b874df --- /dev/null +++ b/CodeGenerator/CloudBuilder.CodeGenerator.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.14.37111.16 d17.14 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CloudBuilder.CodeGenerator", "CloudBuilder.CodeGenerator\CloudBuilder.CodeGenerator.csproj", "{A905410A-CD69-B6DB-264C-5796F8D57CE7}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A905410A-CD69-B6DB-264C-5796F8D57CE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A905410A-CD69-B6DB-264C-5796F8D57CE7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A905410A-CD69-B6DB-264C-5796F8D57CE7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A905410A-CD69-B6DB-264C-5796F8D57CE7}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {467DD073-1E3D-4419-B580-A5A324C45BDE} + EndGlobalSection +EndGlobal diff --git a/CodeGenerator/CloudBuilder.CodeGenerator/.vs/CloudBuilder.CodeGenerator/CopilotIndices/17.14.1641.39856/CodeChunks.db b/CodeGenerator/CloudBuilder.CodeGenerator/.vs/CloudBuilder.CodeGenerator/CopilotIndices/17.14.1641.39856/CodeChunks.db new file mode 100644 index 0000000..3b0f44c Binary files /dev/null and b/CodeGenerator/CloudBuilder.CodeGenerator/.vs/CloudBuilder.CodeGenerator/CopilotIndices/17.14.1641.39856/CodeChunks.db differ diff --git a/CodeGenerator/CloudBuilder.CodeGenerator/.vs/CloudBuilder.CodeGenerator/CopilotIndices/17.14.1641.39856/SemanticSymbols.db b/CodeGenerator/CloudBuilder.CodeGenerator/.vs/CloudBuilder.CodeGenerator/CopilotIndices/17.14.1641.39856/SemanticSymbols.db new file mode 100644 index 0000000..e7704af Binary files /dev/null and b/CodeGenerator/CloudBuilder.CodeGenerator/.vs/CloudBuilder.CodeGenerator/CopilotIndices/17.14.1641.39856/SemanticSymbols.db differ diff --git a/CodeGenerator/CloudBuilder.CodeGenerator/.vs/CloudBuilder.CodeGenerator/DesignTimeBuild/.dtbcache.v2 b/CodeGenerator/CloudBuilder.CodeGenerator/.vs/CloudBuilder.CodeGenerator/DesignTimeBuild/.dtbcache.v2 new file mode 100644 index 0000000..957c936 Binary files /dev/null and b/CodeGenerator/CloudBuilder.CodeGenerator/.vs/CloudBuilder.CodeGenerator/DesignTimeBuild/.dtbcache.v2 differ diff --git a/CodeGenerator/CloudBuilder.CodeGenerator/.vs/CloudBuilder.CodeGenerator/v17/.futdcache.v2 b/CodeGenerator/CloudBuilder.CodeGenerator/.vs/CloudBuilder.CodeGenerator/v17/.futdcache.v2 new file mode 100644 index 0000000..98b0421 Binary files /dev/null and b/CodeGenerator/CloudBuilder.CodeGenerator/.vs/CloudBuilder.CodeGenerator/v17/.futdcache.v2 differ diff --git a/CodeGenerator/CloudBuilder.CodeGenerator/.vs/CloudBuilder.CodeGenerator/v17/.suo b/CodeGenerator/CloudBuilder.CodeGenerator/.vs/CloudBuilder.CodeGenerator/v17/.suo new file mode 100644 index 0000000..839fc19 Binary files /dev/null and b/CodeGenerator/CloudBuilder.CodeGenerator/.vs/CloudBuilder.CodeGenerator/v17/.suo differ diff --git a/CodeGenerator/CloudBuilder.CodeGenerator/.vs/ProjectEvaluation/cloudbuilder.codegenerator.metadata.v9.bin b/CodeGenerator/CloudBuilder.CodeGenerator/.vs/ProjectEvaluation/cloudbuilder.codegenerator.metadata.v9.bin new file mode 100644 index 0000000..17da98a Binary files /dev/null and b/CodeGenerator/CloudBuilder.CodeGenerator/.vs/ProjectEvaluation/cloudbuilder.codegenerator.metadata.v9.bin differ diff --git a/CodeGenerator/CloudBuilder.CodeGenerator/.vs/ProjectEvaluation/cloudbuilder.codegenerator.projects.v9.bin b/CodeGenerator/CloudBuilder.CodeGenerator/.vs/ProjectEvaluation/cloudbuilder.codegenerator.projects.v9.bin new file mode 100644 index 0000000..5e8c0f1 Binary files /dev/null and b/CodeGenerator/CloudBuilder.CodeGenerator/.vs/ProjectEvaluation/cloudbuilder.codegenerator.projects.v9.bin differ diff --git a/CodeGenerator/CloudBuilder.CodeGenerator/.vs/ProjectEvaluation/cloudbuilder.codegenerator.strings.v9.bin b/CodeGenerator/CloudBuilder.CodeGenerator/.vs/ProjectEvaluation/cloudbuilder.codegenerator.strings.v9.bin new file mode 100644 index 0000000..f225d95 Binary files /dev/null and b/CodeGenerator/CloudBuilder.CodeGenerator/.vs/ProjectEvaluation/cloudbuilder.codegenerator.strings.v9.bin differ diff --git a/CodeGenerator/CloudBuilder.CodeGenerator/CloudBuilder.CodeGenerator.csproj b/CodeGenerator/CloudBuilder.CodeGenerator/CloudBuilder.CodeGenerator.csproj new file mode 100644 index 0000000..714e0f7 --- /dev/null +++ b/CodeGenerator/CloudBuilder.CodeGenerator/CloudBuilder.CodeGenerator.csproj @@ -0,0 +1,71 @@ + + + + WinExe + net8.0-windows + enable + true + enable + + + + + + + + + + Always + + + Always + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ..\Lib\CloudBuilder.Core.dll + + + + + + True + True + Resources.resx + + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + \ No newline at end of file diff --git a/CodeGenerator/CloudBuilder.CodeGenerator/CloudBuilder.CodeGenerator.csproj.user b/CodeGenerator/CloudBuilder.CodeGenerator/CloudBuilder.CodeGenerator.csproj.user new file mode 100644 index 0000000..96c9fcc --- /dev/null +++ b/CodeGenerator/CloudBuilder.CodeGenerator/CloudBuilder.CodeGenerator.csproj.user @@ -0,0 +1,23 @@ + + + + + UserControl + + + Form + + + UserControl + + + UserControl + + + UserControl + + + UserControl + + + \ No newline at end of file diff --git a/CodeGenerator/CloudBuilder.CodeGenerator/Config/ToolInitConfig.cs b/CodeGenerator/CloudBuilder.CodeGenerator/Config/ToolInitConfig.cs new file mode 100644 index 0000000..63f004f --- /dev/null +++ b/CodeGenerator/CloudBuilder.CodeGenerator/Config/ToolInitConfig.cs @@ -0,0 +1,95 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Serialization; + +namespace CloudBuilder.CodeGenerator.Config +{ + public class ToolInitConfig + { + private static ToolInitConfig instance = null; + private static string filename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "config\\tool-init-config.xml"); + private static ToolInitConfig Load() + { + if (!System.IO.File.Exists(filename)) + { + throw new ValidationException("ToolInitConfig config file not found"); + } + + StringReader textReader = new StringReader(System.IO.File.ReadAllText(filename, Encoding.UTF8)); + XmlSerializer serializer = new XmlSerializer(typeof(ToolInitConfig)); + return (ToolInitConfig)serializer.Deserialize(textReader); + } + + public static void ClearInstance() + { + instance = null; + } + + public static ToolInitConfig GetInstance() + { + if (instance == null) + { + instance = Load(); + } + return instance; + } + + public string TemplatePath { get; set; } + public string CurrentAssembly { get; set; } + + public string Using { get; set; } + + public NamespaceObject[] NamespaceObjects { get; set; } + + public AssemblyReference[] AssemblyReferences { get; set; } + + public string[] ExculdePropertyTypes { get; set; } + + public static void Save(ToolInitConfig toolInitConfig) + { + XmlSerializer xmlSerializer = new XmlSerializer(typeof(ToolInitConfig)); + string xml = null; + + using (MemoryStream stream = new MemoryStream()) + { + StreamWriter writer = new StreamWriter(stream, Encoding.UTF8); + xmlSerializer.Serialize((TextWriter)writer, toolInitConfig); + stream.Seek(0L, SeekOrigin.Begin); + StreamReader reader = new StreamReader(stream, Encoding.UTF8); + xml = reader.ReadToEnd(); + } + + StreamWriter sw = new StreamWriter(filename, false); + sw.WriteLine(xml); + sw.Close(); + sw.Dispose(); + } + } + + public class AssemblyReference + { + public string AssemblyFileName { get; set; } + } + + public class NamespaceObject + { + public const string OUT_FILE_PATH = "OutFilePath"; + public const string ASSEMBLY = "Assembly"; + public const string NAMESPACE = "Namespace"; + + public string TemplateType { get; set; } + public string TemplateFileName { get; set; } + public string OutFilePath { get; set; } + public string Assembly { get; set; } + public string Namespace { get; set; } + + public string FileNameSuffix { get; set; } + + public string FileNamePrefix { get; set; } + + } +} diff --git a/CodeGenerator/CloudBuilder.CodeGenerator/Config/tool-init-config.xml b/CodeGenerator/CloudBuilder.CodeGenerator/Config/tool-init-config.xml new file mode 100644 index 0000000..eb2eaa6 --- /dev/null +++ b/CodeGenerator/CloudBuilder.CodeGenerator/Config/tool-init-config.xml @@ -0,0 +1,203 @@ + + + D:\Docker\Templates + CloudBuilder.AI + + @using CloudBuilder.CodeGenerator.Config; + @using CloudBuilder.CodeGenerator.Data; + @using CloudBuilder.CodeGenerator.Entity; + @using CloudBuilder.Core.Application.Builders; + @using CloudBuilder.Core.DatabaseAccessor.Entity; + @using CloudBuilder.Core.DependencyInjection.Form; + @using CloudBuilder.Core.Extensions; + @using CloudBuilder.Core.Utility; + @using Microsoft.Extensions.DependencyInjection; + @using System.Data; + @using System; + @using System.Reflection; + + + + Request + Request.cshtml + D:\Docker\CloudBuilder\CloudBuilder.Request\AI + CloudBuilder.Request + CloudBuilder.Request.AI + Request.auto.cs + + + + Entity + IEntity.cshtml + D:\Docker\CloudBuilder\CloudBuilder.AI\Entity + CloudBuilder.AI + CloudBuilder.AI + Entity.auto.cs + + + IEntityKey + IEntityKey.cshtml + D:\Docker\CloudBuilder\CloudBuilder.AI\Entity + CloudBuilder.AI + CloudBuilder.AI + EntityKey.auto.cs + + + IService + IService.cshtml + D:\Docker\CloudBuilder\CloudBuilder.AI\Service + CloudBuilder.AI + CloudBuilder.AI + Service.auto.cs + I + + + Permission + Permission.cshtml + D:\Docker\CloudBuilder\CloudBuilder.AI\Policy + CloudBuilder.AI + CloudBuilder.AI + PermissionPolicy.auto.cs + + + RegistEntity + RegistEntity.cshtml + D:\Docker\CloudBuilder\CloudBuilder.AI\Entity + CloudBuilder.AI + CloudBuilder.AI + RegistEntity.auto.cs + + + SearchCriteria + SearchCriteria.cshtml + D:\Docker\CloudBuilder\CloudBuilder.AI\SearchCriteria + CloudBuilder.AI + CloudBuilder.AI + SearchCriteria.auto.cs + + + Service + Service.cshtml + D:\Docker\CloudBuilder\CloudBuilder.AI.Service + CloudBuilder.AI + CloudBuilder.AI + Service.auto.cs + + + TypeScript + TypeScript.cshtml + D:\Docker\WebVue\src\data\auto + CloudBuilder.AI + CloudBuilder.AI + .ts + + + Controller + Controller.cshtml + D:\Docker\CloudBuilder\CloudBuilder.Web.Entry\Controllers\Ai + CloudBuilder.AI.Service + CloudBuilder.Web.Entry.Controllers.Ai + Controller.auto.cs + + + TypeScriptService + TypeScriptService.cshtml + D:\Docker\WebVue\src\service\Ai + CloudBuilder.AI.Service + CloudBuilder.Web.Entry.Controllers.Ai + .ts + + + Entity + IEntity.cshtml + D:\Docker\CloudBuilder\CloudBuilder.Security\Entity + CloudBuilder.Security + CloudBuilder.Security + Entity.auto.cs + + + IEntityKey + IEntityKey.cshtml + D:\Docker\CloudBuilder\CloudBuilder.Security\Entity + CloudBuilder.Security + CloudBuilder.Security + EntityKey.auto.cs + + + IService + IService.cshtml + D:\Docker\CloudBuilder\CloudBuilder.Security\Service + CloudBuilder.Security + CloudBuilder.Security + Service.auto.cs + I + + + Permission + Permission.cshtml + D:\Docker\CloudBuilder\CloudBuilder.Security\Policy + CloudBuilder.Security + CloudBuilder.Security + PermissionPolicy.auto.cs + + + RegistEntity + RegistEntity.cshtml + D:\Docker\CloudBuilder\CloudBuilder.Security\Entity + CloudBuilder.Security + CloudBuilder.Security + RegistEntity.auto.cs + + + SearchCriteria + SearchCriteria.cshtml + D:\Docker\CloudBuilder\CloudBuilder.Security\SearchCriteria + CloudBuilder.Security + CloudBuilder.Security + SearchCriteria.auto.cs + + + Service + Service.cshtml + D:\Docker\CloudBuilder\CloudBuilder.Security.Service + CloudBuilder.Security + CloudBuilder.Security + Service.auto.cs + + + TypeScript + TypeScript.cshtml + D:\Docker\WebVue\src\data\auto + CloudBuilder.Security + CloudBuilder.Security + .ts + + + Controller + Controller.cshtml + D:\Docker\CloudBuilder\CloudBuilder.Web.Entry\Controllers\Security + CloudBuilder.Security.Service + CloudBuilder.Web.Entry.Controllers.Security + Controller.auto.cs + + + TypeScriptService + TypeScriptService.cshtml + D:\Docker\WebVue\src\service\security + CloudBuilder.Security.Service + CloudBuilder.Web.Entry.Controllers.Security + .ts + + + + + D:\Docker\CloudBuilder\CloudBuilder.Security.Service\bin\Debug\net8.0\CloudBuilder.Security.Service.dll + + + D:\Docker\CloudBuilder\CloudBuilder.Security\bin\Debug\net8.0\CloudBuilder.Security.dll + + + + Dictionary + + diff --git a/CodeGenerator/CloudBuilder.CodeGenerator/ConfigUserControl.Designer.cs b/CodeGenerator/CloudBuilder.CodeGenerator/ConfigUserControl.Designer.cs new file mode 100644 index 0000000..afee2bf --- /dev/null +++ b/CodeGenerator/CloudBuilder.CodeGenerator/ConfigUserControl.Designer.cs @@ -0,0 +1,527 @@ +namespace CloudBuilder.CodeGenerator +{ + partial class ConfigUserControl + { + /// + /// 設計工具所需的變數。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清除任何使用中的資源。 + /// + /// 如果應該處置受控資源則為 true,否則為 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 元件設計工具產生的程式碼 + + /// + /// 此為設計工具支援所需的方法 - 請勿使用程式碼編輯器修改 + /// 這個方法的內容。 + /// + private void InitializeComponent() + { + folderBrowserDialog1 = new FolderBrowserDialog(); + kryptonLabel1 = new Krypton.Toolkit.KryptonLabel(); + kryptonLabel2 = new Krypton.Toolkit.KryptonLabel(); + kryptonLabel3 = new Krypton.Toolkit.KryptonLabel(); + kryptonLabel4 = new Krypton.Toolkit.KryptonLabel(); + kryptonLabel5 = new Krypton.Toolkit.KryptonLabel(); + kryptonHeader1 = new Krypton.Toolkit.KryptonHeader(); + tableLayoutPanel1 = new TableLayoutPanel(); + outFilePathTxt = new Krypton.Toolkit.KryptonTextBox(); + outFilePathBut = new Krypton.Toolkit.KryptonButton(); + assemblyTxt = new Krypton.Toolkit.KryptonTextBox(); + kryptonLabel8 = new Krypton.Toolkit.KryptonLabel(); + templatePathTxt = new Krypton.Toolkit.KryptonTextBox(); + templatePathBut = new Krypton.Toolkit.KryptonButton(); + templateTypeTxt = new Krypton.Toolkit.KryptonTextBox(); + kryptonLabel9 = new Krypton.Toolkit.KryptonLabel(); + templateFileNameTxt = new Krypton.Toolkit.KryptonTextBox(); + kryptonHeader3 = new Krypton.Toolkit.KryptonHeader(); + kryptonLabel7 = new Krypton.Toolkit.KryptonLabel(); + assemblyComboBox = new Krypton.Toolkit.KryptonComboBox(); + templateTypeCombox = new Krypton.Toolkit.KryptonComboBox(); + kryptonHeader4 = new Krypton.Toolkit.KryptonHeader(); + dbConnTxt = new Krypton.Toolkit.KryptonTextBox(); + kryptonHeader2 = new Krypton.Toolkit.KryptonHeader(); + kryptonHeader6 = new Krypton.Toolkit.KryptonHeader(); + kryptonLabel6 = new Krypton.Toolkit.KryptonLabel(); + usingTxt = new Krypton.Toolkit.KryptonRichTextBox(); + kryptonLabel10 = new Krypton.Toolkit.KryptonLabel(); + fileNameSuffixTxt = new Krypton.Toolkit.KryptonTextBox(); + tableLayoutPanel2 = new TableLayoutPanel(); + saveConfigBut = new Krypton.Toolkit.KryptonButton(); + deleteConfigBut = new Krypton.Toolkit.KryptonButton(); + namespaceTxt = new Krypton.Toolkit.KryptonTextBox(); + kryptonLabel11 = new Krypton.Toolkit.KryptonLabel(); + fileNamePrefixTxt = new Krypton.Toolkit.KryptonTextBox(); + tableLayoutPanel1.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)assemblyComboBox).BeginInit(); + ((System.ComponentModel.ISupportInitialize)templateTypeCombox).BeginInit(); + tableLayoutPanel2.SuspendLayout(); + SuspendLayout(); + // + // kryptonLabel1 + // + kryptonLabel1.Location = new Point(4, 45); + kryptonLabel1.Margin = new Padding(4, 6, 4, 4); + kryptonLabel1.Name = "kryptonLabel1"; + kryptonLabel1.Size = new Size(75, 20); + kryptonLabel1.TabIndex = 0; + kryptonLabel1.Values.Text = "模板路径:"; + // + // kryptonLabel2 + // + kryptonLabel2.Location = new Point(4, 272); + kryptonLabel2.Margin = new Padding(4); + kryptonLabel2.Name = "kryptonLabel2"; + kryptonLabel2.Size = new Size(75, 20); + kryptonLabel2.TabIndex = 1; + kryptonLabel2.Values.Text = "输出路径:"; + // + // kryptonLabel3 + // + kryptonLabel3.Location = new Point(4, 303); + kryptonLabel3.Margin = new Padding(4); + kryptonLabel3.Name = "kryptonLabel3"; + kryptonLabel3.Size = new Size(62, 20); + kryptonLabel3.TabIndex = 2; + kryptonLabel3.Values.Text = "程序集:"; + // + // kryptonLabel4 + // + kryptonLabel4.Location = new Point(4, 334); + kryptonLabel4.Margin = new Padding(4); + kryptonLabel4.Name = "kryptonLabel4"; + kryptonLabel4.Size = new Size(75, 20); + kryptonLabel4.TabIndex = 3; + kryptonLabel4.Values.Text = "命名空间:"; + // + // kryptonLabel5 + // + kryptonLabel5.Location = new Point(4, 74); + kryptonLabel5.Margin = new Padding(4); + kryptonLabel5.Name = "kryptonLabel5"; + kryptonLabel5.Size = new Size(88, 20); + kryptonLabel5.TabIndex = 8; + kryptonLabel5.Values.Text = "程序集集合:"; + // + // kryptonHeader1 + // + tableLayoutPanel1.SetColumnSpan(kryptonHeader1, 4); + kryptonHeader1.Dock = DockStyle.Fill; + kryptonHeader1.Location = new Point(4, 4); + kryptonHeader1.Margin = new Padding(4); + kryptonHeader1.Name = "kryptonHeader1"; + kryptonHeader1.Size = new Size(792, 31); + kryptonHeader1.TabIndex = 12; + kryptonHeader1.Values.Description = ""; + kryptonHeader1.Values.Heading = "模块化设置"; + kryptonHeader1.Values.Image = null; + // + // tableLayoutPanel1 + // + tableLayoutPanel1.AutoSize = true; + tableLayoutPanel1.AutoSizeMode = AutoSizeMode.GrowAndShrink; + tableLayoutPanel1.ColumnCount = 4; + tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F)); + tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 20F)); + tableLayoutPanel1.Controls.Add(kryptonLabel2, 0, 10); + tableLayoutPanel1.Controls.Add(kryptonLabel3, 0, 11); + tableLayoutPanel1.Controls.Add(kryptonLabel4, 0, 12); + tableLayoutPanel1.Controls.Add(outFilePathTxt, 1, 10); + tableLayoutPanel1.Controls.Add(outFilePathBut, 2, 10); + tableLayoutPanel1.Controls.Add(assemblyTxt, 1, 11); + tableLayoutPanel1.Controls.Add(kryptonHeader1, 0, 0); + tableLayoutPanel1.Controls.Add(kryptonLabel1, 0, 1); + tableLayoutPanel1.Controls.Add(kryptonLabel8, 0, 6); + tableLayoutPanel1.Controls.Add(templatePathTxt, 1, 1); + tableLayoutPanel1.Controls.Add(templatePathBut, 2, 1); + tableLayoutPanel1.Controls.Add(templateTypeTxt, 1, 6); + tableLayoutPanel1.Controls.Add(kryptonLabel9, 0, 7); + tableLayoutPanel1.Controls.Add(templateFileNameTxt, 1, 7); + tableLayoutPanel1.Controls.Add(kryptonHeader3, 0, 5); + tableLayoutPanel1.Controls.Add(kryptonLabel5, 0, 2); + tableLayoutPanel1.Controls.Add(kryptonLabel7, 0, 4); + tableLayoutPanel1.Controls.Add(assemblyComboBox, 1, 2); + tableLayoutPanel1.Controls.Add(templateTypeCombox, 1, 4); + tableLayoutPanel1.Controls.Add(kryptonHeader4, 0, 3); + tableLayoutPanel1.Controls.Add(dbConnTxt, 1, 21); + tableLayoutPanel1.Controls.Add(kryptonHeader2, 0, 19); + tableLayoutPanel1.Controls.Add(kryptonHeader6, 0, 17); + tableLayoutPanel1.Controls.Add(kryptonLabel6, 0, 21); + tableLayoutPanel1.Controls.Add(usingTxt, 0, 18); + tableLayoutPanel1.Controls.Add(kryptonLabel10, 0, 9); + tableLayoutPanel1.Controls.Add(fileNameSuffixTxt, 1, 9); + tableLayoutPanel1.Controls.Add(tableLayoutPanel2, 1, 15); + tableLayoutPanel1.Controls.Add(namespaceTxt, 1, 12); + tableLayoutPanel1.Controls.Add(kryptonLabel11, 0, 8); + tableLayoutPanel1.Controls.Add(fileNamePrefixTxt, 1, 8); + tableLayoutPanel1.Dock = DockStyle.Fill; + tableLayoutPanel1.Location = new Point(0, 0); + tableLayoutPanel1.Margin = new Padding(4); + tableLayoutPanel1.Name = "tableLayoutPanel1"; + tableLayoutPanel1.RowCount = 22; + tableLayoutPanel1.RowStyles.Add(new RowStyle()); + tableLayoutPanel1.RowStyles.Add(new RowStyle()); + tableLayoutPanel1.RowStyles.Add(new RowStyle()); + tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Absolute, 8F)); + tableLayoutPanel1.RowStyles.Add(new RowStyle()); + tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Absolute, 8F)); + tableLayoutPanel1.RowStyles.Add(new RowStyle()); + tableLayoutPanel1.RowStyles.Add(new RowStyle()); + tableLayoutPanel1.RowStyles.Add(new RowStyle()); + tableLayoutPanel1.RowStyles.Add(new RowStyle()); + tableLayoutPanel1.RowStyles.Add(new RowStyle()); + tableLayoutPanel1.RowStyles.Add(new RowStyle()); + tableLayoutPanel1.RowStyles.Add(new RowStyle()); + tableLayoutPanel1.RowStyles.Add(new RowStyle()); + tableLayoutPanel1.RowStyles.Add(new RowStyle()); + tableLayoutPanel1.RowStyles.Add(new RowStyle()); + tableLayoutPanel1.RowStyles.Add(new RowStyle()); + tableLayoutPanel1.RowStyles.Add(new RowStyle()); + tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent, 100F)); + tableLayoutPanel1.RowStyles.Add(new RowStyle()); + tableLayoutPanel1.RowStyles.Add(new RowStyle()); + tableLayoutPanel1.RowStyles.Add(new RowStyle()); + tableLayoutPanel1.Size = new Size(800, 600); + tableLayoutPanel1.TabIndex = 1; + // + // outFilePathTxt + // + outFilePathTxt.Location = new Point(100, 272); + outFilePathTxt.Margin = new Padding(4); + outFilePathTxt.Name = "outFilePathTxt"; + outFilePathTxt.Size = new Size(599, 23); + outFilePathTxt.TabIndex = 4; + // + // outFilePathBut + // + outFilePathBut.AutoSize = true; + outFilePathBut.Location = new Point(707, 272); + outFilePathBut.Margin = new Padding(4); + outFilePathBut.Name = "outFilePathBut"; + outFilePathBut.Size = new Size(89, 22); + outFilePathBut.TabIndex = 5; + outFilePathBut.Values.Text = "选择文件夹(...)"; + outFilePathBut.Click += outFilePathBut_Click; + // + // assemblyTxt + // + assemblyTxt.Location = new Point(100, 303); + assemblyTxt.Margin = new Padding(4); + assemblyTxt.Name = "assemblyTxt"; + assemblyTxt.Size = new Size(347, 23); + assemblyTxt.TabIndex = 9; + // + // kryptonLabel8 + // + kryptonLabel8.Location = new Point(4, 148); + kryptonLabel8.Margin = new Padding(4); + kryptonLabel8.Name = "kryptonLabel8"; + kryptonLabel8.Size = new Size(75, 20); + kryptonLabel8.TabIndex = 3; + kryptonLabel8.Values.Text = "模板名称:"; + // + // templatePathTxt + // + templatePathTxt.Location = new Point(100, 43); + templatePathTxt.Margin = new Padding(4); + templatePathTxt.Name = "templatePathTxt"; + templatePathTxt.Size = new Size(599, 23); + templatePathTxt.TabIndex = 4; + // + // templatePathBut + // + templatePathBut.AutoSize = true; + templatePathBut.Location = new Point(707, 43); + templatePathBut.Margin = new Padding(4); + templatePathBut.Name = "templatePathBut"; + templatePathBut.Size = new Size(89, 22); + templatePathBut.TabIndex = 5; + templatePathBut.Values.Text = "选择文件夹(...)"; + templatePathBut.Click += templatePathBut_Click; + // + // templateTypeTxt + // + templateTypeTxt.Location = new Point(100, 148); + templateTypeTxt.Margin = new Padding(4); + templateTypeTxt.Name = "templateTypeTxt"; + templateTypeTxt.Size = new Size(347, 23); + templateTypeTxt.TabIndex = 4; + // + // kryptonLabel9 + // + kryptonLabel9.Location = new Point(4, 179); + kryptonLabel9.Margin = new Padding(4); + kryptonLabel9.Name = "kryptonLabel9"; + kryptonLabel9.Size = new Size(62, 20); + kryptonLabel9.TabIndex = 3; + kryptonLabel9.Values.Text = "文件名:"; + // + // templateFileNameTxt + // + templateFileNameTxt.Location = new Point(100, 179); + templateFileNameTxt.Margin = new Padding(4); + templateFileNameTxt.Name = "templateFileNameTxt"; + templateFileNameTxt.Size = new Size(347, 23); + templateFileNameTxt.TabIndex = 4; + // + // kryptonHeader3 + // + tableLayoutPanel1.SetColumnSpan(kryptonHeader3, 3); + kryptonHeader3.Dock = DockStyle.Fill; + kryptonHeader3.Location = new Point(3, 139); + kryptonHeader3.Name = "kryptonHeader3"; + kryptonHeader3.Size = new Size(794, 2); + kryptonHeader3.TabIndex = 14; + kryptonHeader3.Values.Description = ""; + kryptonHeader3.Values.Heading = ""; + kryptonHeader3.Values.Image = null; + // + // kryptonLabel7 + // + kryptonLabel7.Location = new Point(4, 111); + kryptonLabel7.Margin = new Padding(4); + kryptonLabel7.Name = "kryptonLabel7"; + kryptonLabel7.Size = new Size(75, 20); + kryptonLabel7.TabIndex = 3; + kryptonLabel7.Values.Text = "模板名称:"; + // + // assemblyComboBox + // + assemblyComboBox.DropDownStyle = ComboBoxStyle.DropDownList; + assemblyComboBox.DropDownWidth = 362; + assemblyComboBox.IntegralHeight = false; + assemblyComboBox.Location = new Point(100, 74); + assemblyComboBox.Margin = new Padding(4); + assemblyComboBox.Name = "assemblyComboBox"; + assemblyComboBox.Size = new Size(347, 21); + assemblyComboBox.TabIndex = 6; + assemblyComboBox.SelectionChangeCommitted += assemblyComboBox_SelectionChangeCommitted; + // + // templateTypeCombox + // + templateTypeCombox.DropDownStyle = ComboBoxStyle.DropDownList; + templateTypeCombox.DropDownWidth = 362; + templateTypeCombox.IntegralHeight = false; + templateTypeCombox.Location = new Point(100, 111); + templateTypeCombox.Margin = new Padding(4); + templateTypeCombox.Name = "templateTypeCombox"; + templateTypeCombox.Size = new Size(347, 21); + templateTypeCombox.TabIndex = 6; + templateTypeCombox.SelectionChangeCommitted += templateTypeCombox_SelectionChangeCommitted; + // + // kryptonHeader4 + // + tableLayoutPanel1.SetColumnSpan(kryptonHeader4, 3); + kryptonHeader4.Dock = DockStyle.Fill; + kryptonHeader4.Location = new Point(3, 102); + kryptonHeader4.Name = "kryptonHeader4"; + kryptonHeader4.Size = new Size(794, 2); + kryptonHeader4.TabIndex = 14; + kryptonHeader4.Values.Description = ""; + kryptonHeader4.Values.Heading = ""; + kryptonHeader4.Values.Image = null; + // + // dbConnTxt + // + tableLayoutPanel1.SetColumnSpan(dbConnTxt, 2); + dbConnTxt.Location = new Point(100, 573); + dbConnTxt.Margin = new Padding(4); + dbConnTxt.Name = "dbConnTxt"; + dbConnTxt.ReadOnly = true; + dbConnTxt.Size = new Size(696, 23); + dbConnTxt.StateCommon.Back.Color1 = Color.Silver; + dbConnTxt.TabIndex = 11; + // + // kryptonHeader2 + // + tableLayoutPanel1.SetColumnSpan(kryptonHeader2, 4); + kryptonHeader2.Dock = DockStyle.Fill; + kryptonHeader2.Location = new Point(4, 534); + kryptonHeader2.Margin = new Padding(4); + kryptonHeader2.Name = "kryptonHeader2"; + kryptonHeader2.Size = new Size(792, 31); + kryptonHeader2.TabIndex = 13; + kryptonHeader2.Values.Description = ""; + kryptonHeader2.Values.Heading = "数据库连接设置"; + kryptonHeader2.Values.Image = null; + // + // kryptonHeader6 + // + tableLayoutPanel1.SetColumnSpan(kryptonHeader6, 4); + kryptonHeader6.Dock = DockStyle.Fill; + kryptonHeader6.Location = new Point(4, 398); + kryptonHeader6.Margin = new Padding(4); + kryptonHeader6.Name = "kryptonHeader6"; + kryptonHeader6.Size = new Size(792, 31); + kryptonHeader6.TabIndex = 13; + kryptonHeader6.Values.Description = ""; + kryptonHeader6.Values.Heading = "Using设置"; + kryptonHeader6.Values.Image = null; + // + // kryptonLabel6 + // + kryptonLabel6.Location = new Point(4, 573); + kryptonLabel6.Margin = new Padding(4); + kryptonLabel6.Name = "kryptonLabel6"; + kryptonLabel6.Size = new Size(88, 20); + kryptonLabel6.TabIndex = 10; + kryptonLabel6.Values.Text = "数据库连接:"; + // + // usingTxt + // + tableLayoutPanel1.SetColumnSpan(usingTxt, 3); + usingTxt.Dock = DockStyle.Fill; + usingTxt.Location = new Point(3, 436); + usingTxt.Name = "usingTxt"; + usingTxt.Size = new Size(794, 91); + usingTxt.TabIndex = 15; + usingTxt.Text = ""; + // + // kryptonLabel10 + // + kryptonLabel10.Location = new Point(4, 241); + kryptonLabel10.Margin = new Padding(4); + kryptonLabel10.Name = "kryptonLabel10"; + kryptonLabel10.Size = new Size(75, 20); + kryptonLabel10.TabIndex = 3; + kryptonLabel10.Values.Text = "文件后缀:"; + // + // fileNameSuffixTxt + // + fileNameSuffixTxt.Location = new Point(100, 241); + fileNameSuffixTxt.Margin = new Padding(4); + fileNameSuffixTxt.Name = "fileNameSuffixTxt"; + fileNameSuffixTxt.Size = new Size(347, 23); + fileNameSuffixTxt.TabIndex = 4; + // + // tableLayoutPanel2 + // + tableLayoutPanel2.AutoSize = true; + tableLayoutPanel2.AutoSizeMode = AutoSizeMode.GrowAndShrink; + tableLayoutPanel2.ColumnCount = 2; + tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F)); + tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F)); + tableLayoutPanel2.Controls.Add(saveConfigBut, 0, 0); + tableLayoutPanel2.Controls.Add(deleteConfigBut, 1, 0); + tableLayoutPanel2.Location = new Point(96, 361); + tableLayoutPanel2.Margin = new Padding(0); + tableLayoutPanel2.Name = "tableLayoutPanel2"; + tableLayoutPanel2.RowCount = 1; + tableLayoutPanel2.RowStyles.Add(new RowStyle(SizeType.Percent, 50F)); + tableLayoutPanel2.Size = new Size(226, 33); + tableLayoutPanel2.TabIndex = 7; + // + // saveConfigBut + // + saveConfigBut.Location = new Point(4, 4); + saveConfigBut.Margin = new Padding(4); + saveConfigBut.Name = "saveConfigBut"; + saveConfigBut.Size = new Size(105, 25); + saveConfigBut.TabIndex = 0; + saveConfigBut.Values.Text = "保存"; + saveConfigBut.Click += saveConfigBut_Click; + // + // deleteConfigBut + // + deleteConfigBut.Location = new Point(117, 4); + deleteConfigBut.Margin = new Padding(4); + deleteConfigBut.Name = "deleteConfigBut"; + deleteConfigBut.Size = new Size(105, 25); + deleteConfigBut.TabIndex = 1; + deleteConfigBut.Values.Text = "删除"; + deleteConfigBut.Click += deleteConfigBut_Click; + // + // namespaceTxt + // + namespaceTxt.Location = new Point(100, 334); + namespaceTxt.Margin = new Padding(4); + namespaceTxt.Name = "namespaceTxt"; + namespaceTxt.Size = new Size(347, 23); + namespaceTxt.TabIndex = 4; + // + // kryptonLabel11 + // + kryptonLabel11.Location = new Point(4, 210); + kryptonLabel11.Margin = new Padding(4); + kryptonLabel11.Name = "kryptonLabel11"; + kryptonLabel11.Size = new Size(75, 20); + kryptonLabel11.TabIndex = 3; + kryptonLabel11.Values.Text = "文件前缀:"; + // + // fileNamePrefixTxt + // + fileNamePrefixTxt.Location = new Point(100, 210); + fileNamePrefixTxt.Margin = new Padding(4); + fileNamePrefixTxt.Name = "fileNamePrefixTxt"; + fileNamePrefixTxt.Size = new Size(347, 23); + fileNamePrefixTxt.TabIndex = 4; + // + // ConfigUserControl + // + AutoScaleDimensions = new SizeF(7F, 17F); + AutoScaleMode = AutoScaleMode.Font; + Controls.Add(tableLayoutPanel1); + Name = "ConfigUserControl"; + Size = new Size(800, 600); + tableLayoutPanel1.ResumeLayout(false); + tableLayoutPanel1.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)assemblyComboBox).EndInit(); + ((System.ComponentModel.ISupportInitialize)templateTypeCombox).EndInit(); + tableLayoutPanel2.ResumeLayout(false); + ResumeLayout(false); + PerformLayout(); + } + + #endregion + + private FolderBrowserDialog folderBrowserDialog1; + private Krypton.Toolkit.KryptonLabel kryptonLabel1; + private Krypton.Toolkit.KryptonLabel kryptonLabel2; + private Krypton.Toolkit.KryptonLabel kryptonLabel3; + private Krypton.Toolkit.KryptonLabel kryptonLabel4; + private Krypton.Toolkit.KryptonLabel kryptonLabel5; + private TableLayoutPanel tableLayoutPanel1; + private Krypton.Toolkit.KryptonHeader kryptonHeader1; + private Krypton.Toolkit.KryptonLabel kryptonLabel8; + private Krypton.Toolkit.KryptonLabel kryptonLabel9; + private Krypton.Toolkit.KryptonHeader kryptonHeader3; + private Krypton.Toolkit.KryptonTextBox outFilePathTxt; + private Krypton.Toolkit.KryptonTextBox namespaceTxt; + private Krypton.Toolkit.KryptonButton outFilePathBut; + private TableLayoutPanel tableLayoutPanel2; + private Krypton.Toolkit.KryptonButton saveConfigBut; + private Krypton.Toolkit.KryptonButton deleteConfigBut; + private Krypton.Toolkit.KryptonTextBox assemblyTxt; + public Krypton.Toolkit.KryptonComboBox assemblyComboBox; + private Krypton.Toolkit.KryptonTextBox templatePathTxt; + private Krypton.Toolkit.KryptonButton templatePathBut; + private Krypton.Toolkit.KryptonTextBox templateTypeTxt; + private Krypton.Toolkit.KryptonTextBox templateFileNameTxt; + private Krypton.Toolkit.KryptonLabel kryptonLabel7; + private Krypton.Toolkit.KryptonComboBox templateTypeCombox; + private Krypton.Toolkit.KryptonHeader kryptonHeader4; + private Krypton.Toolkit.KryptonHeader kryptonHeader6; + private Krypton.Toolkit.KryptonTextBox dbConnTxt; + private Krypton.Toolkit.KryptonHeader kryptonHeader2; + private Krypton.Toolkit.KryptonLabel kryptonLabel6; + private Krypton.Toolkit.KryptonRichTextBox usingTxt; + private Krypton.Toolkit.KryptonLabel kryptonLabel10; + private Krypton.Toolkit.KryptonTextBox fileNameSuffixTxt; + private Krypton.Toolkit.KryptonLabel kryptonLabel11; + private Krypton.Toolkit.KryptonTextBox fileNamePrefixTxt; + } +} diff --git a/CodeGenerator/CloudBuilder.CodeGenerator/ConfigUserControl.cs b/CodeGenerator/CloudBuilder.CodeGenerator/ConfigUserControl.cs new file mode 100644 index 0000000..c144e0c --- /dev/null +++ b/CodeGenerator/CloudBuilder.CodeGenerator/ConfigUserControl.cs @@ -0,0 +1,255 @@ +using CloudBuilder.CodeGenerator.Config; +using CloudBuilder.Core.DatabaseAccessor; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using CloudBuilder.Core.DependencyInjection.Form; +using CloudBuilder.Core.Utility; +using Microsoft.AspNetCore.Connections; +using Microsoft.AspNetCore.Routing.Template; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace CloudBuilder.CodeGenerator +{ + public partial class ConfigUserControl : UserControl, IUserControl + { + private readonly IApplicationService app; + private readonly OperationUserControl operationUserControl; + public ToolInitConfig toolInitConfig; + public ConfigUserControl(IApplicationService app, + [FromKeyedServices("OperationUserControl")] OperationUserControl operationUserControl) + { + InitializeComponent(); + this.app = app; + this.operationUserControl = operationUserControl; + InitUserControl(); + } + + public void InitUserControl() + { + dbConnTxt.Text = app.CloudBuilder.CloudBuilderOptions.DbContexts[MasterDbContext.MASTER_DB_CONTEXT].ConnectionString; + + toolInitConfig = ToolInitConfig.GetInstance(); + + app.CloudBuilder.Services.AddSingleton(toolInitConfig); + usingTxt.Text = toolInitConfig.Using; + + assemblyComboBox.DisplayMember = "Text"; + assemblyComboBox.ValueMember = "Value"; + + List l = new List(); + foreach (NamespaceObject nso in toolInitConfig.NamespaceObjects) + { + if (l.Select(x => x.Text).Contains(nso.Assembly)) continue; + l.Add(CreateNewComboBoxItem(nso.Assembly, nso.Assembly)); + } + + DataTable dtbl = DataTableConvertor.ToDataTable(l); + assemblyComboBox.DataSource = dtbl; + + assemblyComboBox.SelectedValue = toolInitConfig.CurrentAssembly; + + templateTypeCombox.DisplayMember = "Text"; + templateTypeCombox.ValueMember = "Value"; + + NamespaceObject namespaceObject = toolInitConfig.NamespaceObjects.Where(x => x.Assembly == toolInitConfig.CurrentAssembly).FirstOrDefault(); + + l = new List(); + foreach (NamespaceObject nso in toolInitConfig.NamespaceObjects.Where(x => x.Assembly == toolInitConfig.CurrentAssembly).ToArray()) + { + if (l.Select(x => x.Text).Contains(nso.TemplateType)) continue; + l.Add(CreateNewComboBoxItem(nso.TemplateType, nso.TemplateType)); + } + + dtbl = DataTableConvertor.ToDataTable(l); + templateTypeCombox.DataSource = dtbl; + + + templateTypeCombox.SelectedValue = namespaceObject.TemplateType; + + templatePathTxt.Text = toolInitConfig.TemplatePath; + + BindData(namespaceObject); + } + + public string GetTemplateType() + { + return (string)templateTypeCombox.SelectedValue; + } + + public string GetAssembly() + { + return (string)assemblyComboBox.SelectedValue; + } + + private void BindData(NamespaceObject namespaceObject) + { + if (namespaceObject == null) + { + templateTypeCombox.SelectedIndex = -1; + fileNamePrefixTxt.Text = fileNameSuffixTxt.Text = templateTypeTxt.Text = outFilePathTxt.Text = templateFileNameTxt.Text = assemblyTxt.Text = namespaceTxt.Text = null; + return; + } + templateTypeCombox.SelectedValue= namespaceObject.TemplateType; + templateTypeTxt.Text = namespaceObject.TemplateType; + outFilePathTxt.Text = namespaceObject.OutFilePath; + templateFileNameTxt.Text = namespaceObject.TemplateFileName; + fileNameSuffixTxt.Text = namespaceObject.FileNameSuffix; + fileNamePrefixTxt.Text = namespaceObject.FileNamePrefix; + assemblyTxt.Text = namespaceObject.Assembly; + namespaceTxt.Text = namespaceObject.Namespace; + } + + public class ComboBoxItem + { + public string Text { get; set; } + public string Value { get; set; } + } + + + private ComboBoxItem CreateNewComboBoxItem(string text, string value) + { + ComboBoxItem item = new ComboBoxItem(); + item.Text = text; + item.Value = value; + + return item; + } + + private void assemblyComboBox_SelectionChangeCommitted(object sender, EventArgs e) + { + if (assemblyComboBox.SelectedValue == null) return; + NamespaceObject namespaceObject = toolInitConfig.NamespaceObjects.Where(x => x.Assembly == (string)assemblyComboBox.SelectedValue).FirstOrDefault(); + + List l = new List(); + foreach (NamespaceObject nso in toolInitConfig.NamespaceObjects.Where(x => x.Assembly == (string)assemblyComboBox.SelectedValue).ToArray()) + { + if (l.Select(x => x.Text).Contains(nso.TemplateType)) continue; + l.Add(CreateNewComboBoxItem(nso.TemplateType, nso.TemplateType)); + } + + DataTable dtbl = DataTableConvertor.ToDataTable(l); + templateTypeCombox.DataSource = dtbl; + + BindData(namespaceObject); + + ((MainFunctionView)(this.ParentForm)).SetOperationUserControl(assemblyComboBox.SelectedValue); + } + + private void templateTypeCombox_SelectionChangeCommitted(object sender, EventArgs e) + { + if (templateTypeCombox.SelectedValue == null) return; + NamespaceObject namespaceObject = toolInitConfig.NamespaceObjects.Where(x => x.Assembly == (string)assemblyComboBox.SelectedValue && x.TemplateType == (string)templateTypeCombox.SelectedValue).FirstOrDefault(); + + BindData(namespaceObject); + } + + private void saveConfigBut_Click(object sender, EventArgs e) + { + toolInitConfig.TemplatePath = templatePathTxt.Text.Trim(); + toolInitConfig.CurrentAssembly = assemblyTxt.Text.Trim(); + toolInitConfig.Using = usingTxt.Text.Trim(); + + NamespaceObject namespaceObject = new NamespaceObject(); + namespaceObject.TemplateType = templateTypeTxt.Text.Trim(); + namespaceObject.TemplateFileName = templateFileNameTxt.Text.Trim(); + namespaceObject.FileNameSuffix = fileNameSuffixTxt.Text.Trim(); + namespaceObject.FileNamePrefix = fileNamePrefixTxt.Text.Trim(); + namespaceObject.OutFilePath = outFilePathTxt.Text.Trim(); + + namespaceObject.Assembly = assemblyTxt.Text.Trim(); + namespaceObject.Namespace = namespaceTxt.Text.Trim(); + + + NamespaceObject obj = toolInitConfig.NamespaceObjects.Where(x => x.Assembly == assemblyTxt.Text.Trim()).FirstOrDefault(); + + //如果不存在,插入 + if (obj == null) + { + List l = new List(); + l.Add(namespaceObject); + if (toolInitConfig.NamespaceObjects != null && toolInitConfig.NamespaceObjects.Length > 0) + l.AddRange(toolInitConfig.NamespaceObjects); + toolInitConfig.NamespaceObjects = l.ToArray(); + } + else + { + obj = toolInitConfig.NamespaceObjects.Where(x => x.Assembly == assemblyTxt.Text.Trim() && x.TemplateType == templateTypeTxt.Text.Trim()).FirstOrDefault(); + if (obj == null) + { + List ls = new List(); + ls.AddRange(toolInitConfig.NamespaceObjects); + ls.Add(namespaceObject); + toolInitConfig.NamespaceObjects = ls.OrderBy(x => x.Assembly).ThenBy(x => x.TemplateType).ToArray(); + } + else + { + foreach (NamespaceObject t in toolInitConfig.NamespaceObjects) + { + if (t.Assembly != assemblyTxt.Text.Trim()) continue; + if (t.TemplateType != templateTypeTxt.Text.Trim()) continue; + t.Assembly = namespaceObject.Assembly; + t.Namespace = namespaceObject.Namespace; + t.OutFilePath = namespaceObject.OutFilePath; + t.TemplateType = namespaceObject.TemplateType; + t.TemplateFileName = namespaceObject.TemplateFileName; + t.FileNameSuffix = namespaceObject.FileNameSuffix; + t.FileNamePrefix = namespaceObject.FileNamePrefix; + } + } + } + ToolInitConfig.Save(toolInitConfig); + InitUserControl(); + ((OperationUserControl)operationUserControl).InitUserControl(); + } + + private void deleteConfigBut_Click(object sender, EventArgs e) + { + NamespaceObject obj = toolInitConfig.NamespaceObjects.Where(x => x.Assembly == assemblyTxt.Text.Trim() && x.TemplateType == templateTypeTxt.Text.Trim()).FirstOrDefault(); + + //如果存在,删除,如果只有一个,不能删除 + if (obj != null && toolInitConfig.NamespaceObjects != null && toolInitConfig.NamespaceObjects.Length > 1) + { + toolInitConfig.NamespaceObjects = toolInitConfig.NamespaceObjects.Where(x => !(x.Assembly == obj.Assembly && x.TemplateType == obj.TemplateType)).ToArray(); + + var current = toolInitConfig.NamespaceObjects.Where(x => x.Assembly == assemblyComboBox.Text.Trim()).FirstOrDefault(); + + if (current == null) + { + toolInitConfig.CurrentAssembly = toolInitConfig.NamespaceObjects.FirstOrDefault().Assembly; + } + + ToolInitConfig.Save(toolInitConfig); + + InitUserControl(); + ((OperationUserControl)operationUserControl).InitUserControl(); + } + else + { + MessageBox.Show("最后一个选项不能删除", "提示"); + } + + } + + private void templatePathBut_Click(object sender, EventArgs e) + { + if (folderBrowserDialog1.ShowDialog() != DialogResult.OK) return; + + templatePathTxt.Text = folderBrowserDialog1.SelectedPath; + } + + private void outFilePathBut_Click(object sender, EventArgs e) + { + if (folderBrowserDialog1.ShowDialog() != DialogResult.OK) return; + + outFilePathTxt.Text = folderBrowserDialog1.SelectedPath; + } + } +} diff --git a/CodeGenerator/CloudBuilder.CodeGenerator/ConfigUserControl.resx b/CodeGenerator/CloudBuilder.CodeGenerator/ConfigUserControl.resx new file mode 100644 index 0000000..54d100c --- /dev/null +++ b/CodeGenerator/CloudBuilder.CodeGenerator/ConfigUserControl.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + \ No newline at end of file diff --git a/CodeGenerator/CloudBuilder.CodeGenerator/Data/ClassInfo.cs b/CodeGenerator/CloudBuilder.CodeGenerator/Data/ClassInfo.cs new file mode 100644 index 0000000..1abbe22 --- /dev/null +++ b/CodeGenerator/CloudBuilder.CodeGenerator/Data/ClassInfo.cs @@ -0,0 +1,86 @@ +using Microsoft.AspNetCore.Authorization; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.CodeGenerator.Data +{ + public class ClassInfo + { + public string ClassName { get; set; } + public string InterfaceName { get; set; } + public string ImplementTypeName { get; set; } + public string[] Usings { get; set; } + + public bool IsDownload { get; set; } = false; + + public ClassConstructorInfo[] ClassConstructorInfos; + + public ClassMethodInfo[] ClassMethodInfos; + + public ClassPropertyInfo[] ClassProperties; + + public ClassFieldInfo[] ClassFields; + } + + public class ClassFieldInfo + { + public bool IsValueType { get; set; } = false; + public string FieldName { get; set; } + public string FieldTypeName { get; set; } + + public string FieldValue { get; set; } + } + + public class ClassPropertyInfo + { + public bool IsValueType { get; set; } = false; + public string PropertyName { get; set; } + public string PropertyTypeName { get; set; } + } + + public class ClassConstructorInfo + { + public string ConstructorName { get; set; } + public MethodParameter[] Parameters { get; set; } + } + + public class ClassMethodInfo + { + public string MethodName { get; set; } + public string HttpName { get; set; } = "[HttpPost]"; + public string UnitOfWorkName { get; set; } = "[UnitOfWork]"; + public string AuthorizeName { get; set; } = "[AllowAnonymous]"; + public string PermissionOperate { get; set; } = "[PermissionOperate(name: {0}, operate: {1})]"; + public PermissionOperateAttribute PermissionOperateAttribute { get; set; } + public string MethodReturnName { get; set; } + public bool IsValueType { get; set; } = false; + public MethodParameter[] Parameters { get; set; } + } + + public class MethodParameter + { + public bool IsValueType { get; set; } = false; + public string ParameterName { get; set; } + public string ParameterTypeName { get; set; } + + public static bool CheckValueType(Type type) + { + var typeInfo = type.GetTypeInfo(); + if (typeInfo.IsGenericType && typeInfo.GetGenericTypeDefinition() == typeof(Nullable<>)) + { + // nullable type, check if the nested type is simple. + return CheckValueType(typeInfo.GetGenericArguments()[0]); + } + return typeInfo.IsPrimitive + || typeInfo.BaseType?.Name == "ValueType" + || typeInfo.IsEnum + || type.Equals(typeof(string)) + || type.Equals(typeof(DateTime)) + || type.Equals(typeof(decimal)); + } + } +} diff --git a/CodeGenerator/CloudBuilder.CodeGenerator/Data/ModelData.cs b/CodeGenerator/CloudBuilder.CodeGenerator/Data/ModelData.cs new file mode 100644 index 0000000..0b7b037 --- /dev/null +++ b/CodeGenerator/CloudBuilder.CodeGenerator/Data/ModelData.cs @@ -0,0 +1,28 @@ +using CloudBuilder.CodeGenerator.Config; +using CloudBuilder.CodeGenerator.Data; +using CloudBuilder.CodeGenerator.Entity; +using System; +using System.CodeDom.Compiler; +using System.Collections.Generic; +using System.Linq; +using System.Net.NetworkInformation; +using System.Text; +using System.Threading.Tasks; +using static System.Windows.Forms.LinkLabel; + +namespace CloudBuilder.CodeGenerator.Data +{ + public class ModelData + { + public SysTableSchemaViewEntity[] sysTableSchemas; + public NamespaceObject NamespaceObject; + public ClassInfo[] ClassInfos; + + public ClassInfo ClassInfo; + + public string KeyType; + + public int KeyCount; + } +} + diff --git a/CodeGenerator/CloudBuilder.CodeGenerator/Data/SysTable.cs b/CodeGenerator/CloudBuilder.CodeGenerator/Data/SysTable.cs new file mode 100644 index 0000000..1217404 --- /dev/null +++ b/CodeGenerator/CloudBuilder.CodeGenerator/Data/SysTable.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.CodeGenerator.Data +{ + public class SysTable + { + public string Selected { get; set; } = null!; + public string TableName { get; set; } = null!; + } +} diff --git a/CodeGenerator/CloudBuilder.CodeGenerator/Entity/CodeGeneratorRegistEntity.auto.cs b/CodeGenerator/CloudBuilder.CodeGenerator/Entity/CodeGeneratorRegistEntity.auto.cs new file mode 100644 index 0000000..fd5ae5b --- /dev/null +++ b/CodeGenerator/CloudBuilder.CodeGenerator/Entity/CodeGeneratorRegistEntity.auto.cs @@ -0,0 +1,39 @@ +using CloudBuilder.Core.DependencyInjection.EFCore; +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.CodeGenerator.Entity +{ + public partial class CodeGeneratorRegistEntity : IMasterRegistEntityType + { + /// + /// 注入模块内的所有实体类 + /// + /// + public void RegistEntity(ModelBuilder builder) + { + string _assemblyName = Assembly.GetExecutingAssembly().GetName().Name; + //注入所有Entity实体类 + AddEntityType(builder, _assemblyName); + //如果Entity实体类不是单一主键,要单独重写注入 + RegistKeys(builder); + } + + public void AddEntityType(ModelBuilder builder, string _assemblyName) + { + RegistEntityHelper.AddMasterEntityType(builder, _assemblyName); + } + + public void RegistKeys(ModelBuilder builder) + { + //***BEGIN*** + builder.Entity(eb => { eb.HasNoKey(); }); + //***END*** + } + } +} diff --git a/CodeGenerator/CloudBuilder.CodeGenerator/Entity/SysTableSchemaViewEntity.auto.cs b/CodeGenerator/CloudBuilder.CodeGenerator/Entity/SysTableSchemaViewEntity.auto.cs new file mode 100644 index 0000000..98f5f44 --- /dev/null +++ b/CodeGenerator/CloudBuilder.CodeGenerator/Entity/SysTableSchemaViewEntity.auto.cs @@ -0,0 +1,135 @@ +using CloudBuilder.Core.DatabaseAccessor.Entity; +using System.ComponentModel.DataAnnotations.Schema; +using System.Runtime.CompilerServices; + +namespace CloudBuilder.CodeGenerator.Entity +{ + [Table("sys_table_schema_view")] + public class SysTableSchemaViewEntity : ViewEntityBase + { + [Column("table_name")] + public string TableName { get; set; } + [Column("field_name")] + public string FieldName { get; set; } + [Column("type_name")] + public string TypeName { get; set; } + [Column("type_of_name")] + public string TypeOfName { get; set; } + [Column("max_length")] + public int MaxLength { get; set; } + [Column("scale")] + public int Scale { get; set; } + [Column("is_null_able")] + public string IsNullAble { get; set; } + [Column("field_default_value")] + public string FieldDefaultValue { get; set; } + [Column("xtype")] + public string Xtype { get; set; } + [Column("find_by")] + public int FindBy { get; set; } + [Column("operation")] + public int Operation { get; set; } + [Column("pk")] + public long Pk { get; set; } + [Column("pk_name")] + public string PkName { get; set; } + [Column("is_identity")] + public long IsIdentity { get; set; } + [Column("colid")] + public int Colid { get; set; } + + + public const string TABLE_NAME = "TableName"; + public const string FIELD_NAME = "FieldName"; + public const string TYPE_NAME = "TypeName"; + public const string TYPE_OF_NAME = "TypeOfName"; + public const string MAX_LENGTH = "MaxLength"; + public const string SCALE = "Scale"; + public const string IS_NULL_ABLE = "IsNullAble"; + public const string FIELD_DEFAULT_VALUE = "FieldDefaultValue"; + public const string XTYPE = "Xtype"; + public const string FIND_BY = "FindBy"; + public const string OPERATION = "operation"; + public const string PK = "Pk"; + public const string PK_NAME = "PkName"; + public const string IS_IDENTITY = "IsIdentity"; + public const string COLID = "Colid"; + + public const string DB_NAME_SYS_TABLE_SCHEMA = "sys_table_schema_view"; + + public const string DB_NAME_FIELDS = "table_name,field_name,type_name,type_of_name,max_length,scale,is_null_able,field_default_value,xtype,find_by,operation,pk,pk_name,is_identity,colid"; + + public const string DB_TABLE_NAME = "table_name"; + public const string DB_FIELD_NAME = "field_name"; + public const string DB_TYPE_NAME = "type_name"; + public const string DB_TYPE_OF_NAME = "type_of_name"; + public const string DB_MAX_LENGTH = "max_length"; + public const string DB_SCALE = "scale"; + public const string DB_IS_NULL_ABLE = "is_null_able"; + public const string DB_FIELD_DEFAULT_VALUE = "field_default_value"; + public const string DB_XTYPE = "xtype"; + public const string DB_FIND_BY = "find_by"; + public const string DB_OPERATION = "operation"; + public const string DB_PK = "pk"; + public const string DB_PK_NAME = "pk_name"; + public const string DB_IS_IDENTITY = "is_identity"; + public const string DB_COLID = "colid"; + + + public static SysTableSchemaViewEntity GetInstance() + { + return new SysTableSchemaViewEntity(); + } + + public SysTableSchemaViewEntity() + : base() + { + } + + public virtual void CopyFrom(SysTableSchemaViewEntity source) + { + CopyFrom(source, true); + } + + public virtual void CopyFrom(SysTableSchemaViewEntity source, bool includeSystemFields) + { + if (source == null) + { + throw new NullReferenceException("Source entity is null."); + } + + this.TableName = source.TableName; + this.FieldName = source.FieldName; + this.TypeName = source.TypeName; + this.TypeOfName = source.TypeOfName; + this.MaxLength = source.MaxLength; + this.Scale = source.Scale; + this.IsNullAble = source.IsNullAble; + this.FieldDefaultValue = source.FieldDefaultValue; + this.Xtype = source.Xtype; + this.FindBy = source.FindBy; + this.Operation = source.Operation; + this.Pk = source.Pk; + this.PkName = source.PkName; + this.IsIdentity = source.IsIdentity; + this.Colid = source.Colid; + + if (includeSystemFields) + { + } + } + + public string GetSelectFrom() + { + return $" select {DB_NAME_FIELDS} from {DB_NAME_SYS_TABLE_SCHEMA} "; + } + + public SysTableSchemaViewEntity Clone() + { + SysTableSchemaViewEntity result = new SysTableSchemaViewEntity(); + result.CopyFrom(this); + + return result; + } + } +} diff --git a/CodeGenerator/CloudBuilder.CodeGenerator/MainFunctionView.Designer.cs b/CodeGenerator/CloudBuilder.CodeGenerator/MainFunctionView.Designer.cs new file mode 100644 index 0000000..0ceb66d --- /dev/null +++ b/CodeGenerator/CloudBuilder.CodeGenerator/MainFunctionView.Designer.cs @@ -0,0 +1,90 @@ +namespace CloudBuilder.CodeGenerator +{ + partial class MainFunctionView + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + kryptonDockingManager = new Krypton.Docking.KryptonDockingManager(); + kryptonDockableWorkspace = new Krypton.Docking.KryptonDockableWorkspace(); + mainPanel = new Krypton.Toolkit.KryptonPanel(); + ((System.ComponentModel.ISupportInitialize)kryptonDockableWorkspace).BeginInit(); + ((System.ComponentModel.ISupportInitialize)mainPanel).BeginInit(); + mainPanel.SuspendLayout(); + SuspendLayout(); + // + // kryptonDockableWorkspace + // + kryptonDockableWorkspace.ActivePage = null; + kryptonDockableWorkspace.AutoHiddenHost = false; + kryptonDockableWorkspace.CompactFlags = Krypton.Workspace.CompactFlags.RemoveEmptyCells | Krypton.Workspace.CompactFlags.RemoveEmptySequences | Krypton.Workspace.CompactFlags.PromoteLeafs; + kryptonDockableWorkspace.ContainerBackStyle = Krypton.Toolkit.PaletteBackStyle.PanelClient; + kryptonDockableWorkspace.Dock = DockStyle.Fill; + kryptonDockableWorkspace.Location = new Point(0, 0); + kryptonDockableWorkspace.Name = "kryptonDockableWorkspace"; + // + // + // + kryptonDockableWorkspace.Root.UniqueName = "9b8557cebb92477fa6d1f0b015e0ff50"; + kryptonDockableWorkspace.Root.WorkspaceControl = kryptonDockableWorkspace; + kryptonDockableWorkspace.SeparatorStyle = Krypton.Toolkit.SeparatorStyle.LowProfile; + kryptonDockableWorkspace.ShowMaximizeButton = false; + kryptonDockableWorkspace.Size = new Size(1008, 761); + kryptonDockableWorkspace.SplitterWidth = 5; + kryptonDockableWorkspace.TabIndex = 0; + kryptonDockableWorkspace.TabStop = true; + // + // mainPanel + // + mainPanel.Controls.Add(kryptonDockableWorkspace); + mainPanel.Dock = DockStyle.Fill; + mainPanel.Location = new Point(0, 0); + mainPanel.Name = "mainPanel"; + mainPanel.Size = new Size(1008, 761); + mainPanel.TabIndex = 1; + // + // MainFunctionView + // + AutoScaleDimensions = new SizeF(7F, 17F); + AutoScaleMode = AutoScaleMode.Font; + ClientSize = new Size(1008, 761); + Controls.Add(mainPanel); + Name = "MainFunctionView"; + Text = "代码生成器"; + Load += MainFunctionView_Load; + ((System.ComponentModel.ISupportInitialize)kryptonDockableWorkspace).EndInit(); + ((System.ComponentModel.ISupportInitialize)mainPanel).EndInit(); + mainPanel.ResumeLayout(false); + ResumeLayout(false); + } + + #endregion + + private Krypton.Docking.KryptonDockingManager kryptonDockingManager; + private Krypton.Docking.KryptonDockableWorkspace kryptonDockableWorkspace; + private Krypton.Toolkit.KryptonPanel mainPanel; + } +} \ No newline at end of file diff --git a/CodeGenerator/CloudBuilder.CodeGenerator/MainFunctionView.cs b/CodeGenerator/CloudBuilder.CodeGenerator/MainFunctionView.cs new file mode 100644 index 0000000..c0f4546 --- /dev/null +++ b/CodeGenerator/CloudBuilder.CodeGenerator/MainFunctionView.cs @@ -0,0 +1,103 @@ +using CloudBuilder.CodeGenerator.Entity; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using CloudBuilder.Core.DependencyInjection.Form; +using Krypton.Docking; +using Krypton.Navigator; +using Krypton.Toolkit; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace CloudBuilder.CodeGenerator +{ + public partial class MainFunctionView : KryptonForm, IForm + { + public TableControl tableControl; + public ConfigUserControl configUserControl; + private readonly TemplateUserControl templateUserControl; + private readonly OutputUserControl outputUserControl; + private readonly OperationUserControl operationUserControl; + + public void SetConfigUserControl(object? value) + { + configUserControl.assemblyComboBox.SelectedValue = value; + } + + public void SetOperationUserControl(object? value) + { + operationUserControl.assemblyComboBox.SelectedValue = value; + } + + public MainFunctionView( + [FromKeyedServices("TableControl")] TableControl tableControl, + [FromKeyedServices("ConfigUserControl")] ConfigUserControl configUserControl, + [FromKeyedServices("TemplateUserControl")] TemplateUserControl templateUserControl, + [FromKeyedServices("OutputUserControl")] OutputUserControl outputUserControl, + [FromKeyedServices("OperationUserControl")] OperationUserControl operationUserControl) + { + InitializeComponent(); + this.tableControl = tableControl; + this.configUserControl = configUserControl; + this.templateUserControl = templateUserControl; + this.outputUserControl = outputUserControl; + this.operationUserControl = operationUserControl; + } + + + + private void MainFunctionView_Load(object sender, EventArgs e) + { + KryptonDockingWorkspace w = kryptonDockingManager.ManageWorkspace(kryptonDockableWorkspace); + kryptonDockingManager.ManageControl(mainPanel, w); + kryptonDockingManager.ManageFloating(this); + + kryptonDockingManager.AddDockspace("Control", DockingEdge.Right, new KryptonPage[] { NewOperationUserControl() }); + kryptonDockingManager.AddToWorkspace("Workspace", new KryptonPage[] { NewTableControl(), NewConfigUserControl(), NewTemplateUserControl(), NewOutputUserControl() }); + } + + private KryptonPage NewTableControl() + { + return NewOutputControl("数据操作", 1, tableControl); + } + + private KryptonPage NewConfigUserControl() + { + return NewOutputControl("模板设置", 2, configUserControl); + } + + private KryptonPage NewTemplateUserControl() + { + return NewOutputControl("模板內容", 3, templateUserControl); + } + + private KryptonPage NewOutputUserControl() + { + return NewOutputControl("模板生成內容", 4, outputUserControl); + } + + private KryptonPage NewOperationUserControl() + { + return NewOutputControl("模板输出", 4, operationUserControl); + } + + private KryptonPage NewOutputControl(string text, int imageIndex, UserControl userControl) + { + KryptonPage p = new KryptonPage(); + p.TextTitle = p.Text = text; + p.MinimumSize = new Size(200, 250); + + userControl.Dock = DockStyle.Fill; + p.Controls.Add(userControl); + + return p; + } + + } +} diff --git a/CodeGenerator/CloudBuilder.CodeGenerator/MainFunctionView.resx b/CodeGenerator/CloudBuilder.CodeGenerator/MainFunctionView.resx new file mode 100644 index 0000000..1f07adb --- /dev/null +++ b/CodeGenerator/CloudBuilder.CodeGenerator/MainFunctionView.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + \ No newline at end of file diff --git a/CodeGenerator/CloudBuilder.CodeGenerator/OperationUserControl.Designer.cs b/CodeGenerator/CloudBuilder.CodeGenerator/OperationUserControl.Designer.cs new file mode 100644 index 0000000..024698f --- /dev/null +++ b/CodeGenerator/CloudBuilder.CodeGenerator/OperationUserControl.Designer.cs @@ -0,0 +1,178 @@ +namespace CloudBuilder.CodeGenerator +{ + partial class OperationUserControl + { + /// + /// 設計工具所需的變數。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清除任何使用中的資源。 + /// + /// 如果應該處置受控資源則為 true,否則為 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 元件設計工具產生的程式碼 + + /// + /// 此為設計工具支援所需的方法 - 請勿使用程式碼編輯器修改 + /// 這個方法的內容。 + /// + private void InitializeComponent() + { + assemblyComboBox = new Krypton.Toolkit.KryptonComboBox(); + kryptonHeader1 = new Krypton.Toolkit.KryptonHeader(); + kryptonCheckedListBox1 = new Krypton.Toolkit.KryptonCheckedListBox(); + kryptonHeader2 = new Krypton.Toolkit.KryptonHeader(); + kryptonHeader3 = new Krypton.Toolkit.KryptonHeader(); + templateBut = new Krypton.Toolkit.KryptonButton(); + tableLayoutPanel1 = new TableLayoutPanel(); + outputFileBut = new Krypton.Toolkit.KryptonCheckButton(); + ((System.ComponentModel.ISupportInitialize)assemblyComboBox).BeginInit(); + tableLayoutPanel1.SuspendLayout(); + SuspendLayout(); + // + // assemblyComboBox + // + assemblyComboBox.Dock = DockStyle.Fill; + assemblyComboBox.DropDownStyle = ComboBoxStyle.DropDownList; + assemblyComboBox.DropDownWidth = 362; + assemblyComboBox.IntegralHeight = false; + assemblyComboBox.Location = new Point(4, 43); + assemblyComboBox.Margin = new Padding(4); + assemblyComboBox.Name = "assemblyComboBox"; + assemblyComboBox.Size = new Size(275, 21); + assemblyComboBox.TabIndex = 7; + assemblyComboBox.SelectionChangeCommitted += assemblyComboBox_SelectionChangeCommitted; + assemblyComboBox.SelectedValueChanged += assemblyComboBox_SelectedValueChanged; + // + // kryptonHeader1 + // + kryptonHeader1.Dock = DockStyle.Fill; + kryptonHeader1.Location = new Point(4, 4); + kryptonHeader1.Margin = new Padding(4); + kryptonHeader1.Name = "kryptonHeader1"; + kryptonHeader1.Size = new Size(275, 31); + kryptonHeader1.TabIndex = 0; + kryptonHeader1.Values.Description = ""; + kryptonHeader1.Values.Heading = "当前程序集"; + kryptonHeader1.Values.Image = null; + // + // kryptonCheckedListBox1 + // + kryptonCheckedListBox1.Dock = DockStyle.Fill; + kryptonCheckedListBox1.Location = new Point(4, 111); + kryptonCheckedListBox1.Margin = new Padding(4); + kryptonCheckedListBox1.Name = "kryptonCheckedListBox1"; + kryptonCheckedListBox1.Size = new Size(275, 227); + kryptonCheckedListBox1.TabIndex = 8; + // + // kryptonHeader2 + // + kryptonHeader2.Dock = DockStyle.Fill; + kryptonHeader2.Location = new Point(4, 72); + kryptonHeader2.Margin = new Padding(4); + kryptonHeader2.Name = "kryptonHeader2"; + kryptonHeader2.Size = new Size(275, 31); + kryptonHeader2.TabIndex = 9; + kryptonHeader2.Values.Description = ""; + kryptonHeader2.Values.Heading = "输出项显示"; + kryptonHeader2.Values.Image = null; + // + // kryptonHeader3 + // + kryptonHeader3.Dock = DockStyle.Fill; + kryptonHeader3.Location = new Point(4, 346); + kryptonHeader3.Margin = new Padding(4); + kryptonHeader3.Name = "kryptonHeader3"; + kryptonHeader3.Size = new Size(275, 4); + kryptonHeader3.TabIndex = 10; + kryptonHeader3.Values.Description = ""; + kryptonHeader3.Values.Heading = ""; + kryptonHeader3.Values.Image = null; + // + // templateBut + // + templateBut.Location = new Point(4, 391); + templateBut.Margin = new Padding(4); + templateBut.Name = "templateBut"; + templateBut.Size = new Size(105, 25); + templateBut.TabIndex = 12; + templateBut.Values.Text = "模板生成"; + templateBut.Click += templateBut_Click; + // + // tableLayoutPanel1 + // + tableLayoutPanel1.AutoSize = true; + tableLayoutPanel1.AutoSizeMode = AutoSizeMode.GrowAndShrink; + tableLayoutPanel1.ColumnCount = 1; + tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F)); + tableLayoutPanel1.Controls.Add(assemblyComboBox, 0, 1); + tableLayoutPanel1.Controls.Add(kryptonHeader1, 0, 0); + tableLayoutPanel1.Controls.Add(kryptonCheckedListBox1, 0, 3); + tableLayoutPanel1.Controls.Add(kryptonHeader2, 0, 2); + tableLayoutPanel1.Controls.Add(kryptonHeader3, 0, 4); + tableLayoutPanel1.Controls.Add(outputFileBut, 0, 7); + tableLayoutPanel1.Controls.Add(templateBut, 0, 8); + tableLayoutPanel1.Dock = DockStyle.Fill; + tableLayoutPanel1.Location = new Point(0, 0); + tableLayoutPanel1.Margin = new Padding(4); + tableLayoutPanel1.Name = "tableLayoutPanel1"; + tableLayoutPanel1.RowCount = 9; + tableLayoutPanel1.RowStyles.Add(new RowStyle()); + tableLayoutPanel1.RowStyles.Add(new RowStyle()); + tableLayoutPanel1.RowStyles.Add(new RowStyle()); + tableLayoutPanel1.RowStyles.Add(new RowStyle()); + tableLayoutPanel1.RowStyles.Add(new RowStyle()); + tableLayoutPanel1.RowStyles.Add(new RowStyle()); + tableLayoutPanel1.RowStyles.Add(new RowStyle()); + tableLayoutPanel1.RowStyles.Add(new RowStyle()); + tableLayoutPanel1.RowStyles.Add(new RowStyle()); + tableLayoutPanel1.Size = new Size(283, 649); + tableLayoutPanel1.TabIndex = 1; + // + // outputFileBut + // + outputFileBut.Location = new Point(4, 358); + outputFileBut.Margin = new Padding(4); + outputFileBut.Name = "outputFileBut"; + outputFileBut.Size = new Size(105, 25); + outputFileBut.TabIndex = 13; + outputFileBut.Values.Text = "输出文件"; + outputFileBut.Click += outputFileBut_Click; + // + // OperationUserControl + // + AutoScaleDimensions = new SizeF(7F, 17F); + AutoScaleMode = AutoScaleMode.Font; + Controls.Add(tableLayoutPanel1); + MinimumSize = new Size(240, 0); + Name = "OperationUserControl"; + Size = new Size(283, 649); + ((System.ComponentModel.ISupportInitialize)assemblyComboBox).EndInit(); + tableLayoutPanel1.ResumeLayout(false); + tableLayoutPanel1.PerformLayout(); + ResumeLayout(false); + PerformLayout(); + } + + #endregion + + public Krypton.Toolkit.KryptonComboBox assemblyComboBox; + private Krypton.Toolkit.KryptonHeader kryptonHeader1; + private Krypton.Toolkit.KryptonCheckedListBox kryptonCheckedListBox1; + private Krypton.Toolkit.KryptonHeader kryptonHeader2; + private Krypton.Toolkit.KryptonHeader kryptonHeader3; + private Krypton.Toolkit.KryptonButton templateBut; + private TableLayoutPanel tableLayoutPanel1; + private Krypton.Toolkit.KryptonCheckButton outputFileBut; + } +} diff --git a/CodeGenerator/CloudBuilder.CodeGenerator/OperationUserControl.cs b/CodeGenerator/CloudBuilder.CodeGenerator/OperationUserControl.cs new file mode 100644 index 0000000..6bcd9ea --- /dev/null +++ b/CodeGenerator/CloudBuilder.CodeGenerator/OperationUserControl.cs @@ -0,0 +1,286 @@ +using CloudBuilder.CodeGenerator.Config; +using CloudBuilder.CodeGenerator.Data; +using CloudBuilder.CodeGenerator.Utility; +using CloudBuilder.Core.Application.Builders; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using CloudBuilder.Core.DependencyInjection.Form; +using CloudBuilder.Core.Extensions; +using CloudBuilder.Core.Service; +using CloudBuilder.Core.Utility; +using Krypton.Toolkit; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.VisualStudio.OLE.Interop; +using RazorEngineCore; +using System.Data; +using System.Linq; +using System.Reflection; +using System.Windows.Forms.Design; + +namespace CloudBuilder.CodeGenerator +{ + public partial class OperationUserControl : UserControl, IUserControl + { + private readonly IApplicationService app; + private readonly TableControl tableControl; + private ConfigUserControl configUserControl; + private readonly TemplateUserControl templateUserControl; + private readonly OutputUserControl outputUserControl; + private ToolInitConfig toolInitConfig; + public OperationUserControl(IApplicationService app, + [FromKeyedServices("TableControl")] TableControl tableControl, + [FromKeyedServices("TemplateUserControl")] TemplateUserControl templateUserControl, + [FromKeyedServices("OutputUserControl")] OutputUserControl outputUserControl) + { + InitializeComponent(); + this.app = app; + this.tableControl = tableControl; + + this.templateUserControl = templateUserControl; + this.outputUserControl = outputUserControl; + InitUserControl(); + } + + public void InitUserControl() + { + assemblyComboBox.DisplayMember = "Text"; + assemblyComboBox.ValueMember = "Value"; + + toolInitConfig = ToolInitConfig.GetInstance(); + + List l = new List(); + List types = new List(); + foreach (NamespaceObject nso in toolInitConfig.NamespaceObjects) + { + if (l.Select(x => x.Text).Contains(nso.Assembly)) continue; + l.Add(CreateNewComboBoxItem(nso.Assembly, nso.Assembly)); + } + + DataTable dtbl = DataTableConvertor.ToDataTable(l); + assemblyComboBox.DataSource = dtbl; + assemblyComboBox.SelectedValue = toolInitConfig.CurrentAssembly; + + InitkryptonCheckedListBox1(toolInitConfig.CurrentAssembly); + } + + private void InitkryptonCheckedListBox1(string currentAssembly) + { + if (string.IsNullOrEmpty(currentAssembly)) return; + int i = 0; + kryptonCheckedListBox1.Items.Clear(); + foreach (NamespaceObject nso in toolInitConfig.NamespaceObjects.Where(x => x.Assembly == currentAssembly).ToList()) + { + if (nso.TemplateType.Contains("Entity") && nso.TemplateType != "Entity") continue; + + if (nso.TemplateType.Contains("TypeScript")) continue; + + kryptonCheckedListBox1.Items.Add(CreateNewItem(nso.TemplateType)); + + if (!nso.TemplateType.Contains("Entity")) + { + i++; + continue; + } + + kryptonCheckedListBox1.SetItemCheckState(i++, CheckState.Checked); + } + } + + private void outputFileBut_Click(object sender, EventArgs e) + { + ModelData model = GetModelData(); + if (model.sysTableSchemas == null || model.sysTableSchemas.Length == 0) + { + MessageBox.Show("请选择要生成的数据表", "提示"); + return; + } + + for (var i = 0; i < kryptonCheckedListBox1.Items.Count; i++) + { + if (kryptonCheckedListBox1.GetItemCheckState(i) == CheckState.Checked) + { + KryptonListItem a = (KryptonListItem)kryptonCheckedListBox1.Items[i]; + + WriteAllText(model, a.ShortText); + } + } + + MessageBox.Show("生成成功", "提示"); + } + + private void WriteAllText(ModelData model, string templateType) + { + NamespaceObject namespaceObject = toolInitConfig.NamespaceObjects.Where(x => x.Assembly == assemblyComboBox.Text.Trim() && x.TemplateType == templateType).FirstOrDefault(); + + if (namespaceObject == null) return; + + string fileName = Path.Combine(toolInitConfig.TemplatePath, namespaceObject.TemplateFileName); + if (!File.Exists(fileName)) return; + + if (!Path.Exists(namespaceObject.OutFilePath)) return; + + var tp = File.ReadAllText(fileName); + + string outputFileName = Path.Combine(namespaceObject.OutFilePath, namespaceObject.FileNamePrefix + model.sysTableSchemas[0].TableName.StringToProerty() + namespaceObject.FileNameSuffix); + + if (templateType == "RegistEntity") + { + outputFileName = Path.Combine(namespaceObject.OutFilePath, namespaceObject.Assembly.Replace(".", "") + namespaceObject.FileNameSuffix); + + //文件不存在,先初始化文件 + if (!File.Exists(outputFileName)) File.WriteAllText(outputFileName, RazorEngineHelper.CompiledTemplate(tp, model)); + + string allTxt = File.ReadAllText(outputFileName); + + tp = File.ReadAllText(Path.Combine(toolInitConfig.TemplatePath, namespaceObject.TemplateFileName.Replace(".cshtml", ".Key.cshtml"))); + var temp = RazorEngineHelper.CompiledTemplate(tp, model); + + if (allTxt.Contains("<" + model.sysTableSchemas[0].TableName.StringToProerty() + "Entity>()")) return; + + int end = allTxt.IndexOf("//***END***", StringComparison.OrdinalIgnoreCase); + + allTxt = allTxt.Substring(0, end) + temp + allTxt.Substring(end, allTxt.Length - end); + + File.WriteAllText(outputFileName, allTxt); + return; + } + else if (templateType == "Permission") + { + outputFileName = Path.Combine(namespaceObject.OutFilePath, namespaceObject.Assembly.Split('.')[namespaceObject.Assembly.Split('.').Length - 1] + namespaceObject.FileNameSuffix); + + //文件存在不覆盖,插入 + if (File.Exists(outputFileName)) + { + string allTxt = File.ReadAllText(outputFileName); + + tp = File.ReadAllText(Path.Combine(toolInitConfig.TemplatePath, namespaceObject.TemplateFileName)); + var temp = RazorEngineHelper.CompiledTemplate(tp, model); + + if (allTxt.Contains(model.sysTableSchemas[0].TableName.StringToProerty())) return; + + int end = allTxt.IndexOf("//***END***", StringComparison.OrdinalIgnoreCase); + + allTxt = allTxt.Substring(0, end) + temp + allTxt.Substring(end, allTxt.Length - end); + + File.WriteAllText(outputFileName, allTxt); + return; + } + else + { + tp = File.ReadAllText(Path.Combine(toolInitConfig.TemplatePath, namespaceObject.TemplateFileName.Replace(".cshtml", ".auto.cshtml"))); + var temp = RazorEngineHelper.CompiledTemplate(tp, model); + File.WriteAllText(outputFileName, temp); + } + } + //Entity可以直接輸出,其他要文件不存在才生成 + if (templateType == "Entity" || templateType == "IEntityKey" || !File.Exists(outputFileName)) + File.WriteAllText(outputFileName, RazorEngineHelper.CompiledTemplate(tp, model)); + + if ((model.KeyCount >= 0) && templateType == "Entity") + { + if (model.KeyCount > 1) + WriteAllText(model, "IEntityKey"); + WriteAllText(model, "RegistEntity"); + } + else if (templateType == "Service") + { + WriteAllText(model, "Permission"); + } + } + + private void templateBut_Click(object sender, EventArgs e) + { + try + { + ModelData modelData = GetModelData(); + + ((OutputUserControl)outputUserControl).contextTxt.Text = RazorEngineHelper.CompiledTemplate(((TemplateUserControl)templateUserControl).contextTxt.Text, modelData); + + MessageBox.Show("生成成功", "提示"); + + + } + catch (Exception ex) + { + MessageBox.Show(ex.Message, "出错"); + } + } + + private ModelData GetModelData() + { + configUserControl = app.ServiceProvider.GetKeyedService("ConfigUserControl"); + ModelData modelData = new ModelData(); + modelData.sysTableSchemas = ((TableControl)tableControl).GetDataSource(); + modelData.NamespaceObject = toolInitConfig.NamespaceObjects.Where(x => x.TemplateType == configUserControl.GetTemplateType() && x.Assembly == configUserControl.GetAssembly()).FirstOrDefault(); + if (modelData.sysTableSchemas != null && modelData.sysTableSchemas.Length > 0) + { + modelData.KeyCount = modelData.sysTableSchemas.Where(x => x.Pk > 0).Count(); + if (modelData.KeyCount == 1) + { + modelData.KeyType = modelData.sysTableSchemas.Where(x => x.Pk > 0).FirstOrDefault().TypeOfName; + } + else if (modelData.KeyCount > 1) + { + modelData.KeyType = $"{modelData.sysTableSchemas[0].TableName.StringToProerty()}EntityKey"; + } + else + { + modelData.KeyType = "string"; + } + } + List assemblies = new List(); + if (toolInitConfig.AssemblyReferences != null) + { + foreach (var reference in toolInitConfig.AssemblyReferences) + { + if (string.IsNullOrEmpty(reference.AssemblyFileName)) continue; + + if (!File.Exists(reference.AssemblyFileName)) continue; + + assemblies.Add(Assembly.LoadFrom(reference.AssemblyFileName)); + } + } + if (configUserControl.GetTemplateType() == "Controller" || configUserControl.GetTemplateType() == "TypeScriptService") + modelData.ClassInfos = RazorEngineHelper.PackIServiceClassInfo(assemblies.Where(x => Path.GetFileNameWithoutExtension(x.ManifestModule.Name) == modelData.NamespaceObject.Assembly).FirstOrDefault()); + else + if (configUserControl.GetTemplateType() == "TypeScript") + modelData.ClassInfos = RazorEngineHelper.PackTypeScriptClassInfo(assemblies.Where(x => Path.GetFileNameWithoutExtension(x.ManifestModule.Name) == modelData.NamespaceObject.Assembly).FirstOrDefault()); + + return modelData; + } + + + public class ComboBoxItem + { + public string Text { get; set; } + public string Value { get; set; } + } + + + private ComboBoxItem CreateNewComboBoxItem(string text, string value) + { + ComboBoxItem item = new ComboBoxItem(); + item.Text = text; + item.Value = value; + + return item; + } + + private object CreateNewItem(string text) + { + KryptonListItem item = new KryptonListItem(); + item.ShortText = text; + + return item; + } + + private void assemblyComboBox_SelectionChangeCommitted(object sender, EventArgs e) + { + ((MainFunctionView)(this.ParentForm)).SetConfigUserControl(assemblyComboBox.SelectedValue); + } + + private void assemblyComboBox_SelectedValueChanged(object sender, EventArgs e) + { + InitkryptonCheckedListBox1((string)assemblyComboBox.SelectedValue); + } + } +} diff --git a/CodeGenerator/CloudBuilder.CodeGenerator/OperationUserControl.resx b/CodeGenerator/CloudBuilder.CodeGenerator/OperationUserControl.resx new file mode 100644 index 0000000..af32865 --- /dev/null +++ b/CodeGenerator/CloudBuilder.CodeGenerator/OperationUserControl.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/CodeGenerator/CloudBuilder.CodeGenerator/OutputUserControl.Designer.cs b/CodeGenerator/CloudBuilder.CodeGenerator/OutputUserControl.Designer.cs new file mode 100644 index 0000000..d7f6983 --- /dev/null +++ b/CodeGenerator/CloudBuilder.CodeGenerator/OutputUserControl.Designer.cs @@ -0,0 +1,93 @@ +namespace CloudBuilder.CodeGenerator +{ + partial class OutputUserControl + { + /// + /// 設計工具所需的變數。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清除任何使用中的資源。 + /// + /// 如果應該處置受控資源則為 true,否則為 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 元件設計工具產生的程式碼 + + /// + /// 此為設計工具支援所需的方法 - 請勿使用程式碼編輯器修改 + /// 這個方法的內容。 + /// + private void InitializeComponent() + { + tableLayoutPanel1 = new TableLayoutPanel(); + kryptonHeader1 = new Krypton.Toolkit.KryptonHeader(); + contextTxt = new Krypton.Toolkit.KryptonRichTextBox(); + tableLayoutPanel1.SuspendLayout(); + SuspendLayout(); + // + // tableLayoutPanel1 + // + tableLayoutPanel1.ColumnCount = 1; + tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F)); + tableLayoutPanel1.Controls.Add(kryptonHeader1, 0, 0); + tableLayoutPanel1.Controls.Add(contextTxt, 0, 2); + tableLayoutPanel1.Dock = DockStyle.Fill; + tableLayoutPanel1.Location = new Point(0, 0); + tableLayoutPanel1.Name = "tableLayoutPanel1"; + tableLayoutPanel1.RowCount = 3; + tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Absolute, 35F)); + tableLayoutPanel1.RowStyles.Add(new RowStyle()); + tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent, 100F)); + tableLayoutPanel1.Size = new Size(779, 531); + tableLayoutPanel1.TabIndex = 1; + // + // kryptonHeader1 + // + tableLayoutPanel1.SetColumnSpan(kryptonHeader1, 4); + kryptonHeader1.Dock = DockStyle.Fill; + kryptonHeader1.Location = new Point(4, 4); + kryptonHeader1.Margin = new Padding(4); + kryptonHeader1.Name = "kryptonHeader1"; + kryptonHeader1.Size = new Size(771, 27); + kryptonHeader1.TabIndex = 13; + kryptonHeader1.Values.Description = ""; + kryptonHeader1.Values.Heading = "模板生成內容"; + kryptonHeader1.Values.Image = null; + // + // contextTxt + // + contextTxt.Dock = DockStyle.Fill; + contextTxt.Location = new Point(3, 38); + contextTxt.Name = "contextTxt"; + contextTxt.Size = new Size(773, 490); + contextTxt.TabIndex = 15; + contextTxt.Text = ""; + // + // OutputUserControl + // + AutoScaleDimensions = new SizeF(7F, 17F); + AutoScaleMode = AutoScaleMode.Font; + Controls.Add(tableLayoutPanel1); + Name = "OutputUserControl"; + Size = new Size(779, 531); + tableLayoutPanel1.ResumeLayout(false); + tableLayoutPanel1.PerformLayout(); + ResumeLayout(false); + } + + #endregion + + private TableLayoutPanel tableLayoutPanel1; + private Krypton.Toolkit.KryptonHeader kryptonHeader1; + public Krypton.Toolkit.KryptonRichTextBox contextTxt; + } +} diff --git a/CodeGenerator/CloudBuilder.CodeGenerator/OutputUserControl.cs b/CodeGenerator/CloudBuilder.CodeGenerator/OutputUserControl.cs new file mode 100644 index 0000000..84d5161 --- /dev/null +++ b/CodeGenerator/CloudBuilder.CodeGenerator/OutputUserControl.cs @@ -0,0 +1,21 @@ +using CloudBuilder.Core.DependencyInjection.Form; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace CloudBuilder.CodeGenerator +{ + public partial class OutputUserControl : UserControl, IUserControl + { + public OutputUserControl() + { + InitializeComponent(); + } + } +} diff --git a/CodeGenerator/CloudBuilder.CodeGenerator/OutputUserControl.resx b/CodeGenerator/CloudBuilder.CodeGenerator/OutputUserControl.resx new file mode 100644 index 0000000..af32865 --- /dev/null +++ b/CodeGenerator/CloudBuilder.CodeGenerator/OutputUserControl.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/CodeGenerator/CloudBuilder.CodeGenerator/Program.cs b/CodeGenerator/CloudBuilder.CodeGenerator/Program.cs new file mode 100644 index 0000000..2039e70 --- /dev/null +++ b/CodeGenerator/CloudBuilder.CodeGenerator/Program.cs @@ -0,0 +1,29 @@ +using CloudBuilder.CodeGenerator; +using Microsoft.Extensions.DependencyInjection; + +namespace WinFormsApp +{ + internal static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + Application.SetHighDpiMode(HighDpiMode.SystemAware); + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + + var services = new ServiceCollection(); + + services.Initialize(); + + var serviceProvider = services.BuildServiceProvider(); + + MainFunctionView mainFunctionView = serviceProvider.GetRequiredKeyedService(typeof(MainFunctionView).Name); + + Application.Run(mainFunctionView); + } + } +} \ No newline at end of file diff --git a/CodeGenerator/CloudBuilder.CodeGenerator/Properties/Resources.Designer.cs b/CodeGenerator/CloudBuilder.CodeGenerator/Properties/Resources.Designer.cs new file mode 100644 index 0000000..79bd763 --- /dev/null +++ b/CodeGenerator/CloudBuilder.CodeGenerator/Properties/Resources.Designer.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// 這段程式碼是由工具產生的。 +// 執行階段版本:4.0.30319.42000 +// +// 對這個檔案所做的變更可能會造成錯誤的行為,而且如果重新產生程式碼, +// 變更將會遺失。 +// +//------------------------------------------------------------------------------ + +namespace CloudBuilder.CodeGenerator.Properties { + using System; + + + /// + /// 用於查詢當地語系化字串等的強類型資源類別。 + /// + // 這個類別是自動產生的,是利用 StronglyTypedResourceBuilder + // 類別透過 ResGen 或 Visual Studio 這類工具。 + // 若要加入或移除成員,請編輯您的 .ResX 檔,然後重新執行 ResGen + // (利用 /str 選項),或重建您的 VS 專案。 + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// 傳回這個類別使用的快取的 ResourceManager 執行個體。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("CloudBuilder.CodeGenerator.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// 覆寫目前執行緒的 CurrentUICulture 屬性,對象是所有 + /// 使用這個強類型資源類別的資源查閱。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/CodeGenerator/CloudBuilder.CodeGenerator/Properties/Resources.resx b/CodeGenerator/CloudBuilder.CodeGenerator/Properties/Resources.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/CodeGenerator/CloudBuilder.CodeGenerator/Properties/Resources.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/CodeGenerator/CloudBuilder.CodeGenerator/TableControl.Designer.cs b/CodeGenerator/CloudBuilder.CodeGenerator/TableControl.Designer.cs new file mode 100644 index 0000000..949e918 --- /dev/null +++ b/CodeGenerator/CloudBuilder.CodeGenerator/TableControl.Designer.cs @@ -0,0 +1,418 @@ +namespace CloudBuilder.CodeGenerator +{ + partial class TableControl + { + /// + /// 設計工具所需的變數。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清除任何使用中的資源。 + /// + /// 如果應該處置受控資源則為 true,否則為 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 元件設計工具產生的程式碼 + + /// + /// 此為設計工具支援所需的方法 - 請勿使用程式碼編輯器修改 + /// 這個方法的內容。 + /// + private void InitializeComponent() + { + DataGridViewCellStyle dataGridViewCellStyle8 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle9 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle10 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle11 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle12 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle13 = new DataGridViewCellStyle(); + DataGridViewCellStyle dataGridViewCellStyle14 = new DataGridViewCellStyle(); + kryptonPanel1 = new Krypton.Toolkit.KryptonPanel(); + splitContainer1 = new SplitContainer(); + leftPanel = new TableLayoutPanel(); + tableNameGv = new Krypton.Toolkit.KryptonDataGridView(); + selectedCol = new Krypton.Toolkit.KryptonDataGridViewCheckBoxColumn(); + tableNameCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + tableLayoutPanel3 = new TableLayoutPanel(); + kryptonLabel1 = new Krypton.Toolkit.KryptonLabel(); + dtTxt = new Krypton.Toolkit.KryptonTextBox(); + dtSearchBut = new Krypton.Toolkit.KryptonButton(); + dtResetBut = new Krypton.Toolkit.KryptonButton(); + loadDbBut = new Krypton.Toolkit.KryptonButton(); + tableLayoutPanel2 = new TableLayoutPanel(); + fieldNameGv = new Krypton.Toolkit.KryptonDataGridView(); + pkCol = new Krypton.Toolkit.KryptonDataGridViewCheckBoxColumn(); + operationCol = new Krypton.Toolkit.KryptonDataGridViewCheckBoxColumn(); + fieldNameCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + typeNameCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + typeOfNameCol = new Krypton.Toolkit.KryptonDataGridViewTextBoxColumn(); + tableLayoutPanel4 = new TableLayoutPanel(); + kryptonLabel2 = new Krypton.Toolkit.KryptonLabel(); + fieldTxt = new Krypton.Toolkit.KryptonTextBox(); + fieldSearchBut = new Krypton.Toolkit.KryptonButton(); + fieldResetBut = new Krypton.Toolkit.KryptonButton(); + ((System.ComponentModel.ISupportInitialize)kryptonPanel1).BeginInit(); + kryptonPanel1.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)splitContainer1).BeginInit(); + splitContainer1.Panel1.SuspendLayout(); + splitContainer1.Panel2.SuspendLayout(); + splitContainer1.SuspendLayout(); + leftPanel.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)tableNameGv).BeginInit(); + tableLayoutPanel3.SuspendLayout(); + tableLayoutPanel2.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)fieldNameGv).BeginInit(); + tableLayoutPanel4.SuspendLayout(); + SuspendLayout(); + // + // kryptonPanel1 + // + kryptonPanel1.Controls.Add(splitContainer1); + kryptonPanel1.Dock = DockStyle.Fill; + kryptonPanel1.Location = new Point(0, 0); + kryptonPanel1.Name = "kryptonPanel1"; + kryptonPanel1.Size = new Size(1024, 600); + kryptonPanel1.TabIndex = 0; + // + // splitContainer1 + // + splitContainer1.BackColor = Color.Transparent; + splitContainer1.BorderStyle = BorderStyle.FixedSingle; + splitContainer1.Dock = DockStyle.Fill; + splitContainer1.Location = new Point(0, 0); + splitContainer1.Name = "splitContainer1"; + // + // splitContainer1.Panel1 + // + splitContainer1.Panel1.Controls.Add(leftPanel); + // + // splitContainer1.Panel2 + // + splitContainer1.Panel2.Controls.Add(tableLayoutPanel2); + splitContainer1.Size = new Size(1024, 600); + splitContainer1.SplitterDistance = 512; + splitContainer1.SplitterWidth = 10; + splitContainer1.TabIndex = 0; + // + // leftPanel + // + leftPanel.ColumnCount = 1; + leftPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F)); + leftPanel.Controls.Add(tableNameGv, 0, 1); + leftPanel.Controls.Add(tableLayoutPanel3, 0, 0); + leftPanel.Dock = DockStyle.Fill; + leftPanel.Location = new Point(0, 0); + leftPanel.Name = "leftPanel"; + leftPanel.RowCount = 2; + leftPanel.RowStyles.Add(new RowStyle()); + leftPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 50F)); + leftPanel.Size = new Size(510, 598); + leftPanel.TabIndex = 0; + // + // tableNameGv + // + tableNameGv.BorderStyle = BorderStyle.None; + tableNameGv.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize; + tableNameGv.Columns.AddRange(new DataGridViewColumn[] { selectedCol, tableNameCol }); + tableNameGv.Dock = DockStyle.Fill; + tableNameGv.Location = new Point(4, 37); + tableNameGv.Margin = new Padding(4); + tableNameGv.Name = "tableNameGv"; + tableNameGv.RowHeadersVisible = false; + tableNameGv.RowTemplate.Height = 23; + tableNameGv.Size = new Size(502, 557); + tableNameGv.TabIndex = 3; + tableNameGv.CellClick += tableNameGv_CellClick; + // + // selectedCol + // + dataGridViewCellStyle8.Alignment = DataGridViewContentAlignment.MiddleCenter; + dataGridViewCellStyle8.NullValue = false; + selectedCol.DefaultCellStyle = dataGridViewCellStyle8; + selectedCol.FalseValue = "N"; + selectedCol.HeaderText = "选择"; + selectedCol.IndeterminateValue = null; + selectedCol.Name = "selectedCol"; + selectedCol.TrueValue = "Y"; + selectedCol.Width = 50; + // + // tableNameCol + // + tableNameCol.DataPropertyName = "TableName"; + tableNameCol.DefaultCellStyle = dataGridViewCellStyle9; + tableNameCol.HeaderText = "数据表"; + tableNameCol.Name = "tableNameCol"; + tableNameCol.Width = 260; + // + // tableLayoutPanel3 + // + tableLayoutPanel3.AutoSize = true; + tableLayoutPanel3.AutoSizeMode = AutoSizeMode.GrowAndShrink; + tableLayoutPanel3.ColumnCount = 5; + tableLayoutPanel3.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel3.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F)); + tableLayoutPanel3.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel3.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel3.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel3.Controls.Add(kryptonLabel1, 0, 0); + tableLayoutPanel3.Controls.Add(dtTxt, 1, 0); + tableLayoutPanel3.Controls.Add(dtSearchBut, 2, 0); + tableLayoutPanel3.Controls.Add(dtResetBut, 3, 0); + tableLayoutPanel3.Controls.Add(loadDbBut, 4, 0); + tableLayoutPanel3.Location = new Point(0, 0); + tableLayoutPanel3.Margin = new Padding(0); + tableLayoutPanel3.Name = "tableLayoutPanel3"; + tableLayoutPanel3.RowCount = 1; + tableLayoutPanel3.RowStyles.Add(new RowStyle()); + tableLayoutPanel3.Size = new Size(382, 33); + tableLayoutPanel3.TabIndex = 2; + // + // kryptonLabel1 + // + kryptonLabel1.Location = new Point(4, 6); + kryptonLabel1.Margin = new Padding(4, 6, 4, 4); + kryptonLabel1.Name = "kryptonLabel1"; + kryptonLabel1.Size = new Size(49, 20); + kryptonLabel1.TabIndex = 0; + kryptonLabel1.Values.Text = "表名:"; + // + // dtTxt + // + dtTxt.Dock = DockStyle.Fill; + dtTxt.Location = new Point(61, 6); + dtTxt.Margin = new Padding(4, 6, 4, 4); + dtTxt.Name = "dtTxt"; + dtTxt.Size = new Size(97, 23); + dtTxt.TabIndex = 1; + // + // dtSearchBut + // + dtSearchBut.Location = new Point(166, 4); + dtSearchBut.Margin = new Padding(4); + dtSearchBut.Name = "dtSearchBut"; + dtSearchBut.Size = new Size(58, 25); + dtSearchBut.TabIndex = 2; + dtSearchBut.Values.Text = "查询"; + dtSearchBut.Click += dtSearchBut_Click; + // + // dtResetBut + // + dtResetBut.Location = new Point(232, 4); + dtResetBut.Margin = new Padding(4); + dtResetBut.Name = "dtResetBut"; + dtResetBut.Size = new Size(58, 25); + dtResetBut.TabIndex = 3; + dtResetBut.Values.Text = "重置"; + dtResetBut.Click += dtResetBut_Click; + // + // loadDbBut + // + loadDbBut.Location = new Point(298, 4); + loadDbBut.Margin = new Padding(4); + loadDbBut.Name = "loadDbBut"; + loadDbBut.Size = new Size(80, 25); + loadDbBut.TabIndex = 3; + loadDbBut.Values.Text = "加载数据库"; + loadDbBut.Click += loadDbBut_Click; + // + // tableLayoutPanel2 + // + tableLayoutPanel2.ColumnCount = 1; + tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F)); + tableLayoutPanel2.Controls.Add(fieldNameGv, 0, 1); + tableLayoutPanel2.Controls.Add(tableLayoutPanel4, 0, 0); + tableLayoutPanel2.Dock = DockStyle.Fill; + tableLayoutPanel2.Location = new Point(0, 0); + tableLayoutPanel2.Margin = new Padding(4); + tableLayoutPanel2.Name = "tableLayoutPanel2"; + tableLayoutPanel2.RowCount = 2; + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle(SizeType.Percent, 100F)); + tableLayoutPanel2.Size = new Size(500, 598); + tableLayoutPanel2.TabIndex = 3; + // + // fieldNameGv + // + fieldNameGv.BorderStyle = BorderStyle.None; + fieldNameGv.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize; + fieldNameGv.Columns.AddRange(new DataGridViewColumn[] { pkCol, operationCol, fieldNameCol, typeNameCol, typeOfNameCol }); + fieldNameGv.Dock = DockStyle.Fill; + fieldNameGv.Location = new Point(4, 37); + fieldNameGv.Margin = new Padding(4); + fieldNameGv.Name = "fieldNameGv"; + fieldNameGv.RowHeadersVisible = false; + fieldNameGv.RowTemplate.Height = 23; + fieldNameGv.Size = new Size(492, 557); + fieldNameGv.TabIndex = 0; + // + // pkCol + // + pkCol.DataPropertyName = "Pk"; + dataGridViewCellStyle10.Alignment = DataGridViewContentAlignment.MiddleCenter; + dataGridViewCellStyle10.NullValue = false; + pkCol.DefaultCellStyle = dataGridViewCellStyle10; + pkCol.FalseValue = "0"; + pkCol.HeaderText = "主键"; + pkCol.IndeterminateValue = null; + pkCol.Name = "pkCol"; + pkCol.TrueValue = "1"; + pkCol.Width = 60; + // + // operationCol + // + operationCol.DataPropertyName = "Operation"; + dataGridViewCellStyle11.Alignment = DataGridViewContentAlignment.MiddleCenter; + dataGridViewCellStyle11.NullValue = false; + operationCol.DefaultCellStyle = dataGridViewCellStyle11; + operationCol.FalseValue = "0"; + operationCol.HeaderText = "差异"; + operationCol.IndeterminateValue = null; + operationCol.Name = "operationCol"; + operationCol.TrueValue = "1"; + operationCol.Width = 60; + // + // fieldNameCol + // + fieldNameCol.DataPropertyName = "FieldName"; + fieldNameCol.DefaultCellStyle = dataGridViewCellStyle12; + fieldNameCol.HeaderText = "字段名"; + fieldNameCol.Name = "fieldNameCol"; + fieldNameCol.Width = 260; + // + // typeNameCol + // + typeNameCol.DataPropertyName = "TypeName"; + typeNameCol.DefaultCellStyle = dataGridViewCellStyle13; + typeNameCol.HeaderText = "类型"; + typeNameCol.Name = "typeNameCol"; + typeNameCol.Width = 60; + // + // typeOfNameCol + // + typeOfNameCol.DataPropertyName = "TypeOfName"; + typeOfNameCol.DefaultCellStyle = dataGridViewCellStyle14; + typeOfNameCol.HeaderText = "映射"; + typeOfNameCol.Name = "typeOfNameCol"; + typeOfNameCol.Width = 60; + // + // tableLayoutPanel4 + // + tableLayoutPanel4.AutoSize = true; + tableLayoutPanel4.AutoSizeMode = AutoSizeMode.GrowAndShrink; + tableLayoutPanel4.ColumnCount = 5; + tableLayoutPanel4.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel4.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F)); + tableLayoutPanel4.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel4.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel4.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel4.Controls.Add(kryptonLabel2, 0, 0); + tableLayoutPanel4.Controls.Add(fieldTxt, 1, 0); + tableLayoutPanel4.Controls.Add(fieldSearchBut, 2, 0); + tableLayoutPanel4.Controls.Add(fieldResetBut, 3, 0); + tableLayoutPanel4.Location = new Point(0, 0); + tableLayoutPanel4.Margin = new Padding(0); + tableLayoutPanel4.Name = "tableLayoutPanel4"; + tableLayoutPanel4.RowCount = 1; + tableLayoutPanel4.RowStyles.Add(new RowStyle()); + tableLayoutPanel4.Size = new Size(340, 33); + tableLayoutPanel4.TabIndex = 1; + // + // kryptonLabel2 + // + kryptonLabel2.Location = new Point(4, 6); + kryptonLabel2.Margin = new Padding(4, 6, 4, 4); + kryptonLabel2.Name = "kryptonLabel2"; + kryptonLabel2.Size = new Size(62, 20); + kryptonLabel2.TabIndex = 0; + kryptonLabel2.Values.Text = "字段名:"; + // + // fieldTxt + // + fieldTxt.Location = new Point(74, 6); + fieldTxt.Margin = new Padding(4, 6, 4, 4); + fieldTxt.Name = "fieldTxt"; + fieldTxt.Size = new Size(130, 23); + fieldTxt.TabIndex = 1; + // + // fieldSearchBut + // + fieldSearchBut.Location = new Point(212, 4); + fieldSearchBut.Margin = new Padding(4); + fieldSearchBut.Name = "fieldSearchBut"; + fieldSearchBut.Size = new Size(58, 25); + fieldSearchBut.TabIndex = 2; + fieldSearchBut.Values.Text = "查询"; + fieldSearchBut.Click += fieldSearchBut_Click; + // + // fieldResetBut + // + fieldResetBut.Location = new Point(278, 4); + fieldResetBut.Margin = new Padding(4); + fieldResetBut.Name = "fieldResetBut"; + fieldResetBut.Size = new Size(58, 25); + fieldResetBut.TabIndex = 3; + fieldResetBut.Values.Text = "重置"; + fieldResetBut.Click += fieldResetBut_Click; + // + // TableControl + // + AutoScaleDimensions = new SizeF(7F, 17F); + AutoScaleMode = AutoScaleMode.Font; + Controls.Add(kryptonPanel1); + Name = "TableControl"; + Size = new Size(1024, 600); + ((System.ComponentModel.ISupportInitialize)kryptonPanel1).EndInit(); + kryptonPanel1.ResumeLayout(false); + splitContainer1.Panel1.ResumeLayout(false); + splitContainer1.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)splitContainer1).EndInit(); + splitContainer1.ResumeLayout(false); + leftPanel.ResumeLayout(false); + leftPanel.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)tableNameGv).EndInit(); + tableLayoutPanel3.ResumeLayout(false); + tableLayoutPanel3.PerformLayout(); + tableLayoutPanel2.ResumeLayout(false); + tableLayoutPanel2.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)fieldNameGv).EndInit(); + tableLayoutPanel4.ResumeLayout(false); + tableLayoutPanel4.PerformLayout(); + ResumeLayout(false); + } + + #endregion + + private Krypton.Toolkit.KryptonPanel kryptonPanel1; + private SplitContainer splitContainer1; + private TableLayoutPanel leftPanel; + private Krypton.Toolkit.KryptonDataGridView tableNameGv; + private TableLayoutPanel tableLayoutPanel3; + private Krypton.Toolkit.KryptonLabel kryptonLabel1; + private Krypton.Toolkit.KryptonTextBox dtTxt; + private Krypton.Toolkit.KryptonButton dtSearchBut; + private TableLayoutPanel tableLayoutPanel2; + private Krypton.Toolkit.KryptonDataGridView fieldNameGv; + private TableLayoutPanel tableLayoutPanel4; + private Krypton.Toolkit.KryptonLabel kryptonLabel2; + private Krypton.Toolkit.KryptonTextBox fieldTxt; + private Krypton.Toolkit.KryptonButton fieldSearchBut; + private Krypton.Toolkit.KryptonButton fieldResetBut; + private Krypton.Toolkit.KryptonButton loadDbBut; + private Krypton.Toolkit.KryptonDataGridViewCheckBoxColumn selectedCol; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn tableNameCol; + private Krypton.Toolkit.KryptonDataGridViewCheckBoxColumn pkCol; + private Krypton.Toolkit.KryptonDataGridViewCheckBoxColumn operationCol; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn fieldNameCol; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn typeNameCol; + private Krypton.Toolkit.KryptonDataGridViewTextBoxColumn typeOfNameCol; + private Krypton.Toolkit.KryptonButton dtResetBut; + } +} diff --git a/CodeGenerator/CloudBuilder.CodeGenerator/TableControl.cs b/CodeGenerator/CloudBuilder.CodeGenerator/TableControl.cs new file mode 100644 index 0000000..06a455b --- /dev/null +++ b/CodeGenerator/CloudBuilder.CodeGenerator/TableControl.cs @@ -0,0 +1,191 @@ +using CloudBuilder.CodeGenerator.Config; +using CloudBuilder.CodeGenerator.Data; +using CloudBuilder.CodeGenerator.Entity; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using CloudBuilder.Core.DependencyInjection.Form; +using CloudBuilder.Core.Extensions; +using CloudBuilder.Core.Utility; +using Krypton.Toolkit; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Reflection.Metadata.Ecma335; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace CloudBuilder.CodeGenerator +{ + public partial class TableControl : UserControl, IUserControl + { + private readonly IApplicationService service; + private readonly ConfigUserControl configUserControl; + private IRepository repository; + public SysTableSchemaViewEntity[] sysTableSchemas; + public SysTableSchemaViewEntity[] sysTableFields; + private SysTable[] sysTables; + private DataTable sysTableField; + + public TableControl(IApplicationService service) + { + InitializeComponent(); + this.service = service; + tableNameGv.AutoGenerateColumns = false; + fieldNameGv.AutoGenerateColumns = false; + } + + private void loadDbBut_Click(object sender, EventArgs e) + { + LoadData(); + } + + public void LoadData() + { + repository = service.GetRepository>(); + sysTableSchemas = repository.DetachedEntities.ToArray(); + + if (sysTableSchemas == null || sysTableSchemas.Length == 0) return; + + sysTables = sysTableSchemas.Select(x => x.TableName).OrderBy(x => x).Distinct() + .Select(x => new SysTable() { TableName = x, Selected = "N" }).ToArray(); + + tableNameGv.DataSource = sysTables; + } + + public SysTableSchemaViewEntity[] GetDataSource() + { + sysTableField = (DataTable)fieldNameGv.DataSource; + return DataTableConvertor.ConvertToList(sysTableField).Where(x => x.Operation == 0).ToArray(); + + } + + private void tableNameGv_CellClick(object sender, DataGridViewCellEventArgs e) + { + if (e.RowIndex < 0) return; + if (e.ColumnIndex != selectedCol.Index) return; + + if (tableNameGv.CurrentRow.Cells[tableNameCol.Name].Value == System.DBNull.Value) return; + + foreach (DataGridViewRow dgrow in tableNameGv.Rows) + { + if (tableNameGv.CurrentRow.Cells[tableNameCol.Name].EditedFormattedValue == dgrow.Cells[tableNameCol.Name].EditedFormattedValue) continue; + + dgrow.Cells[selectedCol.Name].Value = "N"; + } + + sysTableFields = sysTableSchemas.Where(x => x.TableName == (string)tableNameGv.CurrentRow.Cells[tableNameCol.Name].Value).ToArray(); + + sysTableField = DataTableConvertor.ToDataTable(sysTableFields); + fieldNameGv.DataSource = sysTableField; + + SetDataGrivViewCellColor((string)tableNameGv.CurrentRow.Cells[tableNameCol.Name].Value); + } + + private void SetDataGrivViewCellColor(string tableName) + { + ConfigUserControl configUserControl = service.ServiceProvider.GetKeyedService("ConfigUserControl"); + NamespaceObject namespaceObject = configUserControl.toolInitConfig.NamespaceObjects.Where(x => x.Assembly == configUserControl.toolInitConfig.CurrentAssembly + && x.TemplateType == "Entity").FirstOrDefault(); + + if (namespaceObject == null) return; + + string path = Path.Combine(namespaceObject.OutFilePath, tableName.StringToProerty() + namespaceObject.FileNameSuffix); + + //目录先处理对比Entity.cs + if (string.IsNullOrEmpty(path)) return; + + if (!File.Exists(path)) return; + List ents = new List(); + + string[] lines = File.ReadAllLines(path); + SysTableSchemaViewEntity ent; + bool key = false; + foreach (string l in lines) + { + if (l.Contains("[Key]")) + { + key = true; + continue; + } + if (!l.Contains("[Column")) continue; + ent = new SysTableSchemaViewEntity(); + ent.TableName = tableName; + ent.FieldName = l.Split('"')[1];//.Replace("[Column(\"", "").Replace("\")]", "").Trim(); + if (key) ent.Pk = 1; + ents.Add(ent); + key = false; + } + + + if (ents == null || ents.Count == 0) return; + string fileName = null; + + foreach (DataGridViewRow row in fieldNameGv.Rows) + { + row.DefaultCellStyle.BackColor = Color.White; + + fileName = (string)row.Cells[fieldNameCol.Index].Value; + if (string.IsNullOrEmpty(fileName)) continue; + + ent = ents.Where(x => x.FieldName == fileName).FirstOrDefault(); + if (ent == null) + { + row.DefaultCellStyle.BackColor = Color.Pink; + row.Cells[operationCol.Index].Value = 1; + } + else + { + if (ent.Pk > 0 && Convert.ToInt32(row.Cells[pkCol.Index].Value) == 0) + { + row.DefaultCellStyle.BackColor = Color.Red; + } + } + } + } + + private void dtSearchBut_Click(object sender, EventArgs e) + { + if (sysTableSchemas == null) return; + + var sysTable = DataTableConvertor.ToDataTable(sysTables.Where(x => x.TableName.Contains(dtTxt.Text.ToLower().Trim())).ToArray()); + tableNameGv.DataSource = sysTable; + } + + private void dtResetBut_Click(object sender, EventArgs e) + { + if (sysTableSchemas == null) return; + var sysTable = DataTableConvertor.ToDataTable(sysTables); + tableNameGv.DataSource = sysTable; + } + + private void fieldSearchBut_Click(object sender, EventArgs e) + { + if (sysTableSchemas == null) return; + if (sysTableField == null) return; + + sysTableFields = sysTableSchemas.Where(x => x.TableName == (string)tableNameGv.CurrentRow.Cells[tableNameCol.Name].Value + && x.FieldName.StartsWith(fieldTxt.Text.ToLower().Trim())).ToArray(); + + sysTableField = DataTableConvertor.ToDataTable(sysTableFields); + + fieldNameGv.DataSource = sysTableField; + } + + private void fieldResetBut_Click(object sender, EventArgs e) + { + if (sysTableSchemas == null) return; + if (sysTableField == null) return; + sysTableField.Rows.Clear(); + + sysTableFields = sysTableSchemas.Where(x => x.TableName == (string)tableNameGv.CurrentRow.Cells[tableNameCol.Name].Value).ToArray(); + + sysTableField = DataTableConvertor.ToDataTable(sysTableFields); + fieldNameGv.DataSource = sysTableField; + } + } + +} diff --git a/CodeGenerator/CloudBuilder.CodeGenerator/TableControl.resx b/CodeGenerator/CloudBuilder.CodeGenerator/TableControl.resx new file mode 100644 index 0000000..ab896ff --- /dev/null +++ b/CodeGenerator/CloudBuilder.CodeGenerator/TableControl.resx @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + True + + + True + + + True + + \ No newline at end of file diff --git a/CodeGenerator/CloudBuilder.CodeGenerator/TemplateUserControl.Designer.cs b/CodeGenerator/CloudBuilder.CodeGenerator/TemplateUserControl.Designer.cs new file mode 100644 index 0000000..2a3b41e --- /dev/null +++ b/CodeGenerator/CloudBuilder.CodeGenerator/TemplateUserControl.Designer.cs @@ -0,0 +1,168 @@ +namespace CloudBuilder.CodeGenerator +{ + partial class TemplateUserControl + { + /// + /// 設計工具所需的變數。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清除任何使用中的資源。 + /// + /// 如果應該處置受控資源則為 true,否則為 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 元件設計工具產生的程式碼 + + /// + /// 此為設計工具支援所需的方法 - 請勿使用程式碼編輯器修改 + /// 這個方法的內容。 + /// + private void InitializeComponent() + { + tableLayoutPanel1 = new TableLayoutPanel(); + kryptonHeader1 = new Krypton.Toolkit.KryptonHeader(); + tableLayoutPanel2 = new TableLayoutPanel(); + templatePathBut = new Krypton.Toolkit.KryptonButton(); + templatePathTxt = new Krypton.Toolkit.KryptonTextBox(); + kryptonLabel1 = new Krypton.Toolkit.KryptonLabel(); + contextTxt = new Krypton.Toolkit.KryptonRichTextBox(); + saveFileBut = new Krypton.Toolkit.KryptonButton(); + tableLayoutPanel1.SuspendLayout(); + tableLayoutPanel2.SuspendLayout(); + SuspendLayout(); + // + // tableLayoutPanel1 + // + tableLayoutPanel1.ColumnCount = 1; + tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F)); + tableLayoutPanel1.Controls.Add(kryptonHeader1, 0, 0); + tableLayoutPanel1.Controls.Add(tableLayoutPanel2, 0, 1); + tableLayoutPanel1.Controls.Add(contextTxt, 0, 2); + tableLayoutPanel1.Dock = DockStyle.Fill; + tableLayoutPanel1.Location = new Point(0, 0); + tableLayoutPanel1.Name = "tableLayoutPanel1"; + tableLayoutPanel1.RowCount = 3; + tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Absolute, 35F)); + tableLayoutPanel1.RowStyles.Add(new RowStyle()); + tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent, 100F)); + tableLayoutPanel1.Size = new Size(800, 600); + tableLayoutPanel1.TabIndex = 0; + // + // kryptonHeader1 + // + tableLayoutPanel1.SetColumnSpan(kryptonHeader1, 4); + kryptonHeader1.Dock = DockStyle.Fill; + kryptonHeader1.Location = new Point(4, 4); + kryptonHeader1.Margin = new Padding(4); + kryptonHeader1.Name = "kryptonHeader1"; + kryptonHeader1.Size = new Size(792, 27); + kryptonHeader1.TabIndex = 13; + kryptonHeader1.Values.Description = ""; + kryptonHeader1.Values.Heading = "模板加載"; + kryptonHeader1.Values.Image = null; + // + // tableLayoutPanel2 + // + tableLayoutPanel2.AutoSize = true; + tableLayoutPanel2.AutoSizeMode = AutoSizeMode.GrowAndShrink; + tableLayoutPanel2.ColumnCount = 4; + tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F)); + tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel2.Controls.Add(templatePathBut, 0, 0); + tableLayoutPanel2.Controls.Add(templatePathTxt, 0, 0); + tableLayoutPanel2.Controls.Add(kryptonLabel1, 0, 0); + tableLayoutPanel2.Controls.Add(saveFileBut, 3, 0); + tableLayoutPanel2.Dock = DockStyle.Fill; + tableLayoutPanel2.Location = new Point(3, 38); + tableLayoutPanel2.Name = "tableLayoutPanel2"; + tableLayoutPanel2.RowCount = 1; + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.Size = new Size(794, 31); + tableLayoutPanel2.TabIndex = 14; + // + // templatePathBut + // + templatePathBut.AutoSize = true; + templatePathBut.Location = new Point(646, 4); + templatePathBut.Margin = new Padding(4); + templatePathBut.Name = "templatePathBut"; + templatePathBut.Size = new Size(76, 22); + templatePathBut.TabIndex = 6; + templatePathBut.Values.Text = "选择文件(...)"; + templatePathBut.Click += templatePathBut_Click; + // + // templatePathTxt + // + templatePathTxt.Dock = DockStyle.Fill; + templatePathTxt.Location = new Point(87, 4); + templatePathTxt.Margin = new Padding(4); + templatePathTxt.Name = "templatePathTxt"; + templatePathTxt.Size = new Size(551, 23); + templatePathTxt.TabIndex = 5; + // + // kryptonLabel1 + // + kryptonLabel1.Location = new Point(4, 6); + kryptonLabel1.Margin = new Padding(4, 6, 4, 4); + kryptonLabel1.Name = "kryptonLabel1"; + kryptonLabel1.Size = new Size(75, 20); + kryptonLabel1.TabIndex = 1; + kryptonLabel1.Values.Text = "模板路径:"; + // + // contextTxt + // + contextTxt.Dock = DockStyle.Fill; + contextTxt.Location = new Point(3, 75); + contextTxt.Name = "contextTxt"; + contextTxt.Size = new Size(794, 522); + contextTxt.TabIndex = 15; + contextTxt.Text = ""; + // + // saveFileBut + // + saveFileBut.AutoSize = true; + saveFileBut.Location = new Point(730, 4); + saveFileBut.Margin = new Padding(4); + saveFileBut.Name = "saveFileBut"; + saveFileBut.Size = new Size(60, 22); + saveFileBut.TabIndex = 6; + saveFileBut.Values.Text = "保存文件"; + saveFileBut.Click += saveFileBut_Click; + // + // TemplateUserControl + // + AutoScaleDimensions = new SizeF(7F, 17F); + AutoScaleMode = AutoScaleMode.Font; + Controls.Add(tableLayoutPanel1); + Name = "TemplateUserControl"; + Size = new Size(800, 600); + tableLayoutPanel1.ResumeLayout(false); + tableLayoutPanel1.PerformLayout(); + tableLayoutPanel2.ResumeLayout(false); + tableLayoutPanel2.PerformLayout(); + ResumeLayout(false); + } + + #endregion + + private TableLayoutPanel tableLayoutPanel1; + private Krypton.Toolkit.KryptonHeader kryptonHeader1; + private TableLayoutPanel tableLayoutPanel2; + private Krypton.Toolkit.KryptonLabel kryptonLabel1; + private Krypton.Toolkit.KryptonTextBox templatePathTxt; + private Krypton.Toolkit.KryptonButton templatePathBut; + public Krypton.Toolkit.KryptonRichTextBox contextTxt; + private Krypton.Toolkit.KryptonButton saveFileBut; + } +} diff --git a/CodeGenerator/CloudBuilder.CodeGenerator/TemplateUserControl.cs b/CodeGenerator/CloudBuilder.CodeGenerator/TemplateUserControl.cs new file mode 100644 index 0000000..a125957 --- /dev/null +++ b/CodeGenerator/CloudBuilder.CodeGenerator/TemplateUserControl.cs @@ -0,0 +1,37 @@ +using CloudBuilder.Core.DependencyInjection.Form; +using Microsoft.AspNetCore.Routing.Template; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace CloudBuilder.CodeGenerator +{ + public partial class TemplateUserControl : UserControl, IUserControl + { + public TemplateUserControl() + { + InitializeComponent(); + } + + private void templatePathBut_Click(object sender, EventArgs e) + { + OpenFileDialog ofd = new OpenFileDialog(); + if (DialogResult.OK == ofd.ShowDialog()) + { + templatePathTxt.Text = ofd.FileName; + contextTxt.Text = File.ReadAllText(ofd.FileName); + } + } + + private void saveFileBut_Click(object sender, EventArgs e) + { + File.WriteAllText(templatePathTxt.Text, contextTxt.Text); + } + } +} diff --git a/CodeGenerator/CloudBuilder.CodeGenerator/TemplateUserControl.resx b/CodeGenerator/CloudBuilder.CodeGenerator/TemplateUserControl.resx new file mode 100644 index 0000000..af32865 --- /dev/null +++ b/CodeGenerator/CloudBuilder.CodeGenerator/TemplateUserControl.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/CodeGenerator/CloudBuilder.CodeGenerator/Utility/RazorEngineHelper.cs b/CodeGenerator/CloudBuilder.CodeGenerator/Utility/RazorEngineHelper.cs new file mode 100644 index 0000000..3627ed6 --- /dev/null +++ b/CodeGenerator/CloudBuilder.CodeGenerator/Utility/RazorEngineHelper.cs @@ -0,0 +1,302 @@ +using CloudBuilder.CodeGenerator.Config; +using CloudBuilder.CodeGenerator.Data; +using CloudBuilder.Core.Application.Builders; +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.DatabaseAccessor; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using CloudBuilder.Core.Extensions; +using CloudBuilder.Core.Service; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using RazorEngineCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.CodeGenerator.Utility +{ + public class RazorEngineHelper + { + public static string CompiledTemplate(string template, ModelData model) + { + ToolInitConfig toolInitConfig = ToolInitConfig.GetInstance(); + + IRazorEngine razorEngine = new RazorEngine(); + + List args = new List(); + if (toolInitConfig.AssemblyReferences != null) + { + foreach (var reference in toolInitConfig.AssemblyReferences) + { + if (string.IsNullOrEmpty(reference.AssemblyFileName)) continue; + + if (!File.Exists(reference.AssemblyFileName)) continue; + args.Add(reference.AssemblyFileName); + } + } + + template = toolInitConfig.Using + template; + + try + { + IRazorEngineCompiledTemplate compiledTemplate = razorEngine.Compile(template, builder => + { + //builder.AddAssemblyReferenceByName("System.Security"); // by name + foreach (string arg in args) + { + builder.AddAssemblyReference(Assembly.LoadFrom(arg)); + } + + Assembly[] assemblies = CloudBuilderBuilder.GetAssemblies(); + foreach (Assembly assembly in assemblies) + { + builder.AddAssemblyReference(assembly); + } + + builder.AddAssemblyReference(typeof(System.IO.File)); // by type + //builder.AddAssemblyReference(Assembly.Load("source")); // by reference + }); + + return compiledTemplate.Run(model); + } + catch (Exception ex) + { + throw ex; + } + + return null; + } + + public static ClassInfo[] PackIServiceClassInfo(Assembly assembly) + { + if (assembly == null) return null; + + var baseServiceType = typeof(IService); + + var typeServices = assembly.GetTypes() + .Where(type => type != baseServiceType && type.HasImplementedRawGeneric(baseServiceType)) + .Where(x => x.IsClass).ToList(); + + List classInfos = new List(); + List usings = new List(); + foreach (var implementType in typeServices) + { + ClassInfo classInfo = new ClassInfo(); + classInfo.ClassName = implementType.Name; + classInfo.InterfaceName = implementType.GetInterfaces().FirstOrDefault().Name; + if (!usings.Contains(implementType.GetInterfaces().FirstOrDefault().Namespace)) + { + usings.Add(implementType.GetInterfaces().FirstOrDefault().Namespace); + } + + var tors = implementType.GetConstructors(); + ClassConstructorInfo constructorInfo = new ClassConstructorInfo(); + List parameters = new List(); + foreach (var item in tors) + { + ParameterInfo[] Parameters = item.GetParameters(); + MethodParameter methodParameter; + foreach (var pi in Parameters) + { + methodParameter = new MethodParameter(); + methodParameter.ParameterName = pi.Name; + methodParameter.ParameterTypeName = pi.ParameterType.Name; + + if (!usings.Contains(pi.ParameterType.Namespace)) + { + usings.Add(pi.ParameterType.Namespace); + } + + parameters.Add(methodParameter); + } + } + constructorInfo.Parameters = parameters.ToArray(); + classInfo.ClassConstructorInfos = new ClassConstructorInfo[] { constructorInfo }; + + List classMethodInfos = new List(); + ClassMethodInfo classMethodInfo; + MethodInfo[] infos = implementType.GetMethods(); + foreach (var item in infos) + { + var permissionOperate = item.GetCustomAttribute(); + var allowAnonymous = item.GetCustomAttribute(); + if (permissionOperate == null && allowAnonymous == null) continue; + classMethodInfo = new ClassMethodInfo(); + classMethodInfo.MethodName = item.Name; + var httpGet = item.GetCustomAttribute(); + if (httpGet != null) classMethodInfo.HttpName = "[HttpGet]"; + + if (permissionOperate != null) + { + classMethodInfo.AuthorizeName = null; + classMethodInfo.PermissionOperateAttribute = permissionOperate; + } + else + { + classMethodInfo.PermissionOperate = null; + } + + var unitOfWork = item.GetCustomAttribute(); + if (unitOfWork == null) classMethodInfo.UnitOfWorkName = null; + + classMethodInfo.MethodReturnName = item.ReturnType.Name; + bool isValueType = MethodParameter.CheckValueType(item.ReturnType); + classMethodInfo.IsValueType = isValueType; + + if (!isValueType && !usings.Contains(item.ReturnType.Namespace)) + { + usings.Add(item.ReturnType.Namespace); + } + + + classMethodInfo.MethodReturnName = classMethodInfo.MethodReturnName == "Object" ? "dynamic" : classMethodInfo.MethodReturnName; + + ParameterInfo[] methodParameters = item.GetParameters(); + List methodParameterLs = new List(); + MethodParameter methodParameter; + foreach (var pi in methodParameters) + { + methodParameter = new MethodParameter(); + methodParameter.ParameterName = pi.Name; + methodParameter.ParameterTypeName = pi.ParameterType.Name; + + if (!usings.Contains(pi.ParameterType.Namespace)) + { + usings.Add(pi.ParameterType.Namespace); + } + + methodParameter.IsValueType = MethodParameter.CheckValueType(pi.ParameterType); + if (methodParameter.IsValueType) methodParameter.ParameterTypeName = methodParameter.ParameterTypeName; + methodParameterLs.Add(methodParameter); + } + classMethodInfo.Parameters = methodParameterLs.ToArray(); + classMethodInfos.Add(classMethodInfo); + } + classInfo.ClassMethodInfos = classMethodInfos.ToArray(); + classInfo.Usings = usings.ToArray(); + classInfos.Add(classInfo); + } + + return classInfos.ToArray(); + } + + public static ClassInfo[] PackTypeScriptClassInfo(Assembly assembly) + { + var typeDatas = assembly.GetTypes() + .Where(x => x.GetCustomAttribute() != null) + .Where(x => x.IsClass).ToList(); + + List dataInfos = new List(); + ClassInfo dataInfo; + List classPropertyInfos = new List(); + ClassPropertyInfo classPropertyInfo; + List baseTypes = new List(); + foreach (var implementType in typeDatas) + { + PackClassInfo(dataInfos, implementType); + } + + return dataInfos.ToArray(); + } + + public static void PackClassInfo(List dataInfos, Type implementType) + { + ClassInfo dataInfo = new ClassInfo(); + dataInfo.ClassName = implementType.Name; + + if (implementType.BaseType != typeof(ViewEntityBase) && + implementType.BaseType != typeof(object) + && implementType.BaseType != null && !implementType.BaseType.Name.StartsWith("EntityBase")) + { + dataInfo.ImplementTypeName = implementType.BaseType.Name; + PackClassInfo(dataInfos, implementType.BaseType); + } + + PropertyInfo[] properties = implementType.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance); + List baseTypes = new List(); + List classPropertyInfos = new List(); + ClassPropertyInfo classPropertyInfo; + + ToolInitConfig toolInitConfig = ToolInitConfig.GetInstance(); + + foreach (var item in properties) + { + classPropertyInfo = new ClassPropertyInfo(); + classPropertyInfo.PropertyName = item.Name; + + Type type = item.PropertyType; + + bool isContinue = false; + foreach (string exculdePropertyType in toolInitConfig.ExculdePropertyTypes) + { + if (item.PropertyType.Name.Contains(exculdePropertyType)) + { + classPropertyInfo.PropertyTypeName = "any"; + isContinue = true; + break; + } + } + + if (isContinue) + { + classPropertyInfos.Add(classPropertyInfo); + continue; + } + if (item.PropertyType.BaseType != null && item.PropertyType.BaseType.Name == "Array") + { + string typeName = item.PropertyType.FullName.Replace("[]", string.Empty); + type = item.PropertyType.Assembly.GetType(typeName); + classPropertyInfo.IsValueType = MethodParameter.CheckValueType(type); + classPropertyInfo.PropertyTypeName = type.Name + "[]"; + } + else if (item.PropertyType.Name == "List`1") + { + string typeName = item.PropertyType.FullName.Replace("[[", "|").Replace(",", "|").Split('|')[1]; + type = item.PropertyType.Assembly.GetType(typeName); + classPropertyInfo.IsValueType = MethodParameter.CheckValueType(type); + classPropertyInfo.PropertyTypeName = type.Name + "[]"; + } + + else + { + classPropertyInfo.IsValueType = MethodParameter.CheckValueType(item.PropertyType); + classPropertyInfo.PropertyTypeName = item.PropertyType.Name; + } + if (!classPropertyInfo.IsValueType) + { + if (!baseTypes.Contains(type.Name)) + baseTypes.Add(type.Name); + PackClassInfo(dataInfos, type); + } + + classPropertyInfos.Add(classPropertyInfo); + } + dataInfo.ClassProperties = classPropertyInfos.ToArray(); + if (baseTypes.Count > 0) + dataInfo.Usings = baseTypes.ToArray(); + + FieldInfo[] fields = implementType.GetFields(); + List fieldInfos = new List(); + ClassFieldInfo classFieldInfo; + + foreach (var item in fields) + { + if (!item.IsStatic) continue; + bool IsValueType = MethodParameter.CheckValueType(item.FieldType); + if (!IsValueType) continue; + classFieldInfo = new ClassFieldInfo(); + classFieldInfo.IsValueType = IsValueType; + classFieldInfo.FieldName = item.Name; + classFieldInfo.FieldTypeName = item.FieldType.Name; + classFieldInfo.FieldValue = Convert.ToString(item.GetValue(null)); + fieldInfos.Add(classFieldInfo); + } + dataInfo.ClassFields = fieldInfos.ToArray(); + + dataInfos.Add(dataInfo); + } + } +} diff --git a/CodeGenerator/CloudBuilder.CodeGenerator/appsettings.json b/CodeGenerator/CloudBuilder.CodeGenerator/appsettings.json new file mode 100644 index 0000000..00b6c7f --- /dev/null +++ b/CodeGenerator/CloudBuilder.CodeGenerator/appsettings.json @@ -0,0 +1,15 @@ +{ + "CloudBuilder": { + "DbContexts": { + "MasterDbContext": { + "DbContextTypeName": "MasterDbContext", + "ConnectionString": "server=nas.youjiala.com;port=3307;database=Furion;uid=root;pwd=Root@1237890;CharSet=utf8mb4;", + "DatabaseType": "MySql", + "LazyLoadingProxiesEnabled": true, + "AuditEntityEnabled": true, + "AutoMigrationEnabled": true + } + } + }, + "AllowedHosts": "*" +} diff --git a/CodeGenerator/CodeGenerator.sln b/CodeGenerator/CodeGenerator.sln new file mode 100644 index 0000000..26328ca --- /dev/null +++ b/CodeGenerator/CodeGenerator.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.14.37111.16 d17.14 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeGenerator", "CodeGenerator\CodeGenerator.csproj", "{98461068-4E23-136C-C53A-83F0DF4A6EFD}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {98461068-4E23-136C-C53A-83F0DF4A6EFD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {98461068-4E23-136C-C53A-83F0DF4A6EFD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {98461068-4E23-136C-C53A-83F0DF4A6EFD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {98461068-4E23-136C-C53A-83F0DF4A6EFD}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {B758090B-1A94-4803-9CDC-A3A611F46C11} + EndGlobalSection +EndGlobal diff --git a/CodeGenerator/CodeGenerator/.vs/CodeGenerator/CopilotIndices/17.14.1641.39856/CodeChunks.db b/CodeGenerator/CodeGenerator/.vs/CodeGenerator/CopilotIndices/17.14.1641.39856/CodeChunks.db new file mode 100644 index 0000000..b7ed928 Binary files /dev/null and b/CodeGenerator/CodeGenerator/.vs/CodeGenerator/CopilotIndices/17.14.1641.39856/CodeChunks.db differ diff --git a/CodeGenerator/CodeGenerator/.vs/CodeGenerator/CopilotIndices/17.14.1641.39856/SemanticSymbols.db b/CodeGenerator/CodeGenerator/.vs/CodeGenerator/CopilotIndices/17.14.1641.39856/SemanticSymbols.db new file mode 100644 index 0000000..6a00798 Binary files /dev/null and b/CodeGenerator/CodeGenerator/.vs/CodeGenerator/CopilotIndices/17.14.1641.39856/SemanticSymbols.db differ diff --git a/CodeGenerator/CodeGenerator/.vs/CodeGenerator/DesignTimeBuild/.dtbcache.v2 b/CodeGenerator/CodeGenerator/.vs/CodeGenerator/DesignTimeBuild/.dtbcache.v2 new file mode 100644 index 0000000..75b14a3 Binary files /dev/null and b/CodeGenerator/CodeGenerator/.vs/CodeGenerator/DesignTimeBuild/.dtbcache.v2 differ diff --git a/CodeGenerator/CodeGenerator/.vs/CodeGenerator/v17/.futdcache.v2 b/CodeGenerator/CodeGenerator/.vs/CodeGenerator/v17/.futdcache.v2 new file mode 100644 index 0000000..1ce94aa Binary files /dev/null and b/CodeGenerator/CodeGenerator/.vs/CodeGenerator/v17/.futdcache.v2 differ diff --git a/CodeGenerator/CodeGenerator/.vs/CodeGenerator/v17/.suo b/CodeGenerator/CodeGenerator/.vs/CodeGenerator/v17/.suo new file mode 100644 index 0000000..db4e135 Binary files /dev/null and b/CodeGenerator/CodeGenerator/.vs/CodeGenerator/v17/.suo differ diff --git a/CodeGenerator/CodeGenerator/.vs/ProjectEvaluation/codegenerator.metadata.v9.bin b/CodeGenerator/CodeGenerator/.vs/ProjectEvaluation/codegenerator.metadata.v9.bin new file mode 100644 index 0000000..b279c1f Binary files /dev/null and b/CodeGenerator/CodeGenerator/.vs/ProjectEvaluation/codegenerator.metadata.v9.bin differ diff --git a/CodeGenerator/CodeGenerator/.vs/ProjectEvaluation/codegenerator.projects.v9.bin b/CodeGenerator/CodeGenerator/.vs/ProjectEvaluation/codegenerator.projects.v9.bin new file mode 100644 index 0000000..22fbecb Binary files /dev/null and b/CodeGenerator/CodeGenerator/.vs/ProjectEvaluation/codegenerator.projects.v9.bin differ diff --git a/CodeGenerator/CodeGenerator/.vs/ProjectEvaluation/codegenerator.strings.v9.bin b/CodeGenerator/CodeGenerator/.vs/ProjectEvaluation/codegenerator.strings.v9.bin new file mode 100644 index 0000000..f6d67eb Binary files /dev/null and b/CodeGenerator/CodeGenerator/.vs/ProjectEvaluation/codegenerator.strings.v9.bin differ diff --git a/CodeGenerator/CodeGenerator/CodeGenerator.csproj b/CodeGenerator/CodeGenerator/CodeGenerator.csproj new file mode 100644 index 0000000..662b6a7 --- /dev/null +++ b/CodeGenerator/CodeGenerator/CodeGenerator.csproj @@ -0,0 +1,51 @@ + + + + Exe + net8.0-windows + enable + enable + + + + + + + + + + PreserveNewest + + + PreserveNewest + + + + + + + + + + + + + + + + + + + + + + + + ..\CloudBuilder.CodeGenerator\bin\Debug\net8.0-windows\CloudBuilder.CodeGenerator.dll + + + ..\Lib\CloudBuilder.Core.dll + + + + diff --git a/CodeGenerator/CodeGenerator/Config/tool-init-config.xml b/CodeGenerator/CodeGenerator/Config/tool-init-config.xml new file mode 100644 index 0000000..33ad959 --- /dev/null +++ b/CodeGenerator/CodeGenerator/Config/tool-init-config.xml @@ -0,0 +1,212 @@ + + + D:\NET8\Templates + CloudBuilder.AI + + @using CloudBuilder.CodeGenerator.Config; + @using CloudBuilder.CodeGenerator.Data; + @using CloudBuilder.CodeGenerator.Entity; + @using CloudBuilder.Core.Application.Builders; + @using CloudBuilder.Core.DatabaseAccessor.Entity; + @using CloudBuilder.Core.DependencyInjection.Form; + @using CloudBuilder.Core.Extensions; + @using CloudBuilder.Core.Utility; + @using Microsoft.Extensions.DependencyInjection; + @using System.Data; + @using System; + @using System.Reflection; + + + + Request + Request.cshtml + D:\MAFAI\CloudBuilder\CloudBuilder.Request\AI + CloudBuilder.Request + CloudBuilder.Request.AI + Request.auto.cs + + + + Entity + IEntity.cshtml + D:\MAFAI\CloudBuilder\CloudBuilder.AI\Entity + CloudBuilder.AI + CloudBuilder.AI + Entity.auto.cs + + + IEntityKey + IEntityKey.cshtml + D:\MAFAI\CloudBuilder\CloudBuilder.AI\Entity + CloudBuilder.AI + CloudBuilder.AI + EntityKey.auto.cs + + + IService + IService.cshtml + D:\MAFAI\CloudBuilder\CloudBuilder.AI\Service + CloudBuilder.AI + CloudBuilder.AI + Service.auto.cs + I + + + Permission + Permission.cshtml + D:\MAFAI\CloudBuilder\CloudBuilder.AI\Policy + CloudBuilder.AI + CloudBuilder.AI + PermissionPolicy.auto.cs + + + RegistEntity + RegistEntity.cshtml + D:\MAFAI\CloudBuilder\CloudBuilder.AI\Entity + CloudBuilder.AI + CloudBuilder.AI + RegistEntity.auto.cs + + + SearchCriteria + SearchCriteria.cshtml + D:\MAFAI\CloudBuilder\CloudBuilder.AI\SearchCriteria + CloudBuilder.AI + CloudBuilder.AI + SearchCriteria.auto.cs + + + Service + Service.cshtml + D:\MAFAI\CloudBuilder\CloudBuilder.AI.Service + CloudBuilder.AI + CloudBuilder.AI + Service.auto.cs + + + TypeScript + TypeScript.cshtml + D:\MAFAI\WebVue\src\data\auto + CloudBuilder.AI + CloudBuilder.AI + .ts + + + Controller + Controller.cshtml + D:\MAFAI\CloudBuilder\CloudBuilder.Web.Entry\Controllers\Ai + CloudBuilder.AI.Service + CloudBuilder.Web.Entry.Controllers.Ai + Controller.auto.cs + + + TypeScriptService + TypeScriptService.cshtml + D:\MAFAI\WebVue\src\service\Ai + CloudBuilder.AI.Service + CloudBuilder.Web.Entry.Controllers.Ai + .ts + + + Request + Request.cshtml + D:\MAFAI\CloudBuilder\CloudBuilder.Request\Security + CloudBuilder.Request + CloudBuilder.Request.Security + Request.auto.cs + + + + Entity + IEntity.cshtml + D:\MAFAI\CloudBuilder\CloudBuilder.Security\Entity + CloudBuilder.Security + CloudBuilder.Security + Entity.auto.cs + + + IEntityKey + IEntityKey.cshtml + D:\MAFAI\CloudBuilder\CloudBuilder.Security\Entity + CloudBuilder.Security + CloudBuilder.Security + EntityKey.auto.cs + + + IService + IService.cshtml + D:\MAFAI\CloudBuilder\CloudBuilder.Security\Service + CloudBuilder.Security + CloudBuilder.Security + Service.auto.cs + I + + + Permission + Permission.cshtml + D:\MAFAI\CloudBuilder\CloudBuilder.Security\Policy + CloudBuilder.Security + CloudBuilder.Security + PermissionPolicy.auto.cs + + + RegistEntity + RegistEntity.cshtml + D:\MAFAI\CloudBuilder\CloudBuilder.Security\Entity + CloudBuilder.Security + CloudBuilder.Security + RegistEntity.auto.cs + + + SearchCriteria + SearchCriteria.cshtml + D:\MAFAI\CloudBuilder\CloudBuilder.Security\SearchCriteria + CloudBuilder.Security + CloudBuilder.Security + SearchCriteria.auto.cs + + + Service + Service.cshtml + D:\MAFAI\CloudBuilder\CloudBuilder.Security.Service + CloudBuilder.Security + CloudBuilder.Security + Service.auto.cs + + + TypeScript + TypeScript.cshtml + D:\MAFAI\WebVue\src\data\auto + CloudBuilder.Security + CloudBuilder.Security + .ts + + + Controller + Controller.cshtml + D:\MAFAI\CloudBuilder\CloudBuilder.Web.Entry\Controllers\Security + CloudBuilder.Security.Service + CloudBuilder.Web.Entry.Controllers.Security + Controller.auto.cs + + + TypeScriptService + TypeScriptService.cshtml + D:\MAFAI\WebVue\src\service\security + CloudBuilder.Security.Service + CloudBuilder.Web.Entry.Controllers.Security + .ts + + + + + D:\MAFAI\CloudBuilder\CloudBuilder.Security.Service\bin\Debug\net8.0\CloudBuilder.Security.Service.dll + + + D:\MAFAI\CloudBuilder\CloudBuilder.Security\bin\Debug\net8.0\CloudBuilder.Security.dll + + + + Dictionary + + diff --git a/CodeGenerator/CodeGenerator/Program.cs b/CodeGenerator/CodeGenerator/Program.cs new file mode 100644 index 0000000..40bbd59 --- /dev/null +++ b/CodeGenerator/CodeGenerator/Program.cs @@ -0,0 +1,214 @@ +// See https://aka.ms/new-console-template for more information +using CloudBuilder.CodeGenerator.Config; +using CloudBuilder.CodeGenerator.Data; +using CloudBuilder.CodeGenerator.Utility; +using CloudBuilder.Core.Application.Builders; +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.DatabaseAccessor; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using CloudBuilder.Core.Extensions; +using CloudBuilder.Core.Service; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Connections; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; +using RazorEngineCore; +using System.Diagnostics; +using System.Reflection; +using static System.Net.Mime.MediaTypeNames; + +public partial class Program +{ + static void Main(string[] args) + { + try + { + string logFileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "log\\log.txt"); + + if (!Directory.Exists(Path.GetDirectoryName(logFileName))) Directory.CreateDirectory(Path.GetDirectoryName(logFileName)); + using (StreamWriter w = File.AppendText(logFileName)) + { + w.WriteLine($"[{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}]Start:"); + } + + Assembly assembly = null; + + if (args != null && args.Length > 0) + { + Console.WriteLine(args[0]); + assembly = Assembly.LoadFrom(args[0]); + } + + if (assembly == null) return; + + using (StreamWriter w = File.AppendText(logFileName)) + { + w.WriteLine($"[{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}]Succeed:" + assembly.FullName); + } + + ModelData modelData = null; + ToolInitConfig toolInitConfig = ToolInitConfig.GetInstance(); + string template = null; + string outputText = null; + string outputFileName = null; + + + ClassInfo[] dataInfos = RazorEngineHelper.PackTypeScriptClassInfo(assembly); + + using (StreamWriter w = File.AppendText(logFileName)) + { + w.WriteLine($"[{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}]PackTypeScriptClassInfo:" + dataInfos.Count()); + } + + foreach (var item in dataInfos) + { + modelData = new ModelData(); + modelData.ClassInfo = item; + modelData.ClassInfos = new ClassInfo[] { item }; + modelData.NamespaceObject = toolInitConfig.NamespaceObjects.Where(x => x.TemplateType == "TypeScript" && x.Assembly == Path.GetFileNameWithoutExtension(assembly.Location)).FirstOrDefault(); + if (modelData.NamespaceObject == null) continue; + + outputFileName = Path.Combine(modelData.NamespaceObject.OutFilePath, item.ClassName.StringToProtectedProerty() + modelData.NamespaceObject.FileNameSuffix); + if (string.IsNullOrEmpty(outputFileName)) continue; + + template = File.ReadAllText(Path.Combine(toolInitConfig.TemplatePath, modelData.NamespaceObject.TemplateFileName)); + if (string.IsNullOrEmpty(template)) continue; + + outputText = RazorEngineHelper.CompiledTemplate(template, modelData); + if (string.IsNullOrEmpty(outputText)) continue; + + if (!Directory.Exists(Path.GetDirectoryName(outputFileName))) Directory.CreateDirectory(Path.GetDirectoryName(outputFileName)); + + File.WriteAllText(outputFileName, outputText); + + + if (!Directory.Exists(Path.GetDirectoryName(logFileName))) Directory.CreateDirectory(Path.GetDirectoryName(logFileName)); + using (StreamWriter w = File.AppendText(logFileName)) + { + w.WriteLine($"[{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}]Succeed:" + outputFileName); + } + } + + template = null; + outputText = null; + outputFileName = null; + + ClassInfo[] classInfos = RazorEngineHelper.PackIServiceClassInfo(assembly); + + using (StreamWriter w = File.AppendText(logFileName)) + { + w.WriteLine($"[{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}]PackIServiceClassInfo:" + classInfos.Count()); + } + + foreach (var item in classInfos) + { + //没有要生成公共方法的接口不处理 + if (item.ClassMethodInfos.Length == 0) continue; + + modelData = new ModelData(); + modelData.ClassInfo = item; + + if (item.ClassMethodInfos.Select(x => x.MethodName).Where(x => x.StartsWith("PrintBy")).Count() > 0) + { + modelData.ClassInfo.IsDownload = true; + } + + modelData.ClassInfos = new ClassInfo[] { item }; + + modelData.NamespaceObject = toolInitConfig.NamespaceObjects.Where(x => x.TemplateType == "Controller" && x.Assembly == Path.GetFileNameWithoutExtension(assembly.Location)).FirstOrDefault(); + + using (StreamWriter w = File.AppendText(logFileName)) + { + w.WriteLine($"[{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}]Controller:" + (modelData.NamespaceObject == null ? ("配置文件不存在【TemplateType、Assembly】" + Path.GetFileNameWithoutExtension(assembly.Location)) : modelData.NamespaceObject.OutFilePath)); + } + + if (modelData.NamespaceObject == null) continue; + + outputFileName = Path.Combine(modelData.NamespaceObject.OutFilePath, item.ClassName.Replace("Service", "") + modelData.NamespaceObject.FileNameSuffix); + + using (StreamWriter w = File.AppendText(logFileName)) + { + w.WriteLine($"[{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}]Controller:" + (string.IsNullOrEmpty(outputFileName) ? "空文件" : outputFileName)); + } + + if (string.IsNullOrEmpty(outputFileName)) continue; + + template = File.ReadAllText(Path.Combine(toolInitConfig.TemplatePath, modelData.NamespaceObject.TemplateFileName)); + if (string.IsNullOrEmpty(template)) continue; + + outputText = RazorEngineHelper.CompiledTemplate(template, modelData); + if (string.IsNullOrEmpty(outputText)) continue; + + if (!Directory.Exists(Path.GetDirectoryName(outputFileName))) Directory.CreateDirectory(Path.GetDirectoryName(outputFileName)); + + File.WriteAllText(outputFileName, outputText); + + + if (!Directory.Exists(Path.GetDirectoryName(logFileName))) Directory.CreateDirectory(Path.GetDirectoryName(logFileName)); + using (StreamWriter w = File.AppendText(logFileName)) + { + w.WriteLine($"[{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}]Succeed:" + outputFileName); + } + //================================CloudBuilder.Security.Service >.Security + modelData.NamespaceObject = toolInitConfig.NamespaceObjects.Where(x => x.TemplateType == "Request" && + Path.GetFileNameWithoutExtension(assembly.Location).Contains(x.Namespace.Replace(x.Assembly, ""))).FirstOrDefault(); + if (modelData.NamespaceObject == null) continue; + + outputFileName = Path.Combine(modelData.NamespaceObject.OutFilePath, item.ClassName.Replace("Service", "") + modelData.NamespaceObject.FileNameSuffix); + if (string.IsNullOrEmpty(outputFileName)) continue; + + template = File.ReadAllText(Path.Combine(toolInitConfig.TemplatePath, modelData.NamespaceObject.TemplateFileName)); + if (string.IsNullOrEmpty(template)) continue; + + outputText = RazorEngineHelper.CompiledTemplate(template, modelData); + if (string.IsNullOrEmpty(outputText)) continue; + + if (!Directory.Exists(Path.GetDirectoryName(outputFileName))) Directory.CreateDirectory(Path.GetDirectoryName(outputFileName)); + + File.WriteAllText(outputFileName, outputText); + + + if (!Directory.Exists(Path.GetDirectoryName(logFileName))) Directory.CreateDirectory(Path.GetDirectoryName(logFileName)); + using (StreamWriter w = File.AppendText(logFileName)) + { + w.WriteLine($"[{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}]Succeed:" + outputFileName); + } + //================================ + modelData.NamespaceObject = toolInitConfig.NamespaceObjects.Where(x => x.TemplateType == "TypeScriptService" && x.Assembly == Path.GetFileNameWithoutExtension(assembly.Location)).FirstOrDefault(); + if (modelData.NamespaceObject == null) continue; + + outputFileName = Path.Combine(modelData.NamespaceObject.OutFilePath, item.ClassName.StringToProtectedProerty() + modelData.NamespaceObject.FileNameSuffix); + if (string.IsNullOrEmpty(outputFileName)) continue; + + template = File.ReadAllText(Path.Combine(toolInitConfig.TemplatePath, modelData.NamespaceObject.TemplateFileName)); + if (string.IsNullOrEmpty(template)) continue; + + outputText = RazorEngineHelper.CompiledTemplate(template, modelData); + if (string.IsNullOrEmpty(outputText)) continue; + + if (!Directory.Exists(Path.GetDirectoryName(outputFileName))) Directory.CreateDirectory(Path.GetDirectoryName(outputFileName)); + + File.WriteAllText(outputFileName, outputText); + + + if (!Directory.Exists(Path.GetDirectoryName(logFileName))) Directory.CreateDirectory(Path.GetDirectoryName(logFileName)); + using (StreamWriter w = File.AppendText(logFileName)) + { + w.WriteLine($"[{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}]Succeed:" + outputFileName); + } + } + + + + } + catch (Exception ex) + { + string logFileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "log\\log.txt"); + if (!Directory.Exists(Path.GetDirectoryName(logFileName))) Directory.CreateDirectory(Path.GetDirectoryName(logFileName)); + using (StreamWriter w = File.AppendText(logFileName)) + { + w.WriteLine($"[{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}]Exception:" + ex.Message); + } + } + } +} \ No newline at end of file diff --git a/CodeGenerator/CodeGenerator/Properties/launchSettings.json b/CodeGenerator/CodeGenerator/Properties/launchSettings.json new file mode 100644 index 0000000..fbe2540 --- /dev/null +++ b/CodeGenerator/CodeGenerator/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "CodeGenerator": { + "commandName": "Project", + "commandLineArgs": "D:\\Docker\\CloudBuilder\\CloudBuilder.Security.Service\\bin\\Debug\\net8.0\\CloudBuilder.Security.Service.dll" + } + } +} \ No newline at end of file diff --git a/CodeGenerator/CodeGenerator/appsettings.json b/CodeGenerator/CodeGenerator/appsettings.json new file mode 100644 index 0000000..4c6f112 --- /dev/null +++ b/CodeGenerator/CodeGenerator/appsettings.json @@ -0,0 +1,83 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "CloudBuilder": { + "DbContexts": { + "MasterDbContext": { + "DbContextTypeName": "MasterDbContext", + "ConnectionString": "Server=localhost\\SQLEXPRESS;Database=Furion;User=sa;Password=owen123456;MultipleActiveResultSets=True;TrustServerCertificate=true", + "DatabaseType": "SqlServer", + "LazyLoadingProxiesEnabled": true, + "AuditEntityEnabled": true, + "AutoMigrationEnabled": true + }, + "SecondaryDbContext": { + "DbContextTypeName": "SecondaryDbContext", + "ConnectionString": "Server=localhost\\SQLEXPRESS;Database=Furion_dev;User=sa;Password=owen123456;MultipleActiveResultSets=True;TrustServerCertificate=true", + "DatabaseType": "SqlServer", + "LazyLoadingProxiesEnabled": true, + "AuditEntityEnabled": true, + "AutoMigrationEnabled": true + } + }, + "MailSender": { + "Host": "smtp.mxhichina.com", + "Port": 587, + "EnableSsl": true, + "DisplayName": "OSharp邮件发送", + "UserName": "osharpsender@66soft.net", + "Password": "OSharp147963" + }, + "Jwt": { + "Issuer": "Cloud Builder identity", + "Audience": "Cloud Builder", + "Secret": "{8619F7C3-B53C-4B85-99F0-983D351ECD82}", + "AccessExpireMins": 1440, //1天过期 + "RefreshExpireMins": 10080, // 7天 + "IsRefreshAbsoluteExpired": false + }, + "Redis": { + "Configuration": "localhost", + "InstanceName": "CloudBuilder:" + } + }, + "IpRateLimiting": { + "EnableEndpointRateLimiting": true, //False: globally executed, true: executed for each + "StackBlockedRequests": false, //False: Number of rejections should be recorded on another counter + "RealIpHeader": "X-Real-IP", + "ClientIdHeader": "X-ClientId", + "IpWhitelist": [], //白名单 + "EndpointWhitelist": [], + "ClientWhitelist": [], + "HttpStatusCode": 200, + "QuotaExceededResponse": { + "Content": "{{\"code\":429,\"msg\":\"访问过于频繁,请稍后重试\",\"data\":null}}", + "ContentType": "application/json", + "StatusCode": 200 + }, + "GeneralRules": [ + { + "Endpoint": "*", + "Period": "1s", + "Limit": 5 + }, + { + "Endpoint": "*", + "Period": "1m", + "Limit": 50 + }, + { + "Endpoint": "*", + "Period": "12h", + "Limit": 500 + } + ] + + }, + "AllowedHosts": "*" +} diff --git a/CodeGenerator/Lib/CloudBuilder.Core.dll b/CodeGenerator/Lib/CloudBuilder.Core.dll new file mode 100644 index 0000000..103ab21 Binary files /dev/null and b/CodeGenerator/Lib/CloudBuilder.Core.dll differ diff --git a/CodeGenerator/Templates/Controller.cshtml b/CodeGenerator/Templates/Controller.cshtml new file mode 100644 index 0000000..df6c696 --- /dev/null +++ b/CodeGenerator/Templates/Controller.cshtml @@ -0,0 +1,263 @@ +@{ + ModelData modelData = Model; + NamespaceObject namespaceObject = modelData.NamespaceObject; + SysTableSchemaViewEntity[] sysTableSchemas = modelData.sysTableSchemas; + ClassInfo classInfo= modelData.ClassInfos.FirstOrDefault(); + //ClassInfo classInfo= modelData.ClassInfos.Where(x=>x.ClassName=="SecurityUserService").FirstOrDefault(); +} +using CloudBuilder.Core.DatabaseAccessor; +using CloudBuilder.Core.Policy; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System.Transactions; +using CloudBuilder.Core.Service; +@{ + if(classInfo.Usings!=null && classInfo.Usings.Length>0) + { + for (var i = 0; i < classInfo.Usings.Length; i++) + { + if(classInfo.Usings[i]=="CloudBuilder.Core.Service") continue; + using @classInfo.Usings[i]; + + } + } +} + +namespace @namespaceObject.Namespace +{ +[Authorize(AuthorizePolicy.PERMISSION)] +[ApiController] +[Route("[controller]/[action]")] +public class @{@classInfo.ClassName.Replace("Service", "")}Controller : ControllerBase +{ +private readonly IApplicationService service; +private readonly @{@classInfo.InterfaceName} @classInfo.ClassName.StringToProtectedProerty(); + +public @{@classInfo.ClassName.Replace("Service", "")}Controller(IApplicationService service, @{@classInfo.InterfaceName} @classInfo.ClassName.StringToProtectedProerty()) +{ +this.service = service; +this.@classInfo.ClassName.StringToProtectedProerty()= @classInfo.ClassName.StringToProtectedProerty(); +} + +@{ + if(classInfo.ClassMethodInfos!=null && classInfo.ClassMethodInfos.Length>0 && classInfo.ClassMethodInfos[0].Parameters!=null) + { + for (var j= 0; j< classInfo.ClassMethodInfos.Length; j++) + { + //没有参数的情况======================================= + if(classInfo.ClassMethodInfos[j].Parameters.Length==0) + { + if(classInfo.ClassMethodInfos[j].AuthorizeName!=null) + { + @classInfo.ClassMethodInfos[j].AuthorizeName + + } + if(classInfo.ClassMethodInfos[j].PermissionOperate!=null) + { + @{ @string.Format(classInfo.ClassMethodInfos[j].PermissionOperate,"\""+@classInfo.ClassMethodInfos[j].PermissionOperateAttribute.Name+"\"", "\""+@classInfo.ClassMethodInfos[j].PermissionOperateAttribute.Operate.ToString()+"\"") + } + } + if(classInfo.ClassMethodInfos[j].HttpName!=null) + { + @classInfo.ClassMethodInfos[j].HttpName + + } + if(classInfo.ClassMethodInfos[j].UnitOfWorkName!=null) + { + @classInfo.ClassMethodInfos[j].UnitOfWorkName + + } + if(@classInfo.ClassMethodInfos[j].MethodReturnName=="Void") + { + //文本开始================================================================================================================= + public dynamic @{@classInfo.ClassMethodInfos[j].MethodName}() + { + try + { + + @{ @classInfo.ClassName.StringToProtectedProerty()}.@{@classInfo.ClassMethodInfos[j].MethodName}(); + + return string.Empty; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + + //文本结束================================================================================================================= + } + else + { + //文本开始================================================================================================================= + public dynamic @{@classInfo.ClassMethodInfos[j].MethodName}() + { + try + { + + var result = @{@classInfo.ClassName.StringToProtectedProerty()}.@{@classInfo.ClassMethodInfos[j].MethodName}(); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + + //文本结束================================================================================================================= + } + } + + + //只有1个参数的情况============================================ + if(classInfo.ClassMethodInfos[j].Parameters.Length>0) + { + //超过1个参数的情况,如果是get,不能用组合对象,如果是post,要重新组合一个类======================================== + if(classInfo.ClassMethodInfos[j].Parameters.Length>1 && classInfo.ClassMethodInfos[j].HttpName!="[HttpGet]") + { + + public class @{@classInfo.ClassMethodInfos[j].MethodName}CompositionData + { + + + for (var ik = 0; ik < classInfo.ClassMethodInfos[j].Parameters.Length; ik++){ + string parameterTypeName=classInfo.ClassMethodInfos[j].Parameters[ik].ParameterTypeName; + if(classInfo.ClassMethodInfos[j].Parameters[ik].IsValueType) + { + if(classInfo.ClassMethodInfos[j].Parameters[ik].ParameterTypeName=="String") + parameterTypeName="string"; + if(classInfo.ClassMethodInfos[j].Parameters[ik].ParameterTypeName=="Boolean") + parameterTypeName="bool"; + } + public @parameterTypeName @classInfo.ClassMethodInfos[j].Parameters[ik].ParameterName { get; set; } + + + } + + + } + + } + + if(classInfo.ClassMethodInfos[j].AuthorizeName!=null) + { + @classInfo.ClassMethodInfos[j].AuthorizeName + + } + if(classInfo.ClassMethodInfos[j].PermissionOperate!=null) + { + @{ @string.Format(classInfo.ClassMethodInfos[j].PermissionOperate,"\""+@classInfo.ClassMethodInfos[j].PermissionOperateAttribute.Name+"\"","\""+@classInfo.ClassMethodInfos[j].PermissionOperateAttribute.Operate.ToString()+"\"") + } + } + if(classInfo.ClassMethodInfos[j].HttpName!=null) + { + @classInfo.ClassMethodInfos[j].HttpName + + } + if(classInfo.ClassMethodInfos[j].UnitOfWorkName!=null) + { + @classInfo.ClassMethodInfos[j].UnitOfWorkName + + } + + if(@classInfo.ClassMethodInfos[j].MethodReturnName=="Void") + { + string parametersName=@classInfo.ClassMethodInfos[j].Parameters[0].ParameterTypeName.Replace("String", "string").Replace("Boolean", "bool")+" "+@classInfo.ClassMethodInfos[j].Parameters[0].ParameterName; + if(classInfo.ClassMethodInfos[j].Parameters.Length>1 && classInfo.ClassMethodInfos[j].HttpName!="[HttpGet]") + { + parametersName=@classInfo.ClassMethodInfos[j].MethodName+"CompositionData compositionData"; + } + else if(classInfo.ClassMethodInfos[j].Parameters.Length>1){ + parametersName=string.Empty; + + } + //文本开始================================================ + public dynamic @{@classInfo.ClassMethodInfos[j].MethodName}(@{@parametersName}){ + try + { + @{ @classInfo.ClassName.StringToProtectedProerty()}.@{@classInfo.ClassMethodInfos[j].MethodName}(@{for (var i = 0; i < classInfo.ClassMethodInfos[j].Parameters.Length; i++){ + if(classInfo.ClassMethodInfos[j].Parameters.Length>1){ + if(i>0){,}compositionData.@classInfo.ClassMethodInfos[j].Parameters[i].ParameterName + } + else{ + @classInfo.ClassMethodInfos[j].Parameters[i].ParameterName + } + }}); + + return string.Empty; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + + //文本结束=================================================== + } + else + { + string parametersName=@classInfo.ClassMethodInfos[j].Parameters[0].ParameterTypeName.Replace("String", "string").Replace("Boolean", "bool")+" "+@classInfo.ClassMethodInfos[j].Parameters[0].ParameterName; + if(classInfo.ClassMethodInfos[j].Parameters.Length>1 && classInfo.ClassMethodInfos[j].HttpName!="[HttpGet]") + { + parametersName=@classInfo.ClassMethodInfos[j].MethodName+"CompositionData compositionData"; + } + else if(classInfo.ClassMethodInfos[j].Parameters.Length>1) + { + parametersName=string.Empty; + for (var ikb = 0; ikb < classInfo.ClassMethodInfos[j].Parameters.Length; ikb++){ + if(ikb>0)parametersName+=", "; + parametersName+=@classInfo.ClassMethodInfos[j].Parameters[ikb].ParameterTypeName.Replace("String", "string").Replace("Boolean", "bool")+" "+@classInfo.ClassMethodInfos[j].Parameters[ikb].ParameterName; + } + } + //文本开始================================================ + public dynamic @{@classInfo.ClassMethodInfos[j].MethodName}(@{@parametersName}) + { + try + { + + var result = @{@classInfo.ClassName.StringToProtectedProerty()}.@{@classInfo.ClassMethodInfos[j].MethodName}(@{for (var i = 0; i < classInfo.ClassMethodInfos[j].Parameters.Length; i++){ + if(classInfo.ClassMethodInfos[j].Parameters.Length>1){ + if(i>0){,}if(classInfo.ClassMethodInfos[j].HttpName!="[HttpGet]"){compositionData.}@classInfo.ClassMethodInfos[j].Parameters[i].ParameterName + } + else{ + @classInfo.ClassMethodInfos[j].Parameters[i].ParameterName + } + }}); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + + //文本结束=================================================== + } + } + } + } +//下面}为代码段结束================================================================================================================= +} + +} +} \ No newline at end of file diff --git a/CodeGenerator/Templates/IData.cshtml b/CodeGenerator/Templates/IData.cshtml new file mode 100644 index 0000000..ee58c6f --- /dev/null +++ b/CodeGenerator/Templates/IData.cshtml @@ -0,0 +1,82 @@ +@{ + ModelData modelData = Model; + SysTableSchemaViewEntity[] sysTableSchemas = modelData.sysTableSchemas; + NamespaceObject namespaceObject = modelData.NamespaceObject; +} +using CloudBuilder.Core.DatabaseAccessor.Entity; +using System.ComponentModel.DataAnnotations.Schema; +namespace @namespaceObject.Namespace@{.Data} + + { + [TypeScript] + public class @sysTableSchemas[0].TableName.StringToProerty()DisplayData + @if (@sysTableSchemas[0].Xtype.ToUpper().Trim() == "U") + {} + { + + public @sysTableSchemas[0].TableName.StringToProerty()DisplayData() + { + } + + @for (var i = 0; i < sysTableSchemas.Length; i++) + { + if (@sysTableSchemas[i].FieldName.ToUpper() == "ID") { continue; } + + public @sysTableSchemas[i].TypeOfName@{if(@sysTableSchemas[i].IsNullAble=="y"){?}} @sysTableSchemas[i].FieldName.StringToProerty() { get; set; } + + } + + + public static @sysTableSchemas[0].TableName.StringToProerty()DisplayData GetInstance() + { + return new @sysTableSchemas[0].TableName.StringToProerty()DisplayData(); + } + + public virtual void CopyFrom(@sysTableSchemas[0].TableName.StringToProerty()DisplayData source) + { + CopyFrom(source, true); + } + + public virtual void CopyFrom(@sysTableSchemas[0].TableName.StringToProerty()DisplayData source, bool includeSystemFields) + { + if (source == null) + { + throw new NullReferenceException("Source entity is null."); + } + + @for (var i = 0; i < sysTableSchemas.Length; i++) + { + if (@sysTableSchemas[i].FieldName != "created_datetime" || @sysTableSchemas[i].FieldName != "created_by" + || @sysTableSchemas[i].FieldName != "updated_datetime" || @sysTableSchemas[i].FieldName != "updated_by") + { + this.@sysTableSchemas[i].FieldName.StringToProerty() = source.@sysTableSchemas[i].FieldName.StringToProerty(); + + } + } + + if (includeSystemFields) + { + @for (var i = 0; i < sysTableSchemas.Length; i++) + { + if (@sysTableSchemas[i].FieldName == "created_datetime" || @sysTableSchemas[i].FieldName == "created_by" + || @sysTableSchemas[i].FieldName == "updated_datetime" || @sysTableSchemas[i].FieldName == "updated_by") + { + this.@sysTableSchemas[i].FieldName.StringToProerty() = source.@sysTableSchemas[i].FieldName.StringToProerty(); + + } + + } + } + } + + public @sysTableSchemas[0].TableName.StringToProerty()DisplayData Clone() + { + @sysTableSchemas[0].TableName.StringToProerty()DisplayData result = new @sysTableSchemas[0].TableName.StringToProerty()DisplayData (); + result.CopyFrom(this); + + return result; + } + + } +} + diff --git a/CodeGenerator/Templates/IDisplayData.cshtml b/CodeGenerator/Templates/IDisplayData.cshtml new file mode 100644 index 0000000..a171f2e --- /dev/null +++ b/CodeGenerator/Templates/IDisplayData.cshtml @@ -0,0 +1,31 @@ +@{ + ModelData modelData = Model; + SysTableSchemaViewEntity[] sysTableSchemas = modelData.sysTableSchemas; + NamespaceObject namespaceObject = modelData.NamespaceObject; +} +using CloudBuilder.Core.DatabaseAccessor.Entity; +using System.ComponentModel.DataAnnotations.Schema; +namespace @namespaceObject.Namespace@{.Data} + + { + /// + /// 排除实体类标记 + /// + [NotMapped] + [TypeScript] + public class @sysTableSchemas[0].TableName.StringToProerty()DisplayData:@sysTableSchemas[0].TableName.StringToProerty()Entity + @if (@sysTableSchemas[0].Xtype.ToUpper().Trim() == "U") + {} + { + + public @sysTableSchemas[0].TableName.StringToProerty()DisplayData() + { + } + public @sysTableSchemas[0].TableName.StringToProerty()DisplayData(@sysTableSchemas[0].TableName.StringToProerty()Entity entity) + { + CopyFrom(entity); + } + + } +} + diff --git a/CodeGenerator/Templates/IDto.cshtml b/CodeGenerator/Templates/IDto.cshtml new file mode 100644 index 0000000..b0aa509 --- /dev/null +++ b/CodeGenerator/Templates/IDto.cshtml @@ -0,0 +1,81 @@ +@{ + ModelData modelData = Model; + SysTableSchemaViewEntity[] sysTableSchemas = modelData.sysTableSchemas; + NamespaceObject namespaceObject = modelData.NamespaceObject; +} +using CloudBuilder.Core.DatabaseAccessor.Entity; +using System.ComponentModel.DataAnnotations.Schema; +namespace @namespaceObject.Namespace@{.Data} + + { + public class @sysTableSchemas[0].TableName.StringToProerty()DisplayData + @if (@sysTableSchemas[0].Xtype.ToUpper().Trim() == "U") + {} + { + + public @sysTableSchemas[0].TableName.StringToProerty()DisplayData() + { + } + + @for (var i = 0; i < sysTableSchemas.Length; i++) + { + if (@sysTableSchemas[i].FieldName.ToUpper() == "ID") { continue; } + + public @sysTableSchemas[i].TypeOfName@{if(@sysTableSchemas[i].IsNullAble=="y"){?}} @sysTableSchemas[i].FieldName.StringToProerty() { get; set; } + + } + + + public static @sysTableSchemas[0].TableName.StringToProerty()DisplayData GetInstance() + { + return new @sysTableSchemas[0].TableName.StringToProerty()DisplayData(); + } + + public virtual void CopyFrom(@sysTableSchemas[0].TableName.StringToProerty()DisplayData source) + { + CopyFrom(source, true); + } + + public virtual void CopyFrom(@sysTableSchemas[0].TableName.StringToProerty()DisplayData source, bool includeSystemFields) + { + if (source == null) + { + throw new NullReferenceException("Source entity is null."); + } + + @for (var i = 0; i < sysTableSchemas.Length; i++) + { + if (@sysTableSchemas[i].FieldName != "created_datetime" || @sysTableSchemas[i].FieldName != "created_by" + || @sysTableSchemas[i].FieldName != "updated_datetime" || @sysTableSchemas[i].FieldName != "updated_by") + { + this.@sysTableSchemas[i].FieldName.StringToProerty() = source.@sysTableSchemas[i].FieldName.StringToProerty(); + + } + } + + if (includeSystemFields) + { + @for (var i = 0; i < sysTableSchemas.Length; i++) + { + if (@sysTableSchemas[i].FieldName == "created_datetime" || @sysTableSchemas[i].FieldName == "created_by" + || @sysTableSchemas[i].FieldName == "updated_datetime" || @sysTableSchemas[i].FieldName == "updated_by") + { + this.@sysTableSchemas[i].FieldName.StringToProerty() = source.@sysTableSchemas[i].FieldName.StringToProerty(); + + } + + } + } + } + + public @sysTableSchemas[0].TableName.StringToProerty()DisplayData Clone() + { + @sysTableSchemas[0].TableName.StringToProerty()DisplayData result = new @sysTableSchemas[0].TableName.StringToProerty()DisplayData (); + result.CopyFrom(this); + + return result; + } + + } +} + diff --git a/CodeGenerator/Templates/IEntity.cshtml b/CodeGenerator/Templates/IEntity.cshtml new file mode 100644 index 0000000..690bd77 --- /dev/null +++ b/CodeGenerator/Templates/IEntity.cshtml @@ -0,0 +1,186 @@ +@{ + ModelData modelData = Model; + SysTableSchemaViewEntity[] sysTableSchemas = modelData.sysTableSchemas; + NamespaceObject namespaceObject = modelData.NamespaceObject; +} +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +@{ + string entityBase = string.Format("EntityBase<{0}>", @modelData.KeyType); + if (@modelData.KeyCount > 1) + { + entityBase = string.Format("EntityBase<{0}>", @modelData.KeyType); + } + else if (@sysTableSchemas[0].Xtype.ToUpper().Trim() != "U") + { + entityBase = "ViewEntityBase"; + } +} +namespace @namespaceObject.Namespace@{.Entity} + + { + [TypeScript] + [Table("@sysTableSchemas[0].TableName")] + public class @sysTableSchemas[0].TableName.StringToProerty()Entity : @entityBase + @if (@sysTableSchemas[0].Xtype.ToUpper().Trim() == "U") + {} + { + + public @sysTableSchemas[0].TableName.StringToProerty()Entity() + { + } + + @for (var i = 0; i < sysTableSchemas.Length; i++) + { + if (@sysTableSchemas[i].FieldName.ToUpper() == "ID") { continue; } + if (@sysTableSchemas[i].FieldName.ToUpper() == "ROW_VERSION") + { + [Column("row_version")] + [Timestamp] + public byte[]? RowVersion { get; set; } + + continue; + } + + if (@sysTableSchemas[i].Pk > 0 && @modelData.KeyCount < 2) + { + [Key] + + } + if (@sysTableSchemas[i].IsIdentity > 0) + { + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + + } + if (@sysTableSchemas[i].TypeName == "decimal") + { + [Column("@sysTableSchemas[i].FieldName",TypeName = "@sysTableSchemas[i].TypeName(@sysTableSchemas[i].MaxLength,@sysTableSchemas[i].Scale)")] + + } + else + { + [Column("@sysTableSchemas[i].FieldName")] + + } + if (@sysTableSchemas[i].TypeOfName == "string") + { + public @sysTableSchemas[i].TypeOfName@{if(@sysTableSchemas[i].IsNullAble=="y"){?}} @sysTableSchemas[i].FieldName.StringToProerty() { get; set; } + + } + else + { + public @sysTableSchemas[i].TypeOfName @sysTableSchemas[i].FieldName.StringToProerty() { get; set; } + + } + } + + @for (var i = 0; i < sysTableSchemas.Length; i++) + { + public const string @sysTableSchemas[i].FieldName.ToUpper() = "@sysTableSchemas[i].FieldName.StringToProerty()"; + + } + + public const string DB_NAME_@sysTableSchemas[0].TableName.ToUpper() = "@sysTableSchemas[0].TableName"; + @{ + string fs = ""; + } + @for (var i = 0; i < sysTableSchemas.Length; i++) + { + if (@sysTableSchemas[i].FieldName.ToUpper() == "ID") { continue; } + fs += @sysTableSchemas[i].FieldName + ","; + } + @{ + fs = fs.Substring(0, fs.Length - 1); + } public const string DB_NAME_FIELDS="@(fs)"; + + @for (var i = 0; i < sysTableSchemas.Length; i++) + { + public const string DB_@sysTableSchemas[i].FieldName.ToUpper() = "@sysTableSchemas[i].FieldName"; + + } + + + public static @sysTableSchemas[0].TableName.StringToProerty()Entity GetInstance() + { + return new @sysTableSchemas[0].TableName.StringToProerty()Entity(); + } + + public virtual void CopyFrom(@sysTableSchemas[0].TableName.StringToProerty()Entity source) + { + CopyFrom(source, true); + } + + public virtual void CopyFrom(@sysTableSchemas[0].TableName.StringToProerty()Entity source, bool includeSystemFields) + { + if (source == null) + { + throw new NullReferenceException("Source entity is null."); + } + + @for (var i = 0; i < sysTableSchemas.Length; i++) + { + if (@sysTableSchemas[i].FieldName != "created_datetime" || @sysTableSchemas[i].FieldName != "created_by" + || @sysTableSchemas[i].FieldName != "updated_datetime" || @sysTableSchemas[i].FieldName != "updated_by") + { + this.@sysTableSchemas[i].FieldName.StringToProerty() = source.@sysTableSchemas[i].FieldName.StringToProerty(); + + } + } + + if (includeSystemFields) + { + @for (var i = 0; i < sysTableSchemas.Length; i++) + { + if (@sysTableSchemas[i].FieldName == "created_datetime" || @sysTableSchemas[i].FieldName == "created_by" + || @sysTableSchemas[i].FieldName == "updated_datetime" || @sysTableSchemas[i].FieldName == "updated_by") + { + this.@sysTableSchemas[i].FieldName.StringToProerty() = source.@sysTableSchemas[i].FieldName.StringToProerty(); + + } + + } + } + } + + public override string GetSelectFrom() + { + return $" select {DB_NAME_FIELDS} from { DB_NAME_@sysTableSchemas[0].TableName.ToUpper()} with(nolock) "; + } + + public override string GetSelectCountFrom(string sqlWhere) + { + return $" select count(*) from { DB_NAME_@sysTableSchemas[0].TableName.ToUpper()} with(nolock) where 1=1 {sqlWhere}"; + } + + public override string GetSelectTopFrom(int limit, int start,string orderby,string orderbytag, string sqlWhere) + { + if (string.IsNullOrEmpty(orderbytag) || orderbytag.Trim() != "desc") orderbytag = "asc"; + @for (var i = 0; i < sysTableSchemas.Length; i++) + { + if (@sysTableSchemas[i].Pk > 0) + { + if (string.IsNullOrEmpty(orderby) || !DB_NAME_FIELDS.Contains(orderby)) orderby = DB_@sysTableSchemas[i].FieldName.ToUpper() ; + break; + } + } + + @if(sysTableSchemas.Sum(x=>x.Pk)==0) + { + if (string.IsNullOrEmpty(orderby) || !DB_NAME_FIELDS.Contains(orderby)) orderby = DB_@sysTableSchemas[0].FieldName.ToUpper() ; + } + string top = limit > 0 ? $"top {limit}" : ""; + return $" select {top} {DB_NAME_FIELDS} from (select {DB_NAME_FIELDS} ,row_number() over(order by {orderby} {orderbytag}) as num from { DB_NAME_@sysTableSchemas[0].TableName.ToUpper()} with(nolock) where 1=1 {sqlWhere} ) a where num> {limit * (start - 1)}"; + } + + public @sysTableSchemas[0].TableName.StringToProerty()Entity Clone() + { + @sysTableSchemas[0].TableName.StringToProerty()Entity result = new @sysTableSchemas[0].TableName.StringToProerty()Entity(); + result.CopyFrom(this); + + return result; + } + + } +} diff --git a/CodeGenerator/Templates/IEntityKey.cshtml b/CodeGenerator/Templates/IEntityKey.cshtml new file mode 100644 index 0000000..bb015e3 --- /dev/null +++ b/CodeGenerator/Templates/IEntityKey.cshtml @@ -0,0 +1,72 @@ +@{ + ModelData modelData = Model; + SysTableSchemaViewEntity[] sysTableSchemas = modelData.sysTableSchemas; + NamespaceObject namespaceObject = modelData.NamespaceObject; +} +using CloudBuilder.Core.Authorization; +namespace @namespaceObject.Namespace +{ + [TypeScript] + public class @sysTableSchemas[0].TableName.StringToProerty()EntityKey + { + @for (var i = 0; i < sysTableSchemas.Length; i++) + { + if (@sysTableSchemas[i].Pk > 0) + { + public @sysTableSchemas[i].TypeOfName @sysTableSchemas[i].FieldName.StringToProerty() { get; set; } + + } + } + + public override bool Equals(object obj) + { + if (this == obj) return true; + + @sysTableSchemas[0].TableName.StringToProerty()EntityKey pkey = obj as @sysTableSchemas[0].TableName.StringToProerty()EntityKey; + if (pkey == null) return false; + + @for (var i = 0; i < sysTableSchemas.Length; i++) + { + if (@sysTableSchemas[i].Pk > 0) + { + if (@sysTableSchemas[i].FieldName.StringToProerty() != pkey.@sysTableSchemas[i].FieldName.StringToProerty()) return false; + + } + } + + return true; + } + + + public override string ToString() + { + string declareSql=""; + @{int j = 0;} + @for (var i = 0; i < sysTableSchemas.Length; i++) + { + if (@sysTableSchemas[i].Pk > 0) + { + declareSql=declareSql+$"declare @@__tkey_@sysTableSchemas[i].FieldName.StringToProerty()_@j.ToString() varchar(50) select @@__tkey_@sysTableSchemas[i].FieldName.StringToProerty()_@j.ToString() ='{@sysTableSchemas[i].FieldName.StringToProerty()}'; " ; + j++; + } + } + + return declareSql; + } + } + } + /* @if (modelData.KeyCount > 0) + {builder.Entity<@sysTableSchemas[0].TableName.StringToProerty()Entity>().HasKey(c => new {int k = 0; + for (var i = 0; i < sysTableSchemas.Length; i++) + { + if (@sysTableSchemas[i].Pk > 0) + { + k++; + c.@sysTableSchemas[i].FieldName.StringToProerty()if (modelData.KeyCount != k) + {,} + + } + } + }); +} + */ diff --git a/CodeGenerator/Templates/IService.cshtml b/CodeGenerator/Templates/IService.cshtml new file mode 100644 index 0000000..600c218 --- /dev/null +++ b/CodeGenerator/Templates/IService.cshtml @@ -0,0 +1,17 @@ +@{ + ModelData modelData = Model; + SysTableSchemaViewEntity[] sysTableSchemas = modelData.sysTableSchemas; + NamespaceObject namespaceObject = modelData.NamespaceObject; +} + +using @namespaceObject.Assembly.ToString()@{.Entity}; +using @namespaceObject.Assembly.ToString()@{.SearchCriteria}; +using CloudBuilder.Core.Service; + +namespace @namespaceObject.Assembly.ToString()@{.Service} + +{ + public interface @{I}@sysTableSchemas[0].TableName.StringToProerty()Service :IServiceBase<@sysTableSchemas[0].TableName.StringToProerty()Entity, @modelData.KeyType ,@sysTableSchemas[0].TableName.StringToProerty()SearchCriteria> + { + } +} diff --git a/CodeGenerator/Templates/Permission.auto.cshtml b/CodeGenerator/Templates/Permission.auto.cshtml new file mode 100644 index 0000000..881e11c --- /dev/null +++ b/CodeGenerator/Templates/Permission.auto.cshtml @@ -0,0 +1,15 @@ +@{ + ModelData modelData = Model; + SysTableSchemaViewEntity[] sysTableSchemas = modelData.sysTableSchemas; + NamespaceObject namespaceObject = modelData.NamespaceObject; +} +namespace @namespaceObject.Namespace@{.Policy} + +{ + public partial class @namespaceObject.Assembly.Replace("CloudBuilder.", "").Replace(".", "")PermissionPolicy + { + //***BEGIN*** + public const string @sysTableSchemas[0].TableName.StringToProerty() = "@sysTableSchemas[0].TableName.StringToProerty()"; + //***END*** + } +} \ No newline at end of file diff --git a/CodeGenerator/Templates/Permission.cshtml b/CodeGenerator/Templates/Permission.cshtml new file mode 100644 index 0000000..6c514ca --- /dev/null +++ b/CodeGenerator/Templates/Permission.cshtml @@ -0,0 +1,7 @@ +@{ + ModelData modelData = Model; + SysTableSchemaViewEntity[] sysTableSchemas = modelData.sysTableSchemas; + NamespaceObject namespaceObject = modelData.NamespaceObject; +} +public const string @sysTableSchemas[0].TableName.StringToProerty() = "@sysTableSchemas[0].TableName.StringToProerty()"; + \ No newline at end of file diff --git a/CodeGenerator/Templates/RegistEntity.Key.cshtml b/CodeGenerator/Templates/RegistEntity.Key.cshtml new file mode 100644 index 0000000..de0c952 --- /dev/null +++ b/CodeGenerator/Templates/RegistEntity.Key.cshtml @@ -0,0 +1,26 @@ +@{ + ModelData modelData = Model; + SysTableSchemaViewEntity[] sysTableSchemas = modelData.sysTableSchemas; + NamespaceObject namespaceObject = modelData.NamespaceObject; +} +@if (modelData.KeyCount > 1) +{ +builder.Entity<@sysTableSchemas[0].TableName.StringToProerty()Entity>().HasKey(c => new {int k = 0; + for (var i = 0; i < sysTableSchemas.Length; i++) + { + if (@sysTableSchemas[i].Pk > 0) + { + k++; + c.@sysTableSchemas[i].FieldName.StringToProerty()if (modelData.KeyCount != k) + {,} + + } +} +}); + +} +else @if (modelData.KeyCount == 0) +{ +builder.Entity<@sysTableSchemas[0].TableName.StringToProerty()Entity>(eb => { eb.HasNoKey(); }); + +} \ No newline at end of file diff --git a/CodeGenerator/Templates/RegistEntity.cshtml b/CodeGenerator/Templates/RegistEntity.cshtml new file mode 100644 index 0000000..c0567fd --- /dev/null +++ b/CodeGenerator/Templates/RegistEntity.cshtml @@ -0,0 +1,47 @@ +@{ + ModelData modelData = Model; + SysTableSchemaViewEntity[] sysTableSchemas = modelData.sysTableSchemas; + NamespaceObject namespaceObject = modelData.NamespaceObject; +} +using CloudBuilder.Core.DependencyInjection.EFCore; +using Microsoft.EntityFrameworkCore; +using System.Reflection; + +namespace @namespaceObject.Namespace@{.Entity} + +{ + public class @namespaceObject.Namespace.Replace(".","")RegistEntity : IMasterRegistEntityType + { + /// + ///注入模块内的所有实体类 + /// + /// + public void RegistEntity(ModelBuilder builder) + { + string _assemblyName = Assembly.GetExecutingAssembly().GetName().Name; + //注入所有Entity实体类 + AddEntityType(builder, _assemblyName); + //如果Entity实体类不是单一主键,要单独重写注入 + RegistKeys(builder); + } + + public void AddEntityType(ModelBuilder builder, string _assemblyName) + { + RegistEntityHelper.AddMasterEntityType(builder, _assemblyName); + } + + /// + ///如果存在多个主键的,要在RegistKeys方法注入 + ///builder.Entity().HasKey(c => new { c.TableName, c.FieldName }); + ///builder.Entity(eb => { eb.HasNoKey(); }); + /// + /// + public void RegistKeys(ModelBuilder builder) + { + //***BEGIN*** + + //***END*** + } + } +} + diff --git a/CodeGenerator/Templates/Request.cshtml b/CodeGenerator/Templates/Request.cshtml new file mode 100644 index 0000000..579d38f --- /dev/null +++ b/CodeGenerator/Templates/Request.cshtml @@ -0,0 +1,169 @@ +@{ + ModelData modelData = Model; + NamespaceObject namespaceObject = modelData.NamespaceObject; + SysTableSchemaViewEntity[] sysTableSchemas = modelData.sysTableSchemas; + ClassInfo classInfo= modelData.ClassInfos.FirstOrDefault(); + //ClassInfo classInfo= modelData.ClassInfos.Where(x=>x.ClassName=="SecurityUserService").FirstOrDefault(); +} +using CloudBuilder.Core.DependencyInjection.Request; +using CloudBuilder.Core.Request; +using CloudBuilder.Core.Service; +using Microsoft.Extensions.DependencyInjection; +@{ + if(classInfo.Usings!=null && classInfo.Usings.Length>0) + { + for (var i = 0; i < classInfo.Usings.Length; i++) + { + if(classInfo.Usings[i]=="CloudBuilder.Core.Service") continue; + using @classInfo.Usings[i]; + + } + } +} + +namespace @namespaceObject.Namespace +{ + +public class @{@classInfo.ClassName.Replace("Service", "")}Request : IRequest +{ + +private readonly IServiceRequest serviceRequest; +public @{@classInfo.ClassName.Replace("Service", "")}Request(IServiceRequest serviceRequest) +{ +this.serviceRequest = serviceRequest; +} + +@{ + if(classInfo.ClassMethodInfos!=null && classInfo.ClassMethodInfos.Length>0 && classInfo.ClassMethodInfos[0].Parameters!=null) + { + for (var j= 0; j< classInfo.ClassMethodInfos.Length; j++) + { + string methodReturnName="void "; + if(classInfo.ClassMethodInfos[j].MethodReturnName!="Void") + { + methodReturnName=" "+classInfo.ClassMethodInfos[j].MethodReturnName.Replace("String", "string").Replace("Boolean", "bool")+" "; + } + //没有参数的情况======================================= + if(classInfo.ClassMethodInfos[j].Parameters.Length==0) + { + //文本开始================================================================================================================= + public @{ @methodReturnName @classInfo.ClassMethodInfos[j].MethodName }() + { + @{ + //[HttpGet]一定要有返回值,否则使用[HttpPost] + if(classInfo.ClassMethodInfos[j].HttpName=="[HttpGet]"){ + return Task.Run(() => serviceRequest.GetAsync<@{@classInfo.ClassMethodInfos[j].MethodReturnName.Replace("String", "string").Replace("Boolean", "bool")}>("/@{@classInfo.ClassName.Replace("Service", "")}/@{@classInfo.ClassMethodInfos[j].MethodName}")).GetAwaiter().GetResult(); + } + else{ + //[HttpPost]可以有无返回值 + if(classInfo.ClassMethodInfos[j].MethodReturnName!="Void"){return } Task.Run(() => serviceRequest.@{if(classInfo.ClassMethodInfos[j].MethodReturnName!="Void"){PostAsJsonAsync<@{@classInfo.ClassMethodInfos[j].MethodReturnName.Replace("String", "string").Replace("Boolean", "bool")}> }else{PostAsync}}("/@{@classInfo.ClassName.Replace("Service", "")}/@{@classInfo.ClassMethodInfos[j].MethodName}")).GetAwaiter().GetResult(); + } + } + } + + + //文本结束================================================================================================================= + } + + + //只有1个参数的情况============================================ + if(classInfo.ClassMethodInfos[j].Parameters.Length>0) + { + //超过1个参数的情况,如果是get,不能用组合对象,如果是post,要重新组合一个类======================================== + if(classInfo.ClassMethodInfos[j].Parameters.Length>1 && classInfo.ClassMethodInfos[j].HttpName!="[HttpGet]") + { + + public class @{@classInfo.ClassMethodInfos[j].MethodName}CompositionData@{@classInfo.ClassMethodInfos[j].Parameters.Length} + { + + + for (var ik = 0; ik < classInfo.ClassMethodInfos[j].Parameters.Length; ik++){ + string parameterTypeName=classInfo.ClassMethodInfos[j].Parameters[ik].ParameterTypeName; + if(classInfo.ClassMethodInfos[j].Parameters[ik].IsValueType) + { + if(classInfo.ClassMethodInfos[j].Parameters[ik].ParameterTypeName=="String") + parameterTypeName="string"; + if(classInfo.ClassMethodInfos[j].Parameters[ik].ParameterTypeName=="Boolean") + parameterTypeName="bool"; + } + public @parameterTypeName @classInfo.ClassMethodInfos[j].Parameters[ik].ParameterName { get; set; } + + + } + + + } + + } + + + string parametersName=@classInfo.ClassMethodInfos[j].Parameters[0].ParameterTypeName.Replace("String", "string").Replace("Boolean", "bool")+" "+@classInfo.ClassMethodInfos[j].Parameters[0].ParameterName; + string content=string.Empty; + //如果是[HttpGet],一定是值参数,统一使用组合参数 + if(classInfo.ClassMethodInfos[j].Parameters.Length>0 && classInfo.ClassMethodInfos[j].HttpName=="[HttpGet]") + { + content += "var compositionData = new Dictionary();\t\r"; + + for (var iac = 0; iac < classInfo.ClassMethodInfos[j].Parameters.Length; iac++) + { + content += "compositionData.Add(\"" + @classInfo.ClassMethodInfos[j].Parameters[iac].ParameterName + "\", " + @classInfo.ClassMethodInfos[j].Parameters[iac].ParameterName + ".ToString());\t\r"; + } + content += "return Task.Run(() => serviceRequest.GetWithQueryAsync<"+@classInfo.ClassMethodInfos[j].MethodReturnName.Replace("String", "string").Replace("Boolean", "bool")+">(\"/"+@classInfo.ClassName.Replace("Service", "")+"/"+@classInfo.ClassMethodInfos[j].MethodName+"\", compositionData)).GetAwaiter().GetResult();"; + } + else if(classInfo.ClassMethodInfos[j].Parameters.Length>0 && classInfo.ClassMethodInfos[j].HttpName!="[HttpGet]") + { + string returnValue=string.Empty; + if(classInfo.ClassMethodInfos[j].MethodReturnName!="Void")returnValue="return"; + + if(classInfo.ClassMethodInfos[j].Parameters.Length>1) + { + string CompositionData=classInfo.ClassMethodInfos[j].MethodName+"CompositionData"+classInfo.ClassMethodInfos[j].Parameters.Length; + content += "var compositionData = new "+CompositionData+"{\t\r"; + for (var ikp = 0; ikp < classInfo.ClassMethodInfos[j].Parameters.Length; ikp++) + { + if(ikp>0) content += ",\t\r"; + content += @classInfo.ClassMethodInfos[j].Parameters[ikp].ParameterName+" = "+@classInfo.ClassMethodInfos[j].Parameters[ikp].ParameterName; + } + content += " };\t\r"; + string rv=classInfo.ClassMethodInfos[j].MethodReturnName.Replace("String", "string").Replace("Boolean", "bool").Replace("Void", "dynamic"); + content += returnValue+" Task.Run(() => serviceRequest.PostAsJsonAsync<"+CompositionData+", "+rv+">(\"/"+@classInfo.ClassName.Replace("Service", "")+"/"+@classInfo.ClassMethodInfos[j].MethodName+"\", compositionData)).GetAwaiter().GetResult();"; + } + else + { + string post="PostAsync"; + if(classInfo.ClassMethodInfos[j].MethodReturnName!="Void")post="PostAsJsonAsync"+string.Format("<{1},{0}>",classInfo.ClassMethodInfos[j].MethodReturnName.Replace("String", "string").Replace("Boolean", "bool"),@classInfo.ClassMethodInfos[j].Parameters[0].ParameterTypeName.Replace("String", "string").Replace("Boolean", "bool")); + if(!classInfo.ClassMethodInfos[j].Parameters[0].IsValueType && classInfo.ClassMethodInfos[j].MethodReturnName=="Void")post="PostAsJsonAsync"+string.Format("<{0},dynamic>",@classInfo.ClassMethodInfos[j].Parameters[0].ParameterTypeName.Replace("String", "string").Replace("Boolean", "bool")); + if(classInfo.ClassMethodInfos[j].Parameters[0].IsValueType) + { + if(classInfo.ClassMethodInfos[j].MethodReturnName!="Void"){post="PostAsJsonAsync"+string.Format("<{0}>",classInfo.ClassMethodInfos[j].MethodReturnName.Replace("String", "string").Replace("Boolean", "bool"));} + content += returnValue+" Task.Run(() => serviceRequest."+post+"(\"/"+@classInfo.ClassName.Replace("Service", "")+"/"+@classInfo.ClassMethodInfos[j].MethodName+"?"+@classInfo.ClassMethodInfos[j].Parameters[0].ParameterName+"=\" + "+@classInfo.ClassMethodInfos[j].Parameters[0].ParameterName+".ToString())).GetAwaiter().GetResult();"; + } + else{ + content += returnValue+" Task.Run(() => serviceRequest."+post+"(\"/"+@classInfo.ClassName.Replace("Service", "")+"/"+@classInfo.ClassMethodInfos[j].MethodName+"\" , "+@classInfo.ClassMethodInfos[j].Parameters[0].ParameterName+")).GetAwaiter().GetResult();"; + } + } + + } + + + parametersName=string.Empty; + for (var ikb = 0; ikb < classInfo.ClassMethodInfos[j].Parameters.Length; ikb++){ + if(ikb>0)parametersName+=", "; + parametersName+=@classInfo.ClassMethodInfos[j].Parameters[ikb].ParameterTypeName.Replace("String", "string").Replace("Boolean", "bool")+" "+@classInfo.ClassMethodInfos[j].Parameters[ikb].ParameterName; + } + //文本开始================================================ + public @{@methodReturnName @classInfo.ClassMethodInfos[j].MethodName}(@{@parametersName}) + { + @{@content.ToString()} + } + + + //文本结束=================================================== + } + } + } +//下面}为代码段结束================================================================================================================= +} + +} +} \ No newline at end of file diff --git a/CodeGenerator/Templates/SearchCriteria.cshtml b/CodeGenerator/Templates/SearchCriteria.cshtml new file mode 100644 index 0000000..7ab8c28 --- /dev/null +++ b/CodeGenerator/Templates/SearchCriteria.cshtml @@ -0,0 +1,16 @@ +@{ + ModelData modelData = Model; + SysTableSchemaViewEntity[] sysTableSchemas = modelData.sysTableSchemas; + NamespaceObject namespaceObject = modelData.NamespaceObject; +} +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.Service; +namespace @namespaceObject.Namespace@{.SearchCriteria} + +{ + [TypeScript] + public class @sysTableSchemas[0].TableName.StringToProerty()SearchCriteria: AbstractSearchCriteria + { + + } +} diff --git a/CodeGenerator/Templates/Service.cshtml b/CodeGenerator/Templates/Service.cshtml new file mode 100644 index 0000000..927e70f --- /dev/null +++ b/CodeGenerator/Templates/Service.cshtml @@ -0,0 +1,141 @@ +@{ + ModelData modelData = Model; + SysTableSchemaViewEntity[] sysTableSchemas = modelData.sysTableSchemas; + NamespaceObject namespaceObject = modelData.NamespaceObject; +} +using CloudBuilder.Core.DatabaseAccessor.Entity; +using Microsoft.AspNetCore.Authorization; +using CloudBuilder.Core.DatabaseAccessor; +@{ + using @namespaceObject.Assembly.ToString().Entity; + using @namespaceObject.Assembly.ToString().Policy; + using @namespaceObject.Assembly.ToString().SearchCriteria; +} + +namespace @namespaceObject.Assembly.ToString()@{.Service} + +{ + public class @sysTableSchemas[0].TableName.StringToProerty()Service : I@{@sysTableSchemas[0].TableName.StringToProerty()}Service + { + private readonly IApplicationService service; + + private IRepository<@{@sysTableSchemas[0].TableName.StringToProerty()}Entity> repository; + public @{@sysTableSchemas[0].TableName.StringToProerty()}Service(IApplicationService service) + { + this.service = service; + repository = service.GetRepository>(); + } + @if (@modelData.KeyCount < 2) + { + @for (var i = 0; i < sysTableSchemas.Length; i++) + { + if (@sysTableSchemas[i].FieldName.ToUpper() == "ID") { continue; } + + if (@sysTableSchemas[i].Pk > 0 && @modelData.KeyCount < 2) + { + + [PermissionOperate(name: @namespaceObject.Assembly.ToString().Replace(".Service", "").Replace("CloudBuilder.", "").Replace(".", "")PermissionPolicy.@{@sysTableSchemas[0].TableName.StringToProerty()}, operate: Operate.Find)] + public @{@sysTableSchemas[0].TableName.StringToProerty()}Entity FindByKey(@modelData.KeyType key) + { + return repository.DetachedEntities.Where(x => x.@{ @sysTableSchemas[i].FieldName.StringToProerty()} == key).FirstOrDefault()!; + } + + } + } + } + else if (@modelData.KeyCount > 1) + { + + [PermissionOperate(name: @namespaceObject.Assembly.ToString().Replace(".Service", "").Replace("CloudBuilder.", "").Replace(".", "")PermissionPolicy.@{@sysTableSchemas[0].TableName.StringToProerty()}, operate: Operate.Find)] + public @{@sysTableSchemas[0].TableName.StringToProerty()}Entity FindByKey(@{@sysTableSchemas[0].TableName.StringToProerty()}EntityKey key) + { + return repository.DetachedEntities.Where(x => 1==1 + @for (var i = 0; i < sysTableSchemas.Length; i++) + { + if (@sysTableSchemas[i].FieldName.ToUpper() == "ID") { continue; } + + if (@sysTableSchemas[i].Pk > 0) + { + + && x.@{ @sysTableSchemas[i].FieldName.StringToProerty()} == key.@{ @sysTableSchemas[i].FieldName.StringToProerty()} + + } + } + + ).FirstOrDefault()!; + } + + } + + //[PermissionOperate(name: @namespaceObject.Assembly.ToString().Replace(".Service", "").Replace("CloudBuilder.", "").Replace(".", "")PermissionPolicy.@{@sysTableSchemas[0].TableName.StringToProerty()}, operate: Operate.Find)] + public dynamic FindBySearchCriteria(@{@sysTableSchemas[0].TableName.StringToProerty()}SearchCriteria criteria) + { + throw new NotImplementedException(); + } + + //[PermissionOperate(name: @namespaceObject.Assembly.ToString().Replace(".Service", "").Replace("CloudBuilder.", "").Replace(".", "")PermissionPolicy.@{@sysTableSchemas[0].TableName.StringToProerty()}, operate: Operate.Print)] + public dynamic PrintBySearchCriteria(@{@sysTableSchemas[0].TableName.StringToProerty()}SearchCriteria criteria) + { + throw new NotImplementedException(); + } + + [PermissionOperate(name: @namespaceObject.Assembly.ToString().Replace(".Service", "").Replace("CloudBuilder.", "").Replace(".", "")PermissionPolicy.@{@sysTableSchemas[0].TableName.StringToProerty()}, operate: Operate.Insert)] + [UnitOfWork] + public @{@sysTableSchemas[0].TableName.StringToProerty()}Entity Insert(@{@sysTableSchemas[0].TableName.StringToProerty()}Entity data) + { + throw new NotImplementedException(); + } + + [PermissionOperate(name: @namespaceObject.Assembly.ToString().Replace(".Service", "").Replace("CloudBuilder.", "").Replace(".", "")PermissionPolicy.@{@sysTableSchemas[0].TableName.StringToProerty()}, operate: Operate.Update)] + [UnitOfWork] + public @{@sysTableSchemas[0].TableName.StringToProerty()}Entity Update(@{@sysTableSchemas[0].TableName.StringToProerty()}Entity data) + { + throw new NotImplementedException(); + } + + @if (@modelData.KeyCount < 2) + { + @for (var i = 0; i < sysTableSchemas.Length; i++) + { + if (@sysTableSchemas[i].FieldName.ToUpper() == "ID") { continue; } + + if (@sysTableSchemas[i].Pk > 0 && @modelData.KeyCount < 2) + { + + [PermissionOperate(name: @namespaceObject.Assembly.ToString().Replace(".Service", "").Replace("CloudBuilder.", "").Replace(".", "")PermissionPolicy.@{@sysTableSchemas[0].TableName.StringToProerty()}, operate: Operate.Delete)] + [UnitOfWork] + public void Delete(@modelData.KeyType key) + { + var ent= repository.DetachedEntities.Where(x => x.@{ @sysTableSchemas[i].FieldName.StringToProerty()} == key).FirstOrDefault()!; + if (ent != null) { repository.DeleteNow(ent); } + } + + } + } + } + else if (@modelData.KeyCount > 1) + { + + [PermissionOperate(name: @namespaceObject.Assembly.ToString().Replace(".Service", "").Replace("CloudBuilder.", "").Replace(".", "")PermissionPolicy.@{@sysTableSchemas[0].TableName.StringToProerty()}, operate: Operate.Delete)] + public void Delete(@{@sysTableSchemas[0].TableName.StringToProerty()}EntityKey key) + { + @sysTableSchemas[0].TableName.StringToProerty()Entity ent = repository.DetachedEntities.Where(x => 1==1 + @for (var i = 0; i < sysTableSchemas.Length; i++) + { + if (@sysTableSchemas[i].FieldName.ToUpper() == "ID") { continue; } + + if (@sysTableSchemas[i].Pk > 0) + { + + && x.@{ @sysTableSchemas[i].FieldName.StringToProerty()} == key.@{ @sysTableSchemas[i].FieldName.StringToProerty()} + + } + } + + ).FirstOrDefault()!; + if (ent != null) { repository.DeleteNow(ent); } + } + + } + } +} diff --git a/CodeGenerator/Templates/TypeScript.cshtml b/CodeGenerator/Templates/TypeScript.cshtml new file mode 100644 index 0000000..8a5af3c --- /dev/null +++ b/CodeGenerator/Templates/TypeScript.cshtml @@ -0,0 +1,115 @@ +@{ + ModelData modelData = Model; + NamespaceObject namespaceObject = modelData.NamespaceObject; + SysTableSchemaViewEntity[] sysTableSchemas = modelData.sysTableSchemas; + ClassInfo classInfo= modelData.ClassInfos.FirstOrDefault(); + //ClassInfo classInfo= modelData.ClassInfos.Where(x=>x.ClassName=="SecurityUserSearchCriteria").FirstOrDefault(); +} +@{ + if(classInfo.Usings!=null && classInfo.Usings.Length>0) + { + for (var i = 0; i < classInfo.Usings.Length; i++) + { + import { @classInfo.Usings[i].StringToProerty() } from "./@classInfo.Usings[i].StringToProtectedProerty()"; + + } + } +} +@{ + string implementTypeName=string.IsNullOrEmpty(classInfo.ImplementTypeName)?"":" extends "+classInfo.ImplementTypeName; + if(!string.IsNullOrEmpty(implementTypeName)) + { + import { @classInfo.ImplementTypeName.StringToProerty() } from "./@classInfo.ImplementTypeName.StringToProtectedProerty()"; + + } +} +export class @classInfo.ClassName @implementTypeName +{ +@{ + if(classInfo.ClassProperties!=null && classInfo.ClassProperties.Length>0) + { + for (var j= 0; j< classInfo.ClassProperties.Length; j++) + { + if(classInfo.ClassProperties[j].PropertyTypeName=="Nullable`1") + { + public @classInfo.ClassProperties[j].PropertyName?: Date= null!; + + } + else if(classInfo.ClassProperties[j].PropertyTypeName.ToLower()=="datetime") + { + public @classInfo.ClassProperties[j].PropertyName: Date = new Date(); + + } + else if(classInfo.ClassProperties[j].PropertyTypeName=="Boolean") + { + public @classInfo.ClassProperties[j].PropertyName: boolean =false; + + } + else if(classInfo.ClassProperties[j].PropertyTypeName=="String") + { + public @classInfo.ClassProperties[j].PropertyName: string = ""; + + } + else if(classInfo.ClassProperties[j].PropertyTypeName=="Int32" || classInfo.ClassProperties[j].PropertyTypeName=="Int64" || classInfo.ClassProperties[j].PropertyTypeName=="Int16" || classInfo.ClassProperties[j].PropertyTypeName=="Long" || classInfo.ClassProperties[j].PropertyTypeName.ToLower()=="decimal") + { + public @classInfo.ClassProperties[j].PropertyName: number = 0; + + } + else if(classInfo.ClassProperties[j].PropertyTypeName=="Int32[]" || classInfo.ClassProperties[j].PropertyTypeName=="Int64[]" || classInfo.ClassProperties[j].PropertyTypeName=="Int16[]" || classInfo.ClassProperties[j].PropertyTypeName=="Long[]" || classInfo.ClassProperties[j].PropertyTypeName.ToLower()=="decimal[]") + { + public @classInfo.ClassProperties[j].PropertyName: number[] = []; + + } + else if(classInfo.ClassProperties[j].PropertyTypeName.Contains("String[]")) + { + public @classInfo.ClassProperties[j].PropertyName: string[]= []; + + } + else if(!classInfo.ClassProperties[j].IsValueType && classInfo.ClassProperties[j].PropertyTypeName.Contains("[]")) + { + public @classInfo.ClassProperties[j].PropertyName: @classInfo.ClassProperties[j].PropertyTypeName.StringToProerty() = []; + + } + else if(classInfo.ClassProperties[j].PropertyTypeName=="any") + { + public @classInfo.ClassProperties[j].PropertyName: any; + + } + else if(!classInfo.ClassProperties[j].IsValueType) + { + public @classInfo.ClassProperties[j].PropertyName: @classInfo.ClassProperties[j].PropertyTypeName.StringToProerty() = new @{@classInfo.ClassProperties[j].PropertyTypeName.StringToProerty() }(); + + } + else + { + public @classInfo.ClassProperties[j].PropertyName: any ={} + + } + } + } + } + +@{ + if(classInfo.ClassFields!=null && classInfo.ClassFields.Length>0) + { + for (var j= 0; j< classInfo.ClassFields.Length; j++) + { + if(classInfo.ClassFields[j].FieldTypeName =="String") + { + static readonly @classInfo.ClassFields[j].FieldName : string ='@classInfo.ClassFields[j].FieldValue'; + + } + if(classInfo.ClassFields[j].FieldTypeName =="Boolean") + { + static readonly @classInfo.ClassFields[j].FieldName : Boolean ='@classInfo.ClassFields[j].FieldValue'; + + } + else if(classInfo.ClassFields[j].FieldTypeName =="Int32" || classInfo.ClassFields[j].FieldTypeName =="Int64" || classInfo.ClassFields[j].FieldTypeName =="Int16" || classInfo.ClassFields[j].FieldTypeName =="Long" || classInfo.ClassFields[j].FieldTypeName .ToLower()=="decimal") + { + static readonly @classInfo.ClassFields[j].FieldName: number =@classInfo.ClassFields[j].FieldValue; + + } + } + } + } +} diff --git a/CodeGenerator/Templates/TypeScriptService.cshtml b/CodeGenerator/Templates/TypeScriptService.cshtml new file mode 100644 index 0000000..8c244b8 --- /dev/null +++ b/CodeGenerator/Templates/TypeScriptService.cshtml @@ -0,0 +1,147 @@ +@{ + ModelData modelData = Model; + NamespaceObject namespaceObject = modelData.NamespaceObject; + SysTableSchemaViewEntity[] sysTableSchemas = modelData.sysTableSchemas; + ClassInfo classInfo= modelData.ClassInfos.FirstOrDefault(); + //ClassInfo classInfo= modelData.ClassInfos.Where(x=>x.ClassName=="SecurityUserService").FirstOrDefault(); +} +@if(classInfo.IsDownload) +{ + import { request,download } from "@@/utils/request"; + +} +else +{ + import { request } from "@@/utils/request"; + +} +@{ +List l=new List(); +if(classInfo.ClassMethodInfos!=null && classInfo.ClassMethodInfos.Length>0 && classInfo.ClassMethodInfos[0].Parameters!=null) +{ + for (var j= 0; j< classInfo.ClassMethodInfos.Length; j++) + { + for (var i = 0; i < classInfo.ClassMethodInfos[j].Parameters.Length; i++) + { + if(!classInfo.ClassMethodInfos[j].Parameters[i].IsValueType) + { + if (!l.Contains(classInfo.ClassMethodInfos[j].Parameters[i].ParameterTypeName.Replace("[]", ""))) + { + l.Add(classInfo.ClassMethodInfos[j].Parameters[i].ParameterTypeName.Replace("[]", "")); + } + } + } + if("dynamic" !=classInfo.ClassMethodInfos[j].MethodReturnName) + { + if(classInfo.ClassMethodInfos[j].IsValueType) continue; + if (l.Contains(classInfo.ClassMethodInfos[j].MethodReturnName.Replace("[]", ""))) continue; + l.Add(classInfo.ClassMethodInfos[j].MethodReturnName.Replace("[]", "")); + } + } + } + foreach (string s in l) + { + if(s.StringToProtectedProerty()=="string") continue; + if(s.StringToProtectedProerty()=="byte") continue; + import type { @s } from "@@/data/auto/@s.StringToProtectedProerty()"; + + + } + +} + +class @{@classInfo.ClassName}{ +@{ + +if(classInfo.ClassMethodInfos!=null && classInfo.ClassMethodInfos.Length>0 && classInfo.ClassMethodInfos[0].Parameters!=null) +{ + for (var j= 0; j< classInfo.ClassMethodInfos.Length; j++) + { + string methodReturnName=classInfo.ClassMethodInfos[j].MethodReturnName; + if(classInfo.ClassMethodInfos[j].IsValueType) + { + if(classInfo.ClassMethodInfos[j].MethodReturnName=="String") + methodReturnName="string"; + else if(classInfo.ClassMethodInfos[j].MethodReturnName=="Int32" || classInfo.ClassMethodInfos[j].MethodReturnName=="Int64" || classInfo.ClassMethodInfos[j].MethodReturnName=="Int16" || classInfo.ClassMethodInfos[j].MethodReturnName=="Long" || classInfo.ClassMethodInfos[j].MethodReturnName=="decimal" ) + methodReturnName="number"; + else if(classInfo.ClassMethodInfos[j].MethodReturnName=="String[]") + methodReturnName="string[]"; + else if(classInfo.ClassMethodInfos[j].MethodReturnName=="Int32[]" || classInfo.ClassMethodInfos[j].MethodReturnName=="Int64[]" || classInfo.ClassMethodInfos[j].MethodReturnName=="Int16[]" || classInfo.ClassMethodInfos[j].MethodReturnName=="Long[]" || classInfo.ClassMethodInfos[j].MethodReturnName=="decimal[]" ) + methodReturnName="number[]"; + else methodReturnName="any"; + } + + if(classInfo.ClassMethodInfos[j].Parameters.Length==0) + { + + async @{@classInfo.ClassMethodInfos[j].MethodName}() { + return request<@methodReturnName.Replace("dynamic", "any")>( + { + url: "/@{@classInfo.ClassName.Replace("Service", "")}/@{@classInfo.ClassMethodInfos[j].MethodName}", + method: "@{if(classInfo.ClassMethodInfos[j].HttpName!="[HttpGet]"){post}else{get} }", + } + ) + }; + + } + + + for (var i = 0; i < classInfo.ClassMethodInfos[j].Parameters.Length; i++) + { + string parameterTypeName=classInfo.ClassMethodInfos[j].Parameters[i].ParameterTypeName; + string url="\""; + if(classInfo.ClassMethodInfos[j].Parameters[i].IsValueType) + { + url="?"+classInfo.ClassMethodInfos[j].Parameters[i].ParameterName+"=\"+data"; + if(classInfo.ClassMethodInfos[j].Parameters[i].ParameterTypeName=="String") + parameterTypeName="string"; + else if(classInfo.ClassMethodInfos[j].Parameters[i].ParameterTypeName=="Int32" || classInfo.ClassMethodInfos[j].Parameters[i].ParameterTypeName=="Int64" || classInfo.ClassMethodInfos[j].Parameters[i].ParameterTypeName=="Int16" || classInfo.ClassMethodInfos[j].Parameters[i].ParameterTypeName=="Long" || classInfo.ClassMethodInfos[j].Parameters[i].ParameterTypeName=="decimal" ) + parameterTypeName="number"; + else if(classInfo.ClassMethodInfos[j].Parameters[i].ParameterTypeName=="String[]") + parameterTypeName="string[]"; + else if(classInfo.ClassMethodInfos[j].Parameters[i].ParameterTypeName=="Int32[]" || classInfo.ClassMethodInfos[j].Parameters[i].ParameterTypeName=="Int64[]" || classInfo.ClassMethodInfos[j].Parameters[i].ParameterTypeName=="Int16[]" || classInfo.ClassMethodInfos[j].Parameters[i].ParameterTypeName=="Long[]" || classInfo.ClassMethodInfos[j].Parameters[i].ParameterTypeName=="decimal[]" ) + parameterTypeName="number[]"; + else parameterTypeName="any"; + } + if(classInfo.ClassMethodInfos[j].Parameters.Length>1) {url="\"";parameterTypeName="any";} + if(i>0) {continue;} + + + async @{@classInfo.ClassMethodInfos[j].MethodName}(data: @parameterTypeName) { + @{ + bool isPrintBy=false; + bool isDownloadFile=false; + if(classInfo.ClassMethodInfos[j].MethodName.StartsWith("PrintBy")) + { + isPrintBy=true; + } + if(classInfo.ClassMethodInfos[j].MethodName.StartsWith("DownloadFile")) + { + isDownloadFile=true; + } + + } + return @{if(isPrintBy){download}else{ request<@{@methodReturnName.Replace("dynamic", "any")}>}}( + { + url: "/@{@classInfo.ClassName.Replace("Service", "")}/@{@classInfo.ClassMethodInfos[j].MethodName}@url, + method: "@{if(classInfo.ClassMethodInfos[j].HttpName!="[HttpGet]"){post}else{get} }", + data, + @{if(isDownloadFile){ responseType: "arraybuffer", + }else{ } + } + @{if(isPrintBy){ filename:'@classInfo.ClassName.Replace("Service","")' + }else{ } + } + } + ) + }; + + } + } + } +} + +} + +const @{@classInfo.ClassName.StringToProtectedProerty()}= new @{@classInfo.ClassName}(); +export default @{@classInfo.ClassName.StringToProtectedProerty()}; \ No newline at end of file diff --git a/Templates/Controller.cshtml b/Templates/Controller.cshtml new file mode 100644 index 0000000..df6c696 --- /dev/null +++ b/Templates/Controller.cshtml @@ -0,0 +1,263 @@ +@{ + ModelData modelData = Model; + NamespaceObject namespaceObject = modelData.NamespaceObject; + SysTableSchemaViewEntity[] sysTableSchemas = modelData.sysTableSchemas; + ClassInfo classInfo= modelData.ClassInfos.FirstOrDefault(); + //ClassInfo classInfo= modelData.ClassInfos.Where(x=>x.ClassName=="SecurityUserService").FirstOrDefault(); +} +using CloudBuilder.Core.DatabaseAccessor; +using CloudBuilder.Core.Policy; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System.Transactions; +using CloudBuilder.Core.Service; +@{ + if(classInfo.Usings!=null && classInfo.Usings.Length>0) + { + for (var i = 0; i < classInfo.Usings.Length; i++) + { + if(classInfo.Usings[i]=="CloudBuilder.Core.Service") continue; + using @classInfo.Usings[i]; + + } + } +} + +namespace @namespaceObject.Namespace +{ +[Authorize(AuthorizePolicy.PERMISSION)] +[ApiController] +[Route("[controller]/[action]")] +public class @{@classInfo.ClassName.Replace("Service", "")}Controller : ControllerBase +{ +private readonly IApplicationService service; +private readonly @{@classInfo.InterfaceName} @classInfo.ClassName.StringToProtectedProerty(); + +public @{@classInfo.ClassName.Replace("Service", "")}Controller(IApplicationService service, @{@classInfo.InterfaceName} @classInfo.ClassName.StringToProtectedProerty()) +{ +this.service = service; +this.@classInfo.ClassName.StringToProtectedProerty()= @classInfo.ClassName.StringToProtectedProerty(); +} + +@{ + if(classInfo.ClassMethodInfos!=null && classInfo.ClassMethodInfos.Length>0 && classInfo.ClassMethodInfos[0].Parameters!=null) + { + for (var j= 0; j< classInfo.ClassMethodInfos.Length; j++) + { + //没有参数的情况======================================= + if(classInfo.ClassMethodInfos[j].Parameters.Length==0) + { + if(classInfo.ClassMethodInfos[j].AuthorizeName!=null) + { + @classInfo.ClassMethodInfos[j].AuthorizeName + + } + if(classInfo.ClassMethodInfos[j].PermissionOperate!=null) + { + @{ @string.Format(classInfo.ClassMethodInfos[j].PermissionOperate,"\""+@classInfo.ClassMethodInfos[j].PermissionOperateAttribute.Name+"\"", "\""+@classInfo.ClassMethodInfos[j].PermissionOperateAttribute.Operate.ToString()+"\"") + } + } + if(classInfo.ClassMethodInfos[j].HttpName!=null) + { + @classInfo.ClassMethodInfos[j].HttpName + + } + if(classInfo.ClassMethodInfos[j].UnitOfWorkName!=null) + { + @classInfo.ClassMethodInfos[j].UnitOfWorkName + + } + if(@classInfo.ClassMethodInfos[j].MethodReturnName=="Void") + { + //文本开始================================================================================================================= + public dynamic @{@classInfo.ClassMethodInfos[j].MethodName}() + { + try + { + + @{ @classInfo.ClassName.StringToProtectedProerty()}.@{@classInfo.ClassMethodInfos[j].MethodName}(); + + return string.Empty; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + + //文本结束================================================================================================================= + } + else + { + //文本开始================================================================================================================= + public dynamic @{@classInfo.ClassMethodInfos[j].MethodName}() + { + try + { + + var result = @{@classInfo.ClassName.StringToProtectedProerty()}.@{@classInfo.ClassMethodInfos[j].MethodName}(); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + + //文本结束================================================================================================================= + } + } + + + //只有1个参数的情况============================================ + if(classInfo.ClassMethodInfos[j].Parameters.Length>0) + { + //超过1个参数的情况,如果是get,不能用组合对象,如果是post,要重新组合一个类======================================== + if(classInfo.ClassMethodInfos[j].Parameters.Length>1 && classInfo.ClassMethodInfos[j].HttpName!="[HttpGet]") + { + + public class @{@classInfo.ClassMethodInfos[j].MethodName}CompositionData + { + + + for (var ik = 0; ik < classInfo.ClassMethodInfos[j].Parameters.Length; ik++){ + string parameterTypeName=classInfo.ClassMethodInfos[j].Parameters[ik].ParameterTypeName; + if(classInfo.ClassMethodInfos[j].Parameters[ik].IsValueType) + { + if(classInfo.ClassMethodInfos[j].Parameters[ik].ParameterTypeName=="String") + parameterTypeName="string"; + if(classInfo.ClassMethodInfos[j].Parameters[ik].ParameterTypeName=="Boolean") + parameterTypeName="bool"; + } + public @parameterTypeName @classInfo.ClassMethodInfos[j].Parameters[ik].ParameterName { get; set; } + + + } + + + } + + } + + if(classInfo.ClassMethodInfos[j].AuthorizeName!=null) + { + @classInfo.ClassMethodInfos[j].AuthorizeName + + } + if(classInfo.ClassMethodInfos[j].PermissionOperate!=null) + { + @{ @string.Format(classInfo.ClassMethodInfos[j].PermissionOperate,"\""+@classInfo.ClassMethodInfos[j].PermissionOperateAttribute.Name+"\"","\""+@classInfo.ClassMethodInfos[j].PermissionOperateAttribute.Operate.ToString()+"\"") + } + } + if(classInfo.ClassMethodInfos[j].HttpName!=null) + { + @classInfo.ClassMethodInfos[j].HttpName + + } + if(classInfo.ClassMethodInfos[j].UnitOfWorkName!=null) + { + @classInfo.ClassMethodInfos[j].UnitOfWorkName + + } + + if(@classInfo.ClassMethodInfos[j].MethodReturnName=="Void") + { + string parametersName=@classInfo.ClassMethodInfos[j].Parameters[0].ParameterTypeName.Replace("String", "string").Replace("Boolean", "bool")+" "+@classInfo.ClassMethodInfos[j].Parameters[0].ParameterName; + if(classInfo.ClassMethodInfos[j].Parameters.Length>1 && classInfo.ClassMethodInfos[j].HttpName!="[HttpGet]") + { + parametersName=@classInfo.ClassMethodInfos[j].MethodName+"CompositionData compositionData"; + } + else if(classInfo.ClassMethodInfos[j].Parameters.Length>1){ + parametersName=string.Empty; + + } + //文本开始================================================ + public dynamic @{@classInfo.ClassMethodInfos[j].MethodName}(@{@parametersName}){ + try + { + @{ @classInfo.ClassName.StringToProtectedProerty()}.@{@classInfo.ClassMethodInfos[j].MethodName}(@{for (var i = 0; i < classInfo.ClassMethodInfos[j].Parameters.Length; i++){ + if(classInfo.ClassMethodInfos[j].Parameters.Length>1){ + if(i>0){,}compositionData.@classInfo.ClassMethodInfos[j].Parameters[i].ParameterName + } + else{ + @classInfo.ClassMethodInfos[j].Parameters[i].ParameterName + } + }}); + + return string.Empty; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + + //文本结束=================================================== + } + else + { + string parametersName=@classInfo.ClassMethodInfos[j].Parameters[0].ParameterTypeName.Replace("String", "string").Replace("Boolean", "bool")+" "+@classInfo.ClassMethodInfos[j].Parameters[0].ParameterName; + if(classInfo.ClassMethodInfos[j].Parameters.Length>1 && classInfo.ClassMethodInfos[j].HttpName!="[HttpGet]") + { + parametersName=@classInfo.ClassMethodInfos[j].MethodName+"CompositionData compositionData"; + } + else if(classInfo.ClassMethodInfos[j].Parameters.Length>1) + { + parametersName=string.Empty; + for (var ikb = 0; ikb < classInfo.ClassMethodInfos[j].Parameters.Length; ikb++){ + if(ikb>0)parametersName+=", "; + parametersName+=@classInfo.ClassMethodInfos[j].Parameters[ikb].ParameterTypeName.Replace("String", "string").Replace("Boolean", "bool")+" "+@classInfo.ClassMethodInfos[j].Parameters[ikb].ParameterName; + } + } + //文本开始================================================ + public dynamic @{@classInfo.ClassMethodInfos[j].MethodName}(@{@parametersName}) + { + try + { + + var result = @{@classInfo.ClassName.StringToProtectedProerty()}.@{@classInfo.ClassMethodInfos[j].MethodName}(@{for (var i = 0; i < classInfo.ClassMethodInfos[j].Parameters.Length; i++){ + if(classInfo.ClassMethodInfos[j].Parameters.Length>1){ + if(i>0){,}if(classInfo.ClassMethodInfos[j].HttpName!="[HttpGet]"){compositionData.}@classInfo.ClassMethodInfos[j].Parameters[i].ParameterName + } + else{ + @classInfo.ClassMethodInfos[j].Parameters[i].ParameterName + } + }}); + return result; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + + //文本结束=================================================== + } + } + } + } +//下面}为代码段结束================================================================================================================= +} + +} +} \ No newline at end of file diff --git a/Templates/IData.cshtml b/Templates/IData.cshtml new file mode 100644 index 0000000..ee58c6f --- /dev/null +++ b/Templates/IData.cshtml @@ -0,0 +1,82 @@ +@{ + ModelData modelData = Model; + SysTableSchemaViewEntity[] sysTableSchemas = modelData.sysTableSchemas; + NamespaceObject namespaceObject = modelData.NamespaceObject; +} +using CloudBuilder.Core.DatabaseAccessor.Entity; +using System.ComponentModel.DataAnnotations.Schema; +namespace @namespaceObject.Namespace@{.Data} + + { + [TypeScript] + public class @sysTableSchemas[0].TableName.StringToProerty()DisplayData + @if (@sysTableSchemas[0].Xtype.ToUpper().Trim() == "U") + {} + { + + public @sysTableSchemas[0].TableName.StringToProerty()DisplayData() + { + } + + @for (var i = 0; i < sysTableSchemas.Length; i++) + { + if (@sysTableSchemas[i].FieldName.ToUpper() == "ID") { continue; } + + public @sysTableSchemas[i].TypeOfName@{if(@sysTableSchemas[i].IsNullAble=="y"){?}} @sysTableSchemas[i].FieldName.StringToProerty() { get; set; } + + } + + + public static @sysTableSchemas[0].TableName.StringToProerty()DisplayData GetInstance() + { + return new @sysTableSchemas[0].TableName.StringToProerty()DisplayData(); + } + + public virtual void CopyFrom(@sysTableSchemas[0].TableName.StringToProerty()DisplayData source) + { + CopyFrom(source, true); + } + + public virtual void CopyFrom(@sysTableSchemas[0].TableName.StringToProerty()DisplayData source, bool includeSystemFields) + { + if (source == null) + { + throw new NullReferenceException("Source entity is null."); + } + + @for (var i = 0; i < sysTableSchemas.Length; i++) + { + if (@sysTableSchemas[i].FieldName != "created_datetime" || @sysTableSchemas[i].FieldName != "created_by" + || @sysTableSchemas[i].FieldName != "updated_datetime" || @sysTableSchemas[i].FieldName != "updated_by") + { + this.@sysTableSchemas[i].FieldName.StringToProerty() = source.@sysTableSchemas[i].FieldName.StringToProerty(); + + } + } + + if (includeSystemFields) + { + @for (var i = 0; i < sysTableSchemas.Length; i++) + { + if (@sysTableSchemas[i].FieldName == "created_datetime" || @sysTableSchemas[i].FieldName == "created_by" + || @sysTableSchemas[i].FieldName == "updated_datetime" || @sysTableSchemas[i].FieldName == "updated_by") + { + this.@sysTableSchemas[i].FieldName.StringToProerty() = source.@sysTableSchemas[i].FieldName.StringToProerty(); + + } + + } + } + } + + public @sysTableSchemas[0].TableName.StringToProerty()DisplayData Clone() + { + @sysTableSchemas[0].TableName.StringToProerty()DisplayData result = new @sysTableSchemas[0].TableName.StringToProerty()DisplayData (); + result.CopyFrom(this); + + return result; + } + + } +} + diff --git a/Templates/IDisplayData.cshtml b/Templates/IDisplayData.cshtml new file mode 100644 index 0000000..a171f2e --- /dev/null +++ b/Templates/IDisplayData.cshtml @@ -0,0 +1,31 @@ +@{ + ModelData modelData = Model; + SysTableSchemaViewEntity[] sysTableSchemas = modelData.sysTableSchemas; + NamespaceObject namespaceObject = modelData.NamespaceObject; +} +using CloudBuilder.Core.DatabaseAccessor.Entity; +using System.ComponentModel.DataAnnotations.Schema; +namespace @namespaceObject.Namespace@{.Data} + + { + /// + /// 排除实体类标记 + /// + [NotMapped] + [TypeScript] + public class @sysTableSchemas[0].TableName.StringToProerty()DisplayData:@sysTableSchemas[0].TableName.StringToProerty()Entity + @if (@sysTableSchemas[0].Xtype.ToUpper().Trim() == "U") + {} + { + + public @sysTableSchemas[0].TableName.StringToProerty()DisplayData() + { + } + public @sysTableSchemas[0].TableName.StringToProerty()DisplayData(@sysTableSchemas[0].TableName.StringToProerty()Entity entity) + { + CopyFrom(entity); + } + + } +} + diff --git a/Templates/IDto.cshtml b/Templates/IDto.cshtml new file mode 100644 index 0000000..b0aa509 --- /dev/null +++ b/Templates/IDto.cshtml @@ -0,0 +1,81 @@ +@{ + ModelData modelData = Model; + SysTableSchemaViewEntity[] sysTableSchemas = modelData.sysTableSchemas; + NamespaceObject namespaceObject = modelData.NamespaceObject; +} +using CloudBuilder.Core.DatabaseAccessor.Entity; +using System.ComponentModel.DataAnnotations.Schema; +namespace @namespaceObject.Namespace@{.Data} + + { + public class @sysTableSchemas[0].TableName.StringToProerty()DisplayData + @if (@sysTableSchemas[0].Xtype.ToUpper().Trim() == "U") + {} + { + + public @sysTableSchemas[0].TableName.StringToProerty()DisplayData() + { + } + + @for (var i = 0; i < sysTableSchemas.Length; i++) + { + if (@sysTableSchemas[i].FieldName.ToUpper() == "ID") { continue; } + + public @sysTableSchemas[i].TypeOfName@{if(@sysTableSchemas[i].IsNullAble=="y"){?}} @sysTableSchemas[i].FieldName.StringToProerty() { get; set; } + + } + + + public static @sysTableSchemas[0].TableName.StringToProerty()DisplayData GetInstance() + { + return new @sysTableSchemas[0].TableName.StringToProerty()DisplayData(); + } + + public virtual void CopyFrom(@sysTableSchemas[0].TableName.StringToProerty()DisplayData source) + { + CopyFrom(source, true); + } + + public virtual void CopyFrom(@sysTableSchemas[0].TableName.StringToProerty()DisplayData source, bool includeSystemFields) + { + if (source == null) + { + throw new NullReferenceException("Source entity is null."); + } + + @for (var i = 0; i < sysTableSchemas.Length; i++) + { + if (@sysTableSchemas[i].FieldName != "created_datetime" || @sysTableSchemas[i].FieldName != "created_by" + || @sysTableSchemas[i].FieldName != "updated_datetime" || @sysTableSchemas[i].FieldName != "updated_by") + { + this.@sysTableSchemas[i].FieldName.StringToProerty() = source.@sysTableSchemas[i].FieldName.StringToProerty(); + + } + } + + if (includeSystemFields) + { + @for (var i = 0; i < sysTableSchemas.Length; i++) + { + if (@sysTableSchemas[i].FieldName == "created_datetime" || @sysTableSchemas[i].FieldName == "created_by" + || @sysTableSchemas[i].FieldName == "updated_datetime" || @sysTableSchemas[i].FieldName == "updated_by") + { + this.@sysTableSchemas[i].FieldName.StringToProerty() = source.@sysTableSchemas[i].FieldName.StringToProerty(); + + } + + } + } + } + + public @sysTableSchemas[0].TableName.StringToProerty()DisplayData Clone() + { + @sysTableSchemas[0].TableName.StringToProerty()DisplayData result = new @sysTableSchemas[0].TableName.StringToProerty()DisplayData (); + result.CopyFrom(this); + + return result; + } + + } +} + diff --git a/Templates/IEntity.cshtml b/Templates/IEntity.cshtml new file mode 100644 index 0000000..d121926 --- /dev/null +++ b/Templates/IEntity.cshtml @@ -0,0 +1,186 @@ +@{ + ModelData modelData = Model; + SysTableSchemaViewEntity[] sysTableSchemas = modelData.sysTableSchemas; + NamespaceObject namespaceObject = modelData.NamespaceObject; +} +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +@{ + string entityBase = string.Format("EntityBase<{0}>", @modelData.KeyType); + if (@modelData.KeyCount > 1) + { + entityBase = string.Format("EntityBase<{0}>", @modelData.KeyType); + } + else if (@sysTableSchemas[0].Xtype.ToUpper().Trim() != "U") + { + entityBase = "ViewEntityBase"; + } +} +namespace @namespaceObject.Namespace@{.Entity} + + { + [TypeScript] + [Table("@sysTableSchemas[0].TableName")] + public class @sysTableSchemas[0].TableName.StringToProerty()Entity : @entityBase + @if (@sysTableSchemas[0].Xtype.ToUpper().Trim() == "U") + {} + { + + public @sysTableSchemas[0].TableName.StringToProerty()Entity() + { + } + + @for (var i = 0; i < sysTableSchemas.Length; i++) + { + if (@sysTableSchemas[i].FieldName.ToUpper() == "ID") { continue; } + if (@sysTableSchemas[i].FieldName.ToUpper() == "ROW_VERSION") + { + [Column("row_version")] + [Timestamp] + public byte[]? RowVersion { get; set; } + + continue; + } + + if (@sysTableSchemas[i].Pk > 0 && @modelData.KeyCount < 2) + { + [Key] + + } + if (@sysTableSchemas[i].IsIdentity > 0) + { + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + + } + if (@sysTableSchemas[i].TypeName == "decimal") + { + [Column("@sysTableSchemas[i].FieldName",TypeName = "@sysTableSchemas[i].TypeName(@sysTableSchemas[i].MaxLength,@sysTableSchemas[i].Scale)")] + + } + else + { + [Column("@sysTableSchemas[i].FieldName")] + + } + if (@sysTableSchemas[i].TypeOfName == "string") + { + public @sysTableSchemas[i].TypeOfName@{if(@sysTableSchemas[i].IsNullAble=="y"){?}} @sysTableSchemas[i].FieldName.StringToProerty() { get; set; } + + } + else + { + public @sysTableSchemas[i].TypeOfName @sysTableSchemas[i].FieldName.StringToProerty() { get; set; } + + } + } + + @for (var i = 0; i < sysTableSchemas.Length; i++) + { + public const string @sysTableSchemas[i].FieldName.ToUpper() = "@sysTableSchemas[i].FieldName.StringToProerty()"; + + } + + public const string DB_NAME_@sysTableSchemas[0].TableName.ToUpper() = "@sysTableSchemas[0].TableName"; + @{ + string fs = ""; + } + @for (var i = 0; i < sysTableSchemas.Length; i++) + { + if (@sysTableSchemas[i].FieldName.ToUpper() == "ID") { continue; } + fs += @sysTableSchemas[i].FieldName + ","; + } + @{ + fs = fs.Substring(0, fs.Length - 1); + } public const string DB_NAME_FIELDS="@(fs)"; + + @for (var i = 0; i < sysTableSchemas.Length; i++) + { + public const string DB_@sysTableSchemas[i].FieldName.ToUpper() = "@sysTableSchemas[i].FieldName"; + + } + + + public static @sysTableSchemas[0].TableName.StringToProerty()Entity GetInstance() + { + return new @sysTableSchemas[0].TableName.StringToProerty()Entity(); + } + + public virtual void CopyFrom(@sysTableSchemas[0].TableName.StringToProerty()Entity source) + { + CopyFrom(source, true); + } + + public virtual void CopyFrom(@sysTableSchemas[0].TableName.StringToProerty()Entity source, bool includeSystemFields) + { + if (source == null) + { + throw new NullReferenceException("Source entity is null."); + } + + @for (var i = 0; i < sysTableSchemas.Length; i++) + { + if (@sysTableSchemas[i].FieldName != "created_datetime" || @sysTableSchemas[i].FieldName != "created_by" + || @sysTableSchemas[i].FieldName != "updated_datetime" || @sysTableSchemas[i].FieldName != "updated_by") + { + this.@sysTableSchemas[i].FieldName.StringToProerty() = source.@sysTableSchemas[i].FieldName.StringToProerty(); + + } + } + + if (includeSystemFields) + { + @for (var i = 0; i < sysTableSchemas.Length; i++) + { + if (@sysTableSchemas[i].FieldName == "created_datetime" || @sysTableSchemas[i].FieldName == "created_by" + || @sysTableSchemas[i].FieldName == "updated_datetime" || @sysTableSchemas[i].FieldName == "updated_by") + { + this.@sysTableSchemas[i].FieldName.StringToProerty() = source.@sysTableSchemas[i].FieldName.StringToProerty(); + + } + + } + } + } + + public override string GetSelectFrom() + { + return $" select {DB_NAME_FIELDS} from { DB_NAME_@sysTableSchemas[0].TableName.ToUpper()} "; + } + + public override string GetSelectCountFrom(string sqlWhere) + { + return $" select count(*) from { DB_NAME_@sysTableSchemas[0].TableName.ToUpper()} where 1=1 {sqlWhere}"; + } + + public override string GetSelectTopFrom(int limit, int start,string orderby,string orderbytag, string sqlWhere) + { + if (string.IsNullOrEmpty(orderbytag) || orderbytag.Trim() != "desc") orderbytag = "asc"; + @for (var i = 0; i < sysTableSchemas.Length; i++) + { + if (@sysTableSchemas[i].Pk > 0) + { + if (string.IsNullOrEmpty(orderby) || !DB_NAME_FIELDS.Contains(orderby)) orderby = DB_@sysTableSchemas[i].FieldName.ToUpper() ; + break; + } + } + + @if(sysTableSchemas.Sum(x=>x.Pk)==0) + { + if (string.IsNullOrEmpty(orderby) || !DB_NAME_FIELDS.Contains(orderby)) orderby = DB_@sysTableSchemas[0].FieldName.ToUpper() ; + } + int offset = limit * (start - 1); + return $" select {DB_NAME_FIELDS} from (select {DB_NAME_FIELDS} ,row_number() over(order by {orderby} {orderbytag}) as num from { DB_NAME_@sysTableSchemas[0].TableName.ToUpper()} where 1=1 {sqlWhere} ) a where num> {offset} LIMIT {offset},{limit} "; + } + + public @sysTableSchemas[0].TableName.StringToProerty()Entity Clone() + { + @sysTableSchemas[0].TableName.StringToProerty()Entity result = new @sysTableSchemas[0].TableName.StringToProerty()Entity(); + result.CopyFrom(this); + + return result; + } + + } +} diff --git a/Templates/IEntityKey.cshtml b/Templates/IEntityKey.cshtml new file mode 100644 index 0000000..bb015e3 --- /dev/null +++ b/Templates/IEntityKey.cshtml @@ -0,0 +1,72 @@ +@{ + ModelData modelData = Model; + SysTableSchemaViewEntity[] sysTableSchemas = modelData.sysTableSchemas; + NamespaceObject namespaceObject = modelData.NamespaceObject; +} +using CloudBuilder.Core.Authorization; +namespace @namespaceObject.Namespace +{ + [TypeScript] + public class @sysTableSchemas[0].TableName.StringToProerty()EntityKey + { + @for (var i = 0; i < sysTableSchemas.Length; i++) + { + if (@sysTableSchemas[i].Pk > 0) + { + public @sysTableSchemas[i].TypeOfName @sysTableSchemas[i].FieldName.StringToProerty() { get; set; } + + } + } + + public override bool Equals(object obj) + { + if (this == obj) return true; + + @sysTableSchemas[0].TableName.StringToProerty()EntityKey pkey = obj as @sysTableSchemas[0].TableName.StringToProerty()EntityKey; + if (pkey == null) return false; + + @for (var i = 0; i < sysTableSchemas.Length; i++) + { + if (@sysTableSchemas[i].Pk > 0) + { + if (@sysTableSchemas[i].FieldName.StringToProerty() != pkey.@sysTableSchemas[i].FieldName.StringToProerty()) return false; + + } + } + + return true; + } + + + public override string ToString() + { + string declareSql=""; + @{int j = 0;} + @for (var i = 0; i < sysTableSchemas.Length; i++) + { + if (@sysTableSchemas[i].Pk > 0) + { + declareSql=declareSql+$"declare @@__tkey_@sysTableSchemas[i].FieldName.StringToProerty()_@j.ToString() varchar(50) select @@__tkey_@sysTableSchemas[i].FieldName.StringToProerty()_@j.ToString() ='{@sysTableSchemas[i].FieldName.StringToProerty()}'; " ; + j++; + } + } + + return declareSql; + } + } + } + /* @if (modelData.KeyCount > 0) + {builder.Entity<@sysTableSchemas[0].TableName.StringToProerty()Entity>().HasKey(c => new {int k = 0; + for (var i = 0; i < sysTableSchemas.Length; i++) + { + if (@sysTableSchemas[i].Pk > 0) + { + k++; + c.@sysTableSchemas[i].FieldName.StringToProerty()if (modelData.KeyCount != k) + {,} + + } + } + }); +} + */ diff --git a/Templates/IService.cshtml b/Templates/IService.cshtml new file mode 100644 index 0000000..600c218 --- /dev/null +++ b/Templates/IService.cshtml @@ -0,0 +1,17 @@ +@{ + ModelData modelData = Model; + SysTableSchemaViewEntity[] sysTableSchemas = modelData.sysTableSchemas; + NamespaceObject namespaceObject = modelData.NamespaceObject; +} + +using @namespaceObject.Assembly.ToString()@{.Entity}; +using @namespaceObject.Assembly.ToString()@{.SearchCriteria}; +using CloudBuilder.Core.Service; + +namespace @namespaceObject.Assembly.ToString()@{.Service} + +{ + public interface @{I}@sysTableSchemas[0].TableName.StringToProerty()Service :IServiceBase<@sysTableSchemas[0].TableName.StringToProerty()Entity, @modelData.KeyType ,@sysTableSchemas[0].TableName.StringToProerty()SearchCriteria> + { + } +} diff --git a/Templates/Permission.auto.cshtml b/Templates/Permission.auto.cshtml new file mode 100644 index 0000000..881e11c --- /dev/null +++ b/Templates/Permission.auto.cshtml @@ -0,0 +1,15 @@ +@{ + ModelData modelData = Model; + SysTableSchemaViewEntity[] sysTableSchemas = modelData.sysTableSchemas; + NamespaceObject namespaceObject = modelData.NamespaceObject; +} +namespace @namespaceObject.Namespace@{.Policy} + +{ + public partial class @namespaceObject.Assembly.Replace("CloudBuilder.", "").Replace(".", "")PermissionPolicy + { + //***BEGIN*** + public const string @sysTableSchemas[0].TableName.StringToProerty() = "@sysTableSchemas[0].TableName.StringToProerty()"; + //***END*** + } +} \ No newline at end of file diff --git a/Templates/Permission.cshtml b/Templates/Permission.cshtml new file mode 100644 index 0000000..6c514ca --- /dev/null +++ b/Templates/Permission.cshtml @@ -0,0 +1,7 @@ +@{ + ModelData modelData = Model; + SysTableSchemaViewEntity[] sysTableSchemas = modelData.sysTableSchemas; + NamespaceObject namespaceObject = modelData.NamespaceObject; +} +public const string @sysTableSchemas[0].TableName.StringToProerty() = "@sysTableSchemas[0].TableName.StringToProerty()"; + \ No newline at end of file diff --git a/Templates/RegistEntity.Key.cshtml b/Templates/RegistEntity.Key.cshtml new file mode 100644 index 0000000..de0c952 --- /dev/null +++ b/Templates/RegistEntity.Key.cshtml @@ -0,0 +1,26 @@ +@{ + ModelData modelData = Model; + SysTableSchemaViewEntity[] sysTableSchemas = modelData.sysTableSchemas; + NamespaceObject namespaceObject = modelData.NamespaceObject; +} +@if (modelData.KeyCount > 1) +{ +builder.Entity<@sysTableSchemas[0].TableName.StringToProerty()Entity>().HasKey(c => new {int k = 0; + for (var i = 0; i < sysTableSchemas.Length; i++) + { + if (@sysTableSchemas[i].Pk > 0) + { + k++; + c.@sysTableSchemas[i].FieldName.StringToProerty()if (modelData.KeyCount != k) + {,} + + } +} +}); + +} +else @if (modelData.KeyCount == 0) +{ +builder.Entity<@sysTableSchemas[0].TableName.StringToProerty()Entity>(eb => { eb.HasNoKey(); }); + +} \ No newline at end of file diff --git a/Templates/RegistEntity.cshtml b/Templates/RegistEntity.cshtml new file mode 100644 index 0000000..c0567fd --- /dev/null +++ b/Templates/RegistEntity.cshtml @@ -0,0 +1,47 @@ +@{ + ModelData modelData = Model; + SysTableSchemaViewEntity[] sysTableSchemas = modelData.sysTableSchemas; + NamespaceObject namespaceObject = modelData.NamespaceObject; +} +using CloudBuilder.Core.DependencyInjection.EFCore; +using Microsoft.EntityFrameworkCore; +using System.Reflection; + +namespace @namespaceObject.Namespace@{.Entity} + +{ + public class @namespaceObject.Namespace.Replace(".","")RegistEntity : IMasterRegistEntityType + { + /// + ///注入模块内的所有实体类 + /// + /// + public void RegistEntity(ModelBuilder builder) + { + string _assemblyName = Assembly.GetExecutingAssembly().GetName().Name; + //注入所有Entity实体类 + AddEntityType(builder, _assemblyName); + //如果Entity实体类不是单一主键,要单独重写注入 + RegistKeys(builder); + } + + public void AddEntityType(ModelBuilder builder, string _assemblyName) + { + RegistEntityHelper.AddMasterEntityType(builder, _assemblyName); + } + + /// + ///如果存在多个主键的,要在RegistKeys方法注入 + ///builder.Entity().HasKey(c => new { c.TableName, c.FieldName }); + ///builder.Entity(eb => { eb.HasNoKey(); }); + /// + /// + public void RegistKeys(ModelBuilder builder) + { + //***BEGIN*** + + //***END*** + } + } +} + diff --git a/Templates/Request.cshtml b/Templates/Request.cshtml new file mode 100644 index 0000000..579d38f --- /dev/null +++ b/Templates/Request.cshtml @@ -0,0 +1,169 @@ +@{ + ModelData modelData = Model; + NamespaceObject namespaceObject = modelData.NamespaceObject; + SysTableSchemaViewEntity[] sysTableSchemas = modelData.sysTableSchemas; + ClassInfo classInfo= modelData.ClassInfos.FirstOrDefault(); + //ClassInfo classInfo= modelData.ClassInfos.Where(x=>x.ClassName=="SecurityUserService").FirstOrDefault(); +} +using CloudBuilder.Core.DependencyInjection.Request; +using CloudBuilder.Core.Request; +using CloudBuilder.Core.Service; +using Microsoft.Extensions.DependencyInjection; +@{ + if(classInfo.Usings!=null && classInfo.Usings.Length>0) + { + for (var i = 0; i < classInfo.Usings.Length; i++) + { + if(classInfo.Usings[i]=="CloudBuilder.Core.Service") continue; + using @classInfo.Usings[i]; + + } + } +} + +namespace @namespaceObject.Namespace +{ + +public class @{@classInfo.ClassName.Replace("Service", "")}Request : IRequest +{ + +private readonly IServiceRequest serviceRequest; +public @{@classInfo.ClassName.Replace("Service", "")}Request(IServiceRequest serviceRequest) +{ +this.serviceRequest = serviceRequest; +} + +@{ + if(classInfo.ClassMethodInfos!=null && classInfo.ClassMethodInfos.Length>0 && classInfo.ClassMethodInfos[0].Parameters!=null) + { + for (var j= 0; j< classInfo.ClassMethodInfos.Length; j++) + { + string methodReturnName="void "; + if(classInfo.ClassMethodInfos[j].MethodReturnName!="Void") + { + methodReturnName=" "+classInfo.ClassMethodInfos[j].MethodReturnName.Replace("String", "string").Replace("Boolean", "bool")+" "; + } + //没有参数的情况======================================= + if(classInfo.ClassMethodInfos[j].Parameters.Length==0) + { + //文本开始================================================================================================================= + public @{ @methodReturnName @classInfo.ClassMethodInfos[j].MethodName }() + { + @{ + //[HttpGet]一定要有返回值,否则使用[HttpPost] + if(classInfo.ClassMethodInfos[j].HttpName=="[HttpGet]"){ + return Task.Run(() => serviceRequest.GetAsync<@{@classInfo.ClassMethodInfos[j].MethodReturnName.Replace("String", "string").Replace("Boolean", "bool")}>("/@{@classInfo.ClassName.Replace("Service", "")}/@{@classInfo.ClassMethodInfos[j].MethodName}")).GetAwaiter().GetResult(); + } + else{ + //[HttpPost]可以有无返回值 + if(classInfo.ClassMethodInfos[j].MethodReturnName!="Void"){return } Task.Run(() => serviceRequest.@{if(classInfo.ClassMethodInfos[j].MethodReturnName!="Void"){PostAsJsonAsync<@{@classInfo.ClassMethodInfos[j].MethodReturnName.Replace("String", "string").Replace("Boolean", "bool")}> }else{PostAsync}}("/@{@classInfo.ClassName.Replace("Service", "")}/@{@classInfo.ClassMethodInfos[j].MethodName}")).GetAwaiter().GetResult(); + } + } + } + + + //文本结束================================================================================================================= + } + + + //只有1个参数的情况============================================ + if(classInfo.ClassMethodInfos[j].Parameters.Length>0) + { + //超过1个参数的情况,如果是get,不能用组合对象,如果是post,要重新组合一个类======================================== + if(classInfo.ClassMethodInfos[j].Parameters.Length>1 && classInfo.ClassMethodInfos[j].HttpName!="[HttpGet]") + { + + public class @{@classInfo.ClassMethodInfos[j].MethodName}CompositionData@{@classInfo.ClassMethodInfos[j].Parameters.Length} + { + + + for (var ik = 0; ik < classInfo.ClassMethodInfos[j].Parameters.Length; ik++){ + string parameterTypeName=classInfo.ClassMethodInfos[j].Parameters[ik].ParameterTypeName; + if(classInfo.ClassMethodInfos[j].Parameters[ik].IsValueType) + { + if(classInfo.ClassMethodInfos[j].Parameters[ik].ParameterTypeName=="String") + parameterTypeName="string"; + if(classInfo.ClassMethodInfos[j].Parameters[ik].ParameterTypeName=="Boolean") + parameterTypeName="bool"; + } + public @parameterTypeName @classInfo.ClassMethodInfos[j].Parameters[ik].ParameterName { get; set; } + + + } + + + } + + } + + + string parametersName=@classInfo.ClassMethodInfos[j].Parameters[0].ParameterTypeName.Replace("String", "string").Replace("Boolean", "bool")+" "+@classInfo.ClassMethodInfos[j].Parameters[0].ParameterName; + string content=string.Empty; + //如果是[HttpGet],一定是值参数,统一使用组合参数 + if(classInfo.ClassMethodInfos[j].Parameters.Length>0 && classInfo.ClassMethodInfos[j].HttpName=="[HttpGet]") + { + content += "var compositionData = new Dictionary();\t\r"; + + for (var iac = 0; iac < classInfo.ClassMethodInfos[j].Parameters.Length; iac++) + { + content += "compositionData.Add(\"" + @classInfo.ClassMethodInfos[j].Parameters[iac].ParameterName + "\", " + @classInfo.ClassMethodInfos[j].Parameters[iac].ParameterName + ".ToString());\t\r"; + } + content += "return Task.Run(() => serviceRequest.GetWithQueryAsync<"+@classInfo.ClassMethodInfos[j].MethodReturnName.Replace("String", "string").Replace("Boolean", "bool")+">(\"/"+@classInfo.ClassName.Replace("Service", "")+"/"+@classInfo.ClassMethodInfos[j].MethodName+"\", compositionData)).GetAwaiter().GetResult();"; + } + else if(classInfo.ClassMethodInfos[j].Parameters.Length>0 && classInfo.ClassMethodInfos[j].HttpName!="[HttpGet]") + { + string returnValue=string.Empty; + if(classInfo.ClassMethodInfos[j].MethodReturnName!="Void")returnValue="return"; + + if(classInfo.ClassMethodInfos[j].Parameters.Length>1) + { + string CompositionData=classInfo.ClassMethodInfos[j].MethodName+"CompositionData"+classInfo.ClassMethodInfos[j].Parameters.Length; + content += "var compositionData = new "+CompositionData+"{\t\r"; + for (var ikp = 0; ikp < classInfo.ClassMethodInfos[j].Parameters.Length; ikp++) + { + if(ikp>0) content += ",\t\r"; + content += @classInfo.ClassMethodInfos[j].Parameters[ikp].ParameterName+" = "+@classInfo.ClassMethodInfos[j].Parameters[ikp].ParameterName; + } + content += " };\t\r"; + string rv=classInfo.ClassMethodInfos[j].MethodReturnName.Replace("String", "string").Replace("Boolean", "bool").Replace("Void", "dynamic"); + content += returnValue+" Task.Run(() => serviceRequest.PostAsJsonAsync<"+CompositionData+", "+rv+">(\"/"+@classInfo.ClassName.Replace("Service", "")+"/"+@classInfo.ClassMethodInfos[j].MethodName+"\", compositionData)).GetAwaiter().GetResult();"; + } + else + { + string post="PostAsync"; + if(classInfo.ClassMethodInfos[j].MethodReturnName!="Void")post="PostAsJsonAsync"+string.Format("<{1},{0}>",classInfo.ClassMethodInfos[j].MethodReturnName.Replace("String", "string").Replace("Boolean", "bool"),@classInfo.ClassMethodInfos[j].Parameters[0].ParameterTypeName.Replace("String", "string").Replace("Boolean", "bool")); + if(!classInfo.ClassMethodInfos[j].Parameters[0].IsValueType && classInfo.ClassMethodInfos[j].MethodReturnName=="Void")post="PostAsJsonAsync"+string.Format("<{0},dynamic>",@classInfo.ClassMethodInfos[j].Parameters[0].ParameterTypeName.Replace("String", "string").Replace("Boolean", "bool")); + if(classInfo.ClassMethodInfos[j].Parameters[0].IsValueType) + { + if(classInfo.ClassMethodInfos[j].MethodReturnName!="Void"){post="PostAsJsonAsync"+string.Format("<{0}>",classInfo.ClassMethodInfos[j].MethodReturnName.Replace("String", "string").Replace("Boolean", "bool"));} + content += returnValue+" Task.Run(() => serviceRequest."+post+"(\"/"+@classInfo.ClassName.Replace("Service", "")+"/"+@classInfo.ClassMethodInfos[j].MethodName+"?"+@classInfo.ClassMethodInfos[j].Parameters[0].ParameterName+"=\" + "+@classInfo.ClassMethodInfos[j].Parameters[0].ParameterName+".ToString())).GetAwaiter().GetResult();"; + } + else{ + content += returnValue+" Task.Run(() => serviceRequest."+post+"(\"/"+@classInfo.ClassName.Replace("Service", "")+"/"+@classInfo.ClassMethodInfos[j].MethodName+"\" , "+@classInfo.ClassMethodInfos[j].Parameters[0].ParameterName+")).GetAwaiter().GetResult();"; + } + } + + } + + + parametersName=string.Empty; + for (var ikb = 0; ikb < classInfo.ClassMethodInfos[j].Parameters.Length; ikb++){ + if(ikb>0)parametersName+=", "; + parametersName+=@classInfo.ClassMethodInfos[j].Parameters[ikb].ParameterTypeName.Replace("String", "string").Replace("Boolean", "bool")+" "+@classInfo.ClassMethodInfos[j].Parameters[ikb].ParameterName; + } + //文本开始================================================ + public @{@methodReturnName @classInfo.ClassMethodInfos[j].MethodName}(@{@parametersName}) + { + @{@content.ToString()} + } + + + //文本结束=================================================== + } + } + } +//下面}为代码段结束================================================================================================================= +} + +} +} \ No newline at end of file diff --git a/Templates/SearchCriteria.cshtml b/Templates/SearchCriteria.cshtml new file mode 100644 index 0000000..7ab8c28 --- /dev/null +++ b/Templates/SearchCriteria.cshtml @@ -0,0 +1,16 @@ +@{ + ModelData modelData = Model; + SysTableSchemaViewEntity[] sysTableSchemas = modelData.sysTableSchemas; + NamespaceObject namespaceObject = modelData.NamespaceObject; +} +using CloudBuilder.Core.Authorization; +using CloudBuilder.Core.Service; +namespace @namespaceObject.Namespace@{.SearchCriteria} + +{ + [TypeScript] + public class @sysTableSchemas[0].TableName.StringToProerty()SearchCriteria: AbstractSearchCriteria + { + + } +} diff --git a/Templates/Service.cshtml b/Templates/Service.cshtml new file mode 100644 index 0000000..927e70f --- /dev/null +++ b/Templates/Service.cshtml @@ -0,0 +1,141 @@ +@{ + ModelData modelData = Model; + SysTableSchemaViewEntity[] sysTableSchemas = modelData.sysTableSchemas; + NamespaceObject namespaceObject = modelData.NamespaceObject; +} +using CloudBuilder.Core.DatabaseAccessor.Entity; +using Microsoft.AspNetCore.Authorization; +using CloudBuilder.Core.DatabaseAccessor; +@{ + using @namespaceObject.Assembly.ToString().Entity; + using @namespaceObject.Assembly.ToString().Policy; + using @namespaceObject.Assembly.ToString().SearchCriteria; +} + +namespace @namespaceObject.Assembly.ToString()@{.Service} + +{ + public class @sysTableSchemas[0].TableName.StringToProerty()Service : I@{@sysTableSchemas[0].TableName.StringToProerty()}Service + { + private readonly IApplicationService service; + + private IRepository<@{@sysTableSchemas[0].TableName.StringToProerty()}Entity> repository; + public @{@sysTableSchemas[0].TableName.StringToProerty()}Service(IApplicationService service) + { + this.service = service; + repository = service.GetRepository>(); + } + @if (@modelData.KeyCount < 2) + { + @for (var i = 0; i < sysTableSchemas.Length; i++) + { + if (@sysTableSchemas[i].FieldName.ToUpper() == "ID") { continue; } + + if (@sysTableSchemas[i].Pk > 0 && @modelData.KeyCount < 2) + { + + [PermissionOperate(name: @namespaceObject.Assembly.ToString().Replace(".Service", "").Replace("CloudBuilder.", "").Replace(".", "")PermissionPolicy.@{@sysTableSchemas[0].TableName.StringToProerty()}, operate: Operate.Find)] + public @{@sysTableSchemas[0].TableName.StringToProerty()}Entity FindByKey(@modelData.KeyType key) + { + return repository.DetachedEntities.Where(x => x.@{ @sysTableSchemas[i].FieldName.StringToProerty()} == key).FirstOrDefault()!; + } + + } + } + } + else if (@modelData.KeyCount > 1) + { + + [PermissionOperate(name: @namespaceObject.Assembly.ToString().Replace(".Service", "").Replace("CloudBuilder.", "").Replace(".", "")PermissionPolicy.@{@sysTableSchemas[0].TableName.StringToProerty()}, operate: Operate.Find)] + public @{@sysTableSchemas[0].TableName.StringToProerty()}Entity FindByKey(@{@sysTableSchemas[0].TableName.StringToProerty()}EntityKey key) + { + return repository.DetachedEntities.Where(x => 1==1 + @for (var i = 0; i < sysTableSchemas.Length; i++) + { + if (@sysTableSchemas[i].FieldName.ToUpper() == "ID") { continue; } + + if (@sysTableSchemas[i].Pk > 0) + { + + && x.@{ @sysTableSchemas[i].FieldName.StringToProerty()} == key.@{ @sysTableSchemas[i].FieldName.StringToProerty()} + + } + } + + ).FirstOrDefault()!; + } + + } + + //[PermissionOperate(name: @namespaceObject.Assembly.ToString().Replace(".Service", "").Replace("CloudBuilder.", "").Replace(".", "")PermissionPolicy.@{@sysTableSchemas[0].TableName.StringToProerty()}, operate: Operate.Find)] + public dynamic FindBySearchCriteria(@{@sysTableSchemas[0].TableName.StringToProerty()}SearchCriteria criteria) + { + throw new NotImplementedException(); + } + + //[PermissionOperate(name: @namespaceObject.Assembly.ToString().Replace(".Service", "").Replace("CloudBuilder.", "").Replace(".", "")PermissionPolicy.@{@sysTableSchemas[0].TableName.StringToProerty()}, operate: Operate.Print)] + public dynamic PrintBySearchCriteria(@{@sysTableSchemas[0].TableName.StringToProerty()}SearchCriteria criteria) + { + throw new NotImplementedException(); + } + + [PermissionOperate(name: @namespaceObject.Assembly.ToString().Replace(".Service", "").Replace("CloudBuilder.", "").Replace(".", "")PermissionPolicy.@{@sysTableSchemas[0].TableName.StringToProerty()}, operate: Operate.Insert)] + [UnitOfWork] + public @{@sysTableSchemas[0].TableName.StringToProerty()}Entity Insert(@{@sysTableSchemas[0].TableName.StringToProerty()}Entity data) + { + throw new NotImplementedException(); + } + + [PermissionOperate(name: @namespaceObject.Assembly.ToString().Replace(".Service", "").Replace("CloudBuilder.", "").Replace(".", "")PermissionPolicy.@{@sysTableSchemas[0].TableName.StringToProerty()}, operate: Operate.Update)] + [UnitOfWork] + public @{@sysTableSchemas[0].TableName.StringToProerty()}Entity Update(@{@sysTableSchemas[0].TableName.StringToProerty()}Entity data) + { + throw new NotImplementedException(); + } + + @if (@modelData.KeyCount < 2) + { + @for (var i = 0; i < sysTableSchemas.Length; i++) + { + if (@sysTableSchemas[i].FieldName.ToUpper() == "ID") { continue; } + + if (@sysTableSchemas[i].Pk > 0 && @modelData.KeyCount < 2) + { + + [PermissionOperate(name: @namespaceObject.Assembly.ToString().Replace(".Service", "").Replace("CloudBuilder.", "").Replace(".", "")PermissionPolicy.@{@sysTableSchemas[0].TableName.StringToProerty()}, operate: Operate.Delete)] + [UnitOfWork] + public void Delete(@modelData.KeyType key) + { + var ent= repository.DetachedEntities.Where(x => x.@{ @sysTableSchemas[i].FieldName.StringToProerty()} == key).FirstOrDefault()!; + if (ent != null) { repository.DeleteNow(ent); } + } + + } + } + } + else if (@modelData.KeyCount > 1) + { + + [PermissionOperate(name: @namespaceObject.Assembly.ToString().Replace(".Service", "").Replace("CloudBuilder.", "").Replace(".", "")PermissionPolicy.@{@sysTableSchemas[0].TableName.StringToProerty()}, operate: Operate.Delete)] + public void Delete(@{@sysTableSchemas[0].TableName.StringToProerty()}EntityKey key) + { + @sysTableSchemas[0].TableName.StringToProerty()Entity ent = repository.DetachedEntities.Where(x => 1==1 + @for (var i = 0; i < sysTableSchemas.Length; i++) + { + if (@sysTableSchemas[i].FieldName.ToUpper() == "ID") { continue; } + + if (@sysTableSchemas[i].Pk > 0) + { + + && x.@{ @sysTableSchemas[i].FieldName.StringToProerty()} == key.@{ @sysTableSchemas[i].FieldName.StringToProerty()} + + } + } + + ).FirstOrDefault()!; + if (ent != null) { repository.DeleteNow(ent); } + } + + } + } +} diff --git a/Templates/TypeScript.cshtml b/Templates/TypeScript.cshtml new file mode 100644 index 0000000..8a5af3c --- /dev/null +++ b/Templates/TypeScript.cshtml @@ -0,0 +1,115 @@ +@{ + ModelData modelData = Model; + NamespaceObject namespaceObject = modelData.NamespaceObject; + SysTableSchemaViewEntity[] sysTableSchemas = modelData.sysTableSchemas; + ClassInfo classInfo= modelData.ClassInfos.FirstOrDefault(); + //ClassInfo classInfo= modelData.ClassInfos.Where(x=>x.ClassName=="SecurityUserSearchCriteria").FirstOrDefault(); +} +@{ + if(classInfo.Usings!=null && classInfo.Usings.Length>0) + { + for (var i = 0; i < classInfo.Usings.Length; i++) + { + import { @classInfo.Usings[i].StringToProerty() } from "./@classInfo.Usings[i].StringToProtectedProerty()"; + + } + } +} +@{ + string implementTypeName=string.IsNullOrEmpty(classInfo.ImplementTypeName)?"":" extends "+classInfo.ImplementTypeName; + if(!string.IsNullOrEmpty(implementTypeName)) + { + import { @classInfo.ImplementTypeName.StringToProerty() } from "./@classInfo.ImplementTypeName.StringToProtectedProerty()"; + + } +} +export class @classInfo.ClassName @implementTypeName +{ +@{ + if(classInfo.ClassProperties!=null && classInfo.ClassProperties.Length>0) + { + for (var j= 0; j< classInfo.ClassProperties.Length; j++) + { + if(classInfo.ClassProperties[j].PropertyTypeName=="Nullable`1") + { + public @classInfo.ClassProperties[j].PropertyName?: Date= null!; + + } + else if(classInfo.ClassProperties[j].PropertyTypeName.ToLower()=="datetime") + { + public @classInfo.ClassProperties[j].PropertyName: Date = new Date(); + + } + else if(classInfo.ClassProperties[j].PropertyTypeName=="Boolean") + { + public @classInfo.ClassProperties[j].PropertyName: boolean =false; + + } + else if(classInfo.ClassProperties[j].PropertyTypeName=="String") + { + public @classInfo.ClassProperties[j].PropertyName: string = ""; + + } + else if(classInfo.ClassProperties[j].PropertyTypeName=="Int32" || classInfo.ClassProperties[j].PropertyTypeName=="Int64" || classInfo.ClassProperties[j].PropertyTypeName=="Int16" || classInfo.ClassProperties[j].PropertyTypeName=="Long" || classInfo.ClassProperties[j].PropertyTypeName.ToLower()=="decimal") + { + public @classInfo.ClassProperties[j].PropertyName: number = 0; + + } + else if(classInfo.ClassProperties[j].PropertyTypeName=="Int32[]" || classInfo.ClassProperties[j].PropertyTypeName=="Int64[]" || classInfo.ClassProperties[j].PropertyTypeName=="Int16[]" || classInfo.ClassProperties[j].PropertyTypeName=="Long[]" || classInfo.ClassProperties[j].PropertyTypeName.ToLower()=="decimal[]") + { + public @classInfo.ClassProperties[j].PropertyName: number[] = []; + + } + else if(classInfo.ClassProperties[j].PropertyTypeName.Contains("String[]")) + { + public @classInfo.ClassProperties[j].PropertyName: string[]= []; + + } + else if(!classInfo.ClassProperties[j].IsValueType && classInfo.ClassProperties[j].PropertyTypeName.Contains("[]")) + { + public @classInfo.ClassProperties[j].PropertyName: @classInfo.ClassProperties[j].PropertyTypeName.StringToProerty() = []; + + } + else if(classInfo.ClassProperties[j].PropertyTypeName=="any") + { + public @classInfo.ClassProperties[j].PropertyName: any; + + } + else if(!classInfo.ClassProperties[j].IsValueType) + { + public @classInfo.ClassProperties[j].PropertyName: @classInfo.ClassProperties[j].PropertyTypeName.StringToProerty() = new @{@classInfo.ClassProperties[j].PropertyTypeName.StringToProerty() }(); + + } + else + { + public @classInfo.ClassProperties[j].PropertyName: any ={} + + } + } + } + } + +@{ + if(classInfo.ClassFields!=null && classInfo.ClassFields.Length>0) + { + for (var j= 0; j< classInfo.ClassFields.Length; j++) + { + if(classInfo.ClassFields[j].FieldTypeName =="String") + { + static readonly @classInfo.ClassFields[j].FieldName : string ='@classInfo.ClassFields[j].FieldValue'; + + } + if(classInfo.ClassFields[j].FieldTypeName =="Boolean") + { + static readonly @classInfo.ClassFields[j].FieldName : Boolean ='@classInfo.ClassFields[j].FieldValue'; + + } + else if(classInfo.ClassFields[j].FieldTypeName =="Int32" || classInfo.ClassFields[j].FieldTypeName =="Int64" || classInfo.ClassFields[j].FieldTypeName =="Int16" || classInfo.ClassFields[j].FieldTypeName =="Long" || classInfo.ClassFields[j].FieldTypeName .ToLower()=="decimal") + { + static readonly @classInfo.ClassFields[j].FieldName: number =@classInfo.ClassFields[j].FieldValue; + + } + } + } + } +} diff --git a/Templates/TypeScriptService.cshtml b/Templates/TypeScriptService.cshtml new file mode 100644 index 0000000..8c244b8 --- /dev/null +++ b/Templates/TypeScriptService.cshtml @@ -0,0 +1,147 @@ +@{ + ModelData modelData = Model; + NamespaceObject namespaceObject = modelData.NamespaceObject; + SysTableSchemaViewEntity[] sysTableSchemas = modelData.sysTableSchemas; + ClassInfo classInfo= modelData.ClassInfos.FirstOrDefault(); + //ClassInfo classInfo= modelData.ClassInfos.Where(x=>x.ClassName=="SecurityUserService").FirstOrDefault(); +} +@if(classInfo.IsDownload) +{ + import { request,download } from "@@/utils/request"; + +} +else +{ + import { request } from "@@/utils/request"; + +} +@{ +List l=new List(); +if(classInfo.ClassMethodInfos!=null && classInfo.ClassMethodInfos.Length>0 && classInfo.ClassMethodInfos[0].Parameters!=null) +{ + for (var j= 0; j< classInfo.ClassMethodInfos.Length; j++) + { + for (var i = 0; i < classInfo.ClassMethodInfos[j].Parameters.Length; i++) + { + if(!classInfo.ClassMethodInfos[j].Parameters[i].IsValueType) + { + if (!l.Contains(classInfo.ClassMethodInfos[j].Parameters[i].ParameterTypeName.Replace("[]", ""))) + { + l.Add(classInfo.ClassMethodInfos[j].Parameters[i].ParameterTypeName.Replace("[]", "")); + } + } + } + if("dynamic" !=classInfo.ClassMethodInfos[j].MethodReturnName) + { + if(classInfo.ClassMethodInfos[j].IsValueType) continue; + if (l.Contains(classInfo.ClassMethodInfos[j].MethodReturnName.Replace("[]", ""))) continue; + l.Add(classInfo.ClassMethodInfos[j].MethodReturnName.Replace("[]", "")); + } + } + } + foreach (string s in l) + { + if(s.StringToProtectedProerty()=="string") continue; + if(s.StringToProtectedProerty()=="byte") continue; + import type { @s } from "@@/data/auto/@s.StringToProtectedProerty()"; + + + } + +} + +class @{@classInfo.ClassName}{ +@{ + +if(classInfo.ClassMethodInfos!=null && classInfo.ClassMethodInfos.Length>0 && classInfo.ClassMethodInfos[0].Parameters!=null) +{ + for (var j= 0; j< classInfo.ClassMethodInfos.Length; j++) + { + string methodReturnName=classInfo.ClassMethodInfos[j].MethodReturnName; + if(classInfo.ClassMethodInfos[j].IsValueType) + { + if(classInfo.ClassMethodInfos[j].MethodReturnName=="String") + methodReturnName="string"; + else if(classInfo.ClassMethodInfos[j].MethodReturnName=="Int32" || classInfo.ClassMethodInfos[j].MethodReturnName=="Int64" || classInfo.ClassMethodInfos[j].MethodReturnName=="Int16" || classInfo.ClassMethodInfos[j].MethodReturnName=="Long" || classInfo.ClassMethodInfos[j].MethodReturnName=="decimal" ) + methodReturnName="number"; + else if(classInfo.ClassMethodInfos[j].MethodReturnName=="String[]") + methodReturnName="string[]"; + else if(classInfo.ClassMethodInfos[j].MethodReturnName=="Int32[]" || classInfo.ClassMethodInfos[j].MethodReturnName=="Int64[]" || classInfo.ClassMethodInfos[j].MethodReturnName=="Int16[]" || classInfo.ClassMethodInfos[j].MethodReturnName=="Long[]" || classInfo.ClassMethodInfos[j].MethodReturnName=="decimal[]" ) + methodReturnName="number[]"; + else methodReturnName="any"; + } + + if(classInfo.ClassMethodInfos[j].Parameters.Length==0) + { + + async @{@classInfo.ClassMethodInfos[j].MethodName}() { + return request<@methodReturnName.Replace("dynamic", "any")>( + { + url: "/@{@classInfo.ClassName.Replace("Service", "")}/@{@classInfo.ClassMethodInfos[j].MethodName}", + method: "@{if(classInfo.ClassMethodInfos[j].HttpName!="[HttpGet]"){post}else{get} }", + } + ) + }; + + } + + + for (var i = 0; i < classInfo.ClassMethodInfos[j].Parameters.Length; i++) + { + string parameterTypeName=classInfo.ClassMethodInfos[j].Parameters[i].ParameterTypeName; + string url="\""; + if(classInfo.ClassMethodInfos[j].Parameters[i].IsValueType) + { + url="?"+classInfo.ClassMethodInfos[j].Parameters[i].ParameterName+"=\"+data"; + if(classInfo.ClassMethodInfos[j].Parameters[i].ParameterTypeName=="String") + parameterTypeName="string"; + else if(classInfo.ClassMethodInfos[j].Parameters[i].ParameterTypeName=="Int32" || classInfo.ClassMethodInfos[j].Parameters[i].ParameterTypeName=="Int64" || classInfo.ClassMethodInfos[j].Parameters[i].ParameterTypeName=="Int16" || classInfo.ClassMethodInfos[j].Parameters[i].ParameterTypeName=="Long" || classInfo.ClassMethodInfos[j].Parameters[i].ParameterTypeName=="decimal" ) + parameterTypeName="number"; + else if(classInfo.ClassMethodInfos[j].Parameters[i].ParameterTypeName=="String[]") + parameterTypeName="string[]"; + else if(classInfo.ClassMethodInfos[j].Parameters[i].ParameterTypeName=="Int32[]" || classInfo.ClassMethodInfos[j].Parameters[i].ParameterTypeName=="Int64[]" || classInfo.ClassMethodInfos[j].Parameters[i].ParameterTypeName=="Int16[]" || classInfo.ClassMethodInfos[j].Parameters[i].ParameterTypeName=="Long[]" || classInfo.ClassMethodInfos[j].Parameters[i].ParameterTypeName=="decimal[]" ) + parameterTypeName="number[]"; + else parameterTypeName="any"; + } + if(classInfo.ClassMethodInfos[j].Parameters.Length>1) {url="\"";parameterTypeName="any";} + if(i>0) {continue;} + + + async @{@classInfo.ClassMethodInfos[j].MethodName}(data: @parameterTypeName) { + @{ + bool isPrintBy=false; + bool isDownloadFile=false; + if(classInfo.ClassMethodInfos[j].MethodName.StartsWith("PrintBy")) + { + isPrintBy=true; + } + if(classInfo.ClassMethodInfos[j].MethodName.StartsWith("DownloadFile")) + { + isDownloadFile=true; + } + + } + return @{if(isPrintBy){download}else{ request<@{@methodReturnName.Replace("dynamic", "any")}>}}( + { + url: "/@{@classInfo.ClassName.Replace("Service", "")}/@{@classInfo.ClassMethodInfos[j].MethodName}@url, + method: "@{if(classInfo.ClassMethodInfos[j].HttpName!="[HttpGet]"){post}else{get} }", + data, + @{if(isDownloadFile){ responseType: "arraybuffer", + }else{ } + } + @{if(isPrintBy){ filename:'@classInfo.ClassName.Replace("Service","")' + }else{ } + } + } + ) + }; + + } + } + } +} + +} + +const @{@classInfo.ClassName.StringToProtectedProerty()}= new @{@classInfo.ClassName}(); +export default @{@classInfo.ClassName.StringToProtectedProerty()}; \ No newline at end of file diff --git a/WebVue/src/data/auto/abstractSearchCriteria.ts b/WebVue/src/data/auto/abstractSearchCriteria.ts new file mode 100644 index 0000000..183522a --- /dev/null +++ b/WebVue/src/data/auto/abstractSearchCriteria.ts @@ -0,0 +1,18 @@ + +import { SearchFilter } from "./searchFilter"; +import { GridColumnInfo } from "./gridColumnInfo"; +import { SelectOption } from "./selectOption"; +export class AbstractSearchCriteria +{ + public limit: number = 0; + public page: number = 0; + public clear: number = 0; + public orderby: string = ""; + public orderbytag: string = ""; + public Filter: SearchFilter[] = []; + public IsModal: boolean =false; + public ReportName: string = ""; + public GridColumns: GridColumnInfo[] = []; + public SelectOptions: SelectOption[] = []; + +} diff --git a/WebVue/src/data/auto/biometricLoginChallengeDto.ts b/WebVue/src/data/auto/biometricLoginChallengeDto.ts new file mode 100644 index 0000000..91a925a --- /dev/null +++ b/WebVue/src/data/auto/biometricLoginChallengeDto.ts @@ -0,0 +1,7 @@ + +export class BiometricLoginChallengeDto +{ + public RequestOptionsJson: string = ""; + public ChallengeId: string = ""; + +} diff --git a/WebVue/src/data/auto/biometricRegistrationResultDto.ts b/WebVue/src/data/auto/biometricRegistrationResultDto.ts new file mode 100644 index 0000000..d852bd0 --- /dev/null +++ b/WebVue/src/data/auto/biometricRegistrationResultDto.ts @@ -0,0 +1,6 @@ + +export class BiometricRegistrationResultDto +{ + public CredentialIdBase64Url: string = ""; + +} diff --git a/WebVue/src/data/auto/finishBiometricLoginData.ts b/WebVue/src/data/auto/finishBiometricLoginData.ts new file mode 100644 index 0000000..65bf2c2 --- /dev/null +++ b/WebVue/src/data/auto/finishBiometricLoginData.ts @@ -0,0 +1,9 @@ + +export class FinishBiometricLoginData +{ + public Username: string = ""; + public AssertionJson: string = ""; + public RequestOptionsJson: string = ""; + public ChallengeId: string = ""; + +} diff --git a/WebVue/src/data/auto/finishBiometricRegistrationData.ts b/WebVue/src/data/auto/finishBiometricRegistrationData.ts new file mode 100644 index 0000000..5e787d0 --- /dev/null +++ b/WebVue/src/data/auto/finishBiometricRegistrationData.ts @@ -0,0 +1,7 @@ + +export class FinishBiometricRegistrationData +{ + public AttestationJson: string = ""; + public CreationOptionsJson: string = ""; + +} diff --git a/WebVue/src/data/auto/gridColumnInfo.ts b/WebVue/src/data/auto/gridColumnInfo.ts new file mode 100644 index 0000000..bb94f0f --- /dev/null +++ b/WebVue/src/data/auto/gridColumnInfo.ts @@ -0,0 +1,11 @@ + +export class GridColumnInfo +{ + public title: string = ""; + public dataIndex: string = ""; + public sequence: number = 0; + public align: string = ""; + public hidden: string = ""; + public format: string = ""; + +} diff --git a/WebVue/src/data/auto/jwtInfo.ts b/WebVue/src/data/auto/jwtInfo.ts new file mode 100644 index 0000000..982f8e1 --- /dev/null +++ b/WebVue/src/data/auto/jwtInfo.ts @@ -0,0 +1,8 @@ + +export class JwtInfo +{ + public AccessToken: string = ""; + public RefreshToken: string = ""; + public CreatedTime: Date = new Date(); + +} diff --git a/WebVue/src/data/auto/localeData.ts b/WebVue/src/data/auto/localeData.ts new file mode 100644 index 0000000..d3f1cf8 --- /dev/null +++ b/WebVue/src/data/auto/localeData.ts @@ -0,0 +1,9 @@ + +import { LocaleDisplayData } from "./localeDisplayData"; +export class LocaleData +{ + public Inserts: LocaleDisplayData[] = []; + public Updates: LocaleDisplayData[] = []; + public Deletes: LocaleDisplayData[] = []; + +} diff --git a/WebVue/src/data/auto/localeDisplayData.ts b/WebVue/src/data/auto/localeDisplayData.ts new file mode 100644 index 0000000..2bd8999 --- /dev/null +++ b/WebVue/src/data/auto/localeDisplayData.ts @@ -0,0 +1,9 @@ + +import { LocaleEntity } from "./localeEntity"; +export class LocaleDisplayData extends LocaleEntity +{ + public OrgGroupName: string = ""; + public OrgLang: string = ""; + public OrgName: string = ""; + +} diff --git a/WebVue/src/data/auto/localeEntity.ts b/WebVue/src/data/auto/localeEntity.ts new file mode 100644 index 0000000..e115fbc --- /dev/null +++ b/WebVue/src/data/auto/localeEntity.ts @@ -0,0 +1,34 @@ + +export class LocaleEntity +{ + public CreatedBy: string = ""; + public CreatedDatetime: Date = new Date(); + public GroupName: string = ""; + public Lang: string = ""; + public Name: string = ""; + public OrderBy: number = 0; + public UpdatedBy: string = ""; + public UpdatedDatetime: Date = new Date(); + public Value: string = ""; + + static readonly CREATED_BY : string ='CreatedBy'; + static readonly CREATED_DATETIME : string ='CreatedDatetime'; + static readonly GROUP_NAME : string ='GroupName'; + static readonly LANG : string ='Lang'; + static readonly NAME : string ='Name'; + static readonly ORDER_BY : string ='OrderBy'; + static readonly UPDATED_BY : string ='UpdatedBy'; + static readonly UPDATED_DATETIME : string ='UpdatedDatetime'; + static readonly VALUE : string ='Value'; + static readonly DB_NAME_LOCALE : string ='locale'; + static readonly DB_NAME_FIELDS : string ='created_by,created_datetime,group_name,lang,name,order_by,updated_by,updated_datetime,value'; + static readonly DB_CREATED_BY : string ='created_by'; + static readonly DB_CREATED_DATETIME : string ='created_datetime'; + static readonly DB_GROUP_NAME : string ='group_name'; + static readonly DB_LANG : string ='lang'; + static readonly DB_NAME : string ='name'; + static readonly DB_ORDER_BY : string ='order_by'; + static readonly DB_UPDATED_BY : string ='updated_by'; + static readonly DB_UPDATED_DATETIME : string ='updated_datetime'; + static readonly DB_VALUE : string ='value'; +} diff --git a/WebVue/src/data/auto/localeEntityKey.ts b/WebVue/src/data/auto/localeEntityKey.ts new file mode 100644 index 0000000..64f5dc4 --- /dev/null +++ b/WebVue/src/data/auto/localeEntityKey.ts @@ -0,0 +1,8 @@ + +export class LocaleEntityKey +{ + public GroupName: string = ""; + public Lang: string = ""; + public Name: string = ""; + +} diff --git a/WebVue/src/data/auto/localeResultData.ts b/WebVue/src/data/auto/localeResultData.ts new file mode 100644 index 0000000..d4eb541 --- /dev/null +++ b/WebVue/src/data/auto/localeResultData.ts @@ -0,0 +1,8 @@ + +import { LocaleDisplayData } from "./localeDisplayData"; +import { SearchCriteriaResultData } from "./searchCriteriaResultData"; +export class LocaleResultData extends SearchCriteriaResultData +{ + public Datas: LocaleDisplayData[] = []; + +} diff --git a/WebVue/src/data/auto/localeSearchCriteria.ts b/WebVue/src/data/auto/localeSearchCriteria.ts new file mode 100644 index 0000000..e9839b1 --- /dev/null +++ b/WebVue/src/data/auto/localeSearchCriteria.ts @@ -0,0 +1,6 @@ + +import { AbstractSearchCriteria } from "./abstractSearchCriteria"; +export class LocaleSearchCriteria extends AbstractSearchCriteria +{ + +} diff --git a/WebVue/src/data/auto/loginData.ts b/WebVue/src/data/auto/loginData.ts new file mode 100644 index 0000000..b7ad253 --- /dev/null +++ b/WebVue/src/data/auto/loginData.ts @@ -0,0 +1,12 @@ + +export class LoginData +{ + public UserName: string = ""; + public AgentUserName: string = ""; + public UserMobile: string = ""; + public UserPassword: string = ""; + public RsaUserPassword: string = ""; + public Guid: string = ""; + public Culture: string = ""; + +} diff --git a/WebVue/src/data/auto/loginProfile.ts b/WebVue/src/data/auto/loginProfile.ts new file mode 100644 index 0000000..cc4abde --- /dev/null +++ b/WebVue/src/data/auto/loginProfile.ts @@ -0,0 +1,14 @@ + +import { JwtInfo } from "./jwtInfo"; +import { SecurityUserPermissionInfo } from "./securityUserPermissionInfo"; +export class LoginProfile +{ + public Token: JwtInfo = new JwtInfo(); + public UserType: string = ""; + public Username: string = ""; + public UserLocalName: string = ""; + public UserEngName: string = ""; + public UserMobile: string = ""; + public PermissionInfo: SecurityUserPermissionInfo = new SecurityUserPermissionInfo(); + +} diff --git a/WebVue/src/data/auto/registerData.ts b/WebVue/src/data/auto/registerData.ts new file mode 100644 index 0000000..df7dc3a --- /dev/null +++ b/WebVue/src/data/auto/registerData.ts @@ -0,0 +1,11 @@ + +export class RegisterData +{ + public UserName: string = ""; + public UserMobile: string = ""; + public UserPassword: string = ""; + public ConfirmUserPassword: string = ""; + public RsaUserPassword: string = ""; + public Agree: string = ""; + +} diff --git a/WebVue/src/data/auto/searchCriteriaResultData.ts b/WebVue/src/data/auto/searchCriteriaResultData.ts new file mode 100644 index 0000000..43e4d62 --- /dev/null +++ b/WebVue/src/data/auto/searchCriteriaResultData.ts @@ -0,0 +1,10 @@ + +export class SearchCriteriaResultData +{ + public Limit: number = 0; + public Page: number = 0; + public Total: number = 0; + public Sql: string = ""; + public ErrorMessage: string = ""; + +} diff --git a/WebVue/src/data/auto/searchFilter.ts b/WebVue/src/data/auto/searchFilter.ts new file mode 100644 index 0000000..f7b611a --- /dev/null +++ b/WebVue/src/data/auto/searchFilter.ts @@ -0,0 +1,11 @@ + +export class SearchFilter +{ + public Column: string = ""; + public Type: string = ""; + public Operator: string = ""; + public Value: string = ""; + public Value1: string = ""; + public Values: string[]= []; + +} diff --git a/WebVue/src/data/auto/securityActorData.ts b/WebVue/src/data/auto/securityActorData.ts new file mode 100644 index 0000000..2a6049c --- /dev/null +++ b/WebVue/src/data/auto/securityActorData.ts @@ -0,0 +1,11 @@ + +import { SecurityActorEntity } from "./securityActorEntity"; +import { SecurityActorGroupViewEntity } from "./securityActorGroupViewEntity"; +import { SecurityUserActorViewEntity } from "./securityUserActorViewEntity"; +export class SecurityActorData +{ + public SecurityActor: SecurityActorEntity = new SecurityActorEntity(); + public SecurityActorGroups: SecurityActorGroupViewEntity[] = []; + public SecurityUserActors: SecurityUserActorViewEntity[] = []; + +} diff --git a/WebVue/src/data/auto/securityActorEntity.ts b/WebVue/src/data/auto/securityActorEntity.ts new file mode 100644 index 0000000..2533615 --- /dev/null +++ b/WebVue/src/data/auto/securityActorEntity.ts @@ -0,0 +1,28 @@ + +export class SecurityActorEntity +{ + public ActorEngName: string = ""; + public ActorLocalName: string = ""; + public ActorName: string = ""; + public CreatedBy: string = ""; + public CreatedDatetime: Date = new Date(); + public UpdatedBy: string = ""; + public UpdatedDatetime: Date = new Date(); + + static readonly ACTOR_ENG_NAME : string ='ActorEngName'; + static readonly ACTOR_LOCAL_NAME : string ='ActorLocalName'; + static readonly ACTOR_NAME : string ='ActorName'; + static readonly CREATED_BY : string ='CreatedBy'; + static readonly CREATED_DATETIME : string ='CreatedDatetime'; + static readonly UPDATED_BY : string ='UpdatedBy'; + static readonly UPDATED_DATETIME : string ='UpdatedDatetime'; + static readonly DB_NAME_SECURITY_ACTOR : string ='security_actor'; + static readonly DB_NAME_FIELDS : string ='actor_eng_name,actor_local_name,actor_name,created_by,created_datetime,updated_by,updated_datetime'; + static readonly DB_ACTOR_ENG_NAME : string ='actor_eng_name'; + static readonly DB_ACTOR_LOCAL_NAME : string ='actor_local_name'; + static readonly DB_ACTOR_NAME : string ='actor_name'; + static readonly DB_CREATED_BY : string ='created_by'; + static readonly DB_CREATED_DATETIME : string ='created_datetime'; + static readonly DB_UPDATED_BY : string ='updated_by'; + static readonly DB_UPDATED_DATETIME : string ='updated_datetime'; +} diff --git a/WebVue/src/data/auto/securityActorGroupEntity.ts b/WebVue/src/data/auto/securityActorGroupEntity.ts new file mode 100644 index 0000000..5f56f2f --- /dev/null +++ b/WebVue/src/data/auto/securityActorGroupEntity.ts @@ -0,0 +1,25 @@ + +export class SecurityActorGroupEntity +{ + public ActorName: string = ""; + public CreatedBy: string = ""; + public CreatedDatetime: Date = new Date(); + public GroupName: string = ""; + public UpdatedBy: string = ""; + public UpdatedDatetime: Date = new Date(); + + static readonly ACTOR_NAME : string ='ActorName'; + static readonly CREATED_BY : string ='CreatedBy'; + static readonly CREATED_DATETIME : string ='CreatedDatetime'; + static readonly GROUP_NAME : string ='GroupName'; + static readonly UPDATED_BY : string ='UpdatedBy'; + static readonly UPDATED_DATETIME : string ='UpdatedDatetime'; + static readonly DB_NAME_SECURITY_ACTOR_GROUP : string ='security_actor_group'; + static readonly DB_NAME_FIELDS : string ='actor_name,created_by,created_datetime,group_name,updated_by,updated_datetime'; + static readonly DB_ACTOR_NAME : string ='actor_name'; + static readonly DB_CREATED_BY : string ='created_by'; + static readonly DB_CREATED_DATETIME : string ='created_datetime'; + static readonly DB_GROUP_NAME : string ='group_name'; + static readonly DB_UPDATED_BY : string ='updated_by'; + static readonly DB_UPDATED_DATETIME : string ='updated_datetime'; +} diff --git a/WebVue/src/data/auto/securityActorGroupEntityKey.ts b/WebVue/src/data/auto/securityActorGroupEntityKey.ts new file mode 100644 index 0000000..6cf0812 --- /dev/null +++ b/WebVue/src/data/auto/securityActorGroupEntityKey.ts @@ -0,0 +1,7 @@ + +export class SecurityActorGroupEntityKey +{ + public ActorName: string = ""; + public GroupName: string = ""; + +} diff --git a/WebVue/src/data/auto/securityActorGroupViewEntity.ts b/WebVue/src/data/auto/securityActorGroupViewEntity.ts new file mode 100644 index 0000000..340a3fc --- /dev/null +++ b/WebVue/src/data/auto/securityActorGroupViewEntity.ts @@ -0,0 +1,19 @@ + +export class SecurityActorGroupViewEntity +{ + public ActorLocalName: string = ""; + public ActorName: string = ""; + public GroupLocalName: string = ""; + public GroupName: string = ""; + + static readonly ACTOR_LOCAL_NAME : string ='ActorLocalName'; + static readonly ACTOR_NAME : string ='ActorName'; + static readonly GROUP_LOCAL_NAME : string ='GroupLocalName'; + static readonly GROUP_NAME : string ='GroupName'; + static readonly DB_NAME_SECURITY_ACTOR_GROUP_VIEW : string ='security_actor_group_view'; + static readonly DB_NAME_FIELDS : string ='actor_local_name,actor_name,group_local_name,group_name'; + static readonly DB_ACTOR_LOCAL_NAME : string ='actor_local_name'; + static readonly DB_ACTOR_NAME : string ='actor_name'; + static readonly DB_GROUP_LOCAL_NAME : string ='group_local_name'; + static readonly DB_GROUP_NAME : string ='group_name'; +} diff --git a/WebVue/src/data/auto/securityActorResultData.ts b/WebVue/src/data/auto/securityActorResultData.ts new file mode 100644 index 0000000..708108f --- /dev/null +++ b/WebVue/src/data/auto/securityActorResultData.ts @@ -0,0 +1,8 @@ + +import { SecurityActorEntity } from "./securityActorEntity"; +import { SearchCriteriaResultData } from "./searchCriteriaResultData"; +export class SecurityActorResultData extends SearchCriteriaResultData +{ + public Datas: SecurityActorEntity[] = []; + +} diff --git a/WebVue/src/data/auto/securityActorSearchCriteria.ts b/WebVue/src/data/auto/securityActorSearchCriteria.ts new file mode 100644 index 0000000..213f2e0 --- /dev/null +++ b/WebVue/src/data/auto/securityActorSearchCriteria.ts @@ -0,0 +1,6 @@ + +import { AbstractSearchCriteria } from "./abstractSearchCriteria"; +export class SecurityActorSearchCriteria extends AbstractSearchCriteria +{ + +} diff --git a/WebVue/src/data/auto/securityFunctionData.ts b/WebVue/src/data/auto/securityFunctionData.ts new file mode 100644 index 0000000..964e12e --- /dev/null +++ b/WebVue/src/data/auto/securityFunctionData.ts @@ -0,0 +1,10 @@ + +import { SecurityFunctionDisplayData } from "./securityFunctionDisplayData"; +import { SecurityFunctionMapViewEntity } from "./securityFunctionMapViewEntity"; +export class SecurityFunctionData +{ + public SecurityFunction: SecurityFunctionDisplayData = new SecurityFunctionDisplayData(); + public SecurityFunctionMapParents: SecurityFunctionMapViewEntity[] = []; + public SecurityFunctionMapSons: SecurityFunctionMapViewEntity[] = []; + +} diff --git a/WebVue/src/data/auto/securityFunctionDisplayData.ts b/WebVue/src/data/auto/securityFunctionDisplayData.ts new file mode 100644 index 0000000..3ae321b --- /dev/null +++ b/WebVue/src/data/auto/securityFunctionDisplayData.ts @@ -0,0 +1,11 @@ + +import { SecurityFunctionEntity } from "./securityFunctionEntity"; +export class SecurityFunctionDisplayData extends SecurityFunctionEntity +{ + public FunctionNameParent: string = ""; + public Orderby: number = 0; + public PermissionName: string = ""; + public SonSecurityFunctions: string[]= []; + + static readonly PERMISSION_NAME : string ='PermissionName'; +} diff --git a/WebVue/src/data/auto/securityFunctionEntity.ts b/WebVue/src/data/auto/securityFunctionEntity.ts new file mode 100644 index 0000000..75ed17d --- /dev/null +++ b/WebVue/src/data/auto/securityFunctionEntity.ts @@ -0,0 +1,43 @@ + +export class SecurityFunctionEntity +{ + public ApiRoute: string = ""; + public CreatedBy: string = ""; + public CreatedDatetime: Date = new Date(); + public FunctionEngName: string = ""; + public FunctionIndc: string = ""; + public FunctionLocalName: string = ""; + public FunctionName: string = ""; + public Icon: string = ""; + public PageName: string = ""; + public PageUrl: string = ""; + public UpdatedBy: string = ""; + public UpdatedDatetime: Date = new Date(); + + static readonly API_ROUTE : string ='ApiRoute'; + static readonly CREATED_BY : string ='CreatedBy'; + static readonly CREATED_DATETIME : string ='CreatedDatetime'; + static readonly FUNCTION_ENG_NAME : string ='FunctionEngName'; + static readonly FUNCTION_INDC : string ='FunctionIndc'; + static readonly FUNCTION_LOCAL_NAME : string ='FunctionLocalName'; + static readonly FUNCTION_NAME : string ='FunctionName'; + static readonly ICON : string ='Icon'; + static readonly PAGE_NAME : string ='PageName'; + static readonly PAGE_URL : string ='PageUrl'; + static readonly UPDATED_BY : string ='UpdatedBy'; + static readonly UPDATED_DATETIME : string ='UpdatedDatetime'; + static readonly DB_NAME_SECURITY_FUNCTION : string ='security_function'; + static readonly DB_NAME_FIELDS : string ='api_route,created_by,created_datetime,function_eng_name,function_indc,function_local_name,function_name,icon,page_name,page_url,updated_by,updated_datetime'; + static readonly DB_API_ROUTE : string ='api_route'; + static readonly DB_CREATED_BY : string ='created_by'; + static readonly DB_CREATED_DATETIME : string ='created_datetime'; + static readonly DB_FUNCTION_ENG_NAME : string ='function_eng_name'; + static readonly DB_FUNCTION_INDC : string ='function_indc'; + static readonly DB_FUNCTION_LOCAL_NAME : string ='function_local_name'; + static readonly DB_FUNCTION_NAME : string ='function_name'; + static readonly DB_ICON : string ='icon'; + static readonly DB_PAGE_NAME : string ='page_name'; + static readonly DB_PAGE_URL : string ='page_url'; + static readonly DB_UPDATED_BY : string ='updated_by'; + static readonly DB_UPDATED_DATETIME : string ='updated_datetime'; +} diff --git a/WebVue/src/data/auto/securityFunctionMapEntity.ts b/WebVue/src/data/auto/securityFunctionMapEntity.ts new file mode 100644 index 0000000..47e2de5 --- /dev/null +++ b/WebVue/src/data/auto/securityFunctionMapEntity.ts @@ -0,0 +1,28 @@ + +export class SecurityFunctionMapEntity +{ + public CreatedBy: string = ""; + public CreatedDatetime: Date = new Date(); + public FunctionNameParent: string = ""; + public FunctionNameSon: string = ""; + public Orderby: number = 0; + public UpdatedBy: string = ""; + public UpdatedDatetime: Date = new Date(); + + static readonly CREATED_BY : string ='CreatedBy'; + static readonly CREATED_DATETIME : string ='CreatedDatetime'; + static readonly FUNCTION_NAME_PARENT : string ='FunctionNameParent'; + static readonly FUNCTION_NAME_SON : string ='FunctionNameSon'; + static readonly ORDERBY : string ='Orderby'; + static readonly UPDATED_BY : string ='UpdatedBy'; + static readonly UPDATED_DATETIME : string ='UpdatedDatetime'; + static readonly DB_NAME_SECURITY_FUNCTION_MAP : string ='security_function_map'; + static readonly DB_NAME_FIELDS : string ='created_by,created_datetime,function_name_parent,function_name_son,orderby,updated_by,updated_datetime'; + static readonly DB_CREATED_BY : string ='created_by'; + static readonly DB_CREATED_DATETIME : string ='created_datetime'; + static readonly DB_FUNCTION_NAME_PARENT : string ='function_name_parent'; + static readonly DB_FUNCTION_NAME_SON : string ='function_name_son'; + static readonly DB_ORDERBY : string ='orderby'; + static readonly DB_UPDATED_BY : string ='updated_by'; + static readonly DB_UPDATED_DATETIME : string ='updated_datetime'; +} diff --git a/WebVue/src/data/auto/securityFunctionMapEntityKey.ts b/WebVue/src/data/auto/securityFunctionMapEntityKey.ts new file mode 100644 index 0000000..4227089 --- /dev/null +++ b/WebVue/src/data/auto/securityFunctionMapEntityKey.ts @@ -0,0 +1,7 @@ + +export class SecurityFunctionMapEntityKey +{ + public FunctionNameParent: string = ""; + public FunctionNameSon: string = ""; + +} diff --git a/WebVue/src/data/auto/securityFunctionMapViewEntity.ts b/WebVue/src/data/auto/securityFunctionMapViewEntity.ts new file mode 100644 index 0000000..7abde73 --- /dev/null +++ b/WebVue/src/data/auto/securityFunctionMapViewEntity.ts @@ -0,0 +1,25 @@ + +export class SecurityFunctionMapViewEntity +{ + public Orderby: number = 0; + public ParentFunctionLocalName: string = ""; + public ParentFunctionName: string = ""; + public SonFunctionLocalName: string = ""; + public SonFunctionName: string = ""; + public SonPageName: string = ""; + + static readonly ORDERBY : string ='Orderby'; + static readonly PARENT_FUNCTION_LOCAL_NAME : string ='ParentFunctionLocalName'; + static readonly PARENT_FUNCTION_NAME : string ='ParentFunctionName'; + static readonly SON_FUNCTION_LOCAL_NAME : string ='SonFunctionLocalName'; + static readonly SON_FUNCTION_NAME : string ='SonFunctionName'; + static readonly SON_PAGE_NAME : string ='SonPageName'; + static readonly DB_NAME_SECURITY_FUNCTION_MAP_VIEW : string ='security_function_map_view'; + static readonly DB_NAME_FIELDS : string ='orderby,parent_function_local_name,parent_function_name,son_function_local_name,son_function_name,son_page_name'; + static readonly DB_ORDERBY : string ='orderby'; + static readonly DB_PARENT_FUNCTION_LOCAL_NAME : string ='parent_function_local_name'; + static readonly DB_PARENT_FUNCTION_NAME : string ='parent_function_name'; + static readonly DB_SON_FUNCTION_LOCAL_NAME : string ='son_function_local_name'; + static readonly DB_SON_FUNCTION_NAME : string ='son_function_name'; + static readonly DB_SON_PAGE_NAME : string ='son_page_name'; +} diff --git a/WebVue/src/data/auto/securityFunctionResultData.ts b/WebVue/src/data/auto/securityFunctionResultData.ts new file mode 100644 index 0000000..d50c5fc --- /dev/null +++ b/WebVue/src/data/auto/securityFunctionResultData.ts @@ -0,0 +1,11 @@ + +import { SecurityFunctionDisplayData } from "./securityFunctionDisplayData"; +import { SecurityFunctionMapEntity } from "./securityFunctionMapEntity"; +import { SearchCriteriaResultData } from "./searchCriteriaResultData"; +export class SecurityFunctionResultData extends SearchCriteriaResultData +{ + public SecurityFunctionDisplayDatas: SecurityFunctionDisplayData[] = []; + public SecurityFunctionMaps: SecurityFunctionMapEntity[] = []; + + static readonly BOOTUP : string ='BOOTUP'; +} diff --git a/WebVue/src/data/auto/securityFunctionSearchCriteria.ts b/WebVue/src/data/auto/securityFunctionSearchCriteria.ts new file mode 100644 index 0000000..e5ab375 --- /dev/null +++ b/WebVue/src/data/auto/securityFunctionSearchCriteria.ts @@ -0,0 +1,10 @@ + +import { AbstractSearchCriteria } from "./abstractSearchCriteria"; +export class SecurityFunctionSearchCriteria extends AbstractSearchCriteria +{ + public FunctionLocalName: string = ""; + public FunctionName: string = ""; + public FunctionIndc: string = ""; + public FunctionIndcEnable?: Date= null!; + +} diff --git a/WebVue/src/data/auto/securityGeneratorNumberData.ts b/WebVue/src/data/auto/securityGeneratorNumberData.ts new file mode 100644 index 0000000..a66dccc --- /dev/null +++ b/WebVue/src/data/auto/securityGeneratorNumberData.ts @@ -0,0 +1,8 @@ + +import { SecurityGeneratorNumberEntity } from "./securityGeneratorNumberEntity"; +import { SearchCriteriaResultData } from "./searchCriteriaResultData"; +export class SecurityGeneratorNumberData extends SearchCriteriaResultData +{ + public datas: SecurityGeneratorNumberEntity[] = []; + +} diff --git a/WebVue/src/data/auto/securityGeneratorNumberEntity.ts b/WebVue/src/data/auto/securityGeneratorNumberEntity.ts new file mode 100644 index 0000000..dbc52b5 --- /dev/null +++ b/WebVue/src/data/auto/securityGeneratorNumberEntity.ts @@ -0,0 +1,43 @@ + +export class SecurityGeneratorNumberEntity +{ + public CreatedBy: string = ""; + public CreatedDatetime: Date = new Date(); + public Format: string = ""; + public GeneratorId: number = 0; + public LastGeneratorDate: Date = new Date(); + public NextId: number = 0; + public Prefix: string = ""; + public RefreshPeriod: string = ""; + public SubsystemId: string = ""; + public SystemId: string = ""; + public UpdatedBy: string = ""; + public UpdatedDatetime: Date = new Date(); + + static readonly CREATED_BY : string ='CreatedBy'; + static readonly CREATED_DATETIME : string ='CreatedDatetime'; + static readonly FORMAT : string ='Format'; + static readonly GENERATOR_ID : string ='GeneratorId'; + static readonly LAST_GENERATOR_DATE : string ='LastGeneratorDate'; + static readonly NEXT_ID : string ='NextId'; + static readonly PREFIX : string ='Prefix'; + static readonly REFRESH_PERIOD : string ='RefreshPeriod'; + static readonly SUBSYSTEM_ID : string ='SubsystemId'; + static readonly SYSTEM_ID : string ='SystemId'; + static readonly UPDATED_BY : string ='UpdatedBy'; + static readonly UPDATED_DATETIME : string ='UpdatedDatetime'; + static readonly DB_NAME_SECURITY_GENERATOR_NUMBER : string ='security_generator_number'; + static readonly DB_NAME_FIELDS : string ='created_by,created_datetime,format,generator_id,last_generator_date,next_id,prefix,refresh_period,subsystem_id,system_id,updated_by,updated_datetime'; + static readonly DB_CREATED_BY : string ='created_by'; + static readonly DB_CREATED_DATETIME : string ='created_datetime'; + static readonly DB_FORMAT : string ='format'; + static readonly DB_GENERATOR_ID : string ='generator_id'; + static readonly DB_LAST_GENERATOR_DATE : string ='last_generator_date'; + static readonly DB_NEXT_ID : string ='next_id'; + static readonly DB_PREFIX : string ='prefix'; + static readonly DB_REFRESH_PERIOD : string ='refresh_period'; + static readonly DB_SUBSYSTEM_ID : string ='subsystem_id'; + static readonly DB_SYSTEM_ID : string ='system_id'; + static readonly DB_UPDATED_BY : string ='updated_by'; + static readonly DB_UPDATED_DATETIME : string ='updated_datetime'; +} diff --git a/WebVue/src/data/auto/securityGeneratorNumberResultData.ts b/WebVue/src/data/auto/securityGeneratorNumberResultData.ts new file mode 100644 index 0000000..2cd5f20 --- /dev/null +++ b/WebVue/src/data/auto/securityGeneratorNumberResultData.ts @@ -0,0 +1,8 @@ + +import { SecurityGeneratorNumberEntity } from "./securityGeneratorNumberEntity"; +import { SearchCriteriaResultData } from "./searchCriteriaResultData"; +export class SecurityGeneratorNumberResultData extends SearchCriteriaResultData +{ + public Datas: SecurityGeneratorNumberEntity[] = []; + +} diff --git a/WebVue/src/data/auto/securityGeneratorNumberSearchCriteria.ts b/WebVue/src/data/auto/securityGeneratorNumberSearchCriteria.ts new file mode 100644 index 0000000..18ed402 --- /dev/null +++ b/WebVue/src/data/auto/securityGeneratorNumberSearchCriteria.ts @@ -0,0 +1,6 @@ + +import { AbstractSearchCriteria } from "./abstractSearchCriteria"; +export class SecurityGeneratorNumberSearchCriteria extends AbstractSearchCriteria +{ + +} diff --git a/WebVue/src/data/auto/securityGroupData.ts b/WebVue/src/data/auto/securityGroupData.ts new file mode 100644 index 0000000..b7a4df1 --- /dev/null +++ b/WebVue/src/data/auto/securityGroupData.ts @@ -0,0 +1,13 @@ + +import { SecurityGroupEntity } from "./securityGroupEntity"; +import { SecurityGroupPermissionViewDisplayData } from "./securityGroupPermissionViewDisplayData"; +import { SecurityGroupPermissionDependentViewDisplayData } from "./securityGroupPermissionDependentViewDisplayData"; +import { SecurityActorGroupViewEntity } from "./securityActorGroupViewEntity"; +export class SecurityGroupData +{ + public SecurityGroup: SecurityGroupEntity = new SecurityGroupEntity(); + public SecurityGroupPermissionViews: SecurityGroupPermissionViewDisplayData[] = []; + public SecurityGroupPermissionDependentViews: SecurityGroupPermissionDependentViewDisplayData[] = []; + public SecurityActorGroups: SecurityActorGroupViewEntity[] = []; + +} diff --git a/WebVue/src/data/auto/securityGroupEntity.ts b/WebVue/src/data/auto/securityGroupEntity.ts new file mode 100644 index 0000000..dd795ee --- /dev/null +++ b/WebVue/src/data/auto/securityGroupEntity.ts @@ -0,0 +1,28 @@ + +export class SecurityGroupEntity +{ + public CreatedBy: string = ""; + public CreatedDatetime: Date = new Date(); + public GroupEngName: string = ""; + public GroupLocalName: string = ""; + public GroupName: string = ""; + public UpdatedBy: string = ""; + public UpdatedDatetime: Date = new Date(); + + static readonly CREATED_BY : string ='CreatedBy'; + static readonly CREATED_DATETIME : string ='CreatedDatetime'; + static readonly GROUP_ENG_NAME : string ='GroupEngName'; + static readonly GROUP_LOCAL_NAME : string ='GroupLocalName'; + static readonly GROUP_NAME : string ='GroupName'; + static readonly UPDATED_BY : string ='UpdatedBy'; + static readonly UPDATED_DATETIME : string ='UpdatedDatetime'; + static readonly DB_NAME_SECURITY_GROUP : string ='security_group'; + static readonly DB_NAME_FIELDS : string ='created_by,created_datetime,group_eng_name,group_local_name,group_name,updated_by,updated_datetime'; + static readonly DB_CREATED_BY : string ='created_by'; + static readonly DB_CREATED_DATETIME : string ='created_datetime'; + static readonly DB_GROUP_ENG_NAME : string ='group_eng_name'; + static readonly DB_GROUP_LOCAL_NAME : string ='group_local_name'; + static readonly DB_GROUP_NAME : string ='group_name'; + static readonly DB_UPDATED_BY : string ='updated_by'; + static readonly DB_UPDATED_DATETIME : string ='updated_datetime'; +} diff --git a/WebVue/src/data/auto/securityGroupPermissionDependentEntity.ts b/WebVue/src/data/auto/securityGroupPermissionDependentEntity.ts new file mode 100644 index 0000000..9d450bc --- /dev/null +++ b/WebVue/src/data/auto/securityGroupPermissionDependentEntity.ts @@ -0,0 +1,40 @@ + +export class SecurityGroupPermissionDependentEntity +{ + public AmendIndc: string = ""; + public CreateIndc: string = ""; + public CreatedBy: string = ""; + public CreatedDatetime: Date = new Date(); + public DeleteIndc: string = ""; + public DependentDetailName: string = ""; + public GroupName: string = ""; + public PermissionName: string = ""; + public UpdatedBy: string = ""; + public UpdatedDatetime: Date = new Date(); + public ViewIndc: string = ""; + + static readonly AMEND_INDC : string ='AmendIndc'; + static readonly CREATE_INDC : string ='CreateIndc'; + static readonly CREATED_BY : string ='CreatedBy'; + static readonly CREATED_DATETIME : string ='CreatedDatetime'; + static readonly DELETE_INDC : string ='DeleteIndc'; + static readonly DEPENDENT_DETAIL_NAME : string ='DependentDetailName'; + static readonly GROUP_NAME : string ='GroupName'; + static readonly PERMISSION_NAME : string ='PermissionName'; + static readonly UPDATED_BY : string ='UpdatedBy'; + static readonly UPDATED_DATETIME : string ='UpdatedDatetime'; + static readonly VIEW_INDC : string ='ViewIndc'; + static readonly DB_NAME_SECURITY_GROUP_PERMISSION_DEPENDENT : string ='security_group_permission_dependent'; + static readonly DB_NAME_FIELDS : string ='amend_indc,create_indc,created_by,created_datetime,delete_indc,dependent_detail_name,group_name,permission_name,updated_by,updated_datetime,view_indc'; + static readonly DB_AMEND_INDC : string ='amend_indc'; + static readonly DB_CREATE_INDC : string ='create_indc'; + static readonly DB_CREATED_BY : string ='created_by'; + static readonly DB_CREATED_DATETIME : string ='created_datetime'; + static readonly DB_DELETE_INDC : string ='delete_indc'; + static readonly DB_DEPENDENT_DETAIL_NAME : string ='dependent_detail_name'; + static readonly DB_GROUP_NAME : string ='group_name'; + static readonly DB_PERMISSION_NAME : string ='permission_name'; + static readonly DB_UPDATED_BY : string ='updated_by'; + static readonly DB_UPDATED_DATETIME : string ='updated_datetime'; + static readonly DB_VIEW_INDC : string ='view_indc'; +} diff --git a/WebVue/src/data/auto/securityGroupPermissionDependentEntityKey.ts b/WebVue/src/data/auto/securityGroupPermissionDependentEntityKey.ts new file mode 100644 index 0000000..8159c72 --- /dev/null +++ b/WebVue/src/data/auto/securityGroupPermissionDependentEntityKey.ts @@ -0,0 +1,8 @@ + +export class SecurityGroupPermissionDependentEntityKey +{ + public DependentDetailName: string = ""; + public GroupName: string = ""; + public PermissionName: string = ""; + +} diff --git a/WebVue/src/data/auto/securityGroupPermissionDependentViewDisplayData.ts b/WebVue/src/data/auto/securityGroupPermissionDependentViewDisplayData.ts new file mode 100644 index 0000000..9dcfd3b --- /dev/null +++ b/WebVue/src/data/auto/securityGroupPermissionDependentViewDisplayData.ts @@ -0,0 +1,14 @@ + +import { SecurityGroupPermissionDependentViewEntity } from "./securityGroupPermissionDependentViewEntity"; +export class SecurityGroupPermissionDependentViewDisplayData extends SecurityGroupPermissionDependentViewEntity +{ + public IsView: boolean =false; + public IsCreate: boolean =false; + public IsAmend: boolean =false; + public IsDelete: boolean =false; + + static readonly IS_VIEW : string ='IsView'; + static readonly IS_CREATE : string ='IsCreate'; + static readonly IS_AMEND : string ='IsAmend'; + static readonly IS_DELETE : string ='IsDelete'; +} diff --git a/WebVue/src/data/auto/securityGroupPermissionDependentViewEntity.ts b/WebVue/src/data/auto/securityGroupPermissionDependentViewEntity.ts new file mode 100644 index 0000000..fc00734 --- /dev/null +++ b/WebVue/src/data/auto/securityGroupPermissionDependentViewEntity.ts @@ -0,0 +1,37 @@ + +export class SecurityGroupPermissionDependentViewEntity +{ + public AmendIndc: string = ""; + public CreateIndc: string = ""; + public DeleteIndc: string = ""; + public Dependent: string = ""; + public DependentDetailDescription: string = ""; + public DependentDetailName: string = ""; + public GroupName: string = ""; + public PermissionDescription: string = ""; + public PermissionName: string = ""; + public ViewIndc: string = ""; + + static readonly AMEND_INDC : string ='AmendIndc'; + static readonly CREATE_INDC : string ='CreateIndc'; + static readonly DELETE_INDC : string ='DeleteIndc'; + static readonly DEPENDENT : string ='Dependent'; + static readonly DEPENDENT_DETAIL_DESCRIPTION : string ='DependentDetailDescription'; + static readonly DEPENDENT_DETAIL_NAME : string ='DependentDetailName'; + static readonly GROUP_NAME : string ='GroupName'; + static readonly PERMISSION_DESCRIPTION : string ='PermissionDescription'; + static readonly PERMISSION_NAME : string ='PermissionName'; + static readonly VIEW_INDC : string ='ViewIndc'; + static readonly DB_NAME_SECURITY_GROUP_PERMISSION_DEPENDENT_VIEW : string ='security_group_permission_dependent_view'; + static readonly DB_NAME_FIELDS : string ='amend_indc,create_indc,delete_indc,dependent,dependent_detail_description,dependent_detail_name,group_name,permission_description,permission_name,view_indc'; + static readonly DB_AMEND_INDC : string ='amend_indc'; + static readonly DB_CREATE_INDC : string ='create_indc'; + static readonly DB_DELETE_INDC : string ='delete_indc'; + static readonly DB_DEPENDENT : string ='dependent'; + static readonly DB_DEPENDENT_DETAIL_DESCRIPTION : string ='dependent_detail_description'; + static readonly DB_DEPENDENT_DETAIL_NAME : string ='dependent_detail_name'; + static readonly DB_GROUP_NAME : string ='group_name'; + static readonly DB_PERMISSION_DESCRIPTION : string ='permission_description'; + static readonly DB_PERMISSION_NAME : string ='permission_name'; + static readonly DB_VIEW_INDC : string ='view_indc'; +} diff --git a/WebVue/src/data/auto/securityGroupPermissionEntity.ts b/WebVue/src/data/auto/securityGroupPermissionEntity.ts new file mode 100644 index 0000000..c1eb195 --- /dev/null +++ b/WebVue/src/data/auto/securityGroupPermissionEntity.ts @@ -0,0 +1,40 @@ + +export class SecurityGroupPermissionEntity +{ + public AmendIndc: string = ""; + public CreateIndc: string = ""; + public CreatedBy: string = ""; + public CreatedDatetime: Date = new Date(); + public DeleteIndc: string = ""; + public Dependent: string = ""; + public GroupName: string = ""; + public PermissionName: string = ""; + public UpdatedBy: string = ""; + public UpdatedDatetime: Date = new Date(); + public ViewIndc: string = ""; + + static readonly AMEND_INDC : string ='AmendIndc'; + static readonly CREATE_INDC : string ='CreateIndc'; + static readonly CREATED_BY : string ='CreatedBy'; + static readonly CREATED_DATETIME : string ='CreatedDatetime'; + static readonly DELETE_INDC : string ='DeleteIndc'; + static readonly DEPENDENT : string ='Dependent'; + static readonly GROUP_NAME : string ='GroupName'; + static readonly PERMISSION_NAME : string ='PermissionName'; + static readonly UPDATED_BY : string ='UpdatedBy'; + static readonly UPDATED_DATETIME : string ='UpdatedDatetime'; + static readonly VIEW_INDC : string ='ViewIndc'; + static readonly DB_NAME_SECURITY_GROUP_PERMISSION : string ='security_group_permission'; + static readonly DB_NAME_FIELDS : string ='amend_indc,create_indc,created_by,created_datetime,delete_indc,dependent,group_name,permission_name,updated_by,updated_datetime,view_indc'; + static readonly DB_AMEND_INDC : string ='amend_indc'; + static readonly DB_CREATE_INDC : string ='create_indc'; + static readonly DB_CREATED_BY : string ='created_by'; + static readonly DB_CREATED_DATETIME : string ='created_datetime'; + static readonly DB_DELETE_INDC : string ='delete_indc'; + static readonly DB_DEPENDENT : string ='dependent'; + static readonly DB_GROUP_NAME : string ='group_name'; + static readonly DB_PERMISSION_NAME : string ='permission_name'; + static readonly DB_UPDATED_BY : string ='updated_by'; + static readonly DB_UPDATED_DATETIME : string ='updated_datetime'; + static readonly DB_VIEW_INDC : string ='view_indc'; +} diff --git a/WebVue/src/data/auto/securityGroupPermissionEntityKey.ts b/WebVue/src/data/auto/securityGroupPermissionEntityKey.ts new file mode 100644 index 0000000..a6a579f --- /dev/null +++ b/WebVue/src/data/auto/securityGroupPermissionEntityKey.ts @@ -0,0 +1,7 @@ + +export class SecurityGroupPermissionEntityKey +{ + public GroupName: string = ""; + public PermissionName: string = ""; + +} diff --git a/WebVue/src/data/auto/securityGroupPermissionViewDisplayData.ts b/WebVue/src/data/auto/securityGroupPermissionViewDisplayData.ts new file mode 100644 index 0000000..2d6ab5c --- /dev/null +++ b/WebVue/src/data/auto/securityGroupPermissionViewDisplayData.ts @@ -0,0 +1,14 @@ + +import { SecurityGroupPermissionViewEntity } from "./securityGroupPermissionViewEntity"; +export class SecurityGroupPermissionViewDisplayData extends SecurityGroupPermissionViewEntity +{ + public IsView: boolean =false; + public IsCreate: boolean =false; + public IsAmend: boolean =false; + public IsDelete: boolean =false; + + static readonly IS_VIEW : string ='IsView'; + static readonly IS_CREATE : string ='IsCreate'; + static readonly IS_AMEND : string ='IsAmend'; + static readonly IS_DELETE : string ='IsDelete'; +} diff --git a/WebVue/src/data/auto/securityGroupPermissionViewEntity.ts b/WebVue/src/data/auto/securityGroupPermissionViewEntity.ts new file mode 100644 index 0000000..e9cf38e --- /dev/null +++ b/WebVue/src/data/auto/securityGroupPermissionViewEntity.ts @@ -0,0 +1,31 @@ + +export class SecurityGroupPermissionViewEntity +{ + public AmendIndc: string = ""; + public CreateIndc: string = ""; + public DeleteIndc: string = ""; + public Dependent: string = ""; + public GroupName: string = ""; + public PermissionDescription: string = ""; + public PermissionName: string = ""; + public ViewIndc: string = ""; + + static readonly AMEND_INDC : string ='AmendIndc'; + static readonly CREATE_INDC : string ='CreateIndc'; + static readonly DELETE_INDC : string ='DeleteIndc'; + static readonly DEPENDENT : string ='Dependent'; + static readonly GROUP_NAME : string ='GroupName'; + static readonly PERMISSION_DESCRIPTION : string ='PermissionDescription'; + static readonly PERMISSION_NAME : string ='PermissionName'; + static readonly VIEW_INDC : string ='ViewIndc'; + static readonly DB_NAME_SECURITY_GROUP_PERMISSION_VIEW : string ='security_group_permission_view'; + static readonly DB_NAME_FIELDS : string ='amend_indc,create_indc,delete_indc,dependent,group_name,permission_description,permission_name,view_indc'; + static readonly DB_AMEND_INDC : string ='amend_indc'; + static readonly DB_CREATE_INDC : string ='create_indc'; + static readonly DB_DELETE_INDC : string ='delete_indc'; + static readonly DB_DEPENDENT : string ='dependent'; + static readonly DB_GROUP_NAME : string ='group_name'; + static readonly DB_PERMISSION_DESCRIPTION : string ='permission_description'; + static readonly DB_PERMISSION_NAME : string ='permission_name'; + static readonly DB_VIEW_INDC : string ='view_indc'; +} diff --git a/WebVue/src/data/auto/securityGroupResultData.ts b/WebVue/src/data/auto/securityGroupResultData.ts new file mode 100644 index 0000000..6b5055f --- /dev/null +++ b/WebVue/src/data/auto/securityGroupResultData.ts @@ -0,0 +1,8 @@ + +import { SecurityGroupEntity } from "./securityGroupEntity"; +import { SearchCriteriaResultData } from "./searchCriteriaResultData"; +export class SecurityGroupResultData extends SearchCriteriaResultData +{ + public Datas: SecurityGroupEntity[] = []; + +} diff --git a/WebVue/src/data/auto/securityGroupSearchCriteria.ts b/WebVue/src/data/auto/securityGroupSearchCriteria.ts new file mode 100644 index 0000000..ecf3da9 --- /dev/null +++ b/WebVue/src/data/auto/securityGroupSearchCriteria.ts @@ -0,0 +1,6 @@ + +import { AbstractSearchCriteria } from "./abstractSearchCriteria"; +export class SecurityGroupSearchCriteria extends AbstractSearchCriteria +{ + +} diff --git a/WebVue/src/data/auto/securityInitializerTickViewEntity.ts b/WebVue/src/data/auto/securityInitializerTickViewEntity.ts new file mode 100644 index 0000000..6216214 --- /dev/null +++ b/WebVue/src/data/auto/securityInitializerTickViewEntity.ts @@ -0,0 +1,43 @@ + +export class SecurityInitializerTickViewEntity +{ + public SecurityActorUpd?: Date= null!; + public SecurityActorGroupUpd?: Date= null!; + public SecurityFunctionUpd?: Date= null!; + public SecurityFunctionMapUpd?: Date= null!; + public ProductUpd?: Date= null!; + public SecurityGroupPermissionUpd?: Date= null!; + public SecurityGroupPermissionDependentUpd?: Date= null!; + public SecurityMasterUpd?: Date= null!; + public SecurityPermissionUpd?: Date= null!; + public SecurityPermissionDependentUpd?: Date= null!; + public SecurityUserUpd?: Date= null!; + public SecurityUserActorUpd?: Date= null!; + + static readonly SECURITY_ACTOR_UPD : string ='SecurityActorUpd'; + static readonly SECURITY_ACTOR_GROUP_UPD : string ='SecurityActorGroupUpd'; + static readonly SECURITY_FUNCTION_UPD : string ='SecurityFunctionUpd'; + static readonly SECURITY_FUNCTION_MAP_UPD : string ='SecurityFunctionMapUpd'; + static readonly PRODUCT_UPD : string ='ProductUpd'; + static readonly SECURITY_GROUP_PERMISSION_UPD : string ='SecurityGroupPermissionUpd'; + static readonly SECURITY_GROUP_PERMISSION_DEPENDENT_UPD : string ='SecurityGroupPermissionDependentUpd'; + static readonly SECURITY_MASTER_UPD : string ='SecurityMasterUpd'; + static readonly SECURITY_PERMISSION_UPD : string ='SecurityPermissionUpd'; + static readonly SECURITY_PERMISSION_DEPENDENT_UPD : string ='SecurityPermissionDependentUpd'; + static readonly SECURITY_USER_UPD : string ='SecurityUserUpd'; + static readonly SECURITY_USER_ACTOR_UPD : string ='SecurityUserActorUpd'; + static readonly DB_NAME_SECURITY_INITIALIZER_TICK_VIEW : string ='security_initializer_tick_view'; + static readonly DB_NAME_FIELDS : string ='security_actor_upd,security_actor_group_upd,security_function_upd,security_function_map_upd,product_upd,security_group_permission_upd,security_group_permission_dependent_upd,security_master_upd,security_permission_upd,security_permission_dependent_upd,security_user_upd,security_user_actor_upd'; + static readonly DB_SECURITY_ACTOR_UPD : string ='security_actor_upd'; + static readonly DB_SECURITY_ACTOR_GROUP_UPD : string ='security_actor_group_upd'; + static readonly DB_SECURITY_FUNCTION_UPD : string ='security_function_upd'; + static readonly DB_SECURITY_FUNCTION_MAP_UPD : string ='security_function_map_upd'; + static readonly DB_PRODUCT_UPD : string ='product_upd'; + static readonly DB_SECURITY_GROUP_PERMISSION_UPD : string ='security_group_permission_upd'; + static readonly DB_SECURITY_GROUP_PERMISSION_DEPENDENT_UPD : string ='security_group_permission_dependent_upd'; + static readonly DB_SECURITY_MASTER_UPD : string ='security_master_upd'; + static readonly DB_SECURITY_PERMISSION_UPD : string ='security_permission_upd'; + static readonly DB_SECURITY_PERMISSION_DEPENDENT_UPD : string ='security_permission_dependent_upd'; + static readonly DB_SECURITY_USER_UPD : string ='security_user_upd'; + static readonly DB_SECURITY_USER_ACTOR_UPD : string ='security_user_actor_upd'; +} diff --git a/WebVue/src/data/auto/securityLockEntity.ts b/WebVue/src/data/auto/securityLockEntity.ts new file mode 100644 index 0000000..37a755b --- /dev/null +++ b/WebVue/src/data/auto/securityLockEntity.ts @@ -0,0 +1,28 @@ + +export class SecurityLockEntity +{ + public CreatedBy: string = ""; + public CreatedDatetime: Date = new Date(); + public EntityName: string = ""; + public LockedByActor: string = ""; + public PkeyId: string = ""; + public UpdatedBy: string = ""; + public UpdatedDatetime: Date = new Date(); + + static readonly CREATED_BY : string ='CreatedBy'; + static readonly CREATED_DATETIME : string ='CreatedDatetime'; + static readonly ENTITY_NAME : string ='EntityName'; + static readonly LOCKED_BY_ACTOR : string ='LockedByActor'; + static readonly PKEY_ID : string ='PkeyId'; + static readonly UPDATED_BY : string ='UpdatedBy'; + static readonly UPDATED_DATETIME : string ='UpdatedDatetime'; + static readonly DB_NAME_SECURITY_LOCK : string ='security_lock'; + static readonly DB_NAME_FIELDS : string ='created_by,created_datetime,entity_name,locked_by_actor,pkey_id,updated_by,updated_datetime'; + static readonly DB_CREATED_BY : string ='created_by'; + static readonly DB_CREATED_DATETIME : string ='created_datetime'; + static readonly DB_ENTITY_NAME : string ='entity_name'; + static readonly DB_LOCKED_BY_ACTOR : string ='locked_by_actor'; + static readonly DB_PKEY_ID : string ='pkey_id'; + static readonly DB_UPDATED_BY : string ='updated_by'; + static readonly DB_UPDATED_DATETIME : string ='updated_datetime'; +} diff --git a/WebVue/src/data/auto/securityLockEntityKey.ts b/WebVue/src/data/auto/securityLockEntityKey.ts new file mode 100644 index 0000000..019a31a --- /dev/null +++ b/WebVue/src/data/auto/securityLockEntityKey.ts @@ -0,0 +1,8 @@ + +export class SecurityLockEntityKey +{ + public EntityName: string = ""; + public LockedByActor: string = ""; + public PkeyId: string = ""; + +} diff --git a/WebVue/src/data/auto/securityLockSearchCriteria.ts b/WebVue/src/data/auto/securityLockSearchCriteria.ts new file mode 100644 index 0000000..dd3388b --- /dev/null +++ b/WebVue/src/data/auto/securityLockSearchCriteria.ts @@ -0,0 +1,6 @@ + +import { AbstractSearchCriteria } from "./abstractSearchCriteria"; +export class SecurityLockSearchCriteria extends AbstractSearchCriteria +{ + +} diff --git a/WebVue/src/data/auto/securityMasterEntity.ts b/WebVue/src/data/auto/securityMasterEntity.ts new file mode 100644 index 0000000..515140e --- /dev/null +++ b/WebVue/src/data/auto/securityMasterEntity.ts @@ -0,0 +1,46 @@ + +export class SecurityMasterEntity +{ + public CreatedBy: string = ""; + public CreatedDatetime: Date = new Date(); + public EngDescription: string = ""; + public LocalDescription: string = ""; + public MasterCategory: string = ""; + public MasterCodeItem: string = ""; + public MasterSubcategory: string = ""; + public OrderBy: number = 0; + public Remark: string = ""; + public UpdatedBy: string = ""; + public UpdatedDatetime: Date = new Date(); + public ValidIndc: string = ""; + public Value: string = ""; + + static readonly CREATED_BY : string ='CreatedBy'; + static readonly CREATED_DATETIME : string ='CreatedDatetime'; + static readonly ENG_DESCRIPTION : string ='EngDescription'; + static readonly LOCAL_DESCRIPTION : string ='LocalDescription'; + static readonly MASTER_CATEGORY : string ='MasterCategory'; + static readonly MASTER_CODE_ITEM : string ='MasterCodeItem'; + static readonly MASTER_SUBCATEGORY : string ='MasterSubcategory'; + static readonly ORDER_BY : string ='OrderBy'; + static readonly REMARK : string ='Remark'; + static readonly UPDATED_BY : string ='UpdatedBy'; + static readonly UPDATED_DATETIME : string ='UpdatedDatetime'; + static readonly VALID_INDC : string ='ValidIndc'; + static readonly VALUE : string ='Value'; + static readonly DB_NAME_SECURITY_MASTER : string ='security_master'; + static readonly DB_NAME_FIELDS : string ='created_by,created_datetime,eng_description,local_description,master_category,master_code_item,master_subcategory,order_by,remark,updated_by,updated_datetime,valid_indc,value'; + static readonly DB_CREATED_BY : string ='created_by'; + static readonly DB_CREATED_DATETIME : string ='created_datetime'; + static readonly DB_ENG_DESCRIPTION : string ='eng_description'; + static readonly DB_LOCAL_DESCRIPTION : string ='local_description'; + static readonly DB_MASTER_CATEGORY : string ='master_category'; + static readonly DB_MASTER_CODE_ITEM : string ='master_code_item'; + static readonly DB_MASTER_SUBCATEGORY : string ='master_subcategory'; + static readonly DB_ORDER_BY : string ='order_by'; + static readonly DB_REMARK : string ='remark'; + static readonly DB_UPDATED_BY : string ='updated_by'; + static readonly DB_UPDATED_DATETIME : string ='updated_datetime'; + static readonly DB_VALID_INDC : string ='valid_indc'; + static readonly DB_VALUE : string ='value'; +} diff --git a/WebVue/src/data/auto/securityMasterEntityKey.ts b/WebVue/src/data/auto/securityMasterEntityKey.ts new file mode 100644 index 0000000..2f9f47e --- /dev/null +++ b/WebVue/src/data/auto/securityMasterEntityKey.ts @@ -0,0 +1,8 @@ + +export class SecurityMasterEntityKey +{ + public MasterCategory: string = ""; + public MasterCodeItem: string = ""; + public MasterSubcategory: string = ""; + +} diff --git a/WebVue/src/data/auto/securityMasterResultData.ts b/WebVue/src/data/auto/securityMasterResultData.ts new file mode 100644 index 0000000..77b03fe --- /dev/null +++ b/WebVue/src/data/auto/securityMasterResultData.ts @@ -0,0 +1,8 @@ + +import { SecurityMasterEntity } from "./securityMasterEntity"; +import { SearchCriteriaResultData } from "./searchCriteriaResultData"; +export class SecurityMasterResultData extends SearchCriteriaResultData +{ + public Datas: SecurityMasterEntity[] = []; + +} diff --git a/WebVue/src/data/auto/securityMasterSearchCriteria.ts b/WebVue/src/data/auto/securityMasterSearchCriteria.ts new file mode 100644 index 0000000..7250505 --- /dev/null +++ b/WebVue/src/data/auto/securityMasterSearchCriteria.ts @@ -0,0 +1,6 @@ + +import { AbstractSearchCriteria } from "./abstractSearchCriteria"; +export class SecurityMasterSearchCriteria extends AbstractSearchCriteria +{ + +} diff --git a/WebVue/src/data/auto/securityPermissionData.ts b/WebVue/src/data/auto/securityPermissionData.ts new file mode 100644 index 0000000..4ca4388 --- /dev/null +++ b/WebVue/src/data/auto/securityPermissionData.ts @@ -0,0 +1,9 @@ + +import { SecurityPermissionEntity } from "./securityPermissionEntity"; +import { SecurityPermissionDependentEntity } from "./securityPermissionDependentEntity"; +export class SecurityPermissionData +{ + public SecurityPermission: SecurityPermissionEntity = new SecurityPermissionEntity(); + public SecurityPermissionDependents: SecurityPermissionDependentEntity[] = []; + +} diff --git a/WebVue/src/data/auto/securityPermissionDependentEntity.ts b/WebVue/src/data/auto/securityPermissionDependentEntity.ts new file mode 100644 index 0000000..cf06028 --- /dev/null +++ b/WebVue/src/data/auto/securityPermissionDependentEntity.ts @@ -0,0 +1,31 @@ + +export class SecurityPermissionDependentEntity +{ + public CreatedBy: string = ""; + public CreatedDatetime: Date = new Date(); + public Dependent: string = ""; + public DependentDetailDescription: string = ""; + public DependentDetailName: string = ""; + public PermissionName: string = ""; + public UpdatedBy: string = ""; + public UpdatedDatetime: Date = new Date(); + + static readonly CREATED_BY : string ='CreatedBy'; + static readonly CREATED_DATETIME : string ='CreatedDatetime'; + static readonly DEPENDENT : string ='Dependent'; + static readonly DEPENDENT_DETAIL_DESCRIPTION : string ='DependentDetailDescription'; + static readonly DEPENDENT_DETAIL_NAME : string ='DependentDetailName'; + static readonly PERMISSION_NAME : string ='PermissionName'; + static readonly UPDATED_BY : string ='UpdatedBy'; + static readonly UPDATED_DATETIME : string ='UpdatedDatetime'; + static readonly DB_NAME_SECURITY_PERMISSION_DEPENDENT : string ='security_permission_dependent'; + static readonly DB_NAME_FIELDS : string ='created_by,created_datetime,dependent,dependent_detail_description,dependent_detail_name,permission_name,updated_by,updated_datetime'; + static readonly DB_CREATED_BY : string ='created_by'; + static readonly DB_CREATED_DATETIME : string ='created_datetime'; + static readonly DB_DEPENDENT : string ='dependent'; + static readonly DB_DEPENDENT_DETAIL_DESCRIPTION : string ='dependent_detail_description'; + static readonly DB_DEPENDENT_DETAIL_NAME : string ='dependent_detail_name'; + static readonly DB_PERMISSION_NAME : string ='permission_name'; + static readonly DB_UPDATED_BY : string ='updated_by'; + static readonly DB_UPDATED_DATETIME : string ='updated_datetime'; +} diff --git a/WebVue/src/data/auto/securityPermissionDependentEntityKey.ts b/WebVue/src/data/auto/securityPermissionDependentEntityKey.ts new file mode 100644 index 0000000..65c3ca5 --- /dev/null +++ b/WebVue/src/data/auto/securityPermissionDependentEntityKey.ts @@ -0,0 +1,7 @@ + +export class SecurityPermissionDependentEntityKey +{ + public DependentDetailName: string = ""; + public PermissionName: string = ""; + +} diff --git a/WebVue/src/data/auto/securityPermissionEntity.ts b/WebVue/src/data/auto/securityPermissionEntity.ts new file mode 100644 index 0000000..918cbec --- /dev/null +++ b/WebVue/src/data/auto/securityPermissionEntity.ts @@ -0,0 +1,31 @@ + +export class SecurityPermissionEntity +{ + public CreatedBy: string = ""; + public CreatedDatetime: Date = new Date(); + public DelegateIndc: string = ""; + public Dependent: string = ""; + public Description: string = ""; + public PermissionName: string = ""; + public UpdatedBy: string = ""; + public UpdatedDatetime: Date = new Date(); + + static readonly CREATED_BY : string ='CreatedBy'; + static readonly CREATED_DATETIME : string ='CreatedDatetime'; + static readonly DELEGATE_INDC : string ='DelegateIndc'; + static readonly DEPENDENT : string ='Dependent'; + static readonly DESCRIPTION : string ='Description'; + static readonly PERMISSION_NAME : string ='PermissionName'; + static readonly UPDATED_BY : string ='UpdatedBy'; + static readonly UPDATED_DATETIME : string ='UpdatedDatetime'; + static readonly DB_NAME_SECURITY_PERMISSION : string ='security_permission'; + static readonly DB_NAME_FIELDS : string ='created_by,created_datetime,delegate_indc,dependent,description,permission_name,updated_by,updated_datetime'; + static readonly DB_CREATED_BY : string ='created_by'; + static readonly DB_CREATED_DATETIME : string ='created_datetime'; + static readonly DB_DELEGATE_INDC : string ='delegate_indc'; + static readonly DB_DEPENDENT : string ='dependent'; + static readonly DB_DESCRIPTION : string ='description'; + static readonly DB_PERMISSION_NAME : string ='permission_name'; + static readonly DB_UPDATED_BY : string ='updated_by'; + static readonly DB_UPDATED_DATETIME : string ='updated_datetime'; +} diff --git a/WebVue/src/data/auto/securityPermissionFunctionMapEntity.ts b/WebVue/src/data/auto/securityPermissionFunctionMapEntity.ts new file mode 100644 index 0000000..aad2686 --- /dev/null +++ b/WebVue/src/data/auto/securityPermissionFunctionMapEntity.ts @@ -0,0 +1,25 @@ + +export class SecurityPermissionFunctionMapEntity +{ + public CreatedBy: string = ""; + public CreatedDatetime: Date = new Date(); + public FunctionName: string = ""; + public PermissionName: string = ""; + public UpdatedBy: string = ""; + public UpdatedDatetime: Date = new Date(); + + static readonly CREATED_BY : string ='CreatedBy'; + static readonly CREATED_DATETIME : string ='CreatedDatetime'; + static readonly FUNCTION_NAME : string ='FunctionName'; + static readonly PERMISSION_NAME : string ='PermissionName'; + static readonly UPDATED_BY : string ='UpdatedBy'; + static readonly UPDATED_DATETIME : string ='UpdatedDatetime'; + static readonly DB_NAME_SECURITY_PERMISSION_FUNCTION_MAP : string ='security_permission_function_map'; + static readonly DB_NAME_FIELDS : string ='created_by,created_datetime,function_name,permission_name,updated_by,updated_datetime'; + static readonly DB_CREATED_BY : string ='created_by'; + static readonly DB_CREATED_DATETIME : string ='created_datetime'; + static readonly DB_FUNCTION_NAME : string ='function_name'; + static readonly DB_PERMISSION_NAME : string ='permission_name'; + static readonly DB_UPDATED_BY : string ='updated_by'; + static readonly DB_UPDATED_DATETIME : string ='updated_datetime'; +} diff --git a/WebVue/src/data/auto/securityPermissionFunctionMapEntityKey.ts b/WebVue/src/data/auto/securityPermissionFunctionMapEntityKey.ts new file mode 100644 index 0000000..03fb5d3 --- /dev/null +++ b/WebVue/src/data/auto/securityPermissionFunctionMapEntityKey.ts @@ -0,0 +1,7 @@ + +export class SecurityPermissionFunctionMapEntityKey +{ + public FunctionName: string = ""; + public PermissionName: string = ""; + +} diff --git a/WebVue/src/data/auto/securityPermissionFunctionMapViewEntity.ts b/WebVue/src/data/auto/securityPermissionFunctionMapViewEntity.ts new file mode 100644 index 0000000..e71bc04 --- /dev/null +++ b/WebVue/src/data/auto/securityPermissionFunctionMapViewEntity.ts @@ -0,0 +1,16 @@ + +export class SecurityPermissionFunctionMapViewEntity +{ + public FunctionName: string = ""; + public PageName: string = ""; + public PermissionName: string = ""; + + static readonly FUNCTION_NAME : string ='FunctionName'; + static readonly PAGE_NAME : string ='PageName'; + static readonly PERMISSION_NAME : string ='PermissionName'; + static readonly DB_NAME_SECURITY_PERMISSION_FUNCTION_MAP_VIEW : string ='security_permission_function_map_view'; + static readonly DB_NAME_FIELDS : string ='function_name,page_name,permission_name'; + static readonly DB_FUNCTION_NAME : string ='function_name'; + static readonly DB_PAGE_NAME : string ='page_name'; + static readonly DB_PERMISSION_NAME : string ='permission_name'; +} diff --git a/WebVue/src/data/auto/securityPermissionPolicy.ts b/WebVue/src/data/auto/securityPermissionPolicy.ts new file mode 100644 index 0000000..be39fcc --- /dev/null +++ b/WebVue/src/data/auto/securityPermissionPolicy.ts @@ -0,0 +1,16 @@ + +export class SecurityPermissionPolicy +{ + + static readonly SecurityUser : string ='SecurityUser'; + static readonly SecurityMaster : string ='SecurityMaster'; + static readonly SecurityGeneratorNumber : string ='SecurityGeneratorNumber'; + static readonly SecurityPermission : string ='SecurityPermission'; + static readonly SecurityFunction : string ='SecurityFunction'; + static readonly SecurityGroup : string ='SecurityGroup'; + static readonly SecurityActor : string ='SecurityActor'; + static readonly Locale : string ='Locale'; + static readonly SecurityUserPreference : string ='SecurityUserPreference'; + static readonly SecurityLock : string ='SecurityLock'; + static readonly CanSeeAllUser : string ='CanSeeAllUser'; +} diff --git a/WebVue/src/data/auto/securityPermissionResultData.ts b/WebVue/src/data/auto/securityPermissionResultData.ts new file mode 100644 index 0000000..a721b92 --- /dev/null +++ b/WebVue/src/data/auto/securityPermissionResultData.ts @@ -0,0 +1,10 @@ + +import { SecurityPermissionEntity } from "./securityPermissionEntity"; +import { SecurityPermissionDependentEntity } from "./securityPermissionDependentEntity"; +import { SearchCriteriaResultData } from "./searchCriteriaResultData"; +export class SecurityPermissionResultData extends SearchCriteriaResultData +{ + public Permissions: SecurityPermissionEntity[] = []; + public Dependents: SecurityPermissionDependentEntity[] = []; + +} diff --git a/WebVue/src/data/auto/securityPermissionSearchCriteria.ts b/WebVue/src/data/auto/securityPermissionSearchCriteria.ts new file mode 100644 index 0000000..ee08bab --- /dev/null +++ b/WebVue/src/data/auto/securityPermissionSearchCriteria.ts @@ -0,0 +1,9 @@ + +import { AbstractSearchCriteria } from "./abstractSearchCriteria"; +export class SecurityPermissionSearchCriteria extends AbstractSearchCriteria +{ + public PermissionName: string = ""; + public Dependent: string = ""; + public DependentEnable?: Date= null!; + +} diff --git a/WebVue/src/data/auto/securityPermissionViewEntity.ts b/WebVue/src/data/auto/securityPermissionViewEntity.ts new file mode 100644 index 0000000..359f662 --- /dev/null +++ b/WebVue/src/data/auto/securityPermissionViewEntity.ts @@ -0,0 +1,22 @@ + +export class SecurityPermissionViewEntity +{ + public CreatedDatetime: Date = new Date(); + public Dependent: string = ""; + public Description: string = ""; + public FunctionName: string = ""; + public PermissionName: string = ""; + + static readonly CREATED_DATETIME : string ='CreatedDatetime'; + static readonly DEPENDENT : string ='Dependent'; + static readonly DESCRIPTION : string ='Description'; + static readonly FUNCTION_NAME : string ='FunctionName'; + static readonly PERMISSION_NAME : string ='PermissionName'; + static readonly DB_NAME_SECURITY_PERMISSION_VIEW : string ='security_permission_view'; + static readonly DB_NAME_FIELDS : string ='created_datetime,dependent,description,function_name,permission_name'; + static readonly DB_CREATED_DATETIME : string ='created_datetime'; + static readonly DB_DEPENDENT : string ='dependent'; + static readonly DB_DESCRIPTION : string ='description'; + static readonly DB_FUNCTION_NAME : string ='function_name'; + static readonly DB_PERMISSION_NAME : string ='permission_name'; +} diff --git a/WebVue/src/data/auto/securityTableDescriptionEntity.ts b/WebVue/src/data/auto/securityTableDescriptionEntity.ts new file mode 100644 index 0000000..b6b8d62 --- /dev/null +++ b/WebVue/src/data/auto/securityTableDescriptionEntity.ts @@ -0,0 +1,31 @@ + +export class SecurityTableDescriptionEntity +{ + public CreatedBy: string = ""; + public CreatedDatetime: Date = new Date(); + public Description: string = ""; + public DescriptionId: number = 0; + public FieldName: string = ""; + public TableName: string = ""; + public UpdatedBy: string = ""; + public UpdatedDatetime: Date = new Date(); + + static readonly CREATED_BY : string ='CreatedBy'; + static readonly CREATED_DATETIME : string ='CreatedDatetime'; + static readonly DESCRIPTION : string ='Description'; + static readonly DESCRIPTION_ID : string ='DescriptionId'; + static readonly FIELD_NAME : string ='FieldName'; + static readonly TABLE_NAME : string ='TableName'; + static readonly UPDATED_BY : string ='UpdatedBy'; + static readonly UPDATED_DATETIME : string ='UpdatedDatetime'; + static readonly DB_NAME_SECURITY_TABLE_DESCRIPTION : string ='security_table_description'; + static readonly DB_NAME_FIELDS : string ='created_by,created_datetime,description,description_id,field_name,table_name,updated_by,updated_datetime'; + static readonly DB_CREATED_BY : string ='created_by'; + static readonly DB_CREATED_DATETIME : string ='created_datetime'; + static readonly DB_DESCRIPTION : string ='description'; + static readonly DB_DESCRIPTION_ID : string ='description_id'; + static readonly DB_FIELD_NAME : string ='field_name'; + static readonly DB_TABLE_NAME : string ='table_name'; + static readonly DB_UPDATED_BY : string ='updated_by'; + static readonly DB_UPDATED_DATETIME : string ='updated_datetime'; +} diff --git a/WebVue/src/data/auto/securityTableDescriptionViewEntity.ts b/WebVue/src/data/auto/securityTableDescriptionViewEntity.ts new file mode 100644 index 0000000..67ff8ba --- /dev/null +++ b/WebVue/src/data/auto/securityTableDescriptionViewEntity.ts @@ -0,0 +1,58 @@ + +export class SecurityTableDescriptionViewEntity +{ + public TableName: string = ""; + public FieldName: string = ""; + public TypeName: string = ""; + public TypeOfName: string = ""; + public MaxLength: number = 0; + public Scale: number = 0; + public IsNullAble: string = ""; + public FieldDefaultValue: string = ""; + public Xtype: string = ""; + public FindBy: number = 0; + public Operation: number = 0; + public Pk: number = 0; + public PkName: string = ""; + public IsIdentity: number = 0; + public Colid: number = 0; + public Description: string = ""; + public DescriptionId: number = 0; + + static readonly TABLE_NAME : string ='TableName'; + static readonly FIELD_NAME : string ='FieldName'; + static readonly TYPE_NAME : string ='TypeName'; + static readonly TYPE_OF_NAME : string ='TypeOfName'; + static readonly MAX_LENGTH : string ='MaxLength'; + static readonly SCALE : string ='Scale'; + static readonly IS_NULL_ABLE : string ='IsNullAble'; + static readonly FIELD_DEFAULT_VALUE : string ='FieldDefaultValue'; + static readonly XTYPE : string ='Xtype'; + static readonly FIND_BY : string ='FindBy'; + static readonly OPERATION : string ='Operation'; + static readonly PK : string ='Pk'; + static readonly PK_NAME : string ='PkName'; + static readonly IS_IDENTITY : string ='IsIdentity'; + static readonly COLID : string ='Colid'; + static readonly DESCRIPTION : string ='Description'; + static readonly DESCRIPTION_ID : string ='DescriptionId'; + static readonly DB_NAME_SECURITY_TABLE_DESCRIPTION_VIEW : string ='security_table_description_view'; + static readonly DB_NAME_FIELDS : string ='table_name,field_name,type_name,type_of_name,max_length,scale,is_null_able,field_default_value,xtype,find_by,operation,pk,pk_name,is_identity,colid,description,description_id'; + static readonly DB_TABLE_NAME : string ='table_name'; + static readonly DB_FIELD_NAME : string ='field_name'; + static readonly DB_TYPE_NAME : string ='type_name'; + static readonly DB_TYPE_OF_NAME : string ='type_of_name'; + static readonly DB_MAX_LENGTH : string ='max_length'; + static readonly DB_SCALE : string ='scale'; + static readonly DB_IS_NULL_ABLE : string ='is_null_able'; + static readonly DB_FIELD_DEFAULT_VALUE : string ='field_default_value'; + static readonly DB_XTYPE : string ='xtype'; + static readonly DB_FIND_BY : string ='find_by'; + static readonly DB_OPERATION : string ='operation'; + static readonly DB_PK : string ='pk'; + static readonly DB_PK_NAME : string ='pk_name'; + static readonly DB_IS_IDENTITY : string ='is_identity'; + static readonly DB_COLID : string ='colid'; + static readonly DB_DESCRIPTION : string ='description'; + static readonly DB_DESCRIPTION_ID : string ='description_id'; +} diff --git a/WebVue/src/data/auto/securityUserActorEntity.ts b/WebVue/src/data/auto/securityUserActorEntity.ts new file mode 100644 index 0000000..a7fcf93 --- /dev/null +++ b/WebVue/src/data/auto/securityUserActorEntity.ts @@ -0,0 +1,25 @@ + +export class SecurityUserActorEntity +{ + public ActorName: string = ""; + public CreatedBy: string = ""; + public CreatedDatetime: Date = new Date(); + public UpdatedBy: string = ""; + public UpdatedDatetime: Date = new Date(); + public UserName: string = ""; + + static readonly ACTOR_NAME : string ='ActorName'; + static readonly CREATED_BY : string ='CreatedBy'; + static readonly CREATED_DATETIME : string ='CreatedDatetime'; + static readonly UPDATED_BY : string ='UpdatedBy'; + static readonly UPDATED_DATETIME : string ='UpdatedDatetime'; + static readonly USER_NAME : string ='UserName'; + static readonly DB_NAME_SECURITY_USER_ACTOR : string ='security_user_actor'; + static readonly DB_NAME_FIELDS : string ='actor_name,created_by,created_datetime,updated_by,updated_datetime,user_name'; + static readonly DB_ACTOR_NAME : string ='actor_name'; + static readonly DB_CREATED_BY : string ='created_by'; + static readonly DB_CREATED_DATETIME : string ='created_datetime'; + static readonly DB_UPDATED_BY : string ='updated_by'; + static readonly DB_UPDATED_DATETIME : string ='updated_datetime'; + static readonly DB_USER_NAME : string ='user_name'; +} diff --git a/WebVue/src/data/auto/securityUserActorEntityKey.ts b/WebVue/src/data/auto/securityUserActorEntityKey.ts new file mode 100644 index 0000000..f7263b5 --- /dev/null +++ b/WebVue/src/data/auto/securityUserActorEntityKey.ts @@ -0,0 +1,7 @@ + +export class SecurityUserActorEntityKey +{ + public ActorName: string = ""; + public UserName: string = ""; + +} diff --git a/WebVue/src/data/auto/securityUserActorViewEntity.ts b/WebVue/src/data/auto/securityUserActorViewEntity.ts new file mode 100644 index 0000000..55e8f5b --- /dev/null +++ b/WebVue/src/data/auto/securityUserActorViewEntity.ts @@ -0,0 +1,22 @@ + +export class SecurityUserActorViewEntity +{ + public ActorLocalName: string = ""; + public ActorName: string = ""; + public UserLocalName: string = ""; + public UserMobile: string = ""; + public UserName: string = ""; + + static readonly ACTOR_LOCAL_NAME : string ='ActorLocalName'; + static readonly ACTOR_NAME : string ='ActorName'; + static readonly USER_LOCAL_NAME : string ='UserLocalName'; + static readonly USER_MOBILE : string ='UserMobile'; + static readonly USER_NAME : string ='UserName'; + static readonly DB_NAME_SECURITY_USER_ACTOR_VIEW : string ='security_user_actor_view'; + static readonly DB_NAME_FIELDS : string ='actor_local_name,actor_name,user_local_name,user_mobile,user_name'; + static readonly DB_ACTOR_LOCAL_NAME : string ='actor_local_name'; + static readonly DB_ACTOR_NAME : string ='actor_name'; + static readonly DB_USER_LOCAL_NAME : string ='user_local_name'; + static readonly DB_USER_MOBILE : string ='user_mobile'; + static readonly DB_USER_NAME : string ='user_name'; +} diff --git a/WebVue/src/data/auto/securityUserData.ts b/WebVue/src/data/auto/securityUserData.ts new file mode 100644 index 0000000..84d1dc4 --- /dev/null +++ b/WebVue/src/data/auto/securityUserData.ts @@ -0,0 +1,9 @@ + +import { SecurityUserDisplayData } from "./securityUserDisplayData"; +import { SecurityUserActorViewEntity } from "./securityUserActorViewEntity"; +export class SecurityUserData +{ + public SecurityUser: SecurityUserDisplayData = new SecurityUserDisplayData(); + public SecurityUserActors: SecurityUserActorViewEntity[] = []; + +} diff --git a/WebVue/src/data/auto/securityUserDelegatedPermissionEntity.ts b/WebVue/src/data/auto/securityUserDelegatedPermissionEntity.ts new file mode 100644 index 0000000..7d75431 --- /dev/null +++ b/WebVue/src/data/auto/securityUserDelegatedPermissionEntity.ts @@ -0,0 +1,34 @@ + +export class SecurityUserDelegatedPermissionEntity +{ + public CreatedBy: string = ""; + public CreatedDatetime: Date = new Date(); + public DelegatedByUser: string = ""; + public EndDatetime: Date = new Date(); + public PermissionName: string = ""; + public StartDatetime: Date = new Date(); + public UpdatedBy: string = ""; + public UpdatedDatetime: Date = new Date(); + public UserName: string = ""; + + static readonly CREATED_BY : string ='CreatedBy'; + static readonly CREATED_DATETIME : string ='CreatedDatetime'; + static readonly DELEGATED_BY_USER : string ='DelegatedByUser'; + static readonly END_DATETIME : string ='EndDatetime'; + static readonly PERMISSION_NAME : string ='PermissionName'; + static readonly START_DATETIME : string ='StartDatetime'; + static readonly UPDATED_BY : string ='UpdatedBy'; + static readonly UPDATED_DATETIME : string ='UpdatedDatetime'; + static readonly USER_NAME : string ='UserName'; + static readonly DB_NAME_SECURITY_USER_DELEGATED_PERMISSION : string ='security_user_delegated_permission'; + static readonly DB_NAME_FIELDS : string ='created_by,created_datetime,delegated_by_user,end_datetime,permission_name,start_datetime,updated_by,updated_datetime,user_name'; + static readonly DB_CREATED_BY : string ='created_by'; + static readonly DB_CREATED_DATETIME : string ='created_datetime'; + static readonly DB_DELEGATED_BY_USER : string ='delegated_by_user'; + static readonly DB_END_DATETIME : string ='end_datetime'; + static readonly DB_PERMISSION_NAME : string ='permission_name'; + static readonly DB_START_DATETIME : string ='start_datetime'; + static readonly DB_UPDATED_BY : string ='updated_by'; + static readonly DB_UPDATED_DATETIME : string ='updated_datetime'; + static readonly DB_USER_NAME : string ='user_name'; +} diff --git a/WebVue/src/data/auto/securityUserDelegatedPermissionEntityKey.ts b/WebVue/src/data/auto/securityUserDelegatedPermissionEntityKey.ts new file mode 100644 index 0000000..7b34859 --- /dev/null +++ b/WebVue/src/data/auto/securityUserDelegatedPermissionEntityKey.ts @@ -0,0 +1,8 @@ + +export class SecurityUserDelegatedPermissionEntityKey +{ + public DelegatedByUser: string = ""; + public PermissionName: string = ""; + public UserName: string = ""; + +} diff --git a/WebVue/src/data/auto/securityUserDisplayData.ts b/WebVue/src/data/auto/securityUserDisplayData.ts new file mode 100644 index 0000000..22e0392 --- /dev/null +++ b/WebVue/src/data/auto/securityUserDisplayData.ts @@ -0,0 +1,7 @@ + +import { SecurityUserEntity } from "./securityUserEntity"; +export class SecurityUserDisplayData extends SecurityUserEntity +{ + public OrgUserPassword: string = ""; + +} diff --git a/WebVue/src/data/auto/securityUserEntity.ts b/WebVue/src/data/auto/securityUserEntity.ts new file mode 100644 index 0000000..ffda152 --- /dev/null +++ b/WebVue/src/data/auto/securityUserEntity.ts @@ -0,0 +1,121 @@ + +export class SecurityUserEntity +{ + public AccountsLockedDatetime?: Date= null!; + public BiometricCounter: number = 0; + public BiometricCredentialId: string = ""; + public BiometricDeviceName: string = ""; + public BiometricEnrolledAt?: Date= null!; + public BiometricLastUsedAt?: Date= null!; + public BiometricPublicKey: string = ""; + public Community: number = 0; + public CompanyName: string = ""; + public CreatedBy: string = ""; + public CreatedDatetime: Date = new Date(); + public ErrorLoginCount: number = 0; + public Industry: string = ""; + public IsAccountsLockedIndc: string = ""; + public IsForeceChangePasswordIndc: string = ""; + public LastLoginDatetime?: Date= null!; + public Postcode: string = ""; + public RoomName: string = ""; + public UpdatedBy: string = ""; + public UpdatedDatetime: Date = new Date(); + public UserAccountsExpireDatetime?: Date= null!; + public UserAddress: string = ""; + public UserAlipayAccount: string = ""; + public UserAlipayAccountImgPath: string = ""; + public UserEngName: string = ""; + public UserGrade: number = 0; + public UserIconImgPath: string = ""; + public UserIsValidIndc: string = ""; + public UserLocalName: string = ""; + public UserMobile: string = ""; + public UserName: string = ""; + public UserPassword: string = ""; + public UserRemark: string = ""; + public UserType: string = ""; + public UserTypeEndDatetime?: Date= null!; + public UserWechatAccount: string = ""; + public UserWechatAccountImgPath: string = ""; + public WelcomePage: string = ""; + + static readonly ACCOUNTS_LOCKED_DATETIME : string ='AccountsLockedDatetime'; + static readonly BIOMETRIC_COUNTER : string ='BiometricCounter'; + static readonly BIOMETRIC_CREDENTIAL_ID : string ='BiometricCredentialId'; + static readonly BIOMETRIC_DEVICE_NAME : string ='BiometricDeviceName'; + static readonly BIOMETRIC_ENROLLED_AT : string ='BiometricEnrolledAt'; + static readonly BIOMETRIC_LAST_USED_AT : string ='BiometricLastUsedAt'; + static readonly BIOMETRIC_PUBLIC_KEY : string ='BiometricPublicKey'; + static readonly COMMUNITY : string ='Community'; + static readonly COMPANY_NAME : string ='CompanyName'; + static readonly CREATED_BY : string ='CreatedBy'; + static readonly CREATED_DATETIME : string ='CreatedDatetime'; + static readonly ERROR_LOGIN_COUNT : string ='ErrorLoginCount'; + static readonly INDUSTRY : string ='Industry'; + static readonly IS_ACCOUNTS_LOCKED_INDC : string ='IsAccountsLockedIndc'; + static readonly IS_FORECE_CHANGE_PASSWORD_INDC : string ='IsForeceChangePasswordIndc'; + static readonly LAST_LOGIN_DATETIME : string ='LastLoginDatetime'; + static readonly POSTCODE : string ='Postcode'; + static readonly ROOM_NAME : string ='RoomName'; + static readonly UPDATED_BY : string ='UpdatedBy'; + static readonly UPDATED_DATETIME : string ='UpdatedDatetime'; + static readonly USER_ACCOUNTS_EXPIRE_DATETIME : string ='UserAccountsExpireDatetime'; + static readonly USER_ADDRESS : string ='UserAddress'; + static readonly USER_ALIPAY_ACCOUNT : string ='UserAlipayAccount'; + static readonly USER_ALIPAY_ACCOUNT_IMG_PATH : string ='UserAlipayAccountImgPath'; + static readonly USER_ENG_NAME : string ='UserEngName'; + static readonly USER_GRADE : string ='UserGrade'; + static readonly USER_ICON_IMG_PATH : string ='UserIconImgPath'; + static readonly USER_IS_VALID_INDC : string ='UserIsValidIndc'; + static readonly USER_LOCAL_NAME : string ='UserLocalName'; + static readonly USER_MOBILE : string ='UserMobile'; + static readonly USER_NAME : string ='UserName'; + static readonly USER_PASSWORD : string ='UserPassword'; + static readonly USER_REMARK : string ='UserRemark'; + static readonly USER_TYPE : string ='UserType'; + static readonly USER_TYPE_END_DATETIME : string ='UserTypeEndDatetime'; + static readonly USER_WECHAT_ACCOUNT : string ='UserWechatAccount'; + static readonly USER_WECHAT_ACCOUNT_IMG_PATH : string ='UserWechatAccountImgPath'; + static readonly WELCOME_PAGE : string ='WelcomePage'; + static readonly DB_NAME_SECURITY_USER : string ='security_user'; + static readonly DB_NAME_FIELDS : string ='accounts_locked_datetime,biometric_counter,biometric_credential_id,biometric_device_name,biometric_enrolled_at,biometric_last_used_at,biometric_public_key,community,company_name,created_by,created_datetime,error_login_count,industry,is_accounts_locked_indc,is_forece_change_password_indc,last_login_datetime,postcode,room_name,updated_by,updated_datetime,user_accounts_expire_datetime,user_address,user_alipay_account,user_alipay_account_img_path,user_eng_name,user_grade,user_icon_img_path,user_is_valid_indc,user_local_name,user_mobile,user_name,user_password,user_remark,user_type,user_type_end_datetime,user_wechat_account,user_wechat_account_img_path,welcome_page'; + static readonly DB_ACCOUNTS_LOCKED_DATETIME : string ='accounts_locked_datetime'; + static readonly DB_BIOMETRIC_COUNTER : string ='biometric_counter'; + static readonly DB_BIOMETRIC_CREDENTIAL_ID : string ='biometric_credential_id'; + static readonly DB_BIOMETRIC_DEVICE_NAME : string ='biometric_device_name'; + static readonly DB_BIOMETRIC_ENROLLED_AT : string ='biometric_enrolled_at'; + static readonly DB_BIOMETRIC_LAST_USED_AT : string ='biometric_last_used_at'; + static readonly DB_BIOMETRIC_PUBLIC_KEY : string ='biometric_public_key'; + static readonly DB_COMMUNITY : string ='community'; + static readonly DB_COMPANY_NAME : string ='company_name'; + static readonly DB_CREATED_BY : string ='created_by'; + static readonly DB_CREATED_DATETIME : string ='created_datetime'; + static readonly DB_ERROR_LOGIN_COUNT : string ='error_login_count'; + static readonly DB_INDUSTRY : string ='industry'; + static readonly DB_IS_ACCOUNTS_LOCKED_INDC : string ='is_accounts_locked_indc'; + static readonly DB_IS_FORECE_CHANGE_PASSWORD_INDC : string ='is_forece_change_password_indc'; + static readonly DB_LAST_LOGIN_DATETIME : string ='last_login_datetime'; + static readonly DB_POSTCODE : string ='postcode'; + static readonly DB_ROOM_NAME : string ='room_name'; + static readonly DB_UPDATED_BY : string ='updated_by'; + static readonly DB_UPDATED_DATETIME : string ='updated_datetime'; + static readonly DB_USER_ACCOUNTS_EXPIRE_DATETIME : string ='user_accounts_expire_datetime'; + static readonly DB_USER_ADDRESS : string ='user_address'; + static readonly DB_USER_ALIPAY_ACCOUNT : string ='user_alipay_account'; + static readonly DB_USER_ALIPAY_ACCOUNT_IMG_PATH : string ='user_alipay_account_img_path'; + static readonly DB_USER_ENG_NAME : string ='user_eng_name'; + static readonly DB_USER_GRADE : string ='user_grade'; + static readonly DB_USER_ICON_IMG_PATH : string ='user_icon_img_path'; + static readonly DB_USER_IS_VALID_INDC : string ='user_is_valid_indc'; + static readonly DB_USER_LOCAL_NAME : string ='user_local_name'; + static readonly DB_USER_MOBILE : string ='user_mobile'; + static readonly DB_USER_NAME : string ='user_name'; + static readonly DB_USER_PASSWORD : string ='user_password'; + static readonly DB_USER_REMARK : string ='user_remark'; + static readonly DB_USER_TYPE : string ='user_type'; + static readonly DB_USER_TYPE_END_DATETIME : string ='user_type_end_datetime'; + static readonly DB_USER_WECHAT_ACCOUNT : string ='user_wechat_account'; + static readonly DB_USER_WECHAT_ACCOUNT_IMG_PATH : string ='user_wechat_account_img_path'; + static readonly DB_WELCOME_PAGE : string ='welcome_page'; +} diff --git a/WebVue/src/data/auto/securityUserLoginLogEntity.ts b/WebVue/src/data/auto/securityUserLoginLogEntity.ts new file mode 100644 index 0000000..e216e91 --- /dev/null +++ b/WebVue/src/data/auto/securityUserLoginLogEntity.ts @@ -0,0 +1,31 @@ + +export class SecurityUserLoginLogEntity +{ + public AgentUserName: string = ""; + public CreatedBy: string = ""; + public CreatedDatetime: Date = new Date(); + public IpAddress: string = ""; + public LoginLogId: number = 0; + public UpdatedBy: string = ""; + public UpdatedDatetime: Date = new Date(); + public UserName: string = ""; + + static readonly AGENT_USER_NAME : string ='AgentUserName'; + static readonly CREATED_BY : string ='CreatedBy'; + static readonly CREATED_DATETIME : string ='CreatedDatetime'; + static readonly IP_ADDRESS : string ='IpAddress'; + static readonly LOGIN_LOG_ID : string ='LoginLogId'; + static readonly UPDATED_BY : string ='UpdatedBy'; + static readonly UPDATED_DATETIME : string ='UpdatedDatetime'; + static readonly USER_NAME : string ='UserName'; + static readonly DB_NAME_SECURITY_USER_LOGIN_LOG : string ='security_user_login_log'; + static readonly DB_NAME_FIELDS : string ='agent_user_name,created_by,created_datetime,ip_address,login_log_id,updated_by,updated_datetime,user_name'; + static readonly DB_AGENT_USER_NAME : string ='agent_user_name'; + static readonly DB_CREATED_BY : string ='created_by'; + static readonly DB_CREATED_DATETIME : string ='created_datetime'; + static readonly DB_IP_ADDRESS : string ='ip_address'; + static readonly DB_LOGIN_LOG_ID : string ='login_log_id'; + static readonly DB_UPDATED_BY : string ='updated_by'; + static readonly DB_UPDATED_DATETIME : string ='updated_datetime'; + static readonly DB_USER_NAME : string ='user_name'; +} diff --git a/WebVue/src/data/auto/securityUserPermissionInfo.ts b/WebVue/src/data/auto/securityUserPermissionInfo.ts new file mode 100644 index 0000000..0fc6f25 --- /dev/null +++ b/WebVue/src/data/auto/securityUserPermissionInfo.ts @@ -0,0 +1,12 @@ + +import { SecurityGroupPermissionViewEntity } from "./securityGroupPermissionViewEntity"; +import { SecurityGroupPermissionDependentViewEntity } from "./securityGroupPermissionDependentViewEntity"; +import { SecurityPermissionFunctionMapViewEntity } from "./securityPermissionFunctionMapViewEntity"; +export class SecurityUserPermissionInfo +{ + public UserGroups: string[]= []; + public Permissions: SecurityGroupPermissionViewEntity[] = []; + public PermissionDependents: SecurityGroupPermissionDependentViewEntity[] = []; + public PermissionFunctionMaps: SecurityPermissionFunctionMapViewEntity[] = []; + +} diff --git a/WebVue/src/data/auto/securityUserPolicy.ts b/WebVue/src/data/auto/securityUserPolicy.ts new file mode 100644 index 0000000..c22aebe --- /dev/null +++ b/WebVue/src/data/auto/securityUserPolicy.ts @@ -0,0 +1,7 @@ + +export class SecurityUserPolicy +{ + + static readonly SECURITY_USER_BASE_ACTOR : string ='SecurityUserBaseActor'; + static readonly ERROR_LOGIN_COUNT: number =5; +} diff --git a/WebVue/src/data/auto/securityUserPreferenceEntity.ts b/WebVue/src/data/auto/securityUserPreferenceEntity.ts new file mode 100644 index 0000000..5e72d3a --- /dev/null +++ b/WebVue/src/data/auto/securityUserPreferenceEntity.ts @@ -0,0 +1,28 @@ + +export class SecurityUserPreferenceEntity +{ + public CreatedBy: string = ""; + public CreatedDatetime: Date = new Date(); + public Preference: string = ""; + public PreferenceKey: string = ""; + public UpdatedBy: string = ""; + public UpdatedDatetime: Date = new Date(); + public Username: string = ""; + + static readonly CREATED_BY : string ='CreatedBy'; + static readonly CREATED_DATETIME : string ='CreatedDatetime'; + static readonly PREFERENCE : string ='Preference'; + static readonly PREFERENCE_KEY : string ='PreferenceKey'; + static readonly UPDATED_BY : string ='UpdatedBy'; + static readonly UPDATED_DATETIME : string ='UpdatedDatetime'; + static readonly USERNAME : string ='Username'; + static readonly DB_NAME_SECURITY_USER_PREFERENCE : string ='security_user_preference'; + static readonly DB_NAME_FIELDS : string ='created_by,created_datetime,preference,preference_key,updated_by,updated_datetime,username'; + static readonly DB_CREATED_BY : string ='created_by'; + static readonly DB_CREATED_DATETIME : string ='created_datetime'; + static readonly DB_PREFERENCE : string ='preference'; + static readonly DB_PREFERENCE_KEY : string ='preference_key'; + static readonly DB_UPDATED_BY : string ='updated_by'; + static readonly DB_UPDATED_DATETIME : string ='updated_datetime'; + static readonly DB_USERNAME : string ='username'; +} diff --git a/WebVue/src/data/auto/securityUserPreferenceEntityKey.ts b/WebVue/src/data/auto/securityUserPreferenceEntityKey.ts new file mode 100644 index 0000000..4a4ca4d --- /dev/null +++ b/WebVue/src/data/auto/securityUserPreferenceEntityKey.ts @@ -0,0 +1,7 @@ + +export class SecurityUserPreferenceEntityKey +{ + public PreferenceKey: string = ""; + public Username: string = ""; + +} diff --git a/WebVue/src/data/auto/securityUserPreferenceSearchCriteria.ts b/WebVue/src/data/auto/securityUserPreferenceSearchCriteria.ts new file mode 100644 index 0000000..13f4216 --- /dev/null +++ b/WebVue/src/data/auto/securityUserPreferenceSearchCriteria.ts @@ -0,0 +1,6 @@ + +import { AbstractSearchCriteria } from "./abstractSearchCriteria"; +export class SecurityUserPreferenceSearchCriteria extends AbstractSearchCriteria +{ + +} diff --git a/WebVue/src/data/auto/securityUserResultData.ts b/WebVue/src/data/auto/securityUserResultData.ts new file mode 100644 index 0000000..868941c --- /dev/null +++ b/WebVue/src/data/auto/securityUserResultData.ts @@ -0,0 +1,8 @@ + +import { SecurityUserEntity } from "./securityUserEntity"; +import { SearchCriteriaResultData } from "./searchCriteriaResultData"; +export class SecurityUserResultData extends SearchCriteriaResultData +{ + public Datas: SecurityUserEntity[] = []; + +} diff --git a/WebVue/src/data/auto/securityUserSearchCriteria.ts b/WebVue/src/data/auto/securityUserSearchCriteria.ts new file mode 100644 index 0000000..d19cc9f --- /dev/null +++ b/WebVue/src/data/auto/securityUserSearchCriteria.ts @@ -0,0 +1,7 @@ + +import { AbstractSearchCriteria } from "./abstractSearchCriteria"; +export class SecurityUserSearchCriteria extends AbstractSearchCriteria +{ + public UserName: string = ""; + +} diff --git a/WebVue/src/data/auto/securityUserViewEntity.ts b/WebVue/src/data/auto/securityUserViewEntity.ts new file mode 100644 index 0000000..299b83f --- /dev/null +++ b/WebVue/src/data/auto/securityUserViewEntity.ts @@ -0,0 +1,25 @@ + +export class SecurityUserViewEntity +{ + public ActorLocalName: string = ""; + public ActorName: string = ""; + public UserLocalName: string = ""; + public UserMobile: string = ""; + public UserName: string = ""; + public WelcomePage: string = ""; + + static readonly ACTOR_LOCAL_NAME : string ='ActorLocalName'; + static readonly ACTOR_NAME : string ='ActorName'; + static readonly USER_LOCAL_NAME : string ='UserLocalName'; + static readonly USER_MOBILE : string ='UserMobile'; + static readonly USER_NAME : string ='UserName'; + static readonly WELCOME_PAGE : string ='WelcomePage'; + static readonly DB_NAME_SECURITY_USER_VIEW : string ='security_user_view'; + static readonly DB_NAME_FIELDS : string ='actor_local_name,actor_name,user_local_name,user_mobile,user_name,welcome_page'; + static readonly DB_ACTOR_LOCAL_NAME : string ='actor_local_name'; + static readonly DB_ACTOR_NAME : string ='actor_name'; + static readonly DB_USER_LOCAL_NAME : string ='user_local_name'; + static readonly DB_USER_MOBILE : string ='user_mobile'; + static readonly DB_USER_NAME : string ='user_name'; + static readonly DB_WELCOME_PAGE : string ='welcome_page'; +} diff --git a/WebVue/src/data/auto/securityUserWebLoginEntity.ts b/WebVue/src/data/auto/securityUserWebLoginEntity.ts new file mode 100644 index 0000000..7117b84 --- /dev/null +++ b/WebVue/src/data/auto/securityUserWebLoginEntity.ts @@ -0,0 +1,31 @@ + +export class SecurityUserWebLoginEntity +{ + public HostIp: string = ""; + public HostUserAgent: string = ""; + public LoginTime: Date = new Date(); + public LogoutTime?: Date= null!; + public RefreshToken: string = ""; + public RefreshTokenRefreshedTime: Date = new Date(); + public SessionId: string = ""; + public Username: string = ""; + + static readonly HOST_IP : string ='HostIp'; + static readonly HOST_USER_AGENT : string ='HostUserAgent'; + static readonly LOGIN_TIME : string ='LoginTime'; + static readonly LOGOUT_TIME : string ='LogoutTime'; + static readonly REFRESH_TOKEN : string ='RefreshToken'; + static readonly REFRESH_TOKEN_REFRESHED_TIME : string ='RefreshTokenRefreshedTime'; + static readonly SESSION_ID : string ='SessionId'; + static readonly USERNAME : string ='Username'; + static readonly DB_NAME_SECURITY_USER_WEB_LOGIN : string ='security_user_web_login'; + static readonly DB_NAME_FIELDS : string ='host_ip,host_user_agent,login_time,logout_time,refresh_token,refresh_token_refreshed_time,session_id,username'; + static readonly DB_HOST_IP : string ='host_ip'; + static readonly DB_HOST_USER_AGENT : string ='host_user_agent'; + static readonly DB_LOGIN_TIME : string ='login_time'; + static readonly DB_LOGOUT_TIME : string ='logout_time'; + static readonly DB_REFRESH_TOKEN : string ='refresh_token'; + static readonly DB_REFRESH_TOKEN_REFRESHED_TIME : string ='refresh_token_refreshed_time'; + static readonly DB_SESSION_ID : string ='session_id'; + static readonly DB_USERNAME : string ='username'; +} diff --git a/WebVue/src/data/auto/securityUserWebLoginEntityKey.ts b/WebVue/src/data/auto/securityUserWebLoginEntityKey.ts new file mode 100644 index 0000000..d8258d8 --- /dev/null +++ b/WebVue/src/data/auto/securityUserWebLoginEntityKey.ts @@ -0,0 +1,7 @@ + +export class SecurityUserWebLoginEntityKey +{ + public SessionId: string = ""; + public Username: string = ""; + +} diff --git a/WebVue/src/data/auto/securityUserWebPagePreferenceEntity.ts b/WebVue/src/data/auto/securityUserWebPagePreferenceEntity.ts new file mode 100644 index 0000000..32ef48c --- /dev/null +++ b/WebVue/src/data/auto/securityUserWebPagePreferenceEntity.ts @@ -0,0 +1,34 @@ + +export class SecurityUserWebPagePreferenceEntity +{ + public CreatedBy: string = ""; + public CreatedDatetime: Date = new Date(); + public DefaultIndc: string = ""; + public Preference: string = ""; + public PreferenceKey: string = ""; + public ProfileName: string = ""; + public UpdatedBy: string = ""; + public UpdatedDatetime: Date = new Date(); + public Username: string = ""; + + static readonly CREATED_BY : string ='CreatedBy'; + static readonly CREATED_DATETIME : string ='CreatedDatetime'; + static readonly DEFAULT_INDC : string ='DefaultIndc'; + static readonly PREFERENCE : string ='Preference'; + static readonly PREFERENCE_KEY : string ='PreferenceKey'; + static readonly PROFILE_NAME : string ='ProfileName'; + static readonly UPDATED_BY : string ='UpdatedBy'; + static readonly UPDATED_DATETIME : string ='UpdatedDatetime'; + static readonly USERNAME : string ='Username'; + static readonly DB_NAME_SECURITY_USER_WEB_PAGE_PREFERENCE : string ='security_user_web_page_preference'; + static readonly DB_NAME_FIELDS : string ='created_by,created_datetime,default_indc,preference,preference_key,profile_name,updated_by,updated_datetime,username'; + static readonly DB_CREATED_BY : string ='created_by'; + static readonly DB_CREATED_DATETIME : string ='created_datetime'; + static readonly DB_DEFAULT_INDC : string ='default_indc'; + static readonly DB_PREFERENCE : string ='preference'; + static readonly DB_PREFERENCE_KEY : string ='preference_key'; + static readonly DB_PROFILE_NAME : string ='profile_name'; + static readonly DB_UPDATED_BY : string ='updated_by'; + static readonly DB_UPDATED_DATETIME : string ='updated_datetime'; + static readonly DB_USERNAME : string ='username'; +} diff --git a/WebVue/src/data/auto/securityUserWebPagePreferenceEntityKey.ts b/WebVue/src/data/auto/securityUserWebPagePreferenceEntityKey.ts new file mode 100644 index 0000000..523dfea --- /dev/null +++ b/WebVue/src/data/auto/securityUserWebPagePreferenceEntityKey.ts @@ -0,0 +1,8 @@ + +export class SecurityUserWebPagePreferenceEntityKey +{ + public PreferenceKey: string = ""; + public ProfileName: string = ""; + public Username: string = ""; + +} diff --git a/WebVue/src/data/auto/selectOption.ts b/WebVue/src/data/auto/selectOption.ts new file mode 100644 index 0000000..ab01592 --- /dev/null +++ b/WebVue/src/data/auto/selectOption.ts @@ -0,0 +1,7 @@ + +export class SelectOption +{ + public DisplayName: string = ""; + public BindValue: string = ""; + +} diff --git a/WebVue/src/data/auto/sysTablePkeyViewEntity.ts b/WebVue/src/data/auto/sysTablePkeyViewEntity.ts new file mode 100644 index 0000000..40b661f --- /dev/null +++ b/WebVue/src/data/auto/sysTablePkeyViewEntity.ts @@ -0,0 +1,25 @@ + +export class SysTablePkeyViewEntity +{ + public ColumnName: string = ""; + public Pk: number = 0; + public PkName: string = ""; + public TableName: string = ""; + public TableOwner: string = ""; + public TableQualifier: string = ""; + + static readonly COLUMN_NAME : string ='ColumnName'; + static readonly PK : string ='Pk'; + static readonly PK_NAME : string ='PkName'; + static readonly TABLE_NAME : string ='TableName'; + static readonly TABLE_OWNER : string ='TableOwner'; + static readonly TABLE_QUALIFIER : string ='TableQualifier'; + static readonly DB_NAME_SYS_TABLE_PKEY_VIEW : string ='sys_table_pkey_view'; + static readonly DB_NAME_FIELDS : string ='column_name,pk,pk_name,table_name,table_owner,table_qualifier'; + static readonly DB_COLUMN_NAME : string ='column_name'; + static readonly DB_PK : string ='pk'; + static readonly DB_PK_NAME : string ='pk_name'; + static readonly DB_TABLE_NAME : string ='table_name'; + static readonly DB_TABLE_OWNER : string ='table_owner'; + static readonly DB_TABLE_QUALIFIER : string ='table_qualifier'; +} diff --git a/WebVue/src/data/auto/sysTableSchemaViewEntity.ts b/WebVue/src/data/auto/sysTableSchemaViewEntity.ts new file mode 100644 index 0000000..5d2d751 --- /dev/null +++ b/WebVue/src/data/auto/sysTableSchemaViewEntity.ts @@ -0,0 +1,52 @@ + +export class SysTableSchemaViewEntity +{ + public Colid: number = 0; + public FieldDefaultValue: string = ""; + public FieldName: string = ""; + public FindBy: number = 0; + public IsIdentity: number = 0; + public IsNullAble: string = ""; + public MaxLength: number = 0; + public Operation: number = 0; + public Pk: number = 0; + public PkName: string = ""; + public Scale: number = 0; + public TableName: string = ""; + public TypeName: string = ""; + public TypeOfName: string = ""; + public Xtype: string = ""; + + static readonly COLID : string ='Colid'; + static readonly FIELD_DEFAULT_VALUE : string ='FieldDefaultValue'; + static readonly FIELD_NAME : string ='FieldName'; + static readonly FIND_BY : string ='FindBy'; + static readonly IS_IDENTITY : string ='IsIdentity'; + static readonly IS_NULL_ABLE : string ='IsNullAble'; + static readonly MAX_LENGTH : string ='MaxLength'; + static readonly OPERATION : string ='Operation'; + static readonly PK : string ='Pk'; + static readonly PK_NAME : string ='PkName'; + static readonly SCALE : string ='Scale'; + static readonly TABLE_NAME : string ='TableName'; + static readonly TYPE_NAME : string ='TypeName'; + static readonly TYPE_OF_NAME : string ='TypeOfName'; + static readonly XTYPE : string ='Xtype'; + static readonly DB_NAME_SYS_TABLE_SCHEMA_VIEW : string ='sys_table_schema_view'; + static readonly DB_NAME_FIELDS : string ='colid,field_default_value,field_name,find_by,is_identity,is_null_able,max_length,operation,pk,pk_name,scale,table_name,type_name,type_of_name,xtype'; + static readonly DB_COLID : string ='colid'; + static readonly DB_FIELD_DEFAULT_VALUE : string ='field_default_value'; + static readonly DB_FIELD_NAME : string ='field_name'; + static readonly DB_FIND_BY : string ='find_by'; + static readonly DB_IS_IDENTITY : string ='is_identity'; + static readonly DB_IS_NULL_ABLE : string ='is_null_able'; + static readonly DB_MAX_LENGTH : string ='max_length'; + static readonly DB_OPERATION : string ='operation'; + static readonly DB_PK : string ='pk'; + static readonly DB_PK_NAME : string ='pk_name'; + static readonly DB_SCALE : string ='scale'; + static readonly DB_TABLE_NAME : string ='table_name'; + static readonly DB_TYPE_NAME : string ='type_name'; + static readonly DB_TYPE_OF_NAME : string ='type_of_name'; + static readonly DB_XTYPE : string ='xtype'; +} diff --git a/WebVue/src/service/security/authService.ts b/WebVue/src/service/security/authService.ts new file mode 100644 index 0000000..00ba45e --- /dev/null +++ b/WebVue/src/service/security/authService.ts @@ -0,0 +1,144 @@ + +import { request } from "@/utils/request"; + import type { LoginData } from "@/data/auto/loginData"; + import type { LoginProfile } from "@/data/auto/loginProfile"; + import type { RegisterData } from "@/data/auto/registerData"; + import type { JwtInfo } from "@/data/auto/jwtInfo"; + import type { FinishBiometricRegistrationData } from "@/data/auto/finishBiometricRegistrationData"; + import type { BiometricRegistrationResultDto } from "@/data/auto/biometricRegistrationResultDto"; + import type { BiometricLoginChallengeDto } from "@/data/auto/biometricLoginChallengeDto"; + import type { FinishBiometricLoginData } from "@/data/auto/finishBiometricLoginData"; + +class AuthService{ + + async Login(data: LoginData) { + return request( + { + url: "/Auth/Login", + method: "post", + data, + } + ) + }; + + async LoginAgent(data: LoginData) { + return request( + { + url: "/Auth/LoginAgent", + method: "post", + data, + } + ) + }; + + async Register(data: RegisterData) { + return request( + { + url: "/Auth/Register", + method: "post", + data, + } + ) + }; + + async AmendPassword(data: LoginData) { + return request( + { + url: "/Auth/AmendPassword", + method: "post", + data, + } + ) + }; + + async GetRsaPublicKey() { + return request( + { + url: "/Auth/GetRsaPublicKey", + method: "get", + } + ) + }; + + async RefreshToken(data: JwtInfo) { + return request( + { + url: "/Auth/RefreshToken", + method: "post", + data, + } + ) + }; + + async Logout() { + return request( + { + url: "/Auth/Logout", + method: "post", + } + ) + }; + + async ConfirmPassword(data: string) { + return request( + { + url: "/Auth/ConfirmPassword?password="+data, + method: "post", + data, + } + ) + }; + + async BeginBiometricRegistration(data: string) { + return request( + { + url: "/Auth/BeginBiometricRegistration?deviceName="+data, + method: "post", + data, + } + ) + }; + + async FinishBiometricRegistration(data: FinishBiometricRegistrationData) { + return request( + { + url: "/Auth/FinishBiometricRegistration", + method: "post", + data, + } + ) + }; + + async BeginBiometricLogin(data: string) { + return request( + { + url: "/Auth/BeginBiometricLogin?username="+data, + method: "post", + data, + } + ) + }; + + async FinishBiometricLogin(data: FinishBiometricLoginData) { + return request( + { + url: "/Auth/FinishBiometricLogin", + method: "post", + data, + } + ) + }; + + async RemoveBiometric() { + return request( + { + url: "/Auth/RemoveBiometric", + method: "post", + } + ) + }; + +} + +const authService= new AuthService(); +export default authService; \ No newline at end of file diff --git a/WebVue/src/service/security/localeService.ts b/WebVue/src/service/security/localeService.ts new file mode 100644 index 0000000..f41a48d --- /dev/null +++ b/WebVue/src/service/security/localeService.ts @@ -0,0 +1,83 @@ + +import { request } from "@/utils/request"; + import type { LocaleEntity } from "@/data/auto/localeEntity"; + import type { LocaleSearchCriteria } from "@/data/auto/localeSearchCriteria"; + import type { LocaleResultData } from "@/data/auto/localeResultData"; + import type { LocaleEntityKey } from "@/data/auto/localeEntityKey"; + import type { LocaleData } from "@/data/auto/localeData"; + +class LocaleService{ + + async FindAll() { + return request( + { + url: "/Locale/FindAll", + method: "get", + } + ) + }; + + async FindBySearchCriteria(data: LocaleSearchCriteria) { + return request( + { + url: "/Locale/FindBySearchCriteria", + method: "post", + data, + } + ) + }; + + async FindByKey(data: LocaleEntityKey) { + return request( + { + url: "/Locale/FindByKey", + method: "post", + data, + } + ) + }; + + async Insert(data: LocaleEntity) { + return request( + { + url: "/Locale/Insert", + method: "post", + data, + } + ) + }; + + async Update(data: LocaleEntity) { + return request( + { + url: "/Locale/Update", + method: "post", + data, + } + ) + }; + + async UpdateLocaleData(data: LocaleData) { + return request( + { + url: "/Locale/UpdateLocaleData", + method: "post", + data, + } + ) + }; + + async Delete(data: LocaleEntityKey) { + return request( + { + url: "/Locale/Delete", + method: "post", + data, + } + ) + }; + +} + +const localeService= new LocaleService(); +export default localeService; \ No newline at end of file diff --git a/WebVue/src/service/security/securityActorService.ts b/WebVue/src/service/security/securityActorService.ts new file mode 100644 index 0000000..5567a5a --- /dev/null +++ b/WebVue/src/service/security/securityActorService.ts @@ -0,0 +1,102 @@ + +import { request,download } from "@/utils/request"; + import type { SecurityActorData } from "@/data/auto/securityActorData"; + import type { SecurityActorEntity } from "@/data/auto/securityActorEntity"; + import type { SecurityActorSearchCriteria } from "@/data/auto/securityActorSearchCriteria"; + import type { SecurityActorResultData } from "@/data/auto/securityActorResultData"; + +class SecurityActorService{ + + async FindByKey(data: string) { + return request( + { + url: "/SecurityActor/FindByKey?key="+data, + method: "post", + data, + } + ) + }; + + async FindAll() { + return request( + { + url: "/SecurityActor/FindAll", + method: "post", + } + ) + }; + + async FindAllByNoPermission() { + return request( + { + url: "/SecurityActor/FindAllByNoPermission", + method: "post", + } + ) + }; + + async FindBySearchCriteria(data: SecurityActorSearchCriteria) { + return request( + { + url: "/SecurityActor/FindBySearchCriteria", + method: "post", + data, + } + ) + }; + + async PrintBySearchCriteria(data: SecurityActorSearchCriteria) { + return download( + { + url: "/SecurityActor/PrintBySearchCriteria", + method: "post", + data, + filename:'SecurityActor' + } + ) + }; + + async Insert(data: SecurityActorData) { + return request( + { + url: "/SecurityActor/Insert", + method: "post", + data, + } + ) + }; + + async Update(data: SecurityActorData) { + return request( + { + url: "/SecurityActor/Update", + method: "post", + data, + } + ) + }; + + async Delete(data: string) { + return request( + { + url: "/SecurityActor/Delete?key="+data, + method: "post", + data, + } + ) + }; + + async Deletes(data: String[]) { + return request( + { + url: "/SecurityActor/Deletes", + method: "post", + data, + } + ) + }; + +} + +const securityActorService= new SecurityActorService(); +export default securityActorService; \ No newline at end of file diff --git a/WebVue/src/service/security/securityFunctionService.ts b/WebVue/src/service/security/securityFunctionService.ts new file mode 100644 index 0000000..7b270bf --- /dev/null +++ b/WebVue/src/service/security/securityFunctionService.ts @@ -0,0 +1,104 @@ + +import { request,download } from "@/utils/request"; + import type { SecurityFunctionData } from "@/data/auto/securityFunctionData"; + import type { SecurityFunctionSearchCriteria } from "@/data/auto/securityFunctionSearchCriteria"; + import type { SecurityFunctionResultData } from "@/data/auto/securityFunctionResultData"; + import type { SecurityFunctionEntity } from "@/data/auto/securityFunctionEntity"; + import type { SecurityFunctionDisplayData } from "@/data/auto/securityFunctionDisplayData"; + +class SecurityFunctionService{ + + async FindByKey(data: string) { + return request( + { + url: "/SecurityFunction/FindByKey?key="+data, + method: "post", + data, + } + ) + }; + + async FindBySearchCriteria(data: SecurityFunctionSearchCriteria) { + return request( + { + url: "/SecurityFunction/FindBySearchCriteria", + method: "post", + data, + } + ) + }; + + async PrintBySearchCriteria(data: SecurityFunctionSearchCriteria) { + return download( + { + url: "/SecurityFunction/PrintBySearchCriteria", + method: "post", + data, + filename:'SecurityFunction' + } + ) + }; + + async Insert(data: SecurityFunctionData) { + return request( + { + url: "/SecurityFunction/Insert", + method: "post", + data, + } + ) + }; + + async Update(data: SecurityFunctionData) { + return request( + { + url: "/SecurityFunction/Update", + method: "post", + data, + } + ) + }; + + async Delete(data: string) { + return request( + { + url: "/SecurityFunction/Delete?key="+data, + method: "post", + data, + } + ) + }; + + async Deletes(data: String[]) { + return request( + { + url: "/SecurityFunction/Deletes", + method: "post", + data, + } + ) + }; + + async FindByFunctionName(data: string) { + return request( + { + url: "/SecurityFunction/FindByFunctionName?functionName="+data, + method: "post", + data, + } + ) + }; + + async FindMenus() { + return request( + { + url: "/SecurityFunction/FindMenus", + method: "post", + } + ) + }; + +} + +const securityFunctionService= new SecurityFunctionService(); +export default securityFunctionService; \ No newline at end of file diff --git a/WebVue/src/service/security/securityGeneratorNumberService.ts b/WebVue/src/service/security/securityGeneratorNumberService.ts new file mode 100644 index 0000000..b654760 --- /dev/null +++ b/WebVue/src/service/security/securityGeneratorNumberService.ts @@ -0,0 +1,73 @@ + +import { request,download } from "@/utils/request"; + import type { SecurityGeneratorNumberEntity } from "@/data/auto/securityGeneratorNumberEntity"; + import type { SecurityGeneratorNumberSearchCriteria } from "@/data/auto/securityGeneratorNumberSearchCriteria"; + import type { SecurityGeneratorNumberResultData } from "@/data/auto/securityGeneratorNumberResultData"; + +class SecurityGeneratorNumberService{ + + async FindByKey(data: number) { + return request( + { + url: "/SecurityGeneratorNumber/FindByKey?key="+data, + method: "post", + data, + } + ) + }; + + async FindBySearchCriteria(data: SecurityGeneratorNumberSearchCriteria) { + return request( + { + url: "/SecurityGeneratorNumber/FindBySearchCriteria", + method: "post", + data, + } + ) + }; + + async PrintBySearchCriteria(data: SecurityGeneratorNumberSearchCriteria) { + return download( + { + url: "/SecurityGeneratorNumber/PrintBySearchCriteria", + method: "post", + data, + filename:'SecurityGeneratorNumber' + } + ) + }; + + async Insert(data: SecurityGeneratorNumberEntity) { + return request( + { + url: "/SecurityGeneratorNumber/Insert", + method: "post", + data, + } + ) + }; + + async Update(data: SecurityGeneratorNumberEntity) { + return request( + { + url: "/SecurityGeneratorNumber/Update", + method: "post", + data, + } + ) + }; + + async Delete(data: number) { + return request( + { + url: "/SecurityGeneratorNumber/Delete?key="+data, + method: "post", + data, + } + ) + }; + +} + +const securityGeneratorNumberService= new SecurityGeneratorNumberService(); +export default securityGeneratorNumberService; \ No newline at end of file diff --git a/WebVue/src/service/security/securityGroupService.ts b/WebVue/src/service/security/securityGroupService.ts new file mode 100644 index 0000000..f82d34f --- /dev/null +++ b/WebVue/src/service/security/securityGroupService.ts @@ -0,0 +1,93 @@ + +import { request,download } from "@/utils/request"; + import type { SecurityGroupData } from "@/data/auto/securityGroupData"; + import type { SecurityGroupEntity } from "@/data/auto/securityGroupEntity"; + import type { SecurityGroupSearchCriteria } from "@/data/auto/securityGroupSearchCriteria"; + import type { SecurityGroupResultData } from "@/data/auto/securityGroupResultData"; + +class SecurityGroupService{ + + async FindByKey(data: string) { + return request( + { + url: "/SecurityGroup/FindByKey?key="+data, + method: "post", + data, + } + ) + }; + + async FindAll() { + return request( + { + url: "/SecurityGroup/FindAll", + method: "post", + } + ) + }; + + async FindBySearchCriteria(data: SecurityGroupSearchCriteria) { + return request( + { + url: "/SecurityGroup/FindBySearchCriteria", + method: "post", + data, + } + ) + }; + + async PrintBySearchCriteria(data: SecurityGroupSearchCriteria) { + return download( + { + url: "/SecurityGroup/PrintBySearchCriteria", + method: "post", + data, + filename:'SecurityGroup' + } + ) + }; + + async Insert(data: SecurityGroupData) { + return request( + { + url: "/SecurityGroup/Insert", + method: "post", + data, + } + ) + }; + + async Update(data: SecurityGroupData) { + return request( + { + url: "/SecurityGroup/Update", + method: "post", + data, + } + ) + }; + + async Delete(data: string) { + return request( + { + url: "/SecurityGroup/Delete?key="+data, + method: "post", + data, + } + ) + }; + + async Deletes(data: String[]) { + return request( + { + url: "/SecurityGroup/Deletes", + method: "post", + data, + } + ) + }; + +} + +const securityGroupService= new SecurityGroupService(); +export default securityGroupService; \ No newline at end of file diff --git a/WebVue/src/service/security/securityLockService.ts b/WebVue/src/service/security/securityLockService.ts new file mode 100644 index 0000000..e98523d --- /dev/null +++ b/WebVue/src/service/security/securityLockService.ts @@ -0,0 +1,101 @@ + +import { request } from "@/utils/request"; + import type { SecurityLockEntityKey } from "@/data/auto/securityLockEntityKey"; + import type { SecurityLockEntity } from "@/data/auto/securityLockEntity"; + +class SecurityLockService{ + + async FindByKey(data: SecurityLockEntityKey) { + return request( + { + url: "/SecurityLock/FindByKey", + method: "post", + data, + } + ) + }; + + async Insert(data: SecurityLockEntity) { + return request( + { + url: "/SecurityLock/Insert", + method: "post", + data, + } + ) + }; + + async Update(data: SecurityLockEntity) { + return request( + { + url: "/SecurityLock/Update", + method: "post", + data, + } + ) + }; + + async Delete(data: SecurityLockEntityKey) { + return request( + { + url: "/SecurityLock/Delete", + method: "post", + data, + } + ) + }; + + async IsLocked(data: any) { + return request( + { + url: "/SecurityLock/IsLocked", + method: "post", + data, + } + ) + }; + + async Lock(data: any) { + return request( + { + url: "/SecurityLock/Lock", + method: "post", + data, + } + ) + }; + + async ForceLock(data: any) { + return request( + { + url: "/SecurityLock/ForceLock", + method: "post", + data, + } + ) + }; + + async ConsumeLock(data: any) { + return request( + { + url: "/SecurityLock/ConsumeLock", + method: "post", + data, + } + ) + }; + + async ClearLock(data: any) { + return request( + { + url: "/SecurityLock/ClearLock", + method: "post", + data, + } + ) + }; + +} + +const securityLockService= new SecurityLockService(); +export default securityLockService; \ No newline at end of file diff --git a/WebVue/src/service/security/securityMasterService.ts b/WebVue/src/service/security/securityMasterService.ts new file mode 100644 index 0000000..9e19bd3 --- /dev/null +++ b/WebVue/src/service/security/securityMasterService.ts @@ -0,0 +1,93 @@ + +import { request,download } from "@/utils/request"; + import type { SecurityMasterEntityKey } from "@/data/auto/securityMasterEntityKey"; + import type { SecurityMasterEntity } from "@/data/auto/securityMasterEntity"; + import type { SecurityMasterSearchCriteria } from "@/data/auto/securityMasterSearchCriteria"; + import type { SecurityMasterResultData } from "@/data/auto/securityMasterResultData"; + +class SecurityMasterService{ + + async FindByKey(data: SecurityMasterEntityKey) { + return request( + { + url: "/SecurityMaster/FindByKey", + method: "post", + data, + } + ) + }; + + async FindAll() { + return request( + { + url: "/SecurityMaster/FindAll", + method: "get", + } + ) + }; + + async FindBySearchCriteria(data: SecurityMasterSearchCriteria) { + return request( + { + url: "/SecurityMaster/FindBySearchCriteria", + method: "post", + data, + } + ) + }; + + async PrintBySearchCriteria(data: SecurityMasterSearchCriteria) { + return download( + { + url: "/SecurityMaster/PrintBySearchCriteria", + method: "post", + data, + filename:'SecurityMaster' + } + ) + }; + + async Insert(data: SecurityMasterEntity) { + return request( + { + url: "/SecurityMaster/Insert", + method: "post", + data, + } + ) + }; + + async Update(data: SecurityMasterEntity) { + return request( + { + url: "/SecurityMaster/Update", + method: "post", + data, + } + ) + }; + + async Delete(data: SecurityMasterEntityKey) { + return request( + { + url: "/SecurityMaster/Delete", + method: "post", + data, + } + ) + }; + + async Deletes(data: SecurityMasterEntity[]) { + return request( + { + url: "/SecurityMaster/Deletes", + method: "post", + data, + } + ) + }; + +} + +const securityMasterService= new SecurityMasterService(); +export default securityMasterService; \ No newline at end of file diff --git a/WebVue/src/service/security/securityPermissionService.ts b/WebVue/src/service/security/securityPermissionService.ts new file mode 100644 index 0000000..787ce66 --- /dev/null +++ b/WebVue/src/service/security/securityPermissionService.ts @@ -0,0 +1,103 @@ + +import { request,download } from "@/utils/request"; + import type { SecurityPermissionData } from "@/data/auto/securityPermissionData"; + import type { SecurityPermissionSearchCriteria } from "@/data/auto/securityPermissionSearchCriteria"; + import type { SecurityPermissionResultData } from "@/data/auto/securityPermissionResultData"; + +class SecurityPermissionService{ + + async FindByKey(data: string) { + return request( + { + url: "/SecurityPermission/FindByKey?key="+data, + method: "post", + data, + } + ) + }; + + async FindBySearchCriteria(data: SecurityPermissionSearchCriteria) { + return request( + { + url: "/SecurityPermission/FindBySearchCriteria", + method: "post", + data, + } + ) + }; + + async FindDependentBySearchCriteria(data: SecurityPermissionSearchCriteria) { + return request( + { + url: "/SecurityPermission/FindDependentBySearchCriteria", + method: "post", + data, + } + ) + }; + + async FindDependentsBySearchCriteria(data: SecurityPermissionSearchCriteria) { + return request( + { + url: "/SecurityPermission/FindDependentsBySearchCriteria", + method: "post", + data, + } + ) + }; + + async PrintBySearchCriteria(data: SecurityPermissionSearchCriteria) { + return download( + { + url: "/SecurityPermission/PrintBySearchCriteria", + method: "post", + data, + filename:'SecurityPermission' + } + ) + }; + + async Insert(data: SecurityPermissionData) { + return request( + { + url: "/SecurityPermission/Insert", + method: "post", + data, + } + ) + }; + + async Update(data: SecurityPermissionData) { + return request( + { + url: "/SecurityPermission/Update", + method: "post", + data, + } + ) + }; + + async Delete(data: string) { + return request( + { + url: "/SecurityPermission/Delete?key="+data, + method: "post", + data, + } + ) + }; + + async Deletes(data: String[]) { + return request( + { + url: "/SecurityPermission/Deletes", + method: "post", + data, + } + ) + }; + +} + +const securityPermissionService= new SecurityPermissionService(); +export default securityPermissionService; \ No newline at end of file diff --git a/WebVue/src/service/security/securityUserPreferenceService.ts b/WebVue/src/service/security/securityUserPreferenceService.ts new file mode 100644 index 0000000..37766f9 --- /dev/null +++ b/WebVue/src/service/security/securityUserPreferenceService.ts @@ -0,0 +1,73 @@ + +import { request,download } from "@/utils/request"; + import type { SecurityUserPreferenceEntityKey } from "@/data/auto/securityUserPreferenceEntityKey"; + import type { SecurityUserPreferenceEntity } from "@/data/auto/securityUserPreferenceEntity"; + import type { SecurityUserPreferenceSearchCriteria } from "@/data/auto/securityUserPreferenceSearchCriteria"; + +class SecurityUserPreferenceService{ + + async FindByKey(data: SecurityUserPreferenceEntityKey) { + return request( + { + url: "/SecurityUserPreference/FindByKey", + method: "post", + data, + } + ) + }; + + async FindBySearchCriteria(data: SecurityUserPreferenceSearchCriteria) { + return request( + { + url: "/SecurityUserPreference/FindBySearchCriteria", + method: "post", + data, + } + ) + }; + + async PrintBySearchCriteria(data: SecurityUserPreferenceSearchCriteria) { + return download( + { + url: "/SecurityUserPreference/PrintBySearchCriteria", + method: "post", + data, + filename:'SecurityUserPreference' + } + ) + }; + + async Insert(data: SecurityUserPreferenceEntity) { + return request( + { + url: "/SecurityUserPreference/Insert", + method: "post", + data, + } + ) + }; + + async Update(data: SecurityUserPreferenceEntity) { + return request( + { + url: "/SecurityUserPreference/Update", + method: "post", + data, + } + ) + }; + + async Delete(data: SecurityUserPreferenceEntityKey) { + return request( + { + url: "/SecurityUserPreference/Delete", + method: "post", + data, + } + ) + }; + +} + +const securityUserPreferenceService= new SecurityUserPreferenceService(); +export default securityUserPreferenceService; \ No newline at end of file diff --git a/WebVue/src/service/security/securityUserService.ts b/WebVue/src/service/security/securityUserService.ts new file mode 100644 index 0000000..32cf8be --- /dev/null +++ b/WebVue/src/service/security/securityUserService.ts @@ -0,0 +1,123 @@ + +import { request,download } from "@/utils/request"; + import type { SecurityUserEntity } from "@/data/auto/securityUserEntity"; + import type { SecurityUserData } from "@/data/auto/securityUserData"; + import type { SecurityUserSearchCriteria } from "@/data/auto/securityUserSearchCriteria"; + import type { SecurityUserResultData } from "@/data/auto/securityUserResultData"; + import type { SecurityFunctionResultData } from "@/data/auto/securityFunctionResultData"; + +class SecurityUserService{ + + async FindByStaffId(data: string) { + return request( + { + url: "/SecurityUser/FindByStaffId?staffid="+data, + method: "post", + data, + } + ) + }; + + async FindByKey(data: string) { + return request( + { + url: "/SecurityUser/FindByKey?key="+data, + method: "post", + data, + } + ) + }; + + async FindAll() { + return request( + { + url: "/SecurityUser/FindAll", + method: "post", + } + ) + }; + + async FindBySearchCriteria(data: SecurityUserSearchCriteria) { + return request( + { + url: "/SecurityUser/FindBySearchCriteria", + method: "post", + data, + } + ) + }; + + async PrintBySearchCriteria(data: SecurityUserSearchCriteria) { + return download( + { + url: "/SecurityUser/PrintBySearchCriteria", + method: "post", + data, + filename:'SecurityUser' + } + ) + }; + + async Insert(data: SecurityUserData) { + return request( + { + url: "/SecurityUser/Insert", + method: "post", + data, + } + ) + }; + + async Update(data: SecurityUserData) { + return request( + { + url: "/SecurityUser/Update", + method: "post", + data, + } + ) + }; + + async Delete(data: string) { + return request( + { + url: "/SecurityUser/Delete?key="+data, + method: "post", + data, + } + ) + }; + + async Deletes(data: String[]) { + return request( + { + url: "/SecurityUser/Deletes", + method: "post", + data, + } + ) + }; + + async FindMenuByUsername() { + return request( + { + url: "/SecurityUser/FindMenuByUsername", + method: "post", + } + ) + }; + + async UpdateLocalName(data: string) { + return request( + { + url: "/SecurityUser/UpdateLocalName?localName="+data, + method: "post", + data, + } + ) + }; + +} + +const securityUserService= new SecurityUserService(); +export default securityUserService; \ No newline at end of file diff --git a/WebVue/src/service/security/yesNoPolicyService.ts b/WebVue/src/service/security/yesNoPolicyService.ts new file mode 100644 index 0000000..d0c4aab --- /dev/null +++ b/WebVue/src/service/security/yesNoPolicyService.ts @@ -0,0 +1,29 @@ + +import { request } from "@/utils/request"; + import type { SelectOption } from "@/data/auto/selectOption"; + +class YesNoPolicyService{ + + async FindSelectOption(data: any) { + return request( + { + url: "/YesNoPolicy/FindSelectOption?blank="+data, + method: "post", + data, + } + ) + }; + + async Copy() { + return request( + { + url: "/YesNoPolicy/Copy", + method: "get", + } + ) + }; + +} + +const yesNoPolicyService= new YesNoPolicyService(); +export default yesNoPolicyService; \ No newline at end of file