Refactored the DI of  IApp to come from the construtor.

--- src/AppBrix.WebApp/Controllers/BooksController.cs
+++ src/AppBrix.WebApp/Controllers/BooksController.cs
@@ -10,28 +10,36 @@
     [Route("api/[controller]")]
     public class BooksController : Controller
     {
+        #region Construction
+        public BooksController(IApp app)
+        {
+            this.app = app;
+        }
+        #endregion
+
+        #region Public methods
         [HttpGet]
-        public IEnumerable<Book> Get([FromServices]IApp app)
+        public IEnumerable<Book> Get()
         {
-            using (var context = app.GetDbContextService().Get<BookContext>())
+            using (var context = this.app.GetDbContextService().Get<BookContext>())
             {
                 return context.Books.ToList();
             }
         }

         [HttpGet("{id}")]
-        public Book Get([FromServices]IApp app, Guid id)
+        public Book Get(Guid id)
         {
-            using (var context = app.GetDbContextService().Get<BookContext>())
+            using (var context = this.app.GetDbContextService().Get<BookContext>())
             {
                 return context.Books.SingleOrDefault(x => x.Id == id);
             }
         }

         [HttpPost]
-        public void Post([FromServices]IApp app, [FromBody]Book book)
+        public void Post([FromBody]Book book)
         {
-            using (var context = app.GetDbContextService().Get<BookContext>())
+            using (var context = this.app.GetDbContextService().Get<BookContext>())
             {
                 context.Books.Add(book);
                 context.SaveChanges();
@@ -39,9 +47,9 @@
         }

         [HttpPut("{id}")]
-        public void Put([FromServices]IApp app, Guid id, [FromBody]Book book)
+        public void Put(Guid id, [FromBody]Book book)
         {
-            using (var context = app.GetDbContextService().Get<BookContext>())
+            using (var context = this.app.GetDbContextService().Get<BookContext>())
             {
                 var original = context.Books.SingleOrDefault(x => x.Id == id);
                 original.Author = book.Author;
@@ -51,14 +59,19 @@
         }

         [HttpDelete("{id}")]
-        public void Delete([FromServices]IApp app, Guid id)
+        public void Delete(Guid id)
         {
-            using (var context = app.GetDbContextService().Get<BookContext>())
+            using (var context = this.app.GetDbContextService().Get<BookContext>())
             {
                 var book = context.Books.Single(x => x.Id == id);
                 context.Books.Remove(book);
                 context.SaveChanges();
             }
         }
+        #endregion
+
+        #region Private fields and constants
+        private readonly IApp app;
+        #endregion
     }
 }


Added a Tier property to PvpBracket

Added a Tier property to PvpBracket

--- src/ArgentPonyWarcraftClient/Models/PvpBracket.cs
+++ src/ArgentPonyWarcraftClient/Models/PvpBracket.cs
@@ -54,5 +54,11 @@
         /// </summary>
         [JsonProperty("seasonLost")]
         public int SeasonLost { get; set; }
+
+        /// <summary>
+        /// Gets or sets the PVP tier.
+        /// </summary>
+        [JsonProperty("tier")]
+        public int Tier { get; set; }
     }
 }


use a more optimizable pattern

use a more optimizable pattern

--- src/Boo.Lang.Compiler/TypeSystem/Core/Entities.cs
+++ src/Boo.Lang.Compiler/TypeSystem/Core/Entities.cs
@@ -64,7 +64,7 @@

 		public static bool IsFlagSet(EntityType flags, EntityType flag)
 		{
-			return flag == (flags & flag);
+			return (flags & flag) != 0;
 		}
 	}
 }


[mono][test] Disable multi-proc test on mono

Microsoft.Build.UnitTests.BackEnd.BuildManager_Tests.MultiProcReentrantProjectWithCallTargetDoesNotFail

.. since that doesn't work on mono yet.

--- src/Build.UnitTests/BackEnd/BuildManager_Tests.cs
+++ src/Build.UnitTests/BackEnd/BuildManager_Tests.cs
@@ -3731,6 +3731,7 @@
         /// Regression test for https://github.com/Microsoft/msbuild/issues/3047
         /// </summary>
         [Fact]
+        [Trait("Category", "mono-osx-failing")] // out-of-proc nodes not working on mono yet
         public void MultiProcReentrantProjectWithCallTargetDoesNotFail()
         {
             var a =


Update Client.cs

Update Client.cs

--- src/Hprose.RPC/Client.cs
+++ src/Hprose.RPC/Client.cs
@@ -23,10 +23,11 @@
 namespace Hprose.RPC {
     public interface ITransport {
         Task<Stream> Transport(Stream request, Context context);
-        void Abort();
+        Task Abort();
     }

     public class Client : IDisposable {
+        private static readonly object[] emptyArgs = new object[0];
         private static readonly Random random = new Random(Guid.NewGuid().GetHashCode());
         private static readonly List<(string, Type)> transTypes = new List<(string, Type)>();
         private static readonly Dictionary<string, string> schemes = new Dictionary<string, string>();
@@ -144,6 +145,7 @@
             return InvokeAsync<object>(fullname, args, context);
         }
         public async Task<T> InvokeAsync<T>(string fullname, object[] args = null, ClientContext context = null) {
+            if (args == null) args = emptyArgs;
             if (context == null) context = new ClientContext();
             context.Init(this, typeof(T));
             var task = invokeManager.Handler(fullname, args, context);
@@ -167,9 +169,9 @@
             }
             throw new NotSupportedException("The protocol " + scheme + " is not supported.");
         }
-        public void Abort() {
+        public async Task Abort() {
             foreach (var pair in transports) {
-                pair.Value.Abort();
+                await pair.Value.Abort();
             }
         }
         private bool disposed = false;


Set ToolsVersion 15.0.

Set ToolsVersion 15.0.

--- src/Codex.Analysis.Managed/MSBuildFileAnalyzer.cs
+++ src/Codex.Analysis.Managed/MSBuildFileAnalyzer.cs
@@ -229,7 +229,7 @@
             {
                 try
                 {
-                    Project project = new Project(file.FilePath, null, null, scope.Collection,
+                    Project project = new Project(file.FilePath, null, "15.0", scope.Collection,
                         ProjectLoadSettings.IgnoreMissingImports | ProjectLoadSettings.RecordDuplicateButNotCircularImports);

                     foreach (var item in project.ItemsIgnoringCondition)


remove using

remove using

--- src/Core/Utilities/CustomIpRateLimitMiddleware.cs
+++ src/Core/Utilities/CustomIpRateLimitMiddleware.cs
@@ -7,7 +7,6 @@
 using Microsoft.Extensions.Options;
 using Newtonsoft.Json;
 using System.Threading.Tasks;
-using System.Linq;
 using System;

 namespace Bit.Core.Utilities


StackList fix for more than 16 items in stack

--- Sweet.Jayson/JaysonStackList.cs
+++ Sweet.Jayson/JaysonStackList.cs
@@ -95,7 +95,7 @@

 		private void EnsureCapacity()
 		{
-			if (m_Index >= m_Length)
+			if (m_Index >= m_Length - 1)
 			{
 				m_Length += FrameSize;


refactor: adds the virtual keyword to Verify(MemberInfo) of

IdiomaticMemberAssertion.

--- src/Experiment.Idioms/IdiomaticMemberAssertion.cs
+++ src/Experiment.Idioms/IdiomaticMemberAssertion.cs
@@ -12,7 +12,7 @@
         /// specified member.
         /// </summary>
         /// <param name="member">The member.</param>
-        public void Verify(MemberInfo member)
+        public virtual void Verify(MemberInfo member)
         {
             var field = member as FieldInfo;
             if (field != null)


Clean up EqualValidatorTests

Clean up EqualValidatorTests

--- src/FluentValidation.Tests/EqualValidatorTests.cs
+++ src/FluentValidation.Tests/EqualValidatorTests.cs
@@ -32,72 +32,64 @@

 		[SetUp]
 		public void Setup() {
-            Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-US");
+			Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-US");
 		}

 		[Test]
 		public void When_the_objects_are_equal_validation_should_succeed() {
-			var person = new Person { Forename = "Foo"};
-			var validator = CreateValidator(x => x.Forename);
-			var result = validator.Validate(new PropertyValidatorContext(null, person, x => "Foo"));
-			result.IsValid().ShouldBeTrue();
+			var validator = new TestValidator { v => v.RuleFor(x => x.Forename).Equal("Foo") };
+			var result = validator.Validate(new Person { Forename = "Foo"});
+
+			result.IsValid.ShouldBeTrue();
 		}

 		[Test]
 		public void When_the_objects_are_not_equal_validation_should_fail() {
-			var person = new Person() { Forename = "Bar" };
-			var validator = CreateValidator(x => x.Forename);
-			var result = validator.Validate(new PropertyValidatorContext(null, person, x => "Foo"));
-			result.IsValid().ShouldBeFalse();
+			var validator = new TestValidator { v => v.RuleFor(x => x.Forename).Equal("Foo") };
+			var result = validator.Validate(new Person() { Forename = "Bar" });
+
+			result.IsValid.ShouldBeFalse();
 		}

 		[Test]
 		public void When_validation_fails_the_error_should_be_set() {
-			var person = new Person() {Forename = "Bar"};
-			var validator = CreateValidator(x => x.Forename);
-			var result = validator.Validate(new PropertyValidatorContext("Forename", person, x => "Foo"));
-			result.Single().ErrorMessage.ShouldEqual("'Forename' should be equal to 'Bar'.");
+			var validator = new TestValidator { v => v.RuleFor(x => x.Forename).Equal("Foo") };
+			var result = validator.Validate(new Person() {Forename = "Bar"});
+
+			result.Errors.Single().ErrorMessage.ShouldEqual("'Forename' should be equal to 'Foo'.");
 		}

 		[Test]
 		public void Should_store_property_to_compare() {
-			var validator = CreateValidator(x => x.Surname);
-			validator.MemberToCompare.ShouldEqual(typeof(Person).GetProperty("Surname"));
+			var validator = new TestValidator { v => v.RuleFor(x => x.Forename).Equal(x => x.Surname) };
+			var descriptor = validator.CreateDescriptor();
+			var propertyValidator = descriptor.GetValidatorsForMember("Forename").Cast<EqualValidator>().Single();
+
+			propertyValidator.MemberToCompare.ShouldEqual(typeof(Person).GetProperty("Surname"));
 		}

 		[Test]
 		public void Should_store_comparison_type() {
-			var validator = CreateValidator(x => x.Surname);
-			validator.Comparison.ShouldEqual(Comparison.Equal);
+			var validator = new TestValidator { v => v.RuleFor(x => x.Surname).Equal("Foo") };
+			var descriptor = validator.CreateDescriptor();
+			var propertyValidator = descriptor.GetValidatorsForMember("Surname").Cast<EqualValidator>().Single();
+
+			propertyValidator.Comparison.ShouldEqual(Comparison.Equal);
 		}

 		[Test]
-		public void Validates_against_constant() {
-			var validator = new EqualValidator("foo");
-			var result = validator.Validate(new PropertyValidatorContext(null, new Person(), x => "bar"));
-			result.IsValid().ShouldBeFalse();
+		public void Validates_against_property() {
+			var validator = new TestValidator { v => v.RuleFor(x => x.Surname).Equal(x => x.Forename) };
+			var result = validator.Validate(new Person { Surname = "foo", Forename = "foo" });
+			result.IsValid.ShouldBeTrue();
 		}

 		[Test]
 		public void Should_succeed_on_case_insensitive_comparison() {
-			var person = new Person { Surname = "foo" };
-			var validator = CreateValidator(x => x.Surname, StringComparer.OrdinalIgnoreCase);
-			var context = new PropertyValidatorContext("Surname", person, x => "FOO");
+			var validator = new TestValidator { v => v.RuleFor(x => x.Surname).Equal("FOO", StringComparer.OrdinalIgnoreCase) };
+			var result = validator.Validate(new Person { Surname = "foo" });

-			var result = validator.Validate(context);
-			result.IsValid().ShouldBeTrue();
-		}
-
-		private EqualValidator CreateValidator<T>(Expression<PropertySelector<Person, T>> expression) {
-			var func = expression.Compile();
-			PropertySelector selector = x => func((Person)x);
-			return new EqualValidator(selector, expression.GetMember());
-		}
-
-		private EqualValidator CreateValidator<T>(Expression<PropertySelector<Person, T>> expression, IEqualityComparer equalityComparer) {
-			var func = expression.Compile();
-			PropertySelector selector = x => func((Person)x);
-			return new EqualValidator(selector, expression.GetMember(), equalityComparer);
+			result.IsValid.ShouldBeTrue();
 		}
 	}
 }


remove warning

remove warning

--- SystemInteract/ProcessHelper.cs
+++ SystemInteract/ProcessHelper.cs
@@ -23,8 +23,6 @@
         public static void ReadToEnd(ISystemProcess process, Action<String> output, Action<String> error,
             int timeout = DefaultTimeout)
         {
-            DataReceivedEventHandler errorEvent = null, outEvent = null;
-
             List<Task> tasks = new List<Task>();
             if (process.StartInfo.RedirectStandardError)
             {


Remove parens

Remove parens

--- src/FubarDev.FtpServer/MultiBindingTcpListener.cs
+++ src/FubarDev.FtpServer/MultiBindingTcpListener.cs
@@ -51,16 +51,16 @@
             if (_address == IPAddress.Any.ToString())
             {
                 // "0.0.0.0"
-                addresses = new List<IPAddress>() { IPAddress.Any };
+                addresses = new List<IPAddress> { IPAddress.Any };
             }
             else if (_address == IPAddress.IPv6Any.ToString())
             {
                 // "::"
-                addresses = new List<IPAddress>() { IPAddress.IPv6Any };
+                addresses = new List<IPAddress> { IPAddress.IPv6Any };
             }
             else if (_address == "*")
             {
-                addresses = new List<IPAddress>() { IPAddress.Any, IPAddress.IPv6Any };
+                addresses = new List<IPAddress> { IPAddress.Any, IPAddress.IPv6Any };
             }
             else
             {


fix create campaign

fix create campaign

--- src/GiveCRM.Web/Controllers/CampaignController.cs
+++ src/GiveCRM.Web/Controllers/CampaignController.cs
@@ -57,7 +57,7 @@
         [HttpGet]
         public ActionResult Create()
         {
-            var model = new CampaignShowViewModel(Resources.Literal_CreateCampaign);
+            var model = new CampaignShowViewModel(Resources.Literal_CreateCampaign) {Campaign = new Campaign()};
             return View("Show", model);
         }


Start of load test tool sucking less.

Start of load test tool sucking less.

--- src/LoadTests/Program.cs
+++ src/LoadTests/Program.cs
@@ -21,9 +21,21 @@

             var cts = new CancellationTokenSource();
             var task = MainAsync(cts.Token);
-            Console.WriteLine("Press key to stop...");
+            PrintMenu();
             Console.ReadKey();
             cts.Cancel();
+        }
+
+        private static void PrintMenu()
+        {
+            Console.WriteLine("Load tests. Choose wisely.");
+            Console.WriteLine($"(your processor count is {Environment.ProcessorCount}).\r\n");
+            var foregroundColor = Console.ForegroundColor;
+            Console.ForegroundColor = ConsoleColor.Yellow;
+            Console.WriteLine(" 1. ExpectedVersion.Any on one stream.");
+            Console.WriteLine(" 2. ExpectedVersion.Any on a stream per task.");
+            Console.ForegroundColor = foregroundColor;
+            Console.WriteLine();
         }

         private static async Task MainAsync(CancellationToken cancellationToken)
@@ -71,7 +83,7 @@

                             Log.Logger.Information($"Begin {info}");
                             await eventStore.AppendToStream(
-                                $"stream-1",
+                                $"stream-{taskNumber}",
                                 ExpectedVersion.Any,
                                 newStreamEvents,
                                 cts.Token);


refactorizations across all storage DBs. supplying options for newarly all the things

--- src/MyRainbow/Program.cs
+++ src/MyRainbow/Program.cs
@@ -14,235 +14,245 @@
 {
 	public class HashCreator
 	{
+		private IEnumerable<IEnumerable<char>> _tableOfTableOfChars;
+		private MD5 _hasherMD5;
+		private Stopwatch _stopwatch;
+		private SHA256 _hasherSHA256;
+		private bool _purge;
+
 		private IConfiguration Configuration { get; set; }

-		/*private Dictionary<string, string> GetSwitchMappings(IReadOnlyDictionary<string, string> configurationStrings)
-		{
-			return configurationStrings.Select(item =>
-				new KeyValuePair<string, string>(
-					"-" + item.Key.Substring(item.Key.LastIndexOf(':') + 1),
-					item.Key))
-					.ToDictionary(
-						item => item.Key, item => item.Value);
-		}*/
-
 		public void SetupConfiguration(string[] args)
 		{
-			/*var opt_dict = new Dictionary<string, string>
-			{
-				{ "aaSqlConnection", "Rick" },
-				{ "zzzMySQL", "11" },
-				{ "zzzRedis", "blah" },
-				{ "zzzMongoDB", "buuu" },
-				{ "zzCassandra", "cass" },
-				{ "zzzDBKind", "unknown" }
-			};*/
-
 			var builder = new ConfigurationBuilder()
 			  // For more details on using the user secret store see http://go.microsoft.com/fwlink/?LinkID=532709
 			  .AddUserSecrets()
 			  .AddEnvironmentVariables()
-			  //.AddInMemoryCollection(opt_dict)
-			  .AddCommandLine(args/*, GetSwitchMappings(opt_dict)*/);
+			  .AddCommandLine(args);
+
 			var configuration = builder.Build();
-
 			Configuration = configuration;
 		}

-		private string GetParamFromCmdSecretOrEnv(string configParam = "SqlConnection")
+		private T GetParamFromCmdSecretOrEnv<T>(string configParam = "SqlConnection")
 		{
 			string conn_str = Configuration[configParam];
-			return conn_str;
+			if (conn_str == null)
+				return default(T);
+
+			return (T)Convert.ChangeType(conn_str, typeof(T));
 		}

 		internal void SqlServerExample()
 		{
-			MyCartesian cart = new MyCartesian(5, "abcdefghijklmopqrstuvwxyz");
-
-			Console.WriteLine($"Alphabet = {cart.Alphabet}{Environment.NewLine}" +
-				$"AlphabetPower = {cart.AlphabetPower}{Environment.NewLine}Length = {cart.Length}{Environment.NewLine}" +
-				$"Combination count = {cart.CombinationCount}");
-
-			var table_of_table_of_chars = cart.Generate2();
-			Console.WriteLine("Keys generated");
-			var hasherMD5 = MD5.Create();
-			var hasherSHA256 = SHA256.Create();
-			var stopwatch = new Stopwatch();
-
-			using (var dbase = new SqlDatabaseHasher(GetParamFromCmdSecretOrEnv("SqlConnection")))
-			{
-				dbase.EnsureExist();
-				//dbase.Purge();
-
-				dbase.Generate(table_of_table_of_chars, hasherMD5, hasherSHA256,
-					(key, hashMD5, hashSHA256, counter, tps) =>
-					{
-						Console.WriteLine($"MD5({key})={hashMD5},SHA256({key})={hashSHA256},counter={counter},tps={tps}");
-						if (Console.KeyAvailable)
-							return true;
-						return false;
-					}, stopwatch);
-
-				stopwatch.Stop();
-
-				dbase.Verify();
-			}
-
-			Console.WriteLine($"Done. Elpased time = {stopwatch.Elapsed}");
+			/*MyCartesian cart = new MyCartesian(5, "abcdefghijklmopqrstuvwxyz");
+
+			Console.WriteLine($"Alphabet = {cart.Alphabet}{Environment.NewLine}" +
+				$"AlphabetPower = {cart.AlphabetPower}{Environment.NewLine}Length = {cart.Length}{Environment.NewLine}" +
+				$"Combination count = {cart.CombinationCount}");
+
+			var table_of_table_of_chars = cart.Generate2();
+			Console.WriteLine("Keys generated");
+			var hasherMD5 = MD5.Create();
+			var hasherSHA256 = SHA256.Create();
+			var stopwatch = new Stopwatch();*/
+
+			using (var dbase = new SqlDatabaseHasher(GetParamFromCmdSecretOrEnv<string>("SqlConnection")))
+			{
+				dbase.EnsureExist();
+				if(_purge)
+					dbase.Purge();
+
+				dbase.Generate(_tableOfTableOfChars, _hasherMD5, _hasherSHA256,
+					(key, hashMD5, hashSHA256, counter, tps) =>
+					{
+						Console.WriteLine($"MD5({key})={hashMD5},SHA256({key})={hashSHA256},counter={counter},tps={tps}");
+						if (Console.KeyAvailable)
+							return true;
+						return false;
+					}, _stopwatch);
+
+				_stopwatch.Stop();
+
+				dbase.Verify();
+			}
+
+			Console.WriteLine($"Done. Elpased time = {_stopwatch.Elapsed}");
 			Console.ReadKey();
 		}

 		internal void RedisExample()
 		{
-			MyCartesian cart = new MyCartesian(5, "abcdefghijklmopqrstuvwxyz");
-
-			Console.WriteLine($"Alphabet = {cart.Alphabet}{Environment.NewLine}" +
-				$"AlphabetPower = {cart.AlphabetPower}{Environment.NewLine}Length = {cart.Length}{Environment.NewLine}" +
-				$"Combination count = {cart.CombinationCount}");
-
-			var table_of_table_of_chars = cart.Generate2();
-			Console.WriteLine("Keys generated");
-			var hasherMD5 = MD5.Create();
-			var hasherSHA256 = SHA256.Create();
-			var stopwatch = new Stopwatch();
-
-			using (var redis = new RedisHasher(GetParamFromCmdSecretOrEnv("Redis")))
-			{
-				redis.EnsureExist();
-				redis.Purge();
-
-				redis.Generate(table_of_table_of_chars, hasherMD5, hasherSHA256,
-					(key, hashMD5, hashSHA256, counter, tps) =>
-					{
-						Console.WriteLine($"MD5({key})={hashMD5},SHA256({key})={hashSHA256},counter={counter},tps={tps}");
-						if (Console.KeyAvailable)
-							return true;
-						return false;
-					}, stopwatch);
-
-				stopwatch.Stop();
-
-				redis.Verify();
-			}
-
-			Console.WriteLine($"Done. Elpased time = {stopwatch.Elapsed}");
+			/*MyCartesian cart = new MyCartesian(5, "abcdefghijklmopqrstuvwxyz");
+
+			Console.WriteLine($"Alphabet = {cart.Alphabet}{Environment.NewLine}" +
+				$"AlphabetPower = {cart.AlphabetPower}{Environment.NewLine}Length = {cart.Length}{Environment.NewLine}" +
+				$"Combination count = {cart.CombinationCount}");
+
+			var table_of_table_of_chars = cart.Generate2();
+			Console.WriteLine("Keys generated");
+			var hasherMD5 = MD5.Create();
+			var hasherSHA256 = SHA256.Create();
+			var stopwatch = new Stopwatch();*/
+
+			using (var dbase = new RedisHasher(GetParamFromCmdSecretOrEnv<string>("Redis")))
+			{
+				dbase.EnsureExist();
+				if (_purge)
+					dbase.Purge();
+
+				dbase.Generate(_tableOfTableOfChars, _hasherMD5, _hasherSHA256,
+					(key, hashMD5, hashSHA256, counter, tps) =>
+					{
+						Console.WriteLine($"MD5({key})={hashMD5},SHA256({key})={hashSHA256},counter={counter},tps={tps}");
+						if (Console.KeyAvailable)
+							return true;
+						return false;
+					}, _stopwatch);
+
+				_stopwatch.Stop();
+
+				dbase.Verify();
+			}
+
+			Console.WriteLine($"Done. Elpased time = {_stopwatch.Elapsed}");
 			Console.ReadKey();
 		}

 		internal void MongoDBExample()
 		{
-			MyCartesian cart = new MyCartesian(5, "abcdefghijklmopqrstuvwxyz");
-
-			Console.WriteLine($"Alphabet = {cart.Alphabet}{Environment.NewLine}" +
-				$"AlphabetPower = {cart.AlphabetPower}{Environment.NewLine}Length = {cart.Length}{Environment.NewLine}" +
-				$"Combination count = {cart.CombinationCount}");
-
-			var table_of_table_of_chars = cart.Generate2();
-			Console.WriteLine("Keys generated");
-			var hasherMD5 = MD5.Create();
-			var hasherSHA256 = SHA256.Create();
-			var stopwatch = new Stopwatch();
-
-			using (var dbase = new MongoDBHasher(GetParamFromCmdSecretOrEnv("MongoDB")))
-			{
-				dbase.EnsureExist();
-				//dbase.Purge();
-
-				dbase.Generate(table_of_table_of_chars, hasherMD5, hasherSHA256,
-					(key, hashMD5, hashSHA256, counter, tps) =>
-					{
-						Console.WriteLine($"MD5({key})={hashMD5},SHA256({key})={hashSHA256},counter={counter},tps={tps}");
-						if (Console.KeyAvailable)
-							return true;
-						return false;
-					}, stopwatch);
-
-				stopwatch.Stop();
-
-				dbase.Verify();
-			}
-
-			Console.WriteLine($"Done. Elpased time = {stopwatch.Elapsed}");
+			/*MyCartesian cart = new MyCartesian(5, "abcdefghijklmopqrstuvwxyz");
+
+			Console.WriteLine($"Alphabet = {cart.Alphabet}{Environment.NewLine}" +
+				$"AlphabetPower = {cart.AlphabetPower}{Environment.NewLine}Length = {cart.Length}{Environment.NewLine}" +
+				$"Combination count = {cart.CombinationCount}");
+
+			var table_of_table_of_chars = cart.Generate2();
+			Console.WriteLine("Keys generated");
+			var hasherMD5 = MD5.Create();
+			var hasherSHA256 = SHA256.Create();
+			var stopwatch = new Stopwatch();*/
+
+			using (var dbase = new MongoDBHasher(GetParamFromCmdSecretOrEnv<string>("MongoDB")))
+			{
+				dbase.EnsureExist();
+				if (_purge)
+					dbase.Purge();
+
+				dbase.Generate(_tableOfTableOfChars, _hasherMD5, _hasherSHA256,
+					(key, hashMD5, hashSHA256, counter, tps) =>
+					{
+						Console.WriteLine($"MD5({key})={hashMD5},SHA256({key})={hashSHA256},counter={counter},tps={tps}");
+						if (Console.KeyAvailable)
+							return true;
+						return false;
+					}, _stopwatch);
+
+				_stopwatch.Stop();
+
+				dbase.Verify();
+			}
+
+			Console.WriteLine($"Done. Elpased time = {_stopwatch.Elapsed}");
 			Console.ReadKey();
 		}

 		internal void CassandraExample()
 		{
-			MyCartesian cart = new MyCartesian(3, "abcdefghijklmopqrstuvwxyz");
-
-			Console.WriteLine($"Alphabet = {cart.Alphabet}{Environment.NewLine}" +
-				$"AlphabetPower = {cart.AlphabetPower}{Environment.NewLine}Length = {cart.Length}{Environment.NewLine}" +
-				$"Combination count = {cart.CombinationCount}");
-
-			var table_of_table_of_chars = cart.Generate2();
-			Console.WriteLine("Keys generated");
-			var hasherMD5 = MD5.Create();
-			var hasherSHA256 = SHA256.Create();
-			var stopwatch = new Stopwatch();
-
-			using (var dbase = new CassandraDBHasher(GetParamFromCmdSecretOrEnv("Cassandra")))
-			{
-				dbase.EnsureExist();
-				//dbase.Purge();
-
-				dbase.Generate(table_of_table_of_chars, hasherMD5, hasherSHA256,
-					(key, hashMD5, hashSHA256, counter, tps) =>
-					{
-						Console.WriteLine($"MD5({key})={hashMD5},SHA256({key})={hashSHA256},counter={counter},tps={tps}");
-						if (Console.KeyAvailable)
-							return true;
-						return false;
-					}, stopwatch);
-
-				stopwatch.Stop();
-
-				dbase.Verify();
-			}
-
-			Console.WriteLine($"Done. Elpased time = {stopwatch.Elapsed}");
+			/*MyCartesian cart = new MyCartesian(5, "abcdefghijklmopqrstuvwxyz");
+
+			Console.WriteLine($"Alphabet = {cart.Alphabet}{Environment.NewLine}" +
+				$"AlphabetPower = {cart.AlphabetPower}{Environment.NewLine}Length = {cart.Length}{Environment.NewLine}" +
+				$"Combination count = {cart.CombinationCount}");
+
+			var table_of_table_of_chars = cart.Generate2();
+			Console.WriteLine("Keys generated");
+			var hasherMD5 = MD5.Create();
+			var hasherSHA256 = SHA256.Create();
+			var stopwatch = new Stopwatch();*/
+
+			using (var dbase = new CassandraDBHasher(GetParamFromCmdSecretOrEnv<string>("Cassandra")))
+			{
+				dbase.EnsureExist();
+				if (_purge)
+					dbase.Purge();
+
+				dbase.Generate(_tableOfTableOfChars, _hasherMD5, _hasherSHA256,
+					(key, hashMD5, hashSHA256, counter, tps) =>
+					{
+						Console.WriteLine($"MD5({key})={hashMD5},SHA256({key})={hashSHA256},counter={counter},tps={tps}");
+						if (Console.KeyAvailable)
+							return true;
+						return false;
+					}, _stopwatch);
+
+				_stopwatch.Stop();
+
+				dbase.Verify();
+			}
+
+			Console.WriteLine($"Done. Elpased time = {_stopwatch.Elapsed}");
 			Console.ReadKey();
 		}

 		internal void MySqlExample()
 		{
-			MyCartesian cart = new MyCartesian(5, "abcdefghijklmopqrstuvwxyz");
-
-			Console.WriteLine($"Alphabet = {cart.Alphabet}{Environment.NewLine}" +
-				$"AlphabetPower = {cart.AlphabetPower}{Environment.NewLine}Length = {cart.Length}{Environment.NewLine}" +
-				$"Combination count = {cart.CombinationCount}");
-
-			var table_of_table_of_chars = cart.Generate2();
-			Console.WriteLine("Keys generated");
-			var hasherMD5 = MD5.Create();
-			var hasherSHA256 = SHA256.Create();
-			var stopwatch = new Stopwatch();
-
-			using (var dbase = new MySqlDatabaseHasher(GetParamFromCmdSecretOrEnv("MySQL")))
-			{
-				dbase.EnsureExist();
-				//dbase.Purge();
-
-				dbase.Generate(table_of_table_of_chars, hasherMD5, hasherSHA256,
-					(key, hashMD5, hashSHA256, counter, tps) =>
-					{
-						Console.WriteLine($"MD5({key})={hashMD5},SHA256({key})={hashSHA256},counter={counter},tps={tps}");
-						if (Console.KeyAvailable)
-							return true;
-						return false;
-					}, stopwatch);
-
-				stopwatch.Stop();
-
-				dbase.Verify();
-			}
-
-			Console.WriteLine($"Done. Elpased time = {stopwatch.Elapsed}");
+			/*MyCartesian cart = new MyCartesian(5, "abcdefghijklmopqrstuvwxyz");
+
+			Console.WriteLine($"Alphabet = {cart.Alphabet}{Environment.NewLine}" +
+				$"AlphabetPower = {cart.AlphabetPower}{Environment.NewLine}Length = {cart.Length}{Environment.NewLine}" +
+				$"Combination count = {cart.CombinationCount}");
+
+			var table_of_table_of_chars = cart.Generate2();
+			Console.WriteLine("Keys generated");
+			var hasherMD5 = MD5.Create();
+			var hasherSHA256 = SHA256.Create();
+			var stopwatch = new Stopwatch();*/
+
+			using (var dbase = new MySqlDatabaseHasher(GetParamFromCmdSecretOrEnv<string>("MySQL")))
+			{
+				dbase.EnsureExist();
+				if (_purge)
+					dbase.Purge();
+
+				dbase.Generate(_tableOfTableOfChars, _hasherMD5, _hasherSHA256,
+					(key, hashMD5, hashSHA256, counter, tps) =>
+					{
+						Console.WriteLine($"MD5({key})={hashMD5},SHA256({key})={hashSHA256},counter={counter},tps={tps}");
+						if (Console.KeyAvailable)
+							return true;
+						return false;
+					}, _stopwatch);
+
+				_stopwatch.Stop();
+
+				dbase.Verify();
+			}
+
+			Console.WriteLine($"Done. Elpased time = {_stopwatch.Elapsed}");
 			Console.ReadKey();
 		}

 		internal void Exeute()
 		{
-			var db_kind = GetParamFromCmdSecretOrEnv("DBKind");
+			var db_kind = GetParamFromCmdSecretOrEnv<string>("DBKind");
+			var alphabet = GetParamFromCmdSecretOrEnv<string>("alphabet") ?? "abcdefghijklmopqrstuvwxyz";
+			var length = GetParamFromCmdSecretOrEnv<int?>("length") ?? 3;
+			_purge = GetParamFromCmdSecretOrEnv<bool?>("purge") ?? false;
+
+			MyCartesian cart = new MyCartesian(/*5*/length, /*"abcdefghijklmopqrstuvwxyz"*/alphabet);
+
+			Console.WriteLine($"Alphabet = {cart.Alphabet}{Environment.NewLine}" +
+				$"AlphabetPower = {cart.AlphabetPower}{Environment.NewLine}Length = {cart.Length}{Environment.NewLine}" +
+				$"Combination count = {cart.CombinationCount}");
+
+			_tableOfTableOfChars = cart.Generate2();
+			Console.WriteLine("Keys generated");
+			_hasherMD5 = MD5.Create();
+			_hasherSHA256 = SHA256.Create();
+			_stopwatch = new Stopwatch();
+
+

 			switch (db_kind?.Trim()?.ToLower())
 			{
@@ -267,6 +277,7 @@
 					break;

 				case "cassandra":
+				case "casandra":
 				case "cassandradb":
 					CassandraExample();
 					break;


classic search engine test

classic search engine test

--- Test/ClassicSearchEngineTest.cs
+++ Test/ClassicSearchEngineTest.cs
@@ -45,11 +45,11 @@
 		{
 			public TestDataFile()
 			{
-				var mz1 = new double { 50, 60, 70, 80, 90, 100 };
-				var intensities1 = new double { 1, 1, 1, 1, 1, 1 };
-
-				var mz2 = new double { 50, 60, 70, 147.076418656749, 200, 300 };
-				var intensities2 = new double{ 1, 1, 1, 1, 1, 1 };
+				var mz1 = new double []{ 50, 60, 70, 80, 90, 100 };
+				var intensities1 = new double []{ 1, 1, 1, 1, 1, 1 };
+
+				var mz2 = new double []{ 50, 60, 70, 147.076418656749, 200, 300 };
+				var intensities2 = new double[]{ 1, 1, 1, 1, 1, 1 };

 				var MassSpectrum1 = new DefaultMzSpectrum(mz1, intensities1, false);
 				var MassSpectrum2 = new DefaultMzSpectrum(mz2, intensities2, false);


Fixed a bug when cancelling a disposed cts throw an unrecoverable exception.

--- src/Lime.Protocol/Client/OnDemandClientChannel.cs
+++ src/Lime.Protocol/Client/OnDemandClientChannel.cs
@@ -333,8 +333,16 @@
                     clientChannel = _clientChannel;
                     if (ShouldCreateChannel(clientChannel))
                     {
-                        _cts?.Cancel();
-                        _cts?.Dispose();
+                        try
+                        {
+                            _cts?.Cancel();
+                            _cts?.Dispose();
+                        }
+                        catch { }
+                        finally
+                        {
+                            _cts = null;
+                        }

                         clientChannel = _clientChannel = await _builder
                             .BuildAndEstablishAsync(cancellationToken)


Added code to help me catch more station messages.

--- src/Neptunium/Fragments/NowPlayingViewFragment.cs
+++ src/Neptunium/Fragments/NowPlayingViewFragment.cs
@@ -26,6 +26,7 @@
 using Windows.Storage.Streams;
 using Crystal3.UI.Commands;
 using Windows.System;
+using System.Diagnostics;

 namespace Neptunium.Fragments
 {
@@ -217,6 +218,16 @@
         {
             if (StationMediaPlayer.CurrentStation.StationMessages.Contains(e.Title)) return; //ignore that pre-defined station message that happens every so often.

+            if (!string.IsNullOrWhiteSpace(e.Title) && string.IsNullOrWhiteSpace(e.Artist))
+            {
+                //station message got through.
+
+#if DEBUG
+                if (Debugger.IsAttached)
+                    Debugger.Break();
+#endif
+            }
+
             await App.Dispatcher.RunWhenIdleAsync(() =>
             {
                 SongMetadata = e.Title + " by " + e.Artist;


#1726 Xaml binding error in variable explorer

--- src/Package/Impl/DataInspect/VariableViewModel.cs
+++ src/Package/Impl/DataInspect/VariableViewModel.cs
@@ -59,7 +59,7 @@
             CanShowOpenCsv = CanShowDetail && (_detailsViewer.Capabilities & tableCaps) != 0 && result.Length > 0;
             if (CanShowOpenCsv) {
                 OpenInCsvAppCommand = new DelegateCommand(OpenInCsvApp, o => CanShowOpenCsv);
-                OpenCsvAppCommandTooltip = Resources.OpenCsvAppCommandTooltip;
+                OpenInCsvAppCommandTooltip = Resources.OpenCsvAppCommandTooltip;
             }
         }

@@ -140,7 +140,7 @@
         public bool CanShowOpenCsv { get; private set; }

         public ICommand OpenInCsvAppCommand { get; private set; }
-        public string OpenCsvAppCommandTooltip { get; private set; }
+        public string OpenInCsvAppCommandTooltip { get; private set; }

         private void OpenInCsvApp(object parameter) {
             CsvAppFileIO.OpenDataCsvApp(DebugEvaluation).DoNotWait();


$_SERVER "HTTPS" set to "on" instead of TRUE

--- src/Peachpie.AspNetCore.Web/RequestContextCore.cs
+++ src/Peachpie.AspNetCore.Web/RequestContextCore.cs
@@ -332,7 +332,7 @@
             _encoding = encoding;

             httpcontext.Items[HttpContextItemKey] = this;
-
+
             // enable synchronous IO until we make everything async
             // https://github.com/aspnet/Announcements/issues/342
             var bodyControl = httpcontext.Features.Get<IHttpBodyControlFeature>();
@@ -459,7 +459,11 @@
             }
             array[CommonPhpArrayKeys.REQUEST_TIME_FLOAT] = (PhpValue)DateTimeUtils.UtcToUnixTimeStampFloat(DateTime.UtcNow);
             array[CommonPhpArrayKeys.REQUEST_TIME] = (PhpValue)DateTimeUtils.UtcToUnixTimeStamp(DateTime.UtcNow);
-            array[CommonPhpArrayKeys.HTTPS] = string.Equals(request.Scheme, "https", StringComparison.OrdinalIgnoreCase);
+
+            if (string.Equals(request.Scheme, "https", StringComparison.OrdinalIgnoreCase))
+            {
+                array[CommonPhpArrayKeys.HTTPS] = "on";
+            }

             //
             return array;


PP9-4517: fix retry delay calculation

PP9-4517: fix retry delay calculation

--- src/Picturepark.SDK.V1/PictureparkRetryHandler.cs
+++ src/Picturepark.SDK.V1/PictureparkRetryHandler.cs
@@ -28,10 +28,10 @@
                 }

                 var delay = TimeSpan.FromSeconds(Math.Pow(2, i));
-                if (int.TryParse(msg.ReasonPhrase, out int waitSeconds))
-                {
-                    delay = delay.Add(TimeSpan.FromSeconds(waitSeconds));
-                }
+                if (msg.Headers.RetryAfter.Delta != null)
+                    delay = delay.Add(msg.Headers.RetryAfter.Delta.Value);
+                else if (msg.Headers.RetryAfter.Date != null)
+                    delay = msg.Headers.RetryAfter.Date.Value - DateTime.Now;

                 await Task.Delay(delay, cancellationToken).ConfigureAwait(false);
             }


fix issue with empty database.

fix issue with empty database.

--- src/RavenDbTalk.Web/Controllers/HomeController.cs
+++ src/RavenDbTalk.Web/Controllers/HomeController.cs
@@ -37,7 +37,7 @@
             Db.Advanced.Eagerly.ExecuteAllPendingLazyOperations();

             model.RandomAuthors = authors.Value.ToList();
-            model.RandomQuote = quote.Value.FirstOrDefault();
+            model.RandomQuote = quote.Value.FirstOrDefault() ?? new Quote();
             model.RandomCategories = categories.Value.ToList();

             return View(model);


Delete with already serialized body

Delete with already serialized body

--- src/RiskFirst.RestClient/RestRequestExtensions.cs
+++ src/RiskFirst.RestClient/RestRequestExtensions.cs
@@ -230,5 +230,23 @@
             }
         }

+        /// <summary>
+        ///     Execute a delete request from the specified rest client
+        /// </summary>
+        /// <param name="request">The rest request</param>
+        /// <returns>HttpResponseMessage</returns>
+        public static async Task<HttpResponseMessage> DeleteAsync(this RestRequest request, HttpContent content, HttpClient httpClient = null, CancellationToken cancellationToken = default(CancellationToken))
+        {
+            try
+            {
+                var requestMessage = request.CreateRequestMessage(HttpMethod.Delete, content);
+                var client = httpClient ?? DefaultHttpClient;
+                return await client.SendAsync(requestMessage, HttpCompletionOption.ResponseContentRead, cancellationToken);
+            }
+            catch (Exception ex)
+            {
+                throw new RestClientException($"Failed to execute delete request to {request.Uri.AbsoluteUri}", ex);
+            }
+        }
     }
 }


Add api/GetAllProductsAge endpoint

Add api/GetAllProductsAge endpoint

--- RohlikAPIWeb/Controllers/RohlikController.cs
+++ RohlikAPIWeb/Controllers/RohlikController.cs
@@ -1,4 +1,5 @@
-using System.Configuration;
+using System;
+using System.Configuration;
 using System.Net;
 using System.Threading.Tasks;
 using System.Web.Http;
@@ -22,6 +23,16 @@
         }

         [HttpGet]
+        [Route("api/GetAllProductsAge")]
+        public int GetProductsAgeHours()
+        {
+            var lastSyncTime = Cache.GetAllProducts().SyncTime;
+            TimeSpan diff = DateTime.UtcNow - lastSyncTime;
+            var hours = (int) diff.TotalHours;
+            return hours;
+        }
+
+        [HttpGet]
         [Route("api/UpdateProducts")]
         public IHttpActionResult UpdateProducts(string key)
         {


ActorFetcher fully tested

ActorFetcher fully tested

--- test/TrackTV.DataRetrieval.Tests/ActorFetcherTest.cs
+++ test/TrackTV.DataRetrieval.Tests/ActorFetcherTest.cs
@@ -3,7 +3,6 @@
     using System;
     using System.Collections.Generic;
     using System.Linq;
-    using System.Linq.Expressions;
     using System.Threading.Tasks;

     using NSubstitute;
@@ -12,6 +11,7 @@
     using TrackTV.DataRetrieval.Fetchers;

     using TrackTv.Models;
+    using TrackTv.Models.Joint;

     using TvDbSharper.BaseSchemas;
     using TvDbSharper.Clients.Series;
@@ -28,6 +28,123 @@

         // ReSharper disable once InconsistentNaming
         public async Task PopulateActorsAsync_should_add_existing_actors()
+        {
+            var repository = Substitute.For<IActorsRepository>();
+            var client = Substitute.For<ISeriesClient>();
+
+            var response = new TvDbResponse<ActorData[]>();
+
+            var data = new List<ActorData>();
+
+            for (int i = 0; i < 5; i++)
+            {
+                data.Add(new ActorData
+                {
+                    Id = i,
+                    Name = $"Actor {i}",
+                    LastUpdated = $"0001-02-0{i + 1}",
+                    Image = $"Image {i}"
+                });
+            }
+
+            response.Data = data.ToArray();
+
+            var show = new Show
+            {
+                TheTvDbId = 42
+            };
+
+            var actors = response.Data.Select(x => new Actor
+                                 {
+                                     TheTvDbId = x.Id
+                                 }).ToArray();
+
+            RigRepository(repository, actors);
+            RigClient(client, show.TheTvDbId, response);
+
+            var fetcher = new ActorFetcher(repository, client);
+
+            await fetcher.PopulateActorsAsync(show);
+
+            var relationships = show.ShowsActors.ToArray();
+
+            Assert.Equal(response.Data.Length, relationships.Length);
+
+            for (int i = 0; i < response.Data.Length; i++)
+            {
+                Assert.Equal(actors[i], relationships[i].Actor);
+                Assert.Equal(response.Data[i].Role, relationships[i].Role);
+
+                Assert.Equal(response.Data[i].Id, actors[i].TheTvDbId);
+                Assert.Equal(response.Data[i].Name, actors[i].Name);
+                Assert.Equal(response.Data[i].Image, actors[i].Image);
+                Assert.Equal(response.Data[i].LastUpdated, actors[i].LastUpdated.ToString("yyyy-MM-dd"));
+            }
+        }
+
+        [Fact]
+
+        // ReSharper disable once InconsistentNaming
+        public async Task PopulateActorsAsync_should_add_existing_and_new_actors()
+        {
+            var repository = Substitute.For<IActorsRepository>();
+            var client = Substitute.For<ISeriesClient>();
+
+            var response = new TvDbResponse<ActorData[]>();
+
+            var data = new List<ActorData>();
+
+            for (int i = 0; i < 5; i++)
+            {
+                data.Add(new ActorData
+                {
+                    Id = i,
+                    Name = $"Actor {i}",
+                    LastUpdated = $"0001-01-0{i + 1}",
+                    Image = $"Image {i}",
+                    Role = $"Role {i}"
+                });
+            }
+
+            response.Data = data.ToArray();
+
+            var show = new Show
+            {
+                TheTvDbId = 42
+            };
+
+            var actors = response.Data.Take(2).Select(x => new Actor
+                                 {
+                                     TheTvDbId = x.Id
+                                 }).ToArray();
+
+            RigRepository(repository, actors);
+            RigClient(client, show.TheTvDbId, response);
+
+            var fetcher = new ActorFetcher(repository, client);
+
+            await fetcher.PopulateActorsAsync(show);
+
+            var relationships = show.ShowsActors.ToArray();
+
+            Assert.Equal(response.Data.Length, relationships.Length);
+
+            Assert.Equal(actors[0], relationships[0].Actor);
+            Assert.Equal(actors[1], relationships[1].Actor);
+            Assert.Equal(response.Data[2].Id, relationships[2].Actor.TheTvDbId);
+            Assert.Equal(response.Data[3].Id, relationships[3].Actor.TheTvDbId);
+            Assert.Equal(response.Data[4].Id, relationships[4].Actor.TheTvDbId);
+
+            for (int i = 0; i < response.Data.Length; i++)
+            {
+                Assert.Equal(response.Data[i].Role, relationships[i].Role);
+            }
+        }
+
+        [Fact]
+
+        // ReSharper disable once InconsistentNaming
+        public async Task PopulateActorsAsync_should_add_new_actors()
         {
             var repository = Substitute.For<IActorsRepository>();
             var client = Substitute.For<ISeriesClient>();
@@ -54,58 +171,6 @@
                 TheTvDbId = 42
             };

-            var actors = response.Data.Select(x => new Actor
-                                 {
-                                     TheTvDbId = x.Id
-                                 }).ToArray();
-
-            RigRepository(repository, actors);
-            RigClient(client, show.TheTvDbId, response);
-
-            var fetcher = new ActorFetcher(repository, client);
-
-            await fetcher.PopulateActorsAsync(show);
-
-            var relationships = show.ShowsActors.ToArray();
-
-            Assert.Equal(response.Data.Length, relationships.Length);
-
-            for (int i = 0; i < response.Data.Length; i++)
-            {
-                Assert.Equal(actors[i], relationships[i].Actor);
-            }
-        }
-
-        [Fact]
-
-        // ReSharper disable once InconsistentNaming
-        public async Task PopulateActorsAsync_should_add_new_actors()
-        {
-            var repository = Substitute.For<IActorsRepository>();
-            var client = Substitute.For<ISeriesClient>();
-
-            var response = new TvDbResponse<ActorData[]>();
-
-            var data = new List<ActorData>();
-
-            for (int i = 0; i < 5; i++)
-            {
-                data.Add(new ActorData
-                {
-                    Id = i,
-                    Name = $"Actor {i}",
-                    LastUpdated = $"0001-01-0{i + 1}",
-                    Image = $"Image {i}"
-                });
-            }
-
-            response.Data = data.ToArray();
-
-            var show = new Show
-            {
-                TheTvDbId = 42
-            };
-
             RigRepository(repository, Array.Empty<Actor>());
             RigClient(client, show.TheTvDbId, response);

@@ -176,7 +241,7 @@
             var fetcher = new ActorFetcher(repository, client);
             await fetcher.PopulateActorsAsync(show);

-            await AssertClientCalledAsync(client, show.TheTvDbId);
+            await client.Received().GetActorsAsync(show.TheTvDbId);
         }

         [Fact]
@@ -229,19 +294,61 @@
             var fetcher = new ActorFetcher(repository, client);
             await fetcher.PopulateActorsAsync(show);

-            await AssertRepositoryCalledAsync(repository, expectedIds);
-        }
-
-        private static async Task AssertClientCalledAsync(ISeriesClient client, int theTvDbId)
-        {
-            await client.Received().GetActorsAsync(theTvDbId);
-        }
-
-        private static async Task AssertRepositoryCalledAsync(IActorsRepository repository, int[] expectedIds)
-        {
-            Expression<Predicate<int[]>> allInIds = x => x.All(expectedIds.Contains);
-
-            await repository.Received().GetActorsByTheTvDbIdsAsync(Arg.Is(allInIds));
+            await repository.Received().GetActorsByTheTvDbIdsAsync(Arg.Is<int[]>(x => x.All(expectedIds.Contains)));
+        }
+
+        [Fact]
+
+        // ReSharper disable once InconsistentNaming
+        public async Task PopulateActorsAsync_should_update_role_on_existing_actor()
+        {
+            var repository = Substitute.For<IActorsRepository>();
+            var client = Substitute.For<ISeriesClient>();
+
+            var response = new TvDbResponse<ActorData[]>
+            {
+                Data = new[]
+                {
+                    new ActorData
+                    {
+                        Id = 1,
+                        Name = "Actor 1",
+                        LastUpdated = "0001-02-01",
+                        Image = "Image 1",
+                        Role = "Role 1"
+                    }
+                }
+            };
+
+            var actor = new Actor
+            {
+                TheTvDbId = 1
+            };
+
+            var show = new Show
+            {
+                TheTvDbId = 42,
+                ShowsActors = {
+                    new ShowsActors
+                    {
+                        Actor = actor
+                    }
+                }
+            };
+
+            var actors = new List<Actor>
+            {
+                actor
+            };
+
+            RigRepository(repository, actors.ToArray());
+            RigClient(client, show.TheTvDbId, response);
+
+            var fetcher = new ActorFetcher(repository, client);
+
+            await fetcher.PopulateActorsAsync(show);
+
+            Assert.Equal(response.Data.First().Role, show.ShowsActors.First().Role);
         }

         private static void RigClient(ISeriesClient client, int theTvDbId, TvDbResponse<ActorData[]> actorResponse)
@@ -251,9 +358,7 @@

         private static void RigRepository(IActorsRepository repository, Actor[] actors, int[] expectedIds)
         {
-            Expression<Predicate<int[]>> allInIds = x => x.All(expectedIds.Contains);
-
-            repository.GetActorsByTheTvDbIdsAsync(Arg.Is(allInIds)).Returns(actors);
+            repository.GetActorsByTheTvDbIdsAsync(Arg.Is<int[]>(x => x.All(expectedIds.Contains))).Returns(actors);
         }

         private static void RigRepository(IActorsRepository repository, Actor[] actors)