public List<AbstractNode> findChildren(int opcode) {
   List<AbstractNode> children = new ArrayList<>();
   for (AbstractNode n : this) {
     if (n.opcode() == opcode) children.add(n);
   }
   return !children.isEmpty() ? children : null;
 }
 @SuppressWarnings("unchecked")
 public <T extends AbstractNode> T first(Class<? extends AbstractNode> clazz) {
   for (AbstractNode n : this) {
     if (n.getClass().equals(clazz)) return (T) n;
   }
   return null;
 }
 public int total() {
   int size = 1;
   for (AbstractNode n : this) {
     size += n.total();
   }
   return size;
 }
 public AbstractNode preLayer(int... opcodes) {
   AbstractNode node = this;
   for (int opcode : opcodes) {
     node = node.parent();
     if (node == null || node.opcode() != opcode) return null;
   }
   return node;
 }
 public AbstractNode previous(int opcode, int max) {
   int i = 0;
   AbstractNode prev = this;
   while ((prev = prev.previous()) != null && i++ < max) {
     if (prev.opcode() == opcode) return prev;
   }
   return null;
 }
 public AbstractNode next(int opcode, int max) {
   int i = 0;
   AbstractNode next = this;
   while ((next = next.next()) != null && i++ < max) {
     if (next.opcode() == opcode) return next;
   }
   return null;
 }
 public MethodMemberNode firstMethod() {
   for (AbstractNode n : this) {
     if (n instanceof ReferenceNode) {
       if (n.insn() instanceof MethodInsnNode) return (MethodMemberNode) n;
     }
   }
   return null;
 }
 public FieldMemberNode firstField() {
   for (AbstractNode n : this) {
     if (n instanceof ReferenceNode) {
       if (n.insn() instanceof FieldInsnNode) return (FieldMemberNode) n;
     }
   }
   return null;
 }
 @SuppressWarnings("unchecked")
 public <T extends AbstractNode> T next(Class<? extends AbstractNode> clazz, int max) {
   int i = 0;
   AbstractNode next = this;
   while ((next = next.next()) != null && i++ < max) {
     if (next.getClass().equals(clazz)) return (T) next;
   }
   return null;
 }
 public AbstractNode find(int opcode, int index) {
   int i = 0;
   for (AbstractNode n : this) {
     if (n.opcode() == opcode) {
       if (i++ == index) return n;
     }
   }
   return null;
 }
 protected String toString(int tab) {
   StringBuilder sb = new StringBuilder();
   sb.append(Assembly.toString(insn));
   for (AbstractNode n : this) {
     sb.append('\n');
     for (int i = 0; i < tab; i++) {
       sb.append('\t');
     }
     sb.append(n.toString(tab + 1));
   }
   return sb.toString();
 }
 public AbstractInsnNode[] collapse() {
   if (instructions != null) {
     return instructions;
   }
   instructions = new AbstractInsnNode[total()];
   int i = 0;
   for (AbstractNode n : this) {
     AbstractInsnNode[] nodes = n.collapse();
     System.arraycopy(nodes, 0, instructions, i, nodes.length);
     i += nodes.length;
   }
   if (instructions.length - i != 1) {
     throw new RuntimeException();
   }
   instructions[i] = insn();
   return instructions;
 }
 public List<AbstractNode> layerAll(int... opcodes) {
   List<AbstractNode> children = findChildren(opcodes[0]);
   if (children == null) return null;
   if (opcodes.length == 1) return children;
   for (int i = 1; i < opcodes.length; i++) {
     List<AbstractNode> next = new ArrayList<>();
     for (AbstractNode n : children) {
       List<AbstractNode> match = n.findChildren(opcodes[i]);
       if (match == null) continue;
       next.addAll(match);
     }
     if (next.isEmpty()) {
       return null;
     } else {
       children.clear();
       children.addAll(next);
     }
   }
   return children;
 }
 public AbstractNode first(int opcode) {
   for (AbstractNode n : this) {
     if (n.opcode() == opcode) return n;
   }
   return null;
 }