diff options
| author | DeDiamondPro <67508414+DeDiamondPro@users.noreply.github.com> | 2022-03-27 19:12:44 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-03-27 19:12:44 +0200 |
| commit | 47efdd4f84cc9a29738fe16d631eb33ee716db61 (patch) | |
| tree | af7514fac2d55c7a2885025d6e858b8a2cfa3b55 /src | |
| parent | e202e4adf979073921455083f5e737bc4fcf5f14 (diff) | |
| download | NotEnoughUpdates-47efdd4f84cc9a29738fe16d631eb33ee716db61.tar.gz NotEnoughUpdates-47efdd4f84cc9a29738fe16d631eb33ee716db61.tar.bz2 NotEnoughUpdates-47efdd4f84cc9a29738fe16d631eb33ee716db61.zip | |
New wiki in wiki renderer (#97)
* partly working and pushing cuz jani
* way better rendering stuff but still not perfect
* finish most of wiki renderer for new wiki
* JANI MY FRIEND PLEASE TEST
* Windows time :sad:
* fix wiki renderer
* Some things I forgor
* changelog
* Better corrupted file handling in graph and added check for crash that I have no idea how it happened.
Diffstat (limited to 'src')
7 files changed, 164 insertions, 43 deletions
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java b/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java index df31834f..abe0bdcf 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java @@ -23,6 +23,7 @@ import org.apache.commons.io.FileUtils; import org.lwjgl.input.Keyboard; import org.lwjgl.opengl.Display; +import javax.net.ssl.HttpsURLConnection; import javax.swing.JDialog; import javax.swing.JOptionPane; import java.io.*; @@ -1032,11 +1033,12 @@ public class NEUManager { } catch (IOException e) { return null; } - try ( - BufferedInputStream inStream = new BufferedInputStream(new URL( - url + "?action=raw&templates=expand").openStream()); - FileOutputStream fileOutputStream = new FileOutputStream(f) - ) { + try { + HttpsURLConnection con = (HttpsURLConnection) new URL(url + "?action=raw&templates=expand").openConnection(); + con.setRequestMethod("GET"); + con.setRequestProperty("User-Agent", "NotEnoughUpdates"); + BufferedInputStream inStream = new BufferedInputStream(con.getInputStream()); + FileOutputStream fileOutputStream = new FileOutputStream(f); byte[] dataBuffer = new byte[1024]; int bytesRead; while ((bytesRead = inStream.read(dataBuffer, 0, 1024)) != -1) { diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NEUOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/NEUOverlay.java index 5ad02f94..b7aa42d6 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/NEUOverlay.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/NEUOverlay.java @@ -751,16 +751,27 @@ public class NEUOverlay extends Gui { public void showInfo(JsonObject item) { if (item.has("info") && item.has("infoType")) { JsonArray lore = item.get("info").getAsJsonArray(); - StringBuilder loreBuilder = new StringBuilder(); - for (int i = 0; i < lore.size(); i++) { - loreBuilder.append(lore.get(i).getAsString()); - if (i != lore.size() - 1) - loreBuilder.append("\n"); + String infoType = item.get("infoType").getAsString(); + String infoText = ""; + if (infoType.equals("WIKI_URL")) { + for (JsonElement url : lore) { + infoText = url.getAsString(); + if ( + url.getAsString().startsWith("https://wiki.hypixel.net/") && NotEnoughUpdates.INSTANCE.config.misc.wiki == 0 + || url.getAsString().startsWith("https://hypixel-skyblock.fandom.com/") && + NotEnoughUpdates.INSTANCE.config.misc.wiki == 1) break; + } + } else { + StringBuilder loreBuilder = new StringBuilder(); + for (int i = 0; i < lore.size(); i++) { + loreBuilder.append(lore.get(i).getAsString()); + if (i != lore.size() - 1) + loreBuilder.append("\n"); + } + infoText = loreBuilder.toString(); } - String infoText = loreBuilder.toString(); String internalname = item.get("internalname").getAsString(); String name = item.get("displayname").getAsString(); - String infoType = item.get("infoType").getAsString(); displayInformationPane(new TextInfoPane( this, manager, @@ -825,6 +836,10 @@ public class NEUOverlay extends Gui { if (selectedItemGroup != null) { int selectedX = Math.min(selectedItemGroupX, width - getBoxPadding() - 18 * selectedItemGroup.size()); if (mouseY > selectedItemGroupY + 17 && mouseY < selectedItemGroupY + 35) { + if (!Mouse.getEventButtonState()) { + Utils.pushGuiScale(-1); + return true; //End early if the mouse isn't pressed, but still cancel event. + } for (int i = 0; i < selectedItemGroup.size(); i++) { if (mouseX >= selectedX - 1 + 18 * i && mouseX <= selectedX + 17 + 18 * i) { JsonObject item = selectedItemGroup.get(i); @@ -1349,7 +1364,8 @@ public class NEUOverlay extends Gui { } else if (getSortMode() == SORT_MODE_PET) { return internalname.matches(petRegex) && item.get("displayname").getAsString().contains("["); } else if (getSortMode() == SORT_MODE_TOOL) { - return checkItemType(item.get("lore").getAsJsonArray(), + return checkItemType( + item.get("lore").getAsJsonArray(), "SWORD", "BOW", "AXE", diff --git a/src/main/java/io/github/moulberry/notenoughupdates/infopanes/HTMLInfoPane.java b/src/main/java/io/github/moulberry/notenoughupdates/infopanes/HTMLInfoPane.java index baf88457..e4098f3e 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/infopanes/HTMLInfoPane.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/infopanes/HTMLInfoPane.java @@ -14,6 +14,7 @@ import io.github.moulberry.notenoughupdates.util.AllowEmptyHTMLTag; import io.github.moulberry.notenoughupdates.util.Utils; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.Gui; import net.minecraft.client.gui.ScaledResolution; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.texture.DynamicTexture; @@ -30,10 +31,12 @@ import java.net.URL; import java.net.URLConnection; import java.nio.charset.CharsetEncoder; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; +import java.util.regex.Pattern; public class HTMLInfoPane extends TextInfoPane { private static final WikiModel wikiModel; @@ -47,6 +50,10 @@ public class HTMLInfoPane extends TextInfoPane { private int imageHeight = 0; private int imageWidth = 0; + private float xMin = 0; + private int mouseOffset = 0; + private boolean selected = false; + private static boolean hasAttemptedDownload = false; /* @@ -61,6 +68,16 @@ public class HTMLInfoPane extends TextInfoPane { conf.addTokenTag("infobox", new IgnoreTag("infobox")); conf.addTokenTag("tabber", new IgnoreTag("tabber")); conf.addTokenTag("kbd", new HTMLTag("kbd")); + conf.addTokenTag("td", new AllowEmptyHTMLTag("td")); + conf.addTokenTag("tbody", new AllowEmptyHTMLTag("tbody")); + conf.addTokenTag("style", new AllowEmptyHTMLTag("style")); + conf.addTokenTag("article", new AllowEmptyHTMLTag("article")); + conf.addTokenTag("section", new AllowEmptyHTMLTag("section")); + conf.addTokenTag("link", new AllowEmptyHTMLTag("link")); + conf.addTokenTag("wbr", new AllowEmptyHTMLTag("wbr")); + conf.addTokenTag("dl", new AllowEmptyHTMLTag("dl")); + conf.addTokenTag("dd", new AllowEmptyHTMLTag("dd")); + conf.addTokenTag("dt", new AllowEmptyHTMLTag("dt")); wikiModel = new WikiModel(conf, "https://hypixel-skyblock.fandom.com/wiki/Special:Filepath/${image}", "https://hypixel-skyblock.fandom.com/wiki/${title}" ) { @@ -101,7 +118,7 @@ public class HTMLInfoPane extends TextInfoPane { ) { return manager.getWebFile(wikiUrl).thenApply(f -> { if (f == null) { - return new HTMLInfoPane(overlay, manager, "error", "error", "Failed to load wiki url: " + wikiUrl); + return new HTMLInfoPane(overlay, manager, "error", "error", "Failed to load wiki url: " + wikiUrl, false); } StringBuilder sb = new StringBuilder(); @@ -114,9 +131,16 @@ public class HTMLInfoPane extends TextInfoPane { sb.append(l).append("\n"); } } catch (IOException e) { - return new HTMLInfoPane(overlay, manager, "error", "error", "Failed to load wiki url: " + wikiUrl); + return new HTMLInfoPane(overlay, manager, "error", "error", "Failed to load wiki url: " + wikiUrl, false); } - return createFromWikiText(overlay, manager, name, f.getName(), sb.toString()); + return createFromWikiText( + overlay, + manager, + name, + f.getName(), + sb.toString(), + wikiUrl.startsWith("https://wiki.hypixel.net/") + ); }); } @@ -126,15 +150,37 @@ public class HTMLInfoPane extends TextInfoPane { * a more permanent solution that can be abstracted to work with arbitrary wiki codes (eg. moulberry.github.io/ * files/neu_help.html). */ + + private static final Pattern replacePattern = Pattern.compile( + "<nav class=\"page-actions-menu\">.*</nav>|", + Pattern.DOTALL + ); + public static HTMLInfoPane createFromWikiText( NEUOverlay overlay, NEUManager manager, String name, String filename, - String wiki + String wiki, boolean isOfficialWiki ) { - String[] split = wiki.split("</infobox>"); - wiki = split[split.length - 1]; //Remove everything before infobox - wiki = wiki.split("<span class=\"navbox-vde\">")[0]; //Remove navbox - wiki = wiki.split("<table class=\"navbox mw-collapsible\"")[0]; - wiki = "__NOTOC__\n" + wiki; //Remove TOC + if (isOfficialWiki) { + wiki = wiki.split("<main id=\"content\" class=\"mw-body\">")[1].split("</main>")[0]; // hide top bar + wiki = wiki.split("<div class=\"container-navbox\">")[0]; // hide giant bottom list + wiki = wiki.split("<div class=\"categoryboxcontainer\">")[0]; // hide small bottom category thing + wiki = replacePattern.matcher(wiki).replaceAll(""); + wiki = wiki.replaceAll( + "<div id=\"siteNotice\"></div><div id=\"mw-dismissablenotice-anonplace\"></div><script>.*</script>", + "" + ); // hide beta box + wiki = wiki.replaceAll("<h1 id=\"section_0\">.*</h1>", ""); // hide title + wiki = wiki.replace("src=\"/", "src=\"https://wiki.hypixel.net/"); + wiki = wiki.replace("\uD83D\uDDF8", "✓"); // replace checkmark with one that renders + wiki = wiki.replace("\uD83E\uDC10", "\u27F5"); // replace left arrow with one that renders + wiki = wiki.replace("\uD83E\uDC12", "\u27F6"); // replace right arrow with one that renders + } else { + String[] split = wiki.split("</infobox>"); + wiki = split[split.length - 1]; //Remove everything before infobox + wiki = wiki.split("<span class=\"navbox-vde\">")[0]; //Remove navbox + wiki = wiki.split("<table class=\"navbox mw-collapsible\"")[0]; + wiki = "__NOTOC__\n" + wiki; //Remove TOC + } try (PrintWriter out = new PrintWriter(new File(manager.configLocation, "debug/parsed.txt"))) { out.println(wiki); } catch (IOException ignored) { @@ -143,13 +189,13 @@ public class HTMLInfoPane extends TextInfoPane { try { html = wikiModel.render(wiki); } catch (IOException e) { - return new HTMLInfoPane(overlay, manager, "error", "error", "Could not render wiki."); + return new HTMLInfoPane(overlay, manager, "error", "error", "Could not render wiki.", false); } try (PrintWriter out = new PrintWriter(new File(manager.configLocation, "debug/html.txt"))) { out.println(html); } catch (IOException ignored) { } - return new HTMLInfoPane(overlay, manager, name, filename, html); + return new HTMLInfoPane(overlay, manager, name, filename, html, isOfficialWiki); } private String spaceEscape(String str) { @@ -164,7 +210,14 @@ public class HTMLInfoPane extends TextInfoPane { * generation is done asynchronously as sometimes it can take up to 10 seconds for more * complex webpages. */ - public HTMLInfoPane(NEUOverlay overlay, NEUManager manager, String name, String filename, String html) { + public HTMLInfoPane( + NEUOverlay overlay, + NEUManager manager, + String name, + String filename, + String html, + boolean isOfficial + ) { super(overlay, manager, name, ""); this.title = name; @@ -180,7 +233,7 @@ public class HTMLInfoPane extends TextInfoPane { return; } - File cssFile = new File(manager.configLocation, "wikia.css"); + File cssFile = new File(manager.configLocation, isOfficial ? "official-wiki.css" : "wikia.css"); File wkHtmlToImage = new File(manager.configLocation, "wkhtmltox-" + osId + "/bin/wkhtmltoimage"); //Use old binary folder @@ -235,6 +288,15 @@ public class HTMLInfoPane extends TextInfoPane { return; } + if (!cssFile.exists() && isOfficial) { + try { + Files.copy(this.getClass().getResourceAsStream("/assets/notenoughupdates/official-wiki.css"), cssFile.toPath()); + } catch (IOException e) { + e.printStackTrace(); + return; + } + } + File input = new File(manager.configLocation, "tmp/input.html"); String outputFileName = filename.replaceAll("(?i)\\u00A7.", "") .replaceAll("[^a-zA-Z0-9_\\-]", "_"); @@ -412,12 +474,23 @@ public class HTMLInfoPane extends TextInfoPane { } int yScroll = scrollHeight.getValue(); + float xSize = Math.min((paneWidth - overlay.getBoxPadding() * 2f) / imageWidth * scaleF, 1); + float xMax = xMin + xSize; + float vMin = yScroll / (imageHeight / scaleF); float vMax = (yScroll + height - overlay.getBoxPadding() * 3) / (imageHeight / scaleF); Utils.drawTexturedRect(leftSide + overlay.getBoxPadding(), overlay.getBoxPadding() * 2, imageW, - height - overlay.getBoxPadding() * 3, - 0, 1, vMin, vMax + (height - overlay.getBoxPadding() * 3), + xMin, xMax, vMin, vMax ); + if (xSize < 1) { + int barX = (int) (xMin * imageW) + leftSide + overlay.getBoxPadding(); + int barY = height - overlay.getBoxPadding() - 10; + int barWidth = (int) (xMax * imageW) + leftSide + overlay.getBoxPadding(); + int barHeight = height - overlay.getBoxPadding() - 5; + boolean isHovered = mouseX >= barX && mouseX <= barWidth && mouseY >= barY && mouseY <= barHeight || selected; + Gui.drawRect(barX, barY, barWidth, barHeight, new Color(255, 255, 255, isHovered ? 150 : 100).getRGB()); + } } else { scrollHeight.setValue(0); @@ -435,6 +508,27 @@ public class HTMLInfoPane extends TextInfoPane { @Override public void mouseInput(int width, int height, int mouseX, int mouseY, boolean mouseDown) { + int paneWidth = (int) (width / 3 * overlay.getWidthMult()); + int rightSide = (int) (width * overlay.getInfoPaneOffsetFactor()); + int leftSide = rightSide - paneWidth; + int imageW = paneWidth - overlay.getBoxPadding() * 2; + float scaleF = IMAGE_WIDTH * ZOOM_FACTOR / (float) imageW; + float xSize = Math.min((paneWidth - overlay.getBoxPadding() * 2f) / imageWidth * scaleF, 1); + float xMax = xMin + xSize; + int barX = (int) (xMin * imageW) + leftSide + overlay.getBoxPadding(); + int barY = height - overlay.getBoxPadding() - 10; + int barWidth = (int) (xMax * imageW) + leftSide + overlay.getBoxPadding(); + int barHeight = height - overlay.getBoxPadding() - 5; + if (!mouseDown) + selected = false; + if (mouseX >= barX && mouseX <= barWidth && mouseY >= barY && mouseY <= barHeight && mouseDown || selected) { + if (!selected) + mouseOffset = mouseX - barX; + xMin = (mouseX - leftSide - overlay.getBoxPadding() / 2f - mouseOffset) / imageWidth * scaleF; + xMin = Math.max(0, xMin); + xMin = Math.min(xMin, 1 - xSize); + selected = true; + } super.mouseInput(width, height, mouseX, mouseY, mouseDown); } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/infopanes/InfoPane.java b/src/main/java/io/github/moulberry/notenoughupdates/infopanes/InfoPane.java index 70d7d65b..03cb64f6 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/infopanes/InfoPane.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/infopanes/InfoPane.java @@ -61,10 +61,10 @@ public abstract class InfoPane extends Gui { return HTMLInfoPane.createFromWikiUrl(overlay, manager, name, infoText); case "WIKI": return CompletableFuture.completedFuture( - HTMLInfoPane.createFromWikiText(overlay, manager, name, internalName, infoText)); + HTMLInfoPane.createFromWikiText(overlay, manager, name, internalName, infoText, false)); case "HTML": return CompletableFuture.completedFuture( - new HTMLInfoPane(overlay, manager, name, internalName, infoText)); + new HTMLInfoPane(overlay, manager, name, internalName, infoText, false)); default: return CompletableFuture.completedFuture( new TextInfoPane(overlay, manager, name, infoText)); diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiPriceGraph.java b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiPriceGraph.java index 3955b35f..63a08d41 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiPriceGraph.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiPriceGraph.java @@ -117,12 +117,11 @@ public class GuiPriceGraph extends GuiScreen { Utils.drawStringCentered("Loading...", Minecraft.getMinecraft().fontRendererObj, guiLeft + 166, guiTop + 116, false, 0xffffff00 ); - else if (dataPoints == null || dataPoints.get() == null || dataPoints.get().size() <= 1) + else if (dataPoints == null || dataPoints.get() == null || dataPoints.get().size() <= 1 || lowestValue == null) Utils.drawStringCentered("No data found.", Minecraft.getMinecraft().fontRendererObj, guiLeft + 166, guiTop + 116, false, 0xffff0000 ); else { - int graphColor = SpecialColour.specialToChromaRGB(NotEnoughUpdates.INSTANCE.config.ahGraph.graphColor); int graphColor2 = SpecialColour.specialToChromaRGB(NotEnoughUpdates.INSTANCE.config.ahGraph.graphColor2); Integer lowestDist = null; @@ -399,15 +398,17 @@ public class GuiPriceGraph extends GuiScreen { if (!file.getName().endsWith(".gz")) continue; if (file.lastModified() < System.currentTimeMillis() - NotEnoughUpdates.INSTANCE.config.ahGraph.dataRetention * 86400000L) + //noinspection ResultOfMethodCallIgnored file.delete(); } Date date = new Date(); Long epochSecond = date.toInstant().getEpochSecond(); File file = new File(dir, "prices_" + format.format(date) + ".gz"); HashMap<String, Data> prices = new HashMap<>(); - if (file.exists()) - prices = load(file); - if (prices == null) return; + if (file.exists()) { + HashMap<String, Data> tempPrices = load(file); + if (tempPrices != null) prices = tempPrices; + } for (Map.Entry<String, JsonElement> item : items.entrySet()) { if (prices.containsKey(item.getKey())) { if (bazaar && item.getValue().getAsJsonObject().has("curr_buy") && item.getValue().getAsJsonObject().has( @@ -493,7 +494,10 @@ public class GuiPriceGraph extends GuiScreen { )) ) { return GSON.fromJson(reader, type); - } catch (Exception ignored) { + } catch (Exception e) { + System.out.println("Deleting " + file.getName() + " because it is probably corrupted."); + //noinspection ResultOfMethodCallIgnored + file.delete(); } } return null; diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Misc.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Misc.java index e872bfc0..dafbe202 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Misc.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Misc.java @@ -1,13 +1,7 @@ package io.github.moulberry.notenoughupdates.options.seperateSections; import com.google.gson.annotations.Expose; -import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigAccordionId; -import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorAccordion; -import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorBoolean; -import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorButton; -import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorDropdown; -import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorSlider; -import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigOption; +import io.github.moulberry.notenoughupdates.core.config.annotations.*; public class Misc { @Expose @@ -147,4 +141,14 @@ public class Misc { @ConfigEditorBoolean public boolean disableNPCRetexturing = false; + @Expose + @ConfigOption( + name = "Wiki", + desc = "The wiki to use in the wiki renderer." + ) + @ConfigEditorDropdown(values = { + "Hypixel", + "Fandom" + }) + public int wiki = 0; } diff --git a/src/main/resources/assets/notenoughupdates/official-wiki.css b/src/main/resources/assets/notenoughupdates/official-wiki.css new file mode 100644 index 00000000..a9f82a32 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/official-wiki.css @@ -0,0 +1 @@ +.client-js .mw-dismissable-notice { display: none}.mw-dismissable-notice-close { visibility: hidden}.sitedir-ltr .mw-dismissable-notice-close { float: right}.sitedir-rtl .mw-dismissable-notice-close { float: left}.sitedir-ltr .mw-dismissable-notice-body { margin: .5em 20% .5em 5em}.sitedir-rtl .mw-dismissable-notice-body { margin: .5em 5em .5em 20%}.hlist dl,.hlist ol,.hlist ul { margin: 0; padding: 0}.hlist dl dl,.hlist ol dl,.hlist ul dl,.hlist dl ol,.hlist ol ol,.hlist ul ol,.hlist dl ul,.hlist ol ul,.hlist ul ul { display: inline}.hlist dd,.hlist dt,.hlist li { margin: 0; display: inline}ul.hlist li,.hlist>ul li,.hlist>dl li { display: inline-block; margin-right: 8px}.hlist-separated li:after { content: '•'!important; padding-left: 8px; font-size: 1em; line-height: 1}.hlist-separated :last-child:after { content: none!important}.mw-ui-button { background-color: #f8f9fa; color: #202122; display: inline-block; -moz-box-sizing: border-box; box-sizing: border-box; border: 1px solid #a2a9b1; border-radius: 2px; cursor: pointer; vertical-align: middle; font-family: inherit; font-size: 1em; font-weight: 700; line-height: 1.28571429em; text-align: center; -webkit-appearance: none}.mw-ui-button:not(.mw-ui-icon-element) { min-height: 32px; min-width: 4em; max-width: 28.75em; margin: 0; padding: 5px 12px}.mw-ui-button:not(:disabled) { -webkit-transition: background-color 100ms,color 100ms,border-color 100ms,box-shadow 100ms; transition: background-color 100ms,color 100ms,border-color 100ms,box-shadow 100ms}.mw-ui-button:not(:disabled):visited { color: #202122}.mw-ui-button:not(:disabled):hover { background-color: #fff; color: #404244; border-color: #a2a9b1}.mw-ui-button:not(:disabled):focus { color: #202122; border-color: #36c; box-shadow: inset 0 0 0 1px #36c,inset 0 0 0 2px #fff; outline-width: 0}.mw-ui-button:not(:disabled):focus::-moz-focus-inner { border-color: transparent; padding: 0}.mw-ui-button:not(:disabled):active,.mw-ui-button:not(:disabled).is-on { background-color: #c8ccd1; color: #000; border-color: #72777d; box-shadow: none}.mw-ui-button:disabled { background-color: #c8ccd1; color: #fff; border-color: #c8ccd1; cursor: default}.mw-ui-button.mw-ui-icon-element:not(.mw-ui-icon-with-label-desktop) { color: transparent!important}.mw-ui-button.mw-ui-icon-element:not(.mw-ui-icon-with-label-desktop) span { display: block; position: absolute!important; clip: rect(1px,1px,1px,1px); width: 1px; height: 1px; margin: -1px; border: 0; padding: 0; overflow: hidden}@media all and (max-width: 1000px) { .mw-ui-button.mw-ui-icon-element.mw-ui-icon-with-label-desktop { color:transparent!important } .mw-ui-button.mw-ui-icon-element span { display: block; position: absolute!important; clip: rect(1px,1px,1px,1px); width: 1px; height: 1px; margin: -1px; border: 0; padding: 0; overflow: hidden }}.mw-ui-button.mw-ui-quiet,.mw-ui-button.mw-ui-quiet.mw-ui-progressive,.mw-ui-button.mw-ui-quiet.mw-ui-destructive { background-color: transparent; color: #202122; border-color: transparent; font-weight: 700}.mw-ui-button.mw-ui-quiet:not(.mw-ui-icon-element),.mw-ui-button.mw-ui-quiet.mw-ui-progressive:not(.mw-ui-icon-element),.mw-ui-button.mw-ui-quiet.mw-ui-destructive:not(.mw-ui-icon-element) { min-height: 32px}input[type=checkbox]:hover+.mw-ui-button.mw-ui-quiet,input[type=checkbox]:hover+.mw-ui-button.mw-ui-quiet.mw-ui-progressive,input[type=checkbox]:hover+.mw-ui-button.mw-ui-quiet.mw-ui-destructive,.mw-ui-button.mw-ui-quiet:hover,.mw-ui-button.mw-ui-quiet.mw-ui-progressive:hover,.mw-ui-button.mw-ui-quiet.mw-ui-destructive:hover { background-color: rgba(0,24,73,.02745098); color: #202122; border-color: transparent}input[type=checkbox]:focus+.mw-ui-button.mw-ui-quiet,input[type=checkbox]:focus+.mw-ui-button.mw-ui-quiet.mw-ui-progressive,input[type=checkbox]:focus+.mw-ui-button.mw-ui-quiet.mw-ui-destructive,.mw-ui-button.mw-ui-quiet:focus,.mw-ui-button.mw-ui-quiet.mw-ui-progressive:focus,.mw-ui-button.mw-ui-quiet.mw-ui-destructive:focus { color: #202122; border-color: #36c; box-shadow: inset 0 0 0 1px #36c,inset 0 0 0 2px #fff}input[type=checkbox]:active+.mw-ui-button.mw-ui-quiet,input[type=checkbox]:active+.mw-ui-button.mw-ui-quiet.mw-ui-progressive,input[type=checkbox]:active+.mw-ui-button.mw-ui-quiet.mw-ui-destructive,.mw-ui-button.mw-ui-quiet:active,.mw-ui-button.mw-ui-quiet.mw-ui-progressive:active,.mw-ui-button.mw-ui-quiet.mw-ui-destructive:active { background-color: rgba(0,36,73,.08235294); color: #000; border-color: #72777d; box-shadow: none}.mw-ui-button.mw-ui-quiet:disabled,.mw-ui-button.mw-ui-quiet.mw-ui-progressive:disabled,.mw-ui-button.mw-ui-quiet.mw-ui-destructive:disabled,.mw-ui-button.mw-ui-quiet:disabled:hover,.mw-ui-button.mw-ui-quiet.mw-ui-progressive:disabled:hover,.mw-ui-button.mw-ui-quiet.mw-ui-destructive:disabled:hover,.mw-ui-button.mw-ui-quiet:disabled:active,.mw-ui-button.mw-ui-quiet.mw-ui-progressive:disabled:active,.mw-ui-button.mw-ui-quiet.mw-ui-destructive:disabled:active { background-color: transparent; color: #72777d; border-color: transparent}.mw-ui-button.mw-ui-progressive:not(:disabled) { background-color: #36c; color: #fff; border-color: #36c}.mw-ui-button.mw-ui-progressive:not(:disabled):hover { background-color: #447ff5; border-color: #447ff5}.mw-ui-button.mw-ui-progressive:not(:disabled):focus { box-shadow: inset 0 0 0 1px #36c,inset 0 0 0 2px #fff}.mw-ui-button.mw-ui-progressive:not(:disabled):active,.mw-ui-button.mw-ui-progressive:not(:disabled).is-on { background-color: #2a4b8d; border-color: #2a4b8d; box-shadow: none}.mw-ui-button.mw-ui-progressive:disabled { background-color: #c8ccd1; color: #fff; border-color: #c8ccd1}.mw-ui-button.mw-ui-progressive.mw-ui-quiet { color: #36c; background-color: transparent; border-color: transparent}input[type=checkbox]:hover+.mw-ui-button.mw-ui-progressive.mw-ui-quiet,.mw-ui-button.mw-ui-progressive.mw-ui-quiet:hover { background-color: rgba(52,123,255,.2); border-color: transparent; color: #447ff5}input[type=checkbox]:focus+.mw-ui-button.mw-ui-progressive.mw-ui-quiet,.mw-ui-button.mw-ui-progressive.mw-ui-quiet:focus { color: #36c; border-color: #36c}input[type=checkbox]:active+.mw-ui-button.mw-ui-progressive.mw-ui-quiet,.mw-ui-button.mw-ui-progressive.mw-ui-quiet:active { color: #fff; background-color: #2a4b8d; border-color: #2a4b8d}.mw-ui-button.mw-ui-destructive:not(:disabled) { background-color: #d33; color: #fff; border-color: #d33}.mw-ui-button.mw-ui-destructive:not(:disabled):hover { background-color: #ff4242; border-color: #ff4242}.mw-ui-button.mw-ui-destructive:not(:disabled):focus { box-shadow: inset 0 0 0 1px #d33,inset 0 0 0 2px #fff}.mw-ui-button.mw-ui-destructive:not(:disabled):active,.mw-ui-button.mw-ui-destructive:not(:disabled).is-on { background-color: #b32424; border-color: #b32424; box-shadow: none}.mw-ui-button.mw-ui-destructive:disabled { background-color: #c8ccd1; color: #fff; border-color: #c8ccd1}.mw-ui-button.mw-ui-destructive.mw-ui-quiet { color: #d33; background-color: transparent; border-color: transparent}input[type=checkbox]:hover+.mw-ui-button.mw-ui-destructive.mw-ui-quiet,.mw-ui-button.mw-ui-destructive.mw-ui-quiet:hover { background-color: rgba(209,29,19,.2); border-color: transparent; color: #ff4242}input[type=checkbox]:focus+.mw-ui-button.mw-ui-destructive.mw-ui-quiet,.mw-ui-button.mw-ui-destructive.mw-ui-quiet:focus { color: #d33; border-color: #d33}input[type=checkbox]:active+.mw-ui-button.mw-ui-destructive.mw-ui-quiet,.mw-ui-button.mw-ui-destructive.mw-ui-quiet:active { color: #fff; background-color: #b32424; border-color: #b32424}.mw-ui-button.mw-ui-big { font-size: 1.3em}.mw-ui-button.mw-ui-block { display: block; width: 100%; margin-left: auto; margin-right: auto}a.mw-ui-button { text-decoration: none}a.mw-ui-button:hover,a.mw-ui-button:focus { text-decoration: none}.mw-ui-button-group>* { min-width: 48px; border-radius: 0; float: left}.mw-ui-button-group>*:first-child { border-top-left-radius: 2px; border-bottom-left-radius: 2px}.mw-ui-button-group>*:not(:first-child) { border-left: 0}.mw-ui-button-group>*:last-child { border-top-right-radius: 2px; border-bottom-right-radius: 2px}.mw-ui-button-group .is-on .button { cursor: default}.mw-ui-icon { font-size: initial; position: relative; display: inline-block; box-sizing: content-box!important; width: 1.25em; height: 1.25em; min-width: 1.25em; min-height: 1.25em; flex-basis: 1.25em; vertical-align: middle; line-height: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; -moz-appearance: none; -webkit-appearance: none; background-color: transparent; border: 0; margin: 0; padding: 0}.mw-ui-icon:before { content: ''; display: block; width: 100%; height: 100%; min-width: 1.25em; min-height: 1.25em; background-repeat: no-repeat; background-size: 1.25em 1.25em; background-position: center}.mw-ui-icon-flush-top { margin-top: -.75em}.mw-ui-icon-flush-left { margin-left: -.75em}.mw-ui-icon-flush-right { margin-right: -.75em}.mw-ui-icon-element { border-radius: 2px; padding: .75em; -webkit-transition: background-color 100ms; transition: background-color 100ms; color: transparent}.mw-ui-icon-element:focus,.mw-ui-icon-element:active,.mw-ui-icon-element:visited { color: transparent}.mw-ui-icon-element:active { background-color: rgba(0,0,0,.03)}@media(hover: hover) { .mw-ui-icon-element:not(.disabled):hover { background-color:rgba(0,0,0,.03) }}.mw-ui-icon-small { width: 1em; height: 1em; min-width: 1em; min-height: 1em; flex-basis: 1em; line-height: 1em}.mw-ui-icon-small:before { content: ''; display: block; width: 100%; height: 100%; min-width: 1em; min-height: 1em; background-repeat: no-repeat; background-size: 1em 1em; background-position: center}.mw-ui-icon-small.mw-ui-icon-element { padding: .5625em}.mw-ui-icon-small.mw-ui-icon-flush-left { margin-left: -.5625em}.mw-ui-icon-small.mw-ui-icon-flush-right { margin-right: -.5625em}.mw-ui-icon-small.mw-ui-icon-before:before { min-width: 1em; min-height: 1em; margin-right: .5625em}.mw-ui-icon-before { width: auto; max-width: 100%}.mw-ui-icon-before:before { display: inline-block; font-size: initial; width: auto; min-width: 1.25em; min-height: 1.25em; margin-right: 8px; vertical-align: middle}.mw-ui-icon-before span { vertical-align: middle}@media all and (min-width: 1000px) { .mw-ui-icon-with-label-desktop { color:#54595d; width: auto; line-height: inherit; flex-basis: auto } .mw-ui-icon-with-label-desktop:hover,.mw-ui-icon-with-label-desktop:focus,.mw-ui-icon-with-label-desktop:active,.mw-ui-icon-with-label-desktop:visited { color: #54595d; text-decoration: none } .mw-ui-icon-with-label-desktop:before { width: auto; display: inline-block; margin-right: 8px; vertical-align: text-bottom }}.minerva__tab-container { white-space: nowrap; overflow-x: auto}.minerva__tab-container .minerva__tab { font-size: .85em; margin: 0 10px 0 0; color: #54595d; font-weight: 700; padding-bottom: 6px; display: inline-block}.minerva__tab-container .minerva__tab:visited,.minerva__tab-container .minerva__tab:hover,.minerva__tab-container .minerva__tab:active,.minerva__tab-container .minerva__tab.new,.minerva__tab-container .minerva__tab.new:visited,.minerva__tab-container .minerva__tab.new:active,.minerva__tab-container .minerva__tab.new:hover { color: #54595d; text-decoration: none}.minerva__tab-container .minerva__tab:last-child { margin-right: 0}.minerva__tab-container .minerva__tab.selected { border-bottom: 2px solid #54595d}.toggle-list__list--drop-down { -webkit-transform: translateY(-8px); -ms-transform: translateY(-8px); transform: translateY(-8px); -webkit-tap-highlight-color: transparent}.minerva-animations-ready .toggle-list__list--drop-down { -webkit-transition: opacity 100ms ease-in-out,-webkit-tap-highlight-color 0s ease-in-out,transform 100ms ease-in-out,visibility 100ms ease-in-out; transition: opacity 100ms ease-in-out,-webkit-tap-highlight-color 0s ease-in-out,transform 100ms ease-in-out,visibility 100ms ease-in-out}.toggle-list__checkbox:checked~.toggle-list__list--drop-down { -webkit-transform: translateY(0); -ms-transform: translateY(0); transform: translateY(0)}.toggle-list-item { display: block; padding: .75em .875em}.toggle-list-item:hover { background: #eaecf0}.toggle-list-item__anchor { display: block; line-height: 1}.toggle-list-item__anchor:hover { text-decoration: none}.toggle-list-item__anchor:visited,.toggle-list-item__anchor:active { color: #54595d}.toggle-list-item__icon { vertical-align: middle}.toggle-list-item__label { text-align: left; color: #54595d; font-weight: 700; white-space: nowrap; vertical-align: middle; font-size: .875em}.minerva-user-menu-list { top: 100%; right: -.75em; min-width: 200px; border-radius: 2px}.minerva--history-page-action-enabled .page-actions-menu__list-item { flex-basis: auto}.minerva--history-page-action-enabled .page-actions-menu__list-item:first-child { flex-grow: 0}.page-actions-overflow-list { top: 100%; right: -.75em; border-radius: 2px}.mw-ui-icon-minerva-ellipsis:before { -webkit-transform: rotate(90deg); -ms-transform: rotate(90deg); transform: rotate(90deg)}@media screen { @counter-style meetei { system: numeric; symbols: '\ABF0''\ABF1''\ABF2''\ABF3''\ABF4''\ABF5''\ABF6''\ABF7''\ABF8''\ABF9'; suffix: ') ' } @counter-style santali { system: numeric; symbols: '\1C50''\1C51''\1C52''\1C53''\1C54''\1C55''\1C56''\1C57''\1C58''\1C59' } ol:lang(azb) li,ol:lang(bcc) li,ol:lang(bgn) li,ol:lang(bqi) li,ol:lang(fa) li,ol:lang(glk) li,ol:lang(kk-arab) li,ol:lang(lrc) li,ol:lang(luz) li,ol:lang(mzn) li { list-style-type: persian } ol:lang(ckb) li,ol:lang(sdh) li { list-style-type: arabic-indic } ol:lang(hi) li,ol:lang(mai) li,ol:lang(mr) li,ol:lang(ne) li { list-style-type: devanagari } ol:lang(as) li,ol:lang(bn) li { list-style-type: bengali } ol:lang(mni) li { list-style-type: meetei } ol:lang(or) li { list-style-type: oriya } ol:lang(sat) li { list-style-type: santali }}div,span,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,ins,em,img,small,strike,strong,sub,sup,tt,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,input,button,select,audio,video { margin: 0; padding: 0; border: 0; font: inherit; font-size: 100%; vertical-align: baseline; background: 0 0}table,caption,tbody,tfoot,thead,tr,th,td { font-size: 100%}caption { font-weight: 700}button { border: 0; background-color: transparent; cursor: pointer}input { line-height: normal}ul { list-style: none}table { border-collapse: collapse}html,body { height: 100%}html { font-size: 100%; -webkit-text-size-adjust: none}body { background-color: transparent; color: #202122; margin: 0}main { display: block}.mw-body { border-top: 1px solid transparent; padding-bottom: 32px}.overlay-enabled,.mw-body { background-color: transparent}.header-container { border-bottom: 1px solid #c8ccd1; padding: 0 16px}.header-container.header-chrome { background-color: #eaecf0; border: 0; box-shadow: inset 0 -1px 3px rgba(0,0,0,.08)}.navigation-drawer--loading,#footer-info-lastmod { display: none}.header { display: table; width: 100%; border-spacing: 0; border-collapse: collapse; height: 3.375em; white-space: nowrap; border-top: 1px solid #c8ccd1; margin-top: -1px}.header>div,.header>.navigation-drawer { position: relative; vertical-align: middle; display: table-cell}.header>div a { display: block}.header .branding-box { width: auto; opacity: .66}.header .branding-box h1,.header .branding-box a { margin-left: 5px; font-size: 1em; text-decoration: none; color: #202122}.header .branding-box h1 span,.header .branding-box a span { line-height: 1; font-size: inherit}.header .branding-box h1 img,.header .branding-box a img { vertical-align: middle}.header .branding-box h1>*,.header .branding-box a>* { float: left}.header .branding-box h1 sup,.header .branding-box a sup { color: #54595d; display: none}.beta .header .branding-box h1 sup,.beta .header .branding-box a sup { display: initial}.header>.header-title { vertical-align: middle}#searchInput { cursor: text}.search-box,.header .search-box { display: none; width: auto}.search-box .search { background-color: #fff; background-position: left .5em center; background-repeat: no-repeat; background-size: 1.125em; -webkit-appearance: none; width: 100%; margin-top: 0; height: 2.25em; border: 1px solid #fff; border-radius: 2px; padding: 7px 0 7px 2.0625em; box-shadow: 0 1px 1px rgba(0,0,0,.05); outline: 0; -webkit-transition: border-color 250ms,box-shadow 250ms; transition: border-color 250ms,box-shadow 250ms}.client-nojs .search-box .search:focus,.search-overlay .search-box .search:focus { border-color: #36c; box-shadow: inset 0 0 0 1px #36c,0 1px 1px rgba(0,0,0,.05)}input.search::-webkit-search-decoration,input.search::-webkit-search-cancel-button,input.search::-webkit-search-results-button,input.search::-webkit-search-results-decoration { display: none}.content h2 { clear: left}.content .collapsible-heading .edit-page { visibility: hidden}.content .collapsible-heading.open-block .edit-page { visibility: visible}.content .mw-parser-output>h2,.content .section-heading { border-bottom: 1px solid #eaecf0; margin-bottom: .5em}.content .mw-parser-output>h1,.content .mw-parser-output>h2,.content .mw-parser-output>h3,.content .mw-parser-output>h4,.content .mw-parser-output>h5,.content .section-heading,.content .in-block { display: table}.content .mw-parser-output>h1 .mw-headline,.content .mw-parser-output>h2 .mw-headline,.content .mw-parser-output>h3 .mw-headline,.content .mw-parser-output>h4 .mw-headline,.content .mw-parser-output>h5 .mw-headline,.content .section-heading .mw-headline,.content .in-block .mw-headline { width: 100%}.content .mw-parser-output>h1>span,.content .mw-parser-output>h2>span,.content .mw-parser-output>h3>span,.content .mw-parser-output>h |
