Exemplo n.º 1
0
        /// <summary>
        /// Create an OperandKey from an enumerable of Entity Ids
        /// </summary>
        /// <param name="sourceValueIds"></param>
        /// <param name="entType"></param>
        /// <param name="entityId"></param>
        /// <returns></returns>
        public static OperandKey OperandKey(this IEnumerable <Guid> sourceValueIds, EntityType entType, Guid?entityId = null)
        {
            if (!entityId.HasValue || entityId == Guid.Empty)
            {
                entityId = GuidHelpers.NewTimeUuid();
            }

            var opKey = new OperandKey {
                EntType = entType, EntityId = entityId.Value, SourceEntityIds = ImmutableArray.CreateRange(sourceValueIds?.ToArray() ?? new Guid[0])
            };

            return(opKey);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Create an OperandKey from a single Value
        /// </summary>
        /// <param name="value"></param>
        /// <param name="entType"></param>
        /// <param name="entityId"></param>
        /// <returns></returns>
        public static OperandKey OperandKey(this Value value, EntityType entType, Guid?entityId = null)
        {
            if (!entityId.HasValue || entityId == Guid.Empty)
            {
                entityId = GuidHelpers.NewTimeUuid();
            }

            var opKey = new OperandKey {
                EntType = entType, EntityId = entityId.Value, SourceEntityIds = ImmutableArray.Create(value.EntityId)
            };

            return(opKey);
        }
Exemplo n.º 3
0
        /// <summary>
        /// Create an OperandKey for a supplied EntityType and EntityId - this OperandKey will not specify any SourceEntityIds
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="entity"></param>
        /// <returns></returns>
        public static OperandKey OperandKey(this EntityType entType, Guid entityId)
        {
            if (entityId == Guid.Empty || !entType.IsProcessable())
            {
                throw new ArgumentException("The supplied entityId was empty, or the supplied entType was not processable");
            }

            var opKey = new OperandKey {
                EntType = entType, EntityId = entityId, SourceEntityIds = ImmutableArray <Guid> .Empty
            };

            return(opKey);
        }
Exemplo n.º 4
0
        /// <summary>
        /// Create an OperandKey for a supplied Entity - this OperandKey will not specify any SourceEntityIds
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="entity"></param>
        /// <returns></returns>
        public static OperandKey OperandKey <T>(this T entity) where T : IEntity
        {
            if (entity == null || entity.EntityId == Guid.Empty || !entity.IsProcessable())
            {
                throw new ArgumentException("The supplied entity was null, had no Id, or was not processable");
            }

            var opKey = new OperandKey {
                EntType = entity.EntType, EntityId = entity.EntityId, SourceEntityIds = ImmutableArray <Guid> .Empty
            };

            return(opKey);
        }
Exemplo n.º 5
0
        public static T GetEntityFromValue <T>(this ProcessingRulEngStore newState, OperandKey entity) where T : IEntity
        {
            var newEntity  = default(T);
            var refValueId = entity.SourceEntityIds.FirstOrDefault();

            if (refValueId != null)
            {
                newEntity = ((JProperty)newState.Values.FirstOrDefault(v => v.ValueId == refValueId).Detail).ToObject <T>();
            }

            newEntity.EntityId = entity.EntityId;

            return(newEntity);
        }
        protected override void ApplyOperation(CompactFontFormatTopLevelDictionary dictionary, List <Operand> operands, OperandKey key, IReadOnlyList <string> stringIndex)
        {
            switch (key.Byte0)
            {
            case 0:
                dictionary.Version = GetString(operands, stringIndex);
                break;

            case 1:
                dictionary.Notice = GetString(operands, stringIndex);
                break;

            case 2:
                dictionary.FullName = GetString(operands, stringIndex);
                break;

            case 3:
                dictionary.FamilyName = GetString(operands, stringIndex);
                break;

            case 4:
                dictionary.Weight = GetString(operands, stringIndex);
                break;

            case 5:
                dictionary.FontBoundingBox = GetBoundingBox(operands);
                break;

            case 12:
            {
                if (!key.Byte1.HasValue)
                {
                    throw new InvalidOperationException("A single byte sequence beginning with 12 was found.");
                }

                switch (key.Byte1.Value)
                {
                case 0:
                    dictionary.Copyright = GetString(operands, stringIndex);
                    break;

                case 1:
                    dictionary.IsFixedPitch = operands[0].Decimal == 1;
                    break;

                case 2:
                    dictionary.ItalicAngle = operands[0].Decimal;
                    break;

                case 3:
                    dictionary.UnderlinePosition = operands[0].Decimal;
                    break;

                case 4:
                    dictionary.UnderlineThickness = operands[0].Decimal;
                    break;

                case 5:
                    dictionary.PaintType = operands[0].Decimal;
                    break;

                case 6:
                    dictionary.CharStringType = (CompactFontFormatCharStringType)GetIntOrDefault(operands, 2);
                    break;

                case 7:
                {
                    var array = ToArray(operands);

                    if (array.Length != 4)
                    {
                        throw new InvalidOperationException($"Expected four values for the font matrix, instead got: {array}.");
                    }

                    dictionary.FontMatrix = TransformationMatrix.FromArray(array);
                }
                break;

                case 8:
                    dictionary.StrokeWidth = operands[0].Decimal;
                    break;

                case 20:
                    dictionary.SyntheticBaseFontIndex = GetIntOrDefault(operands);
                    break;

                case 21:
                    dictionary.PostScript = GetString(operands, stringIndex);
                    break;

                case 22:
                    dictionary.BaseFontName = GetString(operands, stringIndex);
                    break;

                case 23:
                    dictionary.BaseFontBlend = ReadDeltaToArray(operands);
                    break;

                // TODO: CID Font Stuff
                case 30:
                    break;

                case 31:
                    break;

                case 32:
                    break;

                case 33:
                    break;

                case 34:
                    break;

                case 35:
                    break;

                case 36:
                    break;

                case 37:
                    break;

                case 38:
                    break;
                }
            }
            break;

            case 13:
                dictionary.UniqueId = operands.Count > 0 ? operands[0].Decimal : 0;
                break;

            case 14:
                dictionary.Xuid = ToArray(operands);
                break;

            case 15:
                dictionary.CharSetOffset = GetIntOrDefault(operands);
                break;

            case 16:
                dictionary.EncodingOffset = GetIntOrDefault(operands);
                break;

            case 17:
                dictionary.CharStringsOffset = GetIntOrDefault(operands);
                break;

            case 18:
            {
                var size = GetIntOrDefault(operands);
                operands.RemoveAt(0);
                var offset = GetIntOrDefault(operands);
                dictionary.PrivateDictionaryLocation = new CompactFontFormatTopLevelDictionary.SizeAndOffset(size, offset);
            }
            break;
            }
        }
Exemplo n.º 7
0
        protected override void ApplyOperation(CompactFontFormatPrivateDictionary.Builder dictionary, List <Operand> operands, OperandKey operandKey, IReadOnlyList <string> stringIndex)
        {
            switch (operandKey.Byte0)
            {
            case 6:
                dictionary.BlueValues = ReadDeltaToIntArray(operands);
                break;

            case 7:
                dictionary.OtherBlues = ReadDeltaToIntArray(operands);
                break;

            case 8:
                dictionary.FamilyBlues = ReadDeltaToIntArray(operands);
                break;

            case 9:
                dictionary.FamilyOtherBlues = ReadDeltaToIntArray(operands);
                break;

            case 10:
                dictionary.StandardHorizontalWidth = operands[0].Decimal;
                break;

            case 11:
                dictionary.StandardVerticalWidth = operands[0].Decimal;
                break;

            case 12:
            {
                if (!operandKey.Byte1.HasValue)
                {
                    throw new InvalidOperationException("In the CFF private dictionary, got the operation key 12 without a second byte.");
                }

                switch (operandKey.Byte1.Value)
                {
                case 9:
                    dictionary.BlueScale = operands[0].Decimal;
                    break;

                case 10:
                    dictionary.BlueShift = operands[0].Int;
                    break;

                case 11:
                    dictionary.BlueFuzz = operands[0].Int;
                    break;

                case 12:
                    dictionary.StemSnapHorizontalWidths = ReadDeltaToArray(operands);
                    break;

                case 13:
                    dictionary.StemSnapVerticalWidths = ReadDeltaToArray(operands);
                    break;

                case 14:
                    dictionary.ForceBold = operands[0].Decimal == 1;
                    break;

                case 17:
                    dictionary.LanguageGroup = operands[0].Int;
                    break;

                case 18:
                    dictionary.ExpansionFactor = operands[0].Decimal;
                    break;

                case 19:
                    dictionary.InitialRandomSeed = operands[0].Decimal;
                    break;
                }
            }
            break;

            case 19:
                dictionary.LocalSubroutineOffset = GetIntOrDefault(operands, -1);
                break;

            case 20:
                dictionary.DefaultWidthX = operands[0].Decimal;
                break;

            case 21:
                dictionary.NominalWidthX = operands[0].Decimal;
                break;
            }
        }
 protected abstract void ApplyOperation(T dictionary, List <Operand> operands, OperandKey operandKey, string[] stringIndex);
Exemplo n.º 9
0
 protected abstract void ApplyOperation(TBuilder builder, List <Operand> operands, OperandKey operandKey, IReadOnlyList <string> stringIndex);
Exemplo n.º 10
0
        public static void Main()
        {
            Console.WriteLine("Hello Salesman!");

            // Travelling Salesman - Setup
            const int cityCount = 50;

            Console.WriteLine($"Start Setup for {cityCount} cities : {DateTime.UtcNow.ToString("yyyy-MMM-dd HH:mm:ss.ff")}");

            (var rules, var ruleResults, var values, var rulePrescriptions) = BuildTheCities(cityCount);

            // Build a Collection Rule, Result and Prescription for all of the above rules
            (var collectRule, var collectRuleResult, var collectRulePrescription) = ruleResults.And();

            // Add the Collection Rule, Result and Prescription
            rules.Add(collectRule);
            ruleResults.Add(collectRuleResult);
            rulePrescriptions.Add(collectRulePrescription);

            var operations             = new List <Operation>();
            var operationPrescriptions = new List <OperationMxProcessing>();

            var cityValues = values.Where(c => c.Detail["properties"]["cityNo"] != null).ToList();

            (var pointOperations, var pointOperationPrescriptions) = BuildTheGeoJsonOutput(collectRuleResult, cityValues);
            operations.Add(pointOperations);
            operationPrescriptions.Add(pointOperationPrescriptions);

            (var distOperations, var distOperationPrescriptions) = BuildTheCityDistances(collectRuleResult, cityValues);
            operations.AddRange(distOperations);
            operationPrescriptions.AddRange(distOperationPrescriptions);

            // Build the Rule Engine Store ready for processing
            var startingStore = new RulEngStore
            {
                Rules       = rules.ToImmutableHashSet(),
                RuleResults = ruleResults.ToImmutableHashSet(),
                Operations  = operations.ToImmutableHashSet(),
                Values      = values.ToImmutableHashSet()
            };

            RvStore = new Store <RulEngStore>(StoreReducers.ReduceStore, startingStore);
            File.WriteAllText("storeStart.json", RvStore.GetState().ToString());

            // Commence Processing
            RulEngStore changes;

            RvStore.Subscribe(state => changes = state);

            var pass = 0;

            TikTok(pass++, rulePrescriptions, operationPrescriptions);

            Console.WriteLine($"Add more to Store for {cityCount} cities : {DateTime.UtcNow.ToString("yyyy-MMM-dd HH:mm:ss.ff")}");
            // Build the exists rules for the values resulting from the distance operations
            (var distRules, var distRuleResults, var distRulePrescriptions) =
                distOperations.SelectMany(dp => dp.Operands).Exists(false);

            // Build the operations to convert the distance results to roads
            var storeValues = RvStore.GetState().Values.ToList();

            (var roadOperations, var roadOperationPrescriptions) = BuildTheCityRoads(distRules, storeValues);

            // Add the new Entities to the Store ready for processing
            RvStore.AddUpdate(distRules, distRuleResults, roadOperations, null);
            TikTok(pass++, distRulePrescriptions, roadOperationPrescriptions);

            Console.WriteLine($"Add more to Store for {cityCount} cities : {DateTime.UtcNow.ToString("yyyy-MMM-dd HH:mm:ss.ff")}");
            // Build the exists rules for the values resulting from the 'road' operations
            (var roadExistsRules, var roadExistsRuleResults, var roadExistsRulePrescriptions) =
                roadOperations.SelectMany(rp => rp.Operands).Exists(false);
            // TODO: Build operations to mark the roads between CityA and CityB (and vice versa) as 'accepted'
            // Build a Collection Rule, Result and Prescription for all of the 'road' rules
            (var collectRoadRule, var collectRoadRuleResult, var collectRoadRulePrescription) = roadExistsRuleResults.And();
            roadExistsRules.Add(collectRoadRule);
            roadExistsRuleResults.Add(collectRoadRuleResult);
            roadExistsRulePrescriptions.Add(collectRoadRulePrescription);

            // Join the new Roads together in one map
            var roadValues = RvStore.GetState().Values
                             .Where(c => c.Detail != null && c.Detail.Type == JTokenType.Object && c.Detail["properties"]?["roadId"] != null)
                             .ToList();

            (var lineOperation, var lineOperationPrescription) = BuildTheGeoJsonOutput(collectRoadRuleResult, roadValues);

            // Add the new Entities to the Store ready for processing
            RvStore
            .AddUpdate(roadExistsRules, roadExistsRuleResults, new[] { lineOperation }.ToList(), null);

            TikTok(pass++, roadExistsRulePrescriptions, new[] { lineOperationPrescription });

            // Searching or finding entities by arbitrary requirements is not currently supported
            // It could potentially be implemented with:
            // a new Rule (e.g. AnyMatch) that triggers
            // a special Operation (Match -> Generates Exists Rules as simple triggers)
            // regular Operation(s) to process the matching entities

            // So search for duplicate roads (A->B and B->A) by code external to the RuleEngine store
            //(var dupRoadExistsRules, var dupRoadExistsRuleResults, var dupRoadDeleteOperations,
            //        var dupRoadRulePrescriptions, var dupRoadOpPrescriptions) =
            //    DeleteTheDuplicateRoads(roadValues, roadExistsRules);

            //RvStore.AddUpdate(dupRoadExistsRules, dupRoadExistsRuleResults, dupRoadDeleteOperations, null);

            //TikTok(pass++, dupRoadRulePrescriptions, dupRoadOpPrescriptions);

            // Refresh the list of roads
            roadValues = RvStore.GetState().Values
                         .Where(c => c.Detail != null && c.Detail.Type == JTokenType.Object && c.Detail["properties"]?["roadId"] != null)
                         .ToList();
            roadExistsRules = RvStore.GetState().Rules
                              .Where(c => c.RuleType == RuleType.Exists &&
                                     roadValues.Select(v => v.ValueId).Contains(c.ReferenceValues.EntityIds[0].EntityId))
                              .ToList();
            roadExistsRuleResults = RvStore.GetState().RuleResults
                                    .Where(s => roadExistsRules.Select(c => c.RuleId).Contains(s.RuleId))
                                    .ToList();

            // recreate the prescriptions for road rules
            roadExistsRulePrescriptions = new List <IRuleProcessing>();
            foreach (var rv in roadExistsRules)
            {
                roadExistsRulePrescriptions.Add(rv.Exists());
            }
            // Rebuild the Collection Rule, Result and Prescription for all of the 'road' rules
            (collectRoadRule, collectRoadRuleResult, collectRoadRulePrescription) = roadExistsRuleResults.And(collectRoadRule, collectRoadRuleResult);
            roadExistsRules.Add(collectRoadRule);
            roadExistsRuleResults.Add(collectRoadRuleResult);
            roadExistsRulePrescriptions.Add(collectRoadRulePrescription);

            // Join the new Roads together in one map
            (lineOperation, lineOperationPrescription) = BuildTheGeoJsonOutput(collectRoadRuleResult, roadValues, lineOperation);

            // Add the new Entities to the Store ready for processing
            RvStore
            .AddUpdate(roadExistsRules, roadExistsRuleResults, new[] { lineOperation }.ToList(), null);

            TikTok(pass++, roadExistsRulePrescriptions, new[] { lineOperationPrescription });

            // Find the Duplicate roads to be deleted
            // First create a Search Operation to generate Exists Rules and RuleResults
            var opKeyDups = new OperandKey
            {
                EntityId = GuidHelpers.NewTimeUuid(),
                EntTags  = new List <string> {
                    "Duplicates"
                },
                EntType       = EntityType.Rule,
                SourceEntType = EntityType.Value
            };

            // The source data is always presented as a serialised JSON string
            var searchTemplate = "JSON.parse(source)"
                                 // Filter for values with a roadId property
                                 + ".filter(function(s){return s.Detail&&s.Detail.properties&&s.Detail.properties.roadId})"
                                 // Map the results to just the values Id and the roadId (a hash)
                                 + ".map(function(s){return {vId:s.ValueId,rId:s.Detail.properties.roadId};})"
                                 // Reduce to an array grouping by the roadId, the first valueId with that roadId will also be in the structure
                                 + ".reduce(function(a,c){var ix=0;"
                                 + "for(;ix<a.length;ix++){if(a[ix].el.rId===c.rId)break;}"
                                 + "if(ix<a.length){a[ix].t++;}else{a.push({el:c,t:1});}"
                                 + "return a;},[])"
                                 // Filter for roadIds that occur more than once
                                 + ".filter(function(s){return s.t>1})"
                                 // Get the valueId
                                 + ".map(function(s){return s.el.vId})"
                                 // Sort (makes it easier to follow what's going on)
                                 + ".sort(function(a,b){if(a<b)return -1;return(a>b)?1:0;})";

            var opRoadSearch             = collectRuleResult.SearchOperation(new[] { opKeyDups }, GuidHelpers.NewTimeUuid(), searchTemplate);
            var opRoadSearchPrescription = opRoadSearch.Search();

            RvStore.AddUpdate(null, null, opRoadSearch, null);

            TikTok(pass++, null, new[] { opRoadSearchPrescription });

            // Generate Prescriptions for all of the Rules and execute them
            var searchForDupPrescriptions = RvStore.GetState()
                                            .Rules
                                            .Where(r => r.EntTags != null && r.EntTags[0] == "Duplicates")
                                            .Select(r => r.Exists())
                                            .ToList();

            TikTok(pass++, searchForDupPrescriptions, null);

            // Grab one of the Rule Results from above that was successful and use it to trigger the next operation
            var dupRuleResults    = searchForDupPrescriptions.Select(fdp => fdp.Entities.RuleResultId).ToList();
            var dupRoadRuleResult = RvStore.GetState()
                                    .RuleResults
                                    .FirstOrDefault(r => r.EntTags != null && r.EntTags[0] == "Duplicates" && dupRuleResults.Contains(r.RuleResultId) && r.Detail);

            var opKeyDels = new OperandKey
            {
                EntityId = GuidHelpers.NewTimeUuid(),
                EntTags  = new List <string> {
                    "Duplicates"
                },
                EntType       = EntityType.Operation,
                SourceEntType = EntityType.RuleResult
            };

            // The source data is always presented as a serialised JSON string
            var searchDupsTemplate = "JSON.parse(source)"
                                     // Filter for Rule Results with a Duplicates tag
                                     + ".filter(function(s){return s.EntTags&&s.EntTags[0]==='Duplicates'})"
                                     // Map the results to just the ruleresult Id
                                     + ".map(function(s){return s.RuleResultId;})"
                                     // Sort (makes it easier to follow what's going on)
                                     + ".sort(function(a,b){if(a<b)return -1;return(a>b)?1:0;})";

            var opDelRoadSearch = dupRoadRuleResult.SearchOperation(new[] { opKeyDels }, GuidHelpers.NewTimeUuid(), searchDupsTemplate);

            opDelRoadSearch.OperationType = OperationType.Delete;
            var opDelRoadSearchPrescription = opDelRoadSearch.Search();

            RvStore.AddUpdate(null, null, opDelRoadSearch, null);

            TikTok(pass++, null, new[] { opDelRoadSearchPrescription });


            // We'll start by adding all the shortest ones as the first set of 'actual' roads
            // A minimum of two * (cityCount - 1) roads will be required
            ////var roadSet = values
            ////    .Where(r => r.Detail["properties"]["cityAId"] != null && (r.Detail["properties"]["usage"] == null || (string)r.Detail["properties"]["usage"] == "Not Set"))
            ////    .OrderBy(r => (double)r.Detail["properties"]["distance"]);
            ////var cityIds = new List<(Guid cityId, int Count)>();
            ////foreach (var road in roadSet)
            ////{
            ////    var roadGeoJson = (JObject)road.Detail;
            ////    var cityAId = (Guid)roadGeoJson["properties"]["cityAId"];
            ////    var cityBId = (Guid)roadGeoJson["properties"]["cityBId"];

            ////    // Test whether either city at the end of this road already have two roads
            ////    var cityHasRoads = cityIds.Where(ci => ci.cityId == cityAId || ci.cityId == cityBId).ToList();

            ////    var citiesFullyConnected = cityHasRoads.Count(chr => chr.Count >= 2);

            ////    Console.WriteLine($"{cityIds.Count} - {citiesFullyConnected}");

            ////    switch (citiesFullyConnected)
            ////    {
            ////        case 0:
            ////            // Road connects two cities and neither has a full set of connecting roads
            ////            // Do connection
            ////            roadGeoJson["properties"]["usage"] = "Accepted";
            ////            try
            ////            {
            ////                var a = cityIds.First(chr => chr.cityId == cityAId);
            ////                cityIds.Remove(a);
            ////                a.Count++;
            ////                cityIds.Add(a);
            ////            }
            ////            catch
            ////            {
            ////                cityIds.Add((cityAId, 1));
            ////            }
            ////            try
            ////            {
            ////                var b = cityIds.First(chr => chr.cityId == cityBId);
            ////                cityIds.Remove(b);
            ////                b.Count++;
            ////                cityIds.Add(b);
            ////            }
            ////            catch
            ////            {
            ////                cityIds.Add((cityBId, 1));
            ////            }
            ////            break;
            ////        case 1:
            ////            // Road connecting one fully connected city
            ////            if (cityHasRoads.Count == 1)
            ////            {
            ////                // And only one city - so create an empty connection record for the other
            ////                var ci = cityHasRoads.All(chr => chr.cityId == cityAId) ? (cityBId, 0) : (cityAId, 0);
            ////                cityIds.Add(ci);
            ////            }
            ////            break;

            ////        case 2:
            ////        default:
            ////            // Road connecting two already full connected cities
            ////            break;
            ////    }

            ////    if (cityIds.Count >= 10)
            ////    {
            ////        break;
            ////    }
            ////}

            ////var acceptedRoads = values.Where(v =>
            ////    v.Detail["properties"]["cityAId"] != null &&
            ////    v.Detail["properties"]["usage"] != null && (string)v.Detail["properties"]["usage"] == "Accepted")
            ////    .ToList();
            ////var salesmansJourney = new StringBuilder();
            ////salesmansJourney.Append("{\"type\":\"FeatureCollection\",\"features\":[");
            ////salesmansJourney.Append(string.Join(',', acceptedRoads.Select(v => v.Detail.ToString())));
            ////salesmansJourney.Append("]}");
            ////var jny = JObject.Parse(salesmansJourney.ToString());
            ////File.WriteAllText("Routes00.json", jny.ToString());

            //var citiesWithNoRoadsCount = cityIds.Count(ci => ci.Count == 0);

            // For each city with no connections
            // Determine its two closest connected neighbours and reject that road
            // and accept the two roads to and from this city to those two closest neighbours
            ////foreach (var ci in cityIds.Where(ci => ci.Count == 0))
            ////{
            ////    Console.WriteLine($"{ci.cityId}");

            ////    var closestNeighboursWithRoads = values.Where(v =>
            ////        v.Detail["properties"]["cityAId"] != null &&
            ////        ((Guid)v.Detail["properties"]["cityAId"] == ci.cityId || (Guid)v.Detail["properties"]["cityBId"] == ci.cityId) &&
            ////        v.Detail["properties"]["usage"] != null && (string)v.Detail["properties"]["usage"] == "Accepted")
            ////        .OrderBy(r => (double)r.Detail["properties"]["distance"])
            ////        .ToList();

            ////    var closestNeighbourGuids = closestNeighboursWithRoads.SelectMany(ar => new[]
            ////        {(Guid) ar.Detail["properties"]["cityAId"], (Guid) ar.Detail["properties"]["cityBId"]})
            ////        .GroupBy(cg => cg)
            ////        .Select(cg => cg.Key)
            ////        .ToList();

            ////    foreach (var cng in closestNeighbourGuids)
            ////    {
            ////        var notCng = closestNeighbourGuids.Where(cg => cng != cg).ToList();

            ////        var cnwr = closestNeighboursWithRoads.Where(v =>
            ////        v.Detail["properties"]["cityAId"] != null &&
            ////        ((Guid)v.Detail["properties"]["cityAId"] == ci.cityId || (Guid)v.Detail["properties"]["cityBId"] == ci.cityId) &&
            ////        (notCng.Contains((Guid)v.Detail["properties"]["cityAId"]) || notCng.Contains((Guid)v.Detail["properties"]["cityBId"])))
            ////        .ToList();

            ////        if (!cnwr.Any())
            ////        {
            ////            continue;
            ////        }
            ////        // Road to Reject
            ////        var r2R = cnwr.First();
            ////        values.First(r => r.EntityId == r2R.EntityId).Detail["properties"]["usage"] = "Rejected";

            ////        // Rejected road cities
            ////        var cnwor = new[] { (Guid)r2R.Detail["properties"]["cityAId"], (Guid)r2R.Detail["properties"]["cityBId"] };

            ////        // Roads to Accept
            ////        var r2A = closestNeighboursWithRoads.Where(v =>
            ////            v.Detail["properties"]["cityAId"] != null &&
            ////            ((Guid)v.Detail["properties"]["cityAId"] == ci.cityId || (Guid)v.Detail["properties"]["cityBId"] == ci.cityId) &&
            ////            (cnwor.Contains((Guid)v.Detail["properties"]["cityAId"]) || cnwor.Contains((Guid)v.Detail["properties"]["cityBId"])));
            ////        foreach (var rd in r2A)
            ////        {
            ////            values.First(r => r.EntityId == rd.EntityId).Detail["properties"]["usage"] = "Accepted";
            ////        }
            ////        break;
            ////    }
            ////}

            // Now we'll ensure that every city has at least two roads connecting it
            // First step is to group all of the cities and get a count for the number of roads to each one
            //var citiesWithRoads = acceptedRoads
            //    .SelectMany(ar => new[]
            //        {(Guid) ar.Detail["properties"]["cityAId"], (Guid) ar.Detail["properties"]["cityBId"]})
            //    .GroupBy(cg => cg)
            //    .Select(cg => new { cityId = cg.Key, Count = cg.Count() })
            //    .ToList();
            //citiesWithRoadsCount = citiesWithRoads.Count;

            ////        acceptedRoads = values.Where(v =>
            ////v.Detail["properties"]["cityAId"] != null &&
            ////v.Detail["properties"]["usage"] != null && (string)v.Detail["properties"]["usage"] == "Accepted")
            ////.ToList();
            ////        salesmansJourney = new StringBuilder();
            ////        salesmansJourney.Append("{\"type\":\"FeatureCollection\",\"features\":[");
            ////        salesmansJourney.Append(string.Join(',', acceptedRoads.Select(v => v.Detail.ToString())));
            ////        salesmansJourney.Append("]}");
            ////        jny = JObject.Parse(salesmansJourney.ToString());
            ////        File.WriteAllText("Routes01.json", jny.ToString());

            // Then there's a need to check for any cities with no roads at all connected to them (a possibility)
            // and add these to the same list with a count of zero for each one.
            //if (citiesWithRoadsCount < cityCount)
            //{
            //    var citiesWithNoRoads = values.Where(c =>
            //            c.Detail["properties"]["cityNo"] != null &&
            //            !citiesWithRoads.Select(cr => cr.cityId).Contains(c.EntityId))
            //        .Select(cn => new { cityId = cn.EntityId, Count = 0 })
            //        .ToList();

            //    citiesWithNoRoadsCount = citiesWithNoRoads.Count;

            //    citiesWithRoads.AddRange(citiesWithNoRoads);
            //}

            //do
            //{
            //    if (pass > 10)
            //    {
            //        break;
            //    }

            //    // Take this list and add the two closest roads for each city with less than two roads
            //    // and output the result.
            //    foreach (var cwr in citiesWithRoads.Where(cwr => cwr.Count < 2))
            //    {
            //        roadSet = values.Where(v =>
            //                v.Detail["properties"]["cityAId"] != null &&
            //                v.Detail["properties"]["usage"] != null &&
            //                (string) v.Detail["properties"]["usage"] == "Not Set" &&
            //                ((Guid) v.Detail["properties"]["cityAId"] == cwr.cityId ||
            //                 (Guid) v.Detail["properties"]["cityBId"] == cwr.cityId))
            //            .OrderBy(r => (double) r.Detail["properties"]["distance"])
            //            .Take(2 - cwr.Count);

            //        foreach (var road in roadSet)
            //        {
            //            var roadGeoJson = (JObject) road.Detail;

            //            roadGeoJson["properties"]["usage"] = "Accepted";
            //        }
            //    }

            //    acceptedRoads = values.Where(v =>
            //            v.Detail["properties"]["cityAId"] != null &&
            //            v.Detail["properties"]["usage"] != null &&
            //            (string) v.Detail["properties"]["usage"] == "Accepted")
            //        .ToList();
            //    salesmansJourney = new StringBuilder();
            //    salesmansJourney.Append("{\"type\":\"FeatureCollection\",\"features\":[");
            //    salesmansJourney.Append(string.Join(',', acceptedRoads.Select(v => v.Detail.ToString())));
            //    salesmansJourney.Append("]}");
            //    jny = JObject.Parse(salesmansJourney.ToString());
            //    File.WriteAllText($"routes{pass++}.json", jny.ToString());

            //    // Identify cities with too many roads
            //    var citiesWithTooManyRoads = acceptedRoads
            //        .SelectMany(ar => new[]
            //            {(Guid) ar.Detail["properties"]["cityAId"], (Guid) ar.Detail["properties"]["cityBId"]})
            //        .GroupBy(cg => cg)
            //        .Select(cg => new {cityId = cg.Key, Count = cg.Count()})
            //        .Where(cwr => cwr.Count > 2)
            //        .ToList();

            //    foreach (var cwr in citiesWithTooManyRoads)
            //    {
            //        var road = values.Where(v =>
            //                v.Detail["properties"]["cityAId"] != null &&
            //                v.Detail["properties"]["usage"] != null &&
            //                (string) v.Detail["properties"]["usage"] == "Accepted" &&
            //                ((Guid) v.Detail["properties"]["cityAId"] == cwr.cityId ||
            //                 (Guid) v.Detail["properties"]["cityBId"] == cwr.cityId))
            //            .OrderByDescending(r => (double) r.Detail["properties"]["distance"])
            //            .First();
            //            //.Take(cwr.Count - 2);

            //        //foreach (var road in roadSet)
            //        //{
            //            Guid otherCityId;
            //            otherCityId = (Guid) road.Detail["properties"]["cityAId"] == cwr.cityId
            //                ? (Guid) road.Detail["properties"]["cityBId"]
            //                : (Guid) road.Detail["properties"]["cityAId"];
            //            var otherCityHasTooManyRoads = values.Count(v =>
            //                                               v.Detail["properties"]["cityAId"] != null &&
            //                                               v.Detail["properties"]["usage"] != null &&
            //                                               (string) v.Detail["properties"]["usage"] == "Accepted" &&
            //                                               ((Guid) v.Detail["properties"]["cityAId"] == otherCityId ||
            //                                                (Guid) v.Detail["properties"]["cityBId"] == otherCityId)) >
            //                                           2;

            //            if (!otherCityHasTooManyRoads)
            //            {
            //                continue;
            //            }

            //            var roadGeoJson = (JObject) road.Detail;

            //            roadGeoJson["properties"]["usage"] = "Rejected";
            //        //}
            //    }

            //    acceptedRoads = values.Where(v =>
            //            v.Detail["properties"]["cityAId"] != null &&
            //            v.Detail["properties"]["usage"] != null &&
            //            (string) v.Detail["properties"]["usage"] == "Accepted")
            //        .ToList();
            //    salesmansJourney = new StringBuilder();
            //    salesmansJourney.Append("{\"type\":\"FeatureCollection\",\"features\":[");
            //    salesmansJourney.Append(string.Join(',', acceptedRoads.Select(v => v.Detail.ToString())));
            //    salesmansJourney.Append("]}");
            //    jny = JObject.Parse(salesmansJourney.ToString());
            //    File.WriteAllText($"routes{pass++}.json", jny.ToString());

            //    citiesWithRoads = acceptedRoads
            //        .SelectMany(ar => new[]
            //            {(Guid) ar.Detail["properties"]["cityAId"], (Guid) ar.Detail["properties"]["cityBId"]})
            //        .GroupBy(cg => cg)
            //        .Select(cg => new {cityId = cg.Key, Count = cg.Count()})
            //        .ToList();
            //    citiesWithRoadsCount = citiesWithRoads.Count(cwr => cwr.Count >= 2);

            //    // Then there's a need to check for any cities with no roads at all connected to them (a possibility)
            //    // and add these to the same list with a count of zero for each one.
            //    if (citiesWithRoadsCount < cityCount)
            //    {
            //        var citiesWithNoRoads = values.Where(c =>
            //                c.Detail["properties"]["cityNo"] != null &&
            //                !citiesWithRoads.Select(cr => cr.cityId).Contains(c.EntityId))
            //            .Select(cn => new {cityId = cn.EntityId, Count = 0})
            //            .ToList();

            //        citiesWithNoRoadsCount = citiesWithNoRoads.Count;
            //        citiesWithRoads.AddRange(citiesWithNoRoads);
            //    }
            //} while (citiesWithRoadsCount != cityCount || citiesWithNoRoadsCount != 0);
            //values.Add(new Value(jny));

            //var startingStore = new RulEngStore
            //{
            //    Values = values.ToImmutableHashSet()
            //};

            //RvStore = new Store<RulEngStore>(null, startingStore);



            //var requestJObj = JToken.Parse("{\"Q\": \"How can we help?\", \"AA\":[\"New Claim\", \"Existing Claim\"]}");
            //var requestObj = new Value(12);

            //(rule, ruleResult, rulePrescription) = requestObj.Exists();

            //rules.Add(rule);
            //ruleResults.Add(ruleResult);
            //rulePrescriptions.Add(rulePrescription);

            //(operation, operationPrescription) = ruleResult.Create<Value>(requestObj);

            //operations.Add(operation);
            //operationPrescriptions.Add(operationPrescription);
            //values.Add(requestObj);

            //requestObj = new Value(13);
            //(ruleResult, rulePrescription) = requestObj.Exists(rule);
            //ruleResults.Add(ruleResult);

            //(operation, operationPrescription) = ruleResult.Create<Value>(requestObj);

            //operations.Add(operation);
            //operationPrescriptions.Add(operationPrescription);
            //values.Add(requestObj);



            //var valIds = new List<Guid> {values[0].ValueId, values[1].ValueId};
            //(operation, value, operationPrescription) = ruleResult.Create<Value>(new [] { values[0].ValueId }.ToList());
            //operations.Add(operation);
            //values.Add(value);
            //operationPrescriptions.Add(operationPrescription);
            //(operation, value, operationPrescription) = ruleResult.Create<Value>(new[] { values[1].ValueId }.ToList());
            //operations.Add(operation);
            //values.Add(value);
            //operationPrescriptions.Add(operationPrescription);

            ////var procAllRules = new ProcessAllRulesPrescription();
            ////var procAllOperations = new ProcessAllOperationsPrescription();

            //RvStore = new Store<RulEngStore>(StoreReducers.ReduceStore);

            //RulEngStore changes;
            //RvStore.Subscribe(state => changes = state);

            //var act = RvStore.Dispatch(rulePrescription);
            //foreach (var prescription in operationPrescriptions)
            //{
            //    act = RvStore.Dispatch(prescription);
            //}

            //File.WriteAllText("storeBefore.json", RvStore.GetState().ToString());
            //act = rvStore.Dispatch(procAllRules);
            // File.WriteAllText("storeMiddle.json", rvStore.GetState().ToString());
            //act = rvStore.Dispatch(procAllOperations);
            //File.WriteAllText("storeAfter.json", RvStore.GetState().ToString());
            pass++;
        }