here's a test

here's a test

--- Octokit.Tests.Integration/Clients/AuthorizationClientTests.cs
+++ Octokit.Tests.Integration/Clients/AuthorizationClientTests.cs
@@ -1,23 +1,96 @@
-using System.Threading.Tasks;
+using System;
+using System.Threading.Tasks;
 using Xunit;

 namespace Octokit.Tests.Integration.Clients
 {
     public class AuthorizationClientTests
     {
-        public class TheCreateMethod
+        [ApplicationTest]
+        public async Task CanCreateAndGetAuthorizationWithoutFingerPrint()
         {
-            [ApplicationTest]
-            public async Task CanCreateAnAuthorization()
-            {
-                var client = Helper.GetAuthenticatedClient();
-                var newAuthorization = new NewAuthorization();
-                // TODO: probably some more setup work here
-                var authorization = await client.Authorization.Create(newAuthorization);
+            var client = Helper.GetAuthenticatedClient();
+            var note = Helper.MakeNameWithTimestamp("Testing authentication");
+            var newAuthorization = new NewAuthorization(
+                note,
+                new[] { "user" });

-                Assert.NotNull(authorization);
-            }
+            // the first call will create the authorization
+            var created = await client.Authorization.GetOrCreateApplicationAuthentication(
+                Helper.ClientId,
+                Helper.ClientSecret,
+                newAuthorization);
+
+            Assert.NotNull(created);
+            Assert.False(String.IsNullOrWhiteSpace(created.Token));
+            Assert.True(String.IsNullOrWhiteSpace(created.TokenLastEight));
+            Assert.True(String.IsNullOrWhiteSpace(created.HashedToken));
+
+            // we can then query it through the regular API
+            var get = await client.Authorization.Get(created.Id);
+
+            Assert.Equal(created.Id, get.Id);
+            Assert.Equal(created.Note, get.Note);
+
+            // but the second time we call this API we get
+            // a different set of data
+            var getExisting = await client.Authorization.GetOrCreateApplicationAuthentication(
+                Helper.ClientId,
+                Helper.ClientSecret,
+                newAuthorization);
+
+            Assert.Equal(created.Id, getExisting.Id);
+
+            // NOTE: the old API will continue to return the full
+            //       token if no Fingerprint is included
+            Assert.False(String.IsNullOrWhiteSpace(getExisting.Token));
+
+            // NOTE: and these new values are not included
+            Assert.True(String.IsNullOrWhiteSpace(getExisting.TokenLastEight));
+            Assert.True(String.IsNullOrWhiteSpace(getExisting.HashedToken));
+
+            await client.Authorization.Delete(created.Id);
         }

+        [ApplicationTest]
+        public async Task CanCreateAndGetAuthorizationByFingerprint()
+        {
+            var client = Helper.GetAuthenticatedClient();
+            var fingerprint = Helper.MakeNameWithTimestamp("authorization-testing");
+            var note = Helper.MakeNameWithTimestamp("Testing authentication");
+            var newAuthorization = new NewAuthorization(
+                note,
+                new[] { "user" },
+                fingerprint);
+
+            var created = await client.Authorization.GetOrCreateApplicationAuthentication(
+                Helper.ClientId,
+                Helper.ClientSecret,
+                newAuthorization);
+
+            Assert.NotNull(created);
+            Assert.False(String.IsNullOrWhiteSpace(created.Token));
+
+            // we can then query it through the regular API
+            var get = await client.Authorization.Get(created.Id);
+
+            Assert.Equal(created.Id, get.Id);
+            Assert.Equal(created.Note, get.Note);
+
+
+            // but the second time we call this API we get
+            // a different set of data
+            var getExisting = await client.Authorization.GetOrCreateApplicationAuthentication(
+                Helper.ClientId,
+                Helper.ClientSecret,
+                newAuthorization);
+
+            Assert.Equal(created.Id, getExisting.Id);
+            Assert.True(String.IsNullOrWhiteSpace(getExisting.Token));
+            Assert.False(String.IsNullOrWhiteSpace(getExisting.TokenLastEight));
+            Assert.False(String.IsNullOrWhiteSpace(getExisting.HashedToken));
+
+            await client.Authorization.Delete(created.Id);
+        }
     }
 }


Fix typo

Fix typo

--- src/NinjaCatDiscordBot/BotCommands.cs
+++ src/NinjaCatDiscordBot/BotCommands.cs
@@ -287,7 +287,7 @@

             // If the actual build returned is a normal build, skip ahead is probably closed and merged.
             if (data.Item3 != BuildType.SkipAheadPc)
-                await ReplyAsync($"Skip Ahead is appears to be closed. The latest Windows 10 build for PCs is **{data.Item1}**. :cat: :computer:\n{data.Item2}");
+                await ReplyAsync($"Skip Ahead appears to be closed. The latest Windows 10 build for PCs is **{data.Item1}**. :cat: :computer:\n{data.Item2}");
             else
                 await ReplyAsync($"The latest Windows 10 Skip Ahead build is **{data.Item1}**. :cat: :fast_forward:\n{data.Item2}");
         }


updated version to 0.6

updated version to 0.6

--- src/Nvents/Properties/AssemblyInfo.cs
+++ src/Nvents/Properties/AssemblyInfo.cs
@@ -12,4 +12,4 @@

 [assembly: ComVisible(false)]

-[assembly: AssemblyVersion("0.5.*")]
+[assembly: AssemblyVersion("0.6.*")]


Actually remove the script when it's task inventory item is deleted, rather than just stopping it.

--- OpenSim/Region/Environment/Scenes/SceneObjectPartInventory.cs
+++ OpenSim/Region/Environment/Scenes/SceneObjectPartInventory.cs
@@ -527,7 +527,7 @@
                     int type = m_items[itemID].InvType;
                     if (type == 10) // Script
                     {
-                        m_part.ParentGroup.Scene.EventManager.TriggerStopScript(m_part.LocalId, itemID);
+                        m_part.ParentGroup.Scene.EventManager.TriggerRemoveScript(m_part.LocalId, itemID);
                     }
                     m_items.Remove(itemID);
                     m_inventorySerial++;


Avoid writing script state to the filesystem if the state has not changed. Remove the unneccessary double check that was only used to provide a meaningless warning message for a corner case.

--- OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
+++ OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
@@ -92,6 +92,7 @@
         private StateSource m_stateSource;
         private bool m_postOnRez;
         private bool m_startedFromSavedState = false;
+        private string m_CurrentState = String.Empty;

         //private ISponsor m_ScriptSponsor;
         private Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>>
@@ -870,21 +871,25 @@

             string xml = ScriptSerializer.Serialize(this);

-            try
-            {
-                FileStream fs = File.Create(Path.Combine(Path.GetDirectoryName(assembly), m_ItemID.ToString() + ".state"));
-                System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
-                Byte[] buf = enc.GetBytes(xml);
-                fs.Write(buf, 0, buf.Length);
-                fs.Close();
-            }
-            catch(Exception e)
-            {
-                m_log.Error("Unable to save xml\n"+e.ToString());
-            }
-            if (!File.Exists(Path.Combine(Path.GetDirectoryName(assembly), m_ItemID.ToString() + ".state")))
-            {
-                throw new Exception("Completed persistence save, but no file was created");
+            if (m_CurrentState != xml)
+            {
+                try
+                {
+                    FileStream fs = File.Create(Path.Combine(Path.GetDirectoryName(assembly), m_ItemID.ToString() + ".state"));
+                    System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
+                    Byte[] buf = enc.GetBytes(xml);
+                    fs.Write(buf, 0, buf.Length);
+                    fs.Close();
+                }
+                catch(Exception e)
+                {
+                    m_log.Error("Unable to save xml\n"+e.ToString());
+                }
+                //if (!File.Exists(Path.Combine(Path.GetDirectoryName(assembly), m_ItemID.ToString() + ".state")))
+                //{
+                //    throw new Exception("Completed persistence save, but no file was created");
+                //}
+                m_CurrentState = xml;
             }
         }


validation: depreciate `ValidationOr`

validation: depreciate `ValidationOr`

--- src/Odachi.Validation/ValidationOr.cs
+++ src/Odachi.Validation/ValidationOr.cs
@@ -1,4 +1,5 @@
-using System.Runtime.Serialization;
+using System;
+using System.Runtime.Serialization;

 namespace Odachi.Validation
 {
@@ -6,6 +7,7 @@
 	/// Either value or validation state.
 	/// </summary>
 	[DataContract]
+	[Obsolete("Will be removed in 2.0. Use `OneOf<?, ValidationState>` instead.")]
 	public struct ValidationOr<TValue>
 	{
 		public ValidationOr(TValue value)


Removed unused logging from PartConversionQueue

--- PART/Source/CprBroker/CPRDirect/Queues/PartConversionQueue.cs
+++ PART/Source/CprBroker/CPRDirect/Queues/PartConversionQueue.cs
@@ -11,27 +11,14 @@
     {
         public const int QueueTypeId = 101;

-        DateTime start = DateTime.Now;
-        void logger(ref TimeSpan ts)
-        {
-            ts += DateTime.Now - start;
-            start = DateTime.Now;
-        }
-
         public override ExtractQueueItem[] Process(ExtractQueueItem[] items)
         {
-            start = DateTime.Now;
-            TimeSpan load, updateDatabase, uuids, convert, err;
-            load = updateDatabase = uuids = convert = err = new TimeSpan();
-
-
             var succeeded = new List<ExtractQueueItem>();
             var cache = new CprBroker.Engine.Part.UuidCache();
             var pnrs = items.Select(i => i.PNR).ToArray();
             using (var dataContext = new ExtractDataContext())
             {
                 items.LoadExtractAndItems(dataContext);
-                logger(ref load);

                 // Cahce UUIDS
                 var allPnrs = items.Select(qi => qi.PNR).ToList();
@@ -43,31 +30,25 @@
                     .Where(pnr => !string.IsNullOrEmpty(pnr))
                     .ToList();
                 cache.FillCache(allPnrs.ToArray());
-                logger(ref uuids);

                 foreach (var person in items)
                 {
                     try
                     {
                         var uuid = cache.GetUuid(person.PNR);
-                        logger(ref uuids);
                         var response = Extract.ToIndividualResponseType(person.Extract, person.ExtractItems.AsQueryable(), Constants.DataObjectMap);
                         var oioPerson = response.ToRegistreringType1(cache.GetUuid);
-                        logger(ref convert);
                         var personIdentifier = new Schemas.PersonIdentifier() { CprNumber = person.PNR, UUID = uuid };
                         UpdateDatabase.UpdatePersonRegistration(personIdentifier, oioPerson);
-                        logger(ref updateDatabase);

                         succeeded.Add(person);
                     }
                     catch (Exception ex)
                     {
                         Admin.LogException(ex);
-                        logger(ref err);
                     }
                 }
             }
-            CprBroker.Engine.Local.Admin.LogFormattedSuccess("Part converstion load <{0}>, uuids <{1}>, convert <{2}>, update <{3}>", load, uuids, convert, updateDatabase);
             return succeeded.ToArray();
         }
     }


fixed code style

fixed code style

--- src/DotNet/Writer/MethodBodyChunks.cs
+++ src/DotNet/Writer/MethodBodyChunks.cs
@@ -99,8 +99,7 @@
 			return methodBody;
 		}

-		public bool Remove(MethodBody methodBody)
-		{
+		public bool Remove(MethodBody methodBody) {
 			if (setOffsetCalled)
 				throw new InvalidOperationException("SetOffset() has already been called");
 			var list = methodBody.IsFat ? fatMethods : tinyMethods;


Check for almost-expired auth tickets and if almost expired, use the auth token instead. (#69)

--- src/POGOLib.Official/Net/RpcClient.cs
+++ src/POGOLib.Official/Net/RpcClient.cs
@@ -393,6 +393,12 @@
             if (addDefaultRequests)
                 requestEnvelope.Requests.AddRange(GetDefaultRequests());

+            if (_session.AccessToken.AuthTicket != null && _session.AccessToken.AuthTicket.ExpireTimestampMs < ((ulong)TimeUtil.GetCurrentTimestampInMilliseconds() - (60000 * 2)))
+            {
+                // Check for almost expired AuthTicket (2 minute buffer). Null out the AuthTicket so that AccessToken is used.
+                _session.AccessToken.AuthTicket = null;
+            }
+
             if (_session.AccessToken.AuthTicket == null || _session.AccessToken.IsExpired)
             {
                 if (_session.AccessToken.IsExpired)


Refactoring if-statements handling the increase and decrease of the items quality. Removing obsolete if-statements for checking quality - it is now handled when calling the increase and decrease methods for an item.

--- src/GildedRose.Console/ItemManager.cs
+++ src/GildedRose.Console/ItemManager.cs
@@ -41,49 +41,29 @@
         {
             for (var i = 0; i < Items.Count; i++)
             {
+                // Decrease an item quality if it is not aged brie or Backstage passses.
                 if (Items[i].Name != "Aged Brie" && Items[i].Name != "Backstage passes to a TAFKAL80ETC concert")
                 {
+                    DecreaseItemQuality(Items[i]);
+                }
+                else
+                {
+                    IncreaseItemQuality(Items[i]);

-                    // Decrease quality for all items except Sulfuras.
-                    if (Items[i].Quality > 0)
+                    if (Items[i].Name == "Backstage passes to a TAFKAL80ETC concert")
                     {
-                        if (Items[i].Name != "Sulfuras, Hand of Ragnaros")
+                        if (Items[i].SellIn < 11)
                         {
-                            Items[i].Quality = Items[i].Quality - 1;
+                            IncreaseItemQuality(Items[i]);
+                        }
+
+                        if (Items[i].SellIn < 6)
+                        {
+                            IncreaseItemQuality(Items[i]);
                         }
                     }
                 }
-                else
-                {
-                    if (Items[i].Quality < 50)
-                    {
-                        Items[i].Quality = Items[i].Quality + 1;
-
-                        if (Items[i].Name == "Backstage passes to a TAFKAL80ETC concert")
-                        {
-                            if (Items[i].SellIn < 11)
-                            {
-                                if (Items[i].Quality < 50)
-                                {
-                                    Items[i].Quality = Items[i].Quality + 1;
-                                }
-                            }
-
-                            if (Items[i].SellIn < 6)
-                            {
-                                if (Items[i].Quality < 50)
-                                {
-                                    Items[i].Quality = Items[i].Quality + 1;
-                                }
-                            }
-                        }
-                    }
-                }
-
-                if (Items[i].Name != "Sulfuras, Hand of Ragnaros")
-                {
-                    Items[i].SellIn = Items[i].SellIn - 1;
-                }
+                UpdateSellInForItem(Items[i]);

                 if (Items[i].SellIn < 0)
                 {
@@ -106,13 +86,37 @@
                     }
                     else
                     {
-                        if (Items[i].Quality < 50)
-                        {
-                            Items[i].Quality = Items[i].Quality + 1;
-                        }
+                        IncreaseItemQuality(Items[i]);
                     }
                 }
             }
         }
+
+        private void DecreaseItemQuality(Item item)
+        {
+            if (item.Quality > 0)
+            {
+                if (item.Name != "Sulfuras, Hand of Ragnaros")
+                {
+                    item.Quality -= 1;
+                }
+            }
+        }
+
+        private void IncreaseItemQuality(Item item)
+        {
+            if (item.Quality < 50)
+            {
+                item.Quality += 1;
+            }
+        }
+
+        private void UpdateSellInForItem(Item item)
+        {
+            if (item.Name != "Sulfuras, Hand of Ragnaros")
+            {
+                item.SellIn -= 1;
+            }
+        }
     }
 }


Exclude changes not related to fix

Exclude changes not related to fix

--- src/Hangfire.LiteDB/LiteDbJobQueue.cs
+++ src/Hangfire.LiteDB/LiteDbJobQueue.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
 using System.Threading;
 using Hangfire.Annotations;
 using Hangfire.LiteDB.Entities;
@@ -46,26 +46,20 @@
                 throw new ArgumentException("Queue array must be non-empty.", nameof(queues));
             }

-            var fetchConditions = new[]
-            {
-                Query.EQ("FetchedAt", null),
-                Query.LT("FetchedAt", DateTime.UtcNow.AddSeconds(_storageOptions.InvisibilityTimeout.Negate().TotalSeconds))
-            };
-            var fetchConditionsIndex = 0;

             JobQueue fetchedJob = null;
             while (fetchedJob == null)
             {
                 cancellationToken.ThrowIfCancellationRequested();

-                var fetchCondition = fetchConditions[fetchConditionsIndex];

                 foreach (var queue in queues)
                 {
                     var lockQueue = string.Intern($"f13333e1-a0c8-48c8-bf8c-788e89030329_{queue}");
                     lock (lockQueue)
                     {
-                        fetchedJob = _connection.JobQueue.FindOne(Query.And(fetchCondition, Query.EQ("Queue", queue)));
+                        fetchedJob =
+                            _connection.JobQueue.FindOne(x => x.FetchedAt == null && x.Queue == queue);

                         if (fetchedJob != null)
                         {
@@ -76,16 +70,34 @@
                     }
                 }

-                if (fetchedJob == null && fetchConditionsIndex == fetchConditions.Length - 1)
+                if (fetchedJob == null)
+                    foreach (var queue in queues)
+                    {
+                        var lockQueue = string.Intern($"f13333e1-a0c8-48c8-bf8c-788e89030329_{queue}");
+                        lock (lockQueue)
+                        {
+                            fetchedJob =
+                                _connection.JobQueue.FindOne(x =>
+                                    x.FetchedAt <
+                                    DateTime.UtcNow.AddSeconds(
+                                        _storageOptions.InvisibilityTimeout.Negate().TotalSeconds) && x.Queue == queue);
+
+                            if (fetchedJob != null)
+                            {
+                                fetchedJob.FetchedAt = DateTime.UtcNow;
+                                _connection.JobQueue.Update(fetchedJob);
+                                break;
+                            }
+                        }
+                    }
+
+                if (fetchedJob == null)
                 {
                     // ...and we are out of fetch conditions as well.
                     // Wait for a while before polling again.
                     cancellationToken.WaitHandle.WaitOne(_storageOptions.QueuePollInterval);
                     cancellationToken.ThrowIfCancellationRequested();
                 }
-
-                // Move on to next fetch condition
-                fetchConditionsIndex = (fetchConditionsIndex + 1) % fetchConditions.Length;
             }

             return new LiteDbFetchedJob(_connection, fetchedJob.Id, fetchedJob.JobId, fetchedJob.Queue);


SetApiConnection bugfix

SetApiConnection bugfix

--- src/ITCO.SboAddon.Framework/SboApp.cs
+++ src/ITCO.SboAddon.Framework/SboApp.cs
@@ -20,7 +20,7 @@
             SAPbobsCOM.Company diCompany, SAPbouiCOM.Application application = null)
         {
             _diCompany = diCompany;
-            if (_application != null)
+            if (application != null)
                 _application = application;
         }


Removed old network action command types

--- src/Procon.Core.Shared/CommandType.cs
+++ src/Procon.Core.Shared/CommandType.cs
@@ -146,18 +146,5 @@
         /// </summary>
         NetworkProtocolQuerySettings,

-
-        // Game actions
-
-        /// <summary>
-        /// Raw packet to send to the server.
-        /// </summary>
-        NetworkProtocolActionRaw,
-        NetworkProtocolActionChat,
-        NetworkProtocolActionKill,
-        NetworkProtocolActionMap,
-        NetworkProtocolActionMove,
-        NetworkProtocolActionKick,
-        NetworkProtocolActionBan
     }
 }


part of last commit

part of last commit

--- PanoramicDataWin8/model/data/attribute/AttributeGroupModel.cs
+++ PanoramicDataWin8/model/data/attribute/AttributeGroupModel.cs
@@ -10,9 +10,8 @@
     {
         private List<AttributeModel> _inputModels = new List<AttributeModel>();

-        public AttributeGroupModel(string name)
+        public AttributeGroupModel()
         {
-            RawName = DisplayName = name;
         }

         public List<AttributeModel> InputModels
@@ -22,6 +21,11 @@
         }

         string _rawName, _displayName;
+
+        public void SetName(string name)
+        {
+            RawName = DisplayName = name;
+        }
         public override string RawName
         {
             get { return _rawName; }


Connect asm name fix

Connect asm name fix


Reuse channels for burst publishes.

Reuse channels for burst publishes.

--- src/RawRabbit/Operations/Publisher.cs
+++ src/RawRabbit/Operations/Publisher.cs
@@ -17,6 +17,8 @@
 	public class Publisher<TMessageContext> : OperatorBase, IPublisher where TMessageContext : IMessageContext
 	{
 		private readonly IMessageContextProvider<TMessageContext> _contextProvider;
+		private ThreadLocal<IModel> _channel;
+		private Timer _channelTimer;
 		private readonly ILogger _logger = LogManager.GetLogger<Publisher<TMessageContext>>();

 		public Publisher(IChannelFactory channelFactory, IMessageSerializer serializer, IMessageContextProvider<TMessageContext> contextProvider)
@@ -27,36 +29,60 @@

 		public Task PublishAsync<TMessage>(TMessage message, Guid globalMessageId, PublishConfiguration config)
 		{
-			return _contextProvider
-				.GetMessageContextAsync(globalMessageId)
-				.ContinueWith(ctxTask =>
+			return Task.Run(() =>
+			{
+				var context = _contextProvider.GetMessageContext(globalMessageId);
+				var channel = GetOrCreateChannel();
+				DeclareQueue(config.Queue, channel);
+				DeclareExchange(config.Exchange, channel);
+				var properties = new BasicProperties
 				{
-					var channel = ChannelFactory.GetChannel();
-					DeclareQueue(config.Queue, channel);
-					DeclareExchange(config.Exchange, channel);
-					var properties = new BasicProperties
-					{
-						MessageId = Guid.NewGuid().ToString(),
-						Headers = new Dictionary<string, object>
+					MessageId = Guid.NewGuid().ToString(),
+					Headers = new Dictionary<string, object>
 						{
-							{ _contextProvider.ContextHeaderName, ctxTask.Result },
+							{ _contextProvider.ContextHeaderName, context },
 							{PropertyHeaders.Sent, DateTime.UtcNow.ToString("u") }
 						}
-					};
+				};

-					channel.BasicPublish(
-						exchange: config.Exchange.ExchangeName,
-						routingKey: config.RoutingKey,
-						basicProperties: properties,
-						body: Serializer.Serialize(message)
-						);
-					channel.Dispose();
-				});
+				channel.BasicPublish(
+					exchange: config.Exchange.ExchangeName,
+					routingKey: config.RoutingKey,
+					basicProperties: properties,
+					body: Serializer.Serialize(message)
+					);
+			});
+		}
+
+		private IModel GetOrCreateChannel()
+		{
+			if (_channel == null)
+			{
+				_channel = new ThreadLocal<IModel>(() => ChannelFactory.CreateChannel());
+				_channelTimer = new Timer(state =>
+				{
+					foreach (var channel in _channel.Values)
+					{
+						channel?.Dispose();
+					}
+					_channel?.Dispose();
+					_channel = null;
+				}, null, TimeSpan.FromSeconds(1), new TimeSpan(-1));
+			}
+			if (_channel.Value.IsClosed)
+			{
+				_channel.Value.Dispose();
+				_channel.Value = ChannelFactory.CreateChannel();
+			}
+			_channelTimer.Change(TimeSpan.FromSeconds(1), new TimeSpan(-1));
+			return _channel.Value;
 		}

 		public override void Dispose()
 		{
 			_logger.LogDebug("Disposing Publisher");
+			_channelTimer?.Dispose();
+			_channel?.Dispose();
 			base.Dispose();
 		}
 	}


Reworded exception message

Reworded exception message

--- src/Scientist/Internals/Experiment.cs
+++ src/Scientist/Internals/Experiment.cs
@@ -40,7 +40,7 @@
         {
             if (_candidates.ContainsKey(CandidateExperimentName))
             {
-                throw new InvalidOperationException("You have already added a default try, name this one something different");
+                throw new InvalidOperationException("You have already added a default try. Give this candidate a new name with the Try(string, Func<Task<T>> overload");
             }
             _candidates.Add(CandidateExperimentName, candidate);
         }
@@ -49,7 +49,7 @@
         {
             if (_candidates.ContainsKey(CandidateExperimentName))
             {
-                throw new InvalidOperationException("You have already added a default try, name this one something different");
+                throw new InvalidOperationException("You have already added a default try. Give this candidate a new name with the Try(string, Func<Task<T>> overload");
             }
             _candidates.Add(CandidateExperimentName, () => Task.FromResult(candidate()));
         }
@@ -58,7 +58,7 @@
         {
             if (_candidates.ContainsKey(name))
             {
-                throw new InvalidOperationException($"You already have a candidate named {name}, name this one something different");
+                throw new InvalidOperationException($"You already have a candidate named {name}. Provide a different name for this test.");
             }
             _candidates.Add(name, candidate);
         }
@@ -67,7 +67,7 @@
         {
             if (_candidates.ContainsKey(name))
             {
-                throw new InvalidOperationException($"You already have a candidate named {name}, name this one something different");
+                throw new InvalidOperationException($"You already have a candidate named {name}. Provide a different name for this test.");
             }
             _candidates.Add(name, () => Task.FromResult(candidate()));
         }


Make default fallback path factory static

--- src/SpaFallback/SpaFallbackOptions.cs
+++ src/SpaFallback/SpaFallbackOptions.cs
@@ -5,7 +5,9 @@
 {
     public class SpaFallbackOptions
     {
-        public Func<HttpContext, PathString> FallbackPathFactory { get; set; } = _ => "/index.html";
+        private static readonly Func<HttpContext, PathString> DefaultFallbackPathFactory = _ => "/index.html";
+
+        public Func<HttpContext, PathString> FallbackPathFactory { get; set; } = DefaultFallbackPathFactory;

         public bool AllowFileExtensions { get; set; } = false;


Fix the problem that import is added into an ImportGroup.

--- src/VisualStudio/ProjectExtensions.cs
+++ src/VisualStudio/ProjectExtensions.cs
@@ -861,12 +861,24 @@
             {
                 ProjectImportElement pie = buildProject.Xml.AddImport(targetsPath);
                 pie.Condition = "Exists('" + targetsPath + "')";
+
                 if (location == ProjectImportLocation.Top)
                 {
                     // There's no public constructor to create a ProjectImportElement directly.
                     // So we have to cheat by adding Import at the end, then remove it and insert at the beginning
                     pie.Parent.RemoveChild(pie);
                     buildProject.Xml.InsertBeforeChild(pie, buildProject.Xml.FirstChild);
+                }
+                else
+                {
+                    // the import might get added into an ImportGroup. In this case,
+                    // we remove it from the ImportGroup and add it at the end of the
+                    // project.
+                    if (pie.Parent.GetType() == typeof(ProjectImportGroupElement))
+                    {
+                        pie.Parent.RemoveChild(pie);
+                        buildProject.Xml.AppendChild(pie);
+                    }
                 }

                 NuGet.MSBuildProjectUtility.AddEnsureImportedTarget(buildProject, targetsPath);


Changed the signaler from ManualResetEvent to AutoResetEvent and defined the shared variable active_ as volatile.

--- src/base/common/concurrent/Mailbox.cs
+++ src/base/common/concurrent/Mailbox.cs
@@ -37,10 +37,10 @@

     // True if the underlying queue is active, ie. when we are allowed to
     // read command from it.
-    bool active_;
+    volatile bool active_;

     // Signaler to pass signals from writer thread to reader thread.
-    ManualResetEvent signaler_;
+    AutoResetEvent signaler_;

     #region .ctor
     /// <summary>
@@ -48,8 +48,13 @@
     /// </summary>
     public Mailbox() {
       mutex_ = new object();
-      signaler_ = new ManualResetEvent(false);
-      message_queue_ = new YQueue<T>(0);
+      message_queue_ = new YQueue<T>(16);
+
+      // Get the pipe into passive state. That way, if the user starts by
+      // polling on the associated queue it, it will be woken up when
+      // new message is posted.
+      signaler_ = new AutoResetEvent(false);
+      active_ = false;
     }
     #endregion

@@ -61,14 +66,38 @@
       lock(mutex_) {
         message_queue_.Enqueue(message);
       }
+
+      // wake-up the reader thread.
+      if (!active_) {
+        signaler_.Set();
+      }
+    }
+
+
+    /// <summary>
+    /// Receives messages from the mailbox.
+    /// </summary>
+    /// <remarks>If no incoming message is available at the mailbox, the
+    /// <see cref="Receive()"/> call blocks and waits for message to arrive.
+    /// </remarks>
+    public T Receive() {
+      T t;
+      bool ok = Receive(out t, Timeout.Infinite);
+      return t;
     }

     /// <summary>
-    /// Receives a command from the mailbox.
+    /// Receives messages from the mailbox, using a 32-bit signed integer to
+    /// specify the maxi wait time interval.
     /// </summary>
     /// <param name="message">The message that was received.</param>
-    /// <param name="timeout_ms">A timeout </param>
-    /// <returns></returns>
+    /// <param name="timeout_ms">The number of milliseconds to wait for a
+    /// message, ot Timeoit.Infinite(-1) to wait indefinitely.</param>
+    /// <returns><c>true</c> if the a message was received from the mailbox;
+    /// otherwise, <c>false</c>.</returns>
+    /// <remarks>If no incoming message is available at the mailbox, the
+    /// <see cref="Receive"/> call blocks and waits for message to arrive.
+    /// </remarks>
     public bool Receive(out T message, int timeout_ms) {
       bool ok;
       // try to get command straight away.


Fix bug on computing Update operation.

Fix bug on computing Update operation.

--- ProgramSynthesis/ProseFunctions/Spg.Witness/Transformation.cs
+++ ProgramSynthesis/ProseFunctions/Spg.Witness/Transformation.cs
@@ -205,7 +205,7 @@
         private static Edit<SyntaxNodeOrToken> ProcessRootNodeHasMoreThanOneChild(Script script, List<Edit<SyntaxNodeOrToken>> children, TreeNode<SyntaxNodeOrToken> parent, TreeNode<SyntaxNodeOrToken> transformed)
         {
             //todo correct the children.First children.second
-            if (children.Count == 2 && children.First().EditOperation is Insert<SyntaxNodeOrToken> && children.ElementAt(1).EditOperation is Delete<SyntaxNodeOrToken>)
+            if (IsDirectUpdate(children, parent, transformed))
             {
                 var @from = ConverterHelper.ConvertCSharpToTreeNode(children.ElementAt(1).EditOperation.T1Node.Value);
                 var to = children.First().EditOperation.T1Node;
@@ -241,6 +241,18 @@
                     return operation;
                 }
             }
+        }
+
+        private static bool IsDirectUpdate(List<Edit<SyntaxNodeOrToken>> children, TreeNode<SyntaxNodeOrToken> parent, TreeNode<SyntaxNodeOrToken> transformed)
+        {
+            if (children.Count != 2) return false;
+
+            if (!(children.First().EditOperation is Insert<SyntaxNodeOrToken> &&
+                  children.ElementAt(1).EditOperation is Delete<SyntaxNodeOrToken>)) return false;
+
+            var indexInsert = transformed.Children.FindIndex(o => o.Equals(children.First().EditOperation.T1Node));
+            var indexDelete = parent.Children.FindIndex(o => o.Equals(children.ElementAt(1).EditOperation.T1Node));
+            return indexInsert == indexDelete;
         }

         private static TreeNode<SyntaxNodeOrToken> ProcessScriptOnNode(Script script, TreeNode<SyntaxNodeOrToken> parent)


Implemented all GM characterization tests

--- TradeProcessor.Tests.ConsoleApp.GM/FirstGMTest.cs
+++ TradeProcessor.Tests.ConsoleApp.GM/FirstGMTest.cs
@@ -55,5 +55,41 @@
                 "WARN: Trade currencies on line 1 malformed: \'Test\'\r\nINFO: 0 trades processed\r\n",
                 _applicationUnderTest.ConsoleOutput);
         }
+
+        [TestMethod]
+        public void TradeVolumeInvalid()
+        {
+            _testDataInputFile.WithContent("GBPUSD,xyz,abc");
+
+            _applicationUnderTest.Run();
+
+            Assert.AreEqual(
+                "WARN: Trade amount on line 1 not a valid integer: \'xyz\'\r\nWARN: Trade price on line 1 not a valid decimal: \'abc\'\r\nINFO: 1 trades processed\r\n",
+                _applicationUnderTest.ConsoleOutput);
+        }
+
+        [TestMethod]
+        public void TradeAmountInvalid()
+        {
+            _testDataInputFile.WithContent("GBPUSD,100,abc");
+
+            _applicationUnderTest.Run();
+
+            Assert.AreEqual(
+                "WARN: Trade price on line 1 not a valid decimal: \'abc\'\r\nINFO: 1 trades processed\r\n",
+                _applicationUnderTest.ConsoleOutput);
+        }
+
+        [TestMethod]
+        public void CorrectFormat()
+        {
+            _testDataInputFile.WithContent("GBPUSD,100,0.81");
+
+            _applicationUnderTest.Run();
+
+            Assert.AreEqual(
+                "INFO: 1 trades processed\r\n",
+                _applicationUnderTest.ConsoleOutput);
+        }
     }
 }


Fixed an issue #132 (Incorrect network messages/malformed packets could easily overwhelm the server). NetPeer.Heartbeat() method will no longer prematurely return from the method in case of encountering an incorrect packet.


Add unit tests

Add unit tests

--- UnitTestUsefullFunctions/UnitTestFunctionsMath.cs
+++ UnitTestUsefullFunctions/UnitTestFunctionsMath.cs
@@ -1371,7 +1371,7 @@
     }

     [TestMethod]
-    public void TestMethod_GetGreatests_negative_number_mixed_with_positive_numbers()
+    public void TestMethod_GetGreatests_negative_numbers_mixed_with_positive_numbers()
     {
       var source1 = new List<int> { 9, 0, 8, -7, 6, -5, 4, -3, 2, 1 };
       const int source2 = 6;
@@ -1379,6 +1379,16 @@
       var result = FunctionsMath.GetGreatests(source1, source2);
       AssertListsAreEqual(result, expected);
     }
+
+    [TestMethod]
+    public void TestMethod_GetGreatests_negative_and_positive_numbers_with_decimals()
+    {
+      var source1 = new List<int> { 9000, 0, 800, -7, 60, -5, 40, 15, -3, 22, 11 };
+      const int source2 = 6;
+      var expected = new List<int> { 9000, 800, 60, 40, 22, 15 };
+      var result = FunctionsMath.GetGreatests(source1, source2);
+      AssertListsAreEqual(result, expected);
+    }
     #endregion GetGreatests
     #endregion Math Methods
   }


fixed clothing item NRE

fixed clothing item NRE

--- UnityProject/Assets/Scripts/Items/ClothingItem.cs
+++ UnityProject/Assets/Scripts/Items/ClothingItem.cs
@@ -89,7 +89,7 @@
 				PushTexture();
 			}

-			if (!InHands)
+			if (!InHands && GameObjectReference != null)
 			{
 				// did we take off clothing?
 				var unequippedClothing = GameObjectReference.GetComponent<ClothingV2>();


trying to make the thing do the thing

trying to make the thing do the thing

--- UnityProject/Assets/Scripts/UI/Comms/GUI_Comms.cs
+++ UnityProject/Assets/Scripts/UI/Comms/GUI_Comms.cs
@@ -38,6 +38,8 @@
 	private EscapeShuttle shuttle;
 	private Coroutine callResultHandle;

+	private CentComm.AlertLevel AlertLevel = CentComm.AlertLevel.Green;
+
 	protected override void InitServer()
 	{
 		if (CustomNetworkManager.Instance._isServer)
@@ -173,9 +175,29 @@
 	}
 	public void ChangeAlertLevel()
 	{
-		//todo
 		Logger.Log( nameof(ChangeAlertLevel), Category.NetUI );
-	}
+		GameManager.Instance.CentComm.ChangeAlertLevel(AlertLevel);
+		OpenMenu();
+	}
+
+	public void SelectAlertGreen()
+	{
+		AlertLevel = CentComm.AlertLevel.Green;
+	}
+	public void SelectAlertBlue()
+	{
+		AlertLevel = CentComm.AlertLevel.Blue;
+	}
+	public void SelectAlertRed()
+	{
+		AlertLevel = CentComm.AlertLevel.Red;
+	}
+	public void SelectAlertDelta()
+	{
+		AlertLevel = CentComm.AlertLevel.Delta;
+	}
+
+
 	public void RequestNukeCodes()
 	{
 		//todo


cleanup converter

cleanup converter

--- WalletWasabi.Fluent/Converters/MoneyConverters.cs
+++ WalletWasabi.Fluent/Converters/MoneyConverters.cs
@@ -7,7 +7,7 @@
 	public static class MoneyConverters
 	{
 		public static readonly IValueConverter MoneyToString =
-			new FuncValueConverter<Money, string>(x =>
+			new FuncValueConverter<Money?, string>(x =>
 			{
 				return x switch
 				{
@@ -15,8 +15,5 @@
 					{ } => x.ToString(fplus: false, trimExcessZero: true),
 				};
 			});
-
-		public static readonly IValueConverter MoneyToBrush =
-			new FuncValueConverter<Money?, ISolidColorBrush>(x => x?.ToDecimal(MoneyUnit.BTC) > 0 ? Brushes.MediumSeaGreen : Brushes.IndianRed);
 	}
 }


path fixed

path fixed

git-svn-id: fd6972359415efc6fe3bcffb0078819e0d731d7f@222 a697401b-0683-4274-95e2-f182755d979b


[Modify] Add it

[Modify] Add it

--- websocket-sharp/Net/HttpConnection.cs
+++ websocket-sharp/Net/HttpConnection.cs
@@ -409,6 +409,15 @@
       _contextRegistered = false;
     }

+    private void unregisterContext ()
+    {
+      if (!_contextRegistered)
+        return;
+
+      _context.Listener.UnregisterContext (_context);
+      _contextRegistered = false;
+    }
+
     #endregion

     #region Internal Methods


[Modify] Replace it

[Modify] Replace it

--- websocket-sharp/Net/HttpConnection.cs
+++ websocket-sharp/Net/HttpConnection.cs
@@ -351,8 +351,7 @@
         if (conn._timeoutCanceled[current])
           return;

-        conn._context.ErrorStatusCode = 408;
-        conn._context.SendError ();
+        conn._context.SendError (408);
       }
     }


[Modify] Edit it

[Modify] Edit it

--- websocket-sharp/Net/HttpStatusCode.cs
+++ websocket-sharp/Net/HttpStatusCode.cs
@@ -53,8 +53,8 @@
     /// </summary>
     Continue = 100,
     /// <summary>
-    /// Equivalent to status code 101.
-    /// Indicates that the server is switching the HTTP version or protocol on the connection.
+    /// Equivalent to status code 101. Indicates that the server is switching
+    /// the HTTP version or protocol on the connection.
     /// </summary>
     SwitchingProtocols = 101,
     /// <summary>


Use the new observation type

Use the new observation type

--- code/SoftwareThresher/SoftwareThresher/Settings/Search/OpenGrokJsonSearch.cs
+++ code/SoftwareThresher/SoftwareThresher/Settings/Search/OpenGrokJsonSearch.cs
@@ -21,11 +21,9 @@
       public string BaseLocation { private get; set; }

       // TODO - Find a better way to search by ".cs" - do we double check in the code somehow and or search differently so that we can use the same parameter value - or should we use a filter?
-
       // TODO - use location?
       public List<Observation> GetObservations(string location, string searchPattern) {
-         // TODO - I do not think we want a FileObservation here - create a new class - have the to string convert \ to /
-         return GetResults($"{PathSearchParameterLabel}\"{searchPattern}\"").ConvertAll(r => (Observation)new FileObservation(r.path));
+         return GetResults($"{PathSearchParameterLabel}\"{searchPattern}\"").ConvertAll(r => (Observation)new OpenGrokObservation(r.directory, r.filename));
       }

       public List<string> GetReferenceLine(Observation observation, string searchPattern) {
@@ -58,15 +56,15 @@
       }

       public class OpenGrokJsonSearchResult {
-         //public string directory { get; set; }
-         //public string filename { get; set; }
+         public string directory { get; set; }
+         public string filename { get; set; }
          //public int lineno { get; set; }
          string _line;
          public string line {
             get { return _line; }
             set { _line = Encoding.UTF8.GetString(Convert.FromBase64String(value)); }
          }
-         public string path { get; set; }
+         //public string path { get; set; }
       }
    }
 }


Run code cleanup

Run code cleanup

--- code/Inbox.cs
+++ code/Inbox.cs
@@ -1,16 +1,16 @@
 using System;
+using System.Collections.Generic;
+using System.IO;
 using System.Linq;
-using System.Collections.Generic;
 using System.Media;
 using System.Net;
 using System.Text.RegularExpressions;
+using System.Threading.Tasks;
 using Google.Apis.Gmail.v1;
 using Google.Apis.Gmail.v1.Data;
 using Google.Apis.Services;
 using notifier.Languages;
 using notifier.Properties;
-using System.IO;
-using System.Threading.Tasks;

 namespace notifier {
 	class Inbox : IDisposable {


fixed error in help message

fixed error in help message

--- code/smake.cs
+++ code/smake.cs
@@ -593,7 +593,7 @@
     Note for Makefile creators: Default makefile is the first makefile in the list!
 Example Usage:
     smake                                   | Default run
-    smake [OtherMakefile] build_and_clean   | Select Makefile 'OtherMakeFile' and run 'build_and_clean' in it.
+    smake -m OtherMakefile build_and_clean  | Select Makefile 'OtherMakeFile' and run 'build_and_clean' in it.
     smake --verbose --mono --arch x86       | Run verbose, force 32 bit and force to use mono.
 Arguments (Optional):
     [target]              | Select target to be run.


Fixed issue with icons not visible

Fixed issue with icons not visible

--- SketchUpp/Sketching/Sketching.Common/Views/SketchView.xaml.cs
+++ SketchUpp/Sketching/Sketching.Common/Views/SketchView.xaml.cs
@@ -1,5 +1,6 @@
 using System.Collections.Generic;
 using System.Linq;
+using System.Reflection;
 using System.Security;
 using System.Windows.Input;
 using Sketching.Common.Interfaces;
@@ -59,17 +60,19 @@

 		private void AddDefaultToolbarItems()
 		{
-			AddToolbarItem(ImageSource.FromResource("Sketching.Common.Resources.Line.png"), new LineTool(), ActivateToolCommand);
-			AddToolbarItem(ImageSource.FromResource("Sketching.Common.Resources.Curve.png"), new CurveTool(), ActivateToolCommand);
-			AddToolbarItem(ImageSource.FromResource("Sketching.Common.Resources.Highlight.png"), new HighlightTool(), ActivateToolCommand);
-			AddToolbarItem(ImageSource.FromResource("Sketching.Common.Resources.Circle.png"), new CircleTool(), ActivateToolCommand);
-			AddToolbarItem(ImageSource.FromResource("Sketching.Common.Resources.Oval.png"), new OvalTool(), ActivateToolCommand);
-			AddToolbarItem(ImageSource.FromResource("Sketching.Common.Resources.Rectangle.png"), new RectangleTool(), ActivateToolCommand);
-			AddToolbarItem(ImageSource.FromResource("Sketching.Common.Resources.Arrow.png"), new ArrowTool(), ActivateToolCommand);
-			AddToolbarItem(ImageSource.FromResource("Sketching.Common.Resources.Point.png"), new PointTool(), ActivateToolCommand);
-			AddToolbarItem(ImageSource.FromResource("Sketching.Common.Resources.Text.png"), new TextTool(Navigation), ActivateToolCommand);
-			AddToolbarItem(ImageSource.FromResource("Sketching.Common.Resources.Undo.png"), null, UndoCommand);
-			AddToolbarItem(ImageSource.FromResource("Sketching.Common.Resources.Trash.png"), null, UndoAllCommand);
+			var assembly = typeof(SketchView).GetTypeInfo().Assembly;
+
+			AddToolbarItem(ImageSource.FromResource("Sketching.Common.Resources.Line.png",assembly), new LineTool(), ActivateToolCommand);
+			AddToolbarItem(ImageSource.FromResource("Sketching.Common.Resources.Curve.png", assembly), new CurveTool(), ActivateToolCommand);
+			AddToolbarItem(ImageSource.FromResource("Sketching.Common.Resources.Highlight.png", assembly), new HighlightTool(), ActivateToolCommand);
+			AddToolbarItem(ImageSource.FromResource("Sketching.Common.Resources.Circle.png", assembly), new CircleTool(), ActivateToolCommand);
+			AddToolbarItem(ImageSource.FromResource("Sketching.Common.Resources.Oval.png", assembly), new OvalTool(), ActivateToolCommand);
+			AddToolbarItem(ImageSource.FromResource("Sketching.Common.Resources.Rectangle.png", assembly), new RectangleTool(), ActivateToolCommand);
+			AddToolbarItem(ImageSource.FromResource("Sketching.Common.Resources.Arrow.png", assembly), new ArrowTool(), ActivateToolCommand);
+			AddToolbarItem(ImageSource.FromResource("Sketching.Common.Resources.Point.png", assembly), new PointTool(), ActivateToolCommand);
+			AddToolbarItem(ImageSource.FromResource("Sketching.Common.Resources.Text.png", assembly), new TextTool(Navigation), ActivateToolCommand);
+			AddToolbarItem(ImageSource.FromResource("Sketching.Common.Resources.Undo.png", assembly), null, UndoCommand);
+			AddToolbarItem(ImageSource.FromResource("Sketching.Common.Resources.Trash.png", assembly), null, UndoAllCommand);
 		}

 		private void ActivateTool(ITool tool)


Added some more base stuff.

Added some more base stuff.

--- Slack.Webhooks.PowerShell/Slack.Webhooks.PowerShell/Class1.cs
+++ Slack.Webhooks.PowerShell/Slack.Webhooks.PowerShell/Class1.cs
@@ -49,6 +49,7 @@

         protected override void ProcessRecord()
         {
+            WriteDebug(string.Format("Sending Message to {0}", URI));
             slackClient.Post(Message);
         }

@@ -57,11 +58,11 @@
             base.EndProcessing();
         }
     }
-    [Cmdlet(VerbsCommon.New, "SlackMessage", SupportsShouldProcess = false)]
+    [Cmdlet(VerbsCommon.New, "SlackMessage", SupportsShouldProcess = false, SupportsTransactions = false)]
     public class CreateSlackMessage : PSCmdlet
     {
         [Parameter(
-            Mandatory = true,
+            Mandatory = false,
             Position = 0
             )]
         public string Channel
@@ -70,7 +71,7 @@
             set;
         }
         [Parameter(
-            Mandatory = true,
+            Mandatory = false,
             Position = 1
             )]
         public string Text
@@ -96,19 +97,22 @@
             get;
             set;
         }
-        public bool LinkNames
-        {
-            get;
-            set;
-        }
-        public bool Markdown
-        {
-            get;
-            set;
-        }
-
-        [Parameter(
-            Mandatory = false
+        [Parameter(Mandatory = false)]
+        public SwitchParameter LinkNames
+        {
+            get;
+            set;
+        }
+        [Parameter(Mandatory = false)]
+        public SwitchParameter NotMarkdown
+        {
+            get;
+            set;
+        }
+
+        [Parameter(
+            Mandatory = false,
+            HelpMessage = "https://api.slack.com/docs/message-formatting"
             )]
         [ValidateSet("full","none")]
         public string ParseMode
@@ -116,6 +120,18 @@
             get;
             set;
         }
+        [Parameter(Mandatory = false)]
+        public string IconUrl
+        {
+            get;
+            set;
+        }
+        [Parameter(Mandatory = false)]
+        public SlackAttachment Attachments
+        {
+            get;
+            set;
+        }

         protected override void BeginProcessing()
         {
@@ -123,20 +139,136 @@

         protected override void ProcessRecord()
         {
-
+            WriteDebug("Instansiating SlackMessage")
             SlackMessage message = new SlackMessage
             {
                 Channel = Channel,
                 Text = Text,
                 Username = Username,
-                LinkNames = LinkNames,
-                Mrkdwn = Markdown,
-
+                Parse = ParseMode
+        };
+
+            if(!string.IsNullOrEmpty(IconUrl))
+            {
+                WriteDebug("Building IconUrl URIBuilder");
+                UriBuilder IconURI = new UriBuilder(IconUrl);
+                message.IconUrl = IconURI.Uri;
+            }
+            if(NotMarkdown){message.Mrkdwn = false;}
+            if(LinkNames) { message.LinkNames = true; }
+            if(Attachments != null)
+            {
+                WriteDebug("Attachments Found. Converting to list");
+                message.Attachments = new List<SlackAttachment> { Attachments };
+            }
+            WriteDebug("Message Created Ouputting to pipeline");
+            WriteObject(message);
+        }
+
+        protected override void EndProcessing()
+        {
+            base.EndProcessing();
+        }
+    }
+    [Cmdlet(VerbsCommon.New, "SlackAttachment", SupportsShouldProcess = false, SupportsTransactions = false)]
+    public class CreateSlackAttachment : PSCmdlet
+    {
+        [Parameter(
+            Mandatory = false,
+            Position = 0
+            )]
+        public string Channel
+        {
+            get;
+            set;
+        }
+        [Parameter(
+            Mandatory = false,
+            Position = 1
+            )]
+        public string Text
+        {
+            get;
+            set;
+        }
+        [Parameter(
+            Mandatory = false,
+            Position = 2
+            )]
+        public string IconEmoji
+        {
+            get;
+            set;
+        }
+        [Parameter(
+            Mandatory = false,
+            Position = 3
+            )]
+        public string Username
+        {
+            get;
+            set;
+        }
+        [Parameter(Mandatory = false)]
+        public SwitchParameter LinkNames
+        {
+            get;
+            set;
+        }
+        [Parameter(Mandatory = false)]
+        public SwitchParameter NotMarkdown
+        {
+            get;
+            set;
+        }
+
+        [Parameter(
+            Mandatory = false,
+            HelpMessage = "https://api.slack.com/docs/message-formatting"
+            )]
+        [ValidateSet("full", "none")]
+        public string ParseMode
+        {
+            get;
+            set;
+        }
+        [Parameter(Mandatory = false)]
+        public string IconUrl
+        {
+            get;
+            set;
+        }
+        [Parameter(Mandatory = false)]
+        public SlackAttachment Attachments
+        {
+            get;
+            set;
+        }
+
+        protected override void BeginProcessing()
+        {
+        }
+
+        protected override void ProcessRecord()
+        {
+            WriteDebug("Instansiating SlackMessage");
+            SlackAttachment attachment = new SlackAttachment
+            {
+                AuthorIcon = "",
+                AuthorLink = "",
+                AuthorName = "",
+                Color = "",
+                Fallback = "",
+                ImageUrl = "",
+                Pretext = "",
+                Text = "",
+                ThumbUrl = "",
+                Title = "",
+                TitleLink = ""
             };
-
-            message.Parse
-
-            WriteObject(message);
+            //Fields
+            //MrkdwnIn
+            WriteObject(attachment);
         }

         protected override void EndProcessing()


Only update bone skin vertex buffer if bone matrices are updated.

--- Source/HelixToolkit.SharpDX.Shared/Core/BoneSkinRenderCore.cs
+++ Source/HelixToolkit.SharpDX.Shared/Core/BoneSkinRenderCore.cs
@@ -14,12 +14,16 @@

     public class BoneSkinRenderCore : MeshRenderCore
     {
+        private bool matricsChanged = true;
         private BoneMatricesStruct boneMatrices;
         public BoneMatricesStruct BoneMatrices
         {
             set
             {
-                SetAffectsRender(ref boneMatrices, value);
+                if(SetAffectsRender(ref boneMatrices, value))
+                {
+                    matricsChanged = true;
+                }
             }
             get { return boneMatrices; }
         }
@@ -36,6 +40,7 @@
         {
             if(base.OnAttach(technique))
             {
+                matricsChanged = true;
                 boneCB = technique.ConstantBufferPool.Register(new ConstantBufferDescription(DefaultBufferNames.BoneCB, BoneMatricesStruct.SizeInBytes));
                 boneSkinPass = technique[DefaultPassNames.MeshBoneSkinned];
                 return true;
@@ -48,7 +53,7 @@

         protected override void OnUpdate(RenderContext context, DeviceContextProxy deviceContext)
         {
-            if (boneSkinPass.IsNULL)
+            if (boneSkinPass.IsNULL || !matricsChanged)
             {
                 return;
             }
@@ -64,6 +69,7 @@
                 deviceContext.Draw(GeometryBuffer.VertexBuffer[0].ElementCount, 0);
                 boneBuffer.UnBindSkinnedVertexBufferToOutput(deviceContext);
             }
+            matricsChanged = false;
         }
     }
 }


Fix showdown functionality

Fix showdown functionality

Only if both players have not folded there`s a showdown, otherwise none of the players hands are shown.

--- Source/TexasHoldem.Logic/GameMechanics/TwoPlayersHandLogic.cs
+++ Source/TexasHoldem.Logic/GameMechanics/TwoPlayersHandLogic.cs
@@ -71,15 +71,6 @@

             this.DetermineWinnerAndAddPot(this.bettingLogic.Pot);

-            // showdown
-            foreach (var player in this.players)
-            {
-                if (player.PlayerMoney.InHand)
-                {
-                    this.showdownCards.Add(player.Name, player.Cards);
-                }
-            }
-
             foreach (var player in this.players)
             {
                 player.EndHand(new EndHandContext(this.showdownCards));
@@ -95,6 +86,15 @@
             }
             else
             {
+                // showdown
+                foreach (var player in this.players)
+                {
+                    if (player.PlayerMoney.InHand)
+                    {
+                        this.showdownCards.Add(player.Name, player.Cards);
+                    }
+                }
+
                 var betterHand = Helpers.CompareCards(
                     this.players[0].Cards.Concat(this.communityCards),
                     this.players[1].Cards.Concat(this.communityCards));


Removed IsNavigating

Removed IsNavigating

--- Sources/Silphid.Showzup/Sources/Controls/NavigationControl.cs
+++ Sources/Silphid.Showzup/Sources/Controls/NavigationControl.cs
@@ -20,7 +20,6 @@
         #region Fields

         private readonly CompositeDisposable _disposables = new CompositeDisposable();
-        private readonly ReactiveProperty<bool> _isNavigating = new ReactiveProperty<bool>(false);
         private readonly Subject<Nav> _navigating = new Subject<Nav>();
         private readonly Subject<Nav> _navigated = new Subject<Nav>();
         private ReadOnlyReactiveProperty<bool> _canPush;
@@ -30,8 +29,6 @@

         public GameObject HistoryContainer;
         public bool CanPopTopLevelView;
-
-        public ReadOnlyReactiveProperty<bool> IsNavigating { get; private set; }

         [FormerlySerializedAs("ShouldHandleBackRequests")] [FormerlySerializedAs("HandlesBackRequest")]
         public bool HandleBackRequest;
@@ -41,7 +38,6 @@
         [Inject]
         public void Inject()
         {
-            IsNavigating = _isNavigating.ToReadOnlyReactiveProperty();
             History.PairWithPrevious().Skip(1).Subscribe(DisposeDroppedViews).AddTo(_disposables);
         }

@@ -207,7 +203,6 @@

         private void StartChange()
         {
-         	_isNavigating.Value = true;
             MutableState.Value = PresenterState.Loading;
         }

@@ -233,7 +228,6 @@

         private void CompleteChange(Nav nav)
         {
-        	_isNavigating.Value = false;
             MutableState.Value = PresenterState.Ready;
             (nav.Target as IPostNavigate)?.OnPostNavigate();
         }


probably fixed #37

probably fixed #37

--- TCC.Core/ViewModels/MultiThreadManagers/GroupWindowManager.cs
+++ TCC.Core/ViewModels/MultiThreadManagers/GroupWindowManager.cs
@@ -730,6 +730,7 @@
         {
             if(TryGetUser(startList, serverId,playerId, out User u))
             {
+                if (TryGetUser(endList, serverId, playerId, out User x)) return;
                 endList.Add(u);
                 startList.Remove(u);
             }


UOW moved up

UOW moved up

--- TIKSN.Core/Finance/ForeignExchange/ExchangeRateServiceBase.cs
+++ TIKSN.Core/Finance/ForeignExchange/ExchangeRateServiceBase.cs
@@ -65,33 +65,39 @@
         {
             var combinedRates = new List<ExchangeRateEntity>();

-            foreach (var provider in _providers)
+            using (var uow = _unitOfWorkFactory.Create())
             {
-                var ticksToIntervalRatio = asOn.Ticks / provider.Value.InvalidationInterval.Ticks;
-                var dateFrom = new DateTimeOffset(ticksToIntervalRatio * provider.Value.InvalidationInterval.Ticks, asOn.Offset);
-                var dateTo = new DateTimeOffset((ticksToIntervalRatio + 1) * provider.Value.InvalidationInterval.Ticks, asOn.Offset);
+                foreach (var provider in _providers)
+                {
+                    var ticksToIntervalRatio = asOn.Ticks / provider.Value.InvalidationInterval.Ticks;
+                    var dateFrom = new DateTimeOffset(ticksToIntervalRatio * provider.Value.InvalidationInterval.Ticks, asOn.Offset);
+                    var dateTo = new DateTimeOffset((ticksToIntervalRatio + 1) * provider.Value.InvalidationInterval.Ticks, asOn.Offset);

-                var rates = await _exchangeRateRepository.SearchAsync(provider.Key, pair.BaseCurrency.ISOCurrencySymbol, pair.CounterCurrency.ISOCurrencySymbol, dateFrom, dateTo, cancellationToken);
+                    var rates = await _exchangeRateRepository.SearchAsync(provider.Key, pair.BaseCurrency.ISOCurrencySymbol, pair.CounterCurrency.ISOCurrencySymbol, dateFrom, dateTo, cancellationToken);

-                if (rates.Count == 0)
-                {
-                    if (provider.Value.BatchProvider != null)
-                        await FetchExchangeRatesAsync(provider.Key, provider.Value.BatchProvider, asOn, cancellationToken);
-                    else if (provider.Value.IndividualProvider != null)
-                        await FetchExchangeRatesAsync(provider.Key, provider.Value.IndividualProvider, pair, asOn, cancellationToken);
+                    if (rates.Count == 0)
+                    {
+                        if (provider.Value.BatchProvider != null)
+                            await FetchExchangeRatesAsync(provider.Key, provider.Value.BatchProvider, asOn, cancellationToken);
+                        else if (provider.Value.IndividualProvider != null)
+                            await FetchExchangeRatesAsync(provider.Key, provider.Value.IndividualProvider, pair, asOn, cancellationToken);
+                        else
+                            throw new Exception($"{nameof(provider.Value.BatchProvider)} and {nameof(provider.Value.IndividualProvider)} are both null, one of them should be null and other should not.");
+
+                        var rate = await _exchangeRateRepository.GetAsync(provider.Key, pair.BaseCurrency.ISOCurrencySymbol, pair.CounterCurrency.ISOCurrencySymbol, asOn, cancellationToken);
+
+                        if (rate != null)
+                            combinedRates.Add(rate);
+                    }
                     else
-                        throw new Exception($"{nameof(provider.Value.BatchProvider)} and {nameof(provider.Value.IndividualProvider)} are both null, one of them should be null and other should not.");
+                    {
+                        combinedRates.AddRange(rates);
+                    }
+                }

-                    var rate = await _exchangeRateRepository.GetAsync(provider.Key, pair.BaseCurrency.ISOCurrencySymbol, pair.CounterCurrency.ISOCurrencySymbol, asOn, cancellationToken);
+                await uow.CompleteAsync(cancellationToken);
+            }

-                    if (rate != null)
-                        combinedRates.Add(rate);
-                }
-                else
-                {
-                    combinedRates.AddRange(rates);
-                }
-            }
             var exchangeRateEntity = combinedRates
                 .MinBy(item => Math.Abs((item.AsOn - asOn).Ticks))
                 .First();
@@ -165,24 +171,19 @@

         private async Task SaveExchangeRatesAsync(int foreignExchangeID, IEnumerable<ExchangeRate> exchangeRates, CancellationToken cancellationToken)
         {
-            using (var uow = _unitOfWorkFactory.Create())
+            var id = Interlocked.Increment(ref nextID);
+
+            var entities = exchangeRates.Select(item => new ExchangeRateEntity
             {
-                var id = Interlocked.Increment(ref nextID);
+                ID = id,
+                AsOn = item.AsOn,
+                BaseCurrencyCode = item.Pair.BaseCurrency.ISOCurrencySymbol,
+                CounterCurrencyCode = item.Pair.CounterCurrency.ISOCurrencySymbol,
+                ForeignExchangeID = foreignExchangeID,
+                Rate = item.Rate
+            }).ToArray();

-                var entities = exchangeRates.Select(item => new ExchangeRateEntity
-                {
-                    ID = id,
-                    AsOn = item.AsOn,
-                    BaseCurrencyCode = item.Pair.BaseCurrency.ISOCurrencySymbol,
-                    CounterCurrencyCode = item.Pair.CounterCurrency.ISOCurrencySymbol,
-                    ForeignExchangeID = foreignExchangeID,
-                    Rate = item.Rate
-                }).ToArray();
-
-                await _exchangeRateRepository.AddRangeAsync(entities, cancellationToken);
-
-                await uow.CompleteAsync(cancellationToken);
-            }
+            await _exchangeRateRepository.AddRangeAsync(entities, cancellationToken);
         }
     }
 }


Serving ckeditor from secure domain

Serving ckeditor from secure domain

--- Trappist/src/Promact.Trappist.Web/Views/Shared/_Layout.cshtml
+++ Trappist/src/Promact.Trappist.Web/Views/Shared/_Layout.cshtml
@@ -47,6 +47,6 @@
             }
         </div>
     </footer>
-    <script src="http://cdn.ckeditor.com/4.6.2/standard/ckeditor.js"></script>
+    <script src="https://cdn.ckeditor.com/4.6.2/standard/ckeditor.js"></script>
 </body>
 </html>


Cache only 3 songs at a time

Cache only 3 songs at a time

--- Espera/Espera.Core/Library/Library.cs
+++ Espera/Espera.Core/Library/Library.cs
@@ -303,13 +303,21 @@
         /// <param name="songList">The songs to add to the end of the playlist.</param>
         public void AddSongsToPlaylist(IEnumerable<Song> songList)
         {
+            var options = new ParallelOptions { MaxDegreeOfParallelism = 3 };
+
+            Task.Factory.StartNew(() =>
+            {
+                Parallel.ForEach(songList, options, song =>
+                {
+                    if (!song.IsCached)
+                    {
+                        song.LoadToCache();
+                    }
+                });
+            });
+
             foreach (Song song in songList)
             {
-                if (!song.IsCached)
-                {
-                    Task.Factory.StartNew(song.LoadToCache);
-                }
-
                 int newIndex = this.playlist.Keys.Count == 0 ? 0 : this.playlist.Keys.Max() + 1;

                 this.playlist.Add(newIndex, song);


Fix to pass Models.TimeTests

Fix to pass Models.TimeTests


Do not fail the routine if it takes us more than 1 time

--- ArchiSteamFarm/Actions.cs
+++ ArchiSteamFarm/Actions.cs
@@ -60,6 +60,8 @@
 				return false;
 			}

+			HashSet<ulong> handledTradeOfferIDs = null;
+
 			for (byte i = 0; (i == 0) || ((i < WebBrowser.MaxTries) && waitIfNeeded); i++) {
 				if (i > 0) {
 					await Task.Delay(1000).ConfigureAwait(false);
@@ -89,9 +91,15 @@
 					return false;
 				}

+				IEnumerable<ulong> handledTradeOfferIDsThisRound = results.Where(details => (details != null) && (details.TradeOfferID != 0)).Select(result => result.TradeOfferID);
+
+				if (handledTradeOfferIDs != null) {
+					handledTradeOfferIDs.UnionWith(handledTradeOfferIDsThisRound);
+				} else {
+					handledTradeOfferIDs = handledTradeOfferIDsThisRound.ToHashSet();
+				}
+
 				// Check if those are all that we were expected to confirm
-				HashSet<ulong> handledTradeOfferIDs = results.Where(details => (details != null) && (details.TradeOfferID != 0)).Select(result => result.TradeOfferID).ToHashSet();
-
 				if (handledTradeOfferIDs.SetEquals(acceptedTradeOfferIDs)) {
 					return true;
 				}


Misc trading improvements

Misc trading improvements

--- ArchiSteamFarm/Trading.cs
+++ ArchiSteamFarm/Trading.cs
@@ -34,8 +34,7 @@
 		internal const byte MaxTradesPerAccount = 5; // This is limit introduced by Valve

 		private readonly Bot Bot;
-		private readonly ConcurrentHashSet<ulong> IgnoredTrades = new ConcurrentHashSet<ulong>();
-		private readonly ConcurrentHashSet<ulong> RecentTrades = new ConcurrentHashSet<ulong>();
+		private readonly ConcurrentHashSet<ulong> HandledTradeOfferIDs = new ConcurrentHashSet<ulong>();
 		private readonly SemaphoreSlim TradesSemaphore = new SemaphoreSlim(1, 1);

 		private bool ParsingScheduled;
@@ -255,10 +254,7 @@
 			return true;
 		}

-		internal void OnDisconnected() {
-			IgnoredTrades.Clear();
-			RecentTrades.Clear();
-		}
+		internal void OnDisconnected() => HandledTradeOfferIDs.Clear();

 		internal async Task OnNewTrade() {
 			// We aim to have a maximum of 2 tasks, one already working, and one waiting in the queue
@@ -408,15 +404,11 @@
 				return;
 			}

-			if (IgnoredTrades.Count > 0) {
-				IgnoredTrades.IntersectWith(tradeOffers.Select(tradeOffer => tradeOffer.TradeOfferID));
-			}
-
-			if (RecentTrades.Count > 0) {
-				RecentTrades.IntersectWith(tradeOffers.Select(tradeOffer => tradeOffer.TradeOfferID));
-			}
-
-			IEnumerable<Task<(ParseTradeResult TradeResult, bool RequiresMobileConfirmation)>> tasks = tradeOffers.Where(tradeOffer => !IgnoredTrades.Contains(tradeOffer.TradeOfferID)).Select(ParseTrade);
+			if (HandledTradeOfferIDs.Count > 0) {
+				HandledTradeOfferIDs.IntersectWith(tradeOffers.Select(tradeOffer => tradeOffer.TradeOfferID));
+			}
+
+			IEnumerable<Task<(ParseTradeResult TradeResult, bool RequiresMobileConfirmation)>> tasks = tradeOffers.Where(tradeOffer => !HandledTradeOfferIDs.Contains(tradeOffer.TradeOfferID)).Select(ParseTrade);
 			IList<(ParseTradeResult TradeResult, bool RequiresMobileConfirmation)> results = await Utilities.InParallel(tasks).ConfigureAwait(false);

 			if (Bot.HasMobileAuthenticator) {
@@ -424,6 +416,8 @@

 				if (mobileTradeOfferIDs.Count > 0) {
 					if (!await Bot.Actions.AcceptConfirmations(true, Steam.ConfirmationDetails.EType.Trade, mobileTradeOfferIDs, true).ConfigureAwait(false)) {
+						HandledTradeOfferIDs.ExceptWith(mobileTradeOfferIDs);
+
 						return;
 					}
 				}
@@ -448,12 +442,11 @@
 				return (null, false);
 			}

-			if (!RecentTrades.Add(tradeOffer.TradeOfferID)) {
-				// We've already seen this trade
-				IgnoredTrades.Add(tradeOffer.TradeOfferID);
-				Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.IgnoringTrade, tradeOffer.TradeOfferID));
-
-				return (new ParseTradeResult(tradeOffer.TradeOfferID, ParseTradeResult.EResult.RejectedPermanently), false);
+			if (!HandledTradeOfferIDs.Add(tradeOffer.TradeOfferID)) {
+				// We've already seen this trade, this should not happen
+				Bot.ArchiLogger.LogGenericError(string.Format(Strings.IgnoringTrade, tradeOffer.TradeOfferID));
+
+				return (new ParseTradeResult(tradeOffer.TradeOfferID, ParseTradeResult.EResult.RejectedTemporarily), false);
 			}

 			ParseTradeResult result = await ShouldAcceptTrade(tradeOffer).ConfigureAwait(false);
@@ -470,26 +463,39 @@

 					(bool success, bool requiresMobileConfirmation) = await Bot.ArchiWebHandler.AcceptTradeOffer(tradeOffer.TradeOfferID).ConfigureAwait(false);

-					if (success) {
-						if (tradeOffer.ItemsToReceive.Sum(item => item.Amount) > tradeOffer.ItemsToGive.Sum(item => item.Amount)) {
-							Bot.ArchiLogger.LogGenericTrace(string.Format(Strings.BotAcceptedDonationTrade, tradeOffer.TradeOfferID));
-						}
-					}
-
-					return (result, success && requiresMobileConfirmation);
-				case ParseTradeResult.EResult.RejectedAndBlacklisted:
+					if (!success) {
+						result.Result = ParseTradeResult.EResult.TryAgain;
+
+						goto case ParseTradeResult.EResult.TryAgain;
+					}
+
+					if (tradeOffer.ItemsToReceive.Sum(item => item.Amount) > tradeOffer.ItemsToGive.Sum(item => item.Amount)) {
+						Bot.ArchiLogger.LogGenericTrace(string.Format(Strings.BotAcceptedDonationTrade, tradeOffer.TradeOfferID));
+					}
+
+					return (result, requiresMobileConfirmation);
+				case ParseTradeResult.EResult.Blacklisted:
 				case ParseTradeResult.EResult.RejectedPermanently when Bot.BotConfig.BotBehaviour.HasFlag(BotConfig.EBotBehaviour.RejectInvalidTrades):
+				case ParseTradeResult.EResult.RejectedTemporarily when Bot.BotConfig.BotBehaviour.HasFlag(BotConfig.EBotBehaviour.RejectInvalidTrades):
 					Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.RejectingTrade, tradeOffer.TradeOfferID));
-					await Bot.ArchiWebHandler.DeclineTradeOffer(tradeOffer.TradeOfferID).ConfigureAwait(false);
+
+					if (!await Bot.ArchiWebHandler.DeclineTradeOffer(tradeOffer.TradeOfferID).ConfigureAwait(false)) {
+						result.Result = ParseTradeResult.EResult.TryAgain;
+
+						goto case ParseTradeResult.EResult.TryAgain;
+					}

 					return (result, false);
+				case ParseTradeResult.EResult.Ignored:
 				case ParseTradeResult.EResult.RejectedPermanently:
-					IgnoredTrades.Add(tradeOffer.TradeOfferID);
-					goto case ParseTradeResult.EResult.RejectedTemporarily;
 				case ParseTradeResult.EResult.RejectedTemporarily:
 					Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.IgnoringTrade, tradeOffer.TradeOfferID));

 					return (result, false);
+				case ParseTradeResult.EResult.TryAgain:
+					HandledTradeOfferIDs.Remove(tradeOffer.TradeOfferID);
+
+					goto case ParseTradeResult.EResult.Ignored;
 				default:
 					Bot.ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(result.Result), result.Result));

@@ -512,7 +518,7 @@

 				// Always deny trades from blacklisted steamIDs
 				if (Bot.IsBlacklistedFromTrades(tradeOffer.OtherSteamID64)) {
-					return new ParseTradeResult(tradeOffer.TradeOfferID, ParseTradeResult.EResult.RejectedAndBlacklisted, tradeOffer.ItemsToReceive);
+					return new ParseTradeResult(tradeOffer.TradeOfferID, ParseTradeResult.EResult.Blacklisted, tradeOffer.ItemsToReceive);
 				}
 			}

@@ -520,8 +526,8 @@
 			switch (tradeOffer.ItemsToGive.Count) {
 				case 0 when tradeOffer.ItemsToReceive.Count == 0:

-					// If it's steam issue, temporarily ignore it
-					return new ParseTradeResult(tradeOffer.TradeOfferID, ParseTradeResult.EResult.RejectedTemporarily, tradeOffer.ItemsToReceive);
+					// If it's steam issue, try again later
+					return new ParseTradeResult(tradeOffer.TradeOfferID, ParseTradeResult.EResult.TryAgain, tradeOffer.ItemsToReceive);
 				case 0:

 					// Otherwise react accordingly, depending on our preference
@@ -565,8 +571,8 @@
 			byte? holdDuration = await Bot.GetTradeHoldDuration(tradeOffer.OtherSteamID64, tradeOffer.TradeOfferID).ConfigureAwait(false);

 			if (!holdDuration.HasValue) {
-				// If we can't get trade hold duration, reject trade temporarily
-				return new ParseTradeResult(tradeOffer.TradeOfferID, ParseTradeResult.EResult.RejectedTemporarily, tradeOffer.ItemsToReceive);
+				// If we can't get trade hold duration, try again later
+				return new ParseTradeResult(tradeOffer.TradeOfferID, ParseTradeResult.EResult.TryAgain, tradeOffer.ItemsToReceive);
 			}

 			// If user has a trade hold, we add extra logic
@@ -593,22 +599,23 @@
 			HashSet<Steam.Asset> inventory = await Bot.ArchiWebHandler.GetInventory(Bot.SteamID, wantedSets: wantedSets).ConfigureAwait(false);

 			if ((inventory == null) || (inventory.Count == 0)) {
-				// If we can't check our inventory when not using MatchEverything, this is a temporary failure
+				// If we can't check our inventory when not using MatchEverything, this is a temporary failure, try again later
 				Bot.ArchiLogger.LogGenericWarning(string.Format(Strings.ErrorIsEmpty, nameof(inventory)));

-				return new ParseTradeResult(tradeOffer.TradeOfferID, ParseTradeResult.EResult.RejectedTemporarily, tradeOffer.ItemsToReceive);
+				return new ParseTradeResult(tradeOffer.TradeOfferID, ParseTradeResult.EResult.TryAgain, tradeOffer.ItemsToReceive);
 			}

 			bool accept = IsTradeNeutralOrBetter(inventory, tradeOffer.ItemsToGive, tradeOffer.ItemsToReceive);

-			// Even if trade is not neutral+ for us right now, it might be in the future, unless we're bot account where we assume that inventory doesn't change
-			return new ParseTradeResult(tradeOffer.TradeOfferID, accept ? ParseTradeResult.EResult.Accepted : Bot.BotConfig.BotBehaviour.HasFlag(BotConfig.EBotBehaviour.RejectInvalidTrades) ? ParseTradeResult.EResult.RejectedPermanently : ParseTradeResult.EResult.RejectedTemporarily, tradeOffer.ItemsToReceive);
+			// Even if trade is not neutral+ for us right now, it might be in the future, so we're rejecting it temporarily and letting bot logic decide what to do with it
+			return new ParseTradeResult(tradeOffer.TradeOfferID, accept ? ParseTradeResult.EResult.Accepted : ParseTradeResult.EResult.RejectedTemporarily, tradeOffer.ItemsToReceive);
 		}

 		private sealed class ParseTradeResult {
 			internal readonly HashSet<Steam.Asset.EType> ReceivingItemTypes;
-			internal readonly EResult Result;
 			internal readonly ulong TradeOfferID;
+
+			internal EResult Result { get; set; }

 			internal ParseTradeResult(ulong tradeOfferID, EResult result, IReadOnlyCollection<Steam.Asset> itemsToReceive = null) {
 				if ((tradeOfferID == 0) || (result == EResult.Unknown)) {
@@ -626,9 +633,11 @@
 			internal enum EResult : byte {
 				Unknown,
 				Accepted,
+				Blacklisted,
+				Ignored,
+				RejectedPermanently,
 				RejectedTemporarily,
-				RejectedPermanently,
-				RejectedAndBlacklisted
+				TryAgain
 			}
 		}
 	}


Updated version to 1.1.0

Updated version to 1.1.0

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


Bumping version to 1.2.4-beta

Bumping version to 1.2.4-beta


Fix: Crash on application shutdown

Fix: Crash on application shutdown

--- source/Playnite.DesktopApp/DesktopCollectionView.cs
+++ source/Playnite.DesktopApp/DesktopCollectionView.cs
@@ -100,8 +100,6 @@

         public override void Dispose()
         {
-            ClearItems();
-            base.Dispose();
             Database.Games.ItemCollectionChanged -= Database_GamesCollectionChanged;
             Database.Games.ItemUpdated -= Database_GameUpdated;
             Database.Platforms.ItemUpdated -= Database_PlatformUpdated;
@@ -116,6 +114,8 @@
             Database.Tags.ItemUpdated -= Tags_ItemUpdated;
             Database.Features.ItemUpdated -= Features_ItemUpdated;
             viewSettings.PropertyChanged -= ViewSettings_PropertyChanged;
+            ClearItems();
+            base.Dispose();
         }

         private void ViewSettings_PropertyChanged(object sender, PropertyChangedEventArgs e)


Add test for reading properties.

Add test for reading properties.

--- UnitTests/StringBuilderFillTests.cs
+++ UnitTests/StringBuilderFillTests.cs
@@ -152,5 +152,20 @@
             var sb = new StringBuilder();
             sb.AppendFill("{", new {});
         }
+
+        private class TestParameters
+        {
+            public string S { get; set; }
+            public int I { get; set; }
+        }
+
+        [TestMethod]
+        public void StringBuilder_AppendFill_ShouldFillUsingProperties()
+        {
+            var parameters = new TestParameters {S = "eggs", I = 201};
+            var sb = new StringBuilder();
+            sb.AppendFill("{S} = {I}", parameters);
+            Assert.AreEqual("eggs = 201", sb.ToString());
+        }
     }
 }


Use Sample

Use Sample

--- WalletWasabi.Gui/Controls/WalletExplorer/CoinListViewModel.cs
+++ WalletWasabi.Gui/Controls/WalletExplorer/CoinListViewModel.cs
@@ -424,7 +424,7 @@

 			Observable
 				.FromEventPattern(this, nameof(SelectionCheckBoxesInvalidated))
-				.Throttle(TimeSpan.FromSeconds(0.5))
+				.Sample(TimeSpan.FromSeconds(0.5))
 				.ObserveOn(RxApp.MainThreadScheduler)
 				.Subscribe(x =>
 				{
@@ -442,7 +442,7 @@

 			Observable
 				.FromEventPattern(this, nameof(CoinListStatusColumnInvalidated))
-				.Throttle(TimeSpan.FromSeconds(0.5))
+				.Sample(TimeSpan.FromSeconds(0.5))
 				.ObserveOn(RxApp.MainThreadScheduler)
 				.Subscribe(_ =>
 				{


add dummy getTimePosition_XXX() for monthly and yearly

--- Assets/timeGraphScript.cs
+++ Assets/timeGraphScript.cs
@@ -153,6 +153,10 @@
 			return getTimePosition_daily (dt);
 		case XType.Weekly:
 			return getTimePosition_weekly(dt);
+		case XType.Monthly:
+			return getTimePosition_monthly(dt);
+		case XType.Yearly:
+			return getTimePosition_yearly(dt);
 		default:
 			return getTimePosition_daily (dt);
 		}
@@ -170,6 +174,14 @@
 	static public float getTimePosition_weekly(System.DateTime dt)
 	{
 		return getTimePosition_daily(dt) / 10.0f;
+	}
+	static public float getTimePosition_monthly(System.DateTime dt)
+	{
+		return getTimePosition_daily(dt) / 100.0f;
+	}
+	static public float getTimePosition_yearly(System.DateTime dt)
+	{
+		return getTimePosition_daily(dt) / 1000.0f;
 	}

 	static public void SetXYVal(System.DateTime time, float yval_)


Add keep-alives to SSH

Add keep-alives to SSH

Fixes #185

--- AtlasSSH/SSHConnection.cs
+++ AtlasSSH/SSHConnection.cs
@@ -67,6 +67,7 @@
             // Create the connection, but do it lazy so we don't do anything if we aren't used.
             _client = new Lazy<SshClient>(() => {
                 var c = new SshClient(host, username, passwordInfo.Password);
+                c.KeepAliveInterval = TimeSpan.FromSeconds(15);
                 c.Connect();
                 return c;
             });
@@ -326,7 +327,7 @@
             var r = new SSHSubShellContext(_prompt, this);

             // Issue the ssh command... Since this isn't coming back, we have to do it a little differently.
-            ExecuteCommand($"ssh -oStrictHostKeyChecking=no {username}@{host}", WaitForCommandResult: false);
+            ExecuteCommand($"ssh -oStrictHostKeyChecking=no -o TCPKeepAlive=yes -o ServerAliveInterval=15 {username}@{host}", WaitForCommandResult: false);
             _prompt = null;
             var cmdResult = new StringBuilder();
             while (_prompt == null)


Bump version to 1.3.0

Bump version to 1.3.0

--- common/SolutionInfo.cs
+++ common/SolutionInfo.cs
@@ -31,7 +31,7 @@
 namespace System
 {
     internal static class AssemblyVersionInformation {
-        private const string GitHubForUnityVersion = "1.2.2";
+        private const string GitHubForUnityVersion = "1.3.0";
         internal const string VersionForAssembly = GitHubForUnityVersion;

         // If this is an alpha, beta or other pre-release, mark it as such as shown below


Add more details to the Setup in case it fails (#64)

--- AzureBot.Tests/General.cs
+++ AzureBot.Tests/General.cs
@@ -25,14 +25,27 @@

             botHelper = new BotHelper(directLineToken, appId, fromUser);

-            var reply = botHelper.SendMessage("select subscription").Result;
-            string expected = "Please select the subscription";
-            Assert.IsTrue(reply.StartsWith(expected));
+            Func<string, string, string> errorMessageHandler = (message, expected) => $"Setup failed with message: '{message}'. The expected message is '{expected}'.";

             var subscription = context.GetSubscription();
-            reply = botHelper.SendMessage(subscription).Result;
-            expected = $"Setting {subscription}";
-            Assert.IsTrue(reply.StartsWith(expected));
+
+            var step1 = new BotTestCase()
+            {
+                Action = "select subscription",
+                ExpectedReply = "Please select the subscription",
+                ErrorMessageHandler = errorMessageHandler
+            };
+
+            var step2 = new BotTestCase()
+            {
+                Action = subscription,
+                ExpectedReply = $"Setting {subscription}",
+                ErrorMessageHandler = errorMessageHandler
+            };
+
+            var steps = new List<BotTestCase> { step1, step2 };
+
+            TestRunner.RunTestCases(steps).Wait();
         }

         // Will run after all the tests have finished


支持Gravatar头像

支持Gravatar头像

--- website/SDNUOJ/Views/User/Info.cshtml
+++ website/SDNUOJ/Views/User/Info.cshtml
@@ -16,55 +16,64 @@

Information

+

+

+                    @{var emailMd5 = @SDNUOJ.Utilities.Security.MD5Encrypt.EncryptToHexString(Model.Item1.Email, false);}
+                    @*使用Gravatar头像*@
+
+
+

+

+
+                        @Html.Raw(Model.Item1.NickName)@*!TIP:User.NickName添加时已Encode*@
+                        @Html.Raw(SDNUOJ.Configuration.ConfigurationManager.AllowUserMail ? "(@" + Model.Item1.UserName + ")" : "")
+

+                    @if (Model.Item1.Permission > SDNUOJ.Entity.PermissionType.None)
+                    {Group: @Model.Item1.Permission.ToString()
}
+                    Rank: @Model.Item1.Rank,
+                    Solved: @Html.ActionLink(Model.Item1.SolvedCount.ToString(), "List", "Status", new { name = Model.Item1.UserName, type = (Byte)SDNUOJ.Entity.ResultType.Accepted }, null),
+                    Submissions: @Html.ActionLink(Model.Item1.SubmitCount.ToString(), "List", "Status", new { name = Model.Item1.UserName }, null),
+                    Ratio: @Model.Item1.Ratio.ToString("F2")%

+
+
+                            from:@(!String.IsNullOrEmpty(Model.Item1.School) ? Model.Item1.School : "Unknown") ,
+                            registered on @Model.Item1.CreateDate.ToString("yyyy-MM-dd")
+
+
+

+

+

+

+
Solved problems

+

+

-
-                @Html.Raw(Model.Item1.NickName)@*!TIP:User.NickName添加时已Encode*@
-                @Html.Raw(SDNUOJ.Configuration.ConfigurationManager.AllowUserMail ? "(@" + Model.Item1.UserName + ")" : "")
-

-            @if (Model.Item1.Permission > SDNUOJ.Entity.PermissionType.None) { Group: @Model.Item1.Permission.ToString()
 }
-            Rank: @Model.Item1.Rank,
-            Solved: @Html.ActionLink(Model.Item1.SolvedCount.ToString(), "List", "Status", new { name = Model.Item1.UserName, type = (Byte)SDNUOJ.Entity.ResultType.Accepted }, null),
-            Submissions: @Html.ActionLink(Model.Item1.SubmitCount.ToString(), "List", "Status", new { name = Model.Item1.UserName }, null),
-            Ratio: @Model.Item1.Ratio.ToString("F2")%

-
-
-                    from:@(!String.IsNullOrEmpty(Model.Item1.School) ? Model.Item1.School : "Unknown") ,
-                    registered on @Model.Item1.CreateDate.ToString("yyyy-MM-dd")
-
-
+                @for (Int32 i = 0; i < Model.Item2.Count; i++)
+                {
+                    @Html.ActionLink(Model.Item2[i].ToString(), "List", "Status", new { name = Model.Item1.UserName, pid = Model.Item2[i], type = (Byte)SDNUOJ.Entity.ResultType.Accepted }, null);
+                    @:
+                }
+                @if (Model.Item2.Count == 0)
+                {
+                    @: No solved problems
+                }
+

+

+

+
Unsolved problems

+

+

+

+                @for (Int32 i = 0; i < Model.Item3.Count; i++)
+                {
+                    @Html.ActionLink(Model.Item3[i].ToString(), "List", "Status", new { name = Model.Item1.UserName, pid = Model.Item3[i] }, null);
+                    @:
+                }
+                @if (Model.Item3.Count == 0)
+                {
+                    @: No unsolved problems
+                }
+

-

-
Solved problems

-

-

-

-            @for (Int32 i = 0; i < Model.Item2.Count; i++)
-            {
-                @Html.ActionLink(Model.Item2[i].ToString(), "List", "Status", new { name = Model.Item1.UserName, pid = Model.Item2[i], type = (Byte)SDNUOJ.Entity.ResultType.Accepted }, null);
-                @:
-            }
-            @if (Model.Item2.Count == 0)
-            {
-                @: No solved problems
-            }
-

-

-

-
Unsolved problems

-

-

-

-            @for (Int32 i = 0; i < Model.Item3.Count; i++)
-            {
-                @Html.ActionLink(Model.Item3[i].ToString(), "List", "Status", new { name = Model.Item1.UserName, pid = Model.Item3[i] }, null);
-                @:
-            }
-            @if (Model.Item3.Count == 0)
-            {
-                @: No unsolved problems
-            }
-

-

-


-fixed result order using own Timestamp (total time != laptime sum "problem")

-giving both collision events incident points for every event (carid order problem)
-broadcasting collision event (will probably be disabled in release)

--- AC_SessionReportPlugin/ReportPlugin.cs
+++ AC_SessionReportPlugin/ReportPlugin.cs
@@ -131,7 +131,7 @@
                             int winnerlapcount = 0;
                             int winnertime = 0;
                             // might be incorrect for players connected after race started
-                            foreach (DriverReport connection in this.currentSession.Connections.OrderByDescending(d => d.LapCount).ThenBy(d => d.TotalTime))
+                            foreach (DriverReport connection in this.currentSession.Connections.OrderByDescending(d => d.LapCount).ThenBy(d => this.currentSession.Laps.Where(l=> l.ConnectionId == d.ConnectionId && l.LapNo == d.LapCount).First().TimeStamp))
                             {
                                 if (position == 1)
                                 {
@@ -343,12 +343,13 @@
                     DriverReport driver = carUsedByDictionary[msg.CarId];
                     bool withOtherCar = msg.Subtype == (byte)ACSProtocol.MessageType.ACSP_CE_COLLISION_WITH_CAR;

-                    driver.Incidents += withOtherCar ? 4 : 2; // TODO only if relVel > thresh
+                    driver.Incidents += withOtherCar ? 2 : 1; // TODO only if relVel > thresh

                     DriverReport driver2 = null;
                     if (withOtherCar)
                     {
                         driver2 = carUsedByDictionary[msg.OtherCarId];
+                        driver2.Incidents += 2; // TODO only if relVel > thresh
                     }

                     currentSession.Events.Add(new IncidentReport()
@@ -362,7 +363,10 @@
                         RelPosition = ToSingle3(msg.RelativePosition),
                     });

-                    //this.BroadcastChatMessage(string.Format("Collision Relative Velocity: {0}", msg.RelativeVelocity));
+                    if (withOtherCar)
+                    {
+                        this.BroadcastChatMessage(string.Format("Collision between {0} and {1} with {2}km/h", driver.Name, driver2.Name, msg.RelativeVelocity));
+                    }
                 }
                 catch (Exception ex)
                 {


Tables on confirmation page

Tables on confirmation page

--- Anlab.Mvc/Views/Order/Confirmed.cshtml
+++ Anlab.Mvc/Views/Order/Confirmed.cshtml
@@ -71,35 +71,62 @@
          }
          else
          {
-

-
New Client Info

-            Client Name:
-            @Model.OrderDetails.ClientInfo.Name
-

-            Employer:
-            @Model.OrderDetails.ClientInfo.Employer
-

-             Department/Unit:
-             @Model.OrderDetails.ClientInfo.Department
-

-            Email:
-            @Model.OrderDetails.ClientInfo.Email
-

-            Phone Number:
-             @Model.OrderDetails.ClientInfo.PhoneNumber
-

-             PI Name:
-             @Model.OrderDetails.ClientInfo.PiName
-

-             PI Email:
-             @Model.OrderDetails.ClientInfo.PiEmail
-

+

+
New Client Info:

+

+

+

+

+                             Client Name
+                             @Model.OrderDetails.ClientInfo.Name
+

+

+                             Employer
+                             @Model.OrderDetails.ClientInfo.Employer
+

+

+                             Department/Unit
+                             @Model.OrderDetails.ClientInfo.Department
+

+

+                             Email
+                             @Model.OrderDetails.ClientInfo.Email
+

+

+                             Phone Number
+                             @Model.OrderDetails.ClientInfo.PhoneNumber
+

+

+                             PI Name
+                             @Model.OrderDetails.ClientInfo.PiName
+

+

+                             PI Email
+                             @Model.OrderDetails.ClientInfo.PiEmail
+

+

+

+

          }

-
Submitter Info:

-              Name: @Model.Order.Creator.Name

-              Email: @Model.Order.Creator.Email

-              Phone: @Model.Order.Creator.Phone
+
Submitter Info:

+

+

+

+

+                         Name
+                         @Model.Order.Creator.Name
+

+

+                         Email
+                         @Model.Order.Creator.Email
+

+

+                         Phone
+                         @Model.Order.Creator.Phone
+

+

+

               Payment Method:


Update

Update

--- Assets/[0]Framework/LibMono/Storage.cs
+++ Assets/[0]Framework/LibMono/Storage.cs
@@ -176,7 +176,7 @@

         public bool TryGet(int entityID, out T val)
         {
-            if (entityID >= length)
+            if (entityID >= length || !entityHasComponent[entityID])
             {
                 val = default(T);
                 return false;


Reverted to old, dumb Linq request temporarily

--- CodeCur/CodeCur/Services/NavService.cs
+++ CodeCur/CodeCur/Services/NavService.cs
@@ -22,20 +22,20 @@

         public static IEnumerable<Project> GetUserProjects(string ID)
         {
-            var userProjectIds = (from PP in _db.UserProjectRelations where PP.UserID == ID select PP.ID).ToList();
+            /*var userProjectIds = (from PP in _db.UserProjectRelations where PP.UserID == ID select PP.ID).ToList();

-            List<Project> Projects = new List<Project>();
+            List<Project> projects = new List<Project>();

             foreach (var idnum in userProjectIds)
             {
-                Projects.Add(
+                projects.Add(
                     (from prj in _db.Projects where prj.ID == idnum select prj).FirstOrDefault());
-            }
+            }*/

-            //IEnumerable<Project> projects = (from project in _db.Projects
-            //                                 where project.UserID == ID
-            //                                 select project).ToList();
-            return Projects;
+            IEnumerable<Project> projects = (from project in _db.Projects
+                                             where project.UserID == ID
+                                             select project).ToList();
+            return projects;
         }

         /*


Changed RiakMapReduce ctor to initialize MapReducePhases with Dictionary<string, IRiakMapReducePhase>

Former-commit-id: 0b449ceaca5e3c078481637913ed44afe7f7037a

--- CorrugatedIron/Models/RiakMapReduce.cs
+++ CorrugatedIron/Models/RiakMapReduce.cs
@@ -35,6 +35,12 @@

     public class RiakMapReduce
     {
+        public RiakMapReduce()
+        {
+            MapReducePhases = new Dictionary<string, IRiakMapReducePhase>();
+            Filters = new List<IRiakKeyFilterToken>();
+        }
+
         public List<IRiakKeyFilterToken> Filters { get; set; }
         public Dictionary<string, IRiakMapReducePhase> MapReducePhases { get; set; }

@@ -45,14 +51,7 @@
         // This could be exposed via the client interface as part of a configuration object
         public string ContentType { get; set; }

-        public RiakMapReduce()
-        {
-            MapReducePhases = new Dictionary<string, RiakMapReducePhase>();
-            Filters = new List<IRiakKeyFilterToken>();
-        }
-
         // TODO create and implement Bucket class
-

         /// <summary>
         /// Set the inputs property of the MapReduce job to a single bucket
@@ -179,7 +178,7 @@

                     jw.WriteEndObject();
                 }
-
+
                 Request = sb.ToString();
             }

@@ -198,7 +197,7 @@
             var phase = new RiakMapReducePhase
                             {
                                 MapReducePhaseType = mapReducePhaseType,
-                                MapReduceLanguage =  language,
+                                MapReduceLanguage = language,
                                 Keep = keep,
                                 Source = source,
                                 Name = name,


pseudo implementation on AsyncEnumerable implementation.

--- LanguageFeaturesCs7/CS8AsyncStreams.cs
+++ LanguageFeaturesCs7/CS8AsyncStreams.cs
@@ -21,21 +21,22 @@

     public class TestAsyncList : IAsyncEnumerable<Person>, IAsyncEnumerator<Person>
     {
-        public Person Current => throw new NotImplementedException();
+        public Person Current => new Person();

         public ValueTask DisposeAsync()
         {
-            throw new NotImplementedException();
+            // Nothing to dispose
+            return new ValueTask();
         }

         public IAsyncEnumerator<Person> GetAsyncEnumerator(CancellationToken cancellationToken = default)
         {
-            throw new NotImplementedException();
+            return this;
         }

         public ValueTask<bool> MoveNextAsync()
         {
-            throw new NotImplementedException();
+            return new ValueTask<bool>(false);
         }
     }
 	public class Person


Simplify Last4Digits setter/getter

Simplify Last4Digits setter/getter

--- MaxMind.MinFraud/Request/CreditCard.cs
+++ MaxMind.MinFraud/Request/CreditCard.cs
@@ -134,14 +134,10 @@
         [JsonIgnore]
         public string? Last4Digits
         {
-            get => _lastDigits;
-            init
-            {
-                if (value != null && !LastDigitsRe.IsMatch(value))
-                {
-                    throw new ArgumentException($"The last credit card digits {value} is of the wrong format.");
-                }
-                _lastDigits = value;
+            get => LastDigits;
+            init
+            {
+                LastDigits = value;
             }
         }


Add debug code for attach kill test

Add debug code for attach kill test

--- MedallionShell.Tests/AttachingTests.cs
+++ MedallionShell.Tests/AttachingTests.cs
@@ -63,6 +63,12 @@
                 .ShouldEqual(true, "Attaching to process failed.");

             attachedCommand.Kill();
+
+            // TODO CHANGE
+            var now = DateTime.UtcNow;
+            attachedCommand.Task.Wait(11000);
+            Console.WriteLine($"Died after {DateTime.UtcNow - now}");
+
             attachedCommand.Process.HasExited
                 .ShouldEqual(true, "The process is still alive after Kill() has finished.");
         }


Removed explicit settings for socket buffer sizes.

--- Naiad/Runtime/Networking/Networking.cs
+++ Naiad/Runtime/Networking/Networking.cs
@@ -736,8 +736,6 @@
                     this.connections[destProcessID].SendSocket.NoDelay = true;
                 }

-                this.connections[destProcessID].SendSocket.SendBufferSize = MAX_SEND_SIZE;
-
                 try
                 {
                     this.connections[destProcessID].SendSocket.Connect(this.connections[destProcessID].EndPoint);
@@ -787,8 +785,7 @@
             {
                 socket.NoDelay = true;
             }
-            socket.SendBufferSize = MAX_SEND_SIZE;
-
+
             if (this.Controller.Configuration.KeepAlives)
             {
                 socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
@@ -913,10 +910,6 @@
             {
                 socket.NoDelay = true;
             }
-
-            socket.ReceiveBufferSize = MAX_SEND_SIZE;
-            //this.connections[peerID].Socket.ReceiveBufferSize = 1 << 20;
-            //this.connections[peerID].Socket.SendBufferSize = 1 << 20;

             long numRecvs = 0;


--- CSharp/Method/Internal.cs
+++ CSharp/Method/Internal.cs
@@ -1,11 +1,8 @@
 public class Tricycle {
     //só pode ser acessado por tipos dentro da DLL
     internal void Pedal() { }
-    private int wheels = 3;
-
     //pode ser acessado por uma classe qualquer que derive desta, ou tipos desta DLL.
-    protected internal int Wheels {
-        get { return wheels; }
+    protected internal int Wheels => { get; } => 3
     }
 }