private void performRandomization(final String filename, final long seed,
			byte[] trainerClasses, byte[] trainerNames, byte[] nicknames) {

		final boolean raceMode = raceModeCB.isSelected();
		int checkValue = 0;
		final long startTime = System.currentTimeMillis();
		// Setup verbose log
		final ByteArrayOutputStream baos = new ByteArrayOutputStream();
		String nl = System.getProperty("line.separator");
		try {
			verboseLog = new PrintStream(baos, false, "UTF-8");
		} catch (UnsupportedEncodingException e) {
			verboseLog = new PrintStream(baos);
		}
		try {
			// limit pokemon?
			if (this.pokeLimitCB.isSelected()) {
				romHandler.setPokemonPool(currentRestrictions);
				romHandler.removeEvosForPokemonPool();
			}

			// Update type effectiveness in RBY?
			if (romHandler instanceof Gen1RomHandler
					&& this.goUpdateTypesCheckBox.isSelected()) {
				romHandler.fixTypeEffectiveness();
			}

			// Move updates
			if (this.goUpdateMovesCheckBox.isSelected()) {
				romHandler.initMoveUpdates();
				if (!(romHandler instanceof Gen5RomHandler)) {
					romHandler.updateMovesToGen5();
				}
				if (!this.goUpdateMovesLegacyCheckBox.isSelected()) {
					romHandler.updateMovesToGen6();
				}
				romHandler.printMoveUpdates();
			}

			List<Move> moves = romHandler.getMoves();

			// Trade evolutions removal
			if (this.goRemoveTradeEvosCheckBox.isSelected()) {
				romHandler.removeTradeEvolutions(!this.pmsUnchangedRB
						.isSelected());
			}

			// Camel case?
			if (!(romHandler instanceof Gen5RomHandler)
					&& !(romHandler instanceof Gen4RomHandler)
					&& this.goLowerCaseNamesCheckBox.isSelected()) {
				romHandler.applyCamelCaseNames();
			}

			// National dex gen3?
			if (romHandler instanceof Gen3RomHandler
					&& this.goNationalDexCheckBox.isSelected()) {
				romHandler.patchForNationalDex();
			}

			// Code Tweaks?
			if (romHandler.codeTweaksAvailable() != 0) {
				int ctavailable = romHandler.codeTweaksAvailable();
				if ((ctavailable & CodeTweaks.BW_EXP_PATCH) > 0
						&& (currentCodeTweaks & CodeTweaks.BW_EXP_PATCH) > 0) {
					romHandler.applyBWEXPPatch();
				}

				if ((ctavailable & CodeTweaks.FIX_CRIT_RATE) > 0
						&& (currentCodeTweaks & CodeTweaks.FIX_CRIT_RATE) > 0) {
					romHandler.applyCritRatePatch();
				}

				if ((ctavailable & CodeTweaks.NERF_X_ACCURACY) > 0
						&& (currentCodeTweaks & CodeTweaks.NERF_X_ACCURACY) > 0) {
					romHandler.applyXAccNerfPatch();
				}
			}

			// Hollows?
			if (romHandler.hasHiddenHollowPokemon()
					&& this.randomizeHollowsCB.isSelected()) {
				romHandler.randomizeHiddenHollowPokemon();
			}

			List<Pokemon> allPokes = romHandler.getPokemon();

			// Base stats changing
			if (this.pbsChangesShuffleRB.isSelected()) {
				romHandler.shufflePokemonStats();
			} else if (this.pbsChangesRandomEvosRB.isSelected()) {
				romHandler.randomizePokemonStats(true);
			} else if (this.pbsChangesRandomTotalRB.isSelected()) {
				romHandler.randomizePokemonStats(false);
			}

			if (this.pbsStandardEXPCurvesCB.isSelected()) {
				romHandler.standardizeEXPCurves();
			}

			// Abilities? (new 1.0.2)
			if (this.romHandler.abilitiesPerPokemon() > 0
					&& this.paRandomizeRB.isSelected()) {
				romHandler
						.randomizeAbilities(this.paWonderGuardCB.isSelected());
			}

			// Pokemon Types
			if (this.ptRandomFollowEvosRB.isSelected()) {
				romHandler.randomizePokemonTypes(true);
			} else if (this.ptRandomTotalRB.isSelected()) {
				romHandler.randomizePokemonTypes(false);
			}

			// Wild Held Items?
			String[] itemNames = romHandler.getItemNames();
			if (this.wpHeldItemsCB.isSelected()) {
				romHandler.randomizeWildHeldItems();
			}

			// Log base stats & types if changed at all
			if (this.pbsChangesUnchangedRB.isSelected()
					&& this.ptUnchangedRB.isSelected()
					&& this.paUnchangedRB.isSelected()
					&& this.wpHeldItemsCB.isSelected() == false) {
				verboseLog.println("Pokemon base stats & type: unchanged" + nl);
			} else {
				verboseLog.println("--Pokemon Base Stats & Types--");
				if (romHandler instanceof Gen1RomHandler) {
					verboseLog
							.println("NUM|NAME      |TYPE             |  HP| ATK| DEF| SPE|SPEC");
					for (Pokemon pkmn : allPokes) {
						if (pkmn != null) {
							String typeString = pkmn.primaryType == null ? "NULL"
									: pkmn.primaryType.toString();
							if (pkmn.secondaryType != null) {
								typeString += "/"
										+ (pkmn.secondaryType == null ? "NULL"
												: pkmn.secondaryType.toString());
							}
							verboseLog.printf(
									"%3d|%-10s|%-17s|%4d|%4d|%4d|%4d|%4d" + nl,
									pkmn.number, pkmn.name, typeString,
									pkmn.hp, pkmn.attack, pkmn.defense,
									pkmn.speed, pkmn.special);
						}

					}
				} else {
					verboseLog
							.print("NUM|NAME      |TYPE             |  HP| ATK| DEF| SPE|SATK|SDEF");
					int abils = romHandler.abilitiesPerPokemon();
					for (int i = 0; i < abils; i++) {
						verboseLog.print("|ABILITY" + (i + 1) + "    ");
					}
					verboseLog.print("|ITEM");
					verboseLog.println();
					for (Pokemon pkmn : allPokes) {
						if (pkmn != null) {
							String typeString = pkmn.primaryType.toString();
							if (pkmn.secondaryType != null) {
								typeString += "/"
										+ pkmn.secondaryType.toString();
							}
							verboseLog.printf(
									"%3d|%-10s|%-17s|%4d|%4d|%4d|%4d|%4d|%4d",
									pkmn.number, pkmn.name, typeString,
									pkmn.hp, pkmn.attack, pkmn.defense,
									pkmn.speed, pkmn.spatk, pkmn.spdef);
							if (abils > 0) {
								verboseLog.printf("|%-12s|%-12s",
										romHandler.abilityName(pkmn.ability1),
										romHandler.abilityName(pkmn.ability2));
								if (abils > 2) {
									verboseLog.printf("|%-12s", romHandler
											.abilityName(pkmn.ability3));
								}
							}
							verboseLog.print("|");
							if (pkmn.guaranteedHeldItem > 0) {
								verboseLog
										.print(itemNames[pkmn.guaranteedHeldItem]
												+ " (100%)");
							} else {
								int itemCount = 0;
								if (pkmn.commonHeldItem > 0) {
									itemCount++;
									verboseLog
											.print(itemNames[pkmn.commonHeldItem]
													+ " (common)");
								}
								if (pkmn.rareHeldItem > 0) {
									if (itemCount > 0) {
										verboseLog.print(", ");
									}
									itemCount++;
									verboseLog
											.print(itemNames[pkmn.rareHeldItem]
													+ " (rare)");
								}
								if (pkmn.darkGrassHeldItem > 0) {
									if (itemCount > 0) {
										verboseLog.print(", ");
									}
									itemCount++;
									verboseLog
											.print(itemNames[pkmn.darkGrassHeldItem]
													+ " (dark grass only)");
								}
							}
							verboseLog.println();
						}

					}
				}
				if (raceMode) {
					for (Pokemon pkmn : allPokes) {
						if (pkmn != null) {
							checkValue = addToCV(checkValue, pkmn.hp,
									pkmn.attack, pkmn.defense, pkmn.speed,
									pkmn.spatk, pkmn.spdef, pkmn.ability1,
									pkmn.ability2, pkmn.ability3);
						}
					}
				}
				verboseLog.println();
			}

			// Starter Pokemon
			// Applied after type to update the strings correctly based on new
			// types
			if (romHandler.canChangeStarters()) {
				if (this.spCustomRB.isSelected()) {
					verboseLog.println("--Custom Starters--");
					Pokemon pkmn1 = allPokes.get(this.spCustomPoke1Chooser
							.getSelectedIndex() + 1);
					verboseLog.println("Set starter 1 to " + pkmn1.name);
					Pokemon pkmn2 = allPokes.get(this.spCustomPoke2Chooser
							.getSelectedIndex() + 1);
					verboseLog.println("Set starter 2 to " + pkmn2.name);
					if (romHandler.isYellow()) {
						romHandler.setStarters(Arrays.asList(pkmn1, pkmn2));
					} else {
						Pokemon pkmn3 = allPokes.get(this.spCustomPoke3Chooser
								.getSelectedIndex() + 1);
						verboseLog.println("Set starter 3 to " + pkmn3.name);
						romHandler.setStarters(Arrays.asList(pkmn1, pkmn2,
								pkmn3));
					}
					verboseLog.println();

				} else if (this.spRandomRB.isSelected()) {
					// Randomise
					verboseLog.println("--Random Starters--");
					int starterCount = 3;
					if (romHandler.isYellow()) {
						starterCount = 2;
					}
					List<Pokemon> starters = new ArrayList<Pokemon>();
					for (int i = 0; i < starterCount; i++) {
						Pokemon pkmn = romHandler.randomPokemon();
						while (starters.contains(pkmn)) {
							pkmn = romHandler.randomPokemon();
						}
						verboseLog.println("Set starter " + (i + 1) + " to "
								+ pkmn.name);
						starters.add(pkmn);
					}
					romHandler.setStarters(starters);
					verboseLog.println();
				} else if (this.spRandom2EvosRB.isSelected()) {
					// Randomise
					verboseLog.println("--Random 2-Evolution Starters--");
					int starterCount = 3;
					if (romHandler.isYellow()) {
						starterCount = 2;
					}
					List<Pokemon> starters = new ArrayList<Pokemon>();
					for (int i = 0; i < starterCount; i++) {
						Pokemon pkmn = romHandler.random2EvosPokemon();
						while (starters.contains(pkmn)) {
							pkmn = romHandler.random2EvosPokemon();
						}
						verboseLog.println("Set starter " + (i + 1) + " to "
								+ pkmn.name);
						starters.add(pkmn);
					}
					romHandler.setStarters(starters);
					verboseLog.println();
				}
				if (this.spHeldItemsCB.isSelected()
						&& (romHandler instanceof Gen1RomHandler) == false) {
					romHandler.randomizeStarterHeldItems();
				}
			}

			// Movesets
			boolean noBrokenMoves = this.brokenMovesCB.isSelected();
			boolean forceFourLv1s = (romHandler instanceof Gen1RomHandler)
					&& this.pmsGen14MovesCB.isSelected();
			if (this.pmsRandomTypeRB.isSelected()) {
				romHandler.randomizeMovesLearnt(true, noBrokenMoves,
						forceFourLv1s);
			} else if (this.pmsRandomTotalRB.isSelected()) {
				romHandler.randomizeMovesLearnt(false, noBrokenMoves,
						forceFourLv1s);
			}

			// Show the new movesets if applicable
			if (this.pmsUnchangedRB.isSelected()) {
				verboseLog.println("Pokemon Movesets: Unchanged." + nl);
			} else if (this.pmsMetronomeOnlyRB.isSelected()) {
				verboseLog.println("Pokemon Movesets: Metronome Only." + nl);
			} else {
				verboseLog.println("--Pokemon Movesets--");
				List<String> movesets = new ArrayList<String>();
				Map<Pokemon, List<MoveLearnt>> moveData = romHandler
						.getMovesLearnt();
				for (Pokemon pkmn : moveData.keySet()) {
					StringBuilder sb = new StringBuilder();
					sb.append(String.format("%03d %-10s : ", pkmn.number,
							pkmn.name));
					List<MoveLearnt> data = moveData.get(pkmn);
					boolean first = true;
					for (MoveLearnt ml : data) {
						if (!first) {
							sb.append(", ");
						}

						sb.append(moves.get(ml.move).name + " at level "
								+ ml.level);
						first = false;
					}
					movesets.add(sb.toString());
				}
				Collections.sort(movesets);
				for (String moveset : movesets) {
					verboseLog.println(moveset);
				}
				verboseLog.println();
			}

			// Trainer Pokemon
			if (this.tpRandomRB.isSelected()) {
				romHandler.randomizeTrainerPokes(
						this.tpRivalCarriesStarterCB.isSelected(),
						this.tpPowerLevelsCB.isSelected(),
						this.tpNoLegendariesCB.isSelected(),
						this.tpNoEarlyShedinjaCB.isSelected());
			} else if (this.tpTypeThemedRB.isSelected()) {
				romHandler.typeThemeTrainerPokes(
						this.tpRivalCarriesStarterCB.isSelected(),
						this.tpPowerLevelsCB.isSelected(),
						this.tpTypeWeightingCB.isSelected(),
						this.tpNoLegendariesCB.isSelected(),
						this.tpNoEarlyShedinjaCB.isSelected());
			}

			// Trainer names & class names randomization
			// done before trainer log to add proper names

			if (this.tcnRandomizeCB.isSelected()) {
				romHandler.randomizeTrainerClassNames(trainerClasses);
			}

			if (this.tnRandomizeCB.isSelected()) {
				romHandler.randomizeTrainerNames(trainerNames);
			}

			if (this.tpUnchangedRB.isSelected()) {
				verboseLog.println("Trainers: Unchanged." + nl);
			} else {
				verboseLog.println("--Trainers Pokemon--");
				List<Trainer> trainers = romHandler.getTrainers();
				int idx = 0;
				for (Trainer t : trainers) {
					idx++;
					verboseLog.print("#" + idx + " ");
					if (t.fullDisplayName != null) {
						verboseLog.print("(" + t.fullDisplayName + ")");
					} else if (t.name != null) {
						verboseLog.print("(" + t.name + ")");
					}
					if (t.offset != idx && t.offset != 0) {
						verboseLog.printf("@%X", t.offset);
					}
					verboseLog.print(" - ");
					boolean first = true;
					for (TrainerPokemon tpk : t.pokemon) {
						if (!first) {
							verboseLog.print(", ");
						}
						verboseLog.print(tpk.pokemon.name + " Lv" + tpk.level);
						first = false;
					}
					verboseLog.println();
				}
				verboseLog.println();
			}

			// Apply metronome only mode now that trainers have been dealt with
			if (pmsMetronomeOnlyRB.isSelected()) {
				romHandler.metronomeOnlyMode();
			}

			if (raceMode) {
				List<Trainer> trainers = romHandler.getTrainers();
				for (Trainer t : trainers) {
					for (TrainerPokemon tpk : t.pokemon) {
						checkValue = addToCV(checkValue, tpk.level,
								tpk.pokemon.number);
					}
				}
			}

			// Wild Pokemon
			// actually call this code (Kappa)
			if (this.wpCatchRateCB.isSelected()) {
				if (romHandler instanceof Gen5RomHandler) {
					romHandler.minimumCatchRate(50, 25);
				} else {
					romHandler.minimumCatchRate(75, 37);
				}
			}
			if (this.wpRandomRB.isSelected()) {
				romHandler.randomEncounters(this.wpUseTimeCB.isSelected(),
						this.wpARCatchEmAllRB.isSelected(),
						this.wpARTypeThemedRB.isSelected(),
						this.wpARSimilarStrengthRB.isSelected(),
						this.wpNoLegendariesCB.isSelected());
			} else if (this.wpArea11RB.isSelected()) {
				romHandler.area1to1Encounters(this.wpUseTimeCB.isSelected(),
						this.wpARCatchEmAllRB.isSelected(),
						this.wpARTypeThemedRB.isSelected(),
						this.wpARSimilarStrengthRB.isSelected(),
						this.wpNoLegendariesCB.isSelected());
			} else if (this.wpGlobalRB.isSelected()) {
				romHandler.game1to1Encounters(this.wpUseTimeCB.isSelected(),
						this.wpARSimilarStrengthRB.isSelected(),
						this.wpNoLegendariesCB.isSelected());
			}

			if (this.wpUnchangedRB.isSelected()) {
				verboseLog.println("Wild Pokemon: Unchanged." + nl);
			} else {
				verboseLog.println("--Wild Pokemon--");
				List<EncounterSet> encounters = romHandler
						.getEncounters(this.wpUseTimeCB.isSelected());
				int idx = 0;
				for (EncounterSet es : encounters) {
					idx++;
					verboseLog.print("Set #" + idx + " ");
					if (es.displayName != null) {
						verboseLog.print("- " + es.displayName + " ");
					}
					verboseLog.print("(rate=" + es.rate + ")");
					verboseLog.print(" - ");
					boolean first = true;
					for (Encounter e : es.encounters) {
						if (!first) {
							verboseLog.print(", ");
						}
						verboseLog.print(e.pokemon.name + " Lv");
						if (e.maxLevel > 0 && e.maxLevel != e.level) {
							verboseLog.print("s " + e.level + "-" + e.maxLevel);
						} else {
							verboseLog.print(e.level);
						}
						first = false;
					}
					verboseLog.println();
				}
				verboseLog.println();
			}

			if (raceMode) {
				List<EncounterSet> encounters = romHandler
						.getEncounters(this.wpUseTimeCB.isSelected());
				for (EncounterSet es : encounters) {
					for (Encounter e : es.encounters) {
						checkValue = addToCV(checkValue, e.level,
								e.pokemon.number);
					}
				}
			}

			// Static Pokemon

			if (romHandler.canChangeStaticPokemon()) {
				List<Pokemon> oldStatics = romHandler.getStaticPokemon();
				if (this.stpRandomL4LRB.isSelected()) {
					romHandler.randomizeStaticPokemon(true);
				} else if (this.stpRandomTotalRB.isSelected()) {
					romHandler.randomizeStaticPokemon(false);
				}
				List<Pokemon> newStatics = romHandler.getStaticPokemon();
				if (this.stpUnchangedRB.isSelected()) {
					verboseLog.println("Static Pokemon: Unchanged." + nl);
				} else {
					verboseLog.println("--Static Pokemon--");
					Map<Pokemon, Integer> seenPokemon = new TreeMap<Pokemon, Integer>();
					for (int i = 0; i < oldStatics.size(); i++) {
						Pokemon oldP = oldStatics.get(i);
						Pokemon newP = newStatics.get(i);
						if (raceMode) {
							checkValue = addToCV(checkValue, newP.number);
						}
						verboseLog.print(oldP.name);
						if (seenPokemon.containsKey(oldP)) {
							int amount = seenPokemon.get(oldP);
							verboseLog.print("(" + (++amount) + ")");
							seenPokemon.put(oldP, amount);
						} else {
							seenPokemon.put(oldP, 1);
						}
						verboseLog.println(" => " + newP.name);
					}
					verboseLog.println();
				}
			}

			// TMs
			if (!pmsMetronomeOnlyRB.isSelected()
					&& this.tmmRandomRB.isSelected()) {
				romHandler.randomizeTMMoves(noBrokenMoves);
				verboseLog.println("--TM Moves--");
				List<Integer> tmMoves = romHandler.getTMMoves();
				for (int i = 0; i < tmMoves.size(); i++) {
					verboseLog.printf("TM%02d %s" + nl, i + 1,
							moves.get(tmMoves.get(i)).name);
					if (raceMode) {
						checkValue = addToCV(checkValue, tmMoves.get(i));
					}
				}
				verboseLog.println();
			} else if (pmsMetronomeOnlyRB.isSelected()) {
				verboseLog.println("TM Moves: Metronome Only." + nl);
			} else {
				verboseLog.println("TM Moves: Unchanged." + nl);
			}

			// TM/HM compatibility
			if (this.thcRandomTypeRB.isSelected()) {
				romHandler.randomizeTMHMCompatibility(true);
			} else if (this.thcRandomTotalRB.isSelected()) {
				romHandler.randomizeTMHMCompatibility(false);
			}

			// Move Tutors (new 1.0.3)
			if (this.romHandler.hasMoveTutors()) {
				if (!pmsMetronomeOnlyRB.isSelected()
						&& this.mtmRandomRB.isSelected()) {
					List<Integer> oldMtMoves = romHandler.getMoveTutorMoves();
					romHandler.randomizeMoveTutorMoves(noBrokenMoves);
					verboseLog.println("--Move Tutor Moves--");
					List<Integer> newMtMoves = romHandler.getMoveTutorMoves();
					for (int i = 0; i < newMtMoves.size(); i++) {
						verboseLog.printf("%s => %s" + nl,
								moves.get(oldMtMoves.get(i)).name,
								moves.get(newMtMoves.get(i)).name);
						if (raceMode) {
							checkValue = addToCV(checkValue, newMtMoves.get(i));
						}
					}
					verboseLog.println();
				} else if (pmsMetronomeOnlyRB.isSelected()) {
					verboseLog
							.println("Move Tutor Moves: Metronome Only." + nl);
				} else {
					verboseLog.println("Move Tutor Moves: Unchanged." + nl);
				}

				// Compatibility
				if (this.mtcRandomTypeRB.isSelected()) {
					romHandler.randomizeMoveTutorCompatibility(true);
				} else if (this.mtcRandomTotalRB.isSelected()) {
					romHandler.randomizeMoveTutorCompatibility(false);
				}
			}

			// In-game trades
			List<IngameTrade> oldTrades = romHandler.getIngameTrades();
			if (this.igtGivenOnlyRB.isSelected()) {
				romHandler.randomizeIngameTrades(false, nicknames,
						this.igtRandomNicknameCB.isSelected(), trainerNames,
						this.igtRandomOTCB.isSelected(),
						this.igtRandomIVsCB.isSelected(),
						this.igtRandomItemCB.isSelected());
			} else if (this.igtBothRB.isSelected()) {
				romHandler.randomizeIngameTrades(true, nicknames,
						this.igtRandomNicknameCB.isSelected(), trainerNames,
						this.igtRandomOTCB.isSelected(),
						this.igtRandomIVsCB.isSelected(),
						this.igtRandomItemCB.isSelected());
			}

			if (!this.igtUnchangedRB.isSelected()) {
				verboseLog.println("--In-Game Trades--");
				List<IngameTrade> newTrades = romHandler.getIngameTrades();
				int size = oldTrades.size();
				for (int i = 0; i < size; i++) {
					IngameTrade oldT = oldTrades.get(i);
					IngameTrade newT = newTrades.get(i);
					verboseLog.printf(
							"Trading %s for %s the %s has become trading %s for %s the %s"
									+ nl, oldT.requestedPokemon.name,
							oldT.nickname, oldT.givenPokemon.name,
							newT.requestedPokemon.name, newT.nickname,
							newT.givenPokemon.name);
				}
				verboseLog.println();
			}

			// Field Items
			if (this.fiShuffleRB.isSelected()) {
				romHandler.shuffleFieldItems();
			} else if (this.fiRandomRB.isSelected()) {
				romHandler.randomizeFieldItems();
			}

			// Signature...
			romHandler.applySignature();

			// Save
			final int finishedCV = checkValue;
			opDialog = new OperationDialog(
					bundle.getString("RandomizerGUI.savingText"), this, true);
			Thread t = new Thread() {
				@Override
				public void run() {
					SwingUtilities.invokeLater(new Runnable() {
						@Override
						public void run() {
							opDialog.setVisible(true);
						}
					});
					boolean succeededSave = false;
					try {
						RandomizerGUI.this.romHandler.saveRom(filename);
						succeededSave = true;
					} catch (Exception ex) {
						long time = System.currentTimeMillis();
						try {
							String errlog = "error_" + time + ".txt";
							PrintStream ps = new PrintStream(
									new FileOutputStream(errlog));
							PrintStream e1 = System.err;
							System.setErr(ps);
							ex.printStackTrace();
							verboseLog.close();
							System.setErr(e1);
							ps.close();
							JOptionPane
									.showMessageDialog(
											RandomizerGUI.this,
											String.format(
													bundle.getString("RandomizerGUI.saveFailedIO"),
													errlog));
						} catch (Exception logex) {
							JOptionPane
									.showMessageDialog(
											RandomizerGUI.this,
											bundle.getString("RandomizerGUI.saveFailedIONoLog"));
							verboseLog.close();
						}
					}
					if (succeededSave) {
						SwingUtilities.invokeLater(new Runnable() {
							@Override
							public void run() {
								RandomizerGUI.this.opDialog.setVisible(false);
								// Log tail
								verboseLog
										.println("------------------------------------------------------------------");
								verboseLog.println("Randomization of "
										+ romHandler.getROMName()
										+ " completed.");
								verboseLog.println("Time elapsed: "
										+ (System.currentTimeMillis() - startTime)
										+ "ms");
								verboseLog.println("RNG Calls: "
										+ RandomSource.callsSinceSeed());
								verboseLog
										.println("------------------------------------------------------------------");

								// Log?
								verboseLog.close();
								byte[] out = baos.toByteArray();
								verboseLog = System.out;

								if (raceMode) {
									JOptionPane.showMessageDialog(
											RandomizerGUI.this,
											String.format(
													bundle.getString("RandomizerGUI.raceModeCheckValuePopup"),
													finishedCV));
								} else {
									int response = JOptionPane.showConfirmDialog(
											RandomizerGUI.this,
											bundle.getString("RandomizerGUI.saveLogDialog.text"),
											bundle.getString("RandomizerGUI.saveLogDialog.title"),
											JOptionPane.YES_NO_OPTION);
									if (response == JOptionPane.YES_OPTION) {
										try {
											FileOutputStream fos = new FileOutputStream(
													filename + ".log");
											fos.write(0xEF);
											fos.write(0xBB);
											fos.write(0xBF);
											fos.write(out);
											fos.close();
										} catch (IOException e) {
											JOptionPane.showMessageDialog(
													RandomizerGUI.this,
													bundle.getString("RandomizerGUI.logSaveFailed"));
											return;
										}
										JOptionPane.showMessageDialog(
												RandomizerGUI.this,
												String.format(
														bundle.getString("RandomizerGUI.logSaved"),
														filename));
									}
								}
								if (presetMode) {
									JOptionPane.showMessageDialog(
											RandomizerGUI.this,
											bundle.getString("RandomizerGUI.randomizationDone"));
									// Done
									RandomizerGUI.this.romHandler = null;
									initialFormState();
								} else {
									// Compile a config string
									String configString = getConfigString();
									// Show the preset maker
									new PresetMakeDialog(RandomizerGUI.this,
											seed, configString);

									// Done
									RandomizerGUI.this.romHandler = null;
									initialFormState();
								}
							}
						});
					} else {
						SwingUtilities.invokeLater(new Runnable() {
							@Override
							public void run() {
								RandomizerGUI.this.opDialog.setVisible(false);
								verboseLog = System.out;
								RandomizerGUI.this.romHandler = null;
								initialFormState();
							}
						});
					}
				}
			};
			t.start();
		} catch (Exception ex) {
			long time = System.currentTimeMillis();
			try {
				String errlog = "error_" + time + ".txt";
				PrintStream ps = new PrintStream(new FileOutputStream(errlog));
				PrintStream e1 = System.err;
				System.setErr(ps);
				ex.printStackTrace();
				verboseLog.close();
				byte[] out = baos.toByteArray();
				System.err.print(new String(out, "UTF-8"));
				System.setErr(e1);
				ps.close();
				JOptionPane.showMessageDialog(this, String.format(
						bundle.getString("RandomizerGUI.saveFailed"), errlog));
			} catch (Exception logex) {
				JOptionPane.showMessageDialog(this,
						bundle.getString("RandomizerGUI.saveFailedNoLog"));
				verboseLog.close();
			}
		}

	}