private static RepositoryChangeRecord Merge(
            RepositoryChangeRecord earlierRecord,
            RepositoryChangeRecord laterRecord)
        {
            var mergedRecord = new RepositoryChangeRecord
            {
                Next = laterRecord.Next
            };

            // merged.add is ((earlier.add - later.remove) + later.add)
            mergedRecord.Add = earlierRecord.Add
                .Except(laterRecord.Remove)
                .Union(laterRecord.Add)
                .Distinct()
                .ToArray();

            // merged.remove is ((earlier.remove + later.remove) - later.add)
            mergedRecord.Remove = earlierRecord.Remove
                .Union(laterRecord.Remove)
                .Except(laterRecord.Add)
                .Distinct()
                .ToArray();

            return mergedRecord;
        }
        public static RepositoryChangeRecord MergeRepositoryChangeRecordsStartingWithIndex(this IRepositoryPublisher feed, int index)
        {
            RepositoryChangeRecord resultRecord = null;
            var scanIndex = index;

            for (; ;)
            {
                var scanRecord = feed.GetRepositoryChangeRecord(scanIndex);

                if (scanRecord == null)
                {
                    return(resultRecord);
                }

                if (resultRecord == null)
                {
                    resultRecord = scanRecord;
                }
                else
                {
                    resultRecord = Merge(resultRecord, scanRecord);
                }
                scanIndex = resultRecord.Next;
            }
        }
        private static RepositoryChangeRecord Merge(
            RepositoryChangeRecord earlierRecord,
            RepositoryChangeRecord laterRecord)
        {
            var mergedRecord = new RepositoryChangeRecord
            {
                Next = laterRecord.Next
            };

            // merged.add is ((earlier.add - later.remove) + later.add)
            mergedRecord.Add = earlierRecord.Add
                               .Except(laterRecord.Remove)
                               .Union(laterRecord.Add)
                               .Distinct()
                               .ToArray();

            // merged.remove is ((earlier.remove + later.remove) - later.add)
            mergedRecord.Remove = earlierRecord.Remove
                                  .Union(laterRecord.Remove)
                                  .Except(laterRecord.Add)
                                  .Distinct()
                                  .ToArray();

            return(mergedRecord);
        }
        public virtual void StoreRepositoryChangeRecord(int index, RepositoryChangeRecord record)
        {
            var changeRecordPath = GetChangeRecordPath(index);

            StoreFile(
                changeRecordPath,
                record,
                createNew: index != 0);
        }
        public virtual void ApplyFileChanges(RepositoryChangeRecord changeRecord)
        {
            var alterations = changeRecord.Add
                              .Concat(changeRecord.Remove)
                              .Select(FirstTwoParts)
                              .Distinct()
                              .ToLookup(FirstPart);

            foreach (var firstPart in alterations)
            {
                Reports.Information.WriteLine("Working with {0}", firstPart.Key.Bold());

                var nameIndexPath = firstPart + "/$index.json";

                var addVersions    = new List <string>();
                var removeVersions = new List <string>();

                foreach (var firstTwoParts in firstPart)
                {
                    Reports.Information.WriteLine("Working with {0}", firstTwoParts.Bold());

                    var addAssets    = changeRecord.Add.SelectMany(After(firstTwoParts));
                    var removeAssets = changeRecord.Remove.SelectMany(After(firstTwoParts));

                    bool addedAllAssets;
                    bool removedAllAssets;
                    ChangeContents(
                        firstTwoParts + "/$index.json",
                        addAssets,
                        removeAssets,
                        out addedAllAssets,
                        out removedAllAssets);

                    if (addedAllAssets)
                    {
                        addVersions.Add(After(firstPart.Key)(firstTwoParts).Single());
                    }
                    else if (removedAllAssets)
                    {
                        removeVersions.Add(After(firstPart.Key)(firstTwoParts).Single());
                    }
                }

                bool addedAllVersions;
                bool removedAllVersions;
                ChangeContents(
                    firstPart.Key + "/$index.json",
                    addVersions,
                    removeVersions,
                    out addedAllVersions,
                    out removedAllVersions);
            }
        }
        public virtual void ApplyFileChanges(RepositoryChangeRecord changeRecord, IRepositoryPublisher source)
        {
            ApplyFileChanges(changeRecord);

            foreach (var removeFile in changeRecord.Remove)
            {
                RemoveArtifact(removeFile);
            }
            foreach (var addFile in changeRecord.Add)
            {
                using (var inputStream = source.ReadArtifactStream(addFile))
                {
                    WriteArtifactStream(addFile, inputStream, createNew: false);
                }
            }
        }