// Path: src/matcher/gui/IGuiComponent.java
// public interface IGuiComponent {
// 	default void onProjectChange() { }
// 
// 	default void onViewChange() { }
// 
// 	default void onMappingChange() { }
// 	default void onMatchChange(Set<MatchType> types) { }
// 
// 	default void onClassSelect(ClassInstance cls) { }
// 	default void onMethodSelect(MethodInstance method) { }
// 	default void onFieldSelect(FieldInstance field) { }
// 	default void onMethodVarSelect(MethodVarInstance arg) { }
// 
// 	default void onMatchListRefresh() { }
// }
// 
// Path: src/matcher/srcprocess/HtmlUtil.java
// public class HtmlUtil {
// 	public static String getId(MethodInstance method) {
// 		return "method-".concat(escapeId(method.getId()));
// 	}
// 
// 	public static String getId(FieldInstance field) {
// 		return "field-".concat(escapeId(field.getId()));
// 	}
// 
// 	private static String escapeId(String str) {
// 		StringBuilder ret = null;
// 		int retEnd = 0;
// 
// 		for (int i = 0, max = str.length(); i < max; i++) {
// 			char c = str.charAt(i);
// 
// 			if ((c < 'A' || c > 'Z') && (c < 'a' || c > 'z') && (c < '0' || c > '9') && c != '-' && c != '_' && c != '.') { // use : as an escape identifier
// 				if (ret == null) ret = new StringBuilder(max * 2);
// 
// 				ret.append(str, retEnd, i);
// 
// 				ret.append(':');
// 
// 				for (int j = 0; j < 4; j++) {
// 					int v = (c >>> ((3 - j) * 4)) & 0xf;
// 					ret.append("0123456789abcdef".charAt(v));
// 				}
// 
// 				retEnd = i + 1;
// 			}
// 		}
// 
// 		if (ret == null) {
// 			return str;
// 		} else {
// 			ret.append(str, retEnd, str.length());
// 
// 			return ret.toString();
// 		}
// 	}
// 
// 	public static String escape(String str) {
// 		StringBuilder ret = null;
// 		int retEnd = 0;
// 
// 		for (int i = 0, max = str.length(); i < max; i++) {
// 			char c = str.charAt(i);
// 
// 			if (c == '<' || c == '>' || c == '&') {
// 				if (ret == null) ret = new StringBuilder(max * 2);
// 
// 				ret.append(str, retEnd, i);
// 
// 				if (c == '<') {
// 					ret.append("&lt;");
// 				} else if (c == '>') {
// 					ret.append("&gt;");
// 				} else {
// 					ret.append("&amp;");
// 				}
// 
// 				retEnd = i + 1;
// 			}
// 		}
// 
// 		if (ret == null) {
// 			return str;
// 		} else {
// 			ret.append(str, retEnd, str.length());
// 
// 			return ret.toString();
// 		}
// 	}
// }


import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.UncheckedIOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Queue;
import javafx.concurrent.Worker.State;
import javafx.scene.control.Tab;
import javafx.scene.web.WebView;
import matcher.gui.IGuiComponent;
import matcher.srcprocess.HtmlUtil;
		addWebViewTask(() -> webView.getEngine().executeScript("var newAnchor = document.getElementById('"+anchorId+"');"
				+ "if (newAnchor !== null) document.body.scrollTop = newAnchor.getBoundingClientRect().top + window.scrollY;"
				+ "if (window.hasOwnProperty('anchorElem') && window.anchorElem !== null) window.anchorElem.classList.remove('selected');"
				+ "if (newAnchor !== null) newAnchor.classList.add('selected');"
				+ "window.anchorElem = newAnchor;"));
	}

	protected double getScrollTop() {
		Object result;

		if (webView.getEngine().getLoadWorker().getState() == State.SUCCEEDED
				&& (result = webView.getEngine().executeScript("document.body.scrollTop")) instanceof Number) {
			return ((Number) result).doubleValue();
		} else {
			return 0;
		}
	}

	protected void setScrollTop(double value) {
		addWebViewTask(() -> webView.getEngine().executeScript("document.body.scrollTop = "+value));
	}

	private void addWebViewTask(Runnable r) {
		if (webView.getEngine().getLoadWorker().getState() == State.SUCCEEDED) {
			r.run();
		} else {
			pendingWebViewTasks.add(r);
		}
	}

// Path: src/matcher/gui/IGuiComponent.java
// public interface IGuiComponent {
// 	default void onProjectChange() { }
// 
// 	default void onViewChange() { }
// 
// 	default void onMappingChange() { }
// 	default void onMatchChange(Set<MatchType> types) { }
// 
// 	default void onClassSelect(ClassInstance cls) { }
// 	default void onMethodSelect(MethodInstance method) { }
// 	default void onFieldSelect(FieldInstance field) { }
// 	default void onMethodVarSelect(MethodVarInstance arg) { }
// 
// 	default void onMatchListRefresh() { }
// }
// 
// Path: src/matcher/srcprocess/HtmlUtil.java
// public class HtmlUtil {
// 	public static String getId(MethodInstance method) {
// 		return "method-".concat(escapeId(method.getId()));
// 	}
// 
// 	public static String getId(FieldInstance field) {
// 		return "field-".concat(escapeId(field.getId()));
// 	}
// 
// 	private static String escapeId(String str) {
// 		StringBuilder ret = null;
// 		int retEnd = 0;
// 
// 		for (int i = 0, max = str.length(); i < max; i++) {
// 			char c = str.charAt(i);
// 
// 			if ((c < 'A' || c > 'Z') && (c < 'a' || c > 'z') && (c < '0' || c > '9') && c != '-' && c != '_' && c != '.') { // use : as an escape identifier
// 				if (ret == null) ret = new StringBuilder(max * 2);
// 
// 				ret.append(str, retEnd, i);
// 
// 				ret.append(':');
// 
// 				for (int j = 0; j < 4; j++) {
// 					int v = (c >>> ((3 - j) * 4)) & 0xf;
// 					ret.append("0123456789abcdef".charAt(v));
// 				}
// 
// 				retEnd = i + 1;
// 			}
// 		}
// 
// 		if (ret == null) {
// 			return str;
// 		} else {
// 			ret.append(str, retEnd, str.length());
// 
// 			return ret.toString();
// 		}
// 	}
// 
// 	public static String escape(String str) {
// 		StringBuilder ret = null;
// 		int retEnd = 0;
// 
// 		for (int i = 0, max = str.length(); i < max; i++) {
// 			char c = str.charAt(i);
// 
// 			if (c == '<' || c == '>' || c == '&') {
// 				if (ret == null) ret = new StringBuilder(max * 2);
// 
// 				ret.append(str, retEnd, i);
// 
// 				if (c == '<') {
// 					ret.append("&lt;");
// 				} else if (c == '>') {
// 					ret.append("&gt;");
// 				} else {
// 					ret.append("&amp;");
// 				}
// 
// 				retEnd = i + 1;
// 			}
// 		}
// 
// 		if (ret == null) {
// 			return str;
// 		} else {
// 			ret.append(str, retEnd, str.length());
// 
// 			return ret.toString();
// 		}
// 	}
// }


// Path: src/matcher/gui/tab/WebViewTab.java
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.UncheckedIOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Queue;
import javafx.concurrent.Worker.State;
import javafx.scene.control.Tab;
import javafx.scene.web.WebView;
import matcher.gui.IGuiComponent;
import matcher.srcprocess.HtmlUtil;

		addWebViewTask(() -> webView.getEngine().executeScript("var newAnchor = document.getElementById('"+anchorId+"');"
				+ "if (newAnchor !== null) document.body.scrollTop = newAnchor.getBoundingClientRect().top + window.scrollY;"
				+ "if (window.hasOwnProperty('anchorElem') && window.anchorElem !== null) window.anchorElem.classList.remove('selected');"
				+ "if (newAnchor !== null) newAnchor.classList.add('selected');"
				+ "window.anchorElem = newAnchor;"));
	}

	protected double getScrollTop() {
		Object result;

		if (webView.getEngine().getLoadWorker().getState() == State.SUCCEEDED
				&& (result = webView.getEngine().executeScript("document.body.scrollTop")) instanceof Number) {
			return ((Number) result).doubleValue();
		} else {
			return 0;
		}
	}

	protected void setScrollTop(double value) {
		addWebViewTask(() -> webView.getEngine().executeScript("document.body.scrollTop = "+value));
	}

	private void addWebViewTask(Runnable r) {
		if (webView.getEngine().getLoadWorker().getState() == State.SUCCEEDED) {
			r.run();
		} else {
			pendingWebViewTasks.add(r);
		}
	}

	protected void cancelWebViewTasks() {