static void optimize(final File f, final File d, final Remapper remapper)
			throws IOException {
		if (f.isDirectory()) {
			File[] files = f.listFiles();
			for (int i = 0; i < files.length; ++i) {
				optimize(files[i], d, remapper);
			}
		} else if (f.getName().endsWith(".class")) {
			ConstantPool cp = new ConstantPool();
			ClassReader cr = new ClassReader(new FileInputStream(f));
			ClassWriter cw = new ClassWriter(0);
			ClassConstantsCollector ccc = new ClassConstantsCollector(cw, cp);
			ClassOptimizer co = new ClassOptimizer(ccc, remapper);
			cr.accept(co, ClassReader.SKIP_DEBUG);

			Set constants = new TreeSet(new ConstantComparator());
			constants.addAll(cp.values());

			cr = new ClassReader(cw.toByteArray());
			cw = new ClassWriter(0);
			Iterator i = constants.iterator();
			while (i.hasNext()) {
				Constant c = (Constant) i.next();
				c.write(cw);
			}
			cr.accept(cw, ClassReader.SKIP_DEBUG);

			if (MAPPING.getProperty(cr.getClassName() + "/remove") != null) {
				return;
			}
			String n = remapper.mapType(cr.getClassName());
			File g = new File(d, n + ".class");
			if (!g.exists() || g.lastModified() < f.lastModified()) {
				g.getParentFile().mkdirs();
				OutputStream os = new FileOutputStream(g);
				os.write(cw.toByteArray());
				os.close();
			}
		}
	}