using System.Collections.ObjectModel; using System.Globalization; using System.Text; using System.Text.Json; using System.Text.RegularExpressions; namespace View_by_Distance.Shared.Models.Stateless.Methods; internal abstract class GenealogicalDataCommunication { // ... private static string[] GetHeaderLines(string startsWith, string[] sourceLines) { List results = new(); for (int i = 0; i < sourceLines.Length; i++) { if (sourceLines[i].StartsWith(startsWith)) break; results.Add(sourceLines[i]); } return results.ToArray(); } private static List GetRelations(string personBirthdayFormat, ReadOnlyDictionary personKeyFormattedToPersonFullName, Dictionary idToNick, List familyGroupLines) { List results = new(); string? nick; long? personKey; string relation; string? fullName; string[] segments; string[] familyLines; Models.PersonBirthday? personBirthday; for (int i = 0; i < familyGroupLines.Count; i++) { familyLines = familyGroupLines[i]; for (int j = 0; j < familyLines.Length; j++) { segments = familyLines[j].Split('@'); if (segments.First().Length < 3 || segments.Length != 3) continue; if (!idToNick.TryGetValue(segments[1], out nick)) continue; relation = segments.First()[2..].Trim(); personBirthday = IPersonBirthday.GetPersonBirthday(personBirthdayFormat, nick); personKey = personBirthday?.Value.Ticks; fullName = personKeyFormattedToPersonFullName.GetValueOrDefault(nick); if (j + 1 >= familyLines.Length || familyLines[j + 1].Length < 3 || familyLines[j + 1][..3] != "2 _") results.Add(new(i, relation, segments[1], nick, personKey, fullName, null)); else results.Add(new(i, relation, segments[1], nick, personKey, fullName, familyLines[j + 1][2..])); } } return results; } private static ReadOnlyDictionary Convert(Dictionary> keyValuePairs) { Dictionary results = new(); foreach (KeyValuePair> keyValuePair in keyValuePairs) results.Add(keyValuePair.Key, keyValuePair.Value.ToArray()); return new(results); } internal static (string[], ReadOnlyDictionary, List, string[], List genealogicalDataCommunicationRelations) GetIndividuals(string personBirthdayFormat, string genealogicalDataCommunicationFile, ReadOnlyCollection personContainers, bool requireNickName) { ReadOnlyDictionary results; string? nick; string[] segments; List lines = new(); const string startsWith = "0 @"; List footerLines = new(); List familyGroupLines = new(); Dictionary idToNick = new(); Dictionary> keyValuePairs = new(); ReadOnlyDictionary personKeyFormattedToPersonFullName = IPersonContainer.GetPersonKeyFormattedToPersonFullName(personBirthdayFormat, personContainers); string[] sourceLines = string.IsNullOrEmpty(genealogicalDataCommunicationFile) || !File.Exists(genealogicalDataCommunicationFile) ? Array.Empty() : File.ReadAllLines(genealogicalDataCommunicationFile); string[] headerLines = GetHeaderLines(startsWith, sourceLines); for (int i = headerLines.Length; i < sourceLines.Length; i++) { if (!sourceLines[i].StartsWith(startsWith)) continue; nick = null; lines.Add(sourceLines[i]); if (sourceLines[i].EndsWith("@ SOUR") || sourceLines[i].EndsWith("@ SUBM") || sourceLines[i].EndsWith("@ OBJE") || sourceLines[i].EndsWith("@ REPO")) continue; else if (sourceLines[i].EndsWith("@ FAM")) { lines.Clear(); for (int j = sourceLines.Length - 1; j >= i; j--) { lines.Add(sourceLines[j]); if (sourceLines[j].First() == '0') { if (!sourceLines[j].EndsWith("@ FAM")) footerLines.AddRange(lines); else { lines.Reverse(); familyGroupLines.Add(lines.ToArray()); } lines.Clear(); } } familyGroupLines.Reverse(); footerLines.Reverse(); break; } else if (sourceLines[i].EndsWith("@ INDI")) { segments = sourceLines[i].Split('@'); for (int j = i + 1; j < sourceLines.Length; j++) { if (sourceLines[j].StartsWith(startsWith)) break; lines.Add(sourceLines[j]); if (!sourceLines[j].StartsWith("2 NICK ")) continue; nick = sourceLines[j][7..]; if (segments.Length == 3) idToNick.Add(segments[1], nick); } if (requireNickName && string.IsNullOrEmpty(nick)) throw new Exception(string.Join(Environment.NewLine, lines)); nick ??= Guid.NewGuid().ToString(); keyValuePairs.Add(nick, new()); if (!lines.Any()) continue; keyValuePairs[nick].AddRange(lines); lines.Clear(); } else throw new NotSupportedException(); } results = Convert(keyValuePairs); List genealogicalDataCommunicationRelations = GetRelations(personBirthdayFormat, personKeyFormattedToPersonFullName, idToNick, familyGroupLines); return (headerLines, results, familyGroupLines, footerLines.ToArray(), genealogicalDataCommunicationRelations); } internal static List GetMappedLines(string personBirthdayFormat, string genealogicalDataCommunicationFile, ReadOnlyCollection personContainers, bool requireNickName) { List results = new(); Models.PersonBirthday personBirthday = new(DateTime.Now); GenealogicalDataCommunicationLines genealogicalDataCommunicationLines; (string[] headerLines, ReadOnlyDictionary individuals, List familyGroupLines, string[] footerLines, _) = GetIndividuals(personBirthdayFormat, genealogicalDataCommunicationFile, personContainers, requireNickName); results.AddRange(headerLines); foreach (KeyValuePair keyValuePair in individuals) { genealogicalDataCommunicationLines = GetGenealogicalDataCommunicationLines(personBirthday, keyValuePair.Value); if (!string.IsNullOrEmpty(genealogicalDataCommunicationLines.Id)) results.Add(genealogicalDataCommunicationLines.Id); if (!string.IsNullOrEmpty(genealogicalDataCommunicationLines.UId)) results.Add(genealogicalDataCommunicationLines.UId); if (!string.IsNullOrEmpty(genealogicalDataCommunicationLines.Name)) results.Add(genealogicalDataCommunicationLines.Name); if (!string.IsNullOrEmpty(genealogicalDataCommunicationLines.GivenName)) results.Add(genealogicalDataCommunicationLines.GivenName); if (!string.IsNullOrEmpty(genealogicalDataCommunicationLines.SurName)) results.Add(genealogicalDataCommunicationLines.SurName); if (!string.IsNullOrEmpty(genealogicalDataCommunicationLines.NickName)) results.Add(genealogicalDataCommunicationLines.NickName); if (!string.IsNullOrEmpty(genealogicalDataCommunicationLines.Sex)) results.Add(genealogicalDataCommunicationLines.Sex); results.AddRange(genealogicalDataCommunicationLines.Birth); results.AddRange(genealogicalDataCommunicationLines.Death); results.AddRange(genealogicalDataCommunicationLines.Changed); } for (int i = 0; i < familyGroupLines.Count; i++) results.AddRange(familyGroupLines[i]); results.AddRange(footerLines); return results; } internal static GenealogicalDataCommunicationLines GetGenealogicalDataCommunicationLines(Models.PersonBirthday personBirthday, string[] individualsLines) { GenealogicalDataCommunicationLines result; string? idLine = null; string? sexLine = null; string? uIdLine = null; string? nameLine = null; string? suffixLine = null; string? surNameLine = null; string? nickNameLine = null; string? givenNameLine = null; List birthLines = new(); List deathLines = new(); List changedLines = new(); for (int i = 0; i < individualsLines.Length; i++) { if (idLine is null && individualsLines[i].EndsWith("@ INDI")) idLine = individualsLines[i]; else if (uIdLine is null && individualsLines[i].StartsWith("1 _UID")) uIdLine = individualsLines[i]; else if (nameLine is null && individualsLines[i].StartsWith("1 NAME")) nameLine = individualsLines[i]; else if (givenNameLine is null && individualsLines[i].StartsWith("2 GIVN")) givenNameLine = individualsLines[i]; else if (surNameLine is null && individualsLines[i].StartsWith("2 SURN")) surNameLine = individualsLines[i]; else if (suffixLine is null && individualsLines[i].StartsWith("2 NSFX")) suffixLine = individualsLines[i]; else if (nickNameLine is null && individualsLines[i].StartsWith("2 NICK")) nickNameLine = individualsLines[i]; else if (sexLine is null && individualsLines[i].StartsWith("1 SEX")) sexLine = individualsLines[i]; else if (!birthLines.Any() && individualsLines[i] == "1 BIRT") { birthLines.Add(individualsLines[i]); if (individualsLines.Length > i + 1 && individualsLines[i + 1].StartsWith("2 DATE")) { i += 1; birthLines.Add(individualsLines[i]); } } else if (!deathLines.Any() && individualsLines[i].StartsWith("1 DEAT")) { deathLines.Add(individualsLines[i]); if (individualsLines.Length > i + 1 && individualsLines[i + 1].StartsWith("2 DATE")) { i += 1; deathLines.Add(individualsLines[i]); } } else if (!changedLines.Any() && individualsLines[i] == "1 CHAN") { changedLines.Add(individualsLines[i]); if (individualsLines.Length > i + 1 && individualsLines[i + 1].StartsWith("2 DATE")) { i += 1; changedLines.Add(individualsLines[i]); } } } if (!birthLines.Any()) { birthLines.Add("1 BIRT"); birthLines.Add($"2 DATE {personBirthday.Value:dd MMM yyyy}"); } result = new(idLine, uIdLine, nameLine, givenNameLine, surNameLine, suffixLine, nickNameLine, sexLine, birthLines, deathLines, changedLines); return result; } internal static Models.GenealogicalDataCommunication GetGenealogicalDataCommunication(bool first, GenealogicalDataCommunicationLines genealogicalDataCommunicationLines) { Models.GenealogicalDataCommunication result; DateTime? birth; DateTime? death; DateTime? changed; string? uId = string.IsNullOrEmpty(genealogicalDataCommunicationLines.UId) || !genealogicalDataCommunicationLines.UId.Contains("1 _UID ") ? null : genealogicalDataCommunicationLines.UId.Split("1 _UID ")[1]; char sex = string.IsNullOrEmpty(genealogicalDataCommunicationLines.Sex) || !genealogicalDataCommunicationLines.Sex.Contains("1 SEX ") ? 'U' : genealogicalDataCommunicationLines.Sex.Split("1 SEX ")[1].First(); string? name = string.IsNullOrEmpty(genealogicalDataCommunicationLines.Name) || !genealogicalDataCommunicationLines.Name.Contains("1 NAME ") ? null : genealogicalDataCommunicationLines.Name.Split("1 NAME ")[1]; string? suffix = string.IsNullOrEmpty(genealogicalDataCommunicationLines.Suffix) || !genealogicalDataCommunicationLines.Suffix.Contains("2 NSFX ") ? null : genealogicalDataCommunicationLines.Suffix.Split("2 NSFX ")[1]; string? surName = string.IsNullOrEmpty(genealogicalDataCommunicationLines.SurName) || !genealogicalDataCommunicationLines.SurName.Contains("2 SURN ") ? null : genealogicalDataCommunicationLines.SurName.Split("2 SURN ")[1]; string nickName = string.IsNullOrEmpty(genealogicalDataCommunicationLines.NickName) || !genealogicalDataCommunicationLines.NickName.Contains("2 NICK ") ? throw new NotSupportedException() : genealogicalDataCommunicationLines.NickName.Split("2 NICK ")[1]; string? givenName = string.IsNullOrEmpty(genealogicalDataCommunicationLines.GivenName) || !genealogicalDataCommunicationLines.GivenName.Contains("2 GIVN ") ? null : genealogicalDataCommunicationLines.GivenName.Split("2 GIVN ")[1]; string? id = string.IsNullOrEmpty(genealogicalDataCommunicationLines.Id) || !genealogicalDataCommunicationLines.Id.Contains("0 @I") || !genealogicalDataCommunicationLines.Id.Contains("@ INDI") ? null : genealogicalDataCommunicationLines.Id.Split('@')[1][1..]; string[] birthLines = (from l in genealogicalDataCommunicationLines.Birth where l.Contains("2 DATE ") select l.Split("2 DATE ")[1]).ToArray(); string[] deathLines = (from l in genealogicalDataCommunicationLines.Death where l.Contains("2 DATE ") select l.Split("2 DATE ")[1]).ToArray(); string[] changedLines = (from l in genealogicalDataCommunicationLines.Changed where l.Contains("2 DATE ") select l.Split("2 DATE ")[1]).ToArray(); if (!birthLines.Any() || !DateTime.TryParse(birthLines[0], out DateTime parseBirth)) birth = null; else birth = parseBirth; if (!deathLines.Any() || !DateTime.TryParse(deathLines[0], out DateTime parseDeath)) death = null; else death = parseDeath; if (!changedLines.Any() || !DateTime.TryParse(changedLines[0], out DateTime parseChanged)) changed = null; else changed = parseChanged; if (birth is not null) { bool alive = death is null && !genealogicalDataCommunicationLines.Death.Any(l => l == "1 DEAT Y"); (int age, _) = IAge.GetAge(DateTime.Now.Ticks, birth.Value.Ticks); int hours = IPersonBirthday.GetHour(alive, sex); if (!first) hours += 2; if (death == birth) death = death.Value.AddHours(hours); birth = birth.Value.AddHours(hours); if (age < 1) birth = null; if (birth is not null && death is null && (!alive || (age > 110 && !IPersonBirthday.IsCounterPersonBirthday(new(birth.Value))))) death = birth; } death ??= !genealogicalDataCommunicationLines.Death.Any(l => l == "1 DEAT Y") ? null : birth; result = new(birth, changed, death, givenName, id, name, nickName, sex, suffix, surName, uId); return result; } internal static bool CleanDisplayDirectoryAllFilesAndWriteTicksGed(string mappingDefaultName, string personBirthdayFormat, ReadOnlyCollection personContainers, string[] headerLines, List familyGroupLines, string[] footerLines, long ticks, string a2PeopleContentDirectory) { bool result = false; string directory; string[] mdFiles; string[] txtFiles; const int zero = 0; string[] jsonFiles; string[] pGedFiles; string personKeyFormatted; List lines = new(); List distinct = new(); List individualsLines; DateTime dateTime = new(ticks); Models.PersonBirthday personBirthday; Calendar calendar = new CultureInfo("en-US").Calendar; string weekOfYear = calendar.GetWeekOfYear(dateTime, CalendarWeekRule.FirstDay, DayOfWeek.Sunday).ToString("00"); lines.AddRange(headerLines); foreach (Models.PersonContainer personContainer in personContainers) { if (personContainer.Key is null || personContainer.Birthdays is null || personContainer.Person is null || !personContainer.Birthdays.Any()) continue; if (IPerson.IsDefaultName(mappingDefaultName, personContainer.DisplayDirectoryName) || IPerson.IsDefaultName(mappingDefaultName, personContainer.Person)) continue; if (distinct.Contains(personContainer.Key.Value)) continue; distinct.Add(personContainer.Key.Value); personBirthday = personContainer.Birthdays[zero]; personKeyFormatted = IPersonBirthday.GetFormatted(personBirthdayFormat, personBirthday); mdFiles = (from l in personContainer.DisplayDirectoryAllFiles where l.EndsWith(".md") select l).ToArray(); txtFiles = (from l in personContainer.DisplayDirectoryAllFiles where l.EndsWith(".txt") select l).ToArray(); jsonFiles = (from l in personContainer.DisplayDirectoryAllFiles where l.EndsWith(".json") select l).ToArray(); pGedFiles = (from l in personContainer.DisplayDirectoryAllFiles where l.EndsWith(".pged") select l).ToArray(); foreach (string mdFile in mdFiles) { if (string.IsNullOrEmpty(personKeyFormatted)) continue; if (!mdFile.Contains(personKeyFormatted)) { if (!result) result = true; File.Delete(mdFile); } } foreach (string pGedFile in pGedFiles) { if (string.IsNullOrEmpty(personKeyFormatted)) continue; if (!pGedFile.Contains(personKeyFormatted)) { if (!result) result = true; File.Delete(pGedFile); continue; } individualsLines = File.ReadAllLines(pGedFile).ToList(); foreach (string jsonFile in jsonFiles) { if (!result) result = true; File.Delete(jsonFile); } foreach (string txtFile in txtFiles) { if (new FileInfo(txtFile).Length == 0) { if (!result) result = true; File.Delete(txtFile); } } lines.AddRange(individualsLines); } } for (int i = 0; i < familyGroupLines.Count; i++) lines.AddRange(familyGroupLines[i]); lines.AddRange(footerLines); directory = Path.Combine(a2PeopleContentDirectory, $"{dateTime.Year}-GenealogicalDataCommunication", $"{dateTime.Year}-Week-{weekOfYear}"); if (!Directory.Exists(directory)) _ = Directory.CreateDirectory(directory); File.WriteAllLines(Path.Combine(directory, $"{ticks}.ged"), lines); return result; } internal static ReadOnlyDictionary> GetFamilyIndexToCollection(List genealogicalDataCommunicationRelations) { Dictionary> results = new(); List? relations; foreach (GenealogicalDataCommunicationRelation genealogicalDataCommunicationRelation in genealogicalDataCommunicationRelations) { if (!results.TryGetValue(genealogicalDataCommunicationRelation.FamilyIndex, out relations)) { results.Add(genealogicalDataCommunicationRelation.FamilyIndex, new()); if (!results.TryGetValue(genealogicalDataCommunicationRelation.FamilyIndex, out relations)) throw new NotSupportedException(); } relations.Add(genealogicalDataCommunicationRelation); } return new(results); } internal static ReadOnlyDictionary> GetCollection(string personBirthdayFormat, List genealogicalDataCommunicationRelations) { Dictionary> results = new(); long personKey; string personKeyFormatted; Models.PersonBirthday? personBirthday; List? collection; foreach (GenealogicalDataCommunicationRelation genealogicalDataCommunicationRelation in genealogicalDataCommunicationRelations) { personKeyFormatted = genealogicalDataCommunicationRelation.NickName; personBirthday = IPersonBirthday.GetPersonBirthday(personBirthdayFormat, personKeyFormatted); if (personBirthday is null) continue; personKey = personBirthday.Value.Ticks; if (!results.TryGetValue(personKey, out collection)) { results.Add(personKey, new()); if (!results.TryGetValue(personKey, out collection)) throw new NotSupportedException(); } collection.Add(genealogicalDataCommunicationRelation); } return new(results); } internal static ReadOnlyDictionary> GetCollection(string personBirthdayFormat, ReadOnlyDictionary> familyIndexToCollection) { Dictionary> results = new(); long personKey; string personKeyFormatted; Models.PersonBirthday? personBirthday; List? collection; foreach (KeyValuePair> keyValuePair in familyIndexToCollection) { foreach (GenealogicalDataCommunicationRelation genealogicalDataCommunicationRelation in keyValuePair.Value) { personKeyFormatted = genealogicalDataCommunicationRelation.NickName; personBirthday = IPersonBirthday.GetPersonBirthday(personBirthdayFormat, personKeyFormatted); if (personBirthday is null) continue; personKey = personBirthday.Value.Ticks; if (!results.TryGetValue(personKey, out collection)) { results.Add(personKey, new()); if (!results.TryGetValue(personKey, out collection)) throw new NotSupportedException(); } collection.Add(genealogicalDataCommunicationRelation); } } return new(results); } internal static string GetMergeWithLineTwo(GenealogicalDataCommunicationRelation genealogicalDataCommunicationRelation, GenealogicalDataCommunicationRelation relation) { string result; const char father = 'F'; const char mother = 'M'; string wife = IGenealogicalDataCommunication.Wife; string husband = IGenealogicalDataCommunication.Husband; if (string.IsNullOrEmpty(genealogicalDataCommunicationRelation.LineTwo)) { if (relation.Relation == wife) result = nameof(mother); else if (relation.Relation == husband) result = nameof(father); else result = string.Empty; } else { StringBuilder stringBuilder = new(); if (genealogicalDataCommunicationRelation.LineTwo[1] == father) { if (relation.Relation == wife) _ = stringBuilder.Append(nameof(mother)); else if (relation.Relation == husband) _ = stringBuilder.Append(genealogicalDataCommunicationRelation.LineTwo.Split(' ').Last()).Append(' ').Append(nameof(father)); } else if (genealogicalDataCommunicationRelation.LineTwo[1] == mother) { if (relation.Relation == husband) _ = stringBuilder.Append(nameof(father)); else if (relation.Relation == wife) _ = stringBuilder.Append(genealogicalDataCommunicationRelation.LineTwo.Split(' ').Last()).Append(' ').Append(nameof(mother)); } result = stringBuilder.ToString(); } return result; } private static void WriteAll(long ticks, string a2PeopleContentDirectory, List frontMatterLinesCollections, string weekOfYear) { string json; string[] segments; string? directory; string frontMatterLastLine; DateTime dateTime = new(ticks); List allFrontMatterLines = new(); foreach (string[] frontMatterLines in frontMatterLinesCollections) { allFrontMatterLines.Add("{"); frontMatterLastLine = frontMatterLines.Last(); foreach (string frontMatterLine in frontMatterLines) { segments = frontMatterLine.Split(": "); if (segments.Length != 2) continue; if (frontMatterLine == frontMatterLastLine) allFrontMatterLines.Add($"\"{string.Join("\": ", segments)}"); else allFrontMatterLines.Add($"\"{string.Join("\": ", segments)},"); } allFrontMatterLines.Add("},"); } directory = Path.Combine(a2PeopleContentDirectory, $"{dateTime.Year}-Markdown", $"{dateTime.Year}-Week-{weekOfYear}", ticks.ToString()); if (!Directory.Exists(directory)) _ = Directory.CreateDirectory(directory); json = $"[{string.Join(Environment.NewLine, allFrontMatterLines.ToArray(), 0, allFrontMatterLines.Count - 1)}{allFrontMatterLines.Last()[..^1]}]"; Models.GenealogicalDataCommunication[]? genealogicalDataCommunications = JsonSerializer.Deserialize(json, GenealogicalDataCommunicationSourceCollectionGenerationContext.Default.GenealogicalDataCommunicationArray); if (genealogicalDataCommunications is null) throw new NullReferenceException(nameof(genealogicalDataCommunications)); json = JsonSerializer.Serialize(genealogicalDataCommunications, GenealogicalDataCommunicationSourceCollectionGenerationContext.Default.GenealogicalDataCommunicationArray); _ = IPath.WriteAllText(Path.Combine(directory, $"{ticks}.json"), json, updateDateWhenMatches: false, compareBeforeWrite: true); } internal static void MaybeWriteMarkDownFiles(string mappingDefaultName, string personBirthdayFormat, long ticks, ReadOnlyCollection personContainers, ReadOnlyDictionary individuals, ReadOnlyDictionary> familyIndexToCollection, string a2PeopleContentDirectory) { bool? male; bool? first; string fullName; string[]? lines; string[] matches; string? directory; bool isDefaultName; const int zero = 0; string personKeyFormatted; string lowerHyphenFullName; List frontMatterLines; string pattern = "[^a-z0-9-]"; DateTime dateTime = new(ticks); Calendar calendar = new CultureInfo("en-US").Calendar; List<(string? Id, string[] FrontMatterLines)> collection = new(); Models.GenealogicalDataCommunication genealogicalDataCommunication; GenealogicalDataCommunicationLines? genealogicalDataCommunicationLines; string weekOfYear = calendar.GetWeekOfYear(dateTime, CalendarWeekRule.FirstDay, DayOfWeek.Sunday).ToString("00"); ReadOnlyDictionary personKeyFormattedToPersonFullName = IPersonContainer.GetPersonKeyFormattedToPersonFullName(personBirthdayFormat, personContainers); foreach (Models.PersonContainer personContainer in personContainers.OrderByDescending(l => l.Key)) { if (personContainer.Key is null || personContainer.Birthdays is null || personContainer.Person is null || personContainer.PersonDirectory is null || !personContainer.Birthdays.Any()) continue; male = personContainer.PersonDirectory.Sex == 'U' ? null : personContainer.PersonDirectory.Sex == 'M' || (personContainer.PersonDirectory.Sex == 'F' ? false : throw new Exception()); first = personContainer.PersonDirectory.First == 'U' ? null : personContainer.PersonDirectory.First == 'Y' || (personContainer.PersonDirectory.First == 'N' ? false : throw new Exception()); if (first is null) continue; isDefaultName = IPerson.IsDefaultName(mappingDefaultName, personContainer.DisplayDirectoryName); personKeyFormatted = IPersonBirthday.GetFormatted(personBirthdayFormat, personContainer.Key.Value); matches = (from l in personContainer.DisplayDirectoryAllFiles where l.Contains(personKeyFormatted) select l).ToArray(); if (!matches.Any()) continue; directory = Path.GetDirectoryName(matches[zero]); if (directory is null) continue; if (!individuals.TryGetValue(personKeyFormatted, out lines)) continue; genealogicalDataCommunicationLines = lines is null ? null : GetGenealogicalDataCommunicationLines(personContainer.Birthdays[zero], lines); if (genealogicalDataCommunicationLines is null) continue; genealogicalDataCommunication = GetGenealogicalDataCommunication(first.Value, genealogicalDataCommunicationLines); if (genealogicalDataCommunication.Sex != personContainer.PersonDirectory.Sex) continue; if (genealogicalDataCommunication.Birth is not null && !directory.EndsWith(genealogicalDataCommunication.Birth.Value.Hour.ToString())) continue; if (genealogicalDataCommunication.Death is null && personContainer.PersonDirectory.Status == 'D' || genealogicalDataCommunication.Death is not null && personContainer.PersonDirectory.Status == 'A') continue; fullName = PersonName.GetFullName(personContainer.Person.Name); lowerHyphenFullName = $"{Regex.Replace(fullName.ToLower(), pattern, "-")}"; frontMatterLines = MarkDown.GetFrontMatterLines(ticks, fullName, lowerHyphenFullName, genealogicalDataCommunication); if (!frontMatterLines.Any()) continue; collection.Add((genealogicalDataCommunication.Id, frontMatterLines.ToArray())); MarkDown.WriteFile(personKeyFormatted, ticks, a2PeopleContentDirectory, calendar, pattern, personKeyFormattedToPersonFullName, familyIndexToCollection, genealogicalDataCommunication, fullName, lowerHyphenFullName, frontMatterLines); } if (collection.Any()) { List frontMatterLinesCollections = (from l in collection orderby l.Id.Length, l.Id where l.Id is not null select l.FrontMatterLines).ToList(); WriteAll(ticks, a2PeopleContentDirectory, frontMatterLinesCollections, weekOfYear); } } }