Inventory Fixes (#1634)

Inventory Fixes (#1634)

* Inventory Fixes

Fix the merge exploit.

Remove some broadcast messages on errors that weren't needed

Fixed an issue when picking up and merging a partial stack using the R key.

* Make sure the stacks being merged from haven't moved

* I like this better

* Fix exception when two players try to pick up the same item.

* Make sure merge source/target are compatible

* Debug messages added to help detect possible duping

Note that these instances can occur normally under regular gameplay and do not necessarily mean it was a duping attempt.

--- Source/ACE.Server/WorldObjects/Player_Inventory.cs
+++ Source/ACE.Server/WorldObjects/Player_Inventory.cs
@@ -632,19 +632,33 @@
                         return;
                     }

-                    var returnStance = new Motion(CurrentMotionState.Stance);
-
                     if (!success)
                     {
                         Session.Network.EnqueueSend(new GameEventInventoryServerSaveFailed(Session, itemGuid, WeenieError.ActionCancelled));
-                        EnqueueBroadcastMotion(returnStance);
                         return;
                     }

+                    // Was this item picked up by someone else?
+                    if (itemRootOwner == null && item.CurrentLandblock == null)
+                    {
+                        Session.Network.EnqueueSend(new GameEventInventoryServerSaveFailed(Session, itemGuid, WeenieError.ActionCancelled));
+                        return;
+                    }
+
                     var pickupChain = AddPickupChainToMoveToChain(itemRootOwner, container);

                     pickupChain.AddAction(this, () =>
                     {
+                        var returnStance = new Motion(CurrentMotionState.Stance);
+
+                        // Was this item picked up by someone else?
+                        if (itemRootOwner == null && item.CurrentLandblock == null)
+                        {
+                            Session.Network.EnqueueSend(new GameEventInventoryServerSaveFailed(Session, itemGuid, WeenieError.ActionCancelled));
+                            EnqueueBroadcastMotion(returnStance);
+                            return;
+                        }
+
                         var questSolve = false;

                         if (itemRootOwner != this && containerRootOwner == this && item.Quest != null) // We're picking up a quest item
@@ -690,6 +704,7 @@
                                     QuestManager.Update(item.Quest);
                             }
                         }
+
                         EnqueueBroadcastMotion(returnStance);
                     });

@@ -883,19 +898,33 @@
                         return;
                     }

-                    var returnStance = new Motion(CurrentMotionState.Stance);
-
                     if (!success)
                     {
                         Session.Network.EnqueueSend(new GameEventInventoryServerSaveFailed(Session, itemGuid, WeenieError.ActionCancelled));
-                        EnqueueBroadcastMotion(returnStance);
                         return;
                     }

+                    // Was this item picked up by someone else?
+                    if (rootOwner == null && item.CurrentLandblock == null)
+                    {
+                        Session.Network.EnqueueSend(new GameEventInventoryServerSaveFailed(Session, itemGuid, WeenieError.ActionCancelled));
+                        return;
+                    }
+
                     var pickupChain = AddPickupChainToMoveToChain(rootOwner, this);

                     pickupChain.AddAction(this, () =>
                     {
+                        var returnStance = new Motion(CurrentMotionState.Stance);
+
+                        // Was this item picked up by someone else?
+                        if (rootOwner == null && item.CurrentLandblock == null)
+                        {
+                            Session.Network.EnqueueSend(new GameEventInventoryServerSaveFailed(Session, itemGuid, WeenieError.ActionCancelled));
+                            EnqueueBroadcastMotion(returnStance);
+                            return;
+                        }
+
                         if (DoHandleActionGetAndWieldItem(item, rootOwner, wasEquipped, wieldedLocation))
                         {
                             Session.Network.EnqueueSend(new GameMessagePrivateUpdatePropertyInt(this, PropertyInt.EncumbranceVal, EncumbranceVal ?? 0));
@@ -905,6 +934,7 @@
                             item.EmoteManager.OnPickup(this);
                             item.NotifyOfEvent(RegenerationType.PickUp);
                         }
+
                         EnqueueBroadcastMotion(returnStance);
                     });

@@ -1197,9 +1227,6 @@
                 return;
             }

-            var newStack = WorldObjectFactory.CreateNewWorldObject(stack.WeenieClassId);
-            newStack.SetStackSize(amount);
-
             if ((stackRootOwner == this && containerRootOwner != this)  || (stackRootOwner != this && containerRootOwner == this)) // Movement is between the player and the world
             {
                 WorldObject moveToObject;
@@ -1209,6 +1236,8 @@
                 else
                     moveToObject = stackRootOwner ?? stack;

+                var stackOriginalContainer = stack.ContainerId;
+
                 CreateMoveToChain(moveToObject, (success) =>
                 {
                     if (CurrentLandblock == null) // Maybe we were teleported as we were motioning to split the item
@@ -1222,14 +1251,35 @@
                     if (!success)
                     {
                         Session.Network.EnqueueSend(new GameEventInventoryServerSaveFailed(Session, stackId, WeenieError.ActionCancelled));
-                        EnqueueBroadcastMotion(returnStance);
                         return;
                     }

+                    // We make sure the stack is still valid. It could have changed during our movement
+                    if (stackOriginalContainer != stack.ContainerId || stack.StackSize < amount)
+                    {
+                        log.DebugFormat("Player 0x{0:X8}:{1} tried to split an item that's no longer valid 0x{2:X8}:{3}.", Guid.Full, Name, stack.Guid.Full, stack.Name);
+                        Session.Network.EnqueueSend(new GameEventCommunicationTransientString(Session, "Split failed!")); // Custom error message
+                        Session.Network.EnqueueSend(new GameEventInventoryServerSaveFailed(Session, stackId, WeenieError.ActionCancelled));
+                        return;
+                    }
+
                     var pickupChain = AddPickupChainToMoveToChain(stackRootOwner, containerRootOwner);

                     pickupChain.AddAction(this, () =>
                     {
+                        // We make sure the stack is still valid. It could have changed during our pickup animation
+                        if (stackOriginalContainer != stack.ContainerId || stack.StackSize < amount)
+                        {
+                            log.DebugFormat("Player 0x{0:X8}:{1} tried to split an item that's no longer valid 0x{2:X8}:{3}.", Guid.Full, Name, stack.Guid.Full, stack.Name);
+                            Session.Network.EnqueueSend(new GameEventCommunicationTransientString(Session, "Split failed!")); // Custom error message
+                            Session.Network.EnqueueSend(new GameEventInventoryServerSaveFailed(Session, stackId, WeenieError.ActionCancelled));
+                            EnqueueBroadcastMotion(returnStance);
+                            return;
+                        }
+
+                        var newStack = WorldObjectFactory.CreateNewWorldObject(stack.WeenieClassId);
+                        newStack.SetStackSize(amount);
+
                         if (DoHandleActionStackableSplitToContainer(stack, stackFoundInContainer, stackRootOwner, container, containerRootOwner, newStack, placementPosition, amount))
                         {
                             Session.Network.EnqueueSend(new GameMessagePrivateUpdatePropertyInt(this, PropertyInt.EncumbranceVal, EncumbranceVal ?? 0));
@@ -1251,6 +1301,9 @@
             }
             else // This is a self-contained movement
             {
+                var newStack = WorldObjectFactory.CreateNewWorldObject(stack.WeenieClassId);
+                newStack.SetStackSize(amount);
+
                 DoHandleActionStackableSplitToContainer(stack, stackFoundInContainer, stackRootOwner, container, containerRootOwner, newStack, placementPosition, amount);
             }
         }
@@ -1368,7 +1421,7 @@
         /// This is raised when we:
         /// - try to merge two stacks stack in the same container
         /// - try to merge two stacks stack in different container
-        /// - try to merge a stack fron the landblock into a container
+        /// - try to merge a stack from the landblock into a container
         /// - try to split a stack into a different container that has a stack that can support a merge
         /// </summary>
         public void HandleActionStackableMerge(uint mergeFromGuid, uint mergeToGuid, int amount)
@@ -1401,6 +1454,14 @@
             {
                 Session.Network.EnqueueSend(new GameEventCommunicationTransientString(Session, "Target stack not found!")); // Custom error message
                 Session.Network.EnqueueSend(new GameEventInventoryServerSaveFailed(Session, mergeFromGuid));
+                return;
+            }
+
+            if (sourceStack.WeenieClassId != targetStack.WeenieClassId)
+            {
+                log.WarnFormat("Player 0x{0:X8}:{1} tried to merge different items 0x{2:X8}:{3} and 0x{4:X8}:{5}.", Guid.Full, Name, sourceStack.Guid.Full, sourceStack.Name, targetStack.Guid.Full, targetStack.Name);
+                Session.Network.EnqueueSend(new GameEventCommunicationTransientString(Session, "Stacks not compatible!")); // Custom error message
+                Session.Network.EnqueueSend(new GameEventInventoryServerSaveFailed(Session, mergeFromGuid, WeenieError.YouCannotMergeDifferentStacks));
                 return;
             }

@@ -1437,6 +1498,8 @@
                 else
                     moveToObject = sourceStackRootOwner ?? sourceStack;

+                var sourceStackOriginalContainer = sourceStack.ContainerId;
+
                 CreateMoveToChain(moveToObject, (success) =>
                 {
                     if (CurrentLandblock == null) // Maybe we were teleported as we were motioning to split the item
@@ -1450,16 +1513,38 @@
                     if (!success)
                     {
                         Session.Network.EnqueueSend(new GameEventInventoryServerSaveFailed(Session, mergeFromGuid, WeenieError.ActionCancelled));
-                        EnqueueBroadcastMotion(returnStance);
                         return;
                     }

+                    // We make sure the stack is still valid. It could have changed during our movement
+                    if (sourceStackOriginalContainer != sourceStack.ContainerId || sourceStack.StackSize < amount)
+                    {
+                        log.DebugFormat("Player 0x{0}:{1} tried to merge an item that's no longer valid 0x{2:X8}:{3}.", Guid.Full, Name, sourceStack.Guid.Full, sourceStack.Name);
+                        Session.Network.EnqueueSend(new GameEventCommunicationTransientString(Session, "Merge Failed!")); // Custom error message
+                        Session.Network.EnqueueSend(new GameEventInventoryServerSaveFailed(Session, mergeFromGuid, WeenieError.ActionCancelled));
+                        return;
+                    }
+
                     var pickupChain = AddPickupChainToMoveToChain(sourceStackRootOwner, targetStackRootOwner);

                     pickupChain.AddAction(this, () =>
                     {
+                        // We make sure the stack is still valid. It could have changed during our pickup animation
+                        if (sourceStackOriginalContainer != sourceStack.ContainerId || sourceStack.StackSize < amount)
+                        {
+                            log.DebugFormat("Player 0x{0}:{1} tried to merge an item that's no longer valid 0x{2:X8}:{3}.", Guid.Full, Name, sourceStack.Guid.Full, sourceStack.Name);
+                            Session.Network.EnqueueSend(new GameEventCommunicationTransientString(Session, "Merge Failed!")); // Custom error message
+                            Session.Network.EnqueueSend(new GameEventInventoryServerSaveFailed(Session, mergeFromGuid, WeenieError.ActionCancelled));
+                            EnqueueBroadcastMotion(returnStance);
+                            return;
+                        }
+
                         if (DoHandleActionStackableMerge(sourceStack, sourceStackFoundInContainer, sourceStackRootOwner, targetStack, targetStackFoundInContainer, targetStackRootOwner, amount))
                         {
+                            // If the client used the R key to merge a partial stack from the landscape, it also tries to add the "ghosted" item of the picked up stack to the inventory as well.
+                            if (sourceStackRootOwner != this && sourceStack.StackSize > 0)
+                                Session.Network.EnqueueSend(new GameMessageCreateObject(sourceStack));
+
                             Session.Network.EnqueueSend(new GameMessagePrivateUpdatePropertyInt(this, PropertyInt.EncumbranceVal, EncumbranceVal ?? 0));

                             if (sourceStack.WeenieType == WeenieType.Coin)


Fix issue where Shade was not being properly set on items given from emote (#3663)

--- Source/ACE.Server/WorldObjects/Player_Inventory.cs
+++ Source/ACE.Server/WorldObjects/Player_Inventory.cs
@@ -3330,7 +3330,7 @@

                     if (palette > 0)
                         item.PaletteTemplate = palette;
-                    if (item.Shade > 0)
+                    if (shade > 0)
                         item.Shade = shade;

                     TryCreateForGive(emoter, item);


#367 - building ReasonForFailure with string.Format, not Concat Per inspection comments in #381.

--- Source/FakeItEasy/Creation/ProxyGeneratorResult.cs
+++ Source/FakeItEasy/Creation/ProxyGeneratorResult.cs
@@ -44,16 +44,14 @@
                 exception = exception.InnerException;
             }

-            this.ReasonForFailure = string.Concat(
-                reasonForFailure,
-                Environment.NewLine,
-                "An exception of type ",
-                exception.GetType(),
-                " was caught during this call. Its message was:",
-                Environment.NewLine,
-                exception.Message,
-                Environment.NewLine,
-                exception.StackTrace);
+            this.ReasonForFailure =
+                string.Format(
+                    "{0}{1}An exception of type {2} was caught during this call. Its message was:{1}{3}{1}{4}",
+                    reasonForFailure,
+                    Environment.NewLine,
+                    exception.GetType(),
+                    exception.Message,
+                    exception.StackTrace);
         }

         /// <summary>


develop: removed unneccesary multiplication in the minheap

--- Source/Code/Pathfindax/Collections/MinHeap.cs
+++ Source/Code/Pathfindax/Collections/MinHeap.cs
@@ -43,7 +43,7 @@
 			while (true)
 			{
 				var childIndexLeft = item.HeapIndex * 2 + 1;
-				var childIndexRight = item.HeapIndex * 2 + 2;
+				var childIndexRight = childIndexLeft + 1;

 				if (childIndexLeft < Count)
 				{


Add missing XML comment

Add missing XML comment

--- Source/Csla.Shared/Security/PrincipalCache.cs
+++ Source/Csla.Shared/Security/PrincipalCache.cs
@@ -20,6 +20,9 @@
     private static List<IPrincipal> _cache = new List<IPrincipal>();

     private static int _maxCacheSize;
+    /// <summary>
+    /// Gets the maximum cache size
+    /// </summary>
     public static int MaxCacheSize
     {
       get


とりあえず最初のオブジェクトに注目しとく

とりあえず最初のオブジェクトに注目しとく

--- WPFTests/MapIOTest.xaml.cs
+++ WPFTests/MapIOTest.xaml.cs
@@ -1,5 +1,6 @@
 using System;
 using System.IO;
+using System.Linq;
 using System.Windows;
 using System.Windows.Controls;
 using System.Windows.Input;
@@ -84,6 +85,7 @@
                 })
                 {
                     Canvas = canvas,
+                    FocusTo = map.GetMapObjects().FirstOrDefault()
                 };
                 textBlockError.Text = "";
             }


Check null

Check null

--- WalletWasabi.Gui/Global.cs
+++ WalletWasabi.Gui/Global.cs
@@ -410,7 +410,10 @@
 				Logger.LogInfo("WalletService started.");
 			}
 			CancelWalletServiceInitialization = null; // Must make it null explicitly, because dispose won't make it null.
-			WalletService.Coins.CollectionChanged += Coins_CollectionChanged;
+			if (WalletService?.Coins != null)
+			{
+				WalletService.Coins.CollectionChanged += Coins_CollectionChanged;
+			}
 		}

 		public static string GetWalletFullPath(string walletName)


admin_startRpc

--- Source/EthereumGethRpc/Api/GethRpcAdminApi.cs
+++ Source/EthereumGethRpc/Api/GethRpcAdminApi.cs
@@ -64,7 +64,6 @@
         public async Task<bool> StartRpcAsync(string host="localhost",string port="8545",string cors="",string apis = "eth,net,web3")
         {
             string rpcReq = BuildRpcRequest("admin_startRpc", host, port, cors, apis);
-
             return await ExecuteRpcRequestAsync<bool>(rpcReq);
         }
     }


Add null check to ViewProvider of NavigationFrame

--- Source/Kamishibai.Wpf.View/NavigationFrame.cs
+++ Source/Kamishibai.Wpf.View/NavigationFrame.cs
@@ -22,7 +22,11 @@

     internal IViewProvider ViewProvider
     {
-        get => _viewProvider!;
+        get
+        {
+            if (_viewProvider is null) throw new InvalidOperationException("ViewProvider is not initialized.");
+            return _viewProvider!;
+        }
         set => _viewProvider = value;
     }


GSF.Web: Updated HTTP handler processing to not cache content cache since web server will not know when content has changed. Handler can cache value as an optimization.

--- Source/Libraries/GSF.Web/Hosting/WebServer.cs
+++ Source/Libraries/GSF.Web/Hosting/WebServer.cs
@@ -327,16 +327,7 @@

             if (ClientCacheEnabled && handler.UseClientCache)
             {
-                long responseHash;
-
-                if (!m_etagCache.TryGetValue(fileName, out responseHash))
-                {
-                    responseHash = handler.GetContentHash(request);
-                    m_etagCache.TryAdd(fileName, responseHash);
-                    OnStatusMessage($"Cache [{responseHash}] added for file \"{fileName}\"");
-                }
-
-                if (PublishResponseContent(request, response, responseHash))
+                if (PublishResponseContent(request, response, handler.GetContentHash(request)))
                     await handler.ProcessRequestAsync(request, response);
             }
             else


PlotModel legends use DefaultFont if LegendFont is not set

--- Source/OxyPlot/PlotModel/PlotModel.Legends.cs
+++ Source/OxyPlot/PlotModel/PlotModel.Legends.cs
@@ -48,11 +48,11 @@
             {
                 OxySize titleSize;
                 if (measureOnly)
-                    titleSize = rc.MeasureMathText(LegendTitle, LegendTitleFont, LegendTitleFontSize, LegendTitleFontWeight);
+                    titleSize = rc.MeasureMathText(LegendTitle, LegendTitleFont ?? DefaultFont, LegendTitleFontSize, LegendTitleFontWeight);
                 else
                     titleSize = rc.DrawMathText(new ScreenPoint(rect.Left + x, rect.Top + top),
                                 LegendTitle, TextColor,
-                                LegendTitleFont, LegendTitleFontSize, LegendTitleFontWeight, 0, HorizontalTextAlign.Left,
+                                LegendTitleFont ?? DefaultFont, LegendTitleFontSize, LegendTitleFontWeight, 0, HorizontalTextAlign.Left,
                                 VerticalTextAlign.Top, true);
                 top += titleSize.Height;
                 size.Width = x + titleSize.Width + LegendPadding;
@@ -70,7 +70,7 @@
             {
                 if (String.IsNullOrEmpty(s.Title))
                     continue;
-                var textSize = rc.MeasureMathText(s.Title, LegendFont, LegendFontSize, LegendFontWeight);
+                var textSize = rc.MeasureMathText(s.Title, LegendFont ?? DefaultFont, LegendFontSize, LegendFontWeight);
                 double itemWidth = LegendSymbolLength + LegendSymbolMargin + textSize.Width;
                 double itemHeight = textSize.Height;

@@ -162,7 +162,7 @@
                 x += LegendSymbolLength + LegendSymbolMargin;

             var textSize = rc.DrawMathText(new ScreenPoint(x, rect.Top), s.Title, TextColor,
-                                               LegendFont, LegendFontSize, LegendFontWeight, 0,
+                                               LegendFont ?? DefaultFont, LegendFontSize, LegendFontWeight, 0,
                                                LegendItemAlignment, VerticalTextAlign.Top, true);
             double x0 = x;
             switch (LegendItemAlignment)


Added NoRows to Grid

Added NoRows to Grid

--- Aras.ViewModel/Grid.cs
+++ Aras.ViewModel/Grid.cs
@@ -45,6 +45,44 @@

         [Attributes.Property("Rows")]
         public Model.ObservableList<Row> Rows {get; private set;}
+
+        public System.Int32 NoRows
+        {
+            get
+            {
+                return this.Rows.Count();
+            }
+            set
+            {
+                if (value >= 0)
+                {
+                    if (value == 0)
+                    {
+                        this.Rows.Clear();
+                    }
+                    else
+                    {
+                        if (value > this.Rows.Count())
+                        {
+                            Int32 diff = value - this.Rows.Count();
+
+                            for (int i=0; i < diff; i++)
+                            {
+                                this.AddRow();
+                            }
+                        }
+                        else if (value < this.Rows.Count())
+                        {
+                            this.Rows.RemoveRange(value, (this.Rows.Count() - value));
+                        }
+                    }
+                }
+                else
+                {
+                    throw new ArgumentException("Number of Rows must be greater than or equal to 0");
+                }
+            }
+        }

         public Row AddRow()
         {


Started development on v0.6.0.0

Started development on v0.6.0.0

--- AssemblyInfo.Global.cs
+++ AssemblyInfo.Global.cs
@@ -8,7 +8,7 @@
 [assembly: AssemblyCopyright("Copyright © 2015 1und1 Internet SE")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
-[assembly: AssemblyVersion("0.5.0.0")]
+[assembly: AssemblyVersion("0.6.0.0")]
 [assembly: ComVisible(false)]

 [assembly: InternalsVisibleTo("Dehydrator.UnitTests, PublicKey=002400000480000094000000060200000024000052534131000400000100010065be9ae8ce335904900434943dae20813bffdcda0a7c2a95ca78d64d0b645f2403086e71824a26e62e4a0e45400c45cf24cdba5010ba8476c5af6a6e931622ff924283bed343b0d756c62264840d77d97789c6ad21b24ca180ae878beabd5f21ad835c6c92618d505fed0ffd973b98199b921cab78c69a42b85ac5467d3aefc8")]


Simplified Game Camera

Simplified Game Camera

--- Assets/Scripts/Game.cs
+++ Assets/Scripts/Game.cs
@@ -2,14 +2,15 @@
 using System.Collections;

 public class Game : MonoBehaviour {
-
-	public Camera mainCamera;
+
 	public BoxCollider2D leftWall;
 	public BoxCollider2D rightWall;
 	public BoxCollider2D topWall;
 	public BoxCollider2D bottomWall;

 	void Start () {
+		Camera mainCamera = Camera.main;
+
 		topWall.size = new Vector2 (mainCamera.ScreenToWorldPoint (new Vector3 (Screen.width * 2f, 0f, 0f)).x, 1f);
 		topWall.center = new Vector2 (0f, mainCamera.ScreenToWorldPoint (new Vector3 (0f, Screen.height, 0f)).y + .5f);


Add check if data is null

Add check if data is null

--- Assets/Scripts/Wall.cs
+++ Assets/Scripts/Wall.cs
@@ -24,7 +24,9 @@

 		//Set spriteRenderer to the damaged wall sprite.
 		// TODO CHeck the sprite renderer
-//		spriteRenderer.sprite = dmgSprite;
+		if (spriteRenderer != null) {
+		spriteRenderer.sprite = dmgSprite;
+		}

 		//Subtract loss from hit point total.
 		hp -= loss;


fixed bug

fixed bug

--- Source/Mizu_Assembly/WorkGiver_DrawFromWaterNet.cs
+++ Source/Mizu_Assembly/WorkGiver_DrawFromWaterNet.cs
@@ -16,10 +16,10 @@
             var thing = giver as Thing;
             if (thing == null) return null;

-            var bwn = giver as IBuilding_WaterNet;
-            if (bwn == null || bwn.InputWaterNet == null) return null;
-            if (!recipe.needWaterTypes.Contains(bwn.InputWaterNet.WaterType)) return null;
-            if (bwn.InputWaterNet.StoredWaterVolume < recipe.needWaterVolume) return null;
+            var workTable = giver as Building_WaterNetWorkTable;
+            if (workTable == null) return null;
+            if (!recipe.needWaterTypes.Contains(workTable.StoredWaterType)) return null;
+            if (workTable.StoredWaterVolume < recipe.needWaterVolume) return null;

             return new Job(MizuDef.Job_DrawFromWaterNet, thing) { bill = bill };
         }


Set default timeout

Set default timeout

--- Web/ConsolRHandler.ashx.cs
+++ Web/ConsolRHandler.ashx.cs
@@ -77,7 +77,11 @@

 		static ExecuteEndPoint()
 		{
-			var timeout = int.Parse(ConfigurationManager.AppSettings["ConsolR.ExecutionTimeout"]);
+			int timeout;
+			if (!int.TryParse(ConfigurationManager.AppSettings["ConsolR.ExecutionTimeout"], out timeout))
+			{
+				timeout = 30;
+			};
 			ExecutionTimeout = TimeSpan.FromSeconds(timeout);
 		}


update version comment

update version comment

--- Assets/echoServerCS.cs
+++ Assets/echoServerCS.cs
@@ -7,12 +7,18 @@

 using NS_MyRs232cUtil;

+/*
+ * v0.1 2015/09/22
+ *   - can echo back
+ */
+
 public class echoServerCS : MonoBehaviour {

 	private static bool doStart = false;
 	private static bool doStop = false;
 	private Thread rcvThr;
-
+
+	public InputField IF_comname;
 	public Text T_status;
 	private SerialPort mySP;
 	private string accRcvd = "";
@@ -20,7 +26,7 @@
 	void Update () {
 		if (doStart) {
 			doStart = false;
-			bool res = MyRs232cUtil.Open ("COM3", out mySP);
+			bool res = MyRs232cUtil.Open (IF_comname.text, out mySP);
 			mySP.ReadTimeout = 1;
 			if (res == false) {
 				T_status.text = "open fail";


Variablennamen in AddinServer geändert

Variablennamen in AddinServer geändert

--- Addin/MasterModel/MasterModel/StandardAddInServer.cs
+++ Addin/MasterModel/MasterModel/StandardAddInServer.cs
@@ -40,7 +40,7 @@
         private UserInterfaceEvents m_userInterfaceEvents;

         // ribbon panel
-        RibbonPanel partSketchMasterRibbonPanel;
+        RibbonPanel partToolMasterRibbonPanel;

         //event handler delegates
         //to make changes in comandbar or enviroment ui
@@ -121,13 +121,13 @@

                         //add buttons to toolbar
                         MasterCommander.Controls.AddButton(ButtON.ButtonDefinition, 0);
-
+
                         //Get the 2d sketch environment base object
-                        Inventor.Environment partSketchEnvironment;
-                        partSketchEnvironment = userInterfaceManager.Environments["PMxPartSkEnvironment"];
-
-                        //make this command bar accessible in the panel menu for the 2d sketch environment.
-                        partSketchEnvironment.PanelBar.CommandBarList.Add(MasterCommander);
+                        Inventor.Environment partToolEnvironment;
+                        partToolEnvironment = userInterfaceManager.Environments["PMxPartSkEnvironment"];
+
+                        //make this command bar accessible in the panel menu for the Tool environment.
+                        partToolEnvironment.PanelBar.CommandBarList.Add(MasterCommander);
                     }
                     //create the UI for ribbon interface
                     else
@@ -139,26 +139,27 @@
                         Inventor.Ribbon partRibbon;
                         partRibbon = ribbons["Part"];

-                        //get the tabls associated with part ribbon
+                        //get the tabs associated with part ribbon
                         RibbonTabs ribbonTabs;
                         ribbonTabs = partRibbon.RibbonTabs;

-                        RibbonTab partSketchRibbonTab;
-                        partSketchRibbonTab = ribbonTabs["id_TabTools"];
+                        //get the Tool tab
+                        RibbonTab partToolRibbonTab;
+                        partToolRibbonTab = ribbonTabs["id_TabTools"];

                         //create a new panel with the tab
                         RibbonPanels ribbonPanels;
-                        ribbonPanels = partSketchRibbonTab.RibbonPanels;
-
-                        partSketchMasterRibbonPanel = ribbonPanels.Add("Master Model", "MasterModel:StandardAddInServer:BenjaminBUTTONRibbonPanel", "{DB59D9A7-EE4C-434A-BB5A-F93E8866E872}", "", false);
+                        ribbonPanels = partToolRibbonTab.RibbonPanels;
+
+                        partToolMasterRibbonPanel = ribbonPanels.Add("Master Model", "MasterModel:StandardAddInServer:BenjaminBUTTONRibbonPanel", "{DB59D9A7-EE4C-434A-BB5A-F93E8866E872}", "", false);

                         //add controls to the MasterModel panel
-                        CommandControls partSketchMasterRibbonPanelCtrls;
-                        partSketchMasterRibbonPanelCtrls = partSketchMasterRibbonPanel.CommandControls;
+                        CommandControls partToolMasterRibbonPanelCtrls;
+                        partToolMasterRibbonPanelCtrls = partToolMasterRibbonPanel.CommandControls;

                         //add the buttons to the ribbon panel
                         CommandControl MasterMoRiPaCtrl;
-                        MasterMoRiPaCtrl = partSketchMasterRibbonPanelCtrls.AddButton(ButtON.ButtonDefinition, false, true, "", false);
+                        MasterMoRiPaCtrl = partToolMasterRibbonPanelCtrls.AddButton(ButtON.ButtonDefinition, false, true, "", false);
                     }
                 }
             }
@@ -293,12 +294,12 @@
                 RibbonPanels ribbonPanels;
                 ribbonPanels = partSketchRibbonTab.RibbonPanels;

-                partSketchMasterRibbonPanel = ribbonPanels.Add("MasterModel", "MasterModel:StandardAddInServer:BenjaminBUTTONRibbonPanel",
+                partToolMasterRibbonPanel = ribbonPanels.Add("MasterModel", "MasterModel:StandardAddInServer:BenjaminBUTTONRibbonPanel",
                                                              "{DB59D9A7-EE4C-434A-BB5A-F93E8866E872}", "", false);

                 //add controls to the MasterModel panel
                 CommandControls partSketchMasterMoRiPaCtrl;
-                partSketchMasterMoRiPaCtrl = partSketchMasterRibbonPanel.CommandControls;
+                partSketchMasterMoRiPaCtrl = partToolMasterRibbonPanel.CommandControls;

                 //add the buttons to the ribbon panel
                 CommandControl MasterCommander;


fixed another issue with the foggy nodes

--- AiPathFinding/Algorithm/AbstractPathFindAlgorithm.cs
+++ AiPathFinding/Algorithm/AbstractPathFindAlgorithm.cs
@@ -182,9 +182,14 @@
             // try different fog nodes until an exit is found or we run out of options
             while (true)
             {
+                // add currently foggy nodes to all foggy nodes
+                _allFoggyNodes.AddRange(FoggyNodes);
+
                 // find possible foggy nodes to investigate
                 var foggyPossibilities = new List<Node>();
-                foggyPossibilities.AddRange(RemoveLonelyFoggyNodes(AbstractFogExploreAlgorithm.RemoveKnownFoggyNodes(FoggyNodes)));
+                foggyPossibilities.AddRange(AbstractFogExploreAlgorithm.RemoveKnownFoggyNodes(FoggyNodes));
+                var removableNodes = RemoveLonelyFoggyNodes(foggyPossibilities);
+                foggyPossibilities = foggyPossibilities.Except(removableNodes).ToList();
                 FoggyNodes.Clear();
                 FoggyNodes.AddRange(foggyPossibilities);

@@ -219,7 +224,7 @@
                 if (clearNodeWhereFogWasLeft == null)
                 {
                     // move from playernode to clearfavorite
-                    path = GetPath(playerNode, clearFavorite);
+                    path = GetPath(playerNode, clearFavorite).SubArray(1);
                 }
                 else
                 {
@@ -241,9 +246,6 @@
                 int[] pathCostData = null;
                 if (path.Length > 0)
                     pathCostData = MovePath(path, "Moving towards fog at " + foggyNode);
-
-                // add currently foggy nodes to all foggy nodes
-                _allFoggyNodes.AddRange(FoggyNodes);

                 // update cost of foggy node
                 AddCostToNode(foggyNode, PartialCost + foggyNode.Cost);
@@ -341,7 +343,7 @@
         /// <summary>
         /// Removes all foggy nodes where all neighbors are known or otherwise contained in the foggy node list
         /// </summary>
-        /// <param name="nodes">Collection of foggy nodes</param>
+        /// <param name="nodes">Collection of REMOVABLE nodes</param>
         /// <returns>Nodes without the ones that don't need to be investigated</returns>
         private IEnumerable<Node> RemoveLonelyFoggyNodes(IList<Node> nodes)
         {
@@ -373,7 +375,7 @@
             if (removedString != "")
                 Console.WriteLine("Removed nodes " + removedString.Substring(2) + " from foggy node list.");

-            return nodes;
+            return removedNodes;
         }

         /// <summary>


Delete deprecated events

Delete deprecated events

refs: https://developer.github.com/webhooks/

--- WebHook/WebHookFunction.cs
+++ WebHook/WebHookFunction.cs
@@ -50,8 +50,6 @@
             {
                 case "installation_repositories":
                 case "installation":
-                case "integration_installation_repositories":
-                case "integration_installation":
                     result = await ProcessInstallationAsync(hook, routerMessages, installationTable, logger);
                     break;
                 case "push":


Support for multiselect options sets

Support for multiselect options sets

--- AlexanderDevelopment.ConfigDataMover.Lib/Importer.cs
+++ AlexanderDevelopment.ConfigDataMover.Lib/Importer.cs
@@ -1128,6 +1128,17 @@
                                 jObject = (Newtonsoft.Json.Linq.JObject)exportAttribute.AttributeValue;
                                 attributeValue = new OptionSetValue { Value = (int)jObject["Value"] };
                                 break;
+                            //if it's a multiselectoptionset
+                            case "Microsoft.Xrm.Sdk.OptionSetValueCollection":
+                                jArray = (Newtonsoft.Json.Linq.JArray)exportAttribute.AttributeValue;
+
+                                OptionSetValueCollection multiOption = new OptionSetValueCollection { };
+                                foreach (var child in jArray.Children())
+                                {
+                                    multiOption.Add(new OptionSetValue { Value = (int)child["Value"] });
+                                }
+                                attributeValue = multiOption;
+                                break;
                             //if it's money
                             case "Microsoft.Xrm.Sdk.Money":
                                 jObject = (Newtonsoft.Json.Linq.JObject)exportAttribute.AttributeValue;


added better error logging

added better error logging

--- Sources/Agent/Controllers/DeployController.cs
+++ Sources/Agent/Controllers/DeployController.cs
@@ -77,6 +77,8 @@
             }
             catch (Exception e)
             {
+                logger.Log(e.InnerException != null ? e.InnerException.Message : e.Message, true);
+
                 return new ExecutionResult()
                 {
                     Success = false,
@@ -112,6 +114,7 @@
             }
             catch (Exception e)
             {
+                logger.Log(e.InnerException != null ? e.InnerException.Message : e.Message, true);
                 return new ExecutionResult()
                 {
                     Success = false,
@@ -148,6 +151,7 @@
             }
             catch (Exception e)
             {
+                logger.Log(e.InnerException != null ? e.InnerException.Message : e.Message, true);
                 return new ExecutionResult()
                 {
                     Success = false,


Added GetDecayMultiplier() method. Used to provide unified, predictable decay-math across forces and stick to DRY principle

--- SourceFiles/Controllers/AbstractForceController.cs
+++ SourceFiles/Controllers/AbstractForceController.cs
@@ -116,6 +116,56 @@
         /// Curve to be used for Decay in Curve mode
         /// </summary>
         public Curve DecayCurve;
+
+        /// <summary>
+        /// Calculate the Decay for a given body. Meant to ease force development and stick to
+        /// the DRY principle and provide unified and predictable decay math.
+        /// </summary>
+        /// <param name="Body"></param>
+        /// <returns></returns>
+        protected float GetDecayMultiplier(Body Body)
+        {
+            float Distance = (Body.Position - Position).Length();
+            switch (DecayMode)
+            {
+                case DecayModes.None:
+                    {
+                        return 1.0f;
+                    }
+                case DecayModes.Step:
+                    {
+                        if (Distance < DecayEnd)
+                            return 1.0f;
+                        else
+                            return 0.0f;
+                    }
+                case DecayModes.Linear:
+                    {
+                        if (Distance < DecayStart)
+                            return 1.0f;
+                        if (Distance > DecayEnd)
+                            return 0.0f;
+                        return (DecayEnd - DecayStart / Distance - DecayStart);
+                    }
+                case DecayModes.InverseSquare:
+                    {
+                        if (Distance < DecayStart)
+                            return 1.0f;
+                        else
+                            return 1.0f / ((Distance - DecayStart)*(Distance - DecayStart));
+                    }
+                case DecayModes.Curve:
+                    {
+                        if (Distance < DecayStart)
+                            return 1.0f;
+                        else
+                            return DecayCurve.Evaluate(Distance - DecayStart);
+                    }
+                default:
+                    return 1.0f;
+            }
+
+        }

         /// <summary>
         /// Constructor


Added horizontal movement (Drag & Drop)

Added horizontal movement (Drag & Drop)

--- TFG/TFG.Droid/Callbacks/HealthCardCallback.cs
+++ TFG/TFG.Droid/Callbacks/HealthCardCallback.cs
@@ -27,7 +27,7 @@
         }

         public override int GetMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
-            int dragFlags = ItemTouchHelper.Up | ItemTouchHelper.Down;  //Support for drag and drop
+            int dragFlags = ItemTouchHelper.Up | ItemTouchHelper.Down | ItemTouchHelper.Left | ItemTouchHelper.Right;  //Support for drag and drop
             int swipeFlags = 0;     //No support for swipe
             return MakeMovementFlags(dragFlags, swipeFlags);
         }


Start of Font overhaul (not finished)

Start of Font overhaul (not finished)


Inserted comment into DistanceJoint to give David directions

--- SourceFiles/FP3.0/Dynamics/Joints/DistanceJoint.cs
+++ SourceFiles/FP3.0/Dynamics/Joints/DistanceJoint.cs
@@ -70,8 +70,15 @@
             : base(bodyA, bodyB)
         {
             JointType = JointType.Distance;
+
+            //Theo Jansen's walker works
+            //LocalAnchorA = BodyA.GetLocalPoint(anchor1);
+            //LocalAnchorB = BodyB.GetLocalPoint(anchor2);
+
+            //Web works
             LocalAnchorA = anchor1;
             LocalAnchorB = anchor2;
+
             Vector2 d = WorldAnchorB - WorldAnchorA;
             Length = d.Length();
         }


Added tests in FakeItEasyMethodTest class.

--- Src/AutoFakeItEasyUnitTest/FakeItEasyMethodTest.cs
+++ Src/AutoFakeItEasyUnitTest/FakeItEasyMethodTest.cs
@@ -1,6 +1,7 @@
 using System;
 using System.Linq;
 using System.Reflection;
+using FakeItEasy;
 using Ploeh.AutoFixture.Kernel;
 using Ploeh.TestTypeFoundation;
 using Xunit;
@@ -55,5 +56,49 @@
             Assert.Equal(t, result);
             // Teardown
         }
+
+        [Fact]
+        public void ParametersIsCorrect()
+        {
+            // Fixture setup
+            var parameters = Enumerable.Empty<ParameterInfo>();
+            var sut = new FakeItEasyMethod(typeof(object), parameters.ToArray());
+            // Exercise system
+            var result = sut.Parameters;
+            // Verify outcome
+            Assert.Equal(parameters, result);
+            // Teardown
+        }
+
+        [Theory]
+        [InlineData(typeof(IInterface))]
+        [InlineData(typeof(AbstractType))]
+        public void InvokeReturnsCorrectResult(Type type)
+        {
+            // Fixture setup
+            var sut = new FakeItEasyMethod(type, new ParameterInfo[] { });
+            var expectedFake = typeof(Fake<>).MakeGenericType(type);
+            // Exercise system
+            var result = sut.Invoke(Enumerable.Empty<object>());
+            // Verify outcome
+            Assert.IsAssignableFrom(expectedFake, result);
+            // Teardown
+        }
+
+        [Fact]
+        public void InvokeOnTypeWithNonDefaultConstructorReturnsCorrectResult()
+        {
+            // Fixture setup
+            var sut = new FakeItEasyMethod(
+                typeof(AbstractTypeWithNonDefaultConstructor<int>),
+                new ParameterInfo[] { }
+                );
+            // Exercise system
+            var result = sut.Invoke(new object[] { 1 });
+            // Verify outcome
+            var fake = Assert.IsAssignableFrom<Fake<AbstractTypeWithNonDefaultConstructor<int>>>(result);
+            Assert.Equal(1, fake.FakedObject.Property);
+            // Teardown
+        }
     }
 }


Adding a null guard against primitive entry points in InjectBindingGenerator.

--- Stiletto.Fody/Generators/InjectBindingGenerator.cs
+++ Stiletto.Fody/Generators/InjectBindingGenerator.cs
@@ -176,10 +176,11 @@
         {
             // If an entry-point is declared that has no injectables (i.e. a primitive type),
             // there's nothing to emit.
-            if (!InjectableCtor.CustomAttributes.Any(Attributes.IsInjectAttribute)
+            if ((InjectableCtor == null || !InjectableCtor.CustomAttributes.Any(Attributes.IsInjectAttribute))
                 && InjectableProperties.Count == 0
                 && BaseTypeKey == null)
             {
+                Conditions.Assert(IsEntryPoint, "Non-entry-points must have a constructor!");
                 return null;
             }


Fixed order of some things regarding the color parsing for groups.  Users still seem to not be getting anything.

--- TDSMPermissions/TDSMPermissions/TDSMPermissions.cs
+++ TDSMPermissions/TDSMPermissions/TDSMPermissions.cs
@@ -99,7 +99,6 @@

         public void LoadPerms()
         {
-            ProgramLog.Debug.Log("Loading Permissions");
             Token to;
             TextReader re = File.OpenText(permissionsYML);

@@ -123,14 +122,7 @@
                                     }
                                 case "permissions":
                                     {
-                                        //if (inUsers)
-                                        //{
-                                        //    ProcessUserPermissions();
-                                        //}
-                                        //else
-                                        //{
-                                        ProcessPermissions();
-                                        //}
+										ProcessPermissions();
                                         break;
                                     }
                                 case "inheritance":
@@ -176,7 +168,6 @@
                         break;
                 }
             }
-            ProgramLog.Debug.Log("Permissions file loaded.");
         }

         private void ProcessGroups()
@@ -267,17 +258,27 @@
             while (sc.TokenText != "color")
             {
                 sc.NextToken();
-                if (sc.TokenText == "")
+                if (sc.Token == Token.Outdent)
+				{
+					color = ChatColor.White;
                     break;
-            }
-
-            if (sc.TokenText == "")
-                color = ChatColor.White;
-            else
-                Color.TryParseRGB(sc.TokenText, out color);
-
-            while (sc.NextToken() != Token.TextContent)
-            { }
+				}
+            }
+
+			if (sc.Token == Token.TextContent && sc.TokenText == "color")
+			{
+				while (sc.NextToken() != Token.TextContent)
+				{
+					if (sc.Token == Token.Outdent)
+						break;
+				}
+				if (sc.Token == Token.TextContent)
+					Color.TryParseRGB(sc.TokenText, out color);
+				else
+					color = ChatColor.White;
+			}
+
+
         }

         private void ProcessInheritance()


Update KnownFoldersConfiguration.cs

Update KnownFoldersConfiguration.cs

--- TIKSN.Core/FileSystem/KnownFoldersConfiguration.cs
+++ TIKSN.Core/FileSystem/KnownFoldersConfiguration.cs
@@ -7,11 +7,11 @@
     {
         public KnownFoldersConfiguration(Assembly mainAssembly, KnownFolderVersionConsideration versionConsideration)
         {
-            MainAssembly = mainAssembly ?? throw new ArgumentNullException(nameof(mainAssembly));
-            VersionConsideration = versionConsideration;
+            this.MainAssembly = mainAssembly ?? throw new ArgumentNullException(nameof(mainAssembly));
+            this.VersionConsideration = versionConsideration;
         }

         public Assembly MainAssembly { get; }
         public KnownFolderVersionConsideration VersionConsideration { get; }
     }
-}+}


Indicate when a variable name really is useless (Type cast)

The diagnostic "Use implicitly typed local variable declaration" now
have
two forms, one as a warning when the type is specified on the right and
one as an info if it isn't.

--- TestDiagnostics/VarConversion/TypeToVarAnalyzer.cs
+++ TestDiagnostics/VarConversion/TypeToVarAnalyzer.cs
@@ -14,18 +14,28 @@
 namespace BlackFox.Roslyn.Diagnostics.VarConversion
 {
     [DiagnosticAnalyzer]
-    [ExportDiagnosticAnalyzer(Id, LanguageNames.CSharp)]
+    [ExportDiagnosticAnalyzer("BlackFox.TypeToVar", LanguageNames.CSharp)]
     public class TypeToVarAnalyzer : ISyntaxNodeAnalyzer<SyntaxKind>
     {
-        public const string Id = "BlackFox.TypeToVar";
+        public const string Id = "BlackFox.TypeToVar_Normal";
+        public const string IdWithCast = "BlackFox.TypeToVar_WithCast";

         public static DiagnosticDescriptor Descriptor { get; }
             = new DiagnosticDescriptor(
                 Id,
-                "'var' can be used",
-                "'var' can be used",
+                "Use implicitly typed local variable declaration",
+                "Use implicitly typed local variable declaration",
                 "Readability",
                 DiagnosticSeverity.Hidden,
+                isEnabledByDefault: true);
+
+        public static DiagnosticDescriptor DescriptorWithCast { get; }
+            = new DiagnosticDescriptor(
+                IdWithCast,
+                "Use implicitly typed local variable declaration",
+                "Use implicitly typed local variable declaration",
+                "Readability",
+                DiagnosticSeverity.Warning,
                 isEnabledByDefault: true);

         public ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; }
@@ -68,7 +78,15 @@
                 return;
             }

-            addDiagnostic(Diagnostic.Create(Descriptor, variableDeclaration.Type.GetLocation()));
+            var location = variableDeclaration.Type.GetLocation();
+            if (variableInitializer.Value is CastExpressionSyntax)
+            {
+                addDiagnostic(Diagnostic.Create(DescriptorWithCast, location));
+            }
+            else
+            {
+                addDiagnostic(Diagnostic.Create(Descriptor, location));
+            }
         }
     }
 }


Unit test update

Unit test update

--- Tests/Engine/DataFeeds/LiveTradingDataFeedTests.cs
+++ Tests/Engine/DataFeeds/LiveTradingDataFeedTests.cs
@@ -1766,6 +1766,7 @@
         public void HandlesFutureAndOptionChainUniverse(SecurityType securityType)
         {
             Log.DebuggingEnabled = LogsEnabled;
+            Log.LogHandler = new ConsoleLogHandler();

             // startDate and endDate are in algorithm time zone
             var startDate = new DateTime(2019, 11, 19, 4, 0, 0);
@@ -1778,8 +1779,9 @@
             timeProvider.SetCurrentTime(startDate);

             var lastTime = DateTime.MinValue;
+            var timeAdvanceStep = TimeSpan.FromMinutes(60);
             var timeAdvanced = new AutoResetEvent(true);
-            var isLookupSymbolsCalled = false;
+            var lookupCount = 0;

             var optionSymbol1 = Symbol.CreateOption("SPY", Market.USA, OptionStyle.American, OptionRight.Call, 192m, new DateTime(2019, 12, 19));
             var optionSymbol2 = Symbol.CreateOption("SPY", Market.USA, OptionStyle.American, OptionRight.Put, 192m, new DateTime(2019, 12, 19));
@@ -1788,6 +1790,7 @@
             var futureSymbol2 = Symbol.CreateFuture("SPY", Market.USA, new DateTime(2020, 3, 19));

             Symbol canonicalOptionSymbol = null;
+            Exception lookupSymbolsException = null;

             var futureSymbols = new HashSet<Symbol>();
             var optionSymbols = new HashSet<Symbol>();
@@ -1795,8 +1798,8 @@
             var timer = new Timer(
                 _ =>
                 {
-                    timeProvider.Advance(TimeSpan.FromMinutes(60));
-                    ConsoleWriteLine($"Time advanced to {timeProvider.GetUtcNow()} UTC");
+                    timeProvider.Advance(timeAdvanceStep);
+                    Log.Debug($"Time advanced to {timeProvider.GetUtcNow()} (UTC)");
                     timeAdvanced.Set();
                 }, null, Time.OneSecond, TimeSpan.FromMilliseconds(100));

@@ -1865,7 +1868,7 @@
                                 Quantity = 1
                             }));

-                    ConsoleWriteLine($"DQH: Emitting data point at {utcTime.ConvertFromUtc(algorithmTimeZone)}");
+                    Log.Debug($"DQH: Emitting data point(s) at {utcTime.ConvertFromUtc(algorithmTimeZone)} ({algorithmTimeZone})");

                     return dataPoints;
                 },
@@ -1873,16 +1876,19 @@
                 // LookupSymbols
                 (lookupName, secType, securityCurrency, securityExchange) =>
                 {
-                    isLookupSymbolsCalled = true;
+                    lookupCount++;

                     var utcTime = timeProvider.GetUtcNow();
                     var time = utcTime.ConvertFromUtc(algorithmTimeZone);

                     var isValidTime = time.Hour >= 1 && time.Hour < 23;

-                    ConsoleWriteLine($"LookupSymbols() called at {time} - valid: {isValidTime}");
-
-                    Assert.That(isValidTime);
+                    Log.Debug($"LookupSymbols() called at {time} ({algorithmTimeZone}) - valid: {isValidTime}");
+
+                    if (!isValidTime)
+                    {
+                        lookupSymbolsException = new Exception($"Invalid LookupSymbols call time: {time} ({algorithmTimeZone})");
+                    }

                     time = utcTime.ConvertFromUtc(exchangeTimeZone);

@@ -1908,7 +1914,7 @@
                     var time = timeProvider.GetUtcNow().ConvertFromUtc(algorithmTimeZone);
                     var result = time.Hour >= 1 && time.Hour < 23;

-                    ConsoleWriteLine($"CanAdvanceTime() called at {time}, returning {result}");
+                    Log.Debug($"CanAdvanceTime() called at {time} ({algorithmTimeZone}), returning {result}");

                     return result;
                 });
@@ -1999,9 +2005,9 @@
                     {
                         var symbols = futureChain.Contracts.Values.Select(x => x.Symbol).ToList();
                         futureContractCount += symbols.Count;
-                        ConsoleWriteLine($"{timeSlice.Time} - future contracts: {string.Join(",", symbols)}");
-                    }
-                    ConsoleWriteLine($"{timeSlice.Time} - future symbols: {string.Join(",", futureSymbols)}");
+                        Log.Debug($"{timeSlice.Time} - future contracts: {string.Join(",", symbols)}");
+                    }
+                    Log.Debug($"{timeSlice.Time} - future symbols: {string.Join(",", futureSymbols)}");
                 }
                 else if (securityType == SecurityType.Option)
                 {
@@ -2009,13 +2015,13 @@
                     {
                         var symbols = optionChain.Contracts.Values.Select(x => x.Symbol).ToList();
                         optionContractCount += symbols.Count;
-                        ConsoleWriteLine($"{timeSlice.Time} - option contracts: {string.Join(",", symbols)}");
-                    }
-                    ConsoleWriteLine($"{timeSlice.Time} - option symbols: {string.Join(",", optionSymbols)}");
+                        Log.Debug($"{timeSlice.Time} - option contracts: {string.Join(",", symbols)}");
+                    }
+                    Log.Debug($"{timeSlice.Time} - option symbols: {string.Join(",", optionSymbols)}");
                 }

                 if (lastSecurityChangedTime != null &&
-                    timeSlice.Time > lastSecurityChangedTime.Value.AddMinutes(60))
+                    timeSlice.Time > lastSecurityChangedTime.Value.Add(timeAdvanceStep))
                 {
                     if (securityType == SecurityType.Future)
                     {
@@ -2043,13 +2049,13 @@
                     if (security.Symbol.SecurityType == SecurityType.Future)
                     {
                         lastSecurityChangedTime = timeSlice.Time;
-                        ConsoleWriteLine($"{timeSlice.Time} - Adding future symbol: {security.Symbol}");
+                        Log.Debug($"{timeSlice.Time} - Adding future symbol: {security.Symbol}");
                         futureSymbols.Add(security.Symbol);
                     }
                     else if (security.Symbol.SecurityType == SecurityType.Option)
                     {
                         lastSecurityChangedTime = timeSlice.Time;
-                        ConsoleWriteLine($"{timeSlice.Time} - Adding option symbol: {security.Symbol}");
+                        Log.Debug($"{timeSlice.Time} - Adding option symbol: {security.Symbol}");
                         optionSymbols.Add(security.Symbol);
                     }
                 }
@@ -2059,13 +2065,13 @@
                     if (security.Symbol.SecurityType == SecurityType.Future)
                     {
                         lastSecurityChangedTime = timeSlice.Time;
-                        ConsoleWriteLine($"{timeSlice.Time} - Removing future symbol: {security.Symbol}");
+                        Log.Debug($"{timeSlice.Time} - Removing future symbol: {security.Symbol}");
                         futureSymbols.Remove(security.Symbol);
                     }
                     else if (security.Symbol.SecurityType == SecurityType.Option)
                     {
                         lastSecurityChangedTime = timeSlice.Time;
-                        ConsoleWriteLine($"{timeSlice.Time} - Removing option symbol: {security.Symbol}");
+                        Log.Debug($"{timeSlice.Time} - Removing option symbol: {security.Symbol}");
                         optionSymbols.Remove(security.Symbol);
                     }
                 }
@@ -2075,15 +2081,15 @@
                 foreach (var baseDataCollection in timeSlice.UniverseData.Values)
                 {
                     var symbols = string.Join(",", baseDataCollection.Data.Select(x => x.Symbol));
-                    ConsoleWriteLine($"{timeSlice.Time} - universe data: {symbols}");
+                    Log.Debug($"{timeSlice.Time} - universe data: {symbols}");
                 }

                 var currentTime = timeProvider.GetUtcNow();
                 algorithm.SetDateTime(currentTime);

-                ConsoleWriteLine($"{timeSlice.Time} - " +
-                                 $"Algorithm time set to {currentTime.ConvertFromUtc(algorithmTimeZone)}");
-                ConsoleWriteLine();
+                Log.Debug($"{timeSlice.Time} - " +
+                                 $"Algorithm time set to {currentTime.ConvertFromUtc(algorithmTimeZone)} ({algorithmTimeZone})");
+                Log.Debug("");

                 if (currentTime.ConvertFromUtc(algorithmTimeZone) > endDate)
                 {
@@ -2093,15 +2099,20 @@
                 }
             }

-            Assert.IsTrue(isLookupSymbolsCalled);
+            if (lookupSymbolsException != null)
+            {
+                throw lookupSymbolsException;
+            }
+
+            Assert.AreEqual(3, lookupCount, "LookupSymbols call count mismatch");

             if (securityType == SecurityType.Future)
             {
-                Assert.AreEqual(2, futureSymbols.Count);
+                Assert.AreEqual(2, futureSymbols.Count, "Future symbols count mismatch");
             }
             else if (securityType == SecurityType.Option)
             {
-                Assert.AreEqual(2, optionSymbols.Count);
+                Assert.AreEqual(2, optionSymbols.Count, "Option symbols count mismatch");
             }

             dataManager.RemoveAllSubscriptions();


- Added unsigned testcases to Mul

- Added unsigned testcases to Mul

git-svn-id: 61c3ae23f3a6520e9bc357b51591209af2ede9d8@248 45b04e34-05f1-4d87-a130-40a8491d5c8b

--- Test/Mosa/Runtime/CompilerFramework/IL/Mul.cs
+++ Test/Mosa/Runtime/CompilerFramework/IL/Mul.cs
@@ -99,6 +99,55 @@
         /// <param name="a"></param>
         /// <param name="b"></param>
         /// <returns></returns>
+        delegate bool U4_U1_U1(uint expect, byte a, byte b);
+        /// <summary>
+        ///
+        /// </summary>
+        /// <param name="a"></param>
+        /// <param name="b"></param>
+        [Row(1, 2)]
+        [Row(23, 21)]
+        [Row(0, 0)]
+        // And reverse
+        [Row(2, 1)]
+        [Row(21, 23)]
+        // (MinValue, X) Cases
+        [Row(byte.MinValue, 0)]
+        [Row(byte.MinValue, 1)]
+        [Row(byte.MinValue, 17)]
+        [Row(byte.MinValue, 123)]
+        // (MaxValue, X) Cases
+        [Row(byte.MaxValue, 0)]
+        [Row(byte.MaxValue, 1)]
+        [Row(byte.MaxValue, 17)]
+        [Row(byte.MaxValue, 123)]
+        // (X, MinValue) Cases
+        [Row(0, byte.MinValue)]
+        [Row(1, byte.MinValue)]
+        [Row(17, byte.MinValue)]
+        [Row(123, byte.MinValue)]
+        // (X, MaxValue) Cases
+        [Row(0, byte.MaxValue)]
+        [Row(1, byte.MaxValue)]
+        [Row(17, byte.MaxValue)]
+        [Row(123, byte.MaxValue)]
+        // Extremvaluecases
+        [Row(byte.MinValue, byte.MaxValue)]
+        [Row(byte.MaxValue, byte.MinValue)]
+        [Test, Author("alyman", "mail.alex.lyman@gmail.com")]
+        public void MulU1(byte a, byte b)
+        {
+            CodeSource = "static class Test { static bool MulU1(uint expect, byte a, byte b) { return expect == (a * b); } }";
+            Assert.IsTrue((bool)Run<U4_U1_U1>("", "Test", "MulU1", a * b, a, b));
+        }
+
+        /// <summary>
+        ///
+        /// </summary>
+        /// <param name="expect"></param>
+        /// <param name="a"></param>
+        /// <param name="b"></param>
+        /// <returns></returns>
         delegate bool I4_I2_I2(int expect, short a, short b);
         /// <summary>
         ///
@@ -170,6 +219,55 @@
         /// <param name="a"></param>
         /// <param name="b"></param>
         /// <returns></returns>
+        delegate bool U4_U2_U2(uint expect, ushort a, ushort b);
+        /// <summary>
+        ///
+        /// </summary>
+        /// <param name="a"></param>
+        /// <param name="b"></param>
+        [Row(1, 2)]
+        [Row(23, 21)]
+        [Row(0, 0)]
+        // And reverse
+        [Row(2, 1)]
+        [Row(21, 23)]
+        // (MinValue, X) Cases
+        [Row(ushort.MinValue, 0)]
+        [Row(ushort.MinValue, 1)]
+        [Row(ushort.MinValue, 17)]
+        [Row(ushort.MinValue, 123)]
+        // (MaxValue, X) Cases
+        [Row(ushort.MaxValue, 0)]
+        [Row(ushort.MaxValue, 1)]
+        [Row(ushort.MaxValue, 17)]
+        [Row(ushort.MaxValue, 123)]
+        // (X, MinValue) Cases
+        [Row(0, ushort.MinValue)]
+        [Row(1, ushort.MinValue)]
+        [Row(17, ushort.MinValue)]
+        [Row(123, ushort.MinValue)]
+        // (X, MaxValue) Cases
+        [Row(0, ushort.MaxValue)]
+        [Row(1, ushort.MaxValue)]
+        [Row(17, ushort.MaxValue)]
+        [Row(123, ushort.MaxValue)]
+        // Extremvaluecases
+        [Row(ushort.MinValue, ushort.MaxValue)]
+        [Row(ushort.MaxValue, ushort.MinValue)]
+        [Test, Author("alyman", "mail.alex.lyman@gmail.com")]
+        public void MulU2(ushort a, ushort b)
+        {
+            CodeSource = "static class Test { static bool MulU2(uint expect, ushort a, ushort b) { return expect == (a * b); } }";
+            Assert.IsTrue((bool)Run<U4_U2_U2>("", "Test", "MulU2", (a * b), a, b));
+        }
+
+        /// <summary>
+        ///
+        /// </summary>
+        /// <param name="expect"></param>
+        /// <param name="a"></param>
+        /// <param name="b"></param>
+        /// <returns></returns>
         delegate bool I4_I4_I4(int expect, int a, int b);
         /// <summary>
         ///
@@ -233,6 +331,55 @@
             CodeSource = "static class Test { static bool MulI4(int expect, int a, int b) { return expect == (a * b); } }";
             Assert.IsTrue((bool)Run<I4_I4_I4>("", "Test", "MulI4", (a * b), a, b));
         }
+
+        /// <summary>
+        ///
+        /// </summary>
+        /// <param name="expect"></param>
+        /// <param name="a"></param>
+        /// <param name="b"></param>
+        /// <returns></returns>
+        delegate bool U4_U4_U4(uint expect, uint a, uint b);
+        /// <summary>
+        ///
+        /// </summary>
+        /// <param name="a"></param>
+        /// <param name="b"></param>
+        [Row(1, 2)]
+        [Row(23, 21)]
+        [Row(0, 0)]
+        // And reverse
+        [Row(2, 1)]
+        [Row(21, 23)]
+        // (MinValue, X) Cases
+        [Row(uint.MinValue, 0)]
+        [Row(uint.MinValue, 1)]
+        [Row(uint.MinValue, 17)]
+        [Row(uint.MinValue, 123)]
+        // (MaxValue, X) Cases
+        [Row(uint.MaxValue, 0)]
+        [Row(uint.MaxValue, 1)]
+        [Row(uint.MaxValue, 17)]
+        [Row(uint.MaxValue, 123)]
+        // (X, MinValue) Cases
+        [Row(0, uint.MinValue)]
+        [Row(1, uint.MinValue)]
+        [Row(17, uint.MinValue)]
+        [Row(123, uint.MinValue)]
+        // (X, MaxValue) Cases
+        [Row(0, uint.MaxValue)]
+        [Row(1, uint.MaxValue)]
+        [Row(17, uint.MaxValue)]
+        [Row(123, uint.MaxValue)]
+        // Extremvaluecases
+        [Row(uint.MinValue, uint.MaxValue)]
+        [Row(uint.MaxValue, uint.MinValue)]
+        [Test, Author("alyman", "mail.alex.lyman@gmail.com")]
+        public void MulU4(uint a, uint b)
+        {
+            CodeSource = "static class Test { static bool MulU4(uint expect, uint a, uint b) { return expect == (a * b); } }";
+            Assert.IsTrue((bool)Run<U4_U4_U4>("", "Test", "MulU4", (a * b), a, b));
+        }

         /// <summary>
         ///
@@ -301,6 +448,52 @@
             CodeSource = "static class Test { static bool MulI8(long expect, long a, long b) { return expect == (a * b); } }";
             Assert.IsTrue((bool)Run<I8_I8_I8>("", "Test", "MulI8", (a * b), a, b));
         }
+
+        /// <summary>
+        ///
+        /// </summary>
+        /// <param name="expect"></param>
+        /// <param name="a"></param>
+        /// <param name="b"></param>
+        /// <returns></returns>
+        delegate bool U8_U8_U8(ulong expect, ulong a, ulong b);
+        /// <summary>
+        ///
+        /// </summary>
+        /// <param name="a"></param>
+        /// <param name="b"></param>
+        [Row(1, 2)]
+        [Row(23, 21)]
+        [Row(0, 0)]
+        // And reverse
+        [Row(2, 1)]
+        [Row(21, 23)]
+        // (MinValue, X) Cases
+        [Row(ulong.MinValue, 0)]
+        [Row(ulong.MinValue, 1)]
+        [Row(ulong.MinValue, 17)]
+        [Row(ulong.MinValue, 123)]
+        // (MaxValue, X) Cases
+        [Row(ulong.MaxValue, 0)]
+        [Row(ulong.MaxValue, 1)]
+        [Row(ulong.MaxValue, 17)]
+        [Row(ulong.MaxValue, 123)]
+        // (X, MinValue) Cases
+        [Row(0, ulong.MinValue)]
+        [Row(1, ulong.MinValue)]
+        [Row(17, ulong.MinValue)]
+        [Row(123, ulong.MinValue)]
+        // (X, MaxValue) Cases
+        [Row(0, ulong.MaxValue)]
+        [Row(1, ulong.MaxValue)]
+        [Row(17, ulong.MaxValue)]
+        [Row(123, ulong.MaxValue)]
+        [Test, Author("alyman", "mail.alex.lyman@gmail.com")]
+        public void MulU8(ulong a, ulong b)
+        {
+            CodeSource = "static class Test { static bool MulU8(ulong expect, ulong a, ulong b) { return expect == (a * b); } }";
+            Assert.IsTrue((bool)Run<U8_U8_U8>("", "Test", "MulU8", (a * b), a, b));
+        }

         /// <summary>
         ///


Fixed log statement, using Logger alias instead of UnityEngine.Debug.

--- Assets/June/LocalStorage/Providers/JSONLocalStore.cs
+++ Assets/June/LocalStorage/Providers/JSONLocalStore.cs
@@ -32,7 +32,7 @@
 			string data = null;
 			try {
 				if(File.Exists(FILE_PATH)) {
-					Debug.Log(FILE_PATH);
+					Logger.Log("[JSONLocalStorage] Opening: " + FILE_PATH);
 					using(StreamReader sr = new StreamReader(FILE_PATH)) {
 						data = sr.ReadToEnd();
 					}


Removed the CiF Appraisal of Events as it is no longer needed

--- Assets/RolePlayCharacter/RolePlayerCharacterAsset.cs
+++ Assets/RolePlayCharacter/RolePlayerCharacterAsset.cs
@@ -345,17 +345,7 @@
                             CurrentActionTarget = null;
                         }
                         this.AddKnownAgent(e.GetNTerm(2));
-                        var cif_Events = m_commeillFautAsset.AppraiseEvents(new[] { e }, m_kb);
-                        if (cif_Events.Count > 0)
-                        {
-                            var toPerceive = new List<Name>();
-                            foreach (var ev in cif_Events)
-                            {
-                                var newEvent = EventHelper.PropertyChange(ev.Key.ToString(), ev.Value.ToString(), this.CharacterName.ToString());
-                                toPerceive.Add(newEvent);
-                            }
-                            Perceive(toPerceive);
-                        }
+
                     }
                 }
                 m_emotionalAppraisalAsset.AppraiseEvents(events, observer, m_emotionalState, m_am, m_kb);


Authorize on unit controller, Fixes #103

--- Battery-Commander.Web/Controllers/UnitsController.cs
+++ Battery-Commander.Web/Controllers/UnitsController.cs
@@ -8,6 +8,7 @@

 namespace BatteryCommander.Web.Controllers
 {
+    [Authorize]
     public class UnitsController : Controller
     {
         private readonly Database db;


Implement IParser on named arguments builder.

Start to factor away the parsing responsibility. This is a bit of a weird
implementation at the moment, so that the tests remain green, but the
inheritance from DynamicBuilderBase<T> will eventually fall away.

--- BobTheBuilder/Syntax/NamedArgumentsDynamicBuilder.cs
+++ BobTheBuilder/Syntax/NamedArgumentsDynamicBuilder.cs
@@ -6,7 +6,7 @@

 namespace BobTheBuilder.Syntax
 {
-    public class NamedArgumentsDynamicBuilder<T> : DynamicBuilderBase<T> where T : class
+    public class NamedArgumentsDynamicBuilder<T> : DynamicBuilderBase<T>, IParser where T : class
     {
         private readonly IDynamicBuilder<T> wrappedBuilder;

@@ -22,14 +22,24 @@

         public override bool InvokeBuilderMethod(InvokeMemberBinder binder, object[] args, out object result)
         {
+            result = this;
+            if (!Parse(binder, args))
+            {
+                return wrappedBuilder.InvokeBuilderMethod(binder, args, out result);
+            }
+
+            return true;
+        }
+
+        public bool Parse(InvokeMemberBinder binder, object[] args)
+        {
             if (binder.Name == "With")
             {
                 ParseNamedArgumentValues(binder.CallInfo, args);
-                result = this;
                 return true;
             }

-            return wrappedBuilder.InvokeBuilderMethod(binder, args, out result);
+            return false;
         }

         private void ParseNamedArgumentValues(CallInfo callInfo, object[] args)


Add unit test

Add unit test

--- UnitTestUsefullFunctions/UnitTestFunctionsExcel.cs
+++ UnitTestUsefullFunctions/UnitTestFunctionsExcel.cs
@@ -593,5 +593,19 @@
       List<string> result = FunctionsExcel.AllColumnsNameUntil(source);
       CollectionAssert.AreEquivalent(result, expected);
     }
+
+    [TestMethod]
+    [TestCategory("Excel")]
+    public void TestMethod_AllColumnsUntil_65()
+    {
+      const int source = 65;
+      List<string> expected = new List<string>
+      {
+        "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "AA", "AB", "AC", "AD", "AE", "AF", "AG", "AH", "AI", "AJ", "AK", "AL", "AM", "AN", "AO", "AP", "AQ", "AR", "AS", "AT", "AU", "AV", "AW", "AX", "AY", "AZ", "BA", "BB", "BC", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BK", "BL"
+      };
+
+      List<string> result = FunctionsExcel.AllColumnsNameUntil(source);
+      CollectionAssert.AreEquivalent(result, expected);
+    }
   }
 }


added a lil temp fix until icreate a final one

--- Unity/Assets/Scripts/Controlers/GroundControler.cs
+++ Unity/Assets/Scripts/Controlers/GroundControler.cs
@@ -24,16 +24,24 @@
     // Update is called once per frame
     void Update()
     {
+        EndLeft = LeftWall.position;
+        EndLeft.y = transform.position.y;
+        EndLeft.z = transform.position.z;
+
+        EndRight = RightWall.position;
+        EndRight.y = transform.position.y;
+        EndRight.z = transform.position.z;
+
         if (dir > 0)
         {
-            if (Vector3.Distance(EndRight, transform.position) < 0.5f)
+            if (Vector3.Distance(EndRight, transform.position) < 1f)
             {
                 dir = -1;
             }
         }
         else if (dir < 0)
         {
-            if (Vector3.Distance(EndLeft, transform.position) < 0.5f)
+            if (Vector3.Distance(EndLeft, transform.position) < 1f)
             {
                 dir = 1;
             }


Remove pre/post build events

Remove pre/post build events

--- Unosquare.Labs.SshDeploy/DeploymentManager.Push.cs
+++ Unosquare.Labs.SshDeploy/DeploymentManager.Push.cs
@@ -19,7 +19,8 @@
                 FileName = "dotnet",
                 Arguments = " msbuild /t:Publish " +
                 $" /p:Configuration={verbOptions.Configuration};" +
-                $"TargetFramework={verbOptions.Framework};RuntimeIdentifier={verbOptions.Runtime}"
+                $"TargetFramework={verbOptions.Framework};RuntimeIdentifier={verbOptions.Runtime};" +
+                $"PreBuildEvent=\"\";PostBuildEvent=\"\""
             };
             var process = Process.Start(psi);
             process.WaitForExit();


Fix QueryStringSchemaTester file encoding.

Change-Id: I45919e25e237bde54f37d30d62f85b8d7f57d9e9

--- Verse.UTest/src/Schemas/QueryStringSchemaTester.cs
+++ Verse.UTest/src/Schemas/QueryStringSchemaTester.cs
@@ -1,30 +1,30 @@
-using System.IO;
-using System.Text;
-using NUnit.Framework;
-using Verse.Schemas;
-
-namespace Verse.UTest.Schemas
-{
-    [TestFixture]
-    public class QueryStringSchemaTester : SchemaTester
-    {
-        [Test]
-        [TestCase("?a&b&c")]
-        [TestCase("?a&")]
-        public void ParseSuccess(string query)
-        {
-            IParser<string> parser;
-            QueryStringSchema<string> schema;
-            string value;
-
-            schema = new QueryStringSchema<string>();
-            value = string.Empty;
-
-            parser = schema.CreateParser();
-
-            Assert.IsTrue(parser.Parse(new MemoryStream(Encoding.UTF8.GetBytes(query)), ref value));
-        }
-
+using System.IO;
+using System.Text;
+using NUnit.Framework;
+using Verse.Schemas;
+
+namespace Verse.UTest.Schemas
+{
+    [TestFixture]
+    public class QueryStringSchemaTester : SchemaTester
+    {
+        [Test]
+        [TestCase("?a&b&c")]
+        [TestCase("?a&")]
+        public void ParseSuccess(string query)
+        {
+            IParser<string> parser;
+            QueryStringSchema<string> schema;
+            string value;
+
+            schema = new QueryStringSchema<string>();
+            value = string.Empty;
+
+            parser = schema.CreateParser();
+
+            Assert.IsTrue(parser.Parse(new MemoryStream(Encoding.UTF8.GetBytes(query)), ref value));
+        }
+
         [Test]
         [TestCase("f0", "?f0=v0", "v0")]
         [TestCase("f0", "?f0=", "")]
@@ -39,59 +39,59 @@
         [TestCase("f0", "?f0=v0*v1", "v0*v1")]
         [TestCase("f0", "?f0=v0'v1", "v0'v1")]
         [TestCase("f0", "?f0=a,b&f1=c", "a,b")]
-        [TestCase("f1", "?f0=a,b&f1=c", "c")]
-        public void ParseFieldValue<T>(string name, string query, T expected)
-        {
-            IParser<T> parser;
-            QueryStringSchema<T> schema;
-            T value;
-
-            schema = new QueryStringSchema<T>();
-            schema.ParserDescriptor.HasField(name).IsValue();
-
-            parser = schema.CreateParser();
-            value = default(T);
-
-            Assert.IsTrue(parser.Parse(new MemoryStream(Encoding.UTF8.GetBytes(query)), ref value));
-            Assert.AreEqual(expected, value);
-        }
-
+        [TestCase("f1", "?f0=a,b&f1=c", "c")]
+        public void ParseFieldValue<T>(string name, string query, T expected)
+        {
+            IParser<T> parser;
+            QueryStringSchema<T> schema;
+            T value;
+
+            schema = new QueryStringSchema<T>();
+            schema.ParserDescriptor.HasField(name).IsValue();
+
+            parser = schema.CreateParser();
+            value = default(T);
+
+            Assert.IsTrue(parser.Parse(new MemoryStream(Encoding.UTF8.GetBytes(query)), ref value));
+            Assert.AreEqual(expected, value);
+        }
+
         [Test]
         [TestCase("f0", "?f0=v0+v1", "v0 v1")]
         [TestCase("f0", "?f0=v0%3Dv1", "v0=v1")]
         [TestCase("f0", "?f0=v0%3dv1", "v0=v1")]
-        [TestCase("f0", "?f0=http%3a%2f%2fwww.pokewiki.de%2fSchillern+de_Pok%c3%a9mon", "http://www.pokewiki.de/Schillern de_Pokmon")]
-        public void ParseSpecialCharacter<T>(string name, string query, T expected)
-        {
-            IParser<T> parser;
-            QueryStringSchema<T> schema;
-            T value;
-
-            schema = new QueryStringSchema<T>();
-            schema.ParserDescriptor.HasField(name).IsValue();
-
-            parser = schema.CreateParser();
-            value = default(T);
-
-            Assert.IsTrue(parser.Parse(new MemoryStream(Encoding.UTF8.GetBytes(query)), ref value));
-            Assert.AreEqual(expected, value);
-        }
-
-        [Test]
-        [TestCase("?=v0")]
-        [TestCase("?&f0")]
-        [TestCase("?f0==v0")]
-        public void ParseFail(string query)
-        {
-            IParser<string> parser;
-            QueryStringSchema<string> schema;
-            string value;
-
-            schema = new QueryStringSchema<string>();
-            parser = schema.CreateParser();
-            value = string.Empty;
-
-            Assert.IsFalse(parser.Parse(new MemoryStream(Encoding.UTF8.GetBytes(query)), ref value));
-        }
-    }
+        [TestCase("f0", "?f0=http%3a%2f%2fwww.pokewiki.de%2fSchillern+de_Pok%c3%a9mon", "http://www.pokewiki.de/Schillern de_Pokémon")]
+        public void ParseSpecialCharacter<T>(string name, string query, T expected)
+        {
+            IParser<T> parser;
+            QueryStringSchema<T> schema;
+            T value;
+
+            schema = new QueryStringSchema<T>();
+            schema.ParserDescriptor.HasField(name).IsValue();
+
+            parser = schema.CreateParser();
+            value = default(T);
+
+            Assert.IsTrue(parser.Parse(new MemoryStream(Encoding.UTF8.GetBytes(query)), ref value));
+            Assert.AreEqual(expected, value);
+        }
+
+        [Test]
+        [TestCase("?=v0")]
+        [TestCase("?&f0")]
+        [TestCase("?f0==v0")]
+        public void ParseFail(string query)
+        {
+            IParser<string> parser;
+            QueryStringSchema<string> schema;
+            string value;
+
+            schema = new QueryStringSchema<string>();
+            parser = schema.CreateParser();
+            value = string.Empty;
+
+            Assert.IsFalse(parser.Parse(new MemoryStream(Encoding.UTF8.GetBytes(query)), ref value));
+        }
+    }
 }


Improvements in debug attach sequence (#620)

***NO_CI***

--- VisualStudio.Extension/CorDebug/CorDebugProcess.cs
+++ VisualStudio.Extension/CorDebug/CorDebugProcess.cs
@@ -328,62 +328,69 @@

                 for (int retries = 0; retries < maxOperationRetries; retries++)
                 {
-                    if (_engine.IsConnectedTonanoCLR)
-                    {
-                        currentExecutionMode = _engine.GetExecutionMode();
-
-                        if (currentExecutionMode.IsDeviceInInitializeState())
+                    if (AttachToEngine() != null)
+                    {
+                        Thread.Yield();
+
+                        if (_engine.IsConnectedTonanoCLR)
                         {
-                            MessageCentre.InternalErrorWriteLine("Device is running the CLR in initialized state");
-
-                            // check to see if the device has type resolution failed flag set
-                            if (currentExecutionMode.IsDeviceStoppedOnTypeResolutionFailed())
+                            currentExecutionMode = _engine.GetExecutionMode();
+
+                            if (currentExecutionMode.IsDeviceInInitializeState())
                             {
-                                MessageCentre.DebugMessage("******************************************************************************");
-                                MessageCentre.DebugMessage("** Error: Device stopped after type resolution failure.                     **");
-                                MessageCentre.DebugMessage("** Check in each assembly which assemblies are referenced and their version **");
-                                MessageCentre.DebugMessage("******************************************************************************");
+                                MessageCentre.InternalErrorWriteLine("Device is running the CLR in initialized state");
+
+                                // check to see if the device has type resolution failed flag set
+                                if (currentExecutionMode.IsDeviceStoppedOnTypeResolutionFailed())
+                                {
+                                    MessageCentre.DebugMessage("******************************************************************************");
+                                    MessageCentre.DebugMessage("** Error: Device stopped after type resolution failure.                     **");
+                                    MessageCentre.DebugMessage("** Check in each assembly which assemblies are referenced and their version **");
+                                    MessageCentre.DebugMessage("******************************************************************************");

 #pragma warning disable S112 // General exceptions should never be thrown
-                                throw new Exception("Device stopped after type resolution failure. Can't start execution.");
+                                    throw new Exception("Device stopped after type resolution failure. Can't start execution.");
 #pragma warning restore S112 // OK to use this here, that's the way to exit the debugger process
+                                }
+
+                                if (_engine.UpdateDebugFlags())
+                                {
+                                    Thread.Yield();
+
+                                    fSucceeded = true;
+                                    break;
+                                }
                             }
-
-                            if (_engine.UpdateDebugFlags())
+                            else
                             {
-                                fSucceeded = true;
-                                break;
+                                MessageCentre.InternalErrorWriteLine($"Device is running CLR, requesting reboot and pause for debugger ({retries + 1}/{ maxOperationRetries }).");
+
+                                _engine.RebootDevice(RebootOptions.ClrOnly | RebootOptions.WaitForDebugger);
+
+                                Thread.Yield();
                             }
+                        }
+                        else if (_engine.IsConnectedTonanoBooter)
+                        {
+                            MessageCentre.InternalErrorWriteLine($"Device is running nanoBooter, requesting to launch CLR ({retries + 1}/{ maxOperationRetries }).");
+
+                            // this is telling nanoBooter to enter CLR
+                            _engine.ExecuteMemory(0);
+
+                            Thread.Yield();
+
+                            // better pause here to allow the reboot to occur
+                            // use a back-off strategy of increasing the wait time to accommodate slower or less responsive targets (such as networked ones)
+                            Thread.Sleep(initDeviceWaitTimeout * (retries + 1));
                         }
                         else
                         {
-                            MessageCentre.InternalErrorWriteLine($"Device is running CLR, requesting reboot and pause for debugger ({retries + 1}/{ maxOperationRetries }).");
-
-                            _engine.RebootDevice(RebootOptions.ClrOnly | RebootOptions.WaitForDebugger);
-
-                            Thread.Sleep(500);
+                            MessageCentre.InternalErrorWriteLine("*** ERROR: device is running on an unknown state ***");
+
+                            // unknown connection source?!
+                            // shouldn't be here, but...
+                            // ...maybe this is caused by a comm timeout because the target is rebooting
                         }
-                    }
-                    else if (_engine.IsConnectedTonanoBooter)
-                    {
-                        MessageCentre.InternalErrorWriteLine($"Device is running nanoBooter, requesting to launch CLR ({retries + 1}/{ maxOperationRetries }).");
-
-                        // this is telling nanoBooter to enter CLR
-                        _engine.ExecuteMemory(0);
-
-                        Thread.Yield();
-
-                        // better pause here to allow the reboot to occur
-                        // use a back-off strategy of increasing the wait time to accommodate slower or less responsive targets (such as networked ones)
-                        Thread.Sleep(initDeviceWaitTimeout * (retries + 1));
-                    }
-                    else
-                    {
-                        MessageCentre.InternalErrorWriteLine("*** ERROR: device is running on an unknown state ***");
-
-                        // unknown connection source?!
-                        // shouldn't be here, but...
-                        // ...maybe this is caused by a comm timeout because the target is rebooting
                     }

                     Thread.Yield();
@@ -447,23 +454,26 @@
                         _engine.OnProcessExit += new EventHandler(OnProcessExit);
                     }

-                    if(!_engine.IsConnected)
-                    {
-                        _engine.Connect();
-                    }
-
-                    if (_engine.UpdateDebugFlags())
-                    {
-                        _engine.ThrowOnCommunicationFailure = true;
-
-                        break;
+                    if (_engine.Connect(true))
+                    {
+                        Thread.Yield();
+
+                        if (_engine.UpdateDebugFlags())
+                        {
+                            Thread.Yield();
+
+                            _engine.ThrowOnCommunicationFailure = true;
+
+                            break;
+                        }
+                        else
+                        {
+                            MessageCentre.InternalErrorWriteLine($"*** ERROR: updating debugger flags of device ***");
+                        }
                     }
                     else
                     {
-                        MessageCentre.InternalErrorWriteLine($"*** ERROR: updating debugger flags of device ***");
-
-                        // reset flag
-                        _engine.StopDebuggerOnConnect = false;
+                        Thread.Sleep(500);
                     }

                     Thread.Yield();
@@ -661,7 +671,10 @@
                 else
                 {
                     IsExecutionPaused = false;
+
                     PauseExecution();
+
+                    Thread.Yield();

                     UpdateAssemblies();
                     UpdateThreadList();
@@ -735,7 +748,9 @@
             try
             {
                 if (_pid == 0)
+                {
                     throw new Exception(Resources.ResourceStrings.BogusCorDebugProcess);
+                }

                 Init(corDebug, fLaunch);

@@ -1636,7 +1651,7 @@
                     //nop
                     break;
                 default:
-                    MessageCentre.InternalErrorMessage(false, "Unexpected command=" + msg.Header.Cmd);
+                    MessageCentre.InternalErrorMessage(false, "Unexpected command=" + GetCommandName(msg.Header.Cmd));
                     break;
             }
         }
@@ -2364,5 +2379,26 @@
         {
             MessageCentre.InternalErrorMessage(condition, message);
         }
+
+        private string GetCommandName(uint cmd)
+        {
+            switch(cmd)
+            {
+                case Commands.c_Debugging_Execution_BreakpointStatus:
+                    return "BreakpointStatus";
+
+                case Commands.c_Debugging_Execution_QueryCLRCapabilities:
+                    return "QueryCLRCapabilities";
+
+                case Commands.c_Debugging_Execution_Allocate:
+                    return "Allocate";
+
+                case Commands.c_Debugging_Execution_ChangeConditions:
+                    return "ChangeConditions";
+
+                default:
+                    return $"0x{cmd:X8}";
+           }
+        }
     }
 }


Add UI scale option to options menu.

Add UI scale option to options menu.

--- Content.Client/UserInterface/OptionsMenu.Graphics.cs
+++ Content.Client/UserInterface/OptionsMenu.Graphics.cs
@@ -5,6 +5,7 @@
 using Robust.Shared.Interfaces.Configuration;
 using Robust.Shared.IoC;
 using Robust.Shared.Localization;
+using Robust.Shared.Maths;

 namespace Content.Client.UserInterface
 {
@@ -12,13 +13,24 @@
     {
         private sealed class GraphicsControl : Control
         {
+            private static readonly float[] UIScaleOptions =
+            {
+                0f,
+                0.75f,
+                1f,
+                1.25f,
+                1.50f,
+                1.75f,
+                2f
+            };
+
             private readonly IConfigurationManager _cfg;

             private readonly Button ApplyButton;
             private readonly CheckBox VSyncCheckBox;
             private readonly CheckBox FullscreenCheckBox;
             private readonly OptionButton LightingPresetOption;
-
+            private readonly OptionButton _uiScaleOption;

             public GraphicsControl(IConfigurationManager cfg)
             {
@@ -42,7 +54,7 @@
                 LightingPresetOption.AddItem(Loc.GetString("High"));
                 LightingPresetOption.OnItemSelected += OnLightingQualityChanged;

-                var lightingHBox = new HBoxContainer
+                contents.AddChild(new HBoxContainer
                 {
                     Children =
                     {
@@ -50,8 +62,7 @@
                         new Control {CustomMinimumSize = (4, 0)},
                         LightingPresetOption
                     }
-                };
-                contents.AddChild(lightingHBox);
+                });

                 ApplyButton = new Button
                 {
@@ -61,10 +72,24 @@

                 var resourceCache = IoCManager.Resolve<IResourceCache>();

-                contents.AddChild(new Placeholder(resourceCache)
-                {
-                    SizeFlagsVertical = SizeFlags.FillExpand,
-                    PlaceholderText = "UI Scaling"
+                _uiScaleOption = new OptionButton();
+                _uiScaleOption.AddItem(Loc.GetString("Automatic ({0}%)", UserInterfaceManager.DefaultUIScale * 100));
+                _uiScaleOption.AddItem(Loc.GetString("75%"));
+                _uiScaleOption.AddItem(Loc.GetString("100%"));
+                _uiScaleOption.AddItem(Loc.GetString("125%"));
+                _uiScaleOption.AddItem(Loc.GetString("150%"));
+                _uiScaleOption.AddItem(Loc.GetString("175%"));
+                _uiScaleOption.AddItem(Loc.GetString("200%"));
+                _uiScaleOption.OnItemSelected += OnUIScaleChanged;
+
+                contents.AddChild(new HBoxContainer
+                {
+                    Children =
+                    {
+                        new Label {Text = Loc.GetString("UI Scale:")},
+                        new Control {CustomMinimumSize = (4, 0)},
+                        _uiScaleOption
+                    }
                 });

                 contents.AddChild(new Placeholder(resourceCache)
@@ -99,9 +124,15 @@
                 VSyncCheckBox.Pressed = _cfg.GetCVar<bool>("display.vsync");
                 FullscreenCheckBox.Pressed = ConfigIsFullscreen;
                 LightingPresetOption.SelectId(GetConfigLightingQuality());
-
+                _uiScaleOption.SelectId(GetConfigUIScalePreset(ConfigUIScale));

                 AddChild(vBox);
+            }
+
+            private void OnUIScaleChanged(OptionButton.ItemSelectedEventArgs args)
+            {
+                _uiScaleOption.SelectId(args.Id);
+                UpdateApplyButton();
             }

             private void OnApplyButtonPressed(BaseButton.ButtonEventArgs args)
@@ -110,6 +141,7 @@
                 SetConfigLightingQuality(LightingPresetOption.SelectedId);
                 _cfg.SetCVar("display.windowmode",
                     (int) (FullscreenCheckBox.Pressed ? WindowMode.Fullscreen : WindowMode.Windowed));
+                _cfg.SetCVar("display.uiScale", UIScaleOptions[_uiScaleOption.SelectedId]);
                 _cfg.SaveToFile();
                 UpdateApplyButton();
             }
@@ -130,11 +162,14 @@
                 var isVSyncSame = VSyncCheckBox.Pressed == _cfg.GetCVar<bool>("display.vsync");
                 var isFullscreenSame = FullscreenCheckBox.Pressed == ConfigIsFullscreen;
                 var isLightingQualitySame = LightingPresetOption.SelectedId == GetConfigLightingQuality();
-                ApplyButton.Disabled = isVSyncSame && isFullscreenSame && isLightingQualitySame;
+                var isUIScaleSame = MathHelper.CloseTo(UIScaleOptions[_uiScaleOption.SelectedId], ConfigUIScale);
+                ApplyButton.Disabled = isVSyncSame && isFullscreenSame && isLightingQualitySame && isUIScaleSame;
             }

             private bool ConfigIsFullscreen =>
                 _cfg.GetCVar<int>("display.windowmode") == (int) WindowMode.Fullscreen;
+
+            private float ConfigUIScale => _cfg.GetCVar<float>("display.uiScale");

             private int GetConfigLightingQuality()
             {
@@ -180,6 +215,19 @@
                         break;
                 }
             }
+
+            private static int GetConfigUIScalePreset(float value)
+            {
+                for (var i = 0; i < UIScaleOptions.Length; i++)
+                {
+                    if (MathHelper.CloseTo(UIScaleOptions[i], value))
+                    {
+                        return i;
+                    }
+                }
+
+                return 0;
+            }
         }
     }
 }