GitHubSync update

GitHubSync update

--- deployment/cake/tests.cake
+++ deployment/cake/tests.cake
@@ -65,7 +65,7 @@

     try
     {
-        if (!testTargetFramework.Contains("netcore") && IsDotNetCoreProject(buildContext, projectName))
+        if (testTargetFramework.Contains("netcore") && IsDotNetCoreProject(buildContext, projectName))
         {
             buildContext.CakeContext.Information("Project '{0}' is a .NET core project, using 'dotnet test' to run the unit tests", projectName);


Fix NRE in SwitchMangler

Fix NRE in SwitchMangler

--- Confuser.Protections/ControlFlow/SwitchMangler.cs
+++ Confuser.Protections/ControlFlow/SwitchMangler.cs
@@ -135,7 +135,7 @@
 						if (trace.AfterStack[instr.Offset] != 0) {
 							if (instr.Operand is Instruction)
 								requiredInstr.Add((Instruction)instr.Operand);
-							else {
+							else if (instr.Operand is Instruction[]) {
 								foreach (var target in (Instruction[])instr.Operand)
 									requiredInstr.Add(target);
 								shouldSpilt = false;


dont play equipsound if tryequip got called with silent true

--- Content.Shared/Inventory/InventorySystem.Equip.cs
+++ Content.Shared/Inventory/InventorySystem.Equip.cs
@@ -92,7 +92,7 @@
             return false;
         }

-        if(item.EquipSound != null)
+        if(!silent && item.EquipSound != null)
             SoundSystem.Play(Filter.Pvs(target), item.EquipSound.GetSound(), target, AudioParams.Default.WithVolume(-2f));

         inventory.Dirty();


Don't affect "Folder Watcher" queue on resume

--- DesktopWidgets/Widgets/FolderWatcher/ViewModel.cs
+++ DesktopWidgets/Widgets/FolderWatcher/ViewModel.cs
@@ -273,8 +273,6 @@
             _resumeTimer?.Stop();
             Settings.ResumeOnNextStart = false;
             IsPaused = false;
-            _isShowing = false;
-            HandleDirectoryChange();
         }

         private void NextExecute()


Fix incorrect id reference in test

Fix incorrect id reference in test

--- osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs
+++ osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs
@@ -638,7 +638,7 @@
             AddStep("Find an icon for different ruleset", () =>
             {
                 difficultyIcon = set.ChildrenOfType<DrawableCarouselBeatmapSet.FilterableDifficultyIcon>()
-                                    .First(icon => icon.Item.Beatmap.ID == 3);
+                                    .First(icon => icon.Item.Beatmap.Ruleset.ID == 3);
             });

             AddAssert("Check ruleset is osu!", () => Ruleset.Value.ID == 0);


added option

added option

--- src/health-check-middleware/HealthcheckMiddleware.cs
+++ src/health-check-middleware/HealthcheckMiddleware.cs
@@ -26,7 +26,18 @@
             if (context.Request.Path.StartsWithSegments(_options.Path))
             {
                 _logger.LogInformation("Healthcheck requested: " + context.Request.Path);
-                await context.Response.WriteAsync(_options.Message);
+
+                if(_options.AddVersion)
+                {
+
+                    await context.Response.WriteAsync(_options.Message);
+                }
+                else
+                {
+                    await context.Response.WriteAsync(_options.Message);
+                }
+
+
             }
             else
             {
@@ -48,10 +59,12 @@
         public HealthCheckOptions()
         {
             Path = "/healthcheck";
-            Message = "i am alive!";
+            Message = "i am alive!";
+            AddVersion = false;
         }

         public string Path { get; set; }
         public string Message { get; set; }
+        public bool AddVersion { get; set; }
     }
 }


[packages,Python,3.5.1] Renamed PythonExtensionModule to PythonDynamicExtensionModule

--- packages/Python-3.5.1/bam/Scripts/PythonExtensionModules.cs
+++ packages/Python-3.5.1/bam/Scripts/PythonExtensionModules.cs
@@ -31,7 +31,7 @@
 namespace Python
 {
     [Bam.Core.ModuleGroup("Thirdparty/Python/Module")]
-    class PythonExtensionModule :
+    class PythonDynamicExtensionModule :
         C.Plugin
     {
         private string ModuleName;
@@ -40,7 +40,7 @@
         private Bam.Core.Module.PrivatePatchDelegate CompilationPatch;
         private Bam.Core.Module.PrivatePatchDelegate LinkerPatch;

-        protected PythonExtensionModule(
+        protected PythonDynamicExtensionModule(
             string moduleName,
             Bam.Core.StringArray sourceFiles,
             Bam.Core.StringArray libraries,
@@ -54,21 +54,21 @@
             this.LinkerPatch = linkerPatch;
         }

-        protected PythonExtensionModule(
+        protected PythonDynamicExtensionModule(
             string moduleName,
             Bam.Core.StringArray sourceFiles)
             :
             this(moduleName, sourceFiles, null, null, null)
         {}

-        protected PythonExtensionModule(
+        protected PythonDynamicExtensionModule(
             string moduleName,
             string sourceFile)
             :
             this(moduleName, new Bam.Core.StringArray(sourceFile))
         {}

-        protected PythonExtensionModule(
+        protected PythonDynamicExtensionModule(
             string moduleName,
             string sourceFile,
             Bam.Core.Module.PrivatePatchDelegate compilationPatch)
@@ -76,7 +76,7 @@
             this(moduleName, new Bam.Core.StringArray(sourceFile), null, compilationPatch, null)
         {}

-        protected PythonExtensionModule(
+        protected PythonDynamicExtensionModule(
             string moduleName,
             string sourceFile,
             Bam.Core.Module.PrivatePatchDelegate compilationPatch,
@@ -85,7 +85,7 @@
             this(moduleName, new Bam.Core.StringArray(sourceFile), null, compilationPatch, linkerPatch)
         { }

-        protected PythonExtensionModule(
+        protected PythonDynamicExtensionModule(
             string moduleName,
             Bam.Core.StringArray sourceFiles,
             Bam.Core.Module.PrivatePatchDelegate compilationPatch)
@@ -93,7 +93,7 @@
             this(moduleName, sourceFiles, null, compilationPatch, null)
         { }

-        protected PythonExtensionModule(
+        protected PythonDynamicExtensionModule(
             string moduleName)
             :
             this(moduleName, new Bam.Core.StringArray(moduleName))
@@ -179,7 +179,7 @@
     // new list
     [Bam.Core.PlatformFilter(Bam.Core.EPlatform.NotWindows)] // Windows builtin
     class array :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public array()
             :
@@ -189,7 +189,7 @@

     [Bam.Core.PlatformFilter(Bam.Core.EPlatform.NotWindows)] // Windows builtin
     class cmath :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public cmath()
             :
@@ -199,7 +199,7 @@

     [Bam.Core.PlatformFilter(Bam.Core.EPlatform.NotWindows)] // Windows builtin
     class math :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public math()
             :
@@ -209,7 +209,7 @@

     [Bam.Core.PlatformFilter(Bam.Core.EPlatform.NotWindows)] // Windows builtin
     class _struct :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public _struct()
             :
@@ -218,7 +218,7 @@
     }

     class _testcapi :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public _testcapi()
             :
@@ -228,7 +228,7 @@

     [Bam.Core.PlatformFilter(Bam.Core.EPlatform.NotWindows)] // Windows builtin
     class _random :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public _random()
             :
@@ -237,7 +237,7 @@
     }

     class _elementtree :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public _elementtree()
             :
@@ -255,7 +255,7 @@

     [Bam.Core.PlatformFilter(Bam.Core.EPlatform.NotWindows)] // Windows builtin
     class _pickle :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public _pickle()
             :
@@ -265,7 +265,7 @@

     [Bam.Core.PlatformFilter(Bam.Core.EPlatform.NotWindows)] // Windows builtin
     class _datetime :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public _datetime()
             :
@@ -275,7 +275,7 @@

     [Bam.Core.PlatformFilter(Bam.Core.EPlatform.NotWindows)] // Windows builtin
     class _bisect :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public _bisect()
             :
@@ -285,7 +285,7 @@

     [Bam.Core.PlatformFilter(Bam.Core.EPlatform.NotWindows)] // Windows builtin
     class _heapq :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public _heapq()
             :
@@ -294,7 +294,7 @@
     }

     class unicodedata :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public unicodedata()
             :
@@ -304,7 +304,7 @@

     [Bam.Core.PlatformFilter(Bam.Core.EPlatform.NotWindows)] // not buildable on Windows
     class fcntl :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public fcntl()
             :
@@ -318,7 +318,7 @@

     [Bam.Core.PlatformFilter(Bam.Core.EPlatform.Invalid)]
     class spwd :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public spwd()
             :
@@ -328,7 +328,7 @@

     [Bam.Core.PlatformFilter(Bam.Core.EPlatform.NotWindows)] // not buildable on Windows
     class grp :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public grp()
             :
@@ -337,7 +337,7 @@
     }

     class select :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public select()
             :
@@ -354,7 +354,7 @@

     [Bam.Core.PlatformFilter(Bam.Core.EPlatform.NotWindows)] // Windows builtin
     class mmap :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public mmap()
             :
@@ -364,7 +364,7 @@

     [Bam.Core.PlatformFilter(Bam.Core.EPlatform.NotWindows)] // Windows builtin
     class _csv :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public _csv()
             :
@@ -373,7 +373,7 @@
     }

     class _socket :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public _socket()
             :
@@ -399,7 +399,7 @@

     [Bam.Core.PlatformFilter(Bam.Core.EPlatform.Invalid)] // requires OpenSLL
     class _ssl :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public _ssl()
             :
@@ -409,7 +409,7 @@

     [Bam.Core.PlatformFilter(Bam.Core.EPlatform.NotWindows)] // not linkable on Windows
     class _crypt :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public _crypt()
             :
@@ -426,7 +426,7 @@

     [Bam.Core.PlatformFilter(Bam.Core.EPlatform.NotWindows)] // not buildable on Windows
     class nis :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public nis()
             :
@@ -436,7 +436,7 @@

     [Bam.Core.PlatformFilter(Bam.Core.EPlatform.NotWindows)] // not buildable on Windows
     class termios :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public termios()
             :
@@ -446,7 +446,7 @@

     [Bam.Core.PlatformFilter(Bam.Core.EPlatform.NotWindows)] // not buildable on Windows
     class resource :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public resource()
             :
@@ -456,7 +456,7 @@

     [Bam.Core.PlatformFilter(Bam.Core.EPlatform.NotWindows)] // not buildable on Windows
     class _posixsubprocess :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public _posixsubprocess()
             :
@@ -466,7 +466,7 @@

     [Bam.Core.PlatformFilter(Bam.Core.EPlatform.NotWindows)] // Windows builtin
     class audioop :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public audioop()
             :
@@ -476,7 +476,7 @@

     [Bam.Core.PlatformFilter(Bam.Core.EPlatform.NotWindows)] // Windows builtin
     class _md5 :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public _md5()
             :
@@ -486,7 +486,7 @@

     [Bam.Core.PlatformFilter(Bam.Core.EPlatform.NotWindows)] // Windows builtin
     class _sha1 :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public _sha1()
             :
@@ -496,7 +496,7 @@

     [Bam.Core.PlatformFilter(Bam.Core.EPlatform.NotWindows)] // Windows builtin
     class _sha256 :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public _sha256()
             :
@@ -506,7 +506,7 @@

     [Bam.Core.PlatformFilter(Bam.Core.EPlatform.NotWindows)] // Windows builtin
     class _sha512 :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public _sha512()
             :
@@ -516,7 +516,7 @@

     [Bam.Core.PlatformFilter(Bam.Core.EPlatform.Invalid)] // no tcl.h
     class _tkinter :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public _tkinter()
             :
@@ -526,7 +526,7 @@

     [Bam.Core.PlatformFilter(Bam.Core.EPlatform.NotWindows)] // not buildable on Windows
     class syslog :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public syslog()
             :
@@ -536,7 +536,7 @@

     [Bam.Core.PlatformFilter(Bam.Core.EPlatform.NotWindows)] // not buildable on Windows
     class _curses :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public _curses()
             :
@@ -546,7 +546,7 @@

     [Bam.Core.PlatformFilter(Bam.Core.EPlatform.NotWindows)] // not buildable on Windows
     class _curses_panel :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public _curses_panel()
             :
@@ -556,7 +556,7 @@

     [Bam.Core.PlatformFilter(Bam.Core.EPlatform.Invalid)]
     class _dbm :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public _dbm()
             :
@@ -566,7 +566,7 @@

     [Bam.Core.PlatformFilter(Bam.Core.EPlatform.Invalid)]
     class _gdbm :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public _gdbm()
             :
@@ -576,7 +576,7 @@

     [Bam.Core.PlatformFilter(Bam.Core.EPlatform.NotWindows)] // Windows builtin
     class binascii :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public binascii()
             :
@@ -586,7 +586,7 @@

     [Bam.Core.PlatformFilter(Bam.Core.EPlatform.NotWindows)] // Windows builtin
     class parser :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public parser()
             :
@@ -595,7 +595,7 @@
     }

     class fpectl :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public fpectl()
             :
@@ -604,7 +604,7 @@
     }

     class fpetest :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public fpetest()
             :
@@ -614,7 +614,7 @@

     [Bam.Core.PlatformFilter(Bam.Core.EPlatform.NotWindows)] // Windows builtin
     class zlib :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public zlib()
             :
@@ -640,7 +640,7 @@
     }

     class pyexpat :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public pyexpat()
             :
@@ -668,7 +668,7 @@

     [Bam.Core.PlatformFilter(Bam.Core.EPlatform.NotWindows)] // Windows builtin
     class _multibytecodec :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public _multibytecodec()
             :
@@ -678,7 +678,7 @@

     [Bam.Core.PlatformFilter(Bam.Core.EPlatform.NotWindows)] // Windows builtin
     class _codecs_cn :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public _codecs_cn()
             :
@@ -688,7 +688,7 @@

     [Bam.Core.PlatformFilter(Bam.Core.EPlatform.NotWindows)] // Windows builtin
     class _codecs_hk :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public _codecs_hk()
             :
@@ -698,7 +698,7 @@

     [Bam.Core.PlatformFilter(Bam.Core.EPlatform.NotWindows)] // Windows builtin
     class _codecs_iso2022 :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public _codecs_iso2022()
             :
@@ -708,7 +708,7 @@

     [Bam.Core.PlatformFilter(Bam.Core.EPlatform.NotWindows)] // Windows builtin
     class _codecs_jp :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public _codecs_jp()
             :
@@ -718,7 +718,7 @@

     [Bam.Core.PlatformFilter(Bam.Core.EPlatform.NotWindows)] // Windows builtin
     class _codecs_kr :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public _codecs_kr()
             :
@@ -728,7 +728,7 @@

     [Bam.Core.PlatformFilter(Bam.Core.EPlatform.NotWindows)] // Windows builtin
     class _codecs_tw :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public _codecs_tw()
             :
@@ -739,7 +739,7 @@
 #if false
     // old list
     class TimeModule :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public TimeModule()
             :
@@ -749,7 +749,7 @@

     class AtexitModule :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public AtexitModule()
             :
@@ -758,7 +758,7 @@
     }

     class JsonModule :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public JsonModule()
             :
@@ -767,7 +767,7 @@
     }

     class TestBufferModule :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public TestBufferModule()
             :
@@ -776,7 +776,7 @@
     }

     class TestImportMultipleModule :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public TestImportMultipleModule()
             :
@@ -785,7 +785,7 @@
     }

     class TestMultiPhaseModule :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public TestMultiPhaseModule()
             :
@@ -794,7 +794,7 @@
     }

     class LSProfModule :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public LSProfModule()
             :
@@ -803,7 +803,7 @@
     }

     class OpCodeModule :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public OpCodeModule()
             :
@@ -812,7 +812,7 @@
     }

     class PwdModule :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public PwdModule()
             :
@@ -826,7 +826,7 @@
     // TODO: deprecated APIs called on OSX
 #if false
     class HashLibModule :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public HashLibModule()
             :
@@ -842,7 +842,7 @@
     // TODO: needs a library
     #if false
     class CursesModule :
-        PythonExtensionModule
+        PythonDynamicExtensionModule
     {
         public CursesModule()
             :


Fixed WikiToken subclasses with string properties to never return null. The distinction between null and empty string is irrelevant in all these cases.

--- src/Schnell/WikiToken.cs
+++ src/Schnell/WikiToken.cs
@@ -108,12 +108,12 @@

         public string Key
         {
-            get { return _key; }
+            get { return _key ?? string.Empty; }
         }

         public string Value
         {
-            get { return _value; }
+            get { return _value ?? string.Empty; }
         }
     }

@@ -129,7 +129,7 @@

         public string Src
         {
-            get { return _src; }
+            get { return _src ?? string.Empty; }
         }
     }

@@ -145,7 +145,7 @@

         public string Href
         {
-            get { return _href; }
+            get { return _href ?? string.Empty; }
         }
     }

@@ -161,7 +161,7 @@

         public string Word
         {
-            get { return _word; }
+            get { return _word ?? string.Empty; }
         }
     }

@@ -177,7 +177,7 @@

         public string Text
         {
-            get { return _text; }
+            get { return _text ?? string.Empty; }
         }
     }
 }


Added check for file existence

Added check for file existence

--- src/ScreenshotManager.cs
+++ src/ScreenshotManager.cs
@@ -56,7 +56,7 @@

         private bool IsFullScreenshot(string filename)
         {
-            return filename.EndsWith(".png") && !filename.EndsWith("-thumb.png") && File.Exists(Path.ChangeExtension(filename, ".sfs"));
+            return filename.EndsWith(".png") && !filename.EndsWith("-thumb.png") && File.Exists(filename) && File.Exists(Path.ChangeExtension(filename, ".sfs"));
         }

         private void SaveScreenshot(string filename)


Switch to 1.2.3-new-subs01

Switch to 1.2.3-new-subs01

--- src/SharedVersionInfo.cs
+++ src/SharedVersionInfo.cs
@@ -1,5 +1,5 @@
 using System.Reflection;

-[assembly: AssemblyVersion("1.2.2")]
-[assembly: AssemblyFileVersion("1.2.2")]
-[assembly: AssemblyInformationalVersion("1.2.2")]+[assembly: AssemblyVersion("1.2.3")]
+[assembly: AssemblyFileVersion("1.2.3")]
+[assembly: AssemblyInformationalVersion("1.2.3-new-subs01")]


Remove some dead argument checks for unsigned primitives for less than zero (#12349)

* Remove dead comparisons of unsigned primitive less than zero

* Delete bad assertition that is consistently hit using the Debug coreclr using the tests

--- src/mscorlib/src/System/Runtime/InteropServices/SafeBuffer.cs
+++ src/mscorlib/src/System/Runtime/InteropServices/SafeBuffer.cs
@@ -98,8 +98,6 @@
         [CLSCompliant(false)]
         public void Initialize(ulong numBytes)
         {
-            if (numBytes < 0)
-                throw new ArgumentOutOfRangeException(nameof(numBytes), SR.ArgumentOutOfRange_NeedNonNegNum);
             if (IntPtr.Size == 4 && numBytes > UInt32.MaxValue)
                 throw new ArgumentOutOfRangeException(nameof(numBytes), SR.ArgumentOutOfRange_AddressSpace);
             Contract.EndContractBlock();
@@ -117,11 +115,6 @@
         [CLSCompliant(false)]
         public void Initialize(uint numElements, uint sizeOfEachElement)
         {
-            if (numElements < 0)
-                throw new ArgumentOutOfRangeException(nameof(numElements), SR.ArgumentOutOfRange_NeedNonNegNum);
-            if (sizeOfEachElement < 0)
-                throw new ArgumentOutOfRangeException(nameof(sizeOfEachElement), SR.ArgumentOutOfRange_NeedNonNegNum);
-
             if (IntPtr.Size == 4 && numElements * sizeOfEachElement > UInt32.MaxValue)
                 throw new ArgumentOutOfRangeException("numBytes", SR.ArgumentOutOfRange_AddressSpace);
             Contract.EndContractBlock();
@@ -377,7 +370,6 @@

         private static InvalidOperationException NotInitialized()
         {
-            Debug.Assert(false, "Uninitialized SafeBuffer!  Someone needs to call Initialize before using this instance!");
             return new InvalidOperationException(SR.InvalidOperation_MustCallInitialize);
         }


modify demo

modify demo

--- Samples/Senparc.Weixin.MP.Sample.vs2017/Senparc.Weixin.MP.CoreSample/Controllers/CacheController.cs
+++ Samples/Senparc.Weixin.MP.Sample.vs2017/Senparc.Weixin.MP.CoreSample/Controllers/CacheController.cs
@@ -71,7 +71,7 @@
             else
             {
                 sb.Append("使用本地缓存
");
-                CacheStrategyFactory.RegisterObjectCacheStrategy(() => null);
+                CacheStrategyFactory.RegisterObjectCacheStrategy(() => null);//注意：此处不能输入()=>null，这样仍然是一个有内容的委托！
             }

             //var cacheKey = TestContainer1.GetContainerCacheKey();
@@ -87,7 +87,7 @@
                 Key = bagKey,
                 DateTime = DateTime.Now
             };
-            TestContainer1.Update(bagKey, bag);//更新到缓存（队列）
+            TestContainer1.Update(bagKey, bag);//更新到缓存（立即更新）

             itemCollection = containerCacheStrategy.GetAll<TestContainerBag1>();

@@ -125,7 +125,7 @@
                     Key = shortBagKey,
                     DateTime = DateTime.Now
                 };
-                TestContainer1.Update(shortBagKey, bag); //更新到缓存（队列）
+                TestContainer1.Update(shortBagKey, bag); //更新到缓存（立即更新）
                 sb.AppendFormat("{0}：{1}
", "bag.DateTime", bag.DateTime.ToString("o"));

                 Thread.Sleep(1);


Fix SA1009 handling of closing parenthesis followed by pointer dereference

Fixes #1832

--- StyleCop.Analyzers/StyleCop.Analyzers/SpacingRules/SA1009ClosingParenthesisMustBeSpacedCorrectly.cs
+++ StyleCop.Analyzers/StyleCop.Analyzers/SpacingRules/SA1009ClosingParenthesisMustBeSpacedCorrectly.cs
@@ -128,7 +128,8 @@
                 break;

             case SyntaxKind.DotToken:
-                // allow a space for this case, but only if the ')' character is the last on the line
+            case SyntaxKind.MinusGreaterThanToken:
+                // allow a space for these cases, but only if the ')' character is the last on the line
                 allowEndOfLine = true;
                 precedesStickyCharacter = true;
                 break;


Added changes to DiceRoller

Added changes to DiceRoller

--- DungeonsAndDragons/DnDEngine/Roller/DiceRoller.cs
+++ DungeonsAndDragons/DnDEngine/Roller/DiceRoller.cs
@@ -4,50 +4,50 @@
 {
     public static class DiceRoller
     {
-        public static int RollD100()
+        public static int RollD100(int numberOfDice)
         {
-            return new Random().Next(1, 100);
+            return RollDice(numberOfDice, 100);
         }

-        public static int RollD20()
+        public static int RollD20(int numberOfDice)
         {
-            return new Random().Next(1, 20);
+            return RollDice(numberOfDice, 20);
         }

-        public static int RollD12()
+        public static int RollD12(int numberOfDice)
         {
-            return new Random().Next(1, 12);
+            return RollDice(numberOfDice, 12);
         }

-        public static int RollD10()
+        public static int RollD10(int numberOfDice)
         {
-            return new Random().Next(1, 10);
+            return RollDice(numberOfDice, 10);
         }

-        public static int RollD8()
+        public static int RollD8(int numberOfDice)
         {
-            return new Random().Next(1, 8);
+            return RollDice(numberOfDice, 8);
         }

-        public static int RollD6()
+        public static int RollD6(int numberOfDice)
         {
-            return new Random().Next(1, 6);
+            return RollDice(numberOfDice, 6);
         }

-        public static int RollD4()
+        public static int RollD4(int numberOfDice)
         {
-            return new Random().Next(1, 4);
+            return RollDice(numberOfDice, 4);
         }

         // the no good fun killer lazy version of rolling dice
-        public static int RollDice(int NumberOfSides, int NumberOfDice)
+        public static int RollDice(int numberOfSides, int numberOfDice)
         {
-            int RandomNumber = 0;
-            for (int i = 1; i <= NumberOfDice; i++)
+            int randomNumber = 0;
+            for (int i = 1; i <= numberOfDice; i++)
             {
-                RandomNumber += new Random().Next(1, NumberOfSides);
+                randomNumber += new Random().Next(1, numberOfSides);
             }
-            return RandomNumber;
+            return randomNumber;
         }
     }
 }


Issue warning when backup is cancelled by user.

Previously, a yellow warning icon would be displayed but the logs did
not contain any details regarding the cause of the warning.

This concerns issue #3982.

--- Duplicati/Library/Main/Operation/BackupHandler.cs
+++ Duplicati/Library/Main/Operation/BackupHandler.cs
@@ -30,6 +30,7 @@
 using Duplicati.Library.Utility;
 using Duplicati.Library.Common.IO;
 using Duplicati.Library.Common;
+using Duplicati.Library.Logging;
 using Duplicati.Library.Main.Operation.Backup;
 using Duplicati.Library.Main.Operation.Common;

@@ -244,6 +245,7 @@
                 if (token.IsCancellationRequested)
                 {
                     result.PartialBackup = true;
+                    Log.WriteWarningMessage(LOGTAG, "CancellationRequested", null, "Cancellation was requested by user.");
                 }
                 else
                 {


preferring depth-first search by ordering by parent it if there is no match

--- EightPuzzle/EightPuzzle/ActionByWeightComparer.cs
+++ EightPuzzle/EightPuzzle/ActionByWeightComparer.cs
@@ -18,7 +18,7 @@
             var result = x.Cost.CompareTo(y.Cost);

             // these are simply to keep a stable search order
-            if (result == 0) result = x.VisitedNodeId.CompareTo(y.VisitedNodeId);
+            if (result == 0) result = -x.VisitedNodeId.CompareTo(y.VisitedNodeId);
             if (result == 0) result = x.Move.From.CompareTo(y.Move.From);
             if (result == 0) result = x.Move.To.CompareTo(y.Move.To);


resolve issue with response body not being set

--- Fetcher.Core/Services/FetcherRepositoryService.cs
+++ Fetcher.Core/Services/FetcherRepositoryService.cs
@@ -172,27 +172,20 @@
                 hero.FetcherWebResponseId = response.Id;
                 hero.FetcherWebResponse = response as FetcherWebResponse;
             }
-            else
-            {
-                hero.FetcherWebResponse.Body = response.Body;
-                hero.FetcherWebResponse.Error = response.Error;
-                hero.FetcherWebResponse.Headers = response.Headers;
-                hero.FetcherWebResponse.HttpStatusCode = response.HttpStatusCode;
-            }
+            hero.FetcherWebResponse.Body = response.Body;
+            hero.FetcherWebResponse.Error = response.Error;
+            hero.FetcherWebResponse.Headers = response.Headers;
+            hero.FetcherWebResponse.HttpStatusCode = response.HttpStatusCode;

-            if(request.Id != 0)
+            if (request.Id != 0)
             {
                 hero.FetcherWebRequestId = request.Id;
                 hero.FetcherWebRequest = request as FetcherWebRequest;
             }
-            else
-            {
-                hero.FetcherWebRequest.Headers = request.Headers;
-                hero.FetcherWebRequest.Body = request.Body;
-                hero.FetcherWebRequest.ContentType = request.ContentType;
-                hero.FetcherWebRequest.Method = request.Method;
-
-            }
+            hero.FetcherWebRequest.Headers = request.Headers;
+            hero.FetcherWebRequest.Body = request.Body;
+            hero.FetcherWebRequest.ContentType = request.ContentType;
+            hero.FetcherWebRequest.Method = request.Method;

             hero.FetcherWebRequest.Url = request.Url;
             hero.LastUpdated = timestamp;


Run T4 template

Run T4 template

--- FileHelpers/Messages/GenerateMessages1.autogen.cs
+++ FileHelpers/Messages/GenerateMessages1.autogen.cs
@@ -2,7 +2,7 @@

 namespace FileHelpers
 {
-    internal class Messages
+internal class Messages
 {
 internal class Errors
 {
@@ -342,7 +342,7 @@
 }internal class SameFieldOrderClass: MessageBase
 {

-internal SameFieldOrderClass(): base(@"The field: $FieldName1$ has the same FieldOrder that: $FieldName2$ you must use different values") {}
+internal SameFieldOrderClass(): base(@"The field: $FieldName1$ has the same FieldOrder as: $FieldName2$. You must use different values") {}
  private string mFieldName1 = null;
  internal SameFieldOrderClass FieldName1(string value)
 {


[TheForest] Better NRE handling for BoltConnection in IOnServerCommand

--- Games/Unity/Oxide.Game.TheForest/TheForestCore.cs
+++ Games/Unity/Oxide.Game.TheForest/TheForestCore.cs
@@ -204,7 +204,9 @@
             if (Interface.Call("OnServerCommand", command, data) != null) return true;

             // Check if command is from a player
-            var id = connection?.RemoteEndPoint.SteamId.Id.ToString();
+            if (connection == null) return null;
+
+            var id = connection.RemoteEndPoint.SteamId.Id.ToString();
             var entity = Scene.SceneTracker.allPlayerEntities.FirstOrDefault(ent => ent.source.ConnectionId == connection.ConnectionId);
             if (entity == null) return null;


adjustung perf test boundaries

adjustung perf test boundaries

--- GridGomain.Tests.Stress/NBenchAvailabilityTest.cs
+++ GridGomain.Tests.Stress/NBenchAvailabilityTest.cs
@@ -29,9 +29,9 @@

         [NBenchFact]
         [PerfBenchmark(Description = "Test to ensure that a minimal throughput test can be rapidly executed.",
-            NumberOfIterations = 3, RunMode = RunMode.Iterations,
+            NumberOfIterations = 1, RunMode = RunMode.Iterations,
             RunTimeMilliseconds = 1000, TestMode = TestMode.Test)]
-        [CounterThroughputAssertion(TotalCommandsExecutedCounter, MustBe.GreaterThan, 400)]
+        [CounterThroughputAssertion(TotalCommandsExecutedCounter, MustBe.GreaterThan, 1)]

         public void SimpleFact()
         {


Delay for zombz death

Delay for zombz death


fix occupy room to sent 1 email

fix occupy room to sent 1 email

--- JoinRpg.Services.Impl/AccommodationServiceImpl.cs
+++ JoinRpg.Services.Impl/AccommodationServiceImpl.cs
@@ -93,10 +93,7 @@

             await UnitOfWork.SaveChangesAsync();

-            foreach (var accommodationRequest in accommodationRequests)
-            {
-                await EmailService.Email(await CreateRoomEmail<OccupyRoomEmail>(room, accommodationRequest.Subjects.ToArray()));
-            }
+            await EmailService.Email(await CreateRoomEmail<OccupyRoomEmail>(room, accommodationRequests.SelectMany(ar => ar.Subjects).ToArray()));
         }

         private async Task<T> CreateRoomEmail<T>(ProjectAccommodation room, Claim[] changed)


Richer Spawn sample showing-off options

Richer Spawn sample showing-off options

--- eg/Program.cs
+++ eg/Program.cs
@@ -44,7 +44,8 @@
                     new { Title = nameof(DuckDuckGo)            , Query = DuckDuckGo()             , IsWindowsOnly = false },
                     new { Title = nameof(QueenSongs)            , Query = QueenSongs()             , IsWindowsOnly = false },
                     new { Title = nameof(ScheduledTasksViaSpawn), Query = ScheduledTasksViaSpawn() , IsWindowsOnly = true  },
-                    new { Title = nameof(PowerShellDirViaSpawn) , Query = PowerShellDirViaSpawn()  , IsWindowsOnly = true  },
+                    new { Title = nameof(PowerShellDirViaSpawn) , Query = PowerShellDirViaSpawn(Environment.GetEnvironmentVariable("WINDIR") ?? Environment.SystemDirectory),
+                                                                                IsWindowsOnly = true  },
                     new { Title = nameof(TopHackerNews)         , Query = TopHackerNews(100)       , IsWindowsOnly = false },
                     new { Title = nameof(MsdnBooksXmlSample)    , Query = MsdnBooksXmlSample()     , IsWindowsOnly = false },
                     new { Title = nameof(MockarooCsv)           , Query = MockarooCsv()            , IsWindowsOnly = false },
@@ -113,14 +114,31 @@
                 Arguments = (string)e.Element(ns + "Arguments"),
             };

-        static IObservable<object> PowerShellDirViaSpawn() =>
+        static ISpawnObservable<string>
+            SpawnPowerShell(string command,
+                            bool noLogo = false,
+                            bool noProfile = false,
+                            bool nonInteractive = false) =>
+            Spawn("PowerShell", ProgramArguments.Empty)
+                .AddArguments(
+                    from @switch in new[]
+                    {
+                        new { Present = noLogo        , Text = "-NoLogo"         },
+                        new { Present = noProfile     , Text = "-NoProfile"      },
+                        new { Present = nonInteractive, Text = "-NonInteractive" },
+                    }
+                    where @switch.Present
+                    select @switch.Text)
+                .AddArgument("-C", command);
+
+        static IObservable<object> PowerShellDirViaSpawn(string dir) =>

             from row in
-                Spawn("PowerShell",
-                      ProgramArguments.Var(@"-C",
-                          "Get-ChildItem $env:WINDIR " +
-                          "| Select-Object FullName, Mode, Length " +
-                          "| ConvertTo-Csv -NoType"))
+                SpawnPowerShell(string.Join("|", "Get-ChildItem $env:DIR",
+                                                 "Select-Object FullName, Mode, Length",
+                                                 "ConvertTo-Csv -NoType"),
+                                noProfile: true)
+                    .AddEnvironment("DIR", dir)
                     .ParseCsv(hr => new
                               {
                                   FullName = hr.GetFirstIndex("FullName"),


When generating the Base class, set its name to use the class generic name  (with template arguments changed to generic ones) if it exists

--- src/generator/Main.cs
+++ src/generator/Main.cs
@@ -273,7 +273,7 @@

 				// FIXME: Handle when base class name is fully qualified
 				foreach (Entry bs in clas.children.Where (o => o.type == "Base")) {
-					clas.Class.Bases.Add (new Class.BaseClass { Name = bs.Base.name, Access = bs.CheckValue ("access", "public") ? Access.Public : bs.CheckValue ("access", "protected") ? Access.Protected : Access.Private, IsVirtual = bs.IsTrue ("virtual") });
+					clas.Class.Bases.Add (new Class.BaseClass { Name = bs.Base.Class != null ? (bs.Base.Class.GenericName ?? bs.Base.Class.Name) : bs.computedName, Access = bs.CheckValue ("access", "public") ? Access.Public : bs.CheckValue ("access", "protected") ? Access.Protected : Access.Private, IsVirtual = bs.IsTrue ("virtual") });
 				}

 				IEnumerable<CodeAtom> nested = null;


replaced Byte type with Integer, Byte[] type with Blob

--- generator/ClientApiGenerator/Models/ParameterInfo.cs
+++ generator/ClientApiGenerator/Models/ParameterInfo.cs
@@ -34,7 +34,7 @@
             get
             {
                 string temp = TypeName;
-                if(temp.Contains("Int"))
+                if(temp.Contains("Int") || temp == "Byte" || temp == "Byte?")
                 {
                     return TypeName.Replace(temp, "Integer");
                 } else if(temp.Contains("Dictionary"))
@@ -43,6 +43,9 @@
                 } else if(temp.Contains("ErrorCodeId"))
                 {
                     return TypeName.Replace(temp, "String");
+                } else if (temp.Contains("Byte[]"))
+                {
+                    return TypeName.Replace(temp, "Blob");
                 } else
                 {
                     return TypeName.Replace("?", "");


work around a change in the cairo rendering in 1.0.2.

2007-02-05  Larry Ewing  <lewing@novell.com>

        * src/Widgets/SoftFocus.cs: work around a change in the cairo
        rendering in 1.0.2.

svn path=/trunk/; revision=2916

--- src/Widgets/SoftFocus.cs
+++ src/Widgets/SoftFocus.cs
@@ -93,8 +93,16 @@

 			RadialGradient circle = new RadialGradient (center.X * scale, center.Y * scale, radius * max,
 								    center.X * scale, center.Y * scale, radius * max * .7);
-			circle.AddColorStop (0, new Cairo.Color (0.0, 0.0, 0.0, 0.0));
-			circle.AddColorStop (1.0, new Cairo.Color (1.0, 1.0, 1.0, 1.0));
+
+
+			// FIXME ugh cairo 1.0.2 is so broken why are we still shipping it.
+			if (CairoAPI.cairo_version () > (1 * 10000 + 2 * 100 + 0)) {
+				circle.AddColorStop (0, new Cairo.Color (0.0, 0.0, 0.0, 0.0));
+				circle.AddColorStop (1.0, new Cairo.Color (1.0, 1.0, 1.0, 1.0));
+			} else {
+				circle.AddColorStop (1.0, new Cairo.Color (0.0, 0.0, 0.0, 0.0));
+				circle.AddColorStop (0, new Cairo.Color (1.0, 1.0, 1.0, 1.0));
+			}
 			return circle;
 		}


Remove unused using

Remove unused using

--- osu.Framework.Tests/Audio/AudioThreadTest.cs
+++ osu.Framework.Tests/Audio/AudioThreadTest.cs
@@ -4,7 +4,6 @@
 using System;
 using System.Threading;
 using System.Threading.Tasks;
-using ManagedBass;
 using NUnit.Framework;
 using osu.Framework.Audio.Track;
 using osu.Framework.IO.Stores;


Remove lazy load logic and simplify closing logic

--- osu.Framework/Graphics/UserInterface/Menu.cs
+++ osu.Framework/Graphics/UserInterface/Menu.cs
@@ -53,19 +53,19 @@

         protected readonly Direction Direction;

-        private readonly Lazy<Menu> lazySubMenu;
-        private Menu subMenu => lazySubMenu.Value;
         private Menu parentMenu;
+        private Menu subMenu;

         private readonly Box background;

         private Cached sizeCache = new Cached();

+        private readonly Container<Menu> subMenuContainer;
+
         public Menu(Direction direction)
         {
             Direction = direction;

-            Container<Menu> subMenuContainer;
             InternalChildren = new Drawable[]
             {
                 MaskingContainer = new Container
@@ -95,13 +95,6 @@
                 }
             };

-            lazySubMenu = new Lazy<Menu>(() =>
-            {
-                var menu = CreateSubMenu();
-                subMenuContainer.Add(menu);
-                return menu;
-            });
-
             switch (direction)
             {
                 case Direction.Horizontal:
@@ -219,10 +212,9 @@
             get { return state; }
             set
             {
-                if (AlwaysOpen && value == MenuState.Closed)
-                {
-                    if (lazySubMenu.IsValueCreated)
-                        subMenu?.clearRecursively();
+                if (AlwaysOpen)
+                {
+                    subMenu?.Close();
                     return;
                 }

@@ -239,16 +231,16 @@

         private void updateState()
         {
+            subMenu?.Close();
+
             switch (State)
             {
                 case MenuState.Closed:
                     AnimateClose();

-                    if (AlwaysOpen)
-                        break;
-
                     if (HasFocus)
                         GetContainingInputManager().ChangeFocus(null);
+
                     break;
                 case MenuState.Opened:
                     AnimateOpen();
@@ -282,8 +274,6 @@
             drawableItem.Hovered = menuItemHovered;

             ItemsContainer.Add(drawableItem);
-
-            subMenu.parentMenu = this;
         }

         /// <summary>
@@ -316,11 +306,7 @@
         /// <summary>
         /// Closes this <see cref="Menu"/>.
         /// </summary>
-        public void Close()
-        {
-            State = MenuState.Closed;
-            openedAtItem = null;
-        }
+        public void Close() => State = MenuState.Closed;

         /// <summary>
         /// Toggles the state of this <see cref="Menu"/>.
@@ -397,7 +383,7 @@
         {
             // We only want to close the sub-menu if we're not a sub menu - if we are a sub menu
             // then clicks should instead cause the sub menus to instantly show up
-            if (RequireClickToOpen && subMenu.State == MenuState.Opened)
+            if (RequireClickToOpen && subMenu?.State == MenuState.Opened)
             {
                 subMenu.Close();
                 return;
@@ -412,32 +398,51 @@
             }

             openDelegate?.Cancel();
-            subMenu.openAt(item);
+            openSubmenuFor(item);
+        }
+
+        private void openSubmenuFor(DrawableMenuItem item)
+        {
+            if (subMenu == null)
+            {
+                subMenuContainer.Add(subMenu = CreateSubMenu());
+                subMenu.parentMenu = this;
+            }
+            else
+                subMenu.Close();
+
+            subMenu.Items = item.Item.Items;
+            subMenu.Position = new Vector2(
+                Direction == Direction.Vertical ? Width : item.X,
+                Direction == Direction.Horizontal ? Height : item.Y);
+
+            subMenu.Open();
         }

         private ScheduledDelegate openDelegate;
         private void menuItemHovered(DrawableMenuItem item)
         {
             // If we're not a sub-menu, then hover shouldn't display a sub-menu unless an item is clicked
-            if (RequireClickToOpen && subMenu.State == MenuState.Closed)
+            if (RequireClickToOpen && subMenu?.State != MenuState.Opened)
                 return;

             openDelegate?.Cancel();

             if (RequireClickToOpen || HoverOpenDelay == 0)
-                subMenu.openAt(item);
+                openSubmenuFor(item);
             else
             {
                 openDelegate = Scheduler.AddDelayed(() =>
                 {
                     if (item.IsHovered)
-                        subMenu.openAt(item);
+                        openSubmenuFor(item);
                 }, HoverOpenDelay);
             }
         }

         public override bool AcceptsFocus => true;
         protected override bool OnClick(InputState state) => true;
+        protected override bool OnHover(InputState state) => true;

         protected override void OnFocusLost(InputState state)
         {
@@ -454,45 +459,18 @@
         /// </summary>
         private void closeAll()
         {
-            var iterator = this;
+            Close();
+
+            var iterator = parentMenu;
             while (iterator != null)
             {
+                if (iterator.IsHovered)
+                    break;
                 iterator.Close();
                 iterator = iterator.parentMenu;
             }
         }

-        private DrawableMenuItem openedAtItem;
-
-        /// <summary>
-        /// Opens a <see cref="Menu"/> with the items of <paramref name="item"/> and at a position offset from <paramref name="item"/>.
-        /// </summary>
-        /// <param name="item">The <see cref="DrawableMenuItem"/> which the sub-<see cref="Menu"/> should display for.</param>
-        private void openAt(DrawableMenuItem item)
-        {
-            if (openedAtItem == item)
-                return;
-            openedAtItem = item;
-
-            Items = item.Item.Items;
-            Position = new Vector2(parentMenu.Direction == Direction.Vertical ? parentMenu.Width : item.X, parentMenu.Direction == Direction.Horizontal ? parentMenu.Height : item.Y);
-            Open();
-
-            subMenu?.clearRecursively();
-        }
-
-        /// <summary>
-        /// Closes this <see cref="Menu"/> and the <see cref="subMenu"/> recursively.
-        /// </summary>
-        private void clearRecursively()
-        {
-            Clear();
-
-            if (lazySubMenu.IsValueCreated)
-                subMenu?.clearRecursively();
-
-            openedAtItem = null;
-        }
         #endregion

         /// <summary>
@@ -683,7 +661,7 @@
                         Hovered?.Invoke(this);
                 });

-                return true;
+                return false;
             }

             protected override void OnHoverLost(InputState state)


Ensure we don't access a null stream

Ensure we don't access a null stream

--- osu.Framework/Graphics/Video/VideoDecoder.cs
+++ osu.Framework/Graphics/Video/VideoDecoder.cs
@@ -29,7 +29,7 @@
         /// <summary>
         /// The duration of the video that is being decoded. Can only be queried after the decoder has started decoding has loaded. This value may be an estimate by FFmpeg, depending on the video loaded.
         /// </summary>
-        public double Duration => stream->duration * timeBaseInSeconds * 1000;
+        public double Duration => stream == null ? 0 : stream->duration * timeBaseInSeconds * 1000;

         /// <summary>
         /// True if the decoder currently does not decode any more frames, false otherwise.
@@ -49,7 +49,7 @@
         /// <summary>
         /// The frame rate of the video stream this decoder is decoding.
         /// </summary>
-        public double FrameRate => stream->avg_frame_rate.GetValue();
+        public double FrameRate => stream == null ? 0 : stream->avg_frame_rate.GetValue();

         /// <summary>
         /// True if the decoder can seek, false otherwise. Determined by the stream this decoder was created with.


Override instead of re-binding event

Override instead of re-binding event

--- osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs
+++ osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs
@@ -49,10 +49,9 @@

             var fruit = (DrawableFruit)h;
             fruit.CheckPosition = catcherArea.CheckIfWeCanCatch;
-            fruit.OnJudgement += Fruit_OnJudgement;
         }

-        private void Fruit_OnJudgement(DrawableHitObject judgedObject, Judgement judgement)
+        public override void OnJudgement(DrawableHitObject judgedObject, Judgement judgement)
         {
             if (judgement.IsHit)
             {


Reword comment slightly

Reword comment slightly

--- osu.Game/Online/Spectator/SpectatorClient.cs
+++ osu.Game/Online/Spectator/SpectatorClient.cs
@@ -206,8 +206,8 @@
                 if (!IsPlaying)
                     return;

-                // Disposal could be processed late, leading to EndPlaying potentially being called after a future BeginPlaying call.
-                // Account for this by ensuring the current score matches the score in the provided GameplayState.
+                // Disposal can take some time, leading to EndPlaying potentially being called after a future play session.
+                // Account for this by ensuring the score of the current play matches the one in the provided state.
                 if (currentScore != state.Score)
                     return;


Add countdown settings to design section

--- osu.Game/Screens/Edit/Setup/DesignSection.cs
+++ osu.Game/Screens/Edit/Setup/DesignSection.cs
@@ -1,14 +1,28 @@
 // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
 // See the LICENCE file in the repository root for full licence text.

+using System;
+using System.Globalization;
+using System.Linq;
 using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
 using osu.Framework.Localisation;
+using osu.Game.Beatmaps;
 using osu.Game.Graphics.UserInterfaceV2;
+using osuTK;

 namespace osu.Game.Screens.Edit.Setup
 {
     internal class DesignSection : SetupSection
     {
+        private const float fade_duration = 250;
+
+        private LabelledSwitchButton enableCountdown;
+        private FillFlowContainer countdownSettings;
+        private LabelledEnumDropdown<CountdownType> countdownSpeed;
+        private LabelledNumberBox countdownOffset;
+
         private LabelledSwitchButton widescreenSupport;
         private LabelledSwitchButton epilepsyWarning;
         private LabelledSwitchButton letterboxDuringBreaks;
@@ -20,6 +34,35 @@
         {
             Children = new[]
             {
+                enableCountdown = new LabelledSwitchButton
+                {
+                    Label = "Enable countdown",
+                    Current = { Value = Beatmap.BeatmapInfo.Countdown != CountdownType.None },
+                    Description = "If enabled, an \"Are you ready? 3, 2, 1, GO!\" countdown will be inserted at the beginning of the beatmap, assuming there is enough time to do so."
+                },
+                countdownSettings = new FillFlowContainer
+                {
+                    RelativeSizeAxes = Axes.X,
+                    AutoSizeAxes = Axes.Y,
+                    Spacing = new Vector2(10),
+                    Direction = FillDirection.Vertical,
+                    Children = new Drawable[]
+                    {
+                        countdownSpeed = new LabelledEnumDropdown<CountdownType>
+                        {
+                            Label = "Countdown speed",
+                            Current = { Value = Beatmap.BeatmapInfo.Countdown != CountdownType.None ? Beatmap.BeatmapInfo.Countdown : CountdownType.Normal },
+                            Items = Enum.GetValues(typeof(CountdownType)).Cast<CountdownType>().Where(type => type != CountdownType.None)
+                        },
+                        countdownOffset = new LabelledNumberBox
+                        {
+                            Label = "Countdown offset",
+                            Current = { Value = Beatmap.BeatmapInfo.CountdownOffset.ToString() },
+                            Description = "If the countdown sounds off-time, use this to make it appear one or more beats early.",
+                        }
+                    }
+                },
+                Empty(),
                 widescreenSupport = new LabelledSwitchButton
                 {
                     Label = "Widescreen support",
@@ -45,13 +88,34 @@
         {
             base.LoadComplete();

+            enableCountdown.Current.BindValueChanged(_ => updateCountdownSettingsVisibility(), true);
+            countdownSettings.FinishTransforms(true);
+
+            enableCountdown.Current.BindValueChanged(_ => updateBeatmap());
+            countdownSpeed.Current.BindValueChanged(_ => updateBeatmap());
+            countdownOffset.OnCommit += (_, __) => updateBeatmap();
+
             widescreenSupport.Current.BindValueChanged(_ => updateBeatmap());
             epilepsyWarning.Current.BindValueChanged(_ => updateBeatmap());
             letterboxDuringBreaks.Current.BindValueChanged(_ => updateBeatmap());
         }

+        private void updateCountdownSettingsVisibility()
+        {
+            bool countdownEnabled = enableCountdown.Current.Value;
+
+            foreach (var child in countdownSettings)
+            {
+                child.ScaleTo(new Vector2(1, countdownEnabled ? 1 : 0), fade_duration, Easing.OutQuint)
+                     .FadeTo(countdownEnabled ? 1 : 0, fade_duration, Easing.OutQuint);
+            }
+        }
+
         private void updateBeatmap()
         {
+            Beatmap.BeatmapInfo.Countdown = enableCountdown.Current.Value ? countdownSpeed.Current.Value : CountdownType.None;
+            Beatmap.BeatmapInfo.CountdownOffset = int.TryParse(countdownOffset.Current.Value, NumberStyles.None, CultureInfo.InvariantCulture, out int offset) ? offset : 0;
+
             Beatmap.BeatmapInfo.WidescreenStoryboard = widescreenSupport.Current.Value;
             Beatmap.BeatmapInfo.EpilepsyWarning = epilepsyWarning.Current.Value;
             Beatmap.BeatmapInfo.LetterboxInBreaks = letterboxDuringBreaks.Current.Value;


Give more space to the parameter adjustment area

--- osu.Game/Screens/Edit/Timing/TimingScreen.cs
+++ osu.Game/Screens/Edit/Timing/TimingScreen.cs
@@ -32,7 +32,7 @@
             ColumnDimensions = new[]
             {
                 new Dimension(),
-                new Dimension(GridSizeMode.Absolute, 200),
+                new Dimension(GridSizeMode.Absolute, 350),
             },
             Content = new[]
             {


Removed PositionTests.cs - missed in last commit

--- MarsRoverTechnicalChallengeTests/PositionTests.cs
+++ MarsRoverTechnicalChallengeTests/PositionTests.cs
@@ -1,64 +0,0 @@
-using System;
-using MarsRoverTechnicalChallenge;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-
-namespace MarsRoverTechnicalChallengeTests
-{
-    [TestClass]
-    public class PositionTests
-    {
-        [TestMethod]
-        public void PositionGivenZeroZeroNConstructsCorrectly()
-        {
-            var position = new Position(0, 0, Orientation.N);
-
-            Assert.AreEqual(position.X, 0);
-            Assert.AreEqual(position.Y, 0);
-            Assert.AreEqual(Orientation.N, position.Facing);
-        }
-
-        [TestMethod]
-        public void PositionGivenZeroZeroNRotatedRFacesE()
-        {
-            var position = new Position(0, 0, Orientation.N);
-            position.Rotate(Direction.R);
-
-            Assert.AreEqual(Orientation.E, position.Facing);
-        }
-
-        [TestMethod]
-        public void PositionGivenZeroZeroSRotatedLFacesE()
-        {
-            var position = new Position(0, 0, Orientation.S);
-            position.Rotate(Direction.L);
-
-            Assert.AreEqual(Orientation.E, position.Facing);
-        }
-
-        [TestMethod]
-        public void PositionGivenZeroZeroNRotatedRRRRFacesN()
-        {
-            var position = new Position(0, 0, Orientation.N);
-
-            for (int i = 0; i < 4; i++)
-            {
-                position.Rotate(Direction.R);
-            }
-
-            Assert.AreEqual(Orientation.N, position.Facing);
-        }
-
-        [TestMethod]
-        public void PositionGivenZeroZeroNRotatedLLLLFacesN()
-        {
-            var position = new Position(0, 0, Orientation.N);
-
-            for (int i = 0; i < 4; i++)
-            {
-                position.Rotate(Direction.L);
-            }
-
-            Assert.AreEqual(Orientation.N, position.Facing);
-        }
-    }
-}


refactoring

refactoring

--- MatterControlLib/DesignTools/Primitives/Gear2D.cs
+++ MatterControlLib/DesignTools/Primitives/Gear2D.cs
@@ -49,7 +49,74 @@
 	// http://lcamtuf.coredump.cx/gcnc/ Guerrilla guide to CNC machining, mold making, and resin casting
 	public class Gear2D : VertexSourceLegacySupport
 	{
+		private double _backlash = .05;
+		private double _centerHoleDiameter = 4;
 		private double _circularPitch = 8;
+
+		private double _clearance = .05;
+
+		// Most common stock gears have a 20° pressure angle, with 14½° and 25° pressure angle gears being much less
+		// common. Increasing the pressure angle increases the width of the base of the gear tooth, leading to greater strength and load carrying capacity. Decreasing
+		// the pressure angle provides lower backlash, smoother operation and less sensitivity to manufacturing errors. (reference: http://en.wikipedia.org/wiki/Involute_gear)
+		private double _pressureAngle = 20;
+
+		private int _toothCount = 30;
+
+		private double addendum;
+
+		private double angleToothToTooth;
+
+		private Vector2 center = Vector2.Zero;
+
+		private Gear2D connectedGear;
+
+		private double diametralPitch;
+
+		private double outerRadius;
+
+		private double pitchDiameter;
+
+		private double pitchRadius;
+
+		private double profileShift = 0;
+
+		private double shiftedAddendum;
+
+		private int stepsPerToothAngle = 10;
+
+		public Gear2D()
+		{
+			CalculateDependants();
+		}
+
+		public enum GearTypes
+		{
+			External,
+			Internal,
+			Rack
+		}
+
+		public double Backlash
+		{
+			get => _backlash;
+
+			set
+			{
+				_backlash = value;
+				CalculateDependants();
+			}
+		}
+
+		public double CenterHoleDiameter
+		{
+			get => _centerHoleDiameter;
+
+			set
+			{
+				_centerHoleDiameter = value;
+				CalculateDependants();
+			}
+		}

 		/// <summary>
 		/// Gets or sets distance from one face of a tooth to the corresponding face of an adjacent tooth on the same gear, measured along the pitch circle.
@@ -64,9 +131,6 @@
 			}
 		}

-		private double diametralPitch;
-		private double addendum;
-		private double _clearance = .05;
 		public double Clearance
 		{
 			get => _clearance;
@@ -78,10 +142,18 @@
 			}
 		}

-		// Most common stock gears have a 20° pressure angle, with 14½° and 25° pressure angle gears being much less
-		// common. Increasing the pressure angle increases the width of the base of the gear tooth, leading to greater strength and load carrying capacity. Decreasing
-		// the pressure angle provides lower backlash, smoother operation and less sensitivity to manufacturing errors. (reference: http://en.wikipedia.org/wiki/Involute_gear)
-		private double _pressureAngle = 20;
+		private GearTypes _gearType = GearTypes.External;
+		public GearTypes GearType
+		{
+			get => _gearType;
+
+			set
+			{
+				_gearType = value;
+				CalculateDependants();
+			}
+		}
+
 		public double PressureAngle
 		{
 			get => _pressureAngle;
@@ -93,23 +165,6 @@
 			}
 		}

-		private double _backlash = .05;
-		public double Backlash
-		{
-			get => _backlash;
-
-			set
-			{
-				_backlash = value;
-				CalculateDependants();
-			}
-		}
-		private double profileShift = 0;
-		private double shiftedAddendum;
-		private double outerRadius;
-		private double angleToothToTooth;
-
-		private int _toothCount = 30;
 		public int ToothCount
 		{
 			get => _toothCount;
@@ -121,317 +176,29 @@
 			}
 		}

-		private GearType gearType = GearType.External;
-		private int stepsPerToothAngle = 10;
-		private double pitchDiameter;
-		private double pitchRadius;
-		private Vector2 center = Vector2.Zero;
-		private Gear2D connectedGear;
-		private double _centerHoleDiameter = 4;
-		public double CenterHoleDiameter
-		{
-			get => _centerHoleDiameter;
-
-			set
-			{
-				_centerHoleDiameter = value;
-				CalculateDependants();
-			}
-		}
-
-		public enum GearType
-		{
-			External,
-			Internal,
-			Rack
-		}
-
-		public Gear2D()
-		{
-			CalculateDependants();
-		}
-
-		private void CalculateDependants()
-		{
-			// convert circular pitch to diametral pitch
-			this.diametralPitch = Math.PI / this.CircularPitch; // Ratio of the number of teeth to the pitch diameter
-																// this.circularPitch = Math.PI / this.diametralPitch;
-
-			this.center = Vector2.Zero; // center of the gear
-										// this.angle = 0; // angle in degrees of the complete gear (changes during rotation animation)
-
-			// Pitch diameter: Diameter of pitch circle.
-			this.pitchDiameter = this.ToothCount / this.diametralPitch;
-			this.pitchRadius = this.pitchDiameter / 2;
-
-			// Addendum: Radial distance from pitch circle to outside circle.
-			this.addendum = 1 / this.diametralPitch;
-
-			// Typically no profile shift is used meaning that this.shiftedAddendum = this.addendum
-			this.shiftedAddendum = this.addendum * (1 + this.profileShift);
-
-			// Outer Circle
-			this.outerRadius = this.pitchRadius + this.shiftedAddendum;
-			this.angleToothToTooth = 360.0 / this.ToothCount;
-		}
-
 		public override IEnumerable<VertexData> Vertices()
 		{
-			IVertexSource shape;
-			// shape = CreateRackShape();
-			shape = CreateRegularGearShape();
-			// shape = CreateInternalGearShape();
-			// shape = CreateSingleTooth().tooth;
-			// shape = CreateInternalGearShape();
+			IVertexSource shape = null;
+
+			switch (GearType)
+			{
+				case GearTypes.External:
+					shape = CreateExternalGearShape();
+					break;
+
+				case GearTypes.Internal:
+					shape = CreateInternalGearShape();
+					break;
+
+				case GearTypes.Rack:
+					shape = CreateRackShape();
+					break;
+			}

 			return shape.Vertices();
 		}

-		private IVertexSource CreateRackShape()
-		{
-			IVertexSource rack = new VertexStorage();
-
-			// we draw one tooth in the middle and then five on either side
-			for (var i = 0; i < ToothCount; i++)
-			{
-				var tooth = this.CreateRackTooth();
-				tooth = tooth.Translate(0, (0.5 + -ToothCount / 2 + i) * this.CircularPitch);
-				rack = rack.Union(tooth);
-			}
-
-			// creating the bar backing the teeth
-			var rightX = -(this.addendum + this.Clearance);
-			var width = 4 * this.addendum;
-			var halfHeight = ToothCount * this.CircularPitch / 2;
-			var bar = new RoundedRect(rightX - width, -halfHeight, rightX, halfHeight, 0);
-
-			var rackFinal = rack.Union(bar) as VertexStorage;
-			rackFinal.Translate(this.addendum * this.profileShift, 0);
-			return rackFinal;
-		}
-
-		private IVertexSource CreateRegularGearShape()
-		{
-			var tooth = this.CreateSingleTooth();
-
-			// we could now take the tooth cutout, rotate it tooth count times and union the various slices together into a complete gear.
-			// However, the union operations become more and more complex as the complete gear is built up.
-			// So instead we capture the outer path of the tooth and concatenate rotated versions of this path into a complete outer gear path.
-			// Concatenating paths is inexpensive resulting in significantly faster execution.
-			var outlinePaths = tooth.tooth;
-
-			// first we need to find the corner that sits at the center
-			for (var i = 1; i < this.ToothCount; i++)
-			{
-				var angle = i * this.angleToothToTooth;
-				var roatationMatrix = Affine.NewRotation(MathHelper.DegreesToRadians(angle));
-				var rotatedCorner = new VertexSourceApplyTransform(tooth.tooth, roatationMatrix);
-				outlinePaths = new CombinePaths(outlinePaths, rotatedCorner);
-			}
-
-			var gearShape = tooth.wheel.Subtract(outlinePaths);
-
-			if (this.CenterHoleDiameter > 0)
-			{
-				var radius = this.CenterHoleDiameter / 2;
-				var centerhole = new Ellipse(0, 0, radius, radius)
-				{
-					ResolutionScale = 10
-				};
-				gearShape = gearShape.Subtract(centerhole) as VertexStorage;
-			}
-
-			return gearShape;// .RotateZDegrees(-90);
-		}
-
-		private IVertexSource CreateInternalGearShape()
-		{
-			var singleTooth = this._createInternalToothProfile();
-			// return singleTooth;
-
-			var outlinePaths = singleTooth;
-			var corners = outlinePaths as VertexStorage;
-
-			// first we need to find the corner that sits at the center
-			var centerCornerIndex = 0;
-			var radius = this.pitchRadius + (1 + this.profileShift) * this.addendum + this.Clearance;
-
-			var delta = 0.0000001;
-			for (var i = 0; i < corners.Count; i++)
-			{
-				var corner = corners[i];
-				if (corner.Y < delta && (corner.X + radius) < delta)
-				{
-					centerCornerIndex = i;
-					break;
-				}
-			}
-
-			var outerCorners = new VertexStorage();
-			for (var i = 2; i < corners.Count - 2; i++)
-			{
-				var corner = corners[(i + centerCornerIndex) % corners.Count];
-				outerCorners.add(corner.position);
-			}
-
-			var reversedOuterCorners = new VertexStorage();
-			foreach (var vertex in new ReversePath(outerCorners).Vertices())
-			{
-				reversedOuterCorners.add(vertex.position);
-			}
-			outerCorners = reversedOuterCorners;
-
-			var cornersCount = outerCorners.Count;
-
-			for (var i = 1; i < this.ToothCount; i++)
-			{
-				var angle = i * this.angleToothToTooth;
-				var roatationMatrix = Affine.NewRotation(MathHelper.DegreesToRadians(angle));
-				for (var j = 0; j < cornersCount; j++)
-				{
-					var rotatedCorner = roatationMatrix.Transform(outerCorners[j].position);
-					outerCorners.add(rotatedCorner);
-				}
-			}
-
-			outerCorners = this._smoothConcaveCorners(outerCorners) as VertexStorage;
-
-			var innerRadius = this.pitchRadius + (1 - this.profileShift) * this.addendum + this.Clearance;
-			var outerRadius = innerRadius + 4 * this.addendum;
-			var outerCircle = new Ellipse(this.center, outerRadius, outerRadius);
-			// return outerCircle;
-
-			// return gearCutout;
-			return outerCircle.Subtract(outerCorners);
-		}
-
-		private IVertexSource CreateRackTooth()
-		{
-			var toothWidth = this.CircularPitch / 2;
-			var toothDepth = this.addendum + this.Clearance;
-
-			var sinPressureAngle = Math.Sin(this.PressureAngle * Math.PI / 180);
-			var cosPressureAngle = Math.Cos(this.PressureAngle * Math.PI / 180);
-
-			// if a positive backlash is defined then we widen the trapezoid accordingly.
-			// Each side of the tooth needs to widened by a fourth of the backlash (vertical to cutter faces).
-			var dx = this.Backlash / 4 / cosPressureAngle;
-
-			var leftDepth = this.addendum + this.Clearance;
-
-			var upperLeftCorner = new Vector2(-leftDepth, toothWidth / 2 - dx + (this.addendum + this.Clearance) * sinPressureAngle);
-			var upperRightCorner = new Vector2(this.addendum, toothWidth / 2 - dx - this.addendum * sinPressureAngle);
-			var lowerRightCorner = new Vector2(upperRightCorner[0], -upperRightCorner[1]);
-			var lowerLeftCorner = new Vector2(upperLeftCorner[0], -upperLeftCorner[1]);
-
-			var tooth = new VertexStorage();
-			tooth.MoveTo(upperLeftCorner);
-			tooth.LineTo(upperRightCorner);
-			tooth.LineTo(lowerRightCorner);
-			tooth.LineTo(lowerLeftCorner);
-
-			return tooth;
-		}
-
-		private (IVertexSource tooth, IVertexSource wheel) CreateSingleTooth()
-		{
-			// create outer circle sector covering one tooth
-			var toothSectorPath = new Arc(Vector2.Zero, new Vector2(this.outerRadius, this.outerRadius), MathHelper.DegreesToRadians(90), MathHelper.DegreesToRadians(90 - this.angleToothToTooth))
-			{
-				ResolutionScale = 10
-			};
-
-			var toothCutOut = CreateToothCutout();
-
-			return (toothCutOut, toothSectorPath);
-		}
-
-		private IVertexSource CreateToothCutout()
-		{
-			var angleToothToTooth = 360.0 / this.ToothCount;
-			var angleStepSize = this.angleToothToTooth / this.stepsPerToothAngle;
-
-			IVertexSource toothCutout = new VertexStorage();
-
-			var toothCutterShape = this.CreateToothCutter();
-			var bounds = toothCutterShape.GetBounds();
-			var lowerLeftCorner = new Vector2(bounds.Left, bounds.Bottom);
-
-			// To create the tooth profile we move the (virtual) infinite gear and then turn the resulting cutter position back.
-			// For illustration see http://lcamtuf.coredump.cx/gcnc/ch6/, section 'Putting it all together'
-			// We continue until the moved tooth cutter's lower left corner is outside of the outer circle of the gear.
-			// Going any further will no longer influence the shape of the tooth
-			var stepCounter = 0;
-			while (true)
-			{
-				var angle = stepCounter * angleStepSize;
-				var xTranslation = new Vector2(angle * Math.PI / 180 * this.pitchRadius, 0);
-
-				var movedLowerLeftCorner = lowerLeftCorner + xTranslation;
-				movedLowerLeftCorner = Vector2.Rotate(movedLowerLeftCorner, MathHelper.DegreesToRadians(angle));
-
-				if (movedLowerLeftCorner.Length > this.outerRadius)
-				{
-					// the cutter is now completely outside the gear and no longer influences the shape of the gear tooth
-					break;
-				}
-
-				// we move in both directions
-				var movedToothCutterShape = toothCutterShape.Translate(xTranslation);
-				movedToothCutterShape = movedToothCutterShape.RotateZDegrees(angle);
-				toothCutout = toothCutout.Union(movedToothCutterShape);
-
-				if (xTranslation[0] > 0)
-				{
-					movedToothCutterShape = toothCutterShape.Translate(new Vector2(-xTranslation[0], xTranslation[1]));
-					movedToothCutterShape = movedToothCutterShape.RotateZDegrees(-angle);
-					toothCutout = toothCutout.Union(movedToothCutterShape);
-				}
-
-				stepCounter++;
-			}
-
-			toothCutout = this._smoothConcaveCorners(toothCutout);
-
-			return toothCutout.RotateZDegrees(-this.angleToothToTooth / 2);
-		}
-
-		private IVertexSource CreateToothCutter()
-		{
-			// we create a trapezoidal cutter as described at http://lcamtuf.coredump.cx/gcnc/ch6/ under the section 'Putting it all together'
-			var toothWidth = this.CircularPitch / 2;
-
-			var cutterDepth = this.addendum + this.Clearance;
-			var cutterOutsideLength = 3 * this.addendum;
-
-			var sinPressureAngle = Math.Sin(this.PressureAngle * Math.PI / 180.0);
-			var cosPressureAngle = Math.Cos(this.PressureAngle * Math.PI / 180.0);
-
-			// if a positive backlash is defined then we widen the trapezoid accordingly.
-			// Each side of the tooth needs to widened by a fourth of the backlash (vertical to cutter faces).
-			var dx = this.Backlash / 2 / cosPressureAngle;
-
-			var lowerRightCorner = new Vector2(toothWidth / 2 + dx - cutterDepth * sinPressureAngle, this.pitchRadius + this.profileShift * this.addendum - cutterDepth);
-			var upperRightCorner = new Vector2(toothWidth / 2 + dx + cutterOutsideLength * sinPressureAngle, this.pitchRadius + this.profileShift * this.addendum + cutterOutsideLength);
-			var upperLeftCorner = new Vector2(-upperRightCorner[0], upperRightCorner[1]);
-			var lowerLeftCorner = new Vector2(-lowerRightCorner[0], lowerRightCorner[1]);
-
-			var cutterPath = new VertexStorage();
-			cutterPath.MoveTo(lowerLeftCorner);
-			cutterPath.LineTo(upperLeftCorner);
-			cutterPath.LineTo(upperRightCorner);
-			cutterPath.LineTo(lowerRightCorner);
-
-			return cutterPath;
-		}
-
-		private IVertexSource _smoothConvexCorners(IVertexSource corners)
-		{
-			// removes single convex corners located between concave corners
-			return this._smoothCorners(corners, true); // removeSingleConvex
-		}
-
-		private IVertexSource _createInternalToothCutter()
+		private IVertexSource CreateInternalToothCutter()
 		{
 			// To cut the internal gear teeth, the actual pinion comes close but we need to enlarge it so properly caters for clearance and backlash
 			var pinion = this.connectedGear;
@@ -452,7 +219,7 @@
 			return tooth.tooth.RotateZDegrees(90 + 180 / enlargedPinion.ToothCount); // we need a tooth pointing to the left
 		}

-		private IVertexSource _createInternalToothProfile()
+		private IVertexSource CreateInternalToothProfile()
 		{
 			var radius = this.pitchRadius + (1 - this.profileShift) * this.addendum + this.Clearance;
 			var angleToothToTooth = 360 / this.ToothCount;
@@ -474,7 +241,7 @@

 			var sector = fullSector.Subtract(innerCircle);

-			var cutterTemplate = this._createInternalToothCutter();
+			var cutterTemplate = this.CreateInternalToothCutter();

 			var pinion = this.connectedGear;
 			var stepsPerTooth = this.stepsPerToothAngle;
@@ -505,14 +272,19 @@
 			return toothShape;
 		}

-
-		private IVertexSource _smoothConcaveCorners(IVertexSource corners)
+		private IVertexSource SmoothConcaveCorners(IVertexSource corners)
 		{
 			// removes single concave corners located between convex corners
-			return this._smoothCorners(corners, false); // removeSingleConvex
-		}
-
-		private IVertexSource _smoothCorners(IVertexSource corners_in, bool removeSingleConvex)
+			return this.SmoothCorners(corners, false); // removeSingleConvex
+		}
+
+		private IVertexSource SmoothConvexCorners(IVertexSource corners)
+		{
+			// removes single convex corners located between concave corners
+			return this.SmoothCorners(corners, true); // removeSingleConvex
+		}
+
+		private IVertexSource SmoothCorners(IVertexSource corners_in, bool removeSingleConvex)
 		{
 			var corners = corners_in as VertexStorage;
 			var isConvex = new List<bool>();
@@ -561,39 +333,302 @@

 			return cleanedUpCorners;
 		}
+
+		private void CalculateDependants()
+		{
+			// convert circular pitch to diametral pitch
+			this.diametralPitch = Math.PI / this.CircularPitch; // Ratio of the number of teeth to the pitch diameter
+																// this.circularPitch = Math.PI / this.diametralPitch;
+
+			this.center = Vector2.Zero; // center of the gear
+										// this.angle = 0; // angle in degrees of the complete gear (changes during rotation animation)
+
+			// Pitch diameter: Diameter of pitch circle.
+			this.pitchDiameter = this.ToothCount / this.diametralPitch;
+			this.pitchRadius = this.pitchDiameter / 2;
+
+			// Addendum: Radial distance from pitch circle to outside circle.
+			this.addendum = 1 / this.diametralPitch;
+
+			// Typically no profile shift is used meaning that this.shiftedAddendum = this.addendum
+			this.shiftedAddendum = this.addendum * (1 + this.profileShift);
+
+			// Outer Circle
+			this.outerRadius = this.pitchRadius + this.shiftedAddendum;
+			this.angleToothToTooth = 360.0 / this.ToothCount;
+		}
+
+		private IVertexSource CreateInternalGearShape()
+		{
+			var singleTooth = this.CreateInternalToothProfile();
+			// return singleTooth;
+
+			var outlinePaths = singleTooth;
+			var corners = outlinePaths as VertexStorage;
+
+			// first we need to find the corner that sits at the center
+			var centerCornerIndex = 0;
+			var radius = this.pitchRadius + (1 + this.profileShift) * this.addendum + this.Clearance;
+
+			var delta = 0.0000001;
+			for (var i = 0; i < corners.Count; i++)
+			{
+				var corner = corners[i];
+				if (corner.Y < delta && (corner.X + radius) < delta)
+				{
+					centerCornerIndex = i;
+					break;
+				}
+			}
+
+			var outerCorners = new VertexStorage();
+			for (var i = 2; i < corners.Count - 2; i++)
+			{
+				var corner = corners[(i + centerCornerIndex) % corners.Count];
+				outerCorners.add(corner.position);
+			}
+
+			var reversedOuterCorners = new VertexStorage();
+			foreach (var vertex in new ReversePath(outerCorners).Vertices())
+			{
+				reversedOuterCorners.add(vertex.position);
+			}
+
+			outerCorners = reversedOuterCorners;
+
+			var cornersCount = outerCorners.Count;
+
+			for (var i = 1; i < this.ToothCount; i++)
+			{
+				var angle = i * this.angleToothToTooth;
+				var roatationMatrix = Affine.NewRotation(MathHelper.DegreesToRadians(angle));
+				for (var j = 0; j < cornersCount; j++)
+				{
+					var rotatedCorner = roatationMatrix.Transform(outerCorners[j].position);
+					outerCorners.add(rotatedCorner);
+				}
+			}
+
+			outerCorners = this.SmoothConcaveCorners(outerCorners) as VertexStorage;
+
+			var innerRadius = this.pitchRadius + (1 - this.profileShift) * this.addendum + this.Clearance;
+			var outerRadius = innerRadius + 4 * this.addendum;
+			var outerCircle = new Ellipse(this.center, outerRadius, outerRadius);
+			// return outerCircle;
+
+			// return gearCutout;
+			return outerCircle.Subtract(outerCorners);
+		}
+
+		private IVertexSource CreateRackShape()
+		{
+			IVertexSource rack = new VertexStorage();
+
+			// we draw one tooth in the middle and then five on either side
+			for (var i = 0; i < ToothCount; i++)
+			{
+				var tooth = this.CreateRackTooth();
+				tooth = tooth.Translate(0, (0.5 + -ToothCount / 2 + i) * this.CircularPitch);
+				rack = rack.Union(tooth);
+			}
+
+			// creating the bar backing the teeth
+			var rightX = -(this.addendum + this.Clearance);
+			var width = 4 * this.addendum;
+			var halfHeight = ToothCount * this.CircularPitch / 2;
+			var bar = new RoundedRect(rightX - width, -halfHeight, rightX, halfHeight, 0);
+
+			var rackFinal = rack.Union(bar) as VertexStorage;
+			rackFinal.Translate(this.addendum * this.profileShift, 0);
+			return rackFinal;
+		}
+
+		private IVertexSource CreateRackTooth()
+		{
+			var toothWidth = this.CircularPitch / 2;
+			var toothDepth = this.addendum + this.Clearance;
+
+			var sinPressureAngle = Math.Sin(this.PressureAngle * Math.PI / 180);
+			var cosPressureAngle = Math.Cos(this.PressureAngle * Math.PI / 180);
+
+			// if a positive backlash is defined then we widen the trapezoid accordingly.
+			// Each side of the tooth needs to widened by a fourth of the backlash (vertical to cutter faces).
+			var dx = this.Backlash / 4 / cosPressureAngle;
+
+			var leftDepth = this.addendum + this.Clearance;
+
+			var upperLeftCorner = new Vector2(-leftDepth, toothWidth / 2 - dx + (this.addendum + this.Clearance) * sinPressureAngle);
+			var upperRightCorner = new Vector2(this.addendum, toothWidth / 2 - dx - this.addendum * sinPressureAngle);
+			var lowerRightCorner = new Vector2(upperRightCorner[0], -upperRightCorner[1]);
+			var lowerLeftCorner = new Vector2(upperLeftCorner[0], -upperLeftCorner[1]);
+
+			var tooth = new VertexStorage();
+			tooth.MoveTo(upperLeftCorner);
+			tooth.LineTo(upperRightCorner);
+			tooth.LineTo(lowerRightCorner);
+			tooth.LineTo(lowerLeftCorner);
+
+			return tooth;
+		}
+
+		private IVertexSource CreateExternalGearShape()
+		{
+			var tooth = this.CreateSingleTooth();
+
+			// we could now take the tooth cutout, rotate it tooth count times and union the various slices together into a complete gear.
+			// However, the union operations become more and more complex as the complete gear is built up.
+			// So instead we capture the outer path of the tooth and concatenate rotated versions of this path into a complete outer gear path.
+			// Concatenating paths is inexpensive resulting in significantly faster execution.
+			var outlinePaths = tooth.tooth;
+
+			// first we need to find the corner that sits at the center
+			for (var i = 1; i < this.ToothCount; i++)
+			{
+				var angle = i * this.angleToothToTooth;
+				var roatationMatrix = Affine.NewRotation(MathHelper.DegreesToRadians(angle));
+				var rotatedCorner = new VertexSourceApplyTransform(tooth.tooth, roatationMatrix);
+				outlinePaths = new CombinePaths(outlinePaths, rotatedCorner);
+			}
+
+			var gearShape = tooth.wheel.Subtract(outlinePaths);
+
+			if (this.CenterHoleDiameter > 0)
+			{
+				var radius = this.CenterHoleDiameter / 2;
+				var centerhole = new Ellipse(0, 0, radius, radius)
+				{
+					ResolutionScale = 10
+				};
+				gearShape = gearShape.Subtract(centerhole) as VertexStorage;
+			}
+
+			return gearShape; // .RotateZDegrees(-90);
+		}
+
+		private (IVertexSource tooth, IVertexSource wheel) CreateSingleTooth()
+		{
+			// create outer circle sector covering one tooth
+			var toothSectorPath = new Arc(Vector2.Zero, new Vector2(this.outerRadius, this.outerRadius), MathHelper.DegreesToRadians(90), MathHelper.DegreesToRadians(90 - this.angleToothToTooth))
+			{
+				ResolutionScale = 10
+			};
+
+			var toothCutOut = CreateToothCutout();
+
+			return (toothCutOut, toothSectorPath);
+		}
+
+		private IVertexSource CreateToothCutout()
+		{
+			var angleToothToTooth = 360.0 / this.ToothCount;
+			var angleStepSize = this.angleToothToTooth / this.stepsPerToothAngle;
+
+			IVertexSource toothCutout = new VertexStorage();
+
+			var toothCutterShape = this.CreateToothCutter();
+			var bounds = toothCutterShape.GetBounds();
+			var lowerLeftCorner = new Vector2(bounds.Left, bounds.Bottom);
+
+			// To create the tooth profile we move the (virtual) infinite gear and then turn the resulting cutter position back.
+			// For illustration see http://lcamtuf.coredump.cx/gcnc/ch6/, section 'Putting it all together'
+			// We continue until the moved tooth cutter's lower left corner is outside of the outer circle of the gear.
+			// Going any further will no longer influence the shape of the tooth
+			var stepCounter = 0;
+			while (true)
+			{
+				var angle = stepCounter * angleStepSize;
+				var xTranslation = new Vector2(angle * Math.PI / 180 * this.pitchRadius, 0);
+
+				var movedLowerLeftCorner = lowerLeftCorner + xTranslation;
+				movedLowerLeftCorner = Vector2.Rotate(movedLowerLeftCorner, MathHelper.DegreesToRadians(angle));
+
+				if (movedLowerLeftCorner.Length > this.outerRadius)
+				{
+					// the cutter is now completely outside the gear and no longer influences the shape of the gear tooth
+					break;
+				}
+
+				// we move in both directions
+				var movedToothCutterShape = toothCutterShape.Translate(xTranslation);
+				movedToothCutterShape = movedToothCutterShape.RotateZDegrees(angle);
+				toothCutout = toothCutout.Union(movedToothCutterShape);
+
+				if (xTranslation[0] > 0)
+				{
+					movedToothCutterShape = toothCutterShape.Translate(new Vector2(-xTranslation[0], xTranslation[1]));
+					movedToothCutterShape = movedToothCutterShape.RotateZDegrees(-angle);
+					toothCutout = toothCutout.Union(movedToothCutterShape);
+				}
+
+				stepCounter++;
+			}
+
+			toothCutout = this.SmoothConcaveCorners(toothCutout);
+
+			return toothCutout.RotateZDegrees(-this.angleToothToTooth / 2);
+		}
+
+		private IVertexSource CreateToothCutter()
+		{
+			// we create a trapezoidal cutter as described at http://lcamtuf.coredump.cx/gcnc/ch6/ under the section 'Putting it all together'
+			var toothWidth = this.CircularPitch / 2;
+
+			var cutterDepth = this.addendum + this.Clearance;
+			var cutterOutsideLength = 3 * this.addendum;
+
+			var sinPressureAngle = Math.Sin(this.PressureAngle * Math.PI / 180.0);
+			var cosPressureAngle = Math.Cos(this.PressureAngle * Math.PI / 180.0);
+
+			// if a positive backlash is defined then we widen the trapezoid accordingly.
+			// Each side of the tooth needs to widened by a fourth of the backlash (vertical to cutter faces).
+			var dx = this.Backlash / 2 / cosPressureAngle;
+
+			var lowerRightCorner = new Vector2(toothWidth / 2 + dx - cutterDepth * sinPressureAngle, this.pitchRadius + this.profileShift * this.addendum - cutterDepth);
+			var upperRightCorner = new Vector2(toothWidth / 2 + dx + cutterOutsideLength * sinPressureAngle, this.pitchRadius + this.profileShift * this.addendum + cutterOutsideLength);
+			var upperLeftCorner = new Vector2(-upperRightCorner[0], upperRightCorner[1]);
+			var lowerLeftCorner = new Vector2(-lowerRightCorner[0], lowerRightCorner[1]);
+
+			var cutterPath = new VertexStorage();
+			cutterPath.MoveTo(lowerLeftCorner);
+			cutterPath.LineTo(upperLeftCorner);
+			cutterPath.LineTo(upperRightCorner);
+			cutterPath.LineTo(lowerRightCorner);
+
+			return cutterPath;
+		}
 	}
 }

 public static class Extensions
 {
+	public static IVertexSource Minus(this IVertexSource a, IVertexSource b)
+	{
+		return CombinePaths(a, b, ClipType.ctDifference);
+	}
+
+	public static IVertexSource Plus(this IVertexSource a, IVertexSource b)
+	{
+		return CombinePaths(a, b, ClipType.ctUnion);
+	}
+
+	public static IVertexSource RotateZDegrees(this IVertexSource a, double angle)
+	{
+		return new VertexSourceApplyTransform(a, Affine.NewRotation(MathHelper.DegreesToRadians(angle)));
+	}
+
 	public static IVertexSource Subtract(this IVertexSource a, IVertexSource b)
 	{
 		return a.Minus(b);
 	}

+	public static IVertexSource Translate(this IVertexSource a, Vector2 delta)
+	{
+		return new VertexSourceApplyTransform(a, Affine.NewTranslation(delta));
+	}
+
 	public static IVertexSource Union(this IVertexSource a, IVertexSource b)
 	{
 		return a.Plus(b);
-	}
-
-	public static IVertexSource RotateZDegrees(this IVertexSource a, double angle)
-	{
-		return new VertexSourceApplyTransform(a, Affine.NewRotation(MathHelper.DegreesToRadians(angle)));
-	}
-
-	public static IVertexSource Translate(this IVertexSource a, Vector2 delta)
-	{
-		return new VertexSourceApplyTransform(a, Affine.NewTranslation(delta));
-	}
-
-	public static IVertexSource Minus(this IVertexSource a, IVertexSource b)
-	{
-		return CombinePaths(a, b, ClipType.ctDifference);
-	}
-
-	public static IVertexSource Plus(this IVertexSource a, IVertexSource b)
-	{
-		return CombinePaths(a, b, ClipType.ctUnion);
 	}

 	private static VertexStorage CombinePaths(IVertexSource a, IVertexSource b, ClipType clipType)


Only move to enabled stages

Only move to enabled stages

- Issue MatterHackers/MCCentral#5279
Staged wizard next button advances to stage which is not active

--- MatterControlLib/SetupWizard/StagedSetupWindow.cs
+++ MatterControlLib/SetupWizard/StagedSetupWindow.cs
@@ -157,7 +157,7 @@

 		public void NextIncompleteStage()
 		{
-			ISetupWizard nextStage = setupWizard.Stages.FirstOrDefault(s => s.SetupRequired);
+			ISetupWizard nextStage = setupWizard.Stages.FirstOrDefault(s => s.SetupRequired && s.Enabled);

 			if (nextStage != null)
 			{


Add SearchPattern.Normalize method

Add SearchPattern.Normalize method

--- src/Zio/SearchPattern.cs
+++ src/Zio/SearchPattern.cs
@@ -36,6 +36,11 @@
         public static SearchPattern Parse(ref UPath path, ref string searchPattern)
         {
             return new SearchPattern(ref path, ref searchPattern);
+        }
+
+        public static void Normalize(ref UPath path, ref string searchPattern)
+        {
+            Parse(ref path, ref searchPattern);
         }

         private SearchPattern(ref UPath path, ref string searchPattern)


Fix Uwp typo

Fix Uwp typo

--- NET/API/Treehopper.UWP/Properties/AssemblyInfo.cs
+++ NET/API/Treehopper.UWP/Properties/AssemblyInfo.cs
@@ -4,7 +4,7 @@
 // General Information about an assembly is controlled through the following
 // set of attributes. Change these attribute values to modify the information
 // associated with an assembly.
-[assembly: AssemblyTitle("Treehopper.UWP")]
+[assembly: AssemblyTitle("Treehopper.Uwp")]
 [assembly: AssemblyDescription("")]
 [assembly: AssemblyConfiguration("")]
 [assembly: AssemblyCompany("")]


Fixed the sun position to be TZ-relative to UTC but (and) unaffected by DST. Fixes Mantis 1863.

--- OpenSim/Region/CoreModules/World/Sun/SunModule.cs
+++ OpenSim/Region/CoreModules/World/Sun/SunModule.cs
@@ -135,21 +135,17 @@

         private const int TICKS_PER_SECOND = 10000000;

-
-
         // Current time in elapsed seconds since Jan 1st 1970
         private ulong CurrentTime
         {
             get
             {
-                return (ulong)(((DateTime.Now.Ticks) - TicksToEpoch + TicksUTCOffset) / TICKS_PER_SECOND);
+                return (ulong)(((DateTime.UtcNow.Ticks) - TicksToEpoch + TicksUTCOffset) / TICKS_PER_SECOND);
             }
         }

         // Time in seconds since UTC to use to calculate sun position.
         ulong PosTime = 0;
-
-

         /// <summary>
         /// Calculate the sun's orbital position and its velocity.
@@ -297,11 +293,8 @@
                 m_scene.AddCommand(this, String.Format("sun {0}", kvp.Key), String.Format("{0} - {1}", kvp.Key, kvp.Value), String.Empty, HandleSunConsoleCommand);
             }

-
-
-            TimeZone local = TimeZone.CurrentTimeZone;
-            TicksUTCOffset = local.GetUtcOffset(local.ToLocalTime(DateTime.Now)).Ticks;
-            m_log.Debug("[SUN]: localtime offset is " + TicksUTCOffset);
+            // Use a fixed offset from UTC for Pacific time with no DST changes. Must be a specific unchanging offset, could be 0.
+            TicksUTCOffset = -288000000000; // -8 * 60 * 60 * TICKS_PER_SECOND

             // Align ticks with Second Life


Always return a reason when logging in.

Always return a reason when logging in.

--- OpenSim/Services/LLLoginService/LLLoginService.cs
+++ OpenSim/Services/LLLoginService/LLLoginService.cs
@@ -1072,6 +1072,8 @@
                             success = TryFindGridRegionForAgentLogin(safeRegions, account,
                                 appearance, session, secureSession, circuitCode, position,
                                 clientIP, aCircuit, out dest);
+                            if (!success)
+                                reason = "No Region Found";
                         }
                     }
                 }


Whitespace fixes

Whitespace fixes

--- PART/Source/CprBroker/DBR/CprConverter.Lookups.cs
+++ PART/Source/CprBroker/DBR/CprConverter.Lookups.cs
@@ -1,115 +1,115 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.IO;
-using System.Data.SqlClient;
-using CprBroker.Providers.DPR;
-using CprBroker.Providers.CPRDirect;
-using CprBroker.DBR.Extensions;
-
-namespace CprBroker.DBR
-{
-    public partial class CprConverter
-    {
-        public static Dictionary<string, string> SplitFile(string path)
-        {
-            var ret = new Dictionary<string, string>();
-            var streams = new Dictionary<string, StreamWriter>();
-
-            using (var source = new System.IO.StreamReader(path, Encoding.GetEncoding(1252)))
-            {
-                while (!source.EndOfStream)
-                {
-                    int batchSize = 100;
-                    var wrappers = CprBroker.Providers.CPRDirect.CompositeWrapper.Parse(source, CprBroker.Providers.CPRDirect.Constants.DataObjectMap_P05780, batchSize);
-
-                    foreach (var w in wrappers)
-                    {
-                        var code = w.Contents.Substring(0, 3);
-                        StreamWriter target;
-                        if (streams.ContainsKey(code))
-                        {
-                            target = streams[code];
-                        }
-                        else
-                        {
-                            var fileName = string.Format("{0}-{1}-{2}.txt", path, code, w.GetType().Name);
-                            target = new StreamWriter(fileName, false, Encoding.GetEncoding(1252));
-                            streams[code] = target;
-                            ret[code] = fileName;
-                        }
-                        target.Write(w.Contents);
-                    }
-                }
-            }
-            foreach (var kvp in streams)
-            {
-                kvp.Value.Close();
-            }
-            return ret;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.IO;
+using System.Data.SqlClient;
+using CprBroker.Providers.DPR;
+using CprBroker.Providers.CPRDirect;
+using CprBroker.DBR.Extensions;
+
+namespace CprBroker.DBR
+{
+    public partial class CprConverter
+    {
+        public static Dictionary<string, string> SplitFile(string path)
+        {
+            var ret = new Dictionary<string, string>();
+            var streams = new Dictionary<string, StreamWriter>();
+
+            using (var source = new System.IO.StreamReader(path, Encoding.GetEncoding(1252)))
+            {
+                while (!source.EndOfStream)
+                {
+                    int batchSize = 100;
+                    var wrappers = CprBroker.Providers.CPRDirect.CompositeWrapper.Parse(source, CprBroker.Providers.CPRDirect.Constants.DataObjectMap_P05780, batchSize);
+
+                    foreach (var w in wrappers)
+                    {
+                        var code = w.Contents.Substring(0, 3);
+                        StreamWriter target;
+                        if (streams.ContainsKey(code))
+                        {
+                            target = streams[code];
+                        }
+                        else
+                        {
+                            var fileName = string.Format("{0}-{1}-{2}.txt", path, code, w.GetType().Name);
+                            target = new StreamWriter(fileName, false, Encoding.GetEncoding(1252));
+                            streams[code] = target;
+                            ret[code] = fileName;
+                        }
+                        target.Write(w.Contents);
+                    }
+                }
+            }
+            foreach (var kvp in streams)
+            {
+                kvp.Value.Close();
+            }
+            return ret;
         }

-        public static int ImportLookups(string fileName, int batchSize, Encoding encoding, string dprConnectionString, Dictionary<string, Type> objectMap)
-        {
-            var ret = 0;
-
-            var fileMap = SplitFile(fileName);
-
-            var extensionType = typeof(CprConverterExtensions);
-            foreach (var kvp in fileMap)
-            {
-                // Init type parameters
-                var typeKey = kvp.Key;
-                var typeFile = kvp.Value;
-                var sourceType = objectMap[kvp.Key];
-                var method = extensionType.GetMethods().Where(m =>
-                    {
-                        var pars = m.GetParameters();
-                        return pars.Length == 1 && pars.Where(p => p.ParameterType.Equals(sourceType)).Count() == 1;
-                    }).SingleOrDefault();
-                if (method != null)
-                {
-                    var targetType = method.ReturnType;
-                    Converter<object, object> converter = (o) => method.Invoke(o, new object[] { o });
-
-                    // Call batch conversion and insertion
-                    ret += ImportLookup(typeFile, targetType, batchSize, encoding, dprConnectionString, converter, objectMap);
-                }
-            }
-            return ret;
-        }
-
-        public static int ImportLookup(string fileName, Type targetType, int batchSize, Encoding encoding, string dprConnectionString,
-            Converter<object, object> func, Dictionary<string, Type> objectMap)
-        {
-            int totalReadLinesCount = 0;
-            var tableName = Utilities.DataLinq.GetTableName(targetType);
-
-            using (var file = new StreamReader(fileName, encoding))
-            {
-                using (var conn = new SqlConnection(dprConnectionString))
-                {
-                    conn.Open();
-                    using(var cmd = new SqlCommand(string.Format("truncate table [{0}];",tableName),conn))
-                    {
-                        cmd.ExecuteNonQuery();
-                    }
-
-                    // Start reading the file
-                    while (!file.EndOfStream)
-                    {
-                        var wrappers = CompositeWrapper.Parse(file, objectMap, batchSize);
-                        var batchReadLinesCount = wrappers.Count;
-
-                        var dprObjects = wrappers.Select(w => func(w)).ToArray();
-
-                        conn.BulkInsertAll(targetType, dprObjects);
-                        totalReadLinesCount += batchReadLinesCount;
-                    }
-                }
-            }
-            return totalReadLinesCount;
-        }
-    }
-}
+        public static int ImportLookups(string fileName, int batchSize, Encoding encoding, string dprConnectionString, Dictionary<string, Type> objectMap)
+        {
+            var ret = 0;
+
+            var fileMap = SplitFile(fileName);
+
+            var extensionType = typeof(CprConverterExtensions);
+            foreach (var kvp in fileMap)
+            {
+                // Init type parameters
+                var typeKey = kvp.Key;
+                var typeFile = kvp.Value;
+                var sourceType = objectMap[kvp.Key];
+                var method = extensionType.GetMethods().Where(m =>
+                    {
+                        var pars = m.GetParameters();
+                        return pars.Length == 1 && pars.Where(p => p.ParameterType.Equals(sourceType)).Count() == 1;
+                    }).SingleOrDefault();
+                if (method != null)
+                {
+                    var targetType = method.ReturnType;
+                    Converter<object, object> converter = (o) => method.Invoke(o, new object[] { o });
+
+                    // Call batch conversion and insertion
+                    ret += ImportLookup(typeFile, targetType, batchSize, encoding, dprConnectionString, converter, objectMap);
+                }
+            }
+            return ret;
+        }
+
+        public static int ImportLookup(string fileName, Type targetType, int batchSize, Encoding encoding, string dprConnectionString,
+            Converter<object, object> func, Dictionary<string, Type> objectMap)
+        {
+            int totalReadLinesCount = 0;
+            var tableName = Utilities.DataLinq.GetTableName(targetType);
+
+            using (var file = new StreamReader(fileName, encoding))
+            {
+                using (var conn = new SqlConnection(dprConnectionString))
+                {
+                    conn.Open();
+                    using (var cmd = new SqlCommand(string.Format("truncate table [{0}];", tableName), conn))
+                    {
+                        cmd.ExecuteNonQuery();
+                    }
+
+                    // Start reading the file
+                    while (!file.EndOfStream)
+                    {
+                        var wrappers = CompositeWrapper.Parse(file, objectMap, batchSize);
+                        var batchReadLinesCount = wrappers.Count;
+
+                        var dprObjects = wrappers.Select(w => func(w)).ToArray();
+
+                        conn.BulkInsertAll(targetType, dprObjects);
+                        totalReadLinesCount += batchReadLinesCount;
+                    }
+                }
+            }
+            return totalReadLinesCount;
+        }
+    }
+}