Linq: Handle methods that return true or false when provided with null.  Significant code simplification. (NH-2583 again)

SVN: 488784591515bd4cdaa016be4ec9b172dc4e7caf@5732

--- src/NHibernate/Linq/Visitors/WhereJoinDetector.cs
+++ src/NHibernate/Linq/Visitors/WhereJoinDetector.cs
@@ -1,3 +1,4 @@
+// FIXME - Are there other things that can convert N into T?  What about the ?: operator?
 using System;
 using System.Collections.Generic;
 using System.Linq.Expressions;
@@ -28,6 +29,8 @@
         private static readonly int[,] AND = new int[8, 8];
         private static readonly int[,] OR = new int[8, 8];
         private static readonly int[] NOT = new int[8];
+        private static readonly int[] ISNULL = new int[8];
+        private static readonly int[] ISNOTNULL = new int[8];

         /// <summary>
         /// Setup of <see cref="AND"/>, <see cref="OR"/>, <see cref="NOT"/>.
@@ -38,6 +41,12 @@
             NOT[T] = F;
             NOT[N] = N;
             NOT[F] = T;
+            ISNULL[T] = F;
+            ISNULL[N] = T;
+            ISNULL[F] = F;
+            ISNOTNULL[T] = T;
+            ISNOTNULL[N] = F;
+            ISNOTNULL[F] = T;

             foreach (var p in new[] { T, N, F })
             {
@@ -66,15 +75,21 @@
             foreach (var p in allValues)
             {
                 int[] splitP = split[p];
-                // We only need to compute NOT for compound values.
+                // We only need to compute unary operations for compound values.
                 if (splitP.Length > 1)
                 {
                     int notResult = 0;
+                    int isNullResult = 0;
+                    int isNotNullResult = 0;
                     foreach (var p0 in splitP)
                     {
                         notResult |= NOT[p0];
+                        isNullResult |= ISNULL[p0];
+                        isNotNullResult |= ISNOTNULL[p0];
                     }
                     NOT[p] = notResult;
+                    ISNULL[p] = isNullResult;
+                    ISNOTNULL[p] = isNotNullResult;
                 }
                 foreach (var q in allValues)
                 {
@@ -106,7 +121,6 @@
         private Stack<Dictionary<string, int>> _memberExpressionMappings = new Stack<Dictionary<string, int>>();

         // The following two are used for member expressions traversal.
-        private Stack<HashSet<string>> _collectedPathMemberExpressionsInExpressions = new Stack<HashSet<string>>();
         private int _memberExpressionDepth = 0;

         internal
@@ -115,6 +129,24 @@
         {
         }

+        internal static void Find(Expression expression, NameGenerator nameGenerator, IIsEntityDecider isEntityDecider, Dictionary<string, NhJoinClause> joins, Dictionary<MemberExpression, QuerySourceReferenceExpression> expressionMap)
+        {
+            WhereJoinDetector f = new WhereJoinDetector(nameGenerator, isEntityDecider, joins, expressionMap);
+
+            f._memberExpressionMappings.Push(new Dictionary<string, int>());
+
+            f.VisitExpression(expression);
+
+            foreach (var mapping in f._memberExpressionMappings.Pop())
+            {
+                // If outer join can never produce true, we can safely inner join.
+                if ((mapping.Value & T) == 0)
+                {
+                    f.MakeInnerIfJoined(mapping.Key);
+                }
+            }
+        }
+
         protected override Expression VisitBinaryExpression(BinaryExpression expression)
         {
             ArgumentUtility.CheckNotNull("expression", expression);
@@ -131,7 +163,7 @@
                 var newRight = VisitExpression(expression.Right);
                 var rightMapping = _memberExpressionMappings.Pop();

-                BinaryMapping(_memberExpressionMappings.Peek(), leftMapping, rightMapping, AND);
+                BinaryMapping(leftMapping, rightMapping, AND);

                 // The following is copy-pasted from Relinq's visitor, as I had to split the code above.
                 var newConversion = (LambdaExpression)VisitExpression(expression.Conversion);
@@ -149,7 +181,7 @@
                 var newRight = VisitExpression(expression.Right);
                 var rightMapping = _memberExpressionMappings.Pop();

-                BinaryMapping(_memberExpressionMappings.Peek(), leftMapping, rightMapping, OR);
+                BinaryMapping(leftMapping, rightMapping, OR);

                 // Again, the following is copy-pasted from Relinq's visitor, as I had to split the code above.
                 var newConversion = (LambdaExpression)VisitExpression(expression.Conversion);
@@ -157,39 +189,22 @@
                     baseResult = Expression.MakeBinary(expression.NodeType, newLeft, newRight, expression.IsLiftedToNull, expression.Method, newConversion);
             }
             else if (expression.Type == typeof(bool)
-                && (expression.NodeType == ExpressionType.Equal && !IsNullConstantExpression(expression.Right) && !IsNullConstantExpression(expression.Left)
-                 || expression.NodeType == ExpressionType.NotEqual && !IsNullConstantExpression(expression.Right) && !IsNullConstantExpression(expression.Left)
-                 || expression.NodeType == ExpressionType.LessThan
-                 || expression.NodeType == ExpressionType.LessThanOrEqual
-                 || expression.NodeType == ExpressionType.GreaterThan
-                 || expression.NodeType == ExpressionType.GreaterThanOrEqual))
-            {
-                // Cases (e), (f).2, (g).2
-                _collectedPathMemberExpressionsInExpressions.Push(new HashSet<string>());
-
+                && expression.NodeType == ExpressionType.NotEqual
+                && (IsNullConstantExpression(expression.Right) || IsNullConstantExpression(expression.Left)))
+            {
+                // Case (h)
+                _memberExpressionMappings.Push(new Dictionary<string, int>());
                 baseResult = base.VisitBinaryExpression(expression);
-
-                FixedMapping(_memberExpressionMappings.Peek(), _collectedPathMemberExpressionsInExpressions.Pop(), N);
+                UnaryMapping(_memberExpressionMappings.Pop(), ISNOTNULL);
             }
             else if (expression.Type == typeof(bool)
-                && expression.NodeType == ExpressionType.NotEqual)
-            {
-                // Case (h)
-                _collectedPathMemberExpressionsInExpressions.Push(new HashSet<string>());
-
+                && expression.NodeType == ExpressionType.Equal
+                && (IsNullConstantExpression(expression.Right) || IsNullConstantExpression(expression.Left)))
+            {
+                // Case (i)
+                _memberExpressionMappings.Push(new Dictionary<string, int>());
                 baseResult = base.VisitBinaryExpression(expression);
-
-                FixedMapping(_memberExpressionMappings.Peek(), _collectedPathMemberExpressionsInExpressions.Pop(), F);
-            }
-            else if (expression.Type == typeof(bool)
-                && expression.NodeType == ExpressionType.Equal)
-            {
-                // Case (i)
-                _collectedPathMemberExpressionsInExpressions.Push(new HashSet<string>());
-
-                baseResult = base.VisitBinaryExpression(expression);
-
-                FixedMapping(_memberExpressionMappings.Peek(), _collectedPathMemberExpressionsInExpressions.Pop(), T);
+                UnaryMapping(_memberExpressionMappings.Pop(), ISNULL);
             }
             else // +, * etc.
             {
@@ -199,51 +214,6 @@
             return baseResult;
         }

-        private static void FixedMapping(Dictionary<string, int> resultMapping, IEnumerable<string> collectedPathMemberExpressionsInExpression, int value)
-        {
-            foreach (var me in collectedPathMemberExpressionsInExpression)
-            {
-                // This ORing behavior was added without much thought to fix NHibernate.Test.NHSpecificTest.NH2378.Fixture.ShortEntityCanBeQueryCorrectlyUsingLinqProvider.
-                if (resultMapping.ContainsKey(me))
-                    resultMapping[me] |= value;
-                else
-                    resultMapping.Add(me, value);
-            }
-        }
-
-        private static void BinaryMapping(Dictionary<string, int> resultMapping, Dictionary<string, int> leftMapping, Dictionary<string, int> rightMapping, int[,] op)
-        {
-            // Compute mapping for all member expressions in leftMapping. If the member expression is missing
-            // in rightMapping, use TNF as a "pessimistic approximation" instead (inside the ?: operator). See
-            // the text for an explanation of this.
-            foreach (var lhs in leftMapping)
-            {
-                resultMapping.Add(lhs.Key, op[lhs.Value, rightMapping.ContainsKey(lhs.Key) ? rightMapping[lhs.Key] : TNF]);
-            }
-            // Compute mapping for all member expressions *only* in rightMapping (we did the common ones above).
-            // Again, use TNF as pessimistic approximation to result of left subcondition.
-            foreach (var rhs in rightMapping)
-            {
-                if (!leftMapping.ContainsKey(rhs.Key))
-                {
-                    resultMapping[rhs.Key] = op[rhs.Value, TNF];
-                }
-            }
-        }
-
-        private static bool IsNullConstantExpression(Expression expression)
-        {
-            if (expression is ConstantExpression)
-            {
-                var constant = (ConstantExpression)expression;
-                return constant.Value == null;
-            }
-            else
-            {
-                return false;
-            }
-        }
-
         protected override Expression VisitUnaryExpression(UnaryExpression expression)
         {
             ArgumentUtility.CheckNotNull("expression", expression);
@@ -254,12 +224,7 @@
                 // Case (c) from text at NH-2583.
                 _memberExpressionMappings.Push(new Dictionary<string, int>());
                 baseResult = VisitExpression(expression.Operand);
-                var opMapping = _memberExpressionMappings.Pop();
-
-                foreach (var m in opMapping)
-                {
-                    _memberExpressionMappings.Peek().Add(m.Key, NOT[m.Value]);
-                }
+                UnaryMapping(_memberExpressionMappings.Pop(), NOT);
             }
             else
             {
@@ -284,104 +249,105 @@

         protected override Expression VisitMethodCallExpression(MethodCallExpression expression)
         {
-            // Similar logic to VisitMemberExpression, but for handling boolean method results instead of boolean members.
-            bool addOwnMemberExpressionMapping = false;
-            if (_memberExpressionDepth == 0 && _collectedPathMemberExpressionsInExpressions.Count == 0)
-            {
-                if (expression.Type != typeof(bool))
-                    throw new AssertionFailure("Was expecting a boolean member expression.");
-                addOwnMemberExpressionMapping = true;
-                _collectedPathMemberExpressionsInExpressions.Push(new HashSet<string>());
-            }
-
+            _memberExpressionMappings.Push(new Dictionary<string, int>());
+            Expression result = base.VisitMethodCallExpression(expression);
+            // We would usually get NULL if one of our inner member expresions was null. (Mapped to N)
+            // However, it's possible a method call will convert the null value from the failed join into any one of True, False, or Null. (Mapped to TNF)
+            // This could be optimized by actually checking what the method does.  For example StartsWith("s") would leave null as null and would still allow us to inner join.
+            FixedMapping(_memberExpressionMappings.Pop(), TNF);
+            return result;
+        }
+
+        protected override Expression VisitMemberExpression(MemberExpression expression)
+        {
+            ArgumentUtility.CheckNotNull("expression", expression);
+
+            Expression newExpression;
             try
             {
-                return base.VisitMethodCallExpression(expression);
+                _memberExpressionDepth++;
+                newExpression = base.VisitExpression(expression.Expression);
             }
             finally
             {
-                if (addOwnMemberExpressionMapping)
+                _memberExpressionDepth--;
+            }
+            bool isEntity = _isEntityDecider.IsEntity(expression.Type);
+
+            if (isEntity)
+            {
+                // See (h) why we do not check for _memberExpressionDepth here!
+                AddPossibility(ExpressionKeyVisitor.Visit(expression, null), N);
+            }
+
+            if (_memberExpressionDepth > 0 && isEntity)
+            {
+                return AddJoin(expression);
+            }
+            else
+            {
+                if (newExpression != expression.Expression)
+                    return Expression.MakeMemberAccess(newExpression, expression.Member);
+                return expression;
+            }
+        }
+
+        private void FixedMapping(Dictionary<string, int> sourceMapping, int value)
+        {
+            foreach (var me in sourceMapping.Keys)
+            {
+                AddPossibility(me, value);
+            }
+        }
+
+        private void BinaryMapping(Dictionary<string, int> leftMapping, Dictionary<string, int> rightMapping, int[,] op)
+        {
+            // Compute mapping for all member expressions in leftMapping. If the member expression is missing
+            // in rightMapping, use TNF as a "pessimistic approximation" instead (inside the ?: operator). See
+            // the text for an explanation of this.
+            foreach (var lhs in leftMapping)
+            {
+                AddPossibility(lhs.Key, op[lhs.Value, rightMapping.ContainsKey(lhs.Key) ? rightMapping[lhs.Key] : TNF]);
+            }
+            // Compute mapping for all member expressions *only* in rightMapping (we did the common ones above).
+            // Again, use TNF as pessimistic approximation to result of left subcondition.
+            foreach (var rhs in rightMapping)
+            {
+                if (!leftMapping.ContainsKey(rhs.Key))
                 {
-                    // We would often get the same mapping as the not-null (in)equality clause in VisitBinaryExpression.
-                    // However, it's possible a method call will convert the null value from the failed join into any one of True, False, or Null.
-                    FixedMapping(_memberExpressionMappings.Peek(), _collectedPathMemberExpressionsInExpressions.Pop(), TNF);
+                    AddPossibility(rhs.Key, op[rhs.Value, TNF]);
                 }
             }
         }

-        protected override Expression VisitMemberExpression(MemberExpression expression)
-        {
-            ArgumentUtility.CheckNotNull("expression", expression);
-
-            // For the boolean part of expressions like: a => a.B.C == 1 && a.D.E
-            // There wouldn't have been a parent operator to collect paths for a.D.E.
-            // Below we add the same mapping as if we were doing a.D.E == true.
-            bool addOwnMemberExpressionMapping = false;
-            if (_memberExpressionDepth == 0 && _collectedPathMemberExpressionsInExpressions.Count == 0)
-            {
-                if (expression.Type != typeof(bool))
-                    throw new AssertionFailure("Was expecting a boolean member expression.");
-                addOwnMemberExpressionMapping = true;
-                _collectedPathMemberExpressionsInExpressions.Push(new HashSet<string>());
-            }
-
-            try
-            {
-                Expression newExpression;
-                try
-                {
-                    _memberExpressionDepth++;
-                    newExpression = base.VisitExpression(expression.Expression);
-                }
-                finally
-                {
-                    _memberExpressionDepth--;
-                }
-                bool isEntity = _isEntityDecider.IsEntity(expression.Type);
-
-                if (isEntity)
-                {
-                    // See (h) why we do not check for _memberExpressionDepth here!
-                    _collectedPathMemberExpressionsInExpressions.Peek().Add(ExpressionKeyVisitor.Visit(expression, null));
-                }
-
-                if (_memberExpressionDepth > 0 && isEntity)
-                {
-                    return AddJoin(expression);
-                }
-                else
-                {
-                    if (newExpression != expression.Expression)
-                        return Expression.MakeMemberAccess(newExpression, expression.Member);
-                    return expression;
-                }
-            }
-            finally
-            {
-                if (addOwnMemberExpressionMapping)
-                {
-                    // Same mapping as the not-null (in)equality clause in VisitBinaryExpression.
-                    FixedMapping(_memberExpressionMappings.Peek(), _collectedPathMemberExpressionsInExpressions.Pop(), N);
-                }
-            }
-        }
-
-        internal static void Find(Expression expression, NameGenerator nameGenerator, IIsEntityDecider isEntityDecider, Dictionary<string, NhJoinClause> joins, Dictionary<MemberExpression, QuerySourceReferenceExpression> expressionMap)
-        {
-            WhereJoinDetector f = new WhereJoinDetector(nameGenerator, isEntityDecider, joins, expressionMap);
-
-            f._memberExpressionMappings.Push(new Dictionary<string, int>());
-
-            f.VisitExpression(expression);
-
-            foreach (var mapping in f._memberExpressionMappings.Pop())
-            {
-                // If outer join can never produce true, we can safely inner join.
-                if ((mapping.Value & T) == 0)
-                {
-                    f.MakeInnerIfJoined(mapping.Key);
-                }
-            }
+        private void UnaryMapping(Dictionary<string, int> sourceMapping, int[] op)
+        {
+            foreach (var item in sourceMapping)
+            {
+                AddPossibility(item.Key, op[item.Value]);
+            }
+        }
+
+        private static bool IsNullConstantExpression(Expression expression)
+        {
+            if (expression is ConstantExpression)
+            {
+                var constant = (ConstantExpression)expression;
+                return constant.Value == null;
+            }
+            else
+            {
+                return false;
+            }
+        }
+
+        private void AddPossibility(string memberPath, int value)
+        {
+            Dictionary<string, int> mapping = _memberExpressionMappings.Peek();
+            if (mapping.ContainsKey(memberPath))
+                mapping[memberPath] |= value;
+            else
+                mapping[memberPath] = value;
         }
     }
 }


optimizing the solution. Place 1000 queens for 13sec

--- NQueensProblem/Program.cs
+++ NQueensProblem/Program.cs
@@ -1,41 +1,41 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-
-namespace NQueensProblem
-{
-    class Program
-    {
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+
+namespace NQueensProblem
+{
+    class Program
+    {
         private static Random random = new Random();
-        public static int COUNTER = 0;
-        static void Main(string[] args)
-        {
-            int n = 4;
-            var watch = System.Diagnostics.Stopwatch.StartNew();
-            if (n < 4)
-            {
-                Console.WriteLine("{0} queens cannot be placed in this board", n);
-                return;
-            }
-
+
+        static void Main(string[] args)
+        {
+            int n = 1000;
+            var watch = System.Diagnostics.Stopwatch.StartNew();
+            if (n < 4)
+            {
+                Console.WriteLine("{0} queens cannot be placed in this board", n);
+                return;
+            }
+
             PlaceQueens(n);

             watch.Stop();
             var elapsedMs = watch.ElapsedMilliseconds;
-            Console.WriteLine("Total time: {0} ms", elapsedMs);
-
-            Console.ReadLine();
-        }
-
-        public static void PlaceQueens(int n)
-        {
-            int[] board = new int[n];
-
+            Console.WriteLine("Total time: {0} ms", elapsedMs);
+
+            Console.ReadLine();
+        }
+
+        public static void PlaceQueens(int n)
+        {
+            int[] board = new int[n];
+
             RandomInitBoard(board);
-            //PrintBoard(board);
+
             int[] queensConflictsCount = InitQueensConflictsArray(board);

             if (!HasConflicts(queensConflictsCount))
@@ -43,40 +43,40 @@
                 Console.WriteLine("Yeah the queens are places");
                 PrintBoard(board);
                 return;
-            }
-
-            int limit = n * n;
-            for (int i = 0; i < limit; i++)
-            {
-                queensConflictsCount = SwapQueens(board, queensConflictsCount);
-
-                if (!HasConflicts(queensConflictsCount))
-                {
-                    Console.WriteLine("Yeah the queens are places");
-                    PrintBoard(board);
-                    return;
-                }
-            }
-
-            if (HasConflicts(queensConflictsCount))
-            {
-                Console.WriteLine("New Recursive call");
-                PlaceQueens(n);
-            }
-        }
-
-        private static void RandomInitBoard(int[] board)
+            }
+
+            int limit = n * n;
+            for (int i = 0; i < limit; i++)
+            {
+                queensConflictsCount = SwapQueens(board, queensConflictsCount);
+
+                if (!HasConflicts(queensConflictsCount))
+                {
+                    Console.WriteLine("Yeah the queens are places");
+                    PrintBoard(board);
+                    return;
+                }
+            }
+
+            if (HasConflicts(queensConflictsCount))
+            {
+                Console.WriteLine("New Recursive call");
+                PlaceQueens(n);
+            }
+        }
+
+        private static void RandomInitBoard(int[] board)
         {
             List<int> placedValues = new List<int>();
-            bool isPlaceAllowed = false;
-            for (int i = 0; i < board.Length; i++)
+            bool isPlaceAllowed = false;
+            for (int i = 0; i < board.Length; i++)
             {
                 do
                 {
                     var newValue = random.Next(board.Length);
                     isPlaceAllowed = isPlacingAllowed(placedValues, newValue, board, i);
-                } while (!isPlaceAllowed);
-            }
+                } while (!isPlaceAllowed);
+            }
         }

         private static bool isPlacingAllowed(List<int> placedValues, int newValue, int[] board, int index)
@@ -88,76 +88,96 @@
                 return true;
             }
             return false;
-        }
-
-        private static int GetMinConflictsQueenRow(int[] swapQueensConflictsArr)
-        {
-            int minIndex = Array.IndexOf(swapQueensConflictsArr, swapQueensConflictsArr.Min());
-            var indexes = swapQueensConflictsArr.Where(x => x == minIndex).ToList();
-            return indexes[random.Next(indexes.Count-1)];
-        }
-
-        private static int GetMaxConflictsQueenRow(int[] swapQueensConflictsArr)
-        {
-            var indexes = swapQueensConflictsArr.Where(x => x == swapQueensConflictsArr.Max()).ToList();
-            return indexes[random.Next(indexes.Count - 1)];
-        }
-
-        private static int[] SwapQueens(int[] board, int[] queensConflictsCountArray)
-        {
-            int minConflictsColumnIndex;
-            int maxConflictsColumnIndex = GetMaxConflictsQueenRow(queensConflictsCountArray);
-
-            do
-            {
-                minConflictsColumnIndex = random.Next(board.Length-1);
-            } while (minConflictsColumnIndex == maxConflictsColumnIndex);
-
-
+        }
+
+        private static int GetMaxConflictsQueenRow(int[] swapQueensConflictsArr)
+        {
+            var indexes = new List<int>() { 0 };
+            int max = swapQueensConflictsArr[0];
+            for (int i = 1; i < swapQueensConflictsArr.Length; i++)
+            {
+                if (swapQueensConflictsArr[i] == max)
+                {
+                    indexes.Add(i);
+                }
+                else if (swapQueensConflictsArr[i] > max)
+                {
+                    max = swapQueensConflictsArr[i];
+                    indexes = new List<int>() { i };
+                }
+            }
+
+            return indexes[random.Next(indexes.Count)];
+        }
+
+        private static int[] SwapQueens(int[] board, int[] queensConflictsCountArray)
+        {
+            int maxConflictsColumnIndex = GetMaxConflictsQueenRow(queensConflictsCountArray);
+
+            var currentQueenConflictsCount = queensConflictsCountArray[maxConflictsColumnIndex];
+            var minConflictsRowsIndexesArr = new List<int>();
+            var minConflicts = currentQueenConflictsCount;
+
+            for (int i = 0; i < board.Length; i++) //current col
+            {
+                if (i != board[maxConflictsColumnIndex]) //row check
+                {
+                    board[maxConflictsColumnIndex] = i;
+                    var conflictsCount = GetCertainColumnConflictsCount(board, maxConflictsColumnIndex);
+                    if (conflictsCount < minConflicts)
+                    {
+                        minConflicts = conflictsCount;
+                        minConflictsRowsIndexesArr.Clear();
+                        minConflictsRowsIndexesArr.Add(i);
+                    }
+                    else if (conflictsCount == minConflicts)
+                    {
+                        minConflictsRowsIndexesArr.Add(i);
+                    }
+                }
+            }
+
             //decrease conflicts indexes
-            //DereaseConflictsCount(board, minConflictsColumnIndex, queensConflictsCountArray);
             //DereaseConflictsCount(board, maxConflictsColumnIndex, queensConflictsCountArray);

             //swap
-            int minColumn = board[minConflictsColumnIndex];
-            board[minConflictsColumnIndex] = board[maxConflictsColumnIndex];
-            board[maxConflictsColumnIndex] = minColumn;
+            int swapIndex = random.Next(minConflictsRowsIndexesArr.Count);
+            board[maxConflictsColumnIndex] = minConflictsRowsIndexesArr[swapIndex];

             //increase conflicts indexes
-            //IncreaseConflictsCount(board, minConflictsColumnIndex, queensConflictsCountArray);
             //IncreaseConflictsCount(board, maxConflictsColumnIndex, queensConflictsCountArray);

             queensConflictsCountArray = InitQueensConflictsArray(board);

-            return queensConflictsCountArray;
-        }
-
-        private static int GetCertainColumnConflictsCount(int[] board, int colIndex)
-        {
-            int conflictsCount = 0;
-
-            for (int i = 0; i < board.Length; i++)
-            {
-                if (i != colIndex)
-                {
-                    if (board[i] == board[colIndex])
-                        conflictsCount++;
-                    else if (Math.Abs(board[colIndex] - board[i]) == Math.Abs(i - colIndex))
-                        conflictsCount++;
-                }
-            }
-            return conflictsCount;
-        }
-
-        private static int[] InitQueensConflictsArray(int[] board)
-        {
-            int[] queensConflictsCount = new int[board.Length];
-            for (int i = 0; i < board.Length; i++)
-            {
-                IncreaseConflictsCount(board, i, queensConflictsCount);
-            }
-
-            return queensConflictsCount;
+            return queensConflictsCountArray;
+        }
+
+        private static int GetCertainColumnConflictsCount(int[] board, int colIndex)
+        {
+            int conflictsCount = 0;
+
+            for (int i = 0; i < board.Length; i++)
+            {
+                if (i != colIndex)
+                {
+                    if (board[i] == board[colIndex])
+                        conflictsCount++;
+                    else if (Math.Abs(board[colIndex] - board[i]) == Math.Abs(i - colIndex))
+                        conflictsCount++;
+                }
+            }
+            return conflictsCount;
+        }
+
+        private static int[] InitQueensConflictsArray(int[] board)
+        {
+            int[] queensConflictsCount = new int[board.Length];
+            for (int i = 0; i < board.Length; i++)
+            {
+                IncreaseConflictsCount(board, i, queensConflictsCount);
+            }
+
+            return queensConflictsCount;
         }

         private static void IncreaseConflictsCount(int[] board, int index, int[] queensConflictsCountArr)
@@ -211,24 +231,16 @@
                     }
                 }
             }
-        }
-
-        private static bool HasConflicts(int[] queensConflitsCountArr)
-        {
-            //for (int i = 0; i < queensConflitsCountArr.Length; i++)
-            //{
-            //    if (queensConflitsCountArr[i] > 0)
-            //        return true;
-            //}
-
-            //return false;
-
-            return queensConflitsCountArr.Count(x => x > 0) > 0;
-        }
-
-        private static void PrintBoard(int[] board)
-        {
-            Console.WriteLine(string.Join(" ", board));
-        }
-    }
+        }
+
+        private static bool HasConflicts(int[] queensConflitsCountArr)
+        {
+            return queensConflitsCountArr.Count(x => x > 0) > 0;
+        }
+
+        private static void PrintBoard(int[] board)
+        {
+            Console.WriteLine(string.Join(" ", board));
+        }
+    }
 }


reorder

reorder

--- NetCoreCMS.Web/Startup.cs
+++ NetCoreCMS.Web/Startup.cs
@@ -79,6 +79,172 @@
             var logFilePath = NccInfo.LogFolder + "\\NetCoreCMS_Logs_{Date}.log";
             Log.Logger      = new LoggerConfiguration().Enrich.FromLogContext().WriteTo.RollingFile(logFilePath).CreateLogger();
         }
+
+        public IConfiguration Configuration { get; }
+        public IConfigurationRoot ConfigurationRoot { get; }
+
+        // This method gets called by the runtime. Use this method to add services to the container.
+        public void ConfigureServices(IServiceCollection services)
+        {
+            _services = services;
+
+            _services.AddLogging(loggingBuilder =>
+            loggingBuilder.AddSerilog(dispose: true));
+
+            _services.AddOptions();
+            _services.AddSingleton(typeof(IStringLocalizer), typeof(NccStringLocalizer<SharedResource>));
+            _services.AddSingleton<IAuthorizationHandler, AuthRequireHandler>();
+
+            _services.AddLocalization();
+            _mvcBuilder = services.AddMvc(config => {
+                var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
+                config.Filters.Add(new AuthorizeFilter(policy));
+            });
+
+            _mvcBuilder.AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix);
+            _mvcBuilder.AddDataAnnotationsLocalization(options => {
+                options.DataAnnotationLocalizerProvider = (type, factory) => new NccStringLocalizer<SharedResource>(factory, new HttpContextAccessor());
+            });
+
+            _services.AddResponseCaching();
+            _services.AddSession(options =>
+            {
+                options.Cookie.Name = ".NetCoreCMS.Cookie.Session";
+                options.IdleTimeout = TimeSpan.FromMinutes(20);
+                options.Cookie.HttpOnly = true;
+            });
+
+            _services.AddDistributedMemoryCache();
+            _services.AddResponseCompression();
+            _services.AddSingleton(Configuration);
+
+            _services.AddMaintenance(() => _setupConfig.IsMaintenanceMode, Encoding.UTF8.GetBytes("

" + _setupConfig.MaintenanceMessage + "

"), "text/html", _setupConfig.MaintenanceDownTime * 60);
+
+            _services.AddNccCoreModuleServices();
+            _serviceProvider = _services.Build(ConfigurationRoot, _hostingEnvironment);
+
+
+            var themeFolder = Path.Combine(_hostingEnvironment.ContentRootPath, NccInfo.ThemeFolder);
+            var moduleFolder = _hostingEnvironment.ContentRootFileProvider.GetDirectoryContents(NccInfo.ModuleFolder);
+            var coreModuleFolder = _hostingEnvironment.ContentRootFileProvider.GetDirectoryContents(NccInfo.CoreModuleFolder);
+            var themesDirectoryContents = _hostingEnvironment.ContentRootFileProvider.GetDirectoryContents(NccInfo.ThemeFolder);
+
+            _themeManager.ScanThemeDirectory(themeFolder);
+            _themeManager.RegisterThemes(_mvcBuilder, _services,_serviceProvider, themesDirectoryContents);
+
+            var coreModules = _moduleManager.LoadModules(coreModuleFolder);
+            var userModules = _moduleManager.LoadModules(moduleFolder);
+
+            GlobalContext.Modules.AddRange(userModules);
+
+            if (SetupHelper.IsDbCreateComplete)
+            {
+                #region Database Selection
+
+                if (SetupHelper.SelectedDatabase == "SqLite")
+                {
+                    _services.AddDbContext<NccDbContext>(options =>
+                        options.UseSqlite(SetupHelper.ConnectionString, opt => opt.MigrationsAssembly("NetCoreCMS.Framework"))
+                    );
+                }
+                else if (SetupHelper.SelectedDatabase == "MSSQL")
+                {
+                    _services.AddDbContext<NccDbContext>(options =>
+                        options.UseSqlServer(SetupHelper.ConnectionString, opt => opt.MigrationsAssembly("NetCoreCMS.Framework"))
+                    );
+                }
+                else if (SetupHelper.SelectedDatabase == "MySql")
+                {
+                    _services.AddDbContext<NccDbContext>(options =>
+                        options.UseMySql(SetupHelper.ConnectionString, opt => opt.MigrationsAssembly("NetCoreCMS.Framework"))
+                    );
+                }
+                else
+                {
+                    _services.AddDbContext<NccDbContext>(options =>
+                        options.UseInMemoryDatabase("NetCoreCMS")
+                    );
+                }
+
+                #endregion
+
+                _services.AddCustomizedIdentity();
+                _startup.RegisterDatabase(_services);
+
+                _serviceProvider = _services.Build(ConfigurationRoot, _hostingEnvironment);
+
+                _moduleManager.AddModulesAsApplicationPart(_mvcBuilder, _services, _serviceProvider);
+
+                _moduleManager.AddModuleServices(_services);
+                _moduleManager.AddModuleFilters(_services);
+                _moduleManager.AddShortcodes(_services);
+                _moduleManager.AddModuleWidgets(_services);
+
+                _serviceProvider = _services.Build(ConfigurationRoot, _hostingEnvironment);
+
+                _themeManager.RegisterThemeWidgets(_mvcBuilder, _services, _serviceProvider, themesDirectoryContents);
+                _moduleManager.RegisterModuleWidgets(_mvcBuilder, _services, _serviceProvider);
+                _moduleManager.RegisterModuleFilters(_mvcBuilder, _serviceProvider);
+                _moduleManager.RegisterModuleShortCodes(_mvcBuilder, _serviceProvider);
+            }
+
+            var defaultCulture = new RequestCulture("en");
+
+            if (SetupHelper.IsAdminCreateComplete)
+            {
+                GlobalContext.SetupConfig = SetupHelper.LoadSetup();
+                defaultCulture = new RequestCulture(GlobalContext.SetupConfig.Language);
+                GlobalMessageRegistry.LoadMessagesFromStorage();
+            }
+
+            services.Configure<RouteOptions>(options =>
+            {
+                options.ConstraintMap.Add("lang", typeof(LanguageRouteConstraint));
+            });
+
+            _services.Configure<RequestLocalizationOptions>(
+                opts =>
+                {
+                    var supportedCultures = SupportedCultures.Cultures;
+                    opts.DefaultRequestCulture = defaultCulture;
+                    opts.SupportedCultures = supportedCultures;
+                    opts.SupportedUICultures = supportedCultures;
+
+                    var provider = new RouteDataRequestCultureProvider();
+                    provider.RouteDataStringKey = "lang";
+                    provider.UIRouteDataStringKey = "lang";
+                    provider.Options = opts;
+                    opts.RequestCultureProviders = new[] { provider };
+                }
+            );
+
+            services.Configure<ClassLibraryLocalizationOptions>(
+                options => options.ResourcePaths = new Dictionary<string, string>
+                {
+                    { "NetCoreCMS.Framework", "i18n/Resources" },
+                    { "NetCoreCMS.Web", "Resources" }
+                }
+            );
+
+            _serviceProvider = _services.Build(ConfigurationRoot, _hostingEnvironment);
+            _serviceProvider = _services.BuildModules(ConfigurationRoot, _hostingEnvironment);
+
+            GlobalContext.ServiceProvider = _serviceProvider;
+            GlobalContext.Services = _services;
+            NetCoreCmsHost.Mediator = _serviceProvider.GetService<IMediator>();
+            NetCoreCmsHost.Services = _services;
+            NetCoreCmsHost.ServiceProvider = _serviceProvider;
+        }
+
+        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
+        public void Configure(IApplicationBuilder app, IHostingEnvironment env, IMediator mediator, ILoggerFactory loggerFactory)
+        {
+            app.UseRequestTracker();
+            app.UseNetCoreCMS(env, _serviceProvider, loggerFactory);
+            app.UseNccRoutes(env, _serviceProvider, loggerFactory);
+            NetCoreCmsHost.Logger = loggerFactory.CreateLogger<Startup>();
+            NetCoreCmsHost.HttpContext = new HttpContextAccessor().HttpContext;
+        }

         private void ResetGlobalContext(IConfiguration configuration, IHostingEnvironment env)
         {
@@ -92,172 +258,6 @@
             GlobalContext.Menus = new List<NccMenu>();
             GlobalContext.Themes = new List<Theme>();
         }
-
-        public IConfiguration Configuration { get; }
-        public IConfigurationRoot ConfigurationRoot { get; }
-
-        // This method gets called by the runtime. Use this method to add services to the container.
-        public void ConfigureServices(IServiceCollection services)
-        {
-            _services = services;
-
-            _services.AddLogging(loggingBuilder =>
-            loggingBuilder.AddSerilog(dispose: true));
-
-            _services.AddOptions();
-            _services.AddSingleton(typeof(IStringLocalizer), typeof(NccStringLocalizer<SharedResource>));
-            _services.AddSingleton<IAuthorizationHandler, AuthRequireHandler>();
-
-            _services.AddLocalization();
-            _mvcBuilder = services.AddMvc(config => {
-                var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
-                config.Filters.Add(new AuthorizeFilter(policy));
-            });
-
-            _mvcBuilder.AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix);
-            _mvcBuilder.AddDataAnnotationsLocalization(options => {
-                options.DataAnnotationLocalizerProvider = (type, factory) => new NccStringLocalizer<SharedResource>(factory, new HttpContextAccessor());
-            });
-
-            _services.AddResponseCaching();
-            _services.AddSession(options =>
-            {
-                options.Cookie.Name = ".NetCoreCMS.Cookie.Session";
-                options.IdleTimeout = TimeSpan.FromMinutes(20);
-                options.Cookie.HttpOnly = true;
-            });
-
-            _services.AddDistributedMemoryCache();
-            _services.AddResponseCompression();
-            _services.AddSingleton(Configuration);
-
-            _services.AddMaintenance(() => _setupConfig.IsMaintenanceMode, Encoding.UTF8.GetBytes("

" + _setupConfig.MaintenanceMessage + "

"), "text/html", _setupConfig.MaintenanceDownTime * 60);
-
-            _services.AddNccCoreModuleServices();
-            _serviceProvider = _services.Build(ConfigurationRoot, _hostingEnvironment);
-
-
-            var themeFolder = Path.Combine(_hostingEnvironment.ContentRootPath, NccInfo.ThemeFolder);
-            var moduleFolder = _hostingEnvironment.ContentRootFileProvider.GetDirectoryContents(NccInfo.ModuleFolder);
-            var coreModuleFolder = _hostingEnvironment.ContentRootFileProvider.GetDirectoryContents(NccInfo.CoreModuleFolder);
-            var themesDirectoryContents = _hostingEnvironment.ContentRootFileProvider.GetDirectoryContents(NccInfo.ThemeFolder);
-
-            _themeManager.ScanThemeDirectory(themeFolder);
-            _themeManager.RegisterThemes(_mvcBuilder, _services,_serviceProvider, themesDirectoryContents);
-
-            var coreModules = _moduleManager.LoadModules(coreModuleFolder);
-            var userModules = _moduleManager.LoadModules(moduleFolder);
-
-            GlobalContext.Modules.AddRange(userModules);
-
-            if (SetupHelper.IsDbCreateComplete)
-            {
-                #region Database Selection
-
-                if (SetupHelper.SelectedDatabase == "SqLite")
-                {
-                    _services.AddDbContext<NccDbContext>(options =>
-                        options.UseSqlite(SetupHelper.ConnectionString, opt => opt.MigrationsAssembly("NetCoreCMS.Framework"))
-                    );
-                }
-                else if (SetupHelper.SelectedDatabase == "MSSQL")
-                {
-                    _services.AddDbContext<NccDbContext>(options =>
-                        options.UseSqlServer(SetupHelper.ConnectionString, opt => opt.MigrationsAssembly("NetCoreCMS.Framework"))
-                    );
-                }
-                else if (SetupHelper.SelectedDatabase == "MySql")
-                {
-                    _services.AddDbContext<NccDbContext>(options =>
-                        options.UseMySql(SetupHelper.ConnectionString, opt => opt.MigrationsAssembly("NetCoreCMS.Framework"))
-                    );
-                }
-                else
-                {
-                    _services.AddDbContext<NccDbContext>(options =>
-                        options.UseInMemoryDatabase("NetCoreCMS")
-                    );
-                }
-
-                #endregion
-
-                _services.AddCustomizedIdentity();
-                _startup.RegisterDatabase(_services);
-
-                _serviceProvider = _services.Build(ConfigurationRoot, _hostingEnvironment);
-
-                _moduleManager.AddModulesAsApplicationPart(_mvcBuilder, _services, _serviceProvider);
-
-                _moduleManager.AddModuleServices(_services);
-                _moduleManager.AddModuleFilters(_services);
-                _moduleManager.AddShortcodes(_services);
-                _moduleManager.AddModuleWidgets(_services);
-
-                _serviceProvider = _services.Build(ConfigurationRoot, _hostingEnvironment);
-
-                _themeManager.RegisterThemeWidgets(_mvcBuilder, _services, _serviceProvider, themesDirectoryContents);
-                _moduleManager.RegisterModuleWidgets(_mvcBuilder, _services, _serviceProvider);
-                _moduleManager.RegisterModuleFilters(_mvcBuilder, _serviceProvider);
-                _moduleManager.RegisterModuleShortCodes(_mvcBuilder, _serviceProvider);
-            }
-
-            var defaultCulture = new RequestCulture("en");
-
-            if (SetupHelper.IsAdminCreateComplete)
-            {
-                GlobalContext.SetupConfig = SetupHelper.LoadSetup();
-                defaultCulture = new RequestCulture(GlobalContext.SetupConfig.Language);
-                GlobalMessageRegistry.LoadMessagesFromStorage();
-            }
-
-            services.Configure<RouteOptions>(options =>
-            {
-                options.ConstraintMap.Add("lang", typeof(LanguageRouteConstraint));
-            });
-
-            _services.Configure<RequestLocalizationOptions>(
-                opts =>
-                {
-                    var supportedCultures = SupportedCultures.Cultures;
-                    opts.DefaultRequestCulture = defaultCulture;
-                    opts.SupportedCultures = supportedCultures;
-                    opts.SupportedUICultures = supportedCultures;
-
-                    var provider = new RouteDataRequestCultureProvider();
-                    provider.RouteDataStringKey = "lang";
-                    provider.UIRouteDataStringKey = "lang";
-                    provider.Options = opts;
-                    opts.RequestCultureProviders = new[] { provider };
-                }
-            );
-
-            services.Configure<ClassLibraryLocalizationOptions>(
-                options => options.ResourcePaths = new Dictionary<string, string>
-                {
-                    { "NetCoreCMS.Framework", "i18n/Resources" },
-                    { "NetCoreCMS.Web", "Resources" }
-                }
-            );
-
-            _serviceProvider = _services.Build(ConfigurationRoot, _hostingEnvironment);
-            _serviceProvider = _services.BuildModules(ConfigurationRoot, _hostingEnvironment);
-
-            GlobalContext.ServiceProvider = _serviceProvider;
-            GlobalContext.Services = _services;
-            NetCoreCmsHost.Mediator = _serviceProvider.GetService<IMediator>();
-            NetCoreCmsHost.Services = _services;
-            NetCoreCmsHost.ServiceProvider = _serviceProvider;
-        }
-
-        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
-        public void Configure(IApplicationBuilder app, IHostingEnvironment env, IMediator mediator, ILoggerFactory loggerFactory)
-        {
-            app.UseRequestTracker();
-            app.UseNetCoreCMS(env, _serviceProvider, loggerFactory);
-            app.UseNccRoutes(env, _serviceProvider, loggerFactory);
-            NetCoreCmsHost.Logger = loggerFactory.CreateLogger<Startup>();
-            NetCoreCmsHost.HttpContext = new HttpContextAccessor().HttpContext;
-        }
     }
 }


Add DragOver Handlers

Add DragOver Handlers

--- ThemeEditor.WPF/Markup/DragDropBehaviour.cs
+++ ThemeEditor.WPF/Markup/DragDropBehaviour.cs
@@ -2,6 +2,7 @@
 // 3DS Theme Editor - DropBehaviour.cs
 // --------------------------------------------------

+using System.Linq.Expressions;
 using System.Windows;
 using System.Windows.Input;

@@ -27,9 +28,21 @@
                 typeof(DragDropBehaviour),
                 new PropertyMetadata(default(ICommand), OnDragLeaveChanged));

+        public static readonly DependencyProperty DragOverCommandProperty
+      = DependencyProperty.RegisterAttached("DragOverCommand",
+          typeof(ICommand),
+          typeof(DragDropBehaviour),
+          new PropertyMetadata(default(ICommand), OnDragOverChanged));
+
+
+
         public static ICommand GetDragLeaveCommand(DependencyObject element)
         {
             return (ICommand)element.GetValue(DragLeaveCommandProperty);
+        }
+        public static ICommand GetDragOverCommand(DependencyObject element)
+        {
+            return (ICommand)element.GetValue(DragOverCommandProperty);
         }

         public static ICommand GetDragDropCommand(DependencyObject element)
@@ -47,6 +60,11 @@
             element.SetValue(DragLeaveCommandProperty, value);
         }

+        public static void SetDragOverCommand(DependencyObject element, ICommand value)
+        {
+            element.SetValue(DragOverCommandProperty, value);
+        }
+
         public static void SetDragDropCommand(DependencyObject element, ICommand value)
         {
             element.SetValue(DragDropCommandProperty, value);
@@ -61,10 +79,14 @@
         {
             var command = GetDragEnterCommand((DependencyObject) sender);
             if (command?.CanExecute(args) ?? false)
+            {
                 command.Execute(args);
+            }
             else
+            {
                 args.Effects = DragDropEffects.None;
-            args.Handled = true;
+                args.Handled = true;
+            }
         }

         private static void OnDragEnterChanged(DependencyObject elem, DependencyPropertyChangedEventArgs args)
@@ -80,10 +102,37 @@
         {
             var command = GetDragDropCommand((DependencyObject) sender);
             if (command?.CanExecute(args) ?? false)
+            {
                 command.Execute(args);
+            }
             else
+            {
                 args.Effects = DragDropEffects.None;
-            args.Handled = true;
+                args.Handled = true;
+            }
+        }
+
+        private static void OnDragOverChanged(DependencyObject elem, DependencyPropertyChangedEventArgs args)
+        {
+            var uiElement = elem as UIElement;
+            if (uiElement == null)
+                return;
+
+            uiElement.PreviewDragOver += OnDragOver;
+        }
+
+        private static void OnDragOver(object sender, DragEventArgs args)
+        {
+            var command = GetDragOverCommand((DependencyObject) sender);
+            if (command?.CanExecute(args) ?? false)
+            {
+                command.Execute(args);
+            }
+            else
+            {
+                args.Effects = DragDropEffects.None;
+                args.Handled = true;
+            }
         }

         private static void OnDropChanged(DependencyObject elem, DependencyPropertyChangedEventArgs args)
@@ -99,10 +148,14 @@
         {
             var command = GetDragLeaveCommand((DependencyObject)sender);
             if (command?.CanExecute(args) ?? false)
+            {
                 command.Execute(args);
+            }
             else
+            {
                 args.Effects = DragDropEffects.None;
-            args.Handled = true;
+                args.Handled = true;
+            }
         }

         private static void OnDragLeaveChanged(DependencyObject elem, DependencyPropertyChangedEventArgs args)


Move location of .asm output for new test compiler.

--- source2/Users/Kudzu/HelloWorld/Program.cs
+++ source2/Users/Kudzu/HelloWorld/Program.cs
@@ -25,10 +25,10 @@
       using (var xOldAsmblr = new CosmosAssembler(0)) {
         //InitializePlugs(aPlugs);
         xScanner.Execute(xEntryPoint);
+
 				var xPath = Path.GetDirectoryName(typeof(Program).Assembly.Location);
-				xPath = Path.Combine(xPath, "Output.asm");
-				using (var xOut = File.CreateText(xPath))
-				{
+				xPath = Path.Combine(xPath, @"..\..\Output.asm");
+				using (var xOut = File.CreateText(xPath)) {
 					xOldAsmblr.FlushText(xOut);
 				}
       }


fixed devil originfunc to be consistent with PixImage;

--- src/Aardvark.Base/Images/PixImageDevil.cs
+++ src/Aardvark.Base/Images/PixImageDevil.cs
@@ -19,7 +19,10 @@
             Bootstrap.Init();
             IL.Init();
             IL.Enable(EnableCap.OverwriteExistingFile);
+            IL.OriginFunc(OriginMode.UpperLeft);
+            IL.Enable(EnableCap.ConvertPalette);
             IL.Enable(EnableCap.AbsoluteOrigin);
+
         }

         private static Dictionary<Devil.ChannelFormat, Col.Format> s_pixColorFormats = new Dictionary<Devil.ChannelFormat, Col.Format>()


resolve #4560 Improve the constructor of UnitOfWork.

--- src/Abp/Domain/Uow/UnitOfWorkAttribute.cs
+++ src/Abp/Domain/Uow/UnitOfWorkAttribute.cs
@@ -145,6 +145,47 @@
             Timeout = TimeSpan.FromMilliseconds(timeout);
         }

+        /// <summary>
+        /// Creates a new <see cref="UnitOfWorkAttribute"/> object.
+        /// <see cref="IsTransactional"/> is automatically set to true.
+        /// </summary>
+        /// <param name="scope">Transaction scope</param>
+        /// <param name="isolationLevel">Transaction isolation level</param>
+        public UnitOfWorkAttribute(TransactionScopeOption scope, IsolationLevel isolationLevel)
+        {
+            IsTransactional = true;
+            Scope = scope;
+            IsolationLevel = isolationLevel;
+        }
+
+        /// <summary>
+        /// Creates a new <see cref="UnitOfWorkAttribute"/> object.
+        /// <see cref="IsTransactional"/> is automatically set to true.
+        /// </summary>
+        /// <param name="scope">Transaction scope</param>
+        /// <param name="isolationLevel">Transaction isolation level</param>
+        /// <param name="timeout">Transaction  timeout as milliseconds</param>
+        public UnitOfWorkAttribute(TransactionScopeOption scope, IsolationLevel isolationLevel, int timeout)
+        {
+            IsTransactional = true;
+            Scope = scope;
+            IsolationLevel = isolationLevel;
+            Timeout = TimeSpan.FromMilliseconds(timeout);
+        }
+
+        /// <summary>
+        /// Creates a new <see cref="UnitOfWorkAttribute"/> object.
+        /// </summary>
+        /// <param name="scope">Transaction scope</param>
+        /// <param name="isTransactional"/>
+        /// <param name="timeout">Transaction  timeout as milliseconds</param>
+        public UnitOfWorkAttribute(TransactionScopeOption scope, bool isTransactional, int timeout)
+        {
+            Scope = scope;
+            IsTransactional = isTransactional;
+            Timeout = TimeSpan.FromMilliseconds(timeout);
+        }
+
         internal UnitOfWorkOptions CreateOptions()
         {
             return new UnitOfWorkOptions


Eliminate reflection usage in DefaultHttpRequester

--- src/AngleSharp/Io/DefaultHttpRequester.cs
+++ src/AngleSharp/Io/DefaultHttpRequester.cs
@@ -4,7 +4,6 @@
     using AngleSharp.Text;
     using System;
     using System.Collections.Generic;
-    using System.Diagnostics;
     using System.Diagnostics.CodeAnalysis;
     using System.Globalization;
     using System.IO;
@@ -25,8 +24,6 @@

         private static readonly String Version = typeof(DefaultHttpRequester).Assembly.GetCustomAttribute<AssemblyFileVersionAttribute>().Version;
         private static readonly String AgentName = "AngleSharp/" + Version;
-        private static readonly Dictionary<String, PropertyInfo> PropCache = new Dictionary<String, PropertyInfo>();
-        private static readonly List<String> Restricted = new List<String>();

         #endregion

@@ -147,7 +144,7 @@

                 if (_request.Method == HttpMethod.Post || _request.Method == HttpMethod.Put)
                 {
-                    var target = await Task.Factory.FromAsync<Stream>(_http.BeginGetRequestStream, _http.EndGetRequestStream, null).ConfigureAwait(false);
+                    var target = await _http.GetRequestStreamAsync().ConfigureAwait(false);
                     SendRequest(target);
                 }

@@ -155,7 +152,7 @@

                 try
                 {
-                    response = await Task.Factory.FromAsync<WebResponse>(_http.BeginGetResponse, _http.EndGetResponse, null).ConfigureAwait(false);
+                    response = await _http.GetResponseAsync().ConfigureAwait(false);
                 }
                 catch (WebException ex)
                 {
@@ -183,7 +180,7 @@
                 }
             }

-            [return:NotNullIfNotNull("response")]
+            [return: NotNullIfNotNull("response")]
             private DefaultResponse? GetResponse(HttpWebResponse response)
             {
                 if (response != null)
@@ -250,27 +247,27 @@
                 }
                 else if (key.Is(HeaderNames.Expect))
                 {
-                    SetProperty(HeaderNames.Expect, value);
+                    _http.Expect = value;
                 }
                 else if (key.Is(HeaderNames.Date))
                 {
-                    SetProperty(HeaderNames.Date, DateTime.Parse(value, CultureInfo.InvariantCulture));
+                    _http.Date = DateTime.Parse(value, CultureInfo.InvariantCulture);
                 }
                 else if (key.Is(HeaderNames.Host))
                 {
-                    SetProperty(HeaderNames.Host, value);
+                    _http.Host = value;
                 }
                 else if (key.Is(HeaderNames.IfModifiedSince))
                 {
-                    SetProperty("IfModifiedSince", DateTime.Parse(value, CultureInfo.InvariantCulture));
+                    _http.IfModifiedSince = DateTime.Parse(value, CultureInfo.InvariantCulture);
                 }
                 else if (key.Is(HeaderNames.Referer))
                 {
-                    SetProperty(HeaderNames.Referer, value);
+                    _http.Referer = value;
                 }
                 else if (key.Is(HeaderNames.UserAgent))
                 {
-                    SetProperty("UserAgent", value);
+                    _http.UserAgent = value;
                 }
                 else if (!key.Is(HeaderNames.Connection) && !key.Is(HeaderNames.Range) && !key.Is(HeaderNames.ContentLength) && !key.Is(HeaderNames.TransferEncoding))
                 {
@@ -302,73 +299,18 @@

             private void AllowCompression()
             {
-                SetProperty("AutomaticDecompression", 3);
+                _http.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
             }

             private void DisableAutoRedirect()
             {
-                SetProperty("AllowAutoRedirect", false);
-            }
-
-            /// <summary>
-            /// Sets properties of the special headers (described here
-            /// http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.headers.aspx)
-            /// which are not accessible (in general) in this profile
-            /// (profile78). However, usually they are here and can be modified
-            /// with reflection. If not they are not set.
-            /// </summary>
-            /// <param name="name">The name of the property.</param>
-            /// <param name="value">
-            /// The value of the property, which will be set.
-            /// </param>
-            private void SetProperty(String name, Object value)
-            {
-                if (!PropCache.TryGetValue(name, out var property))
-                {
-                    lock (PropCache)
-                    {
-                        if (!PropCache.TryGetValue(name, out property))
-                        {
-                            property = _http.GetType().GetProperty(name);
-                            PropCache.Add(name, property);
-                        }
-                    }
-                }
-
-                if (!Restricted.Contains(name) && property != null && property.CanWrite)
-                {
-                    try
-                    {
-                        //This might fail on certain platforms
-                        property.SetValue(_http, value, null);
-                    }
-                    catch (Exception ex)
-                    {
-                        Debug.WriteLine("Exception while setting value on the HTTP requester: {0}", ex);
-
-                        //Catch any failure and do not try again on the same platform
-                        lock (Restricted)
-                        {
-                            if (!Restricted.Contains(name))
-                            {
-                                Restricted.Add(name);
-                            }
-                        }
-                    }
-                }
-            }
-        }
+                _http.AllowAutoRedirect = false;
+            }
+        }

         private static void RaiseConnectionLimit(HttpWebRequest http)
         {
-            var field = typeof(HttpWebRequest).GetField("_ServicePoint");
-            var servicePoint = field?.GetValue(http);
-
-            if (servicePoint != null)
-            {
-                var connectionLimit = servicePoint.GetType().GetProperty("ConnectionLimit");
-                connectionLimit?.SetValue(servicePoint, 1024, null);
-            }
+            http.ServicePoint.ConnectionLimit = 1024;
         }

         #endregion


BL-3019 Reinstate and fix broken tests for update table

--- src/BloomTests/UpdateVersionTableTests.cs
+++ src/BloomTests/UpdateVersionTableTests.cs
@@ -24,16 +24,27 @@
 			Assert.IsEmpty(t.LookupURLOfUpdate().URL);
 		}

-		[Test, Ignore("Broken by 253bc70c10c5304092c16efd51855c2278430269")]
-		public void LookupURLOfUpdate_AllWell_ReportsNoConnectivityError()
+		[Test]
+		public void LookupURLOfUpdate_NoLineForDesiredVersion_ReportsError()
 		{
 			var t = new UpdateVersionTable();
 			t.TextContentsOfTable = @"0.0.0,3.1.99999, http://first.com/first";
 			t.RunningVersion = Version.Parse("3.2.0");
 			var lookupResult = t.LookupURLOfUpdate();
+			Assert.IsNullOrEmpty(lookupResult.URL);
+			Assert.That(lookupResult.Error.Message, Is.EqualTo("http://bloomlibrary.org/channels/UpgradeTableTestChannel.txt contains no record for this version of Bloom"));
+		}
+
+		[Test]
+		public void LookupURLOfUpdate_AllWell_ReportsNoErrorAndReturnsUrl()
+		{
+			var t = new UpdateVersionTable();
+			t.TextContentsOfTable = @"0.0.0,3.2.99999, http://first.com/first";
+			t.RunningVersion = Version.Parse("3.2.0");
+			var lookupResult = t.LookupURLOfUpdate();
 			Assert.IsFalse(lookupResult.IsConnectivityError);
-			Assert.IsNullOrEmpty(lookupResult.Error.Message);
-			Assert.IsNullOrEmpty(lookupResult.URL);
+			Assert.IsNull(lookupResult.Error);
+			Assert.That(lookupResult.URL, Is.EqualTo("http://first.com/first"));
 		}

 		[Test]


Add a command line flag for adding a folder source.

Instead of constantly commenting / uncommenting the code to add a new
folder source, you can now use a command line flag to do this.

    mono FlashUnit.exe --add-foldersrc=file:///home/ruben/Pictures/

Or if you use the makefile:

    make run TRIPOD_DEV_OPTIONS="--add-foldersrc=file:///home/ruben/Pictures/tmp/"

--- src/Clients/FlashUnit/FlashUnit/Client.cs
+++ src/Clients/FlashUnit/FlashUnit/Client.cs
@@ -44,26 +44,17 @@
             Core.Initialize ("FlashUnit", ref args);

             Log.Information ("Hello World! Flash!");
-
-            //var main_window = new MainWindow ();
-            //main_window.Destroyed += (o, e) => Application.Quit ();
-            //main_window.Show ();
-
-            //Application.Run ();
-
-            //var cache = new MainCachePhotoSource ();
-            //cache.Start ();
-
-            Log.Debug ("Main cache started");

             var main_window = new MainWindow ();
             main_window.Destroyed += (o, e) => Application.Quit ();
             main_window.Show ();

+            if (ApplicationContext.CommandLine ["add-foldersrc"] != String.Empty) {
+                var source = new LocalFolderPhotoSource (new Uri (ApplicationContext.CommandLine ["add-foldersrc"]));
+                Core.MainCachePhotoSource.RegisterPhotoSource (source);
+            }
+
             Application.Run ();
-
-            //var source = new LocalFolderPhotoSource (new Uri("file:///home/mike/Pictures/"));
-            //Core.MainCachePhotoSource.RegisterPhotoSource (source);

 /*            var t = Log.DebugTimerStart();
             Log.DebugTimerPrint(t, "starting");


Reverting back superflous check

Reverting back superflous check

--- src/CommandLine/ParserResultExtensions.cs
+++ src/CommandLine/ParserResultExtensions.cs
@@ -24,10 +24,7 @@
             var parsed = result as Parsed<T>;
             if (parsed != null)
             {
-                if (parsed.Value is T)
-                {
-                    action(parsed.Value);
-                }
+                action(parsed.Value);
             }
             return result;
         }
@@ -65,10 +62,7 @@
             var notParsed = result as NotParsed<T>;
             if (notParsed != null)
             {
-                if (notParsed.Value is T)
-                {
-                    action(notParsed.Errors);
-                }
+                action(notParsed.Errors);
             }
             return result;
         }


updated values for enum

updated values for enum

--- src/Core/HubSpotAssociationDefinitions.cs
+++ src/Core/HubSpotAssociationDefinitions.cs
@@ -6,53 +6,83 @@
 {
     public enum HubSpotAssociationDefinitions
     {
-        CompanyToCompany = 1,

-        CompanyToContact,
+        ContactToCompany = 1,

-        DealToContact,
+        CompanyToContact = 2,

-        ContactToDeal,
+        DealToContact = 3,

-        DealToCompany,
+        ContactToDeal = 4,

-        CompanyToDeal,
+        DealToCompany = 5,

-        CompanyToEngagement,
+        CompanyToDeal = 6,

-        EngagementToCompany,
+        CompanyToEngagement = 7,

-        ContactToEngagement,
+        EngagementToCompany = 8,

-        EngagementToContact,
+        ContactToEngagement = 9,

-        DealToEngagement,
+        EngagementToContact = 10,

-        EngagementToDeal,
+        DealToEngagement = 11,

+        EngagementToDeal = 12,

-        ParentCompanyToChildCompany,
+        ParentCompanyToChildCompany = 13,

-        ChildCompanyToParentCompany,
+        ChildCompanyToParentCompany = 14,

-        ContactToTicket,
+        ContactToTicket = 15,

-        TicketToContact,
-
-        TicketToEngagement,
+        TicketToContact = 16,

-        EngagementToTicket,
+        TicketToEngagement = 17,

-        DealToLineItem,
+        EngagementToTicket = 18,

-        LineItemToDeal,
+        DealToLineItem = 19,
+
+        LineItemToDeal = 20,

         CompanyToTicket = 25,

-        TicketToCompany,
+        TicketToCompany = 26,

-        DealToTicket,
-
-        TicketToDeal
+        DealToTicket = 27,
+
+        TicketToDeal = 28,
+
+        // special contact associations
+
+        AdvisorToCompany = 33,
+
+        CompanyToAdvisor = 34,
+
+        BoardMemberToCompany = 35,
+
+        CompanyToBoardMember = 36,
+
+        ContractorToCompany = 37,
+
+        CompanyToContractor = 38,
+
+        ManagerToCompany = 39,
+
+        CompanyToManager = 40,
+
+        BusinessOwnerToCompany = 41,
+
+        CompanyToBusinessOwner = 42,
+
+        PartnerToCompany = 43,
+
+        CompanyToPartner = 44,
+
+        ResellerToCompany = 45,
+
+        CompanyToReseller = 46
     }
 }


fix font select bug

fix font select bug

--- src/DiabloInterface/Gui/SettingsWindow.cs
+++ src/DiabloInterface/Gui/SettingsWindow.cs
@@ -269,8 +269,18 @@
             // Get the item text
             string text = ((ComboBox)sender).Items[e.Index].ToString();

+            Font fSender = ((Control)sender).Font;
+            Font f;
+            try
+            {
+                f = new Font(text, 10f, fSender.Style);
+            } catch
+            {
+                f = fSender;
+            }
+
             // Draw the text
-            e.Graphics.DrawString(text, new Font(text, 10f), Brushes.Black, e.Bounds.X, e.Bounds.Y);
+            e.Graphics.DrawString(text, f, Brushes.Black, e.Bounds.X, e.Bounds.Y);
         }
     }


Reordering a channel only modifies channels of the same type.

--- src/Discord.Net/DiscordClient.Channels.cs
+++ src/Discord.Net/DiscordClient.Channels.cs
@@ -157,7 +157,7 @@
 				int oldPos = channel.Position;
 				int newPos = position.Value;
 				int minPos;
-				Channel[] channels = channel.Server.Channels.OrderBy(x => x.Position).ToArray();
+				Channel[] channels = channel.Server.Channels.Where(x => x.Type == channel.Type).OrderBy(x => x.Position).ToArray();

 				if (oldPos < newPos) //Moving Down
 				{


Update WeeklyXamarin.cs

Update WeeklyXamarin.cs

--- src/Firehose.Web/Authors/WeeklyXamarin.cs
+++ src/Firehose.Web/Authors/WeeklyXamarin.cs
@@ -14,7 +14,7 @@

         public string EmailAddress => "inbox@weeklyxamarin.com";

-        public string Title => "Newsletter";
+        public string Title => "newsletter that contains a weekly hand-picked round up of the best development links. Curated by Geoffrey Huntley";

         public Uri WebSite => new Uri("https://www.weeklyxamarin.com");


Delete ObjectOffsetController.cs

Delete ObjectOffsetController.cs

--- ObjectOffsetController.cs
+++ ObjectOffsetController.cs
@@ -1,15 +0,0 @@
-using UnityEngine;
-using System.Collections;
-
-public class ObjectOffsetController : MonoBehaviour {
-
-	void Awake () {
-        InteractiveObjectController parent = GetComponentInParent<InteractiveObjectController>();
-        parent.offsetPoint = this.transform;
-        parent.offsetStatus = true;
-    }
-
-	void Update () {
-
-    }
-}


chore(*): makes internals visible to test assembly

--- src/GitIgnorer/Properties/AssemblyInfo.cs
+++ src/GitIgnorer/Properties/AssemblyInfo.cs
@@ -34,3 +34,4 @@
 // [assembly: AssemblyVersion("1.0.*")]
 [assembly: AssemblyVersion("1.0.0.0")]
 [assembly: AssemblyFileVersion("1.0.0.0")]
+[assembly: InternalsVisibleTo("GitIgnorer.Tests")]


removed extra line break

removed extra line break

--- src/Handyman.Extensions/TypeExtensions.cs
+++ src/Handyman.Extensions/TypeExtensions.cs
@@ -21,7 +21,6 @@
             IReadOnlyCollection<Type> types;
             return type.IsConcreteClassClosing(genericTypeDefinition, out types);
         }
-

         public static bool IsConcreteClassClosing(this Type type, Type genericTypeDefinition, out IReadOnlyCollection<Type> genericTypes)
         {


Changed DefaultPrinter default to null and check before assigning to the printer settings.

--- PdfiumViewer/PdfViewer.cs
+++ PdfiumViewer/PdfViewer.cs
@@ -96,7 +96,7 @@
         /// Gets or sets the pre-selected printer to be used when the print
         /// dialog shows up.
         /// </summary>
-        [DefaultValue("")]
+        [DefaultValue(null)]
         public string DefaultPrinter { get; set; }

         /// <summary>
@@ -203,7 +203,8 @@
                 form.UseEXDialog = true;
                 form.Document.PrinterSettings.FromPage = 1;
                 form.Document.PrinterSettings.ToPage = _document.PageCount;
-                form.Document.PrinterSettings.PrinterName = DefaultPrinter;
+                if (DefaultPrinter != null)
+                    form.Document.PrinterSettings.PrinterName = DefaultPrinter;

                 if (form.ShowDialog(FindForm()) == DialogResult.OK)
                 {


beginning new mesh algo

beginning new mesh algo

--- src/IntraLattice/CORE/Mesh/LatticeMesh.cs
+++ src/IntraLattice/CORE/Mesh/LatticeMesh.cs
@@ -69,12 +69,13 @@
             //====================================================================================

             // Initialize lists of objects
-            List<LatticePlate> plates = new List<LatticePlate>();
+            List<LatticePlate> struts = new List<LatticePlate>();
             List<LatticeNode> nodes = new List<LatticeNode>();
-            // To avoid creating duplicates nodes, this list stores which nodes have been created
-            Point3dList nodeLookup = new Point3dList();
-
+
             // Cycle through all the struts, building the model as we go
+            // - No duplicate nodes are created
+            // - No duplicate struts are created
+            Point3dList nodeLookup = new Point3dList(); // To avoid creating duplicates nodes
             for (int i = 0; i < lineList.Count; i++)
             {
                 // Define plates for current strut
@@ -90,6 +91,7 @@
                 pts.Add(lineList[i].From); pts.Add(lineList[i].To);   // Start point first

                 // Loops over the 2 nodes, updating the lattice model
+                bool strutExists = true;
                 for (int j = 0; j < 2; j++)
                 {
                     int nodeIndex;


fix: ServiceLocator related stability.

fix: ServiceLocator related stability.


fix(controls): #4210 recalculate sizes for all RangeSlider visuals

--- src/MahApps.Metro/Controls/RangeSlider.cs
+++ src/MahApps.Metro/Controls/RangeSlider.cs
@@ -849,6 +849,7 @@
         private int _precision;
         private readonly PropertyChangeNotifier actualWidthPropertyChangeNotifier;
         private readonly PropertyChangeNotifier actualHeightPropertyChangeNotifier;
+        private readonly PropertyChangeNotifier visibilityPropertyChangeNotifier;

         #endregion

@@ -863,6 +864,14 @@
             this.actualWidthPropertyChangeNotifier.ValueChanged += (_, _) => this.ReCalculateSize();
             this.actualHeightPropertyChangeNotifier = new PropertyChangeNotifier(this, ActualHeightProperty);
             this.actualHeightPropertyChangeNotifier.ValueChanged += (_, _) => this.ReCalculateSize();
+            this.visibilityPropertyChangeNotifier = new PropertyChangeNotifier(this, VisibilityProperty);
+            this.visibilityPropertyChangeNotifier.ValueChanged += (_, _) =>
+                {
+                    if (this.IsVisible)
+                    {
+                        this.ReCalculateSize();
+                    }
+                };

             this._timer = new DispatcherTimer();
             this._timer.Tick += this.MoveToNextValue;


(GH-3513) Code formatting and handle IsEnabled property from inner button.

--- src/MahApps.Metro/Controls/SplitButton.cs
+++ src/MahApps.Metro/Controls/SplitButton.cs
@@ -16,11 +16,8 @@
     [TemplatePart(Name = "PART_Expander", Type = typeof(Button))]
     public class SplitButton : ComboBox
     {
-        private Button _clickButton;
-        private Button _expander;
-
         public static readonly RoutedEvent ClickEvent
-            = EventManager.RegisterRoutedEvent("Click",
+            = EventManager.RegisterRoutedEvent(nameof(Click),
                                                RoutingStrategy.Bubble,
                                                typeof(RoutedEventHandler),
                                                typeof(SplitButton));
@@ -31,22 +28,104 @@
             remove { this.RemoveHandler(ClickEvent, value); }
         }

-        public static readonly DependencyProperty ExtraTagProperty = DependencyProperty.Register("ExtraTag", typeof(object), typeof(SplitButton));
-
-        public static readonly DependencyProperty OrientationProperty = DependencyProperty.Register("Orientation", typeof(Orientation), typeof(SplitButton), new FrameworkPropertyMetadata(Orientation.Horizontal, FrameworkPropertyMetadataOptions.AffectsMeasure));
-
-        public static readonly DependencyProperty IconProperty = DependencyProperty.Register("Icon", typeof(object), typeof(SplitButton));
-        public static readonly DependencyProperty IconTemplateProperty = DependencyProperty.Register("IconTemplate", typeof(DataTemplate), typeof(SplitButton));
-
-        public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command", typeof(ICommand), typeof(SplitButton));
-        public static readonly DependencyProperty CommandTargetProperty = DependencyProperty.Register("CommandTarget", typeof(IInputElement), typeof(SplitButton));
-        public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register("CommandParameter", typeof(object), typeof(SplitButton));
-
-        public static readonly DependencyProperty ButtonStyleProperty = DependencyProperty.Register("ButtonStyle", typeof(Style), typeof(SplitButton), new FrameworkPropertyMetadata(default(Style), FrameworkPropertyMetadataOptions.Inherits | FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure));
-        public static readonly DependencyProperty ButtonArrowStyleProperty = DependencyProperty.Register("ButtonArrowStyle", typeof(Style), typeof(SplitButton), new FrameworkPropertyMetadata(default(Style), FrameworkPropertyMetadataOptions.Inherits | FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure));
-        public static readonly DependencyProperty ArrowBrushProperty = DependencyProperty.Register("ArrowBrush", typeof(Brush), typeof(SplitButton), new FrameworkPropertyMetadata(default(Brush), FrameworkPropertyMetadataOptions.AffectsRender));
-        public static readonly DependencyProperty ArrowMouseOverBrushProperty = DependencyProperty.Register("ArrowMouseOverBrush", typeof(Brush), typeof(SplitButton), new FrameworkPropertyMetadata(default(Brush), FrameworkPropertyMetadataOptions.AffectsRender));
-        public static readonly DependencyProperty ArrowPressedBrushProperty = DependencyProperty.Register("ArrowPressedBrush", typeof(Brush), typeof(SplitButton), new FrameworkPropertyMetadata(default(Brush), FrameworkPropertyMetadataOptions.AffectsRender));
+        public static readonly DependencyProperty ExtraTagProperty
+            = DependencyProperty.Register(
+                nameof(ExtraTag),
+                typeof(object),
+                typeof(SplitButton));
+
+        /// <summary>
+        /// Gets or sets an extra tag.
+        /// </summary>
+        public object ExtraTag
+        {
+            get { return this.GetValue(ExtraTagProperty); }
+            set { this.SetValue(ExtraTagProperty, value); }
+        }
+
+        public static readonly DependencyProperty OrientationProperty
+            = DependencyProperty.Register(
+                nameof(Orientation),
+                typeof(Orientation),
+                typeof(SplitButton),
+                new FrameworkPropertyMetadata(Orientation.Horizontal, FrameworkPropertyMetadataOptions.AffectsMeasure));
+
+        /// <summary>
+        /// Gets or sets the orientation of children stacking.
+        /// </summary>
+        public Orientation Orientation
+        {
+            get { return (Orientation)this.GetValue(OrientationProperty); }
+            set { this.SetValue(OrientationProperty, value); }
+        }
+
+        public static readonly DependencyProperty IconProperty
+            = DependencyProperty.Register(
+                nameof(Icon),
+                typeof(object),
+                typeof(SplitButton));
+
+        /// <summary>
+        ///  Gets or sets the Content used to generate the icon part.
+        /// </summary>
+        [Bindable(true)]
+        public object Icon
+        {
+            get { return this.GetValue(IconProperty); }
+            set { this.SetValue(IconProperty, value); }
+        }
+
+        public static readonly DependencyProperty IconTemplateProperty
+            = DependencyProperty.Register(
+                nameof(IconTemplate),
+                typeof(DataTemplate),
+                typeof(SplitButton));
+
+        /// <summary>
+        /// Gets or sets the ContentTemplate used to display the content of the icon part.
+        /// </summary>
+        [Bindable(true)]
+        public DataTemplate IconTemplate
+        {
+            get { return (DataTemplate)this.GetValue(IconTemplateProperty); }
+            set { this.SetValue(IconTemplateProperty, value); }
+        }
+
+        public static readonly DependencyProperty CommandProperty
+            = DependencyProperty.Register(
+                nameof(Command),
+                typeof(ICommand),
+                typeof(SplitButton));
+
+        /// <summary>
+        /// Get or sets the Command property.
+        /// </summary>
+        public ICommand Command
+        {
+            get { return (ICommand)this.GetValue(CommandProperty); }
+            set { this.SetValue(CommandProperty, value); }
+        }
+
+        public static readonly DependencyProperty CommandTargetProperty
+            = DependencyProperty.Register(
+                nameof(CommandTarget),
+                typeof(IInputElement),
+                typeof(SplitButton));
+
+        /// <summary>
+        /// Gets or sets the target element on which to fire the command.
+        /// </summary>
+        public IInputElement CommandTarget
+        {
+            get { return (IInputElement)this.GetValue(CommandTargetProperty); }
+            set { this.SetValue(CommandTargetProperty, value); }
+        }
+
+        public static readonly DependencyProperty CommandParameterProperty
+            = DependencyProperty.Register(
+                nameof(CommandParameter),
+                typeof(object),
+                typeof(SplitButton));

         /// <summary>
         /// Reflects the parameter to pass to the CommandProperty upon execution.
@@ -57,61 +136,12 @@
             set { this.SetValue(CommandParameterProperty, value); }
         }

-        /// <summary>
-        /// Gets or sets the target element on which to fire the command.
-        /// </summary>
-        public IInputElement CommandTarget
-        {
-            get { return (IInputElement)this.GetValue(CommandTargetProperty); }
-            set { this.SetValue(CommandTargetProperty, value); }
-        }
-
-        /// <summary>
-        /// Get or sets the Command property.
-        /// </summary>
-        public ICommand Command
-        {
-            get { return (ICommand)this.GetValue(CommandProperty); }
-            set { this.SetValue(CommandProperty, value); }
-        }
-
-        /// <summary>
-        /// Gets or sets an extra tag.
-        /// </summary>
-        public object ExtraTag
-        {
-            get { return this.GetValue(ExtraTagProperty); }
-            set { this.SetValue(ExtraTagProperty, value); }
-        }
-
-        /// <summary>
-        /// Gets or sets the dimension of children stacking.
-        /// </summary>
-        public Orientation Orientation
-        {
-            get { return (Orientation)this.GetValue(OrientationProperty); }
-            set { this.SetValue(OrientationProperty, value); }
-        }
-
-        /// <summary>
-        ///  Gets or sets the Content used to generate the icon part.
-        /// </summary>
-        [Bindable(true)]
-        public object Icon
-        {
-            get { return this.GetValue(IconProperty); }
-            set { this.SetValue(IconProperty, value); }
-        }
-
-        /// <summary>
-        /// Gets or sets the ContentTemplate used to display the content of the icon part.
-        /// </summary>
-        [Bindable(true)]
-        public DataTemplate IconTemplate
-        {
-            get { return (DataTemplate)this.GetValue(IconTemplateProperty); }
-            set { this.SetValue(IconTemplateProperty, value); }
-        }
+        public static readonly DependencyProperty ButtonStyleProperty
+            = DependencyProperty.Register(
+                nameof(ButtonStyle),
+                typeof(Style),
+                typeof(SplitButton),
+                new FrameworkPropertyMetadata(default(Style), FrameworkPropertyMetadataOptions.Inherits | FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure));

         /// <summary>
         /// Gets/sets the button style.
@@ -122,6 +152,13 @@
             set { this.SetValue(ButtonStyleProperty, value); }
         }

+        public static readonly DependencyProperty ButtonArrowStyleProperty
+            = DependencyProperty.Register(
+                nameof(ButtonArrowStyle),
+                typeof(Style),
+                typeof(SplitButton),
+                new FrameworkPropertyMetadata(default(Style), FrameworkPropertyMetadataOptions.Inherits | FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure));
+
         /// <summary>
         /// Gets/sets the button arrow style.
         /// </summary>
@@ -131,6 +168,13 @@
             set { this.SetValue(ButtonArrowStyleProperty, value); }
         }

+        public static readonly DependencyProperty ArrowBrushProperty
+            = DependencyProperty.Register(
+                nameof(ArrowBrush),
+                typeof(Brush),
+                typeof(SplitButton),
+                new FrameworkPropertyMetadata(default(Brush), FrameworkPropertyMetadataOptions.AffectsRender));
+
         /// <summary>
         /// Gets/sets the brush of the button arrow icon.
         /// </summary>
@@ -140,6 +184,13 @@
             set { this.SetValue(ArrowBrushProperty, value); }
         }

+        public static readonly DependencyProperty ArrowMouseOverBrushProperty
+            = DependencyProperty.Register(
+                nameof(ArrowMouseOverBrush),
+                typeof(Brush),
+                typeof(SplitButton),
+                new FrameworkPropertyMetadata(default(Brush), FrameworkPropertyMetadataOptions.AffectsRender));
+
         /// <summary>
         /// Gets/sets the brush of the button arrow icon if the mouse is over the split button.
         /// </summary>
@@ -148,6 +199,13 @@
             get { return (Brush)this.GetValue(ArrowMouseOverBrushProperty); }
             set { this.SetValue(ArrowMouseOverBrushProperty, value); }
         }
+
+        public static readonly DependencyProperty ArrowPressedBrushProperty
+            = DependencyProperty.Register(
+                nameof(ArrowPressedBrush),
+                typeof(Brush),
+                typeof(SplitButton),
+                new FrameworkPropertyMetadata(default(Brush), FrameworkPropertyMetadataOptions.AffectsRender));

         /// <summary>
         /// Gets/sets the brush of the button arrow icon if the arrow button is pressed.
@@ -187,26 +245,38 @@
         public override void OnApplyTemplate()
         {
             base.OnApplyTemplate();
-            this._clickButton = this.EnforceInstance<Button>("PART_Button");
-            this._expander = this.EnforceInstance<Button>("PART_Expander");
-            this.InitializeVisualElementsContainer();
-        }
-
-        private void InitializeVisualElementsContainer()
-        {
-            this._expander.PreviewMouseLeftButtonDown -= this.ExpanderMouseLeftButtonDown;
-            this._expander.PreviewMouseLeftButtonDown += this.ExpanderMouseLeftButtonDown;
-
-            this._clickButton.Click -= this.ButtonClick;
-            this._clickButton.Click += this.ButtonClick;
-        }
-
-        //Get element from name. If it exist then element instance return, if not, new will be created
-        private T EnforceInstance<T>(string partName)
-            where T : FrameworkElement, new()
-        {
-            T element = this.GetTemplateChild(partName) as T ?? new T();
-            return element;
-        }
+
+            if (this._clickButton != null)
+            {
+                this._clickButton.Click -= this.ButtonClick;
+                this._clickButton.IsEnabledChanged -= this.ButtonIsEnabledChanged;
+            }
+
+            this._clickButton = this.GetTemplateChild("PART_Button") as Button;
+            if (this._clickButton != null)
+            {
+                this._clickButton.Click += this.ButtonClick;
+                this._clickButton.IsEnabledChanged += this.ButtonIsEnabledChanged;
+            }
+
+            if (this._expander != null)
+            {
+                this._expander.PreviewMouseLeftButtonDown -= this.ExpanderMouseLeftButtonDown;
+            }
+
+            this._expander = this.GetTemplateChild("PART_Expander") as Button;
+            if (this._expander != null)
+            {
+                this._expander.PreviewMouseLeftButtonDown += this.ExpanderMouseLeftButtonDown;
+            }
+        }
+
+        private void ButtonIsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
+        {
+            this.SetCurrentValue(IsEnabledProperty, e.NewValue);
+        }
+
+        private Button _clickButton;
+        private Button _expander;
     }
 }


Command knows its command resolution strategy

A command may be resolved from a nuget package, from the executing
assembly directory, or from the path.

--- src/Microsoft.DotNet.Cli.Utils/Command.cs
+++ src/Microsoft.DotNet.Cli.Utils/Command.cs
@@ -21,9 +21,24 @@
         private readonly StreamForwarder _stdOut;
         private readonly StreamForwarder _stdErr;

+        public enum CommandResolutionStrategy
+        {
+            //command loaded from a nuget package
+            NugetPackage,
+
+            //command loaded from the same directory as the executing assembly
+            BaseDirectory,
+
+            //command loaded from path
+            Path,
+
+            //command not found
+            None
+        }
+
         private bool _running = false;

-        private Command(string executable, string args)
+        private Command(string executable, string args, CommandResolutionStrategy commandResolution)
         {
             // Set the things we need
             var psi = new ProcessStartInfo()
@@ -41,6 +56,8 @@

             _stdOut = new StreamForwarder();
             _stdErr = new StreamForwarder();
+
+            CommandResolution = commandResolution;
         }

         public static Command Create(string executable, IEnumerable<string> args, NuGetFramework framework = null)
@@ -50,20 +67,25 @@

         public static Command Create(string executable, string args, NuGetFramework framework = null)
         {
-            ResolveExecutablePath(ref executable, ref args, framework);
-
-            return new Command(executable, args);
-        }
-
-        private static void ResolveExecutablePath(ref string executable, ref string args, NuGetFramework framework = null)
+
+            var commandResolution = CommandResolutionStrategy.None;
+
+            ResolveExecutablePath(ref executable, ref args, ref commandResolution, framework);
+
+            return new Command(executable, args, commandResolution);
+        }
+
+        private static void ResolveExecutablePath(ref string executable, ref string args, ref CommandResolutionStrategy commandResolution, NuGetFramework framework = null)
         {
             executable =
-                ResolveExecutablePathFromProject(executable, framework) ??
-                ResolveExecutableFromPath(executable, ref args);
-        }
-
-        private static string ResolveExecutableFromPath(string executable, ref string args)
-        {
+                ResolveExecutablePathFromProject(executable, framework, ref commandResolution) ??
+                ResolveExecutableFromPath(executable, ref args, ref commandResolution);
+        }
+
+        private static string ResolveExecutableFromPath(string executable, ref string args, ref CommandResolutionStrategy commandResolution)
+        {
+            commandResolution = CommandResolutionStrategy.Path;
+
             foreach (string suffix in Constants.RunnableSuffixes)
             {
                 var fullExecutable = Path.GetFullPath(Path.Combine(
@@ -72,6 +94,8 @@
                 if (File.Exists(fullExecutable))
                 {
                     executable = fullExecutable;
+
+                    commandResolution = CommandResolutionStrategy.BaseDirectory;

                     // In priority order we've found the best runnable extension, so break.
                     break;
@@ -93,7 +117,7 @@
             return executable;
         }

-        private static string ResolveExecutablePathFromProject(string executable, NuGetFramework framework)
+        private static string ResolveExecutablePathFromProject(string executable, NuGetFramework framework, ref CommandResolutionStrategy commandResolution)
         {
             if (framework == null) return null;

@@ -124,6 +148,8 @@

             var commandPath = commandPackage.Library.Files
                 .First(f => Path.GetFileName(f) == commandName + FileNameSuffixes.DotNet.Exe);
+
+            commandResolution = CommandResolutionStrategy.NugetPackage;

             return Path.Combine(projectContext.PackagesDirectory, commandPackage.Path, commandPath);
         }
@@ -286,6 +312,8 @@
             return this;
         }

+        public CommandResolutionStrategy CommandResolution { get; }
+
         private string FormatProcessInfo(ProcessStartInfo info)
         {
             if (string.IsNullOrWhiteSpace(info.Arguments))


Fix namespace

Fix namespace

--- src/Microsoft.DotNet.Tools.Run/Program.cs
+++ src/Microsoft.DotNet.Tools.Run/Program.cs
@@ -8,7 +8,7 @@
 using Microsoft.Extensions.ProjectModel;
 using NuGet.Frameworks;

-namespace Microsoft.DotNet.Tools.Compiler
+namespace Microsoft.DotNet.Tools.Run
 {
     public class Program
     {