text:
namespace SimpleInjector.Extensions.ExecutionContextScoping.Tests.Unit
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Linq;
    using System.Linq.Expressions;
    using System.Reflection;
    using System.Threading.Tasks;
    using Microsoft.VisualStudio.TestTools.UnitTesting;

    using SimpleInjector.Advanced;
    using SimpleInjector.Lifestyles;
    using SimpleInjector.Tests.Unit;

    [TestClass]
    public class AsyncScopedLifestyleTests
    {
        [TestMethod]
        public void Async_AsyncScopedLifestyle_Nesting()
        {
            var container = new Container();

            container.Register<DisposableCommand>(new AsyncScopedLifestyle());

            DisposableCommand cmd;
            using (AsyncScopedLifestyle.BeginScope(container))
            {
                // Act
                cmd = container.GetInstance<DisposableCommand>();
                Outer(container, cmd).Wait();

                Assert.IsFalse(cmd.HasBeenDisposed);
            }

            Assert.IsTrue(cmd.HasBeenDisposed);
        }

        [TestMethod]
        public void GetInstance_RegistrationUsingAsyncScopedLifestyle_Succeeds()
        {
            // Arrange
            var container = new Container();

            container.Register<ICommand, ConcreteCommand>(new AsyncScopedLifestyle());

            using (AsyncScopedLifestyle.BeginScope(container))
            {
                // Act
                container.GetInstance<ICommand>();
            }
        }

        [TestMethod]
        public void GetInstance_RegistrationUsingFuncAsyncScopedLifestyle_Succeeds()
        {
            // Arrange
            var container = new Container();

            container.Register<ICommand>(() => new ConcreteCommand(), new AsyncScopedLifestyle());

            using (AsyncScopedLifestyle.BeginScope(container))
            {
                // Act
                container.GetInstance<ICommand>();
            }
        }

        [TestMethod]
        public void BeginScope_WithoutAnyAsyncScopedLifestyleRegistrations_Succeeds()
        {
            // Arrange
            var container = new Container();

            container.Register<ConcreteCommand>();

            // Act
            using (var scope = AsyncScopedLifestyle.BeginScope(container))
            {
                container.GetInstance<ConcreteCommand>();
            }
        }

        [TestMethod]
        public void BeginScope_WithoutAnyAsyncScopedLifestyleRegistrations_Succeeds2()
        {
            // Arrange
            var container = new Container();

            // Act
            using (AsyncScopedLifestyle.BeginScope(container))
            {
            }
        }

        [TestMethod]
        public void ContainerVerify_WithAsyncScopedLifestyleRegistrationInOpenGeneric_Succeeds()
        {
            // Arrange
            var container = new Container();

            container.Register(typeof(IGeneric<>), typeof(Generic<>), new AsyncScopedLifestyle());

            container.Register<ClassDependingOn<IGeneric<int>>>();

            // Act
            container.Verify();
        }

        [TestMethod]
        public void ContainerVerify_WithHybridAsyncScopedLifestyleRegistrationInOpenGeneric_Succeeds()
        {
            // Arrange
            var container = new Container();

            var hybrid = Lifestyle.CreateHybrid(() => false, new AsyncScopedLifestyle(), new AsyncScopedLifestyle());

            container.Register(typeof(IGeneric<>), typeof(Generic<>), hybrid);

            container.Register<ClassDependingOn<IGeneric<int>>>();

            // Act
            container.Verify();
        }

        [TestMethod]
        public void GetCurrentAsyncScopedLifestyle_InsideANestedAsyncScopedLifestyle_ReturnsTheInnerMostScope()
        {
            // Arrange
            var container = new Container();
            container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();

            using (Scope outerScope = AsyncScopedLifestyle.BeginScope(container))
            {
                using (Scope innerScope = AsyncScopedLifestyle.BeginScope(container))
                {
                    Assert.IsFalse(object.ReferenceEquals(outerScope, innerScope), "Test setup failed.");

                    // Act
                    Scope currentScope = Lifestyle.Scoped.GetCurrentScope(container);

                    // Assert
                    Assert.IsTrue(object.ReferenceEquals(innerScope, currentScope));
                }
            }
        }

        [TestMethod]
        public void GetInstance_WithoutAsyncScopedLifestyle_ThrowsExpectedException()
        {
            // Arrange
            var container = new Container();

            container.Register<ICommand, ConcreteCommand>(new AsyncScopedLifestyle());

            try
            {
                // Act
                container.GetInstance<ICommand>();

                // Assert
                Assert.Fail("Exception expected.");
            }
            catch (ActivationException ex)
            {
                AssertThat.ExceptionMessageContains(@"
                    ConcreteCommand is registered using the 'Async Scoped' lifestyle, but the instance is
                    requested outside the context of an active (Async Scoped) scope."
                    .TrimInside(),
                    ex);
            }
        }

        [TestMethod]
        public void ContainerVerify_WithoutAsyncScopedLifestyle_Succeeds()
        {
            // Arrange
            var container = new Container();

            container.Register<ICommand, ConcreteCommand>(new AsyncScopedLifestyle());

            // Act
            container.Verify();
        }

        [TestMethod]
        public void GetInstance_WithinAsyncScopedLifestyle_ReturnsInstanceOfExpectedType()
        {
            // Arrange
            var container = new Container();

            container.Register<ICommand, ConcreteCommand>(new AsyncScopedLifestyle());

            using (AsyncScopedLifestyle.BeginScope(container))
            {
                // Act
                var actualInstance = container.GetInstance<ICommand>();

                // Assert
                AssertThat.IsInstanceOfType(typeof(ConcreteCommand), actualInstance);
            }
        }

        [TestMethod]
        public void GetInstance_CalledMultipleTimesWithinSingleAsyncScopedLifestyle_ReturnsASingleInstance()
        {
            // Arrange
            var container = new Container();

            container.Register<ICommand, ConcreteCommand>(new AsyncScopedLifestyle());

            using (AsyncScopedLifestyle.BeginScope(container))
            {
                // Act
                var firstInstance = container.GetInstance<ICommand>();
                var secondInstance = container.GetInstance<ICommand>();

                // Assert
                Assert.IsTrue(object.ReferenceEquals(firstInstance, secondInstance));
            }
        }

        [TestMethod]
        public void GetInstance_CalledWithinNestedSingleAsyncScopedLifestyles_ReturnsAnInstancePerScope()
        {
            // Arrange
            var container = new Container();

            container.Register<ICommand, ConcreteCommand>(new AsyncScopedLifestyle());

            using (AsyncScopedLifestyle.BeginScope(container))
            {
                // Act
                var firstInstance = container.GetInstance<ICommand>();

                using (AsyncScopedLifestyle.BeginScope(container))
                {
                    var secondInstance = container.GetInstance<ICommand>();

                    // Assert
                    Assert.IsFalse(object.ReferenceEquals(firstInstance, secondInstance));
                }
            }
        }

        [TestMethod]
        public void GetInstance_CalledWithinSameAsyncScopedLifestyleWithOtherScopesInBetween_ReturnsASingleInstance()
        {
            // Arrange
            var container = new Container();

            container.Register<ICommand, ConcreteCommand>(new AsyncScopedLifestyle());

            using (AsyncScopedLifestyle.BeginScope(container))
            {
                // Act
                var firstInstance = container.GetInstance<ICommand>();

                using (AsyncScopedLifestyle.BeginScope(container))
                {
                    container.GetInstance<ICommand>();
                }

                var secondInstance = container.GetInstance<ICommand>();

                // Assert
                Assert.IsTrue(object.ReferenceEquals(firstInstance, secondInstance));
            }
        }

        [TestMethod]
        public void AsyncScopedLifestyleDispose_RegisterAsyncScopedLifestyleWithDisposal_EnsuresInstanceGetDisposedAfterAsyncScopedLifestyleEnds()
        {
            // Arrange
            var container = new Container();

            container.Register<DisposableCommand>(new AsyncScopedLifestyle());

            DisposableCommand command;

            // Act
            using (AsyncScopedLifestyle.BeginScope(container))
            {
                command = container.GetInstance<DisposableCommand>();
            }

            // Assert
            Assert.IsTrue(command.HasBeenDisposed, "The instance was expected to be disposed.");
        }

        [TestMethod]
        public void AsyncScopedLifestyleDispose_TransientDisposableObject_DoesNotDisposeInstanceAfterAsyncScopedLifestyleEnds()
        {
            // Arrange
            var container = ContainerFactory.New();

            // Transient
            container.Register<DisposableCommand>();

            DisposableCommand command;

            // Act
            using (AsyncScopedLifestyle.BeginScope(container))
            {
                command = container.GetInstance<DisposableCommand>();
            }

            // Assert
            Assert.IsFalse(command.HasBeenDisposed,
                "The execution scope should not dispose objects that are not explicitly marked as such, since " +
                "this would allow the scope to accidentally dispose singletons.");
        }

        [TestMethod]
        public void AsyncScopedLifestyleDispose_WithInstanceExplicitlyRegisteredForDisposal_DisposesThatInstance()
        {
            // Arrange
            var container = ContainerFactory.New();

            var scopedLifestyle = new AsyncScopedLifestyle();

            // Transient
            container.Register<DisposableCommand>();

            container.RegisterInitializer<DisposableCommand>(instance =>
            {
                Scope scope = scopedLifestyle.GetCurrentScope(container);

                // The following line explicitly registers the transient DisposableCommand for disposal when
                // the execution context scope ends.
                scope.RegisterForDisposal(instance);
            });

            DisposableCommand command;

            // Act
            using (AsyncScopedLifestyle.BeginScope(container))
            {
                command = container.GetInstance<DisposableCommand>();
            }

            // Assert
            Assert.IsTrue(command.HasBeenDisposed,
                "The transient instance was expected to be disposed, because it was registered for disposal.");
        }

        [TestMethod]
        public void RegisterIDisposableForDisposal_WithNullArgument_ThrowsExpectedException()
        {
            // Arrange
            IDisposable invalidArgument = null;

            var container = new Container();

            // Act
            using (var scope = AsyncScopedLifestyle.BeginScope(container))
            {
                try
                {
                    scope.RegisterForDisposal(invalidArgument);

                    Assert.Fail("Exception expected.");
                }
                catch (ArgumentNullException)
                {
                    // This exception is expected.
                }
            }
        }

        [TestMethod]
        public void RegisterIAsyncDisposableForDisposal_WithNullArgument_ThrowsExpectedException()
        {
            // Arrange
            IAsyncDisposable invalidArgument = null;

            var container = new Container();

            // Act
            using (var scope = AsyncScopedLifestyle.BeginScope(container))
            {
                try
                {
                    scope.RegisterForDisposal(invalidArgument);

                    Assert.Fail("Exception expected.");
                }
                catch (ArgumentNullException)
                {
                    // This exception is expected.
                }
            }
        }

        [TestMethod]
        public void AsyncScopedLifestyleDispose_OnAsyncScopedLifestyledObject_EnsuresInstanceGetDisposedAfterAsyncScopedLifestyle()
        {
            // Arrange
            var container = new Container();

            container.Register<ICommand, DisposableCommand>(new AsyncScopedLifestyle());

            DisposableCommand command;

            // Act
            using (AsyncScopedLifestyle.BeginScope(container))
            {
                command = container.GetInstance<ICommand>() as DisposableCommand;
            }

            // Assert
            Assert.IsTrue(command.HasBeenDisposed, "The execution scoped instance was expected to be disposed.");
        }

        [TestMethod]
        public void GetInstance_OnAsyncScopedLifestyledObject_WillNotBeDisposedDuringAsyncScopedLifestyle()
        {
            // Arrange
            var container = new Container();

            container.Register<DisposableCommand>(new AsyncScopedLifestyle());

            // Act
            using (AsyncScopedLifestyle.BeginScope(container))
            {
                var command = container.GetInstance<DisposableCommand>();

                // Assert
                Assert.IsFalse(command.HasBeenDisposed, "The instance should not be disposed inside the scope.");
            }
        }

        [TestMethod]
        public void GetInstance_WithinAAsyncScopedLifestyle_NeverDisposesASingleton()
        {
            // Arrange
            var container = new Container();
            container.Options.EnableAutoVerification = false;

            container.Register<DisposableCommand>(Lifestyle.Singleton);

            container.Register<ICommand, DisposableCommand>(new AsyncScopedLifestyle());

            DisposableCommand singleton;

            // Act
            using (AsyncScopedLifestyle.BeginScope(container))
            {
                singleton = container.GetInstance<DisposableCommand>();
            }

            // Assert
            Assert.IsFalse(singleton.HasBeenDisposed, "Singletons should not be disposed.");
        }

        [TestMethod]
        public void AsyncScopedLifestyleDispose_RegisteredConcereteWithExplicitDisposal_DisposesThatInstance()
        {
            // Arrange
            var container = new Container();

            container.Register<DisposableCommand>(new AsyncScopedLifestyle());

            DisposableCommand instanceToDispose;

            // Act
            using (AsyncScopedLifestyle.BeginScope(container))
            {
                instanceToDispose = container.GetInstance<DisposableCommand>();
            }

            // Assert
            Assert.IsTrue(instanceToDispose.HasBeenDisposed);
        }

        [TestMethod]
        public void AsyncScopedLifestyleDispose_RegisteredWithExplicitDisposal_DisposesThatInstance()
        {
            // Arrange
            var container = new Container();

            container.Register<IDisposable, DisposableCommand>(new AsyncScopedLifestyle());

            DisposableCommand instanceToDispose;

            // Act
            using (AsyncScopedLifestyle.BeginScope(container))
            {
                instanceToDispose = container.GetInstance<IDisposable>() as DisposableCommand;
            }

            // Assert
            Assert.IsTrue(instanceToDispose.HasBeenDisposed);
        }

        [TestMethod]
        public void GetInstance_CalledMultipleTimesOnAAsyncScopedLifestyleServiceWithinASingleScope_DisposesThatInstanceOnce()
        {
            // Arrange
            var container = new Container();

            container.Register<DisposableCommand>(new AsyncScopedLifestyle());

            DisposableCommand command;

            // Act
            using (AsyncScopedLifestyle.BeginScope(container))
            {
                command = container.GetInstance<DisposableCommand>();

                container.GetInstance<DisposableCommand>();
                container.GetInstance<DisposableCommand>();
            }

            // Assert
            Assert.AreEqual(1, command.DisposeCount, "Dispose should be called exactly once.");
        }

        [TestMethod]
        public void GetInstance_ResolveMultipleAsyncScopedLifestyledServicesWithStrangeEqualsImplementations_CorrectlyDisposesAllInstances()
        {
            // Arrange
            var container = new Container();

            var lifestyle = new AsyncScopedLifestyle();

            container.Register<DisposableCommandWithOverriddenEquality1>(lifestyle);
            container.Register<DisposableCommandWithOverriddenEquality2>(lifestyle);

            // Act
            DisposableCommandWithOverriddenEquality1 command1;
            DisposableCommandWithOverriddenEquality2 command2;

            // Act
            using (AsyncScopedLifestyle.BeginScope(container))
            {
                command1 = container.GetInstance<DisposableCommandWithOverriddenEquality1>();
                command2 = container.GetInstance<DisposableCommandWithOverriddenEquality2>();

                // Give both instances the same hash code. Both have an equals implementation that compared
                // using the hash code, which make them look like they're the same instance.
                command1.HashCode = 1;
                command2.HashCode = 1;
            }

            // Assert
            string assertMessage =
                "Dispose is expected to be called on this command, even when it contains a GetHashCode and " +
                "Equals implementation that is totally screwed up, since storing disposable objects, " +
                "should be completely independent to this implementation. ";

            Assert.AreEqual(1, command1.DisposeCount, assertMessage + "command1");
            Assert.AreEqual(1, command2.DisposeCount, assertMessage + "command2");
        }

        [TestMethod]
        public void RegisterAsyncScopedLifestyle_CalledAfterInitialization_ThrowsExpectedException()
        {
            // Arrange
            var container = new Container();

            // This locks the container.
            container.GetInstance<Container>();

            try
            {
                // Act
                container.Register<ICommand, ConcreteCommand>(new AsyncScopedLifestyle());

                // Assert
                Assert.Fail("Exception expected.");
            }
            catch (InvalidOperationException ex)
            {
                Assert.IsTrue(ex.Message.Contains("The container can't be changed"),
                    "Actual: " + ex.Message);
            }
        }

        [TestMethod]
        public void BeginScope_WithNullArgument_ThrowsExpectedException()
        {
            // Act
            Action action = () => AsyncScopedLifestyle.BeginScope(null);

            // Assert
            AssertThat.Throws<ArgumentNullException>(action);
        }

        [TestMethod]
        public void GetInstance_AsyncScopedLifestyledInstanceWithInitializer_CallsInitializerOncePerAsyncScopedLifestyle()
        {
            // Arrange
            int initializerCallCount = 0;

            var container = ContainerFactory.New();

            container.Register<ICommand, ConcreteCommand>(new AsyncScopedLifestyle());

            container.RegisterInitializer<ICommand>(command => { initializerCallCount++; });

            using (AsyncScopedLifestyle.BeginScope(container))
            {
                // Act
                container.GetInstance<ICommand>();
                container.GetInstance<ICommand>();
            }

            // Assert
            Assert.AreEqual(1, initializerCallCount, "The initializer for ICommand is expected to get fired once.");
        }

        [TestMethod]
        public void GetInstance_AsyncScopedLifestyledFuncInstanceWithInitializer_CallsInitializerOncePerAsyncScopedLifestyle()
        {
            // Arrange
            int initializerCallCount = 0;

            var container = ContainerFactory.New();

            container.Register<ICommand>(() => new ConcreteCommand(), new AsyncScopedLifestyle());

            container.RegisterInitializer<ICommand>(command => { initializerCallCount++; });

            using (AsyncScopedLifestyle.BeginScope(container))
            {
                // Act
                container.GetInstance<ICommand>();
                container.GetInstance<ICommand>();
            }

            // Assert
            Assert.AreEqual(1, initializerCallCount, "The initializer for ICommand is expected to get fired once.");
        }

        [TestMethod]
        public void GetInstance_OnDecoratedAsyncScopedLifestyledInstance_WrapsTheInstanceWithTheDecorator()
        {
            // Arrange
            var container = new Container();

            container.Register<ICommand, ConcreteCommand>(new AsyncScopedLifestyle());

            container.RegisterDecorator(typeof(ICommand), typeof(CommandDecorator));

            using (AsyncScopedLifestyle.BeginScope(container))
            {
                // Act
                ICommand instance = container.GetInstance<ICommand>();

                // Assert
                AssertThat.IsInstanceOfType(typeof(CommandDecorator), instance);

                var decorator = (CommandDecorator)instance;

                AssertThat.IsInstanceOfType(typeof(ConcreteCommand), decorator.DecoratedInstance);
            }
        }

        [TestMethod]
        public void GetInstance_CalledTwiceInOneScopeForDecoratedAsyncScopedLifestyledInstance_WrapsATransientDecoratorAroundAAsyncScopedLifestyledInstance()
        {
            // Arrange
            var container = new Container();

            container.Register<ICommand, ConcreteCommand>(new AsyncScopedLifestyle());

            container.RegisterDecorator(typeof(ICommand), typeof(CommandDecorator));

            using (AsyncScopedLifestyle.BeginScope(container))
            {
                // Act
                var decorator1 = (CommandDecorator)container.GetInstance<ICommand>();
                var decorator2 = (CommandDecorator)container.GetInstance<ICommand>();

                // Assert
                Assert.IsFalse(object.ReferenceEquals(decorator1, decorator2),
                    "The decorator should be transient.");

                Assert.IsTrue(object.ReferenceEquals(decorator1.DecoratedInstance, decorator2.DecoratedInstance),
                    "The decorated instance should be scoped per execution context. It seems to be transient.");
            }
        }

        [TestMethod]
        public void GetInstance_CalledTwiceInOneScopeForDecoratedAsyncScopedLifestyledInstance2_WrapsATransientDecoratorAroundAAsyncScopedLifestyledInstance()
        {
            // Arrange
            var container = new Container();

            // Same as previous test, but now with RegisterDecorator called first.
            container.RegisterDecorator(typeof(ICommand), typeof(CommandDecorator));

            container.Register<ICommand, ConcreteCommand>(new AsyncScopedLifestyle());

            using (AsyncScopedLifestyle.BeginScope(container))
            {
                // Act
                var decorator1 = (CommandDecorator)container.GetInstance<ICommand>();
                var decorator2 = (CommandDecorator)container.GetInstance<ICommand>();

                // Assert
                Assert.IsFalse(object.ReferenceEquals(decorator1, decorator2),
                    "The decorator should be transient but seems to have a scoped lifestyle.");

                Assert.IsTrue(object.ReferenceEquals(decorator1.DecoratedInstance, decorator2.DecoratedInstance),
                    "The decorated instance should be scoped per execution context. It seems to be transient.");
            }
        }

        [TestMethod]
        public void ContainerVerify_WithWhenScopeEndsRegistration_Succeeds()
        {
            // Arrange
            var container = new Container();

            var lifestyle = new AsyncScopedLifestyle();

            container.Register<ICommand, DisposableCommand>(lifestyle);

            container.RegisterInitializer<DisposableCommand>(command =>
            {
                lifestyle.WhenScopeEnds(container, () => { });
            });

            // Act
            container.Verify();
        }

        [TestMethod]
        public void AsyncScopedLifestyleDispose_WithWhenScopeEndsRegistration_CallsTheRegisteredAction()
        {
            // Arrange
            int actionCallCount = 0;

            var container = new Container();

            var lifestyle = new AsyncScopedLifestyle();

            container.Register<DisposableCommand, DisposableCommand>(lifestyle);

            container.RegisterInitializer<DisposableCommand>(command =>
            {
                lifestyle.WhenScopeEnds(container, () => { actionCallCount++; });
            });

            var scope = AsyncScopedLifestyle.BeginScope(container);

            try
            {
                container.GetInstance<DisposableCommand>();
            }
            finally
            {
                // Act
                scope.Dispose();
            }

            // Assert
            Assert.AreEqual(1, actionCallCount, "Delegate is expected to be called exactly once.");
        }

        [TestMethod]
        public void AsyncScopedLifestyleDispose_WithWhenScopeEndsRegistration_CallsTheRegisteredActionBeforeCallingDispose()
        {
            // Arrange
            bool delegateHasBeenCalled = false;
            DisposableCommand instanceToDispose = null;

            var container = new Container();

            var lifestyle = new AsyncScopedLifestyle();

            container.Register<DisposableCommand>(lifestyle);

            container.RegisterInitializer<DisposableCommand>(command =>
            {
                lifestyle.WhenScopeEnds(container, () =>
                {
                    Assert.IsFalse(command.HasBeenDisposed,
                        "The action should be called before disposing the instance, because users are " +
                        "to use those instances.");
                    delegateHasBeenCalled = true;
                });
            });

            var scope = AsyncScopedLifestyle.BeginScope(container);

            try
            {
                instanceToDispose = container.GetInstance<DisposableCommand>();
            }
            finally
            {
                // Act
                scope.Dispose();
            }

            // Assert
            Assert.IsTrue(delegateHasBeenCalled, "Delegate is expected to be called.");
        }

        [TestMethod]
        public void AsyncScopedLifestyleDispose_WithTransientRegisteredForDisposal_DisposesThatInstance()
        {
            // Arrange
            DisposableCommand transientInstanceToDispose = null;

            var container = new Container();
            container.Options.EnableAutoVerification = false;

            var lifestyle = new AsyncScopedLifestyle();

            container.Register<DisposableCommand>();

            container.RegisterInitializer<DisposableCommand>(command =>
            {
                lifestyle.RegisterForDisposal(container, command);
            });

            var scope = AsyncScopedLifestyle.BeginScope(container);

            try
            {
                transientInstanceToDispose = container.GetInstance<DisposableCommand>();
            }
            finally
            {
                // Act
                scope.Dispose();
            }

            // Assert
            Assert.IsTrue(transientInstanceToDispose.HasBeenDisposed);
        }

        [TestMethod]
        public void WhenScopeEnds_NullContainerArgument_ThrowsException()
        {
            // Arrange
            Container invalidArgument = null;

            var lifestyle = new AsyncScopedLifestyle();

            // Act
            Action action = () => lifestyle.WhenScopeEnds(invalidArgument, () => { });

            // Assert
            AssertThat.Throws<ArgumentNullException>(action);
        }

        [TestMethod]
        public void WhenScopeEnds_NullActionArgument_ThrowsException()
        {
            // Arrange
            Action invalidArgument = null;

            var lifestyle = new AsyncScopedLifestyle();

            // Act
            Action action = () => lifestyle.WhenScopeEnds(new Container(), invalidArgument);

            // Assert
            AssertThat.Throws<ArgumentNullException>(action);
        }

        [TestMethod]
        public void WhenScopeEnds_CalledOutOfTheContextOfAAsyncScopedLifestyle_ThrowsException()
        {
            // Arrange
            var lifestyle = new AsyncScopedLifestyle();

            var container = new Container();

            container.Register<ConcreteCommand>(new AsyncScopedLifestyle());

            try
            {
                // Act
                lifestyle.WhenScopeEnds(container, () => { });

                // Assert
                Assert.Fail("Exception expected.");
            }
            catch (InvalidOperationException ex)
            {
                Assert.IsTrue(ex.Message.Contains(
                    "This method can only be called within the context of an active (Async Scoped) scope."),
                    "Actual: " + ex.Message);
            }
        }

        [TestMethod]
        public void WhenScopeEnds_WithMultipleDisposableComponentsDependingOnEachOther_DependsComponentsInExpectedOrder()
        {
            // Arrange
            var expectedOrderOfDisposal = new List<Type>
            {
                typeof(Outer),
                typeof(Middle),
                typeof(Inner),
            };

            var actualOrderOfDisposal = new List<Type>();

            var container = ContainerFactory.New();

            // Outer, Middle and Inner all depend on Func<object> and call it when disposed.
            // This way we can check in which order the instances are disposed.
            container.RegisterInstance<Action<object>>(instance => actualOrderOfDisposal.Add(instance.GetType()));

            // Outer depends on Middle that depends on Inner.
            // Registration is deliberately made in a different order to prevent that the order of
            // registration might influence the order of disposing.
            var lifestyle = new AsyncScopedLifestyle();

            container.Register<Middle>(lifestyle);
            container.Register<Inner>(lifestyle);
            container.Register<Outer>(lifestyle);

            var scope = AsyncScopedLifestyle.BeginScope(container);

            try
            {
                // Resolve the outer most object.
                container.GetInstance<Outer>();
            }
            finally
            {
                // Act
                scope.Dispose();
            }

            // Assert
            Assert.IsTrue(
                expectedOrderOfDisposal.SequenceEqual(actualOrderOfDisposal),
                "Types were expected to be disposed in the following order: {0}, " +
                "but they actually were disposed in the order: {1}. " +
                "This order is important, because when a components gets disposed, it might still want to " +
                "call the components it depends on, but at that time those components are already disposed.",
                string.Join(", ", expectedOrderOfDisposal.Select(type => type.Name)),
                string.Join(", ", actualOrderOfDisposal.Select(type => type.Name)));
        }

        [TestMethod]
        public void WhenScopeEnds_WithMultipleDisposableComponentsAndPropertyDependencyDependingOnEachOther_DependsComponentsInExpectedOrder()
        {
            // Arrange
            var expectedOrderOfDisposal = new List<Type>
            {
                typeof(Middle),
                typeof(Inner),
                typeof(PropertyDependency),
            };

            var actualOrderOfDisposal = new List<Type>();

            var container = ContainerFactory.New();

            // Allow PropertyDependency to be injected as property on Inner
            container.Options.PropertySelectionBehavior = new InjectProperties<ImportAttribute>();

            // PropertyDependency, Middle and Inner all depend on Func<object> and call it when disposed.
            // This way we can check in which order the instances are disposed.
            container.RegisterInstance<Action<object>>(instance => actualOrderOfDisposal.Add(instance.GetType()));

            // Middle depends on Inner that depends on property PropertyDependency.
            // Registration is deliberately made in a different order to prevent that the order of
            // registration might influence the order of disposing.
            var lifestyle = new AsyncScopedLifestyle();

            container.Register<PropertyDependency>(lifestyle);
            container.Register<Middle>(lifestyle);
            container.Register<Inner>(lifestyle);

            // Act
            var scope = AsyncScopedLifestyle.BeginScope(container);

            try
            {
                // Resolve the outer most object.
                container.GetInstance<Middle>();
            }
            finally
            {
                // Act
                scope.Dispose();
            }

            // Assert
            Assert.IsTrue(
                expectedOrderOfDisposal.SequenceEqual(actualOrderOfDisposal),
                "Types were expected to be disposed in the following order: {0}, " +
                "but they actually were disposed in the order: {1}. " +
                "Since PropertyDependency is injected as property into Inner, it is important that " +
                "PropertyDependency is disposed after Inner.",
                string.Join(", ", expectedOrderOfDisposal.Select(type => type.Name)),
                string.Join(", ", actualOrderOfDisposal.Select(type => type.Name)));
        }

        [TestMethod]
        public void GetCurrentAsyncScopedLifestyle_AfterMiddleScopeDisposedWhileInnerScopeNotDisposed_ReturnsOuterScope()
        {
            // Arrange
            var container = new Container();
            var lifestyle = new AsyncScopedLifestyle();

            var instanceToDispose = new DisposableCommand();

            container.Register<DisposableCommand>(lifestyle);

            using (Scope outerScope = AsyncScopedLifestyle.BeginScope(container))
            {
                Scope middleScope = AsyncScopedLifestyle.BeginScope(container);

                Scope innerScope = AsyncScopedLifestyle.BeginScope(container);

                middleScope.Dispose();

                // Act
                Scope actualScope = lifestyle.GetCurrentScope(container);

                // Assert
                Assert.AreSame(outerScope, actualScope);
            }
        }

        [TestMethod]
        public void GetCurrentAsyncScopedLifestyle_DisposingTheMiddleScopeBeforeInnerScope_ReturnsOuterScope()
        {
            // Arrange
            var container = new Container();
            var lifestyle = new AsyncScopedLifestyle();

            var instanceToDispose = new DisposableCommand();

            container.Register<DisposableCommand>(lifestyle);

            using (Scope outerScope = AsyncScopedLifestyle.BeginScope(container))
            {
                Scope middleScope = AsyncScopedLifestyle.BeginScope(container);

                Scope innerScope = AsyncScopedLifestyle.BeginScope(container);

                middleScope.Dispose();
                innerScope.Dispose();

                // Act
                Scope actualScope = lifestyle.GetCurrentScope(container);

                // Assert
                Assert.AreSame(outerScope, actualScope,
                    "Since the middle scope is already disposed, the current scope should be the outer.");
            }
        }

        [TestMethod]
        public void GetCurrentAsyncScopedLifestyle_DisposingAnInnerScope_ShouldNeverCauseToBeSetToInnerScope()
        {
            // Arrange
            var container = new Container();
            container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();

            var instanceToDispose = new DisposableCommand();

            container.Register<DisposableCommand>(Lifestyle.Scoped);

            using (Scope outerScope = AsyncScopedLifestyle.BeginScope(container))
            {
                Scope outerMiddleScope = AsyncScopedLifestyle.BeginScope(container);

                Scope innerMiddleScope = AsyncScopedLifestyle.BeginScope(container);

                Scope innerScope = AsyncScopedLifestyle.BeginScope(container);

                // This will cause GetCurrentAsyncScopedLifestyle to become outerScope.
                outerMiddleScope.Dispose();

                // This should not cause BeginScope to change
                innerScope.Dispose();

                // Act
                Scope actualScope = Lifestyle.Scoped.GetCurrentScope(container);

                // Assert
                Assert.AreSame(outerScope, actualScope,
                    "Even though the inner middle scope never got disposed, the inner scope should not " +
                    "this scope upon disposal. The outer scope should retain focus.");
            }
        }

        [TestMethod]
        public void GetInstance_WithPossibleObjectGraphOptimizableRegistration_Succeeds()
        {
            // Arrange
            var container = new Container();

            container.Register<ICommand, DisposableCommand>(new AsyncScopedLifestyle());

            container.Register<ClassDependingOn<ICommand>>();

            // This registration can be optimized to prevent ICommand from being requested more than once from
            // the AsyncScopedLifestyleRegistration.GetInstance
            container.Register<ClassDependingOn<ClassDependingOn<ICommand>, ClassDependingOn<ICommand>>>();

            using (AsyncScopedLifestyle.BeginScope(container))
            {
                // Act
                var instance =
                    container.GetInstance<ClassDependingOn<ClassDependingOn<ICommand>, ClassDependingOn<ICommand>>>();
            }
        }

        [TestMethod]
        public void BuildExpression_ManuallyCompiledToDelegate_CanBeExecutedSuccessfully()
        {
            // Arrange
            var container = ContainerFactory.New();

            container.Register<ICommand, ConcreteCommand>(new AsyncScopedLifestyle());

            // Creating the instance for type ICommand failed. The configuration is invalid.
            // The type ConcreteCommand is directly or indirectly depending on itself.
            // The cyclic graph contains the following types: ConcreteCommand.
            // Verification was triggered because Container.Options.EnableAutoVerification was enabled.
            // To prevent the container from being verified on first resolve, set the value to false.
            InstanceProducer producer = container.GetRegistration(typeof(ICommand));
            Expression expression = producer.BuildExpression();
            var factory = Expression.Lambda<Func<ICommand>>(expression).Compile();

            using (AsyncScopedLifestyle.BeginScope(container))
            {
                // Act
                factory();
            }
        }

        [TestMethod]
        public void Dispose_ObjectRegisteredForDisposalUsingRequestedCurrentLifetimeScope_DisposesThatInstance()
        {
            // Arrange
            var container = new Container();
            container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();

            var instanceToDispose = new DisposableCommand();

            container.Register<DisposableCommand>(Lifestyle.Scoped);

            using (AsyncScopedLifestyle.BeginScope(container))
            {
                var command = container.GetInstance<DisposableCommand>();

                command.Disposing += s =>
                {
                    Lifestyle.Scoped.RegisterForDisposal(container, instanceToDispose);
                };

                // Act
            }

            // Assert
            Assert.IsTrue(instanceToDispose.HasBeenDisposed);
        }

        [TestMethod]
        public void GetCurrentScope_WithCurrentScopeSet_ReturnsTheSetScope()
        {
            var lifestyle = new AsyncScopedLifestyle();
            var container = new Container();
            var expectedScope = new Scope(container);

            // Act
            lifestyle.SetCurrentScope(expectedScope);

            // Assert
            var actualScope = lifestyle.GetCurrentScope(container);

            Assert.AreSame(expectedScope, actualScope);
        }

        private static async Task Inner(Container container, ICommand command)
        {
            DisposableCommand cmd1, cmd2;

            await Task.Yield();

            cmd1 = container.GetInstance<DisposableCommand>();
            Assert.AreSame(command, cmd1);

            using (AsyncScopedLifestyle.BeginScope(container))
            {
                // Act
                cmd2 = container.GetInstance<DisposableCommand>();

                Assert.AreNotSame(command, cmd2);
                Assert.IsFalse(cmd2.HasBeenDisposed);
            }

            Assert.IsTrue(cmd2.HasBeenDisposed);
        }

        private static async Task Outer(Container container, ICommand command)
        {
            DisposableCommand cmd1, cmd2;

            await Task.Yield();

            cmd1 = container.GetInstance<DisposableCommand>();
            Assert.AreSame(command, cmd1);

            using (AsyncScopedLifestyle.BeginScope(container))
            {
                // Act
                cmd2 = container.GetInstance<DisposableCommand>();
                Assert.AreNotSame(command, cmd2);

                var t1 = Inner(container, cmd2);
                var t2 = Inner(container, cmd2);

                await Task.WhenAll(t1, t2).ConfigureAwait(false);
                Assert.IsFalse(cmd2.HasBeenDisposed);
            }

            Assert.IsFalse(cmd1.HasBeenDisposed);
            Assert.IsTrue(cmd2.HasBeenDisposed);
        }

        public class Generic<T> : IGeneric<T>
        {
        }

        public class ClassDependingOn<TDependency>
        {
            public ClassDependingOn(TDependency dependency)
            {
            }
        }

        public class ClassDependingOn<TDependency1, TDependency2>
        {
            public ClassDependingOn(TDependency1 dependency1, TDependency2 dependency2)
            {
            }
        }

        public class DisposableCommand : ICommand, IDisposable
        {
            public event Action<DisposableCommand> Disposing;

            public int DisposeCount { get; private set; }

            public bool HasBeenDisposed => this.DisposeCount > 0;

            public void Dispose()
            {
                this.DisposeCount++;

                this.Disposing?.Invoke(this);
            }

            public void Execute()
            {
            }
        }

        public class DisposableCommandWithOverriddenEquality1 : DisposableCommandWithOverriddenEquality
        {
        }

        public class DisposableCommandWithOverriddenEquality2 : DisposableCommandWithOverriddenEquality
        {
        }

        public abstract class DisposableCommandWithOverriddenEquality : ICommand, IDisposable
        {
            public int HashCode { get; set; }

            public int DisposeCount { get; private set; }

            public void Dispose()
            {
                this.DisposeCount++;
            }

            public void Execute()
            {
            }

            public override int GetHashCode() => this.HashCode;

            public override bool Equals(object obj) => this.GetHashCode() == obj.GetHashCode();
        }

        public class CommandDecorator : ICommand
        {
            public CommandDecorator(ICommand decorated)
            {
                this.DecoratedInstance = decorated;
            }

            public ICommand DecoratedInstance { get; }

            public void Execute()
            {
            }
        }

        private sealed class InjectProperties<TAttribute> : IPropertySelectionBehavior
            where TAttribute : Attribute
        {
            public bool SelectProperty(Type t, PropertyInfo p) => p.GetCustomAttribute<TAttribute>() != null;
        }
    }

    public class Outer : DisposableBase
    {
        public Outer(Middle dependency, Action<object> disposing)
            : base(disposing)
        {
            Debug.WriteLine(this.GetType().Name + " created.");
        }
    }

    public class Middle : DisposableBase
    {
        public Middle(Inner dependency, Action<object> disposing)
            : base(disposing)
        {
            Debug.WriteLine(this.GetType().Name + " created.");
        }
    }

    public class Inner : DisposableBase
    {
        public Inner(Action<object> disposing)
            : base(disposing)
        {
            Debug.WriteLine(this.GetType().Name + " created.");
        }

        [Import]
        public PropertyDependency PropertyDependency { get; set; }
    }

    public class PropertyDependency : DisposableBase
    {
        public PropertyDependency(Action<object> disposing)
            : base(disposing)
        {
            Debug.WriteLine(this.GetType().Name + " created.");
        }
    }

    public abstract class DisposableBase : IDisposable
    {
        private readonly Action<object> disposing;

        protected DisposableBase(Action<object> disposing)
        {
            this.disposing = disposing;
        }

        public void Dispose()
        {
            this.disposing(this);
        }
    }
}


text:
package origin

import (
	"crypto/tls"
	"fmt"
	"net/http"
	"net/url"
	"path"
	"strings"
	"time"

	"github.com/elazarl/go-bindata-assetfs"
	"github.com/golang/glog"

	"k8s.io/apimachinery/pkg/api/meta"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/util/sets"
	utilwait "k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/apiserver/pkg/server"
	kapi "k8s.io/kubernetes/pkg/api"
	kversion "k8s.io/kubernetes/pkg/version"

	"github.com/openshift/origin/pkg/api"
	"github.com/openshift/origin/pkg/api/latest"
	"github.com/openshift/origin/pkg/assets"
	"github.com/openshift/origin/pkg/assets/java"
	configapi "github.com/openshift/origin/pkg/cmd/server/api"
	"github.com/openshift/origin/pkg/cmd/server/crypto"
	cmdutil "github.com/openshift/origin/pkg/cmd/util"
	oauthutil "github.com/openshift/origin/pkg/oauth/util"
	oversion "github.com/openshift/origin/pkg/version"
)

// WithAssets decorates a handler by serving static assets for the subpath of
// the public URL and passing through all other requests to the given handler.
func (c *AssetConfig) WithAssets(handler http.Handler) (http.Handler, error) {
	if c == nil {
		return handler, nil
	}

	return c.addHandlers(handler)
}

// Run starts an http server for the static assets listening on the configured
// bind address
func (c *AssetConfig) Run() {
	mux, err := c.addHandlers(nil)
	if err != nil {
		glog.Fatal(err)
	}

	timeout := c.Options.ServingInfo.RequestTimeoutSeconds
	if timeout == -1 {
		timeout = 0
	}

	server := &http.Server{
		Addr:           c.Options.ServingInfo.BindAddress,
		Handler:        mux,
		ReadTimeout:    time.Duration(timeout) * time.Second,
		WriteTimeout:   time.Duration(timeout) * time.Second,
		MaxHeaderBytes: 1 << 20,
	}

	isTLS := configapi.UseTLS(c.Options.ServingInfo.ServingInfo)

	go utilwait.Forever(func() {
		if isTLS {
			extraCerts, err := configapi.GetNamedCertificateMap(c.Options.ServingInfo.NamedCertificates)
			if err != nil {
				glog.Fatal(err)
			}
			server.TLSConfig = crypto.SecureTLSConfig(&tls.Config{
				// Set SNI certificate func
				GetCertificate: cmdutil.GetCertificateFunc(extraCerts),
				MinVersion:     crypto.TLSVersionOrDie(c.Options.ServingInfo.MinTLSVersion),
				CipherSuites:   crypto.CipherSuitesOrDie(c.Options.ServingInfo.CipherSuites),
			})
			glog.Infof("Web console listening at https://%s", c.Options.ServingInfo.BindAddress)
			glog.Fatal(cmdutil.ListenAndServeTLS(server, c.Options.ServingInfo.BindNetwork, c.Options.ServingInfo.ServerCert.CertFile, c.Options.ServingInfo.ServerCert.KeyFile))
		} else {
			glog.Infof("Web console listening at http://%s", c.Options.ServingInfo.BindAddress)
			glog.Fatal(server.ListenAndServe())
		}
	}, 0)

	// Attempt to verify the server came up for 20 seconds (100 tries * 100ms, 100ms timeout per try)
	cmdutil.WaitForSuccessfulDial(isTLS, c.Options.ServingInfo.BindNetwork, c.Options.ServingInfo.BindAddress, 100*time.Millisecond, 100*time.Millisecond, 100)

	glog.Infof("Web console available at %s", c.Options.PublicURL)
}

func (c *AssetConfig) buildAssetHandler() (http.Handler, error) {
	assets.RegisterMimeTypes()

	publicURL, err := url.Parse(c.Options.PublicURL)
	if err != nil {
		glog.Fatal(err)
	}

	assetFunc := assets.JoinAssetFuncs(assets.Asset, java.Asset)
	assetDirFunc := assets.JoinAssetDirFuncs(assets.AssetDir, java.AssetDir)

	handler := http.FileServer(&assetfs.AssetFS{Asset: assetFunc, AssetDir: assetDirFunc, Prefix: ""})

	// Map of context roots (no leading or trailing slash) to the asset path to serve for requests to a missing asset
	subcontextMap := map[string]string{
		"":     "index.html",
		"java": "java/index.html",
	}

	handler, err = assets.HTML5ModeHandler(publicURL.Path, subcontextMap, handler, assetFunc)
	if err != nil {
		return nil, err
	}

	// Cache control should happen after all Vary headers are added, but before
	// any asset related routing (HTML5ModeHandler and FileServer)
	handler = assets.CacheControlHandler(oversion.Get().GitCommit, handler)

	handler = assets.SecurityHeadersHandler(handler)

	// Gzip first so that inner handlers can react to the addition of the Vary header
	handler = assets.GzipHandler(handler)

	return handler, nil
}

// Have to convert to arrays because go templates are limited and we need to be able to know
// if we are on the last index for trailing commas in JSON
func extensionPropertyArray(extensionProperties map[string]string) []assets.WebConsoleExtensionProperty {
	extensionPropsArray := []assets.WebConsoleExtensionProperty{}
	for key, value := range extensionProperties {
		extensionPropsArray = append(extensionPropsArray, assets.WebConsoleExtensionProperty{
			Key:   key,
			Value: value,
		})
	}
	return extensionPropsArray
}

func (c *AssetConfig) addHandlers(handler http.Handler) (http.Handler, error) {
	publicURL, err := url.Parse(c.Options.PublicURL)
	if err != nil {
		return nil, err
	}

	mux := http.NewServeMux()
	if handler != nil {
		// colocated with other routes, so pass any unrecognized routes through to
		// handler
		mux.Handle("/", handler)
	} else {
		// standalone mode, so redirect any unrecognized routes to the console
		if publicURL.Path != "/" {
			mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
				http.Redirect(w, req, publicURL.Path, http.StatusFound)
			})
		}
	}

	assetHandler, err := c.buildAssetHandler()
	if err != nil {
		return nil, err
	}

	masterURL, err := url.Parse(c.Options.MasterPublicURL)
	if err != nil {
		return nil, err
	}

	// Web console assets
	mux.Handle(publicURL.Path, http.StripPrefix(publicURL.Path, assetHandler))

	originResources := sets.NewString()
	k8sResources := sets.NewString()

	versions := []schema.GroupVersion{}
	versions = append(versions, kapi.Registry.GroupOrDie(api.GroupName).GroupVersions...)
	versions = append(versions, kapi.Registry.GroupOrDie(kapi.GroupName).GroupVersions...)
	deadOriginVersions := sets.NewString(configapi.DeadOpenShiftAPILevels...)
	deadKubernetesVersions := sets.NewString(configapi.DeadKubernetesAPILevels...)
	for _, version := range versions {
		for kind := range kapi.Scheme.KnownTypes(version) {
			if strings.HasSuffix(kind, "List") {
				continue
			}
			resource, _ := meta.KindToResource(version.WithKind(kind))
			if latest.OriginKind(version.WithKind(kind)) {
				if !deadOriginVersions.Has(version.String()) {
					originResources.Insert(resource.Resource)
				}
			} else {
				if !deadKubernetesVersions.Has(version.String()) {
					k8sResources.Insert(resource.Resource)
				}
			}
		}
	}

	commonResources := sets.NewString()
	for _, r := range originResources.List() {
		if k8sResources.Has(r) {
			commonResources.Insert(r)
		}
	}
	if commonResources.Len() > 0 {
		return nil, fmt.Errorf("Resources for kubernetes and origin types intersect: %v", commonResources.List())
	}

	// Generated web console config and server version
	config := assets.WebConsoleConfig{
		APIGroupAddr:          masterURL.Host,
		APIGroupPrefix:        server.APIGroupPrefix,
		MasterAddr:            masterURL.Host,
		MasterPrefix:          api.Prefix,
		MasterResources:       originResources.List(),
		KubernetesAddr:        masterURL.Host,
		KubernetesPrefix:      server.DefaultLegacyAPIPrefix,
		KubernetesResources:   k8sResources.List(),
		OAuthAuthorizeURI:     oauthutil.OpenShiftOAuthAuthorizeURL(masterURL.String()),
		OAuthTokenURI:         oauthutil.OpenShiftOAuthTokenURL(masterURL.String()),
		OAuthRedirectBase:     c.Options.PublicURL,
		OAuthClientID:         OpenShiftWebConsoleClientID,
		LogoutURI:             c.Options.LogoutURL,
		LoggingURL:            c.Options.LoggingPublicURL,
		MetricsURL:            c.Options.MetricsPublicURL,
		LimitRequestOverrides: c.LimitRequestOverrides,
	}
	kVersionInfo := kversion.Get()
	oVersionInfo := oversion.Get()
	versionInfo := assets.WebConsoleVersion{
		KubernetesVersion: kVersionInfo.GitVersion,
		OpenShiftVersion:  oVersionInfo.GitVersion,
	}

	extensionProps := assets.WebConsoleExtensionProperties{
		ExtensionProperties: extensionPropertyArray(c.Options.ExtensionProperties),
	}
	configPath := path.Join(publicURL.Path, "config.js")
	configHandler, err := assets.GeneratedConfigHandler(config, versionInfo, extensionProps)
	configHandler = assets.SecurityHeadersHandler(configHandler)
	if err != nil {
		return nil, err
	}
	mux.Handle(configPath, assets.GzipHandler(configHandler))

	// Extension scripts
	extScriptsPath := path.Join(publicURL.Path, "scripts/extensions.js")
	extScriptsHandler, err := assets.ExtensionScriptsHandler(c.Options.ExtensionScripts, c.Options.ExtensionDevelopment)
	extScriptsHandler = assets.SecurityHeadersHandler(extScriptsHandler)
	if err != nil {
		return nil, err
	}
	mux.Handle(extScriptsPath, assets.GzipHandler(extScriptsHandler))

	// Extension stylesheets
	extStylesheetsPath := path.Join(publicURL.Path, "styles/extensions.css")
	extStylesheetsHandler, err := assets.ExtensionStylesheetsHandler(c.Options.ExtensionStylesheets, c.Options.ExtensionDevelopment)
	extStylesheetsHandler = assets.SecurityHeadersHandler(extStylesheetsHandler)
	if err != nil {
		return nil, err
	}
	mux.Handle(extStylesheetsPath, assets.GzipHandler(extStylesheetsHandler))

	// Extension files
	for _, extConfig := range c.Options.Extensions {
		extBasePath := path.Join(publicURL.Path, "extensions", extConfig.Name)
		extPath := extBasePath + "/"
		extHandler := assets.AssetExtensionHandler(extConfig.SourceDirectory, extPath, extConfig.HTML5Mode)
		mux.Handle(extPath, http.StripPrefix(extBasePath, extHandler))
	}

	return mux, nil
}

redpajama_set_name: RedPajamaGithub


text:
import { connect } from 'react-redux'
import { actionCreators } from '../actions/postActions';

const mapStateToProps = (state) => {
  return { posts: state.posts };
};

const mapDispatchToProps = (dispatch) => {
  return {
    getPosts: (posts) => {
      dispatch(actionCreators.getPosts(posts));
    }
  };
};

export default connect(mapStateToProps, mapDispatchToProps);


text:
// @flow
import React from 'react';

import { getToolbarButtons } from '../../../base/config';
import { isMobileBrowser } from '../../../base/environment/utils';
import { connect } from '../../../base/redux';
import { LAYOUT_CLASSNAMES } from '../../../conference/components/web/Conference';
import { getCurrentLayout, LAYOUTS } from '../../../video-layout';
import {
    ASPECT_RATIO_BREAKPOINT,
    TOOLBAR_HEIGHT_MOBILE
} from '../../constants';
import { getActiveParticipantsIds } from '../../functions';

import Filmstrip from './Filmstrip';

type Props = {

    /**
     * The current layout of the filmstrip.
     */
    _currentLayout: string,

    /**
     * The number of columns in tile view.
     */
    _columns: number,

    /**
     * The width of the filmstrip.
     */
    _filmstripWidth: number,

    /**
     * The height of the filmstrip.
     */
    _filmstripHeight: number,

    /**
     * Whether or not the current layout is vertical filmstrip.
     */
    _isVerticalFilmstrip: boolean,

    /**
     * The participants in the call.
     */
    _remoteParticipants: Array<Object>,

    /**
     * The length of the remote participants array.
     */
    _remoteParticipantsLength: number,

    /**
     * Whether or not the filmstrip should be user-resizable.
     */
    _resizableFilmstrip: boolean,

    /**
     * The number of rows in tile view.
     */
    _rows: number,

    /**
     * The height of the thumbnail.
     */
    _thumbnailHeight: number,

    /**
     * The width of the thumbnail.
     */
    _thumbnailWidth: number,

    /**
     * Whether or not the vertical filmstrip should have a background color.
     */
    _verticalViewBackground: boolean,

    /**
     * Whether or not the vertical filmstrip should be displayed as grid.
     */
    _verticalViewGrid: boolean,

    /**
     * Additional CSS class names to add to the container of all the thumbnails.
     */
    _videosClassName: string,

    /**
     * Whether or not the filmstrip videos should currently be displayed.
     */
    _visible: boolean
};

const StageFilmstrip = (props: Props) => props._currentLayout === LAYOUTS.STAGE_FILMSTRIP_VIEW && (
    <span className = { LAYOUT_CLASSNAMES[LAYOUTS.TILE_VIEW] }>
        <Filmstrip
            { ...props }
            _stageFilmstrip = { true } />
    </span>
);

/**
 * Maps (parts of) the Redux state to the associated {@code Filmstrip}'s props.
 *
 * @param {Object} state - The Redux state.
 * @private
 * @returns {Props}
 */
function _mapStateToProps(state) {
    const toolbarButtons = getToolbarButtons(state);
    const { visible } = state['features/filmstrip'];
    const activeParticipants = getActiveParticipantsIds(state);
    const reduceHeight = state['features/toolbox'].visible && toolbarButtons.length;
    const {
        gridDimensions: dimensions = {},
        filmstripHeight,
        filmstripWidth,
        thumbnailSize
    } = state['features/filmstrip'].stageFilmstripDimensions;
    const gridDimensions = dimensions;

    const { clientHeight, clientWidth } = state['features/base/responsive-ui'];
    const availableSpace = clientHeight - filmstripHeight;
    let filmstripPadding = 0;

    if (availableSpace > 0) {
        const paddingValue = TOOLBAR_HEIGHT_MOBILE - availableSpace;

        if (paddingValue > 0) {
            filmstripPadding = paddingValue;
        }
    } else {
        filmstripPadding = TOOLBAR_HEIGHT_MOBILE;
    }

    const collapseTileView = reduceHeight
        && isMobileBrowser()
        && clientWidth <= ASPECT_RATIO_BREAKPOINT;

    const remoteFilmstripHeight = filmstripHeight - (collapseTileView && filmstripPadding > 0 ? filmstripPadding : 0);

    return {
        _columns: gridDimensions.columns,
        _currentLayout: getCurrentLayout(state),
        _filmstripHeight: remoteFilmstripHeight,
        _filmstripWidth: filmstripWidth,
        _remoteParticipantsLength: activeParticipants.length,
        _remoteParticipants: activeParticipants,
        _resizableFilmstrip: false,
        _rows: gridDimensions.rows,
        _thumbnailWidth: thumbnailSize?.width,
        _thumbnailHeight: thumbnailSize?.height,
        _visible: visible,
        _verticalViewGrid: false,
        _verticalViewBackground: false
    };
}

export default connect(_mapStateToProps)(StageFilmstrip);


text:
"""
Connection module for Amazon CloudWatch

.. versionadded:: 2014.7.0

:configuration: This module accepts explicit credentials but can also utilize
    IAM roles assigned to the instance through Instance Profiles. Dynamic
    credentials are then automatically obtained from AWS API and no further
    configuration is necessary. More Information available at:

    .. code-block:: text

        http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html

    If IAM roles are not used you need to specify them either in a pillar or
    in the minion's config file:

    .. code-block:: yaml

        cloudwatch.keyid: GKTADJGHEIQSXMKKRBJ08H
        cloudwatch.key: askdjghsdfjkghWupUjasdflkdfklgjsdfjajkghs

    A region may also be specified in the configuration:

    .. code-block:: yaml

        cloudwatch.region: us-east-1

    If a region is not specified, the default is us-east-1.

    It's also possible to specify key, keyid and region via a profile, either
    as a passed in dict, or as a string to pull from pillars or minion config:

    .. code-block:: yaml

        myprofile:
            keyid: GKTADJGHEIQSXMKKRBJ08H
            key: askdjghsdfjkghWupUjasdflkdfklgjsdfjajkghs
            region: us-east-1

:depends: boto
"""
# keep lint from choking on _get_conn and _cache_id
# pylint: disable=E0602

import logging

import yaml  # pylint: disable=blacklisted-import

import salt.utils.json
import salt.utils.odict as odict
import salt.utils.versions

try:
    import boto
    import boto.ec2.cloudwatch
    import boto.ec2.cloudwatch.dimension
    import boto.ec2.cloudwatch.listelement

    logging.getLogger("boto").setLevel(logging.CRITICAL)
    HAS_BOTO = True
except ImportError:
    HAS_BOTO = False

log = logging.getLogger(__name__)

def __virtual__():
    """
    Only load if boto libraries exist.
    """
    has_boto_reqs = salt.utils.versions.check_boto_reqs(check_boto3=False)
    if has_boto_reqs is True:
        __utils__["boto.assign_funcs"](
            __name__, "cloudwatch", module="ec2.cloudwatch", pack=__salt__
        )
    return has_boto_reqs

def get_alarm(name, region=None, key=None, keyid=None, profile=None):
    """
    Get alarm details. Also can be used to check to see if an alarm exists.

    CLI Example:

    .. code-block:: bash

        salt myminion boto_cloudwatch.get_alarm myalarm region=us-east-1
    """
    conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile)

    alarms = conn.describe_alarms(alarm_names=[name])
    if not alarms:
        return None
    if len(alarms) > 1:
        log.error("multiple alarms matched name '%s'", name)
    return _metric_alarm_to_dict(alarms[0])

def _safe_dump(data):
    """
    this presenter magic makes yaml.safe_dump
    work with the objects returned from
    boto.describe_alarms()
    """
    custom_dumper = __utils__["yaml.get_dumper"]("SafeOrderedDumper")

    def boto_listelement_presenter(dumper, data):
        return dumper.represent_list(list(data))

    yaml.add_representer(
        boto.ec2.cloudwatch.listelement.ListElement,
        boto_listelement_presenter,
        Dumper=custom_dumper,
    )

    def dimension_presenter(dumper, data):
        return dumper.represent_dict(dict(data))

    yaml.add_representer(
        boto.ec2.cloudwatch.dimension.Dimension,
        dimension_presenter,
        Dumper=custom_dumper,
    )

    return __utils__["yaml.dump"](data, Dumper=custom_dumper)

def get_all_alarms(region=None, prefix=None, key=None, keyid=None, profile=None):
    """
    Get all alarm details.  Produces results that can be used to create an sls
    file.

    If prefix parameter is given, alarm names in the output will be prepended
    with the prefix; alarms that have the prefix will be skipped.  This can be
    used to convert existing alarms to be managed by salt, as follows:

        1. Make a "backup" of all existing alarms
            $ salt-call boto_cloudwatch.get_all_alarms --out=txt | sed "s/local: //" > legacy_alarms.sls

        2. Get all alarms with new prefixed names
            $ salt-call boto_cloudwatch.get_all_alarms "prefix=**MANAGED BY SALT** " --out=txt | sed "s/local: //" > managed_alarms.sls

        3. Insert the managed alarms into cloudwatch
            $ salt-call state.template managed_alarms.sls

        4.  Manually verify that the new alarms look right

        5.  Delete the original alarms
            $ sed s/present/absent/ legacy_alarms.sls > remove_legacy_alarms.sls
            $ salt-call state.template remove_legacy_alarms.sls

        6.  Get all alarms again, verify no changes
            $ salt-call boto_cloudwatch.get_all_alarms --out=txt | sed "s/local: //" > final_alarms.sls
            $ diff final_alarms.sls managed_alarms.sls

    CLI Example:

    .. code-block:: bash

        salt myminion boto_cloudwatch.get_all_alarms region=us-east-1 --out=txt
    """
    conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile)

    alarms = conn.describe_alarms()
    results = odict.OrderedDict()
    for alarm in alarms:
        alarm = _metric_alarm_to_dict(alarm)
        name = alarm["name"]
        if prefix:
            if name.startswith(prefix):
                continue
            name = prefix + alarm["name"]
        del alarm["name"]
        alarm_sls = [{"name": name}, {"attributes": alarm}]
        results["manage alarm " + name] = {"boto_cloudwatch_alarm.present": alarm_sls}
    return _safe_dump(results)

def create_or_update_alarm(
    connection=None,
    name=None,
    metric=None,
    namespace=None,
    statistic=None,
    comparison=None,
    threshold=None,
    period=None,
    evaluation_periods=None,
    unit=None,
    description="",
    dimensions=None,
    alarm_actions=None,
    insufficient_data_actions=None,
    ok_actions=None,
    region=None,
    key=None,
    keyid=None,
    profile=None,
):
    """
    Create or update a cloudwatch alarm.

    Params are the same as:
        https://boto.readthedocs.io/en/latest/ref/cloudwatch.html#boto.ec2.cloudwatch.alarm.MetricAlarm.

    Dimensions must be a dict. If the value of Dimensions is a string, it will
    be json decoded to produce a dict. alarm_actions, insufficient_data_actions,
    and ok_actions must be lists of string.  If the passed-in value is a string,
    it will be split on "," to produce a list. The strings themselves for
    alarm_actions, insufficient_data_actions, and ok_actions must be Amazon
    resource names (ARN's); however, this method also supports an arn lookup
    notation, as follows:

        arn:aws:....                                    ARN as per http://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html
        scaling_policy:<as_name>:<scaling_policy_name>  The named autoscale group scaling policy, for the named group (e.g.  scaling_policy:my-asg:ScaleDown)

    This is convenient for setting up autoscaling as follows.  First specify a
    boto_asg.present state for an ASG with scaling_policies, and then set up
    boto_cloudwatch_alarm.present states which have alarm_actions that
    reference the scaling_policy.

    CLI Example:

    .. code-block:: bash

        salt myminion boto_cloudwatch.create_alarm name=myalarm ... region=us-east-1
    """
    # clean up argument types, so that CLI works
    if threshold:
        threshold = float(threshold)
    if period:
        period = int(period)
    if evaluation_periods:
        evaluation_periods = int(evaluation_periods)
    if isinstance(dimensions, str):
        dimensions = salt.utils.json.loads(dimensions)
        if not isinstance(dimensions, dict):
            log.error(
                "could not parse dimensions argument: must be json encoding of a dict:"
                " '%s'",
                dimensions,
            )
            return False
    if isinstance(alarm_actions, str):
        alarm_actions = alarm_actions.split(",")
    if isinstance(insufficient_data_actions, str):
        insufficient_data_actions = insufficient_data_actions.split(",")
    if isinstance(ok_actions, str):
        ok_actions = ok_actions.split(",")

    # convert provided action names into ARN's
    if alarm_actions:
        alarm_actions = convert_to_arn(
            alarm_actions, region=region, key=key, keyid=keyid, profile=profile
        )
    if insufficient_data_actions:
        insufficient_data_actions = convert_to_arn(
            insufficient_data_actions,
            region=region,
            key=key,
            keyid=keyid,
            profile=profile,
        )
    if ok_actions:
        ok_actions = convert_to_arn(
            ok_actions, region=region, key=key, keyid=keyid, profile=profile
        )

    conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile)

    alarm = boto.ec2.cloudwatch.alarm.MetricAlarm(
        connection=connection,
        name=name,
        metric=metric,
        namespace=namespace,
        statistic=statistic,
        comparison=comparison,
        threshold=threshold,
        period=period,
        evaluation_periods=evaluation_periods,
        unit=unit,
        description=description,
        dimensions=dimensions,
        alarm_actions=alarm_actions,
        insufficient_data_actions=insufficient_data_actions,
        ok_actions=ok_actions,
    )
    conn.create_alarm(alarm)
    log.info("Created/updated alarm %s", name)
    return True

def convert_to_arn(arns, region=None, key=None, keyid=None, profile=None):
    """
    Convert a list of strings into actual arns. Converts convenience names such
    as 'scaling_policy:...'

    CLI Example:

    .. code-block:: bash

        salt '*' convert_to_arn 'scaling_policy:'
    """
    results = []
    for arn in arns:
        if arn.startswith("scaling_policy:"):
            _, as_group, scaling_policy_name = arn.split(":")
            policy_arn = __salt__["boto_asg.get_scaling_policy_arn"](
                as_group, scaling_policy_name, region, key, keyid, profile
            )
            if policy_arn:
                results.append(policy_arn)
            else:
                log.error("Could not convert: %s", arn)
        else:
            results.append(arn)
    return results

def delete_alarm(name, region=None, key=None, keyid=None, profile=None):
    """
    Delete a cloudwatch alarm

    CLI example to delete a queue::

        salt myminion boto_cloudwatch.delete_alarm myalarm region=us-east-1
    """
    conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile)

    conn.delete_alarms([name])
    log.info("Deleted alarm %s", name)
    return True

def _metric_alarm_to_dict(alarm):
    """
    Convert a boto.ec2.cloudwatch.alarm.MetricAlarm into a dict. Convenience
    for pretty printing.
    """
    d = odict.OrderedDict()
    fields = [
        "name",
        "metric",
        "namespace",
        "statistic",
        "comparison",
        "threshold",
        "period",
        "evaluation_periods",
        "unit",
        "description",
        "dimensions",
        "alarm_actions",
        "insufficient_data_actions",
        "ok_actions",
    ]
    for f in fields:
        if hasattr(alarm, f):
            d[f] = getattr(alarm, f)
    return d