void SearchThroughBuckets(SuitBuilder builder, int index)
        {
            if (!Running)
            {
                return;
            }

            // Only continue to build any suits with a minimum potential of no less than 1 armor pieces less than our largest built suit so far
            if (builder.Count + 1 < highestArmorCountSuitBuilt - (totalArmorBucketsWithItems - Math.Min(index, totalArmorBucketsWithItems)))
            {
                return;
            }

            // Are we at the end of the line?
            if (buckets.Count <= index)
            {
                if (builder.Count == 0)
                {
                    return;
                }

                lock (lockObject)
                {
                    if (builder.TotalBodyArmorPieces > highestArmorCountSuitBuilt)
                    {
                        highestArmorCountSuitBuilt = builder.TotalBodyArmorPieces;
                    }

                    // We should keep track of the highest AL suits we built for every number of armor count suits built, and only push out ones that fall within our top X
                    List <int> list = highestArmorSuitsBuilt[builder.Count];
                    if (list.Count < list.Capacity)
                    {
                        if (!list.Contains(builder.TotalBaseArmorLevel))
                        {
                            list.Add(builder.TotalBaseArmorLevel);

                            if (list.Count == list.Capacity)
                            {
                                list.Sort();
                            }
                        }
                    }
                    else
                    {
                        if (list[list.Count - 1] > builder.TotalBaseArmorLevel)
                        {
                            return;
                        }

                        if (list[list.Count - 1] < builder.TotalBaseArmorLevel && !list.Contains(builder.TotalBaseArmorLevel))
                        {
                            list[list.Count - 1] = builder.TotalBaseArmorLevel;
                            list.Sort();
                        }
                    }

                    CompletedSuit newSuit = builder.CreateCompletedSuit();

                    // We should also keep track of all the suits we've built and make sure we don't push out a suit with the same exact pieces in swapped slots
                    foreach (CompletedSuit suit in completedSuits)
                    {
                        if (newSuit.IsSubsetOf(suit))
                        {
                            return;
                        }
                    }
                    completedSuits.Add(newSuit);

                    OnSuitCreated(newSuit);
                }

                return;
            }

            if (index == 0)             // If this is the first bucket we're searching through, multi-thread the subsearches
            {
                Parallel.ForEach(buckets[index], piece =>
                {
                    SuitBuilder clone = builder.Clone();

                    if (clone.SlotIsOpen(buckets[index].Slot) && (!piece.EquippableSlots.IsBodyArmor() || clone.HasRoomForArmorSet(Config.PrimaryArmorSet, Config.SecondaryArmorSet, piece.ItemSetId)) && clone.CanGetBeneficialSpellFrom(piece))
                    {
                        clone.Push(piece, buckets[index].Slot);

                        SearchThroughBuckets(clone, index + 1);

                        clone.Pop();
                    }
                });
            }
            else
            {
                foreach (SuitBuildableMyWorldObject piece in buckets[index])
                {
                    if (builder.SlotIsOpen(buckets[index].Slot) && (!piece.EquippableSlots.IsBodyArmor() || builder.HasRoomForArmorSet(Config.PrimaryArmorSet, Config.SecondaryArmorSet, piece.ItemSetId)) && builder.CanGetBeneficialSpellFrom(piece))
                    {
                        builder.Push(piece, buckets[index].Slot);

                        SearchThroughBuckets(builder, index + 1);

                        builder.Pop();
                    }
                }
            }

            SearchThroughBuckets(builder, index + 1);
        }
        void SearchThroughBuckets(List <Bucket> buckets, int index)
        {
            if (!Running)
            {
                return;
            }

            // Only continue to build any suits with a minimum potential of no less than 1 epics less than our largest built suit so far
            if (SuitBuilder.Count + 1 < highestCountSuitBuilt - (highestCountSuitBuilt - index))
            {
                return;
            }

            // Are we at the end of the line?
            if (buckets.Count <= index)
            {
                if (SuitBuilder.Count == 0)
                {
                    return;
                }

                if (SuitBuilder.Count > highestCountSuitBuilt)
                {
                    highestCountSuitBuilt = SuitBuilder.TotalBodyArmorPieces;
                }

                CompletedSuit newSuit = SuitBuilder.CreateCompletedSuit();

                // We should keep track of the highest epic suits we built for every number of item count suits built, and only push out ones that fall within our top X
                List <int> list = highestEffectiveSpellsSuitBuilt[SuitBuilder.Count];
                if (list.Count < list.Capacity)
                {
                    list.Add(newSuit.TotalEffectiveEpics);

                    if (list.Count == list.Capacity)
                    {
                        list.Sort();
                    }
                }
                else
                {
                    if (list[list.Count - 1] >= newSuit.TotalEffectiveEpics)
                    {
                        return;
                    }

                    list[list.Count - 1] = newSuit.TotalEffectiveEpics;
                    list.Sort();
                }

                // We should also keep track of all the suits we've built and make sure we don't push out a suit with the same exact pieces in swapped slots
                foreach (CompletedSuit suit in completedSuits)
                {
                    if (newSuit.IsSubsetOf(suit))
                    {
                        return;
                    }
                }

                completedSuits.Add(newSuit);

                OnSuitCreated(newSuit);

                return;
            }

            //for (int i = 0; i < buckets[index].Count ; i++)
            foreach (var piece in buckets[index])             // Using foreach: 10.85s, for: 11s
            {
                if (SuitBuilder.CanGetBeneficialSpellFrom(piece))
                {
                    SuitBuilder.Push(piece, buckets[index].Slot);

                    SearchThroughBuckets(buckets, index + 1);

                    SuitBuilder.Pop();
                }
            }

            SearchThroughBuckets(buckets, index + 1);
        }