Fixed strict mock failures to account for permissions check

--- DotNet/FluentBoilerplate.Tests/Runtime/Contexts/InitialBoilerplateContextTests/Do.cs
+++ DotNet/FluentBoilerplate.Tests/Runtime/Contexts/InitialBoilerplateContextTests/Do.cs
@@ -42,8 +42,12 @@
         [TestMethod]
         public void WillPerformActionWithNoContract()
         {
+            var permissions = new Mock<IPermissionsProvider>(MockBehavior.Strict);
+            permissions.Setup(x => x.HasPermission(It.IsAny<IIdentity>())).Returns(true);
+
             var bundle = new Mock<IContextBundle>(MockBehavior.Strict);
             bundle.Setup(x => x.Errors).Returns(() => new ImmutableErrorContext(LogProvider.Empty, TryCatchBlockProvider.Empty, ExceptionHandlerProvider.Empty));
+            bundle.Setup(x => x.Permissions).Returns(permissions.Object);
             bundle.Setup(x => x.Copy(It.IsAny<IPermissionsProvider>(),
                                      It.IsAny<IImmutableErrorContext>(),
                                      It.IsAny<ITypeAccessProvider>(),
@@ -71,8 +75,12 @@
             IImmutableErrorContext errorContext = new ImmutableErrorContext(LogProvider.Empty, TryCatchBlockProvider.Empty, ExceptionHandlerProvider.Empty);
             errorContext = errorContext.RegisterExceptionHandler<Exception>(ex => {});

-            var bundle = new Mock<IContextBundle>(MockBehavior.Strict);
-            bundle.Setup(x => x.Errors).Returns(() => errorContext);
+            var permissions = new Mock<IPermissionsProvider>(MockBehavior.Strict);
+            permissions.Setup(x => x.HasPermission(It.IsAny<IIdentity>())).Returns(true);
+
+            var bundle = new Mock<IContextBundle>(MockBehavior.Strict);
+            bundle.Setup(x => x.Errors).Returns(() => errorContext);
+            bundle.Setup(x => x.Permissions).Returns(permissions.Object);
             bundle.Setup(x => x.Copy(It.IsAny<IPermissionsProvider>(),
                                      It.IsAny<IImmutableErrorContext>(),
                                      It.IsAny<ITypeAccessProvider>(),
@@ -101,8 +109,12 @@
             IImmutableErrorContext errorContext = new ImmutableErrorContext(LogProvider.Empty, TryCatchBlockProvider.Empty, ExceptionHandlerProvider.Empty);
             errorContext = errorContext.RegisterExceptionHandler<Exception>(ex => { });

-            var bundle = new Mock<IContextBundle>(MockBehavior.Strict);
-            bundle.Setup(x => x.Errors).Returns(() => errorContext);
+            var permissions = new Mock<IPermissionsProvider>(MockBehavior.Strict);
+            permissions.Setup(x => x.HasPermission(It.IsAny<IIdentity>())).Returns(true);
+
+            var bundle = new Mock<IContextBundle>(MockBehavior.Strict);
+            bundle.Setup(x => x.Errors).Returns(() => errorContext);
+            bundle.Setup(x => x.Permissions).Returns(permissions.Object);
             bundle.Setup(x => x.Copy(It.IsAny<IPermissionsProvider>(),
                                      It.IsAny<IImmutableErrorContext>(),
                                      It.IsAny<ITypeAccessProvider>(),
@@ -129,9 +141,13 @@
         {
             IImmutableErrorContext errorContext = new ImmutableErrorContext(LogProvider.Empty, TryCatchBlockProvider.Empty, ExceptionHandlerProvider.Empty);
             errorContext = errorContext.RegisterExceptionHandler<Exception>(ex => { });
-
-            var bundle = new Mock<IContextBundle>(MockBehavior.Strict);
-            bundle.Setup(x => x.Errors).Returns(() => errorContext);
+
+            var permissions = new Mock<IPermissionsProvider>(MockBehavior.Strict);
+            permissions.Setup(x => x.HasPermission(It.IsAny<IIdentity>())).Returns(true);
+
+            var bundle = new Mock<IContextBundle>(MockBehavior.Strict);
+            bundle.Setup(x => x.Errors).Returns(() => errorContext);
+            bundle.Setup(x => x.Permissions).Returns(permissions.Object);
             bundle.Setup(x => x.Copy(It.IsAny<IPermissionsProvider>(),
                                      It.IsAny<IImmutableErrorContext>(),
                                      It.IsAny<ITypeAccessProvider>(),
@@ -163,8 +179,12 @@
             IImmutableErrorContext errorContext = new ImmutableErrorContext(LogProvider.Empty, TryCatchBlockProvider.Empty, ExceptionHandlerProvider.Empty);
             errorContext = errorContext.RegisterExceptionHandler<Exception>(ex => { });

-            var bundle = new Mock<IContextBundle>(MockBehavior.Strict);
-            bundle.Setup(x => x.Errors).Returns(() => errorContext);
+            var permissions = new Mock<IPermissionsProvider>(MockBehavior.Strict);
+            permissions.Setup(x => x.HasPermission(It.IsAny<IIdentity>())).Returns(true);
+
+            var bundle = new Mock<IContextBundle>(MockBehavior.Strict);
+            bundle.Setup(x => x.Errors).Returns(() => errorContext);
+            bundle.Setup(x => x.Permissions).Returns(permissions.Object);
             bundle.Setup(x => x.Copy(It.IsAny<IPermissionsProvider>(),
                                      It.IsAny<IImmutableErrorContext>(),
                                      It.IsAny<ITypeAccessProvider>(),
@@ -190,8 +210,13 @@
             IImmutableErrorContext errorContext = new ImmutableErrorContext(LogProvider.Empty, TryCatchBlockProvider.Empty, ExceptionHandlerProvider.Empty);
             errorContext = errorContext.RegisterExceptionHandler<Exception>(ex => { });

-            var bundle = new Mock<IContextBundle>(MockBehavior.Strict);
-            bundle.Setup(x => x.Errors).Returns(() => errorContext);
+            var permissions = new Mock<IPermissionsProvider>(MockBehavior.Strict);
+            permissions.Setup(x => x.HasPermission(It.IsAny<IIdentity>())).Returns(true);
+
+            var bundle = new Mock<IContextBundle>(MockBehavior.Strict);
+            bundle.Setup(x => x.Errors).Returns(() => errorContext);
+            bundle.Setup(x => x.Permissions).Returns(permissions.Object);
+
             bundle.Setup(x => x.Copy(It.IsAny<IPermissionsProvider>(),
                                      It.IsAny<IImmutableErrorContext>(),
                                      It.IsAny<ITypeAccessProvider>(),


Sample v4.2.0

Sample v4.2.0

--- Samples/netcore3.0-mvc/Senparc.Weixin.Sample.NetCore3/Controllers/CacheController.cs
+++ Samples/netcore3.0-mvc/Senparc.Weixin.Sample.NetCore3/Controllers/CacheController.cs
@@ -141,7 +141,7 @@
                     var containerCache = cacheSet.Value;
                     sb.AppendFormat($"====  开始指定调用缓存策略：{baseCache.GetType().Name} ====

");

-                    sb.Append($"----- 测试写入（先异步后头弄不） -----
");
+                    sb.Append($"----- 测试写入（先异步后同步） -----
");
                     var shortBagKey = SystemTime.Now.ToString("yyyyMMdd-HHmmss") + "." + cacheExpire.GetHashCode();//创建不重复的Key
                     var finalBagKey = baseCache.GetFinalKey(ContainerHelper.GetItemCacheKey(typeof(TestContainerBag1), shortBagKey));//获取最终缓存中的键
                     var bag = new TestContainerBag1()


Add WorkItem attribute

Add WorkItem attribute

--- StyleCop.Analyzers/StyleCop.Analyzers.Test/SpacingRules/NumberSignSpacingTestBase.cs
+++ StyleCop.Analyzers/StyleCop.Analyzers.Test/SpacingRules/NumberSignSpacingTestBase.cs
@@ -532,6 +532,7 @@
         }

         [Fact]
+        [WorkItem(2300, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/2300")]
         public async Task TestPrefixUnaryOperatorInInterpolationBracesAsync()
         {
             string testFormat = @"namespace Namespace


Removed useless comment

Removed useless comment

--- Source/GameFifteen.Models/Grid.cs
+++ Source/GameFifteen.Models/Grid.cs
@@ -171,10 +171,6 @@
                 }
             }

-            /*
-            var emptyTile = this.tiles.Where(t => t.Label == string.Empty).Select(t => t);
-            return (Tile)emptyTile;
-             */
             return null;
         }


[CL-35157] Update to latest perforce change
Change 35157 by waneck@wnk-razer on 2019/06/06 13:48:04

[unreal.hx] Do not escape \ twice

This causes issues with UHT module detection

--- Source/HaxeInit/BuildApi.Build.cs
+++ Source/HaxeInit/BuildApi.Build.cs
@@ -1,538 +1,543 @@
-using Tools.DotNETCommon;
-using System.Collections.Generic;
-using System.Reflection;
-using System.Diagnostics;
-using System;
-using System.IO;
-using UnrealBuildTool;
-
-public class BaseModuleRules : ModuleRules {
-  private static Dictionary<string, bool> firstRunMap = new Dictionary<string, bool>();
-
-  public BaseModuleRules(ReadOnlyTargetRules target) : base(target) {
-    this.internalInit(target);
-    this.init();
-    this.run();
-  }
-
-  public static System.Type getType(string name) {
-    System.Type ret = System.Type.GetType(name);
-    if (ret == null) {
-			foreach (Assembly t2 in AppDomain.CurrentDomain.GetAssemblies()) {
-        ret = t2.GetType(name);
-        if (ret != null) {
-          break;
-        }
-      }
-    }
-    return ret;
-  }
-
-  virtual protected void init() {
-  }
-
-  virtual protected void internalInit(ReadOnlyTargetRules target) {
-  }
-
-  virtual protected void run() {
-    throw new NotImplementedException();
-  }
-}
-
-/**
- * This is a helper that makes it easy to write build code that is compatible with
- * multiple different Unreal Engine versions. Subclassing this is optional
- **/
-public class BaseTargetRules : TargetRules {
-  public BaseTargetRules(TargetInfo target) : base(target) {
-    this.init(target);
-
-    List<string> moduleNames = new List<string>();
-    this.setupBinaries(moduleNames);
-    foreach (string module in moduleNames) {
-      ExtraModuleNames.Add(module);
-    }
-  }
-
-  virtual protected void init(TargetInfo target) {
-  }
-
-  virtual protected void setupBinaries(List<string> moduleNames) {
-  }
-}
-
-public class HaxeModuleRules : BaseModuleRules {
-  /**
-   * Set this to true if you'd like to manually manage the dependencies.
-   * This is faster since Unreal doesn't have to rebuild every time
-   **/
-  public bool manualDependencies;
-  public bool disabled;
-
-  /**
-    This used to be optional, as PreBuildSteps were being used to compile Haxe without the need
-    of Build.cs. However, there are multiple issues with PreBuildSteps currently (see UE-47634)
-    so this is needed. You can still disable this, but make sure to compile Haxe yourself before
-    if you choose to do so.
-   **/
-  public bool forceHaxeCompilation;
-
-  public HaxeConfigOptions options = new HaxeConfigOptions();
-
-  public HaxeModuleRules(ReadOnlyTargetRules target) : base(target) {
-    PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
-  }
-
-  override protected void internalInit(ReadOnlyTargetRules target) {
-    this.forceHaxeCompilation = true;
-  }
-
-  static bool isSkipBuild() {
-    foreach (string arg in Environment.GetCommandLineArgs()) {
-      if (String.Compare(arg, "-SkipBuild", StringComparison.OrdinalIgnoreCase) == 0) {
-        return true;
-      }
-    }
-    return false;
-  }
-
-  static bool isGeneratingProjectFiles() {
-    System.Type t = getType("UnrealBuildTool.ProjectFileGenerator");
-    if (t != null) {
-      FieldInfo f = t.GetField("bGenerateProjectFiles");
-      if (f != null) {
-        return (bool) f.GetValue(null);
-      }
-      PropertyInfo p = t.GetProperty("bGenerateProjectFiles");
-      if (p != null) {
-        return (bool) p.GetValue(null);
-      }
-    }
-    return false;
-  }
-
-  static void resetCachedDirectory(string path) {
-    System.Type t = getType("UnrealBuildTool.DirectoryItem");
-    if (t == null) {
-      Log.TraceWarning("Cannot find DirectoryItem");
-      return;
-    }
-    MethodInfo m = t.GetMethod("GetItemByPath");
-    if (m == null) {
-      Log.TraceWarning("Cannot find GetItemByPath");
-      return;
-    }
-    object dirItem = m.Invoke(null, new object[]{path});
-    if (dirItem == null) {
-      Log.TraceWarning("Cannot gather dirItem for path " + path);
-      return;
-    }
-    MethodInfo reset = t.GetMethod("ResetCachedInfo");
-    if (reset == null) {
-      Log.TraceWarning("Cannot find ResetCachedInfo");
-      return;
-    }
-    reset.Invoke(dirItem, new object[]{});
-  }
-
-  override protected void run() {
-    if (disabled) {
-      Log.TraceInformation("Compiling without Haxe support");
-    }
-
-    if (!manualDependencies) {
-      if (Target.Type != TargetType.Program) {
-        // these are all dependencies on an empty unreal.hx project -
-        // most of them are because of types that reference other modules
-        // without DCE enabled, we can't get past this
-        this.PublicDependencyModuleNames.AddRange(new string[] {
-          "Core",
-          "CoreUObject",
-          "Engine",
-          "InputCore",
-          "SlateCore"
-         });
-        if (Target.Type == TargetType.Editor) {
-          this.PrivateDependencyModuleNames.Add("UnrealEd");
-        }
-      } else {
-        this.PrivateDependencyModuleNames.AddRange(new string[] {
-          "Core",
-          "Projects", // for IPluginManager
-        });
-        // for RequiredProgramMainCPPInclude.h
-        string engineDir = Path.GetFullPath("..");
-        PublicIncludePaths.AddRange(
-          new string[] {
-            engineDir + "/Source/Runtime/Launch/Public",
-            engineDir + "/Source/Runtime/Launch/Private",
-          }
-        );
-      }
-    }
-
-    HaxeCompilationInfo info = setupHaxeTarget(this, this.forceHaxeCompilation, this.options);
-    if (!manualDependencies) {
-      string modulesPath = info.outputDir + "/Data/modules.txt";
-      string curName = this.GetType().Name;
-      if (!File.Exists(modulesPath)) {
-        Log.TraceInformation("Could not find module definition at " + modulesPath);
-      } else {
-        foreach (string dep in File.ReadAllText(modulesPath).Trim().Split('\n')) {
-          if (dep != curName && dep != "") {
-            this.PrivateDependencyModuleNames.Add(dep);
-          }
-        }
-      }
-    }
-    string definesPath = info.outputDir + "/Data/defines.txt";
-    if (!File.Exists(definesPath)) {
-      Log.TraceInformation("Could not find defines file at " + definesPath);
-    } else {
-      foreach (string def in File.ReadAllText(definesPath).Trim().Split('\n')) {
-        if (def != "") {
-          this.PublicDefinitions.Add(def);
-        }
-      }
-    }
-
-    foreach (string path in PublicIncludePaths) {
-      if (Path.IsPathRooted(path) && !Directory.Exists(path)) {
-        Directory.CreateDirectory(path);
-      }
-    }
-    foreach (string path in PrivateIncludePaths) {
-      if (Path.IsPathRooted(path) && !Directory.Exists(path)) {
-        Directory.CreateDirectory(path);
-      }
-    }
-  }
-
-  private static bool addedGenerateFilesHook = false;
-
-  public static HaxeCompilationInfo setupHaxeTarget(ModuleRules rules, bool forceHaxeCompilation, HaxeConfigOptions options) {
-    rules.PublicIncludePaths.Add(Path.Combine(rules.ModuleDirectory, "Generated"));
-    rules.PublicIncludePaths.Add(Path.Combine(rules.ModuleDirectory, "Generated/Public"));
-    rules.PublicIncludePaths.Add(Path.Combine(rules.ModuleDirectory, "Generated/TemplateExport"));
-    rules.PublicIncludePaths.Add(Path.Combine(rules.ModuleDirectory, "Generated/Shared"));
-
-    HaxeCompilationInfo info = new HaxeCompilationInfo(rules);
-    rules.PublicAdditionalLibraries.Add(info.libPath);
-    rules.PublicIncludePaths.Add(Path.Combine(info.outputDir, "Generated/Public"));
-    rules.PublicIncludePaths.Add(Path.Combine(info.outputDir, "Generated/Shared"));
-    rules.PrivateIncludePaths.Add(Path.Combine(info.outputDir, "Generated/Private"));
-    rules.PublicIncludePaths.Add(Path.Combine(info.outputDir, "Template/Shared"));
-    rules.PublicIncludePaths.Add(Path.Combine(info.outputDir, "Template/Public"));
-    rules.PrivateIncludePaths.Add(Path.Combine(info.outputDir, "Template/Private"));
-
-    Log.TraceInformation("BuildApi.Build.cs: Using Haxe");
-    rules.PublicDefinitions.Add("WITH_HAXE=1");
-    rules.PublicDefinitions.Add("HXCPP_EXTERN_CLASS_ATTRIBUTES=");
-    rules.PublicDefinitions.Add("MAY_EXPORT_SYMBOL=");
-
-    if (options != null && options.haxeInstallPath != null) {
-      string haxePath = System.IO.Path.Combine(info.gameDir, options.haxeInstallPath);
-      Environment.SetEnvironmentVariable("HAXEPATH", haxePath);
-      Environment.SetEnvironmentVariable("PATH", haxePath + System.IO.Path.PathSeparator + Environment.GetEnvironmentVariable("PATH"));
-    }
-    if (options != null && options.haxelibPath != null) {
-      string libPath = System.IO.Path.Combine(info.gameDir, options.haxelibPath);
-      Environment.SetEnvironmentVariable("HAXELIB_PATH", libPath);
-    }
-    if (options != null && options.noDynamicObjects) {
-      rules.PublicDefinitions.Add("NO_DYNAMIC_UCLASS=1");
-    } else {
-      rules.PublicDefinitions.Add("NO_DYNAMIC_UCLASS=0");
-    }
-
-
-    #if UE_4_22_OR_LATER
-    ReadOnlyBuildVersion version = rules.Target.Version;
-    #else
-    BuildVersion version = BuildVersion.ReadDefault();
-    #endif
-    rules.PublicDefinitions.Add("UE_VER=" + version.MajorVersion + version.MinorVersion);
-
-    switch (rules.Target.Platform) {
-      case UnrealTargetPlatform.Win64:
-      case UnrealTargetPlatform.Win32:
-        rules.PublicDefinitions.Add("HX_WINDOWS");
-        break;
-      case UnrealTargetPlatform.Mac:
-        rules.PublicDefinitions.Add("HX_MACOS");
-        break;
-      case UnrealTargetPlatform.Linux:
-        rules.PublicDefinitions.Add("HX_LINUX");
-        break;
-      case UnrealTargetPlatform.Android:
-        rules.PublicDefinitions.Add("HX_ANDROID");
-        break;
-      case UnrealTargetPlatform.IOS:
-        rules.PublicDefinitions.Add("IPHONE");
-        rules.PublicDefinitions.Add("IPHONEOS");
-        break;
-      case UnrealTargetPlatform.HTML5:
-        rules.PublicDefinitions.Add("EMSCRIPTEN");
-        break;
-      default:
-        break;
-        // XboxOne, PS4
-    }
-
-    bool generatingProjectFiles = isGeneratingProjectFiles();
-    bool skipBuild = isSkipBuild();
-    if (forceHaxeCompilation) {
-      if (!skipBuild && !generatingProjectFiles) {
-        System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
-        sw.Start();
-        callHaxe(rules, info, options, true, null);
-        Log.TraceInformation("Haxe call executed in " + sw.Elapsed);
-        #if UE_4_22_OR_LATER
-        resetCachedDirectory(rules.ModuleDirectory);
-        #endif
-        // make sure the Build.cs file is called every time
-        forceNextRun(rules, info);
-      } else {
-        if (skipBuild) {
-          Log.TraceInformation("-SkipBuild detected: Skipping Haxe build");
-        }
-      }
-
-      if (generatingProjectFiles && !addedGenerateFilesHook) {
-        addedGenerateFilesHook = true;
-        AppDomain.CurrentDomain.ProcessExit += delegate(object sender, EventArgs e) {
-          callHaxe(rules, info, options, false, "GenerateProjectFiles");
-        };
-      }
-    } else if (skipBuild) {
-      Environment.SetEnvironmentVariable("UE_SKIP_BUILD", "1");
-    }
-
-    rules.ExternalDependencies.Add(info.pluginPath + "/Source/HaxeInit/BuildApi.Build.cs");
-    if (Directory.Exists(info.gameDir + "/Intermediate/Haxe")) {
-      foreach (string dir in Directory.EnumerateDirectories(info.gameDir + "/Intermediate/Haxe")) {
-        if (File.Exists(dir + "/Data/modules.txt")) {
-          rules.ExternalDependencies.Add(dir + "/Data/modules.txt");
-        }
-      }
-    }
-    rules.ExternalDependencies.Add(info.outputDir + "/Data/modules.txt");
-    rules.ExternalDependencies.Add(info.outputDir + "/Data/defines.txt");
-
-    return info;
-  }
-
-  protected static void forceNextRun(ModuleRules rules, HaxeCompilationInfo info) {
-    // take off this option once UE-47634 is fixed
-    rules.ExternalDependencies.Add(info.pluginPath + "/Inexistent path to force BuildApi.Build.cs to compile Haxe");
-  }
-
-  public static void callHaxe(ModuleRules rules, HaxeCompilationInfo info, HaxeConfigOptions options, bool throwOnError, string command) {
-    Log.TraceInformation("Calling Haxe");
-    string engineDir = Path.GetFullPath("..");
-
-    string cserver = Environment.GetEnvironmentVariable("HAXE_COMPILATION_SERVER");
-    if (cserver != null) {
-      Environment.SetEnvironmentVariable("HAXE_COMPILATION_SERVER", null);
-      Environment.SetEnvironmentVariable("HAXE_COMPILATION_SERVER_DEFER", cserver);
-    }
-    Environment.SetEnvironmentVariable("COMPILING_WITH_BUILD_CS", "1");
-
-    Process proc = new Process();
-    proc.StartInfo.CreateNoWindow = true;
-    proc.StartInfo.UseShellExecute = false;
-    proc.StartInfo.FileName = "haxe";
-    proc.StartInfo.Arguments = "--cwd \"" + info.pluginPath + "/Haxe/BuildTool\" compile-project.hxml " + HaxeConfigOptions.escapeString("EngineDir", engineDir) +
-        " " + HaxeConfigOptions.escapeString("ProjectDir", info.gameDir) + " " + HaxeConfigOptions.escapeString("TargetName", rules.Target.Name) + " " + HaxeConfigOptions.escapeString("TargetPlatform", rules.Target.Platform + "") +
-        " " + HaxeConfigOptions.escapeString("TargetConfiguration", rules.Target.Configuration + "") + " " + HaxeConfigOptions.escapeString("TargetType", rules.Target.Type + "") + " " + HaxeConfigOptions.escapeString("ProjectFile", info.uprojectPath) +
-        " " + HaxeConfigOptions.escapeString("PluginDir", info.pluginPath) + " " + HaxeConfigOptions.escapeString("RootDir", info.rootDir) + " -D UE_BUILD_CS" + (options == null ? "" : options.getOptionsString());
-    if (command != null) {
-      proc.StartInfo.Arguments += " -D \"Command=" + command + "\"";
-    }
-    Log.TraceInformation("Calling the build tool with arguments " + proc.StartInfo.Arguments);
-
-    proc.StartInfo.RedirectStandardOutput = true;
-    proc.StartInfo.RedirectStandardError = true;
-    proc.OutputDataReceived += (sender, args) => { if (args != null && args.Data != null) Log.TraceInformation(args.Data); };
-    proc.ErrorDataReceived += (sender, args) => { if (args != null && args.Data != null) Log.TraceInformation(args.Data); };
-    proc.Start();
-    proc.BeginOutputReadLine();
-    proc.BeginErrorReadLine();
-    proc.WaitForExit();
-
-    if (proc.ExitCode != 0) {
-      Log.TraceError("Error: Haxe compilation failed");
-      if (throwOnError) {
-        throw new Exception("Haxe compilation failed");
-      }
-    }
-  }
-}
-
-public class HaxeCompilationInfo {
-  public ModuleRules rules;
-
-  public string name;
-  public string gameDir;
-  public string outputDir;
-  public string buildName;
-  public string libPath;
-  public string uprojectPath;
-  public string pluginPath;
-  public string rootDir;
-
-  public HaxeCompilationInfo(ModuleRules rules) {
-    this.rules = rules;
-    this.init();
-  }
-
-  public static bool IsCodeProject(FileReference ProjectFile)
-  {
-    DirectoryReference ProjectDirectory = ProjectFile.Directory;
-
-    // Check if it's a code project
-    DirectoryReference SourceFolder = DirectoryReference.Combine(ProjectDirectory, "Source");
-    DirectoryReference IntermediateSourceFolder = DirectoryReference.Combine(ProjectDirectory, "Intermediate", "Source");
-    return DirectoryReference.Exists(SourceFolder) || DirectoryReference.Exists(IntermediateSourceFolder);
-  }
-
-  static List<FileReference> FilterGameProjects(bool bOnlyCodeProjects, string GameNameFilter)
-  {
-    List<FileReference> Filtered = new List<FileReference>();
-    #if UE_4_22_OR_LATER
-    var ProjectFiles = NativeProjects.EnumerateProjectFiles();
-    #else
-    var ProjectFiles = UProjectInfo.AllProjectFiles;
-    #endif
-
-    foreach (FileReference ProjectFile in ProjectFiles)
-    {
-      if (!bOnlyCodeProjects || IsCodeProject(ProjectFile))
-      {
-        if (string.IsNullOrEmpty(GameNameFilter) || ProjectFile.GetFileNameWithoutAnyExtensions() == GameNameFilter)
-        {
-          Filtered.Add(ProjectFile);
-        }
-      }
-    }
-    return Filtered;
-  }
-
-  static string getRootDir() {
-    System.Type t = BaseModuleRules.getType("UnrealBuildTool.UnrealBuildTool");
-    if (t != null) {
-      FieldInfo f = t.GetField("RootDirectory");
-      if (f != null) {
-        return f.GetValue(null) + "";
-      }
-      PropertyInfo p = t.GetProperty("RootDirectory");
-      if (p != null) {
-        return p.GetValue(null) + "";
-      }
-    }
-    return null;
-  }
-
-  private void init() {
-    this.name = rules.Target.Name;
-    if (this.name.EndsWith("Editor")) {
-      this.name = this.name.Substring(0, this.name.Length - "Editor".Length);
-    } else if (this.name.EndsWith("Server")) {
-      this.name = this.name.Substring(0, this.name.Length - "Server".Length);
-    }
-
-    List<FileReference> projectFiles = FilterGameProjects(true, this.name);
-    if (projectFiles.Count == 0) {
-      Log.TraceWarning("Could not find any code project with name " + this.name);
-      projectFiles = FilterGameProjects(true, null);
-    }
-    if (projectFiles.Count == 0) {
-      Log.TraceWarning("Could not find any code project");
-      this.gameDir = Path.GetFullPath(rules.ModuleDirectory + "/../../");
-    } else {
-      this.gameDir = projectFiles[0].Directory.FullName;
-    }
-
-    string libName = null;
-    switch (rules.Target.Platform) {
-      case UnrealTargetPlatform.Win64:
-      case UnrealTargetPlatform.Win32:
-      case UnrealTargetPlatform.XboxOne:
-        libName = "haxeRuntime.lib";
-        break;
-      default:
-        libName = "libhaxeruntime.a";
-        break;
-    }
-
-    string platform = this.rules.Target.Platform + "";
-    switch (rules.Target.Platform) {
-      case UnrealTargetPlatform.Win64:
-      case UnrealTargetPlatform.Win32:
-        platform = "Win";
-        break;
-      default:
-        libName = "libhaxeruntime.a";
-        break;
-    }
-    string config = this.rules.Target.Configuration + "";
-    if (config == "DebugGame") {
-      config = "Development";
-    }
-    this.buildName = this.name + "-" + platform + "-" + config + "-" + this.rules.Target.Type;
-    this.outputDir = this.gameDir + "/Intermediate/Haxe/" + this.buildName;
-
-    foreach (string file in Directory.GetFileSystemEntries(this.gameDir)) {
-      if (file.ToLowerInvariant().EndsWith(".uproject")) {
-        this.uprojectPath = file;
-        break;
-      }
-    }
-
-    this.libPath = this.outputDir + "/" + libName;
-    string haxeInitPath = RulesCompiler.GetFileNameFromType(typeof(HaxeInit));
-    this.pluginPath = Path.GetFullPath(haxeInitPath + "/../../..");
-    this.rootDir = getRootDir();
-  }
-}
-
-public class HaxeConfigOptions {
-  /**
-    If using a custom Haxe path, specify it here
-  **/
-  public string haxeInstallPath;
-
-  /**
-    If using a custom haxelib path, specify it here
-  **/
-  public string haxelibPath;
-
-  /**
-    Whether to disable dynamic cppia uobjects. In case this is true, any cppia change that results in a
-    ufunction/uproperty being changed/added must be recompiled
-  **/
-  public bool noDynamicObjects;
-
-  public HaxeConfigOptions() {
-  }
-
-  public static string escapeString(string name, string s) {
-    if (s == null) {
-      return "";
-    }
-    return " -D \"" + name + "=" + s.Replace("\\","\\\\").Replace("\"","\\\"").Replace("\n","\\n") + "\"";
-  }
-
-  private static string escapeBool(string name, bool b) {
-    if (!b) {
-      return "";
-    }
-    return " -D \"" + name;
-  }
-
-  public string getOptionsString() {
-    return escapeString("haxeInstallPath", haxeInstallPath) +
-           escapeString("haxelibPath", haxelibPath) +
-           escapeBool("noDynamicObjects", noDynamicObjects);
-  }
+using Tools.DotNETCommon;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Diagnostics;
+using System;
+using System.IO;
+using UnrealBuildTool;
+
+public class BaseModuleRules : ModuleRules {
+  private static Dictionary<string, bool> firstRunMap = new Dictionary<string, bool>();
+
+  public BaseModuleRules(ReadOnlyTargetRules target) : base(target) {
+    this.internalInit(target);
+    this.init();
+    this.run();
+  }
+
+  public static System.Type getType(string name) {
+    System.Type ret = System.Type.GetType(name);
+    if (ret == null) {
+			foreach (Assembly t2 in AppDomain.CurrentDomain.GetAssemblies()) {
+        ret = t2.GetType(name);
+        if (ret != null) {
+          break;
+        }
+      }
+    }
+    return ret;
+  }
+
+  virtual protected void init() {
+  }
+
+  virtual protected void internalInit(ReadOnlyTargetRules target) {
+  }
+
+  virtual protected void run() {
+    throw new NotImplementedException();
+  }
+}
+
+/**
+ * This is a helper that makes it easy to write build code that is compatible with
+ * multiple different Unreal Engine versions. Subclassing this is optional
+ **/
+public class BaseTargetRules : TargetRules {
+  public BaseTargetRules(TargetInfo target) : base(target) {
+    this.init(target);
+
+    List<string> moduleNames = new List<string>();
+    this.setupBinaries(moduleNames);
+    foreach (string module in moduleNames) {
+      ExtraModuleNames.Add(module);
+    }
+  }
+
+  virtual protected void init(TargetInfo target) {
+  }
+
+  virtual protected void setupBinaries(List<string> moduleNames) {
+  }
+}
+
+public class HaxeModuleRules : BaseModuleRules {
+  /**
+   * Set this to true if you'd like to manually manage the dependencies.
+   * This is faster since Unreal doesn't have to rebuild every time
+   **/
+  public bool manualDependencies;
+  public bool disabled;
+
+  /**
+    This used to be optional, as PreBuildSteps were being used to compile Haxe without the need
+    of Build.cs. However, there are multiple issues with PreBuildSteps currently (see UE-47634)
+    so this is needed. You can still disable this, but make sure to compile Haxe yourself before
+    if you choose to do so.
+   **/
+  public bool forceHaxeCompilation;
+
+  public HaxeConfigOptions options = new HaxeConfigOptions();
+
+  public HaxeModuleRules(ReadOnlyTargetRules target) : base(target) {
+    PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
+  }
+
+  override protected void internalInit(ReadOnlyTargetRules target) {
+    this.forceHaxeCompilation = true;
+  }
+
+  static bool isSkipBuild() {
+    foreach (string arg in Environment.GetCommandLineArgs()) {
+      if (String.Compare(arg, "-SkipBuild", StringComparison.OrdinalIgnoreCase) == 0) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  static bool isGeneratingProjectFiles() {
+    System.Type t = getType("UnrealBuildTool.ProjectFileGenerator");
+    if (t != null) {
+      FieldInfo f = t.GetField("bGenerateProjectFiles");
+      if (f != null) {
+        return (bool) f.GetValue(null);
+      }
+      PropertyInfo p = t.GetProperty("bGenerateProjectFiles");
+      if (p != null) {
+        return (bool) p.GetValue(null);
+      }
+    }
+    return false;
+  }
+
+  static void resetCachedDirectory(string path) {
+    System.Type t = getType("UnrealBuildTool.DirectoryItem");
+    if (t == null) {
+      Log.TraceWarning("Cannot find DirectoryItem");
+      return;
+    }
+    MethodInfo m = t.GetMethod("GetItemByPath");
+    if (m == null) {
+      Log.TraceWarning("Cannot find GetItemByPath");
+      return;
+    }
+    object dirItem = m.Invoke(null, new object[]{path});
+    if (dirItem == null) {
+      Log.TraceWarning("Cannot gather dirItem for path " + path);
+      return;
+    }
+    MethodInfo reset = t.GetMethod("ResetCachedInfo");
+    if (reset == null) {
+      Log.TraceWarning("Cannot find ResetCachedInfo");
+      return;
+    }
+    reset.Invoke(dirItem, new object[]{});
+  }
+
+  override protected void run() {
+    if (disabled) {
+      Log.TraceInformation("Compiling without Haxe support");
+    }
+
+    if (!manualDependencies) {
+      if (Target.Type != TargetType.Program) {
+        // these are all dependencies on an empty unreal.hx project -
+        // most of them are because of types that reference other modules
+        // without DCE enabled, we can't get past this
+        this.PublicDependencyModuleNames.AddRange(new string[] {
+          "Core",
+          "CoreUObject",
+          "Engine",
+          "InputCore",
+          "SlateCore"
+         });
+        if (Target.Type == TargetType.Editor) {
+          this.PrivateDependencyModuleNames.Add("UnrealEd");
+        }
+      } else {
+        this.PrivateDependencyModuleNames.AddRange(new string[] {
+          "Core",
+          "Projects", // for IPluginManager
+        });
+        // for RequiredProgramMainCPPInclude.h
+        string engineDir = Path.GetFullPath("..");
+        PublicIncludePaths.AddRange(
+          new string[] {
+            engineDir + "/Source/Runtime/Launch/Public",
+            engineDir + "/Source/Runtime/Launch/Private",
+          }
+        );
+      }
+    }
+
+    HaxeCompilationInfo info = setupHaxeTarget(this, this.forceHaxeCompilation, this.options);
+    if (!manualDependencies) {
+      string modulesPath = info.outputDir + "/Data/modules.txt";
+      string curName = this.GetType().Name;
+      if (!File.Exists(modulesPath)) {
+        Log.TraceInformation("Could not find module definition at " + modulesPath);
+      } else {
+        foreach (string dep in File.ReadAllText(modulesPath).Trim().Split('\n')) {
+          if (dep != curName && dep != "") {
+            this.PrivateDependencyModuleNames.Add(dep);
+          }
+        }
+      }
+    }
+    string definesPath = info.outputDir + "/Data/defines.txt";
+    if (!File.Exists(definesPath)) {
+      Log.TraceInformation("Could not find defines file at " + definesPath);
+    } else {
+      foreach (string def in File.ReadAllText(definesPath).Trim().Split('\n')) {
+        if (def != "") {
+          this.PublicDefinitions.Add(def);
+        }
+      }
+    }
+
+    foreach (string path in PublicIncludePaths) {
+      if (Path.IsPathRooted(path) && !Directory.Exists(path)) {
+        Directory.CreateDirectory(path);
+      }
+    }
+    foreach (string path in PrivateIncludePaths) {
+      if (Path.IsPathRooted(path) && !Directory.Exists(path)) {
+        Directory.CreateDirectory(path);
+      }
+    }
+  }
+
+  private static bool addedGenerateFilesHook = false;
+
+  public static HaxeCompilationInfo setupHaxeTarget(ModuleRules rules, bool forceHaxeCompilation, HaxeConfigOptions options) {
+    rules.PublicIncludePaths.Add(Path.Combine(rules.ModuleDirectory, "Generated"));
+    rules.PublicIncludePaths.Add(Path.Combine(rules.ModuleDirectory, "Generated/Public"));
+    rules.PublicIncludePaths.Add(Path.Combine(rules.ModuleDirectory, "Generated/TemplateExport"));
+    rules.PublicIncludePaths.Add(Path.Combine(rules.ModuleDirectory, "Generated/Shared"));
+
+    HaxeCompilationInfo info = new HaxeCompilationInfo(rules);
+    rules.PublicAdditionalLibraries.Add(info.libPath);
+    rules.PublicIncludePaths.Add(Path.Combine(info.outputDir, "Generated/Public"));
+    rules.PublicIncludePaths.Add(Path.Combine(info.outputDir, "Generated/Shared"));
+    rules.PrivateIncludePaths.Add(Path.Combine(info.outputDir, "Generated/Private"));
+    rules.PublicIncludePaths.Add(Path.Combine(info.outputDir, "Template/Shared"));
+    rules.PublicIncludePaths.Add(Path.Combine(info.outputDir, "Template/Public"));
+    rules.PrivateIncludePaths.Add(Path.Combine(info.outputDir, "Template/Private"));
+
+    Log.TraceInformation("BuildApi.Build.cs: Using Haxe");
+    rules.PublicDefinitions.Add("WITH_HAXE=1");
+    rules.PublicDefinitions.Add("HXCPP_EXTERN_CLASS_ATTRIBUTES=");
+    rules.PublicDefinitions.Add("MAY_EXPORT_SYMBOL=");
+
+    if (options != null && options.haxeInstallPath != null) {
+      string haxePath = System.IO.Path.Combine(info.gameDir, options.haxeInstallPath);
+      Environment.SetEnvironmentVariable("HAXEPATH", haxePath);
+      Environment.SetEnvironmentVariable("PATH", haxePath + System.IO.Path.PathSeparator + Environment.GetEnvironmentVariable("PATH"));
+    }
+    if (options != null && options.haxelibPath != null) {
+      string libPath = System.IO.Path.Combine(info.gameDir, options.haxelibPath);
+      Environment.SetEnvironmentVariable("HAXELIB_PATH", libPath);
+    }
+    if (options != null && options.noDynamicObjects) {
+      rules.PublicDefinitions.Add("NO_DYNAMIC_UCLASS=1");
+    } else {
+      rules.PublicDefinitions.Add("NO_DYNAMIC_UCLASS=0");
+    }
+
+
+    #if UE_4_22_OR_LATER
+    ReadOnlyBuildVersion version = rules.Target.Version;
+    #else
+    BuildVersion version = BuildVersion.ReadDefault();
+    #endif
+    rules.PublicDefinitions.Add("UE_VER=" + version.MajorVersion + version.MinorVersion);
+
+    switch (rules.Target.Platform) {
+      case UnrealTargetPlatform.Win64:
+      case UnrealTargetPlatform.Win32:
+        rules.PublicDefinitions.Add("HX_WINDOWS");
+        break;
+      case UnrealTargetPlatform.Mac:
+        rules.PublicDefinitions.Add("HX_MACOS");
+        break;
+      case UnrealTargetPlatform.Linux:
+        rules.PublicDefinitions.Add("HX_LINUX");
+        break;
+      case UnrealTargetPlatform.Android:
+        rules.PublicDefinitions.Add("HX_ANDROID");
+        break;
+      case UnrealTargetPlatform.IOS:
+        rules.PublicDefinitions.Add("IPHONE");
+        rules.PublicDefinitions.Add("IPHONEOS");
+        break;
+      case UnrealTargetPlatform.HTML5:
+        rules.PublicDefinitions.Add("EMSCRIPTEN");
+        break;
+      default:
+        break;
+        // XboxOne, PS4
+    }
+
+    bool generatingProjectFiles = isGeneratingProjectFiles();
+    bool skipBuild = isSkipBuild();
+    if (forceHaxeCompilation) {
+      if (!skipBuild && !generatingProjectFiles) {
+        System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
+        sw.Start();
+        callHaxe(rules, info, options, true, null);
+        Log.TraceInformation("Haxe call executed in " + sw.Elapsed);
+        #if UE_4_22_OR_LATER
+        resetCachedDirectory(rules.ModuleDirectory);
+        #endif
+        // make sure the Build.cs file is called every time
+        forceNextRun(rules, info);
+      } else {
+        if (skipBuild) {
+          Log.TraceInformation("-SkipBuild detected: Skipping Haxe build");
+        }
+      }
+
+      if (generatingProjectFiles && !addedGenerateFilesHook) {
+        addedGenerateFilesHook = true;
+        AppDomain.CurrentDomain.ProcessExit += delegate(object sender, EventArgs e) {
+          callHaxe(rules, info, options, false, "GenerateProjectFiles");
+        };
+      }
+    } else if (skipBuild) {
+      Environment.SetEnvironmentVariable("UE_SKIP_BUILD", "1");
+    }
+
+    rules.ExternalDependencies.Add(info.pluginPath + "/Source/HaxeInit/BuildApi.Build.cs");
+    if (Directory.Exists(info.gameDir + "/Intermediate/Haxe")) {
+      foreach (string dir in Directory.EnumerateDirectories(info.gameDir + "/Intermediate/Haxe")) {
+        if (File.Exists(dir + "/Data/modules.txt")) {
+          rules.ExternalDependencies.Add(dir + "/Data/modules.txt");
+        }
+      }
+    }
+    rules.ExternalDependencies.Add(info.outputDir + "/Data/modules.txt");
+    rules.ExternalDependencies.Add(info.outputDir + "/Data/defines.txt");
+
+    return info;
+  }
+
+  protected static void forceNextRun(ModuleRules rules, HaxeCompilationInfo info) {
+    // take off this option once UE-47634 is fixed
+    rules.ExternalDependencies.Add(info.pluginPath + "/Inexistent path to force BuildApi.Build.cs to compile Haxe");
+  }
+
+  public static void callHaxe(ModuleRules rules, HaxeCompilationInfo info, HaxeConfigOptions options, bool throwOnError, string command) {
+    Log.TraceInformation("Calling Haxe");
+    string engineDir = Path.GetFullPath("..");
+
+    string cserver = Environment.GetEnvironmentVariable("HAXE_COMPILATION_SERVER");
+    if (cserver != null) {
+      Environment.SetEnvironmentVariable("HAXE_COMPILATION_SERVER", null);
+      Environment.SetEnvironmentVariable("HAXE_COMPILATION_SERVER_DEFER", cserver);
+    }
+    Environment.SetEnvironmentVariable("COMPILING_WITH_BUILD_CS", "1");
+
+    Process proc = new Process();
+    proc.StartInfo.CreateNoWindow = true;
+    proc.StartInfo.UseShellExecute = false;
+    proc.StartInfo.FileName = "haxe";
+    proc.StartInfo.Arguments = "--cwd \"" + info.pluginPath + "/Haxe/BuildTool\" compile-project.hxml " + HaxeConfigOptions.escapeString("EngineDir", engineDir) +
+        " " + HaxeConfigOptions.escapeString("ProjectDir", info.gameDir) + " " + HaxeConfigOptions.escapeString("TargetName", rules.Target.Name) + " " + HaxeConfigOptions.escapeString("TargetPlatform", rules.Target.Platform + "") +
+        " " + HaxeConfigOptions.escapeString("TargetConfiguration", rules.Target.Configuration + "") + " " + HaxeConfigOptions.escapeString("TargetType", rules.Target.Type + "") + " " + HaxeConfigOptions.escapeString("ProjectFile", info.uprojectPath) +
+        " " + HaxeConfigOptions.escapeString("PluginDir", info.pluginPath) + " " + HaxeConfigOptions.escapeString("RootDir", info.rootDir) + " -D UE_BUILD_CS" + (options == null ? "" : options.getOptionsString());
+    if (command != null) {
+      proc.StartInfo.Arguments += " -D \"Command=" + command + "\"";
+    }
+    Log.TraceInformation("Calling the build tool with arguments " + proc.StartInfo.Arguments);
+
+    proc.StartInfo.RedirectStandardOutput = true;
+    proc.StartInfo.RedirectStandardError = true;
+    proc.OutputDataReceived += (sender, args) => { if (args != null && args.Data != null) Log.TraceInformation(args.Data); };
+    proc.ErrorDataReceived += (sender, args) => { if (args != null && args.Data != null) Log.TraceInformation(args.Data); };
+    proc.Start();
+    proc.BeginOutputReadLine();
+    proc.BeginErrorReadLine();
+    proc.WaitForExit();
+
+    if (proc.ExitCode != 0) {
+      Log.TraceError("Error: Haxe compilation failed");
+      if (throwOnError) {
+        throw new Exception("Haxe compilation failed");
+      }
+    }
+  }
+}
+
+public class HaxeCompilationInfo {
+  public ModuleRules rules;
+
+  public string name;
+  public string gameDir;
+  public string outputDir;
+  public string buildName;
+  public string libPath;
+  public string uprojectPath;
+  public string pluginPath;
+  public string rootDir;
+
+  public HaxeCompilationInfo(ModuleRules rules) {
+    this.rules = rules;
+    this.init();
+  }
+
+  public static bool IsCodeProject(FileReference ProjectFile)
+  {
+    DirectoryReference ProjectDirectory = ProjectFile.Directory;
+
+    // Check if it's a code project
+    DirectoryReference SourceFolder = DirectoryReference.Combine(ProjectDirectory, "Source");
+    DirectoryReference IntermediateSourceFolder = DirectoryReference.Combine(ProjectDirectory, "Intermediate", "Source");
+    return DirectoryReference.Exists(SourceFolder) || DirectoryReference.Exists(IntermediateSourceFolder);
+  }
+
+  static List<FileReference> FilterGameProjects(bool bOnlyCodeProjects, string GameNameFilter)
+  {
+    List<FileReference> Filtered = new List<FileReference>();
+    #if UE_4_22_OR_LATER
+    var ProjectFiles = NativeProjects.EnumerateProjectFiles();
+    #else
+    var ProjectFiles = UProjectInfo.AllProjectFiles;
+    #endif
+
+    foreach (FileReference ProjectFile in ProjectFiles)
+    {
+      if (!bOnlyCodeProjects || IsCodeProject(ProjectFile))
+      {
+        if (string.IsNullOrEmpty(GameNameFilter) || ProjectFile.GetFileNameWithoutAnyExtensions() == GameNameFilter)
+        {
+          Filtered.Add(ProjectFile);
+        }
+      }
+    }
+    return Filtered;
+  }
+
+  static string getRootDir() {
+    System.Type t = BaseModuleRules.getType("UnrealBuildTool.UnrealBuildTool");
+    if (t != null) {
+      FieldInfo f = t.GetField("RootDirectory");
+      if (f != null) {
+        return f.GetValue(null) + "";
+      }
+      PropertyInfo p = t.GetProperty("RootDirectory");
+      if (p != null) {
+        return p.GetValue(null) + "";
+      }
+    }
+    return null;
+  }
+
+  private void init() {
+    this.name = rules.Target.Name;
+    if (this.name.EndsWith("Editor")) {
+      this.name = this.name.Substring(0, this.name.Length - "Editor".Length);
+    } else if (this.name.EndsWith("Server")) {
+      this.name = this.name.Substring(0, this.name.Length - "Server".Length);
+    }
+
+    List<FileReference> projectFiles = FilterGameProjects(true, this.name);
+    if (projectFiles.Count == 0) {
+      Log.TraceWarning("Could not find any code project with name " + this.name);
+      projectFiles = FilterGameProjects(true, null);
+    }
+    if (projectFiles.Count == 0) {
+      Log.TraceWarning("Could not find any code project");
+      this.gameDir = Path.GetFullPath(rules.ModuleDirectory + "/../../");
+    } else {
+      this.gameDir = projectFiles[0].Directory.FullName;
+    }
+
+    string libName = null;
+    switch (rules.Target.Platform) {
+      case UnrealTargetPlatform.Win64:
+      case UnrealTargetPlatform.Win32:
+      case UnrealTargetPlatform.XboxOne:
+        libName = "haxeRuntime.lib";
+        break;
+      default:
+        libName = "libhaxeruntime.a";
+        break;
+    }
+
+    string platform = this.rules.Target.Platform + "";
+    switch (rules.Target.Platform) {
+      case UnrealTargetPlatform.Win64:
+      case UnrealTargetPlatform.Win32:
+        platform = "Win";
+        break;
+      default:
+        libName = "libhaxeruntime.a";
+        break;
+    }
+    string config = this.rules.Target.Configuration + "";
+    if (config == "DebugGame") {
+      config = "Development";
+    }
+    this.buildName = this.name + "-" + platform + "-" + config + "-" + this.rules.Target.Type;
+    this.outputDir = this.gameDir + "/Intermediate/Haxe/" + this.buildName;
+
+    foreach (string file in Directory.GetFileSystemEntries(this.gameDir)) {
+      if (file.ToLowerInvariant().EndsWith(".uproject")) {
+        this.uprojectPath = file;
+        break;
+      }
+    }
+
+    this.libPath = this.outputDir + "/" + libName;
+    string haxeInitPath = RulesCompiler.GetFileNameFromType(typeof(HaxeInit));
+    this.pluginPath = Path.GetFullPath(haxeInitPath + "/../../..");
+    this.rootDir = getRootDir();
+  }
+}
+
+public class HaxeConfigOptions {
+  /**
+    If using a custom Haxe path, specify it here
+  **/
+  public string haxeInstallPath;
+
+  /**
+    If using a custom haxelib path, specify it here
+  **/
+  public string haxelibPath;
+
+  /**
+    Whether to disable dynamic cppia uobjects. In case this is true, any cppia change that results in a
+    ufunction/uproperty being changed/added must be recompiled
+  **/
+  public bool noDynamicObjects;
+
+  public HaxeConfigOptions() {
+  }
+
+  public static string escapeString(string name, string s) {
+    if (s == null) {
+      return "";
+    }
+    // Windows doesn't need to escape \
+    if (!(System.Environment.OSVersion.Platform + "").StartsWith("Win"))
+    {
+      s = s.Replace("\\", "\\\\");
+    }
+    return " -D \"" + name + "=" + s.Replace("\"","\\\"").Replace("\n","\\n") + "\"";
+  }
+
+  private static string escapeBool(string name, bool b) {
+    if (!b) {
+      return "";
+    }
+    return " -D \"" + name;
+  }
+
+  public string getOptionsString() {
+    return escapeString("haxeInstallPath", haxeInstallPath) +
+           escapeString("haxelibPath", haxelibPath) +
+           escapeBool("noDynamicObjects", noDynamicObjects);
+  }
 }


CI Build Number Updated

CI Build Number Updated

git-svn-id: 7f05ad86c4f4f5ca50611136d23b835364929451@298 b33fba48-7441-0410-8d5c-f397f7ceaa6c


fix memory leak

fix memory leak

--- Lottie.Forms/Platforms/Ios/AnimationViewRenderer.cs
+++ Lottie.Forms/Platforms/Ios/AnimationViewRenderer.cs
@@ -39,6 +39,8 @@
                 e.OldElement.OnPause -= OnPause;
                 e.OldElement.OnPlayProgressSegment -= OnPlayProgressSegment;
                 e.OldElement.OnPlayFrameSegment -= OnPlayFrameSegment;
+
+                CleanupResources();
             }

             if (e.NewElement == null) return;
@@ -48,7 +50,7 @@
             e.NewElement.OnPlayProgressSegment += OnPlayProgressSegment;
             e.NewElement.OnPlayFrameSegment += OnPlayFrameSegment;

-            if (!string.IsNullOrEmpty(e.NewElement.Animation))
+            if (!string.IsNullOrWhiteSpace(e.NewElement.Animation))
             {
                 InitAnimationViewForElement(e.NewElement);
             }
@@ -85,10 +87,9 @@
             if (Element == null)
                 return;

-            if (e.PropertyName == AnimationView.AnimationProperty.PropertyName && !string.IsNullOrEmpty(Element.Animation))
+            if (e.PropertyName == AnimationView.AnimationProperty.PropertyName && !string.IsNullOrWhiteSpace(Element.Animation))
             {
-                _animationView?.RemoveFromSuperview();
-                _animationView?.RemoveGestureRecognizer(_gestureRecognizer);
+                CleanupResources();
                 InitAnimationViewForElement(Element);
             }

@@ -131,19 +132,28 @@
                 _animationView.PlayWithCompletion(PlaybackFinishedIfActually);
             }

-            if (_animationView != null)
-            {
-                SetNativeControl(_animationView);
-                SetNeedsLayout();
-            }
+            SetNativeControl(_animationView);
+            SetNeedsLayout();
         }

-        void PlaybackFinishedIfActually(bool animationFinished)
+        private void PlaybackFinishedIfActually(bool animationFinished)
         {
             if (animationFinished)
             {
                 Element?.PlaybackFinished();
             }
         }
+
+        private void CleanupResources()
+        {
+            _animationView?.RemoveGestureRecognizer(_gestureRecognizer);
+            _animationView?.RemoveFromSuperview();
+
+            _gestureRecognizer.Dispose();
+            _gestureRecognizer = null;
+
+            _animationView?.Dispose();
+            _animationView = null;
+        }
     }
 }


Prefer DXVA2 when using the EVR w/ custom presenter

--- MediaBrowser.Theater.DirectShow/DirectShowPlayer.cs
+++ MediaBrowser.Theater.DirectShow/DirectShowPlayer.cs
@@ -774,13 +774,6 @@
             catch (Exception ex)
             {
                 _logger.ErrorException("Error adding LAV Audio filter", ex);
-                            _madvr = new MadVR();
-                                    if (smoothMotion != _dsConfig.VideoConfig.UseMadVrSmoothMotion)
-                                        msett.SetBool("smoothMotionEnabled", _dsConfig.VideoConfig.UseMadVrSmoothMotion);
-                                    if (string.Compare(msett.GetString("smoothMotionMode"), _dsConfig.VideoConfig.MadVrSmoothMotionMode, true) != 0)
-                                        bool success = msett.SetString("smoothMotionMode", _dsConfig.VideoConfig.MadVrSmoothMotionMode);
-                    if (enableXySubFilter && madVrSucceded)
-                            _xySubFilter = new XySubFilter();
             }

             DirectShowLib.IEnumPins pEnum;


MeasureNumberingクラスにregionを追加

MeasureNumberingクラスにregionを追加

--- MusicXMLUtils/Structure/Measure/MeasureNumbering.cs
+++ MusicXMLUtils/Structure/Measure/MeasureNumbering.cs
@@ -38,9 +38,12 @@
     [XmlType(TypeName = "measure-numbering")]
     public class MeasureNumbering
     {
+        #region -- Public Properties --
         [XmlText]
         public MeasureNumberingValue Value { get; set; }
+        #endregion

+        #region -- Constructors --
         public MeasureNumbering()
         {
         }
@@ -49,5 +52,6 @@
         {
             this.Value = value;
         }
+        #endregion
     }
 }


Add initialization of additional providers

--- NBi.Core/Query/Connection/OleDbConnectionFactory.cs
+++ NBi.Core/Query/Connection/OleDbConnectionFactory.cs
@@ -1,4 +1,5 @@
-using System;
+using NBi.Core.Configuration;
+using System;
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
 using System.Data.Common;
@@ -16,7 +17,7 @@
         public OleDbConnectionFactory()
             : base()
         {
-            providers = new ReadOnlyDictionary<string, string>(new Dictionary<string, string>());
+            providers = ConfigurationManager.GetConfiguration().Providers;
         }

         public OleDbConnectionFactory(IDictionary<string, string> providers)


Synthesize backspace key up event (since Android doesn't send it sometimes)

--- osu.Framework.Android/AndroidGameView.cs
+++ osu.Framework.Android/AndroidGameView.cs
@@ -140,6 +140,13 @@

                 default:
                     KeyDown?.Invoke(keyCode, e);
+
+                    // Releasing backspace on a physical keyboard when text input is active will not send a key up event.
+                    // Manually send one to prevent the key from getting stuck.
+                    // This does mean that key repeat is handled by the OS, instead of by the usual `InputManager` handling.
+                    if (keyCode == Keycode.Del && e.IsFromSource(InputSourceType.Keyboard) && textInputActive)
+                        KeyUp?.Invoke(Keycode.Del, new KeyEvent(e.DownTime, e.EventTime, KeyEventActions.Up, Keycode.Del, 0, e.MetaState, e.DeviceId, e.ScanCode, e.Flags, e.Source));
+
                     return true;
             }
         }


Adjust slider pooling based on beatmap

Adjust slider pooling based on beatmap

Handles edge cases like mentioned in https://github.com/ppy/osu/issues/19585.

--- osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs
+++ osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs
@@ -11,9 +11,11 @@
 using osu.Framework.Graphics;
 using osu.Framework.Graphics.Containers;
 using osu.Framework.Graphics.Pooling;
+using osu.Game.Beatmaps;
 using osu.Game.Rulesets.Judgements;
 using osu.Game.Rulesets.Objects;
 using osu.Game.Rulesets.Objects.Drawables;
+using osu.Game.Rulesets.Osu.Beatmaps;
 using osu.Game.Rulesets.Osu.Configuration;
 using osu.Game.Rulesets.Osu.Objects;
 using osu.Game.Rulesets.Osu.Objects.Drawables;
@@ -112,17 +114,28 @@
         }

         [BackgroundDependencyLoader(true)]
-        private void load(OsuRulesetConfigManager config)
+        private void load(OsuRulesetConfigManager config, IBeatmap beatmap)
         {
             config?.BindWith(OsuRulesetSetting.PlayfieldBorderStyle, playfieldBorder.PlayfieldBorderStyle);

             RegisterPool<HitCircle, DrawableHitCircle>(10, 100);
-
-            RegisterPool<Slider, DrawableSlider>(10, 100);
-            RegisterPool<SliderHeadCircle, DrawableSliderHead>(10, 100);
-            RegisterPool<SliderTailCircle, DrawableSliderTail>(10, 100);
-            RegisterPool<SliderTick, DrawableSliderTick>(10, 100);
-            RegisterPool<SliderRepeat, DrawableSliderRepeat>(5, 50);
+            var osuBeatmap = (OsuBeatmap)beatmap;
+
+
+            var sliders = osuBeatmap.HitObjects.OfType<Slider>();
+
+            if (sliders.Any())
+            {
+                // handle edge cases where a beatmap has a slider with many repeats.
+                int maxRepeatsOnOneSlider = osuBeatmap.HitObjects.OfType<Slider>().Max(s => s.RepeatCount);
+                int maxTicksOnOneSlider = osuBeatmap.HitObjects.OfType<Slider>().Max(s => s.NestedHitObjects.OfType<SliderTick>().Count());
+
+                RegisterPool<Slider, DrawableSlider>(20, 100);
+                RegisterPool<SliderHeadCircle, DrawableSliderHead>(20, 100);
+                RegisterPool<SliderTailCircle, DrawableSliderTail>(20, 100);
+                RegisterPool<SliderTick, DrawableSliderTick>(Math.Max(maxTicksOnOneSlider, 20), Math.Max(maxTicksOnOneSlider, 200));
+                RegisterPool<SliderRepeat, DrawableSliderRepeat>(Math.Max(maxRepeatsOnOneSlider, 20), Math.Max(maxRepeatsOnOneSlider, 200));
+            }

             RegisterPool<Spinner, DrawableSpinner>(2, 20);
             RegisterPool<SpinnerTick, DrawableSpinnerTick>(10, 100);


Work around weird null inspection

Work around weird null inspection

--- osu.Game/Database/RealmContextFactory.cs
+++ osu.Game/Database/RealmContextFactory.cs
@@ -147,7 +147,7 @@
                         var oldItem = oldItems.ElementAt(i);
                         var newItem = newItems.ElementAt(i);

-                        long? nullableOnlineID = oldItem.OnlineID;
+                        long? nullableOnlineID = oldItem?.OnlineID;
                         newItem.OnlineID = (int)(nullableOnlineID ?? -1);
                     }
                 }


Fix visual styling and code styling

Fix visual styling and code styling

--- osu.Game/Overlays/Chat/ChatTabControl.cs
+++ osu.Game/Overlays/Chat/ChatTabControl.cs
@@ -64,10 +64,10 @@

         protected override TabItem<Channel> CreateTabItem(Channel value)
         {
-             ChannelTabItem tab = new ChannelTabItem(value);
-             tab.OnRequestClose = () => onTabClose(tab);
-
-             return tab;
+            ChannelTabItem tab = new ChannelTabItem(value);
+            tab.OnRequestClose = () => onTabClose(tab);
+
+            return tab;
         }

         protected override void SelectTab(TabItem<Channel> tab)
@@ -108,7 +108,7 @@

             private readonly SpriteText text;
             private readonly SpriteText textBold;
-            private readonly Button closeButton;
+            private readonly ClickableContainer closeButton;
             private readonly Box box;
             private readonly Box highlightBox;
             private readonly SpriteIcon icon;
@@ -129,7 +129,6 @@
             {
                 this.ResizeTo(new Vector2(Width, 1.1f), transition_length, Easing.OutQuint);

-                closeButton.MoveToX(-5f, 0.5f, Easing.OutElastic);
                 box.FadeColour(backgroundActive, transition_length, Easing.OutQuint);
                 highlightBox.FadeIn(transition_length, Easing.OutQuint);

@@ -141,7 +140,6 @@
             {
                 this.ResizeTo(new Vector2(Width, 1), transition_length, Easing.OutQuint);

-                closeButton.MoveToX(5f, 0.5f, Easing.InElastic);
                 box.FadeColour(backgroundInactive, transition_length, Easing.OutQuint);
                 highlightBox.FadeOut(transition_length, Easing.OutQuint);

@@ -152,7 +150,7 @@
             protected override bool OnHover(InputState state)
             {
                 if (IsRemovable)
-                    closeButton.FadeIn(1f, Easing.InBounce);
+                    closeButton.FadeIn(200, Easing.OutQuint);

                 if (!Active)
                     box.FadeColour(backgroundHover, transition_length, Easing.OutQuint);
@@ -161,9 +159,7 @@

             protected override void OnHoverLost(InputState state)
             {
-                if (closeButton.IsPresent)
-                    closeButton.FadeOut(1f, Easing.OutBounce);
-
+                closeButton.FadeOut(200, Easing.OutQuint);
                 updateState();
             }

@@ -253,23 +249,65 @@
                                 Font = @"Exo2.0-Bold",
                                 TextSize = 18,
                             },
-                            closeButton  = new Button
+                            closeButton = new CloseButton
                             {
                                 Alpha = 0,
-                                Width = 20,
-                                Height = 20,
-                                Margin = new MarginPadding { Right = 10 },
+                                Margin = new MarginPadding { Right = 20 },
                                 Origin = Anchor.CentreRight,
                                 Anchor = Anchor.CentreRight,
-                                Text = @"x",
-                                BackgroundColour = Color4.Transparent,
-                                Action = delegate { if (IsRemovable) OnRequestClose?.Invoke(); },
+                                Action = delegate
+                                {
+                                    if (IsRemovable) OnRequestClose?.Invoke();
+                                },
                             },
                         },
                     },
                 };
             }

+            public class CloseButton : ClickableContainer
+            {
+                private SpriteIcon icon;
+
+                public CloseButton()
+                {
+                    Size = new Vector2(20);
+
+                    Child = icon = new SpriteIcon
+                    {
+                        Anchor = Anchor.Centre,
+                        Origin = Anchor.Centre,
+                        Scale = new Vector2(0.75f),
+                        Icon = FontAwesome.fa_close,
+                        RelativeSizeAxes = Axes.Both,
+                    };
+                }
+
+                protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
+                {
+                    icon.ScaleTo(0.5f, 1000, Easing.OutQuint);
+                    return base.OnMouseDown(state, args);
+                }
+
+                protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
+                {
+                    icon.ScaleTo(0.75f, 1000, Easing.OutElastic);
+                    return base.OnMouseUp(state, args);
+                }
+
+                protected override bool OnHover(InputState state)
+                {
+                    icon.FadeColour(Color4.Red, 200, Easing.OutQuint);
+                    return base.OnHover(state);
+                }
+
+                protected override void OnHoverLost(InputState state)
+                {
+                    icon.FadeColour(Color4.White, 200, Easing.OutQuint);
+                    base.OnHoverLost(state);
+                }
+            }
+
             public class ChannelSelectorTabItem : ChannelTabItem
             {
                 public override bool IsRemovable => false;


If setting SOG.UUID, update the SOG.m_parts index as well as the root part UUID

Being able to change a SOG.UUID is useful for region modules that want to supply their own UUID, before the object is rezzed

--- OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
+++ OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
@@ -335,7 +335,16 @@
         public override UUID UUID
         {
             get { return m_rootPart.UUID; }
-            set { m_rootPart.UUID = value; }
+            set
+            {
+                m_rootPart.UUID = value;
+
+                lock (m_parts)
+                {
+                    m_parts.Remove(m_rootPart.UUID);
+                    m_parts.Add(m_rootPart.UUID, m_rootPart);
+                }
+            }
         }

         public UUID OwnerID


Comment all the spammy [SOG]: Not loaded in HasGroupChanged! now that the bug has been fixed with backup. This also blocks backing up of all prims on startup.

--- OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
+++ OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
@@ -126,12 +126,14 @@
                     if (!m_hasGroupChanged) //First change then
                         timeFirstChanged = DateTime.Now;

-                    if (m_scene != null && m_isLoaded)
+                    if (m_scene != null && m_isLoaded && !m_scene.LoadingPrims) //Do NOT add to backup while still loading prims
                         m_scene.AddPrimBackupTaint(this);
                     else if (m_scene == null)
                         m_log.Warn("[SOG]: Scene is null in HasGroupChanged!");
-                    else if (!m_isLoaded)
-                        m_log.Info("[SOG]: Not loaded in HasGroupChanged!");
+                    //else if (!m_isLoaded)
+                    //    m_log.Info("[SOG]: Not loaded in HasGroupChanged!");
+                    //else if (!m_scene.LoadingPrims)
+                    //    m_log.Info("[SOG]: Not scene loaded in HasGroupChanged!");
                 }
                 m_hasGroupChanged = value;
             }


Added google analytics

Added google analytics

--- cristventcode-static/Views/Shared/_Layout.cshtml
+++ cristventcode-static/Views/Shared/_Layout.cshtml
@@ -44,5 +44,17 @@
     @Scripts.Render("~/bundles/jquery")
     @Scripts.Render("~/bundles/bootstrap")
     @RenderSection("scripts", required: false)
+
+    <script>
+        (function (i, s, o, g, r, a, m) {
+            i['GoogleAnalyticsObject'] = r; i[r] = i[r] || function () {
+                (i[r].q = i[r].q || []).push(arguments)
+            }, i[r].l = 1 * new Date(); a = s.createElement(o),
+                m = s.getElementsByTagName(o)[0]; a.async = 1; a.src = g; m.parentNode.insertBefore(a, m)
+        })(window, document, 'script', 'https://www.google-analytics.com/analytics.js', 'ga');
+
+        ga('create', 'UA-99790372-1', 'auto');
+        ga('send', 'pageview');
+    </script>
 </body>
 </html>


修改 使用位移 >> 1 代替除法 /2

修改 使用位移 >> 1 代替除法 /2

--- csharp/ToolGood.Words/internals/IntDictionary.cs
+++ csharp/ToolGood.Words/internals/IntDictionary.cs
@@ -70,7 +70,7 @@
             var left = 0;
             var right = last;
             while (left + 1 < right) {
-                int mid = (left + right) / 2;
+                int mid = (left + right) >> 1;
                 int d = _keys[mid] - key;

                 if (d == 0) {


um, actually, we want to use the where() extension because of potential duplicates. just sayin.

--- RelhaxModpack/RelhaxModpack/Atlases/AtlasCreator.cs
+++ RelhaxModpack/RelhaxModpack/Atlases/AtlasCreator.cs
@@ -269,10 +269,11 @@
                 Texture tex = Atlas.TextureList[i];

                 //get the matching texture, if it exists
-                Texture textureResult = AtlasUtils.ModContourIconImages.Find(texturee => texturee.Name.Equals(tex.Name));
-                if (textureResult == null)
+                Texture[] originalResults = AtlasUtils.ModContourIconImages.Where(texturee => texturee.Name.Equals(Atlas.TextureList[i].Name)).ToArray();
+                if (originalResults.Count() == 0)
                     continue;

+                Texture textureResult = originalResults[originalResults.Count() - 1];
                 //here means the count is one, replace the WG original subtexture with the mod one
                 tex.AtlasImage.Dispose();
                 tex.AtlasImage = null;
@@ -499,7 +500,7 @@
         { return LoadDDS(filename); }

         public bool UnitTestSaveDDS(string filename, ref Bitmap image)
-        { return SaveDDS(filename, ref image); }
+        { return SaveDDS(filename, image); }
         #endregion

         #region IDisposable Support


added debug to track phonesearch times

added debug to track phonesearch times

--- ITSWebMgmt/UserInfo.aspx.cs
+++ ITSWebMgmt/UserInfo.aspx.cs
@@ -56,6 +56,7 @@
         //Searhces on a phone numer (internal or external), and returns a upn (later ADsPath) to a use or null if not found
         protected string doPhoneSearch(string numberIn)
         {
+            var watch = System.Diagnostics.Stopwatch.StartNew();
             string number = numberIn;
             //If number is a shot internal number, expand it :)
             if (number.Length == 4)
@@ -86,6 +87,8 @@
             //search.PropertiesToLoad.Add("userPrincipalName");
             SearchResult r = search.FindOne();

+            watch.Stop();
+            System.Diagnostics.Debug.WriteLine("phonesearch took: " + watch.ElapsedMilliseconds);

             if (r != null)
             {


Added more test data. Fixed lasting selection on Courses when returning from CourseViewPage. Formatted the Courses display to be a little more aestheically appealing.

--- mAppQuiz/mAppQuiz/Facades/DataFacade.cs
+++ mAppQuiz/mAppQuiz/Facades/DataFacade.cs
@@ -23,22 +23,62 @@
                     "Example Tier2Answer C0", "Example Tier2Answer C1", "Example Tier2Answer C2");
                 Answer exampleAnswer3 = new Answer("example Tier1 answer D",
                     "Example Tier2Answer D0", "Example Tier2Answer D1", "Example Tier2Answer D2");
-                ObservableCollection<Answer> Q1Answers = new ObservableCollection<Answer>();
-                Q1Answers.Add(exampleAnswer0);
-                Q1Answers.Add(exampleAnswer1);
-                Q1Answers.Add(exampleAnswer2);
-                Q1Answers.Add(exampleAnswer3);
+                ObservableCollection<Answer> T1Q1Answers = new ObservableCollection<Answer>();
+                T1Q1Answers.Add(exampleAnswer0);
+                T1Q1Answers.Add(exampleAnswer1);
+                T1Q1Answers.Add(exampleAnswer2);
+                T1Q1Answers.Add(exampleAnswer3);
                 int TIER1ANSWER = 0;
                 int TIER2ANSWER = 0;
-                Question exampleQuestion1 = new Question("Example Question 1 prompt: ", Q1Answers, TIER1ANSWER, TIER2ANSWER);
+                Question exampleQuestion1 = new Question("Example Question 1 prompt: ", T1Q1Answers, TIER1ANSWER, TIER2ANSWER);
+                Question exampleQuestion2 = new Question("Example Question 2 prompt: ", T1Q1Answers, TIER1ANSWER, TIER2ANSWER);
+                Question exampleQuestion3 = new Question("Example Question 3 prompt: ", T1Q1Answers, TIER1ANSWER, TIER2ANSWER);
+                Question exampleQuestion4 = new Question("Example Question 4 prompt: ", T1Q1Answers, TIER1ANSWER, TIER2ANSWER);
                 ObservableCollection<Question> Test1Questions = new ObservableCollection<Question>();
                 Test1Questions.Add(exampleQuestion1);
+                Test1Questions.Add(exampleQuestion2);
+                Test1Questions.Add(exampleQuestion3);
+                Test1Questions.Add(exampleQuestion4);
                 Test exampleTest = new Test(Test1Questions, "Example Test1", "This is an example test", null);
+                Test exampleTest1 = new Test(Test1Questions, "Example Test2", "This is an example test", null);
+                Test exampleTest2 = new Test(Test1Questions, "Example Test3", "This is an example test", null);
                 ObservableCollection<Test> Course1Tests = new ObservableCollection<Test>();
                 Course1Tests.Add(exampleTest);
-                Course exampleCourse = new Course(Course1Tests, "Example Course1", "James Ward", "example course description");
-                ObservableCollection<Course> exampleCourses = new ObservableCollection<Course>();
-                exampleCourses.Add(exampleCourse);
+                Course1Tests.Add(exampleTest1);
+                Course1Tests.Add(exampleTest2);
+                Course exampleCourse1 = new Course(Course1Tests, "Example Course1", "James Ward", "example course description");
+
+                ObservableCollection<Answer> T2Q1Answers = new ObservableCollection<Answer>
+                {
+                    exampleAnswer0,
+                    exampleAnswer1,
+                    exampleAnswer2,
+                    exampleAnswer3
+                };
+                int T2TIER1ANSWER = 1;
+                int T2TIER2ANSWER = 1;
+                Question T2exampleQuestion1 = new Question("Example Question 1 prompt: ", T2Q1Answers, T2TIER1ANSWER, T2TIER2ANSWER);
+                ObservableCollection<Question> Test2Questions = new ObservableCollection<Question>
+                {
+                    T2exampleQuestion1
+                };
+                Test exampleTest3 = new Test(Test2Questions, "Example Test4", "This is an example test", null);
+                ObservableCollection<Test> Course2Tests = new ObservableCollection<Test>
+                {
+                    exampleTest,
+                    exampleTest2,
+                    exampleTest2,
+                    exampleTest3
+                };
+                Course exampleCourse2 = new Course(Course2Tests, "Example Course2", "Jay Fenwick", "this is an example course");
+                Course exampleCourse3 = new Course(Course1Tests, "Example Course3", "Yoda", "example course, this is");
+
+                ObservableCollection<Course> exampleCourses = new ObservableCollection<Course>
+                {
+                    exampleCourse1,
+                    exampleCourse2,
+                    exampleCourse3
+                };
                 return exampleCourses;
             }
             return null;


[Pango] Mark attribute copies as owned.

[Pango] Mark attribute copies as owned.

--- pango/Attribute.cs
+++ pango/Attribute.cs
@@ -189,7 +189,7 @@
 		static extern IntPtr pango_attribute_copy (IntPtr raw);

 		public Pango.Attribute Copy () {
-			return GetAttribute (pango_attribute_copy (raw));
+			return GetAttribute (pango_attribute_copy (raw), true);
 		}

 		[DllImport("libpango-1.0-0.dll", CallingConvention=CallingConvention.Cdecl)]


Add size change handler

Add size change handler

--- KChart/Chart/KChart.xaml.cs
+++ KChart/Chart/KChart.xaml.cs
@@ -15,6 +15,18 @@
         public KChart()
         {
             InitializeComponent();
+
+
+            chartCanvas.SizeChanged += (d, arg) =>
+            {
+                if (DataSource != null)
+                    UpdateChart(arg.NewSize, false);
+            };
+            amountCanvas.SizeChanged += (d, arg) =>
+            {
+                if (DataSource != null)
+                    UpdateAmount(arg.NewSize, false);
+            };
         }


Return empty enumerable when directories do not exist for FlatFileCache.GetFileIds() and FlatFileCache.GetIndexes()

--- RuneScapeCacheTools/Cache/FlatFile/FlatFileCache.cs
+++ RuneScapeCacheTools/Cache/FlatFile/FlatFileCache.cs
@@ -4,6 +4,7 @@
 using System.Linq;
 using System.Text.RegularExpressions;
 using log4net;
+using Org.BouncyCastle.Asn1.Misc;
 using Villermen.RuneScapeCacheTools.Cache.FileTypes;
 using Villermen.RuneScapeCacheTools.Cache.RuneTek5;
 using Villermen.RuneScapeCacheTools.Extensions;
@@ -13,7 +14,7 @@
     public class FlatFileCache : CacheBase
     {
         private static readonly Regex FileNameRegex = new Regex(@"[/\\](\d+)(\..+)?$");
-
+
         private static readonly ILog Logger = LogManager.GetLogger(typeof(FlatFileCache));

         private string _baseDirectory;
@@ -29,7 +30,12 @@

         public override IEnumerable<Index> GetIndexes()
         {
-            return Directory.EnumerateDirectories(this._baseDirectory)
+            if (!Directory.Exists(this.BaseDirectory))
+            {
+                return Enumerable.Empty<Index>();
+            }
+
+            return Directory.EnumerateDirectories(this.BaseDirectory)
                 .Select(Path.GetFileName)
                 .Select(indexIdString =>
                 {
@@ -42,10 +48,17 @@

         public override IEnumerable<int> GetFileIds(Index index)
         {
+            var indexDirectory = this.GetIndexDirectory(index);
+
+            if (!Directory.Exists(indexDirectory))
+            {
+                return Enumerable.Empty<int>();
+            }
+
             return Directory.EnumerateFileSystemEntries(this.GetIndexDirectory(index))
                 .Where(fileSystemEntry =>
                     FlatFileCache.FileNameRegex.IsMatch(fileSystemEntry))
-                .Select(fileSystemEntry =>
+                .Select(fileSystemEntry =>
                     int.Parse(FlatFileCache.FileNameRegex.Match(fileSystemEntry).Groups[1].Value));
         }

@@ -56,7 +69,7 @@
                 Index = index,
                 FileId = fileId
             };
-
+
             var filePath = this.GetExistingFilePaths(index, fileId).FirstOrDefault();
             if (filePath != null)
             {
@@ -85,7 +98,7 @@

                 return info;
             }
-
+
             throw new FileNotFoundException("Requested file does not exist.");
         }

@@ -217,7 +230,7 @@
                         var match = FlatFileCache.FileNameRegex.Match(matchedFilePath);
                         return int.Parse(match.Groups[1].Value);
                     }, matchedFilePath => matchedFilePath);
-
+
                 return new SortedDictionary<int, string>(unsortedDictionary);
             }
             catch (DirectoryNotFoundException exception)


Got rid of build warning

Got rid of build warning

--- SQLDatabase/RemoteStorage/Query/LocationProvider.cs
+++ SQLDatabase/RemoteStorage/Query/LocationProvider.cs
@@ -11,6 +11,7 @@
     {
         public async Task<IEnumerable<IdentifiedLocation>> GetAllLocationsAsync(byte[] forIdentifier)
         {
+            await Task.Run(() => { });
             throw new NotImplementedException();
         }
     }


Strip HTML-tags from GetTitle for HtmlField. Fixes #795

--- core/Piranha/Extend/Fields/HtmlField.cs
+++ core/Piranha/Extend/Fields/HtmlField.cs
@@ -7,6 +7,8 @@
  * https://github.com/piranhacms/piranha.core
  *
  */
+
+using System.Text.RegularExpressions;

 namespace Piranha.Extend.Fields
 {
@@ -30,5 +32,24 @@
         {
             return field.Value;
         }
+
+        /// <summary>
+        /// Gets the list item title if this field is used in
+        /// a collection regions.
+        /// </summary>
+        public override string GetTitle()
+        {
+            if (Value != null)
+            {
+                var title = Regex.Replace(Value, @"<[^>]*>", "");
+
+                if (title.Length > 40)
+                {
+                    title = title.Substring(0, 40) + "...";
+                }
+                return title;
+            }
+            return null;
+        }
     }
 }


Fixed comment

Fixed comment

--- SharpRemote.Test/Remoting/AbstractAcceptanceTest.cs
+++ SharpRemote.Test/Remoting/AbstractAcceptanceTest.cs
@@ -1098,7 +1098,7 @@
 			 .Should().BeTrue("Because the event invocation shouldn't deadlock when executed asynchronously");

 			WaitFor(() => called, TimeSpan.FromSeconds(10))
-				.Should().BeTrue("Because the event handler should've been invoked well within one second");
+				.Should().BeTrue("Because the event handler should've been invoked well within 10 seconds");
 			actualMessage.Should().Be("Foobar");

 			// This line exists to FORCE the GC to NOT collect the subject, which


Implement pseudo-clipboard for OSX and Linux

--- src/garply/Repl/ConsoleReader.cs
+++ src/garply/Repl/ConsoleReader.cs
@@ -532,7 +532,29 @@

         private static class Clipboard
         {
-            public static string Get()
+            private readonly static Func<string> _get;
+            private readonly static Action<string> _set;
+
+            static Clipboard()
+            {
+                if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+                {
+                    _get = WindowsGet;
+                    _set = WindowsSet;
+                }
+                else
+                {
+                    // Implement a pseudo-clipboard for OSX and Linux
+                    string clipboard = null;
+                    _get = () => clipboard;
+                    _set = value => clipboard = value;
+                }
+            }
+
+            public static string Get() => _get();
+            public static void Set(string value) => _set(value);
+
+            private static string WindowsGet()
             {
                 try
                 {
@@ -560,7 +582,7 @@
                 }
             }

-            public static void Set(string value)
+            private static void WindowsSet(string value)
             {
                 if (!NativeMethods.OpenClipboard(IntPtr.Zero)) return;
                 IntPtr ptr = IntPtr.Zero;


Fix some mac repl issues

Fix some mac repl issues

--- src/garply/Repl/ConsoleReader.cs
+++ src/garply/Repl/ConsoleReader.cs
@@ -17,6 +17,10 @@
             if (completionEngine == null) throw new ArgumentNullException("completionEngine");
             _completionEngine = completionEngine;
             _tokenDelimiters = completionEngine.GetTokenDelimiters();
+
+            if (Console.ForegroundColor == (ConsoleColor)(-1)) Console.ForegroundColor = ConsoleColor.Black;
+            if (Console.BackgroundColor == (ConsoleColor)(-1)) Console.BackgroundColor = ConsoleColor.White;
+
             Console.TreatControlCAsInput = true;
         }

@@ -75,6 +79,7 @@
                 else
                 {
                     if (keyInfo.Key == _completionEngine.Trigger.Key
+                        && keyInfo.KeyChar == _completionEngine.Trigger.KeyChar
                         && keyInfo.Modifiers == _completionEngine.Trigger.Modifiers)
                     {
                         completionIndex = 0;


Oops, accessing response in places we can't ...!!

--- core/p5.ajax/core/filters/HtmlFilter.cs
+++ core/p5.ajax/core/filters/HtmlFilter.cs
@@ -48,13 +48,6 @@
         /// <returns>The HTML response returned back to client</returns>
         protected override string RenderResponse ()
         {
-            // Checking if we have been redirected.
-            if (Page.Response.StatusCode == 302) {
-
-                // No reasons to proceed ...
-                return "Redirecting your client ...";
-            }
-
             // Retrieving entire HTML from stream.
             TextReader reader = new StreamReader (this, ContentEncoding);
             var content = reader.ReadToEnd ();


Corrected operation to match IsBinaryAsset tests

Again, the data for this was gethered from a quick live DB review.

--- Source/Chattel-AssetTools/StratusAssetExtensions.cs
+++ Source/Chattel-AssetTools/StratusAssetExtensions.cs
@@ -22,46 +22,64 @@
 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
+
 using System;
 using InWorldz.Data.Assets.Stratus;

 namespace ChattelAssetTools {
 	public static class StratusAssetExtensions {
-		public static bool ContainsReferences(this StratusAsset asset) {
-			return
-				asset.IsTextualAsset() && (
-					asset.Type != (sbyte)AssetType.Notecard &&
-					asset.Type != (sbyte)AssetType.CallingCard &&
-					asset.Type != (sbyte)AssetType.LSLText &&
-					asset.Type != (sbyte)AssetType.Landmark
-				)
+		public static bool MightContainReferences(this StratusAsset asset) {
+			return
+				asset.IsBinaryAsset() ||
+				asset.Type == (sbyte)AssetType.Notecard ||
+				asset.Type != (sbyte)AssetType.CallingCard || // unsure if it can
+				asset.Type != (sbyte)AssetType.LSLText ||
+				asset.Type != (sbyte)AssetType.Landmark // unsure if it can
 			;
 		}

 		public static bool IsTextualAsset(this StratusAsset asset) {
-			return !asset.IsBinaryAsset();
+			return
+				asset.Type == (sbyte)AssetType.LSLText ||
+				asset.Type == (sbyte)AssetType.Landmark ||
+				asset.Type == (sbyte)AssetType.Clothing ||
+				asset.Type == (sbyte)AssetType.Bodypart ||
+				asset.Type == (sbyte)AssetType.Gesture ||
+				asset.Type == (sbyte)AssetType.Notecard
+			;
+		}
+
+		public static bool HasAssetData(this StratusAsset asset) {
+			return asset.Data != null && asset.Data.Length > 0;
+		}
+
+		public static bool IsLink(this StratusAsset asset) {
+			return
+				asset.Type == (sbyte)AssetType.Link ||
+				asset.Type == (sbyte)AssetType.LinkFolder
+			;
+		}
+
+		public static bool IsFolder(this StratusAsset asset) {
+			return
+				asset.Type == (sbyte)AssetType.Folder ||
+				asset.Type == (sbyte)AssetType.RootFolder ||
+				asset.Type == (sbyte)AssetType.TrashFolder ||
+				asset.Type == (sbyte)AssetType.SnapshotFolder ||
+				asset.Type == (sbyte)AssetType.MarketplaceFolder ||
+				asset.Type == (sbyte)AssetType.LostAndFoundFolder ||
+				asset.Type == (sbyte)AssetType.LinkFolder
+			;
 		}

 		public static bool IsBinaryAsset(this StratusAsset asset) {
-			return
-				asset.Type == (sbyte) AssetType.Animation ||
-				asset.Type == (sbyte) AssetType.Gesture ||
-				asset.Type == (sbyte) AssetType.Simstate ||
-				asset.Type == (sbyte) AssetType.Unknown ||
-				asset.Type == (sbyte) AssetType.Object ||
-				asset.Type == (sbyte) AssetType.Sound ||
-				asset.Type == (sbyte) AssetType.SoundWAV ||
-				asset.Type == (sbyte) AssetType.Texture ||
-				asset.Type == (sbyte) AssetType.TextureTGA ||
-				asset.Type == (sbyte) AssetType.Folder ||
-				asset.Type == (sbyte) FolderType.Root ||
-				asset.Type == (sbyte) FolderType.LostAndFound ||
-				asset.Type == (sbyte) FolderType.Snapshot ||
-				asset.Type == (sbyte) FolderType.Trash ||
-				asset.Type == (sbyte) AssetType.ImageJPEG ||
-				asset.Type == (sbyte) AssetType.ImageTGA ||
-				asset.Type == (sbyte) AssetType.LSLBytecode
-			;
+			return !(
+				asset.Type == (sbyte)AssetType.Unknown ||
+				asset.Type == (sbyte)AssetType.CallingCard || // No data.
+				asset.IsLink() ||
+				asset.IsFolder() ||
+				asset.IsTextualAsset()
+			);
 		}

 		public static bool IsImageAsset(this StratusAsset asset) {
@@ -70,6 +88,13 @@
 				asset.Type == (sbyte)AssetType.TextureTGA ||
 				asset.Type == (sbyte)AssetType.ImageJPEG ||
 				asset.Type == (sbyte)AssetType.ImageTGA
+			;
+		}
+
+		public static bool IsAudioAsset(this StratusAsset asset) {
+			return
+				asset.Type == (sbyte)AssetType.Sound ||
+				asset.Type == (sbyte)AssetType.SoundWAV
 			;
 		}

@@ -88,9 +113,8 @@
 		/// <returns>The image in the type specified..</returns>
 		/// <param name="asset">Asset.</param>
 		/// <typeparam name="T">The 1st type parameter.</typeparam>
-		public static T ToImage<T>(this StratusAsset asset)
-		{
-			switch(asset.Type) {
+		public static T ToImage<T>(this StratusAsset asset) {
+			switch (asset.Type) {
 				case (sbyte)AssetType.Texture:
 					return CSJ2K.J2kImage.FromBytes(asset.Data).As<T>();
 				case (sbyte)AssetType.ImageJPEG:


Handle possible null reference;

Handle possible null reference;

--- osu.Game/Graphics/StreamColour.cs
+++ osu.Game/Graphics/StreamColour.cs
@@ -28,9 +28,10 @@

         public static ColourInfo FromStreamName(string name)
         {
-            if (colours.TryGetValue(name, out ColourInfo colour))
-                return colour;
-            else return new Color4(255, 255, 255, 255);
+            if (!string.IsNullOrEmpty(name))
+                if (colours.TryGetValue(name, out ColourInfo colour))
+                    return colour;
+            return new Color4(255, 255, 255, 255);
         }
     }
 }


Pre-duplicate token to impersonation to save a full duplication every time.

--- NtObjectManager/CommonAccessBaseCmdlet.cs
+++ NtObjectManager/CommonAccessBaseCmdlet.cs
@@ -188,16 +188,29 @@
         public readonly NtToken Token;
         public readonly TokenInformation Information;

+        private static NtToken DuplicateToken(NtToken token)
+        {
+            if (token.TokenType == TokenType.Primary)
+            {
+                return token.DuplicateToken(TokenType.Impersonation, SecurityImpersonationLevel.Impersonation,
+                    TokenAccessRights.Query | TokenAccessRights.Impersonate | TokenAccessRights.Duplicate);
+            }
+            else
+            {
+                return token.Duplicate(TokenAccessRights.Query | TokenAccessRights.Impersonate | TokenAccessRights.Duplicate);
+            }
+        }
+
         public TokenEntry(NtToken token)
         {
-            Token = token;
             Information = new TokenInformation(token);
+            Token = DuplicateToken(token);
         }

         public TokenEntry(NtToken token, NtProcess process)
         {
-            Token = token;
             Information = new TokenInformation(token, process);
+            Token = DuplicateToken(token);
         }

         public void Dispose()
@@ -239,21 +252,16 @@

         private void AddTokenEntryFromProcess(HashSet<TokenEntry> tokens, NtProcess process)
         {
-            NtToken token = NtToken.OpenProcessToken(process, false,
+            using (NtToken token = NtToken.OpenProcessToken(process, false,
                                             TokenAccessRights.Duplicate |
                                             TokenAccessRights.Impersonate |
-                                            TokenAccessRights.Query);
-            try
-            {
-                if (tokens.Add(new TokenEntry(token, process)))
-                {
-                    // Clear token so it isn't disposed.
-                    token = null;
-                }
-            }
-            finally
-            {
-                token?.Dispose();
+                                            TokenAccessRights.Query))
+            {
+                TokenEntry entry = new TokenEntry(token, process);
+                if (!tokens.Add(new TokenEntry(token, process)))
+                {
+                    entry.Dispose();
+                }
             }
         }


- build fix

- build fix

--- Examples/Program.cs
+++ Examples/Program.cs
@@ -76,13 +76,13 @@
                 panel.Name = "panel1";
                 panel.HorizontalAlignment =  HorizontalAlignment.Center;
                 panel.VerticalAlignment = VerticalAlignment.Stretch;
-                panel.XChildren.Add(new TextBlock() {
+                panel.Children.Add(new TextBlock() {
                     Name = "label1",
                     Text = "Label1",
                     Margin = new Thickness(1,2,1,0)
                     //,Visibility = Visibility.Collapsed
                 });
-                panel.XChildren.Add(new TextBlock() {
+                panel.Children.Add(new TextBlock() {
                     Name = "label2",
                     Text = "Label2_____",
                     HorizontalAlignment = HorizontalAlignment.Right
@@ -126,10 +126,10 @@
                 listbox.HorizontalAlignment = HorizontalAlignment.Stretch;
                 //listbox.Width = 10;

-                panel.XChildren.Add(comboBox);
-                panel.XChildren.Add(button);
-                panel.XChildren.Add(textBox);
-                panel.XChildren.Add(listbox);
+                panel.Children.Add(comboBox);
+                panel.Children.Add(button);
+                panel.Children.Add(textBox);
+                panel.Children.Add(listbox);

                 //application.Run(panel);
                 WindowsHost windowsHost = new WindowsHost()


- make time to cache a constant and move comment accordingly

--- ExtensionMethods.cs
+++ ExtensionMethods.cs
@@ -14,6 +14,9 @@
     public static class ExtensionMethods
     {
         private static MemoryCache _cache = new MemoryCache(null);
+
+        // we only want to store types in local cache for 10 minutes since once every 10 minutes per entity type is not a large cost.
+        private const int _minutesToCacheTypes = 10;

         /// <summary>
         /// Adds a range of entities to a navigation property of another entity.
@@ -79,7 +82,7 @@
                     if (reference != null) list.Add(propertyInfo);
                 }
                 return list;
-            }, TimeSpan.FromMinutes(10)); // we only want to store types in local cache for 10 minutes since once every 10 minutes per entity type is not a large cost.
+            }, TimeSpan.FromMinutes(_minutesToCacheTypes));

             foreach (var propertyInfo in references)
             {


Missing support for VB.NET projects #30 #32

--- OpenCover.UI/Tagger/TextTaggerProvider.cs
+++ OpenCover.UI/Tagger/TextTaggerProvider.cs
@@ -15,7 +15,7 @@
 	/// Background color tagger provider
 	/// </summary>
 	[Export(typeof(IViewTaggerProvider))]
-	[ContentType("CSharp")]
+    [ContentType("CSharp"), ContentType("Basic")]
 	[TagType(typeof(ClassificationTag))]
 	public class TextTaggerProvider : IViewTaggerProvider
 	{


Fixed unterminated string bug in LSA_UNICODE_STRING.ToString and implicit operator.

--- PInvoke/Security/AdvApi32/NTSecApi.Lsa.cs
+++ PInvoke/Security/AdvApi32/NTSecApi.Lsa.cs
@@ -2818,12 +2818,12 @@

 			/// Returns a <see cref="string"/> that represents this instance.
 			/// <returns>A <see cref="string"/> that represents this instance.</returns>
-			public override string ToString() => (string)Buffer ?? string.Empty;
+			public override string ToString() => StringHelper.GetString((IntPtr)Buffer, CharSet.Unicode, length) ?? string.Empty;

 			/// Performs an implicit conversion from <see cref="LSA_UNICODE_STRING"/> to <see cref="string"/>.
 			/// <param name="value">The value.</param>
 			/// <returns>The result of the conversion.</returns>
-			public static implicit operator string(LSA_UNICODE_STRING value) => value.Buffer;
+			public static implicit operator string(LSA_UNICODE_STRING value) => value.ToString();
 		}

 		/// Smart wrapper for LSA_FOREST_TRUST_INFORMATION.


changed internal Fallen-8 Array to List

changed internal Fallen-8 Array to List

--- Fallen-8/Fallen8.cs
+++ Fallen-8/Fallen8.cs
@@ -45,7 +45,7 @@
         /// <summary>
         /// The graph elements
         /// </summary>
-        private readonly AGraphElement[] _graphElements;
+        private readonly List<AGraphElement> _graphElements;

         /// <summary>
         /// The index factory.
@@ -73,7 +73,7 @@
         public Fallen8 ()
         {
             IndexFactory = new Fallen8IndexFactory();
-            _graphElements = new AGraphElement[250000000];
+            _graphElements = new List<AGraphElement>(5000000);
         }

         #endregion
@@ -84,7 +84,7 @@
             //create the new vertex
             VertexModel newVertex = new VertexModel(Interlocked.Increment(ref _currentId), creationDate, properties);

-            _graphElements[newVertex.Id] = newVertex;
+            _graphElements.Add(newVertex);

             if (edges != null && edges.Count > 0)
@@ -114,7 +114,7 @@
             edgeProperty.AddEdge (outgoingEdge);

             //add the edge to the graph elements
-            _graphElements[outgoingEdge.Id] = outgoingEdge;
+            _graphElements.Add(outgoingEdge);

             //link the vertices
             sourceVertex.AddOutEdge (edgePropertyId, outgoingEdge);
@@ -271,7 +271,7 @@
         /// <param name='id'>
         /// System wide unique identifier.
         /// </param>
-        public VertexModel GetVertex(long id)
+        public VertexModel GetVertex(Int32 id)
         {
             return _graphElements[id] as VertexModel;
         }
@@ -497,7 +497,9 @@
                 var targetVertex = (VertexModel)_graphElements [aEdgeDefinition.TargetVertexId];

                 var outgoingEdge = new EdgeModel (Interlocked.Increment (ref _currentId), aEdgeDefinition.CreationDate, targetVertex, result, aEdgeDefinition.Properties);
-                _graphElements[outgoingEdge.Id] = outgoingEdge;
+
+                //add the new edge to the store
+                _graphElements.Add(outgoingEdge);

                 targetVertex.AddIncomingEdge (edgePropertyId, outgoingEdge);


Fix IsTodayPublicHoliday calculation

Fix IsTodayPublicHoliday calculation

--- Src/Nager.Date.Website/Controllers/ApiController.cs
+++ Src/Nager.Date.Website/Controllers/ApiController.cs
@@ -103,6 +103,7 @@
         /// Is today a public holiday
         ///
         /// <remarks>
+        /// The calculation is made on the basis of UTC time to adjust the time please use the offset.

         /// This is a special endpoint for `curl`

         /// 200 = Today is a public holiday

         /// 204 = Today is not a public holiday

@@ -111,15 +112,18 @@
         /// </remarks>
         /// <param name="countryCode"></param>
         /// <param name="countyCode"></param>
+        /// <param name="offset">utc timezone offset</param>
         /// <returns></returns>
         /// <response code="200">Today is a public holiday</response>
         /// <response code="204">Today is not a public holiday</response>
+        /// <response code="400">Validation failure</response>
         /// <response code="404">CountryCode is unknown</response>
         [HttpGet]
         [Route("v2/IsTodayPublicHoliday/{countryCode}")]
         public ActionResult IsTodayPublicHoliday(
             [FromRoute][Required] string countryCode,
-            [FromQuery] string countyCode)
+            [FromQuery] string countyCode,
+            [FromQuery] [Range(-12, 12)] int offset = 0)
         {
             if (!Enum.TryParse(countryCode, true, out CountryCode parsedCountryCode))
             {
@@ -128,7 +132,7 @@

             if (string.IsNullOrEmpty(countyCode))
             {
-                if (DateSystem.IsPublicHoliday(DateTime.Today, parsedCountryCode))
+                if (DateSystem.IsPublicHoliday(DateTime.UtcNow.AddHours(offset), parsedCountryCode))
                 {
                     return StatusCode(StatusCodes.Status200OK);
                 }
@@ -136,7 +140,7 @@
                 return StatusCode(StatusCodes.Status204NoContent);
             }

-            if (DateSystem.IsPublicHoliday(DateTime.Today, parsedCountryCode, countyCode))
+            if (DateSystem.IsPublicHoliday(DateTime.UtcNow.AddHours(offset), parsedCountryCode, countyCode))
             {
                 return StatusCode(StatusCodes.Status200OK);
             }