Add test to cover spatial aggregation bug (#2823)

--- test/OpenTelemetry.Tests/Metrics/MetricAPITest.cs
+++ test/OpenTelemetry.Tests/Metrics/MetricAPITest.cs
@@ -15,7 +15,9 @@
 // </copyright>

 using System;
+using System.Buffers;
 using System.Collections.Generic;
+using System.ComponentModel.Design;
 using System.Diagnostics;
 using System.Diagnostics.Metrics;
 using System.Threading;
@@ -385,6 +387,131 @@
         [Theory]
         [InlineData(true)]
         [InlineData(false)]
+        public void ObservableCounterWithTagsAggregationTest(bool exportDelta)
+        {
+            var exportedItems = new List<Metric>();
+            var tags1 = new List<KeyValuePair<string, object>>();
+            tags1.Add(new("statusCode", 200));
+            tags1.Add(new("verb", "get"));
+
+            var tags2 = new List<KeyValuePair<string, object>>();
+            tags2.Add(new("statusCode", 200));
+            tags2.Add(new("verb", "post"));
+
+            var tags3 = new List<KeyValuePair<string, object>>();
+            tags3.Add(new("statusCode", 500));
+            tags3.Add(new("verb", "get"));
+
+            using var meter = new Meter($"{Utils.GetCurrentMethodName()}.{exportDelta}");
+            var counterLong = meter.CreateObservableCounter(
+                "observable-counter",
+                () =>
+                {
+                    return new List<Measurement<long>>()
+                    {
+                        new Measurement<long>(10, tags1),
+                        new Measurement<long>(10, tags2),
+                        new Measurement<long>(10, tags3),
+                    };
+                });
+
+            using var meterProvider = Sdk.CreateMeterProviderBuilder()
+                .AddMeter(meter.Name)
+                .AddReader(new BaseExportingMetricReader(new InMemoryExporter<Metric>(exportedItems))
+                {
+                    Temporality = exportDelta ? AggregationTemporality.Delta : AggregationTemporality.Cumulative,
+                })
+                .Build();
+
+            meterProvider.ForceFlush(MaxTimeToAllowForFlush);
+            Assert.Single(exportedItems);
+            var metric = exportedItems[0];
+            Assert.Equal("observable-counter", metric.Name);
+            List<MetricPoint> metricPoints = new List<MetricPoint>();
+            foreach (ref readonly var mp in metric.GetMetricPoints())
+            {
+                metricPoints.Add(mp);
+            }
+
+            Assert.Equal(3, metricPoints.Count);
+
+            var metricPoint1 = metricPoints[0];
+            Assert.Equal(10, metricPoint1.GetSumLong());
+            ValidateMetricPointTags(tags1, metricPoint1.Tags);
+
+            var metricPoint2 = metricPoints[1];
+            Assert.Equal(10, metricPoint2.GetSumLong());
+            ValidateMetricPointTags(tags2, metricPoint2.Tags);
+
+            var metricPoint3 = metricPoints[2];
+            Assert.Equal(10, metricPoint3.GetSumLong());
+            ValidateMetricPointTags(tags3, metricPoint3.Tags);
+        }
+
+        [Theory(Skip = "Known issue.")]
+        [InlineData(true)]
+        [InlineData(false)]
+        public void ObservableCounterSpatialAggregationTest(bool exportDelta)
+        {
+            var exportedItems = new List<Metric>();
+            var tags1 = new List<KeyValuePair<string, object>>();
+            tags1.Add(new("statusCode", 200));
+            tags1.Add(new("verb", "get"));
+
+            var tags2 = new List<KeyValuePair<string, object>>();
+            tags2.Add(new("statusCode", 200));
+            tags2.Add(new("verb", "post"));
+
+            var tags3 = new List<KeyValuePair<string, object>>();
+            tags3.Add(new("statusCode", 500));
+            tags3.Add(new("verb", "get"));
+
+            using var meter = new Meter($"{Utils.GetCurrentMethodName()}.{exportDelta}");
+            var counterLong = meter.CreateObservableCounter(
+                "requestCount",
+                () =>
+                {
+                    return new List<Measurement<long>>()
+                    {
+                        new Measurement<long>(10, tags1),
+                        new Measurement<long>(10, tags2),
+                        new Measurement<long>(10, tags3),
+                    };
+                });
+
+            using var meterProvider = Sdk.CreateMeterProviderBuilder()
+                .AddMeter(meter.Name)
+                .AddReader(new BaseExportingMetricReader(new InMemoryExporter<Metric>(exportedItems))
+                {
+                    Temporality = exportDelta ? AggregationTemporality.Delta : AggregationTemporality.Cumulative,
+                })
+                .AddView("requestCount", new MetricStreamConfiguration() { TagKeys = new string[] { } })
+                .Build();
+
+            meterProvider.ForceFlush(MaxTimeToAllowForFlush);
+            Assert.Single(exportedItems);
+            var metric = exportedItems[0];
+            Assert.Equal("requestCount", metric.Name);
+            List<MetricPoint> metricPoints = new List<MetricPoint>();
+            foreach (ref readonly var mp in metric.GetMetricPoints())
+            {
+                metricPoints.Add(mp);
+            }
+
+            Assert.Single(metricPoints);
+
+            var emptyTags = new List<KeyValuePair<string, object>>();
+            var metricPoint1 = metricPoints[0];
+            ValidateMetricPointTags(emptyTags, metricPoint1.Tags);
+
+            // This will fail, as SDK is not "spatially" aggregating the
+            // requestCount
+            Assert.Equal(30, metricPoint1.GetSumLong());
+        }
+
+        [Theory]
+        [InlineData(true)]
+        [InlineData(false)]
         public void DimensionsAreOrderInsensitiveWithSortedKeysFirst(bool exportDelta)
         {
             var exportedItems = new List<Metric>();
@@ -796,6 +923,19 @@
             var counter = meter.CreateCounter<long>("counter");

             counter.Add(10, new KeyValuePair<string, object>("key", "value"));
+        }
+
+        private static void ValidateMetricPointTags(List<KeyValuePair<string, object>> expectedTags, ReadOnlyTagCollection actualTags)
+        {
+            int tagIndex = 0;
+            foreach (var tag in actualTags)
+            {
+                Assert.Equal(expectedTags[tagIndex].Key, tag.Key);
+                Assert.Equal(expectedTags[tagIndex].Value, tag.Value);
+                tagIndex++;
+            }
+
+            Assert.Equal(expectedTags.Count, tagIndex);
         }

         private static long GetLongSum(List<Metric> metrics)


Added back optional SignInMessage for AuthenticateLocal

--- source/Core/Services/IUserService.cs
+++ source/Core/Services/IUserService.cs
@@ -24,7 +24,7 @@
     public interface IUserService
     {
         Task<AuthenticateResult> PreAuthenticateAsync(SignInMessage message);
-        Task<AuthenticateResult> AuthenticateLocalAsync(string username, string password, SignInMessage message);
+        Task<AuthenticateResult> AuthenticateLocalAsync(string username, string password, SignInMessage message = null);
         Task<AuthenticateResult> AuthenticateExternalAsync(ExternalIdentity externalUser);
         Task SignOutAsync(ClaimsPrincipal subject);


(Fast snake-autosuicide fix)

(Fast snake-autosuicide fix)

--- source/Cosmos.Demos.Snake/Program.cs
+++ source/Cosmos.Demos.Snake/Program.cs
@@ -56,14 +56,22 @@
         {
             if (snake != null && !aReleased)
             {
-                if (aScanCode == (byte)Key.Left)
+                if (aScanCode == (byte)Key.Left && snake.direction != Direction.Right)
+                {
                     snake.direction = Direction.Left;
-                else if (aScanCode == (byte)Key.Up)
+                }
+                else if (aScanCode == (byte)Key.Up && snake.direction != Direction.Down)
+                {
                     snake.direction = Direction.Up;
-                else if (aScanCode == (byte)Key.Right)
+                }
+                else if (aScanCode == (byte)Key.Right && snake.direction != Direction.Left)
+                {
                     snake.direction = Direction.Right;
-                else if (aScanCode == (byte)Key.Down)
+                }
+                else if (aScanCode == (byte)Key.Down && snake.direction != Direction.Up)
+                {
                     snake.direction = Direction.Down;
+                }
                 else if (aScanCode == (byte)Key.Escape)
                     running = false;
             }
@@ -198,7 +206,7 @@
                     pause--;

                 isBlocked[snake.X + snake.Y * S.Columns] = Blocked.Snake;
-
+
                 switch(snake.direction)
                 {
                     case Direction.Left:


Add IsUndefinedBindingResult (#244)

Add IsUndefinedBindingResult (#244)

Add a public util method that checks for the internal type `UndefinedBindingResult` so a registered helper can check for undefined. (Say, to create a custom helper with "coalesce" semantics).

--- source/Handlebars/HandlebarsUtils.cs
+++ source/Handlebars/HandlebarsUtils.cs
@@ -10,6 +10,11 @@
         public static bool IsTruthy(object value)
         {
             return !IsFalsy(value);
+        }
+
+        public static bool IsUndefinedBindingResult(object value)
+        {
+            return value is UndefinedBindingResult;
         }

         public static bool IsFalsy(object value)


Added ShortCode to Organisation

Added ShortCode to Organisation

ShortCode has been available in the API since the Mar 11,
2013 version 2.22 release so have put it in the wrapper.
The caveat described in https://community.xero.com/developer/discussion/1167775
"ShortCodes will be changing in an upcoming release on March
25th 2013 - after this date, the ShortCode retrieved via
the API will not change, but prior to this, will be unique,
but the value is not permanent" has passed so this should be safe.

--- source/XeroApi/Model/Organisation.cs
+++ source/XeroApi/Model/Organisation.cs
@@ -35,6 +35,8 @@
         public int FinancialYearEndMonth;

         public string Timezone;
+
+        public string ShortCode;

         public override string ToString()
         {


Better isControl frame

Better isControl frame

--- wslib/Protocol/WebSocket.cs
+++ wslib/Protocol/WebSocket.cs
@@ -86,7 +86,7 @@
             while (IsConnected())
             {
                 var frame = await WsDissector.ReadFrameHeader(stream, serverSocket, cancellationToken).ConfigureAwait(false);
-                if (!isDataFrame(frame))
+                if (isControlFrame(frame))
                 {
                     await processControlFrame(frame, cancellationToken).ConfigureAwait(false);
                     continue;
@@ -178,9 +178,9 @@
             await SendMessage(WsFrameHeader.Opcodes.PONG, payload, cancellationToken).ConfigureAwait(false);
         }

-        private static bool isDataFrame(WsFrame frame)
-        {
-            return frame.Header.OPCODE == WsFrameHeader.Opcodes.BINARY || frame.Header.OPCODE == WsFrameHeader.Opcodes.TEXT || frame.Header.OPCODE == WsFrameHeader.Opcodes.CONTINUATION;
+        private static bool isControlFrame(WsFrame frame)
+        {
+            return frame.Header.OPCODE >= WsFrameHeader.Opcodes.CLOSE;
         }

         public async Task SendMessage(WsFrameHeader.Opcodes opcode, byte[] payload, CancellationToken cancellationToken)
@@ -188,7 +188,7 @@
             await writeSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); // TODO: timeout
             try
             {
-                var header = WsDissector.SerializeFrameHeader(new WsFrameHeader(0, 0) { FIN = true, OPCODE = opcode }, payload.Length, null);
+                var header = WsDissector.SerializeFrameHeader(new WsFrameHeader { FIN = true, OPCODE = opcode }, payload.Length, null);
                 await stream.WriteAsync(header.Array, header.Offset, header.Count, cancellationToken).ConfigureAwait(false);
                 await stream.WriteAsync(payload, 0, payload.Length, cancellationToken).ConfigureAwait(false);
             }


dbl oops

dbl oops

--- trunk/DefaultCombat/Helpers/Extensions.cs
+++ trunk/DefaultCombat/Helpers/Extensions.cs
@@ -62,7 +62,7 @@
             new Debuff("Hunting Trap (Any)", 0),
             //Lost Island
             //Maelstrom Prison
-            new Debuff("Affliction (Force)", 0),
+            new Debuff("Affliction (Force)", 0)
             //Mandalorian Raiders
             //Red Reaper
             //Taral V


Group Window access together.

Group Window access together.

--- osu.Framework/Game.cs
+++ osu.Framework/Game.cs
@@ -109,12 +109,13 @@
                 Config = new FrameworkConfigManager(host.Storage);

             this.host = host;
-
-            host.Window?.SetupWindow(Config);
             host.Exiting += OnExiting;

             if (Window != null)
+            {
+                Window.SetupWindow(Config);
                 Window.Title = $@"osu.Framework (running ""{Name}"")";
+            }
         }

         [BackgroundDependencyLoader]


test: add MIT header

test: add MIT header

--- tests/Yaapii.Atoms.Tests/IO/TempDirectoryTests.cs
+++ tests/Yaapii.Atoms.Tests/IO/TempDirectoryTests.cs
@@ -1,4 +1,26 @@
-using System.IO;
+// MIT License
+//
+// Copyright(c) 2017 ICARUS Consulting GmbH
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+using System.IO;
 using Xunit;

 namespace Yaapii.Atoms.IO.Tests


Review config equality assertion helper

Review config equality assertion helper

--- tests/HttpConfigTests.cs
+++ tests/HttpConfigTests.cs
@@ -47,7 +47,7 @@
             var config = HttpConfig.Default.WithHeader("name", "value");
             Assert.That(config.Headers, Is.EqualTo(new HttpHeaderCollection().Set("name", "value")));

-            AssertConfigurationsExcept(config, HttpConfig.Default, Configuration.Headers);
+            AssertConfigurationsEqual(config, HttpConfig.Default, ExceptMember.Headers);
         }

         [Test]
@@ -58,7 +58,7 @@
             Assert.That(config.Headers, Is.EqualTo(new HttpHeaderCollection().Set("name1", "value1")
                                                                              .Set("name2", "value2")));

-            AssertConfigurationsExcept(config, HttpConfig.Default, Configuration.Headers);
+            AssertConfigurationsEqual(config, HttpConfig.Default, ExceptMember.Headers);
         }

         [Test]
@@ -68,8 +68,8 @@
             var config2 = HttpConfig.Default.WithHeaders(new HttpHeaderCollection().Set("name", "value"));
             Assert.That(config1.Headers, Is.EqualTo(config2.Headers));

-            AssertConfigurationsExcept(config1, config2, Configuration.Headers);
-            AssertConfigurationsExcept(config1, HttpConfig.Default, Configuration.Headers);
+            AssertConfigurationsEqual(config1, config2, ExceptMember.Headers);
+            AssertConfigurationsEqual(config1, HttpConfig.Default, ExceptMember.Headers);
         }

         [Test]
@@ -78,7 +78,7 @@
             var config = HttpConfig.Default.WithTimeout(new TimeSpan(0, 1, 0));
             Assert.That(config.Timeout, Is.EqualTo(new TimeSpan(0, 1, 0)));

-            AssertConfigurationsExcept(config, HttpConfig.Default, Configuration.Timeout);
+            AssertConfigurationsEqual(config, HttpConfig.Default, ExceptMember.Timeout);
         }

         [Test]
@@ -87,7 +87,7 @@
             var config = HttpConfig.Default.WithUserAgent("Spider/1.0");
             Assert.That(config.UserAgent, Is.EqualTo("Spider/1.0"));

-            AssertConfigurationsExcept(config, HttpConfig.Default, Configuration.UserAgent);
+            AssertConfigurationsEqual(config, HttpConfig.Default, ExceptMember.UserAgent);
         }

         [Test]
@@ -97,7 +97,7 @@
             var config = HttpConfig.Default.WithCredentials(credentials);
             Assert.That(config.Credentials, Is.SameAs(credentials));

-            AssertConfigurationsExcept(config, HttpConfig.Default, Configuration.Credentials);
+            AssertConfigurationsEqual(config, HttpConfig.Default, ExceptMember.Credentials);
         }

         [Test]
@@ -107,7 +107,7 @@
             Assert.That(config.UseDefaultCredentials, Is.EqualTo(true));
             Assert.That(config.Credentials, Is.EqualTo(HttpConfig.Default.Credentials));

-            AssertConfigurationsExcept(config, HttpConfig.Default, Configuration.UseDefaultCredentials);
+            AssertConfigurationsEqual(config, HttpConfig.Default, ExceptMember.UseDefaultCredentials);
         }

         [Test]
@@ -116,7 +116,7 @@
             var config = HttpConfig.Default.WithCookies(new[] { new Cookie("name", "value") });
             Assert.That(config.Cookies, Is.EquivalentTo(new[] { new Cookie("name", "value") }));

-            AssertConfigurationsExcept(config, HttpConfig.Default, Configuration.Cookies);
+            AssertConfigurationsEqual(config, HttpConfig.Default, ExceptMember.Cookies);
         }

         [Test]
@@ -125,10 +125,10 @@
             var config = HttpConfig.Default.WithIgnoreInvalidServerCertificate(true);
             Assert.That(config.IgnoreInvalidServerCertificate, Is.True);

-            AssertConfigurationsExcept(config, HttpConfig.Default, Configuration.IgnoreInvalidServerCertificate);
+            AssertConfigurationsEqual(config, HttpConfig.Default, ExceptMember.IgnoreInvalidServerCertificate);
         }

-        enum Configuration
+        enum ExceptMember
         {
             Headers,
             Timeout,
@@ -139,28 +139,28 @@
             IgnoreInvalidServerCertificate,
         }

-        static void AssertConfigurationsExcept(HttpConfig config1, HttpConfig config2, Configuration e)
+        static void AssertConfigurationsEqual(HttpConfig actual, HttpConfig expected, ExceptMember e)
         {
-            if (e != Configuration.Headers)
-                Assert.That(config1.Headers, Is.EqualTo(config2.Headers));
+            if (e != ExceptMember.Headers)
+                Assert.That(actual.Headers, Is.EqualTo(expected.Headers));

-            if (e != Configuration.Timeout)
-                Assert.That(config1.Timeout, Is.EqualTo(config2.Timeout));
+            if (e != ExceptMember.Timeout)
+                Assert.That(actual.Timeout, Is.EqualTo(expected.Timeout));

-            if (e != Configuration.UseDefaultCredentials)
-                Assert.That(config1.UseDefaultCredentials, Is.EqualTo(config2.UseDefaultCredentials));
+            if (e != ExceptMember.UseDefaultCredentials)
+                Assert.That(actual.UseDefaultCredentials, Is.EqualTo(expected.UseDefaultCredentials));

-            if (e != Configuration.Credentials)
-                Assert.That(config1.Credentials, Is.SameAs(config2.Credentials));
+            if (e != ExceptMember.Credentials)
+                Assert.That(actual.Credentials, Is.SameAs(expected.Credentials));

-            if (e != Configuration.UserAgent)
-                Assert.That(config1.UserAgent, Is.EqualTo(config2.UserAgent));
+            if (e != ExceptMember.UserAgent)
+                Assert.That(actual.UserAgent, Is.EqualTo(expected.UserAgent));

-            if (e != Configuration.Cookies)
-                Assert.That(config1.Cookies, Is.SameAs(config2.Cookies));
+            if (e != ExceptMember.Cookies)
+                Assert.That(actual.Cookies, Is.SameAs(expected.Cookies));

-            if (e != Configuration.IgnoreInvalidServerCertificate)
-                Assert.That(config1.IgnoreInvalidServerCertificate, Is.EqualTo(config2.IgnoreInvalidServerCertificate));
+            if (e != ExceptMember.IgnoreInvalidServerCertificate)
+                Assert.That(actual.IgnoreInvalidServerCertificate, Is.EqualTo(expected.IgnoreInvalidServerCertificate));
         }
     }
 }


Better color sorting for multiple starting points

--- AllColors/MainWindow.xaml.cs
+++ AllColors/MainWindow.xaml.cs
@@ -71,7 +71,7 @@
 					startCoords.Add((x: (byte)tPos.Position.X, y: (byte)tPos.Position.Y));
 					break;
 				default:
-					for (var n = rng.Next(9) + 1; n > 0; n--)
+					for (var n = rng.Next(4) + 1; n > 0; n--)
 						startCoords.Add((x: (byte)rng.Next(256), y: (byte)rng.Next(128)));
 					break;
 			}
@@ -94,6 +94,30 @@
 						.OrderBy(t => t.diff)
 						.Select(t => t.c)
 						.ToArray();
+				else
+				{
+					var n = startCoords.Count;
+					var buckets = new List<short>[n];
+					for (var i = 0; i < n; i++)
+						buckets[i] = new List<short>(uniqueColors / n + 1) {randomColors[i]};
+					for (var i = n; i < uniqueColors; i++)
+					{
+						var minBucketRank = buckets.Min(l => l.Count);
+						var qualifiedBuckets = buckets.Where(l => l.Count == minBucketRank).ToList();
+						var selectedBucket = qualifiedBuckets.Select(b => (diff: LinearDifference(randomColors[i], b[0]), b: b)).OrderBy(t => t.diff).Select(t => t.b).First();
+						selectedBucket.Add(randomColors[i]);
+					}
+					var maxBucketRank = buckets.Max(l => l.Count);
+					var zip = new List<short>();
+					for (var i = 0; i < maxBucketRank; i++)
+					for (var j = 0; j < n; j++)
+						if (i < buckets[j].Count)
+							zip.Add(buckets[j][i]);
+					if (zip.Count != randomColors.Length)
+						throw new InvalidOperationException("Looks like you screwed up the zipping");
+
+					randomColors = zip.ToArray();
+				}

 				//next we put the pixels one by one where they fit best (by cortesian coordinates in the color space)
 				var result = new short[128][];


refactoring

refactoring

--- AppMetrics.Client/Tracker.cs
+++ AppMetrics.Client/Tracker.cs
@@ -69,7 +69,7 @@
 			LoggingThread.Abort();
 		}

-		public void Log(string name, object val, MessagePriority priority = MessagePriority.Low)
+		public void Log(string name, string val, MessagePriority priority = MessagePriority.Low)
 		{
 			lock (Sync)
 			{
@@ -79,7 +79,7 @@
 				}
 				catch (Exception exc)
 				{
-					Log("Exception", exc);
+					Log(exc);
 				}

 				if (Messages.Count >= MaxMessagesCount)
@@ -98,29 +98,61 @@
 			}
 		}

+		public void Log(Exception exc)
+		{
+			Log("Exception", exc.ToString(), MessagePriority.High);
+		}
+
+		public void Log(string name, object val, MessagePriority priority = MessagePriority.Low)
+		{
+			Log(name, val.ToString(), priority);
+		}
+
+		public void Log(string name, double val, MessagePriority priority = MessagePriority.Low)
+		{
+			Log(name, val.ToString(CultureInfo.InvariantCulture), priority);
+		}
+
+		public void Log(string name, float val, MessagePriority priority = MessagePriority.Low)
+		{
+			Log(name, val.ToString(CultureInfo.InvariantCulture), priority);
+		}
+
+		public void Log(string name, decimal val, MessagePriority priority = MessagePriority.Low)
+		{
+			Log(name, val.ToString(CultureInfo.InvariantCulture), priority);
+		}
+
+		public void Log(string name, long val, MessagePriority priority = MessagePriority.Low)
+		{
+			Log(name, val.ToString(CultureInfo.InvariantCulture), priority);
+		}
+
+		public void Log(string name, ulong val, MessagePriority priority = MessagePriority.Low)
+		{
+			Log(name, val.ToString(CultureInfo.InvariantCulture), priority);
+		}
+
+		public void LogFormat(string name, MessagePriority priority, string format, params object[] args)
+		{
+			var text = string.Format(CultureInfo.InvariantCulture, format, args);
+			Log(name, text, priority);
+		}
+
+		public void LogFormat(string name, string format, params object[] args)
+		{
+			LogFormat(name, MessagePriority.Low, format, args);
+		}
+
 		private const string WarningName = "AppMetrics.Warning";
 		private const string ErrorName = "AppMetrics.Error";

-		private void AddMessage(string name, object val, MessagePriority priority)
+		private void AddMessage(string name, string val, MessagePriority priority)
 		{
 			if (_terminated)
 				return;

-			string valText;
-			if (val == null)
-				valText = "";
-			else if (val is string)
-				valText = (string)val;
-			else if (val is double)
-				valText = ((double)val).ToString(CultureInfo.InvariantCulture);
-			else if (val is float)
-				valText = ((float)val).ToString(CultureInfo.InvariantCulture);
-			else if (val is decimal)
-				valText = ((decimal)val).ToString(CultureInfo.InvariantCulture);
-			else
-				valText = val.ToString();
-
-			valText = Util.Escape(valText);
+			var valText = Util.Escape(val ?? "");

 			lock (Sync)
 			{


Add handling for consumable EType

Add handling for consumable EType

--- ArchiSteamFarm/Json/Steam.cs
+++ ArchiSteamFarm/Json/Steam.cs
@@ -198,10 +198,7 @@
 				TradingCard,
 				SteamGems,
 				SaleItem,
-
-				// ReSharper disable once UnusedMember.Global - TODO: This type exists, but we don't know what item class it has, maybe we can fill it when consumables return in one of the future sales
 				Consumable,
-
 				ProfileModifier
 			}
 		}
@@ -581,6 +578,10 @@
 										type = Asset.EType.BoosterPack;

 										break;
+									case "item_class_6":
+										type = Asset.EType.Consumable;
+
+										break;
 									case "item_class_7":
 										type = Asset.EType.SteamGems;


Fix inkbunny fetch

Fix inkbunny fetch

--- ArtSourceWrapper/Inkbunny.cs
+++ ArtSourceWrapper/Inkbunny.cs
@@ -37,7 +37,7 @@
             }

             _rid = response.rid;
-            var details = await _client.GetSubmissionsAsync(response.submissions.Select(s => s.submission_id));
+            var details = await _client.GetSubmissionsAsync(response.submissions.Select(s => s.submission_id), show_description_bbcode_parsed: true);
             var wrappers = details.submissions
                 .Where(s => s.@public)
                 .OrderByDescending(s => s.create_datetime)


final fix for dead +spectate

final fix for dead +spectate

--- Assets/Scripts/ChatScript.cs
+++ Assets/Scripts/ChatScript.cs
@@ -207,6 +207,7 @@
                             case "/spectate":
                                 if (!ServerScript.Spectating)
                                 {
+                                    bool isDead = false;
                                     foreach (var p in FindObjectsOfType(typeof(PlayerScript)).Cast<PlayerScript>())
                                         if (p.networkView != null && p.networkView.isMine)
                                         {
@@ -214,6 +215,7 @@
                                             if (h.Health == 0)
                                             {
                                                 LogChat(Network.player, "Wait until you respawned to spectate", true, true);
+                                                isDead = true;
                                                 break;
                                             }

@@ -221,10 +223,12 @@
                                                                                RPCMode.All, true);
                                         }

-                                    ServerScript.Spectating = true;
-
-                                    networkView.RPC("LogChat", RPCMode.All, Network.player,
-                                                    "went in spectator mode.", true, false);
+                                    if (!isDead)
+                                    {
+                                        ServerScript.Spectating = true;
+                                        networkView.RPC("LogChat", RPCMode.All, Network.player,
+                                                        "went in spectator mode.", true, false);
+                                    }
                                 }
                                 else
                                     LogChat(Network.player, "Already spectating!", true, true);


smart enemies can shoot now

smart enemies can shoot now

--- Assets/Scripts/SmartEnemy.cs
+++ Assets/Scripts/SmartEnemy.cs
@@ -28,8 +28,9 @@
         base.Update();
         playerLoc = GameObject.Find("AlbertPlayerPrefab").transform.position;
         aim = Quaternion.LookRotation(playerLoc - transform.position);
-        shooter.rotation = Quaternion.Slerp(transform.rotation, aim, Time.deltaTime);
-
+        shooter.rotation = Quaternion.Slerp(transform.rotation, aim, Time.deltaTime * 100f);
+
+        Debug.Log( playerLoc);

 	}


Added some lost lines.

Added some lost lines.

--- Assets/Storage/NetStorage.cs
+++ Assets/Storage/NetStorage.cs
@@ -2,6 +2,7 @@
 using System.Collections.Generic;
 using SimpleJSON;
 using UnityEngine;
+using System.Collections;

 public class NetStorage : Storage
 {
@@ -13,7 +14,7 @@
 	private string authorization;
 	private NetStartListener netStartListener;
 	private Dictionary<string,string> trackHeaders = new Dictionary<string, string> ();
-
+
 	/// <summary>
 	/// </summary>
 	/// <param name="net">An object to interact with the network.</param>
@@ -28,10 +29,13 @@
 		this.authorization = "a:";

 		string filePath = Application.dataPath + "/Assets/track.txt";
+
 		if (Application.platform != RuntimePlatform.WebGLPlayer)
 		{
 			filePath = "file:///" + filePath;
 		}
+
+		WWW www = new WWW(filePath);

 		behaviour.StartCoroutine(WaitForRequest(www));
 	}
@@ -44,11 +48,16 @@
 	private IEnumerator WaitForRequest(WWW www)
 	{
 		yield return www;
-		string[] readLine = readLine.Split(';');
-		if(readLine.Length == 2)
+		// check for errors
+		if (www.error == null)
 		{
-			host = readLine[0];
-			trackingCode = readLine[1];
+			string line = www.text;
+			string[] readLine = line.Split(';');
+			if (readLine.Length == 2)
+			{
+				host = readLine[0];
+				trackingCode = readLine[1];
+			}
 		}
 	}

@@ -75,11 +84,11 @@
 	{
 		trackHeaders.Add ("Authorization", authToken);
 	}
-
+
 	public class NetStartListener : Tracker.StartListener
 	{
 		private NetStorage storage;
-
+
 		public NetStartListener (Tracker tracker, NetStorage storage) : base(tracker)
 		{
 			this.storage = storage;


[Modify] Polish it

[Modify] Polish it

--- websocket-sharp/Net/HttpListenerPrefix.cs
+++ websocket-sharp/Net/HttpListenerPrefix.cs
@@ -133,6 +133,7 @@
       var root = uriPrefix.IndexOf ('/', startHost + 1, len - startHost - 1);

       var colon = uriPrefix.LastIndexOf (':', root - 1, root - startHost - 1);
+
       if (uriPrefix[root - 1] != ']' && colon > startHost) {
         _host = uriPrefix.Substring (startHost, colon - startHost);
         _port = uriPrefix.Substring (colon + 1, root - colon - 1);
@@ -144,8 +145,13 @@

       _path = uriPrefix.Substring (root);

-      _prefix =
-        String.Format ("http{0}://{1}:{2}{3}", _secure ? "s" : "", _host, _port, _path);
+      _prefix = String.Format (
+                  "http{0}://{1}:{2}{3}",
+                  _secure ? "s" : "",
+                  _host,
+                  _port,
+                  _path
+                );
     }

     #endregion


Refactored WebSocketServer.cs

Refactored WebSocketServer.cs

--- websocket-sharp/Server/WebSocketServer.cs
+++ websocket-sharp/Server/WebSocketServer.cs
@@ -80,8 +80,8 @@
     /// Initializes a new instance of the <see cref="WebSocketServer"/> class.
     /// </summary>
     /// <remarks>
-    /// An instance initialized by this constructor listens for the incoming
-    /// connection requests on port 80.
+    /// An instance initialized by this constructor listens for the incoming connection requests on
+    /// port 80.
     /// </remarks>
     public WebSocketServer ()
       : this (80)
@@ -89,17 +89,16 @@
     }

     /// <summary>
-    /// Initializes a new instance of the <see cref="WebSocketServer"/> class
-    /// with the specified <paramref name="port"/>.
-    /// </summary>
-    /// <remarks>
-    ///   <para>
-    ///   An instance initialized by this constructor listens for the incoming
-    ///   connection requests on <paramref name="port"/>.
-    ///   </para>
-    ///   <para>
-    ///   And if <paramref name="port"/> is 443, that instance provides a secure
-    ///   connection.
+    /// Initializes a new instance of the <see cref="WebSocketServer"/> class with the specified
+    /// <paramref name="port"/>.
+    /// </summary>
+    /// <remarks>
+    ///   <para>
+    ///   An instance initialized by this constructor listens for the incoming connection requests
+    ///   on <paramref name="port"/>.
+    ///   </para>
+    ///   <para>
+    ///   And if <paramref name="port"/> is 443, that instance provides a secure connection.
     ///   </para>
     /// </remarks>
     /// <param name="port">
@@ -114,18 +113,18 @@
     }

     /// <summary>
-    /// Initializes a new instance of the <see cref="WebSocketServer"/> class
-    /// with the specified WebSocket URL.
-    /// </summary>
-    /// <remarks>
-    ///   <para>
-    ///   An instance initialized by this constructor listens for the incoming
-    ///   connection requests on the port (if any) in <paramref name="url"/>.
-    ///   </para>
-    ///   <para>
-    ///   So if <paramref name="url"/> is without a port, either port 80 or 443
-    ///   is used on which to listen. It's determined by the scheme (ws or wss)
-    ///   in <paramref name="url"/>. (port 80 if the scheme is ws.)
+    /// Initializes a new instance of the <see cref="WebSocketServer"/> class with the specified
+    /// WebSocket URL.
+    /// </summary>
+    /// <remarks>
+    ///   <para>
+    ///   An instance initialized by this constructor listens for the incoming connection requests
+    ///   on the port (if any) in <paramref name="url"/>.
+    ///   </para>
+    ///   <para>
+    ///   So if <paramref name="url"/> is without a port, either port 80 or 443 is used on which to
+    ///   listen. It's determined by the scheme (ws or wss) in <paramref name="url"/>. (port 80 if
+    ///   the scheme is ws.)
     ///   </para>
     /// </remarks>
     /// <param name="url">
@@ -150,8 +149,7 @@
       _address = host.ToIPAddress ();
       if (_address == null || !_address.IsLocal ())
         throw new ArgumentException (
-          String.Format (
-            "The host part must be the local host name: {0}", host), "url");
+          String.Format ("The host part must be the local host name: {0}", host), "url");

       _port = _uri.Port;
       _secure = _uri.Scheme == "wss" ? true : false;
@@ -160,19 +158,19 @@
     }

     /// <summary>
-    /// Initializes a new instance of the <see cref="WebSocketServer"/> class
-    /// with the specified <paramref name="port"/> and <paramref name="secure"/>.
-    /// </summary>
-    /// <remarks>
-    /// An instance initialized by this constructor listens for the incoming
-    /// connection requests on <paramref name="port"/>.
+    /// Initializes a new instance of the <see cref="WebSocketServer"/> class with the specified
+    /// <paramref name="port"/> and <paramref name="secure"/>.
+    /// </summary>
+    /// <remarks>
+    /// An instance initialized by this constructor listens for the incoming connection requests on
+    /// <paramref name="port"/>.
     /// </remarks>
     /// <param name="port">
     /// An <see cref="int"/> that represents the port number on which to listen.
     /// </param>
     /// <param name="secure">
-    /// A <see cref="bool"/> that indicates providing a secure connection or not.
-    /// (<c>true</c> indicates providing a secure connection.)
+    /// A <see cref="bool"/> that indicates providing a secure connection or not. (<c>true</c>
+    /// indicates providing a secure connection.)
     /// </param>
     /// <exception cref="ArgumentOutOfRangeException">
     /// <paramref name="port"/> isn't between 1 and 65535.
@@ -186,22 +184,20 @@
     }

     /// <summary>
-    /// Initializes a new instance of the <see cref="WebSocketServer"/> class
-    /// with the specified <paramref name="address"/> and <paramref name="port"/>.
-    /// </summary>
-    /// <remarks>
-    ///   <para>
-    ///   An instance initialized by this constructor listens for the incoming
-    ///   connection requests on <paramref name="port"/>.
-    ///   </para>
-    ///   <para>
-    ///   And if <paramref name="port"/> is 443, that instance provides a secure
-    ///   connection.
+    /// Initializes a new instance of the <see cref="WebSocketServer"/> class with the specified
+    /// <paramref name="address"/> and <paramref name="port"/>.
+    /// </summary>
+    /// <remarks>
+    ///   <para>
+    ///   An instance initialized by this constructor listens for the incoming connection requests
+    ///   on <paramref name="port"/>.
+    ///   </para>
+    ///   <para>
+    ///   And if <paramref name="port"/> is 443, that instance provides a secure connection.
     ///   </para>
     /// </remarks>
     /// <param name="address">
-    /// A <see cref="System.Net.IPAddress"/> that represents the local IP address
-    /// of the server.
+    /// A <see cref="System.Net.IPAddress"/> that represents the local IP address of the server.
     /// </param>
     /// <param name="port">
     /// An <see cref="int"/> that represents the port number on which to listen.
@@ -221,24 +217,22 @@
     }

     /// <summary>
-    /// Initializes a new instance of the <see cref="WebSocketServer"/> class
-    /// with the specified <paramref name="address"/>, <paramref name="port"/>,
-    /// and <paramref name="secure"/>.
-    /// </summary>
-    /// <remarks>
-    /// An instance initialized by this constructor listens for the incoming
-    /// connection requests on <paramref name="port"/>.
+    /// Initializes a new instance of the <see cref="WebSocketServer"/> class with the specified
+    /// <paramref name="address"/>, <paramref name="port"/>, and <paramref name="secure"/>.
+    /// </summary>
+    /// <remarks>
+    /// An instance initialized by this constructor listens for the incoming connection requests on
+    /// <paramref name="port"/>.
     /// </remarks>
     /// <param name="address">
-    /// A <see cref="System.Net.IPAddress"/> that represents the local IP address
-    /// of the server.
+    /// A <see cref="System.Net.IPAddress"/> that represents the local IP address of the server.
     /// </param>
     /// <param name="port">
     /// An <see cref="int"/> that represents the port number on which to listen.
     /// </param>
     /// <param name="secure">
-    /// A <see cref="bool"/> that indicates providing a secure connection or not.
-    /// (<c>true</c> indicates providing a secure connection.)
+    /// A <see cref="bool"/> that indicates providing a secure connection or not. (<c>true</c>
+    /// indicates providing a secure connection.)
     /// </param>
     /// <exception cref="ArgumentNullException">
     /// <paramref name="address"/> is <see langword="null"/>.
@@ -254,25 +248,21 @@
     ///   -or-
     ///   </para>
     ///   <para>
-    ///   Pair of <paramref name="port"/> and <paramref name="secure"/> is
-    ///   invalid.
+    ///   Pair of <paramref name="port"/> and <paramref name="secure"/> is invalid.
     ///   </para>
     /// </exception>
     public WebSocketServer (System.Net.IPAddress address, int port, bool secure)
     {
       if (!address.IsLocal ())
         throw new ArgumentException (
-          String.Format (
-            "Must be the local IP address: {0}", address), "address");
+          String.Format ("Must be the local IP address: {0}", address), "address");

       if (!port.IsPortNumber ())
-        throw new ArgumentOutOfRangeException (
-          "port", "Must be between 1 and 65535: " + port);
+        throw new ArgumentOutOfRangeException ("port", "Must be between 1 and 65535: " + port);

       if ((port == 80 && secure) || (port == 443 && !secure))
         throw new ArgumentException (
-          String.Format (
-            "Invalid pair of 'port' and 'secure': {0}, {1}", port, secure));
+          String.Format ("Invalid pair of 'port' and 'secure': {0}, {1}", port, secure));

       _address = address;
       _port = port;
@@ -290,8 +280,7 @@
     /// Gets the local IP address of the server.
     /// </summary>
     /// <value>
-    /// A <see cref="System.Net.IPAddress"/> that represents the local IP
-    /// address of the server.
+    /// A <see cref="System.Net.IPAddress"/> that represents the local IP address of the server.
     /// </value>
     public System.Net.IPAddress Address {
       get {
@@ -303,9 +292,9 @@
     /// Gets or sets the scheme used to authenticate the clients.
     /// </summary>
     /// <value>
-    /// One of the <see cref="WebSocketSharp.Net.AuthenticationSchemes"/> enum
-    /// values, indicates the scheme used to authenticate the clients. The default
-    /// value is <see cref="WebSocketSharp.Net.AuthenticationSchemes.Anonymous"/>.
+    /// One of the <see cref="WebSocketSharp.Net.AuthenticationSchemes"/> enum values, indicates
+    /// the scheme used to authenticate the clients.
+    /// The default value is <see cref="WebSocketSharp.Net.AuthenticationSchemes.Anonymous"/>.
     /// </value>
     public AuthenticationSchemes AuthenticationSchemes {
       get {
@@ -321,8 +310,7 @@
     }

     /// <summary>
-    /// Gets or sets the certificate used to authenticate the server on the
-    /// secure connection.
+    /// Gets or sets the certificate used to authenticate the server on the secure connection.
     /// </summary>
     /// <value>
     /// A <see cref="X509Certificate2"/> used to authenticate the server.
@@ -366,12 +354,12 @@
     }

     /// <summary>
-    /// Gets or sets a value indicating whether the server cleans up the inactive
-    /// sessions periodically.
-    /// </summary>
-    /// <value>
-    /// <c>true</c> if the server cleans up the inactive sessions every 60
-    /// seconds; otherwise, <c>false</c>. The default value is <c>true</c>.
+    /// Gets or sets a value indicating whether the server cleans up the inactive sessions
+    /// periodically.
+    /// </summary>
+    /// <value>
+    /// <c>true</c> if the server cleans up the inactive sessions every 60 seconds; otherwise,
+    /// <c>false</c>. The default value is <c>true</c>.
     /// </value>
     public bool KeepClean {
       get {
@@ -387,9 +375,9 @@
     /// Gets the logging functions.
     /// </summary>
     /// <remarks>
-    /// The default logging level is <see cref="LogLevel.ERROR"/>. If you would
-    /// like to change it, you should set the <c>Log.Level</c> property to any of
-    /// the <see cref="LogLevel"/> enum values.
+    /// The default logging level is <see cref="LogLevel.ERROR"/>. If you would like to change it,
+    /// you should set the <c>Log.Level</c> property to any of the <see cref="LogLevel"/> enum
+    /// values.
     /// </remarks>
     /// <value>
     /// A <see cref="Logger"/> that provides the logging functions.
@@ -413,12 +401,11 @@
     }

     /// <summary>
-    /// Gets or sets the name of the realm associated with the
-    /// <see cref="WebSocketServer"/>.
-    /// </summary>
-    /// <value>
-    /// A <see cref="string"/> that represents the name of the realm.
-    /// The default value is <c>SECRET AREA</c>.
+    /// Gets or sets the name of the realm associated with the server.
+    /// </summary>
+    /// <value>
+    /// A <see cref="string"/> that represents the name of the realm. The default value is
+    /// <c>SECRET AREA</c>.
     /// </value>
     public string Realm {
       get {
@@ -434,13 +421,13 @@
     }

     /// <summary>
-    /// Gets or sets the delegate called to find the credentials for an identity
-    /// used to authenticate a client.
-    /// </summary>
-    /// <value>
-    /// A Func<<see cref="IIdentity"/>, <see cref="NetworkCredential"/>>
-    /// delegate that references the method(s) used to find the credentials.
-    /// The default value is a function that only returns <see langword="null"/>.
+    /// Gets or sets the delegate called to find the credentials for an identity used to
+    /// authenticate a client.
+    /// </summary>
+    /// <value>
+    /// A Func<<see cref="IIdentity"/>, <see cref="NetworkCredential"/>> delegate that
+    /// references the method(s) used to find the credentials. The default value is a function
+    /// that only returns <see langword="null"/>.
     /// </value>
     public Func<IIdentity, NetworkCredential> UserCredentialsFinder {
       get {
@@ -456,7 +443,7 @@
     }

     /// <summary>
-    /// Gets the access to the WebSocket services provided by the <see cref="WebSocketServer"/>.
+    /// Gets the access to the WebSocket services provided by the server.
     /// </summary>
     /// <value>
     /// A <see cref="WebSocketServiceManager"/> that manages the WebSocket services.
@@ -512,8 +499,7 @@
       var path = context.Path;

       WebSocketServiceHost host;
-      if (path == null ||
-          !_services.TryGetServiceHostInternally (path, out host)) {
+      if (path == null || !_services.TryGetServiceHostInternally (path, out host)) {
         context.Close (HttpStatusCode.NotImplemented);
         return;
       }
@@ -551,8 +537,7 @@
         }

         var header = context.Headers ["Authorization"];
-        if (header == null ||
-            !header.StartsWith (expected, StringComparison.OrdinalIgnoreCase)) {
+        if (header == null || !header.StartsWith (expected, StringComparison.OrdinalIgnoreCase)) {
           context.SendAuthChallenge (challenge);
           return auth ();
         }
@@ -573,7 +558,7 @@
       if (_state == ServerState.START || _state == ServerState.SHUTDOWN) {
         _logger.Error (
           String.Format (
-            "The '{0}' property cannot set a value because the server has already been started.",
+            "Set operation of {0} isn't available because the server has already started.",
             property));

         return false;
@@ -606,9 +591,7 @@
           acceptRequestAsync (_listener.AcceptTcpClient ());
         }
         catch (SocketException ex) {
-          _logger.Warn (
-            String.Format (
-              "Receiving has been stopped.\nreason: {0}.", ex.Message));
+          _logger.Warn (String.Format ("Receiving has been stopped.\nreason: {0}.", ex.Message));

           break;
         }
@@ -655,74 +638,65 @@
     #region Public Methods

     /// <summary>
-    /// Adds the specified typed WebSocket service with the specified
-    /// <paramref name="servicePath"/>.
-    /// </summary>
-    /// <remarks>
-    /// This method converts <paramref name="servicePath"/> to URL-decoded string
-    /// and removes <c>'/'</c> from tail end of <paramref name="servicePath"/>.
-    /// </remarks>
-    /// <param name="servicePath">
-    /// A <see cref="string"/> that represents the absolute path to the WebSocket
-    /// service.
+    /// Adds the specified typed WebSocket service with the specified <paramref name="path"/>.
+    /// </summary>
+    /// <remarks>
+    /// This method converts <paramref name="path"/> to URL-decoded string and removes <c>'/'</c>
+    /// from tail end of <paramref name="path"/>.
+    /// </remarks>
+    /// <param name="path">
+    /// A <see cref="string"/> that represents the absolute path to the WebSocket service to add.
     /// </param>
     /// <typeparam name="TWithNew">
-    /// The type of the WebSocket service. The TWithNew must inherit the
-    /// <see cref="WebSocketService"/> class and must have a public parameterless
-    /// constructor.
+    /// The type of the WebSocket service.
+    /// The TWithNew must inherit the <see cref="WebSocketService"/> class and must have a public
+    /// parameterless constructor.
     /// </typeparam>
-    public void AddWebSocketService<TWithNew> (string servicePath)
+    public void AddWebSocketService<TWithNew> (string path)
       where TWithNew : WebSocketService, new ()
     {
-      AddWebSocketService<TWithNew> (servicePath, () => new TWithNew ());
-    }
-
-    /// <summary>
-    /// Adds the specified typed WebSocket service with the specified
-    /// <paramref name="servicePath"/> and <paramref name="serviceConstructor"/>.
-    /// </summary>
-    /// <remarks>
-    ///   <para>
-    ///   This method converts <paramref name="servicePath"/> to URL-decoded
-    ///   string and removes <c>'/'</c> from tail end of
-    ///   <paramref name="servicePath"/>.
-    ///   </para>
-    ///   <para>
-    ///   <paramref name="serviceConstructor"/> returns a initialized specified
-    ///   typed WebSocket service instance.
-    ///   </para>
-    /// </remarks>
-    /// <param name="servicePath">
-    /// A <see cref="string"/> that represents the absolute path to the WebSocket
-    /// service.
-    /// </param>
-    /// <param name="serviceConstructor">
-    /// A Func<T> delegate that references the method used to initialize
-    /// a new WebSocket service instance (a new WebSocket session).
+      AddWebSocketService<TWithNew> (path, () => new TWithNew ());
+    }
+
+    /// <summary>
+    /// Adds the specified typed WebSocket service with the specified <paramref name="path"/>
+    /// and <paramref name="constructor"/>.
+    /// </summary>
+    /// <remarks>
+    ///   <para>
+    ///   This method converts <paramref name="path"/> to URL-decoded string and removes <c>'/'</c>
+    ///   from tail end of <paramref name="path"/>.
+    ///   </para>
+    ///   <para>
+    ///   <paramref name="constructor"/> returns a initialized specified typed
+    ///   <see cref="WebSocketService"/> instance.
+    ///   </para>
+    /// </remarks>
+    /// <param name="path">
+    /// A <see cref="string"/> that represents the absolute path to the WebSocket service to add.
+    /// </param>
+    /// <param name="constructor">
+    /// A Func<T> delegate that references the method used to initialize a new specified
+    /// typed <see cref="WebSocketService"/> instance (a new <see cref="IWebSocketSession"/>
+    /// instance).
     /// </param>
     /// <typeparam name="T">
-    /// The type of the WebSocket service. The T must inherit the
-    /// <see cref="WebSocketService"/> class.
+    /// The type of the WebSocket service. The T must inherit the <see cref="WebSocketService"/>
+    /// class.
     /// </typeparam>
-    public void AddWebSocketService<T> (
-      string servicePath, Func<T> serviceConstructor)
+    public void AddWebSocketService<T> (string path, Func<T> constructor)
       where T : WebSocketService
     {
-      var msg = servicePath.CheckIfValidServicePath () ??
-                (serviceConstructor == null
-                 ? "'serviceConstructor' must not be null."
-                 : null);
+      var msg = path.CheckIfValidServicePath () ??
+                (constructor == null ? "'constructor' must not be null." : null);

       if (msg != null) {
-        _logger.Error (
-          String.Format ("{0}\nservice path: {1}", msg, servicePath ?? ""));
+        _logger.Error (String.Format ("{0}\nservice path: {1}", msg, path));

         return;
       }

-      var host = new WebSocketServiceHost<T> (
-        servicePath, serviceConstructor, _logger);
-
+      var host = new WebSocketServiceHost<T> (path, constructor, _logger);
       if (!KeepClean)
         host.KeepClean = false;

@@ -730,32 +704,29 @@
     }

     /// <summary>
-    /// Removes the WebSocket service with the specified
-    /// <paramref name="servicePath"/>.
-    /// </summary>
-    /// <remarks>
-    /// This method converts <paramref name="servicePath"/> to URL-decoded string
-    /// and removes <c>'/'</c> from tail end of <paramref name="servicePath"/>.
+    /// Removes the WebSocket service with the specified <paramref name="path"/>.
+    /// </summary>
+    /// <remarks>
+    /// This method converts <paramref name="path"/> to URL-decoded string and removes <c>'/'</c>
+    /// from tail end of <paramref name="path"/>.
     /// </remarks>
     /// <returns>
-    /// <c>true</c> if the WebSocket service is successfully found and removed;
-    /// otherwise, <c>false</c>.
+    /// <c>true</c> if the WebSocket service is successfully found and removed; otherwise,
+    /// <c>false</c>.
     /// </returns>
-    /// <param name="servicePath">
-    /// A <see cref="string"/> that represents the absolute path to the WebSocket
-    /// service to find.
-    /// </param>
-    public bool RemoveWebSocketService (string servicePath)
-    {
-      var msg = servicePath.CheckIfValidServicePath ();
+    /// <param name="path">
+    /// A <see cref="string"/> that represents the absolute path to the WebSocket service to find.
+    /// </param>
+    public bool RemoveWebSocketService (string path)
+    {
+      var msg = path.CheckIfValidServicePath ();
       if (msg != null) {
-        _logger.Error (
-          String.Format ("{0}\nservice path: {1}", msg, servicePath));
+        _logger.Error (String.Format ("{0}\nservice path: {1}", msg, path));

         return false;
       }

-      return _services.Remove (servicePath);
+      return _services.Remove (path);
     }

     /// <summary>
@@ -766,9 +737,7 @@
       lock (_sync) {
         var msg = _state.CheckIfStartable () ?? checkIfCertExists ();
         if (msg != null) {
-          _logger.Error (
-            String.Format (
-              "{0}\nstate: {1}\nsecure: {2}", msg, _state, _secure));
+          _logger.Error (String.Format ("{0}\nstate: {1}\nsecure: {2}", msg, _state, _secure));

           return;
         }
@@ -803,12 +772,11 @@
     }

     /// <summary>
-    /// Stops receiving the WebSocket connection requests with the specified
-    /// <see cref="ushort"/> and <see cref="string"/>.
+    /// Stops receiving the WebSocket connection requests with the specified <see cref="ushort"/>
+    /// and <see cref="string"/>.
     /// </summary>
     /// <param name="code">
-    /// A <see cref="ushort"/> that represents the status code indicating the
-    /// reason for stop.
+    /// A <see cref="ushort"/> that represents the status code indicating the reason for stop.
     /// </param>
     /// <param name="reason">
     /// A <see cref="string"/> that represents the reason for stop.
@@ -823,8 +791,7 @@

         if (msg != null) {
           _logger.Error (
-            String.Format (
-              "{0}\nstate: {1}\ncode: {2}\nreason: {3}", msg, _state, code, reason));
+            String.Format ("{0}\nstate: {1}\ncode: {2}\nreason: {3}", msg, _state, code, reason));

           return;
         }
@@ -843,8 +810,8 @@
     /// <see cref="CloseStatusCode"/> and <see cref="string"/>.
     /// </summary>
     /// <param name="code">
-    /// One of the <see cref="CloseStatusCode"/> enum values, represents the
-    /// status code indicating the reason for stop.
+    /// One of the <see cref="CloseStatusCode"/> enum values, represents the status code indicating
+    /// the reason for stop.
     /// </param>
     /// <param name="reason">
     /// A <see cref="string"/> that represents the reason for stop.
@@ -857,8 +824,7 @@
                   (data = ((ushort) code).Append (reason)).CheckIfValidControlData ("reason");

         if (msg != null) {
-          _logger.Error (
-            String.Format ("{0}\nstate: {1}\nreason: {2}", msg, _state, reason));
+          _logger.Error (String.Format ("{0}\nstate: {1}\nreason: {2}", msg, _state, reason));

           return;
         }


Fixed issue with the Issues dialog attempting to jump to an invalid layout/card index.

--- CardMaker/Forms/MDIIssues.cs
+++ CardMaker/Forms/MDIIssues.cs
@@ -93,15 +93,19 @@
         {
             if (1 == listViewIssues.SelectedItems.Count)
             {
-                ListViewItem zItem = listViewIssues.SelectedItems[0];
-                int nLayout = int.Parse(zItem.SubItems[0].Text);
-                int nCard = int.Parse(zItem.SubItems[1].Text);
-                // Select the Layout
-                LayoutManager.Instance.FireLayoutSelectRequested(ProjectManager.Instance.LoadedProject.Layout[nLayout]);
-                // Select the Element
-                ElementManager.Instance.FireElementSelectRequestedEvent(LayoutManager.Instance.GetElement(zItem.SubItems[2].Text));
-                // Select the Card Index
-                LayoutManager.Instance.FireDeckIndexChangeRequested(nCard - 1);
+                var zItem = listViewIssues.SelectedItems[0];
+                var nLayout = (int) zItem.Tag;
+                int nCard;
+
+                if (int.TryParse(zItem.SubItems[1].Text, out nCard))
+                {
+                    // Select the Layout
+                    LayoutManager.Instance.FireLayoutSelectRequested(ProjectManager.Instance.LoadedProject.Layout[nLayout]);
+                    // Select the Element
+                    ElementManager.Instance.FireElementSelectRequestedEvent(LayoutManager.Instance.GetElement(zItem.SubItems[2].Text));
+                    // Select the Card Index
+                    LayoutManager.Instance.FireDeckIndexChangeRequested(nCard - 1);
+                }
             }
         }

@@ -136,12 +140,14 @@

             if (listViewIssues.InvokeActionIfRequired(() => AddIssue(sIssue)))
             {
+                // NOTE: The tag stores the index of the layout
                 var zItem = new ListViewItem(new string[] {
                     ProjectManager.Instance.LoadedProject.Layout[m_nCurrentLayoutIndex].Name,
                     m_sCurrentCardIndex,
                     m_sCurrentElementName,
                     sIssue
                 });
+                zItem.Tag = m_nCurrentLayoutIndex;
                 listViewIssues.Items.Add(zItem);
             }
         }


Update cargo monitor

Update cargo monitor

--- CargoMonitor/CargoMonitor.cs
+++ CargoMonitor/CargoMonitor.cs
@@ -1,15 +1,119 @@
-using System;
+using Eddi;
+using EddiDataDefinitions;
+using EddiEvents;
+using Newtonsoft.Json;
+using System;
 using System.Collections.Generic;
+using System.IO;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
+using System.Windows.Controls;
+using Utilities;

 namespace EddiCargoMonitor
 {
     /// <summary>
     /// A monitor that keeps track of cargo
     /// </summary>
-    public class CargoMonitor
+    public class CargoMonitor : EDDIMonitor
     {
+        // The file to log cargo
+        public static readonly string CargoFile = Constants.DATA_DIR + @"\cargo.json";
+
+        // The cargo
+        private List<Cargo> cargo = new List<Cargo>();
+
+        public string MonitorName()
+        {
+            return "Cargo monitor";
+        }
+
+        public string MonitorVersion()
+        {
+            return "1.0.0";
+        }
+
+        public string MonitorDescription()
+        {
+            return "Tracks your cargo and provides information to speech responder scripts.";
+        }
+
+        public CargoMonitor()
+        {
+            ReadCargo();
+            Logging.Info("Initialised " + MonitorName() + " " + MonitorVersion());
+        }
+
+        public void Start()
+        {
+            // We don't actively do anything, just listen to events, so nothing to do here
+        }
+
+        public void Stop()
+        {
+        }
+
+        public void Reload()
+        {
+            ReadCargo();
+        }
+
+        public UserControl ConfigurationTabItem()
+        {
+            return null;
+        }
+
+        public void Handle(Event @event)
+        {
+            Logging.Debug("Received event " + JsonConvert.SerializeObject(@event));
+            // Handle the events that we care about
+
+            if (@event is CargoInventoryEvent)
+            {
+                handleCargoInventoryEvent((CargoInventoryEvent)@event);
+            }
+        }
+
+        private void handleCargoInventoryEvent(CargoInventoryEvent @event)
+        {
+
+        }
+
+        public IDictionary<string, object> GetVariables()
+        {
+            IDictionary<string, object> variables = new Dictionary<string, object>();
+            //variables["cargo"] = configuration.materials;
+
+            return variables;
+        }
+
+        private void ReadCargo()
+        {
+            try
+            {
+                cargo = JsonConvert.DeserializeObject<List<Cargo>>(File.ReadAllText(CargoFile));
+            }
+            catch (Exception ex)
+            {
+                Logging.Warn("Failed to read cargo", ex);
+            }
+            if (cargo == null)
+            {
+                cargo = new List<Cargo>();
+            }
+        }
+
+        private void WriteCargo()
+        {
+            try
+            {
+                File.WriteAllText(CargoFile, JsonConvert.SerializeObject(this, Formatting.Indented));
+            }
+            catch (Exception ex)
+            {
+                Logging.Warn("Failed to write cargo", ex);
+            }
+        }
     }
-}
+}


Implement OnTakeFocus - code imported from CefSharp1 branch

--- CefSharp.WinForms/WebView.cs
+++ CefSharp.WinForms/WebView.cs
@@ -168,7 +168,7 @@

         public void OnTakeFocus(bool next)
         {
-            throw new NotImplementedException();
+            SelectNextControl(this, next, true, true, true);
         }

         public void OnConsoleMessage(string message, string source, int line)


Updated first middleware to not short-circuit

--- Chaining/Chaining/Startup.cs
+++ Chaining/Chaining/Startup.cs
@@ -6,8 +6,14 @@
     {
         public void Configuration(IAppBuilder app)
         {
-            app.Run(context => context.Response.WriteAsync("I'm middleware #1"));
-            app.Run(context => context.Response.WriteAsync("I'm middleware #2"));
+            app.Use((context, next) =>
+            {
+                context.Response.WriteAsync("I'm middleware #1");
+
+                return next.Invoke();
+            });
+
+            app.Run(context => context.Response.WriteAsync(" - I'm middleware #2"));
         }
     }
 }


Burst player will not read .json files (as it is unclear whether they come from beta or regular version)

--- Controller/LogBurstPlayer.cs
+++ Controller/LogBurstPlayer.cs
@@ -47,10 +47,11 @@
                     yield return @event;

                 // Read Market.json, Outfitting.json etc.
-                files = LogEnumerator.GetJsonEventFiles(LogDirectory).ToList();
-                events = files.Select(f => reader.ReadFileEvent(f)).Where(e => e != null);
-                foreach (var @event in events)
-                    yield return @event;
+                // Disabled - it is unclear for now how to deal with beta data
+                //files = LogEnumerator.GetJsonEventFiles(LogDirectory).ToList();
+                //events = files.Select(f => reader.ReadFileEvent(f)).Where(e => e != null);
+                //foreach (var @event in events)
+                //    yield return @event;
             }
         }


Tidy up HTML->text conversion when <br> is followed by a newline

--- CrosspostSharp/WeasylForm.cs
+++ CrosspostSharp/WeasylForm.cs
@@ -384,8 +384,8 @@
                     : GlobalSettings.Defaults.HeaderHTML?.Replace("{TITLE}", submission.Title) ?? "";
                 txtInkbunnyTitle.Text = txtFlickrTitle.Text = submission.Title;
 				txtDescription.Text = submission.HTMLDescription;
-                txtFlickrDesc.Text = Regex.Replace(submission.HTMLDescription ?? "", @"<br ?\/?>", Environment.NewLine);
-                string bbCode = HtmlToBBCode.ConvertHtml(txtDescription.Text);
+                txtFlickrDesc.Text = Regex.Replace(submission.HTMLDescription ?? "", @"<br ?\/?>\r?\n?", Environment.NewLine);
+                string bbCode = HtmlToBBCode.ConvertHtml(txtFlickrDesc.Text);
 				txtInkbunnyDescription.Text = bbCode;
 				txtURL.Text = submission.ViewURL ?? "";


Fixing the loading of the field_values for fields inside a FieldGroup.

--- eFormCore/Infrastructure/SqlController.cs
+++ eFormCore/Infrastructure/SqlController.cs
@@ -1430,7 +1430,7 @@
                                     _field.FieldValues = new List<FieldValue>();
                                     foreach (field_values fieldValue in subField.FieldValues.Where(x => x.CaseId == caseId).ToList())
                                     {
-                                        FieldValue answer = await ReadFieldValue(fieldValue, field, false);
+                                        FieldValue answer = await ReadFieldValue(fieldValue, subField, false);
                                         _field.FieldValues.Add(answer);
                                     }
                                     dataItemSubList.Add(_field);


tested IfElse

tested IfElse

--- Dragon/UnitTests/TestStmt.cs
+++ Dragon/UnitTests/TestStmt.cs
@@ -23,5 +23,16 @@
             //      goto L99
             //L1:
         }
+
+        [TestMethod]
+        public void TestIfElse()
+        {
+            var ifElse = new IfElse(new Rel(new Token('>'), new Constant(42), new Constant(99)), new Stmt(), new Stmt());
+            ifElse.Gen(10, 100);
+            //output:
+            //      iffalse 42 > 99 goto L2
+            //L1:	goto L100
+            //L2:
+        }
     }
 }


Performance Improved performance of AppendJIT by performing a cumulative average instead of recalculating for all points.

--- Duality/Drawing/DrawBatch.cs
+++ Duality/Drawing/DrawBatch.cs
@@ -161,11 +161,13 @@
 				Array.Resize(ref this.vertices, newArrSize);
 			}
 			Array.Copy(data, 0, this.vertices, this.vertexCount, length);
+
+			if (this.material.Technique.Res.NeedsZSort)
+				this.zSortIndex = (SumZPositions(data) + this.VertexCount * zSortIndex) / (this.VertexCount + length);
+
 			this.vertexCount += length;
-
-			if (this.material.Technique.Res.NeedsZSort)
-				this.zSortIndex = CalcZSortIndex(this.vertices, this.vertexCount);
-		}
+		}
+
 		public bool CanAppend(IDrawBatch other)
 		{
 			return
@@ -217,5 +219,15 @@
 			}
 			return zSortIndex / count;
 		}
+
+		private static float SumZPositions(T[] data)
+		{
+			float sum = 0;
+			foreach (var vertex in data)
+			{
+				sum += vertex.Pos.Z;
+			}
+			return sum;
+		}
 	}
 }


Bug fixes #FIX: Texture.LoadData could crash when trying to dispose it's base pixmap if it's base pixmap had never loaded.

--- Duality/Resources/Texture.cs
+++ Duality/Resources/Texture.cs
@@ -611,7 +611,7 @@

 			GL.BindTexture(TextureTarget.Texture2D, lastTexId);

-			if (this.keepPixmapDataResident == false)
+			if (this.keepPixmapDataResident == false && basePixmap.IsLoaded)
 				basePixmap.Res.Dispose();
 		}


Search know works in Play mode! + now searching AnimatorOverrideController's in Project, too.

--- Editor/AssetUsageDetector.cs
+++ Editor/AssetUsageDetector.cs
@@ -14,7 +14,6 @@
 using UnityEditor;
 using UnityEngine.SceneManagement;
 using UnityEditor.SceneManagement;
-using UnityEditor.Animations;
 using System.Collections;
 using System.Collections.Generic;
 using System.Reflection;
@@ -26,17 +25,13 @@
 public class SceneObjectReferences
 {
 	public string scenePath;
+	public bool clickable;
 	public List<Object> references;

-	public SceneObjectReferences()
-	{
-		scenePath = null; // Project View (Assets)
-		references = new List<Object>();
-	}
-
-	public SceneObjectReferences( string scenePath )
+	public SceneObjectReferences( string scenePath, bool clickable )
 	{
 		this.scenePath = scenePath;
+		this.clickable = clickable;
 		references = new List<Object>();
 	}

@@ -46,8 +41,8 @@
 		Color c = GUI.color;
 		GUI.color = Color.cyan;

-		if( scenePath == null )
-			GUILayout.Box( "Project View (Assets)", AssetUsageDetector.boxGUIStyle, GUILayout.ExpandWidth( true ), GUILayout.Height( 40 ) );
+		if( !clickable )
+			GUILayout.Box( scenePath, AssetUsageDetector.boxGUIStyle, GUILayout.ExpandWidth( true ), GUILayout.Height( 40 ) );
 		else if( GUILayout.Button( scenePath, AssetUsageDetector.boxGUIStyle, GUILayout.ExpandWidth( true ), GUILayout.Height( 40 ) ) )
 		{
 			// If scene name is clicked, highlight it on Project view
@@ -102,7 +97,21 @@
 	private string errorMessage = "";

 	private Color32 ORANGE_COLOR = new Color32( 235, 185, 140, 255 );
-	public static GUIStyle boxGUIStyle; // GUIStyle used to draw the results of the search
+	private static GUIStyle m_boxGUIStyle; // GUIStyle used to draw the results of the search
+	public static GUIStyle boxGUIStyle
+	{
+		get
+		{
+			if( m_boxGUIStyle == null )
+			{
+				m_boxGUIStyle = new GUIStyle( EditorStyles.helpBox );
+				m_boxGUIStyle.alignment = TextAnchor.MiddleCenter;
+				m_boxGUIStyle.font = EditorStyles.label.font;
+			}
+
+			return m_boxGUIStyle;
+		}
+	}
 	private Vector2 scrollPosition = Vector2.zero;

 	// Initial scene setup (which scenes were open and/or loaded)
@@ -120,11 +129,7 @@
 		// Get existing open window or if none, make a new one
 		AssetUsageDetector window = (AssetUsageDetector) EditorWindow.GetWindow( typeof( AssetUsageDetector ) );
 		window.titleContent = new GUIContent( "Asset Usage" );
-
-		boxGUIStyle = new GUIStyle( EditorStyles.helpBox );
-		boxGUIStyle.alignment = TextAnchor.MiddleCenter;
-		boxGUIStyle.font = EditorStyles.label.font;
-
+
 		window.Show();
 	}

@@ -161,13 +166,27 @@

 			GUILayout.Box( "SCENES TO SEARCH", GUILayout.ExpandWidth( true ) );

-			if( searchInAllScenes )
+			if( EditorApplication.isPlaying )
+			{
+				searchInAllScenes = false;
+				searchInScenesInBuild = false;
+			}
+			else if( searchInAllScenes )
 				GUI.enabled = false;

 			searchInOpenScenes = EditorGUILayout.ToggleLeft( "Currently open (loaded) scene(s)", searchInOpenScenes );
+
+			if( EditorApplication.isPlaying )
+				GUI.enabled = false;
+
 			searchInScenesInBuild = EditorGUILayout.ToggleLeft( "Scenes in Build Settings (ticked)", searchInScenesInBuild );
+
+			if( !EditorApplication.isPlaying )
+				GUI.enabled = true;
+
+			searchInAllScenes = EditorGUILayout.ToggleLeft( "All scenes in project (including scenes not in build)", searchInAllScenes );
+
 			GUI.enabled = true;
-			searchInAllScenes = EditorGUILayout.ToggleLeft( "All scenes in project (including scenes not in build)", searchInAllScenes );

 			GUILayout.Space( 10 );

@@ -194,7 +213,7 @@
 				{
 					errorMessage = "SELECT AN ASSET FIRST!";
 				}
-				else if( !AreScenesSaved() )
+				else if( !EditorApplication.isPlaying && !AreScenesSaved() )
 				{
 					// Don't start the search if at least one scene is currently dirty (not saved)
 					errorMessage = "SAVE OPEN SCENES FIRST!";
@@ -206,9 +225,16 @@
 					errorMessage = "";
 					currentPhase = Phase.Processing;

-					// Get the scenes that are open right now
-					sceneInitialSetup = EditorSceneManager.GetSceneManagerSetup();
-
+					if( !EditorApplication.isPlaying )
+					{
+						// Get the scenes that are open right now
+						sceneInitialSetup = EditorSceneManager.GetSceneManagerSetup();
+					}
+					else
+					{
+						sceneInitialSetup = null;
+					}
+
 					// Start searching
 					ExecuteQuery();

@@ -228,7 +254,7 @@

 			if( GUILayout.Button( "Reset Search", GUILayout.Height( 30 ) ) )
 			{
-				if( !restoreInitialSceneSetup || EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo() )
+				if( EditorApplication.isPlaying || !restoreInitialSceneSetup || sceneInitialSetup == null || EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo() )
 				{
 					errorMessage = "";
 					currentPhase = Phase.Setup;
@@ -452,7 +478,7 @@

 		if( searchInAssetsFolder )
 		{
-			currentSceneReferences = new SceneObjectReferences();
+			currentSceneReferences = new SceneObjectReferences( "Project View( Assets )", false );

 			// Search through all prefabs and imported models
 			string[] pathsToAssets = AssetDatabase.FindAssets( "t:GameObject" );
@@ -507,10 +533,10 @@
 				if( !stopAtFirstOccurrence || currentSceneReferences.references.Count == 0 )
 				{
 					// Search through all animator controllers
-					pathsToAssets = AssetDatabase.FindAssets( "t:AnimatorController" );
+					pathsToAssets = AssetDatabase.FindAssets( "t:RuntimeAnimatorController" );
 					for( int i = 0; i < pathsToAssets.Length; i++ )
 					{
-						AnimatorController animController = AssetDatabase.LoadAssetAtPath<AnimatorController>( AssetDatabase.GUIDToAssetPath( pathsToAssets[i] ) );
+						RuntimeAnimatorController animController = AssetDatabase.LoadAssetAtPath<RuntimeAnimatorController>( AssetDatabase.GUIDToAssetPath( pathsToAssets[i] ) );
 						AnimationClip[] animClips = animController.animationClips;
 						bool foundAsset = false;
 						for( int j = 0; j < animClips.Length; j++ )
@@ -540,16 +566,76 @@
 			}
 		}

-		foreach( string scenePath in scenesToSearch )
-		{
-			if( scenePath != null )
-			{
-				// Open the scene additively (to access its objects)
-				Scene scene = EditorSceneManager.OpenScene( scenePath, OpenSceneMode.Additive );
-				currentSceneReferences = new SceneObjectReferences( scenePath );
-
-				// Search through all GameObjects in the scene
-				GameObject[] rootGameObjects = scene.GetRootGameObjects();
+		if( !stopAtFirstOccurrence || searchResult.Count == 0 )
+		{
+			foreach( string scenePath in scenesToSearch )
+			{
+				if( scenePath != null )
+				{
+					// Open the scene additively (to access its objects)
+					Scene scene;
+					if( EditorApplication.isPlaying )
+						scene = EditorSceneManager.GetSceneByPath( scenePath );
+					else
+						scene = EditorSceneManager.OpenScene( scenePath, OpenSceneMode.Additive );
+
+					currentSceneReferences = new SceneObjectReferences( scenePath, true );
+
+					// Search through all GameObjects in the scene
+					GameObject[] rootGameObjects = scene.GetRootGameObjects();
+					for( int i = 0; i < rootGameObjects.Length; i++ )
+					{
+						CheckGameObjectForAssetRecursive( rootGameObjects[i] );
+
+						if( stopAtFirstOccurrence && currentSceneReferences.references.Count > 0 )
+							break;
+					}
+
+					// If no reference is found in this scene
+					// and the scene is not part of the initial scene setup,
+					// close it
+					if( currentSceneReferences.references.Count == 0 )
+					{
+						if( !EditorApplication.isPlaying )
+						{
+							bool sceneIsOneOfInitials = false;
+							for( int i = 0; i < sceneInitialSetup.Length; i++ )
+							{
+								if( sceneInitialSetup[i].path == scenePath )
+								{
+									if( !sceneInitialSetup[i].isLoaded )
+										EditorSceneManager.CloseScene( scene, false );
+
+									sceneIsOneOfInitials = true;
+									break;
+								}
+							}
+
+							if( !sceneIsOneOfInitials )
+								EditorSceneManager.CloseScene( scene, true );
+						}
+					}
+					else
+					{
+						// Some references are found in this scene,
+						// save the results
+						searchResult.Add( currentSceneReferences );
+
+						if( stopAtFirstOccurrence )
+							break;
+					}
+				}
+			}
+		}
+
+		if( !stopAtFirstOccurrence || searchResult.Count == 0 )
+		{
+			if( EditorApplication.isPlaying )
+			{
+				currentSceneReferences = new SceneObjectReferences( "DontDestroyOnLoad", false );
+
+				// Search through all GameObjects under the DontDestroyOnLoad scene
+				GameObject[] rootGameObjects = GetDontDestroyOnLoadObjects().ToArray();
 				for( int i = 0; i < rootGameObjects.Length; i++ )
 				{
 					CheckGameObjectForAssetRecursive( rootGameObjects[i] );
@@ -558,35 +644,11 @@
 						break;
 				}

-				// If no reference is found in this scene
-				// and the scene is not part of the initial scene setup,
-				// close it
-				if( currentSceneReferences.references.Count == 0 )
-				{
-					bool sceneIsOneOfInitials = false;
-					for( int i = 0; i < sceneInitialSetup.Length; i++ )
-					{
-						if( sceneInitialSetup[i].path == scenePath )
-						{
-							if( !sceneInitialSetup[i].isLoaded )
-								EditorSceneManager.CloseScene( scene, false );
-
-							sceneIsOneOfInitials = true;
-							break;
-						}
-					}
-
-					if( !sceneIsOneOfInitials )
-						EditorSceneManager.CloseScene( scene, true );
-				}
-				else
+				if( currentSceneReferences.references.Count > 0 )
 				{
 					// Some references are found in this scene,
 					// save the results
 					searchResult.Add( currentSceneReferences );
-
-					if( stopAtFirstOccurrence )
-						break;
 				}
 			}
 		}
@@ -619,13 +681,23 @@
 			for( int i = 0; i < components.Length; i++ )
 			{
 				Component component = components[i];
-
+
 				if( component == null )
 					continue;
-
+
 				// Ignore Transform component (no object field to search for)
 				if( component is Transform )
 					continue;
+
+				if( component == assetToSearch )
+				{
+					currentSceneReferences.references.Add( component );
+
+					if( stopAtFirstOccurrence )
+						return;
+					else
+						continue;
+				}

 				if( assetType == AssetType.Script && component is MonoBehaviour )
 				{
@@ -1118,10 +1190,44 @@
 		return false;
 	}

+	// Get the GameObject's listed under the DontDestroyOnLoad scene runtime
+	private List<GameObject> GetDontDestroyOnLoadObjects()
+	{
+		List<GameObject> result = new List<GameObject>();
+
+		List<GameObject> rootGameObjectsExceptDontDestroyOnLoad = new List<GameObject>();
+		for( int i = 0; i < SceneManager.sceneCount; i++ )
+		{
+			rootGameObjectsExceptDontDestroyOnLoad.AddRange( SceneManager.GetSceneAt( i ).GetRootGameObjects() );
+		}
+
+		List<GameObject> rootGameObjects = new List<GameObject>();
+		Transform[] allTransforms = Resources.FindObjectsOfTypeAll<Transform>();
+		for( int i = 0; i < allTransforms.Length; i++ )
+		{
+			Transform root = allTransforms[i].root;
+			if( root.hideFlags == HideFlags.None && !rootGameObjects.Contains( root.gameObject ) )
+			{
+				rootGameObjects.Add( root.gameObject );
+			}
+		}
+
+		for( int i = 0; i < rootGameObjects.Count; i++ )
+		{
+			if( !rootGameObjectsExceptDontDestroyOnLoad.Contains( rootGameObjects[i] ) )
+				result.Add( rootGameObjects[i] );
+		}
+
+		//foreach( GameObject obj in result )
+		//    Debug.Log( obj );
+
+		return result;
+	}
+
 	// Close the scenes that were not part of the initial scene setup
 	private void RestoreInitialSceneSetup()
 	{
-		if( sceneInitialSetup == null )
+		if( EditorApplication.isPlaying || sceneInitialSetup == null )
 			return;

 		SceneSetup[] sceneFinalSetup = EditorSceneManager.GetSceneManagerSetup();


Déclaration des poissons et ajout dans un tableau

--- Enigmas/PhoqueEnigmaPanel.cs
+++ Enigmas/PhoqueEnigmaPanel.cs
@@ -1,5 +1,6 @@
 using System.Drawing;
 using System.Windows.Forms;
+using System;

 namespace Cpln.Enigmos.Enigmas
 {
@@ -7,14 +8,29 @@
     {
         public PhoqueEnigmaPanel()
         {
+            //Déclaration des variables et tableaux
+            PictureBox[] tblPoissons = new PictureBox[3];
+            Random RandomX = new Random();
+
             //Création du Phoque
             PictureBox pbxPhoque = new PictureBox();
             pbxPhoque.Size = new Size(20, 40);
             pbxPhoque.BackColor = Color.Blue;
             pbxPhoque.Location = new Point(400 - (pbxPhoque.Width / 2), 550 - (pbxPhoque.Height));
+            Controls.Add(pbxPhoque);

-            //Ajout des composants
-            Controls.Add(pbxPhoque);
+            //Création des poissons
+            for (int i = 0; i < tblPoissons.Length; i++)
+            {
+                PictureBox pbxPoisson = new PictureBox();
+                pbxPoisson.Size = new Size(20, 40);
+                pbxPoisson.BackColor = Color.Gray;
+                pbxPoisson.Location = new Point(RandomX.Next(0, 800) - pbxPoisson.Width, 0 - pbxPoisson.Height);
+                pbxPoisson.Name = "Poisson_" + i;
+                tblPoissons[i] = pbxPoisson;
+                Controls.Add(pbxPoisson);
+            }
+
         }
     }
 }


Always set permissions of newly created prims (mantis #214)

git-svn-id: c32cf1ecefca26b8770d7b0740bc0c5c174087e4@1728 c754d5e9-d413-0410-bcdf-9574c9dba6b7

--- libsecondlife/examples/TestClient/Commands/Prims/ImportCommand.cs
+++ libsecondlife/examples/TestClient/Commands/Prims/ImportCommand.cs
@@ -131,11 +131,13 @@

                     }

+                    // Create a list of the local IDs of the newly created prims
+                    List<uint> primIDs = new List<uint>(primsCreated.Count);
+                    primIDs.Add(rootLocalID); // Root prim is first in list.
+
                     if (linkset.Children.Count != 0)
                     {
-                        // Create a list of the local IDs of the newly created prims
-                        List<uint> primIDs = new List<uint>(primsCreated.Count);
-                        primIDs.Add(rootLocalID); // Root prim is first in list.
+                        // Add the rest of the prims to the list of local IDs
                         foreach (Primitive prim in primsCreated)
                         {
                             if (prim.LocalID != rootLocalID)
@@ -153,14 +155,17 @@
                         else
                             Console.WriteLine("Warning: Failed to link {0} prims", linkQueue.Count);

-                        Client.Objects.SetPermissions(Client.Network.CurrentSim, primIDs,
-                            PermissionWho.Everyone | PermissionWho.Group | PermissionWho.NextOwner,
-                            PermissionMask.All, true);
                     }
                     else
                     {
                         Client.Objects.SetRotation(Client.Network.CurrentSim, rootLocalID, rootRotation);
                     }
+
+                    // Set permissions on newly created prims
+                    Client.Objects.SetPermissions(Client.Network.CurrentSim, primIDs,
+                        PermissionWho.Everyone | PermissionWho.Group | PermissionWho.NextOwner,
+                        PermissionMask.All, true);
+
                     state = ImporterState.Idle;
                 }
                 else


React to Hosting changes

React to Hosting changes

--- samples/SessionSample/Startup.cs
+++ samples/SessionSample/Startup.cs
@@ -80,7 +80,7 @@
         public static void Main(string[] args)
         {
             var host = new WebHostBuilder()
-                .UseDefaultConfiguration(args)
+                .UseDefaultHostingConfiguration(args)
                 .UseServer("Microsoft.AspNetCore.Server.Kestrel")
                 .UseIISPlatformHandlerUrl()
                 .UseStartup<Startup>()


clean up and typo fixing

clean up and typo fixing

--- AudioRenderer.cs
+++ AudioRenderer.cs
@@ -102,8 +102,7 @@
         #endregion

         #region synthesizer events
-
-
+
         void _speaker_SpeakCompleted(object sender, SpeakCompletedEventArgs e)
         {
             firefinishedEvent();
@@ -345,8 +344,7 @@
             }
             catch { }
         }
-
-
+
         #endregion

         #region Play functions
@@ -603,6 +601,7 @@
             outputQueueThread.IsBackground = true;
             outputQueueThread.Start();
         }
+
         void checkOutputQueue()
         {
             while (_run)
@@ -698,7 +697,6 @@
         /// </summary>
         public event EventHandler<EventArgs> Finished;

-
         void fireTextSpokenEvent(string text)
         {
             try
@@ -803,7 +801,7 @@
         /// </summary>
         public readonly String Gender;
         /// <summary>
-        /// Give some information about the adge of the speaker if set.
+        /// Give some information about the age of the speaker if set.
         /// </summary>
         public readonly String Adge;
         public Voice(string name, String culture, String gender, String adge)


Updated AI.Shoot to return a bool. In AI.Shoot I added a buffer around the playfield to avoid having to check for edges.

--- Battleship/AI.cs
+++ Battleship/AI.cs
@@ -18,82 +18,89 @@

         /// <summary>
         /// Chooses which square the AI in the Battleships game will shoot at.
-        /// Returns the coordinates as two integers. Returns -1 if there are no viable
-        /// coordinates to fire at.
+        /// <para>The coordinates will be returned in <paramref name="rowCoord"/> and <paramref name="colCoord"/></para>
+        /// Returns true if valid coordinates could be found, otherwise returns false
         /// </summary>
         /// <param name="playFieldArray">The array containing the playing field.</param>
-        /// <param name="firstCoord">The first dimension coordinate that the AI fires at.</param>
-        /// <param name="secondCoord">The second dimension coordinate that the AI fires at.</param>
-        public static void Shoot(Square[,] playFieldArray, out int firstCoord, out int secondCoord)
+        /// <param name="rowCoord">The row that the AI fires at.</param>
+        /// <param name="colCoord">The column that the AI fires at.</param>
+        /// <returns>True if valid coordinates could be found otherwise false.</returns>
+        public static bool Shoot(Square[,] playFieldArray, out int rowCoord, out int colCoord)
         {
-            int minFirst = 0, maxFirst = playFieldArray.GetLength(0), minSecond = 0, maxSecond = playFieldArray.GetLength(1);
+            const int arrayBuffer = 1, neighbour = 1;
+            int rowMin = 1, rowMax = playFieldArray.GetLength(0) + 1, colMin = 1, colMax = playFieldArray.GetLength(1) + 1;
             Random randomizeCoord = new Random();
             int chosenRandom;
             bool foundHit = false;
             List<Tuple<int, int>> allowedCoordinates = new List<Tuple<int, int>>(); // Array or list to hold possible

+            // Add a buffer around the playFieldArray to avoid having to check for edges
+            // Do this by making a new array with an extra row and column on each side.
+            Square[,] bufferedSquareArray = new Square[rowMax + 2 * arrayBuffer, colMax + 2 * arrayBuffer];
+            for (int row = 0; row < rowMax - arrayBuffer; row++)
+            {
+                for (int col = 0; col < colMax - arrayBuffer; col++)
+                {
+                    bufferedSquareArray[row + arrayBuffer, col + arrayBuffer] = playFieldArray[row, col];
+                }
+            }
+
             // Loop through entire array with nested loop
-            for (int x = 0; x < maxFirst && !foundHit; x++)
+            for (int row = rowMin; row < rowMax && !foundHit; row++)
             {
-                for (int y = 0; y < maxSecond && !foundHit; y++)
+                for (int col = colMin; col < colMax && !foundHit; col++)
                 {
-                    if (playFieldArray[x, y] == Square.Hit)
+                    if (bufferedSquareArray[row, col] == Square.Hit)
                     {
                         // Found a hit but not sunk ship, clear allowedCoordinates to fire only around that hit
                         foundHit = true;
                         allowedCoordinates.Clear();

                         // Check for other hits along 1st dimension
-                        if (x < (maxFirst - 1) &&
-                            playFieldArray[x + 1, y] == Square.Hit)
+                        if (bufferedSquareArray[row + neighbour, col] == Square.Hit)
                         {
                             // Add square to the left unless we are at the edge or there is a miss
-                            if (x != minFirst &&
-                                playFieldArray[x - 1, y] != Square.Miss)
+                            if (bufferedSquareArray[row - neighbour, col] != Square.Miss)
                             {
-                                allowedCoordinates.Add(Tuple.Create(x - 1, y));
+                                allowedCoordinates.Add(Tuple.Create(row - neighbour, col));
                             }

                             // Find end of hits on the boat along the first dimension
-                            while (x < (maxFirst - 1) &&
-                                playFieldArray[x, y] == Square.Hit)
+                            while (bufferedSquareArray[row, col] == Square.Hit)
                             {
-                                x++;
+                                row++;
                             }

                             // Add the square right of the last hit unless we are at the edge or there is a miss
-                            if (playFieldArray[x, y] == Square.Water ||
-                                playFieldArray[x, y] == Square.Ship)
+                            if (bufferedSquareArray[row, col] == Square.Water ||
+                                bufferedSquareArray[row, col] == Square.Ship)
                             {
-                                allowedCoordinates.Add(Tuple.Create(x - 1, y));
+                                allowedCoordinates.Add(Tuple.Create(row, col));
                             }

                             foundHit = true;
                         }

                         // Check for other hits along 2nd dimension
-                        else if (y < (maxSecond - 1) &&
-                            playFieldArray[x, y + 1] == Square.Hit)
+                        else if (bufferedSquareArray[row, col + neighbour] == Square.Hit)
                         {
                             // Add square above the hit unless we are at the edge or there is a miss
-                            if (y != minSecond &&
-                                playFieldArray[x, y - 1] != Square.Miss)
+                            if (bufferedSquareArray[row, col - neighbour] != Square.Miss)
                             {
-                                allowedCoordinates.Add(Tuple.Create(x, y - 1));
+                                allowedCoordinates.Add(Tuple.Create(row, col - neighbour));
                             }

                             // Find end of hits on the boat along the seond dimension
-                            while (y < (maxSecond - 1) &&
-                                playFieldArray[x, y] == Square.Hit)
+                            while (bufferedSquareArray[row, col] == Square.Hit)
                             {
-                                y++;
+                                col++;
                             }

                             // Add the square below the last hit unless we are at the edge or there is a miss
-                            if (playFieldArray[x, y] == Square.Water ||
-                                playFieldArray[x, y] == Square.Ship)
+                            if (bufferedSquareArray[row, col] == Square.Water ||
+                                bufferedSquareArray[row, col] == Square.Ship)
                             {
-                                allowedCoordinates.Add(Tuple.Create(x, y));
+                                allowedCoordinates.Add(Tuple.Create(row, col));
                             }

                             foundHit = true;
@@ -102,87 +109,45 @@
                         else
                         {
                             // No other hits were found.
-                            // Make sure we are not at the edge in each direction and
-                            // that we haven't tried to fire there but missed
-                            if (x != minFirst &&
-                                playFieldArray[x - 1, y] != Square.Miss)
+                            // Make sure that we haven't tried to fire in each direction but missed
+                            if (bufferedSquareArray[row - neighbour, col] != Square.Miss)
                             {
-                                allowedCoordinates.Add(Tuple.Create(x - 1, y));
+                                allowedCoordinates.Add(Tuple.Create(row - neighbour, col));
                             }

-                            if (y != minSecond &&
-                                playFieldArray[x, y - 1] != Square.Miss)
+                            if (bufferedSquareArray[row, col - neighbour] != Square.Miss)
                             {
-                                allowedCoordinates.Add(Tuple.Create(x, y - 1));
+                                allowedCoordinates.Add(Tuple.Create(row, col - neighbour));
                             }

-                            if (x < (maxFirst - 1) &&
-                                playFieldArray[x + 1, y] != Square.Miss)
+                            if (bufferedSquareArray[row + neighbour, col] != Square.Miss)
                             {
-                                allowedCoordinates.Add(Tuple.Create(x + 1, y));
+                                allowedCoordinates.Add(Tuple.Create(row + neighbour, col));
                             }

-                            if (y < (maxSecond - 1) &&
-                                playFieldArray[x, y + 1] != Square.Miss)
+                            if (bufferedSquareArray[row, col + neighbour] != Square.Miss)
                             {
-                                allowedCoordinates.Add(Tuple.Create(x, y + 1));
+                                allowedCoordinates.Add(Tuple.Create(row, col + neighbour));
                             }
                         }
                     }
-                    else if (!foundHit && (playFieldArray[x, y] == Square.Water || playFieldArray[x, y] == Square.Ship))
+                    else if (!foundHit && (bufferedSquareArray[row, col] == Square.Water || bufferedSquareArray[row, col] == Square.Ship))
                     {
                         // We haven't already found a hit and the current square is water or ship.
-                        // Check the squares around the current square for sunk ships since
+                        // Check the eight squares around the current square for sunk ships since
                         // ships can't be next to each other.
-                        if (x != minFirst &&
-                            y != minSecond &&
-                            playFieldArray[x - 1, y - 1] == Square.Sunk)
-                        {
-                            // There is a sunk ship above and left of the current square
-                        }
-                        else if (y != minSecond &&
-                            playFieldArray[x, y - 1] == Square.Sunk)
-                        {
-                            // There is a sunk ship above the current square
-                        }
-                        else if (x < (maxFirst - 1) &&
-                            y != minSecond &&
-                            playFieldArray[x + 1, y - 1] == Square.Sunk)
-                        {
-                            // There is a sunk ship above and right of the current square
-                        }
-                        else if (x != minFirst &&
-                            playFieldArray[x - 1, y] == Square.Sunk)
-                        {
-                            // There is a sunk ship left of the current square
-                        }
-                        else if (x < (maxFirst - 1) &&
-                            playFieldArray[x + 1, y] == Square.Sunk)
-                        {
-                            // There is a sunk ship right of the current square
-                        }
-                        else if (x != minFirst &&
-                            y < (maxSecond - 1) &&
-                            playFieldArray[x - 1, y + 1] == Square.Sunk)
-                        {
-                            // There is a sunk ship below and left of the current square
-                        }
-                        else if (y < (maxSecond - 1) &&
-                            playFieldArray[x, y + 1] == Square.Sunk)
-                        {
-                            // There is a sunk ship below the current square
-                        }
-                        else if (x < (maxFirst - 1) &&
-                            y < (maxSecond - 1) &&
-                            playFieldArray[x + 1, y + 1] == Square.Sunk)
-                        {
-                            // There is a sunk ship below and right of the current square
-                        }
-                        else
+                        if (bufferedSquareArray[row - neighbour, col - neighbour] != Square.Sunk &&
+                            bufferedSquareArray[row, col - neighbour] != Square.Sunk &&
+                            bufferedSquareArray[row + neighbour, col - neighbour] != Square.Sunk &&
+                            bufferedSquareArray[row - neighbour, col] != Square.Sunk &&
+                            bufferedSquareArray[row + neighbour, col] != Square.Sunk &&
+                            bufferedSquareArray[row - neighbour, col + neighbour] != Square.Sunk &&
+                            bufferedSquareArray[row, col + neighbour] != Square.Sunk &&
+                            bufferedSquareArray[row + neighbour, col + neighbour] != Square.Sunk)
                         {
                             // If it is a square with water or ship with no sunk ship next to it
                             // then add it to the allowed coordinates
-                            allowedCoordinates.Add(Tuple.Create(x, y));
+                            allowedCoordinates.Add(Tuple.Create(row, col));
                         }
                     }
                 }
@@ -191,16 +156,20 @@
             if (allowedCoordinates.Count != 0)
             {
                 // Randomly choose one of the allowed coordinates
-                // and return the chosen coordinates
+                // Remove the buffer from the coordinates so they point correctly on the
+                // non-buffered array
+                // Then return the chosen coordinates
                 chosenRandom = randomizeCoord.Next(allowedCoordinates.Count);
-                firstCoord = allowedCoordinates[chosenRandom].Item1;
-                secondCoord = allowedCoordinates[chosenRandom].Item2;
+                rowCoord = allowedCoordinates[chosenRandom].Item1 - arrayBuffer;
+                colCoord = allowedCoordinates[chosenRandom].Item2 - arrayBuffer;
+                return true;
             }
             else
             {
                 // There are no coordinates that we can fire at
-                firstCoord = -1;
-                secondCoord = -1;
+                rowCoord = -1;
+                colCoord = -1;
+                return false;
             }
         }
     }