// Path: src/main/java/org/lambda3/text/simplification/discourse/utils/IndexRange.java
// public class IndexRange {
//     private final int fromIdx;
//     private final int toIdx;
// 
//     public IndexRange(int fromIdx, int toIdx) {
//         this.fromIdx = fromIdx;
//         this.toIdx = toIdx;
//     }
// 
//     public int getFromIdx() {
//         return fromIdx;
//     }
// 
//     public int getToIdx() {
//         return toIdx;
//     }
// 
//     @Override
//     public String toString() {
//         return "(" + fromIdx + " | " + toIdx + ")";
//     }
// }
// 
// Path: src/main/java/org/lambda3/text/simplification/discourse/utils/ner/NERExtractionUtils.java
// public class NERExtractionUtils {
// 
//     public static List<IndexRange> getNERIndexRanges(NERString nerString) {
//         List<IndexRange> res = new ArrayList<>();
// 
//         for (NERTokenGroup group : nerString.getGroups()) {
//             res.add(new IndexRange(group.getFromTokenIndex(), group.getToTokenIndex()));
//         }
// 
//         return res;
//     }
// }
// 
// Path: src/main/java/org/lambda3/text/simplification/discourse/utils/ner/NERString.java
// public class NERString {
//     public static final String NO_CATEGORY = "O";
// 
//     protected final List<NERToken> tokens;
//     private List<NERTokenGroup> groups;
// 
//     public NERString(List<NERToken> tokens) {
//         this.tokens = tokens;
//         this.createGroups();
//     }
// 
//     private void createGroups() {
//         this.groups = new ArrayList<>();
// 
//         String lastCategory = null;
//         List<NERToken> currGroupTokens = new ArrayList<>();
//         for (NERToken nerToken : this.tokens) {
// 
//             if ((lastCategory != null) && (!nerToken.getCategory().equals(lastCategory))) {
//                 // add
//                 this.groups.add(new NERTokenGroup(currGroupTokens));
//                 currGroupTokens = new ArrayList<>();
//             }
// 
//             currGroupTokens.add(nerToken);
//             lastCategory = nerToken.getCategory();
//         }
// 
//         // add
//         this.groups.add(new NERTokenGroup(currGroupTokens));
//     }
// 
//     public List<NERToken> getTokens() {
//         return tokens;
//     }
// 
//     public List<NERTokenGroup> getGroups() {
//         return groups;
//     }
// 
//     private List<Word> getWords(int fromIndex, int toIndex) {
//         return tokens.subList(fromIndex, toIndex).stream().map(t -> new Word(t.getText())).collect(Collectors.toList());
//     }
// 
//     public List<Word> getWords() {
//         return getWords(0, tokens.size());
//     }
// 
//     @Override
//     public String toString() {
//         return tokens.stream().map(NERToken::toString).collect(Collectors.joining("\n"));
//     }
// }


import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import edu.stanford.nlp.ling.Word;
import edu.stanford.nlp.trees.Tree;
import org.lambda3.text.simplification.discourse.utils.IndexRange;
import org.lambda3.text.simplification.discourse.utils.ner.NERExtractionUtils;
import org.lambda3.text.simplification.discourse.utils.ner.NERString;
import java.util.ArrayList;
import java.util.Collections;



    public static List<Word> leavesToWords(List<Tree> leaves) {
        return leaves.stream().map(l -> l.yieldWords().get(0)).collect(Collectors.toList());
    }

    public static List<List<Tree>> splitLeaves(Tree anchorTree, List<Tree> leaves, INodeChecker leafChecker, boolean removeEmpty) {
        List<List<Tree>> res = new ArrayList<>();
        List<Tree> currElement = new ArrayList<>();
        for (Tree leaf : leaves) {
            if (leafChecker.check(anchorTree, leaf)) {
                if ((currElement.size() > 0) || (!removeEmpty))
                    res.add(currElement);
                currElement = new ArrayList<>();
            } else {
                currElement.add(leaf);
            }
        }
        if ((currElement.size() > 0) || (!removeEmpty))
            res.add(currElement);

        return res;
    }

    public static List<Tree> findLeaves(Tree anchorTree, List<Tree> leaves, INodeChecker leafChecker, boolean reversed) {
        List<Tree> res = leaves.stream().filter(l -> leafChecker.check(anchorTree, l)).collect(Collectors.toList());
        if (reversed) {
            Collections.reverse(res);
        }
// Path: src/main/java/org/lambda3/text/simplification/discourse/utils/IndexRange.java
// public class IndexRange {
//     private final int fromIdx;
//     private final int toIdx;
// 
//     public IndexRange(int fromIdx, int toIdx) {
//         this.fromIdx = fromIdx;
//         this.toIdx = toIdx;
//     }
// 
//     public int getFromIdx() {
//         return fromIdx;
//     }
// 
//     public int getToIdx() {
//         return toIdx;
//     }
// 
//     @Override
//     public String toString() {
//         return "(" + fromIdx + " | " + toIdx + ")";
//     }
// }
// 
// Path: src/main/java/org/lambda3/text/simplification/discourse/utils/ner/NERExtractionUtils.java
// public class NERExtractionUtils {
// 
//     public static List<IndexRange> getNERIndexRanges(NERString nerString) {
//         List<IndexRange> res = new ArrayList<>();
// 
//         for (NERTokenGroup group : nerString.getGroups()) {
//             res.add(new IndexRange(group.getFromTokenIndex(), group.getToTokenIndex()));
//         }
// 
//         return res;
//     }
// }
// 
// Path: src/main/java/org/lambda3/text/simplification/discourse/utils/ner/NERString.java
// public class NERString {
//     public static final String NO_CATEGORY = "O";
// 
//     protected final List<NERToken> tokens;
//     private List<NERTokenGroup> groups;
// 
//     public NERString(List<NERToken> tokens) {
//         this.tokens = tokens;
//         this.createGroups();
//     }
// 
//     private void createGroups() {
//         this.groups = new ArrayList<>();
// 
//         String lastCategory = null;
//         List<NERToken> currGroupTokens = new ArrayList<>();
//         for (NERToken nerToken : this.tokens) {
// 
//             if ((lastCategory != null) && (!nerToken.getCategory().equals(lastCategory))) {
//                 // add
//                 this.groups.add(new NERTokenGroup(currGroupTokens));
//                 currGroupTokens = new ArrayList<>();
//             }
// 
//             currGroupTokens.add(nerToken);
//             lastCategory = nerToken.getCategory();
//         }
// 
//         // add
//         this.groups.add(new NERTokenGroup(currGroupTokens));
//     }
// 
//     public List<NERToken> getTokens() {
//         return tokens;
//     }
// 
//     public List<NERTokenGroup> getGroups() {
//         return groups;
//     }
// 
//     private List<Word> getWords(int fromIndex, int toIndex) {
//         return tokens.subList(fromIndex, toIndex).stream().map(t -> new Word(t.getText())).collect(Collectors.toList());
//     }
// 
//     public List<Word> getWords() {
//         return getWords(0, tokens.size());
//     }
// 
//     @Override
//     public String toString() {
//         return tokens.stream().map(NERToken::toString).collect(Collectors.joining("\n"));
//     }
// }


// Path: src/main/java/org/lambda3/text/simplification/discourse/utils/parseTree/ParseTreeExtractionUtils.java
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import edu.stanford.nlp.ling.Word;
import edu.stanford.nlp.trees.Tree;
import org.lambda3.text.simplification.discourse.utils.IndexRange;
import org.lambda3.text.simplification.discourse.utils.ner.NERExtractionUtils;
import org.lambda3.text.simplification.discourse.utils.ner.NERString;
import java.util.ArrayList;
import java.util.Collections;




    public static List<Word> leavesToWords(List<Tree> leaves) {
        return leaves.stream().map(l -> l.yieldWords().get(0)).collect(Collectors.toList());
    }

    public static List<List<Tree>> splitLeaves(Tree anchorTree, List<Tree> leaves, INodeChecker leafChecker, boolean removeEmpty) {
        List<List<Tree>> res = new ArrayList<>();
        List<Tree> currElement = new ArrayList<>();
        for (Tree leaf : leaves) {
            if (leafChecker.check(anchorTree, leaf)) {
                if ((currElement.size() > 0) || (!removeEmpty))
                    res.add(currElement);
                currElement = new ArrayList<>();
            } else {
                currElement.add(leaf);
            }
        }
        if ((currElement.size() > 0) || (!removeEmpty))
            res.add(currElement);

        return res;
    }

    public static List<Tree> findLeaves(Tree anchorTree, List<Tree> leaves, INodeChecker leafChecker, boolean reversed) {
        List<Tree> res = leaves.stream().filter(l -> leafChecker.check(anchorTree, l)).collect(Collectors.toList());
        if (reversed) {
            Collections.reverse(res);
        }
        return res;