public static Errorable<Commit.Builder> FromJSON(this CommitRequest cmj)
        {
            // Do conversions on the strings and detect any errors:
            cmj.parents = cmj.parents ?? new string[0];
            var maybeparentids = cmj.parents.SelectAsArray(s => CommitID.TryParse(s ?? String.Empty));
            var maybetreeid = TreeID.TryParse(cmj.treeid ?? String.Empty);

            // Which ones failed?
            var errors =
                (from m in maybeparentids where m.HasErrors select m.Errors)
                .Concat(from m in new[] { maybetreeid } where m.HasErrors select m.Errors)
                .Aggregate(new ErrorContainer(), (acc, err) => acc + err);

            // Return any errors encountered:
            if (errors.HasAny) return errors;

            Commit.Builder cm = new Commit.Builder(
                pParents:       maybeparentids.SelectAsArray(id => id.Value).ToList(maybeparentids.Length),
                pTreeID:        maybetreeid.Value,
                pCommitter:     cmj.committer ?? String.Empty,
                pDateCommitted: String.IsNullOrWhiteSpace(cmj.date_committed) ? DateTimeOffset.Now : ToDate(cmj.date_committed),
                pMessage:       cmj.message ?? String.Empty
            );
            return cm;
        }
 internal async Task PersistRefTest()
 {
     TreeNode tr = new TreeNode.Builder(new List<TreeTreeReference>(0), new List<TreeBlobReference>(0));
     await trrepo.PersistTree(tr.ID, new IVO.Definition.Containers.ImmutableContainer<TreeID, TreeNode>(trx => trx.ID, tr));
     Commit cm = new Commit.Builder(new List<CommitID>(0), tr.ID, "James S. Dunne", DateTimeOffset.Now, "Initial commit.");
     await cmrepo.PersistCommit(cm);
     Ref rf = new Ref.Builder((RefName)"v1.0", cm.ID);
     await rfrepo.PersistRef(rf);
 }
        internal async Task GetRefByNameTest()
        {
            TreeNode tr = new TreeNode.Builder(new List<TreeTreeReference>(0), new List<TreeBlobReference>(0));
            await trrepo.PersistTree(tr.ID, new IVO.Definition.Containers.ImmutableContainer<TreeID, TreeNode>(trx => trx.ID, tr));
            Commit cm = new Commit.Builder(new List<CommitID>(0), tr.ID, "James S. Dunne", DateTimeOffset.Now, "Initial commit.");
            await cmrepo.PersistCommit(cm);
            Ref rf = new Ref.Builder((RefName)"v1.0", cm.ID);
            await rfrepo.PersistRef(rf);

            var errf = await rfrepo.GetRefByName((RefName)"v1.0");
            Assert.IsFalse(errf.HasErrors);
            Ref rrf = errf.Value;
            Assert.IsNotNull(rrf);
            Assert.AreEqual(rf.Name.ToString(), rrf.Name.ToString());
            Assert.AreEqual(rf.CommitID, rrf.CommitID);
        }
        private async Task<Errorable<Commit>> getCommit(CommitID id)
        {
            FileInfo fi = system.getPathByID(id);
            if (!fi.Exists) return null;

            byte[] buf;
            int nr = 0;
            using (var fs = new FileStream(fi.FullName, FileMode.Open, FileAccess.Read, FileShare.Read, 16384, true))
            {
                // TODO: implement an async buffered Stream:
                buf = new byte[16384];
                nr = await fs.ReadAsync(buf, 0, 16384).ConfigureAwait(continueOnCapturedContext: false);
                if (nr >= 16384)
                {
                    // My, what a large commit you have!
                    throw new NotSupportedException();
                }
            }

            Commit.Builder cb = new Commit.Builder()
            {
                Parents = new List<CommitID>()
            };

            // Parse the Commit:
            using (var ms = new MemoryStream(buf, 0, nr, false))
            using (var sr = new StreamReader(ms, Encoding.UTF8))
            {
                string line;

                // Read the list of parent CommitIDs:
                while ((line = sr.ReadLine()) != null)
                {
                    if (!line.StartsWith("parent ")) break;

                    string parent_commitid = line.Substring("parent ".Length);
                    var ecid = CommitID.TryParse(parent_commitid);
                    if (ecid.HasErrors) return ecid.Errors;
                    cb.Parents.Add(ecid.Value);
                }

                // Set TreeID:
                if (line == null || !line.StartsWith("tree ")) return new CommitParseExpectedTreeError();
                var etrid = TreeID.TryParse(line.Substring("tree ".Length));
                if (etrid.HasErrors) return etrid.Errors;
                cb.TreeID = etrid.Value;

                // Set Committer:
                line = sr.ReadLine();
                if (line == null || !line.StartsWith("committer ")) return new CommitParseExpectedCommitterError();
                cb.Committer = line.Substring("committer ".Length);

                // Set DateCommitted:
                line = sr.ReadLine();
                if (line == null || !line.StartsWith("date ")) return new CommitParseExpectedDateError();

                // NOTE: date parsing will result in an inexact DateTimeOffset from what was created with, but it
                // is close enough because the SHA-1 hash is calculated using the DateTimeOffset.ToString(), so
                // only the ToString() representations of the DateTimeOffsets need to match.
                DateTimeOffset tmpDate;
                if (!DateTimeOffset.TryParse(line.Substring("date ".Length), out tmpDate))
                    return new CommitParseBadDateFormatError();
                cb.DateCommitted = tmpDate;

                // Skip empty line:
                line = sr.ReadLine();
                if (line == null || line.Length != 0) return new CommitParseExpectedBlankLineError();

                // Set Message:
                cb.Message = sr.ReadToEnd();
            }

            // Create the immutable Commit from the Builder:
            Commit cm = cb;
            // Validate the computed CommitID:
            if (cm.ID != id) return new ComputedCommitIDMismatchError(cm.ID, id);

            return cm;
        }