more work on the browser automation task. but i need to convert it to the winforms one cause lol it's better suited for what i want to do

--- RelhaxModpack/RelhaxModpack/Automation/DownloadBrowserTask.cs
+++ RelhaxModpack/RelhaxModpack/Automation/DownloadBrowserTask.cs
@@ -1,9 +1,17 @@
-using RelhaxModpack.Database;
+using HtmlAgilityPack;
+using RelhaxModpack.Database;
+using RelhaxModpack.Utilities;
+using RelhaxModpack.Utilities.Enums;
 using System;
 using System.Collections.Generic;
 using System.Linq;
+using System.Net;
+using System.Reflection;
 using System.Text;
 using System.Threading.Tasks;
+using System.Windows.Controls;
+using System.Windows.Threading;
+
 namespace RelhaxModpack.Automation
 {
     public class DownloadBrowserTask : DownloadHtmlTask, IDownloadTask, IXmlSerializable
@@ -13,6 +21,16 @@
         public int Retries { get; } = 3;

         public override string Command { get; } = "download_browser";
+
+        protected WebBrowser Browser = null;
+
+        public Dispatcher BrowserDispatcher = null;
+
+        protected string HtmlString = null;
+
+        protected int BrowserFinishedLoadingScriptsCounter = 0;
+
+        protected bool BrowserLoaded = false;

         #region Xml serialization
         public override string[] PropertiesForSerializationAttributes()
@@ -24,17 +42,99 @@
         #region Task execution
         public override void ValidateCommands()
         {
-            throw new NotImplementedException();
+            base.ValidateCommands();
+            if (WaitTimeMs <= 0)
+            {
+                ExitCode = 1;
+                ErrorMessage = string.Format("ExitCode {0}: WaitTimeMs must be greater then 0. Current value: {1}", ExitCode, WaitTimeMs.ToString());
+                Logging.Error(Logfiles.AutomationRunner, LogOptions.MethodName, ErrorMessage);
+                return;
+            }
+            if (Retries <= 0)
+            {
+                ExitCode = 1;
+                ErrorMessage = string.Format("ExitCode {0}: Retries must be greater then 0. Current value: {1}", ExitCode, Retries.ToString());
+                Logging.Error(Logfiles.AutomationRunner, LogOptions.MethodName, ErrorMessage);
+                return;
+            }
         }

-        public override Task RunTask()
+        public async override Task RunTask()
         {
-            throw new NotImplementedException();
+            //add registry entry to use latest IE for script parsing
+            Logging.AutomationRunner("Setting application to use latest version of IE for embedded browser", LogLevel.Debug);
+            RegistryUtils.SetRegisterKeyForIEVersion(IERegistryVersion.IE11Forced);
+
+            Logging.AutomationRunner("Running Browser execution code");
+            await RunBrowserAsync();
+
+            //parse html from the browser
+            Logging.Info(Logfiles.AutomationRunner, "Running htmlpath to get download file url");
+            Logging.Debug(Logfiles.AutomationRunner, "The htmlpath used was {0}", HtmlPath);
+            HtmlDocument document = new HtmlDocument();
+            document.LoadHtml(HtmlString);
+            HtmlNode node = document.DocumentNode;
+            //https://stackoverflow.com/questions/1390568/how-can-i-match-on-an-attribute-that-contains-a-certain-string
+            //sample html xpath: //div[contains(@class, 'ModDetails_label')]
+            HtmlNode resultNode = node.SelectSingleNode(HtmlPath);
+            Logging.Debug(Logfiles.AutomationRunner, "Htmlpath results in node value '{0}' of type '{1}'", resultNode.InnerText, resultNode.NodeType.ToString());
+            Url = resultNode.InnerText;
+
+            Logging.AutomationRunner("Using DownloadStaticTask explicit cast to invoke RunTask()", LogLevel.Debug);
+            (this as DownloadStaticTask).RunTask();
+        }
+
+        protected async Task RunBrowserAsync()
+        {
+            Dispatcher dispatcher = this.BrowserDispatcher == null ? App.Current.Dispatcher : this.BrowserDispatcher;
+            await dispatcher.Invoke(RunBrowserRealAsync);
+        }
+
+        protected async Task RunBrowserRealAsync()
+        {
+            using (Browser = new WebBrowser())
+            {
+                //set event handler for browser to be done loading
+                Logging.Debug(Logfiles.AutomationRunner, "Setting browser loadCompleted event handler");
+                Browser.LoadCompleted += (sendahh, endArgs) =>
+                {
+                    Logging.Debug(Logfiles.AutomationRunner, "The browser reports load completed");
+                    BrowserLoaded = true;
+                };
+
+                Browser.Navigating += (sendahh, endArgs) =>
+                {
+                    //suppress script errors message window
+                    Logging.Debug(Logfiles.AutomationRunner, "Setting browser script suppression");
+                    //https://stackoverflow.com/questions/1298255/how-do-i-suppress-script-errors-when-using-the-wpf-webbrowser-control
+                    dynamic activeX = this.Browser.GetType().InvokeMember("ActiveXInstance", BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.NonPublic,
+                        null, this.Browser, new object[] { });
+                    activeX.Silent = true;
+                };
+
+                //run browser enough to get scripts parsed to get download link
+                Logging.Debug(Logfiles.AutomationRunner, "Running async task to load browser and wait for it to finish");
+                bool temp = Browser.IsInitialized;
+                Browser.BeginInit();
+                Browser.EndInit();
+                Browser.Navigate(Url);
+
+                //this wait allows the browser to finish loading external scripts
+                while (!((BrowserFinishedLoadingScriptsCounter >= 3) && BrowserLoaded))
+                {
+                    await Task.Delay(WaitTimeMs);
+                    Logging.Debug(Logfiles.AutomationRunner, "The browser task delay has elapsed, BrowserLoadingCounter is set to {0}", ++BrowserFinishedLoadingScriptsCounter);
+                }
+
+                Logging.Info(Logfiles.AutomationRunner, "The browser reports that the task loading is done, save html to string");
+                var doc = Browser.Document as mshtml.HTMLDocument;
+                HtmlString = doc.body.outerHTML;
+            }
         }

         public override void ProcessTaskResults()
         {
-            throw new NotImplementedException();
+            base.ProcessTaskResults();
         }
         #endregion
     }


Updating work in progress

Updating work in progress

--- WebInput/WebInput.cs
+++ WebInput/WebInput.cs
@@ -42,7 +42,7 @@
             set
             {
                 _connectedUsers = value;
-                MyForm.ConnectedUserCount.Text = String.Format("Connected Users: {0}", _connectedUsers);
+                MyForm.ConnectedUserCount.Text = String.Format("Connected Users: {0}", value);
             }
         }

@@ -70,28 +70,6 @@
             this.Resize += new EventHandler(frmWebInput_Resize);
             this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.frmWebInput_FormClosing);

-        }
-
-        /**
-         * Set the window state
-         * @param string newState the new window state
-         */
-        public static void setWindowState(string newState)
-        {
-            frmWebInput frmWebInput = new frmWebInput();
-
-            if (newState == "minimize")
-            {
-                frmWebInput.WindowState = FormWindowState.Minimized;
-            }
-            else if (newState == "maximize")
-            {
-                frmWebInput.WindowState = FormWindowState.Maximized;
-            }
-            else
-            {
-                frmWebInput.WindowState = FormWindowState.Normal;
-            }
         }

         /**
@@ -116,7 +94,7 @@
                     lblIP.Text = "http://" + LocalIPAddress() + ":" + port;
                     lblIP.Visible = true;

-                    connectedUsers = connectedUsers;
+                    connectedUsers = 0;
                     ConnectedUserCount.Visible = true;
                 }
                 catch (HttpListenerException Ex)
@@ -211,7 +189,7 @@
                     connectedUsers = connectedUsers + 1;

                     QRCode.Close();
-                    WebInput.frmWebInput.setWindowState("minimize");
+                    MyForm.WindowState = FormWindowState.Minimized;
                 }

                 /**


PlgConfig: dev2

PlgConfig: dev2

--- ScadaWeb/OpenPlugins/PlgConfig/plugins/Config/Plugins.aspx.cs
+++ ScadaWeb/OpenPlugins/PlgConfig/plugins/Config/Plugins.aspx.cs
@@ -26,6 +26,9 @@
 using Scada.UI;
 using System;
 using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Web.UI.WebControls;

 namespace Scada.Web.Plugins.Config
 {
@@ -49,32 +52,61 @@
             /// </summary>
             Active,
             /// <summary>
-            /// Активен, но не загружен
-            /// </summary>
-            ActiveNotLoaded
+            /// Не удалось загрузить
+            /// </summary>
+            NotLoaded
         }

         /// <summary>
         /// Элемент списка плагинов
         /// </summary>
-        protected class PluginItem
-        {
+        protected class PluginItem : IComparable<PluginItem>
+        {
+            /// <summary>
+            /// Конструктор
+            /// </summary>
+            public PluginItem(string name, string descr, string fileName, PlaginStates state)
+            {
+                State = state;
+                Name = name;
+                Descr = descr;
+                FileName = fileName;
+            }
+            /// <summary>
+            /// Конструктор
+            /// </summary>
+            public PluginItem(PluginSpec pluginSpec, PlaginStates state)
+            {
+                State = state;
+                Name = pluginSpec.Name;
+                Descr = pluginSpec.Descr;
+                FileName = Path.GetFileName(Assembly.GetAssembly(pluginSpec.GetType()).Location);
+            }
+
+            /// <summary>
+            /// Получить или установить наименование плагина
+            /// </summary>
+            public string Name { get; set; }
+            /// <summary>
+            /// Получить или установить описание плагина
+            /// </summary>
+            public string Descr { get; set; }
+            /// <summary>
+            /// Получить или установить короткое имя файла библиотеки плагина
+            /// </summary>
+            public string FileName { get; set; }
             /// <summary>
             /// Получить или установить состояние плагина
             /// </summary>
             public PlaginStates State { get; set; }
-            /// <summary>
-            /// Получить или установить наименование плагина
-            /// </summary>
-            public string Name { get; set; }
-            /// <summary>
-            /// Получить или установить описание плагина
-            /// </summary>
-            public string Descr { get; set; }
-            /// <summary>
-            /// Получить или установить короткое имя файла библиотеки плагина
-            /// </summary>
-            public string FileName { get; set; }
+
+            /// <summary>
+            /// Сравнить текущий объект с другим объектом такого же типа
+            /// </summary>
+            public int CompareTo(PluginItem other)
+            {
+                return Name.CompareTo(other.Name);
+            }
         }

@@ -83,24 +115,93 @@

         /// <summary>
-        /// Получить список плагинов
-        /// </summary>
-        private List<PluginItem> GetPluginItems()
+        /// Получить все доступные плагины
+        /// </summary>
+        private List<PluginItem> GetAllPlugins()
         {
             List<PluginItem> pluginItems = new List<PluginItem>();
+            HashSet<string> existingFileNames = GetExistingFileNames();
+            HashSet<string> settingsFileNames = GetSettingsFileNames();
+            HashSet<string> allFileNames = new HashSet<string>();
+            allFileNames.UnionWith(existingFileNames);
+            allFileNames.UnionWith(settingsFileNames);
+            Dictionary<string, PluginItem> activePlugins = GetActivePlugins();
+
+            foreach (string fileName in allFileNames)
+            {
+                PluginItem pluginItem;
+
+                if (activePlugins.TryGetValue(fileName, out pluginItem))
+                {
+                    // добавление активного плагина
+                    pluginItems.Add(pluginItem);
+                }
+                else if (settingsFileNames.Contains(fileName))
+                {
+                    // добавление активного, но не загруженного плагина
+                    pluginItems.Add(new PluginItem(fileName, "", fileName, PlaginStates.NotLoaded));
+                }
+                else
+                {
+                    // загрузка спецификации неактивного плагина
+                    string errMsg;
+                    PluginSpec pluginSpec = PluginSpec.CreateFromDll(appData.AppDirs.BinDir + fileName, out errMsg);
+
+                    if (pluginSpec == null)
+                        appData.Log.WriteError(errMsg);
+                    else
+                        pluginItems.Add(new PluginItem(pluginSpec, PlaginStates.Inactive));
+                }
+            }
+
+            pluginItems.Sort();
+            return pluginItems;
+        }
+
+        /// <summary>
+        /// Получить имена существующих файлов библиотек плагинов
+        /// </summary>
+        private HashSet<string> GetExistingFileNames()
+        {
+            HashSet<string> fileNameSet = new HashSet<string>();
+            DirectoryInfo dirInfo = new DirectoryInfo(appData.AppDirs.BinDir);
+            FileInfo[] fileInfoArr = dirInfo.GetFiles("plg*.dll", SearchOption.TopDirectoryOnly);
+
+            foreach (FileInfo fileInfo in fileInfoArr)
+            {
+                string fileName = fileInfo.Name;
+                if (!fileName.EndsWith("common.dll", StringComparison.OrdinalIgnoreCase))
+                    fileNameSet.Add(fileName);
+            }
+
+            return fileNameSet;
+        }
+
+        /// <summary>
+        /// Получить имена файлов библиотек плагинов из настроек
+        /// </summary>
+        private HashSet<string> GetSettingsFileNames()
+        {
+            HashSet<string> fileNameSet = new HashSet<string>();
+            fileNameSet.UnionWith(userData.WebSettings.PluginFileNames);
+            return fileNameSet;
+        }
+
+        /// <summary>
+        /// Получить словарь активных плагинов, ключ - имя файла библиотеки
+        /// </summary>
+        /// <returns></returns>
+        private Dictionary<string, PluginItem> GetActivePlugins()
+        {
+            Dictionary<string, PluginItem> activePlugins = new Dictionary<string, PluginItem>();

             foreach (PluginSpec pluginSpec in userData.PluginSpecs)
             {
-                pluginItems.Add(new PluginItem()
-                {
-                    State = PlaginStates.Active,
-                    Name = pluginSpec.Name,
-                    Descr = pluginSpec.Descr,
-                    FileName = ""
-                });
-            }
-
-            return pluginItems;
+                PluginItem pluginItem = new PluginItem(pluginSpec, PlaginStates.Active);
+                activePlugins[pluginItem.FileName] = pluginItem;
+            }
+
+            return activePlugins;
         }

@@ -121,9 +222,34 @@
                 Translator.TranslatePage(Page, "Scada.Web.Plugins.Config.WFrmPlugins");

                 // построение списка плагинов
-                repPlugins.DataSource = GetPluginItems();
+                repPlugins.DataSource = GetAllPlugins();
                 repPlugins.DataBind();
             }
+        }
+
+        protected void repPlugins_ItemDataBound(object sender, RepeaterItemEventArgs e)
+        {
+            // настройка кнопок активации и деактивации
+            PluginItem pluginItem = e.Item.DataItem as PluginItem;
+
+            if (pluginItem != null)
+            {
+                if (pluginItem.State == PlaginStates.Inactive)
+                {
+                    Button btnDeactivate = (Button)e.Item.FindControl("btnDeactivate");
+                    btnDeactivate.Visible = false;
+                }
+                else
+                {
+                    Button btnActivate = (Button)e.Item.FindControl("btnActivate");
+                    btnActivate.Visible = false;
+                }
+            }
+        }
+
+        protected void repPlugins_ItemCommand(object source, RepeaterCommandEventArgs e)
+        {
+
         }
     }
 }


fix ordering issue

fix ordering issue

--- Serenity.Core/Reflection/CodeGeneration/ScriptDtoGenerator.cs
+++ Serenity.Core/Reflection/CodeGeneration/ScriptDtoGenerator.cs
@@ -83,8 +83,9 @@

             sb.AppendLine();

-            var byNameSpace = generatedCode.Keys.ToLookup(x => x.Namespace);
-            var byOwnerType = generatedCode.Keys.ToLookup(x => (x.IsNested ? x.DeclaringType : null));
+            var ordered = generatedCode.Keys.OrderBy(x => x.Namespace).ThenBy(x => x.Name);
+            var byNameSpace = ordered.ToLookup(x => x.Namespace);
+            var byOwnerType = ordered.ToLookup(x => (x.IsNested ? x.DeclaringType : null));
             var outputted = new HashSet<Type>();

             foreach (var ns in byNameSpace.ToArray().OrderBy(x => x.Key))


Fixed sample

Fixed sample

--- samples/ConsoleChat/ConsoleChat/Program.cs
+++ samples/ConsoleChat/ConsoleChat/Program.cs
@@ -19,7 +19,7 @@

             Console.WriteLine("*******************************************************");

-            var client = new FirebaseClient("https://torrid-inferno-3642.firebaseio.com/");
+            var client = new FirebaseClient("https://yourfirebase.firebaseio.com/");
             var child = client.Child("messages");
             var o = child.AsObservable<Message>();


Closes #1251 Documentatie aangepast

Closes #1251 Documentatie aangepast

git-svn-id: 0ffdc289f568b1e7493e560395a00d06174c8a92@2089 99b415e2-69d1-4072-8d93-0ed3a15484ab

--- Solution/Chiro.Gap.WebApp/Controllers/AfdelingenController.cs
+++ Solution/Chiro.Gap.WebApp/Controllers/AfdelingenController.cs
@@ -272,7 +272,7 @@
 		}

 		/// <summary>
-		/// Postback voor activeren/bewerken afdeling(sjaar).
+		/// Postback voor activeren/bewerken afdelingsjaar
 		/// </summary>
 		/// <param name="model">De property <c>model.AfdelingsJaar</c> bevat de relevante details over het afdelingsjaar</param>
 		/// <param name="groepID">Groep waarin de gebruiker momenteel aan het werken is</param>
@@ -315,12 +315,12 @@
 		}

         /// <summary>
-        /// Laat de gebruiker het bestaande afdelingsjaar met afdelingsjaarID <paramref name="id"/>
+        /// Laat de gebruiker een bestaande afdeling met afdelingID <paramref name="id"/>
         /// bewerken.
         /// </summary>
         /// <param name="groepID">ID van de geselecteerde groep</param>
-        /// <param name="id">ID van het te bewerken afdelingsjaar</param>
-        /// <returns>De view 'afdelingsjaar'</returns>
+        /// <param name="id">ID van de te bewerken afdeling</param>
+        /// <returns>De view 'afdeling'</returns>
         [HandleError]
         public ActionResult AfdBewerken(int groepID, int id)
         {
@@ -336,12 +336,12 @@
         }

         /// <summary>
-        /// Postback voor activeren/bewerken afdeling(sjaar).
-        /// </summary>
-        /// <param name="model">De property <c>model.AfdelingsJaar</c> bevat de relevante details over het afdelingsjaar</param>
+        /// Postback voor activeren/bewerken afdeling
+        /// </summary>
+        /// <param name="model">De property <c>model.AfdelingInfo</c> bevat de relevante details over de afdeling</param>
         /// <param name="groepID">Groep waarin de gebruiker momenteel aan het werken is</param>
         /// <returns>Het afdelingsoverzicht als de wijzigingen bewaard zijn, en anders opnieuw de
-        /// 'AfdelingsJaarView'.</returns>
+        /// 'AfdelingView'.</returns>
         [AcceptVerbs(HttpVerbs.Post)]
         [HandleError]
         public ActionResult AfdBewerken(AfdelingInfoModel model, int groepID)


Updated manager to compare raw (non-decrypted) connection string with service to validate same connection info

--- Source/Applications/openPDCManager/openPDCManager/App.xaml.cs
+++ Source/Applications/openPDCManager/openPDCManager/App.xaml.cs
@@ -25,6 +25,7 @@
 using System.Diagnostics;
 using System.IO;
 using System.Linq;
+using System.Reflection;
 using System.Security.Principal;
 using System.Windows;
 using System.Windows.Forms;
@@ -108,7 +109,18 @@

                     if (!configSettings["KeepCustomConnection"].Value.ParseBoolean())
                     {
-                        string connectionString = configSettings["ConnectionString"].Value;
+                        MethodInfo getRawValueMethod = typeof(CategorizedSettingsElement).GetMethod("GetRawValue", BindingFlags.Instance | BindingFlags.NonPublic);
+
+                        string getRawValue(CategorizedSettingsElement element)
+                        {
+                            if (getRawValueMethod is null)
+                                return element.Value;
+
+                            return getRawValueMethod.Invoke(element, Array.Empty<object>()) as string;
+                        }
+
+                        // Get value from connection string that is still encrypted for proper comparison
+                        string connectionString = getRawValue(configSettings["ConnectionString"]);
                         string dataProviderString = configSettings["DataProviderString"].Value;
                         string nodeID = configSettings["NodeID"].Value;


[Toolkit.Graphics] Add support for DepthStencilBuffer as ShaderInput

--- Source/Toolkit/SharpDX.Toolkit.Graphics/DepthStencilBuffer.cs
+++ Source/Toolkit/SharpDX.Toolkit.Graphics/DepthStencilBuffer.cs
@@ -189,37 +189,43 @@
         /// <param name="height">The height.</param>
         /// <param name="format">Describes the format to use.</param>
         /// <param name="arraySize">Size of the texture 2D array, default to 1.</param>
+        /// <param name="shaderResource">if set to <c>true</c> this depth stencil buffer can be set as an input to a shader (default: false).</param>
         /// <returns>A new instance of <see cref="DepthStencilBuffer" /> class.</returns>
         /// <msdn-id>ff476521</msdn-id>
         ///   <unmanaged>HRESULT ID3D11Device::CreateTexture2D([In] const D3D11_TEXTURE2D_DESC* pDesc,[In, Buffer, Optional] const D3D11_SUBRESOURCE_DATA* pInitialData,[Out, Fast] ID3D11Texture2D** ppTexture2D)</unmanaged>
         ///   <unmanaged-short>ID3D11Device::CreateTexture2D</unmanaged-short>
-        public static DepthStencilBuffer New(GraphicsDevice device, int width, int height, DepthFormat format, int arraySize = 1)
-        {
-            return new DepthStencilBuffer(device, NewDepthStencilBufferDescription(device.MainDevice, width, height, format, MSAALevel.None, arraySize), format);
+        public static DepthStencilBuffer New(GraphicsDevice device, int width, int height, DepthFormat format, bool shaderResource = false, int arraySize = 1)
+        {
+            return new DepthStencilBuffer(device, NewDepthStencilBufferDescription(device.MainDevice, width, height, format, MSAALevel.None, arraySize, shaderResource), format);
         }

         /// <summary>
         /// Creates a new <see cref="DepthStencilBuffer" /> using multisampling.
         /// </summary>
-        /// <param name="device">The <see cref="GraphicsDevice"/>.</param>
+        /// <param name="device">The <see cref="GraphicsDevice" />.</param>
         /// <param name="width">The width.</param>
         /// <param name="height">The height.</param>
+        /// <param name="multiSampleCount">The multisample count.</param>
         /// <param name="format">Describes the format to use.</param>
         /// <param name="arraySize">Size of the texture 2D array, default to 1.</param>
-        /// <param name="multiSampleCount">The multisample count.</param>
+        /// <param name="shaderResource">if set to <c>true</c> this depth stencil buffer can be set as an input to a shader (default: false).</param>
         /// <returns>A new instance of <see cref="DepthStencilBuffer" /> class.</returns>
         /// <msdn-id>ff476521</msdn-id>
         ///   <unmanaged>HRESULT ID3D11Device::CreateTexture2D([In] const D3D11_TEXTURE2D_DESC* pDesc,[In, Buffer, Optional] const D3D11_SUBRESOURCE_DATA* pInitialData,[Out, Fast] ID3D11Texture2D** ppTexture2D)</unmanaged>
         ///   <unmanaged-short>ID3D11Device::CreateTexture2D</unmanaged-short>
-        public static DepthStencilBuffer New(GraphicsDevice device, int width, int height, MSAALevel multiSampleCount, DepthFormat format, int arraySize = 1)
-        {
-            return new DepthStencilBuffer(device, NewDepthStencilBufferDescription(device.MainDevice, width, height, format, multiSampleCount, arraySize), format);
-        }
-
-        protected static Texture2DDescription NewDepthStencilBufferDescription(GraphicsDevice device, int width, int height, DepthFormat format, MSAALevel multiSampleCount, int arraySize)
+        public static DepthStencilBuffer New(GraphicsDevice device, int width, int height, MSAALevel multiSampleCount, DepthFormat format, bool shaderResource = false, int arraySize = 1)
+        {
+            return new DepthStencilBuffer(device, NewDepthStencilBufferDescription(device.MainDevice, width, height, format, multiSampleCount, arraySize, shaderResource), format);
+        }
+
+        protected static Texture2DDescription NewDepthStencilBufferDescription(GraphicsDevice device, int width, int height, DepthFormat format, MSAALevel multiSampleCount, int arraySize, bool shaderResource)
         {
             var desc = Texture2DBase.NewDescription(width, height, DXGI.Format.Unknown, TextureFlags.None, 1, arraySize, ResourceUsage.Default);
             desc.BindFlags |= BindFlags.DepthStencil;
+            if (shaderResource)
+            {
+                desc.BindFlags |= BindFlags.ShaderResource;
+            }
             // Sets the MSAALevel
             int maximumMSAA = (int)device.Features[(DXGI.Format)format].MSAALevelMax;
             desc.SampleDescription.Count = Math.Max(1, Math.Min((int)multiSampleCount, maximumMSAA));
@@ -287,10 +293,12 @@
             {
                 case SharpDX.DXGI.Format.D16_UNorm:
                 case DXGI.Format.R16_Float:
+                case DXGI.Format.R16_Typeless:
                     return DepthFormat.Depth16;

                 case SharpDX.DXGI.Format.D32_Float:
                 case DXGI.Format.R32_Float:
+                case DXGI.Format.R32_Typeless:
                     return DepthFormat.Depth32;

                 case SharpDX.DXGI.Format.D24_UNorm_S8_UInt:


fixed spelling mistake

fixed spelling mistake

--- Sources/Nuget.Server.AzureStorage/AzurePropertiesConstants.cs
+++ Sources/Nuget.Server.AzureStorage/AzurePropertiesConstants.cs
@@ -8,7 +8,7 @@
         /// <summary>
         /// The created
         /// </summary>
-        public const string Created = "Creted";
+        public const string Created = "Created";

         /// <summary>
         /// The latest modification date


Use new [Optional] injection attribute in TransitionControl

--- Sources/Silphid.Showzup/Sources/Controls/TransitionControl.cs
+++ Sources/Silphid.Showzup/Sources/Controls/TransitionControl.cs
@@ -28,8 +28,7 @@

         #region Injected properties

-        [Inject(IsOptional = true)]
-        internal ITransitionResolver TransitionResolver { get; set; }
+        [Inject] [Optional] internal ITransitionResolver TransitionResolver { get; set; }

         #endregion


Fix for key error

Fix for key error

--- DebRefund/DebRefundManager.cs
+++ DebRefund/DebRefundManager.cs
@@ -81,7 +81,7 @@
                     mass += p.mass;
                     cost += p.partInfo.cost;

-                    if (!PartCosts.ContainsKey(p.partName))
+                    if (!PartCosts.ContainsKey(p.partRef.partInfo.title))
                     {
                         PartCosts.Add(p.partRef.partInfo.title, p.partInfo.cost);
                         Parts.Add(p.partRef.partInfo.title, 0);


Corrected list initiallizer syntax in Trial cstr

--- DecimalPartitionSums/Trial.cs
+++ DecimalPartitionSums/Trial.cs
@@ -25,7 +25,7 @@

             for(int i = 0; i < Rows.Count; i++)
             {
-                RowsUsed[i] = false;
+                RowsUsed.Add(false);
             }

             done = false;


Fixed possible crash with empty layer when making entities.

--- Tiled/TMXGlueLib/DataTypes/ReducedTileMapInfo.TiledMapSave.cs
+++ Tiled/TMXGlueLib/DataTypes/ReducedTileMapInfo.TiledMapSave.cs
@@ -268,6 +268,13 @@
         private static void AddObjectLayerTiles(ReducedLayerInfo reducedLayerInfo, AbstractMapLayer tiledLayer, Tileset tileSet, uint? gid, int tileWidth, int tileHeight)
         {
             var asMapLayer = tiledLayer as mapObjectgroup;
+
+            // early out
+            if(asMapLayer.@object == null)
+            {
+                return;
+            }
+
             foreach (var objectInstance in asMapLayer.@object)
             {
                 if (objectInstance.gid > 0)


Add thread safety to font retrievals

Add thread safety to font retrievals

--- osu.Framework/IO/Stores/FontStore.cs
+++ osu.Framework/IO/Stores/FontStore.cs
@@ -117,18 +117,23 @@
             base.RemoveStore(store);
         }

+        private readonly object fontLookupLock = new object();
+
         public override Texture Get(string name)
         {
             var found = base.Get(name);

-            if (found == null)
+            lock (fontLookupLock)
             {
-                foreach (var store in nestedFontStores)
-                    if ((found = store.Get(name)) != null)
-                        break;
+                if (found == null)
+                {
+                    foreach (var store in nestedFontStores)
+                        if ((found = store.Get(name)) != null)
+                            break;
+                }
+
+                return found;
             }
-
-            return found;
         }

         public float? GetBaseHeight(char c)


only use `==` for comparion on primitive types

--- osu.Game/Beatmaps/BeatmapMetadata.cs
+++ osu.Game/Beatmaps/BeatmapMetadata.cs
@@ -74,16 +74,16 @@
                 return false;

             return onlineBeatmapSetID == other.onlineBeatmapSetID
-                && (Title?.Equals(other.Title) ?? false)
-                && (TitleUnicode?.Equals(other.TitleUnicode) ?? false)
-                && (Artist?.Equals(other.Artist) ?? false)
-                && (ArtistUnicode?.Equals(other.ArtistUnicode) ?? false)
-                && (AuthorString?.Equals(other.AuthorString) ?? false)
-                && (Source?.Equals(other.Source) ?? false)
-                && (Tags?.Equals(other.Tags) ?? false)
+                && Title == other.Title
+                && TitleUnicode == other.TitleUnicode
+                && Artist == other.Artist
+                && ArtistUnicode == other.ArtistUnicode
+                && AuthorString == other.AuthorString
+                && Source == other.Source
+                && Tags == other.Tags
                 && PreviewTime == other.PreviewTime
-                && (AudioFile?.Equals(other.AudioFile) ?? false)
-                && (BackgroundFile?.Equals(other.BackgroundFile) ?? false);
+                && AudioFile == other.AudioFile
+                && BackgroundFile == other.BackgroundFile;
         }
     }
 }


Removed the reopening of the playlist overlay

--- osu.Game/Overlays/MusicController.cs
+++ osu.Game/Overlays/MusicController.cs
@@ -58,8 +58,6 @@

         private Container dragContainer;
         private Container playerContainer;
-
-        private bool showPlaylistOnceAvailable;

         public MusicController()
         {
@@ -233,16 +231,8 @@
             nextButton.Enabled.Value = !disabled;
             playlistButton.Enabled.Value = !disabled;

-            // Toggle the playlist's visibility if required
             if (disabled)
-            {
-                showPlaylistOnceAvailable = playlist.State == Visibility.Visible;
-
-                if (showPlaylistOnceAvailable)
-                    playlist.Hide();
-            }
-            else if (showPlaylistOnceAvailable && State == Visibility.Visible)
-                playlist.Show();
+                playlist.Hide();
         }

         protected override void UpdateAfterChildren()
@@ -401,9 +391,6 @@

             FadeIn(transition_length, EasingTypes.OutQuint);
             dragContainer.ScaleTo(1, transition_length, EasingTypes.OutElastic);
-
-            if (Alpha == 0)
-                showPlaylistOnceAvailable = false;
         }

         protected override void PopOut()


PricingWizard, added real calculations at CustomerCustomType, for ProviderDataInputUnit:minutes and CustomerDataInputUnit:number (or 'quantity' alias).

--- en_US/PricingWizard/_CustomerCustomType.cshtml
+++ en_US/PricingWizard/_CustomerCustomType.cshtml
@@ -5,45 +5,92 @@
 @{
     var clienttypeid = PageData["ClientTypeID"];
     var c = PageData["customerrow"];
+    var p = PageData["providerrow"];
     var pos = PageData["positionrow"];
+    var idprefix = "pricingwizard";
     dynamic pvars;
+    var pvalues = new Dictionary<int, string>();
+    decimal timeRequired = 0, hourPrice = 0, feePrice = 0, subtotalPrice = 0, totalPrice = 0;

     using (var db = Database.Open("sqlloco")){
         // Get the Variables
         pvars = db.Query(@"
-            SELECT *
+            SELECT  PricingVariableID,
+                    PricingVariableName, CustomerInputDataRequired, CustomerDataInputType,
+                    CustomerDataValues, CustomerPricingVariableDisplayText,
+                    ProviderDataInputUnit, CustomerDataInputUnit
             FROM    pricingvariable
             WHERE   CountryID=@0 AND LanguageID=@1 AND ClientTypeID=@2 AND PositionID=@3
                      AND Active = 1 AND PricingTypeID = 2
         ", 1, 1, clienttypeid, pos.PositionID);
+
+        // Get specific Provider values for this pricing variables
+        var providerInputs = db.Query(@"
+                SELECT  PricingVariableID, PricingDataInput
+                FROM    providerpricingvariableinputs
+                WHERE   UserID = @0
+                ORDER BY    PricingVariableID
+            ", p.UserID);
+        // Transform providerInputs data into a dictionary searchable by PricingVariableID
+        foreach (var pinput in providerInputs){
+            pvalues.Add(pinput.PricingVariableID, pinput.PricingDataInput);
+        }
+
+        // Get provider hour price
+        hourPrice = db.QueryValue(@"
+            SELECT  TOP 1 HourlyRate
+            FROM    providerhourlyrate
+            WHERE   UserID = @0 AND PositionID = @1 AND ClientTypeID = @2 AND Active = 1
+        ", p.UserID, pos.PositionID, clienttypeid) ?? 0;
     }
-
-    var idprefix = "pricingwizard";
-    float timeRequired = 0, hourPrice = 0, feePrice = 0, subtotalPrice = 0, totalPrice = 0;

     if (IsPost){
         if (UrlData[0].ToLower() == "calculate"){
             // Do the calculation and return the result
-
-            // TODO Get hour price from database:
-            hourPrice = 20F;

-
             // Calculate time required
             timeRequired = 0;

             foreach (var pvar in pvars){
                 string customerValue = Request[pvar.PricingVariableName];

-                // TODO Get provider value
-                string providervalue;
+                // Get provider value for this pricing variable
+                string providerValue = "";
+                if (pvalues.ContainsKey(pvar.PricingVariableID)){
+                    providerValue = pvalues[pvar.PricingVariableID];
+                }
+                // TODO We must have default values for when a provider have not defined their values.

-                // Testing
-                timeRequired++;
+                // Analizing the provider value depending on the data-type (unit just now)
+                switch ((string)pvar.ProviderDataInputUnit){
+                    case "minutes":
+                        decimal provParsedValue = 0;
+                        decimal.TryParse(providerValue, out provParsedValue);
+
+                        switch ((string)pvar.CustomerDataInputUnit){
+                            case "number":
+                            case "quantity":
+                                decimal custParsedValue = 0;
+                                decimal.TryParse(customerValue, out custParsedValue);
+
+                                // Calculation Formula:
+                                //  (Provider.CostPerHour * (ProviderInputValue / 60) * CustomerInputValue)
+                                //subtotalPrice += hourPrice * (provParsedValue / 60) * custParsedValue;
+                                timeRequired += (provParsedValue / 60) * custParsedValue;
+
+                                break;
+                            default:
+                                break;
+                        }
+
+                        break;
+                    default:
+                        break;
+                }
             }

             subtotalPrice = timeRequired * hourPrice;
-            feePrice = .1F * subtotalPrice;
+            feePrice = .1M * subtotalPrice;
             totalPrice = subtotalPrice + feePrice;

         }else{
@@ -95,18 +142,18 @@

-
Time required:	@timeRequired hour(s)

+
Time required:	@timeRequired.ToString("#,##0.00") hour(s)

-                @timeRequired hour(s) @@ $@hourPrice
-                $@subtotalPrice
+                @timeRequired.ToString("#,##0.00") hour(s) @@ $@hourPrice.ToString("#,##0.00")
+                $@subtotalPrice.ToString("#,##0.00")

                 Loconomics service fee:
-                $@feePrice
+                $@feePrice.ToString("#,##0.00")

                 Total price:
-                $@totalPrice
+                $@totalPrice.ToString("#,##0.00")


Use lock while searching in the assemblies

--- BLM/Loader.cs
+++ BLM/Loader.cs
@@ -34,18 +34,23 @@
             }
         }

+        private static object _loadingTypes = new object();
+
         static void LoadTypes()
         {
-            var assemblies = AppDomain.CurrentDomain.GetAssemblies().ToList();
-            _loadedTypes = new List<Type>();
-            foreach (var assembly in assemblies)
+            lock (_loadingTypes)
             {
-                _loadedTypes.AddRange(
-                    assembly.GetTypes().Where(a =>
-                        a.GetInterfaces().Contains(typeof(IBlmEntry))
-                        && a.IsClass
-                        && !a.IsAbstract
-                        ));
+                var assemblies = AppDomain.CurrentDomain.GetAssemblies().ToList();
+                _loadedTypes = new List<Type>();
+                foreach (var assembly in assemblies)
+                {
+                    _loadedTypes.AddRange(
+                        assembly.GetTypes().Where(a =>
+                            a.GetInterfaces().Contains(typeof(IBlmEntry))
+                            && a.IsClass
+                            && !a.IsAbstract
+                            ));
+                }
             }
         }


Example for calculation of remaining Time

--- Downloader.Example/Program.cs
+++ Downloader.Example/Program.cs
@@ -44,13 +44,17 @@
             while (!finished)
             {
                 Thread.Sleep(1000);
+
+                var percent = progressMonitor.GetCurrentProgressPercentage(download) * 100;
+                var alreadyDownloadedSize = (progressMonitor.GetCurrentProgressInBytes(download) / 1024);
+                var totalDownloadSize = (progressMonitor.GetTotalFilesizeInBytes(download) / 1024);
+                var speed = (speedMonitor.GetCurrentBytesPerSecond() / 1024);
+                var remainingTime = (progressMonitor.GetTotalFilesizeInBytes(download) - progressMonitor.GetCurrentProgressInBytes(download)) / speedMonitor.GetCurrentBytesPerSecond();
+
                 Console.WriteLine(
-                    "Progress: " +
-                    (progressMonitor.GetCurrentProgressPercentage(download) * 100) + "% " +
-                    "(" + (progressMonitor.GetCurrentProgressInBytes(download) / 1024) + " of " +
-                    (progressMonitor.GetTotalFilesizeInBytes(download) / 1024) + " KiB)" +
-                    "   Speed: " +
-                    (speedMonitor.GetCurrentBytesPerSecond() / 1024) + " KiB/sec.");
+                    "Progress: " + percent + "% " + "(" + alreadyDownloadedSize + " of " + totalDownloadSize + " KiB)" +
+                    "   Speed: " + speed + " KiB/sec." +
+                    "   Remaining time: " + remainingTime + " sec.");
             }
         }


Added support code to the webserver for adding backups and schedules

--- Duplicati/Server/WebServer.cs
+++ Duplicati/Server/WebServer.cs
@@ -111,7 +111,7 @@
                                 where int.TryParse(n, out port)
                                 select int.Parse(n);

-            if (ports == null || ports.Count() == 0)
+            if (ports == null || !ports.Any())
                 ports = new int[] { 8080 };

             // If we are in hosted mode with no specified port,
@@ -674,12 +674,20 @@
                     var bk = Program.DataConnection.GetBackup(id);
                     if (bk == null)
                         ReportError(response, bw, "Invalid or missing backup id");
-                    else
+                    else
+                    {
+                        var scheduleId = Program.DataConnection.GetScheduleIDsFromTags(new string[] { "ID=" + id });
+                        var schedule = scheduleId.Any() ? null : Program.DataConnection.GetSchedule(scheduleId.First());
+
                         OutputObject(bw, new
                         {
                             success = true,
-                            data = bk
+                            data = new {
+                                Schedule = schedule,
+                                Backup = bk,
+                            }
                         });
+                    }
                 }
             }

@@ -692,29 +700,54 @@
                     return;
                 }

-                long id;
-                if (!long.TryParse(request.Form["id"].Value, out id))
-                {
-                    ReportError(response, bw, "Invalid or missing backup id");
-                    return;
-                }
-
                 try
                 {
+                    var data = Serializer.Deserialize<AddOrUpdateBackupData>(new StringReader(str));
+                    if (data.Backup == null)
+                    {
+                        ReportError(response, bw, "Data object had no backup entry");
+                        return;
+                    }
+
+                    if (data.Backup.ID <= 0)
+                    {
+                        ReportError(response, bw, "Invalid or missing backup id");
+                        return;
+                    }
+
                     lock(Program.DataConnection.m_lock)
                     {
-                        var backup = Program.DataConnection.GetBackup(id);
+                        var backup = Program.DataConnection.GetBackup(data.Backup.ID);
                         if (backup == null)
                         {
                             ReportError(response, bw, "Invalid or missing backup id");
                             return;
                         }

-                        backup = Serializer.Deserialize<Database.Backup>(new StringReader(str));
-                        backup.ID = id;
+                        if (Program.DataConnection.Backups.Where(x => x.Name.Equals(data.Backup.Name, StringComparison.InvariantCultureIgnoreCase) && x.ID != data.Backup.ID).Any())
+                        {
+                            ReportError(response, bw, "There already exists a backup with the name: " + data.Backup.Name);
+                            return;
+                        }

-                        //TODO: Validate, duplicate names etc.
-                        Program.DataConnection.AddOrUpdateBackup(backup);
+                        Program.DataConnection.AddOrUpdateBackup(data.Backup);
+                        var ids = Program.DataConnection.GetScheduleIDsFromTags(new string[] {"ID=" + data.Backup.ID});
+
+                        //TODO: Should be a transaction
+                        if (data.Schedule == null)
+                        {
+                            foreach(var i in ids)
+                                Program.DataConnection.DeleteSchedule(i);
+                        }
+                        else
+                        {
+                            if (ids.Any())
+                                data.Schedule.ID = ids.First();
+                            else
+                                data.Schedule.ID = -1;
+
+                            Program.DataConnection.AddOrUpdateSchedule(data.Schedule);
+                        }
                     }

                     OutputObject(bw, new { status = "OK" });
@@ -724,6 +757,12 @@
                     ReportError(response, bw, string.Format("Unable to parse backup object: {0}", ex.Message));
                 }
             }
+
+            private class AddOrUpdateBackupData
+            {
+                public Database.Schedule Schedule {get; set;}
+                public Database.Backup Backup {get; set;}
+            }

             private void AddBackup(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
             {
@@ -736,14 +775,33 @@

                 try
                 {
+
+                    var data = Serializer.Deserialize<AddOrUpdateBackupData>(new StringReader(str));
+                    if (data.Backup == null)
+                    {
+                        ReportError(response, bw, "Data object had no backup entry");
+                        return;
+                    }
+
+                    data.Backup.ID = -1;
+
                     lock(Program.DataConnection.m_lock)
                     {
-                        var backup = Serializer.Deserialize<Database.Backup>(new StringReader(str));
-                        backup.ID = -1;
-
-                        //TODO: Validate, duplicate names etc.
-
-                        Program.DataConnection.AddOrUpdateBackup(backup);
+                        if (Program.DataConnection.Backups.Where(x => x.Name.Equals(data.Backup.Name, StringComparison.InvariantCultureIgnoreCase)).Any())
+                        {
+                            ReportError(response, bw, "There already exists a backup with the name: " + data.Backup.Name);
+                            return;
+                        }
+
+                        Program.DataConnection.AddOrUpdateBackup(data.Backup);
+
+                        //TODO: Should be a transaction
+                        if (data.Schedule != null)
+                        {
+                            data.Schedule.ID = -1;
+                            data.Schedule.Tags = new string[] {"ID=" + data.Backup.ID };
+                            Program.DataConnection.AddOrUpdateSchedule(data.Schedule);
+                        }
                     }

                     OutputObject(bw, new { status = "OK" });
@@ -834,6 +892,8 @@
                         return;
                     }
                 }
+
+                Program.DataConnection.DeleteBackup(backup);

                 //We have fiddled with the schedules
                 Program.Scheduler.Reschedule();


Bugfix to handle null trace flag list.

Bugfix to handle null trace flag list.

--- SqlServerParseTreeViewer/ViewerForm.cs
+++ SqlServerParseTreeViewer/ViewerForm.cs
@@ -925,9 +925,12 @@
                     }
                 }

-                // Handle trace flags that are enabled in options but not returned by dbcc tracestatus
-                List<TraceFlag> traceFlags = ViewerSettings.Instance.TraceFlags.Where(tf => tf.Enabled && discoveredTraceFlags.Contains(tf.TraceFlagNumber) == false).ToList();
-                traceFlags.ForEach(tf => ToggleTraceFlag(tf.TraceFlagNumber, true));
+                if (ViewerSettings.Instance.TraceFlags != null)
+                {
+                    // Handle trace flags that are enabled in options but not returned by dbcc tracestatus
+                    List<TraceFlag> traceFlags = ViewerSettings.Instance.TraceFlags.Where(tf => tf.Enabled && discoveredTraceFlags.Contains(tf.TraceFlagNumber) == false).ToList();
+                    traceFlags.ForEach(tf => ToggleTraceFlag(tf.TraceFlagNumber, true));
+                }
             }
         }


Update Demo

Update Demo

--- Src/Asp.Net/PerformanceTest/Program.cs
+++ Src/Asp.Net/PerformanceTest/Program.cs
@@ -15,10 +15,29 @@
         /// <param name="args"></param>
         static void Main(string[] args)
         {
-            //new TestGetAll().Init(OrmType.Dapper);
-            //new TestGetById().Init(OrmType.EF);
-            new TestSql().Init(OrmType.SqlSugar);
+            var type = DemoType.GetAll;
+            var ormType = OrmType.Dapper;
+            switch (type)
+            {
+                case DemoType.GetAll:
+                    new TestGetAll().Init(ormType);
+                    break;
+                case DemoType.GetById:
+                    new TestGetAll().Init(ormType);
+                    break;
+                case DemoType.TestSql:
+                    new TestGetAll().Init(ormType);
+                    break;
+                default:
+                    break;
+            }
             Console.ReadKey();
+        }
+        enum DemoType
+        {
+            GetAll,
+            GetById,
+            TestSql
         }
     }
 }


Fixed another bug

Fixed another bug

--- Src/PTester/PRuntime/PrtImplMachine.cs
+++ Src/PTester/PRuntime/PrtImplMachine.cs
@@ -498,6 +498,7 @@
             }
             else if(PrtIsActionInstalled(currEventValue))
             {
+                eventValue = currEventValue;
                 goto DoAction;
             }
             else


Fixing contract.UnderlyingLastPrice bug (trello #1103)

--- Engine/DataFeeds/TimeSlice.cs
+++ Engine/DataFeeds/TimeSlice.cs
@@ -325,6 +325,11 @@
                 if (universeData.Underlying != null)
                 {
                     chain.Underlying = universeData.Underlying;
+
+                    foreach(var addedContract in chain.Contracts)
+                    {
+                        addedContract.Value.UnderlyingLastPrice = chain.Underlying.Price;
+                    }
                 }
                 foreach (var contractSymbol in universeData.FilteredContracts)
                 {
@@ -347,6 +352,7 @@
                     AskSize = security.AskSize,
                     UnderlyingLastPrice = chain.Underlying.Price
                 };
+
                 chain.Contracts[baseData.Symbol] = contract;
                 var option = security as Option;
                 if (option != null)


Updated the styling of the getting started example.

--- Structurizr.Examples/GettingStarted.cs
+++ Structurizr.Examples/GettingStarted.cs
@@ -20,8 +20,8 @@
             contextView.AddAllPeople();

             Styles styles = viewSet.Configuration.Styles;
-            styles.Add(new ElementStyle(Tags.SoftwareSystem) { Background = "#a4b7c9", Color = "#000000" });
-            styles.Add(new ElementStyle(Tags.Person) { Background = "#728da5", Color = "#ffffff" });
+            styles.Add(new ElementStyle(Tags.SoftwareSystem) { Background = "#1168bd", Color = "#ffffff" });
+            styles.Add(new ElementStyle(Tags.Person) { Background = "#08427b", Color = "#ffffff" });

             StructurizrClient structurizrClient = new StructurizrClient("key", "secret");
             structurizrClient.PutWorkspace(1234, workspace);


[YTTR-21] Test Suite for automatic deduction of coalesced trees.

--- src/test/MathNet.Yttrium.Test/PatternTest.cs
+++ src/test/MathNet.Yttrium.Test/PatternTest.cs
@@ -4,6 +4,7 @@
 using System;
 using System.Collections.Generic;

+using MathNet.Numerics;
 using MathNet.Symbolics.Workplace;
 using MathNet.Symbolics.Core;
 using MathNet.Symbolics.Backend;
@@ -71,14 +72,148 @@
             Assert.AreEqual(false, psimp.Match(x2, x2.DrivenByPort), "B02");

             TreePattern psinsqr = new TreePattern(new EntityCondition(new MathIdentifier("Sine", "Std")));
-            psinsqr.Add(new Pattern(new EntityCondition(new MathIdentifier("Square", "Std"))), false);
+            psinsqr.Add(new Pattern(new EntityCondition(new MathIdentifier("Square", "Std"))));
             Assert.AreEqual(true, psinsqr.Match(sinx2, sinx2.DrivenByPort), "B03");
             Assert.AreEqual(false, psinsqr.Match(x2, x2.DrivenByPort), "B04");

             TreePattern psinadd = new TreePattern(new EntityCondition(new MathIdentifier("Sine", "Std")));
-            psinadd.Add(new Pattern(new EntityCondition(new MathIdentifier("Add", "Std"))), false);
+            psinadd.Add(new Pattern(new EntityCondition(new MathIdentifier("Add", "Std"))));
             Assert.AreEqual(false, psinadd.Match(sinx2, sinx2.DrivenByPort), "B03");
             Assert.AreEqual(false, psinadd.Match(x2, x2.DrivenByPort), "B04");
         }
+
+        [Test]
+        public void Pattern_CoalescedTreeMatching()
+        {
+            Project p = new Project();
+            MathSystem s = p.CurrentSystem;
+            Builder b = p.Builder;
+            Context c = p.Context;
+
+            // sin(x^2)
+            Signal x = new Signal(c); x.Label = "x";
+            x.AddConstraint(RealSetProperty.Instance);
+            Signal x2 = b.Square(x); x2.Label = "x2";
+            Signal sinx2 = Std.Sine(c, x2); sinx2.Label = "sinx2";
+
+            CoalescedTreeNode root = new CoalescedTreeNode(AlwaysTrueCondition.Instance);
+            root.Subscribe(new MathIdentifier("A", "Test"));
+
+            CoalescedTreeNode sin = new CoalescedTreeNode(new EntityCondition(new MathIdentifier("Sine", "Std")));
+            sin.AddGroup(new MathIdentifier("B", "Test"), "sin");
+            root.ConditionAxis.Add(sin);
+
+            CoalescedTreeNode sqr = new CoalescedTreeNode(new EntityCondition(new MathIdentifier("Square", "Std")));
+            sqr.AddGroup(new MathIdentifier("B", "Test"), "sqr");
+            sqr.Subscribe(new MathIdentifier("B", "Test"));
+            CoalescedChildPattern sqrPattern = new CoalescedChildPattern();
+            sqrPattern.AddChild(sqr);
+            sin.PatternAxis.Add(sqrPattern);
+
+            CoalescedTreeNode tan = new CoalescedTreeNode(new EntityCondition(new MathIdentifier("Tangent", "Std")));
+            tan.AddGroup(new MathIdentifier("B", "Test"), "tan");
+            tan.Subscribe(new MathIdentifier("C", "Test"));
+            root.ConditionAxis.Add(tan);
+
+            MatchCollection res = root.MatchAll(sinx2, sinx2.DrivenByPort);
+            Assert.AreEqual(true, res.Contains(new MathIdentifier("A", "Test")), "C01");
+            Assert.AreEqual(true, res.Contains(new MathIdentifier("B", "Test")), "C02");
+            Assert.AreEqual(false, res.Contains(new MathIdentifier("C", "Test")), "C03");
+
+            Match mA = res[new MathIdentifier("A", "Test")];
+            Assert.AreEqual(new MathIdentifier("A", "Test"), mA.PatternId, "C04");
+            Assert.AreEqual(0, mA.GroupLabels.Count, "C05");
+
+            Match mB = res[new MathIdentifier("B", "Test")];
+            Assert.AreEqual(new MathIdentifier("B", "Test"), mB.PatternId, "C06");
+            Assert.AreEqual(2, mB.GroupLabels.Count, "C07");
+
+            List<Tuple<Signal,Port>> mBsqr = mB.Groups("sqr");
+            Assert.AreEqual(1, mBsqr.Count, "C08");
+            Assert.AreEqual(x2.InstanceId, mBsqr[0].First.InstanceId, "C09");
+            Assert.AreEqual(x2.DrivenByPort.InstanceId, mBsqr[0].Second.InstanceId, "C10");
+
+            List<Tuple<Signal, Port>> mBsin = mB.Groups("sin");
+            Assert.AreEqual(1, mBsin.Count, "C11");
+            Assert.AreEqual(sinx2.InstanceId, mBsin[0].First.InstanceId, "C12");
+            Assert.AreEqual(sinx2.DrivenByPort.InstanceId, mBsin[0].Second.InstanceId, "C13");
+        }
+
+        [Test]
+        public void Pattern_CoalescedTreeDeduction()
+        {
+            Project p = new Project();
+            MathSystem s = p.CurrentSystem;
+            Builder b = p.Builder;
+            Context c = p.Context;
+
+            // sin(x^2)
+            Signal x = new Signal(c); x.Label = "x";
+            x.AddConstraint(RealSetProperty.Instance);
+            Signal x2 = b.Square(x); x2.Label = "x2";
+            Signal sinx2 = Std.Sine(c, x2); sinx2.Label = "sinx2";
+
+            TreePattern psinadd = new TreePattern(new EntityCondition(new MathIdentifier("Sine", "Std")));
+            Pattern psinadd_add = new Pattern(new EntityCondition(new MathIdentifier("Add", "Std")));
+            psinadd.Add(psinadd_add);
+            psinadd_add.Group = "add";
+
+            TreePattern psinsqr = new TreePattern(new EntityCondition(new MathIdentifier("Sine", "Std")));
+            Pattern psinsqr_sqr = new Pattern(new EntityCondition(new MathIdentifier("Square", "Std")));
+            psinsqr.Add(psinsqr_sqr);
+            psinsqr.Group = "sin";
+            psinsqr_sqr.Group = "sqr";
+
+            // generate coalesced tree
+            CoalescedTreeNode root;
+            List<CoalescedTreeNode> list = CoalescedTreeNode.CreateRootTree(out root);
+            psinadd.MergeToCoalescedTree(new MathIdentifier("SinAdd", "Test"), list);
+            psinsqr.MergeToCoalescedTree(new MathIdentifier("SinSqr", "Test"), list);
+
+            // test whether the tree was generated correctly
+            Assert.AreEqual(1, root.ConditionAxis.Count, "D01");
+            Assert.AreEqual(0, root.PatternAxis.Count, "D02");
+
+            CoalescedTreeNode csin = root.ConditionAxis[0];
+            Assert.AreEqual(true, csin.Condition is EntityCondition, "D03");
+            Assert.AreEqual(new MathIdentifier("Sine", "Std"), ((EntityCondition)csin.Condition).EntityId, "D04");
+            Assert.AreEqual(1, csin.GroupAxis.Count, "D05");
+            Assert.AreEqual(0, csin.SubscriptionAxis.Count, "D06");
+            Assert.AreEqual("sin", csin.GroupAxis[new MathIdentifier("SinSqr", "Test")], "D07");
+            Assert.AreEqual(1, csin.PatternAxis.Count, "D08");
+            Assert.AreEqual(1, csin.PatternAxis[0].ChildrenAxis.Count, "D09");
+            Assert.AreEqual(true, csin.PatternAxis[0].ChildrenAxis[0].Condition is AlwaysTrueCondition, "D10");
+
+            CoalescedTreeNode cadd = csin.PatternAxis[0].ChildrenAxis[0].ConditionAxis[0];
+            Assert.AreEqual(true, cadd.Condition is EntityCondition, "D11");
+            Assert.AreEqual(new MathIdentifier("Add", "Std"), ((EntityCondition)cadd.Condition).EntityId, "D12");
+            Assert.AreEqual(1, cadd.GroupAxis.Count, "D13");
+            Assert.AreEqual(1, cadd.SubscriptionAxis.Count, "D14");
+            Assert.AreEqual("add", cadd.GroupAxis[new MathIdentifier("SinAdd", "Test")], "D15");
+            Assert.AreEqual(new MathIdentifier("SinAdd", "Test"), cadd.SubscriptionAxis[0], "D16");
+            Assert.AreEqual(0, cadd.PatternAxis.Count, "D18");
+
+            CoalescedTreeNode csqr = csin.PatternAxis[0].ChildrenAxis[0].ConditionAxis[1];
+            Assert.AreEqual(true, csqr.Condition is EntityCondition, "D19");
+            Assert.AreEqual(new MathIdentifier("Square", "Std"), ((EntityCondition)csqr.Condition).EntityId, "D20");
+            Assert.AreEqual(1, csqr.GroupAxis.Count, "D21");
+            Assert.AreEqual(1, csqr.SubscriptionAxis.Count, "D22");
+            Assert.AreEqual("sqr", csqr.GroupAxis[new MathIdentifier("SinSqr", "Test")], "D23");
+            Assert.AreEqual(new MathIdentifier("SinSqr", "Test"), csqr.SubscriptionAxis[0], "D24");
+            Assert.AreEqual(0, csqr.PatternAxis.Count, "D26");
+
+            // test whether the tree works as expected
+            MatchCollection res = root.MatchAll(sinx2, sinx2.DrivenByPort);
+            Assert.AreEqual(true, res.Contains(new MathIdentifier("SinSqr", "Test")), "D27");
+            Assert.AreEqual(false, res.Contains(new MathIdentifier("SinAdd", "Test")), "D28");
+
+            Match match = res[new MathIdentifier("SinSqr", "Test")];
+            Assert.AreEqual(new MathIdentifier("SinSqr", "Test"), match.PatternId, "D29");
+            Assert.AreEqual(2, match.GroupLabels.Count, "D30");
+            Assert.AreEqual(1, match.Groups("sin").Count, "D31");
+            Assert.AreEqual(sinx2.InstanceId, match.Groups("sin")[0].First.InstanceId, "D32");
+            Assert.AreEqual(1, match.Groups("sqr").Count, "D33");
+            Assert.AreEqual(x2.InstanceId, match.Groups("sqr")[0].First.InstanceId, "D34");
+        }
     }
 }


Throttle refreshes (Select boxes, Status width)

--- WalletWasabi.Gui/Controls/WalletExplorer/CoinListViewModel.cs
+++ WalletWasabi.Gui/Controls/WalletExplorer/CoinListViewModel.cs
@@ -23,6 +23,12 @@
 {
 	public class CoinListViewModel : ViewModelBase
 	{
+		private static HashSet<SmartCoinStatus> NotVisibleStatuses = new HashSet<SmartCoinStatus>()
+			{
+				SmartCoinStatus.Confirmed,
+				SmartCoinStatus.Unconfirmed
+			};
+
 		private CompositeDisposable Disposables { get; set; }

 		public SourceList<CoinViewModel> RootList { get; private set; }
@@ -47,8 +53,6 @@
 		private ShieldState _selectAllPrivateShieldState;
 		private ShieldState _selectAllNonPrivateShieldState;
 		private bool _isCoinListLoading;
-		private bool _invalidateCoinSelections;
-		private bool _invalidateCoinStatuses;

 		public Global Global { get; }
 		public CoinListContainerType CoinListContainerType { get; }
@@ -64,6 +68,10 @@

 		public event EventHandler<CoinViewModel> SelectionChanged;

+		public event EventHandler SelectionCheckBoxesInvalidated;
+
+		public event EventHandler CoinListStatusColumnInvalidated;
+
 		public ReadOnlyObservableCollection<CoinViewModel> Coins => _coinViewModels;

 		private SortExpressionComparer<CoinViewModel> MyComparer
@@ -136,18 +144,6 @@
 		{
 			get => _labelExposeCommonOwnershipWarning;
 			set => this.RaiseAndSetIfChanged(backingField: ref _labelExposeCommonOwnershipWarning, value);
-		}
-
-		public bool InvalidateCoinSelections
-		{
-			get => _invalidateCoinSelections;
-			set => this.RaiseAndSetIfChanged(ref _invalidateCoinSelections, value);
-		}
-
-		public bool InvalidateCoinStatuses
-		{
-			get => _invalidateCoinStatuses;
-			set => this.RaiseAndSetIfChanged(ref _invalidateCoinStatuses, value);
 		}

 		private void RefreshOrdering()
@@ -260,6 +256,8 @@
 			CoinListContainerType = coinListContainerType;
 			AmountSortDirection = SortOrder.Decreasing;
 			IsCoinListLoading = true;
+			CoinJoinStatusWidth = new GridLength(0);
+
 			RefreshOrdering();

 			// Otherwise they're all selected as null on load.
@@ -278,7 +276,17 @@
 				.Sort(MyComparer, comparerChanged: sortChanged, resetThreshold: 5)
 				.ObserveOn(RxApp.MainThreadScheduler)
 				.Bind(out _coinViewModels)
-				.OnItemRemoved(cvm => cvm.Dispose())
+				.OnItemAdded(cvm =>
+				{
+					SelectionCheckBoxesInvalidated?.Invoke(this, null);
+					CoinListStatusColumnInvalidated?.Invoke(this, null);
+				})
+				.OnItemRemoved(cvm =>
+				{
+					SelectionCheckBoxesInvalidated?.Invoke(this, null);
+					CoinListStatusColumnInvalidated?.Invoke(this, null);
+					cvm.Dispose();
+				})
 				.Subscribe();

 			SortCommand = ReactiveCommand.Create(RefreshOrdering);
@@ -344,7 +352,6 @@

 			SelectAllCheckBoxCommand = ReactiveCommand.Create(() =>
 				{
-					//Global.WalletService.Coins.First(c => c.Unspent).Unspent = false;
 					switch (SelectAllCheckBoxState)
 					{
 						case true:
@@ -414,6 +421,25 @@
 					IsCoinListLoading = false;
 				}
 			});
+
+			Observable
+				.FromEventPattern(this, nameof(SelectionCheckBoxesInvalidated))
+				.Throttle(TimeSpan.FromSeconds(0.5))
+				.ObserveOn(RxApp.MainThreadScheduler)
+				.Subscribe(x =>
+				{
+					SelectAllCheckBoxState = GetCheckBoxesSelectedState(x => true);
+					SelectPrivateCheckBoxState = GetCheckBoxesSelectedState(x => x.AnonymitySet >= Global.Config.MixUntilAnonymitySet);
+					SelectNonPrivateCheckBoxState = GetCheckBoxesSelectedState(x => x.AnonymitySet < Global.Config.MixUntilAnonymitySet);
+				});
+
+			Observable
+				.FromEventPattern(this, nameof(CoinListStatusColumnInvalidated))
+				.Throttle(TimeSpan.FromSeconds(0.5))
+				.ObserveOn(RxApp.MainThreadScheduler)
+				.Subscribe(_ => CoinJoinStatusWidth = Coins.Any() || Coins.All(x => NotVisibleStatuses.Contains(x.Status))
+						? new GridLength(0)
+						: new GridLength(180));

 			Observable
 				.Merge(InitList.ThrownExceptions)
@@ -492,9 +518,6 @@

 						var toRestore = args.EventArgs.RestoredCoins;
 						RootList.AddRange(toRestore.Select(coin => new CoinViewModel(this, coin)));
-
-						SetSelections();
-						SetCoinJoinStatusWidth();
 					}
 					catch (Exception ex)
 					{
@@ -511,9 +534,6 @@
 					{
 						var toRemove = args.EventArgs.Remove;
 						RootList.RemoveMany(RootList.Items.Where(cvm => toRemove.Any(sm => cvm.Model == sm)));
-
-						SetSelections();
-						SetCoinJoinStatusWidth();
 					}
 					catch (Exception ex)
 					{
@@ -528,8 +548,8 @@
 				.Subscribe(x => RefreshSelectCheckBoxesShields(x))
 				.DisposeWith(Disposables);

-			SetSelections();
-			SetCoinJoinStatusWidth();
+			SelectionCheckBoxesInvalidated?.Invoke(this, null);
+			CoinListStatusColumnInvalidated?.Invoke(this, null);
 		}

 		private void RefreshSelectCheckBoxesShields(int mixUntilAnonymitySet)
@@ -553,7 +573,7 @@
 					isStrongPrivate
 					);

-			SetSelections();
+			SelectionCheckBoxesInvalidated?.Invoke(this, null);
 		}

 		public void OnClose()
@@ -563,29 +583,10 @@
 			Disposables = null;
 		}

-		private void SetSelections()
-		{
-			SelectAllCheckBoxState = GetCheckBoxesSelectedState(x => true);
-			SelectPrivateCheckBoxState = GetCheckBoxesSelectedState(x => x.AnonymitySet >= Global.Config.MixUntilAnonymitySet);
-			SelectNonPrivateCheckBoxState = GetCheckBoxesSelectedState(x => x.AnonymitySet < Global.Config.MixUntilAnonymitySet);
-		}
-
-		private void SetCoinJoinStatusWidth()
-		{
-			CoinJoinStatusWidth = Coins.Any(x => x.Status == SmartCoinStatus.MixingConnectionConfirmation
-				 || x.Status == SmartCoinStatus.MixingInputRegistration
-				 || x.Status == SmartCoinStatus.MixingOnWaitingList
-				 || x.Status == SmartCoinStatus.MixingOutputRegistration
-				 || x.Status == SmartCoinStatus.MixingSigning
-				 || x.Status == SmartCoinStatus.MixingWaitingForConfirmation
-				 || x.Status == SmartCoinStatus.SpentAccordingToBackend)
-				? new GridLength(180)
-				: new GridLength(0);
-		}
-
 		public void OnCoinIsSelectedChanged(CoinViewModel cvm)
 		{
-			SetSelections();
+			SelectionCheckBoxesInvalidated?.Invoke(this, null);
+
 			SelectionChanged?.Invoke(this, cvm);
 			SelectedAmount = Coins.Where(x => x.IsSelected).Sum(x => x.Amount);
 			LabelExposeCommonOwnershipWarning = CoinListContainerType == CoinListContainerType.CoinJoinTabViewModel
@@ -597,18 +598,13 @@

 		public void OnCoinStatusChanged()
 		{
-			SetCoinJoinStatusWidth();
+			CoinListStatusColumnInvalidated?.Invoke(this, null);
 		}

 		public void OnCoinUnspentChanged(CoinViewModel cvm)
 		{
-			if (!cvm.Unspent)
-			{
-				RootList.Remove(cvm);
-			}
-
-			SetSelections();
-			SetCoinJoinStatusWidth();
+			// Removing the coin in Global.WalletService.TransactionProcessor.CoinSpent not here.
+			CoinListStatusColumnInvalidated?.Invoke(this, null);
 		}
 	}
 }


Dispose WalletManagerView properly

Dispose WalletManagerView properly

--- WalletWasabi.Gui/Tabs/WalletManager/WalletManagerViewModel.cs
+++ WalletWasabi.Gui/Tabs/WalletManager/WalletManagerViewModel.cs
@@ -1,19 +1,14 @@
-using Avalonia.Threading;
 using ReactiveUI;
 using System;
-using System.Collections.Generic;
 using System.Collections.ObjectModel;
 using System.Composition;
 using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
+using System.Reactive.Disposables;
 using WalletWasabi.Gui.Tabs.WalletManager.GenerateWallets;
 using WalletWasabi.Gui.Tabs.WalletManager.HardwareWallets;
 using WalletWasabi.Gui.Tabs.WalletManager.LoadWallets;
 using WalletWasabi.Gui.Tabs.WalletManager.RecoverWallets;
 using WalletWasabi.Gui.ViewModels;
-using WalletWasabi.Hwi.Models;
-using WalletWasabi.Logging;

 namespace WalletWasabi.Gui.Tabs.WalletManager
 {
@@ -24,29 +19,10 @@
 		private ObservableCollection<CategoryViewModel> _categories;
 		private CategoryViewModel _selectedCategory;
 		private ViewModelBase _currentView;
-		private LoadWalletViewModel LoadWalletViewModelDesktop { get; }
+		private LoadWalletViewModel LoadWalletViewModelDesktop { get; set; }

 		public WalletManagerViewModel() : base("Wallet Manager")
 		{
-			LoadWalletViewModelDesktop = new LoadWalletViewModel(this, LoadWalletType.Desktop);
-
-			Categories = new ObservableCollection<CategoryViewModel>
-			{
-				new GenerateWalletViewModel(this),
-				new RecoverWalletViewModel(this),
-				LoadWalletViewModelDesktop,
-				new LoadWalletViewModel(this, LoadWalletType.Password),
-				new ConnectHardwareWalletViewModel(this)
-			};
-
-			SelectedCategory = Categories.FirstOrDefault();
-
-			this.WhenAnyValue(x => x.SelectedCategory).Subscribe(category =>
-				{
-					category?.OnCategorySelected();
-
-					CurrentView = category;
-				});
 		}

 		public ObservableCollection<CategoryViewModel> Categories
@@ -84,6 +60,40 @@
 			passwordTestViewModel.SelectedWallet = passwordTestViewModel.Wallets.FirstOrDefault(w => w.WalletName == walletName);
 		}

+		public override void OnOpen(CompositeDisposable disposables)
+		{
+			base.OnOpen(disposables);
+
+			LoadWalletViewModelDesktop = new LoadWalletViewModel(this, LoadWalletType.Desktop);
+
+			Categories = new ObservableCollection<CategoryViewModel>
+			{
+				new GenerateWalletViewModel(this),
+				new RecoverWalletViewModel(this),
+				LoadWalletViewModelDesktop,
+				new LoadWalletViewModel(this, LoadWalletType.Password),
+				new ConnectHardwareWalletViewModel(this)
+			};
+
+			SelectedCategory = Categories.FirstOrDefault();
+
+			this.WhenAnyValue(x => x.SelectedCategory).Subscribe(category =>
+			{
+				category?.OnCategorySelected();
+
+				CurrentView = category;
+			});
+		}
+
+		public override bool OnClose()
+		{
+			foreach (var tab in Categories.OfType<IDisposable>())
+			{
+				tab.Dispose();
+			}
+			return base.OnClose();
+		}
+
 		public ViewModelBase CurrentView
 		{
 			get => _currentView;


Fix unix bug.

Fix unix bug.

crossgen fails on unix if there is an empty path passed as input to
"-platform_assemblies_paths".

--- scripts/dotnet-cli-build/Utils/Crossgen.cs
+++ scripts/dotnet-cli-build/Utils/Crossgen.cs
@@ -92,11 +92,14 @@
                 // The right fix -
                 // If the assembly has deps.json then parse the json file to get all the dependencies. Pass these dependencies as input to crossgen.
                 // else pass the current directory of assembly as input to crossgen.
-                string addtionalPaths = string.Join(";", Directory.GetDirectories(pathToAssemblies, "*", SearchOption.AllDirectories));
+                var addtionalPaths = Directory.GetDirectories(pathToAssemblies, "*", SearchOption.AllDirectories).ToList();
+                var paths = new List<string>() { sharedFxPath, pathToAssemblies };
+                paths.AddRange(addtionalPaths);
+                var platformAssembliesPaths = string.Join(";", paths.Distinct());

                 IList<string> crossgenArgs = new List<string> {
                     "-readytorun", "-in", file, "-out", tempPathName,
-                    "-platform_assemblies_paths", $"{sharedFxPath};{pathToAssemblies};{addtionalPaths}"
+                    "-platform_assemblies_paths", platformAssembliesPaths
                 };

                 var env = new Dictionary<string, string>()


Lazy Nullability review

Lazy Nullability review

--- Framework.Core/System/Lazy.cs
+++ Framework.Core/System/Lazy.cs
@@ -2,6 +2,7 @@

 using System.Collections.Generic;
 using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
 using System.Threading;
 using Theraot.Core;
 using Theraot.Reflection;
@@ -168,8 +169,7 @@
         [DebuggerBrowsable(DebuggerBrowsableState.Never)]
         public T Value => _valueFactory.Invoke();

-        // ReSharper disable once RedundantDefaultMemberInitializer
-        internal T ValueForDebugDisplay { get; private set; } = default!;
+        [MaybeNull] internal T ValueForDebugDisplay { get; private set; } = default!;

         private static void AddThread(HashSet<Thread> threads)
         {


Added client's display names to the Fund model.

--- FundEntities/Entities/Fund.cs
+++ FundEntities/Entities/Fund.cs
@@ -19,6 +19,7 @@
         public string AreaId { get; set; }

         [Required]
+        [Display(Name="Fund number")]
         public string Number { get; set; }

         public DateTimeOffset DateTimeCreated { get; set; }
@@ -26,6 +27,7 @@
         public ICollection<DateTimeOffset> DateTimeEdited { get; set; }

         [Required]
+        [Display(Name="Fund title")]
         public string Title { get; set; }

         public Status Status { get; set; }
@@ -34,14 +36,17 @@
         public string Description { get; set; }

         [Required]
+        [Display(Name="Responsible person")]
         public string ResponsiblePerson { get; set; }

         [Required]
         [DataMember(IsRequired = true)]
+        [Display(Name="Current fiscal year approved budget")]
         public int CurrentBudget { get; set; }

         [Required]
         [DataMember(IsRequired = true)]
+        [Display(Name="YTD and projected expenditures through June 30")]
         public int ProjectedExpenditures { get; set; }

         [Required]


Resolve #335 -- Logger crashing due to multithreaded access

Added StringBuilder lock.
Added FileStream lock.

Refs #335

--- GameServerLib/Logic/Logger.cs
+++ GameServerLib/Logic/Logger.cs
@@ -121,24 +121,33 @@
                 RefreshLoop();
             }

+            //Can get called by different threads
             private void RefreshLoop()
             {
-                if (_stringBuilder.Length > 0)
-                {
-                    String text = _stringBuilder.ToString();
-                    _stringBuilder.Clear();
-                    Task.Factory.StartNew(() =>
+                string text = null;
+                lock (_stringBuilder)
+                {
+                    if (_stringBuilder.Length > 0)
                     {
-                        Console.Write(text);
-                    });
+                        text = _stringBuilder.ToString();
+                        _stringBuilder.Clear();
+                    }
+                }
+                if (text != null)
+                {
                     WriteTextToLogFile(text + Environment.NewLine);
-                }
-            }
-
+                    Console.Write(text);
+                }
+            }
+
+            //Can get called by different threads
             private void WriteTextToLogFile(string text)
             {
                 byte[] info = new UTF8Encoding(true).GetBytes(text);
-                _logFile.WriteAsync(info, 0, info.Length);
+                lock (_logFile)
+                {
+                    _logFile.WriteAsync(info, 0, info.Length);
+                }
             }

             public void Log(string lines, string type = "LOG")
@@ -149,8 +158,10 @@
                     type.ToUpper(),
                     lines
                 );
-
-                _stringBuilder.AppendLine(text);
+                lock (_stringBuilder)
+                {
+                    _stringBuilder.AppendLine(text);
+                }
             }

             public void CreateLogFile(string directory, string name)


ReadOnlyArray<T> implement IList<T> fix ReadOnlyArray<T> issue of deserialization

--- LightWands.cs
+++ LightWands.cs
@@ -1543,6 +1543,7 @@
     }

     #endregion
+
 #endif

 #if NET45_WINRT45_WP8 || TESTS
@@ -1560,33 +1561,26 @@
         }

         [DataContract]
-        class ReadOnlyArray<T> : IReadOnlyList<T>
+        class ReadOnlyArray<T> : IReadOnlyList<T>, IList<T>
         {
             [DataMember]
-            readonly T[] array;
+            readonly T[] coreArray;

             public ReadOnlyArray(T[] array)
             {
                 Contract.Requires<ArgumentNullException>(array != null);

-                this.array = array;
-            }
-
-            [ContractInvariantMethod]
-            [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "Required for code contracts.")]
-            private void ObjectInvariant()
-            {
-                Contract.Invariant(array != null);
+                this.coreArray = array;
             }

             public int Count
             {
-                get { return array.Length; }
+                get { return coreArray == null ? 0 : coreArray.Length; }
             }

             public IEnumerator<T> GetEnumerator()
             {
-                return array.AsEnumerable().GetEnumerator();
+                return (coreArray ?? new T[0]).AsEnumerable().GetEnumerator();
             }

             IEnumerator IEnumerable.GetEnumerator()
@@ -1596,7 +1590,64 @@

             public T this[int index]
             {
-                get { return array[index]; }
+                get { return (coreArray ?? new T[0])[index]; /* 例外は丸投げ */ }
+            }
+
+            int IList<T>.IndexOf(T item)
+            {
+                return coreArray == null ? -1 : Array.IndexOf(coreArray, item);
+            }
+
+            void IList<T>.Insert(int index, T item)
+            {
+                throw new NotSupportedException();
+            }
+
+            void IList<T>.RemoveAt(int index)
+            {
+                throw new NotSupportedException();
+            }
+
+            T IList<T>.this[int index]
+            {
+                get
+                {
+                    return this[index];
+                }
+                set
+                {
+                    throw new NotSupportedException();
+                }
+            }
+
+            void ICollection<T>.Add(T item)
+            {
+                throw new NotSupportedException();
+            }
+
+            void ICollection<T>.Clear()
+            {
+                throw new NotSupportedException();
+            }
+
+            bool ICollection<T>.Contains(T item)
+            {
+                return coreArray == null ? false : coreArray.Any(elem => Object.Equals(elem, item));
+            }
+
+            void ICollection<T>.CopyTo(T[] array, int arrayIndex)
+            {
+                (coreArray ?? new T[0]).CopyTo(array, arrayIndex);
+            }
+
+            bool ICollection<T>.IsReadOnly
+            {
+                get { return true; }
+            }
+
+            bool ICollection<T>.Remove(T item)
+            {
+                throw new NotSupportedException();
             }
         }
     }


Allow changes to training record without new documentation

--- src/website/api/TrainingRecordsController.cs
+++ src/website/api/TrainingRecordsController.cs
@@ -215,7 +215,10 @@
         // Documentation required.
         if (!model.UploadsPending && string.IsNullOrWhiteSpace(model.metadata))
         {
-          errors.Add(new SubmitError { Error = Strings.API_TrainingRecord_DocumentationRequired, Property = BaseApiController.ModelRootNodeName });
+          if (!db.Documents.Any(f => f.ReferenceId == model.Id))
+          {
+            errors.Add(new SubmitError { Error = Strings.API_TrainingRecord_DocumentationRequired, Property = BaseApiController.ModelRootNodeName });
+          }
         }

         // Prevent duplicate records


Add debugging tool for analyzing onscreen font sizes

--- Gui/TextWidgets/TextWidget.cs
+++ Gui/TextWidgets/TextWidget.cs
@@ -242,6 +242,13 @@
 				Printer.Render(graphics2D, currentColor);
 			}

+			// Debug onscreen fonts
+			if (false && this.Text.Trim().Length > 1)
+			{
+				graphics2D.FillRectangle(this.Width - 13, 0, this.Width, this.Height - 2, RGBA_Bytes.White);
+				graphics2D.DrawString(this.PointSize.ToString(), this.Width - 12, 2, 8, color: RGBA_Bytes.Red);
+			}
+
 			graphics2D.PopTransform();

 			base.OnDraw(graphics2D);


raspbian?

raspbian?

--- H3Control/DeviceDataSource.cs
+++ H3Control/DeviceDataSource.cs
@@ -29,6 +29,8 @@
             int.TryParse(ReadSmallFile("/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq"), out curCpu);
             var legacyTempPath = "/sys/devices/virtual/hwmon/hwmon1/temp1_input";
             var mainlineTempPath = "/sys/devices/virtual/thermal/thermal_zone0/temp";
+            // TODO: Raspbian
+            var raspbianTempPath = "/sys/class/thermal/thermal_zone0/temp";
             if (File.Exists(legacyTempPath))
             {
                 int.TryParse(ReadSmallFile(legacyTempPath), out tempr);
@@ -186,6 +188,7 @@
             else
             {
                 ret = (T) raw;
+
             }

             return ret;


cp fix

cp fix

--- Edges.cs
+++ Edges.cs
@@ -164,7 +164,7 @@
         EdgeCP res = new EdgeCP();

         res.normalized_t = m_data.ClosestPointParam( pt );
-        if ( res.normalized_t < 0 || res.normalized_t > 1 )
+        if ( res.normalized_t <= 0 || res.normalized_t >= 1 )
             res.at_edge_end = res.normalized_t > 0;

         if ( !m_sense )
@@ -173,8 +173,12 @@

             if ( res.at_edge_end.HasValue )
                 res.at_edge_end = !res.at_edge_end;
-        }
-
+        }
+
+        if ( res.at_edge_end.HasValue )
+            res.normalized_t = res.at_edge_end.Value ? 1 : 0;
+
+        res.pt = Eval( res.normalized_t ).pt;
         return res;
     }


Another minor update

Another minor update

--- Form1.cs
+++ Form1.cs
@@ -9,6 +9,7 @@
 using System.Windows.Forms;
 using System.IO;
 using System.Text.RegularExpressions;
+using System.Diagnostics;

 namespace EHDownloader_UI
 {
@@ -224,6 +225,10 @@
                     }
                     listBox1.EndUpdate();
                 }
+            }else
+            {
+                string SelectedManga = listBox1.SelectedItem.ToString();
+                Process.Start(Directory.GetCurrentDirectory() + "\\" + SelectedManga);
             }
         }


Changed test Startup with a workaround.

Changed test Startup with a workaround.

--- test/AbpCompanyName.AbpProjectName.Web.Tests/Startup.cs
+++ test/AbpCompanyName.AbpProjectName.Web.Tests/Startup.cs
@@ -4,9 +4,11 @@
 using Abp.AspNetCore.TestBase;
 using Abp.Dependency;
 using AbpCompanyName.AbpProjectName.EntityFrameworkCore;
+using AbpCompanyName.AbpProjectName.Web.Controllers;
 using Castle.MicroKernel.Registration;
 using Microsoft.AspNetCore.Builder;
 using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Mvc.ApplicationParts;
 using Microsoft.EntityFrameworkCore;
 using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.Logging;
@@ -19,10 +21,17 @@
         {
             services.AddEntityFrameworkInMemoryDatabase();

-            services.AddMvc(options =>
+            var mvc = services.AddMvc(options =>
             {
                 options.AddAbp(); //Add ABP infrastructure to MVC
-            }).AddControllersAsServices();
+            });
+
+            //Workaround defined here: https://github.com/aspnet/Mvc/issues/4897#issuecomment-228093609
+            var parts = mvc.PartManager.ApplicationParts;
+            parts.Clear();
+            parts.Add(new AssemblyPart(typeof(HomeController).Assembly));
+
+            mvc.AddControllersAsServices();

             //Configure Abp and Dependency Injection
             return services.AddAbp(options =>


Adjusted serialization (now exactly the same as input for functions)

--- UnitTests/Css/CssTransitionProperty.cs
+++ UnitTests/Css/CssTransitionProperty.cs
@@ -226,7 +226,7 @@
             Assert.AreEqual(CssValueType.List, concrete.Value.Type);
             Assert.IsFalse(concrete.IsInherited);
             Assert.IsTrue(concrete.HasValue);
-            Assert.AreEqual("steps(25, end), linear, cubic-bezier(0.25, 1, 0.5, 1)", concrete.Value.CssText);
+            Assert.AreEqual("steps(25), linear, cubic-bezier(0.25, 1, 0.5, 1)", concrete.Value.CssText);
         }

         [TestMethod]
@@ -331,7 +331,7 @@
             Assert.AreEqual(CssValueType.List, concrete.Value.Type);
             Assert.IsFalse(concrete.IsInherited);
             Assert.IsTrue(concrete.HasValue);
-            Assert.AreEqual("steps(25, end), linear, cubic-bezier(0.25, 1, 0.5, 1)", concrete.Value.CssText);
+            Assert.AreEqual("steps(25), linear, cubic-bezier(0.25, 1, 0.5, 1)", concrete.Value.CssText);
         }

         [TestMethod]
@@ -391,7 +391,7 @@
             Assert.AreEqual(CssValueType.List, concrete.Value.Type);
             Assert.IsFalse(concrete.IsInherited);
             Assert.IsTrue(concrete.HasValue);
-            Assert.AreEqual("all 1s ease, height steps(5, end) 50ms", concrete.Value.CssText);
+            Assert.AreEqual("all 1s ease, height steps(5) 50ms", concrete.Value.CssText);
         }

         [TestMethod]


Added unti test for instanceof operator

Added unti test for instanceof operator

--- IronJS.Tests/BinaryOpTests.cs
+++ IronJS.Tests/BinaryOpTests.cs
@@ -514,5 +514,32 @@
                 )
             );
         }
+
+        [TestMethod]
+        public void TestOperatorInstanceOf()
+        {
+            Assert.AreEqual(
+                "truefalsefalsetrue",
+                ScriptRunner.Run(
+                    @"
+                    var fooCtor = function () {
+
+                    };
+
+                    var barCtor = function () {
+
+                    };
+
+                    foo = new fooCtor();
+                    bar = new barCtor();
+
+                    emit(foo instanceof fooCtor);
+                    emit(foo instanceof barCtor);
+                    emit(bar instanceof fooCtor);
+                    emit(bar instanceof barCtor);
+                    "
+                )
+            );
+        }
     }
 }


abcdef

abcdef

--- JabbR/Views/Home/index.cshtml
+++ JabbR/Views/Home/index.cshtml
@@ -4,7 +4,7 @@
 <!DOCTYPE html>
 <html>
 <head>
-    <title>jean0516new01</title>
+    <title>jean0516last</title>
     <meta http-equiv="X-UA-Compatible" content="IE=9" />
     <meta name="description" content="A real-time chat application." />
     <meta name="keywords" content="chat,realtime chat,signalr,jabbr" />


Fixed hidden bug because I wasn't logging the exception. Duh!

--- JobScheduling/JobScheduler.cs
+++ JobScheduling/JobScheduler.cs
@@ -196,7 +196,7 @@
                 IEnumerable<IJob> toExecute;
                 lock (locker)
                 {
-                    toExecute = jobs.Where(job => job.ShouldRunNow(now));
+                    toExecute = jobs.Where(job => job.ShouldRunNow(now)).ToArray();
                 }
                 foreach (IJob job in toExecute)
                 {
@@ -204,9 +204,10 @@
                     job.Run();
                 }
             }
-            catch
+            catch (Exception ex)
             {
                 // TODO(Richo): Log exceptions!
+                Console.WriteLine(ex.ToString());
             }
             finally
             {


added tracing when the type is not found

--- Joyride/Platforms/Detector.cs
+++ Joyride/Platforms/Detector.cs
@@ -1,5 +1,6 @@
 using System;
 using System.Collections.Generic;
+using System.Diagnostics;
 using System.Linq;
 using System.Reflection;

@@ -89,11 +90,15 @@
             return detectable;
         }

-        public T Detect(string modalDialogName)
+        public T Detect(string name)
         {
-            if (!LookupTable.ContainsKey(modalDialogName))
+            if (!LookupTable.ContainsKey(name))
+            {
+                Trace.WriteLine("Unable to find detectable:  " + name);
                 return default(T);
-            var detectableType = LookupTable[modalDialogName];
+            }
+
+            var detectableType = LookupTable[name];
             return IsOnScreen(detectableType, TimeoutSecs) ? FactoryMethod(detectableType) : default(T);
         }


Update GeoPoliticalContext.cs

Update GeoPoliticalContext.cs

--- source/ADAPT/Common/GeoPoliticalContext.cs
+++ source/ADAPT/Common/GeoPoliticalContext.cs
@@ -12,6 +12,7 @@
   *    Joseph Ross - Adding intializer for id
   *    R. Andres Ferreyra - Added GPCLevel, GPCVocSource, Lexicalizations
   *******************************************************************************/
+using System.Collections.Generic;

 namespace AgGateway.ADAPT.ApplicationDataModel.Common
 {
@@ -68,4 +69,4 @@
         /// Provides strings human-readable labels for the geopolitical context, in specific languages.</value>
         public List<Lexicalization> Lexicalizations { get; set; }
     }
-}+}


Don't handle resizing if the window isn't being drawn

--- KSPPartSorter/PartArranger.cs
+++ KSPPartSorter/PartArranger.cs
@@ -139,8 +139,8 @@
         /// </summary>
         public void Update()
         {
-            if ((Boolean)settings["HidePlugin"])
-                return;
+            if ((Boolean)settings["HidePlugin"] || !windowShown)
+                return; // Don't handle resizing if the plugin is hidden or if the window isn't being shown

             // Fix reversed y position in mouse coordinates
             Vector3 mousePos = Input.mousePosition;


Test12で中間層のcDNIに教師信号が入力されていない不具合を修正

Test12で中間層のcDNIに教師信号が入力されていない不具合を修正

--- KelpNetTester/Tests/Test12.cs
+++ KelpNetTester/Tests/Test12.cs
@@ -102,14 +102,14 @@
             );

             FunctionStack cDNI2 = new FunctionStack(
-                new Linear(256, 1024, name: "cDNI2 Linear1"),
+                new Linear(256+10, 1024, name: "cDNI2 Linear1"),
                 new BatchNormalization(1024, name: "cDNI2 Nrom1"),
                 new ReLU(name: "cDNI2 ReLU1"),
                 new Linear(1024, 256, initialW: new double[1024, 256], name: "cDNI2 Linear3")
             );

             FunctionStack cDNI3 = new FunctionStack(
-                new Linear(256, 1024, name: "cDNI3 Linear1"),
+                new Linear(256+10, 1024, name: "cDNI3 Linear1"),
                 new BatchNormalization(1024, name: "cDNI3 Nrom1"),
                 new ReLU(name: "cDNI3 ReLU1"),
                 new Linear(1024, 256, initialW: new double[1024, 256], name: "cDNI3 Linear3")


Document HwiCommands.cs

Document HwiCommands.cs

--- WalletWasabi/Hwi/Models/HwiCommands.cs
+++ WalletWasabi/Hwi/Models/HwiCommands.cs
@@ -4,20 +4,125 @@

 namespace WalletWasabi.Hwi.Models
 {
+	///
+	/// List of commands that HWI project supports for various <see href="https://en.wikipedia.org/wiki/Human_interface_device">HID devices</see>.
+	///
+	/// <remarks>HWI may partially support a hardware device.</remarks>
+	/// <seealso href="https://github.com/bitcoin-core/HWI/blob/master/hwilib/hwwclient.py"/>
+	/// <seealso href="https://github.com/bitcoin-core/HWI/blob/master/docs/trezor.md"/>
+	/// <seealso href="https://github.com/bitcoin-core/HWI/blob/master/docs/ledger.md"/>
 	public enum HwiCommands
 	{
+		/// Get a list of all available hardware wallets.
 		Enumerate,
+
+		///
+		/// Return the master BIP44 public key.
+		///
+		/// <para>Retrieve the public key at the "m/44h/0h/0h" derivation path.</para>
+		///
+		/// <remarks>
+		/// Return {"xpub": <xpub string>"}.
+		/// </remarks>
 		GetMasterXpub,
+
+		///
+		/// Sign a partially signed bitcoin transaction (PSBT).
+		///
+		/// <remarks>
+		/// Return {"psbt": <base64 psbt string>.
+		/// </remarks>
 		SignTx,
+
+		///
+		/// ???
+		///
 		GetXpub,
+
+		///
+		/// Sign a message (bitcoin message signing).
+		///
+		/// <para>Sign the message according to the bitcoin message signing standard.</para>
+		/// <para>Retrieve the signing key at the specified BIP32 derivation path.</para>
+		///
+		/// <remarks>
+		/// Return {"signature": <base64 signature string>}.
+		/// </remarks>
 		SignMessage,
+
+		///
+		/// ??? (unused at the moment?)
+		///
 		GetKeypool,
+
+		///
+		/// Display and return the address of specified type.
+		/// <para>redeem_script is a hex-string.</para>
+		/// <para>Retrieve the public key at the specified BIP32 derivation path.</para>
+		///
+		/// <remarks>
+		/// Return {"address": <base58 or bech32 address string>}.
+		/// </remarks>
 		DisplayAddress,
+
+		///
+		/// Setup the HID device.
+		///
+		/// <para>Must return a dictionary with the "success" key, possibly including also "error" and "code".</para>
+		///
+		/// <remarks>
+		/// Return {"success": bool, "error": str, "code": int}.
+		/// </remarks>
 		Setup,
+
+		///
+		/// Wipe the HID device.
+		///
+		/// <para>Must return a dictionary with the "success" key, possibly including also "error" and "code".</para>
+		///
+		/// <remarks>
+		/// Return {"success": bool, "error": srt, "code": int}.
+		/// </remarks>
 		Wipe,
+
+		///
+		/// Restore the HID device from mnemonic.
+		///
+		/// <para>Must return a dictionary with the "success" key, possibly including also "error" and "code".</para>
+		///
+		/// <remarks>
+		/// Return {"success": bool, "error": srt, "code": int}.
+		/// </remarks>
 		Restore,
+
+		///
+		/// Backup the HID device.
+		///
+		/// <para>Must return a dictionary with the "success" key, possibly including also "error" and "code".</para>
+		///
+		/// <remarks>
+		/// Return {"success": bool, "error": srt, "code": int}.
+		/// </remarks>
 		Backup,
+
+		///
+		/// Prompt for PIN.
+		///
+		/// <para>Must return a dictionary with the "success" key, possibly including also "error" and "code".</para>
+		///
+		/// <remarks>
+		/// Return {"success": bool, "error": srt, "code": int}.
+		/// </remarks>
 		PromptPin,
+
+		///
+		/// Send PIN.
+		///
+		/// <para>Must return a dictionary with the "success" key, possibly including also "error" and "code".</para>
+		///
+		/// <remarks>
+		/// Return {"success": bool, "error": srt, "code": int}.
+		/// </remarks>
 		SendPin
 	}
 }


formatting

formatting

--- King.BTrak.Program/Program.cs
+++ King.BTrak.Program/Program.cs
@@ -23,7 +23,11 @@
                 var parameters = new Parameters(args);
                 var config = parameters.Process();

-                Trace.TraceInformation("{0}{3}{1}{3}{2}{3}", config.SQLConenctionString, config.StorageAccountConnectionString, config.StorageTableName, Environment.NewLine);
+                Trace.TraceInformation("SQL Server Connection String: '{0}'{3}Storage Account: '{1}'{3}Table Name: '{2}'{3}"
+                    , config.SQLConenctionString
+                    , config.StorageAccountConnectionString
+                    , config.StorageTableName
+                    , Environment.NewLine);

                 var database = new SqlConnection(config.SQLConenctionString);
                 var table = new TableStorage(config.StorageTableName, config.StorageAccountConnectionString);


Fix MainForm

Fix MainForm

--- KugelmatikControl/MainForm.cs
+++ KugelmatikControl/MainForm.cs
@@ -28,6 +28,7 @@
         private ClusterForm clusterForm;
         private PingPongForm pingPongForm;
         private HeightViewForm heightViewForm;
+        private SearchForm searchForm;

         public MainForm()
         {
@@ -47,6 +48,7 @@
             CloseWindow(clusterForm);
             CloseWindow(pingPongForm);
             CloseWindow(heightViewForm);
+            CloseWindow(searchForm);
         }

         private void CloseWindow(Form form)
@@ -532,6 +534,12 @@
                 ShowForm(heightViewForm, () => heightViewForm = new HeightViewForm(Kugelmatik));
         }

+        private void searchClustersToolStripMenuItem_Click(object sender, EventArgs e)
+        {
+            if (Kugelmatik != null)
+                ShowForm(searchForm, () => searchForm = new SearchForm(Kugelmatik.Config));
+        }
+
         private void resetRevisionToolStripMenuItem_Click(object sender, EventArgs e)
         {
             if (Kugelmatik == null)


ContainerBindings - make it successfully fall back and create a cache even when Azure SDK is not installed. (fixes: unhandled TypeInitializationException during startup)

--- Website/App_Start/ContainerBindings.cs
+++ Website/App_Start/ContainerBindings.cs
@@ -38,8 +38,8 @@
             Bind<ISearchService>()
                 .To<LuceneSearchService>()
                 .InRequestScope();
-
-            if (RoleEnvironment.IsAvailable)
+
+            if (CanBindCache())
             {
                 // when running on Windows Azure, use the Azure Cache service
                 Bind<ICacheService>()
@@ -243,5 +243,22 @@
                 .To<PackageVersionsQuery>()
                 .InRequestScope();
         }
+
+        private bool CanBindCache()
+        {
+            try
+            {
+                if (RoleEnvironment.IsAvailable)
+                {
+                    return true;
+                }
+            }
+            catch (TypeInitializationException)
+            {
+                // Catch 'Could not load file or assembly 'msshrtmi' from not having Azure SDK installed.
+            }
+
+            return false;
+        }
     }
 }


[WPF] Fix Label wrapping issue

[WPF] Fix Label wrapping issue

--- Xwt.WPF/Xwt.WPFBackend/LabelBackend.cs
+++ Xwt.WPF/Xwt.WPFBackend/LabelBackend.cs
@@ -53,6 +53,17 @@
 			get { return (ILabelEventSink)base.EventSink; }
 		}

+		public override Size GetPreferredSize (SizeConstraint widthConstraint, SizeConstraint heightConstraint)
+		{
+			var s = base.GetPreferredSize (widthConstraint, heightConstraint);
+
+			// If the label is ellipsized or can wrap then the width can't be dermined unless we have a constraint.
+			// If there is no constraint, just return the smallest size
+			if (!widthConstraint.IsConstrained && (Wrap != WrapMode.None || Ellipsize != EllipsizeMode.None))
+				s.Width = 1;
+			return s;
+		}
+
 		public string Text {
 			get { return Label.TextBlock.Text; }
 			set {
@@ -185,6 +196,7 @@
 					Label.TextBlock.TextTrimming = TextTrimming.None;
 				else
 					Label.TextBlock.TextTrimming = TextTrimming.CharacterEllipsis;
+				Widget.InvalidateMeasure ();
 			}
 		}