Commented out tests that have not been written

--- aaLogReader.Tests/aaLogReaderTests/aaLogReaderTests.cs
+++ aaLogReader.Tests/aaLogReaderTests/aaLogReaderTests.cs
@@ -349,184 +349,184 @@
             Assert.That(lr.HostFQDN, Is.EqualTo(_expectedFqdn), "HostFQDN is wrong");
         }

-        [Test]
-        public void GetRecordByMessageNumber()
-        {
-            Assert.That(false, "TODO");
-        }
-
-        [Test]
-        public void GetRecordByFileTime()
-        {
-            Assert.That(false, "TODO");
-        }
-
-        [Test]
-        public void GetRecordByFileTimeTest()
-        {
-            Assert.Fail("TODO");
-        }
-
-        [Test]
-        public void GetRecordByTimestampTest()
-        {
-            Assert.Fail("TODO");
-        }
-
-        [Test]
-        public void aaLogReaderTest()
-        {
-            Assert.Fail("TODO");
-        }
-
-        [Test]
-        public void DisposeTest()
-        {
-            Assert.Fail("TODO");
-        }
-
-        [Test]
-        public void OpenLogFileTest()
-        {
-            Assert.Fail("TODO");
-        }
-
-        [Test]
-        public void OpenCurrentLogFileTest()
-        {
-            Assert.Fail("TODO");
-        }
-
-        [Test]
-        public void CloseCurrentLogFileTest()
-        {
-            Assert.Fail("TODO");
-        }
-
-        [Test]
-        public void ReadLogHeaderTest()
-        {
-            Assert.Fail("TODO");
-        }
-
-        [Test]
-        public void ReadLogHeaderTest1()
-        {
-            Assert.Fail("TODO");
-        }
-
-        [Test]
-        public void GetFirstRecordTest()
-        {
-            Assert.Fail("TODO");
-        }
-
-        [Test]
-        public void GetLastRecordTest()
-        {
-            Assert.Fail("TODO");
-        }
-
-        [Test]
-        public void GetNextRecordTest()
-        {
-            Assert.Fail("TODO");
-        }
-
-        [Test]
-        public void GetPrevRecordTest()
-        {
-            Assert.Fail("TODO");
-        }
-
-        [Test]
-        public void GetLogFilePathsForMessageNumberTest()
-        {
-            Assert.Fail("TODO");
-        }
-
-        [Test]
-        public void GetLogFilePathsForMessageTimestampTest()
-        {
-            Assert.Fail("TODO");
-        }
-
-        [Test]
-        public void GetLogFilePathsForMessageFileTimeTest()
-        {
-            Assert.Fail("TODO");
-        }
-
-        [Test]
-        public void GetRecordByMessageNumberTest()
-        {
-            Assert.Fail("TODO");
-        }
-
-        [Test]
-        public void GetRecordsByStartMessageNumberAndCountTest()
-        {
-            Assert.Fail("TODO");
-        }
-
-        [Test]
-        public void GetRecordsByEndMessageNumberAndCountTest()
-        {
-            Assert.Fail("TODO");
-        }
-
-        [Test]
-        public void GetRecordsByMessageNumberAndCountTest()
-        {
-            Assert.Fail("TODO");
-        }
-
-        [Test]
-        public void GetRecordsByStartandEndMessageNumberTest()
-        {
-            Assert.Fail("TODO");
-        }
-
-        [Test]
-        public void GetRecordsByEndFileTimeAndCountTest()
-        {
-            Assert.Fail("TODO");
-        }
-
-        [Test]
-        public void GetRecordsByEndTimestampAndCountTest()
-        {
-            Assert.Fail("TODO");
-        }
-
-        [Test]
-        public void GetRecordsByStartFileTimeAndCountTest()
-        {
-            Assert.Fail("TODO");
-        }
-
-        [Test]
-        public void GetRecordsByStartTimestampAndCountTest()
-        {
-            Assert.Fail("TODO");
-        }
-
-        [Test]
-        public void GetRecordsByStartAndEndFileTimeTest()
-        {
-            Assert.Fail("TODO");
-        }
-
-        [Test]
-        public void GetRecordsByStartAndEndTimeStampTest()
-        {
-            Assert.Fail("TODO");
-        }
-
-        [Test]
-        public void GetUnreadRecordsTest()
-        {
-            Assert.Fail("TODO");
-        }
+        //[Test]
+        //public void GetRecordByMessageNumber()
+        //{
+        //    Assert.That(false, "TODO");
+        //}
+
+        //[Test]
+        //public void GetRecordByFileTime()
+        //{
+        //    Assert.That(false, "TODO");
+        //}
+
+        //[Test]
+        //public void GetRecordByFileTimeTest()
+        //{
+        //    Assert.Fail("TODO");
+        //}
+
+        //[Test]
+        //public void GetRecordByTimestampTest()
+        //{
+        //    Assert.Fail("TODO");
+        //}
+
+        //[Test]
+        //public void aaLogReaderTest()
+        //{
+        //    Assert.Fail("TODO");
+        //}
+
+        //[Test]
+        //public void DisposeTest()
+        //{
+        //    Assert.Fail("TODO");
+        //}
+
+        //[Test]
+        //public void OpenLogFileTest()
+        //{
+        //    Assert.Fail("TODO");
+        //}
+
+        //[Test]
+        //public void OpenCurrentLogFileTest()
+        //{
+        //    Assert.Fail("TODO");
+        //}
+
+        //[Test]
+        //public void CloseCurrentLogFileTest()
+        //{
+        //    Assert.Fail("TODO");
+        //}
+
+        //[Test]
+        //public void ReadLogHeaderTest()
+        //{
+        //    Assert.Fail("TODO");
+        //}
+
+        //[Test]
+        //public void ReadLogHeaderTest1()
+        //{
+        //    Assert.Fail("TODO");
+        //}
+
+        //[Test]
+        //public void GetFirstRecordTest()
+        //{
+        //    Assert.Fail("TODO");
+        //}
+
+        //[Test]
+        //public void GetLastRecordTest()
+        //{
+        //    Assert.Fail("TODO");
+        //}
+
+        //[Test]
+        //public void GetNextRecordTest()
+        //{
+        //    Assert.Fail("TODO");
+        //}
+
+        //[Test]
+        //public void GetPrevRecordTest()
+        //{
+        //    Assert.Fail("TODO");
+        //}
+
+        //[Test]
+        //public void GetLogFilePathsForMessageNumberTest()
+        //{
+        //    Assert.Fail("TODO");
+        //}
+
+        //[Test]
+        //public void GetLogFilePathsForMessageTimestampTest()
+        //{
+        //    Assert.Fail("TODO");
+        //}
+
+        //[Test]
+        //public void GetLogFilePathsForMessageFileTimeTest()
+        //{
+        //    Assert.Fail("TODO");
+        //}
+
+        //[Test]
+        //public void GetRecordByMessageNumberTest()
+        //{
+        //    Assert.Fail("TODO");
+        //}
+
+        //[Test]
+        //public void GetRecordsByStartMessageNumberAndCountTest()
+        //{
+        //    Assert.Fail("TODO");
+        //}
+
+        //[Test]
+        //public void GetRecordsByEndMessageNumberAndCountTest()
+        //{
+        //    Assert.Fail("TODO");
+        //}
+
+        //[Test]
+        //public void GetRecordsByMessageNumberAndCountTest()
+        //{
+        //    Assert.Fail("TODO");
+        //}
+
+        //[Test]
+        //public void GetRecordsByStartandEndMessageNumberTest()
+        //{
+        //    Assert.Fail("TODO");
+        //}
+
+        //[Test]
+        //public void GetRecordsByEndFileTimeAndCountTest()
+        //{
+        //    Assert.Fail("TODO");
+        //}
+
+        //[Test]
+        //public void GetRecordsByEndTimestampAndCountTest()
+        //{
+        //    Assert.Fail("TODO");
+        //}
+
+        //[Test]
+        //public void GetRecordsByStartFileTimeAndCountTest()
+        //{
+        //    Assert.Fail("TODO");
+        //}
+
+        //[Test]
+        //public void GetRecordsByStartTimestampAndCountTest()
+        //{
+        //    Assert.Fail("TODO");
+        //}
+
+        //[Test]
+        //public void GetRecordsByStartAndEndFileTimeTest()
+        //{
+        //    Assert.Fail("TODO");
+        //}
+
+        //[Test]
+        //public void GetRecordsByStartAndEndTimeStampTest()
+        //{
+        //    Assert.Fail("TODO");
+        //}
+
+        //[Test]
+        //public void GetUnreadRecordsTest()
+        //{
+        //    Assert.Fail("TODO");
+        //}
     }
 }


#1520 Clear info list when model changes

--- Source/Csla.Blazor/ViewModel.cs
+++ Source/Csla.Blazor/ViewModel.cs
@@ -46,6 +46,7 @@
     /// <param name="newValue">New Model value</param>
     protected virtual void OnModelChanging(T oldValue, T newValue)
     {
+      _info.Clear();
       if (oldValue is INotifyPropertyChanged oldObj)
         oldObj.PropertyChanged -= (s, e) => OnModelPropertyChanged(e.PropertyName);
       if (newValue is INotifyPropertyChanged newObj)


#1585 Eliminate RefreshAsync that accepts param array

--- Source/Csla.Blazor/ViewModel.cs
+++ Source/Csla.Blazor/ViewModel.cs
@@ -108,59 +108,6 @@
     }

     /// <summary>
-    /// Refresh the Model
-    /// </summary>
-    /// <param name="parameters">Parameters passed to data portal</param>
-    /// <returns></returns>
-    public async Task<T> RefreshAsync(params object[] parameters)
-    {
-      Exception = null;
-      ViewModelErrorText = null;
-      try
-      {
-        Model = await DoRefreshAsync(parameters);
-      }
-      catch (DataPortalException ex)
-      {
-        Model = default;
-        Exception = ex;
-        ViewModelErrorText = ex.BusinessExceptionMessage;
-      }
-      catch (Exception ex)
-      {
-        Model = default;
-        Exception = ex;
-        ViewModelErrorText = ex.Message;
-      }
-      return Model;
-    }
-
-    /// <summary>
-    /// Override to provide custom Model refresh behavior
-    /// </summary>
-    /// <param name="parameters">Parameters passed to data portal</param>
-    /// <returns></returns>
-    protected virtual async Task<T> DoRefreshAsync(params object[] parameters)
-    {
-      if (typeof(Core.IReadOnlyObject).IsAssignableFrom(typeof(T)) ||
-          typeof(Core.IReadOnlyCollection).IsAssignableFrom(typeof(T)) ||
-          typeof(Core.IEditableCollection).IsAssignableFrom(typeof(T)))
-      {
-        if (Server.DataPortal.GetCriteriaFromArray(parameters) is Server.EmptyCriteria)
-          return await DataPortal.FetchAsync();
-        else
-          return await DataPortal.FetchAsync(parameters);
-      }
-      else
-      {
-        if (Server.DataPortal.GetCriteriaFromArray(parameters) is Server.EmptyCriteria)
-          return await DataPortal.CreateAsync();
-        else
-          return await DataPortal.FetchAsync(parameters);
-      }
-    }
-
-    /// <summary>
     /// Saves the Model
     /// </summary>
     /// <returns></returns>


Replaced constant that was removed accidentally during merge

--- Source/Platibus/QueueOptions.cs
+++ Source/Platibus/QueueOptions.cs
@@ -38,6 +38,7 @@
         /// The default concurrency limit, i.e. the maximum number of concurrent worker
         /// processes that read from the same queue
         /// </summary>
+        public const int DefaultConcurrencyLimit = 4;

         /// <summary>
         /// The default retry delay expressed in milliseconds


Fixed moving platform jump bug.

Fixed moving platform jump bug.

--- Player/PlayerMovement.cs
+++ Player/PlayerMovement.cs
@@ -391,14 +391,14 @@
 	{
 		// clamp to maxRisingSpeed to eliminate jitteriness when rising too fast,
 		// otherwise, clamp to maxFallingSpeed to prevent player leaving screen
-		if (MovingTooFast() && state.RidingFastPlatform && !state.MovingHorizontally)
-		{
-			velocity.y = Mathf.Clamp(velocity.y, -maxFallingSpeed, maxRisingSpeed);
-		}
-		else
-		{
+		// if (MovingTooFast() && state.RidingFastPlatform && !state.MovingHorizontally)
+		// {
+		// 	velocity.y = Mathf.Clamp(velocity.y, -maxFallingSpeed, maxRisingSpeed);
+		// }
+		// else
+		// {
 			velocity.y = Mathf.Clamp(velocity.y, -maxFallingSpeed, maxFallingSpeed);
-		}
+		// }
 	}

 	void ApplyMovement()


Fix invalid initial value of currentMonoLength

--- osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs
+++ osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs
@@ -37,7 +37,7 @@
         /// <summary>
         /// Length of the current mono pattern.
         /// </summary>
-        private int currentMonoLength = 1;
+        private int currentMonoLength;

         protected override double StrainValueOf(DifficultyHitObject current)
         {


Fix vertical centering of button

Fix vertical centering of button

--- osu.Game/Screens/Select/Carousel/SetPanelContent.cs
+++ osu.Game/Screens/Select/Carousel/SetPanelContent.cs
@@ -64,7 +64,17 @@
                         Spacing = new Vector2(5),
                         Children = new[]
                         {
-                            beatmapSet.AllBeatmapsUpToDate ? Empty() : new UpdateRequiredIcon(beatmapSet),
+                            beatmapSet.AllBeatmapsUpToDate
+                                ? Empty()
+                                : new Container
+                                {
+                                    AutoSizeAxes = Axes.X,
+                                    RelativeSizeAxes = Axes.Y,
+                                    Children = new Drawable[]
+                                    {
+                                        new UpdateRequiredIcon(beatmapSet),
+                                    }
+                                },
                             new BeatmapSetOnlineStatusPill
                             {
                                 AutoSizeAxes = Axes.Both,


如果是1，会出现程序无法退出的问题。

如果是1，会出现程序无法退出的问题。

--- CSharpGL/OpenGLObjects/GLSwitches/PolygonModeSwitch.cs
+++ CSharpGL/OpenGLObjects/GLSwitches/PolygonModeSwitch.cs
@@ -8,7 +8,7 @@
     public class PolygonModeSwitch : GLSwitch
     {

-        int[] originalPolygonMode = new int[1];
+        int[] originalPolygonMode = new int[2];

         public PolygonModeSwitch() : this(PolygonModes.Filled) { }


Updated File Types

Updated File Types

Updated Unity And Compressed File Type Excludes


Repositioning HUD lives.

Repositioning HUD lives.

--- HUD/DisplayHearts.cs
+++ HUD/DisplayHearts.cs
@@ -17,17 +17,17 @@
     void Start()
     {
         mainCamera = GameObject.FindWithTag("MainCamera").GetComponent<Camera>();
-        PositionHUDElements();

         HUDHearts = spriteRenderer;
         HUDHearts.sprite = threeHearts;
         HUDHearts.DOKill();
         FadeInShield();
+        Invoke("PositionHUDElements", .5f);
     }

     void PositionHUDElements()
     {
-        transform.position = mainCamera.ScreenToWorldPoint(new Vector3 (Screen.width - renderer.bounds.size.x, Screen.height - HUD_TOP_MARGIN - 20, HUD_Z));
+        transform.position = mainCamera.ScreenToWorldPoint(new Vector3 (Screen.width - 100, Screen.height - 70, HUD_Z));
     }

     void FadeInShield()


Adds new dotnet publish options.

Adds new dotnet publish options.

--- src/FlubuCore/Tasks/NetCore/DotnetPublishTask.cs
+++ src/FlubuCore/Tasks/NetCore/DotnetPublishTask.cs
@@ -71,7 +71,7 @@
         /// </summary>
         /// <param name="directory"></param>
         /// <returns></returns>
-        [ArgKey("-o", "--output")]
+        [ArgKey("--output", "-o")]
         public DotnetPublishTask OutputDirectory(string directory)
         {
             WithArgumentsKeyFromAttribute(directory);
@@ -195,6 +195,39 @@
         public DotnetPublishTask Verbosity(VerbosityOptions verbosity)
         {
             WithArgumentsKeyFromAttribute(verbosity.ToString().ToLower());
+            return this;
+        }
+
+        /// <summary>
+        ///  Publish the .NET Core runtime with your application so the runtime doesn't need to be installed on the target machine.
+        /// </summary>
+        /// <returns></returns>
+        [ArgKey("--self-contained")]
+        public DotnetPublishTask SelfContained()
+        {
+            WithArgumentsKeyFromAttribute();
+            return this;
+        }
+
+        /// <summary>
+        ///  Do not build the project before publishing. Implies --no-restore.
+        /// </summary>
+        /// <returns></returns>
+        [ArgKey("--no-build")]
+        public DotnetPublishTask NoBuild()
+        {
+            WithArgumentsKeyFromAttribute();
+            return this;
+        }
+
+        /// <summary>
+        ///  Do not restore the project before building.
+        /// </summary>
+        /// <returns></returns>
+        [ArgKey("--no-restore")]
+        public DotnetPublishTask NoRestore()
+        {
+            WithArgumentsKeyFromAttribute();
             return this;
         }


Set tree node name to NameProperty if set before NameFormat

--- src/Fluidity/Web/Trees/FluidityTreeController.cs
+++ src/Fluidity/Web/Trees/FluidityTreeController.cs
@@ -253,11 +253,14 @@
             var itemId = entity.GetPropertyValue(collection.IdProperty);
             var compositeId = collection.Alias + "!" + itemId;

+            var entityName = collection.NameProperty != null ? entity.GetPropertyValue(collection.NameProperty).ToString()
+                                : collection.NameFormat != null ? collection.NameFormat(entity) : entity.ToString();
+
             var node = CreateTreeNode(
                 compositeId,
                 collection.Alias,
                 queryStrings,
-                collection.NameFormat != null ? collection.NameFormat(entity) : entity.ToString(),
+                entityName,
                 collection.IconSingular,
                 false,
                 SectionAlias + "/fluidity/edit/" + compositeId);


Fix compiler warnings CS1584 and CS1658.

--- src/GitVersion.App/OverrideConfigOptionParser.cs
+++ src/GitVersion.App/OverrideConfigOptionParser.cs
@@ -15,7 +15,7 @@
         internal ILookup<string, PropertyInfo> SupportedProperties => _lazySupportedProperties.Value;

         /// <summary>
-        /// Dynamically creates <see cref="ILookup{string, PropertyInfo}"/> of
+        /// Dynamically creates <see cref="System.Linq.ILookup{TKey, TElement}"/> of
         /// <see cref="Config"/> properties supported as a part of command line '/overrideconfig' option.
         /// </summary>
         /// <returns></returns>


Oh Cho - fixed an issue with banning chogall

--- src/Heisenslaught/Infrastructure/DraftHandler.cs
+++ src/Heisenslaught/Infrastructure/DraftHandler.cs
@@ -153,14 +153,12 @@

         public bool canPickHero(string heroId)
         {
-            var isValid = isValidHero(heroId);
-            var isPicked = isHeroPickedOrBanned(heroId);
-            var isDisabled = isHeroDisabled(heroId);
-
+
             var allowed = isValidHero(heroId) && !isHeroPickedOrBanned(heroId) && !isHeroDisabled(heroId);
             if (allowed && (heroId == "cho" || heroId == "gall"))
             {
-                if (!isFirstPickOfDoublePick)
+
+                if (!isFirstPickOfDoublePick && !isBan)
                 {
                     allowed = false;
                 }
@@ -258,7 +256,7 @@

             state.picks.Add(heroId);

-            if(heroId == "cho" || heroId == "gall")
+            if(!isBan && (heroId == "cho" || heroId == "gall"))
             {
                 state.picks.Add(heroId == "cho" ? "gall" : "cho");
             }


Solid Edge ST9 MP1 release

Solid Edge ST9 MP1 release

--- src/Interop.SolidEdge/Properties/AssemblyInfo.cs
+++ src/Interop.SolidEdge/Properties/AssemblyInfo.cs
@@ -38,4 +38,4 @@
 [assembly: AssemblyVersion("109.0.0.0")]

 // This version should match the NuGet version.
-[assembly: AssemblyFileVersion("109.0.0.0")]
+[assembly: AssemblyFileVersion("109.1.0.0")]


Mała poprawka w IdentityModels

Mała poprawka w IdentityModels

--- SerwisAudiometryczny/SerwisAudiometryczny/Models/IdentityModels.cs
+++ SerwisAudiometryczny/SerwisAudiometryczny/Models/IdentityModels.cs
@@ -129,7 +129,7 @@
             }
         }

-        public string emaildn { get; set; }
+        private string emaildn { get; set; }
         /// <summary>
         /// Opisuje adres e-mail użytkownika.
         /// </summary>


fix AllowSimpleUserNames in AzureAuthenticationServer

--- Signum.React.Extensions/Authorization/AzureAuthenticationServer.cs
+++ Signum.React.Extensions/Authorization/AzureAuthenticationServer.cs
@@ -38,9 +38,10 @@
                     UserEntity? user =
                         Database.Query<UserEntity>().SingleOrDefault(a => a.Mixin<UserOIDMixin>().OID == ctx.OID);

-                    if(user == null && ada.GetConfig().AllowSimpleUserNames)
+                    if(user == null)
                     {
-                        user = Database.Query<UserEntity>().SingleOrDefault(a => a.UserName == ctx.UserName);
+                        user = Database.Query<UserEntity>().SingleOrDefault(a => a.UserName == ctx.UserName) ??
+                            (ctx.UserName.Contains("@") && ada.GetConfig().AllowSimpleUserNames ? Database.Query<UserEntity>().SingleOrDefault(a => a.UserName == ctx.UserName.Before("@")) : null);

                         if (user != null && user.Mixin<UserOIDMixin>().OID == null)
                         {


Auto-commit from successful build on CHRIS-32F02A9F1 by Administrator at 22:43:47.41 on Wed 08/11/2010

--- Source/Fluency.Tests/Conventions/ByName/LastNameConventionSpecs.cs
+++ Source/Fluency.Tests/Conventions/ByName/LastNameConventionSpecs.cs
@@ -15,13 +15,8 @@
 		{
 			protected static IDefaultConvention< string > convention;
 			protected static PropertyInfo propertyInfo;
-			protected static object defaultValue;

-			Because of = () =>
-			             	{
-			             		convention = Convention.LastName();
-			             		defaultValue = convention.DefaultValue( propertyInfo );
-			             	};
+			Because of = () => { convention = Convention.LastName(); };
 		}

@@ -35,7 +30,7 @@
 			                    	};

 			It should_apply = () => convention.AppliesTo( propertyInfo ).Should().Be.True();
-			It should_return_a_random_last_name = () => defaultValue.ToString().Length.Should().Be.GreaterThan( 0 );
+			It should_return_a_random_last_name = () => convention.DefaultValue( propertyInfo ).Should().Not.Be.Empty();
 		}

@@ -49,7 +44,7 @@
 			                    	};

 			It should_apply = () => convention.AppliesTo( propertyInfo ).Should().Be.True();
-			It should_return_a_random_last_name = () => defaultValue.ToString().Length.Should().Be.GreaterThan( 0 );
+			It should_return_a_random_last_name = () => convention.DefaultValue( propertyInfo ).Should().Not.Be.Empty();
 		}

@@ -63,7 +58,7 @@
 			                    	};

 			It should_apply = () => convention.AppliesTo( propertyInfo ).Should().Be.True();
-			It should_return_a_random_first_name = () => defaultValue.ToString().Length.Should().Be.GreaterThan( 0 );
+			It should_return_a_random_last_name = () => convention.DefaultValue( propertyInfo ).Should().Not.Be.Empty();
 		}

@@ -77,7 +72,7 @@
 			                    	};

 			It should_apply = () => convention.AppliesTo( propertyInfo ).Should().Be.True();
-			It should_return_a_random_first_name = () => defaultValue.ToString().Length.Should().Be.GreaterThan( 0 );
+			It should_return_a_random_last_name = () => convention.DefaultValue( propertyInfo ).Should().Not.Be.Empty();
 		}

@@ -91,7 +86,7 @@
 			                    	};

 			It should_not_apply = () => convention.AppliesTo( propertyInfo ).Should().Be.False();
-			It should_return_nothing = () => defaultValue.Should().Be.Null();
+			It should_return_nothing = () => convention.DefaultValue( propertyInfo ).Should().Be.Null();
 		}
 	}
 }


GrafanaAdapters: Added scaffolding to allow "time-slice" based series group operations.

--- Source/Libraries/Adapters/GrafanaAdapters/GrafanaDataSourceBase.cs
+++ Source/Libraries/Adapters/GrafanaAdapters/GrafanaDataSourceBase.cs
@@ -359,7 +359,7 @@
         Interval,
         /// <summary>
         /// Renames a series with the specified label value. If multiple series are targeted, labels will be indexed starting at one, e.g., if there are three
-        /// series in the target expression with a label value of "Max", series would be labeled as "Max1", "Max2" and "Max3".
+        /// series in the target expression with a label value of "Max", series would be labeled as "Max 1", "Max 2" and "Max 3".
         /// </summary>
         /// <remarks>
         /// Signature: <c>Label(value, expression)</c><br/>
@@ -370,6 +370,25 @@
         Label,
         /// <summary>
         /// Not a recognized function.
+        /// </summary>
+        None
+    }
+
+    /// <summary>
+    /// Group series operations.
+    /// </summary>
+    public enum GroupOperation
+    {
+        /// <summary>
+        /// Operates on each series end-to-end.
+        /// </summary>
+        Set,
+        /// <summary>
+        /// Operates on each series as a group per time-slice.
+        /// </summary>
+        Slice,
+        /// <summary>
+        /// Performs no group operation on the series set.
         /// </summary>
         None
     }
@@ -550,7 +569,7 @@
             if (seriesFunctions.Count > 0)
             {
                 // Execute series functions
-                foreach (Tuple<SeriesFunction, string, bool> parsedFunction in seriesFunctions.Select(ParseSeriesFunction))
+                foreach (Tuple<SeriesFunction, string, GroupOperation> parsedFunction in seriesFunctions.Select(ParseSeriesFunction))
                     foreach (DataSourceValueGroup valueGroup in ExecuteSeriesFunction(parsedFunction, startTime, stopTime, interval, decimate, cancellationToken))
                         yield return valueGroup;

@@ -596,11 +615,11 @@
             }
         }

-        private IEnumerable<DataSourceValueGroup> ExecuteSeriesFunction(Tuple<SeriesFunction, string, bool> parsedFunction, DateTime startTime, DateTime stopTime, string interval, bool decimate, CancellationToken cancellationToken)
+        private IEnumerable<DataSourceValueGroup> ExecuteSeriesFunction(Tuple<SeriesFunction, string, GroupOperation> parsedFunction, DateTime startTime, DateTime stopTime, string interval, bool decimate, CancellationToken cancellationToken)
         {
             SeriesFunction seriesFunction = parsedFunction.Item1;
             string expression = parsedFunction.Item2;
-            bool setOperation = parsedFunction.Item3;
+            GroupOperation groupOperation = parsedFunction.Item3;

             // Parse out function parameters and target expression
             Tuple<string[], string> expressionParameters = TargetCache<Tuple<string[], string>>.GetOrAdd(expression, () =>
@@ -696,32 +715,37 @@
             }
             else
             {
-                if (setOperation)
+                switch (groupOperation)
                 {
-                    // Flatten all series into a single enumerable for set operations
-                    DataSourceValueGroup result = new DataSourceValueGroup
-                    {
-                        Target = $"Set{seriesFunction}({string.Join(", ", parameters)}{(parameters.Length > 0 ? ", " : "")}{targetExpression})",
-                        Source = ExecuteSeriesFunctionOverSource(dataset.AsParallel().WithCancellation(cancellationToken).SelectMany(source => source.Source), seriesFunction, parameters)
-                    };
-
-                    // Handle edge-case set operations - for these functions there is data in the target series as well
-                    if (seriesFunction == SeriesFunction.Minimum || seriesFunction == SeriesFunction.Maximum || seriesFunction == SeriesFunction.Median || seriesFunction == SeriesFunction.Mode)
-                    {
-                        DataSourceValue dataValue = result.Source.First();
-                        result.Target = $"Set{seriesFunction} = {dataValue.Target}";
-                    }
-
-                    yield return result;
-                }
-                else
-                {
-                    foreach (DataSourceValueGroup dataValues in dataset)
-                        yield return new DataSourceValueGroup
+                    case GroupOperation.Set:
+                        // Flatten all series into a single enumerable for set operations
+                        DataSourceValueGroup result = new DataSourceValueGroup
                         {
-                            Target = $"{seriesFunction}({string.Join(", ", parameters)}{(parameters.Length > 0 ? ", " : "")}{dataValues.Target})",
-                            Source = ExecuteSeriesFunctionOverSource(dataValues.Source, seriesFunction, parameters)
+                            Target = $"Set{seriesFunction}({string.Join(", ", parameters)}{(parameters.Length > 0 ? ", " : "")}{targetExpression})",
+                            Source = ExecuteSeriesFunctionOverSource(dataset.AsParallel().WithCancellation(cancellationToken).SelectMany(source => source.Source), seriesFunction, parameters)
                         };
+
+                        // Handle edge-case set operations - for these functions there is data in the target series as well
+                        if (seriesFunction == SeriesFunction.Minimum || seriesFunction == SeriesFunction.Maximum || seriesFunction == SeriesFunction.Median || seriesFunction == SeriesFunction.Mode)
+                        {
+                            DataSourceValue dataValue = result.Source.First();
+                            result.Target = $"Set{seriesFunction} = {dataValue.Target}";
+                        }
+
+                        yield return result;
+
+                        break;
+                    case GroupOperation.Slice:
+                        break;
+                    default:
+                        foreach (DataSourceValueGroup dataValues in dataset)
+                            yield return new DataSourceValueGroup
+                            {
+                                Target = $"{seriesFunction}({string.Join(", ", parameters)}{(parameters.Length > 0 ? ", " : "")}{dataValues.Target})",
+                                Source = ExecuteSeriesFunctionOverSource(dataValues.Source, seriesFunction, parameters)
+                            };
+
+                        break;
                 }
             }
         }
@@ -764,6 +788,7 @@
         private static readonly Regex s_labelExpression;
         private static readonly Dictionary<SeriesFunction, int> s_requiredParameters;
         private static readonly Dictionary<SeriesFunction, int> s_optionalParameters;
+        private static readonly string[] s_groupOperationNames;

         // Static Constructor
         static GrafanaDataSourceBase()
@@ -771,7 +796,8 @@
             const string GetExpression = @"^{0}\s*\(\s*(?<Expression>.+)\s*\)";

             // RegEx instance to find all series functions
-            s_seriesFunctions = new Regex(@"(SET)?\w+\s*(?<!\s+IN\s+)\((([^\(\)]|(?<counter>\()|(?<-counter>\)))*(?(counter)(?!)))\)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
+            s_groupOperationNames = Enum.GetNames(typeof(GroupOperation));
+            s_seriesFunctions = new Regex($@"({string.Join("|", s_groupOperationNames)})?\w+\s*(?<!\s+IN\s+)\((([^\(\)]|(?<counter>\()|(?<-counter>\)))*(?(counter)(?!)))\)", RegexOptions.Compiled | RegexOptions.IgnoreCase);

             // RegEx instances to identify specific functions and extract internal expressions
             s_averageExpression = new Regex(string.Format(GetExpression, "(Average|Avg|Mean)"), RegexOptions.Compiled | RegexOptions.IgnoreCase);
@@ -877,226 +903,238 @@
         }

         // Static Methods
-        private static Tuple<SeriesFunction, string, bool> ParseSeriesFunction(Match matchedFunction)
-        {
-            Tuple<SeriesFunction, string, bool> result = TargetCache<Tuple<SeriesFunction, string, bool>>.GetOrAdd(matchedFunction.Value, () =>
-            {
-                bool setOperation = matchedFunction.Groups[1].Success;
-                string expression = setOperation ? matchedFunction.Value.Substring(3) : matchedFunction.Value;
+        private static Tuple<SeriesFunction, string, GroupOperation> ParseSeriesFunction(Match matchedFunction)
+        {
+            Tuple<SeriesFunction, string, GroupOperation> result = TargetCache<Tuple<SeriesFunction, string, GroupOperation>>.GetOrAdd(matchedFunction.Value, () =>
+            {
+                GroupOperation groupOperation;
                 Match filterMatch;
+                string expression;
+
+                // Determine if expression is defined as a group operation
+                if (matchedFunction.Groups[1].Success)
+                {
+                    groupOperation = (GroupOperation)s_groupOperationNames.IndexOf(groupOperationName => matchedFunction.Groups[1].Value.Equals(groupOperationName, StringComparison.OrdinalIgnoreCase));
+                    expression = matchedFunction.Value.Substring(groupOperation.ToString().Length);
+                }
+                else
+                {
+                    groupOperation = GroupOperation.None;
+                    expression = matchedFunction.Value;
+                }

                 // Look for average function
                 lock (s_averageExpression)
                     filterMatch = s_averageExpression.Match(expression);

                 if (filterMatch.Success)
-                    return new Tuple<SeriesFunction, string, bool>(SeriesFunction.Average, filterMatch.Result("${Expression}").Trim(), setOperation);
+                    return new Tuple<SeriesFunction, string, GroupOperation>(SeriesFunction.Average, filterMatch.Result("${Expression}").Trim(), groupOperation);

                 // Look for minimum function
                 lock (s_minimumExpression)
                     filterMatch = s_minimumExpression.Match(expression);

                 if (filterMatch.Success)
-                    return new Tuple<SeriesFunction, string, bool>(SeriesFunction.Minimum, filterMatch.Result("${Expression}").Trim(), setOperation);
+                    return new Tuple<SeriesFunction, string, GroupOperation>(SeriesFunction.Minimum, filterMatch.Result("${Expression}").Trim(), groupOperation);

                 // Look for maximum function
                 lock (s_maximumExpression)
                     filterMatch = s_maximumExpression.Match(expression);

                 if (filterMatch.Success)
-                    return new Tuple<SeriesFunction, string, bool>(SeriesFunction.Maximum, filterMatch.Result("${Expression}").Trim(), setOperation);
+                    return new Tuple<SeriesFunction, string, GroupOperation>(SeriesFunction.Maximum, filterMatch.Result("${Expression}").Trim(), groupOperation);

                 // Look for total function
                 lock (s_totalExpression)
                     filterMatch = s_totalExpression.Match(expression);

                 if (filterMatch.Success)
-                    return new Tuple<SeriesFunction, string, bool>(SeriesFunction.Total, filterMatch.Result("${Expression}").Trim(), setOperation);
+                    return new Tuple<SeriesFunction, string, GroupOperation>(SeriesFunction.Total, filterMatch.Result("${Expression}").Trim(), groupOperation);

                 // Look for range function
                 lock (s_rangeExpression)
                     filterMatch = s_rangeExpression.Match(expression);

                 if (filterMatch.Success)
-                    return new Tuple<SeriesFunction, string, bool>(SeriesFunction.Range, filterMatch.Result("${Expression}").Trim(), setOperation);
+                    return new Tuple<SeriesFunction, string, GroupOperation>(SeriesFunction.Range, filterMatch.Result("${Expression}").Trim(), groupOperation);

                 // Look for count function
                 lock (s_countExpression)
                     filterMatch = s_countExpression.Match(expression);

                 if (filterMatch.Success)
-                    return new Tuple<SeriesFunction, string, bool>(SeriesFunction.Count, filterMatch.Result("${Expression}").Trim(), setOperation);
+                    return new Tuple<SeriesFunction, string, GroupOperation>(SeriesFunction.Count, filterMatch.Result("${Expression}").Trim(), groupOperation);

                 // Look for distinct function
                 lock (s_distinctExpression)
                     filterMatch = s_distinctExpression.Match(expression);

                 if (filterMatch.Success)
-                    return new Tuple<SeriesFunction, string, bool>(SeriesFunction.Distinct, filterMatch.Result("${Expression}").Trim(), setOperation);
+                    return new Tuple<SeriesFunction, string, GroupOperation>(SeriesFunction.Distinct, filterMatch.Result("${Expression}").Trim(), groupOperation);

                 // Look for absolute value function
                 lock (s_absoluteValueExpression)
                     filterMatch = s_absoluteValueExpression.Match(expression);

                 if (filterMatch.Success)
-                    return new Tuple<SeriesFunction, string, bool>(SeriesFunction.AbsoluteValue, filterMatch.Result("${Expression}").Trim(), setOperation);
+                    return new Tuple<SeriesFunction, string, GroupOperation>(SeriesFunction.AbsoluteValue, filterMatch.Result("${Expression}").Trim(), groupOperation);

                 // Look for add function
                 lock (s_addExpression)
                     filterMatch = s_addExpression.Match(expression);

                 if (filterMatch.Success)
-                    return new Tuple<SeriesFunction, string, bool>(SeriesFunction.Add, filterMatch.Result("${Expression}").Trim(), setOperation);
+                    return new Tuple<SeriesFunction, string, GroupOperation>(SeriesFunction.Add, filterMatch.Result("${Expression}").Trim(), groupOperation);

                 // Look for multiply function
                 lock (s_multiplyExpression)
                     filterMatch = s_multiplyExpression.Match(expression);

                 if (filterMatch.Success)
-                    return new Tuple<SeriesFunction, string, bool>(SeriesFunction.Multiply, filterMatch.Result("${Expression}").Trim(), setOperation);
+                    return new Tuple<SeriesFunction, string, GroupOperation>(SeriesFunction.Multiply, filterMatch.Result("${Expression}").Trim(), groupOperation);

                 // Look for round function
                 lock (s_roundExpression)
                     filterMatch = s_roundExpression.Match(expression);

                 if (filterMatch.Success)
-                    return new Tuple<SeriesFunction, string, bool>(SeriesFunction.Round, filterMatch.Result("${Expression}").Trim(), setOperation);
+                    return new Tuple<SeriesFunction, string, GroupOperation>(SeriesFunction.Round, filterMatch.Result("${Expression}").Trim(), groupOperation);

                 // Look for floor function
                 lock (s_floorExpression)
                     filterMatch = s_floorExpression.Match(expression);

                 if (filterMatch.Success)
-                    return new Tuple<SeriesFunction, string, bool>(SeriesFunction.Floor, filterMatch.Result("${Expression}").Trim(), setOperation);
+                    return new Tuple<SeriesFunction, string, GroupOperation>(SeriesFunction.Floor, filterMatch.Result("${Expression}").Trim(), groupOperation);

                 // Look for ceiling function
                 lock (s_ceilingExpression)
                     filterMatch = s_ceilingExpression.Match(expression);

                 if (filterMatch.Success)
-                    return new Tuple<SeriesFunction, string, bool>(SeriesFunction.Ceiling, filterMatch.Result("${Expression}").Trim(), setOperation);
+                    return new Tuple<SeriesFunction, string, GroupOperation>(SeriesFunction.Ceiling, filterMatch.Result("${Expression}").Trim(), groupOperation);

                 // Look for truncate function
                 lock (s_truncateExpression)
                     filterMatch = s_truncateExpression.Match(expression);

                 if (filterMatch.Success)
-                    return new Tuple<SeriesFunction, string, bool>(SeriesFunction.Truncate, filterMatch.Result("${Expression}").Trim(), setOperation);
+                    return new Tuple<SeriesFunction, string, GroupOperation>(SeriesFunction.Truncate, filterMatch.Result("${Expression}").Trim(), groupOperation);

                 // Look for standard deviation function
                 lock (s_standardDeviationExpression)
                     filterMatch = s_standardDeviationExpression.Match(expression);

                 if (filterMatch.Success)
-                    return new Tuple<SeriesFunction, string, bool>(SeriesFunction.StandardDeviation, filterMatch.Result("${Expression}").Trim(), setOperation);
+                    return new Tuple<SeriesFunction, string, GroupOperation>(SeriesFunction.StandardDeviation, filterMatch.Result("${Expression}").Trim(), groupOperation);

                 // Look for sampled-based standard deviation function
                 lock (s_standardDeviationSampleExpression)
                     filterMatch = s_standardDeviationSampleExpression.Match(expression);

                 if (filterMatch.Success)
-                    return new Tuple<SeriesFunction, string, bool>(SeriesFunction.StandardDeviationSample, filterMatch.Result("${Expression}").Trim(), setOperation);
+                    return new Tuple<SeriesFunction, string, GroupOperation>(SeriesFunction.StandardDeviationSample, filterMatch.Result("${Expression}").Trim(), groupOperation);

                 // Look for median function
                 lock (s_medianExpression)
                     filterMatch = s_medianExpression.Match(expression);

                 if (filterMatch.Success)
-                    return new Tuple<SeriesFunction, string, bool>(SeriesFunction.Median, filterMatch.Result("${Expression}").Trim(), setOperation);
+                    return new Tuple<SeriesFunction, string, GroupOperation>(SeriesFunction.Median, filterMatch.Result("${Expression}").Trim(), groupOperation);

                 // Look for mode function
                 lock (s_modeExpression)
                     filterMatch = s_modeExpression.Match(expression);

                 if (filterMatch.Success)
-                    return new Tuple<SeriesFunction, string, bool>(SeriesFunction.Mode, filterMatch.Result("${Expression}").Trim(), setOperation);
+                    return new Tuple<SeriesFunction, string, GroupOperation>(SeriesFunction.Mode, filterMatch.Result("${Expression}").Trim(), groupOperation);

                 // Look for top function
                 lock (s_topExpression)
                     filterMatch = s_topExpression.Match(expression);

                 if (filterMatch.Success)
-                    return new Tuple<SeriesFunction, string, bool>(SeriesFunction.Top, filterMatch.Result("${Expression}").Trim(), setOperation);
+                    return new Tuple<SeriesFunction, string, GroupOperation>(SeriesFunction.Top, filterMatch.Result("${Expression}").Trim(), groupOperation);

                 // Look for bottom function
                 lock (s_bottomExpression)
                     filterMatch = s_bottomExpression.Match(expression);

                 if (filterMatch.Success)
-                    return new Tuple<SeriesFunction, string, bool>(SeriesFunction.Bottom, filterMatch.Result("${Expression}").Trim(), setOperation);
+                    return new Tuple<SeriesFunction, string, GroupOperation>(SeriesFunction.Bottom, filterMatch.Result("${Expression}").Trim(), groupOperation);

                 // Look for random function
                 lock (s_randomExpression)
                     filterMatch = s_randomExpression.Match(expression);

                 if (filterMatch.Success)
-                    return new Tuple<SeriesFunction, string, bool>(SeriesFunction.Random, filterMatch.Result("${Expression}").Trim(), setOperation);
+                    return new Tuple<SeriesFunction, string, GroupOperation>(SeriesFunction.Random, filterMatch.Result("${Expression}").Trim(), groupOperation);

                 // Look for first function
                 lock (s_firstExpression)
                     filterMatch = s_firstExpression.Match(expression);

                 if (filterMatch.Success)
-                    return new Tuple<SeriesFunction, string, bool>(SeriesFunction.First, filterMatch.Result("${Expression}").Trim(), setOperation);
+                    return new Tuple<SeriesFunction, string, GroupOperation>(SeriesFunction.First, filterMatch.Result("${Expression}").Trim(), groupOperation);

                 // Look for last function
                 lock (s_lastExpression)
                     filterMatch = s_lastExpression.Match(expression);

                 if (filterMatch.Success)
-                    return new Tuple<SeriesFunction, string, bool>(SeriesFunction.Last, filterMatch.Result("${Expression}").Trim(), setOperation);
+                    return new Tuple<SeriesFunction, string, GroupOperation>(SeriesFunction.Last, filterMatch.Result("${Expression}").Trim(), groupOperation);

                 // Look for percentile function
                 lock (s_percentileExpression)
                     filterMatch = s_percentileExpression.Match(expression);

                 if (filterMatch.Success)
-                    return new Tuple<SeriesFunction, string, bool>(SeriesFunction.Percentile, filterMatch.Result("${Expression}").Trim(), setOperation);
+                    return new Tuple<SeriesFunction, string, GroupOperation>(SeriesFunction.Percentile, filterMatch.Result("${Expression}").Trim(), groupOperation);

                 // Look for difference function
                 lock (s_differenceExpression)
                     filterMatch = s_differenceExpression.Match(expression);

                 if (filterMatch.Success)
-                    return new Tuple<SeriesFunction, string, bool>(SeriesFunction.Difference, filterMatch.Result("${Expression}").Trim(), setOperation);
+                    return new Tuple<SeriesFunction, string, GroupOperation>(SeriesFunction.Difference, filterMatch.Result("${Expression}").Trim(), groupOperation);

                 // Look for time difference function
                 lock (s_timeDifferenceExpression)
                     filterMatch = s_timeDifferenceExpression.Match(expression);

                 if (filterMatch.Success)
-                    return new Tuple<SeriesFunction, string, bool>(SeriesFunction.TimeDifference, filterMatch.Result("${Expression}").Trim(), setOperation);
+                    return new Tuple<SeriesFunction, string, GroupOperation>(SeriesFunction.TimeDifference, filterMatch.Result("${Expression}").Trim(), groupOperation);

                 // Look for derivative function
                 lock (s_derivativeExpression)
                     filterMatch = s_derivativeExpression.Match(expression);

                 if (filterMatch.Success)
-                    return new Tuple<SeriesFunction, string, bool>(SeriesFunction.Derivative, filterMatch.Result("${Expression}").Trim(), setOperation);
+                    return new Tuple<SeriesFunction, string, GroupOperation>(SeriesFunction.Derivative, filterMatch.Result("${Expression}").Trim(), groupOperation);

                 // Look for time integration function
                 lock (s_timeIntegrationExpression)
                     filterMatch = s_timeIntegrationExpression.Match(expression);

                 if (filterMatch.Success)
-                    return new Tuple<SeriesFunction, string, bool>(SeriesFunction.TimeIntegration, filterMatch.Result("${Expression}").Trim(), setOperation);
+                    return new Tuple<SeriesFunction, string, GroupOperation>(SeriesFunction.TimeIntegration, filterMatch.Result("${Expression}").Trim(), groupOperation);

                 // Look for interval function
                 lock (s_intervalExpression)
                     filterMatch = s_intervalExpression.Match(expression);

                 if (filterMatch.Success)
-                    return new Tuple<SeriesFunction, string, bool>(SeriesFunction.Interval, filterMatch.Result("${Expression}").Trim(), setOperation);
+                    return new Tuple<SeriesFunction, string, GroupOperation>(SeriesFunction.Interval, filterMatch.Result("${Expression}").Trim(), groupOperation);

                 // Look for label function
                 lock (s_labelExpression)
                     filterMatch = s_labelExpression.Match(expression);

                 if (filterMatch.Success)
-                    return new Tuple<SeriesFunction, string, bool>(SeriesFunction.Label, filterMatch.Result("${Expression}").Trim(), setOperation);
+                    return new Tuple<SeriesFunction, string, GroupOperation>(SeriesFunction.Label, filterMatch.Result("${Expression}").Trim(), groupOperation);

                 // Target is not a recognized function
-                return new Tuple<SeriesFunction, string, bool>(SeriesFunction.None, expression, false);
+                return new Tuple<SeriesFunction, string, GroupOperation>(SeriesFunction.None, expression, GroupOperation.None);
             });

             if (result.Item1 == SeriesFunction.None)


GrafanaAdapters: Optimized aggregation function execution.

--- Source/Libraries/Adapters/GrafanaAdapters/GrafanaDataSourceBase.cs
+++ Source/Libraries/Adapters/GrafanaAdapters/GrafanaDataSourceBase.cs
@@ -107,12 +107,12 @@
                 return QueryTimeSeriesValuesFromTargets(request.targets.Select(target => target.target), startTime, stopTime, maxDataPoints, cancellationToken);
             },
             cancellationToken);
-        }
+        }

         private List<TimeSeriesValues> QueryTimeSeriesValuesFromTargets(IEnumerable<string> targets, DateTime startTime, DateTime stopTime, int maxDataPoints, CancellationToken cancellationToken)
         {
             // A single target might look like the following:
-            // PPA:15; STAT:20; SUM(COUNT(PPA:8; PPA:9; PPA:10)); FILTER ActiveMeasurements WHERE SignalType = 'VPHA'; RANGE(PPA:99; SUM(FILTER ActiveMeasurements WHERE SignalType = 'FREQ'; STAT:12))
+            // PPA:15; STAT:20; SETSUM(COUNT(PPA:8; PPA:9; PPA:10)); FILTER ActiveMeasurements WHERE SignalType = 'VPHA'; RANGE(PPA:99; SUM(FILTER ActiveMeasurements WHERE SignalType = 'FREQ'; STAT:12))

             List<TimeSeriesValues> results = new List<TimeSeriesValues>();
             HashSet<string> targetSet = new HashSet<string>(targets, StringComparer.OrdinalIgnoreCase); // Targets include user provided input, so casing should be ignored
@@ -138,7 +138,8 @@
                     foreach (string aggregate in aggregates.Select(match => match.Value))
                         reducedTarget = reducedTarget.Replace(aggregate, "");

-                    reducedTargetSet.Add(reducedTarget);
+                    if (!string.IsNullOrWhiteSpace(reducedTarget))
+                        reducedTargetSet.Add(reducedTarget);
                 }
                 else
                 {
@@ -149,7 +150,7 @@
             if (aggregateExpressions.Count > 0)
             {
                 // Parse aggregate expressions
-                Tuple<Aggregate, string, bool>[] parsedAggregates = aggregateExpressions.Select(ParseAggregate).ToArray();
+                IEnumerable<Tuple<Aggregate, string, bool>> parsedAggregates = aggregateExpressions.Select(ParseAggregate);

                 // Execute aggregate expressions
                 foreach (Tuple<Aggregate, string, bool> parsedAggregate in parsedAggregates)
@@ -193,7 +194,7 @@
         {
             bool setOperation = aggregate.Groups[1].Success;
             string aggregateExpression = setOperation ? aggregate.Value.Substring(3) : aggregate.Value;
-            Tuple <Aggregate, string, bool> result = TargetCache<Tuple<Aggregate, string, bool>>.GetOrAdd(aggregate.Value, () =>
+            Tuple<Aggregate, string, bool> result = TargetCache<Tuple<Aggregate, string, bool>>.GetOrAdd(aggregate.Value, () =>
             {
                 Match filterMatch;

@@ -239,20 +240,6 @@
                 if (filterMatch.Success)
                     return new Tuple<Aggregate, string, bool>(Aggregate.Count, filterMatch.Result("${Expression}").Trim(), setOperation);

-                // Look for time integration aggregate
-                lock (s_timeIntExpression)
-                    filterMatch = s_timeIntExpression.Match(aggregateExpression);
-
-                if (filterMatch.Success)
-                    return new Tuple<Aggregate, string, bool>(Aggregate.TimeInt, filterMatch.Result("${Expression}").Trim(), setOperation);
-
-                // Look for derivative aggregate
-                lock (s_derivativeExpression)
-                    filterMatch = s_derivativeExpression.Match(aggregateExpression);
-
-                if (filterMatch.Success)
-                    return new Tuple<Aggregate, string, bool>(Aggregate.Derivative, filterMatch.Result("${Expression}").Trim(), setOperation);
-
                 // Look for standard deviation aggregate
                 lock (s_stdDevExpression)
                     filterMatch = s_stdDevExpression.Match(aggregateExpression);
@@ -267,6 +254,23 @@
                 if (filterMatch.Success)
                     return new Tuple<Aggregate, string, bool>(Aggregate.StDevSamp, filterMatch.Result("${Expression}").Trim(), setOperation);

+                if (!setOperation)
+                {
+                    // Look for time integration aggregate
+                    lock (s_timeIntExpression)
+                        filterMatch = s_timeIntExpression.Match(aggregateExpression);
+
+                    if (filterMatch.Success)
+                        return new Tuple<Aggregate, string, bool>(Aggregate.TimeInt, filterMatch.Result("${Expression}").Trim(), false);
+
+                    // Look for derivative aggregate
+                    lock (s_derivativeExpression)
+                        filterMatch = s_derivativeExpression.Match(aggregateExpression);
+
+                    if (filterMatch.Success)
+                        return new Tuple<Aggregate, string, bool>(Aggregate.Derivative, filterMatch.Result("${Expression}").Trim(), false);
+                }
+
                 // Target is not a recognized aggregate
                 return new Tuple<Aggregate, string, bool>(Aggregate.None, aggregateExpression, false);
             });
@@ -280,74 +284,89 @@
         private List<TimeSeriesValues> ExecuteAggregate(Tuple<Aggregate, string, bool> parsedAggregate, DateTime startTime, DateTime stopTime, int maxDataPoints, CancellationToken cancellationToken)
         {
             List<TimeSeriesValues> results = new List<TimeSeriesValues>();
+            List<TimeSeriesValues> dataset;
+            TimeSeriesValues result;
+
             Aggregate aggregate = parsedAggregate.Item1;
             string expression = parsedAggregate.Item2;
             bool setOperation = parsedAggregate.Item3;
-            List<TimeSeriesValues> dataset = QueryTimeSeriesValuesFromTargets(new[] { expression }, startTime, stopTime, maxDataPoints, cancellationToken);
-            double[] currentSeries, currentTimes;
+
+            // Handle min and max set operations as special cases
+            if (setOperation && (aggregate == Aggregate.Minimum || aggregate == Aggregate.Maximum))
+            {
+                // Execute expression as a non-set function to get min/max of each series
+                dataset = ExecuteAggregate(new Tuple<Aggregate, string, bool>(aggregate, expression, false), startTime, stopTime, maxDataPoints, cancellationToken);
+
+                if (aggregate == Aggregate.Minimum)
+                {
+                    result = dataset.MinBy(series => series.datapoints[0][TimeSeriesValues.Value]);
+                    result.target = $"SetMinimum = {result.target}";
+                }
+                else
+                {
+                    result = dataset.MaxBy(series => series.datapoints[0][TimeSeriesValues.Value]);
+                    result.target = $"SetMaximum = {result.target}";
+                }
+
+                results.Add(result);
+                return results;
+            }
+
+            // Query aggregate expression to get series data
+            dataset = QueryTimeSeriesValuesFromTargets(new[] { expression }, startTime, stopTime, maxDataPoints, cancellationToken);

             if (dataset.Count == 0 || cancellationToken.IsCancellationRequested)
                 return results;

             if (setOperation)
             {
-                TimeSeriesValues result = new TimeSeriesValues
+                result = new TimeSeriesValues
                 {
                     target = $"Set{aggregate}({expression})",
                     datapoints = new List<double[]>()
                 };

                 IEnumerable<double> values = dataset.Select(series => series.datapoints).SelectMany(points => points[TimeSeriesValues.Value]);
-                IEnumerable<double> times = dataset.Select(series => series.datapoints).SelectMany(points => points[TimeSeriesValues.Time]);
+                double lastTime = dataset.Select(series => series.datapoints).SelectMany(points => points[TimeSeriesValues.Time]).Max();

                 switch (aggregate)
                 {
                     case Aggregate.Average:
-                        result.datapoints.Add(new [] { values.Average(), times.Max() });
-                        break;
-                    case Aggregate.Minimum:
-                        List<TimeSeriesValues> minSet = ExecuteAggregate(new Tuple<Aggregate, string, bool>(aggregate, expression, false), startTime, stopTime, maxDataPoints, cancellationToken);
-                        result = minSet.MinBy(value => value.datapoints[0][TimeSeriesValues.Value]);
-                        result.target = $"SetMinimum = {result.target}";
-                        break;
-                    case Aggregate.Maximum:
-                        List<TimeSeriesValues> maxSet = ExecuteAggregate(new Tuple<Aggregate, string, bool>(aggregate, expression, false), startTime, stopTime, maxDataPoints, cancellationToken);
-                        result = maxSet.MaxBy(value => value.datapoints[0][TimeSeriesValues.Value]);
-                        result.target = $"SetMaximum = {result.target}";
+                        result.datapoints.Add(new[] { values.Average(), lastTime });
                         break;
                     case Aggregate.Total:
-                        result.datapoints.Add(new [] { values.Sum(), times.Max() });
+                        result.datapoints.Add(new[] { values.Sum(), lastTime });
                         break;
                     case Aggregate.Range:
-                        result.datapoints.Add(new [] { values.Max() - values.Min(), times.Max() });
+                        result.datapoints.Add(new[] { values.Max() - values.Min(), lastTime });
                         break;
                     case Aggregate.Count:
-                        result.datapoints.Add(new [] { values.Count(), times.Max() });
-                        break;
-                    case Aggregate.TimeInt:
-                        double integratedValue = 0.0D;
-                        currentSeries = values.ToArray();
-                        currentTimes = times.ToArray();
-
-                        for (int i = 1; i < currentSeries.Length; i++)
-                            integratedValue += currentSeries[i] * (currentTimes[i] - currentTimes[i - 1]);
-
-                        result.datapoints.Add(new [] { integratedValue, times.Max() });
-                        break;
-                    case Aggregate.Derivative:
-                        currentSeries = values.ToArray();
-                        currentTimes = times.ToArray();
-
-                        for (int i = 1; i < currentSeries.Length; i++)
-                            result.datapoints.Add(new [] { currentSeries[i] - currentSeries[i -1], currentTimes[i] });
-
+                        result.datapoints.Add(new[] { values.Count(), lastTime });
                         break;
                     case Aggregate.StdDev:
-                        result.datapoints.Add(new [] { values.StandardDeviation(), times.Max() });
+                        result.datapoints.Add(new[] { values.StandardDeviation(), lastTime });
                         break;
                     case Aggregate.StDevSamp:
-                        result.datapoints.Add(new [] { values.StandardDeviation(true), times.Max() });
+                        result.datapoints.Add(new[] { values.StandardDeviation(true), lastTime });
                         break;
+                    //case Aggregate.TimeInt:
+                    //    double integratedValue = 0.0D;
+                    //    currentSeries = values.ToArray();
+                    //    currentTimes = times.ToArray();
+
+                    //    for (int i = 1; i < currentSeries.Length; i++)
+                    //        integratedValue += currentSeries[i] * (currentTimes[i] - currentTimes[i - 1]);
+
+                    //    result.datapoints.Add(new [] { integratedValue, lastTime });
+                    //    break;
+                    //case Aggregate.Derivative:
+                    //    currentSeries = values.ToArray();
+                    //    currentTimes = times.ToArray();
+
+                    //    for (int i = 1; i < currentSeries.Length; i++)
+                    //        result.datapoints.Add(new[] { currentSeries[i] - currentSeries[i - 1], currentTimes[i] });
+
+                    //    break;
                 }

                 results.Add(result);
@@ -356,84 +375,82 @@
             {
                 foreach (TimeSeriesValues source in dataset)
                 {
-                    TimeSeriesValues result = new TimeSeriesValues
+                    result = new TimeSeriesValues
                     {
                         target = $"{aggregate}({source.target})",
                         datapoints = new List<double[]>()
                     };

                     IEnumerable<double> values = source.datapoints.Select(points => points[TimeSeriesValues.Value]);
-                    IEnumerable<double> times = source.datapoints.Select(points => points[TimeSeriesValues.Time]);
                     double lastTime = source.datapoints[source.datapoints.Count - 1][TimeSeriesValues.Time];
+                    double value;

                     switch (aggregate)
                     {
-                        case Aggregate.Average:
-                            result.datapoints.Add(new [] { values.Average(), lastTime });
-                            break;
                         case Aggregate.Minimum:
                             double minValue = double.MaxValue;
                             int minIndex = 0;
-                            currentSeries = values.ToArray();
-
-                            for (int i = 0; i < currentSeries.Length; i++)
+
+                            for (int i = 0; i < source.datapoints.Count; i++)
                             {
-                                if (currentSeries[i] < minValue)
+                                value = source.datapoints[i][TimeSeriesValues.Value];
+
+                                if (value < minValue)
                                 {
-                                    minValue = currentSeries[i];
+                                    minValue = value;
                                     minIndex = i;
                                 }
                             }

-                            result.datapoints.Add(new [] { minValue, times.ElementAt(minIndex) });
+                            result.datapoints.Add(new[] { minValue, source.datapoints[minIndex][TimeSeriesValues.Time] });
                             break;
                         case Aggregate.Maximum:
                             double maxValue = double.MinValue;
                             int maxIndex = 0;
-                            currentSeries = values.ToArray();
-
-                            for (int i = 0; i < currentSeries.Length; i++)
+
+                            for (int i = 0; i < source.datapoints.Count; i++)
                             {
-                                if (currentSeries[i] > maxValue)
+                                value = source.datapoints[i][TimeSeriesValues.Value];
+
+                                if (value > maxValue)
                                 {
-                                    maxValue = currentSeries[i];
+                                    maxValue = value;
                                     maxIndex = i;
                                 }
                             }

-                            result.datapoints.Add(new [] { maxValue, times.ElementAt(maxIndex) });
+                            result.datapoints.Add(new[] { maxValue, source.datapoints[maxIndex][TimeSeriesValues.Time] });
+                            break;
+                        case Aggregate.Average:
+                            result.datapoints.Add(new[] { values.Average(), lastTime });
                             break;
                         case Aggregate.Total:
-                            result.datapoints.Add(new [] { values.Sum(), lastTime });
+                            result.datapoints.Add(new[] { values.Sum(), lastTime });
                             break;
                         case Aggregate.Range:
-                            result.datapoints.Add(new [] { values.Max() - values.Min(), lastTime });
+                            result.datapoints.Add(new[] { values.Max() - values.Min(), lastTime });
                             break;
                         case Aggregate.Count:
-                            result.datapoints.Add(new [] { source.datapoints.Count, lastTime });
+                            result.datapoints.Add(new[] { source.datapoints.Count, lastTime });
+                            break;
+                        case Aggregate.StdDev:
+                            result.datapoints.Add(new[] { values.StandardDeviation(), lastTime });
+                            break;
+                        case Aggregate.StDevSamp:
+                            result.datapoints.Add(new[] { values.StandardDeviation(true), lastTime });
                             break;
                         case Aggregate.TimeInt:
                             double integratedValue = 0.0D;

                             for (int i = 1; i < source.datapoints.Count; i++)
-                                integratedValue += source.datapoints[i][TimeSeriesValues.Value] *
-                                    (source.datapoints[i][TimeSeriesValues.Time] - source.datapoints[i - 1][TimeSeriesValues.Time]);
-
-                            result.datapoints.Add(new [] { integratedValue, lastTime });
+                                integratedValue += source.datapoints[i][TimeSeriesValues.Value] * (source.datapoints[i][TimeSeriesValues.Time] - source.datapoints[i - 1][TimeSeriesValues.Time]);
+
+                            result.datapoints.Add(new[] { integratedValue, lastTime });
                             break;
                         case Aggregate.Derivative:
-                            currentSeries = values.ToArray();
-                            currentTimes = times.ToArray();
-
-                            for (int i = 1; i < currentSeries.Length; i++)
-                                result.datapoints.Add(new[] { currentSeries[i] - currentSeries[i - 1], currentTimes[i] });
-
-                            break;
-                        case Aggregate.StdDev:
-                            result.datapoints.Add(new [] { values.StandardDeviation(), lastTime });
-                            break;
-                        case Aggregate.StDevSamp:
-                            result.datapoints.Add(new [] { values.StandardDeviation(true), lastTime });
+                            for (int i = 1; i < source.datapoints.Count; i++)
+                                result.datapoints.Add(new[] { source.datapoints[i][TimeSeriesValues.Value] - source.datapoints[i -1][TimeSeriesValues.Value], source.datapoints[i][TimeSeriesValues.Time] });
+
                             break;
                     }

@@ -464,13 +481,7 @@
             // TODO: Make openHistorian Grafana data source metric query more interactive, adding drop-downs and/or query builders

             // For now, just return a truncated list of tag names
-            return Task.Factory.StartNew(() =>
-            {
-                return Metadata.Tables["ActiveMeasurements"]
-                    .Select($"ID LIKE '{InstanceName}:%'")
-                    .Take(MaximumSearchTargetsPerRequest)
-                    .Select(row => $"{row["PointTag"]}").ToArray();
-            });
+            return Task.Factory.StartNew(() => { return Metadata.Tables["ActiveMeasurements"].Select($"ID LIKE '{InstanceName}:%'").Take(MaximumSearchTargetsPerRequest).Select(row => $"{row["PointTag"]}").ToArray(); });
         }

         /// <summary>
@@ -498,7 +509,8 @@
                     {
                         AnnotationResponse response = new AnnotationResponse
                         {
-                            annotation = request.annotation, time = datapoint[TimeSeriesValues.Time]
+                            annotation = request.annotation,
+                            time = datapoint[TimeSeriesValues.Time]
                         };

                         type.PopulateResponse(response, target, definition, datapoint, Metadata);


Updated advancedsamples PolygonBrush to have the correct namespace.

--- Demos/AdvancedSamplesXNA/DrawingSystem/PolygonBrush.cs
+++ Demos/AdvancedSamplesXNA/DrawingSystem/PolygonBrush.cs
@@ -3,7 +3,7 @@
 using Microsoft.Xna.Framework.Graphics;
 using FarseerGames.FarseerPhysics.Collisions;

-namespace FarseerGames.SimpleSamplesXNA.DrawingSystem
+namespace FarseerGames.AdvancedSamplesXNA.DrawingSystem
 {
     public class PolygonBrush
     {


Synchrophasor: Fixed error in the handling of socket disconnect in RemoteOutputAdapter.

git-tfs-id: [https://tfs.codeplex.com/tfs/TFS07]$/openpdc/Synchrophasor/Current Version;C30338

--- Source/Libraries/Adapters/HistorianAdapters/RemoteOutputAdapter.cs
+++ Source/Libraries/Adapters/HistorianAdapters/RemoteOutputAdapter.cs
@@ -14,6 +14,8 @@
 //       Added new header and license agreement.
 //  09/22/2009 - Pinal C. Patel
 //       Re-wrote the adapter to utilize new components.
+//  09/23/2009 - Pinal C. Patel
+//       Fixed the handling of socket disconnect.
 //
 //*******************************************************************************************************

@@ -454,6 +456,9 @@
         /// <exception cref="OperationCanceledException">Acknowledgement is not received from historian for published data.</exception>
         protected override void ProcessMeasurements(IMeasurement[] measurements)
         {
+            if (m_historianPublisher.CurrentState != ClientState.Connected)
+                throw new InvalidOperationException("Historian publisher socket is not connected");
+
             try
             {
                 double publishTime = Common.SystemTimer;
@@ -494,21 +499,11 @@

         private void HistorianPublisher_ConnectionTerminated(object sender, EventArgs e)
         {
-            OnDisconnected();
             m_publisherReady = false;
             m_publishedMeasurements = 0;

-            try
-            {
-                if (!m_publisherDisconnecting)
-                    AttemptConnection();
-            }
-            catch (Exception ex)
-            {
-                OnProcessException(ex);
-                if (Enabled)
-                    Start();
-            }
+            if (!m_publisherDisconnecting)
+                Start();
         }

         private void HistorianPublisher_SendDataException(object sender, EventArgs<Exception> e)


Working towards DI compatibility.

Working towards DI compatibility.

A lot of members are now protected instead of private. Introduced a new protected constructor that takes all parameters needed for work.

--- DevTrends.MvcDonutCaching/DonutOutputCacheAttribute.cs
+++ DevTrends.MvcDonutCaching/DonutOutputCacheAttribute.cs
@@ -10,24 +10,40 @@
     [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
     public class DonutOutputCacheAttribute : ActionFilterAttribute, IExceptionFilter
     {
-        private readonly ICacheHeadersHelper _cacheHeadersHelper;
-        private readonly ICacheSettingsManager _cacheSettingsManager;
-        private readonly IDonutHoleFiller _donutHoleFiller;
-        private readonly IKeyGenerator _keyGenerator;
-        private readonly IReadWriteOutputCacheManager _outputCacheManager;
-        private CacheSettings _cacheSettings;
+        // Protected
+        protected readonly ICacheHeadersHelper CacheHeadersHelper;
+        protected readonly ICacheSettingsManager CacheSettingsManager;
+        protected readonly IDonutHoleFiller DonutHoleFiller;
+        protected readonly IKeyGenerator KeyGenerator;
+        protected readonly IReadWriteOutputCacheManager OutputCacheManager;
+        protected CacheSettings CacheSettings;
+
+        // Private
         private bool? _noStore;
         private OutputCacheOptions? _options;

         public DonutOutputCacheAttribute() : this(new KeyBuilder()) { }

-        public DonutOutputCacheAttribute(IKeyBuilder keyBuilder)
-        {
-            _keyGenerator         = new KeyGenerator(keyBuilder);
-            _outputCacheManager   = new OutputCacheManager(OutputCache.Instance, keyBuilder);
-            _donutHoleFiller      = new DonutHoleFiller(new EncryptingActionSettingsSerialiser(new ActionSettingsSerialiser(), new Encryptor()));
-            _cacheSettingsManager = new CacheSettingsManager();
-            _cacheHeadersHelper   = new CacheHeadersHelper();
+        public DonutOutputCacheAttribute(IKeyBuilder keyBuilder) :
+            this(
+               new KeyGenerator(keyBuilder),
+               new OutputCacheManager(OutputCache.Instance, keyBuilder),
+               new DonutHoleFiller(new EncryptingActionSettingsSerialiser(new ActionSettingsSerialiser(), new Encryptor())),
+               new CacheSettingsManager(),
+               new CacheHeadersHelper()
+        )
+        { }
+
+        protected DonutOutputCacheAttribute(
+            IKeyGenerator keyGenerator, IReadWriteOutputCacheManager outputCacheManager,
+            IDonutHoleFiller donutHoleFiller, ICacheSettingsManager cacheSettingsManager, ICacheHeadersHelper cacheHeadersHelper
+        )
+        {
+            KeyGenerator = keyGenerator;
+            OutputCacheManager = outputCacheManager;
+            DonutHoleFiller = donutHoleFiller;
+            CacheSettingsManager = cacheSettingsManager;
+            CacheHeadersHelper = cacheHeadersHelper;

             Duration = -1;
             Location = (OutputCacheLocation)(-1);
@@ -112,7 +128,7 @@

         public void OnException(ExceptionContext filterContext)
         {
-            if (_cacheSettings != null)
+            if (CacheSettings != null)
             {
                 ExecuteCallback(filterContext, true);
             }
@@ -124,23 +140,23 @@
         /// <param name="filterContext">The filter context.</param>
         public override void OnActionExecuting(ActionExecutingContext filterContext)
         {
-            _cacheSettings = BuildCacheSettings();
-
-            var cacheKey = _keyGenerator.GenerateKey(filterContext, _cacheSettings);
+            CacheSettings = BuildCacheSettings();
+
+            var cacheKey = KeyGenerator.GenerateKey(filterContext, CacheSettings);

             // Are we actually storing data on the server side ?
-            if (_cacheSettings.IsServerCachingEnabled)
+            if (CacheSettings.IsServerCachingEnabled)
             {
                 ICacheItem cachedItem = null;

                 // If the request is a POST, we lookup for NoCacheLookupForPosts option
                 // We are fetching the stored value only if the option has not been set and the request is not a POST
                 if (
-                    (_cacheSettings.Options & OutputCacheOptions.NoCacheLookupForPosts) != OutputCacheOptions.NoCacheLookupForPosts ||
+                    (CacheSettings.Options & OutputCacheOptions.NoCacheLookupForPosts) != OutputCacheOptions.NoCacheLookupForPosts ||
                     filterContext.HttpContext.Request.HttpMethod != "POST"
                 )
                 {
-                    cachedItem = _outputCacheManager.GetItem(cacheKey);
+                    cachedItem = OutputCacheManager.GetItem(cacheKey);
                 }

                 // We have a cached version on the server side
@@ -150,7 +166,7 @@
                     // The MVC action won't execute as we injected the previous cached result.
                     filterContext.Result = new ContentResult
                     {
-                        Content = _donutHoleFiller.ReplaceDonutHoleContent(cachedItem.Content, filterContext, _cacheSettings.Options),
+                        Content = DonutHoleFiller.ReplaceDonutHoleContent(cachedItem.Content, filterContext, CacheSettings.Options),
                         ContentType = cachedItem.ContentType
                     };
                 }
@@ -192,12 +208,12 @@
                 };

                 filterContext.HttpContext.Response.Write(
-                    _donutHoleFiller.RemoveDonutHoleWrappers(cacheItem.Content, filterContext, _cacheSettings.Options)
+                    DonutHoleFiller.RemoveDonutHoleWrappers(cacheItem.Content, filterContext, CacheSettings.Options)
                 );

-                if (_cacheSettings.IsServerCachingEnabled && filterContext.HttpContext.Response.StatusCode == 200)
-                {
-                    _outputCacheManager.AddItem(cacheKey, cacheItem, DateTime.UtcNow.AddSeconds(_cacheSettings.Duration));
+                if (CacheSettings.IsServerCachingEnabled && filterContext.HttpContext.Response.StatusCode == 200)
+                {
+                    OutputCacheManager.AddItem(cacheKey, cacheItem, DateTime.UtcNow.AddSeconds(CacheSettings.Duration));
                 }
             });
         }
@@ -208,7 +224,7 @@
         /// <param name="filterContext">The filter context.</param>
         public override void OnResultExecuted(ResultExecutedContext filterContext)
         {
-            if (_cacheSettings == null)
+            if (CacheSettings == null)
             {
                 return;
             }
@@ -220,7 +236,7 @@
             // the right HTTP Cache headers for the final response.
             if (!filterContext.IsChildAction)
             {
-                _cacheHeadersHelper.SetCacheHeaders(filterContext.HttpContext.Response, _cacheSettings);
+                CacheHeadersHelper.SetCacheHeaders(filterContext.HttpContext.Response, CacheSettings);
             }
         }

@@ -232,7 +248,7 @@
             {
                 cacheSettings = new CacheSettings
                 {
-                    IsCachingEnabled = _cacheSettingsManager.IsCachingEnabledGlobally,
+                    IsCachingEnabled = CacheSettingsManager.IsCachingEnabledGlobally,
                     Duration = Duration,
                     VaryByCustom = VaryByCustom,
                     VaryByParam = VaryByParam,
@@ -243,11 +259,11 @@
             }
             else
             {
-                var cacheProfile = _cacheSettingsManager.RetrieveOutputCacheProfile(CacheProfile);
+                var cacheProfile = CacheSettingsManager.RetrieveOutputCacheProfile(CacheProfile);

                 cacheSettings = new CacheSettings
                 {
-                    IsCachingEnabled = _cacheSettingsManager.IsCachingEnabledGlobally && cacheProfile.Enabled,
+                    IsCachingEnabled = CacheSettingsManager.IsCachingEnabledGlobally && cacheProfile.Enabled,
                     Duration = Duration == -1 ? cacheProfile.Duration : Duration,
                     VaryByCustom = VaryByCustom ?? cacheProfile.VaryByCustom,
                     VaryByParam = VaryByParam ?? cacheProfile.VaryByParam,
@@ -272,7 +288,7 @@

         private void ExecuteCallback(ControllerContext context, bool hasErrors)
         {
-            var cacheKey = _keyGenerator.GenerateKey(context, _cacheSettings);
+            var cacheKey = KeyGenerator.GenerateKey(context, CacheSettings);

             var callback = context.HttpContext.Items[cacheKey] as Action<bool>;


Improved `getprops`

Improved `getprops`

--- src/Main/Hadouken.Impl/Http/Api/GetProperties.cs
+++ src/Main/Hadouken.Impl/Http/Api/GetProperties.cs
@@ -21,17 +21,29 @@
         {
             string hash = Context.Request.QueryString["hash"];

-            if(_torrentEngine.Managers.ContainsKey(hash))
+            if (_torrentEngine.Managers.ContainsKey(hash))
             {
                 var manager = _torrentEngine.Managers[hash];
-                return Json(new[]
+                return Json(new
                                 {
-                                    new
-                                        {
-                                            hash = manager.InfoHash,
-                                            trackers = "",
-                                            //ulrate = manager.Settings
-                                        }
+                                    props = new[]
+                                                {
+                                                    new
+                                                        {
+                                                            hash = manager.InfoHash,
+                                                            trackers = "",
+                                                            ulrate = manager.Settings.MaxUploadSpeed,
+                                                            dlrate = manager.Settings.MaxDownloadSpeed,
+                                                            superseed = manager.IsInitialSeeding,
+                                                            dht = manager.Settings.UseDht,
+                                                            pex = manager.Settings.EnablePeerExchange,
+                                                            seed_override = false,
+                                                            seed_ratio = 0,
+                                                            seed_time = 0,
+                                                            ulslots = manager.Settings.UploadSlots,
+                                                            seed_num = 0
+                                                        }
+                                                }
                                 });
             }


Resubmit of failed check-in.  Git bug?

Resubmit of failed check-in.  Git bug?

--- Source/Plugins/Lizitt/Outfitter/Framework/Editor/BodyPartEditor.cs
+++ Source/Plugins/Lizitt/Outfitter/Framework/Editor/BodyPartEditor.cs
@@ -101,7 +101,7 @@

             var nstatus = EditorGUIDraw.FilteredColliderStatusPopup(
                 EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight), m_StatusLabel,
-                bp.ColliderBehavior, ColliderBehaviorCategory.Rigidbody);
+                bp.ColliderBehavior, ColliderBehaviorCategory.RigidBody);

             if (nstatus != bp.ColliderBehavior)
                 EditorGUIUtil.SetRigidbodyBehavior(bp.Collider.GetAssociatedRigidBody(), (RigidbodyBehavior)nstatus);


Update SpecialOffer_Functions.cs

Update SpecialOffer_Functions.cs

--- Test/AdventureWorksFunctionalModel/Sales/SpecialOffer_Functions.cs
+++ Test/AdventureWorksFunctionalModel/Sales/SpecialOffer_Functions.cs
@@ -21,8 +21,6 @@
         public static (SpecialOffer, IContext) EditDescription(this SpecialOffer sp, string description, IContext context)
         => context.SaveAndDisplay(sp with { Description = description, ModifiedDate = context.Now() });

-        public static bool HideEditDescription(this SpecialOffer sp, IContext context) =>
-            HideIfEnded(sp, context);

         [Edit]
         public static (SpecialOffer, IContext) EditDiscount(this SpecialOffer sp, decimal discountPct, IContext context)
@@ -34,6 +32,9 @@
         [Edit]
         public static (SpecialOffer, IContext) EditType(this SpecialOffer sp, string type, IContext context)
         => context.SaveAndDisplay(sp with { Type = type, ModifiedDate = context.Now() });
+
+        public static bool HideEditType(this SpecialOffer sp, IContext context) =>
+            HideIfEnded(sp, context);

         [Edit]
         public static (SpecialOffer, IContext) EditCategory(this SpecialOffer sp, string category, IContext context)


Improved performance of some commonly used queries

--- Duplicati/Library/Main/Database/LocalBackupDatabase.cs
+++ Duplicati/Library/Main/Database/LocalBackupDatabase.cs
@@ -518,7 +518,10 @@

                     default:
                         m_findfilesetCommand.Transaction = transaction;
-                        fileidobj = m_findfilesetCommand.ExecuteScalar(null, blocksetID, metadataID, filename);
+                        m_findfilesetCommand.SetParameterValue(0, blocksetID);
+                        m_findfilesetCommand.SetParameterValue(1, metadataID);
+                        m_findfilesetCommand.SetParameterValue(2, filename);
+                        fileidobj = m_findfilesetCommand.ExecuteScalar();
                         if (fileidobj == null || fileidobj == DBNull.Value)
                             m_filesetLookup.FalsePositives++;
                         else
@@ -529,7 +532,10 @@
             else
             {
                 m_findfilesetCommand.Transaction = transaction;
-                fileidobj = m_findfilesetCommand.ExecuteScalar(null, blocksetID, metadataID, filename);
+                m_findfilesetCommand.SetParameterValue(0, blocksetID);
+                m_findfilesetCommand.SetParameterValue(1, metadataID);
+                m_findfilesetCommand.SetParameterValue(2, filename);
+                fileidobj = m_findfilesetCommand.ExecuteScalar();
             }

             if (fileidobj == null || fileidobj == DBNull.Value)
@@ -593,7 +599,8 @@
                 }
             }

-            using(var rd = m_selectfileSimpleCommand.ExecuteReader(null, path))
+            m_selectfileSimpleCommand.SetParameterValue(0, path);
+            using(var rd = m_selectfileSimpleCommand.ExecuteReader())
                 if (rd.Read())
                 {
                     if (m_fileScantimeLookup != null)


183: 	App crash when attempting to re-dock a floating putty window (fix applied)

git-svn-id: 67c3ee79c80598486550ce992e66ca9291e224ee@240 8d6e282c-8220-11de-b77e-d9b456c0130a

--- SuperPutty/Utils/TabSwitcher.cs
+++ SuperPutty/Utils/TabSwitcher.cs
@@ -46,7 +46,6 @@

             this.DockPanel = dockPanel;
             this.DockPanel.ContentAdded += DockPanel_ContentAdded;
-            this.DockPanel.ContentRemoved += DockPanel_ContentRemoved;
         }

         public ITabSwitchStrategy TabSwitchStrategy
@@ -97,14 +96,17 @@
                 {
                     if (e.Content.DockHandler.DockState == DockState.Document)
                     {
-                        this.AddDocument((ToolWindow)e.Content);
+                        ToolWindow window = (ToolWindow)e.Content;
+                        this.AddDocument(window);
+                        window.FormClosed += window_FormClosed;
                     }
                 }));
         }

-        void DockPanel_ContentRemoved(object sender, DockContentEventArgs e)
-        {
-            this.RemoveDocument((ToolWindow)e.Content);
+        void window_FormClosed(object sender, System.Windows.Forms.FormClosedEventArgs e)
+        {
+            ToolWindow window = (ToolWindow)sender;
+            this.RemoveDocument((ToolWindow)sender);
         }

         void AddDocument(ToolWindow tab)
@@ -142,7 +144,10 @@
         public void Dispose()
         {
             this.DockPanel.ContentAdded -= DockPanel_ContentAdded;
-            this.DockPanel.ContentRemoved -= DockPanel_ContentRemoved;
+            foreach (ToolWindow win in this.Documents)
+            {
+                win.FormClosed -= this.window_FormClosed;
+            }
         }

         public ToolWindow ActiveDocument { get { return (ToolWindow)this.DockPanel.ActiveDocument; } }
@@ -227,6 +232,8 @@
     #region VisualOrderTabSwitchStrategy
     public class VisualOrderTabSwitchStrategy : AbstractOrderedTabSwitchStrategy
     {
+        private static readonly ILog Log = LogManager.GetLogger(typeof(VisualOrderTabSwitchStrategy));
+
         public VisualOrderTabSwitchStrategy() :
             base("Visual: Left-to-Right, Top-to-Bottom") { }

@@ -245,7 +252,13 @@
                 {
                     if (pane.Appearance == DockPane.AppearanceStyle.Document)
                     {
-                        docs.AddRange(pane.Contents);
+                        foreach (IDockContent content in pane.Contents)
+                        {
+                            if (content.DockHandler.DockState == DockState.Document)
+                            {
+                                docs.Add(content);
+                            }
+                        }
                         //Log.InfoFormat("\tPane: contents={0}, L={1}, T={2}", pane.Contents.Count, pane.Left, pane.Top);
                         //foreach (IDockContent content in pane.Contents) { //Log.Info("\t\t" + content.DockHandler.TabText); }
                     }


Convert ResolvePropertyName to expression bodied method

--- src/NodaTime.Serialization.JsonNet/Extensions.cs
+++ src/NodaTime.Serialization.JsonNet/Extensions.cs
@@ -160,14 +160,12 @@

         /// <summary>
         /// Resolves property name according <see cref="DefaultContractResolver.NamingStrategy"/>.
-        /// <para>If serializer is not DefaultContractResolver then original propertyName returns.</para>
+        /// <para>If serializer is not <see cref="DefaultContractResolver"/> then original <paramref name="propertyName"/> returns.</para>
         /// </summary>
         /// <param name="serializer">The serializer to use name resolve.</param>
         /// <param name="propertyName">Property name.</param>
-        /// <returns>Resolved propertyName.</returns>
-        internal static string ResolvePropertyName(this JsonSerializer serializer, string propertyName)
-        {
-            return (serializer.ContractResolver as DefaultContractResolver)?.GetResolvedPropertyName(propertyName) ?? propertyName;
-        }
+        /// <returns>Resolved or original property name.</returns>
+        internal static string ResolvePropertyName(this JsonSerializer serializer, string propertyName) =>
+            (serializer.ContractResolver as DefaultContractResolver)?.GetResolvedPropertyName(propertyName) ?? propertyName;
     }
 }


Include GuessZoneIdByTransitionsUncached in non-PCL builds, for better testing.

--- src/NodaTime/TimeZones/TzdbDateTimeZoneSource.cs
+++ src/NodaTime/TimeZones/TzdbDateTimeZoneSource.cs
@@ -242,6 +242,7 @@
                 return guess;
             }
         }
+#endif

         /// <summary>
         /// In cases where we can't get a zone mapping, either because we haven't kept
@@ -253,6 +254,8 @@
         /// transitions in all primary mappings for the next year.
         /// Heuristically, this seems to be good enough to get the right results in most cases.
         /// </summary>
+        /// <remarks>This method is not PCL-only as we would like to test it frequently. It will
+        /// never actually be called in the non-PCL release though.</remarks>
         /// <param name="zone">Zone to resolve in a best-effort fashion.</param>
         internal string GuessZoneIdByTransitionsUncached(TimeZoneInfo zone)
         {
@@ -282,7 +285,6 @@
             // If we haven't hit at least 70%, it's effectively unmappable
             return bestScore * 100 / instants.Count > 70 ? bestZone.Id : null;
         }
-#endif

         /// <summary>
         /// Returns a lookup from canonical time zone ID (e.g. "Europe/London") to a group of aliases for that time zone


double_col tests

double_col tests

--- src/Parquet.Test/ParquetReaderOnTestFilesTest.cs
+++ src/Parquet.Test/ParquetReaderOnTestFilesTest.cs
@@ -114,6 +114,17 @@
                Assert.Equal((float)0.0, floatCol.Values[6]);
                Assert.Equal((float)1.1, floatCol.Values[7]);

+               ParquetColumn doubleCol = ds.Columns[7];
+               Assert.Equal("double_col", doubleCol.Name);
+               Assert.Equal((double)0.0, doubleCol.Values[0]);
+               Assert.Equal((double)10.1, doubleCol.Values[1]);
+               Assert.Equal((double)0.0, doubleCol.Values[2]);
+               Assert.Equal((double)10.1, doubleCol.Values[3]);
+               Assert.Equal((double)0.0, doubleCol.Values[4]);
+               Assert.Equal((double)10.1, doubleCol.Values[5]);
+               Assert.Equal((double)0.0, doubleCol.Values[6]);
+               Assert.Equal((double)10.1, doubleCol.Values[7]);
+
             }
          }