Improve integration testing for Triggers

--- CakeMail.RestClient.IntegrationTests/Triggers.cs
+++ CakeMail.RestClient.IntegrationTests/Triggers.cs
@@ -1,6 +1,7 @@
 using CakeMail.RestClient.Models;
 using System;
 using System.Linq;
+using System.Threading;

 namespace CakeMail.RestClient.IntegrationTests
 {
@@ -12,7 +13,9 @@
 			Console.WriteLine(new string('-', 25));
 			Console.WriteLine("Executing TRIGGERS methods...");

-			var list = api.GetLists(userKey, ListStatus.Active, null, ListsSortBy.Name, SortDirection.Ascending, 1, 0, clientId).First();
+			var listId = api.CreateList(userKey, "INTEGRATION TESTING list for trigger", "Bob Smith", "bobsmith@fictitiouscomapny.com", true, clientId);
+			var listMemberId = api.Subscribe(userKey, listId, "desautelsj@hotmail.com", true, true, null, clientId);
+
 			var campaign = api.GetCampaigns(userKey, CampaignStatus.Ongoing, null, CampaignsSortBy.Name, SortDirection.Ascending, 1, 0, clientId).First();

 			var triggers = api.GetTriggers(userKey, TriggerStatus.Active, null, null, null, null, null, clientId);
@@ -21,13 +24,13 @@
 			var triggersCount = api.GetTriggersCount(userKey, TriggerStatus.Active, null, null, null, clientId);
 			Console.WriteLine("Triggers count = {0}", triggersCount);

-			var triggerId = api.CreateTrigger(userKey, "Integration Testing: trigger", list.Id, campaign.Id, null, null, clientId);
+			var triggerId = api.CreateTrigger(userKey, "Integration Testing: trigger", listId, campaign.Id, null, null, clientId);
 			Console.WriteLine("New trigger created. Id: {0}", triggerId);

 			var trigger = api.GetTrigger(userKey, triggerId, clientId);
 			Console.WriteLine("Trigger retrieved: Name = {0}", trigger.Name);

-			var updated = api.UpdateTrigger(userKey, triggerId, name: "UPDATED INTEGRATION TEST: trigger", htmlContent: "Hello World in HTML. CakeMail web site</body", textContent: "Hello World in text", subject: "This is a test", trackClicksInHtml: true, trackClicksInText: true, trackOpens: true, clientId: clientId);
+			var updated = api.UpdateTrigger(userKey, triggerId, name: "UPDATED INTEGRATION TEST: trigger", htmlContent: "Hello World in HTML. CakeMail web site", textContent: "Hello World in text", subject: "This is a test", trackClicksInHtml: true, trackClicksInText: true, trackOpens: true, clientId: clientId);
 			Console.WriteLine("Trigger updated: {0}", updated ? "success" : "failed");

 			var rawEmail = api.GetTriggerRawEmailMessage(userKey, triggerId, clientId);
@@ -39,6 +42,12 @@
 			var rawText = api.GetTriggerRawText(userKey, triggerId, clientId);
 			Console.WriteLine("Trigger raw text: {0}", rawText);

+			var unleashed = api.UnleashTrigger(userKey, triggerId, listMemberId, clientId);
+			Console.WriteLine("Trigger unleashed: {0}", unleashed ? "success" : "failed");
+
+			// Short pause to allow enough time for the trigger to be sent by CakeMail
+			Thread.Sleep(2000);
+
 			var logs = api.GetTriggerLogs(userKey, triggerId, null, null, false, false, null, null, null, null, clientId);
 			Console.WriteLine("All trigger logs retrieved. Count = {0}", logs.Count());

@@ -48,11 +57,21 @@
 			var linksCount = api.GetTriggerLinksCount(userKey, triggerId, clientId);
 			Console.WriteLine("Trigger links count = {0}", linksCount);

+			var linksLogs = api.GetTriggerLinksLogs(userKey, triggerId, null, null, null, null, clientId);
+			Console.WriteLine("Trigger links logs retrieved. Count = {0}", linksLogs.Count());
+
+			var linksLogsCount = api.GetTriggerLinksLogsCount(userKey, triggerId, null, null, clientId);
+			Console.WriteLine("Trigger links logs count = {0}", linksLogsCount);
+
 			if (links.Any())
 			{
-				var link = api.GetTriggerLink(userKey, links.First().Id, clientId);
-				Console.WriteLine("Trigger link retrieved. URI = {0}", link.Uri);
+				// As of May 2015, CakeMail has not implemented despite documenting in on their web site
+				//var link = api.GetTriggerLink(userKey, links.First().Id, clientId);
+				//Console.WriteLine("Trigger link retrieved. URI = {0}", link.Uri);
 			}
+
+			var deleted = api.DeleteList(userKey, listId, clientId);
+			Console.WriteLine("List deleted: {0}", deleted ? "success" : "failed");

 			Console.WriteLine(new string('-', 25));
 			Console.WriteLine("");


Update FilenameTranslator.cs

Update FilenameTranslator.cs

Adding #SI for filenames to allow sub-index numbering (for example Room-#SI with a count of 4 for a card would return Room-1, Room-2, Room-3, and Room-4.  Important when card deck index doesn't matter but multiples of a particular card with different info based on sub index are.

--- CardMaker/Card/Translation/FilenameTranslator.cs
+++ CardMaker/Card/Translation/FilenameTranslator.cs
@@ -97,7 +97,7 @@
                 }
             }
             // replace ##, #L, Newlines
-            sOutput = sOutput.Replace("##", nCardNumber.ToString(CultureInfo.InvariantCulture).PadLeft(nLeftPad, '0')).Replace("#L", zLayout.Name).Replace(Environment.NewLine, string.Empty);
+            sOutput = sOutput.Replace("##", nCardNumber.ToString(CultureInfo.InvariantCulture).PadLeft(nLeftPad, '0')).Replace("#SI", zCurrentPrintLine.RowSubIndex+1).Replace("#L", zLayout.Name).Replace(Environment.NewLine, string.Empty);

             // last chance: replace unsupported characters (for file name)
             var zBuilder = new StringBuilder();


Move to separate namespace

Move to separate namespace

--- Cascara.Tests/Src/Extensions/AssertExtensions.cs
+++ Cascara.Tests/Src/Extensions/AssertExtensions.cs
@@ -1,7 +1,7 @@
 using System;
 using Xunit;

-namespace Cascara.Tests
+namespace Cascara.Tests.Extensions
 {
     public class AssertExtensions : Assert
     {


Cosmetic fix

Cosmetic fix

--- CheckPointObjects/CheckPointObjectsRepository.cs
+++ CheckPointObjects/CheckPointObjectsRepository.cs
@@ -177,17 +177,17 @@
             return (from objectInfo in _repository where objectInfo.Value.IsPredefined select objectInfo.Value.Object).ToList();
         }

-        public string Port2KnownService(string port, out bool found)
+        public string GetKnownServiceName(string id, out bool found)
         {
             found = false;

-            if (_knownServices.ContainsKey(port))
+            if (_knownServices.ContainsKey(id))
             {
                 found = true;
-                return _knownServices[port];
-            }
-
-            return port;
+                return _knownServices[id];
+            }
+
+            return id;
         }

         public bool IsKnownService(string serviceName)


FilterServiceProvider now checks for available configuration before checking updates. Fixes #113

--- CitadelService/Services/FilterServiceProvider.cs
+++ CitadelService/Services/FilterServiceProvider.cs
@@ -821,7 +821,14 @@
             {
                 m_appcastUpdaterLock.EnterWriteLock();

-                m_lastFetchedUpdate = m_updater.CheckForUpdate(m_userConfig != null ? m_userConfig.UpdateChannel : string.Empty).Result;
+                if (m_userConfig != null)
+                {
+                    m_lastFetchedUpdate = m_updater.CheckForUpdate(m_userConfig != null ? m_userConfig.UpdateChannel : string.Empty).Result;
+                }
+                else
+                {
+                    m_logger.Info("No configuration downloaded yet. Skipping application update checks.");
+                }

                 if (m_lastFetchedUpdate != null && !isSyncButton)
                 {


Pushing authtoken / email fix for registry purge.

--- CitadelService/Services/FilterServiceProvider.cs
+++ CitadelService/Services/FilterServiceProvider.cs
@@ -329,6 +329,31 @@

         private void OnStartup()
         {
+            // Load authtoken and email data from files.
+            try
+            {
+                string appDataPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "CloudVeil");
+                string authTokenPath = Path.Combine(appDataPath, "authtoken.data");
+
+                if(File.Exists(authTokenPath))
+                {
+                    string authToken = File.ReadAllText(authTokenPath);
+                    WebServiceUtil.Default.AuthToken = authToken;
+                }
+
+                string emailPath = Path.Combine(appDataPath, "email.data");
+
+                if(File.Exists(emailPath))
+                {
+                    string email = File.ReadAllText(emailPath);
+                    WebServiceUtil.Default.UserEmail = email;
+                }
+            }
+            catch (Exception e)
+            {
+                m_logger.Warn("Could not load authtoken or email data. User may have to sign back in.");
+            }
+
             // Hook the shutdown/logoff event.
             SystemEvents.SessionEnding += OnAppSessionEnding;

@@ -466,6 +491,37 @@
                                 {
                                     writer.Write("# This file left intentionally blank (tee-hee)\n");
                                 }
+                            }
+
+                            // Save auth token when shutting down for update.
+                            string appDataPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "CloudVeil");
+
+                            try
+                            {
+                                if (StringExtensions.Valid(WebServiceUtil.Default.AuthToken))
+                                {
+                                    string authTokenPath = Path.Combine(appDataPath, "authtoken.data");
+
+                                    using (StreamWriter writer = File.CreateText(authTokenPath))
+                                    {
+                                        writer.Write(WebServiceUtil.Default.AuthToken);
+                                    }
+                                }
+
+                                if (StringExtensions.Valid(WebServiceUtil.Default.UserEmail))
+                                {
+                                    string emailPath = Path.Combine(appDataPath, "email.data");
+
+                                    using (StreamWriter writer = File.CreateText(emailPath))
+                                    {
+                                        writer.Write(WebServiceUtil.Default.UserEmail);
+                                    }
+                                }
+                            }
+                            catch (Exception e)
+                            {
+                                m_logger.Warn("Could not save authtoken or email before update.");
+                                LoggerUtil.RecursivelyLogException(m_logger, e);
                             }

                             Environment.Exit((int)ExitCodes.ShutdownForUpdate);


Added null check for jumping isf vessel is more advanced

--- Client/Systems/VesselDockSys/VesselDockEvents.cs
+++ Client/Systems/VesselDockSys/VesselDockEvents.cs
@@ -159,8 +159,11 @@
         private static void JumpIfVesselOwnerIsInFuture(Guid vesselId)
         {
             var dominantVesselOwner = LockSystem.LockQuery.GetControlLockOwner(vesselId);
-            var dominantVesselOwnerSubspace = SystemsContainer.Get<WarpSystem>().GetPlayerSubspace(dominantVesselOwner);
-            SystemsContainer.Get<WarpSystem>().WarpIfSubspaceIsMoreAdvanced(dominantVesselOwnerSubspace);
+            if (dominantVesselOwner != null)
+            {
+                var dominantVesselOwnerSubspace = SystemsContainer.Get<WarpSystem>().GetPlayerSubspace(dominantVesselOwner);
+                SystemsContainer.Get<WarpSystem>().WarpIfSubspaceIsMoreAdvanced(dominantVesselOwnerSubspace);
+            }
         }

         /// <summary>


If there are no active terms, assigning a null value to the cache would cause an exception. Wrapped it in an if.

git-tfs-id: [https://tfs.caes.ucdavis.edu:8088/tfs]$/Commencement/Trunk/Commencement;C9074

--- Commencement/Controllers/Services/TermService.cs
+++ Commencement/Controllers/Services/TermService.cs
@@ -19,7 +19,10 @@
                 if (term == null)
                 {
                     term = repository.Queryable.Where(a => a.IsActive).OrderByDescending(a => a.Id).FirstOrDefault();
-                    System.Web.HttpContext.Current.Cache[StaticIndexes.CurrentTermKey] = term;
+                    if(term != null)
+                    {
+                        System.Web.HttpContext.Current.Cache[StaticIndexes.CurrentTermKey] = term;
+                    }
                 }

                 return term;


DNN-8573 Suppress X-Frame-Options header by default.


DNN-4415 upgrade to 7.2.0 fails when module creator project is already installed uninstall any old (codeplex) versions of module creator


DMLF SQL format

DMLF SQL format

--- DbShell.Driver.Common/DmlFramework/DmlfSelect.cs
+++ DbShell.Driver.Common/DmlFramework/DmlfSelect.cs
@@ -168,12 +168,12 @@
             if (Having != null) Having.GenSql(dmp);
             if (OrderBy != null && OrderBy.Count > 0)
             {
-                dmp.Put(" ^order ^by ");
+                dmp.Put("&n^order ^by ");
                 OrderBy.GenSql(dmp);
             }
             if (LimitCount != null)
             {
-                dmp.Put(" ^limit %s ^offset %s", LimitCount, Offset);
+                dmp.Put("&n^limit %s ^offset %s", LimitCount, Offset);
             }
         }


UseEndurance and RegenHP methods created and commented a bit more

--- DungeonGame/DungeonGame/Assets/Scripts/Player.cs
+++ DungeonGame/DungeonGame/Assets/Scripts/Player.cs
@@ -29,7 +29,7 @@
 	void Start () {
         this.curhp = GetMaxHP(); //heals player all the way at start

-        //temporary for testing
+        //all stuff below temporary for testing
         helmet = new HeadItem("Helmet Of Doom", 10, 3, 2, 5, 4);
         chest = new ChestItem("Chain Mail Chest", 5, 5, 1, 3, 3);
         //legs = new LegItem("Steel Plated Legs", 5, 2, 7, 3);
@@ -39,20 +39,36 @@
         legs = (LegItem)inventory[0];

         SetStats();
+        UseEndurance();
 	}

 	// Update is called once per frame
 	void Update () {
-
+        RegenHP();
 	}

     //Methods
-    public void SetStats()
+    public void SetStats() //Method SetStats takes all of the stats from equipt armor and applies it to the player
     {
         this.defense = helmet.GetDefense() + chest.GetDefense() + legs.GetDefense() + weapon.GetDefense();
         this.strength = helmet.GetStrength() + chest.GetStrength() + legs.GetStrength() + weapon.GetStrength();
         this.endurance = helmet.GetEndurance() + chest.GetEndurance() + legs.GetEndurance() + weapon.GetEndurance();
         this.crit = helmet.GetCrit() + chest.GetCrit() + legs.GetCrit() + weapon.GetCrit();
+    }
+    public void UseEndurance() //Method UseEndurance takes eache endurance point and adds it to the players float maxHP
+    {
+        maxhp += this.endurance;
+    }
+    public void RegenHP() //Method RegenHP checks if curHp is less than max HP and if it is, it heals the player and stops at maxhp
+    {
+        if (GetCurHP() < GetMaxHP())
+        {
+            this.curhp += Time.deltaTime / 5;
+        }
+        else if(GetCurHP() >= GetMaxHP())
+        {
+            this.curhp = GetMaxHP();
+        }
     }


Level 18

Level 18

--- EarthMagicCharacters/Classes/Monk/GenericMonk.cs
+++ EarthMagicCharacters/Classes/Monk/GenericMonk.cs
@@ -537,7 +537,14 @@
         /// </summary>
         private void Level18()
         {
-            List<string> levelUpReport = new List<string> {   };
+            List<string> levelUpReport = new List<string> { "Title: Master of the West Wind", "Immunity to Non Magical Weapons", "TH: +1", "AC: +1" };
+
+            this.Title = "Master of the West Wind";
+            this.Abilities.ImmunityToNonMagicWeapons = true;
+            this.Attributes.ToHit++;
+            this.Attributes.AC++;
+
+            Util.WriteLine(levelUpReport);
         }

         /// <summary>


removed hidden-xs css class (#533)

removed hidden-xs css class (#533)

--- EmpleoDotNet/Views/Shared/_JobListPartial.cshtml
+++ EmpleoDotNet/Views/Shared/_JobListPartial.cshtml
@@ -42,7 +42,7 @@
                                     @jobOpportunity.JobOpportunityLocation.Name
                                 }

-
@jobOpportunity.Created.ToDominicanFormat()

+
@jobOpportunity.Created.ToDominicanFormat()

                             @if (jobOpportunity.IsRemote)


Add comment

Add comment

--- FonctionsUtiles.Fred.Csharp/FunctionsDateTime.cs
+++ FonctionsUtiles.Fred.Csharp/FunctionsDateTime.cs
@@ -200,6 +200,7 @@
         return true;
       }

+      //return theDate.Year % 100 != 0 && theDate.Year % 400 == 0;
       if (theDate.Year % 100 != 0 && theDate.Year % 400 == 0)
       {
         return true;


Added CancellationToken to Progressor.CreateFromIObservable

--- Framework.Core/Theraot/Collections/Progressor.cs
+++ Framework.Core/Theraot/Collections/Progressor.cs
@@ -108,7 +108,7 @@
             return new Progressor<T>(proxy, Take);
         }

-        public static Progressor<T> CreateFromIObservable(IObservable<T> observable, Action exhaustedCallback = null)
+        public static Progressor<T> CreateFromIObservable(IObservable<T> observable, Action exhaustedCallback = null, CancellationToken token = default)
         {
             if (observable == null)
             {
@@ -139,37 +139,53 @@
             }
             bool TakeInitial(out T value)
             {
-                if (source.IsCancellationRequested)
-                {
-                    if (Interlocked.CompareExchange(ref tryTake[0], TakeReplacement, tryTake[0]) == tryTake[0])
-                    {
-                        Interlocked.Exchange(ref subscription, null)?.Dispose();
-                    }
-                }
-                else
-                {
-                    if (exhaustedCallback != null)
-                    {
-                        var spinWait = new SpinWait();
-                        while (semaphore.CurrentCount == 0 && !source.IsCancellationRequested)
-                        {
-                            exhaustedCallback();
-                            spinWait.SpinOnce();
-                        }
-                    }
-                }
-                if (!source.IsCancellationRequested)
-                {
-                    try
-                    {
-                        semaphore.Wait(source.Token);
-                    }
-                    catch (OperationCanceledException exception)
-                    {
-                        GC.KeepAlive(exception);
-                    }
-                }
-                return TakeReplacement(out value);
+                if (!token.IsCancellationRequested)
+                {
+                    if (source.IsCancellationRequested)
+                    {
+                        if (Interlocked.CompareExchange(ref tryTake[0], TakeReplacement, tryTake[0]) == tryTake[0])
+                        {
+                            Interlocked.Exchange(ref subscription, null)?.Dispose();
+                        }
+                    }
+                    else
+                    {
+                        if (exhaustedCallback != null)
+                        {
+                            var spinWait = new SpinWait();
+                            while (semaphore.CurrentCount == 0 && !source.IsCancellationRequested &&
+                                   !token.IsCancellationRequested)
+                            {
+                                exhaustedCallback();
+                                spinWait.SpinOnce();
+                            }
+                            if (token.IsCancellationRequested)
+                            {
+                                Interlocked.Exchange(ref subscription, null)?.Dispose();
+                                value = default;
+                                return false;
+                            }
+                        }
+                    }
+                }
+                if (!token.IsCancellationRequested)
+                {
+                    if (!source.IsCancellationRequested)
+                    {
+                        try
+                        {
+                            semaphore.Wait(source.Token);
+                        }
+                        catch (OperationCanceledException exception)
+                        {
+                            GC.KeepAlive(exception);
+                        }
+                    }
+                    return TakeReplacement(out value);
+                }
+                Interlocked.Exchange(ref subscription, null)?.Dispose();
+                value = default;
+                return false;
             }
             bool TakeReplacement(out T value)
             {


update SlotItemType string

update SlotItemType string

--- Grabacr07.KanColleWrapper/Models/SlotItemType.cs
+++ Grabacr07.KanColleWrapper/Models/SlotItemType.cs
@@ -163,6 +163,9 @@
 			{SlotItemIconType.LandingCraft, "上陸用舟艇"},
 			{SlotItemIconType.Autogyro, "オートジャイロ"},
 			{SlotItemIconType.ArtillerySpotter, "指揮連絡機"},
+			{SlotItemIconType.AntiTorpedoBulge, "増設バルジ"},
+			{SlotItemIconType.Searchlight, "探照灯"},
+			{SlotItemIconType.DrumCanister, "ドラム缶"},
 		};
 	}
 }


JIRA search was not returning IssueType field.

--- IntegrationService.Targets.JIRA/JiraSubsystem.cs
+++ IntegrationService.Targets.JIRA/JiraSubsystem.cs
@@ -351,7 +351,7 @@
 			//https://yoursite.atlassian.net/rest/api/latest/search?jql=project=%22More+Tests%22+and+status=%22open%22+and+created+%3E+%222008/12/31+12:00%22+order+by+created+asc&fields=id,status,priority,summary,description
 			var request = new RestRequest("/rest/api/latest/search", Method.GET);
 			request.AddParameter("jql", jqlQuery);
-			request.AddParameter("fields", "id,status,priority,summary,description,type,assignee,duedate,labels");
+			request.AddParameter("fields", "id,status,priority,summary,description,issuetype,type,assignee,duedate,labels");
 	        request.AddParameter("maxResults", "9999");

 			var jiraResp = _restClient.Execute(request);
@@ -374,7 +374,7 @@
 				foreach (var issue in issues)
  				{
 					Log.Info("Issue [{0}]: {1}, {2}, {3}", issue.Key, issue.Fields.Summary, issue.Fields.Status.Name, issue.Fields.Priority.Name);
-
+
 					// does this workitem have a corresponding card?
 					var card = LeanKit.GetCardByExternalId(project.Identity.LeanKit, issue.Key);

@@ -795,7 +795,7 @@
 		{
 			public long Id { get; set; }
 			public string Key { get; set; }
-			public Fields Fields { get; set; }
+			public Fields Fields { get; set; }

 			public Issue()
 			{


Use static strings as expected in firewall tests

Signed-off-by: John_Shahid <7c84c4d4148af24079897a92115d562877358578@pivotal.io>

--- IronFrame.Test/Utilities/FirewallManagerTests.cs
+++ IronFrame.Test/Utilities/FirewallManagerTests.cs
@@ -75,8 +75,8 @@
                 manager.CreateOutboundFirewallRule(Username, firewallRuleSpec);
                 var rule = (INetFwRule3)firewallPolicy.Rules.Item(Username);
                 CheckCommonRuleProperties(rule);
-                Assert.Equal(rule.Protocol, (int)NET_FW_IP_PROTOCOL_.NET_FW_IP_PROTOCOL_TCP);
-                Assert.Equal(firewallRuleSpec.RemoteAddresses, rule.RemoteAddresses);
+                Assert.Equal((int)NET_FW_IP_PROTOCOL_.NET_FW_IP_PROTOCOL_TCP, rule.Protocol);
+                Assert.Equal("10.1.1.1-10.1.10.10", rule.RemoteAddresses);
                 Assert.Equal("*", rule.RemotePorts);
             }

@@ -94,9 +94,9 @@
                 manager.CreateOutboundFirewallRule(Username, firewallSpec);
                 var rule = (INetFwRule3)firewallPolicy.Rules.Item(Username);
                 CheckCommonRuleProperties(rule);
-                Assert.Equal(rule.Protocol, (int)NET_FW_IP_PROTOCOL_.NET_FW_IP_PROTOCOL_TCP);
+                Assert.Equal((int)NET_FW_IP_PROTOCOL_.NET_FW_IP_PROTOCOL_TCP, rule.Protocol);
                 Assert.Equal("*", rule.RemoteAddresses);
-                Assert.Equal(firewallSpec.RemotePorts, rule.RemotePorts);
+                Assert.Equal("8080-8090", rule.RemotePorts);
             }

             [FactAdminRequired]
@@ -118,9 +118,9 @@
                 manager.CreateOutboundFirewallRule(Username, firewallSpec);
                 var rule = (INetFwRule3)firewallPolicy.Rules.Item(Username);
                 CheckCommonRuleProperties(rule);
-                Assert.Equal(rule.Protocol, (int)NET_FW_IP_PROTOCOL_.NET_FW_IP_PROTOCOL_TCP);
-                Assert.Equal(firewallSpec.RemoteAddresses, rule.RemoteAddresses);
-                Assert.Equal(firewallSpec.RemotePorts, rule.RemotePorts);
+                Assert.Equal((int)NET_FW_IP_PROTOCOL_.NET_FW_IP_PROTOCOL_TCP, rule.Protocol);
+                Assert.Equal("10.1.1.1-10.1.1.100", rule.RemoteAddresses);
+                Assert.Equal("8080-8090", rule.RemotePorts);
             }
         }

@@ -142,16 +142,16 @@
                 // On windows we have to create two rules one for tcp and another for udp
                 var rule = (INetFwRule3)firewallPolicy.Rules.Item(Username);
                 CheckCommonRuleProperties(rule);
-                Assert.Equal(rule.Protocol, (int)NET_FW_IP_PROTOCOL_.NET_FW_IP_PROTOCOL_TCP);
-                Assert.Equal(firewallSpec.RemoteAddresses, rule.RemoteAddresses);
-                Assert.Equal(firewallSpec.RemotePorts, rule.RemotePorts);
+                Assert.Equal((int)NET_FW_IP_PROTOCOL_.NET_FW_IP_PROTOCOL_TCP, rule.Protocol);
+                Assert.Equal("*", rule.RemoteAddresses);
+                Assert.Equal("8080-8090", rule.RemotePorts);
                 firewallPolicy.Rules.Remove(Username);

                 rule = (INetFwRule3)firewallPolicy.Rules.Item(Username);
                 CheckCommonRuleProperties(rule);
-                Assert.Equal(rule.Protocol, (int)NET_FW_IP_PROTOCOL_.NET_FW_IP_PROTOCOL_UDP);
-                Assert.Equal(firewallSpec.RemoteAddresses, rule.RemoteAddresses);
-                Assert.Equal(firewallSpec.RemotePorts, rule.RemotePorts);
+                Assert.Equal((int)NET_FW_IP_PROTOCOL_.NET_FW_IP_PROTOCOL_UDP, rule.Protocol);
+                Assert.Equal("*", rule.RemoteAddresses);
+                Assert.Equal("8080-8090", rule.RemotePorts);
             }
         };

@@ -176,9 +176,9 @@
                 manager.CreateOutboundFirewallRule(Username, firewallSpec);
                 var rule = (INetFwRule3)firewallPolicy.Rules.Item(Username);
                 CheckCommonRuleProperties(rule);
-                Assert.Equal(rule.Protocol, (int)NET_FW_IP_PROTOCOL_.NET_FW_IP_PROTOCOL_UDP);
-                Assert.Equal(firewallSpec.RemoteAddresses, rule.RemoteAddresses);
-                Assert.Equal(firewallSpec.RemotePorts, rule.RemotePorts);
+                Assert.Equal((int)NET_FW_IP_PROTOCOL_.NET_FW_IP_PROTOCOL_UDP, rule.Protocol);
+                Assert.Equal("10.1.1.1-10.1.1.100", rule.RemoteAddresses);
+                Assert.Equal("8080-8090", rule.RemotePorts);
             }
         };


Fixed bug for anon game browsing

Fixed bug for anon game browsing

--- Joinrpg/Controllers/Common/ControllerGameBase.cs
+++ Joinrpg/Controllers/Common/ControllerGameBase.cs
@@ -60,40 +60,42 @@
       ViewBag.ProjectId = project.ProjectId;

       var acl = project.ProjectAcls.FirstOrDefault(a => a.UserId == CurrentUserIdOrDefault);
-      //TODO[GroupsLoad]. If we not loaded groups already, that's slow
-      var bigGroups =
-        project.RootGroup.ChildGroups.Where(
-            cg => !cg.IsSpecial && cg.IsActive && cg.IsVisible(CurrentUserId))
-          .Select(cg => new CharacterGroupLinkViewModel(cg));
+
+      MenuViewModelBase menuModel;
       if (acl != null)
       {
-        ViewBag.MasterMenu = new MasterMenuViewModel
+        menuModel = new MasterMenuViewModel()
         {
-          ProjectId = project.ProjectId,
-          ProjectName = project.ProjectName,
-          AccessToProject = acl,
-          BigGroups = bigGroups,
-          IsAcceptingClaims = project.IsAcceptingClaims,
-          IsActive = project.Active,
-          RootGroupId = project.RootGroup.CharacterGroupId,
-          IsAdmin = IsCurrentUserAdmin(),
+          AccessToProject = acl
         };
       }
       else
       {
-        ViewBag.PlayerMenu = new PlayerMenuViewModel
+        menuModel = new PlayerMenuViewModel()
         {
-          ProjectId = project.ProjectId,
-          ProjectName = project.ProjectName,
-          Claims =
-            project.Claims.OfUserActive(CurrentUserIdOrDefault).Select(c => new ClaimShortListItemViewModel(c)).ToArray(),
-          BigGroups = bigGroups,
-          IsAcceptingClaims = project.IsAcceptingClaims,
-          IsActive = project.Active,
-          RootGroupId = project.RootGroup.IsAvailable ? (int?) project.RootGroup.CharacterGroupId : null,
-          PlotPublished = project.Details.PublishPlot,
-          IsAdmin = IsCurrentUserAdmin(),
+          Claims = project.Claims.OfUserActive(CurrentUserIdOrDefault).Select(c => new ClaimShortListItemViewModel(c)).ToArray(),
+          PlotPublished = project.Details.PublishPlot
         };
+      }
+      menuModel.ProjectId = project.ProjectId;
+      menuModel.ProjectName = project.ProjectName;
+      //TODO[GroupsLoad]. If we not loaded groups already, that's slow
+      menuModel.BigGroups = project.RootGroup.ChildGroups.Where(
+          cg => !cg.IsSpecial && cg.IsActive && cg.IsVisible(CurrentUserIdOrDefault))
+        .Select(cg => new CharacterGroupLinkViewModel(cg)).ToList();
+      menuModel.IsAcceptingClaims = project.IsAcceptingClaims;
+      menuModel.IsActive = project.Active;
+      menuModel.RootGroupId = project.RootGroup.CharacterGroupId;
+      menuModel.IsAdmin = IsCurrentUserAdmin();
+
+
+      if (acl != null)
+      {
+        ViewBag.MasterMenu = menuModel;
+      }
+      else
+      {
+        ViewBag.PlayerMenu = menuModel;
       }
     }


LiveScmController.Delete should take the lock during the deletion

--- Kudu.Services/SourceControl/LiveScmController.cs
+++ Kudu.Services/SourceControl/LiveScmController.cs
@@ -55,44 +55,40 @@
         public void Delete(int deleteWebRoot = 0)
         {
             // Fail if a deployment is in progress
-            if (_deploymentLock.IsHeld)
+            _deploymentLock.LockOperation(() =>
+            {
+                using (_tracer.Step("Deleting deployment cache"))
+                {
+                    // Delete the deployment cache
+                    FileSystemHelpers.DeleteDirectorySafe(_environment.DeploymentCachePath);
+                }
+
+                using (_tracer.Step("Deleting repository"))
+                {
+                    // Delete the repository
+                    FileSystemHelpers.DeleteDirectorySafe(_environment.RepositoryPath);
+                }
+
+                using (_tracer.Step("Deleting ssh key"))
+                {
+                    // Delete the ssh key
+                    FileSystemHelpers.DeleteDirectorySafe(_environment.SSHKeyPath);
+                }
+
+                if (deleteWebRoot != 0)
+                {
+                    using (_tracer.Step("Deleting web root"))
+                    {
+                        // Delete the wwwroot folder
+                        FileSystemHelpers.DeleteDirectoryContentsSafe(_environment.WebRootPath);
+                    }
+                }
+            },
+            () =>
             {
                 HttpResponseMessage response = Request.CreateErrorResponse(HttpStatusCode.Conflict, Resources.Error_DeploymentInProgess);
                 throw new HttpResponseException(response);
-            }
-
-            using (_tracer.Step("Deleting deployment cache"))
-            {
-                // Delete the deployment cache
-                FileSystemHelpers.DeleteDirectorySafe(_environment.DeploymentCachePath);
-            }
-
-            using (_tracer.Step("Deleting repository"))
-            {
-                // Delete the repository
-                FileSystemHelpers.DeleteDirectorySafe(_environment.RepositoryPath);
-            }
-
-            using (_tracer.Step("Deleting ssh key"))
-            {
-                // Delete the ssh key
-                FileSystemHelpers.DeleteDirectorySafe(_environment.SSHKeyPath);
-            }
-
-            using (_tracer.Step("Deleting diagnostics"))
-            {
-                // Delete the repository
-                FileSystemHelpers.DeleteDirectorySafe(_environment.DiagnosticsPath);
-            }
-
-            if (deleteWebRoot != 0)
-            {
-                using (_tracer.Step("Deleting web root"))
-                {
-                    // Delete the wwwroot folder
-                    FileSystemHelpers.DeleteDirectoryContentsSafe(_environment.WebRootPath);
-                }
-            }
+            });
         }

         /// <summary>


Fix IMin

Fix IMin

IMin constant was `Int32.MaxValue` and should be `Int32.MinValue`

--- LanguageExt.Core/ClassInstances/Const/Integer.cs
+++ LanguageExt.Core/ClassInstances/Const/Integer.cs
@@ -284,7 +284,7 @@
     public struct I536870912 : Const<int> { public int Value => 536870912; }
     public struct I1073741824 : Const<int> { public int Value => 1073741824; }
     public struct IMax : Const<int> { public int Value => Int32.MaxValue; }
-    public struct IMin : Const<int> { public int Value => Int32.MaxValue; }
+    public struct IMin : Const<int> { public int Value => Int32.MinValue; }

     // 100s up to 10,000
     public struct I300 : Const<int> { public int Value => 300; }


Removed randomly placed semi-colon

Removed randomly placed semi-colon

--- Libraries/FarmhandGame/SerializableDictionary.cs
+++ Libraries/FarmhandGame/SerializableDictionary.cs
@@ -25,7 +25,7 @@
             [InputBind(typeof(XmlReader), "reader")] XmlReader reader)
         {
             return ReadXmlGeneric<TKey, TValue>(@this, reader);
-;        }
+        }

         [Hook(HookType.Entry, "StardewValley.SerializableDictionary`2", "WriteXml")]
         internal static bool WriteXmlOverride<TKey, TValue>([ThisBind] object @this,


refactor Lookup Anything's item subject a bit

--- LookupAnything/Framework/Subjects/ItemSubject.cs
+++ LookupAnything/Framework/Subjects/ItemSubject.cs
@@ -73,7 +73,6 @@
             // get data
             Item item = this.Target;
             SObject obj = item as SObject;
-            bool isObject = obj != null;
             bool isCrop = this.FromCrop != null;
             bool isSeed = this.SeedForCrop != null;
             bool isDeadCrop = this.FromCrop?.dead.Value == true;
@@ -100,81 +99,8 @@
             }

             // crop fields
-            if (isCrop || isSeed)
-            {
-                // get crop
-                Crop crop = this.FromCrop ?? this.SeedForCrop;
-
-                // get harvest schedule
-                int harvestablePhase = crop.phaseDays.Count - 1;
-                bool canHarvestNow = (crop.currentPhase.Value >= harvestablePhase) && (!crop.fullyGrown.Value || crop.dayOfCurrentPhase.Value <= 0);
-                int daysToFirstHarvest = crop.phaseDays.Take(crop.phaseDays.Count - 1).Sum(); // ignore harvestable phase
-
-                // add next-harvest field
-                if (isCrop)
-                {
-                    // calculate next harvest
-                    int daysToNextHarvest = 0;
-                    SDate dayOfNextHarvest = null;
-                    if (!canHarvestNow)
-                    {
-                        // calculate days until next harvest
-                        int daysUntilLastPhase = daysToFirstHarvest - crop.dayOfCurrentPhase.Value - crop.phaseDays.Take(crop.currentPhase.Value).Sum();
-                        {
-                            // growing: days until next harvest
-                            if (!crop.fullyGrown.Value)
-                                daysToNextHarvest = daysUntilLastPhase;
-
-                            // regrowable crop harvested today
-                            else if (crop.dayOfCurrentPhase.Value >= crop.regrowAfterHarvest.Value)
-                                daysToNextHarvest = crop.regrowAfterHarvest.Value;
-
-                            // regrowable crop
-                            else
-                                daysToNextHarvest = crop.dayOfCurrentPhase.Value; // dayOfCurrentPhase decreases to 0 when fully grown, where <=0 is harvestable
-                        }
-                        dayOfNextHarvest = SDate.Now().AddDays(daysToNextHarvest);
-                    }
-
-                    // generate field
-                    string summary;
-                    if (canHarvestNow)
-                        summary = this.Translate(L10n.Crop.HarvestNow);
-                    else if (Game1.currentLocation.Name != Constant.LocationNames.Greenhouse && !crop.seasonsToGrowIn.Contains(dayOfNextHarvest.Season))
-                        summary = this.Translate(L10n.Crop.HarvestTooLate, new { date = this.Stringify(dayOfNextHarvest) });
-                    else
-                        summary = $"{this.Stringify(dayOfNextHarvest)} ({this.Text.GetPlural(daysToNextHarvest, L10n.Generic.Tomorrow, L10n.Generic.InXDays).Tokens(new { count = daysToNextHarvest })})";
-
-                    yield return new GenericField(this.GameHelper, this.Translate(L10n.Crop.Harvest), summary);
-                }
-
-                // crop summary
-                {
-                    List<string> summary = new List<string>();
-
-                    // harvest
-                    summary.Add(crop.regrowAfterHarvest.Value == -1
-                        ? this.Translate(L10n.Crop.SummaryHarvestOnce, new { daysToFirstHarvest = daysToFirstHarvest })
-                        : this.Translate(L10n.Crop.SummaryHarvestMulti, new { daysToFirstHarvest = daysToFirstHarvest, daysToNextHarvests = crop.regrowAfterHarvest })
-                    );
-
-                    // seasons
-                    summary.Add(this.Translate(L10n.Crop.SummarySeasons, new { seasons = string.Join(", ", this.Text.GetSeasonNames(crop.seasonsToGrowIn)) }));
-
-                    // drops
-                    if (crop.minHarvest != crop.maxHarvest && crop.chanceForExtraCrops.Value > 0)
-                        summary.Add(this.Translate(L10n.Crop.SummaryDropsXToY, new { min = crop.minHarvest, max = crop.maxHarvest, percent = Math.Round(crop.chanceForExtraCrops.Value * 100, 2) }));
-                    else if (crop.minHarvest.Value > 1)
-                        summary.Add(this.Translate(L10n.Crop.SummaryDropsX, new { count = crop.minHarvest }));
-
-                    // crop sale price
-                    Item drop = this.GameHelper.GetObjectBySpriteIndex(crop.indexOfHarvest.Value);
-                    summary.Add(this.Translate(L10n.Crop.SummarySellsFor, new { price = GenericField.GetSaleValueString(this.GetSaleValue(drop, false, metadata), 1, this.Text) }));
-
-                    // generate field
-                    yield return new GenericField(this.GameHelper, this.Translate(L10n.Crop.Summary), "-" + string.Join($"{Environment.NewLine}-", summary));
-                }
-            }
+            foreach (ICustomField field in this.GetCropFields(this.FromCrop ?? this.SeedForCrop, isCrop, metadata))
+                yield return field;

             // indoor pot crop
             if (obj is IndoorPot pot)
@@ -187,112 +113,16 @@
                 }
             }

-            // held object
-            if (obj?.heldObject?.Value != null)
-            {
-                if (obj is Cask cask)
-                {
-                    // get cask data
-                    SObject agingObj = cask.heldObject.Value;
-                    ItemQuality curQuality = (ItemQuality)agingObj.Quality;
-                    string curQualityName = this.Translate(L10n.For(curQuality));
-
-                    // calculate aging schedule
-                    float effectiveAge = metadata.Constants.CaskAgeSchedule.Values.Max() - cask.daysToMature.Value;
-                    var schedule =
-                        (
-                            from entry in metadata.Constants.CaskAgeSchedule
-                            let quality = entry.Key
-                            let baseDays = entry.Value
-                            where baseDays > effectiveAge
-                            orderby baseDays ascending
-                            let daysLeft = (int)Math.Ceiling((baseDays - effectiveAge) / cask.agingRate.Value)
-                            select new
-                            {
-                                Quality = quality,
-                                DaysLeft = daysLeft,
-                                HarvestDate = SDate.Now().AddDays(daysLeft)
-                            }
-                        )
-                        .ToArray();
-
-                    // display fields
-                    yield return new ItemIconField(this.GameHelper, this.Translate(L10n.Item.Contents), obj.heldObject.Value);
-                    if (cask.MinutesUntilReady <= 0 || !schedule.Any())
-                        yield return new GenericField(this.GameHelper, this.Translate(L10n.Item.CaskSchedule), this.Translate(L10n.Item.CaskScheduleNow, new { quality = curQualityName }));
-                    else
-                    {
-                        string scheduleStr = string.Join(Environment.NewLine, (
-                            from entry in schedule
-                            let tokens = new { quality = this.Translate(L10n.For(entry.Quality)), count = entry.DaysLeft, date = entry.HarvestDate }
-                            let str = this.Text.GetPlural(entry.DaysLeft, L10n.Item.CaskScheduleTomorrow, L10n.Item.CaskScheduleInXDays).Tokens(tokens)
-                            select $"-{str}"
-                        ));
-                        yield return new GenericField(this.GameHelper, this.Translate(L10n.Item.CaskSchedule), this.Translate(L10n.Item.CaskSchedulePartial, new { quality = curQualityName }) + Environment.NewLine + scheduleStr);
-                    }
-                }
-                else if (obj is Furniture)
-                {
-                    string summary = this.Translate(L10n.Item.ContentsPlaced, new { name = obj.heldObject.Value.DisplayName });
-                    yield return new ItemIconField(this.GameHelper, this.Translate(L10n.Item.Contents), obj.heldObject.Value, summary);
-                }
-                else if (obj.ParentSheetIndex == Constant.ObjectIndexes.AutoGrabber)
-                {
-                    string readyText = this.Text.Stringify(obj.heldObject.Value is Chest output && output.items.Any());
-                    yield return new GenericField(this.GameHelper, this.Translate(L10n.Item.Contents), readyText);
-                }
-                else
-                {
-                    string summary = obj.MinutesUntilReady <= 0
-                        ? this.Translate(L10n.Item.ContentsReady, new { name = obj.heldObject.Value.DisplayName })
-                        : this.Translate(L10n.Item.ContentsPartial, new { name = obj.heldObject.Value.DisplayName, time = this.Stringify(TimeSpan.FromMinutes(obj.MinutesUntilReady)) });
-                    yield return new ItemIconField(this.GameHelper, this.Translate(L10n.Item.Contents), obj.heldObject.Value, summary);
-                }
-            }
+            // machine output
+            foreach (ICustomField field in this.GetMachineOutputFields(obj, metadata))
+                yield return field;

             // item
             if (showInventoryFields)
             {
                 // needed for
-                {
-                    List<string> neededFor = new List<string>();
-
-                    // bundles
-                    if (isObject)
-                    {
-                        string[] bundles = (
-                            from bundle in this.GetUnfinishedBundles(obj)
-                            orderby bundle.Area, bundle.DisplayName
-                            let countNeeded = this.GetIngredientCountNeeded(bundle, obj)
-                            select countNeeded > 1
-                                ? $"{this.GetTranslatedBundleArea(bundle)}: {bundle.DisplayName} x {countNeeded}"
-                                : $"{this.GetTranslatedBundleArea(bundle)}: {bundle.DisplayName}"
-                        ).ToArray();
-                        if (bundles.Any())
-                            neededFor.Add(this.Translate(L10n.Item.NeededForCommunityCenter, new { bundles = string.Join(", ", bundles) }));
-                    }
-
-                    // polyculture achievement
-                    if (isObject && metadata.Constants.PolycultureCrops.Contains(obj.ParentSheetIndex))
-                    {
-                        int needed = metadata.Constants.PolycultureCount - this.GameHelper.GetShipped(obj.ParentSheetIndex);
-                        if (needed > 0)
-                            neededFor.Add(this.Translate(L10n.Item.NeededForPolyculture, new { count = needed }));
-                    }
-
-                    // full shipment achievement
-                    if (isObject && this.GameHelper.GetFullShipmentAchievementItems().Any(p => p.Key == obj.ParentSheetIndex && !p.Value))
-                        neededFor.Add(this.Translate(L10n.Item.NeededForFullShipment));
-
-                    // a full collection achievement
-                    LibraryMuseum museum = Game1.locations.OfType<LibraryMuseum>().FirstOrDefault();
-                    if (museum != null && museum.isItemSuitableForDonation(obj))
-                        neededFor.Add(this.Translate(L10n.Item.NeededForFullCollection));
-
-                    // yield
-                    if (neededFor.Any())
-                        yield return new GenericField(this.GameHelper, this.Translate(L10n.Item.NeededFor), string.Join(", ", neededFor));
-                }
+                foreach (ICustomField field in this.GetNeededForFields(obj, metadata))
+                    yield return field;

                 // sale data
                 if (canSell && !isCrop)
@@ -318,7 +148,7 @@
                 // gift tastes
                 var giftTastes = this.GetGiftTastes(item, metadata);
                 yield return new ItemGiftTastesField(this.GameHelper, this.Translate(L10n.Item.LovesThis), giftTastes, GiftTaste.Love);
-                yield return new ItemGiftTastesField(this.GameHelper,this.Translate(L10n.Item.LikesThis), giftTastes, GiftTaste.Like);
+                yield return new ItemGiftTastesField(this.GameHelper, this.Translate(L10n.Item.LikesThis), giftTastes, GiftTaste.Like);
             }

             // fence
@@ -328,7 +158,7 @@

                 // health
                 if (Game1.getFarm().isBuildingConstructed(Constant.BuildingNames.GoldClock))
-                    yield return new GenericField(this.GameHelper,healthLabel, this.Translate(L10n.Item.FenceHealthGoldClock));
+                    yield return new GenericField(this.GameHelper, healthLabel, this.Translate(L10n.Item.FenceHealthGoldClock));
                 else
                 {
                     float maxHealth = fence.isGate.Value ? fence.maxHealth.Value * 2 : fence.maxHealth.Value;
@@ -478,6 +308,207 @@
             return !string.IsNullOrWhiteSpace(categoryName)
                 ? categoryName
                 : this.Translate(L10n.Types.Other);
+        }
+
+        /// Get the custom fields for a crop.
+        /// <param name="crop">The crop to represent.</param>
+        /// <param name="isSeed">Whether the crop being displayed is for an unplanted seed.</param>
+        /// <param name="metadata">Provides metadata that's not available from the game data directly.</param>
+        private IEnumerable<ICustomField> GetCropFields(Crop crop, bool isSeed, Metadata metadata)
+        {
+            if (crop == null)
+                yield break;
+
+            // get harvest schedule
+            int harvestablePhase = crop.phaseDays.Count - 1;
+            bool canHarvestNow = (crop.currentPhase.Value >= harvestablePhase) && (!crop.fullyGrown.Value || crop.dayOfCurrentPhase.Value <= 0);
+            int daysToFirstHarvest = crop.phaseDays.Take(crop.phaseDays.Count - 1).Sum(); // ignore harvestable phase
+
+            // add next-harvest field
+            if (!isSeed)
+            {
+                // calculate next harvest
+                int daysToNextHarvest = 0;
+                SDate dayOfNextHarvest = null;
+                if (!canHarvestNow)
+                {
+                    // calculate days until next harvest
+                    int daysUntilLastPhase = daysToFirstHarvest - crop.dayOfCurrentPhase.Value - crop.phaseDays.Take(crop.currentPhase.Value).Sum();
+                    {
+                        // growing: days until next harvest
+                        if (!crop.fullyGrown.Value)
+                            daysToNextHarvest = daysUntilLastPhase;
+
+                        // regrowable crop harvested today
+                        else if (crop.dayOfCurrentPhase.Value >= crop.regrowAfterHarvest.Value)
+                            daysToNextHarvest = crop.regrowAfterHarvest.Value;
+
+                        // regrowable crop
+                        else
+                            daysToNextHarvest = crop.dayOfCurrentPhase.Value; // dayOfCurrentPhase decreases to 0 when fully grown, where <=0 is harvestable
+                    }
+                    dayOfNextHarvest = SDate.Now().AddDays(daysToNextHarvest);
+                }
+
+                // generate field
+                string summary;
+                if (canHarvestNow)
+                    summary = this.Translate(L10n.Crop.HarvestNow);
+                else if (Game1.currentLocation.Name != Constant.LocationNames.Greenhouse && !crop.seasonsToGrowIn.Contains(dayOfNextHarvest.Season))
+                    summary = this.Translate(L10n.Crop.HarvestTooLate, new { date = this.Stringify(dayOfNextHarvest) });
+                else
+                    summary = $"{this.Stringify(dayOfNextHarvest)} ({this.Text.GetPlural(daysToNextHarvest, L10n.Generic.Tomorrow, L10n.Generic.InXDays).Tokens(new { count = daysToNextHarvest })})";
+
+                yield return new GenericField(this.GameHelper, this.Translate(L10n.Crop.Harvest), summary);
+            }
+
+            // crop summary
+            {
+                List<string> summary = new List<string>();
+
+                // harvest
+                summary.Add(crop.regrowAfterHarvest.Value == -1
+                    ? this.Translate(L10n.Crop.SummaryHarvestOnce, new { daysToFirstHarvest = daysToFirstHarvest })
+                    : this.Translate(L10n.Crop.SummaryHarvestMulti, new { daysToFirstHarvest = daysToFirstHarvest, daysToNextHarvests = crop.regrowAfterHarvest })
+                );
+
+                // seasons
+                summary.Add(this.Translate(L10n.Crop.SummarySeasons, new { seasons = string.Join(", ", this.Text.GetSeasonNames(crop.seasonsToGrowIn)) }));
+
+                // drops
+                if (crop.minHarvest != crop.maxHarvest && crop.chanceForExtraCrops.Value > 0)
+                    summary.Add(this.Translate(L10n.Crop.SummaryDropsXToY, new { min = crop.minHarvest, max = crop.maxHarvest, percent = Math.Round(crop.chanceForExtraCrops.Value * 100, 2) }));
+                else if (crop.minHarvest.Value > 1)
+                    summary.Add(this.Translate(L10n.Crop.SummaryDropsX, new { count = crop.minHarvest }));
+
+                // crop sale price
+                Item drop = this.GameHelper.GetObjectBySpriteIndex(crop.indexOfHarvest.Value);
+                summary.Add(this.Translate(L10n.Crop.SummarySellsFor, new { price = GenericField.GetSaleValueString(this.GetSaleValue(drop, false, metadata), 1, this.Text) }));
+
+                // generate field
+                yield return new GenericField(this.GameHelper, this.Translate(L10n.Crop.Summary), "-" + string.Join($"{Environment.NewLine}-", summary));
+            }
+        }
+
+        /// Get the custom fields for machine output.
+        /// <param name="obj">The machine whose output to represent.</param>
+        /// <param name="metadata">Provides metadata that's not available from the game data directly.</param>
+        private IEnumerable<ICustomField> GetMachineOutputFields(SObject obj, Metadata metadata)
+        {
+            if (obj?.heldObject?.Value == null)
+                yield break;
+
+            // cask
+            if (obj is Cask cask)
+            {
+                // get cask data
+                SObject agingObj = cask.heldObject.Value;
+                ItemQuality curQuality = (ItemQuality)agingObj.Quality;
+                string curQualityName = this.Translate(L10n.For(curQuality));
+
+                // calculate aging schedule
+                float effectiveAge = metadata.Constants.CaskAgeSchedule.Values.Max() - cask.daysToMature.Value;
+                var schedule =
+                    (
+                        from entry in metadata.Constants.CaskAgeSchedule
+                        let quality = entry.Key
+                        let baseDays = entry.Value
+                        where baseDays > effectiveAge
+                        orderby baseDays ascending
+                        let daysLeft = (int)Math.Ceiling((baseDays - effectiveAge) / cask.agingRate.Value)
+                        select new
+                        {
+                            Quality = quality,
+                            DaysLeft = daysLeft,
+                            HarvestDate = SDate.Now().AddDays(daysLeft)
+                        }
+                    )
+                    .ToArray();
+
+                // display fields
+                yield return new ItemIconField(this.GameHelper, this.Translate(L10n.Item.Contents), obj.heldObject.Value);
+                if (cask.MinutesUntilReady <= 0 || !schedule.Any())
+                    yield return new GenericField(this.GameHelper, this.Translate(L10n.Item.CaskSchedule), this.Translate(L10n.Item.CaskScheduleNow, new { quality = curQualityName }));
+                else
+                {
+                    string scheduleStr = string.Join(Environment.NewLine, (
+                        from entry in schedule
+                        let tokens = new { quality = this.Translate(L10n.For(entry.Quality)), count = entry.DaysLeft, date = entry.HarvestDate }
+                        let str = this.Text.GetPlural(entry.DaysLeft, L10n.Item.CaskScheduleTomorrow, L10n.Item.CaskScheduleInXDays).Tokens(tokens)
+                        select $"-{str}"
+                    ));
+                    yield return new GenericField(this.GameHelper, this.Translate(L10n.Item.CaskSchedule), this.Translate(L10n.Item.CaskSchedulePartial, new { quality = curQualityName }) + Environment.NewLine + scheduleStr);
+                }
+            }
+
+            // furniture
+            else if (obj is Furniture)
+            {
+                string summary = this.Translate(L10n.Item.ContentsPlaced, new { name = obj.heldObject.Value.DisplayName });
+                yield return new ItemIconField(this.GameHelper, this.Translate(L10n.Item.Contents), obj.heldObject.Value, summary);
+            }
+
+            // auto-grabber
+            else if (obj.ParentSheetIndex == Constant.ObjectIndexes.AutoGrabber)
+            {
+                string readyText = this.Text.Stringify(obj.heldObject.Value is Chest output && output.items.Any());
+                yield return new GenericField(this.GameHelper, this.Translate(L10n.Item.Contents), readyText);
+            }
+
+            // generic machine
+            else
+            {
+                string summary = obj.MinutesUntilReady <= 0
+                    ? this.Translate(L10n.Item.ContentsReady, new { name = obj.heldObject.Value.DisplayName })
+                    : this.Translate(L10n.Item.ContentsPartial, new { name = obj.heldObject.Value.DisplayName, time = this.Stringify(TimeSpan.FromMinutes(obj.MinutesUntilReady)) });
+                yield return new ItemIconField(this.GameHelper, this.Translate(L10n.Item.Contents), obj.heldObject.Value, summary);
+            }
+        }
+
+        /// Get the custom fields indicating what an item is needed for.
+        /// <param name="obj">The machine whose output to represent.</param>
+        /// <param name="metadata">Provides metadata that's not available from the game data directly.</param>
+        private IEnumerable<ICustomField> GetNeededForFields(SObject obj, Metadata metadata)
+        {
+            if (obj == null)
+                yield break;
+
+            List<string> neededFor = new List<string>();
+
+            // bundles
+            {
+                string[] bundles = (
+                    from bundle in this.GetUnfinishedBundles(obj)
+                    orderby bundle.Area, bundle.DisplayName
+                    let countNeeded = this.GetIngredientCountNeeded(bundle, obj)
+                    select countNeeded > 1
+                        ? $"{this.GetTranslatedBundleArea(bundle)}: {bundle.DisplayName} x {countNeeded}"
+                        : $"{this.GetTranslatedBundleArea(bundle)}: {bundle.DisplayName}"
+                ).ToArray();
+                if (bundles.Any())
+                    neededFor.Add(this.Translate(L10n.Item.NeededForCommunityCenter, new { bundles = string.Join(", ", bundles) }));
+            }
+
+            // polyculture achievement
+            if (metadata.Constants.PolycultureCrops.Contains(obj.ParentSheetIndex))
+            {
+                int needed = metadata.Constants.PolycultureCount - this.GameHelper.GetShipped(obj.ParentSheetIndex);
+                if (needed > 0)
+                    neededFor.Add(this.Translate(L10n.Item.NeededForPolyculture, new { count = needed }));
+            }
+
+            // full shipment achievement
+            if (this.GameHelper.GetFullShipmentAchievementItems().Any(p => p.Key == obj.ParentSheetIndex && !p.Value))
+                neededFor.Add(this.Translate(L10n.Item.NeededForFullShipment));
+
+            // a full collection achievement
+            LibraryMuseum museum = Game1.locations.OfType<LibraryMuseum>().FirstOrDefault();
+            if (museum != null && museum.isItemSuitableForDonation(obj))
+                neededFor.Add(this.Translate(L10n.Item.NeededForFullCollection));
+
+            // yield
+            if (neededFor.Any())
+                yield return new GenericField(this.GameHelper, this.Translate(L10n.Item.NeededFor), string.Join(", ", neededFor));
         }

         /// Get unfinished bundles which require this item.


Fixed indentation

Fixed indentation

--- Marmalade-Global/Employee/CreateEmployee.xaml.cs
+++ Marmalade-Global/Employee/CreateEmployee.xaml.cs
@@ -199,7 +199,7 @@
             if (txtBxs[4].Name == "legalId_tbx")
             {
                 bool number = false;
-
+

                 string dd = "";
                 string mm = "";
@@ -240,7 +240,8 @@
                     if (outInt != 0)
                     {
                         year = outInt;
-                    } else
+                    }
+                    else
                     {
                         number = false;
                     }
@@ -295,7 +296,7 @@
                 }
             }

-            if(errors.Count == 0)
+            if (errors.Count == 0)
             {
                 confirmed = true;
             }
@@ -305,42 +306,43 @@

         private void createEmployee_btn_Click(object sender, RoutedEventArgs e)
         {
-            if (ConfirmInput()) {
-            string name = name_tbx.Text;
-            string phoneNo = phoneNr_tbx.Text;
-            string address = address_tbx.Text;
-            double hourlyWage = Convert.ToDouble(hourlyWage_tbx.Text);
-            string personalID = legalId_tbx.Text;
-            EmployeeStatuses.Department department = (EmployeeStatuses.Department)Enum.Parse(typeof(EmployeeStatuses.Department), department_cbx.Text);
-
-            EmployeeStatuses.MaritalStatus marital = (EmployeeStatuses.MaritalStatus)Enum.Parse(typeof(EmployeeStatuses.MaritalStatus), maritalStatus_cbx.Text);
-
-
-            if (!shift_cbx.Text.Equals(""))
-            {
-                EmployeeStatuses.Shift shift = (EmployeeStatuses.Shift)Enum.Parse(typeof(EmployeeStatuses.Shift), shift_cbx.Text);
-                EmployeeController.CreateEmployee(name,
-                                phoneNo,
-                                address,
-                                hourlyWage,
-                                personalID,
-                                shift,
-                                department,
-                                marital);
-            }
-            else
-            {
-                EmployeeController.CreateEmployee(name,
-                                phoneNo,
-                                address,
-                                hourlyWage,
-                                personalID,
-                                department,
-                                marital);
-            }
-
-
-        }
+            if (ConfirmInput())
+            {
+                string name = name_tbx.Text;
+                string phoneNo = phoneNr_tbx.Text;
+                string address = address_tbx.Text;
+                double hourlyWage = Convert.ToDouble(hourlyWage_tbx.Text);
+                string personalID = legalId_tbx.Text;
+                EmployeeStatuses.Department department = (EmployeeStatuses.Department)Enum.Parse(typeof(EmployeeStatuses.Department), department_cbx.Text);
+
+                EmployeeStatuses.MaritalStatus marital = (EmployeeStatuses.MaritalStatus)Enum.Parse(typeof(EmployeeStatuses.MaritalStatus), maritalStatus_cbx.Text);
+
+
+                if (!shift_cbx.Text.Equals(""))
+                {
+                    EmployeeStatuses.Shift shift = (EmployeeStatuses.Shift)Enum.Parse(typeof(EmployeeStatuses.Shift), shift_cbx.Text);
+                    EmployeeController.CreateEmployee(name,
+                                    phoneNo,
+                                    address,
+                                    hourlyWage,
+                                    personalID,
+                                    shift,
+                                    department,
+                                    marital);
+                }
+                else
+                {
+                    EmployeeController.CreateEmployee(name,
+                                    phoneNo,
+                                    address,
+                                    hourlyWage,
+                                    personalID,
+                                    department,
+                                    marital);
+                }
+
+
+            }
         }
     }
 }


Would you believe ppt text

Would you believe ppt text

Former-commit-id: 411db55bf6f09fc29246b6b1de99d76c01d769a1

--- MeTLMeeting/SandRibbon/Utils/PowerPointLoader.cs
+++ MeTLMeeting/SandRibbon/Utils/PowerPointLoader.cs
@@ -27,7 +27,6 @@
 {
     public class PowerPointLoaderPrintRange : PrintRange
     {
-        //hey Chris, how do I "implement" an interface?
         private int start = 0;
         private int end = 0;
         private object parent;
@@ -37,23 +36,18 @@
         object Microsoft.Office.Interop.PowerPoint.PrintRange.Parent { get { return parent; } }
         Microsoft.Office.Interop.PowerPoint.Application Microsoft.Office.Interop.PowerPoint.PrintRange.Application { get { return app; } }

-
         public PowerPointLoaderPrintRange(Presentation ppt)
         {
             app = ppt.Application;
             parent = ppt.Parent;
             end = ppt.Slides.Count - 1;
         }
-
         public void Delete()
         {
             this.parent = null;
             this.app = null;
         }
     }
-
-
-
     public class PowerPointLoader
     {
         static MsoTriState FALSE = MsoTriState.msoFalse;
@@ -238,7 +232,6 @@
                                 break;
                             case "cancel":
                                 return;
-                                break;
                             default:
                                 LoadPowerpointAsFlatSlides(file, details, 1);
                                 break;
@@ -439,7 +432,7 @@
         private void sendSlide(int id, XElement slide)
         {
             sendShapes(id, slide.Descendants("shape"));
-            //sendPublicTextBoxes(id, slide.Descendants("publicText"));
+            sendPublicTextBoxes(id, slide.Descendants("publicText"));
             sendTextboxes(id, slide.Descendants("privateText"));
         }
         private void sendPublicTextBoxes(int id, IEnumerable<XElement> shapes)
@@ -451,12 +444,18 @@
                 newText.Text = text.Attribute("content").Value;
                 InkCanvas.SetLeft(newText, Double.Parse(text.Attribute("x").Value));
                 InkCanvas.SetTop(newText, Double.Parse(text.Attribute("y").Value));
-                newText.Tag = DateTimeFactory.Now() + text.Attribute("x").Value + text.Attribute("x").Value + me;
+                var textBoxIdentity = DateTimeFactory.Now() + text.Attribute("x").Value + text.Attribute("x").Value + me;
                 var font = text.Descendants("font").ElementAt(0);
                 newText.FontFamily = new FontFamily(font.Attribute("family").Value);
                 newText.FontSize = Double.Parse(font.Attribute("size").Value);
                 newText.Foreground = (Brush)(new BrushConverter().ConvertFromString((font.Attribute("color").Value).ToString()));
-
+                newText.tag(
+                    new TextTag
+                    {
+                        author = me,
+                        id = textBoxIdentity,
+                        privacy = "public"
+                    });
                 wire.SendTextbox(new TargettedTextBox
                 {
                     slide = id,
@@ -637,12 +636,11 @@
                         shape.Visible = MsoTriState.msoTrue;
                         // Importing Powerpoint textboxes AS textboxes instead of pictures currently disabled.
                         //Uncomment the following lines to re-enable.
-                        /*if (shape.HasTextFrame == MsoTriState.msoTrue &&
+                        if (shape.HasTextFrame == MsoTriState.msoTrue &&
                             shape.TextFrame.HasText == MsoTriState.msoTrue &&
                             !String.IsNullOrEmpty(shape.TextFrame.TextRange.Text))
                             addPublicText(xSlide, shape, "private");
                         else
-                        */
                         {
                             try
                             {
@@ -669,12 +667,11 @@
                     {
                         // Importing Powerpoint textboxes AS textboxes instead of pictures currently disabled.
                         //Uncomment the following lines to re-enable.
-                        /*if (shape.HasTextFrame == MsoTriState.msoTrue &&
+                        if (shape.HasTextFrame == MsoTriState.msoTrue &&
                             shape.TextFrame.HasText == MsoTriState.msoTrue &&
                             !String.IsNullOrEmpty(shape.TextFrame.TextRange.Text))
                             addPublicText(xSlide, shape, "public");
                         else
-                        */
                         {
                             shape.Export(file, PpShapeFormat.ppShapeFormatPNG, backgroundWidth, backgroundHeight, exportMode);
                             xSlide.Add(new XElement("shape",


Dispose X509Certificate2 now that it is IDisposable

Fixes some leaks identified in issue #852

--- MimeKit/Cryptography/WindowsSecureMimeContext.cs
+++ MimeKit/Cryptography/WindowsSecureMimeContext.cs
@@ -267,34 +267,42 @@
 		{
 			var collection = new RealCmsRecipientCollection ();

-			foreach (var recipient in recipients) {
-				var certificate = new X509Certificate2 (recipient.Certificate.GetEncoded ());
-				RealSubjectIdentifierType type;
-				RealCmsRecipient real;
-
-				if (recipient.RecipientIdentifierType != SubjectIdentifierType.SubjectKeyIdentifier)
-					type = RealSubjectIdentifierType.IssuerAndSerialNumber;
-				else
-					type = RealSubjectIdentifierType.SubjectKeyIdentifier;
+			try {
+				foreach (var recipient in recipients) {
+					var certificate = new X509Certificate2 (recipient.Certificate.GetEncoded ());
+					RealSubjectIdentifierType type;
+					RealCmsRecipient real;
+
+					if (recipient.RecipientIdentifierType != SubjectIdentifierType.SubjectKeyIdentifier)
+						type = RealSubjectIdentifierType.IssuerAndSerialNumber;
+					else
+						type = RealSubjectIdentifierType.SubjectKeyIdentifier;

 #if NETCOREAPP3_0
-				var padding = recipient.RsaEncryptionPadding?.AsRSAEncryptionPadding ();
-
-				if (padding != null)
-					real = new RealCmsRecipient (type, certificate, padding);
-				else
+					var padding = recipient.RsaEncryptionPadding?.AsRSAEncryptionPadding ();
+
+					if (padding != null)
+						real = new RealCmsRecipient (type, certificate, padding);
+					else
+						real = new RealCmsRecipient (type, certificate);
+#else
+					if (recipient.RsaEncryptionPadding?.Scheme == RsaEncryptionPaddingScheme.Oaep) {
+						certificate.Dispose ();
+						throw new NotSupportedException ("The RSAES-OAEP encryption padding scheme is not supported by the WindowsSecureMimeContext. You must use a subclass of BouncyCastleSecureMimeContext to get this feature.");
+					}
+
 					real = new RealCmsRecipient (type, certificate);
-#else
-				if (recipient.RsaEncryptionPadding?.Scheme == RsaEncryptionPaddingScheme.Oaep)
-					throw new NotSupportedException ("The RSAES-OAEP encryption padding scheme is not supported by the WindowsSecureMimeContext. You must use a subclass of BouncyCastleSecureMimeContext to get this feature.");
-
-				real = new RealCmsRecipient (type, certificate);
 #endif

-				collection.Add (real);
+					collection.Add (real);
+				}
+
+				return collection;
+			} catch {
+				foreach (var recipient in collection)
+					recipient.Certificate.Dispose ();
+				throw;
 			}
-
-			return collection;
 		}

 		/// <summary>
@@ -1514,7 +1522,8 @@
 			if (certificate == null)
 				throw new ArgumentNullException (nameof (certificate));

-			Import (storeName, new X509Certificate2 (certificate.GetEncoded ()), cancellationToken);
+			using (var certificate2 = new X509Certificate2 (certificate.GetEncoded ()))
+				Import (storeName, certificate2, cancellationToken);
 		}

 		/// <summary>


Handle error rolling over log files (File.Move() throws the same Exception)

--- MultiMiner.Utility/Serialization/ObjectLogger.cs
+++ MultiMiner.Utility/Serialization/ObjectLogger.cs
@@ -51,42 +51,36 @@
                 }
             }
         }
-
-        private void RemoveBackupFile(string filePath)
-        {
-            if (File.Exists(filePath))
-            {
-                try
-                {
-                    File.Delete(filePath);
-                }
-                catch (UnauthorizedAccessException)
-                {
-                    //users report occasionally receiving access denied rolling log files
-                    //rename/move the file instead
-                    File.Move(filePath, Path.ChangeExtension(filePath, "deleteme"));
-                }
-            }
-        }
-
+
         private void BackupLogFileToSets(string logFilePath)
         {
             if (oldFileSets > 0)
             {
                 string backupFilePath;
+                try
+                {
+                    for (int i = oldFileSets; i > 0; i--)
+                    {
+                        backupFilePath = Path.ChangeExtension(logFilePath, i.ToString());
+                        string previousFilePath = Path.ChangeExtension(logFilePath, (i - 1).ToString());
+                        if (File.Exists(backupFilePath))
+                            File.Delete(backupFilePath);
+                        if (File.Exists(previousFilePath))
+                            File.Move(previousFilePath, backupFilePath);
+                    }

-                for (int i = oldFileSets; i > 0; i--)
+                    backupFilePath = Path.ChangeExtension(logFilePath, "1");
+                    if (File.Exists(backupFilePath))
+                        File.Delete(backupFilePath);
+                    File.Move(logFilePath, backupFilePath);
+                }
+                catch (UnauthorizedAccessException)
                 {
-                    backupFilePath = Path.ChangeExtension(logFilePath, i.ToString());
-                    string previousFilePath = Path.ChangeExtension(logFilePath, (i - 1).ToString());
-                    RemoveBackupFile(backupFilePath);
-                    if (File.Exists(previousFilePath))
-                        File.Move(previousFilePath, backupFilePath);
+                    //users report occasionally receiving access denied rolling log files
+                    //have received this myself as well - may be in-use by an async log op
+                    //no way to recover, cannot move file either (same exception)
+                    //we'll try again on next call to the method
                 }
-
-                backupFilePath = Path.ChangeExtension(logFilePath, "1");
-                RemoveBackupFile(backupFilePath);
-                File.Move(logFilePath, backupFilePath);
             }
         }
     }


Changed method of clearing input (stopped working for some reason).

--- MvcForms.Tests/SystemTests/Utility/BrowserApp.cs
+++ MvcForms.Tests/SystemTests/Utility/BrowserApp.cs
@@ -4,7 +4,6 @@
 using FluentAssertions;
 using NUnit.Framework;
 using OpenQA.Selenium;
-using OpenQA.Selenium.Interactions;

 namespace MvcForms.Tests.SystemTests.Utility
 {
@@ -176,19 +175,12 @@
                 inputs.Count.Should().Be(1, "should be 1 visible {0}, but found {1}", name, inputs.Count);
                 var input = inputs.Single();

-                var actions = new Actions(_webDriver);
-                actions.Click(input);
+                input.Click();

                 if (clearFirst)
-                {
-                    actions.KeyDown(Keys.Control);
-                    actions.SendKeys("a");
-                    actions.KeyUp(Keys.Control);
-                    actions.SendKeys(Keys.Backspace);
-                }
-
-                actions.SendKeys(text);
-                actions.Perform();
+                    input.Clear();
+
+                input.SendKeys(text);
             });
         }


refactor: Eliminate redundant CreateSceneViewer call on ScenePresence constructors since this is also done on other called constructors

--- OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -672,15 +672,12 @@
                              AvatarWearable[] wearables)
             : this(client, world, reginfo)
         {
-            CreateSceneViewer();
-            m_appearance = new AvatarAppearance(m_uuid, wearables, visualParams);
-
+            m_appearance = new AvatarAppearance(m_uuid, wearables, visualParams);
         }

         public ScenePresence(IClientAPI client, Scene world, RegionInfo reginfo, AvatarAppearance appearance)
             : this(client, world, reginfo)
         {
-            CreateSceneViewer();
             m_appearance = appearance;
         }


HG add a small delay before start sending region data

--- OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -2071,13 +2071,12 @@
                     m_log.DebugFormat("[CompleteMovement]: Missing COF for {0} is {1}", client.AgentId, COF);
                 }

-                if(!gotCrossUpdate)
-                    RotateToLookAt(look);

                 // Tell the client that we're totally ready
                 ControllingClient.MoveAgentIntoRegion(m_scene.RegionInfo, AbsolutePosition, look);

                 m_log.DebugFormat("[CompleteMovement] MoveAgentIntoRegion: {0}ms", Util.EnvironmentTickCountSubtract(ts));
+

                 if (!string.IsNullOrEmpty(m_callbackURI))
                 {
@@ -2107,11 +2106,27 @@
 //                    client.Name, client.AgentId, m_scene.RegionInfo.RegionName);
 //            }

+
                 m_log.DebugFormat("[CompleteMovement] ReleaseAgent: {0}ms", Util.EnvironmentTickCountSubtract(ts));
+
+
+                if(m_teleportFlags > 0)  //sanity check
+                    gotCrossUpdate = false;
+
+                if(!gotCrossUpdate)
+                    RotateToLookAt(look);
+

 // start sending terrain patchs
                 if (!gotCrossUpdate && !isNPC)
                     Scene.SendLayerData(ControllingClient);
+
+                // HG delay
+                if((m_teleportFlags & TeleportFlags.ViaHGLogin) != 0)
+                {
+                    Thread.Sleep(500);
+                    m_log.DebugFormat("[CompleteMovement] HG delay: {0}ms", Util.EnvironmentTickCountSubtract(ts));
+                }

                 m_previusParcelHide = false;
                 m_previusParcelUUID = UUID.Zero;


Prevent a nullref when no script engines are loaded

--- OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -1962,6 +1962,9 @@
                             //
                             foreach (IScriptModule m in m_scriptEngines)
                             {
+                                if (m == null) // No script engine loaded
+                                    continue;
+
                                 m.PostObjectEvent(grp.RootPart.UUID, "changed", new Object[] {16384});
                             }
                         }


* Hack to get avatar to land on prim.   This is a big nasty hack that tricks the client into thinking you're landing on the terrain.   There are some visual artifacts when you land.  It's only temporary until we figure out how this broke.

--- OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -995,6 +995,8 @@

             Animator.TrySetMovementAnimation("LAND");
             SendFullUpdateToAllClients();
+            ControllingClient.SendAvatarTerseUpdate(new SendAvatarTerseData(m_rootRegionHandle, (ushort)(m_scene.TimeDilation * ushort.MaxValue), LocalId,
+                    AbsolutePosition, Velocity, -Vector3.UnitZ, m_bodyRot, Vector4.UnitW, m_uuid, null, GetUpdatePriority(ControllingClient)));
         }

         public void AddNeighbourRegion(ulong regionHandle, string cap)


remove fireandforget call to EnableChildAgents at end on CompleteMovement, since this is already on own thread and its at the end of it.

--- OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -1315,13 +1315,15 @@
             // Create child agents in neighbouring regions
             if (openChildAgents && !IsChildAgent)
             {
+
                 IEntityTransferModule m_agentTransfer = m_scene.RequestModuleInterface<IEntityTransferModule>();
                 if (m_agentTransfer != null)
-                    Util.FireAndForget(delegate { m_agentTransfer.EnableChildAgents(this); });
+                    m_agentTransfer.EnableChildAgents(this);

                 IFriendsModule friendsModule = m_scene.RequestModuleInterface<IFriendsModule>();
                 if (friendsModule != null)
                     friendsModule.SendFriendsOnlineIfNeeded(ControllingClient);
+
             }

 //            m_log.DebugFormat(


bug fix

bug fix

--- OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs
+++ OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs
@@ -950,13 +950,13 @@
                     bool noskip = true;
                     if (dop1ava)
                     {
-                        if (!(((OdeCharacter)p1).Collide(g1, false, ref curContact, ref FeetCollision)))
+                        if (!(((OdeCharacter)p1).Collide(g1,g2, false, ref curContact, ref FeetCollision)))

                             noskip = false;
                     }
                     else if (dop2ava)
                     {
-                        if (!(((OdeCharacter)p2).Collide(g2, true, ref curContact, ref FeetCollision)))
+                        if (!(((OdeCharacter)p2).Collide(g2,g1, true, ref curContact, ref FeetCollision)))
                             noskip = false;
                     }

@@ -1095,10 +1095,11 @@
                         // do colisions with static space
                         d.SpaceCollide2(chr.collider, StaticSpace, IntPtr.Zero, nearCallback);

-                        // chars with chars
-                        d.SpaceCollide(CharsSpace, IntPtr.Zero, nearCallback);
                         // no coll with gnd
                     }
+                    // chars with chars
+                    d.SpaceCollide(CharsSpace, IntPtr.Zero, nearCallback);
+
                 }
                 catch (AccessViolationException)
                 {


Bugfix: Added missing SubmitChanges() call

--- PART/Source/CprBroker/CPRDirectToDPR/DbrQueue.cs
+++ PART/Source/CprBroker/CPRDirectToDPR/DbrQueue.cs
@@ -44,6 +44,7 @@
                             CprBroker.Engine.Local.Admin.LogException(ex);
                         }
                     }
+                    dprDataContext.SubmitChanges();
                 }
             }
             return ret.ToArray();


Fixed tha bonus - It now disappears if taken and a new bonus appears on the top of the board. Fixed minor bugs.

--- AFTH/Game/Game.cs
+++ AFTH/Game/Game.cs
@@ -151,7 +151,7 @@
                     {
                         if (gameNotOver)
                         {
-                            renderer.Append("  Level: "); // Draws the score
+                            renderer.Append("  Level: "); // Draws the level
                             renderer.Append(level);
                         }
                     }
@@ -202,7 +202,14 @@
             }
             if (player[0] == bonusPosition[0] && player[1] == bonusPosition[1]) // Update score when hitted bonus position
             {
-                currentScore += 10;
+                currentScore += 100;
+                bonusPosition[1] = 1; // Removes the bonus from the board and initilizes a new bonus ot the top of the field
+                bonusPosition[0] = rnd.Next(1, size[0] - 2);
+                if (bonusPosition[1] == lineHeight)
+                {
+                    bonusPosition[1]--;
+                }
+
             }
         }

@@ -262,7 +269,7 @@
                 if (line[1] > size[1] - 2)
                 {
                     line[1] = 1;
-                    line[0] = rnd.Next(1, size[1] - 2);
+                    line[0] = rnd.Next(1, size[0] - 2);
                 }
                 updateLineCount = 0;
             }
@@ -279,7 +286,7 @@
                 if (bonusPosition[1] > size[1] - 2)
                 {
                     bonusPosition[1] = 1;
-                    bonusPosition[0] = rnd.Next(1, size[1] - 2);
+                    bonusPosition[0] = rnd.Next(1, size[0] - 2);
                 }
                 updateBonusesCount = 0;
             }


[Modify] Polish it

[Modify] Polish it

--- websocket-sharp/Net/HttpConnection.cs
+++ websocket-sharp/Net/HttpConnection.cs
@@ -394,8 +394,10 @@
             return true;
         }
       }
-      catch (Exception ex) {
-        _context.ErrorMessage = ex.Message;
+      catch (Exception) {
+        // TODO: Logging.
+
+        _context.ErrorMessage = "Processing failure";

         return true;
       }


AdventureSample - reassign same string

AdventureSample - reassign same string

--- projects/AdventureSample/test/GWBas2CS.Test/ExampleProgram.cs
+++ projects/AdventureSample/test/GWBas2CS.Test/ExampleProgram.cs
@@ -15,7 +15,8 @@
             const string Input = @"10 REM My first BASIC program
 20 PRINT ""HELLO, WORLD!""
 30 A$=""a string""
-40 GOTO 20";
+40 A$=""same string""
+100 GOTO 20";
             const string Expected = @"using System;
 using System.IO;

@@ -55,6 +56,7 @@
             ;
         PRINT(""HELLO, WORLD!"");
         A_s = (""a string"");
+        A_s = (""same string"");
         goto L20;
         return false;
     }


Added aligment attribute to minimal geometry

--- foo_title/fooTitle/Geometries/MinimalGeometry.cs
+++ foo_title/fooTitle/Geometries/MinimalGeometry.cs
@@ -5,6 +5,19 @@
 namespace fooTitle.Geometries {
     [GeometryTypeAttribute("minimal")]
     internal class MinimalGeometry : Geometry{
+
+        [Flags]
+        public enum AlignType
+        {
+            None = 0,
+            Left = 1,
+            Right = 1 << 1,
+            Top = 1 << 2,
+            Bottom = 1 << 4,
+            Center = 1 << 5
+        };
+
+        private readonly Rectangle _parentRect;

         /// <summary>
         /// Current values of padding
@@ -18,7 +31,20 @@

         private Size _curContentSize;

+        private AlignType _align;
+        public AlignType Align
+        {
+            get => _align;
+            set
+            {
+                _align = value;
+                Update(_parentRect);
+            }
+        }
+
         public MinimalGeometry(Rectangle parentRect, XmlNode node) : base(parentRect, node) {
+            _parentRect = parentRect;
+
             XmlNode padding = GetFirstChildByName(node, "padding");

             // read and store expressions
@@ -32,7 +58,31 @@
             MyPadding.Top = (int)GetNumberFromAttribute(padding, "top", "0");
             MyPadding.Right = (int)GetNumberFromAttribute(padding, "right", "0");
             MyPadding.Bottom = (int)GetNumberFromAttribute(padding, "bottom", "0");
-
+
+            // read alignment
+            string alignStr = GetAttributeValue(GetFirstChildByName(node, "position"), "align", "left,top");
+            _align = AlignType.None;
+            foreach (string i in alignStr.ToLower().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries))
+            {
+                switch (i)
+                {
+                    case "top":
+                        _align |= AlignType.Top;
+                        break;
+                    case "bottom":
+                        _align |= AlignType.Bottom;
+                        break;
+                    case "right":
+                        _align |= AlignType.Right;
+                        break;
+                    case "left":
+                        _align |= AlignType.Left;
+                        break;
+                    case "center":
+                        _align |= AlignType.Center;
+                        break;
+                }
+            }
         }

         public override void Update(Rectangle parentRect) {
@@ -41,11 +91,38 @@
             MyPadding.Right = GetValueFromExpression(MyExprPadding.Right, MyPadding.Right);
             MyPadding.Bottom = GetValueFromExpression(MyExprPadding.Bottom, MyPadding.Bottom);

-            myClientRect.X = MyPadding.Left + parentRect.Left;
-            myClientRect.Y = MyPadding.Top + parentRect.Top;
+            myClientRect.Width = Math.Max(0, Math.Min(_curContentSize.Width, parentRect.Width) - (MyPadding.Left + MyPadding.Right));
+            myClientRect.Height = Math.Max(0, Math.Min(_curContentSize.Height, parentRect.Height) - (MyPadding.Top + MyPadding.Bottom));

-            myClientRect.Width = Math.Min(_curContentSize.Width, parentRect.Width) - (MyPadding.Left + MyPadding.Right);
-            myClientRect.Height = Math.Min(_curContentSize.Height, parentRect.Height) - (MyPadding.Top + MyPadding.Bottom);
+            Point position = new Point(0,0);
+            if ((_align & AlignType.Left) != 0)
+            {
+                position.X = MyPadding.Left;
+            }
+            else if ((_align & AlignType.Right) != 0)
+            {
+                position.X = parentRect.Right - (myClientRect.Width + MyPadding.Right);
+            }
+            else
+            {
+                position.X = (parentRect.Right - (myClientRect.Width + MyPadding.Right - MyPadding.Left)) / 2;
+            }
+
+            if ((_align & AlignType.Top) != 0)
+            {
+                position.Y = MyPadding.Top;
+            }
+            else if ((_align & AlignType.Bottom) != 0)
+            {
+                position.Y = parentRect.Bottom - (myClientRect.Height + MyPadding.Bottom);
+            }
+            else
+            {
+                position.Y = (parentRect.Bottom - (myClientRect.Height + MyPadding.Bottom - MyPadding.Top))/2;
+            }
+
+            myClientRect.X = position.X + parentRect.Left;
+            myClientRect.Y = position.Y + parentRect.Top;
         }

         public override Size GetMinimalSize(Size contentSize)
@@ -55,8 +132,9 @@
             return _curContentSize;
         }

-        public override Point GetPosition() {
-            return new Point(0, 0);
+        public override Point GetPosition()
+        {
+            return new Point(0,0);
         }

         public override bool IsDynamic() {


Fix errors

Fix errors

--- FCS,ConsoleClient/Startup.cs
+++ FCS,ConsoleClient/Startup.cs
@@ -7,8 +7,7 @@
     {
         public static void Main()
         {
-            IFileCacheConfiguration fileCacheConfiguration = new FileCacheConfiguration();
-            ICacheService cacheService = new FileCache(fileCacheConfiguration);
+            ICacheService cacheService = new FileCache();
         }
     }
 }


THIS IS (NOT) EVEN MY FINAL FORM (#DragonballReferences)


Added event termination after start received for send Added better vars checking for startdialog

--- FEClient/Forms/SendDialog.cs
+++ FEClient/Forms/SendDialog.cs
@@ -31,7 +31,7 @@
         private AesKeys _key;
         private string _remoteKey;
         private bool _terminated;
-        private bool startRevoked;
+        private bool _startRevoked;
         private bool respRevoked;

         public SendDialog(string ip, string fileName, int rounds, int complexity, int timeout)
@@ -68,17 +68,19 @@

         private void MyResource_StartTransmissionAndRespSent(object sender, StartTransmissionEventArgs vars)
         {
-            if (vars.Guid != _guid)
+            if (vars.Guid != _guid || vars.FileName != _file.Name || vars.IP != _ip)
                 return;
             Invoke((MethodInvoker) timer2_Tick); //TODO: maybe another timeout timer?
+            RevokeResp();
         }

         private void MyResource_StartTransmission(object sender, StartTransmissionEventArgs args)
         {
-            if (args.FileName != _file.Name)
+            if (args.FileName != _file.Name || args.Guid != _guid || args.IP != _ip)
                 return;
             args.HasSet = true;
             Invoke((MethodInvoker) delegate { timeoutTimer.Stop(); });
+            RevokeStart();
         }

         private void SendDialog_FormClosed(object sender, FormClosedEventArgs e)
@@ -103,10 +105,10 @@

         private void RevokeStart()
         {
-            if(!startRevoked)
+            if(!_startRevoked)
             {
                 ClientRestApi.StartTransmission -= MyResource_StartTransmission;
-                startRevoked = true;
+                _startRevoked = true;
             }

         }


Add in web version check for releases

Add in web version check for releases

--- FTAnalyser/Forms/MainForm.cs
+++ FTAnalyser/Forms/MainForm.cs
@@ -22,10 +22,9 @@
 using System.Threading.Tasks;
 using System.Windows.Forms;
 using System.Xml;
-#if !__DEBUG__
-    using HtmlAgilityPack;
-    using System.Net;
-#endif
+using HtmlAgilityPack;
+using System.Net;
+

 namespace FTAnalyzer
 {
@@ -52,7 +51,7 @@
             InitializeComponent();
             loading = true;
             FamilyTree.Instance.Version = $"v{VERSION}";
-            var x = NativeMethods.GetTaskBarPos(); // Sets taskbar offset
+            _ = NativeMethods.GetTaskBarPos(); // Sets taskbar offset
             displayOptionsOnLoadToolStripMenuItem.Checked = GeneralSettings.Default.ReportOptions;
             treetopsRelation.MarriedToDB = false;
             ShowMenus(false);
@@ -62,9 +61,7 @@
             string ver = pos > 0 ? VERSION.Substring(0, VERSION.IndexOf('-')) : VERSION;
             DatabaseHelper.Instance.CheckDatabaseVersion(new Version(ver));
             CheckSystemVersion();
-#if !__DEBUG__
-            //CheckWebVersion();
-#endif
+            CheckWebVersion();
             SetSavePath();
             BuildRecentList();
         }
@@ -90,18 +87,19 @@
             if (os.Version.Major == 6 && os.Version.Minor < 2)
                 MessageBox.Show("Please note Microsoft has ended Windows 7 support as such it is no longer advisable to be connected to the internet using it. Any security flaws that are unpatched may be being actively exploited by hackers. You should upgrade as soon as possible.\n\nPlease be aware that FTAnalyzer may be unstable on an outdated unsupported Operating System.");
         }
-
-#if !__DEBUG__
         async void CheckWebVersion()
         {
             Settings.Default.StartTime = DateTime.Now;
             Settings.Default.Save();
             try
             {
-                WebClient wc = new WebClient();
-                HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
-                string webData = wc.DownloadString("https://github.com/ShammyLevva/FTAnalyzer/releases");
-                doc.LoadHtml(webData);
+                HtmlAgilityPack.HtmlDocument doc;
+                using (WebClient wc = new WebClient())
+                {
+                    doc = new HtmlAgilityPack.HtmlDocument();
+                    string webData = wc.DownloadString("https://github.com/ShammyLevva/FTAnalyzer/releases");
+                    doc.LoadHtml(webData);
+                }
                 HtmlNode versionNode = doc.DocumentNode.SelectSingleNode("//div/div/div/span/../../ul/li/a");
                 string webVersion = versionNode.InnerText.Replace('v', ' ').Trim();
                 if (new Version(webVersion) > new Version(VERSION))
@@ -111,14 +109,14 @@
                     if (download == DialogResult.Yes)
                         SpecialMethods.VisitWebsite("https://www.microsoft.com/en-gb/p/ftanalyzer/9pmjl9hvpl7x?cid=clickonceappupgrade");
                 }
-                await Analytics.CheckProgramUsageAsync();
+
+                await Analytics.CheckProgramUsageAsync().ConfigureAwait(true);
             }
             catch (Exception e)
             {
                 Console.WriteLine(e.Message);
             }
         }
-#endif
         void SetupFonts()
         {
             try
@@ -154,7 +152,7 @@
                 UpdateDataErrorsDisplay();
             }
             catch (Exception) { } // for font sizing exception
-         }
+        }

         void RegisterEventHandlers()
         {
@@ -3293,7 +3291,7 @@
             Predicate<Individual> indFilter = reltypesSurnames.BuildFilter<Individual>(x => x.RelationType);
             Predicate<Family> famFilter = reltypesSurnames.BuildFamilyFilter<Family>(x => x.RelationTypes);
             var progress = new Progress<int>(value => { tspbTabProgress.Value = value; });
-            var list = await Task.Run(() =>
+            var list = await Task.Run(() =>
                 new SortableBindingList<SurnameStats>(Statistics.Instance.Surnames(indFilter, famFilter, progress, chkSurnamesIgnoreCase.Checked))).ConfigureAwait(true);
             dgSurnames.DataSource = list;
             dgSurnames.Sort(dgSurnames.Columns["Surname"], ListSortDirection.Ascending);


Sort implemented copied to Windows

Sort implemented copied to Windows

--- FTAnalyser/Forms/MainForm.cs
+++ FTAnalyser/Forms/MainForm.cs
@@ -2861,8 +2861,8 @@
             if (cmbReferrals.Items.Count == 0)
             {
                 HourGlass(true);
-                List<Individual> list = ft.AllIndividuals.ToList<Individual>();
-                list.Sort(new NameComparer());
+                List<Individual> list = ft.AllIndividuals.ToList();
+                list.Sort(new NameComparer(true, false));
                 foreach (Individual ind in list)
                     cmbReferrals.Items.Add(ind);
                 btnReferrals.Enabled = true;


LinBuffer: Do not trigger a "WatchedRangeChanged" event if reading a file range

--- FastFileReader/LineBuffer.cs
+++ FastFileReader/LineBuffer.cs
@@ -75,11 +75,11 @@
                //System.Diagnostics.Debug.WriteLine("Check scheduled");
                if (sleep <= TimeSpan.Zero)
                {
-                  Update();
+                  Update(true);
                }
                else if (timer == null)
                {
-                  timer = new Timer((state) => Update(), null, sleep, Timeout.InfiniteTimeSpan);
+                  timer = new Timer((state) => Update(true), null, sleep, Timeout.InfiniteTimeSpan);
                }
                else
                {
@@ -89,7 +89,7 @@
          }
       }

-      private void Update()
+      private void Update(bool triggerEvent)
       {
          lock (lockObject)
          {
@@ -108,7 +108,10 @@
                   updateForced = false;
                   curState = range;
                   //System.Diagnostics.Debug.WriteLine("Invoke listener");
-                  WatchedRangeChanged?.Invoke(this, curState);
+                  if (triggerEvent)
+                  {
+                     WatchedRangeChanged?.Invoke(this, curState);
+                  }
                }
             }
             else
@@ -151,7 +154,7 @@
          lock (lockObject)
          {
             SetRange(position, origin, maxPrev, maxFoll, maxPrevExtent, maxFollExtent);
-            Update();
+            Update(false);
             return curState;
          }
       }