Added HproseFormatter for .NET MF

Added HproseFormatter for .NET MF

--- src/Hprose/IO/HproseFormatter.cs
+++ src/Hprose/IO/HproseFormatter.cs
@@ -12,7 +12,7 @@
  *                                                        *
  * hprose formatter class for C#.                         *
  *                                                        *
- * LastModified: Apr 11, 2011                             *
+ * LastModified: Jan 21, 2016                             *
  * Author: Ma Bingyao <andot@hprose.com>                  *
  *                                                        *
 \**********************************************************/
@@ -26,16 +26,12 @@

 namespace Hprose.IO {
     public sealed class HproseFormatter {
+#if dotNETMF
+        [CLSCompliantAttribute(false)]
+#endif
         public static MemoryStream Serialize(object obj) {
             MemoryStream stream = new MemoryStream();
             HproseWriter writer = new HproseWriter(stream);
-            writer.Serialize(obj);
-            return stream;
-        }
-
-        public static MemoryStream Serialize(object obj, HproseMode mode) {
-            MemoryStream stream = new MemoryStream();
-            HproseWriter writer = new HproseWriter(stream, mode);
             writer.Serialize(obj);
             return stream;
         }
@@ -45,15 +41,39 @@
             writer.Serialize(obj);
         }

+        public static object Unserialize(byte[] data) {
+            MemoryStream stream = new MemoryStream(data);
+            HproseReader reader = new HproseReader(stream);
+            return reader.Unserialize();
+        }
+
+        public static object Unserialize(byte[] data, Type type) {
+            MemoryStream stream = new MemoryStream(data);
+            HproseReader reader = new HproseReader(stream);
+            return reader.Unserialize(type);
+        }
+
+        public static object Unserialize(Stream stream) {
+            HproseReader reader = new HproseReader(stream);
+            return reader.Unserialize();
+        }
+
+        public static object Unserialize(Stream stream, Type type) {
+            HproseReader reader = new HproseReader(stream);
+            return reader.Unserialize(type);
+        }
+
+#if !dotNETMF
+        public static MemoryStream Serialize(object obj, HproseMode mode) {
+            MemoryStream stream = new MemoryStream();
+            HproseWriter writer = new HproseWriter(stream, mode);
+            writer.Serialize(obj);
+            return stream;
+        }
+
         public static void Serialize(object obj, Stream stream, HproseMode mode) {
             HproseWriter writer = new HproseWriter(stream, mode);
             writer.Serialize(obj);
-        }
-
-        public static object Unserialize(byte[] data) {
-                MemoryStream stream = new MemoryStream(data);
-            HproseReader reader = new HproseReader(stream);
-            return reader.Unserialize();
         }

         public static object Unserialize(byte[] data, HproseMode mode) {
@@ -68,11 +88,6 @@
             return reader.Unserialize(type);
         }

-        public static object Unserialize(Stream stream) {
-            HproseReader reader = new HproseReader(stream);
-            return reader.Unserialize();
-        }
-
         public static object Unserialize(Stream stream, HproseMode mode) {
             HproseReader reader = new HproseReader(stream, mode);
             return reader.Unserialize();
@@ -82,8 +97,9 @@
             HproseReader reader = new HproseReader(stream, mode);
             return reader.Unserialize(type);
         }
+#endif

-#if !(dotNET10 || dotNET11 || dotNETCF10)
+#if !(dotNET10 || dotNET11 || dotNETCF10 || dotNETMF)
         public static T Unserialize<T>(byte[] data) {
             MemoryStream stream = new MemoryStream(data);
             HproseReader reader = new HproseReader(stream);


Fix a IntPtr that should be a void*

Fix a IntPtr that should be a void*

--- src/Kernel32.Desktop/Kernel32.cs
+++ src/Kernel32.Desktop/Kernel32.cs
@@ -1666,7 +1666,7 @@
         ///     otherwise, it is NULL.
         /// </returns>
         [DllImport(nameof(Kernel32), SetLastError = true)]
-        public static extern IntPtr LockResource(IntPtr hResData);
+        public static unsafe extern void* LockResource(IntPtr hResData);

         /// <summary>Retrieves the size, in bytes, of the specified resource.</summary>
         /// <param name="hModule">A handle to the module whose executable file contains the resource.</param>


constructor initialized fields should be readonly

or at least these ones should since they don't change

--- src/Messaging/MessageHandlers.cs
+++ src/Messaging/MessageHandlers.cs
@@ -13,7 +13,7 @@

     internal class MessageHandler<TMessage> : IMessageHandler
     {
-        private Action<TMessage> _handler;
+        private readonly Action<TMessage> _handler;

         public MessageHandler(Action<TMessage> handler)
         {
@@ -31,13 +31,12 @@

     public class MessageHandlers
     {
-        private List<IMessageHandler> _messageHandlers = new List<IMessageHandler>();
+        private readonly List<IMessageHandler> _messageHandlers = new List<IMessageHandler>();

         internal MessageHandlers() { }

         public void Add<TMessage>(Action<TMessage> handler)
         {
-            var messageType = typeof(TMessage);
             // TODO: switch this around so we're not creating an instance if we don't have to
             var messageHandler = new MessageHandler<TMessage>(handler);
             lock (_messageHandlers)


Add a bit more logging where the profiler API is loaded from

--- src/PerfView/CommandProcessor.cs
+++ src/PerfView/CommandProcessor.cs
@@ -2017,6 +2017,8 @@
                 log.WriteLine("ERROR do not have a ETWClrProfiler.dll for architecture {0}", SupportFiles.ProcessArch);
                 return;
             }
+            log.WriteLine("Profiler DLL to load is {0}", profilerDll);
+

             log.WriteLine(@"Adding HKLM\Software\Microsoft\.NETFramework\COR* registry keys");
             using (RegistryKey key = Registry.LocalMachine.CreateSubKey(s_dotNetKey))


連結格式修正

連結格式修正

--- src/SharpMarkdown/Inline/Link.cs
+++ src/SharpMarkdown/Inline/Link.cs
@@ -8,7 +8,7 @@

 namespace SharpMarkdown.Inline {
     [Match(Regex = @"^\[.+\]\s*\[.+\]")]
-    [Match(Regex = @"\[.+\]\s*\(.+\)")]
+    [Match(Regex = @"^\[.+\]\s*\(.+\)")]
     public class Link : Content {
         /// <summary>
         /// 文字
@@ -31,7 +31,7 @@
                 if (string.IsNullOrWhiteSpace(URL)) {
                     result += $"[{ReferenceTag.Id}]";
                 } else {
-                    result += $"[{URL}]";
+                    result += $"({URL})";
                 }
                 return result;
             }
@@ -42,14 +42,14 @@

         public static Link Parse(string text,out int length ) {
             try {
-                Regex tagLink = new Regex(@"\[.+\]\s*\[.+\]");
-                Regex urlLink = new Regex(@"\[.+\]\s*\(.+\)");
+                Regex tagLink = new Regex(@"\[[^\]]+\]\s*\[[^\]]+\]");
+                Regex urlLink = new Regex(@"\[[^\]]+\]\s*\([^\)]+\)");

-                string linkText =
-                    tagLink.Match(text)?.Value ??
+                string linkText = tagLink.IsMatch(text) ?
+                    tagLink.Match(text)?.Value :
                     urlLink.Match(text)?.Value;

-                Regex t1Regex = new Regex(@"\[.+\]");
+                Regex t1Regex = new Regex(@"\[[^\]]+\]");
                 Regex t2Regex = new Regex(@"\(.+\)");
                 Link result = new Link();
                 result.Text = t1Regex.Match(linkText).Value;
@@ -71,7 +71,7 @@
                     length = match.Index + match.Length;
                 }
                 return result;
-            }catch {
+            }catch(Exception e) {
                 throw new FormatException();
             }
         }


add TryParse

add TryParse

--- src/TurkishId/TurkishIdNumber.cs
+++ src/TurkishId/TurkishIdNumber.cs
@@ -16,6 +16,7 @@
 // </copyright>

 using System;
+using System.Diagnostics.CodeAnalysis;
 using System.Runtime.CompilerServices;

 namespace TurkishId
@@ -45,6 +46,21 @@
         }

         /// <summary>
+        /// Initializes a new instance of the <see cref="TurkishIdNumber"/> class using a validated number.
+        /// </summary>
+        /// <param name="number">Input text.</param>
+        /// <param name="alreadyValidated">Must be true.</param>
+        private TurkishIdNumber(string number, bool alreadyValidated)
+        {
+            if (!alreadyValidated)
+            {
+                throw new ArgumentException("Value must be already validated", nameof(alreadyValidated));
+            }
+
+            Value = number;
+        }
+
+        /// <summary>
         /// Gets the value of ID number.
         /// </summary>
         public string Value { get; }
@@ -56,6 +72,26 @@
         public static implicit operator string(TurkishIdNumber instance)
         {
             return instance?.Value ?? string.Empty;
+        }
+
+        /// <summary>
+        /// Try parsing a TurkishIdNumber.
+        /// </summary>
+        /// <param name="number">String to parse.</param>
+        /// <param name="result">Parsed result if return value is true, otherwise null.</param>
+        /// <returns>True if parsing is successful, otherwise false.</returns>
+        public static bool TryParse(
+            string number,
+            [MaybeNullWhen(returnValue: false)] out TurkishIdNumber result)
+        {
+            if (!IsValid(number))
+            {
+                result = null;
+                return false;
+            }
+
+            result = new TurkishIdNumber(number, alreadyValidated: true);
+            return true;
         }

         /// <summary>
@@ -123,16 +159,16 @@
         }

         /// <inheritdoc/>
-        public override bool Equals(object obj)
+        public override bool Equals(object? obj)
         {
-            return obj is TurkishIdNumber instance && this.Value == instance.Value;
+            return obj is TurkishIdNumber other && Value == other.Value;
         }

         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         private static unsafe int nextDigit(ref char* ptr, ref bool invalid)
         {
             int result = *ptr++ - '0';
-            if (result < 0 || result > 9)
+            if (result is < 0 or > 9)
             {
                 invalid = true;
             }


Add more methods for color construction

Add more methods for color construction

 * Adds FromArgb to construct color from an 0xAARRGGBB value.
 * Adds FromRgb to construct color from an 0xRRGGBB value.

--- Corale.Colore/Core/Color.cs
+++ Corale.Colore/Core/Color.cs
@@ -297,6 +297,33 @@
         }

         /// <summary>
+        /// Creates a new <see cref="Color" /> from an ARGB integer value
+        /// in the format of <c>0xAARRGGBB</c> where the alpha component
+        /// ranges from <c>0x00</c> (fully transparent) to <c>0xFF</c> (fully opaque).
+        /// </summary>
+        /// <param name="value">The ARGB value to convert from.</param>
+        /// <returns>A new instance of the <see cref="Color" /> struct.</returns>
+        [PublicAPI]
+        public static Color FromArgb(uint value)
+        {
+            var abgr = (value & 0xFF00FF00) | ((value & 0xFF0000) >> 16) | ((value & 0xFF) << 16);
+            return new Color(abgr);
+        }
+
+        /// <summary>
+        /// Creates a new <see cref="Color" /> from an RGB integer value
+        /// in the format of <c>0xRRGGBB</c>.
+        /// </summary>
+        /// <param name="value">The RGB value to convert from.</param>
+        /// <returns>A new instance of the <see cref="Color" /> struct.</returns>
+        [PublicAPI]
+        public static Color FromRgb(uint value)
+        {
+            var abgr = 0xFF000000 | ((value & 0xFF0000) >> 16) | (value & 0xFF00) | ((value & 0xFF) << 16);
+            return new Color(abgr);
+        }
+
+        /// <summary>
         /// Returns a value indicating whether this instance of <see cref="Color" />
         /// is equal to an <see cref="object" /> <paramref name="other" />.
         /// </summary>


Add NativeMethods.GetIdleSeconds for idle time detection

--- Core/Utils/NativeMethods.cs
+++ Core/Utils/NativeMethods.cs
@@ -24,13 +24,26 @@
             Left, Right
         }

+        private struct LASTINPUTINFO{
+            public static readonly uint Size = (uint)Marshal.SizeOf(typeof(LASTINPUTINFO));
+
+            // ReSharper disable once NotAccessedField.Local
+            public uint cbSize;
+            #pragma warning disable 649
+            public uint dwTime;
+            #pragma warning restore 649
+        }
+
         public delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam);

         [DllImport("user32.dll", EntryPoint = "SetWindowPos")]
-        public static extern bool SetWindowPos(int hWnd, int hWndOrder, int x, int y, int width, int height, uint flags);
+        private static extern bool SetWindowPos(int hWnd, int hWndOrder, int x, int y, int width, int height, uint flags);

         [DllImport("user32.dll")]
-        public static extern void mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo);
+        private static extern void mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo);
+
+        [DllImport("user32.dll")]
+        private static extern bool GetLastInputInfo(ref LASTINPUTINFO info);

         [DllImport("user32.dll")]
         public static extern IntPtr SendMessage(IntPtr hWnd, uint msg, int wParam, IntPtr lParam);
@@ -75,5 +88,23 @@
             mouse_event(flagHold, Cursor.Position.X, Cursor.Position.Y, 0, 0);
             mouse_event(flagRelease, Cursor.Position.X, Cursor.Position.Y, 0, 0);
         }
+
+        public static int GetIdleSeconds(){
+            LASTINPUTINFO info = new LASTINPUTINFO();
+            info.cbSize = LASTINPUTINFO.Size;
+
+            if (!GetLastInputInfo(ref info)){
+                return 0;
+            }
+
+            uint ticks;
+
+            unchecked{
+                ticks = (uint)Environment.TickCount;
+            }
+
+            int seconds = (int)Math.Floor(TimeSpan.FromMilliseconds(ticks-info.dwTime).TotalSeconds);
+            return Math.Max(0, seconds); // ignore rollover after several weeks of uptime
+        }
     }
 }


Force Activities to not be null even if Discord sends a null

--- DSharpPlus/DiscordClient.cs
+++ DSharpPlus/DiscordClient.cs
@@ -1296,7 +1296,7 @@
             }

             // reuse arrays / avoid linq (this is a hot zone)
-            if (rawPresence["activities"] == null)
+            if (presence.Activities == null || rawPresence["activities"] == null)
             {
 #if !NET45 && !NETSTANDARD1_1
                 presence.Activities = Array.Empty<DiscordActivity>();


Fix formatting

Fix formatting

Fix-up some code formatting.

--- tests/AdventOfCode.Tests/Api/HttpServerFixture.cs
+++ tests/AdventOfCode.Tests/Api/HttpServerFixture.cs
@@ -95,18 +95,15 @@
         _host = builder.Build();
         _host.Start();

-        // Extract the selected dynamic port out of the Kestrel server
-        // and assign it onto the client options for convenience so it
-        // "just works" as otherwise it'll be the default http://localhost
-        // URL, which won't route to the Kestrel-hosted HTTP server.
         var server = _host.Services.GetRequiredService<IServer>();
         var addresses = server.Features.Get<IServerAddressesFeature>();

         ClientOptions.BaseAddress = addresses!.Addresses
-            .Select(x => new Uri(x))
+            .Select((p) => new Uri(p))
             .Last();

         testHost.Start();
+
         return testHost;
     }


layer is not Enemy, it's Enemies

layer is not Enemy, it's Enemies

--- game/Assets/scripts/SpawnManager.cs
+++ game/Assets/scripts/SpawnManager.cs
@@ -52,7 +52,7 @@
  				if (obj.name.Equals ("Map")) {
  					Camera gObj = obj.camera;
  					noEnemyMask = gObj.cullingMask;
- 					enemyMask = (gObj.cullingMask) | (1 << LayerMask.NameToLayer("Enemy"));
+ 					enemyMask = (gObj.cullingMask) | (1 << LayerMask.NameToLayer("Enemies"));
  					break;
  				}
  			}


auto versioning

auto versioning

--- Properties/AssemblyInfo.cs
+++ Properties/AssemblyInfo.cs
@@ -32,5 +32,5 @@
 // You can specify all the values or you can default the Build and Revision Numbers
 // by using the '*' as shown below:
 // [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyVersion("0.1.*")]
 [assembly: AssemblyFileVersion("1.0.0.0")]


version number

version number

--- Properties/AssemblyInfo.cs
+++ Properties/AssemblyInfo.cs
@@ -22,7 +22,7 @@
 // The following GUID is for the ID of the typelib if this project is exposed to COM
 [assembly: Guid("f18527dd-a54e-4711-9dcd-c73a221ebb2d")]

-[assembly: AssemblyVersion("1.0.2.1")]
-[assembly: AssemblyFileVersion("1.0.2.1")]
-[assembly: AssemblyInformationalVersion("v2.1")]
-[assembly: KSPAssembly("Contracts_Window", 2, 1)]
+[assembly: AssemblyVersion("1.0.2.2")]
+[assembly: AssemblyFileVersion("1.0.2.2")]
+[assembly: AssemblyInformationalVersion("v2.2")]
+[assembly: KSPAssembly("Contracts_Window", 2, 2)]


Change to the properties file

Change to the properties file

Published a v1.0 release so updated the AssemblyInfo file

--- Properties/AssemblyInfo.cs
+++ Properties/AssemblyInfo.cs
@@ -12,7 +12,7 @@
 [assembly: AssemblyConfiguration("")]
 [assembly: AssemblyCompany("")]
 [assembly: AssemblyProduct("ScreenGrab")]
-[assembly: AssemblyCopyright("Copyright ©  2012")]
+[assembly: AssemblyCopyright("Copyright ©  2014")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]

@@ -32,12 +32,12 @@

 [assembly: ThemeInfo(
-    ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
-    //(used if a resource is not found in the page,
-    // or application resource dictionaries)
-    ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
-    //(used if a resource is not found in the page,
-    // app, or any theme specific resource dictionaries)
+	ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
+	//(used if a resource is not found in the page,
+	// or application resource dictionaries)
+	ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
+	//(used if a resource is not found in the page,
+	// app, or any theme specific resource dictionaries)
 )]


Update version number to 1.1.13

Update version number to 1.1.13

--- Properties/AssemblyInfo.cs
+++ Properties/AssemblyInfo.cs
@@ -32,5 +32,5 @@
 // You can specify all the values or you can default the Build and Revision Numbers
 // by using the '*' as shown below:
 // [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.1.12.0")]
-[assembly: AssemblyFileVersion("1.1.12.0")]
+[assembly: AssemblyVersion("1.1.13.0")]
+[assembly: AssemblyFileVersion("1.1.13.0")]


More reordering and refactoring

More reordering and refactoring

--- inklecate2Sharp/Parser/ParsedObjects/FlowBase.cs
+++ inklecate2Sharp/Parser/ParsedObjects/FlowBase.cs
@@ -32,98 +32,7 @@
                 }
 			}
 		}
-
-
-        class GatheredLooseEnd
-        {
-            public Runtime.Divert divert;
-            public Gather targetGather;
-        }
-
-        List<GatheredLooseEnd> _gatheredLooseEnds;
-
-        class WeaveBlockRuntimeResult
-        {
-            public Runtime.Container rootContainer;
-            public Runtime.Container currentContainer;
-            public List<IWeavePoint> looseEnds;
-
-            // Reference to FlowBase's instance
-            List<GatheredLooseEnd> _gatheredLooseEnds;
-
-            public WeaveBlockRuntimeResult(List<GatheredLooseEnd> gatheredLooseEnds) {
-                rootContainer = currentContainer = new Runtime.Container();
-                looseEnds = new List<IWeavePoint> ();
-                _gatheredLooseEnds = gatheredLooseEnds;
-            }
-
-            public void StartGather(Gather gather)
-            {
-                var gatherContainer = gather.runtimeContainer;
-                gatherContainer.name = "gather" + _gatherCount;
-                _gatherCount++;
-
-                // Consume loose ends: divert them to this gather
-                foreach (IWeavePoint looseEnd in looseEnds) {
-
-                    if (looseEnd.hasLooseEnd) {
-                        var divert = new Runtime.Divert ();
-                        looseEnd.runtimeContainer.AddContent (divert);
-
-                        // Maintain a list of them so that we can resolve their paths later
-                        _gatheredLooseEnds.Add (new GatheredLooseEnd{ divert = divert, targetGather = gather });
-
-                    }
-               }
-                looseEnds.RemoveRange (0, looseEnds.Count);
-
-                // Finally, add this gather to the main content, but only accessible
-                // by name so that it isn't stepped into automatically, but only via
-                // a divert from a loose end
-                if (currentContainer.content.Count == 0) {
-                    currentContainer.AddContent (gatherContainer);
-                } else {
-                    currentContainer.AddToNamedContentOnly (gatherContainer);
-                }
-
-
-                // Replace the current container itself
-                currentContainer = gatherContainer;
-
-                _latestLooseGather = gather;
-            }
-
-            public void AddWeavePoint(IWeavePoint weavePoint)
-            {
-                // Current level Gather
-                if (weavePoint is Gather) {
-                    StartGather ((Gather)weavePoint);
-                }
-
-                // Current level choice
-                else if (weavePoint is Choice) {
-                    currentContainer.AddContent (((Choice)weavePoint).runtimeObject);
-                }
-
-                // TODO: Do further analysis on this weavePoint to determine whether
-                // it really is a loose end (e.g. does it end in a divert)
-                if (weavePoint.hasLooseEnd) {
-
-                    looseEnds.Add (weavePoint);
-
-                    // A gather stops becoming a loose end itself
-                    // once it gets a choice
-                    if (_latestLooseGather != null && weavePoint is Choice) {
-                        looseEnds.Remove (_latestLooseGather);
-                    }
-                }
-            }
-
-            Gather _latestLooseGather;
-            int _gatherCount;
-        }
-
-
+
         public override Runtime.Object GenerateRuntimeObject ()
         {
             var container = new Runtime.Container ();
@@ -131,7 +40,7 @@

             // Maintain a list of gathered loose ends so that we can resolve
             // their divert paths in ResolveReferences
-            this._gatheredLooseEnds = new List<GatheredLooseEnd> ();
+            this._allGatheredLooseEnds = new List<GatheredLooseEnd> ();

             bool initialKnotOrStitchEntered = false;

@@ -187,7 +96,187 @@
         // Recursive for further indentation levels.
         WeaveBlockRuntimeResult GenerateWeaveBlockRuntime(ref int contentIdx, int indentIndex)
         {
-            var result = new WeaveBlockRuntimeResult (_gatheredLooseEnds);
+            var result = new WeaveBlockRuntimeResult ();
+            result.gatheredLooseEndDelegate = OnLooseEndGathered;
+
+            // Iterate through content for the block at this level of indentation
+            //  - Normal content is nested under Choices and Gathers
+            //  - Blocks that are further indented cause recursion
+            //  - Keep track of loose ends so that they can be diverted to Gathers
+            while (contentIdx < content.Count) {
+
+                Parsed.Object obj = content [contentIdx];
+
+                // Choice or Gather
+                if (obj is IWeavePoint) {
+                    var weavePoint = (IWeavePoint)obj;
+                    var weaveIndentIdx = weavePoint.indentationDepth - 1;
+
+                    // Moving to outer level indent - this block is complete
+                    if (weaveIndentIdx < indentIndex) {
+                        return result;
+                    }
+
+                    // Inner level indentation - recurse
+                    else if (weaveIndentIdx > indentIndex) {
+                        var nestedResult = GenerateWeaveBlockRuntime (ref contentIdx, weaveIndentIdx);
+                        result.AddNestedBlock (nestedResult);
+                        continue;
+                    }
+
+                    result.AddWeavePoint (weavePoint);
+                }
+
+                // Normal content
+                else {
+                    result.AddResultContent (obj.runtimeObject);
+                }
+
+                contentIdx++;
+            }
+
+            return result;
+        }
+
+        public override void ResolveReferences (Story context)
+		{
+			foreach (Parsed.Object obj in content) {
+				obj.ResolveReferences (context);
+			}
+
+            if (_allGatheredLooseEnds != null) {
+                foreach(GatheredLooseEnd looseEnd in _allGatheredLooseEnds) {
+                    looseEnd.divert.targetPath = looseEnd.targetGather.runtimeObject.path;
+                }
+            }
+
+        }
+
+        void OnLooseEndGathered (Runtime.Divert divert, Gather gather)
+        {
+            _allGatheredLooseEnds.Add (new GatheredLooseEnd{ divert = divert, targetGather = gather });
+        }
+
+        class GatheredLooseEnd
+        {
+            public Runtime.Divert divert;
+            public Gather targetGather;
+        }
+
+        // "Result" isn't quite accurate - it contains most of the logic!
+        class WeaveBlockRuntimeResult
+        {
+            // Containers can be chained as multiple gather points
+            // get created as the same indentation level.
+            // rootContainer is always the first in the chain, while
+            // currentContainer is the latest.
+            public Runtime.Container rootContainer;
+            public Runtime.Container currentContainer;
+
+            public List<IWeavePoint> looseEnds;
+
+            public delegate void LooseEndDelegate (Runtime.Divert divert, Gather gather);
+            public LooseEndDelegate gatheredLooseEndDelegate;
+
+            public WeaveBlockRuntimeResult() {
+                rootContainer = currentContainer = new Runtime.Container();
+                looseEnds = new List<IWeavePoint> ();
+            }
+
+            // Found gather point:
+            //  - gather any loose ends
+            //  - set the gather as the main container to dump new content in
+            public void StartGather(Gather gather)
+            {
+                var gatherContainer = gather.runtimeContainer;
+                gatherContainer.name = "gather" + _gatherCount;
+                _gatherCount++;
+
+                // Consume loose ends: divert them to this gather
+                foreach (IWeavePoint looseEnd in looseEnds) {
+
+                    if (looseEnd.hasLooseEnd) {
+                        var divert = new Runtime.Divert ();
+                        looseEnd.runtimeContainer.AddContent (divert);
+
+                        // Pass back knowledge of this loose end being diverted
+                        // to the FlowBase so that it can maintain a list of them,
+                        // and resolve the divert references later
+                        gatheredLooseEndDelegate (divert, gather);
+                    }
+                }
+                looseEnds.RemoveRange (0, looseEnds.Count);
+
+                // Finally, add this gather to the main content, but only accessible
+                // by name so that it isn't stepped into automatically, but only via
+                // a divert from a loose end
+                if (currentContainer.content.Count == 0) {
+                    currentContainer.AddContent (gatherContainer);
+                } else {
+                    currentContainer.AddToNamedContentOnly (gatherContainer);
+                }
+
+                // Replace the current container itself
+                currentContainer = gatherContainer;
+
+                _latestLooseGather = gather;
+            }
+
+            public void AddWeavePoint(IWeavePoint weavePoint)
+            {
+                // Current level Gather
+                if (weavePoint is Gather) {
+                    StartGather ((Gather)weavePoint);
+                }
+
+                // Current level choice
+                else if (weavePoint is Choice) {
+                    currentContainer.AddContent (((Choice)weavePoint).runtimeObject);
+                }
+
+                // TODO: Do further analysis on this weavePoint to determine whether
+                // it really is a loose end (e.g. does it end in a divert)
+                if (weavePoint.hasLooseEnd) {
+
+                    looseEnds.Add (weavePoint);
+
+                    // A gather stops becoming a loose end itself
+                    // once it gets a choice
+                    if (_latestLooseGather != null && weavePoint is Choice) {
+                        looseEnds.Remove (_latestLooseGather);
+                    }
+                }
+
+                previousWeavePoint = weavePoint;
+            }
+
+            // Add nested block at a greater indentation level
+            public void AddNestedBlock(WeaveBlockRuntimeResult nestedResult)
+            {
+                // Add this inner block to current container
+                // (i.e. within the main container, or within the last defined Choice/Gather)
+                AddResultContent (nestedResult.rootContainer);
+
+                // Append the indented block's loose ends to our own
+                looseEnds.AddRange (nestedResult.looseEnds);
+
+                // Now there's a deeper indentation level, the previous weave point doesn't
+                // count as a loose end (since it will have content to go to)
+                if (previousWeavePoint != null) {
+                    looseEnds.Remove (previousWeavePoint);
+                }
+            }
+
+            // Normal content gets added into the latest Choice or Gather by default,
+            // unless there hasn't been one yet.
+            public void AddResultContent(Runtime.Object content)
+            {
+                if (previousWeavePoint != null) {
+                    previousWeavePoint.runtimeContainer.AddContent (content);
+                } else {
+                    currentContainer.AddContent (content);
+                }
+            }

             // Keep track of previous weave point (Choice or Gather)
             // at the current indentation level:
@@ -197,81 +286,11 @@
             //    indented content since it's no longer a loose end
             IWeavePoint previousWeavePoint = null;

-            // Iterate through content for the block at this level of indentation
-            //  - Normal content is nested under Choices and Gathers
-            //  - Blocks that are further indented cause recursion
-            //  - Keep track of loose ends so that they can be diverted to Gathers
-            while (contentIdx < content.Count) {
-
-                Parsed.Object obj = content [contentIdx];
-
-                // Choice or Gather
-                if (obj is IWeavePoint) {
-                    var weavePoint = (IWeavePoint)obj;
-                    var weaveIndentIdx = weavePoint.indentationDepth - 1;
-
-                    // Moving to outer level indent
-                    if (weaveIndentIdx < indentIndex) {
-                        return result;
-                    }
-
-                    // Inner level indentation
-                    else if (weaveIndentIdx > indentIndex) {
-                        var nestedResult = GenerateWeaveBlockRuntime (ref contentIdx, weaveIndentIdx);
-
-                        // Add this inner block to current container
-                        // (i.e. within the main container, or within the last defined Choice/Gather)
-                        if (previousWeavePoint == null) {
-                            result.currentContainer.AddContent (nestedResult.rootContainer);
-                        } else {
-                            previousWeavePoint.runtimeContainer.AddContent (nestedResult.rootContainer);
-                        }
-
-                        // Append the indented block's loose ends to our own
-                        result.looseEnds.AddRange (nestedResult.looseEnds);
-
-                        // Now there's a deeper indentation level, the previous weave point doesn't
-                        // count as a loose end
-                        if (previousWeavePoint != null) {
-                            result.looseEnds.Remove (previousWeavePoint);
-                        }
-                        continue;
-                    }
-
-                    result.AddWeavePoint (weavePoint);
-
-                    previousWeavePoint = weavePoint;
-                }
-
-                // Normal content
-                else {
-                    if (previousWeavePoint != null) {
-                        previousWeavePoint.runtimeContainer.AddContent (obj.runtimeObject);
-                    } else {
-                        result.currentContainer.AddContent (obj.runtimeObject);
-                    }
-
-                }
-
-                contentIdx++;
-            }
-
-            return result;
-        }
-
-        public override void ResolveReferences (Story context)
-		{
-			foreach (Parsed.Object obj in content) {
-				obj.ResolveReferences (context);
-			}
-
-            if (_gatheredLooseEnds != null) {
-                foreach(GatheredLooseEnd looseEnd in _gatheredLooseEnds) {
-                    looseEnd.divert.targetPath = looseEnd.targetGather.runtimeObject.path;
-                }
-            }
-
-        }
+            Gather _latestLooseGather;
+            int _gatherCount;
+        }
+
+        List<GatheredLooseEnd> _allGatheredLooseEnds;
 	}
 }


Company name added

Company name added

The company name has been added to the assembly information

--- Properties/AssemblyInfo.cs
+++ Properties/AssemblyInfo.cs
@@ -8,7 +8,7 @@
 [assembly: AssemblyTitle("OS")]
 [assembly: AssemblyDescription("")]
 [assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
+[assembly: AssemblyCompany("xplore+")]
 [assembly: AssemblyProduct("OS")]
 [assembly: AssemblyCopyright("Copyright ©  2013")]
 [assembly: AssemblyTrademark("")]


Update version to 1.2.12

Update version to 1.2.12

--- Properties/AssemblyInfo.cs
+++ Properties/AssemblyInfo.cs
@@ -32,5 +32,5 @@
 // You can specify all the values or you can default the Build and Revision Numbers
 // by using the '*' as shown below:
 // [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.2.11.0")]
-[assembly: AssemblyFileVersion("1.2.11.0")]
+[assembly: AssemblyVersion("1.2.12.0")]
+[assembly: AssemblyFileVersion("1.2.12.0")]


update assembly info

update assembly info

--- Properties/AssemblyInfo.cs
+++ Properties/AssemblyInfo.cs
@@ -49,5 +49,5 @@
 // You can specify all the values or you can default the Build and Revision Numbers
 // by using the '*' as shown below:
 // [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("6.2.0.*")]
-[assembly: AssemblyFileVersion("6.2.0")]
+[assembly: AssemblyVersion("7.0.0.*")]
+[assembly: AssemblyFileVersion("7.0.0")]


Version updated

Version updated

--- Properties/AssemblyInfo.cs
+++ Properties/AssemblyInfo.cs
@@ -32,5 +32,5 @@
 //      Revision
 //

-[assembly: AssemblyVersion("3.0.1.*")]
-[assembly: AssemblyFileVersion("3.0.1.90")]+[assembly: AssemblyVersion("3.0.2.*")]
+[assembly: AssemblyFileVersion("3.0.2.94")]


Ver. 1.3.0.0

Ver. 1.3.0.0

--- Properties/AssemblyInfo.cs
+++ Properties/AssemblyInfo.cs
@@ -10,7 +10,7 @@
 [assembly: AssemblyConfiguration( "" )]
 [assembly: AssemblyCompany( "" )]
 [assembly: AssemblyProduct( "Arma3ModOptionMover" )]
-[assembly: AssemblyCopyright( "Copyright ©  2015 itom0717" )]
+[assembly: AssemblyCopyright( "Copyright © 2015 itom0717" )]
 [assembly: AssemblyTrademark( "" )]
 [assembly: AssemblyCulture( "" )]

@@ -32,5 +32,5 @@
 // すべての値を指定するか、下のように '*' を使ってビルドおよびリビジョン番号を
 // 既定値にすることができます:
 // [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion( "1.2.1.0" )]
-[assembly: AssemblyFileVersion( "1.2.1.0" )]
+[assembly: AssemblyVersion( "1.3.0.0" )]
+[assembly: AssemblyFileVersion( "1.3.0.0" )]


Redo some ScriptCommand stuff to be better Creating FileStreams for an XmlReader in 2017 [LUL]

--- gen5_parse_compile/ScriptCommand.cs
+++ gen5_parse_compile/ScriptCommand.cs
@@ -93,14 +93,12 @@
         {
             string s = null;

-            // Check if XML names are allowed still
+            // Use XML names...unless we aren't using XML in the first place.
             if (usesXml.Val)
                 s = GetCommandNameFromXml(id);

             // If s is still null (or was set to it in the the XML function), generic name is used.
-            s = s ?? $"cmd{id:x}";
-
-            return s;
+            return s ?? $"cmd{id:x}";
         }

         private string GetCommandNameFromXml(ushort id)
@@ -113,23 +111,19 @@
                 usesXml.Val = false;
                 return cmdName;
             }
-
-            // TODO: Maybe enclose this in try/catch and set canUseXml if an exception is caught?
-            using (FileStream cmdTable = File.OpenRead(cmdTableFilename))
-            {
-                using (XmlReader cmdTableReader = XmlReader.Create(cmdTable,
-                    InitializeXmlSettings()))
+
+            using (XmlReader cmdTableReader = XmlReader.Create(cmdTableFilename,
+                InitializeXmlSettings()))
+            {
+                if (SeekToXmlCommandById(cmdTableReader))
                 {
-                    if (SeekToXmlCommandById(cmdTableReader))
+                    if (cmdTableReader.ReadToDescendant("name"))
                     {
-                        if (cmdTableReader.ReadToDescendant("name"))
-                        {
-                            cmdName = cmdTableReader.ReadElementContentAsString();
-                        }
-                        // <name> doesn't exist in this case. That's perfectly fine.
-                        // It can be null, it'll just fall back to a generic name.
-                        // Using a generic name doesn't cut off access to the whole XML file.
+                        cmdName = cmdTableReader.ReadElementContentAsString();
                     }
+                    // <name> doesn't exist in this case. That's perfectly fine.
+                    // It can be null, it'll just fall back to a generic name.
+                    // Using a generic name doesn't cut off access to the whole XML file.
                 }
             }

@@ -141,7 +135,7 @@
             // For XmlReader validation
             // TODO: Find performance difference between this and validating once
             XmlSchemaSet schemas = new XmlSchemaSet();
-            schemas.Add("", "cmd_table.xsd");
+            schemas.Add("", cmdTableSchema);

             XmlReaderSettings settings = new XmlReaderSettings()
             {
@@ -255,26 +249,24 @@
             paramList.Clear();

             // XML time.
-            using (FileStream cmdTable = File.OpenRead(cmdTableFilename))
-            {
-                using (XmlReader cmdTableReader = XmlReader.Create(cmdTable,
-                    InitializeXmlSettings()))
+            using (XmlReader cmdTableReader = XmlReader.Create(cmdTableFilename,
+                InitializeXmlSettings()))
+            {
+                if (SeekToXmlCommandById(cmdTableReader))
                 {
-                    if (SeekToXmlCommandById(cmdTableReader))
+                    if (cmdTableReader.ReadToDescendant("arg"))
                     {
-                        if (cmdTableReader.ReadToDescendant("arg"))
+                        // Stuff. This is where the magic begins.
+                        do
                         {
-                            // Stuff. This is where the magic begins.
-                            do
+                            // Populate a new ParamInfo since we've found an "arg"
+                            paramList.Add(new ParamInfo()
                             {
-                                // Get the type of the arg
-                                paramList.Add(new ParamInfo()
-                                {
-                                    Type = ParamInfo.ParseParamType(cmdTableReader
-                                        .GetAttribute("type"), usesXml)
-                                });
-                            } while (cmdTableReader.ReadToNextSibling("arg"));
-                        }
+                                Type = ParamInfo.ParseParamType(cmdTableReader
+                                    .GetAttribute("type"), usesXml),
+                                Name = cmdTableReader.GetAttribute("name") ?? string.Empty
+                            });
+                        } while (cmdTableReader.ReadToNextSibling("arg"));
                     }
                 }
             }


Update some of the validating stuff Now validation is done while the file is read. Kinda confused on whether the rest of the function still goes through after that...

--- gen5_parse_compile/ScriptCommand.cs
+++ gen5_parse_compile/ScriptCommand.cs
@@ -110,6 +110,7 @@
             return paramsSize;
         }

+        // Entirely untested.
         private string GetXmlCommandName(ushort id, ref bool canUseXml)
         {
             string cmdName = null;
@@ -121,42 +122,32 @@
                 return cmdName;
             }

-            if (!IsCommandTableValid("cmd_table.xml"))
-            {
-                Console.WriteLine("Command table failed to validate, forcing generic names.");
-                canUseXml = false;
-                return cmdName;
-            }
-
             FileStream cmdTable = File.Open("cmd_table.xml", FileMode.Open, FileAccess.Read);

-            using (XmlReader cmdTableReader = XmlReader.Create(cmdTable))
+            // For XmlReader validation
+            XmlSchemaSet schemas = new XmlSchemaSet();
+            schemas.Add("", "cmd_table.xsd");
+
+            XmlReaderSettings settings = new XmlReaderSettings()
+            {
+                Schemas = schemas,
+                ValidationType = ValidationType.Schema
+            };
+            settings.ValidationEventHandler += new ValidationEventHandler((o, e) =>
+            {
+                Console.WriteLine($"XML file didn't validate: {e.Message}");
+                // So, did the program crash? An exception was just thrown, right...?
+            });
+
+            using (XmlReader cmdTableReader = XmlReader.Create(cmdTable, settings))
             {
                 cmdTableReader.MoveToContent();
                 cmdTableReader.ReadToDescendant("command");
-
+

             }

             return cmdName;
         }
-
-        private bool IsCommandTableValid(string filename)
-        {
-            bool ret = true;
-
-            XmlSchemaSet schemas = new XmlSchemaSet();
-            schemas.Add("", "cmd_table.xsd");
-
-            XDocument tableDoc = XDocument.Load(filename);
-            tableDoc.Validate(schemas, (o, e) =>
-            {
-                Console.WriteLine(e.Message);
-                Console.WriteLine("Can't use the command table, see above and the XML schema.");
-                ret = false;
-            });
-
-            return ret;
-        }
     }
 }


Added comment about CircleTransformation & linker issue

--- DotNetRu.iOS/AppDelegate.cs
+++ DotNetRu.iOS/AppDelegate.cs
@@ -141,6 +141,7 @@

             CachedImageRenderer.Init();

+            // this is needed to tell linker to keep this type. See https://github.com/luberda-molinet/FFImageLoading/issues/462
             var ignore = new CircleTransformation();
         }


Copy image to memory before creating bitmap

--- EDDiscovery/ImageHandler.cs
+++ EDDiscovery/ImageHandler.cs
@@ -415,6 +415,7 @@
         private Bitmap GetScreenshot(string inputfile, string cur_sysname, int cmdrid, ref JournalScreenshot ss, ref string store_name, ref Point finalsize, ref FileInfo fi)
         {
             FileStream testfile = null;
+            MemoryStream memstrm = new MemoryStream();
             Bitmap bmp = null;

             for (int tries = 60; tries-- > 0;)          // wait 30 seconds and then try it anyway.. 32K hires shots take a while to write.
@@ -425,7 +426,10 @@
                     //Console.WriteLine("Trying " + inputfile);
                     using (testfile = File.Open(inputfile, FileMode.Open, FileAccess.Read, FileShare.Read))        // throws if can't open
                     {
-                        bmp = new Bitmap(testfile);
+                        memstrm.SetLength(0);
+                        testfile.CopyTo(memstrm);
+                        memstrm.Seek(0, SeekOrigin.Begin);
+                        bmp = new Bitmap(memstrm);
                     }
                     //Console.WriteLine("Worked " + inputfile);
                     break;
@@ -440,7 +444,10 @@
                 //Console.WriteLine("Trying " + inputfile);
                 using (testfile = File.Open(inputfile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))        // throws if can't open
                 {
-                    bmp = new Bitmap(testfile);
+                    memstrm.SetLength(0);
+                    testfile.CopyTo(memstrm);
+                    memstrm.Seek(0, SeekOrigin.Begin);
+                    bmp = new Bitmap(memstrm);
                 }
                 //Console.WriteLine("Worked " + inputfile);
             }


Use file time rather than current time for output filename

--- EDDiscovery/ImageHandler.cs
+++ EDDiscovery/ImageHandler.cs
@@ -122,7 +122,7 @@
             numericUpDownWidth.Value = SQLiteDBClass.GetSettingInt("ImageHandlerCropWidth", 0);
             numericUpDownHeight.Value = SQLiteDBClass.GetSettingInt("ImageHandlerCropHeight", 0);

-            textBoxFileNameExample.Text = CreateFileName("Sol", "HighResScreenshot_0000.bmp", comboBoxFileNameFormat.SelectedIndex, checkBoxHires.Checked);
+            textBoxFileNameExample.Text = CreateFileName("Sol", "HighResScreenshot_0000.bmp", comboBoxFileNameFormat.SelectedIndex, checkBoxHires.Checked, DateTime.Now);

             numericUpDownTop.Enabled = numericUpDownWidth.Enabled = numericUpDownLeft.Enabled = numericUpDownHeight.Enabled = checkBoxCropImage.Checked;

@@ -299,7 +299,7 @@
                 {
                     DateTime filetime = fi.CreationTimeUtc;

-                    ConvertParams cp = GetConversionParams(cur_sysname);
+                    ConvertParams cp = GetConversionParams(cur_sysname, filetime);

                     if (cp.cannotexecute)
                     {
@@ -310,7 +310,7 @@

                     if (store_name == null || cp.reconvert)
                     {
-                        using (Bitmap croppedbmp = ConvertImage(cp, inputfile, bmp, cur_sysname, ss, cmdrid, ref store_name))
+                        using (Bitmap croppedbmp = ConvertImage(cp, inputfile, bmp, cur_sysname, filetime, ss, cmdrid, ref store_name))
                         {
                             if (cp.copyclipboard)
                             {
@@ -477,7 +477,7 @@
             public bool reconvert = true;
         }

-        private ConvertParams GetConversionParams(string cur_sysname)
+        private ConvertParams GetConversionParams(string cur_sysname, DateTime timestamp)
         {
             ConvertParams p = new ConvertParams();

@@ -494,25 +494,25 @@
                         break;

                     case 2:     // "YYYY-MM-DD"
-                        p.output_folder += "\\" + DateTime.Now.ToString("yyyy-MM-dd");
+                        p.output_folder += "\\" + timestamp.ToString("yyyy-MM-dd");
                         break;
                     case 3:     // "DD-MM-YYYY"
-                        p.output_folder += "\\" + DateTime.Now.ToString("dd-MM-yyyy");
+                        p.output_folder += "\\" + timestamp.ToString("dd-MM-yyyy");
                         break;
                     case 4:     // "MM-DD-YYYY"
-                        p.output_folder += "\\" + DateTime.Now.ToString("MM-dd-yyyy");
+                        p.output_folder += "\\" + timestamp.ToString("MM-dd-yyyy");
                         break;

                     case 5:  //"YYYY-MM-DD Sysname",
-                        p.output_folder += "\\" + DateTime.Now.ToString("yyyy-MM-dd") + " " + Tools.SafeFileString(cur_sysname);
+                        p.output_folder += "\\" + timestamp.ToString("yyyy-MM-dd") + " " + Tools.SafeFileString(cur_sysname);
                         break;

                     case 6:  //"DD-MM-YYYY Sysname",
-                        p.output_folder += "\\" + DateTime.Now.ToString("dd-MM-yyyy") + " " + Tools.SafeFileString(cur_sysname);
+                        p.output_folder += "\\" + timestamp.ToString("dd-MM-yyyy") + " " + Tools.SafeFileString(cur_sysname);
                         break;

                     case 7: //"MM-DD-YYYY Sysname"
-                        p.output_folder += "\\" + DateTime.Now.ToString("MM-dd-yyyy") + " " + Tools.SafeFileString(cur_sysname);
+                        p.output_folder += "\\" + timestamp.ToString("MM-dd-yyyy") + " " + Tools.SafeFileString(cur_sysname);
                         break;
                 }

@@ -536,12 +536,12 @@
             return p;
         }

-        private Bitmap ConvertImage(ConvertParams cp, string inputfile, Bitmap bmp, string cur_sysname, JournalScreenshot ss, int cmdrid, ref string store_name)
+        private Bitmap ConvertImage(ConvertParams cp, string inputfile, Bitmap bmp, string cur_sysname, DateTime timestamp, JournalScreenshot ss, int cmdrid, ref string store_name)
         {
             int index = 0;
             do                                          // add _N on the filename for index>0, to make them unique.
             {
-                store_name = Path.Combine(cp.output_folder, CreateFileName(cur_sysname, inputfile, cp.formatindex, cp.hires) + (index == 0 ? "" : "_" + index) + cp.extension);
+                store_name = Path.Combine(cp.output_folder, CreateFileName(cur_sysname, inputfile, cp.formatindex, cp.hires, timestamp) + (index == 0 ? "" : "_" + index) + cp.extension);
                 index++;
             } while (File.Exists(store_name));          // if name exists, pick another

@@ -583,7 +583,7 @@
             return croppedbmp;
         }

-        private string CreateFileName(string cur_sysname, string orignalfile, int formatindex, bool hires)
+        private string CreateFileName(string cur_sysname, string orignalfile, int formatindex, bool hires, DateTime timestamp)
         {
             cur_sysname = Tools.SafeFileString(cur_sysname);

@@ -592,11 +592,11 @@
             switch (formatindex)
             {
                 case 0:
-                    return cur_sysname + " (" + DateTime.Now.ToString("yyyyMMdd-HHmmss") + ")" + postfix;
+                    return cur_sysname + " (" + timestamp.ToString("yyyyMMdd-HHmmss") + ")" + postfix;

                 case 1:
                     {
-                        string time = DateTime.Now.ToString();
+                        string time = timestamp.ToString();
                         time = time.Replace(":", "-");
                         time = time.Replace("/", "-");          // Rob found it was outputting 21/2/2020 on mine, so we need more replaces
                         time = time.Replace("\\", "-");
@@ -604,29 +604,29 @@
                     }
                 case 2:
                     {
-                        string time = DateTime.Now.ToString("yyyy-MM-dd HH-mm-ss");
+                        string time = timestamp.ToString("yyyy-MM-dd HH-mm-ss");
                         return time + " " + cur_sysname + postfix;
                     }
                 case 3:
                     {
-                        string time = DateTime.Now.ToString("dd-MM-yyyy HH-mm-ss");
+                        string time = timestamp.ToString("dd-MM-yyyy HH-mm-ss");
                         return time + " " + cur_sysname + postfix;
                     }
                 case 4:
                     {
-                        string time = DateTime.Now.ToString("MM-dd-yyyy HH-mm-ss");
+                        string time = timestamp.ToString("MM-dd-yyyy HH-mm-ss");
                         return time + " " + cur_sysname + postfix;
                     }

                 case 5:
                     {
-                        string time = DateTime.Now.ToString("HH-mm-ss");
+                        string time = timestamp.ToString("HH-mm-ss");
                         return time + " " + cur_sysname + postfix;
                     }

                 case 6:
                     {
-                        string time = DateTime.Now.ToString("HH-mm-ss");
+                        string time = timestamp.ToString("HH-mm-ss");
                         return time + postfix;
                     }

@@ -658,7 +658,7 @@
             {
                 SQLiteDBClass.PutSettingBool("checkBoxHires", checkBoxHires.Checked);
             }
-            textBoxFileNameExample.Text = CreateFileName("Sol", "HighResScreenshot_0000.bmp", comboBoxFileNameFormat.SelectedIndex, checkBoxHires.Checked);
+            textBoxFileNameExample.Text = CreateFileName("Sol", "HighResScreenshot_0000.bmp", comboBoxFileNameFormat.SelectedIndex, checkBoxHires.Checked, DateTime.Now);
         }

         private void comboBoxFileNameFormat_SelectedIndexChanged(object sender, EventArgs e)
@@ -667,7 +667,7 @@
             {
                 SQLiteDBClass.PutSettingInt("comboBoxFileNameFormat", comboBoxFileNameFormat.SelectedIndex);
             }
-            textBoxFileNameExample.Text = CreateFileName("Sol", "HighResScreenshot_0000.bmp", comboBoxFileNameFormat.SelectedIndex, checkBoxHires.Checked);
+            textBoxFileNameExample.Text = CreateFileName("Sol", "HighResScreenshot_0000.bmp", comboBoxFileNameFormat.SelectedIndex, checkBoxHires.Checked, DateTime.Now);
         }

         private void checkBoxCropImage_CheckedChanged(object sender, EventArgs e)


Simplify items

Simplify items

--- osu.Framework.Tests/Visual/UserInterface/TestSceneTabControl.cs
+++ osu.Framework.Tests/Visual/UserInterface/TestSceneTabControl.cs
@@ -5,7 +5,6 @@
 using System.Collections.Generic;
 using System.Linq;
 using NUnit.Framework;
-using osu.Framework.Extensions;
 using osu.Framework.Extensions.IEnumerableExtensions;
 using osu.Framework.Graphics;
 using osu.Framework.Graphics.Shapes;
@@ -18,7 +17,7 @@
 {
     public class TestSceneTabControl : TestScene
     {
-        private readonly List<KeyValuePair<string, TestEnum>> items = new List<KeyValuePair<string, TestEnum>>();
+        private readonly IEnumerable<TestEnum> items;

         private readonly StyledTabControl pinnedAndAutoSort;
         private readonly StyledTabControl switchingTabControl;
@@ -30,8 +29,7 @@
         {
             StyledTabControl simpleTabcontrol;

-            foreach (var val in (TestEnum[])Enum.GetValues(typeof(TestEnum)))
-                items.Add(new KeyValuePair<string, TestEnum>(val.GetDescription(), val));
+            items = ((TestEnum[])Enum.GetValues(typeof(TestEnum))).AsEnumerable();

             AddRange(new Drawable[]
             {
@@ -66,19 +64,21 @@
                 },
             });

-            items.AsEnumerable().ForEach(item => simpleTabcontrol.AddItem(item.Value));
-            items.GetRange(0, 7).AsEnumerable().ForEach(item => pinnedAndAutoSort.AddItem(item.Value));
+            foreach (var item in items)
+            {
+                simpleTabcontrol.AddItem(item);
+                switchingTabControl.AddItem(item);
+                withoutDropdownTabControl.AddItem(item);
+            }
+
+            items.Take(7).ForEach(item => pinnedAndAutoSort.AddItem(item));
             pinnedAndAutoSort.PinItem(TestEnum.Test5);
-            items.AsEnumerable().ForEach(item => switchingTabControl.AddItem(item.Value));
-            items.AsEnumerable().ForEach(item => withoutDropdownTabControl.AddItem(item.Value));
         }

         [Test]
         public void Basic()
         {
-            var nextTest = new Func<TestEnum>(() => items.AsEnumerable()
-                                                         .Select(item => item.Value)
-                                                         .FirstOrDefault(test => !pinnedAndAutoSort.Items.Contains(test)));
+            var nextTest = new Func<TestEnum>(() => items.FirstOrDefault(test => !pinnedAndAutoSort.Items.Contains(test)));

             Stack<TestEnum> pinned = new Stack<TestEnum>();

@@ -127,8 +127,8 @@
             AddStep("Switch forward", () => platformActionContainer.TriggerPressed(new PlatformAction(PlatformActionType.DocumentNext)));
             AddAssert("Ensure first tab", () => switchingTabControl.Current.Value == switchingTabControl.VisibleItems.First());

-            AddStep("Add all items", () => items.AsEnumerable().ForEach(item => removeAllTabControl.AddItem(item.Value)));
-            AddAssert("Ensure all items", () => removeAllTabControl.Items.Count() == items.Count);
+            AddStep("Add all items", () => items.AsEnumerable().ForEach(item => removeAllTabControl.AddItem(item)));
+            AddAssert("Ensure all items", () => removeAllTabControl.Items.Count() == items.Count());

             AddStep("Remove all items", () => removeAllTabControl.Clear());
             AddAssert("Ensure no items", () => !removeAllTabControl.Items.Any());


Fix juice streams not propagating accent colours to nested objects

--- osu.Game.Rulesets.Catch/Objects/Drawable/DrawableJuiceStream.cs
+++ osu.Game.Rulesets.Catch/Objects/Drawable/DrawableJuiceStream.cs
@@ -42,7 +42,11 @@

         protected override void AddNested(DrawableHitObject h)
         {
-            ((DrawableCatchHitObject)h).CheckPosition = o => CheckPosition?.Invoke(o) ?? false;
+            var catchObject = (DrawableCatchHitObject)h;
+
+            catchObject.CheckPosition = o => CheckPosition?.Invoke(o) ?? false;
+            catchObject.AccentColour = HitObject.ComboColour;
+
             dropletContainer.Add(h);
             base.AddNested(h);
         }


Consider shader manager for ruleset dependencies disposal testing

--- osu.Game.Tests/Rulesets/TestSceneDrawableRulesetDependencies.cs
+++ osu.Game.Tests/Rulesets/TestSceneDrawableRulesetDependencies.cs
@@ -13,6 +13,7 @@
 using osu.Framework.Graphics;
 using osu.Framework.Graphics.Containers;
 using osu.Framework.Graphics.OpenGL.Textures;
+using osu.Framework.Graphics.Shaders;
 using osu.Framework.Graphics.Shapes;
 using osu.Framework.Graphics.Textures;
 using osu.Framework.Testing;
@@ -31,12 +32,14 @@
             DrawableWithDependencies drawable = null;
             TestTextureStore textureStore = null;
             TestSampleStore sampleStore = null;
+            TestShaderManager shaderManager = null;

             AddStep("add dependencies", () =>
             {
                 Child = drawable = new DrawableWithDependencies();
                 textureStore = drawable.ParentTextureStore;
                 sampleStore = drawable.ParentSampleStore;
+                shaderManager = drawable.ParentShaderManager;
             });

             AddStep("clear children", Clear);
@@ -52,12 +55,14 @@

             AddAssert("parent texture store not disposed", () => !textureStore.IsDisposed);
             AddAssert("parent sample store not disposed", () => !sampleStore.IsDisposed);
+            AddAssert("parent shader manager not disposed", () => !shaderManager.IsDisposed);
         }

         private class DrawableWithDependencies : CompositeDrawable
         {
             public TestTextureStore ParentTextureStore { get; private set; }
             public TestSampleStore ParentSampleStore { get; private set; }
+            public TestShaderManager ParentShaderManager { get; private set; }

             public DrawableWithDependencies()
             {
@@ -70,6 +75,7 @@

                 dependencies.CacheAs<TextureStore>(ParentTextureStore = new TestTextureStore());
                 dependencies.CacheAs<ISampleStore>(ParentSampleStore = new TestSampleStore());
+                dependencies.CacheAs<ShaderManager>(ParentShaderManager = new TestShaderManager());

                 return new DrawableRulesetDependencies(new OsuRuleset(), dependencies);
             }
@@ -135,5 +141,18 @@

             public int PlaybackConcurrency { get; set; }
         }
+
+        private class TestShaderManager : ShaderManager
+        {
+            public override byte[] LoadRaw(string name) => null;
+
+            public bool IsDisposed { get; private set; }
+
+            protected override void Dispose(bool disposing)
+            {
+                base.Dispose(disposing);
+                IsDisposed = true;
+            }
+        }
     }
 }


Fix tests failing.

Fix tests failing.

--- osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs
+++ osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs
@@ -194,7 +194,8 @@
             AddStep("Transition to Results", () => player.Push(results = new FadeAccessibleResults(new ScoreInfo
             {
                 User = new User { Username = "osu!" },
-                Beatmap = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo
+                Beatmap = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo,
+                Ruleset = new OsuRuleset().RulesetInfo,
             })));

             AddUntilStep("Wait for results is current", () => results.IsCurrentScreen());


Update transfer host logic and simplify local user checks

--- osu.Game.Tests/Visual/Multiplayer/TestSceneMatchStartControl.cs
+++ osu.Game.Tests/Visual/Multiplayer/TestSceneMatchStartControl.cs
@@ -231,14 +231,13 @@
         {
             AddStep("add second user as host", () =>
             {
-                addUser(new APIUser { Id = 2, Username = "Another user" });
-                multiplayerClient.Object.TransferHost(2);
+                addUser(new APIUser { Id = 2, Username = "Another user" }, true);
             });

             AddStep("start countdown", () => multiplayerClient.Object.SendMatchRequest(new StartMatchCountdownRequest { Duration = TimeSpan.FromMinutes(1) }).WaitSafely());
             AddUntilStep("countdown started", () => multiplayerClient.Object.Room?.Countdown != null);

-            AddStep("transfer host to local user", () => multiplayerClient.Object.TransferHost(API.LocalUser.Value.OnlineID));
+            AddStep("transfer host to local user", () => transferHost(localUser));
             AddUntilStep("local user is host", () => multiplayerClient.Object.Room?.Host?.Equals(multiplayerClient.Object.LocalUser) == true);

             ClickButtonWhenEnabled<MultiplayerReadyButton>();
@@ -293,15 +292,14 @@
         {
             AddStep("add second user as host", () =>
             {
-                addUser(new APIUser { Id = 2, Username = "Another user" });
-                multiplayerClient.Object.TransferHost(2);
-            });
-
-            ClickButtonWhenEnabled<MultiplayerReadyButton>();
-            AddUntilStep("user is ready", () => multiplayerClient.Object.Room?.Users[0].State == MultiplayerUserState.Ready);
-
-            ClickButtonWhenEnabled<MultiplayerReadyButton>();
-            AddUntilStep("user is idle", () => multiplayerClient.Object.Room?.Users[0].State == MultiplayerUserState.Idle);
+                addUser(new APIUser { Id = 2, Username = "Another user" }, true);
+            });
+
+            ClickButtonWhenEnabled<MultiplayerReadyButton>();
+            AddUntilStep("user is ready", () => localUser.State == MultiplayerUserState.Ready);
+
+            ClickButtonWhenEnabled<MultiplayerReadyButton>();
+            AddUntilStep("user is idle", () => localUser.State == MultiplayerUserState.Idle);
         }

         [TestCase(true)]
@@ -310,14 +308,14 @@
         {
             AddStep("setup", () =>
             {
-                multiplayerClient.Object.TransferHost(multiplayerClient.Object.Room?.Users[0].UserID ?? 0);
+                transferHost(multiplayerRoom.Users[0]);

                 if (!allReady)
                     addUser(new APIUser { Id = 2, Username = "Another user" });
             });

             ClickButtonWhenEnabled<MultiplayerReadyButton>();
-            AddUntilStep("user is ready", () => multiplayerClient.Object.Room?.Users[0].State == MultiplayerUserState.Ready);
+            AddUntilStep("user is ready", () => localUser.State == MultiplayerUserState.Ready);

             verifyGameplayStartFlow();
         }
@@ -327,32 +325,31 @@
         {
             AddStep("add host", () =>
             {
+                addUser(new APIUser { Id = 2, Username = "Another user" }, true);
+            });
+
+            ClickButtonWhenEnabled<MultiplayerReadyButton>();
+
+            AddStep("make user host", () => transferHost(localUser));
+
+            verifyGameplayStartFlow();
+        }
+
+        [Test]
+        public void TestLoseHostWhileReady()
+        {
+            AddStep("setup", () =>
+            {
                 addUser(new APIUser { Id = 2, Username = "Another user" });
-                multiplayerClient.Object.TransferHost(2);
-            });
-
-            ClickButtonWhenEnabled<MultiplayerReadyButton>();
-            AddStep("make user host", () => multiplayerClient.Object.TransferHost(multiplayerClient.Object.Room?.Users[0].UserID ?? 0));
-
-            verifyGameplayStartFlow();
-        }
-
-        [Test]
-        public void TestLoseHostWhileReady()
-        {
-            AddStep("setup", () =>
-            {
-                multiplayerClient.Object.TransferHost(multiplayerClient.Object.Room?.Users[0].UserID ?? 0);
-                addUser(new APIUser { Id = 2, Username = "Another user" });
-            });
-
-            ClickButtonWhenEnabled<MultiplayerReadyButton>();
-            AddUntilStep("user is ready", () => multiplayerClient.Object.Room?.Users[0].State == MultiplayerUserState.Ready);
-
-            AddStep("transfer host", () => multiplayerClient.Object.TransferHost(multiplayerClient.Object.Room?.Users[1].UserID ?? 0));
-
-            ClickButtonWhenEnabled<MultiplayerReadyButton>();
-            AddUntilStep("user is idle (match not started)", () => multiplayerClient.Object.Room?.Users[0].State == MultiplayerUserState.Idle);
+            });
+
+            ClickButtonWhenEnabled<MultiplayerReadyButton>();
+            AddUntilStep("user is ready", () => localUser.State == MultiplayerUserState.Ready);
+
+            AddStep("transfer host", () => transferHost(multiplayerRoom.Users[1]));
+
+            ClickButtonWhenEnabled<MultiplayerReadyButton>();
+            AddUntilStep("user is idle (match not started)", () => localUser.State == MultiplayerUserState.Idle);
             AddUntilStep("ready button enabled", () => control.ChildrenOfType<OsuButton>().Single().Enabled.Value);
         }

@@ -363,13 +360,10 @@
             const int users = 10;
             AddStep("setup", () =>
             {
-                multiplayerClient.Object.TransferHost(multiplayerClient.Object.Room?.Users[0].UserID ?? 0);
+                transferHost(localUser);
                 for (int i = 0; i < users; i++)
-                    addUser(new APIUser { Id = i, Username = "Another user" });
-            });
-
-            if (!isHost)
-                AddStep("transfer host", () => multiplayerClient.Object.TransferHost(2));
+                    addUser(new APIUser { Id = i, Username = "Another user" }, !isHost && i == 2);
+            });

             ClickButtonWhenEnabled<MultiplayerReadyButton>();

@@ -388,14 +382,14 @@

         private void verifyGameplayStartFlow()
         {
-            AddUntilStep("user is ready", () => multiplayerClient.Object.Room?.Users[0].State == MultiplayerUserState.Ready);
-            ClickButtonWhenEnabled<MultiplayerReadyButton>();
-            AddUntilStep("user waiting for load", () => multiplayerClient.Object.Room?.Users[0].State == MultiplayerUserState.WaitingForLoad);
+            AddUntilStep("user is ready", () => localUser.State == MultiplayerUserState.Ready);
+            ClickButtonWhenEnabled<MultiplayerReadyButton>();
+            AddUntilStep("user waiting for load", () => localUser.State == MultiplayerUserState.WaitingForLoad);

             AddStep("finish gameplay", () =>
             {
-                changeUserState(multiplayerClient.Object.Room?.Users[0].UserID ?? 0, MultiplayerUserState.Loaded);
-                changeUserState(multiplayerClient.Object.Room?.Users[0].UserID ?? 0, MultiplayerUserState.FinishedPlay);
+                changeUserState(localUser.UserID, MultiplayerUserState.Loaded);
+                changeUserState(localUser.UserID, MultiplayerUserState.FinishedPlay);
             });

             AddUntilStep("ready button enabled", () => control.ChildrenOfType<OsuButton>().Single().Enabled.Value);
@@ -420,8 +414,14 @@
             multiplayerRoom.Users.Add(multiplayerRoomUser);

             if (asHost)
-                multiplayerRoom.Host = multiplayerRoomUser;
-
+                transferHost(multiplayerRoomUser);
+
+            raiseRoomUpdated();
+        }
+
+        private void transferHost(MultiplayerRoomUser user)
+        {
+            multiplayerRoom.Host = user;
             raiseRoomUpdated();
         }


Fix overlapping variable usage

Fix overlapping variable usage

--- osu.Game.Tests/Visual/UserInterface/TestSceneModSelectScreen.cs
+++ osu.Game.Tests/Visual/UserInterface/TestSceneModSelectScreen.cs
@@ -59,7 +59,7 @@
             AddUntilStep("two panels active", () => modSelectScreen.ChildrenOfType<ModPanel>().Count(panel => panel.Active.Value) == 2);
             AddAssert("mod multiplier correct", () =>
             {
-                double multiplier = SelectedMods.Value.Aggregate(1d, (multiplier, mod) => multiplier * mod.ScoreMultiplier);
+                double multiplier = SelectedMods.Value.Aggregate(1d, (m, mod) => m * mod.ScoreMultiplier);
                 return Precision.AlmostEquals(multiplier, modSelectScreen.ChildrenOfType<DifficultyMultiplierDisplay>().Single().Current.Value);
             });
             assertCustomisationToggleState(disabled: false, active: false);
@@ -73,7 +73,7 @@
             AddUntilStep("two panels active", () => modSelectScreen.ChildrenOfType<ModPanel>().Count(panel => panel.Active.Value) == 2);
             AddAssert("mod multiplier correct", () =>
             {
-                double multiplier = SelectedMods.Value.Aggregate(1d, (multiplier, mod) => multiplier * mod.ScoreMultiplier);
+                double multiplier = SelectedMods.Value.Aggregate(1d, (m, mod) => m * mod.ScoreMultiplier);
                 return Precision.AlmostEquals(multiplier, modSelectScreen.ChildrenOfType<DifficultyMultiplierDisplay>().Single().Current.Value);
             });
             assertCustomisationToggleState(disabled: false, active: false);


Fix Main file issues

Fix Main file issues

--- osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs
+++ osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs
@@ -18,7 +18,6 @@
 {
     public class ColourHitErrorMeter : HitErrorMeter
     {
-        private const int default_shape_alpha = 0;
         private const int animation_duration = 200;
         private const int drawable_judgement_size = 8;

@@ -35,7 +34,7 @@
         {
             MinValue = 0.01f,
             MaxValue = 1,
-            Precision = .01f,
+            Precision = 0.01f,
         };

         [SettingSource("Spacing", "Space between hit error shapes")]
@@ -43,10 +42,10 @@
         {
             MinValue = 0,
             MaxValue = 10,
-            Precision = .1f
+            Precision = 0.1f
         };

-        [SettingSource("Shape", "What shape to use for hit errors")]
+        [SettingSource("Shape", "The shape of each displayed error")]
         public Bindable<ShapeStyle> HitShape { get; } = new Bindable<ShapeStyle>();

         private readonly JudgementFlow judgementsFlow;
@@ -81,7 +80,7 @@
             }, true);
             HitShape.BindValueChanged(_ =>
             {
-                judgementsFlow.ValueParser = getShapeStyle(HitShape.Value);
+                judgementsFlow.Shape = getShapeStyle(HitShape.Value);
                 judgementsFlow.Clear();
             }, true);
         }
@@ -91,7 +90,7 @@
         private class JudgementFlow : FillFlowContainer<HitErrorShape>
         {
             public override IEnumerable<Drawable> FlowingChildren => base.FlowingChildren.Reverse();
-            internal string ValueParser = null!;
+            internal string Shape = null!;

             public JudgementFlow()
             {
@@ -103,7 +102,7 @@

             public void Push(Color4 colour, int maxErrorShapeCount)
             {
-                Add(new HitErrorShape(colour, drawable_judgement_size, ValueParser));
+                Add(new HitErrorShape(colour, drawable_judgement_size, Shape));

                 if (Children.Count > maxErrorShapeCount)
                     Children.FirstOrDefault(c => !c.IsRemoved)?.Remove();
@@ -124,7 +123,7 @@
                         Child = new Circle
                         {
                             RelativeSizeAxes = Axes.Both,
-                            Alpha = default_shape_alpha,
+                            Alpha = 0,
                             Colour = colour
                         };
                         break;
@@ -133,7 +132,7 @@
                         Child = new Box
                         {
                             RelativeSizeAxes = Axes.Both,
-                            Alpha = default_shape_alpha,
+                            Alpha = 0,
                             Colour = colour
                         };
                         break;


Allow the user to click the menu item several times and handle the case when the temp file has been deleted. Some refactoring too.

--- EditProj/EditProjPackage.cs
+++ EditProj/EditProjPackage.cs
@@ -14,6 +14,7 @@
 using Microsoft.VisualStudio.TextManager.Interop;
 using EnvDTE;
 using System.Collections.Generic;
+using System.Linq;

 namespace rdomunozcom.EditProj
 {
@@ -90,66 +91,6 @@
             }
         }

-        private static bool IsSingleProjectItemSelection(out IVsHierarchy hierarchy, out uint itemid)
-        {
-            hierarchy = null;
-            itemid = VSConstants.VSITEMID_NIL;
-            int hr = VSConstants.S_OK;
-
-            IVsMonitorSelection monitorSelection = Package.GetGlobalService(typeof(SVsShellMonitorSelection)) as IVsMonitorSelection;
-            var solution = Package.GetGlobalService(typeof(SVsSolution)) as IVsSolution;
-            if (monitorSelection == null || solution == null)
-            {
-                return false;
-            }
-
-            IVsMultiItemSelect multiItemSelect = null;
-            IntPtr hierarchyPtr = IntPtr.Zero;
-            IntPtr selectionContainerPtr = IntPtr.Zero;
-
-            try
-            {
-                hr = monitorSelection.GetCurrentSelection(out hierarchyPtr, out itemid, out multiItemSelect, out selectionContainerPtr);
-
-                if (ErrorHandler.Failed(hr) || hierarchyPtr == IntPtr.Zero || itemid == VSConstants.VSITEMID_NIL)
-                {
-                    // there is no selection
-                    return false;
-                }
-
-                // multiple items are selected
-                if (multiItemSelect != null) return false;
-
-                // there is a hierarchy root node selected, thus it is not a single item inside a project
-
-                if (itemid == VSConstants.VSITEMID_ROOT) return true;
-
-                hierarchy = Marshal.GetObjectForIUnknown(hierarchyPtr) as IVsHierarchy;
-                if (hierarchy == null) return false;
-
-                Guid guidProjectID = Guid.Empty;
-
-                if (ErrorHandler.Failed(solution.GetGuidOfProject(hierarchy, out guidProjectID)))
-                {
-                    return false; // hierarchy is not a project inside the Solution if it does not have a ProjectID Guid
-                }
-
-                // if we got this far then there is a single project item selected
-                return true;
-            }
-            finally
-            {
-                if (selectionContainerPtr != IntPtr.Zero)
-                {
-                    Marshal.Release(selectionContainerPtr);
-                }
-
-                if (hierarchyPtr != IntPtr.Zero)
-                {
-                    Marshal.Release(hierarchyPtr);
-                }
-            }
-        }
         #endregion

         /// <summary>
@@ -159,6 +100,42 @@
         /// </summary>
         private void MenuItemCallback(object sender, EventArgs e)
         {
+            try
+            {
+                string projFilePath = GetPathOfSelectedItem();
+                string tempProjFilePath;
+
+                if (DocumentAlreadyOpen(projFilePath, out tempProjFilePath))
+                {
+                    tempProjFilePath = GetTempFileFor(projFilePath);
+                }
+                else
+                {
+                    if (tempProjFilePath != null)
+                    {
+                        this.tempToProjFiles.Remove(tempProjFilePath);
+                    }
+
+                    tempProjFilePath = CreateTempFileWithContentsOf(projFilePath);
+                    this.tempToProjFiles[tempProjFilePath] = projFilePath;
+                }
+
+                OpenFileInEditor(tempProjFilePath);
+            }
+
+            catch (Exception ex)
+            {
+                Debug.WriteLine(string.Format("There was an exception: {0}", ex));
+            }
+        }
+
+        private string GetTempFileFor(string projFilePath)
+        {
+            return this.tempToProjFiles.FirstOrDefault(kv => kv.Value == projFilePath).Key;
+        }
+
+        private string GetPathOfSelectedItem()
+        {
             IVsUIShellOpenDocument openDocument = Package.GetGlobalService(typeof(SVsUIShellOpenDocument)) as IVsUIShellOpenDocument;

             IVsMonitorSelection monitorSelection = Package.GetGlobalService(typeof(SVsShellMonitorSelection)) as IVsMonitorSelection;
@@ -178,19 +155,35 @@
             // Get the file path
             string projFilePath = null;
             ((IVsProject)hierarchy).GetMkDocument(itemid, out projFilePath);
-
-            string projectData = File.ReadAllText(projFilePath);
+            return projFilePath;
+        }
+
+        private static string CreateTempFileWithContentsOf(string filePath)
+        {
+            string projectData = File.ReadAllText(filePath);
             string tempDir = Path.GetTempPath();
             string tempProjFile = Guid.NewGuid().ToString() + ".xml";
             string tempProjFilePath = Path.Combine(tempDir, tempProjFile);
-            this.tempToProjFiles[tempProjFilePath] = projFilePath;
             File.WriteAllText(tempProjFilePath, projectData);

-            OpenFileInEditor(Path.Combine(tempDir, tempProjFilePath), Resources.Project, uiHierarchy, itemid);
-        }
-
-
-        private void OpenFileInEditor(string filePath, string fileName, IVsUIHierarchy uiHierarchy, UInt32 itemID, bool openWith = false)
+            return tempProjFilePath;
+        }
+
+        private bool DocumentAlreadyOpen(string projFilePath, out string tempProjFile)
+        {
+            bool haveOpened = this.tempToProjFiles.Values.Contains(projFilePath);
+            tempProjFile = null;
+            if (haveOpened)
+            {
+                tempProjFile = GetTempFileFor(projFilePath);
+                return File.Exists(tempProjFile);
+            }
+
+            return false;
+        }
+
+
+        private void OpenFileInEditor(string filePath)
         {
             this.dte.ExecuteCommand("File.OpenFile", filePath);
         }


All in one uploaded

All in one uploaded

--- Scripts/Water.cs
+++ Scripts/Water.cs
@@ -1,24 +0,0 @@
-using UnityEngine;
-using System.Collections;
-
-public class Water : MonoBehaviour {
-
-
-
-    //Water specific
-    public Health health;
-    public Movement movement;
-
-    void Start()
-    {
-        health = GetComponent<Health>();
-        movement = GetComponent<Movement>();
-    }
-
-    void OnEnable()
-    {
-        movement.gravity = 5f;
-        movement.jumpSpeed = 15f;
-        movement.speed = 1.5f;
-    }
-}


Fix some duplicate keys for pull requests with the same branch name

--- ForkStalkSharp/ForkStalk.cs
+++ ForkStalkSharp/ForkStalk.cs
@@ -102,14 +102,16 @@
 			var forks = forksTask.Result.Where (f => f.PushedAt >= SinceUtc)
 				.OrderByDescending (f => f.PushedAt)
 				.Take (forkCount);
-			var pullRequests = pullRequestsTask.Result.ToDictionary (p => p.Head.Ref, p => p);
+			var pullRequests = pullRequestsTask.Result.ToDictionary (p => string.Format("{0}/{1}",
+				p.User.Login,
+				p.Head.Ref));

 			// Look for new commits.
 			Parallel.ForEach (forks, fork => {
 				var forkBranches = client.Repository.GetAllBranches (fork.Owner.Login, fork.Name).Result;
 				Parallel.ForEach(forkBranches, branch => {
 					// Check for any open pull request.
-					if (pullRequests.ContainsKey (branch.Name))
+					if (pullRequests.ContainsKey (string.Format ("{0}/{1}", fork.Owner.Login, branch.Name)))
 						return;

 					var forkCommit = client.Repository.Commits.Get (fork.Owner.Login, fork.Name, branch.Name).Result;


Removed an extra call.

Removed an extra call.

--- GitTfs/Core/TfsWorkspace.cs
+++ GitTfs/Core/TfsWorkspace.cs
@@ -40,7 +40,7 @@
                 var shelveset = new Shelveset(_workspace.VersionControlServer, shelvesetName, _workspace.OwnerName);
                 shelveset.Comment = _checkinOptions.CheckinComment;
                 shelveset.WorkItemInfo = GetWorkItemInfos();
-                _workspace.Shelve(shelveset, _workspace.GetPendingChanges(), _checkinOptions.Force ? ShelvingOptions.Replace : ShelvingOptions.None);
+                _workspace.Shelve(shelveset, pendingChanges, _checkinOptions.Force ? ShelvingOptions.Replace : ShelvingOptions.None);
             }
         }


DistributeInThreadPool

DistributeInThreadPool

--- Grit.ACE/Events/EventBus.cs
+++ Grit.ACE/Events/EventBus.cs
@@ -40,34 +40,15 @@
             ServiceLocator.BusLogger.EventPublish(@event);
             if (@event.ShouldDistributeInCurrentThread())
             {
-                DistributeInCurrentThread(@event);
+                Invoke((dynamic)@event);
             }
             if (@event.ShouldDistributeInThreadPool())
             {
-                DistributeInThreadPool(@event);
+                DistributeInThreadPool((dynamic)@event);
             }
             if (ServiceLocator.EventShouldDistributeToExternalQueue && @event.ShouldDistributeToExternalQueue())
             {
                 DistributeToExternalQueue(@event);
-            }
-        }
-
-        private void DistributeInCurrentThread<T>(T @event) where T : Event
-        {
-            var handlers = _eventHandlerFactory.GetHandlers<T>();
-            if (handlers != null)
-            {
-                foreach (var handler in handlers)
-                {
-                    try
-                    {
-                        handler.Handle(@event);
-                    }
-                    catch (Exception ex)
-                    {
-                        ServiceLocator.BusLogger.Exception(@event, ex);
-                    }
-                }
             }
         }

@@ -76,6 +57,8 @@
             var handlers = _eventHandlerFactory.GetHandlers<T>();
             if (handlers != null)
             {
+                @event.Recevied();
+                ServiceLocator.BusLogger.EventHandle(@event);
                 foreach (var handler in handlers)
                 {
                     // handle event in thread pool
@@ -111,10 +94,10 @@
             var handlers = _eventHandlerFactory.GetHandlers<T>();
             if (handlers != null)
             {
+                @event.Recevied();
+                ServiceLocator.BusLogger.EventHandle(@event);
                 foreach (var handler in handlers)
                 {
-                    @event.Recevied();
-                    ServiceLocator.BusLogger.EventHandle(@event);
                     try
                     {
                         // handle event in current thread


[Modify] Do not decode

[Modify] Do not decode

--- websocket-sharp/Server/WebSocketServiceManager.cs
+++ websocket-sharp/Server/WebSocketServiceManager.cs
@@ -985,7 +985,7 @@
         throw new ArgumentException (msg, "path");
       }

-      path = HttpUtility.UrlDecode (path).TrimSlashFromEnd ();
+      path = path.TrimSlashFromEnd ();

       WebSocketServiceHost host;
       lock (_sync) {


Apply track looping via bass, not manually

--- osu.Framework/Audio/Track/TrackBass.cs
+++ osu.Framework/Audio/Track/TrackBass.cs
@@ -109,13 +109,10 @@
                     stopCallback = new SyncCallback((a, b, c, d) => RaiseFailed());
                     endCallback = new SyncCallback((a, b, c, d) =>
                     {
-                        if (Looping)
-                            EnqueueAction(() => Restart());
-                        else
-                        {
-                            hasCompleted = true;
-                            RaiseCompleted();
-                        }
+                        if (Looping) return;
+
+                        hasCompleted = true;
+                        RaiseCompleted();
                     });

                     Bass.ChannelSetSync(activeStream, SyncFlags.Stop, 0, stopCallback.Callback, stopCallback.Handle);
@@ -130,6 +127,12 @@

             InvalidateState();
         }
+
+        private void setLoopFlag(bool value) => EnqueueAction(() =>
+        {
+            if (activeStream != 0)
+                Bass.ChannelFlags(activeStream, value ? BassFlags.Loop : BassFlags.Default, BassFlags.Loop);
+        });

         private int prepareStream(Stream data, bool quick)
         {
@@ -278,7 +281,19 @@
             if (relativeFrequencyHandler.IsFrequencyZero)
                 return true;

+            setLoopFlag(Looping);
+
             return Bass.ChannelPlay(activeStream);
+        }
+
+        public override bool Looping
+        {
+            get => base.Looping;
+            set
+            {
+                base.Looping = value;
+                setLoopFlag(Looping);
+            }
         }

         public override bool Seek(double seek) => SeekAsync(seek).Result;


Try-catch the PrePerform step

Try-catch the PrePerform step

--- osu.Framework/IO/Network/WebRequest.cs
+++ osu.Framework/IO/Network/WebRequest.cs
@@ -246,10 +246,9 @@
             using (timeoutToken = new CancellationTokenSource())
             using (linkedToken = CancellationTokenSource.CreateLinkedTokenSource(abortToken.Token, timeoutToken.Token))
             {
-                PrePerform();
-
                 try
                 {
+                    PrePerform();
                     reportForwardProgress();

                     HttpRequestMessage request;


Add method for checking if cursor should rotate

--- osu.Game/Graphics/Cursor/MenuCursor.cs
+++ osu.Game/Graphics/Cursor/MenuCursor.cs
@@ -83,8 +83,9 @@
                 activeCursor.AdditiveLayer.FadeInFromZero(800, Easing.OutQuint);
             }

-            if ((e.Button == MouseButton.Left || e.Button == MouseButton.Right) && cursorRotate.Value)
+            if (shouldRotate(e) && cursorRotate.Value)
             {
+                // if cursor is already rotating don't reset its rotate origin
                 if (!(dragRotationState == DragRotationState.Rotating))
                 {
                     dragRotationState = DragRotationState.DragStarted;
@@ -97,13 +98,14 @@

         protected override void OnMouseUp(MouseUpEvent e)
         {
-            if (!e.IsPressed(MouseButton.Left) && !e.IsPressed(MouseButton.Middle) && !e.IsPressed(MouseButton.Right))
+            // cursor should go back to original size when none of main buttons are pressed
+            if (!(e.IsPressed(MouseButton.Left) || e.IsPressed(MouseButton.Middle) || e.IsPressed(MouseButton.Right)))
             {
                 activeCursor.AdditiveLayer.FadeOutFromOne(500, Easing.OutQuint);
                 activeCursor.ScaleTo(1, 500, Easing.OutElastic);
             }

-            if (!e.IsPressed(MouseButton.Left) && !e.IsPressed(MouseButton.Right))
+            if (!shouldRotate(e))
             {
                 if (dragRotationState == DragRotationState.Rotating)
                     activeCursor.RotateTo(0, 600 * (1 + Math.Abs(activeCursor.Rotation / 720)), Easing.OutElasticHalf);
@@ -123,6 +125,14 @@
         {
             activeCursor.FadeTo(0, 250, Easing.OutQuint);
             activeCursor.ScaleTo(0.6f, 250, Easing.In);
+        }
+
+        private static bool shouldRotate(MouseEvent e)
+        {
+            if (e.IsPressed(MouseButton.Left) || e.IsPressed(MouseButton.Right))
+                return true;
+            else
+                return false;
         }

         public class Cursor : Container


Reduce 'cursor-tap' sample playback volume on MouseUp

--- osu.Game/Graphics/Cursor/MenuCursor.cs
+++ osu.Game/Graphics/Cursor/MenuCursor.cs
@@ -140,6 +140,7 @@
             // Scale to [-0.75, 0.75] so that the sample isn't fully panned left or right (sounds weird)
             channel.Balance.Value = ((activeCursor.X / DrawWidth) * 2 - 1) * 0.75;
             channel.Frequency.Value = baseFrequency - (random_range / 2f) + RNG.NextDouble(random_range);
+            channel.Volume.Value = baseFrequency;

             channel.Play();
         }


Don't use in music player for now

Don't use in music player for now

--- osu.Game/Overlays/NowPlayingOverlay.cs
+++ osu.Game/Overlays/NowPlayingOverlay.cs
@@ -351,7 +351,6 @@
                 RelativeSizeAxes = Axes.Both;

                 CacheDrawnFrameBuffer = true;
-                RedrawOnScale = false;

                 Children = new Drawable[]
                 {


Better variable name

Better variable name

--- osu.Game/Overlays/Profile/RankGraph.cs
+++ osu.Game/Overlays/Profile/RankGraph.cs
@@ -91,11 +91,11 @@
             graph.Colour = colours.Yellow;
         }

-        private void userChanged(User newUser)
+        private void userChanged(User user)
         {
             placeholder.FadeIn(fade_duration, Easing.Out);

-            if (newUser == null)
+            if (user == null)
             {
                 rankText.Text = string.Empty;
                 performanceText.Text = string.Empty;
@@ -105,7 +105,7 @@
                 return;
             }

-            int[] userRanks = newUser.RankHistory?.Data ?? new[] { newUser.Statistics.Rank };
+            int[] userRanks = user.RankHistory?.Data ?? new[] { user.Statistics.Rank };
             ranks = userRanks.Select((x, index) => new KeyValuePair<int, int>(index, x)).Where(x => x.Value != 0).ToArray();

             if (ranks.Length > 1)


Use beatmap card in solo spectator screen

--- osu.Game/Screens/Play/SoloSpectator.cs
+++ osu.Game/Screens/Play/SoloSpectator.cs
@@ -12,6 +12,7 @@
 using osu.Framework.Threading;
 using osu.Game.Audio;
 using osu.Game.Beatmaps;
+using osu.Game.Beatmaps.Drawables.Cards;
 using osu.Game.Configuration;
 using osu.Game.Graphics;
 using osu.Game.Graphics.Sprites;
@@ -20,7 +21,7 @@
 using osu.Game.Online.API.Requests;
 using osu.Game.Online.API.Requests.Responses;
 using osu.Game.Online.Spectator;
-using osu.Game.Overlays.BeatmapListing.Panels;
+using osu.Game.Overlays;
 using osu.Game.Overlays.Settings;
 using osu.Game.Rulesets;
 using osu.Game.Screens.OnlinePlay.Match.Components;
@@ -52,6 +53,9 @@
         [Resolved]
         private BeatmapModelDownloader beatmapDownloader { get; set; }

+        [Cached]
+        private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple);
+
         private Container beatmapPanelContainer;
         private TriangleButton watchButton;
         private SettingsCheckbox automaticDownload;
@@ -73,7 +77,7 @@
         }

         [BackgroundDependencyLoader]
-        private void load(OsuColour colours, OsuConfigManager config)
+        private void load(OsuConfigManager config)
         {
             InternalChild = new Container
             {
@@ -88,7 +92,7 @@
                 {
                     new Box
                     {
-                        Colour = colours.GreySeafoamDark,
+                        Colour = colourProvider.Background5,
                         RelativeSizeAxes = Axes.Both,
                     },
                     new FillFlowContainer
@@ -229,7 +233,7 @@
             onlineBeatmapRequest.Success += beatmapSet => Schedule(() =>
             {
                 this.beatmapSet = beatmapSet;
-                beatmapPanelContainer.Child = new GridBeatmapPanel(this.beatmapSet);
+                beatmapPanelContainer.Child = new BeatmapCard(this.beatmapSet);
                 checkForAutomaticDownload();
             });


Fix to Tween when reversing while playing

--- Raccoon/Util/Tween/Tween.cs
+++ Raccoon/Util/Tween/Tween.cs
@@ -86,10 +86,10 @@
             }

             Timer += (uint) delta;
-            Time = Math.Clamp(Timer / (float) Duration, 0, 1);
+            Time = Math.Clamp(Timer / (float) Duration, 0f, 1f);

             foreach (Lerper lerp in _lerpers.Values) {
-                lerp.Interpolate(IsReverse ? 1 - Time : Time);
+                lerp.Interpolate(IsReverse ? 1f - Time : Time);
             }

             _onUpdate?.Invoke();
@@ -104,7 +104,7 @@
                     IsPlaying = false;
                     HasEnded = true;
                 } else {
-                    Timer = 0;
+                    Timer = Timer - (uint) Duration;
                 }

                 _onEnd?.Invoke();
@@ -119,8 +119,14 @@
             Time = 0;
             IsReverse = _startReverse;

-            foreach (Lerper lerp in _lerpers.Values) {
-                lerp.Begin();
+            if (IsForward) {
+                foreach (Lerper lerp in _lerpers.Values) {
+                    lerp.Begin();
+                }
+            } else {
+                foreach (Lerper lerp in _lerpers.Values) {
+                    lerp.End();
+                }
             }
         }

@@ -198,12 +204,28 @@
         }

         public Tween Reverse() {
+            if (IsReverse) {
+                return this;
+            }
+
+            if (IsPlaying) {
+                Timer = (uint) ((1f - Time) * Duration);
+            }
+
             IsReverse = true;
             _startReverse = true;
             return this;
         }

         public Tween Forward() {
+            if (IsForward) {
+                return this;
+            }
+
+            if (IsPlaying) {
+                Timer = (uint) ((1f - Time) * Duration);
+            }
+
             IsForward = true;
             _startReverse = false;
             return this;


#42 support chart, table, list, and image insert

--- RdlDesign/RdlUserControl.cs
+++ RdlDesign/RdlUserControl.cs
@@ -407,29 +407,52 @@
             ToolStripButton ctl = (ToolStripButton)sender;
             ctlInsertCurrent = ctl.Checked ? ctl : null;

-
             CurrentInsert = ctlInsertCurrent == null ? null : (string)ctlInsertCurrent.Tag;

         }

         private void chartToolStripButton1_Click(object sender, EventArgs e)
         {
-
+            if (ctlInsertCurrent != null)
+                ctlInsertCurrent.Checked = false;
+
+            ToolStripButton ctl = (ToolStripButton)sender;
+            ctlInsertCurrent = ctl.Checked ? ctl : null;
+
+            CurrentInsert = ctlInsertCurrent == null ? null : (string)ctlInsertCurrent.Tag;
         }

         private void tableToolStripButton1_Click(object sender, EventArgs e)
         {
-
+            if (ctlInsertCurrent != null)
+                ctlInsertCurrent.Checked = false;
+
+            ToolStripButton ctl = (ToolStripButton)sender;
+            ctlInsertCurrent = ctl.Checked ? ctl : null;
+
+            CurrentInsert = ctlInsertCurrent == null ? null : (string)ctlInsertCurrent.Tag;
         }

         private void listToolStripButton1_Click(object sender, EventArgs e)
         {
-
+            if (ctlInsertCurrent != null)
+                ctlInsertCurrent.Checked = false;
+
+            ToolStripButton ctl = (ToolStripButton)sender;
+            ctlInsertCurrent = ctl.Checked ? ctl : null;
+
+            CurrentInsert = ctlInsertCurrent == null ? null : (string)ctlInsertCurrent.Tag;
         }

         private void imageToolStripButton1_Click(object sender, EventArgs e)
         {
-
+            if (ctlInsertCurrent != null)
+                ctlInsertCurrent.Checked = false;
+
+            ToolStripButton ctl = (ToolStripButton)sender;
+            ctlInsertCurrent = ctl.Checked ? ctl : null;
+
+            CurrentInsert = ctlInsertCurrent == null ? null : (string)ctlInsertCurrent.Tag;
         }

         private void matrixToolStripButton1_Click(object sender, EventArgs e)


メソッドがNULLだった場合も通す

メソッドがNULLだった場合も通す

--- Sdx/Scaffold/Config/Value.cs
+++ Sdx/Scaffold/Config/Value.cs
@@ -65,11 +65,6 @@
       else
       {
         var method = type.GetMethod(value.ToString());
-        if (method == null)
-        {
-          throw new NotImplementedException("Missing " + value.ToString() + " method in " + type);
-        }
-
         return method;
       }
     }


fixed a bug in the test

fixed a bug in the test

--- SendGrid/Tests/TestHeader.cs
+++ SendGrid/Tests/TestHeader.cs
@@ -63,7 +63,7 @@
             var test = new Header();
             test.AddFilterSetting("foo", new List<string> { "a", "b" }, "bar");
             var result = test.AsJson();
-            Assert.AreEqual("{\"filters\" : {\"foo\" : {\"settings\" : {\"a\" : {\"b\" : \"bar\"}}}}", result);
+            Assert.AreEqual("{\"filters\" : {\"foo\" : {\"settings\" : {\"a\" : {\"b\" : \"bar\"}}}}}", result);

         }


fixed typo on EditCartLine implementation

--- ShoppingCart/ShoppingCart.cs
+++ ShoppingCart/ShoppingCart.cs
@@ -94,7 +94,7 @@
             return m_AsyncResult;
         }

-        public void EndEditCartLine(IAsyncResult asyncResult0
+        public void EndEditCartLine(IAsyncResult asyncResult)
         {
             if(m_AsyncResult != null)
                 m_AsyncResult.AsyncWaitHandle.WaitOne();