src/glade/grammar/GrammarUtils.java
public static class RepetitionNode implements Node {
	private final NodeData data;
	public final Node start;
	public final Node rep;
	public final Node end;
	public RepetitionNode(NodeData data, Node start, Node rep, Node end) {
		this.data = data;
		this.start = start;
		this.rep = rep;
		this.end = end;
	}
	public List<Node> getChildren() {
		List<Node> children = new ArrayList<Node>();
		children.add(this.start);
		children.add(this.rep);
		children.add(this.end);
		return children;
	}
	public NodeData getData() {
		return this.data;
	}
	public String toString() {
		return this.start.toString() + "(" + this.rep.toString() + ")*" + this.end.toString();
	}
}
src/glade/util/CharacterUtils.java
public static class CharacterGeneralization {
	public final Set<Character> triggers;
	public final List<Character> characters;
	public final List<Character> checks;
	public CharacterGeneralization(Collection<Character> triggers, Collection<Character> characters, Collection<Character> checks) {
		this.triggers = new HashSet<Character>(triggers);
		this.characters = new ArrayList<Character>(characters);
		this.checks = new ArrayList<Character>(checks);
	}
}
src/glade/util/Utils.java
public static class MultivalueMap<K,V> extends HashMap<K,Set<V>> {
	private static final long serialVersionUID = -6390444829513305915L;

	public void add(K k, V v) {
		ensure(k).add(v);
	}
		
	public Set<V> ensure(K k) {
		Set<V> vSet = super.get(k);
		if(vSet == null) {
			super.put(k, vSet = new HashSet<V>());
		}
		return vSet;
	}

	@Override
	public Set<V> get(Object k) {
		Set<V> vSet = super.get(k);
		return vSet == null ? new HashSet<V>() : vSet;
	}
}
src/glade/grammar/GrammarUtils.java
public static class AlternationNode implements Node {
	private final NodeData data;
	public final Node first;
	public final Node second;
	public AlternationNode(NodeData data, Node first, Node second) {
		this.data = data;
		this.first = first;
		this.second = second;
	}
	public List<Node> getChildren() {
		List<Node> children = new ArrayList<Node>();
		children.add(this.first);
		children.add(this.second);
		return children;
	}
	public NodeData getData() {
		return this.data;
	}
	public String toString() {
		return "(" + this.first.toString() + ")+(" + this.second.toString(); 
	}
}
src/glade/util/CharacterUtils.java
public class CharacterUtils {
	public static boolean isNewlineOrTabCharacter(char c) {
		return c == '\n' || c == '\t';
	}
	
	public static boolean isNumeric(char c) {
		return c >= '0' && c <= '9';
	}
	
	public static boolean isAlphaUpperCase(char c) {
		return c >= 'A' && c <= 'Z';
	}
	
	public static boolean isAlphaLowerCase(char c) {
		return c >= 'a' && c <= 'z';
	}
	
	public static boolean isAlpha(char c) {
		return isAlphaUpperCase(c) || isAlphaLowerCase(c);
	}
	
	public static boolean isAlphaNumeric(char c) {
		return isAlpha(c) || isNumeric(c);
	}
	
	public static boolean isNonAlphaNumeric(char c) {
		return !isNumeric(c) && !isAlphaUpperCase(c) && !isAlphaLowerCase(c);
	}
	
	public static boolean isSingleQuote(char c) {
		return c == 39;
	}
	
	public static boolean isDoubleQuote(char c) {
		return c == 34;
	}
	
	public static class CharacterGeneralization {
		public final Set<Character> triggers;
		public final List<Character> characters;
		public final List<Character> checks;
		public CharacterGeneralization(Collection<Character> triggers, Collection<Character> characters, Collection<Character> checks) {
			this.triggers = new HashSet<Character>(triggers);
			this.characters = new ArrayList<Character>(characters);
			this.checks = new ArrayList<Character>(checks);
		}
	}
	
	private static final List<Character> allCharacters = new ArrayList<Character>();
	private static final List<Character> numericCharacters = new ArrayList<Character>();
	private static final List<Character> alphaUpperCaseCharacters = new ArrayList<Character>();
	private static final List<Character> alphaLowerCaseCharacters = new ArrayList<Character>();
	private static final List<Character> nonAlphaNumericCharacters = new ArrayList<Character>();
	private static final List<Character> numericChecks = new ArrayList<Character>();
	private static final List<Character> alphaUpperCaseChecks = new ArrayList<Character>();
	private static final List<Character> alphaLowerCaseChecks = new ArrayList<Character>();
	private static final List<CharacterGeneralization> generalizations = new ArrayList<CharacterGeneralization>();
	static {
		for(char c=0; c<128; c++) {
			allCharacters.add(c);
			if(isNumeric(c)) {
				numericCharacters.add(c);
			} else if(isAlphaUpperCase(c)) {
				alphaUpperCaseCharacters.add(c);
			} else if(isAlphaLowerCase(c)) {
				alphaLowerCaseCharacters.add(c);
			} else {
				nonAlphaNumericCharacters.add(c);
			}
		}
		numericChecks.add('0');
		numericChecks.add('1');
		numericChecks.add('9');
		alphaUpperCaseChecks.add('E');
		alphaUpperCaseChecks.add('Q');
		alphaLowerCaseChecks.add('e');
		alphaLowerCaseChecks.add('q');
		for(char c : nonAlphaNumericCharacters) {
			List<Character> curC = Utils.getList(c);
			generalizations.add(new CharacterGeneralization(numericCharacters, curC, curC));
			generalizations.add(new CharacterGeneralization(alphaLowerCaseCharacters, curC, curC));
			generalizations.add(new CharacterGeneralization(alphaUpperCaseCharacters, curC, curC));
		}
		generalizations.add(new CharacterGeneralization(numericCharacters, numericCharacters, numericChecks));
		generalizations.add(new CharacterGeneralization(numericCharacters, alphaUpperCaseCharacters, alphaUpperCaseChecks));
		generalizations.add(new CharacterGeneralization(numericCharacters, alphaLowerCaseCharacters, alphaLowerCaseChecks));
		generalizations.add(new CharacterGeneralization(alphaUpperCaseCharacters, numericCharacters, numericChecks));
		generalizations.add(new CharacterGeneralization(alphaUpperCaseCharacters, alphaUpperCaseCharacters, alphaUpperCaseChecks));
		generalizations.add(new CharacterGeneralization(alphaUpperCaseCharacters, alphaLowerCaseCharacters, alphaLowerCaseChecks));
		generalizations.add(new CharacterGeneralization(alphaLowerCaseCharacters, numericCharacters, numericChecks));
		generalizations.add(new CharacterGeneralization(alphaLowerCaseCharacters, alphaUpperCaseCharacters, alphaUpperCaseChecks));
		generalizations.add(new CharacterGeneralization(alphaLowerCaseCharacters, alphaLowerCaseCharacters, alphaLowerCaseChecks));
	}
	
	public static List<Character> getAllCharacters() {
		return allCharacters;
	}
	
	public static List<Character> getNumericCharacters() {
		return numericCharacters;
	}
	
	public static List<Character> getAlphaUpperCaseCharacters() {
		return alphaUpperCaseCharacters;
	}
	
	public static List<Character> getAlphaLowerCaseCharacters() {
		return alphaLowerCaseCharacters;
	}
	
	public static List<Character> getNonAlphaNumericCharacters() {
		return nonAlphaNumericCharacters;
	}
	
	public static List<Character> getNumericChecks() {
		return numericChecks;
	}
	
	public static List<Character> getAlphaUpperCaseChecks() {
		return alphaUpperCaseChecks;
	}
	
	public static List<Character> getAlphaLowerCaseChecks() {
		return alphaLowerCaseChecks;
	}
	
	public static List<CharacterGeneralization> getGeneralizations() {
		return generalizations;
	}
}
src/glade/util/Log.java
public class Log {
	private static String logName = null;
	private static boolean verboseValue = false;
	
	public static void init(String log, boolean verbose) {
		logName = log;
		verboseValue = verbose;
		new File(logName).delete();
	}
	
	public static void info(String s) {
		if(logName == null) {
			return;
		}
		if(verboseValue) {
			System.out.println(s);
		}
		try {
			PrintWriter pw = new PrintWriter(new FileOutputStream(logName, true));
			pw.println(s);
			pw.close();
		} catch(IOException e) {
			e.printStackTrace();
		}
	}

	public static void err(Exception e) {
		if(verboseValue) {
			e.printStackTrace();
		} else {
			System.err.println(e.getMessage());
		}
		try {
			PrintWriter pw = new PrintWriter(new FileOutputStream(logName, true));
			e.printStackTrace(pw);
			pw.close();
		} catch(IOException ep) {
			ep.printStackTrace();
		}
	}
}
src/glade/util/OracleUtils.java
public interface DiscriminativeOracle {
	public abstract boolean query(String query);
}
src/glade/grammar/GrammarUtils.java
public static class MultiAlternationNode implements Node {
	private final NodeData data;
	private final List<Node> children = new ArrayList<Node>();
	public MultiAlternationNode(NodeData data, List<Node> children) {
		this.data = data;
		this.children.addAll(children);
	}
	public List<Node> getChildren() {
		List<Node> newChildren = new ArrayList<Node>();
		newChildren.addAll(this.children);
		return newChildren;
	}
	public NodeData getData() {
		return this.data;
	}
	public String toString() {
		StringBuilder sb = new StringBuilder();
		for(Node child : this.children) {
			sb.append("(").append(child.toString()).append(")+");
		}
		return sb.substring(0, sb.length()-1);
	}
}
src/glade/grammar/GrammarUtils.java
public static class ConstantNode implements Node {
	private final NodeData data;
	public ConstantNode(NodeData data) {
		this.data = data;
	}
	public List<Node> getChildren() {
		return new ArrayList<Node>();
	}
	public NodeData getData() {
		return this.data;
	}
	public String toString() {
		return this.data.example;
	}
}
src/glade/grammar/GrammarUtils.java
public static interface Node {
	public abstract List<Node> getChildren();
	public abstract NodeData getData();
}
src/glade/grammar/GrammarUtils.java
public static final class Context {
	public final String pre;
	public final String post;
	public final String extraPre;
	public final String extraPost;
	public Context() {
		this.pre = "";
		this.post = "";
		this.extraPre = "";
		this.extraPost = "";
	}
	public Context(Context parent, String pre, String post, String extraPre, String extraPost) {
		this.pre = parent.pre + pre;
		this.post = post + parent.post;
		this.extraPre = parent.extraPre + extraPre;
		this.extraPost = extraPost + parent.extraPost;
	}
	public boolean useExtra() {
		return !this.pre.equals(this.extraPre) || !this.post.equals(this.extraPost);
	}
}
src/glade/util/Utils.java
public static class Maybe<T> {
	private T t;
	public Maybe(T t) {
		this.t = t;
	}
	public Maybe() {
		this.t = null;
	}
	public T getT() {
		if(this.t != null) {
			return t;
		}
		throw new RuntimeException("Invalid access!");
	}
	public boolean hasT() {
		return this.t != null;
	}
	public T getTOr(T t) {
		return this.hasT() ? this.getT() : t;
	}
}
src/glade/grammar/GrammarUtils.java
public static class MultiConstantNode implements Node {
	private final NodeData data;
	public final List<Set<Character>> characterOptions = new ArrayList<Set<Character>>();
	public final List<Set<Character>> characterChecks = new ArrayList<Set<Character>>();
	public MultiConstantNode(NodeData data, List<List<Character>> characterOptions, List<List<Character>> characterChecks) {
		this.data = data;
		if(characterOptions.size() != characterChecks.size()) {
			throw new RuntimeException("Invalid characters!");
		}
		for(List<Character> characters : characterOptions) {
			this.characterOptions.add(new LinkedHashSet<Character>(characters));
		}
		for(List<Character>characters : characterChecks) {
			this.characterChecks.add(new LinkedHashSet<Character>(characters));
		}
	}
	public List<Node> getChildren() {
		return new ArrayList<Node>();
	}
	public NodeData getData() {
		return this.data;
	}
	public String toString() {
		StringBuilder sb = new StringBuilder();
		for(Set<Character> characterOption : this.characterOptions) {
			sb.append("(");
			for(char character : characterOption) {
				sb.append(character).append("+");
			}
			sb.replace(sb.length()-1, sb.length(), ")");
		}
		return sb.toString();
	}
}


Question: import java.util.List;
import java.util.Set;
import glade.grammar.GrammarUtils.AlternationNode;
import glade.grammar.GrammarUtils.ConstantNode;
import glade.grammar.GrammarUtils.Context;
import glade.grammar.GrammarUtils.MultiAlternationNode;
import glade.grammar.GrammarUtils.MultiConstantNode;
import glade.grammar.GrammarUtils.Node;
import glade.grammar.GrammarUtils.RepetitionNode;
import glade.util.CharacterUtils;
import glade.util.Log;
import glade.util.CharacterUtils.CharacterGeneralization;
import glade.util.OracleUtils.DiscriminativeOracle;
import glade.util.Utils.Maybe;
import glade.util.Utils.MultivalueMap;
import java.util.ArrayList;
import java.util.HashSet;
// Copyright 2015-2016 Stanford University
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package glade.grammar.synthesize;



public class GrammarTransformer {
	public static Node getTransform(Node node, DiscriminativeOracle oracle) {
		Node transformFlatten = getTransform(node, new FlattenTransformer());
		return getTransform(transformFlatten, new ConstantTransformer(oracle, getMultiAlternationRepetitionConstantNodes(transformFlatten)));
	}
	
	private static interface NodeTransformer {
		public abstract Node transformConstant(ConstantNode node);
		public abstract Node transformMultiConstant(MultiConstantNode node);
		public abstract Node transformAlternation(AlternationNode node, Node newFirst, Node newSecond);
		public abstract Node transformRepetition(RepetitionNode node, Node newStart, Node newRep, Node newEnd);
Answer: 		public abstract Node transformMultiAlternation(MultiAlternationNode node, List<Node> newChildren);