Binding list- add safety catch for threading issues

--- Source/Engine/AGS.Engine/Misc/Collection/AGSBindingList.cs
+++ Source/Engine/AGS.Engine/Misc/Collection/AGSBindingList.cs
@@ -2,6 +2,7 @@
 using System.Collections.Generic;
 using System.Collections;
 using AGS.API;
+using System.Diagnostics;

 namespace AGS.Engine
 {
@@ -93,8 +94,20 @@
 		public bool Remove(TItem item)
 		{
 			int index = IndexOf(item);
-			if (index < 0) return false;
-			_list.RemoveAt(index);
+            if (index < 0) return false;
+            try
+            {
+                _list.RemoveAt(index);
+            }
+            catch (ArgumentOutOfRangeException e)
+            {
+                if (Repeat.LessThan("AGSBindingList.Remove Exception", 5))
+                {
+                    Debug.WriteLine("Tried to remove an already removed item from the binding list. Item: {0}, Exception: {1}",
+                                    item, e);
+                }
+                return false;
+            }
 			onListChanged(item, index, ListChangeType.Remove);
 			return true;
 		}


GSF.Web: Fixed errors handling authentication failures in IIS-hosted apps.

--- Source/Libraries/GSF.Web/Security/AuthenticationHandler.cs
+++ Source/Libraries/GSF.Web/Security/AuthenticationHandler.cs
@@ -226,8 +226,9 @@
                         currentIdentity = AdjustedUserName(originalPrincpal.Identity.Name);
                 }

+                bool debuggable = Common.GetApplicationType() != ApplicationType.Web && AssemblyInfo.EntryAssembly.Debuggable;
                 Response.Headers.Add("CurrentIdentity", new[] { currentIdentity });
-                Response.ReasonPhrase = SecurityPrincipal.GetFailureReasonPhrase(securityPrincipal, AuthorizationHeader?.Scheme, AssemblyInfo.EntryAssembly.Debuggable);
+                Response.ReasonPhrase = SecurityPrincipal.GetFailureReasonPhrase(securityPrincipal, AuthorizationHeader?.Scheme, debuggable);

                 return true; // Abort pipeline
             });


Removed KendoHelpers.cs

Removed KendoHelpers.cs


Refactoring: simplified use of RhetosTestContainer.

--- Source/Rhetos.Configuration.Autofac/RhetosTestContainer.cs
+++ Source/Rhetos.Configuration.Autofac/RhetosTestContainer.cs
@@ -100,7 +100,7 @@
                 && File.Exists(Path.Combine(path, @"bin\Rhetos.dll"));
         }

-        protected virtual string SearchForRhetosServerRootFolder()
+        protected string SearchForRhetosServerRootFolder()
         {
             if (_explicitRhetosServerFolder != null)
                 return _explicitRhetosServerFolder;
@@ -149,7 +149,7 @@
             return container;
         }

-        protected virtual Assembly SearchForAssembly(object sender, ResolveEventArgs args)
+        protected Assembly SearchForAssembly(object sender, ResolveEventArgs args)
         {
             foreach (var folder in new[] { Paths.PluginsFolder, Paths.GeneratedFolder, Paths.BinFolder })
             {


paranoia

paranoia

--- Source/AirBreather.Common/AirBreather.Common.Tests/Rfc4180CsvHelperTests.cs
+++ Source/AirBreather.Common/AirBreather.Common.Tests/Rfc4180CsvHelperTests.cs
@@ -30,7 +30,7 @@
                 new[] { string.Empty, string.Empty, string.Empty, string.Empty },
                 new[] { "asdf" },
             };
-            using (var stream = new MemoryStream(bytes))
+            using (var stream = new MemoryStream(bytes, 0, bytes.Length, writable: false, publiclyVisible: false))
             {
                 int i = 0;
                 Rfc4180CsvHelper.ReadUtf8CsvFile(stream, row => Do(row, expectedRows[i++]));
@@ -63,7 +63,7 @@
             byte[] bytes = new byte[7654321];
             bytes[bytes.Length - 1] = (byte)',';

-            using (var stream = new MemoryStream(bytes))
+            using (var stream = new MemoryStream(bytes, 0, bytes.Length, writable: false, publiclyVisible: false))
             {
                 int calledAlready = 0;
                 Rfc4180CsvHelper.ReadUtf8CsvFile(stream, row =>


Exclude AnalyzerConstants.DisabledNoTests from code coverage

--- StyleCop.Analyzers/StyleCop.Analyzers/AnalyzerConstants.cs
+++ StyleCop.Analyzers/StyleCop.Analyzers/AnalyzerConstants.cs
@@ -3,6 +3,7 @@

 namespace StyleCop.Analyzers
 {
+    using System.Diagnostics.CodeAnalysis;
     using Microsoft.CodeAnalysis;

     internal static class AnalyzerConstants
@@ -27,6 +28,7 @@
         /// <see cref="DiagnosticDescriptor(string, string, string, string, DiagnosticSeverity, bool, string, string, string[])"/>
         /// to disable a diagnostic which is currently untested.
         /// </value>
+        [ExcludeFromCodeCoverage]
         internal static bool DisabledNoTests { get; }

         /// <summary>


sealing the leaf entry classes

sealing the leaf entry classes

--- src/ImTools/ImTools.cs
+++ src/ImTools/ImTools.cs
@@ -1847,23 +1847,23 @@
         /// Constructs the entry with the value
         protected ImHashMapEntry(int hash, V value) : base(hash) => Value = value;

-        /// <inheritdoc />
-        public sealed override int Count() => 1;
-
-        internal override int ForEach<S>(S state, int startIndex, Action<ImHashMapEntry<K, V>, int, S> handler)
-        {
-            handler(this, startIndex, state);
-            return startIndex + 1;
-        }
-
 #if !DEBUG
         /// <inheritdoc />
         public override string ToString() => "{K:" + Key + ",V:" + Value + "}";
 #endif
+
+        /// <inheritdoc />
+        public sealed override int Count() => 1;
+
+        internal override int ForEach<S>(S state, int startIndex, Action<ImHashMapEntry<K, V>, int, S> handler)
+        {
+            handler(this, startIndex, state);
+            return startIndex + 1;
+        }
     }

     /// Entry containing the Value in addition to the Hash
-    public class VEntry<V> : ImHashMapEntry<int, V>
+    public sealed class VEntry<V> : ImHashMapEntry<int, V>
     {
         /// The Key is actually the Hash for this entry and the vice versa.
         public override int Key => Hash;
@@ -1892,7 +1892,7 @@
     }

     /// Entry containing the Key and Value in addition to the Hash
-    public class KVEntry<K, V> : ImHashMapEntry<K, V>
+    public sealed class KVEntry<K, V> : ImHashMapEntry<K, V>
     {
         /// The key
         public override K Key => _key;
@@ -1902,6 +1902,11 @@
         public KVEntry(int hash, K key) : base(hash) => _key = key;
         /// Constructs the entry with the key and value
         public KVEntry(int hash, K key, V value) : base(hash, value) => _key = key;
+
+#if !DEBUG
+        /// <inheritdoc />
+        public override string ToString() => "{H: " + Hash + ", K: " + Key + ", V: " + Value + "}";
+#endif

         internal override ImHashMapEntry<K, V> GetOrNull(K key) =>
             _key.Equals(key) ? this : null;
@@ -1950,11 +1955,6 @@
             !Key.Equals(newEntry.Key)
                 ? new HashConflictingEntry(Hash, this, newEntry)
                 : updateOrKeep(state, this, newEntry) != this ? newEntry : this;
-
-#if !DEBUG
-        /// <inheritdoc />
-        public override string ToString() => "{H: " + Hash + ", K: " + Key + ", V: " + Value + "}";
-#endif
     }

     /// The base and the holder class for the map tree leafs and branches, also defines the Empty tree.


Modified DataCacheItem class

Modified DataCacheItem class

--- src/DataCacheItem.cs
+++ src/DataCacheItem.cs
@@ -1,18 +1,10 @@
 using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
 using System.Collections.ObjectModel;

 namespace Alachisoft.NCache.Data.Caching
 {
     public class DataCacheItem
     {
-        #region[    Constructor ]
-        public DataCacheItem()
-        { }
-        #endregion
-
         public string CacheName { get; internal set; }
         public string Key { get; internal set; }
         public string RegionName { get; internal set; }
@@ -20,7 +12,5 @@
         public TimeSpan Timeout { get; internal set; }
         public object Value { get; internal set; }
         public DataCacheItemVersion Version { get; internal set; }
-
-
     }
 }


Clarify [MonotonicVersioner] constructor requirements.

--- libSemVer.NET/Monotonic/MonotonicVersioner.cs
+++ libSemVer.NET/Monotonic/MonotonicVersioner.cs
@@ -158,6 +158,10 @@
         /// A collection of version numbers providing the version
         /// history to use for this instance.
         /// </param>
+        /// <remarks>
+        /// <paramref name="chronology"/> is not required to be
+        /// in order.
+        /// </remarks>
         /// <exception cref="ArgumentNullException">
         /// <paramref name="chronology"/> or an item thereof is null.
         /// </exception>


Update LinearAnimation.cs

Update LinearAnimation.cs

use ObservableHelper method for WithPrevious rather than a private implementation

--- src/LinearAnimation.cs
+++ src/LinearAnimation.cs
@@ -53,8 +53,9 @@
 			if (cts == null)
 				cts = new CancellationTokenSource();

-			relativeTo.DistinctUntilChanged()
-			.WithPrevious((prev, current) => new { prev, current })
+			ObservableHelper.ObserveWithPrevious(
+				relativeTo.DistinctUntilChanged(),
+				(prev, current) => new { prev, current })
 			.Skip(1) // ignore first value where there is no previous
 			.ObserveOn(ctrl).Subscribe(v => {
 				if (v.prev != v.current) {
@@ -71,11 +72,5 @@
 			}, cts.Token);
 			return cts;
 		}
-
-		private static IObservable<TOutput> WithPrevious<TSource, TOutput> (this IObservable<TSource> source, Func<TSource, TSource, TOutput> projection) {
-			return source.Scan(Tuple.Create(default(TSource), default(TSource)),
-				(previous, current) => Tuple.Create(previous.Item2, current))
-					.Select(t => projection(t.Item1, t.Item2));
-		}
 	}
 }


better error reporting

better error reporting

--- src/otchanger/App.cs
+++ src/otchanger/App.cs
@@ -71,7 +71,7 @@
             }
             catch (Exception ex)
             {
-                Console.WriteLine(ex);
+                showException(ex);
             }
         }

@@ -83,8 +83,17 @@
             }
             catch (Exception ex)
             {
+                showException(ex);
+            }
+        }
+
+        static void showException(Exception ex)
+        {
+            do
+            {
                 Console.WriteLine(ex);
-            }
+                ex = ex.InnerException;
+            } while (ex != null);
         }

         public static string exportAssemblies()


made the test cases work

made the test cases work

--- src/NRack.Test/Test.cs
+++ src/NRack.Test/Test.cs
@@ -64,7 +64,7 @@
         {
             StartStopWrap(() =>
             {
-                Thread.Sleep(1000 * 60 * 5);
+                //Thread.Sleep(1000 * 60 * 5);
             });
         }
     }


Remover limitação do campos objetivo, conforme imagem em anexo. - correção de bug - #20000006-1926

--- Src/MSTech.GestaoEscolar.DAL/Abstracts/Abstract_ACA_CurriculoCapituloDAO.cs
+++ Src/MSTech.GestaoEscolar.DAL/Abstracts/Abstract_ACA_CurriculoCapituloDAO.cs
@@ -208,15 +208,13 @@

                 Param = qs.NewParameter();
                 Param.DbType = DbType.String;
-                Param.ParameterName = "@crc_titulo";
-                Param.Size = 200;
+                Param.ParameterName = "@crc_titulo";
                 Param.Value = entity.crc_titulo;
                 qs.Parameters.Add(Param);

                 Param = qs.NewParameter();
                 Param.DbType = DbType.String;
-                Param.ParameterName = "@crc_descricao";
-                Param.Size = 4000;
+                Param.ParameterName = "@crc_descricao";
                 if (!string.IsNullOrEmpty(entity.crc_descricao))
                 {
                     Param.Value = entity.crc_descricao;


threadingissue with more information

threadingissue with more information

--- Tasks/SynchronizationSamples/ThreadingIssues/SampleTask.cs
+++ Tasks/SynchronizationSamples/ThreadingIssues/SampleTask.cs
@@ -19,7 +19,7 @@
                     if (_state != 6)
                     {
                         Console.WriteLine($"Race condition occured after {loop} loops");
-                        Trace.Fail("race condition");
+                        Trace.Fail($"race condition at {loop}");
                     }
                 }
                 _state = 5;


Update SmallAppliances.cs

Update SmallAppliances.cs

--- TeamworkStarFruit/CatalogueLib/Products/SmallAppliances.cs
+++ TeamworkStarFruit/CatalogueLib/Products/SmallAppliances.cs
@@ -1,6 +1,8 @@
 namespace CatalogueLib
 {
+    using System.Text;
     using CatalogueLib.Products.Enumerations;
+

     public abstract class SmallAppliances : Product
     {


ArgumentOutOfRangeException ParamName and ActualValue.

--- Tests/Serilog.Exceptions.Test/ExceptionDestructurerTest.cs
+++ Tests/Serilog.Exceptions.Test/ExceptionDestructurerTest.cs
@@ -53,10 +53,24 @@
         }

         [Fact]
-        public void ArgumentNUllException_ParamNameIsAttachedAsProperty()
+        public void ArgumentNullException_ParamNameIsAttachedAsProperty()
         {
             var argumentException = new ArgumentNullException("testParamName", "MSG");
             Test_LoggedExceptionContainsProperty(argumentException, "ParamName", "testParamName");
+        }
+
+        [Fact]
+        public void ArgumentOfOutRangeException_ParamNameIsAttachedAsProperty()
+        {
+            var argumentException = new ArgumentOutOfRangeException("testParamName");
+            Test_LoggedExceptionContainsProperty(argumentException, "ParamName", "testParamName");
+        }
+
+        [Fact]
+        public void ArgumentOfOutRangeException_ActualValueIsAttachedAsProperty()
+        {
+            var argumentException = new ArgumentOutOfRangeException("testParamName", "ACTUAL_VALUE", "MSG");
+            Test_LoggedExceptionContainsProperty(argumentException, "ActualValue", "ACTUAL_VALUE");
         }

         private void Test_LoggedExceptionContainsProperty(Exception exception, string propertyKey, string propertyValue)


Add CancellationToken to Delete methods (#272)

--- src/Dommel/Delete.cs
+++ src/Dommel/Delete.cs
@@ -2,6 +2,7 @@
 using System.Data;
 using System.Linq;
 using System.Linq.Expressions;
+using System.Threading;
 using System.Threading.Tasks;
 using Dapper;

@@ -33,12 +34,13 @@
         /// <param name="connection">The connection to the database. This can either be open or closed.</param>
         /// <param name="entity">The entity to be deleted.</param>
         /// <param name="transaction">Optional transaction for the command.</param>
+        /// <param name="cancellationToken">Optional cancellation token for the command.</param>
         /// <returns>A value indicating whether the delete operation succeeded.</returns>
-        public static async Task<bool> DeleteAsync<TEntity>(this IDbConnection connection, TEntity entity, IDbTransaction? transaction = null)
+        public static async Task<bool> DeleteAsync<TEntity>(this IDbConnection connection, TEntity entity, IDbTransaction? transaction = null, CancellationToken cancellationToken = default)
         {
             var sql = BuildDeleteQuery(GetSqlBuilder(connection), typeof(TEntity));
             LogQuery<TEntity>(sql);
-            return await connection.ExecuteAsync(sql, entity, transaction) > 0;
+            return await connection.ExecuteAsync(new CommandDefinition(sql, entity, transaction: transaction, cancellationToken: cancellationToken)) > 0;
         }

         internal static string BuildDeleteQuery(ISqlBuilder sqlBuilder, Type type)
@@ -81,13 +83,14 @@
         /// <typeparam name="TEntity">The type of the entity.</typeparam>
         /// <param name="connection">The connection to the database. This can either be open or closed.</param>
         /// <param name="predicate">A predicate to filter which entities are deleted.</param>
-        /// <param name="transaction">Optional transaction for the command.</param>
+        /// <param name="transaction">Optional transaction for the command.</param>
+        /// <param name="cancellationToken">Optional cancellation token for the command.</param>
         /// <returns>The number of rows affected.</returns>
-        public static async Task<int> DeleteMultipleAsync<TEntity>(this IDbConnection connection, Expression<Func<TEntity, bool>> predicate, IDbTransaction? transaction = null)
+        public static async Task<int> DeleteMultipleAsync<TEntity>(this IDbConnection connection, Expression<Func<TEntity, bool>> predicate, IDbTransaction? transaction = null, CancellationToken cancellationToken = default)
         {
             var sql = BuildDeleteMultipleQuery(GetSqlBuilder(connection), predicate, out var parameters);
             LogQuery<TEntity>(sql);
-            return await connection.ExecuteAsync(sql, parameters, transaction);
+            return await connection.ExecuteAsync(new CommandDefinition(sql, parameters, transaction: transaction, cancellationToken: cancellationToken));
         }

         private static string BuildDeleteMultipleQuery<TEntity>(ISqlBuilder sqlBuilder, Expression<Func<TEntity, bool>> predicate, out DynamicParameters parameters)
@@ -125,12 +128,13 @@
         /// <typeparam name="TEntity">The type of the entity.</typeparam>
         /// <param name="connection">The connection to the database. This can either be open or closed.</param>
         /// <param name="transaction">Optional transaction for the command.</param>
+        /// <param name="cancellationToken">Optional cancellation token for the command.</param>
         /// <returns>The number of rows affected.</returns>
-        public static async Task<int> DeleteAllAsync<TEntity>(this IDbConnection connection, IDbTransaction? transaction = null)
+        public static async Task<int> DeleteAllAsync<TEntity>(this IDbConnection connection, IDbTransaction? transaction = null, CancellationToken cancellationToken = default)
         {
             var sql = BuildDeleteAllQuery(GetSqlBuilder(connection), typeof(TEntity));
             LogQuery<TEntity>(sql);
-            return await connection.ExecuteAsync(sql, transaction: transaction);
+            return await connection.ExecuteAsync(new CommandDefinition(sql, transaction: transaction, cancellationToken: cancellationToken));
         }

         internal static string BuildDeleteAllQuery(ISqlBuilder sqlBuilder, Type type)


Change the default from 'in' to 'square foot'

--- src/DrawIt/DrawIt.cs
+++ src/DrawIt/DrawIt.cs
@@ -246,7 +246,7 @@
             LoadUserPreferences();

             // Read the configuration defaults from the app.config.
-            string unit = Configuration.GetSetting(Constants.Document.MeasurementUnit) ?? "in";
+            string unit = Configuration.GetSetting(Constants.Document.MeasurementUnit) ?? "square foot";
             float conversionRate = Configuration.GetSettingOrDefault<float>(Constants.Document.ConversionRate, float.TryParse, 1);

             CreateNewDocument(new Drawing(conversionRate, unit));


キャストする前にisで型を確認する

キャストする前にisで型を確認する

--- Whitebell.Library/Collections/Generic/OrderedDictionary.cs
+++ Whitebell.Library/Collections/Generic/OrderedDictionary.cs
@@ -432,22 +432,12 @@
             if (value == null && default(TValue) != null) // TValue is struct.
                 throw new ArgumentNullException(nameof(value));

-            try
-            {
-                var tkey = (TKey)key;
-                try
-                {
-                    Add(tkey, (TValue)value);
-                }
-                catch (InvalidCastException)
-                {
-                    throw new ArgumentException(nameof(value));
-                }
-            }
-            catch (InvalidCastException)
-            {
+            if (!(key is TKey tk))
                 throw new ArgumentException(nameof(key));
-            }
+            if (!(value is TValue tv))
+                throw new ArgumentException(nameof(value));
+
+            Add(tk, tv);
         }

         bool IDictionary.Contains(object key)
@@ -535,9 +525,9 @@
             {
                 if (key == null)
                     throw new ArgumentNullException(nameof(key));
-                var k = (TKey)key;
-                if (dic.ContainsKey(k))
-                    return dic[k];
+
+                if (key is TKey tk && dic.ContainsKey(tk))
+                    return dic[tk];
                 return null;
             }
             set
@@ -547,23 +537,13 @@
                 if (value == null && default(TValue) != null) // TValue is struct.
                     throw new ArgumentNullException(nameof(value));

-                try
-                {
-                    var k = (TKey)key;
-                    try
-                    {
-                        this[k] = (TValue)value;
-                        version++;
-                    }
-                    catch (InvalidCastException)
-                    {
-                        throw new ArgumentException(nameof(value));
-                    }
-                }
-                catch (InvalidCastException)
-                {
+                if (!(key is TKey tk))
                     throw new ArgumentException(nameof(key));
-                }
+                if (!(value is TValue tv))
+                    throw new ArgumentException(nameof(value));
+
+                this[tk] = tv;
+                version++;
             }
         }

@@ -574,15 +554,12 @@
             {
                 if (value == null && default(TValue) != null) // TValue is struct.
                     throw new ArgumentNullException(nameof(value));
-                try
-                {
-                    this[index] = (TValue)value;
-                    version++;
-                }
-                catch (InvalidCastException)
-                {
+
+                if (!(value is TValue tv))
                     throw new ArgumentException(nameof(value));
-                }
+
+                this[index] = tv;
+                version++;
             }
         }

@@ -594,26 +571,15 @@
                 throw new ArgumentNullException(nameof(key));
             if (value == null && default(TValue) != null) // TValue is struct.
                 throw new ArgumentNullException(nameof(value));
-            try
-            {
-                var k = (TKey)key;
-                if (dic.ContainsKey(k))
-                    throw new ArgumentException(nameof(key));
-
-                try
-                {
-                    var v = (TValue)value;
-                    Insert(index, k, v);
-                }
-                catch (InvalidCastException)
-                {
-                    throw new ArgumentException(nameof(value));
-                }
-            }
-            catch (InvalidCastException)
-            {
+
+            if (!(key is TKey tk))
                 throw new ArgumentException(nameof(key));
-            }
+            if (dic.ContainsKey(tk))
+                throw new ArgumentException(nameof(key));
+            if (!(value is TValue tv))
+                throw new ArgumentException(nameof(value));
+
+            Insert(index, tk, tv);
         }

         IDictionaryEnumerator IOrderedDictionary.GetEnumerator() => GetEnumerator();


CA-286291: Fix the crash when quickly and repeatedly popping up Migrate-to-Server menu (#2018)

* CA-286291: Fix the crash when quickly and repeatedly popping up Migrate-to-Server menu.

* Update the thread model.

Signed-off-by: Michael Zhao <3ffa692bbf15c143ce22e6ed3df1b17f93ab8f33@citrix.com>

* Fix an error in using _stopped flag.

--- XenAdmin/Commands/Controls/VMOperationToolStripMenuItem.cs
+++ XenAdmin/Commands/Controls/VMOperationToolStripMenuItem.cs
@@ -55,8 +55,8 @@
     {
         private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
         private readonly vm_operations _operation;
-        private ProduceConsumerQueue workerQueueWithouWlb;
         private readonly bool _resumeAfter;
+        private HostListUpdater hostListUpdater;

         protected VMOperationToolStripMenuItem(Command command, bool inContextMenu, vm_operations operation)
             : base(command, inContextMenu)
@@ -73,19 +73,16 @@
             base.DropDownItems.Add(new ToolStripMenuItem());
         }

-        private bool _isDropDownClosed;
-
         protected override void OnDropDownClosed(EventArgs e)
         {
             base.OnDropDownClosed(e);
-            workerQueueWithouWlb.CancelWorkers(false);
-            _isDropDownClosed = true;
+            hostListUpdater.Stop();
         }
+

         protected override void OnDropDownOpening(EventArgs e)
         {
             base.DropDownItems.Clear();
-            _isDropDownClosed = false;

             // Work around bug in tool kit where disabled menu items show their dropdown menus
             if (!Enabled)
@@ -110,7 +107,6 @@
                 base.DropDownItems.Add(new VMOperationToolStripMenuSubItem(Messages.HOME_SERVER_MENU_ITEM, Images.StaticImages._000_ServerHome_h32bit_16));
             }

-            workerQueueWithouWlb = new ProduceConsumerQueue(25);
             List<Host> hosts = new List<Host>(connection.Cache.Hosts);
             hosts.Sort();
             foreach (Host host in hosts)
@@ -120,210 +116,277 @@
                 base.DropDownItems.Add(item);
             }

-            // start a new thread to evaluate which hosts can be used.
-            ThreadPool.QueueUserWorkItem(delegate
-            {
-                SelectedItemCollection selection = Command.GetSelection();
-                Session session = selection[0].Connection.DuplicateSession();
-                if (Helpers.WlbEnabled(selection[0].Connection))
-                {
-                    WlbRecommendations recommendations = new WlbRecommendations(selection.AsXenObjects<VM>(), session);
-                    recommendations.Initialize();
-
-                    if (recommendations.IsError)
-                        EnableAppropriateHostsNoWlb(session);
+            SelectedItemCollection selection = Command.GetSelection();
+            Session session = selection[0].Connection.DuplicateSession();
+
+            hostListUpdater = new HostListUpdater();
+            hostListUpdater.updateHostList(this, session);
+
+        }
+
+        /// <summary>
+        /// Hook to add additional members to the menu item
+        /// Note: Called on main window thread by executing code
+        /// </summary>
+        /// <param name="selection"></param>
+        protected virtual void AddAdditionalMenuItems(SelectedItemCollection selection) { return; }
+
+        private class HostListUpdater
+        {
+            private ProduceConsumerQueue workerQueueWithoutWlb;
+            readonly object _locker = new object();
+            private bool _stopped;
+
+            private bool Stopped
+            {
+                set
+                {
+                    lock (_locker)
+                    {
+                        _stopped = value;
+                    }
+                }
+                get
+                {
+                    lock (_locker)
+                    {
+                        return _stopped;
+                    }
+                }
+            }
+
+            public void Stop()
+            {
+                Stopped = true;
+                if (workerQueueWithoutWlb != null)
+                    workerQueueWithoutWlb.CancelWorkers(false);
+            }
+
+            public void updateHostList(VMOperationToolStripMenuItem menu, Session session)
+            {
+                Stopped = false;
+
+                ThreadPool.QueueUserWorkItem(delegate
+                {
+                    if (Stopped)
+                        return;
+
+                    SelectedItemCollection selection = menu.Command.GetSelection();
+                    if (Helpers.WlbEnabled(selection[0].Connection))
+                    {
+                        WlbRecommendations recommendations = new WlbRecommendations(selection.AsXenObjects<VM>(), session);
+                        recommendations.Initialize();
+                        if (Stopped)
+                            return;
+
+                        if (recommendations.IsError)
+                            EnableAppropriateHostsNoWlb(menu, session);
+                        else
+                            EnableAppropriateHostsWlb(menu, session, recommendations);
+                    }
                     else
-                        EnableAppropriateHostsWlb(session, recommendations);
-                }
-                else
-                {
-                    EnableAppropriateHostsNoWlb(session);
-                }
-            });
-        }
-
-        private void EnableAppropriateHostsWlb(Session session, WlbRecommendations recommendations)
-        {
-            SelectedItemCollection selection = Command.GetSelection();
-            // set the first menu item to be the WLB optimal server menu item
-            VMOperationToolStripMenuSubItem firstItem = (VMOperationToolStripMenuSubItem)base.DropDownItems[0];
-            var firstItemCmd = new VMOperationWlbOptimalServerCommand(Command.MainWindowCommandInterface, selection, _operation, recommendations);
-            var firstItemCmdCanExecute = firstItemCmd.CanExecute();
-
-            Program.Invoke(Program.MainWindow, delegate
-            {
-                firstItem.Command = firstItemCmd;
-                firstItem.Enabled = firstItemCmdCanExecute;
-            });
-
-            List<VMOperationToolStripMenuSubItem> hostMenuItems = new List<VMOperationToolStripMenuSubItem>();
-            foreach (VMOperationToolStripMenuSubItem item in base.DropDownItems)
-            {
-                Host host = item.Tag as Host;
-                if (host != null)
-                {
-                    var cmd = new VMOperationWlbHostCommand(Command.MainWindowCommandInterface, selection, host, _operation, recommendations.GetStarRating(host));
-                    var canExecute = cmd.CanExecute();
-
-                    Program.Invoke(Program.MainWindow, delegate
-                    {
-                        item.Command = cmd;
-                        item.Enabled = canExecute;
+                    {
+                        EnableAppropriateHostsNoWlb(menu, session);
+                    }
+                });
+            }
+
+            private void EnableAppropriateHostsWlb(VMOperationToolStripMenuItem menu, Session session, WlbRecommendations recommendations)
+            {
+                SelectedItemCollection selection = menu.Command.GetSelection();
+                // set the first menu item to be the WLB optimal server menu item
+                VMOperationToolStripMenuSubItem firstItem = (VMOperationToolStripMenuSubItem)menu.DropDownItems[0];
+                var firstItemCmd = new VMOperationWlbOptimalServerCommand(menu.Command.MainWindowCommandInterface, selection, menu._operation, recommendations);
+                var firstItemCmdCanExecute = firstItemCmd.CanExecute();
+
+                if (Stopped)
+                    return;
+
+                Program.Invoke(Program.MainWindow, delegate
+                {
+                    firstItem.Command = firstItemCmd;
+                    firstItem.Enabled = firstItemCmdCanExecute;
+                });
+
+                List<VMOperationToolStripMenuSubItem> hostMenuItems = new List<VMOperationToolStripMenuSubItem>();
+                foreach (VMOperationToolStripMenuSubItem item in menu.DropDownItems)
+                {
+                    Host host = item.Tag as Host;
+                    if (host != null)
+                    {
+                        var cmd = new VMOperationWlbHostCommand(menu.Command.MainWindowCommandInterface, selection, host, menu._operation, recommendations.GetStarRating(host));
+                        var canExecute = cmd.CanExecute();
+
+                        if (Stopped)
+                            return;
+
+                        Program.Invoke(Program.MainWindow, delegate
+                        {
+                            item.Command = cmd;
+                            item.Enabled = canExecute;
+                        });
+                        hostMenuItems.Add(item);
+                    }
+                }
+
+                // Shuffle the list to make it look cool
+                // Helpers.ShuffleList(hostMenuItems);
+
+                // sort the hostMenuItems by star rating
+                hostMenuItems.Sort(new WlbHostStarCompare());
+
+                // refresh the drop-down-items from the menuItems.
+                foreach (VMOperationToolStripMenuSubItem menuItem in hostMenuItems)
+                {
+                    if (Stopped)
+                        return;
+
+                    Program.Invoke(Program.MainWindow, delegate ()
+                    {
+                        menu.DropDownItems.Insert(hostMenuItems.IndexOf(menuItem) + 1, menuItem);
                     });
-                    hostMenuItems.Add(item);
-                }
-            }
-
-            // Shuffle the list to make it look cool
-            // Helpers.ShuffleList(hostMenuItems);
-
-            // sort the hostMenuItems by star rating
-            hostMenuItems.Sort(new WlbHostStarCompare());
-
-            // refresh the drop-down-items from the menuItems.
-            foreach (VMOperationToolStripMenuSubItem menuItem in hostMenuItems)
-            {
-                Program.Invoke(Program.MainWindow, delegate()
-                {
-                    base.DropDownItems.Insert(hostMenuItems.IndexOf(menuItem) + 1, menuItem);
-                });
-            }
-
-            Program.Invoke(Program.MainWindow, () => AddAdditionalMenuItems(selection));
-
-        }
-
-        private void EnableAppropriateHostsNoWlb(Session session)
-        {
-            SelectedItemCollection selection = Command.GetSelection();
-            IXenConnection connection = selection[0].Connection;
-
-            VMOperationCommand cmdHome = new VMOperationHomeServerCommand(Command.MainWindowCommandInterface, selection, _operation, session);
-            Host affinityHost = connection.Resolve(((VM)Command.GetSelection()[0].XenObject).affinity);
-
-            Program.Invoke(Program.MainWindow, delegate
-            {
-                var firstItem = (VMOperationToolStripMenuSubItem)base.DropDownItems[0];
-
-                bool oldMigrateToHomeCmdCanRun = cmdHome.CanExecute();
-                if (affinityHost == null || _operation == vm_operations.start_on || oldMigrateToHomeCmdCanRun)
-                {
-                    firstItem.Command = cmdHome;
-                    firstItem.Enabled = oldMigrateToHomeCmdCanRun;
-                }
-                else
-                {
-                    VMOperationCommand cpmCmdHome = new CrossPoolMigrateToHomeCommand(Command.MainWindowCommandInterface, selection, affinityHost);
-
-                    if (cpmCmdHome.CanExecute())
-                    {
-                        firstItem.Command = cpmCmdHome;
-                        firstItem.Enabled = true;
+                }
+
+                if (Stopped)
+                    return;
+
+                Program.Invoke(Program.MainWindow, () => menu.AddAdditionalMenuItems(selection));
+
+            }
+
+            private void EnableAppropriateHostsNoWlb(VMOperationToolStripMenuItem menu, Session session)
+            {
+                SelectedItemCollection selection = menu.Command.GetSelection();
+                IXenConnection connection = selection[0].Connection;
+                workerQueueWithoutWlb = new ProduceConsumerQueue(25);
+                VMOperationCommand cmdHome = new VMOperationHomeServerCommand(menu.Command.MainWindowCommandInterface, selection, menu._operation, session);
+                Host affinityHost = connection.Resolve(((VM)menu.Command.GetSelection()[0].XenObject).affinity);
+
+                if (Stopped)
+                    return;
+
+                Program.Invoke(Program.MainWindow, delegate
+                {
+                    var firstItem = (VMOperationToolStripMenuSubItem)menu.DropDownItems[0];
+
+                    bool oldMigrateToHomeCmdCanRun = cmdHome.CanExecute();
+                    if (affinityHost == null || menu._operation == vm_operations.start_on || oldMigrateToHomeCmdCanRun)
+                    {
+                        firstItem.Command = cmdHome;
+                        firstItem.Enabled = oldMigrateToHomeCmdCanRun;
                     }
                     else
                     {
-                        firstItem.Command = cmdHome;
-                        firstItem.Enabled = false;
-                    }
-                }
-            });
-
-            List<VMOperationToolStripMenuSubItem> dropDownItems = DropDownItems.Cast<VMOperationToolStripMenuSubItem>().ToList();
-
-            // Adds the migrate wizard button, do this before the enable checks on the other items
-            Program.Invoke(Program.MainWindow, () => AddAdditionalMenuItems(selection));
-
-            foreach (VMOperationToolStripMenuSubItem item in dropDownItems)
-            {
-                if (_isDropDownClosed)
-                {
-                    // Stop making requests to assert can start on each host after dropdown is closed
-                    break;
-                }
-
-                Host host = item.Tag as Host;
-                if (host != null)
-                {
-                    // API calls could happen in CanExecute(), which take time to wait.
-                    // So a Producer-Consumer-Queue with size 25 is used here to :
-                    //   1. Make API calls for different menu items happen in parallel;
-                    //   2. Limit the count of concurrent threads (now it's 25).
-                    workerQueueWithouWlb.EnqueueItem(() =>
-                    {
-                        if (_isDropDownClosed)
-                            return;
-                        VMOperationCommand cmd = new VMOperationHostCommand(Command.MainWindowCommandInterface, selection, delegate { return host; }, host.Name().EscapeAmpersands(), _operation, session);
-                        CrossPoolMigrateCommand cpmCmd = new CrossPoolMigrateCommand(Command.MainWindowCommandInterface, selection, host, _resumeAfter);
-
-                        VMOperationToolStripMenuSubItem tempItem = item;
-                        bool oldMigrateCmdCanRun = cmd.CanExecute();
-                        if ((_operation == vm_operations.start_on) || oldMigrateCmdCanRun)
+                        VMOperationCommand cpmCmdHome = new CrossPoolMigrateToHomeCommand(menu.Command.MainWindowCommandInterface, selection, affinityHost);
+
+                        if (cpmCmdHome.CanExecute())
                         {
-                            Program.Invoke(Program.MainWindow, delegate
-                            {
-                                tempItem.Command = cmd;
-                                tempItem.Enabled = oldMigrateCmdCanRun;
-                            });
+                            firstItem.Command = cpmCmdHome;
+                            firstItem.Enabled = true;
                         }
                         else
                         {
-                            bool crossPoolMigrateCmdCanRun = cpmCmd.CanExecute();
-                            if (crossPoolMigrateCmdCanRun || !string.IsNullOrEmpty(cpmCmd.CantExecuteReason))
+                            firstItem.Command = cmdHome;
+                            firstItem.Enabled = false;
+                        }
+                    }
+                });
+
+                List<VMOperationToolStripMenuSubItem> dropDownItems = menu.DropDownItems.Cast<VMOperationToolStripMenuSubItem>().ToList();
+
+                if (Stopped)
+                    return;
+
+                // Adds the migrate wizard button, do this before the enable checks on the other items
+                Program.Invoke(Program.MainWindow, () => menu.AddAdditionalMenuItems(selection));
+
+                foreach (VMOperationToolStripMenuSubItem item in dropDownItems)
+                {
+
+                    Host host = item.Tag as Host;
+                    if (host != null)
+                    {
+                        // API calls could happen in CanExecute(), which take time to wait.
+                        // So a Producer-Consumer-Queue with size 25 is used here to :
+                        //   1. Make API calls for different menu items happen in parallel;
+                        //   2. Limit the count of concurrent threads (now it's 25).
+                        workerQueueWithoutWlb.EnqueueItem(() =>
+                        {
+                            VMOperationCommand cmd = new VMOperationHostCommand(menu.Command.MainWindowCommandInterface, selection, delegate { return host; }, host.Name().EscapeAmpersands(), menu._operation, session);
+                            CrossPoolMigrateCommand cpmCmd = new CrossPoolMigrateCommand(menu.Command.MainWindowCommandInterface, selection, host, menu._resumeAfter);
+
+                            VMOperationToolStripMenuSubItem tempItem = item;
+                            bool oldMigrateCmdCanRun = cmd.CanExecute();
+                            if ((menu._operation == vm_operations.start_on) || oldMigrateCmdCanRun)
                             {
-                                Program.Invoke(Program.MainWindow, delegate
-                                {
-                                    tempItem.Command = cpmCmd;
-                                    tempItem.Enabled = crossPoolMigrateCmdCanRun;
-                                });
-                            }
-                            else
-                            {
+                                if (Stopped)
+                                    return;
+
                                 Program.Invoke(Program.MainWindow, delegate
                                 {
                                     tempItem.Command = cmd;
                                     tempItem.Enabled = oldMigrateCmdCanRun;
                                 });
                             }
-                        }
-                    });
-                }
-            }
-        }
-
-        /// <summary>
-        /// Hook to add additional members to the menu item
-        /// Note: Called on main window thread by executing code
-        /// </summary>
-        /// <param name="selection"></param>
-        protected virtual void AddAdditionalMenuItems(SelectedItemCollection selection) { return; }
-
-        /// <summary>
-        /// This class is an implementation of the 'IComparer' interface
-        /// for sorting vm placement menuItem List when wlb is enabled
-        /// </summary>
-        private class WlbHostStarCompare : IComparer<VMOperationToolStripMenuSubItem>
-        {
-            public int Compare(VMOperationToolStripMenuSubItem x, VMOperationToolStripMenuSubItem y)
-            {
-                int result = 0;
-
-                // if x and y are enabled, compare their start rating
-                if (x.Enabled && y.Enabled)
-                    result = y.StarRating.CompareTo(x.StarRating);
-
-                // if x and y are disabled, they are equal
-                else if (!x.Enabled && !y.Enabled)
-                    result = 0;
-
-                // if x is disabled, y is greater
-                else if (!x.Enabled)
-                    result = 1;
-
-                // if y is disabled, x is greater
-                else if (!y.Enabled)
-                    result = -1;
-
-                return result;
+                            else
+                            {
+                                bool crossPoolMigrateCmdCanRun = cpmCmd.CanExecute();
+                                if (crossPoolMigrateCmdCanRun || !string.IsNullOrEmpty(cpmCmd.CantExecuteReason))
+                                {
+                                    if (Stopped)
+                                        return;
+
+                                    Program.Invoke(Program.MainWindow, delegate
+                                    {
+                                        tempItem.Command = cpmCmd;
+                                        tempItem.Enabled = crossPoolMigrateCmdCanRun;
+                                    });
+                                }
+                                else
+                                {
+                                    if (Stopped)
+                                        return;
+
+                                    Program.Invoke(Program.MainWindow, delegate
+                                    {
+                                        tempItem.Command = cmd;
+                                        tempItem.Enabled = oldMigrateCmdCanRun;
+                                    });
+                                }
+                            }
+                        });
+                    }
+                }
+            }
+
+            /// <summary>
+            /// This class is an implementation of the 'IComparer' interface
+            /// for sorting vm placement menuItem List when wlb is enabled
+            /// </summary>
+            private class WlbHostStarCompare : IComparer<VMOperationToolStripMenuSubItem>
+            {
+                public int Compare(VMOperationToolStripMenuSubItem x, VMOperationToolStripMenuSubItem y)
+                {
+                    int result = 0;
+
+                    // if x and y are enabled, compare their start rating
+                    if (x.Enabled && y.Enabled)
+                        result = y.StarRating.CompareTo(x.StarRating);
+
+                    // if x and y are disabled, they are equal
+                    else if (!x.Enabled && !y.Enabled)
+                        result = 0;
+
+                    // if x is disabled, y is greater
+                    else if (!x.Enabled)
+                        result = 1;
+
+                    // if y is disabled, x is greater
+                    else if (!y.Enabled)
+                        result = -1;
+
+                    return result;
+                }
             }
         }
     }


whoops, this wasn't supposed to be committed

--- src/Kerbalism/Sim.cs
+++ src/Kerbalism/Sim.cs
@@ -91,23 +91,6 @@
 			if (Lib.Landed(v) || double.IsNaN(v.orbit.inclination) || v.orbit == null)
 				return v.mainBody.rotationPeriod * 0.5;

-			var now = Planetarium.GetUniversalTime();
-			var step = v.orbit.period / 30;
-			var nextOrbit = now + v.orbit.period;
-
-			var mainBodyAsList = new List<CelestialBody>();
-			mainBodyAsList.Add(v.mainBody);
-
-			int visible = 0;
-			while (now < nextOrbit)
-			{
-				Vector3d position = v.orbit.getPositionAtUT(now);
-				Vector3d bodyDir;
-				double bodyDist;
-				if(IsBodyVisible(v, position, v.KerbalismData().EnvMainSun.SunData.body, mainBodyAsList, out bodyDir, out bodyDist))
-					visible++;
-				now += step;
-			}

 			// the old method: this calculates the period for circular orbits
 			// double Ra = v.altitude + v.mainBody.Radius;


Add CreateFileW p/invoke method.

Add CreateFileW p/invoke method.

--- src/SilDev/WinApi.cs
+++ src/SilDev/WinApi.cs
@@ -5,7 +5,7 @@
 // ==============================================
 //
 // Filename: WinApi.cs
-// Version:  2020-01-24 20:10
+// Version:  2020-01-27 21:17
 //
 // Copyright (c) 2020, Si13n7 Developments(tm)
 // All rights reserved.
@@ -7268,6 +7268,60 @@
             internal static extern int ControlService(IntPtr hService, ServiceControlOptions dwControl, ServiceStatus lpServiceStatus);

             /// <summary>
+            ///     Creates or opens a file or I/O device. The most commonly used I/O devices
+            ///     are as follows: file, file stream, directory, physical disk, volume,
+            ///     console buffer, tape drive, communications resource, mailslot, and pipe.
+            ///     The function returns a handle that can be used to access the file or device
+            ///     for various types of I/O depending on the file or device and the flags and
+            ///     attributes specified.
+            /// </summary>
+            /// <param name="lpFileName">
+            ///     The name of the file or device to be created or opened. You may use either
+            ///     forward slashes (/) or backslashes () in this name.
+            /// </param>
+            /// <param name="dwDesiredAccess">
+            ///     The requested access to the file or device, which can be summarized as
+            ///     read, write, both or neither zero). The most commonly used values are
+            ///     GENERIC_READ (0x80000000), GENERIC_WRITE (0x40000000), or both. If this
+            ///     parameter is zero, the application can query certain metadata such as file,
+            ///     directory, or device attributes without accessing that file or device, even
+            ///     if GENERIC_READ (0x80000000) access would have been denied.
+            /// </param>
+            /// <param name="dwShareMode">
+            ///     The requested sharing mode of the file or device, which can be read, write,
+            ///     both, delete, all of these, or none (refer to the following table). Access
+            ///     requests to attributes or extended attributes are not affected by this
+            ///     flag. If this parameter is zero and CreateFile succeeds, the file or device
+            ///     cannot be shared and cannot be opened again until the handle to the file or
+            ///     device is closed.
+            /// </param>
+            /// <param name="lpSecurityAttributes">
+            ///     A pointer to a <see cref="SecurityAttributes"/> structure that contains two
+            ///     separate but related data members: an optional security descriptor, and a
+            ///     Boolean value that determines whether the returned handle can be inherited
+            ///     by child processes.
+            /// </param>
+            /// <param name="dwCreationDisposition">
+            ///     An action to take on a file or device that exists or does not exist.
+            /// </param>
+            /// <param name="dwFlagsAndAttributes">
+            ///     The file or device attributes and flags, FILE_ATTRIBUTE_NORMAL (0x80) being
+            ///     the most common default value for files.
+            /// </param>
+            /// <param name="hTemplateFile">
+            ///     A valid handle to a template file with the GENERIC_READ (0x80000000) access
+            ///     right. The template file supplies file attributes and extended attributes
+            ///     for the file that is being created. This parameter can be
+            ///     <see langword="null"/>.
+            /// </param>
+            /// <returns>
+            ///     If the function succeeds, the return value is an open handle to the
+            ///     specified file, device, named pipe, or mail slot.
+            /// </returns>
+            [DllImport(DllNames.Kernel32, EntryPoint = "CreateFileW", SetLastError = true, CharSet = CharSet.Unicode)]
+            internal static extern IntPtr CreateFileW([MarshalAs(UnmanagedType.LPWStr)] string lpFileName, [MarshalAs(UnmanagedType.U4)] uint dwDesiredAccess, [MarshalAs(UnmanagedType.U4)] uint dwShareMode, IntPtr lpSecurityAttributes, [MarshalAs(UnmanagedType.U4)] uint dwCreationDisposition, [MarshalAs(UnmanagedType.U4)] uint dwFlagsAndAttributes, IntPtr hTemplateFile);
+
+            /// <summary>
             ///     Creates a new process and its primary thread. The new process runs in the
             ///     security context of the specified token. It can optionally load the user
             ///     profile for the specified user.


Bugfix: Empty argument type must not generate Arg-placeholder

git-svn-id: a5649c7974654692dcf39c1244dd8f20f3116d6c@4788 c0adb3ac-85ad-b347-9a16-a660ac379d24

--- src/reni2/Struct/FunctionalBody.cs
+++ src/reni2/Struct/FunctionalBody.cs
@@ -22,6 +22,7 @@
 using HWClassLibrary.Debug;
 using HWClassLibrary.Helper;
 using Reni.Basics;
+using Reni.Code;
 using Reni.Syntax;
 using Reni.Type;

@@ -66,7 +67,9 @@

         protected override Result Apply(Category category, TypeBase argsType, RefAlignParam refAlignParam)
         {
-            var argsResult = argsType.ArgResult(category | Category.Type);
+            var argsResult = argsType.ArgResult(category.Typed);
+            if(argsType.IsZeroSized && category.HasCode)
+                argsResult.Code = CodeBase.Void();
             return _structure
                 .CreateFunctionCall(category, Body, argsResult);
         }


Handle multiple trash connectors/sensors or configs more intelligently

--- BARABAS.cs
+++ BARABAS.cs
@@ -521,6 +521,15 @@
 	return block.CubeGrid.GetCubeBlock(block.Position);
 }

+IMyTerminalBlock findBlockById(IMyTerminalBlock block, List<IMyTerminalBlock> blocks) {
+	foreach (var cur in blocks) {
+		if (cur.ToString() == block.ToString()) {
+			return cur;
+		}
+	}
+	return null;
+}
+
 // get local blocks
 List < IMyTerminalBlock > getBlocks(bool force_update = false) {
 	if (local_blocks != null && !force_update) {
@@ -1121,7 +1130,15 @@
 			trash_connector = connectors[0] as IMyShipConnector;
 		}
 	} else if (blocks.Count > 1) {
-		throw new BarabasException("Multiple trash blocks found!");
+		Echo("Multiple trash connectors found.");
+		if (trash_connector != null) {
+			// find our previous config block, ignore the rest
+			trash_connector = findBlockById(trash_connector, blocks);
+		}
+		if (trash_connector == null) {
+			// if we didn't find our config block, just use the first one
+			trash_connector = blocks[0] as IMyShipConnector;
+		}
 	} else {
 		trash_connector = blocks[0] as IMyShipConnector;
 	}
@@ -1138,7 +1155,15 @@
 	if (blocks.Count < 1) {
 		trash_sensor = null;
 	} else if (blocks.Count > 1) {
-		throw new BarabasException("Multiple trash sensors found!");
+		Echo("Multiple trash sensors found.");
+		if (trash_sensor != null) {
+			// find our previous config block, ignore the rest
+			trash_sensor = findBlockById(trash_sensor, blocks);
+		}
+		if (trash_sensor == null) {
+			// if we didn't find our config block, just use the first one
+			trash_sensor = blocks[0] as IMySensorBlock;
+		}
 	} else {
 		trash_sensor = blocks[0] as IMySensorBlock;
 	}
@@ -1154,10 +1179,15 @@
 	if (blocks.Count < 1) {
 		return null;
 	} else if (blocks.Count > 1) {
-		foreach (var tp in blocks) {
-			Echo(tp.ToString() + " " + tp.CustomName);
-		}
-		throw new BarabasException("Multiple config blocks found");
+		Echo("Multiple config blocks found.");
+		if (config_block != null) {
+			// find our previous config block, ignore the rest
+			config_block = findBlockById(config_block, blocks);
+		}
+		if (config_block == null) {
+			// if we didn't find our config block, just use the first one
+			config_block = blocks[0] as IMyTextPanel;
+		}
 	} else {
 		config_block = blocks[0] as IMyTextPanel;
 	}


Better exception handling

Better exception handling

--- BARABAS.cs
+++ BARABAS.cs
@@ -489,7 +489,7 @@

 // just have a method to indicate that this exception comes from BARABAS
 class BarabasException: Exception {
- public BarabasException(string msg, Program p): base("BARABAS: " + msg) {
+ public BarabasException(string msg, Program p) : base("BARABAS: " + msg) {
   // calling the getX() functions will set off a chain of events if local data
   // is not initialized, so use locally stored data instead
   var panels = p.local_text_panels;
@@ -4554,7 +4554,12 @@
  do {
   try {
    states[current_state]();
+  } catch (BarabasException e) {
+   // if we caught our own exception, pass it along
+   Echo(e.StackTrace);
+   throw;
   } catch (Exception e) {
+   Echo(e.StackTrace);
    string msg = String.Format("State: {0} Error: {1}", current_state, e.Message);
    throw new BarabasException(msg, this);
   }


Detect grid size

Detect grid size

--- BARABAS.cs
+++ BARABAS.cs
@@ -378,6 +378,7 @@
 bool can_use_ingots;
 bool can_use_oxygen;
 bool can_refine;
+bool large_grid;
 bool has_air_vents;
 bool has_status_panels;
 bool has_reactors;
@@ -4486,6 +4487,10 @@
 	// load grids from storage
 	local_grids = new List < IMyCubeGrid > ();
 	loadLocalGrids(local_grids);
+
+	// determine grid size
+	var id = Me.BlockDefinition.ToString();
+	large_grid = id.Contains("Large");
 }

 public void Main() {


Adjust material thresholds to reflect new realities

--- BARABAS.cs
+++ BARABAS.cs
@@ -226,16 +226,16 @@

         // ballpark values of "just enough" for each material
         readonly Dictionary<string, float> material_thresholds = new Dictionary<string, float> {
-            { CO, 500 },
-            { AU, 100 },
-            { FE, 5000 },
+            { CO, 1000 },
+            { AU, 150 },
+            { FE, 15000 },
             { MG, 100 },
             { NI, 1000 },
-            { PT, 10 },
-            { SI, 1000 },
-            { AG, 1000 },
-            { U, 10 },
-            { STONE, 5000 },
+            { PT, 20 },
+            { SI, 1500 },
+            { AG, 200 },
+            { U, 0 },
+            { STONE, 400 },
         };

         readonly Dictionary<string, Dictionary<string, float>> ore_to_ingot_ratios = new Dictionary<string, Dictionary<string, float>> {


Adding changes to handle situation, where there is requested a none existing translation, then it should pick the first translation.

--- eFormCore/Infrastructure/SqlController.cs
+++ eFormCore/Infrastructure/SqlController.cs
@@ -145,7 +145,12 @@
                     return null;

                 CheckListTranslation checkListTranslation =
-                    await db.CheckListTranslations.SingleAsync(x => x.CheckListId == mainCl.Id);
+                    await db.CheckListTranslations.SingleOrDefaultAsync(x => x.CheckListId == mainCl.Id && x.LanguageId == defaultLanguage.Id);
+                if (checkListTranslation == null)
+                {
+                    checkListTranslation = await db.CheckListTranslations.FirstAsync(x => x.CheckListId == mainCl.Id);
+                    defaultLanguage = db.Languages.Single(x => x.Id == checkListTranslation.LanguageId);
+                }

                 mainElement = new MainElement(mainCl.Id, checkListTranslation.Text, t.Int(mainCl.DisplayIndex), mainCl.FolderName, t.Int(mainCl.Repeated), DateTime.UtcNow, DateTime.UtcNow.AddDays(2), "da",
                     t.Bool(mainCl.MultiApproval), t.Bool(mainCl.FastNavigation), t.Bool(mainCl.DownloadEntities), t.Bool(mainCl.ManualSync), mainCl.CaseType, "", "", t.Bool(mainCl.QuickSyncEnabled), new List<Element>(), mainCl.Color);
@@ -189,6 +194,16 @@
                     sites.Add(siteNameDto);
                 }
                 bool hasCases = db.Cases.Where(x => x.CheckListId == checkList.Id).AsQueryable().Count() != 0;
+
+                CheckListTranslation checkListTranslation =
+                    await db.CheckListTranslations.SingleOrDefaultAsync(x =>
+                        x.CheckListId == checkList.Id && x.LanguageId == defaultLanguage.Id);
+                if (checkListTranslation == null)
+                {
+                    checkListTranslation =
+                        await db.CheckListTranslations.FirstAsync(x => x.CheckListId == checkList.Id);
+                    defaultLanguage = await db.Languages.SingleAsync(x => x.Id == checkListTranslation.LanguageId);
+                }

                 #region load fields
                 FieldDto fd1 = null;
@@ -206,7 +221,7 @@
                 if (f1 != null)
                 {
                     FieldTranslation translation = await db.FieldTranslations
-                        .SingleOrDefaultAsync(x => x.FieldId == f1.Id && x.LanguageId == defaultLanguage.Id);
+                        .SingleOrDefaultAsync(x => x.FieldId == f1.Id && x.LanguageId == defaultLanguage.Id) ?? await db.FieldTranslations.FirstAsync(x => x.FieldId == f1.Id);
                     FieldType fieldType = await db.FieldTypes.SingleAsync(x => x.Id == f1.FieldTypeId);
                     fd1 = new FieldDto(f1.Id, translation.Text, translation.Description, (int)f1.FieldTypeId, fieldType.Type, (int)f1.CheckListId);
                 }
@@ -214,72 +229,72 @@
                 Data.Entities.Field f2 = await db.Fields.SingleOrDefaultAsync(x => x.Id == checkList.Field2);
                 if (f2 != null) {
                     FieldTranslation translation = await db.FieldTranslations
-                        .SingleOrDefaultAsync(x => x.FieldId == f1.Id && x.LanguageId == defaultLanguage.Id);
-                    FieldType fieldType = await db.FieldTypes.SingleAsync(x => x.Id == f1.FieldTypeId);
+                        .SingleOrDefaultAsync(x => x.FieldId == f2.Id && x.LanguageId == defaultLanguage.Id) ?? await db.FieldTranslations.FirstAsync(x => x.FieldId == f2.Id);
+                    FieldType fieldType = await db.FieldTypes.SingleAsync(x => x.Id == f2.FieldTypeId);
                     fd2 = new FieldDto(f2.Id, translation.Text, translation.Description, (int)f2.FieldTypeId, f2.FieldType.Type, (int)f2.CheckListId);
                 }

                 Data.Entities.Field f3 = await db.Fields.SingleOrDefaultAsync(x => x.Id == checkList.Field3);
                 if (f3 != null) {
                     FieldTranslation translation = await db.FieldTranslations
-                        .SingleOrDefaultAsync(x => x.FieldId == f1.Id && x.LanguageId == defaultLanguage.Id);
-                    FieldType fieldType = await db.FieldTypes.SingleAsync(x => x.Id == f1.FieldTypeId);
+                        .SingleOrDefaultAsync(x => x.FieldId == f3.Id && x.LanguageId == defaultLanguage.Id) ?? await db.FieldTranslations.FirstAsync(x => x.FieldId == f3.Id);
+                    FieldType fieldType = await db.FieldTypes.SingleAsync(x => x.Id == f3.FieldTypeId);
                     fd3 = new FieldDto(f3.Id, translation.Text, translation.Description, (int)f3.FieldTypeId, f3.FieldType.Type, (int)f3.CheckListId);
                 }

                 Data.Entities.Field f4 = await db.Fields.SingleOrDefaultAsync(x => x.Id == checkList.Field4);
                 if (f4 != null) {
                     FieldTranslation translation = await db.FieldTranslations
-                        .SingleOrDefaultAsync(x => x.FieldId == f1.Id && x.LanguageId == defaultLanguage.Id);
-                    FieldType fieldType = await db.FieldTypes.SingleAsync(x => x.Id == f1.FieldTypeId);
+                        .SingleOrDefaultAsync(x => x.FieldId == f4.Id && x.LanguageId == defaultLanguage.Id) ?? await db.FieldTranslations.FirstAsync(x => x.FieldId == f4.Id);
+                    FieldType fieldType = await db.FieldTypes.SingleAsync(x => x.Id == f4.FieldTypeId);
                     fd4 = new FieldDto(f4.Id, translation.Text, translation.Description, (int)f4.FieldTypeId, f4.FieldType.Type, (int)f4.CheckListId);
                 }

                 Data.Entities.Field f5 = await db.Fields.SingleOrDefaultAsync(x => x.Id == checkList.Field5);
                 if (f5 != null) {
                     FieldTranslation translation = await db.FieldTranslations
-                        .SingleOrDefaultAsync(x => x.FieldId == f1.Id && x.LanguageId == defaultLanguage.Id);
-                    FieldType fieldType = await db.FieldTypes.SingleAsync(x => x.Id == f1.FieldTypeId);
+                        .SingleOrDefaultAsync(x => x.FieldId == f5.Id && x.LanguageId == defaultLanguage.Id) ?? await db.FieldTranslations.FirstAsync(x => x.FieldId == f5.Id);
+                    FieldType fieldType = await db.FieldTypes.SingleAsync(x => x.Id == f5.FieldTypeId);
                     fd5 = new FieldDto(f5.Id, translation.Text, translation.Description, (int)f5.FieldTypeId, f5.FieldType.Type, (int)f5.CheckListId);
                 }

                 Data.Entities.Field f6 = await db.Fields.SingleOrDefaultAsync(x => x.Id == checkList.Field6);
                 if (f6 != null) {
                     FieldTranslation translation = await db.FieldTranslations
-                        .SingleOrDefaultAsync(x => x.FieldId == f1.Id && x.LanguageId == defaultLanguage.Id);
-                    FieldType fieldType = await db.FieldTypes.SingleAsync(x => x.Id == f1.FieldTypeId);
+                        .SingleOrDefaultAsync(x => x.FieldId == f6.Id && x.LanguageId == defaultLanguage.Id) ?? await db.FieldTranslations.FirstAsync(x => x.FieldId == f6.Id);
+                    FieldType fieldType = await db.FieldTypes.SingleAsync(x => x.Id == f6.FieldTypeId);
                     fd6 = new FieldDto(f6.Id, translation.Text, translation.Description, (int)f6.FieldTypeId, f6.FieldType.Type, (int)f6.CheckListId);
                 }

                 Data.Entities.Field f7 = await db.Fields.SingleOrDefaultAsync(x => x.Id == checkList.Field7);
                 if (f7 != null) {
                     FieldTranslation translation = await db.FieldTranslations
-                        .SingleOrDefaultAsync(x => x.FieldId == f1.Id && x.LanguageId == defaultLanguage.Id);
-                    FieldType fieldType = await db.FieldTypes.SingleAsync(x => x.Id == f1.FieldTypeId);
+                        .SingleOrDefaultAsync(x => x.FieldId == f7.Id && x.LanguageId == defaultLanguage.Id) ?? await db.FieldTranslations.FirstAsync(x => x.FieldId == f7.Id);
+                    FieldType fieldType = await db.FieldTypes.SingleAsync(x => x.Id == f7.FieldTypeId);
                     fd7 = new FieldDto(f7.Id, translation.Text, translation.Description, (int)f7.FieldTypeId, f7.FieldType.Type, (int)f7.CheckListId);
                 }

                 Data.Entities.Field f8 = await db.Fields.SingleOrDefaultAsync(x => x.Id == checkList.Field8);
                 if (f8 != null) {
                     FieldTranslation translation = await db.FieldTranslations
-                        .SingleOrDefaultAsync(x => x.FieldId == f1.Id && x.LanguageId == defaultLanguage.Id);
-                    FieldType fieldType = await db.FieldTypes.SingleAsync(x => x.Id == f1.FieldTypeId);
+                        .SingleOrDefaultAsync(x => x.FieldId == f8.Id && x.LanguageId == defaultLanguage.Id) ?? await db.FieldTranslations.FirstAsync(x => x.FieldId == f8.Id);
+                    FieldType fieldType = await db.FieldTypes.SingleAsync(x => x.Id == f8.FieldTypeId);
                     fd8 = new FieldDto(f8.Id, translation.Text, translation.Description, (int)f8.FieldTypeId, f8.FieldType.Type, (int)f8.CheckListId);
                 }

                 Data.Entities.Field f9 = await db.Fields.SingleOrDefaultAsync(x => x.Id == checkList.Field9);
                 if (f9 != null) {
                     FieldTranslation translation = await db.FieldTranslations
-                        .SingleOrDefaultAsync(x => x.FieldId == f1.Id && x.LanguageId == defaultLanguage.Id);
-                    FieldType fieldType = await db.FieldTypes.SingleAsync(x => x.Id == f1.FieldTypeId);
+                        .SingleOrDefaultAsync(x => x.FieldId == f9.Id && x.LanguageId == defaultLanguage.Id) ?? await db.FieldTranslations.FirstAsync(x => x.FieldId == f9.Id);
+                    FieldType fieldType = await db.FieldTypes.SingleAsync(x => x.Id == f9.FieldTypeId);
                     fd9 = new FieldDto(f9.Id, translation.Text, translation.Description, (int)f9.FieldTypeId, f9.FieldType.Type, (int)f9.CheckListId);
                 }

                 Data.Entities.Field f10 = await db.Fields.SingleOrDefaultAsync(x => x.Id == checkList.Field10);
                 if (f10 != null) {
                     FieldTranslation translation = await db.FieldTranslations
-                        .SingleOrDefaultAsync(x => x.FieldId == f1.Id && x.LanguageId == defaultLanguage.Id);
-                    FieldType fieldType = await db.FieldTypes.SingleAsync(x => x.Id == f1.FieldTypeId);
+                        .SingleOrDefaultAsync(x => x.FieldId == f10.Id && x.LanguageId == defaultLanguage.Id) ?? await db.FieldTranslations.FirstAsync(x => x.FieldId == f10.Id);
+                    FieldType fieldType = await db.FieldTypes.SingleAsync(x => x.Id == f10.FieldTypeId);
                     fd10 = new FieldDto(f10.Id, translation.Text, translation.Description, (int)f10.FieldTypeId, f10.FieldType.Type, (int)f10.CheckListId);
                 }
                 #endregion
@@ -294,9 +309,6 @@
                 }
                 #endregion

-                CheckListTranslation checkListTranslation =
-                    await db.CheckListTranslations.SingleOrDefaultAsync(x =>
-                        x.CheckListId == checkList.Id && x.LanguageId == defaultLanguage.Id);
                 Template_Dto templateDto = new Template_Dto(checkList.Id, checkList.CreatedAt, checkList.UpdatedAt,
                     checkListTranslation.Text, checkListTranslation.Description, (int) checkList.Repeated, checkList.FolderName,
                     checkList.WorkflowState, sites, hasCases, checkList.DisplayIndex, fd1, fd2, fd3, fd4, fd5, fd6,


Fixing the last broken test.

Fixing the last broken test.

--- eFormCore/Infrastructure/SqlController.cs
+++ eFormCore/Infrastructure/SqlController.cs
@@ -1400,10 +1400,11 @@
                     replyElement.JasperExportEnabled = mainCheckList.JasperExportEnabled;
                     replyElement.DocxExportEnabled = mainCheckList.DocxExportEnabled;

-                    check_lists checkLists = await db.check_lists.SingleAsync(x => x.Id == aCase.CheckListId);
-                    foreach (check_lists checkList in checkLists.Children.OrderBy(x => x.DisplayIndex))
-                    {
-                        replyElement.ElementList.Add(await SubChecks(checkList.Id, aCase.Id));
+                    check_lists checkList = await db.check_lists.SingleAsync(x => x.Id == aCase.CheckListId);
+                    foreach (check_lists subCheckList in await db.check_lists.Where(x =>
+                        x.ParentId == checkList.Id).OrderBy(x => x.DisplayIndex).ToListAsync())
+                    {
+                        replyElement.ElementList.Add(await SubChecks(subCheckList.Id, aCase.Id));
                     }
                     return replyElement;
                 }
@@ -1424,10 +1425,11 @@
                 {
                     var checkList = await db.check_lists.SingleAsync(x => x.Id == parentId);
                     //Element element = new Element();
-                    if (checkList.Children.Any())
+                    if (await db.check_lists.AnyAsync(x => x.ParentId == checkList.Id))
                     {
                         List<Element> elementList = new List<Element>();
-                        foreach (check_lists subList in checkList.Children.OrderBy(x => x.DisplayIndex))
+                        foreach (check_lists subList in await db.check_lists.Where(x =>
+                            x.ParentId == checkList.Id).OrderBy(x => x.DisplayIndex).ToListAsync())
                         {
                             elementList.Add(await SubChecks(subList.Id, caseId));
                         }
@@ -1449,17 +1451,24 @@
                     {
                         List<DataItemGroup> dataItemGroupList = new List<DataItemGroup>();
                         List<DataItem> dataItemList = new List<DataItem>();
-                        foreach (fields field in checkList.Fields.Where(x => x.ParentFieldId == null).OrderBy(x => x.DisplayIndex).ToList())
+                        List<fields> fields = await db.fields.Where(x =>
+                                x.CheckListId == checkList.Id
+                                && x.ParentFieldId == null).OrderBy(x => x.DisplayIndex)
+                            .ToListAsync();
+                        foreach (fields field in fields)
                         {
-                            if (field.FieldType.FieldType == "FieldGroup")
+                            field_types fieldType = db.field_types.Single(x => x.Id == field.FieldTypeId);
+                            if (fieldType.FieldType == "FieldGroup")
                             {
                                 List<DataItem> dataItemSubList = new List<DataItem>();
-                                foreach (fields subField in field.Children.OrderBy(x => x.DisplayIndex))
+                                foreach (fields subField in await db.fields.Where(x =>
+                                    x.ParentFieldId == field.CheckListId).OrderBy(x => x.DisplayIndex).ToListAsync())
                                 {
                                     Field _field = DbFieldToField(subField);

                                     _field.FieldValues = new List<FieldValue>();
-                                    foreach (field_values fieldValue in subField.FieldValues.Where(x => x.CaseId == caseId).ToList())
+                                    foreach (field_values fieldValue in await db.field_values.Where(x =>
+                                        x.FieldId == subField.Id && x.CaseId == caseId).ToListAsync())
                                     {
                                         FieldValue answer = await ReadFieldValue(fieldValue, subField, false);
                                         _field.FieldValues.Add(answer);
@@ -1488,7 +1497,8 @@
                             {
                                 Field _field = DbFieldToField(field);
                                 _field.FieldValues = new List<FieldValue>();
-                                foreach (field_values fieldValue in field.FieldValues.Where(x => x.CaseId == caseId).ToList())
+                                foreach (field_values fieldValue in await db.field_values.Where(x =>
+                                    x.FieldId == field.Id && x.CaseId == caseId).ToListAsync())
                                 {
                                     FieldValue answer = await ReadFieldValue(fieldValue, field, false);
                                     _field.FieldValues.Add(answer);


allow aborting a transition also within the BevorTransition hook

--- src/microwf.Core/Execution/WorkflowExecution.cs
+++ src/microwf.Core/Execution/WorkflowExecution.cs
@@ -54,10 +54,14 @@
       if (!result.CanTrigger) return result;

       var transition = GetTransition(param.TriggerName, param.Instance);
+
       if (context.TransitionAborted)
         return CreateTriggerResult(param.TriggerName, context, transition);

       transition.BeforeTransition?.Invoke(context);
+
+      if (context.TransitionAborted)
+        return CreateTriggerResult(param.TriggerName, context, transition);

       var state = _definition.States.Single(s => s == transition.TargetState);
       param.Instance.State = state;
@@ -81,7 +85,7 @@
           context.SetVariable(variable.Key, variable.Value);
         }
       }
-
+
       return context;
     }

@@ -102,8 +106,8 @@
     }

     private TriggerResult CanMakeTransition(
-      TransitionContext context,
-      string triggerName,
+      TransitionContext context,
+      string triggerName,
       IWorkflow instance)
     {
       var transition = GetTransition(triggerName, instance);


Fix various API issues with CALayer

Fix various API issues with CALayer

DefaultActionForKey, ActionForKey and ActionForLayer must return an
NSObject instead of CAAction, since some types implements the CAAction
protocolo without inheriting from the CAAction type. Fixes #2441.

The Actions property is an NSDictionary in native code, expose is as such,
and make CALayer.DefaultActionForKey a static method.

--- src/coreanimation.cs
+++ src/coreanimation.cs
@@ -336,14 +336,15 @@
 		[Export ("layoutSublayers")]
 		void LayoutSublayers ();

+		[Static]
 		[Export ("defaultActionForKey:")]
-		CAAction DefaultActionForKey (string eventKey);
+		NSObject DefaultActionForKey (string eventKey);

 		[Export ("actionForKey:")]
-		CAAction ActionForKey (string eventKey);
+		NSObject ActionForKey (string eventKey);

 		[Export ("actions", ArgumentSemantic.Copy)]
-		CAAction [] Actions { get; set; }
+		NSDictionary Actions { get; set; }

 		[Export ("addAnimation:forKey:")]
 		void AddAnimation (CAAnimation animation, [NullAllowed] string key);
@@ -732,7 +733,7 @@
 		void LayoutSublayersOfLayer (CALayer layer);

 		[Export ("actionForLayer:forKey:"), EventArgs ("CALayerDelegateAction"), DefaultValue (null)]
-		CAAction ActionForLAyer (CALayer layer, string eventKey);
+		NSObject ActionForLayer (CALayer layer, string eventKey);
 	}

 #if !MONOMAC


Standardize on spaces instead of tabs.

Standardize on spaces instead of tabs.

It appears to be the more common choice among game developers; might as
well go with the flow.

--- Console.cs
+++ Console.cs
@@ -4,53 +4,53 @@

 namespace Consolation
 {
-	/// <summary>
-	/// A console to display Unity's debug logs in-game.
-	/// </summary>
-	class Console : MonoBehaviour
-	{
-		struct Log
-		{
-			public string message;
-			public string stackTrace;
-			public LogType type;
-		}
-
-		#region Inspector Settings
-
-		/// <summary>
-		/// The hotkey to show and hide the console window.
-		/// </summary>
-		public KeyCode toggleKey = KeyCode.BackQuote;
-
-		/// <summary>
-		/// Whether to open the window by shaking the device (mobile-only).
-		/// </summary>
-		public bool shakeToOpen = true;
-
-		/// <summary>
-		/// The (squared) acceleration above which the window should open.
-		/// </summary>
-		public float shakeAcceleration = 3f;
-
-		/// <summary>
-		/// Whether to only keep a certain number of logs.
-		///
-		/// Setting this can be helpful if memory usage is a concern.
-		/// </summary>
-		public bool restrictLogCount = false;
-
-		/// <summary>
-		/// Number of logs to keep before removing old ones.
-		/// </summary>
-		public int maxLogs = 1000;
-
-		#endregion
-
-		readonly List<Log> logs = new List<Log>();
-		Vector2 scrollPosition;
-		bool visible;
-		bool collapse;
+    /// <summary>
+    /// A console to display Unity's debug logs in-game.
+    /// </summary>
+    class Console : MonoBehaviour
+    {
+        struct Log
+        {
+            public string message;
+            public string stackTrace;
+            public LogType type;
+        }
+
+        #region Inspector Settings
+
+        /// <summary>
+        /// The hotkey to show and hide the console window.
+        /// </summary>
+        public KeyCode toggleKey = KeyCode.BackQuote;
+
+        /// <summary>
+        /// Whether to open the window by shaking the device (mobile-only).
+        /// </summary>
+        public bool shakeToOpen = true;
+
+        /// <summary>
+        /// The (squared) acceleration above which the window should open.
+        /// </summary>
+        public float shakeAcceleration = 3f;
+
+        /// <summary>
+        /// Whether to only keep a certain number of logs.
+        ///
+        /// Setting this can be helpful if memory usage is a concern.
+        /// </summary>
+        public bool restrictLogCount = false;
+
+        /// <summary>
+        /// Number of logs to keep before removing old ones.
+        /// </summary>
+        public int maxLogs = 1000;
+
+        #endregion
+
+        readonly List<Log> logs = new List<Log>();
+        Vector2 scrollPosition;
+        bool visible;
+        bool collapse;

         Dictionary<LogType, bool> logTypeFilters = new Dictionary<LogType, bool>
         {
@@ -61,81 +61,81 @@
             { LogType.Warning, true },
         };

-		// Visual elements:
-
-		static readonly Dictionary<LogType, Color> logTypeColors = new Dictionary<LogType, Color>
-		{
-			{ LogType.Assert, Color.white },
-			{ LogType.Error, Color.red },
-			{ LogType.Exception, Color.red },
-			{ LogType.Log, Color.white },
-			{ LogType.Warning, Color.yellow },
-		};
-
-		const string windowTitle = "Console";
-		const int margin = 20;
-		static readonly GUIContent clearLabel = new GUIContent("Clear", "Clear the contents of the console.");
-		static readonly GUIContent collapseLabel = new GUIContent("Collapse", "Hide repeated messages.");
-
-		readonly Rect titleBarRect = new Rect(0, 0, 10000, 20);
-		Rect windowRect = new Rect(margin, margin, Screen.width - (margin * 2), Screen.height - (margin * 2));
-
-		void OnEnable ()
-		{
-			Application.logMessageReceived += HandleLog;
-		}
-
-		void OnDisable ()
-		{
-			Application.logMessageReceived -= HandleLog;
-		}
-
-		void Update ()
-		{
-			if (Input.GetKeyDown(toggleKey)) {
-				visible = !visible;
-			}
-
-			if (shakeToOpen && Input.acceleration.sqrMagnitude > shakeAcceleration) {
-				visible = true;
-			}
-		}
-
-		void OnGUI ()
-		{
-			if (!visible) {
-				return;
-			}
-
-			windowRect = GUILayout.Window(123456, windowRect, DrawConsoleWindow, windowTitle);
-		}
-
-		/// <summary>
-		/// Displays a window that lists the recorded logs.
-		/// </summary>
-		/// <param name="windowID">Window ID.</param>
-		void DrawConsoleWindow (int windowID)
-		{
-			DrawLogsList();
-			DrawToolbar();
-
-			// Allow the window to be dragged by its title bar.
-			GUI.DragWindow(titleBarRect);
-		}
-
-		/// <summary>
-		/// Displays a scrollable list of logs.
-		/// </summary>
-		void DrawLogsList ()
-		{
-			scrollPosition = GUILayout.BeginScrollView(scrollPosition);
-
-			// Used to determine height of accumulated log labels.
-			GUILayout.BeginVertical();
-
-				// Iterate through the recorded logs.
-				for (var i = 0; i < logs.Count; i++) {
-					var log = logs[i];
+        // Visual elements:
+
+        static readonly Dictionary<LogType, Color> logTypeColors = new Dictionary<LogType, Color>
+        {
+            { LogType.Assert, Color.white },
+            { LogType.Error, Color.red },
+            { LogType.Exception, Color.red },
+            { LogType.Log, Color.white },
+            { LogType.Warning, Color.yellow },
+        };
+
+        const string windowTitle = "Console";
+        const int margin = 20;
+        static readonly GUIContent clearLabel = new GUIContent("Clear", "Clear the contents of the console.");
+        static readonly GUIContent collapseLabel = new GUIContent("Collapse", "Hide repeated messages.");
+
+        readonly Rect titleBarRect = new Rect(0, 0, 10000, 20);
+        Rect windowRect = new Rect(margin, margin, Screen.width - (margin * 2), Screen.height - (margin * 2));
+
+        void OnEnable ()
+        {
+            Application.logMessageReceived += HandleLog;
+        }
+
+        void OnDisable ()
+        {
+            Application.logMessageReceived -= HandleLog;
+        }
+
+        void Update ()
+        {
+            if (Input.GetKeyDown(toggleKey)) {
+                visible = !visible;
+            }
+
+            if (shakeToOpen && Input.acceleration.sqrMagnitude > shakeAcceleration) {
+                visible = true;
+            }
+        }
+
+        void OnGUI ()
+        {
+            if (!visible) {
+                return;
+            }
+
+            windowRect = GUILayout.Window(123456, windowRect, DrawConsoleWindow, windowTitle);
+        }
+
+        /// <summary>
+        /// Displays a window that lists the recorded logs.
+        /// </summary>
+        /// <param name="windowID">Window ID.</param>
+        void DrawConsoleWindow (int windowID)
+        {
+            DrawLogsList();
+            DrawToolbar();
+
+            // Allow the window to be dragged by its title bar.
+            GUI.DragWindow(titleBarRect);
+        }
+
+        /// <summary>
+        /// Displays a scrollable list of logs.
+        /// </summary>
+        void DrawLogsList ()
+        {
+            scrollPosition = GUILayout.BeginScrollView(scrollPosition);
+
+            // Used to determine height of accumulated log labels.
+            GUILayout.BeginVertical();
+
+                // Iterate through the recorded logs.
+                for (var i = 0; i < logs.Count; i++) {
+                    var log = logs[i];
                     //If is not filtered, can be drawn.
                     if (logTypeFilters[log.type])
                     {
@@ -152,107 +152,107 @@

                         GUI.contentColor = logTypeColors[log.type];
                         GUILayout.Label(log.message);
-                    }
-				}
-
-			GUILayout.EndVertical();
-			var innerScrollRect = GUILayoutUtility.GetLastRect();
-			GUILayout.EndScrollView();
-			var outerScrollRect = GUILayoutUtility.GetLastRect();
-
-			// If we're scrolled to bottom now, guarantee that it continues to be in next cycle.
-			if (Event.current.type == EventType.Repaint && IsScrolledToBottom(innerScrollRect, outerScrollRect)) {
-				ScrollToBottom();
-			}
-
-			// Ensure GUI colour is reset before drawing other components.
-			GUI.contentColor = Color.white;
-		}
-
-		/// <summary>
-		/// Displays options for filtering and changing the logs list.
-		/// </summary>
-		void DrawToolbar ()
-		{
-			GUILayout.BeginHorizontal();
-
-				if (GUILayout.Button(clearLabel)) {
-					logs.Clear();
-				}
+                    }
+                }
+
+            GUILayout.EndVertical();
+            var innerScrollRect = GUILayoutUtility.GetLastRect();
+            GUILayout.EndScrollView();
+            var outerScrollRect = GUILayoutUtility.GetLastRect();
+
+            // If we're scrolled to bottom now, guarantee that it continues to be in next cycle.
+            if (Event.current.type == EventType.Repaint && IsScrolledToBottom(innerScrollRect, outerScrollRect)) {
+                ScrollToBottom();
+            }
+
+            // Ensure GUI colour is reset before drawing other components.
+            GUI.contentColor = Color.white;
+        }
+
+        /// <summary>
+        /// Displays options for filtering and changing the logs list.
+        /// </summary>
+        void DrawToolbar ()
+        {
+            GUILayout.BeginHorizontal();
+
+                if (GUILayout.Button(clearLabel)) {
+                    logs.Clear();
+                }

                 for (int i = 0; i<5; i++)
                 {
                     LogType actualType = (LogType) i;
-                    logTypeFilters[actualType] = GUILayout.Toggle(logTypeFilters[actualType], new GUIContent(actualType.ToString(), actualType.ToString() + " toggle filter"), ToggleLayoutOptions);
+                    logTypeFilters[actualType] = GUILayout.Toggle(logTypeFilters[actualType], new GUIContent(actualType.ToString(), actualType.ToString() + " toggle filter"), ToggleLayoutOptions);
                 }
-				collapse = GUILayout.Toggle(collapse, collapseLabel, GUILayout.ExpandWidth(false));
-
-			GUILayout.EndHorizontal();
-		}
-
-		/// <summary>
-		/// Records a log from the log callback.
-		/// </summary>
-		/// <param name="message">Message.</param>
-		/// <param name="stackTrace">Trace of where the message came from.</param>
-		/// <param name="type">Type of message (error, exception, warning, assert).</param>
-		void HandleLog (string message, string stackTrace, LogType type)
-		{
-			logs.Add(new Log {
-				message = message,
-				stackTrace = stackTrace,
-				type = type,
-			});
-
-			TrimExcessLogs();
-		}
-
-		/// <summary>
-		/// Determines whether the scroll view is scrolled to the bottom.
-		/// </summary>
-		/// <param name="innerScrollRect">Rect surrounding scroll view content.</param>
-		/// <param name="outerScrollRect">Scroll view container.</param>
-		/// <returns>Whether scroll view is scrolled to bottom.</returns>
-		bool IsScrolledToBottom (Rect innerScrollRect, Rect outerScrollRect) {
-			var innerScrollHeight = innerScrollRect.height;
-
-			// Take into account extra padding added to the scroll container.
-			var outerScrollHeight = outerScrollRect.height - GUI.skin.box.padding.vertical;
-
-			// If contents of scroll view haven't exceeded outer container, treat it as scrolled to bottom.
-			if (outerScrollHeight > innerScrollHeight) {
-				return true;
-			}
-
-			var scrolledToBottom = Mathf.Approximately(innerScrollHeight, scrollPosition.y + outerScrollHeight);
-			return scrolledToBottom;
-		}
-
-		/// <summary>
-		/// Moves the scroll view down so that the last log is visible.
-		/// </summary>
-		void ScrollToBottom ()
-		{
-			scrollPosition = new Vector2(0, Int32.MaxValue);
-		}
-
-		/// <summary>
-		/// Removes old logs that exceed the maximum number allowed.
-		/// </summary>
-		void TrimExcessLogs ()
-		{
-			if (!restrictLogCount) {
-				return;
-			}
-
-			var amountToRemove = Mathf.Max(logs.Count - maxLogs, 0);
-
-			if (amountToRemove == 0) {
-				return;
-			}
-
-			logs.RemoveRange(0, amountToRemove);
-		}
+                collapse = GUILayout.Toggle(collapse, collapseLabel, GUILayout.ExpandWidth(false));
+
+            GUILayout.EndHorizontal();
+        }
+
+        /// <summary>
+        /// Records a log from the log callback.
+        /// </summary>
+        /// <param name="message">Message.</param>
+        /// <param name="stackTrace">Trace of where the message came from.</param>
+        /// <param name="type">Type of message (error, exception, warning, assert).</param>
+        void HandleLog (string message, string stackTrace, LogType type)
+        {
+            logs.Add(new Log {
+                message = message,
+                stackTrace = stackTrace,
+                type = type,
+            });
+
+            TrimExcessLogs();
+        }
+
+        /// <summary>
+        /// Determines whether the scroll view is scrolled to the bottom.
+        /// </summary>
+        /// <param name="innerScrollRect">Rect surrounding scroll view content.</param>
+        /// <param name="outerScrollRect">Scroll view container.</param>
+        /// <returns>Whether scroll view is scrolled to bottom.</returns>
+        bool IsScrolledToBottom (Rect innerScrollRect, Rect outerScrollRect) {
+            var innerScrollHeight = innerScrollRect.height;
+
+            // Take into account extra padding added to the scroll container.
+            var outerScrollHeight = outerScrollRect.height - GUI.skin.box.padding.vertical;
+
+            // If contents of scroll view haven't exceeded outer container, treat it as scrolled to bottom.
+            if (outerScrollHeight > innerScrollHeight) {
+                return true;
+            }
+
+            var scrolledToBottom = Mathf.Approximately(innerScrollHeight, scrollPosition.y + outerScrollHeight);
+            return scrolledToBottom;
+        }
+
+        /// <summary>
+        /// Moves the scroll view down so that the last log is visible.
+        /// </summary>
+        void ScrollToBottom ()
+        {
+            scrollPosition = new Vector2(0, Int32.MaxValue);
+        }
+
+        /// <summary>
+        /// Removes old logs that exceed the maximum number allowed.
+        /// </summary>
+        void TrimExcessLogs ()
+        {
+            if (!restrictLogCount) {
+                return;
+            }
+
+            var amountToRemove = Mathf.Max(logs.Count - maxLogs, 0);
+
+            if (amountToRemove == 0) {
+                return;
+            }
+
+            logs.RemoveRange(0, amountToRemove);
+        }


Removing common assembly info

Removing common assembly info

--- build/common/CommonAssemblyInfo.cs
+++ build/common/CommonAssemblyInfo.cs
@@ -1,3 +0,0 @@
-using System.Reflection;
-
-[assembly: AssemblyCopyright("Copyright © 2017 Justin Emgarten")]


Allow zero low watermark for oxygen/hydrogen

--- BARABAS.cs
+++ BARABAS.cs
@@ -3375,7 +3375,7 @@
    oxygen_high_watermark = 60;
   }
  }
- if (oxygen_low_watermark == 0 && has_oxygen_tanks) {
+ if (oxygen_low_watermark == 0 && oxygen_high_watermark == 0 && has_oxygen_tanks) {
   if (isBaseMode()) {
    oxygen_low_watermark = 10;
   } else {
@@ -3385,7 +3385,7 @@
  if (hydrogen_high_watermark == 0 && has_hydrogen_tanks) {
   hydrogen_high_watermark = 80;
  }
- if (hydrogen_low_watermark == 0 && has_hydrogen_tanks) {
+ if (hydrogen_low_watermark == 0 && hydrogen_high_watermark == 0 && has_hydrogen_tanks) {
   if (isBaseMode()) {
    hydrogen_low_watermark = 10;
   } else {
@@ -3545,12 +3545,12 @@
  } else {
   config_options[CONFIGSTR_KEEP_STONE] = "all";
  }
- if (oxygen_low_watermark > 0) {
+ if (oxygen_high_watermark > 0) {
   config_options[CONFIGSTR_OXYGEN_WATERMARKS] = getWatermarkStr(oxygen_low_watermark, oxygen_high_watermark);
  } else {
   config_options[CONFIGSTR_OXYGEN_WATERMARKS] = "none";
  }
- if (hydrogen_low_watermark > 0) {
+ if (hydrogen_high_watermark > 0) {
   config_options[CONFIGSTR_HYDROGEN_WATERMARKS] = getWatermarkStr(hydrogen_low_watermark, hydrogen_high_watermark);
  } else {
   config_options[CONFIGSTR_HYDROGEN_WATERMARKS] = "none";
@@ -3700,7 +3700,7 @@
    oxygen_low_watermark = -1;
    oxygen_high_watermark = -1;
    return;
-  } else if (Decimal.TryParse(strval, out tmp) && tmp > 0 && tmp <= 100) {
+  } else if (Decimal.TryParse(strval, out tmp) && tmp >= 0 && tmp <= 100) {
    oxygen_low_watermark = tmp;
    oxygen_high_watermark = Math.Min(tmp * 2, 100);
    return;
@@ -3714,7 +3714,7 @@
    hydrogen_low_watermark = -1;
    hydrogen_high_watermark = -1;
    return;
-  } else if (Decimal.TryParse(strval, out tmp) && tmp > 0 && tmp <= 100) {
+  } else if (Decimal.TryParse(strval, out tmp) && tmp >= 0 && tmp <= 100) {
    hydrogen_low_watermark = tmp;
    hydrogen_high_watermark = Math.Min(tmp * 2, 100);
    return;
@@ -3813,7 +3813,7 @@
    oxygen_low_watermark = -1;
    oxygen_high_watermark = -1;
   } else if (parseWatermarkStr(strval, out low, out high)) {
-   if (low > 0 && low <= 100) {
+   if (low >= 0 && low <= 100) {
     oxygen_low_watermark = low;
    } else {
     fail = true;
@@ -3835,7 +3835,7 @@
    hydrogen_low_watermark = -1;
    hydrogen_high_watermark = -1;
   } else if (parseWatermarkStr(strval, out low, out high)) {
-   if (low > 0 && low <= 100) {
+   if (low >= 0 && low <= 100) {
     hydrogen_low_watermark = low;
    } else {
     fail = true;


new game object factory util

new game object factory util

--- platform/fGameObjectFactory.cs
+++ platform/fGameObjectFactory.cs
@@ -20,6 +20,16 @@
         {
             GameObject go = new GameObject(sName);
             return new fGameObject(go, FGOFlags.NoFlags);
+        }
+
+
+        public static T CreateParentTypeGO<T>(string sName)
+            where T : fGameObject, new()
+        {
+            GameObject go = new GameObject(sName);
+            T fgo = new T();
+            fgo.Initialize(go, FGOFlags.NoFlags);
+            return fgo;
         }


Fix typos in last patch

Fix typos in last patch

--- BARABAS.cs
+++ BARABAS.cs
@@ -338,12 +338,12 @@
 int[] skip_steps;

 // thrust block definitions
-var thrust_power = new Dictionary < string, Decimal > () {
+Dictionary < string, Decimal > thrust_power = new Dictionary < string, Decimal > () {
 	{"MyObjectBuilder_Thrust/SmallBlockSmallThrust", 33.6M },
 	{"MyObjectBuilder_Thrust/SmallBlockLargeThrust", 400M },
 	{"MyObjectBuilder_Thrust/LargeBlockSmallThrust", 560M },
 	{"MyObjectBuilder_Thrust/LargeBlockLargeThrust", 6720M },
-}
+};

 // power constants - in kWatts
 const Decimal URANIUM_INGOT_POWER = 68760M;


Corrected spacing issue with small block "D"

--- BigFont.cs
+++ BigFont.cs
@@ -1378,10 +1378,10 @@

             Alphabet.Add(new Tuple<char, Font, FontSize>('D', Font.Block, FontSize.Small), new string[]
             {
-                "█████▄  ",
+                "█████▄ ",
                 "██  ██ ",
                 "██  ██ ",
-                "█████▀  "
+                "█████▀ "
             });

             Alphabet.Add(new Tuple<char, Font, FontSize>('E', Font.Block, FontSize.Small), new string[]


Extract method for formatted string and add culture

--- resharper/src/resharper-unity/ShaderLab/Psi/Colors/ShaderLabColorReference.cs
+++ resharper/src/resharper-unity/ShaderLab/Psi/Colors/ShaderLabColorReference.cs
@@ -1,4 +1,5 @@
 using System.Collections.Generic;
+using System.Globalization;
 using JetBrains.DocumentModel;
 using JetBrains.ReSharper.Plugins.Unity.ShaderLab.Psi.Parsing;
 using JetBrains.ReSharper.Plugins.Unity.ShaderLab.Psi.Tree;
@@ -20,7 +21,7 @@
             myColorPropertyValue = colorPropertyValue;
             myColorValue = colorValue;
             ColorElement = colorElement;
-            Owner = (ITreeNode) colorValue ?? colorPropertyValue;
+            Owner = (ITreeNode)colorValue ?? colorPropertyValue;
             ColorConstantRange = colorConstantRange;

             BindOptions = new ColorBindOptions
@@ -34,13 +35,23 @@
         {
             var languageService = ShaderLabLanguage.Instance.LanguageService();
             Assertion.AssertNotNull(languageService, "languageService != null");
-            var lexer = languageService.GetPrimaryLexerFactory().CreateLexer(new StringBuffer(
-                $"({colorElement.RGBColor.R/255.0:0.##}, {colorElement.RGBColor.G/255.0:0.##}, {colorElement.RGBColor.B/255.0:0.##}, {colorElement.RGBColor.A/255.0:0.##})"));
-            var parser = (IShaderLabParser) languageService.CreateParser(lexer, null, null);
+            var formattedString = GetFormattedString(colorElement);
+            var lexer = languageService.GetPrimaryLexerFactory().CreateLexer(new StringBuffer(formattedString));
+            var parser = (IShaderLabParser)languageService.CreateParser(lexer, null, null);
             var newLiteral = parser.ParseColorLiteral();

             myColorPropertyValue?.SetColor(newLiteral);
             myColorValue?.SetConstant(newLiteral);
+        }
+
+        private static string GetFormattedString(IColorElement colorElement)
+        {
+            return string.Format(CultureInfo.InvariantCulture,
+                "({0:0.##}, {1:0.##}, {2:0.##}, {3:0.##})",
+                colorElement.RGBColor.R / 255.0,
+                colorElement.RGBColor.G / 255.0,
+                colorElement.RGBColor.B / 255.0,
+                colorElement.RGBColor.A / 255.0);
         }

         public IEnumerable<IColorElement> GetColorTable()


Updates to the SharedRedisConnection

Updates to the SharedRedisConnection

--- test/Foundatio.Redis.Tests/SharedConnection.cs
+++ test/Foundatio.Redis.Tests/SharedConnection.cs
@@ -10,11 +10,11 @@
             if (String.IsNullOrEmpty(Configuration.GetConnectionString("RedisConnectionString")))
                 return null;

-            if (_muxer == null)
+            if (_muxer == null) {
                 _muxer = ConnectionMultiplexer.Connect(Configuration.GetConnectionString("RedisConnectionString"));
-
-            _muxer.PreserveAsyncOrder = false;
-
+                _muxer.PreserveAsyncOrder = false;
+            }
+
             return _muxer;
         }
     }


Test method naming

Test method naming

--- test/Serilog.Tests/LoggerConfigurationTests.cs
+++ test/Serilog.Tests/LoggerConfigurationTests.cs
@@ -329,7 +329,7 @@
         }

         [Fact]
-        public void LevelOverridesUpArePropagated()
+        public void HigherMinimumLevelOverridesArePropagated()
         {
             var sink = new CollectingSink();

@@ -347,7 +347,7 @@
         }

         [Fact]
-        public void LevelOverridesDownArePropagated()
+        public void LowerMinimumLevelOverridesArePropagated()
         {
             var sink = new CollectingSink();


Adding tokens to balance stack after for init