import javax.imageio.*;
import java.awt.image.*;
import java.awt.event.*;
import java.awt.*;
import java.security.NoSuchAlgorithmException;
import java.security.MessageDigest;
import java.lang.reflect.*;
import java.net.*;
import java.io.*;
import javax.swing.text.*;
import javax.swing.event.*;
import javax.swing.*;
import java.util.concurrent.*;
import java.util.regex.*;
import java.util.List;
import java.util.zip.*;
import java.util.*;


public class main {
  static String sentence1 = "Yes is the opposite of no. No is the opposite of yes.";
  static String sentence2 = "Green is the opposite of white.";
  
  // Now uses TreeMap for nicer sorting (i.e., A must be a orderable type)
static class MultiSet<A> {
  Map<A, Integer> map = new TreeMap<A, Integer>();
  
  public MultiSet() {
  }
  
  public MultiSet(A key) {
    add(key);
  }

  public void add(A key) {
    add(key, 1);
  }

  public void add(A key, int count) {
    if (map.containsKey(key))
      map.put(key, map.get(key)+count);
    else
      map.put(key, count);
  }

  public int get(A key) {
    return map.containsKey(key) ? map.get(key) : 0;
  }

  public void remove(A key) {
    Integer i = map.get(key);
    if (i != null && i > 1)
      map.put(key, i - 1);
    else
      map.remove(key);
  }

  public List<A> getTopTen(int maxSize) {
    List<A> list = getSortedListDescending();
    return list.size() > maxSize ? list.subList(0, maxSize) : list;
  }

  public List<A> getSortedListDescending() {
    List<A> list = new ArrayList<A>(map.keySet());
    Collections.sort(list, new Comparator<A>() {
      public int compare(A a, A b) {
        return map.get(b).compareTo(map.get(a));
      }
    });
    return list;
  }

  public int getNumberOfUniqueElements() {
    return map.size();
  }

  public Set<A> asSet() {
    return map.keySet();
  }

  public A getMostPopularEntry() {
    int max = 0;
    A a = null;
    for (Map.Entry<A,Integer> entry : map.entrySet()) {
      if (entry.getValue() > max) {
        max = entry.getValue();
        a = entry.getKey();
      }
    }
    return a;
  }

  public void removeAll(A key) {
    map.remove(key);
  }

  /*public A getRandomEntry(Randomizer rand) {
    int total = size(), n = rand.getRandomNumber(total);

    for (Map.Entry<A,Integer> entry : map.entrySet()) {
      n -= entry.getValue();
      if (n < 0)
        return entry.getKey();
    }

    throw new RuntimeException("huch");
  }*/

  public int size() {
    int size = 0;
    for (int i : map.values())
      size += i;
    return size;
  }

  public MultiSet<A> mergeWith(MultiSet<A> set) {
    MultiSet<A> result = new MultiSet<A>();
    for (A a : set.asSet()) {
      result.add(a, set.get(a));
    }
    return result;
  }
  
  public boolean isEmpty() {
    return map.isEmpty();
  }
} // MultiSet
  
  public static void main(String[] args) throws Exception {
    List<String> tok1 = parse(sentence1);
    List<String> tok2 = parse(sentence2);
    
    Map<String, MultiSet<String>> map = makeMMapPrefix(tok1, tok2);
    if (map == null)
      print("No match.");
    else
      print(structure(map));
      
    print(complete(sentence1, sentence2));
  }
  
  static List<String> parse(String s) {
    return tokensToLowerCase(javaTok(s));
  }
  
  static String complete(String sentence1, String sentence2) {
    List<String> tok1 = parse(sentence1);
    List<String> tok2 = parse(sentence2);
    Map<String, MultiSet<String>> map = makeMMapPrefix(tok1, tok2);
    if (map == null) return null;
    List<String> tok = new ArrayList<String>();
    tok.addAll(tok2.subList(0, tok2.size()-1));
    for (int i = tok2.size()-1; i < tok1.size(); i++) {
      String t = tok1.get(i);
      MultiSet<String> set = map.get(t);
      tok.add(set == null ? t : set.getMostPopularEntry());
    }
    return join(tok);
  }
  
  static Map<String, MultiSet<String>> makeMMapPrefix(List<String> tok1, List<String> tok2) {
    if (tok1.size() < tok2.size()) return null;
    
    Map<String, MultiSet<String>> map = new TreeMap<String, MultiSet<String>>();
    for (int i = 1; i < tok2.size(); i += 2) {
      String t1 = tok1.get(i), t2 = tok2.get(i);
      MultiSet<String> set = map.get(t1);
      if (set == null)
        map.put(t1, new MultiSet<String>(t2));
      else
        set.add(t2);
    }
    
    // match succeeds
    return map;
  }

static List<String> tokensToLowerCase(List<String> tok) {
  tok = new ArrayList<String>(tok);
  for (int i = 1; i < tok.size(); i += 2)
    tok.set(i, tok.get(i).toLowerCase());
  return tok;
}

// replacement for class JavaTok
// maybe incomplete, might want to add floating point numbers
// todo also: extended multi-line strings

static List<String> javaTok(String s) {
  List<String> tok = new ArrayList<String>();
  int l = s.length();
  
  int i = 0;
  while (i < l) {
    int j = i;
    char c; String cc;
    
    // scan for whitespace
    while (j < l) {
      c = s.charAt(j);
      cc = s.substring(j, Math.min(j+2, l));
      if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
        ++j;
      else if (cc.equals("/*")) {
        do ++j; while (j < l && !s.substring(j, Math.min(j+2, l)).equals("*/"));
        j = Math.min(j+2, l);
      } else if (cc.equals("//")) {
        do ++j; while (j < l && "\r\n".indexOf(s.charAt(j)) < 0);
      } else
        break;
    }
    
    tok.add(s.substring(i, j));
    i = j;
    if (i >= l) break;
    c = s.charAt(i); // cc is not needed in rest of loop body
    cc = s.substring(i, Math.min(i+2, l));

    // scan for non-whitespace
    if (c == '\'' || c == '"') {
      char opener = c;
      ++j;
      while (j < l) {
        if (s.charAt(j) == opener) {
          ++j;
          break;
        } else if (s.charAt(j) == '\\' && j+1 < l)
          j += 2;
        else
          ++j;
      }
    } else if (Character.isJavaIdentifierStart(c))
      do ++j; while (j < l && Character.isJavaIdentifierPart(s.charAt(j)));
    else if (Character.isDigit(c))
      do ++j; while (j < l && Character.isDigit(s.charAt(j)));
    else if (cc.equals("[[")) {
      do ++j; while (j+1 < l && !s.substring(j, j+2).equals("]]"));
      j = Math.min(j+2, l);
    } else
      ++j;

    tok.add(s.substring(i, j));
    i = j;
  }
  
  if ((tok.size() % 2) == 0) tok.add("");
  return tok;
}


static void print() {
  System.out.println();
}

static void print(Object o) {
  System.out.println(o);
}

static void print(long i) {
  System.out.println(i);
}

  static void set(Class c, String field, Object value) {
    try {
      Field f = set_findStaticField(c, field);
      f.setAccessible(true);
      f.set(null, value);
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }
  
  static Field set_findStaticField(Class<?> c, String field) {
    for (Field f : c.getDeclaredFields())
      if (f.getName().equals(field) && (f.getModifiers() & Modifier.STATIC) != 0)
        return f;
    throw new RuntimeException("Static field '" + field + "' not found in " + c.getName());
  }

  public static String join(String glue, Iterable<String> strings) {
    StringBuilder buf = new StringBuilder();
    Iterator<String> i = strings.iterator();
    if (i.hasNext()) {
      buf.append(i.next());
      while (i.hasNext())
        buf.append(glue).append(i.next());
    }
    return buf.toString();
  }
  
  public static String join(String glue, String[] strings) {
    return join(glue, Arrays.asList(strings));
  }
  
  public static String join(Iterable<String> strings) {
    return join("", strings);
  }
  
  public static String join(String[] strings) {
    return join("", strings);
  }


static Object get(Object o, String field) {
  if (o instanceof Class) return get((Class) o, field);
  try {
    Field f = get_findField(o.getClass(), field);
    f.setAccessible(true);
    return f.get(o);
  } catch (Exception e) {
    throw new RuntimeException(e);
  }
}

static Object get(Class c, String field) {
  try {
    Field f = get_findStaticField(c, field);
    f.setAccessible(true);
    return f.get(null);
  } catch (Exception e) {
    throw new RuntimeException(e);
  }
}

static Field get_findStaticField(Class<?> c, String field) {
  for (Field f : c.getDeclaredFields())
    if (f.getName().equals(field) && (f.getModifiers() & Modifier.STATIC) != 0)
      return f;
  throw new RuntimeException("Static field '" + field + "' not found in " + c.getName());
}

static Field get_findField(Class<?> c, String field) {
  for (Field f : c.getDeclaredFields())
    if (f.getName().equals(field))
      return f;
  throw new RuntimeException("Field '" + field + "' not found in " + c.getName());
}

static String structure(Object o) {
  return structure(o, 0);
}
  
static String structure(Object o, int stringSizeLimit) {
  if (o == null) return "null";
  String name = o.getClass().getName();
  
  StringBuilder buf = new StringBuilder();
  
  if (o instanceof Collection) {
    for (Object x : (Collection) o) {
      if (buf.length() != 0) buf.append(", ");
      buf.append(structure(x, stringSizeLimit));
    }
    return "{" + buf + "}";
  }
  
  if (o instanceof Map) {
    for (Object e : ((Map) o).entrySet()) {
      if (buf.length() != 0) buf.append(", ");
      buf.append(structure(((Map.Entry) e).getKey(), stringSizeLimit));
      buf.append("=");
      buf.append(structure(((Map.Entry) e).getValue(), stringSizeLimit));
    }
    return "{" + buf + "}";
  }
  
  if (o.getClass().isArray()) {
    int n = Array.getLength(o);
    for (int i = 0; i < n; i++) {
      if (buf.length() != 0) buf.append(", ");
      buf.append(structure(Array.get(o, i), stringSizeLimit));
    }
    return "{" + buf + "}";
  }

  if (o instanceof String)
    return quote(stringSizeLimit != 0 ? shorten((String) o, stringSizeLimit) : (String) o);
  
  // Need more cases? This should cover all library classes...
  if (name.startsWith("java.") || name.startsWith("javax."))
    return String.valueOf(o);
    
  String shortName = o.getClass().getName().replaceAll("^main\\$", "");

  // TODO: go to superclasses too
  Field[] fields = o.getClass().getDeclaredFields();
  int numFields = 0;
  String fieldName = "";
  for (Field field : fields) {
    if ((field.getModifiers() & Modifier.STATIC) != 0)
      continue;
    Object value;
    try {
      value = field.get(o);
    } catch (Exception e) {
      value = "?";
    }
    
    fieldName = field.getName();
    
    // put special cases here...

    if (value != null) {
      if (buf.length() != 0) buf.append(", ");
      buf.append(fieldName + "=" + structure(value, stringSizeLimit));
    }
    ++numFields;
  }
  String b = buf.toString();
  if (numFields == 1)
    b = b.replaceAll("^" + fieldName + "=", ""); // drop field name if only one
  String s = shortName;
  if (buf.length() != 0)
    s += "(" + b + ")";
  return s;
}

  public static String quote(String s) {
    if (s == null) return "null";
    return "\"" + s.replace("\\", "\\\\").replace("\"", "\\\"").replace("\r", "\\r").replace("\n", "\\n") + "\"";
  }

static String shorten(String s, int max) {
  return s.length() <= max ? s : s.substring(0, Math.min(s.length(), max)) + "...";
}
}