private static IEnumerable<string> TryDeduceMatchingCandidateSnapshot(
            ImageWrapper transformedOriginalSnapshot,
            IEnumerable<string> candidateSnapshots,
            Func<ImageWrapper, Maybe<ImageWrapper>> candidateTranform
            )
        {
            var candidateResultList = new ConcurrentBag<Tuple<string, int>>();
            using (var originaImageAsLockbit = new LockBitImage(transformedOriginalSnapshot.Image))
            {
                Parallel.ForEach(candidateSnapshots, candidateSnapshot =>
                {
                    var candidateComparisonResult = from loadedCandidateSnapshot in TryLoadImage(candidateSnapshot)
                                                    from transformedCandidate in candidateTranform.Invoke(loadedCandidateSnapshot)
                                                    let candidateLockbitImage = new LockBitImage(transformedCandidate.Image)
                                                    let similarityIndex = SimilarityCalculator.CalculateSimilarityIndex(
                                                        originaImageAsLockbit,
                                                        candidateLockbitImage
                                                    )
                                                    select CommonFunctions.ExecThenDispose(
                                                        () => Tuple.Create<string, int>(candidateSnapshot, similarityIndex),
                                                        loadedCandidateSnapshot,
                                                        transformedCandidate,
                                                        candidateLockbitImage
                                                    );
                    candidateComparisonResult.Apply(i => candidateResultList.Add(i));
                });
            }

            return from candidateTuple in candidateResultList
                   where candidateTuple.Item2 >= 69
                   select candidateTuple.Item1;
        }
 private static Maybe<ImageWrapper> TransformCandidateSnapshotForiPhoneSix(ImageWrapper candidateSnapshot)
 {
     return from resizedCandidateSnapshot in ImageTransformations.TryResizeImage(candidateSnapshot.Image, 1334, 750)
            select ImageCropper.TryCropiPhoneSixImage(
                 new ImageWrapper(resizedCandidateSnapshot, candidateSnapshot.ImagePath)
            );
 }
 /// <summary>
 /// Try to crop a snapshot taken from an iPhone 6
 /// </summary>
 /// <param name="originalImage">The original snapshot from the iPhone 6</param>
 /// <returns>A new image with the top scrubber and bottom controls cropped out</returns>
 public static Maybe<ImageWrapper> TryCropiPhoneSixImage(ImageWrapper originalImage)
 {
     return from croppedImage in ImageTransformations.TryCropImage(
                originalImage.Image,
                IPHONE_6_VIEWPORT_ORIGIN,
                IPHONE_6_VIEWPORT_RECTANGLE
            )
            select new ImageWrapper(croppedImage, originalImage.ImagePath);
 }
        private static IEnumerable<string> TryProcessSnapshotFromiPhoneSix(
            ImageWrapper originalSnapshot,
            IEnumerable<string> candidateSnapshots
            )
        {
            if (Predicates.IsiPhoneSixSize(originalSnapshot.Image) == false)
            {
                return Enumerable.Empty<string>();
            }

            Maybe<IEnumerable<string>> deducedSnapshots = from croppedOriginalSnapshot in ImageCropper.TryCropiPhoneSixImage(originalSnapshot)
                                                          select CommonFunctions.ExecThenDispose(
                                                                   () => TryDeduceMatchingCandidateSnapshot(
                                                                       croppedOriginalSnapshot,
                                                                       candidateSnapshots,
                                                                       TransformCandidateSnapshotForiPhoneSix
                                                                   ),
                                                                   croppedOriginalSnapshot
                                                          );

            return deducedSnapshots.OrElse(Enumerable.Empty<string>());
        }
        private static IEnumerable<string> TryProcessSnapshotFromiPad(
            ImageWrapper originalSnapshot,
            IEnumerable<string> candidateSnapshots
            )
        {
            if (Predicates.IsiPadSize(originalSnapshot.Image) == false)
            {
                return Enumerable.Empty<string>();
            }

            var deducedSnapshots = from croppedImage in ImageCropper.TryCropiPadImage(originalSnapshot)
                                   from resizedImage in ImageTransformations.TryResizeImage(croppedImage.Image, 1280, 720)
                                   let transformedOriginalSnapshot = new ImageWrapper(resizedImage, originalSnapshot.ImagePath)
                                   select CommonFunctions.ExecThenDispose(
                                        () => TryDeduceMatchingCandidateSnapshot(transformedOriginalSnapshot, candidateSnapshots, i => i.ToMaybe()),
                                        croppedImage,
                                        resizedImage
                                   );

            return deducedSnapshots.OrElse(Enumerable.Empty<string>());
        }