Duplicate parrallel-for-each extension methods for IAsyncEnumerator<T>

--- ParallelForEachExtensions.cs
+++ ParallelForEachExtensions.cs
@@ -262,6 +262,105 @@
         /// Invokes an asynchronous action on each item in the collection in parallel
         /// </summary>
         /// <typeparam name="T">The type of an item</typeparam>
+        /// <param name="enumerator">The collection of items to perform actions on</param>
+        /// <param name="asyncItemAction">An asynchronous action to perform on the item, where first argument is the item and second argument is item's index in the collection</param>
+        /// <param name="maxDegreeOfParalellism">Maximum items to schedule processing in parallel. The actual concurrency level depends on TPL settings. Set to 0 to choose a default value based on processor count.</param>
+        /// <param name="breakLoopOnException">Set to True to stop processing items when first exception occurs. The result <see cref="AggregateException"/> might contain several exceptions though when faulty tasks finish at the same time.</param>
+        /// <param name="gracefulBreak">If True (the default behavior), waits on completion for all started tasks when the loop breaks due to cancellation or an exception</param>
+        /// <param name="cancellationToken">Cancellation token</param>
+        /// <exception cref="ParallelForEachException">Wraps any exception(s) that occurred inside <paramref name="asyncItemAction"/></exception>
+        /// <exception cref="OperationCanceledException">Thrown when the loop is canceled with <paramref name="cancellationToken"/></exception>
+        public static Task ParallelForEachAsync<T>(
+            this IAsyncEnumerator<T> enumerator,
+            Func<T, long, Task> asyncItemAction,
+            int maxDegreeOfParalellism,
+            bool breakLoopOnException,
+            bool gracefulBreak,
+            CancellationToken cancellationToken = default(CancellationToken))
+        {
+            if (enumerator == null)
+                throw new ArgumentNullException(nameof(enumerator));
+            if (asyncItemAction == null)
+                throw new ArgumentNullException(nameof(asyncItemAction));
+
+            var context = new ParallelForEachContext(maxDegreeOfParalellism, breakLoopOnException, gracefulBreak, cancellationToken);
+
+            Task.Run(
+                async () =>
+                {
+                    try
+                    {
+                        var itemIndex = 0L;
+
+                        while (await enumerator.MoveNextAsync(cancellationToken).ConfigureAwait(false))
+                        {
+                            if (context.IsLoopBreakRequested)
+                                break;
+
+                            await context.OnStartOperationAsync(cancellationToken).ConfigureAwait(false);
+
+                            if (context.IsLoopBreakRequested)
+                            {
+                                context.OnOperationComplete();
+                                break;
+                            }
+
+                            Task itemActionTask = null;
+                            try
+                            {
+                                itemActionTask = asyncItemAction(enumerator.Current, itemIndex);
+                            }
+                            // there is no guarantee that task is executed asynchronously, so it can throw right away
+                            catch (Exception ex)
+                            {
+                                ex.Data["ForEach.Index"] = itemIndex;
+                                context.OnOperationComplete(ex);
+                            }
+
+                            if (itemActionTask != null)
+                            {
+                                var capturedItemIndex = itemIndex;
+#pragma warning disable CS4014  // Justification: not awaited by design
+                                itemActionTask.ContinueWith(
+                                    task =>
+                                    {
+                                        Exception ex = null;
+                                        if (task.IsFaulted)
+                                        {
+                                            ex = task.Exception;
+
+                                            var aggEx = ex as AggregateException;
+                                            if (aggEx != null && aggEx.InnerExceptions.Count == 1)
+                                                ex = aggEx.InnerException;
+
+                                            ex.Data["ForEach.Index"] = capturedItemIndex;
+                                        }
+
+                                        context.OnOperationComplete(ex);
+                                    });
+#pragma warning restore CS4014
+                            }
+
+                            itemIndex++;
+                        }
+                    }
+                    catch (Exception ex)
+                    {
+                        context.AddException(ex);
+                    }
+                    finally
+                    {
+                        context.OnOperationComplete();
+                    }
+                });
+
+            return context.CompletionTask;
+        }
+
+        /// <summary>
+        /// Invokes an asynchronous action on each item in the collection in parallel
+        /// </summary>
+        /// <typeparam name="T">The type of an item</typeparam>
         /// <param name="collection">The collection of items to perform actions on</param>
         /// <param name="asyncItemAction">An asynchronous action to perform on the item, where first argument is the item and second argument is item's index in the collection</param>
         /// <param name="maxDegreeOfParalellism">Maximum items to schedule processing in parallel. The actual concurrency level depends on TPL settings. Set to 0 to choose a default value based on processor count.</param>
@@ -286,6 +385,30 @@
         /// Invokes an asynchronous action on each item in the collection in parallel
         /// </summary>
         /// <typeparam name="T">The type of an item</typeparam>
+        /// <param name="enumerator">The collection of items to perform actions on</param>
+        /// <param name="asyncItemAction">An asynchronous action to perform on the item, where first argument is the item and second argument is item's index in the collection</param>
+        /// <param name="maxDegreeOfParalellism">Maximum items to schedule processing in parallel. The actual concurrency level depends on TPL settings. Set to 0 to choose a default value based on processor count.</param>
+        /// <param name="breakLoopOnException">Set to True to stop processing items when first exception occurs. The result <see cref="AggregateException"/> might contain several exceptions though when faulty tasks finish at the same time.</param>
+        /// <param name="cancellationToken">Cancellation token</param>
+        /// <exception cref="ParallelForEachException">Wraps any exception(s) that occurred inside <paramref name="asyncItemAction"/></exception>
+        /// <exception cref="OperationCanceledException">Thrown when the loop is canceled with <paramref name="cancellationToken"/></exception>
+        public static Task ParallelForEachAsync<T>(
+            this IAsyncEnumerator<T> enumerator,
+            Func<T, long, Task> asyncItemAction,
+            int maxDegreeOfParalellism,
+            bool breakLoopOnException,
+            CancellationToken cancellationToken = default(CancellationToken))
+            => enumerator.ParallelForEachAsync(
+                asyncItemAction,
+                maxDegreeOfParalellism,
+                breakLoopOnException,
+                /*gracefulBreak:*/true,
+                cancellationToken);
+
+        /// <summary>
+        /// Invokes an asynchronous action on each item in the collection in parallel
+        /// </summary>
+        /// <typeparam name="T">The type of an item</typeparam>
         /// <param name="collection">The collection of items to perform actions on</param>
         /// <param name="asyncItemAction">An asynchronous action to perform on the item, where first argument is the item and second argument is item's index in the collection</param>
         /// <param name="maxDegreeOfParalellism">Maximum items to schedule processing in parallel. The actual concurrency level depends on TPL settings. Set to 0 to choose a default value based on processor count.</param>
@@ -308,6 +431,28 @@
         /// Invokes an asynchronous action on each item in the collection in parallel
         /// </summary>
         /// <typeparam name="T">The type of an item</typeparam>
+        /// <param name="enumerator">The collection of items to perform actions on</param>
+        /// <param name="asyncItemAction">An asynchronous action to perform on the item, where first argument is the item and second argument is item's index in the collection</param>
+        /// <param name="maxDegreeOfParalellism">Maximum items to schedule processing in parallel. The actual concurrency level depends on TPL settings. Set to 0 to choose a default value based on processor count.</param>
+        /// <param name="cancellationToken">Cancellation token</param>
+        /// <exception cref="ParallelForEachException">Wraps any exception(s) that occurred inside <paramref name="asyncItemAction"/></exception>
+        /// <exception cref="OperationCanceledException">Thrown when the loop is canceled with <paramref name="cancellationToken"/></exception>
+        public static Task ParallelForEachAsync<T>(
+            this IAsyncEnumerator<T> enumerator,
+            Func<T, long, Task> asyncItemAction,
+            int maxDegreeOfParalellism,
+            CancellationToken cancellationToken = default(CancellationToken))
+            => enumerator.ParallelForEachAsync(
+                asyncItemAction,
+                maxDegreeOfParalellism,
+                /*breakLoopOnException:*/false,
+                /*gracefulBreak:*/true,
+                cancellationToken);
+
+        /// <summary>
+        /// Invokes an asynchronous action on each item in the collection in parallel
+        /// </summary>
+        /// <typeparam name="T">The type of an item</typeparam>
         /// <param name="collection">The collection of items to perform actions on</param>
         /// <param name="asyncItemAction">An asynchronous action to perform on the item, where first argument is the item and second argument is item's index in the collection</param>
         /// <param name="cancellationToken">Cancellation token</param>
@@ -328,6 +473,26 @@
         /// Invokes an asynchronous action on each item in the collection in parallel
         /// </summary>
         /// <typeparam name="T">The type of an item</typeparam>
+        /// <param name="enumerator">The collection of items to perform actions on</param>
+        /// <param name="asyncItemAction">An asynchronous action to perform on the item, where first argument is the item and second argument is item's index in the collection</param>
+        /// <param name="cancellationToken">Cancellation token</param>
+        /// <exception cref="ParallelForEachException">Wraps any exception(s) that occurred inside <paramref name="asyncItemAction"/></exception>
+        /// <exception cref="OperationCanceledException">Thrown when the loop is canceled with <paramref name="cancellationToken"/></exception>
+        public static Task ParallelForEachAsync<T>(
+            this IAsyncEnumerator<T> enumerator,
+            Func<T, long, Task> asyncItemAction,
+            CancellationToken cancellationToken = default(CancellationToken))
+            => enumerator.ParallelForEachAsync(
+                asyncItemAction,
+                /*maxDegreeOfParalellism:*/0,
+                /*breakLoopOnException:*/false,
+                /*gracefulBreak:*/true,
+                cancellationToken);
+
+        /// <summary>
+        /// Invokes an asynchronous action on each item in the collection in parallel
+        /// </summary>
+        /// <typeparam name="T">The type of an item</typeparam>
         /// <param name="collection">The collection of items to perform actions on</param>
         /// <param name="asyncItemAction">An asynchronous action to perform on the item</param>
         /// <param name="maxDegreeOfParalellism">Maximum items to schedule processing in parallel. The actual concurrency level depends on TPL settings. Set to 0 to choose a default value based on processor count.</param>
@@ -342,6 +507,30 @@
             bool breakLoopOnException,
             CancellationToken cancellationToken = default(CancellationToken))
             => collection.ParallelForEachAsync(
+                (item, index) => asyncItemAction(item),
+                maxDegreeOfParalellism,
+                breakLoopOnException,
+                /*gracefulBreak:*/true,
+                cancellationToken);
+
+        /// <summary>
+        /// Invokes an asynchronous action on each item in the collection in parallel
+        /// </summary>
+        /// <typeparam name="T">The type of an item</typeparam>
+        /// <param name="enumerator">The collection of items to perform actions on</param>
+        /// <param name="asyncItemAction">An asynchronous action to perform on the item</param>
+        /// <param name="maxDegreeOfParalellism">Maximum items to schedule processing in parallel. The actual concurrency level depends on TPL settings. Set to 0 to choose a default value based on processor count.</param>
+        /// <param name="breakLoopOnException">Set to True to stop processing items when first exception occurs. The result <see cref="AggregateException"/> might contain several exceptions though when faulty tasks finish at the same time.</param>
+        /// <param name="cancellationToken">Cancellation token</param>
+        /// <exception cref="ParallelForEachException">Wraps any exception(s) that occurred inside <paramref name="asyncItemAction"/></exception>
+        /// <exception cref="OperationCanceledException">Thrown when the loop is canceled with <paramref name="cancellationToken"/></exception>
+        public static Task ParallelForEachAsync<T>(
+            this IAsyncEnumerator<T> enumerator,
+            Func<T, Task> asyncItemAction,
+            int maxDegreeOfParalellism,
+            bool breakLoopOnException,
+            CancellationToken cancellationToken = default(CancellationToken))
+            => enumerator.ParallelForEachAsync(
                 (item, index) => asyncItemAction(item),
                 maxDegreeOfParalellism,
                 breakLoopOnException,
@@ -378,6 +567,32 @@
         /// Invokes an asynchronous action on each item in the collection in parallel
         /// </summary>
         /// <typeparam name="T">The type of an item</typeparam>
+        /// <param name="enumerator">The collection of items to perform actions on</param>
+        /// <param name="asyncItemAction">An asynchronous action to perform on the item</param>
+        /// <param name="maxDegreeOfParalellism">Maximum items to schedule processing in parallel. The actual concurrency level depends on TPL settings. Set to 0 to choose a default value based on processor count.</param>
+        /// <param name="breakLoopOnException">Set to True to stop processing items when first exception occurs. The result <see cref="AggregateException"/> might contain several exceptions though when faulty tasks finish at the same time.</param>
+        /// <param name="gracefulBreak">If True (the default behavior), waits on completion for all started tasks when the loop breaks due to cancellation or an exception</param>
+        /// <param name="cancellationToken">Cancellation token</param>
+        /// <exception cref="ParallelForEachException">Wraps any exception(s) that occurred inside <paramref name="asyncItemAction"/></exception>
+        /// <exception cref="OperationCanceledException">Thrown when the loop is canceled with <paramref name="cancellationToken"/></exception>
+        public static Task ParallelForEachAsync<T>(
+            this IAsyncEnumerator<T> enumerator,
+            Func<T, Task> asyncItemAction,
+            int maxDegreeOfParalellism,
+            bool breakLoopOnException,
+            bool gracefulBreak,
+            CancellationToken cancellationToken = default(CancellationToken))
+            => enumerator.ParallelForEachAsync(
+                (item, index) => asyncItemAction(item),
+                maxDegreeOfParalellism,
+                breakLoopOnException,
+                gracefulBreak,
+                cancellationToken);
+
+        /// <summary>
+        /// Invokes an asynchronous action on each item in the collection in parallel
+        /// </summary>
+        /// <typeparam name="T">The type of an item</typeparam>
         /// <param name="collection">The collection of items to perform actions on</param>
         /// <param name="asyncItemAction">An asynchronous action to perform on the item</param>
         /// <param name="maxDegreeOfParalellism">Maximum items to schedule processing in parallel. The actual concurrency level depends on TPL settings. Set to 0 to choose a default value based on processor count.</param>
@@ -400,6 +615,28 @@
         /// Invokes an asynchronous action on each item in the collection in parallel
         /// </summary>
         /// <typeparam name="T">The type of an item</typeparam>
+        /// <param name="enumerator">The collection of items to perform actions on</param>
+        /// <param name="asyncItemAction">An asynchronous action to perform on the item</param>
+        /// <param name="maxDegreeOfParalellism">Maximum items to schedule processing in parallel. The actual concurrency level depends on TPL settings. Set to 0 to choose a default value based on processor count.</param>
+        /// <param name="cancellationToken">Cancellation token</param>
+        /// <exception cref="ParallelForEachException">Wraps any exception(s) that occurred inside <paramref name="asyncItemAction"/></exception>
+        /// <exception cref="OperationCanceledException">Thrown when the loop is canceled with <paramref name="cancellationToken"/></exception>
+        public static Task ParallelForEachAsync<T>(
+            this IAsyncEnumerator<T> enumerator,
+            Func<T, Task> asyncItemAction,
+            int maxDegreeOfParalellism,
+            CancellationToken cancellationToken = default(CancellationToken))
+            => enumerator.ParallelForEachAsync(
+                (item, index) => asyncItemAction(item),
+                maxDegreeOfParalellism,
+                /*breakLoopOnException:*/false,
+                /*gracefulBreak:*/true,
+                cancellationToken);
+
+        /// <summary>
+        /// Invokes an asynchronous action on each item in the collection in parallel
+        /// </summary>
+        /// <typeparam name="T">The type of an item</typeparam>
         /// <param name="collection">The collection of items to perform actions on</param>
         /// <param name="asyncItemAction">An asynchronous action to perform on the item</param>
         /// <param name="cancellationToken">Cancellation token</param>
@@ -420,6 +657,26 @@
         /// Invokes an asynchronous action on each item in the collection in parallel
         /// </summary>
         /// <typeparam name="T">The type of an item</typeparam>
+        /// <param name="enumerator">The collection of items to perform actions on</param>
+        /// <param name="asyncItemAction">An asynchronous action to perform on the item</param>
+        /// <param name="cancellationToken">Cancellation token</param>
+        /// <exception cref="ParallelForEachException">Wraps any exception(s) that occurred inside <paramref name="asyncItemAction"/></exception>
+        /// <exception cref="OperationCanceledException">Thrown when the loop is canceled with <paramref name="cancellationToken"/></exception>
+        public static Task ParallelForEachAsync<T>(
+            this IAsyncEnumerator<T> enumerator,
+            Func<T, Task> asyncItemAction,
+            CancellationToken cancellationToken = default(CancellationToken))
+            => enumerator.ParallelForEachAsync(
+                (item, index) => asyncItemAction(item),
+                /*maxDegreeOfParalellism:*/0,
+                /*breakLoopOnException:*/false,
+                /*gracefulBreak:*/true,
+                cancellationToken);
+
+        /// <summary>
+        /// Invokes an asynchronous action on each item in the collection in parallel
+        /// </summary>
+        /// <typeparam name="T">The type of an item</typeparam>
         /// <param name="collection">The collection of items to perform actions on</param>
         /// <param name="asyncItemAction">An asynchronous action to perform on the item, where first argument is the item and second argument is item's index in the collection</param>
         /// <param name="maxDegreeOfParalellism">Maximum items to schedule processing in parallel. The actual concurrency level depends on TPL settings. Set to 0 to choose a default value based on processor count.</param>
@@ -444,6 +701,30 @@
         /// Invokes an asynchronous action on each item in the collection in parallel
         /// </summary>
         /// <typeparam name="T">The type of an item</typeparam>
+        /// <param name="enumerator">The collection of items to perform actions on</param>
+        /// <param name="asyncItemAction">An asynchronous action to perform on the item, where first argument is the item and second argument is item's index in the collection</param>
+        /// <param name="maxDegreeOfParalellism">Maximum items to schedule processing in parallel. The actual concurrency level depends on TPL settings. Set to 0 to choose a default value based on processor count.</param>
+        /// <param name="breakLoopOnException">Set to True to stop processing items when first exception occurs. The result <see cref="AggregateException"/> might contain several exceptions though when faulty tasks finish at the same time.</param>
+        /// <param name="cancellationToken">Cancellation token</param>
+        /// <exception cref="ParallelForEachException">Wraps any exception(s) that occurred inside <paramref name="asyncItemAction"/></exception>
+        /// <exception cref="OperationCanceledException">Thrown when the loop is canceled with <paramref name="cancellationToken"/></exception>
+        public static Task ParallelForEachAsync<T>(
+            this IEnumerator<T> enumerator,
+            Func<T, long, Task> asyncItemAction,
+            int maxDegreeOfParalellism,
+            bool breakLoopOnException,
+            CancellationToken cancellationToken = default(CancellationToken))
+            => enumerator.ToAsyncEnumerator(runSynchronously: true).ParallelForEachAsync(
+                asyncItemAction,
+                maxDegreeOfParalellism,
+                breakLoopOnException,
+                /*gracefulBreak:*/true,
+                cancellationToken);
+
+        /// <summary>
+        /// Invokes an asynchronous action on each item in the collection in parallel
+        /// </summary>
+        /// <typeparam name="T">The type of an item</typeparam>
         /// <param name="collection">The collection of items to perform actions on</param>
         /// <param name="asyncItemAction">An asynchronous action to perform on the item, where first argument is the item and second argument is item's index in the collection</param>
         /// <param name="maxDegreeOfParalellism">Maximum items to schedule processing in parallel. The actual concurrency level depends on TPL settings. Set to 0 to choose a default value based on processor count.</param>
@@ -466,6 +747,28 @@
         /// Invokes an asynchronous action on each item in the collection in parallel
         /// </summary>
         /// <typeparam name="T">The type of an item</typeparam>
+        /// <param name="enumerator">The collection of items to perform actions on</param>
+        /// <param name="asyncItemAction">An asynchronous action to perform on the item, where first argument is the item and second argument is item's index in the collection</param>
+        /// <param name="maxDegreeOfParalellism">Maximum items to schedule processing in parallel. The actual concurrency level depends on TPL settings. Set to 0 to choose a default value based on processor count.</param>
+        /// <param name="cancellationToken">Cancellation token</param>
+        /// <exception cref="ParallelForEachException">Wraps any exception(s) that occurred inside <paramref name="asyncItemAction"/></exception>
+        /// <exception cref="OperationCanceledException">Thrown when the loop is canceled with <paramref name="cancellationToken"/></exception>
+        public static Task ParallelForEachAsync<T>(
+            this IEnumerator<T> enumerator,
+            Func<T, long, Task> asyncItemAction,
+            int maxDegreeOfParalellism,
+            CancellationToken cancellationToken = default(CancellationToken))
+            => enumerator.ToAsyncEnumerator(runSynchronously: true).ParallelForEachAsync(
+                asyncItemAction,
+                maxDegreeOfParalellism,
+                /*breakLoopOnException:*/false,
+                /*gracefulBreak:*/true,
+                cancellationToken);
+
+        /// <summary>
+        /// Invokes an asynchronous action on each item in the collection in parallel
+        /// </summary>
+        /// <typeparam name="T">The type of an item</typeparam>
         /// <param name="collection">The collection of items to perform actions on</param>
         /// <param name="asyncItemAction">An asynchronous action to perform on the item, where first argument is the item and second argument is item's index in the collection</param>
         /// <param name="cancellationToken">Cancellation token</param>
@@ -486,6 +789,26 @@
         /// Invokes an asynchronous action on each item in the collection in parallel
         /// </summary>
         /// <typeparam name="T">The type of an item</typeparam>
+        /// <param name="enumerator">The collection of items to perform actions on</param>
+        /// <param name="asyncItemAction">An asynchronous action to perform on the item, where first argument is the item and second argument is item's index in the collection</param>
+        /// <param name="cancellationToken">Cancellation token</param>
+        /// <exception cref="ParallelForEachException">Wraps any exception(s) that occurred inside <paramref name="asyncItemAction"/></exception>
+        /// <exception cref="OperationCanceledException">Thrown when the loop is canceled with <paramref name="cancellationToken"/></exception>
+        public static Task ParallelForEachAsync<T>(
+            this IEnumerator<T> enumerator,
+            Func<T, long, Task> asyncItemAction,
+            CancellationToken cancellationToken = default(CancellationToken))
+            => enumerator.ToAsyncEnumerator(runSynchronously: true).ParallelForEachAsync(
+                asyncItemAction,
+                /*maxDegreeOfParalellism:*/0,
+                /*breakLoopOnException:*/false,
+                /*gracefulBreak:*/true,
+                cancellationToken);
+
+        /// <summary>
+        /// Invokes an asynchronous action on each item in the collection in parallel
+        /// </summary>
+        /// <typeparam name="T">The type of an item</typeparam>
         /// <param name="collection">The collection of items to perform actions on</param>
         /// <param name="asyncItemAction">An asynchronous action to perform on the item</param>
         /// <param name="maxDegreeOfParalellism">Maximum items to schedule processing in parallel. The actual concurrency level depends on TPL settings. Set to 0 to choose a default value based on processor count.</param>
@@ -510,6 +833,30 @@
         /// Invokes an asynchronous action on each item in the collection in parallel
         /// </summary>
         /// <typeparam name="T">The type of an item</typeparam>
+        /// <param name="enumerator">The collection of items to perform actions on</param>
+        /// <param name="asyncItemAction">An asynchronous action to perform on the item</param>
+        /// <param name="maxDegreeOfParalellism">Maximum items to schedule processing in parallel. The actual concurrency level depends on TPL settings. Set to 0 to choose a default value based on processor count.</param>
+        /// <param name="breakLoopOnException">Set to True to stop processing items when first exception occurs. The result <see cref="AggregateException"/> might contain several exceptions though when faulty tasks finish at the same time.</param>
+        /// <param name="cancellationToken">Cancellation token</param>
+        /// <exception cref="ParallelForEachException">Wraps any exception(s) that occurred inside <paramref name="asyncItemAction"/></exception>
+        /// <exception cref="OperationCanceledException">Thrown when the loop is canceled with <paramref name="cancellationToken"/></exception>
+        public static Task ParallelForEachAsync<T>(
+            this IEnumerator<T> enumerator,
+            Func<T, Task> asyncItemAction,
+            int maxDegreeOfParalellism,
+            bool breakLoopOnException,
+            CancellationToken cancellationToken = default(CancellationToken))
+            => enumerator.ToAsyncEnumerator(runSynchronously: true).ParallelForEachAsync(
+                (item, index) => asyncItemAction(item),
+                maxDegreeOfParalellism,
+                breakLoopOnException,
+                /*gracefulBreak:*/true,
+                cancellationToken);
+
+        /// <summary>
+        /// Invokes an asynchronous action on each item in the collection in parallel
+        /// </summary>
+        /// <typeparam name="T">The type of an item</typeparam>
         /// <param name="collection">The collection of items to perform actions on</param>
         /// <param name="asyncItemAction">An asynchronous action to perform on the item</param>
         /// <param name="maxDegreeOfParalellism">Maximum items to schedule processing in parallel. The actual concurrency level depends on TPL settings. Set to 0 to choose a default value based on processor count.</param>
@@ -532,6 +879,28 @@
         /// Invokes an asynchronous action on each item in the collection in parallel
         /// </summary>
         /// <typeparam name="T">The type of an item</typeparam>
+        /// <param name="enumerator">The collection of items to perform actions on</param>
+        /// <param name="asyncItemAction">An asynchronous action to perform on the item</param>
+        /// <param name="maxDegreeOfParalellism">Maximum items to schedule processing in parallel. The actual concurrency level depends on TPL settings. Set to 0 to choose a default value based on processor count.</param>
+        /// <param name="cancellationToken">Cancellation token</param>
+        /// <exception cref="ParallelForEachException">Wraps any exception(s) that occurred inside <paramref name="asyncItemAction"/></exception>
+        /// <exception cref="OperationCanceledException">Thrown when the loop is canceled with <paramref name="cancellationToken"/></exception>
+        public static Task ParallelForEachAsync<T>(
+            this IEnumerator<T> enumerator,
+            Func<T, Task> asyncItemAction,
+            int maxDegreeOfParalellism,
+            CancellationToken cancellationToken = default(CancellationToken))
+            => enumerator.ToAsyncEnumerator(runSynchronously: true).ParallelForEachAsync(
+                (item, index) => asyncItemAction(item),
+                maxDegreeOfParalellism,
+                /*breakLoopOnException:*/false,
+                /*gracefulBreak:*/true,
+                cancellationToken);
+
+        /// <summary>
+        /// Invokes an asynchronous action on each item in the collection in parallel
+        /// </summary>
+        /// <typeparam name="T">The type of an item</typeparam>
         /// <param name="collection">The collection of items to perform actions on</param>
         /// <param name="asyncItemAction">An asynchronous action to perform on the item</param>
         /// <param name="cancellationToken">Cancellation token</param>
@@ -542,6 +911,26 @@
             Func<T, Task> asyncItemAction,
             CancellationToken cancellationToken = default(CancellationToken))
             => collection.ToAsyncEnumerable<T>(runSynchronously: true).ParallelForEachAsync(
+                (item, index) => asyncItemAction(item),
+                /*maxDegreeOfParalellism:*/0,
+                /*breakLoopOnException:*/false,
+                /*gracefulBreak:*/true,
+                cancellationToken);
+
+        /// <summary>
+        /// Invokes an asynchronous action on each item in the collection in parallel
+        /// </summary>
+        /// <typeparam name="T">The type of an item</typeparam>
+        /// <param name="enumerator">The collection of items to perform actions on</param>
+        /// <param name="asyncItemAction">An asynchronous action to perform on the item</param>
+        /// <param name="cancellationToken">Cancellation token</param>
+        /// <exception cref="ParallelForEachException">Wraps any exception(s) that occurred inside <paramref name="asyncItemAction"/></exception>
+        /// <exception cref="OperationCanceledException">Thrown when the loop is canceled with <paramref name="cancellationToken"/></exception>
+        public static Task ParallelForEachAsync<T>(
+            this IEnumerator<T> enumerator,
+            Func<T, Task> asyncItemAction,
+            CancellationToken cancellationToken = default(CancellationToken))
+            => enumerator.ToAsyncEnumerator(runSynchronously: true).ParallelForEachAsync(
                 (item, index) => asyncItemAction(item),
                 /*maxDegreeOfParalellism:*/0,
                 /*breakLoopOnException:*/false,


adapted on slide events

adapted on slide events

--- Parsley/FrameGrabberSlide.cs
+++ Parsley/FrameGrabberSlide.cs
@@ -28,15 +28,15 @@
       set { _fg = value; }
     }

-    public override void OnSlideShowing() {
+    public override void OnSlidingIn() {
       this.FrameGrabber.OnFramePrepend += new Parsley.Core.FrameProducer.OnFrameHandler(this.OnFrame);
       this.FrameGrabber.Start();
-      base.OnSlideShowing();
+      base.OnSlidingIn();
     }

-    public override void OnSlideHiding(CancelEventArgs args) {
+    public override void OnSlidingOut(CancelEventArgs args) {
       this.FrameGrabber.OnFramePrepend -= new Parsley.Core.FrameProducer.OnFrameHandler(this.OnFrame);
-      base.OnSlideHiding(args);
+      base.OnSlidingOut(args);
     }

     protected virtual void OnFrame(Parsley.Core.FrameProducer fp, Emgu.CV.Image<Emgu.CV.Structure.Bgr, byte> img) { }


Add a way to check if a PathMoveable is moving.

--- PathMoveable/PathMoveable.cs
+++ PathMoveable/PathMoveable.cs
@@ -44,11 +44,11 @@

 	// We use to make sure we "fall" to the ground even if we stop moving.
 	bool isGrounded = false;
-
+
 	void Update ()
 	{
 		CharacterController controller = (CharacterController)collider;
-		if (currentPath != null)
+		if (IsMoving ())
 		{
 			Vector3 toDestination = (currentDestination - transform.position);
 			toDestination.y = 0f;
@@ -166,8 +166,13 @@

 	void OnDrawGizmos ()
 	{
-		if (currentPath != null)
+		if (IsMoving ())
 			currentPath.OnDrawGizmos ();
+	}
+
+	public bool IsMoving ()
+	{
+		return currentPath != null;
 	}
 }


FileUtils: Catch any time of Exception, e.g. ArgumentException from 'Illegal characters in path'

--- source/lib/FileUtils.cs
+++ source/lib/FileUtils.cs
@@ -158,7 +158,7 @@
                     }
                 }
             }
-            catch (IOException)
+            catch (Exception)
             {
                 hash = String.Empty;
             }


Removed all overloads that take an AbstractConsole with overloads that take an ILowLevelConsole

--- src/shell.me/ShellMe.CommandLine/CommandLoop.cs
+++ src/shell.me/ShellMe.CommandLine/CommandLoop.cs
@@ -19,21 +19,16 @@
         private readonly ILockingService _lockingService;
         private readonly InMemoryHistory _history;

-        public CommandLoop() : this(new LowLevelToAbstractConsoleAdapter(new LowLevelNativeConsole()))
+        public CommandLoop(): this(new LowLevelNativeConsole())
         {}

-        public CommandLoop(AbstractConsole console) : this(console, new CommandFactory())
+        public CommandLoop(ILowLevelConsole console) : this(console, new CommandFactory())
         {
         }

         public CommandLoop(ILowLevelConsole console, ICommandFactory commandFactory)
-            : this(new LowLevelToAbstractConsoleAdapter(console), commandFactory)
-        {
-        }
-
-        public CommandLoop(AbstractConsole console, ICommandFactory commandFactory)
-        {
-            Console = console;
+        {
+            Console = new LowLevelToAbstractConsoleAdapter(console);
             _commandFactory = commandFactory;
             _lockingService = new FileBasedLockingService();


Updating tests.

Updating tests.

--- test/AspNet.Plus.Infrastructure.ExceptionIntercept.Tests/ExceptionInterceptManagerTest.cs
+++ test/AspNet.Plus.Infrastructure.ExceptionIntercept.Tests/ExceptionInterceptManagerTest.cs
@@ -7,7 +7,7 @@
 using Microsoft.AspNet.Http;
 using NSubstitute;
 using System;
-using Xunit;
+using Xunit;

 namespace AspNet.Plus.Infrastructure.ExceptionIntercept.Tests
 {


Added missing [Fact] attribute.

Added missing [Fact] attribute.

--- tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests_Virtualization_Simple.cs
+++ tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests_Virtualization_Simple.cs
@@ -658,6 +658,7 @@
             Assert.Equal(expected, actual);
         }

+        [Fact]
         public void Should_Add_Containers_For_Items_After_Clear()
         {
             var target = CreateTarget(itemCount: 10);


Commiting missed test fixes

Commiting missed test fixes

--- AllReadyApp/Web-App/AllReady.UnitTest/Areas/Admin/Controllers/EventAdminControllerTests.cs
+++ AllReadyApp/Web-App/AllReady.UnitTest/Areas/Admin/Controllers/EventAdminControllerTests.cs
@@ -5,6 +5,7 @@
 using AllReady.Areas.Admin.ViewModels.Campaign;
 using AllReady.Areas.Admin.ViewModels.Event;
 using AllReady.Areas.Admin.ViewModels.Validators;
+using AllReady.Security;
 using AllReady.Services;
 using AllReady.UnitTest.Extensions;
 using MediatR;
@@ -30,7 +31,7 @@
         [Fact]
         public async Task DetailsReturnsHttpNotFoundResult_WhenEventIsNull()
         {
-            var sut = new EventController(null, Mock.Of<IMediator>(), null);
+            var sut = new EventController(null, Mock.Of<IMediator>(), null, Mock.Of<IUserAuthorizationService>());
             var result = await sut.Details(It.IsAny<int>());

             Assert.IsType<NotFoundResult>(result);
@@ -42,7 +43,7 @@
             var mediator = new Mock<IMediator>();
             mediator.Setup(x => x.SendAsync(It.IsAny<EventDetailQuery>())).ReturnsAsync(null);

-            var sut = new EventController(null, mediator.Object, null);
+            var sut = new EventController(null, mediator.Object, null, Mock.Of<IUserAuthorizationService>());

             Assert.IsType<NotFoundResult>(await sut.Details(It.IsAny<int>()));
         }
@@ -54,7 +55,7 @@
             mediator.Setup(x => x.SendAsync(It.IsAny<EventDetailQuery>())).ReturnsAsync(new EventDetailViewModel { Id = 1, Name = "Itinerary", OrganizationId = 1 });
             mediator.Setup(x => x.SendAsync(It.IsAny<AuthorizableEventQuery>())).ReturnsAsync(new FakeAuthorizableEvent(false, false, false, false));

-            var sut = new EventController(null, mediator.Object, null);
+            var sut = new EventController(null, mediator.Object, null, Mock.Of<IUserAuthorizationService>());

             Assert.IsType<ForbidResult>(await sut.Details(It.IsAny<int>()));
         }
@@ -70,7 +71,7 @@
             mediator.Setup(x => x.SendAsync(It.IsAny<EventDetailQuery>())).ReturnsAsync(viewModel);
             mediator.Setup(x => x.SendAsync(It.IsAny<AuthorizableEventQuery>())).ReturnsAsync(new FakeAuthorizableEvent(true, false, false, false));

-            var sut = new EventController(null, mediator.Object, null);
+            var sut = new EventController(null, mediator.Object, null, Mock.Of<IUserAuthorizationService>());

             var result = await sut.Details(eventID) as ViewResult;
             Assert.Equal(result.ViewName, null);
@@ -90,7 +91,7 @@
             mediator.Setup(x => x.SendAsync(It.IsAny<EventDetailQuery>())).ReturnsAsync(new EventDetailViewModel { Id = eventID, Name = "Itinerary", OrganizationId = orgId });
             mediator.Setup(x => x.SendAsync(It.IsAny<AuthorizableEventQuery>())).ReturnsAsync(new FakeAuthorizableEvent(true, true, true, true));

-            var sut = new EventController(null, mediator.Object, null);
+            var sut = new EventController(null, mediator.Object, null, Mock.Of<IUserAuthorizationService>());

             var result = await sut.Details(eventID) as ViewResult;
             Assert.Equal(result.ViewName, null);
@@ -110,7 +111,7 @@
             mediator.Setup(x => x.SendAsync(It.IsAny<EventDetailQuery>())).ReturnsAsync(new EventDetailViewModel { Id = eventID, Name = "Itinerary", OrganizationId = orgId });
             mediator.Setup(x => x.SendAsync(It.IsAny<AuthorizableEventQuery>())).ReturnsAsync(new FakeAuthorizableEvent(true, true, false, false));

-            var sut = new EventController(null, mediator.Object, null);
+            var sut = new EventController(null, mediator.Object, null, Mock.Of<IUserAuthorizationService>());

             var result = await sut.Details(eventID) as ViewResult;
             Assert.Equal(result.ViewName, null);
@@ -130,7 +131,7 @@
             mediator.Setup(x => x.SendAsync(It.IsAny<EventDetailQuery>())).ReturnsAsync(new EventDetailViewModel { Id = eventID, Name = "Itinerary", OrganizationId = orgId });
             mediator.Setup(x => x.SendAsync(It.IsAny<AuthorizableEventQuery>())).ReturnsAsync(new FakeAuthorizableEvent(true, true, true, true));

-            var sut = new EventController(null, mediator.Object, null);
+            var sut = new EventController(null, mediator.Object, null, Mock.Of<IUserAuthorizationService>());

             var result = await sut.Details(eventID) as ViewResult;
             Assert.Equal(result.ViewName, null);
@@ -151,7 +152,7 @@
             mediator.Setup(x => x.SendAsync(It.IsAny<EventDetailQuery>())).ReturnsAsync(new EventDetailViewModel { Id = eventID, Name = "Itinerary", OrganizationId = orgId });
             mediator.Setup(x => x.SendAsync(It.IsAny<AuthorizableEventQuery>())).ReturnsAsync(new FakeAuthorizableEvent(true, true, true, false));

-            var sut = new EventController(null, mediator.Object, null);
+            var sut = new EventController(null, mediator.Object, null, Mock.Of<IUserAuthorizationService>());

             var result = await sut.Details(eventID) as ViewResult;
             Assert.Equal(result.ViewName, null);
@@ -192,7 +193,7 @@
             mediator.Setup(x => x.SendAsync(It.IsAny<CampaignSummaryQuery>())).ReturnsAsync(new CampaignSummaryViewModel());
             mediator.Setup(x => x.SendAsync(It.IsAny<AuthorizableCampaignQuery>())).ReturnsAsync(new FakeAuthorizableCampaign(false, false, false, false));

-            var sut = new EventController(null, mediator.Object, null);
+            var sut = new EventController(null, mediator.Object, null, Mock.Of<IUserAuthorizationService>());

             Assert.IsType<ForbidResult>(await sut.Create(It.IsAny<int>()));
         }
@@ -206,7 +207,7 @@
             mediator.Setup(x => x.SendAsync(It.IsAny<CampaignSummaryQuery>())).ReturnsAsync(new CampaignSummaryViewModel());
             mediator.Setup(x => x.SendAsync(It.IsAny<AuthorizableCampaignQuery>())).ReturnsAsync(new FakeAuthorizableCampaign(false, false, false, true));

-            var sut = new EventController(null, mediator.Object, null) { DateTimeTodayDate = () => dateTimeTodayDate };
+            var sut = new EventController(null, mediator.Object, null, Mock.Of<IUserAuthorizationService>()) { DateTimeTodayDate = () => dateTimeTodayDate };

             var view = await sut.Create(It.IsAny<int>()) as ViewResult;
             var viewModel = view.ViewData.Model as EventEditViewModel;
@@ -238,7 +239,7 @@
             eventDetailModelValidator.Setup(x => x.Validate(It.IsAny<EventEditViewModel>(), It.IsAny<CampaignSummaryViewModel>()))
                 .Returns(new List<KeyValuePair<string, string>>());

-            var sut = new EventController(imageService.Object, mediator.Object, eventDetailModelValidator.Object);
+            var sut = new EventController(imageService.Object, mediator.Object, eventDetailModelValidator.Object, Mock.Of<IUserAuthorizationService>());

             sut.ModelState.AddModelError("test", "test");
             var result = (ViewResult)await sut.Create(It.IsAny<int>(), It.IsAny<EventEditViewModel>(), null);
@@ -259,7 +260,7 @@
             eventDetailModelValidator.Setup(x => x.Validate(It.IsAny<EventEditViewModel>(), It.IsAny<CampaignSummaryViewModel>()))
                 .Returns(new List<KeyValuePair<string, string>> { new KeyValuePair<string, string>("ErrorKey", "ErrorMessage") });

-            var sut = new EventController(imageService.Object, mediator.Object, eventDetailModelValidator.Object);
+            var sut = new EventController(imageService.Object, mediator.Object, eventDetailModelValidator.Object, Mock.Of<IUserAuthorizationService>());

             var result = (ViewResult)await sut.Create(1, It.IsAny<EventEditViewModel>(), null);
             Assert.Equal("Edit", result.ViewName);
@@ -292,7 +293,7 @@
         [Fact]
         public void CreatePostHasValidateAntiForgeryTokenAttrbiute()
         {
-            var sut = new EventController(null, Mock.Of<IMediator>(), null);
+            var sut = new EventController(null, Mock.Of<IMediator>(), null, Mock.Of<IUserAuthorizationService>());
             var routeAttribute = sut.GetAttributesOn(x => x.Create(It.IsAny<int>(), It.IsAny<EventEditViewModel>(), It.IsAny<IFormFile>())).OfType<ValidateAntiForgeryTokenAttribute>().SingleOrDefault();
             Assert.NotNull(routeAttribute);
         }
@@ -300,7 +301,7 @@
         [Fact]
         public void CreatePostHasRouteAttrbiuteWithCorrectRoute()
         {
-            var sut = new EventController(null, Mock.Of<IMediator>(), null);
+            var sut = new EventController(null, Mock.Of<IMediator>(), null, Mock.Of<IUserAuthorizationService>());
             var routeAttribute = sut.GetAttributesOn(x => x.Create(It.IsAny<int>(), It.IsAny<EventEditViewModel>(), It.IsAny<IFormFile>())).OfType<RouteAttribute>().SingleOrDefault();
             Assert.NotNull(routeAttribute);
             Assert.Equal(routeAttribute.Template, "Admin/Event/Create/{campaignId}");
@@ -317,7 +318,7 @@
         public async void EditGetReturnsHttpNotFoundResult_WhenEventIsNull()
         {
             var mediator = new Mock<IMediator>();
-            var sut = new EventController(null, mediator.Object, null);
+            var sut = new EventController(null, mediator.Object, null, Mock.Of<IUserAuthorizationService>());
             var result = await sut.Edit(It.IsAny<int>());

             Assert.IsType<NotFoundResult>(result);
@@ -330,7 +331,7 @@
             mediator.Setup(x => x.SendAsync(It.IsAny<EventEditQuery>())).ReturnsAsync(new EventEditViewModel { Id = 1, Name = "Itinerary", OrganizationId = 1 });
             mediator.Setup(x => x.SendAsync(It.IsAny<AuthorizableEventQuery>())).ReturnsAsync(new FakeAuthorizableEvent(false, false, false, false));

-            var sut = new EventController(null, mediator.Object, null);
+            var sut = new EventController(null, mediator.Object, null, Mock.Of<IUserAuthorizationService>());
             sut.MakeUserNotAnOrgAdmin();
             Assert.IsType<ForbidResult>(await sut.Edit(It.IsAny<int>()));
         }
@@ -345,7 +346,7 @@
         [Fact]
         public async Task EditPostReturnsBadRequestResult_WhenEventIsNull()
         {
-            var sut = new EventController(null, Mock.Of<IMediator>(), null);
+            var sut = new EventController(null, Mock.Of<IMediator>(), null, Mock.Of<IUserAuthorizationService>());
             Assert.IsType<BadRequestResult>(await sut.Edit(It.IsAny<EventEditViewModel>(), It.IsAny<IFormFile>()));
         }

@@ -464,7 +465,7 @@
                 .ReturnsAsync(null);
                         mediator.Setup(x => x.SendAsync(It.IsAny<AuthorizableEventQuery>())).ReturnsAsync(new FakeAuthorizableEvent(true, false, true, false));

-            var sut = new EventController(null, mediator.Object, null);
+            var sut = new EventController(null, mediator.Object, null, Mock.Of<IUserAuthorizationService>());

             Assert.IsType<NotFoundResult>(await sut.Delete(It.IsAny<int>()));
@@ -477,7 +478,7 @@
             mediator.Setup(x => x.SendAsync(It.IsAny<DeleteQuery>())).ReturnsAsync(new DeleteViewModel());
             mediator.Setup(x => x.SendAsync(It.IsAny<AuthorizableEventQuery>())).ReturnsAsync(new FakeAuthorizableEvent(true, false, false, false));

-            var sut = new EventController(null, mediator.Object, null);
+            var sut = new EventController(null, mediator.Object, null, Mock.Of<IUserAuthorizationService>());

             Assert.IsType<ForbidResult>(await sut.Delete(It.IsAny<int>()));
         }
@@ -490,7 +491,7 @@
                 .ReturnsAsync(new DeleteViewModel()).Verifiable();
             mediator.Setup(x => x.SendAsync(It.IsAny<AuthorizableEventQuery>())).ReturnsAsync(new FakeAuthorizableEvent(true, false, true, false));

-            var sut = new EventController(null, mediator.Object, null);
+            var sut = new EventController(null, mediator.Object, null, Mock.Of<IUserAuthorizationService>());

             await sut.Delete(1);

@@ -507,7 +508,7 @@
                 .ReturnsAsync(new DeleteViewModel { OrganizationId = organizationId });
             mediator.Setup(x => x.SendAsync(It.IsAny<AuthorizableEventQuery>())).ReturnsAsync(new FakeAuthorizableEvent(true, false, true, false));

-            var sut = new EventController(null, mediator.Object, null);
+            var sut = new EventController(null, mediator.Object, null, Mock.Of<IUserAuthorizationService>());

             var result = (ViewResult)await sut.Delete(It.IsAny<int>());
             var resultModel = result.ViewData.Model;
@@ -521,7 +522,7 @@
             var mediator = new Mock<IMediator>();
             mediator.Setup(x => x.SendAsync(It.IsAny<AuthorizableEventQuery>())).ReturnsAsync(new FakeAuthorizableEvent(true, false, false, false));

-            var sut = new EventController(null, mediator.Object, null);
+            var sut = new EventController(null, mediator.Object, null, Mock.Of<IUserAuthorizationService>());

             Assert.IsType<ForbidResult>(await sut.DeleteConfirmed(1));
         }
@@ -532,7 +533,7 @@
             var mediator = new Mock<IMediator>();
             mediator.Setup(x => x.SendAsync(It.IsAny<AuthorizableEventQuery>())).ReturnsAsync(new FakeAuthorizableEvent(true, false, true, false));

-            var sut = new EventController(null, mediator.Object, null);
+            var sut = new EventController(null, mediator.Object, null, Mock.Of<IUserAuthorizationService>());

             await sut.DeleteConfirmed(1);

@@ -547,7 +548,7 @@
             var mediator = new Mock<IMediator>();
             mediator.Setup(x => x.SendAsync(It.IsAny<AuthorizableEventQuery>())).ReturnsAsync(new FakeAuthorizableEvent(true, false, true, false, cmapaignId));

-            var sut = new EventController(null, mediator.Object, null);
+            var sut = new EventController(null, mediator.Object, null, Mock.Of<IUserAuthorizationService>());

             var result = await sut.DeleteConfirmed(1);

@@ -591,7 +592,7 @@
             mediatorMock.Setup(m => m.SendAsync(It.IsAny<EventEditQuery>())).ReturnsAsync(null);
             var imageServiceMock = new Mock<IImageService>();
             var eventEditViewModelValidatorMock = new Mock<IValidateEventEditViewModels>();
-            var sut = new EventController(imageServiceMock.Object, mediatorMock.Object, eventEditViewModelValidatorMock.Object);
+            var sut = new EventController(imageServiceMock.Object, mediatorMock.Object, eventEditViewModelValidatorMock.Object, Mock.Of<IUserAuthorizationService>());

             var result = await sut.DeleteEventImage(It.IsAny<int>());

@@ -615,7 +616,7 @@

             var imageServiceMock = new Mock<IImageService>();
             var eventEditViewModelValidatorMock = new Mock<IValidateEventEditViewModels>();
-            var sut = new EventController(imageServiceMock.Object, mediatorMock.Object, eventEditViewModelValidatorMock.Object);
+            var sut = new EventController(imageServiceMock.Object, mediatorMock.Object, eventEditViewModelValidatorMock.Object, Mock.Of<IUserAuthorizationService>());
             sut.MakeUserNotAnOrgAdmin();

             var result = await sut.DeleteEventImage(It.IsAny<int>());
@@ -634,7 +635,7 @@
             var mediatorMock = new Mock<IMediator>();
             var imageServiceMock = new Mock<IImageService>();
             var eventEditViewModelValidatorMock = new Mock<IValidateEventEditViewModels>();
-            var sut = new EventController(imageServiceMock.Object, mediatorMock.Object, eventEditViewModelValidatorMock.Object);
+            var sut = new EventController(imageServiceMock.Object, mediatorMock.Object, eventEditViewModelValidatorMock.Object, Mock.Of<IUserAuthorizationService>());

             const int eventId = 2;

@@ -660,7 +661,7 @@

             var imageServiceMock = new Mock<IImageService>();
             var eventEditViewModelValidatorMock = new Mock<IValidateEventEditViewModels>();
-            var sut = new EventController(imageServiceMock.Object, mediatorMock.Object, eventEditViewModelValidatorMock.Object);
+            var sut = new EventController(imageServiceMock.Object, mediatorMock.Object, eventEditViewModelValidatorMock.Object, Mock.Of<IUserAuthorizationService>());
             sut.MakeUserAnOrgAdmin(eventEditViewModel.OrganizationId.ToString());

             await sut.DeleteEventImage(It.IsAny<int>());
@@ -684,7 +685,7 @@

             var imageServiceMock = new Mock<IImageService>();
             var eventEditViewModelValidatorMock = new Mock<IValidateEventEditViewModels>();
-            var sut = new EventController(imageServiceMock.Object, mediatorMock.Object, eventEditViewModelValidatorMock.Object);
+            var sut = new EventController(imageServiceMock.Object, mediatorMock.Object, eventEditViewModelValidatorMock.Object, Mock.Of<IUserAuthorizationService>());
             sut.MakeUserAnOrgAdmin(eventEditViewModel.OrganizationId.ToString());

             await sut.DeleteEventImage(It.IsAny<int>());
@@ -708,7 +709,7 @@

             var imageServiceMock = new Mock<IImageService>();
             var eventEditViewModelValidatorMock = new Mock<IValidateEventEditViewModels>();
-            var sut = new EventController(imageServiceMock.Object, mediatorMock.Object, eventEditViewModelValidatorMock.Object);
+            var sut = new EventController(imageServiceMock.Object, mediatorMock.Object, eventEditViewModelValidatorMock.Object, Mock.Of<IUserAuthorizationService>());
             sut.MakeUserAnOrgAdmin(eventEditViewModel.OrganizationId.ToString());

             var result = await sut.DeleteEventImage(It.IsAny<int>());
@@ -735,7 +736,7 @@

             var imageServiceMock = new Mock<IImageService>();
             var eventEditViewModelValidatorMock = new Mock<IValidateEventEditViewModels>();
-            var sut = new EventController(imageServiceMock.Object, mediatorMock.Object, eventEditViewModelValidatorMock.Object);
+            var sut = new EventController(imageServiceMock.Object, mediatorMock.Object, eventEditViewModelValidatorMock.Object, Mock.Of<IUserAuthorizationService>());
             sut.MakeUserAnOrgAdmin(eventEditViewModel.OrganizationId.ToString());

             var result = await sut.DeleteEventImage(It.IsAny<int>());
@@ -886,7 +887,7 @@
             mockMediator.Setup(x => x.SendAsync(It.IsAny<AuthorizableEventQuery>())).ReturnsAsync(new FakeAuthorizableEvent(true, false, false, false));
             mockMediator.Setup(mock => mock.SendAsync(It.IsAny<EventRequestsQuery>())).ReturnsAsync(new EventRequestsViewModel());

-            var sut = new EventController(null, mockMediator.Object, null);
+            var sut = new EventController(null, mockMediator.Object, null, Mock.Of<IUserAuthorizationService>());
             await sut.Requests(eventId, null);

             mockMediator.Verify(x => x.SendAsync(It.Is<EventRequestsQuery>(y => y.EventId == eventId)), Times.Once);
@@ -899,7 +900,7 @@
             mockMediator.Setup(mock => mock.SendAsync(It.IsAny<OrganizationIdByEventIdQuery>())).ReturnsAsync(It.IsAny<int>());
             mockMediator.Setup(x => x.SendAsync(It.IsAny<AuthorizableEventQuery>())).ReturnsAsync(new FakeAuthorizableEvent(false, false, false, false));

-            var sut = new EventController(null, mockMediator.Object, null);
+            var sut = new EventController(null, mockMediator.Object, null, Mock.Of<IUserAuthorizationService>());

             Assert.IsType<ForbidResult>(await sut.Requests(It.IsAny<int>(), null));
         }
@@ -910,7 +911,7 @@
             var mockMediator = new Mock<IMediator>();
             mockMediator.Setup(x => x.SendAsync(It.IsAny<AuthorizableEventQuery>())).ReturnsAsync(new FakeAuthorizableEvent(true, false, false, false));

-            var sut = new EventController(null, mockMediator.Object, null);
+            var sut = new EventController(null, mockMediator.Object, null, Mock.Of<IUserAuthorizationService>());

             Assert.IsType<RedirectToActionResult>(await sut.Requests(It.IsAny<int>(), "MadeUp"));
         }
@@ -924,7 +925,7 @@
             mockMediator.Setup(x => x.SendAsync(It.IsAny<AuthorizableEventQuery>())).ReturnsAsync(new FakeAuthorizableEvent(true, false, false, false));
             mockMediator.Setup(mock => mock.SendAsync(It.IsAny<EventRequestsQuery>())).ReturnsAsync(new EventRequestsViewModel());

-            var sut = new EventController(null, mockMediator.Object, null);
+            var sut = new EventController(null, mockMediator.Object, null, Mock.Of<IUserAuthorizationService>());

             await sut.Requests(eventId, null);

@@ -940,7 +941,7 @@
             mockMediator.Setup(x => x.SendAsync(It.IsAny<AuthorizableEventQuery>())).ReturnsAsync(new FakeAuthorizableEvent(true, false, false, false));
             mockMediator.Setup(mock => mock.SendAsync(It.IsAny<EventRequestsQuery>())).ReturnsAsync(new EventRequestsViewModel());

-            var sut = new EventController(null, mockMediator.Object, null);
+            var sut = new EventController(null, mockMediator.Object, null, Mock.Of<IUserAuthorizationService>());

             await sut.Requests(eventId, null);

@@ -954,7 +955,7 @@
             mockMediator.Setup(x => x.SendAsync(It.IsAny<AuthorizableEventQuery>())).ReturnsAsync(new FakeAuthorizableEvent(true, false, false, false));
             mockMediator.Setup(mock => mock.SendAsync(It.IsAny<EventRequestsQuery>())).ReturnsAsync(new EventRequestsViewModel());

-            var sut = new EventController(null, mockMediator.Object, null);
+            var sut = new EventController(null, mockMediator.Object, null, Mock.Of<IUserAuthorizationService>());

             var result = await sut.Requests(1, null) as ViewResult;
             result.ShouldNotBeNull();
@@ -972,7 +973,7 @@
             mockMediator.Setup(x => x.SendAsync(It.IsAny<AuthorizableEventQuery>())).ReturnsAsync(new FakeAuthorizableEvent(true, false, false, false));
             mockMediator.Setup(mock => mock.SendAsync(It.IsAny<EventRequestsQuery>())).ReturnsAsync(new EventRequestsViewModel());

-            var sut = new EventController(null, mockMediator.Object, null);
+            var sut = new EventController(null, mockMediator.Object, null, Mock.Of<IUserAuthorizationService>());

             var result = await sut.Requests(1, "Assigned") as ViewResult;
             result.ShouldNotBeNull();
@@ -985,7 +986,7 @@

         private static EventController EventControllerWithNoInjectedDependencies()
         {
-            return new EventController(null, null, null);
+            return new EventController(null, null, null, null);
         }
     }
 }


Modified a bit for WebHeaderCollection.cs, into the year 2015

--- websocket-sharp/Net/WebHeaderCollection.cs
+++ websocket-sharp/Net/WebHeaderCollection.cs
@@ -9,7 +9,7 @@
  *
  * Copyright (c) 2003 Ximian, Inc. (http://www.ximian.com)
  * Copyright (c) 2007 Novell, Inc. (http://www.novell.com)
- * Copyright (c) 2012-2014 sta.blockhead
+ * Copyright (c) 2012-2015 sta.blockhead
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal


Fix Parse to TryParse fallback.

Fix Parse to TryParse fallback.

--- src/ValueString.cs
+++ src/ValueString.cs
@@ -918,24 +918,24 @@
                     }

                     // Wrap the regular parser.
-                    if (fallbackToParse)
-                    {
-                        var parser = InitFunc(false);
-                        if (parser != null)
-                            return InitTryFunc(targetType, (string s, IFormatProvider provider, out T result) =>
+                    if (!fallbackToParse)
+                        return null;
+
+                    var parser = InitFunc(false);
+                    if (parser != null)
+                        return InitTryFunc(targetType, (string s, IFormatProvider provider, out T result) =>
+                        {
+                            try
                             {
-                                try
-                                {
-                                    result = parser(s, provider);
-                                    return true;
-                                }
-                                catch (Exception)
-                                {
-                                    result = default(T);
-                                    return false;
-                                }
-                            });
-                    }
+                                result = parser(s, provider);
+                                return true;
+                            }
+                            catch (Exception)
+                            {
+                                result = default(T);
+                                return false;
+                            }
+                        });

                     // Return a failure parser.
                     return InitTryFunc(targetType, (string s, IFormatProvider provider, out T result) =>


Fixed hash value in test.

Fixed hash value in test.

--- Test/ServerTelemetryChannel.Test/Shared.Tests/Implementation/SamplingScoreGeneratorTest.cs
+++ Test/ServerTelemetryChannel.Test/Shared.Tests/Implementation/SamplingScoreGeneratorTest.cs
@@ -90,7 +90,7 @@
                                                     {"ornuu", 1588005865},
                                                     {"otodvlhtvu", 1544494884},
                                                     {"uhpwhasnvmnykjkitla", 981289895},
-                                                    {"itbnryqnjcgpmjemdghqtg", 1481733713},
+                                                    {"itbnryqnjcgpmjemdghqtg", 1469591400},
                                                     {"wauetkdnivwlafbfhiedsfx", 2114415420},
                                                     {"fniwmeidbvd", 508699380},
                                                     {"vuwdgoxspstvj", 1821547235},


Fix: Playing event being fired before play has been initialized in osu!

resulting in tokens not using playing mods for modded tokens
Fixes #222

--- plugins/OsuMemoryEventSource/MemoryListener.cs
+++ plugins/OsuMemoryEventSource/MemoryListener.cs
@@ -27,6 +27,7 @@
         private OsuMemoryStatus _currentStatus = OsuMemoryStatus.Unknown;
         private string _lastMapHash = "";
         private int _lastMapSelectionMods = -2;
+        private int _lastPlayingMods = -2;
         private MemoryDataProcessor _memoryDataProcessor;
         private PatternsDispatcher _patternsDispatcher;
         public Tokens Tokens => _memoryDataProcessor.Tokens;
@@ -64,6 +65,9 @@
                 var gameMode = reader.ReadSongSelectGameMode();
                 var mapHash = reader.GetMapMd5Safe();
                 var mapSelectionMods = reader.GetMods();
+                var playingMods = status == OsuStatus.Playing || status == OsuStatus.Watching
+                    ? reader.GetPlayingMods()
+                    : -1;
                 var retries = reader.GetRetrys();
                 var currentTime = reader.ReadPlayTime();

@@ -72,7 +76,7 @@
                 var memoryStatusDiffers = _lastStatus != _currentStatus;
                 var gameModeDiffers = gameMode != _lastGameMode;
                 var mapSelectionModsDiffer = mapSelectionMods != _lastMapSelectionMods;
-
+                var playingModsDiffer = (status == OsuStatus.Watching || status == OsuStatus.Playing) && playingMods != _lastPlayingMods;
                 OsuEventType? osuEventType = null;
                 //"good enough" replay retry detection.
                 if (isReplay && _currentStatus == OsuMemoryStatus.Playing && _lastTime > currentTime && DateTime.UtcNow > _nextReplayRetryAllowedAt)
@@ -82,8 +86,8 @@
                 }

                 _lastTime = currentTime;
-
-                if (sendEvents && (
+                var playInitialized = (status != OsuStatus.Watching && status != OsuStatus.Playing) || playingMods != -1;
+                if (sendEvents && playInitialized && (
                         osuEventType.HasValue
                         || mapIdDiffers || memoryStatusDiffers
                         || mapHashDiffers || gameModeDiffers
@@ -92,10 +96,10 @@
                         )
                     )
                 {
-                    if (!osuEventType.HasValue)
+                    if (!osuEventType.HasValue || playingModsDiffer)
                     {
                         osuEventType =
-                            mapIdDiffers || mapHashDiffers || gameModeDiffers || mapSelectionModsDiffer ? OsuEventType.MapChange //different mapId/hash/mode/mods(changed stats) = different map
+                            mapIdDiffers || mapHashDiffers || gameModeDiffers || mapSelectionModsDiffer || playingModsDiffer ? OsuEventType.MapChange //different mapId/hash/mode/mods(changed stats) = different map
                             : memoryStatusDiffers ? OsuEventType.SceneChange //memory scene(status) change = Scene change
                             : _currentStatus == OsuMemoryStatus.Playing ? OsuEventType.PlayChange // map retry
                             : OsuEventType.MapChange; //bail
@@ -107,6 +111,7 @@
                     _lastGameMode = gameMode;
                     _lastMapSelectionMods = mapSelectionMods;
                     _lastMapHash = mapHash;
+                    _lastPlayingMods = playingMods;

                     NewOsuEvent?.Invoke(this, new MapSearchArgs("OsuMemory", osuEventType.Value)
                     {
@@ -118,7 +123,6 @@
                     });

                 }
-

                 _memoryDataProcessor.Tick(status, reader);
             }


Roll TextIndex on PageIndex change.

Roll TextIndex on PageIndex change.

--- test/Grobid.PdfToXml.Test/IndexGeneratorTest.cs
+++ test/Grobid.PdfToXml.Test/IndexGeneratorTest.cs
@@ -26,6 +26,18 @@
             testSubject.TextIndex.Should().Be("p1_t2");
             testSubject.TextIndex.Should().Be("p1_t3");
         }
+
+        [Fact]
+        public void TextIndexShouldRollOnPageChange()
+        {
+            var testSubject = new IndexGenerator();
+            testSubject.PageIndex.Should().Be("p1");
+            testSubject.TextIndex.Should().Be("p1_t1");
+            testSubject.TextIndex.Should().Be("p1_t2");
+            testSubject.PageIndex.Should().Be("p2");
+            testSubject.TextIndex.Should().Be("p2_t1");
+            testSubject.TextIndex.Should().Be("p2_t2");
+        }
     }

     public class IndexGenerator
@@ -38,6 +50,7 @@
             get
             {
                 this.pageIndex++;
+                this.textIndex = 0;
                 return String.Format("p{0}", this.pageIndex);
             }
         }


Fix Consul tests (#7722)

Fix Consul tests (#7722)

--- test/Extensions/Consul.Tests/ConsulTestUtils.cs
+++ test/Extensions/Consul.Tests/ConsulTestUtils.cs
@@ -9,8 +9,7 @@
 {
     public static class ConsulTestUtils
     {
-        public static string ConsulConnectionString = TestDefaultConfiguration.ConsulConnectionString;
-
+        public static readonly string ConsulConnectionString = TestDefaultConfiguration.ConsulConnectionString;
         private static readonly Lazy<bool> EnsureConsulLazy = new Lazy<bool>(() => EnsureConsulAsync().Result);

         public static void EnsureConsul()
@@ -19,8 +18,13 @@
                 throw new SkipException("Consul cluster isn't running");
         }

-        public  static async Task<bool> EnsureConsulAsync()
+        public static async Task<bool> EnsureConsulAsync()
         {
+            if (string.IsNullOrWhiteSpace(ConsulConnectionString))
+            {
+                return false;
+            }
+
             try
             {
                 var client = new HttpClient();


SliderTick transform improvements

SliderTick transform improvements

--- osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs
+++ osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs
@@ -31,6 +31,8 @@
             BorderThickness = 2;
             BorderColour = Color4.White;

+            Alpha = 0;
+
             Children = new Drawable[]
             {
                 new Box
@@ -50,10 +52,8 @@

         protected override void UpdatePreemptState()
         {
-            this.Animate(
-                d => d.FadeIn(ANIM_DURATION),
-                d => d.ScaleTo(0.5f).ScaleTo(1f, ANIM_DURATION * 4, Easing.OutElasticHalf)
-            );
+            this.FadeOut().FadeIn(ANIM_DURATION);
+            this.ScaleTo(0.5f).ScaleTo(1f, ANIM_DURATION * 4, Easing.OutElasticHalf);
         }

         protected override void UpdateCurrentState(ArmedState state)
@@ -64,12 +64,12 @@
                     this.Delay(HitObject.TimePreempt).FadeOut();
                     break;
                 case ArmedState.Miss:
-                    this.FadeOut(ANIM_DURATION)
-                        .FadeColour(Color4.Red, ANIM_DURATION / 2);
+                    this.FadeOut(ANIM_DURATION);
+                    this.FadeColour(Color4.Red, ANIM_DURATION / 2);
                     break;
                 case ArmedState.Hit:
-                    this.FadeOut(ANIM_DURATION, Easing.OutQuint)
-                        .ScaleTo(Scale * 1.5f, ANIM_DURATION, Easing.Out);
+                    this.FadeOut(ANIM_DURATION, Easing.OutQuint);
+                    this.ScaleTo(Scale * 1.5f, ANIM_DURATION, Easing.Out);
                     break;
             }
         }


Parellize more integration tests

Parellize more integration tests

--- tests/Tgstation.Server.Tests/IntegrationTest.cs
+++ tests/Tgstation.Server.Tests/IntegrationTest.cs
@@ -227,9 +227,12 @@
 						var badClient = clientFactory.CreateServerClient(server.Url, newToken);
 						await Assert.ThrowsExceptionAsync<UnauthorizedException>(() => badClient.Version(cancellationToken)).ConfigureAwait(false);

-						await new AdministrationTest(adminClient.Administration).Run(cancellationToken).ConfigureAwait(false);
-						await new UsersTest(adminClient.Users).Run(cancellationToken).ConfigureAwait(false);
+						var adminTest = new AdministrationTest(adminClient.Administration).Run(cancellationToken);
+						var usersTest = new UsersTest(adminClient.Users).Run(cancellationToken);
 						await new InstanceManagerTest(adminClient.Instances, server.Directory).Run(cancellationToken).ConfigureAwait(false);
+
+						await adminTest.ConfigureAwait(false);
+						await usersTest.ConfigureAwait(false);
 					}
 				}
 				catch (Exception ex)


tests(util): Jitter the retry robot delay.

--- testutil/TestUtil.cs
+++ testutil/TestUtil.cs
@@ -57,6 +57,9 @@
         public IEnumerable<Type> RetryWhenExceptions { get; set; } = new Type[0];
         public Func<Exception, bool> ShouldRetry { get; set; }

+        private static readonly Random _random = new Random();
+        private static readonly object _lock = new object();
+
         /// <summary>
         /// Retry action when assertion fails.
         /// </summary>
@@ -73,7 +76,12 @@
                 catch (Exception e)
                 when (ShouldCatch(e) && i < MaxTryCount)
                 {
-                    Thread.Sleep(delayMs);
+                    int jitteredDelayMs;
+                    lock(_lock)
+                    {
+                        jitteredDelayMs = delayMs/2 + (int)(_random.NextDouble() * delayMs);
+                    }
+                    Thread.Sleep(jitteredDelayMs);
                     delayMs *= (int)DelayMultiplier;
                 }
             }


Fix null test.

Fix null test.

--- backend/tools/TestSuite/TestSuite.ApiTests/ContentUpdateTests.cs
+++ backend/tools/TestSuite/TestSuite.ApiTests/ContentUpdateTests.cs
@@ -150,7 +150,7 @@

                 // STEP 2: Get the item and ensure that the text is the same.
-                var updated = await _.Contents.GetAsync(content.Id);
+                var updated = await _.Contents.GetAsync(content.Id, QueryContext.Default.IgnoreFallback());

                 Assert.Null(updated.Data.Localized["en"]);
             }


Bugfix on RandomHelper

Bugfix on RandomHelper

--- src/Abp/RandomHelper.cs
+++ src/Abp/RandomHelper.cs
@@ -71,7 +71,7 @@
                 throw new ArgumentException("objs can not be null or empty!", "objs");
             }

-            return objs[GetRandom(0, objs.Length - 1)];
+            return objs[GetRandom(0, objs.Length)];
         }
     }
-}+}


BL-1027 Nicer error message when Firefox not found

* on Linux, this refers to System Browser, since we don't
  call Firefox specifically

--- src/BloomExe/Browser.cs
+++ src/BloomExe/Browser.cs
@@ -415,14 +415,37 @@
 		public void OnOpenPageInSystemBrowser(object sender, EventArgs e)
 		{
 			Debug.Assert(!InvokeRequired);
-			// An earlier version of this method made a new temp file in hopes that it would go on working
-			// in the browser even after Bloom closed. This has gotten steadily less feasible as we depend
-			// more on the http server. With the <base> element now removed, an independent page file will
-			// have even more missing links. I don't think it's worth making a separate temp file any more.
-			if (Palaso.PlatformUtilities.Platform.IsWindows)
-				Process.Start("Firefox.exe", '"' + _url + '"');
-			else
-				Process.Start("xdg-open", Uri.EscapeUriString(_url));
+			bool isWindows = Palaso.PlatformUtilities.Platform.IsWindows;
+			string genericError = "Something went wrong trying to open this page in ";
+			try
+			{
+				// An earlier version of this method made a new temp file in hopes that it would go on working
+				// in the browser even after Bloom closed. This has gotten steadily less feasible as we depend
+				// more on the http server. With the <base> element now removed, an independent page file will
+				// have even more missing links. I don't think it's worth making a separate temp file any more.
+				if (isWindows)
+					Process.Start("Firefox.exe", '"' + _url + '"');
+				else
+					Process.Start("xdg-open", Uri.EscapeUriString(_url));
+			}
+			catch (Win32Exception)
+			{
+				if (isWindows)
+				{
+					MessageBox.Show(genericError + "Firefox. Do you have Firefox in your PATH variable?");
+				}
+				else
+				{
+					// See comment in OnGetTroubleShootingInformation() about why BeginInvoke is needed.
+					// Also, in Linux, xdg-open calls the System Browser, which isn't necessarily Firefox.
+					// It isn't necessarily in Windows, either, but there we're specifying Firefox.
+					BeginInvoke((Action)delegate()
+					{
+						MessageBox.Show(genericError + "the System Browser.");
+					});
+
+				}
+			}
 		}

 		public void OnOpenPageInStylizer(object sender, EventArgs e)


Do not create a class declaration if one is not found.

--- src/Bridge/Namespace.cs
+++ src/Bridge/Namespace.cs
@@ -137,6 +137,9 @@
             if (@class.IsIncomplete == !isComplete)
                 return @class;

+            if (!createDecl)
+                return null;
+
             var newClass = CreateClass(name, isComplete);

             // Replace the incomplete declaration with the complete one.


Fix C++ <-> C# bridge on Linux.

Fix C++ <-> C# bridge on Linux.

--- platform/unity/yarrar/Assets/yarrar/Scripts/PipelineManager.cs
+++ platform/unity/yarrar/Assets/yarrar/Scripts/PipelineManager.cs
@@ -5,14 +5,23 @@
 using System.Collections.Generic;
 using System.Runtime.InteropServices;

-public class PipelineManager : MonoBehaviour
+public class PipelineManager : MonoBehaviour
 {
+#if UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN
     [DllImport ("yarrar")]
-    private static extern IntPtr initYarrar(int width, int height);
+    private static extern IntPtr initYarrar(int width, int height);
     [DllImport ("yarrar")]
     private static extern IntPtr deinitYarrar();
     [DllImport ("yarrar")]
-    private static extern IntPtr getPose(IntPtr pixelBuffer, int width, int height);
+    private static extern IntPtr getPose(IntPtr pixelBuffer, int width, int height);
+#else
+    [DllImport ("libyarrar")]
+    private static extern IntPtr initYarrar(int width, int height);
+    [DllImport ("libyarrar")]
+    private static extern IntPtr deinitYarrar();
+    [DllImport ("libyarrar")]
+    private static extern IntPtr getPose(IntPtr pixelBuffer, int width, int height);
+#endif

     [Serializable]
     private struct Pose


TestMethod methods work against a private RunCore helper, to enable improved handling of the possibly-null test class instance to run against.

--- src/Fixie/TestMethod.cs
+++ src/Fixie/TestMethod.cs
@@ -26,7 +26,7 @@

         internal bool Invoked { get; private set; }

-        public void Run(object?[] parameters, Action<Case>? caseLifecycle = null)
+        void RunCore(object?[] parameters, Action<Case>? caseLifecycle = null)
         {
             Invoked = true;

@@ -65,21 +65,26 @@
                 recorder.Skip(@case, output);
         }

+        public void Run(object?[] parameters, Action<Case>? caseLifecycle = null)
+        {
+            RunCore(parameters, caseLifecycle);
+        }
+
         public void Run(Action<Case>? caseLifecycle = null)
         {
-            Run(EmptyParameters, caseLifecycle);
+            RunCore(EmptyParameters, caseLifecycle);
         }

         public void RunCases(ParameterSource parameterSource, Action<Case>? caseLifecycle = null)
         {
             foreach (var parameters in GetCases(parameterSource))
-                Run(parameters, caseLifecycle);
+                RunCore(parameters, caseLifecycle);
         }

         public void RunCases(ParameterSource parameterSource, object? instance)
         {
             foreach (var parameters in GetCases(parameterSource))
-                Run(parameters, @case => @case.Execute(instance));
+                RunCore(parameters, @case => @case.Execute(instance));
         }

         IEnumerable<object?[]> GetCases(ParameterSource parameterSource)
@@ -94,7 +99,7 @@
         /// </summary>
         public void Skip(string? reason)
         {
-            Run(EmptyParameters, @case =>
+            RunCore(EmptyParameters, @case =>
             {
                 @case.Skip(reason);
             });
@@ -105,7 +110,7 @@
         /// </summary>
         public void Fail(Exception reason)
         {
-            Run(EmptyParameters, @case =>
+            RunCore(EmptyParameters, @case =>
             {
                 @case.Fail(reason);
             });


chore(CheckProxy): fix typo

chore(CheckProxy): fix typo

--- src/Imgix/UrlBuilder.cs
+++ src/Imgix/UrlBuilder.cs
@@ -141,12 +141,12 @@
         }

         /// <summary>
-        /// Check if the path has one of the four possible acceptable proxy
+        /// Check if the path has one of the three possible acceptable proxy
         /// prefixes. First we check if the path has the correct ascii prefix.
         /// If it does then we know that it is a proxy, but it's not percent
         /// encoded. Second, we check if the path is prefixed by a percent-encoded
         /// prefix. If it is, we know that it's a proxy and that it's percent-encoded.
-        /// Finally, if the path isn't prefixed by any of these four prefixes, it is
+        /// Finally, if the path isn't prefixed by any of these three prefixes, it is
         /// not a valid proxy. This might be "just enough validation," but if we run
         /// into issues we can make this check smarter/more-robust.
         /// </summary>


Update to NativeFileSystem from bsobel. [#5190]

--- src/NativeFileSystem.cs
+++ src/NativeFileSystem.cs
@@ -45,6 +45,11 @@
             : base()
         {
             _basePath = basePath;
+            if (!_basePath.EndsWith(@"\"))
+            {
+                _basePath += @"\";
+            }
+
             _readOnly = readOnly;
         }

@@ -113,6 +118,16 @@
                 throw new UnauthorizedAccessException();
             }

+            if (sourceFile.StartsWith(@"\"))
+            {
+                sourceFile = sourceFile.Substring(1);
+            }
+
+            if (destinationFile.StartsWith(@"\"))
+            {
+                destinationFile = destinationFile.Substring(1);
+            }
+
             File.Copy(Path.Combine(_basePath, sourceFile), Path.Combine(_basePath, destinationFile), true);
         }

@@ -127,6 +142,11 @@
                 throw new UnauthorizedAccessException();
             }

+            if (path.StartsWith(@"\"))
+            {
+                path = path.Substring(1);
+            }
+
             Directory.CreateDirectory(Path.Combine(_basePath, path));
         }

@@ -139,6 +159,11 @@
             if (_readOnly)
             {
                 throw new UnauthorizedAccessException();
+            }
+
+            if (path.StartsWith(@"\"))
+            {
+                path = path.Substring(1);
             }

             Directory.Delete(Path.Combine(_basePath, path));
@@ -178,6 +203,11 @@
                 throw new UnauthorizedAccessException();
             }

+            if (path.StartsWith(@"\"))
+            {
+                path = path.Substring(1);
+            }
+
             File.Delete(Path.Combine(_basePath, path));
         }

@@ -188,6 +218,11 @@
         /// <returns>true if the directory exists</returns>
         public override bool DirectoryExists(string path)
         {
+            if (path.StartsWith(@"\"))
+            {
+                path = path.Substring(1);
+            }
+
             return Directory.Exists(Path.Combine(_basePath, path));
         }

@@ -198,6 +233,11 @@
         /// <returns>true if the file exists</returns>
         public override bool FileExists(string path)
         {
+            if (path.StartsWith(@"\"))
+            {
+                path = path.Substring(1);
+            }
+
             return File.Exists(Path.Combine(_basePath, path));
         }

@@ -243,7 +283,12 @@
         /// <returns>Array of directories matching the search pattern.</returns>
         public override string[] GetDirectories(string path, string searchPattern, SearchOption searchOption)
         {
-            return Directory.GetDirectories(Path.Combine(_basePath, path), searchPattern, searchOption);
+            if (path.StartsWith(@"\"))
+            {
+                path = path.Substring(1);
+            }
+
+            return CleanItems(Directory.GetDirectories(Path.Combine(_basePath, path), searchPattern, searchOption));
         }

         /// <summary>
@@ -277,7 +322,12 @@
         /// <returns>Array of files matching the search pattern.</returns>
         public override string[] GetFiles(string path, string searchPattern, SearchOption searchOption)
         {
-            return Directory.GetFiles(Path.Combine(_basePath, path), searchPattern, searchOption);
+            if (path.StartsWith(@"\"))
+            {
+                path = path.Substring(1);
+            }
+
+            return CleanItems(Directory.GetFiles(Path.Combine(_basePath, path), searchPattern, searchOption));
         }

         /// <summary>
@@ -299,7 +349,12 @@
         /// <returns>Array of files and subdirectories matching the search pattern.</returns>
         public override string[] GetFileSystemEntries(string path, string searchPattern)
         {
-            return Directory.GetFileSystemEntries(Path.Combine(_basePath, path), searchPattern);
+            if (path.StartsWith(@"\"))
+            {
+                path = path.Substring(1);
+            }
+
+            return CleanItems(Directory.GetFileSystemEntries(Path.Combine(_basePath, path), searchPattern));
         }

         /// <summary>
@@ -312,6 +367,16 @@
             if (_readOnly)
             {
                 throw new UnauthorizedAccessException();
+            }
+
+            if (sourceDirectoryName.StartsWith(@"\"))
+            {
+                sourceDirectoryName = sourceDirectoryName.Substring(1);
+            }
+
+            if (destinationDirectoryName.StartsWith(@"\"))
+            {
+                destinationDirectoryName = destinationDirectoryName.Substring(1);
             }

             Directory.Move(Path.Combine(_basePath, sourceDirectoryName), Path.Combine(_basePath, destinationDirectoryName));
@@ -340,11 +405,16 @@
                 throw new UnauthorizedAccessException();
             }

-            if (FileExists(destinationName))
+            if (destinationName.StartsWith(@"\"))
+            {
+                destinationName = destinationName.Substring(1);
+            }
+
+            if (FileExists(Path.Combine(_basePath, destinationName)))
             {
                 if (overwrite)
                 {
-                    DeleteFile(destinationName);
+                    DeleteFile(Path.Combine(_basePath, destinationName));
                 }
                 else
                 {
@@ -352,6 +422,11 @@
                 }
             }

+            if (sourceName.StartsWith(@"\"))
+            {
+                sourceName = sourceName.Substring(1);
+            }
+
             File.Move(Path.Combine(_basePath, sourceName), Path.Combine(_basePath, destinationName));
         }

@@ -380,6 +455,11 @@
                 throw new UnauthorizedAccessException();
             }

+            if (path.StartsWith(@"\"))
+            {
+                path = path.Substring(1);
+            }
+
             return File.Open(Path.Combine(_basePath, path), mode, access);
         }

@@ -390,6 +470,11 @@
         /// <returns>The attributes of the file or directory</returns>
         public override FileAttributes GetAttributes(string path)
         {
+            if (path.StartsWith(@"\"))
+            {
+                path = path.Substring(1);
+            }
+
             return File.GetAttributes(Path.Combine(_basePath, path));
         }

@@ -405,6 +490,11 @@
                 throw new UnauthorizedAccessException();
             }

+            if (path.StartsWith(@"\"))
+            {
+                path = path.Substring(1);
+            }
+
             File.SetAttributes(Path.Combine(_basePath, path), newValue);
         }

@@ -435,6 +525,11 @@
         /// <returns>The creation time.</returns>
         public override DateTime GetCreationTimeUtc(string path)
         {
+            if (path.StartsWith(@"\"))
+            {
+                path = path.Substring(1);
+            }
+
             return File.GetCreationTimeUtc(Path.Combine(_basePath, path));
         }

@@ -450,6 +545,11 @@
                 throw new UnauthorizedAccessException();
             }

+            if (path.StartsWith(@"\"))
+            {
+                path = path.Substring(1);
+            }
+
             File.SetCreationTimeUtc(Path.Combine(_basePath, path), newTime);
         }

@@ -480,6 +580,11 @@
         /// <returns>The last access time</returns>
         public override DateTime GetLastAccessTimeUtc(string path)
         {
+            if (path.StartsWith(@"\"))
+            {
+                path = path.Substring(1);
+            }
+
             return File.GetLastAccessTimeUtc(Path.Combine(_basePath, path));
         }

@@ -495,6 +600,11 @@
                 throw new UnauthorizedAccessException();
             }

+            if (path.StartsWith(@"\"))
+            {
+                path = path.Substring(1);
+            }
+
             File.SetLastAccessTimeUtc(Path.Combine(_basePath, path), newTime);
         }

@@ -525,6 +635,11 @@
         /// <returns>The last write time</returns>
         public override DateTime GetLastWriteTimeUtc(string path)
         {
+            if (path.StartsWith(@"\"))
+            {
+                path = path.Substring(1);
+            }
+
             return File.GetLastWriteTimeUtc(Path.Combine(_basePath, path));
         }

@@ -540,6 +655,11 @@
                 throw new UnauthorizedAccessException();
             }

+            if (path.StartsWith(@"\"))
+            {
+                path = path.Substring(1);
+            }
+
             File.SetLastWriteTimeUtc(Path.Combine(_basePath, path), newTime);
         }

@@ -550,6 +670,11 @@
         /// <returns>The length in bytes</returns>
         public override long GetFileLength(string path)
         {
+            if (path.StartsWith(@"\"))
+            {
+                path = path.Substring(1);
+            }
+
             return new FileInfo(Path.Combine(_basePath, path)).Length;
         }

@@ -585,5 +710,16 @@
         {
             return new DiscFileSystemInfo(this, path);
         }
+
+        private string[] CleanItems(string[] dirtyItems)
+        {
+            string[] cleanList = new string[dirtyItems.Length];
+            for (int x = 0; x < dirtyItems.Length; x++)
+            {
+                cleanList[x] = dirtyItems[x].Substring(_basePath.Length - 1);
+            }
+
+            return cleanList;
+        }
     }
 }


Native: do not try to load native providers when compiled without native flag

--- src/Numerics/Control.cs
+++ src/Numerics/Control.cs
@@ -86,13 +86,18 @@
                     case "OPENBLAS":
                         UseNativeOpenBLAS();
                         break;
-#endif
+
                     default:
                         if (!TryUseNative())
                         {
                             UseManaged();
                         }
                         break;
+#else
+                    default:
+                        UseManaged();
+                        break;
+#endif
                 }
             }
             catch


Fix keys being released and re-pressed when mouse movement interleaves keyboard states

Holding A and tap S while moving the mouse in the KeyBinding test case would previously cause A to flicker between states.

Resolves https://github.com/ppy/osu/issues/1021

--- osu.Framework/Input/InputManager.cs
+++ osu.Framework/Input/InputManager.cs
@@ -286,69 +286,64 @@
         /// <returns>Processed states such that at most one button change occurs between any two consecutive states.</returns>
         private IEnumerable<InputState> createDistinctInputStates(List<InputState> states)
         {
-            InputState last = CurrentState;
+            IKeyboardState lastKeyboard = CurrentState.Keyboard;
+            IMouseState lastMouse = CurrentState.Mouse;

             foreach (var i in states)
             {
-                //first we want to create a copy of ourselves without any button changes
-                //we do this by updating our buttons to the state of the last frame.
-                var iWithoutButtons = i.Clone();
-
-                var iHasMouse = iWithoutButtons.Mouse != null;
-                var iHasKeyboard = iWithoutButtons.Keyboard != null;
+                var iHasMouse = i.Mouse != null;
+                var iHasKeyboard = i.Keyboard != null;

                 if (iHasMouse)
+                {
+                    // first we want to create a copy of ourselves without any button changes
+                    // this is done only for mouse handlers, as they have positional data we want to handle in a separate pass.
+                    var iWithoutButtons = i.Mouse.Clone();
+
                     for (MouseButton b = 0; b < MouseButton.LastButton; b++)
-                        iWithoutButtons.Mouse.SetPressed(b, last.Mouse?.IsPressed(b) ?? false);
-
-                if (iHasKeyboard)
-                    iWithoutButtons.Keyboard.Keys = last.Keyboard?.Keys ?? new Key[] { };
-
-                //we start by adding this state to the processed list...
-                yield return iWithoutButtons;
-                last = iWithoutButtons;
-
-                //and then iterate over each button/key change, adding intermediate states along the way.
-                if (iHasMouse)
-                {
+                        iWithoutButtons.SetPressed(b, lastMouse?.IsPressed(b) ?? false);
+
+                    //we start by adding this state to the processed list...
+                    yield return new InputState { Mouse = iWithoutButtons };
+
+                    lastMouse = iWithoutButtons;
+
+                    //and then iterate over each button/key change, adding intermediate states along the way.
                     for (MouseButton b = 0; b < MouseButton.LastButton; b++)
                     {
-                        if (i.Mouse.IsPressed(b) != (last.Mouse?.IsPressed(b) ?? false))
+                        if (i.Mouse.IsPressed(b) != (lastMouse?.IsPressed(b) ?? false))
                         {
-                            var intermediateState = last.Clone();
-                            if (intermediateState.Mouse == null) intermediateState.Mouse = new MouseState();
+                            var intermediateState = lastMouse?.Clone() ?? new MouseState();

                             //add our single local change
-                            intermediateState.Mouse.SetPressed(b, i.Mouse.IsPressed(b));
-
-                            last = intermediateState;
-                            yield return intermediateState;
+                            intermediateState.SetPressed(b, i.Mouse.IsPressed(b));
+
+                            lastMouse = intermediateState;
+                            yield return new InputState { Mouse = intermediateState };
                         }
                     }
                 }

                 if (iHasKeyboard)
                 {
-                    foreach (var releasedKey in last.Keyboard?.Keys.Except(i.Keyboard.Keys) ?? new Key[] { })
+                    foreach (var releasedKey in lastKeyboard?.Keys.Except(i.Keyboard.Keys) ?? new Key[] { })
                     {
-                        var intermediateState = last.Clone();
-                        if (intermediateState.Keyboard == null) intermediateState.Keyboard = new KeyboardState();
-
-                        intermediateState.Keyboard.Keys = intermediateState.Keyboard.Keys.Where(d => d != releasedKey);
-
-                        last = intermediateState;
-                        yield return intermediateState;
+                        var intermediateState = lastKeyboard?.Clone() ?? new KeyboardState();
+
+                        intermediateState.Keys = intermediateState.Keys.Where(d => d != releasedKey);
+
+                        lastKeyboard = intermediateState;
+                        yield return new InputState { Keyboard = intermediateState };
                     }

-                    foreach (var pressedKey in i.Keyboard.Keys.Except(last.Keyboard?.Keys ?? new Key[] { }))
+                    foreach (var pressedKey in i.Keyboard.Keys.Except(lastKeyboard?.Keys ?? new Key[] { }))
                     {
-                        var intermediateState = last.Clone();
-                        if (intermediateState.Keyboard == null) intermediateState.Keyboard = new KeyboardState();
-
-                        intermediateState.Keyboard.Keys = intermediateState.Keyboard.Keys.Union(new[] { pressedKey });
-
-                        last = intermediateState;
-                        yield return intermediateState;
+                        var intermediateState = lastKeyboard?.Clone() ?? new KeyboardState();
+
+                        intermediateState.Keys = intermediateState.Keys.Union(new[] { pressedKey });
+
+                        lastKeyboard = intermediateState;
+                        yield return new InputState { Keyboard = intermediateState };
                     }
                 }
             }


Add nullability to BeatmapManager's GameHost reference

--- osu.Game/Beatmaps/BeatmapManager.cs
+++ osu.Game/Beatmaps/BeatmapManager.cs
@@ -72,6 +72,7 @@
         private readonly LargeTextureStore largeTextureStore;
         private readonly ITrackStore trackStore;

+        [CanBeNull]
         private readonly GameHost host;

         [CanBeNull]
@@ -502,7 +503,7 @@
         ITrackStore IBeatmapResourceProvider.Tracks => trackStore;
         AudioManager IStorageResourceProvider.AudioManager => audioManager;
         IResourceStore<byte[]> IStorageResourceProvider.Files => Files.Store;
-        IResourceStore<TextureUpload> IStorageResourceProvider.CreateTextureLoaderStore(IResourceStore<byte[]> underlyingStore) => host.CreateTextureLoaderStore(underlyingStore);
+        IResourceStore<TextureUpload> IStorageResourceProvider.CreateTextureLoaderStore(IResourceStore<byte[]> underlyingStore) => host?.CreateTextureLoaderStore(underlyingStore);

         #endregion


Fix outdated xmldoc

Fix outdated xmldoc

--- osu.Game/Beatmaps/BeatmapManager.cs
+++ osu.Game/Beatmaps/BeatmapManager.cs
@@ -588,11 +588,8 @@
         }

         /// <summary>
-        /// Import a beamap into our local <see cref="FileStore"/> storage.
-        /// If the beatmap is already imported, the existing instance will be returned.
-        /// </summary>
-        /// <param name="reader">The beatmap archive to be read.</param>
-        /// <returns>The imported beatmap, or an existing instance if it is already present.</returns>
+        /// Create all required <see cref="BeatmapInfo"/>s for the provided archive.
+        /// </summary>
         private List<BeatmapInfo> createBeatmapDifficulties(ArchiveReader reader)
         {
             var beatmapInfos = new List<BeatmapInfo>();