use of biblemulticonverter.data.FormattedText in project BibleMultiConverter by schierlm.
the class StrippedDiffable method selectVariation.
private void selectVariation(Bible bible, String variation) {
for (Book book : bible.getBooks()) {
for (Chapter chapter : book.getChapters()) {
if (chapter.getProlog() != null) {
FormattedText newProlog = new FormattedText();
chapter.getProlog().accept(new SelectVariationVisitor(newProlog.getAppendVisitor(), variation));
newProlog.finished();
chapter.setProlog(newProlog);
}
List<Verse> verses = chapter.getVerses();
for (int i = 0; i < verses.size(); i++) {
Verse v1 = verses.get(i);
Verse v2 = new Verse(v1.getNumber());
v1.accept(new SelectVariationVisitor(v2.getAppendVisitor(), variation));
v2.finished();
verses.set(i, v2);
}
}
}
}
use of biblemulticonverter.data.FormattedText in project BibleMultiConverter by schierlm.
the class StrippedDiffable method optimizeFormatting.
private void optimizeFormatting(Bible bible, Map<String, String[]> mappings) {
CountFormattingVisitor oldCount = new CountFormattingVisitor();
CountFormattingVisitor newCount = new CountFormattingVisitor();
for (Book book : bible.getBooks()) {
for (Chapter chap : book.getChapters()) {
if (chap.getProlog() != null) {
chap.getProlog().accept(oldCount);
FormattedText newProlog = new FormattedText();
chap.getProlog().accept(new OptimizeFormattingVisitor(newProlog.getAppendVisitor(), mappings));
newProlog.finished();
newProlog.accept(newCount);
chap.setProlog(newProlog);
}
for (int j = 0; j < chap.getVerses().size(); j++) {
Verse v = chap.getVerses().get(j);
v.accept(oldCount);
Verse nv = new Verse(v.getNumber());
v.accept(new OptimizeFormattingVisitor(nv.getAppendVisitor(), mappings));
nv.finished();
nv.accept(newCount);
chap.getVerses().set(j, nv);
}
}
}
System.out.println("Formatting instructions before optimizing:");
oldCount.printSummary();
System.out.println();
System.out.println("Formatting instructions after optimizing:");
newCount.printSummary();
}
use of biblemulticonverter.data.FormattedText in project BibleMultiConverter by schierlm.
the class VersificationMappedDiffable method doExport.
@Override
public void doExport(Bible bible, String... exportArgs) throws Exception {
String outputFile = exportArgs[0];
VersificationSet vs = new VersificationSet(new File(exportArgs[1]));
VersificationMapping vm = vs.findMapping(exportArgs[2]);
boolean dropUnmapped = false, showNumbers = false, addTags = false;
;
for (int i = 3; i < exportArgs.length; i++) {
if (exportArgs[i].equals("DropUnmapped"))
dropUnmapped = true;
else if (exportArgs[i].equals("ShowNumbers"))
showNumbers = true;
else if (exportArgs[i].equals("AddTags"))
addTags = true;
else
throw new IllegalArgumentException("Unsupported option: " + exportArgs[i]);
}
Map<BookID, String> abbrMap = new EnumMap<>(BookID.class);
for (Book book : bible.getBooks()) {
abbrMap.put(book.getId(), book.getAbbr());
}
Bible newBible = new Bible(bible.getName());
Map<BookID, Book> newBooks = new EnumMap<>(BookID.class);
for (Book book : bible.getBooks()) {
if (book.getId().getZefID() < 1) {
// metadata book, introduction or appendix
newBible.getBooks().add(book);
continue;
}
int cnumber = 0;
for (Chapter chap : book.getChapters()) {
cnumber++;
if (chap.getProlog() != null && chap.getVerses().isEmpty()) {
System.out.println("WARNING: Prolog for " + book.getAbbr() + " " + cnumber + " got lost as chapter contains no verses.");
}
for (int j = 0; j < chap.getVerses().size(); j++) {
Verse oldVerse = chap.getVerses().get(j);
Reference ref = new Reference(book.getId(), cnumber, oldVerse.getNumber()), newRef;
List<Reference> newRefs = vm.getMapping(ref);
if ((newRefs == null || newRefs.isEmpty()) && dropUnmapped) {
if (j == 0 && chap.getProlog() != null) {
System.out.println("WARNING: Prolog for " + book.getAbbr() + " " + cnumber + " got lost as first verse of it is unmapped.");
}
continue;
}
if (newRefs == null || newRefs.contains(ref) || newRefs.isEmpty())
newRef = ref;
else
newRef = newRefs.get(0);
if (!newBooks.containsKey(newRef.getBook())) {
Book newBook = null;
for (Book oldBook : bible.getBooks()) {
if (oldBook.getId() == newRef.getBook()) {
newBook = new Book(oldBook.getAbbr(), newRef.getBook(), oldBook.getShortName(), oldBook.getLongName());
break;
}
}
if (newBook == null)
newBook = new Book(newRef.getBook().getOsisID(), newRef.getBook(), newRef.getBook().getEnglishName(), newRef.getBook().getEnglishName());
newBooks.put(newRef.getBook(), newBook);
newBible.getBooks().add(newBook);
}
Book newBook = newBooks.get(newRef.getBook());
while (newBook.getChapters().size() < newRef.getChapter()) newBook.getChapters().add(new Chapter());
Chapter newChapter = newBook.getChapters().get(newRef.getChapter() - 1);
if (j == 0 && chap.getProlog() != null) {
FormattedText newProlog = new FormattedText();
if (newChapter.getProlog() != null) {
newChapter.getProlog().accept(newProlog.getAppendVisitor());
newProlog.getAppendVisitor().visitLineBreak(LineBreakKind.PARAGRAPH);
}
chap.getProlog().accept(new MapXrefVisitor(newProlog.getAppendVisitor(), vm, dropUnmapped, abbrMap));
newProlog.finished();
newChapter.setProlog(newProlog);
}
Verse newVerse = null;
for (Verse v : newChapter.getVerses()) {
if (v.getNumber().equals(newRef.getVerse())) {
newVerse = v;
break;
}
}
boolean needSpace = true;
if (newVerse == null) {
newVerse = new Verse(newRef.getVerse());
newChapter.getVerses().add(newVerse);
needSpace = false;
}
if (needSpace || !ref.equals(newRef)) {
Visitor<RuntimeException> v = newVerse.getAppendVisitor();
if (addTags)
v = v.visitExtraAttribute(ExtraAttributePriority.KEEP_CONTENT, "v11n", "origverse", ref.getBook().getOsisID() + "--" + ref.getChapter() + "--" + ref.getVerse());
if (needSpace)
v.visitText(" ");
if (showNumbers) {
String verseNumber;
if (!ref.getBook().equals(newRef.getBook())) {
verseNumber = ref.getBook().getOsisID() + " " + ref.getChapter() + ":" + ref.getVerse();
} else if (ref.getChapter() != newRef.getChapter()) {
verseNumber = ref.getChapter() + ":" + ref.getVerse();
} else {
verseNumber = ref.getVerse();
}
v.visitFormattingInstruction(FormattingInstructionKind.BOLD).visitText("(" + verseNumber + ")");
v.visitText(" ");
}
}
oldVerse.accept(new MapXrefVisitor(newVerse.getAppendVisitor(), vm, dropUnmapped, abbrMap));
}
}
}
for (Book bk : newBible.getBooks()) {
for (Chapter ch : bk.getChapters()) {
for (Verse v : ch.getVerses()) {
v.finished();
}
}
}
bible = newBible;
new Diffable().doExport(bible, new String[] { outputFile });
}
use of biblemulticonverter.data.FormattedText in project BibleMultiConverter by schierlm.
the class ZefDic method parseBible.
protected Bible parseBible(Dictionary doc) throws Exception {
Bible result = new Bible(doc.getType().toString() + "@" + doc.getRefbible());
MetadataBook metadata = new MetadataBook();
if (doc.getDicversion() != null) {
metadata.setValue(MetadataBookKey.version, doc.getDicversion());
}
if (doc.getRevision() != null) {
metadata.setValue(MetadataBookKey.revision, doc.getRevision());
}
for (JAXBElement<?> elem : doc.getINFORMATION().getTitleOrCreatorOrDescription()) {
if (elem.getValue() == null)
continue;
String value = normalize(elem.getValue().toString(), true).trim();
if (value.length() == 0)
value = "-empty-";
metadata.setValue(elem.getName().getLocalPart(), value);
}
metadata.finished();
if (metadata.getKeys().size() > 0)
result.getBooks().add(metadata.getBook());
int counter = 0;
for (TItem item : doc.getItem()) {
String id = item.getId();
String internalId = id;
if (!id.matches(Utils.BOOK_ABBR_REGEX))
internalId = "L" + (++counter);
Book bk = new Book(internalId, BookID.DICTIONARY_ENTRY, id, id);
result.getBooks().add(bk);
FormattedText prolog = new FormattedText();
bk.getChapters().add(new Chapter());
bk.getChapters().get(0).setProlog(prolog);
Visitor<RuntimeException> vv = prolog.getAppendVisitor();
String strongId = item.getStrongId();
if (strongId != null) {
Visitor<RuntimeException> vvvv = vv.visitExtraAttribute(ExtraAttributePriority.KEEP_CONTENT, "zefdic", "itemfield", "strongid");
vvvv.visitFormattingInstruction(FormattingInstructionKind.BOLD).visitText("Strong-ID: ");
vvvv.visitText(strongId);
vv.visitLineBreak(LineBreakKind.PARAGRAPH);
}
for (Object s : item.getContent()) {
if (s instanceof String) {
if (((String) s).trim().length() > 0)
throw new RuntimeException((String) s);
} else if (s instanceof JAXBElement) {
Object v = ((JAXBElement<?>) s).getValue();
if (!((JAXBElement<?>) s).getName().getNamespaceURI().equals("")) {
throw new RuntimeException(((JAXBElement<?>) s).getName().getNamespaceURI());
}
String nn = ((JAXBElement<?>) s).getName().getLocalPart();
if (v instanceof TParagraph && nn.equals("description")) {
TParagraph para = (TParagraph) v;
if (para.getId() != null)
throw new RuntimeException(para.getId());
Visitor<RuntimeException> vvv = vv.visitExtraAttribute(ExtraAttributePriority.KEEP_CONTENT, "zefdic", "field", "description");
for (Object oo : para.getContent()) {
if (oo instanceof String) {
vvv.visitText(normalize((String) oo, false));
} else if (oo instanceof JAXBElement) {
Object ovv = ((JAXBElement<?>) oo).getValue();
if (!((JAXBElement<?>) oo).getName().getNamespaceURI().equals("")) {
throw new RuntimeException(((JAXBElement<?>) oo).getName().getNamespaceURI());
}
String nnn = ((JAXBElement<?>) oo).getName().getLocalPart();
if (nnn.equals("br") && ovv instanceof String) {
if (((String) ovv).trim().length() > 0)
throw new RuntimeException((String) ovv);
vvv.visitLineBreak(LineBreakKind.NEWLINE);
} else if (nnn.equals("title") && ovv instanceof String) {
vvv.visitHeadline(2).visitText(((String) ovv).trim().replaceAll(" +", " "));
} else if (nnn.equals("sub") && ovv instanceof String) {
vvv.visitFormattingInstruction(FormattingInstructionKind.SUBSCRIPT).visitText(normalize((String) ovv, false));
} else if (nnn.equals("reflink") && ovv instanceof RefLinkType) {
RefLinkType r = (RefLinkType) ovv;
if (r.getTarget() != null || r.getContent() == null || r.getContent().length() > 0)
System.out.println("WARNING: Unsupported reflink attributes " + r.getTarget() + "|" + r.getContent());
if (r.getMscope() == null)
r.setMscope(r.getContent());
vv.visitDictionaryEntry("reflink", r.getMscope().replace(';', '-'));
} else if (nnn.equals("see") && ovv instanceof SeeType) {
SeeType see = (SeeType) ovv;
if (see.getTarget() != null && !see.getTarget().equals("x-self"))
throw new RuntimeException(see.getTarget());
vv.visitDictionaryEntry("dict", see.getContent());
} else if (nnn.equals("bib_link") && ovv instanceof BibLinkType) {
BibLinkType bl = (BibLinkType) ovv;
Visitor<RuntimeException> fn = vv.visitFootnote();
fn.visitText(FormattedText.XREF_MARKER);
BookID bid = BookID.fromZefId(Integer.parseInt(bl.getBn()));
int chapter = Integer.parseInt(bl.getCn1());
fn.visitCrossReference(bid.getOsisID(), bid, chapter, bl.getVn1(), chapter, bl.getVn1()).visitText(bid.getOsisID() + " " + chapter + ":" + bl.getVn1());
} else if (nnn.equals("greek") && ovv instanceof String) {
vv.visitExtraAttribute(ExtraAttributePriority.KEEP_CONTENT, "zefdic", "tag", "greek").visitText(normalize((String) ovv, false));
} else if (nnn.equals("em") && ovv instanceof String) {
vvv.visitFormattingInstruction(FormattingInstructionKind.ITALIC).visitText(normalize((String) ovv, false));
} else if (nnn.equals("strong") && ovv instanceof String) {
vvv.visitFormattingInstruction(FormattingInstructionKind.BOLD).visitText(normalize((String) ovv, false));
} else if (nnn.equals("q") && ovv instanceof String) {
vv.visitExtraAttribute(ExtraAttributePriority.KEEP_CONTENT, "zefdic", "tag", "q").visitText(normalize((String) ovv, false));
} else {
throw new RuntimeException(nnn + "/" + ovv.getClass().getName());
}
} else {
throw new RuntimeException(oo.getClass().getName());
}
}
vv.visitLineBreak(LineBreakKind.PARAGRAPH);
} else if (v instanceof String || v instanceof MyAnyType) {
Visitor<RuntimeException> vvvv;
boolean addParagraph = false;
if (nn.equals("title")) {
vvvv = vv.visitHeadline(1);
} else if (nn.equals("strong_id")) {
vvvv = vv.visitExtraAttribute(ExtraAttributePriority.KEEP_CONTENT, "zefdic", "field", "strongid");
vvvv.visitFormattingInstruction(FormattingInstructionKind.BOLD).visitText("Strong-ID: ");
addParagraph = true;
} else if (nn.equals("transliteration")) {
vvvv = vv.visitExtraAttribute(ExtraAttributePriority.KEEP_CONTENT, "zefdic", "field", "transliteration");
vvvv.visitFormattingInstruction(FormattingInstructionKind.BOLD).visitText("Transliteration: ");
addParagraph = true;
} else if (nn.equals("pronunciation")) {
vvvv = vv.visitExtraAttribute(ExtraAttributePriority.KEEP_CONTENT, "zefdic", "field", "pronunciation");
vvvv.visitFormattingInstruction(FormattingInstructionKind.BOLD).visitText("Pronunciation: ");
addParagraph = true;
} else {
throw new RuntimeException(nn);
}
if (v instanceof MyAnyType) {
parseElement(vvvv, (MyAnyType) v);
} else if (v instanceof String) {
vvvv.visitText(normalize((String) v, false));
}
if (addParagraph) {
vv.visitLineBreak(LineBreakKind.PARAGRAPH);
}
} else {
throw new RuntimeException(nn + "/" + v.getClass().getName());
}
} else {
throw new RuntimeException("" + s.getClass());
}
}
prolog.trimWhitespace();
prolog.finished();
}
return result;
}
use of biblemulticonverter.data.FormattedText in project BibleMultiConverter by schierlm.
the class ZefaniaXML method parseBible.
protected Bible parseBible(XMLBIBLE doc) throws Exception {
Bible result = new Bible(doc.getBiblename());
MetadataBook metadata = new MetadataBook();
if (doc.getStatus() != null) {
metadata.setValue(MetadataBookKey.status, doc.getStatus().value());
}
if (doc.getVersion() != null) {
metadata.setValue(MetadataBookKey.version, doc.getVersion());
}
if (doc.getRevision() != null) {
metadata.setValue(MetadataBookKey.revision, doc.getRevision().toString());
}
for (JAXBElement<?> elem : doc.getINFORMATION().getTitleOrCreatorOrDescription()) {
if (elem.getValue() == null)
continue;
String value = normalize(elem.getValue().toString(), true).trim();
if (value.length() != 0)
metadata.setValue(elem.getName().getLocalPart(), value);
}
metadata.finished();
if (metadata.getKeys().size() > 0)
result.getBooks().add(metadata.getBook());
Set<String> abbrs = new HashSet<String>();
Set<String> shortnames = new HashSet<String>();
Set<String> longnames = new HashSet<String>();
Map<BookID, String> abbrMap = new EnumMap<BookID, String>(BookID.class);
List<BIBLEBOOK> nl = doc.getBIBLEBOOK();
for (BIBLEBOOK e : nl) {
String shortname = e.getBsname();
int number = e.getBnumber().intValue();
BookID bookID;
try {
bookID = BookID.fromZefId(number);
} catch (IllegalArgumentException ex) {
continue;
}
if (shortname == null || shortname.length() == 0)
shortname = "_" + bookID.getOsisID();
String abbr = shortname.replaceAll("[^A-Z0-9a-zäöü]++", "");
if (abbr.length() == 0 || Character.isLowerCase(abbr.charAt(0)))
abbr = "X" + abbr;
if (abbr.length() == 1)
abbr += "x";
if (abbrs.contains(abbr)) {
for (int i = 2; i < 100; i++) {
if (!abbrs.contains(abbr + i)) {
abbr = abbr + i;
break;
}
}
}
abbrs.add(abbr);
abbrMap.put(bookID, abbr);
}
abbrs.clear();
EnumMap<BookID, Book> existingBooks = new EnumMap<BookID, Book>(BookID.class);
for (BIBLEBOOK e : nl) {
String shortname = e.getBsname();
String longname = e.getBname();
int number = e.getBnumber().intValue();
BookID bookID;
try {
bookID = BookID.fromZefId(number);
} catch (IllegalArgumentException ex) {
System.out.println("WARNING: Skipping book with unknown id " + number);
continue;
}
if (shortname == null || shortname.length() == 0)
shortname = "_" + bookID.getOsisID();
if (longname == null || longname.length() == 0)
longname = "_" + bookID.getEnglishName();
else
longname = longname.replaceAll(" ++", " ").trim();
String abbr = shortname.replaceAll("[^A-Z0-9a-zäöü]++", "");
if (abbr.length() == 0 || Character.isLowerCase(abbr.charAt(0)))
abbr = "X" + abbr;
if (abbr.length() == 1)
abbr += "x";
if (abbrs.contains(abbr)) {
for (int i = 2; i < 100; i++) {
if (!abbrs.contains(abbr + i)) {
abbr = abbr + i;
break;
}
}
}
abbrs.add(abbr);
if (shortname.equals("Gen") && longname.equals("Genesis") && bookID == BookID.BOOK_Exod) {
System.out.println("WARNING: Book number " + bookID.getZefID() + " has name " + longname);
shortname = "Exo";
longname = "Exodus";
}
if (shortname.equals("1Chr") && longname.equals("2 Chronicles")) {
System.out.println("WARNING: Book name 2 Chronicles has short name 1Chr");
shortname = "2Chr";
}
if (shortnames.contains(shortname)) {
System.out.println("WARNING: Duplicate short name " + shortname);
for (int i = 2; i < 100; i++) {
if (!shortnames.contains(shortname + i)) {
shortname = shortname + i;
break;
}
}
}
shortnames.add(shortname);
if (longnames.contains(longname)) {
System.out.println("WARNING: Duplicate long name " + shortname);
for (int i = 2; i < 100; i++) {
if (!longnames.contains(longname + i)) {
longname = longname + i;
break;
}
}
}
longnames.add(longname);
Book book = existingBooks.get(bookID);
if (book == null) {
book = new Book(abbr, bookID, shortname, longname);
existingBooks.put(bookID, book);
result.getBooks().add(book);
}
List<Headline> headlineBuffer = new ArrayList<Headline>();
for (CHAPTER e2 : e.getCHAPTER()) {
int chapterNumber = e2.getCnumber().intValue();
while (book.getChapters().size() < chapterNumber) book.getChapters().add(new Chapter());
Chapter chapter = book.getChapters().get(chapterNumber - 1);
int existingVerses = chapter.getVerses().size();
for (Object e3 : e2.getPROLOGOrCAPTIONOrVERS()) {
if (e3 instanceof CAPTION) {
CAPTION caption = (CAPTION) e3;
int depth;
if (caption.getType() == null) {
depth = 9;
} else {
switch(caption.getType()) {
case X_H_1:
depth = 1;
break;
case X_H_2:
depth = 2;
break;
case X_H_3:
depth = 3;
break;
case X_H_4:
depth = 4;
break;
case X_H_5:
depth = 5;
break;
case X_H_6:
depth = 6;
break;
default:
depth = 9;
break;
}
}
int lastDepth = headlineBuffer.size() == 0 ? -1 : headlineBuffer.get(headlineBuffer.size() - 1).getDepth();
if (depth <= lastDepth)
depth = lastDepth == 9 ? 9 : lastDepth + 1;
Headline h = new Headline(depth);
if (parseContent(h.getAppendVisitor(), caption.getContent(), abbrMap)) {
h.trimWhitespace();
h.finished();
headlineBuffer.add(h);
}
} else if (e3 instanceof REMARK) {
REMARK remark = (REMARK) e3;
int vref = remark.getVref().intValue();
int idx = chapter.getVerseIndex("" + vref);
if (idx == -1)
continue;
Verse v = chapter.getVerses().get(idx);
if (remark.getContent().size() != 1)
continue;
String remarkText = normalize((String) remark.getContent().get(0), true).trim();
v.getAppendVisitor().visitFootnote().visitText(remarkText);
} else if (e3 instanceof XREF) {
XREF xref = (XREF) e3;
int vref = xref.getVref().intValue();
int idx = chapter.getVerseIndex("" + vref);
if (idx == -1)
continue;
Verse v = chapter.getVerses().get(idx);
Visitor<RuntimeException> footnoteVisitor = v.getAppendVisitor().visitFootnote();
boolean first = true;
for (String mscope : xref.getMscope().split(" ")) {
Matcher m = Utils.compilePattern("([0-9]+);([0-9]+)(-[0-9]+)?;([0-9]+)(-[0-9]+)?").matcher(mscope);
if (!m.matches())
continue;
BookID xrefBookID = BookID.fromZefId(Integer.parseInt(m.group(1)));
int xrefChapter = Integer.parseInt(m.group(2)), endChapter = xrefChapter;
if (m.group(3) != null)
endChapter = Integer.parseInt(m.group(3).substring(1));
String verse = m.group(4);
String endVerse = m.group(5);
if (endVerse == null)
endVerse = verse;
else
endVerse = endVerse.substring(1);
if (verse.equals("0") || endVerse.equals("0"))
continue;
if (xrefChapter == endChapter && Integer.parseInt(verse) > Integer.parseInt(endVerse))
continue;
String xrefAbbr = abbrMap.get(xrefBookID);
if (xrefAbbr == null)
xrefAbbr = xrefBookID.getOsisID();
if (first)
first = false;
else
footnoteVisitor.visitText(" ");
footnoteVisitor.visitCrossReference(xrefAbbr, xrefBookID, xrefChapter, verse, endChapter, endVerse).visitText(xrefAbbr + " " + xrefChapter + ":" + verse);
}
if (first)
visitEmptyMarker(footnoteVisitor);
} else if (e3 instanceof PROLOG) {
PROLOG prolog = (PROLOG) e3;
if (chapter.getProlog() != null)
continue;
FormattedText prologText = new FormattedText();
if (parseContent(prologText.getAppendVisitor(), prolog.getContent(), abbrMap)) {
prologText.trimWhitespace();
prologText.finished();
chapter.setProlog(prologText);
}
} else if (e3 instanceof VERS) {
VERS vers = (VERS) e3;
int vnumber = vers.getVnumber() == null ? 0 : vers.getVnumber().intValue();
if (vnumber == 0)
vnumber = chapter.getVerses().size() + 1;
String verseNumber = vnumber + (vers.getAix() == null ? "" : vers.getAix());
String infix = "";
while (chapter.getVerseIndex(verseNumber) != -1) {
for (char ch = 'a'; ch <= 'z'; ch++) {
if (chapter.getVerseIndex(vnumber + infix + ch) == -1) {
verseNumber = vnumber + infix + ch;
break;
}
}
infix += "-";
}
Verse verse = new Verse(verseNumber);
Visitor<RuntimeException> visitor = verse.getAppendVisitor();
boolean contentFound = false;
if (headlineBuffer.size() > 0) {
for (Headline h : headlineBuffer) {
h.accept(visitor.visitHeadline(h.getDepth()));
}
headlineBuffer.clear();
contentFound = true;
}
contentFound |= parseContent(visitor, vers.getContent(), abbrMap);
if (contentFound) {
verse.trimWhitespace();
chapter.getVerses().add(verse);
}
}
}
for (Verse v : chapter.getVerses()) {
if (existingVerses > 0) {
existingVerses--;
continue;
}
v.finished();
}
}
}
return result;
}
Aggregations