private async Task VerifyExpectedLeafUrlAsync(CatalogEntry entry, CatalogLeafEntity leafEntity)
        {
            var entryUrl       = entry.Uri.OriginalString;
            var catalogBaseUrl = await GetCatalogBaseUrlAsync();

            if (!entryUrl.StartsWith(catalogBaseUrl))
            {
                throw new InvalidOperationException("The catalog leaf URL should start with the catalog base URL.");
            }

            var actualPath   = entryUrl.Substring(catalogBaseUrl.Length);
            var expectedPath = string.Join("/", new[]
            {
                "data",
                entry.CommitTimeStamp.ToString("yyyy.MM.dd.HH.mm.ss"),
                $"{Uri.EscapeDataString(entry.Id.ToLowerInvariant())}.{entry.Version.ToNormalizedString().ToLowerInvariant()}.json",
            });

            // This should always be true, but we have an oddball:
            // https://api.nuget.org/v3/catalog0/page848.json
            // https://api.nuget.org/v3/catalog0/data/2015.04.03.23.35.56/xunit.core.2.0.0.json
            // Timestamp is 2015-04-03T23:14:16.0340591Z
            if (actualPath != expectedPath)
            {
                leafEntity.RelativePath = actualPath;
            }
            else
            {
                leafEntity.RelativePath = null;
            }
        }
        private async Task <CatalogPageEntity> InitializeAsync(
            string pageUrl,
            IReadOnlyList <CatalogEntry> leaves,
            IReadOnlyDictionary <string, long> identityToPackageKey)
        {
            await VerifyExpectedPageUrlAsync(pageUrl);

            var pageEntity = new CatalogPageEntity
            {
                Url            = pageUrl,
                CatalogCommits = new List <CatalogCommitEntity>(),
            };

            var commits = leaves
                          .GroupBy(x => x.CommitTimeStamp.ToUniversalTime());

            foreach (var commit in commits)
            {
                var commitLeaves = commit.ToList();

                // This really only every be one, but there is an oddball:
                // https://api.nuget.org/v3/catalog0/page868.json, timestamp: 2015-04-17T23:24:26.0796162Z
                var commitId = string.Join(" ", commit
                                           .Select(x => Guid.Parse(x.CommitId))
                                           .OrderBy(x => x)
                                           .Distinct()
                                           .ToList());

                var commitEntity = new CatalogCommitEntity
                {
                    CatalogPage     = pageEntity,
                    CommitId        = commitId,
                    CommitTimestamp = commit.Key.UtcTicks,
                    CatalogLeaves   = new List <CatalogLeafEntity>(),
                    Count           = commitLeaves.Count,
                };

                pageEntity.CatalogCommits.Add(commitEntity);

                foreach (var leaf in commitLeaves)
                {
                    var identity   = $"{leaf.Id}/{leaf.Version.ToNormalizedString()}";
                    var packageKey = identityToPackageKey[identity];

                    if (leaf.Types.Count != 1)
                    {
                        throw new InvalidOperationException($"Found a catalog leaf with {leaf.Types.Count} types instead of 1.");
                    }

                    CatalogLeafType type;
                    if (leaf.IsAddOrUpdate)
                    {
                        type = CatalogLeafType.PackageDetails;
                    }
                    else if (leaf.IsDelete)
                    {
                        type = CatalogLeafType.PackageDelete;
                    }
                    else
                    {
                        throw new InvalidOperationException("Unexpected catalog leaf type.");
                    }

                    var leafEntity = new CatalogLeafEntity
                    {
                        CatalogCommit = commitEntity,
                        PackageKey    = packageKey,
                        Type          = type,
                    };

                    await VerifyExpectedLeafUrlAsync(leaf, leafEntity);

                    commitEntity.CatalogLeaves.Add(leafEntity);
                }
            }

            return(pageEntity);
        }