v1.2.2.1

--- CotcSdk/HighLevel/Cloud.cs
+++ CotcSdk/HighLevel/Cloud.cs
@@ -85,7 +85,7 @@
 		#endregion

 		#region Members
-		public const string SdkVersion = "1.2.2";
+		public const string SdkVersion = "1.2.2.1";
 		private string ApiKey, ApiSecret, Server;
 		internal int HttpTimeoutMillis {
 			get; private set;


order by and offsets now work together well.

--- Destrier/CommandBuilder.cs
+++ Destrier/CommandBuilder.cs
@@ -31,6 +31,7 @@
         private void Initialize()
         {
             this._t = typeof(T);
+            this._orderByClause = new List<OrderByElement>();
             this.Parameters = new Dictionary<String, Object>();
             this.FullyQualifiedTableName = Model.TableNameFullyQualified(_t);

@@ -61,7 +62,14 @@
         protected List<Member> _outputMembers = new List<Member>();
         public IEnumerable<ChildCollectionMember> ChildCollections { get { return _includedChildCollections.OrderByDescending(cm => ReflectionCache.HasChildCollectionMembers(cm.CollectionType)); } }
         public String OutputTableName { get { return this.AsRootMember.OutputTableName; } }
-        private String _orderByClause = null;
+        private List<OrderByElement> _orderByClause = null;
+
+        public class OrderByElement
+        {
+            public Member Member { get; set; }
+            public Boolean Ascending { get; set; }
+        }
+
         #endregion

         #region Update
@@ -94,7 +102,7 @@
             if (columnMember == null)
                 throw new Exception("Invalid Member. Members must be either marked Column or be a child of a ReferencedObject.");

-            _orderByClause = String.Format("[{0}].[{1}] ASC", columnMember.TableAlias, columnMember.Name);
+            _orderByClause.Add(new OrderByElement() { Member = columnMember, Ascending = true });//String.Format("[{0}].[{1}] ASC", columnMember.TableAlias, columnMember.Name);
         }

         public void AddOrderByDescending<F>(Expression<Func<T, F>> expression)
@@ -106,12 +114,12 @@
             if (columnMember == null)
                 throw new Exception("Invalid Member. Members must be either marked Column or be a child of a ReferencedObject.");

-            _orderByClause = String.Format("[{0}].[{1}] DESC", columnMember.TableAlias, columnMember.Name);
+            _orderByClause.Add(new OrderByElement() { Member = columnMember, Ascending = false });
         }

         public void AddThenOrderBy<F>(Expression<Func<T, F>> expression)
         {
-            if (String.IsNullOrEmpty(_orderByClause))
+            if (!_orderByClause.Any())
                 throw new Exception("Need to run OrderBy or OrderByDescending first!");

             var body = (MemberExpression)expression.Body;
@@ -120,12 +128,12 @@
             if (columnMember == null)
                 throw new Exception("Invalid Member. Members must be either marked Column or be a child of a ReferencedObject.");

-            _orderByClause = _orderByClause + String.Format(", [{0}].[{1}] ASC", columnMember.TableAlias, columnMember.Name);
+            _orderByClause.Add(new OrderByElement() { Member = columnMember, Ascending = true });
         }

         public void AddThenOrderByDescending<F>(Expression<Func<T, F>> expression)
         {
-            if (String.IsNullOrEmpty(_orderByClause))
+            if (!_orderByClause.Any())
                 throw new Exception("Need to run OrderBy or OrderByDescending first!");

             var body = (MemberExpression)expression.Body;
@@ -134,7 +142,8 @@
             if (columnMember == null)
                 throw new Exception("Invalid Member. Members must be either marked Column or be a child of a ReferencedObject.");

-            _orderByClause = _orderByClause + String.Format(", [{0}].[{1}] DESC", columnMember.TableAlias, columnMember.Name);
+            _orderByClause.Add(new OrderByElement() { Member = columnMember, Ascending = false });
+            //_orderByClause = _orderByClause + String.Format(", [{0}].[{1}] DESC", columnMember.TableAlias, columnMember.Name);
         }

         public void AddIncludedChildCollection<F>(Expression<Func<T, F>> expression)
@@ -275,6 +284,18 @@
                     ));
             }
             return outputColumns;
+        }
+
+        private String GetOrderByClause()
+        {
+            var values = _orderByClause.Select(o => String.Format("[{0}].[{1}] {2}", ((ColumnMember)o.Member).TableAlias, ((ColumnMember)o.Member).Name, o.Ascending ? "ASC" : "DESC"));
+            return string.Join(",", values);
+        }
+
+        private String GetOuterOrderByClause()
+        {
+            var values = _orderByClause.Select(o => String.Format("[data].[{1}] {2}", ((ColumnMember)o.Member).TableAlias, ((ColumnMember)o.Member).FullyQualifiedName, o.Ascending ? "ASC" : "DESC"));
+            return string.Join(",", values);
         }

         private static void SetupTableAliases(IEnumerable<Member> members, Dictionary<String, String> tableAliases)
@@ -422,9 +443,9 @@
             if (Offset != null)
             {
                 Command.Append("\n\t, ROW_NUMBER()");
-                if (!String.IsNullOrEmpty(_orderByClause))
-                {
-                    Command.AppendFormat(" OVER (order by {0})", _orderByClause);
+                if (_orderByClause.Any())
+                {
+                    Command.AppendFormat(" OVER (order by {0})", GetOrderByClause());
                 }
                 else
                 {
@@ -483,16 +504,22 @@
                 }
             }

-            if (!String.IsNullOrEmpty(_orderByClause))
+            if (Offset == null && _orderByClause.Any())
             {
                 Command.Append("\nORDER BY");
-                Command.AppendFormat("\n\t{0}", _orderByClause);
+                Command.AppendFormat("\n\t{0}", GetOrderByClause());
             }

             if (Offset != null)
             {
                 Command.Append("\n) as data");
                 Command.AppendFormat("\nWHERE [row_number_for_offset] > {0}", Offset.Value.ToString());
+            }
+
+            if (Offset != null && _orderByClause.Any())
+            {
+                Command.Append("\nORDER BY");
+                Command.AppendFormat("\n\t{0}", GetOuterOrderByClause());
             }

             if (_includedChildCollections.Any())


Fix: wallpaper style cant take effect instantly.

--- EarthLiveSharp/mainForm.cs
+++ EarthLiveSharp/mainForm.cs
@@ -53,11 +53,11 @@

             if (Cfg.display_mode == 0)
             {
+                Wallpaper.SetDefaultStyle();
                 if (scraper.saved_path.Length > 0)
                 {
                     Wallpaper.Set(scraper.saved_path);
                 }
-                Wallpaper.SetDefaultStyle();
             }
             else if (Cfg.display_mode == 1)
             {
@@ -84,11 +84,11 @@
             scraper.UpdateImage();
             if (Cfg.display_mode == 0)
             {
+                // Wallpaper.SetDefaultStyle();
                 if (scraper.saved_path.Length > 0)
                 {
                     Wallpaper.Set(scraper.saved_path);
-                }
-                Wallpaper.SetDefaultStyle();
+                }
             }
             else if (Cfg.display_mode == 1)
             {


Implement Creature Attack

Implement Creature Attack

--- EvoNet/Objects/Creature.cs
+++ EvoNet/Objects/Creature.cs
@@ -50,7 +50,10 @@
         }

         private const float COST_EAT = 10f;
+        private const float COST_ATTACK = 10f;
         private const float GAIN_EAT = 100f;
+        private const float DESTROYED_ATTACK = 110f;
+        private const float GAIN_ATTACK = 50f;
         private const float COST_PERMANENT = 1f;
         private const float COST_WALK = 5f;
         private const float COST_ROTATE = 5f;
@@ -87,14 +90,46 @@
         private float feelerAngle;
         private Vector2 feelerPos;

-        private float energy = 150;
+        private float energy_ = 150;
+        private object energyLock = new object();
         public float Energy
         {
             get
             {
-                return energy;
-            }
-        }
+                lock (energyLock)
+                {
+                    return energy_;
+                }
+            }
+            set
+            {
+                lock (energyLock)
+                {
+                    energy_ = value;
+                }
+            }
+        }
+
+        private float timeSinceThisWasAttacked_ = 1;
+        private object AttackLock = new object();
+        public float TimeSinceThisWasAttacked
+        {
+            get
+            {
+                lock (AttackLock)
+                {
+                    return timeSinceThisWasAttacked_;
+                }
+            }
+            set
+            {
+                lock (AttackLock)
+                {
+                    timeSinceThisWasAttacked_ = value;
+                }
+            }
+        }
+
         private float age = 0;
         public float Age
         {
@@ -153,11 +188,50 @@
         private WorkingNeuron outEat         = new WorkingNeuron();
         private WorkingNeuron outMemory1     = new WorkingNeuron();

-        private Color color;
-        private Color color_inv;
+        private object colorLock = new object();
+        private Color color_;
+        private Color color_inv_;
+        private Color color
+        {
+            get
+            {
+                lock (colorLock)
+                {
+                    return color_;
+                }
+            }
+            set
+            {
+                lock (colorLock)
+                {
+                    color_ = value;
+                }
+            }
+        }
+        private Color color_inv
+        {
+            get
+            {
+                lock (colorLock)
+                {
+                    return color_inv_;
+                }
+            }
+            set
+            {
+                lock (colorLock)
+                {
+                    color_inv_ = value;
+                }
+            }
+        }

         private Creature mother;

+        private float timeSinceLastAttack = 0;
+        private const float TIMEBETWEENATTACKS = 0.1f;
+
+        private Creature feelerCreature = null;

         private List<Creature> children = new List<Creature>();
         public List<Creature> Children
@@ -338,6 +412,22 @@
             }
         }

+        private float CalculateGeneticDifferencToFeelerCreature()
+        {
+            if(feelerCreature == null)
+            {
+                return 0;
+            }
+            Vector3 vec = new Vector3(
+                color.R - feelerCreature.color.R,
+                color.G - feelerCreature.color.G,
+                color.B - feelerCreature.color.B
+                );
+
+            vec /= 255f;
+            return vec.Length();
+        }
+
         public void GenerateColorInv()
         {
             color_inv = new Color(255 - color.R, 255 - color.G, 255 - color.B);
@@ -357,10 +447,10 @@
             inFoodValuePosition.SetValue(creatureTile.food / TileMap.MAXIMUMFOODPERTILE);
             inFoodValueFeeler.SetValue(feelerTile.food / TileMap.MAXIMUMFOODPERTILE);
             inOcclusionFeeler.SetValue(feelerOcclusion);
-            inEnergy.SetValue((energy - MINIMUMSURVIVALENERGY) / (STARTENERGY - MINIMUMSURVIVALENERGY));
+            inEnergy.SetValue((Energy - MINIMUMSURVIVALENERGY) / (STARTENERGY - MINIMUMSURVIVALENERGY));
             inAge.SetValue(age / 10f);
-            inGeneticDifference.SetValue(0); //TODO find real value
-            inWasAttacked.SetValue(0); //TODO find real value
+            inGeneticDifference.SetValue(CalculateGeneticDifferencToFeelerCreature());
+            inWasAttacked.SetValue(Mathf.Clamp01(1 - TimeSinceThisWasAttacked));
             inWaterOnFeeler.SetValue(feelerTile.IsLand() ? 0 : 1);
             inWaterOnCreature.SetValue(creatureTile.IsLand() ? 0 : 1);

@@ -377,7 +467,10 @@
             ActBirth();
             ActFeelerRotate();
             ActEat(costMult, t, fixedDeltaTime);
-
+            ActAttack(costMult);
+
+            timeSinceLastAttack += fixedDeltaTime;
+            TimeSinceThisWasAttacked += fixedDeltaTime;
             age += fixedDeltaTime;

             if (oldestCreatureEver == null)
@@ -389,9 +482,7 @@
                 _oldestCreatureEver = this;
             }

-            //TODO implement Attack
-
-            if (energy < 100 || float.IsNaN(energy))
+            if (Energy < 100 || float.IsNaN(Energy))
             {
                 Kill(t);
             }
@@ -403,16 +494,31 @@
         {
             if (t.IsLand())
             {
-                EvoGame.Instance.tileMap.FoodValues[t.position.X, t.position.Y] += energy * FOODDROPPERCENTAGE;
+                EvoGame.Instance.tileMap.FoodValues[t.position.X, t.position.Y] += Energy * FOODDROPPERCENTAGE;
             }
             Manager.RemoveCreature(this);
+        }
+
+        private void ActAttack(float costMult)
+        {
+            if(outAttack.GetValue() > 0 && timeSinceLastAttack > TIMEBETWEENATTACKS)
+            {
+                timeSinceLastAttack = 0;
+                Energy -= COST_ATTACK;
+                if(feelerCreature != null)
+                {
+                    feelerCreature.Energy -= DESTROYED_ATTACK;
+                    feelerCreature.TimeSinceThisWasAttacked = 0;
+                    this.Energy += GAIN_ATTACK;
+                }
+            }
         }

         private void ActRotate(float costMult, float fixedDeltaTime)
         {
             float rotateForce = Mathf.ClampNegPos(outRotate.GetValue());
             this.viewAngle += rotateForce * fixedDeltaTime * ROTATE_FACTOR;
-            energy -= Mathf.Abs(rotateForce * COST_ROTATE * fixedDeltaTime * costMult);
+            Energy -= Mathf.Abs(rotateForce * COST_ROTATE * fixedDeltaTime * costMult);
         }

         private void ActMove(float costMult, float fixedDeltaTime)
@@ -421,7 +527,7 @@
             float forwardForce = Mathf.ClampNegPos(outForward.GetValue());
             forwardVector *= forwardForce;
             this.pos += forwardVector;
-            energy -= Mathf.Abs(forwardForce * COST_WALK * fixedDeltaTime * costMult);
+            Energy -= Mathf.Abs(forwardForce * COST_WALK * fixedDeltaTime * costMult);
         }

         private void ActBirth()
@@ -441,7 +547,7 @@
             if (eatWish > 0)
             {
                 Eat(eatWish, creatureTile, fixedDeltaTime);
-                energy -= eatWish * COST_EAT * fixedDeltaTime * costMult;
+                Energy -= eatWish * COST_EAT * fixedDeltaTime * costMult;
             }
         }

@@ -450,7 +556,7 @@
             if(t.type != TileType.None)
             {
                 float eatAmount = GAIN_EAT * eatWish * fixedDeltaTime;
-                energy += EvoGame.Instance.tileMap.EatOfTile(t.position.X, t.position.Y, eatAmount);
+                Energy += EvoGame.Instance.tileMap.EatOfTile(t.position.X, t.position.Y, eatAmount);
             }

         }
@@ -474,12 +580,12 @@
             child.Manager = Manager;
             children.Add(child);
             Manager.AddCreature(child);
-            energy -= STARTENERGY;
+            Energy -= STARTENERGY;
         }

         public bool IsAbleToGiveBirth()
         {
-            return energy > STARTENERGY + MINIMUMSURVIVALENERGY * 1.1f;
+            return Energy > STARTENERGY + MINIMUMSURVIVALENERGY * 1.1f;
         }

         public void CalculateFeelerPos(float feelerDistance)
@@ -506,9 +612,10 @@
             RenderHelper.DrawLine(spriteBatch, pos.X + offset.X, pos.Y + offset.Y, feelerPos.X + offset.X, feelerPos.Y + offset.Y, Color.White);
             spriteBatch.Draw(bodyTex, new Rectangle((int)(pos.X + offset.X - CREATURESIZE / 2), (int)(pos.Y + offset.Y - CREATURESIZE / 2), CREATURESIZE, CREATURESIZE), color_inv);
             spriteBatch.Draw(bodyTex, new Rectangle((int)(pos.X + offset.X - (CREATURESIZE - 4) / 2), (int)(pos.Y + offset.Y - (CREATURESIZE - 4) / 2), CREATURESIZE - 4, CREATURESIZE - 4), color);
-            spriteBatch.Draw(feelerTex, new Rectangle((int)(feelerPos.X + offset.X - 5), (int)(feelerPos.Y + offset.Y - 5), 10, 10), Color.Blue);
-        }
-
+            spriteBatch.Draw(feelerTex, new Rectangle((int)(feelerPos.X + offset.X - 5), (int)(feelerPos.Y + offset.Y - 5), 10, 10), timeSinceLastAttack > TIMEBETWEENATTACKS ? Color.Blue : Color.Red);
+        }
+
+        [MethodImpl(MethodImplOptions.Synchronized)]
         public void Serialize(BinaryWriter writer)
         {
             writer.Write("CreatureBegin");
@@ -516,7 +623,7 @@
             writer.Write(pos);
             writer.Write(viewAngle);
             writer.Write(feelerAngle);
-            writer.Write(energy);
+            writer.Write(Energy);
             writer.Write(age);
             writer.Write(generation);
             writer.Write(color);
@@ -549,6 +656,7 @@
             }
         }

+        [MethodImpl(MethodImplOptions.Synchronized)]
         public void Deserialize(BinaryReader reader)
         {
             string magicString = reader.ReadString();
@@ -557,7 +665,7 @@
             pos = reader.ReadVector2();
             viewAngle = reader.ReadSingle();
             feelerAngle = reader.ReadSingle();
-            energy = reader.ReadSingle();
+            Energy = reader.ReadSingle();
             age = reader.ReadSingle();
             generation = reader.ReadInt32();
             color = reader.ReadColor();
@@ -579,6 +687,7 @@
         public void HandleCollisions()
         {
             feelerOcclusion = 0;
+            feelerCreature = null;
             CalculateFeelerPos(MAXIMUMFEELERDISTANCE);
             for (int i = collisionGridX - 1; i <= collisionGridX + 1; i++)
             {
@@ -615,8 +724,8 @@
                 CalculateFeelerPos(MAXIMUMFEELERDISTANCE * t);
                 if (IsMyFeelerCollidingWithCreature(c))
                 {
-                    long idd = this.id;
                     feelerOcclusion = 1 - t;
+                    feelerCreature = c;
                     return;
                 }
             }


Fixed test.

Fixed test.

--- Flubu.Tests/TargetTests.cs
+++ Flubu.Tests/TargetTests.cs
@@ -149,9 +149,9 @@
         {
             TargetTree targetTree = new TargetTree(ServiceProvider, new CommandArguments { TargetsToExecute = new List<string> { "target 3", "target 1", "target 2" } });

-            var target1 = targetTree.AddTarget("target 1").AddTaskAsync(new SimpleTaskWithDelay());
-
-            var target2 = targetTree.AddTarget("target 2").AddTaskAsync(new SimpleTaskWithDelay());
+            var target1 = targetTree.AddTarget("target 1").AddTask(new SimpleTaskWithDelay());
+
+            var target2 = targetTree.AddTarget("target 2").AddTask(new SimpleTaskWithDelay());

             var target3 = targetTree.AddTarget("target 3");
             target3.DependsOnAsync(target1, target2);
@@ -173,9 +173,9 @@
         {
             TargetTree targetTree = new TargetTree(ServiceProvider, new CommandArguments {TargetsToExecute = new List<string> { "target 3", "target 1", "target 2" }});

-            var target1 = targetTree.AddTarget("target 1");
-
-            var target2 = targetTree.AddTarget("target 2");
+            var target1 = targetTree.AddTarget("target 1").AddTask(new SimpleTaskWithDelay()); ;
+
+            var target2 = targetTree.AddTarget("target 2").AddTask(new SimpleTaskWithDelay()); ;

             var target3 = targetTree.AddTarget("target 3");
             target3.DependsOn(target1, target2);


add submat test

add submat test

--- test/OpenCvSharp.Tests/core/MatTest.cs
+++ test/OpenCvSharp.Tests/core/MatTest.cs
@@ -102,7 +102,7 @@
             Assert.Equal(new Vec3b(33, 44, 55), mat8UC3.Get<Vec3b>(0, 0));
             Assert.Equal(new Vec3b(33, 44, 55), mat8UC3.Get<Vec3b>(1, 1));
             Assert.Equal(new Vec3b(33, 44, 55), mat8UC3.Get<Vec3b>(2, 2));
-            mat8UC3.Set<Vec3b>(0, 1,  new Vec3b(64, 128, 192));
+            mat8UC3.Set<Vec3b>(0, 1, new Vec3b(64, 128, 192));
             mat8UC3.Set<Vec3b>(1, 2, new Vec3b(64, 128, 192));
             mat8UC3.Set<Vec3b>(2, 0, new Vec3b(64, 128, 192));
             Assert.Equal(new Vec3b(64, 128, 192), mat8UC3.Get<Vec3b>(0, 1));
@@ -161,7 +161,7 @@
         [Fact]
         public void Diag()
         {
-            var data = new byte[] {1, 10, 100};
+            var data = new byte[] { 1, 10, 100 };
             using var mat = new Mat(3, 1, MatType.CV_8UC1, data);
             using var diag = Mat.Diag(mat);
             Assert.Equal(3, diag.Rows);
@@ -178,7 +178,7 @@
             Assert.Equal(0, diag.Get<byte>(2, 1));
             Assert.Equal(100, diag.Get<byte>(2, 2));
         }
-
+
         [Fact]
         public void CopyTo()
         {
@@ -275,7 +275,7 @@
             using var subMat1 = mat.SubMat(0..2, 1..3);
             Assert.Equal(new Size(2, 2), subMat1.Size());
             Assert.True(subMat1.GetArray(out byte[] subMat1Array));
-            Assert.Equal(new byte[]{2, 3, 5, 6}, subMat1Array);
+            Assert.Equal(new byte[] { 2, 3, 5, 6 }, subMat1Array);

             using var subMat2 = mat[1..2, ..];
             Assert.Equal(new Size(3, 1), subMat2.Size());
@@ -305,7 +305,7 @@
         [Fact]
         public void T()
         {
-            var data = new byte[] {1, 10, 100};
+            var data = new byte[] { 1, 10, 100 };
             using var mat = new Mat(3, 1, MatType.CV_8UC1, data);
             using var tExpr = mat.T();
             using var t = tExpr.ToMat();
@@ -318,11 +318,11 @@
             Assert.Equal(10, t.Get<byte>(0, 1));
             Assert.Equal(100, t.Get<byte>(0, 2));
         }
-
+
         [Fact]
         public void Inv()
         {
-            var data = new double[] {1, 2, 3, 4};
+            var data = new double[] { 1, 2, 3, 4 };
             using var mat = new Mat(2, 2, MatType.CV_64FC1, data);
             using var invExpr = mat.Inv();
             using var inv = invExpr.ToMat();
@@ -336,12 +336,12 @@
             Assert.Equal(+1.5, inv.Get<double>(1, 0), 3);
             Assert.Equal(-0.5, inv.Get<double>(1, 1), 3);
         }
-
+
         [Fact]
         public void Dot()
         {
-            var data1 = new double[] {1, 2};
-            var data2 = new double[] {3, 4};
+            var data1 = new double[] { 1, 2 };
+            var data2 = new double[] { 3, 4 };
             using var mat1 = new Mat(2, 1, MatType.CV_64FC1, data1);
             using var mat2 = new Mat(2, 1, MatType.CV_64FC1, data2);
             var dot = mat1.Dot(mat2);
@@ -356,7 +356,7 @@
             mat.Reserve(10);
             mat.ReserveBuffer(100);
         }
-
+
         [Fact]
         public void Resize()
         {
@@ -364,7 +364,7 @@
             mat.Resize(10);
             Assert.Equal(10, mat.Rows);
         }
-
+
         [Fact]
         public void Reshape()
         {
@@ -406,7 +406,7 @@
             Assert.False(m2.IsContinuous());
             Assert.True(m2.IsSubmatrix());
         }
-
+
         [Fact]
         public void Type()
         {
@@ -416,7 +416,7 @@
             using var m2 = new Mat(1, 1, MatType.CV_32FC4);
             Assert.Equal(MatType.CV_32FC4, m2.Type());
         }
-
+
         [Fact]
         public void Depth()
         {
@@ -440,7 +440,7 @@
         [Fact]
         public void MatOfDoubleFromArray()
         {
-            var array = new double[] {7, 8, 9};
+            var array = new double[] { 7, 8, 9 };
             using var m = Mat.FromArray(array);

             var indexer = m.GetIndexer();
@@ -454,7 +454,7 @@
         [Fact]
         public void MatOfDoubleFromRectangularArray()
         {
-            var array = new double[,] {{1, 2}, {3, 4}};
+            var array = new double[,] { { 1, 2 }, { 3, 4 } };
             using var m = Mat.FromArray(array);

             var indexer = m.GetIndexer();
@@ -471,7 +471,7 @@
         [Fact]
         public void MatOfFloatFromArray()
         {
-            var array = new float[] {7, 8, 9};
+            var array = new float[] { 7, 8, 9 };
             using var m = Mat.FromArray(array);

             var indexer = m.GetIndexer();
@@ -485,7 +485,7 @@
         [Fact]
         public void MatOfFloatFromRectangularArray()
         {
-            var array = new float[,] {{1, 2}, {3, 4}};
+            var array = new float[,] { { 1, 2 }, { 3, 4 } };
             using var m = Mat.FromArray(array);

             var indexer = m.GetIndexer();
@@ -502,7 +502,7 @@
         [Fact]
         public void MatOfIntFromArray()
         {
-            var array = new[] {7, 8, 9};
+            var array = new[] { 7, 8, 9 };
             var m = Mat.FromArray(array);

             var indexer = m.GetIndexer();
@@ -516,7 +516,7 @@
         [Fact]
         public void MatOfIntFromRectangularArray()
         {
-            var array = new[,] {{1, 2}, {3, 4}};
+            var array = new[,] { { 1, 2 }, { 3, 4 } };
             using var m = Mat.FromArray(array);

             var indexer = m.GetIndexer();
@@ -533,7 +533,7 @@
         [Fact]
         public void MatOfUShortFromArray()
         {
-            var array = new ushort[] {7, 8, 9};
+            var array = new ushort[] { 7, 8, 9 };
             using var m = Mat.FromArray(array);

             var indexer = m.GetIndexer();
@@ -547,7 +547,7 @@
         [Fact]
         public void MatOfUShortFromRectangularArray()
         {
-            var array = new ushort[,] {{1, 2}, {3, 4}};
+            var array = new ushort[,] { { 1, 2 }, { 3, 4 } };
             using var m = Mat.FromArray(array);

             var indexer = m.GetIndexer();
@@ -564,7 +564,7 @@
         [Fact]
         public void MatOfShortFromArray()
         {
-            var array = new short[] {7, 8, 9};
+            var array = new short[] { 7, 8, 9 };
             using var m = Mat.FromArray(array);

             var indexer = m.GetIndexer();
@@ -578,7 +578,7 @@
         [Fact]
         public void MatOfShortFromRectangularArray()
         {
-            var array = new short[,] {{1, 2}, {3, 4}};
+            var array = new short[,] { { 1, 2 }, { 3, 4 } };
             using var m = Mat.FromArray(array);

             var indexer = m.GetIndexer();
@@ -595,7 +595,7 @@
         [Fact]
         public void MatOfByteFromArray()
         {
-            var array = new byte[] {7, 8, 9};
+            var array = new byte[] { 7, 8, 9 };
             var m = Mat.FromArray(array);

             var indexer = m.GetIndexer();
@@ -609,7 +609,7 @@
         [Fact]
         public void MatOfByteFromRectangularArray()
         {
-            var array = new byte[,] {{1, 2}, {3, 4}};
+            var array = new byte[,] { { 1, 2 }, { 3, 4 } };
             using var m = Mat.FromArray(array);

             var indexer = m.GetIndexer();
@@ -626,7 +626,7 @@
         [Fact]
         public void GetArrayByte()
         {
-            var data = new byte[] {0, 128, 255, 1};
+            var data = new byte[] { 0, 128, 255, 1 };

             using var mat = new Mat(2, 2, MatType.CV_8UC1, data);
             bool success = mat.GetArray(out byte[] data2);
@@ -638,13 +638,13 @@
         [Fact]
         public void GetArrayFailure()
         {
-            var data = new byte[] {0, 128, 255, 1};
+            var data = new byte[] { 0, 128, 255, 1 };

             using var mat = new Mat(2, 2, MatType.CV_64FC4, data);
-            Assert.Throws<OpenCvSharpException>( ()=>
-            {
-                mat.GetArray(out byte[] _);
-            });
+            Assert.Throws<OpenCvSharpException>(() =>
+           {
+               mat.GetArray(out byte[] _);
+           });
         }

         [Fact]
@@ -662,11 +662,11 @@
             Assert.True(success);
             Assert.Equal(data, data2);
         }
-
+
         [Fact]
         public void GetArrayInt16()
         {
-            var data = new short[] {3, short.MaxValue, short.MinValue, 10000};
+            var data = new short[] { 3, short.MaxValue, short.MinValue, 10000 };

             using var mat = new Mat(2, 2, MatType.CV_16SC1, data);
             bool success = mat.GetArray(out short[] data2);
@@ -679,7 +679,7 @@
         public void GetArrayInt32()
         {
             // ReSharper disable once RedundantExplicitArrayCreation
-            var data = new int[] {3, int.MaxValue, int.MinValue, 65536};
+            var data = new int[] { 3, int.MaxValue, int.MinValue, 65536 };

             using var mat = new Mat(2, 2, MatType.CV_32SC1, data);
             bool success = mat.GetArray(out int[] data2);
@@ -692,7 +692,7 @@
         public void GetArraySingle()
         {
             // ReSharper disable once RedundantExplicitArrayCreation
-            var data = new float[] {3.14f, float.MaxValue, float.MinValue, 12345.6789f};
+            var data = new float[] { 3.14f, float.MaxValue, float.MinValue, 12345.6789f };

             using var mat = new Mat(2, 2, MatType.CV_32FC1, data);
             bool success = mat.GetArray(out float[] data2);
@@ -700,12 +700,12 @@
             Assert.True(success);
             Assert.Equal(data, data2);
         }
-
+
         [Fact]
         public void GetArrayDouble()
         {
             // ReSharper disable once RedundantExplicitArrayCreation
-            var data = new double[] {3.14, double.MaxValue, double.MinValue, double.Epsilon};
+            var data = new double[] { 3.14, double.MaxValue, double.MinValue, double.Epsilon };

             using var mat = new Mat(2, 2, MatType.CV_64FC1, data);
             bool success = mat.GetArray(out double[] data2);
@@ -713,16 +713,16 @@
             Assert.True(success);
             Assert.Equal(data, data2);
         }
-
+
         [Fact]
         public void GetArrayPoint()
         {
-            var data = new []
-            {
-                new Point(1, 2),
-                new Point(3, 4),
-                new Point(5, 6),
-                new Point(7, 8),
+            var data = new[]
+            {
+                new Point(1, 2),
+                new Point(3, 4),
+                new Point(5, 6),
+                new Point(7, 8),
             };

             using var mat = new Mat(2, 2, MatType.CV_32SC2, data);
@@ -735,12 +735,12 @@
         [Fact]
         public void GetArrayRect()
         {
-            var data = new []
-            {
-                new Rect(1, 2, 3, 4),
-                new Rect(5, 6, 7, 8),
-                new Rect(9, 10, 11, 12),
-                new Rect(13, 14, 15, 16),
+            var data = new[]
+            {
+                new Rect(1, 2, 3, 4),
+                new Rect(5, 6, 7, 8),
+                new Rect(9, 10, 11, 12),
+                new Rect(13, 14, 15, 16),
             };

             using var mat = new Mat(2, 2, MatType.CV_32SC4, data);
@@ -760,7 +760,7 @@
             {
                 for (int c = 0; c < 2; c++)
                 {
-                    var value = new Vec2b((byte) r, (byte) c);
+                    var value = new Vec2b((byte)r, (byte)c);
                     mat.Set(r, c, value);
                     expectedData[r * 2 + c] = value;
                 }
@@ -797,12 +797,12 @@
         [Fact]
         public void GetArrayVec3b()
         {
-            var data = new []
-            {
-                new Vec3b(1, 2, 3),
-                new Vec3b(4, 5, 6),
-                new Vec3b(7, 8, 9),
-                new Vec3b(10, 11, 12),
+            var data = new[]
+            {
+                new Vec3b(1, 2, 3),
+                new Vec3b(4, 5, 6),
+                new Vec3b(7, 8, 9),
+                new Vec3b(10, 11, 12),
             };

             using var mat = new Mat(2, 2, MatType.CV_8UC3, data);
@@ -811,7 +811,7 @@
             Assert.True(success);
             Assert.Equal(data, data2);
         }
-
+
         [Fact]
         public void GetRectangularArrayVec3b()
         {
@@ -839,7 +839,7 @@
         {
             using var mat = new Mat(2, 2, MatType.CV_8UC1);

-            var data = new byte[] {64, 128, 255, 1};
+            var data = new byte[] { 64, 128, 255, 1 };
             mat.SetArray(data);

             Assert.Equal(data[0], mat.Get<byte>(0, 0));
@@ -847,14 +847,14 @@
             Assert.Equal(data[2], mat.Get<byte>(1, 0));
             Assert.Equal(data[3], mat.Get<byte>(1, 1));
         }
-
+
         [Fact]
         public void SetArrayByteFailure()
         {
             using var mat = new Mat(2, 2, MatType.CV_64FC3);

-            var data = new byte[] {64, 128, 255, 1};
-            Assert.Throws<OpenCvSharpException>(()=>
+            var data = new byte[] { 64, 128, 255, 1 };
+            Assert.Throws<OpenCvSharpException>(() =>
             {
                 mat.SetArray(data);
             });
@@ -867,7 +867,7 @@

             var data = new byte[,]
             {
-                {64, 128},
+                {64, 128},
                 {255, 1}
             };
             mat.SetRectangularArray(data);
@@ -883,7 +883,7 @@
         {
             using var mat = new Mat(2, 2, MatType.CV_16SC1);

-            var data = new short[] {123, short.MinValue, short.MaxValue, 1};
+            var data = new short[] { 123, short.MinValue, short.MaxValue, 1 };
             mat.SetArray(data);

             Assert.Equal(data[0], mat.Get<short>(0, 0));
@@ -891,14 +891,14 @@
             Assert.Equal(data[2], mat.Get<short>(1, 0));
             Assert.Equal(data[3], mat.Get<short>(1, 1));
         }
-
+
         [Fact]
         public void SetArrayInt32()
         {
             using var mat = new Mat(2, 2, MatType.CV_32SC1);

             // ReSharper disable once RedundantExplicitArrayCreation
-            var data = new int[] {12345678, int.MinValue, int.MaxValue, 1};
+            var data = new int[] { 12345678, int.MinValue, int.MaxValue, 1 };
             mat.SetArray(data);

             Assert.Equal(data[0], mat.Get<int>(0, 0));
@@ -906,14 +906,14 @@
             Assert.Equal(data[2], mat.Get<int>(1, 0));
             Assert.Equal(data[3], mat.Get<int>(1, 1));
         }
-
+
         [Fact]
         public void SetArraySingle()
         {
             using var mat = new Mat(2, 2, MatType.CV_32FC1);

             // ReSharper disable once RedundantExplicitArrayCreation
-            var data = new float[] {float.Epsilon, float.MinValue, float.MaxValue, 1};
+            var data = new float[] { float.Epsilon, float.MinValue, float.MaxValue, 1 };
             mat.SetArray(data);

             Assert.Equal(data[0], mat.Get<float>(0, 0));
@@ -921,14 +921,14 @@
             Assert.Equal(data[2], mat.Get<float>(1, 0));
             Assert.Equal(data[3], mat.Get<float>(1, 1));
         }
-
+
         [Fact]
         public void SetArrayDouble()
         {
             using var mat = new Mat(2, 2, MatType.CV_64FC1);

             // ReSharper disable once RedundantExplicitArrayCreation
-            var data = new double[] {double.Epsilon, double.MinValue, double.MaxValue, 1};
+            var data = new double[] { double.Epsilon, double.MinValue, double.MaxValue, 1 };
             mat.SetArray(data);

             Assert.Equal(data[0], mat.Get<double>(0, 0));
@@ -936,19 +936,19 @@
             Assert.Equal(data[2], mat.Get<double>(1, 0));
             Assert.Equal(data[3], mat.Get<double>(1, 1));
         }
-
+
         [Fact]
         public void SetArrayPoint()
         {
             using var mat = new Mat(2, 2, MatType.CV_32SC2);

             // ReSharper disable once RedundantExplicitArrayCreation
-            var data = new []
-            {
-                new Point(1, 2),
-                new Point(3, 4),
-                new Point(5, 6),
-                new Point(7, 8),
+            var data = new[]
+            {
+                new Point(1, 2),
+                new Point(3, 4),
+                new Point(5, 6),
+                new Point(7, 8),
             };
             mat.SetArray(data);

@@ -957,19 +957,19 @@
             Assert.Equal(data[2], mat.Get<Point>(1, 0));
             Assert.Equal(data[3], mat.Get<Point>(1, 1));
         }
-
+
         [Fact]
         public void SetArrayRect()
         {
             using var mat = new Mat(2, 2, MatType.CV_32SC4);

             // ReSharper disable once RedundantExplicitArrayCreation
-            var data = new []
-            {
-                new Rect(1, 2, 3, 4),
-                new Rect(3, 4, 7, 8),
-                new Rect(9, 10, 11, 12),
-                new Rect(13, 14, 15, 16),
+            var data = new[]
+            {
+                new Rect(1, 2, 3, 4),
+                new Rect(3, 4, 7, 8),
+                new Rect(9, 10, 11, 12),
+                new Rect(13, 14, 15, 16),
             };
             mat.SetArray(data);

@@ -978,7 +978,7 @@
             Assert.Equal(data[2], mat.Get<Rect>(1, 0));
             Assert.Equal(data[3], mat.Get<Rect>(1, 1));
         }
-
+
         [Fact]
         public void SetRectangularArrayRect()
         {
@@ -1062,7 +1062,7 @@
                 }
             }
         }
-
+
         [Fact]
         public void RowMat()
         {
@@ -1081,7 +1081,7 @@
                 }
             }
         }
-
+
         [Fact]
         public void RowMatCopyTo()
         {
@@ -1154,12 +1154,12 @@
         {
             {
                 using var expected = new Mat(size, size, MatType.CV_8U);
-                using var actual = expected.Clone();
+                using var actual = expected.Clone();
                 Assert.Equal(expected.Type(), actual.Type());
             }
             {
                 using var expected = new Mat<byte>(size, size);
-                using var actual = expected.Clone();
+                using var actual = expected.Clone();
                 Assert.Equal(expected.Type(), actual.Type());
             }
         }
@@ -1174,12 +1174,12 @@
         {
             {
                 using var expected = new Mat(size, size, MatType.CV_32S);
-                using var actual = expected.Clone();
+                using var actual = expected.Clone();
                 Assert.Equal(expected.Type(), actual.Type());
             }
             {
                 using var expected = new Mat<int>(size, size);
-                using var actual = expected.Clone();
+                using var actual = expected.Clone();
                 Assert.Equal(expected.Type(), actual.Type());
             }
         }
@@ -1194,12 +1194,12 @@
         {
             {
                 using var expected = new Mat(size, size, MatType.CV_64F);
-                using var actual = expected.Clone();
+                using var actual = expected.Clone();
                 Assert.Equal(expected.Type(), actual.Type());
             }
             {
                 using var expected = new Mat<double>(size, size);
-                using var actual = expected.Clone();
+                using var actual = expected.Clone();
                 Assert.Equal(expected.Type(), actual.Type());
             }
         }
@@ -1210,8 +1210,8 @@
         [Fact]
         public void CreateMultiDimensional()
         {
-            using var m = new Mat(new int[] {10,20,30}, MatType.CV_8UC1);
-
+            using var m = new Mat(new int[] { 10, 20, 30 }, MatType.CV_8UC1);
+
             Assert.False(m.Empty());
             Assert.Equal(3, m.Dims);
             Assert.Equal(-1, m.Rows);
@@ -1221,5 +1221,46 @@
             Assert.Equal(20, m.Size(1));
             Assert.Equal(30, m.Size(2));
         }
+
+        /// <summary>
+        /// https://github.com/shimat/opencvsharp/issues/1312
+        /// </summary>
+        [Fact]
+        public void SubmatOfMultiDimensionalMat()
+        {
+            using var m = new Mat(new int[] { 5, 6, 7 }, MatType.CV_8UC1);
+            for (int i = 0; i < 5; i++)
+            {
+                for (int j = 0; j < 6; j++)
+                {
+                    for (int k = 0; k < 7; k++)
+                    {
+                        m.At<byte>(i, j, k) = (byte)(i + j + k);
+                    }
+                }
+            }
+
+            for (int i = 0; i < 5; i++)
+            {
+                using var mi_3d = m.SubMat(new Range(i, i + 1), Range.All, Range.All);
+                Assert.Equal(3, mi_3d.Dims);
+                Assert.Equal(1, mi_3d.Size(0));
+                Assert.Equal(6, mi_3d.Size(1));
+                Assert.Equal(7, mi_3d.Size(2));
+
+                using var mi = mi_3d.Reshape(0, mi_3d.Size(1), mi_3d.Size(2));
+                Assert.Equal(2, mi.Dims);
+                Assert.Equal(6, mi.Size(0));
+                Assert.Equal(7, mi.Size(1));
+
+                for (int j = 0; j < 6; j++)
+                {
+                    for (int k = 0; k < 7; k++)
+                    {
+                        Assert.Equal((byte)(i + j + k), mi.At<byte>(j, k));
+                    }
+                }
+            }
+        }
     }
 }


Remove duplicate laser trail from Blaster 4's projectile.

--- game/server/weapons/blaster4/blaster4.projectile.cs
+++ game/server/weapons/blaster4/blaster4.projectile.cs
@@ -52,7 +52,7 @@
 	//laserTailLen			 = 10.0;

 	laserTrail[0]			= RedBlaster4ProjectileLaserTrail;
-	laserTrail[1]			= RedBlaster4ProjectileLaserTrail;
+	//laserTrail[1]			= RedBlaster4ProjectileLaserTrail;
 	smoothLaserTrail = false;

 	//particleEmitter	  = RedBlaster4ProjectileParticleEmitter;
@@ -123,7 +123,7 @@
 	//laserTail          = BlueBlaster4ProjectileLaserTail;

 	laserTrail[0]      = BlueBlaster4ProjectileLaserTrail;
-	laserTrail[1]      = BlueBlaster4ProjectileLaserTrail;
+	//laserTrail[1]      = BlueBlaster4ProjectileLaserTrail;

 	lightColor  = "0.0 0.0 1.0";
 };


progress on support for UWP and visual studio 2015

--- gen_build.cs
+++ gen_build.cs
@@ -58,6 +58,10 @@
 		items_sqlite3.Add(new config_sqlite3 { env="winrt81", cpu="arm", dll=dyn });
 		items_sqlite3.Add(new config_sqlite3 { env="winrt81", cpu="x64", dll=dyn });
 		items_sqlite3.Add(new config_sqlite3 { env="winrt81", cpu="x86", dll=dyn });
+
+		items_sqlite3.Add(new config_sqlite3 { env="uwp", cpu="arm", dll=dyn });
+		items_sqlite3.Add(new config_sqlite3 { env="uwp", cpu="x64", dll=dyn });
+		items_sqlite3.Add(new config_sqlite3 { env="uwp", cpu="x86", dll=dyn });

 		items_sqlite3.Add(new config_sqlite3 { env="wp80", cpu="arm", dll=dyn });
 		items_sqlite3.Add(new config_sqlite3 { env="wp80", cpu="x86", dll=dyn });
@@ -929,6 +933,14 @@
 					f.WriteElementString("WindowsAppContainer", "true");
 					f.WriteElementString("AppContainerApplication", "true");
 					break;
+				case "uwp":
+					f.WriteElementString("MinimumVisualStudioVersion", "14.0");
+					f.WriteElementString("ApplicationType", "Windows Store");
+					f.WriteElementString("AppContainerApplication", "true");
+					f.WriteElementString("ApplicationTypeRevision", "10.0");
+					f.WriteElementString("WindowsTargetPlatformMinVersion", "10.0.10240.0");
+					f.WriteElementString("WindowsTargetPlatformVersion", "10.0.10586.0");
+					break;
 				case "wp80":
 					f.WriteElementString("MinimumVisualStudioVersion", "11.0");
 					break;
@@ -974,6 +986,9 @@
 				case "winrt81":
 					f.WriteElementString("PlatformToolset", "v120");
 					break;
+				case "uwp":
+					f.WriteElementString("PlatformToolset", "v140");
+					break;
 				case "wp80":
 					f.WriteElementString("PlatformToolset", "v110_wp80");
 					break;
@@ -996,6 +1011,7 @@
 				case "wp80":
 				case "wp81_rt":
 				case "wp81_sl":
+				case "uwp":
 					f.WriteStartElement("ItemDefinitionGroup");
 					f.WriteStartElement("ClCompile");
 					write_cpp_define(f, "SQLITE_OS_WINRT");
@@ -1014,6 +1030,7 @@
 				case "wp80":
 				case "wp81_rt":
 				case "wp81_sl":
+				case "uwp":
 					f.WriteStartElement("ItemDefinitionGroup");
 					f.WriteStartElement("ClCompile");
 					write_cpp_define(f, "SQLITE_WIN32_FILEMAPPING_API=1");


Getting real tired of my sh*t

Getting real tired of my sh*t

--- BrewLab.Scripts.RecipeGenerator/Program.cs
+++ BrewLab.Scripts.RecipeGenerator/Program.cs
@@ -32,44 +32,39 @@

         private static IEnumerable<Recipe> _generateRecipes(int quantity = 100)
         {
-            Func<int, bool, IEnumerable<Recipe>> generate = null;
-
-            generate = new Func<int, bool, IEnumerable<Recipe>>((q, isVersion) =>
+            Func<bool, Recipe> generateRecipe = null;
+
+            generateRecipe = new Func<bool, Recipe>(isVersion =>
             {
-                var recipes = new List<Recipe>();
+                string name = _generateText(10);

-                for (int i = 0; i < q; i++)
+                double volume = ((double)_random.Next(20) / 20) * 5;
+
+                string units = string.Empty;
+
+                if (volume > 2.5)
+                    units = "Gallons";
+                else
+                    units = "Liters";
+
+                string yeastType = _generateText(25);
+
+                var recipe = new Recipe
                 {
-                    string name = _generateText(10);
+                    Name = name,
+                    UserID = _userID,
+                    Volume = volume,
+                    Units = units,
+                    YeastType = yeastType,
+                    Versions = !isVersion ? Enumerable.Range(0, 10)
+                        .Select(x => generateRecipe(true)).ToList() : null
+                };

-                    double volume = ((double)_random.Next(20) / 20) * 5;
-
-                    string units = string.Empty;
-
-                    if (volume > 2.5)
-                        units = "Gallons";
-                    else
-                        units = "Liters";
-
-                    string yeastType = _generateText(25);
-
-                    var recipe = new Recipe
-                    {
-                        Name = name,
-                        UserID = _userID,
-                        Volume = volume,
-                        Units = units,
-                        YeastType = yeastType,
-                        Versions = !isVersion ? generate(10, true).ToList() : null
-                    };
-
-                    recipes.Add(recipe);
-                }
-
-                return recipes;
+                return recipe;
             });

-            return generate(quantity, false);
+            for (int i = 0; i < quantity; i++)
+                yield return generateRecipe(false);
         }

         private static async Task<string> _postRecipe(Recipe recipe)


Don't log exceptions in release builds

Don't log exceptions in release builds

--- RedoxExtensions.Wrapper/Diagnostics/ErrorLogger.cs
+++ RedoxExtensions.Wrapper/Diagnostics/ErrorLogger.cs
@@ -26,6 +26,7 @@

         public void LogError(Exception ex)
         {
+#if DEBUG
             lock (_writeLock)
             {
                 using (StreamWriter errorStream = new StreamWriter(this._currentPath, true))
@@ -50,6 +51,7 @@
             {
                 this._pluginServices.Debug.WriteLine(ex.ToString());
             }
+#endif
         }
     }
 }


Backup and Restore Feature Added

Backup and Restore Feature Added

--- SQLiteFramework/SQLiteFramework/SQLiteFramework.cs
+++ SQLiteFramework/SQLiteFramework/SQLiteFramework.cs
@@ -3,6 +3,7 @@
 using System.Data;
 using System.Data.SQLite;
 using System.Diagnostics;
+using System.IO;
 using System.Linq;
 using System.Reflection;

@@ -14,6 +15,7 @@
         [PrimaryKey, AutoIncrement]
         public ulong ID { get; set; }

+        public static bool IsDisposed { get { return Adap.IsDisposed; } }
         protected class Adapter
         {
             private SQLiteConnection sql_con;
@@ -21,11 +23,19 @@
             private SQLiteDataAdapter DB;
             private DataSet DS = new DataSet();

+            public bool IsDisposed { get; set; } = true;
             private void SetConnection()
             {
-                //Data Source=DemoT.db;New=False;
-                sql_con = new SQLiteConnection("Data Source=DEMO.sqlite;Compress=True;Version=3;");
-            }
+                if (Database == null)
+                {
+                    throw new SQLiteException("No Database Selected. Please Call UseDatabase Method to select a database.");
+                }
+                sql_con = new SQLiteConnection("Data Source=" + Database + ";Compress=True;Version=3;");
+                this.IsDisposed = false;
+            }
+            private string _Database = null;
+            public string Database { get { return this._Database; } set { this._Database = value + ".sqlite"; } }
+
             public int ExecuteQuery(string txtQuery)
             {
                 SetConnection();
@@ -33,7 +43,6 @@
                 sql_cmd = sql_con.CreateCommand();
                 sql_cmd.CommandText = txtQuery;
                 int result = sql_cmd.ExecuteNonQuery();
-                sql_con.Close();
                 return result;
             }
             public int ExecuteMultipleQuery(List<string> QueryList, Dictionary<string, string> Params = null)
@@ -53,7 +62,6 @@
                     if (sql_cmd.ExecuteNonQuery() < 1)
                         return 0;
                 }
-                sql_con.Close();
                 return 1;
             }
             public DataSet ExecuteDataQuery(string query, Dictionary<string, string> Params = null)
@@ -70,8 +78,14 @@
                 DB = new SQLiteDataAdapter(sql_cmd);
                 DS.Reset();
                 DB.Fill(DS);
+                return DS;
+            }
+            public void Dispose()
+            {
+                sql_cmd.Dispose();
                 sql_con.Close();
-                return DS;
+                sql_con.Dispose();
+                this.IsDisposed = true;
             }
         }
         public class Conditions
@@ -249,117 +263,10 @@

         private static Adapter Adap = new Adapter();

-
-        private static void Create(object This)
-        {
-            string output = "CREATE TABLE IF NOT EXISTS ";
-            Type type = This.GetType();
-            string[] temp = type.ToString().Split('.');
-            output += temp[temp.Length - 1];
-
-            object[] attr = type.GetCustomAttributes(true);
-            foreach (object a in attr)
-            {
-                Console.WriteLine("Class Attributes: " + a);
-            }
-            output += @"(";
-            IEnumerable<PropertyInfo> Prop = GetPropertiesWithAttribute<Field>(type);
-            foreach (PropertyInfo p in Prop)
-            {
-                output += @"'" + p.Name + @"' ";
-                if (p.PropertyType == typeof(bool))
-                {
-                    output += @"BOOLEAN";
-                }
-                else if (p.PropertyType == typeof(sbyte) ||
-                    p.PropertyType == typeof(short) ||
-                    p.PropertyType == typeof(int) ||
-                    p.PropertyType == typeof(long) ||
-
-                    p.PropertyType == typeof(byte) ||
-                    p.PropertyType == typeof(ushort) ||
-                    p.PropertyType == typeof(uint) ||
-                    p.PropertyType == typeof(ulong))
-                {
-                    output += @"INTEGER";
-                }
-                else if (p.PropertyType == typeof(float) ||
-                    p.PropertyType == typeof(double) ||
-                    p.PropertyType == typeof(decimal))
-                {
-                    output += @"REAL";
-                }
-                else if (p.PropertyType == typeof(string))
-                {
-                    output += @"VARCHAR";
-                }
-                else if (p.PropertyType == typeof(DateTime))
-                {
-                    output += @"TEXT DEFAULT(datetime('now','localtime'))";
-                }
-                else
-                {
-                    throw new SQLiteException("Type Not Supported in the underlying Database System.");
-                }
-                //output+=Marshal.SizeOf(p.PropertyType);
-                foreach (Attribute a in p.GetCustomAttributes())
-                {
-                    Console.WriteLine("Property: " + p.Name + " PropertyAttributes: " + a);
-                    if (a.ToString().Equals(typeof(PrimaryKey).ToString()))
-                    {
-                        output += " PRIMARY KEY";
-                    }
-                    else if (a.ToString().Equals(typeof(Unique).ToString()))
-                    {
-                        output += " UNIQUE";
-                    }
-                    else if (a.ToString().Equals(typeof(NotNull).ToString()))
-                    {
-                        output += " NOT NULL";
-                    }
-                    else if (a.ToString().Equals(typeof(AutoIncrement).ToString()))
-                    {
-                        if (p.PropertyType == typeof(sbyte) ||
-                            p.PropertyType == typeof(short) ||
-                            p.PropertyType == typeof(int) ||
-                            p.PropertyType == typeof(long) ||
-
-                            p.PropertyType == typeof(byte) ||
-                            p.PropertyType == typeof(ushort) ||
-                            p.PropertyType == typeof(uint) ||
-                            p.PropertyType == typeof(ulong))
-                        {
-                            output += " AUTOINCREMENT";
-                        }
-                        else
-                        {
-                            throw new SQLiteException("AutoIncrement can only be applied to Integer fields");
-                        }
-                    }
-                    else if (a.ToString().Equals(typeof(Default).ToString()))
-                    {
-                        Default d = a as Default;
-                        string value = d.Value.ToString();
-                        if (p.PropertyType == typeof(bool))
-                        {
-                            if (((bool)d.Value) == true)
-                            {
-                                value = "1";
-                            }
-                            else
-                                value = "0";
-                        }
-                        output += " DEFAULT '" + value + "'";
-                    }
-                }
-                output += @", ";
-            }
-            output = output.Remove(output.Length - 2, 2);
-            output += @")";
-            Console.WriteLine(output);
-            Adapter Adap = new Adapter();
-            Adap.ExecuteQuery(output);
-            //Adap.ExecuteQuery();
+        #region Usual Operations
+        public static void UseDatabase(string database)
+        {
+            Adap.Database = database;
         }
         public static bool Insert(object This, bool CreateNew = false)
         {
@@ -457,7 +364,6 @@
             output += "(" + key + ") VALUES(" + value + ")";
             Console.WriteLine(output);

-            Adapter Adap = new Adapter();
             try
             {
                 if (Adap.ExecuteQuery(output) == 0) return false;
@@ -568,7 +474,132 @@
                 return true;
         }

+        #endregion
+
+        #region Backup and Restore Operation
+        public static void Backup(string file)
+        {
+            File.Copy(Adap.Database, file);
+        }
+        public static void Restore(string file)
+        {
+            Adap.Dispose();
+            File.Delete(Adap.Database);
+            File.Copy(file, Adap.Database);
+        }
+        #endregion
+
         #region Support Methods
+        private static void Create(object This)
+        {
+            string output = "CREATE TABLE IF NOT EXISTS ";
+            Type type = This.GetType();
+            string[] temp = type.ToString().Split('.');
+            output += temp[temp.Length - 1];
+
+            object[] attr = type.GetCustomAttributes(true);
+            foreach (object a in attr)
+            {
+                Console.WriteLine("Class Attributes: " + a);
+            }
+            output += @"(";
+            IEnumerable<PropertyInfo> Prop = GetPropertiesWithAttribute<Field>(type);
+            foreach (PropertyInfo p in Prop)
+            {
+                output += @"'" + p.Name + @"' ";
+                if (p.PropertyType == typeof(bool))
+                {
+                    output += @"BOOLEAN";
+                }
+                else if (p.PropertyType == typeof(sbyte) ||
+                    p.PropertyType == typeof(short) ||
+                    p.PropertyType == typeof(int) ||
+                    p.PropertyType == typeof(long) ||
+
+                    p.PropertyType == typeof(byte) ||
+                    p.PropertyType == typeof(ushort) ||
+                    p.PropertyType == typeof(uint) ||
+                    p.PropertyType == typeof(ulong))
+                {
+                    output += @"INTEGER";
+                }
+                else if (p.PropertyType == typeof(float) ||
+                    p.PropertyType == typeof(double) ||
+                    p.PropertyType == typeof(decimal))
+                {
+                    output += @"REAL";
+                }
+                else if (p.PropertyType == typeof(string))
+                {
+                    output += @"VARCHAR";
+                }
+                else if (p.PropertyType == typeof(DateTime))
+                {
+                    output += @"TEXT DEFAULT(datetime('now','localtime'))";
+                }
+                else
+                {
+                    throw new SQLiteException("Type Not Supported in the underlying Database System.");
+                }
+                //output+=Marshal.SizeOf(p.PropertyType);
+                foreach (Attribute a in p.GetCustomAttributes())
+                {
+                    Console.WriteLine("Property: " + p.Name + " PropertyAttributes: " + a);
+                    if (a.ToString().Equals(typeof(PrimaryKey).ToString()))
+                    {
+                        output += " PRIMARY KEY";
+                    }
+                    else if (a.ToString().Equals(typeof(Unique).ToString()))
+                    {
+                        output += " UNIQUE";
+                    }
+                    else if (a.ToString().Equals(typeof(NotNull).ToString()))
+                    {
+                        output += " NOT NULL";
+                    }
+                    else if (a.ToString().Equals(typeof(AutoIncrement).ToString()))
+                    {
+                        if (p.PropertyType == typeof(sbyte) ||
+                            p.PropertyType == typeof(short) ||
+                            p.PropertyType == typeof(int) ||
+                            p.PropertyType == typeof(long) ||
+
+                            p.PropertyType == typeof(byte) ||
+                            p.PropertyType == typeof(ushort) ||
+                            p.PropertyType == typeof(uint) ||
+                            p.PropertyType == typeof(ulong))
+                        {
+                            output += " AUTOINCREMENT";
+                        }
+                        else
+                        {
+                            throw new SQLiteException("AutoIncrement can only be applied to Integer fields");
+                        }
+                    }
+                    else if (a.ToString().Equals(typeof(Default).ToString()))
+                    {
+                        Default d = a as Default;
+                        string value = d.Value.ToString();
+                        if (p.PropertyType == typeof(bool))
+                        {
+                            if (((bool)d.Value) == true)
+                            {
+                                value = "1";
+                            }
+                            else
+                                value = "0";
+                        }
+                        output += " DEFAULT '" + value + "'";
+                    }
+                }
+                output += @", ";
+            }
+            output = output.Remove(output.Length - 2, 2);
+            output += @")";
+            Console.WriteLine(output);
+            Adap.ExecuteQuery(output);
+            //Adap.ExecuteQuery();
+        }
         private static string GenerateUpdateQuery<T>(object This)
         {
             string output = "UPDATE ";
@@ -744,17 +775,15 @@
             return tProp;*/
             return Prop;
         }
-
         #endregion
-        public static T newInstance<T>()
+        public static T NewInstance<T>()
         {
             T Instance = Activator.CreateInstance<T>();
-            //(Instance as SQLiteModel).PropertyChanged += (s, args) =>
-            //{
-            //    Console.WriteLine("Property Changed");
-            //    (Instance as SQLiteModel).Dirty = true;
-            //};
             return Instance;
+        }
+        public static void Dispose()
+        {
+            Adap.Dispose();
         }
     }
     #region Attributes For SQLite
@@ -798,5 +827,4 @@
         public DirtyBit() { }
     }
     #endregion
-
-}
+}


Lat error checks performed

Lat error checks performed

--- Source/HelixToolkit.Shared/Geometry/MeshBuilder.cs
+++ Source/HelixToolkit.Shared/Geometry/MeshBuilder.cs
@@ -857,7 +857,7 @@
             bool baseCap, bool topCap, int thetaDiv)
         {
             var pc = new PointCollection();
-            var tc = new List<DoubleOrSingle>();
+            var tc = new List<double>();
             if (baseCap)
             {
                 pc.Add(new Point(0, 0));
@@ -1769,7 +1769,7 @@
                     new Point(height, (DoubleOrSingle)innerDiameter / 2)
                 };

-            var tc = new List<DoubleOrSingle> { 1, 0, 1, 0 };
+            var tc = new List<double> { 1, 0, 1, 0 };

             if (innerDiameter > 0)
             {
@@ -2822,10 +2822,10 @@
         {
             // Helper Variables
             var right = SharedFunctions.CrossProduct(up, forward);
-            var heightSphere = (DoubleOrSingle)Math.Sqrt(6) / 3 * sideLength;
-            var radiusSphere = (DoubleOrSingle)Math.Sqrt(6) / 4 * sideLength;
-            var heightFace = (DoubleOrSingle)Math.Sqrt(3) / 2 * sideLength;
-            var radiusFace = (DoubleOrSingle)Math.Sqrt(3) / 3 * sideLength;
+            var heightSphere = (DoubleOrSingle)Math.Sqrt(6) / 3 * (DoubleOrSingle)sideLength;
+            var radiusSphere = (DoubleOrSingle)Math.Sqrt(6) / 4 * (DoubleOrSingle)sideLength;
+            var heightFace = (DoubleOrSingle)Math.Sqrt(3) / 2 * (DoubleOrSingle)sideLength;
+            var radiusFace = (DoubleOrSingle)Math.Sqrt(3) / 3 * (DoubleOrSingle)sideLength;
             var smallHeightSphere = heightSphere - radiusSphere;
             var smallHeightFace = heightFace - radiusFace;
             var halfLength = (DoubleOrSingle)sideLength * 0.5f;
@@ -2882,7 +2882,7 @@
                     crossSectionPoints = GetCircle(phiDiv, true);
                 }
                 // Transform Crosssection to real Size
-                crossSectionPoints = crossSectionPoints.Select(p => new Point((DoubleOrSingle)p.X * tubeDiameter * .5f, (DoubleOrSingle)p.Y * tubeDiameter * .5f)).ToList();
+                crossSectionPoints = crossSectionPoints.Select(p => new Point((DoubleOrSingle)p.X * (DoubleOrSingle)tubeDiameter * .5f, (DoubleOrSingle)p.Y * (DoubleOrSingle)tubeDiameter * .5f)).ToList();
                 // Transform the Cross-Section Points to 3D Space
                 var crossSection3DPoints = crossSectionPoints.Select(p => new Point3D(p.X, 0, p.Y)).ToList();


Unity.Common - Add events when the values of the RangeSlider changed and the possibility to set the values from outside

--- Source/Slash.Unity.Common/Source/UI/RangeSlider.cs
+++ Source/Slash.Unity.Common/Source/UI/RangeSlider.cs
@@ -13,11 +13,59 @@

         public GameObject MinHandle;

+        /// <summary>
+        ///     Initial position for maximum handle (0-1).
+        /// </summary>
+        private float initialValueMax = 1;
+
+        /// <summary>
+        ///     Initial position for minimum handle (0-1).
+        /// </summary>
+        private float initialValueMin;
+
         private RangeSliderHandle rangeHandleMax;

         private RangeSliderHandle rangeHandleMin;

         private RectTransform rectTransform;
+
+        /// <summary>
+        ///     Maximum value (as ratio from 0 to 1).
+        /// </summary>
+        public float MaxValue
+        {
+            get { return this.rangeHandleMax != null ? this.PositionToRatio(this.rangeHandleMax.Position) : 1; }
+            set
+            {
+                if (this.rangeHandleMax != null)
+                {
+                    this.rangeHandleMax.Position = this.RatioToPosition(value);
+                }
+                else
+                {
+                    this.initialValueMax = value;
+                }
+            }
+        }
+
+        /// <summary>
+        ///     Minimum value (as ratio from 0 to 1).
+        /// </summary>
+        public float MinValue
+        {
+            get { return this.rangeHandleMin != null ? this.PositionToRatio(this.rangeHandleMin.Position) : 0; }
+            set
+            {
+                if (this.rangeHandleMin != null)
+                {
+                    this.rangeHandleMin.Position = this.RatioToPosition(value);
+                }
+                else
+                {
+                    this.initialValueMin = value;
+                }
+            }
+        }

         private RectTransform RectTransform
         {
@@ -36,6 +84,15 @@
             }
         }

+        private float Width
+        {
+            get { return this.RectTransform.rect.width; }
+        }
+
+        public event Action MaxValueChanged;
+
+        public event Action MinValueChanged;
+
         protected void OnDisable()
         {
             this.UnregisterHandle(ref this.rangeHandleMin, this.OnMinValueChanged);
@@ -44,16 +101,15 @@

         protected void OnEnable()
         {
-            var size = this.RectTransform.rect.size.x;
-
             // Setup handles.
             this.rangeHandleMin = this.RegisterHandle(this.MinHandle, this.OnMinValueChanged);
             this.rangeHandleMax = this.RegisterHandle(this.MaxHandle, this.OnMaxValueChanged);

-            this.rangeHandleMin.MinPosition = -size * 0.5f;
-            this.rangeHandleMin.Position = -size * 0.5f;
-            this.rangeHandleMax.MaxPosition = size * 0.5f;
-            this.rangeHandleMax.Position = size * 0.5f;
+            this.rangeHandleMin.MinPosition = this.RatioToPosition(0);
+            this.rangeHandleMax.MaxPosition = this.RatioToPosition(1);
+
+            this.MinValue = this.initialValueMin;
+            this.MaxValue = this.initialValueMax;

             // Setup active area.
             if (this.ActiveAreaIndicator != null)
@@ -65,16 +121,38 @@
             this.UpdateHandleRanges();
         }

-        private void OnMaxValueChanged()
+        protected virtual void OnMaxValueChanged()
         {
             this.UpdateActiveArea();
             this.UpdateHandleRanges();
-        }
-
-        private void OnMinValueChanged()
+
+            var handler = this.MaxValueChanged;
+            if (handler != null)
+            {
+                handler();
+            }
+        }
+
+        protected virtual void OnMinValueChanged()
         {
             this.UpdateActiveArea();
             this.UpdateHandleRanges();
+
+            var handler = this.MinValueChanged;
+            if (handler != null)
+            {
+                handler();
+            }
+        }
+
+        private float PositionToRatio(float position)
+        {
+            return 0.5f + position / this.Width;
+        }
+
+        private float RatioToPosition(float ratio)
+        {
+            return (ratio - 0.5f) * this.Width;
         }

         private RangeSliderHandle RegisterHandle(GameObject handleGameObject, Action valueChangedCallback)
@@ -115,14 +193,12 @@
                 return;
             }

-            var size = this.RectTransform.rect.size.x;
-
             var offsetMin = this.ActiveAreaIndicator.offsetMin;
-            offsetMin.x = this.rangeHandleMin.Position + size * 0.5f;
+            offsetMin.x = this.rangeHandleMin.Position + this.Width * 0.5f;
             this.ActiveAreaIndicator.offsetMin = offsetMin;

             var offsetMax = this.ActiveAreaIndicator.offsetMax;
-            offsetMax.x = this.rangeHandleMax.Position - size * 0.5f;
+            offsetMax.x = this.rangeHandleMax.Position - this.Width * 0.5f;
             this.ActiveAreaIndicator.offsetMax = offsetMax;
         }


Fixed 30207

Fixed 30207

--- SourceFiles/Controllers/VelocityLimitController.cs
+++ SourceFiles/Controllers/VelocityLimitController.cs
@@ -26,8 +26,8 @@
         public VelocityLimitController()
             : base(ControllerType.VelocityLimitController)
         {
-            _maxLinearVelocity = Settings.MaxTranslation;
-            _maxAngularVelocity = Settings.MaxRotation;
+            MaxLinearVelocity = Settings.MaxTranslation;
+            MaxAngularVelocity = Settings.MaxRotation;
         }

         /// <summary>
@@ -46,8 +46,8 @@
             if (maxAngularVelocity == 0 || maxAngularVelocity == float.MaxValue)
                 LimitAngularVelocity = false;

-            _maxLinearVelocity = maxLinearVelocity;
-            _maxAngularVelocity = maxAngularVelocity;
+            MaxLinearVelocity = maxLinearVelocity;
+            MaxAngularVelocity = maxAngularVelocity;
         }

         /// <summary>
@@ -93,7 +93,7 @@
                     float translationY = dt * body.LinearVelocityInternal.Y;
                     float result = translationX * translationX + translationY * translationY;

-                    if (result > _maxLinearSqared)
+                    if (result > dt * _maxLinearSqared)
                     {
                         float sq = (float)Math.Sqrt(result);

@@ -120,5 +120,10 @@
         {
             _bodies.Add(body);
         }
+
+        public void RemoveBody(Body body)
+        {
+            _bodies.Remove(body);
+        }
     }
 }


W.Threading.ThreadMethod now cancels when disposed before competion

Fixed W.Threading.ThreadMethod so it would cancel when Disposed before completion.

--- Src/Tungsten.Standard1_0/Threading/ThreadMethod.cs
+++ Src/Tungsten.Standard1_0/Threading/ThreadMethod.cs
@@ -4,6 +4,7 @@
 using System.Threading;
 using System.Threading.Tasks;
 using W.Threading.ThreadExtensions;
+using W.AsExtensions;

 namespace W.Threading
 {
@@ -12,340 +13,6 @@
     /// </summary>
     /// <param name="args"></param>
     public delegate void AnyMethodDelegate(params object[] args);
-
-    ///// <summary>
-    ///// Wraps an ThreadMethodDelegate with functionality to prevent re-entrancy and to know when the method is running and completed
-    ///// </summary>
-    //public partial class ThreadMethod : IDisposable
-    //{
-    //    private object _lock = new object();
-    //    private ManualResetEventSlim _mreComplete = new ManualResetEventSlim(false);
-    //    private ManualResetEventSlim _mreIsRunning = new ManualResetEventSlim(false);
-    //    private ThreadMethodDelegate _delegate { get; set; }
-
-    //    /// <summary>
-    //    /// The exception, if one was caught
-    //    /// </summary>
-    //    public Exception Exception { get; private set; }
-    //    /// <summary>
-    //    /// True if the method is currently running, otherwise False
-    //    /// </summary>
-    //    public bool IsRunning { get { lock (_lock) return _mreIsRunning.IsSet; } }
-    //    /// <summary>
-    //    /// True if the method has completed, otherwise False.  The value is False initially and reset to False when Run is called.
-    //    /// </summary>
-    //    public bool IsComplete { get { return _mreComplete.IsSet; } }
-
-    //    /// <summary>
-    //    /// Block the calling thread until the method completes
-    //    /// </summary>
-    //    public void Wait()
-    //    {
-    //        if (IsRunning)
-    //            _mreComplete.Wait();
-    //    }
-    //    /// <summary>
-    //    /// Block the calling thread until the method completes
-    //    /// </summary>
-    //    /// <param name="msTimeout">The number of milliseconds to block before returning a False value.</param>
-    //    /// <returns>True if the method completed within the specified timeout period, otherwise False</returns>
-    //    public bool Wait(int msTimeout)
-    //    {
-    //        if (IsRunning)
-    //            return _mreComplete.Wait(msTimeout);
-    //        return true;
-    //    }
-    //    /// <summary>
-    //    /// Block the calling thread until the method completes
-    //    /// </summary>
-    //    /// <param name="token">A CancellationToken which can be used to stop waiting for the method to complete</param>
-    //    /// <returns>True if the method completed before the CancellatioToken was cancelled, otherwise False</returns>
-    //    public void Wait(CancellationToken token)
-    //    {
-    //        if (IsRunning)
-    //            _mreComplete.Wait(token);
-    //    }
-
-    //    /// <summary>
-    //    /// Synchronously calls the delegate with the specified arguments.  These arguments must be accurate in number and in type to the arguments expected by the delegate.
-    //    /// </summary>
-    //    /// <param name="args">An array of arguments to be passed into the delegate</param>
-    //    public void Run(params object[] args)
-    //    {
-    //        lock (_lock)
-    //        {
-    //            if (_mreIsRunning.IsSet)
-    //                return;
-    //            _mreIsRunning.Set();
-    //            _mreComplete.Reset();
-    //        }
-    //        Exception ex = null;
-    //        try
-    //        {
-    //            if (args?.Length > 0)
-    //                _delegate?.Invoke(args);
-    //            else
-    //                _delegate?.Invoke();
-    //        }
-    //        catch (Exception e)
-    //        {
-    //            ex = e;
-    //        }
-    //        try
-    //        {
-    //            if (ex != null)
-    //            {
-    //                Exception = ex;
-    //                //throw new Exception("The action raised an unhandled exception", ex);
-    //            }
-    //        }
-    //        finally
-    //        {
-    //            lock (_lock)
-    //                _mreIsRunning.Reset();
-    //            _mreComplete.Set();
-    //        }
-    //    }
-    //    /// <summary>
-    //    /// Asynchronously calls the delegate with the specified arguments.  These arguments must be accurate in number and in type to the arguments expected by the delegate.
-    //    /// </summary>
-    //    /// <param name="args">An array of arguments to be passed into the delegate</param>
-    //    /// <returns>The Task associated with this asynchronous operation</returns>
-    //    public async Task RunAsync(params object[] args)
-    //    {
-    //        await RunAsync(CancellationToken.None, args);
-    //    }
-    //    /// <summary>
-    //    /// Calls the delegate with the specified arguments.  These arguments must be accurate in number and in type to the arguments expected by the delegate.
-    //    /// </summary>
-    //    /// <param name="token">A CancellationToken which can be used to interrupt and stop execution of the delegate</param>
-    //    /// <param name="args">An array of arguments to be passed into the delegate</param>
-    //    /// <returns>The Task associated with this asynchronous operation</returns>
-    //    public async Task RunAsync(CancellationToken token, params object[] args)
-    //    {
-    //        await RunAsync(token, TaskCreationOptions.None, args);
-    //    }
-    //    /// <summary>
-    //    /// Calls the delegate with the specified arguments.  These arguments must be accurate in number and in type to the arguments expected by the delegate.
-    //    /// </summary>
-    //    /// <param name="token">A CancellationToken which can be used to interrupt and stop execution of the delegate</param>
-    //    /// <param name="options">Task creation options to use when creating the Task</param>
-    //    /// <param name="args">An array of arguments to be passed into the delegate</param>
-    //    /// <returns>The Task associated with this asynchronous operation</returns>
-    //    public async Task RunAsync(CancellationToken token, TaskCreationOptions options, params object[] args)
-    //    {
-    //        lock (_lock)
-    //        {
-    //            if (_mreIsRunning.IsSet)
-    //                return;
-    //            _mreIsRunning.Set();
-    //            _mreComplete.Reset();
-    //        };
-    //        Exception ex = null;
-    //        await Task.Factory.StartNew(() =>
-    //        {
-    //            try
-    //            {
-    //                if (args?.Length > 0)
-    //                {
-    //                    //_delegate.BeginInvoke(args, ar => _delegate.EndInvoke(ar), null);
-    //                    _delegate?.Invoke(args);
-    //                }
-    //                else
-    //                {
-    //                    //_delegate.BeginInvoke(null, ar => _delegate.EndInvoke(ar), null);
-    //                    _delegate?.Invoke();
-    //                }
-    //            }
-    //            catch (Exception e)
-    //            {
-    //                ex = e;
-    //                Exception = ex;
-    //            }
-    //        }, token, options, TaskScheduler.Current).ContinueWith(task =>
-    //        {
-    //            Exception = Exception ?? task.Exception;
-    //            _mreComplete.Set();
-    //            _mreIsRunning.Reset();
-    //        });
-    //        //if (ex != null) //should this be in the ContinueWith?
-    //        //    throw new Exception("The action raised an unhandled exception", ex);
-    //    }
-
-    //    public void Dispose()
-    //    {
-    //        _mreComplete.Dispose();
-    //        _mreIsRunning.Dispose();
-    //        Exception = null;
-    //        _delegate = null;
-    //        _lock = null;
-    //    }
-    //    /// <summary>
-    //    /// Constructs a new ThreadMethod
-    //    /// </summary>
-    //    /// <param name="action">An action to be called instead of an ThreadMethodDelegate</param>
-    //    public ThreadMethod(Action action) : this((args => action.Invoke())) { }
-    //    /// <summary>
-    //    /// Constructs a new ThreadMethod
-    //    /// </summary>
-    //    /// <param name="delegate">The ThreadMethodDelgate to be called</param>
-    //    public ThreadMethod(ThreadMethodDelegate @delegate)
-    //    {
-    //        if (@delegate == null)
-    //            throw new ArgumentNullException(nameof(@delegate));
-    //        _delegate = @delegate;
-    //    }
-    //    ///// <summary>
-    //    ///// Destructs the ThreadMethod
-    //    ///// </summary>
-    //    //~ThreadMethod()
-    //    //{
-    //    //}
-    //}
-    //public partial class ThreadMethod //static members
-    //{
-    //    /// <summary>
-    //    /// Creates a new ThreadMethod, immediately calls Run and returns the ThreadMethod instance
-    //    /// </summary>
-    //    /// <param name="action">The Action to be called</param>
-    //    /// <returns>The ThreadMethod instanced created</returns>
-    //    public static ThreadMethod Run(Action action)
-    //    {
-    //        var result = new ThreadMethod(action);
-    //        result.Run();
-    //        return result;
-    //    }
-    //    /// <summary>
-    //    /// Creates a new ThreadMethod, immediately calls Run and returns the ThreadMethod instance
-    //    /// </summary>
-    //    /// <param name="delegate">The ActionMethodDelegate to be called</param>
-    //    /// <returns>The ThreadMethod instanced created</returns>
-    //    public static ThreadMethod Run(ThreadMethodDelegate @delegate)
-    //    {
-    //        var result = new ThreadMethod(@delegate);
-    //        result.Run();
-    //        return result;
-    //    }
-    //    /// <summary>
-    //    /// Creates a new ThreadMethod, immediately calls Run and returns the ThreadMethod instance
-    //    /// </summary>
-    //    /// <param name="delegate">The ActionMethodDelegate to be called</param>
-    //    /// <param name="args">Arguments to be passed into the ThreadMethodDelegate when called</param>
-    //    /// <returns>The ThreadMethod instanced created</returns>
-    //    public static ThreadMethod Run(ThreadMethodDelegate @delegate, params object[] args)
-    //    {
-    //        var result = new ThreadMethod(@delegate);
-    //        result.Run(args);
-    //        return result;
-    //    }
-    //    /// <summary>
-    //    /// Creates a new ThreadMethod, immediately calls RunAsync and returns the ThreadMethod instance
-    //    /// </summary>
-    //    /// <param name="action">The Action to be called</param>
-    //    /// <returns>The ThreadMethod instanced created</returns>
-    //    public static async Task<ThreadMethod> RunAsync(Action action)
-    //    {
-    //        var result = new ThreadMethod(action);
-    //        await result.RunAsync();
-    //        return result;
-    //    }
-    //    /// <summary>
-    //    /// Creates a new ThreadMethod, immediately calls RunAsync and returns the ThreadMethod instance
-    //    /// </summary>
-    //    /// <param name="delegate">The ActionMethodDelegate to be called</param>
-    //    /// <returns>The ThreadMethod instanced created</returns>
-    //    public static async Task<ThreadMethod> RunAsync(ThreadMethodDelegate @delegate)
-    //    {
-    //        var result = new ThreadMethod(@delegate);
-    //        await result.RunAsync();
-    //        return result;
-    //    }
-    //    /// <summary>
-    //    /// Creates a new ThreadMethod, immediately calls RunAsync and returns the ThreadMethod instance
-    //    /// </summary>
-    //    /// <param name="delegate">The ActionMethodDelegate to be called</param>
-    //    /// <param name="args">Arguments to be passed into the ThreadMethodDelegate when called</param>
-    //    /// <returns>The ThreadMethod instanced created</returns>
-    //    public static async Task<ThreadMethod> RunAsync(ThreadMethodDelegate @delegate, params object[] args)
-    //    {
-    //        var result = new ThreadMethod(@delegate);
-    //        await result.RunAsync(args);
-    //        return result;
-    //    }
-    //}
-
-    //public class ThreadMethodSlim //: IDisposable
-    //{
-    //    //private CancellationTokenSource _cts;
-    //    private ManualResetEventSlim _mreRun;
-    //    private ManualResetEventSlim _mreComplete;
-    //    private Task _runTask;
-    //    private Task _cleanupTask;
-
-    //    public bool IsComplete => _mreComplete.IsSet;
-
-    //    public void Run()
-    //    {
-    //        _mreRun.Set();
-    //    }
-    //    public async Task RunAsync()
-    //    {
-    //        _mreRun.Set();
-    //        await _runTask;
-    //    }
-    //    public void Wait()
-    //    {
-    //        _mreComplete.Wait();
-    //    }
-    //    public bool Wait(int msTimeout)
-    //    {
-    //        return _mreComplete.Wait(msTimeout);
-    //    }
-    //    public bool Wait(CancellationToken token)
-    //    {
-    //        _mreComplete.Wait(token);
-    //        return IsComplete;
-    //    }
-    //    //public void Dispose()
-    //    //{
-    //    //    try
-    //    //    {
-    //    //        //if (!_cts?.IsCancellationRequested ?? false)
-    //    //        //{
-    //    //            _cts?.Cancel();
-    //    //            _mreTerminated.Wait();
-    //    //        //}
-    //    //    }
-    //    //    catch (Exception e)
-    //    //    {
-    //    //        System.Diagnostics.Debugger.Break();
-    //    //        System.Diagnostics.Debug.WriteLine(e.ToString());
-    //    //    }
-    //    //}
-    //    internal ThreadMethodSlim(Task runTask, Task cleanupTask, ManualResetEventSlim mreRun, ManualResetEventSlim mreComplete)//, CancellationTokenSource cts)
-    //    {
-    //        _runTask = runTask;
-    //        _cleanupTask = cleanupTask;
-    //        _mreRun = mreRun;
-    //        _mreComplete = mreComplete;
-    //        //_cts = cts;
-    //    }
-    //    ~ThreadMethodSlim()
-    //    {
-    //        //this has to be run synchronously to work
-    //        _cleanupTask.RunSynchronously();
-    //    }
-
-    //    /// <summary>
-    //    ///
-    //    /// </summary>
-    //    /// <param name="action"></param>
-    //    /// <returns></returns>
-    //    public static ThreadMethodSlim Create(Action action)
-    //    {
-    //        return action.AsThreadMethodSlim();
-    //    }
-    //}

     /// <summary>
     /// Adds multi-threading and additional functionality to an Action or ThreadMethodDelegate
@@ -355,8 +22,8 @@
         private object _lockDispose = new object();
         private AnyMethodDelegate _delegate = null;
         private CancellationTokenSource _ctsFinalizer = new CancellationTokenSource();
-        private ManualResetEventSlim _mreRun = new ManualResetEventSlim();
-        private ManualResetEventSlim _mreComplete = new ManualResetEventSlim();
+        private ManualResetEventSlim _mreIsRunning = new ManualResetEventSlim();
+        private ManualResetEventSlim _mreIsComplete = new ManualResetEventSlim();
         private Task _runTask;
         private object[] _args;

@@ -372,32 +39,35 @@
         /// <summary>
         /// True if the method is currently running and not complete, otherwise False
         /// </summary>
-        public bool IsRunning => _mreRun.IsSet && !IsComplete;
+        public bool IsRunning => _mreIsRunning.IsSet && !IsComplete;
         /// <summary>
         /// True if the method has completed, otherwise False
         /// </summary>
-        public bool IsComplete => _mreComplete.IsSet;
+        public bool IsComplete => _mreIsComplete.IsSet;

         private void WaitToRun()
         {
-            _mreRun.Wait(_ctsFinalizer.Token);
+            _mreIsRunning.Wait(_ctsFinalizer.Token);
         }
         private void RunTheMethod(Task task)
         {
-            var ok = !task.IsFaulted && !task.IsCanceled;
-            ok = (ok && !_ctsFinalizer.Token.IsCancellationRequested);
             try
             {
-                if (ok)
+                //_mreIsRunning.Wait(_ctsFinalizer.Token);
+                if (_ctsFinalizer.Token.IsCancellationRequested)
+                    return;
+                //var ok = !_ctsFinalizer.IsCancellationRequested;// !task.IsFaulted && !task.IsCanceled;
+                //ok = (ok && !_ctsFinalizer.Token.IsCancellationRequested);
+                //if (ok)
                 {
                     _delegate.Invoke(_args);
                 }
             }
 #if NET45
-                catch (System.Threading.ThreadAbortException)
-                {
-                    System.Threading.Thread.ResetAbort();
-                }
+            catch (System.Threading.ThreadAbortException)
+            {
+                System.Threading.Thread.ResetAbort();
+            }
 #endif
             catch (Exception e)
             {
@@ -406,19 +76,24 @@
             }
             finally
             {
-                _mreComplete.Set();//allow waiters to continue
+                _mreIsComplete.Set();//allow waiters to continue
             }
         }

         /// <summary>
         /// Initializes variables and creates the task associated with this ThreadMethod
         /// </summary>
-        protected void Initialize()
-        {
-            _mreRun.Reset();
-            _mreComplete.Reset();
-            _runTask = Task.Factory.StartNew(WaitToRun, TaskCreationOptions.LongRunning)
-                           .ContinueWith(RunTheMethod, TaskContinuationOptions.LongRunning);
+        protected void Run()
+        {
+            _mreIsRunning.Reset();
+            _mreIsComplete.Reset();
+
+            _runTask = Task.Run(() => Task.Factory.StartNew(WaitToRun, TaskCreationOptions.LongRunning)
+                           .ContinueWith(RunTheMethod, TaskContinuationOptions.LongRunning)
+            , _ctsFinalizer.Token).ContinueWith(task =>
+            {
+                _mreIsRunning.Reset();
+            });
         }

         /// <summary>
@@ -430,11 +105,11 @@
             //Start(args).Wait();
             if (IsRunning)
                 throw new InvalidOperationException("The ThreadMethod is already running");
-            if (!IsStarted || IsComplete)
-                Initialize();

             _args = args;
-            _mreRun.Set();
+            Run();
+
+            _mreIsRunning.Set();
             _runTask.Wait();
         }
         /// <summary>
@@ -446,11 +121,11 @@
         {
             if (IsRunning)
                 throw new InvalidOperationException("The ThreadMethod is already running");
-            if (!IsStarted || IsComplete)
-                Initialize();

             _args = args;
-            _mreRun.Set();
+            Run();
+
+            _mreIsRunning.Set();
             _runTask.ConfigureAwait(false);
         }
         /// <summary>
@@ -462,11 +137,11 @@
         {
             if (IsRunning)
                 throw new InvalidOperationException("The ThreadMethod is already running");
-            if (!IsStarted || IsComplete)
-                Initialize();

             _args = args;
-            _mreRun.Set();
+            Run();
+
+            _mreIsRunning.Set();
             await _runTask.ConfigureAwait(false);
         }

@@ -475,8 +150,7 @@
         /// </summary>
         public void Wait()
         {
-            if (IsStarted)
-                _mreComplete.Wait();
+            _mreIsComplete.Wait();
         }
         /// <summary>
         /// Waits for the thread method to complete
@@ -485,7 +159,7 @@
         /// <returns>True if the thread method completes within the timeout period, otherwise False</returns>
         public bool Wait(int msTimeout)
         {
-            return _mreComplete.Wait(msTimeout);
+            return _mreIsComplete.Wait(msTimeout);
         }
         /// <summary>
         /// Waits for the thread method to complete
@@ -495,7 +169,7 @@
         public bool Wait(CancellationToken token)
         {
             var sw = System.Diagnostics.Stopwatch.StartNew();
-            _mreComplete.Wait(token);
+            _mreIsComplete.Wait(token);
 #if NETSTANDARD1_0 || WINDOWS_UWP || WINDOWS_PORTABLE
             System.Diagnostics.Debug.WriteLine("ThreadMethod.Wait: Elapsed = {0}ms", sw.ElapsedMilliseconds);
 #else
@@ -513,17 +187,17 @@
             {
                 if (_runTask == null)
                     return;
-                if (!_mreRun.IsSet) //still waiting?  Then cancel.
-                    _ctsFinalizer.Cancel();
-                _mreRun.Dispose();
+                _ctsFinalizer.Cancel();
+                _mreIsComplete.Set();
+                //_mreIsComplete.Wait(); //wait for it to complete
+                //#if NET45
+                //_runTask.Wait(1000);
+                //_runTask.Dispose();
+                //#endif
                 _ctsFinalizer.Dispose();
-                if (!_mreComplete.IsSet)
-                    _mreComplete.Set(); //unlock any waiters
-                _mreComplete.Dispose();
-#if NET45
-                _runTask.Wait();
-                _runTask.Dispose();
-#endif
+                //_mreIsComplete.Set(); //unlock any waiters
+                _mreIsComplete.Dispose();
+                _mreIsRunning.Dispose();
                 _runTask = null;
                 System.Diagnostics.Debug.WriteLine("ThreadMethod Destroyed");
             }
@@ -537,13 +211,13 @@
             _delegate = @delegate;
             //Initialize();
         }
-        /// <summary>
-        /// Destructs the ThreadMethod and releases resources
-        /// </summary>
-        ~ThreadMethod()
-        {
-            Dispose();
-        }
+        ///// <summary>
+        ///// Destructs the ThreadMethod and releases resources
+        ///// </summary>
+        //~ThreadMethod()
+        //{
+        //    Dispose();
+        //}
     }
     public partial class ThreadMethod //static members
     {


Basic implementation

Basic implementation

--- osu.Game/Overlays/Chat/DrawableChannel.cs
+++ osu.Game/Overlays/Chat/DrawableChannel.cs
@@ -12,6 +12,8 @@
 using osu.Game.Graphics.Containers;
 using osu.Game.Graphics.Cursor;
 using osu.Game.Online.Chat;
+using osu.Framework.Graphics.Shapes;
+using osu.Framework.Extensions.IEnumerableExtensions;

 namespace osu.Game.Overlays.Chat
 {
@@ -74,17 +76,40 @@

         protected virtual ChatLine CreateChatLine(Message m) => new ChatLine(m);

+        protected virtual Drawable CreateDaySeparator(DateTimeOffset time) => new Container
+        {
+            Margin = new MarginPadding { Vertical = 5 },
+            RelativeSizeAxes = Axes.X,
+            Height = 2,
+            Child = new Box
+            {
+                RelativeSizeAxes = Axes.Both,
+                Colour = Color4.Black,
+            }
+        };
+
         private void newMessagesArrived(IEnumerable<Message> newMessages)
         {
             // Add up to last Channel.MAX_HISTORY messages
             var displayMessages = newMessages.Skip(Math.Max(0, newMessages.Count() - Channel.MaxHistory));

-            ChatLineFlow.AddRange(displayMessages.Select(CreateChatLine));
+            var existingChatLines = getChatLines();

-            if (scroll.IsScrolledToEnd(10) || !ChatLineFlow.Children.Any() || newMessages.Any(m => m is LocalMessage))
+            Message lastMessage = existingChatLines.Any() ? existingChatLines.First().Message : null;
+
+            displayMessages.ForEach(m =>
+            {
+                if (lastMessage == null || lastMessage.Timestamp.ToLocalTime().Date != m.Timestamp.ToLocalTime().Date)
+                    ChatLineFlow.Add(CreateDaySeparator(m.Timestamp));
+
+                ChatLineFlow.Add(CreateChatLine(m));
+                lastMessage = m;
+            });
+
+            if (scroll.IsScrolledToEnd(10) || !existingChatLines.Any() || newMessages.Any(m => m is LocalMessage))
                 scrollToEnd();

-            var staleMessages = ChatLineFlow.Children.Where(c => c.LifetimeEnd == double.MaxValue).ToArray();
+            var staleMessages = existingChatLines.Where(c => c.LifetimeEnd == double.MaxValue).ToArray();
             int count = staleMessages.Length - Channel.MaxHistory;

             for (int i = 0; i < count; i++)
@@ -98,7 +123,7 @@

         private void pendingMessageResolved(Message existing, Message updated)
         {
-            var found = ChatLineFlow.Children.LastOrDefault(c => c.Message == existing);
+            var found = getChatLines().LastOrDefault(c => c.Message == existing);

             if (found != null)
             {
@@ -112,19 +137,25 @@

         private void messageRemoved(Message removed)
         {
-            ChatLineFlow.Children.FirstOrDefault(c => c.Message == removed)?.FadeColour(Color4.Red, 400).FadeOut(600).Expire();
+            getChatLines().FirstOrDefault(c => c.Message == removed)?.FadeColour(Color4.Red, 400).FadeOut(600).Expire();
         }
+
+        private IEnumerable<ChatLine> getChatLines() => ChatLineFlow.Children.OfType<ChatLine>();

         private void scrollToEnd() => ScheduleAfterChildren(() => scroll.ScrollToEnd());

-        protected class ChatLineContainer : FillFlowContainer<ChatLine>
+        protected class ChatLineContainer : FillFlowContainer
         {
             protected override int Compare(Drawable x, Drawable y)
             {
-                var xC = (ChatLine)x;
-                var yC = (ChatLine)y;
+                if (x is ChatLine && y is ChatLine)
+                {
+                    var xC = (ChatLine)x;
+                    var yC = (ChatLine)y;

-                return xC.Message.CompareTo(yC.Message);
+                    return xC.Message.CompareTo(yC.Message);
+                }
+                return base.Compare(x, y);
             }
         }
     }


Groups are now ACTUALLY added to the groups list.

--- TDSMPermissions/TDSMPermissions/TDSMPermissions.cs
+++ TDSMPermissions/TDSMPermissions/TDSMPermissions.cs
@@ -326,7 +326,19 @@
                 while (sc.NextToken() != Token.TextContent)
                 {
 					if (sc.Token == Token.Outdent)
+					{
+						if (!inUsers)
+						{
+							groups.Add(currentGroup);
+							ProgramLog.Debug.Log("Group added: " + currentGroup.Name);
+						}
+						else
+						{
+							users.Add(currentUserName, currentUser);
+							ProgramLog.Debug.Log("Number of users: " + users.Count);
+						}
 						return;
+					}
                 }
                 bool toggle;
                 string tokenText;
@@ -393,15 +405,6 @@
                         currentUser.notHasPerm.Add(tokenText);
                     }
                 }
-            }
-            if (!inUsers)
-            {
-                groups.Add(currentGroup);
-				ProgramLog.Debug.Log("Group added: " + currentGroup.Name);
-            }
-            else
-            {
-                users.Add(currentUserName, currentUser);
             }
         }