Added backward compatibility for LazyField

--- src/Orchard/ContentManagement/Utilities/LazyField.cs
+++ src/Orchard/ContentManagement/Utilities/LazyField.cs
@@ -13,6 +13,11 @@

         public void Loader(Func<T> loader) {
             _loader = loader;
+        }
+
+        [Obsolete]
+        public void Loader(Func<T, T> loader) {
+            _loader = () => loader(_value);
         }

         public void Setter(Func<T, T> setter) {


prefer a method which just configures postal

--- src/Postal.AspNetCore/ServiceCollectionExtensions.cs
+++ src/Postal.AspNetCore/ServiceCollectionExtensions.cs
@@ -20,7 +20,7 @@
             return services;
         }

-        public static IServiceCollection AddPostal(this IServiceCollection services, string smtpConnectionString)
+        public static IServiceCollection ConfigurePostal(this IServiceCollection services, string smtpConnectionString)
         {
             var match = Regex.Match(smtpConnectionString, @"^smtp:\/\/((?<username>[^:@]+):(?<password>[^:@]+)@)?(?<host>[^:@,\/?#]+)(:(?<port>\d+))?(\?(?<option>[^&]+=[^&]+)(&(?<option>[^&]+=[^&]+))*)?$");

@@ -62,7 +62,6 @@
                 }
             }

-            services.AddPostal();
             services.Configure<EmailServiceOptions>(options =>
             {
                 options.Host = host;


Update ObservableObject.cs

Update ObservableObject.cs

[skip ci]

--- src/Core2D/ObservableObject.cs
+++ src/Core2D/ObservableObject.cs
@@ -20,7 +20,7 @@
         /// Gets or sets resource name.
         /// </summary>
         [Name]
-        public string Id
+        public virtual string Id
         {
             get => _id;
             set => Update(ref _id, value);
@@ -29,7 +29,7 @@
         /// <summary>
         /// Gets or sets resource name.
         /// </summary>
-        public string Name
+        public virtual string Name
         {
             get => _name;
             set => Update(ref _name, value);
@@ -38,7 +38,7 @@
         /// <summary>
         /// Gets or sets shape resources.
         /// </summary>
-        public ImmutableArray<ObservableObject> Resources
+        public virtual ImmutableArray<ObservableObject> Resources
         {
             get => _resources;
             set => Update(ref _resources, value);


Removed Background Color of Obstacles

Removed Background Color of Obstacles

--- WhereIsMyBeer/Form1.cs
+++ WhereIsMyBeer/Form1.cs
@@ -110,10 +110,7 @@
             randomLocation = new Random();
             randomSize = new Random();

-            obstacle.BackColor = Color.Red;
-
             obstacle.Height = randomSize.Next(10, 40);
-
             obstacle.Width = randomSize.Next(10, 40);
             obstacle.Top = 429 - obstacle.Height;
             obstacle.Left = 700;
@@ -187,7 +184,6 @@
             randomLocation = new Random();
             randomSize = new Random();

-            obstacle.BackColor = Color.Red;
             obstacle.Height = randomSize.Next(10, 40);
             randomSize = new Random();
             obstacle.Width = randomSize.Next(10, 40);
@@ -212,7 +208,7 @@
                 randomSize = new Random();
                 coldBeer.Width = 10;
                 coldBeer.Top = 429 - coldBeer.Height;
-                coldBeer.Left = 650;
+                coldBeer.Left = 720;

                 coldBeers.Add(coldBeer);
                 Screen.Controls.Add(coldBeers[indexColdBeers]);
@@ -240,7 +236,7 @@
             coldBeer.Left = 650;
             for (int i = 0; i < obstacles.Count; i++)
             {
-                if(coldBeer.Left <= obstacles[i].Left + 70 && coldBeer.Left >= obstacles[i].Left - 70)
+                while(coldBeer.Left <= obstacles[i].Left + 70 && coldBeer.Left >= obstacles[i].Left - 70)
                 {
                     coldBeer.Left = obstacles[i].Left + new Random().Next(71, 160);
                 }


Code cleanup.

Code cleanup.

--- source/Cosmos.Debug.DebugConnectors/DebugConnectorStreamWithoutTimeouts.cs
+++ source/Cosmos.Debug.DebugConnectors/DebugConnectorStreamWithoutTimeouts.cs
@@ -46,37 +46,25 @@
             return OK;
         }

-        public override bool IsConnected
-        {
-            get
-            {
-                return mStream != null;
-            }
-        }
+        public override bool IsConnected => mStream != null;

         // Start is not in ctor, because for servers we have to wait for the callback. This
         // however does not prevent other kind of DebugConnectorStreamWithTimeouts descendants from
         // invoking this method from their constructor.
         protected void Start(Stream aStream)
         {
-            if (aStream == null)
-            {
-                throw new ArgumentNullException("aStream");
-            }
-            mStream = aStream;
+            mStream = aStream ?? throw new ArgumentNullException("aStream");
             Start();
         }

-        public override void Dispose()
+        protected override void Dispose(bool disposing)
         {
-            base.Dispose();
-            // do our own dispose after base, because base dispose cleans up the thread.
-            if (mStream != null)
+            base.Dispose(disposing);
+
+            if (disposing)
             {
-                //TODO: Change to mStream.Close() when Stream.Close() is supported
-                mStream.Dispose();
-                //mStream.Close();
-                mStream = null;
+                // do our own dispose after base, because base dispose cleans up the thread.
+                mStream?.Dispose();
             }
         }
     }


Updated IMetaDataCacheProvider.cs to 4.0.2 compatibility.

--- src/BoboBrowse.Net/BoboBrowse.Net/Search/Section/IMetaDataCacheProvider.cs
+++ src/BoboBrowse.Net/BoboBrowse.Net/Search/Section/IMetaDataCacheProvider.cs
@@ -17,7 +17,7 @@
 //* See the License for the specific language governing permissions and
 //* limitations under the License.

-// Version compatibility level: 3.2.0
+// Version compatibility level: 4.0.2
 namespace BoboBrowse.Net.Search.Section
 {
     using Lucene.Net.Index;


Updated SectionSearchQueryPlan.cs to 4.0.2 compatibility.

--- src/BoboBrowse.Net/BoboBrowse.Net/Search/Section/SectionSearchQueryPlan.cs
+++ src/BoboBrowse.Net/BoboBrowse.Net/Search/Section/SectionSearchQueryPlan.cs
@@ -17,7 +17,7 @@
 //* See the License for the specific language governing permissions and
 //* limitations under the License.

-// Version compatibility level: 3.2.0
+// Version compatibility level: 4.0.2
 namespace BoboBrowse.Net.Search.Section
 {
     using Lucene.Net.Search;
@@ -37,8 +37,8 @@
         public class NodeQueue : PriorityQueue<SectionSearchQueryPlan>
         {
             public NodeQueue(int size)
+                : base(size)
             {
-                Initialize(size);
             }

             public override bool LessThan(SectionSearchQueryPlan nodeA, SectionSearchQueryPlan nodeB)


Fix casing.

Fix casing.

--- src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenShortCircuitOperatorTests.cs
+++ src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenShortCircuitOperatorTests.cs
@@ -7017,7 +7017,7 @@
         }

         [Fact, WorkItem(15670, "https://github.com/dotnet/roslyn/issues/15670")]
-        public void ConditionalAccessOffOfClassconstrainedDefault1()
+        public void ConditionalAccessOffOfClassConstrainedDefault1()
         {
             var source = @"
 using System;


Skip SourcePlusMetadataTests.InterfaceName test

--- src/Compilers/CSharp/Test/Symbol/Symbols/Source/SourcePlusMetadataTests.cs
+++ src/Compilers/CSharp/Test/Symbol/Symbols/Source/SourcePlusMetadataTests.cs
@@ -171,7 +171,7 @@
         }

         [WorkItem(527531, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/527531")]
-        [Fact]
+        [Fact(Skip = "https://github.com/dotnet/roslyn/issues/18985")]
         public void InterfaceName()
         {
             var text = @"


simplify

simplify

--- src/EditorFeatures/Core/Navigation/IDocumentNavigationServiceExtensions.cs
+++ src/EditorFeatures/Core/Navigation/IDocumentNavigationServiceExtensions.cs
@@ -26,37 +26,32 @@

     internal static class IDocumentNavigationServiceExtensions
     {
-        private static Task<bool> SwitchToMainThreadAndNavigateAsync(IThreadingContext threadingContext, INavigableLocation? location, NavigationOptions options, CancellationToken cancellationToken)
-        {
-            return location.NavigateToAsync(threadingContext, options, cancellationToken);
-        }
-
         public static async Task<bool> TryNavigateToSpanAsync(
             this IDocumentNavigationService service, IThreadingContext threadingContext, Workspace workspace, DocumentId documentId, TextSpan textSpan, NavigationOptions options, bool allowInvalidSpan, CancellationToken cancellationToken)
         {
             var location = await service.GetLocationForSpanAsync(workspace, documentId, textSpan, allowInvalidSpan, cancellationToken).ConfigureAwait(false);
-            return await SwitchToMainThreadAndNavigateAsync(threadingContext, location, options, cancellationToken).ConfigureAwait(false);
+            return await location.NavigateToAsync(threadingContext, options, cancellationToken).ConfigureAwait(false);
         }

         public static async Task<bool> TryNavigateToSpanAsync(
             this IDocumentNavigationService service, IThreadingContext threadingContext, Workspace workspace, DocumentId documentId, TextSpan textSpan, NavigationOptions options, CancellationToken cancellationToken)
         {
             var location = await service.GetLocationForSpanAsync(workspace, documentId, textSpan, cancellationToken).ConfigureAwait(false);
-            return await SwitchToMainThreadAndNavigateAsync(threadingContext, location, options, cancellationToken).ConfigureAwait(false);
+            return await location.NavigateToAsync(threadingContext, options, cancellationToken).ConfigureAwait(false);
         }

         public static async Task<bool> TryNavigateToSpanAsync(
             this IDocumentNavigationService service, IThreadingContext threadingContext, Workspace workspace, DocumentId documentId, TextSpan textSpan, CancellationToken cancellationToken)
         {
             var location = await service.GetLocationForSpanAsync(workspace, documentId, textSpan, cancellationToken).ConfigureAwait(false);
-            return await SwitchToMainThreadAndNavigateAsync(threadingContext, location, NavigationOptions.Default, cancellationToken).ConfigureAwait(false);
+            return await location.NavigateToAsync(threadingContext, NavigationOptions.Default, cancellationToken).ConfigureAwait(false);
         }

         public static async Task<bool> TryNavigateToPositionAsync(
             this IDocumentNavigationService service, IThreadingContext threadingContext, Workspace workspace, DocumentId documentId, int position, int virtualSpace, NavigationOptions options, CancellationToken cancellationToken)
         {
             var location = await service.GetLocationForPositionAsync(workspace, documentId, position, virtualSpace, cancellationToken).ConfigureAwait(false);
-            return await SwitchToMainThreadAndNavigateAsync(threadingContext, location, options, cancellationToken).ConfigureAwait(false);
+            return await location.NavigateToAsync(threadingContext, options, cancellationToken).ConfigureAwait(false);
         }

         public static async Task<bool> TryNavigateToPositionAsync(
@@ -64,7 +59,7 @@
         {
             var location = await service.GetLocationForPositionAsync(
                 workspace, documentId, position, cancellationToken).ConfigureAwait(false);
-            return await SwitchToMainThreadAndNavigateAsync(threadingContext, location, NavigationOptions.Default, cancellationToken).ConfigureAwait(false);
+            return await location.NavigateToAsync(threadingContext, NavigationOptions.Default, cancellationToken).ConfigureAwait(false);
         }

         public static async Task<bool> TryNavigateToLineAndOffsetAsync(
@@ -72,7 +67,7 @@
         {
             var location = await service.GetLocationForLineAndOffsetAsync(
                 workspace, documentId, lineNumber, offset, cancellationToken).ConfigureAwait(false);
-            return await SwitchToMainThreadAndNavigateAsync(threadingContext, location, options, cancellationToken).ConfigureAwait(false);
+            return await location.NavigateToAsync(threadingContext, options, cancellationToken).ConfigureAwait(false);
         }
     }
 }


clean up With...() tests

clean up With...() tests

--- Semver.Test/SemVersionWithFieldTests.cs
+++ Semver.Test/SemVersionWithFieldTests.cs
@@ -99,7 +99,7 @@
         [Fact]
         public void WithPrereleaseParsedFrom()
         {
-            var v = Version.WithPrereleaseParsedFrom("bar.baz.100.123abc", allowLeadingZeros: false);
+            var v = Version.WithPrereleaseParsedFrom("bar.baz.100.123abc");

             Assert.Equal(new SemVersion(1, 2, 3, "bar.baz.100.123abc", "metadata"), v);
         }
@@ -107,7 +107,7 @@
         [Fact]
         public void WithPrereleaseParsedFromAlreadyRelease()
         {
-            var v = ReleaseVersion.WithPrereleaseParsedFrom("", allowLeadingZeros: false);
+            var v = ReleaseVersion.WithPrereleaseParsedFrom("");

             Assert.Same(ReleaseVersion, v);
         }
@@ -115,9 +115,8 @@
         [Fact]
         public void WithPrereleaseParsedFromNull()
         {
-            string identifiers = null;
-            var ex = Assert.Throws<ArgumentNullException>(()
-                => Version.WithPrereleaseParsedFrom(identifiers, allowLeadingZeros: false));
+            var ex = Assert.Throws<ArgumentNullException>(()
+                => Version.WithPrereleaseParsedFrom(null));
             Assert.StartsWith("Value cannot be null.", ex.Message);
             Assert.Equal("prerelease", ex.ParamName);
         }
@@ -125,7 +124,7 @@
         [Fact]
         public void WithPrereleaseParsedFromEmptyString()
         {
-            var v = Version.WithPrereleaseParsedFrom("", allowLeadingZeros: false);
+            var v = Version.WithPrereleaseParsedFrom("");

             Assert.Equal(new SemVersion(1, 2, 3, "", "metadata"), v);
         }
@@ -134,7 +133,7 @@
         public void WithPrereleaseParsedFromEmptyIdentifier()
         {
             var ex = Assert.Throws<ArgumentException>(()
-                => Version.WithPrereleaseParsedFrom("bar.", allowLeadingZeros: false));
+                => Version.WithPrereleaseParsedFrom("bar."));
             Assert.StartsWith("Prerelease identifier cannot be empty.", ex.Message);
             Assert.Equal("prerelease", ex.ParamName);
         }
@@ -143,7 +142,7 @@
         public void WithPrereleaseParsedFromLeadingZeros()
         {
             var ex = Assert.Throws<ArgumentException>(()
-                => Version.WithPrereleaseParsedFrom("bar.0123", allowLeadingZeros: false));
+                => Version.WithPrereleaseParsedFrom("bar.0123"));
             Assert.StartsWith("Leading zeros are not allowed on numeric prerelease identifiers '0123'.", ex.Message);
             Assert.Equal("prerelease", ex.ParamName);
         }
@@ -160,7 +159,7 @@
         public void WithPrereleaseParsedFromTooLarge()
         {
             var ex = Assert.Throws<OverflowException>(()
-               => Version.WithPrereleaseParsedFrom("bar.99999999999999999", allowLeadingZeros: false));
+               => Version.WithPrereleaseParsedFrom("bar.99999999999999999"));
             Assert.StartsWith("Prerelease identifier '99999999999999999' was too large for Int32.", ex.Message);
         }

@@ -168,7 +167,7 @@
         public void WithPrereleaseParsedFromInvalidCharacter()
         {
             var ex = Assert.Throws<ArgumentException>(()
-                => Version.WithPrereleaseParsedFrom("bar.abc@123", allowLeadingZeros: false));
+                => Version.WithPrereleaseParsedFrom("bar.abc@123"));
             Assert.StartsWith("A prerelease identifier can contain only ASCII alphanumeric characters and hyphens 'abc@123'.", ex.Message);
             Assert.Equal("prerelease", ex.ParamName);
         }
@@ -277,7 +276,7 @@
         [Fact]
         public void WithPrereleaseStringEnumerable()
         {
-            var v = Version.WithPrerelease(new[] { "bar", "baz", "100", "123abc" }.AsEnumerable());
+            var v = Version.WithPrerelease(new[] { "bar", "baz", "100", "123abc" });

             Assert.Equal(new SemVersion(1, 2, 3, "bar.baz.100.123abc", "metadata"), v);
         }
@@ -293,9 +292,8 @@
         [Fact]
         public void WithPrereleaseStringEnumerableNull()
         {
-            IEnumerable<string> identifiers = null;
-            var ex = Assert.Throws<ArgumentNullException>(()
-                => Version.WithPrerelease(identifiers));
+            var ex = Assert.Throws<ArgumentNullException>(()
+                => Version.WithPrerelease((IEnumerable<string>)null));
             Assert.StartsWith("Value cannot be null.", ex.Message);
             Assert.Equal("prereleaseIdentifiers", ex.ParamName);
         }
@@ -312,7 +310,7 @@
         public void WithPrereleaseStringEnumerableEmptyIdentifier()
         {
             var ex = Assert.Throws<ArgumentException>(()
-                => Version.WithPrerelease(new[] { "bar", "" }.AsEnumerable()));
+                => Version.WithPrerelease(new[] { "bar", "" }));
             Assert.StartsWith("Prerelease identifier cannot be empty.", ex.Message);
             Assert.Equal("prereleaseIdentifiers", ex.ParamName);
         }
@@ -321,7 +319,7 @@
         public void WithPrereleaseStringEnumerableNullIdentifier()
         {
             var ex = Assert.Throws<ArgumentNullException>(()
-                => Version.WithPrerelease(new[] { "bar", null }.AsEnumerable()));
+                => Version.WithPrerelease(new[] { "bar", null }));
             Assert.StartsWith("Value cannot be null.", ex.Message);
             Assert.Equal("prereleaseIdentifiers", ex.ParamName);
         }
@@ -330,7 +328,7 @@
         public void WithPrereleaseStringEnumerableLeadingZeros()
         {
             var ex = Assert.Throws<ArgumentException>(()
-                => Version.WithPrerelease(new[] { "bar", "0123" }.AsEnumerable()));
+                => Version.WithPrerelease(new[] { "bar", "0123" }));
             Assert.StartsWith("Leading zeros are not allowed on numeric prerelease identifiers '0123'.", ex.Message);
             Assert.Equal("prereleaseIdentifiers", ex.ParamName);
         }
@@ -339,7 +337,7 @@
         public void WithPrereleaseStringEnumerableTooLarge()
         {
             var ex = Assert.Throws<OverflowException>(()
-                => Version.WithPrerelease(new[] { "bar", "99999999999999999" }.AsEnumerable()));
+                => Version.WithPrerelease(new[] { "bar", "99999999999999999" }));
             Assert.StartsWith("Prerelease identifier '99999999999999999' was too large for Int32.", ex.Message);
         }

@@ -347,7 +345,7 @@
         public void WithPrereleaseStringEnumerableInvalidCharacter()
         {
             var ex = Assert.Throws<ArgumentException>(()
-                => Version.WithPrerelease(new[] { "bar", "abc@123" }.AsEnumerable()));
+                => Version.WithPrerelease(new[] { "bar", "abc@123" }));
             Assert.StartsWith("A prerelease identifier can contain only ASCII alphanumeric characters and hyphens 'abc@123'.", ex.Message);
             Assert.Equal("prereleaseIdentifiers", ex.ParamName);
         }
@@ -379,7 +377,7 @@
         public void WithPrereleaseIdentifierParamsDefaultIdentifierInFirst()
         {
             var ex = Assert.Throws<ArgumentException>(() => Version.WithPrerelease(
-                default, new PrereleaseIdentifier("bar"), default));
+                default, new PrereleaseIdentifier("bar")));
             Assert.StartsWith("Prerelease identifier cannot be default/null.", ex.Message);
             Assert.Equal("prereleaseIdentifiers", ex.ParamName);
         }
@@ -420,8 +418,8 @@
         [Fact]
         public void WithPrereleaseIdentifiersNull()
         {
-            IEnumerable<PrereleaseIdentifier> identifiers = null;
-            var ex = Assert.Throws<ArgumentNullException>(() => Version.WithPrerelease(identifiers));
+            var ex = Assert.Throws<ArgumentNullException>(()
+                => Version.WithPrerelease((IEnumerable<PrereleaseIdentifier>)null));
             Assert.StartsWith("Value cannot be null.", ex.Message);
             Assert.Equal("prereleaseIdentifiers", ex.ParamName);
         }
@@ -482,9 +480,8 @@
         [Fact]
         public void WithMetadataParsedFromNull()
         {
-            string identifiers = null;
-            var ex = Assert.Throws<ArgumentNullException>(()
-                => Version.WithMetadataParsedFrom(identifiers));
+            var ex = Assert.Throws<ArgumentNullException>(()
+                => Version.WithMetadataParsedFrom(null));
             Assert.StartsWith("Value cannot be null.", ex.Message);
             Assert.Equal("metadata", ex.ParamName);
         }
@@ -576,7 +573,8 @@
         [Fact]
         public void WithMetadataStringParamsNullIdentifierInRest()
         {
-            var ex = Assert.Throws<ArgumentNullException>(() => Version.WithMetadata("bar", "baz", null));
+            var ex = Assert.Throws<ArgumentNullException>(()
+                => Version.WithMetadata("bar", "baz", null));
             Assert.StartsWith("Value cannot be null.", ex.Message);
             Assert.Equal("metadataIdentifiers", ex.ParamName);
         }
@@ -627,7 +625,9 @@
         public void WithMetadataStringParamsInvalidCharacterInRest()
         {
             var ex = Assert.Throws<ArgumentException>(() => Version.WithMetadata("bar", "abc@123"));
-            Assert.StartsWith("A metadata identifier can contain only ASCII alphanumeric characters and hyphens 'abc@123'.", ex.Message);
+            Assert.StartsWith(
+                "A metadata identifier can contain only ASCII alphanumeric characters and hyphens 'abc@123'.",
+                ex.Message);
             Assert.Equal("metadataIdentifiers", ex.ParamName);
         }
         #endregion
@@ -636,7 +636,7 @@
         [Fact]
         public void WithMetadataEnumerable()
         {
-            var v = Version.WithMetadata(new List<string> { "bar", "baz", "100", "123abc" });
+            var v = Version.WithMetadata(new[] { "bar", "baz", "100", "123abc" });

             Assert.Equal(new SemVersion(1, 2, 3, "pre", "bar.baz.100.123abc"), v);
         }
@@ -652,8 +652,8 @@
         [Fact]
         public void WithMetadataEnumerableNull()
         {
-            IEnumerable<string> identifiers = null;
-            var ex = Assert.Throws<ArgumentNullException>(() => Version.WithMetadata(identifiers));
+            var ex = Assert.Throws<ArgumentNullException>(()
+                => Version.WithMetadata((IEnumerable<string>)null));
             Assert.StartsWith("Value cannot be null.", ex.Message);
             Assert.Equal("metadataIdentifiers", ex.ParamName);
         }
@@ -670,7 +670,7 @@
         public void WithMetadataEnumerableEmptyIdentifier()
         {
             var ex = Assert.Throws<ArgumentException>(()
-                => Version.WithMetadata(new List<string> { "bar", "" }));
+                => Version.WithMetadata(new[] { "bar", "" }));
             Assert.StartsWith("Metadata identifier cannot be empty.", ex.Message);
             Assert.Equal("metadataIdentifiers", ex.ParamName);
         }
@@ -679,7 +679,7 @@
         public void WithMetadataEnumerableNullIdentifier()
         {
             var ex = Assert.Throws<ArgumentNullException>(()
-                => Version.WithMetadata(new List<string> { "bar", null }));
+                => Version.WithMetadata(new[] { "bar", null }));
             Assert.StartsWith("Value cannot be null.", ex.Message);
             Assert.Equal("metadataIdentifiers", ex.ParamName);
         }
@@ -687,7 +687,7 @@
         [Fact]
         public void WithMetadataEnumerableLeadingZeros()
         {
-            var v = Version.WithMetadata(new List<string> { "bar", "0123" });
+            var v = Version.WithMetadata(new[] { "bar", "0123" });

             Assert.Equal(new SemVersion(1, 2, 3, "pre", "bar.0123"), v);
         }
@@ -695,7 +695,7 @@
         [Fact]
         public void WithMetadataEnumerableTooLarge()
         {
-            var v = Version.WithMetadata(new List<string> { "bar", "99999999999999999" });
+            var v = Version.WithMetadata(new[] { "bar", "99999999999999999" });

             Assert.Equal(new SemVersion(1, 2, 3, "pre", "bar.99999999999999999"), v);
         }
@@ -704,8 +704,10 @@
         public void WithMetadataEnumerableInvalidCharacter()
         {
             var ex = Assert.Throws<ArgumentException>(()
-                => Version.WithMetadata(new List<string> { "bar", "abc@123" }));
-            Assert.StartsWith("A metadata identifier can contain only ASCII alphanumeric characters and hyphens 'abc@123'.", ex.Message);
+                => Version.WithMetadata(new[] { "bar", "abc@123" }));
+            Assert.StartsWith(
+                "A metadata identifier can contain only ASCII alphanumeric characters and hyphens 'abc@123'.",
+                ex.Message);
             Assert.Equal("metadataIdentifiers", ex.ParamName);
         }
         #endregion
@@ -726,8 +728,8 @@
         [Fact]
         public void WithMetadataIdentifierParamsRestNull()
         {
-            var ex = Assert.Throws<ArgumentNullException>(() => Version.WithMetadata(
-                new MetadataIdentifier("bar"), null));
+            var ex = Assert.Throws<ArgumentNullException>(()
+                => Version.WithMetadata(new MetadataIdentifier("bar"), null));
             Assert.StartsWith("Value cannot be null.", ex.Message);
             Assert.Equal("metadataIdentifiers", ex.ParamName);
         }
@@ -735,8 +737,8 @@
         [Fact]
         public void WithMetadataIdentifierParamsDefaultIdentifierInFirst()
         {
-            var ex = Assert.Throws<ArgumentException>(() => Version.WithMetadata(
-                default, new MetadataIdentifier("bar"), default));
+            var ex = Assert.Throws<ArgumentException>(()
+                => Version.WithMetadata(default, new MetadataIdentifier("bar")));
             Assert.StartsWith("Metadata identifier cannot be default/null.", ex.Message);
             Assert.Equal("metadataIdentifiers", ex.ParamName);
         }
@@ -777,8 +779,8 @@
         [Fact]
         public void WithMetadataIdentifiersNull()
         {
-            IEnumerable<MetadataIdentifier> identifiers = null;
-            var ex = Assert.Throws<ArgumentNullException>(() => Version.WithMetadata(identifiers));
+            var ex = Assert.Throws<ArgumentNullException>(()
+                => Version.WithMetadata((IEnumerable<MetadataIdentifier>)null));
             Assert.StartsWith("Value cannot be null.", ex.Message);
             Assert.Equal("metadataIdentifiers", ex.ParamName);
         }


transactional cache

transactional cache

--- Signum.Engine/Connection/Transaction.cs
+++ Signum.Engine/Connection/Transaction.cs
@@ -387,7 +387,8 @@
                 avoidIndependentTransactions.Value = true;
             }

-            public virtual void Commit()
+
+            public override void Commit()
             {
                 if (Started)
                 {


fix Reflector contraint

fix Reflector contraint

--- Signum.Entities/Reflection/Reflector.cs
+++ Signum.Entities/Reflection/Reflector.cs
@@ -476,12 +476,12 @@
                 throw new FormatException("'{0}' is not a valid identifier".FormatWith(step));
         }

-        public static PropertyInfo PropertyInfo<T>(this T entity, Expression<Func<T, object>> property) where T : Entity
+        public static PropertyInfo PropertyInfo<T>(this T entity, Expression<Func<T, object>> property) where T : ModifiableEntity
         {
             return ReflectionTools.GetPropertyInfo(property);
         }

-        public static string NicePropertyName<T>(this T entity, Expression<Func<T, object>> property) where T : Entity
+        public static string NicePropertyName<T>(this T entity, Expression<Func<T, object>> property) where T : ModifiableEntity
         {
             return ReflectionTools.GetPropertyInfo(property).NiceName();
         }


add _0DoesNotHaveAValid1IdentifierFormat

--- Signum.Entities/ValidationAttributes.cs
+++ Signum.Entities/ValidationAttributes.cs
@@ -966,6 +966,8 @@
     {
         [Description("{0} does not have a valid {1} format")]
         _0DoesNotHaveAValid1Format,
+        [Description("'{0}' does not have a valid {1} identifier format")]
+        _0DoesNotHaveAValid1IdentifierFormat,
         [Description("{0} has an invalid format")]
         _0HasAnInvalidFormat,
         [Description("{0} has more than {1} decimal places")]


add note about original basis of code

add note about original basis of code

--- src/LionFire.Orleans.Http.Swagger/SwashbuckleOrleansDescriptionProvider.cs
+++ src/LionFire.Orleans.Http.Swagger/SwashbuckleOrleansDescriptionProvider.cs
@@ -1,3 +1,5 @@
+// Based on this PR: https://github.com/OrleansContrib/Orleans.Http/pull/43#issuecomment-1165691331
+
 using Microsoft.AspNetCore.Mvc.Abstractions;
 using Microsoft.AspNetCore.Mvc.ActionConstraints;
 using Microsoft.AspNetCore.Mvc.ApiExplorer;
@@ -127,28 +129,28 @@
                     Properties = new Dictionary<object, object>()
                 };

-                var pattern = methodAttributes.Pattern;
-                if(string.IsNullOrWhiteSpace(pattern))
-                {
-                    pattern = "{optionalPrefix}/{optionalTopLevelPattern}{grainTypeName}/{grainId}/{methodName}";
-                }
-                string optionalPrefix = "grians"; // TODO MOVE to configuration
-                string optionalTopLevelPatternWithTrailingSlash = ""; // TODO MOVE to configuration
-
-                var relativePath = pattern
-                    .Replace("{optionalPrefix}", optionalPrefix)
-                    .Replace("{optionalTopLevelPattern}", optionalTopLevelPatternWithTrailingSlash)
-                    .Replace("{grainTypeName}", grainType.FullName)
-                    .Replace("{methodName}", methodInfo.Name)
-                    ;
-
-                var description = new ApiDescription()
-                {
-                    ActionDescriptor = descriptor,
-                    //GroupName = groupName, // Causes things to be skipped by default if the group doesn't match the documentName (SwaggerGeneratorOptions.DefaultOperationIdSelector)
-                    HttpMethod = methodAttributes.Method,
-                    RelativePath = relativePath
-                };
+    var pattern = methodAttributes.Pattern;
+    if(string.IsNullOrWhiteSpace(pattern))
+    {
+        pattern = "{optionalPrefix}/{optionalTopLevelPattern}{grainTypeName}/{grainId}/{methodName}";
+    }
+    string optionalPrefix = "grains"; // TODO MOVE to configuration
+    string optionalTopLevelPatternWithTrailingSlash = ""; // TODO MOVE to configuration
+
+    var relativePath = pattern
+        .Replace("{optionalPrefix}", optionalPrefix)
+        .Replace("{optionalTopLevelPattern}", optionalTopLevelPatternWithTrailingSlash)
+        .Replace("{grainTypeName}", grainType.FullName)
+        .Replace("{methodName}", methodInfo.Name)
+        ;
+
+    var description = new ApiDescription()
+    {
+        ActionDescriptor = descriptor,
+        //GroupName = groupName, // Causes things to be skipped by default if the group doesn't match the documentName (SwaggerGeneratorOptions.DefaultOperationIdSelector)
+        HttpMethod = methodAttributes.Method,
+        RelativePath = relativePath
+    };

                 var methodParams = methodInfo.GetParameters();


add ValidationMessage._0IsEmpty

add ValidationMessage._0IsEmpty

--- Signum.Entities/ValidationAttributes.cs
+++ Signum.Entities/ValidationAttributes.cs
@@ -1094,5 +1094,7 @@
         _0And1And2CanNotBeSetAtTheSameTime,
         [Description("{0} have {1} elements, but allowed only {2}")]
         _0Have1ElementsButAllowedOnly2,
+        [Description("{0} is empty")]
+        _0IsEmpty,
     }
 }


Accordion view - switched from model Article to model ItemList - added media and link

--- Site/Views/Entity/Core/Accordion.cshtml
+++ Site/Views/Entity/Core/Accordion.cshtml
@@ -1,65 +1,47 @@
-@model Sdl.Web.Mvc.Models.Article
+@model Sdl.Web.Mvc.Models.ItemList

-    @if (Model.Image != null)
-    {
-

-

-

-                    @Html.Image(Model.Image, 3.3, "center-block")
-

-
@Model.Headline

-

-

-

-

-    }
-    else
-    {
-
@Model.Headline

-    }
-    @if (@Model.Date != null)
-    {
-

-            @Html.Date(Model.Date)
-

-    }

-        @if (Model.ArticleBody != null)
+        @if (Model.Headline != null)
+        {
+
@Model.Headline

+        }
+        @if (Model.ItemListElements.Count > 0)
         {
             int i = 0;
             string accordionId = Guid.NewGuid().ToString();

-                @foreach (var para in Model.ArticleBody)
+                @foreach (Teaser element in Model.ItemListElements)
                 {
                     string collapseId = Guid.NewGuid().ToString();
-

-                        @if (para.Subheading != null)
+

+                        @if (element.Headline != null)
                         {

-

-                                    @para.Subheading
+

+                                    @element.Headline

                         }
-                        @if (para.Content != null)
+                        @if (element.Text!= null)
                         {
+

+

+                                    @Html.Raw(element.Text)

-

-

-                                    @Html.Raw(para.Content)
+                                    @if (element.Media != null)
+                                    {
+

+                                            @Html.Media(element.Media)
+

+                                    }
+
+                                    @if (element.Link != null)
+                                    {
+

+                                            @(element.Link.LinkText ?? Html.Resource("core.readMoreLinkText"))
+

+                                    }

-                                @if (para.Media != null && para.Media is Image)
-                                {
-

-                                        @Html.Image(((Image)para.Media))
-                                        @if (para.Caption != null)
-                                        {
-

-                                                @para.Caption
-

-                                        }
-

-                                }

                         }


DNN-10760 : Pages "All Users" permissions are not saved

--- src/Modules/Content/Dnn.PersonaBar.Pages/Components/PagesControllerImpl.cs
+++ src/Modules/Content/Dnn.PersonaBar.Pages/Components/PagesControllerImpl.cs
@@ -1113,7 +1113,7 @@
                 foreach (var rolePermission in permissions.RolePermissions.Where(NoLocked()))
                 {
                     var role = RoleController.Instance.GetRoleById(portalSettings.PortalId, rolePermission.RoleId);
-                    if (role != null)
+                    if (role != null || (rolePermission.RoleId.ToString() == Globals.glbRoleAllUsers))
                     {
                         foreach (var permission in rolePermission.Permissions)
                         {


Alias removal is now executed on the published version of a content (#8100) (#8150)

--- src/Orchard.Web/Modules/Orchard.Autoroute/Handlers/AutoroutePartHandler.cs
+++ src/Orchard.Web/Modules/Orchard.Autoroute/Handlers/AutoroutePartHandler.cs
@@ -11,6 +11,7 @@
     public class AutoroutePartHandler : ContentHandler {

         private readonly Lazy<IAutorouteService> _autorouteService;
+        private readonly IContentManager _contentManager;
         private readonly IOrchardServices _orchardServices;
         private readonly IHomeAliasService _homeAliasService;

@@ -19,11 +20,13 @@
         public AutoroutePartHandler(
             IRepository<AutoroutePartRecord> autoroutePartRepository,
             Lazy<IAutorouteService> autorouteService,
+            IContentManager contentManager,
             IOrchardServices orchardServices,
             IHomeAliasService homeAliasService) {

             Filters.Add(StorageFilter.For(autoroutePartRepository));
             _autorouteService = autorouteService;
+            _contentManager = contentManager;
             _orchardServices = orchardServices;
             _homeAliasService = homeAliasService;

@@ -40,8 +43,8 @@

             // Remove alias if destroyed, removed or unpublished
             OnRemoving<AutoroutePart>((ctx, part) => RemoveAlias(part));
-            OnDestroyed<AutoroutePart>((ctx, part) => RemoveAlias(part));
-            OnUnpublished<AutoroutePart>((ctx, part) => RemoveAlias(part));
+            OnDestroying<AutoroutePart>((ctx, part) => RemoveAlias(part));
+            OnUnpublishing<AutoroutePart>((ctx, part) => RemoveAlias(part));

             // Register alias as identity
             OnGetContentItemMetadata<AutoroutePart>((ctx, part) => {
@@ -106,7 +109,9 @@
             if (part.ContentItem.Id == homePageId) {
                 _orchardServices.Notifier.Warning(T("You removed the content item that served as the site's home page. \nMost possibly this means that instead of the home page a \"404 Not Found\" page will be displayed. \n\nTo prevent this you can e.g. publish a content item that has the \"Set as home page\" checkbox ticked."));
             }
-            _autorouteService.Value.RemoveAliases(part);
+
+            var publishedPart = _contentManager.Get<AutoroutePart>(part.ContentItem.Id, VersionOptions.Published);
+            _autorouteService.Value.RemoveAliases(publishedPart);
         }
     }
 }


Removed unnecessary check for "/".

Removed unnecessary check for "/".

The DisplayAlias of a content item will not be set to "" or "/" for the item to become the homepage, so there's no need to check for the display alias to be "/".

--- src/Orchard.Web/Modules/Orchard.Autoroute/Handlers/AutoroutePartHandler.cs
+++ src/Orchard.Web/Modules/Orchard.Autoroute/Handlers/AutoroutePartHandler.cs
@@ -91,13 +91,11 @@
             }

             // Check for permalink conflict, unless we are trying to set the home page.
-            if (part.DisplayAlias != "/") {
-                var previous = part.Path;
-                if (!_autorouteService.Value.ProcessPath(part))
-                    _orchardServices.Notifier.Warning(
-                        T("Permalinks in conflict. \"{0}\" is already set for a previously created {2} so now it has the slug \"{1}\"",
-                                                 previous, part.Path, part.ContentItem.ContentType));
-            }
+            var previous = part.Path;
+            if (!_autorouteService.Value.ProcessPath(part))
+                _orchardServices.Notifier.Warning(
+                    T("Permalinks in conflict. \"{0}\" is already set for a previously created {2} so now it has the slug \"{1}\"",
+                                                previous, part.Path, part.ContentItem.ContentType));
         }

         void RemoveAlias(AutoroutePart part) {


Removed copy/pasting error

Removed copy/pasting error

--HG--
branch : dev

--- src/Orchard.Web/Modules/Orchard.Blogs/DataMigrations/BlogsDataMigration.cs
+++ src/Orchard.Web/Modules/Orchard.Blogs/DataMigrations/BlogsDataMigration.cs
@@ -24,8 +24,6 @@
                 .Column<string>("Description")
                 .Column<int>("PostCount")
                 );
-
-            SchemaBuilder.CreateForeignKey()

             return 1;
         }


725: add debug note,

725: add debug note,

--- src/PixelFarm/LayoutFarm.YourBasicCustomWidgets/1_UIElement/1_UIElement.cs
+++ src/PixelFarm/LayoutFarm.YourBasicCustomWidgets/1_UIElement/1_UIElement.cs
@@ -21,9 +21,17 @@
             int count = s_layoutQueue.Count;
             for (int i = count - 1; i >= 0; --i)
             {
-                UIElement ui = s_layoutQueue.Dequeue();
+                UIElement ui = s_layoutQueue.Dequeue();
                 ui.IsInLayoutQueue = false;
                 UIElement.InvokeContentLayout(ui);
+
+#if DEBUG
+                if (ui.IsInLayoutQueue)
+                {
+                    //should not occur
+                    throw new System.NotSupportedException();
+                }
+#endif
             }
         }
     }
@@ -42,9 +50,6 @@
         float _right;
         float _bottom;

-
-        //~
-
         public UIElement()
         {
         }
@@ -59,7 +64,7 @@
         }
         public abstract void InvalidateGraphics();

-
+
         object _tag;
         public object Tag
         {


re#3912 - changes credit cards api call

re#3912 - changes credit cards api call

--- SnapMD.ConnectedCare.Sdk/PaymentsApi.cs
+++ SnapMD.ConnectedCare.Sdk/PaymentsApi.cs
@@ -35,7 +35,7 @@
         public ApiResponseV2<CimCustomer> GetCustomerProfile(int? patientUserId)
         {
             //API looks so strange
-            var result = MakeCall<ApiResponseV2<CimCustomer>>(string.Format("v2/patients/{0}/payments", patientUserId));
+            var result = MakeCall<ApiResponseV2<CimCustomer>>(string.Format("v2/patients/payments", patientUserId));
             return result;
         }


Problem found

Problem found

It is necessary to run in Integrated Pipeline in order to
allow http modules to handle statically served files. This
is new to IIS 7.

--- SnittListan/Views/Shared/_Layout.cshtml
+++ SnittListan/Views/Shared/_Layout.cshtml
@@ -35,7 +35,6 @@
     <script type="text/javascript">
         var logErrorUrl = '@Url.Action("LogJavaScriptError", "Error")';
     </script>
-    @Content.Script("stacktrace.js", Url)
     @Content.Script("stacktrace.min.js", Url)
     @RenderSection("scripts", false)
 </body>


Implement Reverse Chaining Contextual Single Substitution

--- src/SixLabors.Fonts/Tables/AdvancedTypographic/Gsub/LookupType8SubTable.cs
+++ src/SixLabors.Fonts/Tables/AdvancedTypographic/Gsub/LookupType8SubTable.cs
@@ -95,6 +95,7 @@

         public override bool TrySubstitution(GSubTable table, GlyphSubstitutionCollection collection, ushort index, int count)
         {
+            // https://docs.microsoft.com/en-us/typography/opentype/spec/gsub#81-reverse-chaining-contextual-single-substitution-format-1-coverage-based-glyph-contexts
             int glyphId = collection[index][0];
             if (glyphId < 0)
             {
@@ -102,15 +103,38 @@
             }

             int offset = this.coverageTable.CoverageIndexOf((ushort)glyphId);
-
-            if (offset > -1)
+            if (offset <= -1)
             {
-                // TODO: Implement
-                // https://docs.microsoft.com/en-us/typography/opentype/spec/gsub#81-reverse-chaining-contextual-single-substitution-format-1-coverage-based-glyph-contexts
                 return false;
             }

-            return false;
+            for (int i = 0; i < this.backtrackCoverageTables.Length; ++i)
+            {
+                int id = collection[index - 1 - i][0];
+                if (id < 0 || this.backtrackCoverageTables[i].CoverageIndexOf((ushort)id) < 0)
+                {
+                    return false;
+                }
+            }
+
+            for (int i = 0; i < this.lookaheadCoverageTables.Length; ++i)
+            {
+                int id = collection[index + i][0];
+                if (id < 0 || this.lookaheadCoverageTables[i].CoverageIndexOf((ushort)id) < 0)
+                {
+                    return false;
+                }
+            }
+
+            // It's a match. Perform substitutions and return true if anything changed.
+            bool hasChanged = false;
+            for (int i = 0; i < this.substituteGlyphIds.Length; i++)
+            {
+                collection.Replace(index + i, this.substituteGlyphIds[i]);
+                hasChanged = true;
+            }
+
+            return hasChanged;
         }

         public readonly struct AlternateSetTable
@@ -118,7 +142,7 @@
             public AlternateSetTable(int[] alternateGlyphs)
                 => this.AlternateGlyphs = alternateGlyphs;

-            public readonly int[] AlternateGlyphs { get; }
+            public int[] AlternateGlyphs { get; }
         }
     }
 }


My "and" as in the wrong place

My "and" as in the wrong place

--- src/Umbraco.Web/HealthCheck/NotificationMethods/SlackNotificationMethod.cs
+++ src/Umbraco.Web/HealthCheck/NotificationMethods/SlackNotificationMethod.cs
@@ -93,7 +93,7 @@
                 var errorAttachment = GenerateAttachment(errorResults, "danger", errorTitle);
                 attachments.Add(errorAttachment);

-                messageText = string.Format("{0} Health {1} failed {2} and", errorResults.Count, errorResults.Count > 1 ? checkStringPural : checkString, messageText);
+                messageText = string.Format("{0} Health {1} failed and {2}", errorResults.Count, errorResults.Count > 1 ? checkStringPural : checkString, messageText);
             }

             var slackMessage = new SlackMessage


simplify

simplify

--- src/Workspaces/Core/Portable/DesignerAttribute/DesignerAttributeHelpers.cs
+++ src/Workspaces/Core/Portable/DesignerAttribute/DesignerAttributeHelpers.cs
@@ -51,10 +51,8 @@

                 // if it has designer attribute, set it
                 var attribute = type.GetAttributes().FirstOrDefault(d => designerCategoryType.Equals(d.AttributeClass));
-                if (attribute != null && attribute.ConstructorArguments.Length == 1)
-                {
+                if (attribute?.ConstructorArguments.Length == 1)
                     return GetArgumentString(attribute.ConstructorArguments[0]);
-                }
             }

             return null;


Extending check for matching template classes (a bit)...

--- Source/CsDebugScript.Engine/CodeType.cs
+++ Source/CsDebugScript.Engine/CodeType.cs
@@ -688,10 +688,14 @@
                 return true;

             // TODO: Do better matching of generics type
-            if (className.EndsWith("<>"))
-            {
-                if (name.StartsWith(className.Substring(0, className.Length - 1)))
-                    return true;
+            if (className.Contains("<>"))
+            {
+                string[] partials = className.Split(new string[] { "<>" }, StringSplitOptions.RemoveEmptyEntries);
+
+                foreach (string p in partials)
+                    if (!name.Contains(p))
+                        return false;
+                return true;
             }

             return false;


Implement async/await data portal methods. bugid: 1036

--- Source/Csla.Silverlight/BusinessBase.cs
+++ Source/Csla.Silverlight/BusinessBase.cs
@@ -329,6 +329,50 @@
       this.BeginSave(forceUpdate, handler, null);
     }

+#if WINRT
+    /// <summary>
+    /// Saves the object to the database.
+    /// </summary>
+    public async System.Threading.Tasks.Task<T> SaveAsync()
+    {
+      T result;
+      if (this.IsChild)
+        throw new InvalidOperationException(Resources.NoSaveChildException);
+      if (EditLevel > 0)
+        throw new InvalidOperationException(Resources.NoSaveEditingException);
+      if (!IsValid && !IsDeleted)
+        throw new Rules.ValidationException(Resources.NoSaveInvalidException);
+      if (IsBusy)
+        throw new InvalidOperationException(Resources.BusyObjectsMayNotBeSaved);
+      if (IsDirty)
+        result = await DataPortal.UpdateAsync<T>(this);
+      else
+        result = (T)this;
+      OnSaved(result, null, null);
+      return result;
+    }
+
+    /// <summary>
+    /// Saves the object to the database.
+    /// </summary>
+    /// <param name="forceUpdate">
+    /// If <see langword="true"/>, triggers overriding IsNew and IsDirty.
+    /// If <see langword="false"/> then it is the same as calling Save().
+    /// </param>
+    public async virtual System.Threading.Tasks.Task<T> SaveAsync(bool forceUpdate)
+    {
+      if (forceUpdate && IsNew)
+      {
+        // mark the object as old - which makes it
+        // not dirty
+        MarkOld();
+        // now mark the object as dirty so it can save
+        MarkDirty(true);
+      }
+      return await this.SaveAsync();
+    }
+#endif
+
     #endregion

     #region  Register Properties


Editor- show cursor when outside game area

--- Source/Editor/AGS.Editor/GameToolbar.cs
+++ Source/Editor/AGS.Editor/GameToolbar.cs
@@ -23,6 +23,7 @@
         public GameToolbar(EditorShouldBlockEngineInput blocker, IInput editorInput, IGameSettings settings)
         {
             _editorInput = editorInput;
+            _editorInput.MouseMove.Subscribe(onMouseMove);
             _blocker = blocker;
             _font = settings.Defaults.TextFont;
         }
@@ -88,12 +89,13 @@
             setPosition();
         }

+        private bool isPaused => _playPauseButton.Text == FontIcons.Play;
+
         private void onPlayPauseClicked(MouseButtonEventArgs obj)
         {
             _playPauseButton.Text = _playPauseButton.Text == FontIcons.Pause ? FontIcons.Play : FontIcons.Pause;
-            bool isPaused = _playPauseButton.Text == FontIcons.Play;
             _blocker.BlockEngine = isPaused;
-            _editorInput.Cursor = isPaused ? _pointer : null;
+            updateEditorCursor(_editorInput.MousePosition);
             if (isPaused) _lastGameCursor = _game.Input.Cursor;
             _game.Input.Cursor = isPaused ? null : _lastGameCursor;
         }
@@ -115,5 +117,33 @@
             HotspotLabel hotspot = new HotspotLabel(game, _hotspotLabel) { DebugMode = true };
             hotspot.Start();
         }
+
+        private void onMouseMove(MousePositionEventArgs args)
+        {
+            updateEditorCursor(args.MousePosition);
+        }
+
+        private void updateEditorCursor(MousePosition mousePosition)
+        {
+            if (isPaused)
+            {
+                if (_editorInput.Cursor != null) return;
+                _editorInput.Cursor = _pointer;
+                return;
+            }
+
+            var viewport = _game.State.Viewport;
+            if (mousePosition.XWindow < viewport.ScreenArea.X ||
+                mousePosition.XWindow > viewport.ScreenArea.X + viewport.ScreenArea.Width ||
+                mousePosition.YWindow < viewport.ScreenArea.Y ||
+                mousePosition.YWindow > viewport.ScreenArea.Y + viewport.ScreenArea.Height)
+            {
+                _editorInput.Cursor = _pointer;
+            }
+            else
+            {
+                _editorInput.Cursor = null;
+            }
+        }
     }
 }


TabControl: set parent to null after removing the tab from the handler

--- Source/Eto/Forms/Controls/TabControl.cs
+++ Source/Eto/Forms/Controls/TabControl.cs
@@ -75,8 +75,8 @@

 		internal void RemoveTab (int index, TabPage page)
 		{
-			//page.SetParent (null);
 			handler.RemoveTab (index, page);
+			page.SetParent (null);
 		}

 		internal void ClearTabs ()


ZOMBIES!!!

ZOMBIES!!!

--- Source/LibWhipLru/Cache/CacheManager.cs
+++ Source/LibWhipLru/Cache/CacheManager.cs
@@ -1,676 +0,0 @@
-// CacheManager.cs
-//
-// Author:
-//       Ricky Curtice <ricky@rwcproductions.com>
-//
-// Copyright (c) 2017 Richard Curtice
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Diagnostics.Contracts;
-using System.IO;
-using System.IO.MemoryMappedFiles;
-using System.Linq;
-using System.Reflection;
-using System.Text;
-using System.Threading;
-using Chattel;
-using InWorldz.Data.Assets.Stratus;
-using LightningDB;
-using log4net;
-
-namespace LibWhipLru.Cache {
-	public class CacheManager : IDisposable {
-		private static readonly ILog LOG = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
-
-		public static readonly string DEFAULT_DB_FOLDER_PATH = "cache";
-		public static readonly ulong DEFAULT_DB_MAX_DISK_BYTES = uint.MaxValue/*4TB, maximum size of single asset*/;
-		public static readonly string DEFAULT_WC_FILE_PATH = "whip_lru.whipwcache";
-		public static readonly uint DEFAULT_WC_RECORD_COUNT = 1024U * 1024U * 1024U/*1GB*/ / IdWriteCacheNode.BYTE_SIZE;
-		public static readonly uint DEFAULT_NC_LIFETIME_SECONDS = 60 * 2;
-
-		private LightningEnvironment _dbenv;
-		private object _dbenv_lock = new object();
-		private CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
-
-		private readonly OrderedGuidCache _activeIds;
-		private ChattelReader _assetReader;
-		private ChattelWriter _assetWriter;
-
-		public IEnumerable<Guid> ActiveIds(string prefix) => _activeIds?.ItemsWithPrefix(prefix);
-
-		// Storage for assets that are WIP for remote storage.
-		private static readonly byte[] WRITE_CACHE_MAGIC_NUMBER = Encoding.ASCII.GetBytes("WHIPLRU1");
-		private string _pathToWriteCacheFile;
-		private BlockingCollection<IdWriteCacheNode> _assetsToWriteToRemoteStorage;
-		private IdWriteCacheNode[] _writeCacheNodes;
-		private IdWriteCacheNode _nextAvailableWriteCacheNode;
-		private readonly object _writeCacheNodeLock = new object();
-		private readonly Thread _remoteAssetStoreTask;
-
-		/// <summary>
-		/// Stores IDs that are failures.  No need to disk backup, it's OK to lose this info in a restart.
-		/// </summary>
-		private readonly System.Runtime.Caching.ObjectCache _negativeCache;
-		private readonly System.Runtime.Caching.CacheItemPolicy _negativeCachePolicy;
-		private readonly ReaderWriterLockSlim _negativeCacheLock;
-
-		public CacheManager(
-			string pathToDatabaseFolder,
-			ulong maxAssetCacheDiskSpaceByteCount,
-			string pathToWriteCacheFile,
-			uint maxWriteCacheRecordCount,
-			TimeSpan negativeCacheItemLifetime
-		) {
-			if (string.IsNullOrWhiteSpace(pathToDatabaseFolder)) {
-				throw new ArgumentNullException(nameof(pathToDatabaseFolder), "No database path means no go.");
-			}
-			if (maxAssetCacheDiskSpaceByteCount < uint.MaxValue) {
-				throw new ArgumentOutOfRangeException(nameof(maxAssetCacheDiskSpaceByteCount), $"Asset cache disk space should be able to fit at least one maximum-sized asset, and thus should be at least {uint.MaxValue} bytes.");
-			}
-			try {
-				_dbenv = new LightningEnvironment(pathToDatabaseFolder) {
-					MapSize = (long)maxAssetCacheDiskSpaceByteCount,
-					MaxDatabases = 1,
-				};
-
-				_dbenv.Open(EnvironmentOpenFlags.None, UnixAccessMode.OwnerRead | UnixAccessMode.OwnerWrite);
-			}
-			catch (LightningException e) {
-				throw new ArgumentException($"Given path invalid: '{pathToDatabaseFolder}'", nameof(pathToDatabaseFolder), e);
-			}
-
-			_activeIds = new OrderedGuidCache();
-
-			_assetReader = null;
-			_assetWriter = null;
-
-			_pathToWriteCacheFile = pathToWriteCacheFile;
-			_assetsToWriteToRemoteStorage = new BlockingCollection<IdWriteCacheNode>();
-
-			if (negativeCacheItemLifetime.TotalSeconds > 0) {
-				_negativeCache = System.Runtime.Caching.MemoryCache.Default;
-				_negativeCacheLock = new ReaderWriterLockSlim();
-
-				_negativeCachePolicy = new System.Runtime.Caching.CacheItemPolicy {
-					SlidingExpiration = negativeCacheItemLifetime,
-				};
-			}
-
-			LOG.Info($"Restoring index from DB.");
-			try {
-				using (var tx = _dbenv.BeginTransaction(TransactionBeginFlags.None))
-				using (var db = tx.OpenDatabase("assetstore", new DatabaseConfiguration { Flags = DatabaseOpenFlags.Create })) {
-					// Probably not the most effecient way to do this.
-					var assetData = tx.CreateCursor(db)
-						.Select(kvp => {
-							var str = Encoding.UTF8.GetString(kvp.Key);
-							Guid assetId;
-							return Guid.TryParse(str, out assetId) ? new Tuple<Guid, uint>(assetId, (uint)kvp.Value.Length) : null;
-						})
-						.Where(assetId => assetId != null)
-					;
-
-					foreach (var assetDatum in assetData) {
-						_activeIds.TryAdd(assetDatum.Item1, assetDatum.Item2);
-					}
-				}
-			}
-			catch (Exception e) {
-				throw new CacheException($"Attempting to restore index from db threw an exception!", e);
-			}
-			LOG.Debug($"Restoring index complete.");
-
-			// If the file doesn't exist, create it and zero the needed records.
-			if (!File.Exists(pathToWriteCacheFile)) {
-				LOG.Info($"Write cache file doesn't exist, creating and formatting file '{pathToWriteCacheFile}'");
-				using (var fileStream = new FileStream(pathToWriteCacheFile, FileMode.Create, FileAccess.Write, FileShare.None)) {
-					var maxLength = WRITE_CACHE_MAGIC_NUMBER.Length + ((long)maxWriteCacheRecordCount * IdWriteCacheNode.BYTE_SIZE);
-					fileStream.SetLength(maxLength);
-					// On some FSs the file is all 0s at this point, but it behooves us to make sure of the critical points.
-
-					// Write the header
-					fileStream.Seek(0, SeekOrigin.Begin);
-					fileStream.Write(WRITE_CACHE_MAGIC_NUMBER, 0, WRITE_CACHE_MAGIC_NUMBER.Length);
-
-					// Make sure to flag all record as available, just in case the FS didn't give us a clean slate.
-					for (var offset = (long)WRITE_CACHE_MAGIC_NUMBER.Length; offset < maxLength; offset += IdWriteCacheNode.BYTE_SIZE) {
-						fileStream.Seek(offset, SeekOrigin.Begin);
-						fileStream.WriteByte(0); // First byte is always the status: 0 means it's an open slot.
-					}
-				}
-				LOG.Debug($"Write cache formatting complete.");
-			}
-
-			var writeCacheFileRecordCount = (uint)((new FileInfo(pathToWriteCacheFile).Length - WRITE_CACHE_MAGIC_NUMBER.Length) / IdWriteCacheNode.BYTE_SIZE);
-
-			if (writeCacheFileRecordCount < maxWriteCacheRecordCount) {
-				// Expand the file.
-				var bytesNeeded = (int)((maxWriteCacheRecordCount - writeCacheFileRecordCount) * IdWriteCacheNode.BYTE_SIZE);
-				LOG.Info($"Write cache file expanding by {bytesNeeded} bytes to accomodate requested change in record count.");
-				using (var stream = new FileStream(pathToWriteCacheFile, FileMode.Append)) {
-					stream.Write(new byte[bytesNeeded], 0, bytesNeeded); // In C# a new array is already init'd to 0s.
-				}
-			}
-			else if (writeCacheFileRecordCount > maxWriteCacheRecordCount) {
-				// For now, use the file size.
-				LOG.Warn($"Write cache not able to be shrunk in this version of WHIP_LRU, continuing with old value of {writeCacheFileRecordCount} records instead of requested {maxWriteCacheRecordCount} records.");
-				maxWriteCacheRecordCount = writeCacheFileRecordCount;
-				// TODO: find a way to shrink the file without losing ANY of the records that have not yet been submitted to an upstream server.
-				// Could get difficult in the case of a full file...
-			}
-
-			LOG.Info($"Reading write cache from file '{pathToWriteCacheFile}'. Expecting {maxWriteCacheRecordCount} records, found {writeCacheFileRecordCount} records, choosing the larger.");
-			using (var mmf = MemoryMappedFile.CreateFromFile(pathToWriteCacheFile, FileMode.Open, "whiplruwritecache")) {
-				using (var stream = mmf.CreateViewStream()) {
-					var offset = 0UL;
-					{
-						var magic_number = new byte[WRITE_CACHE_MAGIC_NUMBER.Length];
-						stream.Read(magic_number, 0, WRITE_CACHE_MAGIC_NUMBER.Length);
-						if (!magic_number.SequenceEqual(WRITE_CACHE_MAGIC_NUMBER)) {
-							throw new ArgumentException($"Magic number mismatch when given path: ", nameof(pathToWriteCacheFile));
-						}
-						offset += (ulong)WRITE_CACHE_MAGIC_NUMBER.Length;
-					}
-
-					var nodes = new List<IdWriteCacheNode>((int)maxWriteCacheRecordCount);
-
-					var buffer = new byte[IdWriteCacheNode.BYTE_SIZE];
-
-					while (nodes.Count < maxWriteCacheRecordCount) {
-						stream.Read(buffer, 0, (int)IdWriteCacheNode.BYTE_SIZE);
-						var node = new IdWriteCacheNode(buffer, offset);
-						nodes.Add(node);
-						offset += IdWriteCacheNode.BYTE_SIZE;
-
-						// If the node isn't available that means it's an ID that still needs to be written to long-term storage.
-						if (!node.IsAvailable) {
-							_assetsToWriteToRemoteStorage.Add(node);
-						}
-					}
-
-					_writeCacheNodes = nodes.ToArray();
-				}
-			}
-			LOG.Debug($"Reading write cache complete.");
-
-			// Set up the task for storing the assets to the remote server.
-			if (_assetWriter != null && _assetWriter.HasUpstream) {
-				_remoteAssetStoreTask = new Thread(() => {
-					var crashExceptions = new List<Exception>();
-					var safeExit = false;
-
-					while (crashExceptions.Count < 10) {
-						try {
-							var token = _cancellationTokenSource.Token;
-							foreach (var assetCacheNode in _assetsToWriteToRemoteStorage.GetConsumingEnumerable()) {
-								if (token.IsCancellationRequested) break;
-								LOG.Debug($"Attempting to remotely store {assetCacheNode.AssetId}.");
-
-								var asset = ReadAssetFromDisk(assetCacheNode.AssetId);
-
-								try {
-									_assetWriter.PutAssetSync(asset);
-								}
-								catch (AssetExistsException) {
-									// Ignore these.
-									LOG.Info($"Remote server reports that the asset with ID {assetCacheNode.AssetId} already exists.");
-								}
-
-								// Clear the byte on disk before clearing in memory.
-								using (var mmf = MemoryMappedFile.CreateFromFile(pathToWriteCacheFile, FileMode.Open, "whiplruwritecache"))
-								using (var accessor = mmf.CreateViewAccessor((long)assetCacheNode.FileOffset, IdWriteCacheNode.BYTE_SIZE)) {
-									accessor.Write(0, (byte)0);
-								}
-								assetCacheNode.IsAvailable = true;
-
-								crashExceptions.Clear(); // Success means ignore the past.
-							}
-							if (token.IsCancellationRequested) {
-								safeExit = true;
-								break;
-							}
-						}
-						catch (Exception e) {
-							if (e is OperationCanceledException) {
-								safeExit = true;
-								break;
-							}
-
-							LOG.Warn($"Unhandled exception in localAssetStoreTask thread. Thread restarting.", e);
-							crashExceptions.Add(e);
-						}
-					}
-
-					if (!safeExit && crashExceptions.Count > 0) {
-						LOG.Error("Multiple crashes in localAssetStoreTask thread.", new AggregateException("Multiple crashes in localAssetStoreTask thread.", crashExceptions));
-					}
-				});
-
-				_remoteAssetStoreTask.Start();
-			}
-		}
-
-		/// <summary>
-		/// Attempts to put the asset into the local disk storage and the remote storage system.
-		///
-		/// Does not ever throw on a valid storage attempt. Any exceptions thrown are bugs to be fixed as they mean data loss.
-		/// The exceptions are if the asset cannot be serialized for some inane reason or if you passed an asset with a zero ID.  Either of those cases are considered invalid storage attempts.
-		/// </summary>
-		/// <param name="asset">The asset to store.</param>
-		public PutResult PutAsset(StratusAsset asset) {
-			Contract.Requires(asset != null);
-
-			if (asset == null) {
-				throw new ArgumentNullException(nameof(asset));
-			}
-
-			if (asset.Id == Guid.Empty) {
-				throw new ArgumentException("Asset cannot have zero ID.", nameof(asset));
-			}
-
-			// Why must this method never throw on a valid asset store attempt? It HAS TO WORK: if an asset fails all forms and attempts to store it and send it upstream it will be lost forever. That makes customers VERY cranky.
-
-			if (!_activeIds.Contains(asset.Id)) { // The asset ID didn't exist in the cache, so let's add it to the local and remote storage.
-				// First step: get it in the local disk cache.
-				var lightningException = WriteAssetToDisk(asset);
-
-				if (_negativeCache != null) {
-					_negativeCacheLock.EnterWriteLock();
-					try {
-						_negativeCache.Remove(asset.Id.ToString("N"));
-					}
-					finally {
-						_negativeCacheLock.ExitWriteLock();
-					}
-				}
-
-				// If it's safely in local get it on the upload path to remote.
-				if (lightningException == null) {
-					if (_assetWriter != null && _assetWriter.HasUpstream) { // If there's no asset writer to send to then there's no point in trying to store against a write failure.
-						var writeCacheNode = GetNextAvailableWriteCacheNode();
-
-						writeCacheNode.AssetId = asset.Id;
-
-						// Queue up for remote storage.
-						_assetsToWriteToRemoteStorage.Add(writeCacheNode);
-
-						// Write to writecache file. In this way if we crash after this point we can recover.
-						try {
-							using (var mmf = MemoryMappedFile.CreateFromFile(_pathToWriteCacheFile, FileMode.Open, "whiplruwritecache"))
-							using (var accessor = mmf.CreateViewAccessor((long)writeCacheNode.FileOffset, IdWriteCacheNode.BYTE_SIZE)) {
-								var nodeBytes = writeCacheNode.ToByteArray();
-
-								accessor.WriteArray(0, nodeBytes, 0, (int)IdWriteCacheNode.BYTE_SIZE);
-							}
-						}
-						catch (Exception e) {
-							LOG.Warn($"{asset.Id} failed to write to disk-based write cache!", e);
-							// As long as the queue thread processes the asset this should be OK.
-							return PutResult.WIP;
-						}
-					}
-				}
-				else {
-					// Only known cause of an exception not causing an immediate retry is the case of already exists. And that already logs the details.
-					return PutResult.DUPLICATE;
-				}
-			}
-			else {
-				LOG.Info($"{asset.Id} was rejected from storage as a duplicate.");
-				return PutResult.DUPLICATE;
-			}
-
-			return PutResult.DONE;
-		}
-
-		/// <summary>
-		/// Retrieves the asset. Tries the local cache first, then moves on to the remote storage systems.
-		/// If neither could find the data, or if there is no remote storage set up, null is returned.
-		///
-		/// Can throw, but only if there were problems with the remote storage calls or you passed a zero ID.
-		/// </summary>
-		/// <returns>The asset.</returns>
-		/// <param name="assetId">Asset identifier.</param>
-		/// <param name="cacheResult">Specifies to locally store the asset if it was fetched from a remote.</param>
-		public StratusAsset GetAsset(Guid assetId, bool cacheResult = true) {
-			if (assetId == Guid.Empty) {
-				throw new ArgumentException("Asset ID cannot be zero.", nameof(assetId));
-			}
-
-			if (_negativeCache != null) {
-				_negativeCacheLock.EnterReadLock();
-				try {
-					if (_negativeCache.Contains(assetId.ToString("N"))) {
-						return null;
-					}
-				}
-				finally {
-					_negativeCacheLock.ExitReadLock();
-				}
-			}
-
-			var assetSize = _activeIds?.AssetSize(assetId);
-
-			if (assetSize != null) { // Asset exists, just might not be on disk yet.
-				if (assetSize <= 0) {
-					// Wait here until the asset makes it to disk.
-					SpinWait.SpinUntil(() => _activeIds?.AssetSize(assetId) > 0);
-				}
-
-				try {
-					return ReadAssetFromDisk(assetId);
-				}
-				catch (CacheException e) {
-					LOG.Debug("Error in the cache system, see inner exception.", e);
-					// Cache miss. Bummer.
-				}
-			}
-
-			if (_assetReader != null && _assetReader.HasUpstream) {
-				var asset = _assetReader.GetAssetSync(assetId);
-
-				if (cacheResult) {
-					WriteAssetToDisk(asset); // Don't care if this reports a problem.
-				}
-
-				return asset;
-			}
-
-			if (_negativeCache != null) {
-				_negativeCacheLock.EnterWriteLock();
-				try {
-					_negativeCache.Set(new System.Runtime.Caching.CacheItem(assetId.ToString("N"), 0), _negativeCachePolicy);
-				}
-				finally {
-					_negativeCacheLock.ExitWriteLock();
-				}
-			}
-
-			return null;
-		}
-
-		/// <summary>
-		/// Attempts to verify if the asset is known or not. Tries the local cache first, then moves on to the remote storage systems.
-		///
-		/// Can throw, but only if there were problems with the remote calls or you passed a zero ID.
-		/// </summary>
-		/// <returns>Whether the asset was found or not.</returns>
-		/// <param name="assetId">Asset identifier.</param>
-		public bool CheckAsset(Guid assetId) {
-			if (assetId == Guid.Empty) {
-				throw new ArgumentException("Asset ID cannot be zero.", nameof(assetId));
-			}
-
-			if (_negativeCache != null) {
-				_negativeCacheLock.EnterReadLock();
-				try {
-					if (_negativeCache.Contains(assetId.ToString("N"))) {
-						return false;
-					}
-				}
-				finally {
-					_negativeCacheLock.ExitReadLock();
-				}
-			}
-
-			if (_activeIds?.Contains(assetId) ?? false) {
-				return true;
-			}
-
-			if (_assetReader != null && _assetReader.HasUpstream) {
-				var asset = _assetReader.GetAssetSync(assetId);
-
-				WriteAssetToDisk(asset); // Don't care if this reports a problem.
-
-				if (asset != null) {
-					return true;
-				}
-			}
-
-			if (_negativeCache != null) {
-				_negativeCacheLock.EnterWriteLock();
-				try {
-					_negativeCache.Set(new System.Runtime.Caching.CacheItem(assetId.ToString("N"), 0), _negativeCachePolicy);
-				}
-				finally {
-					_negativeCacheLock.ExitWriteLock();
-				}
-			}
-
-			return false;
-		}
-
-		internal void SetChattelReader(ChattelReader reader) {
-			if (_assetWriter != null) {
-				throw new CacheException("Cannot change asset reader once initialized.");
-			}
-			_assetReader = reader;
-		}
-
-		internal void SetChattelWriter(ChattelWriter writer) {
-			if (_assetWriter != null) {
-				throw new CacheException("Cannot change asset writer once initialized.");
-			}
-			_assetWriter = writer;
-		}
-
-		#region Disk IO tools
-
-		private LightningException WriteAssetToDisk(StratusAsset asset) {
-			// Remember it's important that this method does not throw exceptions.
-			if (asset == null) {
-				return null;
-			}
-
-			LightningException lightningException;
-
-			ulong spaceNeeded;
-
-			_activeIds.TryAdd(asset.Id, 0); // Register the asset as existing, but not yet on disk; size of 0. Failure simply indicates that the asset ID already exists.
-
-			using (var memStream = new MemoryStream()) {
-				ProtoBuf.Serializer.Serialize(memStream, asset); // This can throw, but only if something is VERY and irrecoverably wrong.
-				spaceNeeded = (ulong)memStream.Length;
-				memStream.Position = 0;
-
-				var buffer = new byte[spaceNeeded];
-
-				Buffer.BlockCopy(memStream.GetBuffer(), 0, buffer, 0, (int)spaceNeeded);
-				retryStorageLabel:
-				try {
-					using (var tx = _dbenv.BeginTransaction())
-					using (var db = tx.OpenDatabase("assetstore", new DatabaseConfiguration { Flags = DatabaseOpenFlags.Create })) {
-						tx.Put(db, Encoding.UTF8.GetBytes(asset.Id.ToString("N")), buffer);
-						tx.Commit();
-					}
-
-					_activeIds.AssetSize(asset.Id, spaceNeeded); // Set the size now that it's on disk.
-
-					return null;
-				}
-				catch (LightningException e) {
-					lightningException = e;
-				}
-
-				switch (lightningException.StatusCode) {
-					case -30799:
-						//LightningDB.Native.Lmdb.MDB_KEYEXIST: Not available in lib ATM...
-						// Ignorable.
-						LOG.Warn($"{asset.Id} already exists according to local storage. Adding to memory list - please report this as it should not be able to happen.", lightningException);
-						lightningException = null;
-
-						_activeIds.AssetSize(asset.Id, spaceNeeded); // Set the size now that it's on disk.
-
-						break;
-					case LightningDB.Native.Lmdb.MDB_DBS_FULL:
-					case LightningDB.Native.Lmdb.MDB_MAP_FULL:
-						var lockTaken = Monitor.TryEnter(_dbenv_lock);
-						try {
-							if (lockTaken) {
-								LOG.Warn($"{asset.Id} got storage space full during local storage, clearing some room...", lightningException);
-
-								ulong bytesRemoved;
-								var removedAssetIds = _activeIds.Remove(spaceNeeded * 2, out bytesRemoved);
-
-								try {
-									using (var tx = _dbenv.BeginTransaction())
-									using (var db = tx.OpenDatabase("assetstore")) {
-										foreach (var assetId in removedAssetIds) {
-											tx.Delete(db, Encoding.UTF8.GetBytes(assetId.ToString("N")));
-										}
-										tx.Commit();
-									}
-								}
-								catch (LightningException e) {
-									LOG.Warn($"{asset.Id} had an exception while attempting to clear some space in the local asset store.", e);
-								}
-							}
-							// else skip as another thread is already clearing some space.
-						}
-						finally {
-							if (lockTaken) Monitor.Exit(_dbenv_lock);
-						}
-
-						// Retry the asset storage now that we've got some space.
-						goto retryStorageLabel;
-					default:
-						LOG.Warn($"{asset.Id} got an unexpected exception during local storage.", lightningException);
-
-						Thread.Sleep(200); // Give it some time. The time is a hipshot, not some magic numebr.
-						goto retryStorageLabel;
-				}
-			}
-
-			return lightningException;
-		}
-
-		private StratusAsset ReadAssetFromDisk(Guid assetId) {
-			try {
-				using (var tx = _dbenv.BeginTransaction(TransactionBeginFlags.ReadOnly))
-				using (var db = tx.OpenDatabase("assetstore")) {
-					byte[] buffer;
-					if (tx.TryGet(db, Encoding.UTF8.GetBytes(assetId.ToString("N")), out buffer)) {
-						using (var stream = new MemoryStream(buffer)) {
-							return ProtoBuf.Serializer.Deserialize<StratusAsset>(stream);
-						}
-					}
-
-					throw new CacheException($"Asset with ID {assetId} not found in local storage!");
-				}
-			}
-			catch (LightningException e) {
-				throw new CacheException($"Attempting to read locally stored asset with ID {assetId} threw an exception!", e);
-			}
-			catch (ProtoBuf.ProtoException e) {
-				throw new CacheException($"Attempting to deserialize locally stored asset with ID {assetId} threw an exception!", e);
-			}
-		}
-
-		private IdWriteCacheNode GetNextAvailableWriteCacheNode() {
-			IdWriteCacheNode writeCacheNode;
-
-			lock (_writeCacheNodeLock) {
-				// If we've not bootstrapped, do so.
-				while (_nextAvailableWriteCacheNode == null) {
-					try {
-						_nextAvailableWriteCacheNode = _writeCacheNodes.First(node => node.IsAvailable);
-					}
-					catch (InvalidOperationException) {
-						// No available nodes found, which means we are out of ability to safely continue until one becomes available...
-						_nextAvailableWriteCacheNode = null;
-						Thread.Sleep(100);
-					}
-				}
-
-				writeCacheNode = _nextAvailableWriteCacheNode;
-				writeCacheNode.IsAvailable = false;
-				_nextAvailableWriteCacheNode = null;
-
-				// Find the next one.
-				while (_nextAvailableWriteCacheNode == null) {
-					try {
-						_nextAvailableWriteCacheNode = _writeCacheNodes.First(node => node.IsAvailable);
-					}
-					catch (InvalidOperationException) {
-						// No available nodes found, which means we are out of ability to safely continue until one becomes available...
-						_nextAvailableWriteCacheNode = null;
-						Thread.Sleep(100);
-					}
-				}
-			}
-
-			return writeCacheNode;
-		}
-
-		#endregion
-
-		public enum PutResult {
-			DONE,
-			DUPLICATE,
-			WIP,
-		}
-
-		#region IDisposable Support
-
-		private bool disposedValue; // To detect redundant calls
-
-		protected virtual void Dispose(bool disposing) {
-			if (!disposedValue) {
-				if (disposing) {
-					// dispose managed state (managed objects).
-					_assetsToWriteToRemoteStorage.CompleteAdding();
-					_cancellationTokenSource.Cancel();
-					_cancellationTokenSource.Dispose();
-
-					Thread.Sleep(500);
-					_dbenv.Dispose();
-					_dbenv = null;
-				}
-
-				// Free unmanaged resources (unmanaged objects) and override a finalizer below.
-				// None at this time.
-
-				// Set large fields to null.
-				_cancellationTokenSource = null;
-				_writeCacheNodes = null;
-
-				disposedValue = true;
-			}
-		}
-
-		// Override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources.
-		// ~CacheManager() {
-		//   // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
-		//   Dispose(false);
-		// }
-
-		// This code added to correctly implement the disposable pattern.
-		public void Dispose() {
-			// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
-			Dispose(true);
-			// Uncomment the following line if the finalizer is overridden above.
-			// GC.SuppressFinalize(this);
-		}
-
-		#endregion
-	}
-}