Esempio n. 1
0
 public void NotFwDataFileForBreakupShouldThrow()
 {
     using (var tempFile = new TempFile(""))
     {
         var pathname = tempFile.Path;
         Assert.Throws <ApplicationException>(() => FLExProjectSplitter.PushHumptyOffTheWall(new NullProgress(), pathname));
     }
 }
Esempio n. 2
0
 /// <summary>
 /// Allow the client to do something right after a merge, but before the merge is committed.
 /// </summary>
 /// <remarks>This method is not be called at all, if there was no merging.</remarks>
 public void PrepareForPostMergeCommit(IProgress progress)
 {
     RestoreProjectFile(progress);
     progress.WriteMessage("Checking project for merge problems");
     if (RunFixFwData(progress))
     {
         progress.WriteMessage("Ran fix-up utility after merge.");
         FLExProjectSplitter.PushHumptyOffTheWall(progress, _writeVerbose, _fwdataPathname);
     }
 }
Esempio n. 3
0
 /// <summary>
 /// Allow the client to do something right before the initial local commit.
 /// </summary>
 public void PrepareForInitialCommit(IProgress progress)
 {
     if (!_needToNestMainFile)
     {
         return;                 // Only nest it one time.
     }
     progress.WriteMessage("Split up project file: {0}", ProjectFilename);
     FLExProjectSplitter.PushHumptyOffTheWall(progress, _writeVerbose, _fwdataPathname);
     progress.WriteMessage("Finished splitting up project file: {0}", ProjectFilename);
     _needToNestMainFile = false;
 }
Esempio n. 4
0
 public void UserCancelledBreakupShouldThrow()
 {
     using (var tempFile = TempFile.WithFilename("foo" + Utilities.FwXmlExtension))
     {
         var progress = new NullProgress
         {
             CancelRequested = true
         };
         var pathname = tempFile.Path;
         Assert.Throws <UserCancelledException>(() => FLExProjectSplitter.PushHumptyOffTheWall(progress, pathname));
     }
 }
Esempio n. 5
0
        private MetadataCache GetFreshMdc()
        {
            var mdc = MetadataCache.TestOnlyNewCache;
            var modelVersionPathname = Path.Combine(_workingDir, SharedConstants.ModelVersionFilename);

            if (!File.Exists(modelVersionPathname))
            {
                FLExProjectSplitter.WriteVersionFile(_srcFwdataPathname);
                using (var fastSplitter = new FastXmlElementSplitter(_srcFwdataPathname))
                {
                    bool foundOptionalFirstElement;
                    // NB: The main input file *does* have to deal with the optional first element.
                    foreach (var record in fastSplitter.GetSecondLevelElementBytes(SharedConstants.AdditionalFieldsTag, SharedConstants.RtTag, out foundOptionalFirstElement))
                    {
                        if (foundOptionalFirstElement)
                        {
                            // 2. Write custom properties file with custom properties.
                            FileWriterService.WriteCustomPropertyFile(mdc, _workingDir, record);
                        }
                        else
                        {
                            // Write empty custom properties file.
                            FileWriterService.WriteCustomPropertyFile(Path.Combine(_workingDir, SharedConstants.CustomPropertiesFilename), null);
                        }
                        break;
                    }
                }
            }
            var modelData = File.ReadAllText(modelVersionPathname);

            mdc.UpgradeToVersion(Int32.Parse(modelData.Split(new[] { "{", ":", "}" }, StringSplitOptions.RemoveEmptyEntries)[1]));
            var customPropPathname = Path.Combine(_workingDir, SharedConstants.CustomPropertiesFilename);

            mdc.AddCustomPropInfo(new MergeOrder(
                                      customPropPathname, customPropPathname, customPropPathname,
                                      new MergeSituation(customPropPathname, "", "", "", "", MergeOrder.ConflictHandlingModeChoices.WeWin)));
            return(mdc);
        }
Esempio n. 6
0
        internal static void WriteNestedDomainData(IProgress progress, bool writeVerbose, string rootDir,
                                                   IDictionary <string, XElement> wellUsedElements,
                                                   IDictionary <string, SortedDictionary <string, byte[]> > classData,
                                                   Dictionary <string, string> guidToClassMapping)
        {
            var anthropologyBaseDir = Path.Combine(rootDir, SharedConstants.Anthropology);

            if (!Directory.Exists(anthropologyBaseDir))
            {
                Directory.CreateDirectory(anthropologyBaseDir);
            }

            FLExProjectSplitter.CheckForUserCancelRequested(progress);
            if (writeVerbose)
            {
                progress.WriteVerbose("Writing the anthropology data....");
            }
            else
            {
                progress.WriteMessage("Writing the anthropology data....");
            }
            AnthropologyBoundedContextService.NestContext(anthropologyBaseDir, wellUsedElements, classData, guidToClassMapping);
        }
        internal static void WriteNestedDomainData(IProgress progress, bool writeVerbose, string rootDir,
                                                   IDictionary <string, XElement> wellUsedElements,
                                                   IDictionary <string, SortedDictionary <string, byte[]> > classData,
                                                   Dictionary <string, string> guidToClassMapping)
        {
            var generalBaseDir = Path.Combine(rootDir, SharedConstants.General);

            if (!Directory.Exists(generalBaseDir))
            {
                Directory.CreateDirectory(generalBaseDir);
            }

            FLExProjectSplitter.CheckForUserCancelRequested(progress);
            if (writeVerbose)
            {
                progress.WriteVerbose("Writing the general data....");
                progress.WriteVerbose("Writing user-defined list data....");
            }
            else
            {
                progress.WriteMessage("Writing the general data....");
                progress.WriteMessage("Writing user-defined list data....");
            }
            UserDefinedListsBoundedContextService.NestContext(generalBaseDir, wellUsedElements, classData, guidToClassMapping);

            FLExProjectSplitter.CheckForUserCancelRequested(progress);
            if (writeVerbose)
            {
                progress.WriteVerbose("Writing language project data....");
            }
            else
            {
                progress.WriteMessage("Writing language project data....");
            }
            GeneralDomainBoundedContext.NestContext(generalBaseDir, wellUsedElements, classData, guidToClassMapping);
        }
        internal static void WriteNestedDomainData(IProgress progress, bool writeVerbose, string rootDir,
                                                   IDictionary <string, XElement> wellUsedElements,
                                                   IDictionary <string, SortedDictionary <string, byte[]> > classData,
                                                   Dictionary <string, string> guidToClassMapping)
        {
            var linguisticsBaseDir = Path.Combine(rootDir, SharedConstants.Linguistics);

            if (!Directory.Exists(linguisticsBaseDir))
            {
                Directory.CreateDirectory(linguisticsBaseDir);
            }

            FLExProjectSplitter.CheckForUserCancelRequested(progress);
            if (writeVerbose)
            {
                progress.WriteVerbose("Writing the linguistics data....");
                progress.WriteVerbose("Writing reversal data....");
            }
            else
            {
                progress.WriteMessage("Writing the linguistics data....");
                progress.WriteMessage("Writing reversal data....");
            }
            ReversalBoundedContextService.NestContext(linguisticsBaseDir, wellUsedElements, classData, guidToClassMapping);

            FLExProjectSplitter.CheckForUserCancelRequested(progress);
            if (writeVerbose)
            {
                progress.WriteVerbose("Writing morphology and syntax data....");
            }
            else
            {
                progress.WriteMessage("Writing morphology and syntax data....");
            }
            MorphologyAndSyntaxBoundedContextService.NestContext(linguisticsBaseDir, wellUsedElements, classData, guidToClassMapping);

            // Both ReversalBoundedContextService and MorphologyAndSyntaxBoundedContextService abscond with some stuff owned by LexDb. :-(
            FLExProjectSplitter.CheckForUserCancelRequested(progress);
            if (writeVerbose)
            {
                progress.WriteVerbose("Writing lexical data....");
            }
            else
            {
                progress.WriteMessage("Writing lexical data....");
            }
            LexiconBoundedContextService.NestContext(linguisticsBaseDir, wellUsedElements, classData, guidToClassMapping);

            FLExProjectSplitter.CheckForUserCancelRequested(progress);
            if (writeVerbose)
            {
                progress.WriteVerbose("Writing text corpus data....");
            }
            else
            {
                progress.WriteMessage("Writing text corpus data....");
            }
            TextCorpusBoundedContextService.NestContext(linguisticsBaseDir, wellUsedElements, classData, guidToClassMapping);

            FLExProjectSplitter.CheckForUserCancelRequested(progress);
            if (writeVerbose)
            {
                progress.WriteVerbose("Writing wordform and punctuation data....");
            }
            else
            {
                progress.WriteMessage("Writing wordform and punctuation data....");
            }
            WordformInventoryBoundedContextService.NestContext(linguisticsBaseDir, wellUsedElements, classData, guidToClassMapping);

            FLExProjectSplitter.CheckForUserCancelRequested(progress);
            if (writeVerbose)
            {
                progress.WriteVerbose("Writing discourse data....");
            }
            else
            {
                progress.WriteMessage("Writing discourse data....");
            }
            FLExProjectSplitter.CheckForUserCancelRequested(progress);
            DiscourseAnalysisBoundedContextService.NestContext(linguisticsBaseDir, wellUsedElements, classData, guidToClassMapping);

            if (writeVerbose)
            {
                progress.WriteVerbose("Writing phonology data....");
            }
            else
            {
                progress.WriteMessage("Writing phonology data....");
            }
            PhonologyBoundedContextService.NestContext(linguisticsBaseDir, wellUsedElements, classData, guidToClassMapping);
        }
Esempio n. 9
0
        private void Verify(Stopwatch verifyTimer, StringBuilder sb)
        {
            GC.Collect(2, GCCollectionMode.Forced);
            verifyTimer.Start();
            GetFreshMdc();             // Want it fresh.
            var origData = new Dictionary <string, byte[]>(StringComparer.InvariantCultureIgnoreCase);

            using (var fastSplitterOrig = new FastXmlElementSplitter(_srcFwdataPathname + ".orig"))
            {
                var foundOrigOptionalFirstElement = false;
                var testedforExistanceOfOrigOptionalFirstElement = false;
                foreach (var origRecord in fastSplitterOrig.GetSecondLevelElementBytes(SharedConstants.AdditionalFieldsTag, SharedConstants.RtTag))
                {
                    if (!testedforExistanceOfOrigOptionalFirstElement)
                    {
                        foundOrigOptionalFirstElement = FLExProjectSplitter.IsOptionalFirstElement(origRecord);
                        testedforExistanceOfOrigOptionalFirstElement = true;
                    }
                    if (foundOrigOptionalFirstElement)
                    {
                        origData.Add(SharedConstants.AdditionalFieldsTag, origRecord);
                        foundOrigOptionalFirstElement = false;
                        continue;
                    }
                    origData.Add(XmlUtils.GetAttributes(origRecord, new HashSet <string> {
                        SharedConstants.GuidStr
                    })[SharedConstants.GuidStr].ToLowerInvariant(), origRecord);
                }
            }
            verifyTimer.Stop();
            GC.Collect(2, GCCollectionMode.Forced);
            verifyTimer.Start();
            using (var fastSplitterNew = new FastXmlElementSplitter(_srcFwdataPathname))
            {
                // NB: The main input file *does* have to deal with the optional first element.
                //var counter = 0;
                var foundNewOptionalFirstElement = false;
                var testedforExistanceOfNewOptionalFirstElement = false;
                foreach (var newRecordAsBytes in fastSplitterNew.GetSecondLevelElementBytes(SharedConstants.AdditionalFieldsTag, SharedConstants.RtTag))
                {
                    if (!testedforExistanceOfNewOptionalFirstElement)
                    {
                        foundNewOptionalFirstElement = FLExProjectSplitter.IsOptionalFirstElement(newRecordAsBytes);
                        testedforExistanceOfNewOptionalFirstElement = true;
                    }
                    var    newRecCopyAsBytes = newRecordAsBytes;
                    byte[] origRecAsBytes;
                    string srcGuid = null;
                    if (foundNewOptionalFirstElement)
                    {
                        origRecAsBytes = origData[SharedConstants.AdditionalFieldsTag];
                        origData.Remove(SharedConstants.AdditionalFieldsTag);
                        foundNewOptionalFirstElement = false;
                    }
                    else
                    {
                        var attrValues = XmlUtils.GetAttributes(newRecordAsBytes, new HashSet <string> {
                            SharedConstants.GuidStr, SharedConstants.Class
                        });
                        srcGuid        = attrValues[SharedConstants.GuidStr];
                        origRecAsBytes = origData[srcGuid];
                        origData.Remove(srcGuid);
                        if (attrValues[SharedConstants.Class] == "WfiWordform")
                        {
                            var wfElement = Utilities.CreateFromBytes(origRecAsBytes);
                            var csProp    = wfElement.Element("Checksum");
                            if (csProp != null)
                            {
                                csProp.Attribute(SharedConstants.Val).Value = "0";
                                origRecAsBytes = SharedConstants.Utf8.GetBytes(wfElement.ToString());
                            }
                        }
                    }

                    //if (counter == 1000)
                    //{
                    //    verifyTimer.Stop();
                    //    GC.Collect(2, GCCollectionMode.Forced);
                    //    verifyTimer.Start();
                    //    counter = 0;
                    //}
                    //else
                    //{
                    //    counter++;
                    //}
                    // Way too slow, since it has to always make the XmlNodes.
                    // Just feeding strings to XmlUtilities.AreXmlElementsEqual is faster,
                    // since it skips making them, if the strings are the same.
                    //var origNode = CreateXmlNodeFromBytes(origRecAsBytes);
                    //var newNode = CreateXmlNodeFromBytes(newRecCopyAsBytes);
                    //if (XmlUtilities.AreXmlElementsEqual(origNode, newNode))
                    //    continue;
                    //if (srcGuid == null)
                    //{
                    //    WriteProblemDataFile(Path.Combine(_workingDir, "CustomProperties-SRC.txt"), origNode);
                    //    WriteProblemDataFile(Path.Combine(_workingDir, srcGuid + "CustomProperties-TRG.txt"), newNode);
                    //    sb.Append("Main src and trg custom properties are different in the resulting xml.");
                    //}
                    //else
                    //{
                    //    WriteProblemDataFile(Path.Combine(_workingDir, srcGuid + "-SRC.txt"), origNode);
                    //    WriteProblemDataFile(Path.Combine(_workingDir, srcGuid + "-TRG.txt"), newNode);
                    //    sb.AppendFormat("Main src and trg object with guid '{0}' are different in the resulting xml.", srcGuid);
                    //}
                    //if (XmlUtilities.AreXmlElementsEqual(SharedConstants.Utf8.GetString(origRecAsBytes), SharedConstants.Utf8.GetString(newRecCopyAsBytes)))
                    //	continue;
                    if (XmlUtilities.AreXmlElementsEqual(origRecAsBytes, newRecCopyAsBytes))
                    {
                        continue;
                    }
                    if (srcGuid == null)
                    {
                        WriteProblemDataFile(Path.Combine(_workingDir, "CustomProperties-SRC.txt"), origRecAsBytes);
                        WriteProblemDataFile(Path.Combine(_workingDir, srcGuid + "CustomProperties-TRG.txt"), newRecCopyAsBytes);
                        sb.Append("Main src and trg custom properties are different in the resulting xml.");
                    }
                    else
                    {
                        WriteProblemDataFile(Path.Combine(_workingDir, srcGuid + "-SRC.txt"), origRecAsBytes);
                        WriteProblemDataFile(Path.Combine(_workingDir, srcGuid + "-TRG.txt"), newRecCopyAsBytes);
                        sb.AppendFormat("Main src and trg object with guid '{0}' are different in the resulting xml.", srcGuid);
                    }
                    sb.AppendLine();
                }
            }
            if (origData.Count > 0)
            {
                sb.AppendFormat("Hmm, there are {0} more <rt> elements in the original than in the rebuilt fwdata file.", origData.Count);
                sb.AppendLine();
                foreach (var attrs in origData.Values.Select(byteData => XmlUtils.GetAttributes(byteData, new HashSet <string> {
                    SharedConstants.GuidStr, SharedConstants.Class
                })))
                {
                    sb.AppendFormat("\t\t'{0}' of class '{1}' is not in rebuilt file.", attrs[SharedConstants.GuidStr], attrs[SharedConstants.Class]);
                    sb.AppendLine();
                }
            }
            verifyTimer.Stop();
        }
Esempio n. 10
0
        private void RoundTripData(Stopwatch breakupTimer, Stopwatch restoreTimer, Stopwatch ambiguousTimer, StringBuilder sbValidation)
        {
            File.Copy(_srcFwdataPathname, _srcFwdataPathname + ".orig", true); // Keep it safe.
            GetFreshMdc();                                                     // Want it fresh.
            breakupTimer.Start();
            FLExProjectSplitter.PushHumptyOffTheWall(new NullProgress(), _srcFwdataPathname);
            breakupTimer.Stop();
            GC.Collect(2, GCCollectionMode.Forced);

            if (_cbCheckAmbiguousElements.Checked)
            {
                var allDataFiles = new HashSet <string>();
                var currentDir   = Path.Combine(_workingDir, "Linguistics");
                if (Directory.Exists(currentDir))
                {
                    allDataFiles.UnionWith(from pathname in Directory.GetFiles(currentDir, "*.*", SearchOption.AllDirectories)
                                           where !pathname.ToLowerInvariant().EndsWith("chorusnotes")
                                           select pathname);
                }
                currentDir = Path.Combine(_workingDir, "Anthropology");
                if (Directory.Exists(currentDir))
                {
                    allDataFiles.UnionWith(from pathname in Directory.GetFiles(currentDir, "*.*", SearchOption.AllDirectories)
                                           where !pathname.ToLowerInvariant().EndsWith("chorusnotes")
                                           select pathname);
                }
                currentDir = Path.Combine(_workingDir, "Other");
                if (Directory.Exists(currentDir))
                {
                    allDataFiles.UnionWith(
                        from pathname in Directory.GetFiles(currentDir, "*.*", SearchOption.AllDirectories)
                        where !pathname.ToLowerInvariant().EndsWith("chorusnotes")
                        select pathname);
                }
                currentDir = Path.Combine(_workingDir, "General");
                if (Directory.Exists(currentDir))
                {
                    allDataFiles.UnionWith(from pathname in Directory.GetFiles(currentDir, "*.*", SearchOption.AllDirectories)
                                           where !pathname.ToLowerInvariant().EndsWith("chorusnotes")
                                           select pathname);
                }
                var mergeOrder = new MergeOrder(null, null, null, new NullMergeSituation())
                {
                    EventListener = new ChangeAndConflictAccumulator()
                };
                var merger = FieldWorksMergeServices.CreateXmlMergerForFieldWorksData(mergeOrder, MetadataCache.MdCache);
                ambiguousTimer.Start();
                foreach (var dataFile in allDataFiles)
                {
                    var    extension           = Path.GetExtension(dataFile).Substring(1);
                    string optionalElementName = null;
                    string mainRecordName      = null;
                    switch (extension)
                    {
                    case SharedConstants.Style:
                        mainRecordName = SharedConstants.StStyle;
                        break;

                    case SharedConstants.List:
                        mainRecordName = SharedConstants.CmPossibilityList;
                        break;

                    case SharedConstants.langproj:
                        mainRecordName = SharedConstants.LangProject;
                        break;

                    case SharedConstants.Annotation:
                        mainRecordName = SharedConstants.CmAnnotation;
                        break;

                    case SharedConstants.Filter:
                        mainRecordName = SharedConstants.CmFilter;
                        break;

                    case SharedConstants.orderings:
                        mainRecordName = SharedConstants.VirtualOrdering;
                        break;

                    case SharedConstants.pictures:
                        mainRecordName = SharedConstants.CmPicture;
                        break;

                    case SharedConstants.ArchivedDraft:
                        mainRecordName = SharedConstants.ScrDraft;
                        break;

                    case SharedConstants.ImportSetting:
                        mainRecordName = SharedConstants.ScrImportSet;
                        break;

                    case SharedConstants.Srs:
                        mainRecordName = SharedConstants.ScrRefSystem;
                        break;

                    case SharedConstants.Trans:
                        mainRecordName = SharedConstants.Scripture;
                        break;

                    case SharedConstants.bookannotations:
                        mainRecordName = SharedConstants.ScrBookAnnotations;
                        break;

                    case SharedConstants.book:
                        mainRecordName = SharedConstants.ScrBook;
                        break;

                    case SharedConstants.Ntbk:
                        optionalElementName = SharedConstants.Header;
                        mainRecordName      = SharedConstants.RnGenericRec;
                        break;

                    case SharedConstants.Reversal:
                        optionalElementName = SharedConstants.Header;
                        mainRecordName      = SharedConstants.ReversalIndexEntry;
                        break;

                    case SharedConstants.Lexdb:
                        optionalElementName = SharedConstants.Header;
                        mainRecordName      = SharedConstants.LexEntry;
                        break;

                    case SharedConstants.TextInCorpus:
                        mainRecordName = SharedConstants.Text;
                        break;

                    case SharedConstants.Inventory:
                        optionalElementName = SharedConstants.Header;
                        mainRecordName      = SharedConstants.WfiWordform;
                        break;

                    case SharedConstants.DiscourseExt:
                        optionalElementName = SharedConstants.Header;
                        mainRecordName      = SharedConstants.DsChart;
                        break;

                    case SharedConstants.Featsys:
                        mainRecordName = SharedConstants.FsFeatureSystem;
                        break;

                    case SharedConstants.Phondata:
                        mainRecordName = SharedConstants.PhPhonData;
                        break;

                    case SharedConstants.Morphdata:
                        mainRecordName = SharedConstants.MoMorphData;
                        break;

                    case SharedConstants.Agents:
                        mainRecordName = SharedConstants.CmAgent;
                        break;
                    }
                    using (var fastSplitter = new FastXmlElementSplitter(dataFile))
                    {
                        bool foundOptionalFirstElement;
                        foreach (var record in fastSplitter.GetSecondLevelElementBytes(optionalElementName, mainRecordName, out foundOptionalFirstElement))
                        {
                            XmlMergeService.RemoveAmbiguousChildren(merger.EventListener, merger.MergeStrategies, CreateXmlNodeFromBytes(record));
                        }
                    }
                }
                ambiguousTimer.Stop();
                foreach (var warning in ((ChangeAndConflictAccumulator)merger.EventListener).Warnings)
                {
                    sbValidation.AppendLine(warning.Description);
                    sbValidation.AppendLine();
                    sbValidation.AppendLine(warning.HtmlDetails);
                    sbValidation.AppendLine();
                }
                GC.Collect(2, GCCollectionMode.Forced);
            }
            restoreTimer.Start();
            FLExProjectUnifier.PutHumptyTogetherAgain(new NullProgress(), _srcFwdataPathname);
            restoreTimer.Stop();
            GC.Collect(2, GCCollectionMode.Forced);
        }
Esempio n. 11
0
 public void NonExistingFileForBreakupShouldThrow()
 {
     Assert.Throws <ApplicationException>(() => FLExProjectSplitter.PushHumptyOffTheWall(new NullProgress(), "Bogus" + Utilities.FwXmlExtension));
 }
Esempio n. 12
0
 public void EmptyPathnameForBreakupShouldThrow()
 {
     Assert.Throws <ApplicationException>(() => FLExProjectSplitter.PushHumptyOffTheWall(new NullProgress(), ""));
 }
Esempio n. 13
0
        internal static void WriteNestedDomainData(IProgress progress, bool writeVerbose, string rootDir,
                                                   IDictionary <string, XElement> wellUsedElements,
                                                   IDictionary <string, SortedDictionary <string, byte[]> > classData,
                                                   Dictionary <string, string> guidToClassMapping)
        {
            /*
             *              BC 1. ScrRefSystem (no owner)
             *                      Books prop owns seq of ScrBookRef (which has all basic props).
             *                      No other props.
             *                      [Put all in one file in a subfolder of Scripture?]
             *                      [[Nesting]]
             *
             *              BC 2. CheckLists prop on LP that holds col of CmPossibilityList items.
             *                      Each CmPossibilityList will hold ChkTerm (called ChkItem in model file) objects (derived from CmPossibility)
             *                      [Store each list in a file. Put all lists in subfolder.]
             *                      [[Nesting]]
             *
             *              BC 3. Scripture (owned by LP)
             *                      Leave in:
             *                              Resources prop owns col of CmResource. [Leave.]
             *                      Extract:
             *              BC 4.		ArchivedDrafts prop owns col of ScrDraft. [Each ScrDraft goes in its own file. Archived stuff goes into subfolder of Scripture.]
             *              BC 5.		Styles props owns col of StStyle. [Put styles in subfolder and one for each style.]
             *              BC 6.		ImportSettings prop owns col of ScrImportSet.  [Put sets in subfolder and one for each set.]
             *              BC 7.		NoteCategories prop owns one CmPossibilityList [Put list in its own file.]
             *              BC 8.		ScriptureBooks prop owns seq of ScrBook. [Put each book in its own folder (named for its cononical order number).]
             *              BC 9.		BookAnnotations prop owns seq of ScrBookAnnotations. [Put each ScrBookAnnotations in corresponding subfolder along with optional book.]
             */
            var scriptureBaseDir = Path.Combine(rootDir, SharedConstants.Other);

            if (!Directory.Exists(scriptureBaseDir))
            {
                Directory.CreateDirectory(scriptureBaseDir);
            }

            FLExProjectSplitter.CheckForUserCancelRequested(progress);
            if (writeVerbose)
            {
                progress.WriteVerbose("Writing the other data....");
            }
            else
            {
                progress.WriteMessage("Writing the other data....");
            }
            ScriptureReferenceSystemBoundedContextService.NestContext(scriptureBaseDir, classData, guidToClassMapping);
            var langProj = wellUsedElements[SharedConstants.LangProject];

            FLExProjectSplitter.CheckForUserCancelRequested(progress);
            ScriptureCheckListsBoundedContextService.NestContext(langProj, scriptureBaseDir, classData, guidToClassMapping);

            // These are intentionally out of order from the above numbering scheme.
            var scrAsBytes = classData[SharedConstants.Scripture].Values.FirstOrDefault();

            // // Lela Teli-3 has null.
            if (scrAsBytes != null)
            {
                var scripture = Utilities.CreateFromBytes(scrAsBytes);
                FLExProjectSplitter.CheckForUserCancelRequested(progress);
                ArchivedDraftsBoundedContextService.NestContext(scripture.Element(SharedConstants.ArchivedDrafts), scriptureBaseDir, classData, guidToClassMapping);
                FLExProjectSplitter.CheckForUserCancelRequested(progress);
                ScriptureStylesBoundedContextService.NestContext(scripture.Element(SharedConstants.Styles), scriptureBaseDir, classData, guidToClassMapping);
                FLExProjectSplitter.CheckForUserCancelRequested(progress);
                ImportSettingsBoundedContextService.NestContext(scripture.Element(SharedConstants.ImportSettings), scriptureBaseDir, classData, guidToClassMapping);
                FLExProjectSplitter.CheckForUserCancelRequested(progress);
                ScriptureBoundedContextService.NestContext(langProj, scripture, scriptureBaseDir, classData, guidToClassMapping);
            }

            RemoveFolderIfEmpty(scriptureBaseDir);
        }